imapext-2007

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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/CONTENTS	Mon Sep 14 15:17:45 2009 +0900
     1.3 @@ -0,0 +1,75 @@
     1.4 +/* ========================================================================
     1.5 + * Copyright 1988-2006 University of Washington
     1.6 + *
     1.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.8 + * you may not use this file except in compliance with the License.
     1.9 + * You may obtain a copy of the License at
    1.10 + *
    1.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.12 + *
    1.13 + * 
    1.14 + * ========================================================================
    1.15 + */
    1.16 +
    1.17 +			  TOOLKIT DIRECTORY CONTENTS
    1.18 +
    1.19 +Documentation:
    1.20 + . CONTENTS		this file
    1.21 + . LICENSE.txt		software license
    1.22 + . NOTICE		copyright notice
    1.23 + . README		read this file first
    1.24 + . SUPPORT		where to go to ask questions and/or report bugs
    1.25 + . docs/BUILD		build and installation instructions
    1.26 + . docs/CONFIG		detailed configuration notes
    1.27 + . docs/FAQ.html	frequently asked questions and answers
    1.28 + . docs/FAQ.txt		text version of FAQ.HTML
    1.29 + . docs/RELNOTES	release notes
    1.30 + . docs/SSLBUILD	build and installation instructions using SSL
    1.31 + . docs/Y2K		information relating to Y2K issues
    1.32 + . docs/bugs.txt	known bugs and deficiencies in this software
    1.33 + . docs/calendar.txt	information relating to the calendar
    1.34 + . docs/commndmt.txt	"ten commandments" on how to write a good IMAP client
    1.35 + . docs/draft/		Internet protocol documentation drafts
    1.36 + . docs/drivers.txt	how various mailbox format drivers interact, and
    1.37 +			 comparable features and performance
    1.38 + . docs/formats.txt	mailbox formats
    1.39 + . docs/internal.txt	programming interfaces
    1.40 + . docs/locking.txt	how file locking works
    1.41 + . docs/md5.txt		CRAM-MD5 authentication setup instructions
    1.42 + . docs/mixfmt.txt	specification of new mix format
    1.43 + . docs/naming.txt	mailbox naming conventions
    1.44 + . docs/rfc/		Internet protocol documentation
    1.45 +
    1.46 +Sources:
    1.47 + . Makefile		master makefile for UNIX
    1.48 + . makefile.nt		master makefile for NT/Win32
    1.49 + . makefile.ntk		master makefile for NT/Win32 using Kerberos V
    1.50 + . makefile.os2		master makefile for OS/2
    1.51 + . makefile.w2k		master makefile for Windows 2000
    1.52 + . makefile.wce		master makefile for Windows CE
    1.53 + . src/ansilib		pre-processed ANSI library routines
    1.54 + . src/c-client		pre-processed c-client sources
    1.55 + . src/charset		pre-processed character set conversion tables
    1.56 + . src/dmail		pre-processed user mail delivery sources
    1.57 + . src/ipopd		pre-processed POP2/POP3 daemon sources
    1.58 + . src/imapd		pre-processed IMAP4rev1 daemon sources
    1.59 + . src/mailutil		pre-processed mailbox utility sources
    1.60 + . src/mlock		pre-processed mailbox locking sources
    1.61 + . src/mtest		pre-processed c-client testbed sources
    1.62 + . src/osdep/amiga	pre-processed Amiga-specific sources
    1.63 + . src/osdep/dos	pre-processed DOS-specific sources
    1.64 + . src/osdep/mac	pre-processed Mac-specific sources
    1.65 + . src/osdep/nt		pre-processed NT-specific sources
    1.66 + . src/osdep/os2	pre-processed OS/2-specific sources (incomplete)
    1.67 + . src/osdep/tops-20	pre-processed TOPS-20 specific sources
    1.68 + . src/osdep/unix	pre-processed UNIX-specific sources
    1.69 + . src/osdep/vms	pre-processed VAX/VMS specific sources
    1.70 + . src/osdep/wce	pre-processed Windows CE-specific sources (incomplete)
    1.71 + . src/tmail		pre-processed system mail delivery sources
    1.72 + . tools		internal tools needed as part of the build process
    1.73 +
    1.74 +Directories created at build time on UNIX and NT/Win32:
    1.75 + . c-client		post-processed c-client sources and binary
    1.76 + . ipopd		post-processed POP2/POP3 daemon sources and binaries
    1.77 + . imapd		post-processed IMAP4rev1 daemon sources and binaries
    1.78 + . mtest		post-processed c-client testbed sources and binaries
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/LICENSE.txt	Mon Sep 14 15:17:45 2009 +0900
     2.3 @@ -0,0 +1,201 @@
     2.4 +                                 Apache License
     2.5 +                           Version 2.0, January 2004
     2.6 +                        http://www.apache.org/licenses/
     2.7 +
     2.8 +   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
     2.9 +
    2.10 +   1. Definitions. 
    2.11 +
    2.12 +      "License" shall mean the terms and conditions for use, reproduction,
    2.13 +      and distribution as defined by Sections 1 through 9 of this document.
    2.14 +
    2.15 +      "Licensor" shall mean the copyright owner or entity authorized by
    2.16 +      the copyright owner that is granting the License.
    2.17 +
    2.18 +      "Legal Entity" shall mean the union of the acting entity and all
    2.19 +      other entities that control, are controlled by, or are under common
    2.20 +      control with that entity. For the purposes of this definition,
    2.21 +      "control" means (i) the power, direct or indirect, to cause the
    2.22 +      direction or management of such entity, whether by contract or
    2.23 +      otherwise, or (ii) ownership of fifty percent (50%) or more of the
    2.24 +      outstanding shares, or (iii) beneficial ownership of such entity.
    2.25 +
    2.26 +      "You" (or "Your") shall mean an individual or Legal Entity
    2.27 +      exercising permissions granted by this License.
    2.28 +
    2.29 +      "Source" form shall mean the preferred form for making modifications,
    2.30 +      including but not limited to software source code, documentation
    2.31 +      source, and configuration files.
    2.32 +
    2.33 +      "Object" form shall mean any form resulting from mechanical
    2.34 +      transformation or translation of a Source form, including but
    2.35 +      not limited to compiled object code, generated documentation,
    2.36 +      and conversions to other media types.
    2.37 +
    2.38 +      "Work" shall mean the work of authorship, whether in Source or
    2.39 +      Object form, made available under the License, as indicated by a
    2.40 +      copyright notice that is included in or attached to the work
    2.41 +      (an example is provided in the Appendix below). 
    2.42 +
    2.43 +      "Derivative Works" shall mean any work, whether in Source or Object
    2.44 +      form, that is based on (or derived from) the Work and for which the
    2.45 +      editorial revisions, annotations, elaborations, or other modifications
    2.46 +      represent, as a whole, an original work of authorship. For the purposes
    2.47 +      of this License, Derivative Works shall not include works that remain
    2.48 +      separable from, or merely link (or bind by name) to the interfaces of,
    2.49 +      the Work and Derivative Works thereof.
    2.50 +
    2.51 +      "Contribution" shall mean any work of authorship, including
    2.52 +      the original version of the Work and any modifications or additions
    2.53 +      to that Work or Derivative Works thereof, that is intentionally
    2.54 +      submitted to Licensor for inclusion in the Work by the copyright owner
    2.55 +      or by an individual or Legal Entity authorized to submit on behalf of
    2.56 +      the copyright owner. For the purposes of this definition, "submitted"
    2.57 +      means any form of electronic, verbal, or written communication sent
    2.58 +      to the Licensor or its representatives, including but not limited to
    2.59 +      communication on electronic mailing lists, source code control systems,
    2.60 +      and issue tracking systems that are managed by, or on behalf of, the
    2.61 +      Licensor for the purpose of discussing and improving the Work, but
    2.62 +      excluding communication that is conspicuously marked or otherwise
    2.63 +      designated in writing by the copyright owner as "Not a Contribution."
    2.64 +
    2.65 +      "Contributor" shall mean Licensor and any individual or Legal Entity
    2.66 +      on behalf of whom a Contribution has been received by Licensor and
    2.67 +      subsequently incorporated within the Work.
    2.68 +
    2.69 +   2. Grant of Copyright License. Subject to the terms and conditions of
    2.70 +      this License, each Contributor hereby grants to You a perpetual,
    2.71 +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    2.72 +      copyright license to reproduce, prepare Derivative Works of,
    2.73 +      publicly display, publicly perform, sublicense, and distribute the
    2.74 +      Work and such Derivative Works in Source or Object form.
    2.75 +
    2.76 +   3. Grant of Patent License. Subject to the terms and conditions of
    2.77 +      this License, each Contributor hereby grants to You a perpetual,
    2.78 +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    2.79 +      (except as stated in this section) patent license to make, have made,
    2.80 +      use, offer to sell, sell, import, and otherwise transfer the Work,
    2.81 +      where such license applies only to those patent claims licensable
    2.82 +      by such Contributor that are necessarily infringed by their
    2.83 +      Contribution(s) alone or by combination of their Contribution(s)
    2.84 +      with the Work to which such Contribution(s) was submitted. If You
    2.85 +      institute patent litigation against any entity (including a
    2.86 +      cross-claim or counterclaim in a lawsuit) alleging that the Work
    2.87 +      or a Contribution incorporated within the Work constitutes direct
    2.88 +      or contributory patent infringement, then any patent licenses
    2.89 +      granted to You under this License for that Work shall terminate
    2.90 +      as of the date such litigation is filed.
    2.91 +
    2.92 +   4. Redistribution. You may reproduce and distribute copies of the
    2.93 +      Work or Derivative Works thereof in any medium, with or without
    2.94 +      modifications, and in Source or Object form, provided that You
    2.95 +      meet the following conditions:
    2.96 +
    2.97 +      (a) You must give any other recipients of the Work or
    2.98 +          Derivative Works a copy of this License; and
    2.99 +
   2.100 +      (b) You must cause any modified files to carry prominent notices
   2.101 +          stating that You changed the files; and
   2.102 +
   2.103 +      (c) You must retain, in the Source form of any Derivative Works
   2.104 +          that You distribute, all copyright, patent, trademark, and
   2.105 +          attribution notices from the Source form of the Work,
   2.106 +          excluding those notices that do not pertain to any part of
   2.107 +          the Derivative Works; and
   2.108 +
   2.109 +      (d) If the Work includes a "NOTICE" text file as part of its
   2.110 +          distribution, then any Derivative Works that You distribute must
   2.111 +          include a readable copy of the attribution notices contained
   2.112 +          within such NOTICE file, excluding those notices that do not
   2.113 +          pertain to any part of the Derivative Works, in at least one
   2.114 +          of the following places: within a NOTICE text file distributed
   2.115 +          as part of the Derivative Works; within the Source form or
   2.116 +          documentation, if provided along with the Derivative Works; or,
   2.117 +          within a display generated by the Derivative Works, if and
   2.118 +          wherever such third-party notices normally appear. The contents
   2.119 +          of the NOTICE file are for informational purposes only and
   2.120 +          do not modify the License. You may add Your own attribution
   2.121 +          notices within Derivative Works that You distribute, alongside
   2.122 +          or as an addendum to the NOTICE text from the Work, provided
   2.123 +          that such additional attribution notices cannot be construed
   2.124 +          as modifying the License.
   2.125 +
   2.126 +      You may add Your own copyright statement to Your modifications and
   2.127 +      may provide additional or different license terms and conditions
   2.128 +      for use, reproduction, or distribution of Your modifications, or
   2.129 +      for any such Derivative Works as a whole, provided Your use,
   2.130 +      reproduction, and distribution of the Work otherwise complies with
   2.131 +      the conditions stated in this License.
   2.132 +
   2.133 +   5. Submission of Contributions. Unless You explicitly state otherwise,
   2.134 +      any Contribution intentionally submitted for inclusion in the Work
   2.135 +      by You to the Licensor shall be under the terms and conditions of
   2.136 +      this License, without any additional terms or conditions.
   2.137 +      Notwithstanding the above, nothing herein shall supersede or modify
   2.138 +      the terms of any separate license agreement you may have executed
   2.139 +      with Licensor regarding such Contributions.
   2.140 +
   2.141 +   6. Trademarks. This License does not grant permission to use the trade
   2.142 +      names, trademarks, service marks, or product names of the Licensor,
   2.143 +      except as required for reasonable and customary use in describing the
   2.144 +      origin of the Work and reproducing the content of the NOTICE file.
   2.145 +
   2.146 +   7. Disclaimer of Warranty. Unless required by applicable law or
   2.147 +      agreed to in writing, Licensor provides the Work (and each
   2.148 +      Contributor provides its Contributions) on an "AS IS" BASIS,
   2.149 +      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   2.150 +      implied, including, without limitation, any warranties or conditions
   2.151 +      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
   2.152 +      PARTICULAR PURPOSE. You are solely responsible for determining the
   2.153 +      appropriateness of using or redistributing the Work and assume any
   2.154 +      risks associated with Your exercise of permissions under this License.
   2.155 +
   2.156 +   8. Limitation of Liability. In no event and under no legal theory,
   2.157 +      whether in tort (including negligence), contract, or otherwise,
   2.158 +      unless required by applicable law (such as deliberate and grossly
   2.159 +      negligent acts) or agreed to in writing, shall any Contributor be
   2.160 +      liable to You for damages, including any direct, indirect, special,
   2.161 +      incidental, or consequential damages of any character arising as a
   2.162 +      result of this License or out of the use or inability to use the
   2.163 +      Work (including but not limited to damages for loss of goodwill,
   2.164 +      work stoppage, computer failure or malfunction, or any and all
   2.165 +      other commercial damages or losses), even if such Contributor
   2.166 +      has been advised of the possibility of such damages.
   2.167 +
   2.168 +   9. Accepting Warranty or Additional Liability. While redistributing
   2.169 +      the Work or Derivative Works thereof, You may choose to offer,
   2.170 +      and charge a fee for, acceptance of support, warranty, indemnity,
   2.171 +      or other liability obligations and/or rights consistent with this
   2.172 +      License. However, in accepting such obligations, You may act only
   2.173 +      on Your own behalf and on Your sole responsibility, not on behalf
   2.174 +      of any other Contributor, and only if You agree to indemnify,
   2.175 +      defend, and hold each Contributor harmless for any liability
   2.176 +      incurred by, or claims asserted against, such Contributor by reason
   2.177 +      of your accepting any such warranty or additional liability.
   2.178 +
   2.179 +   END OF TERMS AND CONDITIONS
   2.180 +
   2.181 +   APPENDIX: How to apply the Apache License to your work.
   2.182 +
   2.183 +      To apply the Apache License to your work, attach the following
   2.184 +      boilerplate notice, with the fields enclosed by brackets "[]"
   2.185 +      replaced with your own identifying information. (Don't include
   2.186 +      the brackets!)  The text should be enclosed in the appropriate
   2.187 +      comment syntax for the file format. We also recommend that a
   2.188 +      file or class name and description of purpose be included on the
   2.189 +      same "printed page" as the copyright notice for easier
   2.190 +      identification within third-party archives.
   2.191 +
   2.192 +   Copyright [yyyy] [name of copyright owner]
   2.193 +
   2.194 +   Licensed under the Apache License, Version 2.0 (the "License");
   2.195 +   you may not use this file except in compliance with the License.
   2.196 +   You may obtain a copy of the License at
   2.197 +
   2.198 +       http://www.apache.org/licenses/LICENSE-2.0
   2.199 +
   2.200 +   Unless required by applicable law or agreed to in writing, software
   2.201 +   distributed under the License is distributed on an "AS IS" BASIS,
   2.202 +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   2.203 +   See the License for the specific language governing permissions and
   2.204 +   limitations under the License.
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Makefile	Mon Sep 14 15:17:45 2009 +0900
     3.3 @@ -0,0 +1,736 @@
     3.4 +# ========================================================================
     3.5 +# Copyright 1988-2008 University of Washington
     3.6 +#
     3.7 +# Licensed under the Apache License, Version 2.0 (the "License");
     3.8 +# you may not use this file except in compliance with the License.
     3.9 +# You may obtain a copy of the License at
    3.10 +#
    3.11 +#     http://www.apache.org/licenses/LICENSE-2.0
    3.12 +#
    3.13 +# 
    3.14 +# ========================================================================
    3.15 +
    3.16 +# Program:	IMAP Toolkit Makefile
    3.17 +#
    3.18 +# Author:	Mark Crispin
    3.19 +#		UW Technology
    3.20 +#		Seattle, WA  98195
    3.21 +#		Internet: MRC@Washington.EDU
    3.22 +#
    3.23 +# Date:		7 December 1989
    3.24 +# Last Edited:	12 May 2008
    3.25 +
    3.26 +
    3.27 +# Normal command to build IMAP toolkit:
    3.28 +#  make <port> [EXTRAAUTHENTICATORS=xxx] [EXTRADRIVERS=xxx] [EXTRACFLAGS=xxx]
    3.29 +#	       [PASSWDTYPE=xxx] [SSLTYPE=xxx] [IP=n]
    3.30 +
    3.31 +
    3.32 +# Port name.  These refer to the *standard* compiler on the given system.
    3.33 +# This means, for example, that the hpx port is for HP's compiler and not for
    3.34 +# a non-standard compiler such as gcc.
    3.35 +#
    3.36 +# If you are using gcc and it is not the standard compiler on your system, try
    3.37 +# using an ANSI port that is close to what you have.  For example, if your
    3.38 +# system is SVR4ish, try a32 or lnx; if it's more BSDish, try nxt, mct, or bsi.
    3.39 +#
    3.40 +# The following ports are bundled:
    3.41 +# a32	AIX 3.2 for RS/6000
    3.42 +# a41	AIX 4.1 for RS/6000
    3.43 +# aix	AIX/370 (not RS/6000!!)
    3.44 +# ami	AmigaDOS
    3.45 +# am2	AmigaDOS with a 68020+
    3.46 +# ama	AmigaDOS using AS225R2
    3.47 +# amn	AmigaDOS with a 680x0 using "new" socket library
    3.48 +# aos	AOS for RT
    3.49 +# art	AIX 2.2.1 for RT
    3.50 +# asv	Altos SVR4
    3.51 +# aux	A/UX
    3.52 +# bs3	BSD/i386 3.0 and higher
    3.53 +# bsd	generic BSD 4.3 (as in ancient 1980s version)
    3.54 +# bsf	FreeBSD
    3.55 +# bsi	BSD/i386
    3.56 +# bso	OpenBSD (yes, yet another one...)
    3.57 +# cvx	Convex
    3.58 +# cyg	Cygwin
    3.59 +# d-g	Data General DG/UX prior to 5.4 (d41 port no longer exists)
    3.60 +# d54	Data General DG/UX 5.4
    3.61 +# do4	Apollo Domain/OS sr10.4
    3.62 +# dpx	Bull DPX/2 B.O.S.
    3.63 +# drs	ICL DRS/NX
    3.64 +# dyn	Dynix
    3.65 +# epx	EP/IX
    3.66 +# ga4	GCC AIX 4.x for RS/6000
    3.67 +# gas	GCC Altos SVR4
    3.68 +# gcs	GCC Solaris with Blastwave Community Open Source Software
    3.69 +# gh9   GCC HP-UX 9.x
    3.70 +# ghp	GCC HP-UX 10.x
    3.71 +# ghs	GCC HP-UX 10.x with Trusted Computer Base
    3.72 +# go5	GCC 2.7.1 (95q4 from Skunkware _not_ 98q2!) SCO Open Server 5.0.x
    3.73 +# gsc	GCC Santa Cruz Operation
    3.74 +# gsg	GCC SGI
    3.75 +# gso	GCC Solaris
    3.76 +# gsu	GCC SUN-OS
    3.77 +# gul	GCC RISC Ultrix (DEC-5000)
    3.78 +# h11	HP-UX 11i
    3.79 +# hpp	HP-UX 9.x (see gh9)
    3.80 +# hpx	HP-UX 10.x (see ghp, ghs, hxd, and shp)
    3.81 +# hxd	HP-UX 10.x with DCE security (see shp)
    3.82 +# isc	Interactive Systems
    3.83 +# ldb	Debian Linux
    3.84 +# lfd	Fedora Core 4
    3.85 +# ln8	Linux for Nokia N800
    3.86 +# lnx	Linux with traditional passwords and crypt() in the C library
    3.87 +#	 (see lnp, sl4, sl5, and slx)
    3.88 +# lnp	Linux with Pluggable Authentication Modules (PAM)
    3.89 +# lmd	Mandrake Linux
    3.90 +# lr5	RedHat Enterprise 5 and later (same as lfd)
    3.91 +# lrh	RedHat Linux 7.2 and later
    3.92 +# lsu	SuSE Linux (same as lrh)
    3.93 +# lyn	LynxOS
    3.94 +# mct	MachTen
    3.95 +# mnt	Atari ST Mint (not MacMint)
    3.96 +# neb	NetBSD
    3.97 +# nec	NEC UX
    3.98 +# nto	QNX Neutrine RTP
    3.99 +# nxt	NEXTSTEP
   3.100 +# nx3	NEXTSTEP 3.x
   3.101 +# osf	OSF/1 (see sos, os4)
   3.102 +# os4	OSF/1 (Digital UNIX) 4
   3.103 +# osi	Apple iPhone and iPod Touch
   3.104 +# osx	Mac OS X
   3.105 +# oxp	Mac OS X with Pluggable Authentication Modules (PAM)
   3.106 +# ptx	PTX
   3.107 +# pyr	Pyramid
   3.108 +# qnx	QNX 4
   3.109 +# s40	SUN-OS 4.0 (*not* Solaris)
   3.110 +# sc5	SCO Open Server 5.0.x (see go5)
   3.111 +# sco	Santa Cruz Operation (see sc5, go5)
   3.112 +# shp	HP-UX with Trusted Computer Base
   3.113 +# sgi	Silicon Graphics IRIX
   3.114 +# sg6	Silicon Graphics IRIX 6.5
   3.115 +# sl4	Linux using -lshadow to get the crypt() function
   3.116 +# sl5	Linux with shadow passwords, no extra libraries
   3.117 +# slx	Linux using -lcrypt to get the crypt() function
   3.118 +# snx	Siemens Nixdorf SININX or Reliant UNIX
   3.119 +# soc	Solaris with /opt/SUNWspro/bin/cc
   3.120 +# sol	Solaris (won't work unless "ucbcc" works -- use gso instead)
   3.121 +# sos	OSF/1 with SecureWare
   3.122 +# ssn	SUN-OS with shadow password security
   3.123 +# sua	Windows Vista (Enterprise or Ultima) Subsystem for Unix Applications
   3.124 +# sun	SUN-OS 4.1 or better (*not* Solaris) (see ssn)
   3.125 +# sv2	SVR2 on AT&T PC-7300 (incomplete port)
   3.126 +# sv4	generic SVR4
   3.127 +# ult	RISC Ultrix (DEC-5000)
   3.128 +# uw2	UnixWare SVR4.2
   3.129 +# vul	VAX Ultrix
   3.130 +# vu2	VAX Ultrix 2.3 (e.g. for VAXstation-2000 or similar old version)
   3.131 +
   3.132 +
   3.133 +# Extra authenticators (e.g. OTP, Kerberos, etc.).  Adds linkage for
   3.134 +# auth_xxx.c and executes Makefile.xxx, where xxx is the name of the
   3.135 +# authenticator.  Some authenticators are only available from third parties.
   3.136 +#
   3.137 +# The following extra authenticators are bundled:
   3.138 +# gss	Kerberos V
   3.139 +
   3.140 +EXTRAAUTHENTICATORS=
   3.141 +
   3.142 +
   3.143 +# Additional mailbox drivers.  Add linkage for xxxdriver.  Some drivers are
   3.144 +# only available from third parties.
   3.145 +#
   3.146 +# The following extra drivers are bundled:
   3.147 +# mbox	if file "mbox" exists on the home directory, automatically moves mail
   3.148 +#	 from the spool directory to "mbox" and uses "mbox" as INBOX.
   3.149 +
   3.150 +EXTRADRIVERS=mbox
   3.151 +
   3.152 +
   3.153 +# Plaintext password type.  Defines how plaintext password authentication is
   3.154 +# done on this system.
   3.155 +#
   3.156 +# The following plaintext login types are bundled:
   3.157 +# afs	AFS authentication database
   3.158 +# dce	DCE authentication database
   3.159 +# gss	Kerberos V
   3.160 +# nul	plaintext authentication never permitted
   3.161 +# pam	PAM authentication (note: for Linux, you should use the "lnp" port
   3.162 +#	 instead of setting this...also, you may have to modify PAMLDFLAGS
   3.163 +#	 in the imap-[]/src/osdep/unix/Makefile
   3.164 +# pmb	PAM authentication for broken implementations such as Solaris.
   3.165 +#	 you may have to modify PAMLDFLAGS
   3.166 +# std	system standard (typically passwd file), determined by port
   3.167 +# two	try alternative (defined by CHECKPWALT), then std
   3.168 +
   3.169 +PASSWDTYPE=std
   3.170 +
   3.171 +
   3.172 +# SSL type.  Defines whether or not SSL support is on this system
   3.173 +#
   3.174 +# The following SSL types are bundled:
   3.175 +# none	no SSL support
   3.176 +# unix	SSL support using OpenSSL
   3.177 +# nopwd	SSL support using OpenSSL, and plaintext authentication permitted only
   3.178 +#	in SSL/TLS sessions
   3.179 +# sco	link SSL before other libraries (for SCO systems)
   3.180 +# unix.nopwd	same as nopwd
   3.181 +# sco.nopwd	same as nopwd, plaintext authentication in SSL/TLS only
   3.182 +#
   3.183 +# SSLTYPE=nopwd is now the default as required by RFC 3501
   3.184 +
   3.185 +SSLTYPE=nopwd
   3.186 +
   3.187 +
   3.188 +# IP protocol version
   3.189 +#
   3.190 +# The following IP protocol versions are defined:
   3.191 +# o	IPv4 support, no DNS (truly ancient systems)
   3.192 +# 4	(default) IPv4 support only
   3.193 +# 6	IPv6 and IPv4 support
   3.194 +
   3.195 +IP=4
   3.196 +IP6=6
   3.197 +
   3.198 +
   3.199 +# The following extra compilation flags are defined.  None of these flags are
   3.200 +# recommended.  If you use these, include them in the EXTRACFLAGS.
   3.201 +#
   3.202 +# -DDISABLE_POP_PROXY
   3.203 +#	By default, the ipop[23]d servers offer POP->IMAP proxy access,
   3.204 +#	which allow a POP client to access mail on an IMAP server by using the
   3.205 +#	POP server as a go-between.  Setting this option disables this
   3.206 +#	facility.
   3.207 +#
   3.208 +# -DOLDFILESUFFIX=\"xxx\"
   3.209 +#	Change the default suffix appended to the backup .newsrc file from
   3.210 +#	"old".
   3.211 +#
   3.212 +# -DSTRICT_RFC822_TIMEZONES
   3.213 +#	Disable recognition of the non-standard UTC (0000), MET (+0100),
   3.214 +#	EET (+0200), JST (+0900), ADT (-0300), AST (-0400), YDT (-0800),
   3.215 +#	YST (-0900), and HST (-1000) symbolic timezones.
   3.216 +#
   3.217 +# -DBRITISH_SUMMER_TIME
   3.218 +#	Enables recognition of non-standard symbolic timezone BST as +0100.
   3.219 +#
   3.220 +# -DBERING_STANDARD_TIME
   3.221 +#	Enables recognition of non-standard symbolic timezone BST as -1100.
   3.222 +#
   3.223 +# -DNEWFOUNDLAND_STANDARD_TIME
   3.224 +#	Enables recognition of non-standard symbolic timezone NST as -0330.
   3.225 +#
   3.226 +# -DNOME_STANDARD_TIME
   3.227 +#	Enables recognition of non-standard symbolic timezone NST as -1100.
   3.228 +#
   3.229 +# -DSAMOA_STANDARD_TIME
   3.230 +#	Enables recognition of non-standard symbolic timezone SST as -1100.
   3.231 +#				
   3.232 +# -DY4KBUGFIX
   3.233 +#	Turn on the Y4K bugfix (yes, that's year 4000).  It isn't well-known,
   3.234 +#	but century years evenly divisible by 4000 are *not* leap years in the
   3.235 +#	Gregorian calendar.  A lot of "Y2K compilant" software does not know
   3.236 +#	about this rule.  Remember to turn this on sometime in the next 2000
   3.237 +#	years.
   3.238 +#
   3.239 +# -DUSEORTHODOXCALENDAR
   3.240 +#	Use the more accurate Eastern Orthodox calendar instead of the
   3.241 +#	Gregorian calendar.  The century years which are leap years happen
   3.242 +#	at alternating 400 and 500 year intervals without shifts every 4000
   3.243 +#	years.  The Orthodox and Gregorian calendars diverge by 1 day for
   3.244 +#	gradually-increasing intervals, starting at 2800-2900, and becoming
   3.245 +#	permanent at 48,300.
   3.246 +#
   3.247 +# -DUSEJULIANCALENDAR
   3.248 +#	Use the less accurate Julian calendar instead of the Gregorian
   3.249 +#	calendar.  Leap years are every 4 years, including century years.
   3.250 +#	My apologies to those in the English-speaking world who object to
   3.251 +#	the reform of September 2, 1752 -> September 14, 1752, since this
   3.252 +#	code still uses January 1 (which Julius Ceasar decreed as the start
   3.253 +#	of the year, which since 153 BCE was the day that Roman consuls
   3.254 +#	took office), rather than the traditional March 25 used by the
   3.255 +#	British.  As of 2005, the Julian calendar and the Gregorian calendar
   3.256 +#	diverge by 15 days.
   3.257 +
   3.258 +EXTRACFLAGS=
   3.259 +
   3.260 +
   3.261 +# Extra linker flags (additional/alternative libraries, etc.)
   3.262 +
   3.263 +EXTRALDFLAGS=
   3.264 +
   3.265 +
   3.266 +# Special make flags (e.g. to override make environment variables)
   3.267 +
   3.268 +EXTRASPECIALS=
   3.269 +SPECIALS=
   3.270 +
   3.271 +
   3.272 +# Normal commands
   3.273 +
   3.274 +CAT=cat
   3.275 +CD=cd
   3.276 +LN=ln -s
   3.277 +MAKE=make
   3.278 +MKDIR=mkdir
   3.279 +BUILDTYPE=rebuild
   3.280 +RM=rm -rf
   3.281 +SH=sh
   3.282 +SYSTEM=unix
   3.283 +TOOLS=tools
   3.284 +TOUCH=touch
   3.285 +
   3.286 +
   3.287 +# Primary build command
   3.288 +
   3.289 +BUILD=$(MAKE) build EXTRACFLAGS='$(EXTRACFLAGS)'\
   3.290 + EXTRALDFLAGS='$(EXTRALDFLAGS)'\
   3.291 + EXTRADRIVERS='$(EXTRADRIVERS)'\
   3.292 + EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\
   3.293 + PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP)\
   3.294 + EXTRASPECIALS='$(EXTRASPECIALS)'
   3.295 +
   3.296 +
   3.297 +# Make the IMAP Toolkit
   3.298 +
   3.299 +all:	c-client SPECIALS rebuild bundled
   3.300 +
   3.301 +c-client:
   3.302 +	@echo Not processed yet.  In a first-time build, you must specify
   3.303 +	@echo the system type so that the sources are properly processed.
   3.304 +	@false
   3.305 +
   3.306 +
   3.307 +SPECIALS:
   3.308 +	echo $(SPECIALS) > SPECIALS
   3.309 +
   3.310 +# Note on SCO you may have to set LN to "ln".
   3.311 +
   3.312 +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
   3.313 +	$(BUILD) BUILDTYPE=$@
   3.314 +
   3.315 +# If you use sv4, you may find that it works to move it to use the an process.
   3.316 +# If so, you probably will want to delete the "-Dconst=" from the sv4 CFLAGS in
   3.317 +# the c-client Makefile.
   3.318 +
   3.319 +aos art asv aux bsd cvx dpx dyn isc pyr sv4 ult vul vu2: ua
   3.320 +	$(BUILD) BUILDTYPE=$@
   3.321 +
   3.322 +
   3.323 +# Knotheads moved Kerberos and SSL locations on these platforms
   3.324 +
   3.325 +# Paul Vixie claims that all FreeBSD versions have working IPv6
   3.326 +
   3.327 +bsf:	an
   3.328 +	$(TOUCH) ip6
   3.329 +	$(BUILD) BUILDTYPE=$@ IP=$(IP6) \
   3.330 +	PASSWDTYPE=pam \
   3.331 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/ssl/certs SSLKEYS=/etc/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib PAMLDFLAGS=-lpam"
   3.332 +
   3.333 +# I assume that Theo did the right thing for IPv6.  OpenBSD does not have PAM.
   3.334 +
   3.335 +bso:	an
   3.336 +	$(TOUCH) ip6
   3.337 +	$(BUILD) BUILDTYPE=$@ IP=$(IP6) \
   3.338 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/ssl SSLKEYS=/etc/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib"
   3.339 +
   3.340 +# Info from Joel Reicher about NetBSD SSL paths.  I assume it has PAM because pam is in NetBSD sources...
   3.341 +
   3.342 +neb:	an
   3.343 +	$(TOUCH) ip6
   3.344 +	$(BUILD) BUILDTYPE=$@ IP=$(IP6) \
   3.345 +	PASSWDTYPE=pam \
   3.346 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/openssl/certs SSLKEYS=/etc/openssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib PAMLDFLAGS=-lpam"
   3.347 +
   3.348 +cyg:	an
   3.349 +	$(BUILD) BUILDTYPE=cyg \
   3.350 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/ssl/certs SSLKEYS=/usr/ssl/certs"
   3.351 +
   3.352 +gcs:	an
   3.353 +	$(BUILD) BUILDTYPE=gso \
   3.354 +	SPECIALS="SSLINCLUDE=/opt/csw/include/openssl SSLLIB=/opt/csw/lib SSLCERTS=/opt/csw/ssl/certs SSLKEYS=/opt/csw/ssl/certs"
   3.355 +
   3.356 +ldb:	an
   3.357 +	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
   3.358 +	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"
   3.359 +
   3.360 +lfd:	an
   3.361 +	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
   3.362 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/pki/tls/certs SSLKEYS=/etc/pki/tls/private GSSDIR=/usr/kerberos"
   3.363 +
   3.364 +ln8:	an
   3.365 +	$(TOUCH) ip6
   3.366 +	$(BUILD) BUILDTYPE=slx IP=$(IP6) \
   3.367 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/lib/ssl/certs MAILSPOOL=/var/mail"
   3.368 +
   3.369 +
   3.370 +# RHE5 does not have the IPv6 bug
   3.371 +
   3.372 +lr5:	an
   3.373 +	$(TOUCH) ip6
   3.374 +	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
   3.375 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/pki/tls/certs SSLKEYS=/etc/pki/tls/private GSSDIR=/usr/kerberos"
   3.376 +
   3.377 +lmd:	an
   3.378 +	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
   3.379 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/lib/ssl/certs SSLKEYS=/usr/lib/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib"
   3.380 +
   3.381 +# RHE3 definitely has the IPv6 bug
   3.382 +
   3.383 +lrh:	lrhok an
   3.384 +	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
   3.385 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/share/ssl/certs SSLKEYS=/usr/share/ssl/private GSSDIR=/usr/kerberos"
   3.386 +
   3.387 +lrhok:
   3.388 +	@$(SH) -c '(test ! -d /etc/pki/tls ) || make lrhwarn'
   3.389 +	@$(TOUCH) lrhok
   3.390 +
   3.391 +lrhwarn:
   3.392 +	@echo You are building for OLD versions of RedHat Linux.  This build
   3.393 +	@echo is NOT suitable for RedHat Enterprise 5, which stores SSL/TLS
   3.394 +	@echo certificates and keys in /etc/pki/tls rather than /usr/share/ssl.
   3.395 +	@echo If you want to build for modern RedHat Linux, you should use
   3.396 +	@echo make lr5 instead.
   3.397 +	@echo Do you want to continue this build?  Type y or n please:
   3.398 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
   3.399 +	@echo OK, I will remember that you really want to build for old
   3.400 +	@echo RedHat Linux.  You will not see this message again.
   3.401 +	@echo If you realize that you really wanted to build for modern
   3.402 +	@echo RedHat Linux, then do the following commands:
   3.403 +	@echo % rm lrhok
   3.404 +	@echo % make clean
   3.405 +	@echo % make lr5
   3.406 +
   3.407 +lsu:	an
   3.408 +	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
   3.409 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/share/ssl/certs SSLKEYS=/usr/share/ssl/private GSSDIR=/usr/kerberos"
   3.410 +
   3.411 +# iToy does not have Kerberos or PAM.  It doesn't have a
   3.412 +# /System/Library/OpenSSL directory either, but the libcrypto shared library
   3.413 +# has these locations so this is what we will use.
   3.414 +
   3.415 +osi:	an
   3.416 +	$(TOUCH) ip6
   3.417 +	$(BUILD) BUILDTYPE=osx IP=$(IP6) CC=arm-apple-darwin-gcc \
   3.418 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/System/Library/OpenSSL/certs SSLKEYS=/System/Library/OpenSSL/private"
   3.419 +
   3.420 +oxp:	an
   3.421 +	$(TOUCH) ip6
   3.422 +	$(BUILD) BUILDTYPE=osx IP=$(IP6) EXTRAAUTHENTICATORS="$(EXTRAAUTHENTICATORS) gss" \
   3.423 +	PASSWDTYPE=pam \
   3.424 +	EXTRACFLAGS="$(EXTRACFLAGS) -DMAC_OSX_KLUDGE=1" \
   3.425 +	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"
   3.426 +
   3.427 +osx:	osxok an
   3.428 +	$(TOUCH) ip6
   3.429 +	$(BUILD) BUILDTYPE=$@ IP=$(IP6) EXTRAAUTHENTICATORS="$(EXTRAAUTHENTICATORS) gss" \
   3.430 +	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/System/Library/OpenSSL/certs SSLKEYS=/System/Library/OpenSSL/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib"
   3.431 +
   3.432 +osxok:
   3.433 +	@$(SH) -c '(test ! -f /usr/include/pam/pam_appl.h ) || make osxwarn'
   3.434 +	@$(TOUCH) osxok
   3.435 +
   3.436 +osxwarn:
   3.437 +	@echo You are building for OLD versions of Mac OS X.  This build is
   3.438 +	@echo NOT suitable for modern versions of Mac OS X, such as Tiger,
   3.439 +	@echo which use PAM-based authentication.  If you want to build for
   3.440 +	@echo modern Mac OS X, you should use make oxp instead.
   3.441 +	@echo Do you want to continue this build?  Type y or n please:
   3.442 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
   3.443 +	@echo OK, I will remember that you really want to build for old
   3.444 +	@echo Mac OS X.  You will not see this message again.
   3.445 +	@echo If you realize that you really wanted to build for modern
   3.446 +	@echo Mac OS X, then do the following commands:
   3.447 +	@echo % rm osxok
   3.448 +	@echo % make clean
   3.449 +	@echo % make oxp
   3.450 +
   3.451 +
   3.452 +# Linux shadow password support doesn't build on traditional systems, but most
   3.453 +# Linux systems are shadow these days.
   3.454 +
   3.455 +lnx:	lnxnul an
   3.456 +	$(BUILD) BUILDTYPE=$@
   3.457 +
   3.458 +lnxnul:
   3.459 +	@$(SH) -c '(test $(PASSWDTYPE) = nul) || make lnxok'
   3.460 +
   3.461 +lnxok:
   3.462 +	@echo You are building for traditional Linux.  Most modern Linux
   3.463 +	@echo systems require that you build using make slx.
   3.464 +	@echo Do you want to continue this build?  Type y or n please:
   3.465 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
   3.466 +	@echo OK, I will remember that you really want to build for
   3.467 +	@echo traditional Linux.  You will not see this message again.
   3.468 +	@echo If you discover that you can not log in to the POP and IMAP
   3.469 +	@echo servers, then do the following commands:
   3.470 +	@echo % rm lnxok
   3.471 +	@echo % make clean
   3.472 +	@echo % make slx
   3.473 +	@echo If slx does not work, try sl4 or sl5.  Be sure to do a
   3.474 +	@echo make clean between each try!
   3.475 +	@$(TOUCH) lnxok
   3.476 +
   3.477 +
   3.478 +# SUN-OS C compiler makes you load libdl by hand...
   3.479 +
   3.480 +ssn sun: sunok suntools ua
   3.481 +	$(BUILD) BUILDTYPE=$@
   3.482 +
   3.483 +suntools:
   3.484 +	$(CD) tools;$(MAKE) LDFLAGS=-ldl
   3.485 +
   3.486 +gsu:	sunok an
   3.487 +	$(BUILD) BUILDTYPE=$@
   3.488 +
   3.489 +s40:	sunok ua
   3.490 +	$(BUILD) BUILDTYPE=$@
   3.491 +
   3.492 +sunok:
   3.493 +	@echo You are building for the old BSD-based SUN-OS.  This is NOT
   3.494 +	@echo the modern SVR4-based Solaris.  If you want to build for
   3.495 +	@echo Solaris, you should use make gso or make sol or make soc.  Do
   3.496 +	@echo you want to continue this build?  Type y or n please:
   3.497 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
   3.498 +	@echo OK, I will remember that you really want to build for the old
   3.499 +	@echo BSD-based SUN-OS.  You will not see this message again.
   3.500 +	@echo If the build fails and you realize that you really wanted to
   3.501 +	@echo build for Solaris, then do the following commands:
   3.502 +	@echo % rm sunok
   3.503 +	@echo % make clean
   3.504 +	@echo % make gso
   3.505 +	@echo If gso does not work, try sol.  Be sure to do a make clean
   3.506 +	@echo between each try!
   3.507 +	@$(TOUCH) sunok
   3.508 +
   3.509 +
   3.510 +# SVR2 doesn't have symbolic links (at least my SVR2 system doesn't)
   3.511 +
   3.512 +sv2:
   3.513 +	$(MAKE) ua LN=ln
   3.514 +	$(BUILD) BUILDTYPE=$@ LN=ln
   3.515 +
   3.516 +# Hard links don't quite work right in SUA, and there don't seem to be any
   3.517 +# SSL includes.  However, IPv6 works.
   3.518 +
   3.519 +sua:
   3.520 +	$(TOUCH) ip6 sslnone
   3.521 +	$(MAKE) an LN=cp SSLTYPE=none
   3.522 +	$(BUILD) BUILDTYPE=$@ LN=cp IP=$(IP6) SSLTYPE=none
   3.523 +
   3.524 +
   3.525 +# Pine port names, not distinguished in c-client
   3.526 +
   3.527 +bs2:	an
   3.528 +	$(BUILD) BUILDTYPE=bsi
   3.529 +
   3.530 +pt1:	an
   3.531 +	$(BUILD) BUILDTYPE=ptx
   3.532 +
   3.533 +
   3.534 +# Compatibility
   3.535 +
   3.536 +hxd:
   3.537 +	$(BUILD) BUILDTYPE=hpx PASSWDTYPE=dce
   3.538 +
   3.539 +# Amiga
   3.540 +
   3.541 +ami am2 ama amn:
   3.542 +	$(MAKE) an LN=cp SYSTEM=amiga
   3.543 +	$(BUILD) BUILDTYPE=$@ LN=cp
   3.544 +
   3.545 +
   3.546 +# Courtesy entries for Microsoft systems
   3.547 +
   3.548 +nt:
   3.549 +	nmake /nologo /f makefile.nt
   3.550 +
   3.551 +ntk:
   3.552 +	nmake /nologo /f makefile.ntk
   3.553 +
   3.554 +w2k:
   3.555 +	nmake /nologo /f makefile.w2k
   3.556 +
   3.557 +wce:
   3.558 +	nmake /nologo /f makefile.wce
   3.559 +
   3.560 +
   3.561 +# SSL build choices
   3.562 +
   3.563 +sslnopwd sslunix.nopwd sslsco.nopwd:
   3.564 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.565 +	@echo + Building in full compliance with RFC 3501 security
   3.566 +	@echo + requirements:
   3.567 +	@echo ++ TLS/SSL encryption is supported
   3.568 +	@echo ++ Unencrypted plaintext passwords are prohibited
   3.569 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.570 +
   3.571 +sslunix sslsco:
   3.572 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.573 +	@echo + Building in PARTIAL compliance with RFC 3501 security
   3.574 +	@echo + requirements:
   3.575 +	@echo + Compliant:
   3.576 +	@echo ++ TLS/SSL encryption is supported
   3.577 +	@echo + Non-compliant:
   3.578 +	@echo ++ Unencrypted plaintext passwords are permitted
   3.579 +	@echo +
   3.580 +	@echo + In order to rectify this problem, you MUST build with:
   3.581 +	@echo ++ SSLTYPE=$(SSLTYPE).nopwd
   3.582 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.583 +	@echo
   3.584 +	@echo Do you want to continue this build anyway?  Type y or n please:
   3.585 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) (make nounenc;exit 1);; esac'
   3.586 +
   3.587 +nounenc:
   3.588 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.589 +	@echo + At your request, this build with unencrypted authentication has
   3.590 +	@echo + been CANCELLED.
   3.591 +	@echo + You must start over with a new make command.
   3.592 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.593 +
   3.594 +
   3.595 +sslnone:
   3.596 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.597 +	@echo + Building in NON-COMPLIANCE with RFC 3501 security requirements:
   3.598 +	@echo + Non-compliant:
   3.599 +	@echo ++ TLS/SSL encryption is NOT supported
   3.600 +	@echo ++ Unencrypted plaintext passwords are permitted
   3.601 +	@echo +
   3.602 +	@echo + In order to rectify this problem, you MUST build with:
   3.603 +	@echo ++ SSLTYPE=nopwd
   3.604 +	@echo + You must also have OpenSSL or equivalent installed.
   3.605 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.606 +	@echo
   3.607 +	@echo Do you want to continue this build anyway?  Type y or n please:
   3.608 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) (make nonossl;exit 1);; esac'
   3.609 +
   3.610 +nonossl:
   3.611 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.612 +	@echo + At your request, this build with no TLS/SSL support has been
   3.613 +	@echo + CANCELLED.
   3.614 +	@echo + You must start over with a new make command.
   3.615 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.616 +
   3.617 +
   3.618 +# IP build choices
   3.619 +
   3.620 +ip4:
   3.621 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.622 +	@echo + Building with IPv4 support
   3.623 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.624 +
   3.625 +ip6:
   3.626 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.627 +	@echo + Building with IPv6 support
   3.628 +	@echo +
   3.629 +	@echo + NOTE: Some versions of glibc have a bug in the getaddrinfo
   3.630 +	@echo + call which does DNS name resolution.  This bug causes host
   3.631 +	@echo + names to be canonicalized incorrectly, as well as doing an
   3.632 +	@echo + unnecessary and performance-sapping reverse DNS call.  This
   3.633 +	@echo + problem does not affect the IPv4 gethostbyname call.
   3.634 +	@echo +
   3.635 +	@echo + getaddrinfo works properly on Mac OS X and Windows.  However,
   3.636 +	@echo + the problem has been observed on some Linux systems.
   3.637 +	@echo +
   3.638 +	@echo + If you answer n to the following question the build will be
   3.639 +	@echo + cancelled and you must rebuild.  If you did not specify IPv6
   3.640 +	@echo + yourself, try adding IP6=4 to the make command line.
   3.641 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.642 +	@echo
   3.643 +	@echo Do you want to build with IPv6 anyway?  Type y or n please:
   3.644 +	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) (make noip6;exit 1);; esac'
   3.645 +	@echo OK, I will remember that you really want to build with IPv6.
   3.646 +	@echo You will not see this message again.
   3.647 +	@$(TOUCH) ip6
   3.648 +
   3.649 +noip6:
   3.650 +	$(MAKE) clean
   3.651 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.652 +	@echo + At your request, this build with IPv6 has been CANCELLED.
   3.653 +	@echo + You must start over with a new make command.
   3.654 +	@echo +
   3.655 +	@echo + If you wish to rebuild without IPv6 support, do one of the
   3.656 +	@echo + following:
   3.657 +	@echo +
   3.658 +	@echo + 1. If you specified IP=6 on the make command line, omit it.
   3.659 +	@echo +
   3.660 +	@echo + 2. Some of the Linux builds automatically select IPv6.  If
   3.661 +	@echo + you choose one of those builds, add IP6=4 to the make command
   3.662 +	@echo + line.  Note that this is IP6=4, not IP=4.
   3.663 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.664 +
   3.665 +# C compiler types
   3.666 +
   3.667 +an ua:
   3.668 +	@$(MAKE) ssl$(SSLTYPE)
   3.669 +	@echo Applying $@ process to sources...
   3.670 +	$(TOOLS)/$@ "$(LN)" src/c-client c-client
   3.671 +	$(TOOLS)/$@ "$(LN)" src/ansilib c-client
   3.672 +	$(TOOLS)/$@ "$(LN)" src/charset c-client
   3.673 +	$(TOOLS)/$@ "$(LN)" src/osdep/$(SYSTEM) c-client
   3.674 +	$(TOOLS)/$@ "$(LN)" src/mtest mtest
   3.675 +	$(TOOLS)/$@ "$(LN)" src/ipopd ipopd
   3.676 +	$(TOOLS)/$@ "$(LN)" src/imapd imapd
   3.677 +	$(TOOLS)/$@ "$(LN)" src/mailutil mailutil
   3.678 +	$(TOOLS)/$@ "$(LN)" src/mlock mlock
   3.679 +	$(TOOLS)/$@ "$(LN)" src/dmail dmail
   3.680 +	$(TOOLS)/$@ "$(LN)" src/tmail tmail
   3.681 +	$(LN) $(TOOLS)/$@ .
   3.682 +
   3.683 +build:	OSTYPE rebuild rebuildclean bundled
   3.684 +
   3.685 +OSTYPE:
   3.686 +	@$(MAKE) ip$(IP)
   3.687 +	@echo Building c-client for $(BUILDTYPE)...
   3.688 +	@$(TOUCH) SPECIALS
   3.689 +	echo `$(CAT) SPECIALS` $(EXTRASPECIALS) > c-client/SPECIALS
   3.690 +	$(CD) c-client;$(MAKE) $(BUILDTYPE) EXTRACFLAGS='$(EXTRACFLAGS)'\
   3.691 +	 EXTRALDFLAGS='$(EXTRALDFLAGS)'\
   3.692 +	 EXTRADRIVERS='$(EXTRADRIVERS)'\
   3.693 +	 EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\
   3.694 +	 PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP)\
   3.695 +	 $(SPECIALS) $(EXTRASPECIALS)
   3.696 +	echo $(BUILDTYPE) > OSTYPE
   3.697 +	$(TOUCH) rebuild
   3.698 +
   3.699 +rebuild:
   3.700 +	@$(SH) -c '(test $(BUILDTYPE) = rebuild -o $(BUILDTYPE) = `$(CAT) OSTYPE`) || (echo Already built for `$(CAT) OSTYPE` -- you must do \"make clean\" first && exit 1)'
   3.701 +	@echo Rebuilding c-client for `$(CAT) OSTYPE`...
   3.702 +	@$(TOUCH) SPECIALS
   3.703 +	$(CD) c-client;$(MAKE) all CC=`$(CAT) CCTYPE` \
   3.704 +	 CFLAGS="`$(CAT) CFLAGS`" `$(CAT) SPECIALS`
   3.705 +
   3.706 +rebuildclean:
   3.707 +	$(SH) -c '$(RM) rebuild || true'
   3.708 +
   3.709 +bundled:
   3.710 +	@echo Building bundled tools...
   3.711 +	$(CD) mtest;$(MAKE)
   3.712 +	$(CD) ipopd;$(MAKE)
   3.713 +	$(CD) imapd;$(MAKE)
   3.714 +	$(CD) mailutil;$(MAKE)
   3.715 +	@$(SH) -c '(test -f /usr/include/sysexits.h ) || make sysexitwarn'
   3.716 +	$(CD) mlock;$(MAKE) || true
   3.717 +	$(CD) dmail;$(MAKE) || true
   3.718 +	$(CD) tmail;$(MAKE) || true
   3.719 +
   3.720 +
   3.721 +sysexitwarn:
   3.722 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.723 +	@echo + Hmm...it does not look like /usr/include/sysexits.h exists.
   3.724 +	@echo + Either your system is too ancient to have the sysexits.h
   3.725 +	@echo + include, or your C compiler gets it from some other location
   3.726 +	@echo + than /usr/include.  If your system is too old to have the
   3.727 +	@echo + sysexits.h include, you will not be able to build the
   3.728 +	@echo + following programs.
   3.729 +	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   3.730 +
   3.731 +clean:
   3.732 +	@echo Removing old processed sources and binaries...
   3.733 +	$(SH) -c '$(RM) an ua OSTYPE SPECIALS c-client mtest imapd ipopd mailutil mlock dmail tmail || true'
   3.734 +	$(CD) tools;$(MAKE) clean
   3.735 +
   3.736 +
   3.737 +# A monument to a hack of long ago and far away...
   3.738 +love:
   3.739 +	@echo not war?
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/NOTICE	Mon Sep 14 15:17:45 2009 +0900
     4.3 @@ -0,0 +1,17 @@
     4.4 +UW IMAP toolkit notices:
     4.5 +
     4.6 +This software was developed by the University of Washington
     4.7 +(http://www.washington.edu/).
     4.8 +
     4.9 +The Univerity of Washington IMAP Toolkit (c-client API, dmail, imapd,
    4.10 +ipop2d, ipop3d, mailutil, mlock, mtest, and tmail software; and its
    4.11 +included text) is Copyright 1988-2007 by the University of Washington.
    4.12 +
    4.13 +The c-client library and mtest software are in part based upon code
    4.14 +developed by Mark Crispin at Stanford University, and is
    4.15 +
    4.16 + * Copyright 1988 Stanford University and was developed in the
    4.17 + * Symbolic Systems Resources Group of the Knowledge Systems Laboratory
    4.18 + * at Stanford University in 1987-88, and was funded by the
    4.19 + * Biomedical Research Technology Program of the National Institutes of
    4.20 + * Health under grant number RR-00785.
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/README	Mon Sep 14 15:17:45 2009 +0900
     5.3 @@ -0,0 +1,74 @@
     5.4 +/* ========================================================================
     5.5 + * Copyright 1988-2007 University of Washington
     5.6 + *
     5.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     5.8 + * you may not use this file except in compliance with the License.
     5.9 + * You may obtain a copy of the License at
    5.10 + *
    5.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    5.12 + *
    5.13 + * 
    5.14 + * ========================================================================
    5.15 + */
    5.16 +
    5.17 +			   IMAP Toolkit Environment
    5.18 +			         4 April 2007
    5.19 +				 Mark Crispin
    5.20 +
    5.21 +
    5.22 +			    UNIX QUICK BUILD NOTES
    5.23 +
    5.24 +These quick build notes assume that you have installed OpenSSL before
    5.25 +attempting to build this software, and that you do not have any non-default
    5.26 +configuration parameters.
    5.27 +
    5.28 +If you need additional information in building this software with OpenSSL,
    5.29 +please refer to the docs/SSLBUILD file for more information.
    5.30 +
    5.31 +If you intend to build this software with a non-default configuration
    5.32 +(including building a non-compliant server without SSL support), please
    5.33 +refer to the docs/BUILD file for more information.
    5.34 +
    5.35 +1) Look in the top-level Makefile and find your system type code.  For example,
    5.36 +   modern versions of Linux will use either "slx", "lnp", or one of the
    5.37 +   lnp-variants (such as "lrh").
    5.38 +
    5.39 +2) Type "make" followed by the system type, e.g. "make slx".
    5.40 +
    5.41 +3) Install the POP2 daemon (ipopd/ipop2d), the POP3 daemon (ipopd/ipop3d), and
    5.42 +   the IMAP daemon (imapd/imapd) on a system directory of your choosing.
    5.43 +
    5.44 +4) Update /etc/services to register the pop2 service on TCP port 109, the
    5.45 +   pop3 service on TCP port 110, and the imap service on TCP port 143.  Also
    5.46 +   update Yellow Pages/NIS/NetInfo/etc. if appropriate on your system.
    5.47 +
    5.48 +5) Update /etc/inetd.conf (or install files on /etc/xinetd.d) to invoke the
    5.49 +   POP2, POP3, and IMAP daemons on their associated services.
    5.50 +
    5.51 +6) If your system uses PAM authentication, be sure to set up /etc/pam.d/imap
    5.52 +   (*not* /etc/pam.d/imapd) and /etc/pam.d/pop (*not* /etc/pam.d/ipop3d or
    5.53 +   /etc/pam.d/pop3d or /etc/pam.d/popd or /etc/pam.d/pop3).
    5.54 +
    5.55 +7) Unless you built your system without SSL support, you will need to set
    5.56 +   up SSL server certificates as described in docs/SSLBUILD.
    5.57 +
    5.58 +6) That's all!
    5.59 +
    5.60 +Read the file docs/BUILD and docs/SSLBUILD if you need more detailed
    5.61 +information and/or you don't understand these quick build instructions.
    5.62 +
    5.63 +			     MISCELLANEOUS NOTES
    5.64 +
    5.65 +     mtest has been run under UNIX, DOS, Windows, NT, Macintosh, TOPS-20, and
    5.66 +VMS.  It is a very primitive interface, however, and is suited mainly as a
    5.67 +model of how to write a main program for c-client.  You should take a look at
    5.68 +the source to figure out how to use it.  Briefly, it first asks for a mailbox
    5.69 +name (either a local file path or an IMAP mailbox in the form
    5.70 +"{hostname}mailbox") and then puts you in a command mode where "?" will give
    5.71 +you a list of commands.
    5.72 +
    5.73 +     Pine is available separately on the FTP.CAC.Washington.EDU archives.
    5.74 +
    5.75 +     The focus of development and support is for UNIX and Win32 (including
    5.76 +Windows 95/98/Millenium, Windows NT, and Windows 2000).  The other ports are
    5.77 +not frequently used or tested, and may be incomplete.
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/SUPPORT	Mon Sep 14 15:17:45 2009 +0900
     6.3 @@ -0,0 +1,22 @@
     6.4 +/* ========================================================================
     6.5 + * Copyright 1988-2006 University of Washington
     6.6 + *
     6.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     6.8 + * you may not use this file except in compliance with the License.
     6.9 + * You may obtain a copy of the License at
    6.10 + *
    6.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    6.12 + *
    6.13 + * 
    6.14 + * ========================================================================
    6.15 + */
    6.16 +
    6.17 +			     BUG REPORTING ADDRESS
    6.18 +
    6.19 +     Bug reports, comments, or questions regarding this software may
    6.20 +be reported to the imap-uw@u.washington.edu mailing list (this replaces
    6.21 +the old c-client@u.washington.edu mailing list).  You can subscribe to
    6.22 +this list by sending a message to:
    6.23 +	imap-uw-subscribe@mailman.u.washington.edu
    6.24 +
    6.25 +     An alternative is to use the comp.mail.imap newsgroup.
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/docs/BUILD	Mon Sep 14 15:17:45 2009 +0900
     7.3 @@ -0,0 +1,491 @@
     7.4 +/* ========================================================================
     7.5 + * Copyright 1988-2007 University of Washington
     7.6 + *
     7.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     7.8 + * you may not use this file except in compliance with the License.
     7.9 + * You may obtain a copy of the License at
    7.10 + *
    7.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    7.12 + *
    7.13 + * 
    7.14 + * ========================================================================
    7.15 + */
    7.16 +
    7.17 +			 BUILD AND INSTALLATION NOTES
    7.18 +			 Last Updated: 15 November 2007
    7.19 +
    7.20 +Table of Contents:
    7.21 +1. UNIX Build Notes
    7.22 +2. UNIX Installation Notes
    7.23 +3. Win32 Build Notes
    7.24 +4. Win32 Installation Notes
    7.25 +5. Inactive Ports (TOPS-20, VMS)
    7.26 +6. Other ports (Macintosh, DOS/Win16, Windows CE, Amiga, OS/2)
    7.27 +
    7.28 +
    7.29 +			       UNIX BUILD NOTES
    7.30 +
    7.31 +     The default build on many systems with IPv4 only.  To build with IPv6,
    7.32 +add "IP=6" to the make command line, e.g.
    7.33 +	make lnp IP=6
    7.34 +
    7.35 +     The default build is to build with SSL and disabling plaintext passwords
    7.36 +unless SSL/TLS encryption is in effect (SSLTYPE=nopwd).  This means that
    7.37 +OpenSSL MUST be installed before building the IMAP toolkit.  Please refer to
    7.38 +the SSLBUILD file for more information.
    7.39 +
    7.40 +     To build without SSL, add "SSLTYPE=none" to the make command line.
    7.41 +Note that doing so will produce an IMAP server which is NON-COMPLIANT with
    7.42 +RFC 3501.
    7.43 +
    7.44 +     You must build through the top-level imap-2007/Makefile, which will run
    7.45 +a "process" step the first time and create the imap-2007/c-client,
    7.46 +imap-2007/ipopd, and imap-2007/imapd directories in which building actually
    7.47 +takes place.
    7.48 +
    7.49 +     Before doing a make on UNIX, you should read imap-2007/Makefile and see
    7.50 +if your system type is known.  The various system types are three-letter codes.
    7.51 +If your system type is known, then use this as the make option.  After the
    7.52 +first time you do a make, this option is remembered in a file called OSTYPE,
    7.53 +so just typing "make" suffices.
    7.54 +
    7.55 +     For example, if you are using a more or less modern Linux system, your
    7.56 +system type is probably one of the specific distribution types (such as lrh for
    7.57 +RedHat).  For more generic builds, try slx (shadow passwords only) or lnp (PAM).
    7.58 +To build for RedHat, do:
    7.59 +	make lrh
    7.60 +
    7.61 +     There are other make options, described in imap-2007/src/osdep/Makefile.
    7.62 +
    7.63 +     It's probably best to see if an existing port will work on your system
    7.64 +before inventing a new port.  Try:
    7.65 +	sv4		generic SVR4, non-ANSI compiler
    7.66 +	a32		modern SVR4
    7.67 +	bsd		basic 4.3 BSD, non-ANSI compiler
    7.68 +	bsf		modern BSD
    7.69 +
    7.70 +     If you must invent a new port, you need to create an entry in
    7.71 +imap-2007/Makefile and imap-2007/src/osdep/Makefile for your new port, as
    7.72 +well as osdep/os_???.h and osdep/os_???.c files with the appropriate
    7.73 +OS-dependent support for that system.  You also need to determine which setup
    7.74 +process to use.  You should use the ua process unless you are sure that your
    7.75 +compiler supports *ALL* aspects of ANSI C prototyping.  Note that some
    7.76 +compilers, such as Ultrix, support some aspects of ANSI C but not others;
    7.77 +c-client really beats on the full prototyping capability of ANSI C so you
    7.78 +have to use the non-ANSI source tree for such systems.
    7.79 +
    7.80 +     If you send a new port back to us, we will make it available for others
    7.81 +who use your particular system type.
    7.82 +
    7.83 +     The mbox driver is now enabled by default.  If the file "mbox" exists on
    7.84 +the user's home directory and is in UNIX mailbox format, then when INBOX is
    7.85 +opened this file will be selected as INBOX instead of the mail spool file.
    7.86 +Messages will be automatically transferred from the mail spool file into the
    7.87 +mbox file.  To disable this behavior, delete "mbox" from the EXTRADRIVERS list
    7.88 +in the top-level Makefile and rebuild.
    7.89 +
    7.90 +     WARNING: The SVR2 (sv2) port is *incomplete*.  SVR2 does not appear to
    7.91 +have any way to do ftruncate(), which is needed by the mbox, mbx, mmdf, mtx,
    7.92 +tenex, and unix drivers.
    7.93 +
    7.94 +			   UNIX INSTALLATION NOTES
    7.95 +
    7.96 +     Binaries from the build are:
    7.97 +	imap-2007/mtest/mtest		c-client testbed program
    7.98 +	imap-2007/ipopd/ipop2d		POP2 daemon
    7.99 +	imap-2007/ipopd/ipop3d		POP3 daemon
   7.100 +	imap-2007/imapd/imapd		IMAP4rev1 daemon
   7.101 +
   7.102 +     mtest is normally not used except by c-client developers.
   7.103 +
   7.104 +STEP 1:	[x]inetd setup
   7.105 +
   7.106 +     The ipop2d, ipop3d, and imapd daemons should be installed in a system
   7.107 +daemon directory and invoked by a listener such as xinetd or inetd.  In the
   7.108 +following examples, /usr/local/etc is used).
   7.109 +
   7.110 +STEP 1(A): xinetd-specific setup
   7.111 +
   7.112 +     If your system uses xinetd, the daemons are invoked by files in your
   7.113 +/etc/xinetd.d directory with names corresponding to the service names (that
   7.114 +is: imap, pop2, pop3).  You will need to consult your local xinetd
   7.115 +documentation to see what should go into these files.  Here is a a sample
   7.116 +/etc/xinetd.d/imap file:
   7.117 +
   7.118 +service imap
   7.119 +{
   7.120 +	disable		= no
   7.121 +	socket_type	= stream
   7.122 +	wait		= no
   7.123 +	user		= root
   7.124 +	server		= /usr/local/etc/imapd
   7.125 +	groups		= yes
   7.126 +	flags		= REUSE IPv6
   7.127 +}
   7.128 +
   7.129 +STEP 1(B): inetd-specific setup
   7.130 +
   7.131 +     If your system still uses inetd, the daemons are invoked by your
   7.132 +/etc/inetd.conf file with lines such as:
   7.133 +
   7.134 +pop	stream	tcp	nowait	root	/usr/local/etc/ipop2d	ipop2d
   7.135 +pop3	stream	tcp	nowait	root	/usr/local/etc/ipop3d	ipop3d
   7.136 +imap	stream	tcp	nowait	root	/usr/local/etc/imapd	imapd
   7.137 +
   7.138 +     Note that different variants of UNIX have different versions of inetd,
   7.139 +so you should verify the precise form of these commands (for example, some
   7.140 +versions of inetd do not require the "nowait").
   7.141 +
   7.142 +     IMPORTANT NOTE: inetd has a limit of how many new connections it will
   7.143 +allow in a certain interval, and when this limit is exceeded, it shuts down
   7.144 +the server.  If you have anything beyond a small-scale server, you are
   7.145 +probably going to run up against this limit.  You'll know when it happens;
   7.146 +your syslog will give the misleading message "imap/tcp server failing
   7.147 +(looping), service terminated" and users will complain that IMAP service is
   7.148 +unavailable for the next 10 minutes.  Similarly with "pop3/tcp server
   7.149 +failing"...
   7.150 +
   7.151 +     It must be emphasized that this is *NOT* a bug in the IMAP or POP
   7.152 +servers, nor is it anything that I can "fix".  It is an inetd problem, and
   7.153 +the only way to fix it is to change inetd's behavior.
   7.154 +
   7.155 +     By default, the parameters of this limit are (from inetd.c source code):
   7.156 +
   7.157 +#define TOOMANY         40              /* don't start more than TOOMANY */
   7.158 +#define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
   7.159 +#define RETRYTIME       (60*10)         /* retry after bind or server fail */
   7.160 +
   7.161 +That is, no more than 40 connections (TOOMANY) in 60 seconds (CNT_INTL), and
   7.162 +if exceeded, shut down the server for 10 minutes (RETRYTIME).  This was a
   7.163 +good setting in the 1980s ARPAnet, but is much too small today.
   7.164 +
   7.165 +     Some versions of inetd allow you to see a higher maximum in the
   7.166 +/etc/inetd.conf file.  Read "man inetd" and see if you see something like
   7.167 +this in the text:
   7.168 +
   7.169 +     The wait/nowait entry is applicable to datagram sockets only [...]
   7.170 +     [...]  The optional ``max'' suffix (separated from
   7.171 +     ``wait'' or ``nowait'' by a dot) specifies the maximum number of server
   7.172 +     instances that may be spawned from inetd within an interval of 60 sec-
   7.173 +     onds. When omitted, ``max'' defaults to 40.
   7.174 +
   7.175 +If you see this, then edit the /etc/inetd.conf entry for imapd to be
   7.176 +something like:
   7.177 +
   7.178 +imap	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
   7.179 + (or, if you use TCP wrappers)
   7.180 +imap	stream	tcp	nowait.100	root	/usr/local/etc/tcpd	imapd
   7.181 +
   7.182 +     Otherwise, you'll need to edit the inetd source code to set TOOMANY to a
   7.183 +higher value, then rebuild inetd.
   7.184 +
   7.185 +
   7.186 +STEP 2:	services setup
   7.187 +
   7.188 +     You may also have to edit your /etc/services (or Yellow Pages,
   7.189 +NetInfo, etc. equivalent) to register these services, such as:
   7.190 +
   7.191 +pop		109/tcp
   7.192 +pop3		110/tcp
   7.193 +imap		143/tcp
   7.194 +
   7.195 +
   7.196 +STEP 3: PAM setup
   7.197 +
   7.198 +     If your system has PAM (Pluggable Authentication Modules -- most
   7.199 +modern systems do) then you need to set up PAM authenticators for imap and
   7.200 +pop.  The correct file names are
   7.201 +	/etc/pam.d/imap
   7.202 +and
   7.203 +	/etc/pam.d/pop
   7.204 +
   7.205 +     It probably works to copy your /etc/pam.d/ftpd file to the above two
   7.206 +names.
   7.207 +
   7.208 +     Many people get these file names wrong, and then spend a lot of time
   7.209 +trying to figure out why it doesn't work.  Common mistakes are:
   7.210 +	/etc/pam.d/imapd
   7.211 +	/etc/pam.d/imap4
   7.212 +	/etc/pam.d/imap4rev1
   7.213 +	/etc/pam.d/ipop3d
   7.214 +	/etc/pam.d/pop3d
   7.215 +	/etc/pam.d/popd
   7.216 +	/etc/pam.d/pop3
   7.217 +
   7.218 +
   7.219 +STEP 4:	optional rimap setup
   7.220 +
   7.221 +     If you want to enable the rimap capability, which allows users with a
   7.222 +suitable client and .rhosts file on the server to access IMAP services
   7.223 +without transmitting her password in the clear over the network, you need
   7.224 +to have /etc/rimapd as a link to the real copy of imapd.  Assuming you have
   7.225 +imapd installed on /usr/local/etc as above:
   7.226 +	% ln -s /usr/local/etc/imapd /etc/rimapd
   7.227 +
   7.228 +     Technical note: rimap works by having the client routine tcp_aopen()
   7.229 +invoke `rsh _host_ exec /etc/rimapd' in an child process, and then returning
   7.230 +pipes to that process' standard I/O instead of a TCP socket.  You can set up
   7.231 +`e-mail only accounts' by making the shell be something which accepts only
   7.232 +that string and not ordinary UNIX shell commands.
   7.233 +
   7.234 +
   7.235 +STEP 4:	notes on privileges
   7.236 +
   7.237 +     Neither user "root", not any other UID 0 account, can log in via IMAP or
   7.238 +POP.  "That's not a bug, it's a feature!"
   7.239 +
   7.240 +     This software is designed to run without privileges.  The mail spool
   7.241 +directory must be protected 1777; that is, with world write and the sticky
   7.242 +bit.  Of course, mail *files* should be protected 600!
   7.243 +
   7.244 +     An alternative to having the mail spool directory protected 1777, at the
   7.245 +cost of some performance, is to use the external "mlock" program, available
   7.246 +as part of the imap-utils package.  With mlock installed as /etc/mlock and
   7.247 +setgid mail, the spool directory can be protected 775 with group mail.
   7.248 +Please disregard this paragraph if you don't understand it COMPLETELY, and
   7.249 +know EXACTLY what to do without question.
   7.250 +
   7.251 +
   7.252 +STEP 5:	SVR4 specific setup
   7.253 +
   7.254 +     There is one "gotcha" on System V Release 4 based systems such as
   7.255 +Solaris.  These systems do not use the standard UNIX mail format, but rather a
   7.256 +variant of that format that depends upon a bogus "Content-Length:" message
   7.257 +header.  This is widely recognized to have been a terrible mistake.  One
   7.258 +symptom of the problem is that under certain circumstances, a message may get
   7.259 +broken up into several messages.  I'm also aware of security bugs caused by
   7.260 +programs that foolishly trust "Content-Length:" headers with evil values.
   7.261 +
   7.262 +    To fix your system, edit your sendmail.cf to change the Mlocal line to
   7.263 +have the -E flag.  A typical entry will lool like:
   7.264 +
   7.265 +Mlocal, P=/usr/lib/mail.local, F=flsSDFMmnPE, S=10, R=20, A=mail.local -d $u
   7.266 +
   7.267 +			      WIN32 BUILD NOTES
   7.268 +
   7.269 +     Visual C++ 6.0 along with the current Microsoft Platform SDK
   7.270 +(specifically the CORE SDK and the Internet Development SDK) is required
   7.271 +to build on Windows 9x/Me/NT/2K/XP.  If you do not have the Platform SDK
   7.272 +installed or in your path properly, you'll get errors when building os_nt.c,
   7.273 +typically in env_nt.c, ssl_nt.c, ssl_w2k.c, or gss_shim.c.  You can download
   7.274 +the Microsoft Platform SDK from Microsoft's web site.
   7.275 +
   7.276 +     There is also considerable debate about how new mail is to be snarfed.
   7.277 +I am currently using something that seems to work with WinSMTP.  Look at
   7.278 +the definition of MAILFILE in imap-2007/src/osdep/nt/mailfile.h and at the
   7.279 +sysinbox() function in imap-2007/src/osdep/nt/env_nt.c to see what's there
   7.280 +now, so you have a clue about how to hack it.
   7.281 +
   7.282 +     To build under Windows 95/98/NT, connect to the imap-2007 directory
   7.283 +and do:
   7.284 +	nmake -f makefile.nt
   7.285 +The resulting binaries will support SSL if either schannel.dll or
   7.286 +security.dll is installed in Windows, using the old, undocumented, SSL
   7.287 +interfaces.  You can also use this to build under Me/2000/XP, but it is
   7.288 +not the preferred build on this platform.
   7.289 +
   7.290 +     To build with MIT Kerberos support, connect to the imap-2007 directory
   7.291 +and do:
   7.292 +	nmake -f makefile.ntk
   7.293 +The resulting binaries will support SSL if either schannel.dll or
   7.294 +security.dll is installed in Windows, using the old, undocumented SSL
   7.295 +interfaces.  They will also support MIT Kerberos.  Note, however, that
   7.296 +these binaries will only run on systems which have the MIT Kerberos DLLs
   7.297 +installed, and will not run otherwise.
   7.298 +
   7.299 +     To build under Windows Me/2000/XP, connect to the imap-2007 directory
   7.300 +and do:
   7.301 +	nmake -f makefile.w2k
   7.302 +The resulting binaries will support SSL and Microsoft Kerberos, using the
   7.303 +official, documented, Microsoft interfaces.  Note, however, that these
   7.304 +binaries will not run under Windows 95, Windows 98, or Windows NT4.
   7.305 +
   7.306 +			   WIN32 INSTALLATION NOTES
   7.307 +
   7.308 +     The resulting binaries will be:
   7.309 +	imap-2007\mtest\mtest.exe	(testbed client)
   7.310 +	imap-2007\ipopd\ipop2d.exe	POP2 server
   7.311 +	imap-2007\ipopd\ipop3d.exe	POP3 server
   7.312 +	imap-2007\imapd\imapd.exe	IMAP4rev1 server
   7.313 +
   7.314 +     These servers are stdio servers.  I wrote a simple network listener
   7.315 +for NT called inetlisn; currently it is available as:
   7.316 +	ftp://ftp.cac.washington.edu/mail/nt/inetlisn.tar
   7.317 +To build this, use "nmake" after connecting to the inetlisn directory.
   7.318 +inetlisn takes two arguments, the first being the port number and the second
   7.319 +being the binary to run to serve a connection on that port, e.g.
   7.320 +	c:\bin\inetlisn 143 c:\mail_daemons\imapd
   7.321 +
   7.322 +     Note that NT imapd must be started as SYSTEM in order to be recognized as
   7.323 +being "not logged in"; otherwise it will preauth as whatever user it is
   7.324 +running as which is probably not what you want.  One way to have it run as
   7.325 +system is to have inetlisn run by an AT command, e.g. if the time now is
   7.326 +2:05PM, try something like:
   7.327 +	AT 14:06 "c:\bin\inetlisn 143 c:\mail_daemons\imapd"
   7.328 +
   7.329 +     A more advanced network listener called wsinetd is available on:
   7.330 +	http://wsinetd.sourceforge.net
   7.331 +It is based on inetlisn, and essentially is a "completed" version of inetlisn.
   7.332 +
   7.333 +     Bottom line: this is not plug-and-play.  If you're not a hacker and/or
   7.334 +are unwilling to invest the time to do some programming, you probably want to
   7.335 +buy a commercial server product.
   7.336 +
   7.337 +				INACTIVE PORTS
   7.338 +
   7.339 +     The TOPS-20 and VMS ports were developed at one time or another, but are
   7.340 +no longer actively developed.  However, from time to time I test build both
   7.341 +of these to make sure that they compile without errors and that mtest runs,
   7.342 +and will continue doing so as long as I have access to systems running these
   7.343 +operating systems.
   7.344 +
   7.345 +
   7.346 +			     TOPS-20 BUILD NOTES
   7.347 +
   7.348 +     I have provided a c-client port for TOPS-20 systems, but you're on your
   7.349 +own in terms of a nice TOPS-20 like main program.  Maybe someday some nice
   7.350 +person will try porting Pine to TOPS-20.  This assumes the use of KCC 6, and
   7.351 +probably will not build with other compilers or older versions of KCC.
   7.352 +
   7.353 +     You do not use imap-2007/Makefile under TOPS-20, nor do you build any
   7.354 +components other than c-client and mtest.  Merge the contents of
   7.355 +imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
   7.356 +imap-2007/src/osdep/tops-20 onto a single directory on TOPS-20 and build from
   7.357 +that.  The command:
   7.358 +	DO BUILD.CTL
   7.359 +will build the sources.  If you don't have MIC, then SUBMIT BUILD.CTL and let
   7.360 +BATCON execute it.
   7.361 +
   7.362 +
   7.363 +			       VMS BUILD NOTES
   7.364 +
   7.365 +      The VMS port has been tested with imap-2007, but as I am soon going
   7.366 +to lose access to a VMS system I will no longer be able able to test and
   7.367 +this port will be moved to the "other ports" category".
   7.368 +
   7.369 +      You do not use imap-2007/Makefile under VMS, nor do you build any
   7.370 +components other than c-client and mtest.  Merge the contents of
   7.371 +imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
   7.372 +imap-2007/src/osdep/vms onto a single directory on VMS and build from that.
   7.373 +The command to build it is:
   7.374 +	@BUILD MULTINET
   7.375 +or	@BUILD NETLIB
   7.376 +If you just do @BUILD it will build with dummy TCP code, and since only TCP
   7.377 +based drivers are provided here this isn't too useful.
   7.378 +
   7.379 +     If you aren't on the Pacific coast of the US or Canada, you probably will
   7.380 +need to change the wired-in timezone in the BUILD.COM file.  Apparently, the
   7.381 +wonderful VMS system that DEC loves so much doesn't maintain any concept of
   7.382 +time zone; the VMS C compiler returns a null pointer from gmtime()!
   7.383 +
   7.384 +     Otherwise you're pretty much on your own here.
   7.385 +
   7.386 +				 OTHER PORTS
   7.387 +
   7.388 +     The following ports were developed at one time or another, but are no
   7.389 +longer actively developed or tested.  It is not known if they still work or
   7.390 +not.
   7.391 +
   7.392 +  Port		Status
   7.393 +  ----		------
   7.394 +Macintosh	Obsolete; Mac OS X uses UNIX port
   7.395 +DOS/Win16	Obsolete; modern PCs use Win32 port
   7.396 +Windows CE	Never completed
   7.397 +Amiga		Unknown
   7.398 +OS/2		Unknown
   7.399 +
   7.400 +			     MACINTOSH BUILD NOTES
   7.401 +
   7.402 +     This port is for the old Mac OS system, not Mac OS X.
   7.403 +
   7.404 +     If you are building a Macintosh client, you will need MacTCP installed on
   7.405 +your system as well as the MacTCP C includes and libraries.
   7.406 +
   7.407 +     You do not use imap-2007/Makefile on the Mac, nor do you build any
   7.408 +components other than c-client and mtest.  Merge the contents of
   7.409 +imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
   7.410 +imap-2007/src/osdep/mac onto a single directory on the Mac and build from
   7.411 +that.  mtext.sit.hqx is a THINK C project file and cute icon for building
   7.412 +mtest, encoded with Binhex and StuffIt.
   7.413 +
   7.414 +     THINK C is a truly wretched product which help make me understand why
   7.415 +Macintosh has lost most of its market share.  Not only does it do cretinous
   7.416 +things such as barf about a cast in front of an lvalue, it also limits the size
   7.417 +of code *or* data in a single file to 32K!  So much for having large character
   7.418 +set tables.  Symantec says that "MacOS requires it, break up your files into
   7.419 +smaller pieces" yet somehow gcc under MachTen contrives to compile C programs
   7.420 +without subjecting the programmer to this idiocy.
   7.421 +
   7.422 +     As a result of this, I found myself obliged to comment out the #includes
   7.423 +of the East Asian character sets in utf8.c in order to get it to build.  It's
   7.424 +also necessary to break up some of the files, at least mail.c and imap4r1.c.
   7.425 +Maybe you don't have to do this in CodeWarrior or whatever the new compiler is
   7.426 +called, but I've pretty much given up on Macintosh.
   7.427 +
   7.428 +     If you use precompiled headers, you may get some compilation errors since
   7.429 +some Apple symbols need to be redefined in order to get it to build under all
   7.430 +versions of MacOS.  Try turning off the precompiled headers (so it will
   7.431 +re-read the .h files) and see if it builds any better.
   7.432 +
   7.433 +     If you use a Mac C compiler with 2-byte ints (such as THINK C's normal
   7.434 +mode) you will need to fix some bugs in the MacTCP C includes and libraries to
   7.435 +prevent it from generating bad code, since those MacTCP files violate Apple's
   7.436 +standards of always using explicit shorts or longs, never ints.  You could
   7.437 +avoid this if you set 4-byte ints in THINK C; however, the ANSI and UNIX
   7.438 +libraries in THINK C use 2-byte ints so you will also need to build 4-byte int
   7.439 +versions of these.  c-client itself is 2-byte int or 4-byte int clean; it can
   7.440 +be used in either mode.
   7.441 +
   7.442 +     The most important bug in the MacTCP files that you need to fix is in the
   7.443 +file AddressXlation.h, you need to change the definition of the rtnCode member
   7.444 +of the hostInfo structure to be long instead of int.  There are several other
   7.445 +changes you need to make if you decide to compile dnr.c under THINK C instead
   7.446 +of using the Apple-supplied object file; see me for details if you decide to
   7.447 +undertake such an effort.  This is fixed in newer versions from Apple.
   7.448 +
   7.449 +
   7.450 +			     DOS/WIN16 BUILD NOTES
   7.451 +
   7.452 +     If you are building a DOS client, you will need a TCP/IP stack installed
   7.453 +on your DOS system along with its development environment.  The currently
   7.454 +supported stacks are Beame & Whiteside, PC-NFS, Novell, PC/IP, Waterloo, and
   7.455 +Winsock.  mtest and a version of Pine called PC Pine run under DOS.
   7.456 +
   7.457 +      You do not use imap-2007/Makefile under DOS, nor do you build any
   7.458 +components other than c-client and mtest.  Merge the contents of
   7.459 +imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
   7.460 +imap-2007/src/osdep/dos onto a single directory on DOS and build from that.
   7.461 +The MAKE command on DOS takes an argument identifying the TCP/IP stack in use.
   7.462 +For example, do:
   7.463 +	MAKE MAKEFILE OS=WSK   (or MAKE -F MAKEFILE OS=WSK)
   7.464 +to build for Winsock.  
   7.465 +
   7.466 +     If you write a program for DOS/Win16, you will probably have to write a
   7.467 +replacement cache manager (look at mm_cache()) and otherwise disable most of
   7.468 +c-client's caching.  Even so, memory limitations will be an ongoing problem,
   7.469 +particularly with DOS, and you will have some severe performance problems.
   7.470 +It's a bit better on Win16, but in my opinion you are better off writing a
   7.471 +32-bit program and telling your Win16 customers to upgrade to Windows 95 or at
   7.472 +least install Win32s.
   7.473 +
   7.474 +
   7.475 +			    WINDOWS CE BUILD NOTES
   7.476 +
   7.477 +     I build using Visual C++ 6.0 with the WCE extensions.  The current code
   7.478 +has SH3 wired in for the compiler building.
   7.479 +
   7.480 +     To build under NT, connect to the imap-2007 directory and do:
   7.481 +	nmake -f makefile.wce
   7.482 +
   7.483 +     The only binary produced is a cclient.lib file.  I haven't gotten as far
   7.484 +as building mtest on WCE, mainly because I don't have a stdlib library.
   7.485 +
   7.486 +
   7.487 +		      AMIGA BUILD AND INSTALLATION NOTES
   7.488 +
   7.489 +     The Amiga port was contributed.  Maybe the UNIX notes will help.
   7.490 +
   7.491 +
   7.492 +			       OS2 BUILD NOTES
   7.493 +
   7.494 +     The OS2 port was contributed.  Maybe the Win32 Build Notes will help.
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/docs/CONFIG	Mon Sep 14 15:17:45 2009 +0900
     8.3 @@ -0,0 +1,181 @@
     8.4 +/* ========================================================================
     8.5 + * Copyright 1988-2006 University of Washington
     8.6 + *
     8.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     8.8 + * you may not use this file except in compliance with the License.
     8.9 + * You may obtain a copy of the License at
    8.10 + *
    8.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    8.12 + *
    8.13 + * 
    8.14 + * ========================================================================
    8.15 + */
    8.16 +
    8.17 +		       UNIX Configuration Notes
    8.18 +
    8.19 +     The IMAP and POP3 servers are plug-and-play on standard UNIX
    8.20 +systems.  There is no special configuration needed.  Please ignore all
    8.21 +rumors to the effect that you need to create an IMAP configuration
    8.22 +file.
    8.23 +
    8.24 +     If your system is non-standard, virtually everything that you are
    8.25 +likely to want to modify can be found in the source file
    8.26 +	.../src/osdep/unix/env_unix.c
    8.27 +In particular, special attention should be given to the routines:
    8.28 + env_init()		initialize c-client environment variables,
    8.29 +			especially the user name and home directory
    8.30 + sysinbox()		return the UNIX path of the INBOX in which
    8.31 +			mail delivery will place mail
    8.32 + mailboxdir()		translate a mailbox name into the associated
    8.33 +			UNIX directory for listing
    8.34 + mailboxfile()		translate a mailbox name into the associated
    8.35 +			UNIX file for opening
    8.36 +
    8.37 +     There are also build options in the top-level makefile which you
    8.38 +can give on the command line when building the software.  The most
    8.39 +common build options are "SSLTYPE=unix", to build the software with SSL,
    8.40 +and "SSLTYPE=nopwd", to build the software with SSL and disable plaintext
    8.41 +authentication unless the session is encrypted.
    8.42 +
    8.43 +     You should modify these routines as necessary for local policy.
    8.44 +The most common modifications are to env_init(), to modify the
    8.45 +software's idea of the home directory (which is used everywhere as the
    8.46 +default directory), and to sysinbox(), to modify where the software
    8.47 +looks for newly-delivered mail.
    8.48 +
    8.49 +     Example 1: suppose your mailer delivers mail to file ".mailbox"
    8.50 +in the user's home directory instead of the default UNIX mail spool
    8.51 +directory.  You will want to change routine sysinbox(), changing the
    8.52 +line that reads:
    8.53 +
    8.54 +    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
    8.55 +to be:
    8.56 +    sprintf (tmp,"%s/.mailbox",myhomedir ());
    8.57 +
    8.58 +     Example 2: suppose you want to change c-client's idea of the
    8.59 +user's mailbox directory to be the "mail" subdirectory of the user's
    8.60 +home directory instead of the user's home directory.  You will want to
    8.61 +change variable mailsubdir, changing the line that reads:
    8.62 +
    8.63 +static char *mailsubdir = NIL;	/* mail subdirectory name */
    8.64 + to be:
    8.65 +static char *mailsubdir = "mail";/* mail subdirectory name */
    8.66 +
    8.67 +     Example 3: suppose you want to disable plaintext authentication in
    8.68 +the IMAP and POP servers.  If you want to disable plaintext authentication
    8.69 +in unencrypted sessions but permit it in encrypted sessions, you should use
    8.70 +"SSLTYPE=nopwd" in the make command line when building the software.  For
    8.71 +example, to do this on a Linux system with PAM authentication, do:
    8.72 +	make lnp SSLTYPE=nopwd
    8.73 +If you want to disable plaintext authentication under all circumstances
    8.74 +(including SSL or TLS encrypted sessions), use "PASSWDTYPE=nul", e.g.:
    8.75 +	make lnx EXTRAAUTHENTICATORS=gss PASSWDTYPE=nul
    8.76 +which will make it impossible to log in except via Kerberos.
    8.77 +
    8.78 +     Example 4: suppose you want the IMAP and POP servers to do a chroot()
    8.79 +to the user's home directory.  This is not recommended; there are known
    8.80 +ways of attacking chroot() based security mechanisms.  Furthermore, if you
    8.81 +do this you can not use a traditional UNIX format INBOX in the mail spool
    8.82 +directory, since chroot() will prevent access to that directory.  If you
    8.83 +really want to do this, you need to change variable closedBox, changing
    8.84 +the line which reads:
    8.85 +
    8.86 +static short closedBox = NIL;	/* is a closed box */
    8.87 + to be:
    8.88 +static short closedBox = T;	/* is a closed box */
    8.89 +
    8.90 +     Example 5: suppose you want to disable non-namespace access to the
    8.91 +filesystem root and other users' names, but do not want to go to the
    8.92 +extreme of chroot() and you want to allow access to a traditional UNIX
    8.93 +format INBOX in the mail spool directory.  You need to change variable
    8.94 +restrictBox, changing the line which reads:
    8.95 +
    8.96 +static short restrictBox = NIL;	/* is a restricted box */
    8.97 + to be:
    8.98 +static short restrictBox = -1;	/* is a restricted box */
    8.99 +
   8.100 +Other values to set in restrictBox can be found in env_unix.h.
   8.101 +
   8.102 +     Ignore all references in env_unix.c to a configuration file; that
   8.103 +code is for UW-internal use only.  It is extremely unlikely that that
   8.104 +facility will work usefully for you; it is extremely likely that you
   8.105 +will shoot yourself in the foot by using; and it frequently changes in
   8.106 +an incompatible manner.
   8.107 +
   8.108 +     There are two other build-time configuration issues which you may
   8.109 +need to consider: drivers and authenticators.  Both of these are set
   8.110 +up in the top-level Makefile -- in particular, by the EXTRADRIVERS and
   8.111 +EXTRAAUTHENTICATORS variables.
   8.112 +
   8.113 +     Drivers are code modules that support different mailbox storage
   8.114 +technologies.  By default, all drivers are enabled.  There is little
   8.115 +benefit to be gained by disabling a driver, with one exception.  The
   8.116 +mbox driver implements the behavior of automatically moving new mail
   8.117 +from the spool directory to the "mbox" file on the user's home
   8.118 +directory, if and *only* if the "mbox" exists and is in mailbox
   8.119 +format.  The mbox driver is listed under EXTRADRIVERS; if you wish to
   8.120 +disable it just remove it from that list and rebuild.
   8.121 +
   8.122 +     Authenticators are code modules that support authentication
   8.123 +technology for the server (password file lookup, Kerberos, S/Key,
   8.124 +etc.).  EXTRAAUTHENTICATORS is used to add an authenticator.  This
   8.125 +subject can be complex; find a wizard if you can't figure it out.
   8.126 +
   8.127 +     It is also possible to add your own drivers and authenticators.
   8.128 +This is a topic for wizards, and is beyond the scope of this text.
   8.129 +
   8.130 +			NT Configuration Notes
   8.131 +
   8.132 +     This software is not plug-and-play on NT.  If you're not a hacker
   8.133 +and/or are unwilling to invest the time to do some programming, you
   8.134 +probably want to buy a commercial server for NT.
   8.135 +
   8.136 +     The primary issue that you need to deal with is the format of
   8.137 +mail, where the INBOX is located, and where secondary folders are
   8.138 +located.  As distributed, the software supports mail in the default
   8.139 +format used on UNIX (unix format) as well as mbx, mtx, and tenex
   8.140 +formats.  mbx format is encouraged if at all possible; mtx and tenex
   8.141 +format are for compatibility with the past.  However, it all depends
   8.142 +upon how and where your SMTP server delivers mail.
   8.143 +
   8.144 +     To change the default mailbox format, edit the symbol
   8.145 +DEFAULTDRIVER in:
   8.146 +	../src/osdep/nt/makefile.nt
   8.147 +or
   8.148 +	../src/osdep/nt/makefile.ntk
   8.149 +To change the default location of INBOX, edit the file:
   8.150 +	../src/osdep/nt/mailfile.h
   8.151 +Virtually everything else having to do with environment that you are
   8.152 +likely to want to modify can be found in the source file:
   8.153 +	.../src/osdep/nt/env_nt.c
   8.154 +In particular, special attention should be given to the routines:
   8.155 + env_init()		initialize c-client environment variables,
   8.156 +			especially the user name and home directory
   8.157 + sysinbox()		return the NT path of the INBOX in which
   8.158 +			mail delivery will place mail
   8.159 + mailboxdir()		translate a mailbox name into the associated
   8.160 +			NT directory for listing
   8.161 + mailboxfile()		translate a mailbox name into the associated
   8.162 +			NT file for opening
   8.163 +
   8.164 +     You should modify these routines as necessary.  The most common
   8.165 +modifications are to env_init(), to modify the software's idea of the
   8.166 +home directory (which is used everywhere as the default directory),
   8.167 +and to sysinbox(), to modify where the software looks for
   8.168 +newly-delivered mail.
   8.169 +
   8.170 +     There are two other build-time configuration issues which you may
   8.171 +need to consider: drivers and authenticators.  Both of these are set
   8.172 +up in the top-level Makefile -- in particular, by the EXTRADRIVERS and
   8.173 +EXTRAAUTHENTICATORS variables.
   8.174 +
   8.175 +     Drivers are code modules that support different mailbox storage
   8.176 +technologies.  By default, all drivers are enabled.  There is little
   8.177 +benefit to be gained by disabling a driver.
   8.178 +
   8.179 +     Authenticators are code modules that support authentication
   8.180 +technology for the server (password file lookup, Kerberos, S/Key,
   8.181 +etc.).  EXTRAAUTHENTICATORS is used to add an authenticator.  This
   8.182 +subject can be complex; find a wizard if you can't figure it out.
   8.183 +
   8.184 +     It is also possible to add your own drivers and authenticators.
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/docs/FAQ.html	Mon Sep 14 15:17:45 2009 +0900
     9.3 @@ -0,0 +1,4226 @@
     9.4 +<!--
     9.5 + * ========================================================================
     9.6 + * Copyright 1988-2007 University of Washington
     9.7 + *
     9.8 + * Licensed under the Apache License, Version 2.0 (the "License");
     9.9 + * you may not use this file except in compliance with the License.
    9.10 + * You may obtain a copy of the License at
    9.11 + *
    9.12 + *     http://www.apache.org/licenses/LICENSE-2.0
    9.13 + *
    9.14 + * 
    9.15 + * ========================================================================
    9.16 + *
    9.17 +-->
    9.18 +
    9.19 +<!--chtml set title="IMAP Toolkit Frequently Asked Questions"-->
    9.20 +<!--chtml include "//imap/incs/top.inc"-->
    9.21 +
    9.22 +  <h2>Table of Contents</h2>
    9.23 +
    9.24 +  <ul>
    9.25 +    <li>
    9.26 +      <a href="#general">1. General/Software Feature Questions</a>
    9.27 +
    9.28 +      <ul>
    9.29 +        <li><a href="#1.1">1.1 Can I set up a POP or IMAP server on
    9.30 +        UNIX/Linux/OSF/etc.?</a></li>
    9.31 +
    9.32 +        <li><a href="#1.2">1.2 I am currently using qpopper as my POP3 server
    9.33 +        on UNIX. Do I need to replace it with ipop3d in order to run
    9.34 +        imapd?</a></li>
    9.35 +
    9.36 +        <li><a href="#1.3">1.3 Can I set up a POP or IMAP server on Windows
    9.37 +        XP, 2000, NT, Me, 98, or 95?</a></li>
    9.38 +
    9.39 +        <li><a href="#1.4">1.4 Can I set up a POP or IMAP server on Windows
    9.40 +        3.1 or DOS?</a></li>
    9.41 +
    9.42 +        <li><a href="#1.5">1.5 Can I set up a POP or IMAP server on
    9.43 +        Macintosh?</a></li>
    9.44 +
    9.45 +        <li><a href="#1.6">1.6 Can I set up a POP or IMAP server on
    9.46 +        VAX/VMS?</a></li>
    9.47 +
    9.48 +        <li><a href="#1.7">1.7 Can I set up a POP or IMAP server on
    9.49 +        TOPS-20?</a></li>
    9.50 +
    9.51 +        <li><a href="#1.8">1.8 Are hierarchical mailboxes supported?</a></li>
    9.52 +
    9.53 +        <li><a href="#1.9">1.9 Are "dual-use" mailboxes supported?</a></li>
    9.54 +
    9.55 +        <li><a href="#1.10">1.10 Can I have a mailbox that has both messages
    9.56 +        and sub-mailboxes?</a></li>
    9.57 +
    9.58 +        <li><a href="#1.11">1.11 What is the difference between "mailbox" and
    9.59 +        "folder"?</a></li>
    9.60 +
    9.61 +        <li><a href="#1.12">1.12 What is the status of
    9.62 +        internationalization?</a></li>
    9.63 +
    9.64 +        <li><a href="#1.13">1.13 Can I use SSL?</a></li>
    9.65 +
    9.66 +        <li><a href="#1.14">1.14 Can I use TLS and the STARTTLS
    9.67 +        facility?</a></li>
    9.68 +
    9.69 +        <li><a href="#1.15">1.15 Can I use CRAM-MD5 authentication?</a></li>
    9.70 +
    9.71 +        <li><a href="#1.16">1.16 Can I use APOP authentication?</a></li>
    9.72 +
    9.73 +        <li><a href="#1.17">1.17 Can I use Kerberos V5?</a></li>
    9.74 +
    9.75 +        <li><a href="#1.18">1.18 Can I use PAM for plaintext
    9.76 +        passwords?</a></li>
    9.77 +
    9.78 +        <li><a href="#1.19">1.19 Can I use Kerberos 5 for plaintext
    9.79 +        passwords?</a></li>
    9.80 +
    9.81 +        <li><a href="#1.20">1.20 Can I use AFS for plaintext
    9.82 +        passwords?</a></li>
    9.83 +
    9.84 +        <li><a href="#1.21">1.21 Can I use DCE for plaintext
    9.85 +        passwords?</a></li>
    9.86 +
    9.87 +        <li><a href="#1.22">1.22 Can I use the CRAM-MD5 database for
    9.88 +        plaintext passwords?</a></li>
    9.89 +
    9.90 +        <li><a href="#1.23">1.23 Can I disable plaintext passwords?</a></li>
    9.91 +
    9.92 +        <li><a href="#1.24">1.24 Can I disable plaintext passwords on
    9.93 +        unencrypted sessions, but allow them on encrypted sessions?</a></li>
    9.94 +
    9.95 +        <li><a href="#1.25">1.25 Can I use virtual hosts?</a></li>
    9.96 +
    9.97 +        <li><a href="#1.26">1.26 Can I use RPOP authentication?</a></li>
    9.98 +
    9.99 +        <li><a href="#1.27">1.27 Can I use Kerberos V4?</a></li>
   9.100 +
   9.101 +        <li><a href="#1.28">1.28 Is there support for S/Key or OTP?</a></li>
   9.102 +
   9.103 +        <li><a href="#1.29">1.29 Is there support for NTLM or SPA?</a></li>
   9.104 +
   9.105 +        <li><a href="#1.30">1.30 Is there support for mh?</a></li>
   9.106 +
   9.107 +        <li><a href="#1.31">1.31 Is there support for qmail and the maildir
   9.108 +        format?</a></li>
   9.109 +
   9.110 +        <li><a href="#1.32">1.32 Is there support for the Cyrus mailbox
   9.111 +        format?</a></li>
   9.112 +
   9.113 +        <li><a href="#1.33">1.33 Is this software Y2K compliant?</a></li>
   9.114 +      </ul>
   9.115 +    </li>
   9.116 +
   9.117 +    <li>
   9.118 +      <a href="#requirements">2. What Do I Need to Build This Software?</a>
   9.119 +
   9.120 +      <ul>
   9.121 +        <li><a href="#2.1">2.1 What do I need to build this software with SSL
   9.122 +        on UNIX?</a></li>
   9.123 +
   9.124 +        <li><a href="#2.2">2.2 What do I need to build this software with
   9.125 +        Kerberos V on UNIX?</a></li>
   9.126 +
   9.127 +        <li><a href="#2.3">2.3 What do I need to use a C++ compiler with this
   9.128 +        software to build my own application?</a></li>
   9.129 +
   9.130 +        <li><a href="#2.4">2.4 What do I need to build this software on
   9.131 +        Windows?</a></li>
   9.132 +
   9.133 +        <li><a href="#2.5">2.5 What do I need to build this software on
   9.134 +        DOS?</a></li>
   9.135 +
   9.136 +        <li><a href="#2.6">2.6 Can't I use Borland C to build this software
   9.137 +        on the PC?</a></li>
   9.138 +
   9.139 +        <li><a href="#2.7">2.7 What do I need to build this software on the
   9.140 +        Mac?</a></li>
   9.141 +
   9.142 +        <li><a href="#2.8">2.8 What do I need to build this software on
   9.143 +        VMS?</a></li>
   9.144 +
   9.145 +        <li><a href="#2.9">2.9 What do I need to build this software on
   9.146 +        TOPS-20?</a></li>
   9.147 +
   9.148 +        <li><a href="#2.10">2.10 What do I need to build this software on
   9.149 +        Amiga or OS/2?</a></li>
   9.150 +
   9.151 +        <li><a href="#2.11">2.11 What do I need to build this software on
   9.152 +        Windows CE?</a></li>
   9.153 +      </ul>
   9.154 +    </li>
   9.155 +
   9.156 +    <li>
   9.157 +      <a href="#build">3. Build and Configuration Questions</a>
   9.158 +
   9.159 +      <ul>
   9.160 +        <li><a href="#3.1">3.1 How do I configure the IMAP and POP servers on
   9.161 +        UNIX?</a></li>
   9.162 +
   9.163 +        <li><a href="#3.2">3.2 I built and installed the servers according to
   9.164 +        the BUILD instructions. It can't be that easy. Don't I need to write
   9.165 +        a config file?</a></li>
   9.166 +
   9.167 +        <li><a href="#3.3">3.3 How do I make the IMAP and POP servers look
   9.168 +        for INBOX at some place other than the mail spool directory?</a></li>
   9.169 +
   9.170 +        <li><a href="#3.4">3.4 How do I make the IMAP server look for
   9.171 +        secondary folders at some place other than the user's home
   9.172 +        directory?</a></li>
   9.173 +
   9.174 +        <li><a href="#3.5">3.5 How do I configure SSL?</a></li>
   9.175 +
   9.176 +        <li><a href="#3.6">3.6 How do I configure TLS and the STARTTLS
   9.177 +        facility?</a></li>
   9.178 +
   9.179 +        <li><a href="#3.7">3.7 How do I build/install OpenSSL and
   9.180 +        obtain/create certificates for use with SSL?</a></li>
   9.181 +
   9.182 +        <li><a href="#3.8">3.8 How do I configure CRAM-MD5
   9.183 +        authentication?</a></li>
   9.184 +
   9.185 +        <li><a href="#3.9">3.9 How do I configure APOP
   9.186 +        authentication?</a></li>
   9.187 +
   9.188 +        <li><a href="#3.10">3.10 How do I configure Kerberos V5?</a></li>
   9.189 +
   9.190 +        <li><a href="#3.11">3.11 How do I configure PAM for plaintext
   9.191 +        passwords?</a></li>
   9.192 +
   9.193 +        <li><a href="#3.12">3.12 It looks like all I have to do to make the
   9.194 +        server use Kerberos is to build with PAM on my Linux system, and set
   9.195 +        it up in PAM for Kerberos passwords. Right?</a></li>
   9.196 +
   9.197 +        <li><a href="#3.13">3.13 How do I configure Kerberos 5 for plaintext
   9.198 +        passwords?</a></li>
   9.199 +
   9.200 +        <li><a href="#3.14">3.14 How do I configure AFS for plaintext
   9.201 +        passwords?</a></li>
   9.202 +
   9.203 +        <li><a href="#3.15">3.15 How do I configure DCE for plaintext
   9.204 +        passwords?</a></li>
   9.205 +
   9.206 +        <li><a href="#3.16">3.16 How do I configure the CRAM-MD5 database for
   9.207 +        plaintext passwords?</a></li>
   9.208 +
   9.209 +        <li><a href="#3.17">3.17 How do I disable plaintext
   9.210 +        passwords?</a></li>
   9.211 +
   9.212 +        <li><a href="#3.18">3.18 How do I disable plaintext passwords on
   9.213 +        unencrypted sessions, but allow them in SSL or TLS sessions?</a></li>
   9.214 +
   9.215 +        <li><a href="#3.19">3.19 How do I configure virtual hosts?</a></li>
   9.216 +
   9.217 +        <li>
   9.218 +          <a href="#3.20">3.20 Why do I get compiler warning messages such
   9.219 +          as:
   9.220 +
   9.221 +          <ul>
   9.222 +            <li>passing arg 3 of `scandir' from incompatible pointer
   9.223 +            type</li>
   9.224 +
   9.225 +            <li>Pointers are not assignment-compatible.</li>
   9.226 +
   9.227 +            <li>Argument #4 is not the correct type.</li>
   9.228 +          </ul>during the build?</a>
   9.229 +        </li>
   9.230 +
   9.231 +        <li>
   9.232 +          <a href="#3.21">3.21 Why do I get compiler warning messages such
   9.233 +          as
   9.234 +
   9.235 +          <ul>
   9.236 +            <li>Operation between types "void(*)(int)" and "void*" is not
   9.237 +            allowed.</li>
   9.238 +
   9.239 +            <li>Function argument assignment between types "void*" and
   9.240 +            "void(*)(int)" is not allowed.</li>
   9.241 +
   9.242 +            <li>Pointers are not assignment-compatible.</li>
   9.243 +
   9.244 +            <li>Argument #5 is not the correct type.</li>
   9.245 +          </ul>during the build?</a>
   9.246 +        </li>
   9.247 +
   9.248 +        <li>
   9.249 +          <a href="#3.22">3.22 Why do I get linker warning messages such
   9.250 +          as:
   9.251 +
   9.252 +          <ul>
   9.253 +            <li>mtest.c:515: the `gets' function is dangerous and should not
   9.254 +            be used.</li>
   9.255 +          </ul>during the build? Isn't this a security bug?</a>
   9.256 +        </li>
   9.257 +
   9.258 +        <li>
   9.259 +          <a href="#3.23">3.23 Why do I get linker warning messages such
   9.260 +          as:</a>
   9.261 +
   9.262 +          <ul>
   9.263 +            <li>auth_ssl.c:92: the `tmpnam' function is dangerous and should
   9.264 +            not be used.</li>
   9.265 +          </ul>during the build? Isn't this a security bug?
   9.266 +        </li>
   9.267 +
   9.268 +        <li><a href="#3.24">3.24 OK, suppose I see a warning message about a
   9.269 +        function being "dangerous and should not be used" for something other
   9.270 +        than this gets() or tmpnam() call?</a></li>
   9.271 +      </ul>
   9.272 +    </li>
   9.273 +
   9.274 +    <li>
   9.275 +      <a href="#operation">4. Operational Questions</a>
   9.276 +
   9.277 +      <ul>
   9.278 +        <li><a href="#4.1">4.1 How can I enable anonymous IMAP
   9.279 +        logins?</a></li>
   9.280 +
   9.281 +        <li><a href="#4.2">4.2 How do I set up an alert message that each
   9.282 +        IMAP user will see?</a></li>
   9.283 +
   9.284 +        <li><a href="#4.3">4.3 How does the c-client library choose which of
   9.285 +        its several mechanisms to use to establish an IMAP connection to the
   9.286 +        server? I noticed that it can connect on port 143, port 993, via rsh,
   9.287 +        and via ssh.</a></li>
   9.288 +
   9.289 +        <li><a href="#4.4">4.4 I am using a TLS-capable IMAP server, so I
   9.290 +        don't need to use /ssl to get encryption. However, I want to be
   9.291 +        certain that my session is TLS encrypted before I send my password.
   9.292 +        How to I do this?</a></li>
   9.293 +
   9.294 +        <li><a href="#4.5">4.5 How do I use one of the alternative formats
   9.295 +        described in the formats.txt document? In particular, I hear that mbx
   9.296 +        format will give me better performance and allow shared
   9.297 +        access.</a></li>
   9.298 +
   9.299 +        <li><a href="#4.6">4.6 How do I set up shared mailboxes?</a></li>
   9.300 +
   9.301 +        <li><a href="#4.7">4.7 How can I make the server syslogs go to
   9.302 +        someplace other than the mail syslog?</a></li>
   9.303 +      </ul>
   9.304 +    </li>
   9.305 +
   9.306 +    <li>
   9.307 +      <a href="#security">5. Security Questions</a>
   9.308 +
   9.309 +      <ul>
   9.310 +        <li><a href="#5.1">5.1 I see that the IMAP server allows access to
   9.311 +        arbitary files on the system, including /etc/passwd! How do I disable
   9.312 +        this?</a></li>
   9.313 +
   9.314 +        <li><a href="#5.2">5.2 I've heard that IMAP servers are insecure. Is
   9.315 +        this true?</a></li>
   9.316 +
   9.317 +        <li><a href="#5.3">5.3 How do I know that I have the most secure
   9.318 +        version of the server?</a></li>
   9.319 +
   9.320 +        <li><a href="#5.4">5.4 I see all these strcpy() and sprintf() calls,
   9.321 +        those are unsafe, aren't they?</a></li>
   9.322 +
   9.323 +        <li><a href="#5.5">5.5 Those /tmp lock files are protected 666, is
   9.324 +        that really right?</a></li>
   9.325 +      </ul>
   9.326 +    </li>
   9.327 +
   9.328 +    <li>
   9.329 +      <a href="#strange">6. <i>Why Did You Do This Strange Thing?</i>
   9.330 +      Questions</a>
   9.331 +
   9.332 +      <ul>
   9.333 +        <li><a href="#6.1">6.1 Why don't you use GNU autoconfig / automake /
   9.334 +        autoblurdybloop?</a></li>
   9.335 +
   9.336 +        <li><a href="#6.2">6.2 Why do you insist upon a build with -g?
   9.337 +        Doesn't it waste disk and memory space?</a></li>
   9.338 +
   9.339 +        <li><a href="#6.3">6.3 Why don't you make c-client a shared
   9.340 +        library?</a></li>
   9.341 +
   9.342 +        <li><a href="#6.4">6.4 Why don't you use iconv() for
   9.343 +        internationalization support?</a></li>
   9.344 +
   9.345 +        <li><a href="#6.5">6.5 Why is the IMAP server connected to the home
   9.346 +        directory by default?</a></li>
   9.347 +
   9.348 +        <li><a href="#6.6">6.6 I have a Windows system. Why isn't the server
   9.349 +        plug and play for me?</a></li>
   9.350 +
   9.351 +        <li><a href="#6.7">6.7 I looked at the UNIX SSL code and saw that you
   9.352 +        have the SSL data payload size set to 8192 bytes. SSL allows 16K; why
   9.353 +        aren't you using the full size?</a></li>
   9.354 +
   9.355 +        <li><a href="#6.8">6.8 Why is an mh format INBOX called #mhinbox
   9.356 +        instead of just INBOX?</a></li>
   9.357 +
   9.358 +        <li><a href="#6.9">6.9 Why don't you support the maildir
   9.359 +        format?</a></li>
   9.360 +
   9.361 +        <li><a href="#6.10">6.10 Why don't you support the Cyrus
   9.362 +        format?</a></li>
   9.363 +
   9.364 +        <li><a href="#6.11">6.11 Why is it creating extra forks on my SVR4
   9.365 +        system?</a></li>
   9.366 +
   9.367 +        <li><a href="#6.12">6.12 Why are you so fussy about the date/time
   9.368 +        format in the internal <code>"From&nbsp;"</code> line in traditional
   9.369 +        UNIX mailbox files? My other mail program just considers every line
   9.370 +        that starts with <code>"From&nbsp;"</code> to be the start of the
   9.371 +        message.</a></li>
   9.372 +
   9.373 +        <li><a href="#6.13">6.13 Why is traditional UNIX format the default
   9.374 +        format?</a></li>
   9.375 +
   9.376 +        <li><a href="#6.14">6.14 Why do you write this "DON'T DELETE THIS
   9.377 +        MESSAGE -- FOLDER INTERNAL DATA" message at the start of traditional
   9.378 +        UNIX and MMDF format mailboxes?</a></li>
   9.379 +
   9.380 +        <li><a href="#6.15">6.15 Why don't you stash the mailbox metadata in
   9.381 +        the first real message of the mailbox instead of writing this fake
   9.382 +        FOLDER INTERNAL DATA message?</a></li>
   9.383 +
   9.384 +        <li><a href="#6.16">6.16 Why aren't "dual-use" mailboxes the
   9.385 +        default?</a></li>
   9.386 +
   9.387 +        <li><a href="#6.17">6.17 Why do you use ucbcc to build on
   9.388 +        Solaris?</a></li>
   9.389 +
   9.390 +        <li><a href="#6.18">6.18 Why should I care about some old system with
   9.391 +        BSD libraries? cc is the right thing on my Solaris system!</a></li>
   9.392 +
   9.393 +        <li><a href="#6.19">6.19 Why do you insist upon writing .lock files
   9.394 +        in the spool directory?</a></li>
   9.395 +
   9.396 +        <li><a href="#6.20">6.20 Why should I care about compatibility with
   9.397 +        the past?</a></li>
   9.398 +      </ul>
   9.399 +    </li>
   9.400 +
   9.401 +    <li>
   9.402 +      <a href="#problems">7. Problems and Annoyances</a>
   9.403 +
   9.404 +      <ul>
   9.405 +        <li><a href="#7.1">7.1 Help! My INBOX is empty! What happened to my
   9.406 +        messages?</a></li>
   9.407 +
   9.408 +        <li><a href="#7.2">7.2 Help! All my messages in a non-INBOX mailbox
   9.409 +        have been concatenated into one message which claims to be from me
   9.410 +        and has a subject of the file name of the mailbox! What's going
   9.411 +        on?</a></li>
   9.412 +
   9.413 +        <li>
   9.414 +          <a href="#7.3">7.3 Why do I get the message:
   9.415 +
   9.416 +          <ul>
   9.417 +            <li>CREATE failed: Can't create mailbox node xxxxxxxxx: File
   9.418 +            exists</li>
   9.419 +          </ul>and how do I fix it?</a>
   9.420 +        </li>
   9.421 +
   9.422 +        <li><a href="#7.4">7.4 Why can't I log in to the server? The user
   9.423 +        name and password are right!</a></li>
   9.424 +
   9.425 +        <li><a href="#7.5">7.5 Help! My load average is soaring and I see
   9.426 +        hundreds of POP and IMAP servers, many logged in as the same
   9.427 +        user!</a></li>
   9.428 +
   9.429 +        <li><a href="#7.6">7.6 Why does mail disappear even though I set
   9.430 +        "keep mail on server"?</a></li>
   9.431 +
   9.432 +        <li>
   9.433 +          <a href="#7.7">7.7 Why do I get the message
   9.434 +
   9.435 +          <ul>
   9.436 +            <li>Moved ##### bytes of new mail to /home/user/mbox from
   9.437 +            /var/spool/mail/user</li>
   9.438 +          </ul>and why did this happen?</a>
   9.439 +        </li>
   9.440 +
   9.441 +        <li><a href="#7.8">7.8 Why isn't it showing the local host name as a
   9.442 +        fully-qualified domain name?</a></li>
   9.443 +
   9.444 +        <li><a href="#7.9">7.9 Why is the local host name in the
   9.445 +        From/Sender/Message-ID headers of outgoing mail not coming out as a
   9.446 +        fully-qualified domain name?</a></li>
   9.447 +
   9.448 +        <li>
   9.449 +          <a href="#7.10">7.10 What does the message:
   9.450 +
   9.451 +          <ul>
   9.452 +            <li>Mailbox vulnerable - directory /var/spool/mail must have 1777
   9.453 +            protection</li>
   9.454 +          </ul>mean? How can I fix this?</a>
   9.455 +        </li>
   9.456 +
   9.457 +        <li>
   9.458 +          <a href="#7.11">7.11 What does the message:
   9.459 +
   9.460 +          <ul>
   9.461 +            <li>Mailbox is open by another process, access is readonly</li>
   9.462 +          </ul>mean? How do I fix this?</a>
   9.463 +        </li>
   9.464 +
   9.465 +        <li>
   9.466 +          <a href="#7.12">7.12 What does the message:
   9.467 +
   9.468 +          <ul>
   9.469 +            <li>Can't get write access to mailbox, access is readonly</li>
   9.470 +          </ul>mean?</a>
   9.471 +        </li>
   9.472 +
   9.473 +        <li><a href="#7.13">7.13 I set my POP3 client to "delete messages
   9.474 +        from server" but they never get deleted. What is wrong?</a></li>
   9.475 +
   9.476 +        <li>
   9.477 +          <a href="#7.14">7.14 What do messages such as:
   9.478 +
   9.479 +          <ul>
   9.480 +            <li>Message ... UID ... already has UID ...</li>
   9.481 +
   9.482 +            <li>Message ... UID ... less than ...</li>
   9.483 +
   9.484 +            <li>Message ... UID ... greater than last ...</li>
   9.485 +
   9.486 +            <li>Invalid UID ... in message ..., rebuilding UIDs</li>
   9.487 +          </ul>mean?</a>
   9.488 +        </li>
   9.489 +
   9.490 +        <li>
   9.491 +          <a href="#7.15">7.15 What do the error messages:
   9.492 +
   9.493 +          <ul>
   9.494 +            <li>Unable to read internal header at ...</li>
   9.495 +
   9.496 +            <li>Unable to find CRLF at ...</li>
   9.497 +
   9.498 +            <li>Unable to parse internal header at ...</li>
   9.499 +
   9.500 +            <li>Unable to parse message date at ...</li>
   9.501 +
   9.502 +            <li>Unable to parse message flags at ...</li>
   9.503 +
   9.504 +            <li>Unable to parse message UID at ...</li>
   9.505 +
   9.506 +            <li>Unable to parse message size at ...</li>
   9.507 +
   9.508 +            <li>Last message (at ... ) runs past end of file ...</li>
   9.509 +          </ul>mean? I am using mbx format.</a>
   9.510 +        </li>
   9.511 +
   9.512 +        <li>
   9.513 +          <a href="#7.16">7.16 What do the syslog messages:
   9.514 +
   9.515 +          <ul>
   9.516 +            <li>imap/tcp server failing (looping)</li>
   9.517 +
   9.518 +            <li>pop3/tcp server failing (looping)</li>
   9.519 +          </ul>mean? When it happens, the listed service shuts down. How can
   9.520 +          I fix this?</a>
   9.521 +        </li>
   9.522 +
   9.523 +        <li>
   9.524 +          <a href="#7.17">7.17 What does the syslog message:
   9.525 +
   9.526 +          <ul>
   9.527 +            <li>Mailbox lock file /tmp/.600.1df3 open failure: Permission
   9.528 +            denied</li>
   9.529 +          </ul>mean?</a>
   9.530 +        </li>
   9.531 +
   9.532 +        <li>
   9.533 +          <a href="#7.18">7.18 What do the syslog messages:
   9.534 +
   9.535 +          <ul>
   9.536 +            <li>Command stream end of file, while reading line user=...
   9.537 +            host=...</li>
   9.538 +
   9.539 +            <li>Command stream end of file, while reading char user=...
   9.540 +            host=...</li>
   9.541 +
   9.542 +            <li>Command stream end of file, while writing text user=...
   9.543 +            host=...</li>
   9.544 +          </ul>mean?</a>
   9.545 +        </li>
   9.546 +
   9.547 +        <li>
   9.548 +          <a href="#7.19">7.19 Why did my POP or IMAP session suddenly
   9.549 +          disconnect? The syslog has the message:
   9.550 +
   9.551 +          <ul>
   9.552 +            <li>Killed (lost mailbox lock) user=... host=...</li>
   9.553 +          </ul></a>
   9.554 +        </li>
   9.555 +
   9.556 +        <li><a href="#7.20">7.20 Why does my IMAP client show all the files
   9.557 +        on the system, recursively from the UNIX root directory?</a></li>
   9.558 +
   9.559 +        <li><a href="#7.21">7.21 Why does my IMAP client show all of my
   9.560 +        files, recursively from my UNIX home directory?</a></li>
   9.561 +
   9.562 +        <li><a href="#7.22">7.22 Why does my IMAP client show that I have
   9.563 +        mailboxes named "#mhinbox", "#mh", "#shared", "#ftp", "#news", and
   9.564 +        "#public"?</a></li>
   9.565 +
   9.566 +        <li><a href="#7.23">7.23 Why does my IMAP client show all my files in
   9.567 +        my home directory?</a></li>
   9.568 +
   9.569 +        <li><a href="#7.24">7.24 Why is there a long delay before I get
   9.570 +        connected to the IMAP or POP server, no matter what client I
   9.571 +        use?</a></li>
   9.572 +
   9.573 +        <li><a href="#7.25">7.25 Why is there a long delay in Pine or any
   9.574 +        other c-client based application call before I get connected to the
   9.575 +        IMAP server? The hang seems to be in the c-client mail_open() call. I
   9.576 +        don't have this problem with any other IMAP client. There is no delay
   9.577 +        connecting to a POP3 or NNTP server with mail_open().</a></li>
   9.578 +
   9.579 +        <li><a href="#7.26">7.26 Why does a message sometimes get split into
   9.580 +        two or more messages on my SUN system?</a></li>
   9.581 +
   9.582 +        <li>
   9.583 +          <a href="#7.27">7.27 Why did my POP or IMAP session suddenly
   9.584 +          disconnect? The syslog has the message:
   9.585 +
   9.586 +          <ul>
   9.587 +            <li>Autologout user=&lt;...my user name...&gt; host=&lt;...my
   9.588 +            imap server...&gt;</li>
   9.589 +          </ul></a>
   9.590 +        </li>
   9.591 +
   9.592 +        <li>
   9.593 +          <a href="#7.28">7.28 What does the UNIX error message:
   9.594 +
   9.595 +          <ul>
   9.596 +            <li>TLS/SSL failure: myserver: SSL negotiation failed</li>
   9.597 +          </ul>mean?</a>
   9.598 +        </li>
   9.599 +
   9.600 +        <li>
   9.601 +          <a href="#7.29">7.29 What does the PC error message:
   9.602 +
   9.603 +          <ul>
   9.604 +            <li>TLS/SSL failure: myserver: Unexpected TCP input
   9.605 +            disconnect</li>
   9.606 +          </ul>mean?</a>
   9.607 +        </li>
   9.608 +
   9.609 +        <li>
   9.610 +          <a href="#7.30">7.30 What does the error message:
   9.611 +
   9.612 +          <ul>
   9.613 +            <li>TLS/SSL failure: myserver: Server name does not match
   9.614 +            certificate</li>
   9.615 +          </ul>mean?</a>
   9.616 +        </li>
   9.617 +
   9.618 +        <li>
   9.619 +          <a href="#7.31">7.31 What does the UNIX error message:
   9.620 +
   9.621 +          <ul>
   9.622 +            <li>TLS/SSL failure: myserver: self-signed certificate</li>
   9.623 +          </ul>mean?</a>
   9.624 +        </li>
   9.625 +
   9.626 +        <li>
   9.627 +          <a href="#7.32">7.32 What does the PC error message
   9.628 +
   9.629 +          <ul>
   9.630 +            <li>TLS/SSL failure: myserver: Self-signed certificate or
   9.631 +            untrusted authority</li>
   9.632 +          </ul>mean?</a>
   9.633 +        </li>
   9.634 +
   9.635 +        <li>
   9.636 +          <a href="#7.33">7.33 What does the UNIX error message:
   9.637 +
   9.638 +          <ul>
   9.639 +            <li>TLS/SSL failure: myserver: unable to get local issuer
   9.640 +            certificate</li>
   9.641 +          </ul>mean?</a>
   9.642 +        </li>
   9.643 +
   9.644 +        <li><a href="#7.34">7.34 Why does reading certain messages hang when
   9.645 +        using Netscape? It works fine with Pine!</a></li>
   9.646 +
   9.647 +        <li><a href="#7.35">7.35 Why does Netscape say that there's a problem
   9.648 +        with the IMAP server and that I should "Contact your mail server
   9.649 +        administrator."?</a></li>
   9.650 +
   9.651 +        <li><a href="#7.36">7.36 Why is one user creating huge numbers of
   9.652 +        IMAP or POP server sessions?</a></li>
   9.653 +
   9.654 +        <li><a href="#7.37">7.37 Why don't I get any new mail notifications
   9.655 +        from Outlook Express or Outlook after a while?</a></li>
   9.656 +
   9.657 +        <li><a href="#7.38">7.38 Why don't I get any new mail notifications
   9.658 +        from Entourage?</a></li>
   9.659 +
   9.660 +        <li><a href="#7.39">7.39 Why doesn't Entourage work at all?</a></li>
   9.661 +
   9.662 +        <li><a href="#7.40">7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE)
   9.663 +        work at all?</a></li>
   9.664 +
   9.665 +        <li><a href="#7.41">7.41 Why can't I connect via SSL to Eudora? It
   9.666 +        says the connection has been broken, and in the server syslogs I see
   9.667 +        "Command stream end of file".</a></li>
   9.668 +
   9.669 +        <li><a href="#7.42">7.42 Sheesh. Aren't there <i>any</i> good IMAP
   9.670 +        clients out there?</a></li>
   9.671 +
   9.672 +        <li>
   9.673 +          <a href="#7.43">7.43 But wait! PC Pine (or other PC program build
   9.674 +          with c-client) crashes with the message
   9.675 +
   9.676 +          <ul>
   9.677 +            <li>incomplete SecBuffer exceeds maximum buffer size</li>
   9.678 +          </ul>when I use SSL connections. This is a bug in c-client, right?</a>
   9.679 +        </li>
   9.680 +
   9.681 +        <li><a href="#7.44">7.44 My qpopper users keep on getting the DON'T
   9.682 +        DELETE THIS MESSAGE -- FOLDER INTERNAL DATA if they also use Pine or
   9.683 +        IMAP. How can I fix this?</a></li>
   9.684 +
   9.685 +        <li><a href="#7.45">7.45 Help! I installed the servers but I can't
   9.686 +        connect to them from my client!</a></li>
   9.687 +
   9.688 +        <li>
   9.689 +          <a href="#7.46">7.46 Why do I get the message
   9.690 +
   9.691 +          <ul>
   9.692 +            <li>Can not authenticate to SMTP server: 421 SMTP connection went
   9.693 +            away!</li>
   9.694 +          </ul>and why did this happen? There was also something about
   9.695 +
   9.696 +          <ul>
   9.697 +            <li>SECURITY PROBLEM: insecure server advertised AUTH=PLAIN</li>
   9.698 +          </ul></a>
   9.699 +        </li>
   9.700 +
   9.701 +        <li>
   9.702 +          <a href="#7.47">7.47 Why do I get the message
   9.703 +
   9.704 +          <ul>
   9.705 +            <li>SMTP Authentication cancelled</li>
   9.706 +          </ul>and why did this happen? There was also something about
   9.707 +
   9.708 +          <ul>
   9.709 +            <li>SECURITY PROBLEM: insecure server advertised AUTH=PLAIN</li>
   9.710 +          </ul></a>
   9.711 +        </li>
   9.712 +
   9.713 +        <li>
   9.714 +          <a href="#7.48">7.48 Why do I get the message
   9.715 +
   9.716 +          <ul>
   9.717 +            <li>Invalid base64 string</li>
   9.718 +          </ul>when I try to authenticate to a Cyrus server?
   9.719 +        </li></a>
   9.720 +      </ul>
   9.721 +    </li>
   9.722 +
   9.723 +    <li>
   9.724 +      <a href="#additional">8. Where to Go For Additional Information</a>
   9.725 +
   9.726 +      <ul>
   9.727 +        <li><a href="#8.1">8.1 Where can I go to ask questions?</a></li>
   9.728 +
   9.729 +        <li><a href="#8.2">8.2 I have some ideas for enhancements to IMAP.
   9.730 +        Where should I go?</a></li>
   9.731 +
   9.732 +        <li><a href="#8.3">8.3 Where can I read more about IMAP and other
   9.733 +        email protocols?</a></li>
   9.734 +
   9.735 +        <li><a href="#8.4">8.4 Where can I find out more about setting up and
   9.736 +        administering an IMAP server?</a></li>
   9.737 +      </ul>
   9.738 +    </li>
   9.739 +  </ul><!--=======START BODY-->
   9.740 +  <hr>
   9.741 +
   9.742 +  <h2><a name="general">1. General/Software Feature Questions</a></h2>
   9.743 +  <hr>
   9.744 +
   9.745 +  <p><a name="1.1"><strong>1.1 Can I set up a POP or IMAP server on
   9.746 +     UNIX/Linux/OSF/etc.?</strong></a></p>
   9.747 +
   9.748 +  <dl>
   9.749 +    <dd>Yes. Refer to the UNIX specific notes in files CONFIG and BUILD.</dd>
   9.750 +  </dl>
   9.751 +
   9.752 +  <p><a href="#top">Back to top</a></p>
   9.753 +  <hr>
   9.754 +
   9.755 +  <p><a name="1.2"><strong>1.2 I am currently using qpopper as my POP3 server on
   9.756 +     UNIX. Do I need to replace it with ipop3d in order to run
   9.757 +     imapd?</strong></a></p>
   9.758 +
   9.759 +  <dl>
   9.760 +    <dd>
   9.761 +      Not necessarily.
   9.762 +
   9.763 +      <p>Although ipop3d interoperates with imapd better than qpopper, imapd
   9.764 +      and qpopper will work together. The few qpopper/imapd interoperability
   9.765 +      issues mostly affect users who use both IMAP and POP3 clients; those
   9.766 +      users would probably be better served if their POP3 server is
   9.767 +      ipop3d.</p>
   9.768 +
   9.769 +      <p>If you are happy with qpopper and just want to add imapd, you should
   9.770 +      do that, and defer a decision on changing qpopper to ipop3d. That way,
   9.771 +      you can get comfortable with imapd's performance, without changing
   9.772 +      anything for your qpopper users.</p>
   9.773 +
   9.774 +      <p>Many sites have subsequently decided to change from qpopper to
   9.775 +      ipop3d in order to get better POP3/IMAP interoperability. If you need
   9.776 +      to do this, you'll know. There also seems to be a way to make qpopper
   9.777 +      work better with imapd; see the answer to the <a href="#7.44">My
   9.778 +      qpopper users keep on getting the DON'T DELETE THIS MESSAGE -- FOLDER
   9.779 +      INTERNAL DATA if they also use Pine or IMAP. How can I fix this?</a>
   9.780 +      question.</p>
   9.781 +    </dd>
   9.782 +  </dl>
   9.783 +
   9.784 +  <p><a href="#top">Back to top</a></p>
   9.785 +  <hr>
   9.786 +
   9.787 +  <p><a name="1.3"><strong>1.3 Can I set up a POP or IMAP server on Windows XP,
   9.788 +     2000, NT, Me, 98, or 95?</strong></a></p>
   9.789 +
   9.790 +  <dl>
   9.791 +    <dd>
   9.792 +      Yes. Refer to the NT specific notes in files CONFIG and BUILD. Also,
   9.793 +      for DOS-based versions of Windows (Windows Me, 98, and 95) you *must*
   9.794 +      set up CRAM-MD5 authentication, as described in md5.txt.
   9.795 +
   9.796 +      <p>There is no file access control on Windows 9x or Me, so you probably
   9.797 +      will have to do modifications to env_unix.c to prevent people from
   9.798 +      hacking others' mail.</p>
   9.799 +
   9.800 +      <p>Note, however, that the server is not plug and play the way it is
   9.801 +      for UNIX.</p>
   9.802 +    </dd>
   9.803 +  </dl>
   9.804 +
   9.805 +  <p><a href="#top">Back to top</a></p>
   9.806 +  <hr>
   9.807 +
   9.808 +  <p><a name="1.4"><strong>1.4 Can I set up a POP or IMAP server on Windows 3.1 or
   9.809 +     DOS?</strong></a><br>
   9.810 +  <a name="1.5"><strong>1.5 Can I set up a POP or IMAP server on
   9.811 +     Macintosh?</strong></a><br>
   9.812 +  <a name="1.6"><strong>1.6 Can I set up a POP or IMAP server on
   9.813 +     VAX/VMS?</strong></a></p>
   9.814 +
   9.815 +  <dl>
   9.816 +    <dd>Yes, it's just a small matter of programming.</dd>
   9.817 +  </dl>
   9.818 +
   9.819 +  <p><a href="#top">Back to top</a></p>
   9.820 +  <hr>
   9.821 +
   9.822 +  <p><a name="1.7"><strong>1.7 Can I set up a POP or IMAP server on
   9.823 +     TOPS-20?</strong></a></p>
   9.824 +
   9.825 +  <dl>
   9.826 +    <dd>
   9.827 +      You have a TOPS-20 system? Cool.
   9.828 +
   9.829 +      <p>If IMAP2 (RFC 1176) is good enough for you, you can use MAPSER which
   9.830 +      is about the ultimate gonzo pure TOPS-20 extended addressing assembly
   9.831 +      language program. Unfortunately, IMAP2 is barely good enough for Pine
   9.832 +      these days, and most other IMAP clients won't work with IMAP2 at all.
   9.833 +      Maybe someone will hack MAPSER to do IMAP4rev1 some day.</p>
   9.834 +
   9.835 +      <p>We don't know if anyone wrote a POP3 server for TOPS-20. There
   9.836 +      definitely was a POP2 server once upon a time.</p>
   9.837 +
   9.838 +      <p>Or you can port the POP and IMAP server from this IMAP toolkit to
   9.839 +      it. All that you need for a first stab is to port the MTX driver.
   9.840 +      That'll probably be just a couple of hours of hacking.</p>
   9.841 +    </dd>
   9.842 +  </dl>
   9.843 +
   9.844 +  <p><a href="#top">Back to top</a></p>
   9.845 +  <hr>
   9.846 +
   9.847 +  <p><a name="1.8"><strong>1.8 Are hierarchical mailboxes
   9.848 +     supported?</strong></a><br>
   9.849 +  <a name="1.9"><strong>1.9 Are "dual-use" mailboxes
   9.850 +     supported?</strong></a><br>
   9.851 +  <a name="1.10"><strong>1.10 Can I have a mailbox that has both messages and
   9.852 +     sub-mailboxes?</strong></a></p>
   9.853 +
   9.854 +  <dl>
   9.855 +    <dd>
   9.856 +      Yes. However, there is one important caveat.
   9.857 +
   9.858 +      <p>Some mailbox formats, including the default which is the traditional
   9.859 +      UNIX mailbox format, are stored as a single file containing all the
   9.860 +      messages. UNIX does not permit a name in the filesystem to be both a
   9.861 +      file and a directory; consequently you can not have a sub-mailbox
   9.862 +      within a mailbox that is in one of these formats.</p>
   9.863 +
   9.864 +      <p>This is not a limitation of the software; this is a limitation of
   9.865 +      UNIX. For example, there are mailbox formats in which the name is a
   9.866 +      directory and each message is a file within that directory; these
   9.867 +      formats support sub-mailboxes within such mailboxes. However, for
   9.868 +      technical reasons, the "flat file" formats are generally preferred
   9.869 +      since they perform better. Read imap-2007/docs/formats.txt for more
   9.870 +      information on this topic.</p>
   9.871 +
   9.872 +      <p>It is always permissible to create a directory that is not a
   9.873 +      mailbox, and have sub-mailboxes under it. The easiest way to create a
   9.874 +      directory is to create a new mailbox inside a directory that doesn't
   9.875 +      already exist. For example, if you create "Mail/testbox" on UNIX, the
   9.876 +      directory "Mail/" will automatically be created and then the mailbox
   9.877 +      "testbox" will be created as a sub-mailbox of "Mail/".</p>
   9.878 +
   9.879 +      <p>It is also possible to create the name "Mail/" directly. Check the
   9.880 +      documentation for your client software to see how to do this with that
   9.881 +      software.</p>
   9.882 +
   9.883 +      <p>Of course, on Windows systems you would use "\" instead of "/".</p>
   9.884 +    </dd>
   9.885 +  </dl>
   9.886 +
   9.887 +  <p><a href="#top">Back to top</a></p>
   9.888 +  <hr>
   9.889 +
   9.890 +  <p><a name="1.11"><strong>1.11 What is the difference between "mailbox" and
   9.891 +     "folder"?</strong></a></p>
   9.892 +
   9.893 +  <dl>
   9.894 +    <dd>
   9.895 +      The term "mailbox" is IMAP-speak for what a lot of software calls a
   9.896 +      "folder" or a "mail folder". However, "folder" is often used in other
   9.897 +      contexts to refer to a directory, for example, in the graphic user
   9.898 +      interface on both Windows and Macintosh.
   9.899 +
   9.900 +      <p>A "mailbox" is specifically defined as a named object that contains
   9.901 +      messages. It is not required to be capable of containing other types of
   9.902 +      objects including other mailboxes; although some mailbox formats will
   9.903 +      permit this.</p>
   9.904 +
   9.905 +      <p>In IMAP-speak, a mailbox which can not contain other mailboxes is
   9.906 +      called a "no-inferiors mailbox". Similarly, a directory which can not
   9.907 +      contain messages is not a mailbox and is called a "no-select name".</p>
   9.908 +    </dd>
   9.909 +  </dl>
   9.910 +
   9.911 +  <p><a href="#top">Back to top</a></p>
   9.912 +  <hr>
   9.913 +
   9.914 +  <p><a name="1.12"><strong>1.12 What is the status of
   9.915 +     internationalization?</strong></a></p>
   9.916 +
   9.917 +  <dl>
   9.918 +    <dd>
   9.919 +      The IMAP toolkit is partially internationalized and multilingualized.
   9.920 +
   9.921 +      <p>Searching is supported in the following charsets: US-ASCII, UTF-8,
   9.922 +      ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
   9.923 +      ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10, ISO-8859-11,
   9.924 +      ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, KOI8-R, KOI8-U
   9.925 +      (alias KOI8-RU), TIS-620, VISCII, ISO-2022-JP, ISO-2022-KR,
   9.926 +      ISO-2022-CN, ISO-2022-JP-1, ISO-2022-JP-2, GB2312 (alias CN-GB),
   9.927 +      CN-GB-12345, BIG5 (alias CN-BIG5), EUC-JP, EUC-KR, Shift_JIS,
   9.928 +      Shift-JIS, KS_C_5601-1987, KS_C_5601-1992, WINDOWS_874, WINDOWS-1250,
   9.929 +      WINDOWS-1251, WINDOWS-1252, WINDOWS-1253, WINDOWS-1254, WINDOWS-1255,
   9.930 +      WINDOWS-1256, WINDOWS-1257, WINDOWS-1258.</p>
   9.931 +
   9.932 +      <p>All ISO-2022-?? charsets are treated identically, and support ASCII,
   9.933 +      JIS Roman, hankaku katakana, ISO-8859-[1 - 10], TIS, GB 2312, JIS X
   9.934 +      0208, JIS X 0212, KSC 5601, and planes 1 and 2 of CNS 11643.</p>
   9.935 +
   9.936 +      <p>EUC-JP includes support for JIS X 0212 and hankaku katakana.</p>
   9.937 +
   9.938 +      <p>c-client library support also exists to convert text in any of the
   9.939 +      above charsets into Unicode, including headers with MIME
   9.940 +      encoded-words.</p>
   9.941 +
   9.942 +      <p>There is no support for localization (e.g. non-English error
   9.943 +      messages) at the present time, but such support is planned.</p>
   9.944 +    </dd>
   9.945 +  </dl>
   9.946 +
   9.947 +  <p><a href="#top">Back to top</a></p>
   9.948 +  <hr>
   9.949 +
   9.950 +  <p><a name="1.13"><strong>1.13 Can I use SSL?</strong></a></p>
   9.951 +
   9.952 +  <dl>
   9.953 +    <dd>Yes. See the answer to the <a href="#3.5">How do I configure SSL?</a>
   9.954 +    question.</dd>
   9.955 +  </dl>
   9.956 +
   9.957 +  <p><a href="#top">Back to top</a></p>
   9.958 +  <hr>
   9.959 +
   9.960 +  <p><a name="1.14"><strong>1.14 Can I use TLS and the STARTTLS
   9.961 +     facility?</strong></a></p>
   9.962 +
   9.963 +  <dl>
   9.964 +    <dd>Yes. See the answer to the <a href="#3.6">How do I configure TLS and
   9.965 +    the STARTTLS facility?</a> question.</dd>
   9.966 +  </dl>
   9.967 +
   9.968 +  <p><a href="#top">Back to top</a></p>
   9.969 +  <hr>
   9.970 +
   9.971 +  <p><a name="1.15"><strong>1.15 Can I use CRAM-MD5
   9.972 +     authentication?</strong></a></p>
   9.973 +
   9.974 +  <dl>
   9.975 +    <dd>Yes. See the answer to the <a href="#3.8">How do I configure CRAM-MD5
   9.976 +    authentication?</a> question.</dd>
   9.977 +  </dl>
   9.978 +
   9.979 +  <p><a href="#top">Back to top</a></p>
   9.980 +  <hr>
   9.981 +
   9.982 +  <p><a name="1.16"><strong>1.16 Can I use APOP authentication?</strong></a></p>
   9.983 +
   9.984 +  <dl>
   9.985 +    <dd>
   9.986 +      Yes. See the <a href="#3.9">How do I configure APOP authentication?</a>
   9.987 +      question.
   9.988 +
   9.989 +      <p>Note that there is no client support for APOP authentication.</p>
   9.990 +    </dd>
   9.991 +  </dl>
   9.992 +
   9.993 +  <p><a href="#top">Back to top</a></p>
   9.994 +  <hr>
   9.995 +
   9.996 +  <p><a name="1.17"><strong>1.17 Can I use Kerberos V5?</strong></a></p>
   9.997 +
   9.998 +  <dl>
   9.999 +    <dd>Yes. See the answer to the <a href="#3.10">How do I configure
  9.1000 +    Kerberos V5?</a> question.</dd>
  9.1001 +  </dl>
  9.1002 +
  9.1003 +  <p><a href="#top">Back to top</a></p>
  9.1004 +  <hr>
  9.1005 +
  9.1006 +  <p><a name="1.18"><strong>1.18 Can I use PAM for plaintext
  9.1007 +     passwords?</strong></a></p>
  9.1008 +
  9.1009 +  <dl>
  9.1010 +    <dd>Yes. See the answer to the <a href="#3.11">How do I configure PAM for
  9.1011 +    plaintext passwords?</a> question.</dd>
  9.1012 +  </dl>
  9.1013 +
  9.1014 +  <p><a href="#top">Back to top</a></p>
  9.1015 +  <hr>
  9.1016 +
  9.1017 +  <p><a name="1.19"><strong>1.19 Can I use Kerberos 5 for plaintext
  9.1018 +     passwords?</strong></a></p>
  9.1019 +
  9.1020 +  <dl>
  9.1021 +    <dd>Yes. See the answer to the <a href="#3.13">How do I configure
  9.1022 +    Kerberos 5 for plaintext passwords?</a> question.</dd>
  9.1023 +  </dl>
  9.1024 +
  9.1025 +  <p><a href="#top">Back to top</a></p>
  9.1026 +  <hr>
  9.1027 +
  9.1028 +  <p><a name="1.20"><strong>1.20 Can I use AFS for plaintext
  9.1029 +     passwords?</strong></a></p>
  9.1030 +
  9.1031 +  <dl>
  9.1032 +    <dd>Yes. See the answer to the <a href="#3.14">How do I configure AFS for
  9.1033 +    plaintext passwords?</a> question.</dd>
  9.1034 +  </dl>
  9.1035 +
  9.1036 +  <p><a href="#top">Back to top</a></p>
  9.1037 +  <hr>
  9.1038 +
  9.1039 +  <p><a name="1.21"><strong>1.21 Can I use DCE for plaintext
  9.1040 +     passwords?</strong></a></p>
  9.1041 +
  9.1042 +  <dl>
  9.1043 +    <dd>Yes. See the answer to the <a href="#3.15">How do I configure DCE for
  9.1044 +    plaintext passwords?</a> question.</dd>
  9.1045 +  </dl>
  9.1046 +
  9.1047 +  <p><a href="#top">Back to top</a></p>
  9.1048 +  <hr>
  9.1049 +
  9.1050 +  <p><a name="1.22"><strong>1.22 Can I use the CRAM-MD5 database for plaintext
  9.1051 +     passwords?</strong></a></p>
  9.1052 +
  9.1053 +  <dl>
  9.1054 +    <dd>Yes. See the answer to the <a href="#3.16">How do I configure the
  9.1055 +    CRAM-MD5 database for plaintext passwords?</a> question.</dd>
  9.1056 +  </dl>
  9.1057 +
  9.1058 +  <p><a href="#top">Back to top</a></p>
  9.1059 +  <hr>
  9.1060 +
  9.1061 +  <p><a name="1.23"><strong>1.23 Can I disable plaintext
  9.1062 +     passwords?</strong></a></p>
  9.1063 +
  9.1064 +  <dl>
  9.1065 +    <dd>Yes. See the answer to the <a href="#3.17">How do I disable plaintext
  9.1066 +    passwords?</a> question.</dd>
  9.1067 +  </dl>
  9.1068 +
  9.1069 +  <p><a href="#top">Back to top</a></p>
  9.1070 +  <hr>
  9.1071 +
  9.1072 +  <p><a name="1.24"><strong>1.24 Can I disable plaintext passwords on unencrypted
  9.1073 +     sessions, but allow them on encrypted sessions?</strong></a></p>
  9.1074 +
  9.1075 +  <dl>
  9.1076 +    <dd>Yes. See the answer to the <a href="#3.18">How do I disable plaintext
  9.1077 +    passwords on unencrypted sessions, but allow them in SSL or TLS
  9.1078 +    sessions?</a> question.</dd>
  9.1079 +  </dl>
  9.1080 +
  9.1081 +  <p><a href="#top">Back to top</a></p>
  9.1082 +  <hr>
  9.1083 +
  9.1084 +  <p><a name="1.25"><strong>1.25 Can I use virtual hosts?</strong></a></p>
  9.1085 +
  9.1086 +  <dl>
  9.1087 +    <dd>Yes. See the answer to the <a href="#3.19">How do I configure virtual
  9.1088 +    hosts?</a> question.</dd>
  9.1089 +  </dl>
  9.1090 +
  9.1091 +  <p><a href="#top">Back to top</a></p>
  9.1092 +  <hr>
  9.1093 +
  9.1094 +  <p><a name="1.26"><strong>1.26 Can I use RPOP authentication?</strong></a></p>
  9.1095 +
  9.1096 +  <dl>
  9.1097 +    <dd>There is no support for RPOP authentication.</dd>
  9.1098 +  </dl>
  9.1099 +
  9.1100 +  <p><a href="#top">Back to top</a></p>
  9.1101 +  <hr>
  9.1102 +
  9.1103 +  <p><a name="1.27"><strong>1.27 Can I use Kerberos V4?</strong></a></p>
  9.1104 +
  9.1105 +  <dl>
  9.1106 +    <dd>
  9.1107 +      Kerberos V4 is not supported. Kerberos V4 client-only contributed code
  9.1108 +      is available in
  9.1109 +      <pre>
  9.1110 +<a href=
  9.1111 +"ftp://ftp.cac.washington.edu/mail/kerberos4-patches.tar.Z">ftp://ftp.cac.washington.edu/mail/kerberos4-patches.tar.Z
  9.1112 +</a>
  9.1113 +</pre>This is a patchkit which must be applied to the IMAP toolkit according
  9.1114 +to the instructions in the patchkit's README. We can not promise that this
  9.1115 +code works.
  9.1116 +    </dd>
  9.1117 +  </dl>
  9.1118 +
  9.1119 +  <p><a href="#top">Back to top</a></p>
  9.1120 +  <hr>
  9.1121 +
  9.1122 +  <p><a name="1.28"><strong>1.28 Is there support for S/Key or
  9.1123 +     OTP?</strong></a></p>
  9.1124 +
  9.1125 +  <dl>
  9.1126 +    <dd>There is currently no support for S/Key or OTP. There may be an OTP
  9.1127 +    SASL authenticator available from third parties.</dd>
  9.1128 +  </dl>
  9.1129 +
  9.1130 +  <p><a href="#top">Back to top</a></p>
  9.1131 +  <hr>
  9.1132 +
  9.1133 +  <p><a name="1.29"><strong>1.29 Is there support for NTLM or
  9.1134 +     SPA?</strong></a></p>
  9.1135 +
  9.1136 +  <dl>
  9.1137 +    <dd>
  9.1138 +      There is currently no support for NTLM or SPA, nor are there any plans
  9.1139 +      to add such support. In general, I avoid vendor-specific mechanisms. I
  9.1140 +      also believe that these mechanisms are being deprecated by their
  9.1141 +      vendor.
  9.1142 +
  9.1143 +      <p>There may be an NTLM SASL authenticator available from third
  9.1144 +      parties.</p>
  9.1145 +    </dd>
  9.1146 +  </dl>
  9.1147 +
  9.1148 +  <p><a href="#top">Back to top</a></p>
  9.1149 +  <hr>
  9.1150 +
  9.1151 +  <p><a name="1.30"><strong>1.30 Is there support for mh?</strong></a></p>
  9.1152 +
  9.1153 +  <dl>
  9.1154 +    <dd>
  9.1155 +      Yes, but only as a legacy format. Your mh format INBOX is accessed by
  9.1156 +      the name "#mhinbox", and all other mh format mailboxes are accessed by
  9.1157 +      prefixing "#mh/" to the name, e.g. "#mh/foo". The mh support uses the
  9.1158 +      "Path:" entry in your .mh_profile file to identify the root directory
  9.1159 +      of your mh format mailboxes.
  9.1160 +
  9.1161 +      <p>Non-legacy use of mh format is not encouraged. There is no support
  9.1162 +      for permanent flags or unique identifiers; furthermore there are known
  9.1163 +      severe performance problems with the mh format.</p>
  9.1164 +    </dd>
  9.1165 +  </dl>
  9.1166 +
  9.1167 +  <p><a href="#top">Back to top</a></p>
  9.1168 +  <hr>
  9.1169 +
  9.1170 +  <p><a name="1.31"><strong>1.31 Is there support for qmail and the maildir
  9.1171 +     format?</strong></a></p>
  9.1172 +
  9.1173 +  <dl>
  9.1174 +    <dd>There is no support for qmail or the maildir format in our
  9.1175 +    distribution, nor are there any plans to add such support. Maildir
  9.1176 +    support may be available from third parties.</dd>
  9.1177 +  </dl>
  9.1178 +
  9.1179 +  <p><a href="#top">Back to top</a></p>
  9.1180 +  <hr>
  9.1181 +
  9.1182 +  <p><a name="1.32"><strong>1.32 Is there support for the Cyrus mailbox
  9.1183 +     format?</strong></a></p>
  9.1184 +
  9.1185 +  <dl>
  9.1186 +    <dd>No.</dd>
  9.1187 +  </dl>
  9.1188 +
  9.1189 +  <p><a href="#top">Back to top</a></p>
  9.1190 +  <hr>
  9.1191 +
  9.1192 +  <p><a name="1.33"><strong>1.33 Is this software Y2K compliant?</strong></a></p>
  9.1193 +
  9.1194 +  <dl>
  9.1195 +    <dd>Please read the files Y2K and calendar.txt.</dd>
  9.1196 +  </dl>
  9.1197 +
  9.1198 +  <p><a href="#top">Back to top</a></p>
  9.1199 +  <hr>
  9.1200 +
  9.1201 +  <p><br></p>
  9.1202 +
  9.1203 +  <h2><a name="requirements">2. What Do I Need to Build This Software?</a></h2>
  9.1204 +  <hr>
  9.1205 +
  9.1206 +  <p><a name="2.1"><strong>2.1 What do I need to build this software with SSL on
  9.1207 +     UNIX?</strong></a></p>
  9.1208 +
  9.1209 +  <dl>
  9.1210 +    <dd>You need to build and install OpenSSL first.</dd>
  9.1211 +  </dl>
  9.1212 +
  9.1213 +  <p><a href="#top">Back to top</a></p>
  9.1214 +  <hr>
  9.1215 +
  9.1216 +  <p><a name="2.2"><strong>2.2 What do I need to build this software with Kerberos
  9.1217 +     V on UNIX?</strong></a></p>
  9.1218 +
  9.1219 +  <dl>
  9.1220 +    <dd>You need to build and install MIT Kerberos first.</dd>
  9.1221 +  </dl>
  9.1222 +
  9.1223 +  <p><a href="#top">Back to top</a></p>
  9.1224 +  <hr>
  9.1225 +
  9.1226 +  <p><a name="2.3"><strong>2.3 What do I need to use a C++ compiler with this
  9.1227 +     software to build my own application?</strong></a></p>
  9.1228 +
  9.1229 +  <dl>
  9.1230 +    <dd>
  9.1231 +      If you are building an application using the c-client library, use the
  9.1232 +      new c-client.h file instead of including the other include files. It
  9.1233 +      seems that c-client.h should define away all the troublesome names that
  9.1234 +      conflict with C++.
  9.1235 +
  9.1236 +      <p>If you use gcc, you may need to use -fno-operator-names as well.</p>
  9.1237 +    </dd>
  9.1238 +  </dl>
  9.1239 +
  9.1240 +  <p><a href="#top">Back to top</a></p>
  9.1241 +  <hr>
  9.1242 +
  9.1243 +  <p><a name="2.4"><strong>2.4 What do I need to build this software on
  9.1244 +     Windows?</strong></a></p>
  9.1245 +
  9.1246 +  <dl>
  9.1247 +    <dd>
  9.1248 +      You need Microsoft Visual C++ 6.0, Visual C++ .NET, or Visual C# .NET
  9.1249 +      (which you can buy from any computer store), along with the Microsoft
  9.1250 +      Platform SDK (which you can download from Microsoft's web site).
  9.1251 +
  9.1252 +      <p>You do not need to install the entire Platform SDK; it suffices to
  9.1253 +      install just the Core SDK and the Internet Development SDK.</p>
  9.1254 +    </dd>
  9.1255 +  </dl>
  9.1256 +
  9.1257 +  <p><a href="#top">Back to top</a></p>
  9.1258 +  <hr>
  9.1259 +
  9.1260 +  <p><a name="2.5"><strong>2.5 What do I need to build this software on
  9.1261 +     DOS?</strong></a></p>
  9.1262 +
  9.1263 +  <dl>
  9.1264 +    <dd>It's been several years since we last attempted to do this. At the
  9.1265 +    time, we used Microsoft C.</dd>
  9.1266 +  </dl>
  9.1267 +
  9.1268 +  <p><a href="#top">Back to top</a></p>
  9.1269 +  <hr>
  9.1270 +
  9.1271 +  <p><a name="2.6"><strong>2.6 Can't I use Borland C to build this software on the
  9.1272 +     PC?</strong></a></p>
  9.1273 +
  9.1274 +  <dl>
  9.1275 +    <dd>Probably not. If you know otherwise, please let us know.</dd>
  9.1276 +  </dl>
  9.1277 +
  9.1278 +  <p><a href="#top">Back to top</a></p>
  9.1279 +  <hr>
  9.1280 +
  9.1281 +  <p><a name="2.7"><strong>2.7 What do I need to build this software on the
  9.1282 +     Mac?</strong></a></p>
  9.1283 +
  9.1284 +  <dl>
  9.1285 +    <dd>It has been several years since we last attempted to do this. At the
  9.1286 +    time, we used Symantec THINK C; but today you'll need a C compiler which
  9.1287 +    allows segments to be more than 32K.</dd>
  9.1288 +  </dl>
  9.1289 +
  9.1290 +  <p><a href="#top">Back to top</a></p>
  9.1291 +  <hr>
  9.1292 +
  9.1293 +  <p><a name="2.8"><strong>2.8 What do I need to build this software on
  9.1294 +     VMS?</strong></a></p>
  9.1295 +
  9.1296 +  <dl>
  9.1297 +    <dd>You need the VMS C compiler, and either the Multinet or Netlib
  9.1298 +    TCP.</dd>
  9.1299 +  </dl>
  9.1300 +
  9.1301 +  <p><a href="#top">Back to top</a></p>
  9.1302 +  <hr>
  9.1303 +
  9.1304 +  <p><a name="2.9"><strong>2.9 What do I need to build this software on
  9.1305 +     TOPS-20?</strong></a></p>
  9.1306 +
  9.1307 +  <dl>
  9.1308 +    <dd>You need the TOPS-20 KCC compiler.</dd>
  9.1309 +  </dl>
  9.1310 +
  9.1311 +  <p><a href="#top">Back to top</a></p>
  9.1312 +  <hr>
  9.1313 +
  9.1314 +  <p><a name="2.10"><strong>2.10 What do I need to build this software on Amiga or
  9.1315 +     OS/2?</strong></a></p>
  9.1316 +
  9.1317 +  <dl>
  9.1318 +    <dd>We don't know.</dd>
  9.1319 +  </dl>
  9.1320 +
  9.1321 +  <p><a href="#top">Back to top</a></p>
  9.1322 +  <hr>
  9.1323 +
  9.1324 +  <p><a name="2.11"><strong>2.11 What do I need to build this software on Windows
  9.1325 +     CE?</strong></a></p>
  9.1326 +
  9.1327 +  <dl>
  9.1328 +    <dd>This port is incomplete. Someone needs to finish it.</dd>
  9.1329 +  </dl>
  9.1330 +
  9.1331 +  <p><a href="#top">Back to top</a></p>
  9.1332 +  <hr>
  9.1333 +
  9.1334 +  <p><br></p>
  9.1335 +
  9.1336 +  <h2><a name="build">3. Build and Configuration Questions</a></h2>
  9.1337 +  <hr>
  9.1338 +
  9.1339 +  <p><a name="3.1"><strong>3.1 How do I configure the IMAP and POP servers on
  9.1340 +     UNIX?</strong></a><br>
  9.1341 +  <a name="3.2"><strong>3.2 I built and installed the servers according to the
  9.1342 +     BUILD instructions. It can't be that easy. Don't I need to write a
  9.1343 +     config file?</strong></a></p>
  9.1344 +
  9.1345 +  <dl>
  9.1346 +    <dd>
  9.1347 +      For ordinary "vanilla" UNIX systems, this software is plug and play;
  9.1348 +      just build it, install it, and you're done. If you have a modified
  9.1349 +      system, then you may want to do additional work; most of this is to a
  9.1350 +      single source code file (env_unix.c on UNIX systems). Read the file
  9.1351 +      CONFIG for more details.
  9.1352 +
  9.1353 +      <p>Yes, it's that easy. There are some additional options, such as SSL
  9.1354 +      or Kerberos, which require additional steps to build. See the relevant
  9.1355 +      questions below.</p>
  9.1356 +    </dd>
  9.1357 +  </dl>
  9.1358 +
  9.1359 +  <p><a href="#top">Back to top</a></p>
  9.1360 +  <hr>
  9.1361 +
  9.1362 +  <p><a name="3.3"><strong>3.3 How do I make the IMAP and POP servers look for
  9.1363 +     INBOX at some place other than the mail spool
  9.1364 +     directory?</strong></a><br>
  9.1365 +  <a name="3.4"><strong>3.4 How do I make the IMAP server look for secondary
  9.1366 +     folders at some place other than the user's home
  9.1367 +     directory?</strong></a></p>
  9.1368 +
  9.1369 +  <dl>
  9.1370 +    <dd>Please read the file CONFIG for discussion of this and other
  9.1371 +    issues.</dd>
  9.1372 +  </dl>
  9.1373 +
  9.1374 +  <p><a href="#top">Back to top</a></p>
  9.1375 +  <hr>
  9.1376 +
  9.1377 +  <p><a name="3.5"><strong>3.5 How do I configure SSL?</strong></a><br>
  9.1378 +  <a name="3.6"><strong>3.6 How do I configure TLS and the STARTTLS
  9.1379 +     facility?</strong></a></p>
  9.1380 +
  9.1381 +  <dl>
  9.1382 +    <dd>
  9.1383 +      imap-2007 supports SSL and TLS client functionality on UNIX and 32-bit
  9.1384 +      Windows for IMAP, POP3, SMTP, and NNTP; and SSL and TLS server
  9.1385 +      functionality on UNIX for IMAP and POP3.
  9.1386 +
  9.1387 +      <p>UNIX SSL build requires that a third-party software package,
  9.1388 +      OpenSSL, be installed on the system first. Read imap-2007/docs/SSLBUILD
  9.1389 +      for more information.</p>
  9.1390 +
  9.1391 +      <p>SSL is supported via undocumented Microsoft interfaces in Windows 9x
  9.1392 +      and NT4; and via standard interfaces in Windows 2000, Windows
  9.1393 +      Millenium, and Windows XP.</p>
  9.1394 +    </dd>
  9.1395 +  </dl>
  9.1396 +
  9.1397 +  <p><a href="#top">Back to top</a></p>
  9.1398 +  <hr>
  9.1399 +
  9.1400 +  <p><a name="3.7"><strong>3.7 How do I build/install OpenSSL and obtain/create
  9.1401 +     certificates for use with SSL?</strong></a></p>
  9.1402 +
  9.1403 +  <dl>
  9.1404 +    <dd>If you need help in doing this, try the contacts mentioned in the
  9.1405 +    OpenSSL README. We do not offer support for OpenSSL or certificates.</dd>
  9.1406 +  </dl>
  9.1407 +
  9.1408 +  <p><a href="#top">Back to top</a></p>
  9.1409 +  <hr>
  9.1410 +
  9.1411 +  <p><a name="3.8"><strong>3.8 How do I configure CRAM-MD5
  9.1412 +     authentication?</strong></a><br>
  9.1413 +  <a name="3.9"><strong>3.9 How do I configure APOP
  9.1414 +     authentication?</strong></a></p>
  9.1415 +
  9.1416 +  <dl>
  9.1417 +    <dd>
  9.1418 +      CRAM-MD5 authentication is enabled in the IMAP and POP3 client code on
  9.1419 +      all platforms. Read md5.txt to learn how to set up CRAM-MD5 and APOP
  9.1420 +      authentication on UNIX and NT servers.
  9.1421 +
  9.1422 +      <p>There is no support for APOP client authentication.</p>
  9.1423 +    </dd>
  9.1424 +  </dl>
  9.1425 +
  9.1426 +  <p><a href="#top">Back to top</a></p>
  9.1427 +  <hr>
  9.1428 +
  9.1429 +  <p><a name="3.10"><strong>3.10 How do I configure Kerberos V5?</strong></a></p>
  9.1430 +
  9.1431 +  <dl>
  9.1432 +    <dd>
  9.1433 +      imap-2007 supports client and server functionality on UNIX and 32-bit
  9.1434 +      Windows.
  9.1435 +
  9.1436 +      <p>Kerberos V5 is supported by default in Windows 2000 builds:</p>
  9.1437 +      <pre>
  9.1438 + nmake -f makefile.w2k
  9.1439 +</pre>
  9.1440 +
  9.1441 +      <p>Other builds require that a third-party Kerberos package, e.g. MIT
  9.1442 +      Kerberos, be installed on the system first.</p>
  9.1443 +
  9.1444 +      <p>To build with Kerberos V5 on UNIX, include EXTRAAUTHENTICATORS=gss
  9.1445 +      in the make command line, e.g.</p>
  9.1446 +      <pre>
  9.1447 + make lnp EXTRAAUTHENTICATORS=gss
  9.1448 +</pre>
  9.1449 +
  9.1450 +      <p>To build with Kerberos V5 on Windows 9x, Windows Millenium, and NT4,
  9.1451 +      use the "makefile.ntk" file instead of "makefile.nt":</p>
  9.1452 +      <pre>
  9.1453 +
  9.1454 + nmake -f makefile.ntk
  9.1455 +</pre>
  9.1456 +    </dd>
  9.1457 +  </dl>
  9.1458 +
  9.1459 +  <p><a href="#top">Back to top</a></p>
  9.1460 +  <hr>
  9.1461 +
  9.1462 +  <p><a name="3.11"><strong>3.11 How do I configure PAM for plaintext
  9.1463 +     passwords?</strong></a></p>
  9.1464 +
  9.1465 +  <dl>
  9.1466 +    <dd>
  9.1467 +      On Linux systems, use the lnp port, e.g.
  9.1468 +      <pre>
  9.1469 + make lnp
  9.1470 +
  9.1471 +</pre>On Solaris systems and other systems with defective PAM
  9.1472 +implementations, build with PASSWDTYPE=pmb, e.g.
  9.1473 +      <pre>
  9.1474 + make sol PASSWDTYPE=pmb
  9.1475 +</pre>On all other systems, build with PASSWDTYPE=pam, e.g
  9.1476 +      <pre>
  9.1477 + make foo PASSWDTYPE=pam
  9.1478 +</pre>If you build with PASSWDTYPE=pam and authentication does not work, try
  9.1479 +rebuilding (after a "make clean") with PASSWDTYPE=pmb.
  9.1480 +    </dd>
  9.1481 +  </dl>
  9.1482 +
  9.1483 +  <p><a href="#top">Back to top</a></p>
  9.1484 +  <hr>
  9.1485 +
  9.1486 +  <p><a name="3.12"><strong>3.12 It looks like all I have to do to make the server
  9.1487 +     use Kerberos is to build with PAM on my Linux system, and set it up in
  9.1488 +     PAM for Kerberos passwords. Right?</strong></a></p>
  9.1489 +
  9.1490 +  <dl>
  9.1491 +    <dd>
  9.1492 +      Yes and no.
  9.1493 +
  9.1494 +      <p>Doing this will make plaintext password authentication use the
  9.1495 +      Kerberos password instead of the /etc/passwd password.</p>
  9.1496 +
  9.1497 +      <p>However, this will NOT give you Kerberos-secure authentication. See
  9.1498 +      the answer to the <a href="#3.10">How do I configure Kerberos V5?</a>
  9.1499 +      question for how to build with Kerberos-secure authentication.</p>
  9.1500 +    </dd>
  9.1501 +  </dl>
  9.1502 +
  9.1503 +  <p><a href="#top">Back to top</a></p>
  9.1504 +  <hr>
  9.1505 +
  9.1506 +  <p><a name="3.13"><strong>3.13 How do I configure Kerberos 5 for plaintext
  9.1507 +     passwords?</strong></a></p>
  9.1508 +
  9.1509 +  <dl>
  9.1510 +    <dd>
  9.1511 +      Build with PASSWDTYPE=gss, e.g.
  9.1512 +      <pre>
  9.1513 + make sol PASSWDTYPE=gss
  9.1514 +</pre>However, this will NOT give you Kerberos-secure authentication. See the
  9.1515 +answer to the <a href="#3.10">How do I configure Kerberos V5?</a> question
  9.1516 +for how to build with Kerberos-secure authentication.
  9.1517 +    </dd>
  9.1518 +  </dl>
  9.1519 +
  9.1520 +  <p><a href="#top">Back to top</a></p>
  9.1521 +  <hr>
  9.1522 +
  9.1523 +  <p><a name="3.14"><strong>3.14 How do I configure AFS for plaintext
  9.1524 +     passwords?</strong></a></p>
  9.1525 +
  9.1526 +  <dl>
  9.1527 +    <dd>
  9.1528 +      Build with PASSWDTYPE=afs, e.g
  9.1529 +      <pre>
  9.1530 + make sol PASSWDTYPE=afs
  9.1531 +
  9.1532 +</pre>
  9.1533 +    </dd>
  9.1534 +  </dl>
  9.1535 +
  9.1536 +  <p><a href="#top">Back to top</a></p>
  9.1537 +  <hr>
  9.1538 +
  9.1539 +  <p><a name="3.15"><strong>3.15 How do I configure DCE for plaintext
  9.1540 +     passwords?</strong></a></p>
  9.1541 +
  9.1542 +  <dl>
  9.1543 +    <dd>
  9.1544 +      Build with PASSWDTYPE=dce, e.g
  9.1545 +      <pre>
  9.1546 + make sol PASSWDTYPE=dce
  9.1547 +</pre>
  9.1548 +    </dd>
  9.1549 +  </dl>
  9.1550 +
  9.1551 +  <p><a href="#top">Back to top</a></p>
  9.1552 +  <hr>
  9.1553 +
  9.1554 +  <p><a name="3.16"><strong>3.16 How do I configure the CRAM-MD5 database for
  9.1555 +     plaintext passwords?</strong></a></p>
  9.1556 +
  9.1557 +  <dl>
  9.1558 +    <dd>
  9.1559 +      The CRAM-MD5 password database is automatically used for plaintext
  9.1560 +      password if it exists.
  9.1561 +
  9.1562 +      <p>Note that this is NOT CRAM-MD5-secure authentication. You probably
  9.1563 +      want to consider disabling plaintext passwords for non-SSL/TLS
  9.1564 +      sessions. See the next two questions.</p>
  9.1565 +    </dd>
  9.1566 +  </dl>
  9.1567 +
  9.1568 +  <p><a href="#top">Back to top</a></p>
  9.1569 +  <hr>
  9.1570 +
  9.1571 +  <p><a name="3.17"><strong>3.17 How do I disable plaintext
  9.1572 +     passwords?</strong></a></p>
  9.1573 +
  9.1574 +  <dl>
  9.1575 +    <dd>
  9.1576 +      Server-level plaintext passwords can be disabled by setting
  9.1577 +      PASSWDTYPE=nul, e.g.
  9.1578 +      <pre>
  9.1579 + make lnx EXTRAAUTHENTICATORS=gss PASSWDTYPE=nul
  9.1580 +</pre>Note that you must have a CRAM-MD5 database installed or specify at
  9.1581 +least one EXTRAAUTHENTICATOR, otherwise it will not be possible to log in to
  9.1582 +the server.
  9.1583 +
  9.1584 +      <p>When plaintext passwords are disabled, the IMAP server will
  9.1585 +      advertise the LOGINDISABLED capability and the POP3 server will not
  9.1586 +      advertise the USER capability.</p>
  9.1587 +    </dd>
  9.1588 +  </dl>
  9.1589 +
  9.1590 +  <p><a href="#top">Back to top</a></p>
  9.1591 +
  9.1592 +  <p><a name="3.18"><strong>3.18 How do I disable plaintext passwords on
  9.1593 +     unencrypted sessions, but allow them in SSL or TLS
  9.1594 +     sessions?</strong></a></p>
  9.1595 +
  9.1596 +  <dl>
  9.1597 +    <dd>
  9.1598 +      <p>Do not set PASSWDTYPE=nul or SSLTYPE=unix. Set SSLTYPE=nopwd
  9.1599 +      instead, e.g.</p>
  9.1600 +      <pre>
  9.1601 + make lnx SSLTYPE=nopwd
  9.1602 +</pre>
  9.1603 +
  9.1604 +      <p>When plaintext passwords are disabled, the IMAP server will
  9.1605 +      advertise the LOGINDISABLED capability and the POP3 server will not
  9.1606 +      advertise the USER capability.</p>
  9.1607 +
  9.1608 +      <p>Plaintext passwords will always be enabled in SSL sessions; the IMAP
  9.1609 +      server will not advertise the LOGINDISABLED capability and the POP3
  9.1610 +      server will advertise the USER capability.</p>
  9.1611 +
  9.1612 +      <p>If the client does a successful start-TLS in a non-SSL session,
  9.1613 +      plaintext passwords will be enabled, and a new CAPABILITY or CAPA
  9.1614 +      command (which is required after start-TLS) will show the effect as in
  9.1615 +      SSL sessions.</p>
  9.1616 +    </dd>
  9.1617 +  </dl>
  9.1618 +
  9.1619 +  <p><a href="#top">Back to top</a></p>
  9.1620 +  <hr>
  9.1621 +
  9.1622 +  <p><a name="3.19"><strong>3.19 How do I configure virtual
  9.1623 +     hosts?</strong></a></p>
  9.1624 +
  9.1625 +  <dl>
  9.1626 +    <dd>
  9.1627 +      This is automatic, but with certain restrictions.
  9.1628 +
  9.1629 +      <p>The most important one is that each virtual host must have its own
  9.1630 +      IP address; otherwise the server has no way of knowing which virtual
  9.1631 +      host is desired.</p>
  9.1632 +
  9.1633 +      <p>As distributed, the software uses a global password file; hence user
  9.1634 +      "fred" on one virtual host is "fred" on all virtual hosts. You may want
  9.1635 +      to modify the checkpw() routine to implement some other policy (e.g.
  9.1636 +      separate password files).</p>
  9.1637 +
  9.1638 +      <p>Note that the security model assumes that all users have their own
  9.1639 +      unique UNIX UID number. So if you use separate password files you
  9.1640 +      should make certain that the UID numbers do not overlap between
  9.1641 +      different files.</p>
  9.1642 +
  9.1643 +      <p>More advanced virtual host support may be available as patches from
  9.1644 +      third parties.</p>
  9.1645 +    </dd>
  9.1646 +  </dl>
  9.1647 +
  9.1648 +  <p><a href="#top">Back to top</a></p>
  9.1649 +  <hr>
  9.1650 +
  9.1651 +  <p><a name="3.20"><strong>3.20 Why do I get compiler warning messages such
  9.1652 +     as:</strong></a></p>
  9.1653 +  <pre>
  9.1654 + passing arg 3 of `scandir' from incompatible pointer type
  9.1655 + Pointers are not assignment-compatible.
  9.1656 + Argument #4 is not the correct type.
  9.1657 +
  9.1658 +</pre>
  9.1659 +
  9.1660 +  <p><strong>during the build?</strong></p>
  9.1661 +
  9.1662 +  <dl>
  9.1663 +    <dd>
  9.1664 +      You can safely ignore these messages.
  9.1665 +
  9.1666 +      <p>Over the years, the prototype for scandir() has changed, and thus is
  9.1667 +      variant across different UNIX platforms. In particular, the definitions
  9.1668 +      of the third argument (type select_t) and fourth argument (type
  9.1669 +      compar_t) have changed over the years, the issue being whether or not
  9.1670 +      the arguments to the functions pointed to by these function pointers
  9.1671 +      are of type const or not.</p>
  9.1672 +
  9.1673 +      <p>The way that c-client calls scandir() will tend to generate these
  9.1674 +      compiler warnings on newer systems such as Linux; however, it will
  9.1675 +      still build. The problem with fixing the call is that then it won't
  9.1676 +      build on older systems.</p>
  9.1677 +    </dd>
  9.1678 +  </dl>
  9.1679 +
  9.1680 +  <p><a href="#top">Back to top</a></p>
  9.1681 +  <hr>
  9.1682 +
  9.1683 +  <p><a name="3.21"><strong>3.21 Why do I get compiler warning messages such
  9.1684 +     as</strong></a></p>
  9.1685 +  <pre>
  9.1686 + Operation between types "void(*)(int)" and "void*" is not allowed.
  9.1687 + Function argument assignment between types "void*" and "void(*)(int)" is not allowed.
  9.1688 + Pointers are not assignment-compatible.
  9.1689 + Argument #5 is not the correct type.
  9.1690 +</pre>
  9.1691 +
  9.1692 +  <p><strong>during the build?</strong></p>
  9.1693 +
  9.1694 +  <dl>
  9.1695 +    <dd>
  9.1696 +      You can safely ignore these messages.
  9.1697 +
  9.1698 +      <p>All known systems have no problem with casting a function pointer
  9.1699 +      to/from a void* pointer, certain C compilers issue a compiler
  9.1700 +      diagnostic because this facility is listed as a "Common extension" by
  9.1701 +      the C standard:</p>
  9.1702 +      <pre>
  9.1703 + K.5.7  Function pointer casts
  9.1704 +  [#1] A pointer to an object or to void may be cast to a pointer
  9.1705 +       to a function, allowing data to be invoked as a function (6.3.4).
  9.1706 +  [#2] A pointer to a function may be cast to a pointer to an
  9.1707 +       object or to void, allowing a function to be inspected or
  9.1708 +       modified (for example, by a debugger) (6.3.4).
  9.1709 +
  9.1710 +</pre>It may be just a "common extension", but this facility is relied upon
  9.1711 +heavily by c-client.
  9.1712 +    </dd>
  9.1713 +  </dl>
  9.1714 +
  9.1715 +  <p><a href="#top">Back to top</a></p>
  9.1716 +  <hr>
  9.1717 +
  9.1718 +  <p><a name="3.22"><strong>3.22 Why do I get linker warning messages such
  9.1719 +     as:</strong></a></p>
  9.1720 +  <pre>
  9.1721 +mtest.c:515: the `gets' function is dangerous and should not be used.
  9.1722 +</pre>
  9.1723 +
  9.1724 +  <p><strong>during the build? Isn't this a security bug?</strong></p>
  9.1725 +
  9.1726 +  <dl>
  9.1727 +    <dd>
  9.1728 +      You can safely ignore this message.
  9.1729 +
  9.1730 +      <p>Certain linkers, most notably on Linux, give this warning message.
  9.1731 +      It is indeed true that the traditional gets() function is not a safe
  9.1732 +      one.</p>
  9.1733 +
  9.1734 +      <p>However, the mtest program is only a demonstration program, a model
  9.1735 +      of a very basic application program using c-client. It is not something
  9.1736 +      that you would install, much less run in any security-sensitive
  9.1737 +      context.</p>
  9.1738 +
  9.1739 +      <p>mtest has numerous other shortcuts that you wouldn't want to do in a
  9.1740 +      real application program.</p>
  9.1741 +
  9.1742 +      <p>The only "security bug" with mtest would be if it was run by some
  9.1743 +      script in a security-sensitive context, but mtest isn't particularly
  9.1744 +      useful for such purposes. If you wanted to write a script to automate
  9.1745 +      some email task using c-client, you'd be better off using imapd instead
  9.1746 +      of mtest.</p>
  9.1747 +
  9.1748 +      <p>mtest only has two legitimate uses. It's a useful testbed for me
  9.1749 +      when debugging new versions of c-client, and it's useful as a model for
  9.1750 +      someone writing a simple c-client application to see how the various
  9.1751 +      calls work.</p>
  9.1752 +
  9.1753 +      <p>By the way, if you need a more advanced example of c-client
  9.1754 +      programming than mtest (and you probably will), I recommend that you
  9.1755 +      look at the source code for imapd and Pine.</p>
  9.1756 +    </dd>
  9.1757 +  </dl>
  9.1758 +
  9.1759 +  <p><a href="#top">Back to top</a></p>
  9.1760 +  <hr>
  9.1761 +
  9.1762 +  <p><a name="3.23"><strong>3.23 Why do I get linker warning messages such
  9.1763 +     as:</strong></a></p>
  9.1764 +  <pre>
  9.1765 + auth_ssl.c:92: the `tmpnam' function is dangerous and should not be used.
  9.1766 +</pre>
  9.1767 +
  9.1768 +  <p><strong>during the build? Isn't this a security bug?</strong></p>
  9.1769 +
  9.1770 +  <dl>
  9.1771 +    <dd>
  9.1772 +      You can safely ignore this message.
  9.1773 +
  9.1774 +      <p>Certain linkers, most notably on Linux, give this warning message,
  9.1775 +      based upon two known issues with tmpnam():</p>
  9.1776 +
  9.1777 +      <dl>
  9.1778 +        <dd>there can be a buffer overflow if an inadequate buffer is
  9.1779 +        allocated.</dd>
  9.1780 +
  9.1781 +        <dd>there can be a timing race caused by certain incautious usage of
  9.1782 +        the return value.</dd>
  9.1783 +      </dl>
  9.1784 +
  9.1785 +      <p>Neither of these issues applies in the particular use that is made
  9.1786 +      of tmpnam(). More importantly, the tmpnam() call is never executed on
  9.1787 +      Linux systems.</p>
  9.1788 +    </dd>
  9.1789 +  </dl>
  9.1790 +
  9.1791 +  <p><a href="#top">Back to top</a></p>
  9.1792 +  <hr>
  9.1793 +
  9.1794 +  <p><a name="3.24"><strong>3.24 OK, suppose I see a warning message about a
  9.1795 +     function being "dangerous and should not be used" for something other
  9.1796 +     than this gets() or tmpnam() call?</strong></a></p>
  9.1797 +
  9.1798 +  <dl>
  9.1799 +    <dd>Please forward the details for investigation.</dd>
  9.1800 +  </dl>
  9.1801 +
  9.1802 +  <p><a href="#top">Back to top</a></p>
  9.1803 +  <hr>
  9.1804 +
  9.1805 +  <p><br></p>
  9.1806 +
  9.1807 +  <h2><a name="operation">4. Operational Questions</a></h2>
  9.1808 +  <hr>
  9.1809 +
  9.1810 +  <p><a name="4.1"><strong>4.1 How can I enable anonymous IMAP
  9.1811 +     logins?</strong></a></p>
  9.1812 +
  9.1813 +  <dl>
  9.1814 +    <dd>Create the file /etc/anonymous.newsgroups. At the present time, this
  9.1815 +    file should be empty. This will permit IMAP logins as anonymous as well
  9.1816 +    as the ANONYMOUS SASL authenticator. Anonymous users have access to
  9.1817 +    mailboxes in the #news., #ftp/, and #public/ namespaces only.</dd>
  9.1818 +  </dl>
  9.1819 +
  9.1820 +  <p><a href="#top">Back to top</a></p>
  9.1821 +  <hr>
  9.1822 +
  9.1823 +  <p><a name="4.2"><strong>4.2 How do I set up an alert message that each IMAP
  9.1824 +     user will see?</strong></a></p>
  9.1825 +
  9.1826 +  <dl>
  9.1827 +    <dd>Create the file /etc/imapd.alert with the text of the message. This
  9.1828 +    text should be kept to one line if possible. Note that this will cause an
  9.1829 +    alert to every IMAP user every time they initiate an IMAP session, so it
  9.1830 +    should only be used for critical messages.</dd>
  9.1831 +  </dl>
  9.1832 +
  9.1833 +  <p><a href="#top">Back to top</a></p>
  9.1834 +  <hr>
  9.1835 +
  9.1836 +  <p><a name="4.3"><strong>4.3 How does the c-client library choose which of its
  9.1837 +     several mechanisms to use to establish an IMAP connection to the server?
  9.1838 +     I noticed that it can connect on port 143, port 993, via rsh, and via
  9.1839 +     ssh.</strong></a></p>
  9.1840 +
  9.1841 +  <dl>
  9.1842 +    <dd>
  9.1843 +      c-client chooses how to establish an IMAP connection via the following
  9.1844 +      rules:
  9.1845 +
  9.1846 +      <ul>
  9.1847 +        <li>If /ssl is specified, use an SSL connection. Fail otherwise.</li>
  9.1848 +
  9.1849 +        <li>Else if client is a UNIX system and "ssh server exec /etc/rimapd"
  9.1850 +        works, use that</li>
  9.1851 +
  9.1852 +        <li>Else if /tryssl is specified and an SSL connection works, use
  9.1853 +        that.</li>
  9.1854 +
  9.1855 +        <li>Else if client is a UNIX system and "rsh server exec /etc/rimapd"
  9.1856 +        works, use that.</li>
  9.1857 +
  9.1858 +        <li>Else use a non-SSL connection.</li>
  9.1859 +      </ul>
  9.1860 +    </dd>
  9.1861 +  </dl>
  9.1862 +
  9.1863 +  <p><a href="#top">Back to top</a></p>
  9.1864 +  <hr>
  9.1865 +
  9.1866 +  <p><a name="4.4"><strong>4.4 I am using a TLS-capable IMAP server, so I don't
  9.1867 +     need to use /ssl to get encryption. However, I want to be certain that
  9.1868 +     my session is TLS encrypted before I send my password. How to I do
  9.1869 +     this?</strong></a></p>
  9.1870 +
  9.1871 +  <dl>
  9.1872 +    <dd>Use the /tls option in the mailbox name. This will cause an error
  9.1873 +    message and the connection to fail if the server does not negotiate
  9.1874 +    STARTTLS.</dd>
  9.1875 +  </dl>
  9.1876 +
  9.1877 +  <p><a href="#top">Back to top</a></p>
  9.1878 +  <hr>
  9.1879 +
  9.1880 +  <p><a name="4.5"><strong>4.5 How do I use one of the alternative formats
  9.1881 +     described in the formats.txt document? In particular, I hear that mbx
  9.1882 +     format will give me better performance and allow shared
  9.1883 +     access.</strong></a></p>
  9.1884 +
  9.1885 +  <dl>
  9.1886 +    <dd>
  9.1887 +      The rumors about mbx format being preferred are true. It is faster than
  9.1888 +      the traditional UNIX mailbox format and permits shared access.
  9.1889 +
  9.1890 +      <p>However, and this is <em>very important</em>, note that using an
  9.1891 +      alternative mailbox format is an advanced facility, and only expert
  9.1892 +      users should undertake it. If you don't understand any of the following
  9.1893 +      notes, you may not be enough of an expert yet, and are probably better
  9.1894 +      off not going this route until you are more comfortable with your
  9.1895 +      understanding.</p>
  9.1896 +
  9.1897 +      <p>Some of the formats, including mbx, are only supported by the
  9.1898 +      software based on the c-client library, and are not recognized by other
  9.1899 +      mailbox programs. The "vi" editor will corrupt any mbx format mailbox
  9.1900 +      that it encounters.</p>
  9.1901 +
  9.1902 +      <p>Another problem is that the certain formats, including mbx, use
  9.1903 +      advanced file access and locking techniques that do <em>not</em> work
  9.1904 +      reliably with NFS. NFS is not a real filesystem. Use IMAP instead of
  9.1905 +      NFS for distributed access.</p>
  9.1906 +
  9.1907 +      <p>Each of the following steps are in escalating order of involvement.
  9.1908 +      The further you go down this list, the more deeply committed you
  9.1909 +      become:</p>
  9.1910 +
  9.1911 +      <ul>
  9.1912 +        <li>The simplest way to create a mbx-format mailbox is to prefix the
  9.1913 +        name with "#driver.mbx/" when creating a mailbox through c-client.
  9.1914 +        For example, if you create "#driver.mbx/foo", the mailbox "foo" will
  9.1915 +        be created in mbx format. Only use "#driver.mbx/" when creating the
  9.1916 +        mailbox. At all other times, just use the name ("foo" in this
  9.1917 +        example); the software will automatically select the driver for mbx
  9.1918 +        whenever that mailbox is accessed without you doing anything
  9.1919 +        else.</li>
  9.1920 +
  9.1921 +        <li>You can use the "mailutil copy" command to copy an existing
  9.1922 +        mailbox to a new mailbox in mbx format. Read the man page provided
  9.1923 +        with the mailutil program for details.</li>
  9.1924 +
  9.1925 +        <li>If you create an mbx-format INBOX, by creating
  9.1926 +        "#driver.mbx/INBOX" (note that "INBOX" must be all uppercase), then
  9.1927 +        subsequent access to INBOX by any c-client based application will use
  9.1928 +        the mbx-format INBOX. Any mail delivered to the traditional format
  9.1929 +        mailbox in the spool directory (e.g. /var/spool/mail/$USER) will
  9.1930 +        automatically be copied into the mbx-format INBOX and the spool
  9.1931 +        directory copy removed.</li>
  9.1932 +
  9.1933 +        <li>You can cause any newly-created mailboxes to be in mbx-format by
  9.1934 +        default by changing the definition of CREATEPROTO=unixproto to be
  9.1935 +        CREATEPROTO=mbxproto in src/osdep/unix/Makefile, then rebuilding the
  9.1936 +        IMAP toolkit (do a "make clean" first). Do not change EMPTYPROTO,
  9.1937 +        since mbx format mailboxes are never a zero-byte file. If you use
  9.1938 +        Pine or the imap-utils, you should probably also rebuild them with
  9.1939 +        the new IMAP toolkit too.</li>
  9.1940 +
  9.1941 +        <li>You can deliver directly to the mbx-format INBOX by use of the
  9.1942 +        tmail or dmail programs. tmail is for direct invocation from sendmail
  9.1943 +        (or whatever MTA program you use); dmail is for calls from procmail.
  9.1944 +        Both of these programs have man pages which must be read carefully
  9.1945 +        before making this change.</li>
  9.1946 +      </ul>
  9.1947 +
  9.1948 +      <p>Most other servers (e.g. Cyrus) require use of a non-standard
  9.1949 +      format. A full-fledged format conversion is not significantly different
  9.1950 +      from what you have to do with other servers. The difference, which
  9.1951 +      makes format conversion procedures somewhat more complicated with this
  9.1952 +      server, is that there is no "all or nothing" requirement with this
  9.1953 +      server. There are many points in between. A format conversion can be
  9.1954 +      anything from a single mailbox or single user, to systemwide.</p>
  9.1955 +
  9.1956 +      <p>This is good in that you can decide how far to go, or do the steps
  9.1957 +      incrementally as you become more comfortable with the result. On the
  9.1958 +      other hand, there's no "One True Way" which can be boiled down to a
  9.1959 +      simple set of pedagogical instructions.</p>
  9.1960 +
  9.1961 +      <p>A number of sites have done full-fledged format conversions, and are
  9.1962 +      reportedly quite happy with the results. Feel free to ask in the
  9.1963 +      comp.mail.imap newsgroup or the imap-uw mailing list for advice or
  9.1964 +      help.</p>
  9.1965 +    </dd>
  9.1966 +  </dl>
  9.1967 +
  9.1968 +  <p><a href="#top">Back to top</a></p>
  9.1969 +  <hr>
  9.1970 +
  9.1971 +  <p><a name="4.6"><strong>4.6 How do I set up shared mailboxes?</strong></a></p>
  9.1972 +
  9.1973 +  <dl>
  9.1974 +    <dd>
  9.1975 +      At the simplest level, a shared mailbox is one which has UNIX file and
  9.1976 +      directory protections which permit multiple users to access it. What
  9.1977 +      this means is that your existing skills and tools to create and manage
  9.1978 +      shared files on your UNIX system apply to shared mailboxes; e.g.
  9.1979 +      <pre>
  9.1980 + chmod 666 mailbox
  9.1981 +</pre>
  9.1982 +
  9.1983 +      <p>You may want to consider the use of a mailbox format which permits
  9.1984 +      multiple simultaneous read/write sessions, such as the mbx format. The
  9.1985 +      traditional UNIX format only allows one read/write session to a
  9.1986 +      mailbox at a time.</p>
  9.1987 +
  9.1988 +      <p>An additional convenience item are three system directories, which
  9.1989 +      can be set up for shared namespaces. These are: #ftp, #shared, and
  9.1990 +      #public, and are defined by creating the associated UNIX users and home
  9.1991 +      directories as described below.</p>
  9.1992 +
  9.1993 +      <p>#ftp/ refers to the anonymous ftp filesystem exported by the ftp
  9.1994 +      server, and is equivalent to the home directory for UNIX user "ftp".
  9.1995 +      For example, #ftp/foo/bar refers to the file /foo/bar in the anonymous
  9.1996 +      FTP filesystem, or ~ftp/foo/bar for normal users. Anonymous FTP files
  9.1997 +      are available to anonymous IMAP logins. By default, newly-created files
  9.1998 +      in #ftp/ are protected 644.</p>
  9.1999 +
  9.2000 +      <p>#public/ refers to an IMAP toolkit convention called "public" files,
  9.2001 +      and is equivalent to the home directory for UNIX user "imappublic". For
  9.2002 +      example, #public/foo/bar refers to the file ~imappublic/foo/bar. Public
  9.2003 +      files are available to anonymous IMAP logins. By default, newly-created
  9.2004 +      files in #public are created with protection 0666.</p>
  9.2005 +
  9.2006 +      <p>#shared/ refers to an IMAP toolkit convention called "shared" files,
  9.2007 +      and is equivalent to the home directory for UNIX user "imapshared". For
  9.2008 +      example, #shared/foo/bar refers to the file ~imapshared/foo/bar. Shared
  9.2009 +      files are <em>not</em> available to anonymous IMAP logins. By default,
  9.2010 +      newly-created files in #shared are created with protection 0660.</p>
  9.2011 +    </dd>
  9.2012 +  </dl>
  9.2013 +
  9.2014 +  <p><a href="#top">Back to top</a></p>
  9.2015 +  <hr>
  9.2016 +
  9.2017 +  <p><a name="4.7"><strong>4.7 How can I make the server syslogs go to someplace
  9.2018 +     other than the mail syslog?</strong></a></p>
  9.2019 +
  9.2020 +  <dl>
  9.2021 +    <dd>
  9.2022 +      The openlog() call that sets the syslog facility is in
  9.2023 +      <strong>src/osdep/unix/env_unix.c</strong> in routine
  9.2024 +      <strong>server_init()</strong>. You need to edit this file to change
  9.2025 +      the syslog facility from LOG_MAIL to the facility you want, then
  9.2026 +      rebuild. You also need to set up your /etc/syslog.conf properly.
  9.2027 +
  9.2028 +      <p>Refer to the man pages for syslog and syslogd for more information
  9.2029 +      on what the available syslog facilities are and how to configure
  9.2030 +      syslogs. If you still don't understand what to do, find a UNIX system
  9.2031 +      expert.</p>
  9.2032 +    </dd>
  9.2033 +  </dl>
  9.2034 +
  9.2035 +  <p><a href="#top">Back to top</a></p>
  9.2036 +  <hr>
  9.2037 +
  9.2038 +  <p><br></p>
  9.2039 +
  9.2040 +  <h2><a name="security">5. Security Questions</a></h2>
  9.2041 +  <hr>
  9.2042 +
  9.2043 +  <p><a name="5.1"><strong>5.1 I see that the IMAP server allows access to
  9.2044 +     arbitary files on the system, including /etc/passwd! How do I disable
  9.2045 +     this?</strong></a></p>
  9.2046 +
  9.2047 +  <dl>
  9.2048 +    <dd>
  9.2049 +      You should not worry about this if your IMAP users are allowed shell
  9.2050 +      access. The IMAP server does not permit any access that the user can
  9.2051 +      not have via the shell.
  9.2052 +
  9.2053 +      <p>If, and only if, you deny your IMAP users shell access, you may want
  9.2054 +      to consider one of three choices. Note that these choices reduce IMAP
  9.2055 +      functionality, and may have undesirable side effects. Each of these
  9.2056 +      choices involves an edit to file
  9.2057 +      <strong>src/osdep/unix/env_unix.c</strong></p>
  9.2058 +
  9.2059 +      <p>The first (and recommended) choice is to set
  9.2060 +      <strong>restrictBox</strong> as described in file CONFIG. This will
  9.2061 +      disable access to the filesystem root, to other users' home directory,
  9.2062 +      and to superior directory.</p>
  9.2063 +
  9.2064 +      <p>The second (and strongly NOT recommended) choice is to set
  9.2065 +      <strong>closedBox</strong> as described in file CONFIG. This puts each
  9.2066 +      IMAP session into a so-called "chroot jail", and thus setting this
  9.2067 +      option is <em>extremely</em> dangerous; it can make your system much
  9.2068 +      less secure and open to root compromise attacks. So do not use this
  9.2069 +      option unless you are <em>absolutely certain</em> that you understand
  9.2070 +      all the issues of a "chroot jail."</p>
  9.2071 +
  9.2072 +      <p>The third choice is to rewrite routine
  9.2073 +      <strong>mailboxfile()</strong> to implement whatever mapping from
  9.2074 +      mailbox name to filesystem name (and restrictions) that you wish. This
  9.2075 +      is the most general choice. As a guide, you can see at the start of
  9.2076 +      routine <strong>mailboxfile()</strong> what the
  9.2077 +      <strong>restrictBox</strong> choice does.</p>
  9.2078 +    </dd>
  9.2079 +  </dl>
  9.2080 +
  9.2081 +  <p><a href="#top">Back to top</a></p>
  9.2082 +  <hr>
  9.2083 +
  9.2084 +  <p><a name="5.2"><strong>5.2 I've heard that IMAP servers are insecure. Is this
  9.2085 +     true?</strong></a></p>
  9.2086 +
  9.2087 +  <dl>
  9.2088 +    <dd>
  9.2089 +      There are no known security problems in this version of the IMAP
  9.2090 +      toolkit, including the IMAP and POP servers. The IMAP and POP servers
  9.2091 +      limit what can be done while not logged in, and as part of the login
  9.2092 +      process discard all privileges except those of the user.
  9.2093 +
  9.2094 +      <p>As with other software packages, there have been buffer overflow
  9.2095 +      vulnerabilities in past versions. All known problems of this nature are
  9.2096 +      fixed in this version.</p>
  9.2097 +
  9.2098 +      <p>There is every reason to believe that the bad guys are engaged in an
  9.2099 +      ongoing effort to find vulnerabilities in the IMAP toolkit. We look for
  9.2100 +      such problems, and when one is found we fix it.</p>
  9.2101 +
  9.2102 +      <p>It's unfortunate that any vulnerabilities existed in past versions,
  9.2103 +      and we're doing my best to keep the IMAP toolkit free of
  9.2104 +      vulnerabilities. No new vulnerabilities have been discovered in quite a
  9.2105 +      while, but efforts will not be relaxed.</p>
  9.2106 +
  9.2107 +      <p>Beware of vendors who claim that their implementations can not have
  9.2108 +      vulnerabilities.</p>
  9.2109 +    </dd>
  9.2110 +  </dl>
  9.2111 +
  9.2112 +  <p><a href="#top">Back to top</a></p>
  9.2113 +  <hr>
  9.2114 +
  9.2115 +  <p><a name="5.3"><strong>5.3 How do I know that I have the most secure version
  9.2116 +     of the server?</strong></a></p>
  9.2117 +
  9.2118 +  <dl>
  9.2119 +    <dd>
  9.2120 +      The best way is to keep your server software up to date. The bad guys
  9.2121 +      are always looking for ways to crack software, and when they find one,
  9.2122 +      let all their friends know.
  9.2123 +
  9.2124 +      <p>Oldtimers used to refer to a concept of <em>software rot</em>: if
  9.2125 +      your software hasn't been updated in a while, it would "rot" -- tend to
  9.2126 +      acquire problems that it didn't have when it was new.</p>
  9.2127 +
  9.2128 +      <p>The latest release version of the IMAP toolkit is always available
  9.2129 +      at <a href=
  9.2130 +      "ftp://ftp.cac.washington.edu/mail/imap.tar.Z">ftp://ftp.cac.washington.edu/mail/imap.tar.Z</a></p>
  9.2131 +    </dd>
  9.2132 +  </dl>
  9.2133 +
  9.2134 +  <p><a href="#top">Back to top</a></p>
  9.2135 +  <hr>
  9.2136 +
  9.2137 +  <p><a name="5.4"><strong>5.4 I see all these strcpy() and sprintf() calls, those
  9.2138 +     are unsafe, aren't they?</strong></a></p>
  9.2139 +
  9.2140 +  <dl>
  9.2141 +    <dd>
  9.2142 +      Yes and no.
  9.2143 +
  9.2144 +      <p>It can be unsafe to do these calls if you do not know that the
  9.2145 +      string being written will fit in the buffer. However, they are
  9.2146 +      perfectly safe if you do know that.</p>
  9.2147 +
  9.2148 +      <p>Beware of programmers who advocate doing a brute-force change of all
  9.2149 +      instances of</p>
  9.2150 +      <pre>
  9.2151 + strcpy (s,t);
  9.2152 +</pre>to
  9.2153 +      <pre>
  9.2154 + strncpy (s,t,n)[n] = '\0';
  9.2155 +</pre>and similar measures in the name of "fixing all possible buffer
  9.2156 +overflows."
  9.2157 +
  9.2158 +      <p>There are examples in which a security bug was introduced because of
  9.2159 +      this type of "fix", due to the programmer using the wrong value for n.
  9.2160 +      In one case, the programmer thought that n was larger than it actually
  9.2161 +      was, causing a NUL to be written out of the buffer; in another, n was
  9.2162 +      too small, and a security credential was truncated.</p>
  9.2163 +
  9.2164 +      <p>What is particularly ironic was that in both cases, the original
  9.2165 +      strcpy() was safe, because the size of the source string was known to
  9.2166 +      be safe.</p>
  9.2167 +
  9.2168 +      <p>With all this in mind, the software has been inspected, and it is
  9.2169 +      believed that all places where buffer overflows can happen have been
  9.2170 +      fixed. The strcpy()s that are still are in the code occur after a size
  9.2171 +      check was done in some other way.</p>
  9.2172 +
  9.2173 +      <p>Note that the common C idiom of</p>
  9.2174 +      <pre>
  9.2175 + *s++ = c;
  9.2176 +</pre>is just as vulnerable to buffer overflows. You can't cure buffer
  9.2177 +overflows by outlawing certain functions, nor is it desirable to do so;
  9.2178 +sometimes operations like strcpy() translate into fast machine instructions
  9.2179 +for better performance.
  9.2180 +
  9.2181 +      <p>Nothing replaces careful study of code. That's how the bad guys find
  9.2182 +      bugs. Security is not accomplished by means of brute-force
  9.2183 +      shortcuts.</p>
  9.2184 +    </dd>
  9.2185 +  </dl>
  9.2186 +
  9.2187 +  <p><a href="#top">Back to top</a></p>
  9.2188 +  <hr>
  9.2189 +
  9.2190 +  <p><a name="5.5"><strong>5.5 Those /tmp lock files are protected 666, is that
  9.2191 +     really right?</strong></a></p>
  9.2192 +
  9.2193 +  <dl>
  9.2194 +    <dd>
  9.2195 +      Yes. Shared mailboxes won't work otherwise. Also, you get into
  9.2196 +      accidental denial of service problems with old lock files left lying
  9.2197 +      around; this happens fairly frequently.
  9.2198 +
  9.2199 +      <p>The deliberate mischief that can be caused by fiddling with the lock
  9.2200 +      files is small-scale; harassment level at most. There are many -- and
  9.2201 +      much more effective -- other ways of harassing another user on UNIX.
  9.2202 +      It's usually not difficult to determine the culprit.</p>
  9.2203 +
  9.2204 +      <p>Before worrying about deliberate mischief, worry first about things
  9.2205 +      happening by accident!</p>
  9.2206 +    </dd>
  9.2207 +  </dl>
  9.2208 +
  9.2209 +  <p><a href="#top">Back to top</a></p>
  9.2210 +  <hr>
  9.2211 +
  9.2212 +  <p><br></p>
  9.2213 +
  9.2214 +  <h2><a name="strange">6. <em>Why Did You Do This Strange Thing?</em>
  9.2215 +     Questions</a></h2>
  9.2216 +  <hr>
  9.2217 +
  9.2218 +  <p><a name="6.1"><strong>6.1 Why don't you use GNU autoconfig / automake /
  9.2219 +     autoblurdybloop?</strong></a></p>
  9.2220 +
  9.2221 +  <dl>
  9.2222 +    <dd>
  9.2223 +      Autoconfig et al are not available on all the platforms where the IMAP
  9.2224 +      toolkit is supported; and do not work correctly on some of the
  9.2225 +      platforms where they do exist. Furthermore, these programs add another
  9.2226 +      layer of complexity to an already complex process.
  9.2227 +
  9.2228 +      <p>Coaxing software that uses autoconfig to build properly on platforms
  9.2229 +      which were not specifically considered by that software wastes an
  9.2230 +      inordinate amount of time. When (not if) autoconfig fails to do the
  9.2231 +      right thing, the result is an inpenetrable morass to untangle in order
  9.2232 +      to find the problem and fix it.</p>
  9.2233 +
  9.2234 +      <p>The concept behind autoconfig is good, but the execution is flawed.
  9.2235 +      It rarely does the right thing on a platform that wasn't specifically
  9.2236 +      considered. Human life is too short to debug autoconfig problems,
  9.2237 +      especially since the current mechanism is so much easier.</p>
  9.2238 +    </dd>
  9.2239 +  </dl>
  9.2240 +
  9.2241 +  <p><a href="#top">Back to top</a></p>
  9.2242 +  <hr>
  9.2243 +
  9.2244 +  <p><a name="6.2"><strong>6.2 Why do you insist upon a build with -g? Doesn't it
  9.2245 +     waste disk and memory space?</strong></a></p>
  9.2246 +
  9.2247 +  <dl>
  9.2248 +    <dd>
  9.2249 +      From time to time a submitted port has snuck in without -g. This has
  9.2250 +      <em>always</em> ended up causing problems. There are only two valid
  9.2251 +      excuses for not using -g in a port:
  9.2252 +
  9.2253 +      <ul>
  9.2254 +        <li>The compiler does not support -g</li>
  9.2255 +
  9.2256 +        <li>An alternate form of -g is needed with optimization, e.g.
  9.2257 +        -g3.</li>
  9.2258 +      </ul>
  9.2259 +
  9.2260 +      <p>There will be no new ports added without -g (or a suitable
  9.2261 +      alternative) being set.</p>
  9.2262 +
  9.2263 +      <p>-g has not been arbitrarily added to the ports which do not
  9.2264 +      currently have it because we don't know if doing so would break the
  9.2265 +      build. However, any support issues with one of those port <em>will</em>
  9.2266 +      lead to the correct -g setting being determined and permanently
  9.2267 +      added.</p>
  9.2268 +
  9.2269 +      <p>Processors are fast enough (and disk space is cheap enough) that -g
  9.2270 +      should be automatic in all compilers with no way of turning it off, and
  9.2271 +      /bin/strip should be a symlink to /bin/true. Human life is too short to
  9.2272 +      deal with binaries built without -g. Such binaries should be a bad
  9.2273 +      memory of the days of KIPS processors and disks that costs several
  9.2274 +      dollars per kilobyte.</p>
  9.2275 +    </dd>
  9.2276 +  </dl>
  9.2277 +
  9.2278 +  <p><a href="#top">Back to top</a></p>
  9.2279 +  <hr>
  9.2280 +
  9.2281 +  <p><a name="6.3"><strong>6.3 Why don't you make c-client a shared
  9.2282 +     library?</strong></a></p>
  9.2283 +
  9.2284 +  <dl>
  9.2285 +    <dd>
  9.2286 +      All too often, shared libraries create far more problems than they
  9.2287 +      solve.
  9.2288 +
  9.2289 +      <p>Remember that you only gain the benefit of a shared library when
  9.2290 +      there are multiple applications which use that shared library. Even
  9.2291 +      without shared libraries, on most modern operating systems (and many
  9.2292 +      ancient ones too!) applications will share their text segments between
  9.2293 +      across multiple processes running the same application. This means that
  9.2294 +      if your system only runs one application (e.g. imapd) that uses the
  9.2295 +      c-client library, then you gain no benefit from making c-client a
  9.2296 +      shared library even if it has 100 imapd processes. You will, however
  9.2297 +      suffer added complexity.</p>
  9.2298 +
  9.2299 +      <p>If you have a server system that just runs imapd and ipop3d, then
  9.2300 +      making c-client a shared library will save just one copy of c-client no
  9.2301 +      matter how many IMAP/POP3 processes are running.</p>
  9.2302 +
  9.2303 +      <p>The problem with shared libraries is that you have to keep around a
  9.2304 +      copy of the library every time something changes in the library that
  9.2305 +      would affect the interface the library presents to the application. So,
  9.2306 +      you end up having many copies of the same shared library.</p>
  9.2307 +
  9.2308 +      <p>If you don't keep multiple copies of the shared library, then one of
  9.2309 +      two things happens. If there was proper versioning, then you'll get a
  9.2310 +      message such as "cannot open shared object file" or "minor versions
  9.2311 +      don't match" and the application won't run. Otherwise, the application
  9.2312 +      will run, but will fail in mysterious ways.</p>
  9.2313 +
  9.2314 +      <p>Several sites and third-party distributors have modified the
  9.2315 +      c-client makefile in order to make c-client be a shared library.
  9.2316 +      <em>When</em> (not <em>if</em>) a c-client based application fails in
  9.2317 +      mysterious ways because of a library compatibility problem, the result
  9.2318 +      is a bug report. A lot of time and effort ends up getting wasted
  9.2319 +      investigating such bug reports.</p>
  9.2320 +
  9.2321 +      <p>Memory is so cheap these days that it's not worth it. Human life is
  9.2322 +      too short to deal with shared library compatibility problems.</p>
  9.2323 +    </dd>
  9.2324 +  </dl>
  9.2325 +
  9.2326 +  <p><a href="#top">Back to top</a></p>
  9.2327 +  <hr>
  9.2328 +
  9.2329 +  <p><a name="6.4"><strong>6.4 Why don't you use iconv() for internationalization
  9.2330 +     support?</strong></a></p>
  9.2331 +
  9.2332 +  <dl>
  9.2333 +    <dd>iconv() is not ubiquitous enough.</dd>
  9.2334 +  </dl>
  9.2335 +
  9.2336 +  <p><a href="#top">Back to top</a></p>
  9.2337 +  <hr>
  9.2338 +
  9.2339 +  <p><a name="6.5"><strong>6.5 Why is the IMAP server connected to the home
  9.2340 +     directory by default?</strong></a></p>
  9.2341 +
  9.2342 +  <dl>
  9.2343 +    <dd>
  9.2344 +      The IMAP server has no way of knowing what you might call "mail" as
  9.2345 +      opposed to "some other file"; in fact, you can use IMAP to access any
  9.2346 +      file.
  9.2347 +
  9.2348 +      <p>The IMAP server also doesn't know whether your preferred
  9.2349 +      subdirectory for mailbox files is "mail/", ".mail/", "Mail/",
  9.2350 +      "Mailboxes/", or any of a zillion other possibilities. If one such name
  9.2351 +      were chosen, it would undoubtably anger the partisans of all the other
  9.2352 +      names.</p>
  9.2353 +
  9.2354 +      <p>It is possible to modify the software so that the default connected
  9.2355 +      directory is someplace else. Please read the file CONFIG for discussion
  9.2356 +      of this and other issues.</p>
  9.2357 +    </dd>
  9.2358 +  </dl>
  9.2359 +
  9.2360 +  <p><a href="#top">Back to top</a></p>
  9.2361 +  <hr>
  9.2362 +
  9.2363 +  <p><a name="6.6"><strong>6.6 I have a Windows system. Why isn't the server plug
  9.2364 +     and play for me?</strong></a></p>
  9.2365 +
  9.2366 +  <dl>
  9.2367 +    <dd>
  9.2368 +      There is no standard for how mail is stored on Windows; nor a single
  9.2369 +      standard SMTP server. The closest to either would be the SMTP server in
  9.2370 +      Microsoft's IIS.
  9.2371 +
  9.2372 +      <p>So there's no default by which to make assumptions. As the software
  9.2373 +      is set up, it assumes that the each user has an Windows login account
  9.2374 +      and private home directory, and that mail is stored on that home
  9.2375 +      directory as files in one of the popular UNIX formats. It also assumes
  9.2376 +      that there is some tool equivalent to inetd on UNIX that does the
  9.2377 +      TCP/IP listening and server startup.</p>
  9.2378 +
  9.2379 +      <p>Basically, unless you're an email software hacker, you probably want
  9.2380 +      to look elsewhere if you want IMAP/POP servers for Windows.</p>
  9.2381 +    </dd>
  9.2382 +  </dl>
  9.2383 +
  9.2384 +  <p><a href="#top">Back to top</a></p>
  9.2385 +  <hr>
  9.2386 +
  9.2387 +  <p><a name="6.7"><strong>6.7 I looked at the UNIX SSL code and saw that you have
  9.2388 +     the SSL data payload size set to 8192 bytes. SSL allows 16K; why aren't
  9.2389 +     you using the full size?</strong></a></p>
  9.2390 +
  9.2391 +  <dl>
  9.2392 +    <dd>
  9.2393 +      This is to avoid an interoperability problem with:
  9.2394 +
  9.2395 +      <ul>
  9.2396 +        <li>PC IMAP clients that use Microsoft's SChannel.DLL (SSPI) for SSL
  9.2397 +        support</li>
  9.2398 +
  9.2399 +        <li>Microsoft Exchange server (which also uses SChannel).</li>
  9.2400 +      </ul>
  9.2401 +
  9.2402 +      <p>SChannel has a bug that makes it think that the maximum SSL data
  9.2403 +      payload size is 16379 bytes -- 5 bytes too small. Thus, c-client has to
  9.2404 +      make sure that it never transmits full sized SSL packets.</p>
  9.2405 +
  9.2406 +      <p>The reason for using 8K (as opposed to, say, 16379 bytes, or 15K,
  9.2407 +      or...) is that it corresponds with the TCP buffer size that the
  9.2408 +      software uses elsewhere for input; there's a slight performance benefit
  9.2409 +      to having the two sizes correspond or at least be a multiple of each
  9.2410 +      other. Also, it keeps the size as a power of two, which might be
  9.2411 +      significant on some platforms.</p>
  9.2412 +
  9.2413 +      <p>There wasn't a significant difference that we could measure between
  9.2414 +      8K and 15K.</p>
  9.2415 +
  9.2416 +      <p>Microsoft has developed a hotfix for this bug. Look up MSKB article
  9.2417 +      number 300562. Contrary to the article text which implies that this is
  9.2418 +      a Pine issue, this bug also affects Microsoft Exchange server with
  9.2419 +      <em>any</em> client that transmits full-sized SSL payloads.</p>
  9.2420 +    </dd>
  9.2421 +  </dl>
  9.2422 +
  9.2423 +  <p><a href="#top">Back to top</a></p>
  9.2424 +  <hr>
  9.2425 +
  9.2426 +  <p><a name="6.8"><strong>6.8 Why is an mh format INBOX called #mhinbox instead
  9.2427 +     of just INBOX?</strong></a></p>
  9.2428 +
  9.2429 +  <dl>
  9.2430 +    <dd>
  9.2431 +      It's a long story. In brief, the mh format driver is less functional
  9.2432 +      than any of the other drivers. It turned out that there were some users
  9.2433 +      (including high-level administrators) who tried mh years ago and no
  9.2434 +      longer use it, but still had an mh profile left behind.
  9.2435 +
  9.2436 +      <p>When the mh driver used INBOX, it would see the mh profile, and
  9.2437 +      proceed to move the user's INBOX into the mh format INBOX. This caused
  9.2438 +      considerable confusion as some things stopped working.</p>
  9.2439 +    </dd>
  9.2440 +  </dl>
  9.2441 +
  9.2442 +  <p><a href="#top">Back to top</a></p>
  9.2443 +  <hr>
  9.2444 +
  9.2445 +  <p><a name="6.9"><strong>6.9 Why don't you support the maildir
  9.2446 +     format?</strong></a></p>
  9.2447 +
  9.2448 +  <dl>
  9.2449 +    <dd>
  9.2450 +      It is technically difficult to support maildir in IMAP while
  9.2451 +      maintaining acceptable performance, robustness, following the
  9.2452 +      requirements of the IMAP protocol specification, and following the
  9.2453 +      requirements of maildir.
  9.2454 +
  9.2455 +      <p>No one has succeeded in accomplishing all four together. The various
  9.2456 +      maildir drivers offered as patches all have these problems. The problem
  9.2457 +      is exacerbated because this implementation supports multiple formats;
  9.2458 +      consequently this implementation can't make any performance shortcuts
  9.2459 +      by assuming that all the world is maildir.</p>
  9.2460 +
  9.2461 +      <p>We can't do a better job than the maildir fan community has done
  9.2462 +      with their maildir drivers. Similarly, if the maildir fan community
  9.2463 +      provides the maildir driver, they take on the responsibility for
  9.2464 +      answering maildir-specific support questions. This is as it should be,
  9.2465 +      and that is why maildir support is left to the maildir fan
  9.2466 +      community.</p>
  9.2467 +    </dd>
  9.2468 +  </dl>
  9.2469 +
  9.2470 +  <p><a href="#top">Back to top</a></p>
  9.2471 +  <hr>
  9.2472 +
  9.2473 +  <p><a name="6.10"><strong>6.10 Why don't you support the Cyrus
  9.2474 +     format?</strong></a></p>
  9.2475 +
  9.2476 +  <dl>
  9.2477 +    <dd>
  9.2478 +      There's no point to doing so. An implementation which supports multiple
  9.2479 +      formats will never do as well as one which is optimized to support one
  9.2480 +      single format.
  9.2481 +
  9.2482 +      <p>If you want to use Cyrus mailbox format, you should use the Cyrus
  9.2483 +      server, which is the native implementation of that format and is
  9.2484 +      specifically optimized for that format. That's also why Cyrus doesn't
  9.2485 +      implement any other format.</p>
  9.2486 +    </dd>
  9.2487 +  </dl>
  9.2488 +
  9.2489 +  <p><a href="#top">Back to top</a></p>
  9.2490 +  <hr>
  9.2491 +
  9.2492 +  <p><a name="6.11"><strong>6.11 Why is it creating extra forks on my SVR4
  9.2493 +     system?</strong></a></p>
  9.2494 +
  9.2495 +  <dl>
  9.2496 +    <dd>
  9.2497 +      This is because your system only has fcntl() style locking and not
  9.2498 +      flock() style locking. fcntl() locking has a design flaw that causes a
  9.2499 +      close() to release any locks made by that process on the file opened on
  9.2500 +      that file descriptor, even if the lock was made on a different file
  9.2501 +      descriptor.
  9.2502 +
  9.2503 +      <p>This design flaw causes unexpected loss of lock, and consequent
  9.2504 +      mailbox corruption. The workaround is to do certain "dangerous
  9.2505 +      operations" in another fork, thus avoiding doing a close() in the
  9.2506 +      vulnerable fork.</p>
  9.2507 +
  9.2508 +      <p>The best way to solve this problem is to upgrade your SVR4 (Solaris,
  9.2509 +      AIX, HP-UX, SGI) or OSF/1 system to a more advanced operating system,
  9.2510 +      such as Linux or BSD. These more advanced operating systems have
  9.2511 +      fcntl() locking for compatibility with SVR4, but also have flock()
  9.2512 +      locking.</p>
  9.2513 +
  9.2514 +      <p>Beware of certain SVR4 systems, such as AIX, which have an "flock()"
  9.2515 +      function in their C library that is just a jacket that does an fcntl()
  9.2516 +      lock. This is not a true flock(), and has the same design flaw as
  9.2517 +      fcntl().</p>
  9.2518 +    </dd>
  9.2519 +  </dl>
  9.2520 +
  9.2521 +  <p><a href="#top">Back to top</a></p>
  9.2522 +  <hr>
  9.2523 +
  9.2524 +  <p><a name="6.12"><strong>6.12 Why are you so fussy about the date/time format in
  9.2525 +     the internal <code>"From&nbsp;"</code> line in traditional UNIX mailbox
  9.2526 +     files? My other mail program just considers every line that starts with
  9.2527 +     <code>"From&nbsp;"</code> to be the start of the message.</strong></a></p>
  9.2528 +
  9.2529 +  <dl>
  9.2530 +    <dd>
  9.2531 +      You just answered your own question. If any line that starts with
  9.2532 +      <code>"From&nbsp;"</code> is treated as the start of a message, then
  9.2533 +      every message text line which starts with <code>"From&nbsp;"</code> has
  9.2534 +      to be quoted (typically by prefixing a "&gt;" character). People
  9.2535 +      complain about this -- "why did a &gt; get stuck in my message?"
  9.2536 +
  9.2537 +      <p>So, good mail reading software only considers a line to be a
  9.2538 +      <code>"From&nbsp;"</code> line if it follows the actual specification
  9.2539 +      for a "From&nbsp;" line. This means, among other things, that the day of
  9.2540 +      week is fixed-format: <code>"May&nbsp;14"</code>, but
  9.2541 +      <code>"May&nbsp;&nbsp;7"</code> (note the extra space) as opposed to
  9.2542 +      <code>"May&nbsp;7"</code>. ctime() format for the date is the most
  9.2543 +      common, although POSIX also allows a numeric timezone after the
  9.2544 +      year. For compatibility with ancient software, the seconds are optional,
  9.2545 +      the timezone may appear before the year, the old 3-letter timezones are
  9.2546 +      also permitted, and "remote from xxx" may appear after the whole
  9.2547 +      thing.</p>
  9.2548 +
  9.2549 +      <p>Unfortunately, some software written by novices use other formats.
  9.2550 +      The most common error is to have a variable-width day of month, perhaps
  9.2551 +      in the erroneous belief that RFC 2822 (or RFC 822) defines the format of
  9.2552 +      the date/time in the <code>"From&nbsp;"</code> line (it doesn't; no RFC
  9.2553 +      describes internal formats). I've seen a few other goofs, such as a
  9.2554 +      single-digit second, but these are less common.</p>
  9.2555 +
  9.2556 +      <p>If you are writing your own software that writes mailbox files, and
  9.2557 +      you really aren't all that savvy with all the ins and outs and ancient
  9.2558 +      history, you should seriously consider using the c-client library (e.g.
  9.2559 +      routine mail_append()) instead of doing the file writes yourself. If
  9.2560 +      you must do it yourself, use ctime(), as in:</p>
  9.2561 +      <pre>
  9.2562 + fprintf (mbx,"From %s@%h %s",user,host,ctime (time (0)));
  9.2563 +</pre>rather than try to figure out a good format yourself. ctime() is the
  9.2564 +most traditional format and nobody will flame you for using it.
  9.2565 +    </dd>
  9.2566 +  </dl>
  9.2567 +
  9.2568 +  <p><a href="#top">Back to top</a></p>
  9.2569 +  <hr>
  9.2570 +
  9.2571 +  <p><a name="6.13"><strong>6.13 Why is traditional UNIX format the default
  9.2572 +     format?</strong></a></p>
  9.2573 +
  9.2574 +  <dl>
  9.2575 +    <dd>Compatibility with the past 30 or so years of UNIX history. This
  9.2576 +    server is the only one that completely interoperates with legacy UNIX
  9.2577 +    mail tools.</dd>
  9.2578 +  </dl>
  9.2579 +
  9.2580 +  <p><a href="#top">Back to top</a></p>
  9.2581 +  <hr>
  9.2582 +
  9.2583 +  <p><a name="6.14"><strong>6.14 Why do you write this "DON'T DELETE THIS MESSAGE
  9.2584 +     -- FOLDER INTERNAL DATA" message at the start of traditional UNIX and
  9.2585 +     MMDF format mailboxes?</strong></a></p>
  9.2586 +
  9.2587 +  <dl>
  9.2588 +    <dd>
  9.2589 +      This pseudo-message serves two purposes.
  9.2590 +
  9.2591 +      <p>First, it establishes the mailbox format even when the mailbox has
  9.2592 +      no messages. Otherwise, a mailbox with no messages is a zero-byte file,
  9.2593 +      which could be one of several formats.</p>
  9.2594 +
  9.2595 +      <p>Second, it holds mailbox metadata used by IMAP: the UID validity,
  9.2596 +      the last assigned UID, and mailbox keywords. Without this metadata,
  9.2597 +      which must be preserved even when the mailbox has no messages, the
  9.2598 +      traditional UNIX format wouldn't be able to support the full
  9.2599 +      capabilities of IMAP.</p>
  9.2600 +    </dd>
  9.2601 +  </dl>
  9.2602 +
  9.2603 +  <p><a href="#top">Back to top</a></p>
  9.2604 +  <hr>
  9.2605 +
  9.2606 +  <p><a name="6.15"><strong>6.15 Why don't you stash the mailbox metadata in the
  9.2607 +     first real message of the mailbox instead of writing this fake FOLDER
  9.2608 +     INTERNAL DATA message?</strong></a></p>
  9.2609 +
  9.2610 +  <dl>
  9.2611 +    <dd>
  9.2612 +      In fact, that is what is done if the mailbox is non-empty and does not
  9.2613 +      already have a FOLDER INTERNAL DATA message.
  9.2614 +
  9.2615 +      <p>One problem with doing that is that if some external program removes
  9.2616 +      the first message, the metadata is lost and must be recreated, thus
  9.2617 +      losing any prior UID or keyword list status that IMAP clients may
  9.2618 +      depend upon.</p>
  9.2619 +
  9.2620 +      <p>Another problem is that this doesn't help if the last message is
  9.2621 +      deleted. This will result in an empty mailbox, and the necessity to
  9.2622 +      create a FOLDER INTERNAL DATA message.</p>
  9.2623 +    </dd>
  9.2624 +  </dl>
  9.2625 +
  9.2626 +  <p><a href="#top">Back to top</a></p>
  9.2627 +  <hr>
  9.2628 +
  9.2629 +  <p><a name="6.16"><strong>6.16 Why aren't "dual-use" mailboxes the
  9.2630 +     default?</strong></a></p>
  9.2631 +
  9.2632 +  <dl>
  9.2633 +    <dd>Compatibility with the past 30 or so years of UNIX history, not to
  9.2634 +    mention compatibility with user expectations when using shell tools.</dd>
  9.2635 +  </dl>
  9.2636 +
  9.2637 +  <p><a href="#top">Back to top</a></p>
  9.2638 +  <hr>
  9.2639 +
  9.2640 +  <p><a name="6.17"><strong>6.17 Why do you use ucbcc to build on
  9.2641 +     Solaris?</strong></a></p>
  9.2642 +
  9.2643 +  <dl>
  9.2644 +    <dd>
  9.2645 +      It is a long, long story about why cc is set to ucbcc. You need to
  9.2646 +      invoke the C compiler so that it links with the SVR4 libraries and not
  9.2647 +      the BSD libraries, otherwise readdir() will return the wrong
  9.2648 +      information.
  9.2649 +
  9.2650 +      <p>Of all the names in the most common path, ucbcc is the only name to
  9.2651 +      be found (on /usr/ccs/bin) that points to a suitable compiler. cc is
  9.2652 +      likely to be /usr/ucb/cc which is absolutely not the compiler that you
  9.2653 +      want. The real SVR4 cc is probably something like /opt/SUNWspro/bin/cc
  9.2654 +      which is rarely in anyone's path by default.</p>
  9.2655 +
  9.2656 +      <p>ucbcc is probably a link to acc, e.g. /opt/SUNWspro/SC4.0/bin/acc,
  9.2657 +      and is the UCB C compiler using the SVR4 libraries.</p>
  9.2658 +
  9.2659 +      <p>If ucbcc isn't on your system, then punt on the SUN C compiler and
  9.2660 +      use gcc instead (the gso port instead of the sol port).</p>
  9.2661 +
  9.2662 +      <p>If, in spite of all the above warnings, you choose to change "ucbcc"
  9.2663 +      to "cc", you will probably find that the -O2 needs to be changed to -O.
  9.2664 +      If you don't get any error messages with -O2, that's a pretty good
  9.2665 +      indicator that you goofed and are running the compiler that will link
  9.2666 +      with the BSD libraries.</p>
  9.2667 +
  9.2668 +      <p>To recap:</p>
  9.2669 +
  9.2670 +      <ul>
  9.2671 +        <li>The sol port is designed to be built using the UCB compiler using
  9.2672 +        the SVR4 libraries. This compiler is "ucbcc", which is lunk to acc.
  9.2673 +        You use -O2 as one of the CFLAGS.</li>
  9.2674 +
  9.2675 +        <li>If you build the sol port with the UCB compiler using the BSD
  9.2676 +        libraries, you will get no error messages but you will get bad
  9.2677 +        binaries (the most obvious symptom is dropping the first two
  9.2678 +        characters return filenames from the imapd LIST command. This
  9.2679 +        compiler also uses -O2, and is very often what the user gets from
  9.2680 +        "cc". <strong>BEWARE</strong></li>
  9.2681 +
  9.2682 +        <li>If you build the sol port with the real SVR4 compiler, which is
  9.2683 +        often hidden away or unavailable on many systems, then you will get
  9.2684 +        errors from -O2 and you need to change that to -O. But you will get a
  9.2685 +        good binary. However, you should try it with -O2 first, to make sure
  9.2686 +        that you got this compiler and not the UCB compiler using BSD
  9.2687 +        libraries.</li>
  9.2688 +      </ul>
  9.2689 +    </dd>
  9.2690 +  </dl>
  9.2691 +
  9.2692 +  <p><a href="#top">Back to top</a></p>
  9.2693 +  <hr>
  9.2694 +
  9.2695 +  <p><a name="6.18"><strong>6.18 Why should I care about some old system with BSD
  9.2696 +     libraries? cc is the right thing on my Solaris system!</strong></a></p>
  9.2697 +
  9.2698 +  <dl>
  9.2699 +    <dd>
  9.2700 +      Because there still are sites that use such systems. On those systems,
  9.2701 +      the assumption that "cc" does the right thing will lead to corrupt
  9.2702 +      binaries with no error message or other warning that anything is amiss.
  9.2703 +
  9.2704 +      <p>Too many sites have fallen victim to this problem.</p>
  9.2705 +    </dd>
  9.2706 +  </dl>
  9.2707 +
  9.2708 +  <p><a href="#top">Back to top</a></p>
  9.2709 +  <hr>
  9.2710 +
  9.2711 +  <p><a name="6.19"><strong>6.19 Why do you insist upon writing .lock files in the
  9.2712 +     spool directory?</strong></a></p>
  9.2713 +
  9.2714 +  <dl>
  9.2715 +    <dd>Compatibility with the past 30 years of UNIX software which deals
  9.2716 +    with the spool directory, especially software which delivers mail.
  9.2717 +    Otherwise, it is possible to lose mail.</dd>
  9.2718 +  </dl>
  9.2719 +
  9.2720 +  <p><a href="#top">Back to top</a></p>
  9.2721 +  <hr>
  9.2722 +
  9.2723 +  <p><a name="6.20"><strong>6.20 Why should I care about compatibility with the
  9.2724 +     past?</strong></a></p>
  9.2725 +
  9.2726 +  <dl>
  9.2727 +    <dd>This is one of those questions in which the answer never convinces
  9.2728 +    those who ask it. Somehow, everybody who ever asks this question ends up
  9.2729 +    answering it for themselves as they get older, with the very answer that
  9.2730 +    they rejected years earlier.</dd>
  9.2731 +  </dl>
  9.2732 +
  9.2733 +  <p><a href="#top">Back to top</a></p>
  9.2734 +  <hr>
  9.2735 +
  9.2736 +  <p><br></p>
  9.2737 +
  9.2738 +  <h2><a name="problems">7. Problems and Annoyances</a></h2>
  9.2739 +  <hr>
  9.2740 +
  9.2741 +  <p><a name="7.1"><strong>7.1 Help! My INBOX is empty! What happened to my
  9.2742 +     messages?</strong></a></p>
  9.2743 +
  9.2744 +  <dl>
  9.2745 +    <dd>
  9.2746 +      If you are seeing "0 messages" when you open INBOX and you know you
  9.2747 +      have messages there (and perhaps have looked at your mail spool file
  9.2748 +      and see that messages are there), then probably there is something
  9.2749 +      wrong with the very first line of your mail spool file. Make sure that
  9.2750 +      the first five bytes of the file are "From ", followed by an email
  9.2751 +      address and a date/time in ctime() format, e.g.:
  9.2752 +      <pre>
  9.2753 + From fred@foo.bar Mon May  7 20:54:30 2001
  9.2754 +</pre>
  9.2755 +    </dd>
  9.2756 +  </dl>
  9.2757 +
  9.2758 +  <p><a href="#top">Back to top</a></p>
  9.2759 +  <hr>
  9.2760 +
  9.2761 +  <p><a name="7.2"><strong>7.2 Help! All my messages in a non-INBOX mailbox have
  9.2762 +     been concatenated into one message which claims to be from me and has a
  9.2763 +     subject of the file name of the mailbox! What's going
  9.2764 +     on?</strong></a></p>
  9.2765 +
  9.2766 +  <dl>
  9.2767 +    <dd>
  9.2768 +      Something wrong with the very first line of the mailbox. Make sure that
  9.2769 +      the first five bytes of the file are "From ", followed by an email
  9.2770 +      address and a date/time in ctime() format, e.g.:
  9.2771 +      <pre>
  9.2772 + From fred@foo.bar Mon May  7 20:54:30 2001
  9.2773 +</pre>
  9.2774 +    </dd>
  9.2775 +  </dl>
  9.2776 +
  9.2777 +  <p><a href="#top">Back to top</a></p>
  9.2778 +  <hr>
  9.2779 +
  9.2780 +  <p><a name="7.3"><strong>7.3 Why do I get the message:</strong> <tt>CREATE
  9.2781 +     failed: Can't create mailbox node xxxxxxxxx: File exists</tt>
  9.2782 +     <strong>and how do I fix it?</strong></a></p>
  9.2783 +
  9.2784 +  <dl>
  9.2785 +    <dd>See the answer to the <a href="#1.8">Are hierarchical mailboxes
  9.2786 +    supported?</a> question.</dd>
  9.2787 +  </dl>
  9.2788 +
  9.2789 +  <p><a href="#top">Back to top</a></p>
  9.2790 +  <hr>
  9.2791 +
  9.2792 +  <p><a name="7.4"><strong>7.4 Why can't I log in to the server? The user name and
  9.2793 +     password are right!</strong></a></p>
  9.2794 +
  9.2795 +  <dl>
  9.2796 +    <dd>
  9.2797 +      There are a myriad number of possible answers to this question. The
  9.2798 +      only way to say for sure what is wrong is run the server under a
  9.2799 +      debugger such as gdb while root (yes, you must be root) with a
  9.2800 +      breakpoint at routines checkpw() and loginpw(), then single-step until
  9.2801 +      you see which test rejected you. The server isn't going to give any
  9.2802 +      error messages other than "login failed" in the name of not giving out
  9.2803 +      any unnecessary information to unauthorized individuals.
  9.2804 +
  9.2805 +      <p>Here are some of the more common reasons why login may fail:</p>
  9.2806 +
  9.2807 +      <ul>
  9.2808 +        <li>You didn't really give the correct user name and/or
  9.2809 +        password.</li>
  9.2810 +
  9.2811 +        <li>Your client doesn't send the LOGIN command correctly; for
  9.2812 +        example, IMAP2 clients won't send a password containing a "*"
  9.2813 +        correctly to an IMAP4 server.</li>
  9.2814 +
  9.2815 +        <li>If you have set up a CRAM-MD5 database, remember that the
  9.2816 +        password used is the one in the CRAM-MD5 database, and furthermore
  9.2817 +        that there must also be an entry in /etc/passwd (but the /etc/passwd
  9.2818 +        password is not used).</li>
  9.2819 +
  9.2820 +        <li>If you are using PAM, have you created a service file for the
  9.2821 +        server in /etc/pam.d?</li>
  9.2822 +
  9.2823 +        <li>If you are using shadow passwords, have you used an appropriate
  9.2824 +        port when building? In particular, note that "lnx" is for Linux
  9.2825 +        systems without shadow passwords; you probably want "slx" or "lnp"
  9.2826 +        instead.</li>
  9.2827 +
  9.2828 +        <li>If your system has account or password expirations, check to see
  9.2829 +        that the expiration date hasn't passed.</li>
  9.2830 +
  9.2831 +        <li>You can't log in as root or any other UID 0 user. This is for
  9.2832 +        your own safety, not to mention the fact that the servers use UID 0
  9.2833 +        as meaning "not logged in".</li>
  9.2834 +      </ul>
  9.2835 +    </dd>
  9.2836 +  </dl>
  9.2837 +
  9.2838 +  <p><a href="#top">Back to top</a></p>
  9.2839 +  <hr>
  9.2840 +
  9.2841 +  <p><a name="7.5"><strong>7.5 Help! My load average is soaring and I see hundreds
  9.2842 +     of POP and IMAP servers, many logged in as the same
  9.2843 +     user!</strong></a></p>
  9.2844 +
  9.2845 +  <dl>
  9.2846 +    <dd>
  9.2847 +      Certain inferior losing GUI mail reading programs have a "synchronize
  9.2848 +      all mailboxes at startup" (IMAP) or "check for new mail every second"
  9.2849 +      (POP) feature which causes a rapid and unchecked spawning of servers.
  9.2850 +
  9.2851 +      <p>This is not a problem in the server; the client is really asking for
  9.2852 +      all those server sessions. Unfortunately, there isn't much that the POP
  9.2853 +      and IMAP servers can do about it; they don't spawned themselves.</p>
  9.2854 +
  9.2855 +      <p>Some sites have added code to record the number of server sessions
  9.2856 +      spawned per user per hour, and disable login for a user who has
  9.2857 +      exceeded a predetermined rate. This doesn't stop the servers from being
  9.2858 +      spawned; it just means that a server session will commit suicide a bit
  9.2859 +      faster.</p>
  9.2860 +
  9.2861 +      <p>Another possibility is to detect excessive server spawning activity
  9.2862 +      at the level where the server is spawned, which would be inetd or
  9.2863 +      possibly tcpd. The problem here is that this is a hard time to
  9.2864 +      quantify. 50 sessions in a minute from a multi-user timesharing system
  9.2865 +      may be perfectly alright, whereas 10 sessions a minute from a PC may be
  9.2866 +      too much.</p>
  9.2867 +
  9.2868 +      <p>The real solution is to fix the client configuration, by disabling
  9.2869 +      those evil features. Also tell the vendors of those clients how you
  9.2870 +      feel about distributing denial-of-service attack tools in the guise of
  9.2871 +      mail reading programs.</p>
  9.2872 +    </dd>
  9.2873 +  </dl>
  9.2874 +
  9.2875 +  <p><a href="#top">Back to top</a></p>
  9.2876 +  <hr>
  9.2877 +
  9.2878 +  <p><a name="7.6"><strong>7.6 Why does mail disappear even though I set "keep
  9.2879 +     mail on server"?</strong></a><br>
  9.2880 +  <a name="7.7"><strong>7.7 Why do I get the message</strong> <tt>Moved #####
  9.2881 +     bytes of new mail to /home/user/mbox from /var/spool/mail/user</tt>
  9.2882 +     <strong>and why did this happen?</strong></a></p>
  9.2883 +
  9.2884 +  <dl>
  9.2885 +    <dd>
  9.2886 +      This is probably caused by the mbox driver. If the file "mbox" exists
  9.2887 +      on the user's home directory and is in UNIX mailbox format, then when
  9.2888 +      INBOX is opened this file will be selected as INBOX instead of the mail
  9.2889 +      spool file. Messages will be automatically transferred from the mail
  9.2890 +      spool file into the mbox file.
  9.2891 +
  9.2892 +      <p>To disable this behavior, delete "mbox" from the EXTRADRIVERS list
  9.2893 +      in the top-level Makefile and rebuild. Note that if you do this, users
  9.2894 +      won't be able to access the messages that have already been moved to
  9.2895 +      mbox unless they open mbox instead of INBOX.</p>
  9.2896 +    </dd>
  9.2897 +  </dl>
  9.2898 +
  9.2899 +  <p><a href="#top">Back to top</a></p>
  9.2900 +  <hr>
  9.2901 +
  9.2902 +  <p><a name="7.8"><strong>7.8 Why isn't it showing the local host name as a
  9.2903 +     fully-qualified domain name?</strong></a><br>
  9.2904 +  <a name="7.9"><strong>7.9 Why is the local host name in the
  9.2905 +     From/Sender/Message-ID headers of outgoing mail not coming out as a
  9.2906 +     fully-qualified domain name?</strong></a></p>
  9.2907 +
  9.2908 +  <dl>
  9.2909 +    <dd>
  9.2910 +      Your UNIX system is misconfigured. The entry for your system in
  9.2911 +      /etc/hosts must have the fully-qualified domain name first, e.g.
  9.2912 +      <pre>
  9.2913 + 105.69.1.234	myserver.example.com myserver
  9.2914 +</pre>
  9.2915 +
  9.2916 +      <p>A common mistake of novice system administrators is to have the
  9.2917 +      short name first, e.g.</p>
  9.2918 +      <pre>
  9.2919 + 105.69.1.234	myserver myserver.example.com
  9.2920 +
  9.2921 +</pre>
  9.2922 +
  9.2923 +      <p>or to omit the fully qualified domain name entirely, e.g.</p>
  9.2924 +      <pre>
  9.2925 + 105.69.1.234	myserver
  9.2926 +</pre>
  9.2927 +
  9.2928 +      <p>The result of this is that when the IMAP toolkit does a
  9.2929 +      gethostbyname() call to get the fully-qualified domain name, it would
  9.2930 +      get "myserver" instead of "myserver.example.com".</p>
  9.2931 +
  9.2932 +      <p>On some systems, a configuration file (typically named
  9.2933 +      /etc/svc.conf, /etc/netsvc.conf, or /etc/nsswitch.conf) can be used to
  9.2934 +      configure the system to use the domain name system (DNS) instead of
  9.2935 +      /etc/hosts, so it doesn't matter if /etc/hosts is misconfigured.</p>
  9.2936 +
  9.2937 +      <p>Check the man pages for gethostbyname, hosts, svc, and/or netsvc for
  9.2938 +      more information.</p>
  9.2939 +
  9.2940 +      <p>Unfortunately, certain vendors, most notably SUN, have failed to
  9.2941 +      make this clear in their documentation. Most of SUN's documentation
  9.2942 +      assumes a corporate network that is not connected to the Internet.</p>
  9.2943 +
  9.2944 +      <p>net.folklore once (late 1980s) held that the proper procedure was to
  9.2945 +      append the results of getdomainname() to the name returned by
  9.2946 +      gethostname(), and some versions of sendmail configuration files were
  9.2947 +      distributed that did this. This was incorrect; the string returned from
  9.2948 +      getdomainname() is the Yellow Pages (a.k.a NIS) domain name, which is a
  9.2949 +      completely different (albeit unfortunately named) entity from an
  9.2950 +      Internet domain. These were often fortuitously the same string, except
  9.2951 +      when they weren't. Frequently, this would result in host names with
  9.2952 +      spuriously doubled domain names, e.g.</p>
  9.2953 +      <pre>
  9.2954 + myserver.example.com.example.com
  9.2955 +
  9.2956 +</pre>
  9.2957 +
  9.2958 +      <p>This practice has been thoroughly discredited for many years, but
  9.2959 +      folklore dies hard.</p>
  9.2960 +    </dd>
  9.2961 +  </dl>
  9.2962 +
  9.2963 +  <p><a href="#top">Back to top</a></p>
  9.2964 +  <hr>
  9.2965 +
  9.2966 +  <p><a name="7.10"><strong>7.10 What does the message:</strong> <tt>Mailbox
  9.2967 +     vulnerable - directory /var/spool/mail must have 1777 protection</tt>
  9.2968 +     <strong>mean? How can I fix this?</strong></a></p>
  9.2969 +
  9.2970 +  <dl>
  9.2971 +    <dd>
  9.2972 +      In order to update a mailbox in the default UNIX format, it is
  9.2973 +      necessary to create a lock file to prevent the mailer from delivering
  9.2974 +      mail while an update is in progress. Some systems use a directory
  9.2975 +      protection of 775, requiring that all mail handling programs be setgid
  9.2976 +      mail; or of 755, requiring that all mail handling programs be setuid
  9.2977 +      root.
  9.2978 +
  9.2979 +      <p>The IMAP toolkit does not run with any special privileges, and I
  9.2980 +      plan to keep it that way. It is antithetical to the concept of a
  9.2981 +      toolkit if users can't write their own programs to use it. Also, I've
  9.2982 +      had enough bad experiences with security bugs while running privileged;
  9.2983 +      the IMAP and POP servers have to be root when not logged in, in order
  9.2984 +      to be able to log themselves in. I don't want to go any deeper down
  9.2985 +      that slippery slope.</p>
  9.2986 +
  9.2987 +      <p>Directory protection 1777 is secure enough on most well-managed
  9.2988 +      systems. If you can't trust your users with a 1777 mail spool (petty
  9.2989 +      harassment is about the limit of the abuse exposure), then you have
  9.2990 +      much worse problems then that.</p>
  9.2991 +
  9.2992 +      <p>If you absolutely insist upon requiring privileges to create a lock
  9.2993 +      file, external file locking can be done via a setgid mail program named
  9.2994 +      /etc/mlock (this is defined by LOCKPGM in the c-client Makefile). If
  9.2995 +      the toolkit is unable to create a &lt;...mailbox...&gt;.lock file in
  9.2996 +      the directory by itself, it will try to call mlock to do it. I do not
  9.2997 +      recommend doing this for performance reasons.</p>
  9.2998 +
  9.2999 +      <p>A sample mlock program is included as part of imap-2007. We have
  9.3000 +      tried to make this sample program secure, but it has not been
  9.3001 +      thoroughly audited.</p>
  9.3002 +    </dd>
  9.3003 +  </dl>
  9.3004 +
  9.3005 +  <p><a href="#top">Back to top</a></p>
  9.3006 +  <hr>
  9.3007 +
  9.3008 +  <p><a name="7.11"><strong>7.11 What does the message:</strong> <tt>Mailbox is
  9.3009 +     open by another process, access is readonly</tt> <strong>mean? How do I
  9.3010 +     fix this?</strong></a></p>
  9.3011 +
  9.3012 +  <dl>
  9.3013 +    <dd>
  9.3014 +      A problem occurred in applying a lock to a /tmp lock file. Either some
  9.3015 +      other program has the mailbox open and won't relenquish it, or
  9.3016 +      something is wrong with the protection of /tmp or the lock.
  9.3017 +
  9.3018 +      <p>Make sure that the /tmp directory is protected 1777. Some security
  9.3019 +      scripts incorrectly set the protection of the /tmp directory to 775,
  9.3020 +      which disables /tmp for all non-privileged programs.</p>
  9.3021 +    </dd>
  9.3022 +  </dl>
  9.3023 +
  9.3024 +  <p><a href="#top">Back to top</a></p>
  9.3025 +  <hr>
  9.3026 +
  9.3027 +  <p><a name="7.12"><strong>7.12 What does the message:</strong> <tt>Can't get
  9.3028 +     write access to mailbox, access is readonly</tt>
  9.3029 +     <strong>mean?</strong></a></p>
  9.3030 +
  9.3031 +  <dl>
  9.3032 +    <dd>The mailbox file is write-protected against you.</dd>
  9.3033 +  </dl>
  9.3034 +
  9.3035 +  <p><a href="#top">Back to top</a></p>
  9.3036 +  <hr>
  9.3037 +
  9.3038 +  <p><a name="7.13"><strong>7.13 I set my POP3 client to "delete messages from
  9.3039 +     server" but they never get deleted. What is wrong?</strong></a></p>
  9.3040 +
  9.3041 +  <dl>
  9.3042 +    <dd>
  9.3043 +      Make sure that your mailbox is not read-only: that the mailbox is owned
  9.3044 +      by you and write enabled (protection 0600), and that the /tmp directory
  9.3045 +      is longer world-writeable. /tmp must be world-writeable because lots of
  9.3046 +      applications use it for scratch space. To fix this, do
  9.3047 +      <pre>
  9.3048 +
  9.3049 + chmod 1777 /tmp
  9.3050 +</pre>as root.
  9.3051 +
  9.3052 +      <p>Make sure that your POP3 client issues a QUIT command when it
  9.3053 +      finishes. The POP3 protocol specifies that deletions are discarded
  9.3054 +      unless a proper QUIT is done.</p>
  9.3055 +
  9.3056 +      <p>Make sure that you are not opening multiple POP3 sessions to the
  9.3057 +      same mailbox. It is a requirement of the POP3 protocol than only one
  9.3058 +      POP3 session be in effect to a mailbox at a time, however some,
  9.3059 +      poorly-written POP3 clients violate this. Also, some background "check
  9.3060 +      for new mail" tasks also cause a violation. See the answer to the
  9.3061 +      <a href="#7.19">What does the syslog message: Killed (lost mailbox
  9.3062 +      lock) user=... host=... mean?</a> question for more details.</p>
  9.3063 +    </dd>
  9.3064 +  </dl>
  9.3065 +
  9.3066 +  <p><a href="#top">Back to top</a></p>
  9.3067 +  <hr>
  9.3068 +
  9.3069 +  <p><a name="7.14"><strong>7.14 What do messages such as:</strong></a></p>
  9.3070 +  <pre>
  9.3071 + Message ... UID ... already has UID ...
  9.3072 + Message ... UID ... less than ...
  9.3073 + Message ... UID ... greater than last ...
  9.3074 + Invalid UID ... in message ..., rebuilding UIDs
  9.3075 +</pre>
  9.3076 +
  9.3077 +  <p><strong>mean?</strong></p>
  9.3078 +
  9.3079 +  <dl>
  9.3080 +    <dd>
  9.3081 +      Something happened to corrupt the unique identifier regime in the
  9.3082 +      mailbox. In traditional UNIX-format mailboxes, this can happen if the
  9.3083 +      user deleted the "DO NOT DELETE" internal message.
  9.3084 +
  9.3085 +      <p>This problem is relatively harmless; a new valid unique identifier
  9.3086 +      regime will be created. The main effect is that any references to the
  9.3087 +      old UIDs will no longer be useful.</p>
  9.3088 +
  9.3089 +      <p>So, unless it is a chronic problem or you feel like debugging, you
  9.3090 +      can safely ignore these messages.</p>
  9.3091 +    </dd>
  9.3092 +  </dl>
  9.3093 +
  9.3094 +  <p><a href="#top">Back to top</a></p>
  9.3095 +  <hr>
  9.3096 +
  9.3097 +  <p><a name="7.15"><strong>7.15 What do the error messages:</strong></a></p>
  9.3098 +  <pre>
  9.3099 + Unable to read internal header at ...
  9.3100 + Unable to find CRLF at ...
  9.3101 + Unable to parse internal header at ...
  9.3102 + Unable to parse message date at ...
  9.3103 + Unable to parse message flags at ...
  9.3104 + Unable to parse message UID at ...
  9.3105 + Unable to parse message size at ...
  9.3106 + Last message (at ... ) runs past end of file ...
  9.3107 +</pre>
  9.3108 +
  9.3109 +  <p><strong>mean? I am using mbx format.</strong></p>
  9.3110 +
  9.3111 +  <dl>
  9.3112 +    <dd>
  9.3113 +      The mbx-format mailbox is corrupted and needs to be repaired.
  9.3114 +
  9.3115 +      <p>You should make an effort to find out why the corruption happened.
  9.3116 +      Was there an obvious system problem (crash or disk failure)? Did the
  9.3117 +      user accidentally access the file via NFS? Mailboxes don't get
  9.3118 +      corrupted by themselves; something caused the problem.</p>
  9.3119 +
  9.3120 +      <p>Some people have developed automated scripts, but if you're
  9.3121 +      comfortable using emacs it's pretty easy to fix it manually. Do
  9.3122 +      <em>not</em> use vi or any other editor unless you are certain that
  9.3123 +      editor can handle binary!!!</p>
  9.3124 +
  9.3125 +      <p>If you are not comfortable with emacs, or if the file is too large
  9.3126 +      to read with emacs, see the "step-by-step" technique later on for
  9.3127 +      another way of doing it.</p>
  9.3128 +
  9.3129 +      <p>After the word "at" in the error message is the byte position it got
  9.3130 +      to when it got unhappy with the file, e.g. if you see:</p>
  9.3131 +      <pre>
  9.3132 + Unable to parse internal header at 43921: ne bombastic blurdybloop
  9.3133 +</pre>The problem occurs at the 43,931 byte in the file. That's the point you
  9.3134 +need to fix. c-client is expecting an internal header at that byte number,
  9.3135 +looking something like:
  9.3136 +      <pre>
  9.3137 + 6-Jan-1998 17:42:24 -0800,1045;000000100001-00000001
  9.3138 +</pre>The format of this internal line is:
  9.3139 +      <pre>
  9.3140 + dd-mmm-yyyy hh:mm:ss +zzzz,ssss;ffffffffFFFF-UUUUUUUU
  9.3141 +</pre>The only thing that is variable is the "ssss" field, it can be as many
  9.3142 +digits as needed. All other fields (inluding the "dd") are fixed width. So,
  9.3143 +the easiest thing to do is to look forward in the file for the next internal
  9.3144 +header, and delete everything from the error point to that internal header.
  9.3145 +
  9.3146 +      <p>Here's what to do if you want to be smarter and do a little bit more
  9.3147 +      work. Generally, you're in the middle of a message, and there's nothing
  9.3148 +      wrong with that message. The problem happened in the *previous*
  9.3149 +      message. So, search back to the previous internal header. Now, remember
  9.3150 +      that "ssss" field? That's the size of that message.</p>
  9.3151 +
  9.3152 +      <p>Mark where you are in the file, move the cursor to the line after
  9.3153 +      the internal header, and skip that many bytes ("ssss") forward. If
  9.3154 +      you're at the point of the error in the file, then that message is
  9.3155 +      corrupt. If you're at a different point, then perhaps the previous
  9.3156 +      message is corrupt and has a too long size count that "ate" into this
  9.3157 +      message.</p>
  9.3158 +
  9.3159 +      <p>Basically, what you need to do is make sure that all those size
  9.3160 +      counts are right, and that moving "ssss" bytes from the line after the
  9.3161 +      internal header will land you at another internal header.</p>
  9.3162 +
  9.3163 +      <p>Usually, once you know what you're looking at, it's pretty easy to
  9.3164 +      work out the corruption, and the best remedial action. Repair scripts
  9.3165 +      will make the problem go away but may not always do the smartest/best
  9.3166 +      salvage of the user's data. Manual repair is more flexible and usually
  9.3167 +      preferable.</p>
  9.3168 +
  9.3169 +      <p>Here is a step-by-step technique for fixing corrupt mbx files that's
  9.3170 +      a bit cruder than the procedure outlined above, but works for any size
  9.3171 +      file.</p>
  9.3172 +
  9.3173 +      <p>In this example, suppose that the corrupt file is INBOX, the error
  9.3174 +      message is</p>
  9.3175 +      <pre>
  9.3176 + Unable to find CRLF at 132551754
  9.3177 +</pre>and the size of the INBOX file is 132867870 bytes.
  9.3178 +
  9.3179 +      <p>The first step is to split the mailbox file at the point of the
  9.3180 +      error:</p>
  9.3181 +
  9.3182 +      <ul>
  9.3183 +        <li>Rename the INBOX file to some other name, such as INBOX.bad.</li>
  9.3184 +
  9.3185 +        <li>Copy the first 132,551,754 bytes of INBOX.bad to another file,
  9.3186 +        such as INBOX.new.</li>
  9.3187 +
  9.3188 +        <li>Extract the trailing 316,116 bytes (132867870-132551754) of
  9.3189 +        INBOX.bad into another file, such as INBOX.tail.</li>
  9.3190 +
  9.3191 +        <li>You no longer need INBOX.bad. Delete it.</li>
  9.3192 +      </ul>In other words, use the number from the "Unable to find CRLF at"
  9.3193 +      as the point to split INBOX into two new files, INBOX.new and
  9.3194 +      INBOX.tail.
  9.3195 +
  9.3196 +      <p>Now, remove the erroneous data:</p>
  9.3197 +
  9.3198 +      <ul>
  9.3199 +        <li>Verify that you can open INBOX.new in IMAP or Pine.</li>
  9.3200 +
  9.3201 +        <li>The last message of INBOX.new is probably corrupted. Copy it to
  9.3202 +        another file, such as badmsg.1, then delete and expunge that last
  9.3203 +        message from INBOX.new</li>
  9.3204 +
  9.3205 +        <li>Locate the first occurance of text in INBOX.tail which looks like
  9.3206 +        an internal header, as described above.</li>
  9.3207 +
  9.3208 +        <li>Remove all the text which occurs prior to that point, and place
  9.3209 +        it into another file, such as badmsg.2. Note that in the case of a
  9.3210 +        single digit date, there is a leading space which must not be removed
  9.3211 +        (e.g. " 6-Nov-2001" not "6-Nov-2001").</li>
  9.3212 +      </ul>
  9.3213 +
  9.3214 +      <p>Reassemble the mailbox:</p>
  9.3215 +
  9.3216 +      <ul>
  9.3217 +        <li>Append INBOX.tail to INBOX.new.</li>
  9.3218 +
  9.3219 +        <li>You no longer need INBOX.tail. Delete it.</li>
  9.3220 +
  9.3221 +        <li>Verify that you can open INBOX.new in IMAP or Pine.</li>
  9.3222 +      </ul>
  9.3223 +
  9.3224 +      <p>Reinstall INBOX.new as INBOX:</p>
  9.3225 +
  9.3226 +      <ul>
  9.3227 +        <li>Check to see if you have received any new messages while
  9.3228 +        repairing INBOX.</li>
  9.3229 +
  9.3230 +        <li>If you haven't received any new messages while repairing INBOX,
  9.3231 +        just rename INBOX.new to INBOX.</li>
  9.3232 +
  9.3233 +        <li>If you have received new messages, be sure to copy the new
  9.3234 +        messages from INBOX to INBOX.new before doing the rename.</li>
  9.3235 +      </ul>
  9.3236 +
  9.3237 +      <p>You now have a working INBOX, as well as two files with corrupted
  9.3238 +      data (badmsg.1 and badmsg.2). There may be some useful data in the two
  9.3239 +      badmsg files that you might want to try salvaging; otherwise you can
  9.3240 +      delete the two badmsg files.</p>
  9.3241 +    </dd>
  9.3242 +  </dl>
  9.3243 +
  9.3244 +  <p><a href="#top">Back to top</a></p>
  9.3245 +  <hr>
  9.3246 +
  9.3247 +  <p><a name="7.16"><strong>7.16 What do the syslog messages:</strong></a></p>
  9.3248 +  <pre>
  9.3249 +
  9.3250 + imap/tcp server failing (looping)
  9.3251 + pop3/tcp server failing (looping)
  9.3252 +</pre>
  9.3253 +
  9.3254 +  <p><strong>mean? When it happens, the listed service shuts down. How can I
  9.3255 +  fix this?</strong></p>
  9.3256 +
  9.3257 +  <dl>
  9.3258 +    <dd>
  9.3259 +      The error message "server failing (looping), service terminated" is not
  9.3260 +      from either the IMAP or POP servers. Instead, it comes from inetd, the
  9.3261 +      daemon which listens for TCP connections to a number of servers,
  9.3262 +      including the IMAP and POP servers.
  9.3263 +
  9.3264 +      <p>inetd has a limit of 40 new server sessions per minute for any
  9.3265 +      particular service. If more than 40 sessions are initiated in a minute,
  9.3266 +      inetd will issue the "failing (looping), service terminated" message
  9.3267 +      and shut down the service for 10 minutes. inetd does this to prevent
  9.3268 +      system resource consumption by a client which is spawning infinite
  9.3269 +      numbers of servers. It should be noted that this is a denial of
  9.3270 +      service; however for some systems the alternative is a crash which
  9.3271 +      would be a worse denial of service!</p>
  9.3272 +
  9.3273 +      <p>For larger server systems, the limit of 40 is much too low. The
  9.3274 +      limit was established many years ago when a system typically only ran a
  9.3275 +      few dozen servers.</p>
  9.3276 +
  9.3277 +      <p>On some versions of inetd, such as the one distributed with most
  9.3278 +      versions of Linux, you can modify the <strong>/etc/inetd.conf</strong>
  9.3279 +      file to have a larger number of servers by appending a period followed
  9.3280 +      by a number after the <strong>nowait</strong> word for the server
  9.3281 +      entry. For example, if your existing /etc/inetd.conf line reads:</p>
  9.3282 +      <pre>
  9.3283 + imap    stream  tcp     nowait  root    /usr/etc/imapd imapd
  9.3284 +</pre>try changing it to be:
  9.3285 +      <pre>
  9.3286 + imap    stream  tcp     nowait.100  root    /usr/etc/imapd imapd
  9.3287 +</pre>Another example (using TCP wrappers):
  9.3288 +      <pre>
  9.3289 + imap    stream  tcp     nowait  root    /usr/sbin/tcpd  imapd
  9.3290 +</pre>try changing it to be:
  9.3291 +      <pre>
  9.3292 + imap    stream  tcp     nowait.100  root    /usr/sbin/tcpd  imapd
  9.3293 +
  9.3294 +</pre>to increase the limit to 100 sessions/minute.
  9.3295 +
  9.3296 +      <p>Before making this change, please read the information in "man
  9.3297 +      inetd" to determine whether or not your inetd has this feature. If it
  9.3298 +      does not, and you make this change, the likely outcome is that you will
  9.3299 +      disable IMAP service entirely.</p>
  9.3300 +
  9.3301 +      <p>Another way to fix this problem is to edit the inetd.c source code
  9.3302 +      (provided by your UNIX system vendor) to set higher limits, rebuild
  9.3303 +      inetd, install the new binary, and reboot your system. This should only
  9.3304 +      be done by a UNIX system expert. In the inetd.c source code, the limits
  9.3305 +      <strong>TOOMANY</strong> (normally 40) is the maximum number of new
  9.3306 +      server sessions permitted per minute, and <strong>RETRYTIME</strong>
  9.3307 +      (normally 600) is the number of seconds inetd will shut down the server
  9.3308 +      after it exceeds TOOMANY.</p>
  9.3309 +    </dd>
  9.3310 +  </dl>
  9.3311 +
  9.3312 +  <p><a href="#top">Back to top</a></p>
  9.3313 +  <hr>
  9.3314 +
  9.3315 +  <p><a name="7.17"><strong>7.17 What does the syslog message:</strong>
  9.3316 +     <tt>Mailbox lock file /tmp/.600.1df3 open failure: Permission
  9.3317 +     denied</tt> <strong>mean?</strong></a></p>
  9.3318 +
  9.3319 +  <dl>
  9.3320 +    <dd>
  9.3321 +      This usually means that some "helpful" security script person has
  9.3322 +      protected /tmp so that it is no longer world-writeable. /tmp must be
  9.3323 +      world-writeable because lots of applications use it for scratch space.
  9.3324 +      To fix this, do
  9.3325 +      <pre>
  9.3326 + chmod 1777 /tmp
  9.3327 +
  9.3328 +</pre>as root.
  9.3329 +
  9.3330 +      <p>If that isn't the answer, check the protection of the named file. If
  9.3331 +      it is something other than 666, then either someone is hacking or some
  9.3332 +      "helpful" person modified the code to have a different default lock
  9.3333 +      file protection.</p>
  9.3334 +    </dd>
  9.3335 +  </dl>
  9.3336 +
  9.3337 +  <p><a href="#top">Back to top</a></p>
  9.3338 +  <hr>
  9.3339 +
  9.3340 +  <p><a name="7.18"><strong>7.18 What do the syslog messages:</strong></a></p>
  9.3341 +  <pre>
  9.3342 + Command stream end of file, while reading line user=... host=...
  9.3343 + Command stream end of file, while reading char user=... host=...
  9.3344 + Command stream end of file, while writing text user=... host=...
  9.3345 +</pre>
  9.3346 +
  9.3347 +  <p><strong>mean?</strong></p>
  9.3348 +
  9.3349 +  <dl>
  9.3350 +    <dd>
  9.3351 +      This message occurs when the session is disconnected without a proper
  9.3352 +      LOGOUT (IMAP) or QUIT (POP) command being received by the server first.
  9.3353 +
  9.3354 +      <p>In many cases, this is perfectly normal; many client implementations
  9.3355 +      are impolite and do this. Some programmers think this sort of rudeness
  9.3356 +      is "more efficient".</p>
  9.3357 +
  9.3358 +      <p>The condition could, however, indicate a client or network
  9.3359 +      connectivity problem. The server has no way of knowing whether there's
  9.3360 +      a problem or just a rude client, so it issues this message instead of a
  9.3361 +      Logout.</p>
  9.3362 +
  9.3363 +      <p>Certain inferior losing clients disconnect abruptly after a failed
  9.3364 +      login, and instead of saying that the login failed, just say that they
  9.3365 +      can't access the mailbox. They then complain to the system manager, who
  9.3366 +      looks in the syslog and finds this message. Not very helpful, eh? See
  9.3367 +      the answer to the <a href="#7.4">Why can't I log in to the server? The
  9.3368 +      user name and password are right!</a> question.</p>
  9.3369 +
  9.3370 +      <p>If the user isn't reporting a problem, you can probably ignore this
  9.3371 +      message.</p>
  9.3372 +    </dd>
  9.3373 +  </dl>
  9.3374 +
  9.3375 +  <p><a href="#top">Back to top</a></p>
  9.3376 +  <hr>
  9.3377 +
  9.3378 +  <p><a name="7.19"><strong>7.19 Why did my POP or IMAP session suddenly
  9.3379 +     disconnect? The syslog has the message:</strong> <tt>Killed (lost
  9.3380 +     mailbox lock) user=... host=...</tt></a></p>
  9.3381 +
  9.3382 +  <dl>
  9.3383 +    <dd>
  9.3384 +      This message only happens when either the traditional UNIX mailbox
  9.3385 +      format or MMDF format is in use. This format only allows one session to
  9.3386 +      have the mailbox open read/write at a time.
  9.3387 +
  9.3388 +      <p>The servers assume that if a second session attempts to open the
  9.3389 +      mailbox, that means that the first session is probably owned by an
  9.3390 +      abandoned client. The common scenario here is a user who leaves his
  9.3391 +      client running at the office, and then tries to read his mail from
  9.3392 +      home. Through an internal mechanism called <em>kiss of death</em>, the
  9.3393 +      second session requests the first session to kill itself. When the
  9.3394 +      first session receives the "kiss of death", it issues the "Killed (lost
  9.3395 +      mailbox lock)" syslog message and terminates. The second session then
  9.3396 +      seizes read/write access, and becomes the new "first" session.</p>
  9.3397 +
  9.3398 +      <p>Certain poorly-designed clients routinely open multiple sessions to
  9.3399 +      the same mailbox; the users of those clients tend to get this message a
  9.3400 +      lot.</p>
  9.3401 +
  9.3402 +      <p>Another cause of this message is a background "check for new mail"
  9.3403 +      task which does its work by opening a POP session to server every few
  9.3404 +      seconds. They do this because POP doesn't have a way to announce new
  9.3405 +      mail.</p>
  9.3406 +
  9.3407 +      <p>The solution to both situations is to replace the client with a good
  9.3408 +      online IMAP client such as Pine. Life is too short to waste on POP
  9.3409 +      clients and poorly-designed IMAP clients.</p>
  9.3410 +    </dd>
  9.3411 +  </dl>
  9.3412 +
  9.3413 +  <p><a href="#top">Back to top</a></p>
  9.3414 +  <hr>
  9.3415 +
  9.3416 +  <p><a name="7.20"><strong>7.20 Why does my IMAP client show all the files on the
  9.3417 +     system, recursively from the UNIX root directory?</strong></a><br>
  9.3418 +  <a name="7.21"><strong>7.21 Why does my IMAP client show all of my files,
  9.3419 +     recursively from my UNIX home directory?</strong></a></p>
  9.3420 +
  9.3421 +  <dl>
  9.3422 +    <dd>
  9.3423 +      A well-written client should only show one level of hierarchy and then
  9.3424 +      stop, awaiting explicit user action before going lower. However, some
  9.3425 +      poorly-designed clients will recursively list all files, which may be a
  9.3426 +      very long list (especially if you have symbolic links to directories
  9.3427 +      that create a loop in the filesystem graph!).
  9.3428 +
  9.3429 +      <p>This behavior has also been observed in some third-party c-client
  9.3430 +      drivers, including maildir drivers. Consequently, this problem has even
  9.3431 +      been observed in Pine. It is important to understand that this is not a
  9.3432 +      problem in Pine or c-client; it is a problem in the third-party driver.
  9.3433 +      A Pine built without that third-party driver will not have this
  9.3434 +      problem.</p>
  9.3435 +
  9.3436 +      <p>See also the answer to <a href="#7.73">Why does my IMAP client show
  9.3437 +      all my files in my home directory?</a></p>
  9.3438 +    </dd>
  9.3439 +  </dl>
  9.3440 +
  9.3441 +  <p><a href="#top">Back to top</a></p>
  9.3442 +  <hr>
  9.3443 +
  9.3444 +  <p><a name="7.22"><strong>7.22 Why does my IMAP client show that I have
  9.3445 +     mailboxes named "#mhinbox", "#mh", "#shared", "#ftp", "#news", and
  9.3446 +     "#public"?</strong></a></p>
  9.3447 +
  9.3448 +  <dl>
  9.3449 +    <dd>
  9.3450 +      These are IMAP namespace names. They represent other hierarchies in
  9.3451 +      which messages may exist. These hierarchies may not necessarily exist
  9.3452 +      on a server, but the namespace name is still in the namespace list in
  9.3453 +      order to mark it as reserved.
  9.3454 +
  9.3455 +      <p>A few poorly-designed clients display all namespace names as if they
  9.3456 +      were top-level mailboxes in a user's list of mailboxes, whether or not
  9.3457 +      they actually exist. This is a flaw in those clients.</p>
  9.3458 +    </dd>
  9.3459 +  </dl>
  9.3460 +
  9.3461 +  <p><a href="#top">Back to top</a></p>
  9.3462 +  <hr>
  9.3463 +
  9.3464 +  <p><a name="7.23"><strong>7.23 Why does my IMAP client show all my files in my
  9.3465 +     home directory?</strong></a></p>
  9.3466 +
  9.3467 +  <dl>
  9.3468 +    <dd>
  9.3469 +      As distributed, the IMAP server is connected to your home directory by
  9.3470 +      default. It has no way of knowing what you might call "mail" as opposed
  9.3471 +      to "some other file"; in fact, you can use IMAP to access any file.
  9.3472 +
  9.3473 +      <p>Most clients have an option to configure your connected directory on
  9.3474 +      the IMAP server. For example, in Pine you can specify this as the
  9.3475 +      "Path" in your folder-collection, e.g.</p>
  9.3476 +      <pre>
  9.3477 + Nickname  : Secondary Folders
  9.3478 + Server    : imap.example.com
  9.3479 + Path      : mail/
  9.3480 + View      : 
  9.3481 +</pre>In this example, the user is connected to the "mail" subdirectory of
  9.3482 +his home directory.
  9.3483 +
  9.3484 +      <p>Other servers call this the "folder prefix" or similar term.</p>
  9.3485 +
  9.3486 +      <p>It is possible to modify the IMAP server so that all users are
  9.3487 +      automatically connected to some other directory, e.g. a subdirectory of
  9.3488 +      the user's home directory. Read the file CONFIG for more details.</p>
  9.3489 +    </dd>
  9.3490 +  </dl>
  9.3491 +
  9.3492 +  <p><a href="#top">Back to top</a></p>
  9.3493 +  <hr>
  9.3494 +
  9.3495 +  <p><a name="7.24"><strong>7.24 Why is there a long delay before I get connected
  9.3496 +     to the IMAP or POP server, no matter what client I use?</strong></a></p>
  9.3497 +
  9.3498 +  <dl>
  9.3499 +    <dd>
  9.3500 +      There are two common occurances of this problem:
  9.3501 +
  9.3502 +      <ul>
  9.3503 +        <li>You are running a system (e.g. certain versions of Linux) which
  9.3504 +        by default attempts to connect to an "IDENT" protocol (port 113)
  9.3505 +        server on your client. However, a firewall or NAT box is blocking
  9.3506 +        connections to that port, so the connection attempt times out.
  9.3507 +
  9.3508 +          <p>The IDENT protocol is a well-known bad idea that does not
  9.3509 +          deliver any real security but causes incredible problems. The idea
  9.3510 +          is that this will give the server a record of the user name, or at
  9.3511 +          least what some program listening on port 113 says is the user
  9.3512 +          name. So, if somebody coming from port nnnnn on a system does
  9.3513 +          something bad, IDENT may give you the userid of the bad guy.</p>
  9.3514 +
  9.3515 +          <p>The problem is, IDENT is only meaningful on a timesharing system
  9.3516 +          which has an administrator who is privileged and users who are not.
  9.3517 +          It is of no value on a personal system which has no separate
  9.3518 +          concept of "system administrator" vs. "unprivileged user".</p>
  9.3519 +
  9.3520 +          <p>On either type of system, security-minded people either turn
  9.3521 +          IDENT off or replace it with an IDENT server that lies. Among other
  9.3522 +          things, IDENT gives spammers the ability to harvest email addresses
  9.3523 +          from anyone who connects to a web page.</p>
  9.3524 +
  9.3525 +          <p>This problem has been showing up quite frequently on systems
  9.3526 +          which use xinetd instead of inetd. Look for files named
  9.3527 +          /etc/xinetd.conf, /etc/xinetd.d/imapd, /etc/inetd.d/ipop2d, and
  9.3528 +          /etc/xinetd.d/ipop3d. In those files, look for lines containing
  9.3529 +          "USERID", e.g.</p>
  9.3530 +          <pre>
  9.3531 + log_on_success += USERID
  9.3532 +</pre>Hunt down such lines, and delete them ruthlessly from all files in
  9.3533 +which they occur. Don't be shy about it.
  9.3534 +        </li>
  9.3535 +
  9.3536 +        <li>The DNS is taking a long time to do a reverse DNS (PTR record)
  9.3537 +        lookup of the IP address of your client. This is a problem in your
  9.3538 +        DNS, which either you or you ISP need to resolve. Ideally, the DNS
  9.3539 +        should return the client's name; but if it can't it should at least
  9.3540 +        return an error quickly.</li>
  9.3541 +      </ul>
  9.3542 +
  9.3543 +      <p>As you may have noticed, neither of these are actual problems in the
  9.3544 +      IMAP or POP servers; they are configuration issues with either your
  9.3545 +      system or your network infrastructure. If this is all new to you, run
  9.3546 +      (don't walk) to the nearest technical bookstore and get yourself a good
  9.3547 +      pedagogical text on system administration for the type of system you
  9.3548 +      are running.</p>
  9.3549 +    </dd>
  9.3550 +  </dl>
  9.3551 +
  9.3552 +  <p><a href="#top">Back to top</a></p>
  9.3553 +  <hr>
  9.3554 +
  9.3555 +  <p><a name="7.25"><strong>7.25 Why is there a long delay in Pine or any other
  9.3556 +     c-client based application call before I get connected to the IMAP
  9.3557 +     server? The hang seems to be in the c-client mail_open() call. I don't
  9.3558 +     have this problem with any other IMAP client. There is no delay
  9.3559 +     connecting to a POP3 or NNTP server with mail_open().</strong></a></p>
  9.3560 +
  9.3561 +  <dl>
  9.3562 +    <dd>
  9.3563 +      By default, the c-client library attempts to make a connection through
  9.3564 +      rsh (and ssh, if you enable that). If the command:
  9.3565 +      <pre>
  9.3566 + rsh imapserver exec /etc/rimapd
  9.3567 +
  9.3568 +</pre>(or ssh if that is enabled) returns with a "* PREAUTH" response, it
  9.3569 +will use the resulting rsh session as the IMAP session and not require an
  9.3570 +authentication step on the server.
  9.3571 +
  9.3572 +      <p>Unfortunately, rsh has a design error that treats "TCP connection
  9.3573 +      refused" as "temporary failure, try again"; it expects the "rsh not
  9.3574 +      allowed" case to be implemented as a successful connection followed by
  9.3575 +      an error message and close the connection.</p>
  9.3576 +
  9.3577 +      <p>It must be emphasized that this is a bug in rsh. It is <em>not</em>
  9.3578 +      a bug in the IMAP toolkit.</p>
  9.3579 +
  9.3580 +      <p>The use of rsh can be disabled in any the following ways:</p>
  9.3581 +
  9.3582 +      <ul>
  9.3583 +        <li>You can disable it for this particular session by either:
  9.3584 +
  9.3585 +          <ul>
  9.3586 +            <li>setting an explicit port number in the mailbox name, e.g.
  9.3587 +              <pre>
  9.3588 + {imapserver.foo.com:143}INBOX
  9.3589 +</pre>
  9.3590 +            </li>
  9.3591 +
  9.3592 +            <li>using SSL (the /ssl switch)</li>
  9.3593 +          </ul>
  9.3594 +        </li>
  9.3595 +
  9.3596 +        <li>You can disable rsh globally by setting the rsh timeout value to
  9.3597 +        0 with the call:
  9.3598 +          <pre>
  9.3599 + mail_parameters (NIL,SET_RSHTIMEOUT,0);
  9.3600 +</pre>
  9.3601 +        </li>
  9.3602 +      </ul>
  9.3603 +    </dd>
  9.3604 +  </dl>
  9.3605 +
  9.3606 +  <p><a href="#top">Back to top</a></p>
  9.3607 +  <hr>
  9.3608 +
  9.3609 +  <p><a name="7.26"><strong>7.26 Why does a message sometimes get split into two
  9.3610 +     or more messages on my SUN system?</strong></a></p>
  9.3611 +
  9.3612 +  <dl>
  9.3613 +    <dd>
  9.3614 +      This is caused by an interaction of two independent design problems in
  9.3615 +      SUN mail software. The first problem is that the "forward message"
  9.3616 +      option in SUN's <em>mail tool</em> program includes the internal "From
  9.3617 +      " header line in the text that it forwarded. This internal header line
  9.3618 +      is specific to traditional UNIX mailbox files and is not suitable for
  9.3619 +      use in forwarded messages.
  9.3620 +
  9.3621 +      <p>The second problem is that the mail delivery agent assumes that mail
  9.3622 +      reading programs will not use the traditional UNIX mailbox format but
  9.3623 +      instead an incompatible variant that depends upon a
  9.3624 +      <em>Content-Length:</em> message header. Content-Length is widely
  9.3625 +      recognized to have been a terrible mistake, and is no longer
  9.3626 +      recommended for use in mail (it is used in other facilities that use
  9.3627 +      MIME).</p>
  9.3628 +
  9.3629 +      <p>One symptom of the problem is that under certain circumstances, a
  9.3630 +      message may get broken up into several messages. I'm also aware of
  9.3631 +      security bugs caused by programs that foolishly trust "Content-Length:"
  9.3632 +      headers with evil values.</p>
  9.3633 +
  9.3634 +      <p>To fix the mailer on your system, edit your sendmail.cf to change
  9.3635 +      the <strong>Mlocal</strong> line to have the <strong>-E</strong> flag.
  9.3636 +      A typical entry will lool like:</p>
  9.3637 +      <pre>
  9.3638 + Mlocal,	P=/usr/lib/mail.local, F=flsSDFMmnPE, S=10, R=20,
  9.3639 +		A=mail.local -d $u
  9.3640 +</pre>This fix will also work around the problem with mail tool, because it
  9.3641 +will insert a "&gt;" before the internal header line to prevent it from being
  9.3642 +interpreted by mail reading software as an internal header line.
  9.3643 +    </dd>
  9.3644 +  </dl>
  9.3645 +
  9.3646 +  <p><a href="#top">Back to top</a></p>
  9.3647 +  <hr>
  9.3648 +
  9.3649 +  <p><a name="7.27"><strong>7.27 Why did my POP or IMAP session suddenly
  9.3650 +     disconnect? The syslog has the message:</strong></a></p>
  9.3651 +  <pre>
  9.3652 + Autologout user=&lt;...my user name...&gt; host=&lt;...my client system...&gt;
  9.3653 +
  9.3654 +</pre>
  9.3655 +
  9.3656 +  <dl>
  9.3657 +    <dd>
  9.3658 +      This is a problem in your client.
  9.3659 +
  9.3660 +      <p>In the case of IMAP, it failed to communicate with the IMAP server
  9.3661 +      for over 30 minutes; in the case of POP, it failed to communicate with
  9.3662 +      the POP server for over 10 minutes.</p>
  9.3663 +    </dd>
  9.3664 +  </dl>
  9.3665 +
  9.3666 +  <p><a href="#top">Back to top</a></p>
  9.3667 +  <hr>
  9.3668 +
  9.3669 +  <p><a name="7.28"><strong>7.28 What does the UNIX error message:</strong>
  9.3670 +     <tt>TLS/SSL failure: myserver: SSL negotiation failed</tt>
  9.3671 +     <strong>mean?</strong></a><br>
  9.3672 +  <a name="7.29"><strong>7.29 What does the PC error message:</strong>
  9.3673 +     <tt>TLS/SSL failure: myserver: Unexpected TCP input disconnect</tt>
  9.3674 +     <strong>mean?</strong></a></p>
  9.3675 +
  9.3676 +  <dl>
  9.3677 +    <dd>
  9.3678 +      This usually means that an attempt to negotiate TLS encryption via the
  9.3679 +      STARTTLS command failed, because the server advertises STARTTLS
  9.3680 +      functionality, but doesn't actually have it (e.g. because no
  9.3681 +      certificates are installed).
  9.3682 +
  9.3683 +      <p>Use the /notls option in the mailbox name to disable TLS
  9.3684 +      negotiation.</p>
  9.3685 +    </dd>
  9.3686 +  </dl>
  9.3687 +
  9.3688 +  <p><a href="#top">Back to top</a></p>
  9.3689 +  <hr>
  9.3690 +
  9.3691 +  <p><a name="7.30"><strong>7.30 What does the error message:</strong> <tt>TLS/SSL
  9.3692 +     failure: myserver: Server name does not match certificate</tt>
  9.3693 +     <strong>mean?</strong></a></p>
  9.3694 +
  9.3695 +  <dl>
  9.3696 +    <dd>
  9.3697 +      An SSL or TLS session encryption failed because the server name in the
  9.3698 +      server's certificate does not match the name that you gave it. This
  9.3699 +      could indicate that the server is not really the system you think that
  9.3700 +      it is, but can be also be called if you gave a nickname for the server
  9.3701 +      or name that was not fully-qualified. You must use the fully-qualified
  9.3702 +      domain name for the server in order to validate its certificate
  9.3703 +
  9.3704 +      <p>Use the /novalidate-cert option in the mailbox name to disable
  9.3705 +      validation of the certificate.</p>
  9.3706 +    </dd>
  9.3707 +  </dl>
  9.3708 +
  9.3709 +  <p><a href="#top">Back to top</a></p>
  9.3710 +  <hr>
  9.3711 +
  9.3712 +  <p><a name="7.31"><strong>7.31 What does the UNIX error message:</strong>
  9.3713 +     <tt>TLS/SSL failure: myserver: self-signed certificate</tt>
  9.3714 +     <strong>mean?</strong></a><br>
  9.3715 +  <a name="7.32"><strong>7.32 What does the PC error message:</strong>
  9.3716 +     <tt>TLS/SSL failure: myserver: Self-signed certificate or untrusted
  9.3717 +     authority</tt> <strong>mean?</strong></a></p>
  9.3718 +
  9.3719 +  <dl>
  9.3720 +    <dd>
  9.3721 +      An SSL or TLS session encryption failed because your server's
  9.3722 +      certificate is "self-signed"; that is, it is not signed by any
  9.3723 +      Certificate Authority (CA) and thus can not be validated. A CA-signed
  9.3724 +      certificate costs money, and some smaller sites either don't want to
  9.3725 +      pay for it or haven't gotten one yet. The bad part about this is that
  9.3726 +      this means there is no guarantee that the server is really the system
  9.3727 +      you think that it is.
  9.3728 +
  9.3729 +      <p>Use the /novalidate-cert option in the mailbox name to disable
  9.3730 +      validation of the certificate.</p>
  9.3731 +    </dd>
  9.3732 +  </dl>
  9.3733 +
  9.3734 +  <p><a href="#top">Back to top</a></p>
  9.3735 +  <hr>
  9.3736 +
  9.3737 +  <p><a name="7.33"><strong>7.33 What does the UNIX error message:</strong>
  9.3738 +     <tt>TLS/SSL failure: myserver: unable to get local issuer
  9.3739 +     certificate</tt> <strong>mean?</strong></a></p>
  9.3740 +
  9.3741 +  <dl>
  9.3742 +    <dd>
  9.3743 +      An SSL or TLS session encryption failed because your system does not
  9.3744 +      have the Certificate Authority (CA) certificates installed on OpenSSL's
  9.3745 +      certificates directory. On most systems, this directory is
  9.3746 +      /usr/local/ssl/certs). As a result, it is not possible to validate the
  9.3747 +      server's certificate.
  9.3748 +
  9.3749 +      <p>If CA certificates are properly installed, you should see
  9.3750 +      factory.pem and about a dozen other .pem names such as
  9.3751 +      thawteCb.pem.</p>
  9.3752 +
  9.3753 +      <p>As a workaround, you can use the /novalidate-cert option in the
  9.3754 +      mailbox name to disable validation of the certificate; however, note
  9.3755 +      that you are then vulnerable to various security attacks by bad
  9.3756 +      guys.</p>
  9.3757 +
  9.3758 +      <p>The correct fix is to copy all the files from the certs/ directory
  9.3759 +      in the OpenSSL distribution to the /usr/local/ssl/certs (or whatever)
  9.3760 +      directory. Note that you need to do this after building OpenSSL,
  9.3761 +      because the OpenSSL build creates a number of needed symbolic links.
  9.3762 +      For some bizarre reason, the OpenSSL "make install" doesn't do this for
  9.3763 +      you, so you must do it manually.</p>
  9.3764 +    </dd>
  9.3765 +  </dl>
  9.3766 +
  9.3767 +  <p><a href="#top">Back to top</a></p>
  9.3768 +  <hr>
  9.3769 +
  9.3770 +  <p><a name="7.34"><strong>7.34 Why does reading certain messages hang when using
  9.3771 +     Netscape? It works fine with Pine!</strong></a></p>
  9.3772 +
  9.3773 +  <dl>
  9.3774 +    <dd>
  9.3775 +      There are two possible causes.
  9.3776 +
  9.3777 +      <p>Check the mail syslog. If you see the message "Killed (lost mailbox
  9.3778 +      lock)" for the impacted user(s), read the FAQ entry regarding that
  9.3779 +      message.</p>
  9.3780 +
  9.3781 +      <p>Check the affected mailbox to see if there are embedded NUL
  9.3782 +      characters in the message. NULs in message texts are a technical
  9.3783 +      violation of both the message format and IMAP specifications. Most
  9.3784 +      clients don't care, but apparently Netscape does.</p>
  9.3785 +
  9.3786 +      <p>You can work around this by rebuilding imapd with the
  9.3787 +      <strong>NETSCAPE_BRAIN_DAMAGE</strong> option set (see
  9.3788 +      src/imapd/Makefile); this will cause imapd to convert all NULs to 0x80
  9.3789 +      characters. A better solution is to enable the feature in your MTA to
  9.3790 +      MIME-convert messages with binary content. See the documentation for
  9.3791 +      your MTA for how to do this.</p>
  9.3792 +    </dd>
  9.3793 +  </dl>
  9.3794 +
  9.3795 +  <p><a href="#top">Back to top</a></p>
  9.3796 +  <hr>
  9.3797 +
  9.3798 +  <p><a name="7.35"><strong>7.35 Why does Netscape say that there's a problem with
  9.3799 +     the IMAP server and that I should "Contact your mail server
  9.3800 +     administrator."?</strong></a></p>
  9.3801 +
  9.3802 +  <dl>
  9.3803 +    <dd>
  9.3804 +      Certain versions of Netscape do this when you click the Manage Mail
  9.3805 +      button, which uses an undocumented feature of Netscape's proprietary
  9.3806 +      IMAP server.
  9.3807 +
  9.3808 +      <p>You can work around this by rebuilding imapd with the
  9.3809 +      <strong>NETSCAPE_BRAIN_DAMAGE</strong> option set (see
  9.3810 +      src/imapd/Makefile) to a URL that points either to an alternative IMAP
  9.3811 +      client (e.g. Pine) or perhaps to a homebrew mail account management
  9.3812 +      page.</p>
  9.3813 +    </dd>
  9.3814 +  </dl>
  9.3815 +
  9.3816 +  <p><a href="#top">Back to top</a></p>
  9.3817 +  <hr>
  9.3818 +
  9.3819 +  <p><a name="7.36"><strong>7.36 Why is one user creating huge numbers of IMAP or
  9.3820 +     POP server sessions?</strong></a></p>
  9.3821 +
  9.3822 +  <dl>
  9.3823 +    <dd>The user is probably using Outlook Express, Eudora, or a similar
  9.3824 +    program. See the answer to the <a href="#7.5">Help! My load average is
  9.3825 +    soaring and I see hundreds of POP and IMAP servers, many logged in as the
  9.3826 +    same user!</a> question.</dd>
  9.3827 +  </dl>
  9.3828 +
  9.3829 +  <p><a href="#top">Back to top</a></p>
  9.3830 +  <hr>
  9.3831 +
  9.3832 +  <p><a name="7.37"><strong>7.37 Why don't I get any new mail notifications from
  9.3833 +     Outlook Express or Outlook after a while?</strong></a></p>
  9.3834 +
  9.3835 +  <dl>
  9.3836 +    <dd>
  9.3837 +      This is a known bug in Outlook Express. Microsoft is aware of the
  9.3838 +      problem and its cause. They have informed us that they do not have any
  9.3839 +      plans to fix it at the present time.
  9.3840 +
  9.3841 +      <p>The problem is also reported in Outlook 2000, but not verified.</p>
  9.3842 +
  9.3843 +      <p>Outlook Express uses the IMAP IDLE command to avoid having to "ping"
  9.3844 +      the server every few minutes for new mail. Unfortunately, Outlook
  9.3845 +      Express overlooks the part in the IDLE specification which requires
  9.3846 +      that a client terminate and restart the IDLE before the IMAP 30 minute
  9.3847 +      inactivity autologout timer triggers.</p>
  9.3848 +
  9.3849 +      <p>When this happens, Outlook Express displays "Not connected" at the
  9.3850 +      bottom of the window. Since it's no longer connected to the IMAP
  9.3851 +      server, it isn't going to notice any new mail.</p>
  9.3852 +
  9.3853 +      <p>As soon as the user does anything that would cause an IMAP
  9.3854 +      operation, Outlook Express will reconnect and new mail will flow again.
  9.3855 +      If the user does something that causes an IMAP operation at least every
  9.3856 +      29 minutes, the problem won't happen.</p>
  9.3857 +
  9.3858 +      <p>Modern versions of imapd attempt to work around the problem by
  9.3859 +      automatically reporting fake new mail after 29 minutes. This causes
  9.3860 +      Outlook Express to exit the IDLE state; as soon as this happens imapd
  9.3861 +      revokes the fake new mail. As long as this behavior isn't known to
  9.3862 +      cause problems with other clients, this workaround will remain in
  9.3863 +      imapd.</p>
  9.3864 +    </dd>
  9.3865 +  </dl>
  9.3866 +
  9.3867 +  <p><a href="#top">Back to top</a></p>
  9.3868 +  <hr>
  9.3869 +
  9.3870 +  <p><a name="7.38"><strong>7.38 Why don't I get any new mail notifications from
  9.3871 +     Entourage?</strong></a></p>
  9.3872 +
  9.3873 +  <dl>
  9.3874 +    <dd>
  9.3875 +      This is a known bug in Entourage.
  9.3876 +
  9.3877 +      <p>You built an older version of imapd with the
  9.3878 +      <strong>MICROSOFT_BRAIN_DAMAGE</strong> option set, in order to disable
  9.3879 +      support for the IDLE command. However, Entourage won't get new mail
  9.3880 +      unless IDLE command support exists.</p>
  9.3881 +
  9.3882 +      <p>Note: the MICROSOFT_BRAIN_DAMAGE option no longer exists in modern
  9.3883 +      versions, as the Outlook Express problem which it attempted to solve
  9.3884 +      has been worked around in another way.</p>
  9.3885 +    </dd>
  9.3886 +  </dl>
  9.3887 +
  9.3888 +  <p><a href="#top">Back to top</a></p>
  9.3889 +  <hr>
  9.3890 +
  9.3891 +  <p><a name="7.39"><strong>7.39 Why doesn't Entourage work at
  9.3892 +     all?</strong></a></p>
  9.3893 +
  9.3894 +  <dl>
  9.3895 +    <dd>
  9.3896 +      It's hard to know. Entourage breaks almost every rule in the book for
  9.3897 +      IMAP. It is highly instructive to do a packet trace on Entourage, as an
  9.3898 +      example of how <em>not</em> to use IMAP. It does things like STATUS
  9.3899 +      (MESSAGES) on the currently selected mailbox and re-fetching the same
  9.3900 +      static data over and over again.
  9.3901 +
  9.3902 +      <p>It seems that every time we understand what it is doing wrong in
  9.3903 +      Entourage and come up with a workaround, we learn about something else
  9.3904 +      that's broken.</p>
  9.3905 +
  9.3906 +      <p>Try building imapd with the <strong>ENTOURAGE_BRAIN_DAMAGE</strong>
  9.3907 +      option set, in order to disable the diagnostic that occurs when doing
  9.3908 +      STATUS on the currently selected mailbox.</p>
  9.3909 +    </dd>
  9.3910 +  </dl>
  9.3911 +
  9.3912 +  <p><a href="#top">Back to top</a></p>
  9.3913 +  <hr>
  9.3914 +
  9.3915 +  <p><a name="7.40"><strong>7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE) work
  9.3916 +     at all?</strong></a></p>
  9.3917 +
  9.3918 +  <dl>
  9.3919 +    <dd>
  9.3920 +      This is a bug in NSNOTIFY; it doesn't handle unsolicited data from the
  9.3921 +      server correctly.
  9.3922 +
  9.3923 +      <p>Fortunately, there is no reason to use this program with IMAP;
  9.3924 +      NSNOTIFY is a polling program to let you know when new mail has
  9.3925 +      appeared in your maildrop. This is necessary with POP; but since IMAP
  9.3926 +      dynamically announces new mail in the session you're better off (and
  9.3927 +      will actually cause less load on the server!) keeping your mail reading
  9.3928 +      program's IMAP session open and let IMAP do the notifying for you.</p>
  9.3929 +
  9.3930 +      <p>Consequently, the recommended fix for the NSNOTIFY problem is to
  9.3931 +      delete the NSNOTIFY binary.</p>
  9.3932 +    </dd>
  9.3933 +  </dl>
  9.3934 +
  9.3935 +  <p><a href="#top">Back to top</a></p>
  9.3936 +  <hr>
  9.3937 +
  9.3938 +  <p><a name="7.41"><strong>7.41 Why can't I connect via SSL to Eudora? It says
  9.3939 +     the connection has been broken, and in the server syslogs I see "Command
  9.3940 +     stream end of file".</strong></a></p>
  9.3941 +
  9.3942 +  <dl>
  9.3943 +    <dd>There is a report that you can fix the problem by going into Eudora's
  9.3944 +    advanced network configuration menu and increasing the network buffer
  9.3945 +    size to 8192.</dd>
  9.3946 +  </dl>
  9.3947 +
  9.3948 +  <p><a href="#top">Back to top</a></p>
  9.3949 +  <hr>
  9.3950 +
  9.3951 +  <p><a name="7.42"><strong>7.42 Sheesh. Aren't there <em>any</em> good IMAP
  9.3952 +     clients out there?</strong></a></p>
  9.3953 +
  9.3954 +  <dl>
  9.3955 +    <dd>
  9.3956 +      Yes!
  9.3957 +
  9.3958 +      <p>Pine is a <em>wonderful</em> client. It's fast, it uses IMAP well,
  9.3959 +      and it generates text mail (life is too short to waste on HTML mail).
  9.3960 +      Also, there are some really wonderful things in progress in the Pine
  9.3961 +      world.</p>
  9.3962 +
  9.3963 +      <p>There are some good GUI clients out there, mostly from smaller
  9.3964 +      vendors. Without naming names, look for the vendors who are active in
  9.3965 +      the IMAP protocol development community, and their products.</p>
  9.3966 +
  9.3967 +      <p>Netscape, Eudora, and Outlook <em>can</em> be configured with enough
  9.3968 +      effort to be good citizens and work well for users, <em>but</em> they
  9.3969 +      can also be badly misconfigured, and often the misconfiguration is the
  9.3970 +      default.</p>
  9.3971 +    </dd>
  9.3972 +  </dl>
  9.3973 +
  9.3974 +  <p><a href="#top">Back to top</a></p>
  9.3975 +  <hr>
  9.3976 +
  9.3977 +  <p><a name="7.43"><strong>7.43 But wait! PC Pine (or other PC program build with
  9.3978 +     c-client) crashes with the message</strong> <tt>incomplete SecBuffer
  9.3979 +     exceeds maximum buffer size</tt> <strong>when I use SSL connections.
  9.3980 +     This is a bug in c-client, right?</strong></a></p>
  9.3981 +
  9.3982 +  <dl>
  9.3983 +    <dd>
  9.3984 +      It's a bug in the Microsoft SChannel.DLL, which implements SSL.
  9.3985 +      Microsoft admits it (albeit with an unstatement: "it's not fully RFC
  9.3986 +      compliant"). The problem is that SChannel indicates that the maximum
  9.3987 +      SSL packet data size is 5 bytes smaller than the actual maximum. Thus,
  9.3988 +      any IMAP server which transmits a maximum sized SSL packet will not
  9.3989 +      work with PC Pine or any other program which uses SChannel.
  9.3990 +
  9.3991 +      <p>It can take a while for the problem to show up. The client has to do
  9.3992 +      something that causes at least 16K of contiguous data. Many clients do
  9.3993 +      partial fetching, which tends to reduce the number of cases where this
  9.3994 +      can happen. However, <em>all</em> software which uses SChannel to
  9.3995 +      support SSL is affected by this bug.</p>
  9.3996 +
  9.3997 +      <p>This problem does not affect UNIX code, since OpenSSL is used on
  9.3998 +      UNIX.</p>
  9.3999 +
  9.4000 +      <p>This problem most recently showed up with the CommunigatePro IMAP
  9.4001 +      server. They have an update which trims down their maximum contiguous
  9.4002 +      data to less than 16K, in order to work around the problem.</p>
  9.4003 +
  9.4004 +      <p>This problem has also shown up with the Exchange IMAP server with
  9.4005 +      UNIX clients (including Pine built with an older version of c-client)
  9.4006 +      which sends full-sized 16K SSL packets. Modern c-client works around
  9.4007 +      the problem by trimming down its maximum outgoing SSL packet size to
  9.4008 +      8K.</p>
  9.4009 +
  9.4010 +      <p>Microsoft has developed a hotfix for this bug. Look up MSKB article
  9.4011 +      number 300562. Contrary to the article text which implies that this is
  9.4012 +      a Pine issue, this bug also affect Microsoft Exchange server with *any*
  9.4013 +      UNIX based client that transmits full-sized SSL payloads.</p>
  9.4014 +    </dd>
  9.4015 +  </dl>
  9.4016 +
  9.4017 +  <p><a href="#top">Back to top</a></p>
  9.4018 +  <hr>
  9.4019 +
  9.4020 +  <p><a name="7.44"><strong>7.44 My qpopper users keep on getting the DON'T DELETE
  9.4021 +     THIS MESSAGE -- FOLDER INTERNAL DATA if they also use Pine or IMAP. How
  9.4022 +     can I fix this?</strong></a></p>
  9.4023 +
  9.4024 +  <dl>
  9.4025 +    <dd>
  9.4026 +      This is an incompatibility between qpopper and the c-client library
  9.4027 +      used by Pine, imapd, and ipop[23]d.
  9.4028 +
  9.4029 +      <p>Assuming that you want to continue using qpopper, look into
  9.4030 +      qpopper's <strong>--enable-uw-kludge-flag</strong> configuration flag,
  9.4031 +      which is documented as "check for and hide UW 'Folder Internal Data'
  9.4032 +      messages".</p>
  9.4033 +
  9.4034 +      <p>The other alternative is to switch from qpopper to ipop3d.</p>
  9.4035 +    </dd>
  9.4036 +  </dl>
  9.4037 +
  9.4038 +  <p><a href="#top">Back to top</a></p>
  9.4039 +  <hr>
  9.4040 +
  9.4041 +  <p><a name="7.45"><strong>7.45 Help! I installed the servers but I can't connect
  9.4042 +     to them from my client!</strong></a></p>
  9.4043 +
  9.4044 +  <dl>
  9.4045 +    <dd>
  9.4046 +      Review the installation instructions carefully. Make sure that you have
  9.4047 +      not skipped any of the steps. Make sure that you have made the correct
  9.4048 +      entries in the configuration files; pay careful attention to the exact
  9.4049 +      spelling of the service names and the path names. Make sure as well
  9.4050 +      that you have properly restarted inetd.
  9.4051 +
  9.4052 +      <p>If you have a system with Yellow Pages/NIS such as Solaris, have you
  9.4053 +      updated the service names there as well as in /etc/services?</p>
  9.4054 +
  9.4055 +      <p>If you have a system with TCP wrappers, have you properly updated
  9.4056 +      the TCP wrapper files (e.g. /etc/hosts.allow and /etc/hosts.deny) for
  9.4057 +      the servers?</p>
  9.4058 +
  9.4059 +      <p>If you have a system which uses xinetd instead of inetd, have you
  9.4060 +      made sure that you have made the correct corresponding xinetd changes
  9.4061 +      for those services?</p>
  9.4062 +
  9.4063 +      <p>Try telneting to the server port (143 for IMAP, 110 for POP3). If
  9.4064 +      you get a "refused" error, that probably means that you don't have the
  9.4065 +      service set up in inetd.conf. If the connection opens and then closes
  9.4066 +      with no message, the service is set up, but either the path name of the
  9.4067 +      server binary in inetd.conf is wrong or your TCP wrappers are
  9.4068 +      configured to deny access.</p>
  9.4069 +
  9.4070 +      <p>If you don't know how to make the corresponding changes to these
  9.4071 +      files, seek the help of a local expert for your system.</p>
  9.4072 +    </dd>
  9.4073 +  </dl>
  9.4074 +
  9.4075 +  <p><a href="#top">Back to top</a></p>
  9.4076 +  <hr>
  9.4077 +
  9.4078 +  <p><a name="7.46"><strong>7.46 Why do I get the message</strong> <tt>Can not
  9.4079 +     authenticate to SMTP server: 421 SMTP connection went away!</tt>
  9.4080 +     <strong>and why did this happen? There was also something about</strong>
  9.4081 +     <tt>SECURITY PROBLEM: insecure server advertised AUTH=PLAIN</tt></a></p>
  9.4082 +
  9.4083 +  <dl>
  9.4084 +    <dd>
  9.4085 +      Some versions of qmail, including that running on mail.smtp.yahoo.com,
  9.4086 +      disconnect the SMTP session if you fail to authenticate prior to
  9.4087 +      attempting to transmit mail. An attempt to authenticate was made, but
  9.4088 +      it failed because the server had already disconnected.
  9.4089 +
  9.4090 +      <p>To work around this, you need to specify /user=... in the host name
  9.4091 +      specification.</p>
  9.4092 +
  9.4093 +      <p>The SECURITY PROBLEM came about because the server advertised the
  9.4094 +      AUTH=PLAIN SASL authentication mechanism outside of a TLS-encrypted
  9.4095 +      session, in violation of RFC 4616. This message is just a warning, and
  9.4096 +      in fact occurred after the server had disconnected.</p>
  9.4097 +    </dd>
  9.4098 +  </dl>
  9.4099 +
  9.4100 +  <p><a href="#top">Back to top</a></p>
  9.4101 +  <hr>
  9.4102 +
  9.4103 +  <p><a name="7.47"><strong>7.47 Why do I get the message</strong> <tt>SMTP
  9.4104 +     Authentication cancelled</tt> <strong>and why did this happen? There was
  9.4105 +     also something about</strong> <tt>SECURITY PROBLEM: insecure server
  9.4106 +     advertised AUTH=PLAIN</tt></a></p>
  9.4107 +
  9.4108 +  <dl>
  9.4109 +    <dd>
  9.4110 +      This is a bug in the SMTP server.
  9.4111 +
  9.4112 +      <p>Some versions of qmail, including that running on
  9.4113 +      mail.smtp.yahoo.com, have a bug in their implementation of SASL in
  9.4114 +      their SMTP server, which renders it non-compliant with the
  9.4115 +      standard.</p>
  9.4116 +
  9.4117 +      <p>If the client does not provide an initial response in the command
  9.4118 +      line for an authentication mechanism whose profile does not have an
  9.4119 +      initial challenge, qmail issues a bogus response:</p>
  9.4120 +      <pre>
  9.4121 + 334 ok, go on
  9.4122 +</pre>The problem is the "ok, go on". This violates RFC 4954's requirement
  9.4123 +that the text part in a 334 response be a BASE64 encoded string; in other
  9.4124 +words, it is a protocol syntax error.
  9.4125 +
  9.4126 +      <p>In the case of AUTH=PLAIN, RFC 4422 (page 7) requires that the
  9.4127 +      encoded string have no data. In other words, the appropropiate
  9.4128 +      standards-compliant server response is "334" followed by a SPACE and a
  9.4129 +      CRLF.</p>
  9.4130 +
  9.4131 +      <p>The SECURITY PROBLEM came about because the server advertised the
  9.4132 +      AUTH=PLAIN SASL authentication mechanism outside of a TLS-encrypted
  9.4133 +      session, in violation of RFC 4616. This message is just a warning, and
  9.4134 +      is not related the "Authentication cancelled" problem.</p>
  9.4135 +    </dd>
  9.4136 +  </dl>
  9.4137 +
  9.4138 +  <p><a href="#top">Back to top</a></p>
  9.4139 +  <hr>
  9.4140 +
  9.4141 +  <p><a name="7.48"><strong>7.48 Why do I get the message</strong> <tt>Invalid
  9.4142 +     base64 string</tt> <strong>when I try to authenticate to a Cyrus
  9.4143 +     server?</strong></a></p>
  9.4144 +
  9.4145 +  <dl>
  9.4146 +    <dd>
  9.4147 +      This slightly misleading message is the way that a Cyrus server
  9.4148 +      indicates that an authentication exchange was cancelled. It is not
  9.4149 +      indicative of a bug or protocol violation.
  9.4150 +
  9.4151 +      <p>The most common reason that this happens is if the Cyrus server
  9.4152 +      offers Kerberos authentication, c-client is built with Kerberos
  9.4153 +      support, but your client system is not within the Kerberos realm. In
  9.4154 +      this case, the client code will try to authenticate via Kerberos, fail
  9.4155 +      to get the Kerberos credentials, cancel the authentication attempt, and
  9.4156 +      try the next available authentication technology.</p>
  9.4157 +    </dd>
  9.4158 +  </dl>
  9.4159 +
  9.4160 +  <p><a href="#top">Back to top</a></p>
  9.4161 +  <hr>
  9.4162 +
  9.4163 +  <p><br></p>
  9.4164 +
  9.4165 +  <h2><a name="additional">8. Where to Go For Additional Information</a></h2>
  9.4166 +  <hr>
  9.4167 +
  9.4168 +  <p><a name="8.1"><strong>8.1 Where can I go to ask questions?</strong></a><br>
  9.4169 +  <a name="8.2"><strong>8.2 I have some ideas for enhancements to IMAP. Where
  9.4170 +     should I go?</strong></a></p>
  9.4171 +
  9.4172 +  <dl>
  9.4173 +    <dd>
  9.4174 +      If you have questions about the IMAP protocol, or want to participate
  9.4175 +      in discussions of future directions of the IMAP protocol, the
  9.4176 +      appropriate mailing list is imap-protocol@u.washington.edu. You can
  9.4177 +      subscribe to this list via <a href=
  9.4178 +      "mailto:imap-protocol-request@u.washington.edu"><tt>imap-protocol-request@u.washington.edu</tt></a>
  9.4179 +
  9.4180 +      <p>If you have questions about this software, you can send me email
  9.4181 +      directly or use the imap-uw@u.washington.edu mailing list. You can
  9.4182 +      subscribe to this list via <a href=
  9.4183 +      "mailto:imap-uw-request@u.washington.edu"><tt>imap-uw-request@u.washington.edu</tt></a></p>
  9.4184 +
  9.4185 +      <p>If you have general questions about the use of IMAP software
  9.4186 +      (not specific to the UW IMAP toolkit) use the
  9.4187 +      imap-use@u.washington.edu mailing list. You can subscribe to
  9.4188 +      this list via <a href=
  9.4189 +      "mailto:imap-use-request@u.washington.edu"><tt>imap-use-request@u.washington.edu</tt></a></p>
  9.4190 +
  9.4191 +      <p>You must be a subscriber to post to these lists.  As an
  9.4192 +      alternative, you can use the
  9.4193 +      <strong>comp.mail.imap</strong> newsgroup.</p>
  9.4194 +    </dd>
  9.4195 +  </dl>
  9.4196 +
  9.4197 +  <p><a href="#top">Back to top</a></p>
  9.4198 +  <hr>
  9.4199 +
  9.4200 +  <p><a name="8.3"><strong>8.3 Where can I read more about IMAP and other email
  9.4201 +     protocols?</strong></a></p>
  9.4202 +
  9.4203 +  <dl>
  9.4204 +    <dd>We recommend <em>Internet Email Protocols: A Developer's Guide</em>,
  9.4205 +    by Kevin Johnson, published by Addison Wesley, ISBN 0-201-43288-9.</dd>
  9.4206 +  </dl>
  9.4207 +
  9.4208 +  <p><a href="#top">Back to top</a></p>
  9.4209 +  <hr>
  9.4210 +
  9.4211 +  <p><a name="8.4"><strong>8.4 Where can I find out more about setting up and
  9.4212 +     administering an IMAP server?</strong></a></p>
  9.4213 +
  9.4214 +  <dl>
  9.4215 +    <dd>
  9.4216 +      We recommend <em>Managing IMAP</em>, by Dianna Mullet &amp; Kevin
  9.4217 +      Mullet, published by O'Reilly, ISBN 0-596-00012-X.
  9.4218 +
  9.4219 +      <p>This book also has an excellent comparison of the UW and Cyrus IMAP
  9.4220 +      servers.<br></p>
  9.4221 +    </dd>
  9.4222 +  </dl>
  9.4223 +
  9.4224 +  <p><a href="#top">Back to top</a></p>
  9.4225 +
  9.4226 +  <p>Last Updated: 15 November 2007</p>
  9.4227 +
  9.4228 +<!--chtml include "//imap/incs/bottom.inc"-->
  9.4229 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/docs/FAQ.txt	Mon Sep 14 15:17:45 2009 +0900
    10.3 @@ -0,0 +1,2993 @@
    10.4 +/* ========================================================================
    10.5 + * Copyright 1988-2007 University of Washington
    10.6 + *
    10.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    10.8 + * you may not use this file except in compliance with the License.
    10.9 + * You may obtain a copy of the License at
   10.10 + *
   10.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   10.12 + *
   10.13 + *
   10.14 + * ========================================================================
   10.15 + */
   10.16 +
   10.17 +                    IMAP Toolkit Frequently Asked Questions
   10.18 +
   10.19 +Table of Contents
   10.20 +
   10.21 +     * 1. General/Software Feature Questions
   10.22 +          + 1.1 Can I set up a POP or IMAP server on UNIX/Linux/OSF/etc.?
   10.23 +          + 1.2 I am currently using qpopper as my POP3 server on UNIX.
   10.24 +            Do I need to replace it with ipop3d in order to run imapd?
   10.25 +          + 1.3 Can I set up a POP or IMAP server on Windows XP, 2000,
   10.26 +            NT, Me, 98, or 95?
   10.27 +          + 1.4 Can I set up a POP or IMAP server on Windows 3.1 or DOS?
   10.28 +          + 1.5 Can I set up a POP or IMAP server on Macintosh?
   10.29 +          + 1.6 Can I set up a POP or IMAP server on VAX/VMS?
   10.30 +          + 1.7 Can I set up a POP or IMAP server on TOPS-20?
   10.31 +          + 1.8 Are hierarchical mailboxes supported?
   10.32 +          + 1.9 Are "dual-use" mailboxes supported?
   10.33 +          + 1.10 Can I have a mailbox that has both messages and
   10.34 +            sub-mailboxes?
   10.35 +          + 1.11 What is the difference between "mailbox" and "folder"?
   10.36 +          + 1.12 What is the status of internationalization?
   10.37 +          + 1.13 Can I use SSL?
   10.38 +          + 1.14 Can I use TLS and the STARTTLS facility?
   10.39 +          + 1.15 Can I use CRAM-MD5 authentication?
   10.40 +          + 1.16 Can I use APOP authentication?
   10.41 +          + 1.17 Can I use Kerberos V5?
   10.42 +          + 1.18 Can I use PAM for plaintext passwords?
   10.43 +          + 1.19 Can I use Kerberos 5 for plaintext passwords?
   10.44 +          + 1.20 Can I use AFS for plaintext passwords?
   10.45 +          + 1.21 Can I use DCE for plaintext passwords?
   10.46 +          + 1.22 Can I use the CRAM-MD5 database for plaintext passwords?
   10.47 +          + 1.23 Can I disable plaintext passwords?
   10.48 +          + 1.24 Can I disable plaintext passwords on unencrypted
   10.49 +            sessions, but allow them on encrypted sessions?
   10.50 +          + 1.25 Can I use virtual hosts?
   10.51 +          + 1.26 Can I use RPOP authentication?
   10.52 +          + 1.27 Can I use Kerberos V4?
   10.53 +          + 1.28 Is there support for S/Key or OTP?
   10.54 +          + 1.29 Is there support for NTLM or SPA?
   10.55 +          + 1.30 Is there support for mh?
   10.56 +          + 1.31 Is there support for qmail and the maildir format?
   10.57 +          + 1.32 Is there support for the Cyrus mailbox format?
   10.58 +          + 1.33 Is this software Y2K compliant?
   10.59 +     * 2. What Do I Need to Build This Software?
   10.60 +          + 2.1 What do I need to build this software with SSL on UNIX?
   10.61 +          + 2.2 What do I need to build this software with Kerberos V on
   10.62 +            UNIX?
   10.63 +          + 2.3 What do I need to use a C++ compiler with this software
   10.64 +            to build my own application?
   10.65 +          + 2.4 What do I need to build this software on Windows?
   10.66 +          + 2.5 What do I need to build this software on DOS?
   10.67 +          + 2.6 Can't I use Borland C to build this software on the PC?
   10.68 +          + 2.7 What do I need to build this software on the Mac?
   10.69 +          + 2.8 What do I need to build this software on VMS?
   10.70 +          + 2.9 What do I need to build this software on TOPS-20?
   10.71 +          + 2.10 What do I need to build this software on Amiga or OS/2?
   10.72 +          + 2.11 What do I need to build this software on Windows CE?
   10.73 +     * 3. Build and Configuration Questions
   10.74 +          + 3.1 How do I configure the IMAP and POP servers on UNIX?
   10.75 +          + 3.2 I built and installed the servers according to the BUILD
   10.76 +            instructions. It can't be that easy. Don't I need to write a
   10.77 +            config file?
   10.78 +          + 3.3 How do I make the IMAP and POP servers look for INBOX at
   10.79 +            some place other than the mail spool directory?
   10.80 +          + 3.4 How do I make the IMAP server look for secondary folders
   10.81 +            at some place other than the user's home directory?
   10.82 +          + 3.5 How do I configure SSL?
   10.83 +          + 3.6 How do I configure TLS and the STARTTLS facility?
   10.84 +          + 3.7 How do I build/install OpenSSL and obtain/create
   10.85 +            certificates for use with SSL?
   10.86 +          + 3.8 How do I configure CRAM-MD5 authentication?
   10.87 +          + 3.9 How do I configure APOP authentication?
   10.88 +          + 3.10 How do I configure Kerberos V5?
   10.89 +          + 3.11 How do I configure PAM for plaintext passwords?
   10.90 +          + 3.12 It looks like all I have to do to make the server use
   10.91 +            Kerberos is to build with PAM on my Linux system, and set it
   10.92 +            up in PAM for Kerberos passwords. Right?
   10.93 +          + 3.13 How do I configure Kerberos 5 for plaintext passwords?
   10.94 +          + 3.14 How do I configure AFS for plaintext passwords?
   10.95 +          + 3.15 How do I configure DCE for plaintext passwords?
   10.96 +          + 3.16 How do I configure the CRAM-MD5 database for plaintext
   10.97 +            passwords?
   10.98 +          + 3.17 How do I disable plaintext passwords?
   10.99 +          + 3.18 How do I disable plaintext passwords on unencrypted
  10.100 +            sessions, but allow them in SSL or TLS sessions?
  10.101 +          + 3.19 How do I configure virtual hosts?
  10.102 +          + 3.20 Why do I get compiler warning messages such as:
  10.103 +               o passing arg 3 of `scandir' from incompatible pointer
  10.104 +                 type
  10.105 +               o Pointers are not assignment-compatible.
  10.106 +               o Argument #4 is not the correct type.
  10.107 +            during the build?
  10.108 +          + 3.21 Why do I get compiler warning messages such as
  10.109 +               o Operation between types "void(*)(int)" and "void*" is
  10.110 +                 not allowed.
  10.111 +               o Function argument assignment between types "void*" and
  10.112 +                 "void(*)(int)" is not allowed.
  10.113 +               o Pointers are not assignment-compatible.
  10.114 +               o Argument #5 is not the correct type.
  10.115 +            during the build?
  10.116 +          + 3.22 Why do I get linker warning messages such as:
  10.117 +               o mtest.c:515: the `gets' function is dangerous and should
  10.118 +                 not be used.
  10.119 +            during the build? Isn't this a security bug?
  10.120 +          + 3.23 Why do I get linker warning messages such as:
  10.121 +               o auth_ssl.c:92: the `tmpnam' function is dangerous and
  10.122 +                 should not be used.
  10.123 +            during the build? Isn't this a security bug?
  10.124 +          + 3.24 OK, suppose I see a warning message about a function
  10.125 +            being "dangerous and should not be used" for something other
  10.126 +            than this gets() or tmpnam() call?
  10.127 +     * 4. Operational Questions
  10.128 +          + 4.1 How can I enable anonymous IMAP logins?
  10.129 +          + 4.2 How do I set up an alert message that each IMAP user will
  10.130 +            see?
  10.131 +          + 4.3 How does the c-client library choose which of its several
  10.132 +            mechanisms to use to establish an IMAP connection to the
  10.133 +            server? I noticed that it can connect on port 143, port 993,
  10.134 +            via rsh, and via ssh.
  10.135 +          + 4.4 I am using a TLS-capable IMAP server, so I don't need to
  10.136 +            use /ssl to get encryption. However, I want to be certain
  10.137 +            that my session is TLS encrypted before I send my password.
  10.138 +            How to I do this?
  10.139 +          + 4.5 How do I use one of the alternative formats described in
  10.140 +            the formats.txt document? In particular, I hear that mbx
  10.141 +            format will give me better performance and allow shared
  10.142 +            access.
  10.143 +          + 4.6 How do I set up shared mailboxes?
  10.144 +          + 4.7 How can I make the server syslogs go to someplace other
  10.145 +            than the mail syslog?
  10.146 +     * 5. Security Questions
  10.147 +          + 5.1 I see that the IMAP server allows access to arbitary
  10.148 +            files on the system, including /etc/passwd! How do I disable
  10.149 +            this?
  10.150 +          + 5.2 I've heard that IMAP servers are insecure. Is this true?
  10.151 +          + 5.3 How do I know that I have the most secure version of the
  10.152 +            server?
  10.153 +          + 5.4 I see all these strcpy() and sprintf() calls, those are
  10.154 +            unsafe, aren't they?
  10.155 +          + 5.5 Those /tmp lock files are protected 666, is that really
  10.156 +            right?
  10.157 +     * 6. Why Did You Do This Strange Thing? Questions
  10.158 +          + 6.1 Why don't you use GNU autoconfig / automake /
  10.159 +            autoblurdybloop?
  10.160 +          + 6.2 Why do you insist upon a build with -g? Doesn't it waste
  10.161 +            disk and memory space?
  10.162 +          + 6.3 Why don't you make c-client a shared library?
  10.163 +          + 6.4 Why don't you use iconv() for internationalization
  10.164 +            support?
  10.165 +          + 6.5 Why is the IMAP server connected to the home directory by
  10.166 +            default?
  10.167 +          + 6.6 I have a Windows system. Why isn't the server plug and
  10.168 +            play for me?
  10.169 +          + 6.7 I looked at the UNIX SSL code and saw that you have the
  10.170 +            SSL data payload size set to 8192 bytes. SSL allows 16K; why
  10.171 +            aren't you using the full size?
  10.172 +          + 6.8 Why is an mh format INBOX called #mhinbox instead of just
  10.173 +            INBOX?
  10.174 +          + 6.9 Why don't you support the maildir format?
  10.175 +          + 6.10 Why don't you support the Cyrus format?
  10.176 +          + 6.11 Why is it creating extra forks on my SVR4 system?
  10.177 +          + 6.12 Why are you so fussy about the date/time format in the
  10.178 +            internal "From " line in traditional UNIX mailbox files? My
  10.179 +            other mail program just considers every line that starts with
  10.180 +            "From " to be the start of the message.
  10.181 +          + 6.13 Why is traditional UNIX format the default format?
  10.182 +          + 6.14 Why do you write this "DON'T DELETE THIS MESSAGE --
  10.183 +            FOLDER INTERNAL DATA" message at the start of traditional
  10.184 +            UNIX and MMDF format mailboxes?
  10.185 +          + 6.15 Why don't you stash the mailbox metadata in the first
  10.186 +            real message of the mailbox instead of writing this fake
  10.187 +            FOLDER INTERNAL DATA message?
  10.188 +          + 6.16 Why aren't "dual-use" mailboxes the default?
  10.189 +          + 6.17 Why do you use ucbcc to build on Solaris?
  10.190 +          + 6.18 Why should I care about some old system with BSD
  10.191 +            libraries? cc is the right thing on my Solaris system!
  10.192 +          + 6.19 Why do you insist upon writing .lock files in the spool
  10.193 +            directory?
  10.194 +          + 6.20 Why should I care about compatibility with the past?
  10.195 +     * 7. Problems and Annoyances
  10.196 +          + 7.1 Help! My INBOX is empty! What happened to my messages?
  10.197 +          + 7.2 Help! All my messages in a non-INBOX mailbox have been
  10.198 +            concatenated into one message which claims to be from me and
  10.199 +            has a subject of the file name of the mailbox! What's going
  10.200 +            on?
  10.201 +          + 7.3 Why do I get the message:
  10.202 +               o CREATE failed: Can't create mailbox node xxxxxxxxx: File
  10.203 +                 exists
  10.204 +            and how do I fix it?
  10.205 +          + 7.4 Why can't I log in to the server? The user name and
  10.206 +            password are right!
  10.207 +          + 7.5 Help! My load average is soaring and I see hundreds of
  10.208 +            POP and IMAP servers, many logged in as the same user!
  10.209 +          + 7.6 Why does mail disappear even though I set "keep mail on
  10.210 +            server"?
  10.211 +          + 7.7 Why do I get the message
  10.212 +               o Moved ##### bytes of new mail to /home/user/mbox from
  10.213 +                 /var/spool/mail/user
  10.214 +            and why did this happen?
  10.215 +          + 7.8 Why isn't it showing the local host name as a
  10.216 +            fully-qualified domain name?
  10.217 +          + 7.9 Why is the local host name in the From/Sender/Message-ID
  10.218 +            headers of outgoing mail not coming out as a fully-qualified
  10.219 +            domain name?
  10.220 +          + 7.10 What does the message:
  10.221 +               o Mailbox vulnerable - directory /var/spool/mail must have
  10.222 +                 1777 protection
  10.223 +            mean? How can I fix this?
  10.224 +          + 7.11 What does the message:
  10.225 +               o Mailbox is open by another process, access is readonly
  10.226 +            mean? How do I fix this?
  10.227 +          + 7.12 What does the message:
  10.228 +               o Can't get write access to mailbox, access is readonly
  10.229 +            mean?
  10.230 +          + 7.13 I set my POP3 client to "delete messages from server"
  10.231 +            but they never get deleted. What is wrong?
  10.232 +          + 7.14 What do messages such as:
  10.233 +               o Message ... UID ... already has UID ...
  10.234 +               o Message ... UID ... less than ...
  10.235 +               o Message ... UID ... greater than last ...
  10.236 +               o Invalid UID ... in message ..., rebuilding UIDs
  10.237 +            mean?
  10.238 +          + 7.15 What do the error messages:
  10.239 +               o Unable to read internal header at ...
  10.240 +               o Unable to find CRLF at ...
  10.241 +               o Unable to parse internal header at ...
  10.242 +               o Unable to parse message date at ...
  10.243 +               o Unable to parse message flags at ...
  10.244 +               o Unable to parse message UID at ...
  10.245 +               o Unable to parse message size at ...
  10.246 +               o Last message (at ... ) runs past end of file ...
  10.247 +            mean? I am using mbx format.
  10.248 +          + 7.16 What do the syslog messages:
  10.249 +               o imap/tcp server failing (looping)
  10.250 +               o pop3/tcp server failing (looping)
  10.251 +            mean? When it happens, the listed service shuts down. How can
  10.252 +            I fix this?
  10.253 +          + 7.17 What does the syslog message:
  10.254 +               o Mailbox lock file /tmp/.600.1df3 open failure:
  10.255 +                 Permission denied
  10.256 +            mean?
  10.257 +          + 7.18 What do the syslog messages:
  10.258 +               o Command stream end of file, while reading line user=...
  10.259 +                 host=...
  10.260 +               o Command stream end of file, while reading char user=...
  10.261 +                 host=...
  10.262 +               o Command stream end of file, while writing text user=...
  10.263 +                 host=...
  10.264 +            mean?
  10.265 +          + 7.19 Why did my POP or IMAP session suddenly disconnect? The
  10.266 +            syslog has the message:
  10.267 +               o Killed (lost mailbox lock) user=... host=...
  10.268 +          + 7.20 Why does my IMAP client show all the files on the
  10.269 +            system, recursively from the UNIX root directory?
  10.270 +          + 7.21 Why does my IMAP client show all of my files,
  10.271 +            recursively from my UNIX home directory?
  10.272 +          + 7.22 Why does my IMAP client show that I have mailboxes named
  10.273 +            "#mhinbox", "#mh", "#shared", "#ftp", "#news", and "#public"?
  10.274 +          + 7.23 Why does my IMAP client show all my files in my home
  10.275 +            directory?
  10.276 +          + 7.24 Why is there a long delay before I get connected to the
  10.277 +            IMAP or POP server, no matter what client I use?
  10.278 +          + 7.25 Why is there a long delay in Pine or any other c-client
  10.279 +            based application call before I get connected to the IMAP
  10.280 +            server? The hang seems to be in the c-client mail_open()
  10.281 +            call. I don't have this problem with any other IMAP client.
  10.282 +            There is no delay connecting to a POP3 or NNTP server with
  10.283 +            mail_open().
  10.284 +          + 7.26 Why does a message sometimes get split into two or more
  10.285 +            messages on my SUN system?
  10.286 +          + 7.27 Why did my POP or IMAP session suddenly disconnect? The
  10.287 +            syslog has the message:
  10.288 +               o Autologout user=<...my user name...> host=<...my imap
  10.289 +                 server...>
  10.290 +          + 7.28 What does the UNIX error message:
  10.291 +               o TLS/SSL failure: myserver: SSL negotiation failed
  10.292 +            mean?
  10.293 +          + 7.29 What does the PC error message:
  10.294 +               o TLS/SSL failure: myserver: Unexpected TCP input
  10.295 +                 disconnect
  10.296 +            mean?
  10.297 +          + 7.30 What does the error message:
  10.298 +               o TLS/SSL failure: myserver: Server name does not match
  10.299 +                 certificate
  10.300 +            mean?
  10.301 +          + 7.31 What does the UNIX error message:
  10.302 +               o TLS/SSL failure: myserver: self-signed certificate
  10.303 +            mean?
  10.304 +          + 7.32 What does the PC error message
  10.305 +               o TLS/SSL failure: myserver: Self-signed certificate or
  10.306 +                 untrusted authority
  10.307 +            mean?
  10.308 +          + 7.33 What does the UNIX error message:
  10.309 +               o TLS/SSL failure: myserver: unable to get local issuer
  10.310 +                 certificate
  10.311 +            mean?
  10.312 +          + 7.34 Why does reading certain messages hang when using
  10.313 +            Netscape? It works fine with Pine!
  10.314 +          + 7.35 Why does Netscape say that there's a problem with the
  10.315 +            IMAP server and that I should "Contact your mail server
  10.316 +            administrator."?
  10.317 +          + 7.36 Why is one user creating huge numbers of IMAP or POP
  10.318 +            server sessions?
  10.319 +          + 7.37 Why don't I get any new mail notifications from Outlook
  10.320 +            Express or Outlook after a while?
  10.321 +          + 7.38 Why don't I get any new mail notifications from
  10.322 +            Entourage?
  10.323 +          + 7.39 Why doesn't Entourage work at all?
  10.324 +          + 7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE) work at all?
  10.325 +          + 7.41 Why can't I connect via SSL to Eudora? It says the
  10.326 +            connection has been broken, and in the server syslogs I see
  10.327 +            "Command stream end of file".
  10.328 +          + 7.42 Sheesh. Aren't there any good IMAP clients out there?
  10.329 +          + 7.43 But wait! PC Pine (or other PC program build with
  10.330 +            c-client) crashes with the message
  10.331 +               o incomplete SecBuffer exceeds maximum buffer size
  10.332 +            when I use SSL connections. This is a bug in c-client, right?
  10.333 +          + 7.44 My qpopper users keep on getting the DON'T DELETE THIS
  10.334 +            MESSAGE -- FOLDER INTERNAL DATA if they also use Pine or
  10.335 +            IMAP. How can I fix this?
  10.336 +          + 7.45 Help! I installed the servers but I can't connect to
  10.337 +            them from my client!
  10.338 +          + 7.46 Why do I get the message
  10.339 +               o Can not authenticate to SMTP server: 421 SMTP connection
  10.340 +                 went away!
  10.341 +            and why did this happen? There was also something about
  10.342 +               o SECURITY PROBLEM: insecure server advertised AUTH=PLAIN
  10.343 +          + 7.47 Why do I get the message
  10.344 +               o SMTP Authentication cancelled
  10.345 +            and why did this happen? There was also something about
  10.346 +               o SECURITY PROBLEM: insecure server advertised AUTH=PLAIN
  10.347 +          + 7.48 Why do I get the message
  10.348 +               o Invalid base64 string
  10.349 +            when I try to authenticate to a Cyrus server?
  10.350 +     * 8. Where to Go For Additional Information
  10.351 +          + 8.1 Where can I go to ask questions?
  10.352 +          + 8.2 I have some ideas for enhancements to IMAP. Where should
  10.353 +            I go?
  10.354 +          + 8.3 Where can I read more about IMAP and other email
  10.355 +            protocols?
  10.356 +          + 8.4 Where can I find out more about setting up and
  10.357 +            administering an IMAP server?
  10.358 +     _________________________________________________________________
  10.359 +
  10.360 +1. General/Software Feature Questions
  10.361 +     _________________________________________________________________
  10.362 +
  10.363 +   1.1 Can I set up a POP or IMAP server on UNIX/Linux/OSF/etc.?
  10.364 +
  10.365 +          Yes. Refer to the UNIX specific notes in files CONFIG and
  10.366 +          BUILD.
  10.367 +     _________________________________________________________________
  10.368 +
  10.369 +   1.2 I am currently using qpopper as my POP3 server on UNIX. Do I need
  10.370 +   to replace it with ipop3d in order to run imapd?
  10.371 +
  10.372 +          Not necessarily.
  10.373 +
  10.374 +          Although ipop3d interoperates with imapd better than qpopper,
  10.375 +          imapd and qpopper will work together. The few qpopper/imapd
  10.376 +          interoperability issues mostly affect users who use both IMAP
  10.377 +          and POP3 clients; those users would probably be better served
  10.378 +          if their POP3 server is ipop3d.
  10.379 +
  10.380 +          If you are happy with qpopper and just want to add imapd, you
  10.381 +          should do that, and defer a decision on changing qpopper to
  10.382 +          ipop3d. That way, you can get comfortable with imapd's
  10.383 +          performance, without changing anything for your qpopper users.
  10.384 +
  10.385 +          Many sites have subsequently decided to change from qpopper to
  10.386 +          ipop3d in order to get better POP3/IMAP interoperability. If
  10.387 +          you need to do this, you'll know. There also seems to be a way
  10.388 +          to make qpopper work better with imapd; see the answer to the
  10.389 +          My qpopper users keep on getting the DON'T DELETE THIS MESSAGE
  10.390 +          -- FOLDER INTERNAL DATA if they also use Pine or IMAP. How can
  10.391 +          I fix this? question.
  10.392 +     _________________________________________________________________
  10.393 +
  10.394 +   1.3 Can I set up a POP or IMAP server on Windows XP, 2000, NT, Me, 98,
  10.395 +   or 95?
  10.396 +
  10.397 +          Yes. Refer to the NT specific notes in files CONFIG and BUILD.
  10.398 +          Also, for DOS-based versions of Windows (Windows Me, 98, and
  10.399 +          95) you *must* set up CRAM-MD5 authentication, as described in
  10.400 +          md5.txt.
  10.401 +
  10.402 +          There is no file access control on Windows 9x or Me, so you
  10.403 +          probably will have to do modifications to env_unix.c to prevent
  10.404 +          people from hacking others' mail.
  10.405 +
  10.406 +          Note, however, that the server is not plug and play the way it
  10.407 +          is for UNIX.
  10.408 +     _________________________________________________________________
  10.409 +
  10.410 +   1.4 Can I set up a POP or IMAP server on Windows 3.1 or DOS?
  10.411 +   1.5 Can I set up a POP or IMAP server on Macintosh?
  10.412 +   1.6 Can I set up a POP or IMAP server on VAX/VMS?
  10.413 +
  10.414 +          Yes, it's just a small matter of programming.
  10.415 +     _________________________________________________________________
  10.416 +
  10.417 +   1.7 Can I set up a POP or IMAP server on TOPS-20?
  10.418 +
  10.419 +          You have a TOPS-20 system? Cool.
  10.420 +
  10.421 +          If IMAP2 (RFC 1176) is good enough for you, you can use MAPSER
  10.422 +          which is about the ultimate gonzo pure TOPS-20 extended
  10.423 +          addressing assembly language program. Unfortunately, IMAP2 is
  10.424 +          barely good enough for Pine these days, and most other IMAP
  10.425 +          clients won't work with IMAP2 at all. Maybe someone will hack
  10.426 +          MAPSER to do IMAP4rev1 some day.
  10.427 +
  10.428 +          We don't know if anyone wrote a POP3 server for TOPS-20. There
  10.429 +          definitely was a POP2 server once upon a time.
  10.430 +
  10.431 +          Or you can port the POP and IMAP server from this IMAP toolkit
  10.432 +          to it. All that you need for a first stab is to port the MTX
  10.433 +          driver. That'll probably be just a couple of hours of hacking.
  10.434 +     _________________________________________________________________
  10.435 +
  10.436 +   1.8 Are hierarchical mailboxes supported?
  10.437 +   1.9 Are "dual-use" mailboxes supported?
  10.438 +   1.10 Can I have a mailbox that has both messages and sub-mailboxes?
  10.439 +
  10.440 +          Yes. However, there is one important caveat.
  10.441 +
  10.442 +          Some mailbox formats, including the default which is the
  10.443 +          traditional UNIX mailbox format, are stored as a single file
  10.444 +          containing all the messages. UNIX does not permit a name in the
  10.445 +          filesystem to be both a file and a directory; consequently you
  10.446 +          can not have a sub-mailbox within a mailbox that is in one of
  10.447 +          these formats.
  10.448 +
  10.449 +          This is not a limitation of the software; this is a limitation
  10.450 +          of UNIX. For example, there are mailbox formats in which the
  10.451 +          name is a directory and each message is a file within that
  10.452 +          directory; these formats support sub-mailboxes within such
  10.453 +          mailboxes. However, for technical reasons, the "flat file"
  10.454 +          formats are generally preferred since they perform better. Read
  10.455 +          imap-2007/docs/formats.txt for more information on this topic.
  10.456 +
  10.457 +          It is always permissible to create a directory that is not a
  10.458 +          mailbox, and have sub-mailboxes under it. The easiest way to
  10.459 +          create a directory is to create a new mailbox inside a
  10.460 +          directory that doesn't already exist. For example, if you
  10.461 +          create "Mail/testbox" on UNIX, the directory "Mail/" will
  10.462 +          automatically be created and then the mailbox "testbox" will be
  10.463 +          created as a sub-mailbox of "Mail/".
  10.464 +
  10.465 +          It is also possible to create the name "Mail/" directly. Check
  10.466 +          the documentation for your client software to see how to do
  10.467 +          this with that software.
  10.468 +
  10.469 +          Of course, on Windows systems you would use "\" instead of "/".
  10.470 +     _________________________________________________________________
  10.471 +
  10.472 +   1.11 What is the difference between "mailbox" and "folder"?
  10.473 +
  10.474 +          The term "mailbox" is IMAP-speak for what a lot of software
  10.475 +          calls a "folder" or a "mail folder". However, "folder" is often
  10.476 +          used in other contexts to refer to a directory, for example, in
  10.477 +          the graphic user interface on both Windows and Macintosh.
  10.478 +
  10.479 +          A "mailbox" is specifically defined as a named object that
  10.480 +          contains messages. It is not required to be capable of
  10.481 +          containing other types of objects including other mailboxes;
  10.482 +          although some mailbox formats will permit this.
  10.483 +
  10.484 +          In IMAP-speak, a mailbox which can not contain other mailboxes
  10.485 +          is called a "no-inferiors mailbox". Similarly, a directory
  10.486 +          which can not contain messages is not a mailbox and is called a
  10.487 +          "no-select name".
  10.488 +     _________________________________________________________________
  10.489 +
  10.490 +   1.12 What is the status of internationalization?
  10.491 +
  10.492 +          The IMAP toolkit is partially internationalized and
  10.493 +          multilingualized.
  10.494 +
  10.495 +          Searching is supported in the following charsets: US-ASCII,
  10.496 +          UTF-8, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4,
  10.497 +          ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9,
  10.498 +          ISO-8859-10, ISO-8859-11, ISO-8859-13, ISO-8859-14,
  10.499 +          ISO-8859-15, ISO-8859-16, KOI8-R, KOI8-U (alias KOI8-RU),
  10.500 +          TIS-620, VISCII, ISO-2022-JP, ISO-2022-KR, ISO-2022-CN,
  10.501 +          ISO-2022-JP-1, ISO-2022-JP-2, GB2312 (alias CN-GB),
  10.502 +          CN-GB-12345, BIG5 (alias CN-BIG5), EUC-JP, EUC-KR, Shift_JIS,
  10.503 +          Shift-JIS, KS_C_5601-1987, KS_C_5601-1992, WINDOWS_874,
  10.504 +          WINDOWS-1250, WINDOWS-1251, WINDOWS-1252, WINDOWS-1253,
  10.505 +          WINDOWS-1254, WINDOWS-1255, WINDOWS-1256, WINDOWS-1257,
  10.506 +          WINDOWS-1258.
  10.507 +
  10.508 +          All ISO-2022-?? charsets are treated identically, and support
  10.509 +          ASCII, JIS Roman, hankaku katakana, ISO-8859-[1 - 10], TIS, GB
  10.510 +          2312, JIS X 0208, JIS X 0212, KSC 5601, and planes 1 and 2 of
  10.511 +          CNS 11643.
  10.512 +
  10.513 +          EUC-JP includes support for JIS X 0212 and hankaku katakana.
  10.514 +
  10.515 +          c-client library support also exists to convert text in any of
  10.516 +          the above charsets into Unicode, including headers with MIME
  10.517 +          encoded-words.
  10.518 +
  10.519 +          There is no support for localization (e.g. non-English error
  10.520 +          messages) at the present time, but such support is planned.
  10.521 +     _________________________________________________________________
  10.522 +
  10.523 +   1.13 Can I use SSL?
  10.524 +
  10.525 +          Yes. See the answer to the How do I configure SSL? question.
  10.526 +     _________________________________________________________________
  10.527 +
  10.528 +   1.14 Can I use TLS and the STARTTLS facility?
  10.529 +
  10.530 +          Yes. See the answer to the How do I configure TLS and the
  10.531 +          STARTTLS facility? question.
  10.532 +     _________________________________________________________________
  10.533 +
  10.534 +   1.15 Can I use CRAM-MD5 authentication?
  10.535 +
  10.536 +          Yes. See the answer to the How do I configure CRAM-MD5
  10.537 +          authentication? question.
  10.538 +     _________________________________________________________________
  10.539 +
  10.540 +   1.16 Can I use APOP authentication?
  10.541 +
  10.542 +          Yes. See the How do I configure APOP authentication? question.
  10.543 +
  10.544 +          Note that there is no client support for APOP authentication.
  10.545 +     _________________________________________________________________
  10.546 +
  10.547 +   1.17 Can I use Kerberos V5?
  10.548 +
  10.549 +          Yes. See the answer to the How do I configure Kerberos V5?
  10.550 +          question.
  10.551 +     _________________________________________________________________
  10.552 +
  10.553 +   1.18 Can I use PAM for plaintext passwords?
  10.554 +
  10.555 +          Yes. See the answer to the How do I configure PAM for plaintext
  10.556 +          passwords? question.
  10.557 +     _________________________________________________________________
  10.558 +
  10.559 +   1.19 Can I use Kerberos 5 for plaintext passwords?
  10.560 +
  10.561 +          Yes. See the answer to the How do I configure Kerberos 5 for
  10.562 +          plaintext passwords? question.
  10.563 +     _________________________________________________________________
  10.564 +
  10.565 +   1.20 Can I use AFS for plaintext passwords?
  10.566 +
  10.567 +          Yes. See the answer to the How do I configure AFS for plaintext
  10.568 +          passwords? question.
  10.569 +     _________________________________________________________________
  10.570 +
  10.571 +   1.21 Can I use DCE for plaintext passwords?
  10.572 +
  10.573 +          Yes. See the answer to the How do I configure DCE for plaintext
  10.574 +          passwords? question.
  10.575 +     _________________________________________________________________
  10.576 +
  10.577 +   1.22 Can I use the CRAM-MD5 database for plaintext passwords?
  10.578 +
  10.579 +          Yes. See the answer to the How do I configure the CRAM-MD5
  10.580 +          database for plaintext passwords? question.
  10.581 +     _________________________________________________________________
  10.582 +
  10.583 +   1.23 Can I disable plaintext passwords?
  10.584 +
  10.585 +          Yes. See the answer to the How do I disable plaintext
  10.586 +          passwords? question.
  10.587 +     _________________________________________________________________
  10.588 +
  10.589 +   1.24 Can I disable plaintext passwords on unencrypted sessions, but
  10.590 +   allow them on encrypted sessions?
  10.591 +
  10.592 +          Yes. See the answer to the How do I disable plaintext passwords
  10.593 +          on unencrypted sessions, but allow them in SSL or TLS sessions?
  10.594 +          question.
  10.595 +     _________________________________________________________________
  10.596 +
  10.597 +   1.25 Can I use virtual hosts?
  10.598 +
  10.599 +          Yes. See the answer to the How do I configure virtual hosts?
  10.600 +          question.
  10.601 +     _________________________________________________________________
  10.602 +
  10.603 +   1.26 Can I use RPOP authentication?
  10.604 +
  10.605 +          There is no support for RPOP authentication.
  10.606 +     _________________________________________________________________
  10.607 +
  10.608 +   1.27 Can I use Kerberos V4?
  10.609 +
  10.610 +          Kerberos V4 is not supported. Kerberos V4 client-only
  10.611 +          contributed code is available in
  10.612 +
  10.613 +ftp://ftp.cac.washington.edu/mail/kerberos4-patches.tar.Z
  10.614 +
  10.615 +          This is a patchkit which must be applied to the IMAP toolkit
  10.616 +          according to the instructions in the patchkit's README. We can
  10.617 +          not promise that this code works.
  10.618 +     _________________________________________________________________
  10.619 +
  10.620 +   1.28 Is there support for S/Key or OTP?
  10.621 +
  10.622 +          There is currently no support for S/Key or OTP. There may be an
  10.623 +          OTP SASL authenticator available from third parties.
  10.624 +     _________________________________________________________________
  10.625 +
  10.626 +   1.29 Is there support for NTLM or SPA?
  10.627 +
  10.628 +          There is currently no support for NTLM or SPA, nor are there
  10.629 +          any plans to add such support. In general, I avoid
  10.630 +          vendor-specific mechanisms. I also believe that these
  10.631 +          mechanisms are being deprecated by their vendor.
  10.632 +
  10.633 +          There may be an NTLM SASL authenticator available from third
  10.634 +          parties.
  10.635 +     _________________________________________________________________
  10.636 +
  10.637 +   1.30 Is there support for mh?
  10.638 +
  10.639 +          Yes, but only as a legacy format. Your mh format INBOX is
  10.640 +          accessed by the name "#mhinbox", and all other mh format
  10.641 +          mailboxes are accessed by prefixing "#mh/" to the name, e.g.
  10.642 +          "#mh/foo". The mh support uses the "Path:" entry in your
  10.643 +          .mh_profile file to identify the root directory of your mh
  10.644 +          format mailboxes.
  10.645 +
  10.646 +          Non-legacy use of mh format is not encouraged. There is no
  10.647 +          support for permanent flags or unique identifiers; furthermore
  10.648 +          there are known severe performance problems with the mh format.
  10.649 +     _________________________________________________________________
  10.650 +
  10.651 +   1.31 Is there support for qmail and the maildir format?
  10.652 +
  10.653 +          There is no support for qmail or the maildir format in our
  10.654 +          distribution, nor are there any plans to add such support.
  10.655 +          Maildir support may be available from third parties.
  10.656 +     _________________________________________________________________
  10.657 +
  10.658 +   1.32 Is there support for the Cyrus mailbox format?
  10.659 +
  10.660 +          No.
  10.661 +     _________________________________________________________________
  10.662 +
  10.663 +   1.33 Is this software Y2K compliant?
  10.664 +
  10.665 +          Please read the files Y2K and calendar.txt.
  10.666 +     _________________________________________________________________
  10.667 +
  10.668 +2. What Do I Need to Build This Software?
  10.669 +     _________________________________________________________________
  10.670 +
  10.671 +   2.1 What do I need to build this software with SSL on UNIX?
  10.672 +
  10.673 +          You need to build and install OpenSSL first.
  10.674 +     _________________________________________________________________
  10.675 +
  10.676 +   2.2 What do I need to build this software with Kerberos V on UNIX?
  10.677 +
  10.678 +          You need to build and install MIT Kerberos first.
  10.679 +     _________________________________________________________________
  10.680 +
  10.681 +   2.3 What do I need to use a C++ compiler with this software to build
  10.682 +   my own application?
  10.683 +
  10.684 +          If you are building an application using the c-client library,
  10.685 +          use the new c-client.h file instead of including the other
  10.686 +          include files. It seems that c-client.h should define away all
  10.687 +          the troublesome names that conflict with C++.
  10.688 +
  10.689 +          If you use gcc, you may need to use -fno-operator-names as
  10.690 +          well.
  10.691 +     _________________________________________________________________
  10.692 +
  10.693 +   2.4 What do I need to build this software on Windows?
  10.694 +
  10.695 +          You need Microsoft Visual C++ 6.0, Visual C++ .NET, or Visual
  10.696 +          C# .NET (which you can buy from any computer store), along with
  10.697 +          the Microsoft Platform SDK (which you can download from
  10.698 +          Microsoft's web site).
  10.699 +
  10.700 +          You do not need to install the entire Platform SDK; it suffices
  10.701 +          to install just the Core SDK and the Internet Development SDK.
  10.702 +     _________________________________________________________________
  10.703 +
  10.704 +   2.5 What do I need to build this software on DOS?
  10.705 +
  10.706 +          It's been several years since we last attempted to do this. At
  10.707 +          the time, we used Microsoft C.
  10.708 +     _________________________________________________________________
  10.709 +
  10.710 +   2.6 Can't I use Borland C to build this software on the PC?
  10.711 +
  10.712 +          Probably not. If you know otherwise, please let us know.
  10.713 +     _________________________________________________________________
  10.714 +
  10.715 +   2.7 What do I need to build this software on the Mac?
  10.716 +
  10.717 +          It has been several years since we last attempted to do this.
  10.718 +          At the time, we used Symantec THINK C; but today you'll need a
  10.719 +          C compiler which allows segments to be more than 32K.
  10.720 +     _________________________________________________________________
  10.721 +
  10.722 +   2.8 What do I need to build this software on VMS?
  10.723 +
  10.724 +          You need the VMS C compiler, and either the Multinet or Netlib
  10.725 +          TCP.
  10.726 +     _________________________________________________________________
  10.727 +
  10.728 +   2.9 What do I need to build this software on TOPS-20?
  10.729 +
  10.730 +          You need the TOPS-20 KCC compiler.
  10.731 +     _________________________________________________________________
  10.732 +
  10.733 +   2.10 What do I need to build this software on Amiga or OS/2?
  10.734 +
  10.735 +          We don't know.
  10.736 +     _________________________________________________________________
  10.737 +
  10.738 +   2.11 What do I need to build this software on Windows CE?
  10.739 +
  10.740 +          This port is incomplete. Someone needs to finish it.
  10.741 +     _________________________________________________________________
  10.742 +
  10.743 +3. Build and Configuration Questions
  10.744 +     _________________________________________________________________
  10.745 +
  10.746 +   3.1 How do I configure the IMAP and POP servers on UNIX?
  10.747 +   3.2 I built and installed the servers according to the BUILD
  10.748 +   instructions. It can't be that easy. Don't I need to write a config
  10.749 +   file?
  10.750 +
  10.751 +          For ordinary "vanilla" UNIX systems, this software is plug and
  10.752 +          play; just build it, install it, and you're done. If you have a
  10.753 +          modified system, then you may want to do additional work; most
  10.754 +          of this is to a single source code file (env_unix.c on UNIX
  10.755 +          systems). Read the file CONFIG for more details.
  10.756 +
  10.757 +          Yes, it's that easy. There are some additional options, such as
  10.758 +          SSL or Kerberos, which require additional steps to build. See
  10.759 +          the relevant questions below.
  10.760 +     _________________________________________________________________
  10.761 +
  10.762 +   3.3 How do I make the IMAP and POP servers look for INBOX at some
  10.763 +   place other than the mail spool directory?
  10.764 +   3.4 How do I make the IMAP server look for secondary folders at some
  10.765 +   place other than the user's home directory?
  10.766 +
  10.767 +          Please read the file CONFIG for discussion of this and other
  10.768 +          issues.
  10.769 +     _________________________________________________________________
  10.770 +
  10.771 +   3.5 How do I configure SSL?
  10.772 +   3.6 How do I configure TLS and the STARTTLS facility?
  10.773 +
  10.774 +          imap-2007 supports SSL and TLS client functionality on UNIX and
  10.775 +          32-bit Windows for IMAP, POP3, SMTP, and NNTP; and SSL and TLS
  10.776 +          server functionality on UNIX for IMAP and POP3.
  10.777 +
  10.778 +          UNIX SSL build requires that a third-party software package,
  10.779 +          OpenSSL, be installed on the system first. Read
  10.780 +          imap-2007/docs/SSLBUILD for more information.
  10.781 +
  10.782 +          SSL is supported via undocumented Microsoft interfaces in
  10.783 +          Windows 9x and NT4; and via standard interfaces in Windows
  10.784 +          2000, Windows Millenium, and Windows XP.
  10.785 +     _________________________________________________________________
  10.786 +
  10.787 +   3.7 How do I build/install OpenSSL and obtain/create certificates for
  10.788 +   use with SSL?
  10.789 +
  10.790 +          If you need help in doing this, try the contacts mentioned in
  10.791 +          the OpenSSL README. We do not offer support for OpenSSL or
  10.792 +          certificates.
  10.793 +     _________________________________________________________________
  10.794 +
  10.795 +   3.8 How do I configure CRAM-MD5 authentication?
  10.796 +   3.9 How do I configure APOP authentication?
  10.797 +
  10.798 +          CRAM-MD5 authentication is enabled in the IMAP and POP3 client
  10.799 +          code on all platforms. Read md5.txt to learn how to set up
  10.800 +          CRAM-MD5 and APOP authentication on UNIX and NT servers.
  10.801 +
  10.802 +          There is no support for APOP client authentication.
  10.803 +     _________________________________________________________________
  10.804 +
  10.805 +   3.10 How do I configure Kerberos V5?
  10.806 +
  10.807 +          imap-2007 supports client and server functionality on UNIX and
  10.808 +          32-bit Windows.
  10.809 +
  10.810 +          Kerberos V5 is supported by default in Windows 2000 builds:
  10.811 +
  10.812 + nmake -f makefile.w2k
  10.813 +
  10.814 +          Other builds require that a third-party Kerberos package, e.g.
  10.815 +          MIT Kerberos, be installed on the system first.
  10.816 +
  10.817 +          To build with Kerberos V5 on UNIX, include
  10.818 +          EXTRAAUTHENTICATORS=gss in the make command line, e.g.
  10.819 +
  10.820 + make lnp EXTRAAUTHENTICATORS=gss
  10.821 +
  10.822 +          To build with Kerberos V5 on Windows 9x, Windows Millenium, and
  10.823 +          NT4, use the "makefile.ntk" file instead of "makefile.nt":
  10.824 +
  10.825 +
  10.826 + nmake -f makefile.ntk
  10.827 +     _________________________________________________________________
  10.828 +
  10.829 +   3.11 How do I configure PAM for plaintext passwords?
  10.830 +
  10.831 +          On Linux systems, use the lnp port, e.g.
  10.832 +
  10.833 + make lnp
  10.834 +
  10.835 +          On Solaris systems and other systems with defective PAM
  10.836 +          implementations, build with PASSWDTYPE=pmb, e.g.
  10.837 +
  10.838 + make sol PASSWDTYPE=pmb
  10.839 +
  10.840 +          On all other systems, build with PASSWDTYPE=pam, e.g
  10.841 +
  10.842 + make foo PASSWDTYPE=pam
  10.843 +
  10.844 +          If you build with PASSWDTYPE=pam and authentication does not
  10.845 +          work, try rebuilding (after a "make clean") with
  10.846 +          PASSWDTYPE=pmb.
  10.847 +     _________________________________________________________________
  10.848 +
  10.849 +   3.12 It looks like all I have to do to make the server use Kerberos is
  10.850 +   to build with PAM on my Linux system, and set it up in PAM for
  10.851 +   Kerberos passwords. Right?
  10.852 +
  10.853 +          Yes and no.
  10.854 +
  10.855 +          Doing this will make plaintext password authentication use the
  10.856 +          Kerberos password instead of the /etc/passwd password.
  10.857 +
  10.858 +          However, this will NOT give you Kerberos-secure authentication.
  10.859 +          See the answer to the How do I configure Kerberos V5? question
  10.860 +          for how to build with Kerberos-secure authentication.
  10.861 +     _________________________________________________________________
  10.862 +
  10.863 +   3.13 How do I configure Kerberos 5 for plaintext passwords?
  10.864 +
  10.865 +          Build with PASSWDTYPE=gss, e.g.
  10.866 +
  10.867 + make sol PASSWDTYPE=gss
  10.868 +
  10.869 +          However, this will NOT give you Kerberos-secure authentication.
  10.870 +          See the answer to the How do I configure Kerberos V5? question
  10.871 +          for how to build with Kerberos-secure authentication.
  10.872 +     _________________________________________________________________
  10.873 +
  10.874 +   3.14 How do I configure AFS for plaintext passwords?
  10.875 +
  10.876 +          Build with PASSWDTYPE=afs, e.g
  10.877 +
  10.878 + make sol PASSWDTYPE=afs
  10.879 +     _________________________________________________________________
  10.880 +
  10.881 +   3.15 How do I configure DCE for plaintext passwords?
  10.882 +
  10.883 +          Build with PASSWDTYPE=dce, e.g
  10.884 +
  10.885 + make sol PASSWDTYPE=dce
  10.886 +     _________________________________________________________________
  10.887 +
  10.888 +   3.16 How do I configure the CRAM-MD5 database for plaintext passwords?
  10.889 +
  10.890 +          The CRAM-MD5 password database is automatically used for
  10.891 +          plaintext password if it exists.
  10.892 +
  10.893 +          Note that this is NOT CRAM-MD5-secure authentication. You
  10.894 +          probably want to consider disabling plaintext passwords for
  10.895 +          non-SSL/TLS sessions. See the next two questions.
  10.896 +     _________________________________________________________________
  10.897 +
  10.898 +   3.17 How do I disable plaintext passwords?
  10.899 +
  10.900 +          Server-level plaintext passwords can be disabled by setting
  10.901 +          PASSWDTYPE=nul, e.g.
  10.902 +
  10.903 + make lnx EXTRAAUTHENTICATORS=gss PASSWDTYPE=nul
  10.904 +
  10.905 +          Note that you must have a CRAM-MD5 database installed or
  10.906 +          specify at least one EXTRAAUTHENTICATOR, otherwise it will not
  10.907 +          be possible to log in to the server.
  10.908 +
  10.909 +          When plaintext passwords are disabled, the IMAP server will
  10.910 +          advertise the LOGINDISABLED capability and the POP3 server will
  10.911 +          not advertise the USER capability.
  10.912 +
  10.913 +   3.18 How do I disable plaintext passwords on unencrypted sessions, but
  10.914 +   allow them in SSL or TLS sessions?
  10.915 +
  10.916 +          Do not set PASSWDTYPE=nul or SSLTYPE=unix. Set SSLTYPE=nopwd
  10.917 +          instead, e.g.
  10.918 +
  10.919 + make lnx SSLTYPE=nopwd
  10.920 +
  10.921 +          When plaintext passwords are disabled, the IMAP server will
  10.922 +          advertise the LOGINDISABLED capability and the POP3 server will
  10.923 +          not advertise the USER capability.
  10.924 +
  10.925 +          Plaintext passwords will always be enabled in SSL sessions; the
  10.926 +          IMAP server will not advertise the LOGINDISABLED capability and
  10.927 +          the POP3 server will advertise the USER capability.
  10.928 +
  10.929 +          If the client does a successful start-TLS in a non-SSL session,
  10.930 +          plaintext passwords will be enabled, and a new CAPABILITY or
  10.931 +          CAPA command (which is required after start-TLS) will show the
  10.932 +          effect as in SSL sessions.
  10.933 +     _________________________________________________________________
  10.934 +
  10.935 +   3.19 How do I configure virtual hosts?
  10.936 +
  10.937 +          This is automatic, but with certain restrictions.
  10.938 +
  10.939 +          The most important one is that each virtual host must have its
  10.940 +          own IP address; otherwise the server has no way of knowing
  10.941 +          which virtual host is desired.
  10.942 +
  10.943 +          As distributed, the software uses a global password file; hence
  10.944 +          user "fred" on one virtual host is "fred" on all virtual hosts.
  10.945 +          You may want to modify the checkpw() routine to implement some
  10.946 +          other policy (e.g. separate password files).
  10.947 +
  10.948 +          Note that the security model assumes that all users have their
  10.949 +          own unique UNIX UID number. So if you use separate password
  10.950 +          files you should make certain that the UID numbers do not
  10.951 +          overlap between different files.
  10.952 +
  10.953 +          More advanced virtual host support may be available as patches
  10.954 +          from third parties.
  10.955 +     _________________________________________________________________
  10.956 +
  10.957 +   3.20 Why do I get compiler warning messages such as:
  10.958 + passing arg 3 of `scandir' from incompatible pointer type
  10.959 + Pointers are not assignment-compatible.
  10.960 + Argument #4 is not the correct type.
  10.961 +
  10.962 +   during the build?
  10.963 +
  10.964 +          You can safely ignore these messages.
  10.965 +
  10.966 +          Over the years, the prototype for scandir() has changed, and
  10.967 +          thus is variant across different UNIX platforms. In particular,
  10.968 +          the definitions of the third argument (type select_t) and
  10.969 +          fourth argument (type compar_t) have changed over the years,
  10.970 +          the issue being whether or not the arguments to the functions
  10.971 +          pointed to by these function pointers are of type const or not.
  10.972 +
  10.973 +          The way that c-client calls scandir() will tend to generate
  10.974 +          these compiler warnings on newer systems such as Linux;
  10.975 +          however, it will still build. The problem with fixing the call
  10.976 +          is that then it won't build on older systems.
  10.977 +     _________________________________________________________________
  10.978 +
  10.979 +   3.21 Why do I get compiler warning messages such as
  10.980 + Operation between types "void(*)(int)" and "void*" is not allowed.
  10.981 + Function argument assignment between types "void*" and "void(*)(int)" is not a
  10.982 +llowed.
  10.983 + Pointers are not assignment-compatible.
  10.984 + Argument #5 is not the correct type.
  10.985 +
  10.986 +   during the build?
  10.987 +
  10.988 +          You can safely ignore these messages.
  10.989 +
  10.990 +          All known systems have no problem with casting a function
  10.991 +          pointer to/from a void* pointer, certain C compilers issue a
  10.992 +          compiler diagnostic because this facility is listed as a
  10.993 +          "Common extension" by the C standard:
  10.994 +
  10.995 + K.5.7  Function pointer casts
  10.996 +  [#1] A pointer to an object or to void may be cast to a pointer
  10.997 +       to a function, allowing data to be invoked as a function (6.3.4).
  10.998 +  [#2] A pointer to a function may be cast to a pointer to an
  10.999 +       object or to void, allowing a function to be inspected or
 10.1000 +       modified (for example, by a debugger) (6.3.4).
 10.1001 +
 10.1002 +          It may be just a "common extension", but this facility is
 10.1003 +          relied upon heavily by c-client.
 10.1004 +     _________________________________________________________________
 10.1005 +
 10.1006 +   3.22 Why do I get linker warning messages such as:
 10.1007 +mtest.c:515: the `gets' function is dangerous and should not be used.
 10.1008 +
 10.1009 +   during the build? Isn't this a security bug?
 10.1010 +
 10.1011 +          You can safely ignore this message.
 10.1012 +
 10.1013 +          Certain linkers, most notably on Linux, give this warning
 10.1014 +          message. It is indeed true that the traditional gets() function
 10.1015 +          is not a safe one.
 10.1016 +
 10.1017 +          However, the mtest program is only a demonstration program, a
 10.1018 +          model of a very basic application program using c-client. It is
 10.1019 +          not something that you would install, much less run in any
 10.1020 +          security-sensitive context.
 10.1021 +
 10.1022 +          mtest has numerous other shortcuts that you wouldn't want to do
 10.1023 +          in a real application program.
 10.1024 +
 10.1025 +          The only "security bug" with mtest would be if it was run by
 10.1026 +          some script in a security-sensitive context, but mtest isn't
 10.1027 +          particularly useful for such purposes. If you wanted to write a
 10.1028 +          script to automate some email task using c-client, you'd be
 10.1029 +          better off using imapd instead of mtest.
 10.1030 +
 10.1031 +          mtest only has two legitimate uses. It's a useful testbed for
 10.1032 +          me when debugging new versions of c-client, and it's useful as
 10.1033 +          a model for someone writing a simple c-client application to
 10.1034 +          see how the various calls work.
 10.1035 +
 10.1036 +          By the way, if you need a more advanced example of c-client
 10.1037 +          programming than mtest (and you probably will), I recommend
 10.1038 +          that you look at the source code for imapd and Pine.
 10.1039 +     _________________________________________________________________
 10.1040 +
 10.1041 +   3.23 Why do I get linker warning messages such as:
 10.1042 + auth_ssl.c:92: the `tmpnam' function is dangerous and should not be used.
 10.1043 +
 10.1044 +   during the build? Isn't this a security bug?
 10.1045 +
 10.1046 +          You can safely ignore this message.
 10.1047 +
 10.1048 +          Certain linkers, most notably on Linux, give this warning
 10.1049 +          message, based upon two known issues with tmpnam():
 10.1050 +
 10.1051 +                there can be a buffer overflow if an inadequate buffer is
 10.1052 +                allocated.
 10.1053 +                there can be a timing race caused by certain incautious
 10.1054 +                usage of the return value.
 10.1055 +
 10.1056 +          Neither of these issues applies in the particular use that is
 10.1057 +          made of tmpnam(). More importantly, the tmpnam() call is never
 10.1058 +          executed on Linux systems.
 10.1059 +     _________________________________________________________________
 10.1060 +
 10.1061 +   3.24 OK, suppose I see a warning message about a function being
 10.1062 +   "dangerous and should not be used" for something other than this
 10.1063 +   gets() or tmpnam() call?
 10.1064 +
 10.1065 +          Please forward the details for investigation.
 10.1066 +     _________________________________________________________________
 10.1067 +
 10.1068 +4. Operational Questions
 10.1069 +     _________________________________________________________________
 10.1070 +
 10.1071 +   4.1 How can I enable anonymous IMAP logins?
 10.1072 +
 10.1073 +          Create the file /etc/anonymous.newsgroups. At the present time,
 10.1074 +          this file should be empty. This will permit IMAP logins as
 10.1075 +          anonymous as well as the ANONYMOUS SASL authenticator.
 10.1076 +          Anonymous users have access to mailboxes in the #news., #ftp/,
 10.1077 +          and #public/ namespaces only.
 10.1078 +     _________________________________________________________________
 10.1079 +
 10.1080 +   4.2 How do I set up an alert message that each IMAP user will see?
 10.1081 +
 10.1082 +          Create the file /etc/imapd.alert with the text of the message.
 10.1083 +          This text should be kept to one line if possible. Note that
 10.1084 +          this will cause an alert to every IMAP user every time they
 10.1085 +          initiate an IMAP session, so it should only be used for
 10.1086 +          critical messages.
 10.1087 +     _________________________________________________________________
 10.1088 +
 10.1089 +   4.3 How does the c-client library choose which of its several
 10.1090 +   mechanisms to use to establish an IMAP connection to the server? I
 10.1091 +   noticed that it can connect on port 143, port 993, via rsh, and via
 10.1092 +   ssh.
 10.1093 +
 10.1094 +          c-client chooses how to establish an IMAP connection via the
 10.1095 +          following rules:
 10.1096 +
 10.1097 +          + If /ssl is specified, use an SSL connection. Fail otherwise.
 10.1098 +          + Else if client is a UNIX system and "ssh server exec
 10.1099 +            /etc/rimapd" works, use that
 10.1100 +          + Else if /tryssl is specified and an SSL connection works, use
 10.1101 +            that.
 10.1102 +          + Else if client is a UNIX system and "rsh server exec
 10.1103 +            /etc/rimapd" works, use that.
 10.1104 +          + Else use a non-SSL connection.
 10.1105 +     _________________________________________________________________
 10.1106 +
 10.1107 +   4.4 I am using a TLS-capable IMAP server, so I don't need to use /ssl
 10.1108 +   to get encryption. However, I want to be certain that my session is
 10.1109 +   TLS encrypted before I send my password. How to I do this?
 10.1110 +
 10.1111 +          Use the /tls option in the mailbox name. This will cause an
 10.1112 +          error message and the connection to fail if the server does not
 10.1113 +          negotiate STARTTLS.
 10.1114 +     _________________________________________________________________
 10.1115 +
 10.1116 +   4.5 How do I use one of the alternative formats described in the
 10.1117 +   formats.txt document? In particular, I hear that mbx format will give
 10.1118 +   me better performance and allow shared access.
 10.1119 +
 10.1120 +          The rumors about mbx format being preferred are true. It is
 10.1121 +          faster than the traditional UNIX mailbox format and permits
 10.1122 +          shared access.
 10.1123 +
 10.1124 +          However, and this is very important, note that using an
 10.1125 +          alternative mailbox format is an advanced facility, and only
 10.1126 +          expert users should undertake it. If you don't understand any
 10.1127 +          of the following notes, you may not be enough of an expert yet,
 10.1128 +          and are probably better off not going this route until you are
 10.1129 +          more comfortable with your understanding.
 10.1130 +
 10.1131 +          Some of the formats, including mbx, are only supported by the
 10.1132 +          software based on the c-client library, and are not recognized
 10.1133 +          by other mailbox programs. The "vi" editor will corrupt any mbx
 10.1134 +          format mailbox that it encounters.
 10.1135 +
 10.1136 +          Another problem is that the certain formats, including mbx, use
 10.1137 +          advanced file access and locking techniques that do not work
 10.1138 +          reliably with NFS. NFS is not a real filesystem. Use IMAP
 10.1139 +          instead of NFS for distributed access.
 10.1140 +
 10.1141 +          Each of the following steps are in escalating order of
 10.1142 +          involvement. The further you go down this list, the more deeply
 10.1143 +          committed you become:
 10.1144 +
 10.1145 +          + The simplest way to create a mbx-format mailbox is to prefix
 10.1146 +            the name with "#driver.mbx/" when creating a mailbox through
 10.1147 +            c-client. For example, if you create "#driver.mbx/foo", the
 10.1148 +            mailbox "foo" will be created in mbx format. Only use
 10.1149 +            "#driver.mbx/" when creating the mailbox. At all other times,
 10.1150 +            just use the name ("foo" in this example); the software will
 10.1151 +            automatically select the driver for mbx whenever that mailbox
 10.1152 +            is accessed without you doing anything else.
 10.1153 +          + You can use the "mailutil copy" command to copy an existing
 10.1154 +            mailbox to a new mailbox in mbx format. Read the man page
 10.1155 +            provided with the mailutil program for details.
 10.1156 +          + If you create an mbx-format INBOX, by creating
 10.1157 +            "#driver.mbx/INBOX" (note that "INBOX" must be all
 10.1158 +            uppercase), then subsequent access to INBOX by any c-client
 10.1159 +            based application will use the mbx-format INBOX. Any mail
 10.1160 +            delivered to the traditional format mailbox in the spool
 10.1161 +            directory (e.g. /var/spool/mail/$USER) will automatically be
 10.1162 +            copied into the mbx-format INBOX and the spool directory copy
 10.1163 +            removed.
 10.1164 +          + You can cause any newly-created mailboxes to be in mbx-format
 10.1165 +            by default by changing the definition of
 10.1166 +            CREATEPROTO=unixproto to be CREATEPROTO=mbxproto in
 10.1167 +            src/osdep/unix/Makefile, then rebuilding the IMAP toolkit (do
 10.1168 +            a "make clean" first). Do not change EMPTYPROTO, since mbx
 10.1169 +            format mailboxes are never a zero-byte file. If you use Pine
 10.1170 +            or the imap-utils, you should probably also rebuild them with
 10.1171 +            the new IMAP toolkit too.
 10.1172 +          + You can deliver directly to the mbx-format INBOX by use of
 10.1173 +            the tmail or dmail programs. tmail is for direct invocation
 10.1174 +            from sendmail (or whatever MTA program you use); dmail is for
 10.1175 +            calls from procmail. Both of these programs have man pages
 10.1176 +            which must be read carefully before making this change.
 10.1177 +
 10.1178 +          Most other servers (e.g. Cyrus) require use of a non-standard
 10.1179 +          format. A full-fledged format conversion is not significantly
 10.1180 +          different from what you have to do with other servers. The
 10.1181 +          difference, which makes format conversion procedures somewhat
 10.1182 +          more complicated with this server, is that there is no "all or
 10.1183 +          nothing" requirement with this server. There are many points in
 10.1184 +          between. A format conversion can be anything from a single
 10.1185 +          mailbox or single user, to systemwide.
 10.1186 +
 10.1187 +          This is good in that you can decide how far to go, or do the
 10.1188 +          steps incrementally as you become more comfortable with the
 10.1189 +          result. On the other hand, there's no "One True Way" which can
 10.1190 +          be boiled down to a simple set of pedagogical instructions.
 10.1191 +
 10.1192 +          A number of sites have done full-fledged format conversions,
 10.1193 +          and are reportedly quite happy with the results. Feel free to
 10.1194 +          ask in the comp.mail.imap newsgroup or the imap-uw mailing
 10.1195 +          list for advice or help.
 10.1196 +     _________________________________________________________________
 10.1197 +
 10.1198 +   4.6 How do I set up shared mailboxes?
 10.1199 +
 10.1200 +          At the simplest level, a shared mailbox is one which has UNIX
 10.1201 +          file and directory protections which permit multiple users to
 10.1202 +          access it. What this means is that your existing skills and
 10.1203 +          tools to create and manage shared files on your UNIX system
 10.1204 +          apply to shared mailboxes; e.g.
 10.1205 +
 10.1206 + chmod 666 mailbox
 10.1207 +
 10.1208 +          You may want to consider the use of a mailbox format which
 10.1209 +          permits multiple simultaneous read/write sessions, such as the
 10.1210 +          mbx format. The traditional UNIX format only allows one
 10.1211 +          read/write session to a mailbox at a time.
 10.1212 +
 10.1213 +          An additional convenience item are three system directories,
 10.1214 +          which can be set up for shared namespaces. These are: #ftp,
 10.1215 +          #shared, and #public, and are defined by creating the
 10.1216 +          associated UNIX users and home directories as described below.
 10.1217 +
 10.1218 +          #ftp/ refers to the anonymous ftp filesystem exported by the
 10.1219 +          ftp server, and is equivalent to the home directory for UNIX
 10.1220 +          user "ftp". For example, #ftp/foo/bar refers to the file
 10.1221 +          /foo/bar in the anonymous FTP filesystem, or ~ftp/foo/bar for
 10.1222 +          normal users. Anonymous FTP files are available to anonymous
 10.1223 +          IMAP logins. By default, newly-created files in #ftp/ are
 10.1224 +          protected 644.
 10.1225 +
 10.1226 +          #public/ refers to an IMAP toolkit convention called "public"
 10.1227 +          files, and is equivalent to the home directory for UNIX user
 10.1228 +          "imappublic". For example, #public/foo/bar refers to the file
 10.1229 +          ~imappublic/foo/bar. Public files are available to anonymous
 10.1230 +          IMAP logins. By default, newly-created files in #public are
 10.1231 +          created with protection 0666.
 10.1232 +
 10.1233 +          #shared/ refers to an IMAP toolkit convention called "shared"
 10.1234 +          files, and is equivalent to the home directory for UNIX user
 10.1235 +          "imapshared". For example, #shared/foo/bar refers to the file
 10.1236 +          ~imapshared/foo/bar. Shared files are not available to
 10.1237 +          anonymous IMAP logins. By default, newly-created files in
 10.1238 +          #shared are created with protection 0660.
 10.1239 +     _________________________________________________________________
 10.1240 +
 10.1241 +   4.7 How can I make the server syslogs go to someplace other than the
 10.1242 +   mail syslog?
 10.1243 +
 10.1244 +          The openlog() call that sets the syslog facility is in
 10.1245 +          src/osdep/unix/env_unix.c in routine server_init(). You need to
 10.1246 +          edit this file to change the syslog facility from LOG_MAIL to
 10.1247 +          the facility you want, then rebuild. You also need to set up
 10.1248 +          your /etc/syslog.conf properly.
 10.1249 +
 10.1250 +          Refer to the man pages for syslog and syslogd for more
 10.1251 +          information on what the available syslog facilities are and how
 10.1252 +          to configure syslogs. If you still don't understand what to do,
 10.1253 +          find a UNIX system expert.
 10.1254 +     _________________________________________________________________
 10.1255 +
 10.1256 +5. Security Questions
 10.1257 +     _________________________________________________________________
 10.1258 +
 10.1259 +   5.1 I see that the IMAP server allows access to arbitary files on the
 10.1260 +   system, including /etc/passwd! How do I disable this?
 10.1261 +
 10.1262 +          You should not worry about this if your IMAP users are allowed
 10.1263 +          shell access. The IMAP server does not permit any access that
 10.1264 +          the user can not have via the shell.
 10.1265 +
 10.1266 +          If, and only if, you deny your IMAP users shell access, you may
 10.1267 +          want to consider one of three choices. Note that these choices
 10.1268 +          reduce IMAP functionality, and may have undesirable side
 10.1269 +          effects. Each of these choices involves an edit to file
 10.1270 +          src/osdep/unix/env_unix.c
 10.1271 +
 10.1272 +          The first (and recommended) choice is to set restrictBox as
 10.1273 +          described in file CONFIG. This will disable access to the
 10.1274 +          filesystem root, to other users' home directory, and to
 10.1275 +          superior directory.
 10.1276 +
 10.1277 +          The second (and strongly NOT recommended) choice is to set
 10.1278 +          closedBox as described in file CONFIG. This puts each IMAP
 10.1279 +          session into a so-called "chroot jail", and thus setting this
 10.1280 +          option is extremely dangerous; it can make your system much
 10.1281 +          less secure and open to root compromise attacks. So do not use
 10.1282 +          this option unless you are absolutely certain that you
 10.1283 +          understand all the issues of a "chroot jail."
 10.1284 +
 10.1285 +          The third choice is to rewrite routine mailboxfile() to
 10.1286 +          implement whatever mapping from mailbox name to filesystem name
 10.1287 +          (and restrictions) that you wish. This is the most general
 10.1288 +          choice. As a guide, you can see at the start of routine
 10.1289 +          mailboxfile() what the restrictBox choice does.
 10.1290 +     _________________________________________________________________
 10.1291 +
 10.1292 +   5.2 I've heard that IMAP servers are insecure. Is this true?
 10.1293 +
 10.1294 +          There are no known security problems in this version of the
 10.1295 +          IMAP toolkit, including the IMAP and POP servers. The IMAP and
 10.1296 +          POP servers limit what can be done while not logged in, and as
 10.1297 +          part of the login process discard all privileges except those
 10.1298 +          of the user.
 10.1299 +
 10.1300 +          As with other software packages, there have been buffer
 10.1301 +          overflow vulnerabilities in past versions. All known problems
 10.1302 +          of this nature are fixed in this version.
 10.1303 +
 10.1304 +          There is every reason to believe that the bad guys are engaged
 10.1305 +          in an ongoing effort to find vulnerabilities in the IMAP
 10.1306 +          toolkit. We look for such problems, and when one is found we
 10.1307 +          fix it.
 10.1308 +
 10.1309 +          It's unfortunate that any vulnerabilities existed in past
 10.1310 +          versions, and we're doing my best to keep the IMAP toolkit free
 10.1311 +          of vulnerabilities. No new vulnerabilities have been discovered
 10.1312 +          in quite a while, but efforts will not be relaxed.
 10.1313 +
 10.1314 +          Beware of vendors who claim that their implementations can not
 10.1315 +          have vulnerabilities.
 10.1316 +     _________________________________________________________________
 10.1317 +
 10.1318 +   5.3 How do I know that I have the most secure version of the server?
 10.1319 +
 10.1320 +          The best way is to keep your server software up to date. The
 10.1321 +          bad guys are always looking for ways to crack software, and
 10.1322 +          when they find one, let all their friends know.
 10.1323 +
 10.1324 +          Oldtimers used to refer to a concept of software rot: if your
 10.1325 +          software hasn't been updated in a while, it would "rot" -- tend
 10.1326 +          to acquire problems that it didn't have when it was new.
 10.1327 +
 10.1328 +          The latest release version of the IMAP toolkit is always
 10.1329 +          available at ftp://ftp.cac.washington.edu/mail/imap.tar.Z
 10.1330 +     _________________________________________________________________
 10.1331 +
 10.1332 +   5.4 I see all these strcpy() and sprintf() calls, those are unsafe,
 10.1333 +   aren't they?
 10.1334 +
 10.1335 +          Yes and no.
 10.1336 +
 10.1337 +          It can be unsafe to do these calls if you do not know that the
 10.1338 +          string being written will fit in the buffer. However, they are
 10.1339 +          perfectly safe if you do know that.
 10.1340 +
 10.1341 +          Beware of programmers who advocate doing a brute-force change
 10.1342 +          of all instances of
 10.1343 +
 10.1344 + strcpy (s,t);
 10.1345 +
 10.1346 +          to
 10.1347 +
 10.1348 + strncpy (s,t,n)[n] = '\0';
 10.1349 +
 10.1350 +          and similar measures in the name of "fixing all possible buffer
 10.1351 +          overflows."
 10.1352 +
 10.1353 +          There are examples in which a security bug was introduced
 10.1354 +          because of this type of "fix", due to the programmer using the
 10.1355 +          wrong value for n. In one case, the programmer thought that n
 10.1356 +          was larger than it actually was, causing a NUL to be written
 10.1357 +          out of the buffer; in another, n was too small, and a security
 10.1358 +          credential was truncated.
 10.1359 +
 10.1360 +          What is particularly ironic was that in both cases, the
 10.1361 +          original strcpy() was safe, because the size of the source
 10.1362 +          string was known to be safe.
 10.1363 +
 10.1364 +          With all this in mind, the software has been inspected, and it
 10.1365 +          is believed that all places where buffer overflows can happen
 10.1366 +          have been fixed. The strcpy()s that are still are in the code
 10.1367 +          occur after a size check was done in some other way.
 10.1368 +
 10.1369 +          Note that the common C idiom of
 10.1370 +
 10.1371 + *s++ = c;
 10.1372 +
 10.1373 +          is just as vulnerable to buffer overflows. You can't cure
 10.1374 +          buffer overflows by outlawing certain functions, nor is it
 10.1375 +          desirable to do so; sometimes operations like strcpy()
 10.1376 +          translate into fast machine instructions for better
 10.1377 +          performance.
 10.1378 +
 10.1379 +          Nothing replaces careful study of code. That's how the bad guys
 10.1380 +          find bugs. Security is not accomplished by means of brute-force
 10.1381 +          shortcuts.
 10.1382 +     _________________________________________________________________
 10.1383 +
 10.1384 +   5.5 Those /tmp lock files are protected 666, is that really right?
 10.1385 +
 10.1386 +          Yes. Shared mailboxes won't work otherwise. Also, you get into
 10.1387 +          accidental denial of service problems with old lock files left
 10.1388 +          lying around; this happens fairly frequently.
 10.1389 +
 10.1390 +          The deliberate mischief that can be caused by fiddling with the
 10.1391 +          lock files is small-scale; harassment level at most. There are
 10.1392 +          many -- and much more effective -- other ways of harassing
 10.1393 +          another user on UNIX. It's usually not difficult to determine
 10.1394 +          the culprit.
 10.1395 +
 10.1396 +          Before worrying about deliberate mischief, worry first about
 10.1397 +          things happening by accident!
 10.1398 +     _________________________________________________________________
 10.1399 +
 10.1400 +6. Why Did You Do This Strange Thing? Questions
 10.1401 +     _________________________________________________________________
 10.1402 +
 10.1403 +   6.1 Why don't you use GNU autoconfig / automake / autoblurdybloop?
 10.1404 +
 10.1405 +          Autoconfig et al are not available on all the platforms where
 10.1406 +          the IMAP toolkit is supported; and do not work correctly on
 10.1407 +          some of the platforms where they do exist. Furthermore, these
 10.1408 +          programs add another layer of complexity to an already complex
 10.1409 +          process.
 10.1410 +
 10.1411 +          Coaxing software that uses autoconfig to build properly on
 10.1412 +          platforms which were not specifically considered by that
 10.1413 +          software wastes an inordinate amount of time. When (not if)
 10.1414 +          autoconfig fails to do the right thing, the result is an
 10.1415 +          inpenetrable morass to untangle in order to find the problem
 10.1416 +          and fix it.
 10.1417 +
 10.1418 +          The concept behind autoconfig is good, but the execution is
 10.1419 +          flawed. It rarely does the right thing on a platform that
 10.1420 +          wasn't specifically considered. Human life is too short to
 10.1421 +          debug autoconfig problems, especially since the current
 10.1422 +          mechanism is so much easier.
 10.1423 +     _________________________________________________________________
 10.1424 +
 10.1425 +   6.2 Why do you insist upon a build with -g? Doesn't it waste disk and
 10.1426 +   memory space?
 10.1427 +
 10.1428 +          From time to time a submitted port has snuck in without -g.
 10.1429 +          This has always ended up causing problems. There are only two
 10.1430 +          valid excuses for not using -g in a port:
 10.1431 +
 10.1432 +          + The compiler does not support -g
 10.1433 +          + An alternate form of -g is needed with optimization, e.g.
 10.1434 +            -g3.
 10.1435 +
 10.1436 +          There will be no new ports added without -g (or a suitable
 10.1437 +          alternative) being set.
 10.1438 +
 10.1439 +          -g has not been arbitrarily added to the ports which do not
 10.1440 +          currently have it because we don't know if doing so would break
 10.1441 +          the build. However, any support issues with one of those port
 10.1442 +          will lead to the correct -g setting being determined and
 10.1443 +          permanently added.
 10.1444 +
 10.1445 +          Processors are fast enough (and disk space is cheap enough)
 10.1446 +          that -g should be automatic in all compilers with no way of
 10.1447 +          turning it off, and /bin/strip should be a symlink to
 10.1448 +          /bin/true. Human life is too short to deal with binaries built
 10.1449 +          without -g. Such binaries should be a bad memory of the days of
 10.1450 +          KIPS processors and disks that costs several dollars per
 10.1451 +          kilobyte.
 10.1452 +     _________________________________________________________________
 10.1453 +
 10.1454 +   6.3 Why don't you make c-client a shared library?
 10.1455 +
 10.1456 +          All too often, shared libraries create far more problems than
 10.1457 +          they solve.
 10.1458 +
 10.1459 +          Remember that you only gain the benefit of a shared library
 10.1460 +          when there are multiple applications which use that shared
 10.1461 +          library. Even without shared libraries, on most modern
 10.1462 +          operating systems (and many ancient ones too!) applications
 10.1463 +          will share their text segments between across multiple
 10.1464 +          processes running the same application. This means that if your
 10.1465 +          system only runs one application (e.g. imapd) that uses the
 10.1466 +          c-client library, then you gain no benefit from making c-client
 10.1467 +          a shared library even if it has 100 imapd processes. You will,
 10.1468 +          however suffer added complexity.
 10.1469 +
 10.1470 +          If you have a server system that just runs imapd and ipop3d,
 10.1471 +          then making c-client a shared library will save just one copy
 10.1472 +          of c-client no matter how many IMAP/POP3 processes are running.
 10.1473 +
 10.1474 +          The problem with shared libraries is that you have to keep
 10.1475 +          around a copy of the library every time something changes in
 10.1476 +          the library that would affect the interface the library
 10.1477 +          presents to the application. So, you end up having many copies
 10.1478 +          of the same shared library.
 10.1479 +
 10.1480 +          If you don't keep multiple copies of the shared library, then
 10.1481 +          one of two things happens. If there was proper versioning, then
 10.1482 +          you'll get a message such as "cannot open shared object file"
 10.1483 +          or "minor versions don't match" and the application won't run.
 10.1484 +          Otherwise, the application will run, but will fail in
 10.1485 +          mysterious ways.
 10.1486 +
 10.1487 +          Several sites and third-party distributors have modified the
 10.1488 +          c-client makefile in order to make c-client be a shared
 10.1489 +          library. When (not if) a c-client based application fails in
 10.1490 +          mysterious ways because of a library compatibility problem, the
 10.1491 +          result is a bug report. A lot of time and effort ends up
 10.1492 +          getting wasted investigating such bug reports.
 10.1493 +
 10.1494 +          Memory is so cheap these days that it's not worth it. Human
 10.1495 +          life is too short to deal with shared library compatibility
 10.1496 +          problems.
 10.1497 +     _________________________________________________________________
 10.1498 +
 10.1499 +   6.4 Why don't you use iconv() for internationalization support?
 10.1500 +
 10.1501 +          iconv() is not ubiquitous enough.
 10.1502 +     _________________________________________________________________
 10.1503 +
 10.1504 +   6.5 Why is the IMAP server connected to the home directory by default?
 10.1505 +
 10.1506 +          The IMAP server has no way of knowing what you might call
 10.1507 +          "mail" as opposed to "some other file"; in fact, you can use
 10.1508 +          IMAP to access any file.
 10.1509 +
 10.1510 +          The IMAP server also doesn't know whether your preferred
 10.1511 +          subdirectory for mailbox files is "mail/", ".mail/", "Mail/",
 10.1512 +          "Mailboxes/", or any of a zillion other possibilities. If one
 10.1513 +          such name were chosen, it would undoubtably anger the partisans
 10.1514 +          of all the other names.
 10.1515 +
 10.1516 +          It is possible to modify the software so that the default
 10.1517 +          connected directory is someplace else. Please read the file
 10.1518 +          CONFIG for discussion of this and other issues.
 10.1519 +     _________________________________________________________________
 10.1520 +
 10.1521 +   6.6 I have a Windows system. Why isn't the server plug and play for
 10.1522 +   me?
 10.1523 +
 10.1524 +          There is no standard for how mail is stored on Windows; nor a
 10.1525 +          single standard SMTP server. The closest to either would be the
 10.1526 +          SMTP server in Microsoft's IIS.
 10.1527 +
 10.1528 +          So there's no default by which to make assumptions. As the
 10.1529 +          software is set up, it assumes that the each user has an
 10.1530 +          Windows login account and private home directory, and that mail
 10.1531 +          is stored on that home directory as files in one of the popular
 10.1532 +          UNIX formats. It also assumes that there is some tool
 10.1533 +          equivalent to inetd on UNIX that does the TCP/IP listening and
 10.1534 +          server startup.
 10.1535 +
 10.1536 +          Basically, unless you're an email software hacker, you probably
 10.1537 +          want to look elsewhere if you want IMAP/POP servers for
 10.1538 +          Windows.
 10.1539 +     _________________________________________________________________
 10.1540 +
 10.1541 +   6.7 I looked at the UNIX SSL code and saw that you have the SSL data
 10.1542 +   payload size set to 8192 bytes. SSL allows 16K; why aren't you using
 10.1543 +   the full size?
 10.1544 +
 10.1545 +          This is to avoid an interoperability problem with:
 10.1546 +
 10.1547 +          + PC IMAP clients that use Microsoft's SChannel.DLL (SSPI) for
 10.1548 +            SSL support
 10.1549 +          + Microsoft Exchange server (which also uses SChannel).
 10.1550 +
 10.1551 +          SChannel has a bug that makes it think that the maximum SSL
 10.1552 +          data payload size is 16379 bytes -- 5 bytes too small. Thus,
 10.1553 +          c-client has to make sure that it never transmits full sized
 10.1554 +          SSL packets.
 10.1555 +
 10.1556 +          The reason for using 8K (as opposed to, say, 16379 bytes, or
 10.1557 +          15K, or...) is that it corresponds with the TCP buffer size
 10.1558 +          that the software uses elsewhere for input; there's a slight
 10.1559 +          performance benefit to having the two sizes correspond or at
 10.1560 +          least be a multiple of each other. Also, it keeps the size as a
 10.1561 +          power of two, which might be significant on some platforms.
 10.1562 +
 10.1563 +          There wasn't a significant difference that we could measure
 10.1564 +          between 8K and 15K.
 10.1565 +
 10.1566 +          Microsoft has developed a hotfix for this bug. Look up MSKB
 10.1567 +          article number 300562. Contrary to the article text which
 10.1568 +          implies that this is a Pine issue, this bug also affects
 10.1569 +          Microsoft Exchange server with any client that transmits
 10.1570 +          full-sized SSL payloads.
 10.1571 +     _________________________________________________________________
 10.1572 +
 10.1573 +   6.8 Why is an mh format INBOX called #mhinbox instead of just INBOX?
 10.1574 +
 10.1575 +          It's a long story. In brief, the mh format driver is less
 10.1576 +          functional than any of the other drivers. It turned out that
 10.1577 +          there were some users (including high-level administrators) who
 10.1578 +          tried mh years ago and no longer use it, but still had an mh
 10.1579 +          profile left behind.
 10.1580 +
 10.1581 +          When the mh driver used INBOX, it would see the mh profile, and
 10.1582 +          proceed to move the user's INBOX into the mh format INBOX. This
 10.1583 +          caused considerable confusion as some things stopped working.
 10.1584 +     _________________________________________________________________
 10.1585 +
 10.1586 +   6.9 Why don't you support the maildir format?
 10.1587 +
 10.1588 +          It is technically difficult to support maildir in IMAP while
 10.1589 +          maintaining acceptable performance, robustness, following the
 10.1590 +          requirements of the IMAP protocol specification, and following
 10.1591 +          the requirements of maildir.
 10.1592 +
 10.1593 +          No one has succeeded in accomplishing all four together. The
 10.1594 +          various maildir drivers offered as patches all have these
 10.1595 +          problems. The problem is exacerbated because this
 10.1596 +          implementation supports multiple formats; consequently this
 10.1597 +          implementation can't make any performance shortcuts by assuming
 10.1598 +          that all the world is maildir.
 10.1599 +
 10.1600 +          We can't do a better job than the maildir fan community has
 10.1601 +          done with their maildir drivers. Similarly, if the maildir fan
 10.1602 +          community provides the maildir driver, they take on the
 10.1603 +          responsibility for answering maildir-specific support
 10.1604 +          questions. This is as it should be, and that is why maildir
 10.1605 +          support is left to the maildir fan community.
 10.1606 +     _________________________________________________________________
 10.1607 +
 10.1608 +   6.10 Why don't you support the Cyrus format?
 10.1609 +
 10.1610 +          There's no point to doing so. An implementation which supports
 10.1611 +          multiple formats will never do as well as one which is
 10.1612 +          optimized to support one single format.
 10.1613 +
 10.1614 +          If you want to use Cyrus mailbox format, you should use the
 10.1615 +          Cyrus server, which is the native implementation of that format
 10.1616 +          and is specifically optimized for that format. That's also why
 10.1617 +          Cyrus doesn't implement any other format.
 10.1618 +     _________________________________________________________________
 10.1619 +
 10.1620 +   6.11 Why is it creating extra forks on my SVR4 system?
 10.1621 +
 10.1622 +          This is because your system only has fcntl() style locking and
 10.1623 +          not flock() style locking. fcntl() locking has a design flaw
 10.1624 +          that causes a close() to release any locks made by that process
 10.1625 +          on the file opened on that file descriptor, even if the lock
 10.1626 +          was made on a different file descriptor.
 10.1627 +
 10.1628 +          This design flaw causes unexpected loss of lock, and consequent
 10.1629 +          mailbox corruption. The workaround is to do certain "dangerous
 10.1630 +          operations" in another fork, thus avoiding doing a close() in
 10.1631 +          the vulnerable fork.
 10.1632 +
 10.1633 +          The best way to solve this problem is to upgrade your SVR4
 10.1634 +          (Solaris, AIX, HP-UX, SGI) or OSF/1 system to a more advanced
 10.1635 +          operating system, such as Linux or BSD. These more advanced
 10.1636 +          operating systems have fcntl() locking for compatibility with
 10.1637 +          SVR4, but also have flock() locking.
 10.1638 +
 10.1639 +          Beware of certain SVR4 systems, such as AIX, which have an
 10.1640 +          "flock()" function in their C library that is just a jacket
 10.1641 +          that does an fcntl() lock. This is not a true flock(), and has
 10.1642 +          the same design flaw as fcntl().
 10.1643 +     _________________________________________________________________
 10.1644 +
 10.1645 +   6.12 Why are you so fussy about the date/time format in the internal
 10.1646 +   "From " line in traditional UNIX mailbox files? My other mail program
 10.1647 +   just considers every line that starts with "From " to be the start of
 10.1648 +   the message.
 10.1649 +
 10.1650 +          You just answered your own question. If any line that starts
 10.1651 +          with "From " is treated as the start of a message, then every
 10.1652 +          message text line which starts with "From " has to be quoted
 10.1653 +          (typically by prefixing a ">" character). People complain about
 10.1654 +          this -- "why did a > get stuck in my message?"
 10.1655 +
 10.1656 +          So, good mail reading software only considers a line to be a
 10.1657 +          "From " line if it follows the actual specification for a
 10.1658 +          "From " line. This means, among other things, that the day of
 10.1659 +          week is fixed-format: "May 14", but "May  7" (note the extra
 10.1660 +          space) as opposed to "May 7". ctime() format for the date is
 10.1661 +          the most common, although POSIX also allows a numeric timezone
 10.1662 +          after the year. For compatibility with ancient software, the
 10.1663 +          seconds are optional, the timezone may appear before the year,
 10.1664 +          the old 3-letter timezones are also permitted, and "remote from
 10.1665 +          xxx" may appear after the whole thing.
 10.1666 +
 10.1667 +          Unfortunately, some software written by novices use other
 10.1668 +          formats. The most common error is to have a variable-width day
 10.1669 +          of month, perhaps in the erroneous belief that RFC 2822 (or RFC
 10.1670 +          822) defines the format of the date/time in the "From " line
 10.1671 +          (it doesn't; no RFC describes internal formats). I've seen a
 10.1672 +          few other goofs, such as a single-digit second, but these are
 10.1673 +          less common.
 10.1674 +
 10.1675 +          If you are writing your own software that writes mailbox files,
 10.1676 +          and you really aren't all that savvy with all the ins and outs
 10.1677 +          and ancient history, you should seriously consider using the
 10.1678 +          c-client library (e.g. routine mail_append()) instead of doing
 10.1679 +          the file writes yourself. If you must do it yourself, use
 10.1680 +          ctime(), as in:
 10.1681 +
 10.1682 + fprintf (mbx,"From %s@%h %s",user,host,ctime (time (0)));
 10.1683 +
 10.1684 +          rather than try to figure out a good format yourself. ctime()
 10.1685 +          is the most traditional format and nobody will flame you for
 10.1686 +          using it.
 10.1687 +     _________________________________________________________________
 10.1688 +
 10.1689 +   6.13 Why is traditional UNIX format the default format?
 10.1690 +
 10.1691 +          Compatibility with the past 30 or so years of UNIX history.
 10.1692 +          This server is the only one that completely interoperates with
 10.1693 +          legacy UNIX mail tools.
 10.1694 +     _________________________________________________________________
 10.1695 +
 10.1696 +   6.14 Why do you write this "DON'T DELETE THIS MESSAGE -- FOLDER
 10.1697 +   INTERNAL DATA" message at the start of traditional UNIX and MMDF
 10.1698 +   format mailboxes?
 10.1699 +
 10.1700 +          This pseudo-message serves two purposes.
 10.1701 +
 10.1702 +          First, it establishes the mailbox format even when the mailbox
 10.1703 +          has no messages. Otherwise, a mailbox with no messages is a
 10.1704 +          zero-byte file, which could be one of several formats.
 10.1705 +
 10.1706 +          Second, it holds mailbox metadata used by IMAP: the UID
 10.1707 +          validity, the last assigned UID, and mailbox keywords. Without
 10.1708 +          this metadata, which must be preserved even when the mailbox
 10.1709 +          has no messages, the traditional UNIX format wouldn't be able
 10.1710 +          to support the full capabilities of IMAP.
 10.1711 +     _________________________________________________________________
 10.1712 +
 10.1713 +   6.15 Why don't you stash the mailbox metadata in the first real
 10.1714 +   message of the mailbox instead of writing this fake FOLDER INTERNAL
 10.1715 +   DATA message?
 10.1716 +
 10.1717 +          In fact, that is what is done if the mailbox is non-empty and
 10.1718 +          does not already have a FOLDER INTERNAL DATA message.
 10.1719 +
 10.1720 +          One problem with doing that is that if some external program
 10.1721 +          removes the first message, the metadata is lost and must be
 10.1722 +          recreated, thus losing any prior UID or keyword list status
 10.1723 +          that IMAP clients may depend upon.
 10.1724 +
 10.1725 +          Another problem is that this doesn't help if the last message
 10.1726 +          is deleted. This will result in an empty mailbox, and the
 10.1727 +          necessity to create a FOLDER INTERNAL DATA message.
 10.1728 +     _________________________________________________________________
 10.1729 +
 10.1730 +   6.16 Why aren't "dual-use" mailboxes the default?
 10.1731 +
 10.1732 +          Compatibility with the past 30 or so years of UNIX history, not
 10.1733 +          to mention compatibility with user expectations when using
 10.1734 +          shell tools.
 10.1735 +     _________________________________________________________________
 10.1736 +
 10.1737 +   6.17 Why do you use ucbcc to build on Solaris?
 10.1738 +
 10.1739 +          It is a long, long story about why cc is set to ucbcc. You need
 10.1740 +          to invoke the C compiler so that it links with the SVR4
 10.1741 +          libraries and not the BSD libraries, otherwise readdir() will
 10.1742 +          return the wrong information.
 10.1743 +
 10.1744 +          Of all the names in the most common path, ucbcc is the only
 10.1745 +          name to be found (on /usr/ccs/bin) that points to a suitable
 10.1746 +          compiler. cc is likely to be /usr/ucb/cc which is absolutely
 10.1747 +          not the compiler that you want. The real SVR4 cc is probably
 10.1748 +          something like /opt/SUNWspro/bin/cc which is rarely in anyone's
 10.1749 +          path by default.
 10.1750 +
 10.1751 +          ucbcc is probably a link to acc, e.g.
 10.1752 +          /opt/SUNWspro/SC4.0/bin/acc, and is the UCB C compiler using
 10.1753 +          the SVR4 libraries.
 10.1754 +
 10.1755 +          If ucbcc isn't on your system, then punt on the SUN C compiler
 10.1756 +          and use gcc instead (the gso port instead of the sol port).
 10.1757 +
 10.1758 +          If, in spite of all the above warnings, you choose to change
 10.1759 +          "ucbcc" to "cc", you will probably find that the -O2 needs to
 10.1760 +          be changed to -O. If you don't get any error messages with -O2,
 10.1761 +          that's a pretty good indicator that you goofed and are running
 10.1762 +          the compiler that will link with the BSD libraries.
 10.1763 +
 10.1764 +          To recap:
 10.1765 +
 10.1766 +          + The sol port is designed to be built using the UCB compiler
 10.1767 +            using the SVR4 libraries. This compiler is "ucbcc", which is
 10.1768 +            lunk to acc. You use -O2 as one of the CFLAGS.
 10.1769 +          + If you build the sol port with the UCB compiler using the BSD
 10.1770 +            libraries, you will get no error messages but you will get
 10.1771 +            bad binaries (the most obvious symptom is dropping the first
 10.1772 +            two characters return filenames from the imapd LIST command.
 10.1773 +            This compiler also uses -O2, and is very often what the user
 10.1774 +            gets from "cc". BEWARE
 10.1775 +          + If you build the sol port with the real SVR4 compiler, which
 10.1776 +            is often hidden away or unavailable on many systems, then you
 10.1777 +            will get errors from -O2 and you need to change that to -O.
 10.1778 +            But you will get a good binary. However, you should try it
 10.1779 +            with -O2 first, to make sure that you got this compiler and
 10.1780 +            not the UCB compiler using BSD libraries.
 10.1781 +     _________________________________________________________________
 10.1782 +
 10.1783 +   6.18 Why should I care about some old system with BSD libraries? cc is
 10.1784 +   the right thing on my Solaris system!
 10.1785 +
 10.1786 +          Because there still are sites that use such systems. On those
 10.1787 +          systems, the assumption that "cc" does the right thing will
 10.1788 +          lead to corrupt binaries with no error message or other warning
 10.1789 +          that anything is amiss.
 10.1790 +
 10.1791 +          Too many sites have fallen victim to this problem.
 10.1792 +     _________________________________________________________________
 10.1793 +
 10.1794 +   6.19 Why do you insist upon writing .lock files in the spool
 10.1795 +   directory?
 10.1796 +
 10.1797 +          Compatibility with the past 30 years of UNIX software which
 10.1798 +          deals with the spool directory, especially software which
 10.1799 +          delivers mail. Otherwise, it is possible to lose mail.
 10.1800 +     _________________________________________________________________
 10.1801 +
 10.1802 +   6.20 Why should I care about compatibility with the past?
 10.1803 +
 10.1804 +          This is one of those questions in which the answer never
 10.1805 +          convinces those who ask it. Somehow, everybody who ever asks
 10.1806 +          this question ends up answering it for themselves as they get
 10.1807 +          older, with the very answer that they rejected years earlier.
 10.1808 +     _________________________________________________________________
 10.1809 +
 10.1810 +7. Problems and Annoyances
 10.1811 +     _________________________________________________________________
 10.1812 +
 10.1813 +   7.1 Help! My INBOX is empty! What happened to my messages?
 10.1814 +
 10.1815 +          If you are seeing "0 messages" when you open INBOX and you know
 10.1816 +          you have messages there (and perhaps have looked at your mail
 10.1817 +          spool file and see that messages are there), then probably
 10.1818 +          there is something wrong with the very first line of your mail
 10.1819 +          spool file. Make sure that the first five bytes of the file are
 10.1820 +          "From ", followed by an email address and a date/time in
 10.1821 +          ctime() format, e.g.:
 10.1822 +
 10.1823 + From fred@foo.bar Mon May  7 20:54:30 2001
 10.1824 +     _________________________________________________________________
 10.1825 +
 10.1826 +   7.2 Help! All my messages in a non-INBOX mailbox have been
 10.1827 +   concatenated into one message which claims to be from me and has a
 10.1828 +   subject of the file name of the mailbox! What's going on?
 10.1829 +
 10.1830 +          Something wrong with the very first line of the mailbox. Make
 10.1831 +          sure that the first five bytes of the file are "From ",
 10.1832 +          followed by an email address and a date/time in ctime() format,
 10.1833 +          e.g.:
 10.1834 +
 10.1835 + From fred@foo.bar Mon May  7 20:54:30 2001
 10.1836 +     _________________________________________________________________
 10.1837 +
 10.1838 +   7.3 Why do I get the message: CREATE failed: Can't create mailbox node
 10.1839 +   xxxxxxxxx: File exists and how do I fix it?
 10.1840 +
 10.1841 +          See the answer to the Are hierarchical mailboxes supported?
 10.1842 +          question.
 10.1843 +     _________________________________________________________________
 10.1844 +
 10.1845 +   7.4 Why can't I log in to the server? The user name and password are
 10.1846 +   right!
 10.1847 +
 10.1848 +          There are a myriad number of possible answers to this question.
 10.1849 +          The only way to say for sure what is wrong is run the server
 10.1850 +          under a debugger such as gdb while root (yes, you must be root)
 10.1851 +          with a breakpoint at routines checkpw() and loginpw(), then
 10.1852 +          single-step until you see which test rejected you. The server
 10.1853 +          isn't going to give any error messages other than "login
 10.1854 +          failed" in the name of not giving out any unnecessary
 10.1855 +          information to unauthorized individuals.
 10.1856 +
 10.1857 +          Here are some of the more common reasons why login may fail:
 10.1858 +
 10.1859 +          + You didn't really give the correct user name and/or password.
 10.1860 +          + Your client doesn't send the LOGIN command correctly; for
 10.1861 +            example, IMAP2 clients won't send a password containing a "*"
 10.1862 +            correctly to an IMAP4 server.
 10.1863 +          + If you have set up a CRAM-MD5 database, remember that the
 10.1864 +            password used is the one in the CRAM-MD5 database, and
 10.1865 +            furthermore that there must also be an entry in /etc/passwd
 10.1866 +            (but the /etc/passwd password is not used).
 10.1867 +          + If you are using PAM, have you created a service file for the
 10.1868 +            server in /etc/pam.d?
 10.1869 +          + If you are using shadow passwords, have you used an
 10.1870 +            appropriate port when building? In particular, note that
 10.1871 +            "lnx" is for Linux systems without shadow passwords; you
 10.1872 +            probably want "slx" or "lnp" instead.
 10.1873 +          + If your system has account or password expirations, check to
 10.1874 +            see that the expiration date hasn't passed.
 10.1875 +          + You can't log in as root or any other UID 0 user. This is for
 10.1876 +            your own safety, not to mention the fact that the servers use
 10.1877 +            UID 0 as meaning "not logged in".
 10.1878 +     _________________________________________________________________
 10.1879 +
 10.1880 +   7.5 Help! My load average is soaring and I see hundreds of POP and
 10.1881 +   IMAP servers, many logged in as the same user!
 10.1882 +
 10.1883 +          Certain inferior losing GUI mail reading programs have a
 10.1884 +          "synchronize all mailboxes at startup" (IMAP) or "check for new
 10.1885 +          mail every second" (POP) feature which causes a rapid and
 10.1886 +          unchecked spawning of servers.
 10.1887 +
 10.1888 +          This is not a problem in the server; the client is really
 10.1889 +          asking for all those server sessions. Unfortunately, there
 10.1890 +          isn't much that the POP and IMAP servers can do about it; they
 10.1891 +          don't spawned themselves.
 10.1892 +
 10.1893 +          Some sites have added code to record the number of server
 10.1894 +          sessions spawned per user per hour, and disable login for a
 10.1895 +          user who has exceeded a predetermined rate. This doesn't stop
 10.1896 +          the servers from being spawned; it just means that a server
 10.1897 +          session will commit suicide a bit faster.
 10.1898 +
 10.1899 +          Another possibility is to detect excessive server spawning
 10.1900 +          activity at the level where the server is spawned, which would
 10.1901 +          be inetd or possibly tcpd. The problem here is that this is a
 10.1902 +          hard time to quantify. 50 sessions in a minute from a
 10.1903 +          multi-user timesharing system may be perfectly alright, whereas
 10.1904 +          10 sessions a minute from a PC may be too much.
 10.1905 +
 10.1906 +          The real solution is to fix the client configuration, by
 10.1907 +          disabling those evil features. Also tell the vendors of those
 10.1908 +          clients how you feel about distributing denial-of-service
 10.1909 +          attack tools in the guise of mail reading programs.
 10.1910 +     _________________________________________________________________
 10.1911 +
 10.1912 +   7.6 Why does mail disappear even though I set "keep mail on server"?
 10.1913 +   7.7 Why do I get the message Moved ##### bytes of new mail to
 10.1914 +   /home/user/mbox from /var/spool/mail/user and why did this happen?
 10.1915 +
 10.1916 +          This is probably caused by the mbox driver. If the file "mbox"
 10.1917 +          exists on the user's home directory and is in UNIX mailbox
 10.1918 +          format, then when INBOX is opened this file will be selected as
 10.1919 +          INBOX instead of the mail spool file. Messages will be
 10.1920 +          automatically transferred from the mail spool file into the
 10.1921 +          mbox file.
 10.1922 +
 10.1923 +          To disable this behavior, delete "mbox" from the EXTRADRIVERS
 10.1924 +          list in the top-level Makefile and rebuild. Note that if you do
 10.1925 +          this, users won't be able to access the messages that have
 10.1926 +          already been moved to mbox unless they open mbox instead of
 10.1927 +          INBOX.
 10.1928 +     _________________________________________________________________
 10.1929 +
 10.1930 +   7.8 Why isn't it showing the local host name as a fully-qualified
 10.1931 +   domain name?
 10.1932 +   7.9 Why is the local host name in the From/Sender/Message-ID headers
 10.1933 +   of outgoing mail not coming out as a fully-qualified domain name?
 10.1934 +
 10.1935 +          Your UNIX system is misconfigured. The entry for your system in
 10.1936 +          /etc/hosts must have the fully-qualified domain name first,
 10.1937 +          e.g.
 10.1938 +
 10.1939 + 105.69.1.234   myserver.example.com myserver
 10.1940 +
 10.1941 +          A common mistake of novice system administrators is to have the
 10.1942 +          short name first, e.g.
 10.1943 +
 10.1944 + 105.69.1.234   myserver myserver.example.com
 10.1945 +
 10.1946 +          or to omit the fully qualified domain name entirely, e.g.
 10.1947 +
 10.1948 + 105.69.1.234   myserver
 10.1949 +
 10.1950 +          The result of this is that when the IMAP toolkit does a
 10.1951 +          gethostbyname() call to get the fully-qualified domain name, it
 10.1952 +          would get "myserver" instead of "myserver.example.com".
 10.1953 +
 10.1954 +          On some systems, a configuration file (typically named
 10.1955 +          /etc/svc.conf, /etc/netsvc.conf, or /etc/nsswitch.conf) can be
 10.1956 +          used to configure the system to use the domain name system
 10.1957 +          (DNS) instead of /etc/hosts, so it doesn't matter if /etc/hosts
 10.1958 +          is misconfigured.
 10.1959 +
 10.1960 +          Check the man pages for gethostbyname, hosts, svc, and/or
 10.1961 +          netsvc for more information.
 10.1962 +
 10.1963 +          Unfortunately, certain vendors, most notably SUN, have failed
 10.1964 +          to make this clear in their documentation. Most of SUN's
 10.1965 +          documentation assumes a corporate network that is not connected
 10.1966 +          to the Internet.
 10.1967 +
 10.1968 +          net.folklore once (late 1980s) held that the proper procedure
 10.1969 +          was to append the results of getdomainname() to the name
 10.1970 +          returned by gethostname(), and some versions of sendmail
 10.1971 +          configuration files were distributed that did this. This was
 10.1972 +          incorrect; the string returned from getdomainname() is the
 10.1973 +          Yellow Pages (a.k.a NIS) domain name, which is a completely
 10.1974 +          different (albeit unfortunately named) entity from an Internet
 10.1975 +          domain. These were often fortuitously the same string, except
 10.1976 +          when they weren't. Frequently, this would result in host names
 10.1977 +          with spuriously doubled domain names, e.g.
 10.1978 +
 10.1979 + myserver.example.com.example.com
 10.1980 +
 10.1981 +          This practice has been thoroughly discredited for many years,
 10.1982 +          but folklore dies hard.
 10.1983 +     _________________________________________________________________
 10.1984 +
 10.1985 +   7.10 What does the message: Mailbox vulnerable - directory
 10.1986 +   /var/spool/mail must have 1777 protection mean? How can I fix this?
 10.1987 +
 10.1988 +          In order to update a mailbox in the default UNIX format, it is
 10.1989 +          necessary to create a lock file to prevent the mailer from
 10.1990 +          delivering mail while an update is in progress. Some systems
 10.1991 +          use a directory protection of 775, requiring that all mail
 10.1992 +          handling programs be setgid mail; or of 755, requiring that all
 10.1993 +          mail handling programs be setuid root.
 10.1994 +
 10.1995 +          The IMAP toolkit does not run with any special privileges, and
 10.1996 +          I plan to keep it that way. It is antithetical to the concept
 10.1997 +          of a toolkit if users can't write their own programs to use it.
 10.1998 +          Also, I've had enough bad experiences with security bugs while
 10.1999 +          running privileged; the IMAP and POP servers have to be root
 10.2000 +          when not logged in, in order to be able to log themselves in. I
 10.2001 +          don't want to go any deeper down that slippery slope.
 10.2002 +
 10.2003 +          Directory protection 1777 is secure enough on most well-managed
 10.2004 +          systems. If you can't trust your users with a 1777 mail spool
 10.2005 +          (petty harassment is about the limit of the abuse exposure),
 10.2006 +          then you have much worse problems then that.
 10.2007 +
 10.2008 +          If you absolutely insist upon requiring privileges to create a
 10.2009 +          lock file, external file locking can be done via a setgid mail
 10.2010 +          program named /etc/mlock (this is defined by LOCKPGM in the
 10.2011 +          c-client Makefile). If the toolkit is unable to create a
 10.2012 +          <...mailbox...>.lock file in the directory by itself, it will
 10.2013 +          try to call mlock to do it. I do not recommend doing this for
 10.2014 +          performance reasons.
 10.2015 +
 10.2016 +          A sample mlock program is included as part of imap-2007. We
 10.2017 +          have tried to make this sample program secure, but it has not
 10.2018 +          been thoroughly audited.
 10.2019 +     _________________________________________________________________
 10.2020 +
 10.2021 +   7.11 What does the message: Mailbox is open by another process, access
 10.2022 +   is readonly mean? How do I fix this?
 10.2023 +
 10.2024 +          A problem occurred in applying a lock to a /tmp lock file.
 10.2025 +          Either some other program has the mailbox open and won't
 10.2026 +          relenquish it, or something is wrong with the protection of
 10.2027 +          /tmp or the lock.
 10.2028 +
 10.2029 +          Make sure that the /tmp directory is protected 1777. Some
 10.2030 +          security scripts incorrectly set the protection of the /tmp
 10.2031 +          directory to 775, which disables /tmp for all non-privileged
 10.2032 +          programs.
 10.2033 +     _________________________________________________________________
 10.2034 +
 10.2035 +   7.12 What does the message: Can't get write access to mailbox, access
 10.2036 +   is readonly mean?
 10.2037 +
 10.2038 +          The mailbox file is write-protected against you.
 10.2039 +     _________________________________________________________________
 10.2040 +
 10.2041 +   7.13 I set my POP3 client to "delete messages from server" but they
 10.2042 +   never get deleted. What is wrong?
 10.2043 +
 10.2044 +          Make sure that your mailbox is not read-only: that the mailbox
 10.2045 +          is owned by you and write enabled (protection 0600), and that
 10.2046 +          the /tmp directory is longer world-writeable. /tmp must be
 10.2047 +          world-writeable because lots of applications use it for scratch
 10.2048 +          space. To fix this, do
 10.2049 +
 10.2050 +
 10.2051 + chmod 1777 /tmp
 10.2052 +
 10.2053 +          as root.
 10.2054 +
 10.2055 +          Make sure that your POP3 client issues a QUIT command when it
 10.2056 +          finishes. The POP3 protocol specifies that deletions are
 10.2057 +          discarded unless a proper QUIT is done.
 10.2058 +
 10.2059 +          Make sure that you are not opening multiple POP3 sessions to
 10.2060 +          the same mailbox. It is a requirement of the POP3 protocol than
 10.2061 +          only one POP3 session be in effect to a mailbox at a time,
 10.2062 +          however some, poorly-written POP3 clients violate this. Also,
 10.2063 +          some background "check for new mail" tasks also cause a
 10.2064 +          violation. See the answer to the What does the syslog message:
 10.2065 +          Killed (lost mailbox lock) user=... host=... mean? question for
 10.2066 +          more details.
 10.2067 +     _________________________________________________________________
 10.2068 +
 10.2069 +   7.14 What do messages such as:
 10.2070 + Message ... UID ... already has UID ...
 10.2071 + Message ... UID ... less than ...
 10.2072 + Message ... UID ... greater than last ...
 10.2073 + Invalid UID ... in message ..., rebuilding UIDs
 10.2074 +
 10.2075 +   mean?
 10.2076 +
 10.2077 +          Something happened to corrupt the unique identifier regime in
 10.2078 +          the mailbox. In traditional UNIX-format mailboxes, this can
 10.2079 +          happen if the user deleted the "DO NOT DELETE" internal
 10.2080 +          message.
 10.2081 +
 10.2082 +          This problem is relatively harmless; a new valid unique
 10.2083 +          identifier regime will be created. The main effect is that any
 10.2084 +          references to the old UIDs will no longer be useful.
 10.2085 +
 10.2086 +          So, unless it is a chronic problem or you feel like debugging,
 10.2087 +          you can safely ignore these messages.
 10.2088 +     _________________________________________________________________
 10.2089 +
 10.2090 +   7.15 What do the error messages:
 10.2091 + Unable to read internal header at ...
 10.2092 + Unable to find CRLF at ...
 10.2093 + Unable to parse internal header at ...
 10.2094 + Unable to parse message date at ...
 10.2095 + Unable to parse message flags at ...
 10.2096 + Unable to parse message UID at ...
 10.2097 + Unable to parse message size at ...
 10.2098 + Last message (at ... ) runs past end of file ...
 10.2099 +
 10.2100 +   mean? I am using mbx format.
 10.2101 +
 10.2102 +          The mbx-format mailbox is corrupted and needs to be repaired.
 10.2103 +
 10.2104 +          You should make an effort to find out why the corruption
 10.2105 +          happened. Was there an obvious system problem (crash or disk
 10.2106 +          failure)? Did the user accidentally access the file via NFS?
 10.2107 +          Mailboxes don't get corrupted by themselves; something caused
 10.2108 +          the problem.
 10.2109 +
 10.2110 +          Some people have developed automated scripts, but if you're
 10.2111 +          comfortable using emacs it's pretty easy to fix it manually. Do
 10.2112 +          not use vi or any other editor unless you are certain that
 10.2113 +          editor can handle binary!!!
 10.2114 +
 10.2115 +          If you are not comfortable with emacs, or if the file is too
 10.2116 +          large to read with emacs, see the "step-by-step" technique
 10.2117 +          later on for another way of doing it.
 10.2118 +
 10.2119 +          After the word "at" in the error message is the byte position
 10.2120 +          it got to when it got unhappy with the file, e.g. if you see:
 10.2121 +
 10.2122 + Unable to parse internal header at 43921: ne bombastic blurdybloop
 10.2123 +
 10.2124 +          The problem occurs at the 43,931 byte in the file. That's the
 10.2125 +          point you need to fix. c-client is expecting an internal header
 10.2126 +          at that byte number, looking something like:
 10.2127 +
 10.2128 + 6-Jan-1998 17:42:24 -0800,1045;000000100001-00000001
 10.2129 +
 10.2130 +          The format of this internal line is:
 10.2131 +
 10.2132 + dd-mmm-yyyy hh:mm:ss +zzzz,ssss;ffffffffFFFF-UUUUUUUU
 10.2133 +
 10.2134 +          The only thing that is variable is the "ssss" field, it can be
 10.2135 +          as many digits as needed. All other fields (inluding the "dd")
 10.2136 +          are fixed width. So, the easiest thing to do is to look forward
 10.2137 +          in the file for the next internal header, and delete everything
 10.2138 +          from the error point to that internal header.
 10.2139 +
 10.2140 +          Here's what to do if you want to be smarter and do a little bit
 10.2141 +          more work. Generally, you're in the middle of a message, and
 10.2142 +          there's nothing wrong with that message. The problem happened
 10.2143 +          in the *previous* message. So, search back to the previous
 10.2144 +          internal header. Now, remember that "ssss" field? That's the
 10.2145 +          size of that message.
 10.2146 +
 10.2147 +          Mark where you are in the file, move the cursor to the line
 10.2148 +          after the internal header, and skip that many bytes ("ssss")
 10.2149 +          forward. If you're at the point of the error in the file, then
 10.2150 +          that message is corrupt. If you're at a different point, then
 10.2151 +          perhaps the previous message is corrupt and has a too long size
 10.2152 +          count that "ate" into this message.
 10.2153 +
 10.2154 +          Basically, what you need to do is make sure that all those size
 10.2155 +          counts are right, and that moving "ssss" bytes from the line
 10.2156 +          after the internal header will land you at another internal
 10.2157 +          header.
 10.2158 +
 10.2159 +          Usually, once you know what you're looking at, it's pretty easy
 10.2160 +          to work out the corruption, and the best remedial action.
 10.2161 +          Repair scripts will make the problem go away but may not always
 10.2162 +          do the smartest/best salvage of the user's data. Manual repair
 10.2163 +          is more flexible and usually preferable.
 10.2164 +
 10.2165 +          Here is a step-by-step technique for fixing corrupt mbx files
 10.2166 +          that's a bit cruder than the procedure outlined above, but
 10.2167 +          works for any size file.
 10.2168 +
 10.2169 +          In this example, suppose that the corrupt file is INBOX, the
 10.2170 +          error message is
 10.2171 +
 10.2172 + Unable to find CRLF at 132551754
 10.2173 +
 10.2174 +          and the size of the INBOX file is 132867870 bytes.
 10.2175 +
 10.2176 +          The first step is to split the mailbox file at the point of the
 10.2177 +          error:
 10.2178 +
 10.2179 +          + Rename the INBOX file to some other name, such as INBOX.bad.
 10.2180 +          + Copy the first 132,551,754 bytes of INBOX.bad to another
 10.2181 +            file, such as INBOX.new.
 10.2182 +          + Extract the trailing 316,116 bytes (132867870-132551754) of
 10.2183 +            INBOX.bad into another file, such as INBOX.tail.
 10.2184 +          + You no longer need INBOX.bad. Delete it.
 10.2185 +
 10.2186 +          In other words, use the number from the "Unable to find CRLF
 10.2187 +          at" as the point to split INBOX into two new files, INBOX.new
 10.2188 +          and INBOX.tail.
 10.2189 +
 10.2190 +          Now, remove the erroneous data:
 10.2191 +
 10.2192 +          + Verify that you can open INBOX.new in IMAP or Pine.
 10.2193 +          + The last message of INBOX.new is probably corrupted. Copy it
 10.2194 +            to another file, such as badmsg.1, then delete and expunge
 10.2195 +            that last message from INBOX.new
 10.2196 +          + Locate the first occurance of text in INBOX.tail which looks
 10.2197 +            like an internal header, as described above.
 10.2198 +          + Remove all the text which occurs prior to that point, and
 10.2199 +            place it into another file, such as badmsg.2. Note that in
 10.2200 +            the case of a single digit date, there is a leading space
 10.2201 +            which must not be removed (e.g. " 6-Nov-2001" not
 10.2202 +            "6-Nov-2001").
 10.2203 +
 10.2204 +          Reassemble the mailbox:
 10.2205 +
 10.2206 +          + Append INBOX.tail to INBOX.new.
 10.2207 +          + You no longer need INBOX.tail. Delete it.
 10.2208 +          + Verify that you can open INBOX.new in IMAP or Pine.
 10.2209 +
 10.2210 +          Reinstall INBOX.new as INBOX:
 10.2211 +
 10.2212 +          + Check to see if you have received any new messages while
 10.2213 +            repairing INBOX.
 10.2214 +          + If you haven't received any new messages while repairing
 10.2215 +            INBOX, just rename INBOX.new to INBOX.
 10.2216 +          + If you have received new messages, be sure to copy the new
 10.2217 +            messages from INBOX to INBOX.new before doing the rename.
 10.2218 +
 10.2219 +          You now have a working INBOX, as well as two files with
 10.2220 +          corrupted data (badmsg.1 and badmsg.2). There may be some
 10.2221 +          useful data in the two badmsg files that you might want to try
 10.2222 +          salvaging; otherwise you can delete the two badmsg files.
 10.2223 +     _________________________________________________________________
 10.2224 +
 10.2225 +   7.16 What do the syslog messages:
 10.2226 +
 10.2227 + imap/tcp server failing (looping)
 10.2228 + pop3/tcp server failing (looping)
 10.2229 +
 10.2230 +   mean? When it happens, the listed service shuts down. How can I fix
 10.2231 +   this?
 10.2232 +
 10.2233 +          The error message "server failing (looping), service
 10.2234 +          terminated" is not from either the IMAP or POP servers.
 10.2235 +          Instead, it comes from inetd, the daemon which listens for TCP
 10.2236 +          connections to a number of servers, including the IMAP and POP
 10.2237 +          servers.
 10.2238 +
 10.2239 +          inetd has a limit of 40 new server sessions per minute for any
 10.2240 +          particular service. If more than 40 sessions are initiated in a
 10.2241 +          minute, inetd will issue the "failing (looping), service
 10.2242 +          terminated" message and shut down the service for 10 minutes.
 10.2243 +          inetd does this to prevent system resource consumption by a
 10.2244 +          client which is spawning infinite numbers of servers. It should
 10.2245 +          be noted that this is a denial of service; however for some
 10.2246 +          systems the alternative is a crash which would be a worse
 10.2247 +          denial of service!
 10.2248 +
 10.2249 +          For larger server systems, the limit of 40 is much too low. The
 10.2250 +          limit was established many years ago when a system typically
 10.2251 +          only ran a few dozen servers.
 10.2252 +
 10.2253 +          On some versions of inetd, such as the one distributed with
 10.2254 +          most versions of Linux, you can modify the /etc/inetd.conf file
 10.2255 +          to have a larger number of servers by appending a period
 10.2256 +          followed by a number after the nowait word for the server
 10.2257 +          entry. For example, if your existing /etc/inetd.conf line
 10.2258 +          reads:
 10.2259 +
 10.2260 + imap    stream  tcp     nowait  root    /usr/etc/imapd imapd
 10.2261 +
 10.2262 +          try changing it to be:
 10.2263 +
 10.2264 + imap    stream  tcp     nowait.100  root    /usr/etc/imapd imapd
 10.2265 +
 10.2266 +          Another example (using TCP wrappers):
 10.2267 +
 10.2268 + imap    stream  tcp     nowait  root    /usr/sbin/tcpd  imapd
 10.2269 +
 10.2270 +          try changing it to be:
 10.2271 +
 10.2272 + imap    stream  tcp     nowait.100  root    /usr/sbin/tcpd  imapd
 10.2273 +
 10.2274 +          to increase the limit to 100 sessions/minute.
 10.2275 +
 10.2276 +          Before making this change, please read the information in "man
 10.2277 +          inetd" to determine whether or not your inetd has this feature.
 10.2278 +          If it does not, and you make this change, the likely outcome is
 10.2279 +          that you will disable IMAP service entirely.
 10.2280 +
 10.2281 +          Another way to fix this problem is to edit the inetd.c source
 10.2282 +          code (provided by your UNIX system vendor) to set higher
 10.2283 +          limits, rebuild inetd, install the new binary, and reboot your
 10.2284 +          system. This should only be done by a UNIX system expert. In
 10.2285 +          the inetd.c source code, the limits TOOMANY (normally 40) is
 10.2286 +          the maximum number of new server sessions permitted per minute,
 10.2287 +          and RETRYTIME (normally 600) is the number of seconds inetd
 10.2288 +          will shut down the server after it exceeds TOOMANY.
 10.2289 +     _________________________________________________________________
 10.2290 +
 10.2291 +   7.17 What does the syslog message: Mailbox lock file /tmp/.600.1df3
 10.2292 +   open failure: Permission denied mean?
 10.2293 +
 10.2294 +          This usually means that some "helpful" security script person
 10.2295 +          has protected /tmp so that it is no longer world-writeable.
 10.2296 +          /tmp must be world-writeable because lots of applications use
 10.2297 +          it for scratch space. To fix this, do
 10.2298 +
 10.2299 + chmod 1777 /tmp
 10.2300 +
 10.2301 +          as root.
 10.2302 +
 10.2303 +          If that isn't the answer, check the protection of the named
 10.2304 +          file. If it is something other than 666, then either someone is
 10.2305 +          hacking or some "helpful" person modified the code to have a
 10.2306 +          different default lock file protection.
 10.2307 +     _________________________________________________________________
 10.2308 +
 10.2309 +   7.18 What do the syslog messages:
 10.2310 + Command stream end of file, while reading line user=... host=...
 10.2311 + Command stream end of file, while reading char user=... host=...
 10.2312 + Command stream end of file, while writing text user=... host=...
 10.2313 +
 10.2314 +   mean?
 10.2315 +
 10.2316 +          This message occurs when the session is disconnected without a
 10.2317 +          proper LOGOUT (IMAP) or QUIT (POP) command being received by
 10.2318 +          the server first.
 10.2319 +
 10.2320 +          In many cases, this is perfectly normal; many client
 10.2321 +          implementations are impolite and do this. Some programmers
 10.2322 +          think this sort of rudeness is "more efficient".
 10.2323 +
 10.2324 +          The condition could, however, indicate a client or network
 10.2325 +          connectivity problem. The server has no way of knowing whether
 10.2326 +          there's a problem or just a rude client, so it issues this
 10.2327 +          message instead of a Logout.
 10.2328 +
 10.2329 +          Certain inferior losing clients disconnect abruptly after a
 10.2330 +          failed login, and instead of saying that the login failed, just
 10.2331 +          say that they can't access the mailbox. They then complain to
 10.2332 +          the system manager, who looks in the syslog and finds this
 10.2333 +          message. Not very helpful, eh? See the answer to the Why can't
 10.2334 +          I log in to the server? The user name and password are right!
 10.2335 +          question.
 10.2336 +
 10.2337 +          If the user isn't reporting a problem, you can probably ignore
 10.2338 +          this message.
 10.2339 +     _________________________________________________________________
 10.2340 +
 10.2341 +   7.19 Why did my POP or IMAP session suddenly disconnect? The syslog
 10.2342 +   has the message: Killed (lost mailbox lock) user=... host=...
 10.2343 +
 10.2344 +          This message only happens when either the traditional UNIX
 10.2345 +          mailbox format or MMDF format is in use. This format only
 10.2346 +          allows one session to have the mailbox open read/write at a
 10.2347 +          time.
 10.2348 +
 10.2349 +          The servers assume that if a second session attempts to open
 10.2350 +          the mailbox, that means that the first session is probably
 10.2351 +          owned by an abandoned client. The common scenario here is a
 10.2352 +          user who leaves his client running at the office, and then
 10.2353 +          tries to read his mail from home. Through an internal mechanism
 10.2354 +          called kiss of death, the second session requests the first
 10.2355 +          session to kill itself. When the first session receives the
 10.2356 +          "kiss of death", it issues the "Killed (lost mailbox lock)"
 10.2357 +          syslog message and terminates. The second session then seizes
 10.2358 +          read/write access, and becomes the new "first" session.
 10.2359 +
 10.2360 +          Certain poorly-designed clients routinely open multiple
 10.2361 +          sessions to the same mailbox; the users of those clients tend
 10.2362 +          to get this message a lot.
 10.2363 +
 10.2364 +          Another cause of this message is a background "check for new
 10.2365 +          mail" task which does its work by opening a POP session to
 10.2366 +          server every few seconds. They do this because POP doesn't have
 10.2367 +          a way to announce new mail.
 10.2368 +
 10.2369 +          The solution to both situations is to replace the client with a
 10.2370 +          good online IMAP client such as Pine. Life is too short to
 10.2371 +          waste on POP clients and poorly-designed IMAP clients.
 10.2372 +     _________________________________________________________________
 10.2373 +
 10.2374 +   7.20 Why does my IMAP client show all the files on the system,
 10.2375 +   recursively from the UNIX root directory?
 10.2376 +   7.21 Why does my IMAP client show all of my files, recursively from my
 10.2377 +   UNIX home directory?
 10.2378 +
 10.2379 +          A well-written client should only show one level of hierarchy
 10.2380 +          and then stop, awaiting explicit user action before going
 10.2381 +          lower. However, some poorly-designed clients will recursively
 10.2382 +          list all files, which may be a very long list (especially if
 10.2383 +          you have symbolic links to directories that create a loop in
 10.2384 +          the filesystem graph!).
 10.2385 +
 10.2386 +          This behavior has also been observed in some third-party
 10.2387 +          c-client drivers, including maildir drivers. Consequently, this
 10.2388 +          problem has even been observed in Pine. It is important to
 10.2389 +          understand that this is not a problem in Pine or c-client; it
 10.2390 +          is a problem in the third-party driver. A Pine built without
 10.2391 +          that third-party driver will not have this problem.
 10.2392 +
 10.2393 +          See also the answer to Why does my IMAP client show all my
 10.2394 +          files in my home directory?
 10.2395 +     _________________________________________________________________
 10.2396 +
 10.2397 +   7.22 Why does my IMAP client show that I have mailboxes named
 10.2398 +   "#mhinbox", "#mh", "#shared", "#ftp", "#news", and "#public"?
 10.2399 +
 10.2400 +          These are IMAP namespace names. They represent other
 10.2401 +          hierarchies in which messages may exist. These hierarchies may
 10.2402 +          not necessarily exist on a server, but the namespace name is
 10.2403 +          still in the namespace list in order to mark it as reserved.
 10.2404 +
 10.2405 +          A few poorly-designed clients display all namespace names as if
 10.2406 +          they were top-level mailboxes in a user's list of mailboxes,
 10.2407 +          whether or not they actually exist. This is a flaw in those
 10.2408 +          clients.
 10.2409 +     _________________________________________________________________
 10.2410 +
 10.2411 +   7.23 Why does my IMAP client show all my files in my home directory?
 10.2412 +
 10.2413 +          As distributed, the IMAP server is connected to your home
 10.2414 +          directory by default. It has no way of knowing what you might
 10.2415 +          call "mail" as opposed to "some other file"; in fact, you can
 10.2416 +          use IMAP to access any file.
 10.2417 +
 10.2418 +          Most clients have an option to configure your connected
 10.2419 +          directory on the IMAP server. For example, in Pine you can
 10.2420 +          specify this as the "Path" in your folder-collection, e.g.
 10.2421 +
 10.2422 + Nickname  : Secondary Folders
 10.2423 + Server    : imap.example.com
 10.2424 + Path      : mail/
 10.2425 + View      :
 10.2426 +
 10.2427 +          In this example, the user is connected to the "mail"
 10.2428 +          subdirectory of his home directory.
 10.2429 +
 10.2430 +          Other servers call this the "folder prefix" or similar term.
 10.2431 +
 10.2432 +          It is possible to modify the IMAP server so that all users are
 10.2433 +          automatically connected to some other directory, e.g. a
 10.2434 +          subdirectory of the user's home directory. Read the file CONFIG
 10.2435 +          for more details.
 10.2436 +     _________________________________________________________________
 10.2437 +
 10.2438 +   7.24 Why is there a long delay before I get connected to the IMAP or
 10.2439 +   POP server, no matter what client I use?
 10.2440 +
 10.2441 +          There are two common occurances of this problem:
 10.2442 +
 10.2443 +          + You are running a system (e.g. certain versions of Linux)
 10.2444 +            which by default attempts to connect to an "IDENT" protocol
 10.2445 +            (port 113) server on your client. However, a firewall or NAT
 10.2446 +            box is blocking connections to that port, so the connection
 10.2447 +            attempt times out.
 10.2448 +            The IDENT protocol is a well-known bad idea that does not
 10.2449 +            deliver any real security but causes incredible problems. The
 10.2450 +            idea is that this will give the server a record of the user
 10.2451 +            name, or at least what some program listening on port 113
 10.2452 +            says is the user name. So, if somebody coming from port nnnnn
 10.2453 +            on a system does something bad, IDENT may give you the userid
 10.2454 +            of the bad guy.
 10.2455 +            The problem is, IDENT is only meaningful on a timesharing
 10.2456 +            system which has an administrator who is privileged and users
 10.2457 +            who are not. It is of no value on a personal system which has
 10.2458 +            no separate concept of "system administrator" vs.
 10.2459 +            "unprivileged user".
 10.2460 +            On either type of system, security-minded people either turn
 10.2461 +            IDENT off or replace it with an IDENT server that lies. Among
 10.2462 +            other things, IDENT gives spammers the ability to harvest
 10.2463 +            email addresses from anyone who connects to a web page.
 10.2464 +            This problem has been showing up quite frequently on systems
 10.2465 +            which use xinetd instead of inetd. Look for files named
 10.2466 +            /etc/xinetd.conf, /etc/xinetd.d/imapd, /etc/inetd.d/ipop2d,
 10.2467 +            and /etc/xinetd.d/ipop3d. In those files, look for lines
 10.2468 +            containing "USERID", e.g.
 10.2469 + log_on_success += USERID
 10.2470 +            Hunt down such lines, and delete them ruthlessly from all
 10.2471 +            files in which they occur. Don't be shy about it.
 10.2472 +          + The DNS is taking a long time to do a reverse DNS (PTR
 10.2473 +            record) lookup of the IP address of your client. This is a
 10.2474 +            problem in your DNS, which either you or you ISP need to
 10.2475 +            resolve. Ideally, the DNS should return the client's name;
 10.2476 +            but if it can't it should at least return an error quickly.
 10.2477 +
 10.2478 +          As you may have noticed, neither of these are actual problems
 10.2479 +          in the IMAP or POP servers; they are configuration issues with
 10.2480 +          either your system or your network infrastructure. If this is
 10.2481 +          all new to you, run (don't walk) to the nearest technical
 10.2482 +          bookstore and get yourself a good pedagogical text on system
 10.2483 +          administration for the type of system you are running.
 10.2484 +     _________________________________________________________________
 10.2485 +
 10.2486 +   7.25 Why is there a long delay in Pine or any other c-client based
 10.2487 +   application call before I get connected to the IMAP server? The hang
 10.2488 +   seems to be in the c-client mail_open() call. I don't have this
 10.2489 +   problem with any other IMAP client. There is no delay connecting to a
 10.2490 +   POP3 or NNTP server with mail_open().
 10.2491 +
 10.2492 +          By default, the c-client library attempts to make a connection
 10.2493 +          through rsh (and ssh, if you enable that). If the command:
 10.2494 +
 10.2495 + rsh imapserver exec /etc/rimapd
 10.2496 +
 10.2497 +          (or ssh if that is enabled) returns with a "* PREAUTH"
 10.2498 +          response, it will use the resulting rsh session as the IMAP
 10.2499 +          session and not require an authentication step on the server.
 10.2500 +
 10.2501 +          Unfortunately, rsh has a design error that treats "TCP
 10.2502 +          connection refused" as "temporary failure, try again"; it
 10.2503 +          expects the "rsh not allowed" case to be implemented as a
 10.2504 +          successful connection followed by an error message and close
 10.2505 +          the connection.
 10.2506 +
 10.2507 +          It must be emphasized that this is a bug in rsh. It is not a
 10.2508 +          bug in the IMAP toolkit.
 10.2509 +
 10.2510 +          The use of rsh can be disabled in any the following ways:
 10.2511 +
 10.2512 +          + You can disable it for this particular session by either:
 10.2513 +               o setting an explicit port number in the mailbox name,
 10.2514 +                 e.g.
 10.2515 + {imapserver.foo.com:143}INBOX
 10.2516 +               o using SSL (the /ssl switch)
 10.2517 +          + You can disable rsh globally by setting the rsh timeout value
 10.2518 +            to 0 with the call:
 10.2519 + mail_parameters (NIL,SET_RSHTIMEOUT,0);
 10.2520 +     _________________________________________________________________
 10.2521 +
 10.2522 +   7.26 Why does a message sometimes get split into two or more messages
 10.2523 +   on my SUN system?
 10.2524 +
 10.2525 +          This is caused by an interaction of two independent design
 10.2526 +          problems in SUN mail software. The first problem is that the
 10.2527 +          "forward message" option in SUN's mail tool program includes
 10.2528 +          the internal "From " header line in the text that it forwarded.
 10.2529 +          This internal header line is specific to traditional UNIX
 10.2530 +          mailbox files and is not suitable for use in forwarded
 10.2531 +          messages.
 10.2532 +
 10.2533 +          The second problem is that the mail delivery agent assumes that
 10.2534 +          mail reading programs will not use the traditional UNIX mailbox
 10.2535 +          format but instead an incompatible variant that depends upon a
 10.2536 +          Content-Length: message header. Content-Length is widely
 10.2537 +          recognized to have been a terrible mistake, and is no longer
 10.2538 +          recommended for use in mail (it is used in other facilities
 10.2539 +          that use MIME).
 10.2540 +
 10.2541 +          One symptom of the problem is that under certain circumstances,
 10.2542 +          a message may get broken up into several messages. I'm also
 10.2543 +          aware of security bugs caused by programs that foolishly trust
 10.2544 +          "Content-Length:" headers with evil values.
 10.2545 +
 10.2546 +          To fix the mailer on your system, edit your sendmail.cf to
 10.2547 +          change the Mlocal line to have the -E flag. A typical entry
 10.2548 +          will lool like:
 10.2549 +
 10.2550 + Mlocal,        P=/usr/lib/mail.local, F=flsSDFMmnPE, S=10, R=20,
 10.2551 +                A=mail.local -d $u
 10.2552 +
 10.2553 +          This fix will also work around the problem with mail tool,
 10.2554 +          because it will insert a ">" before the internal header line to
 10.2555 +          prevent it from being interpreted by mail reading software as
 10.2556 +          an internal header line.
 10.2557 +     _________________________________________________________________
 10.2558 +
 10.2559 +   7.27 Why did my POP or IMAP session suddenly disconnect? The syslog
 10.2560 +   has the message:
 10.2561 + Autologout user=<...my user name...> host=<...my client system...>
 10.2562 +
 10.2563 +          This is a problem in your client.
 10.2564 +
 10.2565 +          In the case of IMAP, it failed to communicate with the IMAP
 10.2566 +          server for over 30 minutes; in the case of POP, it failed to
 10.2567 +          communicate with the POP server for over 10 minutes.
 10.2568 +     _________________________________________________________________
 10.2569 +
 10.2570 +   7.28 What does the UNIX error message: TLS/SSL failure: myserver: SSL
 10.2571 +   negotiation failed mean?
 10.2572 +   7.29 What does the PC error message: TLS/SSL failure: myserver:
 10.2573 +   Unexpected TCP input disconnect mean?
 10.2574 +
 10.2575 +          This usually means that an attempt to negotiate TLS encryption
 10.2576 +          via the STARTTLS command failed, because the server advertises
 10.2577 +          STARTTLS functionality, but doesn't actually have it (e.g.
 10.2578 +          because no certificates are installed).
 10.2579 +
 10.2580 +          Use the /notls option in the mailbox name to disable TLS
 10.2581 +          negotiation.
 10.2582 +     _________________________________________________________________
 10.2583 +
 10.2584 +   7.30 What does the error message: TLS/SSL failure: myserver: Server
 10.2585 +   name does not match certificate mean?
 10.2586 +
 10.2587 +          An SSL or TLS session encryption failed because the server name
 10.2588 +          in the server's certificate does not match the name that you
 10.2589 +          gave it. This could indicate that the server is not really the
 10.2590 +          system you think that it is, but can be also be called if you
 10.2591 +          gave a nickname for the server or name that was not
 10.2592 +          fully-qualified. You must use the fully-qualified domain name
 10.2593 +          for the server in order to validate its certificate
 10.2594 +
 10.2595 +          Use the /novalidate-cert option in the mailbox name to disable
 10.2596 +          validation of the certificate.
 10.2597 +     _________________________________________________________________
 10.2598 +
 10.2599 +   7.31 What does the UNIX error message: TLS/SSL failure: myserver:
 10.2600 +   self-signed certificate mean?
 10.2601 +   7.32 What does the PC error message: TLS/SSL failure: myserver:
 10.2602 +   Self-signed certificate or untrusted authority mean?
 10.2603 +
 10.2604 +          An SSL or TLS session encryption failed because your server's
 10.2605 +          certificate is "self-signed"; that is, it is not signed by any
 10.2606 +          Certificate Authority (CA) and thus can not be validated. A
 10.2607 +          CA-signed certificate costs money, and some smaller sites
 10.2608 +          either don't want to pay for it or haven't gotten one yet. The
 10.2609 +          bad part about this is that this means there is no guarantee
 10.2610 +          that the server is really the system you think that it is.
 10.2611 +
 10.2612 +          Use the /novalidate-cert option in the mailbox name to disable
 10.2613 +          validation of the certificate.
 10.2614 +     _________________________________________________________________
 10.2615 +
 10.2616 +   7.33 What does the UNIX error message: TLS/SSL failure: myserver:
 10.2617 +   unable to get local issuer certificate mean?
 10.2618 +
 10.2619 +          An SSL or TLS session encryption failed because your system
 10.2620 +          does not have the Certificate Authority (CA) certificates
 10.2621 +          installed on OpenSSL's certificates directory. On most systems,
 10.2622 +          this directory is /usr/local/ssl/certs). As a result, it is not
 10.2623 +          possible to validate the server's certificate.
 10.2624 +
 10.2625 +          If CA certificates are properly installed, you should see
 10.2626 +          factory.pem and about a dozen other .pem names such as
 10.2627 +          thawteCb.pem.
 10.2628 +
 10.2629 +          As a workaround, you can use the /novalidate-cert option in the
 10.2630 +          mailbox name to disable validation of the certificate; however,
 10.2631 +          note that you are then vulnerable to various security attacks
 10.2632 +          by bad guys.
 10.2633 +
 10.2634 +          The correct fix is to copy all the files from the certs/
 10.2635 +          directory in the OpenSSL distribution to the
 10.2636 +          /usr/local/ssl/certs (or whatever) directory. Note that you
 10.2637 +          need to do this after building OpenSSL, because the OpenSSL
 10.2638 +          build creates a number of needed symbolic links. For some
 10.2639 +          bizarre reason, the OpenSSL "make install" doesn't do this for
 10.2640 +          you, so you must do it manually.
 10.2641 +     _________________________________________________________________
 10.2642 +
 10.2643 +   7.34 Why does reading certain messages hang when using Netscape? It
 10.2644 +   works fine with Pine!
 10.2645 +
 10.2646 +          There are two possible causes.
 10.2647 +
 10.2648 +          Check the mail syslog. If you see the message "Killed (lost
 10.2649 +          mailbox lock)" for the impacted user(s), read the FAQ entry
 10.2650 +          regarding that message.
 10.2651 +
 10.2652 +          Check the affected mailbox to see if there are embedded NUL
 10.2653 +          characters in the message. NULs in message texts are a
 10.2654 +          technical violation of both the message format and IMAP
 10.2655 +          specifications. Most clients don't care, but apparently
 10.2656 +          Netscape does.
 10.2657 +
 10.2658 +          You can work around this by rebuilding imapd with the
 10.2659 +          NETSCAPE_BRAIN_DAMAGE option set (see src/imapd/Makefile); this
 10.2660 +          will cause imapd to convert all NULs to 0x80 characters. A
 10.2661 +          better solution is to enable the feature in your MTA to
 10.2662 +          MIME-convert messages with binary content. See the
 10.2663 +          documentation for your MTA for how to do this.
 10.2664 +     _________________________________________________________________
 10.2665 +
 10.2666 +   7.35 Why does Netscape say that there's a problem with the IMAP server
 10.2667 +   and that I should "Contact your mail server administrator."?
 10.2668 +
 10.2669 +          Certain versions of Netscape do this when you click the Manage
 10.2670 +          Mail button, which uses an undocumented feature of Netscape's
 10.2671 +          proprietary IMAP server.
 10.2672 +
 10.2673 +          You can work around this by rebuilding imapd with the
 10.2674 +          NETSCAPE_BRAIN_DAMAGE option set (see src/imapd/Makefile) to a
 10.2675 +          URL that points either to an alternative IMAP client (e.g.
 10.2676 +          Pine) or perhaps to a homebrew mail account management page.
 10.2677 +     _________________________________________________________________
 10.2678 +
 10.2679 +   7.36 Why is one user creating huge numbers of IMAP or POP server
 10.2680 +   sessions?
 10.2681 +
 10.2682 +          The user is probably using Outlook Express, Eudora, or a
 10.2683 +          similar program. See the answer to the Help! My load average is
 10.2684 +          soaring and I see hundreds of POP and IMAP servers, many logged
 10.2685 +          in as the same user! question.
 10.2686 +     _________________________________________________________________
 10.2687 +
 10.2688 +   7.37 Why don't I get any new mail notifications from Outlook Express
 10.2689 +   or Outlook after a while?
 10.2690 +
 10.2691 +          This is a known bug in Outlook Express. Microsoft is aware of
 10.2692 +          the problem and its cause. They have informed us that they do
 10.2693 +          not have any plans to fix it at the present time.
 10.2694 +
 10.2695 +          The problem is also reported in Outlook 2000, but not verified.
 10.2696 +
 10.2697 +          Outlook Express uses the IMAP IDLE command to avoid having to
 10.2698 +          "ping" the server every few minutes for new mail.
 10.2699 +          Unfortunately, Outlook Express overlooks the part in the IDLE
 10.2700 +          specification which requires that a client terminate and
 10.2701 +          restart the IDLE before the IMAP 30 minute inactivity
 10.2702 +          autologout timer triggers.
 10.2703 +
 10.2704 +          When this happens, Outlook Express displays "Not connected" at
 10.2705 +          the bottom of the window. Since it's no longer connected to the
 10.2706 +          IMAP server, it isn't going to notice any new mail.
 10.2707 +
 10.2708 +          As soon as the user does anything that would cause an IMAP
 10.2709 +          operation, Outlook Express will reconnect and new mail will
 10.2710 +          flow again. If the user does something that causes an IMAP
 10.2711 +          operation at least every 29 minutes, the problem won't happen.
 10.2712 +
 10.2713 +          Modern versions of imapd attempt to work around the problem by
 10.2714 +          automatically reporting fake new mail after 29 minutes. This
 10.2715 +          causes Outlook Express to exit the IDLE state; as soon as this
 10.2716 +          happens imapd revokes the fake new mail. As long as this
 10.2717 +          behavior isn't known to cause problems with other clients, this
 10.2718 +          workaround will remain in imapd.
 10.2719 +     _________________________________________________________________
 10.2720 +
 10.2721 +   7.38 Why don't I get any new mail notifications from Entourage?
 10.2722 +
 10.2723 +          This is a known bug in Entourage.
 10.2724 +
 10.2725 +          You built an older version of imapd with the
 10.2726 +          MICROSOFT_BRAIN_DAMAGE option set, in order to disable support
 10.2727 +          for the IDLE command. However, Entourage won't get new mail
 10.2728 +          unless IDLE command support exists.
 10.2729 +
 10.2730 +          Note: the MICROSOFT_BRAIN_DAMAGE option no longer exists in
 10.2731 +          modern versions, as the Outlook Express problem which it
 10.2732 +          attempted to solve has been worked around in another way.
 10.2733 +     _________________________________________________________________
 10.2734 +
 10.2735 +   7.39 Why doesn't Entourage work at all?
 10.2736 +
 10.2737 +          It's hard to know. Entourage breaks almost every rule in the
 10.2738 +          book for IMAP. It is highly instructive to do a packet trace on
 10.2739 +          Entourage, as an example of how not to use IMAP. It does things
 10.2740 +          like STATUS (MESSAGES) on the currently selected mailbox and
 10.2741 +          re-fetching the same static data over and over again.
 10.2742 +
 10.2743 +          It seems that every time we understand what it is doing wrong
 10.2744 +          in Entourage and come up with a workaround, we learn about
 10.2745 +          something else that's broken.
 10.2746 +
 10.2747 +          Try building imapd with the ENTOURAGE_BRAIN_DAMAGE option set,
 10.2748 +          in order to disable the diagnostic that occurs when doing
 10.2749 +          STATUS on the currently selected mailbox.
 10.2750 +     _________________________________________________________________
 10.2751 +
 10.2752 +   7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE) work at all?
 10.2753 +
 10.2754 +          This is a bug in NSNOTIFY; it doesn't handle unsolicited data
 10.2755 +          from the server correctly.
 10.2756 +
 10.2757 +          Fortunately, there is no reason to use this program with IMAP;
 10.2758 +          NSNOTIFY is a polling program to let you know when new mail has
 10.2759 +          appeared in your maildrop. This is necessary with POP; but
 10.2760 +          since IMAP dynamically announces new mail in the session you're
 10.2761 +          better off (and will actually cause less load on the server!)
 10.2762 +          keeping your mail reading program's IMAP session open and let
 10.2763 +          IMAP do the notifying for you.
 10.2764 +
 10.2765 +          Consequently, the recommended fix for the NSNOTIFY problem is
 10.2766 +          to delete the NSNOTIFY binary.
 10.2767 +     _________________________________________________________________
 10.2768 +
 10.2769 +   7.41 Why can't I connect via SSL to Eudora? It says the connection has
 10.2770 +   been broken, and in the server syslogs I see "Command stream end of
 10.2771 +   file".
 10.2772 +
 10.2773 +          There is a report that you can fix the problem by going into
 10.2774 +          Eudora's advanced network configuration menu and increasing the
 10.2775 +          network buffer size to 8192.
 10.2776 +     _________________________________________________________________
 10.2777 +
 10.2778 +   7.42 Sheesh. Aren't there any good IMAP clients out there?
 10.2779 +
 10.2780 +          Yes!
 10.2781 +
 10.2782 +          Pine is a wonderful client. It's fast, it uses IMAP well, and
 10.2783 +          it generates text mail (life is too short to waste on HTML
 10.2784 +          mail). Also, there are some really wonderful things in progress
 10.2785 +          in the Pine world.
 10.2786 +
 10.2787 +          There are some good GUI clients out there, mostly from smaller
 10.2788 +          vendors. Without naming names, look for the vendors who are
 10.2789 +          active in the IMAP protocol development community, and their
 10.2790 +          products.
 10.2791 +
 10.2792 +          Netscape, Eudora, and Outlook can be configured with enough
 10.2793 +          effort to be good citizens and work well for users, but they
 10.2794 +          can also be badly misconfigured, and often the misconfiguration
 10.2795 +          is the default.
 10.2796 +     _________________________________________________________________
 10.2797 +
 10.2798 +   7.43 But wait! PC Pine (or other PC program build with c-client)
 10.2799 +   crashes with the message incomplete SecBuffer exceeds maximum buffer
 10.2800 +   size when I use SSL connections. This is a bug in c-client, right?
 10.2801 +
 10.2802 +          It's a bug in the Microsoft SChannel.DLL, which implements SSL.
 10.2803 +          Microsoft admits it (albeit with an unstatement: "it's not
 10.2804 +          fully RFC compliant"). The problem is that SChannel indicates
 10.2805 +          that the maximum SSL packet data size is 5 bytes smaller than
 10.2806 +          the actual maximum. Thus, any IMAP server which transmits a
 10.2807 +          maximum sized SSL packet will not work with PC Pine or any
 10.2808 +          other program which uses SChannel.
 10.2809 +
 10.2810 +          It can take a while for the problem to show up. The client has
 10.2811 +          to do something that causes at least 16K of contiguous data.
 10.2812 +          Many clients do partial fetching, which tends to reduce the
 10.2813 +          number of cases where this can happen. However, all software
 10.2814 +          which uses SChannel to support SSL is affected by this bug.
 10.2815 +
 10.2816 +          This problem does not affect UNIX code, since OpenSSL is used
 10.2817 +          on UNIX.
 10.2818 +
 10.2819 +          This problem most recently showed up with the CommunigatePro
 10.2820 +          IMAP server. They have an update which trims down their maximum
 10.2821 +          contiguous data to less than 16K, in order to work around the
 10.2822 +          problem.
 10.2823 +
 10.2824 +          This problem has also shown up with the Exchange IMAP server
 10.2825 +          with UNIX clients (including Pine built with an older version
 10.2826 +          of c-client) which sends full-sized 16K SSL packets. Modern
 10.2827 +          c-client works around the problem by trimming down its maximum
 10.2828 +          outgoing SSL packet size to 8K.
 10.2829 +
 10.2830 +          Microsoft has developed a hotfix for this bug. Look up MSKB
 10.2831 +          article number 300562. Contrary to the article text which
 10.2832 +          implies that this is a Pine issue, this bug also affect
 10.2833 +          Microsoft Exchange server with *any* UNIX based client that
 10.2834 +          transmits full-sized SSL payloads.
 10.2835 +     _________________________________________________________________
 10.2836 +
 10.2837 +   7.44 My qpopper users keep on getting the DON'T DELETE THIS MESSAGE --
 10.2838 +   FOLDER INTERNAL DATA if they also use Pine or IMAP. How can I fix
 10.2839 +   this?
 10.2840 +
 10.2841 +          This is an incompatibility between qpopper and the c-client
 10.2842 +          library used by Pine, imapd, and ipop[23]d.
 10.2843 +
 10.2844 +          Assuming that you want to continue using qpopper, look into
 10.2845 +          qpopper's --enable-uw-kludge-flag configuration flag, which is
 10.2846 +          documented as "check for and hide UW 'Folder Internal Data'
 10.2847 +          messages".
 10.2848 +
 10.2849 +          The other alternative is to switch from qpopper to ipop3d.
 10.2850 +     _________________________________________________________________
 10.2851 +
 10.2852 +   7.45 Help! I installed the servers but I can't connect to them from my
 10.2853 +   client!
 10.2854 +
 10.2855 +          Review the installation instructions carefully. Make sure that
 10.2856 +          you have not skipped any of the steps. Make sure that you have
 10.2857 +          made the correct entries in the configuration files; pay
 10.2858 +          careful attention to the exact spelling of the service names
 10.2859 +          and the path names. Make sure as well that you have properly
 10.2860 +          restarted inetd.
 10.2861 +
 10.2862 +          If you have a system with Yellow Pages/NIS such as Solaris,
 10.2863 +          have you updated the service names there as well as in
 10.2864 +          /etc/services?
 10.2865 +
 10.2866 +          If you have a system with TCP wrappers, have you properly
 10.2867 +          updated the TCP wrapper files (e.g. /etc/hosts.allow and
 10.2868 +          /etc/hosts.deny) for the servers?
 10.2869 +
 10.2870 +          If you have a system which uses xinetd instead of inetd, have
 10.2871 +          you made sure that you have made the correct corresponding
 10.2872 +          xinetd changes for those services?
 10.2873 +
 10.2874 +          Try telneting to the server port (143 for IMAP, 110 for POP3).
 10.2875 +          If you get a "refused" error, that probably means that you
 10.2876 +          don't have the service set up in inetd.conf. If the connection
 10.2877 +          opens and then closes with no message, the service is set up,
 10.2878 +          but either the path name of the server binary in inetd.conf is
 10.2879 +          wrong or your TCP wrappers are configured to deny access.
 10.2880 +
 10.2881 +          If you don't know how to make the corresponding changes to
 10.2882 +          these files, seek the help of a local expert for your system.
 10.2883 +     _________________________________________________________________
 10.2884 +
 10.2885 +   7.46 Why do I get the message Can not authenticate to SMTP server: 421
 10.2886 +   SMTP connection went away! and why did this happen? There was also
 10.2887 +   something about SECURITY PROBLEM: insecure server advertised
 10.2888 +   AUTH=PLAIN
 10.2889 +
 10.2890 +          Some versions of qmail, including that running on
 10.2891 +          mail.smtp.yahoo.com, disconnect the SMTP session if you fail to
 10.2892 +          authenticate prior to attempting to transmit mail. An attempt
 10.2893 +          to authenticate was made, but it failed because the server had
 10.2894 +          already disconnected.
 10.2895 +
 10.2896 +          To work around this, you need to specify /user=... in the host
 10.2897 +          name specification.
 10.2898 +
 10.2899 +          The SECURITY PROBLEM came about because the server advertised
 10.2900 +          the AUTH=PLAIN SASL authentication mechanism outside of a
 10.2901 +          TLS-encrypted session, in violation of RFC 4616. This message
 10.2902 +          is just a warning, and in fact occurred after the server had
 10.2903 +          disconnected.
 10.2904 +     _________________________________________________________________
 10.2905 +
 10.2906 +   7.47 Why do I get the message SMTP Authentication cancelled and why
 10.2907 +   did this happen? There was also something about SECURITY PROBLEM:
 10.2908 +   insecure server advertised AUTH=PLAIN
 10.2909 +
 10.2910 +          This is a bug in the SMTP server.
 10.2911 +
 10.2912 +          Some versions of qmail, including that running on
 10.2913 +          mail.smtp.yahoo.com, have a bug in their implementation of SASL
 10.2914 +          in their SMTP server, which renders it non-compliant with the
 10.2915 +          standard.
 10.2916 +
 10.2917 +          If the client does not provide an initial response in the
 10.2918 +          command line for an authentication mechanism whose profile does
 10.2919 +          not have an initial challenge, qmail issues a bogus response:
 10.2920 +
 10.2921 + 334 ok, go on
 10.2922 +
 10.2923 +          The problem is the "ok, go on". This violates RFC 4954's
 10.2924 +          requirement that the text part in a 334 response be a BASE64
 10.2925 +          encoded string; in other words, it is a protocol syntax error.
 10.2926 +
 10.2927 +          In the case of AUTH=PLAIN, RFC 4422 (page 7) requires that the
 10.2928 +          encoded string have no data. In other words, the appropropiate
 10.2929 +          standards-compliant server response is "334" followed by a
 10.2930 +          SPACE and a CRLF.
 10.2931 +
 10.2932 +          The SECURITY PROBLEM came about because the server advertised
 10.2933 +          the AUTH=PLAIN SASL authentication mechanism outside of a
 10.2934 +          TLS-encrypted session, in violation of RFC 4616. This message
 10.2935 +          is just a warning, and is not related the "Authentication
 10.2936 +          cancelled" problem.
 10.2937 +     _________________________________________________________________
 10.2938 +
 10.2939 +   7.48 Why do I get the message Invalid base64 string when I try to
 10.2940 +   authenticate to a Cyrus server?
 10.2941 +
 10.2942 +          This slightly misleading message is the way that a Cyrus server
 10.2943 +          indicates that an authentication exchange was cancelled. It is
 10.2944 +          not indicative of a bug or protocol violation.
 10.2945 +
 10.2946 +          The most common reason that this happens is if the Cyrus server
 10.2947 +          offers Kerberos authentication, c-client is built with Kerberos
 10.2948 +          support, but your client system is not within the Kerberos
 10.2949 +          realm. In this case, the client code will try to authenticate
 10.2950 +          via Kerberos, fail to get the Kerberos credentials, cancel the
 10.2951 +          authentication attempt, and try the next available
 10.2952 +          authentication technology.
 10.2953 +     _________________________________________________________________
 10.2954 +
 10.2955 +8. Where to Go For Additional Information
 10.2956 +     _________________________________________________________________
 10.2957 +
 10.2958 +   8.1 Where can I go to ask questions?
 10.2959 +   8.2 I have some ideas for enhancements to IMAP. Where should I go?
 10.2960 +
 10.2961 +          If you have questions about the IMAP protocol, or want to
 10.2962 +          participate in discussions of future directions of the IMAP
 10.2963 +          protocol, the appropriate mailing list is
 10.2964 +          imap-protocol@u.washington.edu. You can subscribe to this
 10.2965 +          list via imap-protocol-request@u.washington.edu
 10.2966 +
 10.2967 +          If you have questions about this software, you can send me
 10.2968 +          email directly or use the imap-uw@u.washington.edu mailing
 10.2969 +          list. You can subscribe to this list via
 10.2970 +          imap-uw-request@u.washington.edu
 10.2971 +
 10.2972 +          If you have general questions about the use of IMAP software
 10.2973 +          (not specific to the UW IMAP toolkit) use the
 10.2974 +          imap-use@u.washington.edu mailing list. You can subscribe to
 10.2975 +          this list via imap-use-request@u.washington.edu
 10.2976 +
 10.2977 +          You must be a subscriber to post to these lists.  As an
 10.2978 +          alternative, you can use the comp.mail.imap newsgroup.
 10.2979 +          _________________________________________________________________
 10.2980 +
 10.2981 +   8.3 Where can I read more about IMAP and other email protocols?
 10.2982 +
 10.2983 +          We recommend Internet Email Protocols: A Developer's Guide, by
 10.2984 +          Kevin Johnson, published by Addison Wesley, ISBN 0-201-43288-9.
 10.2985 +     _________________________________________________________________
 10.2986 +
 10.2987 +   8.4 Where can I find out more about setting up and administering an
 10.2988 +   IMAP server?
 10.2989 +
 10.2990 +          We recommend Managing IMAP, by Dianna Mullet & Kevin Mullet,
 10.2991 +          published by O'Reilly, ISBN 0-596-00012-X.
 10.2992 +
 10.2993 +          This book also has an excellent comparison of the UW and Cyrus
 10.2994 +          IMAP servers.
 10.2995 +
 10.2996 +   Last Updated: 15 November 2007
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/docs/IPv6.txt	Mon Sep 14 15:17:45 2009 +0900
    11.3 @@ -0,0 +1,131 @@
    11.4 +/* ========================================================================
    11.5 + * Copyright 1988-2006 University of Washington
    11.6 + *
    11.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    11.8 + * you may not use this file except in compliance with the License.
    11.9 + * You may obtain a copy of the License at
   11.10 + *
   11.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   11.12 + *
   11.13 + * 
   11.14 + * ========================================================================
   11.15 + */
   11.16 +
   11.17 +The following information about configuring inetd and xinetd for IPv6 was
   11.18 +contributed by a user.  I have not checked it for accuracy or completeness,
   11.19 +but have included it as-is in the hope that it may be useful:
   11.20 +
   11.21 +---------------------------------------------------------------------------
   11.22 +One thing you might consider adding to the docs are hints for setting up
   11.23 +inetd or xinetd to simultaneously listen on BOTH IPv4 and IPv6 for
   11.24 +different OS.
   11.25 +
   11.26 +Some OS want to see separate IPv4-only and IPv6-only listening sockets
   11.27 +configured in inetd.conf or xinetd.conf.  Others will accept IPv4
   11.28 +connections on lines configured for IPv6 and actually generate errors if
   11.29 +you have both configured when inetd or xinetd start up.  It's not clear to
   11.30 +me whether this difference is due to how inetd or xinetd are built or
   11.31 +whether it's due to the kernel's IP stack implementation.  I suspect it's
   11.32 +really the latter.  Below are some examples:
   11.33 +
   11.34 +Here's a fragment of /usr/local/etc/xinetd.conf for a FreeBSD 4.9 server:
   11.35 +
   11.36 +service imap
   11.37 +{
   11.38 +        socket_type     = stream
   11.39 +        protocol        = tcp
   11.40 +        wait            = no
   11.41 +        user            = root
   11.42 +        server          = /usr/local/libexec/imapd
   11.43 +}
   11.44 +service imap
   11.45 +{
   11.46 +        flags           = IPv6
   11.47 +        socket_type     = stream
   11.48 +        protocol        = tcp
   11.49 +        wait            = no
   11.50 +        user            = root
   11.51 +        server          = /usr/local/libexec/imapd
   11.52 +}
   11.53 +service imaps
   11.54 +{
   11.55 +        socket_type     = stream
   11.56 +        protocol        = tcp
   11.57 +        wait            = no
   11.58 +        user            = root
   11.59 +        server          = /usr/local/libexec/imapd
   11.60 +}
   11.61 +service imaps
   11.62 +{
   11.63 +        flags           = IPv6
   11.64 +        socket_type     = stream
   11.65 +        protocol        = tcp
   11.66 +        wait            = no
   11.67 +        user            = root
   11.68 +        server          = /usr/local/libexec/imapd
   11.69 +}
   11.70 +
   11.71 +Note that you have to specify a nearly identical paragraph for each
   11.72 +service which differs only by the 'flags = IPv6'.  An equivalent
   11.73 +inetd.conf would look something like:
   11.74 +
   11.75 +imap  stream  tcp     nowait  root    /usr/local/libexec/imapd        imapd
   11.76 +imap  stream  tcp6    nowait  root    /usr/local/libexec/imapd        imapd
   11.77 +imaps stream  tcp     nowait  root    /usr/local/libexec/imapd        imapd
   11.78 +imaps stream  tcp6    nowait  root    /usr/local/libexec/imapd        imapd
   11.79 +
   11.80 +The man pages for inetd suggest that if you use a single entry with
   11.81 +'tcp46' replacing either 'tcp' or 'tcp6' the system will listen on both
   11.82 +types of addresses.  At least for the case of FreeBSD this is actually
   11.83 +incorrect.
   11.84 +
   11.85 +Now if you were to use the above xinetd.conf on Fedora Linux, it would
   11.86 +complain.  What does work under Linux is to create a single service
   11.87 +paragraph for each service which will accept connections on both IPv4 and
   11.88 +IPv6:
   11.89 +
   11.90 +In /etc/xinetd.d/imap:
   11.91 +
   11.92 +service imap
   11.93 +{
   11.94 +        flags       = IPv6
   11.95 +        disable     = no
   11.96 +        socket_type = stream
   11.97 +        wait        = no
   11.98 +        user        = root
   11.99 +        server      = /usr/local/sbin/imapd
  11.100 +}
  11.101 +
  11.102 +In /etc/xinetd.d/imaps:
  11.103 +
  11.104 +service imaps
  11.105 +{
  11.106 +        flags       = IPv6
  11.107 +        disable     = no
  11.108 +        socket_type = stream
  11.109 +        wait        = no
  11.110 +        user        = root
  11.111 +        server      = /usr/local/sbin/imapd
  11.112 +}
  11.113 +
  11.114 +The man page for xinetd says the IPv6 flag means xinetd will listen ONLY
  11.115 +on IPv6.  However the actual behaviour (for Fedora Linux) is to listen on
  11.116 +both IPv4 and IPv6.
  11.117 +
  11.118 +All of the above also applies to ipop3d.  Anyway, this might save some
  11.119 +folks a little bit of head scratching time.
  11.120 +---------------------------------------------------------------------------
  11.121 +Addendum from the original submitter:
  11.122 +---------------------------------------------------------------------------
  11.123 +I've since learned that the discrepancy really is a function of the OS.
  11.124 +It seems those systems that force you to create separate IPv4 and IPv6
  11.125 +listeners in inetd (or xinetd) are the same systems that also disable
  11.126 +IPv4-mapped IPv6 addresses by default.  This is a boot-time configuration
  11.127 +option.  If you enable IPv4-mapped IPv6 addresses, then the 'tcp46' option
  11.128 +in inetd works and the simplified config would look like:
  11.129 +
  11.130 +imap4   stream  tcp46   nowait  root    /usr/local/libexec/imapd        imapd
  11.131 +imaps   stream  tcp46   nowait  root    /usr/local/libexec/imapd        imapd
  11.132 +
  11.133 +In FreeBSD, enabling IPv4-mapped addresses is done by adding
  11.134 +ipv6_ipv4mapping="YES" to /etc/rc.conf (in addition to ipv6_enable="YES").
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/docs/RELNOTES	Mon Sep 14 15:17:45 2009 +0900
    12.3 @@ -0,0 +1,787 @@
    12.4 +/* ========================================================================
    12.5 + * Copyright 1988-2008 University of Washington
    12.6 + *
    12.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    12.8 + * you may not use this file except in compliance with the License.
    12.9 + * You may obtain a copy of the License at
   12.10 + *
   12.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   12.12 + *
   12.13 + * 
   12.14 + * ========================================================================
   12.15 + */
   12.16 +
   12.17 +Updated: 16 December 2008
   12.18 +
   12.19 +imap-2007e is a maintenance release, consisting primarily of bugfixes to
   12.20 +problems discovered in the release that affected a small number of users
   12.21 +plus a security fix for users of the RFC822BUFFER routines.
   12.22 +
   12.23 +
   12.24 +Updated: 29 October 2008
   12.25 +
   12.26 +imap-2007d is a maintenance release, consisting primarily of bugfixes to
   12.27 +problems discovered in the release that affected a small number of users
   12.28 +plus a security fix for users of tmail or dmail.
   12.29 +
   12.30 +
   12.31 +Updated: 25 March 2008
   12.32 +
   12.33 +imap-2007b is a maintenance release, consisting primarily of bugfixes to
   12.34 +problems discovered in the release that affected a small number of users.
   12.35 +
   12.36 +
   12.37 +Updated: 2 January 2008
   12.38 +
   12.39 +imap-2007a is a maintenance release, consisting primarily of bugfixes to
   12.40 +problems discovered in the release that affected a small number of users.
   12.41 +
   12.42 +
   12.43 +Updated: 20 December 2007
   12.44 +
   12.45 +imap-2007 is a release corresponding with the release of Alpine 1.0.
   12.46 +The primary focus of the imap-2007 release is bugfixes and reliability
   12.47 +improvements.  This includes:
   12.48 + . fixes to problems discovered between the Alpine 0.99999 pre-release
   12.49 +    and Alpine 1.0
   12.50 + . fixes to the mix driver to timing race problems uncovered by Timo
   12.51 +    Sirainen's imaptest suite.  imap-2007 using the mix format is
   12.52 +    believed to pass imaptest completely.
   12.53 +
   12.54 +A new function, utf8_csvalidmap(), has been added for the benefit of
   12.55 +Alpine to use in examining UTF-8 text and determining efficiently
   12.56 +whether it can be downgraded to a legacy charset.  If you develop an
   12.57 +MUA, this may be useful for you too, although you'll have to read the
   12.58 +source code to see how to use it.  The purpose of the "not-CJK" bit is
   12.59 +to prevent messages being downgraded to a CJK charset if all they have
   12.60 +in that charset are some special punctuation.
   12.61 +
   12.62 +
   12.63 +Updated: 5 September 2007
   12.64 +
   12.65 +imap-2006k is a maintenance release, consisting primarily of bugfixes to
   12.66 +problems discovered in the release that affected a small number of users.
   12.67 +
   12.68 +The primary focus of this maintenance release is to correct deadlock
   12.69 +issues.  There were two major causes of the deadlocks:
   12.70 + . a change in imap-2006i attempted to resolve a glibc mutex-based
   12.71 +   deadlock in imapd's signal handler, but ended up worsening the problem.
   12.72 + . a bug in the mbx driver, introduced as part of the UIDPLUS work in 2006,
   12.73 +   applied an mbx-style lock briefly on a traditional UNIX format mailbox.
   12.74 +   If the traditional UNIX format mailbox was already locked by some other
   12.75 +   process, the result would be a deadlock of both processes.
   12.76 +
   12.77 +imapd's signal handling logic is rewritten to avoid the mutex issue, and
   12.78 +the mbx driver is fixed so that mbx-style locks are only applied to mbx
   12.79 +format mailboxes.
   12.80 +
   12.81 +imapd now supports the WITHIN extension.
   12.82 +
   12.83 +
   12.84 +Updated: 14 June 2007
   12.85 +
   12.86 +imap-2006j is a maintenance release, consisting primarily of bugfixes to
   12.87 +problems discovered in the release that affected a small number of users.
   12.88 +
   12.89 +
   12.90 +Updated: 5 June 2007
   12.91 +
   12.92 +imap-2006i is a maintenance release, consisting primarily of bugfixes to
   12.93 +problems discovered in the release that affected a small number of users.
   12.94 +
   12.95 +imapd now supports the CHILDREN and ESEARCH extensions.
   12.96 +
   12.97 +imapd's attempt to return COPYUID/APPENDUID information for a traditional
   12.98 +UNIX (and MMDF) format mailbox when the mailbox is open by another process
   12.99 +has been declared to be a failure and is now revoked.  It was subject to a
  12.100 +timing race, loss of which involved an expensive reset of the mailbox's UID
  12.101 +regime.  Any imapd COPY or APPEND to a traditional UNIX or MMDF format that
  12.102 +is open by some other process will now no longer return COPYUID/APPEND.
  12.103 +Although this is technically in violation of RFC 4315, there is a loophole
  12.104 +in that document and the timing race/performance problem is worse.
  12.105 +
  12.106 +
  12.107 +Updated: 4 April 2007
  12.108 +
  12.109 +imap-2006h is a maintenance release, consisting primarily of bugfixes to
  12.110 +problems discovered in the release that affected a small number of users.
  12.111 +
  12.112 +
  12.113 +Updated: 30 March 2007
  12.114 +
  12.115 +imap-2006g is a maintenance release, consisting primarily of bugfixes to
  12.116 +problems discovered in the release that affected a small number of users.
  12.117 +
  12.118 +
  12.119 +Updated: 30 January 2007
  12.120 +
  12.121 +imap-2006f is a maintenance release, consisting primarily of bugfixes to
  12.122 +problems discovered in the release that affected a small number of users.
  12.123 +
  12.124 +For the benefit of multi-threaded applications, use of strtok() has been
  12.125 +abolished in the c-client library.  imapd and ipop3d stuff use it though.
  12.126 +The TOPS-20 and VAX/VMS ports still use strtok() since they don't use UNIX
  12.127 +threads.
  12.128 +
  12.129 +This version has been test-built on Linux, Mac OS X, NeXT, Windows XP,
  12.130 +TOPS-20, and VAX/VMS.  This will probably be the last test-build on VAX/VMS
  12.131 +since the system I use for that purpose is being shut down.  I have no way
  12.132 +to test-build on DOS, legacy Mac OS (OS 9 and earlier), OS/2, or Windows CE;
  12.133 +and the builds on those systems are probably broken.
  12.134 +
  12.135 +
  12.136 +Updated: 26 January 2007
  12.137 +
  12.138 +imap-2006e is a maintenance release, consisting primarily of bugfixes to
  12.139 +problems discovered in the release that affected a small number of users.
  12.140 +
  12.141 +
  12.142 +Updated: 6 December 2006
  12.143 +
  12.144 +imap-2006d is a maintenance release, consisting primarily of bugfixes to
  12.145 +problems discovered in the release that affected a small number of users.
  12.146 +
  12.147 +The decomposition mapping, title-case mapping, and character widths tables
  12.148 +have been updated to comply with the Unicode 5.0 standard.
  12.149 +
  12.150 +Prototypes for the utf8aux.c functions have been moved to a new utf8aux.h.
  12.151 +
  12.152 +The general c-client modules now include c-client.h instead of the individual
  12.153 +files.  Use of c-client.h instead of individual include files insulates
  12.154 +against future shuffling of include files.
  12.155 +
  12.156 +
  12.157 +Updated: 23 October 2006
  12.158 +
  12.159 +imap-2006c is a maintenance release, consisting primarily of bugfixes to
  12.160 +problems discovered in the release that affected a small number of users.
  12.161 +
  12.162 +By popular request, if a user has a mix (or other dual-use) format INBOX,
  12.163 +it will no longer be listed as \NoInferiors.  It's a bad idea to depend
  12.164 +upon this due to the case ambiguity issue, but it's there.
  12.165 +
  12.166 +
  12.167 +Updated: 26 September 2006
  12.168 +
  12.169 +imap-2006b is a maintenance release, consisting entirely of bugfixes to
  12.170 +problems discovered in the release that affected a small number of users.
  12.171 +
  12.172 +
  12.173 +Updated: 15 September 2006
  12.174 +
  12.175 +imap-2006a is a maintenance release, consisting entirely of bugfixes to
  12.176 +problems discovered in the release that affected a small number of users.
  12.177 +
  12.178 +If it is necessary to build IPv4-only on one of the ports that has IPv6
  12.179 +preconfigured (ldb, lfd, lmd, lrh, lsu, osx, oxp), this can be done by
  12.180 +using IP6=4.  You can't do IP=4 in the build command directly since these
  12.181 +ports set IP themselves; however, now instead of setting IP=6 they now set
  12.182 +IP=$(IP6).
  12.183 +
  12.184 +
  12.185 +Updated: 30 August 2006
  12.186 +
  12.187 +imap-2006 is a major release.  Programs written for imap-2004g should
  12.188 +build with this version with minor or no modification.  imap-2005 was not
  12.189 +released except as development snapshots.
  12.190 +
  12.191 +imap-2006 contains major extensions to its Unicode support.  Searching and
  12.192 +sorting are now done with strings canonicalized to titlecase and decomposed
  12.193 +form.  Among other things, this means that Latin letters with diacriticals
  12.194 +will now sort with the basic Latin letter, and case-independent searching of
  12.195 +such letters (e.g., German umlauts) now works.  Previously, sorting was done
  12.196 +strictly by Unicode codepoint, and case-independence only worked with ASCII.
  12.197 +
  12.198 +imapd now supports the UIDPLUS extension for mailboxes in unix, mmdf, mbx, mx,
  12.199 +and mix formats.  UID EXPUNGE is fully implemented.  Note that UIDPLUS is not
  12.200 +supported in the little-used drivers (mh, mtx, tenex) in which meaningful
  12.201 +APPENDUID/COPYUID data can not be returned.  Refer to bugs.txt for more
  12.202 +details.
  12.203 +
  12.204 +The new mix format is a dual-use mailbox format designed for performance and
  12.205 +reliability with large mailboxes.  mix is documented in file mixfmt.txt.
  12.206 +
  12.207 +SSL/TLS certificate validation on UNIX now checks the alternative names in the
  12.208 +certificate if the CN does not match.
  12.209 +
  12.210 +The new /tls-sslv23 flag in a mailbox name causes a TLS session to use the
  12.211 +(incorrect) SSLv23 client method instead of the TLSv1 client method.  Some
  12.212 +broken servers use the SSLv23 server method, and this flag works around that
  12.213 +problem.  WARNING: use of this flag will cause TLS negotiation to fail with
  12.214 +a server which uses the proper TLSv1 server method.  Additionally, there are
  12.215 +known security risks in SSLv2; so users should be suspicious if this switch
  12.216 +suddenly becomes necesary.
  12.217 +
  12.218 +The silly mailbox flag combination /ssl/tls is now rejected as an invalid
  12.219 +remote specification.  Previous versions tried to negotiate TLS over an SSL
  12.220 +session; even if the server permitted such a thing it couldn't work.
  12.221 +
  12.222 +The memory management of several drivers has been redesigned to consume less
  12.223 +memory and hopefully be faster.
  12.224 +
  12.225 +The private.data member of the MESSAGECACHE (elt) has been replaced with
  12.226 +a union that contains private.spare.data and private.spare.ptr, the latter
  12.227 +being a pointer.
  12.228 +
  12.229 +A new FT_RETURNSTRINGSTRUCT flag has been added for mail_fetch_body() and
  12.230 +mail_fetch_text() calls.  If this flag is set, *and* if the function returns
  12.231 +NIL, then the requested string data is available on a stringstruct on
  12.232 +stream->private.string.  This is a special hack for the IMAP and POP servers
  12.233 +and is subject to incompatible change.  The result is a major performance
  12.234 +improvement in the servers with the mbx driver, particularly with large
  12.235 +messages.
  12.236 +
  12.237 +
  12.238 +Updated: 15 September 2005
  12.239 +
  12.240 +imap-2004g is a maintenance release, and consists solely of a bugfix to
  12.241 +quoted string handling in the mailbox name parsing routine.
  12.242 +
  12.243 +
  12.244 +Updated: 15 August 2005
  12.245 +
  12.246 +imap-2004f is a maintenance release, and consists solely of a bugfix to
  12.247 +the TCP code.
  12.248 +
  12.249 +Also included is a new version of the UNIX SSL/TLS routines that allows the
  12.250 +SSL/TLS certificate validation client code to validate alternative names in
  12.251 +server certificates.  This code has not been thoroughly regression-tested but
  12.252 +is believed to work.  To use this new code instead of the old support:
  12.253 +	cd imap-2004f/src/osdep/unix
  12.254 +	mv ssl_unix.c ssl_unix.old
  12.255 +	mv ssl_unix.new ssl_unix.c
  12.256 +Then rebuild.
  12.257 +
  12.258 +
  12.259 +Updated: 21 June 2005
  12.260 +
  12.261 +imap-2004e is a maintenance release, consisting entirely of bugfixes.
  12.262 +
  12.263 +There are no user-visible functional enhancements in this version.
  12.264 +
  12.265 +
  12.266 +Updated: 20 April 2005
  12.267 +
  12.268 +imap-2004d is a maintenance release, released concurrently with Pine
  12.269 +4.63, and consists primarily of bugfixes
  12.270 +
  12.271 +There is now a workaround for RedHat breaking flock().  However, since
  12.272 +RedHat has said that they don't support flock(), there is no guarantee
  12.273 +that they won't break it in the future.  So you may want to consider some
  12.274 +other Linux distribution or BSD instead.  See:
  12.275 +	https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415
  12.276 +for the gruesome details.
  12.277 +
  12.278 +There are no user-visible functional enhancements in this version.
  12.279 +
  12.280 +
  12.281 +Updated: 18 January 2005
  12.282 +
  12.283 +imap-2004c is a maintenance release, released concurrently with Pine
  12.284 +4.62, including fixes to quoted-printable encoding and CRAM-MD5
  12.285 +authentication.
  12.286 +
  12.287 +NNTP proxy in imapd now supports the LIST and LSUB commands.
  12.288 +
  12.289 +There are no other user-visible functional enhancements in this version.
  12.290 +
  12.291 +
  12.292 +Updated: 29 November 2004
  12.293 +
  12.294 +imap-2004b is a maintenance release, consisting primarily of bugfixes.
  12.295 +Programs written for imap-2004a will build with this version without
  12.296 +modifification.
  12.297 +
  12.298 +There are new ports for Solaris with Blastwave Community Open Source
  12.299 +Software (gcs) and Mandrake Linux (lmd).
  12.300 +
  12.301 +SET_SNARFINTERVAL now controls how frequently local drivers will move new
  12.302 +mail from the mail spool as well as from a maildrop.  Maildrops are still
  12.303 +tied to a minimum interval of 1 minute, but there is now no minimum for the
  12.304 +spool file.
  12.305 +
  12.306 +Character set conversions now map non-breaking space to space if the
  12.307 +destination character set doesn't have nbsp.  JIS Roman yen sign is now
  12.308 +mapped to Unicode yen sign.
  12.309 +
  12.310 +There are no user-visible functional enhancements in this version.
  12.311 +
  12.312 +
  12.313 +Updated: 8 July 2004
  12.314 +
  12.315 +imap-2004a is a maintenance release, consisting primarily of critical
  12.316 +bugfixes.  Programs written for imap-2004 will build with this version
  12.317 +without modification.
  12.318 +
  12.319 +imapd now has a supported NNTP proxy capability.  If the file /etc/imapd.nntp
  12.320 +exists, the contents of that file are used as the host name of an NNTP
  12.321 +server which will be used whenever a #news. name is used.  For example, if
  12.322 +/etc/imapd.nntp contains nntp.example.com, and the IMAP client SELECTs or
  12.323 +EXAMINEs the name #news.comp.mail.imap, what will actually be opened in
  12.324 +imapd is {nntp.example.com/nntp}comp.mail.imap
  12.325 +
  12.326 +The OSF/1 port (Digital UNIX, Tru64) now uses flocksim instead of flcksafe.
  12.327 +Some cretin decided to delete the winning flock() call and make flock() use
  12.328 +the losing fcntl() call instead.
  12.329 +
  12.330 +The unix[nt] and mmdf drivers now prevent mail_append() from writing Status:,
  12.331 +X-Status:, X-UID, X-IMAP[base]:, and X-Keywords: header lines to a
  12.332 +traditional UNIX or MMDF format mailbox.  If any such lines are in the
  12.333 +text supplied to mail_append(), they will be quoted by prefixing with
  12.334 +"X-Original-" (e.g. Status: will become X-Original-Status:).
  12.335 +
  12.336 +There are no user-visible functional enhancements in this version.
  12.337 +
  12.338 +
  12.339 +Updated: 10 May 2004
  12.340 +
  12.341 +imap-2004 is a major release.  Programs written for imap-2002e should
  12.342 +build with this version with minor modification.  imap-2003 was not
  12.343 +released except as development snapshots.
  12.344 +
  12.345 +mailutil has three new commands: delete, rename, and prune.
  12.346 +
  12.347 +IPv6 support now exists for UNIX and W2K.  It is the default in W2K builds.
  12.348 +On UNIX, add "IP=6" to the make command line.  Windows IPv6 support is
  12.349 +only for W2K builds.
  12.350 +
  12.351 +The NNTP driver now supports NNTP SASL and TLS.
  12.352 +
  12.353 +The ldb (Debian) and lrh (RedHat) ports now look for mlock on
  12.354 +/usr/sbin/mlock instead of /etc/mlock.
  12.355 +
  12.356 +imapd now supports the LITERAL+ and SASL-IR initial-response extensions.
  12.357 +
  12.358 +The IMAP driver has some additional checks to reduce the amount of network
  12.359 +traffic, including executing "silly searches" (searches of sequence numbers
  12.360 +only) locally.
  12.361 +
  12.362 +The IMAP, POP, SMTP, and NNTP drivers now have diagnostic code to provide
  12.363 +better information about servers which violate SASL's empty challenge
  12.364 +requirements (e.g. with the PLAIN mechanism).
  12.365 +
  12.366 +There is a new mail_fetch_overview_sequence() function which is like
  12.367 +mail_fetch_overview() but takes a sequence number string as an argument.
  12.368 +There should have been a flags argument and FT_UID bit as in all the other
  12.369 +mail_fetch_???() functions but compatibility with the past... :-(
  12.370 +
  12.371 +The overview_t callback (from mail_fetch_overview()) now has a fourth
  12.372 +argument which contains the message sequence number (as opposed to the UID
  12.373 +which is in the second argument).  It turned out that some applications were
  12.374 +calling mail_msgno() (which can be moderately expensive) to get the sequence
  12.375 +number, and c-client already knew it.
  12.376 +
  12.377 +Many declarations which are completely internal to a driver have been removed
  12.378 +from the driver .h file, and in those cases where there are no external
  12.379 +declarations left the .h file has been eliminated entirely.  As part of this,
  12.380 +the mbox driver routines are now incorporated with the unix driver routines
  12.381 +as opposed to being a separate file.  The mbox driver still needs to be lunk
  12.382 +in order to get the mbox functionality.
  12.383 +
  12.384 +
  12.385 +Updated: 27 August 2003
  12.386 +
  12.387 +imap-2002e is a minor release, released concurrently with Pine 4.58, and
  12.388 +contains primarily bugfixes.  Programs written for imap-2002d will build
  12.389 +with this version without modification.
  12.390 +
  12.391 +The NNTP client code now tries to perform better with legacy NNTP servers
  12.392 +which do not comply with the current NNTP protocol specification draft, most
  12.393 +notably Netscape Collabra.
  12.394 +
  12.395 +Delivery notifications now work reliably with SMTP servers that support it.
  12.396 +
  12.397 +The following changes are primarily of concern to developers and power users:
  12.398 +
  12.399 +There is a "limited advertise" option in env_unix.c which, if set, will only
  12.400 +advertise the user's own namespace and the #shared/ namespace.
  12.401 +
  12.402 +It is now possible to build the IMAP toolkit with a separate SSL KEY file
  12.403 +from the certificate file (SSLKEYS vs. SSLCERTS).
  12.404 +
  12.405 +A new BODY structure element, sparep, is available for the main program to
  12.406 +use as a pointer for its own purposes; as well as a SET_FREEBODYSPAREP
  12.407 +function, similar to SET_FREEENVELOPESPAREP, SET_FREEELTSPAREP, etc.
  12.408 +
  12.409 +
  12.410 +Updated: 28 May 2003
  12.411 +
  12.412 +imap-2002d is a minor release, released concurrently with Pine 4.56, and
  12.413 +contains primarily bugfixes.  Programs written for imap-2002 should build
  12.414 +with this version without modification, with one exception.  That exception
  12.415 +is the ngbogus envelope flag, which stopped being used in imap-2002c and is
  12.416 +now gone for good.
  12.417 +
  12.418 +The NNTP newsgroup listing code now tries to use wildmats on the NNTP server,
  12.419 +which should result in better performance especially on slow lines.  It is
  12.420 +also once again permitted to log in on NNTP servers when /loser is set.
  12.421 +
  12.422 +imapd now supports the UNSELECT command.
  12.423 +
  12.424 +A new envelope flag, imapenvonly, indicates that the envelope in a
  12.425 +MESSAGE/RFC822 BODY structure only has the IMAP envelope components and
  12.426 +not the additional components from c-client: Newsgroups, Followup-To,
  12.427 +and References.
  12.428 +
  12.429 +
  12.430 +Updated: 7 April 2003
  12.431 +
  12.432 +imap-2002c is a minor release, released concurrently with Pine 4.55, and
  12.433 +contains primarily bugfixes.  Programs written for imap-2002 will build
  12.434 +with this version without modification.
  12.435 +
  12.436 +The POP3 driver will, with new servers that support CAPA, use the LIST
  12.437 +command to get the elt->rfc822_size and the TOP command to get the message
  12.438 +header, instead of fetching the entire message.  Note that it is a bad idea
  12.439 +to do this with old servers, since they may misimplement LIST and TOP.  The
  12.440 +result is a substantial performance improvement.
  12.441 +
  12.442 +Subject extraction for comparisons in SORT and THREAD are now done in full
  12.443 +compliance with the rules laid out in the specification.  This only makes
  12.444 +a difference if "re:" was part of a MIME quoted-word.
  12.445 +
  12.446 +The new experimental #move namespace allows download-and-delete from a source
  12.447 +mailbox to a destination mailbox.  Immediately following #move is a delimiter
  12.448 +character which must not appear in the source mailbox name, then the source
  12.449 +mailbox name, then the delimiter again, then the destination mailbox name.
  12.450 +For example:
  12.451 +	#move+{pop3.foo.com/pop3}+INBOX
  12.452 +will download messages from "pop3.foo.com" into your local INBOX.
  12.453 +
  12.454 +The NNTP driver now uses the LIST EXTENSIONS command as described in the
  12.455 +current NNTP protocol specification draft, and will prefer to use OVER over
  12.456 +XOVER, HDR over XHDR, etc.
  12.457 +
  12.458 +The SET_NNTPRANGE function of mail_parameters() can be used to limit the
  12.459 +number of articles recognized by the NNTP driver, resulting in a substantial
  12.460 +performance improvement with NNTP servers that may have hundreds of thousands
  12.461 +of old articles in the spool.  If set non-zero, then only the last n article
  12.462 +numbers will be considered.  If you are on a slow link, you may want to set
  12.463 +this to 1000 or less.
  12.464 +
  12.465 +Besides the normally tested UNIX and 32-bit Microsoft platforms, this release
  12.466 +has also been tested and will once build under TOPS-20 and VAX/VMS.  I also
  12.467 +fixed a bug which would keep it from building on 16-bit DOS, but I don't know
  12.468 +if it will build on that platform or not since I no longer have a system with
  12.469 +the old DOS C compiler.  It has not been tested on Macintosh (note however
  12.470 +that Mac OS X is a type of UNIX and should build), Amiga, or OS/2, and probably
  12.471 +no longer builds on those platforms.
  12.472 +
  12.473 +
  12.474 +Updated: 7 January 2003
  12.475 +
  12.476 +imap-2002b is a maintenace release, released concurrently with Pine 4.52,
  12.477 +and contains only bugfixes.  Programs written for imap-2002 will build with
  12.478 +this version without modification.
  12.479 +
  12.480 +Drivers which do not announce new mail are now indicated by the DR_NONEWMAIL
  12.481 +driver flag.  Driver which do not announce new mail when read-only are now
  12.482 +indicated by the DR_NONEWMAILRONLY flag.
  12.483 +
  12.484 +There are no user-visible functional enhancements in this version.
  12.485 +
  12.486 +
  12.487 +Updated: 10 December 2002
  12.488 +
  12.489 +imap-2002a is a maintenance release, consisting entirely of critical
  12.490 +bugfixes.  Programs written for imap-2002 will build with this version
  12.491 +without modification.
  12.492 +
  12.493 +There are no functional enhancements in this version.
  12.494 +
  12.495 +
  12.496 +Updated: 28 October 2002
  12.497 +
  12.498 +imap-2002 is a major release.  Programs written for imap-2001 will probably
  12.499 +build with this version without modification, with one exception.  That
  12.500 +exception is if the program uses [GS]ET_DISABLEAUTOMATICSHAREDNAMESPACES,
  12.501 +which has been renamed to [GS]ET_DISABLEAUTOSHAREDNS in order to placate
  12.502 +some compilers which don't like very long names.
  12.503 +
  12.504 +SSLTYPE=nopwd is now the default, in accordance with current IESG security
  12.505 +requirements.  In order to build the IMAP toolkit without SSL/TLS you must
  12.506 +now use SSLTYPE=none.  At initial build time, you will be told if the SSLTYPE
  12.507 +setting is in compliance with IESG security requirements, and if it is not
  12.508 +you will be asked to confirm to continue the build.
  12.509 +
  12.510 +ORDEREDSUBJECT threading has been changed in accordance with draft 12 of the
  12.511 +IMAP threading specification.  Previously, each non-root message in an
  12.512 +ORDEREDSUBJECT thread has been a child of the message immediately preceeding
  12.513 +it in the thread.  Draft 12 changes this so that the second message in the
  12.514 +thread is the child of the first (root) message, and all subsequent messages
  12.515 +are siblings of the first message.  This is significant in MUAs which display
  12.516 +the thread structure graphically; the new definition is much saner than the
  12.517 +old one since it does not nest endlessly due to parent/child relationships
  12.518 +that may not exist.  This also impacts imapd, since imapd's THREAD command
  12.519 +will return a thread structure.
  12.520 +
  12.521 +RFC 1730 server support, which was disabled in imap-2001, is now fully
  12.522 +removed from imapd.  imapd still supports IMAP2bis, specifically the FIND
  12.523 +command, since there are still a few IMAP2 clients out there.
  12.524 +
  12.525 +The IMAP client routines in the c-client library continue to support recognize
  12.526 +RFC 1730 servers, but do not implement the deprecated features of RFC 1730.
  12.527 +
  12.528 +The Frequently Asked Questions file is now in HTML format, although a text
  12.529 +version (generated from the HTML version with Lynx) is also provided.
  12.530 +
  12.531 +A new program, mailutil, is now bundled with the IMAP toolkit.  mailutil
  12.532 +replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy, mbxcreat,
  12.533 +and mbxcvt programs that were distributed in the imap-utils.  In addition,
  12.534 +the tmail, dmail, and mlock programs from the imap-utils are now also
  12.535 +bundled with the IMAP toolkit.
  12.536 +
  12.537 +In addition to the usual bugfixes, the following c-client functionalities
  12.538 +are new in imap-2002:
  12.539 +
  12.540 +The SET_DISABLE822TZTEXT parameter allows a client to suppress generation of
  12.541 +the "human friendly" time zone text in RFC822 dates.  This placates netnews
  12.542 +and some broken SMTP servers which think that long timezone names from Windows
  12.543 +are an attempt at a buffer overflow attack.
  12.544 +
  12.545 +The restrictBox option in env_unix.c sets "restricted box" functionality,
  12.546 +which disables access to the root (leading "/"), access to other user's
  12.547 +directories (leading "~"), and access to superior directories via "..".
  12.548 +
  12.549 +Content-Location is now supported by the "location" member of the BODY
  12.550 +structure.  Note that there is a bug in the IMAP client code in older
  12.551 +versions of the c-client library that causes it to handle BODYSTRUCTURE
  12.552 +extension data improperly if that data is a literal.  The new functionality
  12.553 +for Content-Location may trigger this bug.  The fix is either to upgrade
  12.554 +the IMAP client program to the imap-2002 version of c-client or to remove
  12.555 +the Content-Location support from imapd.
  12.556 +
  12.557 +There are now 8 spare bits for application use in both the elts and the
  12.558 +mail streams.
  12.559 +
  12.560 +mail_search() now returns a value (previously it was void).  If mail_search()
  12.561 +returns NIL, then the supplied charset was invalid or the IMAP server
  12.562 +returned NO (probably because the supplied charset was invalid).
  12.563 +
  12.564 +New utf8_charset() routine to look up a charset and return c-client's
  12.565 +database about that charset if found.  Among other things, this will give
  12.566 +you the scripts supported by that charset and its Unicode conversion table.
  12.567 +
  12.568 +New FT_NOLOOKAHEAD flag for mail_fetch_structure() disables fetching of
  12.569 +any envelopes other than the one specified.  Otherwise, it will try to do
  12.570 +anticipatory fetching (up to IMAPLOOKAHEAD).
  12.571 +
  12.572 +New GET_FETCHLOOKAHEAD allows better control of mail_fetch_structure()
  12.573 +lookahead.  Instead of looking IMAPLOOKAHEAD messages forward from the
  12.574 +specified message, it will use a supplied SEARCHSET to generate message
  12.575 +sequences and ranges.  It will stop at IMAPLOOKAHEAD messages or at the
  12.576 +completion of a range which exceeds IMAPLOOKAHEAD.  The search set only
  12.577 +applies to the next mail_fetch_structure() on that stream, and is cleared
  12.578 +once it is used.  Call with
  12.579 +  SEARCHSET **set = (SEARCHSET **)
  12.580 +    mail_parameters (stream,GET_FETCHLOOKAHEAD,(void *) stream);
  12.581 +  *set = pointer to desired search set
  12.582 +
  12.583 +New mail_shortdate() routine returns an date in the format expected by
  12.584 +SEARCHPGMs.
  12.585 +
  12.586 +
  12.587 +Updated: 2 November 2001
  12.588 +
  12.589 +imap-2001a is a maintenance release, consisting primarily of bugfixes
  12.590 +including some critical bugfixes to crash and denial of service problems.
  12.591 +Programs written for imap-2001 will build with this version without
  12.592 +modification.
  12.593 +
  12.594 +The following new facilities have also been added:
  12.595 +
  12.596 +The new /norsh switch in mailbox names provides a more intuitive way of
  12.597 +disabling rsh-IMAP than the existing :143 or setting the rsh-timeout to 0.
  12.598 +
  12.599 +Passwords are no longer returned in mm_dlog() callbacks unless the
  12.600 +application sets the SET_DEBUGSENSITIVE parameter.
  12.601 +
  12.602 +The SET_NETFSSTATBUG parameter allows an application to force the
  12.603 +traditional UNIX mailbox driver to close and reopen the mailbox at ping
  12.604 +time.  This is EXTREMELY inefficient, and should only be used to access
  12.605 +files stored on AFS and old NFS systems.
  12.606 +
  12.607 +The ISO 8859 and Windows conversion tables have been updated to comply
  12.608 +with Unicode 3.1, and the KOI8-R table has been verified as compliant with
  12.609 +Unicode 3.1.
  12.610 +
  12.611 +The SPECIALS mechanism for passing parameters to the lowest level Makefile
  12.612 +has been updated to be more general.  See the next item for why you might
  12.613 +care.
  12.614 +
  12.615 +New lrh port to build on Red Hat Linux 7.2, with pre-set definitions for
  12.616 +the places where Red Hat has placed Kerberos and SSL.  It's actually just
  12.617 +the lnp port with SPECIALS defined accordingly.  You may want to use it as
  12.618 +a model if your system needs such definitions.  Note that SPECIALS is
  12.619 +primarily for IMAP toolkit (and Pine) purposes, and that user settings
  12.620 +should use EXTRASPECIALS instead.
  12.621 +
  12.622 +
  12.623 +Updated: 22 June 2001
  12.624 +
  12.625 +imap-2001 is a major release.  Programs written for imap-2000 will probably
  12.626 +build with this version without modification.
  12.627 +
  12.628 +The FAQ document has been significantly expanded.  Be sure to read it for
  12.629 +more information.
  12.630 +
  12.631 +In addition to the usual bugfixes, the following features are new in
  12.632 +imap-2001:
  12.633 +
  12.634 +SSL is now fully integrated into the IMAP toolkit; the old "alt" kludges to
  12.635 +be able to produce a "sanitized" version of the IMAP toolkit to comply with
  12.636 +late unlamented US export regulations are now completely gone.
  12.637 +
  12.638 +Full client and server TLS support is also in this release.
  12.639 +
  12.640 +The server certificate must be signed by a trusted certificate authority and
  12.641 +the name in the certificate match the user's entry for the server host name;
  12.642 +this means that the user must enter a fully-qualified host name.
  12.643 +
  12.644 +To build with SSL/TLS on UNIX, you now use "SSLTYPE=unix" instead of the
  12.645 +former "SPECIALAUTHENTICATORS=ssl".  To build with SSL/TLS on UNIX and disable
  12.646 +the use of plaintext passwords except when under SSL/TLS, use "SSLTYPE=nopwd"
  12.647 +instead of "SSLTYPE=unix".
  12.648 +
  12.649 +RFC 1730 (IMAP4 as opposed to IMAP4rev1) support is turned off by default in
  12.650 +imapd.  No clients should still be using RFC 1730 protocol.  Look at the imapd
  12.651 +Makefile for how to re-enable RFC 1730 support.  Note that this code may be
  12.652 +removed in the future, so if you think you need it you had better let me know.
  12.653 +
  12.654 +There are some new options (turned off by default) which attempt to work around
  12.655 +problems in certain clients.  See the FAQ file for more details.
  12.656 +
  12.657 +
  12.658 +Updated: 24 January 2001
  12.659 +
  12.660 +imap-2000c is a maintenance release, consisting primarily of bugfixes.
  12.661 +
  12.662 +
  12.663 +Updated: 9 January 2001
  12.664 +
  12.665 +imap-2000b is a maintenance release, consisting primarily of bugfixes.
  12.666 +
  12.667 +
  12.668 +Updated: 9 November 2000
  12.669 +
  12.670 +imap-2000a is a maintenance release, consisting primarily of bugfixes.
  12.671 +
  12.672 +
  12.673 +Updated: 19 September 2000
  12.674 +
  12.675 +imap-2000 is a major release.  There are major internal and external changes
  12.676 +from earlier versions (imap-4.x and imap-3.x series).  Programs written for
  12.677 +imap-4.x will probably build with this version without modification.  It is
  12.678 +extremely unlikely that a program written for imap-3.x or earlier series will
  12.679 +build with this version without modifications.  Drivers written for earlier
  12.680 +versions will definitely need to be rewritten.
  12.681 +
  12.682 +In addition to the usual bugfixes, the following features are new in imap-2000:
  12.683 +
  12.684 +SSL support is now available.  For UNIX, it is necessary to install some
  12.685 +version of OpenSSL; see imap-2000/docs/SSLBUILD for more information.  SSL
  12.686 +support is now automatic for the NT, NTK, and W2K ports.  SSL use is indicated
  12.687 +by the /ssl switch in the mailbox name.
  12.688 +
  12.689 +With SSL connections, the server certificate is validated by the client code
  12.690 +on UNIX, and Windows 2000 unless /novalidate-cert is specified.  Server
  12.691 +certificates are currently is not validated on Windows 9x, Windows Millenium,
  12.692 +or Windows NT 4; this is an artifact of the operating system and not the port
  12.693 +(e.g. client code using the NT port will validate certificates if running on
  12.694 +Windows 2000).  On UNIX, the server certificate must be signed by a trusted
  12.695 +certificate authority.  On Windows 2000, the certificate must be signed by a
  12.696 +trusted certificate authority and match the user's entry for the server host
  12.697 +name; this means that the user must enter a fully-qualified host name.
  12.698 +
  12.699 +Calendar reclama for the benefit of old broken non-Y2K compliant software.
  12.700 +Two digit years from 00 to 69 will be interpreted as 2000 through 2069.  In
  12.701 +addition, three digit years from 100 to 105 will be interpreted as 2000
  12.702 +through 2005.
  12.703 +
  12.704 +Support for REFERENCES threading (in addition to the previously-existing
  12.705 +ORDEREDSUBJECT threading).
  12.706 +
  12.707 +Support for the IMAP MULTIAPPEND extension.  This allows much faster uploading
  12.708 +of multiple messages to an IMAP server.
  12.709 +
  12.710 +Support for the LOGINDISABLED IMAP capability.  If the IMAP server sends
  12.711 +LOGINDISABLED as a capability, the client code will never attempt to send an
  12.712 +IMAP LOGIN command.
  12.713 +
  12.714 +Support for SASL authentication identity vs. authorization identity.  If the
  12.715 +authentication method does not support this concept (e.g. AUTH=CRAM-MD5,
  12.716 +AUTH=LOGIN, LOGIN command), the "*" character in the user name may be used to
  12.717 +indicate a separate authentication identity; for example, "fred*joe" indicates
  12.718 +authorization identity "fred", authentication identity "joe".
  12.719 +
  12.720 +
  12.721 +UNIX-specific Changes:
  12.722 +
  12.723 +Support for SASL authentication identity vs. authorization identity in the
  12.724 +IMAP and POP3 servers.  If the user indicated by the authentication identity
  12.725 +is in the "mailadm" group, he may specify any authorization identity and get
  12.726 +logged in as the authorization identity user.
  12.727 +
  12.728 +If the IMAP and POP3 servers are build with PASSWDTYPE=nul, it will send
  12.729 +LOGINDISABLED as a capability and also disable the AUTH=LOGIN and AUTH=PLAIN
  12.730 +SASL authenticators.
  12.731 +
  12.732 +New MAILSUBDIR build option to change the default mailbox directory from the
  12.733 +user's home directory to a subdirectory of the user's home directory.  See
  12.734 +imap-2000/Makefile for more information.
  12.735 +
  12.736 +New CHROOT_SERVER build option for closed server systems only.  If defined, a
  12.737 +chroot() call to the user's home directory is done as part of the login
  12.738 +process.  See imap-2000/Makefile for more information.
  12.739 +
  12.740 +New ADVERTISE_THE_WORLD build option which will add an IMAP namespace that
  12.741 +points to the root.  Not for the faint of heart.
  12.742 +
  12.743 +UNIX format mailboxes no longer require the pseudo-message, nor will a
  12.744 +pseudo-message be added to a mailbox that does not have one.  A new
  12.745 +X-IMAPbase: header will be written in the first message.  This is rather less
  12.746 +efficient and robust than the pseudo-message (which remains the encouraged
  12.747 +mechanism; UNIX format mailboxes will always be created with it), but perhaps
  12.748 +will pacify some people who get upset by the pseudo-message.
  12.749 +
  12.750 +When building with MIT Kerberos it will try to detect and use libk5crypto.a
  12.751 +instead of libcrypto.a.
  12.752 +
  12.753 +The mbx driver is more aggressive about cleaning up expunged messages that
  12.754 +couldn't be purged because of shared access to the mailbox at the time of
  12.755 +expunge.  Now, every checkpoint will try to purge such messages; and a
  12.756 +checkpoint is attempted at close time.
  12.757 +
  12.758 +
  12.759 +Windows-specific Changes:
  12.760 +
  12.761 +New W2K port for Windows 2000.  In addition to supporting SSL using the
  12.762 +official SSPI interface (the NT and NTK ports invoke SChannel.DLL directly),
  12.763 +the W2K port also supports Microsoft Kerberos.  Note that the NT and NTK ports
  12.764 +will work on Windows 2000, but the W2K port will not work on NT4, Windows
  12.765 +9x, or Windows Millenium.
  12.766 +
  12.767 +There is now a #user namespace, equivalent to the "~" namespace on UNIX.
  12.768 +
  12.769 +
  12.770 +
  12.771 +Changes for Developers:
  12.772 +
  12.773 +New c-client.h file which acts as a master include.  c-client based
  12.774 +applications should now include c-client.h instead of the individual c-client
  12.775 +files (mail.h, misc.h, etc.).  It is believed that c-client.h will work in C++
  12.776 +applications.
  12.777 +
  12.778 +New GET_FREEENVELOPESPAREP/SET_FREEENVELOPESPAREP and
  12.779 +GET_FREEELTSPAREP/SET_FREEELTSPAREP function callbacks to free the "sparep"
  12.780 +member of the envelope and cache elements, respectively.
  12.781 +
  12.782 +New OP_MULNEWSRC flag to mail_open() to use multiple newsrc files, and new
  12.783 +GET_NEWSRCQUERY/SET_NEWSRCQUERY function callbacks to get the name of the
  12.784 +newsrc file for news access.
  12.785 +
  12.786 +New "secret" nntp_article() function to do the NNTP ARTICLE command; this is
  12.787 +generally useful only when chasing news URLs.
  12.788 +
  12.789 +New GET_HIDEDOTFILES/SET_HIDEDOTFILES feature to suppress file names that
  12.790 +start with "." in mail_list() results.
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/docs/SSLBUILD	Mon Sep 14 15:17:45 2009 +0900
    13.3 @@ -0,0 +1,267 @@
    13.4 +/* ========================================================================
    13.5 + * Copyright 1988-2007 University of Washington
    13.6 + *
    13.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    13.8 + * you may not use this file except in compliance with the License.
    13.9 + * You may obtain a copy of the License at
   13.10 + *
   13.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   13.12 + *
   13.13 + * 
   13.14 + * ========================================================================
   13.15 + */
   13.16 +
   13.17 +		  SSL/TLS BUILD AND INSTALLATION NOTES FOR UNIX
   13.18 +			 Last Updated: 15 November 2007
   13.19 +
   13.20 +PREREQUISITES BEFORE STARTING:
   13.21 + 1) Review the information in imap-2007/docs/BUILD.
   13.22 + 2) Obtain a copy of OpenSSL.  OpenSSL is available from third parties.  We
   13.23 +    do not provide OpenSSL.
   13.24 + 3) Make sure that you know how to build OpenSSL properly on the standard
   13.25 +    /usr/local/ssl directory.  In particular, /usr/local/ssl/include (and
   13.26 +    /usr/local/ssl/include/openssl) and /usr/local/ssl/lib must be set up
   13.27 +    from the OpenSSL build.  If you have a non-standard installation, then
   13.28 +    you must modify the imap-2007/src/osdep/unix/Makefile file to point
   13.29 +    to the appropriate locations.
   13.30 + 4) Make sure that you know how to obtain appropriate certificates on your
   13.31 +    system.
   13.32 +
   13.33 +NOTE: We can NOT provide you with support in building/installing OpenSSL, or
   13.34 +in obtaining certificates.  If you need help in doing this, try the contacts
   13.35 +mentioned in the OpenSSL README.
   13.36 +
   13.37 +
   13.38 +SSL BUILD:
   13.39 +
   13.40 +     By default, the IMAP toolkit builds with SSL and disabling plaintext
   13.41 +passwords unless SSL/TLS encryption is in effect (SSLTYPE=nopwd).  This
   13.42 +produces an IMAP server which is compliant with RFC 3501 security
   13.43 +requirements.
   13.44 +
   13.45 +     To build with SSL but allow plaintext passwords in insecure sessions,
   13.46 +add "SSLTYPE=unix" to the make command line.  Note that doing so will
   13.47 +produce an IMAP server which is NON-COMPLIANT with RFC 3501.
   13.48 +
   13.49 +     To build without SSL, add "SSLTYPE=none" to the make command line.
   13.50 +Note that doing so will produce an IMAP server which is NON-COMPLIANT
   13.51 +with RFC 3501.
   13.52 +
   13.53 +     There are other make options relevant to SSL, described in
   13.54 + imap-2007/src/osdep/unix/Makefile
   13.55 +The most important of these are SSLDIR, SSLCRYPTO, and SSLRSA.
   13.56 +
   13.57 +     SSLDIR is set to /usr/local/ssl by default.  This is the normal
   13.58 +installation directory for OpenSSL.  If your system uses a different directory
   13.59 +you will need to change this.
   13.60 +
   13.61 +     SSLCRYPTO is set to -lcrypto by default.  Older versions of MIT Kerberos
   13.62 +also have a libcrypto and will cause a library name conflict.  If you are
   13.63 +using an older version of Kerberos, you may need to change SSLCRYPTO to
   13.64 +$(SSLLIB)/libcrypto.a
   13.65 +
   13.66 +     SSLRSA is set empty by default.  It can be set to specify the RSAREF
   13.67 +libraries, which you once had to use with OpenSSL to use RSA algorithms
   13.68 +legally if you are in the USA, due to patent issues.  Since RSA Security Inc.
   13.69 +released the RSA algorithm into the public domain on September 6, 2000, there
   13.70 +is no longer any reason to do this.
   13.71 +
   13.72 +
   13.73 +SSL INSTALLATION:
   13.74 +
   13.75 +     Binaries from the build are:
   13.76 +	imap-2007/mtest/mtest		c-client testbed program
   13.77 +	imap-2007/ipopd/ipop2d		POP2 daemon
   13.78 +	imap-2007/ipopd/ipop3d		POP3 daemon
   13.79 +	imap-2007/imapd/imapd		IMAP4rev1 daemon
   13.80 +
   13.81 +     mtest is normally not used except by c-client developers.
   13.82 +
   13.83 +STEP 1:	inetd setup
   13.84 +
   13.85 +
   13.86 +     The ipop2d, ipop3d, and imapd daemons should be installed in a system
   13.87 +daemon directory and invoked by a listener such as xinetd or inetd.  In the
   13.88 +following examples, /usr/local/etc is used).
   13.89 +
   13.90 +STEP 1(A): xinetd-specific setup
   13.91 +
   13.92 +     If your system uses xinetd, the daemons are invoked by files in your
   13.93 +/etc/xinetd.d directory with names corresponding to the service names (that
   13.94 +is: imap, imaps, pop2, pop3, pop3s).  You will need to consult your local
   13.95 +xinetd documentation to see what should go into these files.  Here is a a
   13.96 +sample /etc/xinetd.d/imaps file:
   13.97 +
   13.98 +service imaps
   13.99 +{
  13.100 +	disable		= no
  13.101 +	socket_type	= stream
  13.102 +	wait		= no
  13.103 +	user		= root
  13.104 +	server		= /usr/local/etc/imapd
  13.105 +	groups		= yes
  13.106 +	flags		= REUSE IPv6
  13.107 +}
  13.108 +
  13.109 +STEP 1(B): inetd-specific setup
  13.110 +
  13.111 +     If your system still uses inetd, the daemons are invoked by your
  13.112 +/etc/inetd.conf file with lines such as:
  13.113 +
  13.114 +pop	stream	tcp	nowait	root	/usr/local/etc/ipop2d	ipop2d
  13.115 +pop3	stream	tcp	nowait	root	/usr/local/etc/ipop3d	ipop3d
  13.116 +imap	stream	tcp	nowait	root	/usr/local/etc/imapd	imapd
  13.117 +pop3s	stream	tcp	nowait	root	/usr/local/etc/ipop3d	ipop3d
  13.118 +imaps	stream	tcp	nowait	root	/usr/local/etc/imapd	imapd
  13.119 +
  13.120 +     Please refer to imap-2007/docs/BUILD for an important note about inetd's
  13.121 +limit on the number of new connections.  If that note applies to you, and you
  13.122 +can configure the number of connection in /etc/inetd.conf as described in
  13.123 +imap-2007/docs/build, here is the sample /etc/inetd.conf entry with SSL:
  13.124 +
  13.125 +pop3	stream	tcp	nowait.100	root	/usr/local/etc/ipop3d	ipop3d
  13.126 +pop3s	stream	tcp	nowait.100	root	/usr/local/etc/ipop3d	ipop3d
  13.127 +imap	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
  13.128 +imaps	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
  13.129 + (or, if you use TCP wrappers)
  13.130 +pop3	stream	tcp	nowait.100	root	/usr/local/etc/tcpd	ipop3d
  13.131 +imap	stream	tcp	nowait.100	root	/usr/local/etc/tcpd	imapd
  13.132 +pop3s	stream	tcp	nowait.100	root	/usr/local/etc/ipop3d	ipop3d
  13.133 +imaps	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
  13.134 +
  13.135 +NOTE: do *NOT* use TCP wrappers (tcpd) for the imaps and pop3s services!  I
  13.136 +don't know why, but it doesn't work with TCP wrappers.
  13.137 +
  13.138 +
  13.139 +STEP 2:	services setup
  13.140 +
  13.141 +     You may also have to edit your /etc/services (or Yellow Pages,
  13.142 +NetInfo, etc. equivalent) to register these services, such as:
  13.143 +
  13.144 +pop		109/tcp
  13.145 +pop3		110/tcp
  13.146 +imap		143/tcp
  13.147 +imaps		993/tcp
  13.148 +pop3s		995/tcp
  13.149 +
  13.150 +NOTE: The SSL IMAP service *MUST* be called "imaps", and the SSL POP3 service
  13.151 +*MUST* be called "pop3s".
  13.152 +
  13.153 +
  13.154 +STEP 3: PAM setup
  13.155 +
  13.156 +     If your system has PAM (Pluggable Authentication Modules -- most
  13.157 +modern systems do) then you need to set up PAM authenticators for imap and
  13.158 +pop.  The correct file names are
  13.159 +	/etc/pam.d/imap
  13.160 +and
  13.161 +	/etc/pam.d/pop
  13.162 +
  13.163 +     It probably works to copy your /etc/pam.d/ftpd file to the above two
  13.164 +names.
  13.165 +
  13.166 +     Many people get these file names wrong, and then spend a lot of time
  13.167 +trying to figure out why it doesn't work.  Common mistakes are:
  13.168 +	/etc/pam.d/imapd
  13.169 +	/etc/pam.d/imap4
  13.170 +	/etc/pam.d/imap4rev1
  13.171 +	/etc/pam.d/imaps
  13.172 +	/etc/pam.d/ipop3d
  13.173 +	/etc/pam.d/pop3d
  13.174 +	/etc/pam.d/popd
  13.175 +	/etc/pam.d/pop3
  13.176 +	/etc/pam.d/pop3s
  13.177 +
  13.178 +
  13.179 +STEP 4:	certificates setup
  13.180 +
  13.181 +NOTE: We can NOT provide you with support in obtaining certificates.  If you
  13.182 +need help in doing this, try the contacts mentioned in the OpenSSL README.
  13.183 +
  13.184 +WARNING: Do NOT install servers built with SSL support unless you also plan to
  13.185 +install proper certificates!  It is NOT supported to run SSL-enabled servers
  13.186 +on a system without the proper certificates.
  13.187 +
  13.188 +     You must set up certificates on /usr/local/ssl/certs (this may be
  13.189 +different if you have a non-standard installation of OpenSSL; for example,
  13.190 +FreeBSD has modified OpenSSL to use /usr/local/certs).  You should install
  13.191 +both the certificate authority certificates from the SSL distribution after
  13.192 +building OpenSSL, plus your own certificates.  The latter should have been
  13.193 +purchased from a certificate authority, although self-signed certificates are
  13.194 +permissible.  A sample certificate file is at the end of this document.
  13.195 +
  13.196 +     Install the resulting certificate file on /usr/local/ssl/certs, with a
  13.197 +file name consisting of the server name and a suffix of ".pem".  For example,
  13.198 +install the imapd certificate on /usr/local/ssl/certs/imapd.pem and the ipop3d
  13.199 +certificate on /usr/local/ssl/certs/ipop3d.pem.  These files should be
  13.200 +protected against random people accessing them.  It is permissible for
  13.201 +imapd.pem and ipop3d.pem to be links to the same file.
  13.202 +
  13.203 +     The imapd.pem and ipop3d.pem must contain a private key and a
  13.204 +certificate.  The private key must not be encrypted.
  13.205 +
  13.206 +     The following command to openssl can be used to create a self-signed
  13.207 +certificate with a 10-year expiration:
  13.208 +	req -new -x509 -nodes -out imapd.pem -keyout imapd.pem -days 3650
  13.209 +
  13.210 +			*** IMPORTANT ***
  13.211 +     We DO NOT recommend, encourage, or sanction the use of self-signed
  13.212 +certificates.  Nor will we be responsible for any problems (including security
  13.213 +problems!) which result from your use of a self-signed certificate.  Use of
  13.214 +self-signed certificates should be limited to testing only.  Buy a real
  13.215 +certificate from a certificate authority!
  13.216 +
  13.217 +			*** IMPORTANT ***
  13.218 +
  13.219 +     If you have a multihomed system with multiple domain names (and hence
  13.220 +separate certificates for each domain name), you can append the IP address
  13.221 +to the service name.  For example, the IMAP certificate for [12.34.56.78]
  13.222 +would be /usr/local/ssl/certs/imapd-12.34.56.78.pem and so on.  You only need
  13.223 +to use this feature if you need to use multiple certificates (because different
  13.224 +DNS names are used).
  13.225 +
  13.226 +
  13.227 +SAMPLE CERTIFICATE FILE
  13.228 +
  13.229 +     Here is a sample certificate file.  Do *NOT* use this on your own
  13.230 +machine; it is simply an example of what one would look like.
  13.231 +
  13.232 +-----BEGIN RSA PRIVATE KEY-----
  13.233 +MIICXQIBAAKBgQDHkqs4YDbakYxRkYXIpY7xLXDQwULR5LW7xWVzuWmmZJOtzwlP
  13.234 +7mN87g+aaiQzwXUVndaCw3Zm6cOG4mytf20jPZq0tvWnjEB3763sorpfpOe/4Vsn
  13.235 +VBFjyQY6YdqYXNmjmzff5gTAecEXOcJ8CrPsaK+nkhw7bHUHX2X+97oMNQIDAQAB
  13.236 +AoGBAMd3YkZAc9LUsig8iDhYsJuAzUb4Qi7Cppj73EBjyqKR18BaM3Z+T1VoIpQ1
  13.237 +DeXkr39heCrN7aNCdTh1SiXGPG6+fkGj9HVw7LmjwXclp4UZwWp3fVbSAWfe3VRe
  13.238 +LM/6p65qogEYuBRMhbSmsn9rBgz3tYVU0lDMZvWxQmUWWg7BAkEA6EbMJeCVdAYu
  13.239 +nQsjwf4vhsHJTChKv/He6kT93Yr/rvq5ihIAPQK/hwcmWf05P9F6bdrA6JTOm3xu
  13.240 +TvJsT/rIvQJBANv0yczI5pUQszw4s+LTzH+kZSb6asWp316BAMDedX+7ID4HaeKk
  13.241 +e4JnBK//xHKVP7xmHuioKYtRlsnuHpWVtNkCQQDPru2+OE6pTRXEqT8xp3sLPJ4m
  13.242 +ECi18yfjxAhRXIU9CUV4ZJv98UUbEJOEBtx3aW/UZbHyw4rwj5N511xtLsjpAkA9
  13.243 +p1XRYxbO/clfvf0ePYP621fHHzZChaUo1jwh07lXvloBSQ6zCqvcF4hG1Qh5ncAp
  13.244 +zO4pBMnwVURRAb/s6fOxAkADv2Tilu1asafmqVzpnRsdfBZx2Xt4oPtquR9IN0Q1
  13.245 +ewRxOC13KZwoAWtkS7l0mY19WD27onF6iAaF7beuK/Va
  13.246 +-----END RSA PRIVATE KEY-----
  13.247 +-----BEGIN CERTIFICATE-----
  13.248 +MIIECTCCA3KgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBujELMAkGA1UEBhMCVVMx
  13.249 +EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxHzAdBgNVBAoT
  13.250 +FkJsdXJkeWJsb29wIEluZHVzdHJpZXMxFjAUBgNVBAsTDUlTIERlcGFydG1lbnQx
  13.251 +ITAfBgNVBAMTGEJvbWJhc3RpYyBULiBCbHVyZHlibG9vcDEoMCYGCSqGSIb3DQEJ
  13.252 +ARYZYm9tYmFzdGljQGJsdXJkeWJsb29wLmNvbTAeFw0wMDA2MDYwMDUxMTRaFw0x
  13.253 +MDA2MDQwMDUxMTRaMIG6MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
  13.254 +bjEQMA4GA1UEBxMHU2VhdHRsZTEfMB0GA1UEChMWQmx1cmR5Ymxvb3AgSW5kdXN0
  13.255 +cmllczEWMBQGA1UECxMNSVMgRGVwYXJ0bWVudDEhMB8GA1UEAxMYQm9tYmFzdGlj
  13.256 +IFQuIEJsdXJkeWJsb29wMSgwJgYJKoZIhvcNAQkBFhlib21iYXN0aWNAYmx1cmR5
  13.257 +Ymxvb3AuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHkqs4YDbakYxR
  13.258 +kYXIpY7xLXDQwULR5LW7xWVzuWmmZJOtzwlP7mN87g+aaiQzwXUVndaCw3Zm6cOG
  13.259 +4mytf20jPZq0tvWnjEB3763sorpfpOe/4VsnVBFjyQY6YdqYXNmjmzff5gTAecEX
  13.260 +OcJ8CrPsaK+nkhw7bHUHX2X+97oMNQIDAQABo4IBGzCCARcwHQYDVR0OBBYEFD+g
  13.261 +lcPrnpsSvIdkm/eol4sYYg09MIHnBgNVHSMEgd8wgdyAFD+glcPrnpsSvIdkm/eo
  13.262 +l4sYYg09oYHApIG9MIG6MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
  13.263 +bjEQMA4GA1UEBxMHU2VhdHRsZTEfMB0GA1UEChMWQmx1cmR5Ymxvb3AgSW5kdXN0
  13.264 +cmllczEWMBQGA1UECxMNSVMgRGVwYXJ0bWVudDEhMB8GA1UEAxMYQm9tYmFzdGlj
  13.265 +IFQuIEJsdXJkeWJsb29wMSgwJgYJKoZIhvcNAQkBFhlib21iYXN0aWNAYmx1cmR5
  13.266 +Ymxvb3AuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAwEEk
  13.267 +JXpVXVaFTuG2VJGIzPOxQ+X3V1Cl86y4gM1bDbqlilOUdByUEG4YfSb8ILIn+eXk
  13.268 +WzMAw63Ww5t0/jkO5JRs6i1SUt0Oy80DryNRJYLBVBi499WEduro8GCVD8HuSkDC
  13.269 +yL1Rdq8qlNhWPsggcbhuhvpbEz4pAfzPkrWMBn4=
  13.270 +-----END CERTIFICATE-----
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/docs/Y2K	Mon Sep 14 15:17:45 2009 +0900
    14.3 @@ -0,0 +1,145 @@
    14.4 +/* ========================================================================
    14.5 + * Copyright 1988-2006 University of Washington
    14.6 + *
    14.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    14.8 + * you may not use this file except in compliance with the License.
    14.9 + * You may obtain a copy of the License at
   14.10 + *
   14.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   14.12 + *
   14.13 + * 
   14.14 + * ========================================================================
   14.15 + */
   14.16 +
   14.17 +QUESTION: Is c-client Y2K compliant?
   14.18 +
   14.19 +ANSWER:
   14.20 +
   14.21 +     There are no known Y2K issues in c-client; nor have there ever
   14.22 +been any known Y2K issues in c-client from its inception.
   14.23 +
   14.24 +     Some older versions of c-client don't like the two-digit year
   14.25 +"00", although the only impact of this is that messages with that year
   14.26 +will sort before any other messages.  Nobody should be using two-digit
   14.27 +years in email messages any more (use "2000" instead of "00").
   14.28 +
   14.29 +     You may wish to read the document calendar.txt for more
   14.30 +information about the Y3.3K/Y4K, Y20K, and Y4)K issues.  Assuming that
   14.31 +c-client is still around in 2000-40,000 years, someone will have to
   14.32 +deal with these.
   14.33 +
   14.34 +     Within the plausible lifetimes of people today, there are three
   14.35 +known date-related issues in c-client which will have to be addressed
   14.36 +in the future.  If I am still alive when the first problem hits, I
   14.37 +will be nearly 82 years old, and won't be maintaining c-client any
   14.38 +more.
   14.39 +
   14.40 +
   14.41 +Y2038:
   14.42 +
   14.43 +     c-client, like most UNIX software, has Y2038 issues.  On Tuesday,
   14.44 +January 19, 2038 at 03:14:08 Coordinated Universal Time (also known as
   14.45 +UTC, UT, or historically GMT), the clock on 32-bit UNIX systems will
   14.46 +wrap around to a negative number; that is, from 0x7fffffff to
   14.47 +0x80000000.
   14.48 +
   14.49 +     c-client uses an unsigned long for its 32-bit time; however the C
   14.50 +library on most UNIX systems uses a signed long and will interpret
   14.51 +that time as being Friday, December 13, 1901 at 20:45:52 UTC.
   14.52 +
   14.53 +     Fixing this problem will require changing the C library to use
   14.54 +either unsigned longs or a wider (e.g. 64-bit) value for time.  Lots
   14.55 +of work will need to be done on 32-bit UNIX systems as 2038
   14.56 +approaches.  History suggests that most of the work will be done in
   14.57 +the autumn of 2037... ;-) It's not known if anything is necessary to
   14.58 +do to c-client other than just rebuild it with the new C library.
   14.59 +
   14.60 +     Going to 32-bit unsigned longs means that there will be a Y2106
   14.61 +bug that someone will have to fix.  Hopefully nobody will even think
   14.62 +of using 32-bit systems by then.
   14.63 +
   14.64 +
   14.65 +Y2070:
   14.66 +
   14.67 +     c-client assumes that 2-digit years with values of 70 or greater
   14.68 +are in the 20th century, and that 2-digit years with values of 69 or
   14.69 +less are in the 21st century.  Time for UNIX began on January 1, 1970
   14.70 +and email on ARPAnet happened between the first TENEX systems shortly
   14.71 +after that; consequently there is no ambiguity with email data with
   14.72 +2-digit years prior to the year 2070.  This is used only when parsing
   14.73 +a 2-digit year.  c-client never generates one.
   14.74 +
   14.75 +     Fixing this problem requires convincing people not to use 2-digit
   14.76 +years.  This is a lesson that people should have figured out 70 years
   14.77 +earlier with Y2K.  Consequently, this may be a "non-problem."
   14.78 +Otherwise, look in mail_parse_date() for the comment "two digit year"
   14.79 +and change the statement as desired.  [Note: do not change the
   14.80 +definition of BASEYEAR since the UNIX port assumes that this matches
   14.81 +when time began in the operating system.]
   14.82 +
   14.83 +
   14.84 +Y2098:
   14.85 +
   14.86 +     On January 1, 2098, the year in per-message internal dates will
   14.87 +expire, since a 7-bit field is allocated for the year.  c-client will
   14.88 +mistakenly think that the day is January 1, 1970.
   14.89 +
   14.90 +     Fortunately, it is easy to fix this problem.  Just increase the
   14.91 +width of "year" in MESSAGECACHE in mail.h.  If you make it 8 bits,
   14.92 +it'll be good until January 1, 2216; 9 bits makes it good until 2482.
   14.93 +10 bits will push it back that you'd worry about the Y2800 question
   14.94 +before having to increase it again.  If you ignore Y2800, 11 bits will
   14.95 +push it it back to having to worry about Y4K first.
   14.96 +
   14.97 +
   14.98 +Y2800:
   14.99 +
  14.100 +     At this year, you will need to decide whether to keep the Gregorian
  14.101 +calendar, which is one day slow every 20,000 years, or go to the more
  14.102 +accurate Eastern Orthodox calendar which is one day slow every 45,000
  14.103 +years.  The Gregorian and Eastern Orthodox calendars diverge at this
  14.104 +year.
  14.105 +
  14.106 +     There hasn't been any statement about how the international
  14.107 +community will deal with the situation of the Orthodox calendar being
  14.108 +one day ahead of the Gregorian calendar between 2800 and 2900.  This
  14.109 +will happen again between 3200 and 3300, and at gradually increasing
  14.110 +intervals until 48,300 when the shift becomes permanent (assuming no
  14.111 +Y20K or Y40K fixes).
  14.112 +
  14.113 +     If you wish to make the transition to the Eastern Orthodox calendar,
  14.114 +rebuild c-client with -DUSEORTHODOXCALENDAR=1.  You can then ignore Y4K
  14.115 +and Y20K!
  14.116 +    
  14.117 +
  14.118 +Y3.3K/Y4K:
  14.119 +
  14.120 +     Some time around the year 3300, the calendar has gotten one day
  14.121 +behind.  To remedy this, a little-known rule in the Gregorian calendar
  14.122 +is that years that are evenly divisible by 4000 are not leap years.
  14.123 +Unlike the other rules, this rule hasn't had effect yet, and won't for
  14.124 +another 2000 years.
  14.125 +
  14.126 +     To fix the Y4K problem, just rebuild c-client with -DY4KBUGFIX=1.
  14.127 +
  14.128 +
  14.129 +Y20K:
  14.130 +
  14.131 +     Those of you who stuck with the Gregorian calendar have a
  14.132 +problem; the calendar is now one day slow.  The Pope has not made any
  14.133 +statement about how this problem will be fixed.  Maybe they'll declare
  14.134 +that 20,004 is also not a leap year or something.
  14.135 +
  14.136 +     There is no fix for this problem in c-client.
  14.137 +
  14.138 +
  14.139 +Y40K:
  14.140 +
  14.141 +     Greeks, Serbs, Russians, and other Eastern Orthodox have spent
  14.142 +the past 38,000 years laughing at westerners' increasingly futile
  14.143 +efforts to keep the Gregorian calendar in order.  The day of reckoning
  14.144 +has come; the Orthodox calendar is now one day slow.  The Patriarch of
  14.145 +Istanbul (nee Constantinople) has not made any statement about how this
  14.146 +will be fixed.
  14.147 +
  14.148 +     There is no fix for this problem in c-client.
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/docs/bugs.txt	Mon Sep 14 15:17:45 2009 +0900
    15.3 @@ -0,0 +1,234 @@
    15.4 +/* ========================================================================
    15.5 + * Copyright 1988-2007 University of Washington
    15.6 + *
    15.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    15.8 + * you may not use this file except in compliance with the License.
    15.9 + * You may obtain a copy of the License at
   15.10 + *
   15.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   15.12 + *
   15.13 + * 
   15.14 + * ========================================================================
   15.15 + */
   15.16 +
   15.17 +	   KNOWN BUGS/MISFEATURES/DEFICIENCIES IN THE IMAP TOOLKIT
   15.18 +			Last Updated: 15 November 2007
   15.19 +
   15.20 +The following are known problems/deficiencies in the imap-2007 toolkit:
   15.21 +
   15.22 + . Possible problems for some installations:
   15.23 +   . In some versions of Redhat Linux, SVR4-style timezone name lookup
   15.24 +      doesn't work properly due to a bug in glibc.  The workaround is to
   15.25 +      edit os_lnx.c to include tz_bsd.c instead of tz_sv4.c.  Note that
   15.26 +      other versions of Linux don't support BSD-style timezone name
   15.27 +      lookup, so don't make this change unless it's needed on your system.
   15.28 +   . In some systems, the OpenSSL distribution is installed other than at
   15.29 +      the standard /usr/local/ssl location.  If this is the case on your
   15.30 +      system and you want to build with SSL support, you will need to set
   15.31 +      the SSLDIR variable, either by including a setting of EXTRASPECIALS
   15.32 +      in the make command line, e.g.
   15.33 +       build lnp SPECIALAUTHENTICATORS=ssl EXTRASPECIALS="SSLDIR=/usr/ssl"
   15.34 +      or by editing .../src/osdep/unix/Makefile
   15.35 +   . /tmp, /usr/tmp or /var/tmp (if present), and the mail spool directory
   15.36 +      must be protected 1777 (world write with sticky bit); otherwise
   15.37 +      mailbox locking and updates won't work.  An alternative to 1777 on
   15.38 +      the mail spool directory is to install the mlock program that is
   15.39 +      bundled with the IMAP toolkit.
   15.40 +   . Multiple access protection locking does not work if the mailbox or
   15.41 +      /tmp are NFS mounted.
   15.42 +   . Shared access mailbox formats (mbx, mtx, mx, and tenex) do not work
   15.43 +      well with NFS and such usage is not supported.  mmdf and unix formats
   15.44 +      are supported for use over NFS; however there won't be any multiple
   15.45 +      access locking protection.
   15.46 +   . Server startup delays may occur if a reverse DNS (IP address to name)
   15.47 +      lookup on the client's IP address does not complete in an expeditious
   15.48 +      fashion.  This is actually a DNS problem and should be fixed in the
   15.49 +      DNS and/or the server's host table.  A workaround exists (see the
   15.50 +      top-level Makefile for details) but is not recommended and can not
   15.51 +      be used at all with Kerberos.
   15.52 +   . At the insistance of the security gurus, SSL certification validation
   15.53 +      is now on by default.  This means that you must now use the new
   15.54 +      /novalidate-cert switch if establishing an SSL connection to a server
   15.55 +      with a self-signed certificate; i.e. if "imap.example.com" has a
   15.56 +      self-signed certificate, you must use a mailbox name such as
   15.57 +       {imap.example.com/ssl/novalidate-cert}INBOX
   15.58 +      to get an SSL session instead of just
   15.59 +       {imap.example.com/ssl}INBOX
   15.60 +   . GCC 8.x and above on SGI systems does not correctly pass/return
   15.61 +      structures which are smaller than 16 bytes and are not 8 bytes.  The
   15.62 +      problem is that structures are padded at the wrong end; e.g. a 4 byte
   15.63 +      structure is loaded into the lower 4 bytes of the register when it
   15.64 +      should be loaded into the upper 4 bytes of the register.  This affects
   15.65 +      IRIX 6 the most because it is a 64-bit system and 4 byte structures are
   15.66 +      common.  This compiler bug impacts the use of inet_ntoa() in c-client
   15.67 +      and causes syslog messages to show IP addresses as 255.255.255.255
   15.68 +      instead of the correct values.  The fix is either to use SGI's C compiler
   15.69 +      instead of GCC or link with an implementation of inet_ntoa() that was
   15.70 +      built with GCC instead of the standard SGI C library version.
   15.71 +   . By default, the UNIX SSL build assumes that RSAREF is not needed, because
   15.72 +      RSA Security Inc. released the RSA public key encryption algorithm into
   15.73 +      the public domain on September 6, 2000.  There is no longer any need to
   15.74 +      use RSAREF, and since RSAREF is slower than OpenSSL's RSA routines
   15.75 +      there's good reason not to.  If for some reason you still want to use
   15.76 +      RSAREF, you will need to edit .../src/osdep/unix/Makefile to
   15.77 +      change SSLRSA to load libRSAglue and librsaref.
   15.78 +   . By default, the UNIX SSL build assumes that no name conflict exists
   15.79 +      between OpenSSL and Kerberos 5.  If you are using an older version
   15.80 +      of Kerberos, you may need to edit .../src/osdep/unix/Makefile
   15.81 +      to change SSLCRYPTO so that it loads the OpenSSL libcrypto library
   15.82 +      explicitly as libcrypto.a.
   15.83 +   . By default, host names are canonicalized via gethostbyname() and
   15.84 +      gethostbyaddr() for everything except for SSL certificate validation.
   15.85 +      This can represent a security bug due to DNS spoofing, but is more
   15.86 +      likely to deliver results that users expect and also may be necessary
   15.87 +      to get Kerberos to work.  Set variable "trustdns" in mail.c to NIL if
   15.88 +      you want to disable this.
   15.89 +
   15.90 + . Bugs:
   15.91 +   . It doesn't work to have a "}" character as a user name in /user= in a
   15.92 +      mailbox name, even if the user name is quoted.  In other words,
   15.93 +       {example.com/user="foo}bar"}zap
   15.94 +      won't work; foo will be interpreted as an unterminated quoted string
   15.95 +      and the remote mailbox name will be
   15.96 +       bar"}zap.
   15.97 +   . The experimental mx driver has performance problems and shouldn't be used
   15.98 +   . docs/internal.txt is out of date (again)
   15.99 +
  15.100 + . UIDPLUS bugs/limitations:
  15.101 +   . Not supported in all local file formats (see below).
  15.102 +   . There are two known issues with UIDPLUS in the mmdf and unix formats:
  15.103 +     (a) If the destination mailbox is currently selected (whether in this
  15.104 +         or another session), no COPYUID or APPENDUID is returned.  The other
  15.105 +         choice was to assign a UID based upon the uid_last value and hope
  15.106 +         that the session selecting the mailbox would pick it up and update
  15.107 +         uid_last.  The problem was a timing race if another message was
  15.108 +         copied/appended to that mailbox before the selecting session updated
  15.109 +         the mailbox.  If the timing race is lost, then all UID in the mailbox
  15.110 +         would be reassigned by the selecting session, thus making the
  15.111 +         returned APPENDUID/COPYUID data useless and causing a performance
  15.112 +         problem.
  15.113 +          Earlier versions did the "hope for the best" method.  This was
  15.114 +         revoked in favor of not returning COPYUID/APPENDUID.
  15.115 +          Although this violates RFC 4315, there is a loophole which, although
  15.116 +         for other purposes, permits this behavior.
  15.117 +     (b) There is a known failure if the destination mailbox is currently
  15.118 +         selected by legacy software (e.g. older versions of the IMAP
  15.119 +         server, Pine, etc.).  In this case, all UIDs end up being
  15.120 +         reassigned by the legacy software.
  15.121 +
  15.122 + . Annoyances:
  15.123 +   . Friendly host names (e.g. "server" instead of "server.foo.com") can't be
  15.124 +      used in a mailbox name with SSL certificate validation; you have to enter
  15.125 +      the fully-qualified domain name.  This is a requirement established by
  15.126 +      the security gurus.
  15.127 +
  15.128 + . IMAP client limitations:
  15.129 +   . No SASL protection mechanisms (SASL authentication mechanisms are
  15.130 +      supported)
  15.131 +
  15.132 + . NNTP client limitations:
  15.133 +   . Non-standard IMAP SCAN extension not supported
  15.134 +
  15.135 + . POP client limitations:
  15.136 +   . No SASL protection mechanisms (SASL authentication mechanisms are
  15.137 +      supported)
  15.138 +   . No POP3 UID support
  15.139 +   . Non-standard IMAP SCAN extension not supported
  15.140 +
  15.141 + . SMTP client limitations:
  15.142 +   . No SASL protection mechanisms (SASL authentication mechanisms are
  15.143 +      supported)
  15.144 +   . No support for use of TURN, ETRN, and pipelining.
  15.145 +   . No support for enhanced status codes
  15.146 +
  15.147 + . UNIX limitations:
  15.148 +   . IPv6 is supported but is not the default on most platforms; you have to
  15.149 +      use IP=6 in the make command
  15.150 +   . Supported local file formats: mbx, mh, mmdf, mix, mtx, mx, news, phile,
  15.151 +      tenex, unix
  15.152 +   . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS, GSSAPI
  15.153 +   . Sticky UIDs are not supported in the mh, mtx, and tenex drivers
  15.154 +   . Creation of keywords is not supported in the mh, mtx, and tenex drivers
  15.155 +   . Copy and append of keywords only works in the mbx driver.
  15.156 +   . Flat file formats (mbx, mmdf, mtx, phile, tenex, unix) do not permit
  15.157 +      mailboxes to have inferior names
  15.158 +   . SSL temporary key should be seeded better than it is.
  15.159 +   . UIDPLUS support is limited to the unix, mmdf, mbx, mx, and mix formats.
  15.160 +   . Non-standard IMAP SCAN extension not support for mh and news formats.
  15.161 +
  15.162 + . Amiga limitations:
  15.163 +   . Supported local file formats: mbx, mh, mmdf, mix, mtx, mx, news, phile,
  15.164 +      tenex, unix
  15.165 +   . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS
  15.166 +   . Sticky UIDs are not supported in the mh, mtx, and tenex drivers
  15.167 +   . Creation of keywords is not supported in the mh, mtx, and tenex drivers
  15.168 +   . Copy and append of keywords only works in the mbx driver.
  15.169 +   . Flat file formats (mbx, mmdf, mtx, phile, tenex, unix) do not permit
  15.170 +      mailboxes to have inferior names
  15.171 +   . UIDPLUS support is limited to the unix, mmdf, mbx, mx, and mix formats.
  15.172 +   . Non-standard IMAP SCAN extension not supported for mh and news formats.
  15.173 +
  15.174 + . Win32 (Win9x/NT/Windows 2000) limitations:
  15.175 +   . IPv6 is supported in W2K builds but is not the default; you have to use
  15.176 +      IP=6 in the nmake command
  15.177 +   . Supported local file formats: mbx, mtx, tenex, unix
  15.178 +   . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS, GSSAPI
  15.179 +   . No server SSL or TLS support.
  15.180 +   . No server authentication for GSSAPI
  15.181 +   . No server authentication for CRAM-MD5 on NT-based Windows (NT/2K/XP);
  15.182 +      it does work on DOS-based Windows (9x/Me).
  15.183 +   . Sticky UIDs are not supported in the mtxnt and tenexnt drivers
  15.184 +   . Creation of keywords is not supported in the mtxnt and tenexnt drivers
  15.185 +   . Copy and append of keywords only works in the mbxnt driver.
  15.186 +   . No support for TCP open timeouts
  15.187 +   . Flat file formats (mbx, mtx, tenex, unix) do not permit mailboxes to have
  15.188 +      inferior names
  15.189 +   . UIDPLUS support is limited to the unix and mbx formats.
  15.190 +
  15.191 + . Win16 (Win3.1)/DOS limitations:
  15.192 +   . IPv6 not supported
  15.193 +   . Supported local file formats: bezerk, mtx
  15.194 +   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
  15.195 +   . Supported TCPs: B&W, Novell, PC-NFs, PC/TCP, Waterloo, Winsock
  15.196 +   . Sticky UIDs are not supported on local files
  15.197 +   . Creation of keywords are not supported on local files
  15.198 +   . Bezerk driver is read-only and does not handle LF-only newlines well
  15.199 +   . No support for any TCP timeouts on Waterloo DOS
  15.200 +   . No support for TCP open timeouts on Winsock and generic DOS
  15.201 +   . Flat file formats (bezerk, mtx) do not permit mailboxes to have inferior
  15.202 +      names
  15.203 +   . Does not work well unless a mailgets routine is armed when fetching
  15.204 +      texts.
  15.205 +
  15.206 + . Mac limitations:
  15.207 +   . IPv6 not supported
  15.208 +   . No local file drivers
  15.209 +   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
  15.210 +   . Does not output human-friendly time zone string
  15.211 +
  15.212 + . TOPS-20 limitations:
  15.213 +   . IPv6 not supported
  15.214 +   . No local file drivers
  15.215 +   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
  15.216 +   . No support for any TCP timeouts
  15.217 +
  15.218 + . VMS limitations:
  15.219 +   . IPv6 not supported
  15.220 +   . No local file drivers
  15.221 +   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
  15.222 +   . Supported TCPs: Multinet, Netlib
  15.223 +   . No support for any TCP timeouts on VMS Netlib
  15.224 +   . No support for TCP open timeouts on VMS Multinet
  15.225 +   . Time zone must be configured at build time
  15.226 +   . Does not output human-friendly time zone string
  15.227 +
  15.228 + . Windows CE limitations:
  15.229 +   . IPv6 not yet supported
  15.230 +   . No local file drivers
  15.231 +   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
  15.232 +   . No support for TCP open timeouts
  15.233 +   . Not finished, only builds c-client library
  15.234 +
  15.235 + . OS/2 limitations:
  15.236 +   . IPv6 not supported
  15.237 +   . Not finished, does not build
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/docs/calendar.txt	Mon Sep 14 15:17:45 2009 +0900
    16.3 @@ -0,0 +1,332 @@
    16.4 +/* ========================================================================
    16.5 + * Copyright 1988-2006 University of Washington
    16.6 + *
    16.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    16.8 + * you may not use this file except in compliance with the License.
    16.9 + * You may obtain a copy of the License at
   16.10 + *
   16.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   16.12 + *
   16.13 + * 
   16.14 + * ========================================================================
   16.15 + */
   16.16 +
   16.17 +			 ALL ABOUT CALENDARS
   16.18 +
   16.19 +     Although one can never be sure of what will happen at some future
   16.20 +time, there is strong historical precedent for presuming that the
   16.21 +present Gregorian calendar will still be in effect within the useful
   16.22 +lifetime of the IMAP toolkit.  We have therefore chosen to adhere to
   16.23 +these precedents.
   16.24 + 
   16.25 +     The purpose of a calendar is to reckon time in advance, to show
   16.26 +how many days have to elapse until a certain event takes place in the
   16.27 +future, such as the harvest or the release of a new version of Pine.
   16.28 +The earliest calendars, naturally, were crude and tended to be based
   16.29 +upon the seasons or the lunar cycle.
   16.30 + 
   16.31 +
   16.32 +ANCIENT CALENDARS
   16.33 +
   16.34 +     The calendar of the Assyrians, for example, was based upon the
   16.35 +phases of the moon.  They knew that a lunation (the time from one full
   16.36 +moon to the next) was 29 1/2 days long, so their lunar year had a
   16.37 +duration of 354 days.  This fell short of the solar year by about 11
   16.38 +days.  (The exact time for the solar year is approximately 365 days, 5
   16.39 +hours, 48 minutes, and 46 seconds.)  After 3 years, such a lunar
   16.40 +calendar would be off by a whole month, so the Assyrians added an extra
   16.41 +month from time to time to keep their calendar in synchronization with
   16.42 +the seasons.
   16.43 + 
   16.44 +     The best approximation that was possible in antiquity was a 19-year
   16.45 +period, with 7 of these 19 years having 13 months (leap months).  This
   16.46 +scheme was adopted as the basis for the lunar calendar used by the
   16.47 +Hebrews.  The Arabs also used this calendar until Mohammed forbade
   16.48 +shifting from 12 months to 13 months; this causes the Muslim holy month
   16.49 +of Ramadan to move backwards through the seasons, completing a cycle
   16.50 +every 32 1/2 years.
   16.51 + 
   16.52 +     When Rome emerged as a world power, the difficulties of making a
   16.53 +calendar were well known, but the Romans complicated their lives because
   16.54 +of their superstition that even numbers were unlucky.  Hence their
   16.55 +months were 29 or 31 days long, with the exception of February, which
   16.56 +had 28 days.  Every second year, the Roman calendar included an extra
   16.57 +month called Mercedonius of 22 or 23 days to keep up with the solar
   16.58 +year.
   16.59 +
   16.60 +
   16.61 +JULIAN CALENDAR
   16.62 +
   16.63 +     Even this algorithm was very poor, so that in 45 BCE, Caesar,
   16.64 +advised by the astronomer Sosigenes, ordered a sweeping reform.  By
   16.65 +imperial decree, the year 46 BCE was made 445 days long to bring the
   16.66 +calendar back in step with the seasons.  The new calendar, similar to
   16.67 +the one we now use was called the Julian calendar (named after Julius
   16.68 +Caesar).
   16.69 +
   16.70 +     Months in the Julian calendar were 30 or 31 days in length and
   16.71 +every fourth year was made a leap year (having 366 days) by adding a day
   16.72 +to the end of the year.  This leap year rule was not consistantly
   16.73 +applied until 8 CE.  The year-ending month of February, never a popular
   16.74 +month, was presently shortened so that Julius Caesar and Emperor
   16.75 +Augustus could each have long months named after them.
   16.76 +
   16.77 +     Caesar also decreed that the year would start with the first of
   16.78 +January, which since 153 BCE was the day that Roman consuls took office,
   16.79 +and not the vernal equinox in late March.  Not everyone accepted that
   16.80 +part of his reform, as we shall see.
   16.81 +
   16.82 + 
   16.83 +GREGORIAN CALENDAR
   16.84 +
   16.85 +     Caesar's year was 11 1/2 minutes short of the calculations
   16.86 +recommended by Sosigenes and eventually the date of the vernal equinox
   16.87 +began to drift.  Roger Bacon became alarmed and sent a note to Pope
   16.88 +Clement IV, who apparently was not impressed.  Pope Sixtus IV later
   16.89 +became convinced that another reform was needed and called the German
   16.90 +astronomer, Regiomontanus, to Rome to advise him.  Unfortunately,
   16.91 +Regiomontanus died of the plague shortly thereafter and the plans died
   16.92 +as well.
   16.93 + 
   16.94 +     In 1545, the Council of Trent authorized Pope Gregory XIII to
   16.95 +reform the calendar once more.  Most of the mathematical work was done
   16.96 +by Father Christopher Clavius, S.J.  The immediate correction that was
   16.97 +adopted was that Thursday, October 4, 1582 was to be the last day of the
   16.98 +Julian calendar.  The next day was Friday, with the date of October 15.
   16.99 +For long range accuracy, a formula suggested by the Vatican librarian
  16.100 +Aloysius Giglio was adopted.  It said that every fourth year is a leap
  16.101 +year except for century years that are not divisible by 400.  Thus 1700,
  16.102 +1800 and 1900 would not be leap years, but 2000 would be a leap year
  16.103 +since 2000 is divisible by 400.  This rule eliminates 3 leap years every
  16.104 +4 centuries, making the calendar sufficiently correct for most ordinary
  16.105 +purposes.  This calendar is known as the Gregorian calendar and is the
  16.106 +one that we now use today.
  16.107 +
  16.108 +     It is interesting to note that in 1582, all the Protestant princes
  16.109 +ignored the papal decree and so many countries continued to use the
  16.110 +Julian calendar until either 1698 or 1752.  Britain and its American
  16.111 +colonies went from Wednesday, September 2, 1752 to Thursday, September
  16.112 +14.  Prior to the changeover, the British used March 25 as the start of
  16.113 +the new year.
  16.114 +
  16.115 +     In Russia, it needed the revolution to introduce the Gregorian
  16.116 +calendar in 1918.  Turkey didn't adopt it until 1927.
  16.117 +
  16.118 +
  16.119 +NUMBERING OF YEARS
  16.120 +
  16.121 +     The numbering of the year is generally done according to an "era",
  16.122 +such as the year of a ruler's reign.
  16.123 +
  16.124 +     In about 525, a monk named Dionysius Exiguus suggested that the
  16.125 +calculated year of Jesus' birth be designated as year 1 in the Julian
  16.126 +calendar.  This suggestion was adopted over the next 500 years and
  16.127 +subsequently followed in the Gregorian calendar.
  16.128 +
  16.129 +     For the benefit of those who seek religious significance to the
  16.130 +calendar millenium, note that year 1 is too late by at least 4 years.
  16.131 +Herod the Great, named in the Christian Bible as having all children in
  16.132 +Bethlehem put to death in an attempt to kill the infant Jesus, died in 4
  16.133 +BCE.
  16.134 +
  16.135 +     Nothing particularly significant of an historic or religious nature
  16.136 +happened in Gregorian year 1; however it has become a worldwide standard
  16.137 +as the "common era."  In modern times, the terms "CE" (common era) and
  16.138 +"BCE" (before common era) are preferred over the earlier (and, as we
  16.139 +have seen, less accurate) "AD" (anno Domini, "the year of the Lord") and
  16.140 +"BC" (before Christ).
  16.141 +
  16.142 +     The Hebrew lunar calendar begins at 3760 BCE, the year of creation
  16.143 +in Jewish tradition.  The Muslim lunar calendar begins on July 16, 622,
  16.144 +when Mohammed fled from Mecca to Medina.
  16.145 +
  16.146 +     The Japanese, Taiwanese, and North Koreans use the Gregorian
  16.147 +calendar, but number the year by political era.  In Japan, an era
  16.148 +begins when an emperor succeeds to the throne; year 1 of the Heisei
  16.149 +era was 1989 when Emperor Akihito ascended to the throne (the first
  16.150 +few days of 1989 was year 64 of the Shouwa era).  In Taiwan, year 1 is
  16.151 +the first full year after the founding of the Republic of China in 1911.
  16.152 +In North Korea, year 1 is the year of the Juche (self-reliance) ideal,
  16.153 +corresponding to the birth year of founder Kim Il-Sung (1912).  Thus,
  16.154 +year 2000 is Heisei 12 (Japan), 89th year of the Republic (Taiwan),
  16.155 +and Juche 89 (North Korea).
  16.156 +
  16.157 +
  16.158 +FURTHER MODIFICATIONS TO THE GREGORIAN CALENDAR
  16.159 +
  16.160 +     Despite the great accuracy of the Gregorian calendar, it still
  16.161 +falls behind very slightly every few years.  The most serious problem
  16.162 +is that the earth's rotation is slowing gradually.  If you are very
  16.163 +concerned about this problem, we suggest that you tune in short wave
  16.164 +radio station WWV or the Global Positioning System, which broadcasts
  16.165 +official time signals for use in the United States.  About once every
  16.166 +3 years, they declare a leap second at which time you should be
  16.167 +careful to adjust your system clock.  If you have trouble picking up
  16.168 +their signals, we suggest you purchase an atomic clock (not part of
  16.169 +the IMAP toolkit).
  16.170 +
  16.171 +     Another problem is that the Gregorian calendar represents a year
  16.172 +of 365.2425 days, whereas the actual time taken for the earth to
  16.173 +rotate around the Sun is 365.2421991 days.  Thus, the Gregorian calendar
  16.174 +is actually 26 seconds slow each year, resulting in the calendar
  16.175 +being one day behind every 3,300 or so years (a Y3.3K problem).
  16.176 +
  16.177 +     Consequently, the Gregorian calendar has been modified with a
  16.178 +further rule, which is that years evenly divisible by 4000 are not
  16.179 +leap years.  Thus, the year 4000 will not be a leap year.  Or, at
  16.180 +least we assume that's what will happen assuming that the calendar
  16.181 +remains unchanged for the next 2000 years.
  16.182 +
  16.183 +     The modified Gregorian calendar represents a year of 365.24225
  16.184 +days.  Thus, the modified Gregorian calendar is actually 4 seconds
  16.185 +slow each year, resulting in the calendar being one day slow every
  16.186 +20,000 or so years.  So there will be a Y20K problem.
  16.187 +
  16.188 +     There is some dispute whether the modified Gregorian calendar was
  16.189 +officially adopted, or if it's just a proposal.  Other options (see
  16.190 +below) exist; fortunately no decision needs to be made for several
  16.191 +centuries yet.
  16.192 +
  16.193 +     There is code in c-client to support the modified Gregorian
  16.194 +calendar, although it is currently disabled.  Sometime in the next
  16.195 +2000 years, someone will need to enable this code so that c-client is
  16.196 +Y4K compiliant.  Then, 18,000 years from now, someone will have to
  16.197 +tear into c-client's code to fix the Y20K bug.
  16.198 +
  16.199 +
  16.200 +EASTERN ORTHODOX MODIFICATION OF THE GREGORIAN CALENDAR
  16.201 +
  16.202 +     The Eastern Orthodox church in 1923 established its own rules to
  16.203 +correct the Julian calendar.  In their calendar, century years modulo
  16.204 +900 must result in value of 200 or 600 to be considered a leap year.
  16.205 +Both the Orthodox and Gregorian calendar agree that the years 2000 and
  16.206 +2400 will be leap years, and the years 1900, 2100, 2200, 2300, 2500,
  16.207 +2600, 2700 are not.  However, the year 2800 will be a leap year in the
  16.208 +Gregorian calendar but not in the Orthodox calendar; similarly, the
  16.209 +year 2900 will be a leap year in the Orthodox calendar but not in the
  16.210 +Gregorian calendar.  Both calendars will agree that 3000 and
  16.211 +3100 are leap years, but will disagree again in 3200 and 3300.
  16.212 +
  16.213 +     There is code in c-client to support the Orthodox calendar.  It
  16.214 +can be enabled by adding -DUSEORTHODOXCALENDAR=1 to the c-client
  16.215 +CFLAGS, e.g.
  16.216 +	make xxx EXTRACFLAGS="-DUSEORTHODOXCALENDAR=1"
  16.217 +
  16.218 +     The Orthodox calendar represents a year of 365.24222222... days.
  16.219 +Thus, the Orthodox calendar is actually 2 seconds slow each year,
  16.220 +resulting in the calendar being one day slow every 40,000 or so years.
  16.221 +The Eastern Orthodox church has not yet made any statements on how the
  16.222 +Y40K bug will be fixed.
  16.223 +
  16.224 +
  16.225 +OTHER ISSUES AFFECTING THE CALENDAR IN THE FUTURE
  16.226 +
  16.227 +     The effect of leap seconds also needs to be considered when
  16.228 +looking at the Y3.3K/Y4K, Y20K, and Y40K problems.  Leap seconds put
  16.229 +the clock back in line with the Earth's rotation, whereas leap years
  16.230 +put the calendar back in line with the Earth's revolution.  Since leap
  16.231 +seconds slow down the clock (and hence the calendar), they actually
  16.232 +bring the day of reckoning for the Gregorian and Orthodox calendars
  16.233 +sooner.
  16.234 +
  16.235 +     Another factor is that the next ice age (technically, the end of
  16.236 +the current interglacial period; we are in the middle of an ice age
  16.237 +now!) is due around Y25K.  It is not known what perturbations this will
  16.238 +cause on the Earth's rotation and revolution, nor what calendar
  16.239 +adjustments will be necessary at that time.
  16.240 +
  16.241 +     Hence my use of "or so" in predicting the years that the calendar
  16.242 +will fall behind.  The actual point may be anywhere from decades (in the
  16.243 +case of Y3.3K) to millenia (in the case of Y40K) off from these predictions.
  16.244 +
  16.245 +
  16.246 +MEANINGS OF DAY NAMES
  16.247 +
  16.248 +     The names of days of the week from a combination of Roman and
  16.249 +Germanic names for celestial bodies:
  16.250 +. Sunday	Latin "dies solis" => "Sun's day"
  16.251 +. Monday	Latin "dies lunae" => "Moon's day"
  16.252 +. Tuesday	Germanic "Tiw's day" => "Mars' day"
  16.253 +. Wednesday	Germanic "Woden's day" => "Mercury's day"
  16.254 +. Thursday	Germanic "Thor's day" => "Jupiter's day"
  16.255 +. Friday	Germanic "Frigg's day" => "Venus' day"
  16.256 +. Saturday	Latin "dies Saturni" => "Saturn's day"
  16.257 +
  16.258 +
  16.259 +MEANINGS OF MONTH NAMES
  16.260 +
  16.261 +     The names of the months are from the Roman calendar:
  16.262 +. January	Janus, protector of doorways
  16.263 +. February	Februalia, a time for sacrifice to atone for sins
  16.264 +. March		Mars, god of war
  16.265 +. April		Latin "aperire" => "to open" buds
  16.266 +. May		Maia, goddess of plant growth
  16.267 +. June		Latin "juvenis" => "youth"
  16.268 +. July		Julius Caesar
  16.269 +. August	Augustus Caesar
  16.270 +. September	Latin "septem" => "seven"
  16.271 +. October	Latin "octo" => "eight"
  16.272 +. November	Latin "novem" => "nine"
  16.273 +. December	Latin "decem" => "ten"
  16.274 +
  16.275 +     As you'll notice, the last four months are numbered 7 to 10, which
  16.276 +is an artifact of the time when the new year started in March.
  16.277 +
  16.278 +
  16.279 +INTERESTING FORMULAE
  16.280 +
  16.281 +     There's another reason why the historical starting of the new year
  16.282 +is significant.  Starting with March, the length of months follows a
  16.283 +mathematical series:
  16.284 +	31 30 31 30 31 31 30 31 30 31 31 28
  16.285 +
  16.286 +     This means that you can calculate the day of week for any
  16.287 +arbitrary day/month/year of the Gregorian calendar with the following
  16.288 +formula (note all divisions are integral):
  16.289 +        _                                      _
  16.290 +       |     7 + 31*(m - 1)       y    y     y  |
  16.291 + dow = | d + -------------- + y + - - --- + --- | MOD 7
  16.292 +       |_          12             4   100   400_|
  16.293 +where
  16.294 + d   := day of month (1..31)
  16.295 + m   := month in old style (March = 1..February = 12)
  16.296 + y   := year in old style
  16.297 + dow := day of week (Tuesday = 0..Monday = 6)
  16.298 +
  16.299 +     To convert from new style month/year to old style:
  16.300 +  if (m > 2) m -= 2;		/* Mar-Dec: subtract 2 from month */
  16.301 +  else m += 10,y--;		/* Jan-Feb: months 11 & 12 of previous year */
  16.302 +
  16.303 +     Here's another fun formula.  To find the number of days between two
  16.304 +days, calculate a pair of calendar days with the formula (again, all
  16.305 +divisions are integral), using new style month/year this time:
  16.306 +                        m
  16.307 +                    m + -
  16.308 +                        8             y    y     y
  16.309 + d + 30 * (m - 1) + ----- + y * 365 + - - --- + --- - ld
  16.310 +                      2               4   100   400
  16.311 +
  16.312 +where:
  16.313 + d   := day of month (1..31)
  16.314 + m   := month in new style (January = 1..December = 12)
  16.315 + y   := year in new style
  16.316 + ld  := leap day correction factor:
  16.317 +	0 for January and February in non-leap years
  16.318 +	1 for January and February in leap years
  16.319 +	2 for all other months in all years        
  16.320 +
  16.321 +     In C code, the leap day correction factor is calculated as:
  16.322 +  (m < 3) ? !(y % 4) && ((y % 100) || !(y % 400)) : 2
  16.323 +
  16.324 +     It's up to you to figure out how to adapt these formulas for the
  16.325 +Y4K bugfix and the Orthodox calendar.  If you're really clever, try to
  16.326 +use these formulae to implement the C library ctime(), gmtime(), and
  16.327 +mktime() functions.  Most C library implementations use a table of the
  16.328 +number of days in a month.  You don't need it.
  16.329 +
  16.330 +
  16.331 +ACKNOWLEDGEMENT:
  16.332 +
  16.333 +The original version is from an old Digital Equipment Corporation SPR
  16.334 +answer for VMS.  Modifications for c-client, and additional information
  16.335 +added by Mark Crispin.
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/docs/commndmt.txt	Mon Sep 14 15:17:45 2009 +0900
    17.3 @@ -0,0 +1,101 @@
    17.4 +/* ========================================================================
    17.5 + * Copyright 1988-2006 University of Washington
    17.6 + *
    17.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    17.8 + * you may not use this file except in compliance with the License.
    17.9 + * You may obtain a copy of the License at
   17.10 + *
   17.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   17.12 + *
   17.13 + * 
   17.14 + * ========================================================================
   17.15 + */
   17.16 +
   17.17 +[I wrote this tongue-in-cheek, but there's a lot here that people who
   17.18 + build IMAP clients should take careful note.  Most existing clients
   17.19 + violate at least one, generally several, of these commandments.
   17.20 + These are based on known user-visible problems that occur with various
   17.21 + commonly used clients.  Put another way, behind each commandment is a
   17.22 + plethora of user (and server administrator) complaints caused by a
   17.23 + violator.]
   17.24 +
   17.25 +	   Ten Commandments of How to Write an IMAP client
   17.26 +			     Mark Crispin
   17.27 +
   17.28 +1. Thou shalt not assume that it is alright to open multiple IMAP
   17.29 +sessions selected on the same mailbox simultaneously, lest thou face
   17.30 +the righteous wrath of mail stores that doth not permit such access.
   17.31 +Instead, thou shalt labor mightily, even unto having to use thy brain
   17.32 +to thinketh the matter through, such that thy client use existing
   17.33 +sessions that are already open.
   17.34 +
   17.35 +2. Thou shalt not abuse the STATUS command by using it to check for
   17.36 +new mail on a mailbox that you already have selected in an IMAP
   17.37 +session; for that session hath already told thou about new mail
   17.38 +without thy having to ask.
   17.39 +
   17.40 +3. Thou shalt remember the 30 minute inactivity timeout, and remember
   17.41 +to speak to the IMAP server before that timeout expires.  If thou
   17.42 +useth the IDLE command, thou shalt send DONE from the IDLE before 29
   17.43 +minutes hath passed, and issue a new IDLE.  If thou maketh no use of
   17.44 +IDLE, then thou shalt send NOOP every few minutes, and the server
   17.45 +shalt tell you about new mail, and there will be much rejoicing in the
   17.46 +land.
   17.47 +
   17.48 +4. Thou shalt not assume that all names are both the name of a mailbox
   17.49 +and the name of a upper level of hierarchy that contains mailboxes;
   17.50 +lest thou face the righteous wrath of mail stores in which a mailbox
   17.51 +is a file and a level of hierarchy is a directory.  Thou shalt pay
   17.52 +diligent attention to the \NoSelect and \NoInferiors flags, so that
   17.53 +your users may praise you with great praise.
   17.54 +
   17.55 +5. Thou shalt learn and understand the unique features of IMAP, such
   17.56 +as the unsolicited data model, the strict ascending rule of UIDs, how
   17.57 +UIDs map to sequence numbers, the ENVELOPE and BODYSTRUCTURE
   17.58 +structures; so that thou may use the IMAP protocol effectively.  For a
   17.59 +POP client hacked to babble IMAP protocol is still no more than a POP
   17.60 +client.
   17.61 +
   17.62 +6. Thou shalt remember untagged data sent by the server, and when thou
   17.63 +needest data thou shalt consult your memory before asking the server.
   17.64 +For those who must analyze thy protocol transactions are weak of
   17.65 +stomach, and are likely to lose their recent meal should they see thou
   17.66 +repeatedly re-fetch static data.
   17.67 +
   17.68 +7. Thou shalt labor with great effort to work within the IMAP
   17.69 +deleted/expunge model, even if thy own model is that of a trashcan;
   17.70 +for interoperability is paramount and a trashcan model can be done
   17.71 +entirely in the user interface.
   17.72 +
   17.73 +8. Thou shalt not fear to open multiple IMAP sessions to the server;
   17.74 +but thou shalt use this technique with wisdom.  For verily it is true;
   17.75 +if thou doth desire to monitor continuously five mailboxes for new
   17.76 +mail, it is better to have five IMAP sessions continuously open on the
   17.77 +mailboxes.  It is generally not good to do a succession of five SELECT
   17.78 +or STATUS commands on a periodic basis; and it is truly wretched to
   17.79 +open and close five sessions to do a STATUS or SELECT on a periodic
   17.80 +basis.  The cost of opening and closing a session is great, especially
   17.81 +if that session is SSL/TLS protected; and the cost of a STATUS or
   17.82 +SELECT can also be great.  By comparison, the cost of an open session
   17.83 +doing an IDLE or getting a NOOP every few minutes is small.  Great
   17.84 +praise shall be given to thy wisdom in doing what is less costly
   17.85 +instead of "common sense."
   17.86 +
   17.87 +9. Thou shalt not abuse subscriptions, for verily the LIST command is
   17.88 +the proper way to discover mailboxes on the server.  Thou shalt not
   17.89 +subscribe names to the user's subscription list without explicit
   17.90 +instructions from the user; nor shalt thou assume that only subscribed
   17.91 +names are valid.  Rather, thou shalt treat subscribed names as akin to
   17.92 +a bookmarks, or perhaps akin to how Windows shows the "My Documents"
   17.93 +folder -- a set of names that are separate from the hierarchy, for
   17.94 +they are such.
   17.95 +
   17.96 +10. Thou shalt use the LIST "*" wildcard only with great care.  If
   17.97 +thou doth not fully comprehend the danger of "*", thou shalt use only
   17.98 +"%" and forget about the existance of "*".
   17.99 +
  17.100 +Honor these commandments, and keep them holy in thy heart, so that thy
  17.101 +users shalt maximize their pleasure, and the server administrators
  17.102 +shalt sing thy praises and recommend thy work as a model for others to
  17.103 +emulate.
  17.104 +
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/docs/draft/README	Mon Sep 14 15:17:45 2009 +0900
    18.3 @@ -0,0 +1,19 @@
    18.4 +Last Updated: 6 March 2008
    18.5 +
    18.6 +This directory contains Internet Drafts which, at the time of release of
    18.7 +this software, were not yet been published as RFCs.  These documents are
    18.8 +expected to be released as RFCs in the near future.
    18.9 +
   18.10 +This software adheres to the specification in these documents, which
   18.11 +are included for informational purposes.  Note, however, that these
   18.12 +documents must be considered preliminary in nature and will be superceded
   18.13 +by the successor RFC.
   18.14 +
   18.15 +File Name	I-D Name
   18.16 +---------	--------
   18.17 +sort.txt	draft-ietf-imapext-sort-20.txt
   18.18 +		;; SORT and THREAD commands
   18.19 +		;; Status: approved, blocked waiting for i18n
   18.20 +
   18.21 +i18n.txt	draft-ietf-imapext-i18n-15.txt
   18.22 +		;; internationalization in IMAP
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/docs/draft/i18n.txt	Mon Sep 14 15:17:45 2009 +0900
    19.3 @@ -0,0 +1,1140 @@
    19.4 +
    19.5 +
    19.6 +
    19.7 +
    19.8 +
    19.9 +
   19.10 +Network Working Group                                       Chris Newman
   19.11 +Internet-Draft                                          Sun Microsystems
   19.12 +Intended Status: Proposed Standard                      Arnt Gulbrandsen
   19.13 +                                                  Oryx Mail Systems GmhH
   19.14 +                                                         Alexey Melnikov
   19.15 +                                                           Isode Limited
   19.16 +                                                        February 1, 2008
   19.17 +
   19.18 +         Internet Message Access Protocol Internationalization
   19.19 +                     draft-ietf-imapext-i18n-15.txt
   19.20 +
   19.21 +
   19.22 +Status of this Memo
   19.23 +    By submitting this Internet-Draft, each author represents that any
   19.24 +    applicable patent or other IPR claims of which he or she is aware
   19.25 +    have been or will be disclosed, and any of which he or she becomes
   19.26 +    aware will be disclosed, in accordance with Section 6 of BCP 79.
   19.27 +
   19.28 +    Internet-Drafts are working documents of the Internet Engineering
   19.29 +    Task Force (IETF), its areas, and its working groups.  Note that
   19.30 +    other groups may also distribute working documents as Internet-
   19.31 +    Drafts.
   19.32 +
   19.33 +    Internet-Drafts are draft documents valid for a maximum of six
   19.34 +    months and may be updated, replaced, or obsoleted by other documents
   19.35 +    at any time.  It is inappropriate to use Internet-Drafts as
   19.36 +    reference material or to cite them other than as "work in progress".
   19.37 +
   19.38 +    The list of current Internet-Drafts can be accessed at
   19.39 +    http://www.ietf.org/ietf/1id-abstracts.txt.  The list of Internet-
   19.40 +    Draft Shadow Directories can be accessed at
   19.41 +    http://www.ietf.org/shadow.html.
   19.42 +
   19.43 +    This Internet-Draft expires in August 2008.
   19.44 +
   19.45 +
   19.46 +Copyright Notice
   19.47 +
   19.48 +    Copyright (C) The IETF Trust (2008).
   19.49 +
   19.50 +
   19.51 +Abstract
   19.52 +
   19.53 +    Internet Message Access Protocol (IMAP) version 4rev1 has basic
   19.54 +    support for non-ASCII characters in mailbox names and search
   19.55 +    substrings.  It also supports non-ASCII message headers and content
   19.56 +    encoded as specified by Multipurpose Internet Mail Extensions
   19.57 +    (MIME).  This specification defines a collection of IMAP extensions
   19.58 +
   19.59 +
   19.60 +
   19.61 +Newman & Co                Expires August 2008                FF[Page 1]
   19.62 +
   19.63 +
   19.64 +
   19.65 +
   19.66 +
   19.67 +Internet-draft                                             February 2008
   19.68 +
   19.69 +
   19.70 +    which improve international support including comparator negotiation
   19.71 +    for search, sort and thread, language negotiation for international
   19.72 +    error text, and translations for namespace prefixes.
   19.73 +
   19.74 +
   19.75 +Table of Contents
   19.76 +
   19.77 +    1.  Conventions Used in this Document . . . . . . . . . . . . . .  2
   19.78 +    2.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .  3
   19.79 +    3.  LANGUAGE Extension  . . . . . . . . . . . . . . . . . . . . .  3
   19.80 +    3.1 LANGUAGE Extension Requirements . . . . . . . . . . . . . . .  3
   19.81 +    3.2 LANGUAGE Command  . . . . . . . . . . . . . . . . . . . . . .  4
   19.82 +    3.3 LANGUAGE Response . . . . . . . . . . . . . . . . . . . . . .  6
   19.83 +    3.4 TRANSLATION Extension to the NAMESPACE Response . . . . . . .  6
   19.84 +    3.5 Formal Syntax . . . . . . . . . . . . . . . . . . . . . . . .  6
   19.85 +    4.  I18NLEVEL=1 and I18NLEVEL=2 Extensions  . . . . . . . . . . .  7
   19.86 +    4.1 Introduction and Overview . . . . . . . . . . . . . . . . . .  8
   19.87 +    4.2 Requirements common to both I18NLEVEL=1 and I18NLEVEL=2 . . .
   19.88 +    4.3 I18NLEVEL=1 Extension Requirements  . . . . . . . . . . . . .  8
   19.89 +    4.4 I18NLEVEL=2 Extension Requirements  . . . . . . . . . . . . .  8
   19.90 +    4.5 Compatibility Notes
   19.91 +    4.6 Comparators and Charsets  . . . . . . . . . . . . . . . . . .  9
   19.92 +    4.7 COMPARATOR Command  . . . . . . . . . . . . . . . . . . . . .  9
   19.93 +    4.8 COMPARATOR Response . . . . . . . . . . . . . . . . . . . . . 10
   19.94 +    4.9 BADCOMPARATOR Response Code . . . . . . . . . . . . . . . . .
   19.95 +    4.10 Formal Syntax  . . . . . . . . . . . . . . . . . . . . . . . 10
   19.96 +    5.  Other IMAP Internationalization Issues  . . . . . . . . . . . 11
   19.97 +    5.1 UTF-8 Userids and Passwords . . . . . . . . . . . . . . . . . 11
   19.98 +    5.2 UTF-8 Mailbox Names . . . . . . . . . . . . . . . . . . . . . 11
   19.99 +    5.3 UTF-8 Domains, Addresses and Mail Headers . . . . . . . . . . 11
  19.100 +    6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12
  19.101 +    7.  Security Considerations . . . . . . . . . . . . . . . . . . . 12
  19.102 +    8.  Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . 12
  19.103 +    9.  Relevant Standards for i18n IMAP Implementations  . . . . . . 13
  19.104 +        Normative References  . . . . . . . . . . . . . . . . . . . . 13
  19.105 +        Informative References  . . . . . . . . . . . . . . . . . . . 14
  19.106 +        Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . 15
  19.107 +        Intellectual Property and Copyright Statements  . . . . . . . 16
  19.108 +
  19.109 +
  19.110 +Conventions Used in This Document
  19.111 +
  19.112 +    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  19.113 +    "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  19.114 +    document are to be interpreted as described in [RFC2119].
  19.115 +
  19.116 +    The formal syntax use the Augmented Backus-Naur Form (ABNF)
  19.117 +    [RFC4234] notation including the core rules defined in Appendix A.
  19.118 +
  19.119 +
  19.120 +
  19.121 +Newman & Co                Expires August 2008                FF[Page 2]
  19.122 +
  19.123 +
  19.124 +
  19.125 +
  19.126 +
  19.127 +Internet-draft                                             February 2008
  19.128 +
  19.129 +
  19.130 +    The UTF8-related productions are defined in [RFC3629].
  19.131 +
  19.132 +    In examples, "C:" and "S:" indicate lines sent by the client and
  19.133 +    server respectively.  If a single "C:" or "S:" label applies to
  19.134 +    multiple lines, then the line breaks between those lines are for
  19.135 +    editorial clarity only and are not part of the actual protocol
  19.136 +    exchange.
  19.137 +
  19.138 +
  19.139 +2.  Introduction
  19.140 +
  19.141 +    This specification defines two IMAP4rev1 [RFC3501] extensions to
  19.142 +    enhance international support.  These extensions can be advertised
  19.143 +    and implemented separately.
  19.144 +
  19.145 +    The LANGUAGE extension allows the client to request a suitable
  19.146 +    language for protocol error messages and in combination with the
  19.147 +    NAMESPACE extension [RFC2342] enables namespace translations.
  19.148 +
  19.149 +    The I18NLEVEL=2 extension allows the client to request a suitable
  19.150 +    collation which will modify the behavior of the base specification's
  19.151 +    SEARCH command as well as the SORT and THREAD extensions [SORT].
  19.152 +    This leverages the collation registry [RFC4790].
  19.153 +
  19.154 +
  19.155 +3.  LANGUAGE Extension
  19.156 +
  19.157 +    IMAP allows server responses to include human-readable text that in
  19.158 +    many cases needs to be presented to the user.  But that text is
  19.159 +    limited to US-ASCII by the IMAP specification [RFC3501] in order to
  19.160 +    preserve backwards compatibility with deployed IMAP implementations.
  19.161 +    This section specifies a way for an IMAP client to negotiate which
  19.162 +    language the server should use when sending human-readable text.
  19.163 +
  19.164 +    The LANGUAGE extension only provides a mechanism for altering fixed
  19.165 +    server strings such as response text and NAMESPACE folder names.
  19.166 +    Assigning localized language aliases to shared mailboxes would be
  19.167 +    done with a separate mechanism such as the proposed METADATA
  19.168 +    extension (see [METADATA]).
  19.169 +
  19.170 +
  19.171 +3.1 LANGUAGE Extension Requirements
  19.172 +
  19.173 +    IMAP servers that support this extension MUST list the keyword
  19.174 +    LANGUAGE in their CAPABILITY response as well as in the greeting
  19.175 +    CAPABILITY data.
  19.176 +
  19.177 +    A server that advertises this extension MUST use the language "i-
  19.178 +
  19.179 +
  19.180 +
  19.181 +Newman & Co                Expires August 2008                FF[Page 3]
  19.182 +
  19.183 +
  19.184 +
  19.185 +
  19.186 +
  19.187 +Internet-draft                                             February 2008
  19.188 +
  19.189 +
  19.190 +    default" as described in [RFC2277] as its default language until
  19.191 +    another supported language is negotiated by the client. A server
  19.192 +    MUST include "i-default" as one of its supported languages.
  19.193 +
  19.194 +    Clients and servers that support this extension MUST also support
  19.195 +    the NAMESPACE extension [RFC2342].
  19.196 +
  19.197 +    The LANGUAGE command is valid in all states. Clients are urged to
  19.198 +    issue LANGUAGE before authentication, since some servers send
  19.199 +    valuable user information as part of authentication (e.g. "password
  19.200 +    is correct, but expired").  If a security layer (such as SASL or
  19.201 +    TLS) is subsequently negotiated by the client, it MUST re-issue the
  19.202 +    LANGUAGE command in order to make sure that no previous active
  19.203 +    attack (if any) on LANGUAGE negotiation has effect on subsequent
  19.204 +    error messages. (See Section 7 for a more detailed explanation of
  19.205 +    the attack.)
  19.206 +
  19.207 +
  19.208 +
  19.209 +3.2 LANGUAGE Command
  19.210 +
  19.211 +    Arguments: Optional language range arguments.
  19.212 +
  19.213 +    Response:  A possible LANGUAGE response (see section 3.3).
  19.214 +               A possible NAMESPACE response (see section 3.4).
  19.215 +
  19.216 +    Result:    OK - Command completed
  19.217 +               NO - Could not complete command
  19.218 +               BAD - arguments invalid
  19.219 +
  19.220 +    The LANGUAGE command requests that human-readable text emitted by
  19.221 +    the server be localized to a language matching one of the language
  19.222 +    range argument as described by section 2 of [RFC4647].
  19.223 +
  19.224 +    If the command succeeds, the server will return human-readable
  19.225 +    responses in the first supported language specified.  These
  19.226 +    responses will be in UTF-8 [RFC3629].  The server MUST send a
  19.227 +    LANGUAGE response specifying the language used, and the change takes
  19.228 +    effect immediately after the LANGUAGE response.
  19.229 +
  19.230 +    If the command fails, the server continues to return human-readable
  19.231 +    responses in the language it was previously using.
  19.232 +
  19.233 +    The special "default" language range argument indicates a request to
  19.234 +    use a language designated as preferred by the server administrator.
  19.235 +    The preferred language MAY vary based on the currently active user.
  19.236 +
  19.237 +    If a language range does not match a known language tag exactly but
  19.238 +
  19.239 +
  19.240 +
  19.241 +Newman & Co                Expires August 2008                FF[Page 4]
  19.242 +
  19.243 +
  19.244 +
  19.245 +
  19.246 +
  19.247 +Internet-draft                                             February 2008
  19.248 +
  19.249 +
  19.250 +    does match a language by the rules of [RFC4647], the server MUST
  19.251 +    send an untagged LANGUAGE response indicating the language selected.
  19.252 +
  19.253 +    If there aren't any arguments, the server SHOULD send an untagged
  19.254 +    LANGUAGE response listing the languages it supports.  If the server
  19.255 +    is unable to enumerate the list of languages it supports it MAY
  19.256 +    return a tagged NO response to the enumeration request.
  19.257 +
  19.258 +        < The server defaults to using English i-default responses until
  19.259 +          the user explicitly changes the language. >
  19.260 +
  19.261 +        C: A001 LOGIN KAREN PASSWORD
  19.262 +        S: A001 OK LOGIN completed
  19.263 +
  19.264 +        < Client requested MUL language, which no server supports. >
  19.265 +
  19.266 +        C: A002 LANGUAGE MUL
  19.267 +        S: A002 NO Unsupported language MUL
  19.268 +
  19.269 +        < A LANGUAGE command with no arguments is a request to enumerate
  19.270 +          the list of languages the server supports. >
  19.271 +
  19.272 +        C: A003 LANGUAGE
  19.273 +        S: * LANGUAGE (EN DE IT i-default)
  19.274 +        S: A003 OK Supported languages have been enumerated
  19.275 +
  19.276 +        C: B001 LANGUAGE
  19.277 +        S: B001 NO Server is unable to enumerate supported languages
  19.278 +
  19.279 +        < Once the client changes the language, all responses will be in
  19.280 +          that language starting after the LANGUAGE response. Note that
  19.281 +          this includes the NAMESPACE response. Because RFCs are in US-
  19.282 +          ASCII, this document uses an ASCII transcription rather than
  19.283 +          UTF-8 text, e.g. ue in the word "ausgefuehrt" >
  19.284 +
  19.285 +        C: C001 LANGUAGE DE
  19.286 +        S: * LANGUAGE (DE)
  19.287 +        S: * NAMESPACE (("" "/")) (("Other Users/" "/" "TRANSLATION"
  19.288 +              ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/"
  19.289 +              "TRANSLATION" ("Gemeinsame Postf&AM8-cher/")))
  19.290 +        S: C001 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt
  19.291 +
  19.292 +        < If a server does not support the requested primary language,
  19.293 +          responses will continue to be returned in the current language
  19.294 +          the server is using. >
  19.295 +
  19.296 +        C: D001 LANGUAGE FR
  19.297 +        S: D001 NO Diese Sprache ist nicht unterstuetzt
  19.298 +
  19.299 +
  19.300 +
  19.301 +Newman & Co                Expires August 2008                FF[Page 5]
  19.302 +
  19.303 +
  19.304 +
  19.305 +
  19.306 +
  19.307 +Internet-draft                                             February 2008
  19.308 +
  19.309 +
  19.310 +        C: D002 LANGUAGE DE-IT
  19.311 +        S: * LANGUAGE (DE-IT)
  19.312 +        S: * NAMESPACE (("" "/"))(("Other Users/" "/" "TRANSLATION"
  19.313 +              ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/"
  19.314 +              "TRANSLATION" ("Gemeinsame Postf&AM8-cher/")))
  19.315 +        S: D002 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt
  19.316 +        C: D003 LANGUAGE "default"
  19.317 +        S: * LANGUAGE (DE)
  19.318 +        S: D003 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt
  19.319 +
  19.320 +        < Server does not speak French, but does speak English. User
  19.321 +          speaks Canadian French and Canadian English. >
  19.322 +
  19.323 +        C: E001 LANGUAGE FR-CA EN-CA
  19.324 +        S: * LANGUAGE (EN)
  19.325 +        S: E001 OK Now speaking English
  19.326 +
  19.327 +
  19.328 +
  19.329 +3.3 LANGUAGE Response
  19.330 +
  19.331 +    Contents:  A list of one or more language tags.
  19.332 +
  19.333 +    The LANGUAGE response occurs as a result of a LANGUAGE command.  A
  19.334 +    LANGUAGE response with a list containing a single language tag
  19.335 +    indicates that the server is now using that language.  A LANGUAGE
  19.336 +    response with a list containing multiple language tags indicates the
  19.337 +    server is communicating a list of available languages to the client,
  19.338 +    and no change in the active language has been made.
  19.339 +
  19.340 +
  19.341 +3.4 TRANSLATION Extension to the NAMESPACE Response
  19.342 +
  19.343 +    If localized representations of the namespace prefixes are available
  19.344 +    in the selected language, the server SHOULD include these in the
  19.345 +    TRANSLATION extension to the NAMESPACE response.
  19.346 +
  19.347 +    The TRANSLATION extension to the NAMESPACE response returns a single
  19.348 +    string, containing the modified UTF-7 [RFC3501] encoded translation
  19.349 +    of the namespace prefix.  It is the responsibility of the client to
  19.350 +    convert between the namespace prefix and the translation of the
  19.351 +    namespace prefix when presenting mailbox names to the user.
  19.352 +
  19.353 +    In this example a server supports the IMAP4 NAMESPACE command. It
  19.354 +    uses no prefix to the user's Personal Namespace, a prefix of "Other
  19.355 +    Users" to its Other Users' Namespace and a prefix of "Public
  19.356 +    Folders" to its only Shared Namespace.  Since a client will often
  19.357 +    display these prefixes to the user, the server includes a
  19.358 +
  19.359 +
  19.360 +
  19.361 +Newman & Co                Expires August 2008                FF[Page 6]
  19.362 +
  19.363 +
  19.364 +
  19.365 +
  19.366 +
  19.367 +Internet-draft                                             February 2008
  19.368 +
  19.369 +
  19.370 +    translation of them that can be presented to the user.
  19.371 +
  19.372 +        C: A001 LANGUAGE DE-IT
  19.373 +        S: * NAMESPACE (("" "/")) (("Other Users/" "/" "TRANSLATION"
  19.374 +              ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/"
  19.375 +              "TRANSLATION" ("Gemeinsame Postf&AM8-cher/")))
  19.376 +        S: A001 OK LANGUAGE-Befehl ausgefuehrt
  19.377 +
  19.378 +
  19.379 +3.5 Formal Syntax
  19.380 +
  19.381 +    The following syntax specification inherits ABNF [RFC4234] rules
  19.382 +    from IMAP4rev1 [RFC3501], IMAP4 Namespace [RFC2342], Tags for the
  19.383 +    Identifying Languages [RFC4646], UTF-8 [RFC3629] and Collected
  19.384 +    Extensions to IMAP4 ABNF [RFC4466].
  19.385 +
  19.386 +    command-any     =/ language-cmd
  19.387 +        ; LANGUAGE command is valid in all states
  19.388 +
  19.389 +    language-cmd    = "LANGUAGE" *(SP lang-range-quoted)
  19.390 +
  19.391 +    response-payload  =/ language-data
  19.392 +
  19.393 +    language-data     = "LANGUAGE" SP "(" lang-tag-quoted *(SP
  19.394 +                      lang-tag-quoted) ")"
  19.395 +
  19.396 +    namespace-trans   = SP DQUOTE "TRANSLATION" DQUOTE SP "(" string ")"
  19.397 +        ; the string is encoded in Modified UTF-7.
  19.398 +        ; this is a subset of the syntax permitted by
  19.399 +        ; the Namespace-Response-Extension rule in [RFC4466]
  19.400 +
  19.401 +    lang-range-quoted = astring
  19.402 +        ; Once any literal wrapper or quoting is removed, this
  19.403 +        ; follows the language-range rule in [RFC4647]
  19.404 +
  19.405 +    lang-tag-quoted = astring
  19.406 +        ; Once any literal wrapper or quoting is removed, this follows
  19.407 +        ; the Language-Tag rule in [RFC4646]
  19.408 +
  19.409 +    resp-text       = ["[" resp-text-code "]" SP ] UTF8-TEXT-CHAR
  19.410 +                      *(UTF8-TEXT-CHAR / "[")
  19.411 +        ; After the server is changed to a language other than
  19.412 +        ; i-default, this resp-text rule replaces the resp-text
  19.413 +        ; rule from [RFC3501].
  19.414 +
  19.415 +    UTF8-TEXT-CHAR  = %x20-5A / %x5C-7E / UTF8-2 / UTF8-3 / UTF8-4
  19.416 +        ; UTF-8 excluding 7-bit control characters and "["
  19.417 +
  19.418 +
  19.419 +
  19.420 +
  19.421 +Newman & Co                Expires August 2008                FF[Page 7]
  19.422 +
  19.423 +
  19.424 +
  19.425 +
  19.426 +
  19.427 +Internet-draft                                             February 2008
  19.428 +
  19.429 +
  19.430 +4.  I18NLEVEL=1 and I18NLEVEL=2 Extensions
  19.431 +
  19.432 +
  19.433 +4.1 Introduction and Overview
  19.434 +
  19.435 +    IMAP4rev1 [RFC3501] includes the SEARCH command which can be used to
  19.436 +    locate messages matching criteria including human-readable text.
  19.437 +    The SORT extension [SORT] to IMAP allows the client to ask the
  19.438 +    server to determine the order of messages based on criteria
  19.439 +    including human-readable text.  These mechanisms require the ability
  19.440 +    to support non-English search and sort functions.
  19.441 +
  19.442 +    Section 4 defines two IMAP extensions for internationalizing IMAP
  19.443 +    SEARCH, SORT and THREAD [SORT] using the comparator framework
  19.444 +    [RFC4790].
  19.445 +
  19.446 +    The I18NLEVEL=1 extension updates SEARCH/SORT/THREAD to use
  19.447 +    i;unicode-casemap comparator, as defined in [UCM]. See Sections 4.2
  19.448 +    and 4.3 for more details.
  19.449 +
  19.450 +    The I18NLEVEL=2 extension is a superset of the I18NLEVEL=1
  19.451 +    extension. It adds to I18NLEVEL=1 extension the ability to determine
  19.452 +    the active comparator (see definition below) and negotiate use of
  19.453 +    comparators using the COMPARATOR command. It also adds the
  19.454 +    COMPARATOR response that indicates the active comparator and
  19.455 +    possibly other available comparators. See Sections 4.2 and 4.4 for
  19.456 +    more details.
  19.457 +
  19.458 +
  19.459 +4.2 Requirements common to both I18NLEVEL=1 and I18NLEVEL=2
  19.460 +
  19.461 +    The term "default comparator" refers to the comparator which is used
  19.462 +    by SEARCH and SORT absent any negotiation using the COMPARATOR (see
  19.463 +    Section 4.7) command.  The term "active comparator" refers to the
  19.464 +    comparator which will be used within a session e.g. by SEARCH and
  19.465 +    SORT.  The COMPARATOR command is used to change the active
  19.466 +    comparator.
  19.467 +
  19.468 +    The active comparator applies to the following SEARCH keys: "BCC",
  19.469 +    "BODY", "CC", "FROM", "SUBJECT", "TEXT", "TO" and "HEADER".  If the
  19.470 +    server also advertises the "SORT" extension, then the active
  19.471 +    comparator applies to the following SORT keys: "CC", "FROM",
  19.472 +    "SUBJECT" and "TO".  If the server advertises THREAD=ORDEREDSUBJECT,
  19.473 +    then the active comparator applies to the ORDEREDSUBJECT threading
  19.474 +    algorithm.  If the server advertises THREAD=REFERENCES, then the
  19.475 +    active comparator applies to the subject field comparisons done by
  19.476 +    REFERENCES threading algorithm.  Future extensions may choose to
  19.477 +    apply the active comparator to their SEARCH keys.
  19.478 +
  19.479 +
  19.480 +
  19.481 +Newman & Co                Expires August 2008                FF[Page 8]
  19.482 +
  19.483 +
  19.484 +
  19.485 +
  19.486 +
  19.487 +Internet-draft                                             February 2008
  19.488 +
  19.489 +
  19.490 +    For SORT and THREAD, the pre-processing necessary to extract the
  19.491 +    base subject text from a Subject header occurs prior to the
  19.492 +    application of a comparator.
  19.493 +
  19.494 +    A server that advertises I18NLEVEL=1 or I18NLEVEL=2 extension MUST
  19.495 +    implement the i;unicode-casemap comparator, as defined in [UCM].
  19.496 +
  19.497 +    A server that advertises I18NLEVEL=1 or I18NLEVEL=2 extension MUST
  19.498 +    support UTF-8 as a SEARCH charset.
  19.499 +
  19.500 +
  19.501 +4.3 I18NLEVEL=1 Extension Requirements
  19.502 +
  19.503 +    An IMAP server that satisfies all requirements specified in sections
  19.504 +    4.2 and 4.6 (and doesn't support/advertise any other I18NLEVEL=<n>
  19.505 +    extension, where n > 1) MUST list the keyword I18NLEVEL=1 in its
  19.506 +    CAPABILITY data once IMAP enters the authenticated state, and MAY
  19.507 +    list that keyword in other states.
  19.508 +
  19.509 +
  19.510 +
  19.511 +4.4 I18NLEVEL=2 Extension Requirements
  19.512 +
  19.513 +    IMAP server that satisfies all requirements specified in sections
  19.514 +    4.2, 4.4, 4.6-4.10 (and doesn't support/advertise any other
  19.515 +    I18NLEVEL=<n> extension, where n > 2) MUST list the keyword
  19.516 +    I18NLEVEL=2 in its CAPABILITY data once IMAP enters the
  19.517 +    authenticated state, and MAY list that keyword in other states.
  19.518 +
  19.519 +    A server that advertises this extension MUST implement the
  19.520 +    i;unicode-casemap comparator, as defined in [UCM]. It MAY implement
  19.521 +    other comparators from the IANA registry established by [RFC4790].
  19.522 +    See also section 4.5 of this document.
  19.523 +
  19.524 +    A server that advertises this extension SHOULD use i;unicode-casemap
  19.525 +    as the default comparator. (Note that i;unicode-casemap is the
  19.526 +    default comparator for I18NLEVEL=1, but not necessarily the default
  19.527 +    for I18NLEVEL=2.) The selection of the default comparator MAY be
  19.528 +    adjustable by the server administrator, and MAY be sensitive to the
  19.529 +    current user.  Once the IMAP connection enters authenticated state,
  19.530 +    the default comparator MUST remain static for the remainder of that
  19.531 +    connection.
  19.532 +
  19.533 +    Note that since SEARCH uses the substring operation, IMAP servers
  19.534 +    can only implement collations that offer the substring operation
  19.535 +    (see [RFC4790 section 4.2.2). Since SORT uses ordering operation
  19.536 +    (and by implication equality), IMAP servers which advertise the SORT
  19.537 +    extension can only implement collations that offer all three
  19.538 +
  19.539 +
  19.540 +
  19.541 +Newman & Co                Expires August 2008                FF[Page 9]
  19.542 +
  19.543 +
  19.544 +
  19.545 +
  19.546 +
  19.547 +Internet-draft                                             February 2008
  19.548 +
  19.549 +
  19.550 +    operations (see [RFC4790] sections 4.2.2-4).
  19.551 +
  19.552 +    If the active collation does not provide the operations needed by an
  19.553 +    IMAP command, the server MUST respond with a tagged BAD.
  19.554 +
  19.555 +
  19.556 +4.5 Compatibility Notes
  19.557 +
  19.558 +    Several server implementations deployed prior to the publication of
  19.559 +    this specification comply with I18NLEVEL=1 (see section 4.3), but do
  19.560 +    not advertise that.  Other legacy servers use the i;ascii-casemap
  19.561 +    (see [RFC4790]) comparator.
  19.562 +
  19.563 +    There is no good way for a client to know which comparator that a
  19.564 +    legacy server uses.  If the client has to assume the worst, it may
  19.565 +    end up doing expensive local operations to obtain i;unicode-casemap
  19.566 +    comparisons even though the server implements it.
  19.567 +
  19.568 +    Legacy server implementations which comply with I18NLEVEL=1 should
  19.569 +    be updated to advertise I18NLEVEL=1.  All server implementations
  19.570 +    should eventually be updated to comply with the I18NLEVEL=2
  19.571 +    extension.
  19.572 +
  19.573 +
  19.574 +4.6 Comparators and Character Encodings
  19.575 +
  19.576 +    RFC 3501, section 6.4.4 says:
  19.577 +
  19.578 +               In all search keys that use strings, a message matches
  19.579 +               the key if the string is a substring of the field.  The
  19.580 +               matching is case-insensitive.
  19.581 +
  19.582 +    When performing the SEARCH operation, the active comparator is
  19.583 +    applied instead of the case-insensitive matching specified above.
  19.584 +
  19.585 +    An IMAP server which performs collation operations (e.g., as part of
  19.586 +    commands such as SEARCH, SORT, THREAD) does so according to the
  19.587 +    following procedure:
  19.588 +
  19.589 +    (a) MIME encoding (for example see [RFC2047] for headers and
  19.590 +        [RFC2045] for body parts) MUST be removed in the texts being
  19.591 +        collated.
  19.592 +
  19.593 +        If MIME encoding removal fails for a message (e.g., a body part
  19.594 +        of the message has an unsupported Content-Transfer-Encoding,
  19.595 +        uses characters not allowed by the Content-Transfer-Encoding,
  19.596 +        etc.), the collation of this message is undefined by this
  19.597 +        specification, and is handled in an implementation-dependent
  19.598 +
  19.599 +
  19.600 +
  19.601 +Newman & Co                Expires August 2008               FF[Page 10]
  19.602 +
  19.603 +
  19.604 +
  19.605 +
  19.606 +
  19.607 +Internet-draft                                             February 2008
  19.608 +
  19.609 +
  19.610 +        manner.
  19.611 +
  19.612 +    (b) The decoded text from (a) MUST be converted to the charset
  19.613 +        expected by the active comparator.
  19.614 +
  19.615 +    (c) For the substring operation:
  19.616 +        If step (b) failed (e.g., the text is in an unknown charset,
  19.617 +        contains a sequence which is not valid according in that
  19.618 +        charset, etc.), the original decoded text from (a) (i.e.,
  19.619 +        before the charset conversion attempt) is collated using the
  19.620 +        i;octet comparator (see [RFC4790]).
  19.621 +
  19.622 +        If step (b) was successful, the converted text from (b) is
  19.623 +        collated according to the active comparator.
  19.624 +
  19.625 +
  19.626 +        For the ordering operation:
  19.627 +
  19.628 +        All strings that were successfully converted by step (b) are
  19.629 +        separated from all strings that failed step (b). Strings in
  19.630 +        each group are collated independently.  All strings successfully
  19.631 +        converted by step (b) are then validated by the active
  19.632 +        comparator. Strings that pass validation are collated using the
  19.633 +        active comparator. All strings that either fail step (b) or fail
  19.634 +        the active collation's validity operation are collated (after
  19.635 +        applying step (a)) using the i;octet comparator (see [RFC4790]).
  19.636 +        The resulting sorted list is produced by appending all collated
  19.637 +        "failed" strings after all strings collated using the active
  19.638 +        comparator.
  19.639 +
  19.640 +
  19.641 +        Example: The following example demonstrates ordering of 4
  19.642 +        different strings using i;unicode-casemap [UCM] comparator.
  19.643 +        Strings are represented using hexadecimal notation used by
  19.644 +        ABNF [RFC4234].
  19.645 +
  19.646 +        (1) %xD0 %xC0 %xD0 %xBD %xD0 %xB4 %xD1 %x80 %xD0 %xB5
  19.647 +            %xD0 %xB9 (labeled with charset=UTF-8)
  19.648 +        (2) %xD1 %x81 %xD0 %x95 %xD0 %xA0 %xD0 %x93 %xD0 %x95
  19.649 +            %xD0 %x99 (labeled with charset=UTF-8)
  19.650 +        (3) %xD0 %x92 %xD0 %xB0 %xD1 %x81 %xD0 %xB8 %xD0 %xBB
  19.651 +            %xD0 %xB8 %xFF %xB9 (labeled with charset=UTF-8)
  19.652 +        (4) %xE1 %xCC %xC5 %xCB %xD3 %xC5 %xCA (labeled with
  19.653 +            charset=KOI8-R)
  19.654 +
  19.655 +        Step (b) will convert string # 4 to the following
  19.656 +        sequence of octets (in UTF-8):
  19.657 +
  19.658 +
  19.659 +
  19.660 +
  19.661 +Newman & Co                Expires August 2008               FF[Page 11]
  19.662 +
  19.663 +
  19.664 +
  19.665 +
  19.666 +
  19.667 +Internet-draft                                             February 2008
  19.668 +
  19.669 +
  19.670 +        %xD0 %x90 %xD0 %xBB %xD0 %xB5 %xD0 %xBA %xD1 %x81 %xD0
  19.671 +        %xB5 %xD0 %xB9
  19.672 +
  19.673 +        and will reject strings (1) and (3), as they contain
  19.674 +        octets not allowed in charset=UTF-8.
  19.675 +        After that, using the i;unicode-casemap collation,
  19.676 +        string (4) will collate before string (2). Using the
  19.677 +        i;octet collation on the original strings, string (3)
  19.678 +        will collate before string (1). So the final ordering
  19.679 +        is as follows: (4) (2) (3) (1).
  19.680 +
  19.681 +    If the substring operation (e.g., IMAP SEARCH) of the active
  19.682 +    comparator returns the "undefined" result (see section 4.2.3 of
  19.683 +    [RFC4790]) for either the text specified in the SEARCH command or
  19.684 +    the message text, then the operation is repeated on the result of
  19.685 +    step (a) using the i;octet comparator.
  19.686 +
  19.687 +    The ordering operation (e.g., IMAP SORT and THREAD) SHOULD collate
  19.688 +    the following together: strings encoded using unknown or invalid
  19.689 +    character encodings, strings in unrecognized charsets, and invalid
  19.690 +    input (as defined by the active collation).
  19.691 +
  19.692 +
  19.693 +
  19.694 +4.7 COMPARATOR Command
  19.695 +
  19.696 +    Arguments: Optional comparator order arguments.
  19.697 +
  19.698 +    Response:  A possible COMPARATOR response (see Section 4.8).
  19.699 +
  19.700 +    Result:    OK - Command completed
  19.701 +               NO - No matching comparator found
  19.702 +               BAD - arguments invalid
  19.703 +
  19.704 +    The COMPARATOR command is valid in authenticated and selected
  19.705 +    states.
  19.706 +
  19.707 +    The COMPARATOR command is used to determine or change the active
  19.708 +    comparator.  When issued with no arguments, it results in a
  19.709 +    COMPARATOR response indicating the currently active comparator.
  19.710 +
  19.711 +    When issued with one or more comparator argument, it changes the
  19.712 +    active comparator as directed. (If more than one installed
  19.713 +    comparator is matched by an argument, the first argument wins.) The
  19.714 +    COMPARATOR response lists all matching comparators if more than one
  19.715 +    matches the specified patterns.
  19.716 +
  19.717 +    The argument "default" refers to the server's default comparator.
  19.718 +
  19.719 +
  19.720 +
  19.721 +Newman & Co                Expires August 2008               FF[Page 12]
  19.722 +
  19.723 +
  19.724 +
  19.725 +
  19.726 +
  19.727 +Internet-draft                                             February 2008
  19.728 +
  19.729 +
  19.730 +    Otherwise each argument is an collation specification as defined in
  19.731 +    the Internet Application Protocol Comparator Registry [RFC4790].
  19.732 +
  19.733 +        < The client requests activating a Czech comparator if possible,
  19.734 +          or else a generic international comparator which it considers
  19.735 +          suitable for Czech. The server picks the first supported
  19.736 +          comparator. >
  19.737 +
  19.738 +        C: A001 COMPARATOR "cz;*" i;basic
  19.739 +        S: * COMPARATOR i;basic
  19.740 +        S: A001 OK Will use i;basic for collation
  19.741 +
  19.742 +
  19.743 +4.8 COMPARATOR Response
  19.744 +
  19.745 +    Contents:  The active comparator.
  19.746 +               An optional list of available matching comparators
  19.747 +
  19.748 +    The COMPARATOR response occurs as a result of a COMPARATOR command.
  19.749 +    The first argument in the comparator response is the name of the
  19.750 +    active comparator.  The second argument is a list of comparators
  19.751 +    which matched any of the arguments to the COMPARATOR command and is
  19.752 +    present only if more than one match is found.
  19.753 +
  19.754 +
  19.755 +4.9 BADCOMPARATOR response code
  19.756 +
  19.757 +    This response code SHOULD be returned as a result of server failing
  19.758 +    an IMAP command (returning NO), when the server knows that none of
  19.759 +    the specified comparators match the requested comparator(s).
  19.760 +
  19.761 +
  19.762 +4.10 Formal Syntax
  19.763 +
  19.764 +    The following syntax specification inherits ABNF [RFC4234] rules
  19.765 +    from IMAP4rev1 [RFC3501], and Internet Application Protocol
  19.766 +    Comparator Registry [RFC4790].
  19.767 +
  19.768 +        command-auth      =/ comparator-cmd
  19.769 +
  19.770 +        resp-text-code    =/ "BADCOMPARATOR"
  19.771 +
  19.772 +        comparator-cmd    = "COMPARATOR" *(SP comp-order-quoted)
  19.773 +
  19.774 +      response-payload  =/ comparator-data
  19.775 +
  19.776 +        comparator-data   = "COMPARATOR" SP comp-sel-quoted [SP "("
  19.777 +                        comp-id-quoted *(SP comp-id-quoted) ")"]
  19.778 +
  19.779 +
  19.780 +
  19.781 +Newman & Co                Expires August 2008               FF[Page 13]
  19.782 +
  19.783 +
  19.784 +
  19.785 +
  19.786 +
  19.787 +Internet-draft                                             February 2008
  19.788 +
  19.789 +
  19.790 +        comp-id-quoted  = astring
  19.791 +            ; Once any literal wrapper or quoting is removed, this
  19.792 +            ; follows the collation-id rule from [RFC4790]
  19.793 +
  19.794 +        comp-order-quoted = astring
  19.795 +            ; Once any literal wrapper or quoting is removed, this
  19.796 +            ; follows the collation-order rule from [RFC4790]
  19.797 +
  19.798 +        comp-sel-quoted   = astring
  19.799 +            ; Once any literal wrapper or quoting is removed, this
  19.800 +            ; follows the collation-selected rule from [RFC4790]
  19.801 +
  19.802 +
  19.803 +5.  Other IMAP Internationalization Issues
  19.804 +
  19.805 +    The following sections provide an overview of various other IMAP
  19.806 +    internationalization issues.  These issues are not resolved by this
  19.807 +    specification, but could be resolved by other standards work, such
  19.808 +    as that being done by the EAI group (see [IMAP-EAI]).
  19.809 +
  19.810 +
  19.811 +5.1 Unicode Userids and Passwords
  19.812 +
  19.813 +    IMAP4rev1 currently restricts the userid and password fields of the
  19.814 +    LOGIN command to US-ASCII. The "userid" and "password" fields of the
  19.815 +    IMAP LOGIN command are restricted to US-ASCII only until a future
  19.816 +    standards track RFC states otherwise.  Servers are encouraged to
  19.817 +    validate both fields to make sure they conform to the formal syntax
  19.818 +    of UTF-8 and to reject the LOGIN command if that syntax is violated.
  19.819 +    Servers MAY reject the use of any 8-bit in the "userid" or
  19.820 +    "password" field.
  19.821 +
  19.822 +    When AUTHENTICATE is used, some servers may support userids and
  19.823 +    passwords in Unicode [RFC3490] since SASL (see [RFC4422]) allows
  19.824 +    that. However, such userids cannot be used as part of email
  19.825 +    addresses.
  19.826 +
  19.827 +
  19.828 +5.2 UTF-8 Mailbox Names
  19.829 +
  19.830 +    The modified UTF-7 mailbox naming convention described in section
  19.831 +    5.1.3 of RFC 3501 is best viewed as an transition from the status
  19.832 +    quo in 1996 when modified UTF-7 was first specified.  At that time,
  19.833 +    there was widespread unofficial use of local character sets such as
  19.834 +    ISO-8859-1 and Shift-JIS for non-ASCII mailbox names, with resultant
  19.835 +    non-interoperability.
  19.836 +
  19.837 +    The requirements in section 5.1 of RFC 3501 are very important if
  19.838 +
  19.839 +
  19.840 +
  19.841 +Newman & Co                Expires August 2008               FF[Page 14]
  19.842 +
  19.843 +
  19.844 +
  19.845 +
  19.846 +
  19.847 +Internet-draft                                             February 2008
  19.848 +
  19.849 +
  19.850 +    we're ever going to be able to deploy UTF-8 mailbox names. Servers
  19.851 +    are encouraged to enforce them.
  19.852 +
  19.853 +
  19.854 +5.3 UTF-8 Domains, Addresses and Mail Headers
  19.855 +
  19.856 +    There is now an IETF standard for Internationalizing Domain Names in
  19.857 +    Applications [RFC3490].  While IMAP clients are free to support this
  19.858 +    standard, an argument can be made that it would be helpful to simple
  19.859 +    clients if the IMAP server could perform this conversion (the same
  19.860 +    argument would apply to MIME header encoding [RFC2047]).  However,
  19.861 +    it would be unwise to move forward with such work until the work in
  19.862 +    progress to define the format of international email addresses is
  19.863 +    complete.
  19.864 +
  19.865 +
  19.866 +6.  IANA Considerations
  19.867 +
  19.868 +    The IANA is requested to add LANGUAGE, I18NLEVEL=1 and I18NLEVEL=2
  19.869 +    to the IMAP4 Capabilities Registry.  [Note to IANA:
  19.870 +    http://www.iana.org/assignments/imap4-capabilities]
  19.871 +
  19.872 +
  19.873 +7.  Security Considerations
  19.874 +
  19.875 +    The LANGUAGE extension makes a new command available in "Not
  19.876 +    Authenticated" state in IMAP.  Some IMAP implementations run with
  19.877 +    root privilege when the server is in "Not Authenticated" state and
  19.878 +    do not revoke that privilege until after authentication is complete.
  19.879 +    Such implementations are particularly vulnerable to buffer overflow
  19.880 +    security errors at this stage and need to implement parsing of this
  19.881 +    command with extra care.
  19.882 +
  19.883 +    A LANGUAGE command issued prior to activation of a security layer is
  19.884 +    subject to an active attack which suppresses or modifies the
  19.885 +    negotiation and thus makes STARTTLS or authentication error messages
  19.886 +    more difficult to interpret.  This is not a new attack as the error
  19.887 +    messages themselves are subject to active attack.  Clients MUST re-
  19.888 +    issue the LANGUAGE command once a security layer is active, so this
  19.889 +    does not impact subsequent protocol operations.
  19.890 +
  19.891 +    LANGUAGE, I18NLEVEL=1 and I18NLEVEL=2 extensions use the UTF-8
  19.892 +    charset, thus the security considerations for UTF-8 [RFC3629] are
  19.893 +    relevent.  However, neither uses UTF-8 for identifiers so the most
  19.894 +    serious concerns do not apply.
  19.895 +
  19.896 +
  19.897 +8.  Acknowledgements
  19.898 +
  19.899 +
  19.900 +
  19.901 +Newman & Co                Expires August 2008               FF[Page 15]
  19.902 +
  19.903 +
  19.904 +
  19.905 +
  19.906 +
  19.907 +Internet-draft                                             February 2008
  19.908 +
  19.909 +
  19.910 +    The LANGUAGE extension is based on a previous Internet draft by Mike
  19.911 +    Gahrns, a substantial portion of the text in that section was
  19.912 +    written by him.  Many people have participated in discussions about
  19.913 +    an IMAP Language extension in the various fora of the IETF and
  19.914 +    Internet working groups, so any list of contributors is bound to be
  19.915 +    incomplete.  However, the authors would like to thank Andrew McCown
  19.916 +    for early work on the original proposal, John Myers for suggestions
  19.917 +    regarding the namespace issue, along with Jutta Degener, Mark
  19.918 +    Crispin, Mark Pustilnik, Larry Osterman, Cyrus Daboo, Martin Duerst,
  19.919 +    Timo Sirainen, Ben Campbell and Magnus Nystrom for their many
  19.920 +    suggestions that have been incorporated into this document.
  19.921 +
  19.922 +    Initial discussion of the I18NLEVEL=2 extension involved input from
  19.923 +    Mark Crispin and other participants of the IMAP Extensions WG.
  19.924 +
  19.925 +
  19.926 +9.  Relevant Standards for i18n IMAP Implementations
  19.927 +
  19.928 +    This is a non-normative list of standards to consider when
  19.929 +    implementing i18n aware IMAP software.
  19.930 +
  19.931 +      o The LANGUAGE and I18NLEVEL=2 extensions to IMAP (this
  19.932 +        specification).
  19.933 +      o The 8-bit rules for mailbox naming in section 5.1 of RFC 3501.
  19.934 +      o The Mailbox International Naming Convention in section 5.1.3 of
  19.935 +        RFC 3501.
  19.936 +      o MIME [RFC2045] for message bodies.
  19.937 +      o MIME header encoding [RFC2047] for message headers.
  19.938 +      o The IETF EAI working group.
  19.939 +      o MIME Parameter Value and Encoded Word Extensions [RFC2231] for
  19.940 +        filenames.  Quality IMAP server implementations will
  19.941 +        automatically combine multipart parameters when generating the
  19.942 +        BODYSTRUCTURE. There is also some deployed non-standard use of
  19.943 +        MIME header encoding inside double-quotes for filenames.
  19.944 +      o IDNA [RFC3490] and punycode [RFC3492] for domain names
  19.945 +        (currently only relevant to IMAP clients).
  19.946 +      o The UTF-8 charset [RFC3629].
  19.947 +      o The IETF policy on Character Sets and Languages [RFC2277].
  19.948 +
  19.949 +
  19.950 +Normative References
  19.951 +
  19.952 +    [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
  19.953 +               Requirement Levels", BCP 14, RFC 2119, March 1997.
  19.954 +
  19.955 +    [RFC2277]  Alvestrand, "IETF Policy on Character Sets and
  19.956 +               Languages", BCP 18, RFC 2277, January 1998.
  19.957 +
  19.958 +
  19.959 +
  19.960 +
  19.961 +Newman & Co                Expires August 2008               FF[Page 16]
  19.962 +
  19.963 +
  19.964 +
  19.965 +
  19.966 +
  19.967 +Internet-draft                                             February 2008
  19.968 +
  19.969 +
  19.970 +    [RFC2342]  Gahrns, Newman, "IMAP4 Namespace", RFC 2342, May 1998.
  19.971 +
  19.972 +    [RFC3501]  Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  19.973 +               4rev1", RFC 3501, March 2003.
  19.974 +
  19.975 +    [RFC3629]  Yergeau, "UTF-8, a transformation format of ISO 10646",
  19.976 +               STD 63, RFC 3629, November 2003.
  19.977 +
  19.978 +    [RFC4234]  Crocker, Overell, "Augmented BNF for Syntax
  19.979 +               Specifications: ABNF", RFC 4234, Brandenburg
  19.980 +               Internetworking, Demon Internet Ltd, October 2005.
  19.981 +
  19.982 +    [RFC4422]  Melnikov, Zeilenga, "Simple Authentication and Security
  19.983 +               Layer (SASL)", RFC 4422, June 2006.
  19.984 +
  19.985 +    [RFC4466]  Melnikov, Daboo, "Collected Extensions to IMAP4 ABNF",
  19.986 +               RFC 4466, Isode Ltd., April 2006.
  19.987 +
  19.988 +    [RFC4646]  Philips, Davis, "Tags for Identifying Languages", BCP 47,
  19.989 +               RFC 4646, September 2006.
  19.990 +
  19.991 +    [RFC4647]  Philips, Davis, "Matching of Language Tags", BCP 47, RFC
  19.992 +               4647, September 2006.
  19.993 +
  19.994 +    [RFC4790]  Newman, Duerst, Gulbrandsen, "Internet Application
  19.995 +               Protocol Comparator Registry", RFC 4790, February 2007.
  19.996 +
  19.997 +    [SORT]     Crispin, M. and K. Murchison, "INTERNET MESSAGE ACCESS
  19.998 +               PROTOCOL - SORT AND THREAD EXTENSION", draft-ietf-
  19.999 +               imapext-sort-19 (work in progress), November 2006.
 19.1000 +
 19.1001 +    [UCM]      Crispin, "i;unicode-casemap - Simple Unicode Collation
 19.1002 +               Algorithm", RFC 5051, October 2007.
 19.1003 +
 19.1004 +    [RFC2045]  Freed, Borenstein, "Multipurpose Internet Mail Extensions
 19.1005 +               (MIME) Part One: Format of Internet Message Bodies", RFC
 19.1006 +               2045, November 1996.
 19.1007 +
 19.1008 +    [RFC2047]  Moore, "MIME (Multipurpose Internet Mail Extensions) Part
 19.1009 +               Three: Message Header Extensions for Non-ASCII Text", RFC
 19.1010 +               2047, November 1996.
 19.1011 +
 19.1012 +
 19.1013 +Informative References
 19.1014 +
 19.1015 +
 19.1016 +    [RFC2231]  Freed, Moore, "MIME Parameter Value and Encoded Word
 19.1017 +               Extensions: Character Sets, Languages, and
 19.1018 +
 19.1019 +
 19.1020 +
 19.1021 +Newman & Co                Expires August 2008               FF[Page 17]
 19.1022 +
 19.1023 +
 19.1024 +
 19.1025 +
 19.1026 +
 19.1027 +Internet-draft                                             February 2008
 19.1028 +
 19.1029 +
 19.1030 +               Continuations", RFC 2231, November 1997.
 19.1031 +
 19.1032 +    [RFC3490]  Faltstrom, Hoffman, Costello, "Internationalizing Domain
 19.1033 +               Names in Applications (IDNA)", RFC 3490, March 2003.
 19.1034 +
 19.1035 +    [RFC3492]  Costello, "Punycode: A Bootstring encoding of Unicode for
 19.1036 +               Internationalized Domain Names in Applications (IDNA)",
 19.1037 +               RFC 3492, March 2003.
 19.1038 +
 19.1039 +    [METADATA] Daboo, C., "IMAP METADATA Extension", draft-daboo-imap-
 19.1040 +               annotatemore-12 (work in progress), December 2007.
 19.1041 +
 19.1042 +    [IMAP-EAI] Resnick, Newman, "IMAP Support for UTF-8", draft-ietf-
 19.1043 +               eai-imap-utf8 (work in progress), May 2006.
 19.1044 +
 19.1045 +
 19.1046 +
 19.1047 +Authors' Addresses
 19.1048 +
 19.1049 +    Chris Newman
 19.1050 +    Sun Microsystems
 19.1051 +    3401 Centrelake Dr., Suite 410
 19.1052 +    Ontario, CA 91761
 19.1053 +    US
 19.1054 +
 19.1055 +    Email: chris.newman@sun.com
 19.1056 +
 19.1057 +
 19.1058 +    Arnt Gulbrandsen
 19.1059 +    Oryx Mail Systems GmbH
 19.1060 +    Schweppermannstr. 8
 19.1061 +    D-81671 Muenchen
 19.1062 +    Germany
 19.1063 +
 19.1064 +    Email: arnt@oryx.com
 19.1065 +
 19.1066 +    Fax: +49 89 4502 9758
 19.1067 +
 19.1068 +
 19.1069 +    Alexey Melnikov
 19.1070 +    Isode Limited
 19.1071 +    5 Castle Business Village, 36 Station Road,
 19.1072 +    Hampton, Middlesex, TW12 2BX, UK
 19.1073 +
 19.1074 +    Email: Alexey.Melnikov@isode.com
 19.1075 +
 19.1076 +
 19.1077 +
 19.1078 +
 19.1079 +
 19.1080 +
 19.1081 +Newman & Co                Expires August 2008               FF[Page 18]
 19.1082 +
 19.1083 +
 19.1084 +
 19.1085 +
 19.1086 +
 19.1087 +Internet-draft                                             February 2008
 19.1088 +
 19.1089 +
 19.1090 +Intellectual Property Statement
 19.1091 +
 19.1092 +    The IETF takes no position regarding the validity or scope of any
 19.1093 +    Intellectual Property Rights or other rights that might be claimed to
 19.1094 +    pertain to the implementation or use of the technology described in
 19.1095 +    this document or the extent to which any license under such rights
 19.1096 +    might or might not be available; nor does it represent that it has
 19.1097 +    made any independent effort to identify any such rights.  Information
 19.1098 +    on the procedures with respect to rights in RFC documents can be found
 19.1099 +    in BCP 78 and BCP 79.
 19.1100 +
 19.1101 +    Copies of IPR disclosures made to the IETF Secretariat and any
 19.1102 +    assurances of licenses to be made available, or the result of an
 19.1103 +    attempt made to obtain a general license or permission for the use of
 19.1104 +    such proprietary rights by implementers or users of this specification
 19.1105 +    can be obtained from the IETF on-line IPR repository at
 19.1106 +    http://www.ietf.org/ipr.
 19.1107 +
 19.1108 +    The IETF invites any interested party to bring to its attention any
 19.1109 +    copyrights, patents or patent applications, or other proprietary
 19.1110 +    rights that may cover technology that may be required to implement
 19.1111 +    this standard.  Please address the information to the IETF at
 19.1112 +    ietf-ipr@ietf.org.
 19.1113 +
 19.1114 +
 19.1115 +Full Copyright Statement
 19.1116 +
 19.1117 +    Copyright (C) The IETF Trust (2008).  This document is subject to
 19.1118 +    the rights, licenses and restrictions contained in BCP 78, and
 19.1119 +    except as set forth therein, the authors retain all their rights.
 19.1120 +
 19.1121 +    This document and the information contained herein are provided on
 19.1122 +    an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
 19.1123 +    REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE
 19.1124 +    IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL
 19.1125 +    WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
 19.1126 +    WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE
 19.1127 +    ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS
 19.1128 +    FOR A PARTICULAR PURPOSE.
 19.1129 +
 19.1130 +
 19.1131 +Acknowledgment
 19.1132 +
 19.1133 +    Funding for the RFC Editor function is currently provided by the
 19.1134 +    Internet Society.
 19.1135 +
 19.1136 +
 19.1137 +
 19.1138 +
 19.1139 +
 19.1140 +
 19.1141 +Newman & Co                Expires August 2008               FF[Page 19]
 19.1142 +
 19.1143 +
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/docs/draft/sort.txt	Mon Sep 14 15:17:45 2009 +0900
    20.3 @@ -0,0 +1,885 @@
    20.4 +IMAP Extensions Working Group                                 M. Crispin
    20.5 +Internet-Draft                                              K. Murchison
    20.6 +Intended status: Proposed Standard                        March 10, 2008
    20.7 +Expires: September 10, 2008
    20.8 +Document: internet-drafts/draft-ietf-imapext-sort-20.txt
    20.9 +
   20.10 +     INTERNET MESSAGE ACCESS PROTOCOL - SORT AND THREAD EXTENSIONS
   20.11 +
   20.12 +Status of this Memo
   20.13 +
   20.14 +   By submitting this Internet-Draft, each author represents that
   20.15 +   any applicable patent or other IPR claims of which he or she is
   20.16 +   aware have been or will be disclosed, and any of which he or she
   20.17 +   becomes aware will be disclosed, in accordance with Section 6 of
   20.18 +   BCP 79.
   20.19 +
   20.20 +   Internet-Drafts are working documents of the Internet Engineering
   20.21 +   Task Force (IETF), its areas, and its working groups.  Note that
   20.22 +   other groups may also distribute working documents as
   20.23 +   Internet-Drafts.
   20.24 +
   20.25 +   Internet-Drafts are draft documents valid for a maximum of six months
   20.26 +   and may be updated, replaced, or obsoleted by other documents at any
   20.27 +   time.  It is inappropriate to use Internet-Drafts as reference
   20.28 +   material or to cite them other than as "work in progress."
   20.29 +
   20.30 +   The list of current Internet-Drafts can be accessed at
   20.31 +   http://www.ietf.org/ietf/1id-abstracts.txt
   20.32 +
   20.33 +   The list of Internet-Draft Shadow Directories can be accessed at
   20.34 +   http://www.ietf.org/shadow.html.
   20.35 +
   20.36 +   A revised version of this draft document will be submitted to the RFC
   20.37 +   editor as a Proposed Standard for the Internet Community.  Discussion
   20.38 +   and suggestions for improvement are requested, and should be sent to
   20.39 +   ietf-imapext@IMC.ORG.
   20.40 +
   20.41 +   Distribution of this memo is unlimited.
   20.42 +
   20.43 +Abstract
   20.44 +
   20.45 +   This document describes the base-level server-based sorting and
   20.46 +   threading extensions to the [IMAP] protocol.  These extensions
   20.47 +   provide substantial performance improvements for IMAP clients which
   20.48 +   offer sorted and threaded views.
   20.49 +
   20.50 +1. Introduction
   20.51 +
   20.52 +   The SORT and THREAD extensions to the [IMAP] protocol provide a means
   20.53 +   of server-based sorting and threading of messages, without requiring
   20.54 +   that the client download the necessary data to do so itself.  This is
   20.55 +   particularly useful for online clients as described in [IMAP-MODELS].
   20.56 +
   20.57 +   A server which supports the base-level SORT extension indicates this
   20.58 +   with a capability name which starts with "SORT".  Future,
   20.59 +   upwards-compatible extensions to the SORT extension will all start
   20.60 +   with "SORT", indicating support for this base level.
   20.61 +
   20.62 +   A server which supports the THREAD extension indicates this with one
   20.63 +   or more capability names consisting of "THREAD=" followed by a
   20.64 +   supported threading algorithm name as described in this document.
   20.65 +   This provides for future upwards-compatible extensions.
   20.66 +
   20.67 +   A server which implements the SORT and/or THREAD extensions MUST
   20.68 +   collate strings in accordance with the requirements of I18NLEVEL=1,
   20.69 +   as described in [IMAP-I18N], and SHOULD implement and advertise the
   20.70 +   I18NLEVEL=1 extension.  Alternatively, a server MAY implement
   20.71 +   I18NLEVEL=2 (or higher) and comply with the rules of that level.
   20.72 +
   20.73 +      Discussion: the SORT and THREAD extensions predate [IMAP-I18N] by
   20.74 +      several years.  At the time of this writing, all known server
   20.75 +      implementations of SORT and THREAD comply with the rules of
   20.76 +      I18NLEVEL=1, but do not necessarily advertise it.  As discussed
   20.77 +      in [IMAP-I18N] section 4.5, all server implementations should
   20.78 +      eventually be updated to comply with the I18NLEVEL=2 extension.
   20.79 +
   20.80 +   Historical note: the REFERENCES threading algorithm is based on the
   20.81 +   [THREADING] algorithm written used in "Netscape Mail and News"
   20.82 +   versions 2.0 through 3.0.  
   20.83 +
   20.84 +2. Terminology
   20.85 +
   20.86 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   20.87 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   20.88 +   document are to be interpreted as described in [KEYWORDS].
   20.89 +
   20.90 +   The word "can" (not "may") is used to refer to a possible
   20.91 +   circumstance or situation, as opposed to an optional facility of the
   20.92 +   protocol.
   20.93 +
   20.94 +   "User" is used to refer to a human user, whereas "client" refers to
   20.95 +   the software being run by the user.
   20.96 +
   20.97 +   In examples, "C:" and "S:" indicate lines sent by the client and
   20.98 +   server respectively.
   20.99 +
  20.100 +2.1 Base Subject
  20.101 +
  20.102 +   Subject sorting and threading use the "base subject," which has
  20.103 +   specific subject artifacts removed.  Due to the complexity of these
  20.104 +   artifacts, the formal syntax for the subject extraction rules is
  20.105 +   ambiguous.  The following procedure is followed to determine the
  20.106 +   "base subject", using the [ABNF] formal syntax rules described in
  20.107 +   section 5:
  20.108 +
  20.109 +        (1) Convert any RFC 2047 encoded-words in the subject to
  20.110 +        UTF-8 as described in "internationalization
  20.111 +        considerations."  Convert all tabs and continuations to
  20.112 +        space.  Convert all multiple spaces to a single space.
  20.113 +
  20.114 +        (2) Remove all trailing text of the subject that matches
  20.115 +        the subj-trailer ABNF, repeat until no more matches are
  20.116 +        possible.
  20.117 +
  20.118 +        (3) Remove all prefix text of the subject that matches the
  20.119 +        subj-leader ABNF.
  20.120 +
  20.121 +        (4) If there is prefix text of the subject that matches the
  20.122 +        subj-blob ABNF, and removing that prefix leaves a non-empty
  20.123 +        subj-base, then remove the prefix text.
  20.124 +
  20.125 +        (5) Repeat (3) and (4) until no matches remain.
  20.126 +
  20.127 +   Note: it is possible to defer step (2) until step (6), but this
  20.128 +   requires checking for subj-trailer in step (4).
  20.129 +
  20.130 +        (6) If the resulting text begins with the subj-fwd-hdr ABNF
  20.131 +        and ends with the subj-fwd-trl ABNF, remove the
  20.132 +        subj-fwd-hdr and subj-fwd-trl and repeat from step (2).
  20.133 +
  20.134 +        (7) The resulting text is the "base subject" used in the
  20.135 +        SORT.
  20.136 +
  20.137 +   All servers and disconnected (as described in [IMAP-MODELS]) clients
  20.138 +   MUST use exactly this algorithm to determine the "base subject".
  20.139 +   Otherwise there is potential for a user to get inconsistent results
  20.140 +   based on whether they are running in connected or disconnected mode.
  20.141 +
  20.142 +2.2 Sent Date
  20.143 +
  20.144 +   As used in this document, the term "sent date" refers to the date and
  20.145 +   time from the Date: header, adjusted by time zone to normalize to
  20.146 +   UTC.  For example, "31 Dec 2000 16:01:33 -0800" is equivalent to the
  20.147 +   UTC date and time of "1 Jan 2001 00:01:33 +0000".
  20.148 +
  20.149 +   If the time zone is invalid, the date and time SHOULD be treated as
  20.150 +   UTC.  If the time is also invalid, the time SHOULD be treated as
  20.151 +   00:00:00.  If there is no valid date or time, the date and time
  20.152 +   SHOULD be treated as 00:00:00 on the earliest possible date.
  20.153 +
  20.154 +   This differs from the date-related criteria in the SEARCH command
  20.155 +   (described in [IMAP] section 6.4.4), which use just the date and not
  20.156 +   the time, and are not adjusted by time zone.
  20.157 +
  20.158 +   If the sent date can not be determined (a Date: header is missing or
  20.159 +   can not be parsed), the INTERNALDATE for that message is used as the
  20.160 +   sent date.
  20.161 +
  20.162 +   When comparing two sent dates that match exactly, the order in which
  20.163 +   the two messages appear in the mailbox (that is, by sequence number)
  20.164 +   is used as a tie-breaker to determine the order.
  20.165 +
  20.166 +3. Additional Commands
  20.167 +
  20.168 +   These commands are extension to the [IMAP] base protocol.
  20.169 +
  20.170 +   The section headings are intended to correspond with where they would
  20.171 +   be located in the main document if they were part of the base
  20.172 +   specification.
  20.173 +
  20.174 +BASE.6.4.SORT. SORT Command
  20.175 +
  20.176 +   Arguments:  sort program
  20.177 +               charset specification
  20.178 +               searching criteria (one or more)
  20.179 +
  20.180 +   Data:       untagged responses: SORT
  20.181 +
  20.182 +   Result:     OK - sort completed
  20.183 +               NO - sort error: can't sort that charset or
  20.184 +                    criteria
  20.185 +               BAD - command unknown or arguments invalid
  20.186 +
  20.187 +      The SORT command is a variant of SEARCH with sorting semantics for
  20.188 +      the results.  Sort has two arguments before the searching criteria
  20.189 +      argument; a parenthesized list of sort criteria, and the searching
  20.190 +      charset.
  20.191 +
  20.192 +      The charset argument is mandatory (unlike SEARCH) and indicates
  20.193 +      the [CHARSET] of the strings that appear in the searching
  20.194 +      criteria.  The US-ASCII and UTF-8 charsets MUST be implemented.
  20.195 +      All other charsets are optional.
  20.196 +
  20.197 +      There is also a UID SORT command which returns unique identifiers
  20.198 +      instead of message sequence numbers.  Note that there are separate
  20.199 +      searching criteria for message sequence numbers and UIDs; thus the
  20.200 +      arguments to UID SORT are interpreted the same as in SORT.  This
  20.201 +      is analogous to the behavior of UID SEARCH, as opposed to UID
  20.202 +      COPY, UID FETCH, or UID STORE.
  20.203 +
  20.204 +      The SORT command first searches the mailbox for messages that
  20.205 +      match the given searching criteria using the charset argument for
  20.206 +      the interpretation of strings in the searching criteria.  It then
  20.207 +      returns the matching messages in an untagged SORT response, sorted
  20.208 +      according to one or more sort criteria.
  20.209 +
  20.210 +      Sorting is in ascending order.  Earlier dates sort before later
  20.211 +      dates; smaller sizes sort before larger sizes; and strings are
  20.212 +      sorted according to ascending values established by their
  20.213 +      collation algorithm (see under "Internationalization
  20.214 +      Considerations").
  20.215 +
  20.216 +      If two or more messages exactly match according to the sorting
  20.217 +      criteria, these messages are sorted according to the order in
  20.218 +      which they appear in the mailbox.  In other words, there is an
  20.219 +      implicit sort criterion of "sequence number".
  20.220 +
  20.221 +      When multiple sort criteria are specified, the result is sorted in
  20.222 +      the priority order that the criteria appear.  For example,
  20.223 +      (SUBJECT DATE) will sort messages in order by their base subject
  20.224 +      text; and for messages with the same base subject text will sort
  20.225 +      by their sent date.
  20.226 +
  20.227 +      Untagged EXPUNGE responses are not permitted while the server is
  20.228 +      responding to a SORT command, but are permitted during a UID SORT
  20.229 +      command.
  20.230 +
  20.231 +      The defined sort criteria are as follows.  Refer to the Formal
  20.232 +      Syntax section for the precise syntactic definitions of the
  20.233 +      arguments.  If the associated RFC-822 header for a particular
  20.234 +      criterion is absent, it is treated as the empty string.  The empty
  20.235 +      string always collates before non-empty strings.
  20.236 +
  20.237 +      ARRIVAL
  20.238 +         Internal date and time of the message.  This differs from the
  20.239 +         ON criteria in SEARCH, which uses just the internal date.
  20.240 +
  20.241 +      CC
  20.242 +         [IMAP] addr-mailbox of the first "cc" address.
  20.243 +
  20.244 +      DATE
  20.245 +         Sent date and time, as described in section 2.2.
  20.246 +
  20.247 +      FROM
  20.248 +         [IMAP] addr-mailbox of the first "From" address.
  20.249 +
  20.250 +      REVERSE
  20.251 +         Followed by another sort criterion, has the effect of that
  20.252 +         criterion but in reverse (descending) order.
  20.253 +            Note: REVERSE only reverses a single criterion, and does not
  20.254 +            affect the implicit "sequence number" sort criterion if all
  20.255 +            other criteria are identicial.  Consequently, a sort of
  20.256 +            REVERSE SUBJECT is not the same as a reverse ordering of a
  20.257 +            SUBJECT sort.  This can be avoided by use of additional
  20.258 +            criteria, e.g. SUBJECT DATE vs. REVERSE SUBJECT REVERSE
  20.259 +            DATE.  In general, however, it's better (and faster, if the
  20.260 +            client has a "reverse current ordering" command) to reverse
  20.261 +            the results in the client instead of issuing a new SORT.
  20.262 +
  20.263 +      SIZE
  20.264 +         Size of the message in octets.
  20.265 +
  20.266 +      SUBJECT
  20.267 +         Base subject text.
  20.268 +
  20.269 +      TO
  20.270 +         [IMAP] addr-mailbox of the first "To" address.
  20.271 +
  20.272 +   Example:    C: A282 SORT (SUBJECT) UTF-8 SINCE 1-Feb-1994
  20.273 +               S: * SORT 2 84 882
  20.274 +               S: A282 OK SORT completed
  20.275 +               C: A283 SORT (SUBJECT REVERSE DATE) UTF-8 ALL
  20.276 +               S: * SORT 5 3 4 1 2
  20.277 +               S: A283 OK SORT completed
  20.278 +               C: A284 SORT (SUBJECT) US-ASCII TEXT "not in mailbox"
  20.279 +               S: * SORT
  20.280 +               S: A284 OK SORT completed
  20.281 +
  20.282 +BASE.6.4.THREAD. THREAD Command
  20.283 +
  20.284 +Arguments:  threading algorithm
  20.285 +            charset specification
  20.286 +            searching criteria (one or more)
  20.287 +
  20.288 +Data:       untagged responses: THREAD
  20.289 +
  20.290 +Result:     OK - thread completed
  20.291 +            NO - thread error: can't thread that charset or
  20.292 +                 criteria
  20.293 +            BAD - command unknown or arguments invalid
  20.294 +
  20.295 +      The THREAD command is a variant of SEARCH with threading semantics
  20.296 +      for the results.  Thread has two arguments before the searching
  20.297 +      criteria argument; a threading algorithm, and the searching
  20.298 +      charset.
  20.299 +
  20.300 +      The charset argument is mandatory (unlike SEARCH) and indicates
  20.301 +      the [CHARSET] of the strings that appear in the searching
  20.302 +      criteria.  The US-ASCII and UTF-8 charsets MUST be implemented.
  20.303 +      All other charsets are optional.
  20.304 +
  20.305 +      There is also a UID THREAD command which returns unique
  20.306 +      identifiers instead of message sequence numbers.  Note that there
  20.307 +      are separate searching criteria for message sequence numbers and
  20.308 +      UIDs; thus the arguments to UID THREAD are interpreted the same as
  20.309 +      in THREAD.  This is analogous to the behavior of UID SEARCH, as
  20.310 +      opposed to UID COPY, UID FETCH, or UID STORE.
  20.311 +
  20.312 +      The THREAD command first searches the mailbox for messages that
  20.313 +      match the given searching criteria using the charset argument for
  20.314 +      the interpretation of strings in the searching criteria.  It then
  20.315 +      returns the matching messages in an untagged THREAD response,
  20.316 +      threaded according to the specified threading algorithm.
  20.317 +
  20.318 +      All collation is in ascending order.  Earlier dates collate before
  20.319 +      later dates and strings are collated according to ascending values
  20.320 +      established by their collation algorithm (see under
  20.321 +      "Internationalization Considerations").
  20.322 +
  20.323 +      Untagged EXPUNGE responses are not permitted while the server is
  20.324 +      responding to a THREAD command, but are permitted during a UID
  20.325 +      THREAD command.
  20.326 +
  20.327 +      The defined threading algorithms are as follows:
  20.328 +
  20.329 +      ORDEREDSUBJECT
  20.330 +
  20.331 +         The ORDEREDSUBJECT threading algorithm is also referred to as
  20.332 +         "poor man's threading."  The searched messages are sorted by
  20.333 +         base subject and then by the sent date.  The messages are then
  20.334 +         split into separate threads, with each thread containing
  20.335 +         messages with the same base subject text.  Finally, the threads
  20.336 +         are sorted by the sent date of the first message in the thread.
  20.337 +
  20.338 +         The first message of each thread are siblings of each other
  20.339 +         (the "root").  The second message of a thread is the child of
  20.340 +         the first message, and subsequent messages of the thread are
  20.341 +         siblings of the second message and hence children of the
  20.342 +         message at the root.  Hence, there are no grandchildren in
  20.343 +         ORDEREDSUBJECT threading.
  20.344 +
  20.345 +         Children in ORDEREDSUBJECT threading do not have descendents.
  20.346 +         Client implementations SHOULD treat descendents of a child in
  20.347 +         a server response as being siblings of that child.
  20.348 +
  20.349 +      REFERENCES
  20.350 +
  20.351 +         The REFERENCES threading algorithm threads the searched
  20.352 +         messages by grouping them together in parent/child
  20.353 +         relationships based on which messages are replies to others.
  20.354 +         The parent/child relationships are built using two methods:
  20.355 +         reconstructing a message's ancestry using the references
  20.356 +         contained within it; and checking the original (not base)
  20.357 +         subject of a message to see if it is a reply to (or forward of)
  20.358 +         another message.
  20.359 +
  20.360 +            Note: "Message ID" in the following description refers to a
  20.361 +            normalized form of the msg-id in [RFC-2822].  The actual
  20.362 +            text in an RFC 2822 may use quoting, resulting in multiple
  20.363 +            ways of expressing the same Message ID.  Implementations of
  20.364 +            the REFERENCES threading algorithm MUST normalize any msg-id
  20.365 +            in order to avoid false non-matches due to differences in
  20.366 +            quoting.
  20.367 +
  20.368 +            For example, the msg-id
  20.369 +               <"01KF8JCEOCBS0045PS"@xxx.yyy.com>
  20.370 +            and the msg-id
  20.371 +               <01KF8JCEOCBS0045PS@xxx.yyy.com>
  20.372 +            MUST be interpreted as being the same Message ID.
  20.373 +
  20.374 +         The references used for reconstructing a message's ancestry are
  20.375 +         found using the following rules:
  20.376 +
  20.377 +            If a message contains a References header line, then use the
  20.378 +            Message IDs in the References header line as the references.
  20.379 +
  20.380 +            If a message does not contain a References header line, or
  20.381 +            the References header line does not contain any valid
  20.382 +            Message IDs, then use the first (if any) valid Message ID
  20.383 +            found in the In-Reply-To header line as the only reference
  20.384 +            (parent) for this message.
  20.385 +
  20.386 +               Note: Although [RFC-2822] permits multiple Message IDs in
  20.387 +               the In-Reply-To header, in actual practice this
  20.388 +               discipline has not been followed.  For example,
  20.389 +               In-Reply-To headers have been observed with message
  20.390 +               addresses after the Message ID, and there are no good
  20.391 +               heuristics for software to determine the difference.
  20.392 +               This is not a problem with the References header however.
  20.393 +
  20.394 +            If a message does not contain an In-Reply-To header line, or
  20.395 +            the In-Reply-To header line does not contain a valid Message
  20.396 +            ID, then the message does not have any references (NIL).
  20.397 +
  20.398 +         A message is considered to be a reply or forward if the base
  20.399 +         subject extraction rules, applied to the original subject,
  20.400 +         remove any of the following: a subj-refwd, a "(fwd)"
  20.401 +         subj-trailer, or a subj-fwd-hdr and subj-fwd-trl.
  20.402 +
  20.403 +         The REFERENCES algorithm is significantly more complex than
  20.404 +         ORDEREDSUBJECT and consists of six main steps.  These steps are
  20.405 +         outlined in detail below.
  20.406 +
  20.407 +         (1) For each searched message:
  20.408 +
  20.409 +            (A) Using the Message IDs in the message's references, link
  20.410 +            the corresponding messages (those whose Message-ID header
  20.411 +            line contains the given reference Message ID) together as
  20.412 +            parent/child.  Make the first reference the parent of the
  20.413 +            second (and the second a child of the first), the second the
  20.414 +            parent of the third (and the third a child of the second),
  20.415 +            etc.  The following rules govern the creation of these
  20.416 +            links:
  20.417 +
  20.418 +               If a message does not contain a Message-ID header line,
  20.419 +               or the Message-ID header line does not contain a valid
  20.420 +               Message ID, then assign a unique Message ID to this
  20.421 +               message.
  20.422 +
  20.423 +               If two or more messages have the same Message ID, then
  20.424 +               only use that Message ID in the first (lowest sequence
  20.425 +               number) message, and assign a unique Message ID to each
  20.426 +               of the subsequent messages with a duplicate of that
  20.427 +               Message ID.
  20.428 +
  20.429 +               If no message can be found with a given Message ID,
  20.430 +               create a dummy message with this ID.  Use this dummy
  20.431 +               message for all subsequent references to this ID.
  20.432 +
  20.433 +               If a message already has a parent, don't change the
  20.434 +               existing link.  This is done because the References
  20.435 +               header line may have been truncated by a MUA.  As a
  20.436 +               result, there is no guarantee that the messages
  20.437 +               corresponding to adjacent Message IDs in the References
  20.438 +               header line are parent and child.
  20.439 +
  20.440 +               Do not create a parent/child link if creating that link
  20.441 +               would introduce a loop.  For example, before making
  20.442 +               message A the parent of B, make sure that A is not a
  20.443 +               descendent of B.
  20.444 +
  20.445 +                  Note: Message ID comparisons are case-sensitive.
  20.446 +
  20.447 +            (B) Create a parent/child link between the last reference
  20.448 +            (or NIL if there are no references) and the current message.
  20.449 +            If the current message already has a parent, it is probably
  20.450 +            the result of a truncated References header line, so break
  20.451 +            the current parent/child link before creating the new
  20.452 +            correct one.  As in step 1.A, do not create the parent/child
  20.453 +            link if creating that link would introduce a loop.  Note
  20.454 +            that if this message has no references, that it will now
  20.455 +            have no parent.
  20.456 +
  20.457 +               Note: The parent/child links created in steps 1.A and 1.B
  20.458 +               MUST be kept consistent with one another at ALL times.
  20.459 +
  20.460 +         (2) Gather together all of the messages that have no parents
  20.461 +         and make them all children (siblings of one another) of a dummy
  20.462 +         parent (the "root").  These messages constitute the first
  20.463 +         (head) message of the threads created thus far.
  20.464 +
  20.465 +         (3) Prune dummy messages from the thread tree.  Traverse each
  20.466 +         thread under the root, and for each message:
  20.467 +
  20.468 +            If it is a dummy message with NO children, delete it.
  20.469 +
  20.470 +            If it is a dummy message with children, delete it, but
  20.471 +            promote its children to the current level.  In other words,
  20.472 +            splice them in with the dummy's siblings.
  20.473 +
  20.474 +            Do not promote the children if doing so would make them
  20.475 +            children of the root, unless there is only one child.
  20.476 +
  20.477 +         (4) Sort the messages under the root (top-level siblings only)
  20.478 +         by sent date as described in section 2.2.  In the case of a
  20.479 +         dummy message, sort its children by sent date and then use the
  20.480 +         first child for the top-level sort.
  20.481 +
  20.482 +         (5) Gather together messages under the root that have the same
  20.483 +         base subject text.
  20.484 +
  20.485 +            (A) Create a table for associating base subjects with
  20.486 +            messages, called the subject table.
  20.487 +
  20.488 +            (B) Populate the subject table with one message per each
  20.489 +            base subject.  For each child of the root:
  20.490 +
  20.491 +               (i) Find the subject of this thread, by using the base
  20.492 +               subject from either the current message or its first
  20.493 +               child if the current message is a dummy.  This is the
  20.494 +               thread subject.
  20.495 +
  20.496 +               (ii) If the thread subject is empty, skip this message.
  20.497 +
  20.498 +               (iii) Look up the message associated with the thread
  20.499 +               subject in the subject table.
  20.500 +
  20.501 +               (iv) If there is no message in the subject table with the
  20.502 +               thread subject, add the current message and the thread
  20.503 +               subject to the subject table.
  20.504 +
  20.505 +               Otherwise, if the message in the subject table is not a
  20.506 +               dummy, AND either of the following criteria are true:
  20.507 +
  20.508 +                  The current message is a dummy, OR
  20.509 +
  20.510 +                  The message in the subject table is a reply or forward
  20.511 +                  and the current message is not.
  20.512 +
  20.513 +            then replace the message in the subject table with the
  20.514 +            current message.
  20.515 +
  20.516 +            (C) Merge threads with the same thread subject.  For each
  20.517 +            child of the root:
  20.518 +
  20.519 +               (i) Find the message's thread subject as in step 5.B.i
  20.520 +               above.
  20.521 +
  20.522 +               (ii) If the thread subject is empty, skip this message.
  20.523 +
  20.524 +               (iii) Lookup the message associated with this thread
  20.525 +               subject in the subject table.
  20.526 +
  20.527 +               (iv) If the message in the subject table is the current
  20.528 +               message, skip this message.
  20.529 +
  20.530 +               Otherwise, merge the current message with the one in the
  20.531 +               subject table using the following rules:
  20.532 +
  20.533 +                  If both messages are dummies, append the current
  20.534 +                  message's children to the children of the message in
  20.535 +                  the subject table (the children of both messages
  20.536 +                  become siblings), and then delete the current message.
  20.537 +
  20.538 +                  If the message in the subject table is a dummy and the
  20.539 +                  current message is not, make the current message a
  20.540 +                  child of the message in the subject table (a sibling
  20.541 +                  of its children).
  20.542 +
  20.543 +                  If the current message is a reply or forward and the
  20.544 +                  message in the subject table is not, make the current
  20.545 +                  message a child of the message in the subject table (a
  20.546 +                  sibling of its children).
  20.547 +
  20.548 +                  Otherwise, create a new dummy message and make both
  20.549 +                  the current message and the message in the subject
  20.550 +                  table children of the dummy.  Then replace the message
  20.551 +                  in the subject table with the dummy message.
  20.552 +
  20.553 +                     Note: Subject comparisons are case-insensitive, as
  20.554 +                     described under "Internationalization
  20.555 +                     Considerations."
  20.556 +
  20.557 +         (6) Traverse the messages under the root and sort each set of
  20.558 +         siblings by sent date as described in section 2.2.  Traverse
  20.559 +         the messages in such a way that the "youngest" set of siblings
  20.560 +         are sorted first, and the "oldest" set of siblings are sorted
  20.561 +         last (grandchildren are sorted before children, etc).  In the
  20.562 +         case of a dummy message (which can only occur with top-level
  20.563 +         siblings), use its first child for sorting.
  20.564 +
  20.565 +   Example:    C: A283 THREAD ORDEREDSUBJECT UTF-8 SINCE 5-MAR-2000
  20.566 +               S: * THREAD (166)(167)(168)(169)(172)(170)(171)
  20.567 +                  (173)(174 (175)(176)(178)(181)(180))(179)(177
  20.568 +                  (183)(182)(188)(184)(185)(186)(187)(189))(190)
  20.569 +                  (191)(192)(193)(194 195)(196 (197)(198))(199)
  20.570 +                  (200 202)(201)(203)(204)(205)(206 207)(208)
  20.571 +               S: A283 OK THREAD completed
  20.572 +               C: A284 THREAD ORDEREDSUBJECT US-ASCII TEXT "gewp"
  20.573 +               S: * THREAD
  20.574 +               S: A284 OK THREAD completed
  20.575 +               C: A285 THREAD REFERENCES UTF-8 SINCE 5-MAR-2000
  20.576 +               S: * THREAD (166)(167)(168)(169)(172)((170)(179))
  20.577 +                  (171)(173)((174)(175)(176)(178)(181)(180))
  20.578 +                  ((177)(183)(182)(188 (184)(189))(185 186)(187))
  20.579 +                  (190)(191)(192)(193)((194)(195 196))(197 198)
  20.580 +                  (199)(200 202)(201)(203)(204)(205 206 207)(208)
  20.581 +               S: A285 OK THREAD completed
  20.582 +
  20.583 +        Note: The line breaks in the first and third server
  20.584 +        responses are for editorial clarity and do not appear in
  20.585 +        real THREAD responses.
  20.586 +
  20.587 +4. Additional Responses
  20.588 +
  20.589 +   These responses are extensions to the [IMAP] base protocol.
  20.590 +
  20.591 +   The section headings of these responses are intended to correspond
  20.592 +   with where they would be located in the main document.
  20.593 +
  20.594 +BASE.7.2.SORT. SORT Response
  20.595 +
  20.596 +   Data:       zero or more numbers
  20.597 +
  20.598 +      The SORT response occurs as a result of a SORT or UID SORT
  20.599 +      command.  The number(s) refer to those messages that match the
  20.600 +      search criteria.  For SORT, these are message sequence numbers;
  20.601 +      for UID SORT, these are unique identifiers.  Each number is
  20.602 +      delimited by a space.
  20.603 +
  20.604 +   Example:    S: * SORT 2 3 6
  20.605 +
  20.606 +BASE.7.2.THREAD. THREAD Response
  20.607 +
  20.608 +   Data:       zero or more threads
  20.609 +
  20.610 +      The THREAD response occurs as a result of a THREAD or UID THREAD
  20.611 +      command.  It contains zero or more threads.  A thread consists of
  20.612 +      a parenthesized list of thread members.
  20.613 +
  20.614 +      Thread members consist of zero or more message numbers, delimited
  20.615 +      by spaces, indicating successive parent and child.  This continues
  20.616 +      until the thread splits into multiple sub-threads, at which point
  20.617 +      the thread nests into multiple sub-threads with the first member
  20.618 +      of each subthread being siblings at this level.  There is no limit
  20.619 +      to the nesting of threads.
  20.620 +
  20.621 +      The messages numbers refer to those messages that match the search
  20.622 +      criteria.  For THREAD, these are message sequence numbers; for UID
  20.623 +      THREAD, these are unique identifiers.
  20.624 +
  20.625 +   Example:    S: * THREAD (2)(3 6 (4 23)(44 7 96))
  20.626 +
  20.627 +      The first thread consists only of message 2.  The second thread
  20.628 +      consists of the messages 3 (parent) and 6 (child), after which it
  20.629 +      splits into two subthreads; the first of which contains messages 4
  20.630 +      (child of 6, sibling of 44) and 23 (child of 4), and the second of
  20.631 +      which contains messages 44 (child of 6, sibling of 4), 7 (child of
  20.632 +      44), and 96 (child of 7).  Since some later messages are parents
  20.633 +      of earlier messages, the messages were probably moved from some
  20.634 +      other mailbox at different times.
  20.635 +
  20.636 +      -- 2
  20.637 +
  20.638 +      -- 3
  20.639 +         \-- 6
  20.640 +             |-- 4
  20.641 +             |   \-- 23
  20.642 +             |
  20.643 +             \-- 44
  20.644 +                  \-- 7
  20.645 +                      \-- 96
  20.646 +
  20.647 +   Example:    S: * THREAD ((3)(5))
  20.648 +
  20.649 +      In this example, 3 and 5 are siblings of a parent which does not
  20.650 +      match the search criteria (and/or does not exist in the mailbox);
  20.651 +      however they are members of the same thread.
  20.652 +
  20.653 +5. Formal Syntax of SORT and THREAD Commands and Responses
  20.654 +
  20.655 +   The following syntax specification uses the Augmented Backus-Naur
  20.656 +   Form (ABNF) notation as specified in [ABNF].  It also uses [ABNF]
  20.657 +   rules defined in [IMAP].
  20.658 +
  20.659 +sort            = ["UID" SP] "SORT" SP sort-criteria SP search-criteria
  20.660 +
  20.661 +sort-criteria   = "(" sort-criterion *(SP sort-criterion) ")"
  20.662 +
  20.663 +sort-criterion  = ["REVERSE" SP] sort-key
  20.664 +
  20.665 +sort-key        = "ARRIVAL" / "CC" / "DATE" / "FROM" / "SIZE" /
  20.666 +                  "SUBJECT" / "TO"
  20.667 +
  20.668 +thread          = ["UID" SP] "THREAD" SP thread-alg SP search-criteria
  20.669 +
  20.670 +thread-alg      = "ORDEREDSUBJECT" / "REFERENCES" / thread-alg-ext
  20.671 +
  20.672 +thread-alg-ext  = atom
  20.673 +                    ; New algorithms MUST be registered with IANA
  20.674 +
  20.675 +search-criteria = charset 1*(SP search-key)
  20.676 +
  20.677 +charset         = atom / quoted
  20.678 +                    ; CHARSET values MUST be registered with IANA
  20.679 +
  20.680 +sort-data       = "SORT" *(SP nz-number)
  20.681 +
  20.682 +thread-data     = "THREAD" [SP 1*thread-list]
  20.683 +
  20.684 +thread-list     = "(" (thread-members / thread-nested) ")"
  20.685 +
  20.686 +thread-members  = nz-number *(SP nz-number) [SP thread-nested]
  20.687 +
  20.688 +thread-nested   = 2*thread-list
  20.689 +
  20.690 +   The following syntax describes base subject extraction rules (2)-(6):
  20.691 +
  20.692 +subject         = *subj-leader [subj-middle] *subj-trailer
  20.693 +
  20.694 +subj-refwd      = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":"
  20.695 +
  20.696 +subj-blob       = "[" *BLOBCHAR "]" *WSP
  20.697 +
  20.698 +subj-fwd        = subj-fwd-hdr subject subj-fwd-trl
  20.699 +
  20.700 +subj-fwd-hdr    = "[fwd:"
  20.701 +
  20.702 +subj-fwd-trl    = "]"
  20.703 +
  20.704 +subj-leader     = (*subj-blob subj-refwd) / WSP
  20.705 +
  20.706 +subj-middle     = *subj-blob (subj-base / subj-fwd)
  20.707 +                    ; last subj-blob is subj-base if subj-base would
  20.708 +                    ; otherwise be empty
  20.709 +
  20.710 +subj-trailer    = "(fwd)" / WSP
  20.711 +
  20.712 +subj-base       = NONWSP *(*WSP NONWSP)
  20.713 +                    ; can be a subj-blob
  20.714 +
  20.715 +BLOBCHAR        = %x01-5a / %x5c / %x5e-ff
  20.716 +                    ; any CHAR8 except '[' and ']'
  20.717 +
  20.718 +NONWSP          = %x01-08 / %x0a-1f / %x21-ff
  20.719 +                    ; any CHAR8 other than WSP
  20.720 +
  20.721 +6. Security Considerations
  20.722 +
  20.723 +   The SORT and THREAD extensions do not raise any security
  20.724 +   considerations that are not present in the base [IMAP] protocol, and
  20.725 +   these issues are discussed in [IMAP].  Nevertheless, it is important
  20.726 +   to remember that [IMAP] protocol transactions, including message
  20.727 +   data, are sent in the clear over the network unless protection from
  20.728 +   snooping is negotiated, either by the use of STARTTLS, privacy
  20.729 +   protection is negotiated in the AUTHENTICATE command, or some other
  20.730 +   protection mechanism.
  20.731 +
  20.732 +   Although not a security consideration, it is important to recognize
  20.733 +   that sorting by REFERENCES can lead to misleading threading trees.
  20.734 +   For example, a message with false References: header data will cause
  20.735 +   a thread to be incorporated into another thread.
  20.736 +
  20.737 +   The process of extracting the base subject may lead to incorrect
  20.738 +   collation if the extracted data was significant text as opposed to
  20.739 +   a subject artifact.
  20.740 +
  20.741 +7. Internationalization Considerations
  20.742 +
  20.743 +   As stated in the introduction, the rules of I18NLEVEL=1 as described
  20.744 +   in [IMAP-I18N] MUST be followed; that is, the SORT and THREAD
  20.745 +   extensions MUST collate strings according to the i;unicode-casemap
  20.746 +   collation described in [UNICASEMAP].  Servers SHOULD also advertise
  20.747 +   the I18NLEVEL=1 extension.  Alternatively, a server MAY implement
  20.748 +   I18NLEVEL=2 (or higher) and comply with the rules of that level.
  20.749 +
  20.750 +   As discussed in [IMAP-I18N] section 4.5, all server implementations
  20.751 +   should eventually be updated to support the [IMAP-I18N] I18NLEVEL=2
  20.752 +   extension.
  20.753 +
  20.754 +   Translations of the "re" or "fw"/"fwd" tokens are not specified for
  20.755 +   removal in the base subject extraction process.  An attempt to add
  20.756 +   such translated tokens would result in a geometrically complex, and
  20.757 +   ultimately unimplementable, task.
  20.758 +
  20.759 +   Instead, note that [RFC-2822] section 3.6.5 recommends that "re:"
  20.760 +   (from the Latin "res", in the matter of) be used to identify a reply.
  20.761 +   Although it is evident that, from the multiple forms of token to
  20.762 +   identify a forwarded message, there is considerable variation found
  20.763 +   in the wild, the variations are (still) manageable.  Consequently, it
  20.764 +   is suggested that "re:" and one of the variations of the tokens for
  20.765 +   forward supported by the base subject extraction rules be adopted for
  20.766 +   Internet mail messages, since doing so makes it a simple display time
  20.767 +   task to localize the token language for the user.
  20.768 +
  20.769 +8. IANA Considerations
  20.770 +
  20.771 +   [IMAP] capabilities are registered by publishing a standards track or
  20.772 +   IESG approved experimental RFC.  This document constitutes
  20.773 +   registration of the SORT and THREAD capabilities in the [IMAP]
  20.774 +   capabilities registry.
  20.775 +
  20.776 +   This document creates a new [IMAP] threading algorithms registry,
  20.777 +   which registers threading algorithms by publishing a standards track
  20.778 +   or IESG approved experimental RFC.  This document constitutes
  20.779 +   registration of the ORDEREDSUBJECT and REFERENCES algorithms in that
  20.780 +   registry.
  20.781 +
  20.782 +9. Normative References
  20.783 +
  20.784 +   The following documents are normative to this document:
  20.785 +
  20.786 +   [ABNF]                Crocker, D. and Overell, P. "Augmented BNF
  20.787 +                         for Syntax Specifications: ABNF", RFC 5234
  20.788 +                         January 2008
  20.789 +
  20.790 +   [CHARSET]             Freed, N. and Postel, J. "IANA Character Set
  20.791 +                         Registration Procedures", RFC 2978, October
  20.792 +                         2000.
  20.793 +
  20.794 +   [IMAP]                Crispin, M. "Internet Message Access Protocol -
  20.795 +                         Version 4rev1", RFC 3501, March 2003.
  20.796 +
  20.797 +   [IMAP-I18N]           Newman, C. and Gulbrandsen, A. "Internet
  20.798 +                         Message Access Protocol Internationalization",
  20.799 +                         Work in Progress.
  20.800 +
  20.801 +   [KEYWORDS]            Bradner, S. "Key words for use in RFCs to
  20.802 +                         Indicate Requirement Levels", BCP 14, RFC 2119,
  20.803 +                         March 1997.
  20.804 +
  20.805 +   [RFC-2822]            Resnick, P. "Internet Message Format", RFC
  20.806 +                         2822, April 2001.
  20.807 +
  20.808 +   [UNICASEMAP]          Crispin, M. "i;unicode-casemap - Simple Unicode
  20.809 +                         Collation Algorithm", RFC 5051.
  20.810 +
  20.811 +10. Informative References
  20.812 +
  20.813 +   The following documents are informative to this document:
  20.814 +
  20.815 +   [IMAP-MODELS]         Crispin, M. "Distributed Electronic Mail Models
  20.816 +                         in IMAP4", RFC 1733, December 1994.
  20.817 +
  20.818 +   [THREADING]           Zawinski, J. "Message Threading",
  20.819 +                         http://www.jwz.org/doc/threading.html,
  20.820 +                         1997-2002.
  20.821 +
  20.822 +Appendices
  20.823 +
  20.824 +Author's Address
  20.825 +
  20.826 +   Mark R. Crispin
  20.827 +   Networks and Distributed Computing
  20.828 +   University of Washington
  20.829 +   4545 15th Avenue NE
  20.830 +   Seattle, WA  98105-4527
  20.831 +
  20.832 +   Phone: +1 (206) 543-5762
  20.833 +
  20.834 +   EMail: MRC@CAC.Washington.EDU
  20.835 +
  20.836 +   Kenneth Murchison
  20.837 +   Carnegie Mellon University
  20.838 +   5000 Forbes Avenue
  20.839 +   Cyert Hall 285
  20.840 +   Pittsburgh, PA  15213
  20.841 +
  20.842 +   Phone: +1 (412) 268-2638
  20.843 +   Email: murch@andrew.cmu.edu
  20.844 +
  20.845 +Full Copyright Statement
  20.846 +
  20.847 +   Copyright (C) The IETF Trust (2008).
  20.848 +
  20.849 +   This document is subject to the rights, licenses and restrictions
  20.850 +   contained in BCP 78, and except as set forth therein, the authors
  20.851 +   retain all their rights.
  20.852 +
  20.853 +   This document and the information contained herein are provided on an
  20.854 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  20.855 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  20.856 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  20.857 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  20.858 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  20.859 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  20.860 +
  20.861 +Intellectual Property
  20.862 +
  20.863 +   The IETF takes no position regarding the validity or scope of any
  20.864 +   Intellectual Property Rights or other rights that might be claimed to
  20.865 +   pertain to the implementation or use of the technology described in
  20.866 +   this document or the extent to which any license under such rights
  20.867 +   might or might not be available; nor does it represent that it has
  20.868 +   made any independent effort to identify any such rights.  Information
  20.869 +   on the procedures with respect to rights in RFC documents can be
  20.870 +   found in BCP 78 and BCP 79.
  20.871 +
  20.872 +   Copies of IPR disclosures made to the IETF Secretariat and any
  20.873 +   assurances of licenses to be made available, or the result of an
  20.874 +   attempt made to obtain a general license or permission for the use of
  20.875 +   such proprietary rights by implementers or users of this
  20.876 +   specification can be obtained from the IETF on-line IPR repository at
  20.877 +   http://www.ietf.org/ipr.
  20.878 +
  20.879 +   The IETF invites any interested party to bring to its attention any
  20.880 +   copyrights, patents or patent applications, or other proprietary
  20.881 +   rights that may cover technology that may be required to implement
  20.882 +   this standard.  Please address the information to the IETF at ietf-
  20.883 +   ipr@ietf.org.
  20.884 +
  20.885 +Acknowledgement
  20.886 +
  20.887 +   Funding for the RFC Editor function is currently provided by the
  20.888 +   Internet Society.
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/docs/drivers.txt	Mon Sep 14 15:17:45 2009 +0900
    21.3 @@ -0,0 +1,189 @@
    21.4 +/* ========================================================================
    21.5 + * Copyright 1988-2006 University of Washington
    21.6 + *
    21.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    21.8 + * you may not use this file except in compliance with the License.
    21.9 + * You may obtain a copy of the License at
   21.10 + *
   21.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   21.12 + *
   21.13 + * 
   21.14 + * ========================================================================
   21.15 + */
   21.16 +
   21.17 +		   c-client Driver Characteristics
   21.18 +			     Mark Crispin
   21.19 +			   11 December 2006
   21.20 +
   21.21 +
   21.22 +     Drivers are code modules that support different mailbox storage
   21.23 +technologies.  A mailbox storage technology may be implemented by
   21.24 + 1) files and directories on the local system
   21.25 + 2) a database
   21.26 + 3) a network protocol.
   21.27 +
   21.28 +     In the case of files and directories on the local system, a
   21.29 +driver supports a particular mailbox format.  Mailbox formats are
   21.30 +discussed in more detail in the file formats.txt.
   21.31 +
   21.32 +     As of the date this document was written, there was no bundled
   21.33 +support for any databases in c-client.  However, it should not be
   21.34 +particularly difficult to write a driver that communicates with a
   21.35 +database.
   21.36 +
   21.37 +     Network protocols supported by c-client drivers are the Internet
   21.38 +Mail Access Protocol (all versions: IMAP4rev1, IMAP4, IMAP2bis, and
   21.39 +IMAP2); the Post Office Protocol (version 3); and the Network News
   21.40 +Transport Protocol (NNTP).  In addition, c-client also supports NNTP
   21.41 +and the Simple Mail Transport Protocol (SMTP) for mailbox transport.
   21.42 +
   21.43 +     By default, all drivers are enabled.  There is little benefit to
   21.44 +be gained by disabling a driver, with one exception.  The mbox driver
   21.45 +implements the behavior of automatically moving new mail from the
   21.46 +spool directory to the "mbox" file on the user's home directory, if
   21.47 +and *only* if the "mbox" exists and is in mailbox format.  The mbox
   21.48 +driver is listed under EXTRADRIVERS; if you wish to disable it just
   21.49 +remove it from that list and rebuild.
   21.50 +
   21.51 +I. Special name "INBOX"
   21.52 +
   21.53 +The following rules to select INBOX and its format apply in
   21.54 +the order given if "black box mode" is not in effect:
   21.55 + 1) mbox format is selected if file ~/mbox exists, and is in unix
   21.56 +    format or is zero-length.
   21.57 + 2) mx format is selected if file ~/INBOX/.mxindex exists.
   21.58 + 3) mbx format is selected if file ~/INBOX exists and is in mbx format.
   21.59 + 4) tenex format is selected if:
   21.60 +    a) file ~/mail.txt exists, and is in tenex format or is zero-length.
   21.61 +    b) file ~/INBOX exists and is in tenex format.
   21.62 + 5) mtx format is selected if:
   21.63 +    a) file ~/INBOX.MTX exists, and is in mtx format or is zero-length.
   21.64 +    b) file ~/INBOX exists and is in mtx format.
   21.65 + 6) mmdf format is selected if the spool directory file exists and is
   21.66 +    in mmdf format.
   21.67 + 7) unix format is selected if the spool directory file exists and is
   21.68 +    in unix format.   
   21.69 + 8) the dummy driver is selected if the spool directory file does not
   21.70 +    exist, or exists and is empty.
   21.71 +
   21.72 +If "black box mode" is not in effect, messages are automatically
   21.73 +transferred ("snarfed") from the spool directory to an INBOX in mbox,
   21.74 +mx, mbx, tenex, and mtx formats.
   21.75 +
   21.76 +The following rules to select INBOX and its format apply in the order
   21.77 +given if "black box mode" is in effect:
   21.78 + 1) mx format is selected if file ~/INBOX/.mxindex exists.
   21.79 + 2) mbx format is selected if file ~/INBOX exists and is in mbx format.
   21.80 + 3) tenex format is selected if file ~/INBOX exists and is in tenex format.
   21.81 + 4) mtx format is selected if file ~/INBOX exists and is in mtx format.
   21.82 + 5) mmdf format is selected if file ~/INBOX exists and is in mmdf format.
   21.83 + 6) unix format is selected if file ~/INBOX exists and is in unix format.
   21.84 + 7) the dummy driver is selected if ~/INBOX does not exist, or exists
   21.85 +    and is empty.
   21.86 +
   21.87 +II. Special Name #mhinbox
   21.88 +
   21.89 +#mhinbox always refers to the directory "inbox" in the MH path, which
   21.90 +is declared in the ~/.mh_profile file.  Messages are automatically
   21.91 +transferred from the spool directory to #mhinbox mailbox.
   21.92 +
   21.93 +
   21.94 +III. Special Prefix "#mh/"
   21.95 +
   21.96 +Any name prefixed with "#mh/" always refers to a directory in the MH
   21.97 +path, which is declared in the ~/.mh_profile file.  For example, the name
   21.98 +"#mh/foo" refers to directory "foo" in the MH path.
   21.99 +
  21.100 +
  21.101 +IV. Special prefix "#news."
  21.102 +
  21.103 +Any name prefixed with "#news" always refers to a newsgroup.  For
  21.104 +example, the name "#news.comp.mail.misc" refers to newsgroup
  21.105 +"comp.mail.misc".
  21.106 +
  21.107 +
  21.108 +V. All Other Names
  21.109 +
  21.110 +The driver is selected by generating a file name from the mailbox
  21.111 +name, and then examining the data of the object with the resulting
  21.112 +name.  The formats are checked in order: mx, mbx, tenex, mtx, mmdf,
  21.113 +unix, and phile.  The dummy driver is selected if the file is empty.
  21.114 +
  21.115 +The file name is generated according to certain rules, based upon the
  21.116 +prefix of the mailbox name.  On UNIX, the following rules apply:
  21.117 +
  21.118 +Prefix		Interpretation of Suffix
  21.119 +------		------------------------
  21.120 +/		[black box] preceeds a user name; "/foo/bar" means
  21.121 +		 "black box user foo's mailbox bar"
  21.122 +		[not black box] preceeds an absolute path name.
  21.123 +~		[not black box] preceeds a user name; "~foo/bar" means
  21.124 +		 "UNIX user foo's mailbox bar"
  21.125 +#ftp/		preceeds UNIX user ftp's mailbox name
  21.126 +#public/	preceeds UNIX user imappublic's mailbox name
  21.127 +#shared/	preceeds UNIX user imapshared's mailbox name
  21.128 +
  21.129 +All other names are interpreted in the context of the UNIX user's home
  21.130 +directory (not black box), the black box user's black box directory
  21.131 +(black box), or UNIX user ftp's home directory (anonymous).
  21.132 +
  21.133 +The strings "..", "//", and /~ are forbidden in names in:
  21.134 + black box mode
  21.135 + #ftp, #public, or #shared names
  21.136 + anonymous users
  21.137 +
  21.138 +Anonymous users may only access:
  21.139 + INBOX (belonging to UNIX user ftp)
  21.140 + files in or below UNIX user ftp's home directory
  21.141 + #ftp, #news, and #public namespace
  21.142 +
  21.143 +VI. Driver Comparison
  21.144 +
  21.145 +The following information about the local file drivers is an
  21.146 +elaboration of a table compiled by Osma Ahvenlampi.
  21.147 +
  21.148 +Driver	CA	CE	UID	Kwd	Sub	NFS	Performance	Layout
  21.149 +------	--	--	---	---	---	---	-----------	------
  21.150 +unix	no	no	yes	yes	no	limited	fair		file
  21.151 + ;;; traditional UNIX format
  21.152 +mbox	no	no	yes	yes	no	limited	fair		file
  21.153 + ;;; traditional UNIX format, INBOX only, using ~/mbox with automatic
  21.154 + ;;; moving from the mail spool directory.
  21.155 +mmdf	no	no	yes	yes	no	limited	fair		file
  21.156 + ;;; default on SCO systems
  21.157 +mbx	yes	yes	yes	yes	no	no	very good	prefile
  21.158 + ;;; best performing local file driver; preferred format at UW
  21.159 +tenex	yes	no	no	limited	no	no	good		prefile
  21.160 + ;;; compatible with UNIX MM
  21.161 +mtx	yes	no	no	limited	no	no	very good	prefile
  21.162 + ;;; PC Pine standard format; compatible with TOPS-20; identical to tenex
  21.163 + ;;; but instead CRLF newlines instead of LF
  21.164 +mx	yes	buggy	yes	yes	yes	no	poor		ixdir
  21.165 + ;;; fullest function; *not* recommended due to performance problems and bugs;
  21.166 + ;;; to be redesigned/rewritten
  21.167 +mh	yes	no	no	no	yes	yes	very poor	dir
  21.168 + ;;; compatible with mh; #mhinbox for INBOX, #mh/ prefix for all other names
  21.169 +news	yes	no	yes	no	yes	yes	very poor	ixdir
  21.170 + ;;; local news spool access; #news. prefix for all names
  21.171 +phile	no	no	no	no	no	yes	good		file
  21.172 + ;;; reads arbitrary file as a single readonly message
  21.173 +
  21.174 +IMPORTANT: the "performance" ratings are relative to other drivers,
  21.175 +and not necessarily to other software which implements those formats.
  21.176 +They relate to the driver's performance in typical operations such as
  21.177 +an IMAP "FETCH ALL".
  21.178 +
  21.179 +Key to headings:
  21.180 +	CA:	concurrent read/write access
  21.181 +	CE:	expunge permitted in concurrent read/write access
  21.182 +	UID:	sticky UIDs
  21.183 +	Kwd:	keyword flags
  21.184 +	Sub:	subfolders
  21.185 +	NFS:	usable over network filesystems (NFS, AFS, etc.)
  21.186 +	Layout:	file - single file
  21.187 +		prefile - file with preallocated space for state
  21.188 +		dir - directory, messages are files
  21.189 +		ixdir - directory, messages are files, with helper index
  21.190 +
  21.191 +In addition, drivers imap, nntp, and pop3 support IMAP4rev1, NNTP, and
  21.192 +POP3 protocols respectively.
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/docs/formats.txt	Mon Sep 14 15:17:45 2009 +0900
    22.3 @@ -0,0 +1,217 @@
    22.4 +/* ========================================================================
    22.5 + * Copyright 1988-2006 University of Washington
    22.6 + *
    22.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    22.8 + * you may not use this file except in compliance with the License.
    22.9 + * You may obtain a copy of the License at
   22.10 + *
   22.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   22.12 + *
   22.13 + * 
   22.14 + * ========================================================================
   22.15 + */
   22.16 +
   22.17 +		    Mailbox Format Characteristics
   22.18 +			     Mark Crispin
   22.19 +			   11 December 2006
   22.20 +
   22.21 +
   22.22 +     When a mailbox storage technology uses local files and
   22.23 +directories directly, the file(s) and directories are layed out in a
   22.24 +mailbox format.
   22.25 +
   22.26 +I. Flat-File Formats
   22.27 +
   22.28 +     In these formats, a mailbox and all the messages inside are a
   22.29 +single file on the filesystem.  The mailbox name is the name of the
   22.30 +file in the filesystem, relative to the user's "mail home directory."
   22.31 +
   22.32 +     A flat-file format mailbox is always a file, never a directory.
   22.33 +This means that it is impossible to have a flat-file format mailbox
   22.34 +that has inferior mailbox names under it (so-called "dual-usage"
   22.35 +mailboxes).  For some inexplicable reason, some people want this.
   22.36 +
   22.37 +     The mail home directory is usually the same as the user login
   22.38 +home directory if that concept is meaningful; otherwise, it is some
   22.39 +other default directory (e.g. "C:\My Documents" on Windows 98).  This
   22.40 +can be redefined by modifying the c-client source code or in an
   22.41 +application via the SET_HOMEDIR mail_parameters() call.
   22.42 +
   22.43 +     For example, a mailbox named "project" is likely to be found in
   22.44 +the file "project" in the user's home directory.  Similarly, a mailbox
   22.45 +named "test/trial1" (assuming a UNIX system) is likely to be found in
   22.46 +the file "trial1" in the subdirectory "test" in the user's home
   22.47 +directory.
   22.48 +
   22.49 +     Note that the name "INBOX" has special semantics and rules, as
   22.50 +described in the file naming.txt.
   22.51 +
   22.52 +     The following flat-file formats are supported by c-client as of
   22.53 +the time of this writing:
   22.54 +
   22.55 +. unix	This is the traditional UNIX mailbox format, in use for nearly
   22.56 +	30 years.  It uses a line starting with "From " to indicate
   22.57 +	start of message, and stores the message status inside the
   22.58 +	RFC822 message header.
   22.59 +
   22.60 +	unix is not particularly efficient; the entire mailbox file
   22.61 +	must be read when the mailbox is open, and when reading message
   22.62 +	texts it is necessary to convert the newline convention to
   22.63 +	Internet standard CR LF form.  unix preserves UIDs, and allows
   22.64 +	the creation of keywords.
   22.65 +
   22.66 +	Only one process may have a unix-format mailbox open
   22.67 +	read/write at a time.
   22.68 +
   22.69 +. mmdf	This is the format used by the MMDF mailer.  It uses a line
   22.70 +	consisting of 4 <CTRL/A> (0x01) characters to indicate start
   22.71 +	and end of message.  Optionally, there may also be a unix
   22.72 +	format "From " line.  It otherwise has the same
   22.73 +	characteristics as unix format.
   22.74 +
   22.75 +. mbx	This is the current preferred mailbox format.  It can be
   22.76 +	handled quite efficiently by c-client, without the problems
   22.77 +	that exist with unix and mmdf formats.  Messages are stored
   22.78 +	in Internet standard CR LF format.
   22.79 +
   22.80 +	mbx permits shared access, including shared expunge.  It
   22.81 +	preserves UIDs, and allows the creation of keywords.
   22.82 +
   22.83 +. mtx	This is supported for compatibility with the past.  This is
   22.84 +	the old Tenex/TOPS-20 mail.txt format.  It can be handled
   22.85 +	quite efficiently by c-client, and has most of the
   22.86 +	characteristics of mbx format.
   22.87 +
   22.88 +	mtx is deficient in that it does not support shared expunge;
   22.89 +	it has no means to store UIDs; and it has no way to define
   22.90 +	keywords except through an external configuration file.
   22.91 +
   22.92 +. tenex	This is supported for compatibility with the past.  This is
   22.93 +	the old Columbia MM format.  This is similar to mtx format,
   22.94 +	only it uses UNIX-style bare-LF newlines instead of CR LF
   22.95 +	newlines, thus incurring a performance penalty for newline
   22.96 +	conversion.
   22.97 +
   22.98 +. phile	This is not strictly a format.  Any file which is not in a
   22.99 +	recognized format is in phile format, which treats the entire
  22.100 +	contents of the file as a single message.
  22.101 +
  22.102 +
  22.103 +II. File/Message Formats
  22.104 +
  22.105 +     In these formats, a mailbox is a directory, and each the messages
  22.106 +inside are separate files inside the directory.  The file names of
  22.107 +these files are generally the text form of a number, which also
  22.108 +matches the UID of the message.
  22.109 +
  22.110 +     In the case of mx, the mailbox name is the name of the directory
  22.111 +in the filesystem, relative to the user's "mail home directory."  In
  22.112 +the case of news and mh, the mailbox name is in a separate namespace
  22.113 +as described in the file naming.txt.
  22.114 +
  22.115 +     A file/message format mailbox is always a directory.  This means
  22.116 +that it is possible to have a file/message format mailbox that has
  22.117 +inferior mailbox names under it (so-called "dual-usage" mailboxes).
  22.118 +For some inexplicable reason, some people want this.
  22.119 +
  22.120 +     Note that the name "INBOX" has special semantics and rules, as
  22.121 +described in the file naming.txt.
  22.122 +
  22.123 +     The following file/message formats are supported by c-client as of
  22.124 +the time of this writing:
  22.125 +
  22.126 +. mx	This is an experimental format, and may be removed in a future
  22.127 +	release.  An mx format mailbox has a .mxindex file which holds
  22.128 +	the message status and unique identifiers.  Messages are
  22.129 +	stored in Internet standard CF LF form, so the file size of
  22.130 +	the message file equals the size of the message.
  22.131 +
  22.132 +	mx is somewhat inefficient; the entire directory must be read
  22.133 +	and each file stat()'d.  We found it intolerable for a
  22.134 +	moderate sized mailbox (2000 messages) and have more or less
  22.135 +	abandoned it.	
  22.136 +
  22.137 +. mh	This is supported for compatibility with the past.  This is
  22.138 +	the format used by the old mh program.
  22.139 +
  22.140 +	mh is very inefficient; the entire directory must be read
  22.141 +	and each file stat()'d, and in order to determine the size
  22.142 +	of a message, the entire file must be read and newline
  22.143 +	conversion performed.
  22.144 +
  22.145 +	mh is deficient in that it does not support any permanent
  22.146 +	flags or keywords; and has no means to store UIDs (because
  22.147 +	the mh "compress" command renames all the files, that's
  22.148 +	why).
  22.149 +
  22.150 +. news	This is an export of the local filesystem's news spool, e.g.
  22.151 +	/var/spool/news.  Access to mailboxes in news format is read
  22.152 +	only; however, message "deleted" status is preserved in a
  22.153 +	.newsrc file in the user's home directory.  There is no other
  22.154 +	status or keywords.
  22.155 +
  22.156 +	news is very inefficient; the entire directory must be
  22.157 +	read and each file stat()'d, and in order to determine the
  22.158 +	size of a message, the entire file must be read and newline
  22.159 +	conversion performed.
  22.160 +
  22.161 +	news is deficient in that it does not support permanent flags
  22.162 +	other than deleted; does not support keywords; and has no
  22.163 +	expunge.
  22.164 +
  22.165 +
  22.166 +Soapbox on File/Message Formats
  22.167 +
  22.168 +     If it sounds from the above descriptions that we're not putting
  22.169 +too much effort into file/message formats, you are correct.
  22.170 +
  22.171 +     There's a general reason why file/message formats are a bad idea.
  22.172 +Just about every filesystem in existance serializes file creation and
  22.173 +deletions because these manipulate the free space map.  This turns out
  22.174 +to be an enormous problem when you start creating/deleting more than a
  22.175 +few messages per second; you spend all your time thrashing in the
  22.176 +filesystem.
  22.177 +
  22.178 +     It is also extremely slow to do a text search through a
  22.179 +file/message format mailbox.  All of those open()s and close()s really
  22.180 +add up to major filesystem thrashing.
  22.181 +
  22.182 +
  22.183 +What about Cyrus and Maildir?
  22.184 +
  22.185 +     Both formats are vulnerable to the filesystem thrashing outlined
  22.186 +above.
  22.187 +
  22.188 +     The Cyrus format used by CMU's Cyrus server (and Esys' server)
  22.189 +has a special associated flat file in each directory that contains
  22.190 +extensive data (including pre-parsed ENVELOPEs and BODYSTRUCTUREs)
  22.191 +about the messages.  Put another way, it's a (considerably) more
  22.192 +featureful form of mx.  It also uses certain operating system
  22.193 +facilities (e.g. file/memory mapping) which are not available on older
  22.194 +systems, at a cost of much more limited portability than c-client.
  22.195 +These considerably ameliorate the fundamental problems with
  22.196 +file/message formats; in fact, Cyrus is halfway to being a database.
  22.197 +Rather than support Cyrus format in c-client, you should run Cyrus or
  22.198 +Esys if you want that format.
  22.199 +
  22.200 +     The Maildir format used by qmail has all of the performance
  22.201 +disadvantages of mh noted above, with the additional problem that the
  22.202 +files are renamed in order to change their status so you end up having
  22.203 +to rescan the directory frequently to locate the current names
  22.204 +(particularly in a shared mailbox scenario).  It doesn't scale, and it
  22.205 +represents a support nightmare; it is therefore not supported in the
  22.206 +official distribution.  Maildir support code for c-client is available
  22.207 +from third parties; but, if you use it, it is entirely at your own
  22.208 +risk (read: don't complain about how poorly it performs or bugs).
  22.209 +
  22.210 +
  22.211 +So what does this all mean?
  22.212 +
  22.213 +     A database (such as used by Exchange) is really a much better
  22.214 +approach if you want to move away from flat files.  mx and especially
  22.215 +Cyrus take a tenative step in that direction; mx failed mostly because
  22.216 +it didn't go anywhere near far enough.  Cyrus goes much further, and
  22.217 +scores remarkable benefits from doing so.
  22.218 +
  22.219 +     However, a well-designed pure database without the overhead of
  22.220 +separate files would do even better.
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/docs/imaprc.txt	Mon Sep 14 15:17:45 2009 +0900
    23.3 @@ -0,0 +1,613 @@
    23.4 +/* ========================================================================
    23.5 + * Copyright 1988-2006 University of Washington
    23.6 + *
    23.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    23.8 + * you may not use this file except in compliance with the License.
    23.9 + * You may obtain a copy of the License at
   23.10 + *
   23.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   23.12 + *
   23.13 + * 
   23.14 + * ========================================================================
   23.15 + */
   23.16 +
   23.17 +		       .imaprc secrets revealed!
   23.18 +		      Mark Crispin, June 17, 2002
   23.19 +
   23.20 +The following information describes the format of the /etc/c-client.cf
   23.21 +and ~/.imaprc file.  The Columbia MM ~/.mminit file is also read by
   23.22 +c-client; however, the only command that ~/.mminit has in common is
   23.23 +set keywords.
   23.24 +
   23.25 +**********************************************************************
   23.26 +*		     DANGER!  BEWARE!  TAKE CARE!		     *
   23.27 +**********************************************************************
   23.28 +*								     *
   23.29 +*  These files, and this documentation, are for internal UW usage    *
   23.30 +* only.  This capability is for UW experimental tinkering, and most  *
   23.31 +* emphatically *not* for sorcerer's apprentices at other sites who   *
   23.32 +* feel that if a config file capability exists, they must write a    *
   23.33 +* config file whether or not there is any need for one.		     *
   23.34 +*								     *
   23.35 +*  This information is subject to change without notice.  Commands   *
   23.36 +* may be added, removed, or altered.  The behavior of comamnds may   *
   23.37 +* change.  Do not use any of this information without consulting me  *
   23.38 +* first.  c-client's defaults have been carefully chosen to be right *
   23.39 +* for general-purpose and most special-purpose configurations.  If   *
   23.40 +* you tinker with these defaults, all hell may break loose.	     *
   23.41 +*								     *
   23.42 +*  This is not an idle threat.  There have been several instances of *
   23.43 +* people who ignored these warnings and have gotten burned.	     *
   23.44 +*								     *
   23.45 +*  Don't even trust this file to work.  Many of the things which can *
   23.46 +* be changed by this file can also be changed by the application,    *
   23.47 +* and it is totally unpredictable which will take precedence.  It    *
   23.48 +* all depends upon how the application is coded.  Not only that, you *
   23.49 +* may cause the application to crash.                                *
   23.50 +*								     *
   23.51 +*  In other words, keep your cotton-pickin' hands off my defaults.   *
   23.52 +* If it crashes and erases your mail, I don't want to hear about it. *
   23.53 +* Consider 'em ``mandatory defaults''.  Got a nice ring, eh?  :-) If *
   23.54 +* you must tinker with defaults, play with the .pinerc and pine.conf *
   23.55 +* files in Pine.  It's got options galore, all supported for you to  *
   23.56 +* have fun.  They're also documented; so well documented, it takes   *
   23.57 +* two strong men to carry around all the documentation.	 ;-) ;-)     *
   23.58 +*								     *
   23.59 +*  Joking aside, you really shouldn't be fooling around with this    *
   23.60 +* capability.  It's dangerous, and you can shoot yourself in the     *
   23.61 +* foot easily.  If you need custom changes, you are better off with  *
   23.62 +* local source code modifications.  Seriously.			     *
   23.63 +*								     *
   23.64 +*  One last warning: don't believe anything that you read in this    *
   23.65 +* document.  Every effort has been made to ensure that this document *
   23.66 +* is incomplete and inaccurate, and I take no responsibility for any *
   23.67 +* glimmers of correct information that may, by some fluke, be here.  *
   23.68 +*								     *
   23.69 +**********************************************************************
   23.70 +
   23.71 +The files are read in order: /etc/c-client.cf, ~/.mminit, ~/.imaprc,
   23.72 +and an entry in a later file overrides the setting of an earlier file
   23.73 +except as noted below.  This ordering and overriding behavior may
   23.74 +change without notice.
   23.75 +
   23.76 +Almost all of these facilities can also be set via the mail_parameters()
   23.77 +call in the program.  Whether the file overrides mail_parameters(), or
   23.78 +mail_parameters() overrides the file, is indeterminate.  It will vary
   23.79 +from program to program, and it may be one way in one version and the
   23.80 +other way in the next version.  It's completely unpredictable, and so
   23.81 +anything you do with these files has to be in complete knowledge of what
   23.82 +the version of each program you're running is going to do.  This is
   23.83 +because the files do something for testing, but the real capability for
   23.84 +configurability is put in the program instead.  Are you getting the
   23.85 +feeling that you shouldn't be messing with these files yet?
   23.86 +
   23.87 +The very first line of the file MUST start with the exact string "I
   23.88 +accept the risk".  This ensures that you have checked the file for
   23.89 +correctness against this version of the IMAP toolkit.  This enable
   23.90 +string may change without notice in future versions, and the new
   23.91 +string may or may not be accurately described in an updated version of
   23.92 +this file.  So any time you install software that uses the IMAP
   23.93 +toolkit, you need to check the new version against these files (if you
   23.94 +have insisted upon creating them in spite of all warnings).  If two
   23.95 +pieces of software use different versions of the IMAP toolkit with
   23.96 +incompatible requirements, one of them won't work.  Re-read the
   23.97 +warning above about why you should not use these files.
   23.98 +
   23.99 +Subsequent lines are read from the file one at a time.  Case does not
  23.100 +matter.  Unrecognized commands are ignored.
  23.101 +
  23.102 +1) set new-folder-format
  23.103 +   sets what format new mailboxes are created in.  This also controls
  23.104 +   default delivery via tmail and dmail.
  23.105 +
  23.106 +   a) set new-folder-format same-as-inbox
  23.107 +      Folder is created using the same mailbox format as INBOX.  If
  23.108 +      INBOX is empty, it defaults to system standard.
  23.109 +
  23.110 +   b) set new-folder-format system-standard
  23.111 +      This is the default.  Folder is created using the wired-in system
  23.112 +      standard format, which on most UNIX systems is ordinary UNIX
  23.113 +      /bin/mail format.  On SCO systems, this is MMDF.
  23.114 +
  23.115 +   c) set new-folder-format <driver name>
  23.116 +      Folder is created using the given driver name, e.g. mbx, unix,
  23.117 +      mmdf, etc.
  23.118 +
  23.119 +   There is no protection against setting this to a silly value (e.g.
  23.120 +   news, nntp, dummy) and doing so is a great way to screw things up.
  23.121 +   Setting this to mh does not do what you think it does.  Setting this
  23.122 +   to tenex or mtx isn't particularly useful.
  23.123 +
  23.124 +2) set empty-folder-format
  23.125 +   sets what format data is written into an empty mailbox file using
  23.126 +   mail_copy() or mail_append().  This also controls default delivery
  23.127 +   via tmail.
  23.128 +
  23.129 +   a) set empty-folder-format same-as-inbox
  23.130 +      Data is written using the same mailbox format as INBOX.  If
  23.131 +      INBOX is empty, it defaults to system standard.
  23.132 +
  23.133 +   b) set empty-folder-format system-standard
  23.134 +      This is the default.  Data is written using the wired-in system
  23.135 +      standard format, which on most UNIX systems is ordinary UNIX
  23.136 +      /bin/mail format.  On SCO systems, this is MMDF.
  23.137 +
  23.138 +   c) set-empty-folder-format <driver name>
  23.139 +      Data is written using the given driver name, e.g. tenex, unix,
  23.140 +      mmdf, etc.
  23.141 +
  23.142 +   There is no protection against setting this to a silly value (e.g.
  23.143 +   news, nntp, dummy) and doing so is a great way to screw things up.
  23.144 +   Setting this to mh, mbx, or mx does not work.
  23.145 +
  23.146 +3) set keywords <word1>, <word2>, ... <wordn>
  23.147 +   Sets the list of keyword flags (supported by tenex and mtx) to the
  23.148 +   given list.  Up to 30 flags may be given.  Since these names
  23.149 +   correspond to numeric bits, the order of the keywords can not be
  23.150 +   changed, nor can keywords be removed or inserted (you can append
  23.151 +   new keywords, up to the limit of 30).
  23.152 +
  23.153 +   Set keywords is a deprecated command.  It may not appear in
  23.154 +   future versions, or it may appear in a changed form.  It exists
  23.155 +   only for compatibility with MM, and should only appear in ~/.mminit
  23.156 +   and not in the other files.  It is likely to disappear entirely in
  23.157 +   IMAP4.
  23.158 +
  23.159 +   There is no protection against setting these to silly values, and
  23.160 +   doing so is a great way to cause a crash.
  23.161 +
  23.162 +4) set from-widget header-only
  23.163 +   Sets smart insertion of the > character in front of lines that
  23.164 +   begin with ``From ''.  Only such lines that are also in UNIX mbox
  23.165 +   header file format will have a > character inserted.  The default
  23.166 +   is to insert the > character in front of all lines which begin with
  23.167 +   ``From '', for the benefit of legacy tools that get confused
  23.168 +   otherwise.
  23.169 +
  23.170 +5) set black-box-directory <directory name>
  23.171 +   Sets the directory in which the user's data can be found.  A user's
  23.172 +   folders can be found in a subdirectory of the black box directory
  23.173 +   named with the user's username.  For example, if the blackbox
  23.174 +   directory is /usr/spool/folders/, user jones' data can be found
  23.175 +   in /usr/spool/folders/jones/.  The user's black-box directory is
  23.176 +   the location of folders, .mminit, .imaprc, .newsrc, and all other
  23.177 +   files used by c-client; internally, it sets c-client's idea of the
  23.178 +   user's ``home directory'', overriding /etc/passwd.
  23.179 +
  23.180 +   This command may not appear in ~/.mminit or ~/.imaprc
  23.181 +
  23.182 +   In black-box mode, it is not permitted to access any folders
  23.183 +   outside of the user's personal blackbox directory.  The breakouts
  23.184 +   ``/'', ``~'', and ``..'' are not permitted.
  23.185 +
  23.186 +   In order to make this work without crashing, you must set another
  23.187 +   option which is not listed in this document.
  23.188 +
  23.189 +   There is no protection against setting this to a silly value, and
  23.190 +   doing so is a great way to cause a crash.
  23.191 +
  23.192 +6) set local-host <host name>
  23.193 +   Sets c-client's idea of the local host name.
  23.194 +
  23.195 +   There is no protection against setting this to a silly value, and
  23.196 +   doing so is a great way to cause a crash.
  23.197 +
  23.198 +7) set news-active-file <file name>
  23.199 +   Sets the location of the news active file, if it is not in the
  23.200 +   standard place.
  23.201 +
  23.202 +   It is recommended to use a courtesy symbolic link instead.
  23.203 +
  23.204 +   There is no protection against setting this to a silly value, and
  23.205 +   doing so is a great way to cause a crash.
  23.206 +
  23.207 +8) set news-spool-directory <directory name>
  23.208 +   Sets the location of the news spool, if it is not in the standard
  23.209 +   place.
  23.210 +
  23.211 +   It is recommended to use a courtesy symbolic link instead.
  23.212 +
  23.213 +   There is no protection against setting this to a silly value, and
  23.214 +   doing so is a great way to cause a crash.
  23.215 +
  23.216 +9) set news-state-file <file name>
  23.217 +   Sets the location of the news state file (normally $(USER)/.newsrc).
  23.218 +
  23.219 +   This is not very useful in /etc/c-client.cf because it is a file name.
  23.220 +   Setting this in /etc/c-client.cf would set all users to the same file
  23.221 +   as their newsrc, which is probably not what you want.
  23.222 +
  23.223 +   There is no protection against setting this to a silly value, and
  23.224 +   doing so is a great way to cause a crash.
  23.225 +
  23.226 +10) set system-inbox <file name>
  23.227 +   Sets the location of the "system inbox", if it is not in the standard
  23.228 +   place.  This is the default location of INBOX, or the mail drop point
  23.229 +   from which mail is snarfed (e.g. in tenex, mtx, mbox, mh formats).
  23.230 +
  23.231 +   This is not very useful in /etc/c-client.cf because it is a file name.
  23.232 +   Setting this in /etc/c-client.cf would set all users to the same file
  23.233 +   as their system inbox, which is probably not what you want.
  23.234 +
  23.235 +   There is no protection against setting this to a silly value, and
  23.236 +   doing so is a great way to cause a crash.
  23.237 +
  23.238 +11) set tcp-open-timeout <number>
  23.239 +    Sets the number of seconds that the TCP routines will block on opening
  23.240 +    a TCP connection before timing out.  If a timeout occurs, the connection
  23.241 +    attempt is aborted.
  23.242 +
  23.243 +    The default is zero, meaning use the operating system default (75
  23.244 +    seconds on most UNIX systems).
  23.245 +
  23.246 +    There is no protection against setting this to an excessively small
  23.247 +    value, such as 1, and doing so is a great way to cause users extreme
  23.248 +    grief.
  23.249 +
  23.250 +12) set tcp-read-timeout <number>
  23.251 +    Sets the number of seconds that the TCP routines will block on reading
  23.252 +    data before calling the timeout routine.  If no timeout routine is set
  23.253 +    by the program, the connection will be aborted on a timeout.
  23.254 +
  23.255 +    The default is zero, meaning infinite.
  23.256 +
  23.257 +    There is no protection against setting this to an excessively small
  23.258 +    value, such as 1, and doing so is a great way to cause users extreme
  23.259 +    grief.
  23.260 +
  23.261 +13) set tcp-write-timeout <number>
  23.262 +    Sets the number of seconds that the TCP routines will block on sending
  23.263 +    data before calling the timeout routine.  If no timeout routine is set
  23.264 +    by the program, the connection will be aborted on a timeout.
  23.265 +
  23.266 +    The default is zero, meaning infinite.
  23.267 +
  23.268 +    There is no protection against setting this to an excessively small
  23.269 +    value, such as 1, and doing so is a great way to cause users extreme
  23.270 +    grief.
  23.271 +
  23.272 +14) set rsh-timeout <number>
  23.273 +    Sets the number of seconds that the rsh routines will block on opening
  23.274 +    an rimapd connection before timing out.  If a timeout occurs, the
  23.275 +    rsh connection attempt is aborted.  A zero timeout will disable rsh.
  23.276 +
  23.277 +    The default is 15 seconds.
  23.278 +
  23.279 +    There is no protection against setting this to an excessively small
  23.280 +    value, such as 1, and doing so is a great way to cause users extreme
  23.281 +    grief.
  23.282 +
  23.283 +15) set maximum-login-trials <number>
  23.284 +    Sets the number of iterations of asking the user, via mm_login(), for
  23.285 +    a user name and password, before cancelling the attempt.
  23.286 +
  23.287 +    The default is 3.
  23.288 +
  23.289 +    There is no protection against setting this to zero, and doing so is
  23.290 +    a great way to cause users extreme grief.
  23.291 +
  23.292 +16) set lookahead <number>
  23.293 +    Sets the number of envelopes that are looked ahead in IMAP, in
  23.294 +    mail_fetchstructure().  This is based on the guess that in such
  23.295 +    operations as drawing browser lines, if you get data for message n
  23.296 +    you are likely to want it for message n+1, n+2,... in short order.
  23.297 +    Lookahead preloads the c-client  cache and saves unnecessary RTTs.
  23.298 +
  23.299 +    The default is 20, a good number for a browser on a 24x80 screen, and
  23.300 +    small enough to usually have no significant real-time difference from
  23.301 +    a single message fetch.
  23.302 +
  23.303 +    Setting it to 0 turns off lookahead.
  23.304 +
  23.305 +    There is no protection against setting this ridiculously high and
  23.306 +    incurring performance penalties as a result.
  23.307 +
  23.308 +17) set prefetch <number>
  23.309 +    Sets the number of envelops which are automatically fetched for the
  23.310 +    messages which match in a search.  This is based on the guess that
  23.311 +    in a browser that is "zoomed" on the results of a search, you are
  23.312 +    likely to want the envelope data for each of those messages in
  23.313 +    short order.  Prefetching reloads the c-client cache, saves
  23.314 +    unnecessary RTTs, and avoids loading undesired envelopes due to
  23.315 +    lookahead (see above).
  23.316 +
  23.317 +    The default is 20.
  23.318 +
  23.319 +    Setting it to 0 turns off prefetch.
  23.320 +
  23.321 +    There is no protection against setting this ridiculously high and
  23.322 +    incurring performance penalties as a result.
  23.323 +
  23.324 +18) set close-on-error <number>
  23.325 +    If non-zero, IMAP connections are closed if an EXAMINE or SELECT
  23.326 +    command fails.  Otherwise, they are left half-open, and can be used
  23.327 +    again to select some other mailbox.  The mailbox name in the stream
  23.328 +    is set to {serverhost}<no_mailbox>
  23.329 +
  23.330 +    The default is zero (do not close on error).
  23.331 +
  23.332 +19) set imap-port <number>
  23.333 +    Set the TCP/IP contact port to use for IMAP.  This overrides the
  23.334 +    wired-in setting and the setting from /etc/services, and can in
  23.335 +    turn be overridden by an explicit user specification in the mailbox
  23.336 +    name, e.g. {serverhost:143}foo
  23.337 +
  23.338 +    The default is zero (use setting from /etc/services or the wired-in
  23.339 +    setting (143).
  23.340 +
  23.341 +    There is no protection against setting this to a silly value, and
  23.342 +    doing so is a great way to cause users extreme grief.
  23.343 +
  23.344 +20) set pop3-port <number>
  23.345 +    Set the TCP/IP contact port to use for POP3.  This overrides the
  23.346 +    wired-in setting and the setting from /etc/services, and can in
  23.347 +    turn be overridden by an explicit user specification in the mailbox
  23.348 +    name, e.g. {serverhost:110/pop3}
  23.349 +
  23.350 +    The default is zero (use setting from /etc/services or the wired-in
  23.351 +    setting (110).
  23.352 +
  23.353 +    There is no protection against setting this to a silly value, and
  23.354 +    doing so is a great way to cause users extreme grief.
  23.355 +
  23.356 +21) set uid-lookahead <number>
  23.357 +    Sets the number of UIDs that are looked ahead in IMAP in mail_uid().
  23.358 +    Lookahead preloads the c-client cache and saves unnecessary RTTs.
  23.359 +
  23.360 +    The default is 1000, small enough to usually have no significant
  23.361 +    real-time difference from a single message UID fetch.
  23.362 +
  23.363 +    Setting it to 0 turns off lookahead.
  23.364 +
  23.365 +    There is no protection against setting this ridiculously high and
  23.366 +    incurring performance penalties as a result.
  23.367 +
  23.368 +22) set mailbox-protection <number>
  23.369 +    Set the default protection for newly-created mailbox files.
  23.370 +
  23.371 +    The default is 384.
  23.372 +
  23.373 +    There is no protection against setting this to a silly value, and
  23.374 +    doing so is a great way to screw things up massively.
  23.375 +
  23.376 +23) set directory-protection <number>
  23.377 +    Set the default protection for newly-created directories.
  23.378 +
  23.379 +    The default is 448.
  23.380 +
  23.381 +    There is no protection against setting this to a silly value, and
  23.382 +    doing so is a great way to screw things up massively.
  23.383 +
  23.384 +24) set lock-protection <number>
  23.385 +    Set the default protection for lock files
  23.386 +
  23.387 +    The default is 438, which is necessary if locks are to be respected
  23.388 +    by processes running as other UIDs.
  23.389 +
  23.390 +    There is no protection against setting this to a silly value, and
  23.391 +    contrary to what you may think just about any value other than 438
  23.392 +    turns out to be a silly value.
  23.393 +
  23.394 +25) set disable-fcntl-locking <number>
  23.395 +    This only applies to SVR4 systems.
  23.396 +
  23.397 +    If non-zero, fnctl() locking is not attempted.  In the past, this
  23.398 +    was used to avoid locking NFS files.  If NFS is involved, the evil
  23.399 +    lockd/statd daemons get invoked.  These daemons supposedly work over
  23.400 +    NFS, but really don't.
  23.401 +
  23.402 +    You probably don't really want to do this, though, because now the
  23.403 +    flock() emulator (which calls fcntl()) now checks to see if the file
  23.404 +    is accessed via NFS and no-ops the lock.  This is compatible with
  23.405 +    BSD.
  23.406 +
  23.407 +    Disabling fcntl() locking loses a great deal of locking protection
  23.408 +    on local files as well as NFS files (which now never have locking
  23.409 +    protection).
  23.410 +
  23.411 +    The default is zero (fcntl() locking is enabled).
  23.412 +
  23.413 +26) set lock-EACCES-error <number>
  23.414 +    If non-zero, a warning message is given if an attempt to create a
  23.415 +    lock file fails.  Otherwise, EACCES is treated as a "silent failure",
  23.416 +    and it proceeds without trying to use the lock file.  This is for
  23.417 +    the benefit of users on systems with paranoid /usr/spool/mail
  23.418 +    protections which don't let users create /usr/spool/mail/$(USER).lock
  23.419 +    files; these unfortunate users would be harassed with a flood of
  23.420 +    error messages otherwise.  The problem is that on SVR4, if EACCES
  23.421 +    remains disabled and fcntl() locking is also disabled, then there is
  23.422 +    no locking at all which is doubleplus-ungood.
  23.423 +
  23.424 +    If the site is paranoid on /usr/spool/mail protections AND if there
  23.425 +    is no fcntl() locking (SVR4) or usable flock() locking (e.g. NFS),
  23.426 +    then there is no way to win.  Find a different system to use.
  23.427 +
  23.428 +    The default is non-zero (report EACCESS as an error).
  23.429 +
  23.430 +27) set list-maximum-level <number>
  23.431 +    Sets the maximum depth of recursion that a * wildcard list will go
  23.432 +    down the directory tree.  0 means that no recursion is permitted,
  23.433 +    and * becomes like %.
  23.434 +
  23.435 +    The default is 20.
  23.436 +
  23.437 +    There is no protection against setting this to a ridiculously high
  23.438 +    value.  Since LIST will follow symbolic links, it can effectively
  23.439 +    recurse infinitely, until the name strings get large enough that
  23.440 +    some name limit is exceeded.
  23.441 +
  23.442 +28) set anonymous-home-directory <directory name>
  23.443 +   Sets the location of the anonymous home directory, if it is not in
  23.444 +   the standard  place.
  23.445 +
  23.446 +   It is recommended to use a courtesy symbolic link instead.
  23.447 +
  23.448 +   There is no protection against setting this to a silly value, and
  23.449 +   doing so is a great way to cause a crash.
  23.450 +
  23.451 +29) set chroot-server <number>
  23.452 +   This option is for closed server systems only.  If defined, a chroot()
  23.453 +   call to the user's home directory is done as part of the login
  23.454 +   process.  This has the effect of preventing access to any files
  23.455 +   outside of the user's home directory (including shared mailboxes).
  23.456 +
  23.457 +   Shared mailboxes with other users can't possibly work with this
  23.458 +   option, because there is no way to export lock information to other
  23.459 +   users.
  23.460 +
  23.461 +   This should be done ONLY on systems which do not permit users to
  23.462 +   have shell access
  23.463 +
  23.464 +   This option should NEVER(!!) be set if users are allowed shell access.
  23.465 +   Doing so actually makes the system *less* secure, since the user could
  23.466 +   create an etc subdirectory which would be treated as real /etc by such
  23.467 +   programs as /bin/su.
  23.468 +
  23.469 +   The default is zero (don't do chroot).
  23.470 +
  23.471 +   This option is strongly *NOT* recommended.
  23.472 +
  23.473 +30) set disable-automatic-shared-namespaces <number>
  23.474 +   Never look up the "ftp", "imappublic", and "imapshared" users as
  23.475 +   posssible home directories for the #ftp, #public, and #shared
  23.476 +   namespaces.  On some systems (reportedly including AIX 4.3.3)
  23.477 +   getpwnam() of an unknown user name is horrendously slow.
  23.478 +
  23.479 +   Note that this does not remove the #ftp, #public, and #shared
  23.480 +   namespaces, and they can still be set up by other means.
  23.481 +
  23.482 +   The default is zero (shared namespaces are automatic).
  23.483 +
  23.484 +31) set advertise-the-world <number>
  23.485 +   Include the UNIX root as a shared namespace.  This is generally a bad
  23.486 +   idea, since certain IMAP clients (names withheld to protect the guilty)
  23.487 +   will take this as license to download the entire filesystem tree.
  23.488 +
  23.489 +   The default is zero (don't advertise the world).
  23.490 +
  23.491 +32) set mail-subdirectory <subdirectory name>
  23.492 +   Change the default connected directory from the user's home directory
  23.493 +   to the named subdirectory of the user's home directory.  For example,
  23.494 +   setting MAILSUBDIR="mail" will cause the POP2 and IMAP servers to
  23.495 +   connect to the user's ~/mail subdirectory.  This is equivalent to
  23.496 +   the env_unix.c edit described in Example 2 of the CONFIG file.
  23.497 +
  23.498 +   Note that if the subdirectory does not exist, the result is undefined.
  23.499 +   It is probably an extremely bad idea to set this unless you can
  23.500 +   guarantee that the subdirectory exists for all users.  If you can not
  23.501 +   guarantee this, then you should leave the default as the user's home
  23.502 +   directory and allow them to configure a personal default in their IMAP
  23.503 +   client.
  23.504 +
  23.505 +   The default is not to use any subdirectory.
  23.506 +
  23.507 +33) set allow-user-config <number>
  23.508 +   Allow users to use ~/.imaprc and ~/.mminit files.
  23.509 +
  23.510 +   The default is zero (don't allow user config files).
  23.511 +
  23.512 +34) set allow-reverse-dns <number>
  23.513 +   By default, the servers (ipop[23]d and imapd) will do gethostbyaddr()
  23.514 +   on the local and remote sockets so that imapd can identify itself
  23.515 +   properly (this is important when the same CPU hosts multiple virtual
  23.516 +   hosts on different IP addresss) and also includes the client's name
  23.517 +   when it writes to the syslog.  There are also client gethostbyaddr()
  23.518 +   calls, used primarily by authentication mechanisms.
  23.519 +
  23.520 +   Setting this option to zero disables all gethostbyaddr() calls.  The
  23.521 +   returned "host name" string for the socket is just the bracketed
  23.522 +   [12.34.56.78] form, as if the reverse DNS lookup failed.
  23.523 +
  23.524 +   WARNING: Some authentication mechanisms, e.g. Kerberos V, depend upon
  23.525 +   the host names being right, and if you set this option, it won't work.
  23.526 +
  23.527 +   You should only do this if you are encountering server performance
  23.528 +   problems due to a misconfigured DNS, e.g. long startup delays or
  23.529 +   client timeouts.
  23.530 +
  23.531 +   The default is non-zero (allow reverse DNS).
  23.532 +
  23.533 +35) set disable-plaintext <number>
  23.534 +   Disable plaintext password authentication (LOGIN command, AUTH=LOGIN,
  23.535 +   and AUTH=PLAIN).
  23.536 +
  23.537 +   The default is zero (allow plaintext authentication).
  23.538 +
  23.539 +36) set trust-dns <number>
  23.540 +   By default, host names are canonicalized via gethostbyname() for
  23.541 +    everything except for SSL certificate validation.
  23.542 +
  23.543 +   This can represent a security bug due to DNS spoofing, but is more
  23.544 +    likely to deliver results that users expect.  It also may be necessary
  23.545 +    for SASL authentication to work right (e.g. generating a correct name
  23.546 +    for a Kerberos service principal) if the name entered by the user is a
  23.547 +    CNAME or not a fully-qualified domain name.
  23.548 +
  23.549 +   If trust-dns is set to zero, no host name canonicalization is done.
  23.550 +    The user's actual entered name is used for SASL authentication and
  23.551 +    will appear in the mailbox name of the open stream.
  23.552 +
  23.553 +   The default is non-zero (do DNS canonicalization).
  23.554 +
  23.555 +37) set sasl-uses-ptr-name <number>
  23.556 +   By default, if trust-dns is set, the host names used in authentication
  23.557 +    (e.g. to generate a Kerberos service principal) are canonicalized via
  23.558 +    gethostbyaddr() instead of by gethostbyname().  If gethostbyaddr()
  23.559 +    fails the gethostbyname() canonicalization is used.
  23.560 +
  23.561 +   This represents an additional security bug due to DNS spoofing, over and
  23.562 +    above trust-dns.  It also adds an additional DNS query to starting a
  23.563 +    session.
  23.564 +
  23.565 +   It is necessary for sites which implement a server cluster with multiple
  23.566 +    A records for a cluster name (instead of a CNAME) but each cluster
  23.567 +    member has a unique PTR record which it expects for a Kerberos service
  23.568 +    principal.
  23.569 +
  23.570 +   If sasl-uses-ptr-name is set to zero and trust-dns is set non-zero, the
  23.571 +    gethostbyname() canonicalized name is used for SASL authentication.
  23.572 +
  23.573 +   The setting of sasl-uses-ptr-name is irrelevant if trust-dns is set to
  23.574 +    zero.
  23.575 +
  23.576 +   The default is non-zero (use name from PTR record for SASL).
  23.577 +
  23.578 +38) set network-filesystem-stat-bug <number>
  23.579 +   By default, traditional UNIX mailbox files are only closed and reopened
  23.580 +    at checkpoint and expunge time.  This ensures that, prior to rewriting
  23.581 +    the file, that any cached stat() data from a network filesystem is
  23.582 +    updated with current data.
  23.583 +
  23.584 +   Very old versions of NFS, and reputedly also AFS, can get into a state
  23.585 +    in which the cached stat() data stays out-of-date, even across a
  23.586 +    close and reopen of the file.
  23.587 +
  23.588 +   If network-filesystem-stat-bug is set non-zero, then the mailbox file
  23.589 +    is closed and reopened at ping time as a workaround for this bug in
  23.590 +    these network filesystems.  This means that in imapd, the mailbox
  23.591 +    file is closed and reopened for every IMAP command.  This is obviously
  23.592 +    something that should be avoided unless absolutely necessary.
  23.593 +
  23.594 +   NFS and AFS are terrible ways to distribute mail.  You use use IMAP
  23.595 +    servers with a local disk instead.
  23.596 +
  23.597 +   The default is zero (only close/reopen at checkpoint and expunge time).
  23.598 +
  23.599 +   Setting this option is a great way to ruin your system's performance.
  23.600 +
  23.601 +39) set restrict-mailbox-access <option> <option> ... <option>
  23.602 +   This option is for closed server systems only.  It is less extreme
  23.603 +   than chroot-server, and allows selective restriction of what mailbox
  23.604 +   named users can use.  The existing options are:
  23.605 +    root	access not permitted to names starting with "/"
  23.606 +    otherusers	access not permitted to other users' names; this should
  23.607 +		 normally be used in conjunction with "root", otherwise
  23.608 +		 another user's names can be accessed via a root name.
  23.609 +    all		all of the above
  23.610 +   Setting any combination of options also disables access to superior
  23.611 +   directories via "..".
  23.612 +
  23.613 +   This should be done ONLY on systems which do not permit users to
  23.614 +   have shell access
  23.615 +
  23.616 +   The default is no restrictions.
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/docs/internal.txt	Mon Sep 14 15:17:45 2009 +0900
    24.3 @@ -0,0 +1,2988 @@
    24.4 +/* ========================================================================
    24.5 + * Copyright 1988-2006 University of Washington
    24.6 + *
    24.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    24.8 + * you may not use this file except in compliance with the License.
    24.9 + * You may obtain a copy of the License at
   24.10 + *
   24.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   24.12 + *
   24.13 + * 
   24.14 + * ========================================================================
   24.15 + */
   24.16 +
   24.17 +	  Documentation of c-client Functions and Interfaces
   24.18 +
   24.19 +REVISED: 19 August 1996
   24.20 +
   24.21 +				  Credits
   24.22 +
   24.23 +     The original version of this document was written by Mark Crispin at
   24.24 +the University of Washington, and described the version of c-client that
   24.25 +supported the IMAP2 (RFC 1176) and IMAP2bis (unpublished) protocols.
   24.26 +
   24.27 +     This version is a substantial rewrite of that document, and was
   24.28 +written by Mark Crispin with funding from Sun Microsystems, Incorporated.
   24.29 +Sun's generous support of this work is gratefully acknowledged.
   24.30 +
   24.31 +
   24.32 +				 Road Map
   24.33 +
   24.34 +     This document is organized into the following sections.  Except as
   24.35 +noted, an implementor of an application that uses c-client needs to be
   24.36 +familiar with all of these sections.  Someone who plans to write a new
   24.37 +mailbox driver for c-client (or otherwise modify it) needs to be familiar
   24.38 +with all sections, no exception.
   24.39 +
   24.40 +History
   24.41 +	History of how c-client came about.
   24.42 +
   24.43 +Overview
   24.44 +	Read this before designing an application that uses c-client.
   24.45 +
   24.46 +c-client Structures
   24.47 +	Documentation of several important c-client structs which are
   24.48 +	used in, and returned by, c-client calls.
   24.49 +
   24.50 +String Structures
   24.51 +	Documentation of the concept of a "string structure", which
   24.52 +	provides random access to strings without requiring that the
   24.53 +	string be in memory.
   24.54 +
   24.55 +c-client Support Functions
   24.56 +	Documentation of support functions for c-client; these deal
   24.57 +	with c-client functionality.
   24.58 +
   24.59 +	Only mail_parameters() is of interest to most application
   24.60 +	developers.  Advanced application developers, particularly
   24.61 +	for limited memory systems, may also need to know about the
   24.62 +	readfn_t, mailgets_t, mailcache_t, and tcptimeout_t function
   24.63 +	pointer types, and possibly also the mail_valid_net_parse()
   24.64 +	function.
   24.65 +
   24.66 +Mailbox Access Functions
   24.67 +	Documentation of functions which deal with mailboxes;
   24.68 +	listing, subscribing, creating, deleting, renaming, status
   24.69 +	inquiries, opening, and closing mailboxes.
   24.70 +
   24.71 +Handle Functions
   24.72 +	Documentation of mail stream handles, which provide protection
   24.73 +	for an advanced application which may have multiple pointers to
   24.74 +	a single mail stream.  If a stream has a handle on it, closing
   24.75 +	the stream does not release its memory, so pointers to it in
   24.76 +	the application remain valid.  Freeing the last handle will free
   24.77 +	the entire stream.
   24.78 +
   24.79 +	This is only of interest for advanced application developers.
   24.80 +
   24.81 +Message Data Fetching Functions
   24.82 +	Documentation on message data fetching in an open mailbox,
   24.83 +	including parsed representations of RFC-822 and MIME headers
   24.84 +	and message text.  Also how to fetch message attributes (flags,
   24.85 +	internal date, sizes).
   24.86 +
   24.87 +Message Status Manipulation Functions
   24.88 +	Documentation on altering message flags in an open mailbox.
   24.89 +
   24.90 +Mailbox Searching
   24.91 +	Documentation on searching an open mailbox for messages which
   24.92 +	match certain criteria (e.g. "messages sent July 4 from Jones
   24.93 +	with text `Paris'").
   24.94 +
   24.95 +Miscellaneous Mailbox and Message Functions
   24.96 +	Documentation on other operations that would be used by an
   24.97 +	application but that don't fit into any of the above categories.
   24.98 +
   24.99 +Date/Time Handling Functions
  24.100 +	Documentation on functions that deal with date/time strings.
  24.101 +
  24.102 +	This is only of interest for advanced application developers
  24.103 +	and for implementors of new c-client drivers.
  24.104 +
  24.105 +Utility Functions
  24.106 +	Documentation on internal utility functions.
  24.107 +
  24.108 +	This is primarily of interest for implementors of new c-client
  24.109 +	drivers, but advanced application developers may also use some
  24.110 +	of these functions.
  24.111 +
  24.112 +Data Structure Instantiation/Destruction functions
  24.113 +	Documentation on creating and destroy c-client structures.
  24.114 +
  24.115 +	This is primarily of interest for implementors of new c-client
  24.116 +	drivers.  However, application developers will need some of
  24.117 +	these functions to create and destroy structures which are used
  24.118 +	as arguments to various application functions.
  24.119 +
  24.120 +Authentication Functions
  24.121 +	Documentation on support for network protocol authentication
  24.122 +	functions.
  24.123 +
  24.124 +	This is only of interest for implementors of new c-client
  24.125 +	drivers which deal with authentication mechanisms.
  24.126 +
  24.127 +Network Access Functions
  24.128 +	Documentation on creating and destroy c-client structures.
  24.129 +
  24.130 +	This is primarily of interest for implementors of new c-client
  24.131 +	drivers which deal with a network.  However, advanced
  24.132 +	application developers may need to use this information if they
  24.133 +	wish to insert their own layer into a network session.
  24.134 +
  24.135 +Subscription Management Functions
  24.136 +	Documentation on managing the local (client-based) subscription
  24.137 +	database file.
  24.138 +
  24.139 +	This is primarily of interest to advanced application developers.
  24.140 +
  24.141 +Miscellaneous Utility Functions
  24.142 +	Documentation on various useful utility functions, such as "make
  24.143 +	a copy of this string."
  24.144 +
  24.145 +SMTP Functions
  24.146 +	Documentation on posting email messages via SMTP protocol.
  24.147 +
  24.148 +NNTP Functions
  24.149 +	Documentation on posting netnews messages via NNTP protocol.
  24.150 +
  24.151 +RFC 822 Support Functions
  24.152 +	Documentation on public RFC-822/MIME functions.
  24.153 +
  24.154 +	This is primarily of interest for implementors of new c-client
  24.155 +	drivers and advanced application developers.
  24.156 +
  24.157 +Operating System-Dependent Public Interface
  24.158 +	Documentation on OS-dependent functions.  With the exception of
  24.159 +	fs_get(), fs_give(), and fs_resize(), which should be called
  24.160 +	instead of malloc(), free(), and realloc(), these functions are
  24.161 +	primarily of interest for implementors of new c-client drivers.
  24.162 +
  24.163 +Main Program Callbacks
  24.164 +	Documentation of functions which the main program must provide
  24.165 +	as callbacks from c-client.
  24.166 +
  24.167 +Driver Interface
  24.168 +	Documentation of the driver dispatch vector and the functions
  24.169 +	which a driver must supply.
  24.170 +
  24.171 +	This is primarily of interest for implementors of new c-client
  24.172 +	drivers.
  24.173 +
  24.174 +Driver Support Functions
  24.175 +	Documentation of support functions which are called by drivers.
  24.176 +
  24.177 +	This is primarily of interest for implementors of new c-client
  24.178 +	drivers.
  24.179 +				  History
  24.180 +
  24.181 +     The c-client API was originally written by Mark Crispin at Stanford
  24.182 +University as a set of routines to support IMAP and SMTP from a main
  24.183 +program which would handle the user interface.  In its original form, it
  24.184 +was written as the low-level routines that were to be used as part of a
  24.185 +Macintosh client.
  24.186 +
  24.187 +     The first IMAP client, MM-D (for "MM on Xerox D machines" -- MM was a
  24.188 +popular DEC-20 mail program) was written in Interlisp for Xerox Lisp
  24.189 +machines.  At that time, there was no name for the embryonic Mac client,
  24.190 +but since it was the first one to be written in C instead of Lisp, it was
  24.191 +given a development name of "C client".  This name became "c-client"
  24.192 +because that is the name of the subdirectory on UNIX where the source files
  24.193 +were stored.
  24.194 +
  24.195 +     To exercise the routines, a minimal main program which uses c-client,
  24.196 +mtest, was written.  mtest has subsequently been extended so that it runs
  24.197 +on every platform that c-client is ported.
  24.198 +
  24.199 +     The real Mac client, was eventually written by Frank Gilmurrary and
  24.200 +Bill Yeager at Stanford using the autumn 1988 version of c-client and named
  24.201 +"MacMS".  In the winter of 1988-89, Mark Crispin, who had changed jobs to
  24.202 +the University of Washington, developed MS as an MM-like text-based program
  24.203 +for UNIX and MailManager as a GUI-based program for NeXT machines.
  24.204 +
  24.205 +     The realization sunk in that this API needed its own name.  As early
  24.206 +as spring 1989, there were at least four programs (mtest, MS, MailManager,
  24.207 +and MacMS) that used it.  The name c-client thus became permanent.
  24.208 +
  24.209 +     In its history, c-client has undergone two major redesigns, both by
  24.210 +Mark Crispin who is now on the staff at the University of Washington.
  24.211 +
  24.212 +     The first major redesign added the following:
  24.213 +	1) ANSI C calling conventions throughout to assist in function
  24.214 +	   argument type checking.
  24.215 +	2) Vectoring mail access calls through "driver" methods; thus
  24.216 +	   providing transparent access to multiple types of mail
  24.217 +	   stores with the same call.
  24.218 +	3) MIME support.
  24.219 +
  24.220 +     The second major redesign was part of the IMAP4 project.  Many
  24.221 +c-client functions were extended with additional arguments and options.
  24.222 +The driver interface was also made simpler, with more work done by
  24.223 +driver-independent code.
  24.224 +
  24.225 +			       Overview
  24.226 +
  24.227 +     The most important file for the author of an application using the
  24.228 +c-client is mail.h.  mail.h defines several important structures of
  24.229 +data which are passed between the main program and the c-client.
  24.230 +Although some functions (e.g. mail_fetchtext_body()) return the data
  24.231 +fetched, for certain other data items (e.g. flags) you need to get the
  24.232 +data as a structure reference.  mail.h also defines a large number of
  24.233 +useful constants and structures.
  24.234 +
  24.235 +     When a function in mail.h exists to reference data, it MUST be
  24.236 +used instead of referencing the structures directly.  This is because
  24.237 +in some cases the data is not actually fetched until a reference (via
  24.238 +the function call) is made.  For example, although the MESSAGECACHE
  24.239 +element for a message can be obtained by indexing the proper cache
  24.240 +element in the stream, there is no guarantee that the item in fact
  24.241 +exists unless mail_fetchstructure_full() is called for that message.
  24.242 +Less costly functions. also exist to create and load a MESSAGECACHE
  24.243 +element.
  24.244 +
  24.245 +     The main program will probably also need to include smtp.h,
  24.246 +misc.h, and osdep.h, but this usage should be solely to receive
  24.247 +function prototypes.  Any other definitions in those files should be
  24.248 +considered private to that module.
  24.249 +
  24.250 +     Two important predefined symbols are NIL and T.  NIL is any sort
  24.251 +of "false"; T is any sort of "true".  NIL is also used to null-specify
  24.252 +certain optional arguments.
  24.253 +
  24.254 +			* * * IMPORTANT * * *
  24.255 +
  24.256 +     Any multi-threaded application should test stream->lock prior to
  24.257 +calling any c-client stream functions.  Any attempt to call a
  24.258 +mail_xxx() function while one is already in progress on the same
  24.259 +stream will cause the application to fail in unpredictable ways.
  24.260 +
  24.261 +     Note that this check is insufficient in a preemptive-scheduling
  24.262 +multi-tasking application due to the possibility of a timing race.
  24.263 +Such applications must be written so that only one process accesses
  24.264 +the stream, or to have a higher level lock.
  24.265 +
  24.266 +     Since MAIL operations will not finish until they are completed, a
  24.267 +single-tasking application does not have to worry about this problem,
  24.268 +except in the callback invoked from MAIL (e.g. mm_exists(), etc.) in which
  24.269 +case the stream is *always* locked.
  24.270 +
  24.271 +			  c-client Structures
  24.272 +
  24.273 +     c-client has a large number of structures which are used for
  24.274 +multiple functions.  The most important of these are described here.
  24.275 +
  24.276 +     The MAILSTREAM structure is used to reference open mailboxes.
  24.277 +Applications may reference the following:
  24.278 +
  24.279 +char *mailbox;			mailbox name
  24.280 +unsigned short use;		stream use count, this is incremented
  24.281 +unsigned short sequence;	stream sequence, this is incremented
  24.282 +				 each time a stream is reused (i.e.
  24.283 +				 mail_open() is called to open a
  24.284 +				 different mailbox on this stream)
  24.285 +unsigned int rdonly : 1;	stream is open read-only
  24.286 +unsigned int anonymous : 1;	stream is open with anonymous access
  24.287 +unsigned int halfopen : 1;	stream is half-open; it can be
  24.288 +				 reopened or used for functions that
  24.289 +				 don't need a open mailbox such as
  24.290 +				 mail_create() but no message data
  24.291 +				 can be fetched
  24.292 +unsigned int perm_seen : 1;	Seen flag can be set permanently
  24.293 +unsigned int perm_deleted : 1;	Deleted flag can be set permanently
  24.294 +unsigned int perm_flagged : 1;	Flagged flag can be set permanently
  24.295 +unsigned int perm_answered :1;	Answered flag can be set permanently
  24.296 +unsigned int perm_draft : 1;	Draft flag can be set permanently
  24.297 +unsigned int kwd_create : 1;	new user flags can be created by
  24.298 +				 referencing then in mail_setflag() or
  24.299 +				 mail_clearflag().  Note: this can
  24.300 +				 change during a session (e.g. if
  24.301 +				 there is a limit on the number of
  24.302 +				 keywords), so check after creating a
  24.303 +				 new flag to see if any more can be
  24.304 +				 created before letting the user try
  24.305 +				 to do so
  24.306 +unsigned long perm_user_flags;	corresponding user flags can be set
  24.307 +				 permanently.  This is a bit mask
  24.308 +				 which matches the entries in
  24.309 +				 stream->user_flags[]
  24.310 +unsigned long gensym;		generated unique value.  Always
  24.311 +				 referenced with stream->gensys++
  24.312 +unsigned long nmsgs;		number of messages in current mailbox
  24.313 +unsigned long recent;		number of recent messages in current
  24.314 +				 mailbox
  24.315 +unsigned long uid_validity;	UID validity value; this is used to
  24.316 +				 verify that recorded UIDs match the
  24.317 +				 UIDs that the stream has.  If the
  24.318 +				 mailbox does not have matching UIDs
  24.319 +				 (e.g. the UIDs were lost or not
  24.320 +				 recorded) then the UID validity value
  24.321 +				 will be different
  24.322 +unsigned long uid_last;		highest currently assigned UID in the
  24.323 +				 current mailbox; a new UID will be
  24.324 +				 assigned with ++stream->uid_last
  24.325 +char *user_flags[NUSERFLAGS];	pointers to user flag names in bit
  24.326 +				 order from stream->perm_user_flags or
  24.327 +				 elt->user_flags
  24.328 +
  24.329 +     The following MAILSTREAM values are only used internally:
  24.330 +
  24.331 +DRIVER *dtb;			dispatch table for this driver
  24.332 +void *local;			pointer to driver local data
  24.333 +unsigned int lock : 1;		stream lock flag (an operation is in
  24.334 +				 progress; used as a bug trap to
  24.335 +				 detect recursion back to c-client
  24.336 +				 from callback routines).
  24.337 +unsigned int debug : 1;		debugging information should be logged
  24.338 +				 via mm_dlog().
  24.339 +unsigned int silent : 1;	don't do main program callbacks on
  24.340 +				 this stream (used when a stream is
  24.341 +				 opened internally)
  24.342 +unsigned int scache : 1;	short caching; don't cache information
  24.343 +				 in memory
  24.344 +
  24.345 +     The following MAILSTREAM values are only used by the cache
  24.346 +manager routine (see the documentation about mailcache_t above):
  24.347 +
  24.348 +unsigned long cachesize;	size of c-client message cache
  24.349 +union {
  24.350 +  void **c;			to get at the cache in general
  24.351 +  MESSAGECACHE **s;		message cache array
  24.352 +  LONGCACHE **l;		long cache array
  24.353 +} cache;
  24.354 +
  24.355 +     The following MAILSTREAM values are for the convenience of
  24.356 +drivers that use short caching and want to be able to garbage collect
  24.357 +any values that they returned:
  24.358 +
  24.359 +unsigned long msgno;		message number of `current' message
  24.360 +ENVELOPE *env;			pointer to `current' message envelope
  24.361 +BODY *body;			pointer to `current' message body
  24.362 +char *text;			pointer to `current' text
  24.363 +
  24.364 +
  24.365 +     The MESSAGECACHE structure (commonly called an "elt" as a
  24.366 +nickname for "cache ELemenT") contains information about messages.
  24.367 +Applications may use the following:
  24.368 +
  24.369 +unsigned long msgno;		message number.  If the elt is locked
  24.370 +				 (by elt->lockcount++), then the elt
  24.371 +				 pointer can be stored (e.g. with the
  24.372 +				 data for a window which draws this
  24.373 +				 message) and elt->msgno will change
  24.374 +				 automatically whenever expunges are
  24.375 +				 done so the window will always view
  24.376 +				 the correct message.  If elt->msgno
  24.377 +				 becomes 0, then the message has been
  24.378 +				 expunged, but the elt won't be freed
  24.379 +				 until the elt lock count is
  24.380 +				 decremented (by mail_free_elt()).
  24.381 +unsigned long uid;		message unique ID
  24.382 +unsigned int hours: 5;		internal date hours (0-23)
  24.383 +unsigned int minutes: 6;	internal date minutes (0-59)
  24.384 +unsigned int seconds: 6;	internal date seconds (0-59)
  24.385 +unsigned int zoccident : 1;	non-zero if internal date time zone is
  24.386 +				 west of UTC
  24.387 +unsigned int zhours : 4;	internal date time zone hours from UTC
  24.388 +				 (0-12)
  24.389 +unsigned int zminutes: 6;	internal date time zone minutes (0-59)
  24.390 +unsigned int seen : 1;		message Seen flag
  24.391 +unsigned int deleted : 1;	message Deleted flag
  24.392 +unsigned int flagged : 1; 	message Flagged flag
  24.393 +unsigned int answered : 1;	message Answered glag
  24.394 +unsigned int draft : 1;		message Draft flag
  24.395 +unsigned int valid : 1;		flags are valid in this elt; an elt
  24.396 +				 that was newly created but never
  24.397 +				 loaded with flags won't have this set.
  24.398 +unsigned int recent : 1;	message recent flag
  24.399 +unsigned int searched : 1;	message matches search criteria in
  24.400 +				 most recent mail_search_full() call
  24.401 +unsigned int spare : 1;		reserved for application use
  24.402 +unsigned int spare2 : 1;	reserved for application use
  24.403 +unsigned int spare3 : 1;	reserved for application use
  24.404 +unsigned int lockcount : 8;	non-zero if multiple references to
  24.405 +				 this elt.  Refer to the msgno member
  24.406 +				 for more information.
  24.407 +unsigned int day : 5;		internal date day of month (1-31)
  24.408 +unsigned int month : 4;		internal date month of year (1-12)
  24.409 +unsigned int year : 7;		internal date year since BASEYEAR
  24.410 +				 (currently 1970; was 1969 in older
  24.411 +				 versions so use BASEYEAR instead of
  24.412 +				 having the base year wired in)
  24.413 +unsigned long user_flags;	message user flags; this is a bit mask
  24.414 +				 which matches the entries in
  24.415 +				 stream->user_flags[]
  24.416 +unsigned long rfc822_size;	size of message in octets
  24.417 +
  24.418 +     The following MESSAGECACHE values are only used internally by
  24.419 +drivers:
  24.420 +
  24.421 +unsigned int sequence : 1;	message is in sequence from either
  24.422 +				 mail_sequence() or mail_uid_sequence()
  24.423 +unsigned long data1;		first data item
  24.424 +unsigned long data2;		second data item
  24.425 +unsigned long data3;		third data item
  24.426 +unsigned long data4;		fourth data item
  24.427 +
  24.428 +
  24.429 +     The ADDRESS structure is a parsed form of a linked list of RFC 822
  24.430 +addresses.  It contains the following information:
  24.431 +
  24.432 +char *personal;			personal name phrase
  24.433 +char *adl;			at-domain-list (also called "source
  24.434 +				 route")
  24.435 +char *mailbox;			mailbox name
  24.436 +char *host;			domain name of mailbox's host
  24.437 +char *error;			error in address from smtp_mail(); if
  24.438 +				 an error is returned from smtp_mail()
  24.439 +				 for one of the recipient addresses
  24.440 +				 the SMTP server's error text for that
  24.441 +				 recipient can be found here.  If it
  24.442 +				 is null then there was no error (or
  24.443 +				 an error was found with a prior
  24.444 +				 recipient
  24.445 +ADDRESS *next;			pointer to next address in list
  24.446 +
  24.447 +
  24.448 +     The ENVELOPE structure is a parsed form of the RFC 822 header.
  24.449 +Its member names correspond to the RFC 822 field names.  It contains
  24.450 +the following information:
  24.451 +
  24.452 +char *remail;			remail header if any
  24.453 +ADDRESS *return_path;		error return address
  24.454 +char *date;			message composition date string
  24.455 +ADDRESS *from;			from address list
  24.456 +ADDRESS *sender;		sender address list
  24.457 +ADDRESS *reply_to;		reply address list
  24.458 +char *subject;			message subject string
  24.459 +ADDRESS *to;			primary recipient list
  24.460 +ADDRESS *cc;			secondary recipient list
  24.461 +ADDRESS *bcc;			blind secondary recipient list
  24.462 +char *in_reply_to;		replied message ID
  24.463 +char *message_id;		message ID
  24.464 +char *newsgroups;		USENET newsgroups
  24.465 +char *followup_to;		USENET reply newsgroups
  24.466 +char *references;		USENET references
  24.467 +
  24.468 +
  24.469 +     The BODY structure is a parsed form of a linked list of the MIME
  24.470 +structure of a message.  It contains the following information.
  24.471 +
  24.472 +unsigned short type;		body primary type code.  This is an
  24.473 +				 index into the body_types vector of
  24.474 +				 body type names.  The following body
  24.475 +				 types are pre-defined:
  24.476 +	TYPETEXT		unformatted text
  24.477 +	TYPEMULTIPART		multiple part
  24.478 +	TYPEMESSAGE		encapsulated message
  24.479 +	TYPEAPPLICATION		application data
  24.480 +	TYPEAUDIO		audio
  24.481 +	TYPEIMAGE		static image (GIF, JPEG, etc.)
  24.482 +	TYPEVIDEO		video
  24.483 +	TYPEOTHER		unknown
  24.484 +				Additional types up to TYPEMAX are
  24.485 +				 dynamically defined if they are
  24.486 +				 encountered by c-client.
  24.487 +unsigned short encoding;	body transfer encoding.  This is an
  24.488 +				 index into the body_encodings vector
  24.489 +				 of body encoding names.  The
  24.490 +				 following body encodings are
  24.491 +				 pre-defined:
  24.492 +	ENC7BIT			7 bit SMTP semantic data
  24.493 +	ENC8BIT			8 bit SMTP semantic data
  24.494 +	ENCBINARY		8 bit binary data
  24.495 +	ENCBASE64		base-64 encoded data
  24.496 +	ENCQUOTEDPRINTABLE	human-readable 8-as-7 bit data
  24.497 +	ENCOTHER		unknown
  24.498 +				Additional encodings up to ENCMAX are
  24.499 +				 dynamically defined if they are
  24.500 +				 encountered by c-client.
  24.501 +char *subtype;			body subtype string
  24.502 +PARAMETER *parameter;		parameter list
  24.503 +char *id;			body content identifier
  24.504 +char *description;		body content description
  24.505 +unsigned char *contents.text;	when composing a message that is NOT
  24.506 +				 of TYPEMULTIPART, non-binary text of
  24.507 +				 the content is stored here.  Note that
  24.508 +				 this happens even when the text is
  24.509 +				 of TYPEMESSAGE.  Text of encoding
  24.510 +				 ENC8BIT may be converted to
  24.511 +				 ENCQUOTEDPRINTABLE when it is sent.
  24.512 +				 This should not be referenced for any
  24.513 +				 other reason; in particular, this is
  24.514 +				 NOT the way for an application to
  24.515 +				 access content data (use
  24.516 +				 mail_fetchbody_full() instead).
  24.517 +BINARY *contents.binary;	when composing a message that is NOT
  24.518 +				 of TYPEMULTIPART, binary content (of
  24.519 +				 encoding ENCBINARY) is stored here.
  24.520 +				 It will be converted to ENCBASE64 when
  24.521 +				 it is sent.
  24.522 +				 This should not be referenced for any
  24.523 +				 other reason; in particular, this is
  24.524 +				 NOT the way for an application to
  24.525 +				 access content data (use
  24.526 +				 mail_fetchbody_full() instead).
  24.527 +PART *contents.part;		for body parts of TYPEMULTIPART, this
  24.528 +				 contains the list of body parts in
  24.529 +				 this multipart
  24.530 +MESSAGE contents.msg;		for body parts of TYPEMESSAGE with
  24.531 +				 subtype "RFC822", this contains the
  24.532 +				 encapsulated message
  24.533 +unsigned long size.lines;	size in lines
  24.534 +unsigned long size.bytes;	size in octets.  This MUST be set when
  24.535 +				composing a message if the encoding is
  24.536 +				ENC8BIT or ENCBINARY.
  24.537 +char *md5;			body content MD5 checksum
  24.538 +
  24.539 +     The following BODY information is used only by c-client
  24.540 +internally.  The use of this data is driver-specific and it can not be
  24.541 +relied-upon by applications.
  24.542 +
  24.543 +unsigned char *contents.text;	drivers can store a pointer to the
  24.544 +				 body contents as text here.		
  24.545 +unsigned long size.ibytes;	internal size of the body content (prior
  24.546 +				 to newline conversion, etc.) in octets
  24.547 +
  24.548 +
  24.549 +     The MESSAGE structure is a parsed form of a MESSAGE/RFC822 MIME
  24.550 +body part.  It contains the following information:
  24.551 +
  24.552 +ENVELOPE *env;			encapsulated message RFC 822 header
  24.553 +BODY *body;			encapsulated message MIME structure
  24.554 +
  24.555 +     The following MESSAGE information is used only by c-client
  24.556 +internally.  The use of this data is driver-specific and it can not be
  24.557 +relied-upon by applications.
  24.558 +
  24.559 +char *hdr;			encapsulated message header
  24.560 +unsigned long hdrsize;		message header size
  24.561 +char *text;			message in RFC 822 form
  24.562 +unsigned long offset;		offset of text from header
  24.563 +
  24.564 +
  24.565 +     The PARAMETER structure is a parsed form of a linked list of
  24.566 +attribute/value pairs.  It contains the following information:
  24.567 +
  24.568 +char *attribute;		attribute name
  24.569 +char *value;			value
  24.570 +PARAMETER *next;		next parameter in list
  24.571 +
  24.572 +
  24.573 +     The PART structure is a parsed form of a linked list of MIME body
  24.574 +parts.  It contains the following information:
  24.575 +
  24.576 +BODY body;			body information for this part
  24.577 +PART *next;			next body part
  24.578 +
  24.579 +     The following PART information is used only by c-client
  24.580 +internally.  The use of this data is driver-specific and it can not be
  24.581 +relied-upon by applications.
  24.582 +
  24.583 +unsigned long offset;		offset from body origin
  24.584 +
  24.585 +
  24.586 +    The NETMBX structure is a parsed form of a network mailbox name:
  24.587 +
  24.588 +char host[NETMAXHOST];		remote host name
  24.589 +char user[NETMAXUSER];		remote user name if specified
  24.590 +char mailbox[NETMAXMBX];	remote mailbox name
  24.591 +char service[NETMAXSRV];	remote service name (IMAP4, NNTP, etc.)
  24.592 +unsigned long port;		TCP/IP port number if specified
  24.593 +unsigned int anoflag : 1;	anonymous access requested
  24.594 +unsigned int dbgflag : 1;	protocol debugging telemetry, via
  24.595 +				 mm_dlog(), requested
  24.596 +
  24.597 +
  24.598 +     The STRINGLIST structure is a list of strings (which may have
  24.599 +embedded NULs) and their lengths:
  24.600 +
  24.601 +char *text;			string text
  24.602 +unsigned long size;		string length
  24.603 +STRINGLIST *next;		next string in list
  24.604 +
  24.605 +			  String Structures
  24.606 +
  24.607 +     A string structure is analogous to a char*, and is used in some
  24.608 +functions as an input argument.  It represents a string of data in a
  24.609 +way that does not necessarily require the entire string to be in
  24.610 +memory at once.  This is essential for small machines with
  24.611 +highly-restricted memory limits (e.g. DOS).
  24.612 +
  24.613 +		       String Structure Access
  24.614 +
  24.615 +     To use a string structure, the caller needs to know a string
  24.616 +driver and needs to know the driver-dependent data used by that string
  24.617 +structure.  A simple string driver is mail_string, a string driver
  24.618 +that takes an in-memory char* string as the driver-dependent data.
  24.619 +The DOS port uses string drivers that take a struct holding a file
  24.620 +descriptor and a file offset.  Often the user of a string driver is
  24.621 +the same module that defined it, so usually the programmer knows about
  24.622 +its conventions.
  24.623 +
  24.624 +     The following calls are used to access a string structure:
  24.625 +
  24.626 +void INIT (STRING *s,STRINGDRIVER *d,void *data,unsigned long size);
  24.627 +	s	pointer to the string structure to be initialized
  24.628 +	d	pointer to the string driver
  24.629 +	data	pointer to driver-dependent data, from which the
  24.630 +		 driver can determine string data
  24.631 +	size	size of the string
  24.632 + This call initializes the string stucture.
  24.633 +
  24.634 +
  24.635 +unsigned long SIZE (STRING *s);
  24.636 +	s	pointer to the string structure
  24.637 + This call returns the number of characters remaining in the string
  24.638 +after the current string character pointer.
  24.639 +
  24.640 +
  24.641 +char CHR (STRING *s);
  24.642 +	s	pointer to the string structure
  24.643 + This call returns the character at the current string character
  24.644 +pointer.
  24.645 +
  24.646 +
  24.647 +char SNX (STRING *s);
  24.648 +	s	pointer to the string structure
  24.649 + This call returns the character at the current string character
  24.650 +pointer, and increments the string character pointer.
  24.651 +
  24.652 +
  24.653 +unsigned long GETPOS (STRING *s);
  24.654 +	s	pointer to the string structure
  24.655 + This returns the value of the current string character pointer.
  24.656 +
  24.657 +
  24.658 +void SETPOS (STRING *s,unsigned long i);
  24.659 +	s	pointer to the string structure
  24.660 +	i	new string pointer value
  24.661 + This method sets the string character pointer to the given value.
  24.662 +
  24.663 +
  24.664 +		      String Structure Internals
  24.665 +
  24.666 +     A string structure holds the following data:
  24.667 +
  24.668 +void *data;		used by the string driver as it likes
  24.669 +unsigned long data1;	used by the string driver as it likes
  24.670 +unsigned long size;	static, holds the total length of the string
  24.671 +			 from the INIT call
  24.672 +char *chunk;		current chunk of in-memory data; this is used
  24.673 +			 for buffering to avoid unnecessary calls to
  24.674 +			 the string driver's next method.
  24.675 +unsigned long chunksize; size of an in-memory data chunk
  24.676 +unsigned long offset;	position of first character of the chunk in
  24.677 +			 the overall string
  24.678 +char *curpos;		current position; this is what CHR() will
  24.679 +			 access
  24.680 +unsigned long cursize;	number of characters remaining in the current
  24.681 +			 string
  24.682 +STRINGDRIVER *dtb;	the string driver for this string structure
  24.683 +
  24.684 +
  24.685 +     A string structure is manipulated by a string driver, which has
  24.686 +the following access methods:
  24.687 +
  24.688 +void (*init) (STRING *s,void *data,unsigned long size);
  24.689 +	s	pointer to the string structure to be initialized
  24.690 +	data	pointer to driver-dependent data, from which the
  24.691 +		 driver can determine string data
  24.692 +	size	size of the string
  24.693 + This method initializes the string stucture.  It can use the data,
  24.694 +data1, and chunksize values as it likes.  The remaining values must be
  24.695 +set up as follows:
  24.696 +	size		static, copied from the size argument
  24.697 +	chunk		pointer to a buffer loaded with initial data
  24.698 +	chunksize	size of the buffer
  24.699 +	offset		0
  24.700 +	curpos		copied from chunk
  24.701 +	cursize		copied from chunksize
  24.702 +	dtb		STRINGDRIVER identity pointer
  24.703 +
  24.704 +
  24.705 +char (*next) (STRING *s);
  24.706 +	s	pointer to the string structure
  24.707 + This method returns the character at the current string character
  24.708 +pointer, and increments the string character pointer.  This method
  24.709 +is likely to call the setpos method if the desired character is not in
  24.710 +the current chunk.
  24.711 +
  24.712 +
  24.713 +void (*setpos) (STRING *s,unsigned long i);
  24.714 +	s	pointer to the string structure
  24.715 +	i	new string pointer value
  24.716 + This method sets the string character pointer to the given value.  If
  24.717 +the pointer is not in the current chunk, then a new chunk is loaded
  24.718 +and the associated values (chunk, offset, curpos, cursize) are
  24.719 +adjusted accordingly.
  24.720 +
  24.721 +		      c-client Support Functions
  24.722 +
  24.723 +
  24.724 +void mail_string_init (STRING *s,void *data,unsigned long size);
  24.725 +char mail_string_next (STRING *s);
  24.726 +void mail_string_setpos (STRING *s,unsigned long i);
  24.727 +
  24.728 +     These three functions are the init, next, and setpos string
  24.729 +structure access methods for the build-in mail_string string driver.
  24.730 +mail_string is a basic string driver for a char* string.  See the
  24.731 +documentation below on "String Structures" for more information.
  24.732 +
  24.733 +
  24.734 +void mail_link (DRIVER *driver);
  24.735 +	driver	pointer to the driver to be added
  24.736 +
  24.737 +     This function adds the specified driver to the list of mailbox
  24.738 +drivers.  Initially there are no drivers lunk, so all programs which
  24.739 +intend to use c-client need to have at least one call to this function.
  24.740 +
  24.741 +     A function which uses IMAP4 would have a statement such as:
  24.742 +	mail_link (&imapdriver);	/* link in IMAP driver */
  24.743 +early in the program's initialization.  Normally, this is done by the
  24.744 +statement
  24.745 +	#include "linkage.c"
  24.746 +which will include the "system standard driver linkage" defined when
  24.747 +c-client was built.  By using linkage.c instead of explicit mail_link()
  24.748 +calls, you are guaranteed that you will have a consistant linkage among
  24.749 +all software built on this system.
  24.750 +
  24.751 +
  24.752 +void auth_link (AUTHENTICATOR *auth);
  24.753 +	auth	pointer to the authenticator to be added
  24.754 +
  24.755 +     This function adds the specified authenticator to the list of
  24.756 +authenticators.  Initially there are no authenticators lunk.  Normally,
  24.757 +this is done by linkage.c so you don't need to call this routine
  24.758 +explicitly.
  24.759 +
  24.760 +
  24.761 +void *mail_parameters (MAILSTREAM *stream,long function,void *value);
  24.762 +	stream	stream to poll or NIL
  24.763 +	function function code
  24.764 +	value	new value for function codes that change a parameter
  24.765 +
  24.766 +     This function fetches or changes the settings of various c-client
  24.767 +operational parameters depending upon the function.  If the stream is
  24.768 +specified, only the action for the underlying driver for that stream is
  24.769 +taken; however, the scope of the operational parameters is global so
  24.770 +there is generally no reason for the stream argument ever to be
  24.771 +non-NIL.
  24.772 +
  24.773 +     The function codes ENABLE_DRIVER and DISABLE_DRIVER take a driver
  24.774 +pointer as a value.  These functions enable and disable mailbox
  24.775 +processing by that driver.  By default, all drivers are enabled.
  24.776 +
  24.777 +     The remaining function codes are in a pair named GET_xxx to
  24.778 +fetch an operational parameter and SET_xxx to set the parameter:
  24.779 +
  24.780 + GET_DRIVERS / SET_DRIVERS
  24.781 +	 The list of currently lunk drivers.
  24.782 +
  24.783 + GET_GETS / SET_GETS
  24.784 +	 If non-NIL, points to a function for reading message text.
  24.785 +	Defaults to NIL.
  24.786 +	 This function is called with three arguments; a function
  24.787 +	pointer to a "reading function", a stream for the reading
  24.788 +	function, and a size in octets.  The reading function is
  24.789 +	in turn called with the stream, a size in octets, and a
  24.790 +	pointer to a readin buffer.
  24.791 +	 This function returns with a char* string, which will be
  24.792 +	returned by the mail_fetchheader(), mail_fetchtext(), or
  24.793 +	mail_fetchbody() function which triggered the message text
  24.794 +	reading.
  24.795 +	 The purpose is to permit reading of large strings, without
  24.796 +	requiring an in-memory buffer for the entire string.  The idea
  24.797 +	is that this function can store the data in some form other
  24.798 +	than a char* (e.g. a temporary file) and the main program will
  24.799 +	recognize that it should get the text from there instead of
  24.800 +	from the results from mail_fetch....().
  24.801 +	 This is only supported on DOS and Win16; on other platforms it
  24.802 +	is inconsistent whether or not it works.
  24.803 +
  24.804 + GET_CACHE / SET_CACHE
  24.805 +	 Points to the c-client cache manager function.  Defaults to
  24.806 +	mm_cache().
  24.807 +
  24.808 + GET_SMTPVERBOSE / SET_SMTPVERBOSE
  24.809 +	 If non-NIL, points to a function that accepts a char* string.
  24.810 +	This function is called any time the SMTP routines receive a
  24.811 +	response code less than 100.  The argument is the text of the
  24.812 +	response code
  24.813 +
  24.814 + GET_RFC822OUTPUT / SET_RFC822OUTPUT
  24.815 +	 If non-NIL, points to an alternate rfc822_output() function.
  24.816 +	rfc822_output() will call this function and return instead of
  24.817 +	doing its normal action.  See the description of
  24.818 +	rfc822_output() for more information.	
  24.819 +
  24.820 + GET_USERNAME / SET_USERNAME
  24.821 +	 The logged-in user name.
  24.822 +
  24.823 + GET_HOMEDIR / SET_HOMEDIR
  24.824 +	 The home directory path name.
  24.825 +
  24.826 + GET_LOCALHOST / SET_LOCALHOST
  24.827 +	 The local host name.
  24.828 +
  24.829 + GET_SYSINBOX / SET_SYSINBOX
  24.830 +	 The "system INBOX" (where mail is delivered) path name.
  24.831 +
  24.832 + GET_OPENTIMEOUT / SET_OPENTIMEOUT
  24.833 +	 TCP/IP open timeout in seconds.  Defaults to 0 (system
  24.834 +	default timeout, usually 75 seconds on Unix).
  24.835 +	
  24.836 + GET_READTIMEOUT / SET_READTIMEOUT
  24.837 +	 TCP/IP read timeout in seconds.  Defaults to 0 (no timeout).
  24.838 +
  24.839 + GET_WRITETIMEOUT / SET_WRITETIMEOUT
  24.840 +	 TCP/IP write timeout in seconds.  Defaults to 0 (no timeout).
  24.841 +
  24.842 + GET_CLOSETIMEOUT / SET_CLOSETIMEOUT
  24.843 +	 TCP/IP close timeout in seconds.  Defaults to 0 (no timeout).
  24.844 +
  24.845 + GET_TIMEOUT / SET_TIMEOUT
  24.846 +	 If non-NIL, points to the function called when a TCP/IP
  24.847 +	timeout occurs.  This function is called with the number of
  24.848 +	seconds since the start of the TCP operation.  If it returns
  24.849 +	non-zero, the TCP/IP operation is continued; if it returns
  24.850 +	non-zero, the TCP/IP connection is aborted.
  24.851 +
  24.852 + GET_RSHTIMEOUT / SET_RSHTIMEOUT
  24.853 +	 rsh connection timeout in seconds.  Defaults to 15 seconds.
  24.854 +
  24.855 + GET_MAXLOGINTRIALS / SET_MAXLOGINTRIALS
  24.856 +	 The maximum number of login attempts permitted in an IMAP or
  24.857 +	POP connection.  Defaults to 3.
  24.858 +
  24.859 + GET_LOOKAHEAD / SET_LOOKAHEAD
  24.860 +	 The number of subsequent envelopes prefetched in IMAP when an
  24.861 +	envelope is fetched.  Defaults to 20.
  24.862 +
  24.863 + GET_IMAPPORT / SET_IMAPPORT
  24.864 +	 The IMAP port number.  Defaults to 143.
  24.865 +
  24.866 + GET_PREFETCH / SET_PREFETCH
  24.867 +	 The number of envelopes prefetched in IMAP from the results
  24.868 +	of a SEARCH.  Defaults to 20.
  24.869 +
  24.870 + GET_CLOSEONERROR / SET_CLOSEONERROR
  24.871 +	 If non-NIL, close an opening IMAP connection if the SELECT
  24.872 +	command fails instead of returning a half-open stream.
  24.873 +	Defaults to NIL.
  24.874 +
  24.875 + GET_POP3PORT / SET_POP3PORT
  24.876 +	 The POP3 port number.  Defaults to 110.
  24.877 +
  24.878 + GET_UIDLOOKAHEAD / SET_UIDLOOKAHEAD
  24.879 +	 The number of UIDs premapped when a message number is
  24.880 +	translated to a UID.  Defaults to 1000.
  24.881 +
  24.882 + GET_MBXPROTECTION / SET_MBXPROTECTION
  24.883 +	 Default file protection for newly created mailboxes.
  24.884 +	Defaults to 0600.
  24.885 +
  24.886 + GET_DIRPROTECTION / SET_DIRPROTECTION
  24.887 +	 Default file protection for newly created directories.
  24.888 +	Defaults to 0700.
  24.889 +
  24.890 + GET_LOCKPROTECTION / SET_LOCKPROTECTION
  24.891 +	 Default file protection for locks.  Defaults to 0666.
  24.892 +	WARNING: don't blithely change this.  If other processes
  24.893 +	can't get access to a lock then they will have trouble in
  24.894 +	locking properly.
  24.895 +
  24.896 + GET_FROMWIDGET / SET_FROMWIDGET
  24.897 +	 If non-NIL, APPEND in the Unix mbox format will insert a
  24.898 +	">" character in front of all lines which begin with the
  24.899 +	string "From ".  If NIL, it will only do so if the entire
  24.900 +	line looks like a message delimiter (that is, the date is
  24.901 +	also in correct format).  Defaults to T.
  24.902 +
  24.903 + GET_NEWSACTIVE / SET_NEWSACTIVE
  24.904 +	 Netnews active file path name.
  24.905 +
  24.906 + GET_NEWSSPOOL / SET_NEWSSPOOL
  24.907 +	 Netnews spool directory path name.
  24.908 +
  24.909 + GET_NEWSRC / SET_NEWSRC
  24.910 +	 Netnews newsgroup reading status file (.newsrc) path name.
  24.911 +
  24.912 + GET_EXTENSION / SET_EXTENSION
  24.913 +	 If non-NIL, points to a string holding the extension for all
  24.914 +	mailbox files.  This is only supported on DOS and Win16.
  24.915 +
  24.916 + GET_DISABLEFCNTLLOCK / SET_DISABLEFCNTLLOCK
  24.917 +	 If non-NIL, disables fcntl() locking on SVR4.  This is done
  24.918 +	if fcntl() tends to hang for no good reason.  Now that the
  24.919 +	fcntl() code checks for NFS files and no-ops the locking,
  24.920 +	this problem usually doesn't happen much any more.  Defaults
  24.921 +	to NIL.
  24.922 +
  24.923 + GET_LOCKEACCESERROR / SET_LOCKEACCESERROR
  24.924 +	 If non-NIL, give a warning if an attempt to create a .lock
  24.925 +	file gets an EACCES ("Permission denied") error.  This usually
  24.926 +	means that somebody protected the system inbox directory (e.g.
  24.927 +	/var/mail) instead of making it public-write with the sticky
  24.928 +	bit.  Defaults to non-NIL, since this is usually bad news.
  24.929 +
  24.930 + GET_LISTMAXLEVEL / SET_LISTMAXLEVEL
  24.931 +	 The maximum depth of recusion that LIST will go on a *
  24.932 +	wildcard.  Defaults to 20.
  24.933 +
  24.934 + GET_ANONYMOUSHOME / SET_ANONYMOUSHOME
  24.935 +	 The anonymous use home directory name.
  24.936 +
  24.937 +
  24.938 +typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer);
  24.939 +	stream	a designator suitable
  24.940 +	size	a number of octets to read
  24.941 +	buffer	a buffer of at least size octets for readin
  24.942 +
  24.943 +     This function reads the given number of octets into the buffer,
  24.944 +using the given stream.  What sort of object the stream is depends upon
  24.945 +the function and its caller, so you must make sure that the readfn is
  24.946 +suitable for the caller's purpose.  Common uses include support of the
  24.947 +mailgets function (see below) and of reading from local files on systems
  24.948 +with limited address space.
  24.949 +
  24.950 +
  24.951 +typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size);
  24.952 +	f	the readfn to use
  24.953 +	stream	stream argument for the readfn
  24.954 +	size	total number of octets to read
  24.955 +
  24.956 +     This is the argument to the SET_GETS mail_parameter() call.  This
  24.957 +function must read size octets from the stream, using the readfn f.  It
  24.958 +may call f multiple times to accomplish this; this will read the data in
  24.959 +a serial fashion.  So, for example, if size is a megabyte and there is
  24.960 +only 4K of available buffer space, it can call f 256 times to satisfy
  24.961 +the request.  There is no way to back up in the reading, so any
  24.962 +processing or saving of the data must be done when it is read.
  24.963 +
  24.964 +     The function mm_gets() in mail.c is a sample mailgets function; it
  24.965 +reads the first MAXMESSAGESIZE of data into memory and discards the
  24.966 +rest.
  24.967 +
  24.968 +
  24.969 +typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
  24.970 +	stream	stream to cache manage
  24.971 +	msgno	message to cache manage in the stream
  24.972 +	op	cache management operation
  24.973 +
  24.974 +     This function manages the c-client cache.  Normally, a program will
  24.975 +use the default c-client cache manager routine mm_cache().  However, a
  24.976 +main program may want to supply its own cache manager, e.g. it may want
  24.977 +to store the data on a disk file instead of in memory on DOS and Win16
  24.978 +where memory is tight.
  24.979 +
  24.980 +     If you write your own cache manager, you need to examine the
  24.981 +default mm_cache() manager closely, as well as paying close attention to
  24.982 +what goes into an elt (a MESSAGECACHE element).  It is highly likely
  24.983 +that if you roll elts out to disk, you will want to set stream->scache
  24.984 +and *NOT* use long elts (because long elts have ENVELOPE and BODY
  24.985 +pointers that you would have to know how to write to disk and read back).
  24.986 +
  24.987 +     The cache management functions are one of the following:
  24.988 +
  24.989 + CH_INIT	 Initialize the entire cache for the stream.  This is
  24.990 +		called only when creating a new stream or when freeing
  24.991 +		it.  The msgno argument is ignored.
  24.992 +
  24.993 + CH_SIZE	 Make sure that the cache is at least large enough to
  24.994 +		support msgno.  This is a request to grow the cache if
  24.995 +		necessary, not shrink it.
  24.996 +
  24.997 + CH_MAKELELT	 Return a long elt for msgno, creating it if necessary.
  24.998 +		This is the underlying support function for mail_lelt().
  24.999 +
 24.1000 + CH_LELT	 Return the long elt for msgno, or NIL if it does not
 24.1001 +		already exist.
 24.1002 +
 24.1003 + CH_MAKEELT	 Return an elt for msgno, creating it if necessary.
 24.1004 +		This is the underlying support function for mail_elt().
 24.1005 +
 24.1006 + CH_ELT		 Return the elt for msgno, or NIL if it does not already
 24.1007 +		exist.
 24.1008 +
 24.1009 + CH_FREE	 Free the [l]elt for msgno.
 24.1010 +
 24.1011 + CH_EXPUNGE	 Free the [l]elt for msgno, and reclaim its position.
 24.1012 +		All subsequent elts are renumbered with their elt->msgno
 24.1013 +		decremented by 1.  [Hence msgno+1 becomes msgno, etc.]
 24.1014 +		This supports message expunging from the cache.
 24.1015 +
 24.1016 +
 24.1017 +typedef long (*tcptimeout_t) (long time);
 24.1018 +	time	total time spent since TCP operation started
 24.1019 +
 24.1020 +     This function is called when a TCP operation times out.  It is set
 24.1021 +by the SET_TIMEOUT mail_parameter().  The function can return non-zero
 24.1022 +to continue the TCP operation (e.g. after outputting a "do you still
 24.1023 +want to wait" prompt) or zero if it wants the TCP operation to abort and
 24.1024 +close.  If the TCP operation aborts, it will likely cause the upper
 24.1025 +level IMAP, SMTP, etc. stream to abort and close as well.
 24.1026 +
 24.1027 +
 24.1028 +DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose);
 24.1029 +	stream	if non-NIL, stream to use for validation
 24.1030 +	mailbox	mailbox name to validate
 24.1031 +	purpose	filled in as xxx in "Can't xxx" in error messages
 24.1032 +
 24.1033 +     This function validates the given mailbox name.  It successful, it
 24.1034 +returns the driver that can open that name if successful, otherwise it
 24.1035 +returns NIL.  If stream is non-NIL, the mailbox name must be valid for
 24.1036 +the type of mailbox associated with that stream (e.g. an NNTP name can
 24.1037 +not be used with an IMAP stream).  If purpose is non-NIL, an error
 24.1038 +message is passed via mm_log() when an error occurs.
 24.1039 +
 24.1040 +
 24.1041 +DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox);
 24.1042 +	name	mailbox name to validate
 24.1043 +	drv	driver name to validate against
 24.1044 +	host	buffer to return host name if non-NIL
 24.1045 +	mailbox	buffer to return remote mailbox name if non-NIL
 24.1046 +
 24.1047 +     This function is an alternative to mail_valid_net_parse().  It
 24.1048 +validates the given mailbox name as a network name and makes sure that
 24.1049 +its service name is the same as the driver in drv.  If successful, it
 24.1050 +returns drv, and copies the host and mailbox strings as needed.
 24.1051 +Otherwise it returns NIL.
 24.1052 +
 24.1053 +
 24.1054 +long mail_valid_net_parse (char *name,NETMBX *mb);
 24.1055 +	name	mailbox name to parse
 24.1056 +	mb	pointer to NETMBX structure to return
 24.1057 +
 24.1058 +     This function parses a network mailbox name.  If the name is a
 24.1059 +network mailbox name, it returns non-NIL, with the NETMBX structure
 24.1060 +loaded with the results form the parse.
 24.1061 +
 24.1062 +		       Mailbox Access Functions
 24.1063 +
 24.1064 +void mail_list (MAILSTREAM *stream,char *ref,char *pat);
 24.1065 +void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 24.1066 +	stream	if non-NIL, stream to use
 24.1067 +	ref	mailbox reference string
 24.1068 +	pat	mailbox pattern string
 24.1069 +	contents contents to search
 24.1070 +
 24.1071 +     This function returns a list of mailboxes via the mm_list()
 24.1072 +callback.  The reference is applied to the pattern in an implementation
 24.1073 +dependent fashion, and the resulting string is used to search for
 24.1074 +matching mailbox names.  "*" is a wildcard which matches zero or more
 24.1075 +characters; "%" is a variant which does not descend a hierarchy level.
 24.1076 +Read the IMAP specification for more information.
 24.1077 +
 24.1078 +     mail_scan() is a variant which takes a string to search for in the
 24.1079 +text of the mailbox.  The string is a free-text string, without regard
 24.1080 +for message boundaries, and thus the choice of strings must be made
 24.1081 +with care.
 24.1082 +
 24.1083 +
 24.1084 +void mail_lsub (MAILSTREAM *stream,char *ref,char *pat);
 24.1085 +	stream	if non-NIL, stream to use
 24.1086 +	ref	mailbox reference string
 24.1087 +	pat	mailbox pattern string
 24.1088 +
 24.1089 +     This function returns a list of subscribed mailboxes via the
 24.1090 +mm_lsub() callback.  The reference is applied to the pattern in an
 24.1091 +implementation dependent fashion, and the resulting string is used to
 24.1092 +search for matching mailbox names in the subscription list.  "*" is a
 24.1093 +wildcard which matches zero or more characters; "%" is a variant which
 24.1094 +does not descend a hierarchy level.  Read the IMAP specification for
 24.1095 +more information.
 24.1096 +
 24.1097 +
 24.1098 +long mail_subscribe (MAILSTREAM *stream,char *mailbox);
 24.1099 +	stream	if non-NIL, stream to use
 24.1100 +	mailbox	mailbox name
 24.1101 +
 24.1102 +     This function adds the given name to the subscription list.  It
 24.1103 +returns T if successful, NIL if unsuccessful.  If unsuccessful, an
 24.1104 +error message is returned via the mm_log() callback.
 24.1105 +
 24.1106 +
 24.1107 +long mail_unsubscribe (MAILSTREAM *stream,char *mailbox);
 24.1108 +	stream	if non-NIL, stream to use
 24.1109 +	mailbox	mailbox name
 24.1110 +
 24.1111 +     This function removes the given name from the subscription list.
 24.1112 +It returns T if successful, NIL if unsuccessful.  If unsuccessful, an
 24.1113 +error message is returned via the mm_log() callback.
 24.1114 +
 24.1115 +
 24.1116 +long mail_create (MAILSTREAM *stream,char *mailbox);
 24.1117 +	stream	if non-NIL, stream to use
 24.1118 +	mailbox	mailbox name
 24.1119 +
 24.1120 +     This function creates a mailbox with the given name.  It returns T
 24.1121 +if successful, NIL if unsuccessful.  If unsuccessful, an error message
 24.1122 +is returned via the mm_log() callback.
 24.1123 +
 24.1124 +     It is an error to create INBOX or a mailbox name which already
 24.1125 +exists.
 24.1126 +
 24.1127 +
 24.1128 +long mail_delete (MAILSTREAM *stream,char *mailbox);
 24.1129 +	stream	if non-NIL, stream to use
 24.1130 +	mailbox	mailbox name
 24.1131 +
 24.1132 +     This function deletes the named mailbox.  It returns T if
 24.1133 +successful, NIL if unsuccessful.  If unsuccessful, an error message is
 24.1134 +returned via the mm_log() callback.
 24.1135 +
 24.1136 +     It is an error to delete INBOX or a mailbox name which does not
 24.1137 +already exist.
 24.1138 +
 24.1139 +
 24.1140 +long mail_rename (MAILSTREAM *stream,char *old,char *newname);
 24.1141 +	stream	if non-NIL, stream to use
 24.1142 +	old	existing mailbox name
 24.1143 +	newname	new (not yet existing) mailbox name
 24.1144 +
 24.1145 +     This function renames the old mailbox to the new mailbox name.
 24.1146 +It returns T if successful, NIL if unsuccessful.  If unsuccessful, an
 24.1147 +error message is returned via the mm_log() callback.
 24.1148 +
 24.1149 +     It is an error to reanme a mailbox that does not exist, or rename
 24.1150 +a mailbox to a name that already exists.  It is permitted to rename
 24.1151 +INBOX; a new empty INBOX is created in its place.
 24.1152 +
 24.1153 +
 24.1154 +long mail_status (MAILSTREAM *stream,char *mbx,long flags);
 24.1155 +	stream	if non-NIL, stream to use
 24.1156 +	mbx	mailbox name
 24.1157 +	flags	option flags
 24.1158 +
 24.1159 +     This function returns the status of the given mailbox name via the
 24.1160 +mm_status() callback.  It returns T if successful, NIL if unsuccessful.
 24.1161 +If unsuccessful, an error message is returned via the mm_log()
 24.1162 +callback.
 24.1163 +
 24.1164 +     The options are a bit mask with one or more of the following,
 24.1165 +indicating the data which should be returned.
 24.1166 +	SA_MESSAGES	number of messages in the mailbox
 24.1167 +	SA_RECENT	number of recent messages in the mailbox
 24.1168 +	SA_UNSEEN	number of unseen messages in the mailbox
 24.1169 +	SA_UIDNEXT	next UID value to be assigned
 24.1170 +	SA_UIDVALIDITY	UID validity value
 24.1171 +
 24.1172 +     Note that, depending upon implementation, some of these values may
 24.1173 +be more costly to get than others.  For example, calculating the
 24.1174 +number of unseen messages may require opening the mailbox and scanning
 24.1175 +all of the message flags.  A mail_status() call should thus be used
 24.1176 +with option flags specifying only the data that is actually needed.
 24.1177 +
 24.1178 +
 24.1179 +MAILSTREAM *mail_open (MAILSTREAM *oldstream,char *name,long options);
 24.1180 +	oldstream if non-NIL, stream to recycle
 24.1181 +	name	mailbox name to open
 24.1182 +	options	option flags.
 24.1183 +
 24.1184 +     This function opens the mailbox and if successful returns a stream
 24.1185 +suitable for use by the other MAIL functions.
 24.1186 +
 24.1187 +     If oldstream is non-NIL, an attempt is made to reuse oldstream as
 24.1188 +the stream for this mailbox; this is useful when you want to open
 24.1189 +another mailbox to the same IMAP or NNTP server without having to open
 24.1190 +a new connection.  Doing this will close the previously open mailbox.
 24.1191 +
 24.1192 +     The options are a bit mask with one or more of the following:
 24.1193 +	OP_DEBUG	Log IMAP protocol telemetry through mm_debug()
 24.1194 +	OP_READONLY	Open mailbox read-only.
 24.1195 +	OP_ANONYMOUS	Don't use or update a .newsrc file for news.
 24.1196 +	OP_SHORTCACHE	Don't cache envelopes or body structures
 24.1197 +	OP_SILENT	Don't pass mailbox events (internal use only)
 24.1198 +	OP_PROTOTYPE	Return the "prototype stream" for the driver
 24.1199 +			 associated with this mailbox instead of
 24.1200 +			 opening the stream
 24.1201 +	OP_HALFOPEN	For IMAP and NNTP names, open a connection
 24.1202 +			 to the server but don't open a mailbox.
 24.1203 +	OP_EXPUNGE	Silently expunge the oldstream before recycling
 24.1204 +
 24.1205 + NIL is returned if this function fails for any reason.
 24.1206 +
 24.1207 +
 24.1208 +MAILSTREAM *mail_close (MAILSTREAM *stream);
 24.1209 +MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options);
 24.1210 +	stream	stream to close
 24.1211 +	options	option flags
 24.1212 +     This function closes the MAIL stream and frees all resources
 24.1213 +associated with it that it may have created (subject to any handles
 24.1214 +existing).
 24.1215 +
 24.1216 +     The options for mail_close_full() are a bit mask with one or more
 24.1217 +of the following:
 24.1218 +	CL_EXPUNGE	Silently expunge before closing
 24.1219 +
 24.1220 +     This function always returns NIL, so it can be used as:
 24.1221 +	stream = mail_close (stream);
 24.1222 +
 24.1223 +			   Handle Functions
 24.1224 +
 24.1225 +     Handles are used when an entity that wishes to access the stream
 24.1226 +may survive the stream without knowing that it outlived it.  For
 24.1227 +example, an object reading a message may have a handle to a stream,
 24.1228 +but the message selection object that spawned it (and which owns the
 24.1229 +stream) may have gone away.  A stream can be closed or recycled while
 24.1230 +handles are pointing at it, but it is not completely freed until all
 24.1231 +handles are gone.  A stream may have an arbitrary number of handles.
 24.1232 +
 24.1233 +
 24.1234 +MAILHANDLE *mail_makehandle (MAILSTREAM *stream);
 24.1235 +	stream	stream to make handle to
 24.1236 +
 24.1237 +     This function creates and returns a handle to the stream.
 24.1238 +
 24.1239 +
 24.1240 +void mail_free_handle (MAILHANDLE **handle);
 24.1241 +	handle	pointer to handle to release
 24.1242 +
 24.1243 +     This function frees the handle and notifies the stream that it has
 24.1244 +one fewer handle.  If this is the last handle on the stream and the
 24.1245 +stream has been closed, then the stream is freed.
 24.1246 +
 24.1247 +
 24.1248 +MAILSTREAM *mail_stream (MAILHANDLE *handle);
 24.1249 +	handle	handle to look up
 24.1250 +
 24.1251 +     This function returns the stream associated with the handle if and
 24.1252 +only if the stream still represents the same MAIL connection associated
 24.1253 +with the handle.  Otherwise, NIL is returned (meaning that there is no
 24.1254 +active stream associated with this handle).
 24.1255 +
 24.1256 +		    Message Data Fetching Functions
 24.1257 +
 24.1258 +[Note!!  There is an important difference between a "sequence" and a
 24.1259 + "msgno".  A sequence is a string representing one or more messages in
 24.1260 + IMAP4-style sequence format ("n", "n:m", or combination of these
 24.1261 + delimited by commas), whereas a msgno is an int representing a single
 24.1262 + message.] 
 24.1263 +
 24.1264 +void mail_fetchfast (MAILSTREAM *stream,char *sequence);
 24.1265 +void mail_fetchfast_full (MAILSTREAM *stream,char *sequence,long flags);
 24.1266 +	stream	stream to fetch on
 24.1267 +	sequence IMAP-format set of message sequence numbers
 24.1268 +	flags	option flags
 24.1269 +
 24.1270 +     This function causes a cache load of all the "fast" information
 24.1271 +(internal date, RFC 822 size, and flags) for the given sequence.  Since
 24.1272 +all this information is also fetched by mail_fetchstructure(), this
 24.1273 +function is generally not used unless the OP_SHORTCACHE option in the
 24.1274 +mail_open() call is used.
 24.1275 +
 24.1276 +     The options for mail_fetchfast_full() are a bit mask with one or
 24.1277 +more of the following:
 24.1278 +	FT_UID		The sequence argument contains UIDs instead of
 24.1279 +			 sequence numbers
 24.1280 +
 24.1281 +
 24.1282 +void mail_fetchflags (MAILSTREAM *stream,char *sequence);
 24.1283 +void mail_fetchflags_full (MAILSTREAM *stream,char *sequence,long flags);
 24.1284 +
 24.1285 +     This function causes a fetch of the flags for the given sequence.
 24.1286 +This main reason for using this function is to update the flags in the
 24.1287 +local cache in case some other process changed the flags (multiple
 24.1288 +simultaneous write access is allowed to the flags) as part of a "check
 24.1289 +entire mailbox" (as opposed to "check for new messages") operation.
 24.1290 +
 24.1291 + The options for mail_fetchflags_full() are a bit mask with one or more
 24.1292 +of the following:
 24.1293 +	FT_UID		The sequence argument contains UIDs instead of
 24.1294 +			 sequence numbers
 24.1295 +
 24.1296 +
 24.1297 +ENVELOPE *mail_fetchenvelope (MAILSTREAM *stream,unsigned long msgno);
 24.1298 +ENVELOPE *mail_fetchstructure (MAILSTREAM *stream,unsigned long msgno,
 24.1299 +			       BODY **body);
 24.1300 +ENVELOPE *mail_fetchstructure_full (MAILSTREAM *stream,unsigned long msgno,
 24.1301 +				    BODY **body,long flags);
 24.1302 +	stream	stream to fetch on
 24.1303 +	msgno	message sequence number
 24.1304 +	body	pointer to where to return BODY structure if non-NIL
 24.1305 +	flags	option flags
 24.1306 +     This function causes a fetch of all the structured information
 24.1307 +(envelope, internal date, RFC 822 size, flags, and body structure) for
 24.1308 +the given msgno and, in the case of IMAP, up to MAPLOOKAHEAD (a
 24.1309 +parameter in IMAP2.H) subsequent messages which are not yet in the
 24.1310 +cache.  No fetch is done if the envelope for the given msgno is already
 24.1311 +in the cache.  The ENVELOPE and the BODY for this msgno is returned.
 24.1312 +It is possible for the BODY to be NIL, in which case no information is
 24.1313 +available about the structure of the message body.
 24.1314 +
 24.1315 +     The options for mail_fetchstructure_full() are a bit mask with one
 24.1316 +or more of the following:
 24.1317 +	FT_UID		The msgno argument is a UID 
 24.1318 +
 24.1319 +     This is the primary function for fetching non-text information
 24.1320 +about messages, and should be called before any attempt to reference
 24.1321 +cache information about this message via mail_elt().
 24.1322 +
 24.1323 +
 24.1324 +char *mail_fetchheader (MAILSTREAM *stream,unsigned long msgno);
 24.1325 +char *mail_fetchheader_full (MAILSTREAM *stream,unsigned long msgno,
 24.1326 +			     STRINGLIST *lines,unsigned long *len,long flags);
 24.1327 +	stream	stream to fetch on
 24.1328 +	msgno	message sequence number
 24.1329 +	lines	list of header lines to fetch
 24.1330 +	len	returned length in octets
 24.1331 +	flags	option flags
 24.1332 +
 24.1333 +     This function causes a fetch of the complete, unfiltered RFC 822
 24.1334 +format header of the specified message as a text string and returns
 24.1335 +that text string.
 24.1336 +
 24.1337 +     If the lines argument is non-NIL, it contains a list of header
 24.1338 +field names to use in subsetting the header text.  Only those lines
 24.1339 +which have that header field name are returned, unless FT_NOT is set in
 24.1340 +which case only those lines which do not have that header field name
 24.1341 +are returned.
 24.1342 +
 24.1343 +     If the len argument is non-NIL, it holds a pointer in which the
 24.1344 +length of the string in octets is returned.  This is useful in cases
 24.1345 +where there may be an embedded null in the string.
 24.1346 +
 24.1347 +     This function always returns a valid string pointer; if no header
 24.1348 +exists or if it can not be fetched (e.g. by a deceased IMAP stream) an
 24.1349 +empty string is returned.
 24.1350 +
 24.1351 +     The options for mail_fetchheader_full() are a bit mask with one or
 24.1352 +more of the following:
 24.1353 +	FT_UID		The msgno argument is a UID 
 24.1354 +	FT_NOT		The returned header lines are those that are
 24.1355 +			 not in the lines argument
 24.1356 +	FT_INTERNAL	The return string is in "internal" format,
 24.1357 +			 without any attempt to canonicalize to CRLF
 24.1358 +			  newlines
 24.1359 +	FT_PREFETCHTEXT	The RFC822.TEXT should be pre-fetched at the
 24.1360 +			 same time.  This avoids an extra RTT on an
 24.1361 +			 IMAP connection if a full message text is
 24.1362 +			 desired (e.g. in a "save to local file"
 24.1363 +			 operation)
 24.1364 +		 
 24.1365 +
 24.1366 +char *mail_fetchtext (MAILSTREAM *stream,unsigned long msgno);
 24.1367 +char *mail_fetchtext_full (MAILSTREAM *stream,unsigned long msgno,
 24.1368 +			   unsigned long *len,long flags);
 24.1369 +	stream	stream to fetch on
 24.1370 +	msgno	message sequence number
 24.1371 +	len	returned length in octets
 24.1372 +	flags	option flags
 24.1373 +
 24.1374 +     This function causes a fetch of the non-header text of the
 24.1375 +specified message as a text string and returns that text string.  No
 24.1376 +attempt is made to segregate individual body parts.
 24.1377 +
 24.1378 +     If the len argument is non-NIL, it holds a pointer in which the
 24.1379 +length of the string in octets is returned.  This is useful in cases
 24.1380 +where there may be an embedded null in the string.
 24.1381 +
 24.1382 +     This function always returns a valid string pointer; if no header
 24.1383 +exists or if it can not be fetched (e.g. by a deceased IMAP stream) an
 24.1384 +empty string is returned.
 24.1385 +
 24.1386 +      The options for mail_fetchtext_full() are a bit mask with one or
 24.1387 +more of the following:
 24.1388 +	FT_UID		The msgno argument is a UID 
 24.1389 +	FT_PEEK		Do not set the \Seen flag if it not already set
 24.1390 +	FT_INTERNAL	The return string is in "internal" format,
 24.1391 +			 without any attempt to canonicalize to CRLF
 24.1392 +			  newlines
 24.1393 +
 24.1394 +
 24.1395 +char *mail_fetchbody (MAILSTREAM *stream,unsigned long msgno,char *sec,
 24.1396 +		      unsigned long *len);
 24.1397 +char *mail_fetchbody_full (MAILSTREAM *stream,unsigned long msgno,char *sec,
 24.1398 +			   unsigned long *len,long flags);
 24.1399 +	stream	stream to fetch on
 24.1400 +	msgno	message sequence number
 24.1401 +	sec	section specifier
 24.1402 +	len	returned length in octets
 24.1403 +	flags	option flags
 24.1404 +
 24.1405 +      This function causes a fetch of the particular section of the
 24.1406 +body of the specified message as a text string and returns that text
 24.1407 +string.  The section specification is a string of integers delimited by
 24.1408 +period which index into a body part list as per the IMAP4
 24.1409 +specification.  Body parts are not decoded by this function; see
 24.1410 +rfc822_base64() and rfc822_quotedprintable().
 24.1411 +
 24.1412 +     If the len argument is non-NIL, it holds a pointer in which the
 24.1413 +length of the string in octets is returned.  This is useful in cases
 24.1414 +where there may be an embedded null in the string.
 24.1415 +
 24.1416 +      This function may return NIL on error.
 24.1417 +
 24.1418 +      The options for mail_fetchbody_full() are a bit mask with one or
 24.1419 +more of the following:
 24.1420 +	FT_UID		The msgno argument is a UID 
 24.1421 +	FT_PEEK		Do not set the \Seen flag if it not already set
 24.1422 +	FT_INTERNAL	The return string is in "internal" format,
 24.1423 +			 without any attempt to canonicalize to CRLF
 24.1424 +			  newlines
 24.1425 +
 24.1426 +
 24.1427 +unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno);
 24.1428 +	stream	stream to fetch on
 24.1429 +	msgno	message sequence number
 24.1430 +
 24.1431 +      This function returns the UID for the given message sequence
 24.1432 +number.
 24.1433 +
 24.1434 +
 24.1435 +void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
 24.1436 +		     long length);
 24.1437 +	s	destination string
 24.1438 +	stream	stream to fetch on
 24.1439 +	msgno	message sequence number
 24.1440 +	length	maximum field length
 24.1441 +
 24.1442 +     This function writes a "from" string of the specified length for
 24.1443 +the specified message, suitable for display to the user in a menu line,
 24.1444 +into the string pointed to by s.
 24.1445 +
 24.1446 +      If the personal name of the first address in the envelope's from
 24.1447 +item is non-NIL, it is used; otherwise a string is created by appending
 24.1448 +the mailbox of the first address, an "@", and the host of the first
 24.1449 +address.  The string is trimmed or padded with trailing spaces as
 24.1450 +necessary to make its length match the length argument.
 24.1451 +
 24.1452 +
 24.1453 +void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
 24.1454 +			long length);
 24.1455 +	s	destination string
 24.1456 +	stream	stream to fetch on
 24.1457 +	msgno	message sequence number
 24.1458 +	length	maximum field length
 24.1459 +
 24.1460 +      This function returns a "subject" string of the specified length
 24.1461 +for the specified message, suitable for display to the user in a menu
 24.1462 +line.
 24.1463 +
 24.1464 +       The envelope's subject item is copied and trimmed as necessary
 24.1465 +to make its length be no more what the caller requested.  Unlike
 24.1466 +mail_fetchfrom(), this function can return a string of shorter length
 24.1467 +than what the caller requested.
 24.1468 +
 24.1469 +
 24.1470 +LONGCACHE *mail_lelt (MAILSTREAM *stream,unsigned long msgno);
 24.1471 +MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno);
 24.1472 +	stream	stream to access
 24.1473 +	msgno	message sequence number
 24.1474 +
 24.1475 +     This function returns the cache entry for the specified message.
 24.1476 +Although it will create a cache entry if it does not already exist,
 24.1477 +that functionality is for internal use only.  This function should
 24.1478 +never be called without having first called mail_fetchfast() or
 24.1479 +mail_fetchstructure() on the message first.
 24.1480 +
 24.1481 +     A cache entry holds the internal date/time, flags, and RFC 822
 24.1482 +size of a message.  It holds other data as well, but that is for
 24.1483 +internal use only.
 24.1484 +
 24.1485 +     mail_lelt() is a variant that returns a `long' cache entry, which
 24.1486 +consists of an cache entry (as a structure, not a pointer), an envelope
 24.1487 +pointer, and a body pointer.  This is used in conjunction with the elt
 24.1488 +lock count functionality, to allow an application to associate the
 24.1489 +cached envelope and body of a message with an open window even if the
 24.1490 +message is subsequently expunged or if the stream is closed.
 24.1491 +
 24.1492 +     Unless your application wants to look at cached envelopes and
 24.1493 +bodies even after the message is expunged or the stream is closed, it
 24.1494 +should not use mail_lelt().  Instead, it should use a returned elt from
 24.1495 +mail_elt() and use the elt->msgsno as the argument to
 24.1496 +mail_fetchstructure().
 24.1497 +
 24.1498 +	BEWARE: the behavior of mail_lelt() is undefined if the
 24.1499 +	stream is open with OP_SHORTCACHE.  mail_lelt() is extremely
 24.1500 +	special purpose, and should only be used in sophisticated
 24.1501 +	special purpose applications after discussing its use with
 24.1502 +	the c-client author.  If you think you need this function,
 24.1503 +	you are probably mistaken.  In almost all cases, you should
 24.1504 +	use mail_elt() and mail_fetchstructure() instead.
 24.1505 +
 24.1506 +		 Message Status Manipulation Functions
 24.1507 +
 24.1508 +void mail_setflag (MAILSTREAM *stream,char *sequence,char *flag);
 24.1509 +void mail_setflag_full (MAILSTREAM *stream,char *sequence,char *flag,
 24.1510 +			long flags);
 24.1511 +	stream	stream to use
 24.1512 +	sequence IMAP-format set of message sequence numbers
 24.1513 +	flag	IMAP-format flag string
 24.1514 +	flags	option flags
 24.1515 +
 24.1516 +    This function causes a store to add the specified flag to the flags
 24.1517 +set for the messages in the specified sequence.  If there is any
 24.1518 +problem in setting flags, a message will be passed to the application
 24.1519 +via the mm_log() facility.
 24.1520 +
 24.1521 +     The options for mail_setflag_full() are a bit mask with one or
 24.1522 +more of the following:
 24.1523 +	ST_UID		The sequence argument contains UIDs instead of
 24.1524 +			 sequence numbers
 24.1525 +	ST_SILENT	Do not update the local cache with the new
 24.1526 +			 value of the flags.  This is useful to save
 24.1527 +			 network bandwidth, at the cost of invalidating
 24.1528 +			 the cache.
 24.1529 +
 24.1530 +
 24.1531 +void mail_clearflag (MAILSTREAM *stream,char *sequence,char *flag);
 24.1532 +void mail_clearflag_full (MAILSTREAM *stream,char *sequence,char *flag,
 24.1533 +			  long flags);
 24.1534 +	stream	stream to use
 24.1535 +	sequence IMAP-format set of message sequence numbers
 24.1536 +	flag	IMAP-format flag string
 24.1537 +	flags	option flags
 24.1538 +
 24.1539 +     This function causes a store to delete the specified flag from the
 24.1540 +flags set for the messages in the specified sequence.  If there is any
 24.1541 +problem in clearing flags, a message will be passed to the application
 24.1542 +via the mm_log() facility.
 24.1543 +
 24.1544 +     The options for mail_setflag_full() are a bit mask with one or
 24.1545 +more of the following:
 24.1546 +	ST_UID		The sequence argument contains UIDs instead of
 24.1547 +			 sequence numbers
 24.1548 +	ST_SILENT	Do not update the local cache with the new
 24.1549 +			 value of the flags.  This is useful to save
 24.1550 +			 network bandwidth, at the cost of invalidating
 24.1551 +			 the cache.
 24.1552 +
 24.1553 +			   Mailbox Searching
 24.1554 +
 24.1555 +void mail_search (MAILSTREAM *stream,char *criteria);
 24.1556 +void mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
 24.1557 +		       long flags);
 24.1558 +	stream	stream to search
 24.1559 +	charset	MIME character set to use when searching strings
 24.1560 +	pgm	search program
 24.1561 +	flags	option flags
 24.1562 +
 24.1563 +     This function causes a mailbox search, using the given MIME
 24.1564 +charset (NIL means the default, US-ASCII) and the given search program.
 24.1565 +A search program is a structure that holds the following data:
 24.1566 +
 24.1567 +SEARCHSET *msgno;	a set of message sequence numbers
 24.1568 +SEARCHSET *uid;		a set of unique identifiers
 24.1569 +SEARCHOR *or;		OR result of two search programs
 24.1570 +SEARCHPGMLIST *not;	AND result of list of NOT'ed search programs
 24.1571 +SEARCHHEADER *header;	message headers
 24.1572 +STRINGLIST *bcc;	string(s) appear in bcc list
 24.1573 +STRINGLIST *body;	string(s) appear in message body text
 24.1574 +STRINGLIST *cc;		string(s) appear in cc list
 24.1575 +STRINGLIST *from;	string(s) appear in from
 24.1576 +STRINGLIST *keyword;	user flag string(s) set
 24.1577 +STRINGLIST *unkeyword;	user flag strings() not set
 24.1578 +STRINGLIST *subject;	string(s) appear in subject
 24.1579 +STRINGLIST *text;	string(s) appear in message header or body
 24.1580 +STRINGLIST *to;		string(s) appear in to list
 24.1581 +unsigned long larger;	larger than this many octets
 24.1582 +unsigned long smaller;	smaller than this many octes
 24.1583 +	The following dates are in form:
 24.1584 +		((year - BASEYEAR) << 9) + (month << 5) + day
 24.1585 +unsigned short sentbefore;
 24.1586 +			sent before this date
 24.1587 +unsigned short senton;	sent on this date
 24.1588 +unsigned short sentsince;
 24.1589 +			sent since this date
 24.1590 +unsigned short before;	received before this date
 24.1591 +unsigned short on;	received on this date
 24.1592 +unsigned short since;	received since this date
 24.1593 +unsigned int answered : 1;
 24.1594 +			message answered
 24.1595 +unsigned int unanswered : 1;
 24.1596 +			message not answered
 24.1597 +unsigned int deleted : 1;
 24.1598 +			message deleted
 24.1599 +unsigned int undeleted : 1;
 24.1600 +			message not deleted
 24.1601 +unsigned int draft : 1;	message is a draft
 24.1602 +unsigned int undraft : 1;
 24.1603 +			message is not a draft
 24.1604 +unsigned int flagged : 1;
 24.1605 +			message flagged as urgent
 24.1606 +unsigned int unflagged : 1;
 24.1607 +			message not flagged as urgent
 24.1608 +unsigned int recent : 1;
 24.1609 +			message recent since last parse of mailbox
 24.1610 +unsigned int old : 1;	message not recent since last parse of mailbox
 24.1611 +unsigned int seen : 1;	message read
 24.1612 +unsigned int unseen : 1;
 24.1613 +			message not read
 24.1614 +
 24.1615 +     The following auxillary structures are used by search programs:
 24.1616 +	SEARCHHEADER:	header line searching
 24.1617 +char *line;		header line field name
 24.1618 +char *text;		text header line
 24.1619 +SEARCHHEADER *next;	next SEARCHHEADER in list (AND'ed)
 24.1620 +
 24.1621 +	SEARCHSET:	message number set
 24.1622 +unsigned long first;	first number in set
 24.1623 +unsigned long last;	if non-zero, last number in set
 24.1624 +SEARCHSET *next;	next SEARCHSET in list (AND'ed)
 24.1625 +
 24.1626 +	SEARCHOR:	two search programs, OR'ed together
 24.1627 +SEARCHPGM *first;	first program
 24.1628 +SEARCHPGM *second;	second program
 24.1629 +SEARCHOR *next;		next SEARCHOR in list
 24.1630 +
 24.1631 +	SEARCHPGMLIST:	list of search programs
 24.1632 +SEARCHPGM *pgm;		search program (AND'd with others in list)
 24.1633 +SEARCHPGMLIST *next;	next SEARCHPGM in list
 24.1634 +
 24.1635 +     mail_search(), the older interface, accepts a search criteria
 24.1636 +argument as a character string in IMAP2 (RFC-1176) format.  Do not try
 24.1637 +to use any IMAP4 search criteria with this interface.
 24.1638 +
 24.1639 +     The application's mm_searched() function is called for each
 24.1640 +message that matches the search criteria.  In addition, after the
 24.1641 +search is completed, the "fast" information (see mail_fetchfast_full()
 24.1642 +and envelopes of the searched messages are fetched (this is called
 24.1643 +pre-fetching).
 24.1644 +
 24.1645 +     If there is any problem in searching, a message will be passed to
 24.1646 +the application via the mm_log() facility.
 24.1647 +
 24.1648 +     The flags for mail_search_full() are a bit mask with one or more
 24.1649 +of the following:
 24.1650 +	SE_UID		Return UIDs instead of sequence numbers
 24.1651 +	SE_FREE		Return the search program to free storage after
 24.1652 +			 finishing
 24.1653 +	SE_NOPREFETCH	Don't prefetch searched messages.
 24.1654 +
 24.1655 +
 24.1656 +unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 24.1657 +			  SORTPGM *pgm,long flags);
 24.1658 +	stream	stream to sort
 24.1659 +	charset	MIME character set to use when sorting strings
 24.1660 +	spg	search program
 24.1661 +	pgm	sort program
 24.1662 +	flags	option flags
 24.1663 +
 24.1664 +
 24.1665 +     This function is a variant of mail_search_full().  It accepts an
 24.1666 +additional argument, a sort program, which specifies one or more sort
 24.1667 +rules to be applied to the result.  If the searching and sorting are
 24.1668 +successful, it returns a 0-terminated vector of message sequence
 24.1669 +numbers (or UIDs if SE_UID is set).  This vector is created out of
 24.1670 +free storage, and must be freed with fs_give() when finished with it.
 24.1671 +
 24.1672 +     A sort program is a structure that holds the following data:
 24.1673 +unsigned int reverse : 1;
 24.1674 +			reverse sorting of this key
 24.1675 +short function;		sort rule, one of the following:
 24.1676 +		SORTDATE	message Date
 24.1677 +		SORTARRIVAL	arrival date
 24.1678 +		SORTFROM	mailbox in first From address
 24.1679 +		SORTSUBJECT	message Subject
 24.1680 +		SORTTO		mailbox in first To address 
 24.1681 +		SORTCC		mailbox in first cc address 
 24.1682 +		SORTSIZE	size of message in octets
 24.1683 +SORTPGM *next;		next sort program to be applied if two or more
 24.1684 +			 messages collate identically with this rule
 24.1685 +
 24.1686 +     The flags for mail_search_full() are a bit mask with one or more
 24.1687 +of the following:
 24.1688 +	SE_UID		Return UIDs instead of sequence numbers
 24.1689 +	SE_FREE		Return the search program to free storage after
 24.1690 +			 finishing
 24.1691 +	SE_NOPREFETCH	Don't prefetch searched messages.
 24.1692 +	SO_FREE		Return the sort program to free storage after
 24.1693 +			 finishing
 24.1694 +
 24.1695 +	      Miscellaneous Mailbox and Message Functions
 24.1696 +
 24.1697 +long mail_ping (MAILSTREAM *stream);
 24.1698 +	stream	string to ping
 24.1699 +
 24.1700 +     The function pings the stream to see if it is still active.  It may
 24.1701 +discover new mail; this is the preferred method for a periodic "new mail
 24.1702 +check" as well as a "keep alive" for servers which have an inactivity
 24.1703 +timeout.  It returns T if the stream is still alive, NIL otherwise.
 24.1704 +
 24.1705 +     If new mail is found, the application's mm_exists() function is
 24.1706 +called with the newly-determined number of messages in the mailbox.
 24.1707 +
 24.1708 +
 24.1709 +void mail_check (MAILSTREAM *stream);
 24.1710 +	stream	stream to checkpoint
 24.1711 +
 24.1712 +      This function causes a mailstore-defined checkpoint of the
 24.1713 +mailbox.  This may include such things as a writeback to disk, a check
 24.1714 +for flag changes in a shared mailbox, etc.  It is not a "check for new
 24.1715 +mail"; mail_ping() performs this function (as potentially does any other
 24.1716 +function).  The status of the check is passed to the application via the
 24.1717 +mm_log() facility.
 24.1718 +
 24.1719 +
 24.1720 +void mail_expunge (MAILSTREAM *stream);
 24.1721 +	stream	string to expunge
 24.1722 +
 24.1723 +     This function causes an expunge (permanent removal of messages
 24.1724 +which are marked as deleted) of the mailbox.  The application's
 24.1725 +mm_expunged() function is called for each message that has been
 24.1726 +expunged.  The application's mm_exists() function is called at the start
 24.1727 +and end of the expunge to ensure synchronization.  The status of the
 24.1728 +expunge is passed to the application via the mm_log() facility.
 24.1729 +
 24.1730 +      Note that the decrementing of msgno's for subsequent messages
 24.1731 +happens immediately; for example, if three consequtive messages starting
 24.1732 +at msgno 5 are expunged, mm_expunged() will be called with a msgno of 5
 24.1733 +three times.
 24.1734 +
 24.1735 +
 24.1736 +long mail_copy (MAILSTREAM *stream,char *sequence,char *mailbox);
 24.1737 +long mail_move (MAILSTREAM *stream,char *sequence,char *mailbox);
 24.1738 +long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
 24.1739 +		     long options);
 24.1740 +	stream	stream to copy
 24.1741 +	sequence IMAP-format set of message numbers
 24.1742 +	mailbox	destination mailbox name
 24.1743 +	options	option flags
 24.1744 +
 24.1745 +     This function causes the messages in the specified sequence to be
 24.1746 +copied to the specified mailbox.  T is returned if the copy is
 24.1747 +successful.  mail_move() is equivalent to setting CP_MOVE in the options.
 24.1748 +
 24.1749 +     If there is any problem in copying, a message will be passed to
 24.1750 +the application via the mm_log() facility and the function returns NIL.
 24.1751 +No copying is actually done in this case.
 24.1752 +
 24.1753 +      Note that the mailbox must be on the same host as the stream and
 24.1754 +is a mailbox of the type of the source mailbox only.
 24.1755 +
 24.1756 +     The flags for mail_search_full() are a bit mask with one or more
 24.1757 +of the following:
 24.1758 +	CP_UID		The sequence argument contains UIDs instead of
 24.1759 +			 sequence numbers
 24.1760 +	CP_MOVE		Delete the messages from the current mailbox
 24.1761 +			 after copying to the destination.
 24.1762 +
 24.1763 +
 24.1764 +long mail_append (MAILSTREAM *stream,char *mailbox,STRING *message);
 24.1765 +long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
 24.1766 +		       STRING *message);
 24.1767 +	stream	stream to use if non-NIL (in the IMAP case)
 24.1768 +	mailbox	destination mailbox name
 24.1769 +	flags	flags to set on message if non-NIL
 24.1770 +	date	internal date (received date) to set on message if non-NIL
 24.1771 +	message	string structure of message to write
 24.1772 +
 24.1773 +     This function writes the message in the string structure to the
 24.1774 +destination mailbox, along with the flags and date if specified.  This
 24.1775 +is useful in those cases where you can't use mail_copy(), e.g. when
 24.1776 +copying from one server to another; you can always fetch the message
 24.1777 +and then mail_append() it to the destination.  It may also be useful
 24.1778 +for maintaining an outbox of your outgoing mail.
 24.1779 +
 24.1780 +
 24.1781 +void mail_gc (MAILSTREAM *stream,long gcflags);
 24.1782 +	stream	stream to GC if non-NIL (else GC's all streams)
 24.1783 +	flags	option flags
 24.1784 +
 24.1785 +      This function garbage collects (purges) the cache of entries of
 24.1786 +a specific type.  Some drivers do not allow purging of particular
 24.1787 +cache types, and an attempt to do so is ignored.
 24.1788 +
 24.1789 +      The flags for mail_gc() are a bit mask with one or more of the
 24.1790 +following:
 24.1791 +	GC_ELT		message cache elements
 24.1792 +	GC_ENV		ENVELOPEs and BODYs
 24.1793 +	GC_TEXTS	cached texts
 24.1794 +
 24.1795 +		     Date/Time Handling Functions
 24.1796 +
 24.1797 +
 24.1798 +char *mail_date (char *string,MESSAGECACHE *elt);
 24.1799 +	string	destination string
 24.1800 +	elt	message cache element containing date
 24.1801 +
 24.1802 +      This function accepts a message cache element that contains date
 24.1803 +information, and writes an IMAP-4 date string, that is, one in form:
 24.1804 +	dd-mmm-yyyy hh:mm:ss +zzzz
 24.1805 +based upon the data in the elt.  The destination string must be large
 24.1806 +enough to hold this string.
 24.1807 +
 24.1808 +
 24.1809 +char *mail_cdate (char *string,MESSAGECACHE *elt);
 24.1810 +	string	destination string
 24.1811 +	elt	message cache element containing date
 24.1812 +
 24.1813 +      This function accepts a message cache element that contains date
 24.1814 +information, and writes a ctime() format date string, that is, one in
 24.1815 +form:
 24.1816 +	www mmm dd hh:mm:ss yyyy\n
 24.1817 +based upon the data in the elt.  The destination string must be large
 24.1818 +enough to hold this string.
 24.1819 +
 24.1820 +
 24.1821 +long mail_parse_date (MESSAGECACHE *elt,char *string);
 24.1822 +	elt	message cache element to store parsed date
 24.1823 +	string	source date string
 24.1824 +
 24.1825 +      This function parses the date/time stored in the given string,
 24.1826 +in format:
 24.1827 +	[www,] date [[hh:mm[:ss][-zzz| +zzzz]
 24.1828 +where the date can be any of:
 24.1829 +	mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy, dd mmm yy, dd mmm yyyy
 24.1830 +and stores the result of the parse in the elt.  If the parse is
 24.1831 +successful, T is returned, else NIL.
 24.1832 +
 24.1833 +
 24.1834 +unsigned long mail_longdate (MESSAGECACHE *elt);
 24.1835 +	elt	message cache element containing date.
 24.1836 +
 24.1837 +      This function accepts a message cache element that contains date
 24.1838 +information, and returns the number of days since the base time of the
 24.1839 +imap-4 toolkit.  At present, this is the same as the Unix time() value
 24.1840 +for that date/time, and hence can be used for functions such as utime().
 24.1841 +
 24.1842 +			  Utility Functions
 24.1843 +
 24.1844 +void mail_debug (MAILSTREAM *stream);
 24.1845 +	stream	stream to debug
 24.1846 +
 24.1847 +      This function enables telemetry logging for this stream.  All
 24.1848 +telemetry is passed to the application via the mm_dlog() facility.
 24.1849 +
 24.1850 +
 24.1851 +void mail_nodebug (MAILSTREAM *stream);
 24.1852 +	stream	stream to disable debugging
 24.1853 +
 24.1854 +     This function disables telemetry logging for this stream.
 24.1855 +
 24.1856 +
 24.1857 +long mail_sequence (MAILSTREAM *stream,char *sequence);
 24.1858 +	stream	stream to set the sequence bits
 24.1859 +	sequence IMAP-format message set string
 24.1860 +
 24.1861 +     This function parses the given sequence string for message
 24.1862 +numbers, sets the sequence bit in the stream's message cache element
 24.1863 +of all messages in the sequence (and turns it off in all other message
 24.1864 +cache elements).  If the parse is successful, T is returned, else NIL.
 24.1865 +
 24.1866 +
 24.1867 +long mail_uid_sequence (MAILSTREAM *stream,char *sequence);
 24.1868 +	stream	stream to set the sequence bits
 24.1869 +	sequence IMAP-format message set string
 24.1870 +
 24.1871 +     This function parses the given sequence string for unique
 24.1872 +identifiers, sets the sequence bit in the stream's message cache
 24.1873 +element of all messages in the sequence (and turns it off in all other
 24.1874 +message cache elements).  If the parse is successful, T is returned,
 24.1875 +else NIL.
 24.1876 +
 24.1877 +
 24.1878 +long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf);
 24.1879 +	stream	stream (used to get user flags)
 24.1880 +	flag	IMAP-format flag string to parse
 24.1881 +	uf	returned location of user flags
 24.1882 +
 24.1883 +     The function parses the given flag string, and returns the system
 24.1884 +flags as its return value and the user flags in the location pointed
 24.1885 +to by the uf argument.  If there is an error in parse, a log message
 24.1886 +is issued via mm_log() and this function returns NIL.
 24.1887 +
 24.1888 +
 24.1889 +unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
 24.1890 +			   long flags);
 24.1891 +	text	RFC 822 text to filter
 24.1892 +	len	length in octets in the text argument
 24.1893 +	lines	string list of header file names to filter
 24.1894 +	flags	option flags
 24.1895 +
 24.1896 +     This function supports the header lines filtering function of
 24.1897 +mail_fetchheader_full().  The lines argument contains a list of header
 24.1898 +field names to use in subsetting the header text.  Only those lines
 24.1899 +which have that header field name are returned, unless FT_NOT is set
 24.1900 +in which case only those lines which do not have that header field
 24.1901 +name are returned.
 24.1902 +
 24.1903 +     The options for mail_filter() are a bit mask with one or more of
 24.1904 +the following:
 24.1905 +	FT_NOT		The returned header lines are those that are
 24.1906 +			 not in the lines argument
 24.1907 +
 24.1908 +
 24.1909 +long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *charset,
 24.1910 +		      SEARCHPGM *pgm);
 24.1911 +	stream	stream to search
 24.1912 +	msgno	message number of message to inspect
 24.1913 +	charset	character set of search strings
 24.1914 +	pgm	search program to test
 24.1915 +
 24.1916 +     This function implements mail_search_full() locally in cases when
 24.1917 +it is not done by a server (e.g. local mail files, NNTP/POP).  It
 24.1918 +inspects the given message on that stream to see if it matches the
 24.1919 +criteria or not.  If it matches, T is returned, else NIL.
 24.1920 +
 24.1921 +
 24.1922 +SEARCHPGM *mail_criteria (char *criteria);
 24.1923 +	criteria IMAP2-format search criteria string
 24.1924 +
 24.1925 +     This function accepts an IMAP2-format search criteria string and
 24.1926 +parses it.  If the parse is successful, it returns a search program
 24.1927 +suitable for use in mail_search_full().
 24.1928 +	WARNING: This function does not accept IMAP4 search criteria.
 24.1929 +	The source string must be writeable (this restriction was also
 24.1930 +	in the old IMAP2 c-client).
 24.1931 +
 24.1932 +	   Data Structure Instantiation/Destruction functions
 24.1933 +
 24.1934 +     These functions are used to obtain structures from free storage and
 24.1935 +to release them.
 24.1936 +
 24.1937 +ENVELOPE *mail_newenvelope (void);
 24.1938 +ADDRESS *mail_newaddr (void);
 24.1939 +BODY *mail_newbody (void);
 24.1940 +BODY *mail_initbody (BODY *body);
 24.1941 +PARAMETER *mail_newbody_parameter (void);
 24.1942 +PART *mail_newbody_part (void);
 24.1943 +STRINGLIST *mail_newstringlist (void);
 24.1944 +SEARCHPGM *mail_newsearchpgm (void);
 24.1945 +SEARCHHEADER *mail_newsearchheader (char *line);
 24.1946 +SEARCHSET *mail_newsearchset (void);
 24.1947 +SEARCHOR *mail_newsearchor (void);
 24.1948 +SEARCHPGMLIST *mail_newsearchpgmlist (void);
 24.1949 +SORTPGM *mail_newsortpgm (void);
 24.1950 +
 24.1951 +     These functions, all named mail_new...(), create a new structure of
 24.1952 +the given type and initialize all of its elements to zero or empty.
 24.1953 +
 24.1954 +void mail_free_body (BODY **body);
 24.1955 +void mail_free_body_parameter (PARAMETER **parameter);
 24.1956 +void mail_free_body_part (PART **part);
 24.1957 +void mail_free_cache (MAILSTREAM *stream);
 24.1958 +void mail_free_elt (MESSAGECACHE **elt);
 24.1959 +void mail_free_lelt (LONGCACHE **lelt);
 24.1960 +void mail_free_envelope (ENVELOPE **env);
 24.1961 +void mail_free_address (ADDRESS **address);
 24.1962 +void mail_free_stringlist (STRINGLIST **string);
 24.1963 +void mail_free_searchpgm (SEARCHPGM **pgm);
 24.1964 +void mail_free_searchheader (SEARCHHEADER **hdr);
 24.1965 +void mail_free_searchset (SEARCHSET **set);
 24.1966 +void mail_free_searchor (SEARCHOR **orl);
 24.1967 +void mail_free_searchpgmlist (SEARCHPGMLIST **pgl);
 24.1968 +void mail_free_sortpgm (SORTPGM **pgm);
 24.1969 +
 24.1970 +     These functions, all named mail_free_...(), take a pointer to a
 24.1971 +structure pointer, free all contained strings and structures within the
 24.1972 +structure, and finally free the structure itself and set its pointer to
 24.1973 +NIL.  For example, mail_free_envelope() frees all the ADDRESS structures
 24.1974 +contained in the envelope.
 24.1975 +
 24.1976 +     Normally, mail_free_elt() and mail_free_lelt() are used only if the
 24.1977 +main program has a private pointer to cache elements.  If so, it is
 24.1978 +expected to increment the cache element's lockcount when it makes a
 24.1979 +private pointer, and to call this function when it is finished with it.
 24.1980 +
 24.1981 +		       Authentication Functions
 24.1982 +
 24.1983 +char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]);
 24.1984 +	mechanism authentication mechanism name
 24.1985 +	resp	callback function for providing responses
 24.1986 +	argc	main() function argc value
 24.1987 +	argv	main() function argv value
 24.1988 +
 24.1989 +     This server function searches the list of authenticators that was
 24.1990 +established by auth_link() for an authenticator with the given name.  If
 24.1991 +an authenticator is found, authentication is initialized.  The function
 24.1992 +pointed to by resp is called as the authenticator requires responses.
 24.1993 +
 24.1994 +
 24.1995 +AUTHENTICATOR *mail_lookup_auth (unsigned int i);
 24.1996 +	i	position in authenticator list
 24.1997 +
 24.1998 +     This function returns the nth authenticator in the list, where n is
 24.1999 +the value of it.
 24.2000 +
 24.2001 +
 24.2002 +unsigned int mail_lookup_auth_name (char *mechanism);
 24.2003 +	mechanism authentication mechanism name
 24.2004 +
 24.2005 +     This function searches the list of authenticators for an
 24.2006 +authenticator with the given name, and returns its position in the
 24.2007 +authenticator list.
 24.2008 +
 24.2009 +
 24.2010 +     The functions below are provided by c-client client drivers or by
 24.2011 +servers to support the protocol-dependent parts of authentication.
 24.2012 +
 24.2013 +typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
 24.2014 +	stream	stream to read challenge
 24.2015 +	len	pointer to returned length in octets
 24.2016 +
 24.2017 +     This driver function is called by an authenticator to read a
 24.2018 +challenge from the given protocol stream in a protocol-dependent way.
 24.2019 +It returns that challenge in binary and its length in octets to the
 24.2020 +authenticator.
 24.2021 +
 24.2022 +
 24.2023 +typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
 24.2024 +	stream	stream to send response
 24.2025 +	s	response string
 24.2026 +	size	length of response string in octets
 24.2027 +
 24.2028 +     This driver function is called by an authenticator to send a
 24.2029 +challenge response to the given stream in a protocol-dependent way.
 24.2030 +It returns T if successful, NIL if failure.
 24.2031 +
 24.2032 +
 24.2033 +typedef char *(*authresponse_t) (void *challenge,unsigned long clen,
 24.2034 +				 unsigned long *rlen);
 24.2035 +	challenge challenge string
 24.2036 +	clen	length of challenge string in octets
 24.2037 +	rlen	pointer to returned length of response string
 24.2038 +
 24.2039 +     This server function is called with a challenge string of clen
 24.2040 +octets.  It sends, according to whatever protocol (IMAP, POP, etc.) it
 24.2041 +uses, and returns the received response and response length in octets.
 24.2042 +
 24.2043 +
 24.2044 +typedef long (*authclient_t) (authchallenge_t challenger,
 24.2045 +			      authrespond_t responder,NETMBX *mb,void *s,
 24.2046 +			      unsigned long trial);
 24.2047 +	challenger pointer to protocol-dependent challenge reader function
 24.2048 +	responder pointer to protocol-dependent response sender function
 24.2049 +	mb	NETMBX struct of the mailbox desired to open
 24.2050 +	s	stream for protocol-dependent routines to use
 24.2051 +	trial	number of authentication attempts remaining
 24.2052 +
 24.2053 +     This client authenticator function negotiates reading challenges
 24.2054 +and sending responses for a particular authenticator (Kerberos, etc.)
 24.2055 +over the protocol, and returns T if authenticated or NIL if failed.
 24.2056 +
 24.2057 +
 24.2058 +typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]);
 24.2059 +	responder pointer to protocol-dependent responder function
 24.2060 +	argc	main() function argc value
 24.2061 +	argv	main() function argv value
 24.2062 +
 24.2063 +    This server authenticator function negotiates sending challenges and
 24.2064 +reading responses for a particular authenticator (Kerberos, etc.), and
 24.2065 +returns either the authenticated user name or NIL if authentication
 24.2066 +failed.
 24.2067 +
 24.2068 +		       Network Access Functions
 24.2069 +
 24.2070 +     These functions provide a layer of indirection between the TCP
 24.2071 +routines and upper level routines.  This makes it possible to insert
 24.2072 +additional code (e.g. privacy or checksum handling).
 24.2073 +
 24.2074 +NETSTREAM *net_open (char *host,char *service,unsigned long port);
 24.2075 +	host	host name
 24.2076 +	service	contact service name
 24.2077 +	port	contact port number
 24.2078 +
 24.2079 +     This function opens a TCP connection to the given host and service
 24.2080 +or port.
 24.2081 +
 24.2082 +
 24.2083 +NETSTREAM *net_aopen (NETMBX *mb,char *service,char *usrbuf);
 24.2084 +	NETMBX	parsed mailbox specification
 24.2085 +	service	stream to open (at present, only /etc/rimapd is used)
 24.2086 +	usrbuf	buffer to return login user name
 24.2087 +
 24.2088 +     This function attempts to open a preauthenticated connection to the
 24.2089 +given mailbox and service.  It will return the login user name of the
 24.2090 +preauthenticated connection, as well as an open network stream, if
 24.2091 +successful.
 24.2092 +
 24.2093 +
 24.2094 +char *net_getline (NETSTREAM *stream);
 24.2095 +	stream	network stream to read
 24.2096 +
 24.2097 +     This routine reads a text line from the stream.  It calls
 24.2098 +stream->dtb->getline, which normally points to tcp_getline() but can be
 24.2099 +set to some other function.
 24.2100 +
 24.2101 +
 24.2102 +long net_getbuffer (void *stream,unsigned long size,char *buffer);
 24.2103 +	stream	network stream to read
 24.2104 +	size	length of data in octets
 24.2105 +	buffer	buffer of at least size octets
 24.2106 +
 24.2107 +     This routine reads data from the stream.  It calls
 24.2108 +stream->dtb->getbuffer, which normally points to tcp_getbuffer() but can
 24.2109 +be set to some other function.
 24.2110 +
 24.2111 +
 24.2112 +long net_soutr (NETSTREAM *stream,char *string);
 24.2113 +	stream	network stream to write
 24.2114 +	string	null-terminated string to output
 24.2115 +
 24.2116 +     This routine writes a null-terminated string to the stream.  It
 24.2117 +calls stream->dtb->soutr, which normally points to tcp_soutr() but can
 24.2118 +be set to some other function.
 24.2119 +
 24.2120 +
 24.2121 +long net_sout (NETSTREAM *stream,char *string,unsigned long size);
 24.2122 +	stream	network stream to write
 24.2123 +	string	string to output
 24.2124 +	size	length of string in octets
 24.2125 +
 24.2126 +     This routine writes a string of length size to the stream.  It
 24.2127 +calls stream->dtb->sout, which normally points to tcp_sout() but can be
 24.2128 +set to some other function.
 24.2129 +
 24.2130 +
 24.2131 +void net_close (NETSTREAM *stream);
 24.2132 +	stream	stream to close
 24.2133 +
 24.2134 +     This routine closes the stream.  It calls stream->dtb->close, which
 24.2135 +normally points to tcp_close() but can point to some other function.
 24.2136 +
 24.2137 +
 24.2138 +char *net_host (NETSTREAM *stream);
 24.2139 +	stream	stream to inspect
 24.2140 +
 24.2141 +     This routine returns the remote host name of the stream.  It calls
 24.2142 +stream->dtb->host, which normally points to tcp_host() but can point
 24.2143 +to some other function.
 24.2144 +
 24.2145 +
 24.2146 +unsigned long net_port (NETSTREAM *stream);
 24.2147 +	stream	stream to inspect
 24.2148 +
 24.2149 +     This routine returns the remote port number of the stream.  It calls
 24.2150 +stream->dtb->port, which normally points to tcp_port() but can point
 24.2151 +to some other function.
 24.2152 +
 24.2153 +
 24.2154 +char *net_localhost (NETSTREAM *stream);
 24.2155 +	stream	stream to inspect
 24.2156 +
 24.2157 +     This routine returns the local host name of the stream.  It calls
 24.2158 +stream->dtb->localhost, which normally points to tcp_localhost() but can
 24.2159 +point to some other function.
 24.2160 +
 24.2161 +		  Subscription Management Functions
 24.2162 +
 24.2163 +long sm_subscribe (char *mailbox);
 24.2164 +	mailbox	mailbox name to subscribe
 24.2165 +
 24.2166 +     This function adds the given mailbox name to the local subscription
 24.2167 +list, and returns T if successful, NIL if failure.
 24.2168 +
 24.2169 +
 24.2170 +long sm_unsubscribe (char *mailbox);
 24.2171 +	mailbox	mailbox name to unsubscribe
 24.2172 +
 24.2173 +     This function removes the given mailbox name from the local
 24.2174 +subscription list, and returns T if successful, NIL if failure.
 24.2175 +
 24.2176 +char *sm_read (void **sdb);
 24.2177 +	sdb	data to use in subsequent calls, or NIL if first call
 24.2178 +
 24.2179 +     This function returns the local subscription list as null
 24.2180 +terminated strings.  Each call returns the next element in the list.
 24.2181 +The first call should be with sdb pointing to a NIL pointer; this will
 24.2182 +be filled in for subsequent calls.  At the last call, NIL will be
 24.2183 +returned.
 24.2184 +
 24.2185 +		    Miscellaneous Utility Functions
 24.2186 +
 24.2187 +char *ucase (char *string);
 24.2188 +	string	string to convert
 24.2189 +
 24.2190 +     This function converts each lowercase character of the specified
 24.2191 +string to uppercase and returns the string.
 24.2192 +
 24.2193 +
 24.2194 +char *lcase (char *string);
 24.2195 +	string	string to convert
 24.2196 +
 24.2197 +     This function converts each uppercase character of the specified
 24.2198 +string to lowercase and returns the string.
 24.2199 +
 24.2200 +
 24.2201 +char *cpystr (char *string);
 24.2202 +	string	string to copy
 24.2203 +
 24.2204 + This function makes a copy of the string from free storage and returns
 24.2205 +the copy.
 24.2206 +
 24.2207 +
 24.2208 +long find_rightmost_bit (long *valptr);
 24.2209 +	valptr	pointer to value to search
 24.2210 +
 24.2211 +      This function returns -1 if the 32-bit value pointed to by valptr
 24.2212 +is non-zero, otherwise it returns the bit number (0 = LSB, 31 = MSB) of
 24.2213 +the right-most bit in that value.  This is used to convert from the bits
 24.2214 +in the cache's userflags item to an index into the stream's userFlags
 24.2215 +array of flag texts.
 24.2216 +
 24.2217 +
 24.2218 +long min (long i,long j);
 24.2219 +	i	first argument
 24.2220 +	j	second argument
 24.2221 +
 24.2222 +      This function returns the minimum of the two integers.
 24.2223 +
 24.2224 +long max (long i,long j);
 24.2225 +	i	first argument
 24.2226 +	j	second argument
 24.2227 +
 24.2228 +     This function returns the maximum of the two integers.
 24.2229 +
 24.2230 +long search (char *s,long c,char *pat,long patc);
 24.2231 +	s	string to search
 24.2232 +	c	size of string
 24.2233 +	pat	pattern to search in string
 24.2234 +	patc	size of pattern
 24.2235 +
 24.2236 +      This function does a fast case-independent search for the given
 24.2237 +pattern in pat (length patc) in base string s, and returns T if the
 24.2238 +pattern is found in the string.
 24.2239 +
 24.2240 +
 24.2241 +long pmatch (char *s,char *pat,delim);
 24.2242 +long pmatch_full (char *s,char *pat,delim);
 24.2243 +	s	string to match
 24.2244 +	pat	wildcard (* and %) to match in pattern
 24.2245 +	delim	hierarchy delimiter
 24.2246 +
 24.2247 +      This function returns T if the given wildcard pattern matches the
 24.2248 +string in s with hierarchy delimiter delim.  Otherwise NIL is returned.
 24.2249 +
 24.2250 +
 24.2251 +long dmatch (char *s,char *pat,char delim);
 24.2252 +	s	string to match
 24.2253 +	pat	wildcard (* and %) to match in pattern
 24.2254 +	delim	hierarchy delimiter
 24.2255 +
 24.2256 +     This function returns T if the given wildcard pattern matches the
 24.2257 +directory.  If not, then none of the elements in the directory are
 24.2258 +considered for recursive checking with pmatch_full().
 24.2259 +
 24.2260 +			     SMTP Functions
 24.2261 +
 24.2262 +SMTPSTREAM *smtp_open (char **hostlist,long debug);
 24.2263 +	hostlist vector of SMTP server host names to try
 24.2264 +	debug	non-zero if want protocol telemetry debugging
 24.2265 +
 24.2266 +      This function opens an SMTP connection to a one of the hosts in the
 24.2267 +host list and if successful returns a stream suitable for use by the
 24.2268 +other SMTP functions.  The hosts are tried in order until a connection is
 24.2269 +successfully opened.  If debug is non-NIL, protocol telemetry is logged
 24.2270 +via mm_dlog().  NIL is returned if this function fails to open a
 24.2271 +connection to any of the hosts in the list.
 24.2272 +
 24.2273 +void smtp_close (SMTPSTREAM *stream);
 24.2274 +	stream	stream to close
 24.2275 +
 24.2276 +     This function closes the SMTP stream and frees all resources
 24.2277 +associated with it that it may have created.
 24.2278 +
 24.2279 +long smtp_mail (SMTPSTREAM *stream,char *type,ENVELOPE *msg,BODY *body);
 24.2280 +	stream	stream to transmit mail
 24.2281 +	type	mail type (MAIL, SEND, SAML, SOML)
 24.2282 +	msg	message envelope
 24.2283 +	body	message body
 24.2284 +
 24.2285 +      This function negotiates an SMTP transaction of the specified type
 24.2286 +(one of "MAIL", "SEND", "SAML", or "SOML") to deliver the specified
 24.2287 +message.  This function returns T if success or NIL if there is any
 24.2288 +failure.  The text reason for the failure is in stream->reply item; if
 24.2289 +it is associated with a recipient it is also in that address'
 24.2290 +address->error item.
 24.2291 +
 24.2292 +
 24.2293 +void smtp_debug (SMTPSTREAM *stream);
 24.2294 +	stream	stream to enable debugging telemetry
 24.2295 +
 24.2296 +      This function enables SMTP protocol telemetry logging for this
 24.2297 +stream.  All SMTP protocol operations are passed to the application via
 24.2298 +the mm_dlog() facility.
 24.2299 +
 24.2300 +
 24.2301 +void smtp_nodebug (SMTPSTREAM *stream);
 24.2302 +	stream	stream to disable debugging telemetry
 24.2303 +
 24.2304 +      This function disables SMTP protocol telemetry logging for this
 24.2305 +stream.
 24.2306 +
 24.2307 +
 24.2308 +typedef void (*smtpverbose_t) (char *buffer);
 24.2309 +	buffer	pointer to verbose reply buffer
 24.2310 +
 24.2311 +     This is the argument to the SET_SMTPVERBOSE mail_parmameter() call.
 24.2312 +If this function pointer is non-NIL, then if a verbose SMTP response
 24.2313 +(with SMTP code less than 100) is received, this function is called with
 24.2314 +that response text as its argument.
 24.2315 +
 24.2316 +			     NNTP Functions
 24.2317 +
 24.2318 +NNTPSTREAM *nntp_open (char **hostlist,long debug);
 24.2319 +	hostlist vector of NNTP server host names to try
 24.2320 +	debug	non-zero if want protocol telemetry debugging
 24.2321 +
 24.2322 +      This function opens an NNTP connection to a one of the hosts in the
 24.2323 +host list and if successful returns a stream suitable for use by the
 24.2324 +other MTP functions.  The hosts are tried in order until a connection is
 24.2325 +successfully opened.  If debug is non-NIL, protocol telemetry is logged
 24.2326 +via mm_dlog().  NIL is returned if this function fails to open a
 24.2327 +connection to any of the hosts in the list.
 24.2328 +
 24.2329 +
 24.2330 +void nntp_close (NNTPSTREAM *stream);
 24.2331 +	stream	stream to close
 24.2332 +
 24.2333 +     This function closes the NNTP stream and frees all resources
 24.2334 +associated with it that it may have created.
 24.2335 +
 24.2336 +
 24.2337 +long nntp_mail (NNTPSTREAM *stream,ENVELOPE *msg,BODY *body);
 24.2338 +	stream	stream to transmit mail
 24.2339 +	msg	message envelope
 24.2340 +	body	message body
 24.2341 +
 24.2342 +      This function negotiates an NNTP posting transaction to deliver
 24.2343 +the specified news message.  This function returns T if success or NIL
 24.2344 +if there is any failure.  The text reason for the failure is in
 24.2345 +stream->reply item; if it is associated with a recipient it is also in
 24.2346 +that address' address->error item.
 24.2347 +
 24.2348 +		      RFC 822 Support Functions
 24.2349 +
 24.2350 +     Although rfc822.c contains several additional functions besides
 24.2351 +these, only the functions documented here should be used by
 24.2352 +applications.  The other functions are for internal use only.
 24.2353 +
 24.2354 +
 24.2355 +void rfc822_header (char *header,ENVELOPE *env,BODY *body);
 24.2356 +	header	buffer to write RFC 822 header
 24.2357 +	env	message ENVELOPE (used to obtain RFC 822 information)
 24.2358 +	body	message BODY (used to obtain MIME information)
 24.2359 +
 24.2360 +     This function writes an RFC 822 format header into header based
 24.2361 +on the information in the envelope and body.  The header buffer must
 24.2362 +be large enough to contain the full text of the resulting header.
 24.2363 +
 24.2364 +
 24.2365 +void rfc822_write_address (char *dest,ADDRESS *adr);
 24.2366 +	dest	buffer to write address list
 24.2367 +	adr	RFC 822 ADDRESS list
 24.2368 +
 24.2369 +     This function writes an RFC 822 format address list into dest
 24.2370 +based on the information in adr.  The dest buffer must be large enough
 24.2371 +to contain the full text of the resulting address list.
 24.2372 +
 24.2373 +void rfc822_parse_msg (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
 24.2374 +		       STRING *b,char *host,char *tmp);
 24.2375 +	en	destination pointer where message ENVELOPE will be stored
 24.2376 +	bdy	destination pointer where message BODY will be stored
 24.2377 +	s	RFC 822 header to parse (character string)
 24.2378 +	i	length of RFC 822 header
 24.2379 +	b	stringstruct of message body
 24.2380 +	host	default host name if an address lacks an @host.
 24.2381 +	temp	scratch buffer, must be long enough to hold unwound
 24.2382 +		 header lines (a buffer that is i octets long is OK)
 24.2383 +
 24.2384 +     This function parses the RFC 822 header pointed to by s with body
 24.2385 +pointed to by string structure b into the specified destination
 24.2386 +envelope and body pointers, using host as the default host name and
 24.2387 +tmp as a scratch buffer.  New ENVELOPE and BODY structures are
 24.2388 +created; when finished with them the application must free them with
 24.2389 +mail_free_envelope() and mail_free_body().  Any parsing errors are
 24.2390 +noted via the mm_log() mechanism using log type PARSE.
 24.2391 +
 24.2392 +
 24.2393 +void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host);
 24.2394 +	lst	destination pointer where ADDRESS will be stored
 24.2395 +	string	string of addresses to parse
 24.2396 +	host	default host name if an address lacks an @host.
 24.2397 +
 24.2398 +     This function parses the address list in the given string into an
 24.2399 +address list in lst.  Any addresses missing a host name are have the
 24.2400 +host name defaulted from the host argument.  If the destination list
 24.2401 +is non-empty it appends the new addresses to the list.  Any parsing
 24.2402 +errors are noted via the mm_log() mechanism using log type PARSE.
 24.2403 +
 24.2404 +long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
 24.2405 +		    long ok8bit);
 24.2406 +	t	scratch buffer, large enough to hold message header
 24.2407 +	env	message ENVELOPE
 24.2408 +	body	message BODY
 24.2409 +	f	I/O function to write to
 24.2410 +	s	stream for I/O function f
 24.2411 +	ok8bit	non-zero if OK to output 8-bit data
 24.2412 +
 24.2413 +     This function writes the message described with the given
 24.2414 +envelope and body.  Any body part contents of type ENCBINARY is
 24.2415 +converted to ENCBASE64 before sending.  If ok8bit is NIL, any message
 24.2416 +data of type ENC8BIT is converted to ENCQUOTEDPRINTABLE before
 24.2417 +sending; if ok8bit is non-NIL then ENC8BIT data is sent as-is.  T is
 24.2418 +returned if the function succeeds, else NIL is returned.
 24.2419 +
 24.2420 +     The function f is typically net_soutr(), but it can be any
 24.2421 +function which matches
 24.2422 +  typedef long (*soutr_t) (void *stream,char *string);
 24.2423 +where stream holds sufficient information to enable the output routine
 24.2424 +to know where to output to, and the string is a null-terminated string
 24.2425 +to output.  This function returns either T or NIL, and that value is
 24.2426 +passed up to rfc822_output() for its return.
 24.2427 +
 24.2428 +
 24.2429 +void *rfc822_base64 (char *src,unsigned long srcl,unsigned long *len);
 24.2430 +	src	source string
 24.2431 +	srcl	size of source string in octets
 24.2432 +	len	pointer to where destination string length in octets
 24.2433 +		 will be returned
 24.2434 +
 24.2435 +     This function decodes a BASE64 body part given a source string
 24.2436 +and its length.  The decoded body part as a sequence of binary octets
 24.2437 +is returned, and its length is returned in len.
 24.2438 +
 24.2439 +
 24.2440 +char *rfc822_qprint (char *src,unsigned long srcl,unsigned long *len);
 24.2441 +	src	source string
 24.2442 +	srcl	size of source string in octets
 24.2443 +	len	pointer to where destination string length in octets
 24.2444 +		 will be returned
 24.2445 +
 24.2446 +     This function decodes a QUOTED-PRINTABLE body part given a source
 24.2447 +string and its length.  The decoded body part as an 8-bit character
 24.2448 +string is returned, and its length is returned in len.
 24.2449 +
 24.2450 +	     Operating System-Dependent Public Interface
 24.2451 +
 24.2452 +     These functions are in OS-dependent code, and are rewritten each
 24.2453 +time c-client is ported to a new operating system.
 24.2454 +
 24.2455 +
 24.2456 +void rfc822_date (char *date);
 24.2457 +	date	buffer to write the date, must be large enough
 24.2458 +
 24.2459 +     This function is called to get the current date and time in an
 24.2460 +RFC 822 format string into the given buffer.
 24.2461 +
 24.2462 +
 24.2463 +void *fs_get (size_t size);
 24.2464 +	size	number of octets requested
 24.2465 +
 24.2466 +      This function allocates and returns a block of free storage of
 24.2467 +the specified size.  Unlike malloc(), there is no failure return; this
 24.2468 +function must return with the requested storage.
 24.2469 +
 24.2470 +
 24.2471 +void fs_resize (void **block,size_t size);
 24.2472 +	block	pointer to pointer to block to be resized
 24.2473 +	size	new size in octets
 24.2474 +
 24.2475 +     This function resizes the free storage block, updating the
 24.2476 +pointer if necessary.  Unlike realloc(), there is no failure return;
 24.2477 +this function must return with the requested storage.
 24.2478 +
 24.2479 +
 24.2480 +void fs_give (void **block);
 24.2481 +	block	pointer to pointer to block to free
 24.2482 +
 24.2483 +      This function releases a block of free storage allocated by
 24.2484 +fs_get().  It also erases the block pointer, so it isn't necessary to
 24.2485 +do this in the application.
 24.2486 +
 24.2487 +
 24.2488 +void fatal (char *string);
 24.2489 +	string	message string
 24.2490 +
 24.2491 +      This function is called when an "impossible" error is detected
 24.2492 +and the client wishes to crash.  The string should contain a reason.
 24.2493 +
 24.2494 +
 24.2495 +char *strcrlfcpy (char **dst,long *dstl,char *src,long srcl);
 24.2496 +	dst	pointer to destination string pointer
 24.2497 +	dstl	pointer to destination string size
 24.2498 +	src	source strin
 24.2499 +	srcl	source string size
 24.2500 +
 24.2501 +      This function is called to copy into a destination string dst of
 24.2502 +size dstl (resized if necessary), a CRLF newline form string from
 24.2503 +local format string src of size srcl.
 24.2504 +
 24.2505 +
 24.2506 +TCPSTREAM *tcp_open (char *host,long port);
 24.2507 +TCPSTREAM *tcp_aopen (char *host,char *service);
 24.2508 +char *tcp_getline (TCPSTREAM *stream);
 24.2509 +long tcp_getbuffer (TCPSTREAM *stream,long size,char *buffer);
 24.2510 +long tcp_soutr (TCPSTREAM *stream,char *string);
 24.2511 +void tcp_close (TCPSTREAM *stream);
 24.2512 +char *tcp_host (TCPSTREAM *stream);
 24.2513 +unsigned long tcp_port (TCPSTREAM *stream);
 24.2514 +char *tcp_localhost (TCPSTREAM *stream);
 24.2515 +
 24.2516 +     These functions are TCP-specific versions of the more general
 24.2517 +net_xxx() functions.  These should not be called directly by
 24.2518 +applications.
 24.2519 +
 24.2520 +
 24.2521 +char *tcp_clienthost (char *dst);
 24.2522 +	dst	destination string buffer
 24.2523 +
 24.2524 +     This function should be called only by a server called by inetd
 24.2525 +or similar mechanism which maps standard input to a network socket.
 24.2526 +It returns the host name of the other end (e.g. the client of a
 24.2527 +server) using the given string buffer, or NIL if it can't get this
 24.2528 +information.
 24.2529 +
 24.2530 +			Main Program Callbacks
 24.2531 +
 24.2532 +     All applications which use the c-client must have the following
 24.2533 +callbacks to handle events from c-client.  Note that in any callback
 24.2534 +which involves a mail stream, the stream is locked and you can not
 24.2535 +recursively call c-client from the callback.  This may also be true in
 24.2536 +callbacks which do not have a stream; in general, the rule is "do not
 24.2537 +call c-client, especially any mail_xxx() function, from a c-client
 24.2538 +callback".
 24.2539 +
 24.2540 +
 24.2541 +void mm_flags (MAILSTREAM *stream,unsigned long number);
 24.2542 +	stream	stream where event happened
 24.2543 +	number	message number
 24.2544 +
 24.2545 +     This function is called when c-client manipulates the flags for
 24.2546 +the given message number.  This alerts the application that it may
 24.2547 +need to inspect that message's flags to see if there are any
 24.2548 +interesting changes.
 24.2549 +
 24.2550 +
 24.2551 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
 24.2552 +	stream	stream where event happened
 24.2553 +	mailbox	mailbox name for this status
 24.2554 +	status	MAILSTATUS structure with message status
 24.2555 +
 24.2556 +     This function is called when c-client reports status of a mailbox
 24.2557 +(generally as the result of a mail_status() function call).  The
 24.2558 +returned MAILSTATUS structure has the following members:
 24.2559 +
 24.2560 +long flags;			validity flags.  These are the same as
 24.2561 +				 the SA_xxx option flags in the
 24.2562 +				 mail_status() call, and they indicate
 24.2563 +				 which of the other members of the
 24.2564 +				 MAILSTATUS structure have usable data
 24.2565 +				 (i.e. if SA_MESSAGES is not set, do
 24.2566 +				 not believe status->messages!!).
 24.2567 +unsigned long messages;		number of messages if SA_MESSAGES
 24.2568 +unsigned long recent;		number of recent messages if SA_RECENT
 24.2569 +unsigned long unseen;		number of unseen messages if SA_UNSEEN
 24.2570 +unsigned long uidnext;		next UID to be assigned if SA_UIDNEXT
 24.2571 +unsigned long uidvalidity;	UID validity value if SA_UIDVALIDITY
 24.2572 +
 24.2573 +
 24.2574 +void mm_searched (MAILSTREAM *stream,unsigned long number);
 24.2575 +	stream	stream where event happened
 24.2576 +	number	message number
 24.2577 +
 24.2578 +     This function is called to notify the main program that this
 24.2579 +message number matches a search (generally as the result of a
 24.2580 +mail_search_full() function call).
 24.2581 +
 24.2582 +
 24.2583 +void mm_exists (MAILSTREAM *stream,unsigned long number);
 24.2584 +	stream	stream where event happened
 24.2585 +	number	message number
 24.2586 +
 24.2587 +     This function is called to notify the main program that there are
 24.2588 +this many messages in the mailbox.  It is also used to notify the main
 24.2589 +program of new mail, by announcing a higher number than the main
 24.2590 +program was previously aware.
 24.2591 +
 24.2592 +
 24.2593 +void mm_expunged (MAILSTREAM *stream,unsigned long number);
 24.2594 +	stream	stream where event happened
 24.2595 +	number	message number
 24.2596 +
 24.2597 +     This function is called to notify the main program that this
 24.2598 +message number has been expunged from the mail file and that all
 24.2599 +subsequent messages are now referenced by a message number one less
 24.2600 +than before.  This implicitly decrements the number of messages in the
 24.2601 +mailbox.
 24.2602 +
 24.2603 +
 24.2604 +void mm_list (MAILSTREAM *stream,char delim,char *name,long attrib);
 24.2605 +	stream	stream where event happened
 24.2606 +	delim	hierarchy delimiter
 24.2607 +	name	mailbox name
 24.2608 +	attrib	mailbox attributes
 24.2609 +
 24.2610 +     This function is called to notify the main program that this
 24.2611 +mailbox name matches a mailbox listing request (generally as the
 24.2612 +result of a mail_list() function call).  The hierarchy delimiter is a
 24.2613 +character that separates out levels of hierarchy in mailbox names.
 24.2614 +The attributes are a bit mask with one of the following:
 24.2615 +	LATT_NOINFERIORS
 24.2616 +			it is not possible for there to be any
 24.2617 +			 hierarchy inferiors to this name (that is,
 24.2618 +			 this name followed by the hierarchy delimiter
 24.2619 +			 and additional name characters).
 24.2620 +	LATT_NOSELECT	this is not a mailbox name, just a hierarchy
 24.2621 +			 level, and it may not be opened by mail_open()
 24.2622 +	LATT_MARKED	this mailbox may have recent messages
 24.2623 +	LATT_UNMARKED	this mailbox does not have any recent messages
 24.2624 +
 24.2625 +
 24.2626 +void mm_lsub (MAILSTREAM *stream,char delim,char *name,long attrib);
 24.2627 +	stream	stream where event happened
 24.2628 +	delim	hierarchy delimiter
 24.2629 +	name	mailbox name
 24.2630 +	attrib	mailbox attributes
 24.2631 +
 24.2632 +
 24.2633 +     This function is called to notify the main program that this
 24.2634 +mailbox name matches a subscribed mailbox listing request (generally
 24.2635 +as the result of a mail_lsub() function call).  The hierarchy
 24.2636 +delimiter is a character that separates out levels of hierarchy in
 24.2637 +mailbox names.  The attributes are a bit mask with one of the
 24.2638 +following:
 24.2639 +	LATT_NOINFERIORS
 24.2640 +			it is not possible for there to be any
 24.2641 +			 hierarchy inferiors to this name (that is,
 24.2642 +			 this name followed by the hierarchy delimiter
 24.2643 +			 and additional name characters).
 24.2644 +	LATT_NOSELECT	this is not a mailbox name, just a hierarchy
 24.2645 +			 level, and it may not be opened by mail_open()
 24.2646 +	LATT_MARKED	this mailbox may have recent messages
 24.2647 +	LATT_UNMARKED	this mailbox does not have any recent messages
 24.2648 +
 24.2649 +
 24.2650 +void mm_notify (MAILSTREAM *stream,char *string,long errflg);
 24.2651 +	stream	stream where event happened
 24.2652 +	string	message string
 24.2653 +	errflg	message error level
 24.2654 +
 24.2655 +     This function is called to deliver a stream-oriented message
 24.2656 +event.  This is the mechanism by which any IMAP response codes for any
 24.2657 +application (e.g. TRYCREATE) are delivered to the application.
 24.2658 +No newline is included in the string, so this function has to output
 24.2659 +its own.
 24.2660 +
 24.2661 +     The message error level is one of the following:
 24.2662 +
 24.2663 +	NIL	normal operation.  The text is `babble' that may be
 24.2664 +		interesting to the user, e.g. the greeting message
 24.2665 +		from a server.
 24.2666 +
 24.2667 +	WARN	A warning event.  This event should be displayed to
 24.2668 +		the user.  Examples: a mailbox rewrite failed because
 24.2669 +		of disk full, but the previous mailbox contents were
 24.2670 +		recovered.
 24.2671 +
 24.2672 +	ERROR	An error event.  This event should be displayed to
 24.2673 +		the user, or at least logged someplace.  This type of
 24.2674 +		error shouldn't happen, and so should be called to the
 24.2675 +		attention of support staff.  Whatever happened has
 24.2676 +		probably disrupted the user's work.  Examples: an
 24.2677 +		untagged BAD from an IMAP server.
 24.2678 +
 24.2679 +
 24.2680 +void mm_log (char *string,long errflg);
 24.2681 +	string	message string
 24.2682 +	errflg	message error level
 24.2683 +
 24.2684 +      This function is called to deliver a log message.  No newline is
 24.2685 +included in the string, so this function has to output its own.  In
 24.2686 +general, it is intended that these messages are logged someplace, and
 24.2687 +possibly shown to the user.
 24.2688 +
 24.2689 +     The message error level is one of the following:
 24.2690 +
 24.2691 +	NIL	normal operation.  The text is `babble' that may be
 24.2692 +		interesting to the user, e.g. "Expunged 3 messages".
 24.2693 +
 24.2694 +	PARSE	An RFC 822 parsing error.  Since bogus headers are
 24.2695 +		all-too-common in the real world, these can often be
 24.2696 +		ignored on the "garbage in, garbage out" princple.
 24.2697 +		However, since surprising results can be yielded when
 24.2698 +		trying to parse garbage, this message should be logged
 24.2699 +		somewhere so it can be figured out what happened.
 24.2700 +
 24.2701 +	WARN	A warning event.  This event should be displayed to
 24.2702 +		the user.  It occurs when an error condition has
 24.2703 +		happened, but c-client knows what to do to recover.
 24.2704 +		Examples: "Can't open read-write, so opening
 24.2705 +		read-only", "Empty mailbox", "Login failed, try
 24.2706 +		again", "Waiting for mailbox to become unlocked",
 24.2707 +		"IMAP protocol error".  Although a user should be
 24.2708 +		told about a warning, it's generally not necessary
 24.2709 +		to interrupt the flow of her work (e.g. it's alright
 24.2710 +		to display the warning in a scrolling window, but
 24.2711 +		not necessary to require the user to do anything).
 24.2712 +
 24.2713 +	ERROR	An error event.  This event should be displayed to
 24.2714 +		the user, or at least logged someplace.  This is a
 24.2715 +		serious error condition occured that aborted the
 24.2716 +		requested operation and possibly also aborted the mail
 24.2717 +		stream.  This ranges from normal error conditions such
 24.2718 +		as "Can't open mailbox", "too many login failures, go
 24.2719 +		away" to bizarre conditions such as "Apparent new mail
 24.2720 +		appeared in the mailbox that doesn't look like mail,
 24.2721 +		program aborting".  Errors must be called to the
 24.2722 +		user's attention, and probably should require some
 24.2723 +		sort of acknowledgement (e.g. answering a modal panel)
 24.2724 +		before the application proceeds.
 24.2725 +
 24.2726 +
 24.2727 +void mm_dlog (char *string);
 24.2728 +	string message string
 24.2729 +
 24.2730 +      This function is called to deliver a debugging telemetry
 24.2731 +message.  No newline is included in the string, so this function has
 24.2732 +to output its own.  This is called only when debugging is enabled.
 24.2733 +
 24.2734 +
 24.2735 +void mm_login (NETMBX *mb,char *user,char *pwd,long trial);
 24.2736 +	mb	parsed mailbox specification
 24.2737 +	user	pointer to where to return user name
 24.2738 +	pwd	pointer to where to return password
 24.2739 +	trial	number of prior login attempts
 24.2740 +
 24.2741 +      This function is called to get a user name and password for the
 24.2742 +given network mailbox.  It stores the user name and password in the
 24.2743 +strings pointed to by the appropriate arguments.  The trial argument
 24.2744 +is the number of attempts to perform the login and is initially zero
 24.2745 +(e.g. for a default username and password login functionality).  It is
 24.2746 +incremented for each subsequent trial until the maximum number of
 24.2747 +trials are made.
 24.2748 +
 24.2749 +
 24.2750 +void mm_critical (MAILSTREAM *stream);
 24.2751 +	stream	stream where event happened
 24.2752 +
 24.2753 +      This function is called to alert the application that c-client
 24.2754 +is about to run some critical code on that stream that may result in a
 24.2755 +clobbered mail file if it is interrupted.  It may be desirable to
 24.2756 +disable CTRL/C, etc. during this time.
 24.2757 +
 24.2758 +
 24.2759 +void mm_nocritical (MAILSTREAM *stream);
 24.2760 +	stream	stream where event happened
 24.2761 +
 24.2762 +      This function is called to alert the application that c-client
 24.2763 +is no longer running critical code on that stream that may result in a
 24.2764 +clobbered mail file if it is interrupted.
 24.2765 +
 24.2766 +
 24.2767 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious);
 24.2768 +	stream	stream where event happened
 24.2769 +	errcode	OS error code for disk error
 24.2770 +	serious	non-zero if c-client can not undo the operation (and
 24.2771 +		 thus must retry to avoid mail file damage)
 24.2772 +
 24.2773 +      This function is called to alert the application that the
 24.2774 +c-client has encountered an unrecoverable write error when trying to
 24.2775 +update the mail file.  errcode contains the system error code.  If
 24.2776 +serious is non-zero, then it is probable that the disk copy of the
 24.2777 +mailbox has been damaged.
 24.2778 +
 24.2779 +     The return value from this function is the abort flag; if serious
 24.2780 +is zero and the abort flag is non-zero, the operation is aborted.  If
 24.2781 +the abort flag is zero or if serious was non-zero, a return from this
 24.2782 +function will retry the failing operation.
 24.2783 +
 24.2784 +
 24.2785 +void mm_fatal (char *string);
 24.2786 +	string	message string
 24.2787 +
 24.2788 +      This function is called from the fatal() routine in the
 24.2789 +operating system code to notify the main program that it is about to
 24.2790 +crash.  The string contains a reason.  At the very minimum, the main
 24.2791 +program should do something like
 24.2792 + mm_log (string,ERROR);
 24.2793 +and then return.  No newline is included in the string, so this
 24.2794 +function has to output its own.
 24.2795 +
 24.2796 +			     Driver interface
 24.2797 +
 24.2798 +     When writing a new driver for the c-client, you must provide a
 24.2799 +DRIVER stucture giving a dispatch vector between MAIL and the driver.
 24.2800 +The DRIVER dispatch vector is described in mail.h.
 24.2801 +
 24.2802 +char *name;
 24.2803 +     Name by which the driver is known to c-client.
 24.2804 +
 24.2805 +unsigned long flags;
 24.2806 +     Attribute flags for this driver:
 24.2807 +	DR_DISABLE	This driver is currently disabled.
 24.2808 +	DR_LOCAL	This driver deals with local mailboxes; if
 24.2809 +			 this is off it deals with mailboxes over a
 24.2810 +			 network.
 24.2811 +	DR_MAIL		This driver supports e-mail messages.
 24.2812 +	DR_NEWS		This driver supports netnews messages
 24.2813 +	DR_READONLY	This driver only allows read-only access;
 24.2814 +			 mail_setflag(), mail_expunge(), etc. are
 24.2815 +			 no-ops.
 24.2816 +	DR_NOFAST	This driver does not implement mail_fetchfast()
 24.2817 +			 in a fast way (e.g. it may have to fetch the
 24.2818 +			 entire message text over a network to
 24.2819 +			 calculate sizes).
 24.2820 +	DR_NAMESPACE	This driver accepts and uses namespace format
 24.2821 +			 names.
 24.2822 +	DR_LOWMEM	This driver is designed for systems with very
 24.2823 +			 limited amounts of memory (e.g. DOS) and
 24.2824 +			 support routines called by this driver should
 24.2825 +			 try not to use much memory.
 24.2826 +
 24.2827 +DRIVER *next;
 24.2828 +     Pointer to the next driver which this application supports (or NIL if
 24.2829 +this is the last driver).  Drivers are lunk together via the mail_link()
 24.2830 +function.
 24.2831 +
 24.2832 +DRIVER *driver_valid (char *mailbox);
 24.2833 +     This function returns a pointer to the driver's DRIVER dispatch
 24.2834 +vector iff this driver accepts the given name as a valid mailbox for this
 24.2835 +driver.  Otherwise, it returns the value of the next driver's
 24.2836 +driver_valid() or NIL if there is no next driver.  In other words, calling
 24.2837 +driver_valid() for the first driver will return the driver dispatch vector
 24.2838 +for the driver which supports this type of mailbox.
 24.2839 +
 24.2840 +void *driver_parameters (long function,void *value);
 24.2841 +     This function implements mail_parameters() for this driver.
 24.2842 +
 24.2843 +void driver_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 24.2844 +     This function implements mail_scan() for this driver.
 24.2845 +
 24.2846 +void driver_list (MAILSTREAM *stream,char *ref,char *pat);
 24.2847 +     This function implements mail_list() for this driver.
 24.2848 +
 24.2849 +void driver_lsub (MAILSTREAM *stream,char *ref,char *pat);
 24.2850 +     This function implements mail_lsub() for this driver.
 24.2851 +
 24.2852 +long driver_subscribe (MAILSTREAM *stream,char *mailbox);
 24.2853 +     This function implements mail_subscribe() for this driver.
 24.2854 +
 24.2855 +long driver_unsubscribe (MAILSTREAM *stream,char *mailbox);
 24.2856 +     This function implements mail_unsubscribe() for this driver.
 24.2857 +
 24.2858 +long driver_create (MAILSTREAM *stream,char *mailbox);
 24.2859 +     This function implements mail_create() for this driver.
 24.2860 +
 24.2861 +long driver_delete (MAILSTREAM *stream,char *mailbox);
 24.2862 +     This function implements mail_delete() for this driver.
 24.2863 +
 24.2864 +long driver_rename (MAILSTREAM *stream,char *old,char *new);
 24.2865 +     This function implements mail_rename() for this driver.
 24.2866 +
 24.2867 +long driver_status (MAILSTREAM *stream,char *mailbox,long flags);
 24.2868 +     This function implements mail_status() for this driver.
 24.2869 +
 24.2870 +MAILSTREAM *driver_open (MAILSTREAM *stream);
 24.2871 +     This function opens the mailbox identified by the given stream.  It
 24.2872 +may use the data on the stream and create additional data on stream->local
 24.2873 +as necessary.  It should return the given stream unless it failed to open
 24.2874 +the mailbox, in which case it should return NIL.
 24.2875 +
 24.2876 +void driver_close (MAILSTREAM *stream,long options);
 24.2877 +     This function implements mail_close() for this driver.
 24.2878 +
 24.2879 +void driver_fetchfast (MAILSTREAM *stream,char *sequence,long flags);
 24.2880 +     This function implements mail_fetchfast() for this driver.
 24.2881 +
 24.2882 +void driver_fetchflags (MAILSTREAM *stream,char *sequence,long flags);
 24.2883 +     This function implements mail_fetchflags() for this driver.
 24.2884 +
 24.2885 +ENVELOPE *driver_fetchstructure (MAILSTREAM *stream,unsigned long msgno,
 24.2886 +				 BODY **body,long flags);
 24.2887 +     This function implements mail_fetchstructure() for this driver.
 24.2888 +
 24.2889 +char *driver_fetchheader (MAILSTREAM *stream,unsigned long msgno,
 24.2890 +			  STRINGLIST *lines,unsigned long *len,long flags);
 24.2891 +     This function implements mail_fetchheader() for this driver.
 24.2892 +
 24.2893 +char *driver_fetchtext (MAILSTREAM *stream,unsigned long msgno,
 24.2894 +			unsigned long *len,long flags);
 24.2895 +     This function implements mail_fetchtext() for this driver.
 24.2896 +
 24.2897 +char *driver_fetchbody (MAILSTREAM *stream,unsigned long msgno,char *section,
 24.2898 +			unsigned long *len,long flags);
 24.2899 +     This function implements mail_fetchbody() for this driver.
 24.2900 +
 24.2901 +void driver_setflag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 24.2902 +     This function implements mail_setflag() for this driver.
 24.2903 +
 24.2904 +void driver_clearflag (MAILSTREAM *stream,char *sequence,char *flag,
 24.2905 +		       long flags);
 24.2906 +     This function implements mail_clearflag() for this driver.
 24.2907 +
 24.2908 +void driver_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
 24.2909 +		    long flags);
 24.2910 +     This function implements mail_search() for this driver.
 24.2911 +
 24.2912 +unsigned long *driver_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 24.2913 +			    SORTPGM *pgm,long flags);
 24.2914 +     This function implements mail_sort() for this driver.
 24.2915 +
 24.2916 +void *driver_thread (MAILSTREAM *stream,char *seq,long function,long flag);
 24.2917 +     This dispatch is reserved for a future threading capability.
 24.2918 +
 24.2919 +long driver_ping (MAILSTREAM *stream);
 24.2920 +      This function implements mail_ping() for this driver.
 24.2921 +
 24.2922 +void driver_check (MAILSTREAM *stream);
 24.2923 +      This function implements mail_check() for this driver.
 24.2924 +
 24.2925 +void driver_expunge (MAILSTREAM *stream);
 24.2926 +      This function implements mail_expunge() for this driver.
 24.2927 +
 24.2928 +long driver_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
 24.2929 +		  long options);
 24.2930 +      This function implements mail_copy() for this driver.
 24.2931 +
 24.2932 +long driver_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
 24.2933 +		    STRING *message);
 24.2934 +      This function implements mail_append() for this driver.
 24.2935 +
 24.2936 +void driver_gc (MAILSTREAM *stream,long gcflags);
 24.2937 +      This function implements mail_gc() for this driver.
 24.2938 +
 24.2939 +			 Driver Support Functions
 24.2940 +
 24.2941 +void mail_searched (MAILSTREAM *stream,unsigned long msgno);
 24.2942 +	stream	stream where event happened
 24.2943 +	msgno	message number
 24.2944 +
 24.2945 +     This function is called by the driver to notify c-client that this
 24.2946 +message number matches a search.  It invokes the main program's
 24.2947 +mm_searched() function.
 24.2948 +
 24.2949 +void mail_exists (MAILSTREAM *stream,unsigned long nmsgs);
 24.2950 +	stream	stream where event happened
 24.2951 +	nmsgs	number of messages
 24.2952 +
 24.2953 +     This function is called by the driver to notify c-client that this
 24.2954 +message number exists (i.e. there are this many messages in the mailbox).
 24.2955 +It invokes the main program's mm_exists() function.
 24.2956 +
 24.2957 +void mail_recent (MAILSTREAM *stream,unsigned long recent);
 24.2958 +	stream	stream where event happened
 24.2959 +	recent	number of messages
 24.2960 +
 24.2961 +      This function is called by the driver to notify c-client that this
 24.2962 +many messages are "recent" (i.e. arrived in the mailbox since the previous
 24.2963 +time the mailbox was opened).
 24.2964 +
 24.2965 +void mail_expunged (MAILSTREAM *stream,unsigned long msgno);
 24.2966 +	stream	stream where event happened
 24.2967 +	msgno	number of messages
 24.2968 +
 24.2969 +      This function is called by the driver to notify MAIL that this
 24.2970 +message number has been expunged from the mail file and that all subsequent
 24.2971 +messages are now referenced by a message number one less than before.  It
 24.2972 +invokes the main program's mm_expunged() function.
 24.2973 +
 24.2974 +void mail_lock (MAILSTREAM *stream);
 24.2975 +	stream	stream where event happened
 24.2976 +      This function sets the stream lock.  It is an error to set the stream
 24.2977 +lock if the stream is already locked.
 24.2978 +
 24.2979 +      This is mainly used to catch errors due to a callback function
 24.2980 +(e.g. mm_exists) inadvertantly recursing back to the MAIL routines and
 24.2981 +establishing an infinite recursion.  Normally, drivers will set the lock
 24.2982 +prior to calling one of the callback functions above or, more likely, in
 24.2983 +the beginning of the driver's non-reentrant "do operation" section.  In the
 24.2984 +IMAP4 driver, the stream lock is set when entering imap_send() and cleared
 24.2985 +on exit.
 24.2986 +
 24.2987 +void mail_unlock (MAILSTREAM *stream);
 24.2988 +	stream	stream where event happened
 24.2989 +
 24.2990 +     This function releases the stream lock.  It is an error to release the
 24.2991 +stream lock if the stream is not locked.
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/docs/locking.txt	Mon Sep 14 15:17:45 2009 +0900
    25.3 @@ -0,0 +1,417 @@
    25.4 +/* ========================================================================
    25.5 + * Copyright 1988-2006 University of Washington
    25.6 + *
    25.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    25.8 + * you may not use this file except in compliance with the License.
    25.9 + * You may obtain a copy of the License at
   25.10 + *
   25.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   25.12 + *
   25.13 + * 
   25.14 + * ========================================================================
   25.15 + */
   25.16 +
   25.17 +	 UNIX Advisory File Locking Implications on c-client
   25.18 +		    Mark Crispin, 28 November 1995
   25.19 +
   25.20 +
   25.21 +	THIS DOCUMENT HAS BEEN UPDATED TO REFLECT THE FACT THAT
   25.22 +	LINUX SUPPORTS BOTH flock() AND fcntl() AND THAT OSF/1
   25.23 +	HAS BEEN BROKEN SO THAT IT ONLY SUPPORTS fcntl().
   25.24 +	-- JUNE 15, 2004
   25.25 +
   25.26 +	THIS DOCUMENT HAS BEEN UPDATED TO REFLECT THE CODE IN THE
   25.27 +	IMAP-4 TOOLKIT AS OF NOVEMBER 28, 1995.  SOME STATEMENTS
   25.28 +	IN THIS DOCUMENT DO NOT APPLY TO EARLIER VERSIONS OF THE
   25.29 +	IMAP TOOLKIT.
   25.30 +
   25.31 +INTRODUCTION
   25.32 +
   25.33 +     Advisory locking is a mechanism by which cooperating processes
   25.34 +can signal to each other their usage of a resource and whether or not
   25.35 +that usage is critical.  It is not a mechanism to protect against
   25.36 +processes which do not cooperate in the locking.
   25.37 +
   25.38 +     The most basic form of locking involves a counter.  This counter
   25.39 +is -1 when the resource is available.  If a process wants the lock, it
   25.40 +executes an atomic increment-and-test-if-zero.  If the value is zero,
   25.41 +the process has the lock and can execute the critical code that needs
   25.42 +exclusive usage of a resource.  When it is finished, it sets the lock
   25.43 +back to -1.  In C terms:
   25.44 +
   25.45 +  while (++lock)		/* try to get lock */
   25.46 +    invoke_other_threads ();	/* failed, try again */
   25.47 +   .
   25.48 +   .	/* critical code  here */
   25.49 +   .
   25.50 +  lock = -1;			/* release lock */
   25.51 +
   25.52 +     This particular form of locking appears most commonly in
   25.53 +multi-threaded applications such as operating system kernels.  It
   25.54 +makes several presumptions:
   25.55 + (1) it is alright to keep testing the lock (no overflow)
   25.56 + (2) the critical resource is single-access only
   25.57 + (3) there is shared writeable memory between the two threads
   25.58 + (4) the threads can be trusted to release the lock when finished
   25.59 +
   25.60 +     In applications programming on multi-user systems, most commonly
   25.61 +the other threads are in an entirely different process, which may even
   25.62 +be logged in as a different user.  Few operating systems offer shared
   25.63 +writeable memory between such processes.
   25.64 +
   25.65 +     A means of communicating this is by use of a file with a mutually
   25.66 +agreed upon name.  A binary semaphore can be passed by means of the
   25.67 +existance or non-existance of that file, provided that there is an
   25.68 +atomic means to create a file if and only if that file does not exist.
   25.69 +In C terms:
   25.70 +
   25.71 +				/* try to get lock */
   25.72 +  while ((fd = open ("lockfile",O_WRONLY|O_CREAT|O_EXCL,0666)) < 0)
   25.73 +    sleep (1);			/* failed, try again */
   25.74 +  close (fd);			/* got the lock */
   25.75 +   .
   25.76 +   .	/* critical code  here */
   25.77 +   .
   25.78 +  unlink ("lockfile"); 		/* release lock */
   25.79 +
   25.80 +     This form of locking makes fewer presumptions, but it still is
   25.81 +guilty of presumptions (2) and (4) above.  Presumption (2) limits the
   25.82 +ability to have processes sharing a resource in a non-conflicting
   25.83 +fashion (e.g. reading from a file).  Presumption (4) leads to
   25.84 +deadlocks should the process crash while it has a resource locked.
   25.85 +
   25.86 +     Most modern operating systems provide a resource locking system
   25.87 +call that has none of these presumptions.  In particular, a mechanism
   25.88 +is provided for identifying shared locks as opposed to exclusive
   25.89 +locks.  A shared lock permits other processes to obtain a shared lock,
   25.90 +but denies exclusive locks.  In other words:
   25.91 +
   25.92 +	current state		want shared	want exclusive
   25.93 +	-------------		-----------	--------------
   25.94 +	 unlocked		 YES		 YES
   25.95 +	 locked shared		 YES		 NO
   25.96 +	 locked exclusive	 NO		 NO
   25.97 +
   25.98 +     Furthermore, the operating system automatically relinquishes all
   25.99 +locks held by that process when it terminates.
  25.100 +
  25.101 +     A useful operation is the ability to upgrade a shared lock to
  25.102 +exclusive (provided there are no other shared users of the lock) and
  25.103 +to downgrade an exclusive lock to shared.  It is important that at no
  25.104 +time is the lock ever removed; a process upgrading to exclusive must
  25.105 +not relenquish its shared lock.
  25.106 +
  25.107 +     Most commonly, the resources being locked are files.  Shared
  25.108 +locks are particularly important with files; multiple simultaneous
  25.109 +processes can read from a file, but only one can safely write at a
  25.110 +time.  Some writes may be safer than others; an append to the end of
  25.111 +the file is safer than changing existing file data.  In turn, changing
  25.112 +a file record in place is safer than rewriting the file with an
  25.113 +entirely different structure.
  25.114 +
  25.115 +
  25.116 +FILE LOCKING ON UNIX
  25.117 +
  25.118 +     In the oldest versions of UNIX, the use of a semaphore lockfile
  25.119 +was the only available form of locking.  Advisory locking system calls
  25.120 +were not added to UNIX until after the BSD vs. System V split.  Both
  25.121 +of these system calls deal with file resources only.
  25.122 +
  25.123 +     Most systems only have one or the other form of locking.  AIX
  25.124 +and newer versions of OSF/1 emulate the BSD form of locking as a jacket
  25.125 +into the System V form.  Ultrix and Linux implement both forms.
  25.126 +
  25.127 +BSD
  25.128 +
  25.129 +     BSD added the flock() system call.  It offers capabilities to
  25.130 +acquire shared lock, acquire exclusive lock, and unlock.  Optionally,
  25.131 +the process can request an immediate error return instead of blocking
  25.132 +when the lock is unavailable.
  25.133 +
  25.134 +
  25.135 +FLOCK() BUGS
  25.136 +
  25.137 +     flock() advertises that it permits upgrading of shared locks to
  25.138 +exclusive and downgrading of exclusive locks to shared, but it does so
  25.139 +by releasing the former lock and then trying to acquire the new lock.
  25.140 +This creates a window of vulnerability in which another process can
  25.141 +grab the exclusive lock.  Therefore, this capability is not useful,
  25.142 +although many programmers have been deluded by incautious reading of
  25.143 +the flock() man page to believe otherwise.  This problem can be
  25.144 +programmed around, once the programmer is aware of it.
  25.145 +
  25.146 +     flock() always returns as if it succeeded on NFS files, when in
  25.147 +fact it is a no-op.  There is no way around this.
  25.148 +
  25.149 +     Leaving aside these two problems, flock() works remarkably well,
  25.150 +and has shown itself to be robust and trustworthy.
  25.151 +
  25.152 +SYSTEM V/POSIX
  25.153 +
  25.154 +     System V added new functions to the fnctl() system call, and a
  25.155 +simple interface through the lockf() subroutine.  This was
  25.156 +subsequently included in POSIX.  Both offer the facility to apply the
  25.157 +lock to a particular region of the file instead of to the entire file.
  25.158 +lockf() only supports exclusive locks, and calls fcntl() internally;
  25.159 +hence it won't be discussed further.
  25.160 +
  25.161 +     Functionally, fcntl() locking is a superset of flock(); it is
  25.162 +possible to implement a flock() emulator using fcntl(), with one minor
  25.163 +exception: it is not possible to acquire an exclusive lock if the file
  25.164 +is not open for write.
  25.165 +
  25.166 +     The fcntl() locking functions are: query lock station of a file
  25.167 +region, lock/unlock a region, and lock/unlock a region and block until
  25.168 +have the lock.  The locks may be shared or exclusive.  By means of the
  25.169 +statd and lockd daemons, fcntl() locking is available on NFS files.
  25.170 +
  25.171 +     When statd is started at system boot, it reads its /etc/state
  25.172 +file (which contains the number of times it has been invoked) and
  25.173 +/etc/sm directory (which contains a list of all remote sites which are
  25.174 +client or server locking with this site), and notifies the statd on
  25.175 +each of these systems that it has been restarted.  Each statd then
  25.176 +notifies the local lockd of the restart of that system.
  25.177 +
  25.178 +     lockd receives fcntl() requests for NFS files.  It communicates
  25.179 +with the lockd at the server and requests it to apply the lock, and
  25.180 +with the statd to request it for notification when the server goes
  25.181 +down.  It blocks until all these requests are completed.
  25.182 +
  25.183 +     There is quite a mythos about fcntl() locking.
  25.184 +
  25.185 +     One religion holds that fcntl() locking is the best thing since
  25.186 +sliced bread, and that programs which use flock() should be converted
  25.187 +to fcntl() so that NFS locking will work.  However, as noted above,
  25.188 +very few systems support both calls, so such an exercise is pointless
  25.189 +except on Ultrix and Linux.
  25.190 +
  25.191 +     Another religion, which I adhere to, has the opposite viewpoint.
  25.192 +
  25.193 +
  25.194 +FCNTL() BUGS
  25.195 +
  25.196 +     For all of the hairy code to do individual section locking of a
  25.197 +file, it's clear that the designers of fcntl() locking never
  25.198 +considered some very basic locking operations.  It's as if all they
  25.199 +knew about locking they got out of some CS textbook with not
  25.200 +investigation of real-world needs.
  25.201 +
  25.202 +     It is not possible to acquire an exclusive lock unless the file
  25.203 +is open for write.  You could have append with shared read, and thus
  25.204 +you could have a case in which a read-only access may need to go
  25.205 +exclusive.  This problem can be programmed around once the programmer
  25.206 +is aware of it.
  25.207 +
  25.208 +     If the file is opened on another file designator in the same
  25.209 +process, the file is unlocked even if no attempt is made to do any
  25.210 +form of locking on the second designator.  This is a very bad bug.  It
  25.211 +means that an application must keep track of all the files that it has
  25.212 +opened and locked.
  25.213 +
  25.214 +     If there is no statd/lockd on the NFS server, fcntl() will hang
  25.215 +forever waiting for them to appear.  This is a bad bug.  It means that
  25.216 +any attempt to lock on a server that doesn't run these daemons will
  25.217 +hang.  There is no way for an application to request flock() style
  25.218 +``try to lock, but no-op if the mechanism ain't there''.
  25.219 +
  25.220 +     There is a rumor to the effect that fcntl() will hang forever on
  25.221 +local files too if there is no local statd/lockd.  These daemons are
  25.222 +running on mailer.u, although they appear not to have much CPU time.
  25.223 +A useful experiment would be to kill them and see if imapd is affected
  25.224 +in any way, but I decline to do so without an OK from UCS!  ;-) If
  25.225 +killing statd/lockd can be done without breaking fcntl() on local
  25.226 +files, this would become one of the primary means of dealing with this
  25.227 +problem.
  25.228 +
  25.229 +     The statd and lockd daemons have quite a reputation for extreme
  25.230 +fragility.  There have been numerous reports about the locking
  25.231 +mechanism being wedged on a systemwide or even clusterwide basis,
  25.232 +requiring a reboot to clear.  It is rumored that this wedge, once it
  25.233 +happens, also blocks local locking.  Presumably killing and restarting
  25.234 +statd would suffice to clear the wedge, but I haven't verified this.
  25.235 +
  25.236 +     There appears to be a limit to how many locks may be in use at a
  25.237 +time on the system, although the documentation only mentions it in
  25.238 +passing.  On some of their systems, UCS has increased lockd's ``size
  25.239 +of the socket buffer'', whatever that means.
  25.240 +
  25.241 +C-CLIENT USAGE
  25.242 +
  25.243 +     c-client uses flock().  On System V systems, flock() is simulated
  25.244 +by an emulator that calls fcntl().
  25.245 +
  25.246 +
  25.247 +BEZERK AND MMDF
  25.248 +
  25.249 +     Locking in the traditional UNIX formats was largely dictated by
  25.250 +the status quo in other applications; however, additional protection
  25.251 +is added against inadvertantly running multiple instances of a
  25.252 +c-client application on the same mail file.
  25.253 +
  25.254 +     (1) c-client attempts to create a .lock file (mail file name with
  25.255 +``.lock'' appended) whenever it reads from, or writes to, the mail
  25.256 +file.  This is an exclusive lock, and is held only for short periods
  25.257 +of time while c-client is actually doing the I/O.  There is a 5-minute
  25.258 +timeout for this lock, after which it is broken on the presumption
  25.259 +that it is a stale lock.  If it can not create the .lock file due to
  25.260 +an EACCES (protection failure) error, it once silently proceeded
  25.261 +without this lock; this was for systems which protect /usr/spool/mail
  25.262 +from unprivileged processes creating files.  Today, c-client reports
  25.263 +an error unless it is built otherwise.  The purpose of this lock is to
  25.264 +prevent against unfavorable interactions with mail delivery.
  25.265 +
  25.266 +     (2) c-client applies a shared flock() to the mail file whenever
  25.267 +it reads from the mail file, and an exclusive flock() whenever it
  25.268 +writes to the mail file.  This lock is freed as soon as it finishes
  25.269 +reading.  The purpose of this lock is to prevent against unfavorable
  25.270 +interactions with mail delivery.
  25.271 +
  25.272 +     (3) c-client applies an exclusive flock() to a file on /tmp
  25.273 +(whose name represents the device and inode number of the file) when
  25.274 +it opens the mail file.  This lock is maintained throughout the
  25.275 +session, although c-client has a feature (called ``kiss of death'')
  25.276 +which permits c-client to forcibly and irreversibly seize the lock
  25.277 +from a cooperating c-client application that surrenders the lock on
  25.278 +demand.  The purpose of this lock is to prevent against unfavorable
  25.279 +interactions with other instances of c-client (rewriting the mail
  25.280 +file).
  25.281 +
  25.282 +     Mail delivery daemons use lock (1), (2), or both.  Lock (1) works
  25.283 +over NFS; lock (2) is the only one that works on sites that protect
  25.284 +/usr/spool/mail against unprivileged file creation.  Prudent mail
  25.285 +delivery daemons use both forms of locking, and of course so does
  25.286 +c-client.
  25.287 +
  25.288 +     If only lock (2) is used, then multiple processes can read from
  25.289 +the mail file simultaneously, although in real life this doesn't
  25.290 +really change things.  The normal state of locks (1) and (2) is
  25.291 +unlocked except for very brief periods.
  25.292 +
  25.293 +
  25.294 +TENEX AND MTX
  25.295 +
  25.296 +     The design of the locking mechanism of these formats was
  25.297 +motivated by a design to enable multiple simultaneous read/write
  25.298 +access.  It is almost the reverse of how locking works with
  25.299 +bezerk/mmdf.
  25.300 +
  25.301 +     (1) c-client applies a shared flock() to the mail file when it
  25.302 +opens the mail file.  It upgrades this lock to exclusive whenever it
  25.303 +tries to expunge the mail file.  Because of the flock() bug that
  25.304 +upgrading a lock actually releases it, it will not do so until it has
  25.305 +acquired an exclusive lock (2) first.  The purpose of this lock is to
  25.306 +prevent against expunge taking place while some other c-client has the
  25.307 +mail file open (and thus knows where all the messages are).
  25.308 +
  25.309 +     (2) c-client applies a shared flock() to a file on /tmp (whose
  25.310 +name represents the device and inode number of the file) when it
  25.311 +parses the mail file.  It applies an exclusive flock() to this file
  25.312 +when it appends new mail to the mail file, as well as before it
  25.313 +attempts to upgrade lock (1) to exclusive.  The purpose of this lock
  25.314 +is to prevent against data being appended while some other c-client is
  25.315 +parsing mail in the file (to prevent reading of incomplete messages).
  25.316 +It also protects against the lock-releasing timing race on lock (1).
  25.317 +
  25.318 +OBSERVATIONS
  25.319 +
  25.320 +     In a perfect world, locking works.  You are protected against
  25.321 +unfavorable interactions with the mailer and against your own mistake
  25.322 +by running more than one instance of your mail reader.  In tenex/mtx
  25.323 +formats, you have the additional benefit that multiple simultaneous
  25.324 +read/write access works, with the sole restriction being that you
  25.325 +can't expunge if there are any sharers of the mail file.
  25.326 +
  25.327 +     If the mail file is NFS-mounted, then flock() locking is a silent
  25.328 +no-op.  This is the way BSD implements flock(), and c-client's
  25.329 +emulation of flock() through fcntl() tests for NFS files and
  25.330 +duplicates this functionality.  There is no locking protection for
  25.331 +tenex/mtx mail files at all, and only protection against the mailer
  25.332 +for bezerk/mmdf mail files.  This has been the accepted state of
  25.333 +affairs on UNIX for many sad years.
  25.334 +
  25.335 +     If you can not create .lock files, it should not affect locking,
  25.336 +since the flock() locks suffice for all protection.  This is, however,
  25.337 +not true if the mailer does not check for flock() locking, or if the
  25.338 +the mail file is NFS-mounted.
  25.339 +
  25.340 +     What this means is that there is *no* locking protection at all
  25.341 +in the case of a client using an NFS-mounted /usr/spool/mail that does
  25.342 +not permit file creation by unprivileged programs.  It is impossible,
  25.343 +under these circumstances, for an unprivileged program to do anything
  25.344 +about it.  Worse, if EACCES errors on .lock file creation are no-op'ed
  25.345 +, the user won't even know about it.  This is arguably a site
  25.346 +configuration error.
  25.347 +
  25.348 +     The problem with not being able to create .lock files exists on
  25.349 +System V as well, but the failure modes for flock() -- which is
  25.350 +implemented via fcntl() -- are different.
  25.351 +
  25.352 +     On System V, if the mail file is NFS-mounted and either the
  25.353 +client or the server lacks a functioning statd/lockd pair, then the
  25.354 +lock attempt would have hung forever if it weren't for the fact that
  25.355 +c-client tests for NFS and no-ops the flock() emulator in this case.
  25.356 +Systemwide or clusterwide failures of statd/lockd have been known to
  25.357 +occur which cause all locks in all processes to hang (including
  25.358 +local?).  Without the special NFS test made by c-client, there would
  25.359 +be no way to request BSD-style no-op behavior, nor is there any way to
  25.360 +determine that this is happening other than the system being hung.
  25.361 +
  25.362 +     The additional locking introduced by c-client was shown to cause
  25.363 +much more stress on the System V locking mechanism than has
  25.364 +traditionally been placed upon it.  If it was stressed too far, all
  25.365 +hell broke loose.  Fortunately, this is now past history.
  25.366 +
  25.367 +TRADEOFFS
  25.368 +
  25.369 +     c-client based applications have a reasonable chance of winning
  25.370 +as long as you don't use NFS for remote access to mail files.  That's
  25.371 +what IMAP is for, after all.  It is, however, very important to
  25.372 +realize that you can *not* use the lock-upgrade feature by itself
  25.373 +because it releases the lock as an interim step -- you need to have
  25.374 +lock-upgrading guarded by another lock.
  25.375 +
  25.376 +     If you have the misfortune of using System V, you are likely to
  25.377 +run into problems sooner or later having to do with statd/lockd.  You
  25.378 +basically end up with one of three unsatisfactory choices:
  25.379 +	1) Grit your teeth and live with it.
  25.380 +	2) Try to make it work:
  25.381 +	   a) avoid NFS access so as not to stress statd/lockd.
  25.382 +	   b) try to understand the code in statd/lockd and hack it
  25.383 +	      to be more robust.
  25.384 +	   c) hunt out the system limit of locks, if there is one,
  25.385 +	      and increase it.  Figure on at least two locks per
  25.386 +	      simultaneous imapd process and four locks per Pine
  25.387 +	      process.  Better yet, make the limit be 10 times the
  25.388 +	      maximum number of processes.
  25.389 +	   d) increase the socket buffer (-S switch to lockd) if
  25.390 +	      it is offered.  I don't know what this actually does,
  25.391 +	      but giving lockd more resources to do its work can't
  25.392 +	      hurt.  Maybe.
  25.393 +	3) Decide that it can't possibly work, and turn off the 
  25.394 +	   fcntl() calls in your program.
  25.395 +	4) If nuking statd/lockd can be done without breaking local
  25.396 +	   locking, then do so.  This would make SVR4 have the same
  25.397 +	   limitations as BSD locking, with a couple of additional
  25.398 +	   bugs.
  25.399 +	5) Check for NFS, and don't do the fcntl() in the NFS case.
  25.400 +	   This is what c-client does.
  25.401 +
  25.402 +     Note that if you are going to use NFS to access files on a server
  25.403 +which does not have statd/lockd running, your only choice is (3), (4),
  25.404 +or (5).  Here again, IMAP can bail you out.
  25.405 +
  25.406 +     These problems aren't unique to c-client applications; they have
  25.407 +also been reported with Elm, Mediamail, and other email tools.
  25.408 +
  25.409 +     Of the other two SVR4 locking bugs:
  25.410 +
  25.411 +     Programmer awareness is necessary to deal with the bug that you
  25.412 +can not get an exclusive lock unless the file is open for write.  I
  25.413 +believe that c-client has fixed all of these cases.
  25.414 +
  25.415 +     The problem about opening a second designator smashing any
  25.416 +current locks on the file has not been addressed satisfactorily yet.
  25.417 +This is not an easy problem to deal with, especially in c-client which
  25.418 +really doesn't know what other files/streams may be open by Pine.
  25.419 +
  25.420 +     Aren't you so happy that you bought an System V system?
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/docs/md5.txt	Mon Sep 14 15:17:45 2009 +0900
    26.3 @@ -0,0 +1,91 @@
    26.4 +/* ========================================================================
    26.5 + * Copyright 1988-2006 University of Washington
    26.6 + *
    26.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    26.8 + * you may not use this file except in compliance with the License.
    26.9 + * You may obtain a copy of the License at
   26.10 + *
   26.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   26.12 + *
   26.13 + * 
   26.14 + * ========================================================================
   26.15 + */
   26.16 +
   26.17 +		       MD5 Based Authentication
   26.18 +			     Mark Crispin
   26.19 +			   1 November 1999
   26.20 +
   26.21 +
   26.22 +     The IMAP toolkit makes available two MD5 based authentication
   26.23 +mechanisms, CRAM-MD5 and APOP.  CRAM-MD5 is described in RFC 2195, and
   26.24 +is a SASL (RFC 2222) authentication mechanism.  APOP is described in
   26.25 +RFC 1939, the standard document for the POP3 protocol.
   26.26 +
   26.27 +     These mechanisms use the same general idea.  The server issues a
   26.28 +challenge; the client responds with an MD5 checksum of the challenge
   26.29 +plus the password; the server in compares the client's response with
   26.30 +its own calculated value of the checksum.  If the client's response
   26.31 +matches the server's calulated value, the client is authenticated.
   26.32 +
   26.33 +     Unlike plaintext passwords, this form of authentication is
   26.34 +believed to be secure against the session being monitored; "sniffing"
   26.35 +the session will not disclose the password nor will it provide usable
   26.36 +information to authenticate in another session without knowing the
   26.37 +password.
   26.38 +
   26.39 +     The key disadvantage with this form of authentication is that the
   26.40 +server must know a plaintext form of the password.  In traditional
   26.41 +UNIX authentication, the server only knows an encrypted form of the
   26.42 +password.  Consequently, the authentication database for this form of
   26.43 +authentication must be kept strictly confidential; a bad guy who
   26.44 +acquires access to this database can access any account in the
   26.45 +database.
   26.46 +
   26.47 +     CRAM-MD5 client support is implemented unconditionally; any
   26.48 +client application built with the IMAP toolkit will use CRAM-MD5 with
   26.49 +any server which advertises CRAM-MD5 SASL support.
   26.50 +
   26.51 +     CRAM-MD5 and APOP server support is implemented if, and only if,
   26.52 +the CRAM-MD5 authentication database exists.  By default, the CRAM-MD5
   26.53 +authentication database is in a UNIX file called
   26.54 +	/etc/cram-md5.pwd
   26.55 +It is recommended that this file be protected 0400.
   26.56 +
   26.57 +	NOTE: FAILURE TO PROTECT THIS FILE AGAINST UNAUTHORIZED
   26.58 +	ACCESS WILL COMPROMSE CRAM-MD5 AND APOP AUTHENTICATION
   26.59 +	FOR ALL USERS LISTED IN THIS DATABASE.
   26.60 +
   26.61 +     If the CRAM-MD5 authentication database exists, then plaintext
   26.62 +password authentication (e.g. the LOGIN command) will also use the
   26.63 +CRAM-MD5 passwords instead of UNIX passwords.  Alternatively, it is
   26.64 +possible to build the IMAP toolkit so that plaintext password
   26.65 +authentication is disabled entirely, by using PASSWDTYPE=nul, e.g.
   26.66 +	make aix PASSWDTYPE=nul
   26.67 +
   26.68 +
   26.69 +     The CRAM-MD5 authentication database file consists of a series of
   26.70 +text lines, consisting of a UNIX user name, a single tab, and the
   26.71 +password.  A line starting with a "#" character is ignored, as are any
   26.72 +lines which are not in valid format.  For example:
   26.73 +
   26.74 +------------------------------Sample------------------------------
   26.75 +# CRAM-MD5 authentication database
   26.76 +# Entries are in form <user><tab><password>
   26.77 +# Lines starting with "#" are comments
   26.78 +
   26.79 +bill	hubba-hubba
   26.80 +hillary	nysenator
   26.81 +monica	beret
   26.82 +tripp	wired
   26.83 +kenstarr	inquisitor
   26.84 +reno	waco
   26.85 +jessie	thebody
   26.86 +billgates	ruleworld
   26.87 +------------------------------Sample------------------------------
   26.88 +
   26.89 +     Every entry in the CRAM-MD5 authentication database must have a
   26.90 +corresponding entry in the /etc/passwd file.  It is STRONGLY
   26.91 +RECOMMENDED that the CRAM-MD5 password NOT be the same as the
   26.92 +/etc/passwd password.  It is permitted for the /etc/passwd password to
   26.93 +be disabled; /etc/passwd is just used to get the UID, GID, and home
   26.94 +directory information.
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/docs/mixfmt.txt	Mon Sep 14 15:17:45 2009 +0900
    27.3 @@ -0,0 +1,363 @@
    27.4 +/* ========================================================================
    27.5 + * Copyright 1988-2006 University of Washington
    27.6 + *
    27.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    27.8 + * you may not use this file except in compliance with the License.
    27.9 + * You may obtain a copy of the License at
   27.10 + *
   27.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   27.12 + *
   27.13 + * 
   27.14 + * ========================================================================
   27.15 + */
   27.16 +
   27.17 +Last update: 18 December 2006
   27.18 +
   27.19 +INTRODUCTION
   27.20 +
   27.21 +This file is the descendant of a design document used to specify the
   27.22 +mix format.  An attempt is being made to keep this document more or
   27.23 +less current with the way the mix format actually works.
   27.24 +
   27.25 +
   27.26 +1. Mix mailbox naming
   27.27 +
   27.28 +Mailbox names correspond to directory names; thus mix format mailboxes
   27.29 +are "dual-use" (lack both \NoInferiors and \NoSelect).  This will
   27.30 +satisfy some long-standing requests.
   27.31 +
   27.32 +
   27.33 +2. Mailbox files
   27.34 +
   27.35 +A mix format mailbox is a directory with regular files with filenames
   27.36 +of:
   27.37 +	.mixmeta	mailbox metadata file
   27.38 +	.mixindex	message index file (message static data)
   27.39 +	.mixstatus	message status file (message dynamic data)
   27.40 +	.mix########	(where ######### is a <hex8>) secondary message
   27.41 +			 data files.
   27.42 +	.mix		primary message data file (used in experimental
   27.43 +			 versions, supported for compatibility only)
   27.44 +
   27.45 +2.1 Metadata, index, and status files
   27.46 +
   27.47 +The mailbox metadata, index, and status files contain a sequence of
   27.48 +CRLF-terminated lines.  These files have an update sequence, which is
   27.49 +a strictly-ascending sequence value.  Any time the file is changed,
   27.50 +the update sequence is increased; this allows easy detection of
   27.51 +whether the file has been changed by another process.  For now, this
   27.52 +update sequence is a modseq (see below).
   27.53 +
   27.54 +2.1.1 Metadata file
   27.55 +
   27.56 +The mailbox metadata file is called ".mixmeta".  It contains a series
   27.57 +of CRLF-terminated lines.  The first character of the line is a key that
   27.58 +identifies the payload of the line, and the remainder of the line is the
   27.59 +payload.
   27.60 +	Key	Payload
   27.61 +	---	-------
   27.62 +	 S	<hex8>			;; update sequence
   27.63 +	 V	<hex8>			;; UIDVALIDITY
   27.64 +	 L	<hex8>			;; UIDLAST
   27.65 +	 N	<hex8>			;; current new message file
   27.66 +	 K	[atom 0*(SP atom)]	;; keyword list
   27.67 +
   27.68 +All other keys are reserved for future assignment and must be ignored
   27.69 +(and may be discarded) by software which does not recognize them.  The
   27.70 +mailbox metadata file is rewritten as part of new mail delivery (so
   27.71 +APPENDUID/COPYUID can work) and when new keywords are added.
   27.72 +
   27.73 +2.1.2 Message static index file
   27.74 +
   27.75 +The mailbox message static index file is called ".mixindex".  It contains
   27.76 +a series of CRLF-terminated lines.  The first character of the line is a
   27.77 +key that identifies the payload of the line, and the remainder of the line
   27.78 +is the payload.
   27.79 +	Key	Payload
   27.80 +	---	-------
   27.81 +	 S	<hex8>			;; update sequence
   27.82 +	 :	<uid>:<date>:<size>:<file>:<pos>:<isiz>:<hsiz>
   27.83 +	 				;; per-message record
   27.84 +
   27.85 +The per-message records contain the following data:
   27.86 +	<uid>  = <hex8>			;; message UID
   27.87 +	<date> = <yyyymmddhhmmss+zzzz>	;; internal date
   27.88 +	<size> = <hex8>			;; rfc822.size
   27.89 +	<file> = <hex8>			;; message data file (0 = .mix file)
   27.90 +	<pos>  = <hex8>			;; message position in file
   27.91 +	<isiz> = <hex8>			;; message internal data size
   27.92 +	<hsiz> = <hex8>			;; header size (offset to body)
   27.93 +
   27.94 +All other keys, and subsequent fields in per-message records, are
   27.95 +reserved for future assignment and must be ignored (and may be
   27.96 +discarded) by software which does not recognize them.  The mailbox
   27.97 +metadata file is appended by new mail delivery and rewritten by
   27.98 +expunge "burping", and otherwise is not altered.
   27.99 +
  27.100 +2.1.3 Message dynamic status file
  27.101 +
  27.102 +The mailbox message dynamic status file is called ".mixstatus".  It contains
  27.103 +a series of CRLF-terminated lines.  The first character of the line is a
  27.104 +key that identifies the payload of the line, and the remainder of the line
  27.105 +is the payload.
  27.106 +   	Key	Payload
  27.107 +	---	-------
  27.108 +	 S	<hex8>			;; update sequence
  27.109 +	 :	<uid>:<uf>:<sf>:<mod>:	;; per-message record
  27.110 +
  27.111 +The per-message records contain the following data:
  27.112 +	<uid>  = <hex8>			;; message UID
  27.113 +	<keys> = <hex8>			;; keyword flags
  27.114 +	<flag> = <hex4>			;; system flags
  27.115 +	<mod>  = <hex8>			;; date/time last modified (modseq)
  27.116 +
  27.117 +All other keys, and subsequent fields in per-message records, are
  27.118 +reserved for future assignment and must be ignored (and may be
  27.119 +discarded) by software which does not recognize them.  The mailbox
  27.120 +dynamic idex file is rewritten by flag changes (or any future change
  27.121 +that alters dynamic data) and is re-read when a session sees that the
  27.122 +mtime has changed (atime and ctime are not used).
  27.123 +
  27.124 +The modseq is an unsigned 32-bit date/time, along with a guarantee
  27.125 +that this value can not go backwards.  It currently corresponds to the
  27.126 +time from time(); however, since it is unsigned, it won't run out until
  27.127 +the year 2106.  In the future, this may be used as a basic for implementing
  27.128 +the IMAP CONDSTORE extension.
  27.129 +
  27.130 +2.2 Message data files
  27.131 +
  27.132 +A mix message file is a regular file with filename starting with
  27.133 +".mix" followed by a <hex8> suffix which indicates the file number.  It
  27.134 +contains a series of CRLF-terminated lines.  By special dispensation, the
  27.135 +filename ".mix" is used for file number 0, which was used in experimental
  27.136 +versions of mix as a "primary" file (this concept no longer exists).
  27.137 +
  27.138 +A file number is set to the current modseq when it is created.  If a copy
  27.139 +or append causes the file to exceed the compiled-in file size limit, a new
  27.140 +file is started and the metadata is updated accordingly.
  27.141 +
  27.142 +Preceeding each message is per-message record with the following format:
  27.143 +   	Key	Payload
  27.144 +	---	-------
  27.145 +					;; per-message record
  27.146 +	:	:<code>:<uid>:<date>:<size>:
  27.147 +
  27.148 +The per-message records contain the following data:
  27.149 +	<code> = "msg"			;; fixed code
  27.150 +	<uid>  = <hex8>			;; message UID
  27.151 +	<date> = <yyyymmddhhmmss+zzzz>	;; internal date
  27.152 +	<size> = <hex8>			;; rfc822.size
  27.153 +The message data begins on the next line
  27.154 +
  27.155 +Subsequent fields are reserved for future assignment and must be ignored.
  27.156 +
  27.157 +
  27.158 +3. New mail delivery
  27.159 +
  27.160 +To deliver a new message, it is necessary to share lock the destination
  27.161 +metadata file, then get an exclusive lock on the destination index and
  27.162 +status files.  Once this is done, the new message data is appended to the
  27.163 +new message file.  The metadata (UIDLAST value), index, and status
  27.164 +files are all updated to add the new message.
  27.165 +
  27.166 +Then all the destination mailbox files are closed.
  27.167 +
  27.168 +
  27.169 +4. Mailbox pinging
  27.170 +
  27.171 +The index and status files are share locked.  Initially, sequences are
  27.172 +remembered as zero, so at open time they are always "altered".
  27.173 +
  27.174 +The sequence from the index file is checked; if it is altered the index
  27.175 +file is read and processed as follows:
  27.176 + . If expunge is permitted, then any messages that are not in the index
  27.177 +   are reported as having been expunged via mm_expunged().
  27.178 + . new messages are announced via mm_exists()/mm_recent().
  27.179 +
  27.180 +Next, the sequence from the status file is checked.  If it is altered,
  27.181 +the status file is read and the status updated for any message which is
  27.182 +new or has an altered modseq in the status file.  Altered modseq messages
  27.183 +are announced via mm_flags().
  27.184 +
  27.185 +Then the index and status files are closed.
  27.186 +
  27.187 +
  27.188 +4. Flag alteration
  27.189 +
  27.190 +The status file is exclusive locked.
  27.191 +
  27.192 +The sequence from the status file is checked.  If it is altered, the
  27.193 +status file is read and the status updated for any message which is
  27.194 +new or has an altered modseq in the status file.  Altered modseq
  27.195 +messages are announced via mm_flags().
  27.196 +
  27.197 +The alterations are then applied for all requested messages, updating
  27.198 +the modseq for each requestedmessage which changes flags as a result
  27.199 +of the alteration (alterations which do not result in a change do not
  27.200 +alter the modseq).  Then the status file is rewritten with a new
  27.201 +sequence, but only if flags of at least one message was changed.
  27.202 +
  27.203 +Then the status file is closed.
  27.204 +
  27.205 +
  27.206 +5. Checkpoint and expunge
  27.207 +
  27.208 +Checkpoint is identical to expunge, however it skips the step of expunging
  27.209 +deleted messages.
  27.210 +
  27.211 +The index and status files are locked exclusive.  If expunging, all
  27.212 +deleted messages are expunged from the index and announced via
  27.213 +mm_expunged().  The message data is notremoved at this time.
  27.214 +
  27.215 +If a checkpoint was requested, or if any messages were expunged, or if
  27.216 +it remembered that a "burp" was needed, then:
  27.217 + . the metadata file is locked exclusive.  If this fails, remember that
  27.218 +   a burp is needed.  Otherwise perform a burp:
  27.219 +   . calculate the file byte ranges occupied by expunged messages
  27.220 +   . for each file needing "burping", open and slide down subsequent file
  27.221 +     data on top of the expunged messages
  27.222 + . update the index and status files
  27.223 +
  27.224 +Then the index and status files are closed.
  27.225 +
  27.226 +5.1 More details on expunging and "burping"
  27.227 +
  27.228 +Shared expunge presents a problem due to the requirements of the IMAP
  27.229 +protocol.  You can't "burp" away a message until you are certain that
  27.230 +no sharers have a pointer to any longer.  Consequently, for the nonce
  27.231 +"burping" out expunged data be defered to an exclusive expunge as in
  27.232 +mbx format.
  27.233 +
  27.234 +If shared burping is ever implemented, then care will be needed not to
  27.235 +burp data that a session still relies upon.  It's easy enough to burp
  27.236 +the index files; just create new index files, deleting the old, and
  27.237 +require that you look for a new one appearing at mailbox ping time
  27.238 +(when it's safe).  The data files are a problem, since we
  27.239 +intentionally don't want to keep them open and do want to avoid quota
  27.240 +problems by overwriting in place.  Also, when you burp you have to
  27.241 +change the pointers in the index file.
  27.242 +
  27.243 +Bottom line: shared burping is too hairy right now, so the first
  27.244 +version will do exclusive-only burping and not worry about it.  If
  27.245 +shared burping is really needed, then that routine will need to be
  27.246 +rewritten.
  27.247 +
  27.248 +Shared burping has been a problem for every other IMAP server.  Most
  27.249 +get it wrong, and cause terrible confusion to clients (including
  27.250 +client crashes).
  27.251 +
  27.252 +
  27.253 +6. Message data file file roll out strategy
  27.254 +
  27.255 +The current new message file is finalized, and a new one started, when
  27.256 +an append or copy is done that would cause the file to grow to larger
  27.257 +than a preconfigured size (MIXDATAROLL).  A multi-message copy or
  27.258 +append is written into its entirety to a single new message file.  In
  27.259 +the case of multi-copy, the new message file is switched when the sum
  27.260 +of the sizes of all messages to be copied would cause the current new
  27.261 +message file to exceed MIXDATAROLL.  In the case of multi-append, only
  27.262 +the first message is considered; this is due to technical limitations.
  27.263 +
  27.264 +7. Error detection
  27.265 +
  27.266 +Mix detects bad data in the metadata, index, and status files; and
  27.267 +declares the stream dead.  It does not unilaterally reassign
  27.268 +UIDVALIDITY the way that the flat file formats do.
  27.269 +
  27.270 +When mix reads a header from the message file, it also reads the
  27.271 +per-message record and verifies that there is a per-message record there.
  27.272 +This is a simple test for message file corruption.  It doesn't declare
  27.273 +the stream dead; it simply issues an error message and returns a
  27.274 +zero-length string for the message header.  This makes it possible for
  27.275 +the user to fix the mailbox simply by deleting and expunging any messages
  27.276 +that are in this state.
  27.277 +
  27.278 +
  27.279 +8. Reconstruct tool
  27.280 +
  27.281 +[None of this is implemented yet.]
  27.282 +
  27.283 +The layout of these files is designed to make the reconstruct tool be
  27.284 +as simple as possible.  Much of the need for the reconstruct tool is
  27.285 +eliminated since the mix format has a much more limited scope of
  27.286 +writing than the flat file formats; thus there is "less collateral
  27.287 +damage."
  27.288 +
  27.289 +If the metadata file is lost or corrupted, then all keywords are lost;
  27.290 +if the mailbox has any keywords used in the .mixstatus file, it'll be
  27.291 +necessary to create some placeholder names.  Otherwise, a new
  27.292 +UIDVALIDITY can be assigned, and a good UIDLAST value calculated by
  27.293 +the reconstruct tool.  Since this file is very small, it's not likely
  27.294 +to be damaged.
  27.295 +
  27.296 +If the index file is lost or corrupted, it is possible to reconstruct
  27.297 +it with no loss by reading all the data files.  However, this could
  27.298 +cause expunged but not yet burped messages to reappear.
  27.299 +
  27.300 +If the status file is lost or corrupted, then flags are lost and
  27.301 +will revert to a default state of no flags set.  Just deleting the
  27.302 +corrupted file is good enough.
  27.303 +
  27.304 +The reconstruct tool can use the per-message record in the message
  27.305 +file to locate messages if the recorded sizes and/or messages are
  27.306 +corrupt.  If that happens, it will need to rebuild the index file
  27.307 +(with associated changes to the metadata file to change the
  27.308 +UIDVALIDITY).  That should probably be a manual operation and not be
  27.309 +part of the default operation or auto-reconstruct.
  27.310 +
  27.311 +
  27.312 +9. Locking strategy
  27.313 +
  27.314 +The mix format does not use the traditional c-client /tmp file locking.
  27.315 +
  27.316 +The metadata file is open and locked whenever the mailbox is open.
  27.317 +Normally this is a shared lock, but it will be upgraded to exclusive
  27.318 +if the mailbox is expunged.  As a guard (since there is no true
  27.319 +lock-upgrade/downgrade on UNIX), the index exclusive lock must be
  27.320 +acquired first before upgrading to exclusive.
  27.321 +
  27.322 +The index file is shared locked when reading the index, and exclusive
  27.323 +locked (and read) when appending new messages to the index or when
  27.324 +expunging (note that expunging also requires an exclusive lock on
  27.325 +metadata).  Normally, the index file is not open or locked.
  27.326 +
  27.327 +The status file is shared locked when reading status, and exclusive
  27.328 +locked (and read) when updating status.  Normally, the status file is
  27.329 +not open or locked.
  27.330 +
  27.331 +It isn't necessary to lock any of the data files as long as we only
  27.332 +have exclusive burping.
  27.333 +
  27.334 +
  27.335 +10. Memory usage
  27.336 +
  27.337 +The mix format returns a file stringstruct, which is the modern
  27.338 +c-client behavior.  This prevents imapd from growing to enormous sizes
  27.339 +due to a godzillagram (how it affects other programs depends upon what
  27.340 +they do with the returned stringstruct).
  27.341 +
  27.342 +
  27.343 +11. Future extensions
  27.344 +
  27.345 +Cached ENVELOPE, BODYSTRUCTURE.  Cyrus does, and this will eliminate
  27.346 +most of the reason to access the data files.  Possibly cached overviews,
  27.347 +ala NNTP, instead?
  27.348 +
  27.349 +
  27.350 +Support for ANNOTATION.
  27.351 +
  27.352 +
  27.353 +12. RENAME issues
  27.354 +
  27.355 +Mix currently makes no attempt to address the IMAP RENAME problem.
  27.356 +This occurs when a mailbox is deleted, and another mailbox is renamed
  27.357 +with that name in place, no attempt is made to reassign UIDVALIDITY
  27.358 +for this mailbox and all the inferior mailboxes.  This potentially can
  27.359 +cause problems for a disconnected-use client that has cached status
  27.360 +for the old mailbox which had that name.
  27.361 +
  27.362 +The RENAME problem is a well known flaw in the IMAP protocol.  Few
  27.363 +servers correctly handle it (among other things, not only do all the
  27.364 +UIDVALIDITY values have to be changed but this has to be done
  27.365 +atomically!).  It was a mistake to add RENAME into IMAP, but it's much
  27.366 +too late to remove it now.
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/docs/naming.txt	Mon Sep 14 15:17:45 2009 +0900
    28.3 @@ -0,0 +1,143 @@
    28.4 +/* ========================================================================
    28.5 + * Copyright 1988-2006 University of Washington
    28.6 + *
    28.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    28.8 + * you may not use this file except in compliance with the License.
    28.9 + * You may obtain a copy of the License at
   28.10 + *
   28.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   28.12 + *
   28.13 + * 
   28.14 + * ========================================================================
   28.15 + */
   28.16 +
   28.17 +		       Mailbox Name Conventions
   28.18 +			     Mark Crispin
   28.19 +			    5 October 2005
   28.20 +
   28.21 +
   28.22 +Please refer to the file drivers.txt for related information.
   28.23 +
   28.24 +
   28.25 +I. Special names
   28.26 +
   28.27 +Special names appear by themselves.
   28.28 +
   28.29 +I.a. INBOX
   28.30 +
   28.31 +The name INBOX is special and refers to primary incoming message
   28.32 +mailbox on the local system.
   28.33 +
   28.34 +
   28.35 +I.b. #mhinbox (UNIX only)
   28.36 +
   28.37 +The name #mhinbox is special and refers to the primary incoming mh
   28.38 +format mailbox on the local system.  Don't worry about this if you
   28.39 +don't know what mh format is.
   28.40 +
   28.41 +
   28.42 +II.  Special prefixes
   28.43 +
   28.44 +All names which start with a "#" have a "special prefix" which
   28.45 +identifies an alternative namespace.  Special prefixes appear in front
   28.46 +of some additional text which constitutes a suffix.
   28.47 +
   28.48 +II.a. #mh/ (UNIX only)
   28.49 +
   28.50 +The prefix #mh/ is special and refers to the mh format mailbox named
   28.51 +with the suffix.  For example, #mh/foo refers to the mh format mailbox
   28.52 +named foo.  Don't worry about this if you don't know what mh format is.
   28.53 +
   28.54 +
   28.55 +II.b. #news. (UNIX only)
   28.56 +
   28.57 +The prefix #news. is special and refers to the newsgroup named with
   28.58 +the suffix.  For example, #news.comp.mail.misc refers to the newsgroup
   28.59 +named comp.mail.misc.
   28.60 +
   28.61 +
   28.62 +II.c. #ftp/ (UNIX only)
   28.63 +
   28.64 +The prefix #ftp/ is special and refers to the anonymous ftp filesystem
   28.65 +named with the suffix.  For example, #ftp/foo/bar refers to the file
   28.66 +/foo/bar in the anonymous FTP filesystem.  Anonymous FTP files are
   28.67 +available to anonymous IMAP logins.
   28.68 +
   28.69 +
   28.70 +II.d. #public/ (UNIX only)
   28.71 +
   28.72 +The prefix #public/ is special and refers to the public files
   28.73 +filesystem named with the suffix.  For example, #public/foo/bar refers
   28.74 +to the file /foo/bar in the public filesystem.  Public files are
   28.75 +available to anonymous IMAP logins.
   28.76 +
   28.77 +
   28.78 +II.e. #shared/ (UNIX only)
   28.79 +
   28.80 +The prefix #shared/ is special and refers to the shared files
   28.81 +filesystem named with the suffix.  For example, #shared/foo/bar
   28.82 +frefers to the file /foo/bar in the shared filesystem.
   28.83 +
   28.84 +
   28.85 +III. Remote names
   28.86 +
   28.87 +All names which start with "{" are remote names, and are in the form
   28.88 +	"{" remote_system_name [":" port] [flags] "}" [mailbox_name]
   28.89 +where:
   28.90 + remote_system_name	Internet domain name or bracketed IP address
   28.91 +			 of server.
   28.92 + port			optional TCP port number, default is the
   28.93 +			 default port for that service		
   28.94 + flags			optional flags, one of the following:
   28.95 +  "/service=" service	mailbox access service, default is "imap"
   28.96 +  "/user=" user		remote user name for login on the server
   28.97 +  "/authuser=" user	remote authentication user; if specified this
   28.98 +			 is the user name whose password is used (e.g.
   28.99 +			 administrator)
  28.100 +  "/anonymous"		remote access as anonymous user
  28.101 +  "/debug"		record protocol telemetry in application's
  28.102 +			 debug log
  28.103 +  "/secure"		do not transmit a plaintext password over
  28.104 +			 the network
  28.105 +  "/imap", "/imap2", "/imap2bis", "/imap4", "/imap4rev1"
  28.106 +			equivalent to /service=imap
  28.107 +  "/pop3"		equivalent to /service=pop3
  28.108 +  "/nntp"		equivalent to /service=nntp
  28.109 +  "/norsh"		do not use rsh or ssh to establish a preauthenticated
  28.110 +			 IMAP session
  28.111 +  "/ssl"		use the Secure Socket Layer to encrypt the session
  28.112 +  "/validate-cert"	validate certificates from TLS/SSL server (this is the
  28.113 +			 default behavior)
  28.114 +  "/novalidate-cert"	do not validate certificates from TLS/SSL server,
  28.115 +			 needed if server uses self-signed certificates
  28.116 +  "/tls"		force use of start-TLS to encrypt the session, and
  28.117 +			 reject connection to servers that do not support it
  28.118 +  "/tls-sslv23"		use the depreciated SSLv23 client when negotiating
  28.119 +			 TLS to the server.  This is necessary with some
  28.120 +			 broken servers which (incorrectly) think that TLS
  28.121 +			 is just another way of doing SSL.
  28.122 +  "/notls"		do not do start-TLS to encrypt the session, even
  28.123 +			 with servers that support it
  28.124 +  "/readonly"		request read-only mailbox open (IMAP only; ignored
  28.125 +			 on NNTP, and an error with SMTP and POP3)
  28.126 +  "/loser"		disable various protocol features and perform various
  28.127 +			 client-side workarounds; for example, it disables
  28.128 +			 the SEARCH command in IMAP and does client-side
  28.129 +			 searching instead.  The precise measures taken by
  28.130 +			 /loser depend upon the protocol and are subject to
  28.131 +			 change over time.  /loser is intended for use with
  28.132 +			 defective servers which do not implement the
  28.133 +			 protocol specification correctly.  It should be used
  28.134 +			 only as a last resort since it will seriously
  28.135 +			 degrade performance.
  28.136 + mailbox_name		remote mailbox name, default is INBOX
  28.137 +
  28.138 +For example:
  28.139 +	{imap.foo.com}INBOX
  28.140 +opens an IMAP connection to system imap.foo.com and selects INBOX.
  28.141 +
  28.142 +
  28.143 +IV. All other names
  28.144 +
  28.145 +All other names are treated as local file names, relative to the
  28.146 +user's home directory.  Read drivers.txt for more details.
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/docs/rfc/README	Mon Sep 14 15:17:45 2009 +0900
    29.3 @@ -0,0 +1,70 @@
    29.4 +The following documents are necessary to understand the syntax rules
    29.5 +most of the remaining documents.  Note that some documents refer to
    29.6 +RFC 2234 which has been replaced by RFC 5234:
    29.7 +   rfc5234.txt	Augmented BNF for Syntax Specifications - ABNF
    29.8 +   rfc4466.txt	Collected Extensions to IMAP4 ABNF
    29.9 +
   29.10 +
   29.11 +The following documents specify the IMAP protocol:
   29.12 +   rfc3501.txt	Internet Message Access Protocol - Version 4rev1
   29.13 +
   29.14 +
   29.15 +The following documents provide additional information which is useful
   29.16 +in understanding the IMAP protocol:
   29.17 +   rfc1733.txt	Distributed Electronic Mail Models in IMAP4
   29.18 +   rfc2180.txt	IMAP4 Multi-Accessed Mailbox Practice
   29.19 +   rfc2683.txt	IMAP4 Implementation Recommendations
   29.20 +   rfc4549.txt	Synchronization Operations for Disconnected IMAP4 Clients
   29.21 +
   29.22 +
   29.23 +The following documents describe extensions to the IMAP protocol.
   29.24 +Items marked with "*" are supported in this distribution:
   29.25 +   rfc4314.txt	ACL
   29.26 + * rfc3516.txt	BINARY
   29.27 +   rfc4469.txt	CATENATE
   29.28 + * rfc3348.txt	CHILDREN
   29.29 +   rfc4978.txt	COMPRESS
   29.30 +   rfc4551.txt	CONDSTORE
   29.31 +   rfc5161.txt	ENABLE
   29.32 + * rfc4731.txt	ESEARCH
   29.33 +   rfc2971.txt	ID
   29.34 + * rfc2177.txt	IDLE
   29.35 + * rfc2088.txt	LITERAL+
   29.36 + * rfc2221.txt	LOGIN-REFERRALS
   29.37 + * rfc2193.txt	MAILBOX-REFERRALS
   29.38 + * rfc3502.txt	MULTIAPPEND
   29.39 + * rfc2342.txt	NAMESPACE
   29.40 +   rfc5162.txt	QRESYNC
   29.41 +   rfc2087.txt	QUOTA
   29.42 + * rfc4959.txt	SASL-IR
   29.43 + * rfc4315.txt	UIDPLUS
   29.44 + * rfc3691.txt	UNSELECT
   29.45 +   rfc4467.txt	URLAUTH
   29.46 + * rfc5032.txt	WITHIN
   29.47 +
   29.48 +
   29.49 +The following documents describe SASL:
   29.50 +   rfc4422.txt	Simple Authentication and Security Layer (SASL)
   29.51 +and the SASL mechanisms supported in this distribution:
   29.52 +   rfc4505.txt	ANONYMOUS
   29.53 +   rfc2195.txt	CRAM-MD5
   29.54 +   rfc4752.txt	GSSAPI
   29.55 +   rfc4616.txt	PLAIN
   29.56 +
   29.57 +
   29.58 +The following documents relate to internationalization issues:
   29.59 +   rfc4790.txt	Internet Application Protocol Collation Registry
   29.60 +   rfc5051.txt	i;unicode-casemap - Simple Unicode Collation Algorithm
   29.61 +
   29.62 +
   29.63 +The following documents are primarily of historic interest:
   29.64 +   rfc1732.txt	IMAP4 Compatibility with IMAP2 and IMAP2bis
   29.65 +   rfc2061.txt	IMAP4 Compatibility with IMAP2bis
   29.66 +   rfc2062.txt	Internet Message Access Protocol - Obsolete Syntax
   29.67 +
   29.68 +
   29.69 +The following documents discuss matters which are related to IMAP:
   29.70 +   rfc3503.txt	MDN Profile for IMAP
   29.71 +   rfc3656.txt	MUPDATE Distributed Mailbox Database Protocol
   29.72 +   rfc4468.txt	Message Submission BURL Extension
   29.73 +   rfc5092.txt	IMAP URL Scheme
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/docs/rfc/rfc1732.txt	Mon Sep 14 15:17:45 2009 +0900
    30.3 @@ -0,0 +1,283 @@
    30.4 +
    30.5 +
    30.6 +
    30.7 +
    30.8 +
    30.9 +
   30.10 +Network Working Group                                         M. Crispin
   30.11 +Request for Comments: 1732                      University of Washington
   30.12 +Category: Informational                                    December 1994
   30.13 +
   30.14 +
   30.15 +              IMAP4 COMPATIBILITY WITH IMAP2 AND IMAP2BIS
   30.16 +
   30.17 +
   30.18 +Status of this Memo
   30.19 +
   30.20 +   This memo provides information for the Internet community.  This memo
   30.21 +   does not specify an Internet standard of any kind.  Distribution of
   30.22 +   this memo is unlimited.
   30.23 +
   30.24 +Introduction
   30.25 +
   30.26 +   This is a summary of hints and recommendations to enable an IMAP4
   30.27 +   implementation to interoperate with implementations that conform to
   30.28 +   earlier specifications.  None of these hints and recommendations are
   30.29 +   required by the IMAP4 specification; implementors must decide for
   30.30 +   themselves whether they want their implementation to fail if it
   30.31 +   encounters old software.
   30.32 +
   30.33 +   IMAP4 has been designed to be upwards compatible with earlier
   30.34 +   specifications.  For the most part, IMAP4 facilities that were not in
   30.35 +   earlier specifications should be invisible to clients unless the
   30.36 +   client asks for the facility.
   30.37 +
   30.38 +   In some cases, older servers may support some of the capabilities
   30.39 +   listed as being "new in IMAP4" as experimental extensions to the
   30.40 +   IMAP2 protocol described in RFC 1176.
   30.41 +
   30.42 +   This information may not be complete; it reflects current knowledge
   30.43 +   of server and client implementations as well as "folklore" acquired
   30.44 +   in the evolution of the protocol.
   30.45 +
   30.46 +
   30.47 +
   30.48 +
   30.49 +
   30.50 +
   30.51 +
   30.52 +
   30.53 +
   30.54 +
   30.55 +
   30.56 +
   30.57 +
   30.58 +
   30.59 +
   30.60 +
   30.61 +Crispin                                                         [Page 1]
   30.62 +
   30.63 +RFC 1732                 IMAP4 - Compatibility             December 1994
   30.64 +
   30.65 +
   30.66 +IMAP4 client interoperability with old servers
   30.67 +
   30.68 +   In general, a client should be able to discover whether an IMAP2
   30.69 +   server supports a facility by trial-and-error; if an attempt to use a
   30.70 +   facility generates a BAD response, the client can assume that the
   30.71 +   server does not support the facility.
   30.72 +
   30.73 +   A quick way to check whether a server implementation supports the
   30.74 +   IMAP4 specification is to try the CAPABILITY command.  An OK response
   30.75 +   that includes the IMAP4 capability value indicates a server that
   30.76 +   supports IMAP4; a BAD response or one without the IMAP4 capability
   30.77 +   value indicates an older server.
   30.78 +
   30.79 +   The following is a list of facilities that are only in IMAP4, and
   30.80 +   suggestions for how new clients might interoperate with old servers:
   30.81 +
   30.82 +   CAPABILITY command
   30.83 +            A BAD response to this command indicates that the server
   30.84 +            implements IMAP2 (or IMAP2bis) and not IMAP4.
   30.85 +
   30.86 +   AUTHENTICATE command.
   30.87 +            Use the LOGIN command.
   30.88 +
   30.89 +   LSUB and LIST commands
   30.90 +            Try the RFC 1176 FIND command.
   30.91 +
   30.92 +   * in a sequence
   30.93 +            Use the number of messages in the mailbox from the EXISTS
   30.94 +            unsolicited response.
   30.95 +
   30.96 +   SEARCH extensions (character set, additional criteria)
   30.97 +            Reformulate the search request using only the searching
   30.98 +            options listed in search_old in the IMAP4 grammar.  This may
   30.99 +            entail doing multiple searches to achieve the desired
  30.100 +            results.
  30.101 +
  30.102 +   BODYSTRUCTURE fetch data item
  30.103 +            Try to fetch the non-extensible BODY data item.
  30.104 +
  30.105 +   body section number 0
  30.106 +            Fetch the entire message and extract the header.
  30.107 +
  30.108 +   RFC822.HEADER.LINES and RFC822.HEADER.LINES.NOT fetch data items
  30.109 +            Use RFC822.HEADER and remove the unwanted information.
  30.110 +
  30.111 +   BODY.PEEK[section], RFC822.PEEK, and RFC822.TEXT.PEEK fetch data
  30.112 +            items Use the corresponding non-PEEK versions and manually
  30.113 +            clear the \Seen flag as necessary.
  30.114 +
  30.115 +
  30.116 +
  30.117 +Crispin                                                         [Page 2]
  30.118 +
  30.119 +RFC 1732                 IMAP4 - Compatibility             December 1994
  30.120 +
  30.121 +
  30.122 +   UID fetch data item and the UID commands
  30.123 +            No equivalent capabilitity exists in older servers.
  30.124 +
  30.125 +   FLAGS.SILENT, +FLAGS.SILENT, and -FLAGS.SILENT store data items
  30.126 +            Use the corresponding non-SILENT versions and ignore the
  30.127 +            untagged FETCH responses which com eback.
  30.128 +
  30.129 +
  30.130 +   The following IMAP4 facilities were introduced in the experimental
  30.131 +   IMAP2bis revisions to RFC-1176, and may be present in a server that
  30.132 +   does not support the CAPABILITY command:
  30.133 +
  30.134 +   CREATE, DELETE, and RENAME commands
  30.135 +            To test whether these commands are present, try a CREATE
  30.136 +            INBOX command.  If the response is NO, these commands are
  30.137 +            supported by the server.  If the response is BAD, they are
  30.138 +            not.  Older servers without the CREATE capability may sup-
  30.139 +            port implicit creation of a mailbox by a COPY command with a
  30.140 +            non-existant name as the destination.
  30.141 +
  30.142 +   APPEND command
  30.143 +            To test whether this command is present, try to append a
  30.144 +            zero-length stream to a mailbox name that is known not to
  30.145 +            exist (or at least, highly unlikely to exist) on the remote
  30.146 +            system.
  30.147 +
  30.148 +   SUBSCRIBE and UNSUBSCRIBE commands
  30.149 +            Try the form of these commands with the optional MAILBOX
  30.150 +            keyword.
  30.151 +
  30.152 +   EXAMINE command
  30.153 +            Use the SELECT command instead.
  30.154 +
  30.155 +   flags and internal date argument to APPEND command
  30.156 +            Try the APPEND without any flag list and internal date argu-
  30.157 +            ments.
  30.158 +
  30.159 +   BODY, BODY[section], and FULL fetch data items
  30.160 +            Use RFC822.TEXT and ALL instead.  Server does not support
  30.161 +            MIME.
  30.162 +
  30.163 +   PARTIAL command
  30.164 +            Use the appropriate FETCH command and ignore the unwanted
  30.165 +            data.
  30.166 +
  30.167 +
  30.168 +   IMAP4 client implementations must accept all responses and data for-
  30.169 +   mats documented in the IMAP4 specification, including those labeled
  30.170 +
  30.171 +
  30.172 +
  30.173 +Crispin                                                         [Page 3]
  30.174 +
  30.175 +RFC 1732                 IMAP4 - Compatibility             December 1994
  30.176 +
  30.177 +
  30.178 +   as obsolete.  This includes the COPY and STORE unsolicited responses
  30.179 +   and the old format of dates and times.  In particular, client imple-
  30.180 +   mentations must not treat a date/time as a fixed format string; nor
  30.181 +   may they assume that the time begins at a particular octet.
  30.182 +
  30.183 +   IMAP4 client implementations must not depend upon the presence of any
  30.184 +   server extensions that are not in the base IMAP4 specification.
  30.185 +
  30.186 +   The experimental IMAP2bis version specified that the TRYCREATE spe-
  30.187 +   cial information token is sent as a separate unsolicited OK response
  30.188 +   instead of inside the NO response.
  30.189 +
  30.190 +   The FIND BBOARDS, FIND ALL.BBOARDS, and BBOARD commands of RFC 1176
  30.191 +   are removed from IMAP4.  There is no equivalent to the bboard com-
  30.192 +   mands, which provided a separate namespace with implicit restrictions
  30.193 +   on what may be done in that namespace.
  30.194 +
  30.195 +   Older server implementations may automatically create the destination
  30.196 +   mailbox on COPY if that mailbox does not already exist.  This was how
  30.197 +   a new mailbox was created in older specifications.  If the server
  30.198 +   does not support the CREATE command (see above for how to test for
  30.199 +   this), it will probably create a mailbox on COPY.
  30.200 +
  30.201 +   Older server implementations may not preserve flags or internal dates
  30.202 +   on COPY.  Some server implementations may not permit the preservation
  30.203 +   of certain flags on COPY or their setting with APPEND as site policy.
  30.204 +
  30.205 +
  30.206 +
  30.207 +
  30.208 +
  30.209 +
  30.210 +
  30.211 +
  30.212 +
  30.213 +
  30.214 +
  30.215 +
  30.216 +
  30.217 +
  30.218 +
  30.219 +
  30.220 +
  30.221 +
  30.222 +
  30.223 +
  30.224 +
  30.225 +
  30.226 +
  30.227 +
  30.228 +
  30.229 +Crispin                                                         [Page 4]
  30.230 +
  30.231 +RFC 1732                 IMAP4 - Compatibility             December 1994
  30.232 +
  30.233 +
  30.234 +IMAP4 server interoperability with old clients
  30.235 +
  30.236 +   In general, there should be no interoperation problem between a
  30.237 +   server conforming to the IMAP4 specification and a well-written
  30.238 +   client that conforms to an earlier specification.  Known problems are
  30.239 +   noted below:
  30.240 +
  30.241 +      Poor wording in the description of the CHECK command in earlier
  30.242 +      specifications implied that a CHECK command is the way to get the
  30.243 +      current number of messages in the mailbox.  This is incorrect.  A
  30.244 +      CHECK command does not necessarily result in an EXISTS response.
  30.245 +      Clients must remember the most recent EXISTS value sent from the
  30.246 +      server, and should not generate unnecessary CHECK commands.
  30.247 +
  30.248 +      An incompatibility exists with COPY in IMAP4.  COPY in IMAP4
  30.249 +      servers does not automatically create the destination mailbox if
  30.250 +      that mailbox does not already exist.  This may cause problems with
  30.251 +      old clients that expect automatic mailbox creation in COPY.
  30.252 +
  30.253 +      The PREAUTH unsolicited response is new in IMAP4.  It is highly
  30.254 +      unlikely that an old client would ever see this response.
  30.255 +
  30.256 +      The format of dates and times has changed due to the impending end
  30.257 +      of the century.  Clients that fail to accept a four-digit year or
  30.258 +      a signed four-digit timezone value will not work properly with
  30.259 +      IMAP4.
  30.260 +
  30.261 +      An incompatibility exists with the use of "\" in quoted strings.
  30.262 +      This is best avoided by using literals instead of quoted strings
  30.263 +      if "\" or <"> is embedded in the string.
  30.264 +
  30.265 +Security Considerations
  30.266 +
  30.267 +   Security issues are not discussed in this memo.
  30.268 +
  30.269 +Author's Address:
  30.270 +
  30.271 +   Mark R. Crispin
  30.272 +   Networks and Distributed Computing, JE-30
  30.273 +   University of Washington
  30.274 +   Seattle, WA  98195
  30.275 +
  30.276 +   Phone: (206) 543-5762
  30.277 +
  30.278 +   EMail: MRC@CAC.Washington.EDU
  30.279 +
  30.280 +
  30.281 +
  30.282 +
  30.283 +
  30.284 +
  30.285 +Crispin                                                         [Page 5]
  30.286 +
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/docs/rfc/rfc1733.txt	Mon Sep 14 15:17:45 2009 +0900
    31.3 @@ -0,0 +1,171 @@
    31.4 +
    31.5 +
    31.6 +
    31.7 +
    31.8 +
    31.9 +
   31.10 +Network Working Group                                         M. Crispin
   31.11 +Request for Comments: 1733                      University of Washington
   31.12 +Category: Informational                                    December 1994
   31.13 +
   31.14 +
   31.15 +              DISTRIBUTED ELECTRONIC MAIL MODELS IN IMAP4
   31.16 +
   31.17 +
   31.18 +Status of this Memo
   31.19 +
   31.20 +   This memo provides information for the Internet community.  This memo
   31.21 +   does not specify an Internet standard of any kind.  Distribution of
   31.22 +   this memo is unlimited.
   31.23 +
   31.24 +
   31.25 +Distributed Electronic Mail Models
   31.26 +
   31.27 +   There are three fundamental models of client/server email: offline,
   31.28 +   online, and disconnected use.  IMAP4 can be used in any one of these
   31.29 +   three models.
   31.30 +
   31.31 +   The offline model is the most familiar form of client/server email
   31.32 +   today, and is used by protocols such as POP-3 (RFC 1225) and UUCP.
   31.33 +   In this model, a client application periodically connects to a
   31.34 +   server.  It downloads all the pending messages to the client machine
   31.35 +   and deletes these from the server.  Thereafter, all mail processing
   31.36 +   is local to the client.  This model is store-and-forward; it moves
   31.37 +   mail on demand from an intermediate server (maildrop) to a single
   31.38 +   destination machine.
   31.39 +
   31.40 +   The online model is most commonly used with remote filesystem
   31.41 +   protocols such as NFS.  In this model, a client application
   31.42 +   manipulates mailbox data on a server machine.  A connection to the
   31.43 +   server is maintained throughout the session.  No mailbox data are
   31.44 +   kept on the client; the client retrieves data from the server as is
   31.45 +   needed.  IMAP4 introduces a form of the online model that requires
   31.46 +   considerably less network bandwidth than a remote filesystem
   31.47 +   protocol, and provides the opportunity for using the server for CPU
   31.48 +   or I/O intensive functions such as parsing and searching.
   31.49 +
   31.50 +   The disconnected use model is a hybrid of the offline and online
   31.51 +   models, and is used by protocols such as PCMAIL (RFC 1056).  In this
   31.52 +   model, a client user downloads some set of messages from the server,
   31.53 +   manipulates them offline, then at some later time uploads the
   31.54 +   changes.  The server remains the authoritative repository of the
   31.55 +   messages.  The problems of synchronization (particularly when
   31.56 +   multiple clients are involved) are handled through the means of
   31.57 +   unique identifiers for each message.
   31.58 +
   31.59 +
   31.60 +
   31.61 +Crispin                                                         [Page 1]
   31.62 +
   31.63 +RFC 1733                     IMAP4 - Model                 December 1994
   31.64 +
   31.65 +
   31.66 +   Each of these models have their own strengths and weaknesses:
   31.67 +
   31.68 +      Feature                               Offline Online  Disc
   31.69 +      -------                               ------- ------  ----
   31.70 +      Can use multiple clients               NO      YES     YES
   31.71 +      Minimum use of server connect time     YES     NO      YES
   31.72 +      Minimum use of server resources        YES     NO      NO
   31.73 +      Minimum use of client disk resources   NO      YES     NO
   31.74 +      Multiple remote mailboxes              NO      YES     YES
   31.75 +      Fast startup                           NO      YES     NO
   31.76 +      Mail processing when not online        YES     NO      YES
   31.77 +
   31.78 +   Although IMAP4 has its origins as a protocol designed to accommodate
   31.79 +   the online model, it can support the other two models as well.  This
   31.80 +   makes possible the creation of clients that can be used in any of the
   31.81 +   three models.  For example, a user may wish to switch between the
   31.82 +   online and disconnected models on a regular basis (e.g. owing to
   31.83 +   travel).
   31.84 +
   31.85 +   IMAP4 is designed to transmit message data on demand, and to provide
   31.86 +   the facilities necessary for a client to decide what data it needs at
   31.87 +   any particular time.  There is generally no need to do a wholesale
   31.88 +   transfer of an entire mailbox or even of the complete text of a
   31.89 +   message.  This makes a difference in situations where the mailbox is
   31.90 +   large, or when the link to the server is slow.
   31.91 +
   31.92 +   More specifically, IMAP4 supports server-based RFC 822 and MIME
   31.93 +   processing.  With this information, it is possible for a client to
   31.94 +   determine in advance whether it wishes to retrieve a particular
   31.95 +   message or part of a message.  For example, a user connected to an
   31.96 +   IMAP4 server via a dialup link can determine that a message has a
   31.97 +   2000 byte text segment and a 40 megabyte video segment, and elect to
   31.98 +   fetch only the text segment.
   31.99 +
  31.100 +   In IMAP4, the client/server relationship lasts only for the duration
  31.101 +   of the TCP connection.  There is no registration of clients.  Except
  31.102 +   for any unique identifiers used in disconnected use operation, the
  31.103 +   client initially has no knowledge of mailbox state and learns it from
  31.104 +   the IMAP4 server when a mailbox is selected.  This initial transfer
  31.105 +   is minimal; the client requests additional state data as it needs.
  31.106 +
  31.107 +   As noted above, the choice for the location of mailbox data depends
  31.108 +   upon the model chosen.  The location of message state (e.g. whether
  31.109 +   or not a message has been read or answered) is also determined by the
  31.110 +   model, and is not necessarily the same as the location of the mailbox
  31.111 +   data.  For example, in the online model message state can be co-
  31.112 +   located with mailbox data; it can also be located elsewhere (on the
  31.113 +   client or on a third agent) using unique identifiers to achieve
  31.114 +
  31.115 +
  31.116 +
  31.117 +Crispin                                                         [Page 2]
  31.118 +
  31.119 +RFC 1733                     IMAP4 - Model                 December 1994
  31.120 +
  31.121 +
  31.122 +   common reference across sessions.  The latter is particularly useful
  31.123 +   with a server that exports public data such as netnews and does not
  31.124 +   maintain per-user state.
  31.125 +
  31.126 +   The IMAP4 protocol provides the generality to implement these
  31.127 +   different models.  This is done by means of server and (especially)
  31.128 +   client configuration, and not by requiring changes to the protocol or
  31.129 +   the implementation of the protocol.
  31.130 +
  31.131 +
  31.132 +Security Considerations
  31.133 +
  31.134 +   Security issues are not discussed in this memo.
  31.135 +
  31.136 +
  31.137 +Author's Address:
  31.138 +
  31.139 +   Mark R. Crispin
  31.140 +   Networks and Distributed Computing, JE-30
  31.141 +   University of Washington
  31.142 +   Seattle, WA  98195
  31.143 +
  31.144 +   Phone: (206) 543-5762
  31.145 +
  31.146 +   EMail: MRC@CAC.Washington.EDU
  31.147 +
  31.148 +
  31.149 +
  31.150 +
  31.151 +
  31.152 +
  31.153 +
  31.154 +
  31.155 +
  31.156 +
  31.157 +
  31.158 +
  31.159 +
  31.160 +
  31.161 +
  31.162 +
  31.163 +
  31.164 +
  31.165 +
  31.166 +
  31.167 +
  31.168 +
  31.169 +
  31.170 +
  31.171 +
  31.172 +
  31.173 +Crispin                                                         [Page 3]
  31.174 +
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/docs/rfc/rfc2061.txt	Mon Sep 14 15:17:45 2009 +0900
    32.3 @@ -0,0 +1,171 @@
    32.4 +
    32.5 +
    32.6 +
    32.7 +
    32.8 +
    32.9 +
   32.10 +Network Working Group                                         M. Crispin
   32.11 +Request for Comments: 2061                      University of Washington
   32.12 +Category: Informational                                    December 1996
   32.13 +
   32.14 +
   32.15 +                   IMAP4 COMPATIBILITY WITH IMAP2BIS
   32.16 +
   32.17 +Status of this Memo
   32.18 +
   32.19 +   This memo provides information for the Internet community.  This memo
   32.20 +   does not specify an Internet standard of any kind.  Distribution of
   32.21 +   this memo is unlimited.
   32.22 +
   32.23 +Introduction
   32.24 +
   32.25 +   The Internet Message Access Protocol (IMAP) has been through several
   32.26 +   revisions and variants in its 10-year history.  Many of these are
   32.27 +   either extinct or extremely rare; in particular, several undocumented
   32.28 +   variants and the variants described in RFC 1064, RFC 1176, and RFC
   32.29 +   1203 fall into this category.
   32.30 +
   32.31 +   One variant, IMAP2bis, is at the time of this writing very common and
   32.32 +   has been widely distributed with the Pine mailer.  Unfortunately,
   32.33 +   there is no definite document describing IMAP2bis.  This document is
   32.34 +   intended to be read along with RFC 1176 and the most recent IMAP4
   32.35 +   specification (RFC 2060) to assist implementors in creating an IMAP4
   32.36 +   implementation to interoperate with implementations that conform to
   32.37 +   earlier specifications.  Nothing in this document is required by the
   32.38 +   IMAP4 specification; implementors must decide for themselves whether
   32.39 +   they want their implementation to fail if it encounters old software.
   32.40 +
   32.41 +   At the time of this writing, IMAP4 has been updated from the version
   32.42 +   described in RFC 1730.  An implementor who wishes to interoperate
   32.43 +   with both RFC 1730 and RFC 2060 should refer to both documents.
   32.44 +
   32.45 +   This information is not complete; it reflects current knowledge of
   32.46 +   server and client implementations as well as "folklore" acquired in
   32.47 +   the evolution of the protocol.  It is NOT a description of how to
   32.48 +   interoperate with all variants of IMAP, but rather with the old
   32.49 +   variant that is most likely to be encountered.  For detailed
   32.50 +   information on interoperating with other old variants, refer to RFC
   32.51 +   1732.
   32.52 +
   32.53 +IMAP4 client interoperability with IMAP2bis servers
   32.54 +
   32.55 +   A quick way to check whether a server implementation supports the
   32.56 +   IMAP4 specification is to try the CAPABILITY command.  An OK response
   32.57 +   will indicate which variant(s) of IMAP4 are supported by the server.
   32.58 +
   32.59 +
   32.60 +
   32.61 +Crispin                      Informational                      [Page 1]
   32.62 +
   32.63 +RFC 2061                  IMAP4 Compatibility              December 1996
   32.64 +
   32.65 +
   32.66 +   If the client does not find any of its known variant in the response,
   32.67 +   it should treat the server as IMAP2bis.  A BAD response indicates an
   32.68 +   IMAP2bis or older server.
   32.69 +
   32.70 +   Most IMAP4 facilities are in IMAP2bis.  The following exceptions
   32.71 +   exist:
   32.72 +
   32.73 +   CAPABILITY command
   32.74 +            The absense of this command indicates IMAP2bis (or older).
   32.75 +
   32.76 +   AUTHENTICATE command.
   32.77 +            Use the LOGIN command.
   32.78 +
   32.79 +   LSUB, SUBSCRIBE, and UNSUBSCRIBE commands
   32.80 +            No direct functional equivalent.  IMAP2bis had a concept
   32.81 +            called "bboards" which is not in IMAP4.  RFC 1176 supported
   32.82 +            these with the BBOARD and FIND BBOARDS commands.  IMAP2bis
   32.83 +            augmented these with the FIND ALL.BBOARDS, SUBSCRIBE BBOARD,
   32.84 +            and UNSUBSCRIBE BBOARD commands.  It is recommended that
   32.85 +            none of these commands be implemented in new software,
   32.86 +            including servers that support old clients.
   32.87 +
   32.88 +   LIST command
   32.89 +            Use the command FIND ALL.MAILBOXES, which has a similar syn-
   32.90 +            tax and response to the FIND MAILBOXES command described in
   32.91 +            RFC 1176.  The FIND MAILBOXES command is unlikely to produce
   32.92 +            useful information.
   32.93 +
   32.94 +   * in a sequence
   32.95 +            Use the number of messages in the mailbox from the EXISTS
   32.96 +            unsolicited response.
   32.97 +
   32.98 +   SEARCH extensions (character set, additional criteria)
   32.99 +            Reformulate the search request using only the RFC 1176 syn-
  32.100 +            tax.  This may entail doing multiple searches to achieve the
  32.101 +            desired results.
  32.102 +
  32.103 +   BODYSTRUCTURE fetch data item
  32.104 +            Use the non-extensible BODY data item.
  32.105 +
  32.106 +   body sections HEADER, TEXT, MIME, HEADER.FIELDS, HEADER.FIELDS.NOT
  32.107 +            Use body section numbers only.
  32.108 +
  32.109 +   BODY.PEEK[section]
  32.110 +            Use BODY[section] and manually clear the \Seen flag as
  32.111 +            necessary.
  32.112 +
  32.113 +
  32.114 +
  32.115 +
  32.116 +
  32.117 +Crispin                      Informational                      [Page 2]
  32.118 +
  32.119 +RFC 2061                  IMAP4 Compatibility              December 1996
  32.120 +
  32.121 +
  32.122 +   FLAGS.SILENT, +FLAGS.SILENT, and -FLAGS.SILENT store data items
  32.123 +            Use the corresponding non-SILENT versions and ignore the
  32.124 +            untagged FETCH responses which come back.
  32.125 +
  32.126 +   UID fetch data item and the UID commands
  32.127 +            No functional equivalent.
  32.128 +
  32.129 +   CLOSE command
  32.130 +            No functional equivalent.
  32.131 +
  32.132 +
  32.133 +   In IMAP2bis, the TRYCREATE special information token is sent as a
  32.134 +   separate unsolicited OK response instead of inside the NO response.
  32.135 +
  32.136 +   IMAP2bis is ambiguous about whether or not flags or internal dates
  32.137 +   are preserved on COPY.  It is impossible to know what behavior is
  32.138 +   supported by the server.
  32.139 +
  32.140 +IMAP4 server interoperability with IMAP2bis clients
  32.141 +
  32.142 +   The only interoperability problem between an IMAP4 server and a
  32.143 +   well-written IMAP2bis client is an incompatibility with the use of
  32.144 +   "\" in quoted strings.  This is best avoided by using literals
  32.145 +   instead of quoted strings if "\" or <"> is embedded in the string.
  32.146 +
  32.147 +Security Considerations
  32.148 +
  32.149 +   Security issues are not discussed in this memo.
  32.150 +
  32.151 +Author's Address
  32.152 +
  32.153 +   Mark R. Crispin
  32.154 +   Networks and Distributed Computing
  32.155 +   University of Washington
  32.156 +   4545 15th Aveneue NE
  32.157 +   Seattle, WA  98105-4527
  32.158 +
  32.159 +   Phone: (206) 543-5762
  32.160 +   EMail: MRC@CAC.Washington.EDU
  32.161 +
  32.162 +
  32.163 +
  32.164 +
  32.165 +
  32.166 +
  32.167 +
  32.168 +
  32.169 +
  32.170 +
  32.171 +
  32.172 +
  32.173 +Crispin                      Informational                      [Page 3]
  32.174 +
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/docs/rfc/rfc2062.txt	Mon Sep 14 15:17:45 2009 +0900
    33.3 @@ -0,0 +1,451 @@
    33.4 +
    33.5 +
    33.6 +
    33.7 +
    33.8 +
    33.9 +
   33.10 +Network Working Group                                         M. Crispin
   33.11 +Request for Comments: 2062                      University of Washington
   33.12 +Category: Informational                                    December 1996
   33.13 +
   33.14 +
   33.15 +           Internet Message Access Protocol - Obsolete Syntax
   33.16 +
   33.17 +Status of this Memo
   33.18 +
   33.19 +   This memo provides information for the Internet community.  This memo
   33.20 +   does not specify an Internet standard of any kind.  Distribution of
   33.21 +   this memo is unlimited.
   33.22 +
   33.23 +Abstract
   33.24 +
   33.25 +   This document describes obsolete syntax which may be encountered by
   33.26 +   IMAP4 implementations which deal with older versions of the Internet
   33.27 +   Mail Access Protocol.  IMAP4 implementations MAY implement this
   33.28 +   syntax in order to maximize interoperability with older
   33.29 +   implementations.
   33.30 +
   33.31 +   This document repeats information from earlier documents, most
   33.32 +   notably RFC 1176 and RFC 1730.
   33.33 +
   33.34 +Obsolete Commands and Fetch Data Items
   33.35 +
   33.36 +   The following commands are OBSOLETE.  It is NOT required to support
   33.37 +   any of these commands or fetch data items in new server
   33.38 +   implementations.  These commands are documented here for the benefit
   33.39 +   of implementors who may wish to support them for compatibility with
   33.40 +   old client implementations.
   33.41 +
   33.42 +   The section headings of these commands are intended to correspond
   33.43 +   with where they would be located in the main document if they were
   33.44 +   not obsoleted.
   33.45 +
   33.46 +6.3.OBS.1.      FIND ALL.MAILBOXES Command
   33.47 +
   33.48 +   Arguments:  mailbox name with possible wildcards
   33.49 +
   33.50 +   Data:       untagged responses: MAILBOX
   33.51 +
   33.52 +   Result:     OK - find completed
   33.53 +               NO - find failure: can't list that name
   33.54 +               BAD - command unknown or arguments invalid
   33.55 +
   33.56 +
   33.57 +
   33.58 +
   33.59 +
   33.60 +
   33.61 +Crispin                      Informational                      [Page 1]
   33.62 +
   33.63 +RFC 2062                     IMAP4 Obsolete                December 1996
   33.64 +
   33.65 +
   33.66 +      The FIND ALL.MAILBOXES command returns a subset of names from the
   33.67 +      complete set of all names available to the user.  It returns zero
   33.68 +      or more untagged MAILBOX replies.  The mailbox argument to FIND
   33.69 +      ALL.MAILBOXES is similar to that for LIST with an empty reference,
   33.70 +      except that the characters "%" and "?" match a single character.
   33.71 +
   33.72 +   Example:    C: A002 FIND ALL.MAILBOXES *
   33.73 +               S: * MAILBOX blurdybloop
   33.74 +               S: * MAILBOX INBOX
   33.75 +               S: A002 OK FIND ALL.MAILBOXES completed
   33.76 +
   33.77 +6.3.OBS.2.      FIND MAILBOXES Command
   33.78 +
   33.79 +   Arguments:  mailbox name with possible wildcards
   33.80 +
   33.81 +   Data:       untagged responses: MAILBOX
   33.82 +
   33.83 +   Result:     OK - find completed
   33.84 +               NO - find failure: can't list that name
   33.85 +               BAD - command unknown or arguments invalid
   33.86 +
   33.87 +      The FIND MAILBOXES command returns a subset of names from the set
   33.88 +      of names that the user has declared as being "active" or
   33.89 +      "subscribed".  It returns zero or more untagged MAILBOX replies.
   33.90 +      The mailbox argument to FIND MAILBOXES is similar to that for LSUB
   33.91 +      with an empty reference, except that the characters "%" and "?"
   33.92 +      match a single character.
   33.93 +
   33.94 +   Example:    C: A002 FIND MAILBOXES *
   33.95 +               S: * MAILBOX blurdybloop
   33.96 +               S: * MAILBOX INBOX
   33.97 +               S: A002 OK FIND MAILBOXES completed
   33.98 +
   33.99 +6.3.OBS.3.      SUBSCRIBE MAILBOX Command
  33.100 +
  33.101 +   Arguments:  mailbox name
  33.102 +
  33.103 +   Data:       no specific data for this command
  33.104 +
  33.105 +   Result:     OK - subscribe completed
  33.106 +               NO - subscribe failure: can't subscribe to that name
  33.107 +               BAD - command unknown or arguments invalid
  33.108 +
  33.109 +      The SUBSCRIBE MAILBOX command is identical in effect to the
  33.110 +      SUBSCRIBE command.  A server which implements this command must be
  33.111 +      able to distinguish between a SUBSCRIBE MAILBOX command and a
  33.112 +      SUBSCRIBE command with a mailbox name argument of "MAILBOX".
  33.113 +
  33.114 +
  33.115 +
  33.116 +
  33.117 +Crispin                      Informational                      [Page 2]
  33.118 +
  33.119 +RFC 2062                     IMAP4 Obsolete                December 1996
  33.120 +
  33.121 +
  33.122 +   Example:    C: A002 SUBSCRIBE MAILBOX #news.comp.mail.mime
  33.123 +               S: A002 OK SUBSCRIBE MAILBOX to #news.comp.mail.mime
  33.124 +               completed
  33.125 +               C: A003 SUBSCRIBE MAILBOX
  33.126 +               S: A003 OK SUBSCRIBE to MAILBOX completed
  33.127 +
  33.128 +
  33.129 +6.3.OBS.4.      UNSUBSCRIBE MAILBOX Command
  33.130 +
  33.131 +   Arguments:  mailbox name
  33.132 +
  33.133 +   Data:       no specific data for this command
  33.134 +
  33.135 +   Result:     OK - unsubscribe completed
  33.136 +               NO - unsubscribe failure: can't unsubscribe that name
  33.137 +               BAD - command unknown or arguments invalid
  33.138 +
  33.139 +      The UNSUBSCRIBE MAILBOX command is identical in effect to the
  33.140 +      UNSUBSCRIBE command.  A server which implements this command must
  33.141 +      be able to distinguish between a UNSUBSCRIBE MAILBOX command and
  33.142 +      an UNSUBSCRIBE command with a mailbox name argument of "MAILBOX".
  33.143 +
  33.144 +   Example:    C: A002 UNSUBSCRIBE MAILBOX #news.comp.mail.mime
  33.145 +               S: A002 OK UNSUBSCRIBE MAILBOX from #news.comp.mail.mime
  33.146 +               completed
  33.147 +               C: A003 UNSUBSCRIBE MAILBOX
  33.148 +               S: A003 OK UNSUBSCRIBE from MAILBOX completed
  33.149 +
  33.150 +6.4.OBS.1       PARTIAL Command
  33.151 +
  33.152 +   Arguments:  message sequence number
  33.153 +               message data item name
  33.154 +               position of first octet
  33.155 +               number of octets
  33.156 +
  33.157 +   Data:       untagged responses: FETCH
  33.158 +
  33.159 +   Result:     OK - partial completed
  33.160 +               NO - partial error: can't fetch that data
  33.161 +               BAD - command unknown or arguments invalid
  33.162 +
  33.163 +      The PARTIAL command is equivalent to the associated FETCH command,
  33.164 +      with the added functionality that only the specified number of
  33.165 +      octets, beginning at the specified starting octet, are returned.
  33.166 +      Only a single message can be fetched at a time.  The first octet
  33.167 +      of a message, and hence the minimum for the starting octet, is
  33.168 +      octet 1.
  33.169 +
  33.170 +
  33.171 +
  33.172 +
  33.173 +Crispin                      Informational                      [Page 3]
  33.174 +
  33.175 +RFC 2062                     IMAP4 Obsolete                December 1996
  33.176 +
  33.177 +
  33.178 +      The following FETCH items are valid data for PARTIAL: RFC822,
  33.179 +      RFC822.HEADER, RFC822.TEXT, BODY[<section>], as well as any .PEEK
  33.180 +      forms of these.
  33.181 +
  33.182 +      Any partial fetch that attempts to read beyond the end of the text
  33.183 +      is truncated as appropriate.  If the starting octet is beyond the
  33.184 +      end of the text, an empty string is returned.
  33.185 +
  33.186 +      The data are returned with the FETCH response.  There is no
  33.187 +      indication of the range of the partial data in this response.  It
  33.188 +      is not possible to stream multiple PARTIAL commands of the same
  33.189 +      data item without processing and synchronizing at each step, since
  33.190 +      streamed commands may be executed out of order.
  33.191 +
  33.192 +      There is no requirement that partial fetches follow any sequence.
  33.193 +      For example, if a partial fetch of octets 1 through 10000 breaks
  33.194 +      in an awkward place for BASE64 decoding, it is permitted to
  33.195 +      continue with a partial fetch of 9987 through 19987, etc.
  33.196 +
  33.197 +      The handling of the \Seen flag is the same as in the associated
  33.198 +      FETCH command.
  33.199 +
  33.200 +   Example:    C: A005 PARTIAL 4 RFC822 1 1024
  33.201 +               S: * 1 FETCH (RFC822 {1024}
  33.202 +               S: Return-Path: <gray@cac.washington.edu>
  33.203 +               S: ...
  33.204 +               S: .........  FLAGS (\Seen))
  33.205 +               S: A005 OK PARTIAL completed
  33.206 +
  33.207 +6.4.5.OBS.1     Obsolete FETCH Data Items
  33.208 +
  33.209 +   The following FETCH data items are obsolete:
  33.210 +
  33.211 +      BODY[<...>0]   A body part number of 0 is the [RFC-822] header of
  33.212 +                     the message.  BODY[0] is functionally equivalent to
  33.213 +                     BODY[HEADER], differing in the syntax of the
  33.214 +                     resulting untagged FETCH data (BODY[0] is
  33.215 +                     returned).
  33.216 +
  33.217 +      RFC822.HEADER.LINES <header_list>
  33.218 +                     Functionally equivalent to BODY.PEEK[HEADER.LINES
  33.219 +                     <header_list>], differing in the syntax of the
  33.220 +                     resulting untagged FETCH data (RFC822.HEADER is
  33.221 +                     returned).
  33.222 +
  33.223 +
  33.224 +
  33.225 +
  33.226 +
  33.227 +
  33.228 +
  33.229 +Crispin                      Informational                      [Page 4]
  33.230 +
  33.231 +RFC 2062                     IMAP4 Obsolete                December 1996
  33.232 +
  33.233 +
  33.234 +      RFC822.HEADER.LINES.NOT <header_list>
  33.235 +                     Functionally equivalent to
  33.236 +                     BODY.PEEK[HEADER.LINES.NOT <header_list>],
  33.237 +                     differing in the syntax of the resulting untagged
  33.238 +                     FETCH data (RFC822.HEADER is returned).
  33.239 +
  33.240 +      RFC822.PEEK    Functionally equivalent to BODY.PEEK[], except for
  33.241 +                     the syntax of the resulting untagged FETCH data
  33.242 +                     (RFC822 is returned).
  33.243 +
  33.244 +      RFC822.TEXT.PEEK
  33.245 +                     Functionally equivalent to BODY.PEEK[TEXT], except
  33.246 +                     for the syntax of the resulting untagged FETCH data
  33.247 +                     (RFC822.TEXT is returned).
  33.248 +
  33.249 +Obsolete Responses
  33.250 +
  33.251 +   The following responses are OBSOLETE.  Except as noted below, these
  33.252 +   responses MUST NOT be transmitted by new server implementations.
  33.253 +   Client implementations SHOULD accept these responses.
  33.254 +
  33.255 +   The section headings of these responses are intended to correspond
  33.256 +   with where they would be located in the main document if they were
  33.257 +   not obsoleted.
  33.258 +
  33.259 +7.2.OBS.1.      MAILBOX Response
  33.260 +
  33.261 +   Data:       name
  33.262 +
  33.263 +      The MAILBOX response MUST NOT be transmitted by server
  33.264 +      implementations except in response to the obsolete FIND MAILBOXES
  33.265 +      and FIND ALL.MAILBOXES commands.  Client implementations that do
  33.266 +      not use these commands MAY ignore this response.  It is documented
  33.267 +      here for the benefit of implementors who may wish to support it
  33.268 +      for compatibility with old client implementations.
  33.269 +
  33.270 +      This response occurs as a result of the FIND MAILBOXES and FIND
  33.271 +      ALL.MAILBOXES commands.  It returns a single name that matches the
  33.272 +      FIND specification.  There are no attributes or hierarchy
  33.273 +      delimiter.
  33.274 +
  33.275 +   Example:    S: * MAILBOX blurdybloop
  33.276 +
  33.277 +
  33.278 +
  33.279 +
  33.280 +
  33.281 +
  33.282 +
  33.283 +
  33.284 +
  33.285 +Crispin                      Informational                      [Page 5]
  33.286 +
  33.287 +RFC 2062                     IMAP4 Obsolete                December 1996
  33.288 +
  33.289 +
  33.290 +7.3.OBS.1.      COPY Response
  33.291 +
  33.292 +   Data:       none
  33.293 +
  33.294 +      The COPY response MUST NOT be transmitted by new server
  33.295 +      implementations.  Client implementations MUST ignore the COPY
  33.296 +      response.  It is documented here for the benefit of client
  33.297 +      implementors who may encounter this response from old server
  33.298 +      implementations.
  33.299 +
  33.300 +      In some experimental versions of this protocol, this response was
  33.301 +      returned in response to a COPY command to indicate on a
  33.302 +      per-message basis that the message was copied successfully.
  33.303 +
  33.304 +   Example:    S: * 44 COPY
  33.305 +
  33.306 +7.3.OBS.2.      STORE Response
  33.307 +
  33.308 +   Data:       message data
  33.309 +
  33.310 +      The STORE response MUST NOT be transmitted by new server
  33.311 +      implementations.  Client implementations MUST treat the STORE
  33.312 +      response as equivalent to the FETCH response.  It is documented
  33.313 +      here for the benefit of client implementors who may encounter this
  33.314 +      response from old server implementations.
  33.315 +
  33.316 +      In some experimental versions of this protocol, this response was
  33.317 +      returned instead of FETCH in response to a STORE command to report
  33.318 +      the new value of the flags.
  33.319 +
  33.320 +   Example:    S: * 69 STORE (FLAGS (\Deleted))
  33.321 +
  33.322 +Formal Syntax of Obsolete Commands and Responses
  33.323 +
  33.324 +   Each obsolete syntax rule that is suffixed with "_old" is added to
  33.325 +   the corresponding name in the formal syntax.  For example,
  33.326 +   command_auth_old adds the FIND command to command_auth.
  33.327 +
  33.328 +   command_auth_old ::= find
  33.329 +
  33.330 +   command_select_old
  33.331 +                   ::= partial
  33.332 +
  33.333 +   date_year_old   ::= 2digit
  33.334 +                       ;; (year - 1900)
  33.335 +
  33.336 +   date_time_old   ::= <"> date_day_fixed "-" date_month "-" date_year
  33.337 +                       SPACE time "-" zone_name <">
  33.338 +
  33.339 +
  33.340 +
  33.341 +Crispin                      Informational                      [Page 6]
  33.342 +
  33.343 +RFC 2062                     IMAP4 Obsolete                December 1996
  33.344 +
  33.345 +
  33.346 +   find            ::= "FIND" SPACE ["ALL."] "MAILBOXES" SPACE
  33.347 +                       list_mailbox
  33.348 +
  33.349 +   fetch_att_old   ::= "RFC822.HEADER.LINES" [".NOT"] SPACE header_list /
  33.350 +                       fetch_text_old
  33.351 +
  33.352 +   fetch_text_old  ::= "BODY" [".PEEK"] section_old /
  33.353 +                       "RFC822" [".HEADER" / ".TEXT" [".PEEK"]]
  33.354 +
  33.355 +   msg_data_old    ::= "COPY" / ("STORE" SPACE msg_att)
  33.356 +
  33.357 +   partial         ::= "PARTIAL" SPACE nz_number SPACE fetch_text_old SPACE
  33.358 +                       number SPACE number
  33.359 +
  33.360 +   section_old     ::= "[" (number ["." number]) "]"
  33.361 +
  33.362 +   subscribe_old   ::= "SUBSCRIBE" SPACE "MAILBOX" SPACE mailbox
  33.363 +
  33.364 +   unsubscribe_old ::= "UNSUBSCRIBE" SPACE "MAILBOX" SPACE mailbox
  33.365 +
  33.366 +   zone_name       ::= "UT" / "GMT" / "Z" /                ;; +0000
  33.367 +                       "AST" / "EDT" /                     ;; -0400
  33.368 +                       "EST" / "CDT" /                     ;; -0500
  33.369 +                       "CST" / "MDT" /                     ;; -0600
  33.370 +                       "MST" / "PDT" /                     ;; -0700
  33.371 +                       "PST" / "YDT" /                     ;; -0800
  33.372 +                       "YST" / "HDT" /                     ;; -0900
  33.373 +                       "HST" / "BDT" /                     ;; -1000
  33.374 +                       "BST" /                             ;; -1100
  33.375 +                       "A" / "B" / "C" / "D" / "E" / "F" / ;; +1 to +6
  33.376 +                       "G" / "H" / "I" / "K" / "L" / "M" / ;; +7 to +12
  33.377 +                       "N" / "O" / "P" / "Q" / "R" / "S" / ;; -1 to -6
  33.378 +                       "T" / "U" / "V" / "W" / "X" / "Y"   ;; -7 to -12
  33.379 +
  33.380 +Security Considerations
  33.381 +
  33.382 +   Security issues are not discussed in this memo.
  33.383 +
  33.384 +
  33.385 +
  33.386 +
  33.387 +
  33.388 +
  33.389 +
  33.390 +
  33.391 +
  33.392 +
  33.393 +
  33.394 +
  33.395 +
  33.396 +
  33.397 +Crispin                      Informational                      [Page 7]
  33.398 +
  33.399 +RFC 2062                     IMAP4 Obsolete                December 1996
  33.400 +
  33.401 +
  33.402 +Author's Address
  33.403 +
  33.404 +   Mark R. Crispin
  33.405 +   Networks and Distributed Computing
  33.406 +   University of Washington
  33.407 +   4545 15th Aveneue NE
  33.408 +   Seattle, WA  98105-4527
  33.409 +
  33.410 +   Phone: (206) 543-5762
  33.411 +   EMail: MRC@CAC.Washington.EDU
  33.412 +
  33.413 +
  33.414 +
  33.415 +
  33.416 +
  33.417 +
  33.418 +
  33.419 +
  33.420 +
  33.421 +
  33.422 +
  33.423 +
  33.424 +
  33.425 +
  33.426 +
  33.427 +
  33.428 +
  33.429 +
  33.430 +
  33.431 +
  33.432 +
  33.433 +
  33.434 +
  33.435 +
  33.436 +
  33.437 +
  33.438 +
  33.439 +
  33.440 +
  33.441 +
  33.442 +
  33.443 +
  33.444 +
  33.445 +
  33.446 +
  33.447 +
  33.448 +
  33.449 +
  33.450 +
  33.451 +
  33.452 +
  33.453 +Crispin                      Informational                      [Page 8]
  33.454 +
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/docs/rfc/rfc2087.txt	Mon Sep 14 15:17:45 2009 +0900
    34.3 @@ -0,0 +1,283 @@
    34.4 +
    34.5 +
    34.6 +
    34.7 +
    34.8 +
    34.9 +
   34.10 +Network Working Group                                           J. Myers
   34.11 +Request for Comments: 2087                               Carnegie Mellon
   34.12 +Category: Standards Track                                   January 1997
   34.13 +
   34.14 +
   34.15 +                         IMAP4 QUOTA extension
   34.16 +
   34.17 +Status of this Memo
   34.18 +
   34.19 +   This document specifies an Internet standards track protocol for the
   34.20 +   Internet community, and requests discussion and suggestions for
   34.21 +   improvements.  Please refer to the current edition of the "Internet
   34.22 +   Official Protocol Standards" (STD 1) for the standardization state
   34.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   34.24 +
   34.25 +1.   Abstract
   34.26 +
   34.27 +   The QUOTA extension of the Internet Message Access Protocol [IMAP4]
   34.28 +   permits administrative limits on resource usage (quotas) to be
   34.29 +   manipulated through the IMAP protocol.
   34.30 +
   34.31 +Table of Contents
   34.32 +
   34.33 +   1.   Abstract........................................... 1
   34.34 +   2.   Conventions Used in this Document.................. 1
   34.35 +   3.   Introduction and Overview.......................... 2
   34.36 +   4.   Commands........................................... 2
   34.37 +   4.1. SETQUOTA Command................................... 2
   34.38 +   4.2. GETQUOTA Command................................... 2
   34.39 +   4.3. GETQUOTAROOT Command............................... 3
   34.40 +   5.   Responses.......................................... 3
   34.41 +   5.1. QUOTA Response..................................... 3
   34.42 +   5.2. QUOTAROOT Response................................. 4
   34.43 +   6.   Formal syntax...................................... 4
   34.44 +   7.   References......................................... 5
   34.45 +   8.   Security Considerations............................ 5
   34.46 +   9.   Author's Address................................... 5
   34.47 +
   34.48 +
   34.49 +2.   Conventions Used in this Document
   34.50 +
   34.51 +   In examples, "C:" and "S:" indicate lines sent by the client and
   34.52 +   server respectively.
   34.53 +
   34.54 +
   34.55 +
   34.56 +
   34.57 +
   34.58 +
   34.59 +
   34.60 +
   34.61 +Myers                       Standards Track                     [Page 1]
   34.62 +
   34.63 +RFC 2087                         QUOTA                      January 1997
   34.64 +
   34.65 +
   34.66 +3.   Introduction and Overview
   34.67 +
   34.68 +   The QUOTA extension is present in any IMAP4 implementation which
   34.69 +   returns "QUOTA" as one of the supported capabilities to the
   34.70 +   CAPABILITY command.
   34.71 +
   34.72 +   An IMAP4 server which supports the QUOTA capability may support
   34.73 +   limits on any number of resources.  Each resource has an atom name
   34.74 +   and an implementation-defined interpretation which evaluates to an
   34.75 +   integer.  Examples of such resources are:
   34.76 +
   34.77 +      Name       Interpretation
   34.78 +
   34.79 +      STORAGE    Sum of messages' RFC822.SIZE, in units of 1024 octets
   34.80 +      MESSAGE    Number of messages
   34.81 +
   34.82 +
   34.83 +   Each mailbox has zero or more implementation-defined named "quota
   34.84 +   roots".  Each quota root has zero or more resource limits.  All
   34.85 +   mailboxes that share the same named quota root share the resource
   34.86 +   limits of the quota root.
   34.87 +
   34.88 +   Quota root names do not necessarily have to match the names of
   34.89 +   existing mailboxes.
   34.90 +
   34.91 +4.   Commands
   34.92 +
   34.93 +4.1. SETQUOTA Command
   34.94 +
   34.95 +   Arguments:  quota root
   34.96 +               list of resource limits
   34.97 +
   34.98 +   Data:       untagged responses: QUOTA
   34.99 +
  34.100 +   Result:     OK - setquota completed
  34.101 +               NO - setquota error: can't set that data
  34.102 +               BAD - command unknown or arguments invalid
  34.103 +
  34.104 +   The SETQUOTA command takes the name of a mailbox quota root and a
  34.105 +   list of resource limits. The resource limits for the named quota root
  34.106 +   are changed to be the specified limits.  Any previous resource limits
  34.107 +   for the named quota root are discarded.
  34.108 +
  34.109 +   If the named quota root did not previously exist, an implementation
  34.110 +   may optionally create it and change the quota roots for any number of
  34.111 +   existing mailboxes in an implementation-defined manner.
  34.112 +
  34.113 +
  34.114 +
  34.115 +
  34.116 +
  34.117 +Myers                       Standards Track                     [Page 2]
  34.118 +
  34.119 +RFC 2087                         QUOTA                      January 1997
  34.120 +
  34.121 +
  34.122 +   Example:    C: A001 SETQUOTA "" (STORAGE 512)
  34.123 +               S: * QUOTA "" (STORAGE 10 512)
  34.124 +               S: A001 OK Setquota completed
  34.125 +
  34.126 +4.2. GETQUOTA Command
  34.127 +
  34.128 +   Arguments:  quota root
  34.129 +
  34.130 +   Data:       untagged responses: QUOTA
  34.131 +
  34.132 +   Result:     OK - getquota completed
  34.133 +               NO - getquota  error:  no  such  quota  root,  permission
  34.134 +               denied
  34.135 +               BAD - command unknown or arguments invalid
  34.136 +
  34.137 +   The GETQUOTA command takes the name of a quota root and returns the
  34.138 +   quota root's resource usage and limits in an untagged QUOTA response.
  34.139 +
  34.140 +   Example:    C: A003 GETQUOTA ""
  34.141 +               S: * QUOTA "" (STORAGE 10 512)
  34.142 +               S: A003 OK Getquota completed
  34.143 +
  34.144 +4.3. GETQUOTAROOT Command
  34.145 +
  34.146 +   Arguments:  mailbox name
  34.147 +
  34.148 +   Data:       untagged responses: QUOTAROOT, QUOTA
  34.149 +
  34.150 +   Result:     OK - getquota completed
  34.151 +               NO - getquota error: no such mailbox, permission denied
  34.152 +               BAD - command unknown or arguments invalid
  34.153 +
  34.154 +   The GETQUOTAROOT command takes the name of a mailbox and returns the
  34.155 +   list of quota roots for the mailbox in an untagged QUOTAROOT
  34.156 +   response.  For each listed quota root, it also returns the quota
  34.157 +   root's resource usage and limits in an untagged QUOTA response.
  34.158 +
  34.159 +   Example:    C: A003 GETQUOTAROOT INBOX
  34.160 +               S: * QUOTAROOT INBOX ""
  34.161 +               S: * QUOTA "" (STORAGE 10 512)
  34.162 +               S: A003 OK Getquota completed
  34.163 +
  34.164 +
  34.165 +
  34.166 +
  34.167 +
  34.168 +
  34.169 +
  34.170 +
  34.171 +
  34.172 +
  34.173 +Myers                       Standards Track                     [Page 3]
  34.174 +
  34.175 +RFC 2087                         QUOTA                      January 1997
  34.176 +
  34.177 +
  34.178 +5.   Responses
  34.179 +
  34.180 +5.1. QUOTA Response
  34.181 +
  34.182 +   Data:       quota root name
  34.183 +               list of resource names, usages, and limits
  34.184 +
  34.185 +      This response occurs as a result of a GETQUOTA or GETQUOTAROOT
  34.186 +      command. The first string is the name of the quota root for which
  34.187 +      this quota applies.
  34.188 +
  34.189 +      The name is followed by a S-expression format list of the resource
  34.190 +      usage and limits of the quota root.  The list contains zero or
  34.191 +      more triplets.  Each triplet conatins a resource name, the current
  34.192 +      usage of the resource, and the resource limit.
  34.193 +
  34.194 +      Resources not named in the list are not limited in the quota root.
  34.195 +      Thus, an empty list means there are no administrative resource
  34.196 +      limits in the quota root.
  34.197 +
  34.198 +      Example:    S: * QUOTA "" (STORAGE 10 512)
  34.199 +
  34.200 +5.2. QUOTAROOT Response
  34.201 +
  34.202 +   Data:       mailbox name
  34.203 +               zero or more quota root names
  34.204 +
  34.205 +      This response occurs as a result of a GETQUOTAROOT command.  The
  34.206 +      first string is the mailbox and the remaining strings are the
  34.207 +      names of the quota roots for the mailbox.
  34.208 +
  34.209 +      Example:    S: * QUOTAROOT INBOX ""
  34.210 +                  S: * QUOTAROOT comp.mail.mime
  34.211 +
  34.212 +6.   Formal syntax
  34.213 +
  34.214 +   The following syntax specification uses the augmented Backus-Naur
  34.215 +   Form (BNF) notation as specified in RFC 822 with one exception; the
  34.216 +   delimiter used with the "#" construct is a single space (SP) and not
  34.217 +   one or more commas.
  34.218 +
  34.219 +   Except as noted otherwise, all alphabetic characters are case-
  34.220 +   insensitive.  The use of upper or lower case characters to define
  34.221 +   token strings is for editorial clarity only.  Implementations MUST
  34.222 +   accept these strings in a case-insensitive fashion.
  34.223 +
  34.224 +
  34.225 +
  34.226 +
  34.227 +
  34.228 +
  34.229 +Myers                       Standards Track                     [Page 4]
  34.230 +
  34.231 +RFC 2087                         QUOTA                      January 1997
  34.232 +
  34.233 +
  34.234 +   getquota        ::= "GETQUOTA" SP astring
  34.235 +
  34.236 +   getquotaroot    ::= "GETQUOTAROOT" SP astring
  34.237 +
  34.238 +   quota_list      ::= "(" #quota_resource ")"
  34.239 +
  34.240 +   quota_resource  ::= atom SP number SP number
  34.241 +
  34.242 +   quota_response  ::= "QUOTA" SP astring SP quota_list
  34.243 +
  34.244 +   quotaroot_response
  34.245 +                   ::= "QUOTAROOT" SP astring *(SP astring)
  34.246 +
  34.247 +   setquota        ::= "SETQUOTA" SP astring SP setquota_list
  34.248 +
  34.249 +   setquota_list   ::= "(" 0#setquota_resource ")"
  34.250 +
  34.251 +   setquota_resource ::= atom SP number
  34.252 +
  34.253 +7.   References
  34.254 +
  34.255 +   [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 4",
  34.256 +   RFC 1730, University of Washington, December 1994.
  34.257 +
  34.258 +   [RFC-822] Crocker, D., "Standard for    the Format of ARPA Internet
  34.259 +   Text Messages", STD 11, RFC 822.
  34.260 +
  34.261 +8.   Security Considerations
  34.262 +
  34.263 +   Implementors should be careful to make sure the implementation of
  34.264 +   these commands does not violate the site's security policy. The
  34.265 +   resource usage of other users is likely to be considered confidential
  34.266 +   information and should not be divulged to unauthorized persons.
  34.267 +
  34.268 +9.   Author's Address
  34.269 +
  34.270 +   John G. Myers
  34.271 +   Carnegie-Mellon University
  34.272 +   5000 Forbes Ave.
  34.273 +   Pittsburgh PA, 15213-3890
  34.274 +
  34.275 +   EMail: jgm+@cmu.edu
  34.276 +
  34.277 +
  34.278 +
  34.279 +
  34.280 +
  34.281 +
  34.282 +
  34.283 +
  34.284 +
  34.285 +Myers                       Standards Track                     [Page 5]
  34.286 +
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/docs/rfc/rfc2088.txt	Mon Sep 14 15:17:45 2009 +0900
    35.3 @@ -0,0 +1,115 @@
    35.4 +
    35.5 +
    35.6 +
    35.7 +
    35.8 +
    35.9 +
   35.10 +Network Working Group                                           J. Myers
   35.11 +Request for Comments: 2088                               Carnegie Mellon
   35.12 +Cateogry: Standards Track                                   January 1997
   35.13 +
   35.14 +
   35.15 +                    IMAP4 non-synchronizing literals
   35.16 +
   35.17 +Status of this Memo
   35.18 +
   35.19 +   This document specifies an Internet standards track protocol for the
   35.20 +   Internet community, and requests discussion and suggestions for
   35.21 +   improvements.  Please refer to the current edition of the "Internet
   35.22 +   Official Protocol Standards" (STD 1) for the standardization state
   35.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   35.24 +
   35.25 +1.   Abstract
   35.26 +
   35.27 +   The Internet Message Access Protocol [IMAP4] contains the "literal"
   35.28 +   syntactic construct for communicating strings.  When sending a
   35.29 +   literal from client to server, IMAP4 requires the client to wait for
   35.30 +   the server to send a command continuation request between sending the
   35.31 +   octet count and the string data.  This document specifies an
   35.32 +   alternate form of literal which does not require this network round
   35.33 +   trip.
   35.34 +
   35.35 +2.   Conventions Used in this Document
   35.36 +
   35.37 +   In examples, "C:" and "S:" indicate lines sent by the client and
   35.38 +   server respectively.
   35.39 +
   35.40 +3.   Specification
   35.41 +
   35.42 +   The non-synchronizing literal is added an alternate form of literal,
   35.43 +   and may appear in communication from client to server instead of the
   35.44 +   IMAP4 form of literal.  The IMAP4 form of literal, used in
   35.45 +   communication from client to server, is referred to as a
   35.46 +   synchronizing literal.
   35.47 +
   35.48 +   Non-synchronizing literals may be used with any IMAP4 server
   35.49 +   implementation which returns "LITERAL+" as one of the supported
   35.50 +   capabilities to the CAPABILITY command.  If the server does not
   35.51 +   advertise the LITERAL+ capability, the client must use synchronizing
   35.52 +   literals instead.
   35.53 +
   35.54 +   The non-synchronizing literal is distinguished from the original
   35.55 +   synchronizing literal by having a plus ('+') between the octet count
   35.56 +   and the closing brace ('}').  The server does not generate a command
   35.57 +   continuation request in response to a non-synchronizing literal, and
   35.58 +
   35.59 +
   35.60 +
   35.61 +Myers                       Standards Track                     [Page 1]
   35.62 +
   35.63 +RFC 2088                        LITERAL                     January 1997
   35.64 +
   35.65 +
   35.66 +   clients are not required to wait before sending the octets of a non-
   35.67 +   synchronizing literal.
   35.68 +
   35.69 +   The protocol receiver of an IMAP4 server must check the end of every
   35.70 +   received line for an open brace ('{') followed by an octet count, a
   35.71 +   plus ('+'), and a close brace ('}') immediately preceeding the CRLF.
   35.72 +   If it finds this sequence, it is the octet count of a non-
   35.73 +   synchronizing literal and the server MUST treat the specified number
   35.74 +   of following octets and the following line as part of the same
   35.75 +   command.  A server MAY still process commands and reject errors on a
   35.76 +   line-by-line basis, as long as it checks for non-synchronizing
   35.77 +   literals at the end of each line.
   35.78 +
   35.79 +   Example:    C: A001 LOGIN {11+}
   35.80 +               C: FRED FOOBAR {7+}
   35.81 +               C: fat man
   35.82 +               S: A001 OK LOGIN completed
   35.83 +
   35.84 +4.   Formal Syntax
   35.85 +
   35.86 +   The following syntax specification uses the augmented Backus-Naur
   35.87 +   Form (BNF) notation as specified in [RFC-822] as modified by [IMAP4].
   35.88 +   Non-terminals referenced but not defined below are as defined by
   35.89 +   [IMAP4].
   35.90 +
   35.91 +   literal         ::= "{" number ["+"] "}" CRLF *CHAR8
   35.92 +                       ;; Number represents the number of CHAR8 octets
   35.93 +
   35.94 +6.   References
   35.95 +
   35.96 +   [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 4",
   35.97 +   draft-crispin-imap-base-XX.txt, University of Washington, April 1996.
   35.98 +
   35.99 +   [RFC-822] Crocker, D., "Standard for the Format of ARPA Internet Text
  35.100 +   Messages", STD 11, RFC 822.
  35.101 +
  35.102 +7.   Security Considerations
  35.103 +
  35.104 +   There are no known security issues with this extension.
  35.105 +
  35.106 +8.   Author's Address
  35.107 +
  35.108 +   John G. Myers
  35.109 +   Carnegie-Mellon University
  35.110 +   5000 Forbes Ave.
  35.111 +   Pittsburgh PA, 15213-3890
  35.112 +
  35.113 +   Email: jgm+@cmu.edu
  35.114 +
  35.115 +
  35.116 +
  35.117 +Myers                       Standards Track                     [Page 2]
  35.118 +
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/docs/rfc/rfc2177.txt	Mon Sep 14 15:17:45 2009 +0900
    36.3 @@ -0,0 +1,227 @@
    36.4 +
    36.5 +
    36.6 +
    36.7 +
    36.8 +
    36.9 +
   36.10 +Network Working Group                                           B. Leiba
   36.11 +Request for Comments: 2177               IBM T.J. Watson Research Center
   36.12 +Category: Standards Track                                      June 1997
   36.13 +
   36.14 +
   36.15 +                           IMAP4 IDLE command
   36.16 +
   36.17 +Status of this Memo
   36.18 +
   36.19 +   This document specifies an Internet standards track protocol for the
   36.20 +   Internet community, and requests discussion and suggestions for
   36.21 +   improvements.  Please refer to the current edition of the "Internet
   36.22 +   Official Protocol Standards" (STD 1) for the standardization state
   36.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   36.24 +
   36.25 +1.   Abstract
   36.26 +
   36.27 +   The Internet Message Access Protocol [IMAP4] requires a client to
   36.28 +   poll the server for changes to the selected mailbox (new mail,
   36.29 +   deletions).  It's often more desirable to have the server transmit
   36.30 +   updates to the client in real time.  This allows a user to see new
   36.31 +   mail immediately.  It also helps some real-time applications based on
   36.32 +   IMAP, which might otherwise need to poll extremely often (such as
   36.33 +   every few seconds).  (While the spec actually does allow a server to
   36.34 +   push EXISTS responses aysynchronously, a client can't expect this
   36.35 +   behaviour and must poll.)
   36.36 +
   36.37 +   This document specifies the syntax of an IDLE command, which will
   36.38 +   allow a client to tell the server that it's ready to accept such
   36.39 +   real-time updates.
   36.40 +
   36.41 +2.   Conventions Used in this Document
   36.42 +
   36.43 +   In examples, "C:" and "S:" indicate lines sent by the client and
   36.44 +   server respectively.
   36.45 +
   36.46 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
   36.47 +   in this document are to be interpreted as described in RFC 2060
   36.48 +   [IMAP4].
   36.49 +
   36.50 +3.   Specification
   36.51 +
   36.52 +   IDLE Command
   36.53 +
   36.54 +   Arguments:  none
   36.55 +
   36.56 +   Responses:  continuation data will be requested; the client sends
   36.57 +               the continuation data "DONE" to end the command
   36.58 +
   36.59 +
   36.60 +
   36.61 +Leiba                       Standards Track                     [Page 1]
   36.62 +
   36.63 +RFC 2177                   IMAP4 IDLE command                  June 1997
   36.64 +
   36.65 +
   36.66 +
   36.67 +   Result:     OK - IDLE completed after client sent "DONE"
   36.68 +               NO - failure: the server will not allow the IDLE
   36.69 +                    command at this time
   36.70 +              BAD - command unknown or arguments invalid
   36.71 +
   36.72 +   The IDLE command may be used with any IMAP4 server implementation
   36.73 +   that returns "IDLE" as one of the supported capabilities to the
   36.74 +   CAPABILITY command.  If the server does not advertise the IDLE
   36.75 +   capability, the client MUST NOT use the IDLE command and must poll
   36.76 +   for mailbox updates.  In particular, the client MUST continue to be
   36.77 +   able to accept unsolicited untagged responses to ANY command, as
   36.78 +   specified in the base IMAP specification.
   36.79 +
   36.80 +   The IDLE command is sent from the client to the server when the
   36.81 +   client is ready to accept unsolicited mailbox update messages.  The
   36.82 +   server requests a response to the IDLE command using the continuation
   36.83 +   ("+") response.  The IDLE command remains active until the client
   36.84 +   responds to the continuation, and as long as an IDLE command is
   36.85 +   active, the server is now free to send untagged EXISTS, EXPUNGE, and
   36.86 +   other messages at any time.
   36.87 +
   36.88 +   The IDLE command is terminated by the receipt of a "DONE"
   36.89 +   continuation from the client; such response satisfies the server's
   36.90 +   continuation request.  At that point, the server MAY send any
   36.91 +   remaining queued untagged responses and then MUST immediately send
   36.92 +   the tagged response to the IDLE command and prepare to process other
   36.93 +   commands. As in the base specification, the processing of any new
   36.94 +   command may cause the sending of unsolicited untagged responses,
   36.95 +   subject to the ambiguity limitations.  The client MUST NOT send a
   36.96 +   command while the server is waiting for the DONE, since the server
   36.97 +   will not be able to distinguish a command from a continuation.
   36.98 +
   36.99 +   The server MAY consider a client inactive if it has an IDLE command
  36.100 +   running, and if such a server has an inactivity timeout it MAY log
  36.101 +   the client off implicitly at the end of its timeout period.  Because
  36.102 +   of that, clients using IDLE are advised to terminate the IDLE and
  36.103 +   re-issue it at least every 29 minutes to avoid being logged off.
  36.104 +   This still allows a client to receive immediate mailbox updates even
  36.105 +   though it need only "poll" at half hour intervals.
  36.106 +
  36.107 +
  36.108 +
  36.109 +
  36.110 +
  36.111 +
  36.112 +
  36.113 +
  36.114 +
  36.115 +
  36.116 +
  36.117 +Leiba                       Standards Track                     [Page 2]
  36.118 +
  36.119 +RFC 2177                   IMAP4 IDLE command                  June 1997
  36.120 +
  36.121 +
  36.122 +   Example:    C: A001 SELECT INBOX
  36.123 +               S: * FLAGS (Deleted Seen)
  36.124 +               S: * 3 EXISTS
  36.125 +               S: * 0 RECENT
  36.126 +               S: * OK [UIDVALIDITY 1]
  36.127 +               S: A001 OK SELECT completed
  36.128 +               C: A002 IDLE
  36.129 +               S: + idling
  36.130 +               ...time passes; new mail arrives...
  36.131 +               S: * 4 EXISTS
  36.132 +               C: DONE
  36.133 +               S: A002 OK IDLE terminated
  36.134 +               ...another client expunges message 2 now...
  36.135 +               C: A003 FETCH 4 ALL
  36.136 +               S: * 4 FETCH (...)
  36.137 +               S: A003 OK FETCH completed
  36.138 +               C: A004 IDLE
  36.139 +               S: * 2 EXPUNGE
  36.140 +               S: * 3 EXISTS
  36.141 +               S: + idling
  36.142 +               ...time passes; another client expunges message 3...
  36.143 +               S: * 3 EXPUNGE
  36.144 +               S: * 2 EXISTS
  36.145 +               ...time passes; new mail arrives...
  36.146 +               S: * 3 EXISTS
  36.147 +               C: DONE
  36.148 +               S: A004 OK IDLE terminated
  36.149 +               C: A005 FETCH 3 ALL
  36.150 +               S: * 3 FETCH (...)
  36.151 +               S: A005 OK FETCH completed
  36.152 +               C: A006 IDLE
  36.153 +
  36.154 +4.   Formal Syntax
  36.155 +
  36.156 +   The following syntax specification uses the augmented Backus-Naur
  36.157 +   Form (BNF) notation as specified in [RFC-822] as modified by [IMAP4].
  36.158 +   Non-terminals referenced but not defined below are as defined by
  36.159 +   [IMAP4].
  36.160 +
  36.161 +   command_auth    ::= append / create / delete / examine / list / lsub /
  36.162 +                       rename / select / status / subscribe / unsubscribe
  36.163 +                       / idle
  36.164 +                       ;; Valid only in Authenticated or Selected state
  36.165 +
  36.166 +   idle            ::= "IDLE" CRLF "DONE"
  36.167 +
  36.168 +
  36.169 +
  36.170 +
  36.171 +
  36.172 +
  36.173 +Leiba                       Standards Track                     [Page 3]
  36.174 +
  36.175 +RFC 2177                   IMAP4 IDLE command                  June 1997
  36.176 +
  36.177 +
  36.178 +5.   References
  36.179 +
  36.180 +   [IMAP4] Crispin, M., "Internet Message Access Protocol - Version
  36.181 +   4rev1", RFC 2060, December 1996.
  36.182 +
  36.183 +6.   Security Considerations
  36.184 +
  36.185 +   There are no known security issues with this extension.
  36.186 +
  36.187 +7.   Author's Address
  36.188 +
  36.189 +   Barry Leiba
  36.190 +   IBM T.J. Watson Research Center
  36.191 +   30 Saw Mill River Road
  36.192 +   Hawthorne, NY  10532
  36.193 +
  36.194 +   Email: leiba@watson.ibm.com
  36.195 +
  36.196 +
  36.197 +
  36.198 +
  36.199 +
  36.200 +
  36.201 +
  36.202 +
  36.203 +
  36.204 +
  36.205 +
  36.206 +
  36.207 +
  36.208 +
  36.209 +
  36.210 +
  36.211 +
  36.212 +
  36.213 +
  36.214 +
  36.215 +
  36.216 +
  36.217 +
  36.218 +
  36.219 +
  36.220 +
  36.221 +
  36.222 +
  36.223 +
  36.224 +
  36.225 +
  36.226 +
  36.227 +
  36.228 +
  36.229 +Leiba                       Standards Track                     [Page 4]
  36.230 +
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/docs/rfc/rfc2180.txt	Mon Sep 14 15:17:45 2009 +0900
    37.3 @@ -0,0 +1,787 @@
    37.4 +
    37.5 +
    37.6 +
    37.7 +
    37.8 +
    37.9 +
   37.10 +Network Working Group                                          M. Gahrns
   37.11 +Request for Comments: 2180                                     Microsoft
   37.12 +Category: Informational                                        July 1997
   37.13 +
   37.14 +
   37.15 +                 IMAP4 Multi-Accessed Mailbox Practice
   37.16 +
   37.17 +Status of this Memo
   37.18 +
   37.19 +   This memo provides information for the Internet community.  This memo
   37.20 +   does not specify an Internet standard of any kind.  Distribution of
   37.21 +   this memo is unlimited.
   37.22 +
   37.23 +1. Abstract
   37.24 +
   37.25 +   IMAP4[RFC-2060] is rich client/server protocol that allows a client
   37.26 +   to access and manipulate electronic mail messages on a server.
   37.27 +   Within the protocol framework, it is possible to have differing
   37.28 +   results for particular client/server interactions. If a protocol does
   37.29 +   not allow for this, it is often unduly restrictive.
   37.30 +
   37.31 +   For example, when multiple clients are accessing a mailbox and one
   37.32 +   attempts to delete the mailbox, an IMAP4 server may choose to
   37.33 +   implement a solution based upon server architectural constraints or
   37.34 +   individual preference.
   37.35 +
   37.36 +   With this flexibility comes greater client responsibility.  It is not
   37.37 +   sufficient for a client to be written based upon the behavior of a
   37.38 +   particular IMAP server.  Rather the client must be based upon the
   37.39 +   behavior allowed by the protocol.
   37.40 +
   37.41 +   By documenting common IMAP4 server practice for the case of
   37.42 +   simultaneous client access to a mailbox, we hope to ensure the widest
   37.43 +   amount of inter-operation between IMAP4 clients and servers.
   37.44 +
   37.45 +   The behavior described in this document reflects the practice of some
   37.46 +   existing servers or behavior that the consensus of the IMAP mailing
   37.47 +   list has deemed to be reasonable.  The behavior described within this
   37.48 +   document is believed to be [RFC-2060] compliant. However, this
   37.49 +   document is not meant to define IMAP4 compliance, nor is it an
   37.50 +   exhaustive list of valid IMAP4 behavior. [RFC-2060] must always be
   37.51 +   consulted to determine IMAP4 compliance, especially for server
   37.52 +   behavior not described within this document.
   37.53 +
   37.54 +
   37.55 +
   37.56 +
   37.57 +
   37.58 +
   37.59 +
   37.60 +
   37.61 +Gahrns                       Informational                      [Page 1]
   37.62 +
   37.63 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
   37.64 +
   37.65 +
   37.66 +2. Conventions used in this document
   37.67 +
   37.68 +   In examples,"C1:", "C2:" and "C3:" indicate lines sent by 3 different
   37.69 +   clients (client #1, client #2 and client #3) that are connected to a
   37.70 +   server.  "S1:", "S2:" and "S3:" indicated lines sent by the server to
   37.71 +   client #1, client #2 and client #3 respectively.
   37.72 +
   37.73 +   A shared mailbox, is a mailbox that can be used by multiple users.
   37.74 +
   37.75 +   A multi-accessed mailbox, is a mailbox that has multiple clients
   37.76 +   simultaneously accessing it.
   37.77 +
   37.78 +   A client is said to have accessed a mailbox after a successful SELECT
   37.79 +   or EXAMINE command.
   37.80 +
   37.81 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   37.82 +   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   37.83 +   document are to be interpreted as described in [RFC-2119].
   37.84 +
   37.85 +
   37.86 +3. Deletion/Renaming of a multi-accessed mailbox
   37.87 +
   37.88 +   If an external agent or multiple clients are accessing a mailbox,
   37.89 +   care must be taken when handling the deletion or renaming of the
   37.90 +   mailbox. Following are some strategies an IMAP server may choose to
   37.91 +   use when dealing with this situation.
   37.92 +
   37.93 +
   37.94 +3.1. The server MAY fail the DELETE/RENAME command of a multi-accessed
   37.95 +     mailbox
   37.96 +
   37.97 +   In some cases, this behavior may not be practical.  For example, if a
   37.98 +   large number of clients are accessing a shared mailbox, the window in
   37.99 +   which no clients have the mailbox accessed may be small or non-
  37.100 +   existent, effectively rendering the mailbox undeletable or
  37.101 +   unrenamable.
  37.102 +
  37.103 +   Example:
  37.104 +
  37.105 +   <Client #1 and Client #2 have mailbox FOO accessed. Client #1 tries
  37.106 +   to DELETE the mailbox and is refused>
  37.107 +
  37.108 +             C1: A001 DELETE FOO
  37.109 +             S1: A001 NO Mailbox FOO is in use by another user.
  37.110 +
  37.111 +
  37.112 +
  37.113 +
  37.114 +
  37.115 +
  37.116 +
  37.117 +Gahrns                       Informational                      [Page 2]
  37.118 +
  37.119 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.120 +
  37.121 +
  37.122 +3.2. The server MAY allow the DELETE command of a multi-accessed
  37.123 +     mailbox, but keep the information in the mailbox available for
  37.124 +     those clients that currently have access to the mailbox.
  37.125 +
  37.126 +   When all clients have finished accessing the mailbox, it is
  37.127 +   permanently removed.  For clients that do not already have access to
  37.128 +   the mailbox, the 'ghosted' mailbox would not be available.  For
  37.129 +   example, it would not be returned to these clients in a subsequent
  37.130 +   LIST or LSUB command and would not be a valid mailbox argument to any
  37.131 +   other IMAP command until the reference count of clients accessing the
  37.132 +   mailbox reached 0.
  37.133 +
  37.134 +   In some cases, this behavior may not be desirable. For example if
  37.135 +   someone created a mailbox with offensive or sensitive information,
  37.136 +   one might prefer to have the mailbox deleted and all access to the
  37.137 +   information contained within removed immediately, rather than
  37.138 +   continuing to allow access until the client closes the mailbox.
  37.139 +
  37.140 +   Furthermore, this behavior, may prevent 'recycling' of the same
  37.141 +   mailbox name until all clients have finished accessing the original
  37.142 +   mailbox.
  37.143 +
  37.144 +   Example:
  37.145 +
  37.146 +   <Client #1 and Client #2 have mailbox FOO selected. Client #1 DELETEs
  37.147 +   mailbox FOO>
  37.148 +
  37.149 +             C1: A001 DELETE FOO
  37.150 +             S1: A001 OK Mailbox FOO is deleted.
  37.151 +
  37.152 +   <Client #2 is still able to operate on the deleted mailbox>
  37.153 +
  37.154 +             C2: B001 STORE 1 +FLAGS (\Seen)
  37.155 +             S2: * 1 FETCH FLAGS (\Seen)
  37.156 +             S2: B001 OK STORE completed
  37.157 +
  37.158 +   <Client #3 which did not have access to the mailbox prior to the
  37.159 +   deletion by client #1 does not have access to the mailbox>
  37.160 +
  37.161 +             C3: C001 STATUS FOO (MESSAGES)
  37.162 +             S3: C001 NO Mailbox does not exist
  37.163 +
  37.164 +   <Nor is client #3 able to create a mailbox with the name FOO, while
  37.165 +   the reference count is non zero>
  37.166 +
  37.167 +             C3: C002 CREATE FOO
  37.168 +             S3: C002 NO Mailbox FOO is still in use. Try again later.
  37.169 +
  37.170 +
  37.171 +
  37.172 +
  37.173 +Gahrns                       Informational                      [Page 3]
  37.174 +
  37.175 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.176 +
  37.177 +
  37.178 +   <Client #2 closes its access to the mailbox, no other clients have
  37.179 +   access to the mailbox FOO and reference count becomes 0>
  37.180 +
  37.181 +             C2: B002 CLOSE
  37.182 +             S2: B002 OK CLOSE Completed
  37.183 +
  37.184 +   <Now that the reference count on FOO has reached 0, the mailbox name
  37.185 +   can be recycled>
  37.186 +
  37.187 +             C3: C003 CREATE FOO
  37.188 +             S3: C003 OK CREATE Completed
  37.189 +
  37.190 +
  37.191 +3.3. The server MAY allow the DELETE/RENAME of a multi-accessed
  37.192 +     mailbox, but disconnect all other clients who have the mailbox
  37.193 +     accessed by sending a untagged BYE response.
  37.194 +
  37.195 +   A server may often choose to disconnect clients in the DELETE case,
  37.196 +   but may choose to implement a "friendlier" method for the RENAME
  37.197 +   case.
  37.198 +
  37.199 +   Example:
  37.200 +
  37.201 +   <Client #1 and Client #2 have mailbox FOO accessed. Client #1 DELETEs
  37.202 +   the mailbox FOO>
  37.203 +
  37.204 +             C1: A002 DELETE FOO
  37.205 +             S1: A002 OK DELETE completed.
  37.206 +
  37.207 +   <Server disconnects all other users of the mailbox>
  37.208 +             S2: * BYE Mailbox FOO has been deleted.
  37.209 +
  37.210 +
  37.211 +3.4. The server MAY allow the RENAME of a multi-accessed mailbox by
  37.212 +     simply changing the name attribute on the mailbox.
  37.213 +
  37.214 +   Other clients that have access to the mailbox can continue issuing
  37.215 +   commands such as FETCH that do not reference the mailbox name.
  37.216 +   Clients would discover the renaming the next time they referred to
  37.217 +   the old mailbox name.  Some servers MAY choose to include the
  37.218 +   [NEWNAME] response code in their tagged NO response to a command that
  37.219 +   contained the old mailbox name, as a hint to the client that the
  37.220 +   operation can succeed if the command is issued with the new mailbox
  37.221 +   name.
  37.222 +
  37.223 +
  37.224 +
  37.225 +
  37.226 +
  37.227 +
  37.228 +
  37.229 +Gahrns                       Informational                      [Page 4]
  37.230 +
  37.231 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.232 +
  37.233 +
  37.234 +   Example:
  37.235 +
  37.236 +   <Client #1 and Client #2 have mailbox FOO accessed. Client #1 RENAMEs
  37.237 +   the mailbox.>
  37.238 +
  37.239 +             C1: A001 RENAME FOO BAR
  37.240 +             S1: A001 OK RENAME completed.
  37.241 +
  37.242 +   <Client #2 is still able to do operations that do not reference the
  37.243 +   mailbox name>
  37.244 +
  37.245 +             C2: B001 FETCH 2:4 (FLAGS)
  37.246 +             S2: * 2 FETCH . . .
  37.247 +             S2: * 3 FETCH . . .
  37.248 +             S2: * 4 FETCH . . .
  37.249 +             S2: B001 OK FETCH completed
  37.250 +
  37.251 +   <Client #2 is not able to do operations that reference the mailbox
  37.252 +   name>
  37.253 +
  37.254 +             C2: B002 APPEND FOO {300} C2: Date: Mon, 7 Feb 1994
  37.255 +             21:52:25 0800 (PST) C2: . . .  S2: B002 NO [NEWNAME FOO
  37.256 +             BAR] Mailbox has been renamed
  37.257 +
  37.258 +
  37.259 +4. Expunging of messages on a multi-accessed mailbox
  37.260 +
  37.261 +   If an external agent or multiple clients are accessing a mailbox,
  37.262 +   care must be taken when handling the EXPUNGE of messages.  Other
  37.263 +   clients accessing the mailbox may be in the midst of issuing a
  37.264 +   command that depends upon message sequence numbers.  Because an
  37.265 +   EXPUNGE response can not be sent while responding to a FETCH, STORE
  37.266 +   or SEARCH command, it is not possible to immediately notify the
  37.267 +   client of the EXPUNGE.  This can result in ambiguity if the client
  37.268 +   issues a FETCH, STORE or SEARCH operation on a message that has been
  37.269 +   EXPUNGED.
  37.270 +
  37.271 +
  37.272 +4.1. Fetching of expunged messages
  37.273 +
  37.274 +   Following are some strategies an IMAP server may choose to use when
  37.275 +   dealing with a FETCH command on expunged messages.
  37.276 +
  37.277 +
  37.278 +
  37.279 +
  37.280 +
  37.281 +
  37.282 +
  37.283 +
  37.284 +
  37.285 +Gahrns                       Informational                      [Page 5]
  37.286 +
  37.287 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.288 +
  37.289 +
  37.290 +   Consider the following scenario:
  37.291 +
  37.292 +   - Client #1 and Client #2 have mailbox FOO selected.
  37.293 +   - There are 7 messages in the mailbox.
  37.294 +   - Messages 4:7 are marked for deletion.
  37.295 +   - Client #1 issues an EXPUNGE, to expunge messages 4:7
  37.296 +
  37.297 +
  37.298 +4.1.1. The server MAY allow the EXPUNGE of a multi-accessed mailbox but
  37.299 +       keep the messages available to satisfy subsequent FETCH commands
  37.300 +       until it is able to send an EXPUNGE response to each client.
  37.301 +
  37.302 +   In some cases, the behavior of keeping "ghosted" messages may not be
  37.303 +   desirable.  For example if a message contained offensive or sensitive
  37.304 +   information, one might prefer to instantaneously remove all access to
  37.305 +   the information, regardless of whether another client is in the midst
  37.306 +   of accessing it.
  37.307 +
  37.308 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.309 +
  37.310 +   <Client #2 is still able to access the expunged messages because the
  37.311 +   server has kept a 'ghosted' copy of the messages until it is able to
  37.312 +   notify client #2 of the EXPUNGE>
  37.313 +
  37.314 +             C2: B001 FETCH 4:7 RFC822
  37.315 +             S2: * 4 FETCH RFC822 . . . (RFC822 info returned)
  37.316 +             S2: * 5 FETCH RFC822 . . . (RFC822 info returned)
  37.317 +             S2: * 6 FETCH RFC822 . . . (RFC822 info returned)
  37.318 +             S2: * 7 FETCH RFC822 . . . (RFC822 info returned)
  37.319 +             S2: B001 OK FETCH Completed
  37.320 +
  37.321 +   <Client #2 issues a command where it can get notified of the EXPUNGE>
  37.322 +
  37.323 +             C2: B002 NOOP
  37.324 +             S2: * 4 EXPUNGE
  37.325 +             S2: * 4 EXPUNGE
  37.326 +             S2: * 4 EXPUNGE
  37.327 +             S2: * 4 EXPUNGE
  37.328 +             S2: * 3 EXISTS
  37.329 +             S2: B002 OK NOOP Complete
  37.330 +
  37.331 +   <Client #2 no longer has access to the expunged messages>
  37.332 +
  37.333 +             C2: B003 FETCH 4:7 RFC822
  37.334 +             S2: B003 NO Messages 4:7 are no longer available.
  37.335 +
  37.336 +
  37.337 +
  37.338 +
  37.339 +
  37.340 +
  37.341 +Gahrns                       Informational                      [Page 6]
  37.342 +
  37.343 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.344 +
  37.345 +
  37.346 +4.1.2 The server MAY allow the EXPUNGE of a multi-accessed mailbox,
  37.347 +      and on subsequent FETCH commands return FETCH responses only for
  37.348 +      non-expunged messages and a tagged NO.
  37.349 +
  37.350 +   After receiving a tagged NO FETCH response, the client SHOULD issue a
  37.351 +   NOOP command so that it will be informed of any pending EXPUNGE
  37.352 +   responses.  The client may then either reissue the failed FETCH
  37.353 +   command, or by examining the EXPUNGE response from the NOOP and the
  37.354 +   FETCH response from the FETCH, determine that the FETCH failed
  37.355 +   because of pending expunges.
  37.356 +
  37.357 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.358 +
  37.359 +   <Client #2 attempts to FETCH a mix of expunged and non-expunged
  37.360 +   messages.  A FETCH response is returned only for then non-expunged
  37.361 +   messages along with a tagged NO>
  37.362 +
  37.363 +             C2: B001 FETCH 3:5 ENVELOPE
  37.364 +             S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned)
  37.365 +             S2: B001 NO Some of the requested messages no longer exist
  37.366 +
  37.367 +   <Upon receiving a tagged NO FETCH response, Client #2 issues a NOOP
  37.368 +   to be informed of any pending EXPUNGE responses>
  37.369 +
  37.370 +             C2: B002 NOOP
  37.371 +             S2: * 4 EXPUNGE
  37.372 +             S2: * 4 EXPUNGE
  37.373 +             S2: * 4 EXPUNGE
  37.374 +             S2: * 4 EXPUNGE
  37.375 +             S2: * 3 EXISTS
  37.376 +             S2: B002 OK NOOP Completed.
  37.377 +
  37.378 +   <By receiving a FETCH response for message 3, and an EXPUNGE response
  37.379 +   that indicates messages 4:7 have been expunged, the client does not
  37.380 +   need to re-issue the FETCH>
  37.381 +
  37.382 +
  37.383 +
  37.384 +
  37.385 +
  37.386 +
  37.387 +
  37.388 +
  37.389 +
  37.390 +
  37.391 +
  37.392 +
  37.393 +
  37.394 +
  37.395 +
  37.396 +
  37.397 +Gahrns                       Informational                      [Page 7]
  37.398 +
  37.399 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.400 +
  37.401 +
  37.402 +4.1.3 The server MAY allow the EXPUNGE of a multi-accessed mailbox, and
  37.403 +      on subsequent FETCH commands return the usual FETCH responses for
  37.404 +      non-expunged messages, "NIL FETCH Responses" for expunged
  37.405 +      messages, and a tagged OK response.
  37.406 +
  37.407 +   If all of the messages in the subsequent FETCH command have been
  37.408 +   expunged, the server SHOULD return only a tagged NO.  In this case,
  37.409 +   the client SHOULD issue a NOOP command so that it will be informed of
  37.410 +   any pending EXPUNGE responses.  The client may then either reissue
  37.411 +   the failed FETCH command, or by examining the EXPUNGE response from
  37.412 +   the NOOP, determine that the FETCH failed because of pending
  37.413 +   expunges.
  37.414 +
  37.415 +   "NIL FETCH responses" are a representation of empty data as
  37.416 +   appropriate for the FETCH argument specified.
  37.417 +
  37.418 +   Example:
  37.419 +
  37.420 +   * 1 FETCH (ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL))
  37.421 +   * 1 FETCH (FLAGS ())
  37.422 +   * 1 FETCH (INTERNALDATE "00-Jan-0000 00:00:00 +0000")
  37.423 +   * 1 FETCH (RFC822 "")
  37.424 +   * 1 FETCH (RFC822.HEADER "")
  37.425 +   * 1 FETCH (RFC822.TEXT "")
  37.426 +   * 1 FETCH (RFC822.SIZE 0)
  37.427 +   * 1 FETCH (BODY ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 0 0)
  37.428 +   * 1 FETCH (BODYSTRUCTURE ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 0 0)
  37.429 +   * 1 FETCH (BODY[<section>] "")
  37.430 +   * 1 FETCH (BODY[<section>]<partial> "")
  37.431 +
  37.432 +   In some cases, a client may not be able to distinguish between "NIL
  37.433 +   FETCH responses" received because a message was expunged and those
  37.434 +   received because the data actually was NIL.  For example, a  * 5
  37.435 +   FETCH (FLAGS ()) response could be received if no flags were set on
  37.436 +   message 5, or because message 5 was expunged. In a case of potential
  37.437 +   ambiguity, the client SHOULD issue a command such as NOOP to force
  37.438 +   the sending of the EXPUNGE responses to resolve any ambiguity.
  37.439 +
  37.440 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.441 +
  37.442 +   <Client #2 attempts to access a mix of expunged and non-expunged
  37.443 +   messages.  Normal data is returned for non-expunged message, "NIL
  37.444 +   FETCH responses" are returned for expunged messages>
  37.445 +
  37.446 +
  37.447 +
  37.448 +
  37.449 +
  37.450 +
  37.451 +
  37.452 +
  37.453 +Gahrns                       Informational                      [Page 8]
  37.454 +
  37.455 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.456 +
  37.457 +
  37.458 +             C2: B002 FETCH 3:5 ENVELOPE
  37.459 +             S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned)
  37.460 +             S2: * 4 FETCH ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL
  37.461 +                   NIL NIL)
  37.462 +             S2: * 5 FETCH ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL
  37.463 +                   NIL NIL)
  37.464 +             S2: B002 OK FETCH Completed
  37.465 +
  37.466 +   <Client #2 attempts to FETCH only expunged messages and receives a
  37.467 +   tagged NO response>
  37.468 +
  37.469 +             C2: B002 FETCH 4:7 ENVELOPE
  37.470 +             S2: B002 NO Messages 4:7 have been expunged.
  37.471 +
  37.472 +
  37.473 +4.1.4 To avoid the situation altogether, the server MAY fail the
  37.474 +      EXPUNGE of a multi-accessed mailbox
  37.475 +
  37.476 +   In some cases, this behavior may not be practical.  For example, if a
  37.477 +   large number of clients are accessing a shared mailbox, the window in
  37.478 +   which no clients have the mailbox accessed may be small or non-
  37.479 +   existent, effectively rendering the message unexpungeable.
  37.480 +
  37.481 +
  37.482 +4.2. Storing of expunged messages
  37.483 +
  37.484 +   Following are some strategies an IMAP server may choose to use when
  37.485 +   dealing with a STORE command on expunged messages.
  37.486 +
  37.487 +
  37.488 +4.2.1 If the ".SILENT" suffix is used, and the STORE completed
  37.489 +      successfully for all the non-expunged messages, the server SHOULD
  37.490 +      return a tagged OK.
  37.491 +
  37.492 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.493 +
  37.494 +   <Client #2 tries to silently STORE flags on expunged and non-
  37.495 +   expunged messages.  The server sets the flags on the non-expunged
  37.496 +   messages and returns OK>
  37.497 +
  37.498 +             C2: B001 STORE 1:7 +FLAGS.SILENT (\SEEN)
  37.499 +             S2: B001 OK
  37.500 +
  37.501 +
  37.502 +
  37.503 +
  37.504 +
  37.505 +
  37.506 +
  37.507 +
  37.508 +
  37.509 +Gahrns                       Informational                      [Page 9]
  37.510 +
  37.511 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.512 +
  37.513 +
  37.514 +4.2.2. If the ".SILENT" suffix is not used, and only expunged messages
  37.515 +       are referenced, the server SHOULD return only a tagged NO.
  37.516 +
  37.517 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.518 +
  37.519 +   <Client #2 tries to STORE flags only on expunged messages>
  37.520 +
  37.521 +             C2: B001 STORE 5:7 +FLAGS (\SEEN)
  37.522 +             S2: B001 NO  Messages have been expunged
  37.523 +
  37.524 +
  37.525 +4.2.3. If the ".SILENT" suffix is not used, and a mixture of expunged
  37.526 +       and non-expunged messages are referenced, the server MAY set the
  37.527 +       flags and return a FETCH response for the non-expunged messages
  37.528 +       along with a tagged NO.
  37.529 +
  37.530 +   After receiving a tagged NO STORE response, the client SHOULD issue a
  37.531 +   NOOP command so that it will be informed of any pending EXPUNGE
  37.532 +   responses.  The client may then either reissue the failed STORE
  37.533 +   command, or by examining the EXPUNGE responses from the NOOP and
  37.534 +   FETCH responses from the STORE, determine that the STORE failed
  37.535 +   because of pending expunges.
  37.536 +
  37.537 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.538 +
  37.539 +   <Client #2 tries to STORE flags on a mixture of expunged and non-
  37.540 +   expunged messages>
  37.541 +
  37.542 +             C2: B001 STORE 1:7 +FLAGS (\SEEN)
  37.543 +             S2: * FETCH 1 FLAGS (\SEEN)
  37.544 +             S2: * FETCH 2 FLAGS (\SEEN)
  37.545 +             S2: * FETCH 3 FLAGS (\SEEN)
  37.546 +             S2: B001 NO Some of the messages no longer exist.
  37.547 +
  37.548 +             C2: B002 NOOP
  37.549 +             S2: * 4 EXPUNGE
  37.550 +             S2: * 4 EXPUNGE
  37.551 +             S2: * 4 EXPUNGE
  37.552 +             S2: * 4 EXPUNGE
  37.553 +             S2: * 3 EXISTS
  37.554 +             S2: B002 OK NOOP Completed.
  37.555 +
  37.556 +   <By receiving FETCH responses for messages 1:3, and an EXPUNGE
  37.557 +   response that indicates messages 4:7 have been expunged, the client
  37.558 +   does not need to re-issue the STORE>
  37.559 +
  37.560 +
  37.561 +
  37.562 +
  37.563 +
  37.564 +
  37.565 +Gahrns                       Informational                     [Page 10]
  37.566 +
  37.567 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.568 +
  37.569 +
  37.570 +4.2.4. If the ".SILENT" suffix is not used, and a mixture of expunged
  37.571 +       and non-expunged messages are referenced, the server MAY return
  37.572 +       an untagged NO and not set any flags.
  37.573 +
  37.574 +   After receiving a tagged NO STORE response, the client SHOULD issue a
  37.575 +   NOOP command so that it will be informed of any pending EXPUNGE
  37.576 +   responses.  The client would then re-issue the STORE command after
  37.577 +   updating its message list per any EXPUNGE response.
  37.578 +
  37.579 +   If a large number of clients are accessing a shared mailbox, the
  37.580 +   window in which there are no pending expunges may be small or non-
  37.581 +   existent, effectively disallowing a client from setting the flags on
  37.582 +   all messages at once.
  37.583 +
  37.584 +   Example:  (Building upon the scenario outlined in 4.1.)
  37.585 +
  37.586 +   <Client #2 tries to STORE flags on a mixture of expunged and non-
  37.587 +   expunged messages>
  37.588 +
  37.589 +             C2: B001 STORE 1:7 +FLAGS (\SEEN)
  37.590 +             S2: B001 NO  Some of the messages no longer exist.
  37.591 +
  37.592 +   <Client #2 issues a NOOP to be informed of the EXPUNGED messages>
  37.593 +
  37.594 +             C2: B002 NOOP
  37.595 +             S2: * 4 EXPUNGE
  37.596 +             S2: * 4 EXPUNGE
  37.597 +             S2: * 4 EXPUNGE
  37.598 +             S2: * 4 EXPUNGE
  37.599 +             S2: * 3 EXISTS
  37.600 +             S2: B002 OK NOOP Completed.
  37.601 +
  37.602 +   <Client #2 updates its message list and re-issues the STORE on only
  37.603 +   those messages that have not been expunged>
  37.604 +
  37.605 +             C2: B003 STORE 1:3 +FLAGS (\SEEN) S2: * FETCH 1 FLAGS
  37.606 +             (\SEEN) S2: * FETCH 2 FLAGS (\SEEN) S2: * FETCH 3 FLAGS
  37.607 +             (\SEEN) S2: B003 OK  STORE Completed
  37.608 +
  37.609 +
  37.610 +4.3. Searching of expunged messages
  37.611 +
  37.612 +   A server MAY simply not return a search response for messages that
  37.613 +   have been expunged and it has not been able to inform the client
  37.614 +   about.  If a client was expecting a particular message to be returned
  37.615 +   in a search result, and it was not, the client SHOULD issue a NOOP
  37.616 +   command to see if the message was expunged by another client.
  37.617 +
  37.618 +
  37.619 +
  37.620 +
  37.621 +Gahrns                       Informational                     [Page 11]
  37.622 +
  37.623 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.624 +
  37.625 +
  37.626 +4.4 Copying of expunged messages
  37.627 +
  37.628 +   COPY is the only IMAP4 sequence number command that is safe to allow
  37.629 +   an EXPUNGE response on.  This is because a client is not permitted to
  37.630 +   cascade several COPY commands together. A client is required to wait
  37.631 +   and confirm that the copy worked before issuing another one.
  37.632 +
  37.633 +4.4.1 The server MAY disallow the COPY of messages in a multi-access
  37.634 +      mailbox that contains expunged messages.
  37.635 +
  37.636 +   Pending EXPUNGE response(s) MUST be returned to the COPY command.
  37.637 +
  37.638 +   Example:
  37.639 +
  37.640 +             C: A001 COPY 2,4,6,8 FRED
  37.641 +             S: * 4 EXPUNGE
  37.642 +             S: A001 NO COPY rejected, because some of the requested
  37.643 +                messages were expunged
  37.644 +
  37.645 +   Note: Non of the above messages are copied because if a COPY command
  37.646 +   is unsuccessful, the server MUST restore the destination mailbox to
  37.647 +   its state before the COPY attempt.
  37.648 +
  37.649 +
  37.650 +4.4.2 The server MAY allow the COPY of messages in a multi-access
  37.651 +      mailbox that contains expunged messages.
  37.652 +
  37.653 +   Pending EXPUNGE response(s) MUST be returned to the COPY command.
  37.654 +   Messages that are copied are messages corresponding to sequence
  37.655 +   numbers before any EXPUNGE response.
  37.656 +
  37.657 +   Example:
  37.658 +
  37.659 +             C: A001 COPY 2,4,6,8 FRED
  37.660 +             S: * 3 EXPUNGE
  37.661 +             S: A001 OK COPY completed
  37.662 +
  37.663 +   In the above example, the messages that are copied to FRED are
  37.664 +   messages 2,4,6,8 at the start of the COPY command.  These are
  37.665 +   equivalent to messages 2,3,5,7 at the end of the COPY command.  The
  37.666 +   EXPUNGE response can't take place until after the messages from the
  37.667 +   COPY command are identified (because of the "no expunge while no
  37.668 +   commands in progress" rule).
  37.669 +
  37.670 +
  37.671 +
  37.672 +
  37.673 +
  37.674 +
  37.675 +
  37.676 +
  37.677 +Gahrns                       Informational                     [Page 12]
  37.678 +
  37.679 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.680 +
  37.681 +
  37.682 +   Example:
  37.683 +
  37.684 +             C: A001 COPY 2,4,6,8 FRED
  37.685 +             S: * 4 EXPUNGE
  37.686 +             S: A001 OK COPY completed
  37.687 +
  37.688 +   In the above example, message 4 was copied before it was expunged,
  37.689 +   and MUST appear in the destination mailbox FRED.
  37.690 +
  37.691 +
  37.692 +5. Security Considerations
  37.693 +
  37.694 +   This document describes behavior of servers that use the IMAP4
  37.695 +   protocol, and as such, has the same security considerations as
  37.696 +   described in [RFC-2060].
  37.697 +
  37.698 +   In particular, some described server behavior does not allow for the
  37.699 +   immediate deletion of information when a mailbox is accessed by
  37.700 +   multiple clients.  This may be a consideration when dealing with
  37.701 +   sensitive information where immediate deletion would be preferred.
  37.702 +
  37.703 +
  37.704 +6. References
  37.705 +
  37.706 +   [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version
  37.707 +   4rev1", RFC 2060, University of Washington, December 1996.
  37.708 +
  37.709 +   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
  37.710 +   Requirement Levels", RFC 2119, Harvard University, March 1997.
  37.711 +
  37.712 +
  37.713 +7.  Acknowledgments
  37.714 +
  37.715 +   This document is the result of discussions on the IMAP4 mailing list
  37.716 +   and is meant to reflect consensus of this group.  In particular,
  37.717 +   Raymond Cheng, Mark Crispin, Jim Evans, Erik Forsberg, Steve Hole,
  37.718 +   Mark Keasling, Barry Leiba, Syd Logan, John Mani, Pat Moran, Larry
  37.719 +   Osterman, Chris Newman, Bart Schaefer, Vladimir Vulovic, and Jack De
  37.720 +   Winter were active participants in this discussion or made
  37.721 +   suggestions to this document.
  37.722 +
  37.723 +
  37.724 +
  37.725 +
  37.726 +
  37.727 +
  37.728 +
  37.729 +
  37.730 +
  37.731 +
  37.732 +
  37.733 +Gahrns                       Informational                     [Page 13]
  37.734 +
  37.735 +RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
  37.736 +
  37.737 +
  37.738 +8. Author's Address
  37.739 +
  37.740 +   Mike Gahrns
  37.741 +   Microsoft
  37.742 +   One Microsoft Way
  37.743 +   Redmond, WA, 98072
  37.744 +
  37.745 +   Phone: (206) 936-9833
  37.746 +   EMail: mikega@microsoft.com
  37.747 +
  37.748 +
  37.749 +
  37.750 +
  37.751 +
  37.752 +
  37.753 +
  37.754 +
  37.755 +
  37.756 +
  37.757 +
  37.758 +
  37.759 +
  37.760 +
  37.761 +
  37.762 +
  37.763 +
  37.764 +
  37.765 +
  37.766 +
  37.767 +
  37.768 +
  37.769 +
  37.770 +
  37.771 +
  37.772 +
  37.773 +
  37.774 +
  37.775 +
  37.776 +
  37.777 +
  37.778 +
  37.779 +
  37.780 +
  37.781 +
  37.782 +
  37.783 +
  37.784 +
  37.785 +
  37.786 +
  37.787 +
  37.788 +
  37.789 +Gahrns                       Informational                     [Page 14]
  37.790 +
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/docs/rfc/rfc2193.txt	Mon Sep 14 15:17:45 2009 +0900
    38.3 @@ -0,0 +1,507 @@
    38.4 +
    38.5 +
    38.6 +
    38.7 +
    38.8 +
    38.9 +
   38.10 +Network Working Group                                        M. Gahrns
   38.11 +Request for Comments: 2193                                   Microsoft
   38.12 +Category: Standards Track                               September 1997
   38.13 +
   38.14 +
   38.15 +                        IMAP4 Mailbox Referrals
   38.16 +
   38.17 +Status of this Memo
   38.18 +
   38.19 +   This document specifies an Internet standards track protocol for the
   38.20 +   Internet community, and requests discussion and suggestions for
   38.21 +   improvements.  Please refer to the current edition of the "Internet
   38.22 +   Official Protocol Standards" (STD 1) for the standardization state
   38.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   38.24 +
   38.25 +1. Abstract
   38.26 +
   38.27 +   When dealing with large amounts of users, messages and geographically
   38.28 +   dispersed IMAP4 [RFC-2060] servers, it is often desirable to
   38.29 +   distribute messages amongst different servers within an organization.
   38.30 +   For example an administrator may choose to store user's personal
   38.31 +   mailboxes on a local IMAP4 server, while storing shared mailboxes
   38.32 +   remotely on another server.  This type of configuration is common
   38.33 +   when it is uneconomical to store all data centrally due to limited
   38.34 +   bandwidth or disk resources.
   38.35 +
   38.36 +   Mailbox referrals allow clients to seamlessly access mailboxes that
   38.37 +   are distributed across several IMAP4 servers.
   38.38 +
   38.39 +   A referral mechanism can provide efficiencies over the alternative
   38.40 +   "proxy method", in which the local IMAP4 server contacts the remote
   38.41 +   server on behalf of the client, and then transfers the data from the
   38.42 +   remote server to itself, and then on to the client.  The referral
   38.43 +   mechanism's direct client connection to the remote server is often a
   38.44 +   more efficient use of bandwidth, and does not require the local
   38.45 +   server to impersonate the client when authenticating to the remote
   38.46 +   server.
   38.47 +
   38.48 +2. Conventions used in this document
   38.49 +
   38.50 +   In examples, "C:" and "S:" indicate lines sent by the client and
   38.51 +   server respectively.
   38.52 +
   38.53 +   A home server, is an IMAP4 server that contains the user's inbox.
   38.54 +
   38.55 +   A remote mailbox is a mailbox that is not hosted on the user's home
   38.56 +   server.
   38.57 +
   38.58 +
   38.59 +
   38.60 +
   38.61 +Gahrns                      Standards Track                     [Page 1]
   38.62 +
   38.63 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
   38.64 +
   38.65 +
   38.66 +   A remote server is a server that contains remote mailboxes.
   38.67 +
   38.68 +   A shared mailbox, is a mailbox that multiple users have access to.
   38.69 +
   38.70 +   An IMAP mailbox referral is when the server directs the client to
   38.71 +   another IMAP mailbox.
   38.72 +
   38.73 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   38.74 +   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   38.75 +   document are to be interpreted as described in [RFC-2119].
   38.76 +
   38.77 +3. Introduction and Overview
   38.78 +
   38.79 +   IMAP4 servers that support this extension MUST list the keyword
   38.80 +   MAILBOX-REFERRALS in their CAPABILITY response.  No client action is
   38.81 +   needed to invoke the MAILBOX-REFERRALS capability in a server.
   38.82 +
   38.83 +   A MAILBOX-REFERRALS capable IMAP4 server MUST NOT return referrals
   38.84 +   that result in a referrals loop.
   38.85 +
   38.86 +   A referral response consists of a tagged NO response and a REFERRAL
   38.87 +   response code.  The REFERRAL response code MUST contain as an
   38.88 +   argument a one or more valid URLs separated by a space as defined in
   38.89 +   [RFC-1738]. If a server replies with multiple URLs for a particular
   38.90 +   object, they MUST all be of the same type. In this case, the URL MUST
   38.91 +   be an IMAP URL as defined in [RFC-2192].  A client that supports the
   38.92 +   REFERRALS extension MUST be prepared for a URL of any type, but it
   38.93 +   need only be able to process IMAP URLs.
   38.94 +
   38.95 +   A server MAY respond with multiple IMAP mailbox referrals if there is
   38.96 +   more than one replica of the mailbox.  This allows the implementation
   38.97 +   of a load balancing or failover scheme. How a server keeps multiple
   38.98 +   replicas of a mailbox in sync is not addressed by this document.
   38.99 +
  38.100 +   If the server has a preferred order in which the client should
  38.101 +   attempt to access the URLs, the preferred URL SHOULD be listed in the
  38.102 +   first, with the remaining URLs presented in descending order of
  38.103 +   preference.  If multiple referrals are given for a mailbox, a server
  38.104 +   should be aware that there are synchronization issues for a client if
  38.105 +   the UIDVALIDITY of the referred mailboxes are different.
  38.106 +
  38.107 +   An IMAP mailbox referral may be given in response to an IMAP command
  38.108 +   that specifies a mailbox as an argument.
  38.109 +
  38.110 +
  38.111 +
  38.112 +
  38.113 +
  38.114 +
  38.115 +
  38.116 +
  38.117 +Gahrns                      Standards Track                     [Page 2]
  38.118 +
  38.119 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.120 +
  38.121 +
  38.122 +   Example:
  38.123 +
  38.124 +      A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/REMOTE]Remote Mailbox
  38.125 +
  38.126 +   NOTE: user;AUTH=* is specified as required by [RFC-2192] to avoid a
  38.127 +   client falling back to anonymous login.
  38.128 +
  38.129 +   Remote mailboxes and their inferiors, that are accessible only via
  38.130 +   referrals SHOULD NOT appear in LIST and LSUB responses issued against
  38.131 +   the user's home server.  They MUST appear in RLIST and RLSUB
  38.132 +   responses issued against the user's home server. Hierarchy referrals,
  38.133 +   in which a client would be required to connect to the remote server
  38.134 +   to issue a LIST to discover the inferiors of a mailbox are not
  38.135 +   addressed in this document.
  38.136 +
  38.137 +   For example, if shared mailboxes were only accessible via referrals
  38.138 +   on a remote server, a RLIST "" "#SHARED/%" command would return the
  38.139 +   same response if issued against the user's home server or the remote
  38.140 +   server.
  38.141 +
  38.142 +   Note: Mailboxes that are available on the user's home server do not
  38.143 +   need to be available on the remote server.  In addition, there may be
  38.144 +   additional mailboxes available on the remote server, but they will
  38.145 +   not accessible to the client via referrals unless they appear in the
  38.146 +   LIST response to the RLIST command against the user's home server.
  38.147 +
  38.148 +   A MAILBOX-REFERRALS capable client will issue the RLIST and RLSUB
  38.149 +   commands in lieu of LIST and LSUB.  The RLIST and RLSUB commands
  38.150 +   behave identically to their LIST and LSUB counterparts, except remote
  38.151 +   mailboxes are returned in addition to local mailboxes in the LIST and
  38.152 +   LSUB responses.  This avoids displaying to a non MAILBOX-REFERRALS
  38.153 +   enabled client inaccessible remote mailboxes.
  38.154 +
  38.155 +4.1. SELECT, EXAMINE, DELETE, SUBSCRIBE, UNSUBSCRIBE, STATUS and APPEND
  38.156 +     Referrals
  38.157 +
  38.158 +   An IMAP4 server MAY respond to the SELECT, EXAMINE, DELETE,
  38.159 +   SUBSCRIBE, UNSUBSCRIBE, STATUS or APPEND command with one or more
  38.160 +   IMAP mailbox referrals to indicate to the client that the mailbox is
  38.161 +   hosted on a remote server.
  38.162 +
  38.163 +   When a client processes an IMAP mailbox referral, it will open a new
  38.164 +   connection or use an existing connection to the remote server so that
  38.165 +   it is able to issue the commands necessary to process the remote
  38.166 +   mailbox.
  38.167 +
  38.168 +
  38.169 +
  38.170 +
  38.171 +
  38.172 +
  38.173 +Gahrns                      Standards Track                     [Page 3]
  38.174 +
  38.175 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.176 +
  38.177 +
  38.178 +   Example:  <IMAP4 connection to home server>
  38.179 +
  38.180 +      C: A001 DELETE "SHARED/FOO"
  38.181 +      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/FOO]
  38.182 +             Remote mailbox. Try SERVER2.
  38.183 +
  38.184 +      <Client established a second connection to SERVER2 and
  38.185 +      issues the DELETE command on the referred mailbox>
  38.186 +
  38.187 +      S: * OK IMAP4rev1 server ready
  38.188 +      C: B001 AUTHENTICATE KERBEROS_V4
  38.189 +      <authentication exchange>
  38.190 +      S: B001 OK user is authenticated
  38.191 +
  38.192 +      C: B002 DELETE "SHARED/FOO"
  38.193 +      S: B002 OK DELETE completed
  38.194 +
  38.195 +   Example:  <IMAP4 connection to home server>
  38.196 +
  38.197 +      C: A001 SELECT REMOTE
  38.198 +      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/REMOTE
  38.199 +          IMAP://user;AUTH=*@SERVER3/REMOTE] Remote mailbox.
  38.200 +          Try SERVER2 or SERVER3.
  38.201 +
  38.202 +      <Client opens second connection to remote server, and
  38.203 +       issues the commands needed to process the items in the
  38.204 +       remote mailbox>
  38.205 +
  38.206 +      S: * OK IMAP4rev1 server ready
  38.207 +      C: B001 AUTHENTICATE KERBEROS_V4
  38.208 +      <authentication exchange>
  38.209 +      S: B001 OK user is authenticated
  38.210 +
  38.211 +      C: B002 SELECT REMOTE
  38.212 +      S: * 12 EXISTS
  38.213 +      S: * 1 RECENT
  38.214 +      S: * OK [UNSEEN 10] Message 10 is first unseen
  38.215 +      S: * OK [UIDVALIDITY 123456789]
  38.216 +      S: * FLAGS (Answered Flagged Deleted Seen Draft)
  38.217 +      S: * OK [PERMANENTFLAGS (Answered Deleted Seen ]
  38.218 +      S: B002 OK [READ-WRITE] Selected completed
  38.219 +
  38.220 +      C: B003 FETCH 10:12 RFC822
  38.221 +      S: * 10 FETCH . . .
  38.222 +      S: * 11 FETCH . . .
  38.223 +      S: * 12 FETCH . . .
  38.224 +      S: B003 OK FETCH Completed
  38.225 +
  38.226 +
  38.227 +
  38.228 +
  38.229 +Gahrns                      Standards Track                     [Page 4]
  38.230 +
  38.231 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.232 +
  38.233 +
  38.234 +      <Client is finished processing the REMOTE mailbox and
  38.235 +       wants to process a mailbox on its home server>
  38.236 +
  38.237 +      C: B004 LOGOUT
  38.238 +      S: * BYE IMAP4rev1 server logging out
  38.239 +      S: B004 OK LOGOUT Completed
  38.240 +
  38.241 +      <Client continues with first connection>
  38.242 +
  38.243 +      C: A002 SELECT INBOX
  38.244 +      S: * 16 EXISTS
  38.245 +      S: * 2 RECENT
  38.246 +      S: * OK [UNSEEN 10] Message 10 is first unseen
  38.247 +      S: * OK [UIDVALIDITY 123456789]
  38.248 +      S: * FLAGS (Answered Flagged Deleted Seen Draft)
  38.249 +      S: * OK [PERMANENTFLAGS (Answered Deleted Seen ]
  38.250 +      S: A002 OK [READ-WRITE] Selected completed
  38.251 +
  38.252 +4.2. CREATE Referrals
  38.253 +
  38.254 +   An IMAP4 server MAY respond to the CREATE command with one or more
  38.255 +   IMAP mailbox referrals, if it wishes to direct the client to issue
  38.256 +   the CREATE against another server.  The server can employ any means,
  38.257 +   such as examining the hierarchy of the specified mailbox name, in
  38.258 +   determining which server the mailbox should be created on.
  38.259 +
  38.260 +   Example:
  38.261 +
  38.262 +      C: A001 CREATE "SHARED/FOO"
  38.263 +      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/FOO]
  38.264 +         Mailbox should be created on remote server
  38.265 +
  38.266 +   Alternatively, because a home server is required to maintain a
  38.267 +   listing of referred remote mailboxes, a server MAY allow the creation
  38.268 +   of a mailbox that will ultimately reside on a remote server against
  38.269 +   the home server, and provide referrals on subsequent commands that
  38.270 +   manipulate the mailbox.
  38.271 +
  38.272 +   Example:
  38.273 +
  38.274 +      C: A001 CREATE "SHARED/FOO"
  38.275 +      S: A001 OK CREATE succeeded
  38.276 +
  38.277 +      C: A002 SELECT "SHARED/FOO"
  38.278 +      S: A002 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/FOO]
  38.279 +         Remote mailbox.  Try SERVER2
  38.280 +
  38.281 +
  38.282 +
  38.283 +
  38.284 +
  38.285 +Gahrns                      Standards Track                     [Page 5]
  38.286 +
  38.287 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.288 +
  38.289 +
  38.290 +4.3. RENAME Referrals
  38.291 +
  38.292 +   An IMAP4 server MAY respond to the RENAME command with one or more
  38.293 +   pairs of IMAP mailbox referrals.  In each pair of IMAP mailbox
  38.294 +   referrals, the first one is an URL to the existing mailbox name and
  38.295 +   the second is an URL to the requested new mailbox name.
  38.296 +
  38.297 +   If within an IMAP mailbox referral pair, the existing and new mailbox
  38.298 +   URLs are on different servers, the remote servers are unable to
  38.299 +   perform the RENAME operation.   To achieve the same behavior of
  38.300 +   server RENAME, the client MAY issue the constituent CREATE, FETCH,
  38.301 +   APPEND, and DELETE commands against both servers.
  38.302 +
  38.303 +   If within an IMAP mailbox referral pair, the existing and new mailbox
  38.304 +   URLs are on the same server it is an indication that the currently
  38.305 +   connected server is unable to perform the operation.  The client can
  38.306 +   simply re-issue the RENAME command on the remote server.
  38.307 +
  38.308 +   Example:
  38.309 +
  38.310 +      C: A001 RENAME FOO BAR
  38.311 +      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER1/FOO
  38.312 +              IMAP://user;AUTH=*@SERVER2/BAR] Unable to rename mailbox
  38.313 +              across servers
  38.314 +
  38.315 +   Since the existing and new mailbox names are on different servers,
  38.316 +   the client would be required to make a connection to both servers and
  38.317 +   issue the constituent commands require to achieve the RENAME.
  38.318 +
  38.319 +   Example:
  38.320 +
  38.321 +      C: A001 RENAME FOO BAR
  38.322 +      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/FOO
  38.323 +              IMAP://user;AUTH=*@SERVER2/BAR] Unable to rename mailbox
  38.324 +              located on SERVER2
  38.325 +
  38.326 +   Since both the existing and new mailbox are on the same remote
  38.327 +   server, the client can simply make a connection to the remote server
  38.328 +   and re-issue the RENAME command.
  38.329 +
  38.330 +4.4. COPY Referrals
  38.331 +
  38.332 +   An IMAP4 server MAY respond to the COPY command with one or more IMAP
  38.333 +   mailbox referrals.  This indicates that the destination mailbox is on
  38.334 +   a remote server.  To achieve the same behavior of a server COPY, the
  38.335 +   client MAY issue the constituent FETCH and APPEND commands against
  38.336 +   both servers.
  38.337 +
  38.338 +
  38.339 +
  38.340 +
  38.341 +Gahrns                      Standards Track                     [Page 6]
  38.342 +
  38.343 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.344 +
  38.345 +
  38.346 +   Example:
  38.347 +
  38.348 +      C: A001 COPY 1 "SHARED/STUFF"
  38.349 +      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/STUFF]
  38.350 +              Unable to copy message(s) to SERVER2.
  38.351 +
  38.352 +5.1 RLIST command
  38.353 +
  38.354 +   Arguments:  reference name
  38.355 +               mailbox name with possible wildcards
  38.356 +
  38.357 +   Responses:  untagged responses: LIST
  38.358 +
  38.359 +   Result:     OK - RLIST Completed
  38.360 +               NO - RLIST Failure
  38.361 +               BAD - command unknown or arguments invalid
  38.362 +
  38.363 +   The RLIST command behaves identically to its LIST counterpart, except
  38.364 +   remote mailboxes are returned in addition to local mailboxes in the
  38.365 +   LIST responses.
  38.366 +
  38.367 +5.2 RLSUB Command
  38.368 +
  38.369 +   Arguments:  reference name
  38.370 +               mailbox name with possible wildcards
  38.371 +
  38.372 +   Responses:  untagged responses: LSUB
  38.373 +
  38.374 +   Result:     OK - RLSUB Completed
  38.375 +               NO - RLSUB Failure
  38.376 +               BAD - command unknown or arguments invalid
  38.377 +
  38.378 +   The RLSUB command behaves identically to its LSUB counterpart, except
  38.379 +   remote mailboxes are returned in addition to local mailboxes in the
  38.380 +   LSUB responses.
  38.381 +
  38.382 +6. Formal Syntax
  38.383 +
  38.384 +   The following syntax specification uses the augmented Backus-Naur
  38.385 +   Form (BNF) as described in [ABNF].
  38.386 +
  38.387 +   list_mailbox = <list_mailbox> as defined in [RFC-2060]
  38.388 +
  38.389 +   mailbox = <mailbox> as defined in [RFC-2060]
  38.390 +
  38.391 +   mailbox_referral = <tag> SPACE "NO" SPACE
  38.392 +      <referral_response_code> (text / text_mime2)
  38.393 +      ; See [RFC-2060] for <tag>, text and text_mime2 definition
  38.394 +
  38.395 +
  38.396 +
  38.397 +Gahrns                      Standards Track                     [Page 7]
  38.398 +
  38.399 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.400 +
  38.401 +
  38.402 +   referral_response_code = "[" "REFERRAL" 1*(SPACE <url>) "]"
  38.403 +      ; See [RFC-1738] for <url> definition
  38.404 +
  38.405 +   rlist = "RLIST" SPACE mailbox SPACE list_mailbox
  38.406 +
  38.407 +   rlsub = "RLSUB" SPACE mailbox SPACE list_mailbox
  38.408 +
  38.409 +6. Security Considerations
  38.410 +
  38.411 +   The IMAP4 referral mechanism makes use of IMAP URLs, and as such,
  38.412 +   have the same security considerations as general internet URLs [RFC-
  38.413 +   1738], and in particular IMAP URLs [RFC-2192].
  38.414 +
  38.415 +   With the MAILBOX-REFERRALS capability, it is potentially easier to
  38.416 +   write a rogue server that injects a bogus referral response that
  38.417 +   directs a user to an incorrect mailbox.  Although referrals reduce
  38.418 +   the effort to write such a server, the referral response makes
  38.419 +   detection of the intrusion easier.
  38.420 +
  38.421 +7. References
  38.422 +
  38.423 +   [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version
  38.424 +   4rev1", RFC 2060, University of Washington, December 1996.
  38.425 +
  38.426 +   [RFC-2192], Newman, C., "IMAP URL Scheme", RFC 2192, Innosoft,
  38.427 +   September 1997.
  38.428 +
  38.429 +   [RFC-1738], Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
  38.430 +   Resource Locators (URL)", RFC 1738, CERN, Xerox Corporation,
  38.431 +   University of Minnesota, December 1994.
  38.432 +
  38.433 +   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
  38.434 +   Requirement Levels", RFC 2119, Harvard University, March 1997.
  38.435 +
  38.436 +   [ABNF], DRUMS working group, Dave Crocker Editor, "Augmented BNF for
  38.437 +   Syntax Specifications: ABNF", Work in Progress, Internet Mail
  38.438 +   Consortium, April 1997.
  38.439 +
  38.440 +8.  Acknowledgments
  38.441 +
  38.442 +   Many valuable suggestions were received from private discussions and
  38.443 +   the IMAP4 mailing list.  In particular, Raymond Cheng, Mark Crispin,
  38.444 +   Mark Keasling, Chris Newman and Larry Osterman made significant
  38.445 +   contributions to this document.
  38.446 +
  38.447 +
  38.448 +
  38.449 +
  38.450 +
  38.451 +
  38.452 +
  38.453 +Gahrns                      Standards Track                     [Page 8]
  38.454 +
  38.455 +RFC 2193                IMAP4 Mailbox Referrals           September 1997
  38.456 +
  38.457 +
  38.458 +9. Author's Address
  38.459 +
  38.460 +   Mike Gahrns
  38.461 +   Microsoft
  38.462 +   One Microsoft Way
  38.463 +   Redmond, WA, 98072
  38.464 +
  38.465 +   Phone: (206) 936-9833
  38.466 +   EMail: mikega@microsoft.com
  38.467 +
  38.468 +
  38.469 +
  38.470 +
  38.471 +
  38.472 +
  38.473 +
  38.474 +
  38.475 +
  38.476 +
  38.477 +
  38.478 +
  38.479 +
  38.480 +
  38.481 +
  38.482 +
  38.483 +
  38.484 +
  38.485 +
  38.486 +
  38.487 +
  38.488 +
  38.489 +
  38.490 +
  38.491 +
  38.492 +
  38.493 +
  38.494 +
  38.495 +
  38.496 +
  38.497 +
  38.498 +
  38.499 +
  38.500 +
  38.501 +
  38.502 +
  38.503 +
  38.504 +
  38.505 +
  38.506 +
  38.507 +
  38.508 +
  38.509 +Gahrns                      Standards Track                     [Page 9]
  38.510 +
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/docs/rfc/rfc2195.txt	Mon Sep 14 15:17:45 2009 +0900
    39.3 @@ -0,0 +1,283 @@
    39.4 +
    39.5 +
    39.6 +
    39.7 +
    39.8 +
    39.9 +
   39.10 +Network Working Group                                       J. Klensin
   39.11 +Request for Comments: 2195                                    R. Catoe
   39.12 +Category: Standards Track                                 P. Krumviede
   39.13 +Obsoletes: 2095                                                    MCI
   39.14 +                                                        September 1997
   39.15 +
   39.16 +
   39.17 +       IMAP/POP AUTHorize Extension for Simple Challenge/Response
   39.18 +
   39.19 +Status of this Memo
   39.20 +
   39.21 +   This document specifies an Internet standards track protocol for the
   39.22 +   Internet community, and requests discussion and suggestions for
   39.23 +   improvements.  Please refer to the current edition of the "Internet
   39.24 +   Official Protocol Standards" (STD 1) for the standardization state
   39.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   39.26 +
   39.27 +Abstract
   39.28 +
   39.29 +   While IMAP4 supports a number of strong authentication mechanisms as
   39.30 +   described in RFC 1731, it lacks any mechanism that neither passes
   39.31 +   cleartext, reusable passwords across the network nor requires either
   39.32 +   a significant security infrastructure or that the mail server update
   39.33 +   a mail-system-wide user authentication file on each mail access.
   39.34 +   This specification provides a simple challenge-response
   39.35 +   authentication protocol that is suitable for use with IMAP4.  Since
   39.36 +   it utilizes Keyed-MD5 digests and does not require that the secret be
   39.37 +   stored in the clear on the server, it may also constitute an
   39.38 +   improvement on APOP for POP3 use as specified in RFC 1734.
   39.39 +
   39.40 +1. Introduction
   39.41 +
   39.42 +   Existing Proposed Standards specify an AUTHENTICATE mechanism for the
   39.43 +   IMAP4 protocol [IMAP, IMAP-AUTH] and a parallel AUTH mechanism for
   39.44 +   the POP3 protocol [POP3-AUTH].  The AUTHENTICATE mechanism is
   39.45 +   intended to be extensible; the four methods specified in [IMAP-AUTH]
   39.46 +   are all fairly powerful and require some security infrastructure to
   39.47 +   support.  The base POP3 specification [POP3] also contains a
   39.48 +   lightweight challenge-response mechanism called APOP.  APOP is
   39.49 +   associated with most of the risks associated with such protocols: in
   39.50 +   particular, it requires that both the client and server machines have
   39.51 +   access to the shared secret in cleartext form. CRAM offers a method
   39.52 +   for avoiding such cleartext storage while retaining the algorithmic
   39.53 +   simplicity of APOP in using only MD5, though in a "keyed" method.
   39.54 +
   39.55 +
   39.56 +
   39.57 +
   39.58 +
   39.59 +
   39.60 +
   39.61 +Klensin, Catoe & Krumviede  Standards Track                     [Page 1]
   39.62 +
   39.63 +RFC 2195              IMAP/POP AUTHorize Extension        September 1997
   39.64 +
   39.65 +
   39.66 +   At present, IMAP [IMAP] lacks any facility corresponding to APOP.
   39.67 +   The only alternative to the strong mechanisms identified in [IMAP-
   39.68 +   AUTH] is a presumably cleartext username and password, supported
   39.69 +   through the LOGIN command in [IMAP].  This document describes a
   39.70 +   simple challenge-response mechanism, similar to APOP and PPP CHAP
   39.71 +   [PPP], that can be used with IMAP (and, in principle, with POP3).
   39.72 +
   39.73 +   This mechanism also has the advantage over some possible alternatives
   39.74 +   of not requiring that the server maintain information about email
   39.75 +   "logins" on a per-login basis.  While mechanisms that do require such
   39.76 +   per-login history records may offer enhanced security, protocols such
   39.77 +   as IMAP, which may have several connections between a given client
   39.78 +   and server open more or less simultaneous, may make their
   39.79 +   implementation particularly challenging.
   39.80 +
   39.81 +2. Challenge-Response Authentication Mechanism (CRAM)
   39.82 +
   39.83 +   The authentication type associated with CRAM is "CRAM-MD5".
   39.84 +
   39.85 +   The data encoded in the first ready response contains an
   39.86 +   presumptively arbitrary string of random digits, a timestamp, and the
   39.87 +   fully-qualified primary host name of the server.  The syntax of the
   39.88 +   unencoded form must correspond to that of an RFC 822 'msg-id'
   39.89 +   [RFC822] as described in [POP3].
   39.90 +
   39.91 +   The client makes note of the data and then responds with a string
   39.92 +   consisting of the user name, a space, and a 'digest'.  The latter is
   39.93 +   computed by applying the keyed MD5 algorithm from [KEYED-MD5] where
   39.94 +   the key is a shared secret and the digested text is the timestamp
   39.95 +   (including angle-brackets).
   39.96 +
   39.97 +   This shared secret is a string known only to the client and server.
   39.98 +   The `digest' parameter itself is a 16-octet value which is sent in
   39.99 +   hexadecimal format, using lower-case ASCII characters.
  39.100 +
  39.101 +   When the server receives this client response, it verifies the digest
  39.102 +   provided.  If the digest is correct, the server should consider the
  39.103 +   client authenticated and respond appropriately.
  39.104 +
  39.105 +   Keyed MD5 is chosen for this application because of the greater
  39.106 +   security imparted to authentication of short messages. In addition,
  39.107 +   the use of the techniques described in [KEYED-MD5] for precomputation
  39.108 +   of intermediate results make it possible to avoid explicit cleartext
  39.109 +   storage of the shared secret on the server system by instead storing
  39.110 +   the intermediate results which are known as "contexts".
  39.111 +
  39.112 +
  39.113 +
  39.114 +
  39.115 +
  39.116 +
  39.117 +Klensin, Catoe & Krumviede  Standards Track                     [Page 2]
  39.118 +
  39.119 +RFC 2195              IMAP/POP AUTHorize Extension        September 1997
  39.120 +
  39.121 +
  39.122 +   CRAM does not support a protection mechanism.
  39.123 +
  39.124 +   Example:
  39.125 +
  39.126 +   The examples in this document show the use of the CRAM mechanism with
  39.127 +   the IMAP4 AUTHENTICATE command [IMAP-AUTH].  The base64 encoding of
  39.128 +   the challenges and responses is part of the IMAP4 AUTHENTICATE
  39.129 +   command, not part of the CRAM specification itself.
  39.130 +
  39.131 +     S: * OK IMAP4 Server
  39.132 +     C: A0001 AUTHENTICATE CRAM-MD5
  39.133 +     S: + PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+
  39.134 +     C: dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
  39.135 +     S: A0001 OK CRAM authentication successful
  39.136 +
  39.137 +      In this example, the shared secret is the string
  39.138 +      'tanstaaftanstaaf'.  Hence, the Keyed MD5 digest is produced by
  39.139 +      calculating
  39.140 +
  39.141 +        MD5((tanstaaftanstaaf XOR opad),
  39.142 +            MD5((tanstaaftanstaaf XOR ipad),
  39.143 +            <1896.697170952@postoffice.reston.mci.net>))
  39.144 +
  39.145 +      where ipad and opad are as defined in the keyed-MD5 Work in
  39.146 +      Progress [KEYED-MD5] and the string shown in the challenge is the
  39.147 +      base64 encoding of <1896.697170952@postoffice.reston.mci.net>. The
  39.148 +      shared secret is null-padded to a length of 64 bytes. If the
  39.149 +      shared secret is longer than 64 bytes, the MD5 digest of the
  39.150 +      shared secret is used as a 16 byte input to the keyed MD5
  39.151 +      calculation.
  39.152 +
  39.153 +      This produces a digest value (in hexadecimal) of
  39.154 +
  39.155 +           b913a602c7eda7a495b4e6e7334d3890
  39.156 +
  39.157 +      The user name is then prepended to it, forming
  39.158 +
  39.159 +           tim b913a602c7eda7a495b4e6e7334d3890
  39.160 +
  39.161 +      Which is then base64 encoded to meet the requirements of the IMAP4
  39.162 +      AUTHENTICATE command (or the similar POP3 AUTH command), yielding
  39.163 +
  39.164 +           dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
  39.165 +
  39.166 +
  39.167 +
  39.168 +
  39.169 +
  39.170 +
  39.171 +
  39.172 +
  39.173 +Klensin, Catoe & Krumviede  Standards Track                     [Page 3]
  39.174 +
  39.175 +RFC 2195              IMAP/POP AUTHorize Extension        September 1997
  39.176 +
  39.177 +
  39.178 +3. References
  39.179 +
  39.180 +   [CHAP]  Lloyd, B., and W. Simpson, "PPP Authentication Protocols",
  39.181 +       RFC 1334, October 1992.
  39.182 +
  39.183 +   [IMAP] Crispin, M., "Internet Message Access Protocol - Version
  39.184 +       4rev1", RFC 2060, University of Washington, December 1996.
  39.185 +
  39.186 +   [IMAP-AUTH] Myers, J., "IMAP4 Authentication Mechanisms",
  39.187 +       RFC 1731, Carnegie Mellon, December 1994.
  39.188 +
  39.189 +   [KEYED-MD5] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for
  39.190 +       Message Authentication", RFC 2104, February 1997.
  39.191 +
  39.192 +   [MD5]  Rivest, R., "The MD5 Message Digest Algorithm",
  39.193 +       RFC 1321, MIT Laboratory for Computer Science, April 1992.
  39.194 +
  39.195 +   [POP3] Myers, J., and M. Rose, "Post Office Protocol - Version 3",
  39.196 +       STD 53, RFC 1939, Carnegie Mellon, May 1996.
  39.197 +
  39.198 +   [POP3-AUTH] Myers, J., "POP3 AUTHentication command", RFC 1734,
  39.199 +       Carnegie Mellon, December, 1994.
  39.200 +
  39.201 +4. Security Considerations
  39.202 +
  39.203 +   It is conjectured that use of the CRAM authentication mechanism
  39.204 +   provides origin identification and replay protection for a session.
  39.205 +   Accordingly, a server that implements both a cleartext password
  39.206 +   command and this authentication type should not allow both methods of
  39.207 +   access for a given user.
  39.208 +
  39.209 +   While the saving, on the server, of "contexts" (see section 2) is
  39.210 +   marginally better than saving the shared secrets in cleartext as is
  39.211 +   required by CHAP [CHAP] and APOP [POP3], it is not sufficient to
  39.212 +   protect the secrets if the server itself is compromised.
  39.213 +   Consequently, servers that store the secrets or contexts must both be
  39.214 +   protected to a level appropriate to the potential information value
  39.215 +   in user mailboxes and identities.
  39.216 +
  39.217 +   As the length of the shared secret increases, so does the difficulty
  39.218 +   of deriving it.
  39.219 +
  39.220 +   While there are now suggestions in the literature that the use of MD5
  39.221 +   and keyed MD5 in authentication procedures probably has a limited
  39.222 +   effective lifetime, the technique is now widely deployed and widely
  39.223 +   understood.  It is believed that this general understanding may
  39.224 +   assist with the rapid replacement, by CRAM-MD5, of the current uses
  39.225 +   of permanent cleartext passwords in IMAP.   This document has been
  39.226 +
  39.227 +
  39.228 +
  39.229 +Klensin, Catoe & Krumviede  Standards Track                     [Page 4]
  39.230 +
  39.231 +RFC 2195              IMAP/POP AUTHorize Extension        September 1997
  39.232 +
  39.233 +
  39.234 +   deliberately written to permit easy upgrading to use SHA (or whatever
  39.235 +   alternatives emerge) when they are considered to be widely available
  39.236 +   and adequately safe.
  39.237 +
  39.238 +   Even with the use of CRAM, users are still vulnerable to active
  39.239 +   attacks.  An example of an increasingly common active attack is 'TCP
  39.240 +   Session Hijacking' as described in CERT Advisory CA-95:01 [CERT95].
  39.241 +
  39.242 +   See section 1 above for additional discussion.
  39.243 +
  39.244 +5. Acknowledgements
  39.245 +
  39.246 +   This memo borrows ideas and some text liberally from [POP3] and
  39.247 +   [RFC-1731] and thanks are due the authors of those documents.  Ran
  39.248 +   Atkinson made a number of valuable technical and editorial
  39.249 +   contributions to the document.
  39.250 +
  39.251 +6. Authors' Addresses
  39.252 +
  39.253 +   John C. Klensin
  39.254 +   MCI Telecommunications
  39.255 +   800 Boylston St, 7th floor
  39.256 +   Boston, MA 02199
  39.257 +   USA
  39.258 +
  39.259 +   EMail: klensin@mci.net
  39.260 +   Phone: +1 617 960 1011
  39.261 +
  39.262 +   Randy Catoe
  39.263 +   MCI Telecommunications
  39.264 +   2100 Reston Parkway
  39.265 +   Reston, VA 22091
  39.266 +   USA
  39.267 +
  39.268 +   EMail: randy@mci.net
  39.269 +   Phone: +1 703 715 7366
  39.270 +
  39.271 +   Paul Krumviede
  39.272 +   MCI Telecommunications
  39.273 +   2100 Reston Parkway
  39.274 +   Reston, VA 22091
  39.275 +   USA
  39.276 +
  39.277 +   EMail: paul@mci.net
  39.278 +   Phone: +1 703 715 7251
  39.279 +
  39.280 +
  39.281 +
  39.282 +
  39.283 +
  39.284 +
  39.285 +Klensin, Catoe & Krumviede  Standards Track                     [Page 5]
  39.286 +
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/docs/rfc/rfc2221.txt	Mon Sep 14 15:17:45 2009 +0900
    40.3 @@ -0,0 +1,283 @@
    40.4 +
    40.5 +
    40.6 +
    40.7 +
    40.8 +
    40.9 +
   40.10 +Network Working Group                                           M. Gahrns
   40.11 +Request for Comments: 2221                                      Microsoft
   40.12 +Category: Standards Track                                    October 1997
   40.13 +
   40.14 +
   40.15 +                         IMAP4 Login Referrals
   40.16 +
   40.17 +Status of this Memo
   40.18 +
   40.19 +   This document specifies an Internet standards track protocol for the
   40.20 +   Internet community, and requests discussion and suggestions for
   40.21 +   improvements.  Please refer to the current edition of the "Internet
   40.22 +   Official Protocol Standards" (STD 1) for the standardization state
   40.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   40.24 +
   40.25 +Copyright Notice
   40.26 +
   40.27 +   Copyright (C) The Internet Society (1997).  All Rights Reserved.
   40.28 +
   40.29 +1. Abstract
   40.30 +
   40.31 +   When dealing with large amounts of users and many IMAP4 [RFC-2060]
   40.32 +   servers, it is often necessary to move users from one IMAP4 server to
   40.33 +   another.  For example, hardware failures or organizational changes
   40.34 +   may dictate such a move.
   40.35 +
   40.36 +   Login referrals allow clients to transparently connect to an
   40.37 +   alternate IMAP4 server, if their home IMAP4 server has changed.
   40.38 +
   40.39 +   A referral mechanism can provide efficiencies over the alternative
   40.40 +   'proxy method', in which the local IMAP4 server contacts the remote
   40.41 +   server on behalf of the client, and then transfers the data from the
   40.42 +   remote server to itself, and then on to the client.  The referral
   40.43 +   mechanism's direct client connection to the remote server is often a
   40.44 +   more efficient use of bandwidth, and does not require the local
   40.45 +   server to impersonate the client when authenticating to the remote
   40.46 +   server.
   40.47 +
   40.48 +2. Conventions used in this document
   40.49 +
   40.50 +   In examples, "C:" and "S:" indicate lines sent by the client and
   40.51 +   server respectively.
   40.52 +
   40.53 +   A home server, is an IMAP4 server that contains the user's inbox.
   40.54 +
   40.55 +   A remote server is a server that contains remote mailboxes.
   40.56 +
   40.57 +
   40.58 +
   40.59 +
   40.60 +
   40.61 +Gahrns                      Standards Track                     [Page 1]
   40.62 +
   40.63 +RFC 2221                 IMAP4 Login Referrals              October 1997
   40.64 +
   40.65 +
   40.66 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   40.67 +   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   40.68 +   document are to be interpreted as described in [RFC-2119].
   40.69 +
   40.70 +3. Introduction and Overview
   40.71 +
   40.72 +   IMAP4 servers that support this extension MUST list the keyword
   40.73 +   LOGIN-REFERRALS in their CAPABILITY response.  No client action is
   40.74 +   needed to invoke the LOGIN-REFERRALS capability in a server.
   40.75 +
   40.76 +   A LOGIN-REFERRALS capable IMAP4 server SHOULD NOT return a referral
   40.77 +   to a server that will return a referral. A client MUST NOT follow
   40.78 +   more than 10 levels of referral without consulting the user.
   40.79 +
   40.80 +   A LOGIN-REFERRALS response code MUST contain as an argument a valid
   40.81 +   IMAP server URL as defined in [IMAP-URL].
   40.82 +
   40.83 +   A home server referral consists of either a tagged NO or OK, or an
   40.84 +   untagged BYE response that contains a LOGIN-REFERRALS response code.
   40.85 +
   40.86 +   Example: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/] Remote Server
   40.87 +
   40.88 +   NOTE: user;AUTH=* is specified as required by [IMAP-URL] to avoid a
   40.89 +   client falling back to anonymous login.
   40.90 +
   40.91 +4. Home Server Referrals
   40.92 +
   40.93 +   A home server referral may be returned in response to an AUTHENTICATE
   40.94 +   or LOGIN command, or it may appear in the connection startup banner.
   40.95 +   If a server returns a home server referral in a tagged NO response,
   40.96 +   that server does not contain any mailboxes that are accessible to the
   40.97 +   user.  If a server returns a home server referral in a tagged OK
   40.98 +   response, it indicates that the user's personal mailboxes are
   40.99 +   elsewhere, but the server contains public mailboxes which are
  40.100 +   readable by the user.  After receiving a home server referral, the
  40.101 +   client can not make any assumptions as to whether this was a
  40.102 +   permanent or temporary move of the user.
  40.103 +
  40.104 +4.1.  LOGIN and AUTHENTICATE Referrals
  40.105 +
  40.106 +   An IMAP4 server MAY respond to a LOGIN or AUTHENTICATE command with a
  40.107 +   home server referral if it wishes to direct the user to another IMAP4
  40.108 +   server.
  40.109 +
  40.110 +   Example:  C: A001 LOGIN MIKE PASSWORD
  40.111 +             S: A001 NO [REFERRAL IMAP://MIKE@SERVER2/] Specified user
  40.112 +                     is invalid on this server. Try SERVER2.
  40.113 +
  40.114 +
  40.115 +
  40.116 +
  40.117 +Gahrns                      Standards Track                     [Page 2]
  40.118 +
  40.119 +RFC 2221                 IMAP4 Login Referrals              October 1997
  40.120 +
  40.121 +
  40.122 +   Example:  C: A001 LOGIN MATTHEW PASSWORD
  40.123 +             S: A001 OK [REFERRAL IMAP://MATTHEW@SERVER2/] Specified
  40.124 +                     user's personal mailboxes located on Server2, but
  40.125 +                     public mailboxes are available.
  40.126 +
  40.127 +   Example:  C: A001 AUTHENTICATE GSSAPI
  40.128 +             <authentication exchange>
  40.129 +             S: A001 NO [REFERRAL IMAP://user;AUTH=GSSAPI@SERVER2/]
  40.130 +                     Specified user is invalid on this server. Try
  40.131 +                     SERVER2.
  40.132 +
  40.133 +4.2. BYE at connection startup referral
  40.134 +
  40.135 +   An IMAP4 server MAY respond with an untagged BYE and a REFERRAL
  40.136 +   response code that contains an IMAP URL to a home server if it is not
  40.137 +   willing to accept connections and wishes to direct the client to
  40.138 +   another IMAP4 server.
  40.139 +
  40.140 +   Example:  S: * BYE [REFERRAL IMAP://user;AUTH=*@SERVER2/] Server not
  40.141 +                  accepting connections.  Try SERVER2
  40.142 +
  40.143 +5. Formal Syntax
  40.144 +
  40.145 +   The following syntax specification uses the augmented Backus-Naur
  40.146 +   Form (BNF) as described in [ABNF].
  40.147 +
  40.148 +   This amends the "resp_text_code" element of the IMAP4 grammar
  40.149 +   described in [RFC-2060]
  40.150 +
  40.151 +   resp_text_code =/ "REFERRAL" SPACE <imapurl>
  40.152 +      ; See [IMAP-URL] for definition of <imapurl>
  40.153 +      ; See [RFC-2060] for base definition of resp_text_code
  40.154 +
  40.155 +6. Security Considerations
  40.156 +
  40.157 +   The IMAP4 login referral mechanism makes use of IMAP URLs, and as
  40.158 +   such, have the same security considerations as general internet URLs
  40.159 +   [RFC-1738], and in particular IMAP URLs [IMAP-URL].
  40.160 +
  40.161 +   A server MUST NOT give a login referral if authentication for that
  40.162 +   user fails. This is to avoid revealing information about the user's
  40.163 +   account to an unauthorized user.
  40.164 +
  40.165 +   With the LOGIN-REFERRALS capability, it is potentially easier to
  40.166 +   write a rogue 'password catching' server that collects login data and
  40.167 +   then refers the client to their actual IMAP4 server.  Although
  40.168 +   referrals reduce the effort to write such a server, the referral
  40.169 +   response makes detection of the intrusion easier.
  40.170 +
  40.171 +
  40.172 +
  40.173 +Gahrns                      Standards Track                     [Page 3]
  40.174 +
  40.175 +RFC 2221                 IMAP4 Login Referrals              October 1997
  40.176 +
  40.177 +
  40.178 +7. References
  40.179 +
  40.180 +   [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version
  40.181 +   4rev1", RFC 2060, December 1996.
  40.182 +
  40.183 +   [IMAP-URL], Newman, C., "IMAP URL Scheme", RFC 2192, Innosoft,
  40.184 +   September 1997.
  40.185 +
  40.186 +   [RFC-1738], Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform
  40.187 +   Resource Locators  (URL)", RFC 1738, December 1994.
  40.188 +
  40.189 +   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
  40.190 +   Requirement Levels", RFC 2119, March 1997.
  40.191 +
  40.192 +   [ABNF], DRUMS working group, Dave Crocker Editor, "Augmented BNF for
  40.193 +   Syntax Specifications: ABNF", Work in Progress.
  40.194 +
  40.195 +8.  Acknowledgments
  40.196 +
  40.197 +   Many valuable suggestions were received from private discussions and
  40.198 +   the IMAP4 mailing list.  In particular, Raymond Cheng, Mark Crispin,
  40.199 +   Mark Keasling Chris Newman and Larry Osterman made significant
  40.200 +   contributions to this document.
  40.201 +
  40.202 +9. Author's Address
  40.203 +
  40.204 +   Mike Gahrns
  40.205 +   Microsoft
  40.206 +   One Microsoft Way
  40.207 +   Redmond, WA, 98072
  40.208 +
  40.209 +   Phone: (206) 936-9833
  40.210 +   EMail: mikega@microsoft.com
  40.211 +
  40.212 +
  40.213 +
  40.214 +
  40.215 +
  40.216 +
  40.217 +
  40.218 +
  40.219 +
  40.220 +
  40.221 +
  40.222 +
  40.223 +
  40.224 +
  40.225 +
  40.226 +
  40.227 +
  40.228 +
  40.229 +Gahrns                      Standards Track                     [Page 4]
  40.230 +
  40.231 +RFC 2221                 IMAP4 Login Referrals              October 1997
  40.232 +
  40.233 +
  40.234 +10.  Full Copyright Statement
  40.235 +
  40.236 +   Copyright (C) The Internet Society (1997).  All Rights Reserved.
  40.237 +
  40.238 +   This document and translations of it may be copied and furnished to
  40.239 +   others, and derivative works that comment on or otherwise explain it
  40.240 +   or assist in its implmentation may be prepared, copied, published
  40.241 +   andand distributed, in whole or in part, without restriction of any
  40.242 +   kind, provided that the above copyright notice and this paragraph are
  40.243 +   included on all such copies and derivative works.  However, this
  40.244 +   document itself may not be modified in any way, such as by removing
  40.245 +   the copyright notice or references to the Internet Society or other
  40.246 +   Internet organizations, except as needed for the purpose of
  40.247 +   developing Internet standards in which case the procedures for
  40.248 +   copyrights defined in the Internet Standards process must be
  40.249 +   followed, or as required to translate it into languages other than
  40.250 +   English.
  40.251 +
  40.252 +   The limited permissions granted above are perpetual and will not be
  40.253 +   revoked by the Internet Society or its successors or assigns.
  40.254 +
  40.255 +   This document and the information contained herein is provided on an
  40.256 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  40.257 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  40.258 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  40.259 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  40.260 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
  40.261 +
  40.262 +
  40.263 +
  40.264 +
  40.265 +
  40.266 +
  40.267 +
  40.268 +
  40.269 +
  40.270 +
  40.271 +
  40.272 +
  40.273 +
  40.274 +
  40.275 +
  40.276 +
  40.277 +
  40.278 +
  40.279 +
  40.280 +
  40.281 +
  40.282 +
  40.283 +
  40.284 +
  40.285 +Gahrns                      Standards Track                     [Page 5]
  40.286 +
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/docs/rfc/rfc2342.txt	Mon Sep 14 15:17:45 2009 +0900
    41.3 @@ -0,0 +1,563 @@
    41.4 +
    41.5 +
    41.6 +
    41.7 +
    41.8 +
    41.9 +
   41.10 +Network Working Group                                         M. Gahrns
   41.11 +Request for Comments: 2342                                    Microsoft
   41.12 +Category: Standards Track                                     C. Newman
   41.13 +                                                               Innosoft
   41.14 +                                                               May 1998
   41.15 +
   41.16 +
   41.17 +                            IMAP4 Namespace
   41.18 +
   41.19 +Status of this Memo
   41.20 +
   41.21 +   This document specifies an Internet standards track protocol for the
   41.22 +   Internet community, and requests discussion and suggestions for
   41.23 +   improvements.  Please refer to the current edition of the "Internet
   41.24 +   Official Protocol Standards" (STD 1) for the standardization state
   41.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   41.26 +
   41.27 +Copyright Notice
   41.28 +
   41.29 +   Copyright (C) The Internet Society (1998).  All Rights Reserved.
   41.30 +
   41.31 +1. Abstract
   41.32 +
   41.33 +   IMAP4 [RFC-2060] does not define a default server namespace. As a
   41.34 +   result, two common namespace models have evolved:
   41.35 +
   41.36 +   The "Personal Mailbox" model, in which the default namespace that is
   41.37 +   presented consists of only the user's personal mailboxes. To access
   41.38 +   shared mailboxes, the user must use an escape mechanism to reach
   41.39 +   another namespace.
   41.40 +
   41.41 +   The "Complete Hierarchy" model, in which the default namespace that
   41.42 +   is presented includes the user's personal mailboxes along with any
   41.43 +   other mailboxes they have access to.
   41.44 +
   41.45 +   These two models, create difficulties for certain client operations.
   41.46 +   This document defines a NAMESPACE command that allows a client to
   41.47 +   discover the prefixes of namespaces used by a server for personal
   41.48 +   mailboxes, other users' mailboxes, and shared mailboxes.  This allows
   41.49 +   a client to avoid much of the manual user configuration that is now
   41.50 +   necessary when mixing and matching IMAP4 clients and servers.
   41.51 +
   41.52 +2. Conventions used in this document
   41.53 +
   41.54 +   In examples, "C:" and "S:" indicate lines sent by the client and
   41.55 +   server respectively.  If such lines are wrapped without a new "C:" or
   41.56 +   "S:" label, then the wrapping is for editorial clarity and is not
   41.57 +   part of the command.
   41.58 +
   41.59 +
   41.60 +
   41.61 +Gahrns & Newman             Standards Track                     [Page 1]
   41.62 +
   41.63 +RFC 2342                    IMAP4 Namespace                     May 1998
   41.64 +
   41.65 +
   41.66 +   Personal Namespace: A namespace that the server considers within the
   41.67 +   personal scope of the authenticated user on a particular connection.
   41.68 +   Typically, only the authenticated user has access to mailboxes in
   41.69 +   their Personal Namespace. It is the part of the namespace that
   41.70 +   belongs to the user that is allocated for mailboxes. If an INBOX
   41.71 +   exists for a user, it MUST appear within the user's personal
   41.72 +   namespace.  In the typical case, there SHOULD be only one Personal
   41.73 +   Namespace on a server.
   41.74 +
   41.75 +   Other Users' Namespace: A namespace that consists of mailboxes from
   41.76 +   the Personal Namespaces of other users.  To access mailboxes in the
   41.77 +   Other Users' Namespace, the currently authenticated user MUST be
   41.78 +   explicitly granted access rights.  For example, it is common for a
   41.79 +   manager to grant to their secretary access rights to their mailbox.
   41.80 +   In the typical case, there SHOULD be only one Other Users' Namespace
   41.81 +   on a server.
   41.82 +
   41.83 +   Shared Namespace: A namespace that consists of mailboxes that are
   41.84 +   intended to be shared amongst users and do not exist within a user's
   41.85 +   Personal Namespace.
   41.86 +
   41.87 +   The namespaces a server uses MAY differ on a per-user basis.
   41.88 +
   41.89 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   41.90 +   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   41.91 +   document are to be interpreted as described in [RFC-2119].
   41.92 +
   41.93 +3. Introduction and Overview
   41.94 +
   41.95 +   Clients often attempt to create mailboxes for such purposes as
   41.96 +   maintaining a record of sent messages (e.g. "Sent Mail") or
   41.97 +   temporarily saving messages being composed (e.g. "Drafts").  For
   41.98 +   these clients to inter-operate correctly with the variety of IMAP4
   41.99 +   servers available, the user must enter the prefix of the Personal
  41.100 +   Namespace used by the server.  Using the NAMESPACE command, a client
  41.101 +   is able to automatically discover this prefix without manual user
  41.102 +   configuration.
  41.103 +
  41.104 +   In addition, users are often required to manually enter the prefixes
  41.105 +   of various namespaces in order to view the mailboxes located there.
  41.106 +   For example, they might be required to enter the prefix of #shared to
  41.107 +   view the shared mailboxes namespace. The NAMESPACE command allows a
  41.108 +   client to automatically discover the namespaces that are available on
  41.109 +   a server. This allows a client to present the available namespaces to
  41.110 +   the user in what ever manner it deems appropriate.  For example, a
  41.111 +
  41.112 +
  41.113 +
  41.114 +
  41.115 +
  41.116 +
  41.117 +Gahrns & Newman             Standards Track                     [Page 2]
  41.118 +
  41.119 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.120 +
  41.121 +
  41.122 +   client could choose to initially display only personal mailboxes, or
  41.123 +   it may choose to display the complete list of mailboxes available,
  41.124 +   and initially position the user at the root of their Personal
  41.125 +   Namespace.
  41.126 +
  41.127 +   A server MAY choose to make available to the NAMESPACE command only a
  41.128 +   subset of the complete set of namespaces the server supports. To
  41.129 +   provide the ability to access these namespaces, a client SHOULD allow
  41.130 +   the user the ability to manually enter a namespace prefix.
  41.131 +
  41.132 +4. Requirements
  41.133 +
  41.134 +   IMAP4 servers that support this extension MUST list the keyword
  41.135 +   NAMESPACE in their CAPABILITY response.
  41.136 +
  41.137 +   The NAMESPACE command is valid in the Authenticated and Selected
  41.138 +   state.
  41.139 +
  41.140 +5. NAMESPACE Command
  41.141 +
  41.142 +   Arguments: none
  41.143 +
  41.144 +   Response:  an untagged NAMESPACE response that contains the prefix
  41.145 +                 and hierarchy delimiter to the server's Personal
  41.146 +                 Namespace(s), Other Users' Namespace(s), and Shared
  41.147 +                 Namespace(s) that the server wishes to expose. The
  41.148 +                 response will contain a NIL for any namespace class
  41.149 +                 that is not available. Namespace_Response_Extensions
  41.150 +                 MAY be included in the response.
  41.151 +                 Namespace_Response_Extensions which are not on the IETF
  41.152 +                 standards track, MUST be prefixed with an "X-".
  41.153 +
  41.154 +   Result:    OK - Command completed
  41.155 +                 NO - Error: Can't complete command
  41.156 +                 BAD - argument invalid
  41.157 +
  41.158 +   Example 5.1:
  41.159 +   ===========
  41.160 +
  41.161 +      < A server that supports a single personal namespace.  No leading
  41.162 +      prefix is used on personal mailboxes and "/" is the hierarchy
  41.163 +      delimiter.>
  41.164 +
  41.165 +      C: A001 NAMESPACE
  41.166 +      S: * NAMESPACE (("" "/")) NIL NIL
  41.167 +      S: A001 OK NAMESPACE command completed
  41.168 +
  41.169 +
  41.170 +
  41.171 +
  41.172 +
  41.173 +Gahrns & Newman             Standards Track                     [Page 3]
  41.174 +
  41.175 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.176 +
  41.177 +
  41.178 +   Example 5.2:
  41.179 +   ===========
  41.180 +
  41.181 +      < A user logged on anonymously to a server.  No personal mailboxes
  41.182 +      are associated with the anonymous user and the user does not have
  41.183 +      access to the Other Users' Namespace.  No prefix is required to
  41.184 +      access shared mailboxes and the hierarchy delimiter is "." >
  41.185 +
  41.186 +      C: A001 NAMESPACE
  41.187 +      S: * NAMESPACE NIL NIL (("" "."))
  41.188 +      S: A001 OK NAMESPACE command completed
  41.189 +
  41.190 +   Example 5.3:
  41.191 +   ===========
  41.192 +
  41.193 +      < A server that contains a Personal Namespace and a single Shared
  41.194 +      Namespace. >
  41.195 +
  41.196 +      C: A001 NAMESPACE
  41.197 +      S: * NAMESPACE (("" "/")) NIL (("Public Folders/" "/"))
  41.198 +      S: A001 OK NAMESPACE command completed
  41.199 +
  41.200 +   Example 5.4:
  41.201 +   ===========
  41.202 +
  41.203 +      < A server that contains a Personal Namespace, Other Users'
  41.204 +      Namespace and multiple Shared Namespaces.  Note that the hierarchy
  41.205 +      delimiter used within each namespace can be different. >
  41.206 +
  41.207 +      C: A001 NAMESPACE
  41.208 +      S: * NAMESPACE (("" "/")) (("~" "/")) (("#shared/" "/")
  41.209 +         ("#public/" "/")("#ftp/" "/")("#news." "."))
  41.210 +      S: A001 OK NAMESPACE command completed
  41.211 +
  41.212 +   The prefix string allows a client to do things such as automatically
  41.213 +   creating personal mailboxes or LISTing all available mailboxes within
  41.214 +   a namespace.
  41.215 +
  41.216 +   Example 5.5:
  41.217 +   ===========
  41.218 +
  41.219 +      < A server that supports only the Personal Namespace, with a
  41.220 +      leading prefix of INBOX to personal mailboxes and a hierarchy
  41.221 +      delimiter of ".">
  41.222 +
  41.223 +      C: A001 NAMESPACE
  41.224 +      S: * NAMESPACE (("INBOX." ".")) NIL  NIL
  41.225 +      S: A001 OK NAMESPACE command completed
  41.226 +
  41.227 +
  41.228 +
  41.229 +Gahrns & Newman             Standards Track                     [Page 4]
  41.230 +
  41.231 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.232 +
  41.233 +
  41.234 +      < Automatically create a mailbox to store sent items.>
  41.235 +
  41.236 +      C: A002 CREATE "INBOX.Sent Mail"
  41.237 +      S: A002 OK CREATE command completed
  41.238 +
  41.239 +   Although typically a server will support only a single Personal
  41.240 +   Namespace, and a single Other User's Namespace, circumstances exist
  41.241 +   where there MAY be multiples of these, and a client MUST be prepared
  41.242 +   for them.   If a client is configured such that it is required to
  41.243 +   create a certain mailbox, there can be circumstances where it is
  41.244 +   unclear which Personal Namespaces it should create the mailbox in.
  41.245 +   In these situations a client SHOULD let the user select which
  41.246 +   namespaces to create the mailbox in.
  41.247 +
  41.248 +   Example 5.6:
  41.249 +   ===========
  41.250 +
  41.251 +      < In this example, a server supports 2 Personal Namespaces.  In
  41.252 +      addition to the regular Personal Namespace, the user has an
  41.253 +      additional personal namespace to allow access to mailboxes in an
  41.254 +      MH format mailstore. >
  41.255 +
  41.256 +      < The client is configured to save a copy of all mail sent by the
  41.257 +      user into a mailbox called 'Sent Mail'.  Furthermore, after a
  41.258 +      message is deleted from a mailbox, the client is configured to
  41.259 +      move that message to a mailbox called 'Deleted Items'.>
  41.260 +
  41.261 +      < Note that this example demonstrates how some extension flags can
  41.262 +      be passed to further describe the #mh namespace. >
  41.263 +
  41.264 +      C: A001 NAMESPACE
  41.265 +      S: * NAMESPACE (("" "/")("#mh/" "/" "X-PARAM" ("FLAG1" "FLAG2")))
  41.266 +         NIL NIL
  41.267 +      S: A001 OK NAMESPACE command completed
  41.268 +
  41.269 +      < It is desired to keep only one copy of sent mail. It is unclear
  41.270 +      which Personal Namespace the client should use to create the 'Sent
  41.271 +      Mail' mailbox.  The user is prompted to select a namespace and
  41.272 +      only one 'Sent Mail' mailbox is created. >
  41.273 +
  41.274 +      C: A002 CREATE "Sent Mail"
  41.275 +      S: A002 OK CREATE command completed
  41.276 +
  41.277 +      < The client is designed so that it keeps two 'Deleted Items'
  41.278 +      mailboxes, one for each namespace. >
  41.279 +
  41.280 +      C: A003 CREATE "Delete Items"
  41.281 +      S: A003 OK CREATE command completed
  41.282 +
  41.283 +
  41.284 +
  41.285 +Gahrns & Newman             Standards Track                     [Page 5]
  41.286 +
  41.287 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.288 +
  41.289 +
  41.290 +      C: A004 CREATE "#mh/Deleted Items"
  41.291 +      S: A004 OK CREATE command completed
  41.292 +
  41.293 +   The next level of hierarchy following the Other Users' Namespace
  41.294 +   prefix SHOULD consist of <username>, where <username> is a user name
  41.295 +   as per the IMAP4 LOGIN or AUTHENTICATE command.
  41.296 +
  41.297 +   A client can construct a LIST command by appending a "%" to the Other
  41.298 +   Users' Namespace prefix to discover the Personal Namespaces of other
  41.299 +   users that are available to the currently authenticated user.
  41.300 +
  41.301 +   In response to such a LIST command, a server SHOULD NOT return user
  41.302 +   names that have not granted access to their personal mailboxes to the
  41.303 +   user in question.
  41.304 +
  41.305 +   A server MAY return a LIST response containing only the names of
  41.306 +   users that have explicitly granted access to the user in question.
  41.307 +
  41.308 +   Alternatively, a server MAY return NO to such a LIST command,
  41.309 +   requiring that a user name be included with the Other Users'
  41.310 +   Namespace prefix before listing any other user's mailboxes.
  41.311 +
  41.312 +   Example 5.7:
  41.313 +   ===========
  41.314 +
  41.315 +      < A server that supports providing a list of other user's
  41.316 +      mailboxes that are accessible to the currently logged on user. >
  41.317 +
  41.318 +      C: A001 NAMESPACE
  41.319 +      S: * NAMESPACE (("" "/")) (("Other Users/" "/")) NIL
  41.320 +      S: A001 OK NAMESPACE command completed
  41.321 +
  41.322 +      C: A002 LIST "" "Other Users/%"
  41.323 +      S: * LIST () "/" "Other Users/Mike"
  41.324 +      S: * LIST () "/" "Other Users/Karen"
  41.325 +      S: * LIST () "/" "Other Users/Matthew"
  41.326 +      S: * LIST () "/" "Other Users/Tesa"
  41.327 +      S: A002 OK LIST command completed
  41.328 +
  41.329 +   Example 5.8:
  41.330 +   ===========
  41.331 +
  41.332 +      < A server that does not support providing a list of other user's
  41.333 +      mailboxes that are accessible to the currently logged on user.
  41.334 +      The mailboxes are listable if the client includes the name of the
  41.335 +      other user with the Other Users' Namespace prefix. >
  41.336 +
  41.337 +
  41.338 +
  41.339 +
  41.340 +
  41.341 +Gahrns & Newman             Standards Track                     [Page 6]
  41.342 +
  41.343 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.344 +
  41.345 +
  41.346 +      C: A001 NAMESPACE
  41.347 +      S: * NAMESPACE (("" "/")) (("#Users/" "/")) NIL
  41.348 +      S: A001 OK NAMESPACE command completed
  41.349 +
  41.350 +      < In this example, the currently logged on user has access to the
  41.351 +      Personal Namespace of user Mike, but the server chose to suppress
  41.352 +      this information in the LIST response.  However, by appending the
  41.353 +      user name Mike (received through user input) to the Other Users'
  41.354 +      Namespace prefix, the client is able to get a listing of the
  41.355 +      personal mailboxes of user Mike. >
  41.356 +
  41.357 +      C: A002 LIST "" "#Users/%"
  41.358 +      S: A002 NO The requested item could not be found.
  41.359 +
  41.360 +      C: A003 LIST "" "#Users/Mike/%"
  41.361 +      S: * LIST () "/" "#Users/Mike/INBOX"
  41.362 +      S: * LIST () "/" "#Users/Mike/Foo"
  41.363 +      S: A003 OK LIST command completed.
  41.364 +
  41.365 +      A prefix string might not contain a hierarchy delimiter, because
  41.366 +      in some cases it is not needed as part of the prefix.
  41.367 +
  41.368 +      Example 5.9:
  41.369 +      ===========
  41.370 +
  41.371 +      < A server that allows access to the Other Users' Namespace by
  41.372 +      prefixing the others' mailboxes with a '~' followed by <username>,
  41.373 +      where <username> is a user name as per the IMAP4 LOGIN or
  41.374 +      AUTHENTICATE command.>
  41.375 +
  41.376 +      C: A001 NAMESPACE
  41.377 +      S: * NAMESPACE (("" "/")) (("~" "/")) NIL
  41.378 +      S: A001 OK NAMESPACE command completed
  41.379 +
  41.380 +      < List the mailboxes for user mark >
  41.381 +
  41.382 +      C: A002 LIST "" "~mark/%"
  41.383 +      S: * LIST () "/" "~mark/INBOX"
  41.384 +      S: * LIST () "/" "~mark/foo"
  41.385 +      S: A002 OK LIST command completed
  41.386 +
  41.387 +   Historical convention has been to start all namespaces with the "#"
  41.388 +   character.  Namespaces that include the "#" character are not IMAP
  41.389 +   URL [IMAP-URL] friendly requiring the "#" character to be represented
  41.390 +   as %23 when within URLs.  As such, server implementers MAY instead
  41.391 +   consider using namespace prefixes that do not contain the "#"
  41.392 +   character.
  41.393 +
  41.394 +
  41.395 +
  41.396 +
  41.397 +Gahrns & Newman             Standards Track                     [Page 7]
  41.398 +
  41.399 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.400 +
  41.401 +
  41.402 +6. Formal Syntax
  41.403 +
  41.404 +   The following syntax specification uses the augmented Backus-Naur
  41.405 +   Form (BNF) as described in [ABNF].
  41.406 +
  41.407 +   atom = <atom>
  41.408 +      ; <atom> as defined in [RFC-2060]
  41.409 +
  41.410 +   Namespace = nil / "(" 1*( "(" string SP  (<"> QUOTED_CHAR <"> /
  41.411 +      nil) *(Namespace_Response_Extension) ")" ) ")"
  41.412 +
  41.413 +   Namespace_Command = "NAMESPACE"
  41.414 +
  41.415 +   Namespace_Response_Extension = SP string SP "(" string *(SP string)
  41.416 +      ")"
  41.417 +
  41.418 +   Namespace_Response = "*" SP "NAMESPACE" SP Namespace SP Namespace SP
  41.419 +      Namespace
  41.420 +
  41.421 +      ; The first Namespace is the Personal Namespace(s)
  41.422 +      ; The second Namespace is the Other Users' Namespace(s)
  41.423 +      ; The third Namespace is the Shared Namespace(s)
  41.424 +
  41.425 +      nil = <nil>
  41.426 +         ; <nil> as defined in [RFC-2060]
  41.427 +
  41.428 +      QUOTED_CHAR = <QUOTED_CHAR>
  41.429 +         ; <QUOTED_CHAR> as defined in [RFC-2060]
  41.430 +
  41.431 +      string = <string>
  41.432 +         ; <string> as defined in [RFC-2060]
  41.433 +         ; Note that  the namespace prefix is to a mailbox and following
  41.434 +         ; IMAP4 convention, any international string in the NAMESPACE
  41.435 +         ; response MUST be of modified UTF-7 format as described in
  41.436 +         ;  [RFC-2060].
  41.437 +
  41.438 +7. Security Considerations
  41.439 +
  41.440 +   In response to a LIST command containing an argument of the Other
  41.441 +   Users' Namespace prefix, a server SHOULD NOT list users that have not
  41.442 +   granted list access to their personal mailboxes to the currently
  41.443 +   authenticated user.  Providing such a list, could compromise security
  41.444 +   by potentially disclosing confidential information of who is located
  41.445 +   on the server, or providing a starting point of a list of user
  41.446 +   accounts to attack.
  41.447 +
  41.448 +
  41.449 +
  41.450 +
  41.451 +
  41.452 +
  41.453 +Gahrns & Newman             Standards Track                     [Page 8]
  41.454 +
  41.455 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.456 +
  41.457 +
  41.458 +8. References
  41.459 +
  41.460 +   [RFC-2060], Crispin, M., "Internet Message Access Protocol Version
  41.461 +   4rev1", RFC 2060, December 1996.
  41.462 +
  41.463 +   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
  41.464 +   Requirement Levels", BCP 14, RFC 2119, March 1997.
  41.465 +
  41.466 +   [ABNF] Crocker, D., Editor, and P. Overell, "Augmented BNF for Syntax
  41.467 +   Specifications: ABNF", RFC 2234, November 1997.
  41.468 +
  41.469 +   [IMAP-URL], Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
  41.470 +
  41.471 +9.  Acknowledgments
  41.472 +
  41.473 +   Many people have participated in the discussion of IMAP namespaces on
  41.474 +   the IMAP mailing list.  In particular, the authors would like to
  41.475 +   thank Mark Crispin for many of the concepts relating to the Personal
  41.476 +   Namespace and accessing the Personal Namespace of other users, Steve
  41.477 +   Hole for summarizing the two namespace models, John Myers and Jack De
  41.478 +   Winter for their work in a preceding effort trying to define a
  41.479 +   standardized personal namespace, and Larry Osterman for his review
  41.480 +   and collaboration on this document.
  41.481 +
  41.482 +11. Authors' Addresses
  41.483 +
  41.484 +   Mike Gahrns
  41.485 +   Microsoft
  41.486 +   One Microsoft Way
  41.487 +   Redmond, WA, 98072, USA
  41.488 +
  41.489 +   Phone: (425) 936-9833
  41.490 +   EMail: mikega@microsoft.com
  41.491 +
  41.492 +
  41.493 +   Chris Newman
  41.494 +   Innosoft International, Inc.
  41.495 +   1050 East Garvey Ave. South
  41.496 +   West Covina, CA, 91790, USA
  41.497 +
  41.498 +   EMail: chris.newman@innosoft.com
  41.499 +
  41.500 +
  41.501 +
  41.502 +
  41.503 +
  41.504 +
  41.505 +
  41.506 +
  41.507 +
  41.508 +
  41.509 +Gahrns & Newman             Standards Track                     [Page 9]
  41.510 +
  41.511 +RFC 2342                    IMAP4 Namespace                     May 1998
  41.512 +
  41.513 +
  41.514 +12.  Full Copyright Statement
  41.515 +
  41.516 +   Copyright (C) The Internet Society (1998).  All Rights Reserved.
  41.517 +
  41.518 +   This document and translations of it may be copied and furnished to
  41.519 +   others, and derivative works that comment on or otherwise explain it
  41.520 +   or assist in its implementation may be prepared, copied, published
  41.521 +   and distributed, in whole or in part, without restriction of any
  41.522 +   kind, provided that the above copyright notice and this paragraph are
  41.523 +   included on all such copies and derivative works.  However, this
  41.524 +   document itself may not be modified in any way, such as by removing
  41.525 +   the copyright notice or references to the Internet Society or other
  41.526 +   Internet organizations, except as needed for the purpose of
  41.527 +   developing Internet standards in which case the procedures for
  41.528 +   copyrights defined in the Internet Standards process must be
  41.529 +   followed, or as required to translate it into languages other than
  41.530 +   English.
  41.531 +
  41.532 +   The limited permissions granted above are perpetual and will not be
  41.533 +   revoked by the Internet Society or its successors or assigns.
  41.534 +
  41.535 +   This document and the information contained herein is provided on an
  41.536 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  41.537 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  41.538 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  41.539 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  41.540 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  41.541 +
  41.542 +
  41.543 +
  41.544 +
  41.545 +
  41.546 +
  41.547 +
  41.548 +
  41.549 +
  41.550 +
  41.551 +
  41.552 +
  41.553 +
  41.554 +
  41.555 +
  41.556 +
  41.557 +
  41.558 +
  41.559 +
  41.560 +
  41.561 +
  41.562 +
  41.563 +
  41.564 +
  41.565 +Gahrns & Newman             Standards Track                    [Page 10]
  41.566 +
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/docs/rfc/rfc2683.txt	Mon Sep 14 15:17:45 2009 +0900
    42.3 @@ -0,0 +1,1291 @@
    42.4 +
    42.5 +
    42.6 +
    42.7 +
    42.8 +
    42.9 +
   42.10 +Network Working Group                                           B. Leiba
   42.11 +Request for Comments: 2683               IBM T.J. Watson Research Center
   42.12 +Category: Informational                                   September 1999
   42.13 +
   42.14 +
   42.15 +                  IMAP4 Implementation Recommendations
   42.16 +
   42.17 +Status of this Memo
   42.18 +
   42.19 +   This memo provides information for the Internet community.  It does
   42.20 +   not specify an Internet standard of any kind.  Distribution of this
   42.21 +   memo is unlimited.
   42.22 +
   42.23 +Copyright Notice
   42.24 +
   42.25 +   Copyright (C) The Internet Society (1999).  All Rights Reserved.
   42.26 +
   42.27 +1. Abstract
   42.28 +
   42.29 +   The IMAP4 specification [RFC-2060] describes a rich protocol for use
   42.30 +   in building clients and servers for storage, retrieval, and
   42.31 +   manipulation of electronic mail.  Because the protocol is so rich and
   42.32 +   has so many implementation choices, there are often trade-offs that
   42.33 +   must be made and issues that must be considered when designing such
   42.34 +   clients and servers.  This document attempts to outline these issues
   42.35 +   and to make recommendations in order to make the end products as
   42.36 +   interoperable as possible.
   42.37 +
   42.38 +2. Conventions used in this document
   42.39 +
   42.40 +   In examples, "C:" indicates lines sent by a client that is connected
   42.41 +   to a server.  "S:" indicates lines sent by the server to the client.
   42.42 +
   42.43 +   The words "must", "must not", "should", "should not", and "may" are
   42.44 +   used with specific meaning in this document; since their meaning is
   42.45 +   somewhat different from that specified in RFC 2119, we do not put
   42.46 +   them in all caps here.  Their meaning is as follows:
   42.47 +
   42.48 +   must --       This word means that the action described is necessary
   42.49 +                 to ensure interoperability.  The recommendation should
   42.50 +                 not be ignored.
   42.51 +   must not --   This phrase means that the action described will be
   42.52 +                 almost certain to hurt interoperability.  The
   42.53 +                 recommendation should not be ignored.
   42.54 +
   42.55 +
   42.56 +
   42.57 +
   42.58 +
   42.59 +
   42.60 +
   42.61 +Leiba                        Informational                      [Page 1]
   42.62 +
   42.63 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
   42.64 +
   42.65 +
   42.66 +   should --     This word means that the action described is strongly
   42.67 +                 recommended and will enhance interoperability or
   42.68 +                 usability.  The recommendation should not be ignored
   42.69 +                 without careful consideration.
   42.70 +   should not -- This phrase means that the action described is strongly
   42.71 +                 recommended against, and might hurt interoperability or
   42.72 +                 usability.  The recommendation should not be ignored
   42.73 +                 without careful consideration.
   42.74 +   may --        This word means that the action described is an
   42.75 +                 acceptable implementation choice.  No specific
   42.76 +                 recommendation is implied; this word is used to point
   42.77 +                 out a choice that might not be obvious, or to let
   42.78 +                 implementors know what choices have been made by
   42.79 +                 existing implementations.
   42.80 +
   42.81 +3. Interoperability Issues and Recommendations
   42.82 +
   42.83 +3.1.   Accessibility
   42.84 +
   42.85 +   This section describes the issues related to access to servers and
   42.86 +   server resources.  Concerns here include data sharing and maintenance
   42.87 +   of client/server connections.
   42.88 +
   42.89 +3.1.1. Multiple Accesses of the Same Mailbox
   42.90 +
   42.91 +   One strong point of IMAP4 is that, unlike POP3, it allows for
   42.92 +   multiple simultaneous access to a single mailbox.  A user can, thus,
   42.93 +   read mail from a client at home while the client in the office is
   42.94 +   still connected; or the help desk staff can all work out of the same
   42.95 +   inbox, all seeing the same pool of questions.  An important point
   42.96 +   about this capability, though is that NO SERVER IS GUARANTEED TO
   42.97 +   SUPPORT THIS.  If you are selecting an IMAP server and this facility
   42.98 +   is important to you, be sure that the server you choose to install,
   42.99 +   in the configuration you choose to use, supports it.
  42.100 +
  42.101 +   If you are designing a client, you must not assume that you can
  42.102 +   access the same mailbox more than once at a time.  That means
  42.103 +
  42.104 +   1. you must handle gracefully the failure of a SELECT command if the
  42.105 +      server refuses the second SELECT,
  42.106 +   2. you must handle reasonably the severing of your connection (see
  42.107 +      "Severed Connections", below) if the server chooses to allow the
  42.108 +      second SELECT by forcing the first off,
  42.109 +   3. you must avoid making multiple connections to the same mailbox in
  42.110 +      your own client (for load balancing or other such reasons), and
  42.111 +   4. you must avoid using the STATUS command on a mailbox that you have
  42.112 +      selected (with some server implementations the STATUS command has
  42.113 +      the same problems with multiple access as do the SELECT and
  42.114 +
  42.115 +
  42.116 +
  42.117 +Leiba                        Informational                      [Page 2]
  42.118 +
  42.119 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.120 +
  42.121 +
  42.122 +      EXAMINE commands).
  42.123 +
  42.124 +   A further note about STATUS: The STATUS command is sometimes used to
  42.125 +   check a non-selected mailbox for new mail.  This mechanism must not
  42.126 +   be used to check for new mail in the selected mailbox; section 5.2 of
  42.127 +   [RFC-2060] specifically forbids this in its last paragraph.  Further,
  42.128 +   since STATUS takes a mailbox name it is an independent operation, not
  42.129 +   operating on the selected mailbox.  Because of this, the information
  42.130 +   it returns is not necessarily in synchronization with the selected
  42.131 +   mailbox state.
  42.132 +
  42.133 +3.1.2. Severed Connections
  42.134 +
  42.135 +   The client/server connection may be severed for one of three reasons:
  42.136 +   the client severs the connection, the server severs the connection,
  42.137 +   or the connection is severed by outside forces beyond the control of
  42.138 +   the client and the server (a telephone line drops, for example).
  42.139 +   Clients and servers must both deal with these situations.
  42.140 +
  42.141 +   When the client wants to sever a connection, it's usually because it
  42.142 +   has finished the work it needed to do on that connection.  The client
  42.143 +   should send a LOGOUT command, wait for the tagged response, and then
  42.144 +   close the socket.  But note that, while this is what's intended in
  42.145 +   the protocol design, there isn't universal agreement here.  Some
  42.146 +   contend that sending the LOGOUT and waiting for the two responses
  42.147 +   (untagged BYE and tagged OK) is wasteful and unnecessary, and that
  42.148 +   the client can simply close the socket.  The server should interpret
  42.149 +   the closed socket as a log out by the client.  The counterargument is
  42.150 +   that it's useful from the standpoint of cleanup, problem
  42.151 +   determination, and the like, to have an explicit client log out,
  42.152 +   because otherwise there is no way for the server to tell the
  42.153 +   difference between "closed socket because of log out" and "closed
  42.154 +   socket because communication was disrupted".  If there is a
  42.155 +   client/server interaction problem, a client which routinely
  42.156 +   terminates a session by breaking the connection without a LOGOUT will
  42.157 +   make it much more difficult to determine the problem.
  42.158 +
  42.159 +   Because of this disagreement, server designers must be aware that
  42.160 +   some clients might close the socket without sending a LOGOUT.  In any
  42.161 +   case, whether or not a LOGOUT was sent, the server should not
  42.162 +   implicitly expunge any messages from the selected mailbox.  If a
  42.163 +   client wants the server to do so, it must send a CLOSE or EXPUNGE
  42.164 +   command explicitly.
  42.165 +
  42.166 +   When the server wants to sever a connection it's usually due to an
  42.167 +   inactivity timeout or is because a situation has arisen that has
  42.168 +   changed the state of the mail store in a way that the server can not
  42.169 +   communicate to the client.  The server should send an untagged BYE
  42.170 +
  42.171 +
  42.172 +
  42.173 +Leiba                        Informational                      [Page 3]
  42.174 +
  42.175 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.176 +
  42.177 +
  42.178 +   response to the client and then close the socket.  Sending an
  42.179 +   untagged BYE response before severing allows the server to send a
  42.180 +   human-readable explanation of the problem to the client, which the
  42.181 +   client may then log, display to the user, or both (see section 7.1.5
  42.182 +   of [RFC-2060]).
  42.183 +
  42.184 +   Regarding inactivity timeouts, there is some controversy.  Unlike
  42.185 +   POP, for which the design is for a client to connect, retrieve mail,
  42.186 +   and log out, IMAP's design encourages long-lived (and mostly
  42.187 +   inactive) client/server sessions.  As the number of users grows, this
  42.188 +   can use up a lot of server resources, especially with clients that
  42.189 +   are designed to maintain sessions for mailboxes that the user has
  42.190 +   finished accessing.  To alleviate this, a server may implement an
  42.191 +   inactivity timeout, unilaterally closing a session (after first
  42.192 +   sending an untagged BYE, as noted above).  Some server operators have
  42.193 +   reported dramatic improvements in server performance after doing
  42.194 +   this.  As specified in [RFC-2060], if such a timeout is done it must
  42.195 +   not be until at least 30 minutes of inactivity.  The reason for this
  42.196 +   specification is to prevent clients from sending commands (such as
  42.197 +   NOOP) to the server at frequent intervals simply to avert a too-early
  42.198 +   timeout.  If the client knows that the server may not time out the
  42.199 +   session for at least 30 minutes, then the client need not poll at
  42.200 +   intervals more frequent than, say, 25 minutes.
  42.201 +
  42.202 +3.2.   Scaling
  42.203 +
  42.204 +   IMAP4 has many features that allow for scalability, as mail stores
  42.205 +   become larger and more numerous.  Large numbers of users, mailboxes,
  42.206 +   and messages, and very large messages require thought to handle
  42.207 +   efficiently.  This document will not address the administrative
  42.208 +   issues involved in large numbers of users, but we will look at the
  42.209 +   other items.
  42.210 +
  42.211 +3.2.1. Flood Control
  42.212 +
  42.213 +   There are three situations when a client can make a request that will
  42.214 +   result in a very large response - too large for the client reasonably
  42.215 +   to deal with: there are a great many mailboxes available, there are a
  42.216 +   great many messages in the selected mailbox, or there is a very large
  42.217 +   message part.  The danger here is that the end user will be stuck
  42.218 +   waiting while the server sends (and the client processes) an enormous
  42.219 +   response.  In all of these cases there are things a client can do to
  42.220 +   reduce that danger.
  42.221 +
  42.222 +   There is also the case where a client can flood a server, by sending
  42.223 +   an arbitratily long command.  We'll discuss that issue, too, in this
  42.224 +   section.
  42.225 +
  42.226 +
  42.227 +
  42.228 +
  42.229 +Leiba                        Informational                      [Page 4]
  42.230 +
  42.231 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.232 +
  42.233 +
  42.234 +3.2.1.1.  Listing Mailboxes
  42.235 +
  42.236 +   Some servers present Usenet newsgroups to IMAP users.  Newsgroups,
  42.237 +   and other such hierarchical mailbox structures, can be very numerous
  42.238 +   but may have only a few entries at the top level of hierarchy.  Also,
  42.239 +   some servers are built against mail stores that can, unbeknownst to
  42.240 +   the server, have circular hierarchies - that is, it's possible for
  42.241 +   "a/b/c/d" to resolve to the same file structure as "a", which would
  42.242 +   then mean that "a/b/c/d/b" is the same as "a/b", and the hierarchy
  42.243 +   will never end.  The LIST response in this case will be unlimited.
  42.244 +
  42.245 +   Clients that will have trouble with this are those that use
  42.246 +
  42.247 +       C: 001 LIST "" *
  42.248 +
  42.249 +   to determine the mailbox list.  Because of this, clients should not
  42.250 +   use an unqualified "*" that way in the LIST command.  A safer
  42.251 +   approach is to list each level of hierarchy individually, allowing
  42.252 +   the user to traverse the tree one limb at a time, thus:
  42.253 +
  42.254 +       C: 001 LIST "" %
  42.255 +       S: * LIST () "/" Banana
  42.256 +       S: * LIST ...etc...
  42.257 +       S: 001 OK done
  42.258 +
  42.259 +   and then
  42.260 +
  42.261 +       C: 002 LIST "" Banana/%
  42.262 +       S: * LIST () "/" Banana/Apple
  42.263 +       S: * LIST ...etc...
  42.264 +       S: 002 OK done
  42.265 +
  42.266 +   Using this technique the client's user interface can give the user
  42.267 +   full flexibility without choking on the voluminous reply to "LIST *".
  42.268 +
  42.269 +   Of course, it is still possible that the reply to
  42.270 +
  42.271 +       C: 005 LIST "" alt.fan.celebrity.%
  42.272 +
  42.273 +   may be thousands of entries long, and there is, unfortunately,
  42.274 +   nothing the client can do to protect itself from that.  This has not
  42.275 +   yet been a notable problem.
  42.276 +
  42.277 +   Servers that may export circular hierarchies (any server that
  42.278 +   directly presents a UNIX file system, for instance) should limit the
  42.279 +   hierarchy depth to prevent unlimited LIST responses.  A suggested
  42.280 +   depth limit is 20 hierarchy levels.
  42.281 +
  42.282 +
  42.283 +
  42.284 +
  42.285 +Leiba                        Informational                      [Page 5]
  42.286 +
  42.287 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.288 +
  42.289 +
  42.290 +3.2.1.2.  Fetching the List of Messages
  42.291 +
  42.292 +   When a client selects a mailbox, it is given a count, in the untagged
  42.293 +   EXISTS response, of the messages in the mailbox.  This number can be
  42.294 +   very large.  In such a case it might be unwise to use
  42.295 +
  42.296 +       C: 004 FETCH 1:* ALL
  42.297 +
  42.298 +   to populate the user's view of the mailbox.  One good method to avoid
  42.299 +   problems with this is to batch the requests, thus:
  42.300 +
  42.301 +       C: 004 FETCH 1:50 ALL
  42.302 +       S: * 1 FETCH ...etc...
  42.303 +       S: 004 OK done
  42.304 +       C: 005 FETCH 51:100 ALL
  42.305 +       S: * 51 FETCH ...etc...
  42.306 +       S: 005 OK done
  42.307 +       C: 006 FETCH 101:150 ALL
  42.308 +       ...etc...
  42.309 +
  42.310 +   Using this method, another command, such as "FETCH 6 BODY[1]" can be
  42.311 +   inserted as necessary, and the client will not have its access to the
  42.312 +   server blocked by a storm of FETCH replies.  (Such a method could be
  42.313 +   reversed to fetch the LAST 50 messages first, then the 50 prior to
  42.314 +   that, and so on.)
  42.315 +
  42.316 +   As a smart extension of this, a well designed client, prepared for
  42.317 +   very large mailboxes, will not automatically fetch data for all
  42.318 +   messages AT ALL.  Rather, the client will populate the user's view
  42.319 +   only as the user sees it, possibly pre-fetching selected information,
  42.320 +   and only fetching other information as the user scrolls to it.  For
  42.321 +   example, to select only those messages beginning with the first
  42.322 +   unseen one:
  42.323 +
  42.324 +       C: 003 SELECT INBOX
  42.325 +       S: * 10000 EXISTS
  42.326 +       S: * 80 RECENT
  42.327 +       S: * FLAGS (\Answered \Flagged \Deleted \Draft \Seen)
  42.328 +       S: * OK [UIDVALIDITY 824708485] UID validity status
  42.329 +       S: * OK [UNSEEN 9921] First unseen message
  42.330 +       S: 003 OK [READ-WRITE] SELECT completed
  42.331 +       C: 004 FETCH 9921:* ALL
  42.332 +       ... etc...
  42.333 +
  42.334 +   If the server does not return an OK [UNSEEN] response, the client may
  42.335 +   use SEARCH UNSEEN to obtain that value.
  42.336 +
  42.337 +
  42.338 +
  42.339 +
  42.340 +
  42.341 +Leiba                        Informational                      [Page 6]
  42.342 +
  42.343 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.344 +
  42.345 +
  42.346 +   This mechanism is good as a default presentation method, but only
  42.347 +   works well if the default message order is acceptable.  A client may
  42.348 +   want to present various sort orders to the user (by subject, by date
  42.349 +   sent, by sender, and so on) and in that case (lacking a SORT
  42.350 +   extension on the server side) the client WILL have to retrieve all
  42.351 +   message descriptors.  A client that provides this service should not
  42.352 +   do it by default and should inform the user of the costs of choosing
  42.353 +   this option for large mailboxes.
  42.354 +
  42.355 +3.2.1.3.  Fetching a Large Body Part
  42.356 +
  42.357 +   The issue here is similar to the one for a list of messages.  In the
  42.358 +   BODYSTRUCTURE response the client knows the size, in bytes, of the
  42.359 +   body part it plans to fetch.  Suppose this is a 70 MB video clip. The
  42.360 +   client can use partial fetches to retrieve the body part in pieces,
  42.361 +   avoiding the problem of an uninterruptible 70 MB literal coming back
  42.362 +   from the server:
  42.363 +
  42.364 +       C: 022 FETCH 3 BODY[1]<0.20000>
  42.365 +       S: * 3 FETCH (FLAGS(\Seen) BODY[1]<0> {20000}
  42.366 +       S: ...data...)
  42.367 +       S: 022 OK done
  42.368 +       C: 023 FETCH 3 BODY[1]<20001.20000>
  42.369 +       S: * 3 FETCH (BODY[1]<20001> {20000}
  42.370 +       S: ...data...)
  42.371 +       S: 023 OK done
  42.372 +       C: 024 FETCH 3 BODY[1]<40001.20000>
  42.373 +       ...etc...
  42.374 +
  42.375 +3.2.1.4.  BODYSTRUCTURE vs. Entire Messages
  42.376 +
  42.377 +   Because FETCH BODYSTRUCTURE is necessary in order to determine the
  42.378 +   number of body parts, and, thus, whether a message has "attachments",
  42.379 +   clients often use FETCH FULL as their normal method of populating the
  42.380 +   user's view of a mailbox.  The benefit is that the client can display
  42.381 +   a paperclip icon or some such indication along with the normal
  42.382 +   message summary.  However, this comes at a significant cost with some
  42.383 +   server configurations.  The parsing needed to generate the FETCH
  42.384 +   BODYSTRUCTURE response may be time-consuming compared with that
  42.385 +   needed for FETCH ENVELOPE.  The client developer should consider this
  42.386 +   issue when deciding whether the ability to add a paperclip icon is
  42.387 +   worth the tradeoff in performance, especially with large mailboxes.
  42.388 +
  42.389 +   Some clients, rather than using FETCH BODYSTRUCTURE, use FETCH BODY[]
  42.390 +   (or the equivalent FETCH RFC822) to retrieve the entire message.
  42.391 +   They then do the MIME parsing in the client.  This may give the
  42.392 +   client slightly more flexibility in some areas (access, for instance,
  42.393 +   to header fields that aren't returned in the BODYSTRUCTURE and
  42.394 +
  42.395 +
  42.396 +
  42.397 +Leiba                        Informational                      [Page 7]
  42.398 +
  42.399 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.400 +
  42.401 +
  42.402 +   ENVELOPE responses), but it can cause severe performance problems by
  42.403 +   forcing the transfer of all body parts when the user might only want
  42.404 +   to see some of them - a user logged on by modem and reading a small
  42.405 +   text message with a large ZIP file attached may prefer to read the
  42.406 +   text only and save the ZIP file for later.  Therefore, a client
  42.407 +   should not normally retrieve entire messages and should retrieve
  42.408 +   message body parts selectively.
  42.409 +
  42.410 +3.2.1.5.  Long Command Lines
  42.411 +
  42.412 +   A client can wind up building a very long command line in an effort to
  42.413 +   try to be efficient about requesting information from a server.  This
  42.414 +   can typically happen when a client builds a message set from selected
  42.415 +   messages and doesn't recognise that contiguous blocks of messages may
  42.416 +   be group in a range.  Suppose a user selects all 10,000 messages in a
  42.417 +   large mailbox and then unselects message 287.  The client could build
  42.418 +   that message set as "1:286,288:10000", but a client that doesn't
  42.419 +   handle that might try to enumerate each message individually and build
  42.420 +   "1,2,3,4, [and so on] ,9999,10000".  Adding that to the fetch command
  42.421 +   results in a command line that's almost 49,000 octets long, and,
  42.422 +   clearly, one can construct a command line that's even longer.
  42.423 +
  42.424 +   A client should limit the length of the command lines it generates to
  42.425 +   approximately 1000 octets (including all quoted strings but not
  42.426 +   including literals).  If the client is unable to group things into
  42.427 +   ranges so that the command line is within that length, it should
  42.428 +   split the request into multiple commands.  The client should use
  42.429 +   literals instead of long quoted strings, in order to keep the command
  42.430 +   length down.
  42.431 +
  42.432 +   For its part, a server should allow for a command line of at least
  42.433 +   8000 octets.  This provides plenty of leeway for accepting reasonable
  42.434 +   length commands from clients.  The server should send a BAD response
  42.435 +   to a command that does not end within the server's maximum accepted
  42.436 +   command length.
  42.437 +
  42.438 +3.2.2. Subscriptions
  42.439 +
  42.440 +   The client isn't the only entity that can get flooded: the end user,
  42.441 +   too, may need some flood control.  The IMAP4 protocol provides such
  42.442 +   control in the form of subscriptions.  Most servers support the
  42.443 +   SUBSCRIBE, UNSUBSCRIBE, and LSUB commands, and many users choose to
  42.444 +   narrow down a large list of available mailboxes by subscribing to the
  42.445 +   ones that they usually want to see.  Clients, with this in mind,
  42.446 +   should give the user a way to see only subscribed mailboxes.  A
  42.447 +   client that never uses the LSUB command takes a significant usability
  42.448 +   feature away from the user.  Of course, the client would not want to
  42.449 +   hide the LIST command completely; the user needs to have a way to
  42.450 +
  42.451 +
  42.452 +
  42.453 +Leiba                        Informational                      [Page 8]
  42.454 +
  42.455 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.456 +
  42.457 +
  42.458 +   choose between LIST and LSUB.  The usual way to do this is to provide
  42.459 +   a setting like "show which mailboxes?:  [] all  [] subscribed only".
  42.460 +
  42.461 +3.2.3. Searching
  42.462 +
  42.463 +   IMAP SEARCH commands can become particularly troublesome (that is,
  42.464 +   slow) on mailboxes containing a large number of messages.  So let's
  42.465 +   put a few things in perspective in that regard.
  42.466 +
  42.467 +   The flag searches should be fast.  The flag searches (ALL, [UN]SEEN,
  42.468 +   [UN]ANSWERED, [UN]DELETED, [UN]DRAFT, [UN]FLAGGED, NEW, OLD, RECENT)
  42.469 +   are known to be used by clients for the client's own use (for
  42.470 +   instance, some clients use "SEARCH UNSEEN" to find unseen mail and
  42.471 +   "SEARCH DELETED" to warn the user before expunging messages).
  42.472 +
  42.473 +   Other searches, particularly the text searches (HEADER, TEXT, BODY)
  42.474 +   are initiated by the user, rather than by the client itself, and
  42.475 +   somewhat slower performance can be tolerated, since the user is aware
  42.476 +   that the search is being done (and is probably aware that it might be
  42.477 +   time-consuming).  A smart server might use dynamic indexing to speed
  42.478 +   commonly used text searches.
  42.479 +
  42.480 +   The client may allow other commands to be sent to the server while a
  42.481 +   SEARCH is in progress, but at the time of this writing there is
  42.482 +   little or no server support for parallel processing of multiple
  42.483 +   commands in the same session (and see "Multiple Accesses of the Same
  42.484 +   Mailbox" above for a description of the dangers of trying to work
  42.485 +   around this by doing your SEARCH in another session).
  42.486 +
  42.487 +   Another word about text searches: some servers, built on database
  42.488 +   back-ends with indexed search capabilities, may return search results
  42.489 +   that do not match the IMAP spec's "case-insensitive substring"
  42.490 +   requirements.  While these servers are in violation of the protocol,
  42.491 +   there is little harm in the violation as long as the search results
  42.492 +   are used only in response to a user's request.  Still, developers of
  42.493 +   such servers should be aware that they ARE violating the protocol,
  42.494 +   should think carefully about that behaviour, and must be certain that
  42.495 +   their servers respond accurately to the flag searches for the reasons
  42.496 +   outlined above.
  42.497 +
  42.498 +   In addition, servers should support CHARSET UTF-8 [UTF-8] in
  42.499 +   searches.
  42.500 +
  42.501 +
  42.502 +
  42.503 +
  42.504 +
  42.505 +
  42.506 +
  42.507 +
  42.508 +
  42.509 +Leiba                        Informational                      [Page 9]
  42.510 +
  42.511 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.512 +
  42.513 +
  42.514 +3.3    Avoiding Invalid Requests
  42.515 +
  42.516 +   IMAP4 provides ways for a server to tell a client in advance what is
  42.517 +   and isn't permitted in some circumstances.  Clients should use these
  42.518 +   features to avoid sending requests that a well designed client would
  42.519 +   know to be invalid.  This section explains this in more detail.
  42.520 +
  42.521 +3.3.1. The CAPABILITY Command
  42.522 +
  42.523 +   All IMAP4 clients should use the CAPABILITY command to determine what
  42.524 +   version of IMAP and what optional features a server supports.  The
  42.525 +   client should not send IMAP4rev1 commands and arguments to a server
  42.526 +   that does not advertize IMAP4rev1 in its CAPABILITY response.
  42.527 +   Similarly, the client should not send IMAP4 commands that no longer
  42.528 +   exist in IMAP4rev1 to a server that does not advertize IMAP4 in its
  42.529 +   CAPABILITY response.  An IMAP4rev1 server is NOT required to support
  42.530 +   obsolete IMAP4 or IMAP2bis commands (though some do; do not let this
  42.531 +   fact lull you into thinking that it's valid to send such commands to
  42.532 +   an IMAP4rev1 server).
  42.533 +
  42.534 +   A client should not send commands to probe for the existance of
  42.535 +   certain extensions.  All standard and standards-track extensions
  42.536 +   include CAPABILITY tokens indicating their presense.  All private and
  42.537 +   experimental extensions should do the same, and clients that take
  42.538 +   advantage of them should use the CAPABILITY response to determine
  42.539 +   whether they may be used or not.
  42.540 +
  42.541 +3.3.2. Don't Do What the Server Says You Can't
  42.542 +
  42.543 +   In many cases, the server, in response to a command, will tell the
  42.544 +   client something about what can and can't be done with a particular
  42.545 +   mailbox.  The client should pay attention to this information and
  42.546 +   should not try to do things that it's been told it can't do.
  42.547 +
  42.548 +   Examples:
  42.549 +
  42.550 +   *  Do not try to SELECT a mailbox that has the \Noselect flag set.
  42.551 +   *  Do not try to CREATE a sub-mailbox in a mailbox that has the
  42.552 +      \Noinferiors flag set.
  42.553 +   *  Do not respond to a failing COPY or APPEND command by trying to
  42.554 +      CREATE the target mailbox if the server does not respond with a
  42.555 +      [TRYCREATE] response code.
  42.556 +   *  Do not try to expunge a mailbox that has been selected with the
  42.557 +      [READ-ONLY] response code.
  42.558 +
  42.559 +
  42.560 +
  42.561 +
  42.562 +
  42.563 +
  42.564 +
  42.565 +Leiba                        Informational                     [Page 10]
  42.566 +
  42.567 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.568 +
  42.569 +
  42.570 +3.4.   Miscellaneous Protocol Considerations
  42.571 +
  42.572 +   We describe here a number of important protocol-related issues, the
  42.573 +   misunderstanding of which has caused significant interoperability
  42.574 +   problems in IMAP4 implementations.  One general item is that every
  42.575 +   implementer should be certain to take note of and to understand
  42.576 +   section 2.2.2 and the preamble to section 7 of the IMAP4rev1 spec
  42.577 +   [RFC-2060].
  42.578 +
  42.579 +3.4.1. Well Formed Protocol
  42.580 +
  42.581 +   We cannot stress enough the importance of adhering strictly to the
  42.582 +   protocol grammar.  The specification of the protocol is quite rigid;
  42.583 +   do not assume that you can insert blank space for "readability" if
  42.584 +   none is called for.  Keep in mind that there are parsers out there
  42.585 +   that will crash if there are protocol errors.  There are clients that
  42.586 +   will report every parser burp to the user.  And in any case,
  42.587 +   information that cannot be parsed is information that is lost.  Be
  42.588 +   careful in your protocol generation.  And see "A Word About Testing",
  42.589 +   below.
  42.590 +
  42.591 +   In particular, note that the string in the INTERNALDATE response is
  42.592 +   NOT an RFC-822 date string - that is, it is not in the same format as
  42.593 +   the first string in the ENVELOPE response.  Since most clients will,
  42.594 +   in fact, accept an RFC-822 date string in the INTERNALDATE response,
  42.595 +   it's easy to miss this in your interoperability testing.  But it will
  42.596 +   cause a problem with some client, so be sure to generate the correct
  42.597 +   string for this field.
  42.598 +
  42.599 +3.4.2. Special Characters
  42.600 +
  42.601 +   Certain characters, currently the double-quote and the backslash, may
  42.602 +   not be sent as-is inside a quoted string.  These characters must be
  42.603 +   preceded by the escape character if they are in a quoted string, or
  42.604 +   else the string must be sent as a literal.  Both clients and servers
  42.605 +   must handle this, both on output (they must send these characters
  42.606 +   properly) and on input (they must be able to receive escaped
  42.607 +   characters in quoted strings).  Example:
  42.608 +
  42.609 +       C: 001 LIST "" %
  42.610 +       S: * LIST () "" INBOX
  42.611 +       S: * LIST () "\\" TEST
  42.612 +       S: * LIST () "\\" {12}
  42.613 +       S: "My" mailbox
  42.614 +       S: 001 OK done
  42.615 +       C: 002 LIST "" "\"My\" mailbox\\%"
  42.616 +       S: * LIST () "\\" {17}
  42.617 +       S: "My" mailbox\Junk
  42.618 +
  42.619 +
  42.620 +
  42.621 +Leiba                        Informational                     [Page 11]
  42.622 +
  42.623 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.624 +
  42.625 +
  42.626 +       S: 002 OK done
  42.627 +
  42.628 +   Note that in the example the server sent the hierarchy delimiter as
  42.629 +   an escaped character in the quoted string and sent the mailbox name
  42.630 +   containing imbedded double-quotes as a literal.  The client used only
  42.631 +   quoted strings, escaping both the backslash and the double-quote
  42.632 +   characters.
  42.633 +
  42.634 +   The CR and LF characters may be sent ONLY in literals; they are not
  42.635 +   allowed, even if escaped, inside quoted strings.
  42.636 +
  42.637 +   And while we're talking about special characters: the IMAP spec, in
  42.638 +   the section titled "Mailbox International Naming Convention",
  42.639 +   describes how to encode mailbox names in modified UTF-7 [UTF-7 and
  42.640 +   RFC-2060].  Implementations must adhere to this in order to be
  42.641 +   interoperable in the international market, and servers should
  42.642 +   validate mailbox names sent by client and reject names that do not
  42.643 +   conform.
  42.644 +
  42.645 +   As to special characters in userids and passwords: clients must not
  42.646 +   restrict what a user may type in for a userid or a password.  The
  42.647 +   formal grammar specifies that these are "astrings", and an astring
  42.648 +   can be a literal.  A literal, in turn can contain any 8-bit
  42.649 +   character, and clients must allow users to enter all 8-bit characters
  42.650 +   here, and must pass them, unchanged, to the server (being careful to
  42.651 +   send them as literals when necessary).  In particular, some server
  42.652 +   configurations use "@" in user names, and some clients do not allow
  42.653 +   that character to be entered; this creates a severe interoperability
  42.654 +   problem.
  42.655 +
  42.656 +3.4.3. UIDs and UIDVALIDITY
  42.657 +
  42.658 +   Servers that support existing back-end mail stores often have no good
  42.659 +   place to save UIDs for messages.  Often the existing mail store will
  42.660 +   not have the concept of UIDs in the sense that IMAP has: strictly
  42.661 +   increasing, never re-issued, 32-bit integers.  Some servers solve
  42.662 +   this by storing the UIDs in a place that's accessible to end users,
  42.663 +   allowing for the possibility that the users will delete them.  Others
  42.664 +   solve it by re-assigning UIDs every time a mailbox is selected.
  42.665 +
  42.666 +   The server should maintain UIDs permanently for all messages if it
  42.667 +   can.  If that's not possible, the server must change the UIDVALIDITY
  42.668 +   value for the mailbox whenever any of the UIDs may have become
  42.669 +   invalid.  Clients must recognize that the UIDVALIDITY has changed and
  42.670 +   must respond to that condition by throwing away any information that
  42.671 +   they have saved about UIDs in that mailbox.  There have been many
  42.672 +   problems in this area when clients have failed to do this; in the
  42.673 +   worst case it will result in loss of mail when a client deletes the
  42.674 +
  42.675 +
  42.676 +
  42.677 +Leiba                        Informational                     [Page 12]
  42.678 +
  42.679 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.680 +
  42.681 +
  42.682 +   wrong piece of mail by using a stale UID.
  42.683 +
  42.684 +   It seems to be a common misunderstanding that "the UIDVALIDITY and
  42.685 +   the UID, taken together, form a 64-bit identifier that uniquely
  42.686 +   identifies a message on a server".  This is absolutely NOT TRUE.
  42.687 +   There is no assurance that the UIDVALIDITY values of two mailboxes be
  42.688 +   different, so the UIDVALIDITY in no way identifies a mailbox.  The
  42.689 +   ONLY purpose of UIDVALIDITY is, as its name indicates, to give the
  42.690 +   client a way to check the validity of the UIDs it has cached.  While
  42.691 +   it is a valid implementation choice to put these values together to
  42.692 +   make a 64-bit identifier for the message, the important concept here
  42.693 +   is that UIDs are not unique between mailboxes; they are only unique
  42.694 +   WITHIN a given mailbox.
  42.695 +
  42.696 +   Some server implementations have attempted to make UIDs unique across
  42.697 +   the entire server.  This is inadvisable, in that it limits the life
  42.698 +   of UIDs unnecessarily.  The UID is a 32-bit number and will run out
  42.699 +   in reasonably finite time if it's global across the server.  If you
  42.700 +   assign UIDs sequentially in one mailbox, you will not have to start
  42.701 +   re-using them until you have had, at one time or another, 2**32
  42.702 +   different messages in that mailbox.  In the global case, you will
  42.703 +   have to reuse them once you have had, at one time or another, 2**32
  42.704 +   different messages in the entire mail store.  Suppose your server has
  42.705 +   around 8000 users registered (2**13).  That gives an average of 2**19
  42.706 +   UIDs per user.  Suppose each user gets 32 messages (2**5) per day.
  42.707 +   That gives you 2**14 days (16000+ days = about 45 years) before you
  42.708 +   run out.  That may seem like enough, but multiply the usage just a
  42.709 +   little (a lot of spam, a lot of mailing list subscriptions, more
  42.710 +   users) and you limit yourself too much.
  42.711 +
  42.712 +   What's worse is that if you have to wrap the UIDs, and, thus, you
  42.713 +   have to change UIDVALIDITY and invalidate the UIDs in the mailbox,
  42.714 +   you have to do it for EVERY mailbox in the system, since they all
  42.715 +   share the same UID pool.  If you assign UIDs per mailbox and you have
  42.716 +   a problem, you only have to kill the UIDs for that one mailbox.
  42.717 +
  42.718 +   Under extreme circumstances (and this is extreme, indeed), the server
  42.719 +   may have to invalidate UIDs while a mailbox is in use by a client -
  42.720 +   that is, the UIDs that the client knows about in its active mailbox
  42.721 +   are no longer valid.  In that case, the server must immediately
  42.722 +   change the UIDVALIDITY and must communicate this to the client.  The
  42.723 +   server may do this by sending an unsolicited UIDVALIDITY message, in
  42.724 +   the same form as in response to the SELECT command.  Clients must be
  42.725 +   prepared to handle such a message and the possibly coincident failure
  42.726 +   of the command in process.  For example:
  42.727 +
  42.728 +
  42.729 +
  42.730 +
  42.731 +
  42.732 +
  42.733 +Leiba                        Informational                     [Page 13]
  42.734 +
  42.735 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.736 +
  42.737 +
  42.738 +       C: 032 UID STORE 382 +Flags.silent \Deleted
  42.739 +       S: * OK [UIDVALIDITY 12345] New UIDVALIDITY value!
  42.740 +       S: 032 NO UID command rejected because UIDVALIDITY changed!
  42.741 +       C: ...invalidates local information and re-fetches...
  42.742 +       C: 033 FETCH 1:* UID
  42.743 +       ...etc...
  42.744 +
  42.745 +   At the time of the writing of this document, the only server known to
  42.746 +   do this does so only under the following condition: the client
  42.747 +   selects INBOX, but there is not yet a physical INBOX file created.
  42.748 +   Nonetheless, the SELECT succeeds, exporting an empty INBOX with a
  42.749 +   temporary UIDVALIDITY of 1.  While the INBOX remains selected, mail
  42.750 +   is delivered to the user, which creates the real INBOX file and
  42.751 +   assigns a permanent UIDVALIDITY (that is likely not to be 1).  The
  42.752 +   server reports the change of UIDVALIDITY, but as there were no
  42.753 +   messages before, so no UIDs have actually changed, all the client
  42.754 +   must do is accept the change in UIDVALIDITY.
  42.755 +
  42.756 +   Alternatively, a server may force the client to re-select the
  42.757 +   mailbox, at which time it will obtain a new UIDVALIDITY value.  To do
  42.758 +   this, the server closes this client session (see "Severed
  42.759 +   Connections" above) and the client then reconnects and gets back in
  42.760 +   synch.  Clients must be prepared for either of these behaviours.
  42.761 +
  42.762 +   We do not know of, nor do we anticipate the future existance of, a
  42.763 +   server that changes UIDVALIDITY while there are existing messages,
  42.764 +   but clients must be prepared to handle this eventuality.
  42.765 +
  42.766 +3.4.4. FETCH Responses
  42.767 +
  42.768 +   When a client asks for certain information in a FETCH command, the
  42.769 +   server may return the requested information in any order, not
  42.770 +   necessarily in the order that it was requested.  Further, the server
  42.771 +   may return the information in separate FETCH responses and may also
  42.772 +   return information that was not explicitly requested (to reflect to
  42.773 +   the client changes in the state of the subject message).  Some
  42.774 +   examples:
  42.775 +
  42.776 +       C: 001 FETCH 1 UID FLAGS INTERNALDATE
  42.777 +       S: * 5 FETCH (FLAGS (\Deleted))
  42.778 +       S: * 1 FETCH (FLAGS (\Seen) INTERNALDATE "..." UID 345)
  42.779 +       S: 001 OK done
  42.780 +
  42.781 +   (In this case, the responses are in a different order.  Also, the
  42.782 +   server returned a flag update for message 5, which wasn't part of the
  42.783 +   client's request.)
  42.784 +
  42.785 +
  42.786 +
  42.787 +
  42.788 +
  42.789 +Leiba                        Informational                     [Page 14]
  42.790 +
  42.791 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.792 +
  42.793 +
  42.794 +       C: 002 FETCH 2 UID FLAGS INTERNALDATE
  42.795 +       S: * 2 FETCH (INTERNALDATE "...")
  42.796 +       S: * 2 FETCH (UID 399)
  42.797 +       S: * 2 FETCH (FLAGS ())
  42.798 +       S: 002 OK done
  42.799 +
  42.800 +   (In this case, the responses are in a different order and were
  42.801 +   returned in separate responses.)
  42.802 +
  42.803 +       C: 003 FETCH 2 BODY[1]
  42.804 +       S: * 2 FETCH (FLAGS (\Seen) BODY[1] {14}
  42.805 +       S: Hello world!
  42.806 +       S: )
  42.807 +       S: 003 OK done
  42.808 +
  42.809 +   (In this case, the FLAGS response was added by the server, since
  42.810 +   fetching the body part caused the server to set the \Seen flag.)
  42.811 +
  42.812 +   Because of this characteristic a client must be ready to receive any
  42.813 +   FETCH response at any time and should use that information to update
  42.814 +   its local information about the message to which the FETCH response
  42.815 +   refers.  A client must not assume that any FETCH responses will come
  42.816 +   in any particular order, or even that any will come at all.  If after
  42.817 +   receiving the tagged response for a FETCH command the client finds
  42.818 +   that it did not get all of the information requested, the client
  42.819 +   should send a NOOP command to the server to ensure that the server
  42.820 +   has an opportunity to send any pending EXPUNGE responses to the
  42.821 +   client (see [RFC-2180]).
  42.822 +
  42.823 +3.4.5. RFC822.SIZE
  42.824 +
  42.825 +   Some back-end mail stores keep the mail in a canonical form, rather
  42.826 +   than retaining the original MIME format of the messages.  This means
  42.827 +   that the server must reassemble the message to produce a MIME stream
  42.828 +   when a client does a fetch such as RFC822 or BODY[], requesting the
  42.829 +   entire message.  It also may mean that the server has no convenient
  42.830 +   way to know the RFC822.SIZE of the message.  Often, such a server
  42.831 +   will actually have to build the MIME stream to compute the size, only
  42.832 +   to throw the stream away and report the size to the client.
  42.833 +
  42.834 +   When this is the case, some servers have chosen to estimate the size,
  42.835 +   rather than to compute it precisely.  Such an estimate allows the
  42.836 +   client to display an approximate size to the user and to use the
  42.837 +   estimate in flood control considerations (q.v.), but requires that
  42.838 +   the client not use the size for things such as allocation of buffers,
  42.839 +   because those buffers might then be too small to hold the actual MIME
  42.840 +   stream.  Instead, a client should use the size that's returned in the
  42.841 +   literal when you fetch the data.
  42.842 +
  42.843 +
  42.844 +
  42.845 +Leiba                        Informational                     [Page 15]
  42.846 +
  42.847 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.848 +
  42.849 +
  42.850 +   The protocol requires that the RFC822.SIZE value returned by the
  42.851 +   server be EXACT.  Estimating the size is a protocol violation, and
  42.852 +   server designers must be aware that, despite the performance savings
  42.853 +   they might realize in using an estimate, this practice will cause
  42.854 +   some clients to fail in various ways.  If possible, the server should
  42.855 +   compute the RFC822.SIZE for a particular message once, and then save
  42.856 +   it for later retrieval.  If that's not possible, the server must
  42.857 +   compute the value exactly every time.  Incorrect estimates do cause
  42.858 +   severe interoperability problems with some clients.
  42.859 +
  42.860 +3.4.6. Expunged Messages
  42.861 +
  42.862 +   If the server allows multiple connections to the same mailbox, it is
  42.863 +   often possible for messages to be expunged in one client unbeknownst
  42.864 +   to another client.  Since the server is not allowed to tell the
  42.865 +   client about these expunged messages in response to a FETCH command,
  42.866 +   the server may have to deal with the issue of how to return
  42.867 +   information about an expunged message.  There was extensive
  42.868 +   discussion about this issue, and the results of that discussion are
  42.869 +   summarized in [RFC-2180].  See that reference for a detailed
  42.870 +   explanation and for recommendations.
  42.871 +
  42.872 +3.4.7. The Namespace Issue
  42.873 +
  42.874 +   Namespaces are a very muddy area in IMAP4 implementation right now
  42.875 +   (see [NAMESPACE] for a proposal to clear the water a bit).  Until the
  42.876 +   issue is resolved, the important thing for client developers to
  42.877 +   understand is that some servers provide access through IMAP to more
  42.878 +   than just the user's personal mailboxes, and, in fact, the user's
  42.879 +   personal mailboxes may be "hidden" somewhere in the user's default
  42.880 +   hierarchy.  The client, therefore, should provide a setting wherein
  42.881 +   the user can specify a prefix to be used when accessing mailboxes. If
  42.882 +   the user's mailboxes are all in "~/mail/", for instance, then the
  42.883 +   user can put that string in the prefix.  The client would then put
  42.884 +   the prefix in front of any name pattern in the LIST and LSUB
  42.885 +   commands:
  42.886 +
  42.887 +       C: 001 LIST "" ~/mail/%
  42.888 +
  42.889 +   (See also "Reference Names in the LIST Command" below.)
  42.890 +
  42.891 +3.4.8. Creating Special-Use Mailboxes
  42.892 +
  42.893 +   It may seem at first that this is part of the namespace issue; it is
  42.894 +   not, and is only indirectly related to it.  A number of clients like
  42.895 +   to create special-use mailboxes with particular names.  Most
  42.896 +   commonly, clients with a "trash folder" model of message deletion
  42.897 +   want to create a mailbox with the name "Trash" or "Deleted".  Some
  42.898 +
  42.899 +
  42.900 +
  42.901 +Leiba                        Informational                     [Page 16]
  42.902 +
  42.903 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.904 +
  42.905 +
  42.906 +   clients want to create a "Drafts" mailbox, an "Outbox" mailbox, or a
  42.907 +   "Sent Mail" mailbox.  And so on.  There are two major
  42.908 +   interoperability problems with this practice:
  42.909 +
  42.910 +   1. different clients may use different names for mailboxes with
  42.911 +      similar functions (such as "Trash" and "Deleted"), or may manage
  42.912 +      the same mailboxes in different ways, causing problems if a user
  42.913 +      switches between clients and
  42.914 +   2. there is no guarantee that the server will allow the creation of
  42.915 +      the desired mailbox.
  42.916 +
  42.917 +   The client developer is, therefore, well advised to consider
  42.918 +   carefully the creation of any special-use mailboxes on the server,
  42.919 +   and, further, the client must not require such mailbox creation -
  42.920 +   that is, if you do decide to do this, you must handle gracefully the
  42.921 +   failure of the CREATE command and behave reasonably when your
  42.922 +   special-use mailboxes do not exist and can not be created.
  42.923 +
  42.924 +   In addition, the client developer should provide a convenient way for
  42.925 +   the user to select the names for any special-use mailboxes, allowing
  42.926 +   the user to make these names the same in all clients used and to put
  42.927 +   them where the user wants them.
  42.928 +
  42.929 +3.4.9. Reference Names in the LIST Command
  42.930 +
  42.931 +   Many implementers of both clients and servers are confused by the
  42.932 +   "reference name" on the LIST command.  The reference name is intended
  42.933 +   to be used in much the way a "cd" (change directory) command is used
  42.934 +   on Unix, PC DOS, Windows, and OS/2 systems.  That is, the mailbox
  42.935 +   name is interpreted in much the same way as a file of that name would
  42.936 +   be found if one had done a "cd" command into the directory specified
  42.937 +   by the reference name.  For example, in Unix we have the following:
  42.938 +
  42.939 +       > cd /u/jones/junk
  42.940 +       > vi banana        [file is "/u/jones/junk/banana"]
  42.941 +       > vi stuff/banana  [file is "/u/jones/junk/stuff/banana"]
  42.942 +       > vi /etc/hosts    [file is "/etc/hosts"]
  42.943 +
  42.944 +   In the past, there have been several interoperability problems with
  42.945 +   this.  First, while some IMAP servers are built on Unix or PC file
  42.946 +   systems, many others are not, and the file system semantics do not
  42.947 +   make sense in those configurations.  Second, while some IMAP servers
  42.948 +   expose the underlying file system to the clients, others allow access
  42.949 +   only to the user's personal mailboxes, or to some other limited set
  42.950 +   of files, making such file-system-like semantics less meaningful.
  42.951 +   Third, because the IMAP spec leaves the interpretation of the
  42.952 +   reference name as "implementation-dependent", in the past the various
  42.953 +   server implementations handled it in vastly differing ways.
  42.954 +
  42.955 +
  42.956 +
  42.957 +Leiba                        Informational                     [Page 17]
  42.958 +
  42.959 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
  42.960 +
  42.961 +
  42.962 +   The following recommendations are the result of significant
  42.963 +   operational experience, and are intended to maximize
  42.964 +   interoperability.
  42.965 +
  42.966 +   Server implementations must implement the reference argument in a way
  42.967 +   that matches the intended "change directory" operation as closely as
  42.968 +   possible.  As a minimum implementation, the reference argument may be
  42.969 +   prepended to the mailbox name (while suppressing double delimiters;
  42.970 +   see the next paragraph).  Even servers that do not provide a way to
  42.971 +   break out of the current hierarchy (see "breakout facility" below)
  42.972 +   must provide a reasonable implementation of the reference argument,
  42.973 +   as described here, so that they will interoperate with clients that
  42.974 +   use it.
  42.975 +
  42.976 +   Server implementations that prepend the reference argument to the
  42.977 +   mailbox name should insert a hierarchy delimiter between them, and
  42.978 +   must not insert a second if one is already present:
  42.979 +
  42.980 +       C: A001 LIST ABC DEF
  42.981 +       S: * LIST () "/" ABC/DEF   <=== should do this
  42.982 +       S: A001 OK done
  42.983 +
  42.984 +       C: A002 LIST ABC/ /DEF
  42.985 +       S: * LIST () "/" ABC//DEF     <=== must not do this
  42.986 +       S: A002 OK done
  42.987 +
  42.988 +   On clients, the reference argument is chiefly used to implement a
  42.989 +   "breakout facility", wherein the user may directly access a mailbox
  42.990 +   outside the "current directory" hierarchy.  Client implementations
  42.991 +   should have an operational mode that does not use the reference
  42.992 +   argument.  This is to interoperate with older servers that did not
  42.993 +   implement the reference argument properly.  While it's a good idea to
  42.994 +   give the user access to a breakout facility, clients that do not
  42.995 +   intend to do so should not use the reference argument at all.
  42.996 +
  42.997 +   Client implementations should always place a trailing hierarchy
  42.998 +   delimiter on the reference argument.  This is because some servers
  42.999 +   prepend the reference argument to the mailbox name without inserting
 42.1000 +   a hierarchy delimiter, while others do insert a hierarchy delimiter
 42.1001 +   if one is not already present.  A client that puts the delimiter in
 42.1002 +   will work with both varieties of server.
 42.1003 +
 42.1004 +   Client implementations that implement a breakout facility should
 42.1005 +   allow the user to choose whether or not to use a leading hierarchy
 42.1006 +   delimiter on the mailbox argument.  This is because the handling of a
 42.1007 +   leading mailbox hierarchy delimiter also varies from server to
 42.1008 +   server, and even between different mailstores on the same server.  In
 42.1009 +   some cases, a leading hierarchy delimiter means "discard the
 42.1010 +
 42.1011 +
 42.1012 +
 42.1013 +Leiba                        Informational                     [Page 18]
 42.1014 +
 42.1015 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
 42.1016 +
 42.1017 +
 42.1018 +   reference argument" (implementing the intended breakout facility),
 42.1019 +   thus:
 42.1020 +
 42.1021 +       C: A001 LIST ABC/ /DEF
 42.1022 +       S: * LIST () "/" /DEF
 42.1023 +       S: A001 OK done
 42.1024 +
 42.1025 +   In other cases, however, the two are catenated and the extra
 42.1026 +   hierarchy delimiter is discarded, thus:
 42.1027 +
 42.1028 +       C: A001 LIST ABC/ /DEF
 42.1029 +       S: * LIST () "/" ABC/DEF
 42.1030 +       S: A001 OK done
 42.1031 +
 42.1032 +   Client implementations must not assume that the server supports a
 42.1033 +   breakout facility, but may provide a way for the user to use one if
 42.1034 +   it is available.  Any breakout facility should be exported to the
 42.1035 +   user interface.  Note that there may be other "breakout" characters
 42.1036 +   besides the hierarchy delimiter (for instance, UNIX filesystem
 42.1037 +   servers are likely to use a leading "~" as well), and that their
 42.1038 +   interpretation is server-dependent.
 42.1039 +
 42.1040 +3.4.10.   Mailbox Hierarchy Delimiters
 42.1041 +
 42.1042 +   The server's selection of what to use as a mailbox hierarchy
 42.1043 +   delimiter is a difficult one, involving several issues: What
 42.1044 +   characters do users expect to see?  What characters can they enter
 42.1045 +   for a hierarchy delimiter if it is desired (or required) that the
 42.1046 +   user enter it?  What character can be used for the hierarchy
 42.1047 +   delimiter, noting that the chosen character can not otherwise be used
 42.1048 +   in the mailbox name?
 42.1049 +
 42.1050 +   Because some interfaces show users the hierarchy delimiters or allow
 42.1051 +   users to enter qualified mailbox names containing them, server
 42.1052 +   implementations should use delimiter characters that users generally
 42.1053 +   expect to see as name separators.  The most common characters used
 42.1054 +   for this are "/" (as in Unix file names), "\" (as in OS/2 and Windows
 42.1055 +   file names), and "." (as in news groups).  There is little to choose
 42.1056 +   among these apart from what users may expect or what is dictated by
 42.1057 +   the underlying file system, if any.  One consideration about using
 42.1058 +   "\" is that it's also a special character in the IMAP protocol. While
 42.1059 +   the use of other hierarchy delimiter characters is permissible, A
 42.1060 +   DESIGNER IS WELL ADVISED TO STAY WITH ONE FROM THIS SET unless the
 42.1061 +   server is intended for special purposes only.  Implementers might be
 42.1062 +   thinking about using characters such as "-", "_", ";", "&", "#", "@",
 42.1063 +   and "!", but they should be aware of the surprise to the user as well
 42.1064 +   as of the effect on URLs and other external specifications (since
 42.1065 +   some of these characters have special meanings there).  Also, a
 42.1066 +
 42.1067 +
 42.1068 +
 42.1069 +Leiba                        Informational                     [Page 19]
 42.1070 +
 42.1071 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
 42.1072 +
 42.1073 +
 42.1074 +   server that uses "\" (and clients of such a server) must remember to
 42.1075 +   escape that character in quoted strings or to send literals instead.
 42.1076 +   Literals are recommended over escaped characters in quoted strings in
 42.1077 +   order to maintain compatibility with older IMAP versions that did not
 42.1078 +   allow escaped characters in quoted strings (but check the grammar to
 42.1079 +   see where literals are allowed):
 42.1080 +
 42.1081 +       C: 001 LIST "" {13}
 42.1082 +       S: + send literal
 42.1083 +       C: this\%\%\%\h*
 42.1084 +       S: * LIST () "\\" {27}
 42.1085 +       S: this\is\a\mailbox\hierarchy
 42.1086 +       S: 001 OK LIST complete
 42.1087 +
 42.1088 +   In any case, a server should not use normal alpha-numeric characters
 42.1089 +   (such as "X" or "0") as delimiters; a user would be very surprised to
 42.1090 +   find that "EXPENDITURES" actually represented a two-level hierarchy.
 42.1091 +   And a server should not use characters that are non-printable or
 42.1092 +   difficult or impossible to enter on a standard US keyboard.  Control
 42.1093 +   characters, box-drawing characters, and characters from non-US
 42.1094 +   alphabets fit into this category.  Their use presents
 42.1095 +   interoperability problems that are best avoided.
 42.1096 +
 42.1097 +   The UTF-7 encoding of mailbox names also raises questions about what
 42.1098 +   to do with the hierarchy delimiters in encoded names: do we encode
 42.1099 +   each hierarchy level and separate them with delimiters, or do we
 42.1100 +   encode the fully qualified name, delimiters and all?  The answer for
 42.1101 +   IMAP is the former: encode each hierarchy level separately, and
 42.1102 +   insert delimiters between.  This makes it particularly important not
 42.1103 +   to use as a hierarchy delimiter a character that might cause
 42.1104 +   confusion with IMAP's modified UTF-7 [UTF-7 and RFC-2060] encoding.
 42.1105 +
 42.1106 +   To repeat: a server should use "/", "\", or "." as its hierarchy
 42.1107 +   delimiter.  The use of any other character is likely to cause
 42.1108 +   problems and is STRONGLY DISCOURAGED.
 42.1109 +
 42.1110 +3.4.11.   ALERT Response Codes
 42.1111 +
 42.1112 +   The protocol spec is very clear on the matter of what to do with
 42.1113 +   ALERT response codes, and yet there are many clients that violate it
 42.1114 +   so it needs to be said anyway: "The human-readable text contains a
 42.1115 +   special alert that must be presented to the user in a fashion that
 42.1116 +   calls the user's attention to the message."  That should be clear
 42.1117 +   enough, but I'll repeat it here: Clients must present ALERT text
 42.1118 +   clearly to the user.
 42.1119 +
 42.1120 +
 42.1121 +
 42.1122 +
 42.1123 +
 42.1124 +
 42.1125 +Leiba                        Informational                     [Page 20]
 42.1126 +
 42.1127 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
 42.1128 +
 42.1129 +
 42.1130 +3.4.12.   Deleting Mailboxes
 42.1131 +
 42.1132 +   The protocol does not guarantee that a client may delete a mailbox
 42.1133 +   that is not empty, though on some servers it is permissible and is,
 42.1134 +   in fact, much faster than the alternative or deleting all the
 42.1135 +   messages from the client.  If the client chooses to try to take
 42.1136 +   advantage of this possibility it must be prepared to use the other
 42.1137 +   method in the even that the more convenient one fails.  Further, a
 42.1138 +   client should not try to delete the mailbox that it has selected, but
 42.1139 +   should first close that mailbox; some servers do not permit the
 42.1140 +   deletion of the selected mailbox.
 42.1141 +
 42.1142 +   That said, a server should permit the deletion of a non-empty
 42.1143 +   mailbox; there's little reason to pass this work on to the client.
 42.1144 +   Moreover, forbidding this prevents the deletion of a mailbox that for
 42.1145 +   some reason can not be opened or expunged, leading to possible
 42.1146 +   denial-of-service problems.
 42.1147 +
 42.1148 +   Example:
 42.1149 +
 42.1150 +       [User tells the client to delete mailbox BANANA, which is
 42.1151 +       currently selected...]
 42.1152 +       C: 008 CLOSE
 42.1153 +       S: 008 OK done
 42.1154 +       C: 009 DELETE BANANA
 42.1155 +       S: 009 NO Delete failed; mailbox is not empty.
 42.1156 +       C: 010 SELECT BANANA
 42.1157 +       S: * ... untagged SELECT responses
 42.1158 +       S: 010 OK done
 42.1159 +       C: 011 STORE 1:* +FLAGS.SILENT \DELETED
 42.1160 +       S: 011 OK done
 42.1161 +       C: 012 CLOSE
 42.1162 +       S: 012 OK done
 42.1163 +       C: 013 DELETE BANANA
 42.1164 +       S: 013 OK done
 42.1165 +
 42.1166 +3.5.   A Word About Testing
 42.1167 +
 42.1168 +   Since the whole point of IMAP is interoperability, and since
 42.1169 +   interoperability can not be tested in a vacuum, the final
 42.1170 +   recommendation of this treatise is, "Test against EVERYTHING."  Test
 42.1171 +   your client against every server you can get an account on.  Test
 42.1172 +   your server with every client you can get your hands on.  Many
 42.1173 +   clients make limited test versions available on the Web for the
 42.1174 +   downloading.  Many server owners will give serious client developers
 42.1175 +   guest accounts for testing.  Contact them and ask.  NEVER assume that
 42.1176 +   because your client works with one or two servers, or because your
 42.1177 +   server does fine with one or two clients, you will interoperate well
 42.1178 +
 42.1179 +
 42.1180 +
 42.1181 +Leiba                        Informational                     [Page 21]
 42.1182 +
 42.1183 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
 42.1184 +
 42.1185 +
 42.1186 +   in general.
 42.1187 +
 42.1188 +   In particular, in addition to everything else, be sure to test
 42.1189 +   against the reference implementations: the PINE client, the
 42.1190 +   University of Washington server, and the Cyrus server.
 42.1191 +
 42.1192 +   See the following URLs on the web for more information here:
 42.1193 +
 42.1194 +       IMAP Products and Sources: http://www.imap.org/products.html
 42.1195 +       IMC MailConnect: http://www.imc.org/imc-mailconnect
 42.1196 +
 42.1197 +4. Security Considerations
 42.1198 +
 42.1199 +   This document describes behaviour of clients and servers that use the
 42.1200 +   IMAP4 protocol, and as such, has the same security considerations as
 42.1201 +   described in [RFC-2060].
 42.1202 +
 42.1203 +5. References
 42.1204 +
 42.1205 +   [RFC-2060]  Crispin, M., "Internet Message Access Protocol - Version
 42.1206 +               4rev1", RFC 2060, December 1996.
 42.1207 +
 42.1208 +   [RFC-2119]  Bradner, S., "Key words for use in RFCs to Indicate
 42.1209 +               Requirement Levels", BCP 14, RFC 2119, March 1997.
 42.1210 +
 42.1211 +   [RFC-2180]  Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC
 42.1212 +               2180, July 1997.
 42.1213 +
 42.1214 +   [UTF-8]     Yergeau, F., " UTF-8, a transformation format of Unicode
 42.1215 +               and ISO 10646", RFC 2044, October 1996.
 42.1216 +
 42.1217 +   [UTF-7]     Goldsmith, D. and M. Davis, "UTF-7, a Mail-Safe
 42.1218 +               Transformation Format of Unicode", RFC 2152, May 1997.
 42.1219 +
 42.1220 +   [NAMESPACE] Gahrns, M. and C. Newman, "IMAP4 Namespace", Work in
 42.1221 +               Progress.
 42.1222 +
 42.1223 +6. Author's Address
 42.1224 +
 42.1225 +   Barry Leiba
 42.1226 +   IBM T.J. Watson Research Center
 42.1227 +   30 Saw Mill River Road
 42.1228 +   Hawthorne, NY  10532
 42.1229 +
 42.1230 +   Phone: 1-914-784-7941
 42.1231 +   EMail: leiba@watson.ibm.com
 42.1232 +
 42.1233 +
 42.1234 +
 42.1235 +
 42.1236 +
 42.1237 +Leiba                        Informational                     [Page 22]
 42.1238 +
 42.1239 +RFC 2683          IMAP4 Implementation Recommendations    September 1999
 42.1240 +
 42.1241 +
 42.1242 +7. Full Copyright Statement
 42.1243 +
 42.1244 +   Copyright (C) The Internet Society (1999).  All Rights Reserved.
 42.1245 +
 42.1246 +   This document and translations of it may be copied and furnished to
 42.1247 +   others, and derivative works that comment on or otherwise explain it
 42.1248 +   or assist in its implementation may be prepared, copied, published
 42.1249 +   and distributed, in whole or in part, without restriction of any
 42.1250 +   kind, provided that the above copyright notice and this paragraph are
 42.1251 +   included on all such copies and derivative works.  However, this
 42.1252 +   document itself may not be modified in any way, such as by removing
 42.1253 +   the copyright notice or references to the Internet Society or other
 42.1254 +   Internet organizations, except as needed for the purpose of
 42.1255 +   developing Internet standards in which case the procedures for
 42.1256 +   copyrights defined in the Internet Standards process must be
 42.1257 +   followed, or as required to translate it into languages other than
 42.1258 +   English.
 42.1259 +
 42.1260 +   The limited permissions granted above are perpetual and will not be
 42.1261 +   revoked by the Internet Society or its successors or assigns.
 42.1262 +
 42.1263 +   This document and the information contained herein is provided on an
 42.1264 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
 42.1265 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
 42.1266 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
 42.1267 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
 42.1268 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 42.1269 +
 42.1270 +Acknowledgement
 42.1271 +
 42.1272 +   Funding for the RFC Editor function is currently provided by the
 42.1273 +   Internet Society.
 42.1274 +
 42.1275 +
 42.1276 +
 42.1277 +
 42.1278 +
 42.1279 +
 42.1280 +
 42.1281 +
 42.1282 +
 42.1283 +
 42.1284 +
 42.1285 +
 42.1286 +
 42.1287 +
 42.1288 +
 42.1289 +
 42.1290 +
 42.1291 +
 42.1292 +
 42.1293 +Leiba                        Informational                     [Page 23]
 42.1294 +
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/docs/rfc/rfc2971.txt	Mon Sep 14 15:17:45 2009 +0900
    43.3 @@ -0,0 +1,451 @@
    43.4 +
    43.5 +
    43.6 +
    43.7 +
    43.8 +
    43.9 +
   43.10 +Network Working Group                                        T. Showalter
   43.11 +Request for Comments: 2971                                Mirapoint, Inc.
   43.12 +Category: Standards Track                                    October 2000
   43.13 +
   43.14 +
   43.15 +                           IMAP4 ID extension
   43.16 +
   43.17 +Status of this Memo
   43.18 +
   43.19 +   This document specifies an Internet standards track protocol for the
   43.20 +   Internet community, and requests discussion and suggestions for
   43.21 +   improvements.  Please refer to the current edition of the "Internet
   43.22 +   Official Protocol Standards" (STD 1) for the standardization state
   43.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   43.24 +
   43.25 +Copyright Notice
   43.26 +
   43.27 +   Copyright (C) The Internet Society (2000).  All Rights Reserved.
   43.28 +
   43.29 +Abstract
   43.30 +
   43.31 +   The ID extension to the Internet Message Access Protocol - Version
   43.32 +   4rev1 (IMAP4rev1) protocol allows the server and client to exchange
   43.33 +   identification information on their implementation in order to make
   43.34 +   bug reports and usage statistics more complete.
   43.35 +
   43.36 +1. Introduction
   43.37 +
   43.38 +   The IMAP4rev1 protocol described in [IMAP4rev1] provides a method for
   43.39 +   accessing remote mail stores, but it provides no facility to
   43.40 +   advertise what program a client or server uses to provide service.
   43.41 +   This makes it difficult for implementors to get complete bug reports
   43.42 +   from users, as it is frequently difficult to know what client or
   43.43 +   server is in use.
   43.44 +
   43.45 +   Additionally, some sites may wish to assemble usage statistics based
   43.46 +   on what clients are used, but in an an environment where users are
   43.47 +   permitted to obtain and maintain their own clients this is difficult
   43.48 +   to accomplish.
   43.49 +
   43.50 +   The ID command provides a facility to advertise information on what
   43.51 +   programs are being used along with contact information (should bugs
   43.52 +   ever occur).
   43.53 +
   43.54 +
   43.55 +
   43.56 +
   43.57 +
   43.58 +
   43.59 +
   43.60 +
   43.61 +Showalter                   Standards Track                     [Page 1]
   43.62 +
   43.63 +RFC 2971                   IMAP4 ID extension               October 2000
   43.64 +
   43.65 +
   43.66 +2. Conventions Used in this Document
   43.67 +
   43.68 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   43.69 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   43.70 +   document are to be interpreted as described in [KEYWORDS].
   43.71 +
   43.72 +   The conventions used in this document are the same as specified in
   43.73 +   [IMAP4rev1].  In examples, "C:" and "S:" indicate lines sent by the
   43.74 +   client and server respectively.  Line breaks have been inserted for
   43.75 +   readability.
   43.76 +
   43.77 +3. Specification
   43.78 +
   43.79 +   The sole purpose of the ID extension is to enable clients and servers
   43.80 +   to exchange information on their implementations for the purposes of
   43.81 +   statistical analysis and problem determination.
   43.82 +
   43.83 +   This information is be submitted to a server by any client wishing to
   43.84 +   provide information for statistical purposes, provided the server
   43.85 +   advertises its willingness to take the information with the atom "ID"
   43.86 +   included in the list of capabilities returned by the CAPABILITY
   43.87 +   command.
   43.88 +
   43.89 +   Implementations MUST NOT make operational changes based on the data
   43.90 +   sent as part of the ID command or response.  The ID command is for
   43.91 +   human consumption only, and is not to be used in improving the
   43.92 +   performance of clients or servers.
   43.93 +
   43.94 +   This includes, but is not limited to, the following:
   43.95 +
   43.96 +      Servers MUST NOT attempt to work around client bugs by using
   43.97 +      information from the ID command.  Clients MUST NOT attempt to work
   43.98 +      around server bugs based on the ID response.
   43.99 +
  43.100 +      Servers MUST NOT provide features to a client or otherwise
  43.101 +      optimize for a particular client by using information from the ID
  43.102 +      command.  Clients MUST NOT provide features to a server or
  43.103 +      otherwise optimize for a particular server based on the ID
  43.104 +      response.
  43.105 +
  43.106 +      Servers MUST NOT deny access to or refuse service for a client
  43.107 +      based on information from the ID command.  Clients MUST NOT refuse
  43.108 +      to operate or limit their operation with a server based on the ID
  43.109 +      response.
  43.110 +
  43.111 +
  43.112 +
  43.113 +
  43.114 +
  43.115 +
  43.116 +
  43.117 +Showalter                   Standards Track                     [Page 2]
  43.118 +
  43.119 +RFC 2971                   IMAP4 ID extension               October 2000
  43.120 +
  43.121 +
  43.122 +   Rationale: It is imperative that this extension not supplant IMAP's
  43.123 +   CAPABILITY mechanism with a ad-hoc approach where implementations
  43.124 +   guess each other's features based on who they claim to be.
  43.125 +
  43.126 +   Implementations MUST NOT send false information in an ID command.
  43.127 +
  43.128 +   Implementations MAY send less information than they have available or
  43.129 +   no information at all.  Such behavior may be useful to preserve user
  43.130 +   privacy.  See Security Considerations, section 7.
  43.131 +
  43.132 +3.1. ID Command
  43.133 +
  43.134 +   Arguments:  client parameter list or NIL
  43.135 +
  43.136 +   Responses:  OPTIONAL untagged response: ID
  43.137 +
  43.138 +   Result:     OK    identification information accepted
  43.139 +               BAD   command unknown or arguments invalid
  43.140 +
  43.141 +   Implementation identification information is sent by the client with
  43.142 +   the ID command.
  43.143 +
  43.144 +   This command is valid in any state.
  43.145 +
  43.146 +   The information sent is in the form of a list of field/value pairs.
  43.147 +   Fields are permitted to be any IMAP4 string, and values are permitted
  43.148 +   to be any IMAP4 string or NIL.  A value of NIL indicates that the
  43.149 +   client can not or will not specify this information.  The client may
  43.150 +   also send NIL instead of the list, indicating that it wants to send
  43.151 +   no information, but would still accept a server response.
  43.152 +
  43.153 +   The available fields are defined in section 3.3.
  43.154 +
  43.155 +   Example:  C: a023 ID ("name" "sodr" "version" "19.34" "vendor"
  43.156 +                 "Pink Floyd Music Limited")
  43.157 +             S: * ID NIL
  43.158 +             S: a023 OK ID completed
  43.159 +
  43.160 +3.2. ID Response
  43.161 +
  43.162 +   Contents:   server parameter list
  43.163 +
  43.164 +   In response to an ID command issued by the client, the server replies
  43.165 +   with a tagged response containing information on its implementation.
  43.166 +   The format is the same as the client list.
  43.167 +
  43.168 +
  43.169 +
  43.170 +
  43.171 +
  43.172 +
  43.173 +Showalter                   Standards Track                     [Page 3]
  43.174 +
  43.175 +RFC 2971                   IMAP4 ID extension               October 2000
  43.176 +
  43.177 +
  43.178 +   Example:  C: a042 ID NIL
  43.179 +             S: * ID ("name" "Cyrus" "version" "1.5" "os" "sunos"
  43.180 +                  "os-version" "5.5" "support-url"
  43.181 +                  "mailto:cyrus-bugs+@andrew.cmu.edu")
  43.182 +             S: a042 OK ID command completed
  43.183 +
  43.184 +   A server MUST send a tagged ID response to an ID command.  However, a
  43.185 +   server MAY send NIL in place of the list.
  43.186 +
  43.187 +3.3. Defined Field Values
  43.188 +
  43.189 +   Any string may be sent as a field, but the following are defined to
  43.190 +   describe certain values that might be sent.  Implementations are free
  43.191 +   to send none, any, or all of these.  Strings are not case-sensitive.
  43.192 +   Field strings MUST NOT be longer than 30 octets.  Value strings MUST
  43.193 +   NOT be longer than 1024 octets.  Implementations MUST NOT send more
  43.194 +   than 30 field-value pairs.
  43.195 +
  43.196 +     name            Name of the program
  43.197 +     version         Version number of the program
  43.198 +     os              Name of the operating system
  43.199 +     os-version      Version of the operating system
  43.200 +     vendor          Vendor of the client/server
  43.201 +     support-url     URL to contact for support
  43.202 +     address         Postal address of contact/vendor
  43.203 +     date            Date program was released, specified as a date-time
  43.204 +                       in IMAP4rev1
  43.205 +     command         Command used to start the program
  43.206 +     arguments       Arguments supplied on the command line, if any
  43.207 +                       if any
  43.208 +     environment     Description of environment, i.e., UNIX environment
  43.209 +                       variables or Windows registry settings
  43.210 +
  43.211 +   Implementations MUST NOT use contact information to submit automatic
  43.212 +   bug reports.  Implementations may include information from an ID
  43.213 +   response in a report automatically prepared, but are prohibited from
  43.214 +   sending the report without user authorization.
  43.215 +
  43.216 +   It is preferable to find the name and version of the underlying
  43.217 +   operating system at runtime in cases where this is possible.
  43.218 +
  43.219 +   Information sent via an ID response may violate user privacy.  See
  43.220 +   Security Considerations, section 7.
  43.221 +
  43.222 +   Implementations MUST NOT send the same field name more than once.
  43.223 +
  43.224 +
  43.225 +
  43.226 +
  43.227 +
  43.228 +
  43.229 +Showalter                   Standards Track                     [Page 4]
  43.230 +
  43.231 +RFC 2971                   IMAP4 ID extension               October 2000
  43.232 +
  43.233 +
  43.234 +4. Formal Syntax
  43.235 +
  43.236 +   This  syntax is intended to augment the grammar specified in
  43.237 +   [IMAP4rev1] in order to provide for the ID command.  This
  43.238 +   specification uses the augmented Backus-Naur Form (BNF) notation as
  43.239 +   used in [IMAP4rev1].
  43.240 +
  43.241 +     command_any ::= "CAPABILITY" / "LOGOUT" / "NOOP" / x_command / id
  43.242 +         ;; adds id command to command_any in [IMAP4rev1]
  43.243 +
  43.244 +     id ::= "ID" SPACE id_params_list
  43.245 +
  43.246 +     id_response ::= "ID" SPACE id_params_list
  43.247 +
  43.248 +     id_params_list ::= "(" #(string SPACE nstring) ")" / nil
  43.249 +         ;; list of field value pairs
  43.250 +
  43.251 +     response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
  43.252 +         mailbox_data / message_data / capability_data / id_response)
  43.253 +
  43.254 +5. Use of the ID extension with Firewalls and Other Intermediaries
  43.255 +
  43.256 +   There exist proxies, firewalls, and other intermediary systems that
  43.257 +   can intercept an IMAP session and make changes to the data exchanged
  43.258 +   in the session.  Such intermediaries are not anticipated by the IMAP4
  43.259 +   protocol design and are not within the scope of the IMAP4 standard.
  43.260 +   However, in order for the ID command to be useful in the presence of
  43.261 +   such intermediaries, those intermediaries need to take special note
  43.262 +   of the ID command and response.  In particular, if an intermediary
  43.263 +   changes any part of the IMAP session it must also change the ID
  43.264 +   command to advertise its presence.
  43.265 +
  43.266 +   A firewall MAY act to block transmission of specific information
  43.267 +   fields in the ID command and response that it believes reveal
  43.268 +   information that could expose a security vulnerability.  However, a
  43.269 +   firewall SHOULD NOT disable the extension, when present, entirely,
  43.270 +   and SHOULD NOT unconditionally remove either the client or server
  43.271 +   list.
  43.272 +
  43.273 +   Finally, it should be noted that a firewall, when handling a
  43.274 +   CAPABILITY response, MUST NOT allow the names of extensions to be
  43.275 +   returned to the client that the firewall has no knowledge of.
  43.276 +
  43.277 +
  43.278 +
  43.279 +
  43.280 +
  43.281 +
  43.282 +
  43.283 +
  43.284 +
  43.285 +Showalter                   Standards Track                     [Page 5]
  43.286 +
  43.287 +RFC 2971                   IMAP4 ID extension               October 2000
  43.288 +
  43.289 +
  43.290 +6. References
  43.291 +
  43.292 +   [KEYWORDS]  Bradner, S., "Key words for use in RFCs to Indicate
  43.293 +               Requirement Levels", RFC 2119, March 1997.
  43.294 +
  43.295 +   [IMAP4rev1] Crispin, M., "Internet Message Access Protocol - Version
  43.296 +               4rev1", RFC 2060, October 1996.
  43.297 +
  43.298 +   [RFC-822]   Crocker, D., "Standard for the Format of ARPA Internet
  43.299 +               Text Messages", STD 11, RFC 822, August 1982.
  43.300 +
  43.301 +7. Security Considerations
  43.302 +
  43.303 +   This extension has the danger of violating the privacy of users if
  43.304 +   misused.  Clients and servers should notify users that they implement
  43.305 +   and enable the ID command.
  43.306 +
  43.307 +   It is highly desirable that implementations provide a method of
  43.308 +   disabling ID support, perhaps by not sending ID at all, or by sending
  43.309 +   NIL as the argument to the ID command or response.
  43.310 +
  43.311 +   Implementors must exercise extreme care in adding fields sent as part
  43.312 +   of an ID command or response.  Some fields, including a processor ID
  43.313 +   number, Ethernet address, or other unique (or mostly unique)
  43.314 +   identifier allow tracking of users in ways that violate user privacy
  43.315 +   expectations.
  43.316 +
  43.317 +   Having implementation information of a given client or server may
  43.318 +   make it easier for an attacker to gain unauthorized access due to
  43.319 +   security holes.
  43.320 +
  43.321 +   Since this command includes arbitrary data and does not require the
  43.322 +   user to authenticate, server implementations are cautioned to guard
  43.323 +   against an attacker sending arbitrary garbage data in order to fill
  43.324 +   up the ID log.  In particular, if a server naively logs each ID
  43.325 +   command to disk without inspecting it, an attacker can simply fire up
  43.326 +   thousands of connections and send a few kilobytes of random data.
  43.327 +   Servers have to guard against this.  Methods include truncating
  43.328 +   abnormally large responses; collating responses by storing only a
  43.329 +   single copy, then keeping a counter of the number of times that
  43.330 +   response has been seen; keeping only particularly interesting parts
  43.331 +   of responses; and only logging responses of users who actually log
  43.332 +   in.
  43.333 +
  43.334 +   Security is affected by firewalls which modify the IMAP protocol
  43.335 +   stream; see section 5, Use of the ID Extension with Firewalls and
  43.336 +   Other Intermediaries, for more information.
  43.337 +
  43.338 +
  43.339 +
  43.340 +
  43.341 +Showalter                   Standards Track                     [Page 6]
  43.342 +
  43.343 +RFC 2971                   IMAP4 ID extension               October 2000
  43.344 +
  43.345 +
  43.346 +8. Author's Address
  43.347 +
  43.348 +   Tim Showalter
  43.349 +   Mirapoint, Inc.
  43.350 +   909 Hermosa Ct.
  43.351 +   Sunnyvale, CA 94095
  43.352 +
  43.353 +   EMail: tjs@mirapoint.com
  43.354 +
  43.355 +
  43.356 +
  43.357 +
  43.358 +
  43.359 +
  43.360 +
  43.361 +
  43.362 +
  43.363 +
  43.364 +
  43.365 +
  43.366 +
  43.367 +
  43.368 +
  43.369 +
  43.370 +
  43.371 +
  43.372 +
  43.373 +
  43.374 +
  43.375 +
  43.376 +
  43.377 +
  43.378 +
  43.379 +
  43.380 +
  43.381 +
  43.382 +
  43.383 +
  43.384 +
  43.385 +
  43.386 +
  43.387 +
  43.388 +
  43.389 +
  43.390 +
  43.391 +
  43.392 +
  43.393 +
  43.394 +
  43.395 +
  43.396 +
  43.397 +Showalter                   Standards Track                     [Page 7]
  43.398 +
  43.399 +RFC 2971                   IMAP4 ID extension               October 2000
  43.400 +
  43.401 +
  43.402 +9.  Full Copyright Statement
  43.403 +
  43.404 +   Copyright (C) The Internet Society (2000).  All Rights Reserved.
  43.405 +
  43.406 +   This document and translations of it may be copied and furnished to
  43.407 +   others, and derivative works that comment on or otherwise explain it
  43.408 +   or assist in its implementation may be prepared, copied, published
  43.409 +   and distributed, in whole or in part, without restriction of any
  43.410 +   kind, provided that the above copyright notice and this paragraph are
  43.411 +   included on all such copies and derivative works.  However, this
  43.412 +   document itself may not be modified in any way, such as by removing
  43.413 +   the copyright notice or references to the Internet Society or other
  43.414 +   Internet organizations, except as needed for the purpose of
  43.415 +   developing Internet standards in which case the procedures for
  43.416 +   copyrights defined in the Internet Standards process must be
  43.417 +   followed, or as required to translate it into languages other than
  43.418 +   English.
  43.419 +
  43.420 +   The limited permissions granted above are perpetual and will not be
  43.421 +   revoked by the Internet Society or its successors or assigns.
  43.422 +
  43.423 +   This document and the information contained herein is provided on an
  43.424 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  43.425 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  43.426 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  43.427 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  43.428 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  43.429 +
  43.430 +Acknowledgement
  43.431 +
  43.432 +   Funding for the RFC Editor function is currently provided by the
  43.433 +   Internet Society.
  43.434 +
  43.435 +
  43.436 +
  43.437 +
  43.438 +
  43.439 +
  43.440 +
  43.441 +
  43.442 +
  43.443 +
  43.444 +
  43.445 +
  43.446 +
  43.447 +
  43.448 +
  43.449 +
  43.450 +
  43.451 +
  43.452 +
  43.453 +Showalter                   Standards Track                     [Page 8]
  43.454 +
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/docs/rfc/rfc3348.txt	Mon Sep 14 15:17:45 2009 +0900
    44.3 @@ -0,0 +1,339 @@
    44.4 +
    44.5 +
    44.6 +
    44.7 +
    44.8 +
    44.9 +
   44.10 +Network Working Group                                          M. Gahrns
   44.11 +Request for Comments: 3348                                      R. Cheng
   44.12 +Category: Informational                                        Microsoft
   44.13 +                                                               July 2002
   44.14 +
   44.15 +
   44.16 +             The Internet Message Action Protocol (IMAP4)
   44.17 +                        Child Mailbox Extension
   44.18 +
   44.19 +Status of this Memo
   44.20 +
   44.21 +   This memo provides information for the Internet community.  It does
   44.22 +   not specify an Internet standard of any kind.  Distribution of this
   44.23 +   memo is unlimited.
   44.24 +
   44.25 +Copyright Notice
   44.26 +
   44.27 +   Copyright (C) The Internet Society (2002).  All Rights Reserved.
   44.28 +
   44.29 +Abstract
   44.30 +
   44.31 +   The Internet Message Action Protocol (IMAP4) CHILDREN extension
   44.32 +   provides a mechanism for a client to efficiently determine if a
   44.33 +   particular mailbox has children, without issuing a LIST "" * or a
   44.34 +   LIST "" % for each mailbox.
   44.35 +
   44.36 +1. Conventions used in this document
   44.37 +
   44.38 +   In examples, "C:" and "S:" indicate lines sent by the client and
   44.39 +   server respectively.  If such lines are wrapped without a new "C:" or
   44.40 +   "S:" label, then the wrapping is for editorial clarity and is not
   44.41 +   part of the command.
   44.42 +
   44.43 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   44.44 +   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   44.45 +   document are to be interpreted as described in [RFC-2119].
   44.46 +
   44.47 +2. Introduction and Overview
   44.48 +
   44.49 +   Many IMAP4 [RFC-2060] clients present to the user a hierarchical view
   44.50 +   of the mailboxes that a user has access to.  Rather than initially
   44.51 +   presenting to the user the entire mailbox hierarchy, it is often
   44.52 +   preferable to show to the user a collapsed outline list of the
   44.53 +   mailbox hierarchy (particularly if there is a large number of
   44.54 +   mailboxes).  The user can then expand the collapsed outline hierarchy
   44.55 +   as needed.  It is common to include within the collapsed hierarchy a
   44.56 +
   44.57 +
   44.58 +
   44.59 +
   44.60 +
   44.61 +Gahrns, et al.               Informational                      [Page 1]
   44.62 +
   44.63 +RFC 3348             IMAP4 Child Mailbox Extension             July 2002
   44.64 +
   44.65 +
   44.66 +   visual clue (such as a "+") to indicate that there are child
   44.67 +   mailboxes under a particular mailbox.  When the visual clue is
   44.68 +   clicked the hierarchy list is expanded to show the child mailboxes.
   44.69 +
   44.70 +   Several IMAP vendors implemented this proposal, and it is proposed to
   44.71 +   document this behavior and functionality as an Informational RFC.
   44.72 +
   44.73 +   There is interest in addressing the general extensibility of the IMAP
   44.74 +   LIST command through an IMAP LIST Extension draft.  Similar
   44.75 +   functionality to the \HasChildren and \HasNoChildren flags could be
   44.76 +   incorporated into this new LIST Extension.  It is proposed that the
   44.77 +   more general LIST Extension draft proceed on the standards track with
   44.78 +   this proposal being relegated to informational status only.
   44.79 +
   44.80 +   If the functionality of the \HasChildren and \HasNoChildren flags
   44.81 +   were incorporated into a more general LIST extension, this would have
   44.82 +   the advantage that a client could then have the opportunity to
   44.83 +   request whether or not the server should return this information.
   44.84 +   This would be an advantage over the current draft for servers where
   44.85 +   this information is expensive to compute, since the server would only
   44.86 +   need to compute the information when it knew that the client
   44.87 +   requesting the information was able to consume it.
   44.88 +
   44.89 +3. Requirements
   44.90 +
   44.91 +   IMAP4 servers that support this extension MUST list the keyword
   44.92 +   CHILDREN in their CAPABILITY response.
   44.93 +
   44.94 +   The CHILDREN extension defines two new attributes that MAY be
   44.95 +   returned within a LIST response.
   44.96 +
   44.97 +   \HasChildren - The presence of this attribute indicates that the
   44.98 +   mailbox has child mailboxes.
   44.99 +
  44.100 +   Servers SHOULD NOT return \HasChildren if child mailboxes exist, but
  44.101 +   none will be displayed to the current user in a LIST response (as
  44.102 +   should be the case where child mailboxes exist, but a client does not
  44.103 +   have permissions to access them.)  In this case, \HasNoChildren
  44.104 +   SHOULD be used.
  44.105 +
  44.106 +   In many cases, however, a server may not be able to efficiently
  44.107 +   compute whether a user has access to all child mailboxes, or multiple
  44.108 +   users may be accessing the same account and simultaneously changing
  44.109 +   the mailbox hierarchy.  As such a client MUST be prepared to accept
  44.110 +   the \HasChildren attribute as a hint.  That is, a mailbox MAY be
  44.111 +   flagged with the \HasChildren attribute, but no child mailboxes will
  44.112 +   appear in a subsequent LIST response.
  44.113 +
  44.114 +
  44.115 +
  44.116 +
  44.117 +Gahrns, et al.               Informational                      [Page 2]
  44.118 +
  44.119 +RFC 3348             IMAP4 Child Mailbox Extension             July 2002
  44.120 +
  44.121 +
  44.122 +   Example 3.1:
  44.123 +   ============
  44.124 +
  44.125 +   /*** Consider a server that has the following mailbox hierarchy:
  44.126 +
  44.127 +   INBOX
  44.128 +   ITEM_1
  44.129 +      ITEM_1A
  44.130 +   ITEM_2
  44.131 +      TOP_SECRET
  44.132 +
  44.133 +   Where INBOX, ITEM_1 and ITEM_2 are top level mailboxes.  ITEM_1A is a
  44.134 +   child mailbox of ITEM_1 and TOP_SECRET is a child mailbox of ITEM_2
  44.135 +   that the currently logged on user does NOT have access to.
  44.136 +
  44.137 +   Note that in this case, the server is not able to efficiently compute
  44.138 +   access rights to child mailboxes and responds with a \HasChildren
  44.139 +   attribute for mailbox ITEM_2, even though ITEM_2/TOP_SECRET does not
  44.140 +   appear in the list response.  ***/
  44.141 +
  44.142 +   C: A001 LIST "" *
  44.143 +   S: * LIST (\HasNoChildren) "/" INBOX
  44.144 +   S: * LIST (\HasChildren) "/" ITEM_1
  44.145 +   S: * LIST (\HasNoChildren) "/" ITEM_1/ITEM_1A
  44.146 +   S: * LIST (\HasChildren) "/" ITEM_2
  44.147 +   S: A001 OK LIST Completed
  44.148 +
  44.149 +   \HasNoChildren - The presence of this attribute indicates that the
  44.150 +   mailbox has NO child mailboxes that are accessible to the currently
  44.151 +   authenticated user.  If a mailbox has the \Noinferiors attribute, the
  44.152 +   \HasNoChildren attribute is redundant and SHOULD be omitted in the
  44.153 +   LIST response.
  44.154 +
  44.155 +   In some instances a server that supports the CHILDREN extension MAY
  44.156 +   NOT be able to determine whether a mailbox has children.  For example
  44.157 +   it may have difficulty determining whether there are child mailboxes
  44.158 +   when LISTing mailboxes while operating in a particular namespace.
  44.159 +
  44.160 +   In these cases, a server MAY exclude both the \HasChildren and
  44.161 +   \HasNoChildren attributes in the LIST response.  As such, a client
  44.162 +   can not make any assumptions about whether a mailbox has children
  44.163 +   based upon the absence of a single attribute.
  44.164 +
  44.165 +   It is an error for the server to return both a \HasChildren and a
  44.166 +   \HasNoChildren attribute in a LIST response.
  44.167 +
  44.168 +
  44.169 +
  44.170 +
  44.171 +
  44.172 +
  44.173 +Gahrns, et al.               Informational                      [Page 3]
  44.174 +
  44.175 +RFC 3348             IMAP4 Child Mailbox Extension             July 2002
  44.176 +
  44.177 +
  44.178 +   It is an error for the server to return both a \HasChildren and a
  44.179 +   \NoInferiors attribute in a LIST response.
  44.180 +
  44.181 +   Note: the \HasNoChildren attribute should not be confused with the
  44.182 +   IMAP4 [RFC-2060] defined attribute \Noinferiors which indicates that
  44.183 +   no child mailboxes exist now and none can be created in the future.
  44.184 +
  44.185 +   The \HasChildren and \HasNoChildren attributes might not be returned
  44.186 +   in response to a LSUB response.  Many servers maintain a simple
  44.187 +   mailbox subscription list that is not updated when the underlying
  44.188 +   mailbox structure is changed.  A client MUST NOT assume that
  44.189 +   hierarchy information will be maintained in the subscription list.
  44.190 +
  44.191 +   RLIST is a command defined in [RFC-2193] that includes in a LIST
  44.192 +   response mailboxes that are accessible only via referral.  That is, a
  44.193 +   client must explicitly issue an RLIST command to see a list of these
  44.194 +   mailboxes.  Thus in the case where a mailbox has child mailboxes that
  44.195 +   are available only via referral, the mailboxes would appear as
  44.196 +   \HasNoChildren in response to the LIST command, and \HasChildren in
  44.197 +   response to the RLIST command.
  44.198 +
  44.199 +5. Formal Syntax
  44.200 +
  44.201 +   The following syntax specification uses the augmented Backus-Naur
  44.202 +   Form (BNF) as described in [ABNF].
  44.203 +
  44.204 +   Two new mailbox attributes are defined as flag_extensions to the
  44.205 +   IMAP4 mailbox_list response:
  44.206 +
  44.207 +   HasChildren = "\HasChildren"
  44.208 +
  44.209 +   HasNoChildren = "\HasNoChildren"
  44.210 +
  44.211 +6. Security Considerations
  44.212 +
  44.213 +   This extension provides a client a more efficient means of
  44.214 +   determining whether a particular mailbox has children.  If a mailbox
  44.215 +   has children, but the currently authenticated user does not have
  44.216 +   access to any of them, the server SHOULD respond with a
  44.217 +   \HasNoChildren attribute.  In many cases, however, a server may not
  44.218 +   be able to efficiently compute whether a user has access to all child
  44.219 +   mailboxes.  If such a server responds with a \HasChildren attribute,
  44.220 +   when in fact the currently authenticated user does not have access to
  44.221 +   any child mailboxes, potentially more information is conveyed about
  44.222 +   the mailbox than intended.  A server designed with such levels of
  44.223 +   security in mind SHOULD NOT attach the \HasChildren attribute to a
  44.224 +   mailbox unless the server is certain that the user has access to at
  44.225 +   least one of the child mailboxes.
  44.226 +
  44.227 +
  44.228 +
  44.229 +Gahrns, et al.               Informational                      [Page 4]
  44.230 +
  44.231 +RFC 3348             IMAP4 Child Mailbox Extension             July 2002
  44.232 +
  44.233 +
  44.234 +7. References
  44.235 +
  44.236 +   [RFC-2060] Crispin, M., "Internet Message Access Protocol - Version
  44.237 +              4rev1", RFC 2060, December 1996.
  44.238 +
  44.239 +   [RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate
  44.240 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  44.241 +
  44.242 +   [RFC-2234] Crocker, D. and P. Overell, Editors, "Augmented BNF for
  44.243 +              Syntax Specifications: ABNF", RFC 2234, November 1997.
  44.244 +
  44.245 +   [RFC-2193] Gahrns, M., "IMAP4 Mailbox Referrals", RFC 2193, September
  44.246 +              1997.
  44.247 +
  44.248 +8.  Acknowledgments
  44.249 +
  44.250 +   The authors would like to thank the participants of several IMC Mail
  44.251 +   Connect events for their input when this idea was originally
  44.252 +   presented and refined.
  44.253 +
  44.254 +9. Author's Address
  44.255 +
  44.256 +   Mike Gahrns
  44.257 +   Microsoft
  44.258 +   One Microsoft Way
  44.259 +   Redmond, WA, 98052
  44.260 +   Phone: (425) 936-9833
  44.261 +   EMail: mikega@microsoft.com
  44.262 +
  44.263 +   Raymond Cheng
  44.264 +   Microsoft
  44.265 +   One Microsoft Way
  44.266 +   Redmond, WA, 98052
  44.267 +   Phone: (425) 703-4913
  44.268 +   EMail: raych@microsoft.com
  44.269 +
  44.270 +
  44.271 +
  44.272 +
  44.273 +
  44.274 +
  44.275 +
  44.276 +
  44.277 +
  44.278 +
  44.279 +
  44.280 +
  44.281 +
  44.282 +
  44.283 +
  44.284 +
  44.285 +Gahrns, et al.               Informational                      [Page 5]
  44.286 +
  44.287 +RFC 3348             IMAP4 Child Mailbox Extension             July 2002
  44.288 +
  44.289 +
  44.290 +10. Full Copyright Statement
  44.291 +
  44.292 +   Copyright (C) The Internet Society (2002).  All Rights Reserved.
  44.293 +
  44.294 +   This document and translations of it may be copied and furnished to
  44.295 +   others, and derivative works that comment on or otherwise explain it
  44.296 +   or assist in its implementation may be prepared, copied, published
  44.297 +   and distributed, in whole or in part, without restriction of any
  44.298 +   kind, provided that the above copyright notice and this paragraph are
  44.299 +   included on all such copies and derivative works.  However, this
  44.300 +   document itself may not be modified in any way, such as by removing
  44.301 +   the copyright notice or references to the Internet Society or other
  44.302 +   Internet organizations, except as needed for the purpose of
  44.303 +   developing Internet standards in which case the procedures for
  44.304 +   copyrights defined in the Internet Standards process must be
  44.305 +   followed, or as required to translate it into languages other than
  44.306 +   English.
  44.307 +
  44.308 +   The limited permissions granted above are perpetual and will not be
  44.309 +   revoked by the Internet Society or its successors or assigns.
  44.310 +
  44.311 +   This document and the information contained herein is provided on an
  44.312 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  44.313 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  44.314 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  44.315 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  44.316 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  44.317 +
  44.318 +Acknowledgement
  44.319 +
  44.320 +   Funding for the RFC Editor function is currently provided by the
  44.321 +   Internet Society.
  44.322 +
  44.323 +
  44.324 +
  44.325 +
  44.326 +
  44.327 +
  44.328 +
  44.329 +
  44.330 +
  44.331 +
  44.332 +
  44.333 +
  44.334 +
  44.335 +
  44.336 +
  44.337 +
  44.338 +
  44.339 +
  44.340 +
  44.341 +Gahrns, et al.               Informational                      [Page 6]
  44.342 +
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/docs/rfc/rfc3501.txt	Mon Sep 14 15:17:45 2009 +0900
    45.3 @@ -0,0 +1,6052 @@
    45.4 +
    45.5 +
    45.6 +
    45.7 +
    45.8 +
    45.9 +
   45.10 +Network Working Group                                         M. Crispin
   45.11 +Request for Comments: 3501                      University of Washington
   45.12 +Obsoletes: 2060                                               March 2003
   45.13 +Category: Standards Track
   45.14 +
   45.15 +
   45.16 +            INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
   45.17 +
   45.18 +Status of this Memo
   45.19 +
   45.20 +   This document specifies an Internet standards track protocol for the
   45.21 +   Internet community, and requests discussion and suggestions for
   45.22 +   improvements.  Please refer to the current edition of the "Internet
   45.23 +   Official Protocol Standards" (STD 1) for the standardization state
   45.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   45.25 +
   45.26 +Copyright Notice
   45.27 +
   45.28 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
   45.29 +
   45.30 +Abstract
   45.31 +
   45.32 +   The Internet Message Access Protocol, Version 4rev1 (IMAP4rev1)
   45.33 +   allows a client to access and manipulate electronic mail messages on
   45.34 +   a server.  IMAP4rev1 permits manipulation of mailboxes (remote
   45.35 +   message folders) in a way that is functionally equivalent to local
   45.36 +   folders.  IMAP4rev1 also provides the capability for an offline
   45.37 +   client to resynchronize with the server.
   45.38 +
   45.39 +   IMAP4rev1 includes operations for creating, deleting, and renaming
   45.40 +   mailboxes, checking for new messages, permanently removing messages,
   45.41 +   setting and clearing flags, RFC 2822 and RFC 2045 parsing, searching,
   45.42 +   and selective fetching of message attributes, texts, and portions
   45.43 +   thereof.  Messages in IMAP4rev1 are accessed by the use of numbers.
   45.44 +   These numbers are either message sequence numbers or unique
   45.45 +   identifiers.
   45.46 +
   45.47 +   IMAP4rev1 supports a single server.  A mechanism for accessing
   45.48 +   configuration information to support multiple IMAP4rev1 servers is
   45.49 +   discussed in RFC 2244.
   45.50 +
   45.51 +   IMAP4rev1 does not specify a means of posting mail; this function is
   45.52 +   handled by a mail transfer protocol such as RFC 2821.
   45.53 +
   45.54 +
   45.55 +
   45.56 +
   45.57 +
   45.58 +
   45.59 +
   45.60 +
   45.61 +Crispin                     Standards Track                     [Page 1]
   45.62 +
   45.63 +RFC 3501                         IMAPv4                       March 2003
   45.64 +
   45.65 +
   45.66 +Table of Contents
   45.67 +
   45.68 +   IMAP4rev1 Protocol Specification ................................  4
   45.69 +   1.      How to Read This Document ...............................  4
   45.70 +   1.1.    Organization of This Document ...........................  4
   45.71 +   1.2.    Conventions Used in This Document .......................  4
   45.72 +   1.3.    Special Notes to Implementors ...........................  5
   45.73 +   2.      Protocol Overview .......................................  6
   45.74 +   2.1.    Link Level ..............................................  6
   45.75 +   2.2.    Commands and Responses ..................................  6
   45.76 +   2.2.1.  Client Protocol Sender and Server Protocol Receiver .....  6
   45.77 +   2.2.2.  Server Protocol Sender and Client Protocol Receiver .....  7
   45.78 +   2.3.    Message Attributes ......................................  8
   45.79 +   2.3.1.  Message Numbers .........................................  8
   45.80 +   2.3.1.1.        Unique Identifier (UID) Message Attribute .......  8
   45.81 +   2.3.1.2.        Message Sequence Number Message Attribute ....... 10
   45.82 +   2.3.2.  Flags Message Attribute ................................. 11
   45.83 +   2.3.3.  Internal Date Message Attribute ......................... 12
   45.84 +   2.3.4.  [RFC-2822] Size Message Attribute ....................... 12
   45.85 +   2.3.5.  Envelope Structure Message Attribute .................... 12
   45.86 +   2.3.6.  Body Structure Message Attribute ........................ 12
   45.87 +   2.4.    Message Texts ........................................... 13
   45.88 +   3.      State and Flow Diagram .................................. 13
   45.89 +   3.1.    Not Authenticated State ................................. 13
   45.90 +   3.2.    Authenticated State ..................................... 13
   45.91 +   3.3.    Selected State .......................................... 13
   45.92 +   3.4.    Logout State ............................................ 14
   45.93 +   4.      Data Formats ............................................ 16
   45.94 +   4.1.    Atom .................................................... 16
   45.95 +   4.2.    Number .................................................. 16
   45.96 +   4.3.    String .................................................. 16
   45.97 +   4.3.1.  8-bit and Binary Strings ................................ 17
   45.98 +   4.4.    Parenthesized List ...................................... 17
   45.99 +   4.5.    NIL ..................................................... 17
  45.100 +   5.      Operational Considerations .............................. 18
  45.101 +   5.1.    Mailbox Naming .......................................... 18
  45.102 +   5.1.1.  Mailbox Hierarchy Naming ................................ 19
  45.103 +   5.1.2.  Mailbox Namespace Naming Convention ..................... 19
  45.104 +   5.1.3.  Mailbox International Naming Convention ................. 19
  45.105 +   5.2.    Mailbox Size and Message Status Updates ................. 21
  45.106 +   5.3.    Response when no Command in Progress .................... 21
  45.107 +   5.4.    Autologout Timer ........................................ 22
  45.108 +   5.5.    Multiple Commands in Progress ........................... 22
  45.109 +   6.      Client Commands ........................................  23
  45.110 +   6.1.    Client Commands - Any State ............................  24
  45.111 +   6.1.1.  CAPABILITY Command .....................................  24
  45.112 +   6.1.2.  NOOP Command ...........................................  25
  45.113 +   6.1.3.  LOGOUT Command .........................................  26
  45.114 +
  45.115 +
  45.116 +
  45.117 +Crispin                     Standards Track                     [Page 2]
  45.118 +
  45.119 +RFC 3501                         IMAPv4                       March 2003
  45.120 +
  45.121 +
  45.122 +   6.2.    Client Commands - Not Authenticated State ..............  26
  45.123 +   6.2.1.  STARTTLS Command .......................................  27
  45.124 +   6.2.2.  AUTHENTICATE Command ...................................  28
  45.125 +   6.2.3.  LOGIN Command ..........................................  30
  45.126 +   6.3.    Client Commands - Authenticated State ..................  31
  45.127 +   6.3.1.  SELECT Command .........................................  32
  45.128 +   6.3.2.  EXAMINE Command ........................................  34
  45.129 +   6.3.3.  CREATE Command .........................................  34
  45.130 +   6.3.4.  DELETE Command .........................................  35
  45.131 +   6.3.5.  RENAME Command .........................................  37
  45.132 +   6.3.6.  SUBSCRIBE Command ......................................  39
  45.133 +   6.3.7.  UNSUBSCRIBE Command ....................................  39
  45.134 +   6.3.8.  LIST Command ...........................................  40
  45.135 +   6.3.9.  LSUB Command ...........................................  43
  45.136 +   6.3.10. STATUS Command .........................................  44
  45.137 +   6.3.11. APPEND Command .........................................  46
  45.138 +   6.4.    Client Commands - Selected State .......................  47
  45.139 +   6.4.1.  CHECK Command ..........................................  47
  45.140 +   6.4.2.  CLOSE Command ..........................................  48
  45.141 +   6.4.3.  EXPUNGE Command ........................................  49
  45.142 +   6.4.4.  SEARCH Command .........................................  49
  45.143 +   6.4.5.  FETCH Command ..........................................  54
  45.144 +   6.4.6.  STORE Command ..........................................  58
  45.145 +   6.4.7.  COPY Command ...........................................  59
  45.146 +   6.4.8.  UID Command ............................................  60
  45.147 +   6.5.    Client Commands - Experimental/Expansion ...............  62
  45.148 +   6.5.1.  X<atom> Command ........................................  62
  45.149 +   7.      Server Responses .......................................  62
  45.150 +   7.1.    Server Responses - Status Responses ....................  63
  45.151 +   7.1.1.  OK Response ............................................  65
  45.152 +   7.1.2.  NO Response ............................................  66
  45.153 +   7.1.3.  BAD Response ...........................................  66
  45.154 +   7.1.4.  PREAUTH Response .......................................  67
  45.155 +   7.1.5.  BYE Response ...........................................  67
  45.156 +   7.2.    Server Responses - Server and Mailbox Status ...........  68
  45.157 +   7.2.1.  CAPABILITY Response ....................................  68
  45.158 +   7.2.2.  LIST Response ..........................................  69
  45.159 +   7.2.3.  LSUB Response ..........................................  70
  45.160 +   7.2.4   STATUS Response ........................................  70
  45.161 +   7.2.5.  SEARCH Response ........................................  71
  45.162 +   7.2.6.  FLAGS Response .........................................  71
  45.163 +   7.3.    Server Responses - Mailbox Size ........................  71
  45.164 +   7.3.1.  EXISTS Response ........................................  71
  45.165 +   7.3.2.  RECENT Response ........................................  72
  45.166 +   7.4.    Server Responses - Message Status ......................  72
  45.167 +   7.4.1.  EXPUNGE Response .......................................  72
  45.168 +   7.4.2.  FETCH Response .........................................  73
  45.169 +   7.5.    Server Responses - Command Continuation Request ........  79
  45.170 +
  45.171 +
  45.172 +
  45.173 +Crispin                     Standards Track                     [Page 3]
  45.174 +
  45.175 +RFC 3501                         IMAPv4                       March 2003
  45.176 +
  45.177 +
  45.178 +   8.      Sample IMAP4rev1 connection ............................  80
  45.179 +   9.      Formal Syntax ..........................................  81
  45.180 +   10.     Author's Note ..........................................  92
  45.181 +   11.     Security Considerations ................................  92
  45.182 +   11.1.   STARTTLS Security Considerations .......................  92
  45.183 +   11.2.   Other Security Considerations ..........................  93
  45.184 +   12.     IANA Considerations ....................................  94
  45.185 +   Appendices .....................................................  95
  45.186 +   A.      References .............................................  95
  45.187 +   B.      Changes from RFC 2060 ..................................  97
  45.188 +   C.      Key Word Index ......................................... 103
  45.189 +   Author's Address ............................................... 107
  45.190 +   Full Copyright Statement ....................................... 108
  45.191 +
  45.192 +IMAP4rev1 Protocol Specification
  45.193 +
  45.194 +1.      How to Read This Document
  45.195 +
  45.196 +1.1.    Organization of This Document
  45.197 +
  45.198 +   This document is written from the point of view of the implementor of
  45.199 +   an IMAP4rev1 client or server.  Beyond the protocol overview in
  45.200 +   section 2, it is not optimized for someone trying to understand the
  45.201 +   operation of the protocol.  The material in sections 3 through 5
  45.202 +   provides the general context and definitions with which IMAP4rev1
  45.203 +   operates.
  45.204 +
  45.205 +   Sections 6, 7, and 9 describe the IMAP commands, responses, and
  45.206 +   syntax, respectively.  The relationships among these are such that it
  45.207 +   is almost impossible to understand any of them separately.  In
  45.208 +   particular, do not attempt to deduce command syntax from the command
  45.209 +   section alone; instead refer to the Formal Syntax section.
  45.210 +
  45.211 +1.2.    Conventions Used in This Document
  45.212 +
  45.213 +   "Conventions" are basic principles or procedures.  Document
  45.214 +   conventions are noted in this section.
  45.215 +
  45.216 +   In examples, "C:" and "S:" indicate lines sent by the client and
  45.217 +   server respectively.
  45.218 +
  45.219 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  45.220 +   "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
  45.221 +   be interpreted as described in [KEYWORDS].
  45.222 +
  45.223 +   The word "can" (not "may") is used to refer to a possible
  45.224 +   circumstance or situation, as opposed to an optional facility of the
  45.225 +   protocol.
  45.226 +
  45.227 +
  45.228 +
  45.229 +Crispin                     Standards Track                     [Page 4]
  45.230 +
  45.231 +RFC 3501                         IMAPv4                       March 2003
  45.232 +
  45.233 +
  45.234 +   "User" is used to refer to a human user, whereas "client" refers to
  45.235 +   the software being run by the user.
  45.236 +
  45.237 +   "Connection" refers to the entire sequence of client/server
  45.238 +   interaction from the initial establishment of the network connection
  45.239 +   until its termination.
  45.240 +
  45.241 +   "Session" refers to the sequence of client/server interaction from
  45.242 +   the time that a mailbox is selected (SELECT or EXAMINE command) until
  45.243 +   the time that selection ends (SELECT or EXAMINE of another mailbox,
  45.244 +   CLOSE command, or connection termination).
  45.245 +
  45.246 +   Characters are 7-bit US-ASCII unless otherwise specified.  Other
  45.247 +   character sets are indicated using a "CHARSET", as described in
  45.248 +   [MIME-IMT] and defined in [CHARSET].  CHARSETs have important
  45.249 +   additional semantics in addition to defining character set; refer to
  45.250 +   these documents for more detail.
  45.251 +
  45.252 +   There are several protocol conventions in IMAP.  These refer to
  45.253 +   aspects of the specification which are not strictly part of the IMAP
  45.254 +   protocol, but reflect generally-accepted practice.  Implementations
  45.255 +   need to be aware of these conventions, and avoid conflicts whether or
  45.256 +   not they implement the convention.  For example, "&" may not be used
  45.257 +   as a hierarchy delimiter since it conflicts with the Mailbox
  45.258 +   International Naming Convention, and other uses of "&" in mailbox
  45.259 +   names are impacted as well.
  45.260 +
  45.261 +1.3.    Special Notes to Implementors
  45.262 +
  45.263 +   Implementors of the IMAP protocol are strongly encouraged to read the
  45.264 +   IMAP implementation recommendations document [IMAP-IMPLEMENTATION] in
  45.265 +   conjunction with this document, to help understand the intricacies of
  45.266 +   this protocol and how best to build an interoperable product.
  45.267 +
  45.268 +   IMAP4rev1 is designed to be upwards compatible from the [IMAP2] and
  45.269 +   unpublished IMAP2bis protocols.  IMAP4rev1 is largely compatible with
  45.270 +   the IMAP4 protocol described in RFC 1730; the exception being in
  45.271 +   certain facilities added in RFC 1730 that proved problematic and were
  45.272 +   subsequently removed.  In the course of the evolution of IMAP4rev1,
  45.273 +   some aspects in the earlier protocols have become obsolete.  Obsolete
  45.274 +   commands, responses, and data formats which an IMAP4rev1
  45.275 +   implementation can encounter when used with an earlier implementation
  45.276 +   are described in [IMAP-OBSOLETE].
  45.277 +
  45.278 +   Other compatibility issues with IMAP2bis, the most common variant of
  45.279 +   the earlier protocol, are discussed in [IMAP-COMPAT].  A full
  45.280 +   discussion of compatibility issues with rare (and presumed extinct)
  45.281 +
  45.282 +
  45.283 +
  45.284 +
  45.285 +Crispin                     Standards Track                     [Page 5]
  45.286 +
  45.287 +RFC 3501                         IMAPv4                       March 2003
  45.288 +
  45.289 +
  45.290 +   variants of [IMAP2] is in [IMAP-HISTORICAL]; this document is
  45.291 +   primarily of historical interest.
  45.292 +
  45.293 +   IMAP was originally developed for the older [RFC-822] standard, and
  45.294 +   as a consequence several fetch items in IMAP incorporate "RFC822" in
  45.295 +   their name.  With the exception of RFC822.SIZE, there are more modern
  45.296 +   replacements; for example, the modern version of RFC822.HEADER is
  45.297 +   BODY.PEEK[HEADER].  In all cases, "RFC822" should be interpreted as a
  45.298 +   reference to the updated [RFC-2822] standard.
  45.299 +
  45.300 +2.      Protocol Overview
  45.301 +
  45.302 +2.1.    Link Level
  45.303 +
  45.304 +   The IMAP4rev1 protocol assumes a reliable data stream such as that
  45.305 +   provided by TCP.  When TCP is used, an IMAP4rev1 server listens on
  45.306 +   port 143.
  45.307 +
  45.308 +2.2.    Commands and Responses
  45.309 +
  45.310 +   An IMAP4rev1 connection consists of the establishment of a
  45.311 +   client/server network connection, an initial greeting from the
  45.312 +   server, and client/server interactions.  These client/server
  45.313 +   interactions consist of a client command, server data, and a server
  45.314 +   completion result response.
  45.315 +
  45.316 +   All interactions transmitted by client and server are in the form of
  45.317 +   lines, that is, strings that end with a CRLF.  The protocol receiver
  45.318 +   of an IMAP4rev1 client or server is either reading a line, or is
  45.319 +   reading a sequence of octets with a known count followed by a line.
  45.320 +
  45.321 +2.2.1.  Client Protocol Sender and Server Protocol Receiver
  45.322 +
  45.323 +   The client command begins an operation.  Each client command is
  45.324 +   prefixed with an identifier (typically a short alphanumeric string,
  45.325 +   e.g., A0001, A0002, etc.) called a "tag".  A different tag is
  45.326 +   generated by the client for each command.
  45.327 +
  45.328 +   Clients MUST follow the syntax outlined in this specification
  45.329 +   strictly.  It is a syntax error to send a command with missing or
  45.330 +   extraneous spaces or arguments.
  45.331 +
  45.332 +   There are two cases in which a line from the client does not
  45.333 +   represent a complete command.  In one case, a command argument is
  45.334 +   quoted with an octet count (see the description of literal in String
  45.335 +   under Data Formats); in the other case, the command arguments require
  45.336 +   server feedback (see the AUTHENTICATE command).  In either case, the
  45.337 +
  45.338 +
  45.339 +
  45.340 +
  45.341 +Crispin                     Standards Track                     [Page 6]
  45.342 +
  45.343 +RFC 3501                         IMAPv4                       March 2003
  45.344 +
  45.345 +
  45.346 +   server sends a command continuation request response if it is ready
  45.347 +   for the octets (if appropriate) and the remainder of the command.
  45.348 +   This response is prefixed with the token "+".
  45.349 +
  45.350 +        Note: If instead, the server detected an error in the
  45.351 +        command, it sends a BAD completion response with a tag
  45.352 +        matching the command (as described below) to reject the
  45.353 +        command and prevent the client from sending any more of the
  45.354 +        command.
  45.355 +
  45.356 +        It is also possible for the server to send a completion
  45.357 +        response for some other command (if multiple commands are
  45.358 +        in progress), or untagged data.  In either case, the
  45.359 +        command continuation request is still pending; the client
  45.360 +        takes the appropriate action for the response, and reads
  45.361 +        another response from the server.  In all cases, the client
  45.362 +        MUST send a complete command (including receiving all
  45.363 +        command continuation request responses and command
  45.364 +        continuations for the command) before initiating a new
  45.365 +        command.
  45.366 +
  45.367 +   The protocol receiver of an IMAP4rev1 server reads a command line
  45.368 +   from the client, parses the command and its arguments, and transmits
  45.369 +   server data and a server command completion result response.
  45.370 +
  45.371 +2.2.2.  Server Protocol Sender and Client Protocol Receiver
  45.372 +
  45.373 +   Data transmitted by the server to the client and status responses
  45.374 +   that do not indicate command completion are prefixed with the token
  45.375 +   "*", and are called untagged responses.
  45.376 +
  45.377 +   Server data MAY be sent as a result of a client command, or MAY be
  45.378 +   sent unilaterally by the server.  There is no syntactic difference
  45.379 +   between server data that resulted from a specific command and server
  45.380 +   data that were sent unilaterally.
  45.381 +
  45.382 +   The server completion result response indicates the success or
  45.383 +   failure of the operation.  It is tagged with the same tag as the
  45.384 +   client command which began the operation.  Thus, if more than one
  45.385 +   command is in progress, the tag in a server completion response
  45.386 +   identifies the command to which the response applies.  There are
  45.387 +   three possible server completion responses: OK (indicating success),
  45.388 +   NO (indicating failure), or BAD (indicating a protocol error such as
  45.389 +   unrecognized command or command syntax error).
  45.390 +
  45.391 +   Servers SHOULD enforce the syntax outlined in this specification
  45.392 +   strictly.  Any client command with a protocol syntax error, including
  45.393 +   (but not limited to) missing or extraneous spaces or arguments,
  45.394 +
  45.395 +
  45.396 +
  45.397 +Crispin                     Standards Track                     [Page 7]
  45.398 +
  45.399 +RFC 3501                         IMAPv4                       March 2003
  45.400 +
  45.401 +
  45.402 +   SHOULD be rejected, and the client given a BAD server completion
  45.403 +   response.
  45.404 +
  45.405 +   The protocol receiver of an IMAP4rev1 client reads a response line
  45.406 +   from the server.  It then takes action on the response based upon the
  45.407 +   first token of the response, which can be a tag, a "*", or a "+".
  45.408 +
  45.409 +   A client MUST be prepared to accept any server response at all times.
  45.410 +   This includes server data that was not requested.  Server data SHOULD
  45.411 +   be recorded, so that the client can reference its recorded copy
  45.412 +   rather than sending a command to the server to request the data.  In
  45.413 +   the case of certain server data, the data MUST be recorded.
  45.414 +
  45.415 +   This topic is discussed in greater detail in the Server Responses
  45.416 +   section.
  45.417 +
  45.418 +2.3.    Message Attributes
  45.419 +
  45.420 +   In addition to message text, each message has several attributes
  45.421 +   associated with it.  These attributes can be retrieved individually
  45.422 +   or in conjunction with other attributes or message texts.
  45.423 +
  45.424 +2.3.1.  Message Numbers
  45.425 +
  45.426 +   Messages in IMAP4rev1 are accessed by one of two numbers; the unique
  45.427 +   identifier or the message sequence number.
  45.428 +
  45.429 +
  45.430 +2.3.1.1.        Unique Identifier (UID) Message Attribute
  45.431 +
  45.432 +   A 32-bit value assigned to each message, which when used with the
  45.433 +   unique identifier validity value (see below) forms a 64-bit value
  45.434 +   that MUST NOT refer to any other message in the mailbox or any
  45.435 +   subsequent mailbox with the same name forever.  Unique identifiers
  45.436 +   are assigned in a strictly ascending fashion in the mailbox; as each
  45.437 +   message is added to the mailbox it is assigned a higher UID than the
  45.438 +   message(s) which were added previously.  Unlike message sequence
  45.439 +   numbers, unique identifiers are not necessarily contiguous.
  45.440 +
  45.441 +   The unique identifier of a message MUST NOT change during the
  45.442 +   session, and SHOULD NOT change between sessions.  Any change of
  45.443 +   unique identifiers between sessions MUST be detectable using the
  45.444 +   UIDVALIDITY mechanism discussed below.  Persistent unique identifiers
  45.445 +   are required for a client to resynchronize its state from a previous
  45.446 +   session with the server (e.g., disconnected or offline access
  45.447 +   clients); this is discussed further in [IMAP-DISC].
  45.448 +
  45.449 +
  45.450 +
  45.451 +
  45.452 +
  45.453 +Crispin                     Standards Track                     [Page 8]
  45.454 +
  45.455 +RFC 3501                         IMAPv4                       March 2003
  45.456 +
  45.457 +
  45.458 +   Associated with every mailbox are two values which aid in unique
  45.459 +   identifier handling: the next unique identifier value and the unique
  45.460 +   identifier validity value.
  45.461 +
  45.462 +   The next unique identifier value is the predicted value that will be
  45.463 +   assigned to a new message in the mailbox.  Unless the unique
  45.464 +   identifier validity also changes (see below), the next unique
  45.465 +   identifier value MUST have the following two characteristics.  First,
  45.466 +   the next unique identifier value MUST NOT change unless new messages
  45.467 +   are added to the mailbox; and second, the next unique identifier
  45.468 +   value MUST change whenever new messages are added to the mailbox,
  45.469 +   even if those new messages are subsequently expunged.
  45.470 +
  45.471 +        Note: The next unique identifier value is intended to
  45.472 +        provide a means for a client to determine whether any
  45.473 +        messages have been delivered to the mailbox since the
  45.474 +        previous time it checked this value.  It is not intended to
  45.475 +        provide any guarantee that any message will have this
  45.476 +        unique identifier.  A client can only assume, at the time
  45.477 +        that it obtains the next unique identifier value, that
  45.478 +        messages arriving after that time will have a UID greater
  45.479 +        than or equal to that value.
  45.480 +
  45.481 +   The unique identifier validity value is sent in a UIDVALIDITY
  45.482 +   response code in an OK untagged response at mailbox selection time.
  45.483 +   If unique identifiers from an earlier session fail to persist in this
  45.484 +   session, the unique identifier validity value MUST be greater than
  45.485 +   the one used in the earlier session.
  45.486 +
  45.487 +        Note: Ideally, unique identifiers SHOULD persist at all
  45.488 +        times.  Although this specification recognizes that failure
  45.489 +        to persist can be unavoidable in certain server
  45.490 +        environments, it STRONGLY ENCOURAGES message store
  45.491 +        implementation techniques that avoid this problem.  For
  45.492 +        example:
  45.493 +
  45.494 +         1) Unique identifiers MUST be strictly ascending in the
  45.495 +            mailbox at all times.  If the physical message store is
  45.496 +            re-ordered by a non-IMAP agent, this requires that the
  45.497 +            unique identifiers in the mailbox be regenerated, since
  45.498 +            the former unique identifiers are no longer strictly
  45.499 +            ascending as a result of the re-ordering.
  45.500 +
  45.501 +         2) If the message store has no mechanism to store unique
  45.502 +            identifiers, it must regenerate unique identifiers at
  45.503 +            each session, and each session must have a unique
  45.504 +            UIDVALIDITY value.
  45.505 +
  45.506 +
  45.507 +
  45.508 +
  45.509 +Crispin                     Standards Track                     [Page 9]
  45.510 +
  45.511 +RFC 3501                         IMAPv4                       March 2003
  45.512 +
  45.513 +
  45.514 +         3) If the mailbox is deleted and a new mailbox with the
  45.515 +            same name is created at a later date, the server must
  45.516 +            either keep track of unique identifiers from the
  45.517 +            previous instance of the mailbox, or it must assign a
  45.518 +            new UIDVALIDITY value to the new instance of the
  45.519 +            mailbox.  A good UIDVALIDITY value to use in this case
  45.520 +            is a 32-bit representation of the creation date/time of
  45.521 +            the mailbox.  It is alright to use a constant such as
  45.522 +            1, but only if it guaranteed that unique identifiers
  45.523 +            will never be reused, even in the case of a mailbox
  45.524 +            being deleted (or renamed) and a new mailbox by the
  45.525 +            same name created at some future time.
  45.526 +
  45.527 +         4) The combination of mailbox name, UIDVALIDITY, and UID
  45.528 +            must refer to a single immutable message on that server
  45.529 +            forever.  In particular, the internal date, [RFC-2822]
  45.530 +            size, envelope, body structure, and message texts
  45.531 +            (RFC822, RFC822.HEADER, RFC822.TEXT, and all BODY[...]
  45.532 +            fetch data items) must never change.  This does not
  45.533 +            include message numbers, nor does it include attributes
  45.534 +            that can be set by a STORE command (e.g., FLAGS).
  45.535 +
  45.536 +
  45.537 +2.3.1.2.        Message Sequence Number Message Attribute
  45.538 +
  45.539 +   A relative position from 1 to the number of messages in the mailbox.
  45.540 +   This position MUST be ordered by ascending unique identifier.  As
  45.541 +   each new message is added, it is assigned a message sequence number
  45.542 +   that is 1 higher than the number of messages in the mailbox before
  45.543 +   that new message was added.
  45.544 +
  45.545 +   Message sequence numbers can be reassigned during the session.  For
  45.546 +   example, when a message is permanently removed (expunged) from the
  45.547 +   mailbox, the message sequence number for all subsequent messages is
  45.548 +   decremented.  The number of messages in the mailbox is also
  45.549 +   decremented.  Similarly, a new message can be assigned a message
  45.550 +   sequence number that was once held by some other message prior to an
  45.551 +   expunge.
  45.552 +
  45.553 +   In addition to accessing messages by relative position in the
  45.554 +   mailbox, message sequence numbers can be used in mathematical
  45.555 +   calculations.  For example, if an untagged "11 EXISTS" is received,
  45.556 +   and previously an untagged "8 EXISTS" was received, three new
  45.557 +   messages have arrived with message sequence numbers of 9, 10, and 11.
  45.558 +   Another example, if message 287 in a 523 message mailbox has UID
  45.559 +   12345, there are exactly 286 messages which have lesser UIDs and 236
  45.560 +   messages which have greater UIDs.
  45.561 +
  45.562 +
  45.563 +
  45.564 +
  45.565 +Crispin                     Standards Track                    [Page 10]
  45.566 +
  45.567 +RFC 3501                         IMAPv4                       March 2003
  45.568 +
  45.569 +
  45.570 +2.3.2.  Flags Message Attribute
  45.571 +
  45.572 +   A list of zero or more named tokens associated with the message.  A
  45.573 +   flag is set by its addition to this list, and is cleared by its
  45.574 +   removal.  There are two types of flags in IMAP4rev1.  A flag of
  45.575 +   either type can be permanent or session-only.
  45.576 +
  45.577 +   A system flag is a flag name that is pre-defined in this
  45.578 +   specification.  All system flags begin with "\".  Certain system
  45.579 +   flags (\Deleted and \Seen) have special semantics described
  45.580 +   elsewhere.  The currently-defined system flags are:
  45.581 +
  45.582 +        \Seen
  45.583 +           Message has been read
  45.584 +
  45.585 +        \Answered
  45.586 +           Message has been answered
  45.587 +
  45.588 +        \Flagged
  45.589 +           Message is "flagged" for urgent/special attention
  45.590 +
  45.591 +        \Deleted
  45.592 +           Message is "deleted" for removal by later EXPUNGE
  45.593 +
  45.594 +        \Draft
  45.595 +           Message has not completed composition (marked as a draft).
  45.596 +
  45.597 +        \Recent
  45.598 +           Message is "recently" arrived in this mailbox.  This session
  45.599 +           is the first session to have been notified about this
  45.600 +           message; if the session is read-write, subsequent sessions
  45.601 +           will not see \Recent set for this message.  This flag can not
  45.602 +           be altered by the client.
  45.603 +
  45.604 +           If it is not possible to determine whether or not this
  45.605 +           session is the first session to be notified about a message,
  45.606 +           then that message SHOULD be considered recent.
  45.607 +
  45.608 +           If multiple connections have the same mailbox selected
  45.609 +           simultaneously, it is undefined which of these connections
  45.610 +           will see newly-arrived messages with \Recent set and which
  45.611 +           will see it without \Recent set.
  45.612 +
  45.613 +   A keyword is defined by the server implementation.  Keywords do not
  45.614 +   begin with "\".  Servers MAY permit the client to define new keywords
  45.615 +   in the mailbox (see the description of the PERMANENTFLAGS response
  45.616 +   code for more information).
  45.617 +
  45.618 +
  45.619 +
  45.620 +
  45.621 +Crispin                     Standards Track                    [Page 11]
  45.622 +
  45.623 +RFC 3501                         IMAPv4                       March 2003
  45.624 +
  45.625 +
  45.626 +   A flag can be permanent or session-only on a per-flag basis.
  45.627 +   Permanent flags are those which the client can add or remove from the
  45.628 +   message flags permanently; that is, concurrent and subsequent
  45.629 +   sessions will see any change in permanent flags.  Changes to session
  45.630 +   flags are valid only in that session.
  45.631 +
  45.632 +        Note: The \Recent system flag is a special case of a
  45.633 +        session flag.  \Recent can not be used as an argument in a
  45.634 +        STORE or APPEND command, and thus can not be changed at
  45.635 +        all.
  45.636 +
  45.637 +2.3.3.  Internal Date Message Attribute
  45.638 +
  45.639 +   The internal date and time of the message on the server.  This
  45.640 +   is not the date and time in the [RFC-2822] header, but rather a
  45.641 +   date and time which reflects when the message was received.  In
  45.642 +   the case of messages delivered via [SMTP], this SHOULD be the
  45.643 +   date and time of final delivery of the message as defined by
  45.644 +   [SMTP].  In the case of messages delivered by the IMAP4rev1 COPY
  45.645 +   command, this SHOULD be the internal date and time of the source
  45.646 +   message.  In the case of messages delivered by the IMAP4rev1
  45.647 +   APPEND command, this SHOULD be the date and time as specified in
  45.648 +   the APPEND command description.  All other cases are
  45.649 +   implementation defined.
  45.650 +
  45.651 +2.3.4.  [RFC-2822] Size Message Attribute
  45.652 +
  45.653 +   The number of octets in the message, as expressed in [RFC-2822]
  45.654 +   format.
  45.655 +
  45.656 +2.3.5.  Envelope Structure Message Attribute
  45.657 +
  45.658 +   A parsed representation of the [RFC-2822] header of the message.
  45.659 +   Note that the IMAP Envelope structure is not the same as an
  45.660 +   [SMTP] envelope.
  45.661 +
  45.662 +2.3.6.  Body Structure Message Attribute
  45.663 +
  45.664 +   A parsed representation of the [MIME-IMB] body structure
  45.665 +   information of the message.
  45.666 +
  45.667 +
  45.668 +
  45.669 +
  45.670 +
  45.671 +
  45.672 +
  45.673 +
  45.674 +
  45.675 +
  45.676 +
  45.677 +Crispin                     Standards Track                    [Page 12]
  45.678 +
  45.679 +RFC 3501                         IMAPv4                       March 2003
  45.680 +
  45.681 +
  45.682 +2.4.    Message Texts
  45.683 +
  45.684 +   In addition to being able to fetch the full [RFC-2822] text of a
  45.685 +   message, IMAP4rev1 permits the fetching of portions of the full
  45.686 +   message text.  Specifically, it is possible to fetch the
  45.687 +   [RFC-2822] message header, [RFC-2822] message body, a [MIME-IMB]
  45.688 +   body part, or a [MIME-IMB] header.
  45.689 +
  45.690 +3.      State and Flow Diagram
  45.691 +
  45.692 +   Once the connection between client and server is established, an
  45.693 +   IMAP4rev1 connection is in one of four states.  The initial
  45.694 +   state is identified in the server greeting.  Most commands are
  45.695 +   only valid in certain states.  It is a protocol error for the
  45.696 +   client to attempt a command while the connection is in an
  45.697 +   inappropriate state, and the server will respond with a BAD or
  45.698 +   NO (depending upon server implementation) command completion
  45.699 +   result.
  45.700 +
  45.701 +3.1.    Not Authenticated State
  45.702 +
  45.703 +   In the not authenticated state, the client MUST supply
  45.704 +   authentication credentials before most commands will be
  45.705 +   permitted.  This state is entered when a connection starts
  45.706 +   unless the connection has been pre-authenticated.
  45.707 +
  45.708 +3.2.    Authenticated State
  45.709 +
  45.710 +   In the authenticated state, the client is authenticated and MUST
  45.711 +   select a mailbox to access before commands that affect messages
  45.712 +   will be permitted.  This state is entered when a
  45.713 +   pre-authenticated connection starts, when acceptable
  45.714 +   authentication credentials have been provided, after an error in
  45.715 +   selecting a mailbox, or after a successful CLOSE command.
  45.716 +
  45.717 +3.3.    Selected State
  45.718 +
  45.719 +   In a selected state, a mailbox has been selected to access.
  45.720 +   This state is entered when a mailbox has been successfully
  45.721 +   selected.
  45.722 +
  45.723 +
  45.724 +
  45.725 +
  45.726 +
  45.727 +
  45.728 +
  45.729 +
  45.730 +
  45.731 +
  45.732 +
  45.733 +Crispin                     Standards Track                    [Page 13]
  45.734 +
  45.735 +RFC 3501                         IMAPv4                       March 2003
  45.736 +
  45.737 +
  45.738 +3.4.    Logout State
  45.739 +
  45.740 +   In the logout state, the connection is being terminated.  This
  45.741 +   state can be entered as a result of a client request (via the
  45.742 +   LOGOUT command) or by unilateral action on the part of either
  45.743 +   the client or server.
  45.744 +
  45.745 +   If the client requests the logout state, the server MUST send an
  45.746 +   untagged BYE response and a tagged OK response to the LOGOUT
  45.747 +   command before the server closes the connection; and the client
  45.748 +   MUST read the tagged OK response to the LOGOUT command before
  45.749 +   the client closes the connection.
  45.750 +
  45.751 +   A server MUST NOT unilaterally close the connection without
  45.752 +   sending an untagged BYE response that contains the reason for
  45.753 +   having done so.  A client SHOULD NOT unilaterally close the
  45.754 +   connection, and instead SHOULD issue a LOGOUT command.  If the
  45.755 +   server detects that the client has unilaterally closed the
  45.756 +   connection, the server MAY omit the untagged BYE response and
  45.757 +   simply close its connection.
  45.758 +
  45.759 +
  45.760 +
  45.761 +
  45.762 +
  45.763 +
  45.764 +
  45.765 +
  45.766 +
  45.767 +
  45.768 +
  45.769 +
  45.770 +
  45.771 +
  45.772 +
  45.773 +
  45.774 +
  45.775 +
  45.776 +
  45.777 +
  45.778 +
  45.779 +
  45.780 +
  45.781 +
  45.782 +
  45.783 +
  45.784 +
  45.785 +
  45.786 +
  45.787 +
  45.788 +
  45.789 +Crispin                     Standards Track                    [Page 14]
  45.790 +
  45.791 +RFC 3501                         IMAPv4                       March 2003
  45.792 +
  45.793 +
  45.794 +                   +----------------------+
  45.795 +                   |connection established|
  45.796 +                   +----------------------+
  45.797 +                              ||
  45.798 +                              \/
  45.799 +            +--------------------------------------+
  45.800 +            |          server greeting             |
  45.801 +            +--------------------------------------+
  45.802 +                      || (1)       || (2)        || (3)
  45.803 +                      \/           ||            ||
  45.804 +            +-----------------+    ||            ||
  45.805 +            |Not Authenticated|    ||            ||
  45.806 +            +-----------------+    ||            ||
  45.807 +             || (7)   || (4)       ||            ||
  45.808 +             ||       \/           \/            ||
  45.809 +             ||     +----------------+           ||
  45.810 +             ||     | Authenticated  |<=++       ||
  45.811 +             ||     +----------------+  ||       ||
  45.812 +             ||       || (7)   || (5)   || (6)   ||
  45.813 +             ||       ||       \/       ||       ||
  45.814 +             ||       ||    +--------+  ||       ||
  45.815 +             ||       ||    |Selected|==++       ||
  45.816 +             ||       ||    +--------+           ||
  45.817 +             ||       ||       || (7)            ||
  45.818 +             \/       \/       \/                \/
  45.819 +            +--------------------------------------+
  45.820 +            |               Logout                 |
  45.821 +            +--------------------------------------+
  45.822 +                              ||
  45.823 +                              \/
  45.824 +                +-------------------------------+
  45.825 +                |both sides close the connection|
  45.826 +                +-------------------------------+
  45.827 +
  45.828 +         (1) connection without pre-authentication (OK greeting)
  45.829 +         (2) pre-authenticated connection (PREAUTH greeting)
  45.830 +         (3) rejected connection (BYE greeting)
  45.831 +         (4) successful LOGIN or AUTHENTICATE command
  45.832 +         (5) successful SELECT or EXAMINE command
  45.833 +         (6) CLOSE command, or failed SELECT or EXAMINE command
  45.834 +         (7) LOGOUT command, server shutdown, or connection closed
  45.835 +
  45.836 +
  45.837 +
  45.838 +
  45.839 +
  45.840 +
  45.841 +
  45.842 +
  45.843 +
  45.844 +
  45.845 +Crispin                     Standards Track                    [Page 15]
  45.846 +
  45.847 +RFC 3501                         IMAPv4                       March 2003
  45.848 +
  45.849 +
  45.850 +4.      Data Formats
  45.851 +
  45.852 +   IMAP4rev1 uses textual commands and responses.  Data in
  45.853 +   IMAP4rev1 can be in one of several forms: atom, number, string,
  45.854 +   parenthesized list, or NIL.  Note that a particular data item
  45.855 +   may take more than one form; for example, a data item defined as
  45.856 +   using "astring" syntax may be either an atom or a string.
  45.857 +
  45.858 +4.1.    Atom
  45.859 +
  45.860 +   An atom consists of one or more non-special characters.
  45.861 +
  45.862 +4.2.    Number
  45.863 +
  45.864 +   A number consists of one or more digit characters, and
  45.865 +   represents a numeric value.
  45.866 +
  45.867 +4.3.    String
  45.868 +
  45.869 +   A string is in one of two forms: either literal or quoted
  45.870 +   string.  The literal form is the general form of string.  The
  45.871 +   quoted string form is an alternative that avoids the overhead of
  45.872 +   processing a literal at the cost of limitations of characters
  45.873 +   which may be used.
  45.874 +
  45.875 +   A literal is a sequence of zero or more octets (including CR and
  45.876 +   LF), prefix-quoted with an octet count in the form of an open
  45.877 +   brace ("{"), the number of octets, close brace ("}"), and CRLF.
  45.878 +   In the case of literals transmitted from server to client, the
  45.879 +   CRLF is immediately followed by the octet data.  In the case of
  45.880 +   literals transmitted from client to server, the client MUST wait
  45.881 +   to receive a command continuation request (described later in
  45.882 +   this document) before sending the octet data (and the remainder
  45.883 +   of the command).
  45.884 +
  45.885 +   A quoted string is a sequence of zero or more 7-bit characters,
  45.886 +   excluding CR and LF, with double quote (<">) characters at each
  45.887 +   end.
  45.888 +
  45.889 +   The empty string is represented as either "" (a quoted string
  45.890 +   with zero characters between double quotes) or as {0} followed
  45.891 +   by CRLF (a literal with an octet count of 0).
  45.892 +
  45.893 +     Note: Even if the octet count is 0, a client transmitting a
  45.894 +     literal MUST wait to receive a command continuation request.
  45.895 +
  45.896 +
  45.897 +
  45.898 +
  45.899 +
  45.900 +
  45.901 +Crispin                     Standards Track                    [Page 16]
  45.902 +
  45.903 +RFC 3501                         IMAPv4                       March 2003
  45.904 +
  45.905 +
  45.906 +4.3.1.  8-bit and Binary Strings
  45.907 +
  45.908 +   8-bit textual and binary mail is supported through the use of a
  45.909 +   [MIME-IMB] content transfer encoding.  IMAP4rev1 implementations MAY
  45.910 +   transmit 8-bit or multi-octet characters in literals, but SHOULD do
  45.911 +   so only when the [CHARSET] is identified.
  45.912 +
  45.913 +   Although a BINARY body encoding is defined, unencoded binary strings
  45.914 +   are not permitted.  A "binary string" is any string with NUL
  45.915 +   characters.  Implementations MUST encode binary data into a textual
  45.916 +   form, such as BASE64, before transmitting the data.  A string with an
  45.917 +   excessive amount of CTL characters MAY also be considered to be
  45.918 +   binary.
  45.919 +
  45.920 +4.4.    Parenthesized List
  45.921 +
  45.922 +   Data structures are represented as a "parenthesized list"; a sequence
  45.923 +   of data items, delimited by space, and bounded at each end by
  45.924 +   parentheses.  A parenthesized list can contain other parenthesized
  45.925 +   lists, using multiple levels of parentheses to indicate nesting.
  45.926 +
  45.927 +   The empty list is represented as () -- a parenthesized list with no
  45.928 +   members.
  45.929 +
  45.930 +4.5.    NIL
  45.931 +
  45.932 +   The special form "NIL" represents the non-existence of a particular
  45.933 +   data item that is represented as a string or parenthesized list, as
  45.934 +   distinct from the empty string "" or the empty parenthesized list ().
  45.935 +
  45.936 +        Note: NIL is never used for any data item which takes the
  45.937 +        form of an atom.  For example, a mailbox name of "NIL" is a
  45.938 +        mailbox named NIL as opposed to a non-existent mailbox
  45.939 +        name.  This is because mailbox uses "astring" syntax which
  45.940 +        is an atom or a string.  Conversely, an addr-name of NIL is
  45.941 +        a non-existent personal name, because addr-name uses
  45.942 +        "nstring" syntax which is NIL or a string, but never an
  45.943 +        atom.
  45.944 +
  45.945 +
  45.946 +
  45.947 +
  45.948 +
  45.949 +
  45.950 +
  45.951 +
  45.952 +
  45.953 +
  45.954 +
  45.955 +
  45.956 +
  45.957 +Crispin                     Standards Track                    [Page 17]
  45.958 +
  45.959 +RFC 3501                         IMAPv4                       March 2003
  45.960 +
  45.961 +
  45.962 +5.      Operational Considerations
  45.963 +
  45.964 +   The following rules are listed here to ensure that all IMAP4rev1
  45.965 +   implementations interoperate properly.
  45.966 +
  45.967 +5.1.    Mailbox Naming
  45.968 +
  45.969 +   Mailbox names are 7-bit.  Client implementations MUST NOT attempt to
  45.970 +   create 8-bit mailbox names, and SHOULD interpret any 8-bit mailbox
  45.971 +   names returned by LIST or LSUB as UTF-8.  Server implementations
  45.972 +   SHOULD prohibit the creation of 8-bit mailbox names, and SHOULD NOT
  45.973 +   return 8-bit mailbox names in LIST or LSUB.  See section 5.1.3 for
  45.974 +   more information on how to represent non-ASCII mailbox names.
  45.975 +
  45.976 +        Note: 8-bit mailbox names were undefined in earlier
  45.977 +        versions of this protocol.  Some sites used a local 8-bit
  45.978 +        character set to represent non-ASCII mailbox names.  Such
  45.979 +        usage is not interoperable, and is now formally deprecated.
  45.980 +
  45.981 +   The case-insensitive mailbox name INBOX is a special name reserved to
  45.982 +   mean "the primary mailbox for this user on this server".  The
  45.983 +   interpretation of all other names is implementation-dependent.
  45.984 +
  45.985 +   In particular, this specification takes no position on case
  45.986 +   sensitivity in non-INBOX mailbox names.  Some server implementations
  45.987 +   are fully case-sensitive; others preserve case of a newly-created
  45.988 +   name but otherwise are case-insensitive; and yet others coerce names
  45.989 +   to a particular case.  Client implementations MUST interact with any
  45.990 +   of these.  If a server implementation interprets non-INBOX mailbox
  45.991 +   names as case-insensitive, it MUST treat names using the
  45.992 +   international naming convention specially as described in section
  45.993 +   5.1.3.
  45.994 +
  45.995 +   There are certain client considerations when creating a new mailbox
  45.996 +   name:
  45.997 +
  45.998 +   1)    Any character which is one of the atom-specials (see the Formal
  45.999 +         Syntax) will require that the mailbox name be represented as a
 45.1000 +         quoted string or literal.
 45.1001 +
 45.1002 +   2)    CTL and other non-graphic characters are difficult to represent
 45.1003 +         in a user interface and are best avoided.
 45.1004 +
 45.1005 +   3)    Although the list-wildcard characters ("%" and "*") are valid
 45.1006 +         in a mailbox name, it is difficult to use such mailbox names
 45.1007 +         with the LIST and LSUB commands due to the conflict with
 45.1008 +         wildcard interpretation.
 45.1009 +
 45.1010 +
 45.1011 +
 45.1012 +
 45.1013 +Crispin                     Standards Track                    [Page 18]
 45.1014 +
 45.1015 +RFC 3501                         IMAPv4                       March 2003
 45.1016 +
 45.1017 +
 45.1018 +   4)    Usually, a character (determined by the server implementation)
 45.1019 +         is reserved to delimit levels of hierarchy.
 45.1020 +
 45.1021 +   5)    Two characters, "#" and "&", have meanings by convention, and
 45.1022 +         should be avoided except when used in that convention.
 45.1023 +
 45.1024 +5.1.1.  Mailbox Hierarchy Naming
 45.1025 +
 45.1026 +   If it is desired to export hierarchical mailbox names, mailbox names
 45.1027 +   MUST be left-to-right hierarchical using a single character to
 45.1028 +   separate levels of hierarchy.  The same hierarchy separator character
 45.1029 +   is used for all levels of hierarchy within a single name.
 45.1030 +
 45.1031 +5.1.2.  Mailbox Namespace Naming Convention
 45.1032 +
 45.1033 +   By convention, the first hierarchical element of any mailbox name
 45.1034 +   which begins with "#" identifies the "namespace" of the remainder of
 45.1035 +   the name.  This makes it possible to disambiguate between different
 45.1036 +   types of mailbox stores, each of which have their own namespaces.
 45.1037 +
 45.1038 +        For example, implementations which offer access to USENET
 45.1039 +        newsgroups MAY use the "#news" namespace to partition the
 45.1040 +        USENET newsgroup namespace from that of other mailboxes.
 45.1041 +        Thus, the comp.mail.misc newsgroup would have a mailbox
 45.1042 +        name of "#news.comp.mail.misc", and the name
 45.1043 +        "comp.mail.misc" can refer to a different object (e.g., a
 45.1044 +        user's private mailbox).
 45.1045 +
 45.1046 +5.1.3.  Mailbox International Naming Convention
 45.1047 +
 45.1048 +   By convention, international mailbox names in IMAP4rev1 are specified
 45.1049 +   using a modified version of the UTF-7 encoding described in [UTF-7].
 45.1050 +   Modified UTF-7 may also be usable in servers that implement an
 45.1051 +   earlier version of this protocol.
 45.1052 +
 45.1053 +   In modified UTF-7, printable US-ASCII characters, except for "&",
 45.1054 +   represent themselves; that is, characters with octet values 0x20-0x25
 45.1055 +   and 0x27-0x7e.  The character "&" (0x26) is represented by the
 45.1056 +   two-octet sequence "&-".
 45.1057 +
 45.1058 +   All other characters (octet values 0x00-0x1f and 0x7f-0xff) are
 45.1059 +   represented in modified BASE64, with a further modification from
 45.1060 +   [UTF-7] that "," is used instead of "/".  Modified BASE64 MUST NOT be
 45.1061 +   used to represent any printing US-ASCII character which can represent
 45.1062 +   itself.
 45.1063 +
 45.1064 +
 45.1065 +
 45.1066 +
 45.1067 +
 45.1068 +
 45.1069 +Crispin                     Standards Track                    [Page 19]
 45.1070 +
 45.1071 +RFC 3501                         IMAPv4                       March 2003
 45.1072 +
 45.1073 +
 45.1074 +   "&" is used to shift to modified BASE64 and "-" to shift back to
 45.1075 +   US-ASCII.  There is no implicit shift from BASE64 to US-ASCII, and
 45.1076 +   null shifts ("-&" while in BASE64; note that "&-" while in US-ASCII
 45.1077 +   means "&") are not permitted.  However, all names start in US-ASCII,
 45.1078 +   and MUST end in US-ASCII; that is, a name that ends with a non-ASCII
 45.1079 +   ISO-10646 character MUST end with a "-").
 45.1080 +
 45.1081 +   The purpose of these modifications is to correct the following
 45.1082 +   problems with UTF-7:
 45.1083 +
 45.1084 +      1) UTF-7 uses the "+" character for shifting; this conflicts with
 45.1085 +         the common use of "+" in mailbox names, in particular USENET
 45.1086 +         newsgroup names.
 45.1087 +
 45.1088 +      2) UTF-7's encoding is BASE64 which uses the "/" character; this
 45.1089 +         conflicts with the use of "/" as a popular hierarchy delimiter.
 45.1090 +
 45.1091 +      3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
 45.1092 +         the use of "\" as a popular hierarchy delimiter.
 45.1093 +
 45.1094 +      4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
 45.1095 +         the use of "~" in some servers as a home directory indicator.
 45.1096 +
 45.1097 +      5) UTF-7 permits multiple alternate forms to represent the same
 45.1098 +         string; in particular, printable US-ASCII characters can be
 45.1099 +         represented in encoded form.
 45.1100 +
 45.1101 +      Although modified UTF-7 is a convention, it establishes certain
 45.1102 +      requirements on server handling of any mailbox name with an
 45.1103 +      embedded "&" character.  In particular, server implementations
 45.1104 +      MUST preserve the exact form of the modified BASE64 portion of a
 45.1105 +      modified UTF-7 name and treat that text as case-sensitive, even if
 45.1106 +      names are otherwise case-insensitive or case-folded.
 45.1107 +
 45.1108 +      Server implementations SHOULD verify that any mailbox name with an
 45.1109 +      embedded "&" character, used as an argument to CREATE, is: in the
 45.1110 +      correctly modified UTF-7 syntax, has no superfluous shifts, and
 45.1111 +      has no encoding in modified BASE64 of any printing US-ASCII
 45.1112 +      character which can represent itself.  However, client
 45.1113 +      implementations MUST NOT depend upon the server doing this, and
 45.1114 +      SHOULD NOT attempt to create a mailbox name with an embedded "&"
 45.1115 +      character unless it complies with the modified UTF-7 syntax.
 45.1116 +
 45.1117 +      Server implementations which export a mail store that does not
 45.1118 +      follow the modified UTF-7 convention MUST convert to modified
 45.1119 +      UTF-7 any mailbox name that contains either non-ASCII characters
 45.1120 +      or the "&" character.
 45.1121 +
 45.1122 +
 45.1123 +
 45.1124 +
 45.1125 +Crispin                     Standards Track                    [Page 20]
 45.1126 +
 45.1127 +RFC 3501                         IMAPv4                       March 2003
 45.1128 +
 45.1129 +
 45.1130 +           For example, here is a mailbox name which mixes English,
 45.1131 +           Chinese, and Japanese text:
 45.1132 +           ~peter/mail/&U,BTFw-/&ZeVnLIqe-
 45.1133 +
 45.1134 +           For example, the string "&Jjo!" is not a valid mailbox
 45.1135 +           name because it does not contain a shift to US-ASCII
 45.1136 +           before the "!".  The correct form is "&Jjo-!".  The
 45.1137 +           string "&U,BTFw-&ZeVnLIqe-" is not permitted because it
 45.1138 +           contains a superfluous shift.  The correct form is
 45.1139 +           "&U,BTF2XlZyyKng-".
 45.1140 +
 45.1141 +5.2.    Mailbox Size and Message Status Updates
 45.1142 +
 45.1143 +   At any time, a server can send data that the client did not request.
 45.1144 +   Sometimes, such behavior is REQUIRED.  For example, agents other than
 45.1145 +   the server MAY add messages to the mailbox (e.g., new message
 45.1146 +   delivery), change the flags of the messages in the mailbox (e.g.,
 45.1147 +   simultaneous access to the same mailbox by multiple agents), or even
 45.1148 +   remove messages from the mailbox.  A server MUST send mailbox size
 45.1149 +   updates automatically if a mailbox size change is observed during the
 45.1150 +   processing of a command.  A server SHOULD send message flag updates
 45.1151 +   automatically, without requiring the client to request such updates
 45.1152 +   explicitly.
 45.1153 +
 45.1154 +   Special rules exist for server notification of a client about the
 45.1155 +   removal of messages to prevent synchronization errors; see the
 45.1156 +   description of the EXPUNGE response for more detail.  In particular,
 45.1157 +   it is NOT permitted to send an EXISTS response that would reduce the
 45.1158 +   number of messages in the mailbox; only the EXPUNGE response can do
 45.1159 +   this.
 45.1160 +
 45.1161 +   Regardless of what implementation decisions a client makes on
 45.1162 +   remembering data from the server, a client implementation MUST record
 45.1163 +   mailbox size updates.  It MUST NOT assume that any command after the
 45.1164 +   initial mailbox selection will return the size of the mailbox.
 45.1165 +
 45.1166 +5.3.    Response when no Command in Progress
 45.1167 +
 45.1168 +   Server implementations are permitted to send an untagged response
 45.1169 +   (except for EXPUNGE) while there is no command in progress.  Server
 45.1170 +   implementations that send such responses MUST deal with flow control
 45.1171 +   considerations.  Specifically, they MUST either (1) verify that the
 45.1172 +   size of the data does not exceed the underlying transport's available
 45.1173 +   window size, or (2) use non-blocking writes.
 45.1174 +
 45.1175 +
 45.1176 +
 45.1177 +
 45.1178 +
 45.1179 +
 45.1180 +
 45.1181 +Crispin                     Standards Track                    [Page 21]
 45.1182 +
 45.1183 +RFC 3501                         IMAPv4                       March 2003
 45.1184 +
 45.1185 +
 45.1186 +5.4.    Autologout Timer
 45.1187 +
 45.1188 +   If a server has an inactivity autologout timer, the duration of that
 45.1189 +   timer MUST be at least 30 minutes.  The receipt of ANY command from
 45.1190 +   the client during that interval SHOULD suffice to reset the
 45.1191 +   autologout timer.
 45.1192 +
 45.1193 +5.5.    Multiple Commands in Progress
 45.1194 +
 45.1195 +   The client MAY send another command without waiting for the
 45.1196 +   completion result response of a command, subject to ambiguity rules
 45.1197 +   (see below) and flow control constraints on the underlying data
 45.1198 +   stream.  Similarly, a server MAY begin processing another command
 45.1199 +   before processing the current command to completion, subject to
 45.1200 +   ambiguity rules.  However, any command continuation request responses
 45.1201 +   and command continuations MUST be negotiated before any subsequent
 45.1202 +   command is initiated.
 45.1203 +
 45.1204 +   The exception is if an ambiguity would result because of a command
 45.1205 +   that would affect the results of other commands.  Clients MUST NOT
 45.1206 +   send multiple commands without waiting if an ambiguity would result.
 45.1207 +   If the server detects a possible ambiguity, it MUST execute commands
 45.1208 +   to completion in the order given by the client.
 45.1209 +
 45.1210 +   The most obvious example of ambiguity is when a command would affect
 45.1211 +   the results of another command, e.g., a FETCH of a message's flags
 45.1212 +   and a STORE of that same message's flags.
 45.1213 +
 45.1214 +   A non-obvious ambiguity occurs with commands that permit an untagged
 45.1215 +   EXPUNGE response (commands other than FETCH, STORE, and SEARCH),
 45.1216 +   since an untagged EXPUNGE response can invalidate sequence numbers in
 45.1217 +   a subsequent command.  This is not a problem for FETCH, STORE, or
 45.1218 +   SEARCH commands because servers are prohibited from sending EXPUNGE
 45.1219 +   responses while any of those commands are in progress.  Therefore, if
 45.1220 +   the client sends any command other than FETCH, STORE, or SEARCH, it
 45.1221 +   MUST wait for the completion result response before sending a command
 45.1222 +   with message sequence numbers.
 45.1223 +
 45.1224 +        Note: UID FETCH, UID STORE, and UID SEARCH are different
 45.1225 +        commands from FETCH, STORE, and SEARCH.  If the client
 45.1226 +        sends a UID command, it must wait for a completion result
 45.1227 +        response before sending a command with message sequence
 45.1228 +        numbers.
 45.1229 +
 45.1230 +
 45.1231 +
 45.1232 +
 45.1233 +
 45.1234 +
 45.1235 +
 45.1236 +
 45.1237 +Crispin                     Standards Track                    [Page 22]
 45.1238 +
 45.1239 +RFC 3501                         IMAPv4                       March 2003
 45.1240 +
 45.1241 +
 45.1242 +   For example, the following non-waiting command sequences are invalid:
 45.1243 +
 45.1244 +      FETCH + NOOP + STORE
 45.1245 +      STORE + COPY + FETCH
 45.1246 +      COPY + COPY
 45.1247 +      CHECK + FETCH
 45.1248 +
 45.1249 +   The following are examples of valid non-waiting command sequences:
 45.1250 +
 45.1251 +      FETCH + STORE + SEARCH + CHECK
 45.1252 +      STORE + COPY + EXPUNGE
 45.1253 +
 45.1254 +      UID SEARCH + UID SEARCH may be valid or invalid as a non-waiting
 45.1255 +      command sequence, depending upon whether or not the second UID
 45.1256 +      SEARCH contains message sequence numbers.
 45.1257 +
 45.1258 +6.      Client Commands
 45.1259 +
 45.1260 +   IMAP4rev1 commands are described in this section.  Commands are
 45.1261 +   organized by the state in which the command is permitted.  Commands
 45.1262 +   which are permitted in multiple states are listed in the minimum
 45.1263 +   permitted state (for example, commands valid in authenticated and
 45.1264 +   selected state are listed in the authenticated state commands).
 45.1265 +
 45.1266 +   Command arguments, identified by "Arguments:" in the command
 45.1267 +   descriptions below, are described by function, not by syntax.  The
 45.1268 +   precise syntax of command arguments is described in the Formal Syntax
 45.1269 +   section.
 45.1270 +
 45.1271 +   Some commands cause specific server responses to be returned; these
 45.1272 +   are identified by "Responses:" in the command descriptions below.
 45.1273 +   See the response descriptions in the Responses section for
 45.1274 +   information on these responses, and the Formal Syntax section for the
 45.1275 +   precise syntax of these responses.  It is possible for server data to
 45.1276 +   be transmitted as a result of any command.  Thus, commands that do
 45.1277 +   not specifically require server data specify "no specific responses
 45.1278 +   for this command" instead of "none".
 45.1279 +
 45.1280 +   The "Result:" in the command description refers to the possible
 45.1281 +   tagged status responses to a command, and any special interpretation
 45.1282 +   of these status responses.
 45.1283 +
 45.1284 +   The state of a connection is only changed by successful commands
 45.1285 +   which are documented as changing state.  A rejected command (BAD
 45.1286 +   response) never changes the state of the connection or of the
 45.1287 +   selected mailbox.  A failed command (NO response) generally does not
 45.1288 +   change the state of the connection or of the selected mailbox; the
 45.1289 +   exception being the SELECT and EXAMINE commands.
 45.1290 +
 45.1291 +
 45.1292 +
 45.1293 +Crispin                     Standards Track                    [Page 23]
 45.1294 +
 45.1295 +RFC 3501                         IMAPv4                       March 2003
 45.1296 +
 45.1297 +
 45.1298 +6.1.    Client Commands - Any State
 45.1299 +
 45.1300 +   The following commands are valid in any state: CAPABILITY, NOOP, and
 45.1301 +   LOGOUT.
 45.1302 +
 45.1303 +6.1.1.  CAPABILITY Command
 45.1304 +
 45.1305 +   Arguments:  none
 45.1306 +
 45.1307 +   Responses:  REQUIRED untagged response: CAPABILITY
 45.1308 +
 45.1309 +   Result:     OK - capability completed
 45.1310 +               BAD - command unknown or arguments invalid
 45.1311 +
 45.1312 +      The CAPABILITY command requests a listing of capabilities that the
 45.1313 +      server supports.  The server MUST send a single untagged
 45.1314 +      CAPABILITY response with "IMAP4rev1" as one of the listed
 45.1315 +      capabilities before the (tagged) OK response.
 45.1316 +
 45.1317 +      A capability name which begins with "AUTH=" indicates that the
 45.1318 +      server supports that particular authentication mechanism.  All
 45.1319 +      such names are, by definition, part of this specification.  For
 45.1320 +      example, the authorization capability for an experimental
 45.1321 +      "blurdybloop" authenticator would be "AUTH=XBLURDYBLOOP" and not
 45.1322 +      "XAUTH=BLURDYBLOOP" or "XAUTH=XBLURDYBLOOP".
 45.1323 +
 45.1324 +      Other capability names refer to extensions, revisions, or
 45.1325 +      amendments to this specification.  See the documentation of the
 45.1326 +      CAPABILITY response for additional information.  No capabilities,
 45.1327 +      beyond the base IMAP4rev1 set defined in this specification, are
 45.1328 +      enabled without explicit client action to invoke the capability.
 45.1329 +
 45.1330 +      Client and server implementations MUST implement the STARTTLS,
 45.1331 +      LOGINDISABLED, and AUTH=PLAIN (described in [IMAP-TLS])
 45.1332 +      capabilities.  See the Security Considerations section for
 45.1333 +      important information.
 45.1334 +
 45.1335 +      See the section entitled "Client Commands -
 45.1336 +      Experimental/Expansion" for information about the form of site or
 45.1337 +      implementation-specific capabilities.
 45.1338 +
 45.1339 +
 45.1340 +
 45.1341 +
 45.1342 +
 45.1343 +
 45.1344 +
 45.1345 +
 45.1346 +
 45.1347 +
 45.1348 +
 45.1349 +Crispin                     Standards Track                    [Page 24]
 45.1350 +
 45.1351 +RFC 3501                         IMAPv4                       March 2003
 45.1352 +
 45.1353 +
 45.1354 +   Example:    C: abcd CAPABILITY
 45.1355 +               S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI
 45.1356 +               LOGINDISABLED
 45.1357 +               S: abcd OK CAPABILITY completed
 45.1358 +               C: efgh STARTTLS
 45.1359 +               S: efgh OK STARTLS completed
 45.1360 +               <TLS negotiation, further commands are under [TLS] layer>
 45.1361 +               C: ijkl CAPABILITY
 45.1362 +               S: * CAPABILITY IMAP4rev1 AUTH=GSSAPI AUTH=PLAIN
 45.1363 +               S: ijkl OK CAPABILITY completed
 45.1364 +
 45.1365 +
 45.1366 +6.1.2.  NOOP Command
 45.1367 +
 45.1368 +   Arguments:  none
 45.1369 +
 45.1370 +   Responses:  no specific responses for this command (but see below)
 45.1371 +
 45.1372 +   Result:     OK - noop completed
 45.1373 +               BAD - command unknown or arguments invalid
 45.1374 +
 45.1375 +      The NOOP command always succeeds.  It does nothing.
 45.1376 +
 45.1377 +      Since any command can return a status update as untagged data, the
 45.1378 +      NOOP command can be used as a periodic poll for new messages or
 45.1379 +      message status updates during a period of inactivity (this is the
 45.1380 +      preferred method to do this).  The NOOP command can also be used
 45.1381 +      to reset any inactivity autologout timer on the server.
 45.1382 +
 45.1383 +   Example:    C: a002 NOOP
 45.1384 +               S: a002 OK NOOP completed
 45.1385 +                  . . .
 45.1386 +               C: a047 NOOP
 45.1387 +               S: * 22 EXPUNGE
 45.1388 +               S: * 23 EXISTS
 45.1389 +               S: * 3 RECENT
 45.1390 +               S: * 14 FETCH (FLAGS (\Seen \Deleted))
 45.1391 +               S: a047 OK NOOP completed
 45.1392 +
 45.1393 +
 45.1394 +
 45.1395 +
 45.1396 +
 45.1397 +
 45.1398 +
 45.1399 +
 45.1400 +
 45.1401 +
 45.1402 +
 45.1403 +
 45.1404 +
 45.1405 +Crispin                     Standards Track                    [Page 25]
 45.1406 +
 45.1407 +RFC 3501                         IMAPv4                       March 2003
 45.1408 +
 45.1409 +
 45.1410 +6.1.3.  LOGOUT Command
 45.1411 +
 45.1412 +   Arguments:  none
 45.1413 +
 45.1414 +   Responses:  REQUIRED untagged response: BYE
 45.1415 +
 45.1416 +   Result:     OK - logout completed
 45.1417 +               BAD - command unknown or arguments invalid
 45.1418 +
 45.1419 +      The LOGOUT command informs the server that the client is done with
 45.1420 +      the connection.  The server MUST send a BYE untagged response
 45.1421 +      before the (tagged) OK response, and then close the network
 45.1422 +      connection.
 45.1423 +
 45.1424 +   Example:    C: A023 LOGOUT
 45.1425 +               S: * BYE IMAP4rev1 Server logging out
 45.1426 +               S: A023 OK LOGOUT completed
 45.1427 +               (Server and client then close the connection)
 45.1428 +
 45.1429 +6.2.    Client Commands - Not Authenticated State
 45.1430 +
 45.1431 +   In the not authenticated state, the AUTHENTICATE or LOGIN command
 45.1432 +   establishes authentication and enters the authenticated state.  The
 45.1433 +   AUTHENTICATE command provides a general mechanism for a variety of
 45.1434 +   authentication techniques, privacy protection, and integrity
 45.1435 +   checking; whereas the LOGIN command uses a traditional user name and
 45.1436 +   plaintext password pair and has no means of establishing privacy
 45.1437 +   protection or integrity checking.
 45.1438 +
 45.1439 +   The STARTTLS command is an alternate form of establishing session
 45.1440 +   privacy protection and integrity checking, but does not establish
 45.1441 +   authentication or enter the authenticated state.
 45.1442 +
 45.1443 +   Server implementations MAY allow access to certain mailboxes without
 45.1444 +   establishing authentication.  This can be done by means of the
 45.1445 +   ANONYMOUS [SASL] authenticator described in [ANONYMOUS].  An older
 45.1446 +   convention is a LOGIN command using the userid "anonymous"; in this
 45.1447 +   case, a password is required although the server may choose to accept
 45.1448 +   any password.  The restrictions placed on anonymous users are
 45.1449 +   implementation-dependent.
 45.1450 +
 45.1451 +   Once authenticated (including as anonymous), it is not possible to
 45.1452 +   re-enter not authenticated state.
 45.1453 +
 45.1454 +
 45.1455 +
 45.1456 +
 45.1457 +
 45.1458 +
 45.1459 +
 45.1460 +
 45.1461 +Crispin                     Standards Track                    [Page 26]
 45.1462 +
 45.1463 +RFC 3501                         IMAPv4                       March 2003
 45.1464 +
 45.1465 +
 45.1466 +   In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
 45.1467 +   the following commands are valid in the not authenticated state:
 45.1468 +   STARTTLS, AUTHENTICATE and LOGIN.  See the Security Considerations
 45.1469 +   section for important information about these commands.
 45.1470 +
 45.1471 +6.2.1.  STARTTLS Command
 45.1472 +
 45.1473 +   Arguments:  none
 45.1474 +
 45.1475 +   Responses:  no specific response for this command
 45.1476 +
 45.1477 +   Result:     OK - starttls completed, begin TLS negotiation
 45.1478 +               BAD - command unknown or arguments invalid
 45.1479 +
 45.1480 +      A [TLS] negotiation begins immediately after the CRLF at the end
 45.1481 +      of the tagged OK response from the server.  Once a client issues a
 45.1482 +      STARTTLS command, it MUST NOT issue further commands until a
 45.1483 +      server response is seen and the [TLS] negotiation is complete.
 45.1484 +
 45.1485 +      The server remains in the non-authenticated state, even if client
 45.1486 +      credentials are supplied during the [TLS] negotiation.  This does
 45.1487 +      not preclude an authentication mechanism such as EXTERNAL (defined
 45.1488 +      in [SASL]) from using client identity determined by the [TLS]
 45.1489 +      negotiation.
 45.1490 +
 45.1491 +      Once [TLS] has been started, the client MUST discard cached
 45.1492 +      information about server capabilities and SHOULD re-issue the
 45.1493 +      CAPABILITY command.  This is necessary to protect against man-in-
 45.1494 +      the-middle attacks which alter the capabilities list prior to
 45.1495 +      STARTTLS.  The server MAY advertise different capabilities after
 45.1496 +      STARTTLS.
 45.1497 +
 45.1498 +   Example:    C: a001 CAPABILITY
 45.1499 +               S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
 45.1500 +               S: a001 OK CAPABILITY completed
 45.1501 +               C: a002 STARTTLS
 45.1502 +               S: a002 OK Begin TLS negotiation now
 45.1503 +               <TLS negotiation, further commands are under [TLS] layer>
 45.1504 +               C: a003 CAPABILITY
 45.1505 +               S: * CAPABILITY IMAP4rev1 AUTH=PLAIN
 45.1506 +               S: a003 OK CAPABILITY completed
 45.1507 +               C: a004 LOGIN joe password
 45.1508 +               S: a004 OK LOGIN completed
 45.1509 +
 45.1510 +
 45.1511 +
 45.1512 +
 45.1513 +
 45.1514 +
 45.1515 +
 45.1516 +
 45.1517 +Crispin                     Standards Track                    [Page 27]
 45.1518 +
 45.1519 +RFC 3501                         IMAPv4                       March 2003
 45.1520 +
 45.1521 +
 45.1522 +6.2.2.  AUTHENTICATE Command
 45.1523 +
 45.1524 +   Arguments:  authentication mechanism name
 45.1525 +
 45.1526 +   Responses:  continuation data can be requested
 45.1527 +
 45.1528 +   Result:     OK - authenticate completed, now in authenticated state
 45.1529 +               NO - authenticate failure: unsupported authentication
 45.1530 +                    mechanism, credentials rejected
 45.1531 +               BAD - command unknown or arguments invalid,
 45.1532 +                    authentication exchange cancelled
 45.1533 +
 45.1534 +      The AUTHENTICATE command indicates a [SASL] authentication
 45.1535 +      mechanism to the server.  If the server supports the requested
 45.1536 +      authentication mechanism, it performs an authentication protocol
 45.1537 +      exchange to authenticate and identify the client.  It MAY also
 45.1538 +      negotiate an OPTIONAL security layer for subsequent protocol
 45.1539 +      interactions.  If the requested authentication mechanism is not
 45.1540 +      supported, the server SHOULD reject the AUTHENTICATE command by
 45.1541 +      sending a tagged NO response.
 45.1542 +
 45.1543 +      The AUTHENTICATE command does not support the optional "initial
 45.1544 +      response" feature of [SASL].  Section 5.1 of [SASL] specifies how
 45.1545 +      to handle an authentication mechanism which uses an initial
 45.1546 +      response.
 45.1547 +
 45.1548 +      The service name specified by this protocol's profile of [SASL] is
 45.1549 +      "imap".
 45.1550 +
 45.1551 +      The authentication protocol exchange consists of a series of
 45.1552 +      server challenges and client responses that are specific to the
 45.1553 +      authentication mechanism.  A server challenge consists of a
 45.1554 +      command continuation request response with the "+" token followed
 45.1555 +      by a BASE64 encoded string.  The client response consists of a
 45.1556 +      single line consisting of a BASE64 encoded string.  If the client
 45.1557 +      wishes to cancel an authentication exchange, it issues a line
 45.1558 +      consisting of a single "*".  If the server receives such a
 45.1559 +      response, it MUST reject the AUTHENTICATE command by sending a
 45.1560 +      tagged BAD response.
 45.1561 +
 45.1562 +      If a security layer is negotiated through the [SASL]
 45.1563 +      authentication exchange, it takes effect immediately following the
 45.1564 +      CRLF that concludes the authentication exchange for the client,
 45.1565 +      and the CRLF of the tagged OK response for the server.
 45.1566 +
 45.1567 +      While client and server implementations MUST implement the
 45.1568 +      AUTHENTICATE command itself, it is not required to implement any
 45.1569 +      authentication mechanisms other than the PLAIN mechanism described
 45.1570 +
 45.1571 +
 45.1572 +
 45.1573 +Crispin                     Standards Track                    [Page 28]
 45.1574 +
 45.1575 +RFC 3501                         IMAPv4                       March 2003
 45.1576 +
 45.1577 +
 45.1578 +      in [IMAP-TLS].  Also, an authentication mechanism is not required
 45.1579 +      to support any security layers.
 45.1580 +
 45.1581 +           Note: a server implementation MUST implement a
 45.1582 +           configuration in which it does NOT permit any plaintext
 45.1583 +           password mechanisms, unless either the STARTTLS command
 45.1584 +           has been negotiated or some other mechanism that
 45.1585 +           protects the session from password snooping has been
 45.1586 +           provided.  Server sites SHOULD NOT use any configuration
 45.1587 +           which permits a plaintext password mechanism without
 45.1588 +           such a protection mechanism against password snooping.
 45.1589 +           Client and server implementations SHOULD implement
 45.1590 +           additional [SASL] mechanisms that do not use plaintext
 45.1591 +           passwords, such the GSSAPI mechanism described in [SASL]
 45.1592 +           and/or the [DIGEST-MD5] mechanism.
 45.1593 +
 45.1594 +      Servers and clients can support multiple authentication
 45.1595 +      mechanisms.  The server SHOULD list its supported authentication
 45.1596 +      mechanisms in the response to the CAPABILITY command so that the
 45.1597 +      client knows which authentication mechanisms to use.
 45.1598 +
 45.1599 +      A server MAY include a CAPABILITY response code in the tagged OK
 45.1600 +      response of a successful AUTHENTICATE command in order to send
 45.1601 +      capabilities automatically.  It is unnecessary for a client to
 45.1602 +      send a separate CAPABILITY command if it recognizes these
 45.1603 +      automatic capabilities.  This should only be done if a security
 45.1604 +      layer was not negotiated by the AUTHENTICATE command, because the
 45.1605 +      tagged OK response as part of an AUTHENTICATE command is not
 45.1606 +      protected by encryption/integrity checking.  [SASL] requires the
 45.1607 +      client to re-issue a CAPABILITY command in this case.
 45.1608 +
 45.1609 +      If an AUTHENTICATE command fails with a NO response, the client
 45.1610 +      MAY try another authentication mechanism by issuing another
 45.1611 +      AUTHENTICATE command.  It MAY also attempt to authenticate by
 45.1612 +      using the LOGIN command (see section 6.2.3 for more detail).  In
 45.1613 +      other words, the client MAY request authentication types in
 45.1614 +      decreasing order of preference, with the LOGIN command as a last
 45.1615 +      resort.
 45.1616 +
 45.1617 +      The authorization identity passed from the client to the server
 45.1618 +      during the authentication exchange is interpreted by the server as
 45.1619 +      the user name whose privileges the client is requesting.
 45.1620 +
 45.1621 +
 45.1622 +
 45.1623 +
 45.1624 +
 45.1625 +
 45.1626 +
 45.1627 +
 45.1628 +
 45.1629 +Crispin                     Standards Track                    [Page 29]
 45.1630 +
 45.1631 +RFC 3501                         IMAPv4                       March 2003
 45.1632 +
 45.1633 +
 45.1634 +   Example:    S: * OK IMAP4rev1 Server
 45.1635 +               C: A001 AUTHENTICATE GSSAPI
 45.1636 +               S: +
 45.1637 +               C: YIIB+wYJKoZIhvcSAQICAQBuggHqMIIB5qADAgEFoQMCAQ6iBw
 45.1638 +                  MFACAAAACjggEmYYIBIjCCAR6gAwIBBaESGxB1Lndhc2hpbmd0
 45.1639 +                  b24uZWR1oi0wK6ADAgEDoSQwIhsEaW1hcBsac2hpdmFtcy5jYW
 45.1640 +                  Mud2FzaGluZ3Rvbi5lZHWjgdMwgdCgAwIBAaEDAgEDooHDBIHA
 45.1641 +                  cS1GSa5b+fXnPZNmXB9SjL8Ollj2SKyb+3S0iXMljen/jNkpJX
 45.1642 +                  AleKTz6BQPzj8duz8EtoOuNfKgweViyn/9B9bccy1uuAE2HI0y
 45.1643 +                  C/PHXNNU9ZrBziJ8Lm0tTNc98kUpjXnHZhsMcz5Mx2GR6dGknb
 45.1644 +                  I0iaGcRerMUsWOuBmKKKRmVMMdR9T3EZdpqsBd7jZCNMWotjhi
 45.1645 +                  vd5zovQlFqQ2Wjc2+y46vKP/iXxWIuQJuDiisyXF0Y8+5GTpAL
 45.1646 +                  pHDc1/pIGmMIGjoAMCAQGigZsEgZg2on5mSuxoDHEA1w9bcW9n
 45.1647 +                  FdFxDKpdrQhVGVRDIzcCMCTzvUboqb5KjY1NJKJsfjRQiBYBdE
 45.1648 +                  NKfzK+g5DlV8nrw81uOcP8NOQCLR5XkoMHC0Dr/80ziQzbNqhx
 45.1649 +                  O6652Npft0LQwJvenwDI13YxpwOdMXzkWZN/XrEqOWp6GCgXTB
 45.1650 +                  vCyLWLlWnbaUkZdEYbKHBPjd8t/1x5Yg==
 45.1651 +               S: + YGgGCSqGSIb3EgECAgIAb1kwV6ADAgEFoQMCAQ+iSzBJoAMC
 45.1652 +                  AQGiQgRAtHTEuOP2BXb9sBYFR4SJlDZxmg39IxmRBOhXRKdDA0
 45.1653 +                  uHTCOT9Bq3OsUTXUlk0CsFLoa8j+gvGDlgHuqzWHPSQg==
 45.1654 +               C:
 45.1655 +               S: + YDMGCSqGSIb3EgECAgIBAAD/////6jcyG4GE3KkTzBeBiVHe
 45.1656 +                  ceP2CWY0SR0fAQAgAAQEBAQ=
 45.1657 +               C: YDMGCSqGSIb3EgECAgIBAAD/////3LQBHXTpFfZgrejpLlLImP
 45.1658 +                  wkhbfa2QteAQAgAG1yYwE=
 45.1659 +               S: A001 OK GSSAPI authentication successful
 45.1660 +
 45.1661 +        Note: The line breaks within server challenges and client
 45.1662 +        responses are for editorial clarity and are not in real
 45.1663 +        authenticators.
 45.1664 +
 45.1665 +
 45.1666 +6.2.3.  LOGIN Command
 45.1667 +
 45.1668 +   Arguments:  user name
 45.1669 +               password
 45.1670 +
 45.1671 +   Responses:  no specific responses for this command
 45.1672 +
 45.1673 +   Result:     OK - login completed, now in authenticated state
 45.1674 +               NO - login failure: user name or password rejected
 45.1675 +               BAD - command unknown or arguments invalid
 45.1676 +
 45.1677 +      The LOGIN command identifies the client to the server and carries
 45.1678 +      the plaintext password authenticating this user.
 45.1679 +
 45.1680 +
 45.1681 +
 45.1682 +
 45.1683 +
 45.1684 +
 45.1685 +Crispin                     Standards Track                    [Page 30]
 45.1686 +
 45.1687 +RFC 3501                         IMAPv4                       March 2003
 45.1688 +
 45.1689 +
 45.1690 +      A server MAY include a CAPABILITY response code in the tagged OK
 45.1691 +      response to a successful LOGIN command in order to send
 45.1692 +      capabilities automatically.  It is unnecessary for a client to
 45.1693 +      send a separate CAPABILITY command if it recognizes these
 45.1694 +      automatic capabilities.
 45.1695 +
 45.1696 +   Example:    C: a001 LOGIN SMITH SESAME
 45.1697 +               S: a001 OK LOGIN completed
 45.1698 +
 45.1699 +        Note: Use of the LOGIN command over an insecure network
 45.1700 +        (such as the Internet) is a security risk, because anyone
 45.1701 +        monitoring network traffic can obtain plaintext passwords.
 45.1702 +        The LOGIN command SHOULD NOT be used except as a last
 45.1703 +        resort, and it is recommended that client implementations
 45.1704 +        have a means to disable any automatic use of the LOGIN
 45.1705 +        command.
 45.1706 +
 45.1707 +        Unless either the STARTTLS command has been negotiated or
 45.1708 +        some other mechanism that protects the session from
 45.1709 +        password snooping has been provided, a server
 45.1710 +        implementation MUST implement a configuration in which it
 45.1711 +        advertises the LOGINDISABLED capability and does NOT permit
 45.1712 +        the LOGIN command.  Server sites SHOULD NOT use any
 45.1713 +        configuration which permits the LOGIN command without such
 45.1714 +        a protection mechanism against password snooping.  A client
 45.1715 +        implementation MUST NOT send a LOGIN command if the
 45.1716 +        LOGINDISABLED capability is advertised.
 45.1717 +
 45.1718 +6.3.    Client Commands - Authenticated State
 45.1719 +
 45.1720 +   In the authenticated state, commands that manipulate mailboxes as
 45.1721 +   atomic entities are permitted.  Of these commands, the SELECT and
 45.1722 +   EXAMINE commands will select a mailbox for access and enter the
 45.1723 +   selected state.
 45.1724 +
 45.1725 +   In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
 45.1726 +   the following commands are valid in the authenticated state: SELECT,
 45.1727 +   EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB,
 45.1728 +   STATUS, and APPEND.
 45.1729 +
 45.1730 +
 45.1731 +
 45.1732 +
 45.1733 +
 45.1734 +
 45.1735 +
 45.1736 +
 45.1737 +
 45.1738 +
 45.1739 +
 45.1740 +
 45.1741 +Crispin                     Standards Track                    [Page 31]
 45.1742 +
 45.1743 +RFC 3501                         IMAPv4                       March 2003
 45.1744 +
 45.1745 +
 45.1746 +6.3.1.  SELECT Command
 45.1747 +
 45.1748 +   Arguments:  mailbox name
 45.1749 +
 45.1750 +   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
 45.1751 +               REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
 45.1752 +               UIDNEXT, UIDVALIDITY
 45.1753 +
 45.1754 +   Result:     OK - select completed, now in selected state
 45.1755 +               NO - select failure, now in authenticated state: no
 45.1756 +                    such mailbox, can't access mailbox
 45.1757 +               BAD - command unknown or arguments invalid
 45.1758 +
 45.1759 +      The SELECT command selects a mailbox so that messages in the
 45.1760 +      mailbox can be accessed.  Before returning an OK to the client,
 45.1761 +      the server MUST send the following untagged data to the client.
 45.1762 +      Note that earlier versions of this protocol only required the
 45.1763 +      FLAGS, EXISTS, and RECENT untagged data; consequently, client
 45.1764 +      implementations SHOULD implement default behavior for missing data
 45.1765 +      as discussed with the individual item.
 45.1766 +
 45.1767 +         FLAGS       Defined flags in the mailbox.  See the description
 45.1768 +                     of the FLAGS response for more detail.
 45.1769 +
 45.1770 +         <n> EXISTS  The number of messages in the mailbox.  See the
 45.1771 +                     description of the EXISTS response for more detail.
 45.1772 +
 45.1773 +         <n> RECENT  The number of messages with the \Recent flag set.
 45.1774 +                     See the description of the RECENT response for more
 45.1775 +                     detail.
 45.1776 +
 45.1777 +         OK [UNSEEN <n>]
 45.1778 +                     The message sequence number of the first unseen
 45.1779 +                     message in the mailbox.  If this is missing, the
 45.1780 +                     client can not make any assumptions about the first
 45.1781 +                     unseen message in the mailbox, and needs to issue a
 45.1782 +                     SEARCH command if it wants to find it.
 45.1783 +
 45.1784 +         OK [PERMANENTFLAGS (<list of flags>)]
 45.1785 +                     A list of message flags that the client can change
 45.1786 +                     permanently.  If this is missing, the client should
 45.1787 +                     assume that all flags can be changed permanently.
 45.1788 +
 45.1789 +         OK [UIDNEXT <n>]
 45.1790 +                     The next unique identifier value.  Refer to section
 45.1791 +                     2.3.1.1 for more information.  If this is missing,
 45.1792 +                     the client can not make any assumptions about the
 45.1793 +                     next unique identifier value.
 45.1794 +
 45.1795 +
 45.1796 +
 45.1797 +Crispin                     Standards Track                    [Page 32]
 45.1798 +
 45.1799 +RFC 3501                         IMAPv4                       March 2003
 45.1800 +
 45.1801 +
 45.1802 +         OK [UIDVALIDITY <n>]
 45.1803 +                     The unique identifier validity value.  Refer to
 45.1804 +                     section 2.3.1.1 for more information.  If this is
 45.1805 +                     missing, the server does not support unique
 45.1806 +                     identifiers.
 45.1807 +
 45.1808 +      Only one mailbox can be selected at a time in a connection;
 45.1809 +      simultaneous access to multiple mailboxes requires multiple
 45.1810 +      connections.  The SELECT command automatically deselects any
 45.1811 +      currently selected mailbox before attempting the new selection.
 45.1812 +      Consequently, if a mailbox is selected and a SELECT command that
 45.1813 +      fails is attempted, no mailbox is selected.
 45.1814 +
 45.1815 +      If the client is permitted to modify the mailbox, the server
 45.1816 +      SHOULD prefix the text of the tagged OK response with the
 45.1817 +      "[READ-WRITE]" response code.
 45.1818 +
 45.1819 +      If the client is not permitted to modify the mailbox but is
 45.1820 +      permitted read access, the mailbox is selected as read-only, and
 45.1821 +      the server MUST prefix the text of the tagged OK response to
 45.1822 +      SELECT with the "[READ-ONLY]" response code.  Read-only access
 45.1823 +      through SELECT differs from the EXAMINE command in that certain
 45.1824 +      read-only mailboxes MAY permit the change of permanent state on a
 45.1825 +      per-user (as opposed to global) basis.  Netnews messages marked in
 45.1826 +      a server-based .newsrc file are an example of such per-user
 45.1827 +      permanent state that can be modified with read-only mailboxes.
 45.1828 +
 45.1829 +   Example:    C: A142 SELECT INBOX
 45.1830 +               S: * 172 EXISTS
 45.1831 +               S: * 1 RECENT
 45.1832 +               S: * OK [UNSEEN 12] Message 12 is first unseen
 45.1833 +               S: * OK [UIDVALIDITY 3857529045] UIDs valid
 45.1834 +               S: * OK [UIDNEXT 4392] Predicted next UID
 45.1835 +               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
 45.1836 +               S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
 45.1837 +               S: A142 OK [READ-WRITE] SELECT completed
 45.1838 +
 45.1839 +
 45.1840 +
 45.1841 +
 45.1842 +
 45.1843 +
 45.1844 +
 45.1845 +
 45.1846 +
 45.1847 +
 45.1848 +
 45.1849 +
 45.1850 +
 45.1851 +
 45.1852 +
 45.1853 +Crispin                     Standards Track                    [Page 33]
 45.1854 +
 45.1855 +RFC 3501                         IMAPv4                       March 2003
 45.1856 +
 45.1857 +
 45.1858 +6.3.2.  EXAMINE Command
 45.1859 +
 45.1860 +   Arguments:  mailbox name
 45.1861 +
 45.1862 +   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
 45.1863 +               REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
 45.1864 +               UIDNEXT, UIDVALIDITY
 45.1865 +
 45.1866 +   Result:     OK - examine completed, now in selected state
 45.1867 +               NO - examine failure, now in authenticated state: no
 45.1868 +                    such mailbox, can't access mailbox
 45.1869 +               BAD - command unknown or arguments invalid
 45.1870 +
 45.1871 +      The EXAMINE command is identical to SELECT and returns the same
 45.1872 +      output; however, the selected mailbox is identified as read-only.
 45.1873 +      No changes to the permanent state of the mailbox, including
 45.1874 +      per-user state, are permitted; in particular, EXAMINE MUST NOT
 45.1875 +      cause messages to lose the \Recent flag.
 45.1876 +
 45.1877 +      The text of the tagged OK response to the EXAMINE command MUST
 45.1878 +      begin with the "[READ-ONLY]" response code.
 45.1879 +
 45.1880 +   Example:    C: A932 EXAMINE blurdybloop
 45.1881 +               S: * 17 EXISTS
 45.1882 +               S: * 2 RECENT
 45.1883 +               S: * OK [UNSEEN 8] Message 8 is first unseen
 45.1884 +               S: * OK [UIDVALIDITY 3857529045] UIDs valid
 45.1885 +               S: * OK [UIDNEXT 4392] Predicted next UID
 45.1886 +               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
 45.1887 +               S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
 45.1888 +               S: A932 OK [READ-ONLY] EXAMINE completed
 45.1889 +
 45.1890 +
 45.1891 +6.3.3.  CREATE Command
 45.1892 +
 45.1893 +   Arguments:  mailbox name
 45.1894 +
 45.1895 +   Responses:  no specific responses for this command
 45.1896 +
 45.1897 +   Result:     OK - create completed
 45.1898 +               NO - create failure: can't create mailbox with that name
 45.1899 +               BAD - command unknown or arguments invalid
 45.1900 +
 45.1901 +      The CREATE command creates a mailbox with the given name.  An OK
 45.1902 +      response is returned only if a new mailbox with that name has been
 45.1903 +      created.  It is an error to attempt to create INBOX or a mailbox
 45.1904 +      with a name that refers to an extant mailbox.  Any error in
 45.1905 +      creation will return a tagged NO response.
 45.1906 +
 45.1907 +
 45.1908 +
 45.1909 +Crispin                     Standards Track                    [Page 34]
 45.1910 +
 45.1911 +RFC 3501                         IMAPv4                       March 2003
 45.1912 +
 45.1913 +
 45.1914 +      If the mailbox name is suffixed with the server's hierarchy
 45.1915 +      separator character (as returned from the server by a LIST
 45.1916 +      command), this is a declaration that the client intends to create
 45.1917 +      mailbox names under this name in the hierarchy.  Server
 45.1918 +      implementations that do not require this declaration MUST ignore
 45.1919 +      the declaration.  In any case, the name created is without the
 45.1920 +      trailing hierarchy delimiter.
 45.1921 +
 45.1922 +      If the server's hierarchy separator character appears elsewhere in
 45.1923 +      the name, the server SHOULD create any superior hierarchical names
 45.1924 +      that are needed for the CREATE command to be successfully
 45.1925 +      completed.  In other words, an attempt to create "foo/bar/zap" on
 45.1926 +      a server in which "/" is the hierarchy separator character SHOULD
 45.1927 +      create foo/ and foo/bar/ if they do not already exist.
 45.1928 +
 45.1929 +      If a new mailbox is created with the same name as a mailbox which
 45.1930 +      was deleted, its unique identifiers MUST be greater than any
 45.1931 +      unique identifiers used in the previous incarnation of the mailbox
 45.1932 +      UNLESS the new incarnation has a different unique identifier
 45.1933 +      validity value.  See the description of the UID command for more
 45.1934 +      detail.
 45.1935 +
 45.1936 +   Example:    C: A003 CREATE owatagusiam/
 45.1937 +               S: A003 OK CREATE completed
 45.1938 +               C: A004 CREATE owatagusiam/blurdybloop
 45.1939 +               S: A004 OK CREATE completed
 45.1940 +
 45.1941 +        Note: The interpretation of this example depends on whether
 45.1942 +        "/" was returned as the hierarchy separator from LIST.  If
 45.1943 +        "/" is the hierarchy separator, a new level of hierarchy
 45.1944 +        named "owatagusiam" with a member called "blurdybloop" is
 45.1945 +        created.  Otherwise, two mailboxes at the same hierarchy
 45.1946 +        level are created.
 45.1947 +
 45.1948 +
 45.1949 +6.3.4.  DELETE Command
 45.1950 +
 45.1951 +   Arguments:  mailbox name
 45.1952 +
 45.1953 +   Responses:  no specific responses for this command
 45.1954 +
 45.1955 +   Result:     OK - delete completed
 45.1956 +               NO - delete failure: can't delete mailbox with that name
 45.1957 +               BAD - command unknown or arguments invalid
 45.1958 +
 45.1959 +
 45.1960 +
 45.1961 +
 45.1962 +
 45.1963 +
 45.1964 +
 45.1965 +Crispin                     Standards Track                    [Page 35]
 45.1966 +
 45.1967 +RFC 3501                         IMAPv4                       March 2003
 45.1968 +
 45.1969 +
 45.1970 +      The DELETE command permanently removes the mailbox with the given
 45.1971 +      name.  A tagged OK response is returned only if the mailbox has
 45.1972 +      been deleted.  It is an error to attempt to delete INBOX or a
 45.1973 +      mailbox name that does not exist.
 45.1974 +
 45.1975 +      The DELETE command MUST NOT remove inferior hierarchical names.
 45.1976 +      For example, if a mailbox "foo" has an inferior "foo.bar"
 45.1977 +      (assuming "." is the hierarchy delimiter character), removing
 45.1978 +      "foo" MUST NOT remove "foo.bar".  It is an error to attempt to
 45.1979 +      delete a name that has inferior hierarchical names and also has
 45.1980 +      the \Noselect mailbox name attribute (see the description of the
 45.1981 +      LIST response for more details).
 45.1982 +
 45.1983 +      It is permitted to delete a name that has inferior hierarchical
 45.1984 +      names and does not have the \Noselect mailbox name attribute.  In
 45.1985 +      this case, all messages in that mailbox are removed, and the name
 45.1986 +      will acquire the \Noselect mailbox name attribute.
 45.1987 +
 45.1988 +      The value of the highest-used unique identifier of the deleted
 45.1989 +      mailbox MUST be preserved so that a new mailbox created with the
 45.1990 +      same name will not reuse the identifiers of the former
 45.1991 +      incarnation, UNLESS the new incarnation has a different unique
 45.1992 +      identifier validity value.  See the description of the UID command
 45.1993 +      for more detail.
 45.1994 +
 45.1995 +   Examples:   C: A682 LIST "" *
 45.1996 +               S: * LIST () "/" blurdybloop
 45.1997 +               S: * LIST (\Noselect) "/" foo
 45.1998 +               S: * LIST () "/" foo/bar
 45.1999 +               S: A682 OK LIST completed
 45.2000 +               C: A683 DELETE blurdybloop
 45.2001 +               S: A683 OK DELETE completed
 45.2002 +               C: A684 DELETE foo
 45.2003 +               S: A684 NO Name "foo" has inferior hierarchical names
 45.2004 +               C: A685 DELETE foo/bar
 45.2005 +               S: A685 OK DELETE Completed
 45.2006 +               C: A686 LIST "" *
 45.2007 +               S: * LIST (\Noselect) "/" foo
 45.2008 +               S: A686 OK LIST completed
 45.2009 +               C: A687 DELETE foo
 45.2010 +               S: A687 OK DELETE Completed
 45.2011 +
 45.2012 +
 45.2013 +
 45.2014 +
 45.2015 +
 45.2016 +
 45.2017 +
 45.2018 +
 45.2019 +
 45.2020 +
 45.2021 +Crispin                     Standards Track                    [Page 36]
 45.2022 +
 45.2023 +RFC 3501                         IMAPv4                       March 2003
 45.2024 +
 45.2025 +
 45.2026 +               C: A82 LIST "" *
 45.2027 +               S: * LIST () "." blurdybloop
 45.2028 +               S: * LIST () "." foo
 45.2029 +               S: * LIST () "." foo.bar
 45.2030 +               S: A82 OK LIST completed
 45.2031 +               C: A83 DELETE blurdybloop
 45.2032 +               S: A83 OK DELETE completed
 45.2033 +               C: A84 DELETE foo
 45.2034 +               S: A84 OK DELETE Completed
 45.2035 +               C: A85 LIST "" *
 45.2036 +               S: * LIST () "." foo.bar
 45.2037 +               S: A85 OK LIST completed
 45.2038 +               C: A86 LIST "" %
 45.2039 +               S: * LIST (\Noselect) "." foo
 45.2040 +               S: A86 OK LIST completed
 45.2041 +
 45.2042 +
 45.2043 +6.3.5.  RENAME Command
 45.2044 +
 45.2045 +   Arguments:  existing mailbox name
 45.2046 +               new mailbox name
 45.2047 +
 45.2048 +   Responses:  no specific responses for this command
 45.2049 +
 45.2050 +   Result:     OK - rename completed
 45.2051 +               NO - rename failure: can't rename mailbox with that name,
 45.2052 +                    can't rename to mailbox with that name
 45.2053 +               BAD - command unknown or arguments invalid
 45.2054 +
 45.2055 +      The RENAME command changes the name of a mailbox.  A tagged OK
 45.2056 +      response is returned only if the mailbox has been renamed.  It is
 45.2057 +      an error to attempt to rename from a mailbox name that does not
 45.2058 +      exist or to a mailbox name that already exists.  Any error in
 45.2059 +      renaming will return a tagged NO response.
 45.2060 +
 45.2061 +      If the name has inferior hierarchical names, then the inferior
 45.2062 +      hierarchical names MUST also be renamed.  For example, a rename of
 45.2063 +      "foo" to "zap" will rename "foo/bar" (assuming "/" is the
 45.2064 +      hierarchy delimiter character) to "zap/bar".
 45.2065 +
 45.2066 +      If the server's hierarchy separator character appears in the name,
 45.2067 +      the server SHOULD create any superior hierarchical names that are
 45.2068 +      needed for the RENAME command to complete successfully.  In other
 45.2069 +      words, an attempt to rename "foo/bar/zap" to baz/rag/zowie on a
 45.2070 +      server in which "/" is the hierarchy separator character SHOULD
 45.2071 +      create baz/ and baz/rag/ if they do not already exist.
 45.2072 +
 45.2073 +
 45.2074 +
 45.2075 +
 45.2076 +
 45.2077 +Crispin                     Standards Track                    [Page 37]
 45.2078 +
 45.2079 +RFC 3501                         IMAPv4                       March 2003
 45.2080 +
 45.2081 +
 45.2082 +      The value of the highest-used unique identifier of the old mailbox
 45.2083 +      name MUST be preserved so that a new mailbox created with the same
 45.2084 +      name will not reuse the identifiers of the former incarnation,
 45.2085 +      UNLESS the new incarnation has a different unique identifier
 45.2086 +      validity value.  See the description of the UID command for more
 45.2087 +      detail.
 45.2088 +
 45.2089 +      Renaming INBOX is permitted, and has special behavior.  It moves
 45.2090 +      all messages in INBOX to a new mailbox with the given name,
 45.2091 +      leaving INBOX empty.  If the server implementation supports
 45.2092 +      inferior hierarchical names of INBOX, these are unaffected by a
 45.2093 +      rename of INBOX.
 45.2094 +
 45.2095 +   Examples:   C: A682 LIST "" *
 45.2096 +               S: * LIST () "/" blurdybloop
 45.2097 +               S: * LIST (\Noselect) "/" foo
 45.2098 +               S: * LIST () "/" foo/bar
 45.2099 +               S: A682 OK LIST completed
 45.2100 +               C: A683 RENAME blurdybloop sarasoop
 45.2101 +               S: A683 OK RENAME completed
 45.2102 +               C: A684 RENAME foo zowie
 45.2103 +               S: A684 OK RENAME Completed
 45.2104 +               C: A685 LIST "" *
 45.2105 +               S: * LIST () "/" sarasoop
 45.2106 +               S: * LIST (\Noselect) "/" zowie
 45.2107 +               S: * LIST () "/" zowie/bar
 45.2108 +               S: A685 OK LIST completed
 45.2109 +
 45.2110 +               C: Z432 LIST "" *
 45.2111 +               S: * LIST () "." INBOX
 45.2112 +               S: * LIST () "." INBOX.bar
 45.2113 +               S: Z432 OK LIST completed
 45.2114 +               C: Z433 RENAME INBOX old-mail
 45.2115 +               S: Z433 OK RENAME completed
 45.2116 +               C: Z434 LIST "" *
 45.2117 +               S: * LIST () "." INBOX
 45.2118 +               S: * LIST () "." INBOX.bar
 45.2119 +               S: * LIST () "." old-mail
 45.2120 +               S: Z434 OK LIST completed
 45.2121 +
 45.2122 +
 45.2123 +
 45.2124 +
 45.2125 +
 45.2126 +
 45.2127 +
 45.2128 +
 45.2129 +
 45.2130 +
 45.2131 +
 45.2132 +
 45.2133 +Crispin                     Standards Track                    [Page 38]
 45.2134 +
 45.2135 +RFC 3501                         IMAPv4                       March 2003
 45.2136 +
 45.2137 +
 45.2138 +6.3.6.  SUBSCRIBE Command
 45.2139 +
 45.2140 +   Arguments:  mailbox
 45.2141 +
 45.2142 +   Responses:  no specific responses for this command
 45.2143 +
 45.2144 +   Result:     OK - subscribe completed
 45.2145 +               NO - subscribe failure: can't subscribe to that name
 45.2146 +               BAD - command unknown or arguments invalid
 45.2147 +
 45.2148 +      The SUBSCRIBE command adds the specified mailbox name to the
 45.2149 +      server's set of "active" or "subscribed" mailboxes as returned by
 45.2150 +      the LSUB command.  This command returns a tagged OK response only
 45.2151 +      if the subscription is successful.
 45.2152 +
 45.2153 +      A server MAY validate the mailbox argument to SUBSCRIBE to verify
 45.2154 +      that it exists.  However, it MUST NOT unilaterally remove an
 45.2155 +      existing mailbox name from the subscription list even if a mailbox
 45.2156 +      by that name no longer exists.
 45.2157 +
 45.2158 +           Note: This requirement is because a server site can
 45.2159 +           choose to routinely remove a mailbox with a well-known
 45.2160 +           name (e.g., "system-alerts") after its contents expire,
 45.2161 +           with the intention of recreating it when new contents
 45.2162 +           are appropriate.
 45.2163 +
 45.2164 +
 45.2165 +   Example:    C: A002 SUBSCRIBE #news.comp.mail.mime
 45.2166 +               S: A002 OK SUBSCRIBE completed
 45.2167 +
 45.2168 +
 45.2169 +6.3.7.  UNSUBSCRIBE Command
 45.2170 +
 45.2171 +   Arguments:  mailbox name
 45.2172 +
 45.2173 +   Responses:  no specific responses for this command
 45.2174 +
 45.2175 +   Result:     OK - unsubscribe completed
 45.2176 +               NO - unsubscribe failure: can't unsubscribe that name
 45.2177 +               BAD - command unknown or arguments invalid
 45.2178 +
 45.2179 +      The UNSUBSCRIBE command removes the specified mailbox name from
 45.2180 +      the server's set of "active" or "subscribed" mailboxes as returned
 45.2181 +      by the LSUB command.  This command returns a tagged OK response
 45.2182 +      only if the unsubscription is successful.
 45.2183 +
 45.2184 +   Example:    C: A002 UNSUBSCRIBE #news.comp.mail.mime
 45.2185 +               S: A002 OK UNSUBSCRIBE completed
 45.2186 +
 45.2187 +
 45.2188 +
 45.2189 +Crispin                     Standards Track                    [Page 39]
 45.2190 +
 45.2191 +RFC 3501                         IMAPv4                       March 2003
 45.2192 +
 45.2193 +
 45.2194 +6.3.8.  LIST Command
 45.2195 +
 45.2196 +   Arguments:  reference name
 45.2197 +               mailbox name with possible wildcards
 45.2198 +
 45.2199 +   Responses:  untagged responses: LIST
 45.2200 +
 45.2201 +   Result:     OK - list completed
 45.2202 +               NO - list failure: can't list that reference or name
 45.2203 +               BAD - command unknown or arguments invalid
 45.2204 +
 45.2205 +      The LIST command returns a subset of names from the complete set
 45.2206 +      of all names available to the client.  Zero or more untagged LIST
 45.2207 +      replies are returned, containing the name attributes, hierarchy
 45.2208 +      delimiter, and name; see the description of the LIST reply for
 45.2209 +      more detail.
 45.2210 +
 45.2211 +      The LIST command SHOULD return its data quickly, without undue
 45.2212 +      delay.  For example, it SHOULD NOT go to excess trouble to
 45.2213 +      calculate the \Marked or \Unmarked status or perform other
 45.2214 +      processing; if each name requires 1 second of processing, then a
 45.2215 +      list of 1200 names would take 20 minutes!
 45.2216 +
 45.2217 +      An empty ("" string) reference name argument indicates that the
 45.2218 +      mailbox name is interpreted as by SELECT.  The returned mailbox
 45.2219 +      names MUST match the supplied mailbox name pattern.  A non-empty
 45.2220 +      reference name argument is the name of a mailbox or a level of
 45.2221 +      mailbox hierarchy, and indicates the context in which the mailbox
 45.2222 +      name is interpreted.
 45.2223 +
 45.2224 +      An empty ("" string) mailbox name argument is a special request to
 45.2225 +      return the hierarchy delimiter and the root name of the name given
 45.2226 +      in the reference.  The value returned as the root MAY be the empty
 45.2227 +      string if the reference is non-rooted or is an empty string.  In
 45.2228 +      all cases, a hierarchy delimiter (or NIL if there is no hierarchy)
 45.2229 +      is returned.  This permits a client to get the hierarchy delimiter
 45.2230 +      (or find out that the mailbox names are flat) even when no
 45.2231 +      mailboxes by that name currently exist.
 45.2232 +
 45.2233 +      The reference and mailbox name arguments are interpreted into a
 45.2234 +      canonical form that represents an unambiguous left-to-right
 45.2235 +      hierarchy.  The returned mailbox names will be in the interpreted
 45.2236 +      form.
 45.2237 +
 45.2238 +
 45.2239 +
 45.2240 +
 45.2241 +
 45.2242 +
 45.2243 +
 45.2244 +
 45.2245 +Crispin                     Standards Track                    [Page 40]
 45.2246 +
 45.2247 +RFC 3501                         IMAPv4                       March 2003
 45.2248 +
 45.2249 +
 45.2250 +           Note: The interpretation of the reference argument is
 45.2251 +           implementation-defined.  It depends upon whether the
 45.2252 +           server implementation has a concept of the "current
 45.2253 +           working directory" and leading "break out characters",
 45.2254 +           which override the current working directory.
 45.2255 +
 45.2256 +           For example, on a server which exports a UNIX or NT
 45.2257 +           filesystem, the reference argument contains the current
 45.2258 +           working directory, and the mailbox name argument would
 45.2259 +           contain the name as interpreted in the current working
 45.2260 +           directory.
 45.2261 +
 45.2262 +           If a server implementation has no concept of break out
 45.2263 +           characters, the canonical form is normally the reference
 45.2264 +           name appended with the mailbox name.  Note that if the
 45.2265 +           server implements the namespace convention (section
 45.2266 +           5.1.2), "#" is a break out character and must be treated
 45.2267 +           as such.
 45.2268 +
 45.2269 +           If the reference argument is not a level of mailbox
 45.2270 +           hierarchy (that is, it is a \NoInferiors name), and/or
 45.2271 +           the reference argument does not end with the hierarchy
 45.2272 +           delimiter, it is implementation-dependent how this is
 45.2273 +           interpreted.  For example, a reference of "foo/bar" and
 45.2274 +           mailbox name of "rag/baz" could be interpreted as
 45.2275 +           "foo/bar/rag/baz", "foo/barrag/baz", or "foo/rag/baz".
 45.2276 +           A client SHOULD NOT use such a reference argument except
 45.2277 +           at the explicit request of the user.  A hierarchical
 45.2278 +           browser MUST NOT make any assumptions about server
 45.2279 +           interpretation of the reference unless the reference is
 45.2280 +           a level of mailbox hierarchy AND ends with the hierarchy
 45.2281 +           delimiter.
 45.2282 +
 45.2283 +      Any part of the reference argument that is included in the
 45.2284 +      interpreted form SHOULD prefix the interpreted form.  It SHOULD
 45.2285 +      also be in the same form as the reference name argument.  This
 45.2286 +      rule permits the client to determine if the returned mailbox name
 45.2287 +      is in the context of the reference argument, or if something about
 45.2288 +      the mailbox argument overrode the reference argument.  Without
 45.2289 +      this rule, the client would have to have knowledge of the server's
 45.2290 +      naming semantics including what characters are "breakouts" that
 45.2291 +      override a naming context.
 45.2292 +
 45.2293 +
 45.2294 +
 45.2295 +
 45.2296 +
 45.2297 +
 45.2298 +
 45.2299 +
 45.2300 +
 45.2301 +Crispin                     Standards Track                    [Page 41]
 45.2302 +
 45.2303 +RFC 3501                         IMAPv4                       March 2003
 45.2304 +
 45.2305 +
 45.2306 +           For example, here are some examples of how references
 45.2307 +           and mailbox names might be interpreted on a UNIX-based
 45.2308 +           server:
 45.2309 +
 45.2310 +               Reference     Mailbox Name  Interpretation
 45.2311 +               ------------  ------------  --------------
 45.2312 +               ~smith/Mail/  foo.*         ~smith/Mail/foo.*
 45.2313 +               archive/      %             archive/%
 45.2314 +               #news.        comp.mail.*   #news.comp.mail.*
 45.2315 +               ~smith/Mail/  /usr/doc/foo  /usr/doc/foo
 45.2316 +               archive/      ~fred/Mail/*  ~fred/Mail/*
 45.2317 +
 45.2318 +           The first three examples demonstrate interpretations in
 45.2319 +           the context of the reference argument.  Note that
 45.2320 +           "~smith/Mail" SHOULD NOT be transformed into something
 45.2321 +           like "/u2/users/smith/Mail", or it would be impossible
 45.2322 +           for the client to determine that the interpretation was
 45.2323 +           in the context of the reference.
 45.2324 +
 45.2325 +      The character "*" is a wildcard, and matches zero or more
 45.2326 +      characters at this position.  The character "%" is similar to "*",
 45.2327 +      but it does not match a hierarchy delimiter.  If the "%" wildcard
 45.2328 +      is the last character of a mailbox name argument, matching levels
 45.2329 +      of hierarchy are also returned.  If these levels of hierarchy are
 45.2330 +      not also selectable mailboxes, they are returned with the
 45.2331 +      \Noselect mailbox name attribute (see the description of the LIST
 45.2332 +      response for more details).
 45.2333 +
 45.2334 +      Server implementations are permitted to "hide" otherwise
 45.2335 +      accessible mailboxes from the wildcard characters, by preventing
 45.2336 +      certain characters or names from matching a wildcard in certain
 45.2337 +      situations.  For example, a UNIX-based server might restrict the
 45.2338 +      interpretation of "*" so that an initial "/" character does not
 45.2339 +      match.
 45.2340 +
 45.2341 +      The special name INBOX is included in the output from LIST, if
 45.2342 +      INBOX is supported by this server for this user and if the
 45.2343 +      uppercase string "INBOX" matches the interpreted reference and
 45.2344 +      mailbox name arguments with wildcards as described above.  The
 45.2345 +      criteria for omitting INBOX is whether SELECT INBOX will return
 45.2346 +      failure; it is not relevant whether the user's real INBOX resides
 45.2347 +      on this or some other server.
 45.2348 +
 45.2349 +
 45.2350 +
 45.2351 +
 45.2352 +
 45.2353 +
 45.2354 +
 45.2355 +
 45.2356 +
 45.2357 +Crispin                     Standards Track                    [Page 42]
 45.2358 +
 45.2359 +RFC 3501                         IMAPv4                       March 2003
 45.2360 +
 45.2361 +
 45.2362 +   Example:    C: A101 LIST "" ""
 45.2363 +               S: * LIST (\Noselect) "/" ""
 45.2364 +               S: A101 OK LIST Completed
 45.2365 +               C: A102 LIST #news.comp.mail.misc ""
 45.2366 +               S: * LIST (\Noselect) "." #news.
 45.2367 +               S: A102 OK LIST Completed
 45.2368 +               C: A103 LIST /usr/staff/jones ""
 45.2369 +               S: * LIST (\Noselect) "/" /
 45.2370 +               S: A103 OK LIST Completed
 45.2371 +               C: A202 LIST ~/Mail/ %
 45.2372 +               S: * LIST (\Noselect) "/" ~/Mail/foo
 45.2373 +               S: * LIST () "/" ~/Mail/meetings
 45.2374 +               S: A202 OK LIST completed
 45.2375 +
 45.2376 +
 45.2377 +6.3.9.  LSUB Command
 45.2378 +
 45.2379 +   Arguments:  reference name
 45.2380 +               mailbox name with possible wildcards
 45.2381 +
 45.2382 +   Responses:  untagged responses: LSUB
 45.2383 +
 45.2384 +   Result:     OK - lsub completed
 45.2385 +               NO - lsub failure: can't list that reference or name
 45.2386 +               BAD - command unknown or arguments invalid
 45.2387 +
 45.2388 +      The LSUB command returns a subset of names from the set of names
 45.2389 +      that the user has declared as being "active" or "subscribed".
 45.2390 +      Zero or more untagged LSUB replies are returned.  The arguments to
 45.2391 +      LSUB are in the same form as those for LIST.
 45.2392 +
 45.2393 +      The returned untagged LSUB response MAY contain different mailbox
 45.2394 +      flags from a LIST untagged response.  If this should happen, the
 45.2395 +      flags in the untagged LIST are considered more authoritative.
 45.2396 +
 45.2397 +      A special situation occurs when using LSUB with the % wildcard.
 45.2398 +      Consider what happens if "foo/bar" (with a hierarchy delimiter of
 45.2399 +      "/") is subscribed but "foo" is not.  A "%" wildcard to LSUB must
 45.2400 +      return foo, not foo/bar, in the LSUB response, and it MUST be
 45.2401 +      flagged with the \Noselect attribute.
 45.2402 +
 45.2403 +      The server MUST NOT unilaterally remove an existing mailbox name
 45.2404 +      from the subscription list even if a mailbox by that name no
 45.2405 +      longer exists.
 45.2406 +
 45.2407 +
 45.2408 +
 45.2409 +
 45.2410 +
 45.2411 +
 45.2412 +
 45.2413 +Crispin                     Standards Track                    [Page 43]
 45.2414 +
 45.2415 +RFC 3501                         IMAPv4                       March 2003
 45.2416 +
 45.2417 +
 45.2418 +   Example:    C: A002 LSUB "#news." "comp.mail.*"
 45.2419 +               S: * LSUB () "." #news.comp.mail.mime
 45.2420 +               S: * LSUB () "." #news.comp.mail.misc
 45.2421 +               S: A002 OK LSUB completed
 45.2422 +               C: A003 LSUB "#news." "comp.%"
 45.2423 +               S: * LSUB (\NoSelect) "." #news.comp.mail
 45.2424 +               S: A003 OK LSUB completed
 45.2425 +
 45.2426 +
 45.2427 +6.3.10. STATUS Command
 45.2428 +
 45.2429 +   Arguments:  mailbox name
 45.2430 +               status data item names
 45.2431 +
 45.2432 +   Responses:  untagged responses: STATUS
 45.2433 +
 45.2434 +   Result:     OK - status completed
 45.2435 +               NO - status failure: no status for that name
 45.2436 +               BAD - command unknown or arguments invalid
 45.2437 +
 45.2438 +      The STATUS command requests the status of the indicated mailbox.
 45.2439 +      It does not change the currently selected mailbox, nor does it
 45.2440 +      affect the state of any messages in the queried mailbox (in
 45.2441 +      particular, STATUS MUST NOT cause messages to lose the \Recent
 45.2442 +      flag).
 45.2443 +
 45.2444 +      The STATUS command provides an alternative to opening a second
 45.2445 +      IMAP4rev1 connection and doing an EXAMINE command on a mailbox to
 45.2446 +      query that mailbox's status without deselecting the current
 45.2447 +      mailbox in the first IMAP4rev1 connection.
 45.2448 +
 45.2449 +      Unlike the LIST command, the STATUS command is not guaranteed to
 45.2450 +      be fast in its response.  Under certain circumstances, it can be
 45.2451 +      quite slow.  In some implementations, the server is obliged to
 45.2452 +      open the mailbox read-only internally to obtain certain status
 45.2453 +      information.  Also unlike the LIST command, the STATUS command
 45.2454 +      does not accept wildcards.
 45.2455 +
 45.2456 +           Note: The STATUS command is intended to access the
 45.2457 +           status of mailboxes other than the currently selected
 45.2458 +           mailbox.  Because the STATUS command can cause the
 45.2459 +           mailbox to be opened internally, and because this
 45.2460 +           information is available by other means on the selected
 45.2461 +           mailbox, the STATUS command SHOULD NOT be used on the
 45.2462 +           currently selected mailbox.
 45.2463 +
 45.2464 +
 45.2465 +
 45.2466 +
 45.2467 +
 45.2468 +
 45.2469 +Crispin                     Standards Track                    [Page 44]
 45.2470 +
 45.2471 +RFC 3501                         IMAPv4                       March 2003
 45.2472 +
 45.2473 +
 45.2474 +           The STATUS command MUST NOT be used as a "check for new
 45.2475 +           messages in the selected mailbox" operation (refer to
 45.2476 +           sections 7, 7.3.1, and 7.3.2 for more information about
 45.2477 +           the proper method for new message checking).
 45.2478 +
 45.2479 +           Because the STATUS command is not guaranteed to be fast
 45.2480 +           in its results, clients SHOULD NOT expect to be able to
 45.2481 +           issue many consecutive STATUS commands and obtain
 45.2482 +           reasonable performance.
 45.2483 +
 45.2484 +      The currently defined status data items that can be requested are:
 45.2485 +
 45.2486 +      MESSAGES
 45.2487 +         The number of messages in the mailbox.
 45.2488 +
 45.2489 +      RECENT
 45.2490 +         The number of messages with the \Recent flag set.
 45.2491 +
 45.2492 +      UIDNEXT
 45.2493 +         The next unique identifier value of the mailbox.  Refer to
 45.2494 +         section 2.3.1.1 for more information.
 45.2495 +
 45.2496 +      UIDVALIDITY
 45.2497 +         The unique identifier validity value of the mailbox.  Refer to
 45.2498 +         section 2.3.1.1 for more information.
 45.2499 +
 45.2500 +      UNSEEN
 45.2501 +         The number of messages which do not have the \Seen flag set.
 45.2502 +
 45.2503 +
 45.2504 +   Example:    C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
 45.2505 +               S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
 45.2506 +               S: A042 OK STATUS completed
 45.2507 +
 45.2508 +
 45.2509 +
 45.2510 +
 45.2511 +
 45.2512 +
 45.2513 +
 45.2514 +
 45.2515 +
 45.2516 +
 45.2517 +
 45.2518 +
 45.2519 +
 45.2520 +
 45.2521 +
 45.2522 +
 45.2523 +
 45.2524 +
 45.2525 +Crispin                     Standards Track                    [Page 45]
 45.2526 +
 45.2527 +RFC 3501                         IMAPv4                       March 2003
 45.2528 +
 45.2529 +
 45.2530 +6.3.11. APPEND Command
 45.2531 +
 45.2532 +   Arguments:  mailbox name
 45.2533 +               OPTIONAL flag parenthesized list
 45.2534 +               OPTIONAL date/time string
 45.2535 +               message literal
 45.2536 +
 45.2537 +   Responses:  no specific responses for this command
 45.2538 +
 45.2539 +   Result:     OK - append completed
 45.2540 +               NO - append error: can't append to that mailbox, error
 45.2541 +                    in flags or date/time or message text
 45.2542 +               BAD - command unknown or arguments invalid
 45.2543 +
 45.2544 +      The APPEND command appends the literal argument as a new message
 45.2545 +      to the end of the specified destination mailbox.  This argument
 45.2546 +      SHOULD be in the format of an [RFC-2822] message.  8-bit
 45.2547 +      characters are permitted in the message.  A server implementation
 45.2548 +      that is unable to preserve 8-bit data properly MUST be able to
 45.2549 +      reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB]
 45.2550 +      content transfer encoding.
 45.2551 +
 45.2552 +           Note: There MAY be exceptions, e.g., draft messages, in
 45.2553 +           which required [RFC-2822] header lines are omitted in
 45.2554 +           the message literal argument to APPEND.  The full
 45.2555 +           implications of doing so MUST be understood and
 45.2556 +           carefully weighed.
 45.2557 +
 45.2558 +      If a flag parenthesized list is specified, the flags SHOULD be set
 45.2559 +      in the resulting message; otherwise, the flag list of the
 45.2560 +      resulting message is set to empty by default.  In either case, the
 45.2561 +      Recent flag is also set.
 45.2562 +
 45.2563 +      If a date-time is specified, the internal date SHOULD be set in
 45.2564 +      the resulting message; otherwise, the internal date of the
 45.2565 +      resulting message is set to the current date and time by default.
 45.2566 +
 45.2567 +      If the append is unsuccessful for any reason, the mailbox MUST be
 45.2568 +      restored to its state before the APPEND attempt; no partial
 45.2569 +      appending is permitted.
 45.2570 +
 45.2571 +      If the destination mailbox does not exist, a server MUST return an
 45.2572 +      error, and MUST NOT automatically create the mailbox.  Unless it
 45.2573 +      is certain that the destination mailbox can not be created, the
 45.2574 +      server MUST send the response code "[TRYCREATE]" as the prefix of
 45.2575 +      the text of the tagged NO response.  This gives a hint to the
 45.2576 +      client that it can attempt a CREATE command and retry the APPEND
 45.2577 +      if the CREATE is successful.
 45.2578 +
 45.2579 +
 45.2580 +
 45.2581 +Crispin                     Standards Track                    [Page 46]
 45.2582 +
 45.2583 +RFC 3501                         IMAPv4                       March 2003
 45.2584 +
 45.2585 +
 45.2586 +      If the mailbox is currently selected, the normal new message
 45.2587 +      actions SHOULD occur.  Specifically, the server SHOULD notify the
 45.2588 +      client immediately via an untagged EXISTS response.  If the server
 45.2589 +      does not do so, the client MAY issue a NOOP command (or failing
 45.2590 +      that, a CHECK command) after one or more APPEND commands.
 45.2591 +
 45.2592 +   Example:    C: A003 APPEND saved-messages (\Seen) {310}
 45.2593 +               S: + Ready for literal data
 45.2594 +               C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
 45.2595 +               C: From: Fred Foobar <foobar@Blurdybloop.COM>
 45.2596 +               C: Subject: afternoon meeting
 45.2597 +               C: To: mooch@owatagu.siam.edu
 45.2598 +               C: Message-Id: <B27397-0100000@Blurdybloop.COM>
 45.2599 +               C: MIME-Version: 1.0
 45.2600 +               C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
 45.2601 +               C:
 45.2602 +               C: Hello Joe, do you think we can meet at 3:30 tomorrow?
 45.2603 +               C:
 45.2604 +               S: A003 OK APPEND completed
 45.2605 +
 45.2606 +        Note: The APPEND command is not used for message delivery,
 45.2607 +        because it does not provide a mechanism to transfer [SMTP]
 45.2608 +        envelope information.
 45.2609 +
 45.2610 +6.4.    Client Commands - Selected State
 45.2611 +
 45.2612 +   In the selected state, commands that manipulate messages in a mailbox
 45.2613 +   are permitted.
 45.2614 +
 45.2615 +   In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
 45.2616 +   and the authenticated state commands (SELECT, EXAMINE, CREATE,
 45.2617 +   DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, and
 45.2618 +   APPEND), the following commands are valid in the selected state:
 45.2619 +   CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID.
 45.2620 +
 45.2621 +6.4.1.  CHECK Command
 45.2622 +
 45.2623 +   Arguments:  none
 45.2624 +
 45.2625 +   Responses:  no specific responses for this command
 45.2626 +
 45.2627 +   Result:     OK - check completed
 45.2628 +               BAD - command unknown or arguments invalid
 45.2629 +
 45.2630 +      The CHECK command requests a checkpoint of the currently selected
 45.2631 +      mailbox.  A checkpoint refers to any implementation-dependent
 45.2632 +      housekeeping associated with the mailbox (e.g., resolving the
 45.2633 +      server's in-memory state of the mailbox with the state on its
 45.2634 +
 45.2635 +
 45.2636 +
 45.2637 +Crispin                     Standards Track                    [Page 47]
 45.2638 +
 45.2639 +RFC 3501                         IMAPv4                       March 2003
 45.2640 +
 45.2641 +
 45.2642 +      disk) that is not normally executed as part of each command.  A
 45.2643 +      checkpoint MAY take a non-instantaneous amount of real time to
 45.2644 +      complete.  If a server implementation has no such housekeeping
 45.2645 +      considerations, CHECK is equivalent to NOOP.
 45.2646 +
 45.2647 +      There is no guarantee that an EXISTS untagged response will happen
 45.2648 +      as a result of CHECK.  NOOP, not CHECK, SHOULD be used for new
 45.2649 +      message polling.
 45.2650 +
 45.2651 +   Example:    C: FXXZ CHECK
 45.2652 +               S: FXXZ OK CHECK Completed
 45.2653 +
 45.2654 +
 45.2655 +6.4.2.  CLOSE Command
 45.2656 +
 45.2657 +   Arguments:  none
 45.2658 +
 45.2659 +   Responses:  no specific responses for this command
 45.2660 +
 45.2661 +   Result:     OK - close completed, now in authenticated state
 45.2662 +               BAD - command unknown or arguments invalid
 45.2663 +
 45.2664 +      The CLOSE command permanently removes all messages that have the
 45.2665 +      \Deleted flag set from the currently selected mailbox, and returns
 45.2666 +      to the authenticated state from the selected state.  No untagged
 45.2667 +      EXPUNGE responses are sent.
 45.2668 +
 45.2669 +      No messages are removed, and no error is given, if the mailbox is
 45.2670 +      selected by an EXAMINE command or is otherwise selected read-only.
 45.2671 +
 45.2672 +      Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT
 45.2673 +      command MAY be issued without previously issuing a CLOSE command.
 45.2674 +      The SELECT, EXAMINE, and LOGOUT commands implicitly close the
 45.2675 +      currently selected mailbox without doing an expunge.  However,
 45.2676 +      when many messages are deleted, a CLOSE-LOGOUT or CLOSE-SELECT
 45.2677 +      sequence is considerably faster than an EXPUNGE-LOGOUT or
 45.2678 +      EXPUNGE-SELECT because no untagged EXPUNGE responses (which the
 45.2679 +      client would probably ignore) are sent.
 45.2680 +
 45.2681 +   Example:    C: A341 CLOSE
 45.2682 +               S: A341 OK CLOSE completed
 45.2683 +
 45.2684 +
 45.2685 +
 45.2686 +
 45.2687 +
 45.2688 +
 45.2689 +
 45.2690 +
 45.2691 +
 45.2692 +
 45.2693 +Crispin                     Standards Track                    [Page 48]
 45.2694 +
 45.2695 +RFC 3501                         IMAPv4                       March 2003
 45.2696 +
 45.2697 +
 45.2698 +6.4.3.  EXPUNGE Command
 45.2699 +
 45.2700 +   Arguments:  none
 45.2701 +
 45.2702 +   Responses:  untagged responses: EXPUNGE
 45.2703 +
 45.2704 +   Result:     OK - expunge completed
 45.2705 +               NO - expunge failure: can't expunge (e.g., permission
 45.2706 +                    denied)
 45.2707 +               BAD - command unknown or arguments invalid
 45.2708 +
 45.2709 +      The EXPUNGE command permanently removes all messages that have the
 45.2710 +      \Deleted flag set from the currently selected mailbox.  Before
 45.2711 +      returning an OK to the client, an untagged EXPUNGE response is
 45.2712 +      sent for each message that is removed.
 45.2713 +
 45.2714 +   Example:    C: A202 EXPUNGE
 45.2715 +               S: * 3 EXPUNGE
 45.2716 +               S: * 3 EXPUNGE
 45.2717 +               S: * 5 EXPUNGE
 45.2718 +               S: * 8 EXPUNGE
 45.2719 +               S: A202 OK EXPUNGE completed
 45.2720 +
 45.2721 +        Note: In this example, messages 3, 4, 7, and 11 had the
 45.2722 +        \Deleted flag set.  See the description of the EXPUNGE
 45.2723 +        response for further explanation.
 45.2724 +
 45.2725 +
 45.2726 +6.4.4.  SEARCH Command
 45.2727 +
 45.2728 +   Arguments:  OPTIONAL [CHARSET] specification
 45.2729 +               searching criteria (one or more)
 45.2730 +
 45.2731 +   Responses:  REQUIRED untagged response: SEARCH
 45.2732 +
 45.2733 +   Result:     OK - search completed
 45.2734 +               NO - search error: can't search that [CHARSET] or
 45.2735 +                    criteria
 45.2736 +               BAD - command unknown or arguments invalid
 45.2737 +
 45.2738 +      The SEARCH command searches the mailbox for messages that match
 45.2739 +      the given searching criteria.  Searching criteria consist of one
 45.2740 +      or more search keys.  The untagged SEARCH response from the server
 45.2741 +      contains a listing of message sequence numbers corresponding to
 45.2742 +      those messages that match the searching criteria.
 45.2743 +
 45.2744 +
 45.2745 +
 45.2746 +
 45.2747 +
 45.2748 +
 45.2749 +Crispin                     Standards Track                    [Page 49]
 45.2750 +
 45.2751 +RFC 3501                         IMAPv4                       March 2003
 45.2752 +
 45.2753 +
 45.2754 +      When multiple keys are specified, the result is the intersection
 45.2755 +      (AND function) of all the messages that match those keys.  For
 45.2756 +      example, the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers
 45.2757 +      to all deleted messages from Smith that were placed in the mailbox
 45.2758 +      since February 1, 1994.  A search key can also be a parenthesized
 45.2759 +      list of one or more search keys (e.g., for use with the OR and NOT
 45.2760 +      keys).
 45.2761 +
 45.2762 +      Server implementations MAY exclude [MIME-IMB] body parts with
 45.2763 +      terminal content media types other than TEXT and MESSAGE from
 45.2764 +      consideration in SEARCH matching.
 45.2765 +
 45.2766 +      The OPTIONAL [CHARSET] specification consists of the word
 45.2767 +      "CHARSET" followed by a registered [CHARSET].  It indicates the
 45.2768 +      [CHARSET] of the strings that appear in the search criteria.
 45.2769 +      [MIME-IMB] content transfer encodings, and [MIME-HDRS] strings in
 45.2770 +      [RFC-2822]/[MIME-IMB] headers, MUST be decoded before comparing
 45.2771 +      text in a [CHARSET] other than US-ASCII.  US-ASCII MUST be
 45.2772 +      supported; other [CHARSET]s MAY be supported.
 45.2773 +
 45.2774 +      If the server does not support the specified [CHARSET], it MUST
 45.2775 +      return a tagged NO response (not a BAD).  This response SHOULD
 45.2776 +      contain the BADCHARSET response code, which MAY list the
 45.2777 +      [CHARSET]s supported by the server.
 45.2778 +
 45.2779 +      In all search keys that use strings, a message matches the key if
 45.2780 +      the string is a substring of the field.  The matching is
 45.2781 +      case-insensitive.
 45.2782 +
 45.2783 +      The defined search keys are as follows.  Refer to the Formal
 45.2784 +      Syntax section for the precise syntactic definitions of the
 45.2785 +      arguments.
 45.2786 +
 45.2787 +      <sequence set>
 45.2788 +         Messages with message sequence numbers corresponding to the
 45.2789 +         specified message sequence number set.
 45.2790 +
 45.2791 +      ALL
 45.2792 +         All messages in the mailbox; the default initial key for
 45.2793 +         ANDing.
 45.2794 +
 45.2795 +      ANSWERED
 45.2796 +         Messages with the \Answered flag set.
 45.2797 +
 45.2798 +
 45.2799 +
 45.2800 +
 45.2801 +
 45.2802 +
 45.2803 +
 45.2804 +
 45.2805 +Crispin                     Standards Track                    [Page 50]
 45.2806 +
 45.2807 +RFC 3501                         IMAPv4                       March 2003
 45.2808 +
 45.2809 +
 45.2810 +      BCC <string>
 45.2811 +         Messages that contain the specified string in the envelope
 45.2812 +         structure's BCC field.
 45.2813 +
 45.2814 +      BEFORE <date>
 45.2815 +         Messages whose internal date (disregarding time and timezone)
 45.2816 +         is earlier than the specified date.
 45.2817 +
 45.2818 +      BODY <string>
 45.2819 +         Messages that contain the specified string in the body of the
 45.2820 +         message.
 45.2821 +
 45.2822 +      CC <string>
 45.2823 +         Messages that contain the specified string in the envelope
 45.2824 +         structure's CC field.
 45.2825 +
 45.2826 +      DELETED
 45.2827 +         Messages with the \Deleted flag set.
 45.2828 +
 45.2829 +      DRAFT
 45.2830 +         Messages with the \Draft flag set.
 45.2831 +
 45.2832 +      FLAGGED
 45.2833 +         Messages with the \Flagged flag set.
 45.2834 +
 45.2835 +      FROM <string>
 45.2836 +         Messages that contain the specified string in the envelope
 45.2837 +         structure's FROM field.
 45.2838 +
 45.2839 +      HEADER <field-name> <string>
 45.2840 +         Messages that have a header with the specified field-name (as
 45.2841 +         defined in [RFC-2822]) and that contains the specified string
 45.2842 +         in the text of the header (what comes after the colon).  If the
 45.2843 +         string to search is zero-length, this matches all messages that
 45.2844 +         have a header line with the specified field-name regardless of
 45.2845 +         the contents.
 45.2846 +
 45.2847 +      KEYWORD <flag>
 45.2848 +         Messages with the specified keyword flag set.
 45.2849 +
 45.2850 +      LARGER <n>
 45.2851 +         Messages with an [RFC-2822] size larger than the specified
 45.2852 +         number of octets.
 45.2853 +
 45.2854 +      NEW
 45.2855 +         Messages that have the \Recent flag set but not the \Seen flag.
 45.2856 +         This is functionally equivalent to "(RECENT UNSEEN)".
 45.2857 +
 45.2858 +
 45.2859 +
 45.2860 +
 45.2861 +Crispin                     Standards Track                    [Page 51]
 45.2862 +
 45.2863 +RFC 3501                         IMAPv4                       March 2003
 45.2864 +
 45.2865 +
 45.2866 +      NOT <search-key>
 45.2867 +         Messages that do not match the specified search key.
 45.2868 +
 45.2869 +      OLD
 45.2870 +         Messages that do not have the \Recent flag set.  This is
 45.2871 +         functionally equivalent to "NOT RECENT" (as opposed to "NOT
 45.2872 +         NEW").
 45.2873 +
 45.2874 +      ON <date>
 45.2875 +         Messages whose internal date (disregarding time and timezone)
 45.2876 +         is within the specified date.
 45.2877 +
 45.2878 +      OR <search-key1> <search-key2>
 45.2879 +         Messages that match either search key.
 45.2880 +
 45.2881 +      RECENT
 45.2882 +         Messages that have the \Recent flag set.
 45.2883 +
 45.2884 +      SEEN
 45.2885 +         Messages that have the \Seen flag set.
 45.2886 +
 45.2887 +      SENTBEFORE <date>
 45.2888 +         Messages whose [RFC-2822] Date: header (disregarding time and
 45.2889 +         timezone) is earlier than the specified date.
 45.2890 +
 45.2891 +      SENTON <date>
 45.2892 +         Messages whose [RFC-2822] Date: header (disregarding time and
 45.2893 +         timezone) is within the specified date.
 45.2894 +
 45.2895 +      SENTSINCE <date>
 45.2896 +         Messages whose [RFC-2822] Date: header (disregarding time and
 45.2897 +         timezone) is within or later than the specified date.
 45.2898 +
 45.2899 +      SINCE <date>
 45.2900 +         Messages whose internal date (disregarding time and timezone)
 45.2901 +         is within or later than the specified date.
 45.2902 +
 45.2903 +      SMALLER <n>
 45.2904 +         Messages with an [RFC-2822] size smaller than the specified
 45.2905 +         number of octets.
 45.2906 +
 45.2907 +
 45.2908 +
 45.2909 +
 45.2910 +
 45.2911 +
 45.2912 +
 45.2913 +
 45.2914 +
 45.2915 +
 45.2916 +
 45.2917 +Crispin                     Standards Track                    [Page 52]
 45.2918 +
 45.2919 +RFC 3501                         IMAPv4                       March 2003
 45.2920 +
 45.2921 +
 45.2922 +      SUBJECT <string>
 45.2923 +         Messages that contain the specified string in the envelope
 45.2924 +         structure's SUBJECT field.
 45.2925 +
 45.2926 +      TEXT <string>
 45.2927 +         Messages that contain the specified string in the header or
 45.2928 +         body of the message.
 45.2929 +
 45.2930 +      TO <string>
 45.2931 +         Messages that contain the specified string in the envelope
 45.2932 +         structure's TO field.
 45.2933 +
 45.2934 +      UID <sequence set>
 45.2935 +         Messages with unique identifiers corresponding to the specified
 45.2936 +         unique identifier set.  Sequence set ranges are permitted.
 45.2937 +
 45.2938 +      UNANSWERED
 45.2939 +         Messages that do not have the \Answered flag set.
 45.2940 +
 45.2941 +      UNDELETED
 45.2942 +         Messages that do not have the \Deleted flag set.
 45.2943 +
 45.2944 +      UNDRAFT
 45.2945 +         Messages that do not have the \Draft flag set.
 45.2946 +
 45.2947 +      UNFLAGGED
 45.2948 +         Messages that do not have the \Flagged flag set.
 45.2949 +
 45.2950 +      UNKEYWORD <flag>
 45.2951 +         Messages that do not have the specified keyword flag set.
 45.2952 +
 45.2953 +      UNSEEN
 45.2954 +         Messages that do not have the \Seen flag set.
 45.2955 +
 45.2956 +
 45.2957 +
 45.2958 +
 45.2959 +
 45.2960 +
 45.2961 +
 45.2962 +
 45.2963 +
 45.2964 +
 45.2965 +
 45.2966 +
 45.2967 +
 45.2968 +
 45.2969 +
 45.2970 +
 45.2971 +
 45.2972 +
 45.2973 +Crispin                     Standards Track                    [Page 53]
 45.2974 +
 45.2975 +RFC 3501                         IMAPv4                       March 2003
 45.2976 +
 45.2977 +
 45.2978 +   Example:    C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
 45.2979 +               S: * SEARCH 2 84 882
 45.2980 +               S: A282 OK SEARCH completed
 45.2981 +               C: A283 SEARCH TEXT "string not in mailbox"
 45.2982 +               S: * SEARCH
 45.2983 +               S: A283 OK SEARCH completed
 45.2984 +               C: A284 SEARCH CHARSET UTF-8 TEXT {6}
 45.2985 +               C: XXXXXX
 45.2986 +               S: * SEARCH 43
 45.2987 +               S: A284 OK SEARCH completed
 45.2988 +
 45.2989 +        Note: Since this document is restricted to 7-bit ASCII
 45.2990 +        text, it is not possible to show actual UTF-8 data.  The
 45.2991 +        "XXXXXX" is a placeholder for what would be 6 octets of
 45.2992 +        8-bit data in an actual transaction.
 45.2993 +
 45.2994 +
 45.2995 +6.4.5.  FETCH Command
 45.2996 +
 45.2997 +   Arguments:  sequence set
 45.2998 +               message data item names or macro
 45.2999 +
 45.3000 +   Responses:  untagged responses: FETCH
 45.3001 +
 45.3002 +   Result:     OK - fetch completed
 45.3003 +               NO - fetch error: can't fetch that data
 45.3004 +               BAD - command unknown or arguments invalid
 45.3005 +
 45.3006 +      The FETCH command retrieves data associated with a message in the
 45.3007 +      mailbox.  The data items to be fetched can be either a single atom
 45.3008 +      or a parenthesized list.
 45.3009 +
 45.3010 +      Most data items, identified in the formal syntax under the
 45.3011 +      msg-att-static rule, are static and MUST NOT change for any
 45.3012 +      particular message.  Other data items, identified in the formal
 45.3013 +      syntax under the msg-att-dynamic rule, MAY change, either as a
 45.3014 +      result of a STORE command or due to external events.
 45.3015 +
 45.3016 +           For example, if a client receives an ENVELOPE for a
 45.3017 +           message when it already knows the envelope, it can
 45.3018 +           safely ignore the newly transmitted envelope.
 45.3019 +
 45.3020 +      There are three macros which specify commonly-used sets of data
 45.3021 +      items, and can be used instead of data items.  A macro must be
 45.3022 +      used by itself, and not in conjunction with other macros or data
 45.3023 +      items.
 45.3024 +
 45.3025 +
 45.3026 +
 45.3027 +
 45.3028 +
 45.3029 +Crispin                     Standards Track                    [Page 54]
 45.3030 +
 45.3031 +RFC 3501                         IMAPv4                       March 2003
 45.3032 +
 45.3033 +
 45.3034 +      ALL
 45.3035 +         Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
 45.3036 +
 45.3037 +      FAST
 45.3038 +         Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
 45.3039 +
 45.3040 +      FULL
 45.3041 +         Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
 45.3042 +         BODY)
 45.3043 +
 45.3044 +      The currently defined data items that can be fetched are:
 45.3045 +
 45.3046 +      BODY
 45.3047 +         Non-extensible form of BODYSTRUCTURE.
 45.3048 +
 45.3049 +      BODY[<section>]<<partial>>
 45.3050 +         The text of a particular body section.  The section
 45.3051 +         specification is a set of zero or more part specifiers
 45.3052 +         delimited by periods.  A part specifier is either a part number
 45.3053 +         or one of the following: HEADER, HEADER.FIELDS,
 45.3054 +         HEADER.FIELDS.NOT, MIME, and TEXT.  An empty section
 45.3055 +         specification refers to the entire message, including the
 45.3056 +         header.
 45.3057 +
 45.3058 +         Every message has at least one part number.  Non-[MIME-IMB]
 45.3059 +         messages, and non-multipart [MIME-IMB] messages with no
 45.3060 +         encapsulated message, only have a part 1.
 45.3061 +
 45.3062 +         Multipart messages are assigned consecutive part numbers, as
 45.3063 +         they occur in the message.  If a particular part is of type
 45.3064 +         message or multipart, its parts MUST be indicated by a period
 45.3065 +         followed by the part number within that nested multipart part.
 45.3066 +
 45.3067 +         A part of type MESSAGE/RFC822 also has nested part numbers,
 45.3068 +         referring to parts of the MESSAGE part's body.
 45.3069 +
 45.3070 +         The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
 45.3071 +         specifiers can be the sole part specifier or can be prefixed by
 45.3072 +         one or more numeric part specifiers, provided that the numeric
 45.3073 +         part specifier refers to a part of type MESSAGE/RFC822.  The
 45.3074 +         MIME part specifier MUST be prefixed by one or more numeric
 45.3075 +         part specifiers.
 45.3076 +
 45.3077 +         The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part
 45.3078 +         specifiers refer to the [RFC-2822] header of the message or of
 45.3079 +         an encapsulated [MIME-IMT] MESSAGE/RFC822 message.
 45.3080 +         HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of
 45.3081 +         field-name (as defined in [RFC-2822]) names, and return a
 45.3082 +
 45.3083 +
 45.3084 +
 45.3085 +Crispin                     Standards Track                    [Page 55]
 45.3086 +
 45.3087 +RFC 3501                         IMAPv4                       March 2003
 45.3088 +
 45.3089 +
 45.3090 +         subset of the header.  The subset returned by HEADER.FIELDS
 45.3091 +         contains only those header fields with a field-name that
 45.3092 +         matches one of the names in the list; similarly, the subset
 45.3093 +         returned by HEADER.FIELDS.NOT contains only the header fields
 45.3094 +         with a non-matching field-name.  The field-matching is
 45.3095 +         case-insensitive but otherwise exact.  Subsetting does not
 45.3096 +         exclude the [RFC-2822] delimiting blank line between the header
 45.3097 +         and the body; the blank line is included in all header fetches,
 45.3098 +         except in the case of a message which has no body and no blank
 45.3099 +         line.
 45.3100 +
 45.3101 +         The MIME part specifier refers to the [MIME-IMB] header for
 45.3102 +         this part.
 45.3103 +
 45.3104 +         The TEXT part specifier refers to the text body of the message,
 45.3105 +         omitting the [RFC-2822] header.
 45.3106 +
 45.3107 +            Here is an example of a complex message with some of its
 45.3108 +            part specifiers:
 45.3109 +
 45.3110 +       HEADER     ([RFC-2822] header of the message)
 45.3111 +       TEXT       ([RFC-2822] text body of the message) MULTIPART/MIXED
 45.3112 +       1          TEXT/PLAIN
 45.3113 +       2          APPLICATION/OCTET-STREAM
 45.3114 +       3          MESSAGE/RFC822
 45.3115 +       3.HEADER   ([RFC-2822] header of the message)
 45.3116 +       3.TEXT     ([RFC-2822] text body of the message) MULTIPART/MIXED
 45.3117 +       3.1        TEXT/PLAIN
 45.3118 +       3.2        APPLICATION/OCTET-STREAM
 45.3119 +       4          MULTIPART/MIXED
 45.3120 +       4.1        IMAGE/GIF
 45.3121 +       4.1.MIME   ([MIME-IMB] header for the IMAGE/GIF)
 45.3122 +       4.2        MESSAGE/RFC822
 45.3123 +       4.2.HEADER ([RFC-2822] header of the message)
 45.3124 +       4.2.TEXT   ([RFC-2822] text body of the message) MULTIPART/MIXED
 45.3125 +       4.2.1      TEXT/PLAIN
 45.3126 +       4.2.2      MULTIPART/ALTERNATIVE
 45.3127 +       4.2.2.1    TEXT/PLAIN
 45.3128 +       4.2.2.2    TEXT/RICHTEXT
 45.3129 +
 45.3130 +
 45.3131 +         It is possible to fetch a substring of the designated text.
 45.3132 +         This is done by appending an open angle bracket ("<"), the
 45.3133 +         octet position of the first desired octet, a period, the
 45.3134 +         maximum number of octets desired, and a close angle bracket
 45.3135 +         (">") to the part specifier.  If the starting octet is beyond
 45.3136 +         the end of the text, an empty string is returned.
 45.3137 +
 45.3138 +
 45.3139 +
 45.3140 +
 45.3141 +Crispin                     Standards Track                    [Page 56]
 45.3142 +
 45.3143 +RFC 3501                         IMAPv4                       March 2003
 45.3144 +
 45.3145 +
 45.3146 +         Any partial fetch that attempts to read beyond the end of the
 45.3147 +         text is truncated as appropriate.  A partial fetch that starts
 45.3148 +         at octet 0 is returned as a partial fetch, even if this
 45.3149 +         truncation happened.
 45.3150 +
 45.3151 +            Note: This means that BODY[]<0.2048> of a 1500-octet message
 45.3152 +            will return BODY[]<0> with a literal of size 1500, not
 45.3153 +            BODY[].
 45.3154 +
 45.3155 +            Note: A substring fetch of a HEADER.FIELDS or
 45.3156 +            HEADER.FIELDS.NOT part specifier is calculated after
 45.3157 +            subsetting the header.
 45.3158 +
 45.3159 +         The \Seen flag is implicitly set; if this causes the flags to
 45.3160 +         change, they SHOULD be included as part of the FETCH responses.
 45.3161 +
 45.3162 +      BODY.PEEK[<section>]<<partial>>
 45.3163 +         An alternate form of BODY[<section>] that does not implicitly
 45.3164 +         set the \Seen flag.
 45.3165 +
 45.3166 +      BODYSTRUCTURE
 45.3167 +         The [MIME-IMB] body structure of the message.  This is computed
 45.3168 +         by the server by parsing the [MIME-IMB] header fields in the
 45.3169 +         [RFC-2822] header and [MIME-IMB] headers.
 45.3170 +
 45.3171 +      ENVELOPE
 45.3172 +         The envelope structure of the message.  This is computed by the
 45.3173 +         server by parsing the [RFC-2822] header into the component
 45.3174 +         parts, defaulting various fields as necessary.
 45.3175 +
 45.3176 +      FLAGS
 45.3177 +         The flags that are set for this message.
 45.3178 +
 45.3179 +      INTERNALDATE
 45.3180 +         The internal date of the message.
 45.3181 +
 45.3182 +      RFC822
 45.3183 +         Functionally equivalent to BODY[], differing in the syntax of
 45.3184 +         the resulting untagged FETCH data (RFC822 is returned).
 45.3185 +
 45.3186 +      RFC822.HEADER
 45.3187 +         Functionally equivalent to BODY.PEEK[HEADER], differing in the
 45.3188 +         syntax of the resulting untagged FETCH data (RFC822.HEADER is
 45.3189 +         returned).
 45.3190 +
 45.3191 +      RFC822.SIZE
 45.3192 +         The [RFC-2822] size of the message.
 45.3193 +
 45.3194 +
 45.3195 +
 45.3196 +
 45.3197 +Crispin                     Standards Track                    [Page 57]
 45.3198 +
 45.3199 +RFC 3501                         IMAPv4                       March 2003
 45.3200 +
 45.3201 +
 45.3202 +      RFC822.TEXT
 45.3203 +         Functionally equivalent to BODY[TEXT], differing in the syntax
 45.3204 +         of the resulting untagged FETCH data (RFC822.TEXT is returned).
 45.3205 +
 45.3206 +      UID
 45.3207 +         The unique identifier for the message.
 45.3208 +
 45.3209 +
 45.3210 +   Example:    C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
 45.3211 +               S: * 2 FETCH ....
 45.3212 +               S: * 3 FETCH ....
 45.3213 +               S: * 4 FETCH ....
 45.3214 +               S: A654 OK FETCH completed
 45.3215 +
 45.3216 +
 45.3217 +6.4.6.  STORE Command
 45.3218 +
 45.3219 +   Arguments:  sequence set
 45.3220 +               message data item name
 45.3221 +               value for message data item
 45.3222 +
 45.3223 +   Responses:  untagged responses: FETCH
 45.3224 +
 45.3225 +   Result:     OK - store completed
 45.3226 +               NO - store error: can't store that data
 45.3227 +               BAD - command unknown or arguments invalid
 45.3228 +
 45.3229 +      The STORE command alters data associated with a message in the
 45.3230 +      mailbox.  Normally, STORE will return the updated value of the
 45.3231 +      data with an untagged FETCH response.  A suffix of ".SILENT" in
 45.3232 +      the data item name prevents the untagged FETCH, and the server
 45.3233 +      SHOULD assume that the client has determined the updated value
 45.3234 +      itself or does not care about the updated value.
 45.3235 +
 45.3236 +           Note: Regardless of whether or not the ".SILENT" suffix
 45.3237 +           was used, the server SHOULD send an untagged FETCH
 45.3238 +           response if a change to a message's flags from an
 45.3239 +           external source is observed.  The intent is that the
 45.3240 +           status of the flags is determinate without a race
 45.3241 +           condition.
 45.3242 +
 45.3243 +
 45.3244 +
 45.3245 +
 45.3246 +
 45.3247 +
 45.3248 +
 45.3249 +
 45.3250 +
 45.3251 +
 45.3252 +
 45.3253 +Crispin                     Standards Track                    [Page 58]
 45.3254 +
 45.3255 +RFC 3501                         IMAPv4                       March 2003
 45.3256 +
 45.3257 +
 45.3258 +      The currently defined data items that can be stored are:
 45.3259 +
 45.3260 +      FLAGS <flag list>
 45.3261 +         Replace the flags for the message (other than \Recent) with the
 45.3262 +         argument.  The new value of the flags is returned as if a FETCH
 45.3263 +         of those flags was done.
 45.3264 +
 45.3265 +      FLAGS.SILENT <flag list>
 45.3266 +         Equivalent to FLAGS, but without returning a new value.
 45.3267 +
 45.3268 +      +FLAGS <flag list>
 45.3269 +         Add the argument to the flags for the message.  The new value
 45.3270 +         of the flags is returned as if a FETCH of those flags was done.
 45.3271 +
 45.3272 +      +FLAGS.SILENT <flag list>
 45.3273 +         Equivalent to +FLAGS, but without returning a new value.
 45.3274 +
 45.3275 +      -FLAGS <flag list>
 45.3276 +         Remove the argument from the flags for the message.  The new
 45.3277 +         value of the flags is returned as if a FETCH of those flags was
 45.3278 +         done.
 45.3279 +
 45.3280 +      -FLAGS.SILENT <flag list>
 45.3281 +         Equivalent to -FLAGS, but without returning a new value.
 45.3282 +
 45.3283 +
 45.3284 +   Example:    C: A003 STORE 2:4 +FLAGS (\Deleted)
 45.3285 +               S: * 2 FETCH (FLAGS (\Deleted \Seen))
 45.3286 +               S: * 3 FETCH (FLAGS (\Deleted))
 45.3287 +               S: * 4 FETCH (FLAGS (\Deleted \Flagged \Seen))
 45.3288 +               S: A003 OK STORE completed
 45.3289 +
 45.3290 +
 45.3291 +6.4.7.  COPY Command
 45.3292 +
 45.3293 +   Arguments:  sequence set
 45.3294 +               mailbox name
 45.3295 +
 45.3296 +   Responses:  no specific responses for this command
 45.3297 +
 45.3298 +   Result:     OK - copy completed
 45.3299 +               NO - copy error: can't copy those messages or to that
 45.3300 +                    name
 45.3301 +               BAD - command unknown or arguments invalid
 45.3302 +
 45.3303 +
 45.3304 +
 45.3305 +
 45.3306 +
 45.3307 +
 45.3308 +
 45.3309 +Crispin                     Standards Track                    [Page 59]
 45.3310 +
 45.3311 +RFC 3501                         IMAPv4                       March 2003
 45.3312 +
 45.3313 +
 45.3314 +      The COPY command copies the specified message(s) to the end of the
 45.3315 +      specified destination mailbox.  The flags and internal date of the
 45.3316 +      message(s) SHOULD be preserved, and the Recent flag SHOULD be set,
 45.3317 +      in the copy.
 45.3318 +
 45.3319 +      If the destination mailbox does not exist, a server SHOULD return
 45.3320 +      an error.  It SHOULD NOT automatically create the mailbox.  Unless
 45.3321 +      it is certain that the destination mailbox can not be created, the
 45.3322 +      server MUST send the response code "[TRYCREATE]" as the prefix of
 45.3323 +      the text of the tagged NO response.  This gives a hint to the
 45.3324 +      client that it can attempt a CREATE command and retry the COPY if
 45.3325 +      the CREATE is successful.
 45.3326 +
 45.3327 +      If the COPY command is unsuccessful for any reason, server
 45.3328 +      implementations MUST restore the destination mailbox to its state
 45.3329 +      before the COPY attempt.
 45.3330 +
 45.3331 +   Example:    C: A003 COPY 2:4 MEETING
 45.3332 +               S: A003 OK COPY completed
 45.3333 +
 45.3334 +
 45.3335 +6.4.8.  UID Command
 45.3336 +
 45.3337 +   Arguments:  command name
 45.3338 +               command arguments
 45.3339 +
 45.3340 +   Responses:  untagged responses: FETCH, SEARCH
 45.3341 +
 45.3342 +   Result:     OK - UID command completed
 45.3343 +               NO - UID command error
 45.3344 +               BAD - command unknown or arguments invalid
 45.3345 +
 45.3346 +      The UID command has two forms.  In the first form, it takes as its
 45.3347 +      arguments a COPY, FETCH, or STORE command with arguments
 45.3348 +      appropriate for the associated command.  However, the numbers in
 45.3349 +      the sequence set argument are unique identifiers instead of
 45.3350 +      message sequence numbers.  Sequence set ranges are permitted, but
 45.3351 +      there is no guarantee that unique identifiers will be contiguous.
 45.3352 +
 45.3353 +      A non-existent unique identifier is ignored without any error
 45.3354 +      message generated.  Thus, it is possible for a UID FETCH command
 45.3355 +      to return an OK without any data or a UID COPY or UID STORE to
 45.3356 +      return an OK without performing any operations.
 45.3357 +
 45.3358 +      In the second form, the UID command takes a SEARCH command with
 45.3359 +      SEARCH command arguments.  The interpretation of the arguments is
 45.3360 +      the same as with SEARCH; however, the numbers returned in a SEARCH
 45.3361 +      response for a UID SEARCH command are unique identifiers instead
 45.3362 +
 45.3363 +
 45.3364 +
 45.3365 +Crispin                     Standards Track                    [Page 60]
 45.3366 +
 45.3367 +RFC 3501                         IMAPv4                       March 2003
 45.3368 +
 45.3369 +
 45.3370 +      of message sequence numbers.  For example, the command UID SEARCH
 45.3371 +      1:100 UID 443:557 returns the unique identifiers corresponding to
 45.3372 +      the intersection of two sequence sets, the message sequence number
 45.3373 +      range 1:100 and the UID range 443:557.
 45.3374 +
 45.3375 +           Note: in the above example, the UID range 443:557
 45.3376 +           appears.  The same comment about a non-existent unique
 45.3377 +           identifier being ignored without any error message also
 45.3378 +           applies here.  Hence, even if neither UID 443 or 557
 45.3379 +           exist, this range is valid and would include an existing
 45.3380 +           UID 495.
 45.3381 +
 45.3382 +           Also note that a UID range of 559:* always includes the
 45.3383 +           UID of the last message in the mailbox, even if 559 is
 45.3384 +           higher than any assigned UID value.  This is because the
 45.3385 +           contents of a range are independent of the order of the
 45.3386 +           range endpoints.  Thus, any UID range with * as one of
 45.3387 +           the endpoints indicates at least one message (the
 45.3388 +           message with the highest numbered UID), unless the
 45.3389 +           mailbox is empty.
 45.3390 +
 45.3391 +      The number after the "*" in an untagged FETCH response is always a
 45.3392 +      message sequence number, not a unique identifier, even for a UID
 45.3393 +      command response.  However, server implementations MUST implicitly
 45.3394 +      include the UID message data item as part of any FETCH response
 45.3395 +      caused by a UID command, regardless of whether a UID was specified
 45.3396 +      as a message data item to the FETCH.
 45.3397 +
 45.3398 +
 45.3399 +      Note: The rule about including the UID message data item as part
 45.3400 +      of a FETCH response primarily applies to the UID FETCH and UID
 45.3401 +      STORE commands, including a UID FETCH command that does not
 45.3402 +      include UID as a message data item.  Although it is unlikely that
 45.3403 +      the other UID commands will cause an untagged FETCH, this rule
 45.3404 +      applies to these commands as well.
 45.3405 +
 45.3406 +   Example:    C: A999 UID FETCH 4827313:4828442 FLAGS
 45.3407 +               S: * 23 FETCH (FLAGS (\Seen) UID 4827313)
 45.3408 +               S: * 24 FETCH (FLAGS (\Seen) UID 4827943)
 45.3409 +               S: * 25 FETCH (FLAGS (\Seen) UID 4828442)
 45.3410 +               S: A999 OK UID FETCH completed
 45.3411 +
 45.3412 +
 45.3413 +
 45.3414 +
 45.3415 +
 45.3416 +
 45.3417 +
 45.3418 +
 45.3419 +
 45.3420 +
 45.3421 +Crispin                     Standards Track                    [Page 61]
 45.3422 +
 45.3423 +RFC 3501                         IMAPv4                       March 2003
 45.3424 +
 45.3425 +
 45.3426 +6.5.    Client Commands - Experimental/Expansion
 45.3427 +
 45.3428 +
 45.3429 +6.5.1.  X<atom> Command
 45.3430 +
 45.3431 +   Arguments:  implementation defined
 45.3432 +
 45.3433 +   Responses:  implementation defined
 45.3434 +
 45.3435 +   Result:     OK - command completed
 45.3436 +               NO - failure
 45.3437 +               BAD - command unknown or arguments invalid
 45.3438 +
 45.3439 +      Any command prefixed with an X is an experimental command.
 45.3440 +      Commands which are not part of this specification, a standard or
 45.3441 +      standards-track revision of this specification, or an
 45.3442 +      IESG-approved experimental protocol, MUST use the X prefix.
 45.3443 +
 45.3444 +      Any added untagged responses issued by an experimental command
 45.3445 +      MUST also be prefixed with an X.  Server implementations MUST NOT
 45.3446 +      send any such untagged responses, unless the client requested it
 45.3447 +      by issuing the associated experimental command.
 45.3448 +
 45.3449 +   Example:    C: a441 CAPABILITY
 45.3450 +               S: * CAPABILITY IMAP4rev1 XPIG-LATIN
 45.3451 +               S: a441 OK CAPABILITY completed
 45.3452 +               C: A442 XPIG-LATIN
 45.3453 +               S: * XPIG-LATIN ow-nay eaking-spay ig-pay atin-lay
 45.3454 +               S: A442 OK XPIG-LATIN ompleted-cay
 45.3455 +
 45.3456 +7.      Server Responses
 45.3457 +
 45.3458 +   Server responses are in three forms: status responses, server data,
 45.3459 +   and command continuation request.  The information contained in a
 45.3460 +   server response, identified by "Contents:" in the response
 45.3461 +   descriptions below, is described by function, not by syntax.  The
 45.3462 +   precise syntax of server responses is described in the Formal Syntax
 45.3463 +   section.
 45.3464 +
 45.3465 +   The client MUST be prepared to accept any response at all times.
 45.3466 +
 45.3467 +   Status responses can be tagged or untagged.  Tagged status responses
 45.3468 +   indicate the completion result (OK, NO, or BAD status) of a client
 45.3469 +   command, and have a tag matching the command.
 45.3470 +
 45.3471 +   Some status responses, and all server data, are untagged.  An
 45.3472 +   untagged response is indicated by the token "*" instead of a tag.
 45.3473 +   Untagged status responses indicate server greeting, or server status
 45.3474 +
 45.3475 +
 45.3476 +
 45.3477 +Crispin                     Standards Track                    [Page 62]
 45.3478 +
 45.3479 +RFC 3501                         IMAPv4                       March 2003
 45.3480 +
 45.3481 +
 45.3482 +   that does not indicate the completion of a command (for example, an
 45.3483 +   impending system shutdown alert).  For historical reasons, untagged
 45.3484 +   server data responses are also called "unsolicited data", although
 45.3485 +   strictly speaking, only unilateral server data is truly
 45.3486 +   "unsolicited".
 45.3487 +
 45.3488 +   Certain server data MUST be recorded by the client when it is
 45.3489 +   received; this is noted in the description of that data.  Such data
 45.3490 +   conveys critical information which affects the interpretation of all
 45.3491 +   subsequent commands and responses (e.g., updates reflecting the
 45.3492 +   creation or destruction of messages).
 45.3493 +
 45.3494 +   Other server data SHOULD be recorded for later reference; if the
 45.3495 +   client does not need to record the data, or if recording the data has
 45.3496 +   no obvious purpose (e.g., a SEARCH response when no SEARCH command is
 45.3497 +   in progress), the data SHOULD be ignored.
 45.3498 +
 45.3499 +   An example of unilateral untagged server data occurs when the IMAP
 45.3500 +   connection is in the selected state.  In the selected state, the
 45.3501 +   server checks the mailbox for new messages as part of command
 45.3502 +   execution.  Normally, this is part of the execution of every command;
 45.3503 +   hence, a NOOP command suffices to check for new messages.  If new
 45.3504 +   messages are found, the server sends untagged EXISTS and RECENT
 45.3505 +   responses reflecting the new size of the mailbox.  Server
 45.3506 +   implementations that offer multiple simultaneous access to the same
 45.3507 +   mailbox SHOULD also send appropriate unilateral untagged FETCH and
 45.3508 +   EXPUNGE responses if another agent changes the state of any message
 45.3509 +   flags or expunges any messages.
 45.3510 +
 45.3511 +   Command continuation request responses use the token "+" instead of a
 45.3512 +   tag.  These responses are sent by the server to indicate acceptance
 45.3513 +   of an incomplete client command and readiness for the remainder of
 45.3514 +   the command.
 45.3515 +
 45.3516 +7.1.    Server Responses - Status Responses
 45.3517 +
 45.3518 +   Status responses are OK, NO, BAD, PREAUTH and BYE.  OK, NO, and BAD
 45.3519 +   can be tagged or untagged.  PREAUTH and BYE are always untagged.
 45.3520 +
 45.3521 +   Status responses MAY include an OPTIONAL "response code".  A response
 45.3522 +   code consists of data inside square brackets in the form of an atom,
 45.3523 +   possibly followed by a space and arguments.  The response code
 45.3524 +   contains additional information or status codes for client software
 45.3525 +   beyond the OK/NO/BAD condition, and are defined when there is a
 45.3526 +   specific action that a client can take based upon the additional
 45.3527 +   information.
 45.3528 +
 45.3529 +
 45.3530 +
 45.3531 +
 45.3532 +
 45.3533 +Crispin                     Standards Track                    [Page 63]
 45.3534 +
 45.3535 +RFC 3501                         IMAPv4                       March 2003
 45.3536 +
 45.3537 +
 45.3538 +   The currently defined response codes are:
 45.3539 +
 45.3540 +      ALERT
 45.3541 +
 45.3542 +         The human-readable text contains a special alert that MUST be
 45.3543 +         presented to the user in a fashion that calls the user's
 45.3544 +         attention to the message.
 45.3545 +
 45.3546 +      BADCHARSET
 45.3547 +
 45.3548 +         Optionally followed by a parenthesized list of charsets.  A
 45.3549 +         SEARCH failed because the given charset is not supported by
 45.3550 +         this implementation.  If the optional list of charsets is
 45.3551 +         given, this lists the charsets that are supported by this
 45.3552 +         implementation.
 45.3553 +
 45.3554 +      CAPABILITY
 45.3555 +
 45.3556 +         Followed by a list of capabilities.  This can appear in the
 45.3557 +         initial OK or PREAUTH response to transmit an initial
 45.3558 +         capabilities list.  This makes it unnecessary for a client to
 45.3559 +         send a separate CAPABILITY command if it recognizes this
 45.3560 +         response.
 45.3561 +
 45.3562 +      PARSE
 45.3563 +
 45.3564 +         The human-readable text represents an error in parsing the
 45.3565 +         [RFC-2822] header or [MIME-IMB] headers of a message in the
 45.3566 +         mailbox.
 45.3567 +
 45.3568 +      PERMANENTFLAGS
 45.3569 +
 45.3570 +         Followed by a parenthesized list of flags, indicates which of
 45.3571 +         the known flags the client can change permanently.  Any flags
 45.3572 +         that are in the FLAGS untagged response, but not the
 45.3573 +         PERMANENTFLAGS list, can not be set permanently.  If the client
 45.3574 +         attempts to STORE a flag that is not in the PERMANENTFLAGS
 45.3575 +         list, the server will either ignore the change or store the
 45.3576 +         state change for the remainder of the current session only.
 45.3577 +         The PERMANENTFLAGS list can also include the special flag \*,
 45.3578 +         which indicates that it is possible to create new keywords by
 45.3579 +         attempting to store those flags in the mailbox.
 45.3580 +
 45.3581 +
 45.3582 +
 45.3583 +
 45.3584 +
 45.3585 +
 45.3586 +
 45.3587 +
 45.3588 +
 45.3589 +Crispin                     Standards Track                    [Page 64]
 45.3590 +
 45.3591 +RFC 3501                         IMAPv4                       March 2003
 45.3592 +
 45.3593 +
 45.3594 +      READ-ONLY
 45.3595 +
 45.3596 +         The mailbox is selected read-only, or its access while selected
 45.3597 +         has changed from read-write to read-only.
 45.3598 +
 45.3599 +      READ-WRITE
 45.3600 +
 45.3601 +         The mailbox is selected read-write, or its access while
 45.3602 +         selected has changed from read-only to read-write.
 45.3603 +
 45.3604 +      TRYCREATE
 45.3605 +
 45.3606 +         An APPEND or COPY attempt is failing because the target mailbox
 45.3607 +         does not exist (as opposed to some other reason).  This is a
 45.3608 +         hint to the client that the operation can succeed if the
 45.3609 +         mailbox is first created by the CREATE command.
 45.3610 +
 45.3611 +      UIDNEXT
 45.3612 +
 45.3613 +         Followed by a decimal number, indicates the next unique
 45.3614 +         identifier value.  Refer to section 2.3.1.1 for more
 45.3615 +         information.
 45.3616 +
 45.3617 +      UIDVALIDITY
 45.3618 +
 45.3619 +         Followed by a decimal number, indicates the unique identifier
 45.3620 +         validity value.  Refer to section 2.3.1.1 for more information.
 45.3621 +
 45.3622 +      UNSEEN
 45.3623 +
 45.3624 +         Followed by a decimal number, indicates the number of the first
 45.3625 +         message without the \Seen flag set.
 45.3626 +
 45.3627 +      Additional response codes defined by particular client or server
 45.3628 +      implementations SHOULD be prefixed with an "X" until they are
 45.3629 +      added to a revision of this protocol.  Client implementations
 45.3630 +      SHOULD ignore response codes that they do not recognize.
 45.3631 +
 45.3632 +7.1.1.  OK Response
 45.3633 +
 45.3634 +   Contents:   OPTIONAL response code
 45.3635 +               human-readable text
 45.3636 +
 45.3637 +      The OK response indicates an information message from the server.
 45.3638 +      When tagged, it indicates successful completion of the associated
 45.3639 +      command.  The human-readable text MAY be presented to the user as
 45.3640 +      an information message.  The untagged form indicates an
 45.3641 +
 45.3642 +
 45.3643 +
 45.3644 +
 45.3645 +Crispin                     Standards Track                    [Page 65]
 45.3646 +
 45.3647 +RFC 3501                         IMAPv4                       March 2003
 45.3648 +
 45.3649 +
 45.3650 +      information-only message; the nature of the information MAY be
 45.3651 +      indicated by a response code.
 45.3652 +
 45.3653 +      The untagged form is also used as one of three possible greetings
 45.3654 +      at connection startup.  It indicates that the connection is not
 45.3655 +      yet authenticated and that a LOGIN command is needed.
 45.3656 +
 45.3657 +   Example:    S: * OK IMAP4rev1 server ready
 45.3658 +               C: A001 LOGIN fred blurdybloop
 45.3659 +               S: * OK [ALERT] System shutdown in 10 minutes
 45.3660 +               S: A001 OK LOGIN Completed
 45.3661 +
 45.3662 +
 45.3663 +7.1.2.  NO Response
 45.3664 +
 45.3665 +   Contents:   OPTIONAL response code
 45.3666 +               human-readable text
 45.3667 +
 45.3668 +      The NO response indicates an operational error message from the
 45.3669 +      server.  When tagged, it indicates unsuccessful completion of the
 45.3670 +      associated command.  The untagged form indicates a warning; the
 45.3671 +      command can still complete successfully.  The human-readable text
 45.3672 +      describes the condition.
 45.3673 +
 45.3674 +   Example:    C: A222 COPY 1:2 owatagusiam
 45.3675 +               S: * NO Disk is 98% full, please delete unnecessary data
 45.3676 +               S: A222 OK COPY completed
 45.3677 +               C: A223 COPY 3:200 blurdybloop
 45.3678 +               S: * NO Disk is 98% full, please delete unnecessary data
 45.3679 +               S: * NO Disk is 99% full, please delete unnecessary data
 45.3680 +               S: A223 NO COPY failed: disk is full
 45.3681 +
 45.3682 +
 45.3683 +7.1.3.  BAD Response
 45.3684 +
 45.3685 +   Contents:   OPTIONAL response code
 45.3686 +               human-readable text
 45.3687 +
 45.3688 +      The BAD response indicates an error message from the server.  When
 45.3689 +      tagged, it reports a protocol-level error in the client's command;
 45.3690 +      the tag indicates the command that caused the error.  The untagged
 45.3691 +      form indicates a protocol-level error for which the associated
 45.3692 +      command can not be determined; it can also indicate an internal
 45.3693 +      server failure.  The human-readable text describes the condition.
 45.3694 +
 45.3695 +
 45.3696 +
 45.3697 +
 45.3698 +
 45.3699 +
 45.3700 +
 45.3701 +Crispin                     Standards Track                    [Page 66]
 45.3702 +
 45.3703 +RFC 3501                         IMAPv4                       March 2003
 45.3704 +
 45.3705 +
 45.3706 +   Example:    C: ...very long command line...
 45.3707 +               S: * BAD Command line too long
 45.3708 +               C: ...empty line...
 45.3709 +               S: * BAD Empty command line
 45.3710 +               C: A443 EXPUNGE
 45.3711 +               S: * BAD Disk crash, attempting salvage to a new disk!
 45.3712 +               S: * OK Salvage successful, no data lost
 45.3713 +               S: A443 OK Expunge completed
 45.3714 +
 45.3715 +
 45.3716 +7.1.4.  PREAUTH Response
 45.3717 +
 45.3718 +   Contents:   OPTIONAL response code
 45.3719 +               human-readable text
 45.3720 +
 45.3721 +      The PREAUTH response is always untagged, and is one of three
 45.3722 +      possible greetings at connection startup.  It indicates that the
 45.3723 +      connection has already been authenticated by external means; thus
 45.3724 +      no LOGIN command is needed.
 45.3725 +
 45.3726 +   Example:    S: * PREAUTH IMAP4rev1 server logged in as Smith
 45.3727 +
 45.3728 +
 45.3729 +7.1.5.  BYE Response
 45.3730 +
 45.3731 +   Contents:   OPTIONAL response code
 45.3732 +               human-readable text
 45.3733 +
 45.3734 +      The BYE response is always untagged, and indicates that the server
 45.3735 +      is about to close the connection.  The human-readable text MAY be
 45.3736 +      displayed to the user in a status report by the client.  The BYE
 45.3737 +      response is sent under one of four conditions:
 45.3738 +
 45.3739 +         1) as part of a normal logout sequence.  The server will close
 45.3740 +            the connection after sending the tagged OK response to the
 45.3741 +            LOGOUT command.
 45.3742 +
 45.3743 +         2) as a panic shutdown announcement.  The server closes the
 45.3744 +            connection immediately.
 45.3745 +
 45.3746 +         3) as an announcement of an inactivity autologout.  The server
 45.3747 +            closes the connection immediately.
 45.3748 +
 45.3749 +         4) as one of three possible greetings at connection startup,
 45.3750 +            indicating that the server is not willing to accept a
 45.3751 +            connection from this client.  The server closes the
 45.3752 +            connection immediately.
 45.3753 +
 45.3754 +
 45.3755 +
 45.3756 +
 45.3757 +Crispin                     Standards Track                    [Page 67]
 45.3758 +
 45.3759 +RFC 3501                         IMAPv4                       March 2003
 45.3760 +
 45.3761 +
 45.3762 +      The difference between a BYE that occurs as part of a normal
 45.3763 +      LOGOUT sequence (the first case) and a BYE that occurs because of
 45.3764 +      a failure (the other three cases) is that the connection closes
 45.3765 +      immediately in the failure case.  In all cases the client SHOULD
 45.3766 +      continue to read response data from the server until the
 45.3767 +      connection is closed; this will ensure that any pending untagged
 45.3768 +      or completion responses are read and processed.
 45.3769 +
 45.3770 +   Example:    S: * BYE Autologout; idle for too long
 45.3771 +
 45.3772 +7.2.    Server Responses - Server and Mailbox Status
 45.3773 +
 45.3774 +   These responses are always untagged.  This is how server and mailbox
 45.3775 +   status data are transmitted from the server to the client.  Many of
 45.3776 +   these responses typically result from a command with the same name.
 45.3777 +
 45.3778 +7.2.1.  CAPABILITY Response
 45.3779 +
 45.3780 +   Contents:   capability listing
 45.3781 +
 45.3782 +      The CAPABILITY response occurs as a result of a CAPABILITY
 45.3783 +      command.  The capability listing contains a space-separated
 45.3784 +      listing of capability names that the server supports.  The
 45.3785 +      capability listing MUST include the atom "IMAP4rev1".
 45.3786 +
 45.3787 +      In addition, client and server implementations MUST implement the
 45.3788 +      STARTTLS, LOGINDISABLED, and AUTH=PLAIN (described in [IMAP-TLS])
 45.3789 +      capabilities.  See the Security Considerations section for
 45.3790 +      important information.
 45.3791 +
 45.3792 +      A capability name which begins with "AUTH=" indicates that the
 45.3793 +      server supports that particular authentication mechanism.
 45.3794 +
 45.3795 +      The LOGINDISABLED capability indicates that the LOGIN command is
 45.3796 +      disabled, and that the server will respond with a tagged NO
 45.3797 +      response to any attempt to use the LOGIN command even if the user
 45.3798 +      name and password are valid.  An IMAP client MUST NOT issue the
 45.3799 +      LOGIN command if the server advertises the LOGINDISABLED
 45.3800 +      capability.
 45.3801 +
 45.3802 +      Other capability names indicate that the server supports an
 45.3803 +      extension, revision, or amendment to the IMAP4rev1 protocol.
 45.3804 +      Server responses MUST conform to this document until the client
 45.3805 +      issues a command that uses the associated capability.
 45.3806 +
 45.3807 +      Capability names MUST either begin with "X" or be standard or
 45.3808 +      standards-track IMAP4rev1 extensions, revisions, or amendments
 45.3809 +      registered with IANA.  A server MUST NOT offer unregistered or
 45.3810 +
 45.3811 +
 45.3812 +
 45.3813 +Crispin                     Standards Track                    [Page 68]
 45.3814 +
 45.3815 +RFC 3501                         IMAPv4                       March 2003
 45.3816 +
 45.3817 +
 45.3818 +      non-standard capability names, unless such names are prefixed with
 45.3819 +      an "X".
 45.3820 +
 45.3821 +      Client implementations SHOULD NOT require any capability name
 45.3822 +      other than "IMAP4rev1", and MUST ignore any unknown capability
 45.3823 +      names.
 45.3824 +
 45.3825 +      A server MAY send capabilities automatically, by using the
 45.3826 +      CAPABILITY response code in the initial PREAUTH or OK responses,
 45.3827 +      and by sending an updated CAPABILITY response code in the tagged
 45.3828 +      OK response as part of a successful authentication.  It is
 45.3829 +      unnecessary for a client to send a separate CAPABILITY command if
 45.3830 +      it recognizes these automatic capabilities.
 45.3831 +
 45.3832 +   Example:    S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI XPIG-LATIN
 45.3833 +
 45.3834 +
 45.3835 +7.2.2.  LIST Response
 45.3836 +
 45.3837 +   Contents:   name attributes
 45.3838 +               hierarchy delimiter
 45.3839 +               name
 45.3840 +
 45.3841 +      The LIST response occurs as a result of a LIST command.  It
 45.3842 +      returns a single name that matches the LIST specification.  There
 45.3843 +      can be multiple LIST responses for a single LIST command.
 45.3844 +
 45.3845 +      Four name attributes are defined:
 45.3846 +
 45.3847 +      \Noinferiors
 45.3848 +         It is not possible for any child levels of hierarchy to exist
 45.3849 +         under this name; no child levels exist now and none can be
 45.3850 +         created in the future.
 45.3851 +
 45.3852 +      \Noselect
 45.3853 +         It is not possible to use this name as a selectable mailbox.
 45.3854 +
 45.3855 +      \Marked
 45.3856 +         The mailbox has been marked "interesting" by the server; the
 45.3857 +         mailbox probably contains messages that have been added since
 45.3858 +         the last time the mailbox was selected.
 45.3859 +
 45.3860 +      \Unmarked
 45.3861 +         The mailbox does not contain any additional messages since the
 45.3862 +         last time the mailbox was selected.
 45.3863 +
 45.3864 +
 45.3865 +
 45.3866 +
 45.3867 +
 45.3868 +
 45.3869 +Crispin                     Standards Track                    [Page 69]
 45.3870 +
 45.3871 +RFC 3501                         IMAPv4                       March 2003
 45.3872 +
 45.3873 +
 45.3874 +      If it is not feasible for the server to determine whether or not
 45.3875 +      the mailbox is "interesting", or if the name is a \Noselect name,
 45.3876 +      the server SHOULD NOT send either \Marked or \Unmarked.
 45.3877 +
 45.3878 +      The hierarchy delimiter is a character used to delimit levels of
 45.3879 +      hierarchy in a mailbox name.  A client can use it to create child
 45.3880 +      mailboxes, and to search higher or lower levels of naming
 45.3881 +      hierarchy.  All children of a top-level hierarchy node MUST use
 45.3882 +      the same separator character.  A NIL hierarchy delimiter means
 45.3883 +      that no hierarchy exists; the name is a "flat" name.
 45.3884 +
 45.3885 +      The name represents an unambiguous left-to-right hierarchy, and
 45.3886 +      MUST be valid for use as a reference in LIST and LSUB commands.
 45.3887 +      Unless \Noselect is indicated, the name MUST also be valid as an
 45.3888 +      argument for commands, such as SELECT, that accept mailbox names.
 45.3889 +
 45.3890 +   Example:    S: * LIST (\Noselect) "/" ~/Mail/foo
 45.3891 +
 45.3892 +
 45.3893 +7.2.3.  LSUB Response
 45.3894 +
 45.3895 +   Contents:   name attributes
 45.3896 +               hierarchy delimiter
 45.3897 +               name
 45.3898 +
 45.3899 +      The LSUB response occurs as a result of an LSUB command.  It
 45.3900 +      returns a single name that matches the LSUB specification.  There
 45.3901 +      can be multiple LSUB responses for a single LSUB command.  The
 45.3902 +      data is identical in format to the LIST response.
 45.3903 +
 45.3904 +   Example:    S: * LSUB () "." #news.comp.mail.misc
 45.3905 +
 45.3906 +
 45.3907 +7.2.4   STATUS Response
 45.3908 +
 45.3909 +   Contents:   name
 45.3910 +               status parenthesized list
 45.3911 +
 45.3912 +      The STATUS response occurs as a result of an STATUS command.  It
 45.3913 +      returns the mailbox name that matches the STATUS specification and
 45.3914 +      the requested mailbox status information.
 45.3915 +
 45.3916 +   Example:    S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
 45.3917 +
 45.3918 +
 45.3919 +
 45.3920 +
 45.3921 +
 45.3922 +
 45.3923 +
 45.3924 +
 45.3925 +Crispin                     Standards Track                    [Page 70]
 45.3926 +
 45.3927 +RFC 3501                         IMAPv4                       March 2003
 45.3928 +
 45.3929 +
 45.3930 +7.2.5.  SEARCH Response
 45.3931 +
 45.3932 +   Contents:   zero or more numbers
 45.3933 +
 45.3934 +      The SEARCH response occurs as a result of a SEARCH or UID SEARCH
 45.3935 +      command.  The number(s) refer to those messages that match the
 45.3936 +      search criteria.  For SEARCH, these are message sequence numbers;
 45.3937 +      for UID SEARCH, these are unique identifiers.  Each number is
 45.3938 +      delimited by a space.
 45.3939 +
 45.3940 +   Example:    S: * SEARCH 2 3 6
 45.3941 +
 45.3942 +
 45.3943 +7.2.6.  FLAGS Response
 45.3944 +
 45.3945 +   Contents:   flag parenthesized list
 45.3946 +
 45.3947 +      The FLAGS response occurs as a result of a SELECT or EXAMINE
 45.3948 +      command.  The flag parenthesized list identifies the flags (at a
 45.3949 +      minimum, the system-defined flags) that are applicable for this
 45.3950 +      mailbox.  Flags other than the system flags can also exist,
 45.3951 +      depending on server implementation.
 45.3952 +
 45.3953 +      The update from the FLAGS response MUST be recorded by the client.
 45.3954 +
 45.3955 +   Example:    S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
 45.3956 +
 45.3957 +
 45.3958 +7.3.    Server Responses - Mailbox Size
 45.3959 +
 45.3960 +   These responses are always untagged.  This is how changes in the size
 45.3961 +   of the mailbox are transmitted from the server to the client.
 45.3962 +   Immediately following the "*" token is a number that represents a
 45.3963 +   message count.
 45.3964 +
 45.3965 +7.3.1.  EXISTS Response
 45.3966 +
 45.3967 +   Contents:   none
 45.3968 +
 45.3969 +      The EXISTS response reports the number of messages in the mailbox.
 45.3970 +      This response occurs as a result of a SELECT or EXAMINE command,
 45.3971 +      and if the size of the mailbox changes (e.g., new messages).
 45.3972 +
 45.3973 +      The update from the EXISTS response MUST be recorded by the
 45.3974 +      client.
 45.3975 +
 45.3976 +   Example:    S: * 23 EXISTS
 45.3977 +
 45.3978 +
 45.3979 +
 45.3980 +
 45.3981 +Crispin                     Standards Track                    [Page 71]
 45.3982 +
 45.3983 +RFC 3501                         IMAPv4                       March 2003
 45.3984 +
 45.3985 +
 45.3986 +7.3.2.  RECENT Response
 45.3987 +
 45.3988 +   Contents:   none
 45.3989 +
 45.3990 +      The RECENT response reports the number of messages with the
 45.3991 +      \Recent flag set.  This response occurs as a result of a SELECT or
 45.3992 +      EXAMINE command, and if the size of the mailbox changes (e.g., new
 45.3993 +      messages).
 45.3994 +
 45.3995 +           Note: It is not guaranteed that the message sequence
 45.3996 +           numbers of recent messages will be a contiguous range of
 45.3997 +           the highest n messages in the mailbox (where n is the
 45.3998 +           value reported by the RECENT response).  Examples of
 45.3999 +           situations in which this is not the case are: multiple
 45.4000 +           clients having the same mailbox open (the first session
 45.4001 +           to be notified will see it as recent, others will
 45.4002 +           probably see it as non-recent), and when the mailbox is
 45.4003 +           re-ordered by a non-IMAP agent.
 45.4004 +
 45.4005 +           The only reliable way to identify recent messages is to
 45.4006 +           look at message flags to see which have the \Recent flag
 45.4007 +           set, or to do a SEARCH RECENT.
 45.4008 +
 45.4009 +      The update from the RECENT response MUST be recorded by the
 45.4010 +      client.
 45.4011 +
 45.4012 +   Example:    S: * 5 RECENT
 45.4013 +
 45.4014 +
 45.4015 +7.4.    Server Responses - Message Status
 45.4016 +
 45.4017 +   These responses are always untagged.  This is how message data are
 45.4018 +   transmitted from the server to the client, often as a result of a
 45.4019 +   command with the same name.  Immediately following the "*" token is a
 45.4020 +   number that represents a message sequence number.
 45.4021 +
 45.4022 +7.4.1.  EXPUNGE Response
 45.4023 +
 45.4024 +   Contents:   none
 45.4025 +
 45.4026 +      The EXPUNGE response reports that the specified message sequence
 45.4027 +      number has been permanently removed from the mailbox.  The message
 45.4028 +      sequence number for each successive message in the mailbox is
 45.4029 +      immediately decremented by 1, and this decrement is reflected in
 45.4030 +      message sequence numbers in subsequent responses (including other
 45.4031 +      untagged EXPUNGE responses).
 45.4032 +
 45.4033 +
 45.4034 +
 45.4035 +
 45.4036 +
 45.4037 +Crispin                     Standards Track                    [Page 72]
 45.4038 +
 45.4039 +RFC 3501                         IMAPv4                       March 2003
 45.4040 +
 45.4041 +
 45.4042 +      The EXPUNGE response also decrements the number of messages in the
 45.4043 +      mailbox; it is not necessary to send an EXISTS response with the
 45.4044 +      new value.
 45.4045 +
 45.4046 +      As a result of the immediate decrement rule, message sequence
 45.4047 +      numbers that appear in a set of successive EXPUNGE responses
 45.4048 +      depend upon whether the messages are removed starting from lower
 45.4049 +      numbers to higher numbers, or from higher numbers to lower
 45.4050 +      numbers.  For example, if the last 5 messages in a 9-message
 45.4051 +      mailbox are expunged, a "lower to higher" server will send five
 45.4052 +      untagged EXPUNGE responses for message sequence number 5, whereas
 45.4053 +      a "higher to lower server" will send successive untagged EXPUNGE
 45.4054 +      responses for message sequence numbers 9, 8, 7, 6, and 5.
 45.4055 +
 45.4056 +      An EXPUNGE response MUST NOT be sent when no command is in
 45.4057 +      progress, nor while responding to a FETCH, STORE, or SEARCH
 45.4058 +      command.  This rule is necessary to prevent a loss of
 45.4059 +      synchronization of message sequence numbers between client and
 45.4060 +      server.  A command is not "in progress" until the complete command
 45.4061 +      has been received; in particular, a command is not "in progress"
 45.4062 +      during the negotiation of command continuation.
 45.4063 +
 45.4064 +           Note: UID FETCH, UID STORE, and UID SEARCH are different
 45.4065 +           commands from FETCH, STORE, and SEARCH.  An EXPUNGE
 45.4066 +           response MAY be sent during a UID command.
 45.4067 +
 45.4068 +      The update from the EXPUNGE response MUST be recorded by the
 45.4069 +      client.
 45.4070 +
 45.4071 +   Example:    S: * 44 EXPUNGE
 45.4072 +
 45.4073 +
 45.4074 +7.4.2.  FETCH Response
 45.4075 +
 45.4076 +   Contents:   message data
 45.4077 +
 45.4078 +      The FETCH response returns data about a message to the client.
 45.4079 +      The data are pairs of data item names and their values in
 45.4080 +      parentheses.  This response occurs as the result of a FETCH or
 45.4081 +      STORE command, as well as by unilateral server decision (e.g.,
 45.4082 +      flag updates).
 45.4083 +
 45.4084 +      The current data items are:
 45.4085 +
 45.4086 +      BODY
 45.4087 +         A form of BODYSTRUCTURE without extension data.
 45.4088 +
 45.4089 +
 45.4090 +
 45.4091 +
 45.4092 +
 45.4093 +Crispin                     Standards Track                    [Page 73]
 45.4094 +
 45.4095 +RFC 3501                         IMAPv4                       March 2003
 45.4096 +
 45.4097 +
 45.4098 +      BODY[<section>]<<origin octet>>
 45.4099 +         A string expressing the body contents of the specified section.
 45.4100 +         The string SHOULD be interpreted by the client according to the
 45.4101 +         content transfer encoding, body type, and subtype.
 45.4102 +
 45.4103 +         If the origin octet is specified, this string is a substring of
 45.4104 +         the entire body contents, starting at that origin octet.  This
 45.4105 +         means that BODY[]<0> MAY be truncated, but BODY[] is NEVER
 45.4106 +         truncated.
 45.4107 +
 45.4108 +            Note: The origin octet facility MUST NOT be used by a server
 45.4109 +            in a FETCH response unless the client specifically requested
 45.4110 +            it by means of a FETCH of a BODY[<section>]<<partial>> data
 45.4111 +            item.
 45.4112 +
 45.4113 +         8-bit textual data is permitted if a [CHARSET] identifier is
 45.4114 +         part of the body parameter parenthesized list for this section.
 45.4115 +         Note that headers (part specifiers HEADER or MIME, or the
 45.4116 +         header portion of a MESSAGE/RFC822 part), MUST be 7-bit; 8-bit
 45.4117 +         characters are not permitted in headers.  Note also that the
 45.4118 +         [RFC-2822] delimiting blank line between the header and the
 45.4119 +         body is not affected by header line subsetting; the blank line
 45.4120 +         is always included as part of header data, except in the case
 45.4121 +         of a message which has no body and no blank line.
 45.4122 +
 45.4123 +         Non-textual data such as binary data MUST be transfer encoded
 45.4124 +         into a textual form, such as BASE64, prior to being sent to the
 45.4125 +         client.  To derive the original binary data, the client MUST
 45.4126 +         decode the transfer encoded string.
 45.4127 +
 45.4128 +      BODYSTRUCTURE
 45.4129 +         A parenthesized list that describes the [MIME-IMB] body
 45.4130 +         structure of a message.  This is computed by the server by
 45.4131 +         parsing the [MIME-IMB] header fields, defaulting various fields
 45.4132 +         as necessary.
 45.4133 +
 45.4134 +         For example, a simple text message of 48 lines and 2279 octets
 45.4135 +         can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
 45.4136 +         "US-ASCII") NIL NIL "7BIT" 2279 48)
 45.4137 +
 45.4138 +         Multiple parts are indicated by parenthesis nesting.  Instead
 45.4139 +         of a body type as the first element of the parenthesized list,
 45.4140 +         there is a sequence of one or more nested body structures.  The
 45.4141 +         second element of the parenthesized list is the multipart
 45.4142 +         subtype (mixed, digest, parallel, alternative, etc.).
 45.4143 +
 45.4144 +
 45.4145 +
 45.4146 +
 45.4147 +
 45.4148 +
 45.4149 +Crispin                     Standards Track                    [Page 74]
 45.4150 +
 45.4151 +RFC 3501                         IMAPv4                       March 2003
 45.4152 +
 45.4153 +
 45.4154 +         For example, a two part message consisting of a text and a
 45.4155 +         BASE64-encoded text attachment can have a body structure of:
 45.4156 +         (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
 45.4157 +         23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
 45.4158 +         "<960723163407.20117h@cac.washington.edu>" "Compiler diff"
 45.4159 +         "BASE64" 4554 73) "MIXED")
 45.4160 +
 45.4161 +         Extension data follows the multipart subtype.  Extension data
 45.4162 +         is never returned with the BODY fetch, but can be returned with
 45.4163 +         a BODYSTRUCTURE fetch.  Extension data, if present, MUST be in
 45.4164 +         the defined order.  The extension data of a multipart body part
 45.4165 +         are in the following order:
 45.4166 +
 45.4167 +         body parameter parenthesized list
 45.4168 +            A parenthesized list of attribute/value pairs [e.g., ("foo"
 45.4169 +            "bar" "baz" "rag") where "bar" is the value of "foo", and
 45.4170 +            "rag" is the value of "baz"] as defined in [MIME-IMB].
 45.4171 +
 45.4172 +         body disposition
 45.4173 +            A parenthesized list, consisting of a disposition type
 45.4174 +            string, followed by a parenthesized list of disposition
 45.4175 +            attribute/value pairs as defined in [DISPOSITION].
 45.4176 +
 45.4177 +         body language
 45.4178 +            A string or parenthesized list giving the body language
 45.4179 +            value as defined in [LANGUAGE-TAGS].
 45.4180 +
 45.4181 +         body location
 45.4182 +            A string list giving the body content URI as defined in
 45.4183 +            [LOCATION].
 45.4184 +
 45.4185 +         Any following extension data are not yet defined in this
 45.4186 +         version of the protocol.  Such extension data can consist of
 45.4187 +         zero or more NILs, strings, numbers, or potentially nested
 45.4188 +         parenthesized lists of such data.  Client implementations that
 45.4189 +         do a BODYSTRUCTURE fetch MUST be prepared to accept such
 45.4190 +         extension data.  Server implementations MUST NOT send such
 45.4191 +         extension data until it has been defined by a revision of this
 45.4192 +         protocol.
 45.4193 +
 45.4194 +         The basic fields of a non-multipart body part are in the
 45.4195 +         following order:
 45.4196 +
 45.4197 +         body type
 45.4198 +            A string giving the content media type name as defined in
 45.4199 +            [MIME-IMB].
 45.4200 +
 45.4201 +
 45.4202 +
 45.4203 +
 45.4204 +
 45.4205 +Crispin                     Standards Track                    [Page 75]
 45.4206 +
 45.4207 +RFC 3501                         IMAPv4                       March 2003
 45.4208 +
 45.4209 +
 45.4210 +         body subtype
 45.4211 +            A string giving the content subtype name as defined in
 45.4212 +            [MIME-IMB].
 45.4213 +
 45.4214 +         body parameter parenthesized list
 45.4215 +            A parenthesized list of attribute/value pairs [e.g., ("foo"
 45.4216 +            "bar" "baz" "rag") where "bar" is the value of "foo" and
 45.4217 +            "rag" is the value of "baz"] as defined in [MIME-IMB].
 45.4218 +
 45.4219 +         body id
 45.4220 +            A string giving the content id as defined in [MIME-IMB].
 45.4221 +
 45.4222 +         body description
 45.4223 +            A string giving the content description as defined in
 45.4224 +            [MIME-IMB].
 45.4225 +
 45.4226 +         body encoding
 45.4227 +            A string giving the content transfer encoding as defined in
 45.4228 +            [MIME-IMB].
 45.4229 +
 45.4230 +         body size
 45.4231 +            A number giving the size of the body in octets.  Note that
 45.4232 +            this size is the size in its transfer encoding and not the
 45.4233 +            resulting size after any decoding.
 45.4234 +
 45.4235 +         A body type of type MESSAGE and subtype RFC822 contains,
 45.4236 +         immediately after the basic fields, the envelope structure,
 45.4237 +         body structure, and size in text lines of the encapsulated
 45.4238 +         message.
 45.4239 +
 45.4240 +         A body type of type TEXT contains, immediately after the basic
 45.4241 +         fields, the size of the body in text lines.  Note that this
 45.4242 +         size is the size in its content transfer encoding and not the
 45.4243 +         resulting size after any decoding.
 45.4244 +
 45.4245 +         Extension data follows the basic fields and the type-specific
 45.4246 +         fields listed above.  Extension data is never returned with the
 45.4247 +         BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
 45.4248 +         Extension data, if present, MUST be in the defined order.
 45.4249 +
 45.4250 +         The extension data of a non-multipart body part are in the
 45.4251 +         following order:
 45.4252 +
 45.4253 +         body MD5
 45.4254 +            A string giving the body MD5 value as defined in [MD5].
 45.4255 +
 45.4256 +
 45.4257 +
 45.4258 +
 45.4259 +
 45.4260 +
 45.4261 +Crispin                     Standards Track                    [Page 76]
 45.4262 +
 45.4263 +RFC 3501                         IMAPv4                       March 2003
 45.4264 +
 45.4265 +
 45.4266 +         body disposition
 45.4267 +            A parenthesized list with the same content and function as
 45.4268 +            the body disposition for a multipart body part.
 45.4269 +
 45.4270 +         body language
 45.4271 +            A string or parenthesized list giving the body language
 45.4272 +            value as defined in [LANGUAGE-TAGS].
 45.4273 +
 45.4274 +         body location
 45.4275 +            A string list giving the body content URI as defined in
 45.4276 +            [LOCATION].
 45.4277 +
 45.4278 +         Any following extension data are not yet defined in this
 45.4279 +         version of the protocol, and would be as described above under
 45.4280 +         multipart extension data.
 45.4281 +
 45.4282 +      ENVELOPE
 45.4283 +         A parenthesized list that describes the envelope structure of a
 45.4284 +         message.  This is computed by the server by parsing the
 45.4285 +         [RFC-2822] header into the component parts, defaulting various
 45.4286 +         fields as necessary.
 45.4287 +
 45.4288 +         The fields of the envelope structure are in the following
 45.4289 +         order: date, subject, from, sender, reply-to, to, cc, bcc,
 45.4290 +         in-reply-to, and message-id.  The date, subject, in-reply-to,
 45.4291 +         and message-id fields are strings.  The from, sender, reply-to,
 45.4292 +         to, cc, and bcc fields are parenthesized lists of address
 45.4293 +         structures.
 45.4294 +
 45.4295 +         An address structure is a parenthesized list that describes an
 45.4296 +         electronic mail address.  The fields of an address structure
 45.4297 +         are in the following order: personal name, [SMTP]
 45.4298 +         at-domain-list (source route), mailbox name, and host name.
 45.4299 +
 45.4300 +         [RFC-2822] group syntax is indicated by a special form of
 45.4301 +         address structure in which the host name field is NIL.  If the
 45.4302 +         mailbox name field is also NIL, this is an end of group marker
 45.4303 +         (semi-colon in RFC 822 syntax).  If the mailbox name field is
 45.4304 +         non-NIL, this is a start of group marker, and the mailbox name
 45.4305 +         field holds the group name phrase.
 45.4306 +
 45.4307 +         If the Date, Subject, In-Reply-To, and Message-ID header lines
 45.4308 +         are absent in the [RFC-2822] header, the corresponding member
 45.4309 +         of the envelope is NIL; if these header lines are present but
 45.4310 +         empty the corresponding member of the envelope is the empty
 45.4311 +         string.
 45.4312 +
 45.4313 +
 45.4314 +
 45.4315 +
 45.4316 +
 45.4317 +Crispin                     Standards Track                    [Page 77]
 45.4318 +
 45.4319 +RFC 3501                         IMAPv4                       March 2003
 45.4320 +
 45.4321 +
 45.4322 +            Note: some servers may return a NIL envelope member in the
 45.4323 +            "present but empty" case.  Clients SHOULD treat NIL and
 45.4324 +            empty string as identical.
 45.4325 +
 45.4326 +            Note: [RFC-2822] requires that all messages have a valid
 45.4327 +            Date header.  Therefore, the date member in the envelope can
 45.4328 +            not be NIL or the empty string.
 45.4329 +
 45.4330 +            Note: [RFC-2822] requires that the In-Reply-To and
 45.4331 +            Message-ID headers, if present, have non-empty content.
 45.4332 +            Therefore, the in-reply-to and message-id members in the
 45.4333 +            envelope can not be the empty string.
 45.4334 +
 45.4335 +         If the From, To, cc, and bcc header lines are absent in the
 45.4336 +         [RFC-2822] header, or are present but empty, the corresponding
 45.4337 +         member of the envelope is NIL.
 45.4338 +
 45.4339 +         If the Sender or Reply-To lines are absent in the [RFC-2822]
 45.4340 +         header, or are present but empty, the server sets the
 45.4341 +         corresponding member of the envelope to be the same value as
 45.4342 +         the from member (the client is not expected to know to do
 45.4343 +         this).
 45.4344 +
 45.4345 +            Note: [RFC-2822] requires that all messages have a valid
 45.4346 +            From header.  Therefore, the from, sender, and reply-to
 45.4347 +            members in the envelope can not be NIL.
 45.4348 +
 45.4349 +      FLAGS
 45.4350 +         A parenthesized list of flags that are set for this message.
 45.4351 +
 45.4352 +      INTERNALDATE
 45.4353 +         A string representing the internal date of the message.
 45.4354 +
 45.4355 +      RFC822
 45.4356 +         Equivalent to BODY[].
 45.4357 +
 45.4358 +      RFC822.HEADER
 45.4359 +         Equivalent to BODY[HEADER].  Note that this did not result in
 45.4360 +         \Seen being set, because RFC822.HEADER response data occurs as
 45.4361 +         a result of a FETCH of RFC822.HEADER.  BODY[HEADER] response
 45.4362 +         data occurs as a result of a FETCH of BODY[HEADER] (which sets
 45.4363 +         \Seen) or BODY.PEEK[HEADER] (which does not set \Seen).
 45.4364 +
 45.4365 +      RFC822.SIZE
 45.4366 +         A number expressing the [RFC-2822] size of the message.
 45.4367 +
 45.4368 +
 45.4369 +
 45.4370 +
 45.4371 +
 45.4372 +
 45.4373 +Crispin                     Standards Track                    [Page 78]
 45.4374 +
 45.4375 +RFC 3501                         IMAPv4                       March 2003
 45.4376 +
 45.4377 +
 45.4378 +      RFC822.TEXT
 45.4379 +         Equivalent to BODY[TEXT].
 45.4380 +
 45.4381 +      UID
 45.4382 +         A number expressing the unique identifier of the message.
 45.4383 +
 45.4384 +
 45.4385 +   Example:    S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)
 45.4386 +
 45.4387 +
 45.4388 +7.5.    Server Responses - Command Continuation Request
 45.4389 +
 45.4390 +   The command continuation request response is indicated by a "+" token
 45.4391 +   instead of a tag.  This form of response indicates that the server is
 45.4392 +   ready to accept the continuation of a command from the client.  The
 45.4393 +   remainder of this response is a line of text.
 45.4394 +
 45.4395 +   This response is used in the AUTHENTICATE command to transmit server
 45.4396 +   data to the client, and request additional client data.  This
 45.4397 +   response is also used if an argument to any command is a literal.
 45.4398 +
 45.4399 +   The client is not permitted to send the octets of the literal unless
 45.4400 +   the server indicates that it is expected.  This permits the server to
 45.4401 +   process commands and reject errors on a line-by-line basis.  The
 45.4402 +   remainder of the command, including the CRLF that terminates a
 45.4403 +   command, follows the octets of the literal.  If there are any
 45.4404 +   additional command arguments, the literal octets are followed by a
 45.4405 +   space and those arguments.
 45.4406 +
 45.4407 +   Example:    C: A001 LOGIN {11}
 45.4408 +               S: + Ready for additional command text
 45.4409 +               C: FRED FOOBAR {7}
 45.4410 +               S: + Ready for additional command text
 45.4411 +               C: fat man
 45.4412 +               S: A001 OK LOGIN completed
 45.4413 +               C: A044 BLURDYBLOOP {102856}
 45.4414 +               S: A044 BAD No such command as "BLURDYBLOOP"
 45.4415 +
 45.4416 +
 45.4417 +
 45.4418 +
 45.4419 +
 45.4420 +
 45.4421 +
 45.4422 +
 45.4423 +
 45.4424 +
 45.4425 +
 45.4426 +
 45.4427 +
 45.4428 +
 45.4429 +Crispin                     Standards Track                    [Page 79]
 45.4430 +
 45.4431 +RFC 3501                         IMAPv4                       March 2003
 45.4432 +
 45.4433 +
 45.4434 +8.      Sample IMAP4rev1 connection
 45.4435 +
 45.4436 +   The following is a transcript of an IMAP4rev1 connection.  A long
 45.4437 +   line in this sample is broken for editorial clarity.
 45.4438 +
 45.4439 +S:   * OK IMAP4rev1 Service Ready
 45.4440 +C:   a001 login mrc secret
 45.4441 +S:   a001 OK LOGIN completed
 45.4442 +C:   a002 select inbox
 45.4443 +S:   * 18 EXISTS
 45.4444 +S:   * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
 45.4445 +S:   * 2 RECENT
 45.4446 +S:   * OK [UNSEEN 17] Message 17 is the first unseen message
 45.4447 +S:   * OK [UIDVALIDITY 3857529045] UIDs valid
 45.4448 +S:   a002 OK [READ-WRITE] SELECT completed
 45.4449 +C:   a003 fetch 12 full
 45.4450 +S:   * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700"
 45.4451 +      RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"
 45.4452 +      "IMAP4rev1 WG mtg summary and minutes"
 45.4453 +      (("Terry Gray" NIL "gray" "cac.washington.edu"))
 45.4454 +      (("Terry Gray" NIL "gray" "cac.washington.edu"))
 45.4455 +      (("Terry Gray" NIL "gray" "cac.washington.edu"))
 45.4456 +      ((NIL NIL "imap" "cac.washington.edu"))
 45.4457 +      ((NIL NIL "minutes" "CNRI.Reston.VA.US")
 45.4458 +      ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL
 45.4459 +      "<B27397-0100000@cac.washington.edu>")
 45.4460 +       BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028
 45.4461 +       92))
 45.4462 +S:    a003 OK FETCH completed
 45.4463 +C:    a004 fetch 12 body[header]
 45.4464 +S:    * 12 FETCH (BODY[HEADER] {342}
 45.4465 +S:    Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT)
 45.4466 +S:    From: Terry Gray <gray@cac.washington.edu>
 45.4467 +S:    Subject: IMAP4rev1 WG mtg summary and minutes
 45.4468 +S:    To: imap@cac.washington.edu
 45.4469 +S:    cc: minutes@CNRI.Reston.VA.US, John Klensin <KLENSIN@MIT.EDU>
 45.4470 +S:    Message-Id: <B27397-0100000@cac.washington.edu>
 45.4471 +S:    MIME-Version: 1.0
 45.4472 +S:    Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
 45.4473 +S:
 45.4474 +S:    )
 45.4475 +S:    a004 OK FETCH completed
 45.4476 +C:    a005 store 12 +flags \deleted
 45.4477 +S:    * 12 FETCH (FLAGS (\Seen \Deleted))
 45.4478 +S:    a005 OK +FLAGS completed
 45.4479 +C:    a006 logout
 45.4480 +S:    * BYE IMAP4rev1 server terminating connection
 45.4481 +S:    a006 OK LOGOUT completed
 45.4482 +
 45.4483 +
 45.4484 +
 45.4485 +Crispin                     Standards Track                    [Page 80]
 45.4486 +
 45.4487 +RFC 3501                         IMAPv4                       March 2003
 45.4488 +
 45.4489 +
 45.4490 +9.      Formal Syntax
 45.4491 +
 45.4492 +   The following syntax specification uses the Augmented Backus-Naur
 45.4493 +   Form (ABNF) notation as specified in [ABNF].
 45.4494 +
 45.4495 +   In the case of alternative or optional rules in which a later rule
 45.4496 +   overlaps an earlier rule, the rule which is listed earlier MUST take
 45.4497 +   priority.  For example, "\Seen" when parsed as a flag is the \Seen
 45.4498 +   flag name and not a flag-extension, even though "\Seen" can be parsed
 45.4499 +   as a flag-extension.  Some, but not all, instances of this rule are
 45.4500 +   noted below.
 45.4501 +
 45.4502 +        Note: [ABNF] rules MUST be followed strictly; in
 45.4503 +        particular:
 45.4504 +
 45.4505 +        (1) Except as noted otherwise, all alphabetic characters
 45.4506 +        are case-insensitive.  The use of upper or lower case
 45.4507 +        characters to define token strings is for editorial clarity
 45.4508 +        only.  Implementations MUST accept these strings in a
 45.4509 +        case-insensitive fashion.
 45.4510 +
 45.4511 +        (2) In all cases, SP refers to exactly one space.  It is
 45.4512 +        NOT permitted to substitute TAB, insert additional spaces,
 45.4513 +        or otherwise treat SP as being equivalent to LWSP.
 45.4514 +
 45.4515 +        (3) The ASCII NUL character, %x00, MUST NOT be used at any
 45.4516 +        time.
 45.4517 +
 45.4518 +address         = "(" addr-name SP addr-adl SP addr-mailbox SP
 45.4519 +                  addr-host ")"
 45.4520 +
 45.4521 +addr-adl        = nstring
 45.4522 +                    ; Holds route from [RFC-2822] route-addr if
 45.4523 +                    ; non-NIL
 45.4524 +
 45.4525 +addr-host       = nstring
 45.4526 +                    ; NIL indicates [RFC-2822] group syntax.
 45.4527 +                    ; Otherwise, holds [RFC-2822] domain name
 45.4528 +
 45.4529 +addr-mailbox    = nstring
 45.4530 +                    ; NIL indicates end of [RFC-2822] group; if
 45.4531 +                    ; non-NIL and addr-host is NIL, holds
 45.4532 +                    ; [RFC-2822] group name.
 45.4533 +                    ; Otherwise, holds [RFC-2822] local-part
 45.4534 +                    ; after removing [RFC-2822] quoting
 45.4535 +
 45.4536 +
 45.4537 +
 45.4538 +
 45.4539 +
 45.4540 +
 45.4541 +Crispin                     Standards Track                    [Page 81]
 45.4542 +
 45.4543 +RFC 3501                         IMAPv4                       March 2003
 45.4544 +
 45.4545 +
 45.4546 +addr-name       = nstring
 45.4547 +                    ; If non-NIL, holds phrase from [RFC-2822]
 45.4548 +                    ; mailbox after removing [RFC-2822] quoting
 45.4549 +
 45.4550 +append          = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP
 45.4551 +                  literal
 45.4552 +
 45.4553 +astring         = 1*ASTRING-CHAR / string
 45.4554 +
 45.4555 +ASTRING-CHAR   = ATOM-CHAR / resp-specials
 45.4556 +
 45.4557 +atom            = 1*ATOM-CHAR
 45.4558 +
 45.4559 +ATOM-CHAR       = <any CHAR except atom-specials>
 45.4560 +
 45.4561 +atom-specials   = "(" / ")" / "{" / SP / CTL / list-wildcards /
 45.4562 +                  quoted-specials / resp-specials
 45.4563 +
 45.4564 +authenticate    = "AUTHENTICATE" SP auth-type *(CRLF base64)
 45.4565 +
 45.4566 +auth-type       = atom
 45.4567 +                    ; Defined by [SASL]
 45.4568 +
 45.4569 +base64          = *(4base64-char) [base64-terminal]
 45.4570 +
 45.4571 +base64-char     = ALPHA / DIGIT / "+" / "/"
 45.4572 +                    ; Case-sensitive
 45.4573 +
 45.4574 +base64-terminal = (2base64-char "==") / (3base64-char "=")
 45.4575 +
 45.4576 +body            = "(" (body-type-1part / body-type-mpart) ")"
 45.4577 +
 45.4578 +body-extension  = nstring / number /
 45.4579 +                   "(" body-extension *(SP body-extension) ")"
 45.4580 +                    ; Future expansion.  Client implementations
 45.4581 +                    ; MUST accept body-extension fields.  Server
 45.4582 +                    ; implementations MUST NOT generate
 45.4583 +                    ; body-extension fields except as defined by
 45.4584 +                    ; future standard or standards-track
 45.4585 +                    ; revisions of this specification.
 45.4586 +
 45.4587 +body-ext-1part  = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
 45.4588 +                  [SP body-fld-loc *(SP body-extension)]]]
 45.4589 +                    ; MUST NOT be returned on non-extensible
 45.4590 +                    ; "BODY" fetch
 45.4591 +
 45.4592 +
 45.4593 +
 45.4594 +
 45.4595 +
 45.4596 +
 45.4597 +Crispin                     Standards Track                    [Page 82]
 45.4598 +
 45.4599 +RFC 3501                         IMAPv4                       March 2003
 45.4600 +
 45.4601 +
 45.4602 +body-ext-mpart  = body-fld-param [SP body-fld-dsp [SP body-fld-lang
 45.4603 +                  [SP body-fld-loc *(SP body-extension)]]]
 45.4604 +                    ; MUST NOT be returned on non-extensible
 45.4605 +                    ; "BODY" fetch
 45.4606 +
 45.4607 +body-fields     = body-fld-param SP body-fld-id SP body-fld-desc SP
 45.4608 +                  body-fld-enc SP body-fld-octets
 45.4609 +
 45.4610 +body-fld-desc   = nstring
 45.4611 +
 45.4612 +body-fld-dsp    = "(" string SP body-fld-param ")" / nil
 45.4613 +
 45.4614 +body-fld-enc    = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
 45.4615 +                  "QUOTED-PRINTABLE") DQUOTE) / string
 45.4616 +
 45.4617 +body-fld-id     = nstring
 45.4618 +
 45.4619 +body-fld-lang   = nstring / "(" string *(SP string) ")"
 45.4620 +
 45.4621 +body-fld-loc    = nstring
 45.4622 +
 45.4623 +body-fld-lines  = number
 45.4624 +
 45.4625 +body-fld-md5    = nstring
 45.4626 +
 45.4627 +body-fld-octets = number
 45.4628 +
 45.4629 +body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil
 45.4630 +
 45.4631 +body-type-1part = (body-type-basic / body-type-msg / body-type-text)
 45.4632 +                  [SP body-ext-1part]
 45.4633 +
 45.4634 +body-type-basic = media-basic SP body-fields
 45.4635 +                    ; MESSAGE subtype MUST NOT be "RFC822"
 45.4636 +
 45.4637 +body-type-mpart = 1*body SP media-subtype
 45.4638 +                  [SP body-ext-mpart]
 45.4639 +
 45.4640 +body-type-msg   = media-message SP body-fields SP envelope
 45.4641 +                  SP body SP body-fld-lines
 45.4642 +
 45.4643 +body-type-text  = media-text SP body-fields SP body-fld-lines
 45.4644 +
 45.4645 +capability      = ("AUTH=" auth-type) / atom
 45.4646 +                    ; New capabilities MUST begin with "X" or be
 45.4647 +                    ; registered with IANA as standard or
 45.4648 +                    ; standards-track
 45.4649 +
 45.4650 +
 45.4651 +
 45.4652 +
 45.4653 +Crispin                     Standards Track                    [Page 83]
 45.4654 +
 45.4655 +RFC 3501                         IMAPv4                       March 2003
 45.4656 +
 45.4657 +
 45.4658 +capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
 45.4659 +                  *(SP capability)
 45.4660 +                    ; Servers MUST implement the STARTTLS, AUTH=PLAIN,
 45.4661 +                    ; and LOGINDISABLED capabilities
 45.4662 +                    ; Servers which offer RFC 1730 compatibility MUST
 45.4663 +                    ; list "IMAP4" as the first capability.
 45.4664 +
 45.4665 +CHAR8           = %x01-ff
 45.4666 +                    ; any OCTET except NUL, %x00
 45.4667 +
 45.4668 +command         = tag SP (command-any / command-auth / command-nonauth /
 45.4669 +                  command-select) CRLF
 45.4670 +                    ; Modal based on state
 45.4671 +
 45.4672 +command-any     = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command
 45.4673 +                    ; Valid in all states
 45.4674 +
 45.4675 +command-auth    = append / create / delete / examine / list / lsub /
 45.4676 +                  rename / select / status / subscribe / unsubscribe
 45.4677 +                    ; Valid only in Authenticated or Selected state
 45.4678 +
 45.4679 +command-nonauth = login / authenticate / "STARTTLS"
 45.4680 +                    ; Valid only when in Not Authenticated state
 45.4681 +
 45.4682 +command-select  = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store /
 45.4683 +                  uid / search
 45.4684 +                    ; Valid only when in Selected state
 45.4685 +
 45.4686 +continue-req    = "+" SP (resp-text / base64) CRLF
 45.4687 +
 45.4688 +copy            = "COPY" SP sequence-set SP mailbox
 45.4689 +
 45.4690 +create          = "CREATE" SP mailbox
 45.4691 +                    ; Use of INBOX gives a NO error
 45.4692 +
 45.4693 +date            = date-text / DQUOTE date-text DQUOTE
 45.4694 +
 45.4695 +date-day        = 1*2DIGIT
 45.4696 +                    ; Day of month
 45.4697 +
 45.4698 +date-day-fixed  = (SP DIGIT) / 2DIGIT
 45.4699 +                    ; Fixed-format version of date-day
 45.4700 +
 45.4701 +date-month      = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
 45.4702 +                  "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
 45.4703 +
 45.4704 +date-text       = date-day "-" date-month "-" date-year
 45.4705 +
 45.4706 +
 45.4707 +
 45.4708 +
 45.4709 +Crispin                     Standards Track                    [Page 84]
 45.4710 +
 45.4711 +RFC 3501                         IMAPv4                       March 2003
 45.4712 +
 45.4713 +
 45.4714 +date-year       = 4DIGIT
 45.4715 +
 45.4716 +date-time       = DQUOTE date-day-fixed "-" date-month "-" date-year
 45.4717 +                  SP time SP zone DQUOTE
 45.4718 +
 45.4719 +delete          = "DELETE" SP mailbox
 45.4720 +                    ; Use of INBOX gives a NO error
 45.4721 +
 45.4722 +digit-nz        = %x31-39
 45.4723 +                    ; 1-9
 45.4724 +
 45.4725 +envelope        = "(" env-date SP env-subject SP env-from SP
 45.4726 +                  env-sender SP env-reply-to SP env-to SP env-cc SP
 45.4727 +                  env-bcc SP env-in-reply-to SP env-message-id ")"
 45.4728 +
 45.4729 +env-bcc         = "(" 1*address ")" / nil
 45.4730 +
 45.4731 +env-cc          = "(" 1*address ")" / nil
 45.4732 +
 45.4733 +env-date        = nstring
 45.4734 +
 45.4735 +env-from        = "(" 1*address ")" / nil
 45.4736 +
 45.4737 +env-in-reply-to = nstring
 45.4738 +
 45.4739 +env-message-id  = nstring
 45.4740 +
 45.4741 +env-reply-to    = "(" 1*address ")" / nil
 45.4742 +
 45.4743 +env-sender      = "(" 1*address ")" / nil
 45.4744 +
 45.4745 +env-subject     = nstring
 45.4746 +
 45.4747 +env-to          = "(" 1*address ")" / nil
 45.4748 +
 45.4749 +examine         = "EXAMINE" SP mailbox
 45.4750 +
 45.4751 +fetch           = "FETCH" SP sequence-set SP ("ALL" / "FULL" / "FAST" /
 45.4752 +                  fetch-att / "(" fetch-att *(SP fetch-att) ")")
 45.4753 +
 45.4754 +fetch-att       = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
 45.4755 +                  "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
 45.4756 +                  "BODY" ["STRUCTURE"] / "UID" /
 45.4757 +                  "BODY" section ["<" number "." nz-number ">"] /
 45.4758 +                  "BODY.PEEK" section ["<" number "." nz-number ">"]
 45.4759 +
 45.4760 +
 45.4761 +
 45.4762 +
 45.4763 +
 45.4764 +
 45.4765 +Crispin                     Standards Track                    [Page 85]
 45.4766 +
 45.4767 +RFC 3501                         IMAPv4                       March 2003
 45.4768 +
 45.4769 +
 45.4770 +flag            = "\Answered" / "\Flagged" / "\Deleted" /
 45.4771 +                  "\Seen" / "\Draft" / flag-keyword / flag-extension
 45.4772 +                    ; Does not include "\Recent"
 45.4773 +
 45.4774 +flag-extension  = "\" atom
 45.4775 +                    ; Future expansion.  Client implementations
 45.4776 +                    ; MUST accept flag-extension flags.  Server
 45.4777 +                    ; implementations MUST NOT generate
 45.4778 +                    ; flag-extension flags except as defined by
 45.4779 +                    ; future standard or standards-track
 45.4780 +                    ; revisions of this specification.
 45.4781 +
 45.4782 +flag-fetch      = flag / "\Recent"
 45.4783 +
 45.4784 +flag-keyword    = atom
 45.4785 +
 45.4786 +flag-list       = "(" [flag *(SP flag)] ")"
 45.4787 +
 45.4788 +flag-perm       = flag / "\*"
 45.4789 +
 45.4790 +greeting        = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
 45.4791 +
 45.4792 +header-fld-name = astring
 45.4793 +
 45.4794 +header-list     = "(" header-fld-name *(SP header-fld-name) ")"
 45.4795 +
 45.4796 +list            = "LIST" SP mailbox SP list-mailbox
 45.4797 +
 45.4798 +list-mailbox    = 1*list-char / string
 45.4799 +
 45.4800 +list-char       = ATOM-CHAR / list-wildcards / resp-specials
 45.4801 +
 45.4802 +list-wildcards  = "%" / "*"
 45.4803 +
 45.4804 +literal         = "{" number "}" CRLF *CHAR8
 45.4805 +                    ; Number represents the number of CHAR8s
 45.4806 +
 45.4807 +login           = "LOGIN" SP userid SP password
 45.4808 +
 45.4809 +lsub            = "LSUB" SP mailbox SP list-mailbox
 45.4810 +
 45.4811 +
 45.4812 +
 45.4813 +
 45.4814 +
 45.4815 +
 45.4816 +
 45.4817 +
 45.4818 +
 45.4819 +
 45.4820 +
 45.4821 +Crispin                     Standards Track                    [Page 86]
 45.4822 +
 45.4823 +RFC 3501                         IMAPv4                       March 2003
 45.4824 +
 45.4825 +
 45.4826 +mailbox         = "INBOX" / astring
 45.4827 +                    ; INBOX is case-insensitive.  All case variants of
 45.4828 +                    ; INBOX (e.g., "iNbOx") MUST be interpreted as INBOX
 45.4829 +                    ; not as an astring.  An astring which consists of
 45.4830 +                    ; the case-insensitive sequence "I" "N" "B" "O" "X"
 45.4831 +                    ; is considered to be INBOX and not an astring.
 45.4832 +                    ;  Refer to section 5.1 for further
 45.4833 +                    ; semantic details of mailbox names.
 45.4834 +
 45.4835 +mailbox-data    =  "FLAGS" SP flag-list / "LIST" SP mailbox-list /
 45.4836 +                   "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
 45.4837 +                   "STATUS" SP mailbox SP "(" [status-att-list] ")" /
 45.4838 +                   number SP "EXISTS" / number SP "RECENT"
 45.4839 +
 45.4840 +mailbox-list    = "(" [mbx-list-flags] ")" SP
 45.4841 +                   (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
 45.4842 +
 45.4843 +mbx-list-flags  = *(mbx-list-oflag SP) mbx-list-sflag
 45.4844 +                  *(SP mbx-list-oflag) /
 45.4845 +                  mbx-list-oflag *(SP mbx-list-oflag)
 45.4846 +
 45.4847 +mbx-list-oflag  = "\Noinferiors" / flag-extension
 45.4848 +                    ; Other flags; multiple possible per LIST response
 45.4849 +
 45.4850 +mbx-list-sflag  = "\Noselect" / "\Marked" / "\Unmarked"
 45.4851 +                    ; Selectability flags; only one per LIST response
 45.4852 +
 45.4853 +media-basic     = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
 45.4854 +                  "MESSAGE" / "VIDEO") DQUOTE) / string) SP
 45.4855 +                  media-subtype
 45.4856 +                    ; Defined in [MIME-IMT]
 45.4857 +
 45.4858 +media-message   = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
 45.4859 +                    ; Defined in [MIME-IMT]
 45.4860 +
 45.4861 +media-subtype   = string
 45.4862 +                    ; Defined in [MIME-IMT]
 45.4863 +
 45.4864 +media-text      = DQUOTE "TEXT" DQUOTE SP media-subtype
 45.4865 +                    ; Defined in [MIME-IMT]
 45.4866 +
 45.4867 +message-data    = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
 45.4868 +
 45.4869 +msg-att         = "(" (msg-att-dynamic / msg-att-static)
 45.4870 +                   *(SP (msg-att-dynamic / msg-att-static)) ")"
 45.4871 +
 45.4872 +msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
 45.4873 +                    ; MAY change for a message
 45.4874 +
 45.4875 +
 45.4876 +
 45.4877 +Crispin                     Standards Track                    [Page 87]
 45.4878 +
 45.4879 +RFC 3501                         IMAPv4                       March 2003
 45.4880 +
 45.4881 +
 45.4882 +msg-att-static  = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time /
 45.4883 +                  "RFC822" [".HEADER" / ".TEXT"] SP nstring /
 45.4884 +                  "RFC822.SIZE" SP number /
 45.4885 +                  "BODY" ["STRUCTURE"] SP body /
 45.4886 +                  "BODY" section ["<" number ">"] SP nstring /
 45.4887 +                  "UID" SP uniqueid
 45.4888 +                    ; MUST NOT change for a message
 45.4889 +
 45.4890 +nil             = "NIL"
 45.4891 +
 45.4892 +nstring         = string / nil
 45.4893 +
 45.4894 +number          = 1*DIGIT
 45.4895 +                    ; Unsigned 32-bit integer
 45.4896 +                    ; (0 <= n < 4,294,967,296)
 45.4897 +
 45.4898 +nz-number       = digit-nz *DIGIT
 45.4899 +                    ; Non-zero unsigned 32-bit integer
 45.4900 +                    ; (0 < n < 4,294,967,296)
 45.4901 +
 45.4902 +password        = astring
 45.4903 +
 45.4904 +quoted          = DQUOTE *QUOTED-CHAR DQUOTE
 45.4905 +
 45.4906 +QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> /
 45.4907 +                  "\" quoted-specials
 45.4908 +
 45.4909 +quoted-specials = DQUOTE / "\"
 45.4910 +
 45.4911 +rename          = "RENAME" SP mailbox SP mailbox
 45.4912 +                    ; Use of INBOX as a destination gives a NO error
 45.4913 +
 45.4914 +response        = *(continue-req / response-data) response-done
 45.4915 +
 45.4916 +response-data   = "*" SP (resp-cond-state / resp-cond-bye /
 45.4917 +                  mailbox-data / message-data / capability-data) CRLF
 45.4918 +
 45.4919 +response-done   = response-tagged / response-fatal
 45.4920 +
 45.4921 +response-fatal  = "*" SP resp-cond-bye CRLF
 45.4922 +                    ; Server closes connection immediately
 45.4923 +
 45.4924 +response-tagged = tag SP resp-cond-state CRLF
 45.4925 +
 45.4926 +resp-cond-auth  = ("OK" / "PREAUTH") SP resp-text
 45.4927 +                    ; Authentication condition
 45.4928 +
 45.4929 +
 45.4930 +
 45.4931 +
 45.4932 +
 45.4933 +Crispin                     Standards Track                    [Page 88]
 45.4934 +
 45.4935 +RFC 3501                         IMAPv4                       March 2003
 45.4936 +
 45.4937 +
 45.4938 +resp-cond-bye   = "BYE" SP resp-text
 45.4939 +
 45.4940 +resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
 45.4941 +                    ; Status condition
 45.4942 +
 45.4943 +resp-specials   = "]"
 45.4944 +
 45.4945 +resp-text       = ["[" resp-text-code "]" SP] text
 45.4946 +
 45.4947 +resp-text-code  = "ALERT" /
 45.4948 +                  "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
 45.4949 +                  capability-data / "PARSE" /
 45.4950 +                  "PERMANENTFLAGS" SP "("
 45.4951 +                  [flag-perm *(SP flag-perm)] ")" /
 45.4952 +                  "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
 45.4953 +                  "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
 45.4954 +                  "UNSEEN" SP nz-number /
 45.4955 +                  atom [SP 1*<any TEXT-CHAR except "]">]
 45.4956 +
 45.4957 +search          = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key)
 45.4958 +                    ; CHARSET argument to MUST be registered with IANA
 45.4959 +
 45.4960 +search-key      = "ALL" / "ANSWERED" / "BCC" SP astring /
 45.4961 +                  "BEFORE" SP date / "BODY" SP astring /
 45.4962 +                  "CC" SP astring / "DELETED" / "FLAGGED" /
 45.4963 +                  "FROM" SP astring / "KEYWORD" SP flag-keyword /
 45.4964 +                  "NEW" / "OLD" / "ON" SP date / "RECENT" / "SEEN" /
 45.4965 +                  "SINCE" SP date / "SUBJECT" SP astring /
 45.4966 +                  "TEXT" SP astring / "TO" SP astring /
 45.4967 +                  "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
 45.4968 +                  "UNKEYWORD" SP flag-keyword / "UNSEEN" /
 45.4969 +                    ; Above this line were in [IMAP2]
 45.4970 +                  "DRAFT" / "HEADER" SP header-fld-name SP astring /
 45.4971 +                  "LARGER" SP number / "NOT" SP search-key /
 45.4972 +                  "OR" SP search-key SP search-key /
 45.4973 +                  "SENTBEFORE" SP date / "SENTON" SP date /
 45.4974 +                  "SENTSINCE" SP date / "SMALLER" SP number /
 45.4975 +                  "UID" SP sequence-set / "UNDRAFT" / sequence-set /
 45.4976 +                  "(" search-key *(SP search-key) ")"
 45.4977 +
 45.4978 +section         = "[" [section-spec] "]"
 45.4979 +
 45.4980 +section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
 45.4981 +                  "TEXT"
 45.4982 +                    ; top-level or MESSAGE/RFC822 part
 45.4983 +
 45.4984 +section-part    = nz-number *("." nz-number)
 45.4985 +                    ; body part nesting
 45.4986 +
 45.4987 +
 45.4988 +
 45.4989 +Crispin                     Standards Track                    [Page 89]
 45.4990 +
 45.4991 +RFC 3501                         IMAPv4                       March 2003
 45.4992 +
 45.4993 +
 45.4994 +section-spec    = section-msgtext / (section-part ["." section-text])
 45.4995 +
 45.4996 +section-text    = section-msgtext / "MIME"
 45.4997 +                    ; text other than actual body part (headers, etc.)
 45.4998 +
 45.4999 +select          = "SELECT" SP mailbox
 45.5000 +
 45.5001 +seq-number      = nz-number / "*"
 45.5002 +                    ; message sequence number (COPY, FETCH, STORE
 45.5003 +                    ; commands) or unique identifier (UID COPY,
 45.5004 +                    ; UID FETCH, UID STORE commands).
 45.5005 +                    ; * represents the largest number in use.  In
 45.5006 +                    ; the case of message sequence numbers, it is
 45.5007 +                    ; the number of messages in a non-empty mailbox.
 45.5008 +                    ; In the case of unique identifiers, it is the
 45.5009 +                    ; unique identifier of the last message in the
 45.5010 +                    ; mailbox or, if the mailbox is empty, the
 45.5011 +                    ; mailbox's current UIDNEXT value.
 45.5012 +                    ; The server should respond with a tagged BAD
 45.5013 +                    ; response to a command that uses a message
 45.5014 +                    ; sequence number greater than the number of
 45.5015 +                    ; messages in the selected mailbox.  This
 45.5016 +                    ; includes "*" if the selected mailbox is empty.
 45.5017 +
 45.5018 +seq-range       = seq-number ":" seq-number
 45.5019 +                    ; two seq-number values and all values between
 45.5020 +                    ; these two regardless of order.
 45.5021 +                    ; Example: 2:4 and 4:2 are equivalent and indicate
 45.5022 +                    ; values 2, 3, and 4.
 45.5023 +                    ; Example: a unique identifer sequence range of
 45.5024 +                    ; 3291:* includes the UID of the last message in
 45.5025 +                    ; the mailbox, even if that value is less than 3291.
 45.5026 +
 45.5027 +sequence-set    = (seq-number / seq-range) *("," sequence-set)
 45.5028 +                    ; set of seq-number values, regardless of order.
 45.5029 +                    ; Servers MAY coalesce overlaps and/or execute the
 45.5030 +                    ; sequence in any order.
 45.5031 +                    ; Example: a message sequence number set of
 45.5032 +                    ; 2,4:7,9,12:* for a mailbox with 15 messages is
 45.5033 +                    ; equivalent to 2,4,5,6,7,9,12,13,14,15
 45.5034 +                    ; Example: a message sequence number set of *:4,5:7
 45.5035 +                    ; for a mailbox with 10 messages is equivalent to
 45.5036 +                    ; 10,9,8,7,6,5,4,5,6,7 and MAY be reordered and
 45.5037 +                    ; overlap coalesced to be 4,5,6,7,8,9,10.
 45.5038 +
 45.5039 +status          = "STATUS" SP mailbox SP
 45.5040 +                  "(" status-att *(SP status-att) ")"
 45.5041 +
 45.5042 +
 45.5043 +
 45.5044 +
 45.5045 +Crispin                     Standards Track                    [Page 90]
 45.5046 +
 45.5047 +RFC 3501                         IMAPv4                       March 2003
 45.5048 +
 45.5049 +
 45.5050 +status-att      = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
 45.5051 +                  "UNSEEN"
 45.5052 +
 45.5053 +status-att-list =  status-att SP number *(SP status-att SP number)
 45.5054 +
 45.5055 +store           = "STORE" SP sequence-set SP store-att-flags
 45.5056 +
 45.5057 +store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
 45.5058 +                  (flag-list / (flag *(SP flag)))
 45.5059 +
 45.5060 +string          = quoted / literal
 45.5061 +
 45.5062 +subscribe       = "SUBSCRIBE" SP mailbox
 45.5063 +
 45.5064 +tag             = 1*<any ASTRING-CHAR except "+">
 45.5065 +
 45.5066 +text            = 1*TEXT-CHAR
 45.5067 +
 45.5068 +TEXT-CHAR       = <any CHAR except CR and LF>
 45.5069 +
 45.5070 +time            = 2DIGIT ":" 2DIGIT ":" 2DIGIT
 45.5071 +                    ; Hours minutes seconds
 45.5072 +
 45.5073 +uid             = "UID" SP (copy / fetch / search / store)
 45.5074 +                    ; Unique identifiers used instead of message
 45.5075 +                    ; sequence numbers
 45.5076 +
 45.5077 +uniqueid        = nz-number
 45.5078 +                    ; Strictly ascending
 45.5079 +
 45.5080 +unsubscribe     = "UNSUBSCRIBE" SP mailbox
 45.5081 +
 45.5082 +userid          = astring
 45.5083 +
 45.5084 +x-command       = "X" atom <experimental command arguments>
 45.5085 +
 45.5086 +zone            = ("+" / "-") 4DIGIT
 45.5087 +                    ; Signed four-digit value of hhmm representing
 45.5088 +                    ; hours and minutes east of Greenwich (that is,
 45.5089 +                    ; the amount that the given time differs from
 45.5090 +                    ; Universal Time).  Subtracting the timezone
 45.5091 +                    ; from the given time will give the UT form.
 45.5092 +                    ; The Universal Time zone is "+0000".
 45.5093 +
 45.5094 +
 45.5095 +
 45.5096 +
 45.5097 +
 45.5098 +
 45.5099 +
 45.5100 +
 45.5101 +Crispin                     Standards Track                    [Page 91]
 45.5102 +
 45.5103 +RFC 3501                         IMAPv4                       March 2003
 45.5104 +
 45.5105 +
 45.5106 +10.     Author's Note
 45.5107 +
 45.5108 +   This document is a revision or rewrite of earlier documents, and
 45.5109 +   supercedes the protocol specification in those documents: RFC 2060,
 45.5110 +   RFC 1730, unpublished IMAP2bis.TXT document, RFC 1176, and RFC 1064.
 45.5111 +
 45.5112 +11.     Security Considerations
 45.5113 +
 45.5114 +   IMAP4rev1 protocol transactions, including electronic mail data, are
 45.5115 +   sent in the clear over the network unless protection from snooping is
 45.5116 +   negotiated.  This can be accomplished either by the use of STARTTLS,
 45.5117 +   negotiated privacy protection in the AUTHENTICATE command, or some
 45.5118 +   other protection mechanism.
 45.5119 +
 45.5120 +11.1.   STARTTLS Security Considerations
 45.5121 +
 45.5122 +   The specification of the STARTTLS command and LOGINDISABLED
 45.5123 +   capability in this document replaces that in [IMAP-TLS].  [IMAP-TLS]
 45.5124 +   remains normative for the PLAIN [SASL] authenticator.
 45.5125 +
 45.5126 +   IMAP client and server implementations MUST implement the
 45.5127 +   TLS_RSA_WITH_RC4_128_MD5 [TLS] cipher suite, and SHOULD implement the
 45.5128 +   TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [TLS] cipher suite.  This is
 45.5129 +   important as it assures that any two compliant implementations can be
 45.5130 +   configured to interoperate.  All other cipher suites are OPTIONAL.
 45.5131 +   Note that this is a change from section 2.1 of [IMAP-TLS].
 45.5132 +
 45.5133 +   During the [TLS] negotiation, the client MUST check its understanding
 45.5134 +   of the server hostname against the server's identity as presented in
 45.5135 +   the server Certificate message, in order to prevent man-in-the-middle
 45.5136 +   attacks.  If the match fails, the client SHOULD either ask for
 45.5137 +   explicit user confirmation, or terminate the connection and indicate
 45.5138 +   that the server's identity is suspect.  Matching is performed
 45.5139 +   according to these rules:
 45.5140 +
 45.5141 +        The client MUST use the server hostname it used to open the
 45.5142 +        connection as the value to compare against the server name
 45.5143 +        as expressed in the server certificate.  The client MUST
 45.5144 +        NOT use any form of the server hostname derived from an
 45.5145 +        insecure remote source (e.g., insecure DNS lookup).  CNAME
 45.5146 +        canonicalization is not done.
 45.5147 +
 45.5148 +        If a subjectAltName extension of type dNSName is present in
 45.5149 +        the certificate, it SHOULD be used as the source of the
 45.5150 +        server's identity.
 45.5151 +
 45.5152 +        Matching is case-insensitive.
 45.5153 +
 45.5154 +
 45.5155 +
 45.5156 +
 45.5157 +Crispin                     Standards Track                    [Page 92]
 45.5158 +
 45.5159 +RFC 3501                         IMAPv4                       March 2003
 45.5160 +
 45.5161 +
 45.5162 +        A "*" wildcard character MAY be used as the left-most name
 45.5163 +        component in the certificate.  For example, *.example.com
 45.5164 +        would match a.example.com, foo.example.com, etc. but would
 45.5165 +        not match example.com.
 45.5166 +
 45.5167 +        If the certificate contains multiple names (e.g., more than
 45.5168 +        one dNSName field), then a match with any one of the fields
 45.5169 +        is considered acceptable.
 45.5170 +
 45.5171 +   Both the client and server MUST check the result of the STARTTLS
 45.5172 +   command and subsequent [TLS] negotiation to see whether acceptable
 45.5173 +   authentication or privacy was achieved.
 45.5174 +
 45.5175 +11.2.   Other Security Considerations
 45.5176 +
 45.5177 +   A server error message for an AUTHENTICATE command which fails due to
 45.5178 +   invalid credentials SHOULD NOT detail why the credentials are
 45.5179 +   invalid.
 45.5180 +
 45.5181 +   Use of the LOGIN command sends passwords in the clear.  This can be
 45.5182 +   avoided by using the AUTHENTICATE command with a [SASL] mechanism
 45.5183 +   that does not use plaintext passwords, by first negotiating
 45.5184 +   encryption via STARTTLS or some other protection mechanism.
 45.5185 +
 45.5186 +   A server implementation MUST implement a configuration that, at the
 45.5187 +   time of authentication, requires:
 45.5188 +      (1) The STARTTLS command has been negotiated.
 45.5189 +   OR
 45.5190 +      (2) Some other mechanism that protects the session from password
 45.5191 +      snooping has been provided.
 45.5192 +   OR
 45.5193 +      (3) The following measures are in place:
 45.5194 +         (a) The LOGINDISABLED capability is advertised, and [SASL]
 45.5195 +         mechanisms (such as PLAIN) using plaintext passwords are NOT
 45.5196 +         advertised in the CAPABILITY list.
 45.5197 +      AND
 45.5198 +         (b) The LOGIN command returns an error even if the password is
 45.5199 +         correct.
 45.5200 +      AND
 45.5201 +         (c) The AUTHENTICATE command returns an error with all [SASL]
 45.5202 +         mechanisms that use plaintext passwords, even if the password
 45.5203 +         is correct.
 45.5204 +
 45.5205 +   A server error message for a failing LOGIN command SHOULD NOT specify
 45.5206 +   that the user name, as opposed to the password, is invalid.
 45.5207 +
 45.5208 +   A server SHOULD have mechanisms in place to limit or delay failed
 45.5209 +   AUTHENTICATE/LOGIN attempts.
 45.5210 +
 45.5211 +
 45.5212 +
 45.5213 +Crispin                     Standards Track                    [Page 93]
 45.5214 +
 45.5215 +RFC 3501                         IMAPv4                       March 2003
 45.5216 +
 45.5217 +
 45.5218 +   Additional security considerations are discussed in the section
 45.5219 +   discussing the AUTHENTICATE and LOGIN commands.
 45.5220 +
 45.5221 +12.     IANA Considerations
 45.5222 +
 45.5223 +   IMAP4 capabilities are registered by publishing a standards track or
 45.5224 +   IESG approved experimental RFC.  The registry is currently located
 45.5225 +   at:
 45.5226 +
 45.5227 +        http://www.iana.org/assignments/imap4-capabilities
 45.5228 +
 45.5229 +   As this specification revises the STARTTLS and LOGINDISABLED
 45.5230 +   extensions previously defined in [IMAP-TLS], the registry will be
 45.5231 +   updated accordingly.
 45.5232 +
 45.5233 +
 45.5234 +
 45.5235 +
 45.5236 +
 45.5237 +
 45.5238 +
 45.5239 +
 45.5240 +
 45.5241 +
 45.5242 +
 45.5243 +
 45.5244 +
 45.5245 +
 45.5246 +
 45.5247 +
 45.5248 +
 45.5249 +
 45.5250 +
 45.5251 +
 45.5252 +
 45.5253 +
 45.5254 +
 45.5255 +
 45.5256 +
 45.5257 +
 45.5258 +
 45.5259 +
 45.5260 +
 45.5261 +
 45.5262 +
 45.5263 +
 45.5264 +
 45.5265 +
 45.5266 +
 45.5267 +
 45.5268 +
 45.5269 +Crispin                     Standards Track                    [Page 94]
 45.5270 +
 45.5271 +RFC 3501                         IMAPv4                       March 2003
 45.5272 +
 45.5273 +
 45.5274 +Appendices
 45.5275 +
 45.5276 +A.      Normative References
 45.5277 +
 45.5278 +   The following documents contain definitions or specifications that
 45.5279 +   are necessary to understand this document properly:
 45.5280 +   [ABNF]                Crocker, D. and P. Overell, "Augmented BNF for
 45.5281 +                         Syntax Specifications: ABNF", RFC 2234,
 45.5282 +                         November 1997.
 45.5283 +
 45.5284 +   [ANONYMOUS]           Newman, C., "Anonymous SASL Mechanism", RFC
 45.5285 +                         2245, November 1997.
 45.5286 +
 45.5287 +   [CHARSET]             Freed, N. and J. Postel, "IANA Character Set
 45.5288 +                         Registration Procedures", RFC 2978, October
 45.5289 +                         2000.
 45.5290 +
 45.5291 +   [DIGEST-MD5]          Leach, P. and C. Newman, "Using Digest
 45.5292 +                         Authentication as a SASL Mechanism", RFC 2831,
 45.5293 +                         May 2000.
 45.5294 +
 45.5295 +   [DISPOSITION]         Troost, R., Dorner, S. and K. Moore,
 45.5296 +                         "Communicating Presentation Information in
 45.5297 +                         Internet Messages: The Content-Disposition
 45.5298 +                         Header", RFC 2183, August 1997.
 45.5299 +
 45.5300 +   [IMAP-TLS]            Newman, C., "Using TLS with IMAP, POP3 and
 45.5301 +                         ACAP", RFC 2595, June 1999.
 45.5302 +
 45.5303 +   [KEYWORDS]            Bradner, S., "Key words for use in RFCs to
 45.5304 +                         Indicate Requirement Levels", BCP 14, RFC 2119,
 45.5305 +                         March 1997.
 45.5306 +
 45.5307 +   [LANGUAGE-TAGS]       Alvestrand, H., "Tags for the Identification of
 45.5308 +                         Languages", BCP 47, RFC 3066, January 2001.
 45.5309 +
 45.5310 +   [LOCATION]            Palme, J., Hopmann, A. and N. Shelness, "MIME
 45.5311 +                         Encapsulation of Aggregate Documents, such as
 45.5312 +                         HTML (MHTML)", RFC 2557, March 1999.
 45.5313 +
 45.5314 +   [MD5]                 Myers, J. and M. Rose, "The Content-MD5 Header
 45.5315 +                         Field", RFC 1864, October 1995.
 45.5316 +
 45.5317 +
 45.5318 +
 45.5319 +
 45.5320 +
 45.5321 +
 45.5322 +
 45.5323 +
 45.5324 +
 45.5325 +Crispin                     Standards Track                    [Page 95]
 45.5326 +
 45.5327 +RFC 3501                         IMAPv4                       March 2003
 45.5328 +
 45.5329 +
 45.5330 +   [MIME-HDRS]           Moore, K., "MIME (Multipurpose Internet Mail
 45.5331 +                         Extensions) Part Three: Message Header
 45.5332 +                         Extensions for Non-ASCII Text", RFC 2047,
 45.5333 +                         November 1996.
 45.5334 +
 45.5335 +   [MIME-IMB]            Freed, N. and N. Borenstein, "MIME
 45.5336 +                         (Multipurpose Internet Mail Extensions) Part
 45.5337 +                         One: Format of Internet Message Bodies", RFC
 45.5338 +                         2045, November 1996.
 45.5339 +
 45.5340 +   [MIME-IMT]            Freed, N. and N. Borenstein, "MIME
 45.5341 +                         (Multipurpose Internet Mail Extensions) Part
 45.5342 +                         Two: Media Types", RFC 2046, November 1996.
 45.5343 +
 45.5344 +   [RFC-2822]            Resnick, P., "Internet Message Format", RFC
 45.5345 +                         2822, April 2001.
 45.5346 +
 45.5347 +   [SASL]                Myers, J., "Simple Authentication and Security
 45.5348 +                         Layer (SASL)", RFC 2222, October 1997.
 45.5349 +
 45.5350 +   [TLS]                 Dierks, T. and C. Allen, "The TLS Protocol
 45.5351 +                         Version 1.0", RFC 2246, January 1999.
 45.5352 +
 45.5353 +   [UTF-7]               Goldsmith, D. and M. Davis, "UTF-7: A Mail-Safe
 45.5354 +                         Transformation Format of Unicode", RFC 2152,
 45.5355 +                         May 1997.
 45.5356 +
 45.5357 +   The following documents describe quality-of-implementation issues
 45.5358 +   that should be carefully considered when implementing this protocol:
 45.5359 +
 45.5360 +   [IMAP-IMPLEMENTATION] Leiba, B., "IMAP Implementation
 45.5361 +                         Recommendations", RFC 2683, September 1999.
 45.5362 +
 45.5363 +   [IMAP-MULTIACCESS]    Gahrns, M., "IMAP4 Multi-Accessed Mailbox
 45.5364 +                         Practice", RFC 2180, July 1997.
 45.5365 +
 45.5366 +A.1     Informative References
 45.5367 +
 45.5368 +   The following documents describe related protocols:
 45.5369 +
 45.5370 +   [IMAP-DISC]           Austein, R., "Synchronization Operations for
 45.5371 +                         Disconnected IMAP4 Clients", Work in Progress.
 45.5372 +
 45.5373 +   [IMAP-MODEL]          Crispin, M., "Distributed Electronic Mail
 45.5374 +                         Models in IMAP4", RFC 1733, December 1994.
 45.5375 +
 45.5376 +
 45.5377 +
 45.5378 +
 45.5379 +
 45.5380 +
 45.5381 +Crispin                     Standards Track                    [Page 96]
 45.5382 +
 45.5383 +RFC 3501                         IMAPv4                       March 2003
 45.5384 +
 45.5385 +
 45.5386 +   [ACAP]                Newman, C. and J. Myers, "ACAP -- Application
 45.5387 +                         Configuration Access Protocol", RFC 2244,
 45.5388 +                         November 1997.
 45.5389 +
 45.5390 +   [SMTP]                Klensin, J., "Simple Mail Transfer Protocol",
 45.5391 +                         STD 10, RFC 2821, April 2001.
 45.5392 +
 45.5393 +   The following documents are historical or describe historical aspects
 45.5394 +   of this protocol:
 45.5395 +
 45.5396 +   [IMAP-COMPAT]         Crispin, M., "IMAP4 Compatibility with
 45.5397 +                         IMAP2bis", RFC 2061, December 1996.
 45.5398 +
 45.5399 +   [IMAP-HISTORICAL]     Crispin, M., "IMAP4 Compatibility with IMAP2
 45.5400 +                         and IMAP2bis", RFC 1732, December 1994.
 45.5401 +
 45.5402 +   [IMAP-OBSOLETE]       Crispin, M., "Internet Message Access Protocol
 45.5403 +                         - Obsolete Syntax", RFC 2062, December 1996.
 45.5404 +
 45.5405 +   [IMAP2]               Crispin, M., "Interactive Mail Access Protocol
 45.5406 +                         - Version 2", RFC 1176, August 1990.
 45.5407 +
 45.5408 +   [RFC-822]             Crocker, D., "Standard for the Format of ARPA
 45.5409 +                         Internet Text Messages", STD 11, RFC 822,
 45.5410 +                         August 1982.
 45.5411 +
 45.5412 +   [RFC-821]             Postel, J., "Simple Mail Transfer Protocol",
 45.5413 +                         STD 10, RFC 821, August 1982.
 45.5414 +
 45.5415 +B.      Changes from RFC 2060
 45.5416 +
 45.5417 +   1) Clarify description of unique identifiers and their semantics.
 45.5418 +
 45.5419 +   2) Fix the SELECT description to clarify that UIDVALIDITY is required
 45.5420 +   in the SELECT and EXAMINE responses.
 45.5421 +
 45.5422 +   3) Added an example of a failing search.
 45.5423 +
 45.5424 +   4) Correct store-att-flags: "#flag" should be "1#flag".
 45.5425 +
 45.5426 +   5) Made search and section rules clearer.
 45.5427 +
 45.5428 +   6) Correct the STORE example.
 45.5429 +
 45.5430 +   7) Correct "BASE645" misspelling.
 45.5431 +
 45.5432 +   8) Remove extraneous close parenthesis in example of two-part message
 45.5433 +   with text and BASE64 attachment.
 45.5434 +
 45.5435 +
 45.5436 +
 45.5437 +Crispin                     Standards Track                    [Page 97]
 45.5438 +
 45.5439 +RFC 3501                         IMAPv4                       March 2003
 45.5440 +
 45.5441 +
 45.5442 +   9) Remove obsolete "MAILBOX" response from mailbox-data.
 45.5443 +
 45.5444 +   10) A spurious "<" in the rule for mailbox-data was removed.
 45.5445 +
 45.5446 +   11) Add CRLF to continue-req.
 45.5447 +
 45.5448 +   12) Specifically exclude "]" from the atom in resp-text-code.
 45.5449 +
 45.5450 +   13) Clarify that clients and servers should adhere strictly to the
 45.5451 +   protocol syntax.
 45.5452 +
 45.5453 +   14) Emphasize in 5.2 that EXISTS can not be used to shrink a mailbox.
 45.5454 +
 45.5455 +   15) Add NEWNAME to resp-text-code.
 45.5456 +
 45.5457 +   16) Clarify that the empty string, not NIL, is used as arguments to
 45.5458 +   LIST.
 45.5459 +
 45.5460 +   17) Clarify that NIL can be returned as a hierarchy delimiter for the
 45.5461 +   empty string mailbox name argument if the mailbox namespace is flat.
 45.5462 +
 45.5463 +   18) Clarify that addr-mailbox and addr-name have RFC-2822 quoting
 45.5464 +   removed.
 45.5465 +
 45.5466 +   19) Update UTF-7 reference.
 45.5467 +
 45.5468 +   20) Fix example in 6.3.11.
 45.5469 +
 45.5470 +   21) Clarify that non-existent UIDs are ignored.
 45.5471 +
 45.5472 +   22) Update DISPOSITION reference.
 45.5473 +
 45.5474 +   23) Expand state diagram.
 45.5475 +
 45.5476 +   24) Clarify that partial fetch responses are only returned in
 45.5477 +   response to a partial fetch command.
 45.5478 +
 45.5479 +   25) Add UIDNEXT response code.  Correct UIDVALIDITY definition
 45.5480 +   reference.
 45.5481 +
 45.5482 +   26) Further clarification of "can" vs. "MAY".
 45.5483 +
 45.5484 +   27) Reference RFC-2119.
 45.5485 +
 45.5486 +   28) Clarify that superfluous shifts are not permitted in modified
 45.5487 +   UTF-7.
 45.5488 +
 45.5489 +   29) Clarify that there are no implicit shifts in modified UTF-7.
 45.5490 +
 45.5491 +
 45.5492 +
 45.5493 +Crispin                     Standards Track                    [Page 98]
 45.5494 +
 45.5495 +RFC 3501                         IMAPv4                       March 2003
 45.5496 +
 45.5497 +
 45.5498 +   30) Clarify that "INBOX" in a mailbox name is always INBOX, even if
 45.5499 +   it is given as a string.
 45.5500 +
 45.5501 +   31) Add missing open parenthesis in media-basic grammar rule.
 45.5502 +
 45.5503 +   32) Correct attribute syntax in mailbox-data.
 45.5504 +
 45.5505 +   33) Add UIDNEXT to EXAMINE responses.
 45.5506 +
 45.5507 +   34) Clarify UNSEEN, PERMANENTFLAGS, UIDVALIDITY, and UIDNEXT
 45.5508 +   responses in SELECT and EXAMINE.  They are required now, but weren't
 45.5509 +   in older versions.
 45.5510 +
 45.5511 +   35) Update references with RFC numbers.
 45.5512 +
 45.5513 +   36) Flush text-mime2.
 45.5514 +
 45.5515 +   37) Clarify that modified UTF-7 names must be case-sensitive and that
 45.5516 +   violating the convention should be avoided.
 45.5517 +
 45.5518 +   38) Correct UID FETCH example.
 45.5519 +
 45.5520 +   39) Clarify UID FETCH, UID STORE, and UID SEARCH vs. untagged EXPUNGE
 45.5521 +   responses.
 45.5522 +
 45.5523 +   40) Clarify the use of the word "convention".
 45.5524 +
 45.5525 +   41) Clarify that a command is not "in progress" until it has been
 45.5526 +   fully received (specifically, that a command is not "in progress"
 45.5527 +   during command continuation negotiation).
 45.5528 +
 45.5529 +   42) Clarify envelope defaulting.
 45.5530 +
 45.5531 +   43) Clarify that SP means one and only one space character.
 45.5532 +
 45.5533 +   44) Forbid silly states in LIST response.
 45.5534 +
 45.5535 +   45) Clarify that the ENVELOPE, INTERNALDATE, RFC822*, BODY*, and UID
 45.5536 +   for a message is static.
 45.5537 +
 45.5538 +   46) Add BADCHARSET response code.
 45.5539 +
 45.5540 +   47) Update formal syntax to [ABNF] conventions.
 45.5541 +
 45.5542 +   48) Clarify trailing hierarchy delimiter in CREATE semantics.
 45.5543 +
 45.5544 +   49) Clarify that the "blank line" is the [RFC-2822] delimiting blank
 45.5545 +   line.
 45.5546 +
 45.5547 +
 45.5548 +
 45.5549 +Crispin                     Standards Track                    [Page 99]
 45.5550 +
 45.5551 +RFC 3501                         IMAPv4                       March 2003
 45.5552 +
 45.5553 +
 45.5554 +   50) Clarify that RENAME should also create hierarchy as needed for
 45.5555 +   the command to complete.
 45.5556 +
 45.5557 +   51) Fix body-ext-mpart to not require language if disposition
 45.5558 +   present.
 45.5559 +
 45.5560 +   52) Clarify the RFC822.HEADER response.
 45.5561 +
 45.5562 +   53) Correct missing space after charset astring in search.
 45.5563 +
 45.5564 +   54) Correct missing quote for BADCHARSET in resp-text-code.
 45.5565 +
 45.5566 +   55) Clarify that ALL, FAST, and FULL preclude any other data items
 45.5567 +   appearing.
 45.5568 +
 45.5569 +   56) Clarify semantics of reference argument in LIST.
 45.5570 +
 45.5571 +   57) Clarify that a null string for SEARCH HEADER X-FOO means any
 45.5572 +   message with a header line with a field-name of X-FOO regardless of
 45.5573 +   the text of the header.
 45.5574 +
 45.5575 +   58) Specifically reserve 8-bit mailbox names for future use as UTF-8.
 45.5576 +
 45.5577 +   59) It is not an error for the client to store a flag that is not in
 45.5578 +   the PERMANENTFLAGS list; however, the server will either ignore the
 45.5579 +   change or make the change in the session only.
 45.5580 +
 45.5581 +   60) Correct/clarify the text regarding superfluous shifts.
 45.5582 +
 45.5583 +   61) Correct typographic errors in the "Changes" section.
 45.5584 +
 45.5585 +   62) Clarify that STATUS must not be used to check for new messages in
 45.5586 +   the selected mailbox
 45.5587 +
 45.5588 +   63) Clarify LSUB behavior with "%" wildcard.
 45.5589 +
 45.5590 +   64) Change AUTHORIZATION to AUTHENTICATE in section 7.5.
 45.5591 +
 45.5592 +   65) Clarify description of multipart body type.
 45.5593 +
 45.5594 +   66) Clarify that STORE FLAGS does not affect \Recent.
 45.5595 +
 45.5596 +   67) Change "west" to "east" in description of timezone.
 45.5597 +
 45.5598 +   68) Clarify that commands which break command pipelining must wait
 45.5599 +   for a completion result response.
 45.5600 +
 45.5601 +   69) Clarify that EXAMINE does not affect \Recent.
 45.5602 +
 45.5603 +
 45.5604 +
 45.5605 +Crispin                     Standards Track                   [Page 100]
 45.5606 +
 45.5607 +RFC 3501                         IMAPv4                       March 2003
 45.5608 +
 45.5609 +
 45.5610 +   70) Make description of MIME structure consistent.
 45.5611 +
 45.5612 +   71) Clarify that date searches disregard the time and timezone of the
 45.5613 +   INTERNALDATE or Date: header.  In other words, "ON 13-APR-2000" means
 45.5614 +   messages with an INTERNALDATE text which starts with "13-APR-2000",
 45.5615 +   even if timezone differential from the local timezone is sufficient
 45.5616 +   to move that INTERNALDATE into the previous or next day.
 45.5617 +
 45.5618 +   72) Clarify that the header fetches don't add a blank line if one
 45.5619 +   isn't in the [RFC-2822] message.
 45.5620 +
 45.5621 +   73) Clarify (in discussion of UIDs) that messages are immutable.
 45.5622 +
 45.5623 +   74) Add an example of CHARSET searching.
 45.5624 +
 45.5625 +   75) Clarify in SEARCH that keywords are a type of flag.
 45.5626 +
 45.5627 +   76) Clarify the mandatory nature of the SELECT data responses.
 45.5628 +
 45.5629 +   77) Add optional CAPABILITY response code in the initial OK or
 45.5630 +   PREAUTH.
 45.5631 +
 45.5632 +   78) Add note that server can send an untagged CAPABILITY command as
 45.5633 +   part of the responses to AUTHENTICATE and LOGIN.
 45.5634 +
 45.5635 +   79) Remove statement about it being unnecessary to issue a CAPABILITY
 45.5636 +   command more than once in a connection.  That statement is no longer
 45.5637 +   true.
 45.5638 +
 45.5639 +   80) Clarify that untagged EXPUNGE decrements the number of messages
 45.5640 +   in the mailbox.
 45.5641 +
 45.5642 +   81) Fix definition of "body" (concatenation has tighter binding than
 45.5643 +   alternation).
 45.5644 +
 45.5645 +   82) Add a new "Special Notes to Implementors" section with reference
 45.5646 +   to [IMAP-IMPLEMENTATION].
 45.5647 +
 45.5648 +   83) Clarify that an untagged CAPABILITY response to an AUTHENTICATE
 45.5649 +   command should only be done if a security layer was not negotiated.
 45.5650 +
 45.5651 +   84) Change the definition of atom to exclude "]".  Update astring to
 45.5652 +   include "]" for compatiblity with the past.  Remove resp-text-atom.
 45.5653 +
 45.5654 +   85) Remove NEWNAME.  It can't work because mailbox names can be
 45.5655 +   literals and can include "]".  Functionality can be addressed via
 45.5656 +   referrals.
 45.5657 +
 45.5658 +
 45.5659 +
 45.5660 +
 45.5661 +Crispin                     Standards Track                   [Page 101]
 45.5662 +
 45.5663 +RFC 3501                         IMAPv4                       March 2003
 45.5664 +
 45.5665 +
 45.5666 +   86) Move modified UTF-7 rationale in order to have more logical
 45.5667 +   paragraph flow.
 45.5668 +
 45.5669 +   87) Clarify UID uniqueness guarantees with the use of MUST.
 45.5670 +
 45.5671 +   88) Note that clients should read response data until the connection
 45.5672 +   is closed instead of immediately closing on a BYE.
 45.5673 +
 45.5674 +   89) Change RFC-822 references to RFC-2822.
 45.5675 +
 45.5676 +   90) Clarify that RFC-2822 should be followed instead of RFC-822.
 45.5677 +
 45.5678 +   91) Change recommendation of optional automatic capabilities in LOGIN
 45.5679 +   and AUTHENTICATE to use the CAPABILITY response code in the tagged
 45.5680 +   OK.  This is more interoperable than an unsolicited untagged
 45.5681 +   CAPABILITY response.
 45.5682 +
 45.5683 +   92) STARTTLS and AUTH=PLAIN are mandatory to implement; add
 45.5684 +   recommendations for other [SASL] mechanisms.
 45.5685 +
 45.5686 +   93) Clarify that a "connection" (as opposed to "server" or "command")
 45.5687 +   is in one of the four states.
 45.5688 +
 45.5689 +   94) Clarify that a failed or rejected command does not change state.
 45.5690 +
 45.5691 +   95) Split references between normative and informative.
 45.5692 +
 45.5693 +   96) Discuss authentication failure issues in security section.
 45.5694 +
 45.5695 +   97) Clarify that a data item is not necessarily of only one data
 45.5696 +   type.
 45.5697 +
 45.5698 +   98) Clarify that sequence ranges are independent of order.
 45.5699 +
 45.5700 +   99) Change an example to clarify that superfluous shifts in
 45.5701 +   Modified-UTF7 can not be fixed just by omitting the shift.  The
 45.5702 +   entire string must be recalculated.
 45.5703 +
 45.5704 +   100) Change Envelope Structure definition since [RFC-2822] uses
 45.5705 +   "envelope" to refer to the [SMTP] envelope and not the envelope data
 45.5706 +   that appears in the [RFC-2822] header.
 45.5707 +
 45.5708 +   101) Expand on RFC822.HEADER response data vs. BODY[HEADER].
 45.5709 +
 45.5710 +   102) Clarify Logout state semantics, change ASCII art.
 45.5711 +
 45.5712 +   103) Security changes to comply with IESG requirements.
 45.5713 +
 45.5714 +
 45.5715 +
 45.5716 +
 45.5717 +Crispin                     Standards Track                   [Page 102]
 45.5718 +
 45.5719 +RFC 3501                         IMAPv4                       March 2003
 45.5720 +
 45.5721 +
 45.5722 +   104) Add definition for body URI.
 45.5723 +
 45.5724 +   105) Break sequence range definition into three rules, with rewritten
 45.5725 +   descriptions for each.
 45.5726 +
 45.5727 +   106) Move STARTTLS and LOGINDISABLED here from [IMAP-TLS].
 45.5728 +
 45.5729 +   107) Add IANA Considerations section.
 45.5730 +
 45.5731 +   108) Clarify valid client assumptions for new message UIDs vs.
 45.5732 +   UIDNEXT.
 45.5733 +
 45.5734 +   109) Clarify that changes to permanentflags affect concurrent
 45.5735 +   sessions as well as subsequent sessions.
 45.5736 +
 45.5737 +   110) Clarify that authenticated state can be entered by the CLOSE
 45.5738 +   command.
 45.5739 +
 45.5740 +   111) Emphasize that SELECT and EXAMINE are the exceptions to the rule
 45.5741 +   that a failing command does not change state.
 45.5742 +
 45.5743 +   112) Clarify that newly-appended messages have the Recent flag set.
 45.5744 +
 45.5745 +   113) Clarify that newly-copied messages SHOULD have the Recent flag
 45.5746 +   set.
 45.5747 +
 45.5748 +   114) Clarify that UID commands always return the UID in FETCH
 45.5749 +   responses.
 45.5750 +
 45.5751 +C.      Key Word Index
 45.5752 +
 45.5753 +       +FLAGS <flag list> (store command data item) ...............   59
 45.5754 +       +FLAGS.SILENT <flag list> (store command data item) ........   59
 45.5755 +       -FLAGS <flag list> (store command data item) ...............   59
 45.5756 +       -FLAGS.SILENT <flag list> (store command data item) ........   59
 45.5757 +       ALERT (response code) ......................................   64
 45.5758 +       ALL (fetch item) ...........................................   55
 45.5759 +       ALL (search key) ...........................................   50
 45.5760 +       ANSWERED (search key) ......................................   50
 45.5761 +       APPEND (command) ...........................................   45
 45.5762 +       AUTHENTICATE (command) .....................................   27
 45.5763 +       BAD (response) .............................................   66
 45.5764 +       BADCHARSET (response code) .................................   64
 45.5765 +       BCC <string> (search key) ..................................   51
 45.5766 +       BEFORE <date> (search key) .................................   51
 45.5767 +       BODY (fetch item) ..........................................   55
 45.5768 +       BODY (fetch result) ........................................   73
 45.5769 +       BODY <string> (search key) .................................   51
 45.5770 +
 45.5771 +
 45.5772 +
 45.5773 +Crispin                     Standards Track                   [Page 103]
 45.5774 +
 45.5775 +RFC 3501                         IMAPv4                       March 2003
 45.5776 +
 45.5777 +
 45.5778 +       BODY.PEEK[<section>]<<partial>> (fetch item) ...............   57
 45.5779 +       BODYSTRUCTURE (fetch item) .................................   57
 45.5780 +       BODYSTRUCTURE (fetch result) ...............................   74
 45.5781 +       BODY[<section>]<<origin octet>> (fetch result) .............   74
 45.5782 +       BODY[<section>]<<partial>> (fetch item) ....................   55
 45.5783 +       BYE (response) .............................................   67
 45.5784 +       Body Structure (message attribute) .........................   12
 45.5785 +       CAPABILITY (command) .......................................   24
 45.5786 +       CAPABILITY (response code) .................................   64
 45.5787 +       CAPABILITY (response) ......................................   68
 45.5788 +       CC <string> (search key) ...................................   51
 45.5789 +       CHECK (command) ............................................   47
 45.5790 +       CLOSE (command) ............................................   48
 45.5791 +       COPY (command) .............................................   59
 45.5792 +       CREATE (command) ...........................................   34
 45.5793 +       DELETE (command) ...........................................   35
 45.5794 +       DELETED (search key) .......................................   51
 45.5795 +       DRAFT (search key) .........................................   51
 45.5796 +       ENVELOPE (fetch item) ......................................   57
 45.5797 +       ENVELOPE (fetch result) ....................................   77
 45.5798 +       EXAMINE (command) ..........................................   33
 45.5799 +       EXISTS (response) ..........................................   71
 45.5800 +       EXPUNGE (command) ..........................................   48
 45.5801 +       EXPUNGE (response) .........................................   72
 45.5802 +       Envelope Structure (message attribute) .....................   12
 45.5803 +       FAST (fetch item) ..........................................   55
 45.5804 +       FETCH (command) ............................................   54
 45.5805 +       FETCH (response) ...........................................   73
 45.5806 +       FLAGGED (search key) .......................................   51
 45.5807 +       FLAGS (fetch item) .........................................   57
 45.5808 +       FLAGS (fetch result) .......................................   78
 45.5809 +       FLAGS (response) ...........................................   71
 45.5810 +       FLAGS <flag list> (store command data item) ................   59
 45.5811 +       FLAGS.SILENT <flag list> (store command data item) .........   59
 45.5812 +       FROM <string> (search key) .................................   51
 45.5813 +       FULL (fetch item) ..........................................   55
 45.5814 +       Flags (message attribute) ..................................   11
 45.5815 +       HEADER (part specifier) ....................................   55
 45.5816 +       HEADER <field-name> <string> (search key) ..................   51
 45.5817 +       HEADER.FIELDS <header-list> (part specifier) ...............   55
 45.5818 +       HEADER.FIELDS.NOT <header-list> (part specifier) ...........   55
 45.5819 +       INTERNALDATE (fetch item) ..................................   57
 45.5820 +       INTERNALDATE (fetch result) ................................   78
 45.5821 +       Internal Date (message attribute) ..........................   12
 45.5822 +       KEYWORD <flag> (search key) ................................   51
 45.5823 +       Keyword (type of flag) .....................................   11
 45.5824 +       LARGER <n> (search key) ....................................   51
 45.5825 +       LIST (command) .............................................   40
 45.5826 +
 45.5827 +
 45.5828 +
 45.5829 +Crispin                     Standards Track                   [Page 104]
 45.5830 +
 45.5831 +RFC 3501                         IMAPv4                       March 2003
 45.5832 +
 45.5833 +
 45.5834 +       LIST (response) ............................................   69
 45.5835 +       LOGIN (command) ............................................   30
 45.5836 +       LOGOUT (command) ...........................................   25
 45.5837 +       LSUB (command) .............................................   43
 45.5838 +       LSUB (response) ............................................   70
 45.5839 +       MAY (specification requirement term) .......................    4
 45.5840 +       MESSAGES (status item) .....................................   45
 45.5841 +       MIME (part specifier) ......................................   56
 45.5842 +       MUST (specification requirement term) ......................    4
 45.5843 +       MUST NOT (specification requirement term) ..................    4
 45.5844 +       Message Sequence Number (message attribute) ................   10
 45.5845 +       NEW (search key) ...........................................   51
 45.5846 +       NO (response) ..............................................   66
 45.5847 +       NOOP (command) .............................................   25
 45.5848 +       NOT <search-key> (search key) ..............................   52
 45.5849 +       OK (response) ..............................................   65
 45.5850 +       OLD (search key) ...........................................   52
 45.5851 +       ON <date> (search key) .....................................   52
 45.5852 +       OPTIONAL (specification requirement term) ..................    4
 45.5853 +       OR <search-key1> <search-key2> (search key) ................   52
 45.5854 +       PARSE (response code) ......................................   64
 45.5855 +       PERMANENTFLAGS (response code) .............................   64
 45.5856 +       PREAUTH (response) .........................................   67
 45.5857 +       Permanent Flag (class of flag) .............................   12
 45.5858 +       READ-ONLY (response code) ..................................   65
 45.5859 +       READ-WRITE (response code) .................................   65
 45.5860 +       RECENT (response) ..........................................   72
 45.5861 +       RECENT (search key) ........................................   52
 45.5862 +       RECENT (status item) .......................................   45
 45.5863 +       RENAME (command) ...........................................   37
 45.5864 +       REQUIRED (specification requirement term) ..................    4
 45.5865 +       RFC822 (fetch item) ........................................   57
 45.5866 +       RFC822 (fetch result) ......................................   78
 45.5867 +       RFC822.HEADER (fetch item) .................................   57
 45.5868 +       RFC822.HEADER (fetch result) ...............................   78
 45.5869 +       RFC822.SIZE (fetch item) ...................................   57
 45.5870 +       RFC822.SIZE (fetch result) .................................   78
 45.5871 +       RFC822.TEXT (fetch item) ...................................   58
 45.5872 +       RFC822.TEXT (fetch result) .................................   79
 45.5873 +       SEARCH (command) ...........................................   49
 45.5874 +       SEARCH (response) ..........................................   71
 45.5875 +       SEEN (search key) ..........................................   52
 45.5876 +       SELECT (command) ...........................................   31
 45.5877 +       SENTBEFORE <date> (search key) .............................   52
 45.5878 +       SENTON <date> (search key) .................................   52
 45.5879 +       SENTSINCE <date> (search key) ..............................   52
 45.5880 +       SHOULD (specification requirement term) ....................    4
 45.5881 +       SHOULD NOT (specification requirement term) ................    4
 45.5882 +
 45.5883 +
 45.5884 +
 45.5885 +Crispin                     Standards Track                   [Page 105]
 45.5886 +
 45.5887 +RFC 3501                         IMAPv4                       March 2003
 45.5888 +
 45.5889 +
 45.5890 +       SINCE <date> (search key) ..................................   52
 45.5891 +       SMALLER <n> (search key) ...................................   52
 45.5892 +       STARTTLS (command) .........................................   27
 45.5893 +       STATUS (command) ...........................................   44
 45.5894 +       STATUS (response) ..........................................   70
 45.5895 +       STORE (command) ............................................   58
 45.5896 +       SUBJECT <string> (search key) ..............................   53
 45.5897 +       SUBSCRIBE (command) ........................................   38
 45.5898 +       Session Flag (class of flag) ...............................   12
 45.5899 +       System Flag (type of flag) .................................   11
 45.5900 +       TEXT (part specifier) ......................................   56
 45.5901 +       TEXT <string> (search key) .................................   53
 45.5902 +       TO <string> (search key) ...................................   53
 45.5903 +       TRYCREATE (response code) ..................................   65
 45.5904 +       UID (command) ..............................................   60
 45.5905 +       UID (fetch item) ...........................................   58
 45.5906 +       UID (fetch result) .........................................   79
 45.5907 +       UID <sequence set> (search key) ............................   53
 45.5908 +       UIDNEXT (response code) ....................................   65
 45.5909 +       UIDNEXT (status item) ......................................   45
 45.5910 +       UIDVALIDITY (response code) ................................   65
 45.5911 +       UIDVALIDITY (status item) ..................................   45
 45.5912 +       UNANSWERED (search key) ....................................   53
 45.5913 +       UNDELETED (search key) .....................................   53
 45.5914 +       UNDRAFT (search key) .......................................   53
 45.5915 +       UNFLAGGED (search key) .....................................   53
 45.5916 +       UNKEYWORD <flag> (search key) ..............................   53
 45.5917 +       UNSEEN (response code) .....................................   65
 45.5918 +       UNSEEN (search key) ........................................   53
 45.5919 +       UNSEEN (status item) .......................................   45
 45.5920 +       UNSUBSCRIBE (command) ......................................   39
 45.5921 +       Unique Identifier (UID) (message attribute) ................    8
 45.5922 +       X<atom> (command) ..........................................   62
 45.5923 +       [RFC-2822] Size (message attribute) ........................   12
 45.5924 +       \Answered (system flag) ....................................   11
 45.5925 +       \Deleted (system flag) .....................................   11
 45.5926 +       \Draft (system flag) .......................................   11
 45.5927 +       \Flagged (system flag) .....................................   11
 45.5928 +       \Marked (mailbox name attribute) ...........................   69
 45.5929 +       \Noinferiors (mailbox name attribute) ......................   69
 45.5930 +       \Noselect (mailbox name attribute) .........................   69
 45.5931 +       \Recent (system flag) ......................................   11
 45.5932 +       \Seen (system flag) ........................................   11
 45.5933 +       \Unmarked (mailbox name attribute) .........................   69
 45.5934 +
 45.5935 +
 45.5936 +
 45.5937 +
 45.5938 +
 45.5939 +
 45.5940 +
 45.5941 +Crispin                     Standards Track                   [Page 106]
 45.5942 +
 45.5943 +RFC 3501                         IMAPv4                       March 2003
 45.5944 +
 45.5945 +
 45.5946 +Author's Address
 45.5947 +
 45.5948 +   Mark R. Crispin
 45.5949 +   Networks and Distributed Computing
 45.5950 +   University of Washington
 45.5951 +   4545 15th Avenue NE
 45.5952 +   Seattle, WA  98105-4527
 45.5953 +
 45.5954 +   Phone: (206) 543-5762
 45.5955 +
 45.5956 +   EMail: MRC@CAC.Washington.EDU
 45.5957 +
 45.5958 +
 45.5959 +
 45.5960 +
 45.5961 +
 45.5962 +
 45.5963 +
 45.5964 +
 45.5965 +
 45.5966 +
 45.5967 +
 45.5968 +
 45.5969 +
 45.5970 +
 45.5971 +
 45.5972 +
 45.5973 +
 45.5974 +
 45.5975 +
 45.5976 +
 45.5977 +
 45.5978 +
 45.5979 +
 45.5980 +
 45.5981 +
 45.5982 +
 45.5983 +
 45.5984 +
 45.5985 +
 45.5986 +
 45.5987 +
 45.5988 +
 45.5989 +
 45.5990 +
 45.5991 +
 45.5992 +
 45.5993 +
 45.5994 +
 45.5995 +
 45.5996 +
 45.5997 +Crispin                     Standards Track                   [Page 107]
 45.5998 +
 45.5999 +RFC 3501                         IMAPv4                       March 2003
 45.6000 +
 45.6001 +
 45.6002 +Full Copyright Statement
 45.6003 +
 45.6004 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
 45.6005 +
 45.6006 +   This document and translations of it may be copied and furnished to
 45.6007 +   others, and derivative works that comment on or otherwise explain it
 45.6008 +   or assist in its implementation may be prepared, copied, published
 45.6009 +   and distributed, in whole or in part, without restriction of any
 45.6010 +   kind, provided that the above copyright notice and this paragraph are
 45.6011 +   included on all such copies and derivative works.  However, this
 45.6012 +   document itself may not be modified in any way, such as by removing
 45.6013 +   the copyright notice or references to the Internet Society or other
 45.6014 +   Internet organizations, except as needed for the purpose of
 45.6015 +   developing Internet standards in which case the procedures for
 45.6016 +   copyrights defined in the Internet Standards process must be
 45.6017 +   followed, or as required to translate it into languages other than
 45.6018 +   English.
 45.6019 +
 45.6020 +   The limited permissions granted above are perpetual and will not be
 45.6021 +   revoked by the Internet Society or its successors or assigns.  v This
 45.6022 +   document and the information contained herein is provided on an "AS
 45.6023 +   IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
 45.6024 +   FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 45.6025 +   LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL
 45.6026 +   NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY
 45.6027 +   OR FITNESS FOR A PARTICULAR PURPOSE.
 45.6028 +
 45.6029 +Acknowledgement
 45.6030 +
 45.6031 +   Funding for the RFC Editor function is currently provided by the
 45.6032 +   Internet Society.
 45.6033 +
 45.6034 +
 45.6035 +
 45.6036 +
 45.6037 +
 45.6038 +
 45.6039 +
 45.6040 +
 45.6041 +
 45.6042 +
 45.6043 +
 45.6044 +
 45.6045 +
 45.6046 +
 45.6047 +
 45.6048 +
 45.6049 +
 45.6050 +
 45.6051 +
 45.6052 +
 45.6053 +Crispin                     Standards Track                   [Page 108]
 45.6054 +
 45.6055 +
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/docs/rfc/rfc3502.txt	Mon Sep 14 15:17:45 2009 +0900
    46.3 @@ -0,0 +1,395 @@
    46.4 +
    46.5 +
    46.6 +
    46.7 +
    46.8 +
    46.9 +
   46.10 +Network Working Group                                         M. Crispin
   46.11 +Request for Comments: 3502                      University of Washington
   46.12 +Category: Standards Track                                     March 2003
   46.13 +
   46.14 +
   46.15 +    Internet Message Access Protocol (IMAP) - MULTIAPPEND Extension
   46.16 +
   46.17 +Status of this Memo
   46.18 +
   46.19 +   This document specifies an Internet standards track protocol for the
   46.20 +   Internet community, and requests discussion and suggestions for
   46.21 +   improvements.  Please refer to the current edition of the "Internet
   46.22 +   Official Protocol Standards" (STD 1) for the standardization state
   46.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   46.24 +
   46.25 +Copyright Notice
   46.26 +
   46.27 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
   46.28 +
   46.29 +Abstract
   46.30 +
   46.31 +   This document describes the multiappending extension to the Internet
   46.32 +   Message Access Protocol (IMAP) (RFC 3501).  This extension provides
   46.33 +   substantial performance improvements for IMAP clients which upload
   46.34 +   multiple messages at a time to a mailbox on the server.
   46.35 +
   46.36 +   A server which supports this extension indicates this with a
   46.37 +   capability name of "MULTIAPPEND".
   46.38 +
   46.39 +Terminology
   46.40 +
   46.41 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   46.42 +   "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
   46.43 +   be interpreted as described in [KEYWORDS].
   46.44 +
   46.45 +Introduction
   46.46 +
   46.47 +   The MULTIAPPEND extension permits uploading of multiple messages with
   46.48 +   a single command.  When used in conjunction with the [LITERAL+]
   46.49 +   extension, the entire upload is accomplished in a single
   46.50 +   command/response round trip.
   46.51 +
   46.52 +   A MULTIAPPEND APPEND operation is atomic; either all messages are
   46.53 +   successfully appended, or no messages are appended.
   46.54 +
   46.55 +   In the base IMAP specification, each message must be appended in a
   46.56 +   separate command, and there is no mechanism to "unappend" messages if
   46.57 +   an error occurs while appending.  Also, some mail stores may require
   46.58 +
   46.59 +
   46.60 +
   46.61 +Crispin                     Standards Track                     [Page 1]
   46.62 +
   46.63 +RFC 3502                    IMAP MULTIAPPEND                  March 2003
   46.64 +
   46.65 +
   46.66 +   an expensive "open/lock + sync/unlock/close" operation as part of
   46.67 +   appending; this can be quite expensive if it must be done on a
   46.68 +   per-message basis.
   46.69 +
   46.70 +   If the server supports both LITERAL+ and pipelining but not
   46.71 +   MULTIAPPEND, it may be possible to get some of the performance
   46.72 +   advantages of MULTIAPPEND by doing a pipelined "batch" append.
   46.73 +   However, it will not work as well as MULTIAPPEND for the following
   46.74 +   reasons:
   46.75 +
   46.76 +        1) Multiple APPEND commands, even as part of a pipelined batch,
   46.77 +        are non-atomic by definition.  There is no way to revert the
   46.78 +        mailbox to the state before the batch append in the event of an
   46.79 +        error.
   46.80 +
   46.81 +        2) It may not be feasible for the server to coalesce pipelined
   46.82 +        APPEND operations so as to avoid the "open/lock +
   46.83 +        sync/unlock/close" overhead described above.  In any case, such
   46.84 +        coalescing would be timing dependent and thus potentially
   46.85 +        unreliable.  In particular, with traditional UNIX mailbox files,
   46.86 +        it is assumed that a lock is held only for a single atomic
   46.87 +        operation, and many applications disregard any lock that is
   46.88 +        older than 5 minutes.
   46.89 +
   46.90 +        3) If an error occurs, depending upon the nature of the error,
   46.91 +        it is possible for additional messages to be appended after the
   46.92 +        error.  For example, the user wants to append 5 messages, but a
   46.93 +        disk quota error occurs with the third message because of its
   46.94 +        size.  However, the fourth and fifth messages have already been
   46.95 +        sent in the pipeline, so the mailbox ends up with the first,
   46.96 +        second, fourth, and fifth messages of the batch appended.
   46.97 +
   46.98 +6.3.11.  APPEND Command
   46.99 +
  46.100 +   Arguments:  mailbox name
  46.101 +               one or more messages to upload, specified as:
  46.102 +                  OPTIONAL flag parenthesized list
  46.103 +                  OPTIONAL date/time string
  46.104 +                  message literal
  46.105 +
  46.106 +   Data:       no specific responses for this command
  46.107 +
  46.108 +   Result:     OK - append completed
  46.109 +               NO - append error: can't append to that mailbox, error
  46.110 +                    in flags or date/time or message text,
  46.111 +                    append cancelled
  46.112 +               BAD - command unknown or arguments invalid
  46.113 +
  46.114 +
  46.115 +
  46.116 +
  46.117 +Crispin                     Standards Track                     [Page 2]
  46.118 +
  46.119 +RFC 3502                    IMAP MULTIAPPEND                  March 2003
  46.120 +
  46.121 +
  46.122 +      The APPEND command appends the literal arguments as new messages
  46.123 +      to the end of the specified destination mailbox.  This argument
  46.124 +      SHOULD be in the format of an [RFC-2822] message.  8-bit
  46.125 +      characters are permitted in the message.  A server implementation
  46.126 +      that is unable to preserve 8-bit data properly MUST be able to
  46.127 +      reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB]
  46.128 +      content transfer encoding.
  46.129 +
  46.130 +            Note: There MAY be exceptions, e.g., draft messages, in
  46.131 +            which required [RFC-2822] header lines are omitted in the
  46.132 +            message literal argument to APPEND.  The full implications
  46.133 +            of doing so MUST be understood and carefully weighed.
  46.134 +
  46.135 +      If a flag parenthesized list is specified, the flags SHOULD be set
  46.136 +      in the resulting message; otherwise, the flag list of the
  46.137 +      resulting message is set empty by default.
  46.138 +
  46.139 +      If a date-time is specified, the internal date SHOULD be set in
  46.140 +      the resulting message; otherwise, the internal date of the
  46.141 +      resulting message is set to the current date and time by default.
  46.142 +
  46.143 +      A zero-length message literal argument is an error, and MUST
  46.144 +      return a NO.  This can be used to cancel the append.
  46.145 +
  46.146 +      If the append is unsuccessful for any reason (including being
  46.147 +      cancelled), the mailbox MUST be restored to its state before the
  46.148 +      APPEND attempt; no partial appending is permitted.  The server MAY
  46.149 +      return an error before processing all the message arguments.
  46.150 +
  46.151 +      If the destination mailbox does not exist, a server MUST return an
  46.152 +      error, and MUST NOT automatically create the mailbox.  Unless it
  46.153 +      is certain that the destination mailbox can not be created, the
  46.154 +      server MUST send the response code "[TRYCREATE]" as the prefix of
  46.155 +      the text of the tagged NO response.  This gives a hint to the
  46.156 +      client that it can attempt a CREATE command and retry the APPEND
  46.157 +      if the CREATE is successful.
  46.158 +
  46.159 +      If the mailbox is currently selected, the normal new message
  46.160 +      actions SHOULD occur.  Specifically, the server SHOULD notify the
  46.161 +      client immediately via an untagged EXISTS response.  If the server
  46.162 +      does not do so, the client MAY issue a NOOP command (or failing
  46.163 +      that, a CHECK command) after one or more APPEND commands.
  46.164 +
  46.165 +
  46.166 +
  46.167 +
  46.168 +
  46.169 +
  46.170 +
  46.171 +
  46.172 +
  46.173 +Crispin                     Standards Track                     [Page 3]
  46.174 +
  46.175 +RFC 3502                    IMAP MULTIAPPEND                  March 2003
  46.176 +
  46.177 +
  46.178 +   Example: C: A003 APPEND saved-messages (\Seen) {329}
  46.179 +            S: + Ready for literal data
  46.180 +            C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  46.181 +            C: From: Fred Foobar <foobar@Blurdybloop.example.COM>
  46.182 +            C: Subject: afternoon meeting
  46.183 +            C: To: mooch@owatagu.example.net
  46.184 +            C: Message-Id: <B27397-0100000@Blurdybloop.example.COM>
  46.185 +            C: MIME-Version: 1.0
  46.186 +            C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  46.187 +            C:
  46.188 +            C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  46.189 +            C:  (\Seen) " 7-Feb-1994 22:43:04 -0800" {295}
  46.190 +            S: + Ready for literal data
  46.191 +            C: Date: Mon, 7 Feb 1994 22:43:04 -0800 (PST)
  46.192 +            C: From: Joe Mooch <mooch@OWaTaGu.example.net>
  46.193 +            C: Subject: Re: afternoon meeting
  46.194 +            C: To: foobar@blurdybloop.example.com
  46.195 +            C: Message-Id: <a0434793874930@OWaTaGu.example.net>
  46.196 +            C: MIME-Version: 1.0
  46.197 +            C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  46.198 +            C:
  46.199 +            C: 3:30 is fine with me.
  46.200 +            C:
  46.201 +            S: A003 OK APPEND completed
  46.202 +            C: A004 APPEND bogusname (\Flagged) {1023}
  46.203 +            S: A004 NO [TRYCREATE] No such mailbox as bogusname
  46.204 +            C: A005 APPEND test (\Flagged) {99}
  46.205 +            S: + Ready for literal data
  46.206 +            C: Date: Mon, 7 Feb 2000 22:43:04 -0800 (PST)
  46.207 +            C: From: Fred Foobar <fred@example.com>
  46.208 +            C: Subject: hmm...
  46.209 +            C:  {35403}
  46.210 +            S: A005 NO APPEND failed: Disk quota exceeded
  46.211 +
  46.212 +        Note: The APPEND command is not used for message delivery,
  46.213 +        because it does not provide a mechanism to transfer [SMTP]
  46.214 +        envelope information.
  46.215 +
  46.216 +Modification to IMAP4rev1 Base Protocol Formal Syntax
  46.217 +
  46.218 +   The following syntax specification uses the Augmented Backus-Naur
  46.219 +   Form (ABNF) notation as specified in [ABNF].
  46.220 +
  46.221 +   append          = "APPEND" SP mailbox 1*append-message
  46.222 +
  46.223 +   append-message  = [SP flag-list] [SP date-time] SP literal
  46.224 +
  46.225 +
  46.226 +
  46.227 +
  46.228 +
  46.229 +Crispin                     Standards Track                     [Page 4]
  46.230 +
  46.231 +RFC 3502                    IMAP MULTIAPPEND                  March 2003
  46.232 +
  46.233 +
  46.234 +MULTIAPPEND Interaction with UIDPLUS Extension
  46.235 +
  46.236 +   Servers which support both MULTIAPPEND and [UIDPLUS] will have the
  46.237 +   "resp-code-apnd" rule modified as follows:
  46.238 +
  46.239 +   resp-code-apnd  = "APPENDUID" SP nz-number SP set
  46.240 +
  46.241 +   That is, the APPENDUID response code returns as many UIDs as there
  46.242 +   were messages appended in the multiple append.  The UIDs returned
  46.243 +   should be in the order the articles where appended.  The message set
  46.244 +   may not contain extraneous UIDs or the symbol "*".
  46.245 +
  46.246 +Security Considerations
  46.247 +
  46.248 +   The MULTIAPPEND extension does not raise any security considerations
  46.249 +   that are not present in the base [IMAP] protocol, and these issues
  46.250 +   are discussed in [IMAP].  Nevertheless, it is important to remember
  46.251 +   that IMAP4rev1 protocol transactions, including electronic mail data,
  46.252 +   are sent in the clear over the network unless protection from
  46.253 +   snooping is negotiated, either by the use of STARTTLS, privacy
  46.254 +   protection is negotiated in the AUTHENTICATE command, or some other
  46.255 +   protection mechanism is in effect.
  46.256 +
  46.257 +Normative References
  46.258 +
  46.259 +   [ABNF]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
  46.260 +              Specifications: ABNF", RFC 2234, November 1997.
  46.261 +
  46.262 +   [IMAP]     Crispin, M., "Internet Message Access Protocol - Version
  46.263 +              4rev1", RFC 3501, March 2003.
  46.264 +
  46.265 +   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
  46.266 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  46.267 +
  46.268 +   [MIME-IMB] Freed, N. and N. Borenstein, "MIME (Multipurpose Internet
  46.269 +              Mail Extensions) Part One: Format of Internet Message
  46.270 +              Bodies", RFC 2045, November 1996.
  46.271 +
  46.272 +   [RFC-2822] Resnick, P., "Internet Message Format", RFC 2822, April
  46.273 +              2001.
  46.274 +
  46.275 +
  46.276 +
  46.277 +
  46.278 +
  46.279 +
  46.280 +
  46.281 +
  46.282 +
  46.283 +
  46.284 +
  46.285 +Crispin                     Standards Track                     [Page 5]
  46.286 +
  46.287 +RFC 3502                    IMAP MULTIAPPEND                  March 2003
  46.288 +
  46.289 +
  46.290 +Informative References
  46.291 +
  46.292 +   [LITERAL+] Myers, J., "IMAP4 non-synchronizing literals", RFC 2088,
  46.293 +              January 1997.
  46.294 +
  46.295 +   [UIDPLUS]  Myers, J., "IMAP4 UIDPLUS extension", RFC 2359, June 1988.
  46.296 +
  46.297 +   [SMTP]     Klensin, J., Editor, "Simple Mail Transfer Protocol", RFC
  46.298 +              2821, April 2001.
  46.299 +
  46.300 +Author's Address
  46.301 +
  46.302 +   Mark R. Crispin
  46.303 +   Networks and Distributed Computing
  46.304 +   University of Washington
  46.305 +   4545 15th Avenue NE
  46.306 +   Seattle, WA  98105-4527
  46.307 +
  46.308 +   Phone: (206) 543-5762
  46.309 +   EMail: MRC@CAC.Washington.EDU
  46.310 +
  46.311 +
  46.312 +
  46.313 +
  46.314 +
  46.315 +
  46.316 +
  46.317 +
  46.318 +
  46.319 +
  46.320 +
  46.321 +
  46.322 +
  46.323 +
  46.324 +
  46.325 +
  46.326 +
  46.327 +
  46.328 +
  46.329 +
  46.330 +
  46.331 +
  46.332 +
  46.333 +
  46.334 +
  46.335 +
  46.336 +
  46.337 +
  46.338 +
  46.339 +
  46.340 +
  46.341 +Crispin                     Standards Track                     [Page 6]
  46.342 +
  46.343 +RFC 3502                    IMAP MULTIAPPEND                  March 2003
  46.344 +
  46.345 +
  46.346 +Full Copyright Statement
  46.347 +
  46.348 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
  46.349 +
  46.350 +   This document and translations of it may be copied and furnished to
  46.351 +   others, and derivative works that comment on or otherwise explain it
  46.352 +   or assist in its implementation may be prepared, copied, published
  46.353 +   and distributed, in whole or in part, without restriction of any
  46.354 +   kind, provided that the above copyright notice and this paragraph are
  46.355 +   included on all such copies and derivative works.  However, this
  46.356 +   document itself may not be modified in any way, such as by removing
  46.357 +   the copyright notice or references to the Internet Society or other
  46.358 +   Internet organizations, except as needed for the purpose of
  46.359 +   developing Internet standards in which case the procedures for
  46.360 +   copyrights defined in the Internet Standards process must be
  46.361 +   followed, or as required to translate it into languages other than
  46.362 +   English.
  46.363 +
  46.364 +   The limited permissions granted above are perpetual and will not be
  46.365 +   revoked by the Internet Society or its successors or assigns.
  46.366 +
  46.367 +   This document and the information contained herein is provided on an
  46.368 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  46.369 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  46.370 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  46.371 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  46.372 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  46.373 +
  46.374 +Acknowledgement
  46.375 +
  46.376 +   Funding for the RFC Editor function is currently provided by the
  46.377 +   Internet Society.
  46.378 +
  46.379 +
  46.380 +
  46.381 +
  46.382 +
  46.383 +
  46.384 +
  46.385 +
  46.386 +
  46.387 +
  46.388 +
  46.389 +
  46.390 +
  46.391 +
  46.392 +
  46.393 +
  46.394 +
  46.395 +
  46.396 +
  46.397 +Crispin                     Standards Track                     [Page 7]
  46.398 +
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/docs/rfc/rfc3503.txt	Mon Sep 14 15:17:45 2009 +0900
    47.3 @@ -0,0 +1,507 @@
    47.4 +
    47.5 +
    47.6 +
    47.7 +
    47.8 +
    47.9 +
   47.10 +Network Working Group                                        A. Melnikov
   47.11 +Request for Comments: 3503                 ACI Worldwide/MessagingDirect
   47.12 +Category: Standards Track                                     March 2003
   47.13 +
   47.14 +
   47.15 +          Message Disposition Notification (MDN) profile for
   47.16 +                Internet Message Access Protocol (IMAP)
   47.17 +
   47.18 +Status of this Memo
   47.19 +
   47.20 +   This document specifies an Internet standards track protocol for the
   47.21 +   Internet community, and requests discussion and suggestions for
   47.22 +   improvements.  Please refer to the current edition of the "Internet
   47.23 +   Official Protocol Standards" (STD 1) for the standardization state
   47.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   47.25 +
   47.26 +Copyright Notice
   47.27 +
   47.28 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
   47.29 +
   47.30 +Abstract
   47.31 +
   47.32 +   The Message Disposition Notification (MDN) facility defined in RFC
   47.33 +   2298 provides a means by which a message can request that message
   47.34 +   processing by the recipient be acknowledged as well as a format to be
   47.35 +   used for such acknowledgements.  However, it doesn't describe how
   47.36 +   multiple Mail User Agents (MUAs) should handle the generation of MDNs
   47.37 +   in an Internet Message Access Protocol (IMAP4) environment.
   47.38 +
   47.39 +   This document describes how to handle MDNs in such an environment and
   47.40 +   provides guidelines for implementers of IMAP4 that want to add MDN
   47.41 +   support to their products.
   47.42 +
   47.43 +
   47.44 +
   47.45 +
   47.46 +
   47.47 +
   47.48 +
   47.49 +
   47.50 +
   47.51 +
   47.52 +
   47.53 +
   47.54 +
   47.55 +
   47.56 +
   47.57 +
   47.58 +
   47.59 +
   47.60 +
   47.61 +Melnikov                    Standards Track                     [Page 1]
   47.62 +
   47.63 +RFC 3503                  MDN profile for IMAP                March 2003
   47.64 +
   47.65 +
   47.66 +Table of Contents
   47.67 +
   47.68 +   1.  Conventions Used in this Document.............................  2
   47.69 +   2.  Introduction and Overview.....................................  2
   47.70 +   3.  Client behavior...............................................  3
   47.71 +       3.1. Client behavior when receiving a message.................  5
   47.72 +       3.2. Client behavior when copying a message...................  5
   47.73 +       3.3. Client behavior when sending a message...................  5
   47.74 +       3.4. Client behavior when saving a temporary message..........  5
   47.75 +   4.  Server behavior...............................................  5
   47.76 +       4.1. Server that supports arbitrary keywords..................  5
   47.77 +       4.2. Server that supports only $MDNSent keyword...............  5
   47.78 +       4.3. Interaction with IMAP ACL extension......................  6
   47.79 +   5.  Examples......................................................  6
   47.80 +   6.  Security Considerations.......................................  7
   47.81 +   7.  Formal Syntax.................................................  7
   47.82 +   8.  Acknowledgments...............................................  7
   47.83 +   9.  Normative References..........................................  8
   47.84 +   10. Author's Address..............................................  8
   47.85 +   11. Full Copyright Statement......................................  9
   47.86 +
   47.87 +1.  Conventions Used in this Document
   47.88 +
   47.89 +   "C:" and "S:" in examples show lines sent by the client and server
   47.90 +   respectively.
   47.91 +
   47.92 +   The keywords "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in
   47.93 +   this document when typed in uppercase are to be interpreted as
   47.94 +   defined in "Key words for use in RFCs to Indicate Requirement Levels"
   47.95 +   [KEYWORDS].
   47.96 +
   47.97 +2.  Introduction and Overview
   47.98 +
   47.99 +   This memo defines an additional [IMAP4] mailbox keyword that allows
  47.100 +   multiple Mail User Agents (MUAs) to know if a requested receipt
  47.101 +   notification was sent.
  47.102 +
  47.103 +   Message Disposition Notification [MDN] does not require any special
  47.104 +   support of IMAP in the case where a user has access to the mailstore
  47.105 +   from only one computer and is using a single MUA.  In this case, the
  47.106 +   MUA behaves as described in [MDN], i.e., the MUA performs automatic
  47.107 +   processing and generates corresponding MDNs, it performs requested
  47.108 +   action and, with the user's permission, sends appropriate MDNs.  The
  47.109 +   MUA will not send MDN twice because the MUA keeps track of sent
  47.110 +   notifications in a local configuration.  However, that does not work
  47.111 +   when IMAP is used to access the same mailstore from different
  47.112 +   locations or is using different MUAs.
  47.113 +
  47.114 +
  47.115 +
  47.116 +
  47.117 +Melnikov                    Standards Track                     [Page 2]
  47.118 +
  47.119 +RFC 3503                  MDN profile for IMAP                March 2003
  47.120 +
  47.121 +
  47.122 +   This document defines a new special purpose mailbox keyword $MDNSent
  47.123 +   that must be used by MUAs.  It does not define any new command or
  47.124 +   response for IMAP, but describes a technique that MUAs should use to
  47.125 +   achieve interoperability.
  47.126 +
  47.127 +   When a client opens a mailbox for the first time, it verifies that
  47.128 +   the server is capable of storing the $MDNSent keyword by examining
  47.129 +   the PERMANENTFLAGS response code.  In order to support MDN in IMAP, a
  47.130 +   server MUST support either the $MDNSent keyword, or arbitrary message
  47.131 +   keywords.
  47.132 +
  47.133 +3.  Client behavior
  47.134 +
  47.135 +   The use of IMAP requires few additional steps in mail processing on
  47.136 +   the client side.  The following timeline modifies the timeline found
  47.137 +   in Section 4 of [MDN].
  47.138 +
  47.139 +   -- User composes message.
  47.140 +
  47.141 +   -- User tells MUA to send message.
  47.142 +
  47.143 +   -- MUA passes message to MSA (original recipient information passed
  47.144 +      along).  MUA [optionally] saves message to a folder for sent mail
  47.145 +      with $MDNSent flag set.
  47.146 +
  47.147 +   -- MSA sends message to MTA.
  47.148 +
  47.149 +   -- Final MTA receives message.
  47.150 +
  47.151 +   -- Final MTA delivers message to MUA (possibly generating DSN).
  47.152 +
  47.153 +   -- MUA logs into IMAP server, opens mailbox, verifies if mailbox can
  47.154 +      store $MDNSent keyword by examining PERMANENTFLAGS response.
  47.155 +
  47.156 +   -- MUA performs automatic processing and generates corresponding MDNs
  47.157 +      ("dispatched", "processed", "deleted", "denied" or "failed"
  47.158 +      disposition type with "automatic-action" and "MDN-sent-
  47.159 +      automatically" disposition modes) for messages that do not have
  47.160 +      $MDNSent keyword, or \Draft flag set. (*)
  47.161 +
  47.162 +   -- MUA sets the $MDNSent keyword for every message that required an
  47.163 +      automatic MDN to be sent, whether or not the MDN was sent.
  47.164 +
  47.165 +   -- MUA displays a list of messages to user.
  47.166 +
  47.167 +   -- User selects a message and requests that some action be performed
  47.168 +      on it.
  47.169 +
  47.170 +
  47.171 +
  47.172 +
  47.173 +Melnikov                    Standards Track                     [Page 3]
  47.174 +
  47.175 +RFC 3503                  MDN profile for IMAP                March 2003
  47.176 +
  47.177 +
  47.178 +   -- MUA performs requested action and, with user's permission, sends
  47.179 +      appropriate MDN ("displayed", "dispatched", "processed",
  47.180 +      "deleted", "denied" or "failed" disposition type with "manual-
  47.181 +      action" and "MDN-sent-manually" or "MDN-sent-automatically"
  47.182 +      disposition mode).  If the generated MDN is saved to a mailbox
  47.183 +      with the APPEND command, the client MUST specify the $MDNSent
  47.184 +      keyword in the APPEND.
  47.185 +
  47.186 +   -- MUA sets the $MDNSent keyword for all messages for which the user
  47.187 +      confirmed the dispatching of disposition (or was explicitly
  47.188 +      prohibited to do so).
  47.189 +
  47.190 +   -- User possibly performs other actions on message, but no further
  47.191 +      MDNs are generated.
  47.192 +
  47.193 +   (*) Note: MUA MUST NOT use \Recent flag as an indicator that it
  47.194 +       should send MDN, because according to [IMAP4], "If multiple
  47.195 +       connections have the same mailbox selected simultaneously, it is
  47.196 +       undefined which of these connections will see newly-arrived
  47.197 +       messages with \Recent set and which will see it without \Recent
  47.198 +       set".  Thus, using \Recent as an indicator will cause
  47.199 +       unpredictable client behavior with different IMAP4 servers.
  47.200 +       However, the client MAY use \Seen flag as one of the indicators
  47.201 +       that MDN must not be sent.  The client MUST NOT use any other
  47.202 +       standard flags, like \Draft or \Answered, to indicate that MDN
  47.203 +       was previously sent, because they have different well known
  47.204 +       meaning.  In any case, in the presence of the $MDNSent keyword,
  47.205 +       the client MUST ignore all other flags or keywords for the
  47.206 +       purpose of generating an MDN and MUST NOT send the MDN.
  47.207 +
  47.208 +   When the client opens a mailbox for the first time, it must verify
  47.209 +   that the server supports the $MDNSent keyword, or arbitrary message
  47.210 +   keywords by examining PERMANENTFLAGS response code.
  47.211 +
  47.212 +   The client MUST NOT try to set the $MDNSent keyword if the server is
  47.213 +   incapable of storing it permanently.
  47.214 +
  47.215 +   The client MUST be prepared to receive NO from the server as the
  47.216 +   result of STORE $MDNSent when the server advertises the support of
  47.217 +   storing arbitrary keywords, because the server may limit the number
  47.218 +   of message keywords it can store in a particular mailbox.  A client
  47.219 +   SHOULD NOT send MDN if it fails to store the $MDNSent keyword.
  47.220 +
  47.221 +   Once the $MDNSent keyword is set, it MUST NOT be unset by a client.
  47.222 +   The client MAY set the $MDNSent keyword when a user denies sending
  47.223 +   the notification.  This prohibits all other MUAs from sending MDN for
  47.224 +   this message.
  47.225 +
  47.226 +
  47.227 +
  47.228 +
  47.229 +Melnikov                    Standards Track                     [Page 4]
  47.230 +
  47.231 +RFC 3503                  MDN profile for IMAP                March 2003
  47.232 +
  47.233 +
  47.234 +3.1.  Client behavior when receiving a message
  47.235 +
  47.236 +   The client MUST NOT send MDN if a message has the $MDNSent keyword
  47.237 +   set.  It also MUST NOT send MDN if a message has \Draft flag, because
  47.238 +   some clients use this flag to mark a message as incomplete.
  47.239 +
  47.240 +   See the timeline in section 3 for details on client behavior when
  47.241 +   receiving a message.
  47.242 +
  47.243 +3.2.  Client behavior when copying a message
  47.244 +
  47.245 +   The client SHOULD verify that $MDNSent is preserved on a COPY
  47.246 +   operation.  Furthermore, when a message is copied between servers
  47.247 +   with the APPEND command, the client MUST set the $MDNSent keyword
  47.248 +   correctly.
  47.249 +
  47.250 +3.3.  Client behavior when sending a message
  47.251 +
  47.252 +   When saving a sent message to any folder, the client MUST set the
  47.253 +   $MDNSent keyword to prevent another client from sending MDN for the
  47.254 +   message.
  47.255 +
  47.256 +3.4.  Client behavior when saving a temporary message
  47.257 +
  47.258 +   When saving an unfinished message to any folder client MUST set
  47.259 +   $MDNSent keyword to prevent another client from sending MDN for the
  47.260 +   message.
  47.261 +
  47.262 +4.  Server behavior
  47.263 +
  47.264 +   Server implementors that want to follow this specification must
  47.265 +   insure that their server complies with either section 4.1 or section
  47.266 +   4.2.  If the server also supports the IMAP [ACL] extension, it MUST
  47.267 +   also comply with the section 4.3.
  47.268 +
  47.269 +4.1.  Server that supports arbitrary keywords
  47.270 +
  47.271 +   No changes are required from the server to make it compatible with
  47.272 +   the extension described in this document if it supports arbitrary
  47.273 +   keywords.
  47.274 +
  47.275 +4.2.  Server that supports only $MDNSent keyword
  47.276 +
  47.277 +   Servers that support only the $MDNSent keyword MUST preserve it on
  47.278 +   the COPY operation.  It is also expected that a server that supports
  47.279 +   SEARCH <flag> will also support the SEARCH KEYWORD $MDNSent.
  47.280 +
  47.281 +
  47.282 +
  47.283 +
  47.284 +
  47.285 +Melnikov                    Standards Track                     [Page 5]
  47.286 +
  47.287 +RFC 3503                  MDN profile for IMAP                March 2003
  47.288 +
  47.289 +
  47.290 +4.3.  Interaction with IMAP ACL extension
  47.291 +
  47.292 +   Any server that conforms to either 4.1 or 4.2 and also supports the
  47.293 +   IMAP [ACL] extension, SHOULD preserve the $MDNSent keyword on COPY
  47.294 +   even if the client does not have 'w' right.  This will prevent the
  47.295 +   generation of a duplicated MDN for the same message.  Note that the
  47.296 +   server MUST still check if the client has rights to perform the COPY
  47.297 +   operation on a message according to [ACL].
  47.298 +
  47.299 +5.  Examples
  47.300 +
  47.301 +   1) MUA opens mailbox for the first time.
  47.302 +
  47.303 +   a) The server supports storing of arbitrary keywords
  47.304 +
  47.305 +   C: a100 select INBOX
  47.306 +   S: * FLAGS (\Flagged \Draft \Deleted \Seen)
  47.307 +   S: * OK [PERMANENTFLAGS (\Flagged \Draft \Deleted \Seen \*)]
  47.308 +   S: * 5 EXISTS
  47.309 +   S: * 3 RECENT
  47.310 +   S: * OK [UIDVALIDITY 894294713]
  47.311 +   S: a100 OK [READ-WRITE] Completed
  47.312 +
  47.313 +   b) The server supports storing of the $MDNSent keyword
  47.314 +
  47.315 +   C: a100 select INBOX
  47.316 +   S: * FLAGS (\Flagged \Draft \Deleted \Seen $MDNSent)
  47.317 +   S: * OK [PERMANENTFLAGS (\Flagged \Draft \Deleted \Seen $MDNSent)]
  47.318 +   S: * 5 EXISTS
  47.319 +   S: * 3 RECENT
  47.320 +   S: * OK [UIDVALIDITY 894294713]
  47.321 +   S: a100 OK [READ-WRITE] Completed
  47.322 +
  47.323 +   2) The MUA successfully sets the $MDNSent keyword
  47.324 +
  47.325 +   C: a200 STORE 4 +FLAGS ($MDNSent)
  47.326 +   S: * 4 FETCH (FLAGS (\Flagged \Seen $MDNSent))
  47.327 +   S: * FLAGS ($MDNSent \Flagged \Deleted \Draft \Seen)
  47.328 +   S: * OK [PERMANENTFLAGS ($MDNSent \Flagged \Deleted \Draft \Seen \*)]
  47.329 +   S: a200 OK STORE completed
  47.330 +
  47.331 +   3) The server refuses to store the $MDNSent keyword
  47.332 +
  47.333 +   C: a200 STORE 4 +FLAGS ($MDNSent)
  47.334 +   S: a200 NO STORE failed : no space left to store $MDNSent keyword
  47.335 +
  47.336 +
  47.337 +
  47.338 +
  47.339 +
  47.340 +
  47.341 +Melnikov                    Standards Track                     [Page 6]
  47.342 +
  47.343 +RFC 3503                  MDN profile for IMAP                March 2003
  47.344 +
  47.345 +
  47.346 +   4) All clients and servers MUST treat the $MDNSent keyword as case
  47.347 +   insensitive in all operations, as stated in [IMAP].
  47.348 +
  47.349 +   C: a300 FETCH 1:* FLAGS
  47.350 +   S: * 1 FETCH (FLAGS (\Seen))
  47.351 +   S: * 2 FETCH (FLAGS (\Answered \Seen $MdnSENt))
  47.352 +   S: * 3 FETCH (FLAGS ())
  47.353 +   S: * 4 FETCH (FLAGS (\Flagged \Seen $MdnSENT))
  47.354 +   S: * 5 FETCH (FLAGS ($MDNSent))
  47.355 +   S: * 6 FETCH (FLAGS (\Recent))
  47.356 +   S: a300 OK FETCH completed
  47.357 +   C: a400 SEARCH KEYWORDS $mdnsent
  47.358 +   S: * SEARCH 2 4 5
  47.359 +   S: a400 OK SEARCH completed
  47.360 +
  47.361 +6.  Security Considerations
  47.362 +
  47.363 +   There are no known security issues with this extension, not found in
  47.364 +   [MDN] and/or [IMAP4].
  47.365 +
  47.366 +   Section 4.3 changes ACL checking requirements on an IMAP server that
  47.367 +   implements IMAP [ACL] extension.
  47.368 +
  47.369 +7.  Formal Syntax
  47.370 +
  47.371 +   The following syntax specification uses the augmented Backus-Naur
  47.372 +   Form (BNF) notation as specified in [RFC-822], as modified by
  47.373 +   [IMAP4].  Non-terminals referenced, but not defined below, are as
  47.374 +   defined by [IMAP4].
  47.375 +
  47.376 +   Except as noted otherwise, all alphabetic characters are case-
  47.377 +   insensitive.  The use of upper or lower case characters to define
  47.378 +   token strings is for editorial clarity only.  Implementations MUST
  47.379 +   accept these strings in a case-insensitive fashion.
  47.380 +
  47.381 +   flag_keyword    ::= "$MDNSent" / other_keywords
  47.382 +
  47.383 +   other_keywords  ::= atom
  47.384 +
  47.385 +8.  Acknowledgments
  47.386 +
  47.387 +   This document is the product of discussions that took place on the
  47.388 +   IMAP mailing list.  Special gratitude to Cyrus Daboo and Randall
  47.389 +   Gellens for reviewing the document.
  47.390 +
  47.391 +   Thank you to my father who as he has helped to make me what I am.  I
  47.392 +   miss you terribly.
  47.393 +
  47.394 +
  47.395 +
  47.396 +
  47.397 +Melnikov                    Standards Track                     [Page 7]
  47.398 +
  47.399 +RFC 3503                  MDN profile for IMAP                March 2003
  47.400 +
  47.401 +
  47.402 +9.  Normative References
  47.403 +
  47.404 +   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
  47.405 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  47.406 +
  47.407 +   [MDN]      Fajman, R., "An Extensible Message Format for Message
  47.408 +              Disposition Notifications", RFC 2298, March 1998.
  47.409 +
  47.410 +   [IMAP4]    Crispin, M., "Internet Message Access Protocol - Version
  47.411 +              4rev1", RFC 3501, March 2003.
  47.412 +
  47.413 +   [ACL]      Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997.
  47.414 +
  47.415 +10.  Author's Address
  47.416 +
  47.417 +   Alexey Melnikov
  47.418 +   ACI Worldwide/MessagingDirect
  47.419 +   59 Clarendon Road
  47.420 +   Watford, Hertfordshire
  47.421 +   United Kingdom, WD17 1FQ
  47.422 +
  47.423 +   Phone: +44 1923 81 2877
  47.424 +   EMail: mel@messagingdirect.com
  47.425 +
  47.426 +
  47.427 +
  47.428 +
  47.429 +
  47.430 +
  47.431 +
  47.432 +
  47.433 +
  47.434 +
  47.435 +
  47.436 +
  47.437 +
  47.438 +
  47.439 +
  47.440 +
  47.441 +
  47.442 +
  47.443 +
  47.444 +
  47.445 +
  47.446 +
  47.447 +
  47.448 +
  47.449 +
  47.450 +
  47.451 +
  47.452 +
  47.453 +Melnikov                    Standards Track                     [Page 8]
  47.454 +
  47.455 +RFC 3503                  MDN profile for IMAP                March 2003
  47.456 +
  47.457 +
  47.458 +11.  Full Copyright Statement
  47.459 +
  47.460 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
  47.461 +
  47.462 +   This document and translations of it may be copied and furnished to
  47.463 +   others, and derivative works that comment on or otherwise explain it
  47.464 +   or assist in its implementation may be prepared, copied, published
  47.465 +   and distributed, in whole or in part, without restriction of any
  47.466 +   kind, provided that the above copyright notice and this paragraph are
  47.467 +   included on all such copies and derivative works.  However, this
  47.468 +   document itself may not be modified in any way, such as by removing
  47.469 +   the copyright notice or references to the Internet Society or other
  47.470 +   Internet organizations, except as needed for the purpose of
  47.471 +   developing Internet standards in which case the procedures for
  47.472 +   copyrights defined in the Internet Standards process must be
  47.473 +   followed, or as required to translate it into languages other than
  47.474 +   English.
  47.475 +
  47.476 +   The limited permissions granted above are perpetual and will not be
  47.477 +   revoked by the Internet Society or its successors or assigns.
  47.478 +
  47.479 +   This document and the information contained herein is provided on an
  47.480 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  47.481 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  47.482 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  47.483 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  47.484 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  47.485 +
  47.486 +Acknowledgement
  47.487 +
  47.488 +   Funding for the RFC Editor function is currently provided by the
  47.489 +   Internet Society.
  47.490 +
  47.491 +
  47.492 +
  47.493 +
  47.494 +
  47.495 +
  47.496 +
  47.497 +
  47.498 +
  47.499 +
  47.500 +
  47.501 +
  47.502 +
  47.503 +
  47.504 +
  47.505 +
  47.506 +
  47.507 +
  47.508 +
  47.509 +Melnikov                    Standards Track                     [Page 9]
  47.510 +
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/docs/rfc/rfc3516.txt	Mon Sep 14 15:17:45 2009 +0900
    48.3 @@ -0,0 +1,451 @@
    48.4 +
    48.5 +
    48.6 +
    48.7 +
    48.8 +
    48.9 +
   48.10 +Network Working Group                                       L. Nerenberg
   48.11 +Request for Comments: 3516                               Orthanc Systems
   48.12 +Category: Standards Track                                     April 2003
   48.13 +
   48.14 +
   48.15 +                     IMAP4 Binary Content Extension
   48.16 +
   48.17 +Status of this Memo
   48.18 +
   48.19 +   This document specifies an Internet standards track protocol for the
   48.20 +   Internet community, and requests discussion and suggestions for
   48.21 +   improvements.  Please refer to the current edition of the "Internet
   48.22 +   Official Protocol Standards" (STD 1) for the standardization state
   48.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   48.24 +
   48.25 +Copyright Notice
   48.26 +
   48.27 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
   48.28 +
   48.29 +Abstract
   48.30 +
   48.31 +   This memo defines the Binary extension to the Internet Message Access
   48.32 +   Protocol (IMAP4).  It provides a mechanism for IMAP4 clients and
   48.33 +   servers to exchange message body data without using a MIME content-
   48.34 +   transfer-encoding.
   48.35 +
   48.36 +1.   Conventions Used in this Document
   48.37 +
   48.38 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
   48.39 +   in this document are to be interpreted as described in [KEYWORD].
   48.40 +
   48.41 +   The abbreviation "CTE" means content-transfer-encoding.
   48.42 +
   48.43 +2.   Introduction
   48.44 +
   48.45 +   The MIME extensions to Internet messaging allow for the transmission
   48.46 +   of non-textual (binary) message content [MIME-IMB].  Since the
   48.47 +   traditional transports for messaging are not always capable of
   48.48 +   passing binary data transparently, MIME provides encoding schemes
   48.49 +   that allow binary content to be transmitted over transports that are
   48.50 +   not otherwise able to do so.
   48.51 +
   48.52 +   The overhead of MIME-encoding this content can be considerable in
   48.53 +   some contexts (e.g., slow radio links, streaming multimedia).
   48.54 +   Reducing the overhead associated with CTE schemes such as base64
   48.55 +
   48.56 +
   48.57 +
   48.58 +
   48.59 +
   48.60 +
   48.61 +Nerenberg                   Standards Track                     [Page 1]
   48.62 +
   48.63 +RFC 3516             IMAP4 Binary Content Extension           April 2003
   48.64 +
   48.65 +
   48.66 +   can give a noticeable reduction in resource consumption.  The Binary
   48.67 +   extension lets the server perform CTE decoding prior to transmitting
   48.68 +   message data to the client.
   48.69 +
   48.70 +3.  Content-Transfer-Encoding Considerations
   48.71 +
   48.72 +   Every IMAP4 body section has a MIME content-transfer-encoding.
   48.73 +   (Those without an explicit Content-Transfer-Encoding header are
   48.74 +   implicitly labeled as "7bit" content.)  In the terminology of [MIME-
   48.75 +   IMB], the CTE specifies both a decoding algorithm and the domain of
   48.76 +   the decoded data.  In this memo, "decoding" refers to the CTE
   48.77 +   decoding step described in [MIME-IMB].
   48.78 +
   48.79 +   Certain CTEs use an identity encoding transformation.  For these CTEs
   48.80 +   there is no decoding required, however the domain of the underlying
   48.81 +   data may not be expressible in the IMAP4 protocol (e.g., MIME
   48.82 +   "binary" content containing NUL octets).  To accommodate these cases
   48.83 +   the Binary extension introduces a new type of literal protocol
   48.84 +   element that is fully eight bit transparent.
   48.85 +
   48.86 +   Thus, server  processing of the FETCH BINARY command involves two
   48.87 +   logical steps:
   48.88 +
   48.89 +   1)  perform any CTE-related decoding
   48.90 +
   48.91 +   2)  determine the domain of the decoded data
   48.92 +
   48.93 +   Step 2 is necessary to determine which protocol element should be
   48.94 +   used to transmit the decoded data.  (See FETCH Response Extensions
   48.95 +   for further details.)
   48.96 +
   48.97 +4.  Framework for the IMAP4 Binary Extension
   48.98 +
   48.99 +   This memo defines the following extensions to [IMAP4rev1].
  48.100 +
  48.101 +4.1.  CAPABILITY Identification
  48.102 +
  48.103 +   IMAP4 servers that support this extension MUST include "BINARY" in
  48.104 +   the response list to the CAPABILITY command.
  48.105 +
  48.106 +4.2.  FETCH Command Extensions
  48.107 +
  48.108 +   This extension defines three new FETCH command data items.
  48.109 +
  48.110 +      BINARY<section-binary>[<partial>]
  48.111 +
  48.112 +         Requests that the specified section be transmitted after
  48.113 +         performing CTE-related decoding.
  48.114 +
  48.115 +
  48.116 +
  48.117 +Nerenberg                   Standards Track                     [Page 2]
  48.118 +
  48.119 +RFC 3516             IMAP4 Binary Content Extension           April 2003
  48.120 +
  48.121 +
  48.122 +         The <partial> argument, if present, requests that a subset of
  48.123 +         the data be returned.  The semantics of a partial FETCH BINARY
  48.124 +         command are the same as for a partial FETCH BODY command, with
  48.125 +         the exception that the <partial> arguments refer to the DECODED
  48.126 +         section data.
  48.127 +
  48.128 +      BINARY.PEEK<section-binary>[<partial>]
  48.129 +
  48.130 +         An alternate form of FETCH BINARY that does not implicitly set
  48.131 +         the \Seen flag.
  48.132 +
  48.133 +      BINARY.SIZE<section-binary>
  48.134 +
  48.135 +         Requests the decoded size of the section (i.e., the size to
  48.136 +         expect in response to the corresponding FETCH BINARY request).
  48.137 +
  48.138 +         Note: client authors are cautioned that this might be an
  48.139 +         expensive operation for some server implementations.
  48.140 +         Needlessly issuing this request could result in degraded
  48.141 +         performance due to servers having to calculate the value every
  48.142 +         time the request is issued.
  48.143 +
  48.144 +4.3.  FETCH Response Extensions
  48.145 +
  48.146 +   This extension defines two new FETCH response data items.
  48.147 +
  48.148 +      BINARY<section-binary>[<<number>>]
  48.149 +
  48.150 +         An <nstring> or <literal8> expressing the content of the
  48.151 +         specified section after removing any CTE-related encoding.  If
  48.152 +         <number> is present it refers to the offset within the DECODED
  48.153 +         section data.
  48.154 +
  48.155 +         If the domain of the decoded data is "8bit" and the data does
  48.156 +         not contain the NUL octet, the server SHOULD return the data in
  48.157 +         a <string> instead of a <literal8>; this allows the client to
  48.158 +         determine if the "8bit" data contains the NUL octet without
  48.159 +         having to explicitly scan the data stream for for NULs.
  48.160 +
  48.161 +         If the server does not know how to decode the section's CTE, it
  48.162 +         MUST fail the request and issue a "NO" response that contains
  48.163 +         the "UNKNOWN-CTE" extended response code.
  48.164 +
  48.165 +
  48.166 +
  48.167 +
  48.168 +
  48.169 +
  48.170 +
  48.171 +
  48.172 +
  48.173 +Nerenberg                   Standards Track                     [Page 3]
  48.174 +
  48.175 +RFC 3516             IMAP4 Binary Content Extension           April 2003
  48.176 +
  48.177 +
  48.178 +      BINARY.SIZE<section-binary>
  48.179 +
  48.180 +         The size of the section after removing any CTE-related
  48.181 +         encoding.  The value returned MUST match the size of the
  48.182 +         <nstring> or <literal8> that will be returned by the
  48.183 +         corresponding FETCH BINARY request.
  48.184 +
  48.185 +         If the server does not know how to decode the section's CTE, it
  48.186 +         MUST fail the request and issue a "NO" response that contains
  48.187 +         the "UNKNOWN-CTE" extended response code.
  48.188 +
  48.189 +4.4.  APPEND Command Extensions
  48.190 +
  48.191 +   The APPEND command is extended to allow the client to append data
  48.192 +   containing NULs by using the <literal8> syntax.  The server MAY
  48.193 +   modify the CTE of the appended data, however any such transformation
  48.194 +   MUST NOT result in a loss of data.
  48.195 +
  48.196 +   If the destination mailbox does not support the storage of binary
  48.197 +   content, the server MUST fail the request and issue a "NO" response
  48.198 +   that contains the "UNKNOWN-CTE" extended response code.
  48.199 +
  48.200 +5.  MIME Encoded Headers
  48.201 +
  48.202 +   [MIME-MHE] defines an encoding that allows for non-US-ASCII text in
  48.203 +   message headers.  This encoding is not the same as the content-
  48.204 +   transfer-encoding applied to message bodies, and the decoding
  48.205 +   transformations described in this memo do not apply to [MIME-MHE]
  48.206 +   encoded header text.  A server MUST NOT perform any conversion of
  48.207 +   [MIME-MHE] encoded header text in response to any binary FETCH or
  48.208 +   APPEND request.
  48.209 +
  48.210 +6.  Implementation Considerations
  48.211 +
  48.212 +   Messaging clients and servers have been notoriously lax in their
  48.213 +   adherence to the Internet CRLF convention for terminating lines of
  48.214 +   textual data in Internet protocols.  When sending data using the
  48.215 +   Binary extension, servers MUST ensure that textual line-oriented
  48.216 +   sections are always transmitted using the IMAP4 CRLF line termination
  48.217 +   syntax, regardless of the underlying storage representation of the
  48.218 +   data on the server.
  48.219 +
  48.220 +   A server may choose to store message body binary content in a non-
  48.221 +   encoded format.  Regardless of the internal storage representation
  48.222 +   used, the server MUST issue BODYSTRUCTURE responses that describe the
  48.223 +   message as though the binary-encoded sections are encoded in a CTE
  48.224 +
  48.225 +
  48.226 +
  48.227 +
  48.228 +
  48.229 +Nerenberg                   Standards Track                     [Page 4]
  48.230 +
  48.231 +RFC 3516             IMAP4 Binary Content Extension           April 2003
  48.232 +
  48.233 +
  48.234 +   acceptable to the IMAP4 base specification.  Furthermore, the results
  48.235 +   of a FETCH BODY MUST return the message body content in the format
  48.236 +   described by the corresponding FETCH BODYSTRUCTURE response.
  48.237 +
  48.238 +   While the server is allowed to modify the CTE of APPENDed <literal8>
  48.239 +   data, this should only be done when it is absolutely necessary.
  48.240 +   Gratuitous encoding changes will render useless most cryptographic
  48.241 +   operations that have been performed on the message.
  48.242 +
  48.243 +   This extension provides an optimization that is useful in certain
  48.244 +   specific situations.  It does not absolve clients from providing
  48.245 +   basic functionality (content transfer decoding) that should be
  48.246 +   available in all messaging clients.  Clients supporting this
  48.247 +   extension SHOULD be prepared to perform their own CTE decoding
  48.248 +   operations.
  48.249 +
  48.250 +7.  Formal Protocol Syntax
  48.251 +
  48.252 +   The following syntax specification uses the augmented Backus-Naur
  48.253 +   Form (ABNF) notation as used in [ABNF], and incorporates by reference
  48.254 +   the Core Rules defined in that document.
  48.255 +
  48.256 +   This syntax augments the grammar specified in [IMAP4rev1].
  48.257 +
  48.258 +   append         =/  "APPEND" SP mailbox [SP flag-list]
  48.259 +                      [SP date-time] SP literal8
  48.260 +
  48.261 +   fetch-att      =/  "BINARY" [".PEEK"] section-binary [partial]
  48.262 +                      / "BINARY.SIZE" section-binary
  48.263 +
  48.264 +   literal8       =   "~{" number "}" CRLF *OCTET
  48.265 +                      ; <number> represents the number of OCTETs
  48.266 +                      ; in the response string.
  48.267 +
  48.268 +   msg-att-static =/  "BINARY" section-binary SP (nstring / literal8)
  48.269 +                      / "BINARY.SIZE" section-binary SP number
  48.270 +
  48.271 +   partial        =   "<" number "." nz-number ">"
  48.272 +
  48.273 +   resp-text-code =/  "UNKNOWN-CTE"
  48.274 +
  48.275 +   section-binary =   "[" [section-part] "]"
  48.276 +
  48.277 +
  48.278 +
  48.279 +
  48.280 +
  48.281 +
  48.282 +
  48.283 +
  48.284 +
  48.285 +Nerenberg                   Standards Track                     [Page 5]
  48.286 +
  48.287 +RFC 3516             IMAP4 Binary Content Extension           April 2003
  48.288 +
  48.289 +
  48.290 +8.  Normative References
  48.291 +
  48.292 +   [ABNF]      Crocker, D., Editor, and P. Overell, "Augmented BNF for
  48.293 +               Syntax Specifications: ABNF", RFC 2234, November 1997.
  48.294 +
  48.295 +   [IMAP4rev1] Crispin, M., "Internet Message Access Protocol Version
  48.296 +               4rev1", RFC 3501, March 2003.
  48.297 +
  48.298 +   [KEYWORD]   Bradner, S., "Key words for use in RFCs to Indicate
  48.299 +               Requirement Levels", BCP 14, RFC 2119, March 1997.
  48.300 +
  48.301 +   [MIME-IMB]  Freed, N. and N. Borenstein, "Multipurpose Internet Mail
  48.302 +               Extensions (MIME) Part One: Format of Internet Message
  48.303 +               Bodies", RFC 2045, November 1996.
  48.304 +
  48.305 +   [MIME-MHE]  Moore, K., "MIME (Multipurpose Internet Mail Extensions)
  48.306 +               Part Three: Message Header Extensions for Non-ASCII
  48.307 +               Text", RFC 2047, November 1996.
  48.308 +
  48.309 +9.  Security Considerations
  48.310 +
  48.311 +   There are no known additional security issues with this extension
  48.312 +   beyond those described in the base protocol described in [IMAP4rev1].
  48.313 +
  48.314 +10.  Intellectual Property
  48.315 +
  48.316 +   The IETF takes no position regarding the validity or scope of any
  48.317 +   intellectual property or other rights that might be claimed to
  48.318 +   pertain to the implementation or use of the technology described in
  48.319 +   this document or the extent to which any license under such rights
  48.320 +   might or might not be available; neither does it represent that it
  48.321 +   has made any effort to identify any such rights.  Information on the
  48.322 +   IETF's procedures with respect to rights in standards-track and
  48.323 +   standards-related documentation can be found in BCP-11.  Copies of
  48.324 +   claims of rights made available for publication and any assurances of
  48.325 +   licenses to be made available, or the result of an attempt made to
  48.326 +   obtain a general license or permission for the use of such
  48.327 +   proprietary rights by implementors or users of this specification can
  48.328 +   be obtained from the IETF Secretariat.
  48.329 +
  48.330 +   The IETF invites any interested party to bring to its attention any
  48.331 +   copyrights, patents or patent applications, or other proprietary
  48.332 +   rights which may cover technology that may be required to practice
  48.333 +   this standard.  Please address the information to the IETF Executive
  48.334 +   Director.
  48.335 +
  48.336 +
  48.337 +
  48.338 +
  48.339 +
  48.340 +
  48.341 +Nerenberg                   Standards Track                     [Page 6]
  48.342 +
  48.343 +RFC 3516             IMAP4 Binary Content Extension           April 2003
  48.344 +
  48.345 +
  48.346 +11.  Author's Address
  48.347 +
  48.348 +   Lyndon Nerenberg
  48.349 +   Orthanc Systems
  48.350 +   1606 - 10770 Winterburn Road
  48.351 +   Edmonton, Alberta
  48.352 +   Canada  T5S 1T6
  48.353 +
  48.354 +   EMail: lyndon@orthanc.ab.ca
  48.355 +
  48.356 +
  48.357 +
  48.358 +
  48.359 +
  48.360 +
  48.361 +
  48.362 +
  48.363 +
  48.364 +
  48.365 +
  48.366 +
  48.367 +
  48.368 +
  48.369 +
  48.370 +
  48.371 +
  48.372 +
  48.373 +
  48.374 +
  48.375 +
  48.376 +
  48.377 +
  48.378 +
  48.379 +
  48.380 +
  48.381 +
  48.382 +
  48.383 +
  48.384 +
  48.385 +
  48.386 +
  48.387 +
  48.388 +
  48.389 +
  48.390 +
  48.391 +
  48.392 +
  48.393 +
  48.394 +
  48.395 +
  48.396 +
  48.397 +Nerenberg                   Standards Track                     [Page 7]
  48.398 +
  48.399 +RFC 3516             IMAP4 Binary Content Extension           April 2003
  48.400 +
  48.401 +
  48.402 +12.  Full Copyright Statement
  48.403 +
  48.404 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
  48.405 +
  48.406 +   This document and translations of it may be copied and furnished to
  48.407 +   others, and derivative works that comment on or otherwise explain it
  48.408 +   or assist in its implementation may be prepared, copied, published
  48.409 +   and distributed, in whole or in part, without restriction of any
  48.410 +   kind, provided that the above copyright notice and this paragraph are
  48.411 +   included on all such copies and derivative works.  However, this
  48.412 +   document itself may not be modified in any way, such as by removing
  48.413 +   the copyright notice or references to the Internet Society or other
  48.414 +   Internet organizations, except as needed for the purpose of
  48.415 +   developing Internet standards in which case the procedures for
  48.416 +   copyrights defined in the Internet Standards process must be
  48.417 +   followed, or as required to translate it into languages other than
  48.418 +   English.
  48.419 +
  48.420 +   The limited permissions granted above are perpetual and will not be
  48.421 +   revoked by the Internet Society or its successors or assigns.
  48.422 +
  48.423 +   This document and the information contained herein is provided on an
  48.424 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
  48.425 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
  48.426 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
  48.427 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
  48.428 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  48.429 +
  48.430 +Acknowledgement
  48.431 +
  48.432 +   Funding for the RFC Editor function is currently provided by the
  48.433 +   Internet Society.
  48.434 +
  48.435 +
  48.436 +
  48.437 +
  48.438 +
  48.439 +
  48.440 +
  48.441 +
  48.442 +
  48.443 +
  48.444 +
  48.445 +
  48.446 +
  48.447 +
  48.448 +
  48.449 +
  48.450 +
  48.451 +
  48.452 +
  48.453 +Nerenberg                   Standards Track                     [Page 8]
  48.454 +
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/docs/rfc/rfc3656.txt	Mon Sep 14 15:17:45 2009 +0900
    49.3 @@ -0,0 +1,1067 @@
    49.4 +
    49.5 +
    49.6 +
    49.7 +
    49.8 +
    49.9 +
   49.10 +Network Working Group                                      R. Siemborski
   49.11 +Request for Comments: 3656                    Carnegie Mellon University
   49.12 +Category: Experimental                                     December 2003
   49.13 +
   49.14 +
   49.15 +                     The Mailbox Update (MUPDATE)
   49.16 +                 Distributed Mailbox Database Protocol
   49.17 +
   49.18 +Status of this Memo
   49.19 +
   49.20 +   This memo defines an Experimental Protocol for the Internet
   49.21 +   community.  It does not specify an Internet standard of any kind.
   49.22 +   Discussion and suggestions for improvement are requested.
   49.23 +   Distribution of this memo is unlimited.
   49.24 +
   49.25 +Copyright Notice
   49.26 +
   49.27 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
   49.28 +
   49.29 +Abstract
   49.30 +
   49.31 +   As the demand for high-performance mail delivery agents increases, it
   49.32 +   becomes apparent that single-machine solutions are inadequate to the
   49.33 +   task, both because of capacity limits and that the failure of the
   49.34 +   single machine means a loss of mail delivery for all users.  It is
   49.35 +   preferable to allow many machines to share the responsibility of mail
   49.36 +   delivery.
   49.37 +
   49.38 +   The Mailbox Update (MUPDATE) protocol allows a group of Internet
   49.39 +   Message Access Protocol (IMAP) or Post Office Protocol - Version 3
   49.40 +   (POP3) servers to function with a unified mailbox namespace.  This
   49.41 +   document is intended to serve as a reference guide to that protocol.
   49.42 +
   49.43 +
   49.44 +
   49.45 +
   49.46 +
   49.47 +
   49.48 +
   49.49 +
   49.50 +
   49.51 +
   49.52 +
   49.53 +
   49.54 +
   49.55 +
   49.56 +
   49.57 +
   49.58 +
   49.59 +
   49.60 +
   49.61 +Siemborski                    Experimental                      [Page 1]
   49.62 +
   49.63 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
   49.64 +
   49.65 +
   49.66 +Table of Contents
   49.67 +
   49.68 +   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
   49.69 +   2.  Protocol Overview . . . . . . . . . . . . . . . . . . . . . .   3
   49.70 +       2.1.  Atoms . . . . . . . . . . . . . . . . . . . . . . . . .   4
   49.71 +       2.2.  Strings . . . . . . . . . . . . . . . . . . . . . . . .   4
   49.72 +   3.  Server Responses  . . . . . . . . . . . . . . . . . . . . . .   4
   49.73 +       3.1.  Response: OK  . . . . . . . . . . . . . . . . . . . . .   5
   49.74 +       3.2.  Response: NO  . . . . . . . . . . . . . . . . . . . . .   5
   49.75 +       3.3.  Response: BAD . . . . . . . . . . . . . . . . . . . . .   5
   49.76 +       3.4.  Response: BYE . . . . . . . . . . . . . . . . . . . . .   6
   49.77 +       3.5.  Response: RESERVE . . . . . . . . . . . . . . . . . . .   6
   49.78 +       3.6.  Response: MAILBOX . . . . . . . . . . . . . . . . . . .   6
   49.79 +       3.7.  Response: DELETE  . . . . . . . . . . . . . . . . . . .   7
   49.80 +       3.8.  Server Capability Response. . . . . . . . . . . . . . .   7
   49.81 +   4.  Client Commands . . . . . . . . . . . . . . . . . . . . . . .   8
   49.82 +       4.1.  Command: ACTIVATE . . . . . . . . . . . . . . . . . . .   8
   49.83 +       4.2.  Command: AUTHENTICATE . . . . . . . . . . . . . . . . .   8
   49.84 +       4.3.  Command: DEACTIVATE . . . . . . . . . . . . . . . . . .   9
   49.85 +       4.4.  Command: DELETE . . . . . . . . . . . . . . . . . . . .   9
   49.86 +       4.5.  Command: FIND . . . . . . . . . . . . . . . . . . . . .   9
   49.87 +       4.6.  Command: LIST . . . . . . . . . . . . . . . . . . . . .  10
   49.88 +       4.7.  Command: LOGOUT . . . . . . . . . . . . . . . . . . . .  10
   49.89 +       4.8.  Command: NOOP . . . . . . . . . . . . . . . . . . . . .  10
   49.90 +       4.9.  Command: RESERVE. . . . . . . . . . . . . . . . . . . .  10
   49.91 +       4.10. Command: STARTTLS . . . . . . . . . . . . . . . . . . .  11
   49.92 +       4.11. Command: UPDATE . . . . . . . . . . . . . . . . . . . .  12
   49.93 +   5.  MUPDATE Formal Syntax . . . . . . . . . . . . . . . . . . . .  12
   49.94 +   6.  MUPDATE URL Scheme. . . . . . . . . . . . . . . . . . . . . .  14
   49.95 +       6.1.  MUPDATE URL Scheme Registration Form. . . . . . . . . .  14
   49.96 +   7.  Security Considerations . . . . . . . . . . . . . . . . . . .  15
   49.97 +   8.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  16
   49.98 +   9.  Intellectual Property Rights. . . . . . . . . . . . . . . . .  16
   49.99 +   10. References. . . . . . . . . . . . . . . . . . . . . . . . . .  17
  49.100 +       10.1. Normative References. . . . . . . . . . . . . . . . . .  17
  49.101 +       10.2. Informative References. . . . . . . . . . . . . . . . .  17
  49.102 +   11. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . .  18
  49.103 +   12. Author's Address. . . . . . . . . . . . . . . . . . . . . . .  18
  49.104 +   13. Full Copyright Statement. . . . . . . . . . . . . . . . . . .  19
  49.105 +
  49.106 +
  49.107 +
  49.108 +
  49.109 +
  49.110 +
  49.111 +
  49.112 +
  49.113 +
  49.114 +
  49.115 +
  49.116 +
  49.117 +Siemborski                    Experimental                      [Page 2]
  49.118 +
  49.119 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.120 +
  49.121 +
  49.122 +1.  Introduction
  49.123 +
  49.124 +   In order to support an architecture where there are multiple [IMAP,
  49.125 +   POP3] servers sharing a common mailbox database, it is necessary to
  49.126 +   be able to provide atomic mailbox operations, as well as offer
  49.127 +   sufficient guarantees about database consistency.
  49.128 +
  49.129 +   The primary goal of the MUPDATE protocol is to be simple to implement
  49.130 +   yet allow for database consistency between participants.
  49.131 +
  49.132 +   The key words "MUST, "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
  49.133 +   "RECOMMENDED", and "MAY" in this document are to be interpreted as
  49.134 +   defined in BCP 14, RFC 2119 [KEYWORDS].
  49.135 +
  49.136 +   In examples, "C:" and "S:" indicate lines sent by the client and
  49.137 +   server respectively.
  49.138 +
  49.139 +2.  Protocol Overview
  49.140 +
  49.141 +   The MUPDATE protocol assumes a reliable data stream such as a TCP
  49.142 +   network connection.  IANA has registered port 3905 with a short name
  49.143 +   of "mupdate" for this purpose.
  49.144 +
  49.145 +   In the current implementation of the MUPDATE protocol there are three
  49.146 +   types of participants: a single master server, slave (or replica)
  49.147 +   servers, and clients.  The master server maintains an authoritative
  49.148 +   copy of the mailbox database.  Slave servers connect to the MUPDATE
  49.149 +   master server as clients, and function as replicas from the point of
  49.150 +   view of end clients.  End clients may connect to either the master or
  49.151 +   any slave and perform searches against the database, however
  49.152 +   operations that change the database can only be performed against the
  49.153 +   master.  For the purposes of protocol discussion we will consider a
  49.154 +   slave's connection to the master identical to that of any other
  49.155 +   client.
  49.156 +
  49.157 +   After connection, all commands from a client to server must have an
  49.158 +   associated unique tag which is an alphanumeric string.  Commands MAY
  49.159 +   be pipelined from the client to the server (that is, the client need
  49.160 +   not wait for the response before sending the next command).  The
  49.161 +   server MUST execute the commands in the order they were received,
  49.162 +   however.
  49.163 +
  49.164 +   If the server supports an inactivity login timeout, it MUST be at
  49.165 +   least 15 minutes.
  49.166 +
  49.167 +
  49.168 +
  49.169 +
  49.170 +
  49.171 +
  49.172 +
  49.173 +Siemborski                    Experimental                      [Page 3]
  49.174 +
  49.175 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.176 +
  49.177 +
  49.178 +   MUPDATE uses data formats similar to those used in [ACAP].  That is,
  49.179 +   atoms and strings.  All commands and tags in the protocol are
  49.180 +   transmitted as atoms.  All other data is considered to a string, and
  49.181 +   must be quoted or transmitted as a literal.
  49.182 +
  49.183 +   Outside of a literal, both clients and servers MUST support line
  49.184 +   lengths of at least 1024 octets (including the trailing CR and LF
  49.185 +   characters).  If a line of a longer length must be transmitted,
  49.186 +   implementations MUST make use of literals to do so.
  49.187 +
  49.188 +2.1.  Atoms
  49.189 +
  49.190 +   An atom consists of one or more alphanumeric characters.  Atoms MUST
  49.191 +   be less than 15 octets in length.
  49.192 +
  49.193 +2.2.  Strings
  49.194 +
  49.195 +   As in [ACAP], a string may be either literal or a quoted string.  A
  49.196 +   literal is a sequence of zero or more octets (including CR and LF),
  49.197 +   prefix-quoted with an octet count in the form of an open brace ("{"),
  49.198 +   the number of octets, an optional plus sign to indicate that the data
  49.199 +   follows immediately (a non-synchronized literal), a close brace
  49.200 +   ("}"), and a CRLF sequence.  If the plus sign is omitted (a
  49.201 +   synchronized literal), then the receiving side MUST send a "+ go
  49.202 +   ahead" response, and the sending side MUST wait for this response.
  49.203 +   Servers MUST support literals of atleast 4096 octets.
  49.204 +
  49.205 +   Strings that are sent from server to client SHOULD NOT be in the
  49.206 +   synchronized literal format.
  49.207 +
  49.208 +   A quoted string is a sequence of zero or more 7-bit characters,
  49.209 +   excluding CR, LF, and the double quote (<">), with double quote
  49.210 +   characters at each end.
  49.211 +
  49.212 +   The empty string is represented as either "" (a quoted string with
  49.213 +   zero characters between double quotes) or as {0} followed by CRLF (a
  49.214 +   literal with an octet count of 0).
  49.215 +
  49.216 +3.  Server Responses
  49.217 +
  49.218 +   Every client command in the MUPDATE protocol may receive one or more
  49.219 +   tagged responses from the server.  Each response is preceded by the
  49.220 +   same tag as the command that elicited the response from the server.
  49.221 +
  49.222 +
  49.223 +
  49.224 +
  49.225 +
  49.226 +
  49.227 +
  49.228 +
  49.229 +Siemborski                    Experimental                      [Page 4]
  49.230 +
  49.231 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.232 +
  49.233 +
  49.234 +3.1.  Response: OK
  49.235 +
  49.236 +   A tagged OK response indicates that the operation completed
  49.237 +   successfully.  There is a mandatory implementation-defined string
  49.238 +   after the OK response.  This response also indicates the beginning of
  49.239 +   the streaming update mode when given in response to an UPDATE
  49.240 +   command.
  49.241 +
  49.242 +   Example:
  49.243 +
  49.244 +C: N01 NOOP
  49.245 +S: N01 OK "NOOP Complete"
  49.246 +
  49.247 +3.2.  Response: NO
  49.248 +
  49.249 +   A tagged NO response indicates that the operation was explicitly
  49.250 +   denied by the server or otherwise failed.  There is a mandatory
  49.251 +   implementation-defined string after the NO response that SHOULD
  49.252 +   explain the reason for denial.
  49.253 +
  49.254 +   Example:
  49.255 +
  49.256 +C: A01 AUTHENTICATE "PLAIN"
  49.257 +S: A01 NO "PLAIN is not a supported SASL mechanism"
  49.258 +
  49.259 +3.3.  Response: BAD
  49.260 +
  49.261 +   A tagged BAD response indicates that the command from the client
  49.262 +   could not be parsed or understood.  There is a mandatory
  49.263 +   implementation-defined string after the BAD response to provide
  49.264 +   additional information about the error.  Note that untagged BAD
  49.265 +   responses are allowed if it is unclear what the tag for a given
  49.266 +   command is (for example, if a blank line is received by the mupdate
  49.267 +   server, it can generate an untagged BAD response).  In the case of an
  49.268 +   untagged response, the tag should be replaced with a "*".
  49.269 +
  49.270 +   Example:
  49.271 +
  49.272 +C: C01 SELECT "INBOX"
  49.273 +S: C01 BAD "This is not an IMAP server"
  49.274 +C:
  49.275 +S: * BAD "Need Command"
  49.276 +
  49.277 +
  49.278 +
  49.279 +
  49.280 +
  49.281 +
  49.282 +
  49.283 +
  49.284 +
  49.285 +Siemborski                    Experimental                      [Page 5]
  49.286 +
  49.287 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.288 +
  49.289 +
  49.290 +3.4.  Response: BYE
  49.291 +
  49.292 +   A tagged BYE response indicates that the server has decided to close
  49.293 +   the connection.  There is a mandatory implementation-defined string
  49.294 +   after the BYE response that SHOULD explain the reason for closing the
  49.295 +   connection.  The server MUST close the connection immediately after
  49.296 +   transmitting the BYE response.
  49.297 +
  49.298 +   Example:
  49.299 +
  49.300 +C: L01 LOGOUT
  49.301 +S: L01 BYE "User Logged Out"
  49.302 +
  49.303 +3.5.  Response: RESERVE
  49.304 +
  49.305 +   A tagged RESERVE response may only be given in response to a FIND,
  49.306 +   LIST, or UPDATE command.  It includes two parameters: the name of the
  49.307 +   mailbox that is being reserved (in mUTF-7 encoding, as specified in
  49.308 +   [IMAP]) and a location string whose contents is defined by the
  49.309 +   clients that are using the database, though it is RECOMMENDED that
  49.310 +   the format of this string be the hostname of the server which is
  49.311 +   storing the mailbox.
  49.312 +
  49.313 +   This response indicates that the given name is no longer available in
  49.314 +   the namespace, though it does not indicate that the given mailbox is
  49.315 +   available to clients at the current time.
  49.316 +
  49.317 +   Example:
  49.318 +
  49.319 +S: U01 RESERVE "internet.bugtraq" "mail2.example.org"
  49.320 +
  49.321 +3.6.  Response: MAILBOX
  49.322 +
  49.323 +   A tagged MAILBOX response may only be given in response to a FIND,
  49.324 +   LIST, or UPDATE command.  It includes three parameters: the name of
  49.325 +   the mailbox, a location string (as with RESERVE), and a client-
  49.326 +   defined string that specifies the IMAP ACL [IMAP-ACL] of the mailbox.
  49.327 +   This message indicates that the given mailbox is ready to be accessed
  49.328 +   by clients.
  49.329 +
  49.330 +   Example:
  49.331 +
  49.332 +S: U01 MAILBOX "internet.bugtraq" "mail2.example.org" "anyone rls"
  49.333 +
  49.334 +
  49.335 +
  49.336 +
  49.337 +
  49.338 +
  49.339 +
  49.340 +
  49.341 +Siemborski                    Experimental                      [Page 6]
  49.342 +
  49.343 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.344 +
  49.345 +
  49.346 +3.7.  Response: DELETE
  49.347 +
  49.348 +   A tagged DELETE response may only be given in response to an UPDATE
  49.349 +   command, and MUST NOT be given before the OK response to the UPDATE
  49.350 +   command is given.  It contains a single parameter, that of the
  49.351 +   mailbox that should be deleted from the slave's database.  This
  49.352 +   response indicates that the given mailbox no longer exists in the
  49.353 +   namespace of the database, and may be given for any mailbox name,
  49.354 +   active, reserved, or nonexistent.  (Though implementations SHOULD NOT
  49.355 +   issue DELETE responses for nonexistent mailboxes).
  49.356 +
  49.357 +   Example:
  49.358 +
  49.359 +S: U01 DELETE "user.rjs3.sent-mail-jan-2002"
  49.360 +
  49.361 +3.8.  Server Capability Response
  49.362 +
  49.363 +   Upon connection of the client to the server, and directly following a
  49.364 +   successful STARTTLS command, the server MUST issue a capabilities
  49.365 +   banner, of the following format:
  49.366 +
  49.367 +   The banner MUST contain a line that begins with "* AUTH" and contain
  49.368 +   a space-separated list of SASL mechanisms that the server will accept
  49.369 +   for authentication.  The mechanism names are transmitted as atoms.
  49.370 +   Servers MAY advertise no available mechanisms (to indicate that
  49.371 +   STARTTLS must be completed before authentication may occur).  If
  49.372 +   STARTTLS is not supported by the server, then the line MUST contain
  49.373 +   at least one mechanism.
  49.374 +
  49.375 +   If the banner is being issued without a TLS layer, and the server
  49.376 +   supports the STARTTLS command, the banner MUST contain the line "*
  49.377 +   STARTTLS".  If the banner is being issued under a TLS layer (or the
  49.378 +   server does not support STARTTLS), the banner MUST NOT contain this
  49.379 +   line.
  49.380 +
  49.381 +   The last line of the banner MUST start with "* OK MUPDATE" and be
  49.382 +   followed by four strings: the server's hostname, an implementation-
  49.383 +   defined string giving the name of the implementation, an
  49.384 +   implementation-defined string giving the version of the
  49.385 +   implementation, and a string that indicates if the server is a master
  49.386 +   or a slave.  The master/slave indication MUST be either "(master)" or
  49.387 +   an MUPDATE URL that defines where the master can be contacted.
  49.388 +
  49.389 +   Any unrecognized responses before the "* OK MUPDATE" response MUST be
  49.390 +   ignored by the client.
  49.391 +
  49.392 +
  49.393 +
  49.394 +
  49.395 +
  49.396 +
  49.397 +Siemborski                    Experimental                      [Page 7]
  49.398 +
  49.399 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.400 +
  49.401 +
  49.402 +   Example:
  49.403 +
  49.404 +S: * AUTH KERBEROS_V4 GSSAPI
  49.405 +S: * STARTTLS
  49.406 +S: * OK MUPDATE "mupdate.example.org" "Cyrus" "v2.1.2" "(master)"
  49.407 +
  49.408 +4.  Client Commands
  49.409 +
  49.410 +   The following are valid commands that a client may send to the
  49.411 +   MUPDATE server: AUTHENTICATE, ACTIVATE, DEACTIVATE, DELETE, FIND,
  49.412 +   LIST, LOGOUT, NOOP, RESERVE, STARTTLS, and UPDATE.
  49.413 +
  49.414 +   Before a successful AUTHENTICATE command has occurred, the server
  49.415 +   MUST NOT accept any commands except for AUTHENTICATE, STARTTLS, and
  49.416 +   LOGOUT (and SHOULD reply with a NO response for all other commands).
  49.417 +
  49.418 +4.1.  Command: ACTIVATE
  49.419 +
  49.420 +   The ACTIVATE command has 3 parameters: the mailbox name, its
  49.421 +   location, and its ACL.  This command MUST NOT not be issued to a
  49.422 +   slave server.
  49.423 +
  49.424 +   This command can also be used to update the ACL or location
  49.425 +   information of a mailbox.  Note that it is not a requirement for a
  49.426 +   mailbox to be reserved (or even exist in the database) for an
  49.427 +   ACTIVATE command to succeed, implementations MUST allow this behavior
  49.428 +   as it facilitates synchronization of the database with the current
  49.429 +   state of the mailboxes.
  49.430 +
  49.431 +4.2.  Command: AUTHENTICATE
  49.432 +
  49.433 +   The AUTHENTICATE command initiates a [SASL] negotiation session
  49.434 +   between the client and the server.  It has two parameters.  The first
  49.435 +   parameter is mandatory, and is a string indicating the desired [SASL]
  49.436 +   mechanism.  The second is a string containing an optional BASE64
  49.437 +   encoded (as defined in section 6.8 of [MIME]) client first send.
  49.438 +
  49.439 +   All of the remaining SASL blobs that are sent MUST be sent across the
  49.440 +   wire must be in BASE64 encoded format, and followed by a CR and LF
  49.441 +   combination.  They MUST NOT be encoded as strings.
  49.442 +
  49.443 +   Clients may cancel authentication by sending a * followed by a CR and
  49.444 +   LF.
  49.445 +
  49.446 +   The [SASL] service name for the MUPDATE protocol is "mupdate".
  49.447 +   Implementations are REQUIRED to implement the GSSAPI [SASL]
  49.448 +   mechanism, though they SHOULD implement as many mechanisms as
  49.449 +   possible.
  49.450 +
  49.451 +
  49.452 +
  49.453 +Siemborski                    Experimental                      [Page 8]
  49.454 +
  49.455 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.456 +
  49.457 +
  49.458 +   If a security layer is negotiated, it should be used directly
  49.459 +   following the CR and LF combination at the end of the server's OK
  49.460 +   response (i.e., beginning with the client's next command) Only one
  49.461 +   successful AUTHENTICATE command may be issued per session.
  49.462 +
  49.463 +4.3.  Command: DEACTIVATE
  49.464 +
  49.465 +   The DEACTIVATE command takes two parameters, the mailbox name and
  49.466 +   location data.  The mailbox MUST already exist and be activated on
  49.467 +   the MUPDATE server.  If the server responds OK, then the mailbox name
  49.468 +   has been moved to the RESERVE state.  If the server responds NO, then
  49.469 +   the mailbox name has not been moved (for example, the mailbox was not
  49.470 +   already active).  Any ACL information that is known about the mailbox
  49.471 +   MAY be lost when a DEACTIVATE succeeds.  This command MUST NOT be
  49.472 +   issued to a slave.
  49.473 +
  49.474 +   Example:
  49.475 +
  49.476 +C: A01 DEACTIVATE "user.rjs3.new" "mail3.example.org!u4"
  49.477 +S: A01 OK "Mailbox Reserved."
  49.478 +
  49.479 +4.4.  Command: DELETE
  49.480 +
  49.481 +   The DELETE command takes only a single parameter, the mailbox name to
  49.482 +   be removed from the database's namespace.  The server SHOULD give a
  49.483 +   NO response if the mailbox does not exist.  This command MUST NOT be
  49.484 +   issued to a slave server.
  49.485 +
  49.486 +4.5.  Command: FIND
  49.487 +
  49.488 +   The FIND command takes a single parameter, a mailbox name.  The
  49.489 +   server then responds with the current record for the given mailbox,
  49.490 +   if any, and an OK response.
  49.491 +
  49.492 +   Example (mailbox does not exist):
  49.493 +
  49.494 +C: F01 FIND "user.rjs3.xyzzy"
  49.495 +S: F01 OK "Search Complete"
  49.496 +
  49.497 +   Example (mailbox is reserved):
  49.498 +
  49.499 +C: F01 FIND "user.rjs3"
  49.500 +S: F01 RESERVE "user.rjs3" "mail4.example.org"
  49.501 +S: F01 OK "Search Complete"
  49.502 +
  49.503 +
  49.504 +
  49.505 +
  49.506 +
  49.507 +
  49.508 +
  49.509 +Siemborski                    Experimental                      [Page 9]
  49.510 +
  49.511 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.512 +
  49.513 +
  49.514 +4.6.  Command: LIST
  49.515 +
  49.516 +   The LIST command is similar to running FIND across the entire
  49.517 +   database.  The LIST command takes a single optional parameter, which
  49.518 +   is a prefix to try to match against the location field of the
  49.519 +   records.  Without the parameter, LIST returns every record in the
  49.520 +   database.
  49.521 +
  49.522 +   For each mailbox that matches, either a MAILBOX or a RESERVE response
  49.523 +   (as applicable) is sent to the client.  When all responses are
  49.524 +   complete, an OK response is issued.
  49.525 +
  49.526 +   Example:
  49.527 +
  49.528 +C: L01 LIST
  49.529 +S: L01 RESERVE "user.rjs3" "mail4.example.org!u2"
  49.530 +S: L01 MAILBOX "user.leg" "mail2.example.org!u1" "leg lrswipcda"
  49.531 +S: L01 OK "List Complete"
  49.532 +C: L02 LIST "mail4.example.org!"
  49.533 +S: L02 RESERVE "user.rjs3" "mail4.example.org!u2"
  49.534 +S: L02 OK "List Complete"
  49.535 +
  49.536 +4.7.  Command: LOGOUT
  49.537 +
  49.538 +   The LOGOUT command tells the server to close the connection.  Its
  49.539 +   only valid response is the BYE response.  The LOGOUT command takes no
  49.540 +   parameters.
  49.541 +
  49.542 +4.8.  Command: NOOP
  49.543 +
  49.544 +   The NOOP command takes no parameters.  Provided the client is
  49.545 +   authenticated, its only acceptable response is an OK.  Any idle
  49.546 +   timeouts that the server may have on the connection SHOULD be reset
  49.547 +   upon receipt of this command.
  49.548 +
  49.549 +   If this command is issued after an UPDATE command has been issued,
  49.550 +   then the OK response also indicates that all pending database updates
  49.551 +   have been sent to the client.  That is, the slave can guarantee that
  49.552 +   its local database is up to date as of a certain time by issuing a
  49.553 +   NOOP and waiting for the OK.  The OK MUST NOT return until all
  49.554 +   updates that were pending at the time of the NOOP have been sent.
  49.555 +
  49.556 +4.9.  Command: RESERVE
  49.557 +
  49.558 +   The RESERVE command takes two parameters (just like the RESERVE
  49.559 +   response), the mailbox name to reserve and location data.  If the
  49.560 +   server responds OK, then the mailbox name has been reserved.  If the
  49.561 +   server responds NO, then the mailbox name has not been reserved (for
  49.562 +
  49.563 +
  49.564 +
  49.565 +Siemborski                    Experimental                     [Page 10]
  49.566 +
  49.567 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.568 +
  49.569 +
  49.570 +   example, another server has reserved it already).  This command MUST
  49.571 +   NOT be issued to a slave.
  49.572 +
  49.573 +   The typical sequence for mailbox creation is:
  49.574 +
  49.575 +C: R01 RESERVE "user.rjs3.new" "mail3.example.org!u4"
  49.576 +S: R01 OK "Mailbox Reserved."
  49.577 +<client does local mailbox create operations>
  49.578 +C: A01 ACTIVATE "user.rjs3.new" "mail3.example.org!u4" "rjs3 lrswipcda"
  49.579 +S: A01 OK "Mailbox Activated."
  49.580 +
  49.581 +4.10.  Command: STARTTLS
  49.582 +
  49.583 +   The STARTTLS command requests the commencement of a [TLS]
  49.584 +   negotiation.  The negotiation begins immediately after the CRLF in
  49.585 +   the OK response.  After a client issues a STARTTLS command, it MUST
  49.586 +   NOT issue further commands until a server response is seen and the
  49.587 +   [TLS] negotiation is complete.
  49.588 +
  49.589 +   The STARTTLS command is only valid in non-authenticated state.  The
  49.590 +   server remains in non-authenticated state, even if client credentials
  49.591 +   are supplied during the [TLS] negotiation.  The [SASL] EXTERNAL
  49.592 +   mechanism MAY be used to authenticate once [TLS] client credentials
  49.593 +   are successfully exchanged.  Note that servers are not required to
  49.594 +   support the EXTERNAL mechanism.
  49.595 +
  49.596 +   After the [TLS] layer is established, the server MUST re-issue the
  49.597 +   initial response banner (see Section 3.8).  This is necessary to
  49.598 +   protect against man-in-the-middle attacks which alter the
  49.599 +   capabilities list prior to STARTTLS, as well as to advertise any new
  49.600 +   SASL mechanisms (or other capabilities) that may be available under
  49.601 +   the layer.  The client MUST discard cached capability information and
  49.602 +   replace it with the new information.
  49.603 +
  49.604 +   After the a successful STARTTLS command, the server SHOULD return a
  49.605 +   NO response to additional STARTTLS commands.
  49.606 +
  49.607 +   Servers MAY choose to not implement STARTTLS.  In this case, they
  49.608 +   MUST NOT advertise STARTTLS in their capabilities banner, and SHOULD
  49.609 +   return a BAD response to the STARTTLS command, if it is issued.
  49.610 +
  49.611 +   Example:
  49.612 +
  49.613 +C: S01 STARTTLS
  49.614 +S: S01 OK "Begin TLS negotiation now"
  49.615 +<TLS negotiation, further commands are under TLS layer>
  49.616 +S: * AUTH KERBEROS_V4 GSSAPI PLAIN
  49.617 +S: * OK MUPDATE "mupdate.example.org" "Cyrus" "v2.1.2" "(master)"
  49.618 +
  49.619 +
  49.620 +
  49.621 +Siemborski                    Experimental                     [Page 11]
  49.622 +
  49.623 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.624 +
  49.625 +
  49.626 +4.11.  Command: UPDATE
  49.627 +
  49.628 +   The UPDATE command is how a slave initializes an update stream from
  49.629 +   the master (though it is also valid to issue this command to a
  49.630 +   slave).  In response to the command, the server returns a list of all
  49.631 +   mailboxes in its database (the same results as a parameterless LIST
  49.632 +   command) followed by an OK response.  From this point forward,
  49.633 +   whenever an update occurs to the master database, it MUST stream the
  49.634 +   update to the slave within 30 seconds.  That is, it will send
  49.635 +   RESERVE, MAILBOX, or DELETE responses as they are applicable.
  49.636 +
  49.637 +   After a client has issued an UPDATE command, it may only issue NOOP
  49.638 +   and LOGOUT commands for the remainder of the session.
  49.639 +
  49.640 +   Example:
  49.641 +
  49.642 +C: U01 UPDATE
  49.643 +S: U01 MAILBOX "user.leg" "mail2.example.org!u1" "leg lrswipcda"
  49.644 +S: U01 MAILBOX "user.rjs3" "mail3.example.org!u4" "rjs3 lrswipcda"
  49.645 +S: U01 RESERVE "internet.bugtraq" "mail1.example.org!u5" "anyone lrs"
  49.646 +S: U01 OK "Streaming Begins"
  49.647 +<some time goes by, and another client creates a new mailbox>
  49.648 +S: U01 RESERVE "user.leg.new" "mail2.example.org!u1"
  49.649 +<some more time passes, and the create succeeds>
  49.650 +S: U01 MAILBOX "user.leg.new" "mail2.example.org!u1" "leg lrswipcda"
  49.651 +<much more time passes, and the slave decides to send a NOOP to reset
  49.652 +its inactivity timer>
  49.653 +C: N01 NOOP
  49.654 +S: U01 DELETE "user.leg.new"
  49.655 +S: N01 OK "NOOP Complete"
  49.656 +
  49.657 +5.  MUPDATE Formal Syntax
  49.658 +
  49.659 +   The following syntax specification uses the Augmented Backus-Naur
  49.660 +   Form (ABNF) notation as specified in [ABNF].  This uses the ABNF core
  49.661 +   rules as specified in Appendix A of [ABNF].
  49.662 +
  49.663 +   Except as noted otherwise, all alphabetic characters are case-
  49.664 +   insensitive.  The use of upper or lower case characters to define
  49.665 +   token strings is for editorial clarity only.  Implementations MUST
  49.666 +   accept these strings in a case-insensitive fashion.
  49.667 +
  49.668 +   Note that this specification also uses some terminals from section 8
  49.669 +   of [ACAP].
  49.670 +
  49.671 +   cmd-activate = "ACTIVATE" SP string SP string SP string
  49.672 +
  49.673 +   cmd-authenticate = "AUTHENTICATE" SP sasl-mech [ SP string ]
  49.674 +
  49.675 +
  49.676 +
  49.677 +Siemborski                    Experimental                     [Page 12]
  49.678 +
  49.679 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.680 +
  49.681 +
  49.682 +   cmd-delete = "DELETE" SP string
  49.683 +
  49.684 +   cmd-find = "FIND" SP string
  49.685 +
  49.686 +   cmd-list = "LIST" [ SP string ]
  49.687 +
  49.688 +   cmd-logout = "LOGOUT"
  49.689 +
  49.690 +   cmd-noop = "NOOP"
  49.691 +
  49.692 +   cmd-reserve = "RESERVE" SP string SP string
  49.693 +
  49.694 +   cmd-starttls = "STARTTLS"
  49.695 +
  49.696 +   cmd-update = "UPDATE"
  49.697 +
  49.698 +   command = tag SP command-type CRLF
  49.699 +
  49.700 +   command-type = cmd-activate / cmd-authenticate / cmd-delete /
  49.701 +                  cmd-find / cmd-list / cmd-logout / cmd-noop /
  49.702 +                  cmd-reserve / cmd-starttls / cmd-update
  49.703 +
  49.704 +   response = tag SP response-type CRLF
  49.705 +
  49.706 +   response-type = rsp-ok / rsp-no / rsp-bad / rsp-bye / rsp-mailbox /
  49.707 +                   rsp-reserve / rsp-delete
  49.708 +
  49.709 +   rsp-bad = "BAD" SP string
  49.710 +
  49.711 +   rsp-bye = "BYE" SP string
  49.712 +
  49.713 +   rsp-mailbox = "MAILBOX" SP string SP string SP string
  49.714 +
  49.715 +   rsp-no = "NO" SP string
  49.716 +
  49.717 +   rsp-ok = "OK" SP string
  49.718 +
  49.719 +   rsp-reserve = "RESERVE" SP string SP string
  49.720 +
  49.721 +   rsp-delete = "DELETE" SP string
  49.722 +
  49.723 +   sasl-mech = 1*ATOM-CHAR
  49.724 +      ; ATOM-CHAR is defined in [ACAP]
  49.725 +
  49.726 +   string = quoted / literal
  49.727 +      ; quoted and literal are defined in [ACAP]
  49.728 +
  49.729 +
  49.730 +
  49.731 +
  49.732 +
  49.733 +Siemborski                    Experimental                     [Page 13]
  49.734 +
  49.735 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.736 +
  49.737 +
  49.738 +   tag = 1*ATOM-CHAR
  49.739 +      ; ATOM-CHAR is defined in [ACAP]
  49.740 +
  49.741 +6.  MUPDATE URL Scheme
  49.742 +
  49.743 +   This document defines the a URL scheme for the purposes of
  49.744 +   referencing MUPDATE resources, according to the requirements in
  49.745 +   [RFC2717].  This includes both MUPDATE servers as a whole, along with
  49.746 +   individual mailbox entries on a given MUPDATE server.
  49.747 +
  49.748 +   There is no MIME type associated with these resources.  It is
  49.749 +   intended that a URL consumer would either retrieve the MUPDATE record
  49.750 +   in question, or simply connect to the MUPDATE server running on the
  49.751 +   specified host.  Note that the consumer will need to have
  49.752 +   authentication credentials for the specified host.
  49.753 +
  49.754 +   The MUPDATE URL scheme is similar to the IMAP URL scheme [IMAP-URL].
  49.755 +   However, it only takes one of two possible forms:
  49.756 +
  49.757 +      mupdate://<iserver>/
  49.758 +      mupdate://<iserver>/<mailbox>
  49.759 +
  49.760 +   The first form refers to a MUPDATE server as a whole, the second form
  49.761 +   indicates both the server and a mailbox to run a FIND against once
  49.762 +   authenticated to the server.  Note that part of <iserver> may include
  49.763 +   username and authentication information along with a hostname and
  49.764 +   port.
  49.765 +
  49.766 +6.1.  MUPDATE URL Scheme Registration Form
  49.767 +
  49.768 +   URL scheme name: "mupdate"
  49.769 +
  49.770 +   URL scheme syntax:
  49.771 +
  49.772 +      This defines the MUPDATE URL Scheme in [ABNF].  Terminals from the
  49.773 +      BNF of IMAP URLs [IMAP-URL] are also used.
  49.774 +
  49.775 +         mupdateurl = "mupdate://" iserver "/" [ enc_mailbox ]
  49.776 +            ; iserver and enc_mailbox are as defined in [IMAP-URL]
  49.777 +
  49.778 +   Character encoding considerations:
  49.779 +
  49.780 +      Identical to those described in [IMAP-URL] for the appropriate
  49.781 +      terminals.
  49.782 +
  49.783 +
  49.784 +
  49.785 +
  49.786 +
  49.787 +
  49.788 +
  49.789 +Siemborski                    Experimental                     [Page 14]
  49.790 +
  49.791 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.792 +
  49.793 +
  49.794 +   Intended Usage:
  49.795 +
  49.796 +      The form of the URL without an associated mailbox is intended to
  49.797 +      designate a MUPDATE server only.  If a mailbox name is included in
  49.798 +      the URL, then the consumer is expected to execute a FIND command
  49.799 +      for that mailbox on the specified server.
  49.800 +
  49.801 +   Applications and/or protocols which use this URL scheme name:
  49.802 +
  49.803 +      The protocol described in this document.
  49.804 +
  49.805 +   Interoperability Considerations:
  49.806 +
  49.807 +      None.
  49.808 +
  49.809 +   Security Considerations:
  49.810 +
  49.811 +      Users of the MUPDATE URL Scheme should review the security
  49.812 +      considerations that are discussed in [IMAP-URL].  In particular,
  49.813 +      the consequences of including authentication mechanism information
  49.814 +      in a URL should be reviewed.
  49.815 +
  49.816 +   Relevant Publications:
  49.817 +
  49.818 +      This document and [IMAP-URL].
  49.819 +
  49.820 +   Author, Change Controller, and Contact for Further Information:
  49.821 +
  49.822 +      Author of this document.
  49.823 +
  49.824 +7.  Security Considerations
  49.825 +
  49.826 +   While no unauthenticated users may make modifications or even perform
  49.827 +   searches on the database, it is important to note that this
  49.828 +   specification assumes no protections of any type for authenticated
  49.829 +   users.
  49.830 +
  49.831 +   All authenticated users have complete access to the database.  For
  49.832 +   this reason it is important to ensure that accounts that are making
  49.833 +   use of the database are well secured.
  49.834 +
  49.835 +   A more secure deployment might have all read only access go through a
  49.836 +   slave, and only have accounts which need write access use the master.
  49.837 +   This has the disadvantage of a marginally longer time for updates to
  49.838 +   reach the clients.
  49.839 +
  49.840 +
  49.841 +
  49.842 +
  49.843 +
  49.844 +
  49.845 +Siemborski                    Experimental                     [Page 15]
  49.846 +
  49.847 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.848 +
  49.849 +
  49.850 +   The protocol assumes that all authenticated users are cooperating to
  49.851 +   maintain atomic operations.  Therefore, all new mailboxes SHOULD be
  49.852 +   RESERVEd before they are ACTIVATEd, despite the fact that the
  49.853 +   protocol does not require this, and it is therefore possible for a
  49.854 +   set of participants which do not obey the provided locking to create
  49.855 +   an inconsistent database.  RESERVEing the mailbox first is not
  49.856 +   required to perform an activate because this behavior simplifies
  49.857 +   synchronization with the actual location of the mailboxes.
  49.858 +
  49.859 +8.  IANA Considerations
  49.860 +
  49.861 +   The IANA has assigned TCP port number 3905 to "mupdate".
  49.862 +
  49.863 +   The IANA has registered a URL scheme for the MUPDATE protocol, as
  49.864 +   defined in section 6.1 of this document.
  49.865 +
  49.866 +   IANA has registered a GSSAPI service name of "mupdate" for the
  49.867 +   MUPDATE protocol in the registry maintained at:
  49.868 +
  49.869 +   http://www.iana.org/assignments/gssapi-service-names
  49.870 +
  49.871 +9.  Intellectual Property Rights
  49.872 +
  49.873 +   The IETF takes no position regarding the validity or scope of any
  49.874 +   intellectual property or other rights that might be claimed to
  49.875 +   pertain to the implementation or use of the technology described in
  49.876 +   this document or the extent to which any license under such rights
  49.877 +   might or might not be available; neither does it represent that it
  49.878 +   has made any effort to identify any such rights.  Information on the
  49.879 +   IETF's procedures with respect to rights in standards-track and
  49.880 +   standards-related documentation can be found in BCP-11.  Copies of
  49.881 +   claims of rights made available for publication and any assurances of
  49.882 +   licenses to be made available, or the result of an attempt made to
  49.883 +   obtain a general license or permission for the use of such
  49.884 +   proprietary rights by implementors or users of this specification can
  49.885 +   be obtained from the IETF Secretariat.
  49.886 +
  49.887 +   The IETF invites any interested party to bring to its attention any
  49.888 +   copyrights, patents or patent applications, or other proprietary
  49.889 +   rights which may cover technology that may be required to practice
  49.890 +   this standard.  Please address the information to the IETF Executive
  49.891 +   Director.
  49.892 +
  49.893 +
  49.894 +
  49.895 +
  49.896 +
  49.897 +
  49.898 +
  49.899 +
  49.900 +
  49.901 +Siemborski                    Experimental                     [Page 16]
  49.902 +
  49.903 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.904 +
  49.905 +
  49.906 +10.  References
  49.907 +
  49.908 +10.1.  Normative References
  49.909 +
  49.910 +   [KEYWORDS]  Bradner, S., "Key words for use in RFCs to Indicate
  49.911 +               Requirement Levels", BCP 14, RFC 2119, March 1997.
  49.912 +
  49.913 +   [IMAP]      Crispin, M., "Internet Message Access Protocol - Version
  49.914 +               4", RFC 3501, March 2003.
  49.915 +
  49.916 +   [ABNF]      Crocker, D., Ed. and P. Overell, "Augmented BNF for
  49.917 +               Syntax Specifications: ABNF", RFC 2234, November 1997.
  49.918 +
  49.919 +   [MIME]      Freed, N. and N. Bornstein, "Multipurpose Internet Mail
  49.920 +               Extensions (MIME) Part One: Format of Internet Message
  49.921 +               Bodies", RFC 2045, November 1996.
  49.922 +
  49.923 +   [IMAP-ACL]  Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997.
  49.924 +
  49.925 +   [SASL]      Myers, J., "Simple Authentication and Security Layer
  49.926 +               (SASL)", RFC 2222, October 1997.
  49.927 +
  49.928 +   [IMAP-URL]  Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
  49.929 +
  49.930 +   [ACAP]      Newman, C. and J. Myers, "ACAP -- Application
  49.931 +               Configuration Access Protocol", RFC 2244, November 1997.
  49.932 +
  49.933 +   [TLS]       Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
  49.934 +               RFC 2246, January 1999.
  49.935 +
  49.936 +10.2.  Informative References
  49.937 +
  49.938 +   [POP3]      Myers, J. and M. Rose, "Post Office Protocol - Version
  49.939 +               3", STD 53, RFC 1939, May 1996.
  49.940 +
  49.941 +   [RFC2717]   Petke, R. and I. King, "Registration Procedures for URL
  49.942 +               Scheme Names", BCP 35, RFC 2717, November 1999.
  49.943 +
  49.944 +
  49.945 +
  49.946 +
  49.947 +
  49.948 +
  49.949 +
  49.950 +
  49.951 +
  49.952 +
  49.953 +
  49.954 +
  49.955 +
  49.956 +
  49.957 +Siemborski                    Experimental                     [Page 17]
  49.958 +
  49.959 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
  49.960 +
  49.961 +
  49.962 +11.  Acknowledgments
  49.963 +
  49.964 +   Lawrence Greenfield and Ken Murchison, for a great deal of input on
  49.965 +   both the protocol and the text of the documents.
  49.966 +
  49.967 +12.  Author's  Address
  49.968 +
  49.969 +   Robert Siemborski
  49.970 +   Carnegie Mellon, Andrew Systems Group
  49.971 +   Cyert Hall 207
  49.972 +   5000 Forbes Avenue
  49.973 +   Pittsburgh, PA  15213
  49.974 +
  49.975 +   Phone: (412) 268-7456
  49.976 +   EMail: rjs3+@andrew.cmu.edu
  49.977 +
  49.978 +
  49.979 +
  49.980 +
  49.981 +
  49.982 +
  49.983 +
  49.984 +
  49.985 +
  49.986 +
  49.987 +
  49.988 +
  49.989 +
  49.990 +
  49.991 +
  49.992 +
  49.993 +
  49.994 +
  49.995 +
  49.996 +
  49.997 +
  49.998 +
  49.999 +
 49.1000 +
 49.1001 +
 49.1002 +
 49.1003 +
 49.1004 +
 49.1005 +
 49.1006 +
 49.1007 +
 49.1008 +
 49.1009 +
 49.1010 +
 49.1011 +
 49.1012 +
 49.1013 +Siemborski                    Experimental                     [Page 18]
 49.1014 +
 49.1015 +RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
 49.1016 +
 49.1017 +
 49.1018 +13.  Full Copyright Statement
 49.1019 +
 49.1020 +   Copyright (C) The Internet Society (2003).  All Rights Reserved.
 49.1021 +
 49.1022 +   This document and translations of it may be copied and furnished to
 49.1023 +   others, and derivative works that comment on or otherwise explain it
 49.1024 +   or assist in its implementation may be prepared, copied, published
 49.1025 +   and distributed, in whole or in part, without restriction of any
 49.1026 +   kind, provided that the above copyright notice and this paragraph are
 49.1027 +   included on all such copies and derivative works.  However, this
 49.1028 +   document itself may not be modified in any way, such as by removing
 49.1029 +   the copyright notice or references to the Internet Society or other
 49.1030 +   Internet organizations, except as needed for the purpose of
 49.1031 +   developing Internet standards in which case the procedures for
 49.1032 +   copyrights defined in the Internet Standards process must be
 49.1033 +   followed, or as required to translate it into languages other than
 49.1034 +   English.
 49.1035 +
 49.1036 +   The limited permissions granted above are perpetual and will not be
 49.1037 +   revoked by the Internet Society or its successors or assignees.
 49.1038 +
 49.1039 +   This document and the information contained herein is provided on an
 49.1040 +   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
 49.1041 +   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
 49.1042 +   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
 49.1043 +   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
 49.1044 +   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 49.1045 +
 49.1046 +Acknowledgement
 49.1047 +
 49.1048 +   Funding for the RFC Editor function is currently provided by the
 49.1049 +   Internet Society.
 49.1050 +
 49.1051 +
 49.1052 +
 49.1053 +
 49.1054 +
 49.1055 +
 49.1056 +
 49.1057 +
 49.1058 +
 49.1059 +
 49.1060 +
 49.1061 +
 49.1062 +
 49.1063 +
 49.1064 +
 49.1065 +
 49.1066 +
 49.1067 +
 49.1068 +
 49.1069 +Siemborski                    Experimental                     [Page 19]
 49.1070 +
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/docs/rfc/rfc3691.txt	Mon Sep 14 15:17:45 2009 +0900
    50.3 @@ -0,0 +1,283 @@
    50.4 +
    50.5 +
    50.6 +
    50.7 +
    50.8 +
    50.9 +
   50.10 +Network Working Group                                        A. Melnikov
   50.11 +Request for Comments: 3691                                    Isode Ltd.
   50.12 +Category: Standards Track                                  February 2004
   50.13 +
   50.14 +
   50.15 +        Internet Message Access Protocol (IMAP) UNSELECT command
   50.16 +
   50.17 +Status of this Memo
   50.18 +
   50.19 +   This document specifies an Internet standards track protocol for the
   50.20 +   Internet community, and requests discussion and suggestions for
   50.21 +   improvements.  Please refer to the current edition of the "Internet
   50.22 +   Official Protocol Standards" (STD 1) for the standardization state
   50.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   50.24 +
   50.25 +Copyright Notice
   50.26 +
   50.27 +   Copyright (C) The Internet Society (2004).  All Rights Reserved.
   50.28 +
   50.29 +Abstract
   50.30 +
   50.31 +   This document defines an UNSELECT command that can be used to close
   50.32 +   the current mailbox in an Internet Message Access Protocol - version
   50.33 +   4 (IMAP4) session without expunging it.  Certain types of IMAP
   50.34 +   clients need to release resources associated with the selected
   50.35 +   mailbox without selecting a different mailbox.  While IMAP4 provides
   50.36 +   this functionality (via a SELECT command with a nonexistent mailbox
   50.37 +   name or reselecting the same mailbox with EXAMINE command), a more
   50.38 +   clean solution is desirable.
   50.39 +
   50.40 +Table of Contents
   50.41 +
   50.42 +   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
   50.43 +   2.  UNSELECT command . . . . . . . . . . . . . . . . . . . . . . .  2
   50.44 +   3.  Security Considerations. . . . . . . . . . . . . . . . . . . .  3
   50.45 +   4.  Formal Syntax. . . . . . . . . . . . . . . . . . . . . . . . .  3
   50.46 +   5.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . .  3
   50.47 +   6.  Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . .  3
   50.48 +   7.  Normative References . . . . . . . . . . . . . . . . . . . . .  4
   50.49 +   8.  Author's Address . . . . . . . . . . . . . . . . . . . . . . .  4
   50.50 +   9.  Full Copyright Statement . . . . . . . . . . . . . . . . . . .  5
   50.51 +
   50.52 +
   50.53 +
   50.54 +
   50.55 +
   50.56 +
   50.57 +
   50.58 +
   50.59 +
   50.60 +
   50.61 +Melnikov                    Standards Track                     [Page 1]
   50.62 +
   50.63 +RFC 3691                 IMAP UNSELECT command             February 2004
   50.64 +
   50.65 +
   50.66 +1.  Introduction
   50.67 +
   50.68 +   Certain types of IMAP clients need to release resources associated
   50.69 +   with the selected mailbox without selecting a different mailbox.
   50.70 +   While [IMAP4] provides this functionality (via a SELECT command with
   50.71 +   a nonexistent mailbox name or reselecting the same mailbox with
   50.72 +   EXAMINE command), a more clean solution is desirable.
   50.73 +
   50.74 +   [IMAP4] defines the CLOSE command that closes the selected mailbox as
   50.75 +   well as permanently removes all messages with the \Deleted flag set.
   50.76 +
   50.77 +   However [IMAP4] lacks a command that simply closes the mailbox
   50.78 +   without expunging it.  This document defines the UNSELECT command for
   50.79 +   this purpose.
   50.80 +
   50.81 +   A server which supports this extension indicates this with a
   50.82 +   capability name of "UNSELECT".
   50.83 +
   50.84 +   "C:" and "S:" in examples show lines sent by the client and server
   50.85 +   respectively.
   50.86 +
   50.87 +   The keywords "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in
   50.88 +   this document when typed in uppercase are to be interpreted as
   50.89 +   defined in "Key words for use in RFCs to Indicate Requirement Levels"
   50.90 +   [KEYWORDS].
   50.91 +
   50.92 +2.  UNSELECT Command
   50.93 +
   50.94 +   Arguments:  none
   50.95 +
   50.96 +   Responses:  no specific responses for this command
   50.97 +
   50.98 +   Result:     OK - unselect completed, now in authenticated state
   50.99 +               BAD - no mailbox selected, or argument supplied but
  50.100 +                     none permitted
  50.101 +
  50.102 +      The UNSELECT command frees server's resources associated with the
  50.103 +      selected mailbox and returns the server to the authenticated
  50.104 +      state.  This command performs the same actions as CLOSE, except
  50.105 +      that no messages are permanently removed from the currently
  50.106 +      selected mailbox.
  50.107 +
  50.108 +   Example:    C: A341 UNSELECT
  50.109 +               S: A341 OK Unselect completed
  50.110 +
  50.111 +
  50.112 +
  50.113 +
  50.114 +
  50.115 +
  50.116 +
  50.117 +Melnikov                    Standards Track                     [Page 2]
  50.118 +
  50.119 +RFC 3691                 IMAP UNSELECT command             February 2004
  50.120 +
  50.121 +
  50.122 +3.  Security Considerations
  50.123 +
  50.124 +   It is believed that this extension doesn't raise any additional
  50.125 +   security concerns not already discussed in [IMAP4].
  50.126 +
  50.127 +4.  Formal Syntax
  50.128 +
  50.129 +   The following syntax specification uses the Augmented Backus-Naur
  50.130 +   Form (ABNF) notation as specified in [ABNF].  Non-terminals
  50.131 +   referenced but not defined below are as defined by [IMAP4].
  50.132 +
  50.133 +   Except as noted otherwise, all alphabetic characters are case-
  50.134 +   insensitive.  The use of upper or lower case characters to define
  50.135 +   token strings is for editorial clarity only.  Implementations MUST
  50.136 +   accept these strings in a case-insensitive fashion.
  50.137 +
  50.138 +   command-select  /= "UNSELECT"
  50.139 +
  50.140 +5.  IANA Considerations
  50.141 +
  50.142 +   IMAP4 capabilities are registered by publishing a standards track or
  50.143 +   IESG approved experimental RFC.  The registry is currently located
  50.144 +   at:
  50.145 +
  50.146 +      http://www.iana.org/assignments/imap4-capabilities
  50.147 +
  50.148 +   This document defines the UNSELECT IMAP capabilities.  IANA has added
  50.149 +   this capability to the registry.
  50.150 +
  50.151 +6.  Acknowledgments
  50.152 +
  50.153 +   UNSELECT command was originally implemented by Tim Showalter in Cyrus
  50.154 +   IMAP server.
  50.155 +
  50.156 +   Also, the author of the document would like to thank Vladimir Butenko
  50.157 +   and Mark Crispin for reminding that UNSELECT has to be documented.
  50.158 +   Also thanks to Simon Josefsson for pointing out that there are
  50.159 +   multiple ways to implement UNSELECT.
  50.160 +
  50.161 +
  50.162 +
  50.163 +
  50.164 +
  50.165 +
  50.166 +
  50.167 +
  50.168 +
  50.169 +
  50.170 +
  50.171 +
  50.172 +
  50.173 +Melnikov                    Standards Track                     [Page 3]
  50.174 +
  50.175 +RFC 3691                 IMAP UNSELECT command             February 2004
  50.176 +
  50.177 +
  50.178 +7.  Normative References
  50.179 +
  50.180 +   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
  50.181 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  50.182 +
  50.183 +   [IMAP4]    Crispin, M., "Internet Message Access Protocol - Version
  50.184 +              4rev1", RFC 3501, March 2003.
  50.185 +
  50.186 +   [ABNF]     Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
  50.187 +              Specifications: ABNF", RFC 2234, November 1997.
  50.188 +
  50.189 +8.  Author's Address
  50.190 +
  50.191 +   Alexey Melnikov
  50.192 +   Isode Limited
  50.193 +   5 Castle Business Village
  50.194 +   Hampton, Middlesex TW12 2BX
  50.195 +
  50.196 +   EMail: Alexey.Melnikov@isode.com
  50.197 +   URI: http://www.melnikov.ca/
  50.198 +
  50.199 +
  50.200 +
  50.201 +
  50.202 +
  50.203 +
  50.204 +
  50.205 +
  50.206 +
  50.207 +
  50.208 +
  50.209 +
  50.210 +
  50.211 +
  50.212 +
  50.213 +
  50.214 +
  50.215 +
  50.216 +
  50.217 +
  50.218 +
  50.219 +
  50.220 +
  50.221 +
  50.222 +
  50.223 +
  50.224 +
  50.225 +
  50.226 +
  50.227 +
  50.228 +
  50.229 +Melnikov                    Standards Track                     [Page 4]
  50.230 +
  50.231 +RFC 3691                 IMAP UNSELECT command             February 2004
  50.232 +
  50.233 +
  50.234 +9.  Full Copyright Statement
  50.235 +
  50.236 +   Copyright (C) The Internet Society (2004).  This document is subject
  50.237 +   to the rights, licenses and restrictions contained in BCP 78 and
  50.238 +   except as set forth therein, the authors retain all their rights.
  50.239 +
  50.240 +   This document and the information contained herein are provided on an
  50.241 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
  50.242 +   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
  50.243 +   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
  50.244 +   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  50.245 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  50.246 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  50.247 +
  50.248 +Intellectual Property
  50.249 +
  50.250 +   The IETF takes no position regarding the validity or scope of any
  50.251 +   Intellectual Property Rights or other rights that might be claimed
  50.252 +   to pertain to the implementation or use of the technology
  50.253 +   described in this document or the extent to which any license
  50.254 +   under such rights might or might not be available; nor does it
  50.255 +   represent that it has made any independent effort to identify any
  50.256 +   such rights.  Information on the procedures with respect to
  50.257 +   rights in RFC documents can be found in BCP 78 and BCP 79.
  50.258 +
  50.259 +   Copies of IPR disclosures made to the IETF Secretariat and any
  50.260 +   assurances of licenses to be made available, or the result of an
  50.261 +   attempt made to obtain a general license or permission for the use
  50.262 +   of such proprietary rights by implementers or users of this
  50.263 +   specification can be obtained from the IETF on-line IPR repository
  50.264 +   at http://www.ietf.org/ipr.
  50.265 +
  50.266 +   The IETF invites any interested party to bring to its attention
  50.267 +   any copyrights, patents or patent applications, or other
  50.268 +   proprietary rights that may cover technology that may be required
  50.269 +   to implement this standard.  Please address the information to the
  50.270 +   IETF at ietf-ipr@ietf.org.
  50.271 +
  50.272 +Acknowledgement
  50.273 +
  50.274 +   Funding for the RFC Editor function is currently provided by the
  50.275 +   Internet Society.
  50.276 +
  50.277 +
  50.278 +
  50.279 +
  50.280 +
  50.281 +
  50.282 +
  50.283 +
  50.284 +
  50.285 +Melnikov                    Standards Track                     [Page 5]
  50.286 +
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/docs/rfc/rfc4314.txt	Mon Sep 14 15:17:45 2009 +0900
    51.3 @@ -0,0 +1,1515 @@
    51.4 +
    51.5 +
    51.6 +
    51.7 +
    51.8 +
    51.9 +
   51.10 +Network Working Group                                        A. Melnikov
   51.11 +Request for Comments: 4314                                    Isode Ltd.
   51.12 +Obsoletes: 2086                                            December 2005
   51.13 +Category: Standards Track
   51.14 +
   51.15 +
   51.16 +               IMAP4 Access Control List (ACL) Extension
   51.17 +
   51.18 +Status of this Memo
   51.19 +
   51.20 +   This document specifies an Internet standards track protocol for the
   51.21 +   Internet community, and requests discussion and suggestions for
   51.22 +   improvements.  Please refer to the current edition of the "Internet
   51.23 +   Official Protocol Standards" (STD 1) for the standardization state
   51.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   51.25 +
   51.26 +Copyright Notice
   51.27 +
   51.28 +   Copyright (C) The Internet Society (2005).
   51.29 +
   51.30 +Abstract
   51.31 +
   51.32 +   The Access Control List (ACL) extension (RFC 2086) of the Internet
   51.33 +   Message Access Protocol (IMAP) permits mailbox access control lists
   51.34 +   to be retrieved and manipulated through the IMAP protocol.
   51.35 +
   51.36 +   This document is a revision of RFC 2086.  It defines several new
   51.37 +   access control rights and clarifies which rights are required for
   51.38 +   different IMAP commands.
   51.39 +
   51.40 +
   51.41 +
   51.42 +
   51.43 +
   51.44 +
   51.45 +
   51.46 +
   51.47 +
   51.48 +
   51.49 +
   51.50 +
   51.51 +
   51.52 +
   51.53 +
   51.54 +
   51.55 +
   51.56 +
   51.57 +
   51.58 +
   51.59 +
   51.60 +
   51.61 +Melnikov                    Standards Track                     [Page 1]
   51.62 +
   51.63 +RFC 4314                        IMAP ACL                   December 2005
   51.64 +
   51.65 +
   51.66 +Table of Contents
   51.67 +
   51.68 +   1. Introduction and Overview .......................................3
   51.69 +      1.1. Conventions Used in This Document ..........................3
   51.70 +   2. Access Control ..................................................3
   51.71 +      2.1. Standard Rights ............................................5
   51.72 +           2.1.1. Obsolete Rights .....................................5
   51.73 +      2.2. Rights Defined in RFC 2086 .................................8
   51.74 +   3. Access control management commands and responses ................8
   51.75 +      3.1. SETACL Command .............................................8
   51.76 +      3.2. DELETEACL Command ..........................................9
   51.77 +      3.3. GETACL Command ............................................10
   51.78 +      3.4. LISTRIGHTS Command ........................................10
   51.79 +      3.5. MYRIGHTS Command ..........................................11
   51.80 +      3.6. ACL Response ..............................................11
   51.81 +      3.7. LISTRIGHTS Response .......................................12
   51.82 +      3.8. MYRIGHTS Response .........................................12
   51.83 +   4. Rights Required to Perform Different IMAP4rev1 Commands ........12
   51.84 +   5. Other Considerations ...........................................17
   51.85 +      5.1. Additional Requirements and Implementation Notes ..........17
   51.86 +           5.1.1. Servers ............................................17
   51.87 +           5.1.2. Clients ............................................18
   51.88 +      5.2. Mapping of ACL Rights to READ-WRITE and READ-ONLY
   51.89 +           Response Codes ............................................19
   51.90 +   6. Security Considerations ........................................20
   51.91 +   7. Formal Syntax ..................................................21
   51.92 +   8. IANA Considerations ............................................22
   51.93 +   9. Internationalization Considerations ............................22
   51.94 +   Appendix A. Changes since RFC 2086 ................................23
   51.95 +   Appendix B. Compatibility with RFC 2086 ...........................24
   51.96 +   Appendix C. Known Deficiencies ....................................24
   51.97 +   Appendix D. Acknowledgements ......................................25
   51.98 +   Normative References ..............................................25
   51.99 +   Informative References ............................................25
  51.100 +
  51.101 +
  51.102 +
  51.103 +
  51.104 +
  51.105 +
  51.106 +
  51.107 +
  51.108 +
  51.109 +
  51.110 +
  51.111 +
  51.112 +
  51.113 +
  51.114 +
  51.115 +
  51.116 +
  51.117 +Melnikov                    Standards Track                     [Page 2]
  51.118 +
  51.119 +RFC 4314                        IMAP ACL                   December 2005
  51.120 +
  51.121 +
  51.122 +1.  Introduction and Overview
  51.123 +
  51.124 +   The ACL (Access Control List) extension of the Internet Message
  51.125 +   Access Protocol [IMAP4] permits mailbox access control lists to be
  51.126 +   retrieved and manipulated through the IMAP protocol.
  51.127 +
  51.128 +   This document is a revision of RFC 2086 [RFC2086].  It tries to
  51.129 +   clarify different ambiguities in RFC 2086, in particular, the use of
  51.130 +   UTF-8 [UTF-8] in access identifiers, which rights are required for
  51.131 +   different IMAP4 commands, and how READ-WRITE/READ-ONLY response codes
  51.132 +   are related to ACL.
  51.133 +
  51.134 +1.1.  Conventions Used in This Document
  51.135 +
  51.136 +   In examples, "C:" and "S:" indicate lines sent by the client and
  51.137 +   server respectively.
  51.138 +
  51.139 +   In all examples "/" character is used as hierarchy separator.
  51.140 +
  51.141 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  51.142 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  51.143 +   document are to be interpreted as described in RFC 2119 [KEYWORDS].
  51.144 +
  51.145 +   The phrase "ACL server" is just a shortcut for saying "IMAP server
  51.146 +   that supports ACL extension as defined in this document".
  51.147 +
  51.148 +2.  Access Control
  51.149 +
  51.150 +   The ACL extension is present in any IMAP4 implementation that returns
  51.151 +   "ACL" as one of the supported capabilities to the CAPABILITY command.
  51.152 +
  51.153 +   A server implementation conformant to this document MUST also return
  51.154 +   rights (see below) not defined in Section 2.2 in the "RIGHTS="
  51.155 +   capability.
  51.156 +
  51.157 +   An access control list is a set of <access identifier,rights> pairs.
  51.158 +   An ACL applies to a mailbox name.
  51.159 +
  51.160 +   Access identifier (or just "identifier") is a UTF-8 [UTF-8] string.
  51.161 +   The identifier "anyone" is reserved to refer to the universal
  51.162 +   identity (all authentications, including anonymous).  All user name
  51.163 +   strings accepted by the LOGIN or AUTHENTICATE commands to
  51.164 +   authenticate to the IMAP server are reserved as identifiers for the
  51.165 +   corresponding users.  Identifiers starting with a dash ("-") are
  51.166 +   reserved for "negative rights", described below.  All other
  51.167 +   identifier strings are interpreted in an implementation-defined
  51.168 +   manner.
  51.169 +
  51.170 +
  51.171 +
  51.172 +
  51.173 +Melnikov                    Standards Track                     [Page 3]
  51.174 +
  51.175 +RFC 4314                        IMAP ACL                   December 2005
  51.176 +
  51.177 +
  51.178 +   Rights is a string listing a (possibly empty) set of alphanumeric
  51.179 +   characters, each character listing a set of operations that is being
  51.180 +   controlled.  Lowercase letters are reserved for "standard" rights,
  51.181 +   listed in Section 2.1.  (Note that for compatibility with deployed
  51.182 +   clients and servers uppercase rights are not allowed.)  The set of
  51.183 +   standard rights can only be extended by a standards-track document.
  51.184 +   Digits are reserved for implementation- or site-defined rights.
  51.185 +
  51.186 +   An implementation MAY tie rights together or MAY force rights to
  51.187 +   always or never be granted to particular identifiers.  For example,
  51.188 +   in an implementation that uses UNIX mode bits, the rights "swite" are
  51.189 +   tied, the "a" right is always granted to the owner of a mailbox and
  51.190 +   is never granted to another user.  If rights are tied in an
  51.191 +   implementation, the implementation must be conservative in granting
  51.192 +   rights in response to SETACL commands--unless all rights in a tied
  51.193 +   set are specified, none of that set should be included in the ACL
  51.194 +   entry for that identifier.  A client can discover the set of rights
  51.195 +   that may be granted to a given identifier in the ACL for a given
  51.196 +   mailbox name by using the LISTRIGHTS command.
  51.197 +
  51.198 +   It is possible for multiple identifiers in an access control list to
  51.199 +   apply to a given user.  For example, an ACL may include rights to be
  51.200 +   granted to the identifier matching the user, one or more
  51.201 +   implementation-defined identifiers matching groups that include the
  51.202 +   user, and/or the identifier "anyone".  How these rights are combined
  51.203 +   to determine the user's access is implementation defined.  An
  51.204 +   implementation may choose, for example, to use the union of the
  51.205 +   rights granted to the applicable identifiers.  An implementation may
  51.206 +   instead choose, for example, to use only those rights granted to the
  51.207 +   most specific identifier present in the ACL.  A client can determine
  51.208 +   the set of rights granted to the logged-in user for a given mailbox
  51.209 +   name by using the MYRIGHTS command.
  51.210 +
  51.211 +   When an identifier in an ACL starts with a dash ("-"), that indicates
  51.212 +   that associated rights are to be removed from the identifier prefixed
  51.213 +   by the dash.  This is referred to as a "negative right".  This
  51.214 +   differs from DELETEACL in that a negative right is added to the ACL
  51.215 +   and is a part of the calculation of the rights.
  51.216 +
  51.217 +   Let's assume that an identifier "fred" refers to a user with login
  51.218 +   "fred".  If the identifier "-fred" is granted the "w" right, that
  51.219 +   indicates that the "w" right is to be removed from users matching the
  51.220 +   identifier "fred", even though the user "fred" might have the "w"
  51.221 +   right as a consequence of some other identifier in the ACL.  A
  51.222 +   DELETEACL of "fred" simply deletes the identifier "fred" from the
  51.223 +   ACL; it does not affect any rights that the user "fred" may get from
  51.224 +   another entry in the ACL, in particular it doesn't affect rights
  51.225 +   granted to the identifier "-fred".
  51.226 +
  51.227 +
  51.228 +
  51.229 +Melnikov                    Standards Track                     [Page 4]
  51.230 +
  51.231 +RFC 4314                        IMAP ACL                   December 2005
  51.232 +
  51.233 +
  51.234 +   Server implementations are not required to support "negative right"
  51.235 +   identifiers.
  51.236 +
  51.237 +2.1.  Standard Rights
  51.238 +
  51.239 +   The currently defined standard rights are (note that the list below
  51.240 +   doesn't list all commands that use a particular right):
  51.241 +
  51.242 +   l - lookup (mailbox is visible to LIST/LSUB commands, SUBSCRIBE
  51.243 +       mailbox)
  51.244 +   r - read (SELECT the mailbox, perform STATUS)
  51.245 +   s - keep seen/unseen information across sessions (set or clear
  51.246 +       \SEEN flag via STORE, also set \SEEN during APPEND/COPY/
  51.247 +       FETCH BODY[...])
  51.248 +   w - write (set or clear flags other than \SEEN and \DELETED via
  51.249 +       STORE, also set them during APPEND/COPY)
  51.250 +   i - insert (perform APPEND, COPY into mailbox)
  51.251 +   p - post (send mail to submission address for mailbox,
  51.252 +       not enforced by IMAP4 itself)
  51.253 +   k - create mailboxes (CREATE new sub-mailboxes in any
  51.254 +       implementation-defined hierarchy, parent mailbox for the new
  51.255 +       mailbox name in RENAME)
  51.256 +   x - delete mailbox (DELETE mailbox, old mailbox name in RENAME)
  51.257 +   t - delete messages (set or clear \DELETED flag via STORE, set
  51.258 +       \DELETED flag during APPEND/COPY)
  51.259 +   e - perform EXPUNGE and expunge as a part of CLOSE
  51.260 +   a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS)
  51.261 +
  51.262 +2.1.1.  Obsolete Rights
  51.263 +
  51.264 +   Due to ambiguity in RFC 2086, some existing RFC 2086 server
  51.265 +   implementations use the "c" right to control the DELETE command.
  51.266 +   Others chose to use the "d" right to control the DELETE command.  For
  51.267 +   the former group, let's define the "create" right as union of the "k"
  51.268 +   and "x" rights, and the "delete" right as union of the "e" and "t"
  51.269 +   rights.  For the latter group, let's define the "create" rights as a
  51.270 +   synonym to the "k" right, and the "delete" right as union of the "e",
  51.271 +   "t", and "x" rights.
  51.272 +
  51.273 +   For compatibility with RFC 2086, this section defines two virtual
  51.274 +   rights "d" and "c".
  51.275 +
  51.276 +   If a client includes the "d" right in a rights list, then it MUST be
  51.277 +   treated as if the client had included every member of the "delete"
  51.278 +   right.  (It is not an error for a client to specify both the "d"
  51.279 +   right and one or more members of the "delete" right, but the effect
  51.280 +   is no different than if just the "d" right or all members of the
  51.281 +   "delete" right had been specified.)
  51.282 +
  51.283 +
  51.284 +
  51.285 +Melnikov                    Standards Track                     [Page 5]
  51.286 +
  51.287 +RFC 4314                        IMAP ACL                   December 2005
  51.288 +
  51.289 +
  51.290 +   When any of the "delete" member rights is set in a list of rights,
  51.291 +   the server MUST also include the "d" right when returning the list in
  51.292 +   a MYRIGHTS or ACL response.  This is to enable older clients
  51.293 +   conforming to RFC 2086 to work with newer servers. (*)
  51.294 +
  51.295 +   Example:    C: A001 SeTacl INBOX/Drafts David lrswida
  51.296 +               S: A001 OK Setacl complete
  51.297 +
  51.298 +   The client has specified the "d" right in the SETACL command above
  51.299 +   and it expands to "et" on the server:
  51.300 +
  51.301 +               C: A002 getacl INBOX/Drafts
  51.302 +               S: * ACL INBOX Fred rwipslxcetda David lrswideta
  51.303 +               S: A002 OK Getacl complete
  51.304 +
  51.305 +   If the identifier specified in the LISTRIGHTS command can be granted
  51.306 +   any of the "delete" member rights on a mailbox, then the server MUST
  51.307 +   include the "d" right in the corresponding LISTRIGHTS response. (*)
  51.308 +   If the member rights aren't tied to non-member rights, then the "d"
  51.309 +   right is returned by itself in the LISTRIGHTS response.  If any of
  51.310 +   the member rights needs to be tied to one (or more) non-member right,
  51.311 +   then the "d" right and all of the member rights need to be tied to
  51.312 +   the same non-member right(s) (**).
  51.313 +
  51.314 +   If a client includes the "c" right in a rights list, then it MUST be
  51.315 +   treated as if the client had included every member of the "create"
  51.316 +   right.  (It is not an error for a client to specify both the "c"
  51.317 +   right and one or more members of the "create" right, but the effect
  51.318 +   is no different than if just the "c" right or all members of the
  51.319 +   "create" right had been specified.)
  51.320 +
  51.321 +   When any of the "create" member rights is set in a list of rights,
  51.322 +   the server MUST also include the "c" right when returning the list in
  51.323 +   a MYRIGHTS or ACL response.  This is to enable older clients
  51.324 +   conforming to RFC 2086 to work with newer servers. (*)
  51.325 +
  51.326 +   Example:    C: A003 Setacl INBOX/Drafts Byron lrswikda
  51.327 +               S: A001 OK Setacl complete
  51.328 +               C: A002 getAcl INBOX/Drafts
  51.329 +               S: * ACL INBOX Fred rwipslxcetda Byron lrswikcdeta
  51.330 +               S: A002 OK Getacl complete
  51.331 +
  51.332 +   The client has specified the "d" right in the SETACL command above
  51.333 +   and it expands to "et" on the server: As the client has specified the
  51.334 +   "k" right (which is a member of the "c" right), the server also
  51.335 +   returns the "c" right.
  51.336 +
  51.337 +
  51.338 +
  51.339 +
  51.340 +
  51.341 +Melnikov                    Standards Track                     [Page 6]
  51.342 +
  51.343 +RFC 4314                        IMAP ACL                   December 2005
  51.344 +
  51.345 +
  51.346 +   If the identifier specified in the LISTRIGHTS command can be granted
  51.347 +   any of the "create" member rights on a mailbox, then the server MUST
  51.348 +   include the "c" right in the corresponding LISTRIGHTS response. (*)
  51.349 +   If the member rights aren't tied to non-member rights, then the "c"
  51.350 +   right is returned by itself in the LISTRIGHTS response.  If any of
  51.351 +   the member rights needs to be tied to one (or more) non-member right,
  51.352 +   then the "c" right and all of the member rights need to be tied to
  51.353 +   the same non-member right(s) (**).
  51.354 +
  51.355 +   Example: The server that ties the rights as follows:
  51.356 +
  51.357 +               lr s w i p k x t
  51.358 +
  51.359 +            and c=k
  51.360 +
  51.361 +            will return:
  51.362 +
  51.363 +               S: * LISTRIGHTS archive/imap anyone ""
  51.364 +                  lr s w i p k x t c d
  51.365 +
  51.366 +   Example: The server that ties the rights as follows:
  51.367 +
  51.368 +               lr s w i p k xte
  51.369 +
  51.370 +            and c=k
  51.371 +
  51.372 +            will return:
  51.373 +
  51.374 +               S: * LISTRIGHTS archive/imap anyone ""
  51.375 +                  lr s w i p k xte c d
  51.376 +
  51.377 +   Example: The server that ties the rights as follows:
  51.378 +
  51.379 +               lr s w i p k x te
  51.380 +
  51.381 +            and c=k
  51.382 +
  51.383 +            will return:
  51.384 +
  51.385 +               S: * LISTRIGHTS archive/imap anyone ""
  51.386 +                  lr s w i p k c x te d
  51.387 +
  51.388 +   Example: The server that ties the rights as follows:
  51.389 +
  51.390 +               lr swte i p k x
  51.391 +
  51.392 +            and c=kx
  51.393 +
  51.394 +
  51.395 +
  51.396 +
  51.397 +Melnikov                    Standards Track                     [Page 7]
  51.398 +
  51.399 +RFC 4314                        IMAP ACL                   December 2005
  51.400 +
  51.401 +
  51.402 +            will return:
  51.403 +
  51.404 +               S: * LISTRIGHTS archive/imap anyone ""
  51.405 +                  lr swted i p k x c
  51.406 +
  51.407 +   (*)  Clients conforming to this document MUST ignore the virtual "d"
  51.408 +        and "c" rights in MYRIGHTS, ACL, and LISTRIGHTS responses.
  51.409 +
  51.410 +   (**) The IMAPEXT Working Group has debated this issue in great length
  51.411 +        and after reviewing existing ACL implementations concluded that
  51.412 +        this is a reasonable restriction.
  51.413 +
  51.414 +2.2.  Rights Defined in RFC 2086
  51.415 +
  51.416 +   The "RIGHTS=" capability MUST NOT include any of the rights defined
  51.417 +   in RFC 2086: "l", "r", "s", "w", "i", "p", "a", "c", "d", and the
  51.418 +   digits ("0" .. "9").
  51.419 +
  51.420 +3.  Access control management commands and responses
  51.421 +
  51.422 +   Servers, when processing a command that has an identifier as a
  51.423 +   parameter (i.e., any of SETACL, DELETEACL, and LISTRIGHTS commands),
  51.424 +   SHOULD first prepare the received identifier using "SASLprep" profile
  51.425 +   [SASLprep] of the "stringprep" algorithm [Stringprep].  If the
  51.426 +   preparation of the identifier fails or results in an empty string,
  51.427 +   the server MUST refuse to perform the command with a BAD response.
  51.428 +   Note that Section 6 recommends additional identifier's verification
  51.429 +   steps.
  51.430 +
  51.431 +3.1.  SETACL Command
  51.432 +
  51.433 +   Arguments:  mailbox name
  51.434 +               identifier
  51.435 +               access right modification
  51.436 +
  51.437 +   Data:       no specific data for this command
  51.438 +
  51.439 +   Result:     OK - setacl completed
  51.440 +               NO - setacl failure: can't set acl
  51.441 +               BAD - arguments invalid
  51.442 +
  51.443 +   The SETACL command changes the access control list on the specified
  51.444 +   mailbox so that the specified identifier is granted permissions as
  51.445 +   specified in the third argument.
  51.446 +
  51.447 +   The third argument is a string containing an optional plus ("+") or
  51.448 +   minus ("-") prefix, followed by zero or more rights characters.  If
  51.449 +   the string starts with a plus, the following rights are added to any
  51.450 +
  51.451 +
  51.452 +
  51.453 +Melnikov                    Standards Track                     [Page 8]
  51.454 +
  51.455 +RFC 4314                        IMAP ACL                   December 2005
  51.456 +
  51.457 +
  51.458 +   existing rights for the identifier.  If the string starts with a
  51.459 +   minus, the following rights are removed from any existing rights for
  51.460 +   the identifier.  If the string does not start with a plus or minus,
  51.461 +   the rights replace any existing rights for the identifier.
  51.462 +
  51.463 +   Note that an unrecognized right MUST cause the command to return the
  51.464 +   BAD response.  In particular, the server MUST NOT silently ignore
  51.465 +   unrecognized rights.
  51.466 +
  51.467 +   Example:    C: A001 GETACL INBOX/Drafts
  51.468 +               S: * ACL INBOX/Drafts Fred rwipslxetad Chris lrswi
  51.469 +               S: A001 OK Getacl complete
  51.470 +               C: A002 SETACL INBOX/Drafts Chris +cda
  51.471 +               S: A002 OK Setacl complete
  51.472 +               C: A003 GETACL INBOX/Drafts
  51.473 +               S: * ACL INBOX/Drafts Fred rwipslxetad Chris lrswicdakxet
  51.474 +               S: A003 OK Getacl complete
  51.475 +
  51.476 +
  51.477 +               C: A035 SETACL INBOX/Drafts John lrQswicda
  51.478 +               S: A035 BAD Uppercase rights are not allowed
  51.479 +
  51.480 +
  51.481 +               C: A036 SETACL INBOX/Drafts John lrqswicda
  51.482 +               S: A036 BAD The q right is not supported
  51.483 +
  51.484 +3.2.  DELETEACL Command
  51.485 +
  51.486 +   Arguments:  mailbox name
  51.487 +               identifier
  51.488 +
  51.489 +   Data:       no specific data for this command
  51.490 +
  51.491 +   Result:     OK - deleteacl completed
  51.492 +               NO - deleteacl failure: can't delete acl
  51.493 +              BAD - arguments invalid
  51.494 +
  51.495 +   The DELETEACL command removes any <identifier,rights> pair for the
  51.496 +   specified identifier from the access control list for the specified
  51.497 +   mailbox.
  51.498 +
  51.499 +   Example:    C: B001 getacl INBOX
  51.500 +               S: * ACL INBOX Fred rwipslxetad -Fred wetd $team w
  51.501 +               S: B001 OK Getacl complete
  51.502 +               C: B002 DeleteAcl INBOX Fred
  51.503 +               S: B002 OK Deleteacl complete
  51.504 +
  51.505 +
  51.506 +
  51.507 +
  51.508 +
  51.509 +Melnikov                    Standards Track                     [Page 9]
  51.510 +
  51.511 +RFC 4314                        IMAP ACL                   December 2005
  51.512 +
  51.513 +
  51.514 +               C: B003 GETACL INBOX
  51.515 +               S: * ACL INBOX -Fred wetd $team w
  51.516 +               S: B003 OK Getacl complete
  51.517 +
  51.518 +3.3.  GETACL Command
  51.519 +
  51.520 +   Arguments:  mailbox name
  51.521 +
  51.522 +   Data:       untagged responses: ACL
  51.523 +
  51.524 +   Result:     OK - getacl completed
  51.525 +               NO - getacl failure: can't get acl
  51.526 +              BAD - arguments invalid
  51.527 +
  51.528 +   The GETACL command returns the access control list for mailbox in an
  51.529 +   untagged ACL response.
  51.530 +
  51.531 +   Some implementations MAY permit multiple forms of an identifier to
  51.532 +   reference the same IMAP account.  Usually, such implementations will
  51.533 +   have a canonical form that is stored internally.  An ACL response
  51.534 +   caused by a GETACL command MAY include a canonicalized form of the
  51.535 +   identifier that might be different from the one used in the
  51.536 +   corresponding SETACL command.
  51.537 +
  51.538 +   Example:    C: A002 GETACL INBOX
  51.539 +               S: * ACL INBOX Fred rwipsldexta
  51.540 +               S: A002 OK Getacl complete
  51.541 +
  51.542 +3.4.  LISTRIGHTS Command
  51.543 +
  51.544 +   Arguments:  mailbox name
  51.545 +               identifier
  51.546 +
  51.547 +   Data:       untagged responses: LISTRIGHTS
  51.548 +
  51.549 +   Result:     OK - listrights completed
  51.550 +               NO - listrights failure: can't get rights list
  51.551 +               BAD - arguments invalid
  51.552 +
  51.553 +   The LISTRIGHTS command takes a mailbox name and an identifier and
  51.554 +   returns information about what rights can be granted to the
  51.555 +   identifier in the ACL for the mailbox.
  51.556 +
  51.557 +   Some implementations MAY permit multiple forms of an identifier to
  51.558 +   reference the same IMAP account.  Usually, such implementations will
  51.559 +   have a canonical form that is stored internally.  A LISTRIGHTS
  51.560 +
  51.561 +
  51.562 +
  51.563 +
  51.564 +
  51.565 +Melnikov                    Standards Track                    [Page 10]
  51.566 +
  51.567 +RFC 4314                        IMAP ACL                   December 2005
  51.568 +
  51.569 +
  51.570 +   response caused by a LISTRIGHTS command MUST always return the same
  51.571 +   form of an identifier as specified by the client.  This is to allow
  51.572 +   the client to correlate the response with the command.
  51.573 +
  51.574 +   Example:    C: a001 LISTRIGHTS ~/Mail/saved smith
  51.575 +               S: * LISTRIGHTS ~/Mail/saved smith la r swicdkxte
  51.576 +               S: a001 OK Listrights completed
  51.577 +
  51.578 +   Example:    C: a005 listrights archive/imap anyone
  51.579 +               S: * LISTRIGHTS archive.imap anyone ""
  51.580 +                  l r s w i p k x t e c d a 0 1 2 3 4 5 6 7 8 9
  51.581 +               S: a005 Listrights successful
  51.582 +
  51.583 +3.5.  MYRIGHTS Command
  51.584 +
  51.585 +   Arguments:  mailbox name
  51.586 +
  51.587 +   Data:       untagged responses: MYRIGHTS
  51.588 +
  51.589 +   Result:     OK - myrights completed
  51.590 +               NO - myrights failure: can't get rights
  51.591 +               BAD - arguments invalid
  51.592 +
  51.593 +   The MYRIGHTS command returns the set of rights that the user has to
  51.594 +   mailbox in an untagged MYRIGHTS reply.
  51.595 +
  51.596 +   Example:    C: A003 MYRIGHTS INBOX
  51.597 +               S: * MYRIGHTS INBOX rwiptsldaex
  51.598 +               S: A003 OK Myrights complete
  51.599 +
  51.600 +3.6.  ACL Response
  51.601 +
  51.602 +   Data:       mailbox name
  51.603 +               zero or more identifier rights pairs
  51.604 +
  51.605 +   The ACL response occurs as a result of a GETACL command.  The first
  51.606 +   string is the mailbox name for which this ACL applies.  This is
  51.607 +   followed by zero or more pairs of strings; each pair contains the
  51.608 +   identifier for which the entry applies followed by the set of rights
  51.609 +   that the identifier has.
  51.610 +
  51.611 +   Section 2.1.1 details additional server requirements related to
  51.612 +   handling of the virtual "d" and "c" rights.
  51.613 +
  51.614 +
  51.615 +
  51.616 +
  51.617 +
  51.618 +
  51.619 +
  51.620 +
  51.621 +Melnikov                    Standards Track                    [Page 11]
  51.622 +
  51.623 +RFC 4314                        IMAP ACL                   December 2005
  51.624 +
  51.625 +
  51.626 +3.7.  LISTRIGHTS Response
  51.627 +
  51.628 +   Data:       mailbox name
  51.629 +               identifier
  51.630 +               required rights
  51.631 +               list of optional rights
  51.632 +
  51.633 +   The LISTRIGHTS response occurs as a result of a LISTRIGHTS command.
  51.634 +   The first two strings are the mailbox name and identifier for which
  51.635 +   this rights list applies.  Following the identifier is a string
  51.636 +   containing the (possibly empty) set of rights the identifier will
  51.637 +   always be granted in the mailbox.
  51.638 +
  51.639 +   Following this are zero or more strings each containing a set of
  51.640 +   rights the identifier can be granted in the mailbox.  Rights
  51.641 +   mentioned in the same string are tied together.  The server MUST
  51.642 +   either grant all tied rights to the identifier in the mailbox or
  51.643 +   grant none.  Section 2.1.1 details additional server requirements
  51.644 +   related to handling of the virtual "d" and "c" rights.
  51.645 +
  51.646 +   The same right MUST NOT be listed more than once in the LISTRIGHTS
  51.647 +   command.
  51.648 +
  51.649 +3.8.  MYRIGHTS Response
  51.650 +
  51.651 +   Data:       mailbox name
  51.652 +               rights
  51.653 +
  51.654 +   The MYRIGHTS response occurs as a result of a MYRIGHTS command.  The
  51.655 +   first string is the mailbox name for which these rights apply.  The
  51.656 +   second string is the set of rights that the client has.
  51.657 +
  51.658 +   Section 2.1.1 details additional server requirements related to
  51.659 +   handling of the virtual "d" and "c" rights.
  51.660 +
  51.661 +4.  Rights Required to Perform Different IMAP4rev1 Commands
  51.662 +
  51.663 +   Before executing a command, an ACL-compliant server MUST check which
  51.664 +   rights are required to perform it.  This section groups command by
  51.665 +   functions they perform and list the rights required.  It also gives
  51.666 +   the detailed description of any special processing required.
  51.667 +
  51.668 +   For the purpose of this section the UID counterpart of a command is
  51.669 +   considered to be the same command, e.g., both UID COPY and COPY
  51.670 +   commands require the same set of rights.
  51.671 +
  51.672 +
  51.673 +
  51.674 +
  51.675 +
  51.676 +
  51.677 +Melnikov                    Standards Track                    [Page 12]
  51.678 +
  51.679 +RFC 4314                        IMAP ACL                   December 2005
  51.680 +
  51.681 +
  51.682 +   The table below summarizes different rights or their combinations
  51.683 +   that are required in order to perform different IMAP operations.  As
  51.684 +   it is not always possible to express complex right checking and
  51.685 +   interactions, the description after the table should be used as the
  51.686 +   primary reference.
  51.687 +
  51.688 +   +-------------------+---+---+---+---+---+---+---+---+---+---+---+---+
  51.689 +   |Operations\Rights  | l | r | s | w | i | k | x | t | e | a |Any|Non|
  51.690 +   +-------------------+---+---+---+---+---+---+---+---+---+---+---+---+
  51.691 +   |                  commands in authenticated state                  |
  51.692 +   +-------------------------------------------------------------------+
  51.693 +   |      LIST         | + |   |   |   |   |   |   |   |   |   |   |   |
  51.694 +   |   SUBSCRIBE       | * |   |   |   |   |   |   |   |   |   |   | * |
  51.695 +   |  UNSUBSCRIBE      |   |   |   |   |   |   |   |   |   |   |   | + |
  51.696 +   |      LSUB         | * |   |   |   |   |   |   |   |   |   |   | * |
  51.697 +   |CREATE (for parent)|   |   |   |   |   | + |   |   |   |   |   |   |
  51.698 +   |     DELETE        |   | ? |   |   |   |   | + | ? | ? |   |   |   |
  51.699 +   |     RENAME        |   |   |   |   |   | + | + |   |   |   |   |   |
  51.700 +   |  SELECT/EXAMINE   |   | + |   |   |   |   |   |   |   |   |   |   |
  51.701 +   |      STATUS       |   | + |   |   |   |   |   |   |   |   |   |   |
  51.702 +   |  SETACL/DELETEACL |   |   |   |   |   |   |   |   |   | + |   |   |
  51.703 +   | GETACL/LISTRIGHTS |   |   |   |   |   |   |   |   |   | + |   |   |
  51.704 +   |     MYRIGHTS      |   |   |   |   |   |   |   |   |   |   | + |   |
  51.705 +   |      APPEND       |   |   | ? | ? | + |   |   | ? |   |   |   |   |
  51.706 +   +-------------------------------------------------------------------+
  51.707 +   |                     commands in selected state                    |
  51.708 +   +-------------------------------------------------------------------+
  51.709 +   |       COPY        |   |   | ? | ? | + |   |   | ? |   |   |   |   |
  51.710 +   |     EXPUNGE       |   |   |   |   |   |   |   |   | + |   |   |   |
  51.711 +   |      CLOSE        |   |   |   |   |   |   |   |   | ? |   |   |   |
  51.712 +   |      FETCH        |   |   | ? |   |   |   |   |   |   |   |   |   |
  51.713 +   |   STORE flags     |   |   | ? | ? |   |   |   | ? |   |   |   |   |
  51.714 +   +-------------------+---+---+---+---+---+---+---+---+---+---+---+---+
  51.715 +
  51.716 +   Note: for all commands in the selected state, the "r" is implied,
  51.717 +   because it is required to SELECT/EXAMINE a mailbox.  Servers are not
  51.718 +   required to check presence of the "r" right once a mailbox is
  51.719 +   successfully selected.
  51.720 +
  51.721 +   Legend:
  51.722 +    +     - The right is required
  51.723 +    *     - Only one of the rights marked with * is required
  51.724 +            (see description below)
  51.725 +    ?     - The right is OPTIONAL (see description below)
  51.726 +    "Any" - at least one of the "l", "r", "i", "k", "x", "a" rights is
  51.727 +            required
  51.728 +    "Non" - No rights required to perform the command
  51.729 +
  51.730 +
  51.731 +
  51.732 +
  51.733 +Melnikov                    Standards Track                    [Page 13]
  51.734 +
  51.735 +RFC 4314                        IMAP ACL                   December 2005
  51.736 +
  51.737 +
  51.738 +   Listing and subscribing/unsubscribing mailboxes:
  51.739 +      LIST - "l" right is required.  However, unlike other commands
  51.740 +      (e.g., SELECT) the server MUST NOT return a NO response if it
  51.741 +      can't list a mailbox.
  51.742 +      Note that if the user has "l" right to a mailbox "A/B", but not to
  51.743 +      its parent mailbox "A", the LIST command should behave as if the
  51.744 +      mailbox "A" doesn't exist, for example:
  51.745 +
  51.746 +               C: A777 LIST "" *
  51.747 +               S: * LIST (\NoInferiors) "/" "A/B"
  51.748 +               S: * LIST () "/" "C"
  51.749 +               S: * LIST (\NoInferiors) "/" "C/D"
  51.750 +               S: A777 OK LIST completed
  51.751 +
  51.752 +
  51.753 +      SUBSCRIBE - "l" right is required only if the server checks for
  51.754 +      mailbox existence when performing SUBSCRIBE.
  51.755 +
  51.756 +      UNSUBSCRIBE - no rights required to perform this operation.
  51.757 +
  51.758 +      LSUB - "l" right is required only if the server checks for mailbox
  51.759 +      existence when performing SUBSCRIBE.  However, unlike other
  51.760 +      commands (e.g., SELECT) the server MUST NOT return a NO response
  51.761 +      if it can't list a subscribed mailbox.
  51.762 +
  51.763 +   Mailbox management:
  51.764 +      CREATE - "k" right on a nearest existing parent mailbox.  When a
  51.765 +      new mailbox is created, it SHOULD inherit the ACL from the parent
  51.766 +      mailbox (if one exists) in the defined hierarchy.
  51.767 +
  51.768 +      DELETE - "x" right on the mailbox.  Note that some servers don't
  51.769 +      allow to delete a non-empty mailbox.  If this is the case, the
  51.770 +      user would also need "r", "e", and "t" rights, in order to open
  51.771 +      the mailbox and empty it.
  51.772 +
  51.773 +      The DELETE command MUST delete the ACL associated with the deleted
  51.774 +      mailbox.
  51.775 +
  51.776 +      RENAME - Moving a mailbox from one parent to another requires the
  51.777 +      "x" right on the mailbox itself and the "k" right for the new
  51.778 +      parent.  For example, if the user wants to rename the mailbox
  51.779 +      named "A/B/C" to "D/E", the user must have the "x" right for the
  51.780 +      mailbox "A/B/C" and the "k" right for the mailbox "D".
  51.781 +      The RENAME command SHOULD NOT change the ACLs on the renamed
  51.782 +      mailbox and submailboxes.
  51.783 +
  51.784 +
  51.785 +
  51.786 +
  51.787 +
  51.788 +
  51.789 +Melnikov                    Standards Track                    [Page 14]
  51.790 +
  51.791 +RFC 4314                        IMAP ACL                   December 2005
  51.792 +
  51.793 +
  51.794 +   Copying or appending messages:
  51.795 +      Before performing a COPY/APPEND command, the server MUST check if
  51.796 +      the user has "i" right for the target mailbox.  If the user
  51.797 +      doesn't have "i" right, the operation fails.  Otherwise for each
  51.798 +      copied/appended message the server MUST check if the user has
  51.799 +         "t" right - when the message has \Deleted flag set
  51.800 +         "s" right - when the message has \Seen flag set
  51.801 +         "w" right - for all other message flags.
  51.802 +      Only when the user has a particular right are the corresponding
  51.803 +      flags stored for the newly created message.  The server MUST NOT
  51.804 +      fail a COPY/APPEND if the user has no rights to set a particular
  51.805 +      flag.
  51.806 +
  51.807 +   Example:    C: A003 MYRIGHTS TargetMailbox
  51.808 +               S: * MYRIGHTS TargetMailbox rwis
  51.809 +               S: A003 OK Myrights complete
  51.810 +
  51.811 +               C: A004 FETCH 1:3 (FLAGS)
  51.812 +               S: * 1 FETCH (FLAGS (\Draft \Deleted)
  51.813 +               S: * 2 FETCH (FLAGS (\Answered)
  51.814 +               S: * 3 FETCH (FLAGS ($Forwarded \Seen)
  51.815 +               S: A004 OK Fetch Completed
  51.816 +
  51.817 +               C: A005 COPY 1:3 TargetMailbox
  51.818 +               S: A005 OK Copy completed
  51.819 +
  51.820 +               C: A006 SELECT TargetMailbox
  51.821 +                  ...
  51.822 +               S: A006 Select Completed
  51.823 +
  51.824 +      Let's assume that the copied messages received message numbers
  51.825 +      77:79.
  51.826 +
  51.827 +               C: A007 FETCH 77:79 (FLAGS)
  51.828 +               S: * 77 FETCH (FLAGS (\Draft))
  51.829 +               S: * 78 FETCH (FLAGS (\Answered))
  51.830 +               S: * 79 FETCH (FLAGS ($Forwarded \Seen))
  51.831 +               S: A007 OK Fetch Completed
  51.832 +
  51.833 +      \Deleted flag was lost on COPY, as the user has no "t" right in
  51.834 +      the target mailbox.
  51.835 +      If the MYRIGHTS command with the tag A003 would have returned:
  51.836 +
  51.837 +               S: * MYRIGHTS TargetMailbox rsti
  51.838 +
  51.839 +      the response from the FETCH with the tag A007 would have been:
  51.840 +
  51.841 +               C: A007 FETCH 77:79 (FLAGS)
  51.842 +
  51.843 +
  51.844 +
  51.845 +Melnikov                    Standards Track                    [Page 15]
  51.846 +
  51.847 +RFC 4314                        IMAP ACL                   December 2005
  51.848 +
  51.849 +
  51.850 +               S: * 77 FETCH (FLAGS (\Deleted))
  51.851 +               S: * 78 FETCH (FLAGS ())
  51.852 +               S: * 79 FETCH (FLAGS (\Seen))
  51.853 +               S: A007 OK Fetch Completed
  51.854 +
  51.855 +      In the latter case, \Answered, $Forwarded, and \Draft flags were
  51.856 +      lost on COPY, as the user has no "w" right in the target mailbox.
  51.857 +
  51.858 +   Expunging the selected mailbox:
  51.859 +      EXPUNGE - "e" right on the selected mailbox.
  51.860 +
  51.861 +      CLOSE - "e" right on the selected mailbox.  If the server is
  51.862 +      unable to expunge the mailbox because the user doesn't have the
  51.863 +      "e" right, the server MUST ignore the expunge request, close the
  51.864 +      mailbox, and return the tagged OK response.
  51.865 +
  51.866 +   Fetch information about a mailbox and its messages:
  51.867 +      SELECT/EXAMINE/STATUS - "r" right on the mailbox.
  51.868 +
  51.869 +      FETCH - A FETCH request that implies setting \Seen flag MUST NOT
  51.870 +      set it, if the current user doesn't have "s" right.
  51.871 +
  51.872 +   Changing flags:
  51.873 +      STORE - the server MUST check if the user has
  51.874 +         "t" right - when the user modifies \Deleted flag
  51.875 +         "s" right - when the user modifies \Seen flag
  51.876 +         "w" right - for all other message flags.
  51.877 +      STORE operation SHOULD NOT fail if the user has rights to modify
  51.878 +      at least one flag specified in the STORE, as the tagged NO
  51.879 +      response to a STORE command is not handled very well by deployed
  51.880 +      clients.
  51.881 +
  51.882 +   Changing ACLs:
  51.883 +      SETACL/DELETEACL - "a" right on the mailbox.
  51.884 +
  51.885 +   Reading ACLs:
  51.886 +      GETACL - "a" right on the mailbox.
  51.887 +
  51.888 +      MYRIGHTS - any of the following rights is required to perform the
  51.889 +      operation: "l", "r", "i", "k", "x", "a".
  51.890 +
  51.891 +      LISTRIGHTS - "a" right on the mailbox.
  51.892 +
  51.893 +
  51.894 +
  51.895 +
  51.896 +
  51.897 +
  51.898 +
  51.899 +
  51.900 +
  51.901 +Melnikov                    Standards Track                    [Page 16]
  51.902 +
  51.903 +RFC 4314                        IMAP ACL                   December 2005
  51.904 +
  51.905 +
  51.906 +5.  Other Considerations
  51.907 +
  51.908 +5.1.  Additional Requirements and Implementation Notes
  51.909 +
  51.910 +5.1.1.  Servers
  51.911 +
  51.912 +   This document defines an additional capability that is used to
  51.913 +   announce the list of extra rights (excluding the ones defined in RFC
  51.914 +   2086) supported by the server.  The set of rights MUST include "t",
  51.915 +   "e", "x", and "k".  Note that the extra rights can appear in any
  51.916 +   order.
  51.917 +
  51.918 +   Example:    C: 1 capability
  51.919 +               S: * CAPABILITY IMAP4REV1 STARTTLS LITERAL+
  51.920 +                  ACL RIGHTS=texk
  51.921 +               S: 1 OK completed
  51.922 +
  51.923 +   Any server implementing an ACL extension MUST accurately reflect the
  51.924 +   current user's rights in FLAGS and PERMANENTFLAGS responses.
  51.925 +
  51.926 +   Example:    C: A142 SELECT INBOX
  51.927 +               S: * 172 EXISTS
  51.928 +               S: * 1 RECENT
  51.929 +               S: * OK [UNSEEN 12] Message 12 is first unseen
  51.930 +               S: * OK [UIDVALIDITY 3857529045] UIDs valid
  51.931 +               S: * OK [UIDNEXT 4392] Predicted next UID
  51.932 +               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  51.933 +               S: * OK [PERMANENTFLAGS (\Seen \Answered \Flagged \*)] L
  51.934 +               S: A142 OK [READ-WRITE] SELECT completed
  51.935 +               C: A143 MYRIGHTS INBOX
  51.936 +               S: * MYRIGHTS INBOX lrwis
  51.937 +               S: A143 OK completed
  51.938 +
  51.939 +   Note that in order to get better performance the client MAY pipeline
  51.940 +   SELECT and MYRIGHTS commands:
  51.941 +
  51.942 +               C: A142 SELECT INBOX
  51.943 +               C: A143 MYRIGHTS INBOX
  51.944 +               S: * 172 EXISTS
  51.945 +               S: * 1 RECENT
  51.946 +               S: * OK [UNSEEN 12] Message 12 is first unseen
  51.947 +               S: * OK [UIDVALIDITY 3857529045] UIDs valid
  51.948 +               S: * OK [UIDNEXT 4392] Predicted next UID
  51.949 +               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  51.950 +               S: * OK [PERMANENTFLAGS (\Seen \Answered \Flagged \*)] L
  51.951 +               S: A142 OK [READ-WRITE] SELECT completed
  51.952 +               S: * MYRIGHTS INBOX lrwis
  51.953 +               S: A143 OK completed
  51.954 +
  51.955 +
  51.956 +
  51.957 +Melnikov                    Standards Track                    [Page 17]
  51.958 +
  51.959 +RFC 4314                        IMAP ACL                   December 2005
  51.960 +
  51.961 +
  51.962 +   Servers MAY cache the rights a user has on a mailbox when the mailbox
  51.963 +   is selected, so that if a client's rights on a mailbox are changed
  51.964 +   with SETACL or DELETEACL, commands specific to the selected state
  51.965 +   (e.g., STORE, EXPUNGE) might not reflect the changed rights until the
  51.966 +   mailbox is re-selected.  If the server checks the rights on each
  51.967 +   command, then it SHOULD send FLAGS and PERMANENTFLAGS responses if
  51.968 +   they have changed.  If such server detects that the user no longer
  51.969 +   has read access to the mailbox, it MAY send an untagged BYE response
  51.970 +   and close connection.  It MAY also refuse to execute all commands
  51.971 +   specific to the selected state until the mailbox is closed; however,
  51.972 +   server implementors should note that most clients don't handle NO
  51.973 +   responses very well.
  51.974 +
  51.975 +   An ACL server MAY modify one or more ACLs for one or more identifiers
  51.976 +   as a side effect of modifying the ACL specified in a
  51.977 +   SETACL/DELETEACL.  If the server does that, it MUST send untagged ACL
  51.978 +   response(s) to notify the client about the changes made.
  51.979 +
  51.980 +   An ACL server implementation MUST treat received ACL modification
  51.981 +   commands as a possible ambiguity with respect to subsequent commands
  51.982 +   affected by the ACL, as described in Section 5.5 of [IMAP4].  Hence a
  51.983 +   pipeline SETACL + MYRIGHTS is an ambiguity with respect to the
  51.984 +   server, meaning that the server must execute the SETACL command to
  51.985 +   completion before the MYRIGHTS.  However, clients are permitted to
  51.986 +   send such a pipeline.
  51.987 +
  51.988 +5.1.2.  Clients
  51.989 +
  51.990 +   The following requirement is put on clients in order to allow for
  51.991 +   future extensibility.  A client implementation that allows a user to
  51.992 +   read and update ACLs MUST preserve unrecognized rights that it
  51.993 +   doesn't allow the user to change.  That is, if the client
  51.994 +
  51.995 +   1) can read ACLs
  51.996 +    and
  51.997 +   2) can update ACLs
  51.998 +    but
  51.999 +   3) doesn't allow the user to change the rights the client doesn't
 51.1000 +   recognize, then it MUST preserve unrecognized rights.
 51.1001 +
 51.1002 +   Otherwise the client could risk unintentionally removing permissions
 51.1003 +   it doesn't understand.
 51.1004 +
 51.1005 +
 51.1006 +
 51.1007 +
 51.1008 +
 51.1009 +
 51.1010 +
 51.1011 +
 51.1012 +
 51.1013 +Melnikov                    Standards Track                    [Page 18]
 51.1014 +
 51.1015 +RFC 4314                        IMAP ACL                   December 2005
 51.1016 +
 51.1017 +
 51.1018 +5.2.  Mapping of ACL Rights to READ-WRITE and READ-ONLY Response Codes
 51.1019 +
 51.1020 +   A particular ACL server implementation MAY allow "shared multiuser
 51.1021 +   access" to some mailboxes.  "Shared multiuser access" to a mailbox
 51.1022 +   means that multiple different users are able to access the same
 51.1023 +   mailbox, if they have proper access rights.  "Shared multiuser
 51.1024 +   access" to the mailbox doesn't mean that the ACL for the mailbox is
 51.1025 +   currently set to allow access by multiple users.  Let's denote a
 51.1026 +   "shared multiuser write access" as a "shared multiuser access" when a
 51.1027 +   user can be granted flag modification rights (any of "w", "s", or
 51.1028 +   "t").
 51.1029 +
 51.1030 +   Section 4 describes which rights are required for modifying different
 51.1031 +   flags.
 51.1032 +
 51.1033 +   If the ACL server implements some flags as shared for a mailbox
 51.1034 +   (i.e., the ACL for the mailbox MAY be set up so that changes to those
 51.1035 +   flags are visible to another user), let's call the set of rights
 51.1036 +   associated with these flags (as described in Section 4) for that
 51.1037 +   mailbox collectively as "shared flag rights".  Note that the "shared
 51.1038 +   flag rights" set MAY be different for different mailboxes.
 51.1039 +
 51.1040 +   If the server doesn't support "shared multiuser write access" to a
 51.1041 +   mailbox or doesn't implement shared flags on the mailbox, "shared
 51.1042 +   flag rights" for the mailbox is defined to be the empty set.
 51.1043 +
 51.1044 +   Example 1: Mailbox "banan" allows "shared multiuser write access" and
 51.1045 +              implements flags \Deleted, \Answered, and $MDNSent as
 51.1046 +              shared flags. "Shared flag rights" for the mailbox "banan"
 51.1047 +              is a set containing flags "t" (because system flag
 51.1048 +              \Deleted requires "t" right) and "w" (because both
 51.1049 +              \Answered and $MDNSent require "w" right).
 51.1050 +
 51.1051 +   Example 2: Mailbox "apple" allows "shared multiuser write access" and
 51.1052 +              implements \Seen system flag as shared flag. "Shared flag
 51.1053 +              rights" for the mailbox "apple" contains "s" right
 51.1054 +              because system flag \Seen requires "s" right.
 51.1055 +
 51.1056 +   Example 3: Mailbox "pear" allows "shared multiuser write access" and
 51.1057 +              implements flags \Seen, \Draft as shared flags. "Shared
 51.1058 +              flag rights" for the mailbox "apple" is a set containing
 51.1059 +              flags "s" (because system flag \Seen requires "s" right)
 51.1060 +              and "w" (because system flag \Draft requires "w" right).
 51.1061 +
 51.1062 +   The server MUST include a READ-ONLY response code in the tagged OK
 51.1063 +   response to a SELECT command if none of the following rights is
 51.1064 +   granted to the current user:
 51.1065 +
 51.1066 +
 51.1067 +
 51.1068 +
 51.1069 +Melnikov                    Standards Track                    [Page 19]
 51.1070 +
 51.1071 +RFC 4314                        IMAP ACL                   December 2005
 51.1072 +
 51.1073 +
 51.1074 +    "i", "e", and "shared flag rights"(***).
 51.1075 +
 51.1076 +   The server SHOULD include a READ-WRITE response code in the tagged OK
 51.1077 +   response if at least one of the "i", "e", or "shared flag
 51.1078 +   rights"(***) is granted to the current user.
 51.1079 +
 51.1080 +   (***) Note that a future extension to this document can extend the
 51.1081 +   list of rights that causes the server to return the READ-WRITE
 51.1082 +   response code.
 51.1083 +
 51.1084 +   Example 1 (continued): The user that has "lrs" rights for the mailbox
 51.1085 +                          "banan".  The server returns READ-ONLY
 51.1086 +                          response code on SELECT, as none of "iewt"
 51.1087 +                          rights is granted to the user.
 51.1088 +
 51.1089 +   Example 2 (continued): The user that has "rit" rights for the mailbox
 51.1090 +                          "apple".  The server returns READ-WRITE
 51.1091 +                          response code on SELECT, as the user has "i"
 51.1092 +                          right.
 51.1093 +
 51.1094 +   Example 3 (continued): The user that has "rset" rights for the
 51.1095 +                          mailbox "pear".  The server returns READ-WRITE
 51.1096 +                          response code on SELECT, as the user has "e"
 51.1097 +                          and "s" rights.
 51.1098 +
 51.1099 +6.  Security Considerations
 51.1100 +
 51.1101 +   An implementation MUST make sure the ACL commands themselves do not
 51.1102 +   give information about mailboxes with appropriately restricted ACLs.
 51.1103 +   For example, when a user agent executes a GETACL command on a mailbox
 51.1104 +   that the user has no permission to LIST, the server would respond to
 51.1105 +   that request with the same error that would be used if the mailbox
 51.1106 +   did not exist, thus revealing no existence information, much less the
 51.1107 +   mailbox's ACL.
 51.1108 +
 51.1109 +   IMAP clients implementing ACL that are able to modify ACLs SHOULD
 51.1110 +   warn a user that wants to give full access (or even just the "a"
 51.1111 +   right) to the special identifier "anyone".
 51.1112 +
 51.1113 +   This document relies on [SASLprep] to describe steps required to
 51.1114 +   perform identifier canonicalization (preparation).  The preparation
 51.1115 +   algorithm in SASLprep was specifically designed such that its output
 51.1116 +   is canonical, and it is well-formed.  However, due to an anomaly
 51.1117 +   [PR29] in the specification of Unicode normalization, canonical
 51.1118 +   equivalence is not guaranteed for a select few character sequences.
 51.1119 +   Identifiers prepared with SASLprep can be stored and returned by an
 51.1120 +   ACL server.  The anomaly affects ACL manipulation and evaluation of
 51.1121 +   identifiers containing the selected character sequences.  These
 51.1122 +
 51.1123 +
 51.1124 +
 51.1125 +Melnikov                    Standards Track                    [Page 20]
 51.1126 +
 51.1127 +RFC 4314                        IMAP ACL                   December 2005
 51.1128 +
 51.1129 +
 51.1130 +   sequences, however, do not appear in well-formed text.  In order to
 51.1131 +   address this problem, an ACL server MAY reject identifiers containing
 51.1132 +   sequences described in [PR29] by sending the tagged BAD response.
 51.1133 +   This is in addition to the requirement to reject identifiers that
 51.1134 +   fail SASLprep preparation as described in Section 3.
 51.1135 +
 51.1136 +   Other security considerations described in [IMAP4] are relevant to
 51.1137 +   this document.  In particular, ACL information is sent in the clear
 51.1138 +   over the network unless confidentiality protection is negotiated.
 51.1139 +
 51.1140 +   This can be accomplished either by the use of STARTTLS, negotiated
 51.1141 +   privacy protection in the AUTHENTICATE command, or some other
 51.1142 +   protection mechanism.
 51.1143 +
 51.1144 +7.  Formal Syntax
 51.1145 +
 51.1146 +   Formal syntax is defined using ABNF [ABNF], extending the ABNF rules
 51.1147 +   in Section 9 of [IMAP4].  Elements not defined here can be found in
 51.1148 +   [ABNF] and [IMAP4].
 51.1149 +
 51.1150 +   Except as noted otherwise, all alphabetic characters are case
 51.1151 +   insensitive.  The use of uppercase or lowercase characters to define
 51.1152 +   token strings is for editorial clarity only.  Implementations MUST
 51.1153 +   accept these strings in a case-insensitive fashion.
 51.1154 +
 51.1155 +   LOWER-ALPHA     =  %x61-7A   ;; a-z
 51.1156 +
 51.1157 +   acl-data        = "ACL" SP mailbox *(SP identifier SP
 51.1158 +                       rights)
 51.1159 +
 51.1160 +   capability      =/ rights-capa
 51.1161 +                       ;;capability is defined in [IMAP4]
 51.1162 +
 51.1163 +   command-auth    =/ setacl / deleteacl / getacl /
 51.1164 +                       listrights / myrights
 51.1165 +                       ;;command-auth is defined in [IMAP4]
 51.1166 +
 51.1167 +   deleteacl       = "DELETEACL" SP mailbox SP identifier
 51.1168 +
 51.1169 +   getacl          = "GETACL" SP mailbox
 51.1170 +
 51.1171 +   identifier      = astring
 51.1172 +
 51.1173 +   listrights      = "LISTRIGHTS" SP mailbox SP identifier
 51.1174 +
 51.1175 +   listrights-data = "LISTRIGHTS" SP mailbox SP identifier
 51.1176 +                           SP rights *(SP rights)
 51.1177 +
 51.1178 +
 51.1179 +
 51.1180 +
 51.1181 +Melnikov                    Standards Track                    [Page 21]
 51.1182 +
 51.1183 +RFC 4314                        IMAP ACL                   December 2005
 51.1184 +
 51.1185 +
 51.1186 +   mailbox-data    =/ acl-data / listrights-data / myrights-data
 51.1187 +                       ;;mailbox-data is defined in [IMAP4]
 51.1188 +
 51.1189 +   mod-rights      = astring
 51.1190 +                       ;; +rights to add, -rights to remove
 51.1191 +                       ;; rights to replace
 51.1192 +
 51.1193 +   myrights        = "MYRIGHTS" SP mailbox
 51.1194 +
 51.1195 +   myrights-data   = "MYRIGHTS" SP mailbox SP rights
 51.1196 +
 51.1197 +   new-rights      = 1*LOWER-ALPHA
 51.1198 +                       ;; MUST include "t", "e", "x", and "k".
 51.1199 +                       ;; MUST NOT include standard rights listed
 51.1200 +                       ;; in section 2.2
 51.1201 +
 51.1202 +   rights          = astring
 51.1203 +                       ;; only lowercase ASCII letters and digits
 51.1204 +                       ;; are allowed.
 51.1205 +
 51.1206 +   rights-capa     = "RIGHTS=" new-rights
 51.1207 +                       ;; RIGHTS=... capability
 51.1208 +
 51.1209 +   setacl          = "SETACL" SP mailbox SP identifier
 51.1210 +                       SP mod-rights
 51.1211 +
 51.1212 +8.  IANA Considerations
 51.1213 +
 51.1214 +   IMAP4 capabilities are registered by publishing a standards-track or
 51.1215 +   IESG-approved experimental RFC.  The registry is currently located
 51.1216 +   at:
 51.1217 +
 51.1218 +      http://www.iana.org/assignments/imap4-capabilities
 51.1219 +
 51.1220 +   This document defines the RIGHTS= IMAP capability.  IANA has added
 51.1221 +   this capability to the registry.
 51.1222 +
 51.1223 +9.  Internationalization Considerations
 51.1224 +
 51.1225 +   Section 3 states requirements on servers regarding
 51.1226 +   internationalization of identifiers.
 51.1227 +
 51.1228 +
 51.1229 +
 51.1230 +
 51.1231 +
 51.1232 +
 51.1233 +
 51.1234 +
 51.1235 +
 51.1236 +
 51.1237 +Melnikov                    Standards Track                    [Page 22]
 51.1238 +
 51.1239 +RFC 4314                        IMAP ACL                   December 2005
 51.1240 +
 51.1241 +
 51.1242 +Appendix A.  Changes since RFC 2086
 51.1243 +
 51.1244 +   1.   Changed the charset of "identifier" from US-ASCII to UTF-8.
 51.1245 +   2.   Specified that mailbox deletion is controlled by the "x" right
 51.1246 +        and EXPUNGE is controlled by the "e" right.
 51.1247 +   3.   Added the "t" right that controls STORE \Deleted.  Redefined the
 51.1248 +        "d" right to be a macro for "e", "t", and possibly "x".
 51.1249 +   4.   Added the "k" right that controls CREATE.  Redefined the "c"
 51.1250 +        right to be a macro for "k" and possibly "x".
 51.1251 +   5.   Specified that the "a" right also controls DELETEACL.
 51.1252 +   6.   Specified that the "r" right also controls STATUS.
 51.1253 +   7.   Removed the requirement to check the "r" right for CHECK, SEARCH
 51.1254 +        and FETCH, as this is required for SELECT/EXAMINE to be
 51.1255 +        successful.
 51.1256 +   8.   LISTRIGHTS requires the "a" right on the mailbox (same as
 51.1257 +        SETACL).
 51.1258 +   9.   Deleted "PARTIAL", this is a deprecated feature of RFC 1730.
 51.1259 +   10.  Specified that the "w" right controls setting flags other than
 51.1260 +        \Seen and \Deleted on APPEND.  Also specified that the "s" right
 51.1261 +        controls the \Seen flag and that the "t" right controls the
 51.1262 +        \Deleted flag.
 51.1263 +   11.  Specified that SUBSCRIBE is NOT allowed with the "r" right.
 51.1264 +   12.  Specified that the "l" right controls SUBSCRIBE.
 51.1265 +   13.  GETACL is NOT allowed with the "r" right, even though there are
 51.1266 +        several implementations that allows that.  If a user only has
 51.1267 +        "r" right, GETACL can disclose information about identifiers
 51.1268 +        existing on the mail system.
 51.1269 +   14.  Clarified that RENAME requires the "k" right for the new parent
 51.1270 +        and the "x" right for the old name.
 51.1271 +   15.  Added new section that describes which rights are required
 51.1272 +        and/or checked when performing various IMAP commands.
 51.1273 +   16.  Added mail client security considerations when dealing with
 51.1274 +        special identifier "anyone".
 51.1275 +   17.  Clarified that negative rights are not the same as DELETEACL.
 51.1276 +   18.  Added "Compatibility with RFC 2086" section.
 51.1277 +   19.  Added section about mapping of ACL rights to READ-WRITE and
 51.1278 +        READ-ONLY response codes.
 51.1279 +   20.  Changed BNF to ABNF.
 51.1280 +   21.  Added "Implementation Notes" section.
 51.1281 +   22.  Updated "References" section.
 51.1282 +   23.  Added more examples.
 51.1283 +   24.  Clarified when the virtual "c" and "d" rights are returned in
 51.1284 +        ACL, MYRIGHTS, and LISTRIGHTS responses.
 51.1285 +
 51.1286 +
 51.1287 +
 51.1288 +
 51.1289 +
 51.1290 +
 51.1291 +
 51.1292 +
 51.1293 +Melnikov                    Standards Track                    [Page 23]
 51.1294 +
 51.1295 +RFC 4314                        IMAP ACL                   December 2005
 51.1296 +
 51.1297 +
 51.1298 +Appendix B.  Compatibility with RFC 2086
 51.1299 +
 51.1300 +   This non-normative section gives guidelines as to how an existing RFC
 51.1301 +   2086 server implementation may be updated to comply with this
 51.1302 +   document.
 51.1303 +
 51.1304 +   This document splits the "d" right into several new different rights:
 51.1305 +   "t", "e", and possibly "x" (see Section 2.1.1 for more details).  The
 51.1306 +   "d" right remains for backward-compatibility, but it is a virtual
 51.1307 +   right.  There are two approaches for RFC 2086 server implementors to
 51.1308 +   handle the "d" right and the new rights that have replaced it:
 51.1309 +
 51.1310 +   a.  Tie "t", "e" (and possibly "x) together - almost no changes.
 51.1311 +   b.  Implement separate "x", "t" and "e".  Return the "d" right in a
 51.1312 +       MYRIGHTS response or an ACL response containing ACL information
 51.1313 +       when any of the "t", "e" (and "x") is granted.
 51.1314 +
 51.1315 +   In a similar manner this document splits the "c" right into several
 51.1316 +   new different rights: "k" and possibly "x" (see Section 2.1.1 for
 51.1317 +   more details).  The "c" right remains for backwards-compatibility but
 51.1318 +   it is a virtual right.  Again, RFC 2086 server implementors can
 51.1319 +   choose to tie rights or to implement separate rights, as described
 51.1320 +   above.
 51.1321 +
 51.1322 +   Also check Sections 5.1.1 and 5.1.2, as well as Appendix A, to see
 51.1323 +   other changes required.  Server implementors should check which
 51.1324 +   rights are required to invoke different IMAP4 commands as described
 51.1325 +   in Section 4.
 51.1326 +
 51.1327 +Appendix C.  Known Deficiencies
 51.1328 +
 51.1329 +   This specification has some known deficiencies including:
 51.1330 +
 51.1331 +   1.  This is inadequate to provide complete read-write access to
 51.1332 +       mailboxes protected by Unix-style rights bits because there is no
 51.1333 +       equivalent to "chown" and "chgrp" commands nor is there a good
 51.1334 +       way to discover such limitations are present.
 51.1335 +   2.  Because this extension leaves the specific semantics of how
 51.1336 +       rights are combined by the server as implementation defined, the
 51.1337 +       ability to build a user-friendly interface is limited.
 51.1338 +   3.  Users, groups, and special identifiers (e.g., anyone) exist in
 51.1339 +       the same namespace.
 51.1340 +
 51.1341 +   The work-in-progress "ACL2" extension is intended to redesign this
 51.1342 +   extension to address these deficiencies without the constraint of
 51.1343 +   backward-compatibility and may eventually supercede this facility.
 51.1344 +
 51.1345 +
 51.1346 +
 51.1347 +
 51.1348 +
 51.1349 +Melnikov                    Standards Track                    [Page 24]
 51.1350 +
 51.1351 +RFC 4314                        IMAP ACL                   December 2005
 51.1352 +
 51.1353 +
 51.1354 +   However, RFC 2086 is deployed in multiple implementations so this
 51.1355 +   intermediate step, which fixes the straightforward deficiencies in a
 51.1356 +   backward-compatible fashion, is considered worthwhile.
 51.1357 +
 51.1358 +Appendix D.  Acknowledgements
 51.1359 +
 51.1360 +   This document is a revision of RFC 2086 written by John G. Myers.
 51.1361 +
 51.1362 +   Editor appreciates comments received from Mark Crispin, Chris Newman,
 51.1363 +   Cyrus Daboo, John G. Myers, Dave Cridland, Ken Murchison, Steve Hole,
 51.1364 +   Vladimir Butenko, Larry Greenfield, Robert Siemborski, Harrie
 51.1365 +   Hazewinkel, Philip Guenther, Brian Candler, Curtis King, Lyndon
 51.1366 +   Nerenberg, Lisa Dusseault, Arnt Gulbrandsen, and other participants
 51.1367 +   of the IMAPEXT working group.
 51.1368 +
 51.1369 +Normative References
 51.1370 +
 51.1371 +   [KEYWORDS]   Bradner, S., "Key words for use in RFCs to Indicate
 51.1372 +                Requirement Levels", BCP 14, RFC 2119, March 1997.
 51.1373 +
 51.1374 +   [ABNF]       Crocker, D. and P. Overell, "Augmented BNF for Syntax
 51.1375 +                Specifications: ABNF", RFC 4234, October 2005.
 51.1376 +
 51.1377 +   [IMAP4]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
 51.1378 +                4rev1", RFC 3501, March 2003.
 51.1379 +
 51.1380 +   [UTF-8]      Yergeau, F., "UTF-8, a transformation format of ISO
 51.1381 +                10646", STD 63, RFC 3629, November 2003.
 51.1382 +
 51.1383 +   [Stringprep] Hoffman, P. and M. Blanchet, "Preparation of
 51.1384 +                Internationalized Strings ("stringprep")", RFC 3454,
 51.1385 +                December 2002.
 51.1386 +
 51.1387 +   [SASLprep]   Zeilenga, K., "SASLprep: Stringprep Profile for User
 51.1388 +                Names and Passwords", RFC 4013, February 2005.
 51.1389 +
 51.1390 +Informative References
 51.1391 +
 51.1392 +   [RFC2086]    Myers, J., "IMAP4 ACL extension", RFC 2086,
 51.1393 +                January 1997.
 51.1394 +
 51.1395 +   [PR29]       "Public Review Issue #29: Normalization Issue",
 51.1396 +                February 2004,
 51.1397 +                <http://www.unicode.org/review/pr-29.html>.
 51.1398 +
 51.1399 +
 51.1400 +
 51.1401 +
 51.1402 +
 51.1403 +
 51.1404 +
 51.1405 +Melnikov                    Standards Track                    [Page 25]
 51.1406 +
 51.1407 +RFC 4314                        IMAP ACL                   December 2005
 51.1408 +
 51.1409 +
 51.1410 +Author's Address
 51.1411 +
 51.1412 +   Alexey Melnikov
 51.1413 +   Isode Ltd.
 51.1414 +   5 Castle Business Village
 51.1415 +   36 Station Road
 51.1416 +   Hampton, Middlesex  TW12 2BX
 51.1417 +   GB
 51.1418 +
 51.1419 +   EMail: alexey.melnikov@isode.com
 51.1420 +
 51.1421 +
 51.1422 +
 51.1423 +
 51.1424 +
 51.1425 +
 51.1426 +
 51.1427 +
 51.1428 +
 51.1429 +
 51.1430 +
 51.1431 +
 51.1432 +
 51.1433 +
 51.1434 +
 51.1435 +
 51.1436 +
 51.1437 +
 51.1438 +
 51.1439 +
 51.1440 +
 51.1441 +
 51.1442 +
 51.1443 +
 51.1444 +
 51.1445 +
 51.1446 +
 51.1447 +
 51.1448 +
 51.1449 +
 51.1450 +
 51.1451 +
 51.1452 +
 51.1453 +
 51.1454 +
 51.1455 +
 51.1456 +
 51.1457 +
 51.1458 +
 51.1459 +
 51.1460 +
 51.1461 +Melnikov                    Standards Track                    [Page 26]
 51.1462 +
 51.1463 +RFC 4314                        IMAP ACL                   December 2005
 51.1464 +
 51.1465 +
 51.1466 +Full Copyright Statement
 51.1467 +
 51.1468 +   Copyright (C) The Internet Society (2005).
 51.1469 +
 51.1470 +   This document is subject to the rights, licenses and restrictions
 51.1471 +   contained in BCP 78, and except as set forth therein, the authors
 51.1472 +   retain all their rights.
 51.1473 +
 51.1474 +   This document and the information contained herein are provided on an
 51.1475 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 51.1476 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
 51.1477 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
 51.1478 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
 51.1479 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 51.1480 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 51.1481 +
 51.1482 +Intellectual Property
 51.1483 +
 51.1484 +   The IETF takes no position regarding the validity or scope of any
 51.1485 +   Intellectual Property Rights or other rights that might be claimed to
 51.1486 +   pertain to the implementation or use of the technology described in
 51.1487 +   this document or the extent to which any license under such rights
 51.1488 +   might or might not be available; nor does it represent that it has
 51.1489 +   made any independent effort to identify any such rights.  Information
 51.1490 +   on the procedures with respect to rights in RFC documents can be
 51.1491 +   found in BCP 78 and BCP 79.
 51.1492 +
 51.1493 +   Copies of IPR disclosures made to the IETF Secretariat and any
 51.1494 +   assurances of licenses to be made available, or the result of an
 51.1495 +   attempt made to obtain a general license or permission for the use of
 51.1496 +   such proprietary rights by implementers or users of this
 51.1497 +   specification can be obtained from the IETF on-line IPR repository at
 51.1498 +   http://www.ietf.org/ipr.
 51.1499 +
 51.1500 +   The IETF invites any interested party to bring to its attention any
 51.1501 +   copyrights, patents or patent applications, or other proprietary
 51.1502 +   rights that may cover technology that may be required to implement
 51.1503 +   this standard.  Please address the information to the IETF at ietf-
 51.1504 +   ipr@ietf.org.
 51.1505 +
 51.1506 +Acknowledgement
 51.1507 +
 51.1508 +   Funding for the RFC Editor function is currently provided by the
 51.1509 +   Internet Society.
 51.1510 +
 51.1511 +
 51.1512 +
 51.1513 +
 51.1514 +
 51.1515 +
 51.1516 +
 51.1517 +Melnikov                    Standards Track                    [Page 27]
 51.1518 +
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/docs/rfc/rfc4315.txt	Mon Sep 14 15:17:45 2009 +0900
    52.3 @@ -0,0 +1,451 @@
    52.4 +
    52.5 +
    52.6 +
    52.7 +
    52.8 +
    52.9 +
   52.10 +Network Working Group                                         M. Crispin
   52.11 +Request for Comments: 4315                                 December 2005
   52.12 +Obsoletes: 2359
   52.13 +Category: Standards Track
   52.14 +
   52.15 +
   52.16 +      Internet Message Access Protocol (IMAP) - UIDPLUS extension
   52.17 +
   52.18 +Status of This Memo
   52.19 +
   52.20 +   This document specifies an Internet standards track protocol for the
   52.21 +   Internet community, and requests discussion and suggestions for
   52.22 +   improvements.  Please refer to the current edition of the "Internet
   52.23 +   Official Protocol Standards" (STD 1) for the standardization state
   52.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   52.25 +
   52.26 +Copyright Notice
   52.27 +
   52.28 +   Copyright (C) The Internet Society (2005).
   52.29 +
   52.30 +Abstract
   52.31 +
   52.32 +   The UIDPLUS extension of the Internet Message Access Protocol (IMAP)
   52.33 +   provides a set of features intended to reduce the amount of time and
   52.34 +   resources used by some client operations.  The features in UIDPLUS
   52.35 +   are primarily intended for disconnected-use clients.
   52.36 +
   52.37 +1.  Introduction and Overview
   52.38 +
   52.39 +   The UIDPLUS extension is present in any IMAP server implementation
   52.40 +   that returns "UIDPLUS" as one of the supported capabilities to the
   52.41 +   CAPABILITY command.
   52.42 +
   52.43 +   The UIDPLUS extension defines an additional command.  In addition,
   52.44 +   this document recommends new status response codes in IMAP that
   52.45 +   SHOULD be returned by all server implementations, regardless of
   52.46 +   whether or not the UIDPLUS extension is implemented.
   52.47 +
   52.48 +   The added facilities of the features in UIDPLUS are optimizations;
   52.49 +   clients can provide equivalent functionality, albeit less
   52.50 +   efficiently, by using facilities in the base protocol.
   52.51 +
   52.52 +1.1.  Conventions Used in This Document
   52.53 +
   52.54 +   In examples, "C:" and "S:" indicate lines sent by the client and
   52.55 +   server, respectively.
   52.56 +
   52.57 +
   52.58 +
   52.59 +
   52.60 +
   52.61 +Crispin                     Standards Track                     [Page 1]
   52.62 +
   52.63 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
   52.64 +
   52.65 +
   52.66 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   52.67 +   "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
   52.68 +   be interpreted as described in [KEYWORDS].
   52.69 +
   52.70 +   A "UID set" is similar to the [IMAP] sequence set; however, the "*"
   52.71 +   value for a sequence number is not permitted.
   52.72 +
   52.73 +2.  Additional Commands
   52.74 +
   52.75 +   The following command definition is an extension to [IMAP] section
   52.76 +   6.4.
   52.77 +
   52.78 +2.1.  UID EXPUNGE Command
   52.79 +
   52.80 +   Arguments:  sequence set
   52.81 +
   52.82 +   Data:       untagged responses: EXPUNGE
   52.83 +
   52.84 +   Result:     OK - expunge completed
   52.85 +               NO - expunge failure (e.g., permission denied)
   52.86 +               BAD - command unknown or arguments invalid
   52.87 +
   52.88 +      The UID EXPUNGE command permanently removes all messages that both
   52.89 +      have the \Deleted flag set and have a UID that is included in the
   52.90 +      specified sequence set from the currently selected mailbox.  If a
   52.91 +      message either does not have the \Deleted flag set or has a UID
   52.92 +      that is not included in the specified sequence set, it is not
   52.93 +      affected.
   52.94 +
   52.95 +      This command is particularly useful for disconnected use clients.
   52.96 +      By using UID EXPUNGE instead of EXPUNGE when resynchronizing with
   52.97 +      the server, the client can ensure that it does not inadvertantly
   52.98 +      remove any messages that have been marked as \Deleted by other
   52.99 +      clients between the time that the client was last connected and
  52.100 +      the time the client resynchronizes.
  52.101 +
  52.102 +      If the server does not support the UIDPLUS capability, the client
  52.103 +      should fall back to using the STORE command to temporarily remove
  52.104 +      the \Deleted flag from messages it does not want to remove, then
  52.105 +      issuing the EXPUNGE command.  Finally, the client should use the
  52.106 +      STORE command to restore the \Deleted flag on the messages in
  52.107 +      which it was temporarily removed.
  52.108 +
  52.109 +      Alternatively, the client may fall back to using just the EXPUNGE
  52.110 +      command, risking the unintended removal of some messages.
  52.111 +
  52.112 +
  52.113 +
  52.114 +
  52.115 +
  52.116 +
  52.117 +Crispin                     Standards Track                     [Page 2]
  52.118 +
  52.119 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
  52.120 +
  52.121 +
  52.122 +   Example:    C: A003 UID EXPUNGE 3000:3002
  52.123 +               S: * 3 EXPUNGE
  52.124 +               S: * 3 EXPUNGE
  52.125 +               S: * 3 EXPUNGE
  52.126 +               S: A003 OK UID EXPUNGE completed
  52.127 +
  52.128 +3.  Additional Response Codes
  52.129 +
  52.130 +   The following response codes are extensions to the response codes
  52.131 +   defined in [IMAP] section 7.1.  With limited exceptions, discussed
  52.132 +   below, server implementations that advertise the UIDPLUS extension
  52.133 +   SHOULD return these response codes.
  52.134 +
  52.135 +   In the case of a mailbox that has permissions set so that the client
  52.136 +   can COPY or APPEND to the mailbox, but not SELECT or EXAMINE it, the
  52.137 +   server SHOULD NOT send an APPENDUID or COPYUID response code as it
  52.138 +   would disclose information about the mailbox.
  52.139 +
  52.140 +   In the case of a mailbox that has UIDNOTSTICKY status (as defined
  52.141 +   below), the server MAY omit the APPENDUID or COPYUID response code as
  52.142 +   it is not meaningful.
  52.143 +
  52.144 +   If the server does not return the APPENDUID or COPYUID response
  52.145 +   codes, the client can discover this information by selecting the
  52.146 +   destination mailbox.  The location of messages placed in the
  52.147 +   destination mailbox by COPY or APPEND can be determined by using
  52.148 +   FETCH and/or SEARCH commands (e.g., for Message-ID or some unique
  52.149 +   marker placed in the message in an APPEND).
  52.150 +
  52.151 +   APPENDUID
  52.152 +
  52.153 +      Followed by the UIDVALIDITY of the destination mailbox and the UID
  52.154 +      assigned to the appended message in the destination mailbox,
  52.155 +      indicates that the message has been appended to the destination
  52.156 +      mailbox with that UID.
  52.157 +
  52.158 +      If the server also supports the [MULTIAPPEND] extension, and if
  52.159 +      multiple messages were appended in the APPEND command, then the
  52.160 +      second value is a UID set containing the UIDs assigned to the
  52.161 +      appended messages, in the order they were transmitted in the
  52.162 +      APPEND command.  This UID set may not contain extraneous UIDs or
  52.163 +      the symbol "*".
  52.164 +
  52.165 +         Note: the UID set form of the APPENDUID response code MUST NOT
  52.166 +         be used if only a single message was appended.  In particular,
  52.167 +         a server MUST NOT send a range such as 123:123.  This is
  52.168 +         because a client that does not support [MULTIAPPEND] expects
  52.169 +         only a single UID and not a UID set.
  52.170 +
  52.171 +
  52.172 +
  52.173 +Crispin                     Standards Track                     [Page 3]
  52.174 +
  52.175 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
  52.176 +
  52.177 +
  52.178 +      UIDs are assigned in strictly ascending order in the mailbox
  52.179 +      (refer to [IMAP], section 2.3.1.1) and UID ranges are as in
  52.180 +      [IMAP]; in particular, note that a range of 12:10 is exactly
  52.181 +      equivalent to 10:12 and refers to the sequence 10,11,12.
  52.182 +
  52.183 +      This response code is returned in a tagged OK response to the
  52.184 +      APPEND command.
  52.185 +
  52.186 +   COPYUID
  52.187 +
  52.188 +      Followed by the UIDVALIDITY of the destination mailbox, a UID set
  52.189 +      containing the UIDs of the message(s) in the source mailbox that
  52.190 +      were copied to the destination mailbox and containing the UIDs
  52.191 +      assigned to the copied message(s) in the destination mailbox,
  52.192 +      indicates that the message(s) have been copied to the destination
  52.193 +      mailbox with the stated UID(s).
  52.194 +
  52.195 +      The source UID set is in the order the message(s) were copied; the
  52.196 +      destination UID set corresponds to the source UID set and is in
  52.197 +      the same order.  Neither of the UID sets may contain extraneous
  52.198 +      UIDs or the symbol "*".
  52.199 +
  52.200 +      UIDs are assigned in strictly ascending order in the mailbox
  52.201 +      (refer to [IMAP], section 2.3.1.1) and UID ranges are as in
  52.202 +      [IMAP]; in particular, note that a range of 12:10 is exactly
  52.203 +      equivalent to 10:12 and refers to the sequence 10,11,12.
  52.204 +
  52.205 +      This response code is returned in a tagged OK response to the COPY
  52.206 +      command.
  52.207 +
  52.208 +   UIDNOTSTICKY
  52.209 +
  52.210 +      The selected mailbox is supported by a mail store that does not
  52.211 +      support persistent UIDs; that is, UIDVALIDITY will be different
  52.212 +      each time the mailbox is selected.  Consequently, APPEND or COPY
  52.213 +      to this mailbox will not return an APPENDUID or COPYUID response
  52.214 +      code.
  52.215 +
  52.216 +      This response code is returned in an untagged NO response to the
  52.217 +      SELECT command.
  52.218 +
  52.219 +         Note: servers SHOULD NOT have any UIDNOTSTICKY mail stores.
  52.220 +         This facility exists to support legacy mail stores in which it
  52.221 +         is technically infeasible to support persistent UIDs.  This
  52.222 +         should be avoided when designing new mail stores.
  52.223 +
  52.224 +
  52.225 +
  52.226 +
  52.227 +
  52.228 +
  52.229 +Crispin                     Standards Track                     [Page 4]
  52.230 +
  52.231 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
  52.232 +
  52.233 +
  52.234 +   Example:    C: A003 APPEND saved-messages (\Seen) {297}
  52.235 +               C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  52.236 +               C: From: Fred Foobar <foobar@example.com>
  52.237 +               C: Subject: afternoon meeting
  52.238 +               C: To: mooch@example.com
  52.239 +               C: Message-Id: <B27397-0100000@example.com>
  52.240 +               C: MIME-Version: 1.0
  52.241 +               C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  52.242 +               C:
  52.243 +               C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  52.244 +               C:
  52.245 +               S: A003 OK [APPENDUID 38505 3955] APPEND completed
  52.246 +               C: A004 COPY 2:4 meeting
  52.247 +               S: A004 OK [COPYUID 38505 304,319:320 3956:3958] Done
  52.248 +               C: A005 UID COPY 305:310 meeting
  52.249 +               S: A005 OK No matching messages, so nothing copied
  52.250 +               C: A006 COPY 2 funny
  52.251 +               S: A006 OK Done
  52.252 +               C: A007 SELECT funny
  52.253 +               S: * 1 EXISTS
  52.254 +               S: * 1 RECENT
  52.255 +               S: * OK [UNSEEN 1] Message 1 is first unseen
  52.256 +               S: * OK [UIDVALIDITY 3857529045] Validity session-only
  52.257 +               S: * OK [UIDNEXT 2] Predicted next UID
  52.258 +               S: * NO [UIDNOTSTICKY] Non-persistent UIDs
  52.259 +               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  52.260 +               S: * OK [PERMANENTFLAGS (\Deleted \Seen)] Limited
  52.261 +               S: A007 OK [READ-WRITE] SELECT completed
  52.262 +
  52.263 +   In this example, A003 and A004 demonstrate successful appending and
  52.264 +   copying to a mailbox that returns the UIDs assigned to the messages.
  52.265 +   A005 is an example in which no messages were copied; this is because
  52.266 +   in A003, we see that message 2 had UID 304, and message 3 had UID
  52.267 +   319; therefore, UIDs 305 through 310 do not exist (refer to section
  52.268 +   2.3.1.1 of [IMAP] for further explanation).  A006 is an example of a
  52.269 +   message being copied that did not return a COPYUID; and, as expected,
  52.270 +   A007 shows that the mail store containing that mailbox does not
  52.271 +   support persistent UIDs.
  52.272 +
  52.273 +4.  Formal Syntax
  52.274 +
  52.275 +   Formal syntax is defined using ABNF [ABNF], which extends the ABNF
  52.276 +   rules defined in [IMAP].  The IMAP4 ABNF should be imported before
  52.277 +   attempting to validate these rules.
  52.278 +
  52.279 +   append-uid      = uniqueid
  52.280 +
  52.281 +   capability      =/ "UIDPLUS"
  52.282 +
  52.283 +
  52.284 +
  52.285 +Crispin                     Standards Track                     [Page 5]
  52.286 +
  52.287 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
  52.288 +
  52.289 +
  52.290 +   command-select  =/ uid-expunge
  52.291 +
  52.292 +   resp-code-apnd  = "APPENDUID" SP nz-number SP append-uid
  52.293 +
  52.294 +   resp-code-copy  = "COPYUID" SP nz-number SP uid-set SP uid-set
  52.295 +
  52.296 +   resp-text-code  =/ resp-code-apnd / resp-code-copy / "UIDNOTSTICKY"
  52.297 +                     ; incorporated before the expansion rule of
  52.298 +                     ;  atom [SP 1*<any TEXT-CHAR except "]">]
  52.299 +                     ; that appears in [IMAP]
  52.300 +
  52.301 +   uid-expunge     = "UID" SP "EXPUNGE" SP sequence-set
  52.302 +
  52.303 +   uid-set         = (uniqueid / uid-range) *("," uid-set)
  52.304 +
  52.305 +   uid-range       = (uniqueid ":" uniqueid)
  52.306 +                     ; two uniqueid values and all values
  52.307 +                     ; between these two regards of order.
  52.308 +                     ; Example: 2:4 and 4:2 are equivalent.
  52.309 +
  52.310 +   Servers that support [MULTIAPPEND] will have the following extension
  52.311 +   to the above rules:
  52.312 +
  52.313 +   append-uid      =/ uid-set
  52.314 +                     ; only permitted if client uses [MULTIAPPEND]
  52.315 +                     ; to append multiple messages.
  52.316 +
  52.317 +5.  Security Considerations
  52.318 +
  52.319 +   The COPYUID and APPENDUID response codes return information about the
  52.320 +   mailbox, which may be considered sensitive if the mailbox has
  52.321 +   permissions set that permit the client to COPY or APPEND to the
  52.322 +   mailbox, but not SELECT or EXAMINE it.
  52.323 +
  52.324 +   Consequently, these response codes SHOULD NOT be issued if the client
  52.325 +   does not have access to SELECT or EXAMINE the mailbox.
  52.326 +
  52.327 +6.  IANA Considerations
  52.328 +
  52.329 +   This document constitutes registration of the UIDPLUS capability in
  52.330 +   the imap4-capabilities registry, replacing [RFC2359].
  52.331 +
  52.332 +7.  Normative References
  52.333 +
  52.334 +   [ABNF]        Crocker, D. and P. Overell, "Augmented BNF for Syntax
  52.335 +                 Specifications: ABNF", RFC 4234, October 2005.
  52.336 +
  52.337 +
  52.338 +
  52.339 +
  52.340 +
  52.341 +Crispin                     Standards Track                     [Page 6]
  52.342 +
  52.343 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
  52.344 +
  52.345 +
  52.346 +   [IMAP]        Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
  52.347 +                 VERSION 4rev1", RFC 3501, March 2003.
  52.348 +
  52.349 +   [KEYWORDS]    Bradner, S., "Key words for use in RFCs to Indicate
  52.350 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
  52.351 +
  52.352 +   [MULTIAPPEND] Crispin, M., "Internet Message Access Protocol (IMAP) -
  52.353 +                 MULTIAPPEND Extension", RFC 3502, March 2003.
  52.354 +
  52.355 +8.  Informative References
  52.356 +
  52.357 +   [RFC2359]     Myers, J., "IMAP4 UIDPLUS extension", RFC 2359, June
  52.358 +                 1998.
  52.359 +
  52.360 +9.  Changes from RFC 2359
  52.361 +
  52.362 +   This document obsoletes [RFC2359].  However, it is based upon that
  52.363 +   document, and takes substantial text from it (albeit with numerous
  52.364 +   clarifications in wording).
  52.365 +
  52.366 +   [RFC2359] implied that a server must always return COPYUID/APPENDUID
  52.367 +   data; thus suggesting that in such cases the server should return
  52.368 +   arbitrary data if the destination mailbox did not support persistent
  52.369 +   UIDs.  This document adds the UIDNOTSTICKY response code to indicate
  52.370 +   that a mailbox does not support persistent UIDs, and stipulates that
  52.371 +   a UIDPLUS server does not return COPYUID/APPENDUID data when the COPY
  52.372 +   (or APPEND) destination mailbox has UIDNOTSTICKY status.
  52.373 +
  52.374 +Author's Address
  52.375 +
  52.376 +   Mark R. Crispin
  52.377 +   Networks and Distributed Computing
  52.378 +   University of Washington
  52.379 +   4545 15th Avenue NE
  52.380 +   Seattle, WA  98105-4527
  52.381 +
  52.382 +   Phone: (206) 543-5762
  52.383 +   EMail: MRC@CAC.Washington.EDU
  52.384 +
  52.385 +
  52.386 +
  52.387 +
  52.388 +
  52.389 +
  52.390 +
  52.391 +
  52.392 +
  52.393 +
  52.394 +
  52.395 +
  52.396 +
  52.397 +Crispin                     Standards Track                     [Page 7]
  52.398 +
  52.399 +RFC 4315                IMAP - UIDPLUS Extension           December 2005
  52.400 +
  52.401 +
  52.402 +Full Copyright Statement
  52.403 +
  52.404 +   Copyright (C) The Internet Society (2005).
  52.405 +
  52.406 +   This document is subject to the rights, licenses and restrictions
  52.407 +   contained in BCP 78, and except as set forth therein, the authors
  52.408 +   retain all their rights.
  52.409 +
  52.410 +   This document and the information contained herein are provided on an
  52.411 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  52.412 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  52.413 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  52.414 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  52.415 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  52.416 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  52.417 +
  52.418 +Intellectual Property
  52.419 +
  52.420 +   The IETF takes no position regarding the validity or scope of any
  52.421 +   Intellectual Property Rights or other rights that might be claimed to
  52.422 +   pertain to the implementation or use of the technology described in
  52.423 +   this document or the extent to which any license under such rights
  52.424 +   might or might not be available; nor does it represent that it has
  52.425 +   made any independent effort to identify any such rights.  Information
  52.426 +   on the procedures with respect to rights in RFC documents can be
  52.427 +   found in BCP 78 and BCP 79.
  52.428 +
  52.429 +   Copies of IPR disclosures made to the IETF Secretariat and any
  52.430 +   assurances of licenses to be made available, or the result of an
  52.431 +   attempt made to obtain a general license or permission for the use of
  52.432 +   such proprietary rights by implementers or users of this
  52.433 +   specification can be obtained from the IETF on-line IPR repository at
  52.434 +   http://www.ietf.org/ipr.
  52.435 +
  52.436 +   The IETF invites any interested party to bring to its attention any
  52.437 +   copyrights, patents or patent applications, or other proprietary
  52.438 +   rights that may cover technology that may be required to implement
  52.439 +   this standard.  Please address the information to the IETF at ietf-
  52.440 +   ipr@ietf.org.
  52.441 +
  52.442 +Acknowledgement
  52.443 +
  52.444 +   Funding for the RFC Editor function is currently provided by the
  52.445 +   Internet Society.
  52.446 +
  52.447 +
  52.448 +
  52.449 +
  52.450 +
  52.451 +
  52.452 +
  52.453 +Crispin                     Standards Track                     [Page 8]
  52.454 +
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/docs/rfc/rfc4422.txt	Mon Sep 14 15:17:45 2009 +0900
    53.3 @@ -0,0 +1,1851 @@
    53.4 +
    53.5 +
    53.6 +
    53.7 +
    53.8 +
    53.9 +
   53.10 +Network Working Group                                   A. Melnikov, Ed.
   53.11 +Request for Comments: 4422                                 Isode Limited
   53.12 +Obsoletes: 2222                                         K. Zeilenga, Ed.
   53.13 +Category: Standards Track                            OpenLDAP Foundation
   53.14 +                                                               June 2006
   53.15 +
   53.16 +
   53.17 +            Simple Authentication and Security Layer (SASL)
   53.18 +
   53.19 +Status of This Memo
   53.20 +
   53.21 +   This document specifies an Internet standards track protocol for the
   53.22 +   Internet community, and requests discussion and suggestions for
   53.23 +   improvements.  Please refer to the current edition of the "Internet
   53.24 +   Official Protocol Standards" (STD 1) for the standardization state
   53.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   53.26 +
   53.27 +Copyright Notice
   53.28 +
   53.29 +   Copyright (C) The Internet Society (2006).
   53.30 +
   53.31 +Abstract
   53.32 +
   53.33 +   The Simple Authentication and Security Layer (SASL) is a framework
   53.34 +   for providing authentication and data security services in
   53.35 +   connection-oriented protocols via replaceable mechanisms.  It
   53.36 +   provides a structured interface between protocols and mechanisms.
   53.37 +   The resulting framework allows new protocols to reuse existing
   53.38 +   mechanisms and allows old protocols to make use of new mechanisms.
   53.39 +   The framework also provides a protocol for securing subsequent
   53.40 +   protocol exchanges within a data security layer.
   53.41 +
   53.42 +   This document describes how a SASL mechanism is structured, describes
   53.43 +   how protocols include support for SASL, and defines the protocol for
   53.44 +   carrying a data security layer over a connection.  In addition, this
   53.45 +   document defines one SASL mechanism, the EXTERNAL mechanism.
   53.46 +
   53.47 +   This document obsoletes RFC 2222.
   53.48 +
   53.49 +
   53.50 +
   53.51 +
   53.52 +
   53.53 +
   53.54 +
   53.55 +
   53.56 +
   53.57 +
   53.58 +
   53.59 +
   53.60 +
   53.61 +Melnikov & Zeilenga         Standards Track                     [Page 1]
   53.62 +
   53.63 +RFC 4422                          SASL                         June 2006
   53.64 +
   53.65 +
   53.66 +Table of Contents
   53.67 +
   53.68 +   1. Introduction ....................................................3
   53.69 +      1.1. Document Audiences .........................................4
   53.70 +      1.2. Relationship to Other Documents ............................4
   53.71 +      1.3. Conventions ................................................5
   53.72 +   2. Identity Concepts ...............................................5
   53.73 +   3. The Authentication Exchange .....................................6
   53.74 +      3.1. Mechanism Naming ...........................................8
   53.75 +      3.2. Mechanism Negotiation ......................................9
   53.76 +      3.3. Request Authentication Exchange ............................9
   53.77 +      3.4. Challenges and Responses ...................................9
   53.78 +           3.4.1. Authorization Identity String ......................10
   53.79 +      3.5. Aborting Authentication Exchanges .........................10
   53.80 +      3.6. Authentication Outcome ....................................11
   53.81 +      3.7. Security Layers ...........................................12
   53.82 +      3.8. Multiple Authentications ..................................12
   53.83 +   4. Protocol Requirements ..........................................13
   53.84 +   5. Mechanism Requirements .........................................16
   53.85 +   6. Security Considerations ........................................18
   53.86 +      6.1. Active Attacks ............................................19
   53.87 +           6.1.1. Hijack Attacks .....................................19
   53.88 +           6.1.2. Downgrade Attacks ..................................19
   53.89 +           6.1.3. Replay Attacks .....................................20
   53.90 +           6.1.4. Truncation Attacks .................................20
   53.91 +           6.1.5. Other Active Attacks ...............................20
   53.92 +      6.2. Passive Attacks ...........................................20
   53.93 +      6.3. Re-keying .................................................21
   53.94 +      6.4. Other Considerations ......................................21
   53.95 +   7. IANA Considerations ............................................22
   53.96 +      7.1. SASL Mechanism Registry ...................................22
   53.97 +      7.2. Registration Changes ......................................26
   53.98 +   8. References .....................................................26
   53.99 +      8.1. Normative References ......................................26
  53.100 +      8.2. Informative References ....................................27
  53.101 +   9. Acknowledgements ...............................................28
  53.102 +   Appendix A.  The SASL EXTERNAL Mechanism ..........................29
  53.103 +      A.1. EXTERNAL Technical Specification ..........................29
  53.104 +      A.2. SASL EXTERNAL Examples ....................................30
  53.105 +      A.3. Security Considerations ...................................31
  53.106 +   Appendix B.  Changes since RFC 2222 ...............................31
  53.107 +
  53.108 +
  53.109 +
  53.110 +
  53.111 +
  53.112 +
  53.113 +
  53.114 +
  53.115 +
  53.116 +
  53.117 +Melnikov & Zeilenga         Standards Track                     [Page 2]
  53.118 +
  53.119 +RFC 4422                          SASL                         June 2006
  53.120 +
  53.121 +
  53.122 +1.  Introduction
  53.123 +
  53.124 +   The Simple Authentication and Security Layer (SASL) is a framework
  53.125 +   for providing authentication and data security services in
  53.126 +   connection-oriented protocols via replaceable mechanisms.  SASL
  53.127 +   provides a structured interface between protocols and mechanisms.
  53.128 +   SASL also provides a protocol for securing subsequent protocol
  53.129 +   exchanges within a data security layer.  The data security layer can
  53.130 +   provide data integrity, data confidentiality, and other services.
  53.131 +
  53.132 +   SASL's design is intended to allow new protocols to reuse existing
  53.133 +   mechanisms without requiring redesign of the mechanisms and allows
  53.134 +   existing protocols to make use of new mechanisms without redesign of
  53.135 +   protocols.
  53.136 +
  53.137 +   SASL is conceptually a framework that provides an abstraction layer
  53.138 +   between protocols and mechanisms as illustrated in the following
  53.139 +   diagram.
  53.140 +
  53.141 +                  SMTP    LDAP    XMPP   Other protocols ...
  53.142 +                     \       |    |      /
  53.143 +                      \      |    |     /
  53.144 +                     SASL abstraction layer
  53.145 +                      /      |    |     \
  53.146 +                     /       |    |      \
  53.147 +              EXTERNAL   GSSAPI  PLAIN   Other mechanisms ...
  53.148 +
  53.149 +   It is through the interfaces of this abstraction layer that the
  53.150 +   framework allows any protocol to utilize any mechanism.  While this
  53.151 +   layer does generally hide the particulars of protocols from
  53.152 +   mechanisms and the particulars of mechanisms from protocols, this
  53.153 +   layer does not generally hide the particulars of mechanisms from
  53.154 +   protocol implementations.  For example, different mechanisms require
  53.155 +   different information to operate, some of them use password-based
  53.156 +   authentication, some of then require realm information, others make
  53.157 +   use of Kerberos tickets, certificates, etc.  Also, in order to
  53.158 +   perform authorization, server implementations generally have to
  53.159 +   implement identity mapping between authentication identities, whose
  53.160 +   form is mechanism specific, and authorization identities, whose form
  53.161 +   is application protocol specific.  Section 2 discusses identity
  53.162 +   concepts.
  53.163 +
  53.164 +   It is possible to design and implement this framework in ways that do
  53.165 +   abstract away particulars of similar mechanisms.  Such a framework
  53.166 +   implementation, as well as mechanisms implementations, could be
  53.167 +   designed not only to be shared by multiple implementations of a
  53.168 +   particular protocol but to be shared by implementations of multiple
  53.169 +   protocols.
  53.170 +
  53.171 +
  53.172 +
  53.173 +Melnikov & Zeilenga         Standards Track                     [Page 3]
  53.174 +
  53.175 +RFC 4422                          SASL                         June 2006
  53.176 +
  53.177 +
  53.178 +   The framework incorporates interfaces with both protocols and
  53.179 +   mechanisms in which authentication exchanges are carried out.
  53.180 +   Section 3 discusses SASL authentication exchanges.
  53.181 +
  53.182 +   To use SASL, each protocol (amongst other items) provides a method
  53.183 +   for identifying which mechanism is to be used, a method for exchange
  53.184 +   of mechanism-specific server-challenges and client-responses, and a
  53.185 +   method for communicating the outcome of the authentication exchange.
  53.186 +   Section 4 discusses SASL protocol requirements.
  53.187 +
  53.188 +   Each SASL mechanism defines (amongst other items) a series of
  53.189 +   server-challenges and client-responses that provide authentication
  53.190 +   services and negotiate data security services.  Section 5 discusses
  53.191 +   SASL mechanism requirements.
  53.192 +
  53.193 +   Section 6 discusses security considerations.  Section 7 discusses
  53.194 +   IANA considerations.  Appendix A defines the SASL EXTERNAL mechanism.
  53.195 +
  53.196 +1.1.  Document Audiences
  53.197 +
  53.198 +   This document is written to serve several different audiences:
  53.199 +
  53.200 +      -  protocol designers using this specification to support
  53.201 +         authentication in their protocol,
  53.202 +
  53.203 +      -  mechanism designers that define new SASL mechanisms, and
  53.204 +
  53.205 +      -  implementors of clients or servers for those protocols that
  53.206 +         support SASL.
  53.207 +
  53.208 +   While the document organization is intended to allow readers to focus
  53.209 +   on details relevant to their engineering, readers are encouraged to
  53.210 +   read and understand all aspects of this document.
  53.211 +
  53.212 +1.2.  Relationship to Other Documents
  53.213 +
  53.214 +   This document obsoletes RFC 2222.  It replaces all portions of RFC
  53.215 +   2222 excepting sections 7.1 (the KERBEROS_IV mechanism), 7.2 (the
  53.216 +   GSSAPI mechanism), 7.3 (the SKEY mechanism).  The KERBEROS_IV and
  53.217 +   SKEY mechanisms are now viewed as obsolete and their specifications
  53.218 +   provided in RFC 2222 are Historic.  The GSSAPI mechanism is now
  53.219 +   separately specified [SASL-GSSAPI].
  53.220 +
  53.221 +   Appendix B provides a summary of changes since RFC 2222.
  53.222 +
  53.223 +
  53.224 +
  53.225 +
  53.226 +
  53.227 +
  53.228 +
  53.229 +Melnikov & Zeilenga         Standards Track                     [Page 4]
  53.230 +
  53.231 +RFC 4422                          SASL                         June 2006
  53.232 +
  53.233 +
  53.234 +1.3.  Conventions
  53.235 +
  53.236 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  53.237 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  53.238 +   document are to be interpreted as described in BCP 14 [RFC2119].
  53.239 +
  53.240 +   Character names in this document use the notation for code points and
  53.241 +   names from the Unicode Standard [Unicode].  For example, the letter
  53.242 +   "a" may be represented as either <U+0061> or <LATIN SMALL LETTER A>.
  53.243 +
  53.244 +   Note: a glossary of terms used in Unicode can be found in [Glossary].
  53.245 +   Information on the Unicode character encoding model can be found in
  53.246 +   [CharModel].
  53.247 +
  53.248 +   In examples, "C:" and "S:" indicate lines of data to be sent by the
  53.249 +   client and server, respectively.  Lines have been wrapped for
  53.250 +   improved readability.
  53.251 +
  53.252 +2.  Identity Concepts
  53.253 +
  53.254 +   In practice, authentication and authorization may involve multiple
  53.255 +   identities, possibly in different forms (simple username, Kerberos
  53.256 +   principal, X.500 Distinguished Name, etc.), possibly with different
  53.257 +   representations (e.g., ABNF-described UTF-8 encoded Unicode character
  53.258 +   string, BER-encoded Distinguished Name).  While technical
  53.259 +   specifications often prescribe both the identity form and
  53.260 +   representation used on the network, different identity forms and/or
  53.261 +   representations may be (and often are) used within implementations.
  53.262 +   How identities of different forms relate to each other is, generally,
  53.263 +   a local matter.  In addition, the forms and representations used
  53.264 +   within an implementation are a local matter.
  53.265 +
  53.266 +   However, conceptually, the SASL framework involves two identities:
  53.267 +
  53.268 +      1) an identity associated with the authentication credentials
  53.269 +         (termed the authentication identity), and
  53.270 +
  53.271 +      2) an identity to act as (termed the authorization identity).
  53.272 +
  53.273 +   SASL mechanism specifications describe the credential form(s) (e.g.,
  53.274 +   X.509 certificates, Kerberos tickets, simple username/password) used
  53.275 +   to authenticate the client, including (where appropriate) the syntax
  53.276 +   and semantics of authentication identities carried in the
  53.277 +   credentials.  SASL protocol specifications describe the identity
  53.278 +   form(s) used in authorization and, in particular, prescribe the
  53.279 +   syntax and semantics of the authorization identity character string
  53.280 +   to be transferred by mechanisms.
  53.281 +
  53.282 +
  53.283 +
  53.284 +
  53.285 +Melnikov & Zeilenga         Standards Track                     [Page 5]
  53.286 +
  53.287 +RFC 4422                          SASL                         June 2006
  53.288 +
  53.289 +
  53.290 +   The client provides its credentials (which include or imply an
  53.291 +   authentication identity) and, optionally, a character string
  53.292 +   representing the requested authorization identity as part of the SASL
  53.293 +   exchange.  When this character string is omitted or empty, the client
  53.294 +   is requesting to act as the identity associated with the credentials
  53.295 +   (e.g., the user is requesting to act as the authentication identity).
  53.296 +
  53.297 +   The server is responsible for verifying the client's credentials and
  53.298 +   verifying that the identity it associates with the client's
  53.299 +   credentials (e.g., the authentication identity) is allowed to act as
  53.300 +   the authorization identity.  A SASL exchange fails if either (or
  53.301 +   both) of these verifications fails.  (The SASL exchange may fail for
  53.302 +   other reasons, such as service authorization failure.)
  53.303 +
  53.304 +   However, the precise form(s) of the authentication identities (used
  53.305 +   within the server in its verifications, or otherwise) and the precise
  53.306 +   form(s) of the authorization identities (used in making authorization
  53.307 +   decisions, or otherwise) are beyond the scope of SASL and this
  53.308 +   specification.  In some circumstances, the precise identity forms
  53.309 +   used in some context outside of the SASL exchange may be dictated by
  53.310 +   other specifications.  For instance, an identity assumption
  53.311 +   authorization (proxy authorization) policy specification may dictate
  53.312 +   how authentication and authorization identities are represented in
  53.313 +   policy statements.
  53.314 +
  53.315 +3.  The Authentication Exchange
  53.316 +
  53.317 +   Each authentication exchange consists of a message from the client to
  53.318 +   the server requesting authentication via a particular mechanism,
  53.319 +   followed by one or more pairs of challenges from the server and
  53.320 +   responses from the client, followed by a message from the server
  53.321 +   indicating the outcome of the authentication exchange.  (Note:
  53.322 +   exchanges may also be aborted as discussed in Section 3.5.)
  53.323 +
  53.324 +   The following illustration provides a high-level overview of an
  53.325 +   authentication exchange.
  53.326 +
  53.327 +      C: Request authentication exchange
  53.328 +      S: Initial challenge
  53.329 +      C: Initial response
  53.330 +      <additional challenge/response messages>
  53.331 +      S: Outcome of authentication exchange
  53.332 +
  53.333 +   If the outcome is successful and a security layer was negotiated,
  53.334 +   this layer is then installed (see Section 3.7).  This also applies to
  53.335 +   the following illustrations.
  53.336 +
  53.337 +
  53.338 +
  53.339 +
  53.340 +
  53.341 +Melnikov & Zeilenga         Standards Track                     [Page 6]
  53.342 +
  53.343 +RFC 4422                          SASL                         June 2006
  53.344 +
  53.345 +
  53.346 +   Some mechanisms specify that the first data sent in the
  53.347 +   authentication exchange is from the client to the server.  Protocols
  53.348 +   may provide an optional initial response field in the request message
  53.349 +   to carry this data.  Where the mechanism specifies that the first
  53.350 +   data sent in the exchange is from the client to the server, the
  53.351 +   protocol provides an optional initial response field, and the client
  53.352 +   uses this field, the exchange is shortened by one round-trip:
  53.353 +
  53.354 +      C: Request authentication exchange + Initial response
  53.355 +      <additional challenge/response messages>
  53.356 +      S: Outcome of authentication exchange
  53.357 +
  53.358 +   Where the mechanism specifies that the first data sent in the
  53.359 +   exchange is from the client to the server and this field is
  53.360 +   unavailable or unused, the client request is followed by an empty
  53.361 +   challenge.
  53.362 +
  53.363 +      C: Request authentication exchange
  53.364 +      S: Empty Challenge
  53.365 +      C: Initial Response
  53.366 +      <additional challenge/response messages>
  53.367 +      S: Outcome of authentication exchange
  53.368 +
  53.369 +   Should a client include an initial response in its request where the
  53.370 +   mechanism does not allow the client to send data first, the
  53.371 +   authentication exchange fails.
  53.372 +
  53.373 +   Some mechanisms specify that the server is to send additional data to
  53.374 +   the client when indicating a successful outcome.  Protocols may
  53.375 +   provide an optional additional data field in the outcome message to
  53.376 +   carry this data.  Where the mechanism specifies that the server is to
  53.377 +   return additional data with the successful outcome, the protocol
  53.378 +   provides an optional additional data field in the outcome message,
  53.379 +   and the server uses this field, the exchange is shortened by one
  53.380 +   round-trip:
  53.381 +
  53.382 +      C: Request authentication exchange
  53.383 +      S: Initial challenge
  53.384 +      C: Initial response
  53.385 +      <additional challenge/response messages>
  53.386 +      S: Outcome of authentication exchange with
  53.387 +         additional data with success
  53.388 +
  53.389 +   Where the mechanism specifies that the server is to return additional
  53.390 +   data to the client with a successful outcome and this field is
  53.391 +   unavailable or unused, the additional data is sent as a challenge
  53.392 +   whose response is empty.  After receiving this response, the server
  53.393 +   then indicates the successful outcome.
  53.394 +
  53.395 +
  53.396 +
  53.397 +Melnikov & Zeilenga         Standards Track                     [Page 7]
  53.398 +
  53.399 +RFC 4422                          SASL                         June 2006
  53.400 +
  53.401 +
  53.402 +      C: Request authentication exchange
  53.403 +      S: Initial challenge
  53.404 +      C: Initial response
  53.405 +      <additional challenge/response messages>
  53.406 +      S: Additional data challenge
  53.407 +      C: Empty Response
  53.408 +      S: Outcome of authentication exchange
  53.409 +
  53.410 +   Where mechanisms specify that the first data sent in the exchange is
  53.411 +   from the client to the server and additional data is sent to the
  53.412 +   client along with indicating a successful outcome, and the protocol
  53.413 +   provides fields supporting both, then the exchange takes two fewer
  53.414 +   round-trips:
  53.415 +
  53.416 +      C: Request authentication exchange + Initial response
  53.417 +      <additional challenge/response messages>
  53.418 +      S: Outcome of authentication exchange
  53.419 +         with additional data with success
  53.420 +
  53.421 +   instead of:
  53.422 +
  53.423 +      C: Request authentication exchange
  53.424 +      S: Empty Challenge
  53.425 +      C: Initial Response
  53.426 +      <additional challenge/response messages>
  53.427 +      S: Additional data challenge
  53.428 +      C: Empty Response
  53.429 +      S: Outcome of authentication exchange
  53.430 +
  53.431 +3.1.  Mechanism Naming
  53.432 +
  53.433 +   SASL mechanisms are named by character strings, from 1 to 20
  53.434 +   characters in length, consisting of ASCII [ASCII] uppercase letters,
  53.435 +   digits, hyphens, and/or underscores.  In the following Augmented
  53.436 +   Backus-Naur Form (ABNF) [RFC4234] grammar, the <sasl-mech> production
  53.437 +   defines the syntax of a SASL mechanism name.
  53.438 +
  53.439 +      sasl-mech    = 1*20mech-char
  53.440 +      mech-char    = UPPER-ALPHA / DIGIT / HYPHEN / UNDERSCORE
  53.441 +      ; mech-char is restricted to A-Z (uppercase only), 0-9, -, and _
  53.442 +      ; from ASCII character set.
  53.443 +
  53.444 +      UPPER-ALPHA  = %x41-5A  ; A-Z (uppercase only)
  53.445 +      DIGIT        = %x30-39  ; 0-9
  53.446 +      HYPHEN       = %x2D ; hyphen (-)
  53.447 +      UNDERSCORE   = %x5F ; underscore (_)
  53.448 +
  53.449 +   SASL mechanism names are registered as discussed in Section 7.1.
  53.450 +
  53.451 +
  53.452 +
  53.453 +Melnikov & Zeilenga         Standards Track                     [Page 8]
  53.454 +
  53.455 +RFC 4422                          SASL                         June 2006
  53.456 +
  53.457 +
  53.458 +3.2.  Mechanism Negotiation
  53.459 +
  53.460 +   Mechanism negotiation is protocol specific.
  53.461 +
  53.462 +   Commonly, a protocol will specify that the server advertises
  53.463 +   supported and available mechanisms to the client via some facility
  53.464 +   provided by the protocol, and the client will then select the "best"
  53.465 +   mechanism from this list that it supports and finds suitable.
  53.466 +
  53.467 +   Note that the mechanism negotiation is not protected by the
  53.468 +   subsequent authentication exchange and hence is subject to downgrade
  53.469 +   attacks if not protected by other means.
  53.470 +
  53.471 +   To detect downgrade attacks, a protocol can allow the client to
  53.472 +   discover available mechanisms subsequent to the authentication
  53.473 +   exchange and installation of data security layers with at least data
  53.474 +   integrity protection.  This allows the client to detect changes to
  53.475 +   the list of mechanisms supported by the server.
  53.476 +
  53.477 +3.3.  Request Authentication Exchange
  53.478 +
  53.479 +   The authentication exchange is initiated by the client by requesting
  53.480 +   authentication via a mechanism it specifies.  The client sends a
  53.481 +   message that contains the name of the mechanism to the server.  The
  53.482 +   particulars of the message are protocol specific.
  53.483 +
  53.484 +   Note that the name of the mechanism is not protected by the
  53.485 +   mechanism, and hence is subject to alteration by an attacker if not
  53.486 +   integrity protected by other means.
  53.487 +
  53.488 +   Where the mechanism is defined to allow the client to send data
  53.489 +   first, and the protocol's request message includes an optional
  53.490 +   initial response field, the client may include the response to the
  53.491 +   initial challenge in the authentication request message.
  53.492 +
  53.493 +3.4.  Challenges and Responses
  53.494 +
  53.495 +   The authentication exchange involves one or more pairs of server-
  53.496 +   challenges and client-responses, the particulars of which are
  53.497 +   mechanism specific.  These challenges and responses are enclosed in
  53.498 +   protocol messages, the particulars of which are protocol specific.
  53.499 +
  53.500 +   Through these challenges and responses, the mechanism may:
  53.501 +
  53.502 +      -  authenticate the client to the server,
  53.503 +
  53.504 +      -  authenticate the server to the client,
  53.505 +
  53.506 +
  53.507 +
  53.508 +
  53.509 +Melnikov & Zeilenga         Standards Track                     [Page 9]
  53.510 +
  53.511 +RFC 4422                          SASL                         June 2006
  53.512 +
  53.513 +
  53.514 +      -  transfer an authorization identity string,
  53.515 +
  53.516 +      -  negotiate a security layer, and
  53.517 +
  53.518 +      -  provide other services.
  53.519 +
  53.520 +   The negotiation of the security layer may involve negotiation of the
  53.521 +   security services to be provided in the layer, how these services
  53.522 +   will be provided, and negotiation of a maximum cipher-text buffer
  53.523 +   size each side is able to receive in the layer (see Section 3.6).
  53.524 +
  53.525 +   After receiving an authentication request or any client response, the
  53.526 +   server may issue a challenge, abort the exchange, or indicate the
  53.527 +   outcome of an exchange.  After receiving a challenge, a client
  53.528 +   mechanism may issue a response or abort the exchange.
  53.529 +
  53.530 +3.4.1.  Authorization Identity String
  53.531 +
  53.532 +   The authorization identity string is a sequence of zero or more
  53.533 +   Unicode [Unicode] characters, excluding the NUL (U+0000) character,
  53.534 +   representing the identity to act as.
  53.535 +
  53.536 +   If the authorization identity string is absent, the client is
  53.537 +   requesting to act as the identity the server associates with the
  53.538 +   client's credentials.  An empty string is equivalent to an absent
  53.539 +   authorization identity.
  53.540 +
  53.541 +   A non-empty authorization identity string indicates that the client
  53.542 +   wishes to act as the identity represented by the string.  In this
  53.543 +   case, the form of identity represented by the string, as well as the
  53.544 +   precise syntax and semantics of the string, is protocol specific.
  53.545 +
  53.546 +   While the character encoding schema used to transfer the
  53.547 +   authorization identity string in the authentication exchange is
  53.548 +   mechanism specific, mechanisms are expected to be capable of carrying
  53.549 +   the entire Unicode repertoire (with the exception of the NUL
  53.550 +   character).
  53.551 +
  53.552 +3.5.  Aborting Authentication Exchanges
  53.553 +
  53.554 +   A client or server may desire to abort an authentication exchange if
  53.555 +   it is unwilling or unable to continue (or enter into).
  53.556 +
  53.557 +   A client may abort the authentication exchange by sending a message,
  53.558 +   the particulars of which are protocol specific, to the server,
  53.559 +   indicating that the exchange is aborted.  The server may be required
  53.560 +   by the protocol to return a message in response to the client's abort
  53.561 +   message.
  53.562 +
  53.563 +
  53.564 +
  53.565 +Melnikov & Zeilenga         Standards Track                    [Page 10]
  53.566 +
  53.567 +RFC 4422                          SASL                         June 2006
  53.568 +
  53.569 +
  53.570 +   Likewise, a server may abort the authentication exchange by sending a
  53.571 +   message, the particulars of which are protocol specific, to the
  53.572 +   client, indicating that the exchange is aborted.
  53.573 +
  53.574 +3.6.  Authentication Outcome
  53.575 +
  53.576 +   At the conclusion of the authentication exchange, the server sends a
  53.577 +   message, the particulars of which are protocol specific, to the
  53.578 +   client indicating the outcome of the exchange.
  53.579 +
  53.580 +   The outcome is not successful if
  53.581 +
  53.582 +      -  the authentication exchange failed for any reason,
  53.583 +
  53.584 +      -  the client's credentials could not be verified,
  53.585 +
  53.586 +      -  the server cannot associate an identity with the client's
  53.587 +         credentials,
  53.588 +
  53.589 +      -  the client-provided authorization identity string is malformed,
  53.590 +
  53.591 +      -  the identity associated with the client's credentials is not
  53.592 +         authorized to act as the requested authorization identity,
  53.593 +
  53.594 +      -  the negotiated security layer (or lack thereof) is not
  53.595 +         suitable, or
  53.596 +
  53.597 +      -  the server is not willing to provide service to the client for
  53.598 +         any reason.
  53.599 +
  53.600 +   The protocol may include an optional additional data field in this
  53.601 +   outcome message.  This field can only include additional data when
  53.602 +   the outcome is successful.
  53.603 +
  53.604 +   If the outcome is successful and a security layer was negotiated,
  53.605 +   this layer is then installed.  If the outcome is unsuccessful, or a
  53.606 +   security layer was not negotiated, any existing security is left in
  53.607 +   place.
  53.608 +
  53.609 +   The outcome message provided by the server can provide a way for the
  53.610 +   client to distinguish between errors that are best dealt with by re-
  53.611 +   prompting the user for her credentials, errors that are best dealt
  53.612 +   with by telling the user to try again later, and errors where the
  53.613 +   user must contact a system administrator for resolution (see the SYS
  53.614 +   and AUTH POP Response Codes [RFC3206] specification for an example).
  53.615 +   This distinction is particularly useful during scheduled server
  53.616 +   maintenance periods as it reduces support costs.  It is also
  53.617 +   important that the server can be configured such that the outcome
  53.618 +
  53.619 +
  53.620 +
  53.621 +Melnikov & Zeilenga         Standards Track                    [Page 11]
  53.622 +
  53.623 +RFC 4422                          SASL                         June 2006
  53.624 +
  53.625 +
  53.626 +   message will not distinguish between a valid user with invalid
  53.627 +   credentials and an invalid user.
  53.628 +
  53.629 +3.7.  Security Layers
  53.630 +
  53.631 +   SASL mechanisms may offer a wide range of services in security
  53.632 +   layers.  Typical services include data integrity and data
  53.633 +   confidentiality.  SASL mechanisms that do not provide a security
  53.634 +   layer are treated as negotiating no security layer.
  53.635 +
  53.636 +   If use of a security layer is negotiated in the authentication
  53.637 +   protocol exchange, the layer is installed by the server after
  53.638 +   indicating the outcome of the authentication exchange and installed
  53.639 +   by the client upon receipt of the outcome indication.  In both cases,
  53.640 +   the layer is installed before transfer of further protocol data.  The
  53.641 +   precise position upon which the layer takes effect in the protocol
  53.642 +   data stream is protocol specific.
  53.643 +
  53.644 +   Once the security layer is in effect in the protocol data stream, it
  53.645 +   remains in effect until either a subsequently negotiated security
  53.646 +   layer is installed or the underlying transport connection is closed.
  53.647 +
  53.648 +   When in effect, the security layer processes protocol data into
  53.649 +   buffers of protected data.  If at any time the security layer is
  53.650 +   unable or unwilling to continue producing buffers protecting protocol
  53.651 +   data, the underlying transport connection MUST be closed.  If the
  53.652 +   security layer is not able to decode a received buffer, the
  53.653 +   underlying connection MUST be closed.  In both cases, the underlying
  53.654 +   transport connection SHOULD be closed gracefully.
  53.655 +
  53.656 +   Each buffer of protected data is transferred over the underlying
  53.657 +   transport connection as a sequence of octets prepended with a four-
  53.658 +   octet field in network byte order that represents the length of the
  53.659 +   buffer.  The length of the protected data buffer MUST be no larger
  53.660 +   than the maximum size that the other side expects.  Upon the receipt
  53.661 +   of a length field whose value is greater than the maximum size, the
  53.662 +   receiver SHOULD close the connection, as this might be a sign of an
  53.663 +   attack.
  53.664 +
  53.665 +   The maximum size that each side expects is fixed by the mechanism,
  53.666 +   either through negotiation or by its specification.
  53.667 +
  53.668 +3.8.  Multiple Authentications
  53.669 +
  53.670 +   Unless explicitly permitted in the protocol (as stated in the
  53.671 +   protocol's technical specification), only one successful SASL
  53.672 +   authentication exchange may occur in a protocol session.  In this
  53.673 +
  53.674 +
  53.675 +
  53.676 +
  53.677 +Melnikov & Zeilenga         Standards Track                    [Page 12]
  53.678 +
  53.679 +RFC 4422                          SASL                         June 2006
  53.680 +
  53.681 +
  53.682 +   case, once an authentication exchange has successfully completed,
  53.683 +   further attempts to initiate an authentication exchange fail.
  53.684 +
  53.685 +   Where multiple successful SASL authentication exchanges are permitted
  53.686 +   in the protocol, then in no case may multiple SASL security layers be
  53.687 +   simultaneously in effect.  If a security layer is in effect and a
  53.688 +   subsequent SASL negotiation selects a second security layer, then the
  53.689 +   second security layer replaces the first.  If a security layer is in
  53.690 +   effect and a subsequent SASL negotiation selects no security layer,
  53.691 +   the original security layer remains in effect.
  53.692 +
  53.693 +   Where multiple successful SASL negotiations are permitted in the
  53.694 +   protocol, the effect of a failed SASL authentication exchange upon
  53.695 +   the previously established authentication and authorization state is
  53.696 +   protocol specific.  The protocol's technical specification should be
  53.697 +   consulted to determine whether the previous authentication and
  53.698 +   authorization state remains in force, or changed to an anonymous
  53.699 +   state, or otherwise was affected.  Regardless of the protocol-
  53.700 +   specific effect upon previously established authentication and
  53.701 +   authorization state, the previously negotiated security layer remains
  53.702 +   in effect.
  53.703 +
  53.704 +4.  Protocol Requirements
  53.705 +
  53.706 +   In order for a protocol to offer SASL services, its specification
  53.707 +   MUST supply the following information:
  53.708 +
  53.709 +   1) A service name, to be selected from registry of "service" elements
  53.710 +      for the Generic Security Service Application Program Interface
  53.711 +      (GSSAPI) host-based service name form, as described in Section 4.1
  53.712 +      of [RFC2743].  Note that this registry is shared by all GSSAPI and
  53.713 +      SASL mechanisms.
  53.714 +
  53.715 +   2) Detail any mechanism negotiation facility that the protocol
  53.716 +      provides (see Section 3.2).
  53.717 +
  53.718 +      A protocol SHOULD specify a facility through which the client may
  53.719 +      discover, both before initiation of the SASL exchange and after
  53.720 +      installing security layers negotiated by the exchange, the names
  53.721 +      of the SASL mechanisms that the server makes available to the
  53.722 +      client.  The latter is important to allow the client to detect
  53.723 +      downgrade attacks.  This facility is typically provided through
  53.724 +      the protocol's extensions or capabilities discovery facility.
  53.725 +
  53.726 +   3) Definition of the messages necessary for authentication exchange,
  53.727 +      including the following:
  53.728 +
  53.729 +
  53.730 +
  53.731 +
  53.732 +
  53.733 +Melnikov & Zeilenga         Standards Track                    [Page 13]
  53.734 +
  53.735 +RFC 4422                          SASL                         June 2006
  53.736 +
  53.737 +
  53.738 +      a) A message to initiate the authentication exchange (see Section
  53.739 +         3.3).
  53.740 +
  53.741 +         This message MUST contain a field for carrying the name of the
  53.742 +         mechanism selected by the client.
  53.743 +
  53.744 +         This message SHOULD contain an optional field for carrying an
  53.745 +         initial response.  If the message is defined with this field,
  53.746 +         the specification MUST describe how messages with an empty
  53.747 +         initial response are distinguished from messages with no
  53.748 +         initial response.  This field MUST be capable of carrying
  53.749 +         arbitrary sequences of octets (including zero-length sequences
  53.750 +         and sequences containing zero-valued octets).
  53.751 +
  53.752 +      b) Messages to transfer server challenges and client responses
  53.753 +         (see Section 3.4).
  53.754 +
  53.755 +         Each of these messages MUST be capable of carrying arbitrary
  53.756 +         sequences of octets (including zero-length sequences and
  53.757 +         sequences containing zero-valued octets).
  53.758 +
  53.759 +      c) A message to indicate the outcome of the authentication
  53.760 +         exchange (see Section 3.6).
  53.761 +
  53.762 +         This message SHOULD contain an optional field for carrying
  53.763 +         additional data with a successful outcome.  If the message is
  53.764 +         defined with this field, the specification MUST describe how
  53.765 +         messages with an empty additional data are distinguished from
  53.766 +         messages with no additional data.  This field MUST be capable
  53.767 +         of carrying arbitrary sequences of octets (including zero-
  53.768 +         length sequences and sequences containing zero-valued octets).
  53.769 +
  53.770 +   4) Prescribe the syntax and semantics of non-empty authorization
  53.771 +      identity strings (see Section 3.4.1).
  53.772 +
  53.773 +      In order to avoid interoperability problems due to differing
  53.774 +      normalizations, the protocol specification MUST detail precisely
  53.775 +      how and where (client or server) non-empty authorization identity
  53.776 +      strings are prepared, including all normalizations, for comparison
  53.777 +      and other applicable functions to ensure proper function.
  53.778 +
  53.779 +      Specifications are encouraged to prescribe use of existing
  53.780 +      authorization identity forms as well as existing string
  53.781 +      representations, such as simple user names [RFC4013].
  53.782 +
  53.783 +      Where the specification does not precisely prescribe how
  53.784 +      identities in SASL relate to identities used elsewhere in the
  53.785 +      protocol, for instance, in access control policy statements, it
  53.786 +
  53.787 +
  53.788 +
  53.789 +Melnikov & Zeilenga         Standards Track                    [Page 14]
  53.790 +
  53.791 +RFC 4422                          SASL                         June 2006
  53.792 +
  53.793 +
  53.794 +      may be appropriate for the protocol to provide a facility by which
  53.795 +      the client can discover information (such as the representation of
  53.796 +      the identity used in making access control decisions) about
  53.797 +      established identities for these uses.
  53.798 +
  53.799 +   5) Detail any facility the protocol provides that allows the client
  53.800 +      and/or server to abort authentication exchange (see Section 3.5).
  53.801 +
  53.802 +      Protocols that support multiple authentications typically allow a
  53.803 +      client to abort an ongoing authentication exchange by initiating a
  53.804 +      new authentication exchange.  Protocols that do not support
  53.805 +      multiple authentications may require the client to close the
  53.806 +      connection and start over to abort an ongoing authentication
  53.807 +      exchange.
  53.808 +
  53.809 +      Protocols typically allow the server to abort ongoing
  53.810 +      authentication exchanges by returning a non-successful outcome
  53.811 +      message.
  53.812 +
  53.813 +   6) Identify precisely where newly negotiated security layers start to
  53.814 +      take effect, in both directions (see Section 3.7).
  53.815 +
  53.816 +      Typically, specifications require security layers to start taking
  53.817 +      effect on the first octet following the outcome message in data
  53.818 +      being sent by the server and on the first octet sent after receipt
  53.819 +      of the outcome message in data being sent by the client.
  53.820 +
  53.821 +   7) If the protocol supports other layered security services, such as
  53.822 +      Transport Layer Security (TLS) [RFC4346], the specification MUST
  53.823 +      prescribe the order in which security layers are applied to
  53.824 +      protocol data.
  53.825 +
  53.826 +      For instance, where a protocol supports both TLS and SASL security
  53.827 +      layers, the specification could prescribe any of the following:
  53.828 +
  53.829 +      a) SASL security layer is always applied first to data being sent
  53.830 +         and, hence, applied last to received data,
  53.831 +
  53.832 +      b) SASL security layer is always applied last to data being sent
  53.833 +         and, hence, applied first to received data,
  53.834 +
  53.835 +      c) Layers are applied in the order in which they were installed,
  53.836 +
  53.837 +      d) Layers are applied in the reverse order in which they were
  53.838 +         installed, or
  53.839 +
  53.840 +      e) Both TLS and SASL security layers cannot be installed.
  53.841 +
  53.842 +
  53.843 +
  53.844 +
  53.845 +Melnikov & Zeilenga         Standards Track                    [Page 15]
  53.846 +
  53.847 +RFC 4422                          SASL                         June 2006
  53.848 +
  53.849 +
  53.850 +   8) Indicate whether the protocol supports multiple authentications
  53.851 +      (see Section 3.8).  If so, the protocol MUST detail the effect a
  53.852 +      failed SASL authentication exchange will have upon a previously
  53.853 +      established authentication and authorization state.
  53.854 +
  53.855 +   Protocol specifications SHOULD avoid stating implementation
  53.856 +   requirements that would hinder replacement of applicable mechanisms.
  53.857 +   In general, protocol specifications SHOULD be mechanism neutral.
  53.858 +   There are a number of reasonable exceptions to this recommendation,
  53.859 +   including
  53.860 +
  53.861 +      -  detailing how credentials (which are mechanism specific) are
  53.862 +         managed in the protocol,
  53.863 +
  53.864 +      -  detailing how authentication identities (which are mechanism
  53.865 +         specific) and authorization identities (which are protocol
  53.866 +         specific) relate to each other, and
  53.867 +
  53.868 +      -  detailing which mechanisms are applicable to the protocol.
  53.869 +
  53.870 +5.  Mechanism Requirements
  53.871 +
  53.872 +   SASL mechanism specifications MUST supply the following information:
  53.873 +
  53.874 +   1) The name of the mechanism (see Section 3.1).  This name MUST be
  53.875 +      registered as discussed in Section 7.1.
  53.876 +
  53.877 +   2) A definition of the server-challenges and client-responses of the
  53.878 +      authentication exchange, as well as the following:
  53.879 +
  53.880 +      a) An indication of whether the mechanism is client-first,
  53.881 +         variable, or server-first.  If a SASL mechanism is defined as
  53.882 +         client-first and the client does not send an initial response
  53.883 +         in the authentication request, then the first server challenge
  53.884 +         MUST be empty (the EXTERNAL mechanism is an example of this
  53.885 +         case).  If a SASL mechanism is defined as variable, then the
  53.886 +         specification needs to state how the server behaves when the
  53.887 +         initial client response in the authentication request is
  53.888 +         omitted (the DIGEST-MD5 mechanism [DIGEST-MD5] is an example of
  53.889 +         this case).  If a SASL mechanism is defined as server-first,
  53.890 +         then the client MUST NOT send an initial client response in the
  53.891 +         authentication request (the CRAM-MD5 mechanism [CRAM-MD5] is an
  53.892 +         example of this case).
  53.893 +
  53.894 +      b) An indication of whether the server is expected to provide
  53.895 +         additional data when indicating a successful outcome.  If so,
  53.896 +         if the server sends the additional data as a challenge, the
  53.897 +
  53.898 +
  53.899 +
  53.900 +
  53.901 +Melnikov & Zeilenga         Standards Track                    [Page 16]
  53.902 +
  53.903 +RFC 4422                          SASL                         June 2006
  53.904 +
  53.905 +
  53.906 +         specification MUST indicate that the response to this challenge
  53.907 +         is an empty response.
  53.908 +
  53.909 +      SASL mechanisms SHOULD be designed to minimize the number of
  53.910 +      challenges and responses necessary to complete the exchange.
  53.911 +
  53.912 +   3) An indication of whether the mechanism is capable of transferring
  53.913 +      authorization identity strings (see Section 3.4.1).  While some
  53.914 +      legacy mechanisms are incapable of transmitting an authorization
  53.915 +      identity (which means that for these mechanisms, the authorization
  53.916 +      identity is always the empty string), newly defined mechanisms
  53.917 +      SHOULD be capable of transferring authorization identity strings.
  53.918 +      The mechanism SHOULD NOT be capable of transferring both no
  53.919 +      authorization identity string and an empty authorization identity.
  53.920 +
  53.921 +      Mechanisms that are capable of transferring an authorization
  53.922 +      identity string MUST be capable of transferring arbitrary non-
  53.923 +      empty sequences of Unicode characters, excluding those that
  53.924 +      contain the NUL (U+0000) character.  Mechanisms SHOULD use the
  53.925 +      UTF-8 [RFC3629] transformation format.  The specification MUST
  53.926 +      detail how any Unicode code points special to the mechanism that
  53.927 +      might appear in the authorization identity string are escaped to
  53.928 +      avoid ambiguity during decoding of the authorization identity
  53.929 +      string.  Typically, mechanisms that have special characters
  53.930 +      require these special characters to be escaped or encoded in the
  53.931 +      character string (after encoding it in a particular Unicode
  53.932 +      transformation format) using a data encoding scheme such as Base64
  53.933 +      [RFC3548].
  53.934 +
  53.935 +   4) The specification MUST detail whether the mechanism offers a
  53.936 +      security layer.  If the mechanism does, the specification MUST
  53.937 +      detail the security and other services offered in the layer as
  53.938 +      well as how these services are to be implemented.
  53.939 +
  53.940 +   5) If the underlying cryptographic technology used by a mechanism
  53.941 +      supports data integrity, then the mechanism specification MUST
  53.942 +      integrity protect the transmission of an authorization identity
  53.943 +      and the negotiation of the security layer.
  53.944 +
  53.945 +   SASL mechanisms SHOULD be protocol neutral.
  53.946 +
  53.947 +   SASL mechanisms SHOULD reuse existing credential and identity forms,
  53.948 +   as well as associated syntaxes and semantics.
  53.949 +
  53.950 +   SASL mechanisms SHOULD use the UTF-8 transformation format [RFC3629]
  53.951 +   for encoding Unicode [Unicode] code points for transfer.
  53.952 +
  53.953 +
  53.954 +
  53.955 +
  53.956 +
  53.957 +Melnikov & Zeilenga         Standards Track                    [Page 17]
  53.958 +
  53.959 +RFC 4422                          SASL                         June 2006
  53.960 +
  53.961 +
  53.962 +   In order to avoid interoperability problems due to differing
  53.963 +   normalizations, when a mechanism calls for character data (other than
  53.964 +   the authorization identity string) to be used as input to a
  53.965 +   cryptographic and/or comparison function, the specification MUST
  53.966 +   detail precisely how and where (client or server) the character data
  53.967 +   is to be prepared, including all normalizations, for input into the
  53.968 +   function to ensure proper operation.
  53.969 +
  53.970 +   For simple user names and/or passwords in authentication credentials,
  53.971 +   SASLprep [RFC4013] (a profile of the StringPrep [RFC3454] preparation
  53.972 +   algorithm), SHOULD be specified as the preparation algorithm.
  53.973 +
  53.974 +   The mechanism SHOULD NOT use the authorization identity string in
  53.975 +   generation of any long-term cryptographic keys or hashes as there is
  53.976 +   no requirement that the authorization identity string be canonical.
  53.977 +   Long-term, here, means a term longer than the duration of the
  53.978 +   authentication exchange in which they were generated.  That is, as
  53.979 +   different clients (of the same or different protocol) may provide
  53.980 +   different authorization identity strings that are semantically
  53.981 +   equivalent, use of authorization identity strings in generation of
  53.982 +   cryptographic keys and hashes will likely lead to interoperability
  53.983 +   and other problems.
  53.984 +
  53.985 +6.  Security Considerations
  53.986 +
  53.987 +   Security issues are discussed throughout this memo.
  53.988 +
  53.989 +   Many existing SASL mechanisms do not provide adequate protection
  53.990 +   against passive attacks, let alone active attacks, in the
  53.991 +   authentication exchange.  Many existing SASL mechanisms do not offer
  53.992 +   security layers.  It is hoped that future SASL mechanisms will
  53.993 +   provide strong protection against passive and active attacks in the
  53.994 +   authentication exchange, as well as security layers with strong basic
  53.995 +   data security features (e.g., data integrity and data
  53.996 +   confidentiality) services.  It is also hoped that future mechanisms
  53.997 +   will provide more advanced data security services like re-keying (see
  53.998 +   Section 6.3).
  53.999 +
 53.1000 +   Regardless, the SASL framework is susceptible to downgrade attacks.
 53.1001 +   Section 6.1.2 offers a variety of approaches for preventing or
 53.1002 +   detecting these attacks.  In some cases, it is appropriate to use
 53.1003 +   data integrity protective services external to SASL (e.g., TLS) to
 53.1004 +   protect against downgrade attacks in SASL.  Use of external
 53.1005 +   protective security services is also important when the mechanisms
 53.1006 +   available do not themselves offer adequate integrity and/or
 53.1007 +   confidentiality protection of the authentication exchange and/or
 53.1008 +   protocol data.
 53.1009 +
 53.1010 +
 53.1011 +
 53.1012 +
 53.1013 +Melnikov & Zeilenga         Standards Track                    [Page 18]
 53.1014 +
 53.1015 +RFC 4422                          SASL                         June 2006
 53.1016 +
 53.1017 +
 53.1018 +6.1.  Active Attacks
 53.1019 +
 53.1020 +6.1.1.  Hijack Attacks
 53.1021 +
 53.1022 +   When the client selects a SASL security layer with at least integrity
 53.1023 +   protection, this protection serves as a counter-measure against an
 53.1024 +   active attacker hijacking the connection and modifying protocol data
 53.1025 +   sent after establishment of the security layer.  Implementations
 53.1026 +   SHOULD close the connection when the security services in a SASL
 53.1027 +   security layer report protocol data report lack of data integrity.
 53.1028 +
 53.1029 +6.1.2.  Downgrade Attacks
 53.1030 +
 53.1031 +   It is important that any security-sensitive protocol negotiations be
 53.1032 +   performed after installation of a security layer with data integrity
 53.1033 +   protection.  Protocols should be designed such that negotiations
 53.1034 +   performed prior to this installation should be revalidated after
 53.1035 +   installation is complete.  Negotiation of the SASL mechanism is
 53.1036 +   security sensitive.
 53.1037 +
 53.1038 +   When a client negotiates the authentication mechanism with the server
 53.1039 +   and/or other security features, it is possible for an active attacker
 53.1040 +   to cause a party to use the least secure security services available.
 53.1041 +   For instance, an attacker can modify the server-advertised mechanism
 53.1042 +   list or can modify the client-advertised security feature list within
 53.1043 +   a mechanism response.  To protect against this sort of attack,
 53.1044 +   implementations SHOULD NOT advertise mechanisms and/or features that
 53.1045 +   cannot meet their minimum security requirements, SHOULD NOT enter
 53.1046 +   into or continue authentication exchanges that cannot meet their
 53.1047 +   minimum security requirements, and SHOULD verify that completed
 53.1048 +   authentication exchanges result in security services that meet their
 53.1049 +   minimum security requirements.  Note that each endpoint needs to
 53.1050 +   independently verify that its security requirements are met.
 53.1051 +
 53.1052 +   In order to detect downgrade attacks to the least (or less) secure
 53.1053 +   mechanism supported, the client can discover the SASL mechanisms that
 53.1054 +   the server makes available both before the SASL authentication
 53.1055 +   exchange and after the negotiated SASL security layer (with at least
 53.1056 +   data integrity protection) has been installed through the protocol's
 53.1057 +   mechanism discovery facility.  If the client finds that the
 53.1058 +   integrity-protected list (the list obtained after the security layer
 53.1059 +   was installed) contains a stronger mechanism than those in the
 53.1060 +   previously obtained list, the client should assume that the
 53.1061 +   previously obtained list was modified by an attacker and SHOULD close
 53.1062 +   the underlying transport connection.
 53.1063 +
 53.1064 +   The client's initiation of the SASL exchange, including the selection
 53.1065 +   of a SASL mechanism, is done in the clear and may be modified by an
 53.1066 +
 53.1067 +
 53.1068 +
 53.1069 +Melnikov & Zeilenga         Standards Track                    [Page 19]
 53.1070 +
 53.1071 +RFC 4422                          SASL                         June 2006
 53.1072 +
 53.1073 +
 53.1074 +   active attacker.  It is important for any new SASL mechanisms to be
 53.1075 +   designed such that an active attacker cannot obtain an authentication
 53.1076 +   with weaker security properties by modifying the SASL mechanism name
 53.1077 +   and/or the challenges and responses.
 53.1078 +
 53.1079 +   Multi-level negotiation of security features is prone to downgrade
 53.1080 +   attack.  Protocol designers should avoid offering higher-level
 53.1081 +   negotiation of security features in protocols (e.g., above SASL
 53.1082 +   mechanism negotiation) and mechanism designers should avoid lower-
 53.1083 +   level negotiation of security features in mechanisms (e.g., below
 53.1084 +   SASL mechanism negotiation).
 53.1085 +
 53.1086 +6.1.3.  Replay Attacks
 53.1087 +
 53.1088 +   Some mechanisms may be subject to replay attacks unless protected by
 53.1089 +   external data security services (e.g., TLS).
 53.1090 +
 53.1091 +6.1.4.  Truncation Attacks
 53.1092 +
 53.1093 +   Most existing SASL security layers do not themselves offer protection
 53.1094 +   against truncation attack.  In a truncation attack, the active
 53.1095 +   attacker causes the protocol session to be closed, causing a
 53.1096 +   truncation of the possibly integrity-protected data stream that leads
 53.1097 +   to behavior of one or both the protocol peers that inappropriately
 53.1098 +   benefits the attacker.  Truncation attacks are fairly easy to defend
 53.1099 +   against in connection-oriented application-level protocols.  A
 53.1100 +   protocol can defend against these attacks by ensuring that each
 53.1101 +   information exchange has a clear final result and that each protocol
 53.1102 +   session has a graceful closure mechanism, and that these are
 53.1103 +   integrity protected.
 53.1104 +
 53.1105 +6.1.5.  Other Active Attacks
 53.1106 +
 53.1107 +   When use of a security layer is negotiated by the authentication
 53.1108 +   protocol exchange, the receiver SHOULD handle gracefully any
 53.1109 +   protected data buffer larger than the defined/negotiated maximal
 53.1110 +   size.  In particular, it MUST NOT blindly allocate the amount of
 53.1111 +   memory specified in the buffer size field, as this might cause the
 53.1112 +   "out of memory" condition.  If the receiver detects a large block, it
 53.1113 +   SHOULD close the connection.
 53.1114 +
 53.1115 +6.2.  Passive Attacks
 53.1116 +
 53.1117 +   Many mechanisms are subject to various passive attacks, including
 53.1118 +   simple eavesdropping of unprotected credential information as well as
 53.1119 +   online and offline dictionary attacks of protected credential
 53.1120 +   information.
 53.1121 +
 53.1122 +
 53.1123 +
 53.1124 +
 53.1125 +Melnikov & Zeilenga         Standards Track                    [Page 20]
 53.1126 +
 53.1127 +RFC 4422                          SASL                         June 2006
 53.1128 +
 53.1129 +
 53.1130 +6.3.  Re-keying
 53.1131 +
 53.1132 +   The secure or administratively permitted lifetimes of SASL
 53.1133 +   mechanisms' security layers are finite.  Cryptographic keys weaken as
 53.1134 +   they are used and as time passes; the more time and/or cipher-text
 53.1135 +   that a cryptanalyst has after the first use of the a key, the easier
 53.1136 +   it is for the cryptanalyst to mount attacks on the key.
 53.1137 +
 53.1138 +   Administrative limits on a security layer's lifetime may take the
 53.1139 +   form of time limits expressed in X.509 certificates, in Kerberos V
 53.1140 +   tickets, or in directories, and are often desired.  In practice, one
 53.1141 +   likely effect of administrative lifetime limits is that applications
 53.1142 +   may find that security layers stop working in the middle of
 53.1143 +   application protocol operation, such as, perhaps, during large data
 53.1144 +   transfers.  As the result of this, the connection will be closed (see
 53.1145 +   Section 3.7), which will result in an unpleasant user experience.
 53.1146 +
 53.1147 +   Re-keying (key renegotiation process) is a way of addressing the
 53.1148 +   weakening of cryptographic keys.  The SASL framework does not itself
 53.1149 +   provide for re-keying; SASL mechanisms may.  Designers of future SASL
 53.1150 +   mechanisms should consider providing re-keying services.
 53.1151 +
 53.1152 +   Implementations that wish to re-key SASL security layers where the
 53.1153 +   mechanism does not provide for re-keying SHOULD reauthenticate the
 53.1154 +   same IDs and replace the expired or soon-to-expire security layers.
 53.1155 +   This approach requires support for reauthentication in the
 53.1156 +   application protocols (see Section 3.8).
 53.1157 +
 53.1158 +6.4.  Other Considerations
 53.1159 +
 53.1160 +   Protocol designers and implementors should understand the security
 53.1161 +   considerations of mechanisms so they may select mechanisms that are
 53.1162 +   applicable to their needs.
 53.1163 +
 53.1164 +   Distributed server implementations need to be careful in how they
 53.1165 +   trust other parties.  In particular, authentication secrets should
 53.1166 +   only be disclosed to other parties that are trusted to manage and use
 53.1167 +   those secrets in a manner acceptable to the disclosing party.
 53.1168 +   Applications using SASL assume that SASL security layers providing
 53.1169 +   data confidentiality are secure even when an attacker chooses the
 53.1170 +   text to be protected by the security layer.  Similarly, applications
 53.1171 +   assume that the SASL security layer is secure even if the attacker
 53.1172 +   can manipulate the cipher-text output of the security layer.  New
 53.1173 +   SASL mechanisms are expected to meet these assumptions.
 53.1174 +
 53.1175 +
 53.1176 +
 53.1177 +
 53.1178 +
 53.1179 +
 53.1180 +
 53.1181 +Melnikov & Zeilenga         Standards Track                    [Page 21]
 53.1182 +
 53.1183 +RFC 4422                          SASL                         June 2006
 53.1184 +
 53.1185 +
 53.1186 +   Unicode security considerations [UTR36] apply to authorization
 53.1187 +   identity strings, as well as UTF-8 [RFC3629] security considerations
 53.1188 +   where UTF-8 is used.  SASLprep [RFC4013] and StringPrep [RFC3454]
 53.1189 +   security considerations also apply where used.
 53.1190 +
 53.1191 +7.  IANA Considerations
 53.1192 +
 53.1193 +7.1.  SASL Mechanism Registry
 53.1194 +
 53.1195 +   The SASL mechanism registry is maintained by IANA.  The registry is
 53.1196 +   currently available at <http://www.iana.org/assignments/sasl-
 53.1197 +   mechanisms>.
 53.1198 +
 53.1199 +   The purpose of this registry is not only to ensure uniqueness of
 53.1200 +   values used to name SASL mechanisms, but also to provide a definitive
 53.1201 +   reference to technical specifications detailing each SASL mechanism
 53.1202 +   available for use on the Internet.
 53.1203 +
 53.1204 +   There is no naming convention for SASL mechanisms; any name that
 53.1205 +   conforms to the syntax of a SASL mechanism name can be registered.
 53.1206 +
 53.1207 +   The procedure detailed in Section 7.1.1 is to be used for
 53.1208 +   registration of a value naming a specific individual mechanism.
 53.1209 +
 53.1210 +   The procedure detailed in Section 7.1.2 is to be used for
 53.1211 +   registration of a value naming a family of related mechanisms.
 53.1212 +
 53.1213 +   Comments may be included in the registry as discussed in Section
 53.1214 +   7.1.3 and may be changed as discussed in Section 7.1.4.
 53.1215 +
 53.1216 +   The SASL mechanism registry has been updated to reflect that this
 53.1217 +   document provides the definitive technical specification for SASL and
 53.1218 +   that this section provides the registration procedures for this
 53.1219 +   registry.
 53.1220 +
 53.1221 +
 53.1222 +
 53.1223 +
 53.1224 +
 53.1225 +
 53.1226 +
 53.1227 +
 53.1228 +
 53.1229 +
 53.1230 +
 53.1231 +
 53.1232 +
 53.1233 +
 53.1234 +
 53.1235 +
 53.1236 +
 53.1237 +Melnikov & Zeilenga         Standards Track                    [Page 22]
 53.1238 +
 53.1239 +RFC 4422                          SASL                         June 2006
 53.1240 +
 53.1241 +
 53.1242 +7.1.1.  Mechanism Name Registration Procedure
 53.1243 +
 53.1244 +   IANA will register new SASL mechanism names on a First Come First
 53.1245 +   Served basis, as defined in BCP 26 [RFC2434].  IANA has the right to
 53.1246 +   reject obviously bogus registration requests, but will perform no
 53.1247 +   review of claims made in the registration form.
 53.1248 +
 53.1249 +   Registration of a SASL mechanism is requested by filling in the
 53.1250 +   following template:
 53.1251 +
 53.1252 +      Subject: Registration of SASL mechanism X
 53.1253 +
 53.1254 +      SASL mechanism name (or prefix for the family):
 53.1255 +
 53.1256 +      Security considerations:
 53.1257 +
 53.1258 +      Published specification (recommended):
 53.1259 +
 53.1260 +      Person & email address to contact for further information:
 53.1261 +
 53.1262 +      Intended usage: (One of COMMON, LIMITED USE, or OBSOLETE)
 53.1263 +
 53.1264 +      Owner/Change controller:
 53.1265 +
 53.1266 +      Note: (Any other information that the author deems relevant may be
 53.1267 +      added here.)
 53.1268 +
 53.1269 +   and sending it via electronic mail to IANA at <iana@iana.org>.
 53.1270 +
 53.1271 +   While this registration procedure does not require expert review,
 53.1272 +   authors of SASL mechanisms are encouraged to seek community review
 53.1273 +   and comment whenever that is feasible.  Authors may seek community
 53.1274 +   review by posting a specification of their proposed mechanism as an
 53.1275 +   Internet-Draft.  SASL mechanisms intended for widespread use should
 53.1276 +   be standardized through the normal IETF process, when appropriate.
 53.1277 +
 53.1278 +
 53.1279 +
 53.1280 +
 53.1281 +
 53.1282 +
 53.1283 +
 53.1284 +
 53.1285 +
 53.1286 +
 53.1287 +
 53.1288 +
 53.1289 +
 53.1290 +
 53.1291 +
 53.1292 +
 53.1293 +Melnikov & Zeilenga         Standards Track                    [Page 23]
 53.1294 +
 53.1295 +RFC 4422                          SASL                         June 2006
 53.1296 +
 53.1297 +
 53.1298 +7.1.2.  Family Name Registration Procedure
 53.1299 +
 53.1300 +   As noted above, there is no general naming convention for SASL
 53.1301 +   mechanisms.  However, specifications may reserve a portion of the
 53.1302 +   SASL mechanism namespace for a set of related SASL mechanisms, a
 53.1303 +   "family" of SASL mechanisms.  Each family of SASL mechanisms is
 53.1304 +   identified by a unique prefix, such as X-.  Registration of new SASL
 53.1305 +   mechanism family names requires expert review as defined in BCP 26
 53.1306 +   [RFC2434].
 53.1307 +
 53.1308 +   Registration of a SASL family name is requested by filling in the
 53.1309 +   following template:
 53.1310 +
 53.1311 +      Subject: Registration of SASL mechanism family X
 53.1312 +
 53.1313 +      SASL family name (or prefix for the family):
 53.1314 +
 53.1315 +      Security considerations:
 53.1316 +
 53.1317 +      Published specification (recommended):
 53.1318 +
 53.1319 +      Person & email address to contact for further information:
 53.1320 +
 53.1321 +      Intended usage: (One of COMMON, LIMITED USE, or OBSOLETE)
 53.1322 +
 53.1323 +      Owner/Change controller:
 53.1324 +
 53.1325 +      Note: (Any other information that the author deems relevant may be
 53.1326 +      added here.)
 53.1327 +
 53.1328 +   and sending it via electronic mail to the IETF SASL mailing list at
 53.1329 +   <ietf-sasl@imc.org> and carbon copying IANA at <iana@iana.org>.
 53.1330 +   After allowing two weeks for community input on the IETF SASL mailing
 53.1331 +   list, the expert will determine the appropriateness of the
 53.1332 +   registration request and either approve or disapprove the request
 53.1333 +   with notice to the requestor, the mailing list, and IANA.
 53.1334 +
 53.1335 +   The review should focus on the appropriateness of the requested
 53.1336 +   family name for the proposed use and the appropriateness of the
 53.1337 +   proposed naming and registration plan for existing and future
 53.1338 +   mechanism names in the family.  The scope of this request review may
 53.1339 +   entail consideration of relevant aspects of any provided technical
 53.1340 +   specification, such as their IANA Considerations section.  However,
 53.1341 +   this review is narrowly focused on the appropriateness of the
 53.1342 +   requested registration and not on the overall soundness of any
 53.1343 +   provided technical specification.
 53.1344 +
 53.1345 +
 53.1346 +
 53.1347 +
 53.1348 +
 53.1349 +Melnikov & Zeilenga         Standards Track                    [Page 24]
 53.1350 +
 53.1351 +RFC 4422                          SASL                         June 2006
 53.1352 +
 53.1353 +
 53.1354 +   Authors are encouraged to pursue community review by posting the
 53.1355 +   technical specification as an Internet-Draft and soliciting comment
 53.1356 +   by posting to appropriate IETF mailing lists.
 53.1357 +
 53.1358 +7.1.3.  Comments on SASL Mechanism Registrations
 53.1359 +
 53.1360 +   Comments on a registered SASL mechanism/family should first be sent
 53.1361 +   to the "owner" of the mechanism/family and/or to the <ietf-
 53.1362 +   sasl@imc.org> mailing list.
 53.1363 +
 53.1364 +   Submitters of comments may, after a reasonable attempt to contact the
 53.1365 +   owner, request IANA to attach their comment to the SASL mechanism
 53.1366 +   registration itself by sending mail to <iana@iana.org>.  At IANA's
 53.1367 +   sole discretion, IANA may attach the comment to the SASL mechanism's
 53.1368 +   registration.
 53.1369 +
 53.1370 +7.1.4.  Change Control
 53.1371 +
 53.1372 +   Once a SASL mechanism registration has been published by IANA, the
 53.1373 +   author may request a change to its definition.  The change request
 53.1374 +   follows the same procedure as the registration request.
 53.1375 +
 53.1376 +   The owner of a SASL mechanism may pass responsibility for the SASL
 53.1377 +   mechanism to another person or agency by informing IANA; this can be
 53.1378 +   done without discussion or review.
 53.1379 +
 53.1380 +   The IESG may reassign responsibility for a SASL mechanism.  The most
 53.1381 +   common case of this will be to enable changes to be made to
 53.1382 +   mechanisms where the author of the registration has died, has moved
 53.1383 +   out of contact, or is otherwise unable to make changes that are
 53.1384 +   important to the community.
 53.1385 +
 53.1386 +   SASL mechanism registrations may not be deleted; mechanisms that are
 53.1387 +   no longer believed appropriate for use can be declared OBSOLETE by a
 53.1388 +   change to their "intended usage" field; such SASL mechanisms will be
 53.1389 +   clearly marked in the lists published by IANA.
 53.1390 +
 53.1391 +   The IESG is considered to be the owner of all SASL mechanisms that
 53.1392 +   are on the IETF standards track.
 53.1393 +
 53.1394 +
 53.1395 +
 53.1396 +
 53.1397 +
 53.1398 +
 53.1399 +
 53.1400 +
 53.1401 +
 53.1402 +
 53.1403 +
 53.1404 +
 53.1405 +Melnikov & Zeilenga         Standards Track                    [Page 25]
 53.1406 +
 53.1407 +RFC 4422                          SASL                         June 2006
 53.1408 +
 53.1409 +
 53.1410 +7.2.  Registration Changes
 53.1411 +
 53.1412 +   The IANA has updated the SASL mechanisms registry as follows:
 53.1413 +
 53.1414 +   1) Changed the "Intended usage" of the KERBEROS_V4 and SKEY mechanism
 53.1415 +      registrations to OBSOLETE.
 53.1416 +
 53.1417 +   2) Changed the "Published specification" of the EXTERNAL mechanism to
 53.1418 +      this document as indicated below:
 53.1419 +
 53.1420 +      Subject: Updated Registration of SASL mechanism EXTERNAL
 53.1421 +      Family of SASL mechanisms: NO
 53.1422 +      SASL mechanism name: EXTERNAL
 53.1423 +      Security considerations: See A.3 of RFC 4422
 53.1424 +      Published specification (optional, recommended): RFC 4422
 53.1425 +      Person & email address to contact for further information:
 53.1426 +          Alexey Melnikov <Alexey.Melnikov@isode.com>
 53.1427 +      Intended usage: COMMON
 53.1428 +      Owner/Change controller: IESG <iesg@ietf.org>
 53.1429 +      Note: Updates existing entry for EXTERNAL
 53.1430 +
 53.1431 +8.  References
 53.1432 +
 53.1433 +8.1.  Normative References
 53.1434 +
 53.1435 +   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
 53.1436 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
 53.1437 +
 53.1438 +   [RFC2244]     Newman, C. and J. G. Myers, "ACAP -- Application
 53.1439 +                 Configuration Access Protocol", RFC 2244, November
 53.1440 +                 1997.
 53.1441 +
 53.1442 +   [RFC2434]     Narten, T. and H. Alvestrand, "Guidelines for Writing
 53.1443 +                 an IANA Considerations Section in RFCs", BCP 26, RFC
 53.1444 +                 2434, October 1998.
 53.1445 +
 53.1446 +   [RFC2743]     Linn, J., "Generic Security Service Application Program
 53.1447 +                 Interface Version 2, Update 1", RFC 2743, January 2000.
 53.1448 +
 53.1449 +   [RFC3454]     Hoffman, P. and M. Blanchet, "Preparation of
 53.1450 +                 Internationalized Strings ("stringprep")", RFC 3454,
 53.1451 +                 December 2002.
 53.1452 +
 53.1453 +   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
 53.1454 +                 10646", STD 63, RFC 3629, November 2003.
 53.1455 +
 53.1456 +   [RFC4013]     Zeilenga, K., "SASLprep: Stringprep Profile for User
 53.1457 +                 Names and Passwords", RFC 4013, February 2005.
 53.1458 +
 53.1459 +
 53.1460 +
 53.1461 +Melnikov & Zeilenga         Standards Track                    [Page 26]
 53.1462 +
 53.1463 +RFC 4422                          SASL                         June 2006
 53.1464 +
 53.1465 +
 53.1466 +   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
 53.1467 +                 Specifications: ABNF", RFC 4234, October 2005.
 53.1468 +
 53.1469 +   [ASCII]       Coded Character Set--7-bit American Standard Code for
 53.1470 +                 Information Interchange, ANSI X3.4-1986.
 53.1471 +
 53.1472 +   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
 53.1473 +                 3.2.0" is defined by "The Unicode Standard, Version
 53.1474 +                 3.0" (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-
 53.1475 +                 61633-5), as amended by the "Unicode Standard Annex
 53.1476 +                 #27: Unicode 3.1"
 53.1477 +                 (http://www.unicode.org/reports/tr27/) and by the
 53.1478 +                 "Unicode Standard Annex #28: Unicode 3.2"
 53.1479 +                 (http://www.unicode.org/reports/tr28/).
 53.1480 +
 53.1481 +   [CharModel]   Whistler, K. and M. Davis, "Unicode Technical Report
 53.1482 +                 #17, Character Encoding Model", UTR17,
 53.1483 +                 <http://www.unicode.org/unicode/reports/tr17/>, August
 53.1484 +                 2000.
 53.1485 +
 53.1486 +   [Glossary]    The Unicode Consortium, "Unicode Glossary",
 53.1487 +                 <http://www.unicode.org/glossary/>.
 53.1488 +
 53.1489 +8.2.  Informative References
 53.1490 +
 53.1491 +   [RFC3206]     Gellens, R., "The SYS and AUTH POP Response Codes", RFC
 53.1492 +                 3206, February 2002.
 53.1493 +
 53.1494 +   [RFC3548]     Josefsson, S., "The Base16, Base32, and Base64 Data
 53.1495 +                 Encodings", RFC 3548, July 2003.
 53.1496 +
 53.1497 +   [RFC4301]     Kent, S. and K. Seo, "Security Architecture for the
 53.1498 +                 Internet Protocol", RFC 4301, December 2005.
 53.1499 +
 53.1500 +   [RFC4346]     Dierks, T. and E. Rescorla, "The Transport Layer
 53.1501 +                 Security (TLS) Protocol Version 1.1", RFC 4346, April
 53.1502 +                 2006.
 53.1503 +
 53.1504 +   [SASL-GSSAPI] Melnikov, A. (Editor), "The Kerberos V5 ("GSSAPI") SASL
 53.1505 +                 Mechanism", Work in Progress, May 2006.
 53.1506 +
 53.1507 +   [UTR36]       Davis, M., "(Draft) Unicode Technical Report #36,
 53.1508 +                 Character Encoding Model", UTR17,
 53.1509 +                 <http://www.unicode.org/unicode/reports/tr36/>,
 53.1510 +                 February 2005.
 53.1511 +
 53.1512 +   [CRAM-MD5]    Nerenberg, L., "The CRAM-MD5 SASL Mechanism", Work in
 53.1513 +                 Progress.
 53.1514 +
 53.1515 +
 53.1516 +
 53.1517 +Melnikov & Zeilenga         Standards Track                    [Page 27]
 53.1518 +
 53.1519 +RFC 4422                          SASL                         June 2006
 53.1520 +
 53.1521 +
 53.1522 +   [DIGEST-MD5]  Leach, P., C. Newman, and A. Melnikov, "Using Digest
 53.1523 +                 Authentication as a SASL Mechanism", Work in Progress,
 53.1524 +                 March 2006.
 53.1525 +
 53.1526 +9.  Acknowledgements
 53.1527 +
 53.1528 +   This document is a revision of RFC 2222 written by John Myers.
 53.1529 +
 53.1530 +   This revision is a product of the IETF Simple Authentication and
 53.1531 +   Security Layer (SASL) Working Group.
 53.1532 +
 53.1533 +   The following individuals contributed significantly to this revision:
 53.1534 +   Abhijit Menon-Sen, Hallvard Furuseth, Jeffrey Hutzelman, John Myers,
 53.1535 +   Luke Howard, Magnus Nystrom, Nicolas Williams, Peter Saint-Andre, RL
 53.1536 +   'Bob' Morgan, Rob Siemborski, Sam Hartman, Simon Josefsson, Tim
 53.1537 +   Alsop, and Tony Hansen.
 53.1538 +
 53.1539 +
 53.1540 +
 53.1541 +
 53.1542 +
 53.1543 +
 53.1544 +
 53.1545 +
 53.1546 +
 53.1547 +
 53.1548 +
 53.1549 +
 53.1550 +
 53.1551 +
 53.1552 +
 53.1553 +
 53.1554 +
 53.1555 +
 53.1556 +
 53.1557 +
 53.1558 +
 53.1559 +
 53.1560 +
 53.1561 +
 53.1562 +
 53.1563 +
 53.1564 +
 53.1565 +
 53.1566 +
 53.1567 +
 53.1568 +
 53.1569 +
 53.1570 +
 53.1571 +
 53.1572 +
 53.1573 +Melnikov & Zeilenga         Standards Track                    [Page 28]
 53.1574 +
 53.1575 +RFC 4422                          SASL                         June 2006
 53.1576 +
 53.1577 +
 53.1578 +Appendix A.  The SASL EXTERNAL Mechanism
 53.1579 +
 53.1580 +   This appendix is normative.
 53.1581 +
 53.1582 +   The EXTERNAL mechanism allows a client to request the server to use
 53.1583 +   credentials established by means external to the mechanism to
 53.1584 +   authenticate the client.  The external means may be, for instance, IP
 53.1585 +   Security [RFC4301] or TLS [RFC4346] services.  In absence of some a
 53.1586 +   priori agreement between the client and the server, the client cannot
 53.1587 +   make any assumption as to what external means the server has used to
 53.1588 +   obtain the client's credentials, nor make an assumption as to the
 53.1589 +   form of credentials.  For example, the client cannot assume that the
 53.1590 +   server will use the credentials the client has established via TLS.
 53.1591 +
 53.1592 +A.1.  EXTERNAL Technical Specification
 53.1593 +
 53.1594 +   The name of this mechanism is "EXTERNAL".
 53.1595 +
 53.1596 +   The mechanism does not provide a security layer.
 53.1597 +
 53.1598 +   The mechanism is capable of transferring an authorization identity
 53.1599 +   string.  If empty, the client is requesting to act as the identity
 53.1600 +   the server has associated with the client's credentials.  If non-
 53.1601 +   empty, the client is requesting to act as the identity represented by
 53.1602 +   the string.
 53.1603 +
 53.1604 +   The client is expected to send data first in the authentication
 53.1605 +   exchange.  Where the client does not provide an initial response data
 53.1606 +   in its request to initiate the authentication exchange, the server is
 53.1607 +   to respond to the request with an empty initial challenge and then
 53.1608 +   the client is to provide its initial response.
 53.1609 +
 53.1610 +   The client sends the initial response containing the UTF-8 [RFC3629]
 53.1611 +   encoding of the requested authorization identity string.  This
 53.1612 +   response is non-empty when the client is requesting to act as the
 53.1613 +   identity represented by the (non-empty) string.  This response is
 53.1614 +   empty when the client is requesting to act as the identity the server
 53.1615 +   associated with its authentication credentials.
 53.1616 +
 53.1617 +   The syntax of the initial response is specified as a value of the
 53.1618 +   <extern-initial-resp> production detailed below using the Augmented
 53.1619 +   Backus-Naur Form (ABNF) [RFC4234] notation.
 53.1620 +
 53.1621 +      external-initial-resp = authz-id-string
 53.1622 +      authz-id-string       = *( UTF8-char-no-nul )
 53.1623 +      UTF8-char-no-nul      = UTF8-1-no-nul / UTF8-2 / UTF8-3 / UTF8-4
 53.1624 +      UTF8-1-no-nul         = %x01-7F
 53.1625 +
 53.1626 +
 53.1627 +
 53.1628 +
 53.1629 +Melnikov & Zeilenga         Standards Track                    [Page 29]
 53.1630 +
 53.1631 +RFC 4422                          SASL                         June 2006
 53.1632 +
 53.1633 +
 53.1634 +   where the <UTF8-2>, <UTF8-3>, and <UTF8-4> productions are as defined
 53.1635 +   in [RFC3629].
 53.1636 +
 53.1637 +   There are no additional challenges and responses.
 53.1638 +
 53.1639 +   Hence, the server is to return the outcome of the authentication
 53.1640 +   exchange.
 53.1641 +
 53.1642 +   The exchange fails if
 53.1643 +
 53.1644 +   -  the client has not established its credentials via external means,
 53.1645 +
 53.1646 +   -  the client's credentials are inadequate,
 53.1647 +
 53.1648 +   -  the client provided an empty authorization identity string and the
 53.1649 +      server is unwilling or unable to associate an authorization
 53.1650 +      identity with the client's credentials,
 53.1651 +
 53.1652 +   -  the client provided a non-empty authorization identity string that
 53.1653 +      is invalid per the syntax requirements of the applicable
 53.1654 +      application protocol specification,
 53.1655 +
 53.1656 +   -  the client provided a non-empty authorization identity string
 53.1657 +      representing an identity that the client is not allowed to act as,
 53.1658 +      or
 53.1659 +
 53.1660 +   -  the server is unwilling or unable to provide service to the client
 53.1661 +      for any other reason.
 53.1662 +
 53.1663 +   Otherwise the exchange is successful.  When indicating a successful
 53.1664 +   outcome, additional data is not provided.
 53.1665 +
 53.1666 +A.2.  SASL EXTERNAL Examples
 53.1667 +
 53.1668 +   This section provides examples of EXTERNAL authentication exchanges.
 53.1669 +   The examples are intended to help the readers understand the above
 53.1670 +   text.  The examples are not definitive.  The Application
 53.1671 +   Configuration Access Protocol (ACAP) [RFC2244] is used in the
 53.1672 +   examples.
 53.1673 +
 53.1674 +   The first example shows use of EXTERNAL with an empty authorization
 53.1675 +   identity.  In this example, the initial response is not sent in the
 53.1676 +   client's request to initiate the authentication exchange.
 53.1677 +
 53.1678 +      S: * ACAP (SASL "DIGEST-MD5")
 53.1679 +      C: a001 STARTTLS
 53.1680 +      S: a001 OK "Begin TLS negotiation now"
 53.1681 +      <TLS negotiation, further commands are under TLS layer>
 53.1682 +
 53.1683 +
 53.1684 +
 53.1685 +Melnikov & Zeilenga         Standards Track                    [Page 30]
 53.1686 +
 53.1687 +RFC 4422                          SASL                         June 2006
 53.1688 +
 53.1689 +
 53.1690 +      S: * ACAP (SASL "DIGEST-MD5" "EXTERNAL")
 53.1691 +      C: a002 AUTHENTICATE "EXTERNAL"
 53.1692 +      S: + ""
 53.1693 +      C: + ""
 53.1694 +      S: a002 OK "Authenticated"
 53.1695 +
 53.1696 +   The second example shows use of EXTERNAL with an authorization
 53.1697 +   identity of "fred@example.com".  In this example, the initial
 53.1698 +   response is sent with the client's request to initiate the
 53.1699 +   authentication exchange.  This saves a round-trip.
 53.1700 +
 53.1701 +      S: * ACAP (SASL "DIGEST-MD5")
 53.1702 +      C: a001 STARTTLS
 53.1703 +      S: a001 OK "Begin TLS negotiation now"
 53.1704 +      <TLS negotiation, further commands are under TLS layer>
 53.1705 +      S: * ACAP (SASL "DIGEST-MD5" "EXTERNAL")
 53.1706 +      C: a002 AUTHENTICATE "EXTERNAL" {16+}
 53.1707 +      C: fred@example.com
 53.1708 +      S: a002 NO "Cannot assume requested authorization identity"
 53.1709 +
 53.1710 +A.3.  Security Considerations
 53.1711 +
 53.1712 +   The EXTERNAL mechanism provides no security protection; it is
 53.1713 +   vulnerable to spoofing by either client or server, active attack, and
 53.1714 +   eavesdropping.  It should only be used when adequate security
 53.1715 +   services have been established.
 53.1716 +
 53.1717 +Appendix B.  Changes since RFC 2222
 53.1718 +
 53.1719 +   This appendix is non-normative.
 53.1720 +
 53.1721 +   The material in RFC 2222 was significantly rewritten in the
 53.1722 +   production of this document.
 53.1723 +
 53.1724 +   RFC 2222, by not stating that the authorization identity string was a
 53.1725 +   string of Unicode characters, let alone character data, implied that
 53.1726 +   the authorization identity string was a string of octets.
 53.1727 +
 53.1728 +   -  The authorization identity string is now defined as a string of
 53.1729 +      Unicode characters.  The NUL (U+0000) character is prohibited.
 53.1730 +      While protocol specifications are responsible for defining the
 53.1731 +      authorization identity form, as well as the Unicode string syntax
 53.1732 +      and related semantics, mechanism specifications are responsible
 53.1733 +      for defining how the Unicode string is carried in the
 53.1734 +      authentication exchange.
 53.1735 +
 53.1736 +   -  Deleted "If so, when the client does not send data first, the
 53.1737 +      initial challenge MUST be specified as being an empty challenge."
 53.1738 +
 53.1739 +
 53.1740 +
 53.1741 +Melnikov & Zeilenga         Standards Track                    [Page 31]
 53.1742 +
 53.1743 +RFC 4422                          SASL                         June 2006
 53.1744 +
 53.1745 +
 53.1746 +   The following technical change was made to the EXTERNAL mechanism:
 53.1747 +
 53.1748 +      - The authorization identity string is to be UTF-8 encoded.
 53.1749 +
 53.1750 +      Note that protocol and mechanism specification requirements have
 53.1751 +      been significantly tightened.  Existing protocol and mechanism
 53.1752 +      specifications will need to be updated to meet these requirements.
 53.1753 +
 53.1754 +Editors' Addresses
 53.1755 +
 53.1756 +   Alexey Melnikov
 53.1757 +   Isode Limited
 53.1758 +   5 Castle Business Village
 53.1759 +   36 Station Road
 53.1760 +   Hampton, Middlesex,
 53.1761 +   TW12 2BX, United Kingdom
 53.1762 +
 53.1763 +   EMail: Alexey.Melnikov@isode.com
 53.1764 +   URI:   http://www.melnikov.ca/
 53.1765 +
 53.1766 +
 53.1767 +   Kurt D. Zeilenga
 53.1768 +   OpenLDAP Foundation
 53.1769 +
 53.1770 +   EMail: Kurt@OpenLDAP.org
 53.1771 +
 53.1772 +
 53.1773 +
 53.1774 +
 53.1775 +
 53.1776 +
 53.1777 +
 53.1778 +
 53.1779 +
 53.1780 +
 53.1781 +
 53.1782 +
 53.1783 +
 53.1784 +
 53.1785 +
 53.1786 +
 53.1787 +
 53.1788 +
 53.1789 +
 53.1790 +
 53.1791 +
 53.1792 +
 53.1793 +
 53.1794 +
 53.1795 +
 53.1796 +
 53.1797 +Melnikov & Zeilenga         Standards Track                    [Page 32]
 53.1798 +
 53.1799 +RFC 4422                          SASL                         June 2006
 53.1800 +
 53.1801 +
 53.1802 +Full Copyright Statement
 53.1803 +
 53.1804 +   Copyright (C) The Internet Society (2006).
 53.1805 +
 53.1806 +   This document is subject to the rights, licenses and restrictions
 53.1807 +   contained in BCP 78, and except as set forth therein, the authors
 53.1808 +   retain all their rights.
 53.1809 +
 53.1810 +   This document and the information contained herein are provided on an
 53.1811 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 53.1812 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
 53.1813 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
 53.1814 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
 53.1815 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 53.1816 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 53.1817 +
 53.1818 +Intellectual Property
 53.1819 +
 53.1820 +   The IETF takes no position regarding the validity or scope of any
 53.1821 +   Intellectual Property Rights or other rights that might be claimed to
 53.1822 +   pertain to the implementation or use of the technology described in
 53.1823 +   this document or the extent to which any license under such rights
 53.1824 +   might or might not be available; nor does it represent that it has
 53.1825 +   made any independent effort to identify any such rights.  Information
 53.1826 +   on the procedures with respect to rights in RFC documents can be
 53.1827 +   found in BCP 78 and BCP 79.
 53.1828 +
 53.1829 +   Copies of IPR disclosures made to the IETF Secretariat and any
 53.1830 +   assurances of licenses to be made available, or the result of an
 53.1831 +   attempt made to obtain a general license or permission for the use of
 53.1832 +   such proprietary rights by implementers or users of this
 53.1833 +   specification can be obtained from the IETF on-line IPR repository at
 53.1834 +   http://www.ietf.org/ipr.
 53.1835 +
 53.1836 +   The IETF invites any interested party to bring to its attention any
 53.1837 +   copyrights, patents or patent applications, or other proprietary
 53.1838 +   rights that may cover technology that may be required to implement
 53.1839 +   this standard.  Please address the information to the IETF at
 53.1840 +   ietf-ipr@ietf.org.
 53.1841 +
 53.1842 +Acknowledgement
 53.1843 +
 53.1844 +   Funding for the RFC Editor function is provided by the IETF
 53.1845 +   Administrative Support Activity (IASA).
 53.1846 +
 53.1847 +
 53.1848 +
 53.1849 +
 53.1850 +
 53.1851 +
 53.1852 +
 53.1853 +Melnikov & Zeilenga         Standards Track                    [Page 33]
 53.1854 +
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/docs/rfc/rfc4466.txt	Mon Sep 14 15:17:45 2009 +0900
    54.3 @@ -0,0 +1,955 @@
    54.4 +
    54.5 +
    54.6 +
    54.7 +
    54.8 +
    54.9 +
   54.10 +Network Working Group                                        A. Melnikov
   54.11 +Request for Comments: 4466                                    Isode Ltd.
   54.12 +Updates: 2088, 2342, 3501, 3502, 3516                           C. Daboo
   54.13 +Category: Standards Track                                     April 2006
   54.14 +
   54.15 +
   54.16 +                   Collected Extensions to IMAP4 ABNF
   54.17 +
   54.18 +Status of This Memo
   54.19 +
   54.20 +   This document specifies an Internet standards track protocol for the
   54.21 +   Internet community, and requests discussion and suggestions for
   54.22 +   improvements.  Please refer to the current edition of the "Internet
   54.23 +   Official Protocol Standards" (STD 1) for the standardization state
   54.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   54.25 +
   54.26 +Copyright Notice
   54.27 +
   54.28 +   Copyright (C) The Internet Society (2006).
   54.29 +
   54.30 +Abstract
   54.31 +
   54.32 +   Over the years, many documents from IMAPEXT and LEMONADE working
   54.33 +   groups, as well as many individual documents, have added syntactic
   54.34 +   extensions to many base IMAP commands described in RFC 3501.  For
   54.35 +   ease of reference, this document collects most of such ABNF changes
   54.36 +   in one place.
   54.37 +
   54.38 +   This document also suggests a set of standard patterns for adding
   54.39 +   options and extensions to several existing IMAP commands defined in
   54.40 +   RFC 3501.  The patterns provide for compatibility between existing
   54.41 +   and future extensions.
   54.42 +
   54.43 +   This document updates ABNF in RFCs 2088, 2342, 3501, 3502, and 3516.
   54.44 +   It also includes part of the errata to RFC 3501.  This document
   54.45 +   doesn't specify any semantic changes to the listed RFCs.
   54.46 +
   54.47 +
   54.48 +
   54.49 +
   54.50 +
   54.51 +
   54.52 +
   54.53 +
   54.54 +
   54.55 +
   54.56 +
   54.57 +
   54.58 +
   54.59 +
   54.60 +
   54.61 +Melnikov & Daboo            Standards Track                     [Page 1]
   54.62 +
   54.63 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
   54.64 +
   54.65 +
   54.66 +Table of Contents
   54.67 +
   54.68 +   1. Introduction ....................................................2
   54.69 +      1.1. Purpose of This Document ...................................2
   54.70 +      1.2. Conventions Used in This Document ..........................3
   54.71 +   2. IMAP ABNF Extensions ............................................3
   54.72 +      2.1. Optional Parameters with the SELECT/EXAMINE Commands .......3
   54.73 +      2.2. Extended CREATE Command ....................................4
   54.74 +      2.3. Extended RENAME Command ....................................5
   54.75 +      2.4. Extensions to FETCH and UID FETCH Commands .................6
   54.76 +      2.5. Extensions to STORE and UID STORE Commands .................6
   54.77 +      2.6. Extensions to SEARCH Command ...............................7
   54.78 +           2.6.1. Extended SEARCH Command .............................7
   54.79 +           2.6.2. ESEARCH untagged response ...........................8
   54.80 +      2.7. Extensions to APPEND Command ...............................8
   54.81 +   3. Formal Syntax ...................................................9
   54.82 +   4. Security Considerations ........................................14
   54.83 +   5. Normative References ...........................................15
   54.84 +   6. Acknowledgements ...............................................15
   54.85 +
   54.86 +1.  Introduction
   54.87 +
   54.88 +1.1.  Purpose of This Document
   54.89 +
   54.90 +   This document serves several purposes:
   54.91 +
   54.92 +      1.  rationalize and generalize ABNF for some existing IMAP
   54.93 +          extensions;
   54.94 +      2.  collect the ABNF in one place in order to minimize cross
   54.95 +          references between documents;
   54.96 +      3.  define building blocks for future extensions so that they can
   54.97 +          be used together in a compatible way.
   54.98 +
   54.99 +   It is expected that a future revision of this document will be
  54.100 +   incorporated into a revision of RFC 3501.
  54.101 +
  54.102 +   This document updates ABNF in RFCs 2088, 2342, 3501, 3502, and 3516.
  54.103 +   It also includes part of the errata to RFC 3501.  This document
  54.104 +   doesn't specify any semantic changes to the listed RFCs.
  54.105 +
  54.106 +   The ABNF in section 6 of RFC 2342 got rewritten to conform to the
  54.107 +   ABNF syntax as defined in RFC 4234 and to reference new non-terminals
  54.108 +   from RFC 3501.  It was also restructured to allow for better
  54.109 +   readability.  There were no changes "on the wire".
  54.110 +
  54.111 +   Section 2 extends ABNF for SELECT, EXAMINE, CREATE, RENAME, FETCH/UID
  54.112 +   FETCH, STORE/UID STORE, SEARCH, and APPEND commands in a consistent
  54.113 +   manner.  Extensions to all the commands but APPEND have the same
  54.114 +
  54.115 +
  54.116 +
  54.117 +Melnikov & Daboo            Standards Track                     [Page 2]
  54.118 +
  54.119 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.120 +
  54.121 +
  54.122 +   structure.  Extensibility for the APPEND command was done slightly
  54.123 +   differently in order to preserve backward compatibility with existing
  54.124 +   extensions.
  54.125 +
  54.126 +   Section 2 also defines a new ESEARCH response, whose purpose is to
  54.127 +   define a better version of the SEARCH response defined in RFC 3501.
  54.128 +
  54.129 +   Section 3 defines the collected ABNF that replaces pieces of ABNF in
  54.130 +   the aforementioned RFCs.  The collected ABNF got generalized to allow
  54.131 +   for easier future extensibility.
  54.132 +
  54.133 +1.2.  Conventions Used in This Document
  54.134 +
  54.135 +   In examples, "C:" and "S:" indicate lines sent by the client and
  54.136 +   server, respectively.
  54.137 +
  54.138 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
  54.139 +   in this document are to be interpreted as defined in "Key words for
  54.140 +   use in RFCs to Indicate Requirement Levels" [KEYWORDS].
  54.141 +
  54.142 +2.  IMAP ABNF Extensions
  54.143 +
  54.144 +   This section is not normative.  It provides some background on the
  54.145 +   intended use of different extensions and it gives some guidance about
  54.146 +   how future extensions should extend the described commands.
  54.147 +
  54.148 +2.1.  Optional Parameters with the SELECT/EXAMINE Commands
  54.149 +
  54.150 +   This document adds the ability to include one or more parameters with
  54.151 +   the IMAP SELECT (section 6.3.1 of [IMAP4]) or EXAMINE (section 6.3.2
  54.152 +   of [IMAP4]) commands, to turn on or off certain standard behaviors,
  54.153 +   or to add new optional behaviors required for a particular extension.
  54.154 +
  54.155 +   There are two possible modes of operation:
  54.156 +
  54.157 +   o  A global state change where a single use of the optional parameter
  54.158 +      will affect the session state from that time on, irrespective of
  54.159 +      subsequent SELECT/EXAMINE commands.
  54.160 +
  54.161 +   o  A per-mailbox state change that will affect the session only for
  54.162 +      the duration of the new selected state.  A subsequent
  54.163 +      SELECT/EXAMINE without the optional parameter will cancel its
  54.164 +      effect for the newly selected mailbox.
  54.165 +
  54.166 +   Optional parameters to the SELECT or EXAMINE commands are added as a
  54.167 +   parenthesized list of attribute/value pairs, and appear after the
  54.168 +   mailbox name in the standard SELECT or EXAMINE command.  The order of
  54.169 +   individual parameters is arbitrary.  A parameter value is optional
  54.170 +
  54.171 +
  54.172 +
  54.173 +Melnikov & Daboo            Standards Track                     [Page 3]
  54.174 +
  54.175 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.176 +
  54.177 +
  54.178 +   and may consist of atoms, strings, or lists in a specific order.  If
  54.179 +   the parameter value is present, it always appears in parentheses (*).
  54.180 +   Any parameter not defined by extensions that the server supports must
  54.181 +   be rejected with a BAD response.
  54.182 +
  54.183 +      Example:
  54.184 +
  54.185 +              C: a SELECT INBOX (ANNOTATE)
  54.186 +              S: ...
  54.187 +              S: a OK SELECT complete
  54.188 +
  54.189 +      In the above example, a single parameter is used with the SELECT
  54.190 +      command.
  54.191 +
  54.192 +      Example:
  54.193 +
  54.194 +              C: a EXAMINE INBOX (ANNOTATE RESPONSES ("UID Responses")
  54.195 +                 CONDSTORE)
  54.196 +              S: ...
  54.197 +              S: a OK EXAMINE complete
  54.198 +
  54.199 +      In the above example, three parameters are used with the EXAMINE
  54.200 +      command.  The second parameter consists of two items: an atom
  54.201 +      "RESPONSES" followed by a quoted string.
  54.202 +
  54.203 +      Example:
  54.204 +
  54.205 +              C: a SELECT INBOX (BLURDYBLOOP)
  54.206 +              S: a BAD Unknown parameter in SELECT command
  54.207 +
  54.208 +      In the above example, a parameter not supported by the server is
  54.209 +      used.  This results in the BAD response from the server.
  54.210 +
  54.211 +   (*) - if a parameter has a mandatory value, which can always be
  54.212 +   represented as a number or a sequence-set, the parameter value does
  54.213 +   not need the enclosing ().  See ABNF for more details.
  54.214 +
  54.215 +2.2.  Extended CREATE Command
  54.216 +
  54.217 +   Arguments:  mailbox name
  54.218 +               OPTIONAL list of CREATE parameters
  54.219 +
  54.220 +   Responses:  no specific responses for this command
  54.221 +
  54.222 +   Result:     OK - create completed
  54.223 +               NO - create failure: cannot create mailbox with
  54.224 +                    that name
  54.225 +               BAD - argument(s) invalid
  54.226 +
  54.227 +
  54.228 +
  54.229 +Melnikov & Daboo            Standards Track                     [Page 4]
  54.230 +
  54.231 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.232 +
  54.233 +
  54.234 +   This document adds the ability to include one or more parameters with
  54.235 +   the IMAP CREATE command (see section 6.3.3 of [IMAP4]), to turn on or
  54.236 +   off certain standard behaviors, or to add new optional behaviors
  54.237 +   required for a particular extension.  No CREATE parameters are
  54.238 +   defined in this document.
  54.239 +
  54.240 +   Optional parameters to the CREATE command are added as a
  54.241 +   parenthesized list of attribute/value pairs after the mailbox name.
  54.242 +   The order of individual parameters is arbitrary.  A parameter value
  54.243 +   is optional and may consist of atoms, strings, or lists in a specific
  54.244 +   order.  If the parameter value is present, it always appears in
  54.245 +   parentheses (*).  Any parameter not defined by extensions that the
  54.246 +   server supports must be rejected with a BAD response.
  54.247 +
  54.248 +   (*) - if a parameter has a mandatory value, which can always be
  54.249 +   represented as a number or a sequence-set, the parameter value does
  54.250 +   not need the enclosing ().  See ABNF for more details.
  54.251 +
  54.252 +2.3.  Extended RENAME Command
  54.253 +
  54.254 +   Arguments:  existing mailbox name
  54.255 +               new mailbox name
  54.256 +               OPTIONAL list of RENAME parameters
  54.257 +
  54.258 +   Responses:  no specific responses for this command
  54.259 +
  54.260 +   Result:     OK - rename completed
  54.261 +               NO - rename failure: cannot rename mailbox with
  54.262 +                    that name, cannot rename to mailbox with
  54.263 +                    that name, etc.
  54.264 +               BAD - argument(s) invalid
  54.265 +
  54.266 +   This document adds the ability to include one or more parameters with
  54.267 +   the IMAP RENAME command (see section 6.3.5 of [IMAP4]), to turn on or
  54.268 +   off certain standard behaviors, or to add new optional behaviors
  54.269 +   required for a particular extension.  No RENAME parameters are
  54.270 +   defined in this document.
  54.271 +
  54.272 +   Optional parameters to the RENAME command are added as a
  54.273 +   parenthesized list of attribute/value pairs after the new mailbox
  54.274 +   name.  The order of individual parameters is arbitrary.  A parameter
  54.275 +   value is optional and may consist of atoms, strings, or lists in a
  54.276 +   specific order.  If the parameter value is present, it always appears
  54.277 +   in parentheses (*).  Any parameter not defined by extensions that the
  54.278 +   server supports must be rejected with a BAD response.
  54.279 +
  54.280 +
  54.281 +
  54.282 +
  54.283 +
  54.284 +
  54.285 +Melnikov & Daboo            Standards Track                     [Page 5]
  54.286 +
  54.287 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.288 +
  54.289 +
  54.290 +   (*) - if a parameter has a mandatory value, which can always be
  54.291 +   represented as a number or a sequence-set, the parameter value does
  54.292 +   not need the enclosing ().  See ABNF for more details.
  54.293 +
  54.294 +2.4.  Extensions to FETCH and UID FETCH Commands
  54.295 +
  54.296 +   Arguments:  sequence set
  54.297 +               message data item names or macro
  54.298 +               OPTIONAL fetch modifiers
  54.299 +
  54.300 +   Responses:  untagged responses: FETCH
  54.301 +
  54.302 +   Result:     OK - fetch completed
  54.303 +               NO - fetch error: cannot fetch that data
  54.304 +               BAD - command unknown or arguments invalid
  54.305 +
  54.306 +   This document extends the syntax of the FETCH and UID FETCH commands
  54.307 +   (see section 6.4.5 of [IMAP4]) to include optional FETCH modifiers.
  54.308 +   No fetch modifiers are defined in this document.
  54.309 +
  54.310 +   The order of individual modifiers is arbitrary.  Each modifier is an
  54.311 +   attribute/value pair.  A modifier value is optional and may consist
  54.312 +   of atoms and/or strings and/or lists in a specific order.  If the
  54.313 +   modifier value is present, it always appears in parentheses (*).  Any
  54.314 +   modifiers not defined by extensions that the server supports must be
  54.315 +   rejected with a BAD response.
  54.316 +
  54.317 +   (*) - if a modifier has a mandatory value, which can always be
  54.318 +   represented as a number or a sequence-set, the modifier value does
  54.319 +   not need the enclosing ().  See ABNF for more details.
  54.320 +
  54.321 +2.5.  Extensions to STORE and UID STORE Commands
  54.322 +
  54.323 +   Arguments:  message set
  54.324 +               OPTIONAL store modifiers
  54.325 +               message data item name
  54.326 +               value for message data item
  54.327 +
  54.328 +   Responses:  untagged responses: FETCH
  54.329 +
  54.330 +   Result:     OK - store completed
  54.331 +               NO - store error: cannot store that data
  54.332 +               BAD - command unknown or arguments invalid
  54.333 +
  54.334 +   This document extends the syntax of the STORE and UID STORE commands
  54.335 +   (see section 6.4.6 of [IMAP4]) to include optional STORE modifiers.
  54.336 +   No store modifiers are defined in this document.
  54.337 +
  54.338 +
  54.339 +
  54.340 +
  54.341 +Melnikov & Daboo            Standards Track                     [Page 6]
  54.342 +
  54.343 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.344 +
  54.345 +
  54.346 +   The order of individual modifiers is arbitrary.  Each modifier is an
  54.347 +   attribute/value pair.  A modifier value is optional and may consist
  54.348 +   of atoms and/or strings and/or lists in a specific order.  If the
  54.349 +   modifier value is present, it always appears in parentheses (*).  Any
  54.350 +   modifiers not defined by extensions that the server supports must be
  54.351 +   rejected with a BAD response.
  54.352 +
  54.353 +   (*) - if a modifier has a mandatory value, which can always be
  54.354 +   represented as a number or a sequence-set, the modifier value does
  54.355 +   not need the enclosing ().  See ABNF for more details.
  54.356 +
  54.357 +2.6.  Extensions to SEARCH Command
  54.358 +
  54.359 +2.6.1.  Extended SEARCH Command
  54.360 +
  54.361 +   Arguments:  OPTIONAL result specifier
  54.362 +               OPTIONAL [CHARSET] specification
  54.363 +               searching criteria (one or more)
  54.364 +
  54.365 +   Responses:  REQUIRED untagged response: SEARCH (*)
  54.366 +
  54.367 +   Result:     OK - search completed
  54.368 +               NO - search error: cannot search that [CHARSET] or
  54.369 +                    criteria
  54.370 +               BAD - command unknown or arguments invalid
  54.371 +
  54.372 +   This section updates definition of the SEARCH command described in
  54.373 +   section 6.4.4 of [IMAP4].
  54.374 +
  54.375 +   The SEARCH command is extended to allow for result options.  This
  54.376 +   document does not define any result options.
  54.377 +
  54.378 +   The order of individual options is arbitrary.  Individual options may
  54.379 +   contain parameters enclosed in parentheses (**).  If an option has
  54.380 +   parameters, they consist of atoms and/or strings and/or lists in a
  54.381 +   specific order.  Any options not defined by extensions that the
  54.382 +   server supports must be rejected with a BAD response.
  54.383 +
  54.384 +   (*) - An extension to the SEARCH command may require another untagged
  54.385 +   response, or no untagged response to be returned.  Section 2.6.2
  54.386 +   defines a new ESEARCH untagged response that replaces the SEARCH
  54.387 +   untagged response.  Note that for a given extended SEARCH command the
  54.388 +   SEARCH and ESEARCH responses SHOULD be mutually exclusive, i.e., only
  54.389 +   one of them should be returned.
  54.390 +
  54.391 +   (**) - if an option has a mandatory parameter, which can always be
  54.392 +   represented as a number or a sequence-set, the option parameter does
  54.393 +   not need the enclosing ().  See ABNF for more details.
  54.394 +
  54.395 +
  54.396 +
  54.397 +Melnikov & Daboo            Standards Track                     [Page 7]
  54.398 +
  54.399 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.400 +
  54.401 +
  54.402 +2.6.2.  ESEARCH untagged response
  54.403 +
  54.404 +   Contents:   one or more search-return-data pairs
  54.405 +
  54.406 +   The ESEARCH response SHOULD be sent as a result of an extended SEARCH
  54.407 +   or UID SEARCH command specified in section 2.6.1.
  54.408 +
  54.409 +   The ESEARCH response starts with an optional search correlator.  If
  54.410 +   it is missing, then the response was not caused by a particular IMAP
  54.411 +   command, whereas if it is present, it contains the tag of the command
  54.412 +   that caused the response to be returned.
  54.413 +
  54.414 +   The search correlator is followed by an optional UID indicator.  If
  54.415 +   this indicator is present, all data in the ESEARCH response refers to
  54.416 +   UIDs, otherwise all returned data refers to message numbers.
  54.417 +
  54.418 +   The rest of the ESEARCH response contains one or more search data
  54.419 +   pairs.  Each pair starts with unique return item name, followed by a
  54.420 +   space and the corresponding data.  Search data pairs may be returned
  54.421 +   in any order.  Unless specified otherwise by an extension, any return
  54.422 +   item name SHOULD appear only once in an ESEARCH response.
  54.423 +
  54.424 +   Example:    S: * ESEARCH UID COUNT 5 ALL 4:19,21,28
  54.425 +
  54.426 +   Example:    S: * ESEARCH (TAG "a567") UID COUNT 5 ALL 4:19,21,28
  54.427 +
  54.428 +   Example:    S: * ESEARCH COUNT 5 ALL 1:17,21
  54.429 +
  54.430 +2.7.  Extensions to APPEND Command
  54.431 +
  54.432 +   The IMAP BINARY extension [BINARY] extends the APPEND command to
  54.433 +   allow a client to append data containing NULs by using the <literal8>
  54.434 +   syntax.  The ABNF was rewritten to allow for easier extensibility by
  54.435 +   IMAP extensions.  This document hasn't specified any semantical
  54.436 +   changes to the [BINARY] extension.
  54.437 +
  54.438 +   In addition, the non-terminal "literal8" defined in [BINARY] got
  54.439 +   extended to allow for non-synchronizing literals if both [BINARY] and
  54.440 +   [LITERAL+] extensions are supported by the server.
  54.441 +
  54.442 +   The IMAP MULTIAPPEND extension [MULTIAPPEND] extends the APPEND
  54.443 +   command to allow a client to append multiple messages atomically.
  54.444 +   This document defines a common syntax for the APPEND command that
  54.445 +   takes into consideration syntactic extensions defined by both
  54.446 +   [BINARY] and [MULTIAPPEND] extensions.
  54.447 +
  54.448 +
  54.449 +
  54.450 +
  54.451 +
  54.452 +
  54.453 +Melnikov & Daboo            Standards Track                     [Page 8]
  54.454 +
  54.455 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.456 +
  54.457 +
  54.458 +3.  Formal Syntax
  54.459 +
  54.460 +   The following syntax specification uses the Augmented Backus-Naur
  54.461 +   Form (ABNF) notation as specified in [ABNF].
  54.462 +
  54.463 +   Non-terminals referenced but not defined below are as defined by
  54.464 +   [IMAP4].
  54.465 +
  54.466 +   Except as noted otherwise, all alphabetic characters are case-
  54.467 +   insensitive.  The use of uppercase or lowercase characters to define
  54.468 +   token strings is for editorial clarity only.  Implementations MUST
  54.469 +   accept these strings in a case-insensitive fashion.
  54.470 +
  54.471 +   append          = "APPEND" SP mailbox 1*append-message
  54.472 +                     ;; only a single append-message may appear
  54.473 +                     ;; if MULTIAPPEND [MULTIAPPEND] capability
  54.474 +                     ;; is not present
  54.475 +
  54.476 +   append-message  = append-opts SP append-data
  54.477 +
  54.478 +   append-ext      = append-ext-name SP append-ext-value
  54.479 +                     ;; This non-terminal define extensions to
  54.480 +                     ;; to message metadata.
  54.481 +
  54.482 +   append-ext-name = tagged-ext-label
  54.483 +
  54.484 +   append-ext-value= tagged-ext-val
  54.485 +                     ;; This non-terminal shows recommended syntax
  54.486 +                     ;; for future extensions.
  54.487 +
  54.488 +
  54.489 +   append-data     = literal / literal8 / append-data-ext
  54.490 +
  54.491 +   append-data-ext = tagged-ext
  54.492 +                     ;; This non-terminal shows recommended syntax
  54.493 +                     ;; for future extensions,
  54.494 +                     ;; i.e., a mandatory label followed
  54.495 +                     ;; by parameters.
  54.496 +
  54.497 +   append-opts     = [SP flag-list] [SP date-time] *(SP append-ext)
  54.498 +                     ;; message metadata
  54.499 +
  54.500 +   charset         = atom / quoted
  54.501 +                     ;; Exact syntax is defined in [CHARSET].
  54.502 +
  54.503 +   create          = "CREATE" SP mailbox
  54.504 +                     [create-params]
  54.505 +                     ;; Use of INBOX gives a NO error.
  54.506 +
  54.507 +
  54.508 +
  54.509 +Melnikov & Daboo            Standards Track                     [Page 9]
  54.510 +
  54.511 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.512 +
  54.513 +
  54.514 +   create-params   = SP "(" create-param *( SP create-param) ")"
  54.515 +
  54.516 +   create-param-name = tagged-ext-label
  54.517 +
  54.518 +   create-param      = create-param-name [SP create-param-value]
  54.519 +
  54.520 +   create-param-value= tagged-ext-val
  54.521 +                     ;; This non-terminal shows recommended syntax
  54.522 +                     ;; for future extensions.
  54.523 +
  54.524 +
  54.525 +   esearch-response  = "ESEARCH" [search-correlator] [SP "UID"]
  54.526 +                        *(SP search-return-data)
  54.527 +                      ;; Note that SEARCH and ESEARCH responses
  54.528 +                      ;; SHOULD be mutually exclusive,
  54.529 +                      ;; i.e., only one of the response types
  54.530 +                      ;; should be
  54.531 +                      ;; returned as a result of a command.
  54.532 +
  54.533 +
  54.534 +   examine         = "EXAMINE" SP mailbox [select-params]
  54.535 +                     ;; modifies the original IMAP EXAMINE command
  54.536 +                     ;; to accept optional parameters
  54.537 +
  54.538 +   fetch           = "FETCH" SP sequence-set SP ("ALL" / "FULL" /
  54.539 +                     "FAST" / fetch-att /
  54.540 +                     "(" fetch-att *(SP fetch-att) ")")
  54.541 +                     [fetch-modifiers]
  54.542 +                     ;; modifies the original IMAP4 FETCH command to
  54.543 +                     ;; accept optional modifiers
  54.544 +
  54.545 +   fetch-modifiers = SP "(" fetch-modifier *(SP fetch-modifier) ")"
  54.546 +
  54.547 +   fetch-modifier  = fetch-modifier-name [ SP fetch-modif-params ]
  54.548 +
  54.549 +   fetch-modif-params  = tagged-ext-val
  54.550 +                     ;; This non-terminal shows recommended syntax
  54.551 +                     ;; for future extensions.
  54.552 +
  54.553 +   fetch-modifier-name = tagged-ext-label
  54.554 +
  54.555 +   literal8        = "~{" number ["+"] "}" CRLF *OCTET
  54.556 +                      ;; A string that might contain NULs.
  54.557 +                      ;; <number> represents the number of OCTETs
  54.558 +                      ;; in the response string.
  54.559 +                      ;; The "+" is only allowed when both LITERAL+ and
  54.560 +                      ;; BINARY extensions are supported by the server.
  54.561 +
  54.562 +
  54.563 +
  54.564 +
  54.565 +Melnikov & Daboo            Standards Track                    [Page 10]
  54.566 +
  54.567 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.568 +
  54.569 +
  54.570 +   mailbox-data      =/ Namespace-Response /
  54.571 +                        esearch-response
  54.572 +
  54.573 +   Namespace         = nil / "(" 1*Namespace-Descr ")"
  54.574 +
  54.575 +   Namespace-Command = "NAMESPACE"
  54.576 +
  54.577 +   Namespace-Descr   = "(" string SP
  54.578 +                          (DQUOTE QUOTED-CHAR DQUOTE / nil)
  54.579 +                           *(Namespace-Response-Extension) ")"
  54.580 +
  54.581 +   Namespace-Response-Extension = SP string SP
  54.582 +                     "(" string *(SP string) ")"
  54.583 +
  54.584 +   Namespace-Response = "NAMESPACE" SP Namespace
  54.585 +                        SP Namespace SP Namespace
  54.586 +         ;; This response is currently only allowed
  54.587 +         ;; if the IMAP server supports [NAMESPACE].
  54.588 +         ;; The first Namespace is the Personal Namespace(s)
  54.589 +         ;; The second Namespace is the Other Users' Namespace(s)
  54.590 +         ;; The third Namespace is the Shared Namespace(s)
  54.591 +
  54.592 +   rename          = "RENAME" SP mailbox SP mailbox
  54.593 +                     [rename-params]
  54.594 +                     ;; Use of INBOX as a destination gives
  54.595 +                     ;; a NO error, unless rename-params
  54.596 +                     ;; is not empty.
  54.597 +
  54.598 +   rename-params     = SP "(" rename-param *( SP rename-param) ")"
  54.599 +
  54.600 +   rename-param      = rename-param-name [SP rename-param-value]
  54.601 +
  54.602 +   rename-param-name = tagged-ext-label
  54.603 +
  54.604 +   rename-param-value= tagged-ext-val
  54.605 +                     ;; This non-terminal shows recommended syntax
  54.606 +                     ;; for future extensions.
  54.607 +
  54.608 +
  54.609 +   response-data   = "*" SP response-payload CRLF
  54.610 +
  54.611 +   response-payload= resp-cond-state / resp-cond-bye /
  54.612 +                     mailbox-data / message-data / capability-data
  54.613 +
  54.614 +   search          = "SEARCH" [search-return-opts]
  54.615 +                     SP search-program
  54.616 +
  54.617 +   search-correlator  = SP "(" "TAG" SP tag-string ")"
  54.618 +
  54.619 +
  54.620 +
  54.621 +Melnikov & Daboo            Standards Track                    [Page 11]
  54.622 +
  54.623 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.624 +
  54.625 +
  54.626 +   search-program     = ["CHARSET" SP charset SP]
  54.627 +                        search-key *(SP search-key)
  54.628 +                        ;; CHARSET argument to SEARCH MUST be
  54.629 +                        ;; registered with IANA.
  54.630 +
  54.631 +   search-return-data = search-modifier-name SP search-return-value
  54.632 +                        ;; Note that not every SEARCH return option
  54.633 +                        ;; is required to have the corresponding
  54.634 +                        ;; ESEARCH return data.
  54.635 +
  54.636 +   search-return-opts = SP "RETURN" SP "(" [search-return-opt
  54.637 +                        *(SP search-return-opt)] ")"
  54.638 +
  54.639 +   search-return-opt = search-modifier-name [SP search-mod-params]
  54.640 +
  54.641 +   search-return-value = tagged-ext-val
  54.642 +                        ;; Data for the returned search option.
  54.643 +                        ;; A single "nz-number"/"number" value
  54.644 +                        ;; can be returned as an atom (i.e., without
  54.645 +                        ;; quoting).  A sequence-set can be returned
  54.646 +                        ;; as an atom as well.
  54.647 +
  54.648 +   search-modifier-name = tagged-ext-label
  54.649 +
  54.650 +   search-mod-params = tagged-ext-val
  54.651 +                     ;; This non-terminal shows recommended syntax
  54.652 +                     ;; for future extensions.
  54.653 +
  54.654 +
  54.655 +   select          = "SELECT" SP mailbox [select-params]
  54.656 +                     ;; modifies the original IMAP SELECT command to
  54.657 +                     ;; accept optional parameters
  54.658 +
  54.659 +   select-params   = SP "(" select-param *(SP select-param) ")"
  54.660 +
  54.661 +   select-param    = select-param-name [SP select-param-value]
  54.662 +                     ;; a parameter to SELECT may contain one or
  54.663 +                     ;; more atoms and/or strings and/or lists.
  54.664 +
  54.665 +   select-param-name= tagged-ext-label
  54.666 +
  54.667 +   select-param-value= tagged-ext-val
  54.668 +                     ;; This non-terminal shows recommended syntax
  54.669 +                     ;; for future extensions.
  54.670 +
  54.671 +
  54.672 +   status-att-list = status-att-val *(SP status-att-val)
  54.673 +                     ;; Redefines status-att-list from RFC 3501.
  54.674 +
  54.675 +
  54.676 +
  54.677 +Melnikov & Daboo            Standards Track                    [Page 12]
  54.678 +
  54.679 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.680 +
  54.681 +
  54.682 +                     ;; status-att-val is defined in RFC 3501 errata
  54.683 +
  54.684 +   status-att-val  = ("MESSAGES" SP number) /
  54.685 +                     ("RECENT" SP number) /
  54.686 +                     ("UIDNEXT" SP nz-number) /
  54.687 +                     ("UIDVALIDITY" SP nz-number) /
  54.688 +                     ("UNSEEN" SP number)
  54.689 +                     ;; Extensions to the STATUS responses
  54.690 +                     ;; should extend this production.
  54.691 +                     ;; Extensions should use the generic
  54.692 +                     ;; syntax defined by tagged-ext.
  54.693 +
  54.694 +   store           = "STORE" SP sequence-set [store-modifiers]
  54.695 +                     SP store-att-flags
  54.696 +                     ;; extend [IMAP4] STORE command syntax
  54.697 +                     ;; to allow for optional store-modifiers
  54.698 +
  54.699 +   store-modifiers =  SP "(" store-modifier *(SP store-modifier)
  54.700 +                       ")"
  54.701 +
  54.702 +   store-modifier  = store-modifier-name [SP store-modif-params]
  54.703 +
  54.704 +   store-modif-params = tagged-ext-val
  54.705 +                     ;; This non-terminal shows recommended syntax
  54.706 +                     ;; for future extensions.
  54.707 +
  54.708 +   store-modifier-name = tagged-ext-label
  54.709 +
  54.710 +   tag-string         = string
  54.711 +                        ;; tag of the command that caused
  54.712 +                        ;; the ESEARCH response, sent as
  54.713 +                        ;; a string.
  54.714 +
  54.715 +   tagged-ext          = tagged-ext-label SP tagged-ext-val
  54.716 +                          ;; recommended overarching syntax for
  54.717 +                          ;; extensions
  54.718 +
  54.719 +   tagged-ext-label    = tagged-label-fchar *tagged-label-char
  54.720 +                         ;; Is a valid RFC 3501 "atom".
  54.721 +
  54.722 +   tagged-label-fchar  = ALPHA / "-" / "_" / "."
  54.723 +
  54.724 +   tagged-label-char   = tagged-label-fchar / DIGIT / ":"
  54.725 +
  54.726 +
  54.727 +
  54.728 +
  54.729 +
  54.730 +
  54.731 +
  54.732 +
  54.733 +Melnikov & Daboo            Standards Track                    [Page 13]
  54.734 +
  54.735 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.736 +
  54.737 +
  54.738 +   tagged-ext-comp     = astring /
  54.739 +                         tagged-ext-comp *(SP tagged-ext-comp) /
  54.740 +                         "(" tagged-ext-comp ")"
  54.741 +                          ;; Extensions that follow this general
  54.742 +                          ;; syntax should use nstring instead of
  54.743 +                          ;; astring when appropriate in the context
  54.744 +                          ;; of the extension.
  54.745 +                          ;; Note that a message set or a "number"
  54.746 +                          ;; can always be represented as an "atom".
  54.747 +                          ;; An URL should be represented as
  54.748 +                          ;; a "quoted" string.
  54.749 +
  54.750 +   tagged-ext-simple   = sequence-set / number
  54.751 +
  54.752 +   tagged-ext-val      = tagged-ext-simple /
  54.753 +                         "(" [tagged-ext-comp] ")"
  54.754 +
  54.755 +4.  Security Considerations
  54.756 +
  54.757 +   This document updates ABNF in RFCs 2088, 2342, 3501, 3502, and 3516.
  54.758 +   The updated documents must be consulted for security considerations
  54.759 +   for the extensions that they define.
  54.760 +
  54.761 +   As a protocol gets more complex, parser bugs become more common
  54.762 +   including buffer overflow, denial of service, and other common
  54.763 +   security coding errors.  To the extent that this document makes the
  54.764 +   parser more complex, it makes this situation worse.  To the extent
  54.765 +   that this document makes the parser more consistent and thus simpler,
  54.766 +   the situation is improved.  The impact will depend on how many
  54.767 +   deployed IMAP extensions are consistent with this document.
  54.768 +   Implementers are encouraged to take care of these issues when
  54.769 +   extending existing implementations.  Future IMAP extensions should
  54.770 +   strive for consistency and simplicity to the greatest extent
  54.771 +   possible.
  54.772 +
  54.773 +   Extensions to IMAP commands that are permitted in NOT AUTHENTICATED
  54.774 +   state are more sensitive to these security issues due to the larger
  54.775 +   possible attacker community prior to authentication, and the fact
  54.776 +   that some IMAP servers run with elevated privileges in that state.
  54.777 +   This document does not extend any commands permitted in NOT
  54.778 +   AUTHENTICATED state.  Future IMAP extensions to commands permitted in
  54.779 +   NOT AUTHENTICATED state should favor simplicity over consistency or
  54.780 +   extensibility.
  54.781 +
  54.782 +
  54.783 +
  54.784 +
  54.785 +
  54.786 +
  54.787 +
  54.788 +
  54.789 +Melnikov & Daboo            Standards Track                    [Page 14]
  54.790 +
  54.791 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.792 +
  54.793 +
  54.794 +5.  Normative References
  54.795 +
  54.796 +   [KEYWORDS]    Bradner, S., "Key words for use in RFCs to Indicate
  54.797 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
  54.798 +
  54.799 +   [IMAP4]       Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
  54.800 +                 VERSION 4rev1", RFC 3501, March 2003.
  54.801 +
  54.802 +   [ABNF]        Crocker, D., Ed., and P. Overell, "Augmented BNF for
  54.803 +                 Syntax Specifications: ABNF", RFC 4234, October 2005.
  54.804 +
  54.805 +   [CHARSET]     Freed, N. and J. Postel, "IANA Charset Registration
  54.806 +                 Procedures", BCP 19, RFC 2978, October 2000.
  54.807 +
  54.808 +   [MULTIAPPEND] Crispin, M., "Internet Message Access Protocol (IMAP) -
  54.809 +                 MULTIAPPEND Extension", RFC 3502, March 2003.
  54.810 +
  54.811 +   [NAMESPACE]   Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
  54.812 +                 May 1998.
  54.813 +
  54.814 +   [LITERAL+]    Myers, J., "IMAP4 non-synchronizing literals", RFC
  54.815 +                 2088, January 1997.
  54.816 +
  54.817 +   [BINARY]      Nerenberg, L., "IMAP4 Binary Content Extension", RFC
  54.818 +                 3516, April 2003.
  54.819 +
  54.820 +6.  Acknowledgements
  54.821 +
  54.822 +   This documents is based on ideas proposed by Pete Resnick, Mark
  54.823 +   Crispin, Ken Murchison, Philip Guenther, Randall Gellens, and Lyndon
  54.824 +   Nerenberg.
  54.825 +
  54.826 +   However, all errors and omissions must be attributed to the authors
  54.827 +   of the document.
  54.828 +
  54.829 +   Thanks to Philip Guenther, Dave Cridland, Mark Crispin, Chris Newman,
  54.830 +   Elwyn Davies, and Barry Leiba for comments and corrections.
  54.831 +
  54.832 +   literal8 syntax was taken from RFC 3516.
  54.833 +
  54.834 +
  54.835 +
  54.836 +
  54.837 +
  54.838 +
  54.839 +
  54.840 +
  54.841 +
  54.842 +
  54.843 +
  54.844 +
  54.845 +Melnikov & Daboo            Standards Track                    [Page 15]
  54.846 +
  54.847 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.848 +
  54.849 +
  54.850 +Authors' Addresses
  54.851 +
  54.852 +   Alexey Melnikov
  54.853 +   Isode Limited
  54.854 +   5 Castle Business Village
  54.855 +   36 Station Road
  54.856 +   Hampton, Middlesex, TW12 2BX
  54.857 +   UK
  54.858 +
  54.859 +   EMail: Alexey.Melnikov@isode.com
  54.860 +
  54.861 +
  54.862 +   Cyrus Daboo
  54.863 +
  54.864 +   EMail: cyrus@daboo.name
  54.865 +
  54.866 +
  54.867 +
  54.868 +
  54.869 +
  54.870 +
  54.871 +
  54.872 +
  54.873 +
  54.874 +
  54.875 +
  54.876 +
  54.877 +
  54.878 +
  54.879 +
  54.880 +
  54.881 +
  54.882 +
  54.883 +
  54.884 +
  54.885 +
  54.886 +
  54.887 +
  54.888 +
  54.889 +
  54.890 +
  54.891 +
  54.892 +
  54.893 +
  54.894 +
  54.895 +
  54.896 +
  54.897 +
  54.898 +
  54.899 +
  54.900 +
  54.901 +Melnikov & Daboo            Standards Track                    [Page 16]
  54.902 +
  54.903 +RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
  54.904 +
  54.905 +
  54.906 +Full Copyright Statement
  54.907 +
  54.908 +   Copyright (C) The Internet Society (2006).
  54.909 +
  54.910 +   This document is subject to the rights, licenses and restrictions
  54.911 +   contained in BCP 78, and except as set forth therein, the authors
  54.912 +   retain all their rights.
  54.913 +
  54.914 +   This document and the information contained herein are provided on an
  54.915 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  54.916 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  54.917 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  54.918 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  54.919 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  54.920 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  54.921 +
  54.922 +Intellectual Property
  54.923 +
  54.924 +   The IETF takes no position regarding the validity or scope of any
  54.925 +   Intellectual Property Rights or other rights that might be claimed to
  54.926 +   pertain to the implementation or use of the technology described in
  54.927 +   this document or the extent to which any license under such rights
  54.928 +   might or might not be available; nor does it represent that it has
  54.929 +   made any independent effort to identify any such rights.  Information
  54.930 +   on the procedures with respect to rights in RFC documents can be
  54.931 +   found in BCP 78 and BCP 79.
  54.932 +
  54.933 +   Copies of IPR disclosures made to the IETF Secretariat and any
  54.934 +   assurances of licenses to be made available, or the result of an
  54.935 +   attempt made to obtain a general license or permission for the use of
  54.936 +   such proprietary rights by implementers or users of this
  54.937 +   specification can be obtained from the IETF on-line IPR repository at
  54.938 +   http://www.ietf.org/ipr.
  54.939 +
  54.940 +   The IETF invites any interested party to bring to its attention any
  54.941 +   copyrights, patents or patent applications, or other proprietary
  54.942 +   rights that may cover technology that may be required to implement
  54.943 +   this standard.  Please address the information to the IETF at
  54.944 +   ietf-ipr@ietf.org.
  54.945 +
  54.946 +Acknowledgement
  54.947 +
  54.948 +   Funding for the RFC Editor function is provided by the IETF
  54.949 +   Administrative Support Activity (IASA).
  54.950 +
  54.951 +
  54.952 +
  54.953 +
  54.954 +
  54.955 +
  54.956 +
  54.957 +Melnikov & Daboo            Standards Track                    [Page 17]
  54.958 +
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/docs/rfc/rfc4467.txt	Mon Sep 14 15:17:45 2009 +0900
    55.3 @@ -0,0 +1,1011 @@
    55.4 +
    55.5 +
    55.6 +
    55.7 +
    55.8 +
    55.9 +
   55.10 +Network Working Group                                         M. Crispin
   55.11 +Request for Comments: 4467                      University of Washington
   55.12 +Updates: 3501                                                   May 2006
   55.13 +Category: Standards Track
   55.14 +
   55.15 +
   55.16 +      Internet Message Access Protocol (IMAP) - URLAUTH Extension
   55.17 +
   55.18 +Status of This Memo
   55.19 +
   55.20 +   This document specifies an Internet standards track protocol for the
   55.21 +   Internet community, and requests discussion and suggestions for
   55.22 +   improvements.  Please refer to the current edition of the "Internet
   55.23 +   Official Protocol Standards" (STD 1) for the standardization state
   55.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   55.25 +
   55.26 +Copyright Notice
   55.27 +
   55.28 +   Copyright (C) The Internet Society (2006).
   55.29 +
   55.30 +Abstract
   55.31 +
   55.32 +   This document describes the URLAUTH extension to the Internet Message
   55.33 +   Access Protocol (IMAP) (RFC 3501) and the IMAP URL Scheme (IMAPURL)
   55.34 +   (RFC 2192).  This extension provides a means by which an IMAP client
   55.35 +   can use URLs carrying authorization to access limited message data on
   55.36 +   the IMAP server.
   55.37 +
   55.38 +   An IMAP server that supports this extension indicates this with a
   55.39 +   capability name of "URLAUTH".
   55.40 +
   55.41 +1.  Introduction
   55.42 +
   55.43 +   In [IMAPURL], a URL of the form imap://fred@example.com/INBOX/;uid=20
   55.44 +   requires authorization as userid "fred".  However, [IMAPURL] implies
   55.45 +   that it only supports authentication and confuses the concepts of
   55.46 +   authentication and authorization.
   55.47 +
   55.48 +   The URLAUTH extension defines an authorization mechanism for IMAP
   55.49 +   URLs to replace [IMAPURL]'s authentication-only mechanism.  URLAUTH
   55.50 +   conveys authorization in the URL string itself and reuses a portion
   55.51 +   of the syntax of the [IMAPURL] authentication mechanism to convey the
   55.52 +   authorization identity (which also defines the default namespace in
   55.53 +   [IMAP]).
   55.54 +
   55.55 +   The URLAUTH extension provides a means by which an authorized user of
   55.56 +   an IMAP server can create URLAUTH-authorized IMAP URLs.  A URLAUTH-
   55.57 +   authorized URL conveys authorization (not authentication) to the data
   55.58 +
   55.59 +
   55.60 +
   55.61 +Crispin                     Standards Track                     [Page 1]
   55.62 +
   55.63 +RFC 4467                IMAP - URLAUTH Extension                May 2006
   55.64 +
   55.65 +
   55.66 +   addressed by that URL.  This URL can be used in another IMAP session
   55.67 +   to access specific content on the IMAP server, without otherwise
   55.68 +   providing authorization to any other data (such as other data in the
   55.69 +   mailbox specified in the URL) owned by the authorizing user.
   55.70 +
   55.71 +   Conceptually, a URLAUTH-authorized URL can be thought of as a "pawn
   55.72 +   ticket" that carries no authentication information and can be
   55.73 +   redeemed by whomever presents it.  However, unlike a pawn ticket,
   55.74 +   URLAUTH has optional mechanisms to restrict the usage of a URLAUTH-
   55.75 +   authorized URL.  Using these mechanisms, URLAUTH-authorized URLs can
   55.76 +   be usable by:
   55.77 +
   55.78 +      . anonymous (the "pawn ticket" model)
   55.79 +      . authenticated users only
   55.80 +      . a specific authenticated user only
   55.81 +      . message submission acting on behalf of a specific user only
   55.82 +
   55.83 +   There is also a mechanism for expiration.
   55.84 +
   55.85 +   A URLAUTH-authorized URL can be used in the argument to the BURL
   55.86 +   command in message composition, as described in [BURL], for such
   55.87 +   purposes as allowing a client (with limited memory or other
   55.88 +   resources) to submit a message forward or to resend from an IMAP
   55.89 +   mailbox without requiring the client to fetch that message data.
   55.90 +
   55.91 +   The URLAUTH is generated using an authorization mechanism name and an
   55.92 +   authorization token, which is generated using a secret mailbox access
   55.93 +   key.  An IMAP client can request that the server generate and assign
   55.94 +   a new mailbox access key (thus effectively revoking all current URLs
   55.95 +   using URLAUTH with the old mailbox access key) but cannot set the
   55.96 +   mailbox access key to a key of its own choosing.
   55.97 +
   55.98 +1.1.  Conventions Used in this Document
   55.99 +
  55.100 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
  55.101 +   in this document are to be interpreted as defined in [KEYWORDS].
  55.102 +
  55.103 +   The formal syntax uses the Augmented Backus-Naur Form (ABNF) notation
  55.104 +   including the core rules defined in Appendix A of [ABNF].
  55.105 +
  55.106 +   In examples, "C:" and "S:" indicate lines sent by the client and
  55.107 +   server, respectively.  If a single "C:" or "S:" label applies to
  55.108 +   multiple lines, then the line breaks between those lines are for
  55.109 +   editorial clarity only and are not part of the actual protocol
  55.110 +   exchange.
  55.111 +
  55.112 +
  55.113 +
  55.114 +
  55.115 +
  55.116 +
  55.117 +Crispin                     Standards Track                     [Page 2]
  55.118 +
  55.119 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.120 +
  55.121 +
  55.122 +2.  Concepts
  55.123 +
  55.124 +2.1.  URLAUTH
  55.125 +
  55.126 +   The URLAUTH is a component, appended at the end of a URL, that
  55.127 +   conveys authorization to access the data addressed by that URL.  It
  55.128 +   contains an authorized access identifier, an authorization mechanism
  55.129 +   name, and an authorization token.  The authorization token is
  55.130 +   generated from the URL, the authorized access identifier, the
  55.131 +   authorization mechanism name, and a mailbox access key.
  55.132 +
  55.133 +2.2.  Mailbox Access Key
  55.134 +
  55.135 +   The mailbox access key is a random string with at least 128 bits of
  55.136 +   entropy.  It is generated by software (not by the human user) and
  55.137 +   MUST be unpredictable.
  55.138 +
  55.139 +   Each user has a table of mailboxes and an associated mailbox access
  55.140 +   key for each mailbox.  Consequently, the mailbox access key is per-
  55.141 +   user and per-mailbox.  In other words, two users sharing the same
  55.142 +   mailbox each have a different mailbox access key for that mailbox,
  55.143 +   and each mailbox accessed by a single user also has a different
  55.144 +   mailbox access key.
  55.145 +
  55.146 +2.3.  Authorized Access Identifier
  55.147 +
  55.148 +   The authorized access identifier restricts use of the URLAUTH
  55.149 +   authorized URL to certain users authorized on the server, as
  55.150 +   described in section 3.
  55.151 +
  55.152 +2.4.  Authorization Mechanism
  55.153 +
  55.154 +   The authorization mechanism is the algorithm by which the URLAUTH is
  55.155 +   generated and subsequently verified, using the mailbox access key.
  55.156 +
  55.157 +2.4.1.  INTERNAL Authorization Mechanism
  55.158 +
  55.159 +   This specification defines the INTERNAL mechanism, which uses a token
  55.160 +   generation algorithm of the server's choosing and does not involve
  55.161 +   disclosure of the mailbox access key to the client.
  55.162 +
  55.163 +      Note: The token generation algorithm chosen by the server
  55.164 +      implementation should be modern and reasonably secure.  At the
  55.165 +      time of the writing of this document, an [HMAC] such as HMAC-SHA1
  55.166 +      is recommended.
  55.167 +
  55.168 +
  55.169 +
  55.170 +
  55.171 +
  55.172 +
  55.173 +Crispin                     Standards Track                     [Page 3]
  55.174 +
  55.175 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.176 +
  55.177 +
  55.178 +      If it becomes necessary to change the token generation algorithm
  55.179 +      of the INTERNAL mechanism (e.g., because an attack against the
  55.180 +      current algorithm has been discovered), all currently existing
  55.181 +      URLAUTH-authorized URLs are invalidated by the change in
  55.182 +      algorithm.  Since this would be an unpleasant surprise to
  55.183 +      applications that depend upon the validity of a URLAUTH-authorized
  55.184 +      URL, and there is no good way to do a bulk update of existing
  55.185 +      deployed URLs, it is best to avoid this situation by using a
  55.186 +      secure algorithm as opposed to one that is "good enough".
  55.187 +
  55.188 +      Server implementations SHOULD consider the possibility of changing
  55.189 +      the algorithm.  In some cases, it may be desirable to implement
  55.190 +      the change of algorithm in a way that newly-generated tokens use
  55.191 +      the new algorithm, but that for a limited period of time tokens
  55.192 +      using either the new or old algorithm can be validated.
  55.193 +      Consequently, the server SHOULD incorporate some means of
  55.194 +      identifying the token generation algorithm within the token.
  55.195 +
  55.196 +   Although this specification is extensible for other mechanisms, none
  55.197 +   are defined in this document.  In addition to the mechanism name
  55.198 +   itself, other mechanisms may have mechanism-specific data, which is
  55.199 +   to be interpreted according to the definition of that mechanism.
  55.200 +
  55.201 +2.5.  Authorization Token
  55.202 +
  55.203 +   The authorization token is a deterministic string of at least 128
  55.204 +   bits that an entity with knowledge of the secret mailbox access key
  55.205 +   and URL authorization mechanism can use to verify the URL.
  55.206 +
  55.207 +3.  IMAP URL Extensions
  55.208 +
  55.209 +   [IMAPURL] is extended by allowing the addition of
  55.210 +   ";EXPIRE=<datetime>" and ";URLAUTH=<access>:<mech>:<token>" to IMAP
  55.211 +   URLs that refer to a specific message or message parts.
  55.212 +
  55.213 +   The URLAUTH is comprised of ";URLAUTH=<access>:<mech>:<token>" and
  55.214 +   MUST be at the end of the URL.
  55.215 +
  55.216 +   URLAUTH does not apply to, and MUST NOT be used with, any IMAP URL
  55.217 +   that refers to an entire IMAP server, a list of mailboxes, an entire
  55.218 +   IMAP mailbox, or IMAP search results.
  55.219 +
  55.220 +   When ";EXPIRE=<datetime>" is used, this indicates the latest date and
  55.221 +   time that the URL is valid.  After that date and time, the URL has
  55.222 +   expired, and server implementations MUST reject the URL.  If
  55.223 +   ";EXPIRE=<datetime>" is not used, the URL has no expiration, but
  55.224 +   still can be revoked as discussed below.
  55.225 +
  55.226 +
  55.227 +
  55.228 +
  55.229 +Crispin                     Standards Track                     [Page 4]
  55.230 +
  55.231 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.232 +
  55.233 +
  55.234 +   The URLAUTH takes the form ";URLAUTH=<access>:<mech>:<token>".  It is
  55.235 +   composed of three parts.  The <access> portion provides the
  55.236 +   authorized access identifiers, which may constrain the operations and
  55.237 +   users that are permitted to use this URL.  The <mech> portion
  55.238 +   provides the authorization mechanism used by the IMAP server to
  55.239 +   generate the authorization token that follows.  The <token> portion
  55.240 +   provides the authorization token.
  55.241 +
  55.242 +   The "submit+" access identifier prefix, followed by a userid,
  55.243 +   indicates that only a userid authorized as a message submission
  55.244 +   entity on behalf of the specified userid is permitted to use this
  55.245 +   URL.  The IMAP server does not validate the specified userid but does
  55.246 +   validate that the IMAP session has an authorization identity that is
  55.247 +   authorized as a message submission entity.  The authorized message
  55.248 +   submission entity MUST validate the userid prior to contacting the
  55.249 +   IMAP server.
  55.250 +
  55.251 +   The "user+" access identifier prefix, followed by a userid, indicates
  55.252 +   that use of this URL is limited to IMAP sessions that are logged in
  55.253 +   as the specified userid (that is, have authorization identity as that
  55.254 +   userid).
  55.255 +
  55.256 +      Note: If a SASL mechanism that provides both authorization and
  55.257 +      authentication identifiers is used to authenticate to the IMAP
  55.258 +      server, the "user+" access identifier MUST match the authorization
  55.259 +      identifier.
  55.260 +
  55.261 +   The "authuser" access identifier indicates that use of this URL is
  55.262 +   limited to IMAP sessions that are logged in as an authorized user
  55.263 +   (that is, have authorization identity as an authorized user) of that
  55.264 +   IMAP server.  Use of this URL is prohibited to anonymous IMAP
  55.265 +   sessions.
  55.266 +
  55.267 +   The "anonymous" access identifier indicates that use of this URL is
  55.268 +   not restricted by session authorization identity; that is, any IMAP
  55.269 +   session in authenticated or selected state (as defined in [IMAP]),
  55.270 +   including anonymous sessions, may issue a URLFETCH using this URL.
  55.271 +
  55.272 +   The authorization token is represented as an ASCII-encoded
  55.273 +   hexadecimal string, which is used to authorize the URL.  The length
  55.274 +   and the calculation of the authorization token depends upon the
  55.275 +   mechanism used; but, in all cases, the authorization token is at
  55.276 +   least 128 bits (and therefore at least 32 hexadecimal digits).
  55.277 +
  55.278 +
  55.279 +
  55.280 +
  55.281 +
  55.282 +
  55.283 +
  55.284 +
  55.285 +Crispin                     Standards Track                     [Page 5]
  55.286 +
  55.287 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.288 +
  55.289 +
  55.290 +4.  Discussion of URLAUTH Authorization Issues
  55.291 +
  55.292 +   In [IMAPURL], the userid before the "@" in the URL has two purposes:
  55.293 +
  55.294 +      1) It provides context for user-specific mailbox paths such as
  55.295 +         "INBOX".
  55.296 +
  55.297 +      2) It specifies that resolution of the URL requires logging in as
  55.298 +         that user and limits use of that URL to only that user.
  55.299 +
  55.300 +   An obvious limitation of using the same field for both purposes is
  55.301 +   that the URL can only be resolved by the mailbox owner.
  55.302 +
  55.303 +   URLAUTH overrides the second purpose of the userid in the IMAP URL
  55.304 +   and by default permits the URL to be resolved by any user permitted
  55.305 +   by the access identifier.
  55.306 +
  55.307 +   The "user+<userid>" access identifier limits resolution of that URL
  55.308 +   to a particular userid, whereas the "submit+<userid>" access
  55.309 +   identifier is more general and simply requires that the session be
  55.310 +   authorized by a user that has been granted a "submit" role within the
  55.311 +   authentication system.  Use of either of these access identifiers
  55.312 +   makes it impossible for an attacker, spying on the session, to use
  55.313 +   the same URL, either directly or by submission to a message
  55.314 +   submission entity.
  55.315 +
  55.316 +   The "authuser" and "anonymous" access identifiers do not have this
  55.317 +   level of protection and should be used with caution.  These access
  55.318 +   identifiers are primarily useful for public export of data from an
  55.319 +   IMAP server, without requiring that it be copied to a web or
  55.320 +   anonymous FTP server.  Refer to the Security Considerations for more
  55.321 +   details.
  55.322 +
  55.323 +5.  Generation of URLAUTH-Authorized URLs
  55.324 +
  55.325 +   A URLAUTH-authorized URL is generated from an initial URL as follows:
  55.326 +
  55.327 +   An initial URL is built, ending with ";URLAUTH=<access>" but without
  55.328 +   the ":<mech>:<token>" components.  An authorization mechanism is
  55.329 +   selected and used to calculate the authorization token, with the
  55.330 +   initial URL as the data and a secret known to the IMAP server as the
  55.331 +   key.  The URLAUTH-authorized URL is generated by taking the initial
  55.332 +   URL and appending ":", the URL authorization mechanism name, ":", and
  55.333 +   the ASCII-encoded hexadecimal representation of the authorization
  55.334 +   token.
  55.335 +
  55.336 +
  55.337 +
  55.338 +
  55.339 +
  55.340 +
  55.341 +Crispin                     Standards Track                     [Page 6]
  55.342 +
  55.343 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.344 +
  55.345 +
  55.346 +      Note: ASCII-encoded hexadecimal is used instead of BASE64 because
  55.347 +      a BASE64 representation may have "=" padding characters, which
  55.348 +      would be problematic in a URL.
  55.349 +
  55.350 +   In the INTERNAL mechanism, the mailbox access key for that mailbox is
  55.351 +   the secret known to the IMAP server, and a server-selected algorithm
  55.352 +   is used as described in section 2.4.1.
  55.353 +
  55.354 +6.  Validation of URLAUTH-authorized URLs
  55.355 +
  55.356 +   A URLAUTH-authorized URL is validated as follows:
  55.357 +
  55.358 +   The URL is split at the ":" that separates "<access>" from
  55.359 +   "<mech>:<token>" in the ";URLAUTH=<access>:<mech>:<token>" portion of
  55.360 +   the URL.  The "<mech>:<token>" portion is first parsed and saved as
  55.361 +   the authorization mechanism and the authorization token.  The URL is
  55.362 +   truncated, discarding the ":" described above, to create a "rump URL"
  55.363 +   (the URL minus the ":" and the "<mech>:<token>" portion).  The rump
  55.364 +   URL is then analyzed to identify the mailbox.
  55.365 +
  55.366 +   If the mailbox cannot be identified, an authorization token is
  55.367 +   calculated on the rump URL, using random "plausible" keys (selected
  55.368 +   by the server) as needed, before returning a validation failure.
  55.369 +   This prevents timing attacks aimed at identifying mailbox names.
  55.370 +
  55.371 +   If the mailbox can be identified, the authorization token is
  55.372 +   calculated on the rump URL and a secret known to the IMAP server
  55.373 +   using the given URL authorization mechanism.  Validation is
  55.374 +   successful if, and only if, the calculated authorization token for
  55.375 +   that mechanism matches the authorization token supplied in
  55.376 +   ";URLAUTH=<access>:<mech>:<token>".
  55.377 +
  55.378 +   Removal of the ":<mech>:<token>" portion of the URL MUST be the only
  55.379 +   operation applied to the URLAUTH-authorized URL to get the rump URL.
  55.380 +   In particular, URL percent escape decoding and case-folding
  55.381 +   (including to the domain part of the URL) MUST NOT occur.
  55.382 +
  55.383 +   In the INTERNAL mechanism, the mailbox access key for that mailbox is
  55.384 +   used as the secret known to the IMAP server, and the same server-
  55.385 +   selected algorithm used for generating URLs is used to calculate the
  55.386 +   authorization token for verification.
  55.387 +
  55.388 +
  55.389 +
  55.390 +
  55.391 +
  55.392 +
  55.393 +
  55.394 +
  55.395 +
  55.396 +
  55.397 +Crispin                     Standards Track                     [Page 7]
  55.398 +
  55.399 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.400 +
  55.401 +
  55.402 +7.  Additional Commands
  55.403 +
  55.404 +   These commands are extensions to the [IMAP] base protocol.
  55.405 +
  55.406 +   The section headings of these commands are intended to correspond
  55.407 +   with where they would be located in the base protocol document if
  55.408 +   they were part of that document.
  55.409 +
  55.410 +BASE.6.3.RESETKEY.  RESETKEY Command
  55.411 +
  55.412 +   Arguments:  optional mailbox name
  55.413 +               optional mechanism name(s)
  55.414 +
  55.415 +   Responses:  none other than in result
  55.416 +
  55.417 +   Result:     OK - RESETKEY completed, URLMECH containing new data
  55.418 +               NO - RESETKEY error: can't change key of that mailbox
  55.419 +               BAD - command unknown or arguments invalid
  55.420 +
  55.421 +   The RESETKEY command has two forms.
  55.422 +
  55.423 +   The first form accepts a mailbox name as an argument and generates a
  55.424 +   new mailbox access key for the given mailbox in the user's mailbox
  55.425 +   access key table, replacing any previous mailbox access key (and
  55.426 +   revoking any URLs that were authorized with a URLAUTH using that key)
  55.427 +   in that table.  By default, the mailbox access key is generated for
  55.428 +   the INTERNAL mechanism; other mechanisms can be specified with the
  55.429 +   optional mechanism argument.
  55.430 +
  55.431 +   The second form, with no arguments, removes all mailbox access keys
  55.432 +   in the user's mailbox access key table, revoking all URLs currently
  55.433 +   authorized using URLAUTH by the user.
  55.434 +
  55.435 +   Any current IMAP session logged in as the user that has the mailbox
  55.436 +   selected will receive an untagged OK response with the URLMECH status
  55.437 +   response code (see section BASE.7.1.URLMECH for more details about
  55.438 +   the URLMECH status response code).
  55.439 +
  55.440 +   Example:
  55.441 +
  55.442 +      C: a31 RESETKEY
  55.443 +      S: a31 OK All keys removed
  55.444 +      C: a32 RESETKEY INBOX
  55.445 +      S: a32 OK [URLMECH INTERNAL] mechs
  55.446 +      C: a33 RESETKEY INBOX XSAMPLE
  55.447 +      S: a33 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done
  55.448 +
  55.449 +
  55.450 +
  55.451 +
  55.452 +
  55.453 +Crispin                     Standards Track                     [Page 8]
  55.454 +
  55.455 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.456 +
  55.457 +
  55.458 +BASE.6.3.GENURLAUTH.  GENURLAUTH Command
  55.459 +
  55.460 +      Argument:   one or more URL/mechanism pairs
  55.461 +
  55.462 +      Response:   untagged response: GENURLAUTH
  55.463 +
  55.464 +      Result:     OK - GENURLAUTH completed
  55.465 +                  NO - GENURLAUTH error: can't generate a URLAUTH
  55.466 +                  BAD - command unknown or arguments invalid
  55.467 +
  55.468 +   The GENURLAUTH command requests that the server generate a URLAUTH-
  55.469 +   authorized URL for each of the given URLs using the given URL
  55.470 +   authorization mechanism.
  55.471 +
  55.472 +   The server MUST validate each supplied URL as follows:
  55.473 +
  55.474 +      (1) The mailbox component of the URL MUST refer to an existing
  55.475 +          mailbox.
  55.476 +
  55.477 +      (2) The server component of the URL MUST contain a valid userid
  55.478 +          that identifies the owner of the mailbox access key table that
  55.479 +          will be used to generate the URLAUTH-authorized URL.  As a
  55.480 +          consequence, the iserver rule of [IMAPURL] is modified so that
  55.481 +          iuserauth is mandatory.
  55.482 +
  55.483 +             Note: the server component of the URL is generally the
  55.484 +             logged in userid and server.  If not, then the logged in
  55.485 +             userid and server MUST have owner-type access to the
  55.486 +             mailbox access key table owned by the userid and server
  55.487 +             indicated by the server component of the URL.
  55.488 +
  55.489 +      (3) There is a valid access identifier that, in the case of
  55.490 +          "submit+" and "user+", will contain a valid userid.  This
  55.491 +          userid is not necessarily the same as the owner userid
  55.492 +          described in (2).
  55.493 +
  55.494 +      (4) The server MAY also verify that the iuid and/or isection
  55.495 +          components (if present) are valid.
  55.496 +
  55.497 +   If any of the above checks fail, the server MUST return a tagged BAD
  55.498 +   response with the following exception.  If an invalid userid is
  55.499 +   supplied as the mailbox access key owner and/or as part of the access
  55.500 +   identifier, the server MAY issue a tagged OK response with a
  55.501 +   generated mailbox key that always fails validation when used with a
  55.502 +   URLFETCH command.  This exception prevents an attacker from
  55.503 +   validating userids.
  55.504 +
  55.505 +
  55.506 +
  55.507 +
  55.508 +
  55.509 +Crispin                     Standards Track                     [Page 9]
  55.510 +
  55.511 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.512 +
  55.513 +
  55.514 +   If there is currently no mailbox access key for the given mailbox in
  55.515 +   the owner's mailbox access key table, one is automatically generated.
  55.516 +   That is, it is not necessary to use RESETKEY prior to first-time use
  55.517 +   of GENURLAUTH.
  55.518 +
  55.519 +   If the command is successful, a GENURLAUTH response code is returned
  55.520 +   listing the requested URLs as URLAUTH-authorized URLs.
  55.521 +
  55.522 +   Examples:
  55.523 +
  55.524 +      C: a775 GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/
  55.525 +         ;section=1.2" INTERNAL
  55.526 +      S: a775 BAD missing access identifier in supplied URL
  55.527 +      C: a776 GENURLAUTH "imap://example.com/Shared/;uid=20/
  55.528 +         ;section=1.2;urlauth=submit+fred" INTERNAL
  55.529 +      S: a776 BAD missing owner username in supplied URL
  55.530 +      C: a777 GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/
  55.531 +         ;section=1.2;urlauth=submit+fred" INTERNAL
  55.532 +      S: * GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
  55.533 +         ;urlauth=submit+fred:internal:91354a473744909de610943775f92038"
  55.534 +      S: a777 OK GENURLAUTH completed
  55.535 +
  55.536 +BASE.6.3.URLFETCH.  URLFETCH Command
  55.537 +
  55.538 +      Argument:   one or more URLs
  55.539 +
  55.540 +      Response:   untagged response: URLFETCH
  55.541 +
  55.542 +      Result:     OK - urlfetch completed
  55.543 +                  NO - urlfetch failed due to server internal error
  55.544 +                  BAD - command unknown or arguments invalid
  55.545 +
  55.546 +   The URLFETCH command requests that the server return the text data
  55.547 +   associated with the specified IMAP URLs, as described in [IMAPURL]
  55.548 +   and extended by this document.  The data is returned for all
  55.549 +   validated URLs, regardless of whether or not the session would
  55.550 +   otherwise be able to access the mailbox containing that data via
  55.551 +   SELECT or EXAMINE.
  55.552 +
  55.553 +      Note: This command does not require that the URL refer to the
  55.554 +      selected mailbox; nor does it require that any mailbox be
  55.555 +      selected.  It also does not in any way interfere with any selected
  55.556 +      mailbox.
  55.557 +
  55.558 +
  55.559 +
  55.560 +
  55.561 +
  55.562 +
  55.563 +
  55.564 +
  55.565 +Crispin                     Standards Track                    [Page 10]
  55.566 +
  55.567 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.568 +
  55.569 +
  55.570 +   The URLFETCH command effectively executes with the access of the
  55.571 +   userid in the server component of the URL (which is generally the
  55.572 +   userid that issued the GENURLAUTH).  By itself, the URLAUTH does NOT
  55.573 +   grant access to the data; once validated, it grants whatever access
  55.574 +   to the data is held by the userid in the server component of the URL.
  55.575 +   That access may have changed since the GENURLAUTH was done.
  55.576 +
  55.577 +   The URLFETCH command MUST return an untagged URLFETCH response and a
  55.578 +   tagged OK response to any URLFETCH command that is syntactically
  55.579 +   valid.  A NO response indicates a server internal failure that may be
  55.580 +   resolved on later retry.
  55.581 +
  55.582 +      Note: The possibility of a NO response is to accommodate
  55.583 +      implementations that would otherwise have to issue an untagged BYE
  55.584 +      with a fatal error due to an inability to respond to a valid
  55.585 +      request.  In an ideal world, a server SHOULD NOT issue a NO
  55.586 +      response.
  55.587 +
  55.588 +   The server MUST return NIL for any IMAP URL that references an entire
  55.589 +   IMAP server, a list of mailboxes, an entire IMAP mailbox, or IMAP
  55.590 +   search results.
  55.591 +
  55.592 +   Example:
  55.593 +
  55.594 +      Note: For clarity, this example uses the LOGIN command, which
  55.595 +      SHOULD NOT be used over a non-encrypted communication path.
  55.596 +
  55.597 +      This example is of a submit server, obtaining a message segment
  55.598 +      for a message that it has already validated was submitted by
  55.599 +      "fred".
  55.600 +
  55.601 +      S: * OK [CAPABILITY IMAP4REV1 URLAUTH] example.com IMAP server
  55.602 +      C: a001 LOGIN submitserver secret
  55.603 +      S: a001 OK submitserver logged in
  55.604 +      C: a002 URLFETCH "imap://joe@example.com/INBOX/;uid=20/
  55.605 +         ;section=1.2;urlauth=submit+fred:internal
  55.606 +         :91354a473744909de610943775f92038"
  55.607 +      S: * URLFETCH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
  55.608 +         ;urlauth=submit+fred:internal
  55.609 +         :91354a473744909de610943775f92038" {28}
  55.610 +      S: Si vis pacem, para bellum.
  55.611 +      S:
  55.612 +      S: a002 OK URLFETCH completed
  55.613 +
  55.614 +
  55.615 +
  55.616 +
  55.617 +
  55.618 +
  55.619 +
  55.620 +
  55.621 +Crispin                     Standards Track                    [Page 11]
  55.622 +
  55.623 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.624 +
  55.625 +
  55.626 +8.  Additional Responses
  55.627 +
  55.628 +   These responses are extensions to the [IMAP] base protocol.
  55.629 +
  55.630 +   The section headings of these responses are intended to correspond
  55.631 +   with where they would be located in the base protocol document if
  55.632 +   they were part of that document.
  55.633 +
  55.634 +BASE.7.1.URLMECH.  URLMECH Status Response Code
  55.635 +
  55.636 +   The URLMECH status response code is followed by a list of URL
  55.637 +   authorization mechanism names.  Mechanism names other than INTERNAL
  55.638 +   may be appended with an "=" and BASE64-encoded form of mechanism-
  55.639 +   specific data.
  55.640 +
  55.641 +   This status response code is returned in an untagged OK response in
  55.642 +   response to a RESETKEY, SELECT, or EXAMINE command.  In the case of
  55.643 +   the RESETKEY command, this status response code can be sent in the
  55.644 +   tagged OK response instead of requiring a separate untagged OK
  55.645 +   response.
  55.646 +
  55.647 +   Example:
  55.648 +
  55.649 +      C: a33 RESETKEY INBOX XSAMPLE
  55.650 +      S: a33 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done
  55.651 +
  55.652 +   In this example, the server supports the INTERNAL mechanism and an
  55.653 +   experimental mechanism called XSAMPLE, which also holds some
  55.654 +   mechanism-specific data (the name "XSAMPLE" is for illustrative
  55.655 +   purposes only).
  55.656 +
  55.657 +BASE.7.4.GENURLAUTH.   GENURLAUTH Response
  55.658 +
  55.659 +   Contents:   One or more URLs
  55.660 +
  55.661 +   The GENURLAUTH response returns the URLAUTH-authorized URL(s)
  55.662 +   requested by a GENURLAUTH command.
  55.663 +
  55.664 +   Example:
  55.665 +
  55.666 +      C: a777 GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/
  55.667 +         ;section=1.2;urlauth=submit+fred" INTERNAL
  55.668 +      S: * GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
  55.669 +         ;urlauth=submit+fred:internal:91354a473744909de610943775f92038"
  55.670 +      S: a777 OK GENURLAUTH completed
  55.671 +
  55.672 +
  55.673 +
  55.674 +
  55.675 +
  55.676 +
  55.677 +Crispin                     Standards Track                    [Page 12]
  55.678 +
  55.679 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.680 +
  55.681 +
  55.682 +BASE.7.4.URLFETCH.  URLFETCH Response
  55.683 +
  55.684 +   Contents:   One or more URL/nstring pairs
  55.685 +
  55.686 +   The URLFETCH response returns the message text data associated with
  55.687 +   one or more IMAP URLs, as described in [IMAPURL] and extended by this
  55.688 +   document.  This response occurs as the result of a URLFETCH command.
  55.689 +
  55.690 +   The returned data string is NIL if the URL is invalid for any reason
  55.691 +   (including validation failure).  If the URL is valid, but the IMAP
  55.692 +   fetch of the body part returned NIL (this should not happen), the
  55.693 +   returned data string should be the empty string ("") and not NIL.
  55.694 +
  55.695 +      Note: This command does not require that the URL refer to the
  55.696 +      selected mailbox; nor does it require that any mailbox be
  55.697 +      selected.  It also does not in any way interfere with any selected
  55.698 +      mailbox.
  55.699 +
  55.700 +   Example:
  55.701 +
  55.702 +      C: a002 URLFETCH "imap://joe@example.com/INBOX/;uid=20/
  55.703 +         ;section=1.2;urlauth=submit+fred:internal
  55.704 +         :91354a473744909de610943775f92038"
  55.705 +      S: * URLFETCH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
  55.706 +         ;urlauth=submit+fred:internal
  55.707 +         :91354a473744909de610943775f92038" {28}
  55.708 +      S: Si vis pacem, para bellum.
  55.709 +      S:
  55.710 +      S: a002 OK URLFETCH completed
  55.711 +
  55.712 +9.  Formal Syntax
  55.713 +
  55.714 +   The following syntax specification uses the Augmented Backus-Naur
  55.715 +   Form (ABNF) notation as specified in [ABNF].
  55.716 +
  55.717 +   The following modifications are made to the Formal Syntax in [IMAP]:
  55.718 +
  55.719 +resetkey        = "RESETKEY" [SP mailbox *(SP mechanism)]
  55.720 +
  55.721 +capability      =/ "URLAUTH"
  55.722 +
  55.723 +command-auth    =/ resetkey / genurlauth / urlfetch
  55.724 +
  55.725 +resp-text-code  =/ "URLMECH" SP "INTERNAL" *(SP mechanism ["=" base64])
  55.726 +
  55.727 +genurlauth      = "GENURLAUTH" 1*(SP url-rump SP mechanism)
  55.728 +
  55.729 +genurlauth-data = "*" SP "GENURLAUTH" 1*(SP url-full)
  55.730 +
  55.731 +
  55.732 +
  55.733 +Crispin                     Standards Track                    [Page 13]
  55.734 +
  55.735 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.736 +
  55.737 +
  55.738 +url-full        = astring
  55.739 +                     ; contains authimapurlfull as defined below
  55.740 +
  55.741 +url-rump        = astring
  55.742 +                     ; contains authimapurlrump as defined below
  55.743 +
  55.744 +urlfetch        = "URLFETCH" 1*(SP url-full)
  55.745 +
  55.746 +urlfetch-data   = "*" SP "URLFETCH" 1*(SP url-full SP nstring)
  55.747 +
  55.748 +   The following extensions are made to the Formal Syntax in [IMAPURL]:
  55.749 +
  55.750 +authimapurl     = "imap://" enc-user [iauth] "@" hostport "/"
  55.751 +                     imessagepart
  55.752 +                     ; replaces "imapurl" and "iserver" rules for
  55.753 +                     ; URLAUTH authorized URLs
  55.754 +
  55.755 +authimapurlfull = authimapurl iurlauth
  55.756 +
  55.757 +authimapurlrump = authimapurl iurlauth-rump
  55.758 +
  55.759 +enc-urlauth     = 32*HEXDIG
  55.760 +
  55.761 +enc-user        = 1*achar
  55.762 +                     ; same as "enc_user" in RFC 2192
  55.763 +
  55.764 +iurlauth        = iurlauth-rump ":" mechanism ":" enc-urlauth
  55.765 +
  55.766 +iurlauth-rump   = [expire] ";URLAUTH=" access
  55.767 +
  55.768 +access          = ("submit+" enc-user) / ("user+" enc-user) /
  55.769 +                    "authuser" / "anonymous"
  55.770 +
  55.771 +expire          = ";EXPIRE=" date-time
  55.772 +                      ; date-time defined in [DATETIME]
  55.773 +
  55.774 +mechanism       = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
  55.775 +                     ; case-insensitive
  55.776 +                     ; new mechanisms MUST be registered with IANA
  55.777 +
  55.778 +
  55.779 +
  55.780 +
  55.781 +
  55.782 +
  55.783 +
  55.784 +
  55.785 +
  55.786 +
  55.787 +
  55.788 +
  55.789 +Crispin                     Standards Track                    [Page 14]
  55.790 +
  55.791 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.792 +
  55.793 +
  55.794 +10.  Security Considerations
  55.795 +
  55.796 +   Security considerations are discussed throughout this memo.
  55.797 +
  55.798 +   The mailbox access key SHOULD have at least 128 bits of entropy
  55.799 +   (refer to [RANDOM] for more details) and MUST be unpredictable.
  55.800 +
  55.801 +   The server implementation of the INTERNAL mechanism SHOULD consider
  55.802 +   the possibility of needing to change the token generation algorithm,
  55.803 +   and SHOULD incorporate some means of identifying the token generation
  55.804 +   algorithm within the token.
  55.805 +
  55.806 +   The URLMECH status response code may expose sensitive data in the
  55.807 +   mechanism-specific data for mechanisms other than INTERNAL.  A server
  55.808 +   implementation MUST implement a configuration that will not return a
  55.809 +   URLMECH status response code unless some mechanism is provided that
  55.810 +   protects the session from snooping, such as a TLS or SASL security
  55.811 +   layer that provides confidentiality protection.
  55.812 +
  55.813 +   The calculation of an authorization token with a "plausible" key if
  55.814 +   the mailbox can not be identified is necessary to avoid attacks in
  55.815 +   which the server is probed to see if a particular mailbox exists on
  55.816 +   the server by measuring the amount of time taken to reject a known
  55.817 +   bad name versus some other name.
  55.818 +
  55.819 +   To protect against a computational denial-of-service attack, a server
  55.820 +   MAY impose progressively longer delays on multiple URL requests that
  55.821 +   fail validation.
  55.822 +
  55.823 +   The decision to use the "authuser" access identifier should be made
  55.824 +   with caution.  An "authuser" access identifier can be used by any
  55.825 +   authorized user of the IMAP server; therefore, use of this access
  55.826 +   identifier should be limited to content that may be disclosed to any
  55.827 +   authorized user of the IMAP server.
  55.828 +
  55.829 +   The decision to use the "anonymous" access identifier should be made
  55.830 +   with extreme caution.  An "anonymous" access identifier can be used
  55.831 +   by anyone; therefore, use of this access identifier should be limited
  55.832 +   to content that may be disclosed to anyone.  Many IMAP servers do not
  55.833 +   permit anonymous access; in this case, the "anonymous" access
  55.834 +   identifier is equivalent to "authuser", but this MUST NOT be relied
  55.835 +   upon.
  55.836 +
  55.837 +   Although this specification does not prohibit the theoretical
  55.838 +   capability to generate a URL with a server component other than the
  55.839 +   logged in userid and server, this capability should only be provided
  55.840 +
  55.841 +
  55.842 +
  55.843 +
  55.844 +
  55.845 +Crispin                     Standards Track                    [Page 15]
  55.846 +
  55.847 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.848 +
  55.849 +
  55.850 +   when the logged in userid/server has been authorized as equivalent to
  55.851 +   the server component userid/server, or otherwise has access to that
  55.852 +   userid/server mailbox access key table.
  55.853 +
  55.854 +11.  IANA Considerations
  55.855 +
  55.856 +   This document constitutes registration of the URLAUTH capability in
  55.857 +   the imap4-capabilities registry.
  55.858 +
  55.859 +   URLAUTH authorization mechanisms are registered by publishing a
  55.860 +   standards track or IESG-approved experimental RFC.  The registry is
  55.861 +   currently located at:
  55.862 +
  55.863 +http://www.iana.org/assignments/urlauth-authorization-mechanism-registry
  55.864 +
  55.865 +   This registry is case-insensitive.
  55.866 +
  55.867 +   This document constitutes registration of the INTERNAL URLAUTH
  55.868 +   authorization mechanism.
  55.869 +
  55.870 +   IMAP URLAUTH Authorization Mechanism Registry
  55.871 +
  55.872 +      Mechanism Name           Reference
  55.873 +      --------------           ---------
  55.874 +      INTERNAL                 [RFC4467]
  55.875 +
  55.876 +
  55.877 +
  55.878 +
  55.879 +
  55.880 +
  55.881 +
  55.882 +
  55.883 +
  55.884 +
  55.885 +
  55.886 +
  55.887 +
  55.888 +
  55.889 +
  55.890 +
  55.891 +
  55.892 +
  55.893 +
  55.894 +
  55.895 +
  55.896 +
  55.897 +
  55.898 +
  55.899 +
  55.900 +
  55.901 +Crispin                     Standards Track                    [Page 16]
  55.902 +
  55.903 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.904 +
  55.905 +
  55.906 +12.  Normative References
  55.907 +
  55.908 +   [ABNF]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
  55.909 +              Specifications: ABNF", RFC 4234, October 2005.
  55.910 +
  55.911 +   [BURL]     Newman, C., "Message Submission BURL Extension", RFC 4468,
  55.912 +              May 2006.
  55.913 +
  55.914 +   [DATETIME] Klyne, G. and C. Newman, "Date and Time on the Internet:
  55.915 +              Timestamps", RFC 3339, July 2002.
  55.916 +
  55.917 +   [IMAP]     Crispin, M., "Internet Message Access Protocol - Version
  55.918 +              4rev1", RFC 3501, March 2003.
  55.919 +
  55.920 +   [IMAPURL]  Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
  55.921 +
  55.922 +   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
  55.923 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  55.924 +
  55.925 +13.  Informative References
  55.926 +
  55.927 +   [HMAC]     Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
  55.928 +              Hashing for Message Authentication", RFC 2104, February
  55.929 +              1997.
  55.930 +
  55.931 +   [RANDOM]   Eastlake, D., 3rd, Schiller, J., and S. Crocker,
  55.932 +              "Randomness Requirements for Security", BCP 106, RFC 4086,
  55.933 +              June 2005.
  55.934 +
  55.935 +Author's Address
  55.936 +
  55.937 +   Mark R. Crispin
  55.938 +   Networks and Distributed Computing
  55.939 +   University of Washington
  55.940 +   4545 15th Avenue NE
  55.941 +   Seattle, WA  98105-4527
  55.942 +
  55.943 +   Phone: (206) 543-5762
  55.944 +   EMail: MRC@CAC.Washington.EDU
  55.945 +
  55.946 +
  55.947 +
  55.948 +
  55.949 +
  55.950 +
  55.951 +
  55.952 +
  55.953 +
  55.954 +
  55.955 +
  55.956 +
  55.957 +Crispin                     Standards Track                    [Page 17]
  55.958 +
  55.959 +RFC 4467                IMAP - URLAUTH Extension                May 2006
  55.960 +
  55.961 +
  55.962 +Full Copyright Statement
  55.963 +
  55.964 +   Copyright (C) The Internet Society (2006).
  55.965 +
  55.966 +   This document is subject to the rights, licenses and restrictions
  55.967 +   contained in BCP 78, and except as set forth therein, the authors
  55.968 +   retain all their rights.
  55.969 +
  55.970 +   This document and the information contained herein are provided on an
  55.971 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  55.972 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  55.973 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  55.974 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  55.975 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  55.976 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  55.977 +
  55.978 +Intellectual Property
  55.979 +
  55.980 +   The IETF takes no position regarding the validity or scope of any
  55.981 +   Intellectual Property Rights or other rights that might be claimed to
  55.982 +   pertain to the implementation or use of the technology described in
  55.983 +   this document or the extent to which any license under such rights
  55.984 +   might or might not be available; nor does it represent that it has
  55.985 +   made any independent effort to identify any such rights.  Information
  55.986 +   on the procedures with respect to rights in RFC documents can be
  55.987 +   found in BCP 78 and BCP 79.
  55.988 +
  55.989 +   Copies of IPR disclosures made to the IETF Secretariat and any
  55.990 +   assurances of licenses to be made available, or the result of an
  55.991 +   attempt made to obtain a general license or permission for the use of
  55.992 +   such proprietary rights by implementers or users of this
  55.993 +   specification can be obtained from the IETF on-line IPR repository at
  55.994 +   http://www.ietf.org/ipr.
  55.995 +
  55.996 +   The IETF invites any interested party to bring to its attention any
  55.997 +   copyrights, patents or patent applications, or other proprietary
  55.998 +   rights that may cover technology that may be required to implement
  55.999 +   this standard.  Please address the information to the IETF at
 55.1000 +   ietf-ipr@ietf.org.
 55.1001 +
 55.1002 +Acknowledgement
 55.1003 +
 55.1004 +   Funding for the RFC Editor function is provided by the IETF
 55.1005 +   Administrative Support Activity (IASA).
 55.1006 +
 55.1007 +
 55.1008 +
 55.1009 +
 55.1010 +
 55.1011 +
 55.1012 +
 55.1013 +Crispin                     Standards Track                    [Page 18]
 55.1014 +
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/docs/rfc/rfc4468.txt	Mon Sep 14 15:17:45 2009 +0900
    56.3 @@ -0,0 +1,787 @@
    56.4 +
    56.5 +
    56.6 +
    56.7 +
    56.8 +
    56.9 +
   56.10 +Network Working Group                                          C. Newman
   56.11 +Request for Comments: 4468                              Sun Microsystems
   56.12 +Updates: 3463                                                   May 2006
   56.13 +Category: Standards Track
   56.14 +
   56.15 +
   56.16 +                   Message Submission BURL Extension
   56.17 +
   56.18 +Status of This Memo
   56.19 +
   56.20 +   This document specifies an Internet standards track protocol for the
   56.21 +   Internet community, and requests discussion and suggestions for
   56.22 +   improvements.  Please refer to the current edition of the "Internet
   56.23 +   Official Protocol Standards" (STD 1) for the standardization state
   56.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   56.25 +
   56.26 +Copyright Notice
   56.27 +
   56.28 +   Copyright (C) The Internet Society (2006).
   56.29 +
   56.30 +Abstract
   56.31 +
   56.32 +   The submission profile of Simple Mail Transfer Protocol (SMTP)
   56.33 +   provides a standard way for an email client to submit a complete
   56.34 +   message for delivery.  This specification extends the submission
   56.35 +   profile by adding a new BURL command that can be used to fetch
   56.36 +   submission data from an Internet Message Access Protocol (IMAP)
   56.37 +   server.  This permits a mail client to inject content from an IMAP
   56.38 +   server into the SMTP infrastructure without downloading it to the
   56.39 +   client and uploading it back to the server.
   56.40 +
   56.41 +
   56.42 +
   56.43 +
   56.44 +
   56.45 +
   56.46 +
   56.47 +
   56.48 +
   56.49 +
   56.50 +
   56.51 +
   56.52 +
   56.53 +
   56.54 +
   56.55 +
   56.56 +
   56.57 +
   56.58 +
   56.59 +
   56.60 +
   56.61 +Newman                      Standards Track                     [Page 1]
   56.62 +
   56.63 +RFC 4468           Message Submission BURL Extension            May 2006
   56.64 +
   56.65 +
   56.66 +Table of Contents
   56.67 +
   56.68 +   1. Introduction ....................................................2
   56.69 +   2. Conventions Used in This Document ...............................2
   56.70 +   3. BURL Submission Extension .......................................3
   56.71 +      3.1. SMTP Submission Extension Registration .....................3
   56.72 +      3.2. BURL Transaction ...........................................3
   56.73 +      3.3. The BURL IMAP Options ......................................4
   56.74 +      3.4. Examples ...................................................5
   56.75 +      3.5. Formal Syntax ..............................................6
   56.76 +   4. 8-Bit and Binary ................................................7
   56.77 +   5. Updates to RFC 3463 .............................................7
   56.78 +   6. Response Codes ..................................................7
   56.79 +   7. IANA Considerations .............................................9
   56.80 +   8. Security Considerations .........................................9
   56.81 +   9. References .....................................................11
   56.82 +      9.1. Normative References ......................................11
   56.83 +      9.2. Informative References ....................................12
   56.84 +   Appendix A.  Acknowledgements .....................................13
   56.85 +
   56.86 +1.  Introduction
   56.87 +
   56.88 +   This specification defines an extension to the standard Message
   56.89 +   Submission [RFC4409] protocol to permit data to be fetched from an
   56.90 +   IMAP server at message submission time.  This MAY be used in
   56.91 +   conjunction with the CHUNKING [RFC3030] mechanism so that chunks of
   56.92 +   the message can come from an external IMAP server.  This provides the
   56.93 +   ability to forward an email message without first downloading it to
   56.94 +   the client.
   56.95 +
   56.96 +2.  Conventions Used in This Document
   56.97 +
   56.98 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
   56.99 +   in this document are to be interpreted as defined in "Key words for
  56.100 +   use in RFCs to Indicate Requirement Levels" [RFC2119].
  56.101 +
  56.102 +   The formal syntax uses the Augmented Backus-Naur Form (ABNF)
  56.103 +   [RFC4234] notation including the core rules defined in Appendix B of
  56.104 +   RFC 4234.
  56.105 +
  56.106 +
  56.107 +
  56.108 +
  56.109 +
  56.110 +
  56.111 +
  56.112 +
  56.113 +
  56.114 +
  56.115 +
  56.116 +
  56.117 +Newman                      Standards Track                     [Page 2]
  56.118 +
  56.119 +RFC 4468           Message Submission BURL Extension            May 2006
  56.120 +
  56.121 +
  56.122 +3.  BURL Submission Extension
  56.123 +
  56.124 +   This section defines the BURL submission extension.
  56.125 +
  56.126 +3.1.  SMTP Submission Extension Registration
  56.127 +
  56.128 +   1.  The name of this submission extension is "BURL".  This extends
  56.129 +       the Message Submission protocol on port 587 and MUST NOT be
  56.130 +       advertised by a regular SMTP [RFC2821] server on port 25 that
  56.131 +       acts as a relay for incoming mail from other SMTP relays.
  56.132 +
  56.133 +   2.  The EHLO keyword value associated with the extension is "BURL".
  56.134 +
  56.135 +   3.  The BURL EHLO keyword will have zero or more arguments.  The only
  56.136 +       argument defined at this time is the "imap" argument, which MUST
  56.137 +       be present in order to use IMAP URLs with BURL.  Clients MUST
  56.138 +       ignore other arguments after the BURL EHLO keyword unless they
  56.139 +       are defined by a subsequent IETF standards track specification.
  56.140 +       The arguments that appear after the BURL EHLO keyword may change
  56.141 +       subsequent to the use of SMTP AUTH [RFC2554], so a server that
  56.142 +       advertises BURL with no arguments prior to authentication
  56.143 +       indicates that BURL is supported but authentication is required
  56.144 +       to use it.
  56.145 +
  56.146 +   4.  This extension adds the BURL SMTP verb.  This verb is used as a
  56.147 +       replacement for the DATA command and is only permitted during a
  56.148 +       mail transaction after at least one successful RCPT TO.
  56.149 +
  56.150 +3.2.  BURL Transaction
  56.151 +
  56.152 +   A simple BURL transaction will consist of MAIL FROM, one or more RCPT
  56.153 +   TO headers, and a BURL command with the "LAST" tag.  The BURL command
  56.154 +   will include an IMAP URL pointing to a fully formed message ready for
  56.155 +   injection into the SMTP infrastructure.  If PIPELINING [RFC2920] is
  56.156 +   advertised, the client MAY send the entire transaction in one round
  56.157 +   trip.  If no valid RCPT TO address is supplied, the BURL command will
  56.158 +   simply fail, and no resolution of the BURL URL argument will be
  56.159 +   performed.  If at least one valid RCPT TO address is supplied, then
  56.160 +   the BURL URL argument will be resolved before the server responds to
  56.161 +   the command.
  56.162 +
  56.163 +   A more sophisticated BURL transaction MAY occur when the server also
  56.164 +   advertises CHUNKING [RFC3030].  In this case, the BURL and BDAT
  56.165 +   commands may be interleaved until one of them terminates the
  56.166 +   transaction with the "LAST" argument.  If PIPELINING [RFC2920] is
  56.167 +   also advertised, then the client may pipeline the entire transaction
  56.168 +   in one round-trip.  However, it MUST wait for the results of the
  56.169 +   "LAST" BDAT or BURL command prior to initiating a new transaction.
  56.170 +
  56.171 +
  56.172 +
  56.173 +Newman                      Standards Track                     [Page 3]
  56.174 +
  56.175 +RFC 4468           Message Submission BURL Extension            May 2006
  56.176 +
  56.177 +
  56.178 +   The BURL command directs the server to fetch the data object to which
  56.179 +   the URL refers and include it in the message.  If the URL fetch
  56.180 +   fails, the server will fail the entire transaction.
  56.181 +
  56.182 +3.3.  The BURL IMAP Options
  56.183 +
  56.184 +   When "imap" is present in the space-separated list of arguments
  56.185 +   following the BURL EHLO keyword, it indicates that the BURL command
  56.186 +   supports the URLAUTH [RFC4467] extended form of IMAP URLs [RFC2192]
  56.187 +   and that the submit server is configured with the necessary
  56.188 +   credentials to resolve "urlauth=submit+" IMAP URLs for the submit
  56.189 +   server's domain.
  56.190 +
  56.191 +   Subsequent to a successful SMTP AUTH command, the submission server
  56.192 +   MAY indicate a prearranged trust relationship with a specific IMAP
  56.193 +   server by including a BURL EHLO keyword argument of the form
  56.194 +   "imap://imap.example.com".  In this case, the submission server will
  56.195 +   permit a regular IMAP URL referring to messages or parts of messages
  56.196 +   on imap.example.com that the user who authenticated to the submit
  56.197 +   server can access.  Note that this form does not imply that the
  56.198 +   submit server supports URLAUTH URLs; the submit server must advertise
  56.199 +   both "imap" and "imap://imap.example.com" to indicate support for
  56.200 +   both extended and non-extended URL forms.
  56.201 +
  56.202 +   When the submit server connects to the IMAP server, it acts as an
  56.203 +   IMAP client and thus is subject to both the mandatory-to-implement
  56.204 +   IMAP capabilities in Section 6.1.1 of RFC 3501, and the security
  56.205 +   considerations in Section 11 of RFC 3501.  Specifically, this
  56.206 +   requires that the submit server implement a configuration that uses
  56.207 +   STARTTLS followed by SASL PLAIN [SASL-PLAIN] to authenticate to the
  56.208 +   IMAP server.
  56.209 +
  56.210 +   When the submit server resolves a URLAUTH IMAP URL, it uses submit
  56.211 +   server credentials when authenticating to the IMAP server.  The
  56.212 +   authentication identity and password used for submit credentials MUST
  56.213 +   be configurable.  The string "submit" is suggested as a default value
  56.214 +   for the authentication identity, with no default for the password.
  56.215 +   Typically, the authorization identity is empty in this case; thus the
  56.216 +   IMAP server will derive the authorization identity from the
  56.217 +   authentication identity.  If the IMAP URL uses the "submit+" access
  56.218 +   identifier prefix, the submit server MUST refuse the BURL command
  56.219 +   unless the userid in the URL's <access> token matches the submit
  56.220 +   client's authorization identity.
  56.221 +
  56.222 +   When the submit server resolves a regular IMAP URL, it uses the
  56.223 +   submit client's authorization identity when authenticating to the
  56.224 +   IMAP server.  If both the submit client and the submit server's
  56.225 +   embedded IMAP client use SASL PLAIN (or the equivalent), the submit
  56.226 +
  56.227 +
  56.228 +
  56.229 +Newman                      Standards Track                     [Page 4]
  56.230 +
  56.231 +RFC 4468           Message Submission BURL Extension            May 2006
  56.232 +
  56.233 +
  56.234 +   server SHOULD forward the client's credentials if and only if the
  56.235 +   submit server knows that the IMAP server is in the same
  56.236 +   administrative domain.  If the submit server supports SASL mechanisms
  56.237 +   other than PLAIN, it MUST implement a configuration in which the
  56.238 +   submit server's embedded IMAP client uses STARTTLS and SASL PLAIN
  56.239 +   with the submit server's authentication identity and password (for
  56.240 +   the respective IMAP server) and the submit client's authorization
  56.241 +   identity.
  56.242 +
  56.243 +3.4.  Examples
  56.244 +
  56.245 +   In examples, "C:" and "S:" indicate lines sent by the client and
  56.246 +   server, respectively.  If a single "C:" or "S:" label applies to
  56.247 +   multiple lines, then the line breaks between those lines are for
  56.248 +   editorial clarity only and are not part of the actual protocol
  56.249 +   exchange.
  56.250 +
  56.251 +   Two successful submissions (without and with pipelining) follow:
  56.252 +
  56.253 +   <SSL/TLS encryption layer negotiated>
  56.254 +   C: EHLO potter.example.com
  56.255 +   S: 250-owlry.example.com
  56.256 +   S: 250-8BITMIME
  56.257 +   S: 250-BURL imap
  56.258 +   S: 250-AUTH PLAIN
  56.259 +   S: 250-DSN
  56.260 +   S: 250 ENHANCEDSTATUSCODES
  56.261 +   C: AUTH PLAIN aGFycnkAaGFycnkAYWNjaW8=
  56.262 +   S: 235 2.7.0 PLAIN authentication successful.
  56.263 +   C: MAIL FROM:<harry@gryffindor.example.com>
  56.264 +   S: 250 2.5.0 Address Ok.
  56.265 +   C: RCPT TO:<ron@gryffindor.example.com>
  56.266 +   S: 250 2.1.5 ron@gryffindor.example.com OK.
  56.267 +   C: BURL imap://harry@gryffindor.example.com/outbox
  56.268 +           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
  56.269 +           :internal:91354a473744909de610943775f92038 LAST
  56.270 +   S: 250 2.5.0 Ok.
  56.271 +
  56.272 +   <SSL/TLS encryption layer negotiated>
  56.273 +   C: EHLO potter.example.com
  56.274 +   S: 250-owlry.example.com
  56.275 +   S: 250-8BITMIME
  56.276 +   S: 250-PIPELINING
  56.277 +   S: 250-BURL imap
  56.278 +   S: 250-AUTH PLAIN
  56.279 +   S: 250-DSN
  56.280 +   S: 250 ENHANCEDSTATUSCODES
  56.281 +   C: AUTH PLAIN aGFycnkAaGFycnkAYWNjaW8=
  56.282 +
  56.283 +
  56.284 +
  56.285 +Newman                      Standards Track                     [Page 5]
  56.286 +
  56.287 +RFC 4468           Message Submission BURL Extension            May 2006
  56.288 +
  56.289 +
  56.290 +   C: MAIL FROM:<harry@gryffindor.example.com>
  56.291 +   C: RCPT TO:<ron@gryffindor.example.com>
  56.292 +   C: BURL imap://harry@gryffindor.example.com/outbox
  56.293 +           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
  56.294 +           :internal:91354a473744909de610943775f92038 LAST
  56.295 +   S: 235 2.7.0 PLAIN authentication successful.
  56.296 +   S: 250 2.5.0 Address Ok.
  56.297 +   S: 250 2.1.5 ron@gryffindor.example.com OK.
  56.298 +   S: 250 2.5.0 Ok.
  56.299 +
  56.300 +   Note that PIPELINING of the AUTH command is only permitted if the
  56.301 +   selected mechanism can be completed in one round trip, a client
  56.302 +   initial response is provided, and no SASL security layer is
  56.303 +   negotiated.  This is possible for PLAIN and EXTERNAL, but not for
  56.304 +   most other SASL mechanisms.
  56.305 +
  56.306 +   Some examples of failure cases:
  56.307 +
  56.308 +   C: MAIL FROM:<harry@gryffindor.example.com>
  56.309 +   C: RCPT TO:<malfoy@slitherin.example.com>
  56.310 +   C: BURL imap://harry@gryffindor.example.com/outbox
  56.311 +           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
  56.312 +           :internal:91354a473744909de610943775f92038 LAST
  56.313 +   S: 250 2.5.0 Address Ok.
  56.314 +   S: 550 5.7.1 Relaying not allowed: malfoy@slitherin.example.com
  56.315 +   S: 554 5.5.0 No recipients have been specified.
  56.316 +
  56.317 +   C: MAIL FROM:<harry@gryffindor.example.com>
  56.318 +   C: RCPT TO:<ron@gryffindor.example.com>
  56.319 +   C: BURL imap://harry@gryffindor.example.com/outbox
  56.320 +           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
  56.321 +           :internal:71354a473744909de610943775f92038 LAST
  56.322 +   S: 250 2.5.0 Address Ok.
  56.323 +   S: 250 2.1.5 ron@gryffindor.example.com OK.
  56.324 +   S: 554 5.7.0 IMAP URL authorization failed
  56.325 +
  56.326 +3.5.  Formal Syntax
  56.327 +
  56.328 +   The following syntax specification inherits ABNF [RFC4234] and
  56.329 +   Uniform Resource Identifiers [RFC3986].
  56.330 +
  56.331 +      burl-param  = "imap" / ("imap://" authority)
  56.332 +                  ; parameter to BURL EHLO keyword
  56.333 +
  56.334 +      burl-cmd    = "BURL" SP absolute-URI [SP end-marker] CRLF
  56.335 +
  56.336 +      end-marker  = "LAST"
  56.337 +
  56.338 +
  56.339 +
  56.340 +
  56.341 +Newman                      Standards Track                     [Page 6]
  56.342 +
  56.343 +RFC 4468           Message Submission BURL Extension            May 2006
  56.344 +
  56.345 +
  56.346 +4.  8-Bit and Binary
  56.347 +
  56.348 +   A submit server that advertises BURL MUST also advertise 8BITMIME
  56.349 +   [RFC1652] and perform the down conversion described in that
  56.350 +   specification on the resulting complete message if 8-bit data is
  56.351 +   received with the BURL command and passed to a 7-bit server.  If the
  56.352 +   URL argument to BURL refers to binary data, then the submit server
  56.353 +   MAY refuse the command or down convert as described in Binary SMTP
  56.354 +   [RFC3030].
  56.355 +
  56.356 +   The Submit server MAY refuse to accept a BURL command or combination
  56.357 +   of BURL and BDAT commands that result in un-encoded 8-bit data in
  56.358 +   mail or MIME [RFC2045] headers.  Alternatively, the server MAY accept
  56.359 +   such data and down convert to MIME header encoding [RFC2047].
  56.360 +
  56.361 +5.  Updates to RFC 3463
  56.362 +
  56.363 +   SMTP or Submit servers that advertise ENHANCEDSTATUSCODES [RFC2034]
  56.364 +   use enhanced status codes defined in RFC 3463 [RFC3463].  The BURL
  56.365 +   extension introduces new error cases that that RFC did not consider.
  56.366 +   The following additional enhanced status codes are defined by this
  56.367 +   specification:
  56.368 +
  56.369 +   X.6.6 Message content not available
  56.370 +
  56.371 +      The message content could not be fetched from a remote system.
  56.372 +      This may be useful as a permanent or persistent temporary
  56.373 +      notification.
  56.374 +
  56.375 +   X.7.8 Trust relationship required
  56.376 +
  56.377 +      The submission server requires a configured trust relationship
  56.378 +      with a third-party server in order to access the message content.
  56.379 +
  56.380 +6.  Response Codes
  56.381 +
  56.382 +   This section includes example response codes to the BURL command.
  56.383 +   Other text may be used with the same response codes.  This list is
  56.384 +   not exhaustive, and BURL clients MUST tolerate any valid SMTP
  56.385 +   response code.  Most of these examples include the appropriate
  56.386 +   enhanced status code [RFC3463].
  56.387 +
  56.388 +   554 5.5.0 No recipients have been specified
  56.389 +
  56.390 +      This response code occurs when BURL is used (for example, with
  56.391 +      PIPELINING) and all RCPT TOs failed.
  56.392 +
  56.393 +
  56.394 +
  56.395 +
  56.396 +
  56.397 +Newman                      Standards Track                     [Page 7]
  56.398 +
  56.399 +RFC 4468           Message Submission BURL Extension            May 2006
  56.400 +
  56.401 +
  56.402 +   503 5.5.0 Valid RCPT TO required before BURL
  56.403 +
  56.404 +      This response code is an alternative to the previous one when BURL
  56.405 +      is used (for example, with PIPELINING) and all RCPT TOs failed.
  56.406 +
  56.407 +   554 5.6.3 Conversion required but not supported
  56.408 +
  56.409 +      This response code occurs when the URL points to binary data and
  56.410 +      the implementation does not support down conversion to base64.
  56.411 +      This can also be used if the URL points to message data with 8-bit
  56.412 +      content in headers and the server does not down convert such
  56.413 +      content.
  56.414 +
  56.415 +   554 5.3.4 Message too big for system
  56.416 +
  56.417 +      The message (subsequent to URL resolution) is larger than the
  56.418 +      per-message size limit for this server.
  56.419 +
  56.420 +   554 5.7.8 URL resolution requires trust relationship
  56.421 +
  56.422 +      The submit server does not have a trust relationship with the IMAP
  56.423 +      server specified in the URL argument to BURL.
  56.424 +
  56.425 +   552 5.2.2 Mailbox full
  56.426 +
  56.427 +      The recipient is local, the submit server supports direct
  56.428 +      delivery, and the recipient has exceeded his quota and any grace
  56.429 +      period for delivery attempts.
  56.430 +
  56.431 +   554 5.6.6 IMAP URL resolution failed
  56.432 +
  56.433 +      The IMAP URLFETCH command returned an error or no data.
  56.434 +
  56.435 +   250 2.5.0 Waiting for additional BURL or BDAT commands
  56.436 +
  56.437 +      A BURL command without the "LAST" modifier was sent.  The URL for
  56.438 +      this BURL command was successfully resolved, but the content will
  56.439 +      not necessarily be committed to persistent storage until the rest
  56.440 +      of the message content is collected.  For example, a Unix server
  56.441 +      may have written the content to a queue file buffer, but may not
  56.442 +      yet have performed an fsync() operation.  If the server loses
  56.443 +      power, the content can still be lost.
  56.444 +
  56.445 +   451 4.4.1 IMAP server unavailable
  56.446 +
  56.447 +      The connection to the IMAP server to resolve the URL failed.
  56.448 +
  56.449 +
  56.450 +
  56.451 +
  56.452 +
  56.453 +Newman                      Standards Track                     [Page 8]
  56.454 +
  56.455 +RFC 4468           Message Submission BURL Extension            May 2006
  56.456 +
  56.457 +
  56.458 +   250 2.5.0 Ok.
  56.459 +
  56.460 +      The URL was successfully resolved, and the complete message data
  56.461 +      has been committed to persistent storage.
  56.462 +
  56.463 +   250 2.6.4 MIME header conversion with loss performed
  56.464 +
  56.465 +      The URL pointed to message data that included mail or MIME headers
  56.466 +      with 8-bit data.  This data was converted to MIME header encoding
  56.467 +      [RFC2047], but the submit server may not have correctly guessed
  56.468 +      the unlabeled character set.
  56.469 +
  56.470 +7.  IANA Considerations
  56.471 +
  56.472 +   The "BURL" SMTP extension as described in Section 3 has been
  56.473 +   registered.  This registration has been marked for use by message
  56.474 +   submission [RFC4409] only in the registry.
  56.475 +
  56.476 +8.  Security Considerations
  56.477 +
  56.478 +   Modern SMTP submission servers often include content-based security
  56.479 +   and denial-of-service defense mechanisms such as virus filtering,
  56.480 +   size limits, server-generated signatures, spam filtering, etc.
  56.481 +   Implementations of BURL should fetch the URL content prior to
  56.482 +   application of such content-based mechanisms in order to preserve
  56.483 +   their function.
  56.484 +
  56.485 +   Clients that generate unsolicited bulk email or email with viruses
  56.486 +   could use this mechanism to compensate for a slow link between the
  56.487 +   client and submit server.  In particular, this mechanism would make
  56.488 +   it feasible for a programmable cell phone or other device on a slow
  56.489 +   link to become a significant source of unsolicited bulk email and/or
  56.490 +   viruses.  This makes it more important for submit server vendors
  56.491 +   implementing BURL to have auditing and/or defenses against such
  56.492 +   denial-of-service attacks including mandatory authentication, logging
  56.493 +   that associates unique client identifiers with mail transactions,
  56.494 +   limits on reuse of the same IMAP URL, rate limits, recipient count
  56.495 +   limits, and content filters.
  56.496 +
  56.497 +   Transfer of the URLAUTH [RFC4467] form of IMAP URLs in the clear can
  56.498 +   expose the authorization token to network eavesdroppers.
  56.499 +   Implementations that support such URLs can address this issue by
  56.500 +   using a strong confidentiality protection mechanism.  For example,
  56.501 +   the SMTP STARTTLS [RFC3207] and the IMAP STARTTLS [RFC3501]
  56.502 +   extensions, in combination with a configuration setting that requires
  56.503 +   their use with such IMAP URLs, would address this concern.
  56.504 +
  56.505 +
  56.506 +
  56.507 +
  56.508 +
  56.509 +Newman                      Standards Track                     [Page 9]
  56.510 +
  56.511 +RFC 4468           Message Submission BURL Extension            May 2006
  56.512 +
  56.513 +
  56.514 +   Use of a prearranged trust relationship between a submit server and a
  56.515 +   specific IMAP server introduces security considerations.  A
  56.516 +   compromise of the submit server should not automatically compromise
  56.517 +   all accounts on the IMAP server, so trust relationships involving
  56.518 +   super-user proxy credentials are strongly discouraged.  A system that
  56.519 +   requires the submit server to authenticate to the IMAP server with
  56.520 +   submit credentials and subsequently requires a URLAUTH URL to fetch
  56.521 +   any content addresses this concern.  A trusted third party model for
  56.522 +   proxy credentials (such as that provided by Kerberos 5 [RFC4120])
  56.523 +   would also suffice.
  56.524 +
  56.525 +   When a client uses SMTP STARTTLS to send a BURL command that
  56.526 +   references non-public information, there is a user expectation that
  56.527 +   the entire message content will be treated confidentially.  To
  56.528 +   address this expectation, the message submission server SHOULD use
  56.529 +   STARTTLS or a mechanism providing equivalent data confidentiality
  56.530 +   when fetching the content referenced by that URL.
  56.531 +
  56.532 +   A legitimate user of a submit server may try to compromise other
  56.533 +   accounts on the server by providing an IMAP URLAUTH URL that points
  56.534 +   to a server under that user's control that is designed to undermine
  56.535 +   the security of the submit server.  For this reason, the IMAP client
  56.536 +   code that the submit server uses must be robust with respect to
  56.537 +   arbitrary input sizes (including large IMAP literals) and arbitrary
  56.538 +   delays from the IMAP server.  Requiring a prearranged trust
  56.539 +   relationship between a submit server and the IMAP server also
  56.540 +   addresses this concern.
  56.541 +
  56.542 +   An authorized user of the submit server could set up a fraudulent
  56.543 +   IMAP server and pass a URL for that server to the submit server.  The
  56.544 +   submit server might then contact the fraudulent IMAP server to
  56.545 +   authenticate with submit credentials and fetch content.  There are
  56.546 +   several ways to mitigate this potential attack.  A submit server that
  56.547 +   only uses submit credentials with a fixed set of trusted IMAP servers
  56.548 +   will not be vulnerable to exposure of those credentials.  A submit
  56.549 +   server can treat the IMAP server as untrusted and include defenses
  56.550 +   for buffer overflows, denial-of-service slowdowns, and other
  56.551 +   potential attacks.  Finally, because authentication is required to
  56.552 +   use BURL, it is possible to keep a secure audit trail and use that to
  56.553 +   detect and punish the offending party.
  56.554 +
  56.555 +
  56.556 +
  56.557 +
  56.558 +
  56.559 +
  56.560 +
  56.561 +
  56.562 +
  56.563 +
  56.564 +
  56.565 +Newman                      Standards Track                    [Page 10]
  56.566 +
  56.567 +RFC 4468           Message Submission BURL Extension            May 2006
  56.568 +
  56.569 +
  56.570 +9.  References
  56.571 +
  56.572 +9.1.  Normative References
  56.573 +
  56.574 +   [RFC1652]     Klensin, J., Freed, N., Rose, M., Stefferud, E., and D.
  56.575 +                 Crocker, "SMTP Service Extension for
  56.576 +                 8bit-MIMEtransport", RFC 1652, July 1994.
  56.577 +
  56.578 +   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
  56.579 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
  56.580 +
  56.581 +   [RFC2192]     Newman, C., "IMAP URL Scheme", RFC 2192,
  56.582 +                 September 1997.
  56.583 +
  56.584 +   [RFC2554]     Myers, J., "SMTP Service Extension for Authentication",
  56.585 +                 RFC 2554, March 1999.
  56.586 +
  56.587 +   [RFC2821]     Klensin, J., "Simple Mail Transfer Protocol", RFC 2821,
  56.588 +                 April 2001.
  56.589 +
  56.590 +   [RFC3207]     Hoffman, P., "SMTP Service Extension for Secure SMTP
  56.591 +                 over Transport Layer Security", RFC 3207,
  56.592 +                 February 2002.
  56.593 +
  56.594 +   [RFC3501]     Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
  56.595 +                 VERSION 4rev1", RFC 3501, March 2003.
  56.596 +
  56.597 +   [RFC3986]     Berners-Lee, T., Fielding, R., and L. Masinter,
  56.598 +                 "Uniform Resource Identifier (URI): Generic Syntax",
  56.599 +                 STD 66, RFC 3986, January 2005.
  56.600 +
  56.601 +   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
  56.602 +                 Specifications: ABNF", RFC 4234, October 2005.
  56.603 +
  56.604 +   [RFC4409]     Gellens, R. and J. Klensin, "Message Submission for
  56.605 +                 Mail", RFC 4409, April 2006.
  56.606 +
  56.607 +   [RFC4467]     Crispin, M., "Internet Message Access Protocol (IMAP) -
  56.608 +                 URLAUTH Extension", RFC 4467, May 2006.
  56.609 +
  56.610 +
  56.611 +
  56.612 +
  56.613 +
  56.614 +
  56.615 +
  56.616 +
  56.617 +
  56.618 +
  56.619 +
  56.620 +
  56.621 +Newman                      Standards Track                    [Page 11]
  56.622 +
  56.623 +RFC 4468           Message Submission BURL Extension            May 2006
  56.624 +
  56.625 +
  56.626 +9.2.  Informative References
  56.627 +
  56.628 +   [RFC2034]     Freed, N., "SMTP Service Extension for Returning
  56.629 +                 Enhanced Error Codes", RFC 2034, October 1996.
  56.630 +
  56.631 +   [RFC2045]     Freed, N. and N. Borenstein, "Multipurpose Internet
  56.632 +                 Mail Extensions (MIME) Part One: Format of Internet
  56.633 +                 Message Bodies", RFC 2045, November 1996.
  56.634 +
  56.635 +   [RFC2047]     Moore, K., "MIME (Multipurpose Internet Mail
  56.636 +                 Extensions) Part Three: Message Header Extensions for
  56.637 +                 Non-ASCII Text", RFC 2047, November 1996.
  56.638 +
  56.639 +   [RFC2920]     Freed, N., "SMTP Service Extension for Command
  56.640 +                 Pipelining", STD 60, RFC 2920, September 2000.
  56.641 +
  56.642 +   [RFC3030]     Vaudreuil, G., "SMTP Service Extensions for
  56.643 +                 Transmission of Large and Binary MIME Messages",
  56.644 +                 RFC 3030, December 2000.
  56.645 +
  56.646 +   [RFC3463]     Vaudreuil, G., "Enhanced Mail System Status Codes",
  56.647 +                 RFC 3463, January 2003.
  56.648 +
  56.649 +   [RFC4120]     Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The
  56.650 +                 Kerberos Network Authentication Service (V5)", RFC
  56.651 +                 4120, July 2005.
  56.652 +
  56.653 +   [SASL-PLAIN]  Zeilenga, K., "The Plain SASL Mechanism", Work in
  56.654 +                 Progress, March 2005.
  56.655 +
  56.656 +
  56.657 +
  56.658 +
  56.659 +
  56.660 +
  56.661 +
  56.662 +
  56.663 +
  56.664 +
  56.665 +
  56.666 +
  56.667 +
  56.668 +
  56.669 +
  56.670 +
  56.671 +
  56.672 +
  56.673 +
  56.674 +
  56.675 +
  56.676 +
  56.677 +Newman                      Standards Track                    [Page 12]
  56.678 +
  56.679 +RFC 4468           Message Submission BURL Extension            May 2006
  56.680 +
  56.681 +
  56.682 +Appendix A.  Acknowledgements
  56.683 +
  56.684 +   This document is a product of the lemonade WG.  Many thanks are due
  56.685 +   to all the participants of that working group for their input.  Mark
  56.686 +   Crispin was instrumental in the conception of this mechanism.  Thanks
  56.687 +   to Randall Gellens, Alexey Melnikov, Sam Hartman, Ned Freed, Dave
  56.688 +   Cridland, Peter Coates, and Mark Crispin for review comments on the
  56.689 +   document.  Thanks to the RFC Editor for correcting the author's
  56.690 +   grammar mistakes.  Thanks to Ted Hardie, Randall Gellens, Mark
  56.691 +   Crispin, Pete Resnick, and Greg Vaudreuil for extremely interesting
  56.692 +   debates comparing this proposal and alternatives.  Thanks to the
  56.693 +   lemonade WG chairs Eric Burger and Glenn Parsons for concluding the
  56.694 +   debate at the correct time and making sure this document got
  56.695 +   completed.
  56.696 +
  56.697 +Author's Address
  56.698 +
  56.699 +   Chris Newman
  56.700 +   Sun Microsystems
  56.701 +   3401 Centrelake Dr., Suite 410
  56.702 +   Ontario, CA  91761
  56.703 +   US
  56.704 +
  56.705 +   EMail: chris.newman@sun.com
  56.706 +
  56.707 +
  56.708 +
  56.709 +
  56.710 +
  56.711 +
  56.712 +
  56.713 +
  56.714 +
  56.715 +
  56.716 +
  56.717 +
  56.718 +
  56.719 +
  56.720 +
  56.721 +
  56.722 +
  56.723 +
  56.724 +
  56.725 +
  56.726 +
  56.727 +
  56.728 +
  56.729 +
  56.730 +
  56.731 +
  56.732 +
  56.733 +Newman                      Standards Track                    [Page 13]
  56.734 +
  56.735 +RFC 4468           Message Submission BURL Extension            May 2006
  56.736 +
  56.737 +
  56.738 +Full Copyright Statement
  56.739 +
  56.740 +   Copyright (C) The Internet Society (2006).
  56.741 +
  56.742 +   This document is subject to the rights, licenses and restrictions
  56.743 +   contained in BCP 78, and except as set forth therein, the authors
  56.744 +   retain all their rights.
  56.745 +
  56.746 +   This document and the information contained herein are provided on an
  56.747 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  56.748 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  56.749 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  56.750 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  56.751 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  56.752 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  56.753 +
  56.754 +Intellectual Property
  56.755 +
  56.756 +   The IETF takes no position regarding the validity or scope of any
  56.757 +   Intellectual Property Rights or other rights that might be claimed to
  56.758 +   pertain to the implementation or use of the technology described in
  56.759 +   this document or the extent to which any license under such rights
  56.760 +   might or might not be available; nor does it represent that it has
  56.761 +   made any independent effort to identify any such rights.  Information
  56.762 +   on the procedures with respect to rights in RFC documents can be
  56.763 +   found in BCP 78 and BCP 79.
  56.764 +
  56.765 +   Copies of IPR disclosures made to the IETF Secretariat and any
  56.766 +   assurances of licenses to be made available, or the result of an
  56.767 +   attempt made to obtain a general license or permission for the use of
  56.768 +   such proprietary rights by implementers or users of this
  56.769 +   specification can be obtained from the IETF on-line IPR repository at
  56.770 +   http://www.ietf.org/ipr.
  56.771 +
  56.772 +   The IETF invites any interested party to bring to its attention any
  56.773 +   copyrights, patents or patent applications, or other proprietary
  56.774 +   rights that may cover technology that may be required to implement
  56.775 +   this standard.  Please address the information to the IETF at
  56.776 +   ietf-ipr@ietf.org.
  56.777 +
  56.778 +Acknowledgement
  56.779 +
  56.780 +   Funding for the RFC Editor function is provided by the IETF
  56.781 +   Administrative Support Activity (IASA).
  56.782 +
  56.783 +
  56.784 +
  56.785 +
  56.786 +
  56.787 +
  56.788 +
  56.789 +Newman                      Standards Track                    [Page 14]
  56.790 +
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/docs/rfc/rfc4469.txt	Mon Sep 14 15:17:45 2009 +0900
    57.3 @@ -0,0 +1,731 @@
    57.4 +
    57.5 +
    57.6 +
    57.7 +
    57.8 +
    57.9 +
   57.10 +Network Working Group                                         P. Resnick
   57.11 +Request for Comments: 4469                         QUALCOMM Incorporated
   57.12 +Updates: 3501, 3502                                           April 2006
   57.13 +Category: Standards Track
   57.14 +
   57.15 +
   57.16 +       Internet Message Access Protocol (IMAP) CATENATE Extension
   57.17 +
   57.18 +Status of This Memo
   57.19 +
   57.20 +   This document specifies an Internet standards track protocol for the
   57.21 +   Internet community, and requests discussion and suggestions for
   57.22 +   improvements.  Please refer to the current edition of the "Internet
   57.23 +   Official Protocol Standards" (STD 1) for the standardization state
   57.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   57.25 +
   57.26 +Copyright Notice
   57.27 +
   57.28 +   Copyright (C) The Internet Society (2006).
   57.29 +
   57.30 +Abstract
   57.31 +
   57.32 +   The CATENATE extension to the Internet Message Access Protocol (IMAP)
   57.33 +   extends the APPEND command to allow clients to create messages on the
   57.34 +   IMAP server that may contain a combination of new data along with
   57.35 +   parts of (or entire) messages already on the server.  Using this
   57.36 +   extension, the client can catenate parts of an already existing
   57.37 +   message onto a new message without having to first download the data
   57.38 +   and then upload it back to the server.
   57.39 +
   57.40 +
   57.41 +
   57.42 +
   57.43 +
   57.44 +
   57.45 +
   57.46 +
   57.47 +
   57.48 +
   57.49 +
   57.50 +
   57.51 +
   57.52 +
   57.53 +
   57.54 +
   57.55 +
   57.56 +
   57.57 +
   57.58 +
   57.59 +
   57.60 +
   57.61 +Resnick                     Standards Track                     [Page 1]
   57.62 +
   57.63 +RFC 4469                IMAP CATENATE Extension               April 2006
   57.64 +
   57.65 +
   57.66 +1.  Introduction
   57.67 +
   57.68 +   The CATENATE extension to the Internet Message Access Protocol (IMAP)
   57.69 +   [1] allows the client to create a message on the server that can
   57.70 +   include the text of messages (or parts of messages) that already
   57.71 +   exist on the server without having to FETCH them and APPEND them back
   57.72 +   to the server.  The CATENATE extension extends the APPEND command so
   57.73 +   that, instead of a single message literal, the command can take as
   57.74 +   arguments any combination of message literals (as described in IMAP
   57.75 +   [1]) and message URLs (as described in the IMAP URL Scheme [2]
   57.76 +   specification).  The server takes all the pieces and catenates them
   57.77 +   into the output message.  The CATENATE extension can also coexist
   57.78 +   with the MULTIAPPEND extension [3] to APPEND multiple messages in a
   57.79 +   single command.
   57.80 +
   57.81 +   There are some obvious uses for the CATENATE extension.  The
   57.82 +   motivating use case was to provide a way for a resource-constrained
   57.83 +   client to compose a message for subsequent submission that contains
   57.84 +   data that already exists in that client's IMAP store.  Because the
   57.85 +   client does not have to download and re-upload potentially large
   57.86 +   message parts, bandwidth and processing limitations do not have as
   57.87 +   much impact.  In addition, since the client can create a message in
   57.88 +   its own IMAP store, the command also addresses the desire of the
   57.89 +   client to archive a copy of a sent message without having to upload
   57.90 +   the message twice.  (Mechanisms for sending the message are outside
   57.91 +   the scope of this document.)
   57.92 +
   57.93 +   The extended APPEND command can also be used to copy parts of a
   57.94 +   message to another mailbox for archival purposes while getting rid of
   57.95 +   undesired parts.  In environments where server storage is limited, a
   57.96 +   client could get rid of large message parts by copying over only the
   57.97 +   necessary parts and then deleting the original message.  The
   57.98 +   mechanism could also be used to add data to a message (such as
   57.99 +   prepending message header fields) or to include other data by making
  57.100 +   a copy of the original and catenating the new data.
  57.101 +
  57.102 +2.  The CATENATE Capability
  57.103 +
  57.104 +   A server that supports this extension returns "CATENATE" as one of
  57.105 +   the responses to the CAPABILITY command.
  57.106 +
  57.107 +
  57.108 +
  57.109 +
  57.110 +
  57.111 +
  57.112 +
  57.113 +
  57.114 +
  57.115 +
  57.116 +
  57.117 +Resnick                     Standards Track                     [Page 2]
  57.118 +
  57.119 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.120 +
  57.121 +
  57.122 +3.  The APPEND Command
  57.123 +
  57.124 +   Arguments:  mailbox name
  57.125 +               (The following can be repeated in the presence of the
  57.126 +               MULTIAPPEND extension [3])
  57.127 +               OPTIONAL flag parenthesized list
  57.128 +               OPTIONAL date/time string
  57.129 +               a single message literal or one or more message parts to
  57.130 +               catenate, specified as:
  57.131 +                           message literal
  57.132 +                           or
  57.133 +                           message (or message part) URL
  57.134 +
  57.135 +   Responses:  OPTIONAL NO responses: BADURL, TOOBIG
  57.136 +
  57.137 +   Result:     OK -  append completed
  57.138 +               NO -  append error: can't append to that mailbox, error
  57.139 +                     in flags or date/time or message text, or can't
  57.140 +                     fetch that data
  57.141 +               BAD - command unknown or arguments invalid
  57.142 +
  57.143 +   The APPEND command concatenates all the message parts and appends
  57.144 +   them as a new message to the end of the specified mailbox.  The
  57.145 +   parenthesized flag list and date/time string set the flags and the
  57.146 +   internal date, respectively, as described in IMAP [1].  The
  57.147 +   subsequent command parameters specify the message parts that are
  57.148 +   appended sequentially to the output message.
  57.149 +
  57.150 +   If the original form of APPEND is used, a message literal follows the
  57.151 +   optional flag list and date/time string, which is appended as
  57.152 +   described in IMAP [1].  If the extended form is used, "CATENATE" and
  57.153 +   a parenthesized list of message literals and message URLs follows,
  57.154 +   each of which is appended to the new message.  If a message literal
  57.155 +   is specified (indicated by "TEXT"), the octets following the count
  57.156 +   are appended.  If a message URL is specified (indicated by "URL"),
  57.157 +   the octets of the body part pointed to by that URL are appended, as
  57.158 +   if the literal returned in a FETCH BODY response were put in place of
  57.159 +   the message part specifier.  The APPEND command does not cause the
  57.160 +   \Seen flag to be set for any catenated body part.  The APPEND command
  57.161 +   does not change the selected mailbox.
  57.162 +
  57.163 +   In the extended APPEND command, the string following "URL" is an IMAP
  57.164 +   URL [2] and is interpreted according to the rules of [2].  The
  57.165 +   present document only describes the behavior of the command using
  57.166 +   IMAP URLs that refer to specific messages or message parts on the
  57.167 +   current IMAP server from the current authenticated IMAP session.
  57.168 +   Because of that, only relative IMAP message or message part URLs
  57.169 +   (i.e., those having no scheme or <iserver>) are used.  The base URL
  57.170 +
  57.171 +
  57.172 +
  57.173 +Resnick                     Standards Track                     [Page 3]
  57.174 +
  57.175 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.176 +
  57.177 +
  57.178 +   for evaluating the relative URL is considered "imap://user@server/",
  57.179 +   where "user" is the user name of the currently authenticated user and
  57.180 +   "server" is the domain name of the current server.  When in the
  57.181 +   selected state, the base URL is considered
  57.182 +   "imap://user@server/mailbox", where "mailbox" is the encoded name of
  57.183 +   the currently selected mailbox.  Additionally, since the APPEND
  57.184 +   command is valid in the authenticated state of an IMAP session, no
  57.185 +   further LOGIN or AUTHENTICATE command is performed for URLs specified
  57.186 +   in the extended APPEND command.
  57.187 +
  57.188 +      Note: Use of an absolute IMAP URL or any URL that refers to
  57.189 +      anything other than a message or message part from the current
  57.190 +      authenticated IMAP session is outside the scope of this document
  57.191 +      and would require an extension to this specification, and a server
  57.192 +      implementing only this specification would return NO to such a
  57.193 +      request.
  57.194 +
  57.195 +   The client is responsible for making sure that the catenated message
  57.196 +   is in the format of an Internet Message Format (RFC 2822) [4] or
  57.197 +   Multipurpose Internet Mail Extension (MIME) [5] message.  In
  57.198 +   particular, when a URL is catenated, the server copies octets,
  57.199 +   unchanged, from the indicated message or message part to the
  57.200 +   catenated message.  It does no data conversion (e.g., MIME transfer
  57.201 +   encodings) nor any verification that the data is appropriate for the
  57.202 +   MIME part of the message into which it is inserted.  The client is
  57.203 +   also responsible for inserting appropriate MIME boundaries between
  57.204 +   body parts, and writing MIME Content-Type and Content-Transfer-
  57.205 +   Encoding lines as needed in the appropriate places.
  57.206 +
  57.207 +   Responses behave just as the original APPEND command described in
  57.208 +   IMAP [1].  If the server implements the IMAP UIDPLUS extension [6],
  57.209 +   it will also return an APPENDUID response code in the tagged OK
  57.210 +   response.  Two response codes are provided in Section 4 that can be
  57.211 +   used in the tagged NO response if the APPEND command fails.
  57.212 +
  57.213 +4.  Response Codes
  57.214 +
  57.215 +   When a APPEND command fails, it may return a response code that
  57.216 +   describes a reason for the failure.
  57.217 +
  57.218 +4.1.  BADURL Response
  57.219 +
  57.220 +   The BADURL response code is returned if the APPEND fails to process
  57.221 +   one of the specified URLs.  Possible reasons for this are bad URL
  57.222 +   syntax, unrecognized URL schema, invalid message UID, or invalid body
  57.223 +   part.  The BADURL response code contains the first URL specified as a
  57.224 +   parameter to the APPEND command that has caused the operation to
  57.225 +   fail.
  57.226 +
  57.227 +
  57.228 +
  57.229 +Resnick                     Standards Track                     [Page 4]
  57.230 +
  57.231 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.232 +
  57.233 +
  57.234 +4.2.  TOOBIG Response
  57.235 +
  57.236 +   The TOOBIG response code is returned if the resulting message will
  57.237 +   exceed the 4-GB IMAP message limit.  This might happen, for example,
  57.238 +   if the client specifies 3 URLs for 2-GB messages.  Note that even if
  57.239 +   the server doesn't return TOOBIG, it still has to be defensive
  57.240 +   against misbehaving or malicious clients that try to construct a
  57.241 +   message over the 4-GB limit.  The server may also wish to return the
  57.242 +   TOOBIG response code if the resulting message exceeds a server-
  57.243 +   specific message size limit.
  57.244 +
  57.245 +5.  Formal Syntax
  57.246 +
  57.247 +   The following syntax specification uses the Augmented Backus-Naur
  57.248 +   Form (ABNF) [7] notation.  Elements not defined here can be found in
  57.249 +   the formal syntax of the ABNF [7], IMAP [1], and IMAP ABNF extensions
  57.250 +   [8] specifications.  Note that capability and resp-text-code are
  57.251 +   extended from the IMAP [1] specification and append-data is extended
  57.252 +   from the IMAP ABNF extensions [8] specification.
  57.253 +
  57.254 +   append-data =/ "CATENATE" SP "(" cat-part *(SP cat-part) ")"
  57.255 +
  57.256 +   cat-part = text-literal / url
  57.257 +
  57.258 +   text-literal = "TEXT" SP literal
  57.259 +
  57.260 +   url = "URL" SP astring
  57.261 +
  57.262 +   resp-text-code =/ toobig-response-code / badurl-response-code
  57.263 +
  57.264 +   toobig-response-code = "TOOBIG"
  57.265 +
  57.266 +   badurl-response-code = "BADURL" SP url-resp-text
  57.267 +
  57.268 +   url-resp-text = 1*(%x01-09 /
  57.269 +                      %x0B-0C /
  57.270 +                      %x0E-5B /
  57.271 +                      %x5D-FE) ; Any TEXT-CHAR except "]"
  57.272 +
  57.273 +   capability =/ "CATENATE"
  57.274 +
  57.275 +   The astring in the definition of url and the url-resp-text in the
  57.276 +   definition of badurl-response-code each contain an imapurl as defined
  57.277 +   by [2].
  57.278 +
  57.279 +
  57.280 +
  57.281 +
  57.282 +
  57.283 +
  57.284 +
  57.285 +Resnick                     Standards Track                     [Page 5]
  57.286 +
  57.287 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.288 +
  57.289 +
  57.290 +6.  Acknowledgements
  57.291 +
  57.292 +   Thanks to the members of the LEMONADE working group for their input.
  57.293 +   Special thanks to Alexey Melnikov for the examples.
  57.294 +
  57.295 +7.  Security Considerations
  57.296 +
  57.297 +   The CATENATE extension does not raise any security considerations
  57.298 +   that are not present for the base protocol or in the use of IMAP
  57.299 +   URLs, and these issues are discussed in the IMAP [1] and IMAP URL [2]
  57.300 +   documents.
  57.301 +
  57.302 +8.  IANA Considerations
  57.303 +
  57.304 +   IMAP4 capabilities are registered by publishing a standards track or
  57.305 +   IESG approved experimental RFC.  The registry is currently located at
  57.306 +   <http://www.iana.org/assignments/imap4-capabilities>.  This document
  57.307 +   defines the CATENATE IMAP capability.  The IANA has added this
  57.308 +   capability to the registry.
  57.309 +
  57.310 +
  57.311 +
  57.312 +
  57.313 +
  57.314 +
  57.315 +
  57.316 +
  57.317 +
  57.318 +
  57.319 +
  57.320 +
  57.321 +
  57.322 +
  57.323 +
  57.324 +
  57.325 +
  57.326 +
  57.327 +
  57.328 +
  57.329 +
  57.330 +
  57.331 +
  57.332 +
  57.333 +
  57.334 +
  57.335 +
  57.336 +
  57.337 +
  57.338 +
  57.339 +
  57.340 +
  57.341 +Resnick                     Standards Track                     [Page 6]
  57.342 +
  57.343 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.344 +
  57.345 +
  57.346 +Appendix A.  Examples
  57.347 +
  57.348 +   Lines not starting with "C: " or "S: " are continuations of the
  57.349 +   previous lines.
  57.350 +
  57.351 +   The original message in examples 1 and 2 below (UID = 20) has the
  57.352 +   following structure:
  57.353 +
  57.354 +
  57.355 +      multipart/mixed MIME message with two body parts:
  57.356 +
  57.357 +      1.  text/plain
  57.358 +
  57.359 +      2.  application/x-zip-compressed
  57.360 +
  57.361 +   Example 1: The following example demonstrates how a CATENATE client
  57.362 +   can replace an attachment in a draft message, without the need to
  57.363 +   download it to the client and upload it back.
  57.364 +
  57.365 +   C: A003 APPEND Drafts (\Seen \Draft $MDNSent) CATENATE
  57.366 +    (URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;section=HEADER"
  57.367 +    TEXT {42}
  57.368 +   S: + Ready for literal data
  57.369 +   C:
  57.370 +   C: --------------030308070208000400050907
  57.371 +   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;section=1.MIME"
  57.372 +    URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;section=1" TEXT {42}
  57.373 +   S: + Ready for literal data
  57.374 +   C:
  57.375 +   C: --------------030308070208000400050907
  57.376 +   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=30" TEXT {44}
  57.377 +   S: + Ready for literal data
  57.378 +   C:
  57.379 +   C: --------------030308070208000400050907--
  57.380 +   C: )
  57.381 +   S: A003 OK catenate append completed
  57.382 +
  57.383 +
  57.384 +
  57.385 +
  57.386 +
  57.387 +
  57.388 +
  57.389 +
  57.390 +
  57.391 +
  57.392 +
  57.393 +
  57.394 +
  57.395 +
  57.396 +
  57.397 +Resnick                     Standards Track                     [Page 7]
  57.398 +
  57.399 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.400 +
  57.401 +
  57.402 +   Example 2: The following example demonstrates how the CATENATE
  57.403 +   extension can be used to replace edited text in a draft message, as
  57.404 +   well as header fields for the top level message part (e.g., Subject
  57.405 +   has changed).  The previous version of the draft is marked as
  57.406 +   \Deleted.  Note that the server also supports the UIDPLUS extension,
  57.407 +   so the APPENDUID response code is returned in the successful OK
  57.408 +   response to the APPEND command.
  57.409 +
  57.410 +   C: A003 APPEND Drafts (\Seen \Draft $MDNSent) CATENATE (TEXT {738}
  57.411 +   S: + Ready for literal data
  57.412 +   C: Return-Path: <bar@example.org>
  57.413 +   C: Received: from [127.0.0.2]
  57.414 +   C:           by rufus.example.org via TCP (internal) with ESMTPA;
  57.415 +   C:           Thu, 11 Nov 2004 16:57:07 +0000
  57.416 +   C: Message-ID: <419399E1.6000505@example.org>
  57.417 +   C: Date: Thu, 12 Nov 2004 16:57:05 +0000
  57.418 +   C: From: Bob Ar <bar@example.org>
  57.419 +   C: X-Accept-Language: en-us, en
  57.420 +   C: MIME-Version: 1.0
  57.421 +   C: To: foo@example.net
  57.422 +   C: Subject: About our holiday trip
  57.423 +   C: Content-Type: multipart/mixed;
  57.424 +   C:               boundary="------------030308070208000400050907"
  57.425 +   C:
  57.426 +   C: --------------030308070208000400050907
  57.427 +   C: Content-Type: text/plain; charset=us-ascii; format=flowed
  57.428 +   C: Content-Transfer-Encoding: 7bit
  57.429 +   C:
  57.430 +   C: Our travel agent has sent the updated schedule.
  57.431 +   C:
  57.432 +   C: Cheers,
  57.433 +   C: Bob
  57.434 +   C: --------------030308070208000400050907
  57.435 +   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;Section=2.MIME"
  57.436 +    URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;Section=2" TEXT {44}
  57.437 +   S: + Ready for literal data
  57.438 +   C:
  57.439 +   C: --------------030308070208000400050907--
  57.440 +   C: )
  57.441 +   S: A003 OK [APPENDUID 385759045 45] append Completed
  57.442 +   C: A004 UID STORE 20 +FLAGS.SILENT (\Deleted)
  57.443 +   S: A004 OK STORE completed
  57.444 +
  57.445 +
  57.446 +
  57.447 +
  57.448 +
  57.449 +
  57.450 +
  57.451 +
  57.452 +
  57.453 +Resnick                     Standards Track                     [Page 8]
  57.454 +
  57.455 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.456 +
  57.457 +
  57.458 +   Example 3: The following example demonstrates how the CATENATE
  57.459 +   extension can be used to strip attachments.  Below, a PowerPoint
  57.460 +   attachment was replaced by a small text part explaining that the
  57.461 +   attachment was stripped.
  57.462 +
  57.463 +   C: A003 APPEND Drafts (\Seen \Draft $MDNSent) CATENATE
  57.464 +    (URL "/Drafts;UIDVALIDITY=385759045/;UID=21/;section=HEADER"
  57.465 +    TEXT {42}
  57.466 +   S: + Ready for literal data
  57.467 +   C:
  57.468 +   C: --------------030308070208000400050903
  57.469 +   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=21/;section=1.MIME"
  57.470 +    URL "/Drafts;UIDVALIDITY=385759045/;UID=21/;section=1" TEXT {255}
  57.471 +   S: + Ready for literal data
  57.472 +   C:
  57.473 +   C: --------------030308070208000400050903
  57.474 +   C: Content-type: text/plain; charset="us-ascii"
  57.475 +   C: Content-transfer-encoding: 7bit
  57.476 +   C:
  57.477 +   C: This body part contained a Power Point presentation that was
  57.478 +   C: deleted upon your request.
  57.479 +   C: --------------030308070208000400050903--
  57.480 +   C: )
  57.481 +   S: A003 OK append Completed
  57.482 +
  57.483 +
  57.484 +
  57.485 +
  57.486 +
  57.487 +
  57.488 +
  57.489 +
  57.490 +
  57.491 +
  57.492 +
  57.493 +
  57.494 +
  57.495 +
  57.496 +
  57.497 +
  57.498 +
  57.499 +
  57.500 +
  57.501 +
  57.502 +
  57.503 +
  57.504 +
  57.505 +
  57.506 +
  57.507 +
  57.508 +
  57.509 +Resnick                     Standards Track                     [Page 9]
  57.510 +
  57.511 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.512 +
  57.513 +
  57.514 +   Example 4: The following example demonstrates a failed APPEND
  57.515 +   command.  The server returns the BADURL response code to indicate
  57.516 +   that one of the provided URLs is invalid.  This example also
  57.517 +   demonstrates how the CATENATE extension can be used to construct a
  57.518 +   digest of several messages.
  57.519 +
  57.520 +   C: A003 APPEND Sent (\Seen $MDNSent) CATENATE (TEXT {541}
  57.521 +   S: + Ready for literal data
  57.522 +   C: Return-Path: <foo@example.org>
  57.523 +   C: Received: from [127.0.0.2]
  57.524 +   C:           by rufus.example.org via TCP (internal) with ESMTPA;
  57.525 +   C:           Thu, 11 Nov 2004 16:57:07 +0000
  57.526 +   C: Message-ID: <419399E1.6000505@example.org>
  57.527 +   C: Date: Thu, 21 Nov 2004 16:57:05 +0000
  57.528 +   C: From: Farren Oo <foo@example.org>
  57.529 +   C: X-Accept-Language: en-us, en
  57.530 +   C: MIME-Version: 1.0
  57.531 +   C: To: bar@example.org
  57.532 +   C: Subject: Digest of the mailing list for today
  57.533 +   C: Content-Type: multipart/digest;
  57.534 +   C:               boundary="------------030308070208000400050904"
  57.535 +   C:
  57.536 +   C: --------------030308070208000400050904
  57.537 +   C:  URL "/INBOX;UIDVALIDITY=785799047/;UID=11467" TEXT {42}
  57.538 +   S: + Ready for literal data
  57.539 +   C:
  57.540 +   C: --------------030308070208000400050904
  57.541 +   C:  URL "/INBOX;UIDVALIDITY=785799047/;UID=113330/;section=1.5.9"
  57.542 +    TEXT {42}
  57.543 +   S: + Ready for literal data
  57.544 +   C:
  57.545 +   C: --------------030308070208000400050904
  57.546 +   C:  URL "/INBOX;UIDVALIDITY=785799047/;UID=11916" TEXT {44}
  57.547 +   S: + Ready for literal data
  57.548 +   C:
  57.549 +   C: --------------030308070208000400050904--
  57.550 +   C: )
  57.551 +   S: A003 NO [BADURL "/INBOX;UIDVALIDITY=785799047/;UID=113330;
  57.552 +   section=1.5.9"] CATENATE append has failed, one message expunged
  57.553 +
  57.554 +   Note that the server could have validated the URLs as they were
  57.555 +   received and therefore could have returned the tagged NO response
  57.556 +   with BADURL response-code in place of any continuation request after
  57.557 +   the URL was received.
  57.558 +
  57.559 +
  57.560 +
  57.561 +
  57.562 +
  57.563 +
  57.564 +
  57.565 +Resnick                     Standards Track                    [Page 10]
  57.566 +
  57.567 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.568 +
  57.569 +
  57.570 +9.  Normative References
  57.571 +
  57.572 +   [1]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1",
  57.573 +        RFC 3501, March 2003.
  57.574 +
  57.575 +   [2]  Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
  57.576 +
  57.577 +   [3]  Crispin, M., "Internet Message Access Protocol (IMAP) -
  57.578 +        MULTIAPPEND Extension", RFC 3502, March 2003.
  57.579 +
  57.580 +   [4]  Resnick, P., "Internet Message Format", RFC 2822, April 2001.
  57.581 +
  57.582 +   [5]  Freed, N. and N. Borenstein, "Multipurpose Internet Mail
  57.583 +        Extensions (MIME) Part One: Format of Internet Message Bodies",
  57.584 +        RFC 2045, November 1996.
  57.585 +
  57.586 +   [6]  Crispin, M., "Internet Message Access Protocol (IMAP) - UIDPLUS
  57.587 +        extension", RFC 4315, December 2005.
  57.588 +
  57.589 +   [7]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
  57.590 +        Specifications: ABNF", RFC 4234, October 2005.
  57.591 +
  57.592 +   [8]  Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4 ABNF",
  57.593 +        RFC 4466, April 2006.
  57.594 +
  57.595 +
  57.596 +
  57.597 +
  57.598 +
  57.599 +
  57.600 +
  57.601 +
  57.602 +
  57.603 +
  57.604 +
  57.605 +
  57.606 +
  57.607 +
  57.608 +
  57.609 +
  57.610 +
  57.611 +
  57.612 +
  57.613 +
  57.614 +
  57.615 +
  57.616 +
  57.617 +
  57.618 +
  57.619 +
  57.620 +
  57.621 +Resnick                     Standards Track                    [Page 11]
  57.622 +
  57.623 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.624 +
  57.625 +
  57.626 +Author's Address
  57.627 +
  57.628 +   Peter W. Resnick
  57.629 +   QUALCOMM Incorporated
  57.630 +   5775 Morehouse Drive
  57.631 +   San Diego, CA  92121-1714
  57.632 +   US
  57.633 +
  57.634 +   Phone: +1 858 651 4478
  57.635 +   EMail: presnick@qualcomm.com
  57.636 +   URI:   http://www.qualcomm.com/~presnick/
  57.637 +
  57.638 +
  57.639 +
  57.640 +
  57.641 +
  57.642 +
  57.643 +
  57.644 +
  57.645 +
  57.646 +
  57.647 +
  57.648 +
  57.649 +
  57.650 +
  57.651 +
  57.652 +
  57.653 +
  57.654 +
  57.655 +
  57.656 +
  57.657 +
  57.658 +
  57.659 +
  57.660 +
  57.661 +
  57.662 +
  57.663 +
  57.664 +
  57.665 +
  57.666 +
  57.667 +
  57.668 +
  57.669 +
  57.670 +
  57.671 +
  57.672 +
  57.673 +
  57.674 +
  57.675 +
  57.676 +
  57.677 +Resnick                     Standards Track                    [Page 12]
  57.678 +
  57.679 +RFC 4469                IMAP CATENATE Extension               April 2006
  57.680 +
  57.681 +
  57.682 +Full Copyright Statement
  57.683 +
  57.684 +   Copyright (C) The Internet Society (2006).
  57.685 +
  57.686 +   This document is subject to the rights, licenses and restrictions
  57.687 +   contained in BCP 78, and except as set forth therein, the authors
  57.688 +   retain all their rights.
  57.689 +
  57.690 +   This document and the information contained herein are provided on an
  57.691 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  57.692 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  57.693 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  57.694 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  57.695 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  57.696 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  57.697 +
  57.698 +Intellectual Property
  57.699 +
  57.700 +   The IETF takes no position regarding the validity or scope of any
  57.701 +   Intellectual Property Rights or other rights that might be claimed to
  57.702 +   pertain to the implementation or use of the technology described in
  57.703 +   this document or the extent to which any license under such rights
  57.704 +   might or might not be available; nor does it represent that it has
  57.705 +   made any independent effort to identify any such rights.  Information
  57.706 +   on the procedures with respect to rights in RFC documents can be
  57.707 +   found in BCP 78 and BCP 79.
  57.708 +
  57.709 +   Copies of IPR disclosures made to the IETF Secretariat and any
  57.710 +   assurances of licenses to be made available, or the result of an
  57.711 +   attempt made to obtain a general license or permission for the use of
  57.712 +   such proprietary rights by implementers or users of this
  57.713 +   specification can be obtained from the IETF on-line IPR repository at
  57.714 +   http://www.ietf.org/ipr.
  57.715 +
  57.716 +   The IETF invites any interested party to bring to its attention any
  57.717 +   copyrights, patents or patent applications, or other proprietary
  57.718 +   rights that may cover technology that may be required to implement
  57.719 +   this standard.  Please address the information to the IETF at
  57.720 +   ietf-ipr@ietf.org.
  57.721 +
  57.722 +Acknowledgement
  57.723 +
  57.724 +   Funding for the RFC Editor function is provided by the IETF
  57.725 +   Administrative Support Activity (IASA).
  57.726 +
  57.727 +
  57.728 +
  57.729 +
  57.730 +
  57.731 +
  57.732 +
  57.733 +Resnick                     Standards Track                    [Page 13]
  57.734 +
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/docs/rfc/rfc4505.txt	Mon Sep 14 15:17:45 2009 +0900
    58.3 @@ -0,0 +1,507 @@
    58.4 +
    58.5 +
    58.6 +
    58.7 +
    58.8 +
    58.9 +
   58.10 +Network Working Group                                   K. Zeilenga, Ed.
   58.11 +Request for Comments: 4505                           OpenLDAP Foundation
   58.12 +Obsoletes: 2245                                                June 2006
   58.13 +Category: Standards Track
   58.14 +
   58.15 +
   58.16 +  Anonymous Simple Authentication and Security Layer (SASL) Mechanism
   58.17 +
   58.18 +Status of This Memo
   58.19 +
   58.20 +   This document specifies an Internet standards track protocol for the
   58.21 +   Internet community, and requests discussion and suggestions for
   58.22 +   improvements.  Please refer to the current edition of the "Internet
   58.23 +   Official Protocol Standards" (STD 1) for the standardization state
   58.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   58.25 +
   58.26 +Copyright Notice
   58.27 +
   58.28 +   Copyright (C) The Internet Society (2006).
   58.29 +
   58.30 +Abstract
   58.31 +
   58.32 +   On the Internet, it is common practice to permit anonymous access to
   58.33 +   various services.  Traditionally, this has been done with a plain-
   58.34 +   text password mechanism using "anonymous" as the user name and using
   58.35 +   optional trace information, such as an email address, as the
   58.36 +   password.  As plain-text login commands are not permitted in new IETF
   58.37 +   protocols, a new way to provide anonymous login is needed within the
   58.38 +   context of the Simple Authentication and Security Layer (SASL)
   58.39 +   framework.
   58.40 +
   58.41 +1.  Introduction
   58.42 +
   58.43 +   This document defines an anonymous mechanism for the Simple
   58.44 +   Authentication and Security Layer ([SASL]) framework.  The name
   58.45 +   associated with this mechanism is "ANONYMOUS".
   58.46 +
   58.47 +   Unlike many other SASL mechanisms, whose purpose is to authenticate
   58.48 +   and identify the user to a server, the purpose of this SASL mechanism
   58.49 +   is to allow the user to gain access to services or resources without
   58.50 +   requiring the user to establish or otherwise disclose their identity
   58.51 +   to the server.  That is, this mechanism provides an anonymous login
   58.52 +   method.
   58.53 +
   58.54 +   This mechanism does not provide a security layer.
   58.55 +
   58.56 +   This document replaces RFC 2245.  Changes since RFC 2245 are detailed
   58.57 +   in Appendix A.
   58.58 +
   58.59 +
   58.60 +
   58.61 +Zeilenga                    Standards Track                     [Page 1]
   58.62 +
   58.63 +RFC 4505                Anonymous SASL Mechanism               June 2006
   58.64 +
   58.65 +
   58.66 +2.  The Anonymous Mechanism
   58.67 +
   58.68 +   The mechanism consists of a single message from the client to the
   58.69 +   server.  The client may include in this message trace information in
   58.70 +   the form of a string of [UTF-8]-encoded [Unicode] characters prepared
   58.71 +   in accordance with [StringPrep] and the "trace" stringprep profile
   58.72 +   defined in Section 3 of this document.  The trace information, which
   58.73 +   has no semantical value, should take one of two forms: an Internet
   58.74 +   email address, or an opaque string that does not contain the '@'
   58.75 +   (U+0040) character and that can be interpreted by the system
   58.76 +   administrator of the client's domain.  For privacy reasons, an
   58.77 +   Internet email address or other information identifying the user
   58.78 +   should only be used with permission from the user.
   58.79 +
   58.80 +   A server that permits anonymous access will announce support for the
   58.81 +   ANONYMOUS mechanism and allow anyone to log in using that mechanism,
   58.82 +   usually with restricted access.
   58.83 +
   58.84 +   A formal grammar for the client message using Augmented BNF [ABNF] is
   58.85 +   provided below as a tool for understanding this technical
   58.86 +   specification.
   58.87 +
   58.88 +      message     = [ email / token ]
   58.89 +                    ;; to be prepared in accordance with Section 3
   58.90 +
   58.91 +      UTF1        = %x00-3F / %x41-7F ;; less '@' (U+0040)
   58.92 +      UTF2        = %xC2-DF UTF0
   58.93 +      UTF3        = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
   58.94 +                    %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
   58.95 +      UTF4        = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
   58.96 +                    %xF4 %x80-8F 2(UTF0)
   58.97 +      UTF0        = %x80-BF
   58.98 +
   58.99 +      TCHAR       = UTF1 / UTF2 / UTF3 / UTF4
  58.100 +                    ;; any UTF-8 encoded Unicode character
  58.101 +                    ;; except '@' (U+0040)
  58.102 +
  58.103 +      email       = addr-spec
  58.104 +                    ;; as defined in [IMAIL]
  58.105 +
  58.106 +      token       = 1*255TCHAR
  58.107 +
  58.108 +   Note to implementors:
  58.109 +      The <token> production is restricted to 255 UTF-8-encoded Unicode
  58.110 +      characters.  As the encoding of a characters uses a sequence of 1
  58.111 +      to 4 octets, a token may be as long as 1020 octets.
  58.112 +
  58.113 +
  58.114 +
  58.115 +
  58.116 +
  58.117 +Zeilenga                    Standards Track                     [Page 2]
  58.118 +
  58.119 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.120 +
  58.121 +
  58.122 +3.  The "trace" Profile of "Stringprep"
  58.123 +
  58.124 +   This section defines the "trace" profile of [StringPrep].  This
  58.125 +   profile is designed for use with the SASL ANONYMOUS Mechanism.
  58.126 +   Specifically, the client is to prepare the <message> production in
  58.127 +   accordance with this profile.
  58.128 +
  58.129 +   The character repertoire of this profile is Unicode 3.2 [Unicode].
  58.130 +
  58.131 +   No mapping is required by this profile.
  58.132 +
  58.133 +   No Unicode normalization is required by this profile.
  58.134 +
  58.135 +   The list of unassigned code points for this profile is that provided
  58.136 +   in Appendix A of [StringPrep].  Unassigned code points are not
  58.137 +   prohibited.
  58.138 +
  58.139 +   Characters from the following tables of [StringPrep] are prohibited:
  58.140 +
  58.141 +      - C.2.1 (ASCII control characters)
  58.142 +      - C.2.2 (Non-ASCII control characters)
  58.143 +      - C.3 (Private use characters)
  58.144 +      - C.4 (Non-character code points)
  58.145 +      - C.5 (Surrogate codes)
  58.146 +      - C.6 (Inappropriate for plain text)
  58.147 +      - C.8 (Change display properties are deprecated)
  58.148 +      - C.9 (Tagging characters)
  58.149 +
  58.150 +   No additional characters are prohibited.
  58.151 +
  58.152 +   This profile requires bidirectional character checking per Section 6
  58.153 +   of [StringPrep].
  58.154 +
  58.155 +4.  Example
  58.156 +
  58.157 +   Here is a sample ANONYMOUS login between an IMAP client and server.
  58.158 +   In this example, "C:" and "S:" indicate lines sent by the client and
  58.159 +   server, respectively.  If such lines are wrapped without a new "C:"
  58.160 +   or "S:" label, then the wrapping is for editorial clarity and is not
  58.161 +   part of the command.
  58.162 +
  58.163 +   Note that this example uses the IMAP profile [IMAP4] of SASL.  The
  58.164 +   base64 encoding of challenges and responses as well as the "+ "
  58.165 +   preceding the responses are part of the IMAP4 profile, not part of
  58.166 +   SASL itself.  Additionally, protocols with SASL profiles permitting
  58.167 +   an initial client response will be able to avoid the extra round trip
  58.168 +   below (the server response with an empty "+ ").
  58.169 +
  58.170 +
  58.171 +
  58.172 +
  58.173 +Zeilenga                    Standards Track                     [Page 3]
  58.174 +
  58.175 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.176 +
  58.177 +
  58.178 +   In this example, the trace information is "sirhc".
  58.179 +
  58.180 +      S: * OK IMAP4 server ready
  58.181 +      C: A001 CAPABILITY
  58.182 +      S: * CAPABILITY IMAP4 IMAP4rev1 AUTH=DIGEST-MD5 AUTH=ANONYMOUS
  58.183 +      S: A001 OK done
  58.184 +      C: A002 AUTHENTICATE ANONYMOUS
  58.185 +      S: +
  58.186 +      C: c2lyaGM=
  58.187 +      S: A003 OK Welcome, trace information has been logged.
  58.188 +
  58.189 +5.  Security Considerations
  58.190 +
  58.191 +   The ANONYMOUS mechanism grants access to services and/or resources by
  58.192 +   anyone.  For this reason, it should be disabled by default so that
  58.193 +   the administrator can make an explicit decision to enable it.
  58.194 +
  58.195 +   If the anonymous user has any write privileges, a denial-of-service
  58.196 +   attack is possible by filling up all available space.  This can be
  58.197 +   prevented by disabling all write access by anonymous users.
  58.198 +
  58.199 +   If anonymous users have read and write access to the same area, the
  58.200 +   server can be used as a communication mechanism to exchange
  58.201 +   information anonymously.  Servers that accept anonymous submissions
  58.202 +   should implement the common "drop box" model, which forbids anonymous
  58.203 +   read access to the area where anonymous submissions are accepted.
  58.204 +
  58.205 +   If the anonymous user can run many expensive operations (e.g., an
  58.206 +   IMAP SEARCH BODY command), this could enable a denial-of-service
  58.207 +   attack.  Servers are encouraged to reduce the priority of anonymous
  58.208 +   users or limit their resource usage.
  58.209 +
  58.210 +   While servers may impose a limit on the number of anonymous users,
  58.211 +   note that such limits enable denial-of-service attacks and should be
  58.212 +   used with caution.
  58.213 +
  58.214 +   The trace information is not authenticated, so it can be falsified.
  58.215 +   This can be used as an attempt to get someone else in trouble for
  58.216 +   access to questionable information.  Administrators investigating
  58.217 +   abuse need to realize that this trace information may be falsified.
  58.218 +
  58.219 +   A client that uses the user's correct email address as trace
  58.220 +   information without explicit permission may violate that user's
  58.221 +   privacy.  Anyone who accesses an anonymous archive on a sensitive
  58.222 +   subject (e.g., sexual abuse) likely has strong privacy needs.
  58.223 +   Clients should not send the email address without the explicit
  58.224 +   permission of the user and should offer the option of supplying no
  58.225 +   trace information, thus only exposing the source IP address and time.
  58.226 +
  58.227 +
  58.228 +
  58.229 +Zeilenga                    Standards Track                     [Page 4]
  58.230 +
  58.231 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.232 +
  58.233 +
  58.234 +   Anonymous proxy servers could enhance this privacy but would have to
  58.235 +   consider the resulting potential denial-of-service attacks.
  58.236 +
  58.237 +   Anonymous connections are susceptible to man-in-the-middle attacks
  58.238 +   that view or alter the data transferred.  Clients and servers are
  58.239 +   encouraged to support external data security services.
  58.240 +
  58.241 +   Protocols that fail to require an explicit anonymous login are more
  58.242 +   susceptible to break-ins given certain common implementation
  58.243 +   techniques.  Specifically, Unix servers that offer user login may
  58.244 +   initially start up as root and switch to the appropriate user id
  58.245 +   after an explicit login command.  Normally, such servers refuse all
  58.246 +   data access commands prior to explicit login and may enter a
  58.247 +   restricted security environment (e.g., the Unix chroot(2) function)
  58.248 +   for anonymous users.  If anonymous access is not explicitly
  58.249 +   requested, the entire data access machinery is exposed to external
  58.250 +   security attacks without the chance for explicit protective measures.
  58.251 +   Protocols that offer restricted data access should not allow
  58.252 +   anonymous data access without an explicit login step.
  58.253 +
  58.254 +   General [SASL] security considerations apply to this mechanism.
  58.255 +
  58.256 +   [StringPrep] security considerations and [Unicode] security
  58.257 +   considerations discussed in [StringPrep] apply to this mechanism.
  58.258 +   [UTF-8] security considerations also apply.
  58.259 +
  58.260 +6.  IANA Considerations
  58.261 +
  58.262 +   The SASL Mechanism registry [IANA-SASL] entry for the ANONYMOUS
  58.263 +   mechanism has been updated by the IANA to reflect that this document
  58.264 +   now provides its technical specification.
  58.265 +
  58.266 +      To: iana@iana.org
  58.267 +      Subject: Updated Registration of SASL mechanism ANONYMOUS
  58.268 +
  58.269 +      SASL mechanism name: ANONYMOUS
  58.270 +      Security considerations: See RFC 4505.
  58.271 +      Published specification (optional, recommended): RFC 4505
  58.272 +      Person & email address to contact for further information:
  58.273 +           Kurt Zeilenga <Kurt@OpenLDAP.org>
  58.274 +           Chris Newman <Chris.Newman@sun.com>
  58.275 +      Intended usage: COMMON
  58.276 +      Author/Change controller: IESG <iesg@ietf.org>
  58.277 +      Note: Updates existing entry for ANONYMOUS
  58.278 +
  58.279 +
  58.280 +
  58.281 +
  58.282 +
  58.283 +
  58.284 +
  58.285 +Zeilenga                    Standards Track                     [Page 5]
  58.286 +
  58.287 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.288 +
  58.289 +
  58.290 +   The [StringPrep] profile "trace", first defined in this RFC, has been
  58.291 +   registered:
  58.292 +
  58.293 +      To: iana@iana.org
  58.294 +      Subject: Initial Registration of Stringprep "trace" profile
  58.295 +
  58.296 +      Stringprep profile: trace
  58.297 +      Published specification: RFC 4505
  58.298 +      Person & email address to contact for further information:
  58.299 +          Kurt Zeilenga <kurt@openldap.org>
  58.300 +
  58.301 +7.  Acknowledgement
  58.302 +
  58.303 +   This document is a revision of RFC 2245 by Chris Newman.  Portions of
  58.304 +   the grammar defined in Section 1 were borrowed from RFC 3629 by
  58.305 +   Francois Yergeau.
  58.306 +
  58.307 +   This document is a product of the IETF SASL WG.
  58.308 +
  58.309 +8.  Normative References
  58.310 +
  58.311 +   [ABNF]       Crocker, D. and P. Overell, "Augmented BNF for Syntax
  58.312 +                Specifications: ABNF", RFC 4234, October 2005.
  58.313 +
  58.314 +   [IMAIL]      Resnick, P., "Internet Message Format", RFC 2822, April
  58.315 +                2001.
  58.316 +
  58.317 +   [SASL]       Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
  58.318 +                Authentication and Security Layer (SASL)", RFC 4422,
  58.319 +                June 2006.
  58.320 +
  58.321 +   [StringPrep] Hoffman, P. and M. Blanchet, "Preparation of
  58.322 +                Internationalized Strings ('stringprep')", RFC 3454,
  58.323 +                December 2002.
  58.324 +
  58.325 +   [Unicode]    The Unicode Consortium, "The Unicode Standard, Version
  58.326 +                3.2.0" is defined by "The Unicode Standard, Version 3.0"
  58.327 +                (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5),
  58.328 +                as amended by the "Unicode Standard Annex #27: Unicode
  58.329 +                3.1" (http://www.unicode.org/reports/tr27/) and by the
  58.330 +                "Unicode Standard Annex #28: Unicode 3.2"
  58.331 +                (http://www.unicode.org/reports/tr28/).
  58.332 +
  58.333 +   [UTF-8]      Yergeau, F., "UTF-8, a transformation format of ISO
  58.334 +                10646", RFC 3629 (also STD 63), November 2003.
  58.335 +
  58.336 +
  58.337 +
  58.338 +
  58.339 +
  58.340 +
  58.341 +Zeilenga                    Standards Track                     [Page 6]
  58.342 +
  58.343 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.344 +
  58.345 +
  58.346 +9.  Informative References
  58.347 +
  58.348 +   [IMAP4]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  58.349 +                4rev1", RFC 3501, March 2003.
  58.350 +
  58.351 +   [IANA-SASL]  IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL)
  58.352 +                MECHANISMS", <http://www.iana.org/assignments/sasl-
  58.353 +                mechanisms>.
  58.354 +
  58.355 +
  58.356 +
  58.357 +
  58.358 +
  58.359 +
  58.360 +
  58.361 +
  58.362 +
  58.363 +
  58.364 +
  58.365 +
  58.366 +
  58.367 +
  58.368 +
  58.369 +
  58.370 +
  58.371 +
  58.372 +
  58.373 +
  58.374 +
  58.375 +
  58.376 +
  58.377 +
  58.378 +
  58.379 +
  58.380 +
  58.381 +
  58.382 +
  58.383 +
  58.384 +
  58.385 +
  58.386 +
  58.387 +
  58.388 +
  58.389 +
  58.390 +
  58.391 +
  58.392 +
  58.393 +
  58.394 +
  58.395 +
  58.396 +
  58.397 +Zeilenga                    Standards Track                     [Page 7]
  58.398 +
  58.399 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.400 +
  58.401 +
  58.402 +Appendix A.  Changes since RFC 2245
  58.403 +
  58.404 +   This appendix is non-normative.
  58.405 +
  58.406 +   RFC 2245 allows the client to include optional trace information in
  58.407 +   the form of a human readable string.  RFC 2245 restricted this string
  58.408 +   to US-ASCII.  As the Internet is international, this document uses a
  58.409 +   string restricted to UTF-8 encoded Unicode characters.  A
  58.410 +   "stringprep" profile is defined to precisely define which Unicode
  58.411 +   characters are allowed in this string.  While the string remains
  58.412 +   restricted to 255 characters, the encoded length of each character
  58.413 +   may now range from 1 to 4 octets.
  58.414 +
  58.415 +   Additionally, a number of editorial changes were made.
  58.416 +
  58.417 +Editor's Address
  58.418 +
  58.419 +   Kurt D. Zeilenga
  58.420 +   OpenLDAP Foundation
  58.421 +
  58.422 +   EMail: Kurt@OpenLDAP.org
  58.423 +
  58.424 +
  58.425 +
  58.426 +
  58.427 +
  58.428 +
  58.429 +
  58.430 +
  58.431 +
  58.432 +
  58.433 +
  58.434 +
  58.435 +
  58.436 +
  58.437 +
  58.438 +
  58.439 +
  58.440 +
  58.441 +
  58.442 +
  58.443 +
  58.444 +
  58.445 +
  58.446 +
  58.447 +
  58.448 +
  58.449 +
  58.450 +
  58.451 +
  58.452 +
  58.453 +Zeilenga                    Standards Track                     [Page 8]
  58.454 +
  58.455 +RFC 4505                Anonymous SASL Mechanism               June 2006
  58.456 +
  58.457 +
  58.458 +Full Copyright Statement
  58.459 +
  58.460 +   Copyright (C) The Internet Society (2006).
  58.461 +
  58.462 +   This document is subject to the rights, licenses and restrictions
  58.463 +   contained in BCP 78, and except as set forth therein, the authors
  58.464 +   retain all their rights.
  58.465 +
  58.466 +   This document and the information contained herein are provided on an
  58.467 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  58.468 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  58.469 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  58.470 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  58.471 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  58.472 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  58.473 +
  58.474 +Intellectual Property
  58.475 +
  58.476 +   The IETF takes no position regarding the validity or scope of any
  58.477 +   Intellectual Property Rights or other rights that might be claimed to
  58.478 +   pertain to the implementation or use of the technology described in
  58.479 +   this document or the extent to which any license under such rights
  58.480 +   might or might not be available; nor does it represent that it has
  58.481 +   made any independent effort to identify any such rights.  Information
  58.482 +   on the procedures with respect to rights in RFC documents can be
  58.483 +   found in BCP 78 and BCP 79.
  58.484 +
  58.485 +   Copies of IPR disclosures made to the IETF Secretariat and any
  58.486 +   assurances of licenses to be made available, or the result of an
  58.487 +   attempt made to obtain a general license or permission for the use of
  58.488 +   such proprietary rights by implementers or users of this
  58.489 +   specification can be obtained from the IETF on-line IPR repository at
  58.490 +   http://www.ietf.org/ipr.
  58.491 +
  58.492 +   The IETF invites any interested party to bring to its attention any
  58.493 +   copyrights, patents or patent applications, or other proprietary
  58.494 +   rights that may cover technology that may be required to implement
  58.495 +   this standard.  Please address the information to the IETF at
  58.496 +   ietf-ipr@ietf.org.
  58.497 +
  58.498 +Acknowledgement
  58.499 +
  58.500 +   Funding for the RFC Editor function is provided by the IETF
  58.501 +   Administrative Support Activity (IASA).
  58.502 +
  58.503 +
  58.504 +
  58.505 +
  58.506 +
  58.507 +
  58.508 +
  58.509 +Zeilenga                    Standards Track                     [Page 9]
  58.510 +
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/docs/rfc/rfc4549.txt	Mon Sep 14 15:17:45 2009 +0900
    59.3 @@ -0,0 +1,1963 @@
    59.4 +
    59.5 +
    59.6 +
    59.7 +
    59.8 +
    59.9 +
   59.10 +Network Working Group                                   A. Melnikov, Ed.
   59.11 +Request for Comments: 4549                                    Isode Ltd.
   59.12 +Category: Informational                                        June 2006
   59.13 +
   59.14 +
   59.15 +       Synchronization Operations for Disconnected IMAP4 Clients
   59.16 +
   59.17 +Status of This Memo
   59.18 +
   59.19 +   This memo provides information for the Internet community.  It does
   59.20 +   not specify an Internet standard of any kind.  Distribution of this
   59.21 +   memo is unlimited.
   59.22 +
   59.23 +Copyright Notice
   59.24 +
   59.25 +   Copyright (C) The Internet Society (2006).
   59.26 +
   59.27 +Abstract
   59.28 +
   59.29 +   This document attempts to address some of the issues involved in
   59.30 +   building a disconnected IMAP4 client.  In particular, it deals with
   59.31 +   the issues of what might be called the "driver" portion of the
   59.32 +   synchronization tool: the portion of the code responsible for issuing
   59.33 +   the correct set of IMAP4 commands to synchronize the disconnected
   59.34 +   client in the way that is most likely to make the human who uses the
   59.35 +   disconnected client happy.
   59.36 +
   59.37 +   This note describes different strategies that can be used by
   59.38 +   disconnected clients and shows how to use IMAP protocol in order to
   59.39 +   minimize the time of the synchronization process.
   59.40 +
   59.41 +   This note also lists IMAP extensions that a server should implement
   59.42 +   in order to provide better synchronization facilities to disconnected
   59.43 +   clients.
   59.44 +
   59.45 +
   59.46 +
   59.47 +
   59.48 +
   59.49 +
   59.50 +
   59.51 +
   59.52 +
   59.53 +
   59.54 +
   59.55 +
   59.56 +
   59.57 +
   59.58 +
   59.59 +
   59.60 +
   59.61 +Melnikov                     Informational                      [Page 1]
   59.62 +
   59.63 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
   59.64 +
   59.65 +
   59.66 +Table of Contents
   59.67 +
   59.68 +   1. Introduction ....................................................3
   59.69 +      1.1. Conventions Used in This Document ..........................3
   59.70 +   2. Design Principles ...............................................3
   59.71 +   3. Overall Picture of Synchronization ..............................4
   59.72 +   4. Mailbox Synchronization Steps and Strategies ....................7
   59.73 +      4.1. Checking UID Validity ......................................7
   59.74 +      4.2. Synchronizing Local Changes with the Server ................8
   59.75 +           4.2.1. Uploading Messages to the Mailbox ...................8
   59.76 +           4.2.2. Optimizing "move" and "copy" Operations .............9
   59.77 +           4.2.3. Replaying Local Flag Changes .......................14
   59.78 +           4.2.4. Processing Mailbox Compression (EXPUNGE) Requests ..15
   59.79 +           4.2.5. Closing a Mailbox ..................................17
   59.80 +      4.3. Details of "Normal" Synchronization of a Single Mailbox ...18
   59.81 +           4.3.1. Discovering New Messages and Changes to Old
   59.82 +                  Messages ...........................................18
   59.83 +           4.3.2. Searching for "Interesting" Messages. ..............20
   59.84 +           4.3.3. Populating Cache with "Interesting" Messages. ......21
   59.85 +           4.3.4. User-Initiated Synchronization .....................22
   59.86 +      4.4. Special Case: Descriptor-Only Synchronization .............22
   59.87 +      4.5. Special Case: Fast New-Only Synchronization ...............23
   59.88 +      4.6. Special Case: Blind FETCH .................................23
   59.89 +   5. Implementation Considerations ..................................24
   59.90 +      5.1. Error Recovery during Playback ............................26
   59.91 +      5.2. Quality of Implementation Issues ..........................28
   59.92 +      5.3. Optimizations .............................................28
   59.93 +   6. IMAP Extensions That May Help ..................................30
   59.94 +      6.1. CONDSTORE Extension .......................................30
   59.95 +   7. Security Considerations ........................................33
   59.96 +   8. References .....................................................33
   59.97 +      8.1. Normative References ......................................33
   59.98 +      8.2. Informative References ....................................34
   59.99 +   9. Acknowledgements ...............................................34
  59.100 +
  59.101 +
  59.102 +
  59.103 +
  59.104 +
  59.105 +
  59.106 +
  59.107 +
  59.108 +
  59.109 +
  59.110 +
  59.111 +
  59.112 +
  59.113 +
  59.114 +
  59.115 +
  59.116 +
  59.117 +Melnikov                     Informational                      [Page 2]
  59.118 +
  59.119 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.120 +
  59.121 +
  59.122 +1.  Introduction
  59.123 +
  59.124 +   Several recommendations presented in this document are generally
  59.125 +   applicable to all types of IMAP clients.  However, this document
  59.126 +   tries to concentrate on disconnected mail clients [IMAP-MODEL].  It
  59.127 +   also suggests some IMAP extensions* that should be implemented by
  59.128 +   IMAP servers in order to make the life of disconnected clients
  59.129 +   easier.  In particular, the [UIDPLUS] extension was specifically
  59.130 +   designed to streamline certain disconnected operations, like
  59.131 +   expunging, uploading, and copying messages (see Sections 4.2.1,
  59.132 +   4.2.2.1, and 4.2.4).
  59.133 +
  59.134 +   Readers of this document are also strongly advised to read RFC 2683
  59.135 +   [RFC2683].
  59.136 +
  59.137 +   * Note that the functionality provided by the base IMAP protocol
  59.138 +     [IMAP4] is sufficient to perform basic synchronization.
  59.139 +
  59.140 +1.1.  Conventions Used in This Document
  59.141 +
  59.142 +   In examples, "C:" and "S:" indicate lines sent by the client and
  59.143 +   server, respectively.  Long lines in examples are broken for
  59.144 +   editorial clarity.
  59.145 +
  59.146 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  59.147 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  59.148 +   document are to be interpreted as described in RFC 2119 [KEYWORDS].
  59.149 +
  59.150 +   Let's call an IMAP command idempotent if the result of executing the
  59.151 +   command twice sequentially is the same as the result of executing the
  59.152 +   command just once.
  59.153 +
  59.154 +2.  Design Principles
  59.155 +
  59.156 +   All mailbox state or content information stored on the disconnected
  59.157 +   client should be viewed strictly as a cache of the state of the
  59.158 +   server.  The "master" state remains on the server, just as it would
  59.159 +   with an interactive IMAP4 client.  The one exception to this rule is
  59.160 +   that information about the state of the disconnected client's cache
  59.161 +   (the state includes flag changes while offline and during scheduled
  59.162 +   message uploads) remains on the disconnected client: that is, the
  59.163 +   IMAP4 server is not responsible for remembering the state of the
  59.164 +   disconnected IMAP4 client.
  59.165 +
  59.166 +   We assume that a disconnected client is a client that, for whatever
  59.167 +   reason, wants to minimize the length of time that it is "on the
  59.168 +   phone" to the IMAP4 server.  Often this will be because the client is
  59.169 +   using a dialup connection, possibly with very low bandwidth, but
  59.170 +
  59.171 +
  59.172 +
  59.173 +Melnikov                     Informational                      [Page 3]
  59.174 +
  59.175 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.176 +
  59.177 +
  59.178 +   sometimes it might just be that the human is in a hurry to catch an
  59.179 +   airplane, or some other event beyond our control.  Whatever the
  59.180 +   reason, we assume that we must make efficient use of the network
  59.181 +   connection, both in the usual sense (not generating spurious traffic)
  59.182 +   and in the sense that we would prefer not to have the connection
  59.183 +   sitting idle while the client and/or the server is performing
  59.184 +   strictly local computation or I/O.  Another, perhaps simpler way of
  59.185 +   stating this is that we assume that network connections are
  59.186 +   "expensive".
  59.187 +
  59.188 +   Practical experience with disconnected mail systems has shown that
  59.189 +   there is no single synchronization strategy that is appropriate for
  59.190 +   all cases.  Different humans have different preferences, and the same
  59.191 +   human's preference will vary depending both on external circumstance
  59.192 +   (how much of a hurry the human is in today) and on the value that the
  59.193 +   human places on the messages being transferred.  The point here is
  59.194 +   that there is no way that the synchronization program can guess
  59.195 +   exactly what the human wants to do, so the human will have to provide
  59.196 +   some guidance.
  59.197 +
  59.198 +   Taken together, the preceding two principles lead to the conclusion
  59.199 +   that the synchronization program must make its decisions based on
  59.200 +   some kind of guidance provided by the human, by selecting the
  59.201 +   appropriate options in the user interface or through some sort of
  59.202 +   configuration file.  Almost certainly, it should not pause for I/O
  59.203 +   with the human in the middle of the synchronization process.  The
  59.204 +   human will almost certainly have several different configurations for
  59.205 +   the synchronization program, for different circumstances.
  59.206 +
  59.207 +   Since a disconnected client has no way of knowing what changes might
  59.208 +   have occurred to the mailbox while it was disconnected, message
  59.209 +   numbers are not useful to a disconnected client.  All disconnected
  59.210 +   client operations should be performed using UIDs, so that the client
  59.211 +   can be sure that it and the server are talking about the same
  59.212 +   messages during the synchronization process.
  59.213 +
  59.214 +3.  Overall Picture of Synchronization
  59.215 +
  59.216 +   The basic strategy for synchronization is outlined below.  Note that
  59.217 +   the real strategy may vary from one application to another or may
  59.218 +   depend on a synchronization mode.
  59.219 +
  59.220 +   a) Process any "actions" that were pending on the client that were
  59.221 +      not associated with any mailbox.  (In particular sending messages
  59.222 +      composed offline with SMTP.  This is not part of IMAP
  59.223 +      synchronization, but it is mentioned here for completeness.)
  59.224 +
  59.225 +
  59.226 +
  59.227 +
  59.228 +
  59.229 +Melnikov                     Informational                      [Page 4]
  59.230 +
  59.231 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.232 +
  59.233 +
  59.234 +   b) Fetch the current list of "interesting" mailboxes.  (The
  59.235 +      disconnected client should allow the user to skip this step
  59.236 +      completely.)
  59.237 +
  59.238 +   c) "Client-to-server synchronization": for each IMAP "action" that
  59.239 +      was pending on the client, do the following:
  59.240 +
  59.241 +      1) If the action implies opening a new mailbox (any operation that
  59.242 +         operates on messages), open the mailbox.  Check its UID
  59.243 +         validity value (see Section 4.1 for more details) returned in
  59.244 +         the UIDVALIDITY response code.  If the UIDVALIDITY value
  59.245 +         returned by the server differs, the client MUST empty the local
  59.246 +         cache of the mailbox and remove any pending "actions" that
  59.247 +         refer to UIDs in that mailbox (and consider them failed).  Note
  59.248 +         that this doesn't affect actions performed on client-generated
  59.249 +         fake UIDs (see Section 5).
  59.250 +
  59.251 +      2) Perform the action.  If the action is to delete a mailbox
  59.252 +         (DELETE), make sure that the mailbox is closed first (see also
  59.253 +         Section 3.4.12 of [RFC2683]).
  59.254 +
  59.255 +   d) "Server-to-client synchronization": for each mailbox that requires
  59.256 +      synchronization, do the following:
  59.257 +
  59.258 +      1) Check the mailbox UIDVALIDITY (see Section 4.1 for more
  59.259 +         details) with SELECT/EXAMINE/STATUS.
  59.260 +
  59.261 +         If UIDVALIDITY value returned by the server differs, the client
  59.262 +         MUST
  59.263 +
  59.264 +         * empty the local cache of that mailbox;
  59.265 +         * remove any pending "actions" that refer to UIDs in that
  59.266 +           mailbox and consider them failed; and
  59.267 +         * skip step 2-II.
  59.268 +
  59.269 +      2) Fetch the current "descriptors";
  59.270 +
  59.271 +         I)  Discover new messages.
  59.272 +
  59.273 +         II) Discover changes to old messages.
  59.274 +
  59.275 +      3) Fetch the bodies of any "interesting" messages that the client
  59.276 +         doesn't already have.
  59.277 +
  59.278 +   e) Close all open mailboxes not required for further operations (if
  59.279 +      staying online) or disconnect all open connections (if going
  59.280 +      offline).
  59.281 +
  59.282 +
  59.283 +
  59.284 +
  59.285 +Melnikov                     Informational                      [Page 5]
  59.286 +
  59.287 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.288 +
  59.289 +
  59.290 +   Terms used:
  59.291 +
  59.292 +   "Actions" are queued requests that were made by the human to the
  59.293 +   client's Mail User Agent (MUA) software while the client was
  59.294 +   disconnected.
  59.295 +
  59.296 +   We define "descriptors" as a set of IMAP4 FETCH data items.
  59.297 +   Conceptually, a message's descriptor is that set of information that
  59.298 +   allows the synchronization program to decide what protocol actions
  59.299 +   are necessary to bring the local cache to the desired state for this
  59.300 +   message; since this decision is really up to the human, this
  59.301 +   information probably includes at least a few header fields intended
  59.302 +   for human consumption.  Exactly what will constitute a descriptor
  59.303 +   depends on the client implementation.  At a minimum, the descriptor
  59.304 +   contains the message's UID and FLAGS.  Other likely candidates are
  59.305 +   the RFC822.SIZE, RFC822.HEADER, BODYSTRUCTURE, or ENVELOPE data
  59.306 +   items.
  59.307 +
  59.308 +   Comments:
  59.309 +
  59.310 +   1) The list of actions should be ordered.  For example, if the human
  59.311 +      deletes message A1 in mailbox A, then expunges mailbox A, and then
  59.312 +      deletes message A2 in mailbox A, the human will expect that
  59.313 +      message A1 is gone and that message A2 is still present but is now
  59.314 +      deleted.
  59.315 +
  59.316 +      By processing all the actions before proceeding with
  59.317 +      synchronization, we avoid having to compensate for the local MUA's
  59.318 +      changes to the server's state.  That is, once we have processed
  59.319 +      all the pending actions, the steps that the client must take to
  59.320 +      synchronize itself will be the same no matter where the changes to
  59.321 +      the server's state originated.
  59.322 +
  59.323 +   2) Steps a and b can be performed in parallel.  Alternatively, step a
  59.324 +      can be performed after d.
  59.325 +
  59.326 +   3) On step b, the set of "interesting" mailboxes pretty much has to
  59.327 +      be determined by the human.  What mailboxes belong to this set may
  59.328 +      vary between different IMAP4 sessions with the same server,
  59.329 +      client, and human.  An interesting mailbox can be a mailbox
  59.330 +      returned by LSUB command (see Section 6.3.9 of [IMAP4]).  The
  59.331 +      special mailbox "INBOX" SHOULD be in the default set of mailboxes
  59.332 +      that the client considers interesting.  However, providing the
  59.333 +      ability to ignore INBOX for a particular session or client may be
  59.334 +      valuable for some mail filtering strategies.
  59.335 +
  59.336 +
  59.337 +
  59.338 +
  59.339 +
  59.340 +
  59.341 +Melnikov                     Informational                      [Page 6]
  59.342 +
  59.343 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.344 +
  59.345 +
  59.346 +   4) On step d-2-II, the client also finds out about changes to the
  59.347 +      flags of messages that the client already has in its local cache,
  59.348 +      and about messages in the local cache that no longer exist on the
  59.349 +      server (i.e., messages that have been expunged).
  59.350 +
  59.351 +   5) "Interesting" messages are those messages that the synchronization
  59.352 +      program thinks the human wants to have cached locally, based on
  59.353 +      the configuration and the data retrieved in step b.
  59.354 +
  59.355 +   6) A disconnected IMAP client is a special case of an IMAP client, so
  59.356 +      it MUST be able to handle any "unexpected" unsolicited responses,
  59.357 +      like EXISTS and EXPUNGE, at any time.  The disconnected client MAY
  59.358 +      ignore EXPUNGE response during "client-to-server" synchronization
  59.359 +      phase (step c).
  59.360 +
  59.361 +   The rest of this discussion will focus primarily on the
  59.362 +   synchronization issues for a single mailbox.
  59.363 +
  59.364 +4.  Mailbox Synchronization Steps and Strategies
  59.365 +
  59.366 +4.1.  Checking UID Validity
  59.367 +
  59.368 +   The "UID validity" of a mailbox is a number returned in an
  59.369 +   UIDVALIDITY response code in an OK untagged response at mailbox
  59.370 +   selection time.  The UID validity value changes between sessions when
  59.371 +   UIDs fail to persist between sessions.
  59.372 +
  59.373 +   Whenever the client selects a mailbox, the client must compare the
  59.374 +   returned UID validity value with the value stored in the local cache.
  59.375 +   If the UID validity values differ, the UIDs in the client's cache are
  59.376 +   no longer valid.  The client MUST then empty the local cache of that
  59.377 +   mailbox and remove any pending "actions" that refer to UIDs in that
  59.378 +   mailbox.  The client MAY also issue a warning to the human.  The
  59.379 +   client MUST NOT cancel any scheduled uploads (i.e., APPENDs) for the
  59.380 +   mailbox.
  59.381 +
  59.382 +   Note that UIDVALIDITY is not only returned on a mailbox selection.
  59.383 +   The COPYUID and APPENDUID response codes defined in the [UIDPLUS]
  59.384 +   extension (see also 4.2.2) and the UIDVALIDITY STATUS response data
  59.385 +   item also contain a UIDVALIDITY value for some other mailbox.  The
  59.386 +   client SHOULD behave as described in the previous paragraph (but it
  59.387 +   should act on the other mailbox's cache), no matter how it obtained
  59.388 +   the UIDVALIDITY value.
  59.389 +
  59.390 +
  59.391 +
  59.392 +
  59.393 +
  59.394 +
  59.395 +
  59.396 +
  59.397 +Melnikov                     Informational                      [Page 7]
  59.398 +
  59.399 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.400 +
  59.401 +
  59.402 +4.2.  Synchronizing Local Changes with the Server
  59.403 +
  59.404 +4.2.1.  Uploading Messages to the Mailbox
  59.405 +
  59.406 +   Two of the most common examples of operations resulting in message
  59.407 +   uploads are:
  59.408 +
  59.409 +   1) Saving a draft message
  59.410 +
  59.411 +   2) Copying a message between remote mailboxes on two different IMAP
  59.412 +      servers or a local mailbox and a remote mailbox.
  59.413 +
  59.414 +   Message upload is performed with the APPEND command.  A message
  59.415 +   scheduled to be uploaded has no UID associated with it, as all UIDs
  59.416 +   are assigned by the server.  The APPEND command will effectively
  59.417 +   associate a UID with the uploaded message that can be stored in the
  59.418 +   local cache for future reference.  However, [IMAP4] doesn't describe
  59.419 +   a simple mechanism to discover the message UID by just performing the
  59.420 +   APPEND command.  In order to discover the UID, the client can do one
  59.421 +   of the following:
  59.422 +
  59.423 +   1) Remove the uploaded message from cache.  Then, use the mechanism
  59.424 +      described in 4.3 to fetch the information about the uploaded
  59.425 +      message as if it had been uploaded by some other client.
  59.426 +
  59.427 +   2) Try to fetch header information as described in 4.2.2 in order to
  59.428 +      find a message that corresponds to the uploaded message.  One
  59.429 +      strategy for doing this is described in 4.2.2.
  59.430 +
  59.431 +   Case 1 describes a not particularly smart client.
  59.432 +
  59.433 +      C: A003 APPEND Drafts (\Seen $MDNSent) {310}
  59.434 +      S: + Ready for literal data
  59.435 +      C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  59.436 +      C: From: Fred Foobar <foobar@blt.example.COM>
  59.437 +      C: Subject: afternoon meeting
  59.438 +      C: To: mooch@owatagu.siam.edu
  59.439 +      C: Message-Id: <B27397-0100000@blt.example.COM>
  59.440 +      C: MIME-Version: 1.0
  59.441 +      C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.442 +      C:
  59.443 +      C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  59.444 +      C:
  59.445 +      S: A003 OK APPEND Completed
  59.446 +
  59.447 +   Fortunately, there is a simpler way to discover the message UID in
  59.448 +   the presence of the [UIDPLUS] extension:
  59.449 +
  59.450 +
  59.451 +
  59.452 +
  59.453 +Melnikov                     Informational                      [Page 8]
  59.454 +
  59.455 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.456 +
  59.457 +
  59.458 +      C: A003 APPEND Drafts (\Seen $MDNSent) {310}
  59.459 +      S: + Ready for literal data
  59.460 +      C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  59.461 +      C: From: Fred Foobar <foobar@blt.example.COM>
  59.462 +      C: Subject: afternoon meeting
  59.463 +      C: To: mooch@owatagu.siam.edu
  59.464 +      C: Message-Id: <B27397-0100000@blt.example.COM>
  59.465 +      C: MIME-Version: 1.0
  59.466 +      C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.467 +      C:
  59.468 +      C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  59.469 +      C:
  59.470 +      S: A003 OK [APPENDUID 1022843275 77712] APPEND completed
  59.471 +
  59.472 +   The UID of the appended message is the second parameter of APPENDUID
  59.473 +   response code.
  59.474 +
  59.475 +4.2.2.  Optimizing "move" and "copy" Operations
  59.476 +
  59.477 +   Practical experience with IMAP and other mailbox access protocols
  59.478 +   that support multiple mailboxes suggests that moving a message from
  59.479 +   one mailbox to another is an extremely common operation.
  59.480 +
  59.481 +4.2.2.1.  Moving a Message between Two Mailboxes on the Same Server
  59.482 +
  59.483 +   In IMAP4, a "move" operation between two mailboxes on the same server
  59.484 +   is really a combination of a COPY operation and a STORE +FLAGS
  59.485 +   (\Deleted) operation.  This makes good protocol sense for IMAP, but
  59.486 +   it leaves a simple-minded disconnected client in the silly position
  59.487 +   of deleting and possibly expunging its cached copy of a message, then
  59.488 +   fetching an identical copy via the network.
  59.489 +
  59.490 +   However, the presence of the UIDPLUS extension in the server can
  59.491 +   help:
  59.492 +
  59.493 +      C: A001 UID COPY 567,414 "Interesting Messages"
  59.494 +      S: A001 OK [COPYUID 1022843275 414,567 5:6] Completed
  59.495 +
  59.496 +   This tells the client that the message with UID 414 in the current
  59.497 +   mailbox was successfully copied to the mailbox "Interesting Messages"
  59.498 +   and was given the UID 5, and that the message with UID 567 was given
  59.499 +   the UID 6.
  59.500 +
  59.501 +   In the absence of UIDPLUS extension support in the server, the
  59.502 +   following trick can be used.  By including the Message-ID: header and
  59.503 +   the INTERNALDATE data item as part of the descriptor, the client can
  59.504 +   check the descriptor of a "new" message against messages that are
  59.505 +   already in its cache and avoid fetching the extra copy.  Of course,
  59.506 +
  59.507 +
  59.508 +
  59.509 +Melnikov                     Informational                      [Page 9]
  59.510 +
  59.511 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.512 +
  59.513 +
  59.514 +   it's possible that the cost of checking to see if the message is
  59.515 +   already in the local cache may exceed the cost of just fetching it,
  59.516 +   so this technique should not be used blindly.  If the MUA implements
  59.517 +   a "move" command, it makes special provisions to use this technique
  59.518 +   when it knows that a copy/delete sequence is the result of a "move"
  59.519 +   command.
  59.520 +
  59.521 +   Note that servers are not required (although they are strongly
  59.522 +   encouraged with "SHOULD language") to preserve INTERNALDATE when
  59.523 +   copying messages.
  59.524 +
  59.525 +   Also note that since it's theoretically possible for this algorithm
  59.526 +   to find the wrong message (given sufficiently malignant Message-ID
  59.527 +   headers), implementers should provide a way to disable this
  59.528 +   optimization, both permanently and on a message-by-message basis.
  59.529 +
  59.530 +   Example 1: Copying a message in the absence of UIDPLUS extension.
  59.531 +
  59.532 +   At some point in time the client has fetched the source message and
  59.533 +   some information was cached:
  59.534 +
  59.535 +      C: C021 UID FETCH <uids> (BODY.PEEK[] INTERNALDATE FLAGS)
  59.536 +      ...
  59.537 +      S: * 27 FETCH (UID 123 INTERNALDATE "31-May-2002 05:26:59 -0600"
  59.538 +          FLAGS (\Draft $MDNSent) BODY[] {1036}
  59.539 +      S: ...
  59.540 +      S: Message-Id: <20040903110856.22a127cd@chardonnay>
  59.541 +      S: ...
  59.542 +      S: ...message body...
  59.543 +      S: )
  59.544 +      ...
  59.545 +      S: C021 OK fetch completed
  59.546 +
  59.547 +   Later on, the client decides to copy the message:
  59.548 +
  59.549 +      C: C035 UID COPY 123 "Interesting Messages"
  59.550 +      S: C035 OK Completed
  59.551 +
  59.552 +   As the server hasn't provided the COPYUID response code, the client
  59.553 +   tries the optimization described above:
  59.554 +
  59.555 +      C: C036 SELECT "Interesting Messages"
  59.556 +      ...
  59.557 +      C: C037 UID SEARCH ON 31-May-2002 HEADER
  59.558 +          "Message-Id" "20040903110856.22a127cd@chardonnay"
  59.559 +      S: SEARCH 12368
  59.560 +      S: C037 OK completed
  59.561 +
  59.562 +
  59.563 +
  59.564 +
  59.565 +Melnikov                     Informational                     [Page 10]
  59.566 +
  59.567 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.568 +
  59.569 +
  59.570 +   Note that if the server has returned multiple UIDs in the SEARCH
  59.571 +   response, the client MUST NOT use any of the returned UID.
  59.572 +
  59.573 +4.2.2.2.  Moving a Message from a Remote Mailbox to a Local
  59.574 +
  59.575 +   Moving a message from a remote mailbox to a local is done with FETCH
  59.576 +   (that includes FLAGS and INTERNALDATE) followed by UID STORE <uid>
  59.577 +   +FLAGS.SILENT (\Deleted):
  59.578 +
  59.579 +      C: A003 UID FETCH 123 (BODY.PEEK[] INTERNALDATE FLAGS)
  59.580 +      S: * 27 FETCH (UID 123 INTERNALDATE "31-May-2002 05:26:59 -0600"
  59.581 +          FLAGS (\Seen $MDNSent) BODY[]
  59.582 +      S: ...message body...
  59.583 +      S: )
  59.584 +      S: A003 OK UID FETCH completed
  59.585 +      C: A004 UID STORE <uid> +FLAGS.SILENT (\Deleted)
  59.586 +      S: A004 STORE completed
  59.587 +
  59.588 +   Note that there is no reason to fetch the message during
  59.589 +   synchronization if it's already in the client's cache.  Also, the
  59.590 +   client SHOULD preserve delivery date in the local cache.
  59.591 +
  59.592 +4.2.2.3.  Moving a Message from a Local Mailbox to a Remote
  59.593 +
  59.594 +   Moving a message from a local mailbox to a remote is done with
  59.595 +   APPEND:
  59.596 +
  59.597 +   C: A003 APPEND Drafts (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
  59.598 +       {310}
  59.599 +   S: + Ready for literal data
  59.600 +   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  59.601 +   C: From: Fred Foobar <foobar@blt.example.COM>
  59.602 +   C: Subject: afternoon meeting
  59.603 +   C: To: mooch@owatagu.siam.edu
  59.604 +   C: Message-Id: <B27397-0100000@blt.example.COM>
  59.605 +   C: MIME-Version: 1.0
  59.606 +   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.607 +   C:
  59.608 +   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  59.609 +   C:
  59.610 +   S: A003 OK [APPENDUID 1022843275 77712] completed
  59.611 +
  59.612 +   The client SHOULD specify the delivery date from the local cache in
  59.613 +   the APPEND.
  59.614 +
  59.615 +   If the [LITERAL+] extension is available, the client can save a
  59.616 +   round-trip*:
  59.617 +
  59.618 +
  59.619 +
  59.620 +
  59.621 +Melnikov                     Informational                     [Page 11]
  59.622 +
  59.623 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.624 +
  59.625 +
  59.626 +   C: A003 APPEND Drafts (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
  59.627 +       {310+}
  59.628 +   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  59.629 +   C: From: Fred Foobar <foobar@blt.example.COM>
  59.630 +   C: Subject: afternoon meeting
  59.631 +   C: To: mooch@owatagu.siam.edu
  59.632 +   C: Message-Id: <B27397-0100000@blt.example.COM>
  59.633 +   C: MIME-Version: 1.0
  59.634 +   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.635 +   C:
  59.636 +   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  59.637 +   C:
  59.638 +   S: A003 OK [APPENDUID 1022843275 77712] completed
  59.639 +
  59.640 +   * Note that there is a risk that the server will reject the message
  59.641 +     due to its size.  If this happens, the client will waste bandwidth
  59.642 +     transferring the whole message.  If the client wouldn't have used
  59.643 +     the LITERAL+, this could have been avoided:
  59.644 +
  59.645 +   C: A003 APPEND Drafts (\Seen $MDNSent) "31-May-2004 05:26:59 -0600"
  59.646 +       {16777215}
  59.647 +   S: A003 NO Sorry, message is too big
  59.648 +
  59.649 +4.2.2.4.  Moving a Message between Two Mailboxes on Different Servers
  59.650 +
  59.651 +   Moving a message between two mailbox on two different servers is a
  59.652 +   combination of the operations described in 4.2.2.2 followed by the
  59.653 +   operations described in 4.2.2.3.
  59.654 +
  59.655 +4.2.2.5.  Uploading Multiple Messages to a Remote Mailbox with
  59.656 +          MULTIAPPEND
  59.657 +
  59.658 +   When there is a need to upload multiple messages to a remote mailbox
  59.659 +   (e.g., as per 4.2.2.3), the presence of certain IMAP extensions may
  59.660 +   significantly improve performance.  One of them is [MULTIAPPEND].
  59.661 +
  59.662 +   For some mail stores, opening a mailbox for appending might be
  59.663 +   expensive.  [MULTIAPPEND] tells the server to open the mailbox once
  59.664 +   (instead of opening and closing it "n" times per "n" messages to be
  59.665 +   uploaded) and to keep it open while a group of messages is being
  59.666 +   uploaded to the server.
  59.667 +
  59.668 +   Also, if the server supports both [MULTIAPPEND] and [LITERAL+]
  59.669 +   extensions, the entire upload is accomplished in a single
  59.670 +   command/response round-trip.
  59.671 +
  59.672 +
  59.673 +
  59.674 +
  59.675 +
  59.676 +
  59.677 +Melnikov                     Informational                     [Page 12]
  59.678 +
  59.679 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.680 +
  59.681 +
  59.682 +   Note: Client implementers should be aware that [MULTIAPPEND] performs
  59.683 +   append of multiple messages atomically.  This means, for example, if
  59.684 +   there is not enough space to save "n"-th message (or the message has
  59.685 +   invalid structure and is rejected by the server) after successful
  59.686 +   upload of "n-1" messages, the whole upload operation fails, and no
  59.687 +   message will be saved in the mailbox.  Although this behavior might
  59.688 +   be desirable in certain situations, it might not be what you want.
  59.689 +   Otherwise, the client should use the regular APPEND command (Section
  59.690 +   4.2.2.3), possibly utilizing the [LITERAL+] extension.  See also
  59.691 +   Section 5.1 for discussions about error recovery.
  59.692 +
  59.693 +   Note: MULTIAPPEND can be used together with the UIDPLUS extension in
  59.694 +   a way similar to what was described in Section 4.2.1.  [MULTIAPPEND]
  59.695 +   extends the syntax of the APPENDUID response code to allow for
  59.696 +   multiple message UIDs in the second parameter.
  59.697 +
  59.698 +   Example 2:
  59.699 +
  59.700 +   This example demonstrates the use of MULTIAPPEND together with
  59.701 +   UIDPLUS (synchronization points where the client waits for
  59.702 +   confirmations from the server are marked with "<--->"):
  59.703 +
  59.704 +   C: A003 APPEND Jan-2002 (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
  59.705 +       {310}
  59.706 +   <--->
  59.707 +   S: + Ready for literal data
  59.708 +   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  59.709 +   C: From: Fred Foobar <foobar@blt.example.COM>
  59.710 +   C: Subject: afternoon meeting
  59.711 +   C: To: mooch@owatagu.siam.edu
  59.712 +   C: Message-Id: <B27397-0100000@blt.example.COM>
  59.713 +   C: MIME-Version: 1.0
  59.714 +   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.715 +   C:
  59.716 +   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  59.717 +   C:  (\Seen) " 1-Jun-2002 22:43:04 -0800" {286}
  59.718 +   <--->
  59.719 +   S: + Ready for literal data
  59.720 +   C: Date: Mon, 7 Feb 1994 22:43:04 -0800 (PST)
  59.721 +   C: From: Joe Mooch <mooch@OWaTaGu.siam.EDU>
  59.722 +   C: Subject: Re: afternoon meeting
  59.723 +   C: To: foobar@blt.example.com
  59.724 +   C: Message-Id: <a0434793874930@OWaTaGu.siam.EDU>
  59.725 +   C: MIME-Version: 1.0
  59.726 +   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.727 +   C:
  59.728 +   C: 3:30 is fine with me.
  59.729 +   C:
  59.730 +
  59.731 +
  59.732 +
  59.733 +Melnikov                     Informational                     [Page 13]
  59.734 +
  59.735 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.736 +
  59.737 +
  59.738 +   S: A003 OK [APPENDUID 1022843275 77712,77713] completed
  59.739 +
  59.740 +   The upload takes 3 round-trips.
  59.741 +
  59.742 +   Example 3:
  59.743 +
  59.744 +   In this example, Example 2 was modified for the case when the server
  59.745 +   supports MULTIAPPEND, LITERAL+, and UIDPLUS.  The upload takes only 1
  59.746 +   round-trip.
  59.747 +
  59.748 +   C: A003 APPEND Jan-2002 (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
  59.749 +       {310+}
  59.750 +   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  59.751 +   C: From: Fred Foobar <foobar@blt.example.COM>
  59.752 +   C: Subject: afternoon meeting
  59.753 +   C: To: mooch@owatagu.siam.edu
  59.754 +   C: Message-Id: <B27397-0100000@blt.example.COM>
  59.755 +   C: MIME-Version: 1.0
  59.756 +   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.757 +   C:
  59.758 +   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
  59.759 +   C:  (\Seen) " 1-Jun-2002 22:43:04 -0800" {286+}
  59.760 +   C: Date: Mon, 7 Feb 1994 22:43:04 -0800 (PST)
  59.761 +   C: From: Joe Mooch <mooch@OWaTaGu.siam.EDU>
  59.762 +   C: Subject: Re: afternoon meeting
  59.763 +   C: To: foobar@blt.example.com
  59.764 +   C: Message-Id: <a0434793874930@OWaTaGu.siam.EDU>
  59.765 +   C: MIME-Version: 1.0
  59.766 +   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  59.767 +   C:
  59.768 +   C: 3:30 is fine with me.
  59.769 +   C:
  59.770 +   S: A003 OK [APPENDUID 1022843275 77712,77713] completed
  59.771 +
  59.772 +4.2.3.  Replaying Local Flag Changes
  59.773 +
  59.774 +   The disconnected client uses the STORE command to synchronize local
  59.775 +   flag state with the server.  The disconnected client SHOULD use
  59.776 +   +FLAGS.SILENT or -FLAGS.SILENT in order to set or unset flags
  59.777 +   modified by the user while offline.  The FLAGS form MUST NOT be used,
  59.778 +   as there is a risk that this will overwrite flags on the server that
  59.779 +   have been changed by some other client.
  59.780 +
  59.781 +   Example 4:
  59.782 +
  59.783 +   For the message with UID 15, the disconnected client stores the
  59.784 +   following flags \Seen and $Highest.  The flags were modified on the
  59.785 +   server by some other client: \Seen, \Answered, and $Highest.  While
  59.786 +
  59.787 +
  59.788 +
  59.789 +Melnikov                     Informational                     [Page 14]
  59.790 +
  59.791 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.792 +
  59.793 +
  59.794 +   offline, the user requested that the $Highest flags be removed and
  59.795 +   that the \Deleted flag be added.  The flag synchronization sequence
  59.796 +   for the message should look like:
  59.797 +
  59.798 +      C: A001 UID STORE 15 +FLAGS.SILENT (\Deleted)
  59.799 +      S: A001 STORE completed
  59.800 +      C: A002 UID STORE 15 -FLAGS.SILENT ($Highest)
  59.801 +      S: A002 STORE completed
  59.802 +
  59.803 +   If the disconnected client is able to store an additional binary
  59.804 +   state information (or a piece of information that can take a value
  59.805 +   from a predefined set of values) in the local cache of an IMAP
  59.806 +   mailbox or in a local mailbox (e.g., message priority), and if the
  59.807 +   server supports storing of arbitrary keywords, the client MUST use
  59.808 +   keywords to store this state on the server.
  59.809 +
  59.810 +   Example 5:
  59.811 +
  59.812 +   Imagine a speculative mail client that can mark a message as one of
  59.813 +   work-related ($Work), personal ($Personal), or spam ($Spam).  In
  59.814 +   order to mark a message as personal, the client issues:
  59.815 +
  59.816 +      C: A001 UID STORE 15 +FLAGS.SILENT ($Personal)
  59.817 +      S: A001 STORE completed
  59.818 +      C: A002 UID STORE 15 -FLAGS.SILENT ($Work $Spam)
  59.819 +      S: A002 STORE completed
  59.820 +
  59.821 +   In order to mark the message as not work, not personal and not spam,
  59.822 +   the client issues:
  59.823 +
  59.824 +      C: A003 UID STORE 15 -FLAGS.SILENT ($Personal $Work $Spam)
  59.825 +      S: A003 STORE completed
  59.826 +
  59.827 +4.2.4.  Processing Mailbox Compression (EXPUNGE) Requests
  59.828 +
  59.829 +   A naive disconnected client implementation that supports compressing
  59.830 +   a mailbox while offline may decide to issue an EXPUNGE command to the
  59.831 +   server in order to expunge messages marked \Deleted.  The problem
  59.832 +   with this command during synchronization is that it permanently
  59.833 +   erases all messages with the \Deleted flag set, i.e., even those
  59.834 +   messages that were marked as \Deleted on the server while the user
  59.835 +   was offline.  Doing this might result in an unpleasant surprise for
  59.836 +   the user.
  59.837 +
  59.838 +   Fortunately the [UIDPLUS] extension can help in this case as well.
  59.839 +   The extension introduces UID EXPUNGE command, that, unlike EXPUNGE,
  59.840 +   takes a UID set parameter, that lists UIDs of all messages that can
  59.841 +   be expunged.  When processing this command the server erases only
  59.842 +
  59.843 +
  59.844 +
  59.845 +Melnikov                     Informational                     [Page 15]
  59.846 +
  59.847 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.848 +
  59.849 +
  59.850 +   messages with \Deleted flag listed in the UID list.  Thus, messages
  59.851 +   not listed in the UID set will not be expunged even if they have the
  59.852 +   \Deleted flag set.
  59.853 +
  59.854 +   Example 6:
  59.855 +
  59.856 +   While the user was offline, 3 messages with UIDs 7, 27, and 65 were
  59.857 +   marked \Deleted when the user requested to compress the open mailbox.
  59.858 +   Another client marked a message \Deleted on the server (UID 34).
  59.859 +   During synchronization, the disconnected client issues:
  59.860 +
  59.861 +      C: A001 UID EXPUNGE 7,27,65
  59.862 +      S: * ... EXPUNGE
  59.863 +      S: * ... EXPUNGE
  59.864 +      S: * ... EXPUNGE
  59.865 +      S: A001 UID EXPUNGE completed
  59.866 +
  59.867 +   If another client issues UID SEARCH DELETED command (to find all
  59.868 +   messages with the \Deleted flag) before and after the UID EXPUNGE, it
  59.869 +   will get:
  59.870 +
  59.871 +   Before:
  59.872 +
  59.873 +      C: B001 UID SEARCH DELETED
  59.874 +      S: * SEARCH 65 34 27 7
  59.875 +      S: B001 UID SEARCH completed
  59.876 +
  59.877 +   After:
  59.878 +
  59.879 +      C: B002 UID SEARCH DELETED
  59.880 +      S: * SEARCH 34
  59.881 +      S: B002 UID SEARCH completed
  59.882 +
  59.883 +   In the absence of the [UIDPLUS] extension, the following sequence of
  59.884 +   commands can be used as an approximation.  Note: It's possible for
  59.885 +   another client to mark additional messages as deleted while this
  59.886 +   sequence is being performed.  In this case, these additional messages
  59.887 +   will be expunged as well.
  59.888 +
  59.889 +   1) Find all messages marked \Deleted on the server.
  59.890 +
  59.891 +      C: A001 UID SEARCH DELETED
  59.892 +      S: * SEARCH 65 34 27 7
  59.893 +      S: A001 UID SEARCH completed
  59.894 +
  59.895 +   2) Find all messages that must not be erased (for the previous
  59.896 +      example the list will consist of the message with UID 34).
  59.897 +
  59.898 +
  59.899 +
  59.900 +
  59.901 +Melnikov                     Informational                     [Page 16]
  59.902 +
  59.903 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.904 +
  59.905 +
  59.906 +   3) Temporarily remove \Deleted flag on all messages found in step 2.
  59.907 +
  59.908 +      C: A002 UID STORE 34 -FLAGS.SILENT (\Deleted)
  59.909 +      S: A002 UID STORE completed
  59.910 +
  59.911 +   4) Expunge the mailbox.
  59.912 +
  59.913 +      C: A003 EXPUNGE
  59.914 +      S: * 20 EXPUNGE
  59.915 +      S: * 7 EXPUNGE
  59.916 +      S: * 1 EXPUNGE
  59.917 +      S: A003 EXPUNGE completed
  59.918 +
  59.919 +      Here, the message with UID 7 has message number 1, with UID 27 has
  59.920 +      message number 7, and with UID 65 has message number 20.
  59.921 +
  59.922 +   5) Restore \Deleted flag on all messages found when performing step
  59.923 +      2.
  59.924 +
  59.925 +      C: A004 UID STORE 34 +FLAGS.SILENT (\Deleted)
  59.926 +      S: A004 UID STORE completed
  59.927 +
  59.928 +4.2.5.  Closing a Mailbox
  59.929 +
  59.930 +   When the disconnected client has to close a mailbox, it should not
  59.931 +   use the CLOSE command, because CLOSE does a silent EXPUNGE.  (Section
  59.932 +   4.2.4 explains why EXPUNGE should not be used by a disconnected
  59.933 +   client.)  It is safe to use CLOSE only if the mailbox was opened with
  59.934 +   EXAMINE.
  59.935 +
  59.936 +   If the mailbox was opened with SELECT, the client can use one of the
  59.937 +   following commands to implicitly close the mailbox and prevent the
  59.938 +   silent expunge:
  59.939 +
  59.940 +   1) UNSELECT - This is a command described in [UNSELECT] that works as
  59.941 +      CLOSE, but doesn't cause the silent EXPUNGE.  This command is
  59.942 +      supported by the server if it reports UNSELECT in its CAPABILITY
  59.943 +      list.
  59.944 +
  59.945 +   2) SELECT <another_mailbox> - SELECT causes implicit CLOSE without
  59.946 +      EXPUNGE.
  59.947 +
  59.948 +   3) If the client intends to issue LOGOUT after closing the mailbox,
  59.949 +      it may just issue LOGOUT, because LOGOUT causes implicit CLOSE
  59.950 +      without EXPUNGE as well.
  59.951 +
  59.952 +   4) SELECT <non_existing_mailbox> - If the client knows a mailbox that
  59.953 +      doesn't exist or can't be selected, it MAY SELECT it.
  59.954 +
  59.955 +
  59.956 +
  59.957 +Melnikov                     Informational                     [Page 17]
  59.958 +
  59.959 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
  59.960 +
  59.961 +
  59.962 +   If the client opened the mailbox with SELECT and just wants to avoid
  59.963 +   implicit EXPUNGE without closing the mailbox, it may also use the
  59.964 +   following:
  59.965 +
  59.966 +   5) EXAMINE <mailbox> - Reselect the same mailbox in read-only mode.
  59.967 +
  59.968 +4.3.  Details of "Normal" Synchronization of a Single Mailbox
  59.969 +
  59.970 +   The most common form of synchronization is where the human trusts the
  59.971 +   integrity of the client's copy of the state of a particular mailbox
  59.972 +   and simply wants to bring the client's cache up to date so that it
  59.973 +   accurately reflects the mailbox's current state on the server.
  59.974 +
  59.975 +4.3.1.  Discovering New Messages and Changes to Old Messages
  59.976 +
  59.977 +   Let <lastseenuid> represent the highest UID that the client knows
  59.978 +   about in this mailbox.  Since UIDs are allocated in strictly
  59.979 +   ascending order, this is simply the UID of the last message in the
  59.980 +   mailbox that the client knows about.  Let <lastseenuid+1> represent
  59.981 +   <lastseenuid>'s UID plus one.  Let <descriptors> represent a list
  59.982 +   consisting of all the FETCH data item items that the implementation
  59.983 +   considers part of the descriptor; at a minimum this is just the FLAGS
  59.984 +   data item, but it usually also includes BODYSTRUCTURE and
  59.985 +   RFC822.SIZE.  At this step, <descriptors> SHOULD NOT include RFC822.
  59.986 +
  59.987 +   With no further information, the client can issue the following two
  59.988 +   commands:
  59.989 +
  59.990 +      tag1 UID FETCH <lastseenuid+1>:* <descriptors>
  59.991 +      tag2 UID FETCH 1:<lastseenuid> FLAGS
  59.992 +
  59.993 +   The first command will request some information about "new" messages
  59.994 +   (i.e., messages received by the server since the last
  59.995 +   synchronization).  It will also allow the client to build a message
  59.996 +   number to UID map (only for new messages).  The second command allows
  59.997 +   the client to
  59.998 +
  59.999 +      1) update cached flags for old messages;
 59.1000 +
 59.1001 +      2) find out which old messages got expunged; and
 59.1002 +
 59.1003 +      3) build a mapping between message numbers and UIDs (for old
 59.1004 +         messages).
 59.1005 +
 59.1006 +   The order here is significant.  We want the server to start returning
 59.1007 +   the list of new message descriptors as fast as it can, so that the
 59.1008 +   client can start issuing more FETCH commands, so we start out by
 59.1009 +   asking for the descriptors of all the messages we know the client
 59.1010 +
 59.1011 +
 59.1012 +
 59.1013 +Melnikov                     Informational                     [Page 18]
 59.1014 +
 59.1015 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1016 +
 59.1017 +
 59.1018 +   cannot possibly have cached yet.  The second command fetches the
 59.1019 +   information we need to determine what changes may have occurred to
 59.1020 +   messages that the client already has cached.  Note that the former
 59.1021 +   command should only be issued if the UIDNEXT value cached by the
 59.1022 +   client differs from the one returned by the server.  Once the client
 59.1023 +   has issued these two commands, there's nothing more the client can do
 59.1024 +   with this mailbox until the responses to the first command start
 59.1025 +   arriving.  A clever synchronization program might use this time to
 59.1026 +   fetch its local cache state from disk or to start the process of
 59.1027 +   synchronizing another mailbox.
 59.1028 +
 59.1029 +   The following is an example of the first FETCH:
 59.1030 +
 59.1031 +   C: A011 UID fetch 131:* (FLAGS BODYSTRUCTURE INTERNALDATE
 59.1032 +       RFC822.SIZE)
 59.1033 +
 59.1034 +   Note 1: The first FETCH may result in the server's sending a huge
 59.1035 +   volume of data.  A smart disconnected client should use message
 59.1036 +   ranges (see also Section 3.2.1.2 of [RFC2683]), so that the user is
 59.1037 +   able to execute a different operation between fetching information
 59.1038 +   for a group of new messages.
 59.1039 +
 59.1040 +   Example 7:
 59.1041 +
 59.1042 +   Knowing the new UIDNEXT returned by the server on SELECT or EXAMINE
 59.1043 +   (<uidnext>), the client can split the UID range
 59.1044 +   <lastseenuid+1>:<uidnext> into groups, e.g., 100 messages.  After
 59.1045 +   that, the client can issue:
 59.1046 +
 59.1047 +      C: A011 UID fetch <lastseenuid+1>:<lastseenuid+100>
 59.1048 +          (FLAGS BODYSTRUCTURE INTERNALDATE RFC822.SIZE)
 59.1049 +      ...
 59.1050 +      C: A012 UID fetch <lastseenuid+101>:<lastseenuid+200>
 59.1051 +          (FLAGS BODYSTRUCTURE INTERNALDATE RFC822.SIZE)
 59.1052 +      ...
 59.1053 +      ...
 59.1054 +      C: A0FF UID fetch <lastseenuid+901>:<uidnext>
 59.1055 +          (FLAGS BODYSTRUCTURE INTERNALDATE RFC822.SIZE)
 59.1056 +
 59.1057 +   Note that unless a SEARCH command is issued, it is impossible to
 59.1058 +   determine how many messages will fall into a subrange, as UIDs are
 59.1059 +   not necessarily contiguous.
 59.1060 +
 59.1061 +   Note 2: The client SHOULD ignore any unsolicited EXPUNGE responses
 59.1062 +   received during the first FETCH command.  EXPUNGE responses contain
 59.1063 +   message numbers that are useless to a client that doesn't have the
 59.1064 +   message-number-to-UID translation table.
 59.1065 +
 59.1066 +
 59.1067 +
 59.1068 +
 59.1069 +Melnikov                     Informational                     [Page 19]
 59.1070 +
 59.1071 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1072 +
 59.1073 +
 59.1074 +   The second FETCH command will result in zero or more untagged fetch
 59.1075 +   responses.  Each response will have a corresponding UID FETCH data
 59.1076 +   item.  All messages that didn't have a matching untagged FETCH
 59.1077 +   response MUST be removed from the local cache.
 59.1078 +
 59.1079 +   For example, if the <lastseenuid> had a value 15000 and the local
 59.1080 +   cache contained 3 messages with the UIDs 12, 777, and 14999,
 59.1081 +   respectively, then after receiving the following responses from the
 59.1082 +   server, the client must remove the message with UID 14999 from its
 59.1083 +   local cache.
 59.1084 +
 59.1085 +      S: * 1 FETCH (UID 12 FLAGS (\Seen))
 59.1086 +      S: * 2 FETCH (UID 777 FLAGS (\Answered \Deleted))
 59.1087 +
 59.1088 +   Note 3: If the client is not interested in flag changes (i.e., the
 59.1089 +   client only wants to know which old messages are still on the
 59.1090 +   server), the second FETCH command can be substituted with:
 59.1091 +
 59.1092 +      tag2 UID SEARCH UID 1:<lastseenuid>
 59.1093 +
 59.1094 +   This command will generate less traffic.  However, an implementor
 59.1095 +   should be aware that in order to build the mapping table from message
 59.1096 +   numbers to UIDs, the output of the SEARCH command MUST be sorted
 59.1097 +   first, because there is no requirement for a server to return UIDs in
 59.1098 +   SEARCH response in any particular order.
 59.1099 +
 59.1100 +4.3.2.  Searching for "Interesting" Messages.
 59.1101 +
 59.1102 +   This step is performed entirely on the client (from the information
 59.1103 +   received in the step described in 4.3.1), entirely on the server, or
 59.1104 +   on some combination of both.  The decision on what is an
 59.1105 +   "interesting" message is up to the client software and the human.
 59.1106 +   One easy criterion that should probably be implemented in any client
 59.1107 +   is whether the message is "too big" for automatic retrieval, where
 59.1108 +   "too big" is a parameter defined in the client's configuration.
 59.1109 +
 59.1110 +   Another commonly used criterion is the age of a message.  For
 59.1111 +   example, the client may choose to download only messages received in
 59.1112 +   the last week (in this case, <date> would be today's date minus 7
 59.1113 +   days):
 59.1114 +
 59.1115 +      tag3 UID SEARCH UID <uidset> SINCE <date>
 59.1116 +
 59.1117 +   Keep in mind that a date search disregards time and time zone.  The
 59.1118 +   client can avoid doing this search if it specified INTERNALDATE in
 59.1119 +   <descriptors> on the step described in 4.3.1.  If the client did, it
 59.1120 +   can perform the local search on its message cache.
 59.1121 +
 59.1122 +
 59.1123 +
 59.1124 +
 59.1125 +Melnikov                     Informational                     [Page 20]
 59.1126 +
 59.1127 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1128 +
 59.1129 +
 59.1130 +   At this step, the client also decides what kind of information about
 59.1131 +   a particular message to fetch from the server.  In particular, even
 59.1132 +   for a message that is considered "too big", the client MAY choose to
 59.1133 +   fetch some part(s) of it.  For example, if the message is a
 59.1134 +   multipart/mixed containing a text part and a MPEG attachment, there
 59.1135 +   is no reason for the client not to fetch the text part.  The decision
 59.1136 +   of which part should or should not be fetched can be based on the
 59.1137 +   information received in the BODYSTRUCTURE FETCH response data item
 59.1138 +   (i.e., if BODYSTRUCTURE was included in <descriptors> on the step
 59.1139 +   described in 4.3.1).
 59.1140 +
 59.1141 +4.3.3.  Populating Cache with "Interesting" Messages.
 59.1142 +
 59.1143 +   Once the client has found out which messages are "interesting", it
 59.1144 +   can start issuing appropriate FETCH commands for "interesting"
 59.1145 +   messages or parts thereof.
 59.1146 +
 59.1147 +   Note that fetching a message into the disconnected client's local
 59.1148 +   cache does NOT imply that the human has (or even will) read the
 59.1149 +   message.  Thus, the synchronization program for a disconnected client
 59.1150 +   should always be careful to use the .PEEK variants of the FETCH data
 59.1151 +   items that implicitly set the \Seen flag.
 59.1152 +
 59.1153 +   Once the last descriptor has arrived and the last FETCH command has
 59.1154 +   been issued, the client simply needs to process the incoming fetch
 59.1155 +   items and use them to update the local message cache.
 59.1156 +
 59.1157 +   In order to avoid deadlock problems, the client must give processing
 59.1158 +   of received messages priority over issuing new FETCH commands during
 59.1159 +   this synchronization process.  This may necessitate temporary local
 59.1160 +   queuing of FETCH requests that cannot be issued without causing a
 59.1161 +   deadlock.  In order to achieve the best use of the "expensive"
 59.1162 +   network connection, the client will almost certainly need to pay
 59.1163 +   careful attention to any flow-control information that it can obtain
 59.1164 +   from the underlying transport connection (usually a TCP connection).
 59.1165 +
 59.1166 +   Note: The requirement stated in the previous paragraph might result
 59.1167 +   in an unpleasant user experience, if followed blindly.  For example,
 59.1168 +   the user might be unwilling to wait for the client to finish
 59.1169 +   synchronization before starting to process the user's requests.  A
 59.1170 +   smart disconnected client should allow the user to perform requested
 59.1171 +   operations in between IMAP commands that are part of the
 59.1172 +   synchronization process.  See also Note 1 in Section 4.3.1.
 59.1173 +
 59.1174 +
 59.1175 +
 59.1176 +
 59.1177 +
 59.1178 +
 59.1179 +
 59.1180 +
 59.1181 +Melnikov                     Informational                     [Page 21]
 59.1182 +
 59.1183 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1184 +
 59.1185 +
 59.1186 +   Example 8:
 59.1187 +
 59.1188 +   After fetching a message BODYSTRUCTURE, the client discovers a
 59.1189 +   complex MIME message.  Then, it decides to fetch MIME headers of the
 59.1190 +   nested MIME messages and some body parts.
 59.1191 +
 59.1192 +   C: A011 UID fetch 11 (BODYSTRUCTURE)
 59.1193 +   S: ...
 59.1194 +   C: A012 UID fetch 11 (BODY[HEADER] BODY[1.MIME] BODY[1.1.MIME]
 59.1195 +       BODY[1.2.MIME] BODY[2.MIME] BODY[3.MIME] BODY[4.MIME]
 59.1196 +       BODY[5.MIME] BODY[6.MIME] BODY[7.MIME] BODY[8.MIME] BODY[9.MIME]
 59.1197 +       BODY[10.MIME] BODY[11.MIME] BODY[12.MIME] BODY[13.MIME]
 59.1198 +       BODY[14.MIME] BODY[15.MIME] BODY[16.MIME] BODY[17.MIME]
 59.1199 +       BODY[18.MIME] BODY[19.MIME] BODY[20.MIME] BODY[21.MIME])
 59.1200 +   S: ...
 59.1201 +   C: A013 UID fetch 11 (BODY[1.1] BODY[1.2])
 59.1202 +   S: ...
 59.1203 +   C: A014 UID fetch 11 (BODY[3] BODY[4] BODY[5] BODY[6] BODY[7] BODY[8]
 59.1204 +       BODY[9] BODY[10] BODY[11] BODY[13] BODY[14] BODY[15] BODY[16]
 59.1205 +       BODY[21])
 59.1206 +   S: ...
 59.1207 +
 59.1208 +4.3.4.  User-Initiated Synchronization
 59.1209 +
 59.1210 +   After the client has finished the main synchronization process as
 59.1211 +   described in Sections 4.3.1-4.3.3, the user may optionally request
 59.1212 +   additional synchronization steps while the client is still online.
 59.1213 +   This is not any different from the process described in Sections
 59.1214 +   4.3.2 and 4.3.3.
 59.1215 +
 59.1216 +   Typical examples are:
 59.1217 +
 59.1218 +    1) fetch all messages selected in UI.
 59.1219 +    2) fetch all messages marked as \Flagged on the server.
 59.1220 +
 59.1221 +4.4.  Special Case: Descriptor-Only Synchronization
 59.1222 +
 59.1223 +   For some mailboxes, fetching the descriptors might be the entire
 59.1224 +   synchronization step.  Practical experience with IMAP has shown that
 59.1225 +   a certain class of mailboxes (e.g., "archival" mailboxes) are used
 59.1226 +   primarily for long-term storage of important messages that the human
 59.1227 +   wants to have instantly available on demand but does not want
 59.1228 +   cluttering up the disconnected client's cache at any other time.
 59.1229 +   Messages in this kind of mailbox would be fetched exclusively by
 59.1230 +   explicit actions queued by the local MUA.  Thus, the only
 59.1231 +   synchronization desirable on this kind of mailbox is fetching enough
 59.1232 +   descriptor information for the user to be able to identify messages
 59.1233 +   for subsequent download.
 59.1234 +
 59.1235 +
 59.1236 +
 59.1237 +Melnikov                     Informational                     [Page 22]
 59.1238 +
 59.1239 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1240 +
 59.1241 +
 59.1242 +   Special mailboxes that receive messages from a high volume, low
 59.1243 +   priority mailing list might also be in this category, at least when
 59.1244 +   the human is in a hurry.
 59.1245 +
 59.1246 +4.5.  Special Case: Fast New-Only Synchronization
 59.1247 +
 59.1248 +   In some cases, the human might be in such a hurry that he or she
 59.1249 +   doesn't care about changes to old messages, just about new messages.
 59.1250 +   In this case, the client can skip the UID FETCH command that obtains
 59.1251 +   the flags and UIDs for old messages (1:<lastseenuid>).
 59.1252 +
 59.1253 +4.6.  Special Case: Blind FETCH
 59.1254 +
 59.1255 +   In some cases, the human may know (for whatever reason) that he or
 59.1256 +   she always wants to fetch any new messages in a particular mailbox,
 59.1257 +   unconditionally.  In this case, the client can just fetch the
 59.1258 +   messages themselves, rather than just the descriptors, by using a
 59.1259 +   command like:
 59.1260 +
 59.1261 +      tag1 UID FETCH <lastseenuid+1>:* (FLAGS BODY.PEEK[])
 59.1262 +
 59.1263 +   Note that this example ignores the fact that the messages can be
 59.1264 +   arbitrary long.  The disconnected client MUST always check for
 59.1265 +   message size before downloading, unless explicitly told otherwise.  A
 59.1266 +   well-behaved client should instead use something like the following:
 59.1267 +
 59.1268 +   1) Issue "tag1 UID FETCH <lastseenuid+1>:* (FLAGS RFC822.SIZE)".
 59.1269 +
 59.1270 +   2) From the message sizes returned in step 1, construct UID set
 59.1271 +      <required_messages>.
 59.1272 +
 59.1273 +   3) Issue "tag2 UID FETCH <required_messages> (BODY.PEEK[])".
 59.1274 +
 59.1275 +   or
 59.1276 +
 59.1277 +   1) Issue "tag1 UID FETCH <lastseenuid+1>:* (FLAGS)".
 59.1278 +
 59.1279 +   2) Construct UID set <old_uids> from the responses of step 1.
 59.1280 +
 59.1281 +   3) Issue "tag2 SEARCH UID <old_uids> SMALLER <message_limit>".
 59.1282 +      Construct UID set <required_messages> from the result of the
 59.1283 +      SEARCH command.
 59.1284 +
 59.1285 +   4) Issue "tag3 UID FETCH <required_messages> (BODY.PEEK[])".
 59.1286 +
 59.1287 +
 59.1288 +
 59.1289 +
 59.1290 +
 59.1291 +
 59.1292 +
 59.1293 +Melnikov                     Informational                     [Page 23]
 59.1294 +
 59.1295 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1296 +
 59.1297 +
 59.1298 +   or
 59.1299 +
 59.1300 +   1) Issue "tag1 UID FETCH <lastseenuid+1>:* (FLAGS
 59.1301 +      BODY.PEEK[]<0.<length>>)", where <length> should be replaced with
 59.1302 +      the maximal message size the client is willing to download.
 59.1303 +
 59.1304 +      Note: In response to such a command, the server will only return
 59.1305 +      partial data if the message is longer than <length>.  It will
 59.1306 +      return the full message data for any message whose size is smaller
 59.1307 +      than or equal to <length>.  In the former case, the client will
 59.1308 +      not be able to extract the full MIME structure of the message from
 59.1309 +      the truncated data, so the client should include BODYSTRUCTURE in
 59.1310 +      the UID FETCH command as well.
 59.1311 +
 59.1312 +5.  Implementation Considerations
 59.1313 +
 59.1314 +   Below are listed some common implementation pitfalls that should be
 59.1315 +   considered when implementing a disconnected client.
 59.1316 +
 59.1317 +   1) Implementing fake UIDs on the client.
 59.1318 +
 59.1319 +      A message scheduled to be uploaded has no UID, as UIDs are
 59.1320 +      selected by the server.  The client may implement fake UIDs
 59.1321 +      internally in order to reference not-yet-uploaded messages in
 59.1322 +      further operations.  (For example, a message could be scheduled to
 59.1323 +      be uploaded, but subsequently marked as deleted or copied to
 59.1324 +      another mailbox).  Here, the client MUST NOT under any
 59.1325 +      circumstances send these fake UIDs to the server.  Also, client
 59.1326 +      implementers should be reminded that according to [IMAP4] a UID is
 59.1327 +      a 32-bit unsigned integer excluding 0.  So, both 4294967295 and
 59.1328 +      2147483648 are valid UIDs, and 0 and -1 are both invalid.  Some
 59.1329 +      disconnected mail clients have been known to send negative numbers
 59.1330 +      (e.g., "-1") as message UIDs to servers during synchronization.
 59.1331 +
 59.1332 +      Situation 1: The user starts composing a new message, edits it,
 59.1333 +      saves it, continues to edit it, and saves it again.
 59.1334 +
 59.1335 +      A disconnected client may record in its replay log (log of
 59.1336 +      operations to be replayed on the server during synchronization)
 59.1337 +      the sequence of operations as shown below.  For the purpose of
 59.1338 +      this situation, we assume that all draft messages are stored in
 59.1339 +      the mailbox called Drafts on an IMAP server.  We will also use the
 59.1340 +      following conventions:  <old_uid> is the UID of the intermediate
 59.1341 +      version of the draft when it was saved for the first time.  This
 59.1342 +      is a fake UID generated on the client.  <new_uid> is the UID of
 59.1343 +      the final version of the draft.  This is another fake UID
 59.1344 +      generated on the client.
 59.1345 +
 59.1346 +
 59.1347 +
 59.1348 +
 59.1349 +Melnikov                     Informational                     [Page 24]
 59.1350 +
 59.1351 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1352 +
 59.1353 +
 59.1354 +      1) APPEND Drafts (\Seen $MDNSent \Drafts) {<nnn>}
 59.1355 +         ...first version of the message follows...
 59.1356 +
 59.1357 +      2) APPEND Drafts (\Seen $MDNSent \Drafts) {<mmm>}
 59.1358 +         ...final version of the message follows...
 59.1359 +
 59.1360 +      3) STORE <old_uid> +FLAGS (\Deleted)
 59.1361 +
 59.1362 +      Step 1 corresponds to the first attempt to save the draft message,
 59.1363 +      step 2 corresponds to the second attempt to save the draft
 59.1364 +      message, and step 3 deletes the first version of the draft message
 59.1365 +      saved in step 1.
 59.1366 +
 59.1367 +      A naive disconnected client may send the command in step 3 without
 59.1368 +      replacing the fake client generated <old_uid> with the value
 59.1369 +      returned by the server in step 1.  A server will probably reject
 59.1370 +      this command, which will make the client believe that the
 59.1371 +      synchronization sequence has failed.
 59.1372 +
 59.1373 +   2) Section 5.1 discusses common implementation errors related to
 59.1374 +      error recovery during playback.
 59.1375 +
 59.1376 +   3) Don't assume that the disconnected client is the only client used
 59.1377 +      by the user.
 59.1378 +
 59.1379 +      Situation 2: Some clients may use the \Deleted flag as an
 59.1380 +      indicator that the message should not appear in the user's view.
 59.1381 +      Usage of the \Deleted flag for this purpose is not safe, as other
 59.1382 +      clients (e.g., online clients) might EXPUNGE the mailbox at any
 59.1383 +      time.
 59.1384 +
 59.1385 +   4) Beware of data dependencies between synchronization operations.
 59.1386 +
 59.1387 +      It might be very tempting for a client writer to perform some
 59.1388 +      optimizations on the playback log.  Such optimizations might
 59.1389 +      include removing redundant operations (for example, see
 59.1390 +      optimization 2 in Section 5.3), or their reordering.
 59.1391 +
 59.1392 +      It is not always safe to reorder or remove redundant operations
 59.1393 +      during synchronization because some operations may have
 59.1394 +      dependencies (as Situation 3 demonstrates).  So, if in doubt,
 59.1395 +      don't do this.
 59.1396 +
 59.1397 +      Situation 3: The user copies a message out of a mailbox and then
 59.1398 +      deletes the mailbox.
 59.1399 +
 59.1400 +
 59.1401 +
 59.1402 +
 59.1403 +
 59.1404 +
 59.1405 +Melnikov                     Informational                     [Page 25]
 59.1406 +
 59.1407 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1408 +
 59.1409 +
 59.1410 +         C: A001 SELECT Old-Mail
 59.1411 +         S: ...
 59.1412 +         C: A002 UID COPY 111 ToDo
 59.1413 +         S: A002 OK [COPYUID 1022843345 111 94] Copy completed
 59.1414 +         ...
 59.1415 +         C: A015 CLOSE
 59.1416 +         S: A015 OK Completed
 59.1417 +         C: A016 DELETE Old-Mail
 59.1418 +         S: A016 OK Mailbox deletion completed successfully
 59.1419 +
 59.1420 +      If the client performs DELETE (tag A016) first and COPY (tag A002)
 59.1421 +      second, then the COPY fails.  Also, the message that the user so
 59.1422 +      carefully copied into another mailbox has been lost.
 59.1423 +
 59.1424 +5.1.  Error Recovery during Playback
 59.1425 +
 59.1426 +   Error recovery during synchronization is one of the trickiest parts
 59.1427 +   to get right.  Below, we will discuss certain error conditions and
 59.1428 +   suggest possible choices for handling them.
 59.1429 +
 59.1430 +   1) Lost connection to the server.
 59.1431 +
 59.1432 +      The client MUST remember the current position in the playback
 59.1433 +      (replay) log and replay it starting from the interrupted operation
 59.1434 +      (the last command issued by the client, but not acknowledged by
 59.1435 +      the server) the next time it successfully connects to the same
 59.1436 +      server.  If the connection was lost while executing a non-
 59.1437 +      idempotent IMAP command (see the definition in Section 1), then
 59.1438 +      when the client is reconnected, it MUST make sure that the
 59.1439 +      interrupted command was indeed not executed.  If it wasn't
 59.1440 +      executed, the client must restart playback from the interrupted
 59.1441 +      command, otherwise from the following command.
 59.1442 +
 59.1443 +      Upon reconnect, care must be taken in order to properly reapply
 59.1444 +      logical operations that are represented by multiple IMAP commands,
 59.1445 +      e.g., UID EXPUNGE emulation when UID EXPUNGE is not supported by
 59.1446 +      the server (see Section 4.2.4).
 59.1447 +
 59.1448 +      Once the client detects that the connection to the server was
 59.1449 +      lost, it MUST stop replaying its log.  There are existing
 59.1450 +      disconnected clients that, to the great annoyance of users, pop up
 59.1451 +      an error dialog for each and every playback operation that fails.
 59.1452 +
 59.1453 +   2) Copying/appending messages to a mailbox that doesn't exist.  (The
 59.1454 +      server advertises this condition by sending the TRYCREATE response
 59.1455 +      code in the tagged NO response to the APPEND or COPY command.)
 59.1456 +
 59.1457 +
 59.1458 +
 59.1459 +
 59.1460 +
 59.1461 +Melnikov                     Informational                     [Page 26]
 59.1462 +
 59.1463 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1464 +
 59.1465 +
 59.1466 +      The user should be advised about the situation and be given one of
 59.1467 +      the following choices:
 59.1468 +
 59.1469 +      a) Try to recreate a mailbox.
 59.1470 +      b) Copy/upload messages to another mailbox.
 59.1471 +      c) Skip copy/upload.
 59.1472 +      d) Abort replay.
 59.1473 +
 59.1474 +   3) Copying messages from a mailbox that doesn't exist, or renaming or
 59.1475 +      getting/changing ACLs [ACL] on a mailbox that doesn't exist:
 59.1476 +
 59.1477 +      a) Skip operation.
 59.1478 +      b) Abort replay.
 59.1479 +
 59.1480 +   4) Deleting mailboxes or deleting/expunging messages that no longer
 59.1481 +      exist.
 59.1482 +
 59.1483 +      This is actually is not an error and should be ignored by the
 59.1484 +      client.
 59.1485 +
 59.1486 +   5) Performing operations on messages that no longer exist.
 59.1487 +
 59.1488 +      a) Skip operation.
 59.1489 +      b) Abort replay.
 59.1490 +
 59.1491 +      In the case of changing flags on an expunged message, the client
 59.1492 +      should silently ignore the error.
 59.1493 +
 59.1494 +   Note 1: Several synchronization operations map to multiple IMAP
 59.1495 +   commands (for example, "move" described in 4.2.2).  The client must
 59.1496 +   guarantee atomicity of each such multistep operation.  For example,
 59.1497 +   when performing a "move" between two mailboxes on the same server, if
 59.1498 +   the server is unable to copy messages, the client MUST NOT attempt to
 59.1499 +   set the \Deleted flag on the messages being copied, let alone expunge
 59.1500 +   them.  However, the client MAY consider that move operation to have
 59.1501 +   succeeded even if the server was unable to set the \Deleted flag on
 59.1502 +   copied messages.
 59.1503 +
 59.1504 +   Note 2: Many synchronization operations have data dependencies.  A
 59.1505 +   failed operation must cause all dependent operations to fail as well.
 59.1506 +   The client should check this and MUST NOT try to perform all
 59.1507 +   dependent operations blindly (unless the user corrected the original
 59.1508 +   problem).  For example, a message may be scheduled to be appended to
 59.1509 +   a mailbox on the server and later on the appended message may be
 59.1510 +   copied to another mailbox.  If the APPEND operation fails, the client
 59.1511 +   must not attempt to COPY the failed message later on.  (See also
 59.1512 +   Section 5, Situation 3).
 59.1513 +
 59.1514 +
 59.1515 +
 59.1516 +
 59.1517 +Melnikov                     Informational                     [Page 27]
 59.1518 +
 59.1519 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1520 +
 59.1521 +
 59.1522 +5.2.  Quality of Implementation Issues
 59.1523 +
 59.1524 +   Below, some quality of implementation issues are listed for
 59.1525 +   disconnected clients.  They will help to write a disconnected client
 59.1526 +   that works correctly, performs synchronization as quickly as possible
 59.1527 +   (and thus can make the user happier as well as save her some money),
 59.1528 +   and minimizes the server load:
 59.1529 +
 59.1530 +   1) Don't lose information.
 59.1531 +
 59.1532 +      No matter how smart your client is in other areas, if it loses
 59.1533 +      information, users will get very upset.
 59.1534 +
 59.1535 +   2) Don't do work unless explicitly asked.  Be flexible.  Ask all
 59.1536 +      questions BEFORE starting synchronization, if possible.
 59.1537 +
 59.1538 +   3) Minimize traffic.
 59.1539 +
 59.1540 +      The client MUST NOT issue a command if the client already received
 59.1541 +      the required information from the server.
 59.1542 +
 59.1543 +      The client MUST make use of UIDPLUS extension if it is supported
 59.1544 +      by the server.
 59.1545 +
 59.1546 +      See also optimization 1 in Section 5.3.
 59.1547 +
 59.1548 +   4) Minimize the number of round-trips.
 59.1549 +
 59.1550 +      Round-trips kill performance, especially on links with high
 59.1551 +      latency.  Sections 4.2.2.5 and 5.2 give some advice on how to
 59.1552 +      minimize the number of round-trips.
 59.1553 +
 59.1554 +      See also optimization 1 in Section 5.3.
 59.1555 +
 59.1556 +5.3.  Optimizations
 59.1557 +
 59.1558 +   Some useful optimizations are described in this section.  A
 59.1559 +   disconnected client that supports the recommendations listed below
 59.1560 +   will give the user a more pleasant experience.
 59.1561 +
 59.1562 +   1) The initial OK or PREAUTH responses may contain the CAPABILITY
 59.1563 +      response code as described in Section 7.1 of [IMAP4].  This
 59.1564 +      response code gives the same information as returned by the
 59.1565 +      CAPABILITY command*.  A disconnected client that pays attention to
 59.1566 +      this response code can avoid sending CAPABILITY command and will
 59.1567 +      save a round-trip.
 59.1568 +
 59.1569 +
 59.1570 +
 59.1571 +
 59.1572 +
 59.1573 +Melnikov                     Informational                     [Page 28]
 59.1574 +
 59.1575 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1576 +
 59.1577 +
 59.1578 +      * Note: Some servers report in the CAPABILITY response code
 59.1579 +        extensions that are only relevant in unauthenticated state or in
 59.1580 +        all states.  Such servers usually send another CAPABILITY
 59.1581 +        response code upon successful authentication using LOGIN or
 59.1582 +        AUTHENTICATE command (that negotiates no security layer; see
 59.1583 +        Section 6.2.2 of [IMAP4]).  The CAPABILITY response code sent
 59.1584 +        upon successful LOGIN/AUTHENTICATE might be different from the
 59.1585 +        CAPABILITY response code in the initial OK response, as
 59.1586 +        extensions only relevant for unauthenticated state will not be
 59.1587 +        advertised, and some additional extensions available only in
 59.1588 +        authenticated and/or selected state will be.
 59.1589 +
 59.1590 +   Example 9:
 59.1591 +
 59.1592 +   S: * OK [CAPABILITY IMAP4REV1 LOGIN-REFERRALS STARTTLS
 59.1593 +       AUTH=DIGEST-MD5 AUTH=SRP] imap.example.com ready
 59.1594 +   C: 2 authenticate DIGEST-MD5
 59.1595 +   S: 2 OK [CAPABILITY IMAP4REV1 IDLE NAMESPACE MAILBOX-REFERRALS SCAN
 59.1596 +       SORT THREAD=REFERENCES THREAD=ORDEREDSUBJECT MULTIAPPEND]
 59.1597 +       User authenticated (no layer)
 59.1598 +
 59.1599 +   2) An advanced disconnected client may choose to optimize its replay
 59.1600 +      log.  For example, there might be some operations that are
 59.1601 +      redundant (the list is not complete):
 59.1602 +
 59.1603 +      a) an EXPUNGE followed by another EXPUNGE or CLOSE;
 59.1604 +      b) changing flags (other than the \Deleted flag) on a message that
 59.1605 +         gets immediately expunged;
 59.1606 +      c) opening and closing the same mailbox.
 59.1607 +
 59.1608 +   When optimizing, be careful about data dependencies between commands.
 59.1609 +   For example, if the client is wishing to optimize (see case b, above)
 59.1610 +
 59.1611 +      tag1 UID STORE <uid1> +FLAGS (\Deleted)
 59.1612 +      ...
 59.1613 +      tag2 UID STORE <uid1> +FLAGS (\Flagged)
 59.1614 +      ...
 59.1615 +      tag3 UID COPY <uid1> "Backup"
 59.1616 +      ...
 59.1617 +      tag4 UID EXPUNGE <uid1>
 59.1618 +
 59.1619 +   it can't remove the second UID STORE command because the message is
 59.1620 +   being copied before it gets expunged.
 59.1621 +
 59.1622 +   In general, it might be a good idea to keep mailboxes open during
 59.1623 +   synchronization (see case c above), if possible.  This can be more
 59.1624 +   easily achieved in conjunction with optimization 3 described below.
 59.1625 +
 59.1626 +
 59.1627 +
 59.1628 +
 59.1629 +Melnikov                     Informational                     [Page 29]
 59.1630 +
 59.1631 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1632 +
 59.1633 +
 59.1634 +   3) Perform some synchronization steps in parallel, if possible.
 59.1635 +
 59.1636 +      Several synchronization steps don't depend on each other and thus
 59.1637 +      can be performed in parallel.  Because the server machine is
 59.1638 +      usually more powerful than the client machine and can perform some
 59.1639 +      operations in parallel, this may speed up the total time of
 59.1640 +      synchronization.
 59.1641 +
 59.1642 +      In order to achieve such parallelization, the client will have to
 59.1643 +      open more than one connection to the same server.  Client writers
 59.1644 +      should not forget about non-trivial cost associated with
 59.1645 +      establishing a TCP connection and performing an authentication.
 59.1646 +      The disconnected client MUST NOT use one connection per mailbox.
 59.1647 +      In most cases, it is sufficient to have two connections.  The
 59.1648 +      disconnected client SHOULD avoid selecting the same mailbox in
 59.1649 +      more than one connection; see Section 3.1.1 of [RFC2683] for more
 59.1650 +      details.
 59.1651 +
 59.1652 +      Any mailbox synchronization MUST start with checking the
 59.1653 +      UIDVALIDITY as described in Section 4.1 of this document.  The
 59.1654 +      client MAY use STATUS command to check UID Validity of a non-
 59.1655 +      selected mailbox.  This is preferable to opening many connections
 59.1656 +      to the same server to perform synchronization of multiple
 59.1657 +      mailboxes simultaneously.  As described in Section 5.3.10 of
 59.1658 +      [IMAP4], this SHOULD NOT be used on the selected mailbox.
 59.1659 +
 59.1660 +6.  IMAP Extensions That May Help
 59.1661 +
 59.1662 +   The following extensions can save traffic and/or the number of
 59.1663 +   round-trips:
 59.1664 +
 59.1665 +   1) The use of [UIDPLUS] is discussed in Sections 4.1, 4.2.1, 4.2.2.1
 59.1666 +      and 4.2.4.
 59.1667 +
 59.1668 +   2) The use of the MULTIAPPEND and LITERAL+ extensions for uploading
 59.1669 +      messages is discussed in Section 4.2.2.5.
 59.1670 +
 59.1671 +   3) Use the CONDSTORE extension (see Section 6.1) for quick flag
 59.1672 +      resynchronization.
 59.1673 +
 59.1674 +6.1.  CONDSTORE Extension
 59.1675 +
 59.1676 +   An advanced disconnected mail client should use the [CONDSTORE]
 59.1677 +   extension when it is supported by the server.  The client must cache
 59.1678 +   the value from HIGHESTMODSEQ OK response code received on mailbox
 59.1679 +   opening and update it whenever the server sends MODSEQ FETCH data
 59.1680 +   items.
 59.1681 +
 59.1682 +
 59.1683 +
 59.1684 +
 59.1685 +Melnikov                     Informational                     [Page 30]
 59.1686 +
 59.1687 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1688 +
 59.1689 +
 59.1690 +   If the client receives NOMODSEQ OK untagged response instead of
 59.1691 +   HIGHESTMODSEQ, it MUST remove the last known HIGHESTMODSEQ value from
 59.1692 +   its cache and follow the more general instructions in Section 3.
 59.1693 +
 59.1694 +   When the client opens the mailbox for synchronization, it first
 59.1695 +   compares UIDVALIDITY as described in step d-1 in Section 3.  If the
 59.1696 +   cached UIDVALIDITY value matches the one returned by the server, the
 59.1697 +   client MUST compare the cached value of HIGHESTMODSEQ with the one
 59.1698 +   returned by the server.  If the cached HIGHESTMODSEQ value also
 59.1699 +   matches the one returned by the server, then the client MUST NOT
 59.1700 +   fetch flags for cached messages, as they hasn't changed.  If the
 59.1701 +   value on the server is higher than the cached one, the client MAY use
 59.1702 +   "SEARCH MODSEQ <cached-value>" to find all messages with flags
 59.1703 +   changed since the last time the client was online and had the mailbox
 59.1704 +   opened.  Alternatively, the client MAY use "FETCH 1:* (FLAGS)
 59.1705 +   (CHANGEDSINCE <cached-value>)".  The latter operation combines
 59.1706 +   searching for changed messages and fetching new information.
 59.1707 +
 59.1708 +   In all cases, the client still needs to fetch information about new
 59.1709 +   messages (if requested by the user) as well as discover which
 59.1710 +   messages have been expunged.
 59.1711 +
 59.1712 +   Step d ("Server-to-client synchronization") in Section 4 in the
 59.1713 +   presence of the CONDSTORE extension is amended as follows:
 59.1714 +
 59.1715 +   d) "Server-to-client synchronization" - For each mailbox that
 59.1716 +      requires synchronization, do the following:
 59.1717 +
 59.1718 +      1a) Check the mailbox UIDVALIDITY (see section 4.1 for more
 59.1719 +          details) with SELECT/EXAMINE/STATUS.
 59.1720 +
 59.1721 +          If the UIDVALIDITY value returned by the server differs, the
 59.1722 +          client MUST
 59.1723 +
 59.1724 +          * empty the local cache of that mailbox;
 59.1725 +          * "forget" the cached HIGHESTMODSEQ value for the mailbox;
 59.1726 +          * remove any pending "actions" that refer to UIDs in that
 59.1727 +            mailbox (note that this doesn't affect actions performed on
 59.1728 +            client-generated fake UIDs; see Section 5); and
 59.1729 +          * skip steps 1b and 2-II;
 59.1730 +
 59.1731 +      1b) Check the mailbox HIGHESTMODSEQ.  If the cached value is the
 59.1732 +          same as the one returned by the server, skip fetching message
 59.1733 +          flags on step 2-II, i.e., the client only has to find out
 59.1734 +          which messages got expunged.
 59.1735 +
 59.1736 +
 59.1737 +
 59.1738 +
 59.1739 +
 59.1740 +
 59.1741 +Melnikov                     Informational                     [Page 31]
 59.1742 +
 59.1743 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1744 +
 59.1745 +
 59.1746 +      2) Fetch the current "descriptors".
 59.1747 +
 59.1748 +         I)  Discover new messages.
 59.1749 +
 59.1750 +         II) Discover changes to old messages and flags for new messages
 59.1751 +             using
 59.1752 +             "FETCH 1:* (FLAGS) (CHANGEDSINCE <cached-value>)" or
 59.1753 +             "SEARCH MODSEQ <cached-value>".
 59.1754 +
 59.1755 +             Discover expunged messages; for example, using
 59.1756 +             "UID SEARCH 1:<lastseenuid>".  (All messages not returned
 59.1757 +             in this command are expunged.)
 59.1758 +
 59.1759 +      3) Fetch the bodies of any "interesting" messages that the client
 59.1760 +         doesn't already have.
 59.1761 +
 59.1762 +         Example 10:
 59.1763 +
 59.1764 +         The UIDVALIDITY value is the same, but the HIGHESTMODSEQ value
 59.1765 +         has changed on the server while the client was offline.
 59.1766 +
 59.1767 +      C: A142 SELECT INBOX
 59.1768 +      S: * 172 EXISTS
 59.1769 +      S: * 1 RECENT
 59.1770 +      S: * OK [UNSEEN 12] Message 12 is first unseen
 59.1771 +      S: * OK [UIDVALIDITY 3857529045] UIDs valid
 59.1772 +      S: * OK [UIDNEXT 201] Predicted next UID
 59.1773 +      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
 59.1774 +      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
 59.1775 +      S: * OK [HIGHESTMODSEQ 20010715194045007]
 59.1776 +      S: A142 OK [READ-WRITE] SELECT completed
 59.1777 +
 59.1778 +   After that, either:
 59.1779 +
 59.1780 +      C: A143 UID FETCH 1:* (FLAGS) (CHANGEDSINCE 20010715194032001)
 59.1781 +      S: * 2 FETCH (UID 6 MODSEQ (20010715205008000) FLAGS (\Deleted))
 59.1782 +      S: * 5 FETCH (UID 9 MODSEQ (20010715195517000) FLAGS ($NoJunk
 59.1783 +          $AutoJunk $MDNSent))
 59.1784 +         ...
 59.1785 +      S: A143 OK FETCH completed
 59.1786 +
 59.1787 +   or:
 59.1788 +
 59.1789 +
 59.1790 +
 59.1791 +
 59.1792 +
 59.1793 +
 59.1794 +
 59.1795 +
 59.1796 +
 59.1797 +Melnikov                     Informational                     [Page 32]
 59.1798 +
 59.1799 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1800 +
 59.1801 +
 59.1802 +      C: A143 UID SEARCH MODSEQ 20010715194032001 UID 1:20
 59.1803 +      S: * SEARCH 6 9 11 12 18 19 20 23 (MODSEQ 20010917162500)
 59.1804 +      S: A143 OK Search complete
 59.1805 +      C: A144 UID SEARCH 1:20
 59.1806 +      S: * SEARCH 6 9 ...
 59.1807 +      S: A144 OK FETCH completed
 59.1808 +
 59.1809 +7.  Security Considerations
 59.1810 +
 59.1811 +   It is believed that this document does not raise any new security
 59.1812 +   concerns that are not already present in the base [IMAP4] protocol,
 59.1813 +   and these issues are discussed in [IMAP4].  Additional security
 59.1814 +   considerations may be found in different extensions mentioned in this
 59.1815 +   document; in particular, in [UIDPLUS], [LITERAL+], [CONDSTORE],
 59.1816 +   [MULTIAPPEND], and [UNSELECT].
 59.1817 +
 59.1818 +   Implementers are also reminded about the importance of thorough
 59.1819 +   testing.
 59.1820 +
 59.1821 +8.  References
 59.1822 +
 59.1823 +8.1.  Normative References
 59.1824 +
 59.1825 +   [KEYWORDS]    Bradner, S., "Key words for use in RFCs to Indicate
 59.1826 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
 59.1827 +
 59.1828 +   [IMAP4]       Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
 59.1829 +                 VERSION 4rev1", RFC 3501, March 2003.
 59.1830 +
 59.1831 +   [UIDPLUS]     Crispin, M., "Internet Message Access Protocol (IMAP) -
 59.1832 +                 UIDPLUS extension", RFC 4315, December 2005.
 59.1833 +
 59.1834 +   [LITERAL+]    Myers, J., "IMAP4 non-synchronizing literals", RFC
 59.1835 +                 2088, January 1997.
 59.1836 +
 59.1837 +   [CONDSTORE]   Melnikov, A. and S. Hole, "IMAP Extension for
 59.1838 +                 Conditional STORE Operation or Quick Flag Changes
 59.1839 +                 Resynchronization", RFC 4551, June 2006.
 59.1840 +
 59.1841 +   [MULTIAPPEND] Crispin, M., "Internet Message Access Protocol (IMAP) -
 59.1842 +                 MULTIAPPEND Extension", RFC 3502, March 2003.
 59.1843 +
 59.1844 +   [UNSELECT]    Melnikov, A., "Internet Message Access Protocol (IMAP)
 59.1845 +                 UNSELECT command", RFC 3691, February 2004.
 59.1846 +
 59.1847 +   [RFC2683]     Leiba, B., "IMAP4 Implementation Recommendations", RFC
 59.1848 +                 2683, September 1999.
 59.1849 +
 59.1850 +
 59.1851 +
 59.1852 +
 59.1853 +Melnikov                     Informational                     [Page 33]
 59.1854 +
 59.1855 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1856 +
 59.1857 +
 59.1858 +8.2.  Informative References
 59.1859 +
 59.1860 +   [ACL]         Melnikov, A., "IMAP4 Access Control List (ACL)
 59.1861 +                 Extension", RFC 4314, December 2005.
 59.1862 +
 59.1863 +   [IMAP-MODEL]  Crispin, M., "Distributed Electronic Mail Models in
 59.1864 +                 IMAP4", RFC 1733, December 1994.
 59.1865 +
 59.1866 +9.  Acknowledgements
 59.1867 +
 59.1868 +   This document is based on version 01 of the text written by Rob
 59.1869 +   Austein in November 1994.
 59.1870 +
 59.1871 +   The editor appreciates comments posted by Mark Crispin to the IMAP
 59.1872 +   mailing list and the comments/corrections/ideas received from Grant
 59.1873 +   Baillie, Cyrus Daboo, John G. Myers, Chris Newman, and Timo Sirainen.
 59.1874 +
 59.1875 +   The editor would also like to thank the developers of Netscape
 59.1876 +   Messenger and Mozilla mail clients for providing examples of
 59.1877 +   disconnected mail clients that served as a base for many
 59.1878 +   recommendations in this document.
 59.1879 +
 59.1880 +Editor's Address
 59.1881 +
 59.1882 +   Alexey Melnikov
 59.1883 +   Isode Limited
 59.1884 +   5 Castle Business Village
 59.1885 +   36 Station Road
 59.1886 +   Hampton, Middlesex
 59.1887 +   TW12 2BX
 59.1888 +   United Kingdom
 59.1889 +
 59.1890 +   Phone: +44 77 53759732
 59.1891 +   EMail: alexey.melnikov@isode.com
 59.1892 +
 59.1893 +
 59.1894 +
 59.1895 +
 59.1896 +
 59.1897 +
 59.1898 +
 59.1899 +
 59.1900 +
 59.1901 +
 59.1902 +
 59.1903 +
 59.1904 +
 59.1905 +
 59.1906 +
 59.1907 +
 59.1908 +
 59.1909 +Melnikov                     Informational                     [Page 34]
 59.1910 +
 59.1911 +RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
 59.1912 +
 59.1913 +
 59.1914 +Full Copyright Statement
 59.1915 +
 59.1916 +   Copyright (C) The Internet Society (2006).
 59.1917 +
 59.1918 +   This document is subject to the rights, licenses and restrictions
 59.1919 +   contained in BCP 78, and except as set forth therein, the authors
 59.1920 +   retain all their rights.
 59.1921 +
 59.1922 +   This document and the information contained herein are provided on an
 59.1923 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 59.1924 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
 59.1925 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
 59.1926 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
 59.1927 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 59.1928 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 59.1929 +
 59.1930 +Intellectual Property
 59.1931 +
 59.1932 +   The IETF takes no position regarding the validity or scope of any
 59.1933 +   Intellectual Property Rights or other rights that might be claimed to
 59.1934 +   pertain to the implementation or use of the technology described in
 59.1935 +   this document or the extent to which any license under such rights
 59.1936 +   might or might not be available; nor does it represent that it has
 59.1937 +   made any independent effort to identify any such rights.  Information
 59.1938 +   on the procedures with respect to rights in RFC documents can be
 59.1939 +   found in BCP 78 and BCP 79.
 59.1940 +
 59.1941 +   Copies of IPR disclosures made to the IETF Secretariat and any
 59.1942 +   assurances of licenses to be made available, or the result of an
 59.1943 +   attempt made to obtain a general license or permission for the use of
 59.1944 +   such proprietary rights by implementers or users of this
 59.1945 +   specification can be obtained from the IETF on-line IPR repository at
 59.1946 +   http://www.ietf.org/ipr.
 59.1947 +
 59.1948 +   The IETF invites any interested party to bring to its attention any
 59.1949 +   copyrights, patents or patent applications, or other proprietary
 59.1950 +   rights that may cover technology that may be required to implement
 59.1951 +   this standard.  Please address the information to the IETF at
 59.1952 +   ietf-ipr@ietf.org.
 59.1953 +
 59.1954 +Acknowledgement
 59.1955 +
 59.1956 +   Funding for the RFC Editor function is provided by the IETF
 59.1957 +   Administrative Support Activity (IASA).
 59.1958 +
 59.1959 +
 59.1960 +
 59.1961 +
 59.1962 +
 59.1963 +
 59.1964 +
 59.1965 +Melnikov                     Informational                     [Page 35]
 59.1966 +
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/docs/rfc/rfc4551.txt	Mon Sep 14 15:17:45 2009 +0900
    60.3 @@ -0,0 +1,1403 @@
    60.4 +
    60.5 +
    60.6 +
    60.7 +
    60.8 +
    60.9 +
   60.10 +Network Working Group                                        A. Melnikov
   60.11 +Request for Comments: 4551                                    Isode Ltd.
   60.12 +Updates: 3501                                                    S. Hole
   60.13 +Category: Standards Track                  ACI WorldWide/MessagingDirect
   60.14 +                                                               June 2006
   60.15 +
   60.16 +
   60.17 +             IMAP Extension for Conditional STORE Operation
   60.18 +                or Quick Flag Changes Resynchronization
   60.19 +
   60.20 +Status of This Memo
   60.21 +
   60.22 +   This document specifies an Internet standards track protocol for the
   60.23 +   Internet community, and requests discussion and suggestions for
   60.24 +   improvements.  Please refer to the current edition of the "Internet
   60.25 +   Official Protocol Standards" (STD 1) for the standardization state
   60.26 +   and status of this protocol.  Distribution of this memo is unlimited.
   60.27 +
   60.28 +Copyright Notice
   60.29 +
   60.30 +   Copyright (C) The Internet Society (2006).
   60.31 +
   60.32 +Abstract
   60.33 +
   60.34 +   Often, multiple IMAP (RFC 3501) clients need to coordinate changes to
   60.35 +   a common IMAP mailbox.  Examples include different clients working on
   60.36 +   behalf of the same user, and multiple users accessing shared
   60.37 +   mailboxes.  These clients need a mechanism to synchronize state
   60.38 +   changes for messages within the mailbox.  They must be able to
   60.39 +   guarantee that only one client can change message state (e.g.,
   60.40 +   message flags) at any time.  An example of such an application is use
   60.41 +   of an IMAP mailbox as a message queue with multiple dequeueing
   60.42 +   clients.
   60.43 +
   60.44 +   The Conditional Store facility provides a protected update mechanism
   60.45 +   for message state information that can detect and resolve conflicts
   60.46 +   between multiple writing mail clients.
   60.47 +
   60.48 +   The Conditional Store facility also allows a client to quickly
   60.49 +   resynchronize mailbox flag changes.
   60.50 +
   60.51 +   This document defines an extension to IMAP (RFC 3501).
   60.52 +
   60.53 +
   60.54 +
   60.55 +
   60.56 +
   60.57 +
   60.58 +
   60.59 +
   60.60 +
   60.61 +Melnikov & Hole             Standards Track                     [Page 1]
   60.62 +
   60.63 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
   60.64 +
   60.65 +
   60.66 +Table of Contents
   60.67 +
   60.68 +   1.  Introduction and Overview ................................. 3
   60.69 +   2.  Conventions Used in This Document ......................... 5
   60.70 +   3.  IMAP Protocol Changes ..................................... 6
   60.71 +   3.1. New OK untagged responses for SELECT and EXAMINE ......... 6
   60.72 +   3.1.1. HIGHESTMODSEQ response code ............................ 6
   60.73 +   3.1.2. NOMODSEQ response code ................................. 7
   60.74 +   3.2. STORE and UID STORE Commands ............................. 7
   60.75 +   3.3 FETCH and UID FETCH Commands ..............................13
   60.76 +   3.3.1. CHANGEDSINCE FETCH modifier ............................13
   60.77 +   3.3.2. MODSEQ message data item in FETCH Command ..............14
   60.78 +   3.4. MODSEQ search criterion in SEARCH ........................16
   60.79 +   3.5. Modified SEARCH untagged response ........................17
   60.80 +   3.6. HIGHESTMODSEQ status data items ..........................17
   60.81 +   3.7. CONDSTORE parameter to SELECT and EXAMINE ................18
   60.82 +   3.8. Additional quality of implementation issues ..............18
   60.83 +   4.  Formal Syntax .............................................19
   60.84 +   5.  Server implementation considerations ......................21
   60.85 +   6.  Security Considerations ...................................22
   60.86 +   7.  IANA Considerations .......................................22
   60.87 +   8.  References ................................................23
   60.88 +   8.1. Normative References .....................................23
   60.89 +   8.2. Informative References ...................................23
   60.90 +   9.  Acknowledgements ..........................................23
   60.91 +
   60.92 +
   60.93 +
   60.94 +
   60.95 +
   60.96 +
   60.97 +
   60.98 +
   60.99 +
  60.100 +
  60.101 +
  60.102 +
  60.103 +
  60.104 +
  60.105 +
  60.106 +
  60.107 +
  60.108 +
  60.109 +
  60.110 +
  60.111 +
  60.112 +
  60.113 +
  60.114 +
  60.115 +
  60.116 +
  60.117 +Melnikov & Hole             Standards Track                     [Page 2]
  60.118 +
  60.119 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.120 +
  60.121 +
  60.122 +1. Introduction and Overview
  60.123 +
  60.124 +   The Conditional STORE extension is present in any IMAP4
  60.125 +   implementation that returns "CONDSTORE" as one of the supported
  60.126 +   capabilities in the CAPABILITY command response.
  60.127 +
  60.128 +   An IMAP server that supports this extension MUST associate a positive
  60.129 +   unsigned 64-bit value called a modification sequence (mod-sequence)
  60.130 +   with every IMAP message.  This is an opaque value updated by the
  60.131 +   server whenever a metadata item is modified.  The server MUST
  60.132 +   guarantee that each STORE command performed on the same mailbox
  60.133 +   (including simultaneous stores to different metadata items from
  60.134 +   different connections) will get a different mod-sequence value.
  60.135 +   Also, for any two successful STORE operations performed in the same
  60.136 +   session on the same mailbox, the mod-sequence of the second completed
  60.137 +   operation MUST be greater than the mod-sequence of the first
  60.138 +   completed.  Note that the latter rule disallows the use of the system
  60.139 +   clock as a mod-sequence, because if system time changes (e.g., an NTP
  60.140 +   [NTP] client adjusting the time), the next generated value might be
  60.141 +   less than the previous one.
  60.142 +
  60.143 +   Mod-sequences allow a client that supports the CONDSTORE extension to
  60.144 +   determine if a message metadata has changed since some known moment.
  60.145 +   Whenever the state of a flag changes (i.e., the flag is added where
  60.146 +   previously it wasn't set, or the flag is removed and before it was
  60.147 +   set) the value of the modification sequence for the message MUST be
  60.148 +   updated.  Adding the flag when it is already present or removing when
  60.149 +   it is not present SHOULD NOT change the mod-sequence.
  60.150 +
  60.151 +   When a message is appended to a mailbox (via the IMAP APPEND command,
  60.152 +   COPY to the mailbox, or using an external mechanism) the server
  60.153 +   generates a new modification sequence that is higher than the highest
  60.154 +   modification sequence of all messages in the mailbox and assigns it
  60.155 +   to the appended message.
  60.156 +
  60.157 +   The server MAY store separate (per-message) modification sequence
  60.158 +   values for different metadata items.  If the server does so, per-
  60.159 +   message mod-sequence is the highest mod-sequence of all metadata
  60.160 +   items for the specified message.
  60.161 +
  60.162 +   The server that supports this extension is not required to be able to
  60.163 +   store mod-sequences for every available mailbox.  Section 3.1.2
  60.164 +   describes how the server may act if a particular mailbox doesn't
  60.165 +   support the persistent storage of mod-sequences.
  60.166 +
  60.167 +
  60.168 +
  60.169 +
  60.170 +
  60.171 +
  60.172 +
  60.173 +Melnikov & Hole             Standards Track                     [Page 3]
  60.174 +
  60.175 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.176 +
  60.177 +
  60.178 +   This extension makes the following changes to the IMAP4 protocol:
  60.179 +
  60.180 +      a) adds UNCHANGEDSINCE STORE modifier.
  60.181 +
  60.182 +      b) adds the MODIFIED response code which should be used with an OK
  60.183 +         response to the STORE command.  (It can also be used in a NO
  60.184 +         response.)
  60.185 +
  60.186 +      c) adds a new MODSEQ message data item for use with the FETCH
  60.187 +         command.
  60.188 +
  60.189 +      d) adds CHANGEDSINCE FETCH modifier.
  60.190 +
  60.191 +      e) adds a new MODSEQ search criterion.
  60.192 +
  60.193 +      f) extends the syntax of untagged SEARCH responses to include
  60.194 +         mod-sequence.
  60.195 +
  60.196 +      g) adds new OK untagged responses for the SELECT and EXAMINE
  60.197 +         commands.
  60.198 +
  60.199 +      h) defines an additional parameter to SELECT/EXAMINE commands.
  60.200 +
  60.201 +      i) adds the HIGHESTMODSEQ status data item to the STATUS command.
  60.202 +
  60.203 +   A client supporting CONDSTORE extension indicates its willingness to
  60.204 +   receive mod-sequence updates in all untagged FETCH responses by
  60.205 +   issuing:
  60.206 +
  60.207 +      -  a SELECT or EXAMINE command with the CONDSTORE parameter,
  60.208 +      -  a STATUS (HIGHESTMODSEQ) command,
  60.209 +      -  a FETCH or SEARCH command that includes the MODSEQ message data
  60.210 +         item,
  60.211 +      -  a FETCH command with the CHANGEDSINCE modifier, or
  60.212 +      -  a STORE command with the UNCHANGEDSINCE modifier.
  60.213 +
  60.214 +   The server MUST include mod-sequence data in all subsequent untagged
  60.215 +   FETCH responses (until the connection is closed), whether they were
  60.216 +   caused by a regular STORE, a STORE with UNCHANGEDSINCE modifier, or
  60.217 +   an external agent.
  60.218 +
  60.219 +   This document uses the term "CONDSTORE-aware client" to refer to a
  60.220 +   client that announces its willingness to receive mod-sequence updates
  60.221 +   as described above.  The term "CONDSTORE enabling command" will refer
  60.222 +   any of the commands listed above.  A future extension to this
  60.223 +   document may extend the list of CONDSTORE enabling commands.  A first
  60.224 +   CONDSTORE enabling command executed in the session MUST cause the
  60.225 +
  60.226 +
  60.227 +
  60.228 +
  60.229 +Melnikov & Hole             Standards Track                     [Page 4]
  60.230 +
  60.231 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.232 +
  60.233 +
  60.234 +   server to return HIGHESTMODSEQ (Section 3.1.1) unless the server has
  60.235 +   sent NOMODSEQ (Section 3.1.2) response code when the currently
  60.236 +   selected mailbox was selected.
  60.237 +
  60.238 +   The rest of this document describes the protocol changes more
  60.239 +   rigorously.
  60.240 +
  60.241 +2.  Conventions Used in This Document
  60.242 +
  60.243 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  60.244 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  60.245 +   document are to be interpreted as described in RFC 2119 [KEYWORDS].
  60.246 +
  60.247 +   In examples, lines beginning with "S:" are sent by the IMAP server,
  60.248 +   and lines beginning with "C:" are sent by the client.  Line breaks
  60.249 +   may appear in example commands solely for editorial clarity; when
  60.250 +   present in the actual message, they are represented by "CRLF".
  60.251 +
  60.252 +   Formal syntax is defined using ABNF [ABNF].
  60.253 +
  60.254 +   The term "metadata" or "metadata item" is used throughout this
  60.255 +   document.  It refers to any system or user-defined keyword.  Future
  60.256 +   documents may extend "metadata" to include other dynamic message
  60.257 +   data.
  60.258 +
  60.259 +   Some IMAP mailboxes are private, accessible only to the owning user.
  60.260 +   Other mailboxes are not, either because the owner has set an Access
  60.261 +   Control List [ACL] that permits access by other users, or because it
  60.262 +   is a shared mailbox.  Let's call a metadata item "shared" for the
  60.263 +   mailbox if any changes to the metadata items are persistent and
  60.264 +   visible to all other users accessing the mailbox.  Otherwise, the
  60.265 +   metadata item is called "private".  Note that private metadata items
  60.266 +   are still visible to all sessions accessing the mailbox as the same
  60.267 +   user.  Also note that different mailboxes may have different metadata
  60.268 +   items as shared.
  60.269 +
  60.270 +   See Section 1 for the definition of a "CONDSTORE-aware client" and a
  60.271 +   "CONDSTORE enabling command".
  60.272 +
  60.273 +
  60.274 +
  60.275 +
  60.276 +
  60.277 +
  60.278 +
  60.279 +
  60.280 +
  60.281 +
  60.282 +
  60.283 +
  60.284 +
  60.285 +Melnikov & Hole             Standards Track                     [Page 5]
  60.286 +
  60.287 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.288 +
  60.289 +
  60.290 +3.  IMAP Protocol Changes
  60.291 +
  60.292 +3.1.  New OK Untagged Responses for SELECT and EXAMINE
  60.293 +
  60.294 +   This document adds two new response codes, HIGHESTMODSEQ and
  60.295 +   NOMODSEQ.  One of those response codes MUST be returned in the OK
  60.296 +   untagged response for a successful SELECT/EXAMINE command.
  60.297 +
  60.298 +   When opening a mailbox, the server must check if the mailbox supports
  60.299 +   the persistent storage of mod-sequences.  If the mailbox supports the
  60.300 +   persistent storage of mod-sequences and the mailbox open operation
  60.301 +   succeeds, the server MUST send the OK untagged response including
  60.302 +   HIGHESTMODSEQ response code.  If the persistent storage for the
  60.303 +   mailbox is not supported, the server MUST send the OK untagged
  60.304 +   response including NOMODSEQ response code instead.
  60.305 +
  60.306 +3.1.1.  HIGHESTMODSEQ Response Code
  60.307 +
  60.308 +   This document adds a new response code that is returned in the OK
  60.309 +   untagged response for the SELECT and EXAMINE commands.  A server
  60.310 +   supporting the persistent storage of mod-sequences for the mailbox
  60.311 +   MUST send the OK untagged response including HIGHESTMODSEQ response
  60.312 +   code with every successful SELECT or EXAMINE command:
  60.313 +
  60.314 +      OK [HIGHESTMODSEQ <mod-sequence-value>]
  60.315 +
  60.316 +      where <mod-sequence-value> is the highest mod-sequence value of
  60.317 +      all messages in the mailbox.  When the server changes UIDVALIDITY
  60.318 +      for a mailbox, it doesn't have to keep the same HIGHESTMODSEQ for
  60.319 +      the mailbox.
  60.320 +
  60.321 +   A disconnected client can use the value of HIGHESTMODSEQ to check if
  60.322 +   it has to refetch metadata from the server.  If the UIDVALIDITY value
  60.323 +   has changed for the selected mailbox, the client MUST delete the
  60.324 +   cached value of HIGHESTMODSEQ.  If UIDVALIDITY for the mailbox is the
  60.325 +   same, and if the HIGHESTMODSEQ value stored in the client's cache is
  60.326 +   less than the value returned by the server, then some metadata items
  60.327 +   on the server have changed since the last synchronization, and the
  60.328 +   client needs to update its cache.  The client MAY use SEARCH MODSEQ
  60.329 +   (Section 3.4) to find out exactly which metadata items have changed.
  60.330 +   Alternatively, the client MAY issue FETCH with the CHANGEDSINCE
  60.331 +   modifier (Section 3.3.1) in order to fetch data for all messages that
  60.332 +   have metadata items changed since some known modification sequence.
  60.333 +
  60.334 +   Example 1:
  60.335 +
  60.336 +      C: A142 SELECT INBOX
  60.337 +      S: * 172 EXISTS
  60.338 +
  60.339 +
  60.340 +
  60.341 +Melnikov & Hole             Standards Track                     [Page 6]
  60.342 +
  60.343 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.344 +
  60.345 +
  60.346 +      S: * 1 RECENT
  60.347 +      S: * OK [UNSEEN 12] Message 12 is first unseen
  60.348 +      S: * OK [UIDVALIDITY 3857529045] UIDs valid
  60.349 +      S: * OK [UIDNEXT 4392] Predicted next UID
  60.350 +      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  60.351 +      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
  60.352 +      S: * OK [HIGHESTMODSEQ 715194045007]
  60.353 +      S: A142 OK [READ-WRITE] SELECT completed
  60.354 +
  60.355 +3.1.2.  NOMODSEQ Response Code
  60.356 +
  60.357 +   A server that doesn't support the persistent storage of mod-sequences
  60.358 +   for the mailbox MUST send the OK untagged response including NOMODSEQ
  60.359 +   response code with every successful SELECT or EXAMINE command.  A
  60.360 +   server that returned NOMODSEQ response code for a mailbox, which
  60.361 +   subsequently receives one of the following commands while the mailbox
  60.362 +   is selected:
  60.363 +
  60.364 +      -  a FETCH command with the CHANGEDSINCE modifier,
  60.365 +      -  a FETCH or SEARCH command that includes the MODSEQ message data
  60.366 +         item, or
  60.367 +      -  a STORE command with the UNCHANGEDSINCE modifier
  60.368 +
  60.369 +   MUST reject any such command with the tagged BAD response.
  60.370 +
  60.371 +   Example 2:
  60.372 +
  60.373 +      C: A142 SELECT INBOX
  60.374 +      S: * 172 EXISTS
  60.375 +      S: * 1 RECENT
  60.376 +      S: * OK [UNSEEN 12] Message 12 is first unseen
  60.377 +      S: * OK [UIDVALIDITY 3857529045] UIDs valid
  60.378 +      S: * OK [UIDNEXT 4392] Predicted next UID
  60.379 +      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  60.380 +      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
  60.381 +      S: * OK [NOMODSEQ] Sorry, this mailbox format doesn't support
  60.382 +           modsequences
  60.383 +      S: A142 OK [READ-WRITE] SELECT completed
  60.384 +
  60.385 +3.2.  STORE and UID STORE Commands
  60.386 +
  60.387 +   This document defines the following STORE modifier (see Section 2.5
  60.388 +   of [IMAPABNF]):
  60.389 +
  60.390 +   UNCHANGEDSINCE <mod-sequence>
  60.391 +
  60.392 +      For each message specified in the message set, the server performs
  60.393 +      the following.  If the mod-sequence of any metadata item of the
  60.394 +
  60.395 +
  60.396 +
  60.397 +Melnikov & Hole             Standards Track                     [Page 7]
  60.398 +
  60.399 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.400 +
  60.401 +
  60.402 +      message is equal or less than the specified UNCHANGEDSINCE value,
  60.403 +      then the requested operation (as described by the message data
  60.404 +      item) is performed.  If the operation is successful, the server
  60.405 +      MUST update the mod-sequence attribute of the message.  An
  60.406 +      untagged FETCH response MUST be sent, even if the .SILENT suffix
  60.407 +      is specified, and the response MUST include the MODSEQ message
  60.408 +      data item.  This is required to update the client's cache with the
  60.409 +      correct mod-sequence values.  See Section 3.3.2 for more details.
  60.410 +
  60.411 +      However, if the mod-sequence of any metadata item of the message
  60.412 +      is greater than the specified UNCHANGEDSINCE value, then the
  60.413 +      requested operation MUST NOT be performed.  In this case, the
  60.414 +      mod-sequence attribute of the message is not updated, and the
  60.415 +      message number (or unique identifier in the case of the UID STORE
  60.416 +      command) is added to the list of messages that failed the
  60.417 +      UNCHANGESINCE test.
  60.418 +
  60.419 +      When the server finished performing the operation on all the
  60.420 +      messages in the message set, it checks for a non-empty list of
  60.421 +      messages that failed the UNCHANGESINCE test.  If this list is
  60.422 +      non-empty, the server MUST return in the tagged response a
  60.423 +      MODIFIED response code.  The MODIFIED response code includes the
  60.424 +      message set (for STORE) or set of UIDs (for UID STORE) of all
  60.425 +      messages that failed the UNCHANGESINCE test.
  60.426 +
  60.427 +   Example 3:
  60.428 +
  60.429 +      All messages pass the UNCHANGESINCE test.
  60.430 +
  60.431 +      C: a103 UID STORE 6,4,8 (UNCHANGEDSINCE 12121230045)
  60.432 +          +FLAGS.SILENT (\Deleted)
  60.433 +      S: * 1 FETCH (UID 4 MODSEQ (12121231000))
  60.434 +      S: * 2 FETCH (UID 6 MODSEQ (12121230852))
  60.435 +      S: * 4 FETCH (UID 8 MODSEQ (12121130956))
  60.436 +      S: a103 OK Conditional Store completed
  60.437 +
  60.438 +   Example 4:
  60.439 +
  60.440 +      C: a104 STORE * (UNCHANGEDSINCE 12121230045) +FLAGS.SILENT
  60.441 +         (\Deleted $Processed)
  60.442 +      S: * 50 FETCH (MODSEQ (12111230047))
  60.443 +      S: a104 OK Store (conditional) completed
  60.444 +
  60.445 +   Example 5:
  60.446 +
  60.447 +      C: c101 STORE 1 (UNCHANGEDSINCE 12121230045) -FLAGS.SILENT
  60.448 +         (\Deleted)
  60.449 +      S: * OK [HIGHESTMODSEQ 12111230047]
  60.450 +
  60.451 +
  60.452 +
  60.453 +Melnikov & Hole             Standards Track                     [Page 8]
  60.454 +
  60.455 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.456 +
  60.457 +
  60.458 +      S: * 50 FETCH (MODSEQ (12111230048))
  60.459 +      S: c101 OK Store (conditional) completed
  60.460 +
  60.461 +      HIGHESTMODSEQ response code was sent by the server presumably
  60.462 +      because this was the first CONDSTORE enabling command.
  60.463 +
  60.464 +   Example 6:
  60.465 +
  60.466 +      In spite of the failure of the conditional STORE operation for
  60.467 +      message 7, the server continues to process the conditional STORE
  60.468 +      in order to find all messages that fail the test.
  60.469 +
  60.470 +      C: d105 STORE 7,5,9 (UNCHANGEDSINCE 320162338)
  60.471 +          +FLAGS.SILENT (\Deleted)
  60.472 +      S: * 5 FETCH (MODSEQ (320162350))
  60.473 +      S: d105 OK [MODIFIED 7,9] Conditional STORE failed
  60.474 +
  60.475 +   Example 7:
  60.476 +
  60.477 +      Same as above, but the server follows the SHOULD recommendation in
  60.478 +      Section 6.4.6 of [IMAP4].
  60.479 +
  60.480 +      C: d105 STORE 7,5,9 (UNCHANGEDSINCE 320162338)
  60.481 +          +FLAGS.SILENT (\Deleted)
  60.482 +      S: * 7 FETCH (MODSEQ (320162342) FLAGS (\Seen \Deleted))
  60.483 +      S: * 5 FETCH (MODSEQ (320162350))
  60.484 +      S: * 9 FETCH (MODSEQ (320162349) FLAGS (\Answered))
  60.485 +      S: d105 OK [MODIFIED 7,9] Conditional STORE failed
  60.486 +
  60.487 +      Use of UNCHANGEDSINCE with a modification sequence of 0 always
  60.488 +      fails if the metadata item exists.  A system flag MUST always be
  60.489 +      considered existent, whether it was set or not.
  60.490 +
  60.491 +   Example 8:
  60.492 +
  60.493 +      C: a102 STORE 12 (UNCHANGEDSINCE 0)
  60.494 +          +FLAGS.SILENT ($MDNSent)
  60.495 +      S: a102 OK [MODIFIED 12] Conditional STORE failed
  60.496 +
  60.497 +      The client has tested the presence of the $MDNSent user-defined
  60.498 +      keyword.
  60.499 +
  60.500 +   Note: A client trying to make an atomic change to the state of a
  60.501 +   particular metadata item (or a set of metadata items) should be
  60.502 +   prepared to deal with the case when the server returns the MODIFIED
  60.503 +   response code if the state of the metadata item being watched hasn't
  60.504 +   changed (but the state of some other metadata item has).  This is
  60.505 +   necessary, because some servers don't store separate mod-sequences
  60.506 +
  60.507 +
  60.508 +
  60.509 +Melnikov & Hole             Standards Track                     [Page 9]
  60.510 +
  60.511 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.512 +
  60.513 +
  60.514 +   for different metadata items.  However, a server implementation
  60.515 +   SHOULD avoid generating spurious MODIFIED responses for +FLAGS/-FLAGS
  60.516 +   STORE operations, even when the server stores a single mod-sequence
  60.517 +   per message.  Section 5 describes how this can be achieved.
  60.518 +
  60.519 +   Unless the server has included an unsolicited FETCH to update
  60.520 +   client's knowledge about messages that have failed the UNCHANGEDSINCE
  60.521 +   test, upon receipt of the MODIFIED response code, the client SHOULD
  60.522 +   try to figure out if the required metadata items have indeed changed
  60.523 +   by issuing FETCH or NOOP command.  It is RECOMMENDED that the server
  60.524 +   avoids the need for the client to do that by sending an unsolicited
  60.525 +   FETCH response (Examples 9 and 10).
  60.526 +
  60.527 +   If the required metadata items haven't changed, the client SHOULD
  60.528 +   retry the command with the new mod-sequence.  The client SHOULD allow
  60.529 +   for a configurable but reasonable number of retries (at least 2).
  60.530 +
  60.531 +   Example 9:
  60.532 +
  60.533 +      In the example below, the server returns the MODIFIED response
  60.534 +      code without sending information describing why the STORE
  60.535 +      UNCHANGEDSINCE operation has failed.
  60.536 +
  60.537 +      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
  60.538 +          +FLAGS.SILENT ($Processed)
  60.539 +      S: * 100 FETCH (MODSEQ (303181230852))
  60.540 +      S: * 102 FETCH (MODSEQ (303181230852))
  60.541 +      ...
  60.542 +      S: * 150 FETCH (MODSEQ (303181230852))
  60.543 +      S: a106 OK [MODIFIED 101] Conditional STORE failed
  60.544 +
  60.545 +      The flag $Processed was set on the message 101...
  60.546 +
  60.547 +      C: a107 NOOP
  60.548 +      S: * 101 FETCH (MODSEQ (303011130956) FLAGS ($Processed))
  60.549 +      S: a107 OK
  60.550 +
  60.551 +      Or the flag hasn't changed, but another has (note that this server
  60.552 +      behaviour is discouraged.  Server implementers should also see
  60.553 +      Section 5)...
  60.554 +
  60.555 +      C: b107 NOOP
  60.556 +      S: * 101 FETCH (MODSEQ (303011130956) FLAGS (\Deleted \Answered))
  60.557 +      S: b107 OK
  60.558 +
  60.559 +      ...and the client retries the operation for the message 101 with
  60.560 +      the updated UNCHANGEDSINCE value
  60.561 +
  60.562 +
  60.563 +
  60.564 +
  60.565 +Melnikov & Hole             Standards Track                    [Page 10]
  60.566 +
  60.567 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.568 +
  60.569 +
  60.570 +      C: b108 STORE 101 (UNCHANGEDSINCE 303011130956)
  60.571 +          +FLAGS.SILENT ($Processed)
  60.572 +      S: * 101 FETCH (MODSEQ (303181230852))
  60.573 +      S: b108 OK Conditional Store completed
  60.574 +
  60.575 +   Example 10:
  60.576 +
  60.577 +      Same as above, but the server avoids the need for the client to
  60.578 +      poll for changes.
  60.579 +
  60.580 +      The flag $Processed was set on the message 101 by another
  60.581 +      client...
  60.582 +
  60.583 +      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
  60.584 +          +FLAGS.SILENT ($Processed)
  60.585 +      S: * 100 FETCH (MODSEQ (303181230852))
  60.586 +      S: * 101 FETCH (MODSEQ (303011130956) FLAGS ($Processed))
  60.587 +      S: * 102 FETCH (MODSEQ (303181230852))
  60.588 +      ...
  60.589 +      S: * 150 FETCH (MODSEQ (303181230852))
  60.590 +      S: a106 OK [MODIFIED 101] Conditional STORE failed
  60.591 +
  60.592 +      Or the flag hasn't changed, but another has (note that this server
  60.593 +      behaviour is discouraged.  Server implementers should also see
  60.594 +      Section 5)...
  60.595 +
  60.596 +      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
  60.597 +          +FLAGS.SILENT ($Processed)
  60.598 +      S: * 100 FETCH (MODSEQ (303181230852))
  60.599 +      S: * 101 FETCH (MODSEQ (303011130956) FLAGS (\Deleted \Answered))
  60.600 +      S: * 102 FETCH (MODSEQ (303181230852))
  60.601 +      ...
  60.602 +      S: * 150 FETCH (MODSEQ (303181230852))
  60.603 +      S: a106 OK [MODIFIED 101] Conditional STORE failed
  60.604 +
  60.605 +      ...and the client retries the operation for the message 101 with
  60.606 +      the updated UNCHANGEDSINCE value
  60.607 +
  60.608 +      C: b108 STORE 101 (UNCHANGEDSINCE 303011130956)
  60.609 +          +FLAGS.SILENT ($Processed)
  60.610 +      S: * 101 FETCH (MODSEQ (303181230852))
  60.611 +      S: b108 OK Conditional Store completed
  60.612 +
  60.613 +      Or the flag hasn't changed, but another has (nice server
  60.614 +      behaviour.  Server implementers should also see Section 5)...
  60.615 +
  60.616 +      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
  60.617 +          +FLAGS.SILENT ($Processed)
  60.618 +
  60.619 +
  60.620 +
  60.621 +Melnikov & Hole             Standards Track                    [Page 11]
  60.622 +
  60.623 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.624 +
  60.625 +
  60.626 +      S: * 100 FETCH (MODSEQ (303181230852))
  60.627 +      S: * 101 FETCH (MODSEQ (303011130956) FLAGS ($Processed \Deleted
  60.628 +           \Answered))
  60.629 +      S: * 102 FETCH (MODSEQ (303181230852))
  60.630 +      ...
  60.631 +      S: * 150 FETCH (MODSEQ (303181230852))
  60.632 +      S: a106 OK Conditional STORE completed
  60.633 +
  60.634 +   Example 11:
  60.635 +
  60.636 +      The following example is based on the example from the Section
  60.637 +      4.2.3 of [RFC-2180] and demonstrates that the MODIFIED response
  60.638 +      code may be also returned in the tagged NO response.
  60.639 +
  60.640 +      Client tries to conditionally STORE flags on a mixture of expunged
  60.641 +      and non-expunged messages; one message fails the UNCHANGEDSINCE
  60.642 +      test.
  60.643 +
  60.644 +      C: B001 STORE 1:7 (UNCHANGEDSINCE 320172338) +FLAGS (\SEEN)
  60.645 +      S: * 1 FETCH (MODSEQ (320172342) FLAGS (\SEEN))
  60.646 +      S: * 3 FETCH (MODSEQ (320172342) FLAGS (\SEEN))
  60.647 +      S: B001 NO [MODIFIED 2] Some of the messages no longer exist.
  60.648 +
  60.649 +      C: B002 NOOP
  60.650 +      S: * 4 EXPUNGE
  60.651 +      S: * 4 EXPUNGE
  60.652 +      S: * 4 EXPUNGE
  60.653 +      S: * 4 EXPUNGE
  60.654 +      S: * 2 FETCH (MODSEQ (320172340) FLAGS (\Deleted \Answered))
  60.655 +      S: B002 OK NOOP Completed.
  60.656 +
  60.657 +      By receiving FETCH responses for messages 1 and 3, and EXPUNGE
  60.658 +      responses that indicate that messages 4 through 7 have been
  60.659 +      expunged, the client retries the operation only for the message 2.
  60.660 +      The updated UNCHANGEDSINCE value is used.
  60.661 +
  60.662 +      C: b003 STORE 2 (UNCHANGEDSINCE 320172340) +FLAGS (\Seen)
  60.663 +      S: * 2 FETCH (MODSEQ (320180050))
  60.664 +      S: b003 OK Conditional Store completed
  60.665 +
  60.666 +   Note: If a message is specified multiple times in the message set,
  60.667 +   and the server doesn't internally eliminate duplicates from the
  60.668 +   message set, it MUST NOT fail the conditional STORE operation for the
  60.669 +   second (or subsequent) occurrence of the message if the operation
  60.670 +   completed successfully for the first occurrence.  For example, if the
  60.671 +   client specifies:
  60.672 +
  60.673 +
  60.674 +
  60.675 +
  60.676 +
  60.677 +Melnikov & Hole             Standards Track                    [Page 12]
  60.678 +
  60.679 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.680 +
  60.681 +
  60.682 +         e105 STORE 7,3:9 (UNCHANGEDSINCE 12121230045)
  60.683 +          +FLAGS.SILENT (\Deleted)
  60.684 +
  60.685 +   the server must not fail the operation for message 7 as part of
  60.686 +   processing "3:9" if it succeeded when message 7 was processed the
  60.687 +   first time.
  60.688 +
  60.689 +   Once the client specified the UNCHANGEDSINCE modifier in a STORE
  60.690 +   command, the server MUST include the MODSEQ fetch response data items
  60.691 +   in all subsequent unsolicited FETCH responses.
  60.692 +
  60.693 +   This document also changes the behaviour of the server when it has
  60.694 +   performed a STORE or UID STORE command and the UNCHANGEDSINCE
  60.695 +   modifier is not specified.  If the operation is successful for a
  60.696 +   message, the server MUST update the mod-sequence attribute of the
  60.697 +   message.  The server is REQUIRED to include the mod-sequence value
  60.698 +   whenever it decides to send the unsolicited FETCH response to all
  60.699 +   CONDSTORE-aware clients that have opened the mailbox containing the
  60.700 +   message.
  60.701 +
  60.702 +   Server implementers should also see Section 3.8 for additional
  60.703 +   quality of implementation issues related to the STORE command.
  60.704 +
  60.705 +3.3.  FETCH and UID FETCH Commands
  60.706 +
  60.707 +3.3.1.  CHANGEDSINCE FETCH Modifier
  60.708 +
  60.709 +   This document defines the following FETCH modifier (see Section 2.4
  60.710 +   of [IMAPABNF]):
  60.711 +
  60.712 +   CHANGEDSINCE <mod-sequence>
  60.713 +
  60.714 +      CHANGEDSINCE FETCH modifier allows to create a further subset of
  60.715 +      the list of messages described by sequence set.  The information
  60.716 +      described by message data items is only returned for messages that
  60.717 +      have mod-sequence bigger than <mod-sequence>.
  60.718 +
  60.719 +      When CHANGEDSINCE FETCH modifier is specified, it implicitly adds
  60.720 +      MODSEQ FETCH message data item (Section 3.3.2).
  60.721 +
  60.722 +   Example 12:
  60.723 +
  60.724 +      C: s100 UID FETCH 1:* (FLAGS) (CHANGEDSINCE 12345)
  60.725 +      S: * 1 FETCH (UID 4 MODSEQ (65402) FLAGS (\Seen))
  60.726 +      S: * 2 FETCH (UID 6 MODSEQ (75403) FLAGS (\Deleted))
  60.727 +      S: * 4 FETCH (UID 8 MODSEQ (29738) FLAGS ($NoJunk $AutoJunk
  60.728 +           $MDNSent))
  60.729 +      S: s100 OK FETCH completed
  60.730 +
  60.731 +
  60.732 +
  60.733 +Melnikov & Hole             Standards Track                    [Page 13]
  60.734 +
  60.735 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.736 +
  60.737 +
  60.738 +3.3.2.  MODSEQ Message Data Item in FETCH Command
  60.739 +
  60.740 +   This extension adds a MODSEQ message data item to the FETCH command.
  60.741 +   The MODSEQ message data item allows clients to retrieve mod-sequence
  60.742 +   values for a range of messages in the currently selected mailbox.
  60.743 +
  60.744 +   Once the client specified the MODSEQ message data item in a FETCH
  60.745 +   request, the server MUST include the MODSEQ fetch response data items
  60.746 +   in all subsequent unsolicited FETCH responses.
  60.747 +
  60.748 +   Syntax:  MODSEQ
  60.749 +
  60.750 +      The MODSEQ message data item causes the server to return MODSEQ
  60.751 +      fetch response data items.
  60.752 +
  60.753 +   Syntax:  MODSEQ ( <permsg-modsequence> )
  60.754 +
  60.755 +      MODSEQ response data items contain per-message mod-sequences.
  60.756 +
  60.757 +      The MODSEQ response data item is returned if the client issued
  60.758 +      FETCH with MODSEQ message data item.  It also allows the server to
  60.759 +      notify the client about mod-sequence changes caused by conditional
  60.760 +      STOREs (Section 3.2) and/or changes caused by external sources.
  60.761 +
  60.762 +   Example 13:
  60.763 +
  60.764 +      C: a FETCH 1:3 (MODSEQ)
  60.765 +      S: * 1 FETCH (MODSEQ (624140003))
  60.766 +      S: * 2 FETCH (MODSEQ (624140007))
  60.767 +      S: * 3 FETCH (MODSEQ (624140005))
  60.768 +      S: a OK Fetch complete
  60.769 +
  60.770 +      In this example, the client requests per-message mod-sequences for
  60.771 +      a set of messages.
  60.772 +
  60.773 +   When a flag for a message is modified in a different session, the
  60.774 +   server sends an unsolicited FETCH response containing the mod-
  60.775 +   sequence for the message.
  60.776 +
  60.777 +   Example 14:
  60.778 +
  60.779 +      (Session 1, authenticated as a user "alex").  The user adds a
  60.780 +      shared flag \Deleted:
  60.781 +
  60.782 +         C: A142 SELECT INBOX
  60.783 +         ...
  60.784 +         S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  60.785 +         S: * OK [PERMANENTFLAGS (\Answered \Deleted \Seen \*)] Limited
  60.786 +
  60.787 +
  60.788 +
  60.789 +Melnikov & Hole             Standards Track                    [Page 14]
  60.790 +
  60.791 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.792 +
  60.793 +
  60.794 +         ...
  60.795 +
  60.796 +         C: A160 STORE 7 +FLAGS.SILENT (\Deleted)
  60.797 +         S: * 7 FETCH (MODSEQ (2121231000))
  60.798 +         S: A160 OK Store completed
  60.799 +
  60.800 +      (Session 2, also authenticated as the user "alex").  Any changes
  60.801 +      to flags are always reported to all sessions authenticated as the
  60.802 +      same user as in the session 1.
  60.803 +
  60.804 +         C: C180 NOOP
  60.805 +         S: * 7 FETCH (FLAGS (\Deleted \Answered) MODSEQ (12121231000))
  60.806 +         S: C180 OK Noop completed
  60.807 +
  60.808 +      (Session 3, authenticated as a user "andrew").  As \Deleted is a
  60.809 +      shared flag, changes in session 1 are also reported in session 3:
  60.810 +
  60.811 +         C: D210 NOOP
  60.812 +         S: * 7 FETCH (FLAGS (\Deleted \Answered) MODSEQ (12121231000))
  60.813 +         S: D210 OK Noop completed
  60.814 +
  60.815 +      The user modifies a private flag \Seen in session 1...
  60.816 +
  60.817 +         C: A240 STORE 7 +FLAGS.SILENT (\Seen)
  60.818 +         S: * 7 FETCH (MODSEQ (12121231777))
  60.819 +         S: A240 OK Store completed
  60.820 +
  60.821 +      ...which is only reported in session 2...
  60.822 +
  60.823 +         C: C270 NOOP
  60.824 +         S: * 7 FETCH (FLAGS (\Deleted \Answered \Seen) MODSEQ
  60.825 +              (12121231777))
  60.826 +         S: C270 OK Noop completed
  60.827 +
  60.828 +      ...but not in session 3.
  60.829 +
  60.830 +         C: D300 NOOP
  60.831 +         S: D300 OK Noop completed
  60.832 +
  60.833 +      And finally, the user removes flags \Answered (shared) and \Seen
  60.834 +      (private) in session 1.
  60.835 +
  60.836 +         C: A330 STORE 7 -FLAGS.SILENT (\Answered \Seen)
  60.837 +         S: * 7 FETCH (MODSEQ (12121245160))
  60.838 +         S: A330 OK Store completed
  60.839 +
  60.840 +
  60.841 +
  60.842 +
  60.843 +
  60.844 +
  60.845 +Melnikov & Hole             Standards Track                    [Page 15]
  60.846 +
  60.847 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.848 +
  60.849 +
  60.850 +      Both changes are reported in the session 2...
  60.851 +
  60.852 +         C: C360 NOOP
  60.853 +         S: * 7 FETCH (FLAGS (\Deleted) MODSEQ (12121245160))
  60.854 +         S: C360 OK Noop completed
  60.855 +
  60.856 +      ...and only changes to shared flags are reported in session 3.
  60.857 +
  60.858 +         C: D390 NOOP
  60.859 +         S: * 7 FETCH (FLAGS (\Deleted) MODSEQ (12121245160))
  60.860 +         S: D390 OK Noop completed
  60.861 +
  60.862 +   Server implementers should also see Section 3.8 for additional
  60.863 +   quality of implementation issues related to the FETCH command.
  60.864 +
  60.865 +3.4.  MODSEQ Search Criterion in SEARCH
  60.866 +
  60.867 +   The MODSEQ criterion for the SEARCH command allows a client to search
  60.868 +   for the metadata items that were modified since a specified moment.
  60.869 +
  60.870 +   Syntax:  MODSEQ [<entry-name> <entry-type-req>] <mod-sequence-valzer>
  60.871 +
  60.872 +      Messages that have modification values that are equal to or
  60.873 +      greater than <mod-sequence-valzer>.  This allows a client, for
  60.874 +      example, to find out which messages contain metadata items that
  60.875 +      have changed since the last time it updated its disconnected
  60.876 +      cache.  The client may also specify <entry-name> (name of metadata
  60.877 +      item) and <entry-type-req> (type of metadata item) before
  60.878 +      <mod-sequence-valzer>.  <entry-type-req> can be one of "shared",
  60.879 +      "priv" (private), or "all".  The latter means that the server
  60.880 +      should use the biggest value among "priv" and "shared" mod-
  60.881 +      sequences for the metadata item.  If the server doesn't store
  60.882 +      internally separate mod-sequences for different metadata items, it
  60.883 +      MUST ignore <entry-name> and <entry-type-req>.  Otherwise, the
  60.884 +      server should use them to narrow down the search.
  60.885 +
  60.886 +      For a flag <flagname>, the corresponding <entry-name> has a form
  60.887 +      "/flags/<flagname>" as defined in [IMAPABNF].  Note that the
  60.888 +      leading "\" character that denotes a system flag has to be escaped
  60.889 +      as per Section 4.3 of [IMAP4], as the <entry-name> uses syntax for
  60.890 +      quoted strings.
  60.891 +
  60.892 +   If client specifies a MODSEQ criterion in a SEARCH command and the
  60.893 +   server returns a non-empty SEARCH result, the server MUST also append
  60.894 +   (to the end of the untagged SEARCH response) the highest mod-sequence
  60.895 +   for all messages being returned.  See also Section 3.5.
  60.896 +
  60.897 +
  60.898 +
  60.899 +
  60.900 +
  60.901 +Melnikov & Hole             Standards Track                    [Page 16]
  60.902 +
  60.903 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.904 +
  60.905 +
  60.906 +   Example 15:
  60.907 +
  60.908 +      C: a SEARCH MODSEQ "/flags/\\draft" all 620162338
  60.909 +      S: * SEARCH 2 5 6 7 11 12 18 19 20 23 (MODSEQ 917162500)
  60.910 +      S: a OK Search complete
  60.911 +
  60.912 +      In the above example, the message numbers of any messages
  60.913 +      containing the string "IMAP4" in the "value" attribute of the
  60.914 +      "/comment" entry and having a mod-sequence equal to or greater
  60.915 +      than 620162338 for the "\Draft" flag are returned in the search
  60.916 +      results.
  60.917 +
  60.918 +   Example 16:
  60.919 +
  60.920 +      C: t SEARCH OR NOT MODSEQ 720162338 LARGER 50000
  60.921 +      S: * SEARCH
  60.922 +      S: t OK Search complete, nothing found
  60.923 +
  60.924 +3.5.  Modified SEARCH Untagged Response
  60.925 +
  60.926 +   Data:       zero or more numbers
  60.927 +               mod-sequence value (omitted if no match)
  60.928 +
  60.929 +   This document extends syntax of the untagged SEARCH response to
  60.930 +   include the highest mod-sequence for all messages being returned.
  60.931 +
  60.932 +   If a client specifies a MODSEQ criterion in a SEARCH (or UID SEARCH)
  60.933 +   command and the server returns a non-empty SEARCH result, the server
  60.934 +   MUST also append (to the end of the untagged SEARCH response) the
  60.935 +   highest mod-sequence for all messages being returned.  See Section
  60.936 +   3.4 for examples.
  60.937 +
  60.938 +3.6.  HIGHESTMODSEQ Status Data Items
  60.939 +
  60.940 +   This document defines a new status data item:
  60.941 +
  60.942 +   HIGHESTMODSEQ
  60.943 +
  60.944 +      The highest mod-sequence value of all messages in the mailbox.
  60.945 +      This is the same value that is returned by the server in the
  60.946 +      HIGHESTMODSEQ response code in an OK untagged response (see
  60.947 +      Section 3.1.1).  If the server doesn't support the persistent
  60.948 +      storage of mod-sequences for the mailbox (see Section 3.1.2), the
  60.949 +      server MUST return 0 as the value of HIGHESTMODSEQ status data
  60.950 +      item.
  60.951 +
  60.952 +
  60.953 +
  60.954 +
  60.955 +
  60.956 +
  60.957 +Melnikov & Hole             Standards Track                    [Page 17]
  60.958 +
  60.959 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
  60.960 +
  60.961 +
  60.962 +   Example 17:
  60.963 +
  60.964 +      C: A042 STATUS blurdybloop (UIDNEXT MESSAGES HIGHESTMODSEQ)
  60.965 +      S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292
  60.966 +           HIGHESTMODSEQ 7011231777)
  60.967 +      S: A042 OK STATUS completed
  60.968 +
  60.969 +3.7.  CONDSTORE Parameter to SELECT and EXAMINE
  60.970 +
  60.971 +   The CONDSTORE extension defines a single optional select parameter,
  60.972 +   "CONDSTORE", which tells the server that it MUST include the MODSEQ
  60.973 +   fetch response data items in all subsequent unsolicited FETCH
  60.974 +   responses.
  60.975 +
  60.976 +   The CONDSTORE parameter to SELECT/EXAMINE helps avoid a race
  60.977 +   condition that might arise when one or more metadata items are
  60.978 +   modified in another session after the server has sent the
  60.979 +   HIGHESTMODSEQ response code and before the client was able to issue a
  60.980 +   CONDSTORE enabling command.
  60.981 +
  60.982 +   Example 18:
  60.983 +
  60.984 +      C: A142 SELECT INBOX (CONDSTORE)
  60.985 +      S: * 172 EXISTS
  60.986 +      S: * 1 RECENT
  60.987 +      S: * OK [UNSEEN 12] Message 12 is first unseen
  60.988 +      S: * OK [UIDVALIDITY 3857529045] UIDs valid
  60.989 +      S: * OK [UIDNEXT 4392] Predicted next UID
  60.990 +      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  60.991 +      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
  60.992 +      S: * OK [HIGHESTMODSEQ 715194045007]
  60.993 +      S: A142 OK [READ-WRITE] SELECT completed, CONDSTORE is now enabled
  60.994 +
  60.995 +3.8.  Additional Quality-of-Implementation Issues
  60.996 +
  60.997 +   Server implementations should follow the following rule, which
  60.998 +   applies to any successfully completed STORE/UID STORE (with and
  60.999 +   without UNCHANGEDSINCE modifier), as well as to a FETCH command that
 60.1000 +   implicitly sets \Seen flag:
 60.1001 +
 60.1002 +      Adding the flag when it is already present or removing when it is
 60.1003 +      not present SHOULD NOT change the mod-sequence.
 60.1004 +
 60.1005 +   This will prevent spurious client synchronization requests.
 60.1006 +
 60.1007 +
 60.1008 +
 60.1009 +
 60.1010 +
 60.1011 +
 60.1012 +
 60.1013 +Melnikov & Hole             Standards Track                    [Page 18]
 60.1014 +
 60.1015 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1016 +
 60.1017 +
 60.1018 +   However, note that client implementers MUST NOT rely on this server
 60.1019 +   behavior.  A client can't distinguish between the case when a server
 60.1020 +   has violated the SHOULD mentioned above, and that when one or more
 60.1021 +   clients set and unset (or unset and set) the flag in another session.
 60.1022 +
 60.1023 +4.  Formal Syntax
 60.1024 +
 60.1025 +   The following syntax specification uses the Augmented Backus-Naur
 60.1026 +   Form (ABNF) [ABNF] notation.  Elements not defined here can be found
 60.1027 +   in the formal syntax of the ABNF [ABNF], IMAP [IMAP4], and IMAP ABNF
 60.1028 +   extensions [IMAPABNF] specifications.
 60.1029 +
 60.1030 +   Except as noted otherwise, all alphabetic characters are case-
 60.1031 +   insensitive.  The use of upper- or lowercase characters to define
 60.1032 +   token strings is for editorial clarity only.  Implementations MUST
 60.1033 +   accept these strings in a case-insensitive fashion.
 60.1034 +
 60.1035 +   capability          =/ "CONDSTORE"
 60.1036 +
 60.1037 +   status-att          =/ "HIGHESTMODSEQ"
 60.1038 +                          ;; extends non-terminal defined in RFC 3501.
 60.1039 +
 60.1040 +   status-att-val      =/ "HIGHESTMODSEQ" SP mod-sequence-valzer
 60.1041 +                          ;; extends non-terminal defined in [IMAPABNF].
 60.1042 +                          ;; Value 0 denotes that the mailbox doesn't
 60.1043 +                          ;; support persistent mod-sequences
 60.1044 +                          ;; as described in Section 3.1.2
 60.1045 +
 60.1046 +   store-modifier      =/ "UNCHANGEDSINCE" SP mod-sequence-valzer
 60.1047 +                          ;; Only a single "UNCHANGEDSINCE" may be
 60.1048 +                          ;; specified in a STORE operation
 60.1049 +
 60.1050 +   fetch-modifier      =/ chgsince-fetch-mod
 60.1051 +                          ;; conforms to the generic "fetch-modifier"
 60.1052 +                          ;; syntax defined in [IMAPABNF].
 60.1053 +
 60.1054 +   chgsince-fetch-mod  = "CHANGEDSINCE" SP mod-sequence-value
 60.1055 +                          ;; CHANGEDSINCE FETCH modifier conforms to
 60.1056 +                          ;; the fetch-modifier syntax
 60.1057 +
 60.1058 +   fetch-att           =/ fetch-mod-sequence
 60.1059 +                          ;; modifies original IMAP4 fetch-att
 60.1060 +
 60.1061 +   fetch-mod-sequence  = "MODSEQ"
 60.1062 +
 60.1063 +   fetch-mod-resp      = "MODSEQ" SP "(" permsg-modsequence ")"
 60.1064 +
 60.1065 +   msg-att-dynamic     =/ fetch-mod-resp
 60.1066 +
 60.1067 +
 60.1068 +
 60.1069 +Melnikov & Hole             Standards Track                    [Page 19]
 60.1070 +
 60.1071 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1072 +
 60.1073 +
 60.1074 +   search-key          =/ search-modsequence
 60.1075 +                          ;; modifies original IMAP4 search-key
 60.1076 +                          ;;
 60.1077 +                          ;; This change applies to all commands
 60.1078 +                          ;; referencing this non-terminal, in
 60.1079 +                          ;; particular SEARCH.
 60.1080 +
 60.1081 +   search-modsequence  = "MODSEQ" [search-modseq-ext] SP
 60.1082 +                         mod-sequence-valzer
 60.1083 +
 60.1084 +   search-modseq-ext   = SP entry-name SP entry-type-req
 60.1085 +
 60.1086 +   resp-text-code      =/ "HIGHESTMODSEQ" SP mod-sequence-value /
 60.1087 +                          "NOMODSEQ" /
 60.1088 +                          "MODIFIED" SP set
 60.1089 +
 60.1090 +   entry-name          = entry-flag-name
 60.1091 +
 60.1092 +   entry-flag-name     = DQUOTE "/flags/" attr-flag DQUOTE
 60.1093 +                          ;; each system or user defined flag <flag>
 60.1094 +                          ;; is mapped to "/flags/<flag>".
 60.1095 +                          ;;
 60.1096 +                          ;; <entry-flag-name> follows the escape rules
 60.1097 +                          ;; used by "quoted" string as described in
 60.1098 +                          ;; Section 4.3 of [IMAP4], e.g., for the flag
 60.1099 +                          ;; \Seen the corresponding <entry-name> is
 60.1100 +                          ;; "/flags/\\seen", and for the flag
 60.1101 +                          ;; $MDNSent, the corresponding <entry-name>
 60.1102 +                          ;; is "/flags/$mdnsent".
 60.1103 +
 60.1104 +   entry-type-resp     = "priv" / "shared"
 60.1105 +                          ;; metadata item type
 60.1106 +
 60.1107 +   entry-type-req      = entry-type-resp / "all"
 60.1108 +                          ;; perform SEARCH operation on private
 60.1109 +                          ;; metadata item, shared metadata item or both
 60.1110 +
 60.1111 +   permsg-modsequence  = mod-sequence-value
 60.1112 +                          ;; per message mod-sequence
 60.1113 +
 60.1114 +   mod-sequence-value  = 1*DIGIT
 60.1115 +                          ;; Positive unsigned 64-bit integer
 60.1116 +                          ;; (mod-sequence)
 60.1117 +                          ;; (1 <= n < 18,446,744,073,709,551,615)
 60.1118 +
 60.1119 +   mod-sequence-valzer = "0" / mod-sequence-value
 60.1120 +
 60.1121 +   search-sort-mod-seq = "(" "MODSEQ" SP mod-sequence-value ")"
 60.1122 +
 60.1123 +
 60.1124 +
 60.1125 +Melnikov & Hole             Standards Track                    [Page 20]
 60.1126 +
 60.1127 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1128 +
 60.1129 +
 60.1130 +   select-param        =/ condstore-param
 60.1131 +                          ;; conforms to the generic "select-param"
 60.1132 +                          ;; non-terminal syntax defined in [IMAPABNF].
 60.1133 +
 60.1134 +   condstore-param     = "CONDSTORE"
 60.1135 +
 60.1136 +   mailbox-data        =/ "SEARCH" [1*(SP nz-number) SP
 60.1137 +                          search-sort-mod-seq]
 60.1138 +
 60.1139 +   attr-flag           = "\\Answered" / "\\Flagged" / "\\Deleted" /
 60.1140 +                         "\\Seen" / "\\Draft" / attr-flag-keyword /
 60.1141 +                         attr-flag-extension
 60.1142 +                          ;; Does not include "\\Recent"
 60.1143 +
 60.1144 +   attr-flag-extension = "\\" atom
 60.1145 +                          ;; Future expansion.  Client implementations
 60.1146 +                          ;; MUST accept flag-extension flags.  Server
 60.1147 +                          ;; implementations MUST NOT generate
 60.1148 +                          ;; flag-extension flags except as defined by
 60.1149 +                          ;; future standard or standards-track
 60.1150 +                          ;; revisions of [IMAP4].
 60.1151 +
 60.1152 +   attr-flag-keyword   = atom
 60.1153 +
 60.1154 +5.  Server Implementation Considerations
 60.1155 +
 60.1156 +   This section describes how a server implementation that doesn't store
 60.1157 +   separate per-metadata mod-sequences for different metadata items can
 60.1158 +   avoid sending the MODIFIED response to any of the following
 60.1159 +   conditional STORE operations:
 60.1160 +
 60.1161 +      +FLAGS
 60.1162 +      -FLAGS
 60.1163 +      +FLAGS.SILENT
 60.1164 +      -FLAGS.SILENT
 60.1165 +
 60.1166 +   Note that the optimization described in this section can't be
 60.1167 +   performed in case of a conditional STORE FLAGS operation.
 60.1168 +
 60.1169 +   Let's use the following example.  The client has issued
 60.1170 +
 60.1171 +      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
 60.1172 +         +FLAGS.SILENT ($Processed)
 60.1173 +
 60.1174 +   When the server receives the command and parses it successfully, it
 60.1175 +   iterates through the message set and tries to execute the conditional
 60.1176 +   STORE command for each message.
 60.1177 +
 60.1178 +
 60.1179 +
 60.1180 +
 60.1181 +Melnikov & Hole             Standards Track                    [Page 21]
 60.1182 +
 60.1183 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1184 +
 60.1185 +
 60.1186 +   Each server internally works as a client, i.e., it has to cache the
 60.1187 +   current state of all IMAP flags as it is known to the client.  In
 60.1188 +   order to report flag changes to the client, the server compares the
 60.1189 +   cached values with the values in its database for IMAP flags.
 60.1190 +
 60.1191 +   Imagine that another client has changed the state of a flag \Deleted
 60.1192 +   on the message 101 and that the change updated the mod-sequence for
 60.1193 +   the message.  The server knows that the mod-sequence for the mailbox
 60.1194 +   has changed; however, it also knows that:
 60.1195 +
 60.1196 +   a) the client is not interested in \Deleted flag, as it hasn't
 60.1197 +      included it in +FLAGS.SILENT operation; and
 60.1198 +
 60.1199 +   b) the state of the flag $Processed hasn't changed (the server can
 60.1200 +      determine this by comparing cached flag state with the state of
 60.1201 +      the flag in the database).
 60.1202 +
 60.1203 +   Therefore, the server doesn't have to report MODIFIED to the client.
 60.1204 +   Instead, the server may set $Processed flag, update the mod-sequence
 60.1205 +   for the message 101 once again and send an untagged FETCH response
 60.1206 +   with new mod-sequence and flags:
 60.1207 +
 60.1208 +      S: * 101 FETCH (MODSEQ (303011130956)
 60.1209 +         FLAGS ($Processed \Deleted \Answered))
 60.1210 +
 60.1211 +   See also Section 3.8 for additional quality-of-implementation issues.
 60.1212 +
 60.1213 +6.  Security Considerations
 60.1214 +
 60.1215 +   It is believed that the Conditional STORE extension doesn't raise any
 60.1216 +   new security concerns that are not already discussed in [IMAP4].
 60.1217 +   However, the availability of this extension may make it possible for
 60.1218 +   IMAP4 to be used in critical applications it could not be used for
 60.1219 +   previously, making correct IMAP server implementation and operation
 60.1220 +   even more important.
 60.1221 +
 60.1222 +7.  IANA Considerations
 60.1223 +
 60.1224 +   IMAP4 capabilities are registered by publishing a standards track or
 60.1225 +   IESG approved experimental RFC.  The registry is currently located
 60.1226 +   at:
 60.1227 +
 60.1228 +         http://www.iana.org/assignments/imap4-capabilities
 60.1229 +
 60.1230 +   This document defines the CONDSTORE IMAP capability.  IANA has added
 60.1231 +   it to the registry accordingly.
 60.1232 +
 60.1233 +
 60.1234 +
 60.1235 +
 60.1236 +
 60.1237 +Melnikov & Hole             Standards Track                    [Page 22]
 60.1238 +
 60.1239 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1240 +
 60.1241 +
 60.1242 +8.  References
 60.1243 +
 60.1244 +8.1.  Normative References
 60.1245 +
 60.1246 +   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
 60.1247 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
 60.1248 +
 60.1249 +   [ABNF]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
 60.1250 +              Specifications: ABNF", RFC 4234, October 2005.
 60.1251 +
 60.1252 +   [IMAP4]    Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
 60.1253 +              4rev1", RFC 3501, March 2003.
 60.1254 +
 60.1255 +   [IMAPABNF] Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4
 60.1256 +              ABNF", RFC 4466, April 2006.
 60.1257 +
 60.1258 +8.2.  Informative References
 60.1259 +
 60.1260 +   [ACAP]     Newman, C. and J. Myers, "ACAP -- Application
 60.1261 +              Configuration Access Protocol", RFC 2244, November 1997.
 60.1262 +
 60.1263 +   [ACL]      Melnikov, A., "IMAP4 Access Control List (ACL) Extension",
 60.1264 +              RFC 4314, December 2005.
 60.1265 +
 60.1266 +   [ANN]      Daboo, C. and R. Gellens, "IMAP ANNOTATE Extension", Work
 60.1267 +              in Progress, March 2006.
 60.1268 +
 60.1269 +   [NTP]      Mills, D., "Network Time Protocol (Version 3)
 60.1270 +              Specification, Implementation and Analysis", RFC 1305,
 60.1271 +              March 1992.
 60.1272 +
 60.1273 +   [RFC-2180] Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC
 60.1274 +              2180, July 1997.
 60.1275 +
 60.1276 +9.  Acknowledgements
 60.1277 +
 60.1278 +   Some text was borrowed from "IMAP ANNOTATE Extension" [ANN] by
 60.1279 +   Randall Gellens and Cyrus Daboo and from "ACAP -- Application
 60.1280 +   Configuration Access Protocol" [ACAP] by Chris Newman and John Myers.
 60.1281 +
 60.1282 +   Many thanks to Randall Gellens for his thorough review of the
 60.1283 +   document.
 60.1284 +
 60.1285 +   The authors also acknowledge the feedback provided by Cyrus Daboo,
 60.1286 +   Larry Greenfield, Chris Newman, Harrie Hazewinkel, Arnt Gulbrandsen,
 60.1287 +   Timo Sirainen, Mark Crispin, Ned Freed, Ken Murchison, and Dave
 60.1288 +   Cridland.
 60.1289 +
 60.1290 +
 60.1291 +
 60.1292 +
 60.1293 +Melnikov & Hole             Standards Track                    [Page 23]
 60.1294 +
 60.1295 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1296 +
 60.1297 +
 60.1298 +Authors' Addresses
 60.1299 +
 60.1300 +   Alexey Melnikov
 60.1301 +   Isode Limited
 60.1302 +   5 Castle Business Village
 60.1303 +   36 Station Road
 60.1304 +   Hampton, Middlesex
 60.1305 +   TW12 2BX,
 60.1306 +   United Kingdom
 60.1307 +
 60.1308 +   EMail: Alexey.Melnikov@isode.com
 60.1309 +
 60.1310 +
 60.1311 +   Steve Hole
 60.1312 +   ACI WorldWide/MessagingDirect
 60.1313 +   #1807, 10088 102 Ave
 60.1314 +   Edmonton, AB
 60.1315 +   T5J 2Z1
 60.1316 +   Canada
 60.1317 +
 60.1318 +   EMail: Steve.Hole@messagingdirect.com
 60.1319 +
 60.1320 +
 60.1321 +
 60.1322 +
 60.1323 +
 60.1324 +
 60.1325 +
 60.1326 +
 60.1327 +
 60.1328 +
 60.1329 +
 60.1330 +
 60.1331 +
 60.1332 +
 60.1333 +
 60.1334 +
 60.1335 +
 60.1336 +
 60.1337 +
 60.1338 +
 60.1339 +
 60.1340 +
 60.1341 +
 60.1342 +
 60.1343 +
 60.1344 +
 60.1345 +
 60.1346 +
 60.1347 +
 60.1348 +
 60.1349 +Melnikov & Hole             Standards Track                    [Page 24]
 60.1350 +
 60.1351 +RFC 4551          IMAP Extension for Conditional STORE         June 2006
 60.1352 +
 60.1353 +
 60.1354 +Full Copyright Statement
 60.1355 +
 60.1356 +   Copyright (C) The Internet Society (2006).
 60.1357 +
 60.1358 +   This document is subject to the rights, licenses and restrictions
 60.1359 +   contained in BCP 78, and except as set forth therein, the authors
 60.1360 +   retain all their rights.
 60.1361 +
 60.1362 +   This document and the information contained herein are provided on an
 60.1363 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 60.1364 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
 60.1365 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
 60.1366 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
 60.1367 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 60.1368 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 60.1369 +
 60.1370 +Intellectual Property
 60.1371 +
 60.1372 +   The IETF takes no position regarding the validity or scope of any
 60.1373 +   Intellectual Property Rights or other rights that might be claimed to
 60.1374 +   pertain to the implementation or use of the technology described in
 60.1375 +   this document or the extent to which any license under such rights
 60.1376 +   might or might not be available; nor does it represent that it has
 60.1377 +   made any independent effort to identify any such rights.  Information
 60.1378 +   on the procedures with respect to rights in RFC documents can be
 60.1379 +   found in BCP 78 and BCP 79.
 60.1380 +
 60.1381 +   Copies of IPR disclosures made to the IETF Secretariat and any
 60.1382 +   assurances of licenses to be made available, or the result of an
 60.1383 +   attempt made to obtain a general license or permission for the use of
 60.1384 +   such proprietary rights by implementers or users of this
 60.1385 +   specification can be obtained from the IETF on-line IPR repository at
 60.1386 +   http://www.ietf.org/ipr.
 60.1387 +
 60.1388 +   The IETF invites any interested party to bring to its attention any
 60.1389 +   copyrights, patents or patent applications, or other proprietary
 60.1390 +   rights that may cover technology that may be required to implement
 60.1391 +   this standard.  Please address the information to the IETF at
 60.1392 +   ietf-ipr@ietf.org.
 60.1393 +
 60.1394 +Acknowledgement
 60.1395 +
 60.1396 +   Funding for the RFC Editor function is provided by the IETF
 60.1397 +   Administrative Support Activity (IASA).
 60.1398 +
 60.1399 +
 60.1400 +
 60.1401 +
 60.1402 +
 60.1403 +
 60.1404 +
 60.1405 +Melnikov & Hole             Standards Track                    [Page 25]
 60.1406 +
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/docs/rfc/rfc4616.txt	Mon Sep 14 15:17:45 2009 +0900
    61.3 @@ -0,0 +1,619 @@
    61.4 +
    61.5 +
    61.6 +
    61.7 +
    61.8 +
    61.9 +
   61.10 +Network Working Group                                   K. Zeilenga, Ed.
   61.11 +Request for Comments: 4616                           OpenLDAP Foundation
   61.12 +Updates: 2595                                                August 2006
   61.13 +Category: Standards Track
   61.14 +
   61.15 +
   61.16 +  The PLAIN Simple Authentication and Security Layer (SASL) Mechanism
   61.17 +
   61.18 +Status of This Memo
   61.19 +
   61.20 +   This document specifies an Internet standards track protocol for the
   61.21 +   Internet community, and requests discussion and suggestions for
   61.22 +   improvements.  Please refer to the current edition of the "Internet
   61.23 +   Official Protocol Standards" (STD 1) for the standardization state
   61.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   61.25 +
   61.26 +Copyright Notice
   61.27 +
   61.28 +   Copyright (C) The Internet Society (2006).
   61.29 +
   61.30 +Abstract
   61.31 +
   61.32 +   This document defines a simple clear-text user/password Simple
   61.33 +   Authentication and Security Layer (SASL) mechanism called the PLAIN
   61.34 +   mechanism.  The PLAIN mechanism is intended to be used, in
   61.35 +   combination with data confidentiality services provided by a lower
   61.36 +   layer, in protocols that lack a simple password authentication
   61.37 +   command.
   61.38 +
   61.39 +
   61.40 +
   61.41 +
   61.42 +
   61.43 +
   61.44 +
   61.45 +
   61.46 +
   61.47 +
   61.48 +
   61.49 +
   61.50 +
   61.51 +
   61.52 +
   61.53 +
   61.54 +
   61.55 +
   61.56 +
   61.57 +
   61.58 +
   61.59 +
   61.60 +
   61.61 +Zeilenga                    Standards Track                     [Page 1]
   61.62 +
   61.63 +RFC 4616                The PLAIN SASL Mechanism             August 2006
   61.64 +
   61.65 +
   61.66 +1.  Introduction
   61.67 +
   61.68 +   Clear-text, multiple-use passwords are simple, interoperate with
   61.69 +   almost all existing operating system authentication databases, and
   61.70 +   are useful for a smooth transition to a more secure password-based
   61.71 +   authentication mechanism.  The drawback is that they are unacceptable
   61.72 +   for use over network connections where data confidentiality is not
   61.73 +   ensured.
   61.74 +
   61.75 +   This document defines the PLAIN Simple Authentication and Security
   61.76 +   Layer ([SASL]) mechanism for use in protocols with no clear-text
   61.77 +   login command (e.g., [ACAP] or [SMTP-AUTH]).  This document updates
   61.78 +   RFC 2595, replacing Section 6.  Changes since RFC 2595 are detailed
   61.79 +   in Appendix A.
   61.80 +
   61.81 +   The name associated with this mechanism is "PLAIN".
   61.82 +
   61.83 +   The PLAIN SASL mechanism does not provide a security layer.
   61.84 +
   61.85 +   The PLAIN mechanism should not be used without adequate data security
   61.86 +   protection as this mechanism affords no integrity or confidentiality
   61.87 +   protections itself.  The mechanism is intended to be used with data
   61.88 +   security protections provided by application-layer protocol,
   61.89 +   generally through its use of Transport Layer Security ([TLS])
   61.90 +   services.
   61.91 +
   61.92 +   By default, implementations SHOULD advertise and make use of the
   61.93 +   PLAIN mechanism only when adequate data security services are in
   61.94 +   place.  Specifications for IETF protocols that indicate that this
   61.95 +   mechanism is an applicable authentication mechanism MUST mandate that
   61.96 +   implementations support an strong data security service, such as TLS.
   61.97 +
   61.98 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   61.99 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  61.100 +   document are to be interpreted as described in [Keywords].
  61.101 +
  61.102 +2.  PLAIN SASL Mechanism
  61.103 +
  61.104 +   The mechanism consists of a single message, a string of [UTF-8]
  61.105 +   encoded [Unicode] characters, from the client to the server.  The
  61.106 +   client presents the authorization identity (identity to act as),
  61.107 +   followed by a NUL (U+0000) character, followed by the authentication
  61.108 +   identity (identity whose password will be used), followed by a NUL
  61.109 +   (U+0000) character, followed by the clear-text password.  As with
  61.110 +   other SASL mechanisms, the client does not provide an authorization
  61.111 +   identity when it wishes the server to derive an identity from the
  61.112 +   credentials and use that as the authorization identity.
  61.113 +
  61.114 +
  61.115 +
  61.116 +
  61.117 +Zeilenga                    Standards Track                     [Page 2]
  61.118 +
  61.119 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.120 +
  61.121 +
  61.122 +   The formal grammar for the client message using Augmented BNF [ABNF]
  61.123 +   follows.
  61.124 +
  61.125 +   message   = [authzid] UTF8NUL authcid UTF8NUL passwd
  61.126 +   authcid   = 1*SAFE ; MUST accept up to 255 octets
  61.127 +   authzid   = 1*SAFE ; MUST accept up to 255 octets
  61.128 +   passwd    = 1*SAFE ; MUST accept up to 255 octets
  61.129 +   UTF8NUL   = %x00 ; UTF-8 encoded NUL character
  61.130 +
  61.131 +   SAFE      = UTF1 / UTF2 / UTF3 / UTF4
  61.132 +               ;; any UTF-8 encoded Unicode character except NUL
  61.133 +
  61.134 +   UTF1      = %x01-7F ;; except NUL
  61.135 +   UTF2      = %xC2-DF UTF0
  61.136 +   UTF3      = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
  61.137 +               %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
  61.138 +   UTF4      = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
  61.139 +               %xF4 %x80-8F 2(UTF0)
  61.140 +   UTF0      = %x80-BF
  61.141 +
  61.142 +   The authorization identity (authzid), authentication identity
  61.143 +   (authcid), password (passwd), and NUL character deliminators SHALL be
  61.144 +   transferred as [UTF-8] encoded strings of [Unicode] characters.  As
  61.145 +   the NUL (U+0000) character is used as a deliminator, the NUL (U+0000)
  61.146 +   character MUST NOT appear in authzid, authcid, or passwd productions.
  61.147 +
  61.148 +   The form of the authzid production is specific to the application-
  61.149 +   level protocol's SASL profile [SASL].  The authcid and passwd
  61.150 +   productions are form-free.  Use of non-visible characters or
  61.151 +   characters that a user may be unable to enter on some keyboards is
  61.152 +   discouraged.
  61.153 +
  61.154 +   Servers MUST be capable of accepting authzid, authcid, and passwd
  61.155 +   productions up to and including 255 octets.  It is noted that the
  61.156 +   UTF-8 encoding of a Unicode character may be as long as 4 octets.
  61.157 +
  61.158 +   Upon receipt of the message, the server will verify the presented (in
  61.159 +   the message) authentication identity (authcid) and password (passwd)
  61.160 +   with the system authentication database, and it will verify that the
  61.161 +   authentication credentials permit the client to act as the (presented
  61.162 +   or derived) authorization identity (authzid).  If both steps succeed,
  61.163 +   the user is authenticated.
  61.164 +
  61.165 +   The presented authentication identity and password strings, as well
  61.166 +   as the database authentication identity and password strings, are to
  61.167 +   be prepared before being used in the verification process.  The
  61.168 +   [SASLPrep] profile of the [StringPrep] algorithm is the RECOMMENDED
  61.169 +   preparation algorithm.  The SASLprep preparation algorithm is
  61.170 +
  61.171 +
  61.172 +
  61.173 +Zeilenga                    Standards Track                     [Page 3]
  61.174 +
  61.175 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.176 +
  61.177 +
  61.178 +   recommended to improve the likelihood that comparisons behave in an
  61.179 +   expected manner.  The SASLprep preparation algorithm is not mandatory
  61.180 +   so as to allow the server to employ other preparation algorithms
  61.181 +   (including none) when appropriate.  For instance, use of a different
  61.182 +   preparation algorithm may be necessary for the server to interoperate
  61.183 +   with an external system.
  61.184 +
  61.185 +   When preparing the presented strings using [SASLPrep], the presented
  61.186 +   strings are to be treated as "query" strings (Section 7 of
  61.187 +   [StringPrep]) and hence unassigned code points are allowed to appear
  61.188 +   in their prepared output.  When preparing the database strings using
  61.189 +   [SASLPrep], the database strings are to be treated as "stored"
  61.190 +   strings (Section 7 of [StringPrep]) and hence unassigned code points
  61.191 +   are prohibited from appearing in their prepared output.
  61.192 +
  61.193 +   Regardless of the preparation algorithm used, if the output of a
  61.194 +   non-invertible function (e.g., hash) of the expected string is
  61.195 +   stored, the string MUST be prepared before input to that function.
  61.196 +
  61.197 +   Regardless of the preparation algorithm used, if preparation fails or
  61.198 +   results in an empty string, verification SHALL fail.
  61.199 +
  61.200 +   When no authorization identity is provided, the server derives an
  61.201 +   authorization identity from the prepared representation of the
  61.202 +   provided authentication identity string.  This ensures that the
  61.203 +   derivation of different representations of the authentication
  61.204 +   identity produces the same authorization identity.
  61.205 +
  61.206 +   The server MAY use the credentials to initialize any new
  61.207 +   authentication database, such as one suitable for [CRAM-MD5] or
  61.208 +   [DIGEST-MD5].
  61.209 +
  61.210 +3.  Pseudo-Code
  61.211 +
  61.212 +   This section provides pseudo-code illustrating the verification
  61.213 +   process (using hashed passwords and the SASLprep preparation
  61.214 +   function) discussed above.  This section is not definitive.
  61.215 +
  61.216 +   boolean Verify(string authzid, string authcid, string passwd) {
  61.217 +     string pAuthcid = SASLprep(authcid, true); # prepare authcid
  61.218 +     string pPasswd = SASLprep(passwd, true);   # prepare passwd
  61.219 +     if (pAuthcid == NULL || pPasswd == NULL) {
  61.220 +       return false;     # preparation failed
  61.221 +     }
  61.222 +     if (pAuthcid == "" || pPasswd == "") {
  61.223 +       return false;     # empty prepared string
  61.224 +     }
  61.225 +
  61.226 +
  61.227 +
  61.228 +
  61.229 +Zeilenga                    Standards Track                     [Page 4]
  61.230 +
  61.231 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.232 +
  61.233 +
  61.234 +     storedHash = FetchPasswordHash(pAuthcid);
  61.235 +     if (storedHash == NULL || storedHash == "") {
  61.236 +       return false;     # error or unknown authcid
  61.237 +     }
  61.238 +
  61.239 +     if (!Compare(storedHash, Hash(pPasswd))) {
  61.240 +       return false;     # incorrect password
  61.241 +     }
  61.242 +
  61.243 +     if (authzid == NULL ) {
  61.244 +       authzid = DeriveAuthzid(pAuthcid);
  61.245 +       if (authzid == NULL || authzid == "") {
  61.246 +           return false; # could not derive authzid
  61.247 +       }
  61.248 +     }
  61.249 +
  61.250 +     if (!Authorize(pAuthcid, authzid)) {
  61.251 +       return false;     # not authorized
  61.252 +     }
  61.253 +
  61.254 +     return true;
  61.255 +   }
  61.256 +
  61.257 +   The second parameter of the SASLprep function, when true, indicates
  61.258 +   that unassigned code points are allowed in the input.  When the
  61.259 +   SASLprep function is called to prepare the password prior to
  61.260 +   computing the stored hash, the second parameter would be false.
  61.261 +
  61.262 +   The second parameter provided to the Authorize function is not
  61.263 +   prepared by this code.  The application-level SASL profile should be
  61.264 +   consulted to determine what, if any, preparation is necessary.
  61.265 +
  61.266 +   Note that the DeriveAuthzid and Authorize functions (whether
  61.267 +   implemented as one function or two, whether designed in a manner in
  61.268 +   which these functions or whether the mechanism implementation can be
  61.269 +   reused elsewhere) require knowledge and understanding of mechanism
  61.270 +   and the application-level protocol specification and/or
  61.271 +   implementation details to implement.
  61.272 +
  61.273 +   Note that the Authorize function outcome is clearly dependent on
  61.274 +   details of the local authorization model and policy.  Both functions
  61.275 +   may be dependent on other factors as well.
  61.276 +
  61.277 +
  61.278 +
  61.279 +
  61.280 +
  61.281 +
  61.282 +
  61.283 +
  61.284 +
  61.285 +Zeilenga                    Standards Track                     [Page 5]
  61.286 +
  61.287 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.288 +
  61.289 +
  61.290 +4.  Examples
  61.291 +
  61.292 +   This section provides examples of PLAIN authentication exchanges.
  61.293 +   The examples are intended to help the readers understand the above
  61.294 +   text.  The examples are not definitive.
  61.295 +
  61.296 +   "C:" and "S:" indicate lines sent by the client and server,
  61.297 +   respectively.  "<NUL>" represents a single NUL (U+0000) character.
  61.298 +   The Application Configuration Access Protocol ([ACAP]) is used in the
  61.299 +   examples.
  61.300 +
  61.301 +   The first example shows how the PLAIN mechanism might be used for
  61.302 +   user authentication.
  61.303 +
  61.304 +   S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
  61.305 +   C: a001 STARTTLS
  61.306 +   S: a001 OK "Begin TLS negotiation now"
  61.307 +   <TLS negotiation, further commands are under TLS layer>
  61.308 +   S: * ACAP (SASL "CRAM-MD5" "PLAIN")
  61.309 +   C: a002 AUTHENTICATE "PLAIN"
  61.310 +   S: + ""
  61.311 +   C: {21}
  61.312 +   C: <NUL>tim<NUL>tanstaaftanstaaf
  61.313 +   S: a002 OK "Authenticated"
  61.314 +
  61.315 +   The second example shows how the PLAIN mechanism might be used to
  61.316 +   attempt to assume the identity of another user.  In this example, the
  61.317 +   server rejects the request.  Also, this example makes use of the
  61.318 +   protocol optional initial response capability to eliminate a round-
  61.319 +   trip.
  61.320 +
  61.321 +   S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
  61.322 +   C: a001 STARTTLS
  61.323 +   S: a001 OK "Begin TLS negotiation now"
  61.324 +   <TLS negotiation, further commands are under TLS layer>
  61.325 +   S: * ACAP (SASL "CRAM-MD5" "PLAIN")
  61.326 +   C: a002 AUTHENTICATE "PLAIN" {20+}
  61.327 +   C: Ursel<NUL>Kurt<NUL>xipj3plmq
  61.328 +   S: a002 NO "Not authorized to requested authorization identity"
  61.329 +
  61.330 +5.  Security Considerations
  61.331 +
  61.332 +   As the PLAIN mechanism itself provided no integrity or
  61.333 +   confidentiality protections, it should not be used without adequate
  61.334 +   external data security protection, such as TLS services provided by
  61.335 +   many application-layer protocols.  By default, implementations SHOULD
  61.336 +   NOT advertise and SHOULD NOT make use of the PLAIN mechanism unless
  61.337 +   adequate data security services are in place.
  61.338 +
  61.339 +
  61.340 +
  61.341 +Zeilenga                    Standards Track                     [Page 6]
  61.342 +
  61.343 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.344 +
  61.345 +
  61.346 +   When the PLAIN mechanism is used, the server gains the ability to
  61.347 +   impersonate the user to all services with the same password
  61.348 +   regardless of any encryption provided by TLS or other confidentiality
  61.349 +   protection mechanisms.  Whereas many other authentication mechanisms
  61.350 +   have similar weaknesses, stronger SASL mechanisms address this issue.
  61.351 +   Clients are encouraged to have an operational mode where all
  61.352 +   mechanisms that are likely to reveal the user's password to the
  61.353 +   server are disabled.
  61.354 +
  61.355 +   General [SASL] security considerations apply to this mechanism.
  61.356 +
  61.357 +   Unicode, [UTF-8], and [StringPrep] security considerations also
  61.358 +   apply.
  61.359 +
  61.360 +6.  IANA Considerations
  61.361 +
  61.362 +   The SASL Mechanism registry [IANA-SASL] entry for the PLAIN mechanism
  61.363 +   has been updated by the IANA to reflect that this document now
  61.364 +   provides its technical specification.
  61.365 +
  61.366 +   To: iana@iana.org
  61.367 +   Subject: Updated Registration of SASL mechanism PLAIN
  61.368 +
  61.369 +   SASL mechanism name: PLAIN
  61.370 +   Security considerations: See RFC 4616.
  61.371 +   Published specification (optional, recommended): RFC 4616
  61.372 +   Person & email address to contact for further information:
  61.373 +        Kurt Zeilenga <kurt@openldap.org>
  61.374 +        IETF SASL WG <ietf-sasl@imc.org>
  61.375 +   Intended usage: COMMON
  61.376 +   Author/Change controller: IESG <iesg@ietf.org>
  61.377 +   Note: Updates existing entry for PLAIN
  61.378 +
  61.379 +7.  Acknowledgements
  61.380 +
  61.381 +   This document is a revision of RFC 2595 by Chris Newman.  Portions of
  61.382 +   the grammar defined in Section 2 were borrowed from [UTF-8] by
  61.383 +   Francois Yergeau.
  61.384 +
  61.385 +   This document is a product of the IETF Simple Authentication and
  61.386 +   Security Layer (SASL) Working Group.
  61.387 +
  61.388 +
  61.389 +
  61.390 +
  61.391 +
  61.392 +
  61.393 +
  61.394 +
  61.395 +
  61.396 +
  61.397 +Zeilenga                    Standards Track                     [Page 7]
  61.398 +
  61.399 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.400 +
  61.401 +
  61.402 +8.  Normative References
  61.403 +
  61.404 +   [ABNF]        Crocker, D., Ed. and P. Overell, "Augmented BNF for
  61.405 +                 Syntax Specifications: ABNF", RFC 4234, October 2005.
  61.406 +
  61.407 +   [Keywords]    Bradner, S., "Key words for use in RFCs to Indicate
  61.408 +                 Requirement Levels", BCP 14, RFC 2119, March 1997.
  61.409 +
  61.410 +   [SASL]        Melnikov, A., Ed., and K. Zeilenga, Ed., "Simple
  61.411 +                 Authentication and Security Layer (SASL)", RFC 4422,
  61.412 +                 June 2006.
  61.413 +
  61.414 +   [SASLPrep]    Zeilenga, K., "SASLprep: Stringprep Profile for User
  61.415 +                 Names and Passwords", RFC 4013, February 2005.
  61.416 +
  61.417 +   [StringPrep]  Hoffman, P. and M. Blanchet, "Preparation of
  61.418 +                 Internationalized Strings ("stringprep")", RFC 3454,
  61.419 +                 December 2002.
  61.420 +
  61.421 +   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
  61.422 +                 3.2.0" is defined by "The Unicode Standard, Version
  61.423 +                 3.0" (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-
  61.424 +                 61633-5), as amended by the "Unicode Standard Annex
  61.425 +                 #27: Unicode 3.1"
  61.426 +                 (http://www.unicode.org/reports/tr27/) and by the
  61.427 +                 "Unicode Standard Annex #28: Unicode 3.2"
  61.428 +                 (http://www.unicode.org/reports/tr28/).
  61.429 +
  61.430 +   [UTF-8]       Yergeau, F., "UTF-8, a transformation format of ISO
  61.431 +                 10646", STD 63, RFC 3629, November 2003.
  61.432 +
  61.433 +   [TLS]         Dierks, T. and E. Rescorla, "The Transport Layer
  61.434 +                 Security (TLS) Protocol Version 1.1", RFC 4346, April
  61.435 +                 2006.
  61.436 +
  61.437 +9.  Informative References
  61.438 +
  61.439 +   [ACAP]        Newman, C. and J. Myers, "ACAP -- Application
  61.440 +                 Configuration Access Protocol", RFC 2244, November
  61.441 +                 1997.
  61.442 +
  61.443 +   [CRAM-MD5]    Nerenberg, L., Ed., "The CRAM-MD5 SASL Mechanism", Work
  61.444 +                 in Progress, June 2006.
  61.445 +
  61.446 +   [DIGEST-MD5]  Melnikov, A., Ed., "Using Digest Authentication as a
  61.447 +                 SASL Mechanism", Work in Progress, June 2006.
  61.448 +
  61.449 +
  61.450 +
  61.451 +
  61.452 +
  61.453 +Zeilenga                    Standards Track                     [Page 8]
  61.454 +
  61.455 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.456 +
  61.457 +
  61.458 +   [IANA-SASL]   IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL)
  61.459 +                 MECHANISMS",
  61.460 +                 <http://www.iana.org/assignments/sasl-mechanisms>.
  61.461 +
  61.462 +   [SMTP-AUTH]   Myers, J., "SMTP Service Extension for Authentication",
  61.463 +                 RFC 2554, March 1999.
  61.464 +
  61.465 +
  61.466 +
  61.467 +
  61.468 +
  61.469 +
  61.470 +
  61.471 +
  61.472 +
  61.473 +
  61.474 +
  61.475 +
  61.476 +
  61.477 +
  61.478 +
  61.479 +
  61.480 +
  61.481 +
  61.482 +
  61.483 +
  61.484 +
  61.485 +
  61.486 +
  61.487 +
  61.488 +
  61.489 +
  61.490 +
  61.491 +
  61.492 +
  61.493 +
  61.494 +
  61.495 +
  61.496 +
  61.497 +
  61.498 +
  61.499 +
  61.500 +
  61.501 +
  61.502 +
  61.503 +
  61.504 +
  61.505 +
  61.506 +
  61.507 +
  61.508 +
  61.509 +Zeilenga                    Standards Track                     [Page 9]
  61.510 +
  61.511 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.512 +
  61.513 +
  61.514 +Appendix A.  Changes since RFC 2595
  61.515 +
  61.516 +   This appendix is non-normative.
  61.517 +
  61.518 +   This document replaces Section 6 of RFC 2595.
  61.519 +
  61.520 +   The specification details how the server is to compare client-
  61.521 +   provided character strings with stored character strings.
  61.522 +
  61.523 +   The ABNF grammar was updated.  In particular, the grammar now allows
  61.524 +   LINE FEED (U+000A) and CARRIAGE RETURN (U+000D) characters in the
  61.525 +   authzid, authcid, passwd productions.  However, whether these control
  61.526 +   characters may be used depends on the string preparation rules
  61.527 +   applicable to the production.  For passwd and authcid productions,
  61.528 +   control characters are prohibited.  For authzid, one must consult the
  61.529 +   application-level SASL profile.  This change allows PLAIN to carry
  61.530 +   all possible authorization identity strings allowed in SASL.
  61.531 +
  61.532 +   Pseudo-code was added.
  61.533 +
  61.534 +   The example section was expanded to illustrate more features of the
  61.535 +   PLAIN mechanism.
  61.536 +
  61.537 +Editor's Address
  61.538 +
  61.539 +   Kurt D. Zeilenga
  61.540 +   OpenLDAP Foundation
  61.541 +
  61.542 +   EMail: Kurt@OpenLDAP.org
  61.543 +
  61.544 +
  61.545 +
  61.546 +
  61.547 +
  61.548 +
  61.549 +
  61.550 +
  61.551 +
  61.552 +
  61.553 +
  61.554 +
  61.555 +
  61.556 +
  61.557 +
  61.558 +
  61.559 +
  61.560 +
  61.561 +
  61.562 +
  61.563 +
  61.564 +
  61.565 +Zeilenga                    Standards Track                    [Page 10]
  61.566 +
  61.567 +RFC 4616                The PLAIN SASL Mechanism             August 2006
  61.568 +
  61.569 +
  61.570 +Full Copyright Statement
  61.571 +
  61.572 +   Copyright (C) The Internet Society (2006).
  61.573 +
  61.574 +   This document is subject to the rights, licenses and restrictions
  61.575 +   contained in BCP 78, and except as set forth therein, the authors
  61.576 +   retain all their rights.
  61.577 +
  61.578 +   This document and the information contained herein are provided on an
  61.579 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  61.580 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
  61.581 +   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
  61.582 +   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  61.583 +   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  61.584 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  61.585 +
  61.586 +Intellectual Property
  61.587 +
  61.588 +   The IETF takes no position regarding the validity or scope of any
  61.589 +   Intellectual Property Rights or other rights that might be claimed to
  61.590 +   pertain to the implementation or use of the technology described in
  61.591 +   this document or the extent to which any license under such rights
  61.592 +   might or might not be available; nor does it represent that it has
  61.593 +   made any independent effort to identify any such rights.  Information
  61.594 +   on the procedures with respect to rights in RFC documents can be
  61.595 +   found in BCP 78 and BCP 79.
  61.596 +
  61.597 +   Copies of IPR disclosures made to the IETF Secretariat and any
  61.598 +   assurances of licenses to be made available, or the result of an
  61.599 +   attempt made to obtain a general license or permission for the use of
  61.600 +   such proprietary rights by implementers or users of this
  61.601 +   specification can be obtained from the IETF on-line IPR repository at
  61.602 +   http://www.ietf.org/ipr.
  61.603 +
  61.604 +   The IETF invites any interested party to bring to its attention any
  61.605 +   copyrights, patents or patent applications, or other proprietary
  61.606 +   rights that may cover technology that may be required to implement
  61.607 +   this standard.  Please address the information to the IETF at
  61.608 +   ietf-ipr@ietf.org.
  61.609 +
  61.610 +Acknowledgement
  61.611 +
  61.612 +   Funding for the RFC Editor function is provided by the IETF
  61.613 +   Administrative Support Activity (IASA).
  61.614 +
  61.615 +
  61.616 +
  61.617 +
  61.618 +
  61.619 +
  61.620 +
  61.621 +Zeilenga                    Standards Track                    [Page 11]
  61.622 +
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/docs/rfc/rfc4731.txt	Mon Sep 14 15:17:45 2009 +0900
    62.3 @@ -0,0 +1,451 @@
    62.4 +
    62.5 +
    62.6 +
    62.7 +
    62.8 +
    62.9 +
   62.10 +Network Working Group                                        A. Melnikov
   62.11 +Request for Comments: 4731                                     Isode Ltd
   62.12 +Category: Standards Track                                    D. Cridland
   62.13 +                                                   Inventure Systems Ltd
   62.14 +                                                           November 2006
   62.15 +
   62.16 +
   62.17 +           IMAP4 Extension to SEARCH Command for Controlling
   62.18 +                  What Kind of Information Is Returned
   62.19 +
   62.20 +Status of This Memo
   62.21 +
   62.22 +   This document specifies an Internet standards track protocol for the
   62.23 +   Internet community, and requests discussion and suggestions for
   62.24 +   improvements.  Please refer to the current edition of the "Internet
   62.25 +   Official Protocol Standards" (STD 1) for the standardization state
   62.26 +   and status of this protocol.  Distribution of this memo is unlimited.
   62.27 +
   62.28 +Copyright Notice
   62.29 +
   62.30 +   Copyright (C) The IETF Trust (2006).
   62.31 +
   62.32 +Abstract
   62.33 +
   62.34 +   This document extends IMAP (RFC 3501) SEARCH and UID SEARCH commands
   62.35 +   with several result options, which can control what kind of
   62.36 +   information is returned. The following result options are defined:
   62.37 +   minimal value, maximal value, all found messages, and number of found
   62.38 +   messages.
   62.39 +
   62.40 +Table of Contents
   62.41 +
   62.42 +   1. Introduction ....................................................2
   62.43 +   2. Conventions Used in This Document ...............................2
   62.44 +   3. IMAP Protocol Changes ...........................................2
   62.45 +      3.1. New SEARCH/UID SEARCH Result Options .......................2
   62.46 +      3.2. Interaction with CONDSTORE extension .......................4
   62.47 +   4. Formal Syntax ...................................................5
   62.48 +   5. Security Considerations .........................................6
   62.49 +   6. IANA Considerations .............................................6
   62.50 +   7. Normative References ............................................6
   62.51 +   8. Acknowledgments .................................................6
   62.52 +
   62.53 +
   62.54 +
   62.55 +
   62.56 +
   62.57 +
   62.58 +
   62.59 +
   62.60 +
   62.61 +Melnikov & Cridland         Standards Track                     [Page 1]
   62.62 +
   62.63 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
   62.64 +
   62.65 +
   62.66 +1.  Introduction
   62.67 +
   62.68 +   [IMAPABNF] extended SEARCH and UID SEARCH commands with result
   62.69 +   specifiers (also known as result options), which can control what
   62.70 +   kind of information is returned.
   62.71 +
   62.72 +   A server advertising the ESEARCH capability supports the following
   62.73 +   result options:  minimal value, maximal value, all found messages,
   62.74 +   and number of found messages.  These result options allow clients to
   62.75 +   get SEARCH results in more convenient forms, while also saving
   62.76 +   bandwidth required to transport the results, for example, by finding
   62.77 +   the first unseen message or returning the number of unseen or deleted
   62.78 +   messages.  Also, when a single MIN or a single MAX result option is
   62.79 +   specified, servers can optimize execution of SEARCHes.
   62.80 +
   62.81 +2.  Conventions Used in This Document
   62.82 +
   62.83 +   In examples, "C:" and "S:" indicate lines sent by the client and
   62.84 +   server, respectively.
   62.85 +
   62.86 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   62.87 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   62.88 +   document are to be interpreted as described in RFC 2119 [KEYWORDS].
   62.89 +
   62.90 +3.   IMAP Protocol Changes
   62.91 +
   62.92 +3.1.  New SEARCH/UID SEARCH Result Options
   62.93 +
   62.94 +   The SEARCH/UID SEARCH commands are extended to allow for the
   62.95 +   following result options:
   62.96 +
   62.97 +      MIN
   62.98 +         Return the lowest message number/UID that satisfies the SEARCH
   62.99 +         criteria.
  62.100 +
  62.101 +         If the SEARCH results in no matches, the server MUST NOT
  62.102 +         include the MIN result option in the ESEARCH response; however,
  62.103 +         it still MUST send the ESEARCH response.
  62.104 +
  62.105 +      MAX
  62.106 +         Return the highest message number/UID that satisfies the SEARCH
  62.107 +         criteria.
  62.108 +
  62.109 +         If the SEARCH results in no matches, the server MUST NOT
  62.110 +         include the MAX result option in the ESEARCH response; however,
  62.111 +         it still MUST send the ESEARCH response.
  62.112 +
  62.113 +
  62.114 +
  62.115 +
  62.116 +
  62.117 +Melnikov & Cridland         Standards Track                     [Page 2]
  62.118 +
  62.119 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
  62.120 +
  62.121 +
  62.122 +      ALL
  62.123 +         Return all message numbers/UIDs that satisfy the SEARCH
  62.124 +         criteria.  Unlike regular (unextended) SEARCH, the messages are
  62.125 +         always returned using the sequence-set syntax.  A sequence-set
  62.126 +         representation may be more compact and can be used as is in a
  62.127 +         subsequent command that accepts sequence-set.  Note, the client
  62.128 +         MUST NOT assume that messages/UIDs will be listed in any
  62.129 +         particular order.
  62.130 +
  62.131 +         If the SEARCH results in no matches, the server MUST NOT
  62.132 +         include the ALL result option in the ESEARCH response; however,
  62.133 +         it still MUST send the ESEARCH response.
  62.134 +
  62.135 +      COUNT
  62.136 +         Return number of the messages that satisfy the SEARCH criteria.
  62.137 +         This result option MUST always be included in the ESEARCH
  62.138 +         response.
  62.139 +
  62.140 +   If one or more result options described above are specified, the
  62.141 +   extended SEARCH command MUST return a single ESEARCH response
  62.142 +   [IMAPABNF], instead of the SEARCH response.
  62.143 +
  62.144 +   An extended UID SEARCH command MUST cause an ESEARCH response with
  62.145 +   the UID indicator present.
  62.146 +
  62.147 +   Note that future extensions to this document can allow servers to
  62.148 +   return multiple ESEARCH responses for a single extended SEARCH
  62.149 +   command.  These extensions will have to describe how results from
  62.150 +   multiple ESEARCH responses are to be amalgamated.
  62.151 +
  62.152 +   If the list of result options is empty, that requests the server to
  62.153 +   return an ESEARCH response instead of the SEARCH response.  This is
  62.154 +   equivalent to "(ALL)".
  62.155 +
  62.156 +      Example:    C: A282 SEARCH RETURN (MIN COUNT) FLAGGED
  62.157 +                     SINCE 1-Feb-1994 NOT FROM "Smith"
  62.158 +                  S: * ESEARCH (TAG "A282") MIN 2 COUNT 3
  62.159 +                  S: A282 OK SEARCH completed
  62.160 +
  62.161 +      Example:    C: A283 SEARCH RETURN () FLAGGED
  62.162 +                     SINCE 1-Feb-1994 NOT FROM "Smith"
  62.163 +                  S: * ESEARCH (TAG "A283") ALL 2,10:11
  62.164 +                  S: A283 OK SEARCH completed
  62.165 +
  62.166 +   The following example demonstrates finding the first unseen message
  62.167 +   as returned in the UNSEEN response code on a successful SELECT
  62.168 +   command:
  62.169 +
  62.170 +
  62.171 +
  62.172 +
  62.173 +Melnikov & Cridland         Standards Track                     [Page 3]
  62.174 +
  62.175 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
  62.176 +
  62.177 +
  62.178 +      Example:    C: A284 SEARCH RETURN (MIN) UNSEEN
  62.179 +                  S: * ESEARCH (TAG "A284") MIN 4
  62.180 +                  S: A284 OK SEARCH completed
  62.181 +
  62.182 +   The following example demonstrates that if the ESEARCH UID indicator
  62.183 +   is present, all data in the ESEARCH response is referring to UIDs;
  62.184 +   for example, the MIN result specifier will be followed by a UID.
  62.185 +
  62.186 +      Example:    C: A285 UID SEARCH RETURN (MIN MAX) 1:5000
  62.187 +                  S: * ESEARCH (TAG "A285") UID MIN 7 MAX 3800
  62.188 +                  S: A285 OK SEARCH completed
  62.189 +
  62.190 +   The following example demonstrates returning the number of deleted
  62.191 +   messages:
  62.192 +
  62.193 +      Example:    C: A286 SEARCH RETURN (COUNT) DELETED
  62.194 +                  S: * ESEARCH (TAG "A286") COUNT 15
  62.195 +                  S: A286 OK SEARCH completed
  62.196 +
  62.197 +3.2.  Interaction with CONDSTORE extension
  62.198 +
  62.199 +   When the server supports both the ESEARCH and the CONDSTORE
  62.200 +   [CONDSTORE] extension, and the client requests one or more result
  62.201 +   option described in section 3.1 together with the MODSEQ search
  62.202 +   criterion in the same SEARCH/UID SEARCH command, then the server MUST
  62.203 +   return the ESEARCH response containing the MODSEQ result option
  62.204 +   (described in the following paragraph) instead of the extended SEARCH
  62.205 +   response described in section 3.5 of [CONDSTORE].
  62.206 +
  62.207 +   If the SEARCH/UID SEARCH command contained a single MIN or MAX result
  62.208 +   option, the MODSEQ result option contains the mod-sequence for the
  62.209 +   found message.  If the SEARCH/UID SEARCH command contained both MIN
  62.210 +   and MAX result options and no ALL/COUNT option, the MODSEQ result
  62.211 +   option contains the highest mod-sequence for the two returned
  62.212 +   messages.  Otherwise the MODSEQ result option contains the highest
  62.213 +   mod-sequence for all messages being returned.
  62.214 +
  62.215 +   Example: The following example demonstrates how Example 15 from
  62.216 +   [CONDSTORE] would look in the presence of one or more result option:
  62.217 +
  62.218 +         C: a1 SEARCH RETURN (MIN) MODSEQ "/flags/\\draft"
  62.219 +             all 620162338
  62.220 +         S: * ESEARCH (TAG "a1") MIN 2 MODSEQ 917162488
  62.221 +         S: a1 OK Search complete
  62.222 +
  62.223 +         C: a2 SEARCH RETURN (MAX) MODSEQ "/flags/\\draft"
  62.224 +             all 620162338
  62.225 +         S: * ESEARCH (TAG "a2") MAX 23 MODSEQ 907162321
  62.226 +
  62.227 +
  62.228 +
  62.229 +Melnikov & Cridland         Standards Track                     [Page 4]
  62.230 +
  62.231 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
  62.232 +
  62.233 +
  62.234 +         S: a2 OK Search complete
  62.235 +
  62.236 +         C: a3 SEARCH RETURN (MIN MAX) MODSEQ "/flags/\\draft"
  62.237 +             all 620162338
  62.238 +         S: * ESEARCH (TAG "a3") MIN 2 MAX 23 MODSEQ 917162488
  62.239 +         S: a3 OK Search complete
  62.240 +
  62.241 +         C: a4 SEARCH RETURN (MIN COUNT) MODSEQ "/flags/\\draft"
  62.242 +             all 620162338
  62.243 +         S: * ESEARCH (TAG "a4") MIN 2 COUNT 10 MODSEQ 917162500
  62.244 +         S: a4 OK Search complete
  62.245 +
  62.246 +4.  Formal Syntax
  62.247 +
  62.248 +   The following syntax specification uses the Augmented Backus-Naur
  62.249 +   Form (ABNF) notation as specified in [ABNF].
  62.250 +
  62.251 +   Non-terminals referenced but not defined below are as defined by
  62.252 +   [IMAP4], [CONDSTORE], or [IMAPABNF].
  62.253 +
  62.254 +   Except as noted otherwise, all alphabetic characters are case-
  62.255 +   insensitive.  The use of upper or lowercase characters to define
  62.256 +   token strings is for editorial clarity only.  Implementations MUST
  62.257 +   accept these strings in a case-insensitive fashion.
  62.258 +
  62.259 +     capability         =/ "ESEARCH"
  62.260 +
  62.261 +     search-return-data = "MIN" SP nz-number /
  62.262 +                          "MAX" SP nz-number /
  62.263 +                          "ALL" SP sequence-set /
  62.264 +                          "COUNT" SP number
  62.265 +                          ;; conforms to the generic
  62.266 +                          ;; search-return-data syntax defined
  62.267 +                          ;; in [IMAPABNF]
  62.268 +
  62.269 +     search-return-opt  = "MIN" / "MAX" / "ALL" / "COUNT"
  62.270 +                          ;; conforms to generic search-return-opt
  62.271 +                          ;; syntax defined in [IMAPABNF]
  62.272 +
  62.273 +     When the CONDSTORE [CONDSTORE] IMAP extension is also supported,
  62.274 +     the ABNF is updated as follows:
  62.275 +
  62.276 +     search-return-data =/ "MODSEQ" SP mod-sequence-value
  62.277 +                          ;; mod-sequence-value is defined
  62.278 +                          ;; in [CONDSTORE]
  62.279 +
  62.280 +
  62.281 +
  62.282 +
  62.283 +
  62.284 +
  62.285 +Melnikov & Cridland         Standards Track                     [Page 5]
  62.286 +
  62.287 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
  62.288 +
  62.289 +
  62.290 +5.  Security Considerations
  62.291 +
  62.292 +   In the general case, the IMAP SEARCH/UID SEARCH commands can be CPU
  62.293 +   and/or IO intensive, and are seen by some as a potential attack point
  62.294 +   for denial of service attacks, so some sites/implementations even
  62.295 +   disable them entirely.  This is quite unfortunate, as SEARCH command
  62.296 +   is one of the best examples demonstrating IMAP advantage over POP3.
  62.297 +
  62.298 +   The ALL and COUNT return options don't change how SEARCH is working
  62.299 +   internally; they only change how information about found messages is
  62.300 +   returned.  MIN and MAX SEARCH result options described in this
  62.301 +   document can lighten the load on IMAP servers that choose to optimize
  62.302 +   SEARCHes containing only one or both of them.
  62.303 +
  62.304 +   It is believed that this extension doesn't raise any additional
  62.305 +   security concerns not already discussed in [IMAP4].
  62.306 +
  62.307 +6.  IANA Considerations
  62.308 +
  62.309 +   IMAP4 capabilities are registered by publishing a standards track RFC
  62.310 +   or an IESG-approved experimental RFC.  The registry is currently
  62.311 +   located at <http://www.iana.org/assignments/imap4-capabilities>.
  62.312 +
  62.313 +   This document defines the ESEARCH IMAP capability, which IANA added
  62.314 +   to the registry.
  62.315 +
  62.316 +7.  Normative References
  62.317 +
  62.318 +   [KEYWORDS]  Bradner, S., "Key words for use in RFCs to Indicate
  62.319 +               Requirement Levels", BCP 14, RFC 2119, March 1997.
  62.320 +
  62.321 +   [IMAP4]     Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  62.322 +               4rev1", RFC 3501, March 2003.
  62.323 +
  62.324 +   [ABNF]      Crocker, D. (Ed.) and P. Overell , "Augmented BNF for
  62.325 +               Syntax Specifications: ABNF", RFC 4234, October 2005.
  62.326 +
  62.327 +   [IMAPABNF]  Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4
  62.328 +               ABNF", RFC 4466, April 2006..
  62.329 +
  62.330 +   [CONDSTORE] Melnikov, A. and S. Hole, "IMAP Extension for Conditional
  62.331 +               STORE", RFC 4551, June 2006.
  62.332 +
  62.333 +8.  Acknowledgments
  62.334 +
  62.335 +   Thanks to Michael Wener, Arnt Gulbrandsen, Cyrus Daboo, Mark Crispin,
  62.336 +   and Pete Maclean for comments and corrections.
  62.337 +
  62.338 +
  62.339 +
  62.340 +
  62.341 +Melnikov & Cridland         Standards Track                     [Page 6]
  62.342 +
  62.343 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
  62.344 +
  62.345 +
  62.346 +Authors' Addresses
  62.347 +
  62.348 +   Alexey Melnikov
  62.349 +   Isode Limited
  62.350 +   5 Castle Business Village
  62.351 +   36 Station Road
  62.352 +   Hampton, Middlesex, TW12 2BX
  62.353 +   UK
  62.354 +
  62.355 +   EMail: Alexey.Melnikov@isode.com
  62.356 +
  62.357 +
  62.358 +   Dave A. Cridland
  62.359 +   Inventure Systems Limited
  62.360 +
  62.361 +   EMail: dave.cridland@inventuresystems.co.uk
  62.362 +   URL: http://invsys.co.uk/dave/
  62.363 +
  62.364 +
  62.365 +
  62.366 +
  62.367 +
  62.368 +
  62.369 +
  62.370 +
  62.371 +
  62.372 +
  62.373 +
  62.374 +
  62.375 +
  62.376 +
  62.377 +
  62.378 +
  62.379 +
  62.380 +
  62.381 +
  62.382 +
  62.383 +
  62.384 +
  62.385 +
  62.386 +
  62.387 +
  62.388 +
  62.389 +
  62.390 +
  62.391 +
  62.392 +
  62.393 +
  62.394 +
  62.395 +
  62.396 +
  62.397 +Melnikov & Cridland         Standards Track                     [Page 7]
  62.398 +
  62.399 +RFC 4731               IMAP4 Extension to SEARCH           November 2006
  62.400 +
  62.401 +
  62.402 +Full Copyright Statement
  62.403 +
  62.404 +   Copyright (C) The IETF Trust (2006).
  62.405 +
  62.406 +   This document is subject to the rights, licenses and restrictions
  62.407 +   contained in BCP 78, and except as set forth therein, the authors
  62.408 +   retain all their rights.
  62.409 +
  62.410 +   This document and the information contained herein are provided on an
  62.411 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  62.412 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST,
  62.413 +   AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES,
  62.414 +   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT
  62.415 +   THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
  62.416 +   IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
  62.417 +   PURPOSE.
  62.418 +
  62.419 +Intellectual Property
  62.420 +
  62.421 +   The IETF takes no position regarding the validity or scope of any
  62.422 +   Intellectual Property Rights or other rights that might be claimed to
  62.423 +   pertain to the implementation or use of the technology described in
  62.424 +   this document or the extent to which any license under such rights
  62.425 +   might or might not be available; nor does it represent that it has
  62.426 +   made any independent effort to identify any such rights.  Information
  62.427 +   on the procedures with respect to rights in RFC documents can be
  62.428 +   found in BCP 78 and BCP 79.
  62.429 +
  62.430 +   Copies of IPR disclosures made to the IETF Secretariat and any
  62.431 +   assurances of licenses to be made available, or the result of an
  62.432 +   attempt made to obtain a general license or permission for the use of
  62.433 +   such proprietary rights by implementers or users of this
  62.434 +   specification can be obtained from the IETF on-line IPR repository at
  62.435 +   http://www.ietf.org/ipr.
  62.436 +
  62.437 +   The IETF invites any interested party to bring to its attention any
  62.438 +   copyrights, patents or patent applications, or other proprietary
  62.439 +   rights that may cover technology that may be required to implement
  62.440 +   this standard.  Please address the information to the IETF at
  62.441 +   ietf-ipr@ietf.org.
  62.442 +
  62.443 +Acknowledgement
  62.444 +
  62.445 +   Funding for the RFC Editor function is currently provided by the
  62.446 +   Internet Society.
  62.447 +
  62.448 +
  62.449 +
  62.450 +
  62.451 +
  62.452 +
  62.453 +Melnikov & Cridland         Standards Track                     [Page 8]
  62.454 +
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/docs/rfc/rfc4752.txt	Mon Sep 14 15:17:45 2009 +0900
    63.3 @@ -0,0 +1,563 @@
    63.4 +
    63.5 +
    63.6 +
    63.7 +
    63.8 +
    63.9 +
   63.10 +Network Working Group                                   A. Melnikov, Ed.
   63.11 +Request for Comments: 4752                                         Isode
   63.12 +Obsoletes: 2222                                            November 2006
   63.13 +Category: Standards Track
   63.14 +
   63.15 +
   63.16 +                       The Kerberos V5 ("GSSAPI")
   63.17 +       Simple Authentication and Security Layer (SASL) Mechanism
   63.18 +
   63.19 +Status of This Memo
   63.20 +
   63.21 +   This document specifies an Internet standards track protocol for the
   63.22 +   Internet community, and requests discussion and suggestions for
   63.23 +   improvements.  Please refer to the current edition of the "Internet
   63.24 +   Official Protocol Standards" (STD 1) for the standardization state
   63.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   63.26 +
   63.27 +Copyright Notice
   63.28 +
   63.29 +   Copyright (C) The IETF Trust (2006).
   63.30 +
   63.31 +Abstract
   63.32 +
   63.33 +   The Simple Authentication and Security Layer (SASL) is a framework
   63.34 +   for adding authentication support to connection-based protocols.
   63.35 +   This document describes the method for using the Generic Security
   63.36 +   Service Application Program Interface (GSS-API) Kerberos V5 in the
   63.37 +   SASL.
   63.38 +
   63.39 +   This document replaces Section 7.2 of RFC 2222, the definition of the
   63.40 +   "GSSAPI" SASL mechanism.  This document, together with RFC 4422,
   63.41 +   obsoletes RFC 2222.
   63.42 +
   63.43 +
   63.44 +
   63.45 +
   63.46 +
   63.47 +
   63.48 +
   63.49 +
   63.50 +
   63.51 +
   63.52 +
   63.53 +
   63.54 +
   63.55 +
   63.56 +
   63.57 +
   63.58 +
   63.59 +
   63.60 +
   63.61 +Melnikov                    Standards Track                     [Page 1]
   63.62 +
   63.63 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
   63.64 +
   63.65 +
   63.66 +Table of Contents
   63.67 +
   63.68 +   1. Introduction ....................................................2
   63.69 +      1.1. Relationship to Other Documents ............................2
   63.70 +   2. Conventions Used in This Document ...............................2
   63.71 +   3. Kerberos V5 GSS-API Mechanism ...................................2
   63.72 +      3.1. Client Side of Authentication Protocol Exchange ............3
   63.73 +      3.2. Server Side of Authentication Protocol Exchange ............4
   63.74 +      3.3. Security Layer .............................................6
   63.75 +   4. IANA Considerations .............................................7
   63.76 +   5. Security Considerations .........................................7
   63.77 +   6. Acknowledgements ................................................8
   63.78 +   7. Changes since RFC 2222 ..........................................8
   63.79 +   8. References ......................................................8
   63.80 +      8.1. Normative References .......................................8
   63.81 +      8.2. Informative References .....................................9
   63.82 +
   63.83 +1.  Introduction
   63.84 +
   63.85 +   This specification documents currently deployed Simple Authentication
   63.86 +   and Security Layer (SASL [SASL]) mechanism supporting the Kerberos V5
   63.87 +   [KERBEROS] Generic Security Service Application Program Interface
   63.88 +   ([GSS-API]) mechanism [RFC4121].  The authentication sequence is
   63.89 +   described in Section 3.  Note that the described authentication
   63.90 +   sequence has known limitations, in particular, it lacks channel
   63.91 +   bindings and the number of round-trips required to complete
   63.92 +   authentication exchange is not minimal.  SASL WG is working on a
   63.93 +   separate document that should address these limitations.
   63.94 +
   63.95 +1.1.  Relationship to Other Documents
   63.96 +
   63.97 +   This document, together with RFC 4422, obsoletes RFC 2222 in its
   63.98 +   entirety.  This document replaces Section 7.2 of RFC 2222.  The
   63.99 +   remainder is obsoleted as detailed in Section 1.2 of RFC 4422.
  63.100 +
  63.101 +2.  Conventions Used in This Document
  63.102 +
  63.103 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
  63.104 +   in this document are to be interpreted as defined in "Key words for
  63.105 +   use in RFCs to Indicate Requirement Levels" [KEYWORDS].
  63.106 +
  63.107 +3.  Kerberos V5 GSS-API Mechanism
  63.108 +
  63.109 +   The SASL mechanism name for the Kerberos V5 GSS-API mechanism
  63.110 +   [RFC4121] is "GSSAPI".  Though known as the SASL GSSAPI mechanism,
  63.111 +   the mechanism is specifically tied to Kerberos V5 and GSS-API's
  63.112 +   Kerberos V5 mechanism.
  63.113 +
  63.114 +
  63.115 +
  63.116 +
  63.117 +Melnikov                    Standards Track                     [Page 2]
  63.118 +
  63.119 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.120 +
  63.121 +
  63.122 +   The GSSAPI SASL mechanism is a "client goes first" SASL mechanism;
  63.123 +   i.e., it starts with the client sending a "response" created as
  63.124 +   described in the following section.
  63.125 +
  63.126 +   The implementation MAY set any GSS-API flags or arguments not
  63.127 +   mentioned in this specification as is necessary for the
  63.128 +   implementation to enforce its security policy.
  63.129 +
  63.130 +   Note that major status codes returned by GSS_Init_sec_context() or
  63.131 +   GSS_Accept_sec_context() other than GSS_S_COMPLETE or
  63.132 +   GSS_S_CONTINUE_NEEDED cause authentication failure.  Major status
  63.133 +   codes returned by GSS_Unwrap() other than GSS_S_COMPLETE (without any
  63.134 +   additional supplementary status codes) cause authentication and/or
  63.135 +   security layer failure.
  63.136 +
  63.137 +3.1.  Client Side of Authentication Protocol Exchange
  63.138 +
  63.139 +   The client calls GSS_Init_sec_context, passing in
  63.140 +   input_context_handle of 0 (initially), mech_type of the Kerberos V5
  63.141 +   GSS-API mechanism [KRB5GSS], chan_binding of NULL, and targ_name
  63.142 +   equal to output_name from GSS_Import_Name called with input_name_type
  63.143 +   of GSS_C_NT_HOSTBASED_SERVICE (*) and input_name_string of
  63.144 +   "service@hostname" where "service" is the service name specified in
  63.145 +   the protocol's profile, and "hostname" is the fully qualified host
  63.146 +   name of the server.  When calling the GSS_Init_sec_context, the
  63.147 +   client MUST pass the integ_req_flag of TRUE (**).  If the client will
  63.148 +   be requesting a security layer, it MUST also supply to the
  63.149 +   GSS_Init_sec_context a mutual_req_flag of TRUE, and a
  63.150 +   sequence_req_flag of TRUE.  If the client will be requesting a
  63.151 +   security layer providing confidentiality protection, it MUST also
  63.152 +   supply to the GSS_Init_sec_context a conf_req_flag of TRUE.  The
  63.153 +   client then responds with the resulting output_token.  If
  63.154 +   GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED, then the client
  63.155 +   should expect the server to issue a token in a subsequent challenge.
  63.156 +   The client must pass the token to another call to
  63.157 +   GSS_Init_sec_context, repeating the actions in this paragraph.
  63.158 +
  63.159 +   (*) Clients MAY use name types other than GSS_C_NT_HOSTBASED_SERVICE
  63.160 +   to import servers' acceptor names, but only when they have a priori
  63.161 +   knowledge that the servers support alternate name types.  Otherwise
  63.162 +   clients MUST use GSS_C_NT_HOSTBASED_SERVICE for importing acceptor
  63.163 +   names.
  63.164 +
  63.165 +   (**) Note that RFC 2222 [RFC2222] implementations will not work with
  63.166 +   GSS-API implementations that require integ_req_flag to be true.  No
  63.167 +   implementations of RFC 1964 [KRB5GSS] or RFC 4121 [RFC4121] that
  63.168 +   require integ_req_flag to be true are believed to exist and it is
  63.169 +   expected that any future update to [RFC4121] will require that
  63.170 +
  63.171 +
  63.172 +
  63.173 +Melnikov                    Standards Track                     [Page 3]
  63.174 +
  63.175 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.176 +
  63.177 +
  63.178 +   integrity be available even in not explicitly requested by the
  63.179 +   application.
  63.180 +
  63.181 +   When GSS_Init_sec_context returns GSS_S_COMPLETE, the client examines
  63.182 +   the context to ensure that it provides a level of protection
  63.183 +   permitted by the client's security policy.  In particular, if the
  63.184 +   integ_avail flag is not set in the context, then no security layer
  63.185 +   can be offered or accepted.
  63.186 +
  63.187 +   If the conf_avail flag is not set in the context, then no security
  63.188 +   layer with confidentiality can be offered or accepted.  If the
  63.189 +   context is acceptable, the client takes the following actions: If the
  63.190 +   last call to GSS_Init_sec_context returned an output_token, then the
  63.191 +   client responds with the output_token, otherwise the client responds
  63.192 +   with no data.  The client should then expect the server to issue a
  63.193 +   token in a subsequent challenge.  The client passes this token to
  63.194 +   GSS_Unwrap and interprets the first octet of resulting cleartext as a
  63.195 +   bit-mask specifying the security layers supported by the server and
  63.196 +   the second through fourth octets as the maximum size output_message
  63.197 +   the server is able to receive (in network byte order).  If the
  63.198 +   resulting cleartext is not 4 octets long, the client fails the
  63.199 +   negotiation.  The client verifies that the server maximum buffer is 0
  63.200 +   if the server does not advertise support for any security layer.
  63.201 +
  63.202 +   The client then constructs data, with the first octet containing the
  63.203 +   bit-mask specifying the selected security layer, the second through
  63.204 +   fourth octets containing in network byte order the maximum size
  63.205 +   output_message the client is able to receive (which MUST be 0 if the
  63.206 +   client does not support any security layer), and the remaining octets
  63.207 +   containing the UTF-8 [UTF8] encoded authorization identity.
  63.208 +   (Implementation note: The authorization identity is not terminated
  63.209 +   with the zero-valued (%x00) octet (e.g., the UTF-8 encoding of the
  63.210 +   NUL (U+0000) character)).  The client passes the data to GSS_Wrap
  63.211 +   with conf_flag set to FALSE and responds with the generated
  63.212 +   output_message.  The client can then consider the server
  63.213 +   authenticated.
  63.214 +
  63.215 +3.2.  Server Side of Authentication Protocol Exchange
  63.216 +
  63.217 +   A server MUST NOT advertise support for the "GSSAPI" SASL mechanism
  63.218 +   described in this document unless it has acceptor credential for the
  63.219 +   Kerberos V GSS-API mechanism [KRB5GSS].
  63.220 +
  63.221 +   The server passes the initial client response to
  63.222 +   GSS_Accept_sec_context as input_token, setting input_context_handle
  63.223 +   to 0 (initially), chan_binding of NULL, and a suitable
  63.224 +   acceptor_cred_handle (see below).  If GSS_Accept_sec_context returns
  63.225 +   GSS_S_CONTINUE_NEEDED, the server returns the generated output_token
  63.226 +
  63.227 +
  63.228 +
  63.229 +Melnikov                    Standards Track                     [Page 4]
  63.230 +
  63.231 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.232 +
  63.233 +
  63.234 +   to the client in challenge and passes the resulting response to
  63.235 +   another call to GSS_Accept_sec_context, repeating the actions in this
  63.236 +   paragraph.
  63.237 +
  63.238 +   Servers SHOULD use a credential obtained by calling GSS_Acquire_cred
  63.239 +   or GSS_Add_cred for the GSS_C_NO_NAME desired_name and the Object
  63.240 +   Identifier (OID) of the Kerberos V5 GSS-API mechanism [KRB5GSS](*).
  63.241 +   Servers MAY use GSS_C_NO_CREDENTIAL as an acceptor credential handle.
  63.242 +   Servers MAY use a credential obtained by calling GSS_Acquire_cred or
  63.243 +   GSS_Add_cred for the server's principal name(s) (**) and the Kerberos
  63.244 +   V5 GSS-API mechanism [KRB5GSS].
  63.245 +
  63.246 +   (*) Unlike GSS_Add_cred the GSS_Acquire_cred uses an OID set of GSS-
  63.247 +   API mechanism as an input parameter.  The OID set can be created by
  63.248 +   using GSS_Create_empty_OID_set and GSS_Add_OID_set_member.  It can be
  63.249 +   freed by calling the GSS_Release_oid_set.
  63.250 +
  63.251 +
  63.252 +   (**) Use of server's principal names having
  63.253 +   GSS_C_NT_HOSTBASED_SERVICE name type and "service@hostname" format,
  63.254 +   where "service" is the service name specified in the protocol's
  63.255 +   profile, and "hostname" is the fully qualified host name of the
  63.256 +   server, is RECOMMENDED.  The server name is generated by calling
  63.257 +   GSS_Import_name with input_name_type of GSS_C_NT_HOSTBASED_SERVICE
  63.258 +   and input_name_string of "service@hostname".
  63.259 +
  63.260 +   Upon successful establishment of the security context (i.e.,
  63.261 +   GSS_Accept_sec_context returns GSS_S_COMPLETE), the server SHOULD
  63.262 +   verify that the negotiated GSS-API mechanism is indeed Kerberos V5
  63.263 +   [KRB5GSS].  This is done by examining the value of the mech_type
  63.264 +   parameter returned from the GSS_Accept_sec_context call.  If the
  63.265 +   value differs, SASL authentication MUST be aborted.
  63.266 +
  63.267 +   Upon successful establishment of the security context and if the
  63.268 +   server used GSS_C_NO_NAME/GSS_C_NO_CREDENTIAL to create acceptor
  63.269 +   credential handle, the server SHOULD also check using the
  63.270 +   GSS_Inquire_context that the target_name used by the client matches
  63.271 +   either
  63.272 +
  63.273 +   -  the GSS_C_NT_HOSTBASED_SERVICE "service@hostname" name syntax,
  63.274 +      where "service" is the service name specified in the application
  63.275 +      protocol's profile,
  63.276 +
  63.277 +      or
  63.278 +
  63.279 +   -  the GSS_KRB5_NT_PRINCIPAL_NAME [KRB5GSS] name syntax for a two-
  63.280 +      component principal where the first component matches the service
  63.281 +      name specified in the application protocol's profile.
  63.282 +
  63.283 +
  63.284 +
  63.285 +Melnikov                    Standards Track                     [Page 5]
  63.286 +
  63.287 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.288 +
  63.289 +
  63.290 +   When GSS_Accept_sec_context returns GSS_S_COMPLETE, the server
  63.291 +   examines the context to ensure that it provides a level of protection
  63.292 +   permitted by the server's security policy.  In particular, if the
  63.293 +   integ_avail flag is not set in the context, then no security layer
  63.294 +   can be offered or accepted.  If the conf_avail flag is not set in the
  63.295 +   context, then no security layer with confidentiality can be offered
  63.296 +   or accepted.
  63.297 +
  63.298 +   If the context is acceptable, the server takes the following actions:
  63.299 +   If the last call to GSS_Accept_sec_context returned an output_token,
  63.300 +   the server returns it to the client in a challenge and expects a
  63.301 +   reply from the client with no data.  Whether or not an output_token
  63.302 +   was returned (and after receipt of any response from the client to
  63.303 +   such an output_token), the server then constructs 4 octets of data,
  63.304 +   with the first octet containing a bit-mask specifying the security
  63.305 +   layers supported by the server and the second through fourth octets
  63.306 +   containing in network byte order the maximum size output_token the
  63.307 +   server is able to receive (which MUST be 0 if the server does not
  63.308 +   support any security layer).  The server must then pass the plaintext
  63.309 +   to GSS_Wrap with conf_flag set to FALSE and issue the generated
  63.310 +   output_message to the client in a challenge.
  63.311 +
  63.312 +   The server must then pass the resulting response to GSS_Unwrap and
  63.313 +   interpret the first octet of resulting cleartext as the bit-mask for
  63.314 +   the selected security layer, the second through fourth octets as the
  63.315 +   maximum size output_message the client is able to receive (in network
  63.316 +   byte order), and the remaining octets as the authorization identity.
  63.317 +   The server verifies that the client has selected a security layer
  63.318 +   that was offered and that the client maximum buffer is 0 if no
  63.319 +   security layer was chosen.  The server must verify that the src_name
  63.320 +   is authorized to act as the authorization identity.  After these
  63.321 +   verifications, the authentication process is complete.  The server is
  63.322 +   not expected to return any additional data with the success
  63.323 +   indicator.
  63.324 +
  63.325 +3.3.  Security Layer
  63.326 +
  63.327 +   The security layers and their corresponding bit-masks are as follows:
  63.328 +
  63.329 +          1 No security layer
  63.330 +          2 Integrity protection.
  63.331 +            Sender calls GSS_Wrap with conf_flag set to FALSE
  63.332 +          4 Confidentiality protection.
  63.333 +            Sender calls GSS_Wrap with conf_flag set to TRUE
  63.334 +
  63.335 +   Other bit-masks may be defined in the future; bits that are not
  63.336 +   understood must be negotiated off.
  63.337 +
  63.338 +
  63.339 +
  63.340 +
  63.341 +Melnikov                    Standards Track                     [Page 6]
  63.342 +
  63.343 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.344 +
  63.345 +
  63.346 +   When decoding any received data with GSS_Unwrap, the major_status
  63.347 +   other than the GSS_S_COMPLETE MUST be treated as a fatal error.
  63.348 +
  63.349 +   Note that SASL negotiates the maximum size of the output_message to
  63.350 +   send.  Implementations can use the GSS_Wrap_size_limit call to
  63.351 +   determine the corresponding maximum size input_message.
  63.352 +
  63.353 +4.  IANA Considerations
  63.354 +
  63.355 +   IANA modified the existing registration for "GSSAPI" as follows:
  63.356 +
  63.357 +   Family of SASL mechanisms:  NO
  63.358 +
  63.359 +   SASL mechanism name:  GSSAPI
  63.360 +
  63.361 +   Security considerations:  See Section 5 of RFC 4752
  63.362 +
  63.363 +   Published specification:  RFC 4752
  63.364 +
  63.365 +   Person & email address to contact for further information:
  63.366 +      Alexey Melnikov <Alexey.Melnikov@isode.com>
  63.367 +
  63.368 +   Intended usage:  COMMON
  63.369 +
  63.370 +   Owner/Change controller:  iesg@ietf.org
  63.371 +
  63.372 +   Additional information:  This mechanism is for the Kerberos V5
  63.373 +      mechanism of GSS-API.
  63.374 +
  63.375 +5.  Security Considerations
  63.376 +
  63.377 +   Security issues are discussed throughout this memo.
  63.378 +
  63.379 +   When constructing the input_name_string, the client SHOULD NOT
  63.380 +   canonicalize the server's fully qualified domain name using an
  63.381 +   insecure or untrusted directory service.
  63.382 +
  63.383 +   For compatibility with deployed software, this document requires that
  63.384 +   the chan_binding (channel bindings) parameter to GSS_Init_sec_context
  63.385 +   and GSS_Accept_sec_context be NULL, hence disallowing use of GSS-API
  63.386 +   support for channel bindings.  GSS-API channel bindings in SASL is
  63.387 +   expected to be supported via a new GSS-API family of SASL mechanisms
  63.388 +   (to be introduced in a future document).
  63.389 +
  63.390 +   Additional security considerations are in the [SASL] and [GSS-API]
  63.391 +   specifications.  Additional security considerations for the GSS-API
  63.392 +   mechanism can be found in [KRB5GSS] and [KERBEROS].
  63.393 +
  63.394 +
  63.395 +
  63.396 +
  63.397 +Melnikov                    Standards Track                     [Page 7]
  63.398 +
  63.399 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.400 +
  63.401 +
  63.402 +6.  Acknowledgements
  63.403 +
  63.404 +   This document replaces Section 7.2 of RFC 2222 [RFC2222] by John G.
  63.405 +   Myers.  He also contributed significantly to this revision.
  63.406 +
  63.407 +   Lawrence Greenfield converted text of this document to the XML
  63.408 +   format.
  63.409 +
  63.410 +   Contributions of many members of the SASL mailing list are gratefully
  63.411 +   acknowledged, in particular comments from Chris Newman, Nicolas
  63.412 +   Williams, Jeffrey Hutzelman, Sam Hartman, Mark Crispin, and Martin
  63.413 +   Rex.
  63.414 +
  63.415 +7.  Changes since RFC 2222
  63.416 +
  63.417 +   RFC 2078 [RFC2078] specifies the version of GSS-API used by RFC 2222
  63.418 +   [RFC2222], which provided the original version of this specification.
  63.419 +   That version of GSS-API did not provide the integ_integ_avail flag as
  63.420 +   an input to GSS_Init_sec_context.  Instead, integrity was always
  63.421 +   requested.  RFC 4422 [SASL] requires that when possible, the security
  63.422 +   layer negotiation be integrity protected.  To meet this requirement
  63.423 +   and as part of moving from RFC 2078 [RFC2078] to RFC 2743 [GSS-API],
  63.424 +   this specification requires that clients request integrity from
  63.425 +   GSS_Init_sec_context so they can use GSS_Wrap to protect the security
  63.426 +   layer negotiation.  This specification does not require that the
  63.427 +   mechanism offer the integrity security layer, simply that the
  63.428 +   security layer negotiation be wrapped.
  63.429 +
  63.430 +8.  References
  63.431 +
  63.432 +8.1.  Normative References
  63.433 +
  63.434 +   [GSS-API]  Linn, J., "Generic Security Service Application Program
  63.435 +              Interface Version 2, Update 1", RFC 2743, January 2000.
  63.436 +
  63.437 +   [KERBEROS] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The
  63.438 +              Kerberos Network Authentication Service (V5)", RFC 4120,
  63.439 +              July 2005.
  63.440 +
  63.441 +   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
  63.442 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  63.443 +
  63.444 +   [KRB5GSS]  Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC
  63.445 +              1964, June 1996.
  63.446 +
  63.447 +
  63.448 +
  63.449 +
  63.450 +
  63.451 +
  63.452 +
  63.453 +Melnikov                    Standards Track                     [Page 8]
  63.454 +
  63.455 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.456 +
  63.457 +
  63.458 +   [RFC4121]  Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos
  63.459 +              Version 5 Generic Security Service Application Program
  63.460 +              Interface (GSS-API) Mechanism: Version 2", RFC 4121, July
  63.461 +              2005.
  63.462 +
  63.463 +   [SASL]     Melnikov, A. and  K. Zeilenga, "Simple Authentication and
  63.464 +              Security Layer (SASL)", RFC 4422, June 2006.
  63.465 +
  63.466 +   [UTF8]     Yergeau, F., "UTF-8, a transformation format of ISO
  63.467 +              10646", STD 63, RFC 3629, November 2003.
  63.468 +
  63.469 +8.2.  Informative References
  63.470 +
  63.471 +   [RFC2078]  Linn, J., "Generic Security Service Application Program
  63.472 +              Interface, Version 2", RFC 2078, January 1997.
  63.473 +
  63.474 +   [RFC2222]  Myers, J., "Simple Authentication and Security Layer
  63.475 +              (SASL)", RFC 2222, October 1997.
  63.476 +
  63.477 +Editor's Address
  63.478 +
  63.479 +   Alexey Melnikov
  63.480 +   Isode Limited
  63.481 +   5 Castle Business Village
  63.482 +   36 Station Road
  63.483 +   Hampton, Middlesex  TW12 2BX
  63.484 +   UK
  63.485 +
  63.486 +   EMail: Alexey.Melnikov@isode.com
  63.487 +   URI:   http://www.melnikov.ca/
  63.488 +
  63.489 +
  63.490 +
  63.491 +
  63.492 +
  63.493 +
  63.494 +
  63.495 +
  63.496 +
  63.497 +
  63.498 +
  63.499 +
  63.500 +
  63.501 +
  63.502 +
  63.503 +
  63.504 +
  63.505 +
  63.506 +
  63.507 +
  63.508 +
  63.509 +Melnikov                    Standards Track                     [Page 9]
  63.510 +
  63.511 +RFC 4752                 SASL GSSAPI Mechanism             November 2006
  63.512 +
  63.513 +
  63.514 +Full Copyright Statement
  63.515 +
  63.516 +   Copyright (C) The IETF Trust (2006).
  63.517 +
  63.518 +   This document is subject to the rights, licenses and restrictions
  63.519 +   contained in BCP 78, and except as set forth therein, the authors
  63.520 +   retain all their rights.
  63.521 +
  63.522 +   This document and the information contained herein are provided on an
  63.523 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  63.524 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST,
  63.525 +   AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES,
  63.526 +   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT
  63.527 +   THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
  63.528 +   IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
  63.529 +   PURPOSE.
  63.530 +
  63.531 +Intellectual Property
  63.532 +
  63.533 +   The IETF takes no position regarding the validity or scope of any
  63.534 +   Intellectual Property Rights or other rights that might be claimed to
  63.535 +   pertain to the implementation or use of the technology described in
  63.536 +   this document or the extent to which any license under such rights
  63.537 +   might or might not be available; nor does it represent that it has
  63.538 +   made any independent effort to identify any such rights.  Information
  63.539 +   on the procedures with respect to rights in RFC documents can be
  63.540 +   found in BCP 78 and BCP 79.
  63.541 +
  63.542 +   Copies of IPR disclosures made to the IETF Secretariat and any
  63.543 +   assurances of licenses to be made available, or the result of an
  63.544 +   attempt made to obtain a general license or permission for the use of
  63.545 +   such proprietary rights by implementers or users of this
  63.546 +   specification can be obtained from the IETF on-line IPR repository at
  63.547 +   http://www.ietf.org/ipr.
  63.548 +
  63.549 +   The IETF invites any interested party to bring to its attention any
  63.550 +   copyrights, patents or patent applications, or other proprietary
  63.551 +   rights that may cover technology that may be required to implement
  63.552 +   this standard.  Please address the information to the IETF at
  63.553 +   ietf-ipr@ietf.org.
  63.554 +
  63.555 +Acknowledgement
  63.556 +
  63.557 +   Funding for the RFC Editor function is currently provided by the
  63.558 +   Internet Society.
  63.559 +
  63.560 +
  63.561 +
  63.562 +
  63.563 +
  63.564 +
  63.565 +Melnikov                    Standards Track                    [Page 10]
  63.566 +
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/docs/rfc/rfc4790.txt	Mon Sep 14 15:17:45 2009 +0900
    64.3 @@ -0,0 +1,1459 @@
    64.4 +
    64.5 +
    64.6 +
    64.7 +
    64.8 +
    64.9 +
   64.10 +Network Working Group                                          C. Newman
   64.11 +Request for Comments: 4790                              Sun Microsystems
   64.12 +Category: Standards Track                                      M. Duerst
   64.13 +                                                Aoyama Gakuin University
   64.14 +                                                          A. Gulbrandsen
   64.15 +                                                                    Oryx
   64.16 +                                                              March 2007
   64.17 +
   64.18 +
   64.19 +            Internet Application Protocol Collation Registry
   64.20 +
   64.21 +Status of This Memo
   64.22 +
   64.23 +   This document specifies an Internet standards track protocol for the
   64.24 +   Internet community, and requests discussion and suggestions for
   64.25 +   improvements.  Please refer to the current edition of the "Internet
   64.26 +   Official Protocol Standards" (STD 1) for the standardization state
   64.27 +   and status of this protocol.  Distribution of this memo is unlimited.
   64.28 +
   64.29 +Copyright Notice
   64.30 +
   64.31 +   Copyright (C) The IETF Trust (2007).
   64.32 +
   64.33 +Abstract
   64.34 +
   64.35 +   Many Internet application protocols include string-based lookup,
   64.36 +   searching, or sorting operations.  However, the problem space for
   64.37 +   searching and sorting international strings is large, not fully
   64.38 +   explored, and is outside the area of expertise for the Internet
   64.39 +   Engineering Task Force (IETF).  Rather than attempt to solve such a
   64.40 +   large problem, this specification creates an abstraction framework so
   64.41 +   that application protocols can precisely identify a comparison
   64.42 +   function, and the repertoire of comparison functions can be extended
   64.43 +   in the future.
   64.44 +
   64.45 +
   64.46 +
   64.47 +
   64.48 +
   64.49 +
   64.50 +
   64.51 +
   64.52 +
   64.53 +
   64.54 +
   64.55 +
   64.56 +
   64.57 +
   64.58 +
   64.59 +
   64.60 +
   64.61 +Newman, et al.              Standards Track                     [Page 1]
   64.62 +
   64.63 +RFC 4790                   Collation Registry                 March 2007
   64.64 +
   64.65 +
   64.66 +Table of Contents
   64.67 +
   64.68 +   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  4
   64.69 +     1.1.  Conventions Used in This Document  . . . . . . . . . . . .  4
   64.70 +   2.  Collation Definition and Purpose . . . . . . . . . . . . . . .  4
   64.71 +     2.1.  Definition . . . . . . . . . . . . . . . . . . . . . . . .  4
   64.72 +     2.2.  Purpose  . . . . . . . . . . . . . . . . . . . . . . . . .  4
   64.73 +     2.3.  Some Other Terms Used in this Document . . . . . . . . . .  5
   64.74 +     2.4.  Sort Keys  . . . . . . . . . . . . . . . . . . . . . . . .  5
   64.75 +   3.  Collation Identifier Syntax  . . . . . . . . . . . . . . . . .  6
   64.76 +     3.1.  Basic Syntax . . . . . . . . . . . . . . . . . . . . . . .  6
   64.77 +     3.2.  Wildcards  . . . . . . . . . . . . . . . . . . . . . . . .  6
   64.78 +     3.3.  Ordering Direction . . . . . . . . . . . . . . . . . . . .  7
   64.79 +     3.4.  URIs . . . . . . . . . . . . . . . . . . . . . . . . . . .  7
   64.80 +     3.5.  Naming Guidelines  . . . . . . . . . . . . . . . . . . . .  7
   64.81 +   4.  Collation Specification Requirements . . . . . . . . . . . . .  8
   64.82 +     4.1.  Collation/Server Interface . . . . . . . . . . . . . . . .  8
   64.83 +     4.2.  Operations Supported . . . . . . . . . . . . . . . . . . .  8
   64.84 +       4.2.1.  Validity . . . . . . . . . . . . . . . . . . . . . . .  9
   64.85 +       4.2.2.  Equality . . . . . . . . . . . . . . . . . . . . . . .  9
   64.86 +       4.2.3.  Substring  . . . . . . . . . . . . . . . . . . . . . .  9
   64.87 +       4.2.4.  Ordering . . . . . . . . . . . . . . . . . . . . . . . 10
   64.88 +     4.3.  Sort Keys  . . . . . . . . . . . . . . . . . . . . . . . . 10
   64.89 +     4.4.  Use of Lookup Tables . . . . . . . . . . . . . . . . . . . 11
   64.90 +   5.  Application Protocol Requirements  . . . . . . . . . . . . . . 11
   64.91 +     5.1.  Character Encoding . . . . . . . . . . . . . . . . . . . . 11
   64.92 +     5.2.  Operations . . . . . . . . . . . . . . . . . . . . . . . . 11
   64.93 +     5.3.  Wildcards  . . . . . . . . . . . . . . . . . . . . . . . . 12
   64.94 +     5.4.  String Comparison  . . . . . . . . . . . . . . . . . . . . 12
   64.95 +     5.5.  Disconnected Clients . . . . . . . . . . . . . . . . . . . 12
   64.96 +     5.6.  Error Codes  . . . . . . . . . . . . . . . . . . . . . . . 13
   64.97 +     5.7.  Octet Collation  . . . . . . . . . . . . . . . . . . . . . 13
   64.98 +   6.  Use by Existing Protocols  . . . . . . . . . . . . . . . . . . 13
   64.99 +   7.  Collation Registration . . . . . . . . . . . . . . . . . . . . 14
  64.100 +     7.1.  Collation Registration Procedure . . . . . . . . . . . . . 14
  64.101 +     7.2.  Collation Registration Format  . . . . . . . . . . . . . . 15
  64.102 +       7.2.1.  Registration Template  . . . . . . . . . . . . . . . . 15
  64.103 +       7.2.2.  The Collation Element  . . . . . . . . . . . . . . . . 15
  64.104 +       7.2.3.  The Identifier Element . . . . . . . . . . . . . . . . 16
  64.105 +       7.2.4.  The Title Element  . . . . . . . . . . . . . . . . . . 16
  64.106 +       7.2.5.  The Operations Element . . . . . . . . . . . . . . . . 16
  64.107 +       7.2.6.  The Specification Element  . . . . . . . . . . . . . . 16
  64.108 +       7.2.7.  The Submitter Element  . . . . . . . . . . . . . . . . 16
  64.109 +       7.2.8.  The Owner Element  . . . . . . . . . . . . . . . . . . 16
  64.110 +       7.2.9.  The Version Element  . . . . . . . . . . . . . . . . . 17
  64.111 +       7.2.10. The Variable Element . . . . . . . . . . . . . . . . . 17
  64.112 +     7.3.  Structure of Collation Registry  . . . . . . . . . . . . . 17
  64.113 +     7.4.  Example Initial Registry Summary . . . . . . . . . . . . . 18
  64.114 +
  64.115 +
  64.116 +
  64.117 +Newman, et al.              Standards Track                     [Page 2]
  64.118 +
  64.119 +RFC 4790                   Collation Registry                 March 2007
  64.120 +
  64.121 +
  64.122 +   8.  Guidelines for Expert Reviewer . . . . . . . . . . . . . . . . 18
  64.123 +   9.  Initial Collations . . . . . . . . . . . . . . . . . . . . . . 19
  64.124 +     9.1.  ASCII Numeric Collation  . . . . . . . . . . . . . . . . . 20
  64.125 +       9.1.1.  ASCII Numeric Collation Description  . . . . . . . . . 20
  64.126 +       9.1.2.  ASCII Numeric Collation Registration . . . . . . . . . 20
  64.127 +     9.2.  ASCII Casemap Collation  . . . . . . . . . . . . . . . . . 21
  64.128 +       9.2.1.  ASCII Casemap Collation Description  . . . . . . . . . 21
  64.129 +       9.2.2.  ASCII Casemap Collation Registration . . . . . . . . . 22
  64.130 +     9.3.  Octet Collation  . . . . . . . . . . . . . . . . . . . . . 22
  64.131 +       9.3.1.  Octet Collation Description  . . . . . . . . . . . . . 22
  64.132 +       9.3.2.  Octet Collation Registration . . . . . . . . . . . . . 23
  64.133 +   10. IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 23
  64.134 +   11. Security Considerations  . . . . . . . . . . . . . . . . . . . 23
  64.135 +   12. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 23
  64.136 +   13. References . . . . . . . . . . . . . . . . . . . . . . . . . . 24
  64.137 +     13.1. Normative References . . . . . . . . . . . . . . . . . . . 24
  64.138 +     13.2. Informative References . . . . . . . . . . . . . . . . . . 24
  64.139 +
  64.140 +
  64.141 +
  64.142 +
  64.143 +
  64.144 +
  64.145 +
  64.146 +
  64.147 +
  64.148 +
  64.149 +
  64.150 +
  64.151 +
  64.152 +
  64.153 +
  64.154 +
  64.155 +
  64.156 +
  64.157 +
  64.158 +
  64.159 +
  64.160 +
  64.161 +
  64.162 +
  64.163 +
  64.164 +
  64.165 +
  64.166 +
  64.167 +
  64.168 +
  64.169 +
  64.170 +
  64.171 +
  64.172 +
  64.173 +Newman, et al.              Standards Track                     [Page 3]
  64.174 +
  64.175 +RFC 4790                   Collation Registry                 March 2007
  64.176 +
  64.177 +
  64.178 +1.  Introduction
  64.179 +
  64.180 +   The Application Configuration Access Protocol ACAP [11] specification
  64.181 +   introduced the concept of a comparator (which we call collation in
  64.182 +   this document), but failed to create an IANA registry.  With the
  64.183 +   introduction of stringprep [6] and the Unicode Collation Algorithm
  64.184 +   [7], it is now time to create that registry and populate it with some
  64.185 +   initial values appropriate for an international community.  This
  64.186 +   specification replaces and generalizes the definition of a comparator
  64.187 +   in ACAP, and creates a collation registry.
  64.188 +
  64.189 +1.1.  Conventions Used in This Document
  64.190 +
  64.191 +   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
  64.192 +   in this document are to be interpreted as defined in "Key words for
  64.193 +   use in RFCs to Indicate Requirement Levels" [1].
  64.194 +
  64.195 +   The attribute syntax specifications use the Augmented Backus-Naur
  64.196 +   Form (ABNF) [2] notation, including the core rules defined in
  64.197 +   Appendix A.  The ABNF production "Language-tag" is imported from
  64.198 +   Language Tags [5] and "reg-name" from URI: Generic Syntax [4].
  64.199 +
  64.200 +2.  Collation Definition and Purpose
  64.201 +
  64.202 +2.1.  Definition
  64.203 +
  64.204 +   A collation is a named function which takes two arbitrary length
  64.205 +   strings as input and can be used to perform one or more of three
  64.206 +   basic comparison operations: equality test, substring match, and
  64.207 +   ordering test.
  64.208 +
  64.209 +2.2.  Purpose
  64.210 +
  64.211 +   Collations are an abstraction for comparison functions so that these
  64.212 +   comparison functions can be used in multiple protocols.  The details
  64.213 +   of a particular comparison operation can be specified by someone with
  64.214 +   appropriate expertise, independent of the application protocols that
  64.215 +   use that collation.  This is similar to the way a charset [13]
  64.216 +   separates the details of octet to character mapping from a protocol
  64.217 +   specification, such as MIME [9], or the way SASL [10] separates the
  64.218 +   details of an authentication mechanism from a protocol specification,
  64.219 +   such as ACAP [11].
  64.220 +
  64.221 +
  64.222 +
  64.223 +
  64.224 +
  64.225 +
  64.226 +
  64.227 +
  64.228 +
  64.229 +Newman, et al.              Standards Track                     [Page 4]
  64.230 +
  64.231 +RFC 4790                   Collation Registry                 March 2007
  64.232 +
  64.233 +
  64.234 +   Here is a small diagram to help illustrate the value of this
  64.235 +   abstraction:
  64.236 +
  64.237 +   +-------------------+                         +-----------------+
  64.238 +   | IMAP i18n SEARCH  |--+                      | Basic           |
  64.239 +   +-------------------+  |                   +--| Collation Spec  |
  64.240 +                          |                   |  +-----------------+
  64.241 +   +-------------------+  |  +-------------+  |  +-----------------+
  64.242 +   | ACAP i18n SEARCH  |--+--| Collation   |--+--| A stringprep    |
  64.243 +   +-------------------+  |  | Registry    |  |  | Collation Spec  |
  64.244 +                          |  +-------------+  |  +-----------------+
  64.245 +   +-------------------+  |                   |  +-----------------+
  64.246 +   | ...other protocol |--+                   |  | locale-specific |
  64.247 +   +-------------------+                      +--| Collation Spec  |
  64.248 +                                                 +-----------------+
  64.249 +
  64.250 +   Thus IMAP, ACAP, and future application protocols with international
  64.251 +   search capability simply specify how to interface to the collation
  64.252 +   registry instead of each protocol specification having to specify all
  64.253 +   the collations it supports.
  64.254 +
  64.255 +2.3.  Some Other Terms Used in this Document
  64.256 +
  64.257 +   The terms client, server, and protocol are used in somewhat unusual
  64.258 +   senses.
  64.259 +
  64.260 +   Client means a user, or a program acting directly on behalf of a
  64.261 +   user.  This may be a mail reader acting as an IMAP client, or it may
  64.262 +   be an interactive shell, where the user can type protocol commands/
  64.263 +   requests directly, or it may be a script or program written by the
  64.264 +   user.
  64.265 +
  64.266 +   Server means a program that performs services requested by the
  64.267 +   client.  This may be a traditional server such as an HTTP server, or
  64.268 +   it may be a Sieve [14] interpreter running a Sieve script written by
  64.269 +   a user.  A server needs to use the operations provided by collations
  64.270 +   in order to fulfill the client's requests.
  64.271 +
  64.272 +   The protocol describes how the client tells the server what it wants
  64.273 +   done, and (if applicable) how the server tells the client about the
  64.274 +   results.  IMAP is a protocol by this definition, and so is the Sieve
  64.275 +   language.
  64.276 +
  64.277 +2.4.  Sort Keys
  64.278 +
  64.279 +   One component of a collation is a transformation, which turns a
  64.280 +   string into a sort key, which is then used while sorting.
  64.281 +
  64.282 +
  64.283 +
  64.284 +
  64.285 +Newman, et al.              Standards Track                     [Page 5]
  64.286 +
  64.287 +RFC 4790                   Collation Registry                 March 2007
  64.288 +
  64.289 +
  64.290 +   The transformation can range from an identity mapping (e.g., the
  64.291 +   i;octet collation Section 9.3) to a mapping that makes the string
  64.292 +   unreadable to a human.
  64.293 +
  64.294 +   This is an implementation detail of collations or servers.  A
  64.295 +   protocol SHOULD NOT expose it to clients, since some collations leave
  64.296 +   the sort key's format up to the implementation, and current
  64.297 +   conformant implementations are known to use different formats.
  64.298 +
  64.299 +3.  Collation Identifier Syntax
  64.300 +
  64.301 +3.1.  Basic Syntax
  64.302 +
  64.303 +   The collation identifier itself is a single US-ASCII string.  The
  64.304 +   identifier MUST NOT be longer than 254 characters, and obeys the
  64.305 +   following grammar:
  64.306 +
  64.307 +     collation-char  = ALPHA / DIGIT / "-" / ";" / "=" / "."
  64.308 +
  64.309 +     collation-id    = collation-prefix ";" collation-core-name
  64.310 +                       *collation-arg
  64.311 +
  64.312 +     collation-scope = Language-tag / "vnd-" reg-name
  64.313 +
  64.314 +     collation-core-name = ALPHA *( ALPHA / DIGIT / "-" )
  64.315 +
  64.316 +     collation-arg   = ";" ALPHA *( ALPHA / DIGIT ) "="
  64.317 +                       1*( ALPHA / DIGIT / "." )
  64.318 +
  64.319 +
  64.320 +   Note: the ABNF production "Language-tag" is imported from Language
  64.321 +   Tags [5] and "reg-name" from URI: Generic Syntax [4].
  64.322 +
  64.323 +   There is a special identifier called "default".  For protocols that
  64.324 +   have a default collation, "default" refers to that collation.  For
  64.325 +   other protocols, the identifier "default" MUST match no collations,
  64.326 +   and servers SHOULD treat it in the same way as they treat nonexistent
  64.327 +   collations.
  64.328 +
  64.329 +3.2.  Wildcards
  64.330 +
  64.331 +   The string a client uses to select a collation MAY contain one or
  64.332 +   more wildcard ("*") characters that match zero or more collation-
  64.333 +   chars.  Wildcard characters MUST NOT be adjacent.  If the wildcard
  64.334 +   string matches multiple collations, the server SHOULD attempt to
  64.335 +   select a widely useful collation in preference to a narrowly useful
  64.336 +   one.
  64.337 +
  64.338 +
  64.339 +
  64.340 +
  64.341 +Newman, et al.              Standards Track                     [Page 6]
  64.342 +
  64.343 +RFC 4790                   Collation Registry                 March 2007
  64.344 +
  64.345 +
  64.346 +     collation-wild  =  ("*" / (ALPHA ["*"])) *(collation-char ["*"])
  64.347 +                         ; MUST NOT exceed 254 characters total
  64.348 +
  64.349 +3.3.  Ordering Direction
  64.350 +
  64.351 +   When used as a protocol element for ordering, the collation
  64.352 +   identifier MAY be prefixed by either "+" or "-" to explicitly specify
  64.353 +   an ordering direction. "+" has no effect on the ordering operation,
  64.354 +   while "-" inverts the result of the ordering operation.  In general,
  64.355 +   collation-order is used when a client requests a collation, and
  64.356 +   collation-selected is used when the server informs the client of the
  64.357 +   selected collation.
  64.358 +
  64.359 +     collation-selected =  ["+" / "-"] collation-id
  64.360 +
  64.361 +     collation-order =  ["+" / "-"] collation-wild
  64.362 +
  64.363 +3.4.  URIs
  64.364 +
  64.365 +   Some protocols are designed to use URIs [4] to refer to collations
  64.366 +   rather than simple tokens.  A special section of the IANA URL space
  64.367 +   is reserved for such usage.  The "collation-uri" form is used to
  64.368 +   refer to a specific named collation (the collation registration may
  64.369 +   not actually be present).  The "collation-auri" form is an abstract
  64.370 +   name for an ordering, a collation pattern or a vendor private
  64.371 +   collator.
  64.372 +
  64.373 +     collation-uri   =  "http://www.iana.org/assignments/collation/"
  64.374 +                        collation-id ".xml"
  64.375 +
  64.376 +     collation-auri  =  ( "http://www.iana.org/assignments/collation/"
  64.377 +                        collation-order ".xml" ) / other-uri
  64.378 +
  64.379 +     other-uri       =  <absoluteURI>
  64.380 +                     ;  excluding the IANA collation namespace.
  64.381 +
  64.382 +3.5.  Naming Guidelines
  64.383 +
  64.384 +   While this specification makes no absolute requirements on the
  64.385 +   structure of collation identifiers, naming consistency is important,
  64.386 +   so the following initial guidelines are provided.
  64.387 +
  64.388 +   Collation identifiers with an international audience typically begin
  64.389 +   with "i;".  Collation identifiers intended for a particular language
  64.390 +   or locale typically begin with a language tag [5] followed by a ";".
  64.391 +   After the first ";" is normally the name of the general collation
  64.392 +   algorithm, followed by a series of algorithm modifications separated
  64.393 +   by the ";" delimiter.  Parameterized modifications will use "=" to
  64.394 +
  64.395 +
  64.396 +
  64.397 +Newman, et al.              Standards Track                     [Page 7]
  64.398 +
  64.399 +RFC 4790                   Collation Registry                 March 2007
  64.400 +
  64.401 +
  64.402 +   delimit the parameter from the value.  The version numbers of any
  64.403 +   lookup tables used by the algorithm SHOULD be present as
  64.404 +   parameterized modifications.
  64.405 +
  64.406 +   Collation identifiers of the form *;vnd-hostname;* are reserved for
  64.407 +   vendor-specific collations created by the owner of the hostname
  64.408 +   following the "vnd-" prefix (e.g., vnd-example.com for the vendor
  64.409 +   example.com).  Registration of such collations (or the name space as
  64.410 +   a whole), with intended use of the "Vendor", is encouraged when a
  64.411 +   public specification or open-source implementation is available, but
  64.412 +   is not required.
  64.413 +
  64.414 +4.  Collation Specification Requirements
  64.415 +
  64.416 +4.1.  Collation/Server Interface
  64.417 +
  64.418 +   The collation itself defines what it operates on.  Most collations
  64.419 +   are expected to operate on character strings.  The i;octet
  64.420 +   (Section 9.3) collation operates on octet strings.  The i;ascii-
  64.421 +   numeric (Section 9.1) operation operates on numbers.
  64.422 +
  64.423 +   This specification defines the collation interface in terms of octet
  64.424 +   strings.  However, implementations may choose to use character
  64.425 +   strings instead.  Such implementations may not be able to implement
  64.426 +   e.g., i;octet.  Since i;octet is not currently mandatory to implement
  64.427 +   for any protocol, this should not be a problem.
  64.428 +
  64.429 +4.2.  Operations Supported
  64.430 +
  64.431 +   A collation specification MUST state which of the three basic
  64.432 +   operations are supported (equality, substring, ordering) and how to
  64.433 +   perform each of the supported operations on any two input character
  64.434 +   strings, including empty strings.  Collations must be deterministic,
  64.435 +   i.e., given a collation with a specific identifier, and any two fixed
  64.436 +   input strings, the result MUST be the same for the same operation.
  64.437 +
  64.438 +   In general, collation operations should behave as their names
  64.439 +   suggest.  While a collation may be new, the operations are not, so
  64.440 +   the new collation's operations should be similar to those of older
  64.441 +   collations.  For example, a date/time collation should not provide a
  64.442 +   "substring" operation that would morph IMAP substring SEARCH into
  64.443 +   e.g., a date-range search.
  64.444 +
  64.445 +   A non-obvious consequence of the rules for each collation operation
  64.446 +   is that, for any single collation, either none or all of the
  64.447 +   operations can return "undefined".  For example, it is not possible
  64.448 +   to have an equality operation that never returns "undefined", and a
  64.449 +   substring operation that occasionally does.
  64.450 +
  64.451 +
  64.452 +
  64.453 +Newman, et al.              Standards Track                     [Page 8]
  64.454 +
  64.455 +RFC 4790                   Collation Registry                 March 2007
  64.456 +
  64.457 +
  64.458 +4.2.1.  Validity
  64.459 +
  64.460 +   The validity test takes one string as argument.  It returns valid if
  64.461 +   its input string is a valid input to the collation's other
  64.462 +   operations, and invalid if not.  (In other words, a string is valid
  64.463 +   if it is equal to itself according to the collation's equality
  64.464 +   operation.)
  64.465 +
  64.466 +   The validity test is provided by all collations.  It MUST NOT be
  64.467 +   listed separately in the collation registration.
  64.468 +
  64.469 +4.2.2.  Equality
  64.470 +
  64.471 +   The equality test always returns "match" or "no-match" when it is
  64.472 +   supplied valid input, and MAY return "undefined" if one or both input
  64.473 +   strings are not valid.
  64.474 +
  64.475 +   The equality test MUST be reflexive and symmetric.  For valid input,
  64.476 +   it MUST be transitive.
  64.477 +
  64.478 +   If a collation provides either a substring or an ordering test, it
  64.479 +   MUST also provide an equality test.  The substring and/or ordering
  64.480 +   tests MUST be consistent with the equality test.
  64.481 +
  64.482 +   The return values of the equality test are called "match", "no-match"
  64.483 +   and "undefined" in this document.
  64.484 +
  64.485 +4.2.3.  Substring
  64.486 +
  64.487 +   The substring matching operation determines if the first string is a
  64.488 +   substring of the second string, i.e., if one or more substrings of
  64.489 +   the second string is equal to the first, as defined by the
  64.490 +   collation's equality operation.
  64.491 +
  64.492 +   A collation that supports substring matching will automatically
  64.493 +   support two special cases of substring matching: prefix and suffix
  64.494 +   matching, if those special cases are supported by the application
  64.495 +   protocol.  It returns "match" or "no-match" when it is supplied valid
  64.496 +   input and returns "undefined" when supplied invalid input.
  64.497 +
  64.498 +   Application protocols MAY return position information for substring
  64.499 +   matches.  If this is done, the position information SHOULD include
  64.500 +   both the starting offset and the ending offset for each match.  This
  64.501 +   is important because more sophisticated collations can match strings
  64.502 +   of unequal length (for example, a pre-composed accented character can
  64.503 +   match a decomposed accented character).  In general, overlapping
  64.504 +   matches SHOULD be reported (as when "ana" occurs twice within
  64.505 +   "banana"), although there are cases where a collation may decide not
  64.506 +
  64.507 +
  64.508 +
  64.509 +Newman, et al.              Standards Track                     [Page 9]
  64.510 +
  64.511 +RFC 4790                   Collation Registry                 March 2007
  64.512 +
  64.513 +
  64.514 +   to.  For example, in a collation which treats all whitespace
  64.515 +   sequences as identical, the substring operation could be defined such
  64.516 +   that " 1 " (SP "1" SP) is reported just once within "  1  " (SP SP
  64.517 +   "1" SP SP), not four times (SP SP "1" SP, SP "1" SP, SP "1" SP SP and
  64.518 +   SP SP "1" SP SP), since the four matches are, in a sense, the same
  64.519 +   match.
  64.520 +
  64.521 +   A string is a substring of itself.  The empty string is a substring
  64.522 +   of all strings.
  64.523 +
  64.524 +   Note that the substring operation of some collations can match
  64.525 +   strings of unequal length.  For example, a pre-composed accented
  64.526 +   character can match a decomposed accented character.  The Unicode
  64.527 +   Collation Algorithm [7] discusses this in more detail.
  64.528 +
  64.529 +   The return values of the substring operation are called "match", "no-
  64.530 +   match", and "undefined" in this document.
  64.531 +
  64.532 +4.2.4.  Ordering
  64.533 +
  64.534 +   The ordering operation determines how two strings are ordered.  It
  64.535 +   MUST be reflexive.  For valid input, it MUST be transitive and
  64.536 +   trichotomous.
  64.537 +
  64.538 +   Ordering returns "less" if the first string is listed before the
  64.539 +   second string, according to the collation; "greater", if the second
  64.540 +   string is listed before the first string; and "equal", if the two
  64.541 +   strings are equal, as defined by the collation's equality operation.
  64.542 +   If one or both strings are invalid, the result of ordering is
  64.543 +   "undefined".
  64.544 +
  64.545 +   When the collation is used with a "+" prefix, the behavior is the
  64.546 +   same as when used with no prefix.  When the collation is used with a
  64.547 +   "-" prefix, the result of the ordering operation of the collation
  64.548 +   MUST be reversed.
  64.549 +
  64.550 +   The return values of the ordering operation are called "less",
  64.551 +   "equal", "greater", and "undefined" in this document.
  64.552 +
  64.553 +4.3.  Sort Keys
  64.554 +
  64.555 +   A collation specification SHOULD describe the internal transformation
  64.556 +   algorithm to generate sort keys.  This algorithm can be applied to
  64.557 +   individual strings, and the result can be stored to potentially
  64.558 +   optimize future comparison operations.  A collation MAY specify that
  64.559 +   the sort key is generated by the identity function.  The sort key may
  64.560 +   have no meaning to a human.  The sort key may not be valid input to
  64.561 +   the collation.
  64.562 +
  64.563 +
  64.564 +
  64.565 +Newman, et al.              Standards Track                    [Page 10]
  64.566 +
  64.567 +RFC 4790                   Collation Registry                 March 2007
  64.568 +
  64.569 +
  64.570 +4.4.  Use of Lookup Tables
  64.571 +
  64.572 +   Some collations use customizable lookup tables, e.g., because the
  64.573 +   tables depend on locale, and may be modified after shipping the
  64.574 +   software.  Collations that use more than one customizable lookup
  64.575 +   table in a documented format MUST assign numbers to the tables they
  64.576 +   use.  This permits an application protocol command to access the
  64.577 +   tables used by a server collation, so that clients and servers use
  64.578 +   the same tables.
  64.579 +
  64.580 +5.  Application Protocol Requirements
  64.581 +
  64.582 +   This section describes the requirements and issues that an
  64.583 +   application protocol needs to consider if it offers searching,
  64.584 +   substring matching and/or sorting, and permits the use of characters
  64.585 +   outside the US-ASCII charset.
  64.586 +
  64.587 +5.1.  Character Encoding
  64.588 +
  64.589 +   The protocol specification has to make sure that it is clear on which
  64.590 +   characters (rather than just octets) the collations are used.  This
  64.591 +   can be done by specifying the protocol itself in terms of characters
  64.592 +   (e.g., in the case of a query language), by specifying a single
  64.593 +   character encoding for the protocol (e.g., UTF-8 [3]), or by
  64.594 +   carefully describing the relevant issues of character encoding
  64.595 +   labeling and conversion.  In the later case, details to consider
  64.596 +   include how to handle unknown charsets, any charsets that are
  64.597 +   mandatory-to-implement, any issues with byte-order that might apply,
  64.598 +   and any transfer encodings that need to be supported.
  64.599 +
  64.600 +5.2.  Operations
  64.601 +
  64.602 +   The protocol must specify which of the operations defined in this
  64.603 +   specification (equality matching, substring matching, and ordering)
  64.604 +   can be invoked in the protocol, and how they are invoked.  There may
  64.605 +   be more than one way to invoke an operation.
  64.606 +
  64.607 +   The protocol MUST provide a mechanism for the client to select the
  64.608 +   collation to use with equality matching, substring matching, and
  64.609 +   ordering.
  64.610 +
  64.611 +   If a protocol needs a total ordering and the collation chosen does
  64.612 +   not provide it because the ordering operation returns "undefined" at
  64.613 +   least once, the recommended fallback is to sort all invalid strings
  64.614 +   after the valid ones, and use i;octet to order the invalid strings.
  64.615 +
  64.616 +   Although the collation's substring function provides a list of
  64.617 +   matches, a protocol need not provide all that to the client.  It may
  64.618 +
  64.619 +
  64.620 +
  64.621 +Newman, et al.              Standards Track                    [Page 11]
  64.622 +
  64.623 +RFC 4790                   Collation Registry                 March 2007
  64.624 +
  64.625 +
  64.626 +   provide only the first matching substring, or even just the
  64.627 +   information that the substring search matched.  In this way,
  64.628 +   collations can be used with protocols that are defined such that "x
  64.629 +   is a substring of y" returns true-false.
  64.630 +
  64.631 +   If the protocol provides positional information for the results of a
  64.632 +   substring match, that positional information SHOULD fully specify the
  64.633 +   substring(s) in the result that matches, independent of the length of
  64.634 +   the search string.  For example, returning both the starting and
  64.635 +   ending offset of the match would suffice, as would the starting
  64.636 +   offset and a length.  Returning just the starting offset is not
  64.637 +   acceptable.  This rule is necessary because advanced collations can
  64.638 +   treat strings of different lengths as equal (for example, pre-
  64.639 +   composed and decomposed accented characters).
  64.640 +
  64.641 +5.3.  Wildcards
  64.642 +
  64.643 +   The protocol MUST specify whether it allows the use of wildcards in
  64.644 +   collation identifiers.  If the protocol allows wildcards, then:
  64.645 +      The protocol MUST specify how comparisons behave in the absence of
  64.646 +      explicit collation negotiation, or when a collation of "default"
  64.647 +      is requested.  The protocol MAY specify that the default collation
  64.648 +      used in such circumstances is sensitive to server configuration.
  64.649 +
  64.650 +      The protocol SHOULD provide a way to list available collations
  64.651 +      matching a given wildcard pattern, or patterns.
  64.652 +
  64.653 +5.4.  String Comparison
  64.654 +
  64.655 +   If a protocol compares strings in any nontrivial way, using a
  64.656 +   collation may be appropriate.  As an example, many protocols use
  64.657 +   case-independent strings.  In many cases, a simple ASCII mapping to
  64.658 +   upper/lower case works well.  In other cases, it may be better to use
  64.659 +   a specifiable collation; for example, so that a server can treat "i"
  64.660 +   and "I" as equivalent in Italy, and different in Turkey (Turkish also
  64.661 +   has a dotted upper-case" I" and a dotless lower-case "i").
  64.662 +
  64.663 +   Protocol designers should consider, in each case, whether to use a
  64.664 +   specifiable collation.  Keywords often have other needs than user
  64.665 +   variables, and search arguments may be different again.
  64.666 +
  64.667 +5.5.  Disconnected Clients
  64.668 +
  64.669 +   If the protocol supports disconnected clients, and a collation is
  64.670 +   used that can use configurable tables (e.g., to support
  64.671 +   locale-specific extensions), then the client may not be able to
  64.672 +   reproduce the server's collation operations while offline.
  64.673 +
  64.674 +
  64.675 +
  64.676 +
  64.677 +Newman, et al.              Standards Track                    [Page 12]
  64.678 +
  64.679 +RFC 4790                   Collation Registry                 March 2007
  64.680 +
  64.681 +
  64.682 +   A mechanism to download such tables has been discussed.  Such a
  64.683 +   mechanism is not included in the present specification, since the
  64.684 +   problem is not yet well understood.
  64.685 +
  64.686 +5.6.  Error Codes
  64.687 +
  64.688 +   The protocol specification should consider assigning protocol error
  64.689 +   codes for the following circumstances:
  64.690 +
  64.691 +   o  The client requests the use of a collation by identifier or
  64.692 +      pattern, but no implemented collation matches that pattern.
  64.693 +
  64.694 +   o  The client attempts to use a collation for an operation that is
  64.695 +      not supported by that collation -- for example, attempting to use
  64.696 +      the "i;ascii-numeric" collation for substring matching.
  64.697 +
  64.698 +   o  The client uses an equality or substring matching collation, and
  64.699 +      the result is an error.  It may be appropriate to distinguish
  64.700 +      between the two input strings, particularly when one is supplied
  64.701 +      by the client and the other is stored by the server.  It might
  64.702 +      also be appropriate to distinguish the specific case of an invalid
  64.703 +      UTF-8 string.
  64.704 +
  64.705 +5.7.  Octet Collation
  64.706 +
  64.707 +   The i;octet (Section 9.3) collation is only usable with protocols
  64.708 +   based on octet-strings.  Clients and servers MUST NOT use i;octet
  64.709 +   with other protocols.
  64.710 +
  64.711 +   If the protocol permits the use of collations with data structures
  64.712 +   other than strings, the protocol MUST describe the default behavior
  64.713 +   for a collation with those data structures.
  64.714 +
  64.715 +6.  Use by Existing Protocols
  64.716 +
  64.717 +   This section is informative.
  64.718 +
  64.719 +   Both ACAP [11] and Sieve [14] are standards track specifications that
  64.720 +   used collations prior to the creation of this specification and
  64.721 +   registry.  Those standards do not meet all the application protocol
  64.722 +   requirements described in Section 5.
  64.723 +
  64.724 +   These protocols allow the use of the i;octet (Section 9.3) collation
  64.725 +   working directly on UTF-8 data, as used in these protocols.
  64.726 +
  64.727 +
  64.728 +
  64.729 +
  64.730 +
  64.731 +
  64.732 +
  64.733 +Newman, et al.              Standards Track                    [Page 13]
  64.734 +
  64.735 +RFC 4790                   Collation Registry                 March 2007
  64.736 +
  64.737 +
  64.738 +   In Sieve, all matches are either true or false.  Accordingly, Sieve
  64.739 +   servers must treat "undefined" and "no-match" results of the equality
  64.740 +   and substring operations as false, and only "match" as true.
  64.741 +
  64.742 +   In ACAP and Sieve, there are no invalid strings.  In this document's
  64.743 +   terms, invalid strings sort after valid strings.
  64.744 +
  64.745 +   IMAP [15] also collates, although that is explicit only when the
  64.746 +   COMPARATOR [17] extension is used.  The built-in IMAP substring
  64.747 +   operation and the ordering provided by the SORT [16] extension may
  64.748 +   not meet the requirements made in this document.
  64.749 +
  64.750 +   Other protocols may be in a similar position.
  64.751 +
  64.752 +   In IMAP, the default collation is i;ascii-casemap, because its
  64.753 +   operations are understood to match IMAP's built-in operations.
  64.754 +
  64.755 +7.  Collation Registration
  64.756 +
  64.757 +7.1.  Collation Registration Procedure
  64.758 +
  64.759 +   The IETF will create a mailing list, collation@ietf.org, which can be
  64.760 +   used for public discussion of collation proposals prior to
  64.761 +   registration.  Use of the mailing list is strongly encouraged.  The
  64.762 +   IESG will appoint a designated expert who will monitor the
  64.763 +   collation@ietf.org mailing list and review registrations.
  64.764 +
  64.765 +   The registration procedure begins when a completed registration
  64.766 +   template is sent to iana@iana.org and collation@ietf.org.  The
  64.767 +   designated expert is expected to tell IANA and the submitter of the
  64.768 +   registration within two weeks whether the registration is approved,
  64.769 +   approved with minor changes, or rejected with cause.  When a
  64.770 +   registration is rejected with cause, it can be re-submitted if the
  64.771 +   concerns listed in the cause are addressed.  Decisions made by the
  64.772 +   designated expert can be appealed to the IESG Applications Area
  64.773 +   Director, then to the IESG.  They follow the normal appeals procedure
  64.774 +   for IESG decisions.
  64.775 +
  64.776 +   Collation registrations in a standards track, BCP, or IESG-approved
  64.777 +   experimental RFC are owned by the IETF, and changes to the
  64.778 +   registration follow normal procedures for updating such documents.
  64.779 +   Collation registrations in other RFCs are owned by the RFC author(s).
  64.780 +   Other collation registrations are owned by the individual(s) listed
  64.781 +   in the contact field of the registration, and IANA will preserve this
  64.782 +   information.
  64.783 +
  64.784 +   If the registration is a change of an existing collation, it MUST be
  64.785 +   approved by the owner.  In the event the owner cannot be contacted
  64.786 +
  64.787 +
  64.788 +
  64.789 +Newman, et al.              Standards Track                    [Page 14]
  64.790 +
  64.791 +RFC 4790                   Collation Registry                 March 2007
  64.792 +
  64.793 +
  64.794 +   for a period of one month, and the designated expert deems the change
  64.795 +   necessary, the IESG MAY re-assign ownership to an appropriate party.
  64.796 +
  64.797 +7.2.  Collation Registration Format
  64.798 +
  64.799 +   Registration of a collation is done by sending a well-formed XML
  64.800 +   document to collation@ietf.org and iana@iana.org.
  64.801 +
  64.802 +7.2.1.  Registration Template
  64.803 +
  64.804 +   Here is a template for the registration:
  64.805 +
  64.806 +   <?xml version='1.0'?>
  64.807 +   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
  64.808 +   <collation rfc="YYYY" scope="global" intendedUse="common">
  64.809 +     <identifier>collation identifier</identifier>
  64.810 +     <title>technical title for collation</title>
  64.811 +     <operations>equality order substring</operations>
  64.812 +     <specification>specification reference</specification>
  64.813 +     <owner>email address of owner or IETF</owner>
  64.814 +     <submitter>email address of submitter</submitter>
  64.815 +     <version>1</version>
  64.816 +   </collation>
  64.817 +
  64.818 +7.2.2.  The Collation Element
  64.819 +
  64.820 +   The root of the registration document MUST be a <collation> element.
  64.821 +   The collation element contains the other elements in the
  64.822 +   registration, which are described in the following sub-subsections,
  64.823 +   in the order given here.
  64.824 +
  64.825 +   The <collation> element MAY include an "rfc=" attribute if the
  64.826 +   specification is in an RFC.  The "rfc=" attribute gives only the
  64.827 +   number of the RFC, without any prefix, such as "RFC", or suffix, such
  64.828 +   as ".txt".
  64.829 +
  64.830 +   The <collation> element MUST include a "scope=" attribute, which MUST
  64.831 +   have one of the values "global", "local", or "other".
  64.832 +
  64.833 +   The <collation> element MUST include an "intendedUse=" attribute,
  64.834 +   which must have one of the values "common", "limited", "vendor", or
  64.835 +   "deprecated".  Collation specifications intended for "common" use are
  64.836 +   expected to reference standards from standards bodies with
  64.837 +   significant experience dealing with the details of international
  64.838 +   character sets.
  64.839 +
  64.840 +   Be aware that future revisions of this specification may add
  64.841 +   additional function types, as well as additional XML attributes,
  64.842 +
  64.843 +
  64.844 +
  64.845 +Newman, et al.              Standards Track                    [Page 15]
  64.846 +
  64.847 +RFC 4790                   Collation Registry                 March 2007
  64.848 +
  64.849 +
  64.850 +   values, and elements.  Any system that automatically parses these XML
  64.851 +   documents MUST take this into account to preserve future
  64.852 +   compatibility.
  64.853 +
  64.854 +7.2.3.  The Identifier Element
  64.855 +
  64.856 +   The <identifier> element gives the precise identifier of the
  64.857 +   collation, e.g., i;ascii-casemap.  The <identifier> element is
  64.858 +   mandatory.
  64.859 +
  64.860 +7.2.4.  The Title Element
  64.861 +
  64.862 +   The <title> element gives the title of the collation.  The <title>
  64.863 +   element is mandatory.
  64.864 +
  64.865 +7.2.5.  The Operations Element
  64.866 +
  64.867 +   The <operations> element lists which of the three operations
  64.868 +   ("equality", "order" or "substring") the collation provides,
  64.869 +   separated by single spaces.  The <operations> element is mandatory.
  64.870 +
  64.871 +7.2.6.  The Specification Element
  64.872 +
  64.873 +   The <specification> element describes where to find the
  64.874 +   specification.  The <specification> element is mandatory.  It MAY
  64.875 +   have a URI attribute.  There may be more than one <specification>
  64.876 +   element, in which case, they together form the specification.
  64.877 +
  64.878 +   If it is discovered that parts of a collation specification conflict,
  64.879 +   a new revision of the collation is necessary, and the
  64.880 +   collation@ietf.org mailing list should be notified.
  64.881 +
  64.882 +7.2.7.  The Submitter Element
  64.883 +
  64.884 +   The <submitter> element provides an RFC 2822 [12] email address for
  64.885 +   the person who submitted the registration.  It is optional if the
  64.886 +   <owner> element contains an email address.
  64.887 +
  64.888 +   There may be more than one <submitter> element.
  64.889 +
  64.890 +7.2.8.  The Owner Element
  64.891 +
  64.892 +   The <owner> element contains either the four letters "IETF" or an
  64.893 +   email address of the owner of the registration.  The <owner> element
  64.894 +   is mandatory.  There may be more than one <owner> element.  If so,
  64.895 +   all owners are equal.  Each owner can speak for all.
  64.896 +
  64.897 +
  64.898 +
  64.899 +
  64.900 +
  64.901 +Newman, et al.              Standards Track                    [Page 16]
  64.902 +
  64.903 +RFC 4790                   Collation Registry                 March 2007
  64.904 +
  64.905 +
  64.906 +7.2.9.  The Version Element
  64.907 +
  64.908 +   The <version> element MUST be included when the registration is
  64.909 +   likely to be revised, or has been revised in such a way that the
  64.910 +   results change for one or more input strings.  The <version> element
  64.911 +   is optional.
  64.912 +
  64.913 +7.2.10.  The Variable Element
  64.914 +
  64.915 +   The <variable> element specifies an optional variable to control the
  64.916 +   collation's behaviour, for example whether it is case sensitive.  The
  64.917 +   <variable> element is optional.  When <variable> is used, it must
  64.918 +   contain <name> and <default> elements, and it may contain one or more
  64.919 +   <value> elements.
  64.920 +
  64.921 +7.2.10.1.  The Name Element
  64.922 +
  64.923 +   The <name> element specifies the name value of a variable.  The
  64.924 +   <name> element is mandatory.
  64.925 +
  64.926 +7.2.10.2.  The Default Element
  64.927 +
  64.928 +   The <default> element specifies the default value of a variable.  The
  64.929 +   <default> element is mandatory.
  64.930 +
  64.931 +7.2.10.3.  The Value Element
  64.932 +
  64.933 +   The <value> element specifies a legal value of a variable.  The
  64.934 +   <value> element is optional.  If one or more <value> elements are
  64.935 +   present, only those values are legal.  If none are, then the
  64.936 +   variable's legal values do not form an enumerated set, and the rules
  64.937 +   MUST be specified in an RFC accompanying the registration.
  64.938 +
  64.939 +7.3.  Structure of Collation Registry
  64.940 +
  64.941 +   Once the registration is approved, IANA will store each XML
  64.942 +   registration document in a URL of the form
  64.943 +   http://www.iana.org/assignments/collation/collation-id.xml, where
  64.944 +   collation-id is the content of the identifier element in the
  64.945 +   registration.  Both the submitter and the designated expert are
  64.946 +   responsible for verifying that the XML is well-formed.  The
  64.947 +   registration document should avoid using new elements.  If any are
  64.948 +   necessary, it is important to be consistent with other registrations.
  64.949 +
  64.950 +   IANA will also maintain a text summary of the registry under the name
  64.951 +   http://www.iana.org/assignments/collation/collation-index.html.  This
  64.952 +   summary is divided into four sections.  The first section is for
  64.953 +   collations intended for common use.  This section is intended for
  64.954 +
  64.955 +
  64.956 +
  64.957 +Newman, et al.              Standards Track                    [Page 17]
  64.958 +
  64.959 +RFC 4790                   Collation Registry                 March 2007
  64.960 +
  64.961 +
  64.962 +   collation registrations published in IESG-approved RFCs, or for
  64.963 +   locally scoped collations from the primary standards body for that
  64.964 +   locale.  The designated expert is encouraged to reject collation
  64.965 +   registrations with an intended use of "common" if the expert believes
  64.966 +   it should be "limited", as it is desirable to keep the number of
  64.967 +   "common" registrations small and of high quality.  The second section
  64.968 +   is reserved for limited-use collations.  The third section is
  64.969 +   reserved for registered vendor-specific collations.  The final
  64.970 +   section is reserved for deprecated collations.
  64.971 +
  64.972 +7.4.  Example Initial Registry Summary
  64.973 +
  64.974 +   The following is an example of how IANA might structure the initial
  64.975 +   registry summary.html file:
  64.976 +
  64.977 +     Collation                              Functions Scope Reference
  64.978 +     ---------                              --------- ----- ---------
  64.979 +   Common Use Collations:
  64.980 +     i;ascii-casemap                        e, o, s   Local [RFC 4790]
  64.981 +
  64.982 +   Limited Use Collations:
  64.983 +     i;octet                                e, o, s   Other [RFC 4790]
  64.984 +     i;ascii-numeric                        e, o      Other [RFC 4790]
  64.985 +
  64.986 +   Vendor Collations:
  64.987 +
  64.988 +   Deprecated Collations:
  64.989 +
  64.990 +
  64.991 +   References
  64.992 +   ----------
  64.993 +   [RFC 4790]  Newman, C., Duerst, M., Gulbrandsen, A., "Internet
  64.994 +               Application Protocol Collation Registry", RFC 4790,
  64.995 +               Sun Microsystems, March 2007.
  64.996 +
  64.997 +8.  Guidelines for Expert Reviewer
  64.998 +
  64.999 +   The expert reviewer appointed by the IESG has fairly broad latitude
 64.1000 +   for this registry.  While a number of collations are expected
 64.1001 +   (particularly customizations of the UCA for localized use), an
 64.1002 +   explosion of collations (particularly common-use collations) is not
 64.1003 +   desirable for widespread interoperability.  However, it is important
 64.1004 +   for the expert reviewer to provide cause when rejecting a
 64.1005 +   registration, and, when possible, to describe corrective action to
 64.1006 +
 64.1007 +
 64.1008 +
 64.1009 +
 64.1010 +
 64.1011 +
 64.1012 +
 64.1013 +Newman, et al.              Standards Track                    [Page 18]
 64.1014 +
 64.1015 +RFC 4790                   Collation Registry                 March 2007
 64.1016 +
 64.1017 +
 64.1018 +   permit the registration to proceed.  The following table includes
 64.1019 +   some example reasons to reject a registration with cause:
 64.1020 +
 64.1021 +   o  The registration is not a well-formed XML document.
 64.1022 +
 64.1023 +   o  The registration has an intended use of "common", but there is no
 64.1024 +      evidence the collation will be widely deployed, so it should be
 64.1025 +      listed as "limited".
 64.1026 +
 64.1027 +   o  The registration has an intended use of "common", but it is
 64.1028 +      redundant with the functionality of a previously registered
 64.1029 +      "common" collation.
 64.1030 +
 64.1031 +   o  The registration has an intended use of "common", but the
 64.1032 +      specification is not detailed enough to allow interoperable
 64.1033 +      implementations by others.
 64.1034 +
 64.1035 +   o  The collation identifier fails to precisely identify the version
 64.1036 +      numbers of relevant tables to use.
 64.1037 +
 64.1038 +   o  The registration fails to meet one of the "MUST" requirements in
 64.1039 +      Section 4.
 64.1040 +
 64.1041 +   o  The collation identifier fails to meet the syntax in Section 3.
 64.1042 +
 64.1043 +   o  The collation specification referenced in the registration is
 64.1044 +      vague or has optional features without a clear behavior specified.
 64.1045 +
 64.1046 +   o  The referenced specification does not adequately address security
 64.1047 +      considerations specific to that collation.
 64.1048 +
 64.1049 +   o  The registration's operations are needlessly different from those
 64.1050 +      of traditional operations.
 64.1051 +
 64.1052 +   o  The registration's XML is needlessly different from that of
 64.1053 +      already registered collations.
 64.1054 +
 64.1055 +9.  Initial Collations
 64.1056 +
 64.1057 +   This section registers the three collations that were originally
 64.1058 +   defined in [11], and are implemented in most [14] engines.  Some of
 64.1059 +   the behavior of these collations is perhaps not ideal, such as
 64.1060 +   i;ascii-casemap accepting non-ASCII input.  Compatibility with widely
 64.1061 +   deployed code was judged more important than fixing the collations.
 64.1062 +   Some of the aspects of these collations are necessary to maintain
 64.1063 +   compatibility with widely deployed code.
 64.1064 +
 64.1065 +
 64.1066 +
 64.1067 +
 64.1068 +
 64.1069 +Newman, et al.              Standards Track                    [Page 19]
 64.1070 +
 64.1071 +RFC 4790                   Collation Registry                 March 2007
 64.1072 +
 64.1073 +
 64.1074 +9.1.  ASCII Numeric Collation
 64.1075 +
 64.1076 +9.1.1.  ASCII Numeric Collation Description
 64.1077 +
 64.1078 +   The "i;ascii-numeric" collation is a simple collation intended for
 64.1079 +   use with arbitrarily-sized, unsigned decimal integer numbers stored
 64.1080 +   as octet strings.  US-ASCII digits (0x30 to 0x39) represent digits of
 64.1081 +   the numbers.  Before converting from string to integer, the input
 64.1082 +   string is truncated at the first non-digit character.  All input is
 64.1083 +   valid; strings that do not start with a digit represent positive
 64.1084 +   infinity.
 64.1085 +
 64.1086 +   The collation supports equality and ordering, but does not support
 64.1087 +   the substring operation.
 64.1088 +
 64.1089 +   The equality operation returns "match" if the two strings represent
 64.1090 +   the same number (i.e., leading zeroes and trailing non-digits are
 64.1091 +   disregarded), and "no-match" if the two strings represent different
 64.1092 +   numbers.
 64.1093 +
 64.1094 +   The ordering operation returns "less" if the first string represents
 64.1095 +   a smaller number than the second, "equal" if they represent the same
 64.1096 +   number, and "greater" if the first string represents a larger number
 64.1097 +   than the second.
 64.1098 +
 64.1099 +   Some examples: "0" is less than "1", and "1" is less than
 64.1100 +   "4294967298". "4294967298", "04294967298", and "4294967298b" are all
 64.1101 +   equal. "04294967298" is less than "". "", "x", and "y" are equal.
 64.1102 +
 64.1103 +9.1.2.  ASCII Numeric Collation Registration
 64.1104 +
 64.1105 +   <?xml version='1.0'?>
 64.1106 +   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
 64.1107 +   <collation rfc="4790" scope="other" intendedUse="limited">
 64.1108 +     <identifier>i;ascii-numeric</identifier>
 64.1109 +     <title>ASCII Numeric</title>
 64.1110 +     <operations>equality order</operations>
 64.1111 +     <specification>RFC 4790</specification>
 64.1112 +     <owner>IETF</owner>
 64.1113 +     <submitter>chris.newman@sun.com</submitter>
 64.1114 +   </collation>
 64.1115 +
 64.1116 +
 64.1117 +
 64.1118 +
 64.1119 +
 64.1120 +
 64.1121 +
 64.1122 +
 64.1123 +
 64.1124 +
 64.1125 +Newman, et al.              Standards Track                    [Page 20]
 64.1126 +
 64.1127 +RFC 4790                   Collation Registry                 March 2007
 64.1128 +
 64.1129 +
 64.1130 +9.2.  ASCII Casemap Collation
 64.1131 +
 64.1132 +9.2.1.  ASCII Casemap Collation Description
 64.1133 +
 64.1134 +   The "i;ascii-casemap" collation is a simple collation that operates
 64.1135 +   on octet strings and treats US-ASCII letters case-insensitively.  It
 64.1136 +   provides equality, substring, and ordering operations.  All input is
 64.1137 +   valid.  Note that letters outside ASCII are not treated case-
 64.1138 +   insensitively.
 64.1139 +
 64.1140 +   Its equality, ordering, and substring operations are as for i;octet,
 64.1141 +   except that at first, the lower-case letters (octet values 97-122) in
 64.1142 +   each input string are changed to upper case (octet values 65-90).
 64.1143 +
 64.1144 +   Care should be taken when using OS-supplied functions to implement
 64.1145 +   this collation, as it is not locale sensitive.  Functions, such as
 64.1146 +   strcasecmp and toupper, are sometimes locale sensitive, and may
 64.1147 +   inappropriately map lower-case letters other than a-z to upper case.
 64.1148 +
 64.1149 +   The i;ascii-casemap collation is well-suited for use with many
 64.1150 +   Internet protocols and computer languages.  Use with natural language
 64.1151 +   is often inappropriate; even though the collation apparently supports
 64.1152 +   languages such as Swahili and English, in real-world use, it tends to
 64.1153 +   mis-sort a number of types of string:
 64.1154 +
 64.1155 +   o  people and place names containing non-ASCII,
 64.1156 +
 64.1157 +   o  words such as "naive" (if spelled with an accent, the accented
 64.1158 +      character could push the word to the wrong spot in a sorted list),
 64.1159 +
 64.1160 +   o  names such as "Lloyd" (which, in Welsh, sorts after "Lyon", unlike
 64.1161 +      in English),
 64.1162 +
 64.1163 +   o  strings containing euro and pound sterling symbols, quotation
 64.1164 +      marks other than '"', dashes/hyphens, etc.
 64.1165 +
 64.1166 +
 64.1167 +
 64.1168 +
 64.1169 +
 64.1170 +
 64.1171 +
 64.1172 +
 64.1173 +
 64.1174 +
 64.1175 +
 64.1176 +
 64.1177 +
 64.1178 +
 64.1179 +
 64.1180 +
 64.1181 +Newman, et al.              Standards Track                    [Page 21]
 64.1182 +
 64.1183 +RFC 4790                   Collation Registry                 March 2007
 64.1184 +
 64.1185 +
 64.1186 +9.2.2.  ASCII Casemap Collation Registration
 64.1187 +
 64.1188 +   <?xml version='1.0'?>
 64.1189 +   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
 64.1190 +   <collation rfc="4790" scope="local" intendedUse="common">
 64.1191 +     <identifier>i;ascii-casemap</identifier>
 64.1192 +     <title>ASCII Casemap</title>
 64.1193 +     <operations>equality order substring</operations>
 64.1194 +     <specification>RFC 4790</specification>
 64.1195 +     <owner>IETF</owner>
 64.1196 +     <submitter>chris.newman@sun.com</submitter>
 64.1197 +   </collation>
 64.1198 +
 64.1199 +9.3.  Octet Collation
 64.1200 +
 64.1201 +9.3.1.  Octet Collation Description
 64.1202 +
 64.1203 +   The "i;octet" collation is a simple and fast collation intended for
 64.1204 +   use on binary octet strings rather than on character data.  Protocols
 64.1205 +   that want to make this collation available have to do so by
 64.1206 +   explicitly allowing it.  If not explicitly allowed, it MUST NOT be
 64.1207 +   used.  It never returns an "undefined" result.  It provides equality,
 64.1208 +   substring, and ordering operations.
 64.1209 +
 64.1210 +   The ordering algorithm is as follows:
 64.1211 +
 64.1212 +   1.  If both strings are the empty string, return the result "equal".
 64.1213 +
 64.1214 +   2.  If the first string is empty and the second is not, return the
 64.1215 +       result "less".
 64.1216 +
 64.1217 +   3.  If the second string is empty and the first is not, return the
 64.1218 +       result "greater".
 64.1219 +
 64.1220 +   4.  If both strings begin with the same octet value, remove the first
 64.1221 +       octet from both strings and repeat this algorithm from step 1.
 64.1222 +
 64.1223 +   5.  If the unsigned value (0 to 255) of the first octet of the first
 64.1224 +       string is less than the unsigned value of the first octet of the
 64.1225 +       second string, then return "less".
 64.1226 +
 64.1227 +   6.  If this step is reached, return "greater".
 64.1228 +
 64.1229 +   This algorithm is roughly equivalent to the C library function
 64.1230 +   memcmp, with appropriate length checks added.
 64.1231 +
 64.1232 +
 64.1233 +
 64.1234 +
 64.1235 +
 64.1236 +
 64.1237 +Newman, et al.              Standards Track                    [Page 22]
 64.1238 +
 64.1239 +RFC 4790                   Collation Registry                 March 2007
 64.1240 +
 64.1241 +
 64.1242 +   The matching operation returns "match" if the sorting algorithm would
 64.1243 +   return "equal".  Otherwise, the matching operation returns "no-
 64.1244 +   match".
 64.1245 +
 64.1246 +   The substring operation returns "match" if the first string is the
 64.1247 +   empty string, or if there exists a substring of the second string of
 64.1248 +   length equal to the length of the first string, which would result in
 64.1249 +   a "match" result from the equality function.  Otherwise, the
 64.1250 +   substring operation returns "no-match".
 64.1251 +
 64.1252 +9.3.2.  Octet Collation Registration
 64.1253 +
 64.1254 +   This collation is defined with intendedUse="limited" because it can
 64.1255 +   only be used by protocols that explicitly allow it.
 64.1256 +
 64.1257 +   <?xml version='1.0'?>
 64.1258 +   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
 64.1259 +   <collation rfc="4790" scope="global" intendedUse="limited">
 64.1260 +     <identifier>i;octet</identifier>
 64.1261 +     <title>Octet</title>
 64.1262 +     <operations>equality order substring</operations>
 64.1263 +     <specification>RFC 4790</specification>
 64.1264 +     <owner>IETF</owner>
 64.1265 +     <submitter>chris.newman@sun.com</submitter>
 64.1266 +   </collation>
 64.1267 +
 64.1268 +10.  IANA Considerations
 64.1269 +
 64.1270 +   Section 7 defines how to register collations with IANA.  Section 9
 64.1271 +   defines a list of predefined collations that have been registered
 64.1272 +   with IANA.
 64.1273 +
 64.1274 +11.  Security Considerations
 64.1275 +
 64.1276 +   Collations will normally be used with UTF-8 strings.  Thus, the
 64.1277 +   security considerations for UTF-8 [3], stringprep [6], and Unicode
 64.1278 +   TR-36 [8] also apply, and are normative to this specification.
 64.1279 +
 64.1280 +12.  Acknowledgements
 64.1281 +
 64.1282 +   The authors want to thank all who have contributed to this document,
 64.1283 +   including Brian Carpenter, John Cowan, Dave Cridland, Mark Davis,
 64.1284 +   Spencer Dawkins, Lisa Dusseault, Lars Eggert, Frank Ellermann, Philip
 64.1285 +   Guenther, Tony Hansen, Ted Hardie, Sam Hartman, Kjetil Torgrim Homme,
 64.1286 +   Michael Kay, John Klensin, Alexey Melnikov, Jim Melton, and Abhijit
 64.1287 +   Menon-Sen.
 64.1288 +
 64.1289 +
 64.1290 +
 64.1291 +
 64.1292 +
 64.1293 +Newman, et al.              Standards Track                    [Page 23]
 64.1294 +
 64.1295 +RFC 4790                   Collation Registry                 March 2007
 64.1296 +
 64.1297 +
 64.1298 +13.  References
 64.1299 +
 64.1300 +13.1.  Normative References
 64.1301 +
 64.1302 +   [1]   Bradner, S., "Key words for use in RFCs to Indicate Requirement
 64.1303 +         Levels", BCP 14, RFC 2119, March 1997.
 64.1304 +
 64.1305 +   [2]   Crocker, D. and P. Overell, "Augmented BNF for Syntax
 64.1306 +         Specifications: ABNF", RFC 4234, October 2005.
 64.1307 +
 64.1308 +   [3]   Yergeau, F., "UTF-8, a transformation format of ISO 10646",
 64.1309 +         STD 63, RFC 3629, November 2003.
 64.1310 +
 64.1311 +   [4]   Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
 64.1312 +         Resource Identifier (URI): Generic Syntax", RFC 3986,
 64.1313 +         January 2005.
 64.1314 +
 64.1315 +   [5]   Phillips, A. and M. Davis, "Tags for Identifying Languages",
 64.1316 +         BCP 47, RFC 4646, September 2006.
 64.1317 +
 64.1318 +   [6]   Hoffman, P. and M. Blanchet, "Preparation of Internationalized
 64.1319 +         Strings ("stringprep")", RFC 3454, December 2002.
 64.1320 +
 64.1321 +   [7]   Davis, M. and K. Whistler, "Unicode Collation Algorithm version
 64.1322 +         14", May 2005,
 64.1323 +         <http://www.unicode.org/reports/tr10/tr10-14.html>.
 64.1324 +
 64.1325 +   [8]   Davis, M. and M. Suignard, "Unicode Security Considerations",
 64.1326 +         February 2006, <http://www.unicode.org/reports/tr36/>.
 64.1327 +
 64.1328 +13.2.  Informative References
 64.1329 +
 64.1330 +   [9]   Freed, N. and N. Borenstein, "Multipurpose Internet Mail
 64.1331 +         Extensions (MIME) Part One: Format of Internet Message Bodies",
 64.1332 +         RFC 2045, November 1996.
 64.1333 +
 64.1334 +   [10]  Melnikov, A., "Simple Authentication and Security Layer
 64.1335 +         (SASL)", RFC 4422, June 2006.
 64.1336 +
 64.1337 +   [11]  Newman, C. and J. Myers, "ACAP -- Application Configuration
 64.1338 +         Access Protocol", RFC 2244, November 1997.
 64.1339 +
 64.1340 +   [12]  Resnick, P., "Internet Message Format", RFC 2822, April 2001.
 64.1341 +
 64.1342 +   [13]  Freed, N. and J. Postel, "IANA Charset Registration
 64.1343 +         Procedures", BCP 19, RFC 2978, October 2000.
 64.1344 +
 64.1345 +
 64.1346 +
 64.1347 +
 64.1348 +
 64.1349 +Newman, et al.              Standards Track                    [Page 24]
 64.1350 +
 64.1351 +RFC 4790                   Collation Registry                 March 2007
 64.1352 +
 64.1353 +
 64.1354 +   [14]  Showalter, T., "Sieve: A Mail Filtering Language", RFC 3028,
 64.1355 +         January 2001.
 64.1356 +
 64.1357 +   [15]  Crispin, M., "Internet Message Access Protocol - Version
 64.1358 +         4rev1", RFC 3501, March 2003.
 64.1359 +
 64.1360 +   [16]  Crispin, M. and K. Murchison, "Internet Message Access Protocol
 64.1361 +         - Sort and Thread Extensions", Work in Progress, May 2004.
 64.1362 +
 64.1363 +   [17]  Newman, C. and A. Gulbrandsen, "Internet Message Access
 64.1364 +         Protocol Internationalization", Work in Progress, January 2006.
 64.1365 +
 64.1366 +Authors' Addresses
 64.1367 +
 64.1368 +   Chris Newman
 64.1369 +   Sun Microsystems
 64.1370 +   1050 Lakes Drive
 64.1371 +   West Covina, CA  91790
 64.1372 +   USA
 64.1373 +
 64.1374 +   EMail: chris.newman@sun.com
 64.1375 +
 64.1376 +
 64.1377 +   Martin Duerst
 64.1378 +   Aoyama Gakuin University
 64.1379 +   5-10-1 Fuchinobe
 64.1380 +   Sagamihara, Kanagawa  229-8558
 64.1381 +   Japan
 64.1382 +
 64.1383 +   Phone: +81 42 759 6329
 64.1384 +   Fax:   +81 42 759 6495
 64.1385 +   EMail: duerst@it.aoyama.ac.jp
 64.1386 +   URI:   http://www.sw.it.aoyama.ac.jp/D%C3%BCrst/
 64.1387 +
 64.1388 +   Note: Please write "Duerst" with u-umlaut wherever possible, for
 64.1389 +   example as "D&#252;rst" in XML and HTML.
 64.1390 +
 64.1391 +
 64.1392 +   Arnt Gulbrandsen
 64.1393 +   Oryx Mail Systems GmbH
 64.1394 +   Schweppermannstr. 8
 64.1395 +   81671 Munich
 64.1396 +   Germany
 64.1397 +
 64.1398 +   Fax:   +49 89 4502 9758
 64.1399 +   EMail: arnt@oryx.com
 64.1400 +   URI:   http://www.oryx.com/arnt/
 64.1401 +
 64.1402 +
 64.1403 +
 64.1404 +
 64.1405 +Newman, et al.              Standards Track                    [Page 25]
 64.1406 +
 64.1407 +RFC 4790                   Collation Registry                 March 2007
 64.1408 +
 64.1409 +
 64.1410 +Full Copyright Statement
 64.1411 +
 64.1412 +   Copyright (C) The IETF Trust (2007).
 64.1413 +
 64.1414 +   This document is subject to the rights, licenses and restrictions
 64.1415 +   contained in BCP 78, and except as set forth therein, the authors
 64.1416 +   retain all their rights.
 64.1417 +
 64.1418 +   This document and the information contained herein are provided on an
 64.1419 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 64.1420 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
 64.1421 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
 64.1422 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
 64.1423 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 64.1424 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 64.1425 +
 64.1426 +Intellectual Property
 64.1427 +
 64.1428 +   The IETF takes no position regarding the validity or scope of any
 64.1429 +   Intellectual Property Rights or other rights that might be claimed to
 64.1430 +   pertain to the implementation or use of the technology described in
 64.1431 +   this document or the extent to which any license under such rights
 64.1432 +   might or might not be available; nor does it represent that it has
 64.1433 +   made any independent effort to identify any such rights.  Information
 64.1434 +   on the procedures with respect to rights in RFC documents can be
 64.1435 +   found in BCP 78 and BCP 79.
 64.1436 +
 64.1437 +   Copies of IPR disclosures made to the IETF Secretariat and any
 64.1438 +   assurances of licenses to be made available, or the result of an
 64.1439 +   attempt made to obtain a general license or permission for the use of
 64.1440 +   such proprietary rights by implementers or users of this
 64.1441 +   specification can be obtained from the IETF on-line IPR repository at
 64.1442 +   http://www.ietf.org/ipr.
 64.1443 +
 64.1444 +   The IETF invites any interested party to bring to its attention any
 64.1445 +   copyrights, patents or patent applications, or other proprietary
 64.1446 +   rights that may cover technology that may be required to implement
 64.1447 +   this standard.  Please address the information to the IETF at
 64.1448 +   ietf-ipr@ietf.org.
 64.1449 +
 64.1450 +Acknowledgement
 64.1451 +
 64.1452 +   Funding for the RFC Editor function is currently provided by the
 64.1453 +   Internet Society.
 64.1454 +
 64.1455 +
 64.1456 +
 64.1457 +
 64.1458 +
 64.1459 +
 64.1460 +
 64.1461 +Newman, et al.              Standards Track                    [Page 26]
 64.1462 +
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/docs/rfc/rfc4959.txt	Mon Sep 14 15:17:45 2009 +0900
    65.3 @@ -0,0 +1,395 @@
    65.4 +
    65.5 +
    65.6 +
    65.7 +
    65.8 +
    65.9 +
   65.10 +Network Working Group                                      R. Siemborski
   65.11 +Request for Comments: 4959                                  Google, Inc.
   65.12 +Category: Standards Track                                 A. Gulbrandsen
   65.13 +                                                  Oryx Mail Systems GmbH
   65.14 +                                                          September 2007
   65.15 +
   65.16 +
   65.17 +   IMAP Extension for Simple Authentication and Security Layer (SASL)
   65.18 +                        Initial Client Response
   65.19 +
   65.20 +Status of This Memo
   65.21 +
   65.22 +   This document specifies an Internet standards track protocol for the
   65.23 +   Internet community, and requests discussion and suggestions for
   65.24 +   improvements.  Please refer to the current edition of the "Internet
   65.25 +   Official Protocol Standards" (STD 1) for the standardization state
   65.26 +   and status of this protocol.  Distribution of this memo is unlimited.
   65.27 +
   65.28 +Abstract
   65.29 +
   65.30 +   To date, the Internet Message Access Protocol (IMAP) has used a
   65.31 +   Simple Authentication and Security Layer (SASL) profile which always
   65.32 +   required at least one complete round trip for an authentication, as
   65.33 +   it did not support an initial client response argument.  This
   65.34 +   additional round trip at the beginning of the session is undesirable,
   65.35 +   especially when round-trip costs are high.
   65.36 +
   65.37 +   This document defines an extension to IMAP which allows clients and
   65.38 +   servers to avoid this round trip by allowing an initial client
   65.39 +   response argument to the IMAP AUTHENTICATE command.
   65.40 +
   65.41 +
   65.42 +
   65.43 +
   65.44 +
   65.45 +
   65.46 +
   65.47 +
   65.48 +
   65.49 +
   65.50 +
   65.51 +
   65.52 +
   65.53 +
   65.54 +
   65.55 +
   65.56 +
   65.57 +
   65.58 +
   65.59 +
   65.60 +
   65.61 +Siemborski & Gulbrandsen  Standards Track                       [Page 1]
   65.62 +
   65.63 +RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
   65.64 +
   65.65 +
   65.66 +1.  Introduction
   65.67 +
   65.68 +   The SASL initial client response extension is present in any IMAP
   65.69 +   [RFC3501] server implementation which returns "SASL-IR" as one of the
   65.70 +   supported capabilities in its CAPABILITY response.
   65.71 +
   65.72 +   Servers which support this extension will accept an optional initial
   65.73 +   client response with the AUTHENTICATE command for any SASL [RFC4422]
   65.74 +   mechanisms which support it.
   65.75 +
   65.76 +2.  Conventions Used in This Document
   65.77 +
   65.78 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   65.79 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   65.80 +   document are to be interpreted as described in [RFC2119].
   65.81 +
   65.82 +   In examples, "C:" and "S:" indicate lines sent by the client and
   65.83 +   server, respectively.
   65.84 +
   65.85 +   Formal syntax is defined by [RFC4234] as extended by [RFC3501].
   65.86 +
   65.87 +3.  IMAP Changes to the IMAP AUTHENTICATE Command
   65.88 +
   65.89 +   This extension adds an optional second argument to the AUTHENTICATE
   65.90 +   command that is defined in Section 6.2.2 of [RFC3501].  If this
   65.91 +   second argument is present, it represents the contents of the
   65.92 +   "initial client response" defined in Section 5.1 of [RFC4422].
   65.93 +
   65.94 +   As with any other client response, this initial client response MUST
   65.95 +   be encoded as defined in Section 4 of [RFC4648].  It also MUST be
   65.96 +   transmitted outside of a quoted string or literal.  To send a zero-
   65.97 +   length initial response, the client MUST send a single pad character
   65.98 +   ("=").  This indicates that the response is present, but is a zero-
   65.99 +   length string.
  65.100 +
  65.101 +   When decoding the BASE64 [RFC4648] data in the initial client
  65.102 +   response, decoding errors MUST be treated as IMAP [RFC3501] would
  65.103 +   handle them in any normal SASL client response.  In particular, the
  65.104 +   server should check for any characters not explicitly allowed by the
  65.105 +   BASE64 alphabet, as well as any sequence of BASE64 characters that
  65.106 +   contains the pad character ('=') anywhere other than the end of the
  65.107 +   string (e.g., "=AAA" and "AAA=BBB" are not allowed).
  65.108 +
  65.109 +   If the client uses an initial response with a SASL mechanism that
  65.110 +   does not support an initial response, the server MUST reject the
  65.111 +   command with a tagged BAD response.
  65.112 +
  65.113 +
  65.114 +
  65.115 +
  65.116 +
  65.117 +Siemborski & Gulbrandsen  Standards Track                       [Page 2]
  65.118 +
  65.119 +RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
  65.120 +
  65.121 +
  65.122 +   Note: support and use of the initial client response is optional for
  65.123 +   both clients and servers.  Servers that implement this extension MUST
  65.124 +   support clients that omit the initial client response, and clients
  65.125 +   that implement this extension MUST NOT send an initial client
  65.126 +   response to servers that do not advertise the SASL-IR capability.  In
  65.127 +   such a situation, clients MUST fall back to an IMAP [RFC3501]
  65.128 +   compatible mode.
  65.129 +
  65.130 +   If either the client or the server do not support the SASL-IR
  65.131 +   capability, a mechanism which uses an initial client response is
  65.132 +   negotiated using the challenge/response exchange described in
  65.133 +   [RFC3501], with an initial zero-length server challenge.
  65.134 +
  65.135 +4.  Examples
  65.136 +
  65.137 +   The following is an example authentication using the PLAIN (see
  65.138 +   [RFC4616]) SASL mechanism (under a TLS protection layer, see
  65.139 +   [RFC4346]) and an initial client response:
  65.140 +
  65.141 +            ... client connects to server and negotiates a TLS
  65.142 +           protection layer ...
  65.143 +        C: C01 CAPABILITY
  65.144 +        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN
  65.145 +        S: C01 OK Completed
  65.146 +        C: A01 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
  65.147 +        S: A01 OK Success (tls protection)
  65.148 +
  65.149 +   Note that even when a server supports this extension, the following
  65.150 +   negotiation (which does not use the initial response) is still valid
  65.151 +   and MUST be supported by the server:
  65.152 +
  65.153 +            ... client connects to server and negotiates a TLS
  65.154 +           protection layer ...
  65.155 +        C: C01 CAPABILITY
  65.156 +        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN
  65.157 +        S: C01 OK Completed
  65.158 +        C: A01 AUTHENTICATE PLAIN
  65.159 +            (note that there is a space following the "+" in the
  65.160 +           following line)
  65.161 +        S: +
  65.162 +        C: dGVzdAB0ZXN0AHRlc3Q=
  65.163 +        S: A01 OK Success (tls protection)
  65.164 +
  65.165 +   The following is an example authentication using the SASL EXTERNAL
  65.166 +   mechanism (defined in [RFC4422]) under a TLS protection layer (see
  65.167 +   [RFC4346]) and an empty initial client response:
  65.168 +
  65.169 +
  65.170 +
  65.171 +
  65.172 +
  65.173 +Siemborski & Gulbrandsen  Standards Track                       [Page 3]
  65.174 +
  65.175 +RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
  65.176 +
  65.177 +
  65.178 +            ... client connects to server and negotiates a TLS
  65.179 +           protection layer ...
  65.180 +        C: C01 CAPABILITY
  65.181 +        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN AUTH=EXTERNAL
  65.182 +        S: C01 OK Completed
  65.183 +        C: A01 AUTHENTICATE EXTERNAL =
  65.184 +        S: A01 OK Success (tls protection)
  65.185 +
  65.186 +   This is in contrast with the handling of such a situation when an
  65.187 +   initial response is omitted:
  65.188 +
  65.189 +         ... client connects to server and negotiates a TLS protection
  65.190 +           layer ...
  65.191 +        C: C01 CAPABILITY
  65.192 +        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN AUTH=EXTERNAL
  65.193 +        S: C01 OK Completed
  65.194 +        C: A01 AUTHENTICATE EXTERNAL
  65.195 +            (note that there is a space following the "+" in the
  65.196 +           following line)
  65.197 +        S: +
  65.198 +        C:
  65.199 +        S: A01 OK Success (tls protection)
  65.200 +
  65.201 +5.  IANA Considerations
  65.202 +
  65.203 +   The IANA has added SASL-IR to the IMAP4 Capabilities Registry.
  65.204 +
  65.205 +6.  Security Considerations
  65.206 +
  65.207 +   The extension defined in this document is subject to many of the
  65.208 +   Security Considerations defined in [RFC3501] and [RFC4422].
  65.209 +
  65.210 +   Server implementations MUST treat the omission of an initial client
  65.211 +   response from the AUTHENTICATE command as defined by [RFC3501] (as if
  65.212 +   this extension did not exist).
  65.213 +
  65.214 +   Although [RFC3501] has no express line length limitations, some
  65.215 +   implementations choose to enforce them anyway.  Such implementations
  65.216 +   MUST be aware that the addition of the initial response parameter to
  65.217 +   AUTHENTICATE may increase the maximum line length that IMAP parsers
  65.218 +   may expect to support.  Server implementations MUST be able to
  65.219 +   receive the largest possible initial client response that their
  65.220 +   supported mechanisms might receive.
  65.221 +
  65.222 +
  65.223 +
  65.224 +
  65.225 +
  65.226 +
  65.227 +
  65.228 +
  65.229 +Siemborski & Gulbrandsen  Standards Track                       [Page 4]
  65.230 +
  65.231 +RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
  65.232 +
  65.233 +
  65.234 +7.  Formal Syntax
  65.235 +
  65.236 +   The following syntax specification uses the Augmented Backus-Naur
  65.237 +   Form [RFC4234] notation.  [RFC3501] defines the non-terminals
  65.238 +   capability, auth-type, and base64.
  65.239 +
  65.240 +      capability    =/ "SASL-IR"
  65.241 +
  65.242 +      authenticate  = "AUTHENTICATE" SP auth-type [SP (base64 / "=")]
  65.243 +                      *(CRLF base64)
  65.244 +                      ;;redefine AUTHENTICATE from [RFC3501]
  65.245 +
  65.246 +8.  Acknowledgments
  65.247 +
  65.248 +   The authors would like to acknowledge the contributions of Ken
  65.249 +   Murchison and Mark Crispin, along with the rest of the IMAPEXT
  65.250 +   Working Group for their assistance in reviewing this document.
  65.251 +
  65.252 +   Alexey Melnikov and Cyrus Daboo also had some early discussions about
  65.253 +   this extension.
  65.254 +
  65.255 +9.  References
  65.256 +
  65.257 +9.1.  Normative References
  65.258 +
  65.259 +   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
  65.260 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  65.261 +
  65.262 +   [RFC3501]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  65.263 +              4rev1", RFC 3501, March 2003.
  65.264 +
  65.265 +   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
  65.266 +              Specifications: ABNF", RFC 4234, October 2005.
  65.267 +
  65.268 +   [RFC4422]  Melnikov, A. and  K. Zeilenga, "Simple Authentication and
  65.269 +              Security Layer (SASL)", RFC 4422, June 2006.
  65.270 +
  65.271 +   [RFC4648]  Josefsson, S., "The Base16, Base32, and Base64 Data
  65.272 +              Encodings", RFC 4648, October 2006.
  65.273 +
  65.274 +9.2.  Informative References
  65.275 +
  65.276 +   [RFC4616]  Zeilenga, K., "The PLAIN Simple Authentication and
  65.277 +              Security Layer (SASL) Mechanism", RFC 4616, August 2006.
  65.278 +
  65.279 +   [RFC4346]  Dierks, T. and E. Rescorla, "The Transport Layer Security
  65.280 +              (TLS) Protocol Version 1.1", RFC 4346, April 2006.
  65.281 +
  65.282 +
  65.283 +
  65.284 +
  65.285 +Siemborski & Gulbrandsen  Standards Track                       [Page 5]
  65.286 +
  65.287 +RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
  65.288 +
  65.289 +
  65.290 +Authors' Addresses
  65.291 +
  65.292 +   Robert Siemborski
  65.293 +   Google, Inc.
  65.294 +   1600 Ampitheatre Parkway
  65.295 +   Mountain View, CA 94043
  65.296 +
  65.297 +   Phone: +1 650 623 6925
  65.298 +   EMail: robsiemb@google.com
  65.299 +
  65.300 +
  65.301 +   Arnt Gulbrandsen
  65.302 +   Oryx Mail Systems GmbH
  65.303 +   Schweppermannstr. 8
  65.304 +   D-81671 Muenchen
  65.305 +   Germany
  65.306 +
  65.307 +   EMail: arnt@oryx.com
  65.308 +
  65.309 +
  65.310 +
  65.311 +
  65.312 +
  65.313 +
  65.314 +
  65.315 +
  65.316 +
  65.317 +
  65.318 +
  65.319 +
  65.320 +
  65.321 +
  65.322 +
  65.323 +
  65.324 +
  65.325 +
  65.326 +
  65.327 +
  65.328 +
  65.329 +
  65.330 +
  65.331 +
  65.332 +
  65.333 +
  65.334 +
  65.335 +
  65.336 +
  65.337 +
  65.338 +
  65.339 +
  65.340 +
  65.341 +Siemborski & Gulbrandsen  Standards Track                       [Page 6]
  65.342 +
  65.343 +RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
  65.344 +
  65.345 +
  65.346 +Full Copyright Statement
  65.347 +
  65.348 +   Copyright (C) The IETF Trust (2007).
  65.349 +
  65.350 +   This document is subject to the rights, licenses and restrictions
  65.351 +   contained in BCP 78, and except as set forth therein, the authors
  65.352 +   retain all their rights.
  65.353 +
  65.354 +   This document and the information contained herein are provided on an
  65.355 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  65.356 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  65.357 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  65.358 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  65.359 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  65.360 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  65.361 +
  65.362 +Intellectual Property
  65.363 +
  65.364 +   The IETF takes no position regarding the validity or scope of any
  65.365 +   Intellectual Property Rights or other rights that might be claimed to
  65.366 +   pertain to the implementation or use of the technology described in
  65.367 +   this document or the extent to which any license under such rights
  65.368 +   might or might not be available; nor does it represent that it has
  65.369 +   made any independent effort to identify any such rights.  Information
  65.370 +   on the procedures with respect to rights in RFC documents can be
  65.371 +   found in BCP 78 and BCP 79.
  65.372 +
  65.373 +   Copies of IPR disclosures made to the IETF Secretariat and any
  65.374 +   assurances of licenses to be made available, or the result of an
  65.375 +   attempt made to obtain a general license or permission for the use of
  65.376 +   such proprietary rights by implementers or users of this
  65.377 +   specification can be obtained from the IETF on-line IPR repository at
  65.378 +   http://www.ietf.org/ipr.
  65.379 +
  65.380 +   The IETF invites any interested party to bring to its attention any
  65.381 +   copyrights, patents or patent applications, or other proprietary
  65.382 +   rights that may cover technology that may be required to implement
  65.383 +   this standard.  Please address the information to the IETF at
  65.384 +   ietf-ipr@ietf.org.
  65.385 +
  65.386 +
  65.387 +
  65.388 +
  65.389 +
  65.390 +
  65.391 +
  65.392 +
  65.393 +
  65.394 +
  65.395 +
  65.396 +
  65.397 +Siemborski & Gulbrandsen  Standards Track                       [Page 7]
  65.398 +
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/docs/rfc/rfc4978.txt	Mon Sep 14 15:17:45 2009 +0900
    66.3 @@ -0,0 +1,507 @@
    66.4 +
    66.5 +
    66.6 +
    66.7 +
    66.8 +
    66.9 +
   66.10 +Network Working Group                                     A. Gulbrandsen
   66.11 +Request for Comments: 4978                        Oryx Mail Systems GmbH
   66.12 +Category: Standards Track                                    August 2007
   66.13 +
   66.14 +
   66.15 +                      The IMAP COMPRESS Extension
   66.16 +
   66.17 +Status of this Memo
   66.18 +
   66.19 +   This document specifies an Internet standards track protocol for the
   66.20 +   Internet community, and requests discussion and suggestions for
   66.21 +   improvements.  Please refer to the current edition of the "Internet
   66.22 +   Official Protocol Standards" (STD 1) for the standardization state
   66.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   66.24 +
   66.25 +Abstract
   66.26 +
   66.27 +   The COMPRESS extension allows an IMAP connection to be effectively
   66.28 +   and efficiently compressed.
   66.29 +
   66.30 +   Table of Contents
   66.31 +
   66.32 +   1. Introduction and Overview .......................................2
   66.33 +   2. Conventions Used in This Document ...............................2
   66.34 +   3. The COMPRESS Command ............................................3
   66.35 +   4. Compression Efficiency ..........................................4
   66.36 +   5. Formal Syntax ...................................................6
   66.37 +   6. Security Considerations .........................................6
   66.38 +   7. IANA Considerations .............................................6
   66.39 +   8. Acknowledgements ................................................7
   66.40 +   9. References ......................................................7
   66.41 +      9.1. Normative References .......................................7
   66.42 +      9.2. Informative References .....................................7
   66.43 +
   66.44 +
   66.45 +
   66.46 +
   66.47 +
   66.48 +
   66.49 +
   66.50 +
   66.51 +
   66.52 +
   66.53 +
   66.54 +
   66.55 +
   66.56 +
   66.57 +
   66.58 +
   66.59 +
   66.60 +
   66.61 +Gulbrandsen                 Standards Track                     [Page 1]
   66.62 +
   66.63 +RFC 4978              The IMAP COMPRESS Extension            August 2007
   66.64 +
   66.65 +
   66.66 +1.  Introduction and Overview
   66.67 +
   66.68 +   A server which supports the COMPRESS extension indicates this with
   66.69 +   one or more capability names consisting of "COMPRESS=" followed by a
   66.70 +   supported compression algorithm name as described in this document.
   66.71 +
   66.72 +   The goal of COMPRESS is to reduce the bandwidth usage of IMAP.
   66.73 +
   66.74 +   Compared to PPP compression (see [RFC1962]) and modem-based
   66.75 +   compression (see [MNP] and [V42BIS]), COMPRESS offers much better
   66.76 +   compression efficiency.  COMPRESS can be used together with Transport
   66.77 +   Security Layer (TLS) [RFC4346], Simple Authentication and Security
   66.78 +   layer (SASL) encryption, Virtual Private Networks (VPNs), etc.
   66.79 +   Compared to TLS compression [RFC3749], COMPRESS has the following
   66.80 +   (dis)advantages:
   66.81 +
   66.82 +   - COMPRESS can be implemented easily both by IMAP servers and
   66.83 +     clients.
   66.84 +
   66.85 +   - IMAP COMPRESS benefits from an intimate knowledge of the IMAP
   66.86 +     protocol's state machine, allowing for dynamic and aggressive
   66.87 +     optimization of the underlying compression algorithm's parameters.
   66.88 +
   66.89 +   - When the TLS layer implements compression, any protocol using that
   66.90 +     layer can transparently benefit from that compression (e.g., SMTP
   66.91 +     and IMAP).  COMPRESS is specific to IMAP.
   66.92 +
   66.93 +   In order to increase interoperation, it is desirable to have as few
   66.94 +   different compression algorithms as possible, so this document
   66.95 +   specifies only one.  The DEFLATE algorithm (defined in [RFC1951]) is
   66.96 +   standard, widely available and fairly efficient, so it is the only
   66.97 +   algorithm defined by this document.
   66.98 +
   66.99 +   In order to increase interoperation, IMAP servers that advertise this
  66.100 +   extension SHOULD also advertise the TLS DEFLATE compression mechanism
  66.101 +   as defined in [RFC3749].  IMAP clients MAY use either COMPRESS or TLS
  66.102 +   compression, however, if the client and server support both, it is
  66.103 +   RECOMMENDED that the client choose TLS compression.
  66.104 +
  66.105 +   The extension adds one new command (COMPRESS) and no new responses.
  66.106 +
  66.107 +2.  Conventions Used in This Document
  66.108 +
  66.109 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  66.110 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  66.111 +   document are to be interpreted as described in [RFC2119].
  66.112 +
  66.113 +   Formal syntax is defined by [RFC4234] as modified by [RFC3501].
  66.114 +
  66.115 +
  66.116 +
  66.117 +Gulbrandsen                 Standards Track                     [Page 2]
  66.118 +
  66.119 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.120 +
  66.121 +
  66.122 +   In the examples, "C:" and "S:" indicate lines sent by the client and
  66.123 +   server respectively. "[...]" denotes elision.
  66.124 +
  66.125 +3.  The COMPRESS Command
  66.126 +
  66.127 +   Arguments: Name of compression mechanism: "DEFLATE".
  66.128 +
  66.129 +   Responses: None
  66.130 +
  66.131 +   Result: OK The server will compress its responses and expects the
  66.132 +              client to compress its commands.
  66.133 +           NO Compression is already active via another layer.
  66.134 +          BAD Command unknown, invalid or unknown argument, or COMPRESS
  66.135 +              already active.
  66.136 +
  66.137 +   The COMPRESS command instructs the server to use the named
  66.138 +   compression mechanism ("DEFLATE" is the only one defined) for all
  66.139 +   commands and/or responses after COMPRESS.
  66.140 +
  66.141 +   The client MUST NOT send any further commands until it has seen the
  66.142 +   result of COMPRESS.  If the response was OK, the client MUST compress
  66.143 +   starting with the first command after COMPRESS.  If the server
  66.144 +   response was BAD or NO, the client MUST NOT turn on compression.
  66.145 +
  66.146 +   If the server responds NO because it knows that the same mechanism is
  66.147 +   active already (e.g., because TLS has negotiated the same mechanism),
  66.148 +   it MUST send COMPRESSIONACTIVE as resp-text-code (see [RFC3501],
  66.149 +   Section 7.1), and the resp-text SHOULD say which layer compresses.
  66.150 +
  66.151 +   If the server issues an OK response, the server MUST compress
  66.152 +   starting immediately after the CRLF which ends the tagged OK
  66.153 +   response.  (Responses issued by the server before the OK response
  66.154 +   will, of course, still be uncompressed.)  If the server issues a BAD
  66.155 +   or NO response, the server MUST NOT turn on compression.
  66.156 +
  66.157 +   For DEFLATE (as for many other compression mechanisms), the
  66.158 +   compressor can trade speed against quality.  When decompressing there
  66.159 +   isn't much of a tradeoff.  Consequently, the client and server are
  66.160 +   both free to pick the best reasonable rate of compression for the
  66.161 +   data they send.
  66.162 +
  66.163 +   When COMPRESS is combined with TLS (see [RFC4346]) or SASL (see
  66.164 +   [RFC4422]) security layers, the sending order of the three extensions
  66.165 +   MUST be first COMPRESS, then SASL, and finally TLS.  That is, before
  66.166 +   data is transmitted it is first compressed.  Second, if a SASL
  66.167 +   security layer has been negotiated, the compressed data is then
  66.168 +   signed and/or encrypted accordingly.  Third, if a TLS security layer
  66.169 +   has been negotiated, the data from the previous step is signed and/or
  66.170 +
  66.171 +
  66.172 +
  66.173 +Gulbrandsen                 Standards Track                     [Page 3]
  66.174 +
  66.175 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.176 +
  66.177 +
  66.178 +   encrypted accordingly.  When receiving data, the processing order
  66.179 +   MUST be reversed.  This ensures that before sending, data is
  66.180 +   compressed before it is encrypted, independent of the order in which
  66.181 +   the client issues COMPRESS, AUTHENTICATE, and STARTTLS.
  66.182 +
  66.183 +   The following example illustrates how commands and responses are
  66.184 +   compressed during a simple login sequence:
  66.185 +
  66.186 +        S: * OK [CAPABILITY IMAP4REV1 STARTTLS COMPRESS=DEFLATE]
  66.187 +        C: a starttls
  66.188 +        S: a OK TLS active
  66.189 +
  66.190 +            From this point on, everything is encrypted.
  66.191 +
  66.192 +        C: b login arnt tnra
  66.193 +        S: b OK Logged in as arnt
  66.194 +        C: c compress deflate
  66.195 +        S: d OK DEFLATE active
  66.196 +
  66.197 +            From this point on, everything is compressed before being
  66.198 +            encrypted.
  66.199 +
  66.200 +   The following example demonstrates how a server may refuse to
  66.201 +   compress twice:
  66.202 +
  66.203 +        S: * OK [CAPABILITY IMAP4REV1 STARTTLS COMPRESS=DEFLATE]
  66.204 +        [...]
  66.205 +        C: c compress deflate
  66.206 +        S: c NO [COMPRESSIONACTIVE] DEFLATE active via TLS
  66.207 +
  66.208 +4.  Compression Efficiency
  66.209 +
  66.210 +   This section is informative, not normative.
  66.211 +
  66.212 +   IMAP poses some unusual problems for a compression layer.
  66.213 +
  66.214 +   Upstream is fairly simple.  Most IMAP clients send the same few
  66.215 +   commands again and again, so any compression algorithm that can
  66.216 +   exploit repetition works efficiently.  The APPEND command is an
  66.217 +   exception; clients that send many APPEND commands may want to
  66.218 +   surround large literals with flushes in the same way as is
  66.219 +   recommended for servers later in this section.
  66.220 +
  66.221 +   Downstream has the unusual property that several kinds of data are
  66.222 +   sent, confusing all dictionary-based compression algorithms.
  66.223 +
  66.224 +
  66.225 +
  66.226 +
  66.227 +
  66.228 +
  66.229 +Gulbrandsen                 Standards Track                     [Page 4]
  66.230 +
  66.231 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.232 +
  66.233 +
  66.234 +   One type is IMAP responses.  These are highly compressible; zlib
  66.235 +   using its least CPU-intensive setting compresses typical responses to
  66.236 +   25-40% of their original size.
  66.237 +
  66.238 +   Another type is email headers.  These are equally compressible, and
  66.239 +   benefit from using the same dictionary as the IMAP responses.
  66.240 +
  66.241 +   A third type is email body text.  Text is usually fairly short and
  66.242 +   includes much ASCII, so the same compression dictionary will do a
  66.243 +   good job here, too.  When multiple messages in the same thread are
  66.244 +   read at the same time, quoted lines etc. can often be compressed
  66.245 +   almost to zero.
  66.246 +
  66.247 +   Finally, attachments (non-text email bodies) are transmitted, either
  66.248 +   in binary form or encoded with base-64.
  66.249 +
  66.250 +   When attachments are retrieved in binary form, DEFLATE may be able to
  66.251 +   compress them, but the format of the attachment is usually not IMAP-
  66.252 +   like, so the dictionary built while compressing IMAP does not help.
  66.253 +   The compressor has to adapt its dictionary from IMAP to the
  66.254 +   attachment's format, and then back.  A few file formats aren't
  66.255 +   compressible at all using deflate, e.g., .gz, .zip, and .jpg files.
  66.256 +
  66.257 +   When attachments are retrieved in base-64 form, the same problems
  66.258 +   apply, but the base-64 encoding adds another problem.  8-bit
  66.259 +   compression algorithms such as deflate work well on 8-bit file
  66.260 +   formats, however base-64 turns a file into something resembling 6-bit
  66.261 +   bytes, hiding most of the 8-bit file format from the compressor.
  66.262 +
  66.263 +   When using the zlib library (see [RFC1951]), the functions
  66.264 +   deflateInit2(), deflate(), inflateInit2(), and inflate() suffice to
  66.265 +   implement this extension.  The windowBits value must be in the range
  66.266 +   -8 to -15, or else deflateInit2() uses the wrong format.
  66.267 +   deflateParams() can be used to improve compression rate and resource
  66.268 +   use.  The Z_FULL_FLUSH argument to deflate() can be used to clear the
  66.269 +   dictionary (the receiving peer does not need to do anything).
  66.270 +
  66.271 +   A client can improve downstream compression by implementing BINARY
  66.272 +   (defined in [RFC3516]) and using FETCH BINARY instead of FETCH BODY.
  66.273 +   In the author's experience, the improvement ranges from 5% to 40%
  66.274 +   depending on the attachment being downloaded.
  66.275 +
  66.276 +   A server can improve downstream compression if it hints to the
  66.277 +   compressor that the data type is about to change strongly, e.g., by
  66.278 +   sending a Z_FULL_FLUSH at the start and end of large non-text
  66.279 +   literals (before and after '*CHAR8' in the definition of literal in
  66.280 +   RFC 3501, page 86).  Small literals are best left alone.  A possible
  66.281 +   boundary is 5k.
  66.282 +
  66.283 +
  66.284 +
  66.285 +Gulbrandsen                 Standards Track                     [Page 5]
  66.286 +
  66.287 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.288 +
  66.289 +
  66.290 +   A server can improve the CPU efficiency both of the server and the
  66.291 +   client if it adjusts the compression level (e.g., using the
  66.292 +   deflateParams() function in zlib) at these points, to avoid trying to
  66.293 +   compress incompressible attachments.  A very simple strategy is to
  66.294 +   change the level to 0 at the start of a literal provided the first
  66.295 +   two bytes are either 0x1F 0x8B (as in deflate-compressed files) or
  66.296 +   0xFF 0xD8 (JPEG), and to keep it at 1-5 the rest of the time.  More
  66.297 +   complex strategies are possible.
  66.298 +
  66.299 +5.  Formal Syntax
  66.300 +
  66.301 +   The following syntax specification uses the Augmented Backus-Naur
  66.302 +   Form (ABNF) notation as specified in [RFC4234].  This syntax augments
  66.303 +   the grammar specified in [RFC3501].  [RFC4234] defines SP and
  66.304 +   [RFC3501] defines command-auth, capability, and resp-text-code.
  66.305 +
  66.306 +   Except as noted otherwise, all alphabetic characters are case-
  66.307 +   insensitive.  The use of upper or lower case characters to define
  66.308 +   token strings is for editorial clarity only.  Implementations MUST
  66.309 +   accept these strings in a case-insensitive fashion.
  66.310 +
  66.311 +       command-auth =/ compress
  66.312 +
  66.313 +       compress    = "COMPRESS" SP algorithm
  66.314 +
  66.315 +       capability  =/ "COMPRESS=" algorithm
  66.316 +                     ;; multiple COMPRESS capabilities allowed
  66.317 +
  66.318 +       algorithm   = "DEFLATE"
  66.319 +
  66.320 +       resp-text-code =/ "COMPRESSIONACTIVE"
  66.321 +
  66.322 +   Note that due the syntax of capability names, future algorithm names
  66.323 +   must be atoms.
  66.324 +
  66.325 +6.  Security Considerations
  66.326 +
  66.327 +   As for TLS compression [RFC3749].
  66.328 +
  66.329 +7.  IANA Considerations
  66.330 +
  66.331 +   The IANA has added COMPRESS=DEFLATE to the list of IMAP capabilities.
  66.332 +
  66.333 +
  66.334 +
  66.335 +
  66.336 +
  66.337 +
  66.338 +
  66.339 +
  66.340 +
  66.341 +Gulbrandsen                 Standards Track                     [Page 6]
  66.342 +
  66.343 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.344 +
  66.345 +
  66.346 +8.  Acknowledgements
  66.347 +
  66.348 +   Eric Burger, Dave Cridland, Tony Finch, Ned Freed, Philip Guenther,
  66.349 +   Randall Gellens, Tony Hansen, Cullen Jennings, Stephane Maes, Alexey
  66.350 +   Melnikov, Lyndon Nerenberg, and Zoltan Ordogh have all helped with
  66.351 +   this document.
  66.352 +
  66.353 +   The author would also like to thank various people in the rooms at
  66.354 +   meetings, whose help is real, but not reflected in the author's
  66.355 +   mailbox.
  66.356 +
  66.357 +9.  References
  66.358 +
  66.359 +9.1.  Normative References
  66.360 +
  66.361 +   [RFC1951]  Deutsch, P., "DEFLATE Compressed Data Format Specification
  66.362 +              version 1.3", RFC 1951, May 1996.
  66.363 +
  66.364 +   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
  66.365 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  66.366 +
  66.367 +   [RFC3501]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  66.368 +              4rev1", RFC 3501, March 2003.
  66.369 +
  66.370 +   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
  66.371 +              Specifications: ABNF", RFC 4234, October 2005.
  66.372 +
  66.373 +9.2.  Informative References
  66.374 +
  66.375 +   [RFC1962]  Rand, D., "The PPP Compression Control Protocol (CCP)",
  66.376 +              RFC 1962, June 1996.
  66.377 +
  66.378 +   [RFC3516]  Nerenberg, L., "IMAP4 Binary Content Extension", RFC 3516,
  66.379 +              April 2003.
  66.380 +
  66.381 +   [RFC3749]  Hollenbeck, S., "Transport Layer Security Protocol
  66.382 +              Compression Methods", RFC 3749, May 2004.
  66.383 +
  66.384 +   [RFC4346]  Dierks, T. and E. Rescorla, "The Transport Layer Security
  66.385 +              (TLS) Protocol Version 1.1", RFC 4346, April 2006.
  66.386 +
  66.387 +   [RFC4422]  Melnikov, A. and  K. Zeilenga, "Simple Authentication and
  66.388 +              Security Layer (SASL)", RFC 4422, June 2006.
  66.389 +
  66.390 +   [V42BIS]   ITU, "V.42bis: Data compression procedures for data
  66.391 +              circuit-terminating equipment (DCE) using error correction
  66.392 +              procedures", http://www.itu.int/rec/T-REC-V.42bis, January
  66.393 +              1990.
  66.394 +
  66.395 +
  66.396 +
  66.397 +Gulbrandsen                 Standards Track                     [Page 7]
  66.398 +
  66.399 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.400 +
  66.401 +
  66.402 +   [MNP]      Gilbert Held, "The Complete Modem Reference", Second
  66.403 +              Edition, Wiley Professional Computing, ISBN 0-471-00852-4,
  66.404 +              May 1994.
  66.405 +
  66.406 +Author's Address
  66.407 +
  66.408 +    Arnt Gulbrandsen
  66.409 +    Oryx Mail Systems GmbH
  66.410 +    Schweppermannstr. 8
  66.411 +    D-81671 Muenchen
  66.412 +    Germany
  66.413 +
  66.414 +    Fax: +49 89 4502 9758
  66.415 +    EMail: arnt@oryx.com
  66.416 +
  66.417 +
  66.418 +
  66.419 +
  66.420 +
  66.421 +
  66.422 +
  66.423 +
  66.424 +
  66.425 +
  66.426 +
  66.427 +
  66.428 +
  66.429 +
  66.430 +
  66.431 +
  66.432 +
  66.433 +
  66.434 +
  66.435 +
  66.436 +
  66.437 +
  66.438 +
  66.439 +
  66.440 +
  66.441 +
  66.442 +
  66.443 +
  66.444 +
  66.445 +
  66.446 +
  66.447 +
  66.448 +
  66.449 +
  66.450 +
  66.451 +
  66.452 +
  66.453 +Gulbrandsen                 Standards Track                     [Page 8]
  66.454 +
  66.455 +RFC 4978              The IMAP COMPRESS Extension            August 2007
  66.456 +
  66.457 +
  66.458 +Full Copyright Statement
  66.459 +
  66.460 +   Copyright (C) The IETF Trust (2007).
  66.461 +
  66.462 +   This document is subject to the rights, licenses and restrictions
  66.463 +   contained in BCP 78, and except as set forth therein, the authors
  66.464 +   retain all their rights.
  66.465 +
  66.466 +   This document and the information contained herein are provided on an
  66.467 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  66.468 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  66.469 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  66.470 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  66.471 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  66.472 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  66.473 +
  66.474 +Intellectual Property
  66.475 +
  66.476 +   The IETF takes no position regarding the validity or scope of any
  66.477 +   Intellectual Property Rights or other rights that might be claimed to
  66.478 +   pertain to the implementation or use of the technology described in
  66.479 +   this document or the extent to which any license under such rights
  66.480 +   might or might not be available; nor does it represent that it has
  66.481 +   made any independent effort to identify any such rights.  Information
  66.482 +   on the procedures with respect to rights in RFC documents can be
  66.483 +   found in BCP 78 and BCP 79.
  66.484 +
  66.485 +   Copies of IPR disclosures made to the IETF Secretariat and any
  66.486 +   assurances of licenses to be made available, or the result of an
  66.487 +   attempt made to obtain a general license or permission for the use of
  66.488 +   such proprietary rights by implementers or users of this
  66.489 +   specification can be obtained from the IETF on-line IPR repository at
  66.490 +   http://www.ietf.org/ipr.
  66.491 +
  66.492 +   The IETF invites any interested party to bring to its attention any
  66.493 +   copyrights, patents or patent applications, or other proprietary
  66.494 +   rights that may cover technology that may be required to implement
  66.495 +   this standard.  Please address the information to the IETF at
  66.496 +   ietf-ipr@ietf.org.
  66.497 +
  66.498 +
  66.499 +
  66.500 +
  66.501 +
  66.502 +
  66.503 +
  66.504 +
  66.505 +
  66.506 +
  66.507 +
  66.508 +
  66.509 +Gulbrandsen                 Standards Track                     [Page 9]
  66.510 +
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/docs/rfc/rfc5032.txt	Mon Sep 14 15:17:45 2009 +0900
    67.3 @@ -0,0 +1,283 @@
    67.4 +
    67.5 +
    67.6 +
    67.7 +
    67.8 +
    67.9 +
   67.10 +Network Working Group                                     E. Burger, Ed.
   67.11 +Request for Comments: 5032                             BEA Systems, Inc.
   67.12 +Updates: 3501                                             September 2007
   67.13 +Category: Standards Track
   67.14 +
   67.15 +
   67.16 +              WITHIN Search Extension to the IMAP Protocol
   67.17 +
   67.18 +Status of This Memo
   67.19 +
   67.20 +   This document specifies an Internet standards track protocol for the
   67.21 +   Internet community, and requests discussion and suggestions for
   67.22 +   improvements.  Please refer to the current edition of the "Internet
   67.23 +   Official Protocol Standards" (STD 1) for the standardization state
   67.24 +   and status of this protocol.  Distribution of this memo is unlimited.
   67.25 +
   67.26 +Abstract
   67.27 +
   67.28 +   This document describes the WITHIN extension to IMAP SEARCH.  IMAP
   67.29 +   SEARCH returns messages whose internal date is within or outside a
   67.30 +   specified interval.  The mechanism described here, OLDER and YOUNGER,
   67.31 +   differs from BEFORE and SINCE in that the client specifies an
   67.32 +   interval, rather than a date.  WITHIN is useful for persistent
   67.33 +   searches where either the device does not have the capacity to
   67.34 +   perform the search at regular intervals or the network is of limited
   67.35 +   bandwidth and thus there is a desire to reduce network traffic from
   67.36 +   sending repeated requests and redundant responses.
   67.37 +
   67.38 +1.  Introduction
   67.39 +
   67.40 +   This extension exposes two new search keys, OLDER and YOUNGER, each
   67.41 +   of which takes a non-zero integer argument corresponding to a time
   67.42 +   interval in seconds.  The server calculates the time of interest by
   67.43 +   subtracting the time interval the client presents from the current
   67.44 +   date and time of the server.  The server then either returns messages
   67.45 +   older or younger than the resultant time and date, depending on the
   67.46 +   search key used.
   67.47 +
   67.48 +1.1.  Conventions Used in This Document
   67.49 +
   67.50 +   In examples, "C:" and "S:" indicate lines sent by the client and
   67.51 +   server, respectively.
   67.52 +
   67.53 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   67.54 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   67.55 +   document are to be interpreted as described in RFC 2119 [RFC2119].
   67.56 +
   67.57 +
   67.58 +
   67.59 +
   67.60 +
   67.61 +Burger                      Standards Track                     [Page 1]
   67.62 +
   67.63 +RFC 5032                     Search Within                September 2007
   67.64 +
   67.65 +
   67.66 +   When describing the general syntax, we omit some definitions, as RFC
   67.67 +   3501 [RFC3501] defines them.
   67.68 +
   67.69 +2.  Protocol Operation
   67.70 +
   67.71 +   An IMAP4 server that supports the capability described here MUST
   67.72 +   return "WITHIN" as one of the server supported capabilities in the
   67.73 +   CAPABILITY command.
   67.74 +
   67.75 +   For both the OLDER and YOUNGER search keys, the server calculates a
   67.76 +   target date and time by subtracting the interval, specified in
   67.77 +   seconds, from the current date and time of the server.  The server
   67.78 +   then compares the target time with the INTERNALDATE of the message,
   67.79 +   as specified in IMAP [RFC3501].  For OLDER, messages match if the
   67.80 +   INTERNALDATE is less recent than or equal to the target time.  For
   67.81 +   YOUNGER, messages match if the INTERNALDATE is more recent than or
   67.82 +   equal to the target time.
   67.83 +
   67.84 +   Both OLDER and YOUNGER searches always result in exact matching, to
   67.85 +   the resolution of a second.  However, if one is doing a dynamic
   67.86 +   evaluation, for example, in a context [CONTEXT], one needs to be
   67.87 +   aware that the server might perform the evaluation periodically.
   67.88 +   Thus, the server may delay the updates.  Clients MUST be aware that
   67.89 +   dynamic search results may not reflect the current state of the
   67.90 +   mailbox.  If the client needs a search result that reflects the
   67.91 +   current state of the mailbox, we RECOMMEND that the client issue a
   67.92 +   new search.
   67.93 +
   67.94 +3.  Formal Syntax
   67.95 +
   67.96 +   The following syntax specification uses the Augmented Backus-Naur
   67.97 +   Form (ABNF) notation.  Elements not defined here can be found in the
   67.98 +   formal syntax of ABNF [RFC4234] and IMAP [RFC3501].
   67.99 +
  67.100 +   This document extends RFC 3501 [RFC3501] with two new search keys:
  67.101 +   OLDER <interval> and YOUNGER <interval>.
  67.102 +
  67.103 +   search-key =/ ( "OLDER" / "YOUNGER" ) SP nz-number
  67.104 +                  ; search-key defined in RFC 3501
  67.105 +
  67.106 +4.  Example
  67.107 +
  67.108 +   C: a1 SEARCH UNSEEN YOUNGER 259200
  67.109 +   S: a1 * SEARCH 4 8 15 16 23 42
  67.110 +
  67.111 +   Search for all unseen messages within the past 3 days, or 259200
  67.112 +   seconds, according to the server's current time.
  67.113 +
  67.114 +
  67.115 +
  67.116 +
  67.117 +Burger                      Standards Track                     [Page 2]
  67.118 +
  67.119 +RFC 5032                     Search Within                September 2007
  67.120 +
  67.121 +
  67.122 +5.  Security Considerations
  67.123 +
  67.124 +   The WITHIN extension does not raise any security considerations that
  67.125 +   are not present in the base protocol.  Considerations are the same as
  67.126 +   for IMAP [RFC3501].
  67.127 +
  67.128 +6.  IANA Considerations
  67.129 +
  67.130 +   Per the IMAP RFC [RFC3501], registration of a new IMAP capability in
  67.131 +   the IMAP Capability registry requires the publication of a standards-
  67.132 +   track RFC or an IESG approved experimental RFC.  The registry is
  67.133 +   currently located at
  67.134 +   <http://www.iana.org/assignments/imap4-capabilities>.  This
  67.135 +   standards-track document defines the WITHIN IMAP capability.  IANA
  67.136 +   has added this extension to the IANA IMAP Capability registry.
  67.137 +
  67.138 +7.  References
  67.139 +
  67.140 +7.1.  Normative References
  67.141 +
  67.142 +   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
  67.143 +              Requirement Levels", RFC 2119, BCP 14, March 1997.
  67.144 +
  67.145 +   [RFC3501]  Crispin, M., "Internet Message Access Protocol - Version
  67.146 +              4rev1", RFC 3501, March 2003.
  67.147 +
  67.148 +   [RFC4234]  Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
  67.149 +              Specifications: ABNF", RFC 4234, October 2005.
  67.150 +
  67.151 +7.2.  Informative References
  67.152 +
  67.153 +   [CONTEXT]  Melnikov, D. and C. King, "Contexts for IMAP4", Work
  67.154 +              in Progress, May 2006.
  67.155 +
  67.156 +
  67.157 +
  67.158 +
  67.159 +
  67.160 +
  67.161 +
  67.162 +
  67.163 +
  67.164 +
  67.165 +
  67.166 +
  67.167 +
  67.168 +
  67.169 +
  67.170 +
  67.171 +
  67.172 +
  67.173 +Burger                      Standards Track                     [Page 3]
  67.174 +
  67.175 +RFC 5032                     Search Within                September 2007
  67.176 +
  67.177 +
  67.178 +Appendix A.  Contributors
  67.179 +
  67.180 +   Stephane Maes and Ray Cromwell wrote the original version of this
  67.181 +   document as part of P-IMAP, as well as the first versions for the
  67.182 +   IETF.  From an attribution perspective, they are clearly authors.
  67.183 +
  67.184 +Appendix B.  Acknowledgements
  67.185 +
  67.186 +   The authors want to thank all who have contributed key insight and
  67.187 +   who have extensively reviewed and discussed the concepts of LPSEARCH.
  67.188 +   They also thank the authors of its early introduction in P-IMAP.
  67.189 +
  67.190 +   We also want to give a special thanks to Arnt Gilbrandsen, Ken
  67.191 +   Murchison, Zoltan Ordogh, and most especially Dave Cridland for their
  67.192 +   review and suggestions.  A special thank you goes to Alexey Melnikov
  67.193 +   for his choice submission of text.
  67.194 +
  67.195 +Author's Address
  67.196 +
  67.197 +   Eric W. Burger (editor)
  67.198 +   BEA Systems, Inc.
  67.199 +   USA
  67.200 +
  67.201 +   EMail: eric.burger@bea.com
  67.202 +   URI:   http://www.standardstrack.com
  67.203 +
  67.204 +
  67.205 +
  67.206 +
  67.207 +
  67.208 +
  67.209 +
  67.210 +
  67.211 +
  67.212 +
  67.213 +
  67.214 +
  67.215 +
  67.216 +
  67.217 +
  67.218 +
  67.219 +
  67.220 +
  67.221 +
  67.222 +
  67.223 +
  67.224 +
  67.225 +
  67.226 +
  67.227 +
  67.228 +
  67.229 +Burger                      Standards Track                     [Page 4]
  67.230 +
  67.231 +RFC 5032                     Search Within                September 2007
  67.232 +
  67.233 +
  67.234 +Full Copyright Statement
  67.235 +
  67.236 +   Copyright (C) The IETF Trust (2007).
  67.237 +
  67.238 +   This document is subject to the rights, licenses and restrictions
  67.239 +   contained in BCP 78, and except as set forth therein, the authors
  67.240 +   retain all their rights.
  67.241 +
  67.242 +   This document and the information contained herein are provided on an
  67.243 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  67.244 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  67.245 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  67.246 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  67.247 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  67.248 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  67.249 +
  67.250 +Intellectual Property
  67.251 +
  67.252 +   The IETF takes no position regarding the validity or scope of any
  67.253 +   Intellectual Property Rights or other rights that might be claimed to
  67.254 +   pertain to the implementation or use of the technology described in
  67.255 +   this document or the extent to which any license under such rights
  67.256 +   might or might not be available; nor does it represent that it has
  67.257 +   made any independent effort to identify any such rights.  Information
  67.258 +   on the procedures with respect to rights in RFC documents can be
  67.259 +   found in BCP 78 and BCP 79.
  67.260 +
  67.261 +   Copies of IPR disclosures made to the IETF Secretariat and any
  67.262 +   assurances of licenses to be made available, or the result of an
  67.263 +   attempt made to obtain a general license or permission for the use of
  67.264 +   such proprietary rights by implementers or users of this
  67.265 +   specification can be obtained from the IETF on-line IPR repository at
  67.266 +   http://www.ietf.org/ipr.
  67.267 +
  67.268 +   The IETF invites any interested party to bring to its attention any
  67.269 +   copyrights, patents or patent applications, or other proprietary
  67.270 +   rights that may cover technology that may be required to implement
  67.271 +   this standard.  Please address the information to the IETF at
  67.272 +   ietf-ipr@ietf.org.
  67.273 +
  67.274 +
  67.275 +
  67.276 +
  67.277 +
  67.278 +
  67.279 +
  67.280 +
  67.281 +
  67.282 +
  67.283 +
  67.284 +
  67.285 +Burger                      Standards Track                     [Page 5]
  67.286 +
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/docs/rfc/rfc5051.txt	Mon Sep 14 15:17:45 2009 +0900
    68.3 @@ -0,0 +1,395 @@
    68.4 +
    68.5 +
    68.6 +
    68.7 +
    68.8 +
    68.9 +
   68.10 +Network Working Group                                         M. Crispin
   68.11 +Request for Comments: 5051                      University of Washington
   68.12 +Category: Standards Track                                   October 2007
   68.13 +
   68.14 +
   68.15 +         i;unicode-casemap - Simple Unicode Collation Algorithm
   68.16 +
   68.17 +Status of This Memo
   68.18 +
   68.19 +   This document specifies an Internet standards track protocol for the
   68.20 +   Internet community, and requests discussion and suggestions for
   68.21 +   improvements.  Please refer to the current edition of the "Internet
   68.22 +   Official Protocol Standards" (STD 1) for the standardization state
   68.23 +   and status of this protocol.  Distribution of this memo is unlimited.
   68.24 +
   68.25 +Abstract
   68.26 +
   68.27 +   This document describes "i;unicode-casemap", a simple case-
   68.28 +   insensitive collation for Unicode strings.  It provides equality,
   68.29 +   substring, and ordering operations.
   68.30 +
   68.31 +1.  Introduction
   68.32 +
   68.33 +   The "i;ascii-casemap" collation described in [COMPARATOR] is quite
   68.34 +   simple to implement and provides case-independent comparisons for the
   68.35 +   26 Latin alphabetics.  It is specified as the default and/or baseline
   68.36 +   comparator in some application protocols, e.g., [IMAP-SORT].
   68.37 +
   68.38 +   However, the "i;ascii-casemap" collation does not produce
   68.39 +   satisfactory results with non-ASCII characters.  It is possible, with
   68.40 +   a modest extension, to provide a more sophisticated collation with
   68.41 +   greater multilingual applicability than "i;ascii-casemap".  This
   68.42 +   extension provides case-independent comparisons for a much greater
   68.43 +   number of characters.  It also collates characters with diacriticals
   68.44 +   with the non-diacritical character forms.
   68.45 +
   68.46 +   This collation, "i;unicode-casemap", is intended to be an alternative
   68.47 +   to, and preferred over, "i;ascii-casemap".  It does not replace the
   68.48 +   "i;basic" collation described in [BASIC].
   68.49 +
   68.50 +2.  Unicode Casemap Collation Description
   68.51 +
   68.52 +   The "i;unicode-casemap" collation is a simple collation which is
   68.53 +   case-insensitive in its treatment of characters.  It provides
   68.54 +   equality, substring, and ordering operations.  The validity test
   68.55 +   operation returns "valid" for any input.
   68.56 +
   68.57 +
   68.58 +
   68.59 +
   68.60 +
   68.61 +Crispin                     Standards Track                     [Page 1]
   68.62 +
   68.63 +RFC 5051                   i;unicode-casemap                October 2007
   68.64 +
   68.65 +
   68.66 +   This collation allows strings in arbitrary (and mixed) character
   68.67 +   sets, as long as the character set for each string is identified and
   68.68 +   it is possible to convert the string to Unicode.  Strings which have
   68.69 +   an unidentified character set and/or cannot be converted to Unicode
   68.70 +   are not rejected, but are treated as binary.
   68.71 +
   68.72 +   Each input string is prepared by converting it to a "titlecased
   68.73 +   canonicalized UTF-8" string according to the following steps, using
   68.74 +   UnicodeData.txt ([UNICODE-DATA]):
   68.75 +
   68.76 +      (1) A Unicode codepoint is obtained from the input string.
   68.77 +
   68.78 +          (a) If the input string is in a known charset that can be
   68.79 +              converted to Unicode, a sequence in the string's charset
   68.80 +              is read and checked for validity according to the rules of
   68.81 +              that charset.  If the sequence is valid, it is converted
   68.82 +              to a Unicode codepoint.  Note that for input strings in
   68.83 +              UTF-8, the UTF-8 sequence must be valid according to the
   68.84 +              rules of [UTF-8]; e.g., overlong UTF-8 sequences are
   68.85 +              invalid.
   68.86 +
   68.87 +          (b) If the input string is in an unknown charset, or an
   68.88 +              invalid sequence occurs in step (1)(a), conversion ceases.
   68.89 +              No further preparation is performed, and any partial
   68.90 +              preparation results are discarded.  The original string is
   68.91 +              used unchanged with the i;octet comparator.
   68.92 +
   68.93 +      (2) The following steps, using UnicodeData.txt ([UNICODE-DATA]),
   68.94 +          are performed on the resulting codepoint from step (1)(a).
   68.95 +
   68.96 +          (a) If the codepoint has a titlecase property in
   68.97 +              UnicodeData.txt (this is normally the same as the
   68.98 +              uppercase property), the codepoint is converted to the
   68.99 +              codepoints in the titlecase property.
  68.100 +
  68.101 +          (b) If the resulting codepoint from (2)(a) has a decomposition
  68.102 +              property of any type in UnicodeData.txt, the codepoint is
  68.103 +              converted to the codepoints in the decomposition property.
  68.104 +              This step is recursively applied to each of the resulting
  68.105 +              codepoints until no more decomposition is possible
  68.106 +              (effectively Normalization Form KD).
  68.107 +
  68.108 +          Example: codepoint U+01C4 (LATIN CAPITAL LETTER DZ WITH CARON)
  68.109 +          has a titlecase property of U+01C5 (LATIN CAPITAL LETTER D
  68.110 +          WITH SMALL LETTER Z WITH CARON).  Codepoint U+01C5 has a
  68.111 +          decomposition property of U+0044 (LATIN CAPITAL LETTER D)
  68.112 +          U+017E (LATIN SMALL LETTER Z WITH CARON).  U+017E has a
  68.113 +          decomposition property of U+007A (LATIN SMALL LETTER Z) U+030c
  68.114 +
  68.115 +
  68.116 +
  68.117 +Crispin                     Standards Track                     [Page 2]
  68.118 +
  68.119 +RFC 5051                   i;unicode-casemap                October 2007
  68.120 +
  68.121 +
  68.122 +          (COMBINING CARON).  Neither U+0044, U+007A, nor U+030C have
  68.123 +          any decomposition properties.  Therefore, U+01C4 is converted
  68.124 +          to U+0044 U+007A U+030C by this step.
  68.125 +
  68.126 +      (3) The resulting codepoint(s) from step (2) is/are appended, in
  68.127 +          UTF-8 format, to the "titlecased canonicalized UTF-8" string.
  68.128 +
  68.129 +      (4) Repeat from step (1) until there is no more data in the input
  68.130 +          string.
  68.131 +
  68.132 +   Following the above preparation process on each string, the equality,
  68.133 +   ordering, and substring operations are as for i;octet.
  68.134 +
  68.135 +   It is permitted to use an alternative implementation of the above
  68.136 +   preparation process if it produces the same results.  For example, it
  68.137 +   may be more convenient for an implementation to convert all input
  68.138 +   strings to a sequence of UTF-16 or UTF-32 values prior to performing
  68.139 +   any of the step (2) actions.  Similarly, if all input strings are (or
  68.140 +   are convertible to) Unicode, it may be possible to use UTF-32 as an
  68.141 +   alternative to UTF-8 in step (3).
  68.142 +
  68.143 +      Note: UTF-16 is unsuitable as an alternative to UTF-8 in step (3),
  68.144 +      because UTF-16 surrogates will cause i;octet to collate codepoints
  68.145 +      U+E0000 through U+FFFF after non-BMP codepoints.
  68.146 +
  68.147 +   This collation is not locale sensitive.  Consequently, care should be
  68.148 +   taken when using OS-supplied functions to implement this collation.
  68.149 +   Functions such as strcasecmp and toupper are sometimes locale
  68.150 +   sensitive and may inconsistently casemap letters.
  68.151 +
  68.152 +   The i;unicode-casemap collation is well suited to use with many
  68.153 +   Internet protocols and computer languages.  Use with natural language
  68.154 +   is often inappropriate; even though the collation apparently supports
  68.155 +   languages such as Swahili and English, in real-world use it tends to
  68.156 +   mis-sort a number of types of string:
  68.157 +
  68.158 +   o  people and place names containing scripts that are not collated
  68.159 +      according to "alphabetical order".
  68.160 +   o  words with characters that have diacriticals.  However,
  68.161 +      i;unicode-casemap generally does a better job than i;ascii-casemap
  68.162 +      for most (but not all) languages.  For example, German umlaut
  68.163 +      letters will sort correctly, but some Scandinavian letters will
  68.164 +      not.
  68.165 +   o  names such as "Lloyd" (which in Welsh sorts after "Lyon", unlike
  68.166 +      in English),
  68.167 +   o  strings containing other non-letter symbols; e.g., euro and pound
  68.168 +      sterling symbols, quotation marks other than '"', dashes/hyphens,
  68.169 +      etc.
  68.170 +
  68.171 +
  68.172 +
  68.173 +Crispin                     Standards Track                     [Page 3]
  68.174 +
  68.175 +RFC 5051                   i;unicode-casemap                October 2007
  68.176 +
  68.177 +
  68.178 +3.  Unicode Casemap Collation Registration
  68.179 +
  68.180 +   <?xml version='1.0'?>
  68.181 +   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
  68.182 +   <collation rfc="5051" scope="global" intendedUse="common">
  68.183 +   <identifier>i;unicode-casemap</identifier>
  68.184 +   <title>Unicode Casemap</title>
  68.185 +   <operations>equality order substring</operations>
  68.186 +   <specification>RFC 5051</specification>
  68.187 +   <owner>IETF</owner>
  68.188 +   <submitter>mrc@cac.washington.edu</submitter>
  68.189 +   </collation>
  68.190 +
  68.191 +4.  Security Considerations
  68.192 +
  68.193 +   The security considerations for [UTF-8], [STRINGPREP], and [UNICODE-
  68.194 +   SECURITY] apply and are normative to this specification.
  68.195 +
  68.196 +   The results from this comparator will vary depending upon the
  68.197 +   implementation for several reasons.  Implementations MUST consider
  68.198 +   whether these possibilities are a problem for their use case:
  68.199 +
  68.200 +   1) New characters added in Unicode may have decomposition or
  68.201 +      titlecase properties that will not be known to an implementation
  68.202 +      based upon an older revision of Unicode.  This impacts step (2).
  68.203 +
  68.204 +   2) Step (2)(b) defines a subset of Normalization Form KD (NFKD) that
  68.205 +      does not require normalization of out-of-order diacriticals.
  68.206 +      However, an implementation MAY use an NFKD library routine that
  68.207 +      does such normalization.  This impacts step (2)(b) and possibly
  68.208 +      also step (1)(a), and is an issue only with ill-formed UTF-8
  68.209 +      input.
  68.210 +
  68.211 +   3) The set of charsets handled in step (1)(a) is open-ended.  UTF-8
  68.212 +      (and, by extension, US-ASCII) are the only mandatory-to-implement
  68.213 +      charsets.  This impacts step (1)(a).
  68.214 +
  68.215 +      Implementations SHOULD, as far as feasible, support all the
  68.216 +      charsets they are likely to encounter in the input data, in order
  68.217 +      to avoid poor collation caused by the fall through to the (1)(b)
  68.218 +      rule.
  68.219 +
  68.220 +   4) Other charsets may have revisions which add new characters that
  68.221 +      are not known to an implementation based upon an older revision.
  68.222 +      This impacts step (1)(a) and possibly also step (1)(b).
  68.223 +
  68.224 +
  68.225 +
  68.226 +
  68.227 +
  68.228 +
  68.229 +Crispin                     Standards Track                     [Page 4]
  68.230 +
  68.231 +RFC 5051                   i;unicode-casemap                October 2007
  68.232 +
  68.233 +
  68.234 +   An attacker may create input that is ill-formed or in an unknown
  68.235 +   charset, with the intention of impacting the results of this
  68.236 +   comparator or exploiting other parts of the system which process this
  68.237 +   input in different ways.  Note, however, that even well-formed data
  68.238 +   in a known charset can impact the result of this comparator in
  68.239 +   unexpected ways.  For example, an attacker can substitute U+0041
  68.240 +   (LATIN CAPITAL LETTER A) with U+0391 (GREEK CAPITAL LETTER ALPHA) or
  68.241 +   U+0410 (CYRILLIC CAPITAL LETTER A) in the intention of causing a
  68.242 +   non-match of strings which visually appear the same and/or causing
  68.243 +   the string to appear elsewhere in a sort.
  68.244 +
  68.245 +5.  IANA Considerations
  68.246 +
  68.247 +   The i;unicode-casemap collation defined in section 2 has been added
  68.248 +   to the registry of collations defined in [COMPARATOR].
  68.249 +
  68.250 +6.  Normative References
  68.251 +
  68.252 +   [COMPARATOR]          Newman, C., Duerst, M., and A. Gulbrandsen,
  68.253 +                         "Internet Application Protocol Collation
  68.254 +                         Registry", RFC 4790, February 2007.
  68.255 +
  68.256 +   [STRINGPREP]          Hoffman, P. and M. Blanchet, "Preparation of
  68.257 +                         Internationalized Strings ("stringprep")", RFC
  68.258 +                         3454, December 2002.
  68.259 +
  68.260 +   [UTF-8]               Yergeau, F., "UTF-8, a transformation format of
  68.261 +                         ISO 10646", STD 63, RFC 3629, November 2003.
  68.262 +
  68.263 +   [UNICODE-DATA]        <http://www.unicode.org/Public/UNIDATA/
  68.264 +                         UnicodeData.txt>
  68.265 +
  68.266 +                         Although the UnicodeData.txt file referenced
  68.267 +                         here is part of the Unicode standard, it is
  68.268 +                         subject to change as new characters are added
  68.269 +                         to Unicode and errors are corrected in Unicode
  68.270 +                         revisions.  As a result, it may be less stable
  68.271 +                         than might otherwise be implied by the
  68.272 +                         standards status of this specification.
  68.273 +
  68.274 +   [UNICODE-SECURITY]    Davis, M. and M. Suignard, "Unicode Security
  68.275 +                         Considerations", February 2006,
  68.276 +                         <http://www.unicode.org/reports/tr36/>.
  68.277 +
  68.278 +
  68.279 +
  68.280 +
  68.281 +
  68.282 +
  68.283 +
  68.284 +
  68.285 +Crispin                     Standards Track                     [Page 5]
  68.286 +
  68.287 +RFC 5051                   i;unicode-casemap                October 2007
  68.288 +
  68.289 +
  68.290 +7.  Informative References
  68.291 +
  68.292 +   [BASIC]               Newman, C., Duerst, M., and A. Gulbrandsen,
  68.293 +                         "i;basic - the Unicode Collation Algorithm",
  68.294 +                         Work in Progress, March 2007.
  68.295 +
  68.296 +   [IMAP-SORT]           Crispin, M. and K. Murchison, "Internet Message
  68.297 +                         Access Protocol - SORT and THREAD Extensions",
  68.298 +                         Work in Progress, September 2007.
  68.299 +
  68.300 +Author's Address
  68.301 +
  68.302 +   Mark R. Crispin
  68.303 +   Networks and Distributed Computing
  68.304 +   University of Washington
  68.305 +   4545 15th Avenue NE
  68.306 +   Seattle, WA  98105-4527
  68.307 +
  68.308 +   Phone: +1 (206) 543-5762
  68.309 +   EMail: MRC@CAC.Washington.EDU
  68.310 +
  68.311 +
  68.312 +
  68.313 +
  68.314 +
  68.315 +
  68.316 +
  68.317 +
  68.318 +
  68.319 +
  68.320 +
  68.321 +
  68.322 +
  68.323 +
  68.324 +
  68.325 +
  68.326 +
  68.327 +
  68.328 +
  68.329 +
  68.330 +
  68.331 +
  68.332 +
  68.333 +
  68.334 +
  68.335 +
  68.336 +
  68.337 +
  68.338 +
  68.339 +
  68.340 +
  68.341 +Crispin                     Standards Track                     [Page 6]
  68.342 +
  68.343 +RFC 5051                   i;unicode-casemap                October 2007
  68.344 +
  68.345 +
  68.346 +Full Copyright Statement
  68.347 +
  68.348 +   Copyright (C) The IETF Trust (2007).
  68.349 +
  68.350 +   This document is subject to the rights, licenses and restrictions
  68.351 +   contained in BCP 78, and except as set forth therein, the authors
  68.352 +   retain all their rights.
  68.353 +
  68.354 +   This document and the information contained herein are provided on an
  68.355 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  68.356 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  68.357 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  68.358 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  68.359 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  68.360 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  68.361 +
  68.362 +Intellectual Property
  68.363 +
  68.364 +   The IETF takes no position regarding the validity or scope of any
  68.365 +   Intellectual Property Rights or other rights that might be claimed to
  68.366 +   pertain to the implementation or use of the technology described in
  68.367 +   this document or the extent to which any license under such rights
  68.368 +   might or might not be available; nor does it represent that it has
  68.369 +   made any independent effort to identify any such rights.  Information
  68.370 +   on the procedures with respect to rights in RFC documents can be
  68.371 +   found in BCP 78 and BCP 79.
  68.372 +
  68.373 +   Copies of IPR disclosures made to the IETF Secretariat and any
  68.374 +   assurances of licenses to be made available, or the result of an
  68.375 +   attempt made to obtain a general license or permission for the use of
  68.376 +   such proprietary rights by implementers or users of this
  68.377 +   specification can be obtained from the IETF on-line IPR repository at
  68.378 +   http://www.ietf.org/ipr.
  68.379 +
  68.380 +   The IETF invites any interested party to bring to its attention any
  68.381 +   copyrights, patents or patent applications, or other proprietary
  68.382 +   rights that may cover technology that may be required to implement
  68.383 +   this standard.  Please address the information to the IETF at
  68.384 +   ietf-ipr@ietf.org.
  68.385 +
  68.386 +
  68.387 +
  68.388 +
  68.389 +
  68.390 +
  68.391 +
  68.392 +
  68.393 +
  68.394 +
  68.395 +
  68.396 +
  68.397 +Crispin                     Standards Track                     [Page 7]
  68.398 +
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/docs/rfc/rfc5092.txt	Mon Sep 14 15:17:45 2009 +0900
    69.3 @@ -0,0 +1,1795 @@
    69.4 +
    69.5 +
    69.6 +
    69.7 +
    69.8 +
    69.9 +
   69.10 +Network Working Group                                   A. Melnikov, Ed.
   69.11 +Request for Comments: 5092                                    Isode Ltd.
   69.12 +Obsoletes: 2192                                                C. Newman
   69.13 +Updates: 4467                                           Sun Microsystems
   69.14 +Category: Standards Track                                  November 2007
   69.15 +
   69.16 +
   69.17 +                            IMAP URL Scheme
   69.18 +
   69.19 +Status of This Memo
   69.20 +
   69.21 +   This document specifies an Internet standards track protocol for the
   69.22 +   Internet community, and requests discussion and suggestions for
   69.23 +   improvements.  Please refer to the current edition of the "Internet
   69.24 +   Official Protocol Standards" (STD 1) for the standardization state
   69.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   69.26 +
   69.27 +Abstract
   69.28 +
   69.29 +   IMAP (RFC 3501) is a rich protocol for accessing remote message
   69.30 +   stores.  It provides an ideal mechanism for accessing public mailing
   69.31 +   list archives as well as private and shared message stores.  This
   69.32 +   document defines a URL scheme for referencing objects on an IMAP
   69.33 +   server.
   69.34 +
   69.35 +   This document obsoletes RFC 2192.  It also updates RFC 4467.
   69.36 +
   69.37 +
   69.38 +
   69.39 +
   69.40 +
   69.41 +
   69.42 +
   69.43 +
   69.44 +
   69.45 +
   69.46 +
   69.47 +
   69.48 +
   69.49 +
   69.50 +
   69.51 +
   69.52 +
   69.53 +
   69.54 +
   69.55 +
   69.56 +
   69.57 +
   69.58 +
   69.59 +
   69.60 +
   69.61 +Melnikov & Newman           Standards Track                     [Page 1]
   69.62 +
   69.63 +RFC 5092                    IMAP URL Scheme                November 2007
   69.64 +
   69.65 +
   69.66 +Table of Contents
   69.67 +
   69.68 +   1. Introduction ....................................................2
   69.69 +   2. Conventions Used in This Document ...............................3
   69.70 +   3. IMAP userinfo Component (iuserinfo) .............................4
   69.71 +      3.1. IMAP Mailbox Naming Scope ..................................4
   69.72 +      3.2. IMAP User Name and Authentication Mechanism ................4
   69.73 +      3.3. Limitations of enc-user ....................................6
   69.74 +   4. IMAP Server .....................................................7
   69.75 +   5. Lists of Messages ...............................................7
   69.76 +   6. A Specific Message or Message Part ..............................8
   69.77 +      6.1. URLAUTH Authorized URL .....................................9
   69.78 +           6.1.1. Concepts ............................................9
   69.79 +                  6.1.1.1. URLAUTH ....................................9
   69.80 +                  6.1.1.2. Mailbox Access Key .........................9
   69.81 +                  6.1.1.3. Authorized Access Identifier ...............9
   69.82 +                  6.1.1.4. Authorization Mechanism ...................10
   69.83 +                  6.1.1.5. Authorization Token .......................10
   69.84 +           6.1.2. URLAUTH Extensions to IMAP URL .....................10
   69.85 +   7. Relative IMAP URLs .............................................11
   69.86 +      7.1. absolute-path References ..................................12
   69.87 +      7.2. relative-path References ..................................12
   69.88 +   8. Internationalization Considerations ............................13
   69.89 +   9. Examples .......................................................13
   69.90 +      9.1. Examples of Relative URLs .................................16
   69.91 +   10. Security Considerations .......................................16
   69.92 +      10.1. Security Considerations Specific to URLAUTH Authorized
   69.93 +            URL ......................................................17
   69.94 +   11. ABNF for IMAP URL Scheme ......................................17
   69.95 +   12. IANA Considerations ...........................................21
   69.96 +      12.1. IANA Registration of imap: URI Scheme ....................21
   69.97 +   13. References ....................................................22
   69.98 +      13.1. Normative References .....................................22
   69.99 +      13.2. Informative References ...................................23
  69.100 +   Appendix A. Sample Code............................................24
  69.101 +   Appendix B. List of Changes since RFC 2192.........................30
  69.102 +   Appendix C. List of Changes since RFC 4467.........................31
  69.103 +   Appendix D. Acknowledgments........................................31
  69.104 +
  69.105 +1.  Introduction
  69.106 +
  69.107 +   The IMAP URL scheme is used to designate IMAP servers, mailboxes,
  69.108 +   messages, MIME bodies [MIME], and search programs on Internet hosts
  69.109 +   accessible using the IMAP protocol over TCP.
  69.110 +
  69.111 +   The IMAP URL follows the common Internet scheme syntax as defined in
  69.112 +   [URI-GEN].  If :<port> is omitted, the port defaults to 143 (as
  69.113 +   defined in Section 2.1 of [IMAP4]).
  69.114 +
  69.115 +
  69.116 +
  69.117 +Melnikov & Newman           Standards Track                     [Page 2]
  69.118 +
  69.119 +RFC 5092                    IMAP URL Scheme                November 2007
  69.120 +
  69.121 +
  69.122 +   An absolute IMAP URL takes one of the following forms:
  69.123 +
  69.124 +      imap://<iserver>[/]
  69.125 +
  69.126 +      imap://<iserver>/<enc-mailbox>[<uidvalidity>][?<enc-search>]
  69.127 +
  69.128 +      imap://<iserver>/<enc-mailbox>[<uidvalidity>]<iuid>
  69.129 +       [<isection>][<ipartial>][<iurlauth>]
  69.130 +
  69.131 +   The first form is used to refer to an IMAP server (see Section 4),
  69.132 +   the second form refers to the contents of a mailbox or a set of
  69.133 +   messages resulting from a search (see Section 5), and the final form
  69.134 +   refers to a specific message or message part, and possibly a byte
  69.135 +   range in that part (see Section 6).  If [URLAUTH] extension is
  69.136 +   supported, then the final form can have the <iurlauth> component (see
  69.137 +   Section 6.1 for more details).
  69.138 +
  69.139 +   The <iserver> component common to all types of absolute IMAP URLs has
  69.140 +   the following syntax expressed in ABNF [ABNF]:
  69.141 +
  69.142 +      [iuserinfo "@"] host [ ":" port ]
  69.143 +
  69.144 +   The <iserver> component is the same as "authority" defined in
  69.145 +   [URI-GEN].  The syntax and uses of the <iuserinfo> ("IMAP userinfo
  69.146 +   component") are described in detail in Section 3.  The syntax of
  69.147 +   <host> and <port> is described in [URI-GEN].
  69.148 +
  69.149 +2.  Conventions Used in This Document
  69.150 +
  69.151 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  69.152 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  69.153 +   document are to be interpreted as described in RFC 2119 [KEYWORDS].
  69.154 +
  69.155 +   This document references many productions from [URI-GEN].  When the
  69.156 +   document needs to emphasize IMAP URI-specific differences from [URI-
  69.157 +   GEN] (i.e., for parts of IMAP URIs that have more restricted syntax
  69.158 +   than generic URIs), it uses a non-terminal i<foo> to define an IMAP-
  69.159 +   specific version of the non-terminal <foo> from [URI-GEN].
  69.160 +
  69.161 +   Note that the ABNF syntax shown in Section 11 is normative.  Sections
  69.162 +   2-6 may use a less formal syntax that does not necessarily match the
  69.163 +   normative ABNF shown in Section 11.  If there are any differences
  69.164 +   between the syntax shown in Sections 2-6 and Section 11, then the
  69.165 +   syntax shown in Section 11 must be treated as authoritative.  Non-
  69.166 +   syntax requirements included in Sections 2-6 are, of course,
  69.167 +   normative.
  69.168 +
  69.169 +
  69.170 +
  69.171 +
  69.172 +
  69.173 +Melnikov & Newman           Standards Track                     [Page 3]
  69.174 +
  69.175 +RFC 5092                    IMAP URL Scheme                November 2007
  69.176 +
  69.177 +
  69.178 +3.  IMAP userinfo Component (iuserinfo)
  69.179 +
  69.180 +   The <iuserinfo> component conforms to the generic syntax of
  69.181 +   <userinfo> defined in [URI-GEN].  It has the following syntax
  69.182 +   expressed in ABNF [ABNF]:
  69.183 +
  69.184 +      enc-user [iauth] / [enc-user] iauth
  69.185 +
  69.186 +   The meaning of the different parts is described in subsections of
  69.187 +   this section.
  69.188 +
  69.189 +3.1.  IMAP Mailbox Naming Scope
  69.190 +
  69.191 +   The "enc-user" part of the "iuserinfo" component, if present, denotes
  69.192 +   mailbox naming scope.  If it is absent, the IMAP URL can only
  69.193 +   reference mailboxes with globally unique names, i.e., mailboxes with
  69.194 +   names that don't change depending on the user the client
  69.195 +   authenticated as to the IMAP server.  Note that not all IMAP
  69.196 +   implementations support globally unique names.
  69.197 +
  69.198 +   For example, a personal mailbox described by the following URL
  69.199 +   <imap://michael@example.org/INBOX> is most likely different from a
  69.200 +   personal mailbox described by <imap://bester@example.org/INBOX>, even
  69.201 +   though both URLs use the same mailbox name.
  69.202 +
  69.203 +3.2.  IMAP User Name and Authentication Mechanism
  69.204 +
  69.205 +   The userinfo component (see [URI-GEN]) of an IMAP URI may contain an
  69.206 +   IMAP user name (a.k.a. authorization identity [SASL], "enc-user")
  69.207 +   and/or an authentication mechanism. (Note that the "enc-user" also
  69.208 +   defines a mailbox naming scope as described in Section 3.1).  The
  69.209 +   IMAP user name and the authentication mechanism are used in the
  69.210 +   "LOGIN" or "AUTHENTICATE" commands after making the connection to the
  69.211 +   IMAP server.
  69.212 +
  69.213 +   If no user name and no authentication mechanism are supplied, the
  69.214 +   client MUST authenticate as anonymous to the server.  If the server
  69.215 +   advertises AUTH=ANONYMOUS IMAP capability, the client MUST use the
  69.216 +   AUTHENTICATE command with ANONYMOUS [ANONYMOUS] SASL mechanism.  If
  69.217 +   SASL ANONYMOUS is not available, the (case-insensitive) user name
  69.218 +   "anonymous" is used with the "LOGIN" command and the Internet email
  69.219 +   address of the end user accessing the resource is supplied as the
  69.220 +   password.  The latter option is given in order to provide for
  69.221 +   interoperability with deployed servers.
  69.222 +
  69.223 +   Note that, as described in RFC 3501, the "LOGIN" command MUST NOT be
  69.224 +   used when the IMAP server advertises the LOGINDISABLED capability.
  69.225 +
  69.226 +
  69.227 +
  69.228 +
  69.229 +Melnikov & Newman           Standards Track                     [Page 4]
  69.230 +
  69.231 +RFC 5092                    IMAP URL Scheme                November 2007
  69.232 +
  69.233 +
  69.234 +   An authentication mechanism (as used by the IMAP AUTHENTICATE
  69.235 +   command) can be expressed by adding ";AUTH=<enc-auth-type>" to the
  69.236 +   end of the user name in an IMAP URL.  When such an <enc-auth-type> is
  69.237 +   indicated, the client SHOULD request appropriate credentials from
  69.238 +   that mechanism and use the "AUTHENTICATE" command instead of the
  69.239 +   "LOGIN" command.  If no user name is specified, one MUST be obtained
  69.240 +   from the mechanism or requested from the user/configuration as
  69.241 +   appropriate.
  69.242 +
  69.243 +   The string ";AUTH=*" indicates that the client SHOULD select an
  69.244 +   appropriate authentication mechanism.  (Though the '*' character in
  69.245 +   this usage is not strictly a delimiter, it is being treated like a
  69.246 +   sub-delim [URI-GEN] in this instance.  It MUST NOT be percent-encoded
  69.247 +   in this usage, as ";AUTH=%2A" will not match this production.)  It
  69.248 +   MAY use any mechanism listed in the response to the CAPABILITY
  69.249 +   command (or CAPABILITY response code) or use an out-of-band security
  69.250 +   service resulting in a PREAUTH connection.  If no user name is
  69.251 +   specified and no appropriate authentication mechanisms are available,
  69.252 +   the client SHOULD fall back to anonymous login as described above.
  69.253 +   The behavior prescribed in this section allows a URL that grants
  69.254 +   read-write access to authorized users and read-only anonymous access
  69.255 +   to other users.
  69.256 +
  69.257 +   If a user name is included with no authentication mechanism, then
  69.258 +   ";AUTH=*" is assumed.
  69.259 +
  69.260 +   Clients must take care when resolving a URL that requires or requests
  69.261 +   any sort of authentication, since URLs can easily come from untrusted
  69.262 +   sources.  Supplying authentication credentials to the wrong server
  69.263 +   may compromise the security of the user's account; therefore, the
  69.264 +   program resolving the URL should meet at least one of the following
  69.265 +   criteria in this case:
  69.266 +
  69.267 +   1) The URL comes from a trusted source, such as a referral server
  69.268 +      that the client has validated and trusts according to site policy.
  69.269 +      Note that user entry of the URL may or may not count as a trusted
  69.270 +      source, depending on the experience level of the user and site
  69.271 +      policy.
  69.272 +
  69.273 +   2) Explicit local site policy permits the client to connect to the
  69.274 +      server in the URL.  For example, a company example.com may have a
  69.275 +      site policy to trust all IMAP server names ending in example.com,
  69.276 +      whereas such a policy would be unwise for example.edu where random
  69.277 +      students can set up IMAP servers.
  69.278 +
  69.279 +   3) The user confirms that connecting to that domain name with the
  69.280 +      specified credentials and/or mechanism is permitted.  For example,
  69.281 +      when using "LOGIN" or SASL PLAIN with Transport Layer Security
  69.282 +
  69.283 +
  69.284 +
  69.285 +Melnikov & Newman           Standards Track                     [Page 5]
  69.286 +
  69.287 +RFC 5092                    IMAP URL Scheme                November 2007
  69.288 +
  69.289 +
  69.290 +      (TLS), the IMAP URL client presents a dialog box "Is it OK to send
  69.291 +      your password to server "example.com"?  Please be aware the owners
  69.292 +      of example.com will be able to reuse your password to connect to
  69.293 +      other servers on your behalf".
  69.294 +
  69.295 +   4) A mechanism is used that validates the server before passing
  69.296 +      potentially compromising client credentials.  For example, a site
  69.297 +      has a designated TLS certificate used to certify site-trusted IMAP
  69.298 +      server certificates, and this has been configured explicitly into
  69.299 +      the IMAP URL client.  Another example is use of a Simple
  69.300 +      Authentication and Security Layer (SASL) mechanism such as
  69.301 +      DIGEST-MD5 [DIGEST-MD5], which supports mutual authentication.
  69.302 +
  69.303 +   5) An authentication mechanism is used that will not reveal any
  69.304 +      information to the server that could be used to compromise future
  69.305 +      connections.  Examples are SASL ANONYMOUS [ANONYMOUS] or GSSAPI
  69.306 +      [GSSAPI].
  69.307 +
  69.308 +   URLs that do not include a user name but include an authentication
  69.309 +   mechanism (";AUTH=<mech>") must be treated with extra care, since for
  69.310 +   some <mech>s they are more likely to compromise the user's primary
  69.311 +   account.  A URL containing ";AUTH=*" must also be treated with extra
  69.312 +   care since it might fall back on a weaker security mechanism.
  69.313 +   Finally, clients are discouraged from using a plaintext password as a
  69.314 +   fallback with ";AUTH=*" unless the connection has strong encryption.
  69.315 +
  69.316 +   A program interpreting IMAP URLs MAY cache open connections to an
  69.317 +   IMAP server for later reuse.  If a URL contains a user name, only
  69.318 +   connections authenticated as that user may be reused.  If a URL does
  69.319 +   not contain a user name or authentication mechanism, then only an
  69.320 +   anonymous connection may be reused.
  69.321 +
  69.322 +   Note that if unsafe or reserved characters such as " " (space) or ";"
  69.323 +   are present in the user name or authentication mechanism, they MUST
  69.324 +   be percent-encoded as described in [URI-GEN].
  69.325 +
  69.326 +3.3.  Limitations of enc-user
  69.327 +
  69.328 +   As per Sections 3.1 and 3.2 of this document, the IMAP URI enc-user
  69.329 +   has two purposes:
  69.330 +
  69.331 +      1) It provides context for user-specific mailbox paths such as
  69.332 +         "INBOX" (Section 3.1).
  69.333 +
  69.334 +      2) It specifies that resolution of the URL requires logging in as
  69.335 +         that user and limits use of that URL to only that user (Section
  69.336 +         3.2).
  69.337 +
  69.338 +
  69.339 +
  69.340 +
  69.341 +Melnikov & Newman           Standards Track                     [Page 6]
  69.342 +
  69.343 +RFC 5092                    IMAP URL Scheme                November 2007
  69.344 +
  69.345 +
  69.346 +   An obvious limitation of using the same field for both purposes is
  69.347 +   that the URL can be resolved only by the mailbox owner.  In order to
  69.348 +   avoid this restriction, implementations should use globally unique
  69.349 +   mailbox names (see Section 3.1) whenever possible.
  69.350 +
  69.351 +      Note: There is currently no general way in IMAP of learning a
  69.352 +      globally unique name for a mailbox.  However, by looking at the
  69.353 +      NAMESPACE [NAMESPACE] command result, it is possible to determine
  69.354 +      whether or not a mailbox name is globally unique.
  69.355 +
  69.356 +   The URLAUTH component overrides the second purpose of the enc-user in
  69.357 +   the IMAP URI and by default permits the URI to be resolved by any
  69.358 +   user permitted by the <access> identifier.  URLAUTH and <access>
  69.359 +   identifier are described in Section 6.1.
  69.360 +
  69.361 +4.  IMAP Server
  69.362 +
  69.363 +   An IMAP URL referring to an IMAP server has the following form:
  69.364 +
  69.365 +      imap://<iserver>[/]
  69.366 +
  69.367 +   This URL type is frequently used to describe a location of an IMAP
  69.368 +   server, both in referrals and in configuration.  It may optionally
  69.369 +   contain the <iuserinfo> component (see Sections 3 and 11).  A program
  69.370 +   interpreting this URL would issue the standard set of commands it
  69.371 +   uses to present a view of the content of the IMAP server, as visible
  69.372 +   to the user described by the "enc-user" part of the <iuserinfo>
  69.373 +   component, if the "enc-user" part is specified.
  69.374 +
  69.375 +5.  Lists of Messages
  69.376 +
  69.377 +   An IMAP URL referring to a list of messages has the following form:
  69.378 +
  69.379 +      imap://<iserver>/<enc-mailbox>[<uidvalidity>][?<enc-search>]
  69.380 +
  69.381 +   The <enc-mailbox> field is used as the argument to the IMAP4 "SELECT"
  69.382 +   or "EXAMINE" command.  Note that if unsafe or reserved characters
  69.383 +   such as " " (space), ";", or "?" are present in <enc-mailbox>, they
  69.384 +   MUST be percent-encoded as described in [URI-GEN].
  69.385 +
  69.386 +   The <uidvalidity> field is optional.  If it is present, it MUST be
  69.387 +   the same as the value of IMAP4 UIDVALIDITY response code at the time
  69.388 +   the URL was created.  This MUST be used by the program interpreting
  69.389 +   the IMAP URL to determine if the URL is stale.  If the IMAP URL is
  69.390 +   stale, then the program should behave as if the corresponding mailbox
  69.391 +   doesn't exist.
  69.392 +
  69.393 +
  69.394 +
  69.395 +
  69.396 +
  69.397 +Melnikov & Newman           Standards Track                     [Page 7]
  69.398 +
  69.399 +RFC 5092                    IMAP URL Scheme                November 2007
  69.400 +
  69.401 +
  69.402 +   Note that the <uidvalidity> field is a modifier to the <enc-mailbox>,
  69.403 +   i.e., it is considered a part of the last "component" (as used in
  69.404 +   [URI-GEN]) of the <enc-mailbox>.  This is significant during relative
  69.405 +   URI resolution.
  69.406 +
  69.407 +   The "?<enc-search>" field is optional.  If it is not present, the
  69.408 +   program interpreting the URL will present the entire content of the
  69.409 +   mailbox.
  69.410 +
  69.411 +   If the "?<enc-search>" field is present, the program interpreting the
  69.412 +   URL should use the contents of this field as arguments following an
  69.413 +   IMAP4 SEARCH command.  These arguments are likely to contain unsafe
  69.414 +   characters such as " " (space) (which are likely to be present in the
  69.415 +   <enc-search>).  If unsafe characters are present, they MUST be
  69.416 +   percent-encoded as described in [URI-GEN].
  69.417 +
  69.418 +   Note that quoted strings and non-synchronizing literals [LITERAL+]
  69.419 +   are allowed in the <enc-search> content; however, synchronizing
  69.420 +   literals are not allowed, as their presence would effectively mean
  69.421 +   that the agent interpreting IMAP URLs needs to parse an <enc-search>
  69.422 +   content, find all synchronizing literals, and perform proper command
  69.423 +   continuation request handling (see Sections 4.3 and 7 of [IMAP4]).
  69.424 +
  69.425 +6.  A Specific Message or Message Part
  69.426 +
  69.427 +   An IMAP URL referring to a specific message or message part has the
  69.428 +   following form:
  69.429 +
  69.430 +      imap://<iserver>/<enc-mailbox>[<uidvalidity>]<iuid>
  69.431 +      [<isection>][<ipartial>][<iurlauth>]
  69.432 +
  69.433 +   The <enc-mailbox> and [uidvalidity] are as defined in Section 5
  69.434 +   above.
  69.435 +
  69.436 +   If <uidvalidity> is present in this form, it SHOULD be used by the
  69.437 +   program interpreting the URL to determine if the URL is stale.
  69.438 +
  69.439 +   The <iuid> refers to an IMAP4 message Unique Identifier (UID), and it
  69.440 +   SHOULD be used as the <set> argument to the IMAP4 "UID FETCH"
  69.441 +   command.
  69.442 +
  69.443 +   The <isection> field is optional.  If not present, the URL refers to
  69.444 +   the entire Internet message as returned by the IMAP command "UID
  69.445 +   FETCH <uid> BODY.PEEK[]".  If present, the URL refers to the object
  69.446 +   returned by a "UID FETCH <uid> BODY.PEEK[<section>]" command.  The
  69.447 +   type of the object may be determined by using a "UID FETCH <uid>
  69.448 +   BODYSTRUCTURE" command and locating the appropriate part in the
  69.449 +
  69.450 +
  69.451 +
  69.452 +
  69.453 +Melnikov & Newman           Standards Track                     [Page 8]
  69.454 +
  69.455 +RFC 5092                    IMAP URL Scheme                November 2007
  69.456 +
  69.457 +
  69.458 +   resulting BODYSTRUCTURE.  Note that unsafe characters in [isection]
  69.459 +   MUST be percent-encoded as described in [URI-GEN].
  69.460 +
  69.461 +   The <ipartial> field is optional.  If present, it effectively appends
  69.462 +   "<<partial-range>>" to the end of the UID FETCH BODY.PEEK[<section>]
  69.463 +   command constructed as described in the previous paragraph.  In other
  69.464 +   words, it allows the client to request a byte range of the
  69.465 +   message/message part.
  69.466 +
  69.467 +   The <iurlauth> field is described in detail in Section 6.1.
  69.468 +
  69.469 +6.1.  URLAUTH Authorized URL
  69.470 +
  69.471 +   URLAUTH authorized URLs are only supported by an IMAP server
  69.472 +   advertising the URLAUTH IMAP capability [URLAUTH].
  69.473 +
  69.474 +6.1.1.  Concepts
  69.475 +
  69.476 +6.1.1.1.  URLAUTH
  69.477 +
  69.478 +   URLAUTH is a component, appended at the end of a URL, that conveys
  69.479 +   authorization to access the data addressed by that URL.  It contains
  69.480 +   an authorized access identifier, an authorization mechanism name, and
  69.481 +   an authorization token.  The authorization token is generated from
  69.482 +   the URL, the authorized access identifier, authorization mechanism
  69.483 +   name, and a mailbox access key.
  69.484 +
  69.485 +      Note: This specification only allows for the URLAUTH component in
  69.486 +      IMAP URLs describing a message or its part.
  69.487 +
  69.488 +6.1.1.2.  Mailbox Access Key
  69.489 +
  69.490 +   The mailbox access key is an unpredictable, random string.  To ensure
  69.491 +   unpredictability, the random string with at least 128 bits of entropy
  69.492 +   is generated by software or hardware (not by the human user).
  69.493 +
  69.494 +   Each user has a table of mailboxes and an associated mailbox access
  69.495 +   key for each mailbox.  Consequently, the mailbox access key is per-
  69.496 +   user and per-mailbox.  In other words, two users sharing the same
  69.497 +   mailbox each have a different mailbox access key for that mailbox,
  69.498 +   and each mailbox accessed by a single user also has a different
  69.499 +   mailbox access key.
  69.500 +
  69.501 +6.1.1.3.  Authorized Access Identifier
  69.502 +
  69.503 +   The authorized <access> identifier restricts use of the URLAUTH
  69.504 +   authorized URL to certain users authorized on the server, as
  69.505 +   described in Section 6.1.2.
  69.506 +
  69.507 +
  69.508 +
  69.509 +Melnikov & Newman           Standards Track                     [Page 9]
  69.510 +
  69.511 +RFC 5092                    IMAP URL Scheme                November 2007
  69.512 +
  69.513 +
  69.514 +6.1.1.4.  Authorization Mechanism
  69.515 +
  69.516 +   The authorization mechanism is the algorithm by which the URLAUTH is
  69.517 +   generated and subsequently verified, using the mailbox access key.
  69.518 +
  69.519 +6.1.1.5.  Authorization Token
  69.520 +
  69.521 +   The authorization token is a deterministic string of at least 128
  69.522 +   bits that an entity with knowledge of the secret mailbox access key
  69.523 +   and URL authorization mechanism can use to verify the URL.
  69.524 +
  69.525 +6.1.2.  URLAUTH Extensions to IMAP URL
  69.526 +
  69.527 +   A specific message or message part IMAP URL can optionally contain
  69.528 +   ";EXPIRE=<datetime>" and/or ";URLAUTH=<access>:<mech>:<token>".
  69.529 +
  69.530 +   When ";EXPIRE=<datetime>" is used, this indicates the latest date and
  69.531 +   time that the URL is valid.  After that date and time, the URL has
  69.532 +   expired and server implementations MUST reject the URL.  If
  69.533 +   ";EXPIRE=<datetime>" is not used, the URL has no expiration, but can
  69.534 +   still be revoked using the RESETKEY command [URLAUTH].
  69.535 +
  69.536 +   The URLAUTH takes the form ";URLAUTH=<access>:<mech>:<token>", and it
  69.537 +   MUST be at the end of the URL.  It is composed of three parts.  The
  69.538 +   <access> portion provides the authorized access identifiers that may
  69.539 +   constrain the operations and users that are permitted to use this
  69.540 +   URL.  The <mech> portion provides the authorization mechanism used by
  69.541 +   the IMAP server to generate the authorization token that follows.
  69.542 +   The <token> portion provides the authorization token, which can be
  69.543 +   generated using the GENURLAUTH command [URLAUTH].
  69.544 +
  69.545 +   The "submit+" <access> identifier prefix, followed by a userid,
  69.546 +   indicates that only a userid authorized as a message submission
  69.547 +   entity on behalf of the specified userid is permitted to use this
  69.548 +   URL.  The IMAP server does not validate the specified userid but does
  69.549 +   validate that the IMAP session has an authorization identity that is
  69.550 +   authorized as a message submission entity.  The authorized message
  69.551 +   submission entity MUST validate the userid prior to contacting the
  69.552 +   IMAP server.
  69.553 +
  69.554 +   The "user+" <access> identifier prefix, followed by a userid,
  69.555 +   indicates that use of this URL is limited to IMAP sessions that are
  69.556 +   logged in as the specified userid (that is, have authorization
  69.557 +   identity as that userid).
  69.558 +
  69.559 +      Note: If a SASL mechanism that provides both authorization and
  69.560 +      authentication identifiers is used to authenticate to the IMAP
  69.561 +      server, the "user+" <access> identifier MUST match the
  69.562 +
  69.563 +
  69.564 +
  69.565 +Melnikov & Newman           Standards Track                    [Page 10]
  69.566 +
  69.567 +RFC 5092                    IMAP URL Scheme                November 2007
  69.568 +
  69.569 +
  69.570 +      authorization identifier.  If the SASL mechanism can't transport
  69.571 +      the authorization identifier, the "user+" <access> identifier MUST
  69.572 +      match the authorization identifier derived from the authentication
  69.573 +      identifier (see [SASL]).
  69.574 +
  69.575 +   The "authuser" <access> identifier indicates that use of this URL is
  69.576 +   limited to authenticated IMAP sessions that are logged in as any
  69.577 +   non-anonymous user (that is, have authorization identity as a non-
  69.578 +   anonymous user) of that IMAP server.  To restate this: use of this
  69.579 +   type of URL is prohibited to anonymous IMAP sessions, i.e., any
  69.580 +   URLFETCH command containing this type of URL issued in an anonymous
  69.581 +   session MUST return NIL in the URLFETCH response.
  69.582 +
  69.583 +   The "anonymous" <access> identifier indicates that use of this URL is
  69.584 +   not restricted by session authorization identity; that is, any IMAP
  69.585 +   session in authenticated or selected state (as defined in [IMAP4]),
  69.586 +   including anonymous sessions, may issue a URLFETCH [URLAUTH] using
  69.587 +   this URL.
  69.588 +
  69.589 +   The authorization token is represented as an ASCII-encoded
  69.590 +   hexadecimal string, which is used to authorize the URL.  The length
  69.591 +   and the calculation of the authorization token depend upon the
  69.592 +   mechanism used, but in all cases, the authorization token is at least
  69.593 +   128 bits (and therefore at least 32 hexadecimal digits).
  69.594 +
  69.595 +   Example:
  69.596 +
  69.597 +      <imap://joe@example.com/INBOX/;uid=20/;section=1.2;urlauth=
  69.598 +      submit+fred:internal:91354a473744909de610943775f92038>
  69.599 +
  69.600 +7.  Relative IMAP URLs
  69.601 +
  69.602 +   Relative IMAP URLs are permitted and are resolved according to the
  69.603 +   rules defined in [URI-GEN].  In particular, in IMAP URLs parameters
  69.604 +   (such as ";uid=" or ";section=") are treated as part of the normal
  69.605 +   path with respect to relative URL resolution.
  69.606 +
  69.607 +   [URI-GEN] defines four forms of relative URLs: <inetwork-path>,
  69.608 +   <iabsolute-path>, <irelative-path>, and <ipath-empty>.  Their syntax
  69.609 +   is defined in Section 11.
  69.610 +
  69.611 +   A relative reference that begins with two slash characters is termed
  69.612 +   a network-path reference (<inetwork-path>); such references are
  69.613 +   rarely used, because in most cases they can be replaced with an
  69.614 +   equivalent absolute URL.  A relative reference that begins with a
  69.615 +   single slash character is termed an absolute-path reference
  69.616 +   (<iabsolute-path>; see also Section 7.1).  A relative reference that
  69.617 +   does not begin with a slash character is termed a relative-path
  69.618 +
  69.619 +
  69.620 +
  69.621 +Melnikov & Newman           Standards Track                    [Page 11]
  69.622 +
  69.623 +RFC 5092                    IMAP URL Scheme                November 2007
  69.624 +
  69.625 +
  69.626 +   reference (<irelative-path>; see also Section 7.2).  The final form
  69.627 +   is <ipath-empty>, which is "same-document reference" (see Section 4.4
  69.628 +   of [URI-GEN]).
  69.629 +
  69.630 +   The following observations about relative URLs are important:
  69.631 +
  69.632 +   The <iauth> grammar element (which is a part of <iuserinfo>, which
  69.633 +   is, in turn, a part of <iserver>; see Section 3) is considered part
  69.634 +   of the user name for purposes of resolving relative IMAP URLs.  This
  69.635 +   means that unless a new user name/server specification is included in
  69.636 +   the relative URL, the authentication mechanism is inherited from the
  69.637 +   base IMAP URL.
  69.638 +
  69.639 +   URLs always use "/" as the hierarchy delimiter for the purpose of
  69.640 +   resolving paths in relative URLs.  IMAP4 permits the use of any
  69.641 +   hierarchy delimiter in mailbox names.  For this reason, relative
  69.642 +   mailbox paths will only work if the mailbox uses "/" as the hierarchy
  69.643 +   delimiter.  Relative URLs may be used on mailboxes that use other
  69.644 +   delimiters, but in that case, the entire mailbox name MUST be
  69.645 +   specified in the relative URL or inherited as a whole from the base
  69.646 +   URL.
  69.647 +
  69.648 +   If an IMAP server allows for mailbox names starting with "./" or
  69.649 +   "../", ending with "/." or "/..", or containing sequences "/../" or
  69.650 +   "/./", then such mailbox names MUST be percent-encoded as described
  69.651 +   in [URI-GEN].  Otherwise, they would be misinterpreted as dot-
  69.652 +   segments (see Section 3.3 of [URI-GEN]), which are processed
  69.653 +   specially during the relative path resolution process.
  69.654 +
  69.655 +7.1.  absolute-path References
  69.656 +
  69.657 +   A relative reference that begins with a single slash character is
  69.658 +   termed an absolute-path reference (see Section 4.2 of [URI-GEN]).  If
  69.659 +   an IMAP server permits mailbox names with a leading "/", then the
  69.660 +   leading "/" MUST be percent-encoded as described in [URI-GEN].
  69.661 +   Otherwise, the produced absolute-path reference URI will be
  69.662 +   misinterpreted as a network-path reference [URI-GEN] described by the
  69.663 +   <inetwork-path> non-terminal.
  69.664 +
  69.665 +7.2.  relative-path References
  69.666 +
  69.667 +   A relative reference that does not begin with a slash character is
  69.668 +   termed a relative-path reference [URI-GEN].  Implementations MUST NOT
  69.669 +   generate or accept relative-path IMAP references.
  69.670 +
  69.671 +   See also Section 4.2 of [URI-GEN] for restrictions on relative-path
  69.672 +   references.
  69.673 +
  69.674 +
  69.675 +
  69.676 +
  69.677 +Melnikov & Newman           Standards Track                    [Page 12]
  69.678 +
  69.679 +RFC 5092                    IMAP URL Scheme                November 2007
  69.680 +
  69.681 +
  69.682 +8.  Internationalization Considerations
  69.683 +
  69.684 +   IMAP4, Section 5.1.3 [IMAP4] includes a convention for encoding non-
  69.685 +   US-ASCII characters in IMAP mailbox names.  Because this convention
  69.686 +   is private to IMAP, it is necessary to convert IMAP's encoding to one
  69.687 +   that can be more easily interpreted by a URL display program.  For
  69.688 +   this reason, IMAP's modified UTF-7 encoding for mailboxes MUST be
  69.689 +   converted to UTF-8 [UTF-8].  Since 8-bit octets are not permitted in
  69.690 +   URLs, the UTF-8 octets are percent-encoded as required by the URL
  69.691 +   specification [URI-GEN], Section 2.1.  Sample code is included in
  69.692 +   Appendix A to demonstrate this conversion.
  69.693 +
  69.694 +   IMAP user names are UTF-8 strings and MUST be percent-encoded as
  69.695 +   required by the URL specification [URI-GEN], Section 2.1.
  69.696 +
  69.697 +   Also note that IMAP SEARCH criteria can contain non-US-ASCII
  69.698 +   characters.  8-bit octets in those strings MUST be percent-encoded as
  69.699 +   required by the URL specification [URI-GEN], Section 2.1.
  69.700 +
  69.701 +9.  Examples
  69.702 +
  69.703 +   The following examples demonstrate how an IMAP4 client program might
  69.704 +   translate various IMAP4 URLs into a series of IMAP4 commands.
  69.705 +   Commands sent from the client to the server are prefixed with "C:",
  69.706 +   and responses sent from the server to the client are prefixed with
  69.707 +   "S:".
  69.708 +
  69.709 +   The URL:
  69.710 +
  69.711 +      <imap://minbari.example.org/gray-council;UIDVALIDITY=385759045/;
  69.712 +      UID=20/;PARTIAL=0.1024>
  69.713 +
  69.714 +   may result in the following client commands and server responses:
  69.715 +
  69.716 +      <connect to minbari.example.org, port 143>
  69.717 +      S: * OK [CAPABILITY IMAP4rev1 STARTTLS AUTH=ANONYMOUS] Welcome
  69.718 +      C: A001 AUTHENTICATE ANONYMOUS
  69.719 +      S: +
  69.720 +      C: c2hlcmlkYW5AYmFieWxvbjUuZXhhbXBsZS5vcmc=
  69.721 +      S: A001 OK Welcome sheridan@babylon5.example.org
  69.722 +      C: A002 SELECT gray-council
  69.723 +      <client verifies the UIDVALIDITY matches>
  69.724 +      C: A003 UID FETCH 20 BODY.PEEK[]<0.1024>
  69.725 +
  69.726 +   The URL:
  69.727 +
  69.728 +      <imap://psicorp.example.org/~peter/%E6%97%A5%E6%9C%AC%E8%AA%9E/
  69.729 +      %E5%8F%B0%E5%8C%97>
  69.730 +
  69.731 +
  69.732 +
  69.733 +Melnikov & Newman           Standards Track                    [Page 13]
  69.734 +
  69.735 +RFC 5092                    IMAP URL Scheme                November 2007
  69.736 +
  69.737 +
  69.738 +   may result in the following client commands:
  69.739 +
  69.740 +      <connect to psicorp.example.org, port 143>
  69.741 +      S: * OK [CAPABILITY IMAP4rev1 STARTTLS AUTH=CRAM-MD5] Welcome
  69.742 +      C: A001 LOGIN ANONYMOUS bester@psycop.psicorp.example.org
  69.743 +      C: A002 SELECT ~peter/&ZeVnLIqe-/&U,BTFw-
  69.744 +      <commands the client uses for viewing the contents of
  69.745 +       the mailbox>
  69.746 +
  69.747 +   The URL:
  69.748 +
  69.749 +      <imap://;AUTH=GSSAPI@minbari.example.org/gray-council/;uid=20/
  69.750 +      ;section=1.2>
  69.751 +
  69.752 +   may result in the following client commands:
  69.753 +
  69.754 +      <connect to minbari.example.org, port 143>
  69.755 +      S: * OK Greetings
  69.756 +      C: A000 CAPABILITY
  69.757 +      S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI
  69.758 +      S: A000 OK
  69.759 +      C: A001 AUTHENTICATE GSSAPI
  69.760 +      <authentication exchange>
  69.761 +      C: A002 SELECT gray-council
  69.762 +      C: A003 UID FETCH 20 BODY.PEEK[1.2]
  69.763 +
  69.764 +   If the following relative URL is located in that body part:
  69.765 +
  69.766 +      <;section=1.4>
  69.767 +
  69.768 +   this could result in the following client commands:
  69.769 +
  69.770 +      C: A004 UID FETCH 20 (BODY.PEEK[1.2.MIME]
  69.771 +            BODY.PEEK[1.MIME]
  69.772 +            BODY.PEEK[HEADER.FIELDS (Content-Location)])
  69.773 +      <Client looks for Content-Location headers in
  69.774 +       result.  If no such headers, then it does the following>
  69.775 +      C: A005 UID FETCH 20 BODY.PEEK[1.4]
  69.776 +
  69.777 +   The URL:
  69.778 +
  69.779 +      <imap://;AUTH=*@minbari.example.org/gray%20council?
  69.780 +      SUBJECT%20shadows>
  69.781 +
  69.782 +
  69.783 +
  69.784 +
  69.785 +
  69.786 +
  69.787 +
  69.788 +
  69.789 +Melnikov & Newman           Standards Track                    [Page 14]
  69.790 +
  69.791 +RFC 5092                    IMAP URL Scheme                November 2007
  69.792 +
  69.793 +
  69.794 +   could result in the following:
  69.795 +
  69.796 +      <connect to minbari.example.org, port 143>
  69.797 +      S: * OK Welcome
  69.798 +      C: A001 CAPABILITY
  69.799 +      S: * CAPABILITY IMAP4rev1 AUTH=DIGEST-MD5
  69.800 +      S: A001 OK
  69.801 +      C: A002 AUTHENTICATE DIGEST-MD5
  69.802 +      <authentication exchange>
  69.803 +      S: A002 OK user lennier authenticated
  69.804 +      C: A003 SELECT "gray council"
  69.805 +      ...
  69.806 +      C: A004 SEARCH SUBJECT shadows
  69.807 +      S: * SEARCH 8 10 13 14 15 16
  69.808 +      S: A004 OK SEARCH completed
  69.809 +      C: A005 FETCH 8,10,13:16 ALL
  69.810 +      ...
  69.811 +
  69.812 +   In the example above, the client has implementation-dependent
  69.813 +   choices.  The authentication mechanism could be anything, including
  69.814 +   PREAUTH.  The final FETCH command could fetch more or less
  69.815 +   information about the messages, depending on what it wishes to
  69.816 +   display to the user.
  69.817 +
  69.818 +   The URL:
  69.819 +
  69.820 +      <imap://john;AUTH=*@minbari.example.org/babylon5/personel?
  69.821 +      charset%20UTF-8%20SUBJECT%20%7B14+%7D%0D%0A%D0%98%D0%B2%
  69.822 +      D0%B0%D0%BD%D0%BE%D0%B2%D0%B0>
  69.823 +
  69.824 +   shows that 8-bit data can be sent using non-synchronizing literals
  69.825 +   [LITERAL+].  This could result in the following:
  69.826 +
  69.827 +      <connect to minbari.example.org, port 143>
  69.828 +      S: * OK Hi there
  69.829 +      C: A001 CAPABILITY
  69.830 +      S: * CAPABILITY IMAP4rev1 LITERAL+ AUTH=DIGEST-MD5
  69.831 +      S: A001 OK
  69.832 +      C: A002 AUTHENTICATE DIGEST-MD5
  69.833 +      <authentication exchange>
  69.834 +      S: A002 OK user john authenticated
  69.835 +      C: A003 SELECT babylon5/personel
  69.836 +      ...
  69.837 +      C: A004 SEARCH CHARSET UTF-8 SUBJECT {14+}
  69.838 +      C: XXXXXXXXXXXXXX
  69.839 +      S: * SEARCH 7 10 12
  69.840 +      S: A004 OK SEARCH completed
  69.841 +      C: A005 FETCH 7,10,12 ALL
  69.842 +
  69.843 +
  69.844 +
  69.845 +Melnikov & Newman           Standards Track                    [Page 15]
  69.846 +
  69.847 +RFC 5092                    IMAP URL Scheme                November 2007
  69.848 +
  69.849 +
  69.850 +      ...
  69.851 +
  69.852 +   where XXXXXXXXXXXXXX is 14 bytes of UTF-8 encoded data as specified
  69.853 +   in the URL above.
  69.854 +
  69.855 +9.1.  Examples of Relative URLs
  69.856 +
  69.857 +   The following absolute-path reference
  69.858 +
  69.859 +      </foo/;UID=20/..>
  69.860 +
  69.861 +   is the same as
  69.862 +
  69.863 +      </foo>
  69.864 +
  69.865 +   That is, both of them reference the mailbox "foo" located on the IMAP
  69.866 +   server described by the corresponding Base URI.
  69.867 +
  69.868 +   The following relative-path reference
  69.869 +
  69.870 +      <;UID=20>
  69.871 +
  69.872 +   references a message with UID in the mailbox specified by the Base
  69.873 +   URI.
  69.874 +
  69.875 +   The following edge case example demonstrates that the ;UIDVALIDITY=
  69.876 +   modifier is a part of the mailbox name as far as relative URI
  69.877 +   resolution is concerned:
  69.878 +
  69.879 +      <..;UIDVALIDITY=385759045/;UID=20>
  69.880 +
  69.881 +   In this example, ".." is not a dot-segment [URI-GEN].
  69.882 +
  69.883 +10.  Security Considerations
  69.884 +
  69.885 +   Security considerations discussed in the IMAP specification [IMAP4]
  69.886 +   and the URI specification [URI-GEN] are relevant.  Security
  69.887 +   considerations related to authenticated URLs are discussed in Section
  69.888 +   3.2 of this document.
  69.889 +
  69.890 +   Many email clients store the plaintext password for later use after
  69.891 +   logging into an IMAP server.  Such clients MUST NOT use a stored
  69.892 +   password in response to an IMAP URL without explicit permission from
  69.893 +   the user to supply that password to the specified host name.
  69.894 +
  69.895 +   Clients resolving IMAP URLs that wish to achieve data confidentiality
  69.896 +   and/or integrity SHOULD use the STARTTLS command (if supported by the
  69.897 +
  69.898 +
  69.899 +
  69.900 +
  69.901 +Melnikov & Newman           Standards Track                    [Page 16]
  69.902 +
  69.903 +RFC 5092                    IMAP URL Scheme                November 2007
  69.904 +
  69.905 +
  69.906 +   server) before starting authentication, or use a SASL mechanism, such
  69.907 +   as GSSAPI, that provides a confidentiality security layer.
  69.908 +
  69.909 +10.1.  Security Consideration Specific to URLAUTH Authorized URL
  69.910 +
  69.911 +   The "user+<userid>" <access> identifier limits resolution of that URL
  69.912 +   to a particular userid, whereas the "submit+<userid>" <access>
  69.913 +   identifier is more general and simply requires that the session be
  69.914 +   authorized by a user that has been granted a "submit" role within the
  69.915 +   authentication system.  Use of either of these mechanisms limits the
  69.916 +   scope of the URL.  An attacker who cannot authenticate using the
  69.917 +   appropriate credentials cannot make use of the URL.
  69.918 +
  69.919 +   The "authuser" and "anonymous" <access> identifiers do not have this
  69.920 +   level of protection.  These access identifiers are primarily useful
  69.921 +   for public export of data from an IMAP server, without requiring that
  69.922 +   it be copied to a web or anonymous FTP server.
  69.923 +
  69.924 +   The decision to use the "authuser" <access> identifier should be made
  69.925 +   with caution.  An "authuser" <access> identifier can be used by any
  69.926 +   authorized user of the IMAP server; therefore, use of this access
  69.927 +   identifier should be limited to content that may be disclosed to any
  69.928 +   authorized user of the IMAP server.
  69.929 +
  69.930 +   The decision to use the "anonymous" <access> identifier should be
  69.931 +   made with extreme caution.  An "anonymous" <access> identifier can be
  69.932 +   used by anyone; therefore, use of this access identifier should be
  69.933 +   limited to content that may be disclosed to anyone.
  69.934 +
  69.935 +11.  ABNF for IMAP URL Scheme
  69.936 +
  69.937 +   Formal syntax is defined using ABNF [ABNF], extending the ABNF rules
  69.938 +   in Section 9 of [IMAP4].  Elements not defined here can be found in
  69.939 +   [ABNF], [IMAP4], [IMAPABNF], or [URI-GEN].  Strings are not case
  69.940 +   sensitive, and free insertion of linear white space is not permitted.
  69.941 +
  69.942 +   sub-delims-sh = "!" / "$" / "'" / "(" / ")" /
  69.943 +                   "*" / "+" / ","
  69.944 +                      ;; Same as [URI-GEN] sub-delims,
  69.945 +                      ;; but without ";", "&" and "=".
  69.946 +
  69.947 +   uchar            = unreserved / sub-delims-sh / pct-encoded
  69.948 +
  69.949 +   achar            = uchar / "&" / "="
  69.950 +                      ;; Same as [URI-GEN] 'unreserved / sub-delims /
  69.951 +                      ;; pct-encoded', but ";" is disallowed.
  69.952 +
  69.953 +   bchar            = achar / ":" / "@" / "/"
  69.954 +
  69.955 +
  69.956 +
  69.957 +Melnikov & Newman           Standards Track                    [Page 17]
  69.958 +
  69.959 +RFC 5092                    IMAP URL Scheme                November 2007
  69.960 +
  69.961 +
  69.962 +   enc-auth-type    = 1*achar
  69.963 +                   ; %-encoded version of [IMAP4] "auth-type"
  69.964 +
  69.965 +   enc-mailbox      = 1*bchar
  69.966 +                  ; %-encoded version of [IMAP4] "mailbox"
  69.967 +
  69.968 +   enc-search       = 1*bchar
  69.969 +                           ; %-encoded version of [IMAPABNF]
  69.970 +                           ; "search-program".  Note that IMAP4
  69.971 +                           ; literals may not be used in
  69.972 +                           ; a "search-program", i.e., only
  69.973 +                           ; quoted or non-synchronizing
  69.974 +                           ; literals (if the server supports
  69.975 +                           ; LITERAL+ [LITERAL+]) are allowed.
  69.976 +
  69.977 +   enc-section      = 1*bchar
  69.978 +                  ; %-encoded version of [IMAP4] "section-spec"
  69.979 +
  69.980 +   enc-user         = 1*achar
  69.981 +                  ; %-encoded version of [IMAP4] authorization
  69.982 +                  ; identity or "userid".
  69.983 +
  69.984 +   imapurl          = "imap://" iserver ipath-query
  69.985 +               ; Defines an absolute IMAP URL
  69.986 +
  69.987 +   ipath-query      = ["/" [ icommand ]]
  69.988 +                    ; Corresponds to "path-abempty [ "?" query ]"
  69.989 +                    ; in [URI-GEN]
  69.990 +
  69.991 +   Generic syntax for relative URLs is defined in Section 4.2 of
  69.992 +   [URI-GEN].  For ease of implementation, the relative IMAP URL syntax
  69.993 +   is defined below:
  69.994 +
  69.995 +   imapurl-rel     = inetwork-path
  69.996 +
  69.997 +                     / iabsolute-path
  69.998 +                     / irelative-path
  69.999 +                     / ipath-empty
 69.1000 +
 69.1001 +   inetwork-path   = "//" iserver ipath-query
 69.1002 +               ; Corresponds to '"//" authority path-abempty
 69.1003 +               ; [ "?" query ]' in [URI-GEN]
 69.1004 +
 69.1005 +   iabsolute-path  = "/" [ icommand ]
 69.1006 +               ; icommand, if present, MUST NOT start with '/'.
 69.1007 +               ;
 69.1008 +               ; Corresponds to 'path-absolute [ "?" query ]'
 69.1009 +               ; in [URI-GEN]
 69.1010 +
 69.1011 +
 69.1012 +
 69.1013 +Melnikov & Newman           Standards Track                    [Page 18]
 69.1014 +
 69.1015 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1016 +
 69.1017 +
 69.1018 +   irelative-path  = imessagelist /
 69.1019 +                     imsg-or-part
 69.1020 +               ; Corresponds to 'path-noscheme [ "?" query ]'
 69.1021 +               ; in [URI-GEN]
 69.1022 +
 69.1023 +   imsg-or-part    = ( imailbox-ref "/" iuid-only ["/" isection-only]
 69.1024 +                       ["/" ipartial-only] ) /
 69.1025 +                     ( iuid-only ["/" isection-only]
 69.1026 +                       ["/" ipartial-only] ) /
 69.1027 +                     ( isection-only ["/" ipartial-only] ) /
 69.1028 +                     ipartial-only
 69.1029 +
 69.1030 +   ipath-empty     = 0<pchar>
 69.1031 +                    ; Zero characters.
 69.1032 +                    ; The same-document reference.
 69.1033 +
 69.1034 +   The following three rules are only used in the presence of the IMAP
 69.1035 +   [URLAUTH] extension:
 69.1036 +
 69.1037 +   authimapurl     = "imap://" iserver "/" imessagepart
 69.1038 +                     ; Same as "imapurl" when "[icommand]" is
 69.1039 +                     ; "imessagepart"
 69.1040 +
 69.1041 +   authimapurlfull = authimapurl iurlauth
 69.1042 +                     ; Same as "imapurl" when "[icommand]" is
 69.1043 +                     ; "imessagepart iurlauth"
 69.1044 +
 69.1045 +   authimapurlrump = authimapurl iurlauth-rump
 69.1046 +
 69.1047 +
 69.1048 +   enc-urlauth     = 32*HEXDIG
 69.1049 +
 69.1050 +   iurlauth        = iurlauth-rump iua-verifier
 69.1051 +
 69.1052 +   iua-verifier    = ":" uauth-mechanism ":" enc-urlauth
 69.1053 +
 69.1054 +   iurlauth-rump   = [expire] ";URLAUTH=" access
 69.1055 +
 69.1056 +   access          = ("submit+" enc-user) / ("user+" enc-user) /
 69.1057 +                       "authuser" / "anonymous"
 69.1058 +
 69.1059 +   expire          = ";EXPIRE=" date-time
 69.1060 +                         ; date-time is defined in [DATETIME]
 69.1061 +
 69.1062 +   uauth-mechanism = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
 69.1063 +                        ; Case-insensitive.
 69.1064 +                        ; New mechanisms MUST be registered with IANA.
 69.1065 +
 69.1066 +
 69.1067 +
 69.1068 +
 69.1069 +Melnikov & Newman           Standards Track                    [Page 19]
 69.1070 +
 69.1071 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1072 +
 69.1073 +
 69.1074 +   iauth            = ";AUTH=" ( "*" / enc-auth-type )
 69.1075 +
 69.1076 +   icommand         = imessagelist /
 69.1077 +                      imessagepart [iurlauth]
 69.1078 +
 69.1079 +   imailbox-ref     = enc-mailbox [uidvalidity]
 69.1080 +
 69.1081 +   imessagelist     = imailbox-ref [ "?" enc-search ]
 69.1082 +                  ; "enc-search" is [URI-GEN] "query".
 69.1083 +
 69.1084 +   imessagepart     = imailbox-ref iuid [isection] [ipartial]
 69.1085 +
 69.1086 +   ipartial         = "/" ipartial-only
 69.1087 +
 69.1088 +   ipartial-only    = ";PARTIAL=" partial-range
 69.1089 +
 69.1090 +   isection         = "/" isection-only
 69.1091 +
 69.1092 +   isection-only    = ";SECTION=" enc-section
 69.1093 +
 69.1094 +   iserver          = [iuserinfo "@"] host [ ":" port ]
 69.1095 +                           ; This is the same as "authority" defined
 69.1096 +                           ; in [URI-GEN].  See [URI-GEN] for "host"
 69.1097 +                           ; and "port" definitions.
 69.1098 +
 69.1099 +   iuid             = "/" iuid-only
 69.1100 +
 69.1101 +   iuid-only        = ";UID=" nz-number
 69.1102 +                  ; See [IMAP4] for "nz-number" definition
 69.1103 +
 69.1104 +   iuserinfo        = enc-user [iauth] / [enc-user] iauth
 69.1105 +                                ; conforms to the generic syntax of
 69.1106 +                                ; "userinfo" as defined in [URI-GEN].
 69.1107 +
 69.1108 +   partial-range    = number ["." nz-number]
 69.1109 +                  ; partial FETCH.  The first number is
 69.1110 +                           ; the offset of the first byte,
 69.1111 +                           ; the second number is the length of
 69.1112 +                           ; the fragment.
 69.1113 +
 69.1114 +   uidvalidity      = ";UIDVALIDITY=" nz-number
 69.1115 +                       ; See [IMAP4] for "nz-number" definition
 69.1116 +
 69.1117 +
 69.1118 +
 69.1119 +
 69.1120 +
 69.1121 +
 69.1122 +
 69.1123 +
 69.1124 +
 69.1125 +Melnikov & Newman           Standards Track                    [Page 20]
 69.1126 +
 69.1127 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1128 +
 69.1129 +
 69.1130 +12.  IANA Considerations
 69.1131 +
 69.1132 +   IANA has updated the "imap" definition in the "Uniform Resource
 69.1133 +   Identifier scheme registry" to point to this document.
 69.1134 +
 69.1135 +   The registration template (as per [URI-REG]) is specified in Section
 69.1136 +   12.1 of this document.
 69.1137 +
 69.1138 +12.1.  IANA Registration of imap: URI Scheme
 69.1139 +
 69.1140 +   This section provides the information required to register the imap:
 69.1141 +   URI scheme.
 69.1142 +
 69.1143 +   URI scheme name: imap
 69.1144 +
 69.1145 +   Status: permanent
 69.1146 +
 69.1147 +   URI scheme syntax:
 69.1148 +
 69.1149 +      See Section 11 of [RFC5092].
 69.1150 +
 69.1151 +   URI scheme semantics:
 69.1152 +
 69.1153 +      The imap: URI scheme is used to designate IMAP servers, mailboxes,
 69.1154 +      messages, MIME bodies [MIME] and their parts, and search programs
 69.1155 +      on Internet hosts accessible using the IMAP protocol.
 69.1156 +
 69.1157 +      There is no MIME type associated with this URI.
 69.1158 +
 69.1159 +   Encoding considerations:
 69.1160 +
 69.1161 +      See Section 8 of [RFC5092].
 69.1162 +
 69.1163 +   Applications/protocols that use this URI scheme name:
 69.1164 +
 69.1165 +      The imap: URI is intended to be used by applications that might
 69.1166 +      need access to an IMAP mailstore.  Such applications may include
 69.1167 +      (but are not limited to) IMAP-capable web browsers; IMAP clients
 69.1168 +      that wish to access a mailbox, message, or edit a message on the
 69.1169 +      server using [CATENATE]; [SUBMIT] clients and servers that are
 69.1170 +      requested to assemble a complete message on submission using
 69.1171 +      [BURL].
 69.1172 +
 69.1173 +   Interoperability considerations:
 69.1174 +
 69.1175 +      A widely deployed IMAP client Netscape Mail (and possibly
 69.1176 +      Mozilla/Thunderbird/Seamonkey) uses a different imap: scheme
 69.1177 +      internally.
 69.1178 +
 69.1179 +
 69.1180 +
 69.1181 +Melnikov & Newman           Standards Track                    [Page 21]
 69.1182 +
 69.1183 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1184 +
 69.1185 +
 69.1186 +   Security considerations:
 69.1187 +
 69.1188 +      See Security Considerations (Section 10) of [RFC5092].
 69.1189 +
 69.1190 +   Contact:
 69.1191 +
 69.1192 +      Alexey Melnikov <alexey.melnikov@isode.com>
 69.1193 +
 69.1194 +   Author/Change controller:
 69.1195 +
 69.1196 +      IESG
 69.1197 +
 69.1198 +   References:
 69.1199 +
 69.1200 +      [RFC5092] and [IMAP4].
 69.1201 +
 69.1202 +13. References
 69.1203 +
 69.1204 +13.1.  Normative References
 69.1205 +
 69.1206 +   [KEYWORDS]   Bradner, S., "Key words for use in RFCs to Indicate
 69.1207 +                Requirement Levels", BCP 14, RFC 2119, March 1997.
 69.1208 +
 69.1209 +   [IMAP4]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
 69.1210 +                4rev1", RFC 3501, March 2003.
 69.1211 +
 69.1212 +   [IMAPABNF]   Melnikov, A. and C. Daboo, "Collected Extensions to
 69.1213 +                IMAP4 ABNF", RFC 4466, April 2006.
 69.1214 +
 69.1215 +   [ABNF]       Crocker, D., Ed., and P. Overell, "Augmented BNF for
 69.1216 +                Syntax Specifications: ABNF", RFC 4234, October 2005.
 69.1217 +
 69.1218 +   [MIME]       Freed, N. and N. Borenstein, "Multipurpose Internet Mail
 69.1219 +                Extensions (MIME) Part One: Format of Internet Message
 69.1220 +                Bodies", RFC 2045, November 1996.
 69.1221 +
 69.1222 +   [URI-GEN]    Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
 69.1223 +                Resource Identifier (URI): Generic Syntax", STD 66, RFC
 69.1224 +                3986, January 2005.
 69.1225 +
 69.1226 +   [UTF-8]      Yergeau, F., "UTF-8, a transformation format of ISO
 69.1227 +                10646", STD 63, RFC 3629, November 2003.
 69.1228 +
 69.1229 +   [NAMESPACE]  Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
 69.1230 +                May 1998.
 69.1231 +
 69.1232 +   [LITERAL+]   Myers, J., "IMAP4 non-synchronizing literals", RFC 2088,
 69.1233 +                January 1997.
 69.1234 +
 69.1235 +
 69.1236 +
 69.1237 +Melnikov & Newman           Standards Track                    [Page 22]
 69.1238 +
 69.1239 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1240 +
 69.1241 +
 69.1242 +   [ANONYMOUS]  Zeilenga, K., "Anonymous Simple Authentication and
 69.1243 +                Security Layer (SASL) Mechanism", RFC 4505, June 2006.
 69.1244 +
 69.1245 +   [DATETIME]   Klyne, G. and C. Newman, "Date and Time on the Internet:
 69.1246 +                Timestamps", RFC 3339, July 2002.
 69.1247 +
 69.1248 +   [URLAUTH]    Crispin, M., "Internet Message Access Protocol (IMAP) -
 69.1249 +                URLAUTH Extension", RFC 4467, May 2006.
 69.1250 +
 69.1251 +13.2.  Informative References
 69.1252 +
 69.1253 +   [SUBMIT]     Gellens, R. and J. Klensin, "Message Submission for
 69.1254 +                Mail", RFC 4409, April 2006.
 69.1255 +
 69.1256 +   [BURL]       Newman, C., "Message Submission BURL Extension", RFC
 69.1257 +                4468, May 2006.
 69.1258 +
 69.1259 +   [CATENATE]   Resnick, P., "Internet Message Access Protocol (IMAP)
 69.1260 +                CATENATE Extension", RFC 4469, April 2006.
 69.1261 +
 69.1262 +   [SASL]       Melnikov, A., Ed., and K. Zeilenga, Ed., "Simple
 69.1263 +                Authentication and Security Layer (SASL)", RFC 4422,
 69.1264 +                June 2006.
 69.1265 +
 69.1266 +   [GSSAPI]     Melnikov, A., Ed., "The Kerberos V5 ("GSSAPI") Simple
 69.1267 +                Authentication and Security Layer (SASL) Mechanism", RFC
 69.1268 +                4752, November 2006.
 69.1269 +
 69.1270 +   [DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as
 69.1271 +                a SASL Mechanism", RFC 2831, May 2000.
 69.1272 +
 69.1273 +   [URI-REG]    Hansen, T., Hardie, T., and L. Masinter, "Guidelines and
 69.1274 +                Registration Procedures for New URI Schemes", BCP 115,
 69.1275 +                RFC 4395, February 2006.
 69.1276 +
 69.1277 +
 69.1278 +
 69.1279 +
 69.1280 +
 69.1281 +
 69.1282 +
 69.1283 +
 69.1284 +
 69.1285 +
 69.1286 +
 69.1287 +
 69.1288 +
 69.1289 +
 69.1290 +
 69.1291 +
 69.1292 +
 69.1293 +Melnikov & Newman           Standards Track                    [Page 23]
 69.1294 +
 69.1295 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1296 +
 69.1297 +
 69.1298 +Appendix A.  Sample Code
 69.1299 +
 69.1300 +   Here is sample C source code to convert between URL paths and IMAP
 69.1301 +   mailbox names, taking into account mapping between IMAP's modified
 69.1302 +   UTF-7 [IMAP4] and hex-encoded UTF-8, which is more appropriate for
 69.1303 +   URLs.  This code has not been rigorously tested nor does it
 69.1304 +   necessarily behave reasonably with invalid input, but it should serve
 69.1305 +   as a useful example.  This code just converts the mailbox portion of
 69.1306 +   the URL and does not deal with parameters, query, or server
 69.1307 +   components of the URL.
 69.1308 +
 69.1309 +/* Copyright (C) The IETF Trust (2007).  This version of
 69.1310 +   sample C code is part of RFC XXXX; see the RFC itself
 69.1311 +   for full legal notices.
 69.1312 +
 69.1313 +   Regarding this sample C code (or any portion of it), the authors
 69.1314 +   make no guarantees and are not responsible for any damage
 69.1315 +   resulting from its use.  The authors grant irrevocable permission
 69.1316 +   to anyone to use, modify, and distribute it in any way that does
 69.1317 +   not diminish the rights of anyone else to use, modify, and
 69.1318 +   distribute it, provided that redistributed derivative works do
 69.1319 +   not contain misleading author or version information.
 69.1320 +
 69.1321 +   Derivative works need not be licensed under similar terms.
 69.1322 + */
 69.1323 +
 69.1324 +#include <stdio.h>
 69.1325 +#include <string.h>
 69.1326 +
 69.1327 +/* hexadecimal lookup table */
 69.1328 +static const char hex[] = "0123456789ABCDEF";
 69.1329 +
 69.1330 +#define XX 127
 69.1331 +/*
 69.1332 + * Table for decoding hexadecimal in %encoding
 69.1333 + */
 69.1334 +static const char index_hex[256] = {
 69.1335 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1336 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1337 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1338 +     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
 69.1339 +    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1340 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1341 +    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1342 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1343 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1344 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1345 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1346 +
 69.1347 +
 69.1348 +
 69.1349 +Melnikov & Newman           Standards Track                    [Page 24]
 69.1350 +
 69.1351 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1352 +
 69.1353 +
 69.1354 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1355 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1356 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1357 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1358 +    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
 69.1359 +};
 69.1360 +#define HEXCHAR(c)  (index_hex[(unsigned char)(c)])
 69.1361 +
 69.1362 +/* "gen-delims" excluding "/" but including "%" */
 69.1363 +#define GENERAL_DELIMS_NO_SLASH     ":?#[]@" "%"
 69.1364 +
 69.1365 +/* "gen-delims" (excluding "/", but including "%")
 69.1366 +   plus subset of "sub-delims" */
 69.1367 +#define GENERAL_UNSAFE_NO_SLASH     GENERAL_DELIMS_NO_SLASH ";&=+"
 69.1368 +#define OTHER_UNSAFE                " \"<>\\^`{|}"
 69.1369 +
 69.1370 +/* URL unsafe printable characters */
 69.1371 +static const char mailbox_url_unsafe[] = GENERAL_UNSAFE_NO_SLASH
 69.1372 +                                         OTHER_UNSAFE;
 69.1373 +
 69.1374 +/* UTF7 modified base64 alphabet */
 69.1375 +static const char base64chars[] =
 69.1376 +  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
 69.1377 +
 69.1378 +#define UNDEFINED 64
 69.1379 +
 69.1380 +/* UTF16 definitions */
 69.1381 +#define UTF16MASK   0x03FFUL
 69.1382 +#define UTF16SHIFT  10
 69.1383 +#define UTF16BASE   0x10000UL
 69.1384 +#define UTF16HIGHSTART   0xD800UL
 69.1385 +#define UTF16HIGHEND     0xDBFFUL
 69.1386 +#define UTF16LOSTART     0xDC00UL
 69.1387 +#define UTF16LOEND  0xDFFFUL
 69.1388 +
 69.1389 +/* Convert an IMAP mailbox to a URL path
 69.1390 + *  dst needs to have roughly 4 times the storage space of src
 69.1391 + *    Hex encoding can triple the size of the input
 69.1392 + *    UTF-7 can be slightly denser than UTF-8
 69.1393 + *     (worst case: 8 octets UTF-7 becomes 9 octets UTF-8)
 69.1394 + */
 69.1395 +void MailboxToURL(char *dst, char *src)
 69.1396 +{
 69.1397 +    unsigned char c, i, bitcount;
 69.1398 +    unsigned long ucs4, utf16, bitbuf;
 69.1399 +    unsigned char base64[256], utf8[6];
 69.1400 +
 69.1401 +    /* initialize modified base64 decoding table */
 69.1402 +
 69.1403 +
 69.1404 +
 69.1405 +Melnikov & Newman           Standards Track                    [Page 25]
 69.1406 +
 69.1407 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1408 +
 69.1409 +
 69.1410 +    memset(base64, UNDEFINED, sizeof (base64));
 69.1411 +    for (i = 0; i < sizeof (base64chars); ++i) {
 69.1412 +     base64[(int) base64chars[i]] = i;
 69.1413 +    }
 69.1414 +
 69.1415 +    /* loop until end of string */
 69.1416 +    while (*src != '\0') {
 69.1417 +     c = *src++;
 69.1418 +     /* deal with literal characters and &- */
 69.1419 +     if (c != '&' || *src == '-') {
 69.1420 +         /* NB: There are no "URL safe" characters after the '~' */
 69.1421 +         if (c < ' ' || c > '~' ||
 69.1422 +             strchr(mailbox_url_unsafe, c) != NULL) {
 69.1423 +          /* hex encode if necessary */
 69.1424 +          dst[0] = '%';
 69.1425 +          dst[1] = hex[c >> 4];
 69.1426 +          dst[2] = hex[c & 0x0f];
 69.1427 +          dst += 3;
 69.1428 +         } else {
 69.1429 +          /* encode literally */
 69.1430 +          *dst++ = c;
 69.1431 +         }
 69.1432 +         /* skip over the '-' if this is an &- sequence */
 69.1433 +         if (c == '&') ++src;
 69.1434 +
 69.1435 +     } else {
 69.1436 +        /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */
 69.1437 +         bitbuf = 0;
 69.1438 +         bitcount = 0;
 69.1439 +         ucs4 = 0;
 69.1440 +         while ((c = base64[(unsigned char) *src]) != UNDEFINED) {
 69.1441 +          ++src;
 69.1442 +          bitbuf = (bitbuf << 6) | c;
 69.1443 +          bitcount += 6;
 69.1444 +          /* enough bits for a UTF-16 character? */
 69.1445 +          if (bitcount >= 16) {
 69.1446 +              bitcount -= 16;
 69.1447 +              utf16 = (bitcount ? bitbuf >> bitcount
 69.1448 +                             : bitbuf) & 0xffff;
 69.1449 +              /* convert UTF16 to UCS4 */
 69.1450 +              if
 69.1451 +                    (utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) {
 69.1452 +               ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT;
 69.1453 +               continue;
 69.1454 +              } else if
 69.1455 +                    (utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) {
 69.1456 +               ucs4 += utf16 - UTF16LOSTART + UTF16BASE;
 69.1457 +              } else {
 69.1458 +
 69.1459 +
 69.1460 +
 69.1461 +Melnikov & Newman           Standards Track                    [Page 26]
 69.1462 +
 69.1463 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1464 +
 69.1465 +
 69.1466 +               ucs4 = utf16;
 69.1467 +              }
 69.1468 +              /* convert UTF-16 range of UCS4 to UTF-8 */
 69.1469 +              if (ucs4 <= 0x7fUL) {
 69.1470 +               utf8[0] = (unsigned char) ucs4;
 69.1471 +               i = 1;
 69.1472 +              } else if (ucs4 <= 0x7ffUL) {
 69.1473 +               utf8[0] = 0xc0 | (unsigned char) (ucs4 >> 6);
 69.1474 +               utf8[1] = 0x80 | (unsigned char) (ucs4 & 0x3f);
 69.1475 +               i = 2;
 69.1476 +              } else if (ucs4 <= 0xffffUL) {
 69.1477 +               utf8[0] = 0xe0 | (unsigned char) (ucs4 >> 12);
 69.1478 +               utf8[1] = 0x80 | (unsigned char) ((ucs4 >> 6) & 0x3f);
 69.1479 +               utf8[2] = 0x80 | (unsigned char) (ucs4 & 0x3f);
 69.1480 +               i = 3;
 69.1481 +              } else {
 69.1482 +               utf8[0] = 0xf0 | (unsigned char) (ucs4 >> 18);
 69.1483 +               utf8[1] = 0x80 | (unsigned char) ((ucs4 >> 12) & 0x3f);
 69.1484 +               utf8[2] = 0x80 | (unsigned char) ((ucs4 >> 6) & 0x3f);
 69.1485 +               utf8[3] = 0x80 | (unsigned char) (ucs4 & 0x3f);
 69.1486 +               i = 4;
 69.1487 +              }
 69.1488 +              /* convert utf8 to hex */
 69.1489 +              for (c = 0; c < i; ++c) {
 69.1490 +               dst[0] = '%';
 69.1491 +               dst[1] = hex[utf8[c] >> 4];
 69.1492 +               dst[2] = hex[utf8[c] & 0x0f];
 69.1493 +               dst += 3;
 69.1494 +              }
 69.1495 +          }
 69.1496 +         }
 69.1497 +         /* skip over trailing '-' in modified UTF-7 encoding */
 69.1498 +         if (*src == '-') ++src;
 69.1499 +     }
 69.1500 +    }
 69.1501 +    /* terminate destination string */
 69.1502 +    *dst = '\0';
 69.1503 +}
 69.1504 +
 69.1505 +/* Convert hex coded UTF-8 URL path to modified UTF-7 IMAP mailbox
 69.1506 + *  dst should be about twice the length of src to deal with non-hex
 69.1507 + *  coded URLs
 69.1508 + */
 69.1509 +int URLtoMailbox(char *dst, char *src)
 69.1510 +{
 69.1511 +    unsigned int utf8pos = 0;
 69.1512 +    unsigned int utf8total, i, c, utf7mode, bitstogo, utf16flag;
 69.1513 +    unsigned long ucs4 = 0, bitbuf = 0;
 69.1514 +
 69.1515 +
 69.1516 +
 69.1517 +Melnikov & Newman           Standards Track                    [Page 27]
 69.1518 +
 69.1519 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1520 +
 69.1521 +
 69.1522 +    utf7mode = 0; /* is the output UTF7 currently in base64 mode? */
 69.1523 +    utf8total = 0; /* how many octets is the current input UTF-8 char;
 69.1524 +                      0 == between characters */
 69.1525 +    bitstogo = 0; /* bits that need to be encoded into base64; if
 69.1526 +                     bitstogo != 0 then utf7mode == 1 */
 69.1527 +    while ((c = (unsigned char)*src) != '\0') {
 69.1528 +     ++src;
 69.1529 +     /* undo hex-encoding */
 69.1530 +     if (c == '%' && src[0] != '\0' && src[1] != '\0') {
 69.1531 +         c = HEXCHAR(src[0]);
 69.1532 +         i = HEXCHAR(src[1]);
 69.1533 +         if (c == XX || i == XX) {
 69.1534 +             return 0;
 69.1535 +         } else {
 69.1536 +             c = (char)((c << 4) | i);
 69.1537 +         }
 69.1538 +         src += 2;
 69.1539 +     }
 69.1540 +     /* normal character? */
 69.1541 +     if (c >= ' ' && c <= '~') {
 69.1542 +         /* switch out of UTF-7 mode */
 69.1543 +         if (utf7mode) {
 69.1544 +          if (bitstogo) {
 69.1545 +          *dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
 69.1546 +          }
 69.1547 +          *dst++ = '-';
 69.1548 +          utf7mode = 0;
 69.1549 +          bitstogo = bitbuf = 0;
 69.1550 +         }
 69.1551 +         *dst++ = c;
 69.1552 +         /* encode '&' as '&-' */
 69.1553 +         if (c == '&') {
 69.1554 +          *dst++ = '-';
 69.1555 +         }
 69.1556 +         continue;
 69.1557 +     }
 69.1558 +     /* switch to UTF-7 mode */
 69.1559 +     if (!utf7mode) {
 69.1560 +         *dst++ = '&';
 69.1561 +         utf7mode = 1;
 69.1562 +     }
 69.1563 +     /* Encode US-ASCII characters as themselves */
 69.1564 +     if (c < 0x80) {
 69.1565 +         ucs4 = c;
 69.1566 +         utf8total = 1;
 69.1567 +     } else if (utf8total) {
 69.1568 +         /* this is a subsequent octet of a multi-octet character */
 69.1569 +         /* save UTF8 bits into UCS4 */
 69.1570 +
 69.1571 +
 69.1572 +
 69.1573 +Melnikov & Newman           Standards Track                    [Page 28]
 69.1574 +
 69.1575 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1576 +
 69.1577 +
 69.1578 +         ucs4 = (ucs4 << 6) | (c & 0x3FUL);
 69.1579 +         if (++utf8pos < utf8total) {
 69.1580 +          continue;
 69.1581 +         }
 69.1582 +     } else {
 69.1583 +         /* this is the first octet of a multi-octet character */
 69.1584 +         utf8pos = 1;
 69.1585 +         if (c < 0xE0) {
 69.1586 +          utf8total = 2;
 69.1587 +          ucs4 = c & 0x1F;
 69.1588 +         } else if (c < 0xF0) {
 69.1589 +          utf8total = 3;
 69.1590 +          ucs4 = c & 0x0F;
 69.1591 +         } else {
 69.1592 +          /* NOTE: can't convert UTF8 sequences longer than 4 */
 69.1593 +          utf8total = 4;
 69.1594 +          ucs4 = c & 0x03;
 69.1595 +         }
 69.1596 +         continue;
 69.1597 +     }
 69.1598 +     /* Finished with UTF-8 character.  Make sure it isn't an
 69.1599 +        overlong sequence.  If it is, return failure. */
 69.1600 +     if ((ucs4 < 0x80 && utf8total > 1) ||
 69.1601 +         (ucs4 < 0x0800 && utf8total > 2) ||
 69.1602 +         (ucs4 < 0x00010000 && utf8total > 3) ||
 69.1603 +         (ucs4 < 0x00200000 && utf8total > 4) ||
 69.1604 +         (ucs4 < 0x04000000 && utf8total > 5) ||
 69.1605 +         (ucs4 < 0x80000000 && utf8total > 6)) {
 69.1606 +         return 0;
 69.1607 +     }
 69.1608 +     /* loop to split ucs4 into two utf16 chars if necessary */
 69.1609 +     utf8total = 0;
 69.1610 +     do {
 69.1611 +         if (ucs4 >= UTF16BASE) {
 69.1612 +                ucs4 -= UTF16BASE;
 69.1613 +          bitbuf = (bitbuf << 16) | ((ucs4 >> UTF16SHIFT)
 69.1614 +                            + UTF16HIGHSTART);
 69.1615 +          ucs4 = (ucs4 & UTF16MASK) + UTF16LOSTART;
 69.1616 +          utf16flag = 1;
 69.1617 +         } else {
 69.1618 +          bitbuf = (bitbuf << 16) | ucs4;
 69.1619 +          utf16flag = 0;
 69.1620 +         }
 69.1621 +         bitstogo += 16;
 69.1622 +         /* spew out base64 */
 69.1623 +         while (bitstogo >= 6) {
 69.1624 +          bitstogo -= 6;
 69.1625 +          *dst++ = base64chars[(bitstogo ? (bitbuf >> bitstogo)
 69.1626 +
 69.1627 +
 69.1628 +
 69.1629 +Melnikov & Newman           Standards Track                    [Page 29]
 69.1630 +
 69.1631 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1632 +
 69.1633 +
 69.1634 +                               : bitbuf)
 69.1635 +                         & 0x3F];
 69.1636 +         }
 69.1637 +     } while (utf16flag);
 69.1638 +    }
 69.1639 +    /* if in UTF-7 mode, finish in ASCII */
 69.1640 +    if (utf7mode) {
 69.1641 +     if (bitstogo) {
 69.1642 +         *dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
 69.1643 +     }
 69.1644 +     *dst++ = '-';
 69.1645 +    }
 69.1646 +    /* tie off string */
 69.1647 +    *dst = '\0';
 69.1648 +    return 1;
 69.1649 +}
 69.1650 +
 69.1651 +Appendix B.  List of Changes since RFC 2192
 69.1652 +
 69.1653 +   Updated boilerplate, list of editor's, etc.
 69.1654 +   Updated references.
 69.1655 +   Updated ABNF not to use _, to use SP instead of SPACE, etc.
 69.1656 +   Updated example domains to use example.org.
 69.1657 +   Fixed ABNF error in "imessagelist" non-terminal.
 69.1658 +   Updated ABNF, due to changes in RFC 3501, RFC 4466, and RFC 3986.
 69.1659 +   Renamed "iuserauth" non-terminal to <iuserinfo>.
 69.1660 +   Clarified that the userinfo component describes both authorization
 69.1661 +   identity and mailbox naming scope.
 69.1662 +   Allow for non-synchronizing literals in "enc-search".
 69.1663 +   Added "ipartial" specifier that denotes a partial FETCH.
 69.1664 +   Moved URLAUTH text from RFC 4467 to this document.
 69.1665 +   Updated ABNF for the whole server to allow missing trailing "/"
 69.1666 +   (e.g., "imap://imap.example.com" is now valid and is the same as
 69.1667 +   "imap://imap.example.com/").
 69.1668 +   Clarified how relative-path references are constructed.
 69.1669 +   Added more examples demonstrating relative-path references.
 69.1670 +   Added rules for relative URLs and restructured ABNF as the result.
 69.1671 +   Removed text on use of relative URLs in MHTML.
 69.1672 +   Added examples demonstrating security considerations when resolving
 69.1673 +   URLs.
 69.1674 +   Recommend usage of STARTTLS/SASL security layer to protect
 69.1675 +   confidential data.
 69.1676 +   Removed some advices about connection reuse that were incorrect.
 69.1677 +   Removed URLs referencing a list of mailboxes, as this feature
 69.1678 +   hasn't seen any deployments.
 69.1679 +   Clarified that user name "anonymous" is case-insensitive.
 69.1680 +
 69.1681 +
 69.1682 +
 69.1683 +
 69.1684 +
 69.1685 +Melnikov & Newman           Standards Track                    [Page 30]
 69.1686 +
 69.1687 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1688 +
 69.1689 +
 69.1690 +Appendix C.  List of Changes since RFC 4467
 69.1691 +
 69.1692 +   Renamed <mechanism> to <uauth-mechanism>.  Restructured ABNF.
 69.1693 +
 69.1694 +Appendix D.  Acknowledgments
 69.1695 +
 69.1696 +   Text describing URLAUTH was lifted from [URLAUTH] by Mark Crispin.
 69.1697 +
 69.1698 +   Stephane H. Maes contributed some ideas to this document; he also
 69.1699 +   co-edited early versions of this document.
 69.1700 +
 69.1701 +   The editors would like to thank Mark Crispin, Ken Murchison, Ted
 69.1702 +   Hardie, Zoltan Ordogh, Dave Cridland, Kjetil Torgrim Homme, Lisa
 69.1703 +   Dusseault, Spencer Dawkins, Filip Navara, Shawn M. Emery, Sam
 69.1704 +   Hartman, Russ Housley, and Lars Eggert for the time they devoted to
 69.1705 +   reviewing this document and/or for the comments received.
 69.1706 +
 69.1707 +Authors' Addresses
 69.1708 +
 69.1709 +   Chris Newman (Author/Editor)
 69.1710 +   Sun Microsystems
 69.1711 +   3401 Centrelake Dr., Suite 410
 69.1712 +   Ontario, CA 91761
 69.1713 +   EMail: chris.newman@sun.com
 69.1714 +
 69.1715 +   Alexey Melnikov (Editor)
 69.1716 +   Isode Limited
 69.1717 +   5 Castle Business Village
 69.1718 +   36 Station Road
 69.1719 +   Hampton, Middlesex
 69.1720 +   TW12 2BX, UK
 69.1721 +   EMail: Alexey.Melnikov@isode.com
 69.1722 +   URI:   http://www.melnikov.ca/
 69.1723 +
 69.1724 +
 69.1725 +
 69.1726 +
 69.1727 +
 69.1728 +
 69.1729 +
 69.1730 +
 69.1731 +
 69.1732 +
 69.1733 +
 69.1734 +
 69.1735 +
 69.1736 +
 69.1737 +
 69.1738 +
 69.1739 +
 69.1740 +
 69.1741 +Melnikov & Newman           Standards Track                    [Page 31]
 69.1742 +
 69.1743 +RFC 5092                    IMAP URL Scheme                November 2007
 69.1744 +
 69.1745 +
 69.1746 +Full Copyright Statement
 69.1747 +
 69.1748 +   Copyright (C) The IETF Trust (2007).
 69.1749 +
 69.1750 +   This document is subject to the rights, licenses and restrictions
 69.1751 +   contained in BCP 78, and except as set forth therein, the authors
 69.1752 +   retain all their rights.
 69.1753 +
 69.1754 +   This document and the information contained herein are provided on an
 69.1755 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 69.1756 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
 69.1757 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
 69.1758 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
 69.1759 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 69.1760 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 69.1761 +
 69.1762 +Intellectual Property
 69.1763 +
 69.1764 +   The IETF takes no position regarding the validity or scope of any
 69.1765 +   Intellectual Property Rights or other rights that might be claimed to
 69.1766 +   pertain to the implementation or use of the technology described in
 69.1767 +   this document or the extent to which any license under such rights
 69.1768 +   might or might not be available; nor does it represent that it has
 69.1769 +   made any independent effort to identify any such rights.  Information
 69.1770 +   on the procedures with respect to rights in RFC documents can be
 69.1771 +   found in BCP 78 and BCP 79.
 69.1772 +
 69.1773 +   Copies of IPR disclosures made to the IETF Secretariat and any
 69.1774 +   assurances of licenses to be made available, or the result of an
 69.1775 +   attempt made to obtain a general license or permission for the use of
 69.1776 +   such proprietary rights by implementers or users of this
 69.1777 +   specification can be obtained from the IETF on-line IPR repository at
 69.1778 +   http://www.ietf.org/ipr.
 69.1779 +
 69.1780 +   The IETF invites any interested party to bring to its attention any
 69.1781 +   copyrights, patents or patent applications, or other proprietary
 69.1782 +   rights that may cover technology that may be required to implement
 69.1783 +   this standard.  Please address the information to the IETF at
 69.1784 +   ietf-ipr@ietf.org.
 69.1785 +
 69.1786 +
 69.1787 +
 69.1788 +
 69.1789 +
 69.1790 +
 69.1791 +
 69.1792 +
 69.1793 +
 69.1794 +
 69.1795 +
 69.1796 +
 69.1797 +Melnikov & Newman           Standards Track                    [Page 32]
 69.1798 +
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/docs/rfc/rfc5161.txt	Mon Sep 14 15:17:45 2009 +0900
    70.3 @@ -0,0 +1,395 @@
    70.4 +
    70.5 +
    70.6 +
    70.7 +
    70.8 +
    70.9 +
   70.10 +Network Working Group                                A. Gulbrandsen, Ed.
   70.11 +Request for Comments: 5161                        Oryx Mail Systems GmbH
   70.12 +Category: Standards Track                               A. Melnikov, Ed.
   70.13 +                                                           Isode Limited
   70.14 +                                                              March 2008
   70.15 +
   70.16 +
   70.17 +                       The IMAP ENABLE Extension
   70.18 +
   70.19 +Status of This Memo
   70.20 +
   70.21 +   This document specifies an Internet standards track protocol for the
   70.22 +   Internet community, and requests discussion and suggestions for
   70.23 +   improvements.  Please refer to the current edition of the "Internet
   70.24 +   Official Protocol Standards" (STD 1) for the standardization state
   70.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   70.26 +
   70.27 +Abstract
   70.28 +
   70.29 +   Most IMAP extensions are used by the client when it wants to and the
   70.30 +   server supports it.  However, a few extensions require the server to
   70.31 +   know whether a client supports that extension.  The ENABLE extension
   70.32 +   allows an IMAP client to say which extensions it supports.
   70.33 +
   70.34 +1.  Overview
   70.35 +
   70.36 +   Several IMAP extensions allow the server to return unsolicited
   70.37 +   responses specific to these extensions in certain circumstances.
   70.38 +   However, servers cannot send those unsolicited responses until they
   70.39 +   know that the clients support such extensions and thus won't choke on
   70.40 +   the extension response data.
   70.41 +
   70.42 +   Up until now, extensions have typically stated that a server cannot
   70.43 +   send the unsolicited responses until after the client has used a
   70.44 +   command with the extension data (i.e., at that point the server knows
   70.45 +   the client is aware of the extension).  CONDSTORE ([RFC4551]),
   70.46 +   ANNOTATE ([ANNOTATE]), and some extensions under consideration at the
   70.47 +   moment use various commands to enable server extensions.  For
   70.48 +   example, CONDSTORE uses a SELECT or FETCH parameter, and ANNOTATE
   70.49 +   uses a side effect of FETCH.
   70.50 +
   70.51 +   The ENABLE extension provides an explicit indication from the client
   70.52 +   that it supports particular extensions.  This is done using a new
   70.53 +   ENABLE command.
   70.54 +
   70.55 +   An IMAP server that supports ENABLE advertises this by including the
   70.56 +   word ENABLE in its capability list.
   70.57 +
   70.58 +
   70.59 +
   70.60 +
   70.61 +Gulbrandsen & Melnikov      Standards Track                     [Page 1]
   70.62 +
   70.63 +RFC 5161               The IMAP ENABLE Extension              March 2008
   70.64 +
   70.65 +
   70.66 +   Most IMAP extensions do not require the client to enable the
   70.67 +   extension in any way.
   70.68 +
   70.69 +2.  Conventions Used in This Document
   70.70 +
   70.71 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   70.72 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   70.73 +   document are to be interpreted as described in [RFC2119].
   70.74 +
   70.75 +   Formal syntax is defined by [RFC5234] and [RFC3501].
   70.76 +
   70.77 +   Example lines prefaced by "C:" are sent by the client and ones
   70.78 +   prefaced by "S:" by the server.  The five characters [...] means that
   70.79 +   something has been elided.
   70.80 +
   70.81 +3.  Protocol Changes
   70.82 +
   70.83 +3.1.  The ENABLE Command
   70.84 +
   70.85 +   Arguments: capability names
   70.86 +
   70.87 +   Result:    OK: Relevant capabilities enabled
   70.88 +              BAD: No arguments, or syntax error in an argument
   70.89 +
   70.90 +   The ENABLE command takes a list of capability names, and requests the
   70.91 +   server to enable the named extensions.  Once enabled using ENABLE,
   70.92 +   each extension remains active until the IMAP connection is closed.
   70.93 +   For each argument, the server does the following:
   70.94 +
   70.95 +   - If the argument is not an extension known to the server, the server
   70.96 +     MUST ignore the argument.
   70.97 +
   70.98 +   - If the argument is an extension known to the server, and it is not
   70.99 +     specifically permitted to be enabled using ENABLE, the server MUST
  70.100 +     ignore the argument.  (Note that knowing about an extension doesn't
  70.101 +     necessarily imply supporting that extension.)
  70.102 +
  70.103 +   - If the argument is an extension that is supported by the server and
  70.104 +     that needs to be enabled, the server MUST enable the extension for
  70.105 +     the duration of the connection.  At present, this applies only to
  70.106 +     CONDSTORE ([RFC4551]).  Note that once an extension is enabled,
  70.107 +     there is no way to disable it.
  70.108 +
  70.109 +   If the ENABLE command is successful, the server MUST send an untagged
  70.110 +   ENABLED response (see Section 3.2).
  70.111 +
  70.112 +
  70.113 +
  70.114 +
  70.115 +
  70.116 +
  70.117 +Gulbrandsen & Melnikov      Standards Track                     [Page 2]
  70.118 +
  70.119 +RFC 5161               The IMAP ENABLE Extension              March 2008
  70.120 +
  70.121 +
  70.122 +   Clients SHOULD only include extensions that need to be enabled by the
  70.123 +   server.  At the time of publication, CONDSTORE is the only such
  70.124 +   extension (i.e., ENABLE CONDSTORE is an additional "CONDSTORE
  70.125 +   enabling command" as defined in [RFC4551]).  Future RFCs may add to
  70.126 +   this list.
  70.127 +
  70.128 +   The ENABLE command is only valid in the authenticated state (see
  70.129 +   [RFC3501]), before any mailbox is selected.  Clients MUST NOT issue
  70.130 +   ENABLE once they SELECT/EXAMINE a mailbox; however, server
  70.131 +   implementations don't have to check that no mailbox is selected or
  70.132 +   was previously selected during the duration of a connection.
  70.133 +
  70.134 +   The ENABLE command can be issued multiple times in a session.  It is
  70.135 +   additive; i.e., "ENABLE a b", followed by "ENABLE c" is the same as a
  70.136 +   single command "ENABLE a b c".  When multiple ENABLE commands are
  70.137 +   issued, each corresponding ENABLED response SHOULD only contain
  70.138 +   extensions enabled by the corresponding ENABLE command.
  70.139 +
  70.140 +   There are no limitations on pipelining ENABLE.  For example, it is
  70.141 +   possible to send ENABLE and then immediately SELECT, or a LOGIN
  70.142 +   immediately followed by ENABLE.
  70.143 +
  70.144 +   The server MUST NOT change the CAPABILITY list as a result of
  70.145 +   executing ENABLE; i.e., a CAPABILITY command issued right after an
  70.146 +   ENABLE command MUST list the same capabilities as a CAPABILITY
  70.147 +   command issued before the ENABLE command.  This is demonstrated in
  70.148 +   the following example:
  70.149 +
  70.150 +      C: t1 CAPABILITY
  70.151 +      S: * CAPABILITY IMAP4rev1 ID LITERAL+ ENABLE X-GOOD-IDEA
  70.152 +      S: t1 OK foo
  70.153 +      C: t2 ENABLE CONDSTORE X-GOOD-IDEA
  70.154 +      S: * ENABLED X-GOOD-IDEA
  70.155 +      S: t2 OK foo
  70.156 +      C: t3 CAPABILITY
  70.157 +      S: * CAPABILITY IMAP4rev1 ID LITERAL+ ENABLE X-GOOD-IDEA
  70.158 +      S: t3 OK foo again
  70.159 +
  70.160 +   In the following example, the client enables CONDSTORE:
  70.161 +
  70.162 +      C: a1 ENABLE CONDSTORE
  70.163 +      S: * ENABLED CONDSTORE
  70.164 +      S: a1 OK Conditional Store enabled
  70.165 +
  70.166 +
  70.167 +
  70.168 +
  70.169 +
  70.170 +
  70.171 +
  70.172 +
  70.173 +Gulbrandsen & Melnikov      Standards Track                     [Page 3]
  70.174 +
  70.175 +RFC 5161               The IMAP ENABLE Extension              March 2008
  70.176 +
  70.177 +
  70.178 +3.2.  The ENABLED Response
  70.179 +
  70.180 +   Contents:   capability listing
  70.181 +
  70.182 +   The ENABLED response occurs as a result of an ENABLE command.  The
  70.183 +   capability listing contains a space-separated listing of capability
  70.184 +   names that the server supports and that were successfully enabled.
  70.185 +   The ENABLED response may contain no capabilities, which means that no
  70.186 +   extensions listed by the client were successfully enabled.
  70.187 +
  70.188 +3.3.  Note to Designers of Extensions That May Use the ENABLE Command
  70.189 +
  70.190 +   Designers of IMAP extensions are discouraged from creating extensions
  70.191 +   that require ENABLE unless there is no good alternative design.
  70.192 +   Specifically, extensions that cause potentially incompatible behavior
  70.193 +   changes to deployed server responses (and thus benefit from ENABLE)
  70.194 +   have a higher complexity cost than extensions that do not.
  70.195 +
  70.196 +4.  Formal Syntax
  70.197 +
  70.198 +   The following syntax specification uses the Augmented Backus-Naur
  70.199 +   Form (ABNF) notation as specified in [RFC5234] including the core
  70.200 +   rules in Appendix B.1.  [RFC3501] defines the non-terminals
  70.201 +   "capability" and "command-any".
  70.202 +
  70.203 +   Except as noted otherwise, all alphabetic characters are
  70.204 +   case-insensitive.  The use of upper or lower case characters to
  70.205 +   define token strings is for editorial clarity only.  Implementations
  70.206 +   MUST accept these strings in a case-insensitive fashion.
  70.207 +
  70.208 +      capability    =/ "ENABLE"
  70.209 +
  70.210 +      command-any   =/ "ENABLE" 1*(SP capability)
  70.211 +
  70.212 +      response-data =/ "*" SP enable-data CRLF
  70.213 +
  70.214 +      enable-data   = "ENABLED" *(SP capability)
  70.215 +
  70.216 +5.  Security Considerations
  70.217 +
  70.218 +   It is believed that this extension doesn't add any security
  70.219 +   considerations that are not already present in the base IMAP protocol
  70.220 +   [RFC3501].
  70.221 +
  70.222 +6.  IANA Considerations
  70.223 +
  70.224 +   The IANA has added ENABLE to the IMAP4 Capabilities Registry.
  70.225 +
  70.226 +
  70.227 +
  70.228 +
  70.229 +Gulbrandsen & Melnikov      Standards Track                     [Page 4]
  70.230 +
  70.231 +RFC 5161               The IMAP ENABLE Extension              March 2008
  70.232 +
  70.233 +
  70.234 +7.  Acknowledgments
  70.235 +
  70.236 +   The editors would like to thank Randy Gellens, Chris Newman, Peter
  70.237 +   Coates, Dave Cridland, Mark Crispin, Ned Freed, Dan Karp, Cyrus
  70.238 +   Daboo, Ken Murchison, and Eric Burger for comments and corrections.
  70.239 +   However, this doesn't necessarily mean that they endorse this
  70.240 +   extension, agree with all details, or are responsible for errors
  70.241 +   introduced by the editors.
  70.242 +
  70.243 +8.  Normative References
  70.244 +
  70.245 +   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
  70.246 +              Requirement Levels", BCP 14, RFC 2119, March 1997.
  70.247 +
  70.248 +   [RFC3501]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  70.249 +              4rev1", RFC 3501, March 2003.
  70.250 +
  70.251 +   [RFC5234]  Crocker, D., Ed., and P. Overell, "Augmented BNF for
  70.252 +              Syntax Specifications: ABNF", STD 68, RFC 5234, January
  70.253 +              2008.
  70.254 +
  70.255 +   [RFC4551]  Melnikov, A. and S. Hole, "IMAP Extension for Conditional
  70.256 +              STORE Operation or Quick Flag Changes Resynchronization",
  70.257 +              RFC 4551, June 2006.
  70.258 +
  70.259 +9.  Informative References
  70.260 +
  70.261 +   [ANNOTATE] Daboo, C. and R. Gellens, "IMAP ANNOTATE Extension", Work
  70.262 +              in Progress, August 2006.
  70.263 +
  70.264 +
  70.265 +
  70.266 +
  70.267 +
  70.268 +
  70.269 +
  70.270 +
  70.271 +
  70.272 +
  70.273 +
  70.274 +
  70.275 +
  70.276 +
  70.277 +
  70.278 +
  70.279 +
  70.280 +
  70.281 +
  70.282 +
  70.283 +
  70.284 +
  70.285 +Gulbrandsen & Melnikov      Standards Track                     [Page 5]
  70.286 +
  70.287 +RFC 5161               The IMAP ENABLE Extension              March 2008
  70.288 +
  70.289 +
  70.290 +Editors' Addresses
  70.291 +
  70.292 +   Arnt Gulbrandsen
  70.293 +   Oryx Mail Systems GmbH
  70.294 +   Schweppermannstr. 8
  70.295 +   D-81671 Muenchen
  70.296 +   Germany
  70.297 +
  70.298 +   Fax: +49 89 4502 9758
  70.299 +   EMail: arnt@oryx.com
  70.300 +
  70.301 +
  70.302 +   Alexey Melnikov
  70.303 +   Isode Ltd
  70.304 +   5 Castle Business Village
  70.305 +   36 Station Road
  70.306 +   Hampton, Middlesex  TW12 2BX
  70.307 +   UK
  70.308 +
  70.309 +   EMail: Alexey.Melnikov@isode.com
  70.310 +
  70.311 +
  70.312 +
  70.313 +
  70.314 +
  70.315 +
  70.316 +
  70.317 +
  70.318 +
  70.319 +
  70.320 +
  70.321 +
  70.322 +
  70.323 +
  70.324 +
  70.325 +
  70.326 +
  70.327 +
  70.328 +
  70.329 +
  70.330 +
  70.331 +
  70.332 +
  70.333 +
  70.334 +
  70.335 +
  70.336 +
  70.337 +
  70.338 +
  70.339 +
  70.340 +
  70.341 +Gulbrandsen & Melnikov      Standards Track                     [Page 6]
  70.342 +
  70.343 +RFC 5161               The IMAP ENABLE Extension              March 2008
  70.344 +
  70.345 +
  70.346 +Full Copyright Statement
  70.347 +
  70.348 +   Copyright (C) The IETF Trust (2008).
  70.349 +
  70.350 +   This document is subject to the rights, licenses and restrictions
  70.351 +   contained in BCP 78, and except as set forth therein, the authors
  70.352 +   retain all their rights.
  70.353 +
  70.354 +   This document and the information contained herein are provided on an
  70.355 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  70.356 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  70.357 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  70.358 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  70.359 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  70.360 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  70.361 +
  70.362 +Intellectual Property
  70.363 +
  70.364 +   The IETF takes no position regarding the validity or scope of any
  70.365 +   Intellectual Property Rights or other rights that might be claimed to
  70.366 +   pertain to the implementation or use of the technology described in
  70.367 +   this document or the extent to which any license under such rights
  70.368 +   might or might not be available; nor does it represent that it has
  70.369 +   made any independent effort to identify any such rights.  Information
  70.370 +   on the procedures with respect to rights in RFC documents can be
  70.371 +   found in BCP 78 and BCP 79.
  70.372 +
  70.373 +   Copies of IPR disclosures made to the IETF Secretariat and any
  70.374 +   assurances of licenses to be made available, or the result of an
  70.375 +   attempt made to obtain a general license or permission for the use of
  70.376 +   such proprietary rights by implementers or users of this
  70.377 +   specification can be obtained from the IETF on-line IPR repository at
  70.378 +   http://www.ietf.org/ipr.
  70.379 +
  70.380 +   The IETF invites any interested party to bring to its attention any
  70.381 +   copyrights, patents or patent applications, or other proprietary
  70.382 +   rights that may cover technology that may be required to implement
  70.383 +   this standard.  Please address the information to the IETF at
  70.384 +   ietf-ipr@ietf.org.
  70.385 +
  70.386 +
  70.387 +
  70.388 +
  70.389 +
  70.390 +
  70.391 +
  70.392 +
  70.393 +
  70.394 +
  70.395 +
  70.396 +
  70.397 +Gulbrandsen & Melnikov      Standards Track                     [Page 7]
  70.398 +
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/docs/rfc/rfc5162.txt	Mon Sep 14 15:17:45 2009 +0900
    71.3 @@ -0,0 +1,1291 @@
    71.4 +
    71.5 +
    71.6 +
    71.7 +
    71.8 +
    71.9 +
   71.10 +Network Working Group                                        A. Melnikov
   71.11 +Request for Comments: 5162                                   D. Cridland
   71.12 +Category: Standards Track                                      Isode Ltd
   71.13 +                                                               C. Wilson
   71.14 +                                                                   Nokia
   71.15 +                                                              March 2008
   71.16 +
   71.17 +
   71.18 +          IMAP4 Extensions for Quick Mailbox Resynchronization
   71.19 +
   71.20 +Status of This Memo
   71.21 +
   71.22 +   This document specifies an Internet standards track protocol for the
   71.23 +   Internet community, and requests discussion and suggestions for
   71.24 +   improvements.  Please refer to the current edition of the "Internet
   71.25 +   Official Protocol Standards" (STD 1) for the standardization state
   71.26 +   and status of this protocol.  Distribution of this memo is unlimited.
   71.27 +
   71.28 +Abstract
   71.29 +
   71.30 +   This document defines an IMAP4 extension, which gives an IMAP client
   71.31 +   the ability to quickly resynchronize any previously opened mailbox as
   71.32 +   part of the SELECT command, without the need for server-side state or
   71.33 +   additional client round-trips.  This extension also introduces a new
   71.34 +   response that allows for a more compact representation of a list of
   71.35 +   expunged messages (and always includes the Unique Identifiers (UIDs)
   71.36 +   expunged).
   71.37 +
   71.38 +
   71.39 +
   71.40 +
   71.41 +
   71.42 +
   71.43 +
   71.44 +
   71.45 +
   71.46 +
   71.47 +
   71.48 +
   71.49 +
   71.50 +
   71.51 +
   71.52 +
   71.53 +
   71.54 +
   71.55 +
   71.56 +
   71.57 +
   71.58 +
   71.59 +
   71.60 +
   71.61 +Melnikov, et al.            Standards Track                     [Page 1]
   71.62 +
   71.63 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
   71.64 +
   71.65 +
   71.66 +Table of Contents
   71.67 +
   71.68 +   1.  Introduction and Overview  . . . . . . . . . . . . . . . . . .  2
   71.69 +   2.  Requirements Notation  . . . . . . . . . . . . . . . . . . . .  4
   71.70 +   3.  IMAP Protocol Changes  . . . . . . . . . . . . . . . . . . . .  4
   71.71 +     3.1.  QRESYNC Parameter to SELECT/EXAMINE  . . . . . . . . . . .  4
   71.72 +     3.2.  VANISHED UID FETCH Modifier  . . . . . . . . . . . . . . .  8
   71.73 +     3.3.  EXPUNGE Command  . . . . . . . . . . . . . . . . . . . . . 10
   71.74 +     3.4.  CLOSE Command  . . . . . . . . . . . . . . . . . . . . . . 11
   71.75 +     3.5.  UID EXPUNGE Command  . . . . . . . . . . . . . . . . . . . 11
   71.76 +     3.6.  VANISHED Response  . . . . . . . . . . . . . . . . . . . . 12
   71.77 +     3.7.  CLOSED Response Code . . . . . . . . . . . . . . . . . . . 15
   71.78 +   4.  Server Implementation Considerations . . . . . . . . . . . . . 15
   71.79 +     4.1.  Server Implementations That Don't Store Extra State  . . . 15
   71.80 +     4.2.  Server Implementations Storing Minimal State . . . . . . . 16
   71.81 +     4.3.  Additional State Required on the Server  . . . . . . . . . 16
   71.82 +   5.  Updated Synchronization Sequence . . . . . . . . . . . . . . . 17
   71.83 +   6.  Formal Syntax  . . . . . . . . . . . . . . . . . . . . . . . . 19
   71.84 +   7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 20
   71.85 +   8.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 21
   71.86 +   9.  Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . . 21
   71.87 +   10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 21
   71.88 +     10.1. Normative References . . . . . . . . . . . . . . . . . . . 21
   71.89 +     10.2. Informative References . . . . . . . . . . . . . . . . . . 22
   71.90 +
   71.91 +1.  Introduction and Overview
   71.92 +
   71.93 +   The [CONDSTORE] extension gives a disconnected client the ability to
   71.94 +   quickly resynchronize IMAP flag changes for previously seen messages.
   71.95 +   This can be done using the CHANGEDSINCE FETCH modifier once a mailbox
   71.96 +   is opened.  In order for the client to discover which messages have
   71.97 +   been expunged, the client still has to issue a UID FETCH or a UID
   71.98 +   SEARCH command.  This document defines an extension to [CONDSTORE]
   71.99 +   that allows a reconnecting client to perform full resynchronization,
  71.100 +   including discovery of expunged messages, in a single round-trip.
  71.101 +   This extension also introduces a new response, VANISHED, that allows
  71.102 +   for a more compact representation of a list of expunged messages.
  71.103 +
  71.104 +   This extension can be useful for mobile clients that can experience
  71.105 +   frequent disconnects caused by environmental factors (battery life,
  71.106 +   signal strength, etc.).  Such clients need a way to quickly reconnect
  71.107 +   to the IMAP server, while minimizing delay experienced by the user as
  71.108 +   well as the amount of traffic (and hence the expense) generated by
  71.109 +   resynchronization.
  71.110 +
  71.111 +
  71.112 +
  71.113 +
  71.114 +
  71.115 +
  71.116 +
  71.117 +Melnikov, et al.            Standards Track                     [Page 2]
  71.118 +
  71.119 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.120 +
  71.121 +
  71.122 +   By extending the SELECT command to perform the additional
  71.123 +   resynchronization, this also allows clients to reduce concurrent
  71.124 +   connections to the IMAP server held purely for the sake of avoiding
  71.125 +   the resynchronization.
  71.126 +
  71.127 +   The quick resync IMAP extension is present if an IMAP4 server returns
  71.128 +   "QRESYNC" as one of the supported capabilities to the CAPABILITY
  71.129 +   command.
  71.130 +
  71.131 +   Servers supporting this extension MUST implement and advertise
  71.132 +   support for the [ENABLE] IMAP extension.  Also, the presence of the
  71.133 +   "QRESYNC" capability implies support for the [CONDSTORE] IMAP
  71.134 +   extension even if the CONDSTORE capability isn't advertised.  A
  71.135 +   server compliant with this specification is REQUIREd to support
  71.136 +   "ENABLE QRESYNC" and "ENABLE QRESYNC CONDSTORE" (which are "CONDSTORE
  71.137 +   enabling commands", as defined in [CONDSTORE], and have identical
  71.138 +   results), but there is no requirement for a compliant server to
  71.139 +   support "ENABLE CONDSTORE" by itself.  The "ENABLE QRESYNC"/"ENABLE
  71.140 +   QRESYNC CONDSTORE" command also tells the server that it SHOULD start
  71.141 +   sending VANISHED responses (see Section 3.6) instead of EXPUNGE
  71.142 +   responses.  This change remains in effect until the connection is
  71.143 +   closed.
  71.144 +
  71.145 +   For compatibility with clients that only support the [CONDSTORE] IMAP
  71.146 +   extension, servers SHOULD advertise CONDSTORE in the CAPABILITY
  71.147 +   response as well.
  71.148 +
  71.149 +   A client making use of this extension MUST issue "ENABLE QRESYNC"
  71.150 +   once it is authenticated.  A server MUST respond with a tagged BAD
  71.151 +   response if the QRESYNC parameter to the SELECT/EXAMINE command or
  71.152 +   the VANISHED UID FETCH modifier is specified and the client hasn't
  71.153 +   issued "ENABLE QRESYNC" in the current connection.
  71.154 +
  71.155 +   This document puts additional requirements on a server implementing
  71.156 +   the [CONDSTORE] extension.  Each mailbox that supports persistent
  71.157 +   storage of mod-sequences, i.e., for which the server has sent a
  71.158 +   HIGHESTMODSEQ untagged OK response code on a successful SELECT/
  71.159 +   EXAMINE, MUST increment the per-mailbox mod-sequence when one or more
  71.160 +   messages are expunged due to EXPUNGE, UID EXPUNGE or CLOSE; the
  71.161 +   server MUST associate the incremented mod-sequence with the UIDs of
  71.162 +   the expunged messages.
  71.163 +
  71.164 +   A client that supports CONDSTORE but not this extension might
  71.165 +   resynchronize a mailbox and discover that its HIGHESTMODSEQ has
  71.166 +   increased from the value cached by the client.  If the increase is
  71.167 +   only due to messages having been expunged since the client last
  71.168 +   synchronized, the client is likely to send a FETCH ...  CHANGEDSINCE
  71.169 +   command that returns no data.  Thus, a client that supports CONDSTORE
  71.170 +
  71.171 +
  71.172 +
  71.173 +Melnikov, et al.            Standards Track                     [Page 3]
  71.174 +
  71.175 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.176 +
  71.177 +
  71.178 +   but not this extension might incur a penalty of an unneeded round-
  71.179 +   trip when resynchronizing some mailboxes (those that have had
  71.180 +   messages expunged but no flag changes since the last
  71.181 +   synchronization).
  71.182 +
  71.183 +   This extra round-trip is only incurred by clients that support
  71.184 +   CONDSTORE but not this extension, and only when a mailbox has had
  71.185 +   messages expunged but no flag changes to non-expunged messages.
  71.186 +   Since CONDSTORE is a relatively new extension, it is thought likely
  71.187 +   that clients that support it will also support this extension.
  71.188 +
  71.189 +2.  Requirements Notation
  71.190 +
  71.191 +   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  71.192 +   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  71.193 +   document are to be interpreted as described in [RFC2119].
  71.194 +
  71.195 +   In examples, "C:" and "S:" indicate lines sent by the client and
  71.196 +   server respectively.  If a single "C:" or "S:" label applies to
  71.197 +   multiple lines, then the line breaks between those lines are for
  71.198 +   editorial clarity only and are not part of the actual protocol
  71.199 +   exchange.  The five characters [...] means that something has been
  71.200 +   elided.
  71.201 +
  71.202 +   Understanding of the IMAP message sequence numbers and UIDs and the
  71.203 +   EXPUNGE response [RFC3501] is essential when reading this document.
  71.204 +
  71.205 +3.  IMAP Protocol Changes
  71.206 +
  71.207 +3.1.  QRESYNC Parameter to SELECT/EXAMINE
  71.208 +
  71.209 +   The Quick Resynchronization parameter to SELECT/EXAMINE commands has
  71.210 +   four arguments:
  71.211 +
  71.212 +   o  the last known UIDVALIDITY,
  71.213 +
  71.214 +   o  the last known modification sequence,
  71.215 +
  71.216 +   o  the optional set of known UIDs, and
  71.217 +
  71.218 +   o  an optional parenthesized list of known sequence ranges and their
  71.219 +      corresponding UIDs.
  71.220 +
  71.221 +   A server MUST respond with a tagged BAD response if the Quick
  71.222 +   Resynchronization parameter to SELECT/EXAMINE command is specified
  71.223 +   and the client hasn't issued "ENABLE QRESYNC" in the current
  71.224 +   connection.
  71.225 +
  71.226 +
  71.227 +
  71.228 +
  71.229 +Melnikov, et al.            Standards Track                     [Page 4]
  71.230 +
  71.231 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.232 +
  71.233 +
  71.234 +   Before opening the specified mailbox, the server verifies all
  71.235 +   arguments for syntactic validity.  If any parameter is not
  71.236 +   syntactically valid, the server returns the tagged BAD response, and
  71.237 +   the mailbox remains unselected.  Once the check is done, the server
  71.238 +   opens the mailbox as if no SELECT/EXAMINE parameters are specified
  71.239 +   (this is subject to processing of other parameters as defined in
  71.240 +   other extensions).  In particular this means that the server MUST
  71.241 +   send all untagged responses as specified in Sections 6.3.1 and 6.3.2
  71.242 +   of [RFC3501].
  71.243 +
  71.244 +   After that, the server checks the UIDVALIDITY value provided by the
  71.245 +   client.  If the provided UIDVALIDITY doesn't match the UIDVALIDITY
  71.246 +   for the mailbox being opened, then the server MUST ignore the
  71.247 +   remaining parameters and behave as if no dynamic message data
  71.248 +   changed.  The client can discover this situation by comparing the
  71.249 +   UIDVALIDITY value returned by the server.  This behavior allows the
  71.250 +   client not to synchronize the mailbox or decide on the best
  71.251 +   synchronization strategy.
  71.252 +
  71.253 +   Example: Attempting to resynchronize INBOX, but the provided
  71.254 +            UIDVALIDITY parameter doesn't match the current UIDVALIDITY
  71.255 +            value.
  71.256 +
  71.257 +   C: A02 SELECT INBOX (QRESYNC (67890007 20050715194045000
  71.258 +            41,43:211,214:541))
  71.259 +            S: * 464 EXISTS
  71.260 +            S: * 3 RECENT
  71.261 +            S: * OK [UIDVALIDITY 3857529045] UIDVALIDITY
  71.262 +            S: * OK [UIDNEXT 550] Predicted next UID
  71.263 +            S: * OK [HIGHESTMODSEQ 90060128194045007]
  71.264 +            S: * OK [UNSEEN 12] Message 12 is first unseen
  71.265 +            S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
  71.266 +            S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
  71.267 +            \Deleted \Seen \*)] Permanent flags
  71.268 +            S: A02 OK [READ-WRITE] Sorry, UIDVALIDITY mismatch
  71.269 +
  71.270 +   Modification Sequence and UID Parameters:
  71.271 +
  71.272 +   A server that doesn't support the persistent storage of mod-sequences
  71.273 +   for the mailbox MUST send the OK untagged response including the
  71.274 +   NOMODSEQ response code with every successful SELECT or EXAMINE
  71.275 +   command, as described in [CONDSTORE].  Such a server doesn't need to
  71.276 +   remember mod-sequences for expunged messages in the mailbox.  It MUST
  71.277 +   ignore the remaining parameters and behave as if no dynamic message
  71.278 +   data changed.
  71.279 +
  71.280 +   If the provided UIDVALIDITY matches that of the selected mailbox, the
  71.281 +   server then checks the last known modification sequence.
  71.282 +
  71.283 +
  71.284 +
  71.285 +Melnikov, et al.            Standards Track                     [Page 5]
  71.286 +
  71.287 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.288 +
  71.289 +
  71.290 +   The server sends the client any pending flag changes (using FETCH
  71.291 +   responses that MUST contain UIDs) and expunges those that have
  71.292 +   occurred in this mailbox since the provided modification sequence.
  71.293 +
  71.294 +   If the list of known UIDs was also provided, the server should only
  71.295 +   report flag changes and expunges for the specified messages.  If the
  71.296 +   client did not provide the list of UIDs, the server acts as if the
  71.297 +   client has specified "1:<maxuid>", where <maxuid> is the mailbox's
  71.298 +   UIDNEXT value minus 1.  If the mailbox is empty and never had any
  71.299 +   messages in it, then lack of the list of UIDs is interpreted as an
  71.300 +   empty set of UIDs.
  71.301 +
  71.302 +   Thus, the client can process just these pending events and need not
  71.303 +   perform a full resynchronization.  Without the message sequence
  71.304 +   number matching information, the result of this step is semantically
  71.305 +   equivalent to the client issuing:
  71.306 +   tag1 UID FETCH "known-uids" (FLAGS) (CHANGEDSINCE
  71.307 +   "mod-sequence-value" VANISHED)
  71.308 +
  71.309 +   Example:
  71.310 +      C: A03 SELECT INBOX (QRESYNC (67890007
  71.311 +         90060115194045000 41,43:211,214:541))
  71.312 +      S: * OK [CLOSED]
  71.313 +      S: * 314 EXISTS
  71.314 +      S: * 15 RECENT
  71.315 +      S: * OK [UIDVALIDITY 67890007] UIDVALIDITY
  71.316 +      S: * OK [UIDNEXT 567] Predicted next UID
  71.317 +      S: * OK [HIGHESTMODSEQ 90060115205545359]
  71.318 +      S: * OK [UNSEEN 7] There are some unseen messages in the mailbox
  71.319 +      S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
  71.320 +      S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
  71.321 +         \Deleted \Seen \*)] Permanent flags
  71.322 +      S: * VANISHED (EARLIER) 41,43:116,118,120:211,214:540
  71.323 +      S: * 49 FETCH (UID 117 FLAGS (\Seen \Answered) MODSEQ
  71.324 +         (90060115194045001))
  71.325 +      S: * 50 FETCH (UID 119 FLAGS (\Draft $MDNSent) MODSEQ
  71.326 +         (90060115194045308))
  71.327 +      S: ...
  71.328 +      S: * 100 FETCH (UID 541 FLAGS (\Seen $Forwarded) MODSEQ
  71.329 +         (90060115194045001))
  71.330 +      S: A03 OK [READ-WRITE] mailbox selected
  71.331 +
  71.332 +   Message sequence match data:
  71.333 +
  71.334 +   A client MAY provide a parenthesized list of a message sequence set
  71.335 +   and the corresponding UID sets.  Both MUST be provided in ascending
  71.336 +   order.  The server uses this data to restrict the range for which it
  71.337 +   provides expunged message information.
  71.338 +
  71.339 +
  71.340 +
  71.341 +Melnikov, et al.            Standards Track                     [Page 6]
  71.342 +
  71.343 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.344 +
  71.345 +
  71.346 +   Conceptually, the client provides a small sample of sequence numbers
  71.347 +   for which it knows the corresponding UIDs.  The server then compares
  71.348 +   each sequence number and UID pair the client provides with the
  71.349 +   current state of the mailbox.  If a pair matches, then the client
  71.350 +   knows of any expunges up to, and including, the message, and thus
  71.351 +   will not include that range in the VANISHED response, even if the
  71.352 +   "mod-sequence-value" provided by the client is too old for the server
  71.353 +   to have data of when those messages were expunged.
  71.354 +
  71.355 +   Thus, if the Nth message number in the first set in the list is 4,
  71.356 +   and the Nth UID in the second set in the list is 8, and the mailbox's
  71.357 +   fourth message has UID 8, then no UIDs equal to or less than 8 are
  71.358 +   present in the VANISHED response.  If the (N+1)th message number is
  71.359 +   12, and the (N+1)th UID is 24, and the (N+1)th message in the mailbox
  71.360 +   has UID 25, then the lowest UID included in the VANISHED response
  71.361 +   would be 9.
  71.362 +
  71.363 +   In the following two examples, the server is unable to remember
  71.364 +   expunges at all, and only UIDs with messages divisible by three are
  71.365 +   present in the mailbox.  In the first example, the client does not
  71.366 +   use the fourth parameter; in the second, it provides it.  This
  71.367 +   example is somewhat extreme, but shows that judicious usage of the
  71.368 +   sequence match data can save a substantial amount of bandwidth.
  71.369 +
  71.370 +   Example:
  71.371 +      C: A04 SELECT INBOX (QRESYNC (67890007
  71.372 +         90060115194045000 1:29997))
  71.373 +      S: * 10003 EXISTS
  71.374 +      S: * 5 RECENT
  71.375 +      S: * OK [UIDVALIDITY 67890007] UIDVALIDITY
  71.376 +      S: * OK [UIDNEXT 30013] Predicted next UID
  71.377 +      S: * OK [HIGHESTMODSEQ 90060115205545359]
  71.378 +      S: * OK [UNSEEN 7] There are some unseen messages in the mailbox
  71.379 +      S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
  71.380 +      S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
  71.381 +         \Deleted \Seen \*)] Permanent flags
  71.382 +      S: * VANISHED (EARLIER) 1:2,4:5,7:8,10:11,13:14 [...]
  71.383 +         29998:29999,30001:30002,30004:30005,30007:30008
  71.384 +      S: * 9889 FETCH (UID 29667 FLAGS (\Seen \Answered) MODSEQ
  71.385 +         (90060115194045027))
  71.386 +      S: * 9890 FETCH (UID 29670 FLAGS (\Draft $MDNSent) MODSEQ
  71.387 +         (90060115194045028))
  71.388 +      S: ...
  71.389 +      S: * 9999 FETCH (UID 29997 FLAGS (\Seen $Forwarded) MODSEQ
  71.390 +         (90060115194045031))
  71.391 +      S: A04 OK [READ-WRITE] mailbox selected
  71.392 +
  71.393 +
  71.394 +
  71.395 +
  71.396 +
  71.397 +Melnikov, et al.            Standards Track                     [Page 7]
  71.398 +
  71.399 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.400 +
  71.401 +
  71.402 +   Example:
  71.403 +      C: B04 SELECT INBOX (QRESYNC (67890007
  71.404 +         90060115194045000 1:29997 (5000,7500,9000,9990:9999 15000,
  71.405 +         22500,27000,29970,29973,29976,29979,29982,29985,29988,29991,
  71.406 +         29994,29997)))
  71.407 +      S: * 10003 EXISTS
  71.408 +      S: * 5 RECENT
  71.409 +      S: * OK [UIDVALIDITY 67890007] UIDVALIDITY
  71.410 +      S: * OK [UIDNEXT 30013] Predicted next UID
  71.411 +      S: * OK [HIGHESTMODSEQ 90060115205545359]
  71.412 +      S: * OK [UNSEEN 7] There are some unseen messages in the mailbox
  71.413 +      S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
  71.414 +      S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
  71.415 +         \Deleted \Seen \*)] Permanent flags
  71.416 +      S: * VANISHED (EARLIER) 29998:29999,30001:30002,30004:30005,30007:
  71.417 +         30008
  71.418 +      S: * 9889 FETCH (UID 29667 FLAGS (\Seen \Answered) MODSEQ
  71.419 +         (90060115194045027))
  71.420 +      S: * 9890 FETCH (UID 29670 FLAGS (\Draft $MDNSent) MODSEQ
  71.421 +         (90060115194045028))
  71.422 +      S: ...
  71.423 +      S: * 9999 FETCH (UID 29997 FLAGS (\Seen $Forwarded) MODSEQ
  71.424 +         (90060115194045031))
  71.425 +      S: B04 OK [READ-WRITE] mailbox selected
  71.426 +
  71.427 +3.2.  VANISHED UID FETCH Modifier
  71.428 +
  71.429 +   [IMAPABNF] has extended the syntax of the FETCH and UID FETCH
  71.430 +   commands to include an optional FETCH modifier.  This document
  71.431 +   defines a new UID FETCH modifier: VANISHED.
  71.432 +
  71.433 +   Note, that the VANISHED UID FETCH modifier is NOT allowed with a
  71.434 +   FETCH command.  The server MUST return a tagged BAD response if this
  71.435 +   response is specified as a modifier to the FETCH command.
  71.436 +
  71.437 +   A server MUST respond with a tagged BAD response if the VANISHED UID
  71.438 +   FETCH modifier is specified and the client hasn't issued "ENABLE
  71.439 +   QRESYNC" in the current connection.
  71.440 +
  71.441 +   The VANISHED UID FETCH modifier MUST only be specified together with
  71.442 +   the CHANGEDSINCE UID FETCH modifier.
  71.443 +
  71.444 +   The VANISHED UID FETCH modifier instructs the server to report those
  71.445 +   messages from the UID set parameter that have been expunged and whose
  71.446 +   associated mod-sequence is larger than the specified mod-sequence.
  71.447 +   That is, the client requests to be informed of messages from the
  71.448 +   specified set that were expunged since the specified mod-sequence.
  71.449 +   Note that the mod-sequence(s) associated with these messages were
  71.450 +
  71.451 +
  71.452 +
  71.453 +Melnikov, et al.            Standards Track                     [Page 8]
  71.454 +
  71.455 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.456 +
  71.457 +
  71.458 +   updated when the messages were expunged (as described above).  The
  71.459 +   expunged messages are reported using the VANISHED response as
  71.460 +   described in Section 3.6, which MUST contain the EARLIER tag.  Any
  71.461 +   VANISHED (EARLIER) responses MUST be returned before any FETCH
  71.462 +   responses, as otherwise the client might get confused about how
  71.463 +   message numbers map to UIDs.
  71.464 +
  71.465 +   Note: A server that receives a mod-sequence smaller than <minmodseq>,
  71.466 +   where <minmodseq> is the value of the smallest expunged mod-sequence
  71.467 +   it remembers minus one, MUST behave as if it was requested to report
  71.468 +   all expunged messages from the provided UID set parameter.
  71.469 +
  71.470 +   Example 1: Without the VANISHED UID FETCH modifier, a CONDSTORE-aware
  71.471 +   client [CONDSTORE] needs to issue separate commands to learn of flag
  71.472 +   changes and expunged messages since the last synchronization:
  71.473 +
  71.474 +   C: s100 UID FETCH 300:500 (FLAGS) (CHANGEDSINCE 12345)
  71.475 +   S: * 1 FETCH (UID 404 MODSEQ (65402) FLAGS (\Seen))
  71.476 +   S: * 2 FETCH (UID 406 MODSEQ (75403) FLAGS (\Deleted))
  71.477 +   S: * 4 FETCH (UID 408 MODSEQ (29738) FLAGS ($NoJunk
  71.478 +       $AutoJunk $MDNSent))
  71.479 +   S: s100 OK FETCH completed
  71.480 +   C: s101 UID SEARCH 300:500
  71.481 +   S: * SEARCH 404 406 407 408 410 412
  71.482 +   S: s101 OK search completed
  71.483 +
  71.484 +   Where 300 and 500 are the lowest and highest UIDs from client's
  71.485 +   cache.  The second SEARCH response tells the client that the messages
  71.486 +   with UIDs 407, 410, and 412 are still present, but their flags
  71.487 +   haven't changed since the specified modification sequence.
  71.488 +
  71.489 +   Using the VANISHED UID FETCH modifier, it is sufficient to issue only
  71.490 +   a single command:
  71.491 +
  71.492 +   C: s100 UID FETCH 300:500 (FLAGS) (CHANGEDSINCE 12345
  71.493 +       VANISHED)
  71.494 +   S: * VANISHED (EARLIER) 300:310,405,411
  71.495 +   S: * 1 FETCH (UID 404 MODSEQ (65402) FLAGS (\Seen))
  71.496 +   S: * 2 FETCH (UID 406 MODSEQ (75403) FLAGS (\Deleted))
  71.497 +   S: * 4 FETCH (UID 408 MODSEQ (29738) FLAGS ($NoJunk
  71.498 +       $AutoJunk $MDNSent))
  71.499 +   S: s100 OK FETCH completed
  71.500 +
  71.501 +
  71.502 +
  71.503 +
  71.504 +
  71.505 +
  71.506 +
  71.507 +
  71.508 +
  71.509 +Melnikov, et al.            Standards Track                     [Page 9]
  71.510 +
  71.511 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.512 +
  71.513 +
  71.514 +3.3.  EXPUNGE Command
  71.515 +
  71.516 +   Arguments: none
  71.517 +
  71.518 +   Responses: untagged responses: EXPUNGE or VANISHED
  71.519 +
  71.520 +   Result: OK - expunge completed
  71.521 +           NO - expunge failure: can't expunge (e.g., permission denied)
  71.522 +           BAD - command unknown or arguments invalid
  71.523 +
  71.524 +   This section updates the definition of the EXPUNGE command described
  71.525 +   in Section 6.4.3 of [RFC3501].
  71.526 +
  71.527 +   The EXPUNGE command permanently removes all messages that have the
  71.528 +   \Deleted flag set from the currently selected mailbox.  Before
  71.529 +   returning an OK to the client, those messages that are removed are
  71.530 +   reported using a VANISHED response or EXPUNGE responses.
  71.531 +
  71.532 +   If the server is capable of storing modification sequences for the
  71.533 +   selected mailbox, it MUST increment the per-mailbox mod-sequence if
  71.534 +   at least one message was permanently removed due to the execution of
  71.535 +   the EXPUNGE command.  For each permanently removed message, the
  71.536 +   server MUST remember the incremented mod-sequence and corresponding
  71.537 +   UID.  If at least one message got expunged, the server MUST send the
  71.538 +   updated per-mailbox modification sequence using the HIGHESTMODSEQ
  71.539 +   response code (defined in [CONDSTORE]) in the tagged OK response.
  71.540 +
  71.541 +      Example:    C: A202 EXPUNGE
  71.542 +                  S: * 3 EXPUNGE
  71.543 +                  S: * 3 EXPUNGE
  71.544 +                  S: * 5 EXPUNGE
  71.545 +                  S: * 8 EXPUNGE
  71.546 +                  S: A202 OK [HIGHESTMODSEQ 20010715194045319] expunged
  71.547 +
  71.548 +   Note: In this example, messages 3, 4, 7, and 11 had the \Deleted flag
  71.549 +   set.  The first "* 3 EXPUNGE" reports message # 3 as expunged.  The
  71.550 +   second "* 3 EXPUNGE" reports message # 4 as expunged (the message
  71.551 +   number got decremented due to the previous EXPUNGE response).  See
  71.552 +   the description of the EXPUNGE response in [RFC3501] for further
  71.553 +   explanation.
  71.554 +
  71.555 +   Note that if the server chooses to always send VANISHED responses
  71.556 +   instead of EXPUNGE responses, the previous example might look like
  71.557 +   this:
  71.558 +
  71.559 +      Example:    C: B202 EXPUNGE
  71.560 +                  S: * VANISHED 405,407,410,425
  71.561 +                  S: B202 OK [HIGHESTMODSEQ 20010715194045319] expunged
  71.562 +
  71.563 +
  71.564 +
  71.565 +Melnikov, et al.            Standards Track                    [Page 10]
  71.566 +
  71.567 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.568 +
  71.569 +
  71.570 +   Here messages with message numbers 3, 4, 7, and 11 have respective
  71.571 +   UIDs 405, 407, 410, and 425.
  71.572 +
  71.573 +3.4.  CLOSE Command
  71.574 +
  71.575 +   Arguments: none
  71.576 +
  71.577 +   Responses: no specific responses for this command
  71.578 +
  71.579 +   Result: OK - close completed, now in authenticated state
  71.580 +           BAD - command unknown or arguments invalid
  71.581 +
  71.582 +   This section updates the definition of the CLOSE command described in
  71.583 +   Section 6.4.2 of [RFC3501].
  71.584 +
  71.585 +   The CLOSE command permanently removes all messages that have the
  71.586 +   \Deleted flag set from the currently selected mailbox, and returns to
  71.587 +   the authenticated state from the selected state.  No untagged EXPUNGE
  71.588 +   (or VANISHED) responses are sent.
  71.589 +
  71.590 +   If the server is capable of storing modification sequences for the
  71.591 +   selected mailbox, it MUST increment the per-mailbox mod-sequence if
  71.592 +   at least one message was permanently removed due to the execution of
  71.593 +   the CLOSE command.  For each permanently removed message, the server
  71.594 +   MUST remember the incremented mod-sequence and corresponding UID.  If
  71.595 +   at least one message got expunged, the server MUST send the updated
  71.596 +   per-mailbox modification sequence using the HIGHESTMODSEQ response
  71.597 +   code (defined in [CONDSTORE]) in the tagged OK response.
  71.598 +
  71.599 +      Example:    C: A202 CLOSE
  71.600 +                  S: A202 OK [HIGHESTMODSEQ 20010715194045319] done
  71.601 +
  71.602 +3.5.  UID EXPUNGE Command
  71.603 +
  71.604 +   Arguments: message set
  71.605 +
  71.606 +   Responses: untagged responses: EXPUNGE or VANISHED
  71.607 +
  71.608 +   Result: OK - expunge completed
  71.609 +           NO - expunge failure: can't expunge (e.g., permission denied)
  71.610 +           BAD - command unknown or arguments invalid
  71.611 +
  71.612 +   This section updates the definition of the UID EXPUNGE command
  71.613 +   described in Section 2.1 of [UIDPLUS].  Servers that implement both
  71.614 +   [UIDPLUS] and QRESYNC extensions must implement UID EXPUNGE as
  71.615 +   described in this section.
  71.616 +
  71.617 +
  71.618 +
  71.619 +
  71.620 +
  71.621 +Melnikov, et al.            Standards Track                    [Page 11]
  71.622 +
  71.623 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.624 +
  71.625 +
  71.626 +   The UID EXPUNGE command permanently removes from the currently
  71.627 +   selected mailbox all messages that both have the \Deleted flag set
  71.628 +   and have a UID that is included in the specified message set.  If a
  71.629 +   message either does not have the \Deleted flag set or has a UID that
  71.630 +   is not included in the specified message set, it is not affected.
  71.631 +
  71.632 +   This command is particularly useful for disconnected mode clients.
  71.633 +   By using UID EXPUNGE instead of EXPUNGE when resynchronizing with the
  71.634 +   server, the client can avoid inadvertently removing any messages that
  71.635 +   have been marked as \Deleted by other clients between the time that
  71.636 +   the client was last connected and the time the client resynchronizes.
  71.637 +
  71.638 +   Before returning an OK to the client, those messages that are removed
  71.639 +   are reported using a VANISHED response or EXPUNGE responses.
  71.640 +
  71.641 +   If the server is capable of storing modification sequences for the
  71.642 +   selected mailbox, it MUST increment the per-mailbox mod-sequence if
  71.643 +   at least one message was permanently removed due to the execution of
  71.644 +   the UID EXPUNGE command.  For each permanently removed message, the
  71.645 +   server MUST remember the incremented mod-sequence and corresponding
  71.646 +   UID.  If at least one message got expunged, the server MUST send the
  71.647 +   updated per-mailbox modification sequence using the HIGHESTMODSEQ
  71.648 +   response code (defined in [CONDSTORE]) in the tagged OK response.
  71.649 +
  71.650 +   Example:    C: . UID EXPUNGE 3000:3002
  71.651 +               S: * 3 EXPUNGE
  71.652 +               S: * 3 EXPUNGE
  71.653 +               S: * 3 EXPUNGE
  71.654 +               S: . OK [HIGHESTMODSEQ 20010715194045319] Ok
  71.655 +
  71.656 +   Note: In this example, at least messages with message numbers 3, 4,
  71.657 +   and 5 (UIDs 3000 to 3002) had the \Deleted flag set.  The first "* 3
  71.658 +   EXPUNGE" reports message # 3 as expunged.  The second "* 3 EXPUNGE"
  71.659 +   reports message # 4 as expunged (the message number got decremented
  71.660 +   due to the previous EXPUNGE response).  See the description of the
  71.661 +   EXPUNGE response in [RFC3501] for further explanation.
  71.662 +
  71.663 +3.6.  VANISHED Response
  71.664 +
  71.665 +   Contents:  an optional EARLIER tag
  71.666 +
  71.667 +   list of UIDs
  71.668 +
  71.669 +   The VANISHED response reports that the specified UIDs have been
  71.670 +   permanently removed from the mailbox.  This response is similar to
  71.671 +   the EXPUNGE response [RFC3501]; however, it can return information
  71.672 +   about multiple messages, and it returns UIDs instead of message
  71.673 +
  71.674 +
  71.675 +
  71.676 +
  71.677 +Melnikov, et al.            Standards Track                    [Page 12]
  71.678 +
  71.679 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.680 +
  71.681 +
  71.682 +   numbers.  The first benefit saves bandwidth, while the second is more
  71.683 +   convenient for clients that only use UIDs to access the IMAP server.
  71.684 +
  71.685 +   The VANISHED response has the same restrictions on when it can be
  71.686 +   sent as does the EXPUNGE response (see below).
  71.687 +
  71.688 +   The VANISHED response has two forms.  The first form contains the
  71.689 +   EARLIER tag, which signifies that the response was caused by a UID
  71.690 +   FETCH (VANISHED) or a SELECT/EXAMINE (QRESYNC) command.  This
  71.691 +   response is sent if the UID set parameter to the UID FETCH (VANISHED)
  71.692 +   command includes UIDs of messages that are no longer in the mailbox.
  71.693 +   When the client sees a VANISHED EARLIER response, it MUST NOT
  71.694 +   decrement message sequence numbers for each successive message in the
  71.695 +   mailbox.
  71.696 +
  71.697 +   The second form doesn't contain the EARLIER tag and is described
  71.698 +   below.  Once a client has issued "ENABLE QRESYNC", the server SHOULD
  71.699 +   use the VANISHED response without the EARLIER tag instead of the
  71.700 +   EXPUNGE response.  The server SHOULD continue using VANISHED in lieu
  71.701 +   of EXPUNGE for the duration of the connection.  In particular, this
  71.702 +   affects the EXPUNGE [RFC3501] and UID EXPUNGE [UIDPLUS] commands, as
  71.703 +   well as messages expunged in other connections.  Such a VANISHED
  71.704 +   response MUST NOT contain the EARLIER tag.
  71.705 +
  71.706 +   A VANISHED response sent because of an EXPUNGE or UID EXPUNGE command
  71.707 +   or because messages were expunged in other connections (i.e., the
  71.708 +   VANISHED response without the EARLIER tag) also decrements the number
  71.709 +   of messages in the mailbox; it is not necessary for the server to
  71.710 +   send an EXISTS response with the new value.  It also decrements
  71.711 +   message sequence numbers for each successive message in the mailbox
  71.712 +   (see the example at the end of this section).  Note that a VANISHED
  71.713 +   response caused by EXPUNGE, UID EXPUNGE, or messages expunged in
  71.714 +   other connections SHOULD only contain UIDs for messages expunged
  71.715 +   since the last VANISHED/EXPUNGE response sent for the currently
  71.716 +   opened mailbox or since the mailbox was opened.  That is, servers
  71.717 +   SHOULD NOT send UIDs for previously expunged messages, unless
  71.718 +   explicitly requested to do so by the UID FETCH (VANISHED) command.
  71.719 +
  71.720 +   Note that client implementors must take care to properly decrement
  71.721 +   the number of messages in the mailbox even if a server violates this
  71.722 +   last SHOULD or repeats the same UID multiple times in the returned
  71.723 +   UID set.  In general, this means that a client using this extension
  71.724 +   should either avoid using message numbers entirely, or have a
  71.725 +   complete mapping of UIDs to message sequence numbers for the selected
  71.726 +   mailbox.
  71.727 +
  71.728 +
  71.729 +
  71.730 +
  71.731 +
  71.732 +
  71.733 +Melnikov, et al.            Standards Track                    [Page 13]
  71.734 +
  71.735 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.736 +
  71.737 +
  71.738 +   Because clients handle the two different forms of the VANISHED
  71.739 +   response differently, servers MUST NOT report UIDs resulting from a
  71.740 +   UID FETCH (VANISHED) or a SELECT/EXAMINE (QRESYNC) in the same
  71.741 +   VANISHED response as UIDs of messages expunged now (i.e., messages
  71.742 +   expunged in other connections).  Instead, the server MUST send
  71.743 +   separate VANISHED responses: one with the EARLIER tag and one
  71.744 +   without.
  71.745 +
  71.746 +   A VANISHED response MUST NOT be sent when no command is in progress,
  71.747 +   nor while responding to a FETCH, STORE, or SEARCH command.  This rule
  71.748 +   is necessary to prevent a loss of synchronization of message sequence
  71.749 +   numbers between client and server.  A command is not "in progress"
  71.750 +   until the complete command has been received; in particular, a
  71.751 +   command is not "in progress" during the negotiation of command
  71.752 +   continuation.
  71.753 +
  71.754 +   Note: UID FETCH, UID STORE, and UID SEARCH are different commands
  71.755 +   from FETCH, STORE, and SEARCH.  A VANISHED response MAY be sent
  71.756 +   during a UID command.  However, the VANISHED response MUST NOT be
  71.757 +   sent during a UID SEARCH command that contains message numbers in the
  71.758 +   search criteria.
  71.759 +
  71.760 +   The update from the VANISHED response MUST be recorded by the client.
  71.761 +
  71.762 +   Example: Let's assume that there is the following mapping between
  71.763 +   message numbers and UIDs in the currently selected mailbox (here "X"
  71.764 +   marks messages with the \Deleted flag set, and "x" represents UIDs
  71.765 +   which are not relevant for the example):
  71.766 +
  71.767 +   Message numbers:   1    2    3    4    5  6   7  8  9 10  11
  71.768 +   UIDs:              x  504  505  507  508  x 510  x  x  x 625
  71.769 +   \Deleted messages:           X    X           X            X
  71.770 +
  71.771 +   In the presence of the extension defined in this document:
  71.772 +
  71.773 +   C: A202 EXPUNGE
  71.774 +   S: * VANISHED 505,507,510,625
  71.775 +   S: A202 OK EXPUNGE completed
  71.776 +
  71.777 +   Without the QRESYNC extension, the same example might look like:
  71.778 +
  71.779 +   C: A202 EXPUNGE
  71.780 +   S: * 3 EXPUNGE
  71.781 +   S: * 3 EXPUNGE
  71.782 +   S: * 5 EXPUNGE
  71.783 +   S: * 8 EXPUNGE
  71.784 +   S: A202 OK EXPUNGE completed
  71.785 +
  71.786 +
  71.787 +
  71.788 +
  71.789 +Melnikov, et al.            Standards Track                    [Page 14]
  71.790 +
  71.791 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.792 +
  71.793 +
  71.794 +   (Continuing previous example) If subsequently messages with UIDs 504
  71.795 +   and 508 got marked as \Deleted:
  71.796 +
  71.797 +   C: A210 EXPUNGE
  71.798 +   S: * VANISHED 504,508
  71.799 +   S: A210 OK EXPUNGE completed
  71.800 +
  71.801 +   i.e., the last VANISHED response only contains UIDs of messages
  71.802 +   expunged since the previous VANISHED response.
  71.803 +
  71.804 +3.7.  CLOSED Response Code
  71.805 +
  71.806 +   The CLOSED response code has no parameters.  A server implementing
  71.807 +   the extension defined in this document MUST return the CLOSED
  71.808 +   response code when the currently selected mailbox is closed
  71.809 +   implicitly using the SELECT/EXAMINE command on another mailbox.  The
  71.810 +   CLOSED response code serves as a boundary between responses for the
  71.811 +   previously opened mailbox (which was closed) and the newly selected
  71.812 +   mailbox: all responses before the CLOSED response code relate to the
  71.813 +   mailbox that was closed, and all subsequent responses relate to the
  71.814 +   newly opened mailbox.
  71.815 +
  71.816 +   There is no need to return the CLOSED response code on completion of
  71.817 +   the CLOSE or the UNSELECT [UNSELECT] command (or similar) whose
  71.818 +   purpose is to close the currently selected mailbox without opening a
  71.819 +   new one.
  71.820 +
  71.821 +4.  Server Implementation Considerations
  71.822 +
  71.823 +   This section describes a minimalist implementation, a moderate
  71.824 +   implementation, and an example of a full implementation.
  71.825 +
  71.826 +4.1.  Server Implementations That Don't Store Extra State
  71.827 +
  71.828 +   Strictly speaking, a server implementation that doesn't remember mod-
  71.829 +   sequences associated with expunged messages can be considered
  71.830 +   compliant with this specification.  Such implementations return all
  71.831 +   expunged messages specified in the UID set of the UID FETCH
  71.832 +   (VANISHED) command every time, without paying attention to the
  71.833 +   specified CHANGEDSINCE mod-sequence.  Such implementations are
  71.834 +   discouraged, as they can end up returning VANISHED responses that are
  71.835 +   bigger than the result of a UID SEARCH command for the same UID set.
  71.836 +
  71.837 +   Clients that use the message sequence match data can reduce the scope
  71.838 +   of this VANISHED response substantially in the typical case where
  71.839 +   expunges have not happened, or happen only toward the end of the
  71.840 +   mailbox.
  71.841 +
  71.842 +
  71.843 +
  71.844 +
  71.845 +Melnikov, et al.            Standards Track                    [Page 15]
  71.846 +
  71.847 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.848 +
  71.849 +
  71.850 +4.2.  Server Implementations Storing Minimal State
  71.851 +
  71.852 +   A server that stores the HIGHESTMODSEQ value at the time of the last
  71.853 +   EXPUNGE can omit the VANISHED response when a client provides a
  71.854 +   MODSEQ value that is equal to, or higher than, the current value of
  71.855 +   this datum, that is, when there have been no EXPUNGEs.
  71.856 +
  71.857 +   A client providing message sequence match data can reduce the scope
  71.858 +   as above.  In the case where there have been no expunges, the server
  71.859 +   can ignore this data.
  71.860 +
  71.861 +4.3.  Additional State Required on the Server
  71.862 +
  71.863 +   When compared to the [CONDSTORE] extension, this extension requires
  71.864 +   servers to store additional state associated with expunged messages.
  71.865 +   Note that implementations are not required to store this state in
  71.866 +   persistent storage; however, use of persistent storage is advisable.
  71.867 +
  71.868 +   One possible way to correctly implement the extension described in
  71.869 +   this document is to store a queue of <UID set, mod-sequence> pairs.
  71.870 +   <UID set> can be represented as a sequence of <min UID, max UID>
  71.871 +   pairs.
  71.872 +
  71.873 +   When messages are expunged, one or more entries are added to the
  71.874 +   queue tail.
  71.875 +
  71.876 +   When the server receives a request to return messages expunged since
  71.877 +   a given mod-sequence, it will search the queue from the tail (i.e.,
  71.878 +   going from the highest expunged mod-sequence to the lowest) until it
  71.879 +   sees the first record with a mod-sequence less than or equal to the
  71.880 +   given mod-sequence or it reaches the head of the queue.
  71.881 +
  71.882 +   Note that indefinitely storing information about expunged messages
  71.883 +   can cause storage and related problems for an implementation.  In the
  71.884 +   worst case, this could result in almost 64Gb of storage for each IMAP
  71.885 +   mailbox.  For example, consider an implementation that stores <min
  71.886 +   UID, max UID, mod-sequence> triples for each range of messages
  71.887 +   expunged at the same time.  Each triple requires 16 octets: 4 octets
  71.888 +   for each of the two UIDs, and 8 octets for the mod-sequence.  Assume
  71.889 +   that there is a mailbox containing a single message with a UID of
  71.890 +   2**32-1 (the maximum possible UID value), where messages had
  71.891 +   previously existed with UIDs starting at 1, and have been expunged
  71.892 +   one at a time.  For this mailbox alone, storage is required for the
  71.893 +   triples <1, 1, modseq1>, <2, 2, modseq2>, ..., <2**32-2, 2**32-2,
  71.894 +   modseq4294967294>.
  71.895 +
  71.896 +
  71.897 +
  71.898 +
  71.899 +
  71.900 +
  71.901 +Melnikov, et al.            Standards Track                    [Page 16]
  71.902 +
  71.903 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.904 +
  71.905 +
  71.906 +   Hence, implementations are encouraged to adopt strategies to protect
  71.907 +   against such storage problems, such as limiting the size of the queue
  71.908 +   used to store mod-sequences for expunged messages and "expiring"
  71.909 +   older records when this limit is reached.  When the selected
  71.910 +   implementation-specific queue limit is reached, the oldest record(s)
  71.911 +   are deleted from the queue (note that such records are located at the
  71.912 +   queue head).  For all such "expired" records, the server needs to
  71.913 +   store a single mod-sequence, which is the highest mod-sequence for
  71.914 +   all "expired" expunged messages.
  71.915 +
  71.916 +   Note that if the client provides the message sequence match data,
  71.917 +   this can heavily reduce the data cost of sending a complete set of
  71.918 +   missing UIDs; thus, reducing the problems for clients if a server is
  71.919 +   unable to persist much of this queue.  If the queue contains data
  71.920 +   back to the requested mod-sequence, this data can be ignored.
  71.921 +
  71.922 +   Also, note that if the UIDVALIDITY of the mailbox changes or if the
  71.923 +   mailbox is deleted, then any state associated with expunged messages
  71.924 +   doesn't need to be preserved and SHOULD be deleted.
  71.925 +
  71.926 +5.  Updated Synchronization Sequence
  71.927 +
  71.928 +   This section updates the description of optimized synchronization in
  71.929 +   Section 6.1 of the [IMAP-DISC].
  71.930 +
  71.931 +   An advanced disconnected mail client should use the QRESYNC and
  71.932 +   [CONDSTORE] extensions when they are supported by the server.  The
  71.933 +   client uses the value from the HIGHESTMODSEQ OK response code
  71.934 +   received on mailbox opening to determine if it needs to
  71.935 +   resynchronize.  Once the synchronization is complete, it MUST cache
  71.936 +   the received value (unless the mailbox UIDVALIDITY value has changed;
  71.937 +   see below).  The client MUST update its copy of the HIGHESTMODSEQ
  71.938 +   value whenever the server sends a subsequent HIGHESTMODSEQ OK
  71.939 +   response code.
  71.940 +
  71.941 +   After completing a full synchronization, the client MUST also take
  71.942 +   note of any unsolicited MODSEQ FETCH data items received from the
  71.943 +   server.  Whenever the client receives a tagged response to a command,
  71.944 +   it calculates the highest value among all MODSEQ FETCH data items
  71.945 +   received since the last tagged response.  If this value is bigger
  71.946 +   than the client's copy of the HIGHESTMODSEQ value, then the client
  71.947 +   MUST use this value as its new HIGHESTMODSEQ value.
  71.948 +
  71.949 +   Note: It is not safe to update the client's copy of the HIGHESTMODSEQ
  71.950 +   value with a MODSEQ FETCH data item value as soon as it is received
  71.951 +   because servers are not required to send MODSEQ FETCH data items in
  71.952 +   increasing modseqence order.  This can lead to the client missing
  71.953 +   some changes in case of connectivity loss.
  71.954 +
  71.955 +
  71.956 +
  71.957 +Melnikov, et al.            Standards Track                    [Page 17]
  71.958 +
  71.959 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
  71.960 +
  71.961 +
  71.962 +   When opening the mailbox for synchronization, the client uses the
  71.963 +   QRESYNC parameter to the SELECT/EXAMINE command.  The QRESYNC
  71.964 +   parameter is followed by the UIDVALIDITY and mailbox HIGHESTMODSEQ
  71.965 +   values, as known to the client.  It can be optionally followed by the
  71.966 +   set of UIDs, for example, if the client is only interested in partial
  71.967 +   synchronization of the mailbox.  The client may also transmit a list
  71.968 +   containing its knowledge of message numbers.
  71.969 +
  71.970 +   If the SELECT/EXAMINE command is successful, the client compares
  71.971 +   UIDVALIDITY as described in step d)1) in Section 3 of the
  71.972 +   [IMAP-DISC].  If the cached UIDVALIDITY value matches the one
  71.973 +   returned by the server and the server also returns the HIGHESTMODSEQ
  71.974 +   response code, then the server reports expunged messages and returns
  71.975 +   flag changes for all messages specified by the client in the UID set
  71.976 +   parameter (or for all messages in the mailbox, if the client omitted
  71.977 +   the UID set parameter).  At this point, the client is synchronized,
  71.978 +   except for maybe the new messages.
  71.979 +
  71.980 +   If upon a successful SELECT/EXAMINE (QRESYNC) command the client
  71.981 +   receives a NOMODSEQ OK untagged response (instead of the
  71.982 +   HIGHESTMODSEQ response code), it MUST remove the last known
  71.983 +   HIGHESTMODSEQ value from its cache and follow the more general
  71.984 +   instructions in Section 3 of the [IMAP-DISC].
  71.985 +
  71.986 +   At this point, the client is in sync with the server regarding old
  71.987 +   messages.  This client can now fetch information about new messages
  71.988 +   (if requested by the user).
  71.989 +
  71.990 +   Step d) ("Server-to-client synchronization") in Section 4 of the
  71.991 +   [IMAP-DISC] in the presence of the QRESYNC & CONDSTORE extensions is
  71.992 +   amended as follows:
  71.993 +
  71.994 +   d) "Server-to-client synchronization" -- for each mailbox that
  71.995 +      requires synchronization, do the following:
  71.996 +
  71.997 +   1a) Check the mailbox UIDVALIDITY (see Section 4.1 of the [IMAP-DISC]
  71.998 +       for more details) after issuing SELECT/EXAMINE (QRESYNC) command.
  71.999 +
 71.1000 +       If the UIDVALIDITY value returned by the server differs, the
 71.1001 +       client MUST
 71.1002 +
 71.1003 +       *   empty the local cache of that mailbox;
 71.1004 +
 71.1005 +       *   "forget" the cached HIGHESTMODSEQ value for the mailbox;
 71.1006 +
 71.1007 +
 71.1008 +
 71.1009 +
 71.1010 +
 71.1011 +
 71.1012 +
 71.1013 +Melnikov, et al.            Standards Track                    [Page 18]
 71.1014 +
 71.1015 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
 71.1016 +
 71.1017 +
 71.1018 +       *   remove any pending "actions" which refer to UIDs in that
 71.1019 +           mailbox.  Note, this doesn't affect actions performed on
 71.1020 +           client generated fake UIDs (see Section 5 of the
 71.1021 +           [IMAP-DISC]);
 71.1022 +
 71.1023 +   2)  Fetch the current "descriptors";
 71.1024 +
 71.1025 +       I) Discover new messages.
 71.1026 +
 71.1027 +   3)  Fetch the bodies of any "interesting" messages that the client
 71.1028 +       doesn't already have.
 71.1029 +
 71.1030 +   Example: The UIDVALIDITY value is the same, but the HIGHESTMODSEQ
 71.1031 +            value has changed on the server while the client was
 71.1032 +            offline:
 71.1033 +
 71.1034 +    C: A142 SELECT INBOX (QRESYNC (3857529045 20010715194032001 1:198))
 71.1035 +    S: * 172 EXISTS
 71.1036 +    S: * 1 RECENT
 71.1037 +    S: * OK [UNSEEN 12] Message 12 is first unseen
 71.1038 +    S: * OK [UIDVALIDITY 3857529045] UIDs valid
 71.1039 +    S: * OK [UIDNEXT 201] Predicted next UID
 71.1040 +    S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
 71.1041 +    S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
 71.1042 +    S: * OK [HIGHESTMODSEQ 20010715194045007]
 71.1043 +    S: * VANISHED (EARLIER) 1:5,7:8,10:15
 71.1044 +    S: * 2 FETCH (UID 6 MODSEQ (20010715205008000)
 71.1045 +        FLAGS (\Deleted))
 71.1046 +    S: * 5 FETCH (UID 9 MODSEQ (20010715195517000)
 71.1047 +        FLAGS ($NoJunk $AutoJunk $MDNSent))
 71.1048 +       ...
 71.1049 +    S: A142 OK [READ-WRITE] SELECT completed
 71.1050 +
 71.1051 +6.  Formal Syntax
 71.1052 +
 71.1053 +   The following syntax specification uses the Augmented Backus-Naur
 71.1054 +   Form (ABNF) notation as specified in [ABNF].
 71.1055 +
 71.1056 +   Non-terminals referenced but not defined below are as defined by
 71.1057 +   [RFC3501], [CONDSTORE], or [IMAPABNF].
 71.1058 +
 71.1059 +   Except as noted otherwise, all alphabetic characters are case-
 71.1060 +   insensitive.  The use of upper or lower case characters to define
 71.1061 +   token strings is for editorial clarity only.  Implementations MUST
 71.1062 +   accept these strings in a case-insensitive fashion.
 71.1063 +
 71.1064 +
 71.1065 +
 71.1066 +
 71.1067 +
 71.1068 +
 71.1069 +Melnikov, et al.            Standards Track                    [Page 19]
 71.1070 +
 71.1071 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
 71.1072 +
 71.1073 +
 71.1074 +   capability          =/ "QRESYNC"
 71.1075 +
 71.1076 +   select-param        =  "QRESYNC" SP "(" uidvalidity SP
 71.1077 +                       mod-sequence-value [SP known-uids]
 71.1078 +                       [SP seq-match-data] ")"
 71.1079 +                       ;; conforms to the generic select-param
 71.1080 +                       ;; syntax defined in [IMAPABNF]
 71.1081 +
 71.1082 +   seq-match-data      =  "(" known-sequence-set SP known-uid-set ")"
 71.1083 +
 71.1084 +   uidvalidity         =  nz-number
 71.1085 +
 71.1086 +   known-uids          =  sequence-set
 71.1087 +                       ;; sequence of UIDs, "*" is not allowed
 71.1088 +
 71.1089 +   known-sequence-set  =  sequence-set
 71.1090 +                       ;; set of message numbers corresponding to
 71.1091 +                       ;; the UIDs in known-uid-set, in ascending order.
 71.1092 +                       ;; * is not allowed.
 71.1093 +
 71.1094 +   known-uid-set       =  sequence-set
 71.1095 +                       ;; set of UIDs corresponding to the messages in
 71.1096 +                       ;; known-sequence-set, in ascending order.
 71.1097 +                       ;; * is not allowed.
 71.1098 +
 71.1099 +   message-data        =/ expunged-resp
 71.1100 +
 71.1101 +   expunged-resp       =  "VANISHED" [SP "(EARLIER)"] SP known-uids
 71.1102 +
 71.1103 +   rexpunges-fetch-mod =  "VANISHED"
 71.1104 +                       ;; VANISHED UID FETCH modifier conforms
 71.1105 +                       ;; to the fetch-modifier syntax
 71.1106 +                       ;; defined in [IMAPABNF].  It is only
 71.1107 +                       ;; allowed in the UID FETCH command.
 71.1108 +
 71.1109 +   resp-text-code      =/ "CLOSED"
 71.1110 +
 71.1111 +7.  Security Considerations
 71.1112 +
 71.1113 +   As always, it is important to thoroughly test clients and servers
 71.1114 +   implementing this extension, as it changes how the server reports
 71.1115 +   expunged messages to the client.
 71.1116 +
 71.1117 +   Security considerations relevant to [CONDSTORE] are relevant to this
 71.1118 +   extension.
 71.1119 +
 71.1120 +   This document doesn't raise any new security concerns not already
 71.1121 +   raised by [CONDSTORE] or [RFC3501].
 71.1122 +
 71.1123 +
 71.1124 +
 71.1125 +Melnikov, et al.            Standards Track                    [Page 20]
 71.1126 +
 71.1127 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
 71.1128 +
 71.1129 +
 71.1130 +8.  IANA Considerations
 71.1131 +
 71.1132 +   IMAP4 capabilities are registered by publishing a standards track or
 71.1133 +   IESG approved experimental RFC.  The registry is currently located
 71.1134 +   at:
 71.1135 +
 71.1136 +      http://www.iana.org/assignments/imap4-capabilities
 71.1137 +
 71.1138 +   This document defines the QRESYNC IMAP capability.  IANA has added
 71.1139 +   this capability to the registry.
 71.1140 +
 71.1141 +9.  Acknowledgments
 71.1142 +
 71.1143 +   Thanks to Steve Hole, Cyrus Daboo, and Michael Wener for encouraging
 71.1144 +   creation of this document.
 71.1145 +
 71.1146 +   Valuable comments, both in agreement and in dissent, were received
 71.1147 +   from Timo Sirainen, Michael Wener, Randall Gellens, Arnt Gulbrandsen,
 71.1148 +   Chris Newman, Peter Coates, Mark Crispin, Elwyn Davies, Dan Karp,
 71.1149 +   Eric Rescorla, and Mike Zraly.
 71.1150 +
 71.1151 +   This document takes substantial text from [RFC3501] by Mark Crispin.
 71.1152 +
 71.1153 +10.  References
 71.1154 +
 71.1155 +10.1.  Normative References
 71.1156 +
 71.1157 +   [ABNF]       Crocker, D. and P. Overell, "Augmented BNF for Syntax
 71.1158 +                Specifications: ABNF", STD 68, RFC 5234, January 2008.
 71.1159 +
 71.1160 +   [CONDSTORE]  Melnikov, A. and S. Hole, "IMAP Extension for
 71.1161 +                Conditional STORE Operation or Quick Flag Changes
 71.1162 +                Resynchronization", RFC 4551, June 2006.
 71.1163 +
 71.1164 +   [ENABLE]     Gulbrandsen, A., Ed. and A. Melnikov, Ed., "The IMAP
 71.1165 +                ENABLE Extension", RFC 5161, March 2008.
 71.1166 +
 71.1167 +   [IMAPABNF]   Melnikov, A. and C. Daboo, "Collected Extensions to
 71.1168 +                IMAP4 ABNF", RFC 4466, April 2006.
 71.1169 +
 71.1170 +   [RFC2119]    Bradner, S., "Key words for use in RFCs to Indicate
 71.1171 +                Requirement Levels", BCP 14, RFC 2119, March 1997.
 71.1172 +
 71.1173 +   [RFC3501]    Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
 71.1174 +                4rev1", RFC 3501, March 2003.
 71.1175 +
 71.1176 +   [UIDPLUS]    Crispin, M., "Internet Message Access Protocol (IMAP) -
 71.1177 +                UIDPLUS extension", RFC 4315, December 2005.
 71.1178 +
 71.1179 +
 71.1180 +
 71.1181 +Melnikov, et al.            Standards Track                    [Page 21]
 71.1182 +
 71.1183 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
 71.1184 +
 71.1185 +
 71.1186 +10.2.  Informative References
 71.1187 +
 71.1188 +   [IMAP-DISC]  Melnikov, A., Ed., "Synchronization Operations For
 71.1189 +                Disconnected Imap4 Clients", RFC 4549, June 2006.
 71.1190 +
 71.1191 +   [UNSELECT]   Melnikov, A., "Internet Message Access Protocol (IMAP)
 71.1192 +                UNSELECT command", RFC 3691, February 2004.
 71.1193 +
 71.1194 +Authors' Addresses
 71.1195 +
 71.1196 +   Alexey Melnikov
 71.1197 +   Isode Ltd
 71.1198 +   5 Castle Business Village
 71.1199 +   36 Station Road
 71.1200 +   Hampton, Middlesex  TW12 2BX
 71.1201 +   UK
 71.1202 +
 71.1203 +   EMail: Alexey.Melnikov@isode.com
 71.1204 +
 71.1205 +
 71.1206 +   Dave Cridland
 71.1207 +   Isode Ltd
 71.1208 +   5 Castle Business Village
 71.1209 +   36 Station Road
 71.1210 +   Hampton, Middlesex  TW12 2BX
 71.1211 +   UK
 71.1212 +
 71.1213 +   EMail: dave.cridland@isode.com
 71.1214 +
 71.1215 +
 71.1216 +   Corby Wilson
 71.1217 +   Nokia
 71.1218 +   5 Wayside Rd.
 71.1219 +   Burlington, MA  01803
 71.1220 +   USA
 71.1221 +
 71.1222 +   EMail: corby@computer.org
 71.1223 +
 71.1224 +
 71.1225 +
 71.1226 +
 71.1227 +
 71.1228 +
 71.1229 +
 71.1230 +
 71.1231 +
 71.1232 +
 71.1233 +
 71.1234 +
 71.1235 +
 71.1236 +
 71.1237 +Melnikov, et al.            Standards Track                    [Page 22]
 71.1238 +
 71.1239 +RFC 5162               IMAP Quick Mailbox Resync              March 2008
 71.1240 +
 71.1241 +
 71.1242 +Full Copyright Statement
 71.1243 +
 71.1244 +   Copyright (C) The IETF Trust (2008).
 71.1245 +
 71.1246 +   This document is subject to the rights, licenses and restrictions
 71.1247 +   contained in BCP 78, and except as set forth therein, the authors
 71.1248 +   retain all their rights.
 71.1249 +
 71.1250 +   This document and the information contained herein are provided on an
 71.1251 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
 71.1252 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
 71.1253 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
 71.1254 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
 71.1255 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
 71.1256 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 71.1257 +
 71.1258 +Intellectual Property
 71.1259 +
 71.1260 +   The IETF takes no position regarding the validity or scope of any
 71.1261 +   Intellectual Property Rights or other rights that might be claimed to
 71.1262 +   pertain to the implementation or use of the technology described in
 71.1263 +   this document or the extent to which any license under such rights
 71.1264 +   might or might not be available; nor does it represent that it has
 71.1265 +   made any independent effort to identify any such rights.  Information
 71.1266 +   on the procedures with respect to rights in RFC documents can be
 71.1267 +   found in BCP 78 and BCP 79.
 71.1268 +
 71.1269 +   Copies of IPR disclosures made to the IETF Secretariat and any
 71.1270 +   assurances of licenses to be made available, or the result of an
 71.1271 +   attempt made to obtain a general license or permission for the use of
 71.1272 +   such proprietary rights by implementers or users of this
 71.1273 +   specification can be obtained from the IETF on-line IPR repository at
 71.1274 +   http://www.ietf.org/ipr.
 71.1275 +
 71.1276 +   The IETF invites any interested party to bring to its attention any
 71.1277 +   copyrights, patents or patent applications, or other proprietary
 71.1278 +   rights that may cover technology that may be required to implement
 71.1279 +   this standard.  Please address the information to the IETF at
 71.1280 +   ietf-ipr@ietf.org.
 71.1281 +
 71.1282 +
 71.1283 +
 71.1284 +
 71.1285 +
 71.1286 +
 71.1287 +
 71.1288 +
 71.1289 +
 71.1290 +
 71.1291 +
 71.1292 +
 71.1293 +Melnikov, et al.            Standards Track                    [Page 23]
 71.1294 +
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/docs/rfc/rfc5234.txt	Mon Sep 14 15:17:45 2009 +0900
    72.3 @@ -0,0 +1,899 @@
    72.4 +
    72.5 +
    72.6 +
    72.7 +
    72.8 +
    72.9 +
   72.10 +Network Working Group                                    D. Crocker, Ed.
   72.11 +Request for Comments: 5234                   Brandenburg InternetWorking
   72.12 +STD: 68                                                       P. Overell
   72.13 +Obsoletes: 4234                                                THUS plc.
   72.14 +Category: Standards Track                                   January 2008
   72.15 +
   72.16 +
   72.17 +             Augmented BNF for Syntax Specifications: ABNF
   72.18 +
   72.19 +Status of This Memo
   72.20 +
   72.21 +   This document specifies an Internet standards track protocol for the
   72.22 +   Internet community, and requests discussion and suggestions for
   72.23 +   improvements.  Please refer to the current edition of the "Internet
   72.24 +   Official Protocol Standards" (STD 1) for the standardization state
   72.25 +   and status of this protocol.  Distribution of this memo is unlimited.
   72.26 +
   72.27 +Abstract
   72.28 +
   72.29 +   Internet technical specifications often need to define a formal
   72.30 +   syntax.  Over the years, a modified version of Backus-Naur Form
   72.31 +   (BNF), called Augmented BNF (ABNF), has been popular among many
   72.32 +   Internet specifications.  The current specification documents ABNF.
   72.33 +   It balances compactness and simplicity with reasonable
   72.34 +   representational power.  The differences between standard BNF and
   72.35 +   ABNF involve naming rules, repetition, alternatives, order-
   72.36 +   independence, and value ranges.  This specification also supplies
   72.37 +   additional rule definitions and encoding for a core lexical analyzer
   72.38 +   of the type common to several Internet specifications.
   72.39 +
   72.40 +
   72.41 +
   72.42 +
   72.43 +
   72.44 +
   72.45 +
   72.46 +
   72.47 +
   72.48 +
   72.49 +
   72.50 +
   72.51 +
   72.52 +
   72.53 +
   72.54 +
   72.55 +
   72.56 +
   72.57 +
   72.58 +
   72.59 +
   72.60 +
   72.61 +Crocker & Overell           Standards Track                     [Page 1]
   72.62 +
   72.63 +RFC 5234                          ABNF                      January 2008
   72.64 +
   72.65 +
   72.66 +Table of Contents
   72.67 +
   72.68 +   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
   72.69 +   2.  Rule Definition  . . . . . . . . . . . . . . . . . . . . . . .  3
   72.70 +     2.1.  Rule Naming  . . . . . . . . . . . . . . . . . . . . . . .  3
   72.71 +     2.2.  Rule Form  . . . . . . . . . . . . . . . . . . . . . . . .  4
   72.72 +     2.3.  Terminal Values  . . . . . . . . . . . . . . . . . . . . .  4
   72.73 +     2.4.  External Encodings . . . . . . . . . . . . . . . . . . . .  6
   72.74 +   3.  Operators  . . . . . . . . . . . . . . . . . . . . . . . . . .  6
   72.75 +     3.1.  Concatenation:  Rule1 Rule2  . . . . . . . . . . . . . . .  6
   72.76 +     3.2.  Alternatives:  Rule1 / Rule2 . . . . . . . . . . . . . . .  7
   72.77 +     3.3.  Incremental Alternatives: Rule1 =/ Rule2 . . . . . . . . .  7
   72.78 +     3.4.  Value Range Alternatives:  %c##-## . . . . . . . . . . . .  8
   72.79 +     3.5.  Sequence Group:  (Rule1 Rule2) . . . . . . . . . . . . . .  8
   72.80 +     3.6.  Variable Repetition:  *Rule  . . . . . . . . . . . . . . .  9
   72.81 +     3.7.  Specific Repetition:  nRule  . . . . . . . . . . . . . . .  9
   72.82 +     3.8.  Optional Sequence:  [RULE] . . . . . . . . . . . . . . . .  9
   72.83 +     3.9.  Comment:  ; Comment  . . . . . . . . . . . . . . . . . . .  9
   72.84 +     3.10. Operator Precedence  . . . . . . . . . . . . . . . . . . . 10
   72.85 +   4.  ABNF Definition of ABNF  . . . . . . . . . . . . . . . . . . . 10
   72.86 +   5.  Security Considerations  . . . . . . . . . . . . . . . . . . . 12
   72.87 +   6.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 12
   72.88 +     6.1.  Normative References . . . . . . . . . . . . . . . . . . . 12
   72.89 +     6.2.  Informative References . . . . . . . . . . . . . . . . . . 12
   72.90 +   Appendix A.  Acknowledgements  . . . . . . . . . . . . . . . . . . 13
   72.91 +   Appendix B.  Core ABNF of ABNF . . . . . . . . . . . . . . . . . . 13
   72.92 +     B.1.  Core Rules . . . . . . . . . . . . . . . . . . . . . . . . 13
   72.93 +     B.2.  Common Encoding  . . . . . . . . . . . . . . . . . . . . . 15
   72.94 +
   72.95 +
   72.96 +
   72.97 +
   72.98 +
   72.99 +
  72.100 +
  72.101 +
  72.102 +
  72.103 +
  72.104 +
  72.105 +
  72.106 +
  72.107 +
  72.108 +
  72.109 +
  72.110 +
  72.111 +
  72.112 +
  72.113 +
  72.114 +
  72.115 +
  72.116 +
  72.117 +Crocker & Overell           Standards Track                     [Page 2]
  72.118 +
  72.119 +RFC 5234                          ABNF                      January 2008
  72.120 +
  72.121 +
  72.122 +1.  Introduction
  72.123 +
  72.124 +   Internet technical specifications often need to define a formal
  72.125 +   syntax and are free to employ whatever notation their authors deem
  72.126 +   useful.  Over the years, a modified version of Backus-Naur Form
  72.127 +   (BNF), called Augmented BNF (ABNF), has been popular among many
  72.128 +   Internet specifications.  It balances compactness and simplicity with
  72.129 +   reasonable representational power.  In the early days of the Arpanet,
  72.130 +   each specification contained its own definition of ABNF.  This
  72.131 +   included the email specifications, [RFC733] and then [RFC822], which
  72.132 +   came to be the common citations for defining ABNF.  The current
  72.133 +   document separates those definitions to permit selective reference.
  72.134 +   Predictably, it also provides some modifications and enhancements.
  72.135 +
  72.136 +   The differences between standard BNF and ABNF involve naming rules,
  72.137 +   repetition, alternatives, order-independence, and value ranges.
  72.138 +   Appendix B supplies rule definitions and encoding for a core lexical
  72.139 +   analyzer of the type common to several Internet specifications.  It
  72.140 +   is provided as a convenience and is otherwise separate from the meta
  72.141 +   language defined in the body of this document, and separate from its
  72.142 +   formal status.
  72.143 +
  72.144 +2.  Rule Definition
  72.145 +
  72.146 +2.1.  Rule Naming
  72.147 +
  72.148 +   The name of a rule is simply the name itself, that is, a sequence of
  72.149 +   characters, beginning with an alphabetic character, and followed by a
  72.150 +   combination of alphabetics, digits, and hyphens (dashes).
  72.151 +
  72.152 +   NOTE:
  72.153 +
  72.154 +      Rule names are case insensitive.
  72.155 +
  72.156 +   The names <rulename>, <Rulename>, <RULENAME>, and <rUlENamE> all
  72.157 +   refer to the same rule.
  72.158 +
  72.159 +   Unlike original BNF, angle brackets ("<", ">") are not required.
  72.160 +   However, angle brackets may be used around a rule name whenever their
  72.161 +   presence facilitates in discerning the use of a rule name.  This is
  72.162 +   typically restricted to rule name references in free-form prose, or
  72.163 +   to distinguish partial rules that combine into a string not separated
  72.164 +   by white space, such as shown in the discussion about repetition,
  72.165 +   below.
  72.166 +
  72.167 +
  72.168 +
  72.169 +
  72.170 +
  72.171 +
  72.172 +
  72.173 +Crocker & Overell           Standards Track                     [Page 3]
  72.174 +
  72.175 +RFC 5234                          ABNF                      January 2008
  72.176 +
  72.177 +
  72.178 +2.2.  Rule Form
  72.179 +
  72.180 +   A rule is defined by the following sequence:
  72.181 +
  72.182 +         name =  elements crlf
  72.183 +
  72.184 +   where <name> is the name of the rule, <elements> is one or more rule
  72.185 +   names or terminal specifications, and <crlf> is the end-of-line
  72.186 +   indicator (carriage return followed by line feed).  The equal sign
  72.187 +   separates the name from the definition of the rule.  The elements
  72.188 +   form a sequence of one or more rule names and/or value definitions,
  72.189 +   combined according to the various operators defined in this document,
  72.190 +   such as alternative and repetition.
  72.191 +
  72.192 +   For visual ease, rule definitions are left aligned.  When a rule
  72.193 +   requires multiple lines, the continuation lines are indented.  The
  72.194 +   left alignment and indentation are relative to the first lines of the
  72.195 +   ABNF rules and need not match the left margin of the document.
  72.196 +
  72.197 +2.3.  Terminal Values
  72.198 +
  72.199 +   Rules resolve into a string of terminal values, sometimes called
  72.200 +   characters.  In ABNF, a character is merely a non-negative integer.
  72.201 +   In certain contexts, a specific mapping (encoding) of values into a
  72.202 +   character set (such as ASCII) will be specified.
  72.203 +
  72.204 +   Terminals are specified by one or more numeric characters, with the
  72.205 +   base interpretation of those characters indicated explicitly.  The
  72.206 +   following bases are currently defined:
  72.207 +
  72.208 +         b           =  binary
  72.209 +
  72.210 +         d           =  decimal
  72.211 +
  72.212 +         x           =  hexadecimal
  72.213 +
  72.214 +   Hence:
  72.215 +
  72.216 +         CR          =  %d13
  72.217 +
  72.218 +         CR          =  %x0D
  72.219 +
  72.220 +   respectively specify the decimal and hexadecimal representation of
  72.221 +   [US-ASCII] for carriage return.
  72.222 +
  72.223 +
  72.224 +
  72.225 +
  72.226 +
  72.227 +
  72.228 +
  72.229 +Crocker & Overell           Standards Track                     [Page 4]
  72.230 +
  72.231 +RFC 5234                          ABNF                      January 2008
  72.232 +
  72.233 +
  72.234 +   A concatenated string of such values is specified compactly, using a
  72.235 +   period (".") to indicate a separation of characters within that
  72.236 +   value.  Hence:
  72.237 +
  72.238 +         CRLF        =  %d13.10
  72.239 +
  72.240 +   ABNF permits the specification of literal text strings directly,
  72.241 +   enclosed in quotation marks.  Hence:
  72.242 +
  72.243 +         command     =  "command string"
  72.244 +
  72.245 +   Literal text strings are interpreted as a concatenated set of
  72.246 +   printable characters.
  72.247 +
  72.248 +   NOTE:
  72.249 +
  72.250 +      ABNF strings are case insensitive and the character set for these
  72.251 +      strings is US-ASCII.
  72.252 +
  72.253 +   Hence:
  72.254 +
  72.255 +         rulename = "abc"
  72.256 +
  72.257 +   and:
  72.258 +
  72.259 +         rulename = "aBc"
  72.260 +
  72.261 +   will match "abc", "Abc", "aBc", "abC", "ABc", "aBC", "AbC", and
  72.262 +   "ABC".
  72.263 +
  72.264 +      To specify a rule that is case sensitive, specify the characters
  72.265 +      individually.
  72.266 +
  72.267 +   For example:
  72.268 +
  72.269 +         rulename    =  %d97 %d98 %d99
  72.270 +
  72.271 +   or
  72.272 +
  72.273 +         rulename    =  %d97.98.99
  72.274 +
  72.275 +   will match only the string that comprises only the lowercase
  72.276 +   characters, abc.
  72.277 +
  72.278 +
  72.279 +
  72.280 +
  72.281 +
  72.282 +
  72.283 +
  72.284 +
  72.285 +Crocker & Overell           Standards Track                     [Page 5]
  72.286 +
  72.287 +RFC 5234                          ABNF                      January 2008
  72.288 +
  72.289 +
  72.290 +2.4.  External Encodings
  72.291 +
  72.292 +   External representations of terminal value characters will vary
  72.293 +   according to constraints in the storage or transmission environment.
  72.294 +   Hence, the same ABNF-based grammar may have multiple external
  72.295 +   encodings, such as one for a 7-bit US-ASCII environment, another for
  72.296 +   a binary octet environment, and still a different one when 16-bit
  72.297 +   Unicode is used.  Encoding details are beyond the scope of ABNF,
  72.298 +   although Appendix B provides definitions for a 7-bit US-ASCII
  72.299 +   environment as has been common to much of the Internet.
  72.300 +
  72.301 +   By separating external encoding from the syntax, it is intended that
  72.302 +   alternate encoding environments can be used for the same syntax.
  72.303 +
  72.304 +3.  Operators
  72.305 +
  72.306 +3.1.  Concatenation:  Rule1 Rule2
  72.307 +
  72.308 +   A rule can define a simple, ordered string of values (i.e., a
  72.309 +   concatenation of contiguous characters) by listing a sequence of rule
  72.310 +   names.  For example:
  72.311 +
  72.312 +         foo         =  %x61           ; a
  72.313 +
  72.314 +         bar         =  %x62           ; b
  72.315 +
  72.316 +         mumble      =  foo bar foo
  72.317 +
  72.318 +   So that the rule <mumble> matches the lowercase string "aba".
  72.319 +
  72.320 +   Linear white space: Concatenation is at the core of the ABNF parsing
  72.321 +   model.  A string of contiguous characters (values) is parsed
  72.322 +   according to the rules defined in ABNF.  For Internet specifications,
  72.323 +   there is some history of permitting linear white space (space and
  72.324 +   horizontal tab) to be freely and implicitly interspersed around major
  72.325 +   constructs, such as delimiting special characters or atomic strings.
  72.326 +
  72.327 +   NOTE:
  72.328 +
  72.329 +      This specification for ABNF does not provide for implicit
  72.330 +      specification of linear white space.
  72.331 +
  72.332 +   Any grammar that wishes to permit linear white space around
  72.333 +   delimiters or string segments must specify it explicitly.  It is
  72.334 +   often useful to provide for such white space in "core" rules that are
  72.335 +   then used variously among higher-level rules.  The "core" rules might
  72.336 +   be formed into a lexical analyzer or simply be part of the main
  72.337 +   ruleset.
  72.338 +
  72.339 +
  72.340 +
  72.341 +Crocker & Overell           Standards Track                     [Page 6]
  72.342 +
  72.343 +RFC 5234                          ABNF                      January 2008
  72.344 +
  72.345 +
  72.346 +3.2.  Alternatives:  Rule1 / Rule2
  72.347 +
  72.348 +   Elements separated by a forward slash ("/") are alternatives.
  72.349 +   Therefore,
  72.350 +
  72.351 +         foo / bar
  72.352 +
  72.353 +   will accept <foo> or <bar>.
  72.354 +
  72.355 +   NOTE:
  72.356 +
  72.357 +      A quoted string containing alphabetic characters is a special form
  72.358 +      for specifying alternative characters and is interpreted as a non-
  72.359 +      terminal representing the set of combinatorial strings with the
  72.360 +      contained characters, in the specified order but with any mixture
  72.361 +      of upper- and lowercase.
  72.362 +
  72.363 +3.3.  Incremental Alternatives: Rule1 =/ Rule2
  72.364 +
  72.365 +   It is sometimes convenient to specify a list of alternatives in
  72.366 +   fragments.  That is, an initial rule may match one or more
  72.367 +   alternatives, with later rule definitions adding to the set of
  72.368 +   alternatives.  This is particularly useful for otherwise independent
  72.369 +   specifications that derive from the same parent ruleset, such as
  72.370 +   often occurs with parameter lists.  ABNF permits this incremental
  72.371 +   definition through the construct:
  72.372 +
  72.373 +         oldrule     =/ additional-alternatives
  72.374 +
  72.375 +   So that the ruleset
  72.376 +
  72.377 +         ruleset     =  alt1 / alt2
  72.378 +
  72.379 +         ruleset     =/ alt3
  72.380 +
  72.381 +         ruleset     =/ alt4 / alt5
  72.382 +
  72.383 +   is the same as specifying
  72.384 +
  72.385 +         ruleset     =  alt1 / alt2 / alt3 / alt4 / alt5
  72.386 +
  72.387 +
  72.388 +
  72.389 +
  72.390 +
  72.391 +
  72.392 +
  72.393 +
  72.394 +
  72.395 +
  72.396 +
  72.397 +Crocker & Overell           Standards Track                     [Page 7]
  72.398 +
  72.399 +RFC 5234                          ABNF                      January 2008
  72.400 +
  72.401 +
  72.402 +3.4.  Value Range Alternatives:  %c##-##
  72.403 +
  72.404 +   A range of alternative numeric values can be specified compactly,
  72.405 +   using a dash ("-") to indicate the range of alternative values.
  72.406 +   Hence:
  72.407 +
  72.408 +         DIGIT       =  %x30-39
  72.409 +
  72.410 +   is equivalent to:
  72.411 +
  72.412 +         DIGIT       =  "0" / "1" / "2" / "3" / "4" / "5" / "6" /
  72.413 +
  72.414 +                        "7" / "8" / "9"
  72.415 +
  72.416 +   Concatenated numeric values and numeric value ranges cannot be
  72.417 +   specified in the same string.  A numeric value may use the dotted
  72.418 +   notation for concatenation or it may use the dash notation to specify
  72.419 +   one value range.  Hence, to specify one printable character between
  72.420 +   end-of-line sequences, the specification could be:
  72.421 +
  72.422 +         char-line = %x0D.0A %x20-7E %x0D.0A
  72.423 +
  72.424 +3.5.  Sequence Group:  (Rule1 Rule2)
  72.425 +
  72.426 +   Elements enclosed in parentheses are treated as a single element,
  72.427 +   whose contents are strictly ordered.  Thus,
  72.428 +
  72.429 +         elem (foo / bar) blat
  72.430 +
  72.431 +   matches (elem foo blat) or (elem bar blat), and
  72.432 +
  72.433 +         elem foo / bar blat
  72.434 +
  72.435 +   matches (elem foo) or (bar blat).
  72.436 +
  72.437 +   NOTE:
  72.438 +
  72.439 +      It is strongly advised that grouping notation be used, rather than
  72.440 +      relying on the proper reading of "bare" alternations, when
  72.441 +      alternatives consist of multiple rule names or literals.
  72.442 +
  72.443 +   Hence, it is recommended that the following form be used:
  72.444 +
  72.445 +        (elem foo) / (bar blat)
  72.446 +
  72.447 +   It will avoid misinterpretation by casual readers.
  72.448 +
  72.449 +
  72.450 +
  72.451 +
  72.452 +
  72.453 +Crocker & Overell           Standards Track                     [Page 8]
  72.454 +
  72.455 +RFC 5234                          ABNF                      January 2008
  72.456 +
  72.457 +
  72.458 +   The sequence group notation is also used within free text to set off
  72.459 +   an element sequence from the prose.
  72.460 +
  72.461 +3.6.  Variable Repetition:  *Rule
  72.462 +
  72.463 +   The operator "*" preceding an element indicates repetition.  The full
  72.464 +   form is:
  72.465 +
  72.466 +         <a>*<b>element
  72.467 +
  72.468 +   where <a> and <b> are optional decimal values, indicating at least
  72.469 +   <a> and at most <b> occurrences of the element.
  72.470 +
  72.471 +   Default values are 0 and infinity so that *<element> allows any
  72.472 +   number, including zero; 1*<element> requires at least one;
  72.473 +   3*3<element> allows exactly 3; and 1*2<element> allows one or two.
  72.474 +
  72.475 +3.7.  Specific Repetition:  nRule
  72.476 +
  72.477 +   A rule of the form:
  72.478 +
  72.479 +         <n>element
  72.480 +
  72.481 +   is equivalent to
  72.482 +
  72.483 +         <n>*<n>element
  72.484 +
  72.485 +   That is, exactly <n> occurrences of <element>.  Thus, 2DIGIT is a
  72.486 +   2-digit number, and 3ALPHA is a string of three alphabetic
  72.487 +   characters.
  72.488 +
  72.489 +3.8.  Optional Sequence:  [RULE]
  72.490 +
  72.491 +   Square brackets enclose an optional element sequence:
  72.492 +
  72.493 +         [foo bar]
  72.494 +
  72.495 +   is equivalent to
  72.496 +
  72.497 +         *1(foo bar).
  72.498 +
  72.499 +3.9.  Comment:  ; Comment
  72.500 +
  72.501 +   A semicolon starts a comment that continues to the end of line.  This
  72.502 +   is a simple way of including useful notes in parallel with the
  72.503 +   specifications.
  72.504 +
  72.505 +
  72.506 +
  72.507 +
  72.508 +
  72.509 +Crocker & Overell           Standards Track                     [Page 9]
  72.510 +
  72.511 +RFC 5234                          ABNF                      January 2008
  72.512 +
  72.513 +
  72.514 +3.10.  Operator Precedence
  72.515 +
  72.516 +   The various mechanisms described above have the following precedence,
  72.517 +   from highest (binding tightest) at the top, to lowest (loosest) at
  72.518 +   the bottom:
  72.519 +
  72.520 +      Rule name, prose-val, Terminal value
  72.521 +
  72.522 +      Comment
  72.523 +
  72.524 +      Value range
  72.525 +
  72.526 +      Repetition
  72.527 +
  72.528 +      Grouping, Optional
  72.529 +
  72.530 +      Concatenation
  72.531 +
  72.532 +      Alternative
  72.533 +
  72.534 +   Use of the alternative operator, freely mixed with concatenations,
  72.535 +   can be confusing.
  72.536 +
  72.537 +      Again, it is recommended that the grouping operator be used to
  72.538 +      make explicit concatenation groups.
  72.539 +
  72.540 +4.  ABNF Definition of ABNF
  72.541 +
  72.542 +   NOTES:
  72.543 +
  72.544 +      1.  This syntax requires a formatting of rules that is relatively
  72.545 +          strict.  Hence, the version of a ruleset included in a
  72.546 +          specification might need preprocessing to ensure that it can
  72.547 +          be interpreted by an ABNF parser.
  72.548 +
  72.549 +      2.  This syntax uses the rules provided in Appendix B.
  72.550 +
  72.551 +
  72.552 +         rulelist       =  1*( rule / (*c-wsp c-nl) )
  72.553 +
  72.554 +         rule           =  rulename defined-as elements c-nl
  72.555 +                                ; continues if next line starts
  72.556 +                                ;  with white space
  72.557 +
  72.558 +         rulename       =  ALPHA *(ALPHA / DIGIT / "-")
  72.559 +
  72.560 +
  72.561 +
  72.562 +
  72.563 +
  72.564 +
  72.565 +Crocker & Overell           Standards Track                    [Page 10]
  72.566 +
  72.567 +RFC 5234                          ABNF                      January 2008
  72.568 +
  72.569 +
  72.570 +         defined-as     =  *c-wsp ("=" / "=/") *c-wsp
  72.571 +                                ; basic rules definition and
  72.572 +                                ;  incremental alternatives
  72.573 +
  72.574 +         elements       =  alternation *c-wsp
  72.575 +
  72.576 +         c-wsp          =  WSP / (c-nl WSP)
  72.577 +
  72.578 +         c-nl           =  comment / CRLF
  72.579 +                                ; comment or newline
  72.580 +
  72.581 +         comment        =  ";" *(WSP / VCHAR) CRLF
  72.582 +
  72.583 +         alternation    =  concatenation
  72.584 +                           *(*c-wsp "/" *c-wsp concatenation)
  72.585 +
  72.586 +         concatenation  =  repetition *(1*c-wsp repetition)
  72.587 +
  72.588 +         repetition     =  [repeat] element
  72.589 +
  72.590 +         repeat         =  1*DIGIT / (*DIGIT "*" *DIGIT)
  72.591 +
  72.592 +         element        =  rulename / group / option /
  72.593 +                           char-val / num-val / prose-val
  72.594 +
  72.595 +         group          =  "(" *c-wsp alternation *c-wsp ")"
  72.596 +
  72.597 +         option         =  "[" *c-wsp alternation *c-wsp "]"
  72.598 +
  72.599 +         char-val       =  DQUOTE *(%x20-21 / %x23-7E) DQUOTE
  72.600 +                                ; quoted string of SP and VCHAR
  72.601 +                                ;  without DQUOTE
  72.602 +
  72.603 +         num-val        =  "%" (bin-val / dec-val / hex-val)
  72.604 +
  72.605 +         bin-val        =  "b" 1*BIT
  72.606 +                           [ 1*("." 1*BIT) / ("-" 1*BIT) ]
  72.607 +                                ; series of concatenated bit values
  72.608 +                                ;  or single ONEOF range
  72.609 +
  72.610 +         dec-val        =  "d" 1*DIGIT
  72.611 +                           [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
  72.612 +
  72.613 +         hex-val        =  "x" 1*HEXDIG
  72.614 +                           [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
  72.615 +
  72.616 +
  72.617 +
  72.618 +
  72.619 +
  72.620 +
  72.621 +Crocker & Overell           Standards Track                    [Page 11]
  72.622 +
  72.623 +RFC 5234                          ABNF                      January 2008
  72.624 +
  72.625 +
  72.626 +         prose-val      =  "<" *(%x20-3D / %x3F-7E) ">"
  72.627 +                                ; bracketed string of SP and VCHAR
  72.628 +                                ;  without angles
  72.629 +                                ; prose description, to be used as
  72.630 +                                ;  last resort
  72.631 +
  72.632 +5.  Security Considerations
  72.633 +
  72.634 +   Security is truly believed to be irrelevant to this document.
  72.635 +
  72.636 +6.  References
  72.637 +
  72.638 +6.1.  Normative References
  72.639 +
  72.640 +   [US-ASCII]  American National Standards Institute, "Coded Character
  72.641 +               Set -- 7-bit American Standard Code for Information
  72.642 +               Interchange", ANSI X3.4, 1986.
  72.643 +
  72.644 +6.2.  Informative References
  72.645 +
  72.646 +   [RFC733]    Crocker, D., Vittal, J., Pogran, K., and D. Henderson,
  72.647 +               "Standard for the format of ARPA network text messages",
  72.648 +               RFC 733, November 1977.
  72.649 +
  72.650 +   [RFC822]    Crocker, D., "Standard for the format of ARPA Internet
  72.651 +               text messages", STD 11, RFC 822, August 1982.
  72.652 +
  72.653 +
  72.654 +
  72.655 +
  72.656 +
  72.657 +
  72.658 +
  72.659 +
  72.660 +
  72.661 +
  72.662 +
  72.663 +
  72.664 +
  72.665 +
  72.666 +
  72.667 +
  72.668 +
  72.669 +
  72.670 +
  72.671 +
  72.672 +
  72.673 +
  72.674 +
  72.675 +
  72.676 +
  72.677 +Crocker & Overell           Standards Track                    [Page 12]
  72.678 +
  72.679 +RFC 5234                          ABNF                      January 2008
  72.680 +
  72.681 +
  72.682 +Appendix A.  Acknowledgements
  72.683 +
  72.684 +   The syntax for ABNF was originally specified in RFC 733.  Ken L.
  72.685 +   Harrenstien, of SRI International, was responsible for re-coding the
  72.686 +   BNF into an Augmented BNF that makes the representation smaller and
  72.687 +   easier to understand.
  72.688 +
  72.689 +   This recent project began as a simple effort to cull out the portion
  72.690 +   of RFC 822 that has been repeatedly cited by non-email specification
  72.691 +   writers, namely the description of Augmented BNF.  Rather than simply
  72.692 +   and blindly converting the existing text into a separate document,
  72.693 +   the working group chose to give careful consideration to the
  72.694 +   deficiencies, as well as benefits, of the existing specification and
  72.695 +   related specifications made available over the last 15 years, and
  72.696 +   therefore to pursue enhancement.  This turned the project into
  72.697 +   something rather more ambitious than was first intended.
  72.698 +   Interestingly, the result is not massively different from that
  72.699 +   original, although decisions, such as removing the list notation,
  72.700 +   came as a surprise.
  72.701 +
  72.702 +   This "separated" version of the specification was part of the DRUMS
  72.703 +   working group, with significant contributions from Jerome Abela,
  72.704 +   Harald Alvestrand, Robert Elz, Roger Fajman, Aviva Garrett, Tom
  72.705 +   Harsch, Dan Kohn, Bill McQuillan, Keith Moore, Chris Newman, Pete
  72.706 +   Resnick, and Henning Schulzrinne.
  72.707 +
  72.708 +   Julian Reschke warrants a special thanks for converting the Draft
  72.709 +   Standard version to XML source form.
  72.710 +
  72.711 +Appendix B.  Core ABNF of ABNF
  72.712 +
  72.713 +   This appendix contains some basic rules that are in common use.
  72.714 +   Basic rules are in uppercase.  Note that these rules are only valid
  72.715 +   for ABNF encoded in 7-bit ASCII or in characters sets that are a
  72.716 +   superset of 7-bit ASCII.
  72.717 +
  72.718 +B.1.  Core Rules
  72.719 +
  72.720 +   Certain basic rules are in uppercase, such as SP, HTAB, CRLF, DIGIT,
  72.721 +   ALPHA, etc.
  72.722 +
  72.723 +         ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
  72.724 +
  72.725 +         BIT            =  "0" / "1"
  72.726 +
  72.727 +         CHAR           =  %x01-7F
  72.728 +                                ; any 7-bit US-ASCII character,
  72.729 +                                ;  excluding NUL
  72.730 +
  72.731 +
  72.732 +
  72.733 +Crocker & Overell           Standards Track                    [Page 13]
  72.734 +
  72.735 +RFC 5234                          ABNF                      January 2008
  72.736 +
  72.737 +
  72.738 +         CR             =  %x0D
  72.739 +                                ; carriage return
  72.740 +
  72.741 +         CRLF           =  CR LF
  72.742 +                                ; Internet standard newline
  72.743 +
  72.744 +         CTL            =  %x00-1F / %x7F
  72.745 +                                ; controls
  72.746 +
  72.747 +         DIGIT          =  %x30-39
  72.748 +                                ; 0-9
  72.749 +
  72.750 +         DQUOTE         =  %x22
  72.751 +                                ; " (Double Quote)
  72.752 +
  72.753 +         HEXDIG         =  DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
  72.754 +
  72.755 +         HTAB           =  %x09
  72.756 +                                ; horizontal tab
  72.757 +
  72.758 +         LF             =  %x0A
  72.759 +                                ; linefeed
  72.760 +
  72.761 +         LWSP           =  *(WSP / CRLF WSP)
  72.762 +                                ; Use of this linear-white-space rule
  72.763 +                                ;  permits lines containing only white
  72.764 +                                ;  space that are no longer legal in
  72.765 +                                ;  mail headers and have caused
  72.766 +                                ;  interoperability problems in other
  72.767 +                                ;  contexts.
  72.768 +                                ; Do not use when defining mail
  72.769 +                                ;  headers and use with caution in
  72.770 +                                ;  other contexts.
  72.771 +
  72.772 +         OCTET          =  %x00-FF
  72.773 +                                ; 8 bits of data
  72.774 +
  72.775 +         SP             =  %x20
  72.776 +
  72.777 +         VCHAR          =  %x21-7E
  72.778 +                                ; visible (printing) characters
  72.779 +
  72.780 +         WSP            =  SP / HTAB
  72.781 +                                ; white space
  72.782 +
  72.783 +
  72.784 +
  72.785 +
  72.786 +
  72.787 +
  72.788 +
  72.789 +Crocker & Overell           Standards Track                    [Page 14]
  72.790 +
  72.791 +RFC 5234                          ABNF                      January 2008
  72.792 +
  72.793 +
  72.794 +B.2.  Common Encoding
  72.795 +
  72.796 +   Externally, data are represented as "network virtual ASCII" (namely,
  72.797 +   7-bit US-ASCII in an 8-bit field), with the high (8th) bit set to
  72.798 +   zero.  A string of values is in "network byte order", in which the
  72.799 +   higher-valued bytes are represented on the left-hand side and are
  72.800 +   sent over the network first.
  72.801 +
  72.802 +Authors' Addresses
  72.803 +
  72.804 +   Dave Crocker (editor)
  72.805 +   Brandenburg InternetWorking
  72.806 +   675 Spruce Dr.
  72.807 +   Sunnyvale, CA  94086
  72.808 +   US
  72.809 +
  72.810 +   Phone: +1.408.246.8253
  72.811 +   EMail: dcrocker@bbiw.net
  72.812 +
  72.813 +
  72.814 +   Paul Overell
  72.815 +   THUS plc.
  72.816 +   1/2 Berkeley Square,
  72.817 +   99 Berkeley Street
  72.818 +   Glasgow  G3 7HR
  72.819 +   UK
  72.820 +
  72.821 +   EMail: paul.overell@thus.net
  72.822 +
  72.823 +
  72.824 +
  72.825 +
  72.826 +
  72.827 +
  72.828 +
  72.829 +
  72.830 +
  72.831 +
  72.832 +
  72.833 +
  72.834 +
  72.835 +
  72.836 +
  72.837 +
  72.838 +
  72.839 +
  72.840 +
  72.841 +
  72.842 +
  72.843 +
  72.844 +
  72.845 +Crocker & Overell           Standards Track                    [Page 15]
  72.846 +
  72.847 +RFC 5234                          ABNF                      January 2008
  72.848 +
  72.849 +
  72.850 +Full Copyright Statement
  72.851 +
  72.852 +   Copyright (C) The IETF Trust (2008).
  72.853 +
  72.854 +   This document is subject to the rights, licenses and restrictions
  72.855 +   contained in BCP 78, and except as set forth therein, the authors
  72.856 +   retain all their rights.
  72.857 +
  72.858 +   This document and the information contained herein are provided on an
  72.859 +   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  72.860 +   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  72.861 +   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  72.862 +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  72.863 +   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  72.864 +   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  72.865 +
  72.866 +Intellectual Property
  72.867 +
  72.868 +   The IETF takes no position regarding the validity or scope of any
  72.869 +   Intellectual Property Rights or other rights that might be claimed to
  72.870 +   pertain to the implementation or use of the technology described in
  72.871 +   this document or the extent to which any license under such rights
  72.872 +   might or might not be available; nor does it represent that it has
  72.873 +   made any independent effort to identify any such rights.  Information
  72.874 +   on the procedures with respect to rights in RFC documents can be
  72.875 +   found in BCP 78 and BCP 79.
  72.876 +
  72.877 +   Copies of IPR disclosures made to the IETF Secretariat and any
  72.878 +   assurances of licenses to be made available, or the result of an
  72.879 +   attempt made to obtain a general license or permission for the use of
  72.880 +   such proprietary rights by implementers or users of this
  72.881 +   specification can be obtained from the IETF on-line IPR repository at
  72.882 +   http://www.ietf.org/ipr.
  72.883 +
  72.884 +   The IETF invites any interested party to bring to its attention any
  72.885 +   copyrights, patents or patent applications, or other proprietary
  72.886 +   rights that may cover technology that may be required to implement
  72.887 +   this standard.  Please address the information to the IETF at
  72.888 +   ietf-ipr@ietf.org.
  72.889 +
  72.890 +
  72.891 +
  72.892 +
  72.893 +
  72.894 +
  72.895 +
  72.896 +
  72.897 +
  72.898 +
  72.899 +
  72.900 +
  72.901 +Crocker & Overell           Standards Track                    [Page 16]
  72.902 +
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
    73.3 @@ -0,0 +1,76 @@
    73.4 +# ========================================================================
    73.5 +# Copyright 1988-2006 University of Washington
    73.6 +#
    73.7 +# Licensed under the Apache License, Version 2.0 (the "License");
    73.8 +# you may not use this file except in compliance with the License.
    73.9 +# You may obtain a copy of the License at
   73.10 +#
   73.11 +#     http://www.apache.org/licenses/LICENSE-2.0
   73.12 +#
   73.13 +# 
   73.14 +# ========================================================================
   73.15 +
   73.16 +# Program:	IMAP Toolkit Makefile for Windows 9x and Windows NT
   73.17 +#
   73.18 +# Author:	Mark Crispin
   73.19 +#		Networks and Distributed Computing
   73.20 +#		Computing & Communications
   73.21 +#		University of Washington
   73.22 +#		Administration Building, AG-44
   73.23 +#		Seattle, WA  98195
   73.24 +#		Internet: MRC@CAC.Washington.EDU
   73.25 +#
   73.26 +# Date:		7 December 1989
   73.27 +# Last Edited:	30 August 2006
   73.28 +
   73.29 +
   73.30 +COPY=copy
   73.31 +CD=cd
   73.32 +MAKE=nmake /nologo /f makefile.nt
   73.33 +MKDIR=mkdir
   73.34 +RD=rmdir /s /q
   73.35 +
   73.36 +
   73.37 +# Make the IMAP Toolkit
   73.38 +
   73.39 +build:	c-client mtest mailutil imapd ipopd
   73.40 +	$(CD) c-client
   73.41 +	$(MAKE)
   73.42 +	$(CD) ..\mtest
   73.43 +	$(MAKE)
   73.44 +	$(CD) ..\mailutil
   73.45 +	$(MAKE)
   73.46 +	$(CD) ..\ipopd
   73.47 +	$(MAKE)
   73.48 +	$(CD) ..\imapd
   73.49 +	$(MAKE)
   73.50 +	$(CD) ..
   73.51 +
   73.52 +c-client:
   73.53 +	$(MKDIR) c-client
   73.54 +	$(COPY) src\c-client\*.* c-client
   73.55 +	$(COPY) src\charset\*.* c-client
   73.56 +	$(COPY) src\osdep\nt\*.* c-client
   73.57 +
   73.58 +mtest:
   73.59 +	$(MKDIR) mtest
   73.60 +	$(COPY) src\mtest\*.* mtest
   73.61 +
   73.62 +mailutil:
   73.63 +	$(MKDIR) mailutil
   73.64 +	$(COPY) src\mailutil\*.* mailutil
   73.65 +
   73.66 +ipopd:
   73.67 +	$(MKDIR) ipopd
   73.68 +	$(COPY) src\ipopd\*.* ipopd
   73.69 +
   73.70 +imapd:
   73.71 +	$(MKDIR) imapd
   73.72 +	$(COPY) src\imapd\*.* imapd
   73.73 +
   73.74 +clean:
   73.75 +	$(RD) c-client mtest mailutil ipopd imapd
   73.76 +
   73.77 +# A monument to a hack of long ago and far away...
   73.78 +love:
   73.79 +	@echo 'not war?'
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
    74.3 @@ -0,0 +1,76 @@
    74.4 +# ========================================================================
    74.5 +# Copyright 1988-2006 University of Washington
    74.6 +#
    74.7 +# Licensed under the Apache License, Version 2.0 (the "License");
    74.8 +# you may not use this file except in compliance with the License.
    74.9 +# You may obtain a copy of the License at
   74.10 +#
   74.11 +#     http://www.apache.org/licenses/LICENSE-2.0
   74.12 +#
   74.13 +# 
   74.14 +# ========================================================================
   74.15 +
   74.16 +# Program:	IMAP Toolkit Makefile for Windows 9x and Windows NT + Kerberos
   74.17 +#
   74.18 +# Author:	Mark Crispin
   74.19 +#		Networks and Distributed Computing
   74.20 +#		Computing & Communications
   74.21 +#		University of Washington
   74.22 +#		Administration Building, AG-44
   74.23 +#		Seattle, WA  98195
   74.24 +#		Internet: MRC@CAC.Washington.EDU
   74.25 +#
   74.26 +# Date:		7 December 1989
   74.27 +# Last Edited:	30 August 2006
   74.28 +
   74.29 +
   74.30 +COPY=copy
   74.31 +CD=cd
   74.32 +MAKE=nmake /nologo /f makefile.ntk
   74.33 +MKDIR=mkdir
   74.34 +RD=rmdir /s /q
   74.35 +
   74.36 +
   74.37 +# Make the IMAP Toolkit
   74.38 +
   74.39 +build:	c-client mtest mailutil imapd ipopd
   74.40 +	$(CD) c-client
   74.41 +	$(MAKE)
   74.42 +	$(CD) ..\mtest
   74.43 +	$(MAKE)
   74.44 +	$(CD) ..\mailutil
   74.45 +	$(MAKE)
   74.46 +	$(CD) ..\ipopd
   74.47 +	$(MAKE)
   74.48 +	$(CD) ..\imapd
   74.49 +	$(MAKE)
   74.50 +	$(CD) ..
   74.51 +
   74.52 +c-client:
   74.53 +	$(MKDIR) c-client
   74.54 +	$(COPY) src\c-client\*.* c-client
   74.55 +	$(COPY) src\charset\*.* c-client
   74.56 +	$(COPY) src\osdep\nt\*.* c-client
   74.57 +
   74.58 +mtest:
   74.59 +	$(MKDIR) mtest
   74.60 +	$(COPY) src\mtest\*.* mtest
   74.61 +
   74.62 +mailutil:
   74.63 +	$(MKDIR) mailutil
   74.64 +	$(COPY) src\mailutil\*.* mailutil
   74.65 +
   74.66 +ipopd:
   74.67 +	$(MKDIR) ipopd
   74.68 +	$(COPY) src\ipopd\*.* ipopd
   74.69 +
   74.70 +imapd:
   74.71 +	$(MKDIR) imapd
   74.72 +	$(COPY) src\imapd\*.* imapd
   74.73 +
   74.74 +clean:
   74.75 +	$(RD) c-client mtest mailutil ipopd imapd
   74.76 +
   74.77 +# A monument to a hack of long ago and far away...
   74.78 +love:
   74.79 +	@echo 'not war?'
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/makefile.os2	Mon Sep 14 15:17:45 2009 +0900
    75.3 @@ -0,0 +1,59 @@
    75.4 +# ========================================================================
    75.5 +# Copyright 1988-2006 University of Washington
    75.6 +#
    75.7 +# Licensed under the Apache License, Version 2.0 (the "License");
    75.8 +# you may not use this file except in compliance with the License.
    75.9 +# You may obtain a copy of the License at
   75.10 +#
   75.11 +#     http://www.apache.org/licenses/LICENSE-2.0
   75.12 +#
   75.13 +# 
   75.14 +# ========================================================================
   75.15 +
   75.16 +# Program:	IMAP Toolkit Makefile
   75.17 +#
   75.18 +# Author:	Mark Crispin
   75.19 +#		Networks and Distributed Computing
   75.20 +#		Computing & Communications
   75.21 +#		University of Washington
   75.22 +#		Administration Building, AG-44
   75.23 +#		Seattle, WA  98195
   75.24 +#		Internet: MRC@CAC.Washington.EDU
   75.25 +#
   75.26 +# Date:		7 December 1989
   75.27 +# Last Edited:	30 August 2006
   75.28 +
   75.29 +
   75.30 +COPY=copy
   75.31 +MAKE=make -f makefile.os2
   75.32 +MKDIR=md
   75.33 +RD=rm -rf
   75.34 +
   75.35 +
   75.36 +# Make the IMAP Toolkit
   75.37 +
   75.38 +build:	c-client mtest mailutil
   75.39 +	(cd c-client & $(MAKE))
   75.40 +	(cd mtest & $(MAKE))
   75.41 +	(cd mailutil & $(MAKE))
   75.42 +
   75.43 +c-client:
   75.44 +	$(MKDIR) c-client
   75.45 +	$(COPY) src\c-client\\* c-client
   75.46 +	$(COPY) src\charset\\* c-client
   75.47 +	$(COPY) src\osdep\os2\\* c-client
   75.48 +
   75.49 +mtest:
   75.50 +	$(MKDIR) mtest
   75.51 +	$(COPY) src\mtest\\* mtest
   75.52 +
   75.53 +mailutil:
   75.54 +	$(MKDIR) mailutil
   75.55 +	$(COPY) src\mailutil\\* mailutil
   75.56 +
   75.57 +clean:
   75.58 +	$(RD) c-client mtest mailutil
   75.59 +
   75.60 +# A monument to a hack of long ago and far away...
   75.61 +love:
   75.62 +	@echo 'not war?'
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
    76.3 @@ -0,0 +1,77 @@
    76.4 +# ========================================================================
    76.5 +# Copyright 1988-2006 University of Washington
    76.6 +#
    76.7 +# Licensed under the Apache License, Version 2.0 (the "License");
    76.8 +# you may not use this file except in compliance with the License.
    76.9 +# You may obtain a copy of the License at
   76.10 +#
   76.11 +#     http://www.apache.org/licenses/LICENSE-2.0
   76.12 +#
   76.13 +# 
   76.14 +# ========================================================================
   76.15 +
   76.16 +# Program:	IMAP Toolkit Makefile for Windows 2000/XP
   76.17 +#
   76.18 +# Author:	Mark Crispin
   76.19 +#		Networks and Distributed Computing
   76.20 +#		Computing & Communications
   76.21 +#		University of Washington
   76.22 +#		Administration Building, AG-44
   76.23 +#		Seattle, WA  98195
   76.24 +#		Internet: MRC@CAC.Washington.EDU
   76.25 +#
   76.26 +# Date:		7 December 1989
   76.27 +# Last Edited:	20 August 2006
   76.28 +
   76.29 +
   76.30 +IP=6
   76.31 +COPY=copy
   76.32 +CD=cd
   76.33 +MAKE=nmake /nologo /f makefile.w2k IP=$(IP)
   76.34 +MKDIR=mkdir
   76.35 +RD=rmdir /s /q
   76.36 +
   76.37 +
   76.38 +# Make the IMAP Toolkit
   76.39 +
   76.40 +build:	c-client mtest mailutil imapd ipopd
   76.41 +	$(CD) c-client
   76.42 +	$(MAKE)
   76.43 +	$(CD) ..\mtest
   76.44 +	$(MAKE)
   76.45 +	$(CD) ..\mailutil
   76.46 +	$(MAKE)
   76.47 +	$(CD) ..\ipopd
   76.48 +	$(MAKE)
   76.49 +	$(CD) ..\imapd
   76.50 +	$(MAKE)
   76.51 +	$(CD) ..
   76.52 +
   76.53 +c-client:
   76.54 +	$(MKDIR) c-client
   76.55 +	$(COPY) src\c-client\*.* c-client
   76.56 +	$(COPY) src\charset\*.* c-client
   76.57 +	$(COPY) src\osdep\nt\*.* c-client
   76.58 +
   76.59 +mtest:
   76.60 +	$(MKDIR) mtest
   76.61 +	$(COPY) src\mtest\*.* mtest
   76.62 +
   76.63 +mailutil:
   76.64 +	$(MKDIR) mailutil
   76.65 +	$(COPY) src\mailutil\*.* mailutil
   76.66 +
   76.67 +ipopd:
   76.68 +	$(MKDIR) ipopd
   76.69 +	$(COPY) src\ipopd\*.* ipopd
   76.70 +
   76.71 +imapd:
   76.72 +	$(MKDIR) imapd
   76.73 +	$(COPY) src\imapd\*.* imapd
   76.74 +
   76.75 +clean:
   76.76 +	$(RD) c-client mtest mailutil ipopd imapd
   76.77 +
   76.78 +# A monument to a hack of long ago and far away...
   76.79 +love:
   76.80 +	@echo 'not war?'
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/makefile.wce	Mon Sep 14 15:17:45 2009 +0900
    77.3 @@ -0,0 +1,64 @@
    77.4 +# ========================================================================
    77.5 +# Copyright 1988-2006 University of Washington
    77.6 +#
    77.7 +# Licensed under the Apache License, Version 2.0 (the "License");
    77.8 +# you may not use this file except in compliance with the License.
    77.9 +# You may obtain a copy of the License at
   77.10 +#
   77.11 +#     http://www.apache.org/licenses/LICENSE-2.0
   77.12 +#
   77.13 +# 
   77.14 +# ========================================================================
   77.15 +
   77.16 +# Program:	IMAP Toolkit Makefile
   77.17 +#
   77.18 +# Author:	Mark Crispin
   77.19 +#		Networks and Distributed Computing
   77.20 +#		Computing & Communications
   77.21 +#		University of Washington
   77.22 +#		Administration Building, AG-44
   77.23 +#		Seattle, WA  98195
   77.24 +#		Internet: MRC@CAC.Washington.EDU
   77.25 +#
   77.26 +# Date:		7 December 1989
   77.27 +# Last Edited:	30 August 2006
   77.28 +
   77.29 +
   77.30 +COPY=copy
   77.31 +CD=cd
   77.32 +MAKE=nmake /nologo /f makefile.wce
   77.33 +MKDIR=mkdir
   77.34 +RD=rmdir /s /q
   77.35 +
   77.36 +
   77.37 +# Make the IMAP Toolkit
   77.38 +
   77.39 +build:	c-client mtest mailutil
   77.40 +	$(CD) c-client
   77.41 +	$(MAKE)
   77.42 +#	$(CD) ..\mtest
   77.43 +#	$(MAKE)
   77.44 +#	$(CD) ..\mailutil
   77.45 +#	$(MAKE)
   77.46 +	$(CD) ..
   77.47 +
   77.48 +c-client:
   77.49 +	$(MKDIR) c-client
   77.50 +	$(COPY) src\c-client\*.* c-client
   77.51 +	$(COPY) src\charset\*.* c-client
   77.52 +	$(COPY) src\osdep\wce\*.* c-client
   77.53 +
   77.54 +mtest:
   77.55 +	$(MKDIR) mtest
   77.56 +	$(COPY) src\mtest\*.* mtest
   77.57 +
   77.58 +mailutil:
   77.59 +	$(MKDIR) mailutil
   77.60 +	$(COPY) src\mailutil\*.* mailutil
   77.61 +
   77.62 +clean:
   77.63 +	$(RD) c-client mtest
   77.64 +
   77.65 +# A monument to a hack of long ago and far away...
   77.66 +love:
   77.67 +	@echo 'not war?'
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/src/ansilib/memmove.c	Mon Sep 14 15:17:45 2009 +0900
    78.3 @@ -0,0 +1,40 @@
    78.4 +/* ========================================================================
    78.5 + * Copyright 1988-2006 University of Washington
    78.6 + *
    78.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    78.8 + * you may not use this file except in compliance with the License.
    78.9 + * You may obtain a copy of the License at
   78.10 + *
   78.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   78.12 + *
   78.13 + * 
   78.14 + * ========================================================================
   78.15 + */
   78.16 +
   78.17 +/*
   78.18 + * Program:	Memory move
   78.19 + *
   78.20 + * Author:	Mark Crispin
   78.21 + *		Networks and Distributed Computing
   78.22 + *		Computing & Communications
   78.23 + *		University of Washington
   78.24 + *		Administration Building, AG-44
   78.25 + *		Seattle, WA  98195
   78.26 + *		Internet: MRC@CAC.Washington.EDU
   78.27 + *
   78.28 + * Date:	1 August 1988
   78.29 + * Last Edited:	30 August 2006
   78.30 + */
   78.31 + 
   78.32 +/* Copy memory block
   78.33 + * Accepts: destination pointer
   78.34 + *	    source pointer
   78.35 + *	    length
   78.36 + * Returns: destination pointer
   78.37 + */
   78.38 +
   78.39 +void *memmove (void *s,void *ct,size_t n)
   78.40 +{
   78.41 +  bcopy (ct,s,n);		/* they should have this one */
   78.42 +  return s;
   78.43 +}
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/src/ansilib/memmove2.c	Mon Sep 14 15:17:45 2009 +0900
    79.3 @@ -0,0 +1,49 @@
    79.4 +/* ========================================================================
    79.5 + * Copyright 1988-2006 University of Washington
    79.6 + *
    79.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    79.8 + * you may not use this file except in compliance with the License.
    79.9 + * You may obtain a copy of the License at
   79.10 + *
   79.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   79.12 + *
   79.13 + * 
   79.14 + * ========================================================================
   79.15 + */
   79.16 +
   79.17 +/*
   79.18 + * Program:	Memory move when no bcopy()
   79.19 + *
   79.20 + * Author:	Mark Crispin
   79.21 + *		Networks and Distributed Computing
   79.22 + *		Computing & Communications
   79.23 + *		University of Washington
   79.24 + *		Administration Building, AG-44
   79.25 + *		Seattle, WA  98195
   79.26 + *		Internet: MRC@CAC.Washington.EDU
   79.27 + *
   79.28 + * Date:	11 May 1989
   79.29 + * Last Edited:	30 August 2006
   79.30 + */
   79.31 +
   79.32 +/* Copy memory block
   79.33 + * Accepts: destination pointer
   79.34 + *	    source pointer
   79.35 + *	    length
   79.36 + * Returns: destination pointer
   79.37 + */
   79.38 +
   79.39 +void *memmove (void *s,void *ct,size_t n)
   79.40 +{
   79.41 +  char *dp,*sp;
   79.42 +  int i;
   79.43 +  unsigned long dest = (unsigned long) s;
   79.44 +  unsigned long src = (unsigned long) ct;
   79.45 +  if (((dest < src) && ((dest + n) < src)) ||
   79.46 +      ((dest > src) && ((src + n) < dest))) return (void *) memcpy (s,ct,n);
   79.47 +  dp = (char *) s;
   79.48 +  sp = (char *) ct;
   79.49 +  if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i];
   79.50 +  else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i];
   79.51 +  return s;
   79.52 +}
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/src/ansilib/memset.c	Mon Sep 14 15:17:45 2009 +0900
    80.3 @@ -0,0 +1,40 @@
    80.4 +/* ========================================================================
    80.5 + * Copyright 1988-2006 University of Washington
    80.6 + *
    80.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    80.8 + * you may not use this file except in compliance with the License.
    80.9 + * You may obtain a copy of the License at
   80.10 + *
   80.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   80.12 + *
   80.13 + * 
   80.14 + * ========================================================================
   80.15 + */
   80.16 +
   80.17 +/*
   80.18 + * Program:	Set memory
   80.19 + *
   80.20 + * Author:	Mark Crispin
   80.21 + *		Networks and Distributed Computing
   80.22 + *		Computing & Communications
   80.23 + *		University of Washington
   80.24 + *		Administration Building, AG-44
   80.25 + *		Seattle, WA  98195
   80.26 + *
   80.27 + * Date:	11 May 1989
   80.28 + * Last Edited:	30 August 2006
   80.29 + */
   80.30 +
   80.31 +/* Set a block of memory
   80.32 + * Accepts: destination pointer
   80.33 + *	    value to set
   80.34 + *	    length
   80.35 + * Returns: destination pointer
   80.36 + */
   80.37 +
   80.38 +void *memset (void *s,int c,size_t n)
   80.39 +{
   80.40 +  if (c) while (n) s[--n] = c;	/* this way if non-zero */
   80.41 +  else bzero (s,n);		/* they should have this one */
   80.42 +  return s;
   80.43 +}
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/src/ansilib/strpbrk.c	Mon Sep 14 15:17:45 2009 +0900
    81.3 @@ -0,0 +1,40 @@
    81.4 +/* ========================================================================
    81.5 + * Copyright 1988-2006 University of Washington
    81.6 + *
    81.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    81.8 + * you may not use this file except in compliance with the License.
    81.9 + * You may obtain a copy of the License at
   81.10 + *
   81.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   81.12 + *
   81.13 + * 
   81.14 + * ========================================================================
   81.15 + */
   81.16 +
   81.17 +/*
   81.18 + * Program:	String search for break character
   81.19 + *
   81.20 + * Author:	Mark Crispin
   81.21 + *		Networks and Distributed Computing
   81.22 + *		Computing & Communications
   81.23 + *		University of Washington
   81.24 + *		Administration Building, AG-44
   81.25 + *		Seattle, WA  98195
   81.26 + *
   81.27 + * Date:	11 May 1989
   81.28 + * Last Edited:	30 August 2006
   81.29 + */
   81.30 +
   81.31 +/* Return pointer to first occurance in string of any delimiter
   81.32 + * Accepts: source pointer
   81.33 + *	    vector of delimiters pointer
   81.34 + * Returns: pointer to delimiter or NIL if not found
   81.35 + */
   81.36 +
   81.37 +char *strpbrk (char *cs,char *ct)
   81.38 +{
   81.39 +  char *s;
   81.40 +				/* search for delimiter until end of string */
   81.41 +  for (; *cs; cs++) for (s = ct; *s; s++) if (*s == *cs) return cs;
   81.42 +  return NIL;			/* not found */
   81.43 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/src/ansilib/strstr.c	Mon Sep 14 15:17:45 2009 +0900
    82.3 @@ -0,0 +1,45 @@
    82.4 +/* ========================================================================
    82.5 + * Copyright 1988-2006 University of Washington
    82.6 + *
    82.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    82.8 + * you may not use this file except in compliance with the License.
    82.9 + * You may obtain a copy of the License at
   82.10 + *
   82.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   82.12 + *
   82.13 + * 
   82.14 + * ========================================================================
   82.15 + */
   82.16 +
   82.17 +/*
   82.18 + * Program:	Substring search
   82.19 + *
   82.20 + * Author:	Mark Crispin
   82.21 + *		Networks and Distributed Computing
   82.22 + *		Computing & Communications
   82.23 + *		University of Washington
   82.24 + *		Administration Building, AG-44
   82.25 + *		Seattle, WA  98195
   82.26 + *
   82.27 + * Date:	11 May 1989
   82.28 + * Last Edited:	30 August 2006
   82.29 + */
   82.30 +
   82.31 +/* Return pointer to first occurance in string of a substring
   82.32 + * Accepts: source pointer
   82.33 + *	    substring pointer
   82.34 + * Returns: pointer to substring in source or NIL if not found
   82.35 + */
   82.36 +
   82.37 +char *strstr (char *cs,char *ct)
   82.38 +{
   82.39 +  char *s;
   82.40 +  char *t;
   82.41 +  while (cs = strchr (cs,*ct)) {/* for each occurance of the first character */
   82.42 +				/* see if remainder of string matches */
   82.43 +    for (s = cs + 1, t = ct + 1; *t && *s == *t; s++, t++);
   82.44 +    if (!*t) return cs;		/* if ran out of substring then have match */
   82.45 +    cs++;			/* try from next character */
   82.46 +  }
   82.47 +  return NIL;			/* not found */
   82.48 +}
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/src/ansilib/strtok.c	Mon Sep 14 15:17:45 2009 +0900
    83.3 @@ -0,0 +1,67 @@
    83.4 +/* ========================================================================
    83.5 + * Copyright 1988-2007 University of Washington
    83.6 + *
    83.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    83.8 + * you may not use this file except in compliance with the License.
    83.9 + * You may obtain a copy of the License at
   83.10 + *
   83.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   83.12 + *
   83.13 + * 
   83.14 + * ========================================================================
   83.15 + */
   83.16 +
   83.17 +/*
   83.18 + * Program:	String return successive tokens
   83.19 + *
   83.20 + * Author:	Mark Crispin
   83.21 + *		Networks and Distributed Computing
   83.22 + *		Computing & Communications
   83.23 + *		University of Washington
   83.24 + *		Administration Building, AG-44
   83.25 + *		Seattle, WA  98195
   83.26 + *
   83.27 + * Date:	11 May 1989
   83.28 + * Last Edited:	30 January 2007
   83.29 + */
   83.30 +
   83.31 +/* Find token in string
   83.32 + * Accepts: source pointer or NIL to use previous source
   83.33 + *	    vector of token delimiters pointer
   83.34 + * Returns: pointer to next token
   83.35 + */
   83.36 +
   83.37 +static char *state = NIL;	/* string to locate tokens */
   83.38 +
   83.39 +char *strtok (char *s,char *ct)
   83.40 +{
   83.41 +  return strtok_r (s,ct,&state);/* jacket into reentrant routine */
   83.42 +}
   83.43 +
   83.44 +
   83.45 +/* Find token in string (reentrant)
   83.46 + * Accepts: source pointer or NIL to use previous source
   83.47 + *	    vector of token delimiters pointer
   83.48 + *	    returned state pointer
   83.49 + * Returns: pointer to next token
   83.50 + */
   83.51 +
   83.52 +char *strtok_r (char *s,char *ct,char **r)
   83.53 +{   
   83.54 +  char *t,*ts;
   83.55 +  if (!s) s = *r;		/* use previous token if none specified */
   83.56 +  *r = NIL;			/* default to no returned state */
   83.57 +  if (!(s && *s)) return NIL;	/* no tokens left */
   83.58 +				/* find any leading delimiters */
   83.59 +  do for (t = ct, ts = NIL; *t; t++) if (*t == *s) {
   83.60 +    if (*(ts = ++s)) break;	/* yes, restart search if more in string */
   83.61 +    return NIL;			/* else no more tokens */
   83.62 +  } while (ts);			/* continue until no more leading delimiters */
   83.63 +				/* can we find a new delimiter? */
   83.64 +  for (ts = s; *ts; ts++) for (t = ct; *t; t++) if (*t == *ts) {
   83.65 +    *ts++ = '\0';		/* yes, tie off token at that point */
   83.66 +    *r = ts;			/* save subsequent tokens for future call */
   83.67 +    return s;			/* return our token */
   83.68 +  }
   83.69 +  return s;			/* return final token */
   83.70 +}
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/src/ansilib/strtoul.c	Mon Sep 14 15:17:45 2009 +0900
    84.3 @@ -0,0 +1,73 @@
    84.4 +/* ========================================================================
    84.5 + * Copyright 1988-2006 University of Washington
    84.6 + *
    84.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    84.8 + * you may not use this file except in compliance with the License.
    84.9 + * You may obtain a copy of the License at
   84.10 + *
   84.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   84.12 + *
   84.13 + * 
   84.14 + * ========================================================================
   84.15 + */
   84.16 +
   84.17 +/*
   84.18 + * Program:	String to unsigned long
   84.19 + *
   84.20 + * Author:	Mark Crispin
   84.21 + *		Networks and Distributed Computing
   84.22 + *		Computing & Communications
   84.23 + *		University of Washington
   84.24 + *		Administration Building, AG-44
   84.25 + *		Seattle, WA  98195
   84.26 + *
   84.27 + * Date:	14 February 1995
   84.28 + * Last Edited:	30 August 2006
   84.29 + */
   84.30 +
   84.31 +/*
   84.32 + * Turn a string unsigned long into the real thing
   84.33 + * Accepts: source string
   84.34 + *	    pointer to place to return end pointer
   84.35 + *	    base
   84.36 + * Returns: parsed unsigned long integer, end pointer is updated
   84.37 + */
   84.38 +
   84.39 +unsigned long strtoul (char *t,char **endp,int base)
   84.40 +{
   84.41 +  unsigned long value = 0;	/* the accumulated value */
   84.42 +  int negative = 0;		/* this a negative number? */
   84.43 +  unsigned char c,*s = t;
   84.44 +  if (base && (base < 2 || base > 36)) {
   84.45 +    errno = EINVAL;		/* insist upon valid base */
   84.46 +    return value;
   84.47 +  }
   84.48 +  while (isspace (*s)) s++;	/* skip leading whitespace */
   84.49 +  switch (*s) {			/* check for leading sign char */
   84.50 +  case '-':
   84.51 +    negative = 1;		/* yes, negative #.  fall into '+' */
   84.52 +  case '+':
   84.53 +    s++;			/* skip the sign character */
   84.54 +  }
   84.55 +  if (!base) {			/* base not specified? */
   84.56 +    if (*s != '0') base = 10;	/* must be decimal if doesn't start with 0 */
   84.57 +				/* starts with 0x? */
   84.58 +    else if (tolower (*++s) == 'x') {
   84.59 +      base = 16;		/* yes, is hex */
   84.60 +      s++;			/* skip the x */
   84.61 +    }
   84.62 +    else base = 8;		/* ...or octal */
   84.63 +  }
   84.64 +  do {				/* convert to numeric form if digit */
   84.65 +    if (isdigit (*s)) c = *s - '0';
   84.66 +				/* alphabetic conversion */
   84.67 +    else if (isalpha (*s)) c = *s - (isupper (*s) ? 'A' : 'a') + 10;
   84.68 +    else break;			/* else no way it's valid */
   84.69 +    if (c >= base) break;	/* digit out of range for base? */
   84.70 +    value = value * base + c;	/* accumulate the digit */
   84.71 +  } while (*++s);		/* loop until non-numeric character */
   84.72 +  if (tolower (*s) == 'l') s++;	/* ignore 'l' or 'L' marker */
   84.73 +  if (endp) *endp = s;		/* save users endp to after number */
   84.74 +				/* negate number if needed */
   84.75 +  return negative ? -value : value;
   84.76 +}
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/src/c-client/auth_ext.c	Mon Sep 14 15:17:45 2009 +0900
    85.3 @@ -0,0 +1,96 @@
    85.4 +/* ========================================================================
    85.5 + * Copyright 1988-2006 University of Washington
    85.6 + *
    85.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    85.8 + * you may not use this file except in compliance with the License.
    85.9 + * You may obtain a copy of the License at
   85.10 + *
   85.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   85.12 + *
   85.13 + * 
   85.14 + * ========================================================================
   85.15 + */
   85.16 +
   85.17 +/*
   85.18 + * Program:	EXTERNAL authenticator
   85.19 + *
   85.20 + * Author:	Mark Crispin
   85.21 + *		Networks and Distributed Computing
   85.22 + *		Computing & Communications
   85.23 + *		University of Washington
   85.24 + *		Administration Building, AG-44
   85.25 + *		Seattle, WA  98195
   85.26 + *		Internet: MRC@CAC.Washington.EDU
   85.27 + *
   85.28 + * Date:	6 April 2005
   85.29 + * Last Edited:	30 August 2006
   85.30 + */
   85.31 +
   85.32 +long auth_external_client (authchallenge_t challenger,authrespond_t responder,
   85.33 +			  char *service,NETMBX *mb,void *stream,
   85.34 +			  unsigned long *trial,char *user);
   85.35 +char *auth_external_server (authresponse_t responder,int argc,char *argv[]);
   85.36 +
   85.37 +AUTHENTICATOR auth_ext = {	/* secure, has full auth, hidden */
   85.38 +  AU_SECURE | AU_AUTHUSER | AU_HIDE,
   85.39 +  "EXTERNAL",			/* authenticator name */
   85.40 +  NIL,				/* always valid */
   85.41 +  auth_external_client,		/* client method */
   85.42 +  auth_external_server,		/* server method */
   85.43 +  NIL				/* next authenticator */
   85.44 +};
   85.45 +
   85.46 +/* Client authenticator
   85.47 + * Accepts: challenger function
   85.48 + *	   responder function
   85.49 + *	   SASL service name
   85.50 + *	   parsed network mailbox structure
   85.51 + *	   stream argument for functions
   85.52 + *	   pointer to current trial count
   85.53 + *	   returned user name
   85.54 + * Returns: T if success, NIL otherwise, number of trials incremented if retry
   85.55 + */
   85.56 +
   85.57 +long auth_external_client (authchallenge_t challenger,authrespond_t responder,
   85.58 +			  char *service,NETMBX *mb,void *stream,
   85.59 +			  unsigned long *trial,char *user)
   85.60 +{
   85.61 +  void *challenge;
   85.62 +  unsigned long clen;
   85.63 +  long ret = NIL;
   85.64 +  *trial = 65535;		/* never retry */
   85.65 +  if (challenge = (*challenger) (stream,&clen)) {
   85.66 +    fs_give ((void **) &challenge);
   85.67 +				/* send authorization id (empty string OK) */
   85.68 +    if ((*responder) (stream,strcpy (user,mb->user),strlen (mb->user))) {
   85.69 +      if (challenge = (*challenger) (stream,&clen))
   85.70 +	fs_give ((void **) &challenge);
   85.71 +      else ret = LONGT;		/* check the authentication */
   85.72 +    }
   85.73 +  }
   85.74 +  return ret;
   85.75 +}
   85.76 +
   85.77 +
   85.78 +/* Server authenticator
   85.79 + * Accepts: responder function
   85.80 + *	    argument count
   85.81 + *	    argument vector
   85.82 + * Returns: authenticated user name or NIL
   85.83 + */
   85.84 +
   85.85 +char *auth_external_server (authresponse_t responder,int argc,char *argv[])
   85.86 +{
   85.87 +  unsigned long len;
   85.88 +  char *authid;
   85.89 +  char *authenid = (char *) mail_parameters (NIL,GET_EXTERNALAUTHID,NIL);
   85.90 +  char *ret = NIL;
   85.91 +				/* get authorization identity */
   85.92 +  if (authenid && (authid = (*responder) ("",0,&len))) {
   85.93 +				/* note: responders null-terminate */
   85.94 +    if (*authid ? authserver_login (authid,authenid,argc,argv) :
   85.95 +	authserver_login (authenid,NIL,argc,argv)) ret = myusername ();
   85.96 +    fs_give ((void **) &authid);
   85.97 +  }
   85.98 +  return ret;
   85.99 +}
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/src/c-client/auth_gss.c	Mon Sep 14 15:17:45 2009 +0900
    86.3 @@ -0,0 +1,423 @@
    86.4 +/* ========================================================================
    86.5 + * Copyright 1988-2006 University of Washington
    86.6 + *
    86.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    86.8 + * you may not use this file except in compliance with the License.
    86.9 + * You may obtain a copy of the License at
   86.10 + *
   86.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   86.12 + *
   86.13 + * 
   86.14 + * ========================================================================
   86.15 + */
   86.16 +
   86.17 +/*
   86.18 + * Program:	GSSAPI authenticator
   86.19 + *
   86.20 + * Author:	Mark Crispin
   86.21 + *		Networks and Distributed Computing
   86.22 + *		Computing & Communications
   86.23 + *		University of Washington
   86.24 + *		Administration Building, AG-44
   86.25 + *		Seattle, WA  98195
   86.26 + *		Internet: MRC@CAC.Washington.EDU
   86.27 + *
   86.28 + * Date:	12 January 1998
   86.29 + * Last Edited:	30 August 2006
   86.30 + */
   86.31 +
   86.32 +
   86.33 +long auth_gssapi_valid (void);
   86.34 +long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
   86.35 +			 char *service,NETMBX *mb,void *stream,
   86.36 +			 unsigned long *trial,char *user);
   86.37 +long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
   86.38 +			      authrespond_t responder,char *service,NETMBX *mb,
   86.39 +			      void *stream,char *user,kinit_t ki);
   86.40 +char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]);
   86.41 +
   86.42 +
   86.43 +AUTHENTICATOR auth_gss = {
   86.44 +  AU_SECURE | AU_AUTHUSER,	/* secure authenticator */
   86.45 +  "GSSAPI",			/* authenticator name */
   86.46 +  auth_gssapi_valid,		/* check if valid */
   86.47 +  auth_gssapi_client,		/* client method */
   86.48 +  auth_gssapi_server,		/* server method */
   86.49 +  NIL				/* next authenticator */
   86.50 +};
   86.51 +
   86.52 +#define AUTH_GSSAPI_P_NONE 1
   86.53 +#define AUTH_GSSAPI_P_INTEGRITY 2
   86.54 +#define AUTH_GSSAPI_P_PRIVACY 4
   86.55 +
   86.56 +#define AUTH_GSSAPI_C_MAXSIZE 8192
   86.57 +
   86.58 +#define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y)
   86.59 +
   86.60 +/* Check if GSSAPI valid on this system
   86.61 + * Returns: T if valid, NIL otherwise
   86.62 + */
   86.63 +
   86.64 +long auth_gssapi_valid (void)
   86.65 +{
   86.66 +  char tmp[MAILTMPLEN];
   86.67 +  OM_uint32 smn;
   86.68 +  gss_buffer_desc buf;
   86.69 +  gss_name_t name;
   86.70 +				/* make service name */
   86.71 +  sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
   86.72 +	   mylocalhost ());
   86.73 +  buf.length = strlen (buf.value = tmp);
   86.74 +				/* see if can build a name */
   86.75 +  if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&name) !=
   86.76 +      GSS_S_COMPLETE) return NIL;
   86.77 +				/* remove server method if no keytab */
   86.78 +  if (!kerberos_server_valid ()) auth_gss.server = NIL;
   86.79 +  gss_release_name (&smn,&name);/* finished with name */
   86.80 +  return LONGT;
   86.81 +}
   86.82 +
   86.83 +/* Client authenticator
   86.84 + * Accepts: challenger function
   86.85 + *	    responder function
   86.86 + *	    SASL service name
   86.87 + *	    parsed network mailbox structure
   86.88 + *	    stream argument for functions
   86.89 + *	    pointer to current trial count
   86.90 + *	    returned user name
   86.91 + * Returns: T if success, NIL otherwise, number of trials incremented if retry
   86.92 + */
   86.93 +
   86.94 +long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
   86.95 +			 char *service,NETMBX *mb,void *stream,
   86.96 +			 unsigned long *trial,char *user)
   86.97 +{
   86.98 +  gss_buffer_desc chal;
   86.99 +  kinit_t ki = (kinit_t) mail_parameters (NIL,GET_KINIT,NIL);
  86.100 +  long ret = NIL;
  86.101 +  *trial = 65535;		/* never retry */
  86.102 +				/* get initial (empty) challenge */
  86.103 +  if (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) {
  86.104 +    if (chal.length) {		/* abort if challenge non-empty */
  86.105 +      mm_log ("Server bug: non-empty initial GSSAPI challenge",WARN);
  86.106 +      (*responder) (stream,NIL,0);
  86.107 +      ret = LONGT;		/* will get a BAD response back */
  86.108 +    }
  86.109 +    else if (mb->authuser[0] && strcmp (mb->authuser,myusername ())) {
  86.110 +      mm_log ("Can't use Kerberos: invalid /authuser",WARN);
  86.111 +      (*responder) (stream,NIL,0);
  86.112 +      ret = LONGT;		/* will get a BAD response back */
  86.113 +    }
  86.114 +    else ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
  86.115 +					stream,user,ki);
  86.116 +  }
  86.117 +  return ret;
  86.118 +}
  86.119 +
  86.120 +/* Client authenticator worker function
  86.121 + * Accepts: challenger function
  86.122 + *	    responder function
  86.123 + *	    SASL service name
  86.124 + *	    parsed network mailbox structure
  86.125 + *	    stream argument for functions
  86.126 + *	    returned user name
  86.127 + *	    kinit function pointer if should retry with kinit
  86.128 + * Returns: T if success, NIL otherwise
  86.129 + */
  86.130 +
  86.131 +long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
  86.132 +			      authrespond_t responder,char *service,NETMBX *mb,
  86.133 +			      void *stream,char *user,kinit_t ki)
  86.134 +{
  86.135 +  char tmp[MAILTMPLEN];
  86.136 +  OM_uint32 smj,smn,dsmj,dsmn;
  86.137 +  OM_uint32 mctx = 0;
  86.138 +  gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  86.139 +  gss_buffer_desc resp,buf;
  86.140 +  long i;
  86.141 +  int conf;
  86.142 +  gss_qop_t qop;
  86.143 +  gss_name_t crname = NIL;
  86.144 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  86.145 +  void *data;
  86.146 +  long ret = NIL;
  86.147 +  sprintf (tmp,"%s@%s",service,mb->host);
  86.148 +  buf.length = strlen (buf.value = tmp);
  86.149 +				/* get service name */
  86.150 +  if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) !=
  86.151 +       GSS_S_COMPLETE) {
  86.152 +    mm_log ("Can't import Kerberos service name",WARN);
  86.153 +    (*responder) (stream,NIL,0);
  86.154 +  }
  86.155 +  else {
  86.156 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
  86.157 +				/* negotiate with KDC */
  86.158 +    smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL,
  86.159 +				GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG |
  86.160 +				GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS,
  86.161 +				GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL);
  86.162 +    (*bn) (BLOCK_NONSENSITIVE,data);
  86.163 +
  86.164 +				/* while continuation needed */
  86.165 +    while (smj == GSS_S_CONTINUE_NEEDED) {
  86.166 +      if (chal.value) fs_give ((void **) &chal.value);
  86.167 +				/* send response, get next challenge */
  86.168 +      i = (*responder) (stream,resp.value,resp.length) &&
  86.169 +	(chal.value = (*challenger) (stream,(unsigned long *) &chal.length));
  86.170 +      gss_release_buffer (&smn,&resp);
  86.171 +      if (i) {			/* negotiate continuation with KDC */
  86.172 +	data = (*bn) (BLOCK_SENSITIVE,NIL);
  86.173 +	switch (smj =		/* make sure continuation going OK */
  86.174 +		gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,
  86.175 +				      crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG |
  86.176 +				      GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,
  86.177 +				      GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL,
  86.178 +				      &resp,NIL,NIL)) {
  86.179 +	case GSS_S_CONTINUE_NEEDED:
  86.180 +	case GSS_S_COMPLETE:
  86.181 +	  break;
  86.182 +	default:		/* error, don't need context any more */
  86.183 +	  gss_delete_sec_context (&smn,&ctx,NIL);
  86.184 +	}
  86.185 +	(*bn) (BLOCK_NONSENSITIVE,data);
  86.186 +      }
  86.187 +      else {			/* error in continuation */
  86.188 +	mm_log ("Error in negotiating Kerberos continuation",WARN);
  86.189 +	(*responder) (stream,NIL,0);
  86.190 +				/* don't need context any more */
  86.191 +	gss_delete_sec_context (&smn,&ctx,NIL);
  86.192 +	break;
  86.193 +      }
  86.194 +    }
  86.195 +
  86.196 +    switch (smj) {		/* done - deal with final condition */
  86.197 +    case GSS_S_COMPLETE:
  86.198 +      if (chal.value) fs_give ((void **) &chal.value);
  86.199 +				/* get prot mechanisms and max size */
  86.200 +      if ((*responder) (stream,resp.value ? resp.value : "",resp.length) &&
  86.201 +	  (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&&
  86.202 +	  (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) &&
  86.203 +	  (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){
  86.204 +				/* make copy of flags and length */
  86.205 +	memcpy (tmp,resp.value,4);
  86.206 +	gss_release_buffer (&smn,&resp);
  86.207 +				/* no session protection */
  86.208 +	tmp[0] = AUTH_GSSAPI_P_NONE;
  86.209 +				/* install user name */
  86.210 +	strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ()));
  86.211 +	buf.value = tmp; buf.length = strlen (user) + 4;
  86.212 +				/* successful negotiation */
  86.213 +	switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) {
  86.214 +	case GSS_S_COMPLETE:
  86.215 +	  if ((*responder) (stream,resp.value,resp.length)) ret = T;
  86.216 +	  gss_release_buffer (&smn,&resp);
  86.217 +	  break;
  86.218 +	default:
  86.219 +	  do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
  86.220 +						GSS_C_NO_OID,&mctx,&resp)) {
  86.221 +	  case GSS_S_COMPLETE:
  86.222 +	    mctx = 0;
  86.223 +	  case GSS_S_CONTINUE_NEEDED:
  86.224 +	    sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value);
  86.225 +	    mm_log (tmp,WARN);
  86.226 +	    gss_release_buffer (&dsmn,&resp);
  86.227 +	  }
  86.228 +	  while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.229 +	  do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
  86.230 +						GSS_C_NO_OID,&mctx,&resp)) {
  86.231 +	  case GSS_S_COMPLETE:
  86.232 +	  case GSS_S_CONTINUE_NEEDED:
  86.233 +	    sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
  86.234 +	    mm_log (tmp,WARN);
  86.235 +	    gss_release_buffer (&dsmn,&resp);
  86.236 +	  }
  86.237 +	  while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.238 +	  (*responder) (stream,NIL,0);
  86.239 +	}
  86.240 +      }
  86.241 +				/* flush final challenge */
  86.242 +      if (chal.value) fs_give ((void **) &chal.value);
  86.243 +				/* don't need context any more */
  86.244 +      gss_delete_sec_context (&smn,&ctx,NIL);
  86.245 +      break;
  86.246 +
  86.247 +    case GSS_S_CREDENTIALS_EXPIRED:
  86.248 +      if (chal.value) fs_give ((void **) &chal.value);
  86.249 +				/* retry if application kinits */
  86.250 +      if (ki && (*ki) (mb->host,"Kerberos credentials expired"))
  86.251 +	ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
  86.252 +				       stream,user,NIL);
  86.253 +      else {			/* application can't kinit */
  86.254 +	sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s",
  86.255 +		 mb->host);
  86.256 +	mm_log (tmp,WARN);
  86.257 +	(*responder) (stream,NIL,0);
  86.258 +      }
  86.259 +      break;
  86.260 +    case GSS_S_FAILURE:
  86.261 +      if (chal.value) fs_give ((void **) &chal.value);
  86.262 +      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
  86.263 +					    GSS_C_NO_OID,&mctx,&resp)) {
  86.264 +      case GSS_S_COMPLETE:	/* end of message, can kinit? */
  86.265 +	if (ki && kerberos_try_kinit (smn) &&
  86.266 +	    (*ki) (mb->host,(char *) resp.value)) {
  86.267 +	  gss_release_buffer (&dsmn,&resp);
  86.268 +	  ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
  86.269 +					 stream,user,NIL);
  86.270 +	  break;		/* done */
  86.271 +	}
  86.272 +	else (*responder) (stream,NIL,0);
  86.273 +      case GSS_S_CONTINUE_NEEDED:
  86.274 +	sprintf (tmp,kerberos_try_kinit (smn) ?
  86.275 +		 "Kerberos error: %.80s (try running kinit) for %.80s" :
  86.276 +		 "GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host);
  86.277 +	mm_log (tmp,WARN);
  86.278 +	gss_release_buffer (&dsmn,&resp);
  86.279 +      } while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.280 +      break;
  86.281 +
  86.282 +    default:			/* miscellaneous errors */
  86.283 +      if (chal.value) fs_give ((void **) &chal.value);
  86.284 +      do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
  86.285 +					    GSS_C_NO_OID,&mctx,&resp)) {
  86.286 +      case GSS_S_COMPLETE:
  86.287 +	mctx = 0;
  86.288 +      case GSS_S_CONTINUE_NEEDED:
  86.289 +	sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value);
  86.290 +	mm_log (tmp,WARN);
  86.291 +	gss_release_buffer (&dsmn,&resp);
  86.292 +      }
  86.293 +      while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.294 +      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
  86.295 +					    GSS_C_NO_OID,&mctx,&resp)) {
  86.296 +      case GSS_S_COMPLETE:
  86.297 +      case GSS_S_CONTINUE_NEEDED:
  86.298 +	sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
  86.299 +	mm_log (tmp,WARN);
  86.300 +	gss_release_buffer (&dsmn,&resp);
  86.301 +      }
  86.302 +      while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.303 +      (*responder) (stream,NIL,0);
  86.304 +      break;
  86.305 +    }
  86.306 +				/* finished with credentials name */
  86.307 +    if (crname) gss_release_name (&smn,&crname);
  86.308 +  }
  86.309 +  return ret;			/* return status */
  86.310 +}
  86.311 +
  86.312 +/* Server authenticator
  86.313 + * Accepts: responder function
  86.314 + *	    argument count
  86.315 + *	    argument vector
  86.316 + * Returns: authenticated user name or NIL
  86.317 + */
  86.318 +
  86.319 +char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[])
  86.320 +{
  86.321 +  char *ret = NIL;
  86.322 +  char tmp[MAILTMPLEN];
  86.323 +  unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE);
  86.324 +  int conf;
  86.325 +  OM_uint32 smj,smn,dsmj,dsmn,flags;
  86.326 +  OM_uint32 mctx = 0;
  86.327 +  gss_name_t crname,name;
  86.328 +  gss_OID mech;
  86.329 +  gss_buffer_desc chal,resp,buf;
  86.330 +  gss_cred_id_t crd;
  86.331 +  gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  86.332 +  gss_qop_t qop = GSS_C_QOP_DEFAULT;
  86.333 +				/* make service name */
  86.334 +  sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
  86.335 +	   tcp_serverhost ());
  86.336 +  buf.length = strlen (buf.value = tmp);
  86.337 +				/* acquire credentials */
  86.338 +  if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) ==
  86.339 +      GSS_S_COMPLETE) {
  86.340 +    if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL))
  86.341 +	== GSS_S_COMPLETE) {
  86.342 +      if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) {
  86.343 +	do {			/* negotiate authentication */
  86.344 +	  smj = gss_accept_sec_context (&smn,&ctx,crd,&resp,
  86.345 +					GSS_C_NO_CHANNEL_BINDINGS,&name,&mech,
  86.346 +					&chal,&flags,NIL,NIL);
  86.347 +				/* don't need response any more */
  86.348 +	  fs_give ((void **) &resp.value);
  86.349 +	  switch (smj) {	/* how did it go? */
  86.350 +	  case GSS_S_COMPLETE:	/* successful */
  86.351 +	  case GSS_S_CONTINUE_NEEDED:
  86.352 +	    if (chal.value) {	/* send challenge, get next response */
  86.353 +	      resp.value = (*responder) (chal.value,chal.length,
  86.354 +					 (unsigned long *) &resp.length);
  86.355 +	      gss_release_buffer (&smn,&chal);
  86.356 +	    }
  86.357 +	    break;
  86.358 +	  }
  86.359 +	}
  86.360 +	while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED));
  86.361 +
  86.362 +				/* successful exchange? */
  86.363 +	if ((smj == GSS_S_COMPLETE) &&
  86.364 +	    (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) {
  86.365 +				/* send security and size */
  86.366 +	  memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4);
  86.367 +	  tmp[0] = AUTH_GSSAPI_P_NONE;
  86.368 +	  if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){
  86.369 +	    resp.value = (*responder) (chal.value,chal.length,
  86.370 +				       (unsigned long *) &resp.length);
  86.371 +	    gss_release_buffer (&smn,&chal);
  86.372 +	    if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) {
  86.373 +				/* client request valid */
  86.374 +	      if (chal.value && (chal.length > 4) &&
  86.375 +		  (chal.length < (MAILTMPLEN - 1)) &&
  86.376 +		  memcpy (tmp,chal.value,chal.length) &&
  86.377 +		  (tmp[0] & AUTH_GSSAPI_P_NONE)) {
  86.378 +				/* tie off authorization ID */
  86.379 +		tmp[chal.length] = '\0';
  86.380 +		ret = kerberos_login (tmp+4,buf.value,argc,argv);
  86.381 +	      }
  86.382 +				/* done with user name */
  86.383 +	      gss_release_buffer (&smn,&chal);
  86.384 +	    }
  86.385 +				/* finished with response */
  86.386 +	    fs_give ((void **) &resp.value);
  86.387 +	  }
  86.388 +				/* don't need name buffer any more */
  86.389 +	  gss_release_buffer (&smn,&buf);
  86.390 +	}
  86.391 +				/* don't need client name any more */
  86.392 +	gss_release_name (&smn,&name);
  86.393 +				/* don't need context any more */
  86.394 +	if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL);
  86.395 +      }
  86.396 +				/* finished with credentials */
  86.397 +      gss_release_cred (&smn,&crd);
  86.398 +    }
  86.399 +
  86.400 +    else {			/* can't acquire credentials! */
  86.401 +      if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE)
  86.402 +	SERVER_LOG ("Failed to acquire credentials for %s",buf.value);
  86.403 +      if (smj != GSS_S_FAILURE) do
  86.404 +	switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
  86.405 +					   GSS_C_NO_OID,&mctx,&resp)) {
  86.406 +	case GSS_S_COMPLETE:
  86.407 +	  mctx = 0;
  86.408 +	case GSS_S_CONTINUE_NEEDED:
  86.409 +	  SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value);
  86.410 +	  gss_release_buffer (&dsmn,&resp);
  86.411 +	}
  86.412 +      while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.413 +      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
  86.414 +					    GSS_C_NO_OID,&mctx,&resp)) {
  86.415 +      case GSS_S_COMPLETE:
  86.416 +      case GSS_S_CONTINUE_NEEDED:
  86.417 +	SERVER_LOG ("GSSAPI mechanism status: %s",resp.value);
  86.418 +	gss_release_buffer (&dsmn,&resp);
  86.419 +      }
  86.420 +      while (dsmj == GSS_S_CONTINUE_NEEDED);
  86.421 +    }
  86.422 +				/* finished with credentials name */
  86.423 +    gss_release_name (&smn,&crname);
  86.424 +  }
  86.425 +  return ret;			/* return status */
  86.426 +}
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/src/c-client/auth_log.c	Mon Sep 14 15:17:45 2009 +0900
    87.3 @@ -0,0 +1,117 @@
    87.4 +/* ========================================================================
    87.5 + * Copyright 1988-2006 University of Washington
    87.6 + *
    87.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    87.8 + * you may not use this file except in compliance with the License.
    87.9 + * You may obtain a copy of the License at
   87.10 + *
   87.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   87.12 + *
   87.13 + * 
   87.14 + * ========================================================================
   87.15 + */
   87.16 +
   87.17 +/*
   87.18 + * Program:	Login authenticator
   87.19 + *
   87.20 + * Author:	Mark Crispin
   87.21 + *		Networks and Distributed Computing
   87.22 + *		Computing & Communications
   87.23 + *		University of Washington
   87.24 + *		Administration Building, AG-44
   87.25 + *		Seattle, WA  98195
   87.26 + *		Internet: MRC@CAC.Washington.EDU
   87.27 + *
   87.28 + * Date:	5 December 1995
   87.29 + * Last Edited:	30 August 2006
   87.30 + */
   87.31 +
   87.32 +long auth_login_client (authchallenge_t challenger,authrespond_t responder,
   87.33 +			char *service,NETMBX *mb,void *stream,
   87.34 +			unsigned long *trial,char *user);
   87.35 +char *auth_login_server (authresponse_t responder,int argc,char *argv[]);
   87.36 +
   87.37 +AUTHENTICATOR auth_log = {
   87.38 +  AU_HIDE,			/* hidden */
   87.39 +  "LOGIN",			/* authenticator name */
   87.40 +  NIL,				/* always valid */
   87.41 +  auth_login_client,		/* client method */
   87.42 +  auth_login_server,		/* server method */
   87.43 +  NIL				/* next authenticator */
   87.44 +};
   87.45 +
   87.46 +#define PWD_USER "User Name"
   87.47 +#define PWD_PWD "Password"
   87.48 +
   87.49 +/* Client authenticator
   87.50 + * Accepts: challenger function
   87.51 + *	    responder function
   87.52 + *	    SASL service name
   87.53 + *	    parsed network mailbox structure
   87.54 + *	    stream argument for functions
   87.55 + *	    pointer to current trial count
   87.56 + *	    returned user name
   87.57 + * Returns: T if success, NIL otherwise, number of trials incremented if retry
   87.58 + */
   87.59 +
   87.60 +long auth_login_client (authchallenge_t challenger,authrespond_t responder,
   87.61 +			char *service,NETMBX *mb,void *stream,
   87.62 +			unsigned long *trial,char *user)
   87.63 +{
   87.64 +  char pwd[MAILTMPLEN];
   87.65 +  void *challenge;
   87.66 +  unsigned long clen;
   87.67 +  long ret = NIL;
   87.68 +				/* get user name prompt */
   87.69 +  if (challenge = (*challenger) (stream,&clen)) {
   87.70 +    fs_give ((void **) &challenge);
   87.71 +    pwd[0] = NIL;		/* prompt user */
   87.72 +    mm_login (mb,user,pwd,*trial);
   87.73 +    if (!pwd[0]) {		/* user requested abort */
   87.74 +      (*responder) (stream,NIL,0);
   87.75 +      *trial = 0;		/* cancel subsequent attempts */
   87.76 +      ret = LONGT;		/* will get a BAD response back */
   87.77 +    }
   87.78 +				/* send user name */
   87.79 +    else if ((*responder) (stream,user,strlen (user)) &&
   87.80 +	     (challenge = (*challenger) (stream,&clen))) {
   87.81 +      fs_give ((void **) &challenge);
   87.82 +				/* send password */
   87.83 +      if ((*responder) (stream,pwd,strlen (pwd))) {
   87.84 +	if (challenge = (*challenger) (stream,&clen))
   87.85 +	  fs_give ((void **) &challenge);
   87.86 +	else {
   87.87 +	  ++*trial;		/* can try again if necessary */
   87.88 +	  ret = LONGT;		/* check the authentication */
   87.89 +	}
   87.90 +      }
   87.91 +    }
   87.92 +  }
   87.93 +  memset (pwd,0,MAILTMPLEN);	/* erase password */
   87.94 +  if (!ret) *trial = 65535;	/* don't retry if bad protocol */
   87.95 +  return ret;
   87.96 +}
   87.97 +
   87.98 +
   87.99 +/* Server authenticator
  87.100 + * Accepts: responder function
  87.101 + *	    argument count
  87.102 + *	    argument vector
  87.103 + * Returns: authenticated user name or NIL
  87.104 + */
  87.105 +
  87.106 +char *auth_login_server (authresponse_t responder,int argc,char *argv[])
  87.107 +{
  87.108 +  char *ret = NIL;
  87.109 +  char *user,*pass,*authuser;
  87.110 +  if (user = (*responder) (PWD_USER,sizeof (PWD_USER),NIL)) {
  87.111 +    if (pass = (*responder) (PWD_PWD,sizeof (PWD_PWD),NIL)) {
  87.112 +				/* delimit user from possible admin */
  87.113 +      if (authuser = strchr (user,'*')) *authuser++ = '\0';
  87.114 +      if (server_login (user,pass,authuser,argc,argv)) ret = myusername ();
  87.115 +      fs_give ((void **) &pass);
  87.116 +    }
  87.117 +    fs_give ((void **) &user);
  87.118 +  }
  87.119 +  return ret;
  87.120 +}
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/src/c-client/auth_md5.c	Mon Sep 14 15:17:45 2009 +0900
    88.3 @@ -0,0 +1,495 @@
    88.4 +/* ========================================================================
    88.5 + * Copyright 1988-2007 University of Washington
    88.6 + *
    88.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    88.8 + * you may not use this file except in compliance with the License.
    88.9 + * You may obtain a copy of the License at
   88.10 + *
   88.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   88.12 + *
   88.13 + * 
   88.14 + * ========================================================================
   88.15 + */
   88.16 +
   88.17 +/*
   88.18 + * Program:	CRAM-MD5 authenticator
   88.19 + *
   88.20 + * Author:	Mark Crispin
   88.21 + *		Networks and Distributed Computing
   88.22 + *		Computing & Communications
   88.23 + *		University of Washington
   88.24 + *		Administration Building, AG-44
   88.25 + *		Seattle, WA  98195
   88.26 + *		Internet: MRC@CAC.Washington.EDU
   88.27 + *
   88.28 + * Date:	21 October 1998
   88.29 + * Last Edited:	30 January 2007
   88.30 + */
   88.31 +
   88.32 +/* MD5 context */
   88.33 +
   88.34 +#define MD5BLKLEN 64		/* MD5 block length */
   88.35 +#define MD5DIGLEN 16		/* MD5 digest length */
   88.36 +
   88.37 +typedef struct {
   88.38 +  unsigned long chigh;		/* high 32bits of byte count */
   88.39 +  unsigned long clow;		/* low 32bits of byte count */
   88.40 +  unsigned long state[4];	/* state (ABCD) */
   88.41 +  unsigned char buf[MD5BLKLEN];	/* input buffer */
   88.42 +  unsigned char *ptr;		/* buffer position */
   88.43 +} MD5CONTEXT;
   88.44 +
   88.45 +
   88.46 +/* Prototypes */
   88.47 +
   88.48 +long auth_md5_valid (void);
   88.49 +long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
   88.50 +		      char *service,NETMBX *mb,void *stream,
   88.51 +		      unsigned long *trial,char *user);
   88.52 +char *auth_md5_server (authresponse_t responder,int argc,char *argv[]);
   88.53 +char *auth_md5_pwd (char *user);
   88.54 +char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
   88.55 +char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl);
   88.56 +void md5_init (MD5CONTEXT *ctx);
   88.57 +void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len);
   88.58 +void md5_final (unsigned char *digest,MD5CONTEXT *ctx);
   88.59 +static void md5_transform (unsigned long *state,unsigned char *block);
   88.60 +static void md5_encode (unsigned char *dst,unsigned long *src,int len);
   88.61 +static void md5_decode (unsigned long *dst,unsigned char *src,int len);
   88.62 +
   88.63 +
   88.64 +/* Authenticator linkage */
   88.65 +
   88.66 +AUTHENTICATOR auth_md5 = {
   88.67 +  AU_SECURE,			/* secure authenticator */
   88.68 +  "CRAM-MD5",			/* authenticator name */
   88.69 +  auth_md5_valid,		/* check if valid */
   88.70 +  auth_md5_client,		/* client method */
   88.71 +  auth_md5_server,		/* server method */
   88.72 +  NIL				/* next authenticator */
   88.73 +};
   88.74 +
   88.75 +/* Check if CRAM-MD5 valid on this system
   88.76 + * Returns: T, always
   88.77 + */
   88.78 +
   88.79 +long auth_md5_valid (void)
   88.80 +{
   88.81 +  struct stat sbuf;
   88.82 +				/* server forbids MD5 if no MD5 enable file */
   88.83 +  if (stat (MD5ENABLE,&sbuf)) auth_md5.server = NIL;
   88.84 +  return T;			/* MD5 is otherwise valid */
   88.85 +}
   88.86 +
   88.87 +
   88.88 +/* Client authenticator
   88.89 + * Accepts: challenger function
   88.90 + *	    responder function
   88.91 + *	    SASL service name
   88.92 + *	    parsed network mailbox structure
   88.93 + *	    stream argument for functions
   88.94 + *	    pointer to current trial count
   88.95 + *	    returned user name
   88.96 + * Returns: T if success, NIL otherwise, number of trials incremented if retry
   88.97 + */
   88.98 +
   88.99 +long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
  88.100 +		      char *service,NETMBX *mb,void *stream,
  88.101 +		      unsigned long *trial,char *user)
  88.102 +{
  88.103 +  char pwd[MAILTMPLEN];
  88.104 +  void *challenge;
  88.105 +  unsigned long clen;
  88.106 +  long ret = NIL;
  88.107 +				/* get challenge */
  88.108 +  if (challenge = (*challenger) (stream,&clen)) {
  88.109 +    pwd[0] = NIL;		/* prompt user */
  88.110 +    mm_login (mb,user,pwd,*trial);
  88.111 +    if (!pwd[0]) {		/* user requested abort */
  88.112 +      fs_give ((void **) &challenge);
  88.113 +      (*responder) (stream,NIL,0);
  88.114 +      *trial = 0;		/* cancel subsequent attempts */
  88.115 +      ret = LONGT;		/* will get a BAD response back */
  88.116 +    }
  88.117 +    else {			/* got password, build response */
  88.118 +      sprintf (pwd,"%.65s %.33s",user,hmac_md5 (challenge,clen,
  88.119 +						pwd,strlen (pwd)));
  88.120 +      fs_give ((void **) &challenge);
  88.121 +				/* send credentials, allow retry if OK */
  88.122 +      if ((*responder) (stream,pwd,strlen (pwd))) {
  88.123 +	if (challenge = (*challenger) (stream,&clen))
  88.124 +	  fs_give ((void **) &challenge);
  88.125 +	else {
  88.126 +	  ++*trial;		/* can try again if necessary */
  88.127 +	  ret = LONGT;		/* check the authentication */
  88.128 +	}
  88.129 +      }
  88.130 +    }
  88.131 +  }
  88.132 +  memset (pwd,0,MAILTMPLEN);	/* erase password in case not overwritten */
  88.133 +  if (!ret) *trial = 65535;	/* don't retry if bad protocol */
  88.134 +  return ret;
  88.135 +}
  88.136 +
  88.137 +/* Server authenticator
  88.138 + * Accepts: responder function
  88.139 + *	    argument count
  88.140 + *	    argument vector
  88.141 + * Returns: authenticated user name or NIL
  88.142 + *
  88.143 + * This is much hairier than it needs to be due to the necessary of zapping
  88.144 + * the password data.
  88.145 + */
  88.146 +
  88.147 +static int md5try = MAXLOGINTRIALS;
  88.148 +
  88.149 +char *auth_md5_server (authresponse_t responder,int argc,char *argv[])
  88.150 +{
  88.151 +  char *ret = NIL;
  88.152 +  char *p,*u,*user,*authuser,*hash,chal[MAILTMPLEN];
  88.153 +  unsigned long cl,pl;
  88.154 +				/* generate challenge */
  88.155 +  sprintf (chal,"<%lu.%lu@%s>",(unsigned long) getpid (),
  88.156 +	   (unsigned long) time (0),mylocalhost ());
  88.157 +				/* send challenge, get user and hash */
  88.158 +  if (user = (*responder) (chal,cl = strlen (chal),NIL)) {
  88.159 +				/* got user, locate hash */
  88.160 +    if (hash = strrchr (user,' ')) {
  88.161 +      *hash++ = '\0';		/* tie off user */
  88.162 +				/* see if authentication user */
  88.163 +      if (authuser = strchr (user,'*')) *authuser++ = '\0';
  88.164 +				/* get password */
  88.165 +      if (p = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) {
  88.166 +	pl = strlen (p);
  88.167 +	u = (md5try && !strcmp (hash,hmac_md5 (chal,cl,p,pl))) ? user : NIL;
  88.168 +	memset (p,0,pl);	/* erase sensitive information */
  88.169 +	fs_give ((void **) &p);	/* flush erased password */
  88.170 +				/* now log in for real */
  88.171 +	if (u && authserver_login (u,authuser,argc,argv)) ret = myusername ();
  88.172 +	else if (md5try) --md5try;
  88.173 +      }
  88.174 +    }
  88.175 +    fs_give ((void **) &user);
  88.176 +  }
  88.177 +  if (!ret) sleep (3);		/* slow down possible cracker */
  88.178 +  return ret;
  88.179 +}
  88.180 +
  88.181 +/* Return MD5 password for user
  88.182 + * Accepts: user name
  88.183 + * Returns: plaintext password if success, else NIL
  88.184 + *
  88.185 + * This is much hairier than it needs to be due to the necessary of zapping
  88.186 + * the password data.  That's why we don't use stdio here.
  88.187 + */
  88.188 +
  88.189 +char *auth_md5_pwd (char *user)
  88.190 +{
  88.191 +  struct stat sbuf;
  88.192 +  int fd = open (MD5ENABLE,O_RDONLY,NIL);
  88.193 +  unsigned char *s,*t,*buf,*lusr,*lret;
  88.194 +  char *r;
  88.195 +  char *ret = NIL;
  88.196 +  if (fd >= 0) {		/* found the file? */
  88.197 +    fstat (fd,&sbuf);		/* yes, slurp it into memory */
  88.198 +    read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
  88.199 +				/* see if any uppercase characters in user */
  88.200 +    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
  88.201 +				/* yes, make lowercase copy */
  88.202 +    lusr = *s ? lcase (cpystr (user)) : NIL;
  88.203 +    for (s = strtok_r ((char *) buf,"\015\012",&r),lret = NIL; s;
  88.204 +	 s = ret ? NIL : strtok_r (NIL,"\015\012",&r))
  88.205 +				/* must be valid entry line */
  88.206 +      if (*s && (*s != '#') && (t = strchr (s,'\t')) && t[1]) {
  88.207 +	*t++ = '\0';		/* found tab, tie off user, point to pwd */
  88.208 +	if (!strcmp (s,user)) ret = cpystr (t);
  88.209 +	else if (lusr && !lret) if (!strcmp (s,lusr)) lret = t;
  88.210 +      }
  88.211 +				/* accept case-independent name */
  88.212 +    if (!ret && lret) ret = cpystr (lret);
  88.213 +				/* don't need lowercase copy any more */
  88.214 +    if (lusr) fs_give ((void **) &lusr);
  88.215 +				/* erase sensitive information from buffer */
  88.216 +    memset (buf,0,sbuf.st_size + 1);
  88.217 +    fs_give ((void **) &buf);	/* flush the buffer */
  88.218 +    close (fd);			/* don't need file any longer */
  88.219 +  }
  88.220 +  return ret;			/* return password */
  88.221 +}
  88.222 +
  88.223 +/* APOP server login
  88.224 + * Accepts: challenge
  88.225 + *	    desired user name
  88.226 + *	    purported MD5
  88.227 + *	    argument count
  88.228 + *	    argument vector
  88.229 + * Returns: authenticated user name or NIL
  88.230 + */
  88.231 +
  88.232 +char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[])
  88.233 +{
  88.234 +  int i,j;
  88.235 +  char *ret = NIL;
  88.236 +  char *s,*authuser,tmp[MAILTMPLEN];
  88.237 +  unsigned char digest[MD5DIGLEN];
  88.238 +  MD5CONTEXT ctx;
  88.239 +  char *hex = "0123456789abcdef";
  88.240 +				/* see if authentication user */
  88.241 +  if (authuser = strchr (user,'*')) *authuser++ = '\0';
  88.242 +				/* get password */
  88.243 +  if (s = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) {
  88.244 +    md5_init (&ctx);		/* initialize MD5 context */
  88.245 +				/* build string to get MD5 digest */
  88.246 +    sprintf (tmp,"%.128s%.128s",chal,s);
  88.247 +    memset (s,0,strlen (s));	/* erase sensitive information */
  88.248 +    fs_give ((void **) &s);	/* flush erased password */
  88.249 +    md5_update (&ctx,(unsigned char *) tmp,strlen (tmp));
  88.250 +    memset (tmp,0,MAILTMPLEN);	/* erase sensitive information */
  88.251 +    md5_final (digest,&ctx);
  88.252 +				/* convert to printable hex */
  88.253 +    for (i = 0, s = tmp; i < MD5DIGLEN; i++) {
  88.254 +      *s++ = hex[(j = digest[i]) >> 4];
  88.255 +      *s++ = hex[j & 0xf];
  88.256 +    }
  88.257 +    *s = '\0';			/* tie off hash text */
  88.258 +    memset (digest,0,MD5DIGLEN);/* erase sensitive information */
  88.259 +    if (md5try && !strcmp (md5,tmp) &&
  88.260 +	authserver_login (user,authuser,argc,argv))
  88.261 +      ret = cpystr (myusername ());
  88.262 +    else if (md5try) --md5try;
  88.263 +    memset (tmp,0,MAILTMPLEN);	/* erase sensitive information */
  88.264 +  }
  88.265 +  if (!ret) sleep (3);		/* slow down possible cracker */
  88.266 +  return ret;
  88.267 +}
  88.268 +
  88.269 +/*
  88.270 + * RFC 2104 HMAC hashing
  88.271 + * Accepts: text to hash
  88.272 + *	    text length
  88.273 + *	    key
  88.274 + *	    key length
  88.275 + * Returns: hash as text, always
  88.276 + */
  88.277 +
  88.278 +char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl)
  88.279 +{
  88.280 +  int i,j;
  88.281 +  static char hshbuf[2*MD5DIGLEN + 1];
  88.282 +  char *s;
  88.283 +  MD5CONTEXT ctx;
  88.284 +  char *hex = "0123456789abcdef";
  88.285 +  unsigned char digest[MD5DIGLEN],k_ipad[MD5BLKLEN+1],k_opad[MD5BLKLEN+1];
  88.286 +  if (kl > MD5BLKLEN) {		/* key longer than pad length? */
  88.287 +    md5_init (&ctx);		/* yes, set key as MD5(key) */
  88.288 +    md5_update (&ctx,(unsigned char *) key,kl);
  88.289 +    md5_final (digest,&ctx);
  88.290 +    key = (char *) digest;
  88.291 +    kl = MD5DIGLEN;
  88.292 +  }
  88.293 +  memcpy (k_ipad,key,kl);	/* store key in pads */
  88.294 +  memset (k_ipad+kl,0,(MD5BLKLEN+1)-kl);
  88.295 +  memcpy (k_opad,k_ipad,MD5BLKLEN+1);
  88.296 +				/* XOR key with ipad and opad values */
  88.297 +  for (i = 0; i < MD5BLKLEN; i++) {
  88.298 +    k_ipad[i] ^= 0x36;
  88.299 +    k_opad[i] ^= 0x5c;
  88.300 +  }
  88.301 +  md5_init (&ctx);		/* inner MD5: hash ipad and text */
  88.302 +  md5_update (&ctx,k_ipad,MD5BLKLEN);
  88.303 +  md5_update (&ctx,(unsigned char *) text,tl);
  88.304 +  md5_final (digest,&ctx);
  88.305 +  md5_init (&ctx);		/* outer MD5: hash opad and inner results */
  88.306 +  md5_update (&ctx,k_opad,MD5BLKLEN);
  88.307 +  md5_update (&ctx,digest,MD5DIGLEN);
  88.308 +  md5_final (digest,&ctx);
  88.309 +				/* convert to printable hex */
  88.310 +  for (i = 0, s = hshbuf; i < MD5DIGLEN; i++) {
  88.311 +    *s++ = hex[(j = digest[i]) >> 4];
  88.312 +    *s++ = hex[j & 0xf];
  88.313 +  }
  88.314 +  *s = '\0';			/* tie off hash text */
  88.315 +  return hshbuf;
  88.316 +}
  88.317 +
  88.318 +/* Everything after this point is derived from the RSA Data Security, Inc.
  88.319 + * MD5 Message-Digest Algorithm
  88.320 + */
  88.321 +
  88.322 +/* You may wonder why these strange "a &= 0xffffffff;" statements are here.
  88.323 + * This is to ensure correct results on machines with a unsigned long size of
  88.324 + * larger than 32 bits.
  88.325 + */
  88.326 +
  88.327 +#define RND1(a,b,c,d,x,s,ac) \
  88.328 + a += ((b & c) | (d & ~b)) + x + (unsigned long) ac; \
  88.329 + a &= 0xffffffff; \
  88.330 + a = b + ((a << s) | (a >> (32 - s)));
  88.331 +
  88.332 +#define RND2(a,b,c,d,x,s,ac) \
  88.333 + a += ((b & d) | (c & ~d)) + x + (unsigned long) ac; \
  88.334 + a &= 0xffffffff; \
  88.335 + a = b + ((a << s) | (a >> (32 - s)));
  88.336 +
  88.337 +#define RND3(a,b,c,d,x,s,ac) \
  88.338 + a += (b ^ c ^ d) + x + (unsigned long) ac; \
  88.339 + a &= 0xffffffff; \
  88.340 + a = b + ((a << s) | (a >> (32 - s)));
  88.341 +
  88.342 +#define RND4(a,b,c,d,x,s,ac) \
  88.343 + a += (c ^ (b | ~d)) + x + (unsigned long) ac; \
  88.344 + a &= 0xffffffff; \
  88.345 + a = b + ((a << s) | (a >> (32 - s)));
  88.346 +
  88.347 +/* Initialize MD5 context
  88.348 + * Accepts: context to initialize
  88.349 + */
  88.350 +
  88.351 +void md5_init (MD5CONTEXT *ctx)
  88.352 +{
  88.353 +  ctx->clow = ctx->chigh = 0;	/* initialize byte count to zero */
  88.354 +				/* initialization constants */
  88.355 +  ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89;
  88.356 +  ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476;
  88.357 +  ctx->ptr = ctx->buf;		/* reset buffer pointer */
  88.358 +}
  88.359 +
  88.360 +
  88.361 +/* MD5 add data to context
  88.362 + * Accepts: context
  88.363 + *	    input data
  88.364 + *	    length of data
  88.365 + */
  88.366 +
  88.367 +void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len)
  88.368 +{
  88.369 +  unsigned long i = (ctx->buf + MD5BLKLEN) - ctx->ptr;
  88.370 +				/* update double precision number of bytes */
  88.371 +  if ((ctx->clow += len) < len) ctx->chigh++;
  88.372 +  while (i <= len) {		/* copy/transform data, 64 bytes at a time */
  88.373 +    memcpy (ctx->ptr,data,i);	/* fill up 64 byte chunk */
  88.374 +    md5_transform (ctx->state,ctx->ptr = ctx->buf);
  88.375 +    data += i,len -= i,i = MD5BLKLEN;
  88.376 +  }
  88.377 +  memcpy (ctx->ptr,data,len);	/* copy final bit of data in buffer */
  88.378 +  ctx->ptr += len;		/* update buffer pointer */
  88.379 +}
  88.380 +
  88.381 +/* MD5 Finalization
  88.382 + * Accepts: destination digest
  88.383 + *	    context
  88.384 + */
  88.385 +
  88.386 +void md5_final (unsigned char *digest,MD5CONTEXT *ctx)
  88.387 +{
  88.388 +  unsigned long i,bits[2];
  88.389 +  bits[0] = ctx->clow << 3;	/* calculate length in bits (before padding) */
  88.390 +  bits[1] = (ctx->chigh << 3) + (ctx->clow >> 29);
  88.391 +  *ctx->ptr++ = 0x80;		/* padding byte */
  88.392 +  if ((i = (ctx->buf + MD5BLKLEN) - ctx->ptr) < 8) {
  88.393 +    memset (ctx->ptr,0,i);	/* pad out buffer with zeros */
  88.394 +    md5_transform (ctx->state,ctx->buf);
  88.395 +				/* pad out with zeros, leaving 8 bytes */
  88.396 +    memset (ctx->buf,0,MD5BLKLEN - 8);
  88.397 +    ctx->ptr = ctx->buf + MD5BLKLEN - 8;
  88.398 +  }
  88.399 +  else if (i -= 8) {		/* need to pad this buffer? */
  88.400 +    memset (ctx->ptr,0,i);	/* yes, pad out with zeros, leaving 8 bytes */
  88.401 +    ctx->ptr += i;
  88.402 +  }
  88.403 +  md5_encode (ctx->ptr,bits,2);	/* make LSB-first length */
  88.404 +  md5_transform (ctx->state,ctx->buf);
  88.405 +				/* store state in digest */
  88.406 +  md5_encode (digest,ctx->state,4);
  88.407 +				/* erase context */
  88.408 +  memset (ctx,0,sizeof (MD5CONTEXT));
  88.409 +}
  88.410 +
  88.411 +/* MD5 basic transformation
  88.412 + * Accepts: state vector
  88.413 + *	    current 64-byte block
  88.414 + */
  88.415 +
  88.416 +static void md5_transform (unsigned long *state,unsigned char *block)
  88.417 +{
  88.418 +  unsigned long a = state[0],b = state[1],c = state[2],d = state[3],x[16];
  88.419 +  md5_decode (x,block,16);	/* decode into 16 longs */
  88.420 +				/* round 1 */
  88.421 +  RND1 (a,b,c,d,x[ 0], 7,0xd76aa478); RND1 (d,a,b,c,x[ 1],12,0xe8c7b756);
  88.422 +  RND1 (c,d,a,b,x[ 2],17,0x242070db); RND1 (b,c,d,a,x[ 3],22,0xc1bdceee);
  88.423 +  RND1 (a,b,c,d,x[ 4], 7,0xf57c0faf); RND1 (d,a,b,c,x[ 5],12,0x4787c62a);
  88.424 +  RND1 (c,d,a,b,x[ 6],17,0xa8304613); RND1 (b,c,d,a,x[ 7],22,0xfd469501);
  88.425 +  RND1 (a,b,c,d,x[ 8], 7,0x698098d8); RND1 (d,a,b,c,x[ 9],12,0x8b44f7af);
  88.426 +  RND1 (c,d,a,b,x[10],17,0xffff5bb1); RND1 (b,c,d,a,x[11],22,0x895cd7be);
  88.427 +  RND1 (a,b,c,d,x[12], 7,0x6b901122); RND1 (d,a,b,c,x[13],12,0xfd987193);
  88.428 +  RND1 (c,d,a,b,x[14],17,0xa679438e); RND1 (b,c,d,a,x[15],22,0x49b40821);
  88.429 +				/* round 2 */
  88.430 +  RND2 (a,b,c,d,x[ 1], 5,0xf61e2562); RND2 (d,a,b,c,x[ 6], 9,0xc040b340);
  88.431 +  RND2 (c,d,a,b,x[11],14,0x265e5a51); RND2 (b,c,d,a,x[ 0],20,0xe9b6c7aa);
  88.432 +  RND2 (a,b,c,d,x[ 5], 5,0xd62f105d); RND2 (d,a,b,c,x[10], 9, 0x2441453);
  88.433 +  RND2 (c,d,a,b,x[15],14,0xd8a1e681); RND2 (b,c,d,a,x[ 4],20,0xe7d3fbc8);
  88.434 +  RND2 (a,b,c,d,x[ 9], 5,0x21e1cde6); RND2 (d,a,b,c,x[14], 9,0xc33707d6);
  88.435 +  RND2 (c,d,a,b,x[ 3],14,0xf4d50d87); RND2 (b,c,d,a,x[ 8],20,0x455a14ed);
  88.436 +  RND2 (a,b,c,d,x[13], 5,0xa9e3e905); RND2 (d,a,b,c,x[ 2], 9,0xfcefa3f8);
  88.437 +  RND2 (c,d,a,b,x[ 7],14,0x676f02d9); RND2 (b,c,d,a,x[12],20,0x8d2a4c8a);
  88.438 +				/* round 3 */
  88.439 +  RND3 (a,b,c,d,x[ 5], 4,0xfffa3942); RND3 (d,a,b,c,x[ 8],11,0x8771f681);
  88.440 +  RND3 (c,d,a,b,x[11],16,0x6d9d6122); RND3 (b,c,d,a,x[14],23,0xfde5380c);
  88.441 +  RND3 (a,b,c,d,x[ 1], 4,0xa4beea44); RND3 (d,a,b,c,x[ 4],11,0x4bdecfa9);
  88.442 +  RND3 (c,d,a,b,x[ 7],16,0xf6bb4b60); RND3 (b,c,d,a,x[10],23,0xbebfbc70);
  88.443 +  RND3 (a,b,c,d,x[13], 4,0x289b7ec6); RND3 (d,a,b,c,x[ 0],11,0xeaa127fa);
  88.444 +  RND3 (c,d,a,b,x[ 3],16,0xd4ef3085); RND3 (b,c,d,a,x[ 6],23, 0x4881d05);
  88.445 +  RND3 (a,b,c,d,x[ 9], 4,0xd9d4d039); RND3 (d,a,b,c,x[12],11,0xe6db99e5);
  88.446 +  RND3 (c,d,a,b,x[15],16,0x1fa27cf8); RND3 (b,c,d,a,x[ 2],23,0xc4ac5665);
  88.447 +				/* round 4 */
  88.448 +  RND4 (a,b,c,d,x[ 0], 6,0xf4292244); RND4 (d,a,b,c,x[ 7],10,0x432aff97);
  88.449 +  RND4 (c,d,a,b,x[14],15,0xab9423a7); RND4 (b,c,d,a,x[ 5],21,0xfc93a039);
  88.450 +  RND4 (a,b,c,d,x[12], 6,0x655b59c3); RND4 (d,a,b,c,x[ 3],10,0x8f0ccc92);
  88.451 +  RND4 (c,d,a,b,x[10],15,0xffeff47d); RND4 (b,c,d,a,x[ 1],21,0x85845dd1);
  88.452 +  RND4 (a,b,c,d,x[ 8], 6,0x6fa87e4f); RND4 (d,a,b,c,x[15],10,0xfe2ce6e0);
  88.453 +  RND4 (c,d,a,b,x[ 6],15,0xa3014314); RND4 (b,c,d,a,x[13],21,0x4e0811a1);
  88.454 +  RND4 (a,b,c,d,x[ 4], 6,0xf7537e82); RND4 (d,a,b,c,x[11],10,0xbd3af235);
  88.455 +  RND4 (c,d,a,b,x[ 2],15,0x2ad7d2bb); RND4 (b,c,d,a,x[ 9],21,0xeb86d391);
  88.456 +				/* update state */
  88.457 +  state[0] += a; state[1] += b; state[2] += c; state[3] += d;
  88.458 +  memset (x,0,sizeof (x));	/* erase sensitive data */
  88.459 +}
  88.460 +
  88.461 +/* You may wonder why these strange "& 0xff" maskings are here.  This is to
  88.462 + * ensure correct results on machines with a char size of larger than 8 bits.
  88.463 + * For example, the KCC compiler on the PDP-10 uses 9-bit chars.
  88.464 + */
  88.465 +
  88.466 +/* MD5 encode unsigned long into LSB-first bytes
  88.467 + * Accepts: destination pointer
  88.468 + *	    source
  88.469 + *	    length of source
  88.470 + */ 
  88.471 +
  88.472 +static void md5_encode (unsigned char *dst,unsigned long *src,int len)
  88.473 +{
  88.474 +  int i;
  88.475 +  for (i = 0; i < len; i++) {
  88.476 +    *dst++ = (unsigned char) (src[i] & 0xff);
  88.477 +    *dst++ = (unsigned char) ((src[i] >> 8) & 0xff);
  88.478 +    *dst++ = (unsigned char) ((src[i] >> 16) & 0xff);
  88.479 +    *dst++ = (unsigned char) ((src[i] >> 24) & 0xff);
  88.480 +  }
  88.481 +}
  88.482 +
  88.483 +
  88.484 +/* MD5 decode LSB-first bytes into unsigned long
  88.485 + * Accepts: destination pointer
  88.486 + *	    source
  88.487 + *	    length of destination
  88.488 + */ 
  88.489 +
  88.490 +static void md5_decode (unsigned long *dst,unsigned char *src,int len)
  88.491 +{
  88.492 +  int i, j;
  88.493 +  for (i = 0, j = 0; i < len; i++, j += 4)
  88.494 +    dst[i] = ((unsigned long) (src[j] & 0xff)) |
  88.495 +      (((unsigned long) (src[j+1] & 0xff)) << 8) |
  88.496 +      (((unsigned long) (src[j+2] & 0xff)) << 16) |
  88.497 +	(((unsigned long) (src[j+3] & 0xff)) << 24);
  88.498 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/src/c-client/auth_pla.c	Mon Sep 14 15:17:45 2009 +0900
    89.3 @@ -0,0 +1,133 @@
    89.4 +/* ========================================================================
    89.5 + * Copyright 1988-2006 University of Washington
    89.6 + *
    89.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    89.8 + * you may not use this file except in compliance with the License.
    89.9 + * You may obtain a copy of the License at
   89.10 + *
   89.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   89.12 + *
   89.13 + * 
   89.14 + * ========================================================================
   89.15 + */
   89.16 +
   89.17 +/*
   89.18 + * Program:	Plain authenticator
   89.19 + *
   89.20 + * Author:	Mark Crispin
   89.21 + *		Networks and Distributed Computing
   89.22 + *		Computing & Communications
   89.23 + *		University of Washington
   89.24 + *		Administration Building, AG-44
   89.25 + *		Seattle, WA  98195
   89.26 + *		Internet: MRC@CAC.Washington.EDU
   89.27 + *
   89.28 + * Date:	22 September 1998
   89.29 + * Last Edited:	30 August 2006
   89.30 + */
   89.31 +
   89.32 +long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
   89.33 +			char *service,NETMBX *mb,void *stream,
   89.34 +			unsigned long *trial,char *user);
   89.35 +char *auth_plain_server (authresponse_t responder,int argc,char *argv[]);
   89.36 +
   89.37 +AUTHENTICATOR auth_pla = {
   89.38 +  AU_AUTHUSER | AU_HIDE,	/* allow authuser, hidden */
   89.39 +  "PLAIN",			/* authenticator name */
   89.40 +  NIL,				/* always valid */
   89.41 +  auth_plain_client,		/* client method */
   89.42 +  auth_plain_server,		/* server method */
   89.43 +  NIL				/* next authenticator */
   89.44 +};
   89.45 +
   89.46 +/* Client authenticator
   89.47 + * Accepts: challenger function
   89.48 + *	    responder function
   89.49 + *	    SASL service name
   89.50 + *	    parsed network mailbox structure
   89.51 + *	    stream argument for functions
   89.52 + *	    pointer to current trial count
   89.53 + *	    returned user name
   89.54 + * Returns: T if success, NIL otherwise, number of trials incremented if retry
   89.55 + */
   89.56 +
   89.57 +long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
   89.58 +			char *service,NETMBX *mb,void *stream,
   89.59 +			unsigned long *trial,char *user)
   89.60 +{
   89.61 +  char *u,pwd[MAILTMPLEN];
   89.62 +  void *challenge;
   89.63 +  unsigned long clen;
   89.64 +  long ret = NIL;
   89.65 +				/* snarl if not SSL/TLS session */
   89.66 +  if (!mb->sslflag && !mb->tlsflag)
   89.67 +    mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN",WARN);
   89.68 +				/* get initial (empty) challenge */
   89.69 +  if (challenge = (*challenger) (stream,&clen)) {
   89.70 +    fs_give ((void **) &challenge);
   89.71 +    if (clen) {			/* abort if challenge non-empty */
   89.72 +      mm_log ("Server bug: non-empty initial PLAIN challenge",WARN);
   89.73 +      (*responder) (stream,NIL,0);
   89.74 +      ret = LONGT;		/* will get a BAD response back */
   89.75 +    }
   89.76 +    pwd[0] = NIL;		/* prompt user if empty challenge */
   89.77 +    mm_login (mb,user,pwd,*trial);
   89.78 +    if (!pwd[0]) {		/* empty challenge or user requested abort */
   89.79 +      (*responder) (stream,NIL,0);
   89.80 +      *trial = 0;		/* cancel subsequent attempts */
   89.81 +      ret = LONGT;		/* will get a BAD response back */
   89.82 +    }
   89.83 +    else {
   89.84 +      unsigned long rlen = 
   89.85 +	strlen (mb->authuser) + strlen (user) + strlen (pwd) + 2;
   89.86 +      char *response = (char *) fs_get (rlen);
   89.87 +      char *t = response;	/* copy authorization id */
   89.88 +      if (mb->authuser[0]) for (u = user; *u; *t++ = *u++);
   89.89 +      *t++ = '\0';		/* delimiting NUL */
   89.90 +				/* copy authentication id */
   89.91 +      for (u = mb->authuser[0] ? mb->authuser : user; *u; *t++ = *u++);
   89.92 +      *t++ = '\0';		/* delimiting NUL */
   89.93 +				/* copy password */
   89.94 +      for (u = pwd; *u; *t++ = *u++);
   89.95 +				/* send credentials */
   89.96 +      if ((*responder) (stream,response,rlen)) {
   89.97 +	if (challenge = (*challenger) (stream,&clen))
   89.98 +	  fs_give ((void **) &challenge);
   89.99 +	else {
  89.100 +	  ++*trial;		/* can try again if necessary */
  89.101 +	  ret = LONGT;		/* check the authentication */
  89.102 +	}
  89.103 +      }
  89.104 +      memset (response,0,rlen);	/* erase credentials */
  89.105 +      fs_give ((void **) &response);
  89.106 +    }
  89.107 +  }
  89.108 +  memset (pwd,0,MAILTMPLEN);	/* erase password */
  89.109 +  if (!ret) *trial = 65535;	/* don't retry if bad protocol */
  89.110 +  return ret;
  89.111 +}
  89.112 +
  89.113 +/* Server authenticator
  89.114 + * Accepts: responder function
  89.115 + *	    argument count
  89.116 + *	    argument vector
  89.117 + * Returns: authenticated user name or NIL
  89.118 + */
  89.119 +
  89.120 +char *auth_plain_server (authresponse_t responder,int argc,char *argv[])
  89.121 +{
  89.122 +  char *ret = NIL;
  89.123 +  char *user,*aid,*pass;
  89.124 +  unsigned long len;
  89.125 +				/* get user name */
  89.126 +  if (aid = (*responder) ("",0,&len)) {
  89.127 +				/* note: responders null-terminate */
  89.128 +    if ((((unsigned long) ((user = aid + strlen (aid) + 1) - aid)) < len) &&
  89.129 +	(((unsigned long) ((pass = user + strlen (user) + 1) - aid)) < len) &&
  89.130 +	(((unsigned long) ((pass + strlen (pass)) - aid)) == len) &&
  89.131 +	(*aid ? server_login (aid,pass,user,argc,argv) :
  89.132 +	 server_login (user,pass,NIL,argc,argv))) ret = myusername ();
  89.133 +    fs_give ((void **) &aid);
  89.134 +  }
  89.135 +  return ret;
  89.136 +}
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/src/c-client/c-client.h	Mon Sep 14 15:17:45 2009 +0900
    90.3 @@ -0,0 +1,55 @@
    90.4 +/* ========================================================================
    90.5 + * Copyright 1988-2006 University of Washington
    90.6 + *
    90.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    90.8 + * you may not use this file except in compliance with the License.
    90.9 + * You may obtain a copy of the License at
   90.10 + *
   90.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   90.12 + *
   90.13 + * 
   90.14 + * ========================================================================
   90.15 + */
   90.16 +
   90.17 +/*
   90.18 + * Program:	c-client master include for application programs
   90.19 + *
   90.20 + * Author:	Mark Crispin
   90.21 + *		Networks and Distributed Computing
   90.22 + *		Computing & Communications
   90.23 + *		University of Washington
   90.24 + *		Administration Building, AG-44
   90.25 + *		Seattle, WA  98195
   90.26 + *		Internet: MRC@CAC.Washington.EDU
   90.27 + *
   90.28 + * Date:	19 May 2000
   90.29 + * Last Edited:	6 December 2006
   90.30 + */
   90.31 +
   90.32 +#ifndef __CCLIENT_H		/* nobody should include this twice... */
   90.33 +#define __CCLIENT_H
   90.34 +
   90.35 +#ifdef __cplusplus		/* help out people who use C++ compilers */
   90.36 +extern "C" {
   90.37 +  /* If you use gcc, you may also have to use -fno-operator-names */
   90.38 +#define private cclientPrivate	/* private to c-client */
   90.39 +#define and cclientAnd		/* C99 doesn't realize that ISO 646 is dead */
   90.40 +#define or cclientOr
   90.41 +#define not cclientNot
   90.42 +#endif
   90.43 +
   90.44 +#include "mail.h"		/* primary interfaces */
   90.45 +#include "osdep.h"		/* OS-dependent routines */
   90.46 +#include "rfc822.h"		/* RFC822 and MIME routines */
   90.47 +#include "smtp.h"		/* SMTP sending routines */
   90.48 +#include "nntp.h"		/* NNTP sending routines */
   90.49 +#include "utf8.h"		/* Unicode and charset routines */
   90.50 +#include "utf8aux.h"		/* Unicode auxillary routines */
   90.51 +#include "misc.h"		/* miscellaneous utility routines */
   90.52 +
   90.53 +#ifdef __cplusplus		/* undo the C++ mischief */
   90.54 +#undef private
   90.55 +}
   90.56 +#endif
   90.57 +
   90.58 +#endif
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/src/c-client/env.h	Mon Sep 14 15:17:45 2009 +0900
    91.3 @@ -0,0 +1,45 @@
    91.4 +/* ========================================================================
    91.5 + * Copyright 1988-2008 University of Washington
    91.6 + *
    91.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    91.8 + * you may not use this file except in compliance with the License.
    91.9 + * You may obtain a copy of the License at
   91.10 + *
   91.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   91.12 + *
   91.13 + * 
   91.14 + * ========================================================================
   91.15 + */
   91.16 +
   91.17 +/*
   91.18 + * Program:	Environment routines
   91.19 + *
   91.20 + * Author:	Mark Crispin
   91.21 + *		UW Technology
   91.22 + *		University of Washington
   91.23 + *		Seattle, WA  98195
   91.24 + *		Internet: MRC@Washington.EDU
   91.25 + *
   91.26 + * Date:	1 August 1988
   91.27 + * Last Edited:	13 February 2008
   91.28 + */
   91.29 +
   91.30 +/* Function prototypes */
   91.31 +
   91.32 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim);
   91.33 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim);
   91.34 +void *env_parameters (long function,void *value);
   91.35 +void rfc822_date (char *date);
   91.36 +void rfc822_timezone (char *s,void *t);
   91.37 +void internal_date (char *date);
   91.38 +long server_input_wait (long seconds);
   91.39 +void server_init (char *server,char *service,char *sasl,
   91.40 +		  void *clkint,void *kodint,void *hupint,void *trmint,
   91.41 +		  void *staint);
   91.42 +long server_login (char *user,char *pass,char *authuser,int argc,char *argv[]);
   91.43 +long authserver_login (char *user,char *authuser,int argc,char *argv[]);
   91.44 +long anonymous_login (int argc,char *argv[]);
   91.45 +char *mylocalhost (void);
   91.46 +char *myhomedir (void);
   91.47 +char *mailboxfile (char *dst,char *name);
   91.48 +MAILSTREAM *default_proto (long type);
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/src/c-client/flstring.c	Mon Sep 14 15:17:45 2009 +0900
    92.3 @@ -0,0 +1,91 @@
    92.4 +/* ========================================================================
    92.5 + * Copyright 1988-2006 University of Washington
    92.6 + *
    92.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    92.8 + * you may not use this file except in compliance with the License.
    92.9 + * You may obtain a copy of the License at
   92.10 + *
   92.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   92.12 + *
   92.13 + * 
   92.14 + * ========================================================================
   92.15 + */
   92.16 +
   92.17 +/*
   92.18 + * Program:	File string routines
   92.19 + *
   92.20 + * Author:	Mark Crispin
   92.21 + *		Networks and Distributed Computing
   92.22 + *		Computing & Communications
   92.23 + *		University of Washington
   92.24 + *		Administration Building, AG-44
   92.25 + *		Seattle, WA  98195
   92.26 + *		Internet: MRC@CAC.Washington.EDU
   92.27 + *
   92.28 + * Date:	15 April 1997
   92.29 + * Last Edited:	6 December 2006
   92.30 + */
   92.31 +
   92.32 +
   92.33 +#include <stdio.h>
   92.34 +#include "mail.h"
   92.35 +#include "flstring.h"
   92.36 +
   92.37 +/* String driver for stdio file strings */
   92.38 +
   92.39 +static void file_string_init (STRING *s,void *data,unsigned long size);
   92.40 +static char file_string_next (STRING *s);
   92.41 +static void file_string_setpos (STRING *s,unsigned long i);
   92.42 +
   92.43 +STRINGDRIVER file_string = {
   92.44 +  file_string_init,		/* initialize string structure */
   92.45 +  file_string_next,		/* get next byte in string structure */
   92.46 +  file_string_setpos		/* set position in string structure */
   92.47 +};
   92.48 +
   92.49 +
   92.50 +/* Initialize mail string structure for file
   92.51 + * Accepts: string structure
   92.52 + *	    pointer to string
   92.53 + *	    size of string
   92.54 + */
   92.55 +
   92.56 +static void file_string_init (STRING *s,void *data,unsigned long size)
   92.57 +{
   92.58 +  s->data = data;		/* note file descriptor */
   92.59 +				/* big enough for one byte */
   92.60 +  s->chunk = s->curpos = (char *) &s->data1;
   92.61 +  s->size = size;		/* data size */
   92.62 +  s->cursize = s->chunksize = 1;/* always call stdio */
   92.63 +  file_string_setpos (s,0);	/* initial offset is 0 */
   92.64 +}
   92.65 +
   92.66 +
   92.67 +/* Get next character from string
   92.68 + * Accepts: string structure
   92.69 + * Returns: character, string structure chunk refreshed
   92.70 + */
   92.71 +
   92.72 +static char file_string_next (STRING *s)
   92.73 +{
   92.74 +  char ret = *s->curpos;
   92.75 +  s->offset++;			/* advance position */
   92.76 +  s->cursize = 1;		/* reset size */
   92.77 +  *s->curpos = (char) getc ((FILE *) s->data);
   92.78 +  return ret;
   92.79 +}
   92.80 +
   92.81 +
   92.82 +/* Set string pointer position
   92.83 + * Accepts: string structure
   92.84 + *	    new position
   92.85 + */
   92.86 +
   92.87 +static void file_string_setpos (STRING *s,unsigned long i)
   92.88 +{
   92.89 +  s->offset = i;		/* note new offset */
   92.90 +  fseek ((FILE *) s->data,i,SEEK_SET);
   92.91 +				/* in case using returnstringstruct hack */
   92.92 +  s->chunk = s->curpos = (char *) &s->data1;
   92.93 +  *s->curpos = (char) getc ((FILE *) s->data);
   92.94 +}
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/src/c-client/flstring.h	Mon Sep 14 15:17:45 2009 +0900
    93.3 @@ -0,0 +1,30 @@
    93.4 +/* ========================================================================
    93.5 + * Copyright 1988-2006 University of Washington
    93.6 + *
    93.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    93.8 + * you may not use this file except in compliance with the License.
    93.9 + * You may obtain a copy of the License at
   93.10 + *
   93.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   93.12 + *
   93.13 + * 
   93.14 + * ========================================================================
   93.15 + */
   93.16 +
   93.17 +/*
   93.18 + * Program:	File string routines
   93.19 + *
   93.20 + * Author:	Mark Crispin
   93.21 + *		Networks and Distributed Computing
   93.22 + *		Computing & Communications
   93.23 + *		University of Washington
   93.24 + *		Administration Building, AG-44
   93.25 + *		Seattle, WA  98195
   93.26 + *		Internet: MRC@CAC.Washington.EDU
   93.27 + *
   93.28 + * Date:	15 April 1997
   93.29 + * Last Edited:	30 August 2006
   93.30 + */
   93.31 +
   93.32 +
   93.33 +extern STRINGDRIVER file_string;
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/src/c-client/fs.h	Mon Sep 14 15:17:45 2009 +0900
    94.3 @@ -0,0 +1,34 @@
    94.4 +/* ========================================================================
    94.5 + * Copyright 1988-2006 University of Washington
    94.6 + *
    94.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    94.8 + * you may not use this file except in compliance with the License.
    94.9 + * You may obtain a copy of the License at
   94.10 + *
   94.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   94.12 + *
   94.13 + * 
   94.14 + * ========================================================================
   94.15 + */
   94.16 +
   94.17 +/*
   94.18 + * Program:	Free storage management routines
   94.19 + *
   94.20 + * Author:	Mark Crispin
   94.21 + *		Networks and Distributed Computing
   94.22 + *		Computing & Communications
   94.23 + *		University of Washington
   94.24 + *		Administration Building, AG-44
   94.25 + *		Seattle, WA  98195
   94.26 + *		Internet: MRC@CAC.Washington.EDU
   94.27 + *
   94.28 + * Date:	1 August 1988
   94.29 + * Last Edited:	30 August 2006
   94.30 + */
   94.31 +
   94.32 +
   94.33 +/* Function prototypes */
   94.34 +
   94.35 +void *fs_get (size_t size);
   94.36 +void fs_resize (void **block,size_t size);
   94.37 +void fs_give (void **block);
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/src/c-client/ftl.h	Mon Sep 14 15:17:45 2009 +0900
    95.3 @@ -0,0 +1,32 @@
    95.4 +/* ========================================================================
    95.5 + * Copyright 1988-2006 University of Washington
    95.6 + *
    95.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    95.8 + * you may not use this file except in compliance with the License.
    95.9 + * You may obtain a copy of the License at
   95.10 + *
   95.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   95.12 + *
   95.13 + * 
   95.14 + * ========================================================================
   95.15 + */
   95.16 +
   95.17 +/*
   95.18 + * Program:	Crash management routines
   95.19 + *
   95.20 + * Author:	Mark Crispin
   95.21 + *		Networks and Distributed Computing
   95.22 + *		Computing & Communications
   95.23 + *		University of Washington
   95.24 + *		Administration Building, AG-44
   95.25 + *		Seattle, WA  98195
   95.26 + *		Internet: MRC@CAC.Washington.EDU
   95.27 + *
   95.28 + * Date:	1 August 1988
   95.29 + * Last Edited:	30 August 2006
   95.30 + */
   95.31 +
   95.32 +
   95.33 +/* Function prototypes */
   95.34 +
   95.35 +void fatal (char *string);
    96.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    96.2 +++ b/src/c-client/imap4r1.c	Mon Sep 14 15:17:45 2009 +0900
    96.3 @@ -0,0 +1,5670 @@
    96.4 +/* ========================================================================
    96.5 + * Copyright 1988-2008 University of Washington
    96.6 + *
    96.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    96.8 + * you may not use this file except in compliance with the License.
    96.9 + * You may obtain a copy of the License at
   96.10 + *
   96.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   96.12 + *
   96.13 + * 
   96.14 + * ========================================================================
   96.15 + */
   96.16 +
   96.17 +/*
   96.18 + * Program:	Interactive Message Access Protocol 4rev1 (IMAP4R1) routines
   96.19 + *
   96.20 + * Author:	Mark Crispin
   96.21 + *		UW Technology
   96.22 + *		University of Washington
   96.23 + *		Seattle, WA  98195
   96.24 + *		Internet: MRC@CAC.Washington.EDU
   96.25 + *
   96.26 + * Date:	15 June 1988
   96.27 + * Last Edited:	8 May 2008
   96.28 + *
   96.29 + * This original version of this file is
   96.30 + * Copyright 1988 Stanford University
   96.31 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
   96.32 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
   96.33 + * Biomedical Research Technology Program of the National Institutes of Health
   96.34 + * under grant number RR-00785.
   96.35 + */
   96.36 +
   96.37 +
   96.38 +#include <ctype.h>
   96.39 +#include <stdio.h>
   96.40 +#include <time.h>
   96.41 +#include "c-client.h"
   96.42 +#include "imap4r1.h"
   96.43 +
   96.44 +/* Parameters */
   96.45 +
   96.46 +#define IMAPLOOKAHEAD 20	/* envelope lookahead */
   96.47 +#define IMAPUIDLOOKAHEAD 1000	/* UID lookahead */
   96.48 +#define IMAPTCPPORT (long) 143	/* assigned TCP contact port */
   96.49 +#define IMAPSSLPORT (long) 993	/* assigned SSL TCP contact port */
   96.50 +#define MAXCOMMAND 1000		/* RFC 2683 guideline for cmd line length */
   96.51 +#define IDLETIMEOUT (long) 30	/* defined in RFC 3501 */
   96.52 +#define MAXSERVERLIT 0x7ffffffe	/* maximum server literal size
   96.53 +				 * must be smaller than 4294967295
   96.54 +				 */
   96.55 +
   96.56 +
   96.57 +/* Parsed reply message from imap_reply */
   96.58 +
   96.59 +typedef struct imap_parsed_reply {
   96.60 +  unsigned char *line;		/* original reply string pointer */
   96.61 +  unsigned char *tag;		/* command tag this reply is for */
   96.62 +  unsigned char *key;		/* reply keyword */
   96.63 +  unsigned char *text;		/* subsequent text */
   96.64 +} IMAPPARSEDREPLY;
   96.65 +
   96.66 +
   96.67 +#define IMAPTMPLEN 16*MAILTMPLEN
   96.68 +
   96.69 +
   96.70 +/* IMAP4 I/O stream local data */
   96.71 +	
   96.72 +typedef struct imap_local {
   96.73 +  NETSTREAM *netstream;		/* TCP I/O stream */
   96.74 +  IMAPPARSEDREPLY reply;	/* last parsed reply */
   96.75 +  MAILSTATUS *stat;		/* status to fill in */
   96.76 +  IMAPCAP cap;			/* server capabilities */
   96.77 +  char *appendmailbox;		/* mailbox being appended to */
   96.78 +  unsigned int uidsearch : 1;	/* UID searching */
   96.79 +  unsigned int byeseen : 1;	/* saw a BYE response */
   96.80 +				/* got implicit capabilities */
   96.81 +  unsigned int gotcapability : 1;
   96.82 +  unsigned int sensitive : 1;	/* sensitive data in progress */
   96.83 +  unsigned int tlsflag : 1;	/* TLS session */
   96.84 +  unsigned int tlssslv23 : 1;	/* TLS using SSLv23 client method */
   96.85 +  unsigned int notlsflag : 1;	/* TLS not used in session */
   96.86 +  unsigned int sslflag : 1;	/* SSL session */
   96.87 +  unsigned int novalidate : 1;	/* certificate not validated */
   96.88 +  unsigned int filter : 1;	/* filter SEARCH/SORT/THREAD results */
   96.89 +  unsigned int loser : 1;	/* server is a loser */
   96.90 +  unsigned int saslcancel : 1;	/* SASL cancelled by protocol */
   96.91 +  long authflags;		/* required flags for authenticators */
   96.92 +  unsigned long sortsize;	/* sort return data size */
   96.93 +  unsigned long *sortdata;	/* sort return data */
   96.94 +  struct {
   96.95 +    unsigned long uid;		/* last UID returned */
   96.96 +    unsigned long msgno;	/* last msgno returned */
   96.97 +  } lastuid;
   96.98 +  NAMESPACE **namespace;	/* namespace return data */
   96.99 +  THREADNODE *threaddata;	/* thread return data */
  96.100 +  char *referral;		/* last referral */
  96.101 +  char *prefix;			/* find prefix */
  96.102 +  char *user;			/* logged-in user */
  96.103 +  char *reform;			/* reformed sequence */
  96.104 +  char tmp[IMAPTMPLEN];		/* temporary buffer */
  96.105 +  SEARCHSET *lookahead;		/* fetch lookahead */
  96.106 +} IMAPLOCAL;
  96.107 +
  96.108 +
  96.109 +/* Convenient access to local data */
  96.110 +
  96.111 +#define LOCAL ((IMAPLOCAL *) stream->local)
  96.112 +
  96.113 +/* Arguments to imap_send() */
  96.114 +
  96.115 +typedef struct imap_argument {
  96.116 +  int type;			/* argument type */
  96.117 +  void *text;			/* argument text */
  96.118 +} IMAPARG;
  96.119 +
  96.120 +
  96.121 +/* imap_send() argument types */
  96.122 +
  96.123 +#define ATOM 0
  96.124 +#define NUMBER 1
  96.125 +#define FLAGS 2
  96.126 +#define ASTRING 3
  96.127 +#define LITERAL 4
  96.128 +#define LIST 5
  96.129 +#define SEARCHPROGRAM 6
  96.130 +#define SORTPROGRAM 7
  96.131 +#define BODYTEXT 8
  96.132 +#define BODYPEEK 9
  96.133 +#define BODYCLOSE 10
  96.134 +#define SEQUENCE 11
  96.135 +#define LISTMAILBOX 12
  96.136 +#define MULTIAPPEND 13
  96.137 +#define SNLIST 14
  96.138 +#define MULTIAPPENDREDO 15
  96.139 +
  96.140 +
  96.141 +/* Append data */
  96.142 +
  96.143 +typedef struct append_data {
  96.144 +  append_t af;
  96.145 +  void *data;
  96.146 +  char *flags;
  96.147 +  char *date;
  96.148 +  STRING *message;
  96.149 +} APPENDDATA;
  96.150 +
  96.151 +/* Function prototypes */
  96.152 +
  96.153 +DRIVER *imap_valid (char *name);
  96.154 +void *imap_parameters (long function,void *value);
  96.155 +void imap_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  96.156 +void imap_list (MAILSTREAM *stream,char *ref,char *pat);
  96.157 +void imap_lsub (MAILSTREAM *stream,char *ref,char *pat);
  96.158 +void imap_list_work (MAILSTREAM *stream,char *cmd,char *ref,char *pat,
  96.159 +		     char *contents);
  96.160 +long imap_subscribe (MAILSTREAM *stream,char *mailbox);
  96.161 +long imap_unsubscribe (MAILSTREAM *stream,char *mailbox);
  96.162 +long imap_create (MAILSTREAM *stream,char *mailbox);
  96.163 +long imap_delete (MAILSTREAM *stream,char *mailbox);
  96.164 +long imap_rename (MAILSTREAM *stream,char *old,char *newname);
  96.165 +long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2);
  96.166 +long imap_status (MAILSTREAM *stream,char *mbx,long flags);
  96.167 +MAILSTREAM *imap_open (MAILSTREAM *stream);
  96.168 +IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb,
  96.169 +			     char *usr,char *tmp);
  96.170 +long imap_anon (MAILSTREAM *stream,char *tmp);
  96.171 +long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr);
  96.172 +long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr);
  96.173 +void *imap_challenge (void *stream,unsigned long *len);
  96.174 +long imap_response (void *stream,char *s,unsigned long size);
  96.175 +void imap_close (MAILSTREAM *stream,long options);
  96.176 +void imap_fast (MAILSTREAM *stream,char *sequence,long flags);
  96.177 +void imap_flags (MAILSTREAM *stream,char *sequence,long flags);
  96.178 +long imap_overview (MAILSTREAM *stream,overview_t ofn);
  96.179 +ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
  96.180 +			  long flags);
  96.181 +long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section,
  96.182 +		   unsigned long first,unsigned long last,STRINGLIST *lines,
  96.183 +		   long flags);
  96.184 +unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno);
  96.185 +unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid);
  96.186 +void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  96.187 +long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
  96.188 +unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
  96.189 +			  SORTPGM *pgm,long flags);
  96.190 +THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset,
  96.191 +			 SEARCHPGM *spg,long flags);
  96.192 +THREADNODE *imap_thread_work (MAILSTREAM *stream,char *type,char *charset,
  96.193 +			      SEARCHPGM *spg,long flags);
  96.194 +long imap_ping (MAILSTREAM *stream);
  96.195 +void imap_check (MAILSTREAM *stream);
  96.196 +long imap_expunge (MAILSTREAM *stream,char *sequence,long options);
  96.197 +long imap_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  96.198 +long imap_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  96.199 +long imap_append_referral (char *mailbox,char *tmp,append_t af,void *data,
  96.200 +			   char *flags,char *date,STRING *message,
  96.201 +			   APPENDDATA *map,long options);
  96.202 +IMAPPARSEDREPLY *imap_append_single (MAILSTREAM *stream,char *mailbox,
  96.203 +				     char *flags,char *date,STRING *message);
  96.204 +
  96.205 +void imap_gc (MAILSTREAM *stream,long gcflags);
  96.206 +void imap_gc_body (BODY *body);
  96.207 +void imap_capability (MAILSTREAM *stream);
  96.208 +long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[]);
  96.209 +
  96.210 +IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[]);
  96.211 +IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s);
  96.212 +long imap_soutr (MAILSTREAM *stream,char *string);
  96.213 +IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s,
  96.214 +				    SIZEDTEXT *as,long wildok,char *limit);
  96.215 +IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
  96.216 +				    STRING *st);
  96.217 +IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base,
  96.218 +				 char **s,SEARCHPGM *pgm,char *limit);
  96.219 +char *imap_send_spgm_trim (char *base,char *s,char *text);
  96.220 +IMAPPARSEDREPLY *imap_send_sset (MAILSTREAM *stream,char *tag,char *base,
  96.221 +				 char **s,SEARCHSET *set,char *prefix,
  96.222 +				 char *limit);
  96.223 +IMAPPARSEDREPLY *imap_send_slist (MAILSTREAM *stream,char *tag,char *base,
  96.224 +				  char **s,char *name,STRINGLIST *list,
  96.225 +				  char *limit);
  96.226 +void imap_send_sdate (char **s,char *name,unsigned short date);
  96.227 +IMAPPARSEDREPLY *imap_reply (MAILSTREAM *stream,char *tag);
  96.228 +IMAPPARSEDREPLY *imap_parse_reply (MAILSTREAM *stream,char *text);
  96.229 +IMAPPARSEDREPLY *imap_fake (MAILSTREAM *stream,char *tag,char *text);
  96.230 +long imap_OK (MAILSTREAM *stream,IMAPPARSEDREPLY *reply);
  96.231 +void imap_parse_unsolicited (MAILSTREAM *stream,IMAPPARSEDREPLY *reply);
  96.232 +void imap_parse_response (MAILSTREAM *stream,char *text,long errflg,long ntfy);
  96.233 +NAMESPACE *imap_parse_namespace (MAILSTREAM *stream,unsigned char **txtptr,
  96.234 +				 IMAPPARSEDREPLY *reply);
  96.235 +THREADNODE *imap_parse_thread (MAILSTREAM *stream,unsigned char **txtptr);
  96.236 +void imap_parse_header (MAILSTREAM *stream,ENVELOPE **env,SIZEDTEXT *hdr,
  96.237 +			STRINGLIST *stl);
  96.238 +void imap_parse_envelope (MAILSTREAM *stream,ENVELOPE **env,
  96.239 +			  unsigned char **txtptr,IMAPPARSEDREPLY *reply);
  96.240 +ADDRESS *imap_parse_adrlist (MAILSTREAM *stream,unsigned char **txtptr,
  96.241 +			     IMAPPARSEDREPLY *reply);
  96.242 +ADDRESS *imap_parse_address (MAILSTREAM *stream,unsigned char **txtptr,
  96.243 +			     IMAPPARSEDREPLY *reply);
  96.244 +void imap_parse_flags (MAILSTREAM *stream,MESSAGECACHE *elt,
  96.245 +		       unsigned char **txtptr);
  96.246 +unsigned long imap_parse_user_flag (MAILSTREAM *stream,char *flag);
  96.247 +unsigned char *imap_parse_astring (MAILSTREAM *stream,unsigned char **txtptr,
  96.248 +			  IMAPPARSEDREPLY *reply,unsigned long *len);
  96.249 +unsigned char *imap_parse_string (MAILSTREAM *stream,unsigned char **txtptr,
  96.250 +				  IMAPPARSEDREPLY *reply,GETS_DATA *md,
  96.251 +				  unsigned long *len,long flags);
  96.252 +void imap_parse_body (GETS_DATA *md,char *seg,unsigned char **txtptr,
  96.253 +		      IMAPPARSEDREPLY *reply);
  96.254 +void imap_parse_body_structure (MAILSTREAM *stream,BODY *body,
  96.255 +				unsigned char **txtptr,IMAPPARSEDREPLY *reply);
  96.256 +PARAMETER *imap_parse_body_parameter (MAILSTREAM *stream,
  96.257 +				      unsigned char **txtptr,
  96.258 +				      IMAPPARSEDREPLY *reply);
  96.259 +void imap_parse_disposition (MAILSTREAM *stream,BODY *body,
  96.260 +			     unsigned char **txtptr,IMAPPARSEDREPLY *reply);
  96.261 +STRINGLIST *imap_parse_language (MAILSTREAM *stream,unsigned char **txtptr,
  96.262 +				 IMAPPARSEDREPLY *reply);
  96.263 +STRINGLIST *imap_parse_stringlist (MAILSTREAM *stream,unsigned char **txtptr,
  96.264 +				   IMAPPARSEDREPLY *reply);
  96.265 +void imap_parse_extension (MAILSTREAM *stream,unsigned char **txtptr,
  96.266 +			   IMAPPARSEDREPLY *reply);
  96.267 +void imap_parse_capabilities (MAILSTREAM *stream,char *t);
  96.268 +IMAPPARSEDREPLY *imap_fetch (MAILSTREAM *stream,char *sequence,long flags);
  96.269 +char *imap_reform_sequence (MAILSTREAM *stream,char *sequence,long flags);
  96.270 +
  96.271 +/* Driver dispatch used by MAIL */
  96.272 +
  96.273 +DRIVER imapdriver = {
  96.274 +  "imap",			/* driver name */
  96.275 +				/* driver flags */
  96.276 +  DR_MAIL|DR_NEWS|DR_NAMESPACE|DR_CRLF|DR_RECYCLE|DR_HALFOPEN,
  96.277 +  (DRIVER *) NIL,		/* next driver */
  96.278 +  imap_valid,			/* mailbox is valid for us */
  96.279 +  imap_parameters,		/* manipulate parameters */
  96.280 +  imap_scan,			/* scan mailboxes */
  96.281 +  imap_list,			/* find mailboxes */
  96.282 +  imap_lsub,			/* find subscribed mailboxes */
  96.283 +  imap_subscribe,		/* subscribe to mailbox */
  96.284 +  imap_unsubscribe,		/* unsubscribe from mailbox */
  96.285 +  imap_create,			/* create mailbox */
  96.286 +  imap_delete,			/* delete mailbox */
  96.287 +  imap_rename,			/* rename mailbox */
  96.288 +  imap_status,			/* status of mailbox */
  96.289 +  imap_open,			/* open mailbox */
  96.290 +  imap_close,			/* close mailbox */
  96.291 +  imap_fast,			/* fetch message "fast" attributes */
  96.292 +  imap_flags,			/* fetch message flags */
  96.293 +  imap_overview,		/* fetch overview */
  96.294 +  imap_structure,		/* fetch message envelopes */
  96.295 +  NIL,				/* fetch message header */
  96.296 +  NIL,				/* fetch message body */
  96.297 +  imap_msgdata,			/* fetch partial message */
  96.298 +  imap_uid,			/* unique identifier */
  96.299 +  imap_msgno,			/* message number */
  96.300 +  imap_flag,			/* modify flags */
  96.301 +  NIL,				/* per-message modify flags */
  96.302 +  imap_search,			/* search for message based on criteria */
  96.303 +  imap_sort,			/* sort messages */
  96.304 +  imap_thread,			/* thread messages */
  96.305 +  imap_ping,			/* ping mailbox to see if still alive */
  96.306 +  imap_check,			/* check for new messages */
  96.307 +  imap_expunge,			/* expunge deleted messages */
  96.308 +  imap_copy,			/* copy messages to another mailbox */
  96.309 +  imap_append,			/* append string message to mailbox */
  96.310 +  imap_gc			/* garbage collect stream */
  96.311 +};
  96.312 +
  96.313 +				/* prototype stream */
  96.314 +MAILSTREAM imapproto = {&imapdriver};
  96.315 +
  96.316 +				/* driver parameters */
  96.317 +static unsigned long imap_maxlogintrials = MAXLOGINTRIALS;
  96.318 +static long imap_lookahead = IMAPLOOKAHEAD;
  96.319 +static long imap_uidlookahead = IMAPUIDLOOKAHEAD;
  96.320 +static long imap_fetchlookaheadlimit = IMAPLOOKAHEAD;
  96.321 +static long imap_defaultport = 0;
  96.322 +static long imap_sslport = 0;
  96.323 +static long imap_tryssl = NIL;
  96.324 +static long imap_prefetch = IMAPLOOKAHEAD;
  96.325 +static long imap_closeonerror = NIL;
  96.326 +static imapenvelope_t imap_envelope = NIL;
  96.327 +static imapreferral_t imap_referral = NIL;
  96.328 +static char *imap_extrahdrs = NIL;
  96.329 +
  96.330 +				/* constants */
  96.331 +static char *hdrheader[] = {
  96.332 +  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-MD5 Content-Disposition Content-Language Content-Location",
  96.333 +  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Disposition Content-Language Content-Location",
  96.334 +  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Language Content-Location",
  96.335 +  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Location",
  96.336 +  "BODY.PEEK[HEADER.FIELDS (Newsgroups"
  96.337 +};
  96.338 +static char *hdrtrailer ="Followup-To References)]";
  96.339 +
  96.340 +/* IMAP validate mailbox
  96.341 + * Accepts: mailbox name
  96.342 + * Returns: our driver if name is valid, NIL otherwise
  96.343 + */
  96.344 +
  96.345 +DRIVER *imap_valid (char *name)
  96.346 +{
  96.347 +  return mail_valid_net (name,&imapdriver,NIL,NIL);
  96.348 +}
  96.349 +
  96.350 +
  96.351 +/* IMAP manipulate driver parameters
  96.352 + * Accepts: function code
  96.353 + *	    function-dependent value
  96.354 + * Returns: function-dependent return value
  96.355 + */
  96.356 +
  96.357 +void *imap_parameters (long function,void *value)
  96.358 +{
  96.359 +  switch ((int) function) {
  96.360 +  case GET_NAMESPACE:
  96.361 +    if (((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->cap.namespace &&
  96.362 +	!((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->namespace)
  96.363 +      imap_send (((MAILSTREAM *) value),"NAMESPACE",NIL);
  96.364 +    value = (void *) &((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->namespace;
  96.365 +    break;
  96.366 +  case GET_THREADERS:
  96.367 +    value = (void *)
  96.368 +      ((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->cap.threader;
  96.369 +    break;
  96.370 +  case SET_FETCHLOOKAHEAD:	/* must use pointer from GET_FETCHLOOKAHEAD */
  96.371 +    fatal ("SET_FETCHLOOKAHEAD not permitted");
  96.372 +  case GET_FETCHLOOKAHEAD:
  96.373 +    value = (void *) &((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->lookahead;
  96.374 +    break;
  96.375 +  case SET_MAXLOGINTRIALS:
  96.376 +    imap_maxlogintrials = (long) value;
  96.377 +    break;
  96.378 +  case GET_MAXLOGINTRIALS:
  96.379 +    value = (void *) imap_maxlogintrials;
  96.380 +    break;
  96.381 +  case SET_LOOKAHEAD:
  96.382 +    imap_lookahead = (long) value;
  96.383 +    break;
  96.384 +  case GET_LOOKAHEAD:
  96.385 +    value = (void *) imap_lookahead;
  96.386 +    break;
  96.387 +  case SET_UIDLOOKAHEAD:
  96.388 +    imap_uidlookahead = (long) value;
  96.389 +    break;
  96.390 +  case GET_UIDLOOKAHEAD:
  96.391 +    value = (void *) imap_uidlookahead;
  96.392 +    break;
  96.393 +
  96.394 +  case SET_IMAPPORT:
  96.395 +    imap_defaultport = (long) value;
  96.396 +    break;
  96.397 +  case GET_IMAPPORT:
  96.398 +    value = (void *) imap_defaultport;
  96.399 +    break;
  96.400 +  case SET_SSLIMAPPORT:
  96.401 +    imap_sslport = (long) value;
  96.402 +    break;
  96.403 +  case GET_SSLIMAPPORT:
  96.404 +    value = (void *) imap_sslport;
  96.405 +    break;
  96.406 +  case SET_PREFETCH:
  96.407 +    imap_prefetch = (long) value;
  96.408 +    break;
  96.409 +  case GET_PREFETCH:
  96.410 +    value = (void *) imap_prefetch;
  96.411 +    break;
  96.412 +  case SET_CLOSEONERROR:
  96.413 +    imap_closeonerror = (long) value;
  96.414 +    break;
  96.415 +  case GET_CLOSEONERROR:
  96.416 +    value = (void *) imap_closeonerror;
  96.417 +    break;
  96.418 +  case SET_IMAPENVELOPE:
  96.419 +    imap_envelope = (imapenvelope_t) value;
  96.420 +    break;
  96.421 +  case GET_IMAPENVELOPE:
  96.422 +    value = (void *) imap_envelope;
  96.423 +    break;
  96.424 +  case SET_IMAPREFERRAL:
  96.425 +    imap_referral = (imapreferral_t) value;
  96.426 +    break;
  96.427 +  case GET_IMAPREFERRAL:
  96.428 +    value = (void *) imap_referral;
  96.429 +    break;
  96.430 +  case SET_IMAPEXTRAHEADERS:
  96.431 +    imap_extrahdrs = (char *) value;
  96.432 +    break;
  96.433 +  case GET_IMAPEXTRAHEADERS:
  96.434 +    value = (void *) imap_extrahdrs;
  96.435 +    break;
  96.436 +  case SET_IMAPTRYSSL:
  96.437 +    imap_tryssl = (long) value;
  96.438 +    break;
  96.439 +  case GET_IMAPTRYSSL:
  96.440 +    value = (void *) imap_tryssl;
  96.441 +    break;
  96.442 +  case SET_FETCHLOOKAHEADLIMIT:
  96.443 +    imap_fetchlookaheadlimit = (long) value;
  96.444 +    break;
  96.445 +  case GET_FETCHLOOKAHEADLIMIT:
  96.446 +    value = (void *) imap_fetchlookaheadlimit;
  96.447 +    break;
  96.448 +
  96.449 +  case SET_IDLETIMEOUT:
  96.450 +    fatal ("SET_IDLETIMEOUT not permitted");
  96.451 +  case GET_IDLETIMEOUT:
  96.452 +    value = (void *) IDLETIMEOUT;
  96.453 +    break;
  96.454 +  default:
  96.455 +    value = NIL;		/* error case */
  96.456 +    break;
  96.457 +  }
  96.458 +  return value;
  96.459 +}
  96.460 +
  96.461 +/* IMAP scan mailboxes
  96.462 + * Accepts: mail stream
  96.463 + *	    reference
  96.464 + *	    pattern to search
  96.465 + *	    string to scan
  96.466 + */
  96.467 +
  96.468 +void imap_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
  96.469 +{
  96.470 +  imap_list_work (stream,"SCAN",ref,pat,contents);
  96.471 +}
  96.472 +
  96.473 +
  96.474 +/* IMAP list mailboxes
  96.475 + * Accepts: mail stream
  96.476 + *	    reference
  96.477 + *	    pattern to search
  96.478 + */
  96.479 +
  96.480 +void imap_list (MAILSTREAM *stream,char *ref,char *pat)
  96.481 +{
  96.482 +  imap_list_work (stream,"LIST",ref,pat,NIL);
  96.483 +}
  96.484 +
  96.485 +
  96.486 +/* IMAP list subscribed mailboxes
  96.487 + * Accepts: mail stream
  96.488 + *	    reference
  96.489 + *	    pattern to search
  96.490 + */
  96.491 +
  96.492 +void imap_lsub (MAILSTREAM *stream,char *ref,char *pat)
  96.493 +{
  96.494 +  void *sdb = NIL;
  96.495 +  char *s,mbx[MAILTMPLEN];
  96.496 +				/* do it on the server */
  96.497 +  imap_list_work (stream,"LSUB",ref,pat,NIL);
  96.498 +  if (*pat == '{') {		/* if remote pattern, must be IMAP */
  96.499 +    if (!imap_valid (pat)) return;
  96.500 +    ref = NIL;			/* good IMAP pattern, punt reference */
  96.501 +  }
  96.502 +				/* if remote reference, must be valid IMAP */
  96.503 +  if (ref && (*ref == '{') && !imap_valid (ref)) return;
  96.504 +				/* kludgy application of reference */
  96.505 +  if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
  96.506 +  else strcpy (mbx,pat);
  96.507 +
  96.508 +  if (s = sm_read (&sdb)) do if (imap_valid (s) && pmatch (s,mbx))
  96.509 +    mm_lsub (stream,NIL,s,NIL);
  96.510 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
  96.511 +}
  96.512 +
  96.513 +/* IMAP find list of mailboxes
  96.514 + * Accepts: mail stream
  96.515 + *	    list command
  96.516 + *	    reference
  96.517 + *	    pattern to search
  96.518 + *	    string to scan
  96.519 + */
  96.520 +
  96.521 +void imap_list_work (MAILSTREAM *stream,char *cmd,char *ref,char *pat,
  96.522 +		     char *contents)
  96.523 +{
  96.524 +  MAILSTREAM *st = stream;
  96.525 +  int pl;
  96.526 +  char *s,prefix[MAILTMPLEN],mbx[MAILTMPLEN];
  96.527 +  IMAPARG *args[4],aref,apat,acont;
  96.528 +  if (ref && *ref) {		/* have a reference? */
  96.529 +    if (!(imap_valid (ref) &&	/* make sure valid IMAP name and open stream */
  96.530 +	  ((stream && LOCAL && LOCAL->netstream) ||
  96.531 +	   (stream = mail_open (NIL,ref,OP_HALFOPEN|OP_SILENT))))) return;
  96.532 +				/* calculate prefix length */
  96.533 +    pl = strchr (ref,'}') + 1 - ref;
  96.534 +    strncpy (prefix,ref,pl);	/* build prefix */
  96.535 +    prefix[pl] = '\0';		/* tie off prefix */
  96.536 +    ref += pl;			/* update reference */
  96.537 +  }
  96.538 +  else {
  96.539 +    if (!(imap_valid (pat) &&	/* make sure valid IMAP name and open stream */
  96.540 +	  ((stream && LOCAL && LOCAL->netstream) ||
  96.541 +	   (stream = mail_open (NIL,pat,OP_HALFOPEN|OP_SILENT))))) return;
  96.542 +				/* calculate prefix length */
  96.543 +    pl = strchr (pat,'}') + 1 - pat;
  96.544 +    strncpy (prefix,pat,pl);	/* build prefix */
  96.545 +    prefix[pl] = '\0';		/* tie off prefix */
  96.546 +    pat += pl;			/* update reference */
  96.547 +  }
  96.548 +  LOCAL->prefix = prefix;	/* note prefix */
  96.549 +  if (contents) {		/* want to do a scan? */
  96.550 +    if (LEVELSCAN (stream)) {	/* make sure permitted */
  96.551 +      args[0] = &aref; args[1] = &apat; args[2] = &acont; args[3] = NIL;
  96.552 +      aref.type = ASTRING; aref.text = (void *) (ref ? ref : "");
  96.553 +      apat.type = LISTMAILBOX; apat.text = (void *) pat;
  96.554 +      acont.type = ASTRING; acont.text = (void *) contents;
  96.555 +      imap_send (stream,cmd,args);
  96.556 +    }
  96.557 +    else mm_log ("Scan not valid on this IMAP server",ERROR);
  96.558 +  }
  96.559 +
  96.560 +  else if (LEVELIMAP4 (stream)){/* easy if IMAP4 */
  96.561 +    args[0] = &aref; args[1] = &apat; args[2] = NIL;
  96.562 +    aref.type = ASTRING; aref.text = (void *) (ref ? ref : "");
  96.563 +    apat.type = LISTMAILBOX; apat.text = (void *) pat;
  96.564 +				/* referrals armed? */
  96.565 +    if (LOCAL->cap.mbx_ref && mail_parameters (stream,GET_IMAPREFERRAL,NIL)) {
  96.566 +				/* yes, convert LIST -> RLIST */
  96.567 +      if (!compare_cstring (cmd,"LIST")) cmd = "RLIST";
  96.568 +				/* and convert LSUB -> RLSUB */
  96.569 +      else if (!compare_cstring (cmd,"LSUB")) cmd = "RLSUB";
  96.570 +    }
  96.571 +    imap_send (stream,cmd,args);
  96.572 +  }
  96.573 +  else if (LEVEL1176 (stream)) {/* convert to IMAP2 format wildcard */
  96.574 +				/* kludgy application of reference */
  96.575 +    if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
  96.576 +    else strcpy (mbx,pat);
  96.577 +    for (s = mbx; *s; s++) if (*s == '%') *s = '*';
  96.578 +    args[0] = &apat; args[1] = NIL;
  96.579 +    apat.type = LISTMAILBOX; apat.text = (void *) mbx;
  96.580 +    if (!(strstr (cmd,"LIST") &&/* if list, try IMAP2bis, then RFC-1176 */
  96.581 +	  strcmp (imap_send (stream,"FIND ALL.MAILBOXES",args)->key,"BAD")) &&
  96.582 +	!strcmp (imap_send (stream,"FIND MAILBOXES",args)->key,"BAD"))
  96.583 +      LOCAL->cap.rfc1176 = NIL;	/* must be RFC-1064 */
  96.584 +  }
  96.585 +  LOCAL->prefix = NIL;		/* no more prefix */
  96.586 +				/* close temporary stream if we made one */
  96.587 +  if (stream != st) mail_close (stream);
  96.588 +}
  96.589 +
  96.590 +/* IMAP subscribe to mailbox
  96.591 + * Accepts: mail stream
  96.592 + *	    mailbox to add to subscription list
  96.593 + * Returns: T on success, NIL on failure
  96.594 + */
  96.595 +
  96.596 +long imap_subscribe (MAILSTREAM *stream,char *mailbox)
  96.597 +{
  96.598 +  MAILSTREAM *st = stream;
  96.599 +  long ret = ((stream && LOCAL && LOCAL->netstream) ||
  96.600 +	      (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT))) ?
  96.601 +		imap_manage (stream,mailbox,LEVELIMAP4 (stream) ?
  96.602 +			     "Subscribe" : "Subscribe Mailbox",NIL) : NIL;
  96.603 +				/* toss out temporary stream */
  96.604 +  if (st != stream) mail_close (stream);
  96.605 +  return ret;
  96.606 +}
  96.607 +
  96.608 +
  96.609 +/* IMAP unsubscribe to mailbox
  96.610 + * Accepts: mail stream
  96.611 + *	    mailbox to delete from manage list
  96.612 + * Returns: T on success, NIL on failure
  96.613 + */
  96.614 +
  96.615 +long imap_unsubscribe (MAILSTREAM *stream,char *mailbox)
  96.616 +{
  96.617 +  MAILSTREAM *st = stream;
  96.618 +  long ret = ((stream && LOCAL && LOCAL->netstream) ||
  96.619 +	      (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT))) ?
  96.620 +		imap_manage (stream,mailbox,LEVELIMAP4 (stream) ?
  96.621 +			     "Unsubscribe" : "Unsubscribe Mailbox",NIL) : NIL;
  96.622 +				/* toss out temporary stream */
  96.623 +  if (st != stream) mail_close (stream);
  96.624 +  return ret;
  96.625 +}
  96.626 +
  96.627 +/* IMAP create mailbox
  96.628 + * Accepts: mail stream
  96.629 + *	    mailbox name to create
  96.630 + * Returns: T on success, NIL on failure
  96.631 + */
  96.632 +
  96.633 +long imap_create (MAILSTREAM *stream,char *mailbox)
  96.634 +{
  96.635 +  return imap_manage (stream,mailbox,"Create",NIL);
  96.636 +}
  96.637 +
  96.638 +
  96.639 +/* IMAP delete mailbox
  96.640 + * Accepts: mail stream
  96.641 + *	    mailbox name to delete
  96.642 + * Returns: T on success, NIL on failure
  96.643 + */
  96.644 +
  96.645 +long imap_delete (MAILSTREAM *stream,char *mailbox)
  96.646 +{
  96.647 +  return imap_manage (stream,mailbox,"Delete",NIL);
  96.648 +}
  96.649 +
  96.650 +
  96.651 +/* IMAP rename mailbox
  96.652 + * Accepts: mail stream
  96.653 + *	    old mailbox name
  96.654 + *	    new mailbox name
  96.655 + * Returns: T on success, NIL on failure
  96.656 + */
  96.657 +
  96.658 +long imap_rename (MAILSTREAM *stream,char *old,char *newname)
  96.659 +{
  96.660 +  return imap_manage (stream,old,"Rename",newname);
  96.661 +}
  96.662 +
  96.663 +/* IMAP manage a mailbox
  96.664 + * Accepts: mail stream
  96.665 + *	    mailbox to manipulate
  96.666 + *	    command to execute
  96.667 + *	    optional second argument
  96.668 + * Returns: T on success, NIL on failure
  96.669 + */
  96.670 +
  96.671 +long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2)
  96.672 +{
  96.673 +  MAILSTREAM *st = stream;
  96.674 +  IMAPPARSEDREPLY *reply;
  96.675 +  long ret = NIL;
  96.676 +  char mbx[MAILTMPLEN],mbx2[MAILTMPLEN];
  96.677 +  IMAPARG *args[3],ambx,amb2;
  96.678 +  imapreferral_t ir =
  96.679 +    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
  96.680 +  ambx.type = amb2.type = ASTRING; ambx.text = (void *) mbx;
  96.681 +  amb2.text = (void *) mbx2;
  96.682 +  args[0] = &ambx; args[1] = args[2] = NIL;
  96.683 +				/* require valid names and open stream */
  96.684 +  if (mail_valid_net (mailbox,&imapdriver,NIL,mbx) &&
  96.685 +      (arg2 ? mail_valid_net (arg2,&imapdriver,NIL,mbx2) : &imapdriver) &&
  96.686 +      ((stream && LOCAL && LOCAL->netstream) ||
  96.687 +       (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT)))) {
  96.688 +    if (arg2) args[1] = &amb2;	/* second arg present? */
  96.689 +    if (!(ret = (imap_OK (stream,reply = imap_send (stream,command,args)))) &&
  96.690 +	ir && LOCAL->referral) {
  96.691 +      long code = -1;
  96.692 +      switch (*command) {	/* which command was it? */
  96.693 +      case 'S': code = REFSUBSCRIBE; break;
  96.694 +      case 'U': code = REFUNSUBSCRIBE; break;
  96.695 +      case 'C': code = REFCREATE; break;
  96.696 +      case 'D': code = REFDELETE; break;
  96.697 +      case 'R': code = REFRENAME; break;
  96.698 +      default:
  96.699 +	fatal ("impossible referral command");
  96.700 +      }
  96.701 +      if ((code >= 0) && (mailbox = (*ir) (stream,LOCAL->referral,code)))
  96.702 +	ret = imap_manage (NIL,mailbox,command,(*command == 'R') ?
  96.703 +			   (mailbox + strlen (mailbox) + 1) : NIL);
  96.704 +    }
  96.705 +    mm_log (reply->text,ret ? NIL : ERROR);
  96.706 +				/* toss out temporary stream */
  96.707 +    if (st != stream) mail_close (stream);
  96.708 +  }
  96.709 +  return ret;
  96.710 +}
  96.711 +
  96.712 +/* IMAP status
  96.713 + * Accepts: mail stream
  96.714 + *	    mailbox name
  96.715 + *	    status flags
  96.716 + * Returns: T on success, NIL on failure
  96.717 + */
  96.718 +
  96.719 +long imap_status (MAILSTREAM *stream,char *mbx,long flags)
  96.720 +{
  96.721 +  IMAPARG *args[3],ambx,aflg;
  96.722 +  char tmp[MAILTMPLEN];
  96.723 +  NETMBX mb;
  96.724 +  unsigned long i;
  96.725 +  long ret = NIL;
  96.726 +  MAILSTREAM *tstream = NIL;
  96.727 +				/* use given stream if (rev1 or halfopen) and
  96.728 +				   right host */
  96.729 +  if (!((stream && (LEVELIMAP4rev1 (stream) || stream->halfopen) &&
  96.730 +	 mail_usable_network_stream (stream,mbx)) ||
  96.731 +	(stream = tstream = mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT))))
  96.732 +    return NIL;
  96.733 +				/* parse mailbox name */
  96.734 +  mail_valid_net_parse (mbx,&mb);
  96.735 +  args[0] = &ambx;args[1] = NIL;/* set up first argument as mailbox */
  96.736 +  ambx.type = ASTRING; ambx.text = (void *) mb.mailbox;
  96.737 +  if (LEVELIMAP4rev1 (stream)) {/* have STATUS command? */
  96.738 +    imapreferral_t ir;
  96.739 +    aflg.type = FLAGS; aflg.text = (void *) tmp;
  96.740 +    args[1] = &aflg; args[2] = NIL;
  96.741 +    tmp[0] = tmp[1] = '\0';	/* build flag list */
  96.742 +    if (flags & SA_MESSAGES) strcat (tmp," MESSAGES");
  96.743 +    if (flags & SA_RECENT) strcat (tmp," RECENT");
  96.744 +    if (flags & SA_UNSEEN) strcat (tmp," UNSEEN");
  96.745 +    if (flags & SA_UIDNEXT) strcat (tmp," UIDNEXT");
  96.746 +    if (flags & SA_UIDVALIDITY) strcat (tmp," UIDVALIDITY");
  96.747 +    tmp[0] = '(';
  96.748 +    strcat (tmp,")");
  96.749 +				/* send "STATUS mailbox flag" */
  96.750 +    if (imap_OK (stream,imap_send (stream,"STATUS",args))) ret = T;
  96.751 +    else if ((ir = (imapreferral_t)
  96.752 +	      mail_parameters (stream,GET_IMAPREFERRAL,NIL)) &&
  96.753 +	     LOCAL->referral &&
  96.754 +	     (mbx = (*ir) (stream,LOCAL->referral,REFSTATUS)))
  96.755 +      ret = imap_status (NIL,mbx,flags | (stream->debug ? SA_DEBUG : NIL));
  96.756 +  }
  96.757 +
  96.758 +				/* IMAP2 way */
  96.759 +  else if (imap_OK (stream,imap_send (stream,"EXAMINE",args))) {
  96.760 +    MAILSTATUS status;
  96.761 +    status.flags = flags & ~ (SA_UIDNEXT | SA_UIDVALIDITY);
  96.762 +    status.messages = stream->nmsgs;
  96.763 +    status.recent = stream->recent;
  96.764 +    status.unseen = 0;
  96.765 +    if (flags & SA_UNSEEN) {	/* must search to get unseen messages */
  96.766 +				/* clear search vector */
  96.767 +      for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL;
  96.768 +      if (imap_OK (stream,imap_send (stream,"SEARCH UNSEEN",NIL)))
  96.769 +	for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
  96.770 +	  if (mail_elt (stream,i)->searched) status.unseen++;
  96.771 +    }
  96.772 +    strcpy (strchr (strcpy (tmp,stream->mailbox),'}') + 1,mb.mailbox);
  96.773 +				/* pass status to main program */
  96.774 +    mm_status (stream,tmp,&status);
  96.775 +    ret = T;			/* note success */
  96.776 +  }
  96.777 +  if (tstream) mail_close (tstream);
  96.778 +  return ret;			/* success */
  96.779 +}
  96.780 +
  96.781 +/* IMAP open
  96.782 + * Accepts: stream to open
  96.783 + * Returns: stream to use on success, NIL on failure
  96.784 + */
  96.785 +
  96.786 +MAILSTREAM *imap_open (MAILSTREAM *stream)
  96.787 +{
  96.788 +  unsigned long i,j;
  96.789 +  char *s,tmp[MAILTMPLEN],usr[MAILTMPLEN];
  96.790 +  NETMBX mb;
  96.791 +  IMAPPARSEDREPLY *reply = NIL;
  96.792 +  imapreferral_t ir =
  96.793 +    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
  96.794 +				/* return prototype for OP_PROTOTYPE call */
  96.795 +  if (!stream) return &imapproto;
  96.796 +  mail_valid_net_parse (stream->mailbox,&mb);
  96.797 +  usr[0] = '\0';		/* initially no user name */
  96.798 +  if (LOCAL) {			/* if stream opened earlier by us */
  96.799 +				/* recycle if still alive */
  96.800 +    if (LOCAL->netstream && (!stream->halfopen || LOCAL->cap.unselect)) {
  96.801 +      i = stream->silent;	/* temporarily mark silent */
  96.802 +      stream->silent = T;	/* don't give mm_exists() events */
  96.803 +      j = imap_ping (stream);	/* learn if stream still alive */
  96.804 +      stream->silent = i;	/* restore prior state */
  96.805 +      if (j) {			/* was stream still alive? */
  96.806 +	sprintf (tmp,"Reusing connection to %s",net_host (LOCAL->netstream));
  96.807 +	if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",
  96.808 +				  LOCAL->user);
  96.809 +	if (!stream->silent) mm_log (tmp,(long) NIL);
  96.810 +				/* unselect if now want halfopen */
  96.811 +	if (stream->halfopen) imap_send (stream,"UNSELECT",NIL);
  96.812 +      }
  96.813 +      else imap_close (stream,NIL);
  96.814 +    }
  96.815 +    else imap_close (stream,NIL);
  96.816 +  }
  96.817 +				/* copy flags from name */
  96.818 +  if (mb.dbgflag) stream->debug = T;
  96.819 +  if (mb.readonlyflag) stream->rdonly = T;
  96.820 +  if (mb.anoflag) stream->anonymous = T;
  96.821 +  if (mb.secflag) stream->secure = T;
  96.822 +  if (mb.trysslflag || imap_tryssl) stream->tryssl = T;
  96.823 +
  96.824 +  if (!LOCAL) {			/* open new connection if no recycle */
  96.825 +    NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL);
  96.826 +    unsigned long defprt = imap_defaultport ? imap_defaultport : IMAPTCPPORT;
  96.827 +    unsigned long sslport = imap_sslport ? imap_sslport : IMAPSSLPORT;
  96.828 +    stream->local =		/* instantiate localdata */
  96.829 +      (void *) memset (fs_get (sizeof (IMAPLOCAL)),0,sizeof (IMAPLOCAL));
  96.830 +				/* assume IMAP2bis server */
  96.831 +    LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
  96.832 +				/* in case server is a loser */
  96.833 +    if (mb.loser) LOCAL->loser = T;
  96.834 +				/* desirable authenticators */
  96.835 +    LOCAL->authflags = (stream->secure ? AU_SECURE : NIL) |
  96.836 +      (mb.authuser[0] ? AU_AUTHUSER : NIL);
  96.837 +    /* IMAP connection open logic is more complex than net_open() normally
  96.838 +     * deals with, because of the simap and rimap hacks.
  96.839 +     * If the session is anonymous, a specific port is given, or if /ssl or
  96.840 +     * /tls is set, do net_open() since those conditions override everything
  96.841 +     * else.
  96.842 +     */
  96.843 +    if (stream->anonymous || mb.port || mb.sslflag || mb.tlsflag)
  96.844 +      reply = (LOCAL->netstream = net_open (&mb,NIL,defprt,ssld,"*imaps",
  96.845 +					    sslport)) ?
  96.846 +	imap_reply (stream,NIL) : NIL;
  96.847 +    /* 
  96.848 +     * No overriding conditions, so get the best connection that we can.  In
  96.849 +     * order, attempt to open via simap, tryssl, rimap, and finally TCP.
  96.850 +     */
  96.851 +				/* try simap */
  96.852 +    else if (reply = imap_rimap (stream,"*imap",&mb,usr,tmp));
  96.853 +    else if (ssld &&		/* try tryssl if enabled */
  96.854 +	     (stream->tryssl || mail_parameters (NIL,GET_TRYSSLFIRST,NIL)) &&
  96.855 +	     (LOCAL->netstream =
  96.856 +	      net_open_work (ssld,mb.host,"*imaps",sslport,mb.port,
  96.857 +			     (mb.novalidate ? NET_NOVALIDATECERT : 0) |
  96.858 +			     NET_SILENT | NET_TRYSSL))) {
  96.859 +      if (net_sout (LOCAL->netstream,"",0)) {
  96.860 +	mb.sslflag = T;
  96.861 +	reply = imap_reply (stream,NIL);
  96.862 +      }
  96.863 +      else {			/* flush fake SSL stream */
  96.864 +	net_close (LOCAL->netstream);
  96.865 +	LOCAL->netstream = NIL;
  96.866 +      }
  96.867 +    }
  96.868 +				/* try rimap first, then TCP */
  96.869 +    else if (!(reply = imap_rimap (stream,"imap",&mb,usr,tmp)) &&
  96.870 +	     (LOCAL->netstream = net_open (&mb,NIL,defprt,NIL,NIL,NIL)))
  96.871 +      reply = imap_reply (stream,NIL);
  96.872 +				/* make sure greeting is good */
  96.873 +    if (!reply || strcmp (reply->tag,"*") ||
  96.874 +	(strcmp (reply->key,"OK") && strcmp (reply->key,"PREAUTH"))) {
  96.875 +      if (reply) mm_log (reply->text,ERROR);
  96.876 +      return NIL;		/* lost during greeting */
  96.877 +    }
  96.878 +
  96.879 +				/* if connected and not preauthenticated */
  96.880 +    if (LOCAL->netstream && strcmp (reply->key,"PREAUTH")) {
  96.881 +      sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL);
  96.882 +				/* get server capabilities */
  96.883 +      if (!LOCAL->gotcapability) imap_capability (stream);
  96.884 +      if (LOCAL->netstream &&	/* does server support STARTTLS? */
  96.885 +	  stls && LOCAL->cap.starttls && !mb.sslflag && !mb.notlsflag &&
  96.886 +	  imap_OK (stream,imap_send (stream,"STARTTLS",NIL))) {
  96.887 +	mb.tlsflag = T;		/* TLS OK, get into TLS at this end */
  96.888 +	LOCAL->netstream->dtb = ssld;
  96.889 +	if (!(LOCAL->netstream->stream =
  96.890 +	      (*stls) (LOCAL->netstream->stream,mb.host,
  96.891 +		       (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
  96.892 +		       (mb.novalidate ? NET_NOVALIDATECERT : NIL)))) {
  96.893 +				/* drat, drop this connection */
  96.894 +	  if (LOCAL->netstream) net_close (LOCAL->netstream);
  96.895 +	  LOCAL->netstream = NIL;
  96.896 +	}
  96.897 +				/* get capabilities now that TLS in effect */
  96.898 +	if (LOCAL->netstream) imap_capability (stream);
  96.899 +      }
  96.900 +      else if (mb.tlsflag) {	/* user specified /tls but can't do it */
  96.901 +	mm_log ("Unable to negotiate TLS with this server",ERROR);
  96.902 +	return NIL;
  96.903 +      }
  96.904 +      if (LOCAL->netstream) {	/* still in the land of the living? */
  96.905 +	if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
  96.906 +				/* remote name for authentication */
  96.907 +	  strncpy (mb.host,(long) mail_parameters(NIL,GET_SASLUSESPTRNAME,NIL)?
  96.908 +		   net_remotehost (LOCAL->netstream) :
  96.909 +		   net_host (LOCAL->netstream),NETMAXHOST-1);
  96.910 +	  mb.host[NETMAXHOST-1] = '\0';
  96.911 +	}
  96.912 +				/* need new capabilities after login */
  96.913 +	LOCAL->gotcapability = NIL;
  96.914 +	if (!(stream->anonymous ? imap_anon (stream,tmp) :
  96.915 +	      (LOCAL->cap.auth ? imap_auth (stream,&mb,tmp,usr) :
  96.916 +	       imap_login (stream,&mb,tmp,usr)))) {
  96.917 +				/* failed, is there a referral? */
  96.918 +	  if (ir && LOCAL->referral &&
  96.919 +	      (s = (*ir) (stream,LOCAL->referral,REFAUTHFAILED))) {
  96.920 +	    imap_close (stream,NIL);
  96.921 +	    fs_give ((void **) &stream->mailbox);
  96.922 +				/* set as new mailbox name to open */
  96.923 +	    stream->mailbox = s;
  96.924 +	    return imap_open (stream);
  96.925 +	  }
  96.926 +	  return NIL;		/* authentication failed */
  96.927 +	}
  96.928 +	else if (ir && LOCAL->referral &&
  96.929 +		 (s = (*ir) (stream,LOCAL->referral,REFAUTH))) {
  96.930 +	  imap_close (stream,NIL);
  96.931 +	  fs_give ((void **) &stream->mailbox);
  96.932 +	  stream->mailbox = s;	/* set as new mailbox name to open */
  96.933 +				/* recurse to log in on real site */
  96.934 +	  return imap_open (stream);
  96.935 +	}
  96.936 +      }
  96.937 +    }
  96.938 +				/* get server capabilities again */
  96.939 +    if (LOCAL->netstream && !LOCAL->gotcapability) imap_capability (stream);
  96.940 +				/* save state for future recycling */
  96.941 +    if (mb.tlsflag) LOCAL->tlsflag = T;
  96.942 +    if (mb.tlssslv23) LOCAL->tlssslv23 = T;
  96.943 +    if (mb.notlsflag) LOCAL->notlsflag = T;
  96.944 +    if (mb.sslflag) LOCAL->sslflag = T;
  96.945 +    if (mb.novalidate) LOCAL->novalidate = T;
  96.946 +    if (mb.loser) LOCAL->loser = T;
  96.947 +  }
  96.948 +
  96.949 +  if (LOCAL->netstream) {	/* still have a connection? */
  96.950 +    stream->perm_seen = stream->perm_deleted = stream->perm_answered =
  96.951 +      stream->perm_draft = LEVELIMAP4 (stream) ? NIL : T;
  96.952 +    stream->perm_user_flags = LEVELIMAP4 (stream) ? NIL : 0xffffffff;
  96.953 +    stream->sequence++;		/* bump sequence number */
  96.954 +    sprintf (tmp,"{%s",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
  96.955 +	     net_host (LOCAL->netstream) : mb.host);
  96.956 +    if (!((i = net_port (LOCAL->netstream)) & 0xffff0000))
  96.957 +      sprintf (tmp + strlen (tmp),":%lu",i);
  96.958 +    strcat (tmp,"/imap");
  96.959 +    if (LOCAL->tlsflag) strcat (tmp,"/tls");
  96.960 +    if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23");
  96.961 +    if (LOCAL->notlsflag) strcat (tmp,"/notls");
  96.962 +    if (LOCAL->sslflag) strcat (tmp,"/ssl");
  96.963 +    if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert");
  96.964 +    if (LOCAL->loser) strcat (tmp,"/loser");
  96.965 +    if (stream->secure) strcat (tmp,"/secure");
  96.966 +    if (stream->rdonly) strcat (tmp,"/readonly");
  96.967 +    if (stream->anonymous) strcat (tmp,"/anonymous");
  96.968 +    else {			/* record user name */
  96.969 +      if (!LOCAL->user && usr[0]) LOCAL->user = cpystr (usr);
  96.970 +      if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",
  96.971 +				LOCAL->user);
  96.972 +    }
  96.973 +    strcat (tmp,"}");
  96.974 +
  96.975 +    if (!stream->halfopen) {	/* wants to open a mailbox? */
  96.976 +      IMAPARG *args[2];
  96.977 +      IMAPARG ambx;
  96.978 +      ambx.type = ASTRING;
  96.979 +      ambx.text = (void *) mb.mailbox;
  96.980 +      args[0] = &ambx; args[1] = NIL;
  96.981 +      stream->nmsgs = 0;
  96.982 +      if (imap_OK (stream,reply = imap_send (stream,stream->rdonly ?
  96.983 +					     "EXAMINE": "SELECT",args))) {
  96.984 +	strcat (tmp,mb.mailbox);/* mailbox name */
  96.985 +	if (!stream->nmsgs && !stream->silent)
  96.986 +	  mm_log ("Mailbox is empty",(long) NIL);
  96.987 +				/* note if an INBOX or not */
  96.988 +	stream->inbox = !compare_cstring (mb.mailbox,"INBOX");
  96.989 +      }
  96.990 +      else if (ir && LOCAL->referral &&
  96.991 +	       (s = (*ir) (stream,LOCAL->referral,REFSELECT))) {
  96.992 +	imap_close (stream,NIL);
  96.993 +	fs_give ((void **) &stream->mailbox);
  96.994 +	stream->mailbox = s;	/* set as new mailbox name to open */
  96.995 +	return imap_open (stream);
  96.996 +      }
  96.997 +      else {
  96.998 +	mm_log (reply->text,ERROR);
  96.999 +	if (imap_closeonerror) return NIL;
 96.1000 +	stream->halfopen = T;	/* let him keep it half-open */
 96.1001 +      }
 96.1002 +    }
 96.1003 +    if (stream->halfopen) {	/* half-open connection? */
 96.1004 +      strcat (tmp,"<no_mailbox>");
 96.1005 +				/* make sure dummy message counts */
 96.1006 +      mail_exists (stream,(long) 0);
 96.1007 +      mail_recent (stream,(long) 0);
 96.1008 +    }
 96.1009 +    fs_give ((void **) &stream->mailbox);
 96.1010 +    stream->mailbox = cpystr (tmp);
 96.1011 +  }
 96.1012 +				/* success if stream open */
 96.1013 +  return LOCAL->netstream ? stream : NIL;
 96.1014 +}
 96.1015 +
 96.1016 +/* IMAP rimap connect
 96.1017 + * Accepts: MAIL stream
 96.1018 + *	    NETMBX specification
 96.1019 + *	    service to use
 96.1020 + *	    user name
 96.1021 + *	    scratch buffer
 96.1022 + * Returns: parsed reply if success, else NIL
 96.1023 + */
 96.1024 +
 96.1025 +IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb,
 96.1026 +			     char *usr,char *tmp)
 96.1027 +{
 96.1028 +  unsigned long i;
 96.1029 +  char c[2];
 96.1030 +  NETSTREAM *tstream;
 96.1031 +  IMAPPARSEDREPLY *reply = NIL;
 96.1032 +				/* try rimap open */
 96.1033 +  if (!mb->norsh && (tstream = net_aopen (NIL,mb,service,usr))) {
 96.1034 +				/* if success, see if reasonable banner */
 96.1035 +    if (net_getbuffer (tstream,(long) 1,c) && (*c == '*')) {
 96.1036 +      i = 0;			/* copy to buffer */
 96.1037 +      do tmp[i++] = *c;
 96.1038 +      while (net_getbuffer (tstream,(long) 1,c) && (*c != '\015') &&
 96.1039 +	     (*c != '\012') && (i < (MAILTMPLEN-1)));
 96.1040 +      tmp[i] = '\0';		/* tie off */
 96.1041 +				/* snarfed a valid greeting? */
 96.1042 +      if ((*c == '\015') && net_getbuffer (tstream,(long) 1,c) &&
 96.1043 +	  (*c == '\012') &&
 96.1044 +	  !strcmp ((reply = imap_parse_reply (stream,cpystr (tmp)))->tag,"*")){
 96.1045 +				/* parse line as IMAP */
 96.1046 +	imap_parse_unsolicited (stream,reply);
 96.1047 +				/* make sure greeting is good */
 96.1048 +	if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH")) {
 96.1049 +	  LOCAL->netstream = tstream;
 96.1050 +	  return reply;		/* return success */
 96.1051 +	}
 96.1052 +      }
 96.1053 +    }
 96.1054 +    net_close (tstream);	/* failed, punt the temporary netstream */
 96.1055 +  }
 96.1056 +  return NIL;
 96.1057 +}
 96.1058 +
 96.1059 +/* IMAP log in as anonymous
 96.1060 + * Accepts: stream to authenticate
 96.1061 + *	    scratch buffer
 96.1062 + * Returns: T on success, NIL on failure
 96.1063 + */
 96.1064 +
 96.1065 +long imap_anon (MAILSTREAM *stream,char *tmp)
 96.1066 +{
 96.1067 +  IMAPPARSEDREPLY *reply;
 96.1068 +  char *s = net_localhost (LOCAL->netstream);
 96.1069 +  if (LOCAL->cap.authanon) {
 96.1070 +    char tag[16];
 96.1071 +    unsigned long i;
 96.1072 +    char *broken = "[CLOSED] IMAP connection broken (anonymous auth)";
 96.1073 +    sprintf (tag,"%08lx",0xffffffff & (stream->gensym++));
 96.1074 +				/* build command */
 96.1075 +    sprintf (tmp,"%s AUTHENTICATE ANONYMOUS",tag);
 96.1076 +    if (!imap_soutr (stream,tmp)) {
 96.1077 +      mm_log (broken,ERROR);
 96.1078 +      return NIL;
 96.1079 +    }
 96.1080 +    if (imap_challenge (stream,&i)) imap_response (stream,s,strlen (s));
 96.1081 +				/* get response */
 96.1082 +    if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag,broken);
 96.1083 +				/* what we wanted? */
 96.1084 +    if (compare_cstring (reply->tag,tag)) {
 96.1085 +				/* abort if don't have tagged response */
 96.1086 +      while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag))
 96.1087 +	imap_soutr (stream,"*");
 96.1088 +    }
 96.1089 +  }
 96.1090 +  else {
 96.1091 +    IMAPARG *args[2];
 96.1092 +    IMAPARG ausr;
 96.1093 +    ausr.type = ASTRING;
 96.1094 +    ausr.text = (void *) s;
 96.1095 +    args[0] = &ausr; args[1] = NIL;
 96.1096 +				/* send "LOGIN anonymous <host>" */
 96.1097 +    reply = imap_send (stream,"LOGIN ANONYMOUS",args);
 96.1098 +  }
 96.1099 +				/* success if reply OK */
 96.1100 +  if (imap_OK (stream,reply)) return T;
 96.1101 +  mm_log (reply->text,ERROR);
 96.1102 +  return NIL;
 96.1103 +}
 96.1104 +
 96.1105 +/* IMAP authenticate
 96.1106 + * Accepts: stream to authenticate
 96.1107 + *	    parsed network mailbox structure
 96.1108 + *	    scratch buffer
 96.1109 + *	    place to return user name
 96.1110 + * Returns: T on success, NIL on failure
 96.1111 + */
 96.1112 +
 96.1113 +long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr)
 96.1114 +{
 96.1115 +  unsigned long trial,ua;
 96.1116 +  int ok;
 96.1117 +  char tag[16];
 96.1118 +  char *lsterr = NIL;
 96.1119 +  AUTHENTICATOR *at;
 96.1120 +  IMAPPARSEDREPLY *reply;
 96.1121 +  for (ua = LOCAL->cap.auth, LOCAL->saslcancel = NIL; LOCAL->netstream && ua &&
 96.1122 +       (at = mail_lookup_auth (find_rightmost_bit (&ua) + 1));) {
 96.1123 +    if (lsterr) {		/* previous authenticator failed? */
 96.1124 +      sprintf (tmp,"Retrying using %s authentication after %.80s",
 96.1125 +	       at->name,lsterr);
 96.1126 +      mm_log (tmp,NIL);
 96.1127 +      fs_give ((void **) &lsterr);
 96.1128 +    }
 96.1129 +    trial = 0;			/* initial trial count */
 96.1130 +    tmp[0] = '\0';		/* no error */
 96.1131 +    do {			/* gensym a new tag */
 96.1132 +      if (lsterr) {		/* previous attempt with this one failed? */
 96.1133 +	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
 96.1134 +	mm_log (tmp,WARN);
 96.1135 +	fs_give ((void **) &lsterr);
 96.1136 +      }
 96.1137 +      LOCAL->saslcancel = NIL;
 96.1138 +      sprintf (tag,"%08lx",0xffffffff & (stream->gensym++));
 96.1139 +				/* build command */
 96.1140 +      sprintf (tmp,"%s AUTHENTICATE %s",tag,at->name);
 96.1141 +      if (imap_soutr (stream,tmp)) {
 96.1142 +				/* hide client authentication responses */
 96.1143 +	if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T;
 96.1144 +	ok = (*at->client) (imap_challenge,imap_response,"imap",mb,stream,
 96.1145 +			    &trial,usr);
 96.1146 +	LOCAL->sensitive = NIL;	/* unhide */
 96.1147 +				/* make sure have a response */
 96.1148 +	if (!(reply = &LOCAL->reply)->tag)
 96.1149 +	  reply = imap_fake (stream,tag,
 96.1150 +			     "[CLOSED] IMAP connection broken (authenticate)");
 96.1151 +	else if (compare_cstring (reply->tag,tag))
 96.1152 +	  while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag))
 96.1153 +	    imap_soutr (stream,"*");
 96.1154 +				/* good if SASL ok and success response */
 96.1155 +	if (ok && imap_OK (stream,reply)) return T;
 96.1156 +	if (!trial) {		/* if main program requested cancellation */
 96.1157 +	  mm_log ("IMAP Authentication cancelled",ERROR);
 96.1158 +	  return NIL;
 96.1159 +	}
 96.1160 +				/* no error if protocol-initiated cancel */
 96.1161 +	lsterr = cpystr (reply->text);
 96.1162 +      }
 96.1163 +    }
 96.1164 +    while (LOCAL->netstream && !LOCAL->byeseen && trial &&
 96.1165 +	   (trial < imap_maxlogintrials));
 96.1166 +  }
 96.1167 +  if (lsterr) {			/* previous authenticator failed? */
 96.1168 +    if (!LOCAL->saslcancel) {	/* don't do this if a cancel */
 96.1169 +      sprintf (tmp,"Can not authenticate to IMAP server: %.80s",lsterr);
 96.1170 +      mm_log (tmp,ERROR);
 96.1171 +    }
 96.1172 +    fs_give ((void **) &lsterr);
 96.1173 +  }
 96.1174 +  return NIL;			/* ran out of authenticators */
 96.1175 +}
 96.1176 +
 96.1177 +/* IMAP login
 96.1178 + * Accepts: stream to login
 96.1179 + *	    parsed network mailbox structure
 96.1180 + *	    scratch buffer of length MAILTMPLEN
 96.1181 + *	    place to return user name
 96.1182 + * Returns: T on success, NIL on failure
 96.1183 + */
 96.1184 +
 96.1185 +long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr)
 96.1186 +{
 96.1187 +  unsigned long trial = 0;
 96.1188 +  IMAPPARSEDREPLY *reply;
 96.1189 +  IMAPARG *args[3];
 96.1190 +  IMAPARG ausr,apwd;
 96.1191 +  long ret = NIL;
 96.1192 +  if (stream->secure)		/* never do LOGIN if want security */
 96.1193 +    mm_log ("Can't do secure authentication with this server",ERROR);
 96.1194 +				/* never do LOGIN if server disabled it */
 96.1195 +  else if (LOCAL->cap.logindisabled)
 96.1196 +    mm_log ("Server disables LOGIN, no recognized SASL authenticator",ERROR);
 96.1197 +  else if (mb->authuser[0])	/* never do LOGIN with /authuser */
 96.1198 +    mm_log ("Can't do /authuser with this server",ERROR);
 96.1199 +  else {			/* OK to try login */
 96.1200 +    ausr.type = apwd.type = ASTRING;
 96.1201 +    ausr.text = (void *) usr;
 96.1202 +    apwd.text = (void *) pwd;
 96.1203 +    args[0] = &ausr; args[1] = &apwd; args[2] = NIL;
 96.1204 +    do {
 96.1205 +      pwd[0] = 0;		/* prompt user for password */
 96.1206 +      mm_login (mb,usr,pwd,trial++);
 96.1207 +      if (pwd[0]) {		/* send login command if have password */
 96.1208 +	LOCAL->sensitive = T;	/* hide this command */
 96.1209 +				/* send "LOGIN usr pwd" */
 96.1210 +	if (imap_OK (stream,reply = imap_send (stream,"LOGIN",args)))
 96.1211 +	  ret = LONGT;		/* success */
 96.1212 +	else {
 96.1213 +	  mm_log (reply->text,WARN);
 96.1214 +	  if (!LOCAL->referral && (trial == imap_maxlogintrials))
 96.1215 +	    mm_log ("Too many login failures",ERROR);
 96.1216 +	}
 96.1217 +	LOCAL->sensitive = NIL;	/* unhide */
 96.1218 +      }
 96.1219 +				/* user refused to give password */
 96.1220 +      else mm_log ("Login aborted",ERROR);
 96.1221 +    } while (!ret && pwd[0] && (trial < imap_maxlogintrials) &&
 96.1222 +	     LOCAL->netstream && !LOCAL->byeseen && !LOCAL->referral);
 96.1223 +  }
 96.1224 +  memset (pwd,0,MAILTMPLEN);	/* erase password */
 96.1225 +  return ret;
 96.1226 +}
 96.1227 +
 96.1228 +/* Get challenge to authenticator in binary
 96.1229 + * Accepts: stream
 96.1230 + *	    pointer to returned size
 96.1231 + * Returns: challenge or NIL if not challenge
 96.1232 + */
 96.1233 +
 96.1234 +void *imap_challenge (void *s,unsigned long *len)
 96.1235 +{
 96.1236 +  char tmp[MAILTMPLEN];
 96.1237 +  void *ret = NIL;
 96.1238 +  MAILSTREAM *stream = (MAILSTREAM *) s;
 96.1239 +  IMAPPARSEDREPLY *reply = NIL;
 96.1240 +				/* get tagged response or challenge */
 96.1241 +  while (stream && LOCAL->netstream &&
 96.1242 +	 (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) &&
 96.1243 +	 !strcmp (reply->tag,"*")) imap_parse_unsolicited (stream,reply);
 96.1244 +				/* parse challenge if have one */
 96.1245 +  if (stream && LOCAL->netstream && reply && reply->tag &&
 96.1246 +      (*reply->tag == '+') && !reply->tag[1] && reply->text &&
 96.1247 +      !(ret = rfc822_base64 ((unsigned char *) reply->text,
 96.1248 +			     strlen (reply->text),len))) {
 96.1249 +    sprintf (tmp,"IMAP SERVER BUG (invalid challenge): %.80s",
 96.1250 +	     (char *) reply->text);
 96.1251 +    mm_log (tmp,ERROR);
 96.1252 +  }
 96.1253 +  return ret;
 96.1254 +}
 96.1255 +
 96.1256 +
 96.1257 +/* Send authenticator response in BASE64
 96.1258 + * Accepts: MAIL stream
 96.1259 + *	    string to send
 96.1260 + *	    length of string
 96.1261 + * Returns: T if successful, else NIL
 96.1262 + */
 96.1263 +
 96.1264 +long imap_response (void *s,char *response,unsigned long size)
 96.1265 +{
 96.1266 +  MAILSTREAM *stream = (MAILSTREAM *) s;
 96.1267 +  unsigned long i,j,ret;
 96.1268 +  char *t,*u;
 96.1269 +  if (response) {		/* make CRLFless BASE64 string */
 96.1270 +    if (size) {
 96.1271 +      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
 96.1272 +	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
 96.1273 +      *u = '\0';		/* tie off string for mm_dlog() */
 96.1274 +      if (stream->debug) mail_dlog (t,LOCAL->sensitive);
 96.1275 +				/* append CRLF */
 96.1276 +      *u++ = '\015'; *u++ = '\012';
 96.1277 +      ret = net_sout (LOCAL->netstream,t,u - t);
 96.1278 +      fs_give ((void **) &t);
 96.1279 +    }
 96.1280 +    else ret = imap_soutr (stream,"");
 96.1281 +  }
 96.1282 +  else {			/* abort requested */
 96.1283 +    ret = imap_soutr (stream,"*");
 96.1284 +    LOCAL->saslcancel = T;	/* mark protocol-requested SASL cancel */
 96.1285 +  }
 96.1286 +  return ret;
 96.1287 +}
 96.1288 +
 96.1289 +/* IMAP close
 96.1290 + * Accepts: MAIL stream
 96.1291 + *	    option flags
 96.1292 + */
 96.1293 +
 96.1294 +void imap_close (MAILSTREAM *stream,long options)
 96.1295 +{
 96.1296 +  THREADER *thr,*t;
 96.1297 +  IMAPPARSEDREPLY *reply;
 96.1298 +  if (stream && LOCAL) {	/* send "LOGOUT" */
 96.1299 +    if (!LOCAL->byeseen) {	/* don't even think of doing it if saw a BYE */
 96.1300 +				/* expunge silently if requested */
 96.1301 +      if (options & CL_EXPUNGE)
 96.1302 +	imap_send (stream,LEVELIMAP4 (stream) ? "CLOSE" : "EXPUNGE",NIL);
 96.1303 +      if (LOCAL->netstream &&
 96.1304 +	  !imap_OK (stream,reply = imap_send (stream,"LOGOUT",NIL)))
 96.1305 +	mm_log (reply->text,WARN);
 96.1306 +    }
 96.1307 +				/* close NET connection if still open */
 96.1308 +    if (LOCAL->netstream) net_close (LOCAL->netstream);
 96.1309 +    LOCAL->netstream = NIL;
 96.1310 +				/* free up memory */
 96.1311 +    if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata);
 96.1312 +    if (LOCAL->namespace) {
 96.1313 +      mail_free_namespace (&LOCAL->namespace[0]);
 96.1314 +      mail_free_namespace (&LOCAL->namespace[1]);
 96.1315 +      mail_free_namespace (&LOCAL->namespace[2]);
 96.1316 +      fs_give ((void **) &LOCAL->namespace);
 96.1317 +    }
 96.1318 +    if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata);
 96.1319 +				/* flush threaders */
 96.1320 +    if (thr = LOCAL->cap.threader) while (t = thr) {
 96.1321 +      fs_give ((void **) &t->name);
 96.1322 +      thr = t->next;
 96.1323 +      fs_give ((void **) &t);
 96.1324 +    }
 96.1325 +    if (LOCAL->referral) fs_give ((void **) &LOCAL->referral);
 96.1326 +    if (LOCAL->user) fs_give ((void **) &LOCAL->user);
 96.1327 +    if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
 96.1328 +    if (LOCAL->reform) fs_give ((void **) &LOCAL->reform);
 96.1329 +				/* nuke the local data */
 96.1330 +    fs_give ((void **) &stream->local);
 96.1331 +  }
 96.1332 +}
 96.1333 +
 96.1334 +/* IMAP fetch fast information
 96.1335 + * Accepts: MAIL stream
 96.1336 + *	    sequence
 96.1337 + *	    option flags
 96.1338 + *
 96.1339 + * Generally, imap_structure is preferred
 96.1340 + */
 96.1341 +
 96.1342 +void imap_fast (MAILSTREAM *stream,char *sequence,long flags)
 96.1343 +{
 96.1344 +  IMAPPARSEDREPLY *reply = imap_fetch (stream,sequence,flags & FT_UID);
 96.1345 +  if (!imap_OK (stream,reply)) mm_log (reply->text,ERROR);
 96.1346 +}
 96.1347 +
 96.1348 +
 96.1349 +/* IMAP fetch flags
 96.1350 + * Accepts: MAIL stream
 96.1351 + *	    sequence
 96.1352 + *	    option flags
 96.1353 + */
 96.1354 +
 96.1355 +void imap_flags (MAILSTREAM *stream,char *sequence,long flags)
 96.1356 +{				/* send "FETCH sequence FLAGS" */
 96.1357 +  char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH";
 96.1358 +  IMAPPARSEDREPLY *reply;
 96.1359 +  IMAPARG *args[3],aseq,aatt;
 96.1360 +  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
 96.1361 +						     flags & FT_UID);
 96.1362 +  aseq.type = SEQUENCE; aseq.text = (void *) sequence;
 96.1363 +  aatt.type = ATOM; aatt.text = (void *) "FLAGS";
 96.1364 +  args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
 96.1365 +  if (!imap_OK (stream,reply = imap_send (stream,cmd,args)))
 96.1366 +    mm_log (reply->text,ERROR);
 96.1367 +}
 96.1368 +
 96.1369 +/* IMAP fetch overview
 96.1370 + * Accepts: MAIL stream, sequence bits set
 96.1371 + *	    pointer to overview return function
 96.1372 + * Returns: T if successful, NIL otherwise
 96.1373 + */
 96.1374 +
 96.1375 +long imap_overview (MAILSTREAM *stream,overview_t ofn)
 96.1376 +{
 96.1377 +  MESSAGECACHE *elt;
 96.1378 +  ENVELOPE *env;
 96.1379 +  OVERVIEW ov;
 96.1380 +  char *s,*t;
 96.1381 +  unsigned long i,start,last,len,slen;
 96.1382 +  if (!LOCAL->netstream) return NIL;
 96.1383 +				/* build overview sequence */
 96.1384 +  for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i)
 96.1385 +    if ((elt = mail_elt (stream,i))->sequence) {
 96.1386 +      if (!elt->private.msg.env) {
 96.1387 +	if (s) {		/* continuing a sequence */
 96.1388 +	  if (i == last + 1) last = i;
 96.1389 +	  else {		/* end of range */
 96.1390 +	    if (last != start) sprintf (t,":%lu,%lu",last,i);
 96.1391 +	    else sprintf (t,",%lu",i);
 96.1392 +	    if ((len - (slen = (t += strlen (t)) - s)) < 20) {
 96.1393 +	      fs_resize ((void **) &s,len += MAILTMPLEN);
 96.1394 +	      t = s + slen;	/* relocate current pointer */
 96.1395 +	    }
 96.1396 +	    start = last = i;	/* begin a new range */
 96.1397 +	  }
 96.1398 +	}
 96.1399 +	else {			/* first time, start new buffer */
 96.1400 +	  s = (char *) fs_get (len = MAILTMPLEN);
 96.1401 +	  sprintf (s,"%lu",start = last = i);
 96.1402 +	  t = s + strlen (s);	/* end of buffer */
 96.1403 +	}
 96.1404 +      }
 96.1405 +    }
 96.1406 +				/* last sequence */
 96.1407 +  if (last != start) sprintf (t,":%lu",last);
 96.1408 +  if (s) {			/* prefetch as needed */
 96.1409 +    imap_fetch (stream,s,FT_NEEDENV);
 96.1410 +    fs_give ((void **) &s);
 96.1411 +  }
 96.1412 +  ov.optional.lines = 0;	/* now overview each message */
 96.1413 +  ov.optional.xref = NIL;
 96.1414 +  if (ofn) for (i = 1; i <= stream->nmsgs; i++)
 96.1415 +    if (((elt = mail_elt (stream,i))->sequence) &&
 96.1416 +	(env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) {
 96.1417 +      ov.subject = env->subject;
 96.1418 +      ov.from = env->from;
 96.1419 +      ov.date = env->date;
 96.1420 +      ov.message_id = env->message_id;
 96.1421 +      ov.references = env->references;
 96.1422 +      ov.optional.octets = elt->rfc822_size;
 96.1423 +      (*ofn) (stream,mail_uid (stream,i),&ov,i);
 96.1424 +    }
 96.1425 +  return LONGT;
 96.1426 +}
 96.1427 +
 96.1428 +/* IMAP fetch structure
 96.1429 + * Accepts: MAIL stream
 96.1430 + *	    message # to fetch
 96.1431 + *	    pointer to return body
 96.1432 + *	    option flags
 96.1433 + * Returns: envelope of this message, body returned in body value
 96.1434 + *
 96.1435 + * Fetches the "fast" information as well
 96.1436 + */
 96.1437 +
 96.1438 +ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
 96.1439 +			  long flags)
 96.1440 +{
 96.1441 +  unsigned long i,j,k,x;
 96.1442 +  char *s,seq[MAILTMPLEN],tmp[MAILTMPLEN];
 96.1443 +  MESSAGECACHE *elt;
 96.1444 +  ENVELOPE **env;
 96.1445 +  BODY **b;
 96.1446 +  IMAPPARSEDREPLY *reply = NIL;
 96.1447 +  IMAPARG *args[3],aseq,aatt;
 96.1448 +  SEARCHSET *set = LOCAL->lookahead;
 96.1449 +  LOCAL->lookahead = NIL;
 96.1450 +  args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
 96.1451 +  aseq.type = SEQUENCE; aseq.text = (void *) seq;
 96.1452 +  aatt.type = ATOM; aatt.text = NIL;
 96.1453 +  if (flags & FT_UID)		/* see if can find msgno from UID */
 96.1454 +    for (i = 1; i <= stream->nmsgs; i++)
 96.1455 +      if ((elt = mail_elt (stream,i))->private.uid == msgno) {
 96.1456 +	msgno = i;		/* found msgno, use it from now on */
 96.1457 +	flags &= ~FT_UID;	/* no longer a UID fetch */
 96.1458 +      }
 96.1459 +  sprintf (s = seq,"%lu",msgno);/* initial sequence */
 96.1460 +  if (LEVELIMAP4 (stream) && (flags & FT_UID)) {
 96.1461 +    /* UID fetching is requested and we can't map the UID to a message sequence
 96.1462 +     * number.  Assume that the message isn't cached at all.
 96.1463 +     */
 96.1464 +    if (!imap_OK (stream,reply = imap_fetch (stream,seq,FT_NEEDENV +
 96.1465 +					     (body ? FT_NEEDBODY : NIL) +
 96.1466 +					     (flags & (FT_UID + FT_NOHDRS)))))
 96.1467 +      mm_log (reply->text,ERROR);
 96.1468 +				/* now hunt for this UID */
 96.1469 +    for (i = 1; i <= stream->nmsgs; i++)
 96.1470 +      if ((elt = mail_elt (stream,i))->private.uid == msgno) {
 96.1471 +	if (body) *body = elt->private.msg.body;
 96.1472 +	return elt->private.msg.env;
 96.1473 +      }
 96.1474 +    if (body) *body = NIL;	/* can't find the UID */
 96.1475 +    return NIL;
 96.1476 +  }
 96.1477 +  elt = mail_elt (stream,msgno);/* get cache pointer */
 96.1478 +  if (stream->scache) {		/* short caching? */
 96.1479 +    env = &stream->env;		/* use temporaries on the stream */
 96.1480 +    b = &stream->body;
 96.1481 +    if (msgno != stream->msgno){/* flush old poop if a different message */
 96.1482 +      mail_free_envelope (env);
 96.1483 +      mail_free_body (b);
 96.1484 +      stream->msgno = msgno;	/* this is now the current short cache msg */
 96.1485 +    }
 96.1486 +  }
 96.1487 +
 96.1488 +  else {			/* normal cache */
 96.1489 +    env = &elt->private.msg.env;/* get envelope and body pointers */
 96.1490 +    b = &elt->private.msg.body;
 96.1491 +				/* prefetch if don't have envelope */
 96.1492 +    if (!(flags & FT_NOLOOKAHEAD) &&
 96.1493 +	((!*env || (*env)->incomplete) ||
 96.1494 +	 (body && !*b && LEVELIMAP2bis (stream)))) {
 96.1495 +      if (set) {		/* have a lookahead list? */
 96.1496 +	MESSAGE *msg;
 96.1497 +	for (k = imap_fetchlookaheadlimit;
 96.1498 +	     k && set && (((s += strlen (s)) - seq) < (MAXCOMMAND - 30));
 96.1499 +	     set = set->next) {
 96.1500 +	  i = (set->first == 0xffffffff) ? stream->nmsgs :
 96.1501 +	    min (set->first,stream->nmsgs);
 96.1502 +	  if (j = (set->last == 0xffffffff) ? stream->nmsgs :
 96.1503 +	      min (set->last,stream->nmsgs)) {
 96.1504 +	    if (i > j) {	/* swap the range if backwards */
 96.1505 +	      x = i; i = j; j = x;
 96.1506 +	    }
 96.1507 +				/* find first message not msgno or in cache */
 96.1508 +	    while (((i == msgno) ||
 96.1509 +		    ((msg = &(mail_elt (stream,i)->private.msg))->env &&
 96.1510 +		     (!body || msg->body))) && (i++ < j));
 96.1511 +				/* until range or lookahead finished */
 96.1512 +	    while (k && (i <= j)) {
 96.1513 +				/* find first cached message in range */
 96.1514 +	      for (x = i + 1; (x <= j) &&
 96.1515 +		     !((msg = &(mail_elt (stream,x)->private.msg))->env &&
 96.1516 +		       (!body || msg->body)); x++);
 96.1517 +	      if (i == --x) {	/* only one message? */
 96.1518 +		sprintf (s += strlen (s),",%lu",i++);
 96.1519 +		k--;		/* prefetching one message */
 96.1520 +	      }
 96.1521 +	      else {		/* a range to prefetch */
 96.1522 +		sprintf (s += strlen (s),",%lu:%lu",i,x);
 96.1523 +		i = 1 + x - i;	/* number of messages in this range */
 96.1524 +				/* still can look ahead some more? */
 96.1525 +		if (k = (k > i) ? k - i : 0)
 96.1526 +				/* yes, scan further in this range */
 96.1527 +		  for (i = x + 2; (i <= j) &&
 96.1528 +			 ((i == msgno) || 
 96.1529 +			  ((msg = &(mail_elt (stream,i)->private.msg))->env &&
 96.1530 +			   (!body || msg->body)));
 96.1531 +		       i++);
 96.1532 +	      }
 96.1533 +	    }
 96.1534 +	  }
 96.1535 +	  else if ((i != msgno) && !mail_elt (stream,i)->private.msg.env) {
 96.1536 +	    sprintf (s += strlen (s),",%lu",i);
 96.1537 +	    k--;		/* prefetching one message */
 96.1538 +	  }
 96.1539 +      }
 96.1540 +      }
 96.1541 +				/* build message number list */
 96.1542 +      else for (i = msgno+1,k = imap_lookahead; k && (i <= stream->nmsgs); i++)
 96.1543 +	if (!mail_elt (stream,i)->private.msg.env) {
 96.1544 +	  s += strlen (s);	/* find string end, see if nearing end */
 96.1545 +	  if ((s - seq) > (MAILTMPLEN - 20)) break;
 96.1546 +	  sprintf (s,",%lu",i);	/* append message */
 96.1547 + 	  for (j = i + 1, k--;	/* hunt for last message without an envelope */
 96.1548 +	       k && (j <= stream->nmsgs) &&
 96.1549 +	       !mail_elt (stream,j)->private.msg.env; j++, k--);
 96.1550 +				/* if different, make a range */
 96.1551 +	  if (i != --j) sprintf (s + strlen (s),":%lu",i = j);
 96.1552 +	}
 96.1553 +    }
 96.1554 +  }
 96.1555 +
 96.1556 +  if (!stream->lock) {		/* no-op if stream locked */
 96.1557 +    /* Build the fetch attributes.  Unlike imap_fetch(), this tries not to
 96.1558 +     * fetch data that is already cached.  However, since it is based on the
 96.1559 +     * message requested and not on any of the prefetched messages, it can
 96.1560 +     * goof, either by fetching data already cached or not prefetching data
 96.1561 +     * that isn't cached (but was cached in the message requested).
 96.1562 +     * Fortunately, no great harm is done.  If it doesn't prefetch the data,
 96.1563 +     * it will get it when the affected message(s) are requested.
 96.1564 +     */
 96.1565 +    if (!elt->private.uid && LEVELIMAP4 (stream)) strcpy (tmp," UID");
 96.1566 +    else tmp[0] = '\0';		/* initialize command */
 96.1567 +				/* need envelope? */
 96.1568 +    if (!*env || (*env)->incomplete) {
 96.1569 +      strcat (tmp," ENVELOPE");	/* yes, get it and possible extra poop */
 96.1570 +      if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) {
 96.1571 +	if (imap_extrahdrs) sprintf (tmp + strlen (tmp)," %s %s %s",
 96.1572 +				     hdrheader[LOCAL->cap.extlevel],
 96.1573 +				     imap_extrahdrs,hdrtrailer);
 96.1574 +	else sprintf (tmp + strlen (tmp)," %s %s",
 96.1575 +		      hdrheader[LOCAL->cap.extlevel],hdrtrailer);
 96.1576 +      }
 96.1577 +    }
 96.1578 +				/* need body? */
 96.1579 +    if (body && !*b && LEVELIMAP2bis (stream))
 96.1580 +      strcat (tmp,LEVELIMAP4 (stream) ? " BODYSTRUCTURE" : " BODY");
 96.1581 +    if (!elt->day) strcat (tmp," INTERNALDATE");
 96.1582 +    if (!elt->rfc822_size) strcat (tmp," RFC822.SIZE");
 96.1583 +    if (tmp[0]) {		/* anything to do? */
 96.1584 +      tmp[0] = '(';		/* make into a list */
 96.1585 +      strcat (tmp," FLAGS)");	/* always get current flags */
 96.1586 +      aatt.text = (void *) tmp;	/* do the built command */
 96.1587 +      if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args))) {
 96.1588 +				/* failed, probably RFC-1176 server */
 96.1589 +	if (!LEVELIMAP4 (stream) && LEVELIMAP2bis (stream) && body && !*b){
 96.1590 +	  aatt.text = (void *) "ALL";
 96.1591 +	  if (imap_OK (stream,reply = imap_send (stream,"FETCH",args)))
 96.1592 +				/* doesn't have body capabilities */
 96.1593 +	    LOCAL->cap.imap2bis = NIL;
 96.1594 +	  else mm_log (reply->text,ERROR);
 96.1595 +	}
 96.1596 +	else mm_log (reply->text,ERROR);
 96.1597 +      }
 96.1598 +    }
 96.1599 +  }
 96.1600 +  if (body) {			/* wants to return body */
 96.1601 +    if (!*b && !LEVELIMAP2bis (stream)) {
 96.1602 +				/* simulate body structure fetch for IMAP2 */
 96.1603 +      *b = mail_initbody (mail_newbody ());
 96.1604 +      (*b)->subtype = cpystr (rfc822_default_subtype ((*b)->type));
 96.1605 +      ((*b)->parameter = mail_newbody_parameter ())->attribute =
 96.1606 +	cpystr ("CHARSET");
 96.1607 +      (*b)->parameter->value = cpystr ("US-ASCII");
 96.1608 +      s = mail_fetch_text (stream,msgno,NIL,&i,flags);
 96.1609 +      (*b)->size.bytes = i;
 96.1610 +      while (i--) if (*s++ == '\n') (*b)->size.lines++;
 96.1611 +    }
 96.1612 +    *body = *b;			/* return the body */
 96.1613 +  }
 96.1614 +  return *env;			/* return the envelope */
 96.1615 +}
 96.1616 +
 96.1617 +/* IMAP fetch message data
 96.1618 + * Accepts: MAIL stream
 96.1619 + *	    message number
 96.1620 + *	    section specifier
 96.1621 + *	    offset of first designated byte or 0 to start at beginning
 96.1622 + *	    maximum number of bytes or 0 for all bytes
 96.1623 + *	    lines to fetch if header
 96.1624 + *	    flags
 96.1625 + * Returns: T on success, NIL on failure
 96.1626 + */
 96.1627 +
 96.1628 +long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section,
 96.1629 +		   unsigned long first,unsigned long last,STRINGLIST *lines,
 96.1630 +		   long flags)
 96.1631 +{
 96.1632 +  int i;
 96.1633 +  char *t,tmp[MAILTMPLEN],partial[40],seq[40];
 96.1634 +  char *noextend,*nopartial,*nolines,*nopeek,*nononpeek;
 96.1635 +  char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH";
 96.1636 +  IMAPPARSEDREPLY *reply;
 96.1637 +  IMAPARG *args[5],*auxargs[3],aseq,aatt,alns,acls,aflg;
 96.1638 +  noextend = nopartial = nolines = nopeek = nononpeek = NIL;
 96.1639 +				/* does searching desire a lookahead? */
 96.1640 +  if ((flags & FT_SEARCHLOOKAHEAD) && (msgno < stream->nmsgs) &&
 96.1641 +      !stream->scache) {
 96.1642 +    sprintf (seq,"%lu:%lu",msgno,
 96.1643 +	     (unsigned long) min (msgno + IMAPLOOKAHEAD,stream->nmsgs));
 96.1644 +    aseq.type = SEQUENCE;
 96.1645 +    aseq.text = (void *) seq;
 96.1646 +  }
 96.1647 +  else {			/* no, do it the easy way */
 96.1648 +    aseq.type = NUMBER;
 96.1649 +    aseq.text = (void *) msgno;
 96.1650 +  }
 96.1651 +  aatt.type = ATOM;		/* assume atomic attribute */
 96.1652 +  alns.type = LIST; alns.text = (void *) lines;
 96.1653 +  acls.type = BODYCLOSE; acls.text = (void *) partial;
 96.1654 +  aflg.type = ATOM; aflg.text = (void *) "FLAGS";
 96.1655 +  args[0] = &aseq; args[1] = &aatt; args[2] = args[3] = args[4] = NIL;
 96.1656 +  auxargs[0] = &aseq; auxargs[1] = &aflg; auxargs[2] = NIL;
 96.1657 +  partial[0] = '\0';		/* initially no partial specifier */
 96.1658 +  if (LEVELIMAP4rev1 (stream)) {/* easy if IMAP4rev1 server */
 96.1659 +				/* HEADER fetching with special handling? */
 96.1660 +    if (!strcmp (section,"HEADER") && (lines || (flags & FT_PREFETCHTEXT))) {
 96.1661 +      if (lines) {		/* want specific header lines? */
 96.1662 +	aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
 96.1663 +	aatt.text = (void *) ((flags & FT_NOT) ?
 96.1664 +			      "HEADER.FIELDS.NOT" : "HEADER.FIELDS");
 96.1665 +	args[2] = &alns; args[3] = &acls;
 96.1666 +      }
 96.1667 +				/* must be prefetching */
 96.1668 +      else aatt.text = (void *) ((flags & FT_PEEK) ?
 96.1669 +				 "(BODY.PEEK[HEADER] BODY.PEEK[TEXT])" :
 96.1670 +				 "(BODY[HEADER] BODY[TEXT])");
 96.1671 +    }
 96.1672 +    else {			/* simple case */
 96.1673 +      aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
 96.1674 +      aatt.text = (void *) section;
 96.1675 +      args[2] = &acls;
 96.1676 +    }
 96.1677 +    if (first || last) sprintf (partial,"<%lu.%lu>",first,last ? last:-1);
 96.1678 +  }
 96.1679 +
 96.1680 +  /* IMAP4 did not have:
 96.1681 +   * . HEADER body part (can simulate with BODY[0] or BODY.PEEK[0])
 96.1682 +   * . TEXT body part (can simulate top-level with RFC822.TEXT or
 96.1683 +   *			RFC822.TEXT.PEEK)
 96.1684 +   * . MIME body part
 96.1685 +   * . (usable) partial fetching
 96.1686 +   * . (usable) selective header line fetching
 96.1687 +   */
 96.1688 +  else if (LEVEL1730 (stream)) {/* IMAP4 (RFC 1730) compatibility */
 96.1689 +				/* BODY[HEADER] becomes BODY.PEEK[0] */
 96.1690 +    if (!strcmp (section,"HEADER"))
 96.1691 +      aatt.text = (void *)
 96.1692 +	((flags & FT_PREFETCHTEXT) ?
 96.1693 +	 ((flags & FT_PEEK) ? "(BODY.PEEK[0] RFC822.TEXT.PEEK)" :
 96.1694 +	  "(BODY[0] RFC822.TEXT)") :
 96.1695 +	 ((flags & FT_PEEK) ? "BODY.PEEK[0]" : "BODY[0]"));
 96.1696 +				/* BODY[TEXT] becomes RFC822.TEXT */
 96.1697 +    else if (!strcmp (section,"TEXT"))
 96.1698 +      aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.TEXT.PEEK" :
 96.1699 +			    "RFC822.TEXT");
 96.1700 +    else if (!section[0])	/* BODY[] becomes RFC822 */
 96.1701 +      aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.PEEK" : "RFC822");
 96.1702 +				/* nested header */
 96.1703 +    else if (t = strstr (section,".HEADER")) {
 96.1704 +      aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
 96.1705 +      args[2] = &acls;		/* will need to close section */
 96.1706 +      aatt.text = (void *) tmp;	/* convert .HEADER to .0 */
 96.1707 +      strncpy (tmp,section,t-section);
 96.1708 +      strcpy (tmp+(t-section),".0");
 96.1709 +    }
 96.1710 +    else {			/* IMAP4 body part */
 96.1711 +      aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
 96.1712 +      args[2] = &acls;		/* will need to close section */
 96.1713 +      aatt.text = (void *) section;
 96.1714 +    }
 96.1715 +    if (strstr (section,".MIME") || strstr (section,".TEXT")) noextend = "4";
 96.1716 +    if (first || last) nopartial = "4";
 96.1717 +    if (lines) nolines = "4";
 96.1718 +  }
 96.1719 +
 96.1720 +  /* IMAP2bis did not have:
 96.1721 +   * . HEADER body part (can simulate peeking top-level with RFC822.HEADER)
 96.1722 +   * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT)
 96.1723 +   * . MIME body part
 96.1724 +   * . partial fetching
 96.1725 +   * . selective header line fetching
 96.1726 +   * . non-peeking header fetching
 96.1727 +   * . peeking body fetching
 96.1728 +   */
 96.1729 +				/* IMAP2bis compatibility */
 96.1730 +  else if (LEVELIMAP2bis (stream)) {
 96.1731 +				/* BODY[HEADER] becomes RFC822.HEADER */
 96.1732 +    if (!strcmp (section,"HEADER")) {
 96.1733 +      aatt.text = (void *)
 96.1734 +	((flags & FT_PREFETCHTEXT) ?
 96.1735 +	 "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER");
 96.1736 +      if (flags & FT_PEEK) flags &= ~FT_PEEK;
 96.1737 +      else nononpeek = "2bis";
 96.1738 +    }
 96.1739 +				/* BODY[TEXT] becomes RFC822.TEXT */
 96.1740 +    else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT";
 96.1741 +				/* BODY[] becomes RFC822 */
 96.1742 +    else if (!section[0]) aatt.text = (void *) "RFC822";
 96.1743 +    else {			/* IMAP2bis body part */
 96.1744 +      aatt.type = BODYTEXT;
 96.1745 +      args[2] = &acls;		/* will need to close section */
 96.1746 +      aatt.text = (void *) section;
 96.1747 +    }
 96.1748 +    if (strstr (section,".HEADER") || strstr (section,".MIME") ||
 96.1749 +	     strstr (section,".TEXT")) noextend = "2bis";
 96.1750 +    if (first || last) nopartial = "2bis";
 96.1751 +    if (lines) nolines = "2bis";
 96.1752 +    if (flags & FT_PEEK) nopeek = "2bis";
 96.1753 +  }
 96.1754 +
 96.1755 +  /* IMAP2 did not have:
 96.1756 +   * . HEADER body part (can simulate peeking top-level with RFC822.HEADER)
 96.1757 +   * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT)
 96.1758 +   * . MIME body part
 96.1759 +   * . multiple body parts (can simulate BODY[1] with RFC822.TEXT)
 96.1760 +   * . partial fetching
 96.1761 +   * . selective header line fetching
 96.1762 +   * . non-peeking header fetching
 96.1763 +   * . peeking body fetching
 96.1764 +   */
 96.1765 +  else {			/* IMAP2 (RFC 1176/1064) compatibility */
 96.1766 +				/* BODY[HEADER] */
 96.1767 +    if (!strcmp (section,"HEADER")) {
 96.1768 +      aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ?
 96.1769 +			    "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER");
 96.1770 +      if (flags & FT_PEEK) flags &= ~FT_PEEK;
 96.1771 +      nononpeek = "2";
 96.1772 +    }
 96.1773 +				/* BODY[TEXT] becomes RFC822.TEXT */
 96.1774 +    else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT";
 96.1775 +				/* BODY[1] treated like RFC822.TEXT */
 96.1776 +    else if (!strcmp (section,"1")) {
 96.1777 +      SIZEDTEXT text;
 96.1778 +      MESSAGECACHE *elt = mail_elt (stream,msgno);
 96.1779 +				/* have a cached RFC822.TEXT? */
 96.1780 +      if (elt->private.msg.text.text.data) {
 96.1781 +	text.size = elt->private.msg.text.text.size;
 96.1782 +				/* should move instead of copy */
 96.1783 +	text.data = memcpy (fs_get (text.size+1),
 96.1784 +			    elt->private.msg.text.text.data,text.size);
 96.1785 +	(t = (char *) text.data)[text.size] = '\0';
 96.1786 +	imap_cache (stream,msgno,"1",NIL,&text);
 96.1787 +	return LONGT;		/* don't have to do any fetches */
 96.1788 +      }
 96.1789 +				/* otherwise do RFC822.TEXT */
 96.1790 +      aatt.text = (void *) "RFC822.TEXT";
 96.1791 +    }
 96.1792 +				/* BODY[] becomes RFC822 */
 96.1793 +    else if (!section[0]) aatt.text = (void *) "RFC822";
 96.1794 +    else noextend = "2";	/* how did we get here? */
 96.1795 +    if (flags & FT_PEEK) nopeek = "2";
 96.1796 +    if (first || last) nopartial = "2";
 96.1797 +    if (lines) nolines = "2";
 96.1798 +  }
 96.1799 +
 96.1800 +  /* Report unavailable functionalities.  The application can use the helpful
 96.1801 +   * LEVELIMAPREV1, LEVELIMAP4, and LEVELIMAP2bis operations provided in
 96.1802 +   * imap4r1.h to avoid triggering these errors.  There aren't any workarounds
 96.1803 +   * for these restrictions.
 96.1804 +   */
 96.1805 +  if (noextend) {
 96.1806 +    sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do extended body fetch",
 96.1807 +	     noextend);
 96.1808 +    mm_log (tmp,ERROR);
 96.1809 +    return NIL;			/* can't do anything close either */
 96.1810 +  }
 96.1811 +  if (nopartial) {
 96.1812 +    sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do partial fetch",
 96.1813 +	     nopartial);
 96.1814 +    mm_notify (stream,tmp,WARN);
 96.1815 +  }
 96.1816 +  if (nolines) {
 96.1817 +    sprintf(tmp,"[NOTIMAP4REV1] IMAP%s server can't do selective header fetch",
 96.1818 +	    nolines);
 96.1819 +    mm_notify (stream,tmp,WARN);
 96.1820 +  }
 96.1821 +
 96.1822 +				/* trying to do unsupported peek behavior? */
 96.1823 +  if ((t = nopeek) || (t = nononpeek)) {
 96.1824 +				/* get most recent \Seen setting */
 96.1825 +    if (!imap_OK (stream,reply = imap_send (stream,cmd,auxargs)))
 96.1826 +      mm_log (reply->text,WARN);
 96.1827 +				/* note current setting of \Seen flag */
 96.1828 +    if (!(i = mail_elt (stream,msgno)->seen)) {
 96.1829 +      sprintf (tmp,nopeek ?	/* only babble if \Seen not set */
 96.1830 +	       "[NOTIMAP4] Simulating peeking fetch in IMAP%s" :
 96.1831 +	       "[NOTIMAP4] Simulating non-peeking header fetch in IMAP%s",t);
 96.1832 +      mm_notify (stream,tmp,NIL);
 96.1833 +    }
 96.1834 +				/* send the fetch command */
 96.1835 +    if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) {
 96.1836 +      mm_log (reply->text,ERROR);
 96.1837 +      return NIL;		/* failure */
 96.1838 +    }
 96.1839 +				/* send command if need to reset \Seen */
 96.1840 +    if (((nopeek && !i && mail_elt (stream,msgno)->seen &&
 96.1841 +	  (aflg.text = "-FLAGS \\Seen")) ||
 96.1842 +	 ((nononpeek && !mail_elt (stream,msgno)->seen) &&
 96.1843 +	  (aflg.text = "+FLAGS \\Seen"))) &&
 96.1844 +	!imap_OK (stream,reply = imap_send (stream,"STORE",auxargs)))
 96.1845 +      mm_log (reply->text,WARN);
 96.1846 +  }
 96.1847 +				/* simple case if traditional behavior */
 96.1848 +  else if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) {
 96.1849 +    mm_log (reply->text,ERROR);
 96.1850 +    return NIL;			/* failure */
 96.1851 +  }
 96.1852 +				/* simulate BODY[1] return for RFC 1064/1176 */
 96.1853 +  if (!LEVELIMAP2bis (stream) && !strcmp (section,"1")) {
 96.1854 +    SIZEDTEXT text;
 96.1855 +    MESSAGECACHE *elt = mail_elt (stream,msgno);
 96.1856 +    text.size = elt->private.msg.text.text.size;
 96.1857 +				/* should move instead of copy */
 96.1858 +    text.data = memcpy (fs_get (text.size+1),elt->private.msg.text.text.data,
 96.1859 +			text.size);
 96.1860 +    (t = (char *) text.data)[text.size] = '\0';
 96.1861 +    imap_cache (stream,msgno,"1",NIL,&text);
 96.1862 +  }
 96.1863 +  return LONGT;
 96.1864 +}
 96.1865 +
 96.1866 +/* IMAP fetch UID
 96.1867 + * Accepts: MAIL stream
 96.1868 + *	    message number
 96.1869 + * Returns: UID
 96.1870 + */
 96.1871 +
 96.1872 +unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno)
 96.1873 +{
 96.1874 +  MESSAGECACHE *elt;
 96.1875 +  IMAPPARSEDREPLY *reply;
 96.1876 +  IMAPARG *args[3],aseq,aatt;
 96.1877 +  char *s,seq[MAILTMPLEN];
 96.1878 +  unsigned long i,j,k;
 96.1879 +				/* IMAP2 didn't have UIDs */
 96.1880 +  if (!LEVELIMAP4 (stream)) return msgno;
 96.1881 +				/* do we know its UID yet? */
 96.1882 +  if (!(elt = mail_elt (stream,msgno))->private.uid) {
 96.1883 +    aseq.type = SEQUENCE; aseq.text = (void *) seq;
 96.1884 +    aatt.type = ATOM; aatt.text = (void *) "UID";
 96.1885 +    args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
 96.1886 +    sprintf (seq,"%lu",msgno);
 96.1887 +    if (k = imap_uidlookahead) {/* build UID list */
 96.1888 +      for (i = msgno + 1, s = seq; k && (i <= stream->nmsgs); i++)
 96.1889 +	if (!mail_elt (stream,i)->private.uid) {
 96.1890 +	  s += strlen (s);	/* find string end, see if nearing end */
 96.1891 +	  if ((s - seq) > (MAILTMPLEN - 20)) break;
 96.1892 +	  sprintf (s,",%lu",i);	/* append message */
 96.1893 +	  for (j = i + 1, k--;	/* hunt for last message without a UID */
 96.1894 +	       k && (j <= stream->nmsgs) && !mail_elt (stream,j)->private.uid;
 96.1895 +	       j++, k--);
 96.1896 +				/* if different, make a range */
 96.1897 +	  if (i != --j) sprintf (s + strlen (s),":%lu",i = j);
 96.1898 +	}
 96.1899 +    }
 96.1900 +				/* send "FETCH msgno UID" */
 96.1901 +    if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args)))
 96.1902 +      mm_log (reply->text,ERROR);
 96.1903 +  }
 96.1904 +  return elt->private.uid;	/* return our UID now */
 96.1905 +}
 96.1906 +
 96.1907 +/* IMAP fetch message number from UID
 96.1908 + * Accepts: MAIL stream
 96.1909 + *	    UID
 96.1910 + * Returns: message number
 96.1911 + */
 96.1912 +
 96.1913 +unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid)
 96.1914 +{
 96.1915 +  IMAPPARSEDREPLY *reply;
 96.1916 +  IMAPARG *args[3],aseq,aatt;
 96.1917 +  char seq[MAILTMPLEN];
 96.1918 +  int holes = 0;
 96.1919 +  unsigned long i,msgno;
 96.1920 +				/* IMAP2 didn't have UIDs */
 96.1921 +  if (!LEVELIMAP4 (stream)) return uid;
 96.1922 +  /* This really should be a binary search, but since there are likely to be
 96.1923 +   * holes in the msgno->UID map it's hard to do.
 96.1924 +   */
 96.1925 +  for (msgno = 1; msgno <= stream->nmsgs; msgno++) {
 96.1926 +    if (!(i = mail_elt (stream,msgno)->private.uid)) holes = T;
 96.1927 +    else if (i == uid) return msgno;
 96.1928 +  }
 96.1929 +  if (holes) {			/* have holes in cache? */
 96.1930 +				/* yes, have server hunt for UID */
 96.1931 +    LOCAL->lastuid.uid = LOCAL->lastuid.msgno = 0;
 96.1932 +    aseq.type = SEQUENCE; aseq.text = (void *) seq;
 96.1933 +    aatt.type = ATOM; aatt.text = (void *) "UID";
 96.1934 +    args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
 96.1935 +    sprintf (seq,"%lu",uid);
 96.1936 +				/* send "UID FETCH uid UID" */
 96.1937 +    if (!imap_OK (stream,reply = imap_send (stream,"UID FETCH",args)))
 96.1938 +      mm_log (reply->text,ERROR);
 96.1939 +    if (LOCAL->lastuid.uid) {	/* got any results from FETCH? */
 96.1940 +      if ((LOCAL->lastuid.uid == uid) &&
 96.1941 +				/* what, me paranoid? */
 96.1942 +	  (LOCAL->lastuid.msgno <= stream->nmsgs) &&
 96.1943 +	  (mail_elt (stream,LOCAL->lastuid.msgno)->private.uid == uid))
 96.1944 +				/* got it the easy way */
 96.1945 +	return LOCAL->lastuid.msgno;
 96.1946 +				/* sigh, do another linear search... */
 96.1947 +      for (msgno = 1; msgno <= stream->nmsgs; msgno++)
 96.1948 +	if (mail_elt (stream,msgno)->private.uid == uid) return msgno;
 96.1949 +    }
 96.1950 +  }
 96.1951 +  return 0;			/* didn't find the UID anywhere */
 96.1952 +}
 96.1953 +
 96.1954 +/* IMAP modify flags
 96.1955 + * Accepts: MAIL stream
 96.1956 + *	    sequence
 96.1957 + *	    flag(s)
 96.1958 + *	    option flags
 96.1959 + */
 96.1960 +
 96.1961 +void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 96.1962 +{
 96.1963 +  char *cmd = (LEVELIMAP4 (stream) && (flags & ST_UID)) ? "UID STORE":"STORE";
 96.1964 +  IMAPPARSEDREPLY *reply;
 96.1965 +  IMAPARG *args[4],aseq,ascm,aflg;
 96.1966 +  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
 96.1967 +						     flags & ST_UID);
 96.1968 +  aseq.type = SEQUENCE; aseq.text = (void *) sequence;
 96.1969 +  ascm.type = ATOM; ascm.text = (void *)
 96.1970 +    ((flags & ST_SET) ?
 96.1971 +     ((LEVELIMAP4 (stream) && (flags & ST_SILENT)) ?
 96.1972 +      "+Flags.silent" : "+Flags") :
 96.1973 +     ((LEVELIMAP4 (stream) && (flags & ST_SILENT)) ?
 96.1974 +      "-Flags.silent" : "-Flags"));
 96.1975 +  aflg.type = FLAGS; aflg.text = (void *) flag;
 96.1976 +  args[0] = &aseq; args[1] = &ascm; args[2] = &aflg; args[3] = NIL;
 96.1977 +				/* send "STORE sequence +Flags flag" */
 96.1978 +  if (!imap_OK (stream,reply = imap_send (stream,cmd,args)))
 96.1979 +    mm_log (reply->text,ERROR);
 96.1980 +}
 96.1981 +
 96.1982 +/* IMAP search for messages
 96.1983 + * Accepts: MAIL stream
 96.1984 + *	    character set
 96.1985 + *	    search program
 96.1986 + *	    option flags
 96.1987 + * Returns: T on success, NIL on failure
 96.1988 + */
 96.1989 +
 96.1990 +long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags)
 96.1991 +{
 96.1992 +  unsigned long i,j,k;
 96.1993 +  char *s;
 96.1994 +  IMAPPARSEDREPLY *reply;
 96.1995 +  MESSAGECACHE *elt;
 96.1996 +  if ((flags & SE_NOSERVER) ||	/* if want to do local search */
 96.1997 +      LOCAL->loser ||		/* or loser */
 96.1998 +      (!LEVELIMAP4 (stream) &&	/* or old server but new functions... */
 96.1999 +       (charset || (flags & SE_UID) || pgm->msgno || pgm->uid || pgm->or ||
 96.2000 +	pgm->not || pgm->header || pgm->larger || pgm->smaller ||
 96.2001 +	pgm->sentbefore || pgm->senton || pgm->sentsince || pgm->draft ||
 96.2002 +	pgm->undraft || pgm->return_path || pgm->sender || pgm->reply_to ||
 96.2003 +	pgm->message_id || pgm->in_reply_to || pgm->newsgroups ||
 96.2004 +	pgm->followup_to || pgm->references)) ||
 96.2005 +      (!LEVELWITHIN (stream) && (pgm->older || pgm->younger))) {
 96.2006 +    if ((flags & SE_NOLOCAL) ||
 96.2007 +	!mail_search_default (stream,charset,pgm,flags | SE_NOSERVER))
 96.2008 +      return NIL;
 96.2009 +  }
 96.2010 +				/* do silly ALL or seq-only search locally */
 96.2011 +  else if (!(flags & (SE_NOLOCAL|SE_SILLYOK)) &&
 96.2012 +	   !(pgm->uid || pgm->or || pgm->not ||
 96.2013 +	     pgm->header || pgm->from || pgm->to || pgm->cc || pgm->bcc ||
 96.2014 +	     pgm->subject || pgm->body || pgm->text ||
 96.2015 +	     pgm->larger || pgm->smaller ||
 96.2016 +	     pgm->sentbefore || pgm->senton || pgm->sentsince ||
 96.2017 +	     pgm->before || pgm->on || pgm->since ||
 96.2018 +	     pgm->answered || pgm->unanswered ||
 96.2019 +	     pgm->deleted || pgm->undeleted || pgm->draft || pgm->undraft ||
 96.2020 +	     pgm->flagged || pgm->unflagged || pgm->recent || pgm->old ||
 96.2021 +	     pgm->seen || pgm->unseen ||
 96.2022 +	     pgm->keyword || pgm->unkeyword ||
 96.2023 +	     pgm->return_path || pgm->sender ||
 96.2024 +	     pgm->reply_to || pgm->in_reply_to || pgm->message_id ||
 96.2025 +	     pgm->newsgroups || pgm->followup_to || pgm->references)) {
 96.2026 +    if (!mail_search_default (stream,NIL,pgm,flags | SE_NOSERVER))
 96.2027 +      fatal ("impossible mail_search_default() failure");
 96.2028 +  }
 96.2029 +
 96.2030 +  else {			/* do server-based SEARCH */
 96.2031 +    char *cmd = (flags & SE_UID) ? "UID SEARCH" : "SEARCH";
 96.2032 +    IMAPARG *args[4],apgm,aatt,achs;
 96.2033 +    SEARCHSET *ss,*set;
 96.2034 +    args[1] = args[2] = args[3] = NIL;
 96.2035 +    apgm.type = SEARCHPROGRAM; apgm.text = (void *) pgm;
 96.2036 +    if (charset) {		/* optional charset argument requested */
 96.2037 +      args[0] = &aatt; args[1] = &achs; args[2] = &apgm;
 96.2038 +      aatt.type = ATOM; aatt.text = (void *) "CHARSET";
 96.2039 +      achs.type = ASTRING; achs.text = (void *) charset;
 96.2040 +    }
 96.2041 +    else args[0] = &apgm;	/* no charset argument */
 96.2042 +				/* tell receiver that these will be UIDs */
 96.2043 +    LOCAL->uidsearch = (flags & SE_UID) ? T : NIL;
 96.2044 +    reply = imap_send (stream,cmd,args);
 96.2045 +				/* did server barf with that searchpgm? */
 96.2046 +    if (!(flags & SE_UID) && pgm && (ss = pgm->msgno) &&
 96.2047 +	!strcmp (reply->key,"BAD")) {
 96.2048 +      LOCAL->filter = T;	/* retry, filtering SEARCH results */
 96.2049 +      for (i = 1; i <= stream->nmsgs; i++)
 96.2050 +	mail_elt (stream,i)->private.filter = NIL;
 96.2051 +      for (set = ss; set; set = set->next) if (i = set->first) {
 96.2052 +				/* single message becomes one-message range */
 96.2053 +	if (!(j = set->last)) j = i;
 96.2054 +	else if (j < i) {	/* swap reversed range */
 96.2055 +	  i = set->last; j = set->first;
 96.2056 +	}
 96.2057 +	while (i <= j) mail_elt (stream,i++)->private.filter = T;
 96.2058 +      }      
 96.2059 +      pgm->msgno = NIL;		/* and without the searchset */
 96.2060 +      reply = imap_send (stream,cmd,args);
 96.2061 +      pgm->msgno = ss;		/* restore searchset */
 96.2062 +      LOCAL->filter = NIL;	/* turn off filtering */
 96.2063 +    }
 96.2064 +    LOCAL->uidsearch = NIL;
 96.2065 +				/* do locally if server won't grok */
 96.2066 +    if (!strcmp (reply->key,"BAD")) {
 96.2067 +      if ((flags & SE_NOLOCAL) ||
 96.2068 +	  !mail_search_default (stream,charset,pgm,flags | SE_NOSERVER))
 96.2069 +	return NIL;
 96.2070 +    }
 96.2071 +    else if (!imap_OK (stream,reply)) {
 96.2072 +      mm_log (reply->text,ERROR);
 96.2073 +      return NIL;
 96.2074 +    }
 96.2075 +  }
 96.2076 +
 96.2077 +				/* can never pre-fetch with a short cache */
 96.2078 +  if ((k = imap_prefetch) && !(flags & (SE_NOPREFETCH | SE_UID)) &&
 96.2079 +      !stream->scache) {	/* only if prefetching permitted */
 96.2080 +    s = LOCAL->tmp;		/* build sequence in temporary buffer */
 96.2081 +    *s = '\0';			/* initially nothing */
 96.2082 +				/* search through mailbox */
 96.2083 +    for (i = 1; k && (i <= stream->nmsgs); ++i) 
 96.2084 +				/* for searched messages with no envelope */
 96.2085 +      if ((elt = mail_elt (stream,i)) && elt->searched &&
 96.2086 +	  !mail_elt (stream,i)->private.msg.env) {
 96.2087 +				/* prepend with comma if not first time */
 96.2088 +	if (LOCAL->tmp[0]) *s++ = ',';
 96.2089 +	sprintf (s,"%lu",j = i);/* output message number */
 96.2090 +	s += strlen (s);	/* point at end of string */
 96.2091 +	k--;			/* count one up */
 96.2092 +				/* search for possible end of range */
 96.2093 +	while (k && (i < stream->nmsgs) &&
 96.2094 +	       (elt = mail_elt (stream,i+1))->searched &&
 96.2095 +	       !elt->private.msg.env) i++,k--;
 96.2096 +	if (i != j) {		/* if a range */
 96.2097 +	  sprintf (s,":%lu",i);	/* output delimiter and end of range */
 96.2098 +	  s += strlen (s);	/* point at end of string */
 96.2099 +	}
 96.2100 +	if ((s - LOCAL->tmp) > (IMAPTMPLEN - 50)) break;
 96.2101 +      }
 96.2102 +    if (LOCAL->tmp[0]) {	/* anything to pre-fetch? */
 96.2103 +      /* pre-fetch envelopes for the first imap_prefetch number of messages */
 96.2104 +      if (!imap_OK (stream,reply =
 96.2105 +		    imap_fetch (stream,s = cpystr (LOCAL->tmp),FT_NEEDENV +
 96.2106 +				((flags & SE_NOHDRS) ? FT_NOHDRS : NIL) +
 96.2107 +				((flags & SE_NEEDBODY) ? FT_NEEDBODY : NIL))))
 96.2108 +	mm_log (reply->text,ERROR);
 96.2109 +      fs_give ((void **) &s);	/* flush copy of sequence */
 96.2110 +    }
 96.2111 +  }
 96.2112 +  return LONGT;
 96.2113 +}
 96.2114 +
 96.2115 +/* IMAP sort messages
 96.2116 + * Accepts: mail stream
 96.2117 + *	    character set
 96.2118 + *	    search program
 96.2119 + *	    sort program
 96.2120 + *	    option flags
 96.2121 + * Returns: vector of sorted message sequences or NIL if error
 96.2122 + */
 96.2123 +
 96.2124 +unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 96.2125 +			  SORTPGM *pgm,long flags)
 96.2126 +{
 96.2127 +  unsigned long i,j,start,last;
 96.2128 +  unsigned long *ret = NIL;
 96.2129 +  pgm->nmsgs = 0;		/* start off with no messages */
 96.2130 +				/* can use server-based sort? */
 96.2131 +  if (LEVELSORT (stream) && !(flags & SE_NOSERVER) &&
 96.2132 +      (!spg || (LEVELWITHIN (stream) || !(spg->older || spg->younger)))) {
 96.2133 +    char *cmd = (flags & SE_UID) ? "UID SORT" : "SORT";
 96.2134 +    IMAPARG *args[4],apgm,achs,aspg;
 96.2135 +    IMAPPARSEDREPLY *reply;
 96.2136 +    SEARCHSET *ss = NIL;
 96.2137 +    SEARCHPGM *tsp = NIL;
 96.2138 +    apgm.type = SORTPROGRAM; apgm.text = (void *) pgm;
 96.2139 +    achs.type = ASTRING; achs.text = (void *) (charset ? charset : "US-ASCII");
 96.2140 +    aspg.type = SEARCHPROGRAM;
 96.2141 +				/* did he provide a searchpgm? */
 96.2142 +    if (!(aspg.text = (void *) spg)) {
 96.2143 +      for (i = 1,start = last = 0; i <= stream->nmsgs; ++i)
 96.2144 +	if (mail_elt (stream,i)->searched) {
 96.2145 +	  if (ss) {		/* continuing a sequence */
 96.2146 +	    if (i == last + 1) last = i;
 96.2147 +	    else {		/* end of range */
 96.2148 +	      if (last != start) ss->last = last;
 96.2149 +	      (ss = ss->next = mail_newsearchset ())->first = i;
 96.2150 +	      start = last = i;	/* begin a new range */
 96.2151 +	    }
 96.2152 +	  }
 96.2153 +	  else {		/* first time, start new searchpgm */
 96.2154 +	    (tsp = mail_newsearchpgm ())->msgno = ss = mail_newsearchset ();
 96.2155 +	    ss->first = start = last = i;
 96.2156 +	  }
 96.2157 +	}
 96.2158 +				/* nothing to sort if no messages */
 96.2159 +      if (!(aspg.text = (void *) tsp)) return NIL;
 96.2160 +				/* else install last sequence */
 96.2161 +      if (last != start) ss->last = last;
 96.2162 +    }
 96.2163 +
 96.2164 +    args[0] = &apgm; args[1] = &achs; args[2] = &aspg; args[3] = NIL;
 96.2165 +				/* ask server to do it */
 96.2166 +    reply = imap_send (stream,cmd,args);
 96.2167 +    if (tsp) {			/* was there a temporary searchpgm? */
 96.2168 +      aspg.text = NIL;		/* yes, flush it */
 96.2169 +      mail_free_searchpgm (&tsp);
 96.2170 +				/* did server barf with that searchpgm? */
 96.2171 +      if (!(flags & SE_UID) && !strcmp (reply->key,"BAD")) {
 96.2172 +	LOCAL->filter = T;	/* retry, filtering SORT/THREAD results */
 96.2173 +	reply = imap_send (stream,cmd,args);
 96.2174 +	LOCAL->filter = NIL;	/* turn off filtering */
 96.2175 +      }
 96.2176 +    }
 96.2177 +				/* do locally if server barfs */
 96.2178 +    if (!strcmp (reply->key,"BAD"))
 96.2179 +      return (flags & SE_NOLOCAL) ? NIL :
 96.2180 +	imap_sort (stream,charset,spg,pgm,flags | SE_NOSERVER);
 96.2181 +				/* server sorted OK? */
 96.2182 +    else if (imap_OK (stream,reply)) {
 96.2183 +      pgm->nmsgs = LOCAL->sortsize;
 96.2184 +      ret = LOCAL->sortdata;
 96.2185 +      LOCAL->sortdata = NIL;	/* mail program is responsible for flushing */
 96.2186 +    }
 96.2187 +    else mm_log (reply->text,ERROR);
 96.2188 +  }
 96.2189 +
 96.2190 +				/* not much can do if short caching */
 96.2191 +  else if (stream->scache) ret = mail_sort_msgs (stream,charset,spg,pgm,flags);
 96.2192 +  else {			/* try to be a bit more clever */
 96.2193 +    char *s,*t;
 96.2194 +    unsigned long len;
 96.2195 +    MESSAGECACHE *elt;
 96.2196 +    SORTCACHE **sc;
 96.2197 +    SORTPGM *sp;
 96.2198 +    long ftflags = 0;
 96.2199 +				/* see if need envelopes */
 96.2200 +    for (sp = pgm; sp && !ftflags; sp = sp->next) switch (sp->function) {
 96.2201 +    case SORTDATE: case SORTFROM: case SORTSUBJECT: case SORTTO: case SORTCC:
 96.2202 +      ftflags = FT_NEEDENV + ((flags & SE_NOHDRS) ? FT_NOHDRS : NIL);
 96.2203 +    }
 96.2204 +    if (spg) {			/* only if a search needs to be done */
 96.2205 +      int silent = stream->silent;
 96.2206 +      stream->silent = T;	/* don't pass up mm_searched() events */
 96.2207 +				/* search for messages */
 96.2208 +      mail_search_full (stream,charset,spg,flags & SE_NOSERVER);
 96.2209 +      stream->silent = silent;	/* restore silence state */
 96.2210 +    }
 96.2211 +				/* initialize progress counters */
 96.2212 +    pgm->nmsgs = pgm->progress.cached = 0;
 96.2213 +				/* pass 1: count messages to sort */
 96.2214 +    for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i)
 96.2215 +      if ((elt = mail_elt (stream,i))->searched) {
 96.2216 +	pgm->nmsgs++;
 96.2217 +	if (ftflags ? !elt->private.msg.env : !elt->day) {
 96.2218 +	  if (s) {		/* continuing a sequence */
 96.2219 +	    if (i == last + 1) last = i;
 96.2220 +	    else {		/* end of range */
 96.2221 +	      if (last != start) sprintf (t,":%lu,%lu",last,i);
 96.2222 +	      else sprintf (t,",%lu",i);
 96.2223 +	      start = last = i;	/* begin a new range */
 96.2224 +	      if ((len - (j = ((t += strlen (t)) - s)) < 20)) {
 96.2225 +		fs_resize ((void **) &s,len += MAILTMPLEN);
 96.2226 +		t = s + j;	/* relocate current pointer */
 96.2227 +	      }
 96.2228 +	    }
 96.2229 +	  }
 96.2230 +	  else {		/* first time, start new buffer */
 96.2231 +	    s = (char *) fs_get (len = MAILTMPLEN);
 96.2232 +	    sprintf (s,"%lu",start = last = i);
 96.2233 +	    t = s + strlen (s);	/* end of buffer */
 96.2234 +	  }
 96.2235 +	}
 96.2236 +      }
 96.2237 +				/* last sequence */
 96.2238 +    if (last != start) sprintf (t,":%lu",last);
 96.2239 +    if (s) {			/* load cache for all messages being sorted */
 96.2240 +      imap_fetch (stream,s,ftflags);
 96.2241 +      fs_give ((void **) &s);
 96.2242 +    }
 96.2243 +    if (pgm->nmsgs) {		/* pass 2: sort cache */
 96.2244 +      sortresults_t sr = (sortresults_t)
 96.2245 +	mail_parameters (NIL,GET_SORTRESULTS,NIL);
 96.2246 +      sc = mail_sort_loadcache (stream,pgm);
 96.2247 +				/* pass 3: sort messages */
 96.2248 +      if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags);
 96.2249 +      fs_give ((void **) &sc);	/* don't need sort vector any more */
 96.2250 +				/* also return via callback if requested */
 96.2251 +      if (sr) (*sr) (stream,ret,pgm->nmsgs);
 96.2252 +    }
 96.2253 +  }
 96.2254 +  return ret;
 96.2255 +}
 96.2256 +
 96.2257 +/* IMAP thread messages
 96.2258 + * Accepts: mail stream
 96.2259 + *	    thread type
 96.2260 + *	    character set
 96.2261 + *	    search program
 96.2262 + *	    option flags
 96.2263 + * Returns: thread node tree or NIL if error
 96.2264 + */
 96.2265 +
 96.2266 +THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset,
 96.2267 +			 SEARCHPGM *spg,long flags)
 96.2268 +{
 96.2269 +  THREADER *thr;
 96.2270 +  if (!(flags & SE_NOSERVER) &&
 96.2271 +      (!spg || (LEVELWITHIN (stream) || !(spg->older || spg->younger))))
 96.2272 +				/* does server have this threader type? */
 96.2273 +    for (thr = LOCAL->cap.threader; thr; thr = thr->next)
 96.2274 +      if (!compare_cstring (thr->name,type)) 
 96.2275 +	return imap_thread_work (stream,type,charset,spg,flags);
 96.2276 +				/* server doesn't support it, do locally */
 96.2277 +  return (flags & SE_NOLOCAL) ? NIL: 
 96.2278 +    mail_thread_msgs (stream,type,charset,spg,flags | SE_NOSERVER,imap_sort);
 96.2279 +}
 96.2280 +
 96.2281 +/* IMAP thread messages worker routine
 96.2282 + * Accepts: mail stream
 96.2283 + *	    thread type
 96.2284 + *	    character set
 96.2285 + *	    search program
 96.2286 + *	    option flags
 96.2287 + * Returns: thread node tree
 96.2288 + */
 96.2289 +
 96.2290 +THREADNODE *imap_thread_work (MAILSTREAM *stream,char *type,char *charset,
 96.2291 +			      SEARCHPGM *spg,long flags)
 96.2292 +{
 96.2293 +  unsigned long i,start,last;
 96.2294 +  char *cmd = (flags & SE_UID) ? "UID THREAD" : "THREAD";
 96.2295 +  IMAPARG *args[4],apgm,achs,aspg;
 96.2296 +  IMAPPARSEDREPLY *reply;
 96.2297 +  THREADNODE *ret = NIL;
 96.2298 +  SEARCHSET *ss = NIL;
 96.2299 +  SEARCHPGM *tsp = NIL;
 96.2300 +  apgm.type = ATOM; apgm.text = (void *) type;
 96.2301 +  achs.type = ASTRING;
 96.2302 +  achs.text = (void *) (charset ? charset : "US-ASCII");
 96.2303 +  aspg.type = SEARCHPROGRAM;
 96.2304 +				/* did he provide a searchpgm? */
 96.2305 +  if (!(aspg.text = (void *) spg)) {
 96.2306 +    for (i = 1,start = last = 0; i <= stream->nmsgs; ++i)
 96.2307 +      if (mail_elt (stream,i)->searched) {
 96.2308 +	if (ss) {		/* continuing a sequence */
 96.2309 +	  if (i == last + 1) last = i;
 96.2310 +	  else {		/* end of range */
 96.2311 +	    if (last != start) ss->last = last;
 96.2312 +	    (ss = ss->next = mail_newsearchset ())->first = i;
 96.2313 +	    start = last =i;	/* begin a new range */
 96.2314 +	  }
 96.2315 +	}
 96.2316 +	else {			/* first time, start new searchpgm */
 96.2317 +	  (tsp = mail_newsearchpgm ())->msgno = ss = mail_newsearchset ();
 96.2318 +	  ss->first = start = last = i;
 96.2319 +	}
 96.2320 +      }
 96.2321 +				/* nothing to sort if no messages */
 96.2322 +    if (!(aspg.text = (void *) tsp)) return NIL;
 96.2323 +				/* else install last sequence */
 96.2324 +    if (last != start) ss->last = last;
 96.2325 +  }
 96.2326 +
 96.2327 +  args[0] = &apgm; args[1] = &achs; args[2] = &aspg; args[3] = NIL;
 96.2328 +				/* ask server to do it */
 96.2329 +  reply = imap_send (stream,cmd,args);
 96.2330 +  if (tsp) {			/* was there a temporary searchpgm? */
 96.2331 +    aspg.text = NIL;		/* yes, flush it */
 96.2332 +    mail_free_searchpgm (&tsp);
 96.2333 +				/* did server barf with that searchpgm? */
 96.2334 +    if (!(flags & SE_UID) && !strcmp (reply->key,"BAD")) {
 96.2335 +      LOCAL->filter = T;	/* retry, filtering SORT/THREAD results */
 96.2336 +      reply = imap_send (stream,cmd,args);
 96.2337 +      LOCAL->filter = NIL;	/* turn off filtering */
 96.2338 +    }
 96.2339 +  }
 96.2340 +				/* do locally if server barfs */
 96.2341 +  if (!strcmp (reply->key,"BAD"))
 96.2342 +    ret = (flags & SE_NOLOCAL) ? NIL: 
 96.2343 +    mail_thread_msgs (stream,type,charset,spg,flags | SE_NOSERVER,imap_sort);
 96.2344 +				/* server threaded OK? */
 96.2345 +  else if (imap_OK (stream,reply)) {
 96.2346 +    ret = LOCAL->threaddata;
 96.2347 +    LOCAL->threaddata = NIL;	/* mail program is responsible for flushing */
 96.2348 +  }
 96.2349 +  else mm_log (reply->text,ERROR);
 96.2350 +  return ret;
 96.2351 +}
 96.2352 +
 96.2353 +/* IMAP ping mailbox
 96.2354 + * Accepts: MAIL stream
 96.2355 + * Returns: T if stream still alive, else NIL
 96.2356 + */
 96.2357 +
 96.2358 +long imap_ping (MAILSTREAM *stream)
 96.2359 +{
 96.2360 +  return (LOCAL->netstream &&	/* send "NOOP" */
 96.2361 +	  imap_OK (stream,imap_send (stream,"NOOP",NIL))) ? T : NIL;
 96.2362 +}
 96.2363 +
 96.2364 +
 96.2365 +/* IMAP check mailbox
 96.2366 + * Accepts: MAIL stream
 96.2367 + */
 96.2368 +
 96.2369 +void imap_check (MAILSTREAM *stream)
 96.2370 +{
 96.2371 +				/* send "CHECK" */
 96.2372 +  IMAPPARSEDREPLY *reply = imap_send (stream,"CHECK",NIL);
 96.2373 +  mm_log (reply->text,imap_OK (stream,reply) ? (long) NIL : ERROR);
 96.2374 +}
 96.2375 +
 96.2376 +/* IMAP expunge mailbox
 96.2377 + * Accepts: MAIL stream
 96.2378 + *	    sequence to expunge if non-NIL
 96.2379 + *	    expunge options
 96.2380 + * Returns: T if success, NIL if failure
 96.2381 + */
 96.2382 +
 96.2383 +long imap_expunge (MAILSTREAM *stream,char *sequence,long options)
 96.2384 +{
 96.2385 +  long ret = NIL;
 96.2386 +  IMAPPARSEDREPLY *reply = NIL;
 96.2387 +  if (sequence) {		/* wants selective expunging? */
 96.2388 +    if (options & EX_UID) {	/* UID EXPUNGE form? */
 96.2389 +      if (LEVELUIDPLUS (stream)) {/* server support UIDPLUS? */
 96.2390 +	IMAPARG *args[2],aseq;
 96.2391 +	aseq.type = SEQUENCE; aseq.text = (void *) sequence;
 96.2392 +	args[0] = &aseq; args[1] = NIL;
 96.2393 +	ret = imap_OK (stream,reply = imap_send (stream,"UID EXPUNGE",args));
 96.2394 +      }
 96.2395 +      else mm_log ("[NOTUIDPLUS] Can't do UID EXPUNGE with this server",ERROR);
 96.2396 +    }
 96.2397 +				/* otherwise try to make into UID EXPUNGE */
 96.2398 +    else if (mail_sequence (stream,sequence)) {
 96.2399 +      unsigned long i,j;
 96.2400 +      char *t = (char *) fs_get (IMAPTMPLEN);
 96.2401 +      char *s = t;
 96.2402 +				/* search through mailbox */
 96.2403 +      for (*s = '\0', i = 1; i <= stream->nmsgs; ++i)
 96.2404 +	if (mail_elt (stream,i)->sequence) {
 96.2405 +	  if (t[0]) *s++ = ',';	/* prepend with comma if not first time */
 96.2406 +	  sprintf (s,"%lu",mail_uid (stream,j = i));
 96.2407 +	  s += strlen (s);	/* point at end of string */
 96.2408 +				/* search for possible end of range */
 96.2409 +	  while ((i < stream->nmsgs) && mail_elt (stream,i+1)->sequence) i++;
 96.2410 +	  if (i != j) {		/* output end of range */
 96.2411 +	    sprintf (s,":%lu",mail_uid (stream,i));
 96.2412 +	    s += strlen (s);	/* point at end of string */
 96.2413 +	  }
 96.2414 +	  if ((s - t) > (IMAPTMPLEN - 50)) {
 96.2415 +	    mm_log ("Excessively complex sequence",ERROR);
 96.2416 +	    return NIL;
 96.2417 +	  }
 96.2418 +	}
 96.2419 +				/* now do as UID EXPUNGE */
 96.2420 +      ret = imap_expunge (stream,t,EX_UID);
 96.2421 +      fs_give ((void **) &t);
 96.2422 +    }
 96.2423 +  }
 96.2424 +				/* ordinary EXPUNGE */
 96.2425 +  else ret = imap_OK (stream,reply = imap_send (stream,"EXPUNGE",NIL));
 96.2426 +  if (reply) mm_log (reply->text,ret ? (long) NIL : ERROR);
 96.2427 +  return ret;
 96.2428 +}
 96.2429 +
 96.2430 +/* IMAP copy message(s)
 96.2431 + * Accepts: MAIL stream
 96.2432 + *	    sequence
 96.2433 + *	    destination mailbox
 96.2434 + *	    option flags
 96.2435 + * Returns: T if successful else NIL
 96.2436 + */
 96.2437 +
 96.2438 +long imap_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long flags)
 96.2439 +{
 96.2440 +  char *cmd = (LEVELIMAP4 (stream) && (flags & CP_UID)) ? "UID COPY" : "COPY";
 96.2441 +  char *s;
 96.2442 +  long ret = NIL;
 96.2443 +  IMAPPARSEDREPLY *reply;
 96.2444 +  IMAPARG *args[3],aseq,ambx;
 96.2445 +  imapreferral_t ir =
 96.2446 +    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
 96.2447 +  mailproxycopy_t pc =
 96.2448 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 96.2449 +  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
 96.2450 +						     flags & CP_UID);
 96.2451 +  aseq.type = SEQUENCE; aseq.text = (void *) sequence;
 96.2452 +  ambx.type = ASTRING; ambx.text = (void *) mailbox;
 96.2453 +  args[0] = &aseq; args[1] = &ambx; args[2] = NIL;
 96.2454 +				/* note mailbox in case APPENDUID */
 96.2455 +  LOCAL->appendmailbox = mailbox;
 96.2456 +				/* send "COPY sequence mailbox" */
 96.2457 +  ret = imap_OK (stream,reply = imap_send (stream,cmd,args));
 96.2458 +  LOCAL->appendmailbox = NIL;	/* no longer appending */
 96.2459 +  if (ret) {			/* success, delete messages if move */
 96.2460 +    if (flags & CP_MOVE) imap_flag (stream,sequence,"\\Deleted",
 96.2461 +				    ST_SET + ((flags&CP_UID) ? ST_UID : NIL));
 96.2462 +  }
 96.2463 +				/* failed, do referral action if any */
 96.2464 +  else if (ir && pc && LOCAL->referral && mail_sequence (stream,sequence) &&
 96.2465 +	   (s = (*ir) (stream,LOCAL->referral,REFCOPY)))
 96.2466 +    ret = (*pc) (stream,sequence,s,flags | (stream->debug ? CP_DEBUG : NIL));
 96.2467 +				/* otherwise issue error message */
 96.2468 +  else mm_log (reply->text,ERROR);
 96.2469 +  return ret;
 96.2470 +}
 96.2471 +
 96.2472 +/* IMAP mail append message from stringstruct
 96.2473 + * Accepts: MAIL stream
 96.2474 + *	    destination mailbox
 96.2475 + *	    append callback
 96.2476 + *	    data for callback
 96.2477 + * Returns: T if append successful, else NIL
 96.2478 + */
 96.2479 +
 96.2480 +long imap_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 96.2481 +{
 96.2482 +  MAILSTREAM *st = stream;
 96.2483 +  IMAPARG *args[3],ambx,amap;
 96.2484 +  IMAPPARSEDREPLY *reply = NIL;
 96.2485 +  APPENDDATA map;
 96.2486 +  char tmp[MAILTMPLEN];
 96.2487 +  long debug = stream ? stream->debug : NIL;
 96.2488 +  long ret = NIL;
 96.2489 +  imapreferral_t ir =
 96.2490 +    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
 96.2491 +				/* mailbox must be good */
 96.2492 +  if (mail_valid_net (mailbox,&imapdriver,NIL,tmp)) {
 96.2493 +				/* create a stream if given one no good */
 96.2494 +    if ((stream && LOCAL && LOCAL->netstream) ||
 96.2495 +	(stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT |
 96.2496 +			     (debug ? OP_DEBUG : NIL)))) {
 96.2497 +				/* note mailbox in case APPENDUID */
 96.2498 +      LOCAL->appendmailbox = mailbox;
 96.2499 +				/* use multi-append? */
 96.2500 +      if (LEVELMULTIAPPEND (stream)) {
 96.2501 +	ambx.type = ASTRING; ambx.text = (void *) tmp;
 96.2502 +	amap.type = MULTIAPPEND; amap.text = (void *) &map;
 96.2503 +	map.af = af; map.data = data;
 96.2504 +	args[0] = &ambx; args[1] = &amap; args[2] = NIL;
 96.2505 +				/* success if OK */
 96.2506 +	ret = imap_OK (stream,reply = imap_send (stream,"APPEND",args));
 96.2507 +	LOCAL->appendmailbox = NIL;
 96.2508 +      }
 96.2509 +				/* do succession of single appends */
 96.2510 +      else while ((*af) (stream,data,&map.flags,&map.date,&map.message) &&
 96.2511 +		  map.message &&
 96.2512 +		  (ret = imap_OK (stream,reply =
 96.2513 +				  imap_append_single (stream,tmp,map.flags,
 96.2514 +						      map.date,map.message))));
 96.2515 +      LOCAL->appendmailbox = NIL;
 96.2516 +				/* don't do referrals if success or no reply */
 96.2517 +      if (ret || !reply) mailbox = NIL;
 96.2518 +				/* otherwise generate referral */
 96.2519 +      else if (!(mailbox = (ir && LOCAL->referral) ?
 96.2520 +		 (*ir) (stream,LOCAL->referral,REFAPPEND) : NIL))
 96.2521 +	mm_log (reply->text,ERROR);
 96.2522 +				/* close temporary stream */
 96.2523 +      if (st != stream) stream = mail_close (stream);
 96.2524 +      if (mailbox)		/* chase referral if any */
 96.2525 +	ret = imap_append_referral (mailbox,tmp,af,data,map.flags,map.date,
 96.2526 +				    map.message,&map,debug);
 96.2527 +    }
 96.2528 +    else mm_log ("Can't access server for append",ERROR);
 96.2529 +  }
 96.2530 +  return ret;			/* return */
 96.2531 +}
 96.2532 +
 96.2533 +/* IMAP mail append message referral retry
 96.2534 + * Accepts: destination mailbox
 96.2535 + *	    temporary buffer
 96.2536 + *	    append callback
 96.2537 + *	    data for callback
 96.2538 + *	    flags from previous attempt
 96.2539 + *	    date from previous attempt
 96.2540 + *	    message stringstruct from previous attempt
 96.2541 + *	    options (currently non-zero to set OP_DEBUG)
 96.2542 + * Returns: T if append successful, else NIL
 96.2543 + */
 96.2544 +
 96.2545 +long imap_append_referral (char *mailbox,char *tmp,append_t af,void *data,
 96.2546 +			   char *flags,char *date,STRING *message,
 96.2547 +			   APPENDDATA *map,long options)
 96.2548 +{
 96.2549 +  MAILSTREAM *stream;
 96.2550 +  IMAPARG *args[3],ambx,amap;
 96.2551 +  IMAPPARSEDREPLY *reply;
 96.2552 +  imapreferral_t ir =
 96.2553 +    (imapreferral_t) mail_parameters (NIL,GET_IMAPREFERRAL,NIL);
 96.2554 +				/* barf if bad mailbox */
 96.2555 +  while (mailbox && mail_valid_net (mailbox,&imapdriver,NIL,tmp)) {
 96.2556 +				/* create a stream if given one no good */
 96.2557 +    if (!(stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT |
 96.2558 +			      (options ? OP_DEBUG : NIL)))) {
 96.2559 +      sprintf (tmp,"Can't access referral server: %.80s",mailbox);
 96.2560 +      mm_log (tmp,ERROR);
 96.2561 +      return NIL;
 96.2562 +    }
 96.2563 +				/* got referral server, use multi-append? */
 96.2564 +    if (LEVELMULTIAPPEND (stream)) {
 96.2565 +      ambx.type = ASTRING; ambx.text = (void *) tmp;
 96.2566 +      amap.type = MULTIAPPENDREDO; amap.text = (void *) map;
 96.2567 +      args[0] = &ambx; args[1] = &amap; args[2] = NIL;
 96.2568 +				/* do multiappend on referral site */
 96.2569 +      if (imap_OK (stream,reply = imap_send (stream,"APPEND",args))) {
 96.2570 +	mail_close (stream);	/* multiappend OK, close stream */
 96.2571 +	return LONGT;		/* all done */
 96.2572 +      }
 96.2573 +    }
 96.2574 +				/* do multiple single appends */
 96.2575 +    else while (imap_OK (stream,reply =
 96.2576 +			 imap_append_single (stream,tmp,flags,date,message)))
 96.2577 +      if (!((*af) (stream,data,&flags,&date,&message) && message)) {
 96.2578 +	mail_close (stream);	/* last message, close stream */
 96.2579 +	return LONGT;		/* all done */
 96.2580 +      }
 96.2581 +				/* generate error if no nested referral */
 96.2582 +    if (!(mailbox = (ir && LOCAL->referral) ?
 96.2583 +	  (*ir) (stream,LOCAL->referral,REFAPPEND) : NIL))
 96.2584 +      mm_log (reply->text,ERROR);
 96.2585 +    mail_close (stream);	/* close previous referral stream */
 96.2586 +  }
 96.2587 +  return NIL;			/* bogus mailbox */
 96.2588 +}
 96.2589 +
 96.2590 +/* IMAP append single message
 96.2591 + * Accepts: mail stream
 96.2592 + *	    destination mailbox
 96.2593 + *	    initial flags
 96.2594 + *	    internal date
 96.2595 + *	    stringstruct of message to append
 96.2596 + * Returns: reply from append
 96.2597 + */
 96.2598 +
 96.2599 +IMAPPARSEDREPLY *imap_append_single (MAILSTREAM *stream,char *mailbox,
 96.2600 +				     char *flags,char *date,STRING *message)
 96.2601 +{
 96.2602 +  MESSAGECACHE elt;
 96.2603 +  IMAPARG *args[5],ambx,aflg,adat,amsg;
 96.2604 +  IMAPPARSEDREPLY *reply;
 96.2605 +  char tmp[MAILTMPLEN];
 96.2606 +  int i;
 96.2607 +  ambx.type = ASTRING; ambx.text = (void *) mailbox;
 96.2608 +  args[i = 0] = &ambx;
 96.2609 +  if (flags) {
 96.2610 +    aflg.type = FLAGS; aflg.text = (void *) flags;
 96.2611 +    args[++i] = &aflg;
 96.2612 +  }
 96.2613 +  if (date) {			/* ensure date in INTERNALDATE format */
 96.2614 +    if (!mail_parse_date (&elt,date)) {
 96.2615 +				/* flush previous reply */
 96.2616 +      if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
 96.2617 +				/* build new fake reply */
 96.2618 +      LOCAL->reply.tag = LOCAL->reply.line = cpystr ("*");
 96.2619 +      LOCAL->reply.key = "BAD";
 96.2620 +      LOCAL->reply.text = "Bad date in append";
 96.2621 +      return &LOCAL->reply;
 96.2622 +    }
 96.2623 +    adat.type = ASTRING;
 96.2624 +    adat.text = (void *) (date = mail_date (tmp,&elt));
 96.2625 +    args[++i] = &adat;
 96.2626 +  }
 96.2627 +  amsg.type = LITERAL; amsg.text = (void *) message;
 96.2628 +  args[++i] = &amsg;
 96.2629 +  args[++i] = NIL;
 96.2630 +				/* easy if IMAP4[rev1] */
 96.2631 +  if (LEVELIMAP4 (stream)) reply = imap_send (stream,"APPEND",args);
 96.2632 +  else {			/* try the IMAP2bis way */
 96.2633 +    args[1] = &amsg; args[2] = NIL;
 96.2634 +    reply = imap_send (stream,"APPEND",args);
 96.2635 +  }
 96.2636 +  return reply;
 96.2637 +}
 96.2638 +
 96.2639 +/* IMAP garbage collect stream
 96.2640 + * Accepts: Mail stream
 96.2641 + *	    garbage collection flags
 96.2642 + */
 96.2643 +
 96.2644 +void imap_gc (MAILSTREAM *stream,long gcflags)
 96.2645 +{
 96.2646 +  unsigned long i;
 96.2647 +  MESSAGECACHE *elt;
 96.2648 +  mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
 96.2649 +				/* make sure the cache is large enough */
 96.2650 +  (*mc) (stream,stream->nmsgs,CH_SIZE);
 96.2651 +  if (gcflags & GC_TEXTS) {	/* garbage collect texts? */
 96.2652 +    if (!stream->scache) for (i = 1; i <= stream->nmsgs; ++i)
 96.2653 +      if (elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT))
 96.2654 +	imap_gc_body (elt->private.msg.body);
 96.2655 +    imap_gc_body (stream->body);
 96.2656 +  }
 96.2657 +				/* gc cache if requested and unlocked */
 96.2658 +  if (gcflags & GC_ELT) for (i = 1; i <= stream->nmsgs; ++i)
 96.2659 +    if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) &&
 96.2660 +	(elt->lockcount == 1)) (*mc) (stream,i,CH_FREE);
 96.2661 +}
 96.2662 +
 96.2663 +/* IMAP garbage collect body texts
 96.2664 + * Accepts: body to GC
 96.2665 + */
 96.2666 +
 96.2667 +void imap_gc_body (BODY *body)
 96.2668 +{
 96.2669 +  PART *part;
 96.2670 +  if (body) {			/* have a body? */
 96.2671 +    if (body->mime.text.data)	/* flush MIME data */
 96.2672 +      fs_give ((void **) &body->mime.text.data);
 96.2673 +				/* flush text contents */
 96.2674 +    if (body->contents.text.data)
 96.2675 +      fs_give ((void **) &body->contents.text.data);
 96.2676 +    body->mime.text.size = body->contents.text.size = 0;
 96.2677 +				/* multipart? */
 96.2678 +    if (body->type == TYPEMULTIPART)
 96.2679 +      for (part = body->nested.part; part; part = part->next)
 96.2680 +	imap_gc_body (&part->body);
 96.2681 +				/* MESSAGE/RFC822? */
 96.2682 +    else if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822")) {
 96.2683 +      imap_gc_body (body->nested.msg->body);
 96.2684 +      if (body->nested.msg->full.text.data)
 96.2685 +	fs_give ((void **) &body->nested.msg->full.text.data);
 96.2686 +      if (body->nested.msg->header.text.data)
 96.2687 +	fs_give ((void **) &body->nested.msg->header.text.data);
 96.2688 +      if (body->nested.msg->text.text.data)
 96.2689 +	fs_give ((void **) &body->nested.msg->text.text.data);
 96.2690 +      body->nested.msg->full.text.size = body->nested.msg->header.text.size =
 96.2691 +	body->nested.msg->text.text.size = 0;
 96.2692 +    }
 96.2693 +  }
 96.2694 +}
 96.2695 +
 96.2696 +/* IMAP get capabilities
 96.2697 + * Accepts: mail stream
 96.2698 + */
 96.2699 +
 96.2700 +void imap_capability (MAILSTREAM *stream)
 96.2701 +{
 96.2702 +  THREADER *thr,*t;
 96.2703 +  LOCAL->gotcapability = NIL;	/* flush any previous capabilities */
 96.2704 +				/* request new capabilities */
 96.2705 +  imap_send (stream,"CAPABILITY",NIL);
 96.2706 +  if (!LOCAL->gotcapability) {	/* did server get any? */
 96.2707 +				/* no, flush threaders just in case */
 96.2708 +    if (thr = LOCAL->cap.threader) while (t = thr) {
 96.2709 +      fs_give ((void **) &t->name);
 96.2710 +      thr = t->next;
 96.2711 +      fs_give ((void **) &t);
 96.2712 +    }
 96.2713 +				/* zap most capabilities */
 96.2714 +    memset (&LOCAL->cap,0,sizeof (LOCAL->cap));
 96.2715 +				/* assume IMAP2bis server if failure */
 96.2716 +    LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
 96.2717 +  }
 96.2718 +}
 96.2719 +
 96.2720 +/* IMAP set ACL
 96.2721 + * Accepts: mail stream
 96.2722 + *	    mailbox name
 96.2723 + *	    authentication identifer
 96.2724 + *	    new access rights
 96.2725 + * Returns: T on success, NIL on failure
 96.2726 + */
 96.2727 +
 96.2728 +long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights)
 96.2729 +{
 96.2730 +  IMAPARG *args[4],ambx,aid,art;
 96.2731 +  ambx.type = aid.type = art.type = ASTRING;
 96.2732 +  ambx.text = (void *) mailbox; aid.text = (void *) id;
 96.2733 +  art.text = (void *) rights;
 96.2734 +  args[0] = &ambx; args[1] = &aid; args[2] = &art; args[3] = NIL;
 96.2735 +  return imap_acl_work (stream,"SETACL",args);
 96.2736 +}
 96.2737 +
 96.2738 +
 96.2739 +/* IMAP delete ACL
 96.2740 + * Accepts: mail stream
 96.2741 + *	    mailbox name
 96.2742 + *	    authentication identifer
 96.2743 + * Returns: T on success, NIL on failure
 96.2744 + */
 96.2745 +
 96.2746 +long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id)
 96.2747 +{
 96.2748 +  IMAPARG *args[3],ambx,aid;
 96.2749 +  ambx.type = aid.type = ASTRING;
 96.2750 +  ambx.text = (void *) mailbox; aid.text = (void *) id;
 96.2751 +  args[0] = &ambx; args[1] = &aid; args[2] = NIL;
 96.2752 +  return imap_acl_work (stream,"DELETEACL",args);
 96.2753 +}
 96.2754 +
 96.2755 +
 96.2756 +/* IMAP get ACL
 96.2757 + * Accepts: mail stream
 96.2758 + *	    mailbox name
 96.2759 + * Returns: T on success with data returned via callback, NIL on failure
 96.2760 + */
 96.2761 +
 96.2762 +long imap_getacl (MAILSTREAM *stream,char *mailbox)
 96.2763 +{
 96.2764 +  IMAPARG *args[2],ambx;
 96.2765 +  ambx.type = ASTRING; ambx.text = (void *) mailbox;
 96.2766 +    args[0] = &ambx; args[1] = NIL;
 96.2767 +  return imap_acl_work (stream,"GETACL",args);
 96.2768 +}
 96.2769 +
 96.2770 +/* IMAP list rights
 96.2771 + * Accepts: mail stream
 96.2772 + *	    mailbox name
 96.2773 + *	    authentication identifer
 96.2774 + * Returns: T on success with data returned via callback, NIL on failure
 96.2775 + */
 96.2776 +
 96.2777 +long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id)
 96.2778 +{
 96.2779 +  IMAPARG *args[3],ambx,aid;
 96.2780 +  ambx.type = aid.type = ASTRING;
 96.2781 +  ambx.text = (void *) mailbox; aid.text = (void *) id;
 96.2782 +  args[0] = &ambx; args[1] = &aid; args[2] = NIL;
 96.2783 +  return imap_acl_work (stream,"LISTRIGHTS",args);
 96.2784 +}
 96.2785 +
 96.2786 +
 96.2787 +/* IMAP my rights
 96.2788 + * Accepts: mail stream
 96.2789 + *	    mailbox name
 96.2790 + * Returns: T on success with data returned via callback, NIL on failure
 96.2791 + */
 96.2792 +
 96.2793 +long imap_myrights (MAILSTREAM *stream,char *mailbox)
 96.2794 +{
 96.2795 +  IMAPARG *args[2],ambx;
 96.2796 +  ambx.type = ASTRING; ambx.text = (void *) mailbox;
 96.2797 +  args[0] = &ambx; args[1] = NIL;
 96.2798 +  return imap_acl_work (stream,"MYRIGHTS",args);
 96.2799 +}
 96.2800 +
 96.2801 +
 96.2802 +/* IMAP ACL worker routine
 96.2803 + * Accepts: mail stream
 96.2804 + *	    command
 96.2805 + *	    command arguments
 96.2806 + * Returns: T on success, NIL on failure
 96.2807 + */
 96.2808 +
 96.2809 +long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[])
 96.2810 +{
 96.2811 +  long ret = NIL;
 96.2812 +  if (LEVELACL (stream)) {	/* send command */
 96.2813 +    IMAPPARSEDREPLY *reply;
 96.2814 +    if (imap_OK (stream,reply = imap_send (stream,command,args)))
 96.2815 +      ret = LONGT;
 96.2816 +    else mm_log (reply->text,ERROR);
 96.2817 +  }
 96.2818 +  else mm_log ("ACL not available on this IMAP server",ERROR);
 96.2819 +  return ret;
 96.2820 +}
 96.2821 +
 96.2822 +/* IMAP set quota
 96.2823 + * Accepts: mail stream
 96.2824 + *	    quota root name
 96.2825 + *	    resource limit list as a stringlist
 96.2826 + * Returns: T on success with data returned via callback, NIL on failure
 96.2827 + */
 96.2828 +
 96.2829 +long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits)
 96.2830 +{
 96.2831 +  long ret = NIL;
 96.2832 +  if (LEVELQUOTA (stream)) {	/* send "SETQUOTA" */
 96.2833 +    IMAPPARSEDREPLY *reply;
 96.2834 +    IMAPARG *args[3],aqrt,alim;
 96.2835 +    aqrt.type = ASTRING; aqrt.text = (void *) qroot;
 96.2836 +    alim.type = SNLIST; alim.text = (void *) limits;
 96.2837 +    args[0] = &aqrt; args[1] = &alim; args[2] = NIL;
 96.2838 +    if (imap_OK (stream,reply = imap_send (stream,"SETQUOTA",args)))
 96.2839 +      ret = LONGT;
 96.2840 +    else mm_log (reply->text,ERROR);
 96.2841 +  }
 96.2842 +  else mm_log ("Quota not available on this IMAP server",ERROR);
 96.2843 +  return ret;
 96.2844 +}
 96.2845 +
 96.2846 +/* IMAP get quota
 96.2847 + * Accepts: mail stream
 96.2848 + *	    quota root name
 96.2849 + * Returns: T on success with data returned via callback, NIL on failure
 96.2850 + */
 96.2851 +
 96.2852 +long imap_getquota (MAILSTREAM *stream,char *qroot)
 96.2853 +{
 96.2854 +  long ret = NIL;
 96.2855 +  if (LEVELQUOTA (stream)) {	/* send "GETQUOTA" */
 96.2856 +    IMAPPARSEDREPLY *reply;
 96.2857 +    IMAPARG *args[2],aqrt;
 96.2858 +    aqrt.type = ASTRING; aqrt.text = (void *) qroot;
 96.2859 +    args[0] = &aqrt; args[1] = NIL;
 96.2860 +    if (imap_OK (stream,reply = imap_send (stream,"GETQUOTA",args)))
 96.2861 +      ret = LONGT;
 96.2862 +    else mm_log (reply->text,ERROR);
 96.2863 +  }
 96.2864 +  else mm_log ("Quota not available on this IMAP server",ERROR);
 96.2865 +  return ret;
 96.2866 +}
 96.2867 +
 96.2868 +
 96.2869 +/* IMAP get quota root
 96.2870 + * Accepts: mail stream
 96.2871 + *	    mailbox name
 96.2872 + * Returns: T on success with data returned via callback, NIL on failure
 96.2873 + */
 96.2874 +
 96.2875 +long imap_getquotaroot (MAILSTREAM *stream,char *mailbox)
 96.2876 +{
 96.2877 +  long ret = NIL;
 96.2878 +  if (LEVELQUOTA (stream)) {	/* send "GETQUOTAROOT" */
 96.2879 +    IMAPPARSEDREPLY *reply;
 96.2880 +    IMAPARG *args[2],ambx;
 96.2881 +    ambx.type = ASTRING; ambx.text = (void *) mailbox;
 96.2882 +    args[0] = &ambx; args[1] = NIL;
 96.2883 +    if (imap_OK (stream,reply = imap_send (stream,"GETQUOTAROOT",args)))
 96.2884 +      ret = LONGT;
 96.2885 +    else mm_log (reply->text,ERROR);
 96.2886 +  }
 96.2887 +  else mm_log ("Quota not available on this IMAP server",ERROR);
 96.2888 +  return ret;
 96.2889 +}
 96.2890 +
 96.2891 +/* Internal routines */
 96.2892 +
 96.2893 +
 96.2894 +/* IMAP send command
 96.2895 + * Accepts: MAIL stream
 96.2896 + *	    command
 96.2897 + *	    argument list
 96.2898 + * Returns: parsed reply
 96.2899 + */
 96.2900 +
 96.2901 +#define CMDBASE LOCAL->tmp	/* command base */
 96.2902 +
 96.2903 +IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[])
 96.2904 +{
 96.2905 +  IMAPPARSEDREPLY *reply;
 96.2906 +  IMAPARG *arg,**arglst;
 96.2907 +  SORTPGM *spg;
 96.2908 +  STRINGLIST *list;
 96.2909 +  SIZEDTEXT st;
 96.2910 +  APPENDDATA *map;
 96.2911 +  sendcommand_t sc = (sendcommand_t) mail_parameters (NIL,GET_SENDCOMMAND,NIL);
 96.2912 +  size_t i;
 96.2913 +  void *a;
 96.2914 +  char c,*s,*t,tag[10];
 96.2915 +  stream->unhealthy = NIL;	/* make stream healthy again */
 96.2916 +  				/* gensym a new tag */
 96.2917 +  sprintf (tag,"%08lx",0xffffffff & (stream->gensym++));
 96.2918 +  if (!LOCAL->netstream)	/* make sure have a session */
 96.2919 +    return imap_fake (stream,tag,"[CLOSED] IMAP connection lost");
 96.2920 +  mail_lock (stream);		/* lock up the stream */
 96.2921 +  if (sc)			/* tell client sending a command */
 96.2922 +    (*sc) (stream,cmd,((compare_cstring (cmd,"FETCH") &&
 96.2923 +			compare_cstring (cmd,"STORE") &&
 96.2924 +			compare_cstring (cmd,"SEARCH")) ? 
 96.2925 +		       NIL : SC_EXPUNGEDEFERRED));
 96.2926 +				/* ignore referral from previous command */
 96.2927 +  if (LOCAL->referral) fs_give ((void **) &LOCAL->referral);
 96.2928 +  sprintf (CMDBASE,"%s %s",tag,cmd);
 96.2929 +  s = CMDBASE + strlen (CMDBASE);
 96.2930 +  if (arglst = args) while (arg = *arglst++) {
 96.2931 +    *s++ = ' ';			/* delimit argument with space */
 96.2932 +    switch (arg->type) {
 96.2933 +    case ATOM:			/* atom */
 96.2934 +      for (t = (char *) arg->text; *t; *s++ = *t++);
 96.2935 +      break;
 96.2936 +    case NUMBER:		/* number */
 96.2937 +      sprintf (s,"%lu",(unsigned long) arg->text);
 96.2938 +      s += strlen (s);
 96.2939 +      break;
 96.2940 +    case FLAGS:			/* flag list as a single string */
 96.2941 +      if (*(t = (char *) arg->text) != '(') {
 96.2942 +	*s++ = '(';		/* wrap parens around string */
 96.2943 +	while (*t) *s++ = *t++;
 96.2944 +	*s++ = ')';		/* wrap parens around string */
 96.2945 +      }
 96.2946 +      else while (*t) *s++ = *t++;
 96.2947 +      break;
 96.2948 +    case ASTRING:		/* atom or string, must be literal? */
 96.2949 +      st.size = strlen ((char *) (st.data = (unsigned char *) arg->text));
 96.2950 +      if (reply = imap_send_astring (stream,tag,&s,&st,NIL,CMDBASE+MAXCOMMAND))
 96.2951 +	return reply;
 96.2952 +      break;
 96.2953 +    case LITERAL:		/* literal, as a stringstruct */
 96.2954 +      if (reply = imap_send_literal (stream,tag,&s,arg->text)) return reply;
 96.2955 +      break;
 96.2956 +
 96.2957 +    case LIST:			/* list of strings */
 96.2958 +      list = (STRINGLIST *) arg->text;
 96.2959 +      c = '(';			/* open paren */
 96.2960 +      do {			/* for each list item */
 96.2961 +	*s++ = c;		/* write prefix character */
 96.2962 +	if (reply = imap_send_astring (stream,tag,&s,&list->text,NIL,
 96.2963 +				       CMDBASE+MAXCOMMAND)) return reply;
 96.2964 +	c = ' ';		/* prefix character for subsequent strings */
 96.2965 +      }
 96.2966 +      while (list = list->next);
 96.2967 +      *s++ = ')';		/* close list */
 96.2968 +      break;
 96.2969 +    case SEARCHPROGRAM:		/* search program */
 96.2970 +      if (reply = imap_send_spgm (stream,tag,CMDBASE,&s,arg->text,
 96.2971 +				  CMDBASE+MAXCOMMAND))
 96.2972 +	return reply;
 96.2973 +      break;
 96.2974 +    case SORTPROGRAM:		/* search program */
 96.2975 +      c = '(';			/* open paren */
 96.2976 +      for (spg = (SORTPGM *) arg->text; spg; spg = spg->next) {
 96.2977 +	*s++ = c;		/* write prefix */
 96.2978 +	if (spg->reverse) for (t = "REVERSE "; *t; *s++ = *t++);
 96.2979 +	switch (spg->function) {
 96.2980 +	case SORTDATE:
 96.2981 +	  for (t = "DATE"; *t; *s++ = *t++);
 96.2982 +	  break;
 96.2983 +	case SORTARRIVAL:
 96.2984 +	  for (t = "ARRIVAL"; *t; *s++ = *t++);
 96.2985 +	  break;
 96.2986 +	case SORTFROM:
 96.2987 +	  for (t = "FROM"; *t; *s++ = *t++);
 96.2988 +	  break;
 96.2989 +	case SORTSUBJECT:
 96.2990 +	  for (t = "SUBJECT"; *t; *s++ = *t++);
 96.2991 +	  break;
 96.2992 +	case SORTTO:
 96.2993 +	  for (t = "TO"; *t; *s++ = *t++);
 96.2994 +	  break;
 96.2995 +	case SORTCC:
 96.2996 +	  for (t = "CC"; *t; *s++ = *t++);
 96.2997 +	  break;
 96.2998 +	case SORTSIZE:
 96.2999 +	  for (t = "SIZE"; *t; *s++ = *t++);
 96.3000 +	  break;
 96.3001 +	default:
 96.3002 +	  fatal ("Unknown sort program function in imap_send()!");
 96.3003 +	}
 96.3004 +	c = ' ';		/* prefix character for subsequent items */
 96.3005 +      }
 96.3006 +      *s++ = ')';		/* close list */
 96.3007 +      break;
 96.3008 +
 96.3009 +    case BODYTEXT:		/* body section */
 96.3010 +      for (t = "BODY["; *t; *s++ = *t++);
 96.3011 +      for (t = (char *) arg->text; *t; *s++ = *t++);
 96.3012 +      break;
 96.3013 +    case BODYPEEK:		/* body section */
 96.3014 +      for (t = "BODY.PEEK["; *t; *s++ = *t++);
 96.3015 +      for (t = (char *) arg->text; *t; *s++ = *t++);
 96.3016 +      break;
 96.3017 +    case BODYCLOSE:		/* close bracket and possible length */
 96.3018 +      s[-1] = ']';		/* no leading space */
 96.3019 +      for (t = (char *) arg->text; *t; *s++ = *t++);
 96.3020 +      break;
 96.3021 +    case SEQUENCE:		/* sequence */
 96.3022 +      if ((i = strlen (t = (char *) arg->text)) <= (size_t) MAXCOMMAND)
 96.3023 +	while (*t) *s++ = *t++;	/* easy case */
 96.3024 +      else {
 96.3025 +	mail_unlock (stream);	/* unlock stream */
 96.3026 +	a = arg->text;		/* save original sequence pointer */
 96.3027 +	arg->type = ATOM;	/* make recursive call be faster */
 96.3028 +	do {			/* break up into multiple commands */
 96.3029 +	  if (i <= MAXCOMMAND) {/* final part? */
 96.3030 +	    reply = imap_send (stream,cmd,args);
 96.3031 +	    i = 0;		/* and mark as done */
 96.3032 +	  }
 96.3033 +	  else {		/* still needs to be split further */
 96.3034 +	    if (!(t = strchr (t + MAXCOMMAND - 30,',')) ||
 96.3035 +		((t - (char *) arg->text) > MAXCOMMAND))
 96.3036 +	      fatal ("impossible over-long sequence");
 96.3037 +	    *t = '\0';		/* tie off sequence at point of split*/
 96.3038 +				/* recurse to do this part */
 96.3039 +	    reply = imap_send (stream,cmd,args);
 96.3040 +	    *t++ = ',';		/* restore the comma in case something cares */
 96.3041 +				/* punt if error */
 96.3042 +	    if (!imap_OK (stream,reply)) break;
 96.3043 +				/* calculate size of remaining sequence */
 96.3044 +	    i -= (t - (char *) arg->text);
 96.3045 +				/* point to new remaining sequence */
 96.3046 +	    arg->text = (void *) t;
 96.3047 +	  }
 96.3048 +	} while (i);
 96.3049 +	arg->type = SEQUENCE;	/* restore in case something cares */
 96.3050 +	arg->text = a;
 96.3051 +	return reply;		/* return result */
 96.3052 +      }
 96.3053 +      break;
 96.3054 +    case LISTMAILBOX:		/* astring with wildcards */
 96.3055 +      st.size = strlen ((char *) (st.data = (unsigned char *) arg->text));
 96.3056 +      if (reply = imap_send_astring (stream,tag,&s,&st,T,CMDBASE+MAXCOMMAND))
 96.3057 +	return reply;
 96.3058 +      break;
 96.3059 +
 96.3060 +    case MULTIAPPEND:		/* append multiple messages */
 96.3061 +				/* get package pointer */
 96.3062 +      map = (APPENDDATA *) arg->text;
 96.3063 +      if (!(*map->af) (stream,map->data,&map->flags,&map->date,&map->message)||
 96.3064 +	  !map->message) {
 96.3065 +	STRING es;
 96.3066 +	INIT (&es,mail_string,"",0);
 96.3067 +	return (reply = imap_send_literal (stream,tag,&s,&es)) ?
 96.3068 +	  reply : imap_fake (stream,tag,"Server zero-length literal error");
 96.3069 +      }
 96.3070 +    case MULTIAPPENDREDO:	/* redo multiappend */
 96.3071 +				/* get package pointer */
 96.3072 +      map = (APPENDDATA *) arg->text;
 96.3073 +      do {			/* make sure date valid if given */
 96.3074 +	char datetmp[MAILTMPLEN];
 96.3075 +	MESSAGECACHE elt;
 96.3076 +	STRING es;
 96.3077 +	if (!map->date || mail_parse_date (&elt,map->date)) {
 96.3078 +	  if (t = map->flags) {	/* flags given? */
 96.3079 +	    if (*t != '(') {
 96.3080 +	      *s++ = '(';	/* wrap parens around string */
 96.3081 +	      while (*t) *s++ = *t++;
 96.3082 +	      *s++ = ')';	/* wrap parens around string */
 96.3083 +	    }
 96.3084 +	    else while (*t) *s++ = *t++;
 96.3085 +	    *s++ = ' ';		/* delimit with space */
 96.3086 +	  }
 96.3087 +	  if (map->date) {	/* date given? */
 96.3088 +	    st.size = strlen ((char *) (st.data = (unsigned char *)
 96.3089 +					mail_date (datetmp,&elt)));
 96.3090 +	    if (reply = imap_send_astring (stream,tag,&s,&st,NIL,
 96.3091 +					   CMDBASE+MAXCOMMAND)) return reply;
 96.3092 +	    *s++ = ' ';		/* delimit with space */
 96.3093 +	  }
 96.3094 +	  if (reply = imap_send_literal (stream,tag,&s,map->message))
 96.3095 +	    return reply;
 96.3096 +				/* get next message */
 96.3097 +	  if ((*map->af) (stream,map->data,&map->flags,&map->date,
 96.3098 +			  &map->message)) {
 96.3099 +				/* have a message, delete next in command */
 96.3100 +	    if (map->message) *s++ = ' ';
 96.3101 +	    continue;		/* loop back for next message */
 96.3102 +	  }
 96.3103 +	}
 96.3104 +				/* bad date or need to abort */
 96.3105 +	INIT (&es,mail_string,"",0);
 96.3106 +	return (reply = imap_send_literal (stream,tag,&s,&es)) ?
 96.3107 +	  reply : imap_fake (stream,tag,"Server zero-length literal error");
 96.3108 +	break;			/* exit the loop */
 96.3109 +      } while (map->message);
 96.3110 +      break;
 96.3111 +
 96.3112 +    case SNLIST:		/* list of string/number pairs */
 96.3113 +      list = (STRINGLIST *) arg->text;
 96.3114 +      c = '(';			/* open paren */
 96.3115 +      do {			/* for each list item */
 96.3116 +	*s++ = c;		/* write prefix character */
 96.3117 +	if (list) {		/* sigh, QUOTA has bizarre syntax! */
 96.3118 +	  for (t = (char *) list->text.data; *t; *s++ = *t++);
 96.3119 +	  sprintf (s," %lu",list->text.size);
 96.3120 +	  s += strlen (s);
 96.3121 +	  c = ' ';		/* prefix character for subsequent strings */
 96.3122 +	}
 96.3123 +      }
 96.3124 +      while (list = list->next);
 96.3125 +      *s++ = ')';		/* close list */
 96.3126 +      break;
 96.3127 +    default:
 96.3128 +      fatal ("Unknown argument type in imap_send()!");
 96.3129 +    }
 96.3130 +  }
 96.3131 +				/* send the command */
 96.3132 +  reply = imap_sout (stream,tag,CMDBASE,&s);
 96.3133 +  mail_unlock (stream);		/* unlock stream */
 96.3134 +  return reply;
 96.3135 +}
 96.3136 +
 96.3137 +/* IMAP send atom-string
 96.3138 + * Accepts: MAIL stream
 96.3139 + *	    reply tag
 96.3140 + *	    pointer to current position pointer of output bigbuf
 96.3141 + *	    atom-string to output
 96.3142 + *	    flag if list_wildcards allowed
 96.3143 + *	    maximum to write as atom or qstring
 96.3144 + * Returns: error reply or NIL if success
 96.3145 + */
 96.3146 +
 96.3147 +IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s,
 96.3148 +				    SIZEDTEXT *as,long wildok,char *limit)
 96.3149 +{
 96.3150 +  unsigned long j;
 96.3151 +  char c;
 96.3152 +  STRING st;
 96.3153 +				/* default to atom unless empty or loser */
 96.3154 +  int qflag = (as->size && !LOCAL->loser) ? NIL : T;
 96.3155 +				/* in case needed */
 96.3156 +  INIT (&st,mail_string,(void *) as->data,as->size);
 96.3157 +				/* always write literal if no space */
 96.3158 +  if ((*s + as->size) > limit) return imap_send_literal (stream,tag,s,&st);
 96.3159 +  for (j = 0; j < as->size; j++) switch (c = as->data[j]) {
 96.3160 +  default:			/* all other characters */
 96.3161 +    if (!(c & 0x80)) {		/* must not be 8bit */
 96.3162 +      if (c <= ' ') qflag = T;	/* must quote if a CTL */
 96.3163 +      break;
 96.3164 +    }
 96.3165 +  case '\0':			/* not a CHAR */
 96.3166 +  case '\012': case '\015':	/* not a TEXT-CHAR */
 96.3167 +  case '"': case '\\':		/* quoted-specials (IMAP2 required this) */
 96.3168 +    return imap_send_literal (stream,tag,s,&st);
 96.3169 +  case '*': case '%':		/* list_wildcards */
 96.3170 +    if (wildok) break;		/* allowed if doing the wild thing */
 96.3171 +				/* atom_specials */
 96.3172 +  case '(': case ')': case '{': case ' ': case 0x7f:
 96.3173 +#if 0
 96.3174 +  case '"': case '\\':		/* quoted-specials (could work in IMAP4) */
 96.3175 +#endif
 96.3176 +    qflag = T;			/* must use quoted string format */
 96.3177 +    break;
 96.3178 +  }
 96.3179 +  if (qflag) *(*s)++ = '"';	/* write open quote */
 96.3180 +  for (j = 0; j < as->size; j++) *(*s)++ = as->data[j];
 96.3181 +  if (qflag) *(*s)++ = '"';	/* write close quote */
 96.3182 +  return NIL;
 96.3183 +}
 96.3184 +
 96.3185 +/* IMAP send literal
 96.3186 + * Accepts: MAIL stream
 96.3187 + *	    reply tag
 96.3188 + *	    pointer to current position pointer of output bigbuf
 96.3189 + *	    literal to output as stringstruct
 96.3190 + * Returns: error reply or NIL if success
 96.3191 + */
 96.3192 +
 96.3193 +IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
 96.3194 +				    STRING *st)
 96.3195 +{
 96.3196 +  IMAPPARSEDREPLY *reply;
 96.3197 +  unsigned long i = SIZE (st);
 96.3198 +  unsigned long j;
 96.3199 +  sprintf (*s,"{%lu}",i);	/* write literal count */
 96.3200 +  *s += strlen (*s);		/* size of literal count */
 96.3201 +				/* send the command */
 96.3202 +  reply = imap_sout (stream,tag,CMDBASE,s);
 96.3203 +  if (strcmp (reply->tag,"+")) {/* prompt for more data? */
 96.3204 +    mail_unlock (stream);	/* no, give up */
 96.3205 +    return reply;
 96.3206 +  }
 96.3207 +  while (i) {			/* dump the text */
 96.3208 +    if (st->cursize) {		/* if text to do in this chunk */
 96.3209 +      /* RFC 3501 technically forbids NULs in literals.  Normally, the
 96.3210 +       * delivering MTA would take care of MIME converting the message text
 96.3211 +       * so that it is NUL-free.  If it doesn't, then we have the choice of
 96.3212 +       * either violating IMAP by sending NULs, corrupting the data, or going
 96.3213 +       * to lots of work to do MIME conversion in the IMAP server.
 96.3214 +       *
 96.3215 +       * No current stringstruct driver objects to having its buffer patched.
 96.3216 +       * If this ever changes, it will be necessary to change this kludge.
 96.3217 +       */
 96.3218 +				/* patch NULs to C1 control */
 96.3219 +      for (j = 0; j < st->cursize; ++j)
 96.3220 +	if (!st->curpos[j]) st->curpos[j] = 0x80;
 96.3221 +      if (!net_sout (LOCAL->netstream,st->curpos,st->cursize)) {
 96.3222 +	mail_unlock (stream);
 96.3223 +	return imap_fake (stream,tag,"[CLOSED] IMAP connection broken (data)");
 96.3224 +      }
 96.3225 +      i -= st->cursize;		/* note that we wrote out this much */
 96.3226 +      st->curpos += (st->cursize - 1);
 96.3227 +      st->cursize = 0;
 96.3228 +    }
 96.3229 +    (*st->dtb->next) (st);	/* advance to next buffer's worth */
 96.3230 +  }
 96.3231 +  return NIL;			/* success */
 96.3232 +}
 96.3233 +
 96.3234 +/* IMAP send search program
 96.3235 + * Accepts: MAIL stream
 96.3236 + *	    reply tag
 96.3237 + *	    base pointer if trimming needed
 96.3238 + *	    pointer to current position pointer of output bigbuf
 96.3239 + *	    search program to output
 96.3240 + *	    pointer to limit guideline
 96.3241 + * Returns: error reply or NIL if success
 96.3242 + */
 96.3243 +
 96.3244 +
 96.3245 +IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base,
 96.3246 +				 char **s,SEARCHPGM *pgm,char *limit)
 96.3247 +{
 96.3248 +  IMAPPARSEDREPLY *reply;
 96.3249 +  SEARCHHEADER *hdr;
 96.3250 +  SEARCHOR *pgo;
 96.3251 +  SEARCHPGMLIST *pgl;
 96.3252 +  char *t;
 96.3253 +				/* trim if called recursively */
 96.3254 +  if (base) *s = imap_send_spgm_trim (base,*s,NIL);
 96.3255 +  base = *s;			/* this is the new base */
 96.3256 +				/* default searchpgm */
 96.3257 +  for (t = "ALL"; *t; *(*s)++ = *t++);
 96.3258 +  if (!pgm) return NIL;		/* done if NIL searchpgm */
 96.3259 +  if ((pgm->msgno &&		/* message sequences */
 96.3260 +       (pgm->msgno->next ||	/* trim away first:last */
 96.3261 +	(pgm->msgno->first != 1) || (pgm->msgno->last != stream->nmsgs)) &&
 96.3262 +       (reply = imap_send_sset (stream,tag,base,s,pgm->msgno," ",limit))) ||
 96.3263 +      (pgm->uid &&
 96.3264 +       (reply = imap_send_sset (stream,tag,base,s,pgm->uid," UID ",limit))))
 96.3265 +    return reply;
 96.3266 +				/* message sizes */
 96.3267 +  if (pgm->larger) {
 96.3268 +    sprintf (*s," LARGER %lu",pgm->larger);
 96.3269 +    *s += strlen (*s);
 96.3270 +  }
 96.3271 +  if (pgm->smaller) {
 96.3272 +    sprintf (*s," SMALLER %lu",pgm->smaller);
 96.3273 +    *s += strlen (*s);
 96.3274 +  }
 96.3275 +
 96.3276 +				/* message flags */
 96.3277 +  if (pgm->answered) for (t = " ANSWERED"; *t; *(*s)++ = *t++);
 96.3278 +  if (pgm->unanswered) for (t =" UNANSWERED"; *t; *(*s)++ = *t++);
 96.3279 +  if (pgm->deleted) for (t =" DELETED"; *t; *(*s)++ = *t++);
 96.3280 +  if (pgm->undeleted) for (t =" UNDELETED"; *t; *(*s)++ = *t++);
 96.3281 +  if (pgm->draft) for (t =" DRAFT"; *t; *(*s)++ = *t++);
 96.3282 +  if (pgm->undraft) for (t =" UNDRAFT"; *t; *(*s)++ = *t++);
 96.3283 +  if (pgm->flagged) for (t =" FLAGGED"; *t; *(*s)++ = *t++);
 96.3284 +  if (pgm->unflagged) for (t =" UNFLAGGED"; *t; *(*s)++ = *t++);
 96.3285 +  if (pgm->recent) for (t =" RECENT"; *t; *(*s)++ = *t++);
 96.3286 +  if (pgm->old) for (t =" OLD"; *t; *(*s)++ = *t++);
 96.3287 +  if (pgm->seen) for (t =" SEEN"; *t; *(*s)++ = *t++);
 96.3288 +  if (pgm->unseen) for (t =" UNSEEN"; *t; *(*s)++ = *t++);
 96.3289 +  if ((pgm->keyword &&		/* keywords */
 96.3290 +       (reply = imap_send_slist (stream,tag,base,s," KEYWORD ",pgm->keyword,
 96.3291 +				 limit))) ||
 96.3292 +      (pgm->unkeyword &&
 96.3293 +       (reply = imap_send_slist (stream,tag,base,s," UNKEYWORD ",
 96.3294 +				 pgm->unkeyword,limit))))
 96.3295 +    return reply;
 96.3296 +				/* sent date ranges */
 96.3297 +  if (pgm->sentbefore) imap_send_sdate (s,"SENTBEFORE",pgm->sentbefore);
 96.3298 +  if (pgm->senton) imap_send_sdate (s,"SENTON",pgm->senton);
 96.3299 +  if (pgm->sentsince) imap_send_sdate (s,"SENTSINCE",pgm->sentsince);
 96.3300 +				/* internal date ranges */
 96.3301 +  if (pgm->before) imap_send_sdate (s,"BEFORE",pgm->before);
 96.3302 +  if (pgm->on) imap_send_sdate (s,"ON",pgm->on);
 96.3303 +  if (pgm->since) imap_send_sdate (s,"SINCE",pgm->since);
 96.3304 +  if (pgm->older) {
 96.3305 +    sprintf (*s," OLDER %lu",pgm->older);
 96.3306 +    *s += strlen (*s);
 96.3307 +  }
 96.3308 +  if (pgm->younger) {
 96.3309 +    sprintf (*s," YOUNGER %lu",pgm->younger);
 96.3310 +    *s += strlen (*s);
 96.3311 +  }
 96.3312 +				/* search texts */
 96.3313 +  if ((pgm->bcc && (reply = imap_send_slist (stream,tag,base,s," BCC ",
 96.3314 +					     pgm->bcc,limit))) ||
 96.3315 +      (pgm->cc && (reply = imap_send_slist (stream,tag,base,s," CC ",pgm->cc,
 96.3316 +					    limit))) ||
 96.3317 +      (pgm->from && (reply = imap_send_slist (stream,tag,base,s," FROM ",
 96.3318 +					      pgm->from,limit))) ||
 96.3319 +      (pgm->to && (reply = imap_send_slist (stream,tag,base,s," TO ",pgm->to,
 96.3320 +					    limit))))
 96.3321 +    return reply;
 96.3322 +  if ((pgm->subject && (reply = imap_send_slist (stream,tag,base,s," SUBJECT ",
 96.3323 +						 pgm->subject,limit))) ||
 96.3324 +      (pgm->body && (reply = imap_send_slist (stream,tag,base,s," BODY ",
 96.3325 +					      pgm->body,limit))) ||
 96.3326 +      (pgm->text && (reply = imap_send_slist (stream,tag,base,s," TEXT ",
 96.3327 +					      pgm->text,limit))))
 96.3328 +    return reply;
 96.3329 +
 96.3330 +  /* Note that these criteria are not supported by IMAP and have to be
 96.3331 +     emulated */
 96.3332 +  if ((pgm->return_path &&
 96.3333 +       (reply = imap_send_slist (stream,tag,base,s," HEADER Return-Path ",
 96.3334 +				 pgm->return_path,limit))) ||
 96.3335 +      (pgm->sender &&
 96.3336 +       (reply = imap_send_slist (stream,tag,base,s," HEADER Sender ",
 96.3337 +				 pgm->sender,limit))) ||
 96.3338 +      (pgm->reply_to &&
 96.3339 +       (reply = imap_send_slist (stream,tag,base,s," HEADER Reply-To ",
 96.3340 +				 pgm->reply_to,limit))) ||
 96.3341 +      (pgm->in_reply_to &&
 96.3342 +       (reply = imap_send_slist (stream,tag,base,s," HEADER In-Reply-To ",
 96.3343 +				 pgm->in_reply_to,limit))) ||
 96.3344 +      (pgm->message_id &&
 96.3345 +       (reply = imap_send_slist (stream,tag,base,s," HEADER Message-ID ",
 96.3346 +				 pgm->message_id,limit))) ||
 96.3347 +      (pgm->newsgroups &&
 96.3348 +       (reply = imap_send_slist (stream,tag,base,s," HEADER Newsgroups ",
 96.3349 +				 pgm->newsgroups,limit))) ||
 96.3350 +      (pgm->followup_to &&
 96.3351 +       (reply = imap_send_slist (stream,tag,base,s," HEADER Followup-To ",
 96.3352 +				 pgm->followup_to,limit))) ||
 96.3353 +      (pgm->references &&
 96.3354 +       (reply = imap_send_slist (stream,tag,base,s," HEADER References ",
 96.3355 +				 pgm->references,limit)))) return reply;
 96.3356 +
 96.3357 +				/* all other headers */
 96.3358 +  if (hdr = pgm->header) do {
 96.3359 +    *s = imap_send_spgm_trim (base,*s," HEADER ");
 96.3360 +    if (reply = imap_send_astring (stream,tag,s,&hdr->line,NIL,limit))
 96.3361 +      return reply;
 96.3362 +    *(*s)++ = ' ';
 96.3363 +    if (reply = imap_send_astring (stream,tag,s,&hdr->text,NIL,limit))
 96.3364 +      return reply;
 96.3365 +  } while (hdr = hdr->next);
 96.3366 +  for (pgo = pgm->or; pgo; pgo = pgo->next) {
 96.3367 +    *s = imap_send_spgm_trim (base,*s," OR (");
 96.3368 +    if (reply = imap_send_spgm (stream,tag,base,s,pgo->first,limit))
 96.3369 +      return reply;
 96.3370 +    for (t = ") ("; *t; *(*s)++ = *t++);
 96.3371 +    if (reply = imap_send_spgm (stream,tag,base,s,pgo->second,limit))
 96.3372 +      return reply;
 96.3373 +    *(*s)++ = ')';
 96.3374 +  }
 96.3375 +  for (pgl = pgm->not; pgl; pgl = pgl->next) {
 96.3376 +    *s = imap_send_spgm_trim (base,*s," NOT (");
 96.3377 +    if (reply = imap_send_spgm (stream,tag,base,s,pgl->pgm,limit))
 96.3378 +      return reply;
 96.3379 +    *(*s)++ = ')';
 96.3380 +  }
 96.3381 +				/* trim if needed */
 96.3382 +  *s = imap_send_spgm_trim (base,*s,NIL);
 96.3383 +  return NIL;			/* search program written OK */
 96.3384 +}
 96.3385 +
 96.3386 +
 96.3387 +/* Write new text and trim extraneous "ALL" from searchpgm
 96.3388 + * Accepts: pointer to start of searchpgm or NIL
 96.3389 + *	    current end pointer
 96.3390 + *	    new text to write or NIL
 96.3391 + * Returns: new end pointer, trimmed if needed
 96.3392 + */
 96.3393 +
 96.3394 +char *imap_send_spgm_trim (char *base,char *s,char *text)
 96.3395 +{
 96.3396 +  char *t;
 96.3397 +				/* write new text */
 96.3398 +  if (text) for (t = text; *t; *s++ = *t++);
 96.3399 +				/* need to trim? */
 96.3400 +  if (base && (s > (t = (base + 4))) && (*base == 'A') && (base[1] == 'L') &&
 96.3401 +      (base[2] == 'L') && (base[3] == ' ')) {
 96.3402 +    memmove (base,t,s - t);	/* yes, blat down remaining text */
 96.3403 +    s -= 4;			/* and reduce current pointer */
 96.3404 +  }
 96.3405 +  return s;			/* return new end pointer */
 96.3406 +}
 96.3407 +
 96.3408 +/* IMAP send search set
 96.3409 + * Accepts: MAIL stream
 96.3410 + *	    current command tag
 96.3411 + *	    base pointer if trimming needed
 96.3412 + *	    pointer to current position pointer of output bigbuf
 96.3413 + *	    search set to output
 96.3414 + *	    message prefix
 96.3415 + *	    maximum output pointer
 96.3416 + * Returns: NIL if success, error reply if error
 96.3417 + */
 96.3418 +
 96.3419 +IMAPPARSEDREPLY *imap_send_sset (MAILSTREAM *stream,char *tag,char *base,
 96.3420 +				 char **s,SEARCHSET *set,char *prefix,
 96.3421 +				 char *limit)
 96.3422 +{
 96.3423 +  IMAPPARSEDREPLY *reply;
 96.3424 +  STRING st;
 96.3425 +  char c,*t;
 96.3426 +  char *start = *s;
 96.3427 +				/* trim and write prefix */
 96.3428 +  *s = imap_send_spgm_trim (base,*s,prefix);
 96.3429 +				/* run down search list */
 96.3430 +  for (c = NIL; set && (*s < limit); set = set->next, c = ',') {
 96.3431 +    if (c) *(*s)++ = c;		/* write delimiter and first value */
 96.3432 +    if (set->first == 0xffffffff) *(*s)++ = '*';
 96.3433 +    else {
 96.3434 +      sprintf (*s,"%lu",set->first);
 96.3435 +      *s += strlen (*s);
 96.3436 +    }
 96.3437 +				/* have a second value? */
 96.3438 +    if (set->last && (set->first != set->last)) {
 96.3439 +      *(*s)++ = ':';		/* write delimiter and second value */
 96.3440 +      if (set->last == 0xffffffff) *(*s)++ = '*';
 96.3441 +      else {
 96.3442 +	sprintf (*s,"%lu",set->last);
 96.3443 +	*s += strlen (*s);
 96.3444 +      }
 96.3445 +    }
 96.3446 +  }
 96.3447 +  if (set) {			/* insert "OR" in front of incomplete set */
 96.3448 +    memmove (start + 3,start,*s - start);
 96.3449 +    memcpy (start," OR",3);
 96.3450 +    *s += 3;			/* point to end of buffer */
 96.3451 +				/* write glue that is equivalent to ALL */
 96.3452 +    for (t =" ((OR BCC FOO NOT BCC "; *t; *(*s)++ = *t++);
 96.3453 +				/* but broken by a literal */
 96.3454 +    INIT (&st,mail_string,(void *) "FOO",3);
 96.3455 +    if (reply = imap_send_literal (stream,tag,s,&st)) return reply;
 96.3456 +    *(*s)++ = ')';		/* close glue */
 96.3457 +    if (reply = imap_send_sset (stream,tag,NIL,s,set,prefix,limit))
 96.3458 +      return reply;
 96.3459 +    *(*s)++ = ')';		/* close second OR argument */
 96.3460 +  }
 96.3461 +  return NIL;
 96.3462 +}
 96.3463 +
 96.3464 +/* IMAP send search list
 96.3465 + * Accepts: MAIL stream
 96.3466 + *	    reply tag
 96.3467 + *	    base pointer if trimming needed
 96.3468 + *	    pointer to current position pointer of output bigbuf
 96.3469 + *	    name of search list
 96.3470 + *	    search list to output
 96.3471 + *	    maximum output pointer
 96.3472 + * Returns: NIL if success, error reply if error
 96.3473 + */
 96.3474 +
 96.3475 +IMAPPARSEDREPLY *imap_send_slist (MAILSTREAM *stream,char *tag,char *base,
 96.3476 +				  char **s,char *name,STRINGLIST *list,
 96.3477 +				  char *limit)
 96.3478 +{
 96.3479 +  IMAPPARSEDREPLY *reply;
 96.3480 +  do {
 96.3481 +    *s = imap_send_spgm_trim (base,*s,name);
 96.3482 +    base = NIL;			/* no longer need trimming */
 96.3483 +    reply = imap_send_astring (stream,tag,s,&list->text,NIL,limit);
 96.3484 +  }
 96.3485 +  while (!reply && (list = list->next));
 96.3486 +  return reply;
 96.3487 +}
 96.3488 +
 96.3489 +
 96.3490 +/* IMAP send search date
 96.3491 + * Accepts: pointer to current position pointer of output bigbuf
 96.3492 + *	    field name
 96.3493 + *	    search date to output
 96.3494 + */
 96.3495 +
 96.3496 +void imap_send_sdate (char **s,char *name,unsigned short date)
 96.3497 +{
 96.3498 +  sprintf (*s," %s %d-%s-%d",name,date & 0x1f,
 96.3499 +	   months[((date >> 5) & 0xf) - 1],BASEYEAR + (date >> 9));
 96.3500 +  *s += strlen (*s);
 96.3501 +}
 96.3502 +
 96.3503 +/* IMAP send buffered command to sender
 96.3504 + * Accepts: MAIL stream
 96.3505 + *	    reply tag
 96.3506 + *	    string
 96.3507 + *	    pointer to string tail pointer
 96.3508 + * Returns: reply
 96.3509 + */
 96.3510 +
 96.3511 +IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s)
 96.3512 +{
 96.3513 +  IMAPPARSEDREPLY *reply;
 96.3514 +  if (stream->debug) {		/* output debugging telemetry */
 96.3515 +    **s = '\0';
 96.3516 +    mail_dlog (base,LOCAL->sensitive);
 96.3517 +  }
 96.3518 +  *(*s)++ = '\015';		/* append CRLF */
 96.3519 +  *(*s)++ = '\012';
 96.3520 +  **s = '\0';
 96.3521 +  reply = net_sout (LOCAL->netstream,base,*s - base) ?
 96.3522 +    imap_reply (stream,tag) :
 96.3523 +      imap_fake (stream,tag,"[CLOSED] IMAP connection broken (command)");
 96.3524 +  *s = base;			/* restart buffer */
 96.3525 +  return reply;
 96.3526 +}
 96.3527 +
 96.3528 +
 96.3529 +/* IMAP send null-terminated string to sender
 96.3530 + * Accepts: MAIL stream
 96.3531 + *	    string
 96.3532 + * Returns: T if success, else NIL
 96.3533 + */
 96.3534 +
 96.3535 +long imap_soutr (MAILSTREAM *stream,char *string)
 96.3536 +{
 96.3537 +  long ret;
 96.3538 +  unsigned long i;
 96.3539 +  char *s;
 96.3540 +  if (stream->debug) mm_dlog (string);
 96.3541 +  sprintf (s = (char *) fs_get ((i = strlen (string) + 2) + 1),
 96.3542 +	   "%s\015\012",string);
 96.3543 +  ret = net_sout (LOCAL->netstream,s,i);
 96.3544 +  fs_give ((void **) &s);
 96.3545 +  return ret;
 96.3546 +}
 96.3547 +
 96.3548 +/* IMAP get reply
 96.3549 + * Accepts: MAIL stream
 96.3550 + *	    tag to search or NIL if want a greeting
 96.3551 + * Returns: parsed reply, never NIL
 96.3552 + */
 96.3553 +
 96.3554 +IMAPPARSEDREPLY *imap_reply (MAILSTREAM *stream,char *tag)
 96.3555 +{
 96.3556 +  IMAPPARSEDREPLY *reply;
 96.3557 +  while (LOCAL->netstream) {	/* parse reply from server */
 96.3558 +    if (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) {
 96.3559 +				/* continuation ready? */
 96.3560 +      if (!strcmp (reply->tag,"+")) return reply;
 96.3561 +				/* untagged data? */
 96.3562 +      else if (!strcmp (reply->tag,"*")) {
 96.3563 +	imap_parse_unsolicited (stream,reply);
 96.3564 +	if (!tag) return reply;	/* return if just wanted greeting */
 96.3565 +      }
 96.3566 +      else {			/* tagged data */
 96.3567 +	if (tag && !compare_cstring (tag,reply->tag)) return reply;
 96.3568 +				/* report bogon */
 96.3569 +	sprintf (LOCAL->tmp,"Unexpected tagged response: %.80s %.80s %.80s",
 96.3570 +		 (char *) reply->tag,(char *) reply->key,(char *) reply->text);
 96.3571 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.3572 +	stream->unhealthy = T;
 96.3573 +      }
 96.3574 +    }
 96.3575 +  }
 96.3576 +  return imap_fake (stream,tag,
 96.3577 +		    "[CLOSED] IMAP connection broken (server response)");
 96.3578 +}
 96.3579 +
 96.3580 +/* IMAP parse reply
 96.3581 + * Accepts: MAIL stream
 96.3582 + *	    text of reply
 96.3583 + * Returns: parsed reply, or NIL if can't parse at least a tag and key
 96.3584 + */
 96.3585 +
 96.3586 +
 96.3587 +IMAPPARSEDREPLY *imap_parse_reply (MAILSTREAM *stream,char *text)
 96.3588 +{
 96.3589 +  char *r;
 96.3590 +  if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
 96.3591 +				/* init fields in case error */
 96.3592 +  LOCAL->reply.key = LOCAL->reply.text = LOCAL->reply.tag = NIL;
 96.3593 +  if (!(LOCAL->reply.line = text)) {
 96.3594 +				/* NIL text means the stream died */
 96.3595 +    if (LOCAL->netstream) net_close (LOCAL->netstream);
 96.3596 +    LOCAL->netstream = NIL;
 96.3597 +    return NIL;
 96.3598 +  }
 96.3599 +  if (stream->debug) mm_dlog (LOCAL->reply.line);
 96.3600 +  if (!(LOCAL->reply.tag = strtok_r (LOCAL->reply.line," ",&r))) {
 96.3601 +    mm_notify (stream,"IMAP server sent a blank line",WARN);
 96.3602 +    stream->unhealthy = T;
 96.3603 +    return NIL;
 96.3604 +  }
 96.3605 +				/* non-continuation replies */
 96.3606 +  if (strcmp (LOCAL->reply.tag,"+")) {
 96.3607 +				/* parse key */
 96.3608 +    if (!(LOCAL->reply.key = strtok_r (NIL," ",&r))) {
 96.3609 +				/* determine what is missing */
 96.3610 +      sprintf (LOCAL->tmp,"Missing IMAP reply key: %.80s",
 96.3611 +	       (char *) LOCAL->reply.tag);
 96.3612 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.3613 +      stream->unhealthy = T;
 96.3614 +      return NIL;		/* can't parse this text */
 96.3615 +    }
 96.3616 +    ucase (LOCAL->reply.key);	/* canonicalize key to upper */
 96.3617 +				/* get text as well, allow empty text */
 96.3618 +    if (!(LOCAL->reply.text = strtok_r (NIL,"\n",&r)))
 96.3619 +      LOCAL->reply.text = LOCAL->reply.key + strlen (LOCAL->reply.key);
 96.3620 +  }
 96.3621 +  else {			/* special handling of continuation */
 96.3622 +    LOCAL->reply.key = "BAD";	/* so it barfs if not expecting continuation */
 96.3623 +    if (!(LOCAL->reply.text = strtok_r (NIL,"\n",&r)))
 96.3624 +      LOCAL->reply.text = "";
 96.3625 +  }
 96.3626 +  return &LOCAL->reply;		/* return parsed reply */
 96.3627 +}
 96.3628 +
 96.3629 +/* IMAP fake reply when stream determined to be dead
 96.3630 + * Accepts: MAIL stream
 96.3631 + *	    tag
 96.3632 + *	    text of fake reply (must start with "[CLOSED]")
 96.3633 + * Returns: parsed reply
 96.3634 + */
 96.3635 +
 96.3636 +IMAPPARSEDREPLY *imap_fake (MAILSTREAM *stream,char *tag,char *text)
 96.3637 +{
 96.3638 +  mm_notify (stream,text,BYE);	/* send bye alert */
 96.3639 +  if (LOCAL->netstream) net_close (LOCAL->netstream);
 96.3640 +  LOCAL->netstream = NIL;	/* farewell, dear NET stream... */
 96.3641 +				/* flush previous reply */
 96.3642 +  if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
 96.3643 +				/* build new fake reply */
 96.3644 +  LOCAL->reply.tag = LOCAL->reply.line = cpystr (tag ? tag : "*");
 96.3645 +  LOCAL->reply.key = "NO";
 96.3646 +  LOCAL->reply.text = text;
 96.3647 +  return &LOCAL->reply;		/* return parsed reply */
 96.3648 +}
 96.3649 +
 96.3650 +
 96.3651 +/* IMAP check for OK response in tagged reply
 96.3652 + * Accepts: MAIL stream
 96.3653 + *	    parsed reply
 96.3654 + * Returns: T if OK else NIL
 96.3655 + */
 96.3656 +
 96.3657 +long imap_OK (MAILSTREAM *stream,IMAPPARSEDREPLY *reply)
 96.3658 +{
 96.3659 +  long ret = NIL;
 96.3660 +				/* OK - operation succeeded */
 96.3661 +  if (!strcmp (reply->key,"OK")) {
 96.3662 +    imap_parse_response (stream,reply->text,NIL,NIL);
 96.3663 +    ret = T;
 96.3664 +  }
 96.3665 +				/* NO - operation failed */
 96.3666 +  else if (!strcmp (reply->key,"NO"))
 96.3667 +    imap_parse_response (stream,reply->text,WARN,NIL);
 96.3668 +  else {			/* BAD - operation rejected */
 96.3669 +    if (!strcmp (reply->key,"BAD")) {
 96.3670 +      imap_parse_response (stream,reply->text,ERROR,NIL);
 96.3671 +      sprintf (LOCAL->tmp,"IMAP protocol error: %.80s",(char *) reply->text);
 96.3672 +    }
 96.3673 +				/* bad protocol received */
 96.3674 +    else sprintf (LOCAL->tmp,"Unexpected IMAP response: %.80s %.80s",
 96.3675 +		  (char *) reply->key,(char *) reply->text);
 96.3676 +    mm_log (LOCAL->tmp,ERROR);	/* either way, this is not good */
 96.3677 +  }
 96.3678 +  return ret;
 96.3679 +}
 96.3680 +
 96.3681 +/* IMAP parse and act upon unsolicited reply
 96.3682 + * Accepts: MAIL stream
 96.3683 + *	    parsed reply
 96.3684 + */
 96.3685 +
 96.3686 +void imap_parse_unsolicited (MAILSTREAM *stream,IMAPPARSEDREPLY *reply)
 96.3687 +{
 96.3688 +  unsigned long i = 0;
 96.3689 +  unsigned long j,msgno;
 96.3690 +  unsigned char *s,*t;
 96.3691 +  char *r;
 96.3692 +				/* see if key is a number */
 96.3693 +  if (isdigit (*reply->key)) {
 96.3694 +    msgno = strtoul (reply->key,(char **) &s,10);
 96.3695 +    if (*s) {			/* better be nothing after number */
 96.3696 +      sprintf (LOCAL->tmp,"Unexpected untagged message: %.80s",
 96.3697 +	       (char *) reply->key);
 96.3698 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.3699 +      stream->unhealthy = T;
 96.3700 +      return;
 96.3701 +    }
 96.3702 +    if (!reply->text) {		/* better be some data */
 96.3703 +      mm_notify (stream,"Missing message data",WARN);
 96.3704 +      stream->unhealthy = T;
 96.3705 +      return;
 96.3706 +    }
 96.3707 +				/* get message data type, canonicalize upper */
 96.3708 +    s = ucase (strtok_r (reply->text," ",&r));
 96.3709 +				/* and locate the text after it */
 96.3710 +    t = strtok_r (NIL,"\n",&r);
 96.3711 +				/* now take the action */
 96.3712 +				/* change in size of mailbox */
 96.3713 +    if (!strcmp (s,"EXISTS") && (msgno >= stream->nmsgs))
 96.3714 +      mail_exists (stream,msgno);
 96.3715 +    else if (!strcmp (s,"RECENT") && (msgno <= stream->nmsgs))
 96.3716 +      mail_recent (stream,msgno);
 96.3717 +    else if (!strcmp (s,"EXPUNGE") && msgno && (msgno <= stream->nmsgs)) {
 96.3718 +      mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
 96.3719 +      MESSAGECACHE *elt = (MESSAGECACHE *) (*mc) (stream,msgno,CH_ELT);
 96.3720 +      if (elt) imap_gc_body (elt->private.msg.body);
 96.3721 +				/* notify upper level */
 96.3722 +      mail_expunged (stream,msgno);
 96.3723 +    }
 96.3724 +
 96.3725 +    else if ((!strcmp (s,"FETCH") || !strcmp (s,"STORE")) &&
 96.3726 +	     msgno && (msgno <= stream->nmsgs)) {
 96.3727 +      char *prop;
 96.3728 +      GETS_DATA md;
 96.3729 +      ENVELOPE **e;
 96.3730 +      MESSAGECACHE *elt = mail_elt (stream,msgno);
 96.3731 +      ENVELOPE *env = NIL;
 96.3732 +      imapenvelope_t ie =
 96.3733 +	(imapenvelope_t) mail_parameters (stream,GET_IMAPENVELOPE,NIL);
 96.3734 +      ++t;			/* skip past open parenthesis */
 96.3735 +				/* parse Lisp-form property list */
 96.3736 +      while (prop = (strtok_r (t," )",&r))) {
 96.3737 +	t = strtok_r (NIL,"\n",&r);
 96.3738 +	INIT_GETS (md,stream,elt->msgno,NIL,0,0);
 96.3739 +	e = NIL;		/* not pointing at any envelope yet */
 96.3740 +				/* canonicalize property, parse it */
 96.3741 +	if (!strcmp (ucase (prop),"FLAGS")) imap_parse_flags (stream,elt,&t);
 96.3742 +	else if (!strcmp (prop,"INTERNALDATE") &&
 96.3743 +		 (s = imap_parse_string (stream,&t,reply,NIL,NIL,LONGT))) {
 96.3744 +	  if (!mail_parse_date (elt,s)) {
 96.3745 +	    sprintf (LOCAL->tmp,"Bogus date: %.80s",(char *) s);
 96.3746 +	    mm_notify (stream,LOCAL->tmp,WARN);
 96.3747 +	    stream->unhealthy = T;
 96.3748 +				/* slam in default so we don't try again */
 96.3749 +	    mail_parse_date (elt,"01-Jan-1970 00:00:00 +0000");
 96.3750 +	  }
 96.3751 +	  fs_give ((void **) &s);
 96.3752 +	}
 96.3753 +				/* unique identifier */
 96.3754 +	else if (!strcmp (prop,"UID")) {
 96.3755 +	  LOCAL->lastuid.uid = elt->private.uid = strtoul (t,(char **) &t,10);
 96.3756 +	  LOCAL->lastuid.msgno = elt->msgno;
 96.3757 +	}
 96.3758 +	else if (!strcmp (prop,"ENVELOPE")) {
 96.3759 +	  if (stream->scache) {	/* short cache, flush old stuff */
 96.3760 +	    mail_free_body (&stream->body);
 96.3761 +	    stream->msgno = elt->msgno;
 96.3762 +	    e = &stream->env;	/* get pointer to envelope */
 96.3763 +	  }
 96.3764 +	  else e = &elt->private.msg.env;
 96.3765 +	  imap_parse_envelope (stream,e,&t,reply);
 96.3766 +	}
 96.3767 +	else if (!strncmp (prop,"BODY",4)) {
 96.3768 +	  if (!prop[4] || !strcmp (prop+4,"STRUCTURE")) {
 96.3769 +	    BODY **body;
 96.3770 +	    if (stream->scache){/* short cache, flush old stuff */
 96.3771 +	      if (stream->msgno != msgno) {
 96.3772 +		mail_free_envelope (&stream->env);
 96.3773 +		sprintf (LOCAL->tmp,"Body received for %lu but current is %lu",
 96.3774 +			 msgno,stream->msgno);
 96.3775 +		stream->msgno = msgno;
 96.3776 +	      }
 96.3777 +				/* get pointer to body */
 96.3778 +	      body = &stream->body;
 96.3779 +	    }
 96.3780 +	    else body = &elt->private.msg.body;
 96.3781 +				/* flush any prior body */
 96.3782 +	    mail_free_body (body);
 96.3783 +				/* instantiate and parse a new body */
 96.3784 +	    imap_parse_body_structure (stream,*body = mail_newbody(),&t,reply);
 96.3785 +	  }
 96.3786 +
 96.3787 +	  else if (prop[4] == '[') {
 96.3788 +	    STRINGLIST *stl = NIL;
 96.3789 +	    SIZEDTEXT text;
 96.3790 +				/* will want to return envelope data */
 96.3791 +	    if (!strcmp (md.what = cpystr (prop + 5),"HEADER]") ||
 96.3792 +		!strcmp (md.what,"0]"))
 96.3793 +	      e = stream->scache ? &stream->env : &elt->private.msg.env;
 96.3794 +	    LOCAL->tmp[0] ='\0';/* no errors yet */
 96.3795 +				/* found end of section? */
 96.3796 +	    if (!(s = strchr (md.what,']'))) {
 96.3797 +				/* skip leading nesting */
 96.3798 +	      for (s = md.what; *s && (isdigit (*s) || (*s == '.')); s++);
 96.3799 +				/* better be one of these */
 96.3800 +	      if (strncmp (s,"HEADER.FIELDS",13) &&
 96.3801 +		  (!s[13] || strcmp (s+13,".NOT")))
 96.3802 +		sprintf (LOCAL->tmp,"Unterminated section: %.80s",md.what);
 96.3803 +				/* get list of headers */
 96.3804 +	      else if (!(stl = imap_parse_stringlist (stream,&t,reply)))
 96.3805 +		sprintf (LOCAL->tmp,"Bogus header field list: %.80s",
 96.3806 +			 (char *) t);
 96.3807 +	      else if (*t != ']')
 96.3808 +		sprintf (LOCAL->tmp,"Unterminated header section: %.80s",
 96.3809 +			 (char *) t);
 96.3810 +				/* point after the text */
 96.3811 +	      else if (t = strchr (s = t,' ')) *t++ = '\0';
 96.3812 +	    }
 96.3813 +	    if (s && !LOCAL->tmp[0]) {
 96.3814 +	      *s++ = '\0';	/* tie off section specifier */
 96.3815 +	      if (*s == '<') {	/* partial specifier? */
 96.3816 +		md.first = strtoul (s+1,(char **) &s,10) + 1;
 96.3817 +		if (*s++ != '>')	/* make sure properly terminated */
 96.3818 +		  sprintf (LOCAL->tmp,"Unterminated partial data: %.80s",
 96.3819 +			   (char *) s-1);
 96.3820 +	      }
 96.3821 +	      if (!LOCAL->tmp[0] && *s)
 96.3822 +		sprintf (LOCAL->tmp,"Junk after section: %.80s",(char *) s);
 96.3823 +	    }
 96.3824 +	    if (LOCAL->tmp[0]) { /* got any errors? */
 96.3825 +	      mm_notify (stream,LOCAL->tmp,WARN);
 96.3826 +	      stream->unhealthy = T;
 96.3827 +	      mail_free_stringlist (&stl);
 96.3828 +	    }
 96.3829 +	    else {		/* parse text from server */
 96.3830 +	      text.data = (unsigned char *)
 96.3831 +		imap_parse_string (stream,&t,reply,
 96.3832 +				   ((md.what[0] && (md.what[0] != 'H')) ||
 96.3833 +				    md.first || md.last) ? &md : NIL,
 96.3834 +				   &text.size,NIL);
 96.3835 +				/* all done if partial */
 96.3836 +	      if (md.first || md.last) mail_free_stringlist (&stl);
 96.3837 +				/* otherwise register it in the cache */
 96.3838 +	      else imap_cache (stream,msgno,md.what,stl,&text);
 96.3839 +	    }
 96.3840 +	    fs_give ((void **) &md.what);
 96.3841 +	  }
 96.3842 +	  else {
 96.3843 +	    sprintf (LOCAL->tmp,"Unknown body message property: %.80s",prop);
 96.3844 +	    mm_notify (stream,LOCAL->tmp,WARN);
 96.3845 +	    stream->unhealthy = T;
 96.3846 +	  }
 96.3847 +	}
 96.3848 +
 96.3849 +				/* one of the RFC822 props? */
 96.3850 +	else if (!strncmp (prop,"RFC822",6) && (!prop[6] || (prop[6] == '.'))){
 96.3851 +	  SIZEDTEXT text;
 96.3852 +	  if (!prop[6]) {	/* cache full message */
 96.3853 +	    md.what = "";
 96.3854 +	    text.data = (unsigned char *)
 96.3855 +	      imap_parse_string (stream,&t,reply,&md,&text.size,NIL);
 96.3856 +	    imap_cache (stream,msgno,md.what,NIL,&text);
 96.3857 +	  }
 96.3858 +	  else if (!strcmp (prop+7,"SIZE"))
 96.3859 +	    elt->rfc822_size = strtoul (t,(char **) &t,10);
 96.3860 +				/* legacy properties */
 96.3861 +	  else if (!strcmp (prop+7,"HEADER")) {
 96.3862 +	    text.data = (unsigned char *)
 96.3863 +	      imap_parse_string (stream,&t,reply,NIL,&text.size,NIL);
 96.3864 +	    imap_cache (stream,msgno,"HEADER",NIL,&text);
 96.3865 +	    e = stream->scache ? &stream->env : &elt->private.msg.env;
 96.3866 +	  }
 96.3867 +	  else if (!strcmp (prop+7,"TEXT")) {
 96.3868 +	    md.what = "TEXT";
 96.3869 +	    text.data = (unsigned char *)
 96.3870 +	      imap_parse_string (stream,&t,reply,&md,&text.size,NIL);
 96.3871 +	    imap_cache (stream,msgno,md.what,NIL,&text);
 96.3872 +	  }
 96.3873 +	  else {
 96.3874 +	    sprintf (LOCAL->tmp,"Unknown RFC822 message property: %.80s",prop);
 96.3875 +	    mm_notify (stream,LOCAL->tmp,WARN);
 96.3876 +	    stream->unhealthy = T;
 96.3877 +	  }
 96.3878 +	}
 96.3879 +	else {
 96.3880 +	  sprintf (LOCAL->tmp,"Unknown message property: %.80s",prop);
 96.3881 +	  mm_notify (stream,LOCAL->tmp,WARN);
 96.3882 +	  stream->unhealthy = T;
 96.3883 +	}
 96.3884 +	if (e && *e) env = *e;	/* note envelope if we got one */
 96.3885 +      }
 96.3886 +				/* do callback if requested */
 96.3887 +      if (ie && env) (*ie) (stream,msgno,env);
 96.3888 +    }
 96.3889 +				/* obsolete response to COPY */
 96.3890 +    else if (strcmp (s,"COPY")) {
 96.3891 +      sprintf (LOCAL->tmp,"Unknown message data: %lu %.80s",msgno,(char *) s);
 96.3892 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.3893 +      stream->unhealthy = T;
 96.3894 +    }
 96.3895 +  }
 96.3896 +
 96.3897 +  else if (!strcmp (reply->key,"FLAGS") && reply->text &&
 96.3898 +	   (*reply->text == '(') &&
 96.3899 +	   (s = strtok_r (reply->text+1," )",&r)))
 96.3900 +    do if (*s != '\\') {
 96.3901 +      for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i] &&
 96.3902 +	     compare_cstring (s,stream->user_flags[i]); i++);
 96.3903 +      if (i > NUSERFLAGS) {
 96.3904 +	sprintf (LOCAL->tmp,"Too many server flags, discarding: %.80s",
 96.3905 +		 (char *) s);
 96.3906 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.3907 +      }
 96.3908 +      else if (!stream->user_flags[i]) stream->user_flags[i++] = cpystr (s);
 96.3909 +    }
 96.3910 +    while (s = strtok_r (NIL," )",&r));
 96.3911 +  else if (!strcmp (reply->key,"SEARCH")) {
 96.3912 +				/* only do something if have text */
 96.3913 +    if (reply->text && (t = strtok_r (reply->text," ",&r))) do
 96.3914 +      if (i = strtoul (t,NIL,10)) {
 96.3915 +				/* UIDs always passed to main program */
 96.3916 +	if (LOCAL->uidsearch) mm_searched (stream,i);
 96.3917 +				/* should be a msgno then */
 96.3918 +	else if ((i <= stream->nmsgs) &&
 96.3919 +		 (!LOCAL->filter || mail_elt (stream,i)->private.filter)) {
 96.3920 +	  mail_elt (stream,i)->searched = T;
 96.3921 +	  if (!stream->silent) mm_searched (stream,i);
 96.3922 +	}
 96.3923 +      } while (t = strtok_r (NIL," ",&r));
 96.3924 +  }
 96.3925 +  else if (!strcmp (reply->key,"SORT")) {
 96.3926 +    sortresults_t sr = (sortresults_t)
 96.3927 +      mail_parameters (NIL,GET_SORTRESULTS,NIL);
 96.3928 +    LOCAL->sortsize = 0;	/* initialize sort data */
 96.3929 +    if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata);
 96.3930 +    LOCAL->sortdata = (unsigned long *)
 96.3931 +      fs_get ((stream->nmsgs + 1) * sizeof (unsigned long));
 96.3932 +				/* only do something if have text */
 96.3933 +    if (reply->text && (t = strtok_r (reply->text," ",&r))) {
 96.3934 +      do if ((i = atol (t)) && (LOCAL->filter ?
 96.3935 +				mail_elt (stream,i)->searched : T))
 96.3936 +	LOCAL->sortdata[LOCAL->sortsize++] = i;
 96.3937 +      while ((t = strtok_r (NIL," ",&r)) && (LOCAL->sortsize < stream->nmsgs));
 96.3938 +    }
 96.3939 +    LOCAL->sortdata[LOCAL->sortsize] = 0;
 96.3940 +				/* also return via callback if requested */
 96.3941 +    if (sr) (*sr) (stream,LOCAL->sortdata,LOCAL->sortsize);
 96.3942 +  }
 96.3943 +  else if (!strcmp (reply->key,"THREAD")) {
 96.3944 +    threadresults_t tr = (threadresults_t)
 96.3945 +      mail_parameters (NIL,GET_THREADRESULTS,NIL);
 96.3946 +    if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata);
 96.3947 +    if (s = reply->text) {
 96.3948 +      LOCAL->threaddata = imap_parse_thread (stream,&s);
 96.3949 +      if (tr) (*tr) (stream,LOCAL->threaddata);
 96.3950 +      if (s && *s) {
 96.3951 +	sprintf (LOCAL->tmp,"Junk at end of thread: %.80s",(char *) s);
 96.3952 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.3953 +	stream->unhealthy = T;
 96.3954 +      }
 96.3955 +    }
 96.3956 +  }
 96.3957 +
 96.3958 +  else if (!strcmp (reply->key,"STATUS") && reply->text) {
 96.3959 +    MAILSTATUS status;
 96.3960 +    unsigned char *txt = reply->text;
 96.3961 +    if ((t = imap_parse_astring (stream,&txt,reply,&j)) && txt &&
 96.3962 +	(*txt++ == ' ') && (*txt++ == '(') && (s = strchr (txt,')')) &&
 96.3963 +	(s - txt) && !s[1]) {
 96.3964 +      *s = '\0';		/* tie off status data */
 96.3965 +				/* initialize data block */
 96.3966 +      status.flags = status.messages = status.recent = status.unseen =
 96.3967 +	status.uidnext = status.uidvalidity = 0;
 96.3968 +      while (*txt && (s = strchr (txt,' '))) {
 96.3969 +	*s++ = '\0';		/* tie off status attribute name */
 96.3970 +				/* get attribute value */
 96.3971 +	i = strtoul (s,(char **) &s,10);
 96.3972 +	if (!compare_cstring (txt,"MESSAGES")) {
 96.3973 +	  status.flags |= SA_MESSAGES;
 96.3974 +	  status.messages = i;
 96.3975 +	}
 96.3976 +	else if (!compare_cstring (txt,"RECENT")) {
 96.3977 +	  status.flags |= SA_RECENT;
 96.3978 +	  status.recent = i;
 96.3979 +	}
 96.3980 +	else if (!compare_cstring (txt,"UNSEEN")) {
 96.3981 +	  status.flags |= SA_UNSEEN;
 96.3982 +	  status.unseen = i;
 96.3983 +	}
 96.3984 +	else if (!compare_cstring (txt,"UIDNEXT")) {
 96.3985 +	  status.flags |= SA_UIDNEXT;
 96.3986 +	  status.uidnext = i;
 96.3987 +	}
 96.3988 +	else if (!compare_cstring (txt,"UIDVALIDITY")) {
 96.3989 +	  status.flags |= SA_UIDVALIDITY;
 96.3990 +	  status.uidvalidity = i;
 96.3991 +	}
 96.3992 +				/* next attribute */
 96.3993 +	txt = (*s == ' ') ? s + 1 : s;
 96.3994 +      }
 96.3995 +      if (((i = 1 + strchr (stream->mailbox,'}') - stream->mailbox) + j) <
 96.3996 +	  IMAPTMPLEN) {
 96.3997 +	strcpy (strncpy (LOCAL->tmp,stream->mailbox,i) + i,t);
 96.3998 +				/* pass status to main program */
 96.3999 +	mm_status (stream,LOCAL->tmp,&status);
 96.4000 +      }
 96.4001 +    }
 96.4002 +    if (t) fs_give ((void **) &t);
 96.4003 +  }
 96.4004 +
 96.4005 +  else if ((!strcmp (reply->key,"LIST") || !strcmp (reply->key,"LSUB")) &&
 96.4006 +	   reply->text && (*reply->text == '(') &&
 96.4007 +	   (s = strchr (reply->text,')')) && (s[1] == ' ')) {
 96.4008 +    char delimiter = '\0';
 96.4009 +    *s++ = '\0';		/* tie off attribute list */
 96.4010 +				/* parse attribute list */
 96.4011 +    if (t = strtok_r (reply->text+1," ",&r)) do {
 96.4012 +      if (!compare_cstring (t,"\\NoInferiors")) i |= LATT_NOINFERIORS;
 96.4013 +      else if (!compare_cstring (t,"\\NoSelect")) i |= LATT_NOSELECT;
 96.4014 +      else if (!compare_cstring (t,"\\Marked")) i |= LATT_MARKED;
 96.4015 +      else if (!compare_cstring (t,"\\Unmarked")) i |= LATT_UNMARKED;
 96.4016 +      else if (!compare_cstring (t,"\\HasChildren")) i |= LATT_HASCHILDREN;
 96.4017 +      else if (!compare_cstring (t,"\\HasNoChildren")) i |= LATT_HASNOCHILDREN;
 96.4018 +				/* ignore extension flags */
 96.4019 +    }
 96.4020 +    while (t = strtok_r (NIL," ",&r));
 96.4021 +    switch (*++s) {		/* process delimiter */
 96.4022 +    case 'N':			/* NIL */
 96.4023 +    case 'n':
 96.4024 +      s += 4;			/* skip over NIL<space> */
 96.4025 +      break;
 96.4026 +    case '"':			/* have a delimiter */
 96.4027 +      delimiter = (*++s == '\\') ? *++s : *s;
 96.4028 +      s += 3;			/* skip over <delimiter><quote><space> */
 96.4029 +    }
 96.4030 +				/* parse the mailbox name */
 96.4031 +    if (t = imap_parse_astring (stream,&s,reply,&j)) {
 96.4032 +				/* prepend prefix if requested */
 96.4033 +      if (LOCAL->prefix && ((strlen (LOCAL->prefix) + j) < IMAPTMPLEN))
 96.4034 +	sprintf (s = LOCAL->tmp,"%s%s",LOCAL->prefix,(char *) t);
 96.4035 +      else s = t;		/* otherwise just mailbox name */
 96.4036 +				/* pass data to main program */
 96.4037 +      if (reply->key[1] == 'S') mm_lsub (stream,delimiter,s,i);
 96.4038 +      else mm_list (stream,delimiter,s,i);
 96.4039 +      fs_give ((void **) &t);	/* flush mailbox name */
 96.4040 +    }
 96.4041 +  }
 96.4042 +  else if (!strcmp (reply->key,"NAMESPACE")) {
 96.4043 +    if (LOCAL->namespace) {
 96.4044 +      mail_free_namespace (&LOCAL->namespace[0]);
 96.4045 +      mail_free_namespace (&LOCAL->namespace[1]);
 96.4046 +      mail_free_namespace (&LOCAL->namespace[2]);
 96.4047 +    }
 96.4048 +    else LOCAL->namespace = (NAMESPACE **) fs_get (3 * sizeof (NAMESPACE *));
 96.4049 +    if (s = reply->text) {	/* parse namespace results */
 96.4050 +      LOCAL->namespace[0] = imap_parse_namespace (stream,&s,reply);
 96.4051 +      LOCAL->namespace[1] = imap_parse_namespace (stream,&s,reply);
 96.4052 +      LOCAL->namespace[2] = imap_parse_namespace (stream,&s,reply);
 96.4053 +      if (s && *s) {
 96.4054 +	sprintf (LOCAL->tmp,"Junk after namespace list: %.80s",(char *) s);
 96.4055 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4056 +	stream->unhealthy = T;
 96.4057 +      }
 96.4058 +    }
 96.4059 +    else {
 96.4060 +      mm_notify (stream,"Missing namespace list",WARN);
 96.4061 +      stream->unhealthy = T;
 96.4062 +    }
 96.4063 +  }
 96.4064 +
 96.4065 +  else if (!strcmp (reply->key,"ACL") && (s = reply->text) &&
 96.4066 +	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4067 +    getacl_t ar = (getacl_t) mail_parameters (NIL,GET_ACL,NIL);
 96.4068 +    if (s && (*s++ == ' ')) {
 96.4069 +      ACLLIST *al = mail_newacllist ();
 96.4070 +      ACLLIST *ac = al;
 96.4071 +      do if ((ac->identifier = imap_parse_astring (stream,&s,reply,NIL)) &&
 96.4072 +	     s && (*s++ == ' '))
 96.4073 +	ac->rights = imap_parse_astring (stream,&s,reply,NIL);
 96.4074 +      while (ac->rights && s && (*s == ' ') && s++ &&
 96.4075 +	     (ac = ac->next = mail_newacllist ()));
 96.4076 +      if (!ac->rights || (s && *s)) {
 96.4077 +	sprintf (LOCAL->tmp,"Invalid ACL identifer/rights for %.80s",
 96.4078 +		 (char *) t);
 96.4079 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4080 +	stream->unhealthy = T;
 96.4081 +      }
 96.4082 +      else if (ar) (*ar) (stream,t,al);
 96.4083 +      mail_free_acllist (&al);	/* clean up */
 96.4084 +    }
 96.4085 +				/* no optional rights */
 96.4086 +    else if (ar) (*ar) (stream,t,NIL);
 96.4087 +    fs_give ((void **) &t);	/* free mailbox name */
 96.4088 +  }
 96.4089 +
 96.4090 +  else if (!strcmp (reply->key,"LISTRIGHTS") && (s = reply->text) &&
 96.4091 +	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4092 +    listrights_t lr = (listrights_t) mail_parameters (NIL,GET_LISTRIGHTS,NIL);
 96.4093 +    char *id,*r;
 96.4094 +    if (s && (*s++ == ' ') && (id = imap_parse_astring (stream,&s,reply,NIL))){
 96.4095 +      if (s && (*s++ == ' ') &&
 96.4096 +	  (r = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4097 +	if (s && (*s++ == ' ')) {
 96.4098 +	  STRINGLIST *rl = mail_newstringlist ();
 96.4099 +	  STRINGLIST *rc = rl;
 96.4100 +	  do rc->text.data = (unsigned char *)
 96.4101 +	    imap_parse_astring (stream,&s,reply,&rc->text.size);
 96.4102 +	  while (rc->text.data && s && (*s == ' ') && s++ &&
 96.4103 +		 (rc = rc->next = mail_newstringlist ()));
 96.4104 +	  if (!rc->text.data || (s && *s)) {
 96.4105 +	    sprintf (LOCAL->tmp,"Invalid optional LISTRIGHTS for %.80s",
 96.4106 +		     (char *) t);
 96.4107 +	    mm_notify (stream,LOCAL->tmp,WARN);
 96.4108 +	    stream->unhealthy = T;
 96.4109 +	  }
 96.4110 +	  else if (lr) (*lr) (stream,t,id,r,rl);
 96.4111 +				/* clean up */
 96.4112 +	  mail_free_stringlist (&rl);
 96.4113 +	}
 96.4114 +				/* no optional rights */
 96.4115 +	else if (lr) (*lr) (stream,t,id,r,NIL);
 96.4116 +	fs_give ((void **) &r);	/* free rights */
 96.4117 +      }
 96.4118 +      else {
 96.4119 +	sprintf (LOCAL->tmp,"Missing LISTRIGHTS rights for %.80s",(char *) t);
 96.4120 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4121 +	stream->unhealthy = T;
 96.4122 +      }
 96.4123 +      fs_give ((void **) &id);	/* free identifier */
 96.4124 +    }
 96.4125 +    else {
 96.4126 +      sprintf (LOCAL->tmp,"Missing LISTRIGHTS identifer for %.80s",(char *) t);
 96.4127 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4128 +      stream->unhealthy = T;
 96.4129 +    }
 96.4130 +    fs_give ((void **) &t);	/* free mailbox name */
 96.4131 +  }
 96.4132 +
 96.4133 +  else if (!strcmp (reply->key,"MYRIGHTS") && (s = reply->text) &&
 96.4134 +	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4135 +    myrights_t mr = (myrights_t) mail_parameters (NIL,GET_MYRIGHTS,NIL);
 96.4136 +    char *r;
 96.4137 +    if (s && (*s++ == ' ') && (r = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4138 +      if (s && *s) {
 96.4139 +	sprintf (LOCAL->tmp,"Junk after MYRIGHTS for %.80s",(char *) t);
 96.4140 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4141 +	stream->unhealthy = T;
 96.4142 +      }
 96.4143 +      else if (mr) (*mr) (stream,t,r);
 96.4144 +      fs_give ((void **) &r);	/* free rights */
 96.4145 +    }
 96.4146 +    else {
 96.4147 +      sprintf (LOCAL->tmp,"Missing MYRIGHTS for %.80s",(char *) t);
 96.4148 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4149 +      stream->unhealthy = T;
 96.4150 +    }
 96.4151 +    fs_give ((void **) &t);	/* free mailbox name */
 96.4152 +  }
 96.4153 +
 96.4154 +				/* this response has a bizarre syntax! */
 96.4155 +  else if (!strcmp (reply->key,"QUOTA") && (s = reply->text) &&
 96.4156 +	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4157 +				/* in case error */
 96.4158 +    sprintf (LOCAL->tmp,"Bad quota resource list for %.80s",(char *) t);
 96.4159 +    if (s && (*s++ == ' ') && (*s++ == '(') && *s && ((*s != ')') || !s[1])) {
 96.4160 +      quota_t qt = (quota_t) mail_parameters (NIL,GET_QUOTA,NIL);
 96.4161 +      QUOTALIST *ql = NIL;
 96.4162 +      QUOTALIST *qc;
 96.4163 +				/* parse non-empty quota resource list */
 96.4164 +      if (*s != ')') for (ql = qc = mail_newquotalist (); T;
 96.4165 +			  qc = qc->next = mail_newquotalist ()) {
 96.4166 +	if ((qc->name = imap_parse_astring (stream,&s,reply,NIL)) && s &&
 96.4167 +	    (*s++ == ' ') && (isdigit (*s) || (LOCAL->loser && (*s == '-')))) {
 96.4168 +	  if (isdigit (*s)) qc->usage = strtoul (s,(char **) &s,10);
 96.4169 +	  else if (t = strchr (s,' ')) t = s;
 96.4170 +	  if ((*s++ == ' ') && (isdigit (*s) || (LOCAL->loser &&(*s == '-')))){
 96.4171 +	    if (isdigit (*s)) qc->limit = strtoul (s,(char **) &s,10);
 96.4172 +	    else if (t = strpbrk (s," )")) t = s;
 96.4173 +				/* another resource follows? */
 96.4174 +	    if (*s == ' ') continue;
 96.4175 +				/* end of resource list? */
 96.4176 +	    if ((*s == ')') && !s[1]) {
 96.4177 +	      if (qt) (*qt) (stream,t,ql);
 96.4178 +	      break;		/* all done */
 96.4179 +	    }
 96.4180 +	  }
 96.4181 +	}
 96.4182 +				/* something bad happened */
 96.4183 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4184 +	stream->unhealthy = T;
 96.4185 +	break;			/* parse failed */
 96.4186 +      }
 96.4187 +				/* all done with quota resource list now */
 96.4188 +      if (ql) mail_free_quotalist (&ql);
 96.4189 +    }
 96.4190 +    else {
 96.4191 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4192 +      stream->unhealthy = T;
 96.4193 +    }
 96.4194 +    fs_give ((void **) &t);	/* free root name */
 96.4195 +  }
 96.4196 +  else if (!strcmp (reply->key,"QUOTAROOT") && (s = reply->text) &&
 96.4197 +	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
 96.4198 +    sprintf (LOCAL->tmp,"Bad quota root list for %.80s",(char *) t);
 96.4199 +    if (s && (*s++ == ' ')) {
 96.4200 +      quotaroot_t qr = (quotaroot_t) mail_parameters (NIL,GET_QUOTAROOT,NIL);
 96.4201 +      STRINGLIST *rl = mail_newstringlist ();
 96.4202 +      STRINGLIST *rc = rl;
 96.4203 +      do rc->text.data = (unsigned char *)
 96.4204 +	imap_parse_astring (stream,&s,reply,&rc->text.size);
 96.4205 +      while (rc->text.data && *s && (*s++ == ' ') &&
 96.4206 +	       (rc = rc->next = mail_newstringlist ()));
 96.4207 +      if (!rc->text.data || (s && *s)) {
 96.4208 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4209 +	stream->unhealthy = T;
 96.4210 +      }
 96.4211 +      else if (qr) (*qr) (stream,t,rl);
 96.4212 +				/* clean up */
 96.4213 +      mail_free_stringlist (&rl);
 96.4214 +    }
 96.4215 +    else {
 96.4216 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4217 +      stream->unhealthy = T;
 96.4218 +    }
 96.4219 +    fs_give ((void **) &t);
 96.4220 +  }
 96.4221 +
 96.4222 +  else if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH"))
 96.4223 +    imap_parse_response (stream,reply->text,NIL,T);
 96.4224 +  else if (!strcmp (reply->key,"NO"))
 96.4225 +    imap_parse_response (stream,reply->text,WARN,T);
 96.4226 +  else if (!strcmp (reply->key,"BAD"))
 96.4227 +    imap_parse_response (stream,reply->text,ERROR,T);
 96.4228 +  else if (!strcmp (reply->key,"BYE")) {
 96.4229 +    LOCAL->byeseen = T;		/* note that a BYE seen */
 96.4230 +    imap_parse_response (stream,reply->text,BYE,T);
 96.4231 +  }
 96.4232 +  else if (!strcmp (reply->key,"CAPABILITY") && reply->text)
 96.4233 +    imap_parse_capabilities (stream,reply->text);
 96.4234 +  else if (!strcmp (reply->key,"MAILBOX") && reply->text) {
 96.4235 +    if (LOCAL->prefix &&
 96.4236 +	((strlen (LOCAL->prefix) + strlen (reply->text)) < IMAPTMPLEN))
 96.4237 +      sprintf (t = LOCAL->tmp,"%s%s",LOCAL->prefix,(char *) reply->text);
 96.4238 +    else t = reply->text;
 96.4239 +    mm_list (stream,NIL,t,NIL);
 96.4240 +  }
 96.4241 +  else {
 96.4242 +    sprintf (LOCAL->tmp,"Unexpected untagged message: %.80s",
 96.4243 +	     (char *) reply->key);
 96.4244 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.4245 +    stream->unhealthy = T;
 96.4246 +  }
 96.4247 +}
 96.4248 +
 96.4249 +/* Parse human-readable response text
 96.4250 + * Accepts: mail stream
 96.4251 + *	    text
 96.4252 + *	    error level for mm_notify()
 96.4253 + *	    non-NIL if want mm_notify() event even if no response code
 96.4254 + */
 96.4255 +
 96.4256 +void imap_parse_response (MAILSTREAM *stream,char *text,long errflg,long ntfy)
 96.4257 +{
 96.4258 +  char *s,*t,*r;
 96.4259 +  size_t i;
 96.4260 +  unsigned long j;
 96.4261 +  MESSAGECACHE *elt;
 96.4262 +  copyuid_t cu;
 96.4263 +  appenduid_t au;
 96.4264 +  SEARCHSET *source = NIL;
 96.4265 +  SEARCHSET *dest = NIL;
 96.4266 +  if (text && (*text == '[') && (t = strchr (s = text + 1,']')) &&
 96.4267 +      ((i = t - s) < IMAPTMPLEN)) {
 96.4268 +    LOCAL->tmp[i] = '\0';	/* make mungable copy of text code */
 96.4269 +    if (s = strchr (strncpy (t = LOCAL->tmp,s,i),' ')) *s++ = '\0';
 96.4270 +    if (s) {			/* have argument? */
 96.4271 +      ntfy = NIL;		/* suppress mm_notify if normal SELECT data */
 96.4272 +      if (!compare_cstring (t,"UIDVALIDITY") &&
 96.4273 +	  ((j = strtoul (s,NIL,10)) != stream->uid_validity)) {
 96.4274 +	mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
 96.4275 +	stream->uid_validity = j;
 96.4276 +				/* purge any UIDs in cache */
 96.4277 +	for (j = 1; j <= stream->nmsgs; j++)
 96.4278 +	  if (elt = (MESSAGECACHE *) (*mc) (stream,j,CH_ELT))
 96.4279 +	    elt->private.uid = 0;
 96.4280 +      }
 96.4281 +      else if (!compare_cstring (t,"UIDNEXT"))
 96.4282 +	stream->uid_last = strtoul (s,NIL,10) - 1;
 96.4283 +      else if (!compare_cstring (t,"PERMANENTFLAGS") && (*s == '(') &&
 96.4284 +	       (t[i-1] == ')')) {
 96.4285 +	t[i-1] = '\0';		/* tie off flags */
 96.4286 +	stream->perm_seen = stream->perm_deleted = stream->perm_answered =
 96.4287 +	  stream->perm_draft = stream->kwd_create = NIL;
 96.4288 +	stream->perm_user_flags = NIL;
 96.4289 +	if (s = strtok_r (s+1," ",&r)) do {
 96.4290 +	  if (*s == '\\') {	/* system flags */
 96.4291 +	    if (!compare_cstring (s,"\\Seen")) stream->perm_seen = T;
 96.4292 +	    else if (!compare_cstring (s,"\\Deleted"))
 96.4293 +	      stream->perm_deleted = T;
 96.4294 +	    else if (!compare_cstring (s,"\\Flagged"))
 96.4295 +	      stream->perm_flagged = T;
 96.4296 +	    else if (!compare_cstring (s,"\\Answered"))
 96.4297 +	      stream->perm_answered = T;
 96.4298 +	    else if (!compare_cstring (s,"\\Draft")) stream->perm_draft = T;
 96.4299 +	    else if (!strcmp (s,"\\*")) stream->kwd_create = T;
 96.4300 +	  }
 96.4301 +	  else stream->perm_user_flags |= imap_parse_user_flag (stream,s);
 96.4302 +	}
 96.4303 +	while (s = strtok_r (NIL," ",&r));
 96.4304 +      }
 96.4305 +
 96.4306 +      else if (!compare_cstring (t,"CAPABILITY"))
 96.4307 +	imap_parse_capabilities (stream,s);
 96.4308 +      else if ((j = LEVELUIDPLUS (stream) && LOCAL->appendmailbox) &&
 96.4309 +	       !compare_cstring (t,"COPYUID") &&
 96.4310 +	       (cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL)) &&
 96.4311 +	       isdigit (*s) && (j = strtoul (s,&s,10)) && (*s++ == ' ') &&
 96.4312 +	       (source = mail_parse_set (s,&s)) && (*s++ == ' ') &&
 96.4313 +	       (dest = mail_parse_set (s,&s)) && !*s)
 96.4314 +	(*cu) (stream,LOCAL->appendmailbox,j,source,dest);
 96.4315 +      else if (j && !compare_cstring (t,"APPENDUID") &&
 96.4316 +	       (au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL)) &&
 96.4317 +	       isdigit (*s) && (j = strtoul (s,&s,10)) && (*s++ == ' ') &&
 96.4318 +	       (dest = mail_parse_set (s,&s)) && !*s)
 96.4319 +	(*au) (LOCAL->appendmailbox,j,dest);
 96.4320 +      else {			/* all other response code events */
 96.4321 +	ntfy = T;		/* must mm_notify() */
 96.4322 +	if (!compare_cstring (t,"REFERRAL"))
 96.4323 +	  LOCAL->referral = cpystr (t + 9);
 96.4324 +      }
 96.4325 +      mail_free_searchset (&source);
 96.4326 +      mail_free_searchset (&dest);
 96.4327 +    }
 96.4328 +    else {			/* no arguments */
 96.4329 +      if (!compare_cstring (t,"UIDNOTSTICKY")) {
 96.4330 +	ntfy = NIL;
 96.4331 +	stream->uid_nosticky = T;
 96.4332 +      }
 96.4333 +      else if (!compare_cstring (t,"READ-ONLY")) stream->rdonly = T;
 96.4334 +      else if (!compare_cstring (t,"READ-WRITE"))
 96.4335 +	stream->rdonly = NIL;
 96.4336 +      else if (!compare_cstring (t,"PARSE") && !errflg)
 96.4337 +	errflg = PARSE;
 96.4338 +    }
 96.4339 +  }
 96.4340 +				/* give event to main program */
 96.4341 +  if (ntfy && !stream->silent) mm_notify (stream,text ? text : "",errflg);
 96.4342 +}
 96.4343 +
 96.4344 +/* Parse a namespace
 96.4345 + * Accepts: mail stream
 96.4346 + *	    current text pointer
 96.4347 + *	    parsed reply
 96.4348 + * Returns: namespace list, text pointer updated
 96.4349 + */
 96.4350 +
 96.4351 +NAMESPACE *imap_parse_namespace (MAILSTREAM *stream,unsigned char **txtptr,
 96.4352 +				 IMAPPARSEDREPLY *reply)
 96.4353 +{
 96.4354 +  NAMESPACE *ret = NIL;
 96.4355 +  NAMESPACE *nam = NIL;
 96.4356 +  NAMESPACE *prev = NIL;
 96.4357 +  PARAMETER *par = NIL;
 96.4358 +  if (*txtptr) {		/* only if argument given */
 96.4359 +				/* ignore leading space */
 96.4360 +    while (**txtptr == ' ') ++*txtptr;
 96.4361 +    switch (**txtptr) {
 96.4362 +    case 'N':			/* if NIL */
 96.4363 +    case 'n':
 96.4364 +      ++*txtptr;		/* bump past "N" */
 96.4365 +      ++*txtptr;		/* bump past "I" */
 96.4366 +      ++*txtptr;		/* bump past "L" */
 96.4367 +      break;
 96.4368 +    case '(':
 96.4369 +      ++*txtptr;		/* skip past open paren */
 96.4370 +      while (**txtptr == '(') {
 96.4371 +	++*txtptr;		/* skip past open paren */
 96.4372 +	prev = nam;		/* note previous if any */
 96.4373 +	nam = (NAMESPACE *) memset (fs_get (sizeof (NAMESPACE)),0,
 96.4374 +				  sizeof (NAMESPACE));
 96.4375 +	if (!ret) ret = nam;	/* if first time note first namespace */
 96.4376 +				/* if previous link new block to it */
 96.4377 +	if (prev) prev->next = nam;
 96.4378 +	nam->name = imap_parse_string (stream,txtptr,reply,NIL,NIL,NIL);
 96.4379 +				/* ignore whitespace */
 96.4380 +	while (**txtptr == ' ') ++*txtptr;
 96.4381 +	switch (**txtptr) {	/* parse delimiter */
 96.4382 +	case 'N':
 96.4383 +	case 'n':
 96.4384 +	  *txtptr += 3;		/* bump past "NIL" */
 96.4385 +	  break;
 96.4386 +	case '"':
 96.4387 +	  if (*++*txtptr == '\\') nam->delimiter = *++*txtptr;
 96.4388 +	  else nam->delimiter = **txtptr;
 96.4389 +	  *txtptr += 2;		/* bump past character and closing quote */
 96.4390 +	  break;
 96.4391 +	default:
 96.4392 +	  sprintf (LOCAL->tmp,"Missing delimiter in namespace: %.80s",
 96.4393 +		   (char *) *txtptr);
 96.4394 +	  mm_notify (stream,LOCAL->tmp,WARN);
 96.4395 +	  stream->unhealthy = T;
 96.4396 +	  *txtptr = NIL;	/* stop parse */
 96.4397 +	  return ret;
 96.4398 +	}
 96.4399 +
 96.4400 +	while (**txtptr == ' '){/* append new parameter to tail */
 96.4401 +	  if (nam->param) par = par->next = mail_newbody_parameter ();
 96.4402 +	  else nam->param = par = mail_newbody_parameter ();
 96.4403 +	  if (!(par->attribute = imap_parse_string (stream,txtptr,reply,NIL,
 96.4404 +						    NIL,NIL))) {
 96.4405 +	    mm_notify (stream,"Missing namespace extension attribute",WARN);
 96.4406 +	    stream->unhealthy = T;
 96.4407 +	    par->attribute = cpystr ("UNKNOWN");
 96.4408 +	  }
 96.4409 +				/* skip space */
 96.4410 +	  while (**txtptr == ' ') ++*txtptr;
 96.4411 +	  if (**txtptr == '(') {/* have value list?  */
 96.4412 +	    char *att = par->attribute;
 96.4413 +	    ++*txtptr;		/* yes */
 96.4414 +	    do {		/* parse each value */
 96.4415 +	      if (!(par->value = imap_parse_string (stream,txtptr,reply,NIL,
 96.4416 +						    NIL,LONGT))) {
 96.4417 +		sprintf (LOCAL->tmp,
 96.4418 +			 "Missing value for namespace attribute %.80s",att);
 96.4419 +		mm_notify (stream,LOCAL->tmp,WARN);
 96.4420 +		stream->unhealthy = T;
 96.4421 +		par->value = cpystr ("UNKNOWN");
 96.4422 +	      }
 96.4423 +				/* is there another value? */
 96.4424 +	      if (**txtptr == ' ') par = par->next = mail_newbody_parameter ();
 96.4425 +	    } while (!par->value);
 96.4426 +	  }
 96.4427 +	  else {
 96.4428 +	    sprintf (LOCAL->tmp,"Missing values for namespace attribute %.80s",
 96.4429 +		     par->attribute);
 96.4430 +	    mm_notify (stream,LOCAL->tmp,WARN);
 96.4431 +	    stream->unhealthy = T;
 96.4432 +	    par->value = cpystr ("UNKNOWN");
 96.4433 +	  }
 96.4434 +	}
 96.4435 +	if (**txtptr == ')') ++*txtptr;
 96.4436 +	else {			/* missing trailing paren */
 96.4437 +	  sprintf (LOCAL->tmp,"Junk at end of namespace: %.80s",
 96.4438 +		   (char *) *txtptr);
 96.4439 +	  mm_notify (stream,LOCAL->tmp,WARN);
 96.4440 +	  stream->unhealthy = T;
 96.4441 +	  return ret;
 96.4442 +	}
 96.4443 +      }
 96.4444 +      if (**txtptr == ')') {	/* expected trailing paren? */
 96.4445 +	++*txtptr;		/* got it! */
 96.4446 +	break;
 96.4447 +      }
 96.4448 +    default:
 96.4449 +      sprintf (LOCAL->tmp,"Not a namespace: %.80s",(char *) *txtptr);
 96.4450 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4451 +      stream->unhealthy = T;
 96.4452 +      *txtptr = NIL;		/* stop parse now */
 96.4453 +      break;
 96.4454 +    }
 96.4455 +  }
 96.4456 +  return ret;
 96.4457 +}
 96.4458 +
 96.4459 +/* Parse a thread node list
 96.4460 + * Accepts: mail stream
 96.4461 + *	    current text pointer
 96.4462 + * Returns: thread node list, text pointer updated
 96.4463 + */
 96.4464 +
 96.4465 +THREADNODE *imap_parse_thread (MAILSTREAM *stream,unsigned char **txtptr)
 96.4466 +{
 96.4467 +  char *s;
 96.4468 +  THREADNODE *ret = NIL;	/* returned tree */
 96.4469 +  THREADNODE *last = NIL;	/* last branch in this tree */
 96.4470 +  THREADNODE *parent = NIL;	/* parent of current node */
 96.4471 +  THREADNODE *cur;		/* current node */
 96.4472 +  while (**txtptr == '(') {	/* see a thread? */
 96.4473 +    ++*txtptr;			/* skip past open paren */
 96.4474 +    while (**txtptr != ')') {	/* parse thread */
 96.4475 +      if (**txtptr == '(') {	/* thread branch */
 96.4476 +	cur = imap_parse_thread (stream,txtptr);
 96.4477 +				/* add to parent */
 96.4478 +	if (parent) parent = parent->next = cur;
 96.4479 +	else {			/* no parent, create dummy */
 96.4480 +	  if (last) last = last->branch = mail_newthreadnode (NIL);
 96.4481 +				/* new tree */
 96.4482 +	  else ret = last = mail_newthreadnode (NIL);
 96.4483 +				/* add to dummy parent */
 96.4484 +	  last->next = parent = cur;
 96.4485 +	}
 96.4486 +      }
 96.4487 +				/* threaded message number */
 96.4488 +      else if (isdigit (*(s = *txtptr)) &&
 96.4489 +	       ((cur = mail_newthreadnode (NIL))->num =
 96.4490 +		strtoul (*txtptr,(char **) txtptr,10))) {
 96.4491 +	if (LOCAL->filter && !mail_elt (stream,cur->num)->searched)
 96.4492 +	  cur->num = NIL;	/* make dummy if filtering and not searched */
 96.4493 +				/* add to parent */
 96.4494 +	if (parent) parent = parent->next = cur;
 96.4495 +				/* no parent, start new thread */
 96.4496 +	else if (last) last = last->branch = parent = cur;
 96.4497 +				/* create new tree */
 96.4498 +	else ret = last = parent = cur;
 96.4499 +      }
 96.4500 +      else {			/* anything else is a bogon */
 96.4501 +	char tmp[MAILTMPLEN];
 96.4502 +	sprintf (tmp,"Bogus thread member: %.80s",s);
 96.4503 +	mm_notify (stream,tmp,WARN);
 96.4504 +	stream->unhealthy = T;
 96.4505 +	return ret;
 96.4506 +      }
 96.4507 +				/* skip past any space */
 96.4508 +      if (**txtptr == ' ') ++*txtptr;
 96.4509 +    }
 96.4510 +    ++*txtptr;			/* skip pase end of thread */
 96.4511 +    parent = NIL;		/* close this thread */
 96.4512 +  }
 96.4513 +  return ret;			/* return parsed thread */
 96.4514 +}
 96.4515 +
 96.4516 +/* Parse RFC822 message header
 96.4517 + * Accepts: MAIL stream
 96.4518 + *	    envelope to parse into
 96.4519 + *	    header as sized text
 96.4520 + *	    stringlist if partial header
 96.4521 + */
 96.4522 +
 96.4523 +void imap_parse_header (MAILSTREAM *stream,ENVELOPE **env,SIZEDTEXT *hdr,
 96.4524 +			STRINGLIST *stl)
 96.4525 +{
 96.4526 +  ENVELOPE *nenv;
 96.4527 +				/* parse what we can from this header */
 96.4528 +  rfc822_parse_msg (&nenv,NIL,(char *) hdr->data,hdr->size,NIL,
 96.4529 +		    net_host (LOCAL->netstream),stream->dtb->flags);
 96.4530 +  if (*env) {			/* need to merge this header into envelope? */
 96.4531 +    if (!(*env)->newsgroups) {	/* need Newsgroups? */
 96.4532 +      (*env)->newsgroups = nenv->newsgroups;
 96.4533 +      nenv->newsgroups = NIL;
 96.4534 +    }
 96.4535 +    if (!(*env)->followup_to) {	/* need Followup-To? */
 96.4536 +      (*env)->followup_to = nenv->followup_to;
 96.4537 +      nenv->followup_to = NIL;
 96.4538 +    }
 96.4539 +    if (!(*env)->references) {	/* need References? */
 96.4540 +      (*env)->references = nenv->references;
 96.4541 +      nenv->references = NIL;
 96.4542 +    }
 96.4543 +    if (!(*env)->sparep) {	/* need spare pointer? */
 96.4544 +      (*env)->sparep = nenv->sparep;
 96.4545 +      nenv->sparep = NIL;
 96.4546 +    }
 96.4547 +    mail_free_envelope (&nenv);
 96.4548 +    (*env)->imapenvonly = NIL;	/* have complete envelope now */
 96.4549 +  }
 96.4550 +				/* otherwise set it to this envelope */
 96.4551 +  else (*env = nenv)->incomplete = stl ? T : NIL;
 96.4552 +}
 96.4553 +
 96.4554 +/* IMAP parse envelope
 96.4555 + * Accepts: MAIL stream
 96.4556 + *	    pointer to envelope pointer
 96.4557 + *	    current text pointer
 96.4558 + *	    parsed reply
 96.4559 + *
 96.4560 + * Updates text pointer
 96.4561 + */
 96.4562 +
 96.4563 +void imap_parse_envelope (MAILSTREAM *stream,ENVELOPE **env,
 96.4564 +			  unsigned char **txtptr,IMAPPARSEDREPLY *reply)
 96.4565 +{
 96.4566 +  ENVELOPE *oenv = *env;
 96.4567 +  char c = *((*txtptr)++);	/* grab first character */
 96.4568 +				/* ignore leading spaces */
 96.4569 +  while (c == ' ') c = *((*txtptr)++);
 96.4570 +  switch (c) {			/* dispatch on first character */
 96.4571 +  case '(':			/* if envelope S-expression */
 96.4572 +    *env = mail_newenvelope ();	/* parse the new envelope */
 96.4573 +    (*env)->date = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4574 +    (*env)->subject = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4575 +    (*env)->from = imap_parse_adrlist (stream,txtptr,reply);
 96.4576 +    (*env)->sender = imap_parse_adrlist (stream,txtptr,reply);
 96.4577 +    (*env)->reply_to = imap_parse_adrlist (stream,txtptr,reply);
 96.4578 +    (*env)->to = imap_parse_adrlist (stream,txtptr,reply);
 96.4579 +    (*env)->cc = imap_parse_adrlist (stream,txtptr,reply);
 96.4580 +    (*env)->bcc = imap_parse_adrlist (stream,txtptr,reply);
 96.4581 +    (*env)->in_reply_to = imap_parse_string (stream,txtptr,reply,NIL,NIL,
 96.4582 +					     LONGT);
 96.4583 +    (*env)->message_id = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4584 +    if (oenv) {			/* need to merge old envelope? */
 96.4585 +      (*env)->newsgroups = oenv->newsgroups;
 96.4586 +      oenv->newsgroups = NIL;
 96.4587 +      (*env)->followup_to = oenv->followup_to;
 96.4588 +      oenv->followup_to = NIL;
 96.4589 +      (*env)->references = oenv->references;
 96.4590 +      oenv->references = NIL;
 96.4591 +      mail_free_envelope(&oenv);/* free old envelope */
 96.4592 +    }
 96.4593 +				/* have IMAP envelope components only */
 96.4594 +    else (*env)->imapenvonly = T;
 96.4595 +    if (**txtptr != ')') {
 96.4596 +      sprintf (LOCAL->tmp,"Junk at end of envelope: %.80s",(char *) *txtptr);
 96.4597 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4598 +      stream->unhealthy = T;
 96.4599 +    }
 96.4600 +    else ++*txtptr;		/* skip past delimiter */
 96.4601 +    break;
 96.4602 +  case 'N':			/* if NIL */
 96.4603 +  case 'n':
 96.4604 +    ++*txtptr;			/* bump past "I" */
 96.4605 +    ++*txtptr;			/* bump past "L" */
 96.4606 +    break;
 96.4607 +  default:
 96.4608 +    sprintf (LOCAL->tmp,"Not an envelope: %.80s",(char *) *txtptr);
 96.4609 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.4610 +    stream->unhealthy = T;
 96.4611 +    break;
 96.4612 +  }
 96.4613 +}
 96.4614 +
 96.4615 +/* IMAP parse address list
 96.4616 + * Accepts: MAIL stream
 96.4617 + *	    current text pointer
 96.4618 + *	    parsed reply
 96.4619 + * Returns: address list, NIL on failure
 96.4620 + *
 96.4621 + * Updates text pointer
 96.4622 + */
 96.4623 +
 96.4624 +ADDRESS *imap_parse_adrlist (MAILSTREAM *stream,unsigned char **txtptr,
 96.4625 +			     IMAPPARSEDREPLY *reply)
 96.4626 +{
 96.4627 +  ADDRESS *adr = NIL;
 96.4628 +  char c = **txtptr;		/* sniff at first character */
 96.4629 +				/* ignore leading spaces */
 96.4630 +  while (c == ' ') c = *++*txtptr;
 96.4631 +  ++*txtptr;			/* skip past open paren */
 96.4632 +  switch (c) {
 96.4633 +  case '(':			/* if envelope S-expression */
 96.4634 +    adr = imap_parse_address (stream,txtptr,reply);
 96.4635 +    if (**txtptr != ')') {
 96.4636 +      sprintf (LOCAL->tmp,"Junk at end of address list: %.80s",
 96.4637 +	       (char *) *txtptr);
 96.4638 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4639 +      stream->unhealthy = T;
 96.4640 +    }
 96.4641 +    else ++*txtptr;		/* skip past delimiter */
 96.4642 +    break;
 96.4643 +  case 'N':			/* if NIL */
 96.4644 +  case 'n':
 96.4645 +    ++*txtptr;			/* bump past "I" */
 96.4646 +    ++*txtptr;			/* bump past "L" */
 96.4647 +    break;
 96.4648 +  default:
 96.4649 +    sprintf (LOCAL->tmp,"Not an address: %.80s",(char *) *txtptr);
 96.4650 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.4651 +    stream->unhealthy = T;
 96.4652 +    break;
 96.4653 +  }
 96.4654 +  return adr;
 96.4655 +}
 96.4656 +
 96.4657 +/* IMAP parse address
 96.4658 + * Accepts: MAIL stream
 96.4659 + *	    current text pointer
 96.4660 + *	    parsed reply
 96.4661 + * Returns: address, NIL on failure
 96.4662 + *
 96.4663 + * Updates text pointer
 96.4664 + */
 96.4665 +
 96.4666 +ADDRESS *imap_parse_address (MAILSTREAM *stream,unsigned char **txtptr,
 96.4667 +			     IMAPPARSEDREPLY *reply)
 96.4668 +{
 96.4669 +  long ingroup = 0;
 96.4670 +  ADDRESS *adr = NIL;
 96.4671 +  ADDRESS *ret = NIL;
 96.4672 +  ADDRESS *prev = NIL;
 96.4673 +  char c = **txtptr;		/* sniff at first address character */
 96.4674 +  switch (c) {
 96.4675 +  case '(':			/* if envelope S-expression */
 96.4676 +    while (c == '(') {		/* recursion dies on small stack machines */
 96.4677 +      ++*txtptr;		/* skip past open paren */
 96.4678 +      if (adr) prev = adr;	/* note previous if any */
 96.4679 +      adr = mail_newaddr ();	/* instantiate address and parse its fields */
 96.4680 +      adr->personal = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4681 +      adr->adl = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4682 +      adr->mailbox = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4683 +      adr->host = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.4684 +      if (**txtptr != ')') {	/* handle trailing paren */
 96.4685 +	sprintf (LOCAL->tmp,"Junk at end of address: %.80s",(char *) *txtptr);
 96.4686 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4687 +	stream->unhealthy = T;
 96.4688 +      }
 96.4689 +      else ++*txtptr;		/* skip past close paren */
 96.4690 +      c = **txtptr;		/* set up for while test */
 96.4691 +				/* ignore leading spaces in front of next */
 96.4692 +      while (c == ' ') c = *++*txtptr;
 96.4693 +
 96.4694 +      if (!adr->mailbox) {	/* end of group? */
 96.4695 +				/* decrement group if all looks well */
 96.4696 +	if (ingroup && !(adr->personal || adr->adl || adr->host)) --ingroup;
 96.4697 +	else {
 96.4698 +	  if (ingroup) {	/* in a group? */
 96.4699 +	    sprintf (LOCAL->tmp,/* yes, must be bad syntax */
 96.4700 +		     "Junk in end of group: pn=%.80s al=%.80s dn=%.80s",
 96.4701 +		     adr->personal ? adr->personal : "",
 96.4702 +		     adr->adl ? adr->adl : "",
 96.4703 +		     adr->host ? adr->host : "");
 96.4704 +	    mm_notify (stream,LOCAL->tmp,WARN);
 96.4705 +	  }
 96.4706 +	  else mm_notify (stream,"End of group encountered when not in group",
 96.4707 +			  WARN);
 96.4708 +	  stream->unhealthy = T;
 96.4709 +	  mail_free_address (&adr);
 96.4710 +	  adr = prev;
 96.4711 +	  prev = NIL;
 96.4712 +	}
 96.4713 +      }
 96.4714 +      else if (!adr->host) {	/* start of group? */
 96.4715 +	if (adr->personal || adr->adl) {
 96.4716 +	  sprintf (LOCAL->tmp,"Junk in start of group: pn=%.80s al=%.80s",
 96.4717 +		   adr->personal ? adr->personal : "",
 96.4718 +		   adr->adl ? adr->adl : "");
 96.4719 +	  mm_notify (stream,LOCAL->tmp,WARN);
 96.4720 +	  stream->unhealthy = T;
 96.4721 +	  mail_free_address (&adr);
 96.4722 +	  adr = prev;
 96.4723 +	  prev = NIL;
 96.4724 +	}
 96.4725 +	else ++ingroup;		/* in a group now */
 96.4726 +      }
 96.4727 +      if (adr) {		/* good address */
 96.4728 +	if (!ret) ret = adr;	/* if first time note first adr */
 96.4729 +				/* if previous link new block to it */
 96.4730 +	if (prev) prev->next = adr;
 96.4731 +				/* flush bogus personal name */
 96.4732 +	if (LOCAL->loser && adr->personal && strchr (adr->personal,'@'))
 96.4733 +	  fs_give ((void **) &adr->personal);
 96.4734 +      }
 96.4735 +    }
 96.4736 +    break;
 96.4737 +  case 'N':			/* if NIL */
 96.4738 +  case 'n':
 96.4739 +    *txtptr += 3;		/* bump past NIL */
 96.4740 +    break;
 96.4741 +  default:
 96.4742 +    sprintf (LOCAL->tmp,"Not an address: %.80s",(char *) *txtptr);
 96.4743 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.4744 +    stream->unhealthy = T;
 96.4745 +    break;
 96.4746 +  }
 96.4747 +  return ret;
 96.4748 +}
 96.4749 +
 96.4750 +/* IMAP parse flags
 96.4751 + * Accepts: current message cache
 96.4752 + *	    current text pointer
 96.4753 + *
 96.4754 + * Updates text pointer
 96.4755 + */
 96.4756 +
 96.4757 +void imap_parse_flags (MAILSTREAM *stream,MESSAGECACHE *elt,
 96.4758 +		       unsigned char **txtptr)
 96.4759 +{
 96.4760 +  char *flag;
 96.4761 +  char c = '\0';
 96.4762 +  struct {			/* old flags */
 96.4763 +    unsigned int valid : 1;
 96.4764 +    unsigned int seen : 1;
 96.4765 +    unsigned int deleted : 1;
 96.4766 +    unsigned int flagged : 1;
 96.4767 +    unsigned int answered : 1;
 96.4768 +    unsigned int draft : 1;
 96.4769 +    unsigned long user_flags;
 96.4770 +  } old;
 96.4771 +  old.valid = elt->valid; old.seen = elt->seen; old.deleted = elt->deleted;
 96.4772 +  old.flagged = elt->flagged; old.answered = elt->answered;
 96.4773 +  old.draft = elt->draft; old.user_flags = elt->user_flags;
 96.4774 +  elt->valid = T;		/* mark have valid flags now */
 96.4775 +  elt->user_flags = NIL;	/* zap old flag values */
 96.4776 +  elt->seen = elt->deleted = elt->flagged = elt->answered = elt->draft =
 96.4777 +    elt->recent = NIL;
 96.4778 +  while (c != ')') {		/* parse list of flags */
 96.4779 +				/* point at a flag */
 96.4780 +    while (*(flag = ++*txtptr) == ' ');
 96.4781 +				/* scan for end of flag */
 96.4782 +    while (**txtptr != ' ' && **txtptr != ')') ++*txtptr;
 96.4783 +    c = **txtptr;		/* save delimiter */
 96.4784 +    **txtptr = '\0';		/* tie off flag */
 96.4785 +    if (!*flag) break;		/* null flag */
 96.4786 +				/* if starts with \ must be sys flag */
 96.4787 +    else if (*flag == '\\') {
 96.4788 +      if (!compare_cstring (flag,"\\Seen")) elt->seen = T;
 96.4789 +      else if (!compare_cstring (flag,"\\Deleted")) elt->deleted = T;
 96.4790 +      else if (!compare_cstring (flag,"\\Flagged")) elt->flagged = T;
 96.4791 +      else if (!compare_cstring (flag,"\\Answered")) elt->answered = T;
 96.4792 +      else if (!compare_cstring (flag,"\\Recent")) elt->recent = T;
 96.4793 +      else if (!compare_cstring (flag,"\\Draft")) elt->draft = T;
 96.4794 +    }
 96.4795 +				/* otherwise user flag */
 96.4796 +    else elt->user_flags |= imap_parse_user_flag (stream,flag);
 96.4797 +  }
 96.4798 +  ++*txtptr;			/* bump past delimiter */
 96.4799 +  if (!old.valid || (old.seen != elt->seen) ||
 96.4800 +      (old.deleted != elt->deleted) || (old.flagged != elt->flagged) ||
 96.4801 +      (old.answered != elt->answered) || (old.draft != elt->draft) ||
 96.4802 +      (old.user_flags != elt->user_flags)) mm_flags (stream,elt->msgno);
 96.4803 +}
 96.4804 +
 96.4805 +
 96.4806 +/* IMAP parse user flag
 96.4807 + * Accepts: MAIL stream
 96.4808 + *	    flag name
 96.4809 + * Returns: flag bit position
 96.4810 + */
 96.4811 +
 96.4812 +unsigned long imap_parse_user_flag (MAILSTREAM *stream,char *flag)
 96.4813 +{
 96.4814 +  long i;
 96.4815 +				/* sniff through all user flags */
 96.4816 +  for (i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i])
 96.4817 +    if (!compare_cstring (flag,stream->user_flags[i])) return (1 << i);
 96.4818 +  return (unsigned long) 0;	/* not found */
 96.4819 +}
 96.4820 +
 96.4821 +/* IMAP parse atom-string
 96.4822 + * Accepts: MAIL stream
 96.4823 + *	    current text pointer
 96.4824 + *	    parsed reply
 96.4825 + *	    returned string length
 96.4826 + * Returns: string
 96.4827 + *
 96.4828 + * Updates text pointer
 96.4829 + */
 96.4830 +
 96.4831 +unsigned char *imap_parse_astring (MAILSTREAM *stream,unsigned char **txtptr,
 96.4832 +				   IMAPPARSEDREPLY *reply,unsigned long *len)
 96.4833 +{
 96.4834 +  unsigned long i;
 96.4835 +  unsigned char c,*s,*ret;
 96.4836 +				/* ignore leading spaces */
 96.4837 +  for (c = **txtptr; c == ' '; c = *++*txtptr);
 96.4838 +  switch (c) {
 96.4839 +  case '"':			/* quoted string? */
 96.4840 +  case '{':			/* literal? */
 96.4841 +    ret = imap_parse_string (stream,txtptr,reply,NIL,len,NIL);
 96.4842 +    break;
 96.4843 +  default:			/* must be atom */
 96.4844 +    for (c = *(s = *txtptr);	/* find end of atom */
 96.4845 +	 c && (c > ' ') && (c != '(') && (c != ')') && (c != '{') &&
 96.4846 +	   (c != '%') && (c != '*') && (c != '"') && (c != '\\') && (c < 0x80);
 96.4847 +	 c = *++*txtptr);
 96.4848 +    if (i = *txtptr - s) {	/* atom ends at atom_special */
 96.4849 +      if (len) *len = i;	/* return length of atom */
 96.4850 +      ret = strncpy ((char *) fs_get (i + 1),s,i);
 96.4851 +      ret[i] = '\0';		/* tie off string */
 96.4852 +    }
 96.4853 +    else {			/* no atom found */
 96.4854 +      sprintf (LOCAL->tmp,"Not an atom: %.80s",(char *) *txtptr);
 96.4855 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4856 +      stream->unhealthy = T;
 96.4857 +      if (len) *len = 0;
 96.4858 +      ret = NIL;
 96.4859 +    }
 96.4860 +    break;
 96.4861 +  }
 96.4862 +  return ret;
 96.4863 +}
 96.4864 +
 96.4865 +/* IMAP parse string
 96.4866 + * Accepts: MAIL stream
 96.4867 + *	    current text pointer
 96.4868 + *	    parsed reply
 96.4869 + *	    mailgets data
 96.4870 + *	    returned string length
 96.4871 + *	    filter newline flag
 96.4872 + * Returns: string
 96.4873 + *
 96.4874 + * Updates text pointer
 96.4875 + */
 96.4876 +
 96.4877 +unsigned char *imap_parse_string (MAILSTREAM *stream,unsigned char **txtptr,
 96.4878 +				  IMAPPARSEDREPLY *reply,GETS_DATA *md,
 96.4879 +				  unsigned long *len,long flags)
 96.4880 +{
 96.4881 +  char *st;
 96.4882 +  char *string = NIL;
 96.4883 +  unsigned long i,j,k;
 96.4884 +  int bogon = NIL;
 96.4885 +  unsigned char c = **txtptr;	/* sniff at first character */
 96.4886 +  mailgets_t mg = (mailgets_t) mail_parameters (NIL,GET_GETS,NIL);
 96.4887 +  readprogress_t rp =
 96.4888 +    (readprogress_t) mail_parameters (NIL,GET_READPROGRESS,NIL);
 96.4889 +				/* ignore leading spaces */
 96.4890 +  while (c == ' ') c = *++*txtptr;
 96.4891 +  st = ++*txtptr;		/* remember start of string */
 96.4892 +  switch (c) {
 96.4893 +  case '"':			/* if quoted string */
 96.4894 +    i = 0;			/* initial byte count */
 96.4895 +				/* search for end of string */
 96.4896 +    for (c = **txtptr; c != '"'; ++i,c = *++*txtptr) {
 96.4897 +				/* backslash quotes next character */
 96.4898 +      if (c == '\\') c = *++*txtptr;
 96.4899 +				/* CHAR8 not permitted in quoted string */
 96.4900 +      if (!bogon && (bogon = (c & 0x80))) {
 96.4901 +	sprintf (LOCAL->tmp,"Invalid CHAR in quoted string: %x",
 96.4902 +		 (unsigned int) c);
 96.4903 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.4904 +	stream->unhealthy = T;
 96.4905 +      }
 96.4906 +      else if (!c) {		/* NUL not permitted either */
 96.4907 +	mm_notify (stream,"Unterminated quoted string",WARN);
 96.4908 +	stream->unhealthy = T;
 96.4909 +	if (len) *len = 0;	/* punt, since may be at end of string */
 96.4910 +	return NIL;
 96.4911 +      }
 96.4912 +    }
 96.4913 +    ++*txtptr;			/* bump past delimiter */
 96.4914 +    string = (char *) fs_get ((size_t) i + 1);
 96.4915 +    for (j = 0; j < i; j++) {	/* copy the string */
 96.4916 +      if (*st == '\\') ++st;	/* quoted character */
 96.4917 +      string[j] = *st++;
 96.4918 +    }
 96.4919 +    string[j] = '\0';		/* tie off string */
 96.4920 +    if (len) *len = i;		/* set return value too */
 96.4921 +    if (md && mg) {		/* have special routine to slurp string? */
 96.4922 +      STRING bs;
 96.4923 +      if (md->first) {		/* partial fetch? */
 96.4924 +	md->first--;		/* restore origin octet */
 96.4925 +	md->last = i;		/* number of octets that we got */
 96.4926 +      }
 96.4927 +      INIT (&bs,mail_string,string,i);
 96.4928 +      (*mg) (mail_read,&bs,i,md);
 96.4929 +    }
 96.4930 +    break;
 96.4931 +
 96.4932 +  case 'N':			/* if NIL */
 96.4933 +  case 'n':
 96.4934 +    ++*txtptr;			/* bump past "I" */
 96.4935 +    ++*txtptr;			/* bump past "L" */
 96.4936 +    if (len) *len = 0;
 96.4937 +    break;
 96.4938 +  case '{':			/* if literal string */
 96.4939 +				/* get size of string */ 
 96.4940 +    if ((i = strtoul (*txtptr,(char **) txtptr,10)) > MAXSERVERLIT) {
 96.4941 +      sprintf (LOCAL->tmp,"Absurd server literal length %lu",i);
 96.4942 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.4943 +      stream->unhealthy = T;	/* read and discard */
 96.4944 +      do net_getbuffer (LOCAL->netstream,j = min (i,(long) IMAPTMPLEN - 1),
 96.4945 +			LOCAL->tmp);
 96.4946 +      while (i -= j);
 96.4947 +    }
 96.4948 +    if (len) *len = i;		/* set return value */
 96.4949 +    if (md && mg) {		/* have special routine to slurp string? */
 96.4950 +      if (md->first) {		/* partial fetch? */
 96.4951 +	md->first--;		/* restore origin octet */
 96.4952 +	md->last = i;		/* number of octets that we got */
 96.4953 +      }
 96.4954 +      else md->flags |= MG_COPY;/* otherwise flag need to copy */
 96.4955 +      string = (*mg) (net_getbuffer,LOCAL->netstream,i,md);
 96.4956 +    }
 96.4957 +    else {			/* must slurp into free storage */
 96.4958 +      string = (char *) fs_get ((size_t) i + 1);
 96.4959 +      *string = '\0';		/* init in case getbuffer fails */
 96.4960 +				/* get the literal */
 96.4961 +      if (rp) for (k = 0; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
 96.4962 +	net_getbuffer (LOCAL->netstream,j,string + k);
 96.4963 +	(*rp) (md,k += j);
 96.4964 +      }
 96.4965 +      else net_getbuffer (LOCAL->netstream,i,string);
 96.4966 +    }
 96.4967 +    fs_give ((void **) &reply->line);
 96.4968 +    if (flags && string)	/* need to filter newlines? */
 96.4969 +      for (st = string; st = strpbrk (st,"\015\012\011"); *st++ = ' ');
 96.4970 +				/* get new reply text line */
 96.4971 +    if (!(reply->line = net_getline (LOCAL->netstream)))
 96.4972 +      reply->line = cpystr ("");
 96.4973 +    if (stream->debug) mm_dlog (reply->line);
 96.4974 +    *txtptr = reply->line;	/* set text pointer to point at it */
 96.4975 +    break;
 96.4976 +  default:
 96.4977 +    sprintf (LOCAL->tmp,"Not a string: %c%.80s",c,(char *) *txtptr);
 96.4978 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.4979 +    stream->unhealthy = T;
 96.4980 +    if (len) *len = 0;
 96.4981 +    break;
 96.4982 +  }
 96.4983 +  return (unsigned char *) string;
 96.4984 +}
 96.4985 +
 96.4986 +/* Register text in IMAP cache
 96.4987 + * Accepts: MAIL stream
 96.4988 + *	    message number
 96.4989 + *	    IMAP segment specifier
 96.4990 + *	    header string list (if a HEADER section specifier)
 96.4991 + *	    sized text to register
 96.4992 + * Returns: non-zero if cache non-empty
 96.4993 + */
 96.4994 +
 96.4995 +long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg,
 96.4996 +		 STRINGLIST *stl,SIZEDTEXT *text)
 96.4997 +{
 96.4998 +  char *t,tmp[MAILTMPLEN];
 96.4999 +  unsigned long i;
 96.5000 +  BODY *b;
 96.5001 +  SIZEDTEXT *ret;
 96.5002 +  STRINGLIST *stc;
 96.5003 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
 96.5004 +				/* top-level header never does mailgets */
 96.5005 +  if (!strcmp (seg,"HEADER") || !strcmp (seg,"0") ||
 96.5006 +      !strcmp (seg,"HEADER.FIELDS") || !strcmp (seg,"HEADER.FIELDS.NOT")) {
 96.5007 +    ret = &elt->private.msg.header.text;
 96.5008 +    if (text) {			/* don't do this if no text */
 96.5009 +      if (ret->data) fs_give ((void **) &ret->data);
 96.5010 +      mail_free_stringlist (&elt->private.msg.lines);
 96.5011 +      elt->private.msg.lines = stl;
 96.5012 +				/* prevent cache reuse of .NOT */
 96.5013 +      if ((seg[0] == 'H') && (seg[6] == '.') && (seg[13] == '.'))
 96.5014 +	for (stc = stl; stc; stc = stc->next) stc->text.size = 0;
 96.5015 +      if (stream->scache) {	/* short caching puts it in the stream */
 96.5016 +	if (stream->msgno != msgno) {
 96.5017 +				/* flush old stuff */
 96.5018 +	  mail_free_envelope (&stream->env);
 96.5019 +	  mail_free_body (&stream->body);
 96.5020 +	  stream->msgno = msgno;
 96.5021 +	}
 96.5022 +	imap_parse_header (stream,&stream->env,text,stl);
 96.5023 +      }
 96.5024 +				/* regular caching */
 96.5025 +      else imap_parse_header (stream,&elt->private.msg.env,text,stl);
 96.5026 +    }
 96.5027 +  }
 96.5028 +				/* top level text */
 96.5029 +  else if (!strcmp (seg,"TEXT")) {
 96.5030 +    ret = &elt->private.msg.text.text;
 96.5031 +    if (text && ret->data) fs_give ((void **) &ret->data);
 96.5032 +  }
 96.5033 +  else if (!*seg) {		/* full message */
 96.5034 +    ret = &elt->private.msg.full.text;
 96.5035 +    if (text && ret->data) fs_give ((void **) &ret->data);
 96.5036 +  }
 96.5037 +
 96.5038 +  else {			/* nested, find non-contents specifier */
 96.5039 +    for (t = seg; *t && !((*t == '.') && (isalpha(t[1]) || !atol (t+1))); t++);
 96.5040 +    if (*t) *t++ = '\0';	/* tie off section from data specifier */
 96.5041 +    if (!(b = mail_body (stream,msgno,seg))) {
 96.5042 +      sprintf (tmp,"Unknown section number: %.80s",seg);
 96.5043 +      mm_notify (stream,tmp,WARN);
 96.5044 +      stream->unhealthy = T;
 96.5045 +      return NIL;
 96.5046 +    }
 96.5047 +    if (*t) {			/* if a non-numberic subpart */
 96.5048 +      if ((i = (b->type == TYPEMESSAGE) && (!strcmp (b->subtype,"RFC822"))) &&
 96.5049 +	  (!strcmp (t,"HEADER") || !strcmp (t,"0") ||
 96.5050 +	   !strcmp (t,"HEADER.FIELDS") || !strcmp (t,"HEADER.FIELDS.NOT"))) {
 96.5051 +	ret = &b->nested.msg->header.text;
 96.5052 +	if (text) {
 96.5053 +	  if (ret->data) fs_give ((void **) &ret->data);
 96.5054 +	  mail_free_stringlist (&b->nested.msg->lines);
 96.5055 +	  b->nested.msg->lines = stl;
 96.5056 +				/* prevent cache reuse of .NOT */
 96.5057 +	  if ((t[0] == 'H') && (t[6] == '.') && (t[13] == '.'))
 96.5058 +	    for (stc = stl; stc; stc = stc->next) stc->text.size = 0;
 96.5059 +	  imap_parse_header (stream,&b->nested.msg->env,text,stl);
 96.5060 +	}
 96.5061 +      }
 96.5062 +      else if (i && !strcmp (t,"TEXT")) {
 96.5063 +	ret = &b->nested.msg->text.text;
 96.5064 +	if (text && ret->data) fs_give ((void **) &ret->data);
 96.5065 +      }
 96.5066 +				/* otherwise it must be MIME */
 96.5067 +      else if (!strcmp (t,"MIME")) {
 96.5068 +	ret = &b->mime.text;
 96.5069 +	if (text && ret->data) fs_give ((void **) &ret->data);
 96.5070 +      }
 96.5071 +      else {
 96.5072 +	sprintf (tmp,"Unknown section specifier: %.80s.%.80s",seg,t);
 96.5073 +	mm_notify (stream,tmp,WARN);
 96.5074 +	stream->unhealthy = T;
 96.5075 +	return NIL;
 96.5076 +      }
 96.5077 +    }
 96.5078 +    else {			/* ordinary contents */
 96.5079 +      ret = &b->contents.text;
 96.5080 +      if (text && ret->data) fs_give ((void **) &ret->data);
 96.5081 +    }
 96.5082 +  }
 96.5083 +  if (text) {			/* update cache if requested */
 96.5084 +    ret->data = text->data;
 96.5085 +    ret->size = text->size;
 96.5086 +  }
 96.5087 +  return ret->data ? LONGT : NIL;
 96.5088 +}
 96.5089 +
 96.5090 +/* IMAP parse body structure
 96.5091 + * Accepts: MAIL stream
 96.5092 + *	    body structure to write into
 96.5093 + *	    current text pointer
 96.5094 + *	    parsed reply
 96.5095 + *
 96.5096 + * Updates text pointer
 96.5097 + */
 96.5098 +
 96.5099 +void imap_parse_body_structure (MAILSTREAM *stream,BODY *body,
 96.5100 +				unsigned char **txtptr,IMAPPARSEDREPLY *reply)
 96.5101 +{
 96.5102 +  int i;
 96.5103 +  char *s;
 96.5104 +  PART *part = NIL;
 96.5105 +  char c = *((*txtptr)++);	/* grab first character */
 96.5106 +				/* ignore leading spaces */
 96.5107 +  while (c == ' ') c = *((*txtptr)++);
 96.5108 +  switch (c) {			/* dispatch on first character */
 96.5109 +  case '(':			/* body structure list */
 96.5110 +    if (**txtptr == '(') {	/* multipart body? */
 96.5111 +      body->type= TYPEMULTIPART;/* yes, set its type */
 96.5112 +      do {			/* instantiate new body part */
 96.5113 +	if (part) part = part->next = mail_newbody_part ();
 96.5114 +	else body->nested.part = part = mail_newbody_part ();
 96.5115 +				/* parse it */
 96.5116 +	imap_parse_body_structure (stream,&part->body,txtptr,reply);
 96.5117 +      } while (**txtptr == '(');/* for each body part */
 96.5118 +      if (body->subtype = imap_parse_string(stream,txtptr,reply,NIL,NIL,LONGT))
 96.5119 +	ucase (body->subtype);
 96.5120 +      else {
 96.5121 +	mm_notify (stream,"Missing multipart subtype",WARN);
 96.5122 +	stream->unhealthy = T;
 96.5123 +	body->subtype = cpystr (rfc822_default_subtype (body->type));
 96.5124 +      }
 96.5125 +      if (**txtptr == ' ')	/* multipart parameters */
 96.5126 +	body->parameter = imap_parse_body_parameter (stream,txtptr,reply);
 96.5127 +      if (**txtptr == ' ') {	/* disposition */
 96.5128 +	imap_parse_disposition (stream,body,txtptr,reply);
 96.5129 +	if (LOCAL->cap.extlevel < BODYEXTDSP) LOCAL->cap.extlevel = BODYEXTDSP;
 96.5130 +      }
 96.5131 +      if (**txtptr == ' ') {	/* language */
 96.5132 +	body->language = imap_parse_language (stream,txtptr,reply);
 96.5133 +	if (LOCAL->cap.extlevel < BODYEXTLANG)
 96.5134 +	  LOCAL->cap.extlevel = BODYEXTLANG;
 96.5135 +      }
 96.5136 +      if (**txtptr == ' ') {	/* location */
 96.5137 +	body->location = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.5138 +	if (LOCAL->cap.extlevel < BODYEXTLOC) LOCAL->cap.extlevel = BODYEXTLOC;
 96.5139 +      }
 96.5140 +      while (**txtptr == ' ') imap_parse_extension (stream,txtptr,reply);
 96.5141 +      if (**txtptr != ')') {	/* validate ending */
 96.5142 +	sprintf (LOCAL->tmp,"Junk at end of multipart body: %.80s",
 96.5143 +		 (char *) *txtptr);
 96.5144 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.5145 +	stream->unhealthy = T;
 96.5146 +      }
 96.5147 +      else ++*txtptr;		/* skip past delimiter */
 96.5148 +    }
 96.5149 +
 96.5150 +    else {			/* not multipart, parse type name */
 96.5151 +      if (**txtptr == ')') {	/* empty body? */
 96.5152 +	++*txtptr;		/* bump past it */
 96.5153 +	break;			/* and punt */
 96.5154 +      }
 96.5155 +      body->type = TYPEOTHER;	/* assume unknown type */
 96.5156 +      body->encoding = ENCOTHER;/* and unknown encoding */
 96.5157 +				/* parse type */
 96.5158 +      if (s = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT)) {
 96.5159 +	ucase (s);		/* application always gets uppercase form */
 96.5160 +	for (i = 0;		/* look in existing table */
 96.5161 +	     (i <= TYPEMAX) && body_types[i] && strcmp (s,body_types[i]); i++);
 96.5162 +	if (i <= TYPEMAX) {	/* only if found a slot */
 96.5163 +	  body->type = i;	/* set body type */
 96.5164 +	  if (body_types[i]) fs_give ((void **) &s);
 96.5165 +	  else body_types[i]=s;	/* assign empty slot */
 96.5166 +	}
 96.5167 +      }
 96.5168 +      if (body->subtype = imap_parse_string(stream,txtptr,reply,NIL,NIL,LONGT))
 96.5169 +	ucase (body->subtype);	/* parse subtype */
 96.5170 +      else {
 96.5171 +	mm_notify (stream,"Missing body subtype",WARN);
 96.5172 +	stream->unhealthy = T;
 96.5173 +	body->subtype = cpystr (rfc822_default_subtype (body->type));
 96.5174 +      }
 96.5175 +      body->parameter = imap_parse_body_parameter (stream,txtptr,reply);
 96.5176 +      body->id = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.5177 +      body->description = imap_parse_string (stream,txtptr,reply,NIL,NIL,
 96.5178 +					     LONGT);
 96.5179 +      if (s = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT)) {
 96.5180 +	ucase (s);		/* application always gets uppercase form */
 96.5181 +	for (i = 0;		/* search for body encoding */
 96.5182 +	     (i <= ENCMAX) && body_encodings[i] && strcmp(s,body_encodings[i]);
 96.5183 +	     i++);
 96.5184 +	if (i > ENCMAX) body->encoding = ENCOTHER;
 96.5185 +	else {			/* only if found a slot */
 96.5186 +	  body->encoding = i;	/* set body encoding */
 96.5187 +	  if (body_encodings[i]) fs_give ((void **) &s);
 96.5188 +				/* assign empty slot */
 96.5189 +	  else body_encodings[i] = s;
 96.5190 +	}
 96.5191 +      }
 96.5192 +				/* parse size of contents in bytes */
 96.5193 +      body->size.bytes = strtoul (*txtptr,(char **) txtptr,10);
 96.5194 +      switch (body->type) {	/* possible extra stuff */
 96.5195 +      case TYPEMESSAGE:		/* message envelope and body */
 96.5196 +				/* non MESSAGE/RFC822 is basic type */
 96.5197 +	if (strcmp (body->subtype,"RFC822")) break;
 96.5198 +	{			/* make certain server sends an envelope */
 96.5199 +	  ENVELOPE *env = NIL;
 96.5200 +	  imap_parse_envelope (stream,&env,txtptr,reply);
 96.5201 +	  if (!env) {
 96.5202 +	    mm_notify (stream,"Missing body message envelope",WARN);
 96.5203 +	    stream->unhealthy = T;
 96.5204 +	    body->subtype = cpystr ("RFC822_MISSING_ENVELOPE");
 96.5205 +	    break;
 96.5206 +	  }
 96.5207 +	  (body->nested.msg = mail_newmsg ())->env = env;
 96.5208 +	}
 96.5209 +	body->nested.msg->body = mail_newbody ();
 96.5210 +	imap_parse_body_structure (stream,body->nested.msg->body,txtptr,reply);
 96.5211 +				/* drop into text case */
 96.5212 +      case TYPETEXT:		/* size in lines */
 96.5213 +	body->size.lines = strtoul (*txtptr,(char **) txtptr,10);
 96.5214 +	break;
 96.5215 +      default:			/* otherwise nothing special */
 96.5216 +	break;
 96.5217 +      }
 96.5218 +
 96.5219 +      if (**txtptr == ' ') {	/* extension data - md5 */
 96.5220 +	body->md5 = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.5221 +	if (LOCAL->cap.extlevel < BODYEXTMD5) LOCAL->cap.extlevel = BODYEXTMD5;
 96.5222 +      }
 96.5223 +      if (**txtptr == ' ') {	/* disposition */
 96.5224 +	imap_parse_disposition (stream,body,txtptr,reply);
 96.5225 +	if (LOCAL->cap.extlevel < BODYEXTDSP) LOCAL->cap.extlevel = BODYEXTDSP;
 96.5226 +      }
 96.5227 +      if (**txtptr == ' ') {	/* language */
 96.5228 +	body->language = imap_parse_language (stream,txtptr,reply);
 96.5229 +	if (LOCAL->cap.extlevel < BODYEXTLANG)
 96.5230 +	  LOCAL->cap.extlevel = BODYEXTLANG;
 96.5231 +      }
 96.5232 +      if (**txtptr == ' ') {	/* location */
 96.5233 +	body->location = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
 96.5234 +	if (LOCAL->cap.extlevel < BODYEXTLOC) LOCAL->cap.extlevel = BODYEXTLOC;
 96.5235 +      }
 96.5236 +      while (**txtptr == ' ') imap_parse_extension (stream,txtptr,reply);
 96.5237 +      if (**txtptr != ')') {	/* validate ending */
 96.5238 +	sprintf (LOCAL->tmp,"Junk at end of body part: %.80s",
 96.5239 +		 (char *) *txtptr);
 96.5240 +	mm_notify (stream,LOCAL->tmp,WARN);
 96.5241 +	stream->unhealthy = T;
 96.5242 +      }
 96.5243 +      else ++*txtptr;		/* skip past delimiter */
 96.5244 +    }
 96.5245 +    break;
 96.5246 +  case 'N':			/* if NIL */
 96.5247 +  case 'n':
 96.5248 +    ++*txtptr;			/* bump past "I" */
 96.5249 +    ++*txtptr;			/* bump past "L" */
 96.5250 +    break;
 96.5251 +  default:			/* otherwise quite bogus */
 96.5252 +    sprintf (LOCAL->tmp,"Bogus body structure: %.80s",(char *) *txtptr);
 96.5253 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.5254 +    stream->unhealthy = T;
 96.5255 +    break;
 96.5256 +  }
 96.5257 +}
 96.5258 +
 96.5259 +/* IMAP parse body parameter
 96.5260 + * Accepts: MAIL stream
 96.5261 + *	    current text pointer
 96.5262 + *	    parsed reply
 96.5263 + * Returns: body parameter
 96.5264 + * Updates text pointer
 96.5265 + */
 96.5266 +
 96.5267 +PARAMETER *imap_parse_body_parameter (MAILSTREAM *stream,
 96.5268 +				      unsigned char **txtptr,
 96.5269 +				      IMAPPARSEDREPLY *reply)
 96.5270 +{
 96.5271 +  PARAMETER *ret = NIL;
 96.5272 +  PARAMETER *par = NIL;
 96.5273 +  char c,*s;
 96.5274 +				/* ignore leading spaces */
 96.5275 +  while ((c = *(*txtptr)++) == ' ');
 96.5276 +				/* parse parameter list */
 96.5277 +  if (c == '(') while (c != ')') {
 96.5278 +				/* append new parameter to tail */
 96.5279 +    if (ret) par = par->next = mail_newbody_parameter ();
 96.5280 +    else ret = par = mail_newbody_parameter ();
 96.5281 +    if(!(par->attribute=imap_parse_string (stream,txtptr,reply,NIL,NIL,
 96.5282 +					   LONGT))) {
 96.5283 +      mm_notify (stream,"Missing parameter attribute",WARN);
 96.5284 +      stream->unhealthy = T;
 96.5285 +      par->attribute = cpystr ("UNKNOWN");
 96.5286 +    }
 96.5287 +    if (!(par->value = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT))){
 96.5288 +      sprintf (LOCAL->tmp,"Missing value for parameter %.80s",par->attribute);
 96.5289 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.5290 +      stream->unhealthy = T;
 96.5291 +      par->value = cpystr ("UNKNOWN");
 96.5292 +    }
 96.5293 +    switch (c = **txtptr) {	/* see what comes after */
 96.5294 +    case ' ':			/* flush whitespace */
 96.5295 +      while ((c = *++*txtptr) == ' ');
 96.5296 +      break;
 96.5297 +    case ')':			/* end of attribute/value pairs */
 96.5298 +      ++*txtptr;		/* skip past closing paren */
 96.5299 +      break;
 96.5300 +    default:
 96.5301 +      sprintf (LOCAL->tmp,"Junk at end of parameter: %.80s",(char *) *txtptr);
 96.5302 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.5303 +      stream->unhealthy = T;
 96.5304 +      break;
 96.5305 +    }
 96.5306 +  }
 96.5307 +				/* empty parameter, must be NIL */
 96.5308 +  else if (((c == 'N') || (c == 'n')) &&
 96.5309 +	   ((*(s = *txtptr) == 'I') || (*s == 'i')) &&
 96.5310 +	   ((s[1] == 'L') || (s[1] == 'l'))) *txtptr += 2;
 96.5311 +  else {
 96.5312 +    sprintf (LOCAL->tmp,"Bogus body parameter: %c%.80s",c,
 96.5313 +	     (char *) (*txtptr) - 1);
 96.5314 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.5315 +    stream->unhealthy = T;
 96.5316 +  }
 96.5317 +  return ret;
 96.5318 +}
 96.5319 +
 96.5320 +/* IMAP parse body disposition
 96.5321 + * Accepts: MAIL stream
 96.5322 + *	    body structure to write into
 96.5323 + *	    current text pointer
 96.5324 + *	    parsed reply
 96.5325 + */
 96.5326 +
 96.5327 +void imap_parse_disposition (MAILSTREAM *stream,BODY *body,
 96.5328 +			     unsigned char **txtptr,IMAPPARSEDREPLY *reply)
 96.5329 +{
 96.5330 +  switch (*++*txtptr) {
 96.5331 +  case '(':
 96.5332 +    ++*txtptr;			/* skip open paren */
 96.5333 +    body->disposition.type = imap_parse_string (stream,txtptr,reply,NIL,NIL,
 96.5334 +						LONGT);
 96.5335 +    body->disposition.parameter =
 96.5336 +      imap_parse_body_parameter (stream,txtptr,reply);
 96.5337 +    if (**txtptr != ')') {	/* validate ending */
 96.5338 +      sprintf (LOCAL->tmp,"Junk at end of disposition: %.80s",
 96.5339 +	       (char *) *txtptr);
 96.5340 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.5341 +      stream->unhealthy = T;
 96.5342 +    }
 96.5343 +    else ++*txtptr;		/* skip past delimiter */
 96.5344 +    break;
 96.5345 +  case 'N':			/* if NIL */
 96.5346 +  case 'n':
 96.5347 +    ++*txtptr;			/* bump past "N" */
 96.5348 +    ++*txtptr;			/* bump past "I" */
 96.5349 +    ++*txtptr;			/* bump past "L" */
 96.5350 +    break;
 96.5351 +  default:
 96.5352 +    sprintf (LOCAL->tmp,"Unknown body disposition: %.80s",(char *) *txtptr);
 96.5353 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.5354 +    stream->unhealthy = T;
 96.5355 +				/* try to skip to next space */
 96.5356 +    while ((*++*txtptr != ' ') && (**txtptr != ')') && **txtptr);
 96.5357 +    break;
 96.5358 +  }
 96.5359 +}
 96.5360 +
 96.5361 +/* IMAP parse body language
 96.5362 + * Accepts: MAIL stream
 96.5363 + *	    current text pointer
 96.5364 + *	    parsed reply
 96.5365 + * Returns: string list or NIL if empty or error
 96.5366 + */
 96.5367 +
 96.5368 +STRINGLIST *imap_parse_language (MAILSTREAM *stream,unsigned char **txtptr,
 96.5369 +				 IMAPPARSEDREPLY *reply)
 96.5370 +{
 96.5371 +  unsigned long i;
 96.5372 +  char *s;
 96.5373 +  STRINGLIST *ret = NIL;
 96.5374 +				/* language is a list */
 96.5375 +  if (*++*txtptr == '(') ret = imap_parse_stringlist (stream,txtptr,reply);
 96.5376 +  else if (s = imap_parse_string (stream,txtptr,reply,NIL,&i,LONGT)) {
 96.5377 +    (ret = mail_newstringlist ())->text.data = (unsigned char *) s;
 96.5378 +    ret->text.size = i;
 96.5379 +  }
 96.5380 +  return ret;
 96.5381 +}
 96.5382 +
 96.5383 +/* IMAP parse string list
 96.5384 + * Accepts: MAIL stream
 96.5385 + *	    current text pointer
 96.5386 + *	    parsed reply
 96.5387 + * Returns: string list or NIL if empty or error
 96.5388 + */
 96.5389 +
 96.5390 +STRINGLIST *imap_parse_stringlist (MAILSTREAM *stream,unsigned char **txtptr,
 96.5391 +				   IMAPPARSEDREPLY *reply)
 96.5392 +{
 96.5393 +  STRINGLIST *stl = NIL;
 96.5394 +  STRINGLIST *stc = NIL;
 96.5395 +  unsigned char *t = *txtptr;
 96.5396 +				/* parse the list */
 96.5397 +  if (*t++ == '(') while (*t != ')') {
 96.5398 +    if (stl) stc = stc->next = mail_newstringlist ();
 96.5399 +    else stc = stl = mail_newstringlist ();
 96.5400 +				/* parse astring */
 96.5401 +    if (!(stc->text.data =
 96.5402 +	  imap_parse_astring (stream,&t,reply,&stc->text.size))) {
 96.5403 +      sprintf (LOCAL->tmp,"Bogus string list member: %.80s",(char *) t);
 96.5404 +      mm_notify (stream,LOCAL->tmp,WARN);
 96.5405 +      stream->unhealthy = T;
 96.5406 +      mail_free_stringlist (&stl);
 96.5407 +      break;
 96.5408 +    }
 96.5409 +    else if (*t == ' ') ++t;	/* another token follows */
 96.5410 +  }
 96.5411 +  if (stl) *txtptr = ++t;	/* update return string */
 96.5412 +  return stl;
 96.5413 +}
 96.5414 +
 96.5415 +/* IMAP parse unknown body extension data
 96.5416 + * Accepts: MAIL stream
 96.5417 + *	    current text pointer
 96.5418 + *	    parsed reply
 96.5419 + *
 96.5420 + * Updates text pointer
 96.5421 + */
 96.5422 +
 96.5423 +void imap_parse_extension (MAILSTREAM *stream,unsigned char **txtptr,
 96.5424 +			   IMAPPARSEDREPLY *reply)
 96.5425 +{
 96.5426 +  unsigned long i,j;
 96.5427 +  switch (*++*txtptr) {		/* action depends upon first character */
 96.5428 +  case '(':
 96.5429 +    while (**txtptr != ')') imap_parse_extension (stream,txtptr,reply);
 96.5430 +    ++*txtptr;			/* bump past closing parenthesis */
 96.5431 +    break;
 96.5432 +  case '"':			/* if quoted string */
 96.5433 +    while (*++*txtptr != '"') if (**txtptr == '\\') ++*txtptr;
 96.5434 +    ++*txtptr;			/* bump past closing quote */
 96.5435 +    break;
 96.5436 +  case 'N':			/* if NIL */
 96.5437 +  case 'n':
 96.5438 +    ++*txtptr;			/* bump past "N" */
 96.5439 +    ++*txtptr;			/* bump past "I" */
 96.5440 +    ++*txtptr;			/* bump past "L" */
 96.5441 +    break;
 96.5442 +  case '{':			/* get size of literal */
 96.5443 +    ++*txtptr;			/* bump past open squiggle */
 96.5444 +    if (i = strtoul (*txtptr,(char **) txtptr,10)) do
 96.5445 +      net_getbuffer (LOCAL->netstream,j = min (i,(long) IMAPTMPLEN - 1),
 96.5446 +		     LOCAL->tmp);
 96.5447 +    while (i -= j);
 96.5448 +				/* get new reply text line */
 96.5449 +    if (!(reply->line = net_getline (LOCAL->netstream)))
 96.5450 +      reply->line = cpystr ("");
 96.5451 +    if (stream->debug) mm_dlog (reply->line);
 96.5452 +    *txtptr = reply->line;	/* set text pointer to point at it */
 96.5453 +    break;
 96.5454 +  case '0': case '1': case '2': case '3': case '4':
 96.5455 +  case '5': case '6': case '7': case '8': case '9':
 96.5456 +    strtoul (*txtptr,(char **) txtptr,10);
 96.5457 +    break;
 96.5458 +  default:
 96.5459 +    sprintf (LOCAL->tmp,"Unknown extension token: %.80s",(char *) *txtptr);
 96.5460 +    mm_notify (stream,LOCAL->tmp,WARN);
 96.5461 +    stream->unhealthy = T;
 96.5462 +				/* try to skip to next space */
 96.5463 +    while ((*++*txtptr != ' ') && (**txtptr != ')') && **txtptr);
 96.5464 +    break;
 96.5465 +  }
 96.5466 +}
 96.5467 +
 96.5468 +/* IMAP parse capabilities
 96.5469 + * Accepts: MAIL stream
 96.5470 + *	    capability list
 96.5471 + */
 96.5472 +
 96.5473 +void imap_parse_capabilities (MAILSTREAM *stream,char *t)
 96.5474 +{
 96.5475 +  char *s,*r;
 96.5476 +  unsigned long i;
 96.5477 +  THREADER *thr,*th;
 96.5478 +  if (!LOCAL->gotcapability) {	/* need to save previous capabilities? */
 96.5479 +				/* no, flush threaders */
 96.5480 +    if (thr = LOCAL->cap.threader) while (th = thr) {
 96.5481 +      fs_give ((void **) &th->name);
 96.5482 +      thr = th->next;
 96.5483 +      fs_give ((void **) &th);
 96.5484 +    }
 96.5485 +				/* zap capabilities */
 96.5486 +    memset (&LOCAL->cap,0,sizeof (LOCAL->cap));
 96.5487 +    LOCAL->gotcapability = T;	/* flag that capabilities arrived */
 96.5488 +  }
 96.5489 +  for (t = strtok_r (t," ",&r); t; t = strtok_r (NIL," ",&r)) {
 96.5490 +    if (!compare_cstring (t,"IMAP4"))
 96.5491 +      LOCAL->cap.imap4 = LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
 96.5492 +    else if (!compare_cstring (t,"IMAP4rev1"))
 96.5493 +      LOCAL->cap.imap4rev1 = LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
 96.5494 +    else if (!compare_cstring (t,"IMAP2")) LOCAL->cap.rfc1176 = T;
 96.5495 +    else if (!compare_cstring (t,"IMAP2bis"))
 96.5496 +      LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
 96.5497 +    else if (!compare_cstring (t,"ACL")) LOCAL->cap.acl = T;
 96.5498 +    else if (!compare_cstring (t,"QUOTA")) LOCAL->cap.quota = T;
 96.5499 +    else if (!compare_cstring (t,"LITERAL+")) LOCAL->cap.litplus = T;
 96.5500 +    else if (!compare_cstring (t,"IDLE")) LOCAL->cap.idle = T;
 96.5501 +    else if (!compare_cstring (t,"MAILBOX-REFERRALS")) LOCAL->cap.mbx_ref = T;
 96.5502 +    else if (!compare_cstring (t,"LOGIN-REFERRALS")) LOCAL->cap.log_ref = T;
 96.5503 +    else if (!compare_cstring (t,"NAMESPACE")) LOCAL->cap.namespace = T;
 96.5504 +    else if (!compare_cstring (t,"UIDPLUS")) LOCAL->cap.uidplus = T;
 96.5505 +    else if (!compare_cstring (t,"STARTTLS")) LOCAL->cap.starttls = T;
 96.5506 +    else if (!compare_cstring (t,"LOGINDISABLED"))LOCAL->cap.logindisabled = T;
 96.5507 +    else if (!compare_cstring (t,"ID")) LOCAL->cap.id = T;
 96.5508 +    else if (!compare_cstring (t,"CHILDREN")) LOCAL->cap.children = T;
 96.5509 +    else if (!compare_cstring (t,"MULTIAPPEND")) LOCAL->cap.multiappend = T;
 96.5510 +    else if (!compare_cstring (t,"BINARY")) LOCAL->cap.binary = T;
 96.5511 +    else if (!compare_cstring (t,"UNSELECT")) LOCAL->cap.unselect = T;
 96.5512 +    else if (!compare_cstring (t,"SASL-IR")) LOCAL->cap.sasl_ir = T;
 96.5513 +    else if (!compare_cstring (t,"SCAN")) LOCAL->cap.scan = T;
 96.5514 +    else if (!compare_cstring (t,"URLAUTH")) LOCAL->cap.urlauth = T;
 96.5515 +    else if (!compare_cstring (t,"CATENATE")) LOCAL->cap.catenate = T;
 96.5516 +    else if (!compare_cstring (t,"CONDSTORE")) LOCAL->cap.condstore = T;
 96.5517 +    else if (!compare_cstring (t,"ESEARCH")) LOCAL->cap.esearch = T;
 96.5518 +    else if (((t[0] == 'S') || (t[0] == 's')) &&
 96.5519 +	     ((t[1] == 'O') || (t[1] == 'o')) &&
 96.5520 +	     ((t[2] == 'R') || (t[2] == 'r')) &&
 96.5521 +	     ((t[3] == 'T') || (t[3] == 't'))) LOCAL->cap.sort = T;
 96.5522 +				/* capability with value? */
 96.5523 +    else if (s = strchr (t,'=')) {
 96.5524 +      *s++ = '\0';		/* separate token from value */
 96.5525 +      if (!compare_cstring (t,"THREAD") && !LOCAL->loser) {
 96.5526 +	THREADER *thread = (THREADER *) fs_get (sizeof (THREADER));
 96.5527 +	thread->name = cpystr (s);
 96.5528 +	thread->dispatch = NIL;
 96.5529 +	thread->next = LOCAL->cap.threader;
 96.5530 +	LOCAL->cap.threader = thread;
 96.5531 +      }
 96.5532 +      else if (!compare_cstring (t,"AUTH")) {
 96.5533 +	if ((i = mail_lookup_auth_name (s,LOCAL->authflags)) &&
 96.5534 +	    (--i < MAXAUTHENTICATORS)) LOCAL->cap.auth |= (1 << i);
 96.5535 +	else if (!compare_cstring (s,"ANONYMOUS")) LOCAL->cap.authanon = T;
 96.5536 +      }
 96.5537 +    }
 96.5538 +				/* ignore other capabilities */
 96.5539 +  }
 96.5540 +				/* disable LOGIN if PLAIN also advertised */
 96.5541 +  if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) &&
 96.5542 +      (LOCAL->cap.auth & (1 << i)) &&
 96.5543 +      (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS))
 96.5544 +    LOCAL->cap.auth &= ~(1 << i);
 96.5545 +}
 96.5546 +
 96.5547 +/* IMAP load cache
 96.5548 + * Accepts: MAIL stream
 96.5549 + *	    sequence
 96.5550 + *	    flags
 96.5551 + * Returns: parsed reply from fetch
 96.5552 + */
 96.5553 +
 96.5554 +IMAPPARSEDREPLY *imap_fetch (MAILSTREAM *stream,char *sequence,long flags)
 96.5555 +{
 96.5556 +  int i = 2;
 96.5557 +  char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ?
 96.5558 +    "UID FETCH" : "FETCH";
 96.5559 +  IMAPARG *args[9],aseq,aarg,aenv,ahhr,axtr,ahtr,abdy,atrl;
 96.5560 +  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
 96.5561 +						     flags & FT_UID);
 96.5562 +  args[0] = &aseq; aseq.type = SEQUENCE; aseq.text = (void *) sequence;
 96.5563 +  args[1] = &aarg; aarg.type = ATOM;
 96.5564 +  aenv.type = ATOM; aenv.text = (void *) "ENVELOPE";
 96.5565 +  ahhr.type = ATOM; ahhr.text = (void *) hdrheader[LOCAL->cap.extlevel];
 96.5566 +  axtr.type = ATOM; axtr.text = (void *) imap_extrahdrs;
 96.5567 +  ahtr.type = ATOM; ahtr.text = (void *) hdrtrailer;
 96.5568 +  abdy.type = ATOM; abdy.text = (void *) "BODYSTRUCTURE";
 96.5569 +  atrl.type = ATOM; atrl.text = (void *) "INTERNALDATE RFC822.SIZE FLAGS)";
 96.5570 +  if (LEVELIMAP4 (stream)) {	/* include UID if IMAP4 or IMAP4rev1 */
 96.5571 +    aarg.text = (void *) "(UID";
 96.5572 +    if (flags & FT_NEEDENV) {	/* if need envelopes */
 96.5573 +      args[i++] = &aenv;	/* include envelope */
 96.5574 +				/* extra header poop if IMAP4rev1 */
 96.5575 +      if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) {
 96.5576 +	args[i++] = &ahhr;	/* header header */
 96.5577 +	if (axtr.text) args[i++] = &axtr;
 96.5578 +	args[i++] = &ahtr;	/* header trailer */
 96.5579 +      }
 96.5580 +				/* fetch body if requested */
 96.5581 +      if (flags & FT_NEEDBODY) args[i++] = &abdy;
 96.5582 +    }
 96.5583 +    args[i++] = &atrl;		/* fetch trailer */
 96.5584 +  }
 96.5585 +				/* easy if IMAP2 */
 96.5586 +  else aarg.text = (void *) (flags & FT_NEEDENV) ?
 96.5587 +    ((flags & FT_NEEDBODY) ?
 96.5588 +     "(RFC822.HEADER BODY INTERNALDATE RFC822.SIZE FLAGS)" :
 96.5589 +     "(RFC822.HEADER INTERNALDATE RFC822.SIZE FLAGS)") : "FAST";
 96.5590 +  args[i] = NIL;		/* tie off command */
 96.5591 +  return imap_send (stream,cmd,args);
 96.5592 +}
 96.5593 +
 96.5594 +/* Reform sequence for losing server that doesn't handle ranges right
 96.5595 + * Accepts: MAIL stream
 96.5596 + *	    sequence
 96.5597 + *	    non-zero if UID
 96.5598 + * Returns: sequence
 96.5599 + */
 96.5600 +
 96.5601 +char *imap_reform_sequence (MAILSTREAM *stream,char *sequence,long flags)
 96.5602 +{
 96.5603 +  unsigned long i,j,star;
 96.5604 +  char *s,*t,*tl,*rs;
 96.5605 +				/* can't win if empty */
 96.5606 +  if (!stream->nmsgs) return sequence;
 96.5607 +				/* get highest possible range value */
 96.5608 +  star = flags ? mail_uid (stream,stream->nmsgs) : stream->nmsgs;
 96.5609 +				/* flush old reformed sequence */
 96.5610 +  if (LOCAL->reform) fs_give ((void **) &LOCAL->reform);
 96.5611 +  rs = LOCAL->reform = (char *) fs_get (1+ strlen (sequence));
 96.5612 +  for (s = sequence; t = strpbrk (s,",:"); ) switch (*t++) {
 96.5613 +  case ',':			/* single message */
 96.5614 +    strncpy (rs,s,i = t - s);	/* copy string up to that point */
 96.5615 +    rs += i;			/* advance destination pointer */
 96.5616 +    s += i;			/* and source */
 96.5617 +    break;
 96.5618 +  case ':':			/* message range */
 96.5619 +    i = (*s == '*') ? star : strtoul (s,NIL,10);
 96.5620 +    if (*t == '*') {		/* range ends with star */
 96.5621 +      j = star;
 96.5622 +      tl = t+1;
 96.5623 +    }
 96.5624 +    else {			/* numeric range end */
 96.5625 +      j = strtoul (t,(char **) &tl,10);
 96.5626 +      if (!tl) tl = t + strlen (t);
 96.5627 +    }
 96.5628 +    if (i <= j) {		/* if first less than second */
 96.5629 +      if (*tl) tl++;		/* skip past end of range if present */
 96.5630 +      strncpy (rs,s,i = tl - s);/* copy string up to that point */
 96.5631 +      rs += i;			/* advance destination and source pointers */
 96.5632 +      s += i;
 96.5633 +    }
 96.5634 +    else {			/* here's the workaround for losing servers */
 96.5635 +      strncpy (rs,t,i = tl - t);/* swap the order */
 96.5636 +      rs[i] = ':';		/* delimit */
 96.5637 +      strncpy (rs+i+1,s,j = (t-1) - s);
 96.5638 +      rs += i + 1 + j;		/* advance destination pointer */
 96.5639 +      if (*tl) *rs++ = *tl++;	/* write trailing delimiter if present */
 96.5640 +      s = tl;			/* advance source pointer */
 96.5641 +    }
 96.5642 +  }
 96.5643 +  if (*s) strcpy (rs,s);	/* write remainder of sequence */
 96.5644 +  else *rs = '\0';		/* tie off string */
 96.5645 +  return LOCAL->reform;
 96.5646 +}
 96.5647 +
 96.5648 +/* IMAP return host name
 96.5649 + * Accepts: MAIL stream
 96.5650 + * Returns: host name
 96.5651 + */
 96.5652 +
 96.5653 +char *imap_host (MAILSTREAM *stream)
 96.5654 +{
 96.5655 +  if (stream->dtb != &imapdriver)
 96.5656 +    fatal ("imap_host called on non-IMAP stream!");
 96.5657 +				/* return host name on stream if open */
 96.5658 +  return (LOCAL && LOCAL->netstream) ? net_host (LOCAL->netstream) :
 96.5659 +    ".NO-IMAP-CONNECTION.";
 96.5660 +}
 96.5661 +
 96.5662 +
 96.5663 +/* IMAP return IMAP capability structure
 96.5664 + * Accepts: MAIL stream
 96.5665 + * Returns: IMAP capability structure
 96.5666 + */
 96.5667 +
 96.5668 +IMAPCAP *imap_cap (MAILSTREAM *stream)
 96.5669 +{
 96.5670 +  if (stream->dtb != &imapdriver)
 96.5671 +    fatal ("imap_cap called on non-IMAP stream!");
 96.5672 +  return &LOCAL->cap;		/* return capability structure */
 96.5673 +}
    97.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    97.2 +++ b/src/c-client/imap4r1.h	Mon Sep 14 15:17:45 2009 +0900
    97.3 @@ -0,0 +1,281 @@
    97.4 +/* ========================================================================
    97.5 + * Copyright 1988-2007 University of Washington
    97.6 + *
    97.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    97.8 + * you may not use this file except in compliance with the License.
    97.9 + * You may obtain a copy of the License at
   97.10 + *
   97.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   97.12 + *
   97.13 + * 
   97.14 + * ========================================================================
   97.15 + */
   97.16 +
   97.17 +/*
   97.18 + * Program:	Interactive Mail Access Protocol 4rev1 (IMAP4R1) routines
   97.19 + *
   97.20 + * Author:	Mark Crispin
   97.21 + *		Networks and Distributed Computing
   97.22 + *		Computing & Communications
   97.23 + *		University of Washington
   97.24 + *		Administration Building, AG-44
   97.25 + *		Seattle, WA  98195
   97.26 + *		Internet: MRC@CAC.Washington.EDU
   97.27 + *
   97.28 + * Date:	14 October 1988
   97.29 + * Last Edited:	5 September 2007
   97.30 + */
   97.31 +
   97.32 +
   97.33 +/* This include file is provided for applications which need to look under
   97.34 + * the covers at the IMAP driver and in particular want to do different
   97.35 + * operations depending upon the IMAP server's protocol level and
   97.36 + * capabilities.  It is NOT included in the normal c-client.h application
   97.37 + * export, and most applications do NOT need the definitions in this file.
   97.38 + *
   97.39 + * As of October 15, 2003, it is believed that:
   97.40 + *
   97.41 + * Version	RFC		Status		Known Implementations
   97.42 + * -------	---		------		---------------------
   97.43 + * IMAP1	none		extinct		experimental TOPS-20 server
   97.44 + * IMAP2	1064		extinct		old TOPS-20, SUMEX servers
   97.45 + * IMAP2	1176		rare		TOPS-20, old UW servers
   97.46 + * IMAP2bis	expired I-D	uncommon	old UW, Cyrus servers
   97.47 + * IMAP3	1203		extinct		none (never implemented)
   97.48 + * IMAP4	1730		rare		old UW, Cyrus, Netscape servers
   97.49 + * IMAP4rev1	2060, 3501	ubiquitous	UW, Cyrus, and many others
   97.50 + *
   97.51 + * Most client implementations will only interoperate with an IMAP4rev1
   97.52 + * server.  c-client based client implementations can interoperate with IMAP2,
   97.53 + * IMAP2bis, IMAP4, and IMAP4rev1 servers, but only if they are very careful.
   97.54 + *
   97.55 + * The LEVELxxx() macros in this file enable the client to determine the
   97.56 + * server protocol level and capabilities.  This file also contains a few
   97.57 + * backdoor calls into the IMAP driver.
   97.58 + */
   97.59 +
   97.60 +/* Server protocol level and capabilities */
   97.61 +
   97.62 +typedef struct imap_cap {
   97.63 +  unsigned int rfc1176 : 1;	/* server is RFC-1176 IMAP2 */
   97.64 +  unsigned int imap2bis : 1;	/* server is IMAP2bis */
   97.65 +  unsigned int imap4 : 1;	/* server is IMAP4 (RFC 1730) */
   97.66 +  unsigned int imap4rev1 : 1;	/* server is IMAP4rev1 */
   97.67 +  unsigned int acl : 1;		/* server has ACL (RFC 2086) */
   97.68 +  unsigned int quota : 1;	/* server has QUOTA (RFC 2087) */
   97.69 +  unsigned int litplus : 1;	/* server has LITERAL+ (RFC 2088) */
   97.70 +  unsigned int idle : 1;	/* server has IDLE (RFC 2177) */
   97.71 +  unsigned int mbx_ref : 1;	/* server has mailbox referrals (RFC 2193) */
   97.72 +  unsigned int log_ref : 1;	/* server has login referrals (RFC 2221) */
   97.73 +  unsigned int authanon : 1;	/* server has anonymous SASL (RFC 2245) */
   97.74 +  unsigned int namespace :1;	/* server has NAMESPACE (RFC 2342) */
   97.75 +  unsigned int uidplus : 1;	/* server has UIDPLUS (RFC 2359) */
   97.76 +  unsigned int starttls : 1;	/* server has STARTTLS (RFC 2595) */
   97.77 +				/* server disallows LOGIN command (RFC 2595) */
   97.78 +  unsigned int logindisabled : 1;
   97.79 +  unsigned int id : 1;		/* server has ID (RFC 2971) */
   97.80 +  unsigned int children : 1;	/* server has CHILDREN (RFC 3348) */
   97.81 +  unsigned int multiappend : 1;	/* server has multi-APPEND (RFC 3502) ;*/
   97.82 +  unsigned int binary : 1;	/* server has BINARY (RFC 3516) */
   97.83 +  unsigned int unselect : 1;	/* server has UNSELECT */
   97.84 +  unsigned int sasl_ir : 1;	/* server has SASL-IR initial response */
   97.85 +  unsigned int sort : 1;	/* server has SORT */
   97.86 +  unsigned int scan : 1;	/* server has SCAN */
   97.87 +  unsigned int urlauth : 1;	/* server has URLAUTH (RFC 4467) */
   97.88 +  unsigned int catenate : 1;	/* server has CATENATE (RFC 4469) */
   97.89 +  unsigned int condstore : 1;	/* server has CONDSTORE (RFC 4551) */
   97.90 +  unsigned int esearch : 1;	/* server has ESEARCH (RFC 4731) */
   97.91 +  unsigned int within : 1;	/* server has WITHIN (RFC 5032) */
   97.92 +  unsigned int extlevel;	/* extension data level supported by server */
   97.93 +				/* supported authenticators */
   97.94 +  unsigned int auth : MAXAUTHENTICATORS;
   97.95 +  THREADER *threader;		/* list of threaders */
   97.96 +} IMAPCAP;
   97.97 +
   97.98 +/* IMAP4rev1 level or better */
   97.99 +
  97.100 +#define LEVELIMAP4rev1(stream) imap_cap (stream)->imap4rev1
  97.101 +
  97.102 +#define LEVELSTATUS LEVELIMAP4rev1
  97.103 +
  97.104 +
  97.105 +/* IMAP4 level or better (not including RFC 1730 design mistakes) */
  97.106 +
  97.107 +#define LEVELIMAP4(stream) (imap_cap (stream)->imap4rev1 || \
  97.108 +			    imap_cap (stream)->imap4)
  97.109 +
  97.110 +
  97.111 +/* IMAP4 RFC-1730 level */
  97.112 +
  97.113 +#define LEVEL1730(stream) imap_cap (stream)->imap4
  97.114 +
  97.115 +
  97.116 +/* IMAP2bis level or better */
  97.117 +
  97.118 +#define LEVELIMAP2bis(stream) imap_cap (stream)->imap2bis
  97.119 +
  97.120 +
  97.121 +/* IMAP2 RFC-1176 level or better */
  97.122 +
  97.123 +#define LEVEL1176(stream) imap_cap (stream)->rfc1176
  97.124 +
  97.125 +
  97.126 +/* IMAP2 RFC-1064 or better */
  97.127 +
  97.128 +#define LEVEL1064(stream) 1
  97.129 +
  97.130 +/* Has ACL extension */
  97.131 +
  97.132 +#define LEVELACL(stream) imap_cap (stream)->acl
  97.133 +
  97.134 +
  97.135 +/* Has QUOTA extension */
  97.136 +
  97.137 +#define LEVELQUOTA(stream) imap_cap (stream)->quota
  97.138 +
  97.139 +
  97.140 +/* Has LITERALPLUS extension */
  97.141 +
  97.142 +#define LEVELLITERALPLUS(stream) imap_cap (stream)->litplus
  97.143 +
  97.144 +
  97.145 +/* Has IDLE extension */
  97.146 +
  97.147 +#define LEVELIDLE(stream) imap_cap (stream)->idle
  97.148 +
  97.149 +
  97.150 +/* Has mailbox referrals */
  97.151 +
  97.152 +#define LEVELMBX_REF(stream) imap_cap (stream)->mbx_ref
  97.153 +
  97.154 +
  97.155 +/* Has login referrals */
  97.156 +
  97.157 +#define LEVELLOG_REF(stream) imap_cap (stream)->log_ref
  97.158 +
  97.159 +
  97.160 +/* Has AUTH=ANONYMOUS extension */
  97.161 +
  97.162 +#define LEVELANONYMOUS(stream) imap_cap (stream)->authanon
  97.163 +
  97.164 +
  97.165 +/* Has NAMESPACE extension */
  97.166 +
  97.167 +#define LEVELNAMESPACE(stream) imap_cap (stream)->namespace
  97.168 +
  97.169 +
  97.170 +/* Has UIDPLUS extension */
  97.171 +
  97.172 +#define LEVELUIDPLUS(stream) imap_cap (stream)->uidplus
  97.173 +
  97.174 +
  97.175 +/* Has STARTTLS extension */
  97.176 +
  97.177 +#define LEVELSTARTTLS(stream) imap_cap (stream)->starttls
  97.178 +
  97.179 +
  97.180 +/* Has LOGINDISABLED extension */
  97.181 +
  97.182 +#define LEVELLOGINDISABLED(stream) imap_cap (stream)->logindisabled
  97.183 +
  97.184 +/* Has ID extension */
  97.185 +
  97.186 +#define LEVELID(stream) imap_cap (stream)->id
  97.187 +
  97.188 +
  97.189 +/* Has CHILDREN extension */
  97.190 +
  97.191 +#define LEVELCHILDREN(stream) imap_cap (stream)->children
  97.192 +
  97.193 +
  97.194 +/* Has MULTIAPPEND extension */
  97.195 +
  97.196 +#define LEVELMULTIAPPEND(stream) imap_cap (stream)->multiappend
  97.197 +
  97.198 +
  97.199 +/* Has BINARY extension */
  97.200 +
  97.201 +#define LEVELBINARY(stream) imap_cap (stream)->binary
  97.202 +
  97.203 +
  97.204 +/* Has UNSELECT extension */
  97.205 +
  97.206 +#define LEVELUNSELECT(stream) imap_cap (stream)->unselect
  97.207 +
  97.208 +
  97.209 +/* Has SASL initial response extension */
  97.210 +
  97.211 +#define LEVELSASLIR(stream) imap_cap (stream)->sasl_ir
  97.212 +
  97.213 +
  97.214 +/* Has SORT extension */
  97.215 +
  97.216 +#define LEVELSORT(stream) imap_cap (stream)->sort
  97.217 +
  97.218 +
  97.219 +/* Has at least one THREAD extension */
  97.220 +
  97.221 +#define LEVELTHREAD(stream) ((imap_cap (stream)->threader) ? T : NIL)
  97.222 +
  97.223 +
  97.224 +/* Has SCAN extension */
  97.225 +
  97.226 +#define LEVELSCAN(stream) imap_cap (stream)->scan
  97.227 +
  97.228 +
  97.229 +/* Has URLAUTH extension */
  97.230 +
  97.231 +#define LEVELURLAUTH(stream) imap_cap (stream)->urlauth
  97.232 +
  97.233 +
  97.234 +/* Has CATENATE extension */
  97.235 +
  97.236 +#define LEVELCATENATE(stream) imap_cap (stream)->catenate
  97.237 +
  97.238 +
  97.239 +/* Has CONDSTORE extension */
  97.240 +
  97.241 +#define LEVELCONDSTORE(stream) imap_cap (stream)->condstore
  97.242 +
  97.243 +
  97.244 +/* Has ESEARCH extension */
  97.245 +
  97.246 +#define LEVELESEARCH(stream) imap_cap (stream)->esearch
  97.247 +
  97.248 +
  97.249 +/* Has WITHIN extension */
  97.250 +
  97.251 +#define LEVELWITHIN(stream) imap_cap (stream)->within
  97.252 +
  97.253 +/* Body structure extension levels */
  97.254 +
  97.255 +/* These are in BODYSTRUCTURE order.  Note that multipart bodies do not have
  97.256 + * body-fld-md5.  This is alright, since all subsequent body structure
  97.257 + * extensions are in both singlepart and multipart bodies.  If that ever
  97.258 + * changes, this will have to be split.
  97.259 + */
  97.260 +
  97.261 +#define BODYEXTMD5 1		/* body-fld-md5 */
  97.262 +#define BODYEXTDSP 2		/* body-fld-dsp */
  97.263 +#define BODYEXTLANG 3		/* body-fld-lang */
  97.264 +#define BODYEXTLOC 4		/* body-fld-loc */
  97.265 +
  97.266 +
  97.267 +/* Function prototypes */
  97.268 +
  97.269 +IMAPCAP *imap_cap (MAILSTREAM *stream);
  97.270 +char *imap_host (MAILSTREAM *stream);
  97.271 +long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg,
  97.272 +		 STRINGLIST *stl,SIZEDTEXT *text);
  97.273 +
  97.274 +
  97.275 +/* Temporary */
  97.276 +
  97.277 +long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights);
  97.278 +long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id);
  97.279 +long imap_getacl (MAILSTREAM *stream,char *mailbox);
  97.280 +long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id);
  97.281 +long imap_myrights (MAILSTREAM *stream,char *mailbox);
  97.282 +long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits);
  97.283 +long imap_getquota (MAILSTREAM *stream,char *qroot);
  97.284 +long imap_getquotaroot (MAILSTREAM *stream,char *mailbox);
    98.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.2 +++ b/src/c-client/mail.c	Mon Sep 14 15:17:45 2009 +0900
    98.3 @@ -0,0 +1,6331 @@
    98.4 +/* ========================================================================
    98.5 + * Copyright 1988-2008 University of Washington
    98.6 + *
    98.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    98.8 + * you may not use this file except in compliance with the License.
    98.9 + * You may obtain a copy of the License at
   98.10 + *
   98.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   98.12 + *
   98.13 + * 
   98.14 + * ========================================================================
   98.15 + */
   98.16 +
   98.17 +/*
   98.18 + * Program:	Mailbox Access routines
   98.19 + *
   98.20 + * Author:	Mark Crispin
   98.21 + *		UW Technology
   98.22 + *		University of Washington
   98.23 + *		Seattle, WA  98195
   98.24 + *		Internet: MRC@Washington.EDU
   98.25 + *
   98.26 + * Date:	22 November 1989
   98.27 + * Last Edited:	15 April 2008
   98.28 + */
   98.29 +
   98.30 +
   98.31 +#include <ctype.h>
   98.32 +#include <stdio.h>
   98.33 +#include <time.h>
   98.34 +#include "c-client.h"
   98.35 +
   98.36 +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";
   98.37 +
   98.38 +/* c-client global data */
   98.39 +
   98.40 +				/* version of this library */
   98.41 +static char *mailcclientversion = CCLIENTVERSION;
   98.42 +				/* list of mail drivers */
   98.43 +static DRIVER *maildrivers = NIL;
   98.44 +				/* list of authenticators */
   98.45 +static AUTHENTICATOR *mailauthenticators = NIL;
   98.46 +				/* SSL driver pointer */
   98.47 +static NETDRIVER *mailssldriver = NIL;
   98.48 +				/* pointer to alternate gets function */
   98.49 +static mailgets_t mailgets = NIL;
   98.50 +				/* pointer to read progress function */
   98.51 +static readprogress_t mailreadprogress = NIL;
   98.52 +				/* mail cache manipulation function */
   98.53 +static mailcache_t mailcache = mm_cache;
   98.54 +				/* RFC-822 output generator */
   98.55 +static rfc822out_t mail822out = NIL;
   98.56 +				/* RFC-822 output generator (new style) */
   98.57 +static rfc822outfull_t mail822outfull = NIL;
   98.58 +				/* SMTP verbose callback */
   98.59 +static smtpverbose_t mailsmtpverbose = mm_dlog;
   98.60 +				/* proxy copy routine */
   98.61 +static mailproxycopy_t mailproxycopy = NIL;
   98.62 +				/* RFC-822 external line parse */
   98.63 +static parseline_t mailparseline = NIL;
   98.64 +				/* RFC-822 external phrase parser */
   98.65 +static parsephrase_t mailparsephrase = NIL;
   98.66 +static kinit_t mailkinit = NIL;	/* application kinit callback */
   98.67 +				/* note network sent command */
   98.68 +static sendcommand_t mailsendcommand = NIL;
   98.69 +				/* newsrc file name decision function */
   98.70 +static newsrcquery_t mailnewsrcquery = NIL;
   98.71 +				/* ACL results callback */
   98.72 +static getacl_t mailaclresults = NIL;
   98.73 +				/* list rights results callback */
   98.74 +static listrights_t maillistrightsresults = NIL;
   98.75 +				/* my rights results callback */
   98.76 +static myrights_t mailmyrightsresults = NIL;
   98.77 +				/* quota results callback */
   98.78 +static quota_t mailquotaresults = NIL;
   98.79 +				/* quota root results callback */
   98.80 +static quotaroot_t mailquotarootresults = NIL;
   98.81 +				/* sorted results callback */
   98.82 +static sortresults_t mailsortresults = NIL;
   98.83 +				/* threaded results callback */
   98.84 +static threadresults_t mailthreadresults = NIL;
   98.85 +				/* COPY UID results */
   98.86 +static copyuid_t mailcopyuid = NIL;
   98.87 +				/* APPEND UID results */
   98.88 +static appenduid_t mailappenduid = NIL;
   98.89 +				/* free elt extra stuff callback */
   98.90 +static freeeltsparep_t mailfreeeltsparep = NIL;
   98.91 +				/* free envelope extra stuff callback */
   98.92 +static freeenvelopesparep_t mailfreeenvelopesparep = NIL;
   98.93 +				/* free body extra stuff callback */
   98.94 +static freebodysparep_t mailfreebodysparep = NIL;
   98.95 +				/* free stream extra stuff callback */
   98.96 +static freestreamsparep_t mailfreestreamsparep = NIL;
   98.97 +				/* SSL start routine */
   98.98 +static sslstart_t mailsslstart = NIL;
   98.99 +				/* SSL certificate query */
  98.100 +static sslcertificatequery_t mailsslcertificatequery = NIL;
  98.101 +				/* SSL client certificate */
  98.102 +static sslclientcert_t mailsslclientcert = NIL;
  98.103 +				/* SSL client private key */
  98.104 +static sslclientkey_t mailsslclientkey = NIL;
  98.105 +				/* SSL failure notify */
  98.106 +static sslfailure_t mailsslfailure = NIL;
  98.107 +				/* snarf interval */
  98.108 +static long mailsnarfinterval = 60;
  98.109 +				/* snarf preservation */
  98.110 +static long mailsnarfpreserve = NIL;
  98.111 +				/* newsrc name uses canonical host */
  98.112 +static long mailnewsrccanon = LONGT;
  98.113 +
  98.114 +				/* supported threaders */
  98.115 +static THREADER mailthreadordsub = {
  98.116 +  "ORDEREDSUBJECT",mail_thread_orderedsubject,NIL
  98.117 +};
  98.118 +static THREADER mailthreadlist = {
  98.119 +  "REFERENCES",mail_thread_references,&mailthreadordsub
  98.120 +};
  98.121 +
  98.122 +				/* server name */
  98.123 +static char *servicename = "unknown";
  98.124 +				/* server externally-set authentication ID */
  98.125 +static char *externalauthid = NIL;
  98.126 +static int expungeatping = T;	/* mail_ping() may call mm_expunged() */
  98.127 +static int trysslfirst = NIL;	/* always try SSL first */
  98.128 +static int notimezones = NIL;	/* write timezones in "From " header */
  98.129 +static int trustdns = T;	/* do DNS canonicalization */
  98.130 +static int saslusesptrname = T;	/* SASL uses name from DNS PTR lookup */
  98.131 +				/* trustdns also must be set */
  98.132 +static int debugsensitive = NIL;/* debug telemetry includes sensitive data */
  98.133 +
  98.134 +/* Default mail cache handler
  98.135 + * Accepts: pointer to cache handle
  98.136 + *	    message number
  98.137 + *	    caching function
  98.138 + * Returns: cache data
  98.139 + */
  98.140 +
  98.141 +void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op)
  98.142 +{
  98.143 +  size_t n;
  98.144 +  void *ret = NIL;
  98.145 +  unsigned long i;
  98.146 +  switch ((int) op) {		/* what function? */
  98.147 +  case CH_INIT:			/* initialize cache */
  98.148 +    if (stream->cache) {	/* flush old cache contents */
  98.149 +      while (stream->cachesize) {
  98.150 +	mm_cache (stream,stream->cachesize,CH_FREE);
  98.151 +	mm_cache (stream,stream->cachesize--,CH_FREESORTCACHE);
  98.152 +      }
  98.153 +      fs_give ((void **) &stream->cache);
  98.154 +      fs_give ((void **) &stream->sc);
  98.155 +      stream->nmsgs = 0;	/* can't have any messages now */
  98.156 +    }
  98.157 +    break;
  98.158 +  case CH_SIZE:			/* (re-)size the cache */
  98.159 +    if (!stream->cache)	{	/* have a cache already? */
  98.160 +				/* no, create new cache */
  98.161 +      n = (stream->cachesize = msgno + CACHEINCREMENT) * sizeof (void *);
  98.162 +      stream->cache = (MESSAGECACHE **) memset (fs_get (n),0,n);
  98.163 +      stream->sc = (SORTCACHE **) memset (fs_get (n),0,n);
  98.164 +    }
  98.165 +				/* is existing cache size large neough */
  98.166 +    else if (msgno > stream->cachesize) {
  98.167 +      i = stream->cachesize;	/* remember old size */
  98.168 +      n = (stream->cachesize = msgno + CACHEINCREMENT) * sizeof (void *);
  98.169 +      fs_resize ((void **) &stream->cache,n);
  98.170 +      fs_resize ((void **) &stream->sc,n);
  98.171 +      while (i < stream->cachesize) {
  98.172 +	stream->cache[i] = NIL;
  98.173 +	stream->sc[i++] = NIL;
  98.174 +      }
  98.175 +    }
  98.176 +    break;
  98.177 +
  98.178 +  case CH_MAKEELT:		/* return elt, make if necessary */
  98.179 +    if (!stream->cache[msgno - 1])
  98.180 +      stream->cache[msgno - 1] = mail_new_cache_elt (msgno);
  98.181 +				/* falls through */
  98.182 +  case CH_ELT:			/* return elt */
  98.183 +    ret = (void *) stream->cache[msgno - 1];
  98.184 +    break;
  98.185 +  case CH_SORTCACHE:		/* return sortcache entry, make if needed */
  98.186 +    if (!stream->sc[msgno - 1]) stream->sc[msgno - 1] =
  98.187 +      (SORTCACHE *) memset (fs_get (sizeof (SORTCACHE)),0,sizeof (SORTCACHE));
  98.188 +    ret = (void *) stream->sc[msgno - 1];
  98.189 +    break;
  98.190 +  case CH_FREE:			/* free elt */
  98.191 +    mail_free_elt (&stream->cache[msgno - 1]);
  98.192 +    break;
  98.193 +  case CH_FREESORTCACHE:
  98.194 +    if (stream->sc[msgno - 1]) {
  98.195 +      if (stream->sc[msgno - 1]->from)
  98.196 +	fs_give ((void **) &stream->sc[msgno - 1]->from);
  98.197 +      if (stream->sc[msgno - 1]->to)
  98.198 +	fs_give ((void **) &stream->sc[msgno - 1]->to);
  98.199 +      if (stream->sc[msgno - 1]->cc)
  98.200 +	fs_give ((void **) &stream->sc[msgno - 1]->cc);
  98.201 +      if (stream->sc[msgno - 1]->subject)
  98.202 +	fs_give ((void **) &stream->sc[msgno - 1]->subject);
  98.203 +      if (stream->sc[msgno - 1]->unique &&
  98.204 +	  (stream->sc[msgno - 1]->unique != stream->sc[msgno - 1]->message_id))
  98.205 +	fs_give ((void **) &stream->sc[msgno - 1]->unique);
  98.206 +      if (stream->sc[msgno - 1]->message_id)
  98.207 +	fs_give ((void **) &stream->sc[msgno - 1]->message_id);
  98.208 +      if (stream->sc[msgno - 1]->references)
  98.209 +	mail_free_stringlist (&stream->sc[msgno - 1]->references);
  98.210 +      fs_give ((void **) &stream->sc[msgno - 1]);
  98.211 +    }
  98.212 +    break;
  98.213 +  case CH_EXPUNGE:		/* expunge cache slot */
  98.214 +    for (i = msgno - 1; msgno < stream->nmsgs; i++,msgno++) {
  98.215 +      if (stream->cache[i] = stream->cache[msgno])
  98.216 +	stream->cache[i]->msgno = msgno;
  98.217 +      stream->sc[i] = stream->sc[msgno];
  98.218 +    }
  98.219 +    stream->cache[i] = NIL;	/* top of cache goes away */
  98.220 +    stream->sc[i] = NIL;
  98.221 +    break;
  98.222 +  default:
  98.223 +    fatal ("Bad mm_cache op");
  98.224 +    break;
  98.225 +  }
  98.226 +  return ret;
  98.227 +}
  98.228 +
  98.229 +/* Dummy string driver for complete in-memory strings */
  98.230 +
  98.231 +static void mail_string_init (STRING *s,void *data,unsigned long size);
  98.232 +static char mail_string_next (STRING *s);
  98.233 +static void mail_string_setpos (STRING *s,unsigned long i);
  98.234 +
  98.235 +STRINGDRIVER mail_string = {
  98.236 +  mail_string_init,		/* initialize string structure */
  98.237 +  mail_string_next,		/* get next byte in string structure */
  98.238 +  mail_string_setpos		/* set position in string structure */
  98.239 +};
  98.240 +
  98.241 +
  98.242 +/* Initialize mail string structure for in-memory string
  98.243 + * Accepts: string structure
  98.244 + *	    pointer to string
  98.245 + *	    size of string
  98.246 + */
  98.247 +
  98.248 +static void mail_string_init (STRING *s,void *data,unsigned long size)
  98.249 +{
  98.250 +				/* set initial string pointers */
  98.251 +  s->chunk = s->curpos = (char *) (s->data = data);
  98.252 +				/* and sizes */
  98.253 +  s->size = s->chunksize = s->cursize = size;
  98.254 +  s->data1 = s->offset = 0;	/* never any offset */
  98.255 +}
  98.256 +
  98.257 +
  98.258 +/* Get next character from string
  98.259 + * Accepts: string structure
  98.260 + * Returns: character, string structure chunk refreshed
  98.261 + */
  98.262 +
  98.263 +static char mail_string_next (STRING *s)
  98.264 +{
  98.265 +  return *s->curpos++;		/* return the last byte */
  98.266 +}
  98.267 +
  98.268 +
  98.269 +/* Set string pointer position
  98.270 + * Accepts: string structure
  98.271 + *	    new position
  98.272 + */
  98.273 +
  98.274 +static void mail_string_setpos (STRING *s,unsigned long i)
  98.275 +{
  98.276 +  s->curpos = s->chunk + i;	/* set new position */
  98.277 +  s->cursize = s->chunksize - i;/* and new size */
  98.278 +}
  98.279 +
  98.280 +/* Mail routines
  98.281 + *
  98.282 + *  mail_xxx routines are the interface between this module and the outside
  98.283 + * world.  Only these routines should be referenced by external callers.
  98.284 + *
  98.285 + *  Note that there is an important difference between a "sequence" and a
  98.286 + * "message #" (msgno).  A sequence is a string representing a sequence in
  98.287 + * {"n", "n:m", or combination separated by commas} format, whereas a msgno
  98.288 + * is a single integer.
  98.289 + *
  98.290 + */
  98.291 +
  98.292 +/* Mail version check
  98.293 + * Accepts: version
  98.294 + */
  98.295 +
  98.296 +void mail_versioncheck (char *version)
  98.297 +{
  98.298 +				/* attempt to protect again wrong .h */
  98.299 +  if (strcmp (version,mailcclientversion)) {
  98.300 +    char tmp[MAILTMPLEN];
  98.301 +    sprintf (tmp,"c-client library version skew, app=%.100s library=%.100s",
  98.302 +	     version,mailcclientversion);
  98.303 +    fatal (tmp);
  98.304 +  }
  98.305 +}
  98.306 +
  98.307 +
  98.308 +/* Mail link driver
  98.309 + * Accepts: driver to add to list
  98.310 + */
  98.311 +
  98.312 +void mail_link (DRIVER *driver)
  98.313 +{
  98.314 +  DRIVER **d = &maildrivers;
  98.315 +  while (*d) d = &(*d)->next;	/* find end of list of drivers */
  98.316 +  *d = driver;			/* put driver at the end */
  98.317 +  driver->next = NIL;		/* this driver is the end of the list */
  98.318 +}
  98.319 +
  98.320 +/* Mail manipulate driver parameters
  98.321 + * Accepts: mail stream
  98.322 + *	    function code
  98.323 + *	    function-dependent value
  98.324 + * Returns: function-dependent return value
  98.325 + */
  98.326 +
  98.327 +void *mail_parameters (MAILSTREAM *stream,long function,void *value)
  98.328 +{
  98.329 +  void *r,*ret = NIL;
  98.330 +  DRIVER *d;
  98.331 +  AUTHENTICATOR *a;
  98.332 +  switch ((int) function) {
  98.333 +  case SET_INBOXPATH:
  98.334 +    fatal ("SET_INBOXPATH not permitted");
  98.335 +  case GET_INBOXPATH:
  98.336 +    if ((stream || (stream = mail_open (NIL,"INBOX",OP_PROTOTYPE))) &&
  98.337 +	stream->dtb) ret = (*stream->dtb->parameters) (function,value);
  98.338 +    break;
  98.339 +  case SET_THREADERS:
  98.340 +    fatal ("SET_THREADERS not permitted");
  98.341 +  case GET_THREADERS:		/* use stream dtb instead of global */
  98.342 +    ret = (stream && stream->dtb) ?
  98.343 +				/* KLUDGE ALERT: note stream passed as value */
  98.344 +      (*stream->dtb->parameters) (function,stream) : (void *) &mailthreadlist;
  98.345 +    break;
  98.346 +  case SET_NAMESPACE:
  98.347 +    fatal ("SET_NAMESPACE not permitted");
  98.348 +    break;
  98.349 +  case SET_NEWSRC:		/* too late on open stream */
  98.350 +    if (stream && stream->dtb && (stream != ((*stream->dtb->open) (NIL))))
  98.351 +      fatal ("SET_NEWSRC not permitted");
  98.352 +    else ret = env_parameters (function,value);
  98.353 +    break;
  98.354 +  case GET_NAMESPACE:
  98.355 +  case GET_NEWSRC:		/* use stream dtb instead of environment */
  98.356 +    ret = (stream && stream->dtb) ?
  98.357 +				/* KLUDGE ALERT: note stream passed as value */
  98.358 +      (*stream->dtb->parameters) (function,stream) :
  98.359 +	env_parameters (function,value);
  98.360 +    break;
  98.361 +  case ENABLE_DEBUG:
  98.362 +    fatal ("ENABLE_DEBUG not permitted");
  98.363 +  case DISABLE_DEBUG:
  98.364 +    fatal ("DISABLE_DEBUG not permitted");
  98.365 +  case SET_DIRFMTTEST:
  98.366 +    fatal ("SET_DIRFMTTEST not permitted");
  98.367 +  case GET_DIRFMTTEST:
  98.368 +    if (!(stream && stream->dtb &&
  98.369 +	  (ret = (*stream->dtb->parameters) (function,NIL))))
  98.370 +      fatal ("GET_DIRFMTTEST not permitted");
  98.371 +    break;
  98.372 +
  98.373 +  case SET_DRIVERS:
  98.374 +    fatal ("SET_DRIVERS not permitted");
  98.375 +  case GET_DRIVERS:		/* always return global */
  98.376 +    ret = (void *) maildrivers;
  98.377 +    break;
  98.378 +  case SET_DRIVER:
  98.379 +    fatal ("SET_DRIVER not permitted");
  98.380 +  case GET_DRIVER:
  98.381 +    for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
  98.382 +	 d = d->next);
  98.383 +    ret = (void *) d;
  98.384 +    break;
  98.385 +  case ENABLE_DRIVER:
  98.386 +    for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
  98.387 +	 d = d->next);
  98.388 +    if (ret = (void *) d) d->flags &= ~DR_DISABLE;
  98.389 +    break;
  98.390 +  case DISABLE_DRIVER:
  98.391 +    for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
  98.392 +	 d = d->next);
  98.393 +    if (ret = (void *) d) d->flags |= DR_DISABLE;
  98.394 +    break;
  98.395 +  case ENABLE_AUTHENTICATOR:
  98.396 +    for (a = mailauthenticators;/* scan authenticators */
  98.397 +	 a && compare_cstring (a->name,(char *) value); a = a->next);
  98.398 +    if (ret = (void *) a) a->flags &= ~AU_DISABLE;
  98.399 +    break;
  98.400 +  case DISABLE_AUTHENTICATOR:
  98.401 +    for (a = mailauthenticators;/* scan authenticators */
  98.402 +	 a && compare_cstring (a->name,(char *) value); a = a->next);
  98.403 +    if (ret = (void *) a) a->flags |= AU_DISABLE;
  98.404 +    break;
  98.405 +  case UNHIDE_AUTHENTICATOR:
  98.406 +    for (a = mailauthenticators;/* scan authenticators */
  98.407 +	 a && compare_cstring (a->name,(char *) value); a = a->next);
  98.408 +    if (ret = (void *) a) a->flags &= ~AU_HIDE;
  98.409 +    break;
  98.410 +  case HIDE_AUTHENTICATOR:
  98.411 +    for (a = mailauthenticators;/* scan authenticators */
  98.412 +	 a && compare_cstring (a->name,(char *) value); a = a->next);
  98.413 +    if (ret = (void *) a) a->flags |= AU_HIDE;
  98.414 +    break;
  98.415 +  case SET_EXTERNALAUTHID:
  98.416 +    if (value) {		/* setting external authentication ID */
  98.417 +      externalauthid = cpystr ((char *) value);
  98.418 +      mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"EXTERNAL");
  98.419 +    }
  98.420 +    else {			/* clearing external authentication ID */
  98.421 +      if (externalauthid) fs_give ((void **) &externalauthid);
  98.422 +      mail_parameters (NIL,HIDE_AUTHENTICATOR,"EXTERNAL");
  98.423 +    }
  98.424 +  case GET_EXTERNALAUTHID:
  98.425 +    ret = (void *) externalauthid;
  98.426 +    break;
  98.427 +
  98.428 +  case SET_GETS:
  98.429 +    mailgets = (mailgets_t) value;
  98.430 +  case GET_GETS:
  98.431 +    ret = (void *) mailgets;
  98.432 +    break;
  98.433 +  case SET_READPROGRESS:
  98.434 +    mailreadprogress = (readprogress_t) value;
  98.435 +  case GET_READPROGRESS:
  98.436 +    ret = (void *) mailreadprogress;
  98.437 +    break;
  98.438 +  case SET_CACHE:
  98.439 +    mailcache = (mailcache_t) value;
  98.440 +  case GET_CACHE:
  98.441 +    ret = (void *) mailcache;
  98.442 +    break;
  98.443 +  case SET_RFC822OUTPUT:
  98.444 +    mail822out = (rfc822out_t) value;
  98.445 +  case GET_RFC822OUTPUT:
  98.446 +    ret = (void *) mail822out;
  98.447 +    break;
  98.448 +  case SET_RFC822OUTPUTFULL:
  98.449 +    mail822outfull = (rfc822outfull_t) value;
  98.450 +  case GET_RFC822OUTPUTFULL:
  98.451 +    ret = (void *) mail822outfull;
  98.452 +    break;
  98.453 +  case SET_SMTPVERBOSE:
  98.454 +    mailsmtpverbose = (smtpverbose_t) value;
  98.455 +  case GET_SMTPVERBOSE:
  98.456 +    ret = (void *) mailsmtpverbose;
  98.457 +    break;
  98.458 +  case SET_MAILPROXYCOPY:
  98.459 +    mailproxycopy = (mailproxycopy_t) value;
  98.460 +  case GET_MAILPROXYCOPY:
  98.461 +    ret = (void *) mailproxycopy;
  98.462 +    break;
  98.463 +  case SET_PARSELINE:
  98.464 +    mailparseline = (parseline_t) value;
  98.465 +  case GET_PARSELINE:
  98.466 +    ret = (void *) mailparseline;
  98.467 +    break;
  98.468 +  case SET_PARSEPHRASE:
  98.469 +    mailparsephrase = (parsephrase_t) value;
  98.470 +  case GET_PARSEPHRASE:
  98.471 +    ret = (void *) mailparsephrase;
  98.472 +    break;
  98.473 +  case SET_NEWSRCQUERY:
  98.474 +    mailnewsrcquery = (newsrcquery_t) value;
  98.475 +  case GET_NEWSRCQUERY:
  98.476 +    ret = (void *) mailnewsrcquery;
  98.477 +    break;
  98.478 +  case SET_NEWSRCCANONHOST:
  98.479 +    mailnewsrccanon = (long) value;
  98.480 +  case GET_NEWSRCCANONHOST:
  98.481 +    ret = (void *) mailnewsrccanon;
  98.482 +    break;
  98.483 +
  98.484 +  case SET_COPYUID:
  98.485 +    mailcopyuid = (copyuid_t) value;
  98.486 +  case GET_COPYUID:
  98.487 +    ret = (void *) mailcopyuid;
  98.488 +    break;
  98.489 +  case SET_APPENDUID:
  98.490 +    mailappenduid = (appenduid_t) value;
  98.491 +  case GET_APPENDUID:
  98.492 +    ret = (void *) mailappenduid;
  98.493 +    break;
  98.494 +  case SET_FREEENVELOPESPAREP:
  98.495 +    mailfreeenvelopesparep = (freeenvelopesparep_t) value;
  98.496 +  case GET_FREEENVELOPESPAREP:
  98.497 +    ret = (void *) mailfreeenvelopesparep;
  98.498 +    break;
  98.499 +  case SET_FREEELTSPAREP:
  98.500 +    mailfreeeltsparep = (freeeltsparep_t) value;
  98.501 +  case GET_FREEELTSPAREP:
  98.502 +    ret = (void *) mailfreeeltsparep;
  98.503 +    break;
  98.504 +  case SET_FREESTREAMSPAREP:
  98.505 +    mailfreestreamsparep = (freestreamsparep_t) value;
  98.506 +  case GET_FREESTREAMSPAREP:
  98.507 +    ret = (void *) mailfreestreamsparep;
  98.508 +    break;
  98.509 +  case SET_FREEBODYSPAREP:
  98.510 +    mailfreebodysparep = (freebodysparep_t) value;
  98.511 +  case GET_FREEBODYSPAREP:
  98.512 +    ret = (void *) mailfreebodysparep;
  98.513 +    break;
  98.514 +
  98.515 +  case SET_SSLSTART:
  98.516 +    mailsslstart = (sslstart_t) value;
  98.517 +  case GET_SSLSTART:
  98.518 +    ret = (void *) mailsslstart;
  98.519 +    break;
  98.520 +  case SET_SSLCERTIFICATEQUERY:
  98.521 +    mailsslcertificatequery = (sslcertificatequery_t) value;
  98.522 +  case GET_SSLCERTIFICATEQUERY:
  98.523 +    ret = (void *) mailsslcertificatequery;
  98.524 +    break;
  98.525 +  case SET_SSLCLIENTCERT:
  98.526 +    mailsslclientcert = (sslclientcert_t) value;
  98.527 +  case GET_SSLCLIENTCERT:
  98.528 +    ret = (void *) mailsslclientcert;
  98.529 +    break;
  98.530 +  case SET_SSLCLIENTKEY:
  98.531 +    mailsslclientkey = (sslclientkey_t) value;
  98.532 +  case GET_SSLCLIENTKEY:
  98.533 +    ret = (void *) mailsslclientkey;
  98.534 +    break;
  98.535 +  case SET_SSLFAILURE:
  98.536 +    mailsslfailure = (sslfailure_t) value;
  98.537 +  case GET_SSLFAILURE:
  98.538 +    ret = (void *) mailsslfailure;
  98.539 +    break;
  98.540 +  case SET_KINIT:
  98.541 +    mailkinit = (kinit_t) value;
  98.542 +  case GET_KINIT:
  98.543 +    ret = (void *) mailkinit;
  98.544 +    break;
  98.545 +  case SET_SENDCOMMAND:
  98.546 +    mailsendcommand = (sendcommand_t) value;
  98.547 +  case GET_SENDCOMMAND:
  98.548 +    ret = (void *) mailsendcommand;
  98.549 +    break;
  98.550 +
  98.551 +  case SET_SERVICENAME:
  98.552 +    servicename = (char *) value;
  98.553 +  case GET_SERVICENAME:
  98.554 +    ret = (void *) servicename;
  98.555 +    break;
  98.556 +  case SET_EXPUNGEATPING:
  98.557 +    expungeatping = (value ? T : NIL);
  98.558 +  case GET_EXPUNGEATPING:
  98.559 +    ret = (void *) (expungeatping ? VOIDT : NIL);
  98.560 +    break;
  98.561 +  case SET_SORTRESULTS:
  98.562 +    mailsortresults = (sortresults_t) value;
  98.563 +  case GET_SORTRESULTS:
  98.564 +    ret = (void *) mailsortresults;
  98.565 +    break;
  98.566 +  case SET_THREADRESULTS:
  98.567 +    mailthreadresults = (threadresults_t) value;
  98.568 +  case GET_THREADRESULTS:
  98.569 +    ret = (void *) mailthreadresults;
  98.570 +    break;
  98.571 +  case SET_SSLDRIVER:
  98.572 +    mailssldriver = (NETDRIVER *) value;
  98.573 +  case GET_SSLDRIVER:
  98.574 +    ret = (void *) mailssldriver;
  98.575 +    break;
  98.576 +  case SET_TRYSSLFIRST:
  98.577 +    trysslfirst = (value ? T : NIL);
  98.578 +  case GET_TRYSSLFIRST:
  98.579 +    ret = (void *) (trysslfirst ? VOIDT : NIL);
  98.580 +    break;
  98.581 +  case SET_NOTIMEZONES:
  98.582 +    notimezones = (value ? T : NIL);
  98.583 +  case GET_NOTIMEZONES:
  98.584 +    ret = (void *) (notimezones ? VOIDT : NIL);
  98.585 +    break;
  98.586 +  case SET_TRUSTDNS:
  98.587 +    trustdns = (value ? T : NIL);
  98.588 +  case GET_TRUSTDNS:
  98.589 +    ret = (void *) (trustdns ? VOIDT : NIL);
  98.590 +    break;
  98.591 +  case SET_SASLUSESPTRNAME:
  98.592 +    saslusesptrname = (value ? T : NIL);
  98.593 +  case GET_SASLUSESPTRNAME:
  98.594 +    ret = (void *) (saslusesptrname ? VOIDT : NIL);
  98.595 +    break;
  98.596 +  case SET_DEBUGSENSITIVE:
  98.597 +    debugsensitive = (value ? T : NIL);
  98.598 +  case GET_DEBUGSENSITIVE:
  98.599 +    ret = (void *) (debugsensitive ? VOIDT : NIL);
  98.600 +    break;
  98.601 +
  98.602 +  case SET_ACL:
  98.603 +    mailaclresults = (getacl_t) value;
  98.604 +  case GET_ACL:
  98.605 +    ret = (void *) mailaclresults;
  98.606 +    break;
  98.607 +  case SET_LISTRIGHTS:
  98.608 +    maillistrightsresults = (listrights_t) value;
  98.609 +  case GET_LISTRIGHTS:
  98.610 +    ret = (void *) maillistrightsresults;
  98.611 +    break;
  98.612 +  case SET_MYRIGHTS:
  98.613 +    mailmyrightsresults = (myrights_t) value;
  98.614 +  case GET_MYRIGHTS:
  98.615 +    ret = (void *) mailmyrightsresults;
  98.616 +    break;
  98.617 +  case SET_QUOTA:
  98.618 +    mailquotaresults = (quota_t) value;
  98.619 +  case GET_QUOTA:
  98.620 +    ret = (void *) mailquotaresults;
  98.621 +    break;
  98.622 +  case SET_QUOTAROOT:
  98.623 +    mailquotarootresults = (quotaroot_t) value;
  98.624 +  case GET_QUOTAROOT:
  98.625 +    ret = (void *) mailquotarootresults;
  98.626 +    break;
  98.627 +  case SET_SNARFINTERVAL:
  98.628 +    mailsnarfinterval = (long) value;
  98.629 +  case GET_SNARFINTERVAL:
  98.630 +    ret = (void *) mailsnarfinterval;
  98.631 +    break;
  98.632 +  case SET_SNARFPRESERVE:
  98.633 +    mailsnarfpreserve = (long) value;
  98.634 +  case GET_SNARFPRESERVE:
  98.635 +    ret = (void *) mailsnarfpreserve;
  98.636 +    break;
  98.637 +  case SET_SNARFMAILBOXNAME:
  98.638 +    if (stream) {		/* have a stream? */
  98.639 +      if (stream->snarf.name) fs_give ((void **) &stream->snarf.name);
  98.640 +      stream->snarf.name = cpystr ((char *) value);
  98.641 +    }
  98.642 +    else fatal ("SET_SNARFMAILBOXNAME with no stream");
  98.643 +  case GET_SNARFMAILBOXNAME:
  98.644 +    if (stream) ret = (void *) stream->snarf.name;
  98.645 +    break;
  98.646 +  default:
  98.647 +    if (r = smtp_parameters (function,value)) ret = r;
  98.648 +    if (r = env_parameters (function,value)) ret = r;
  98.649 +    if (r = tcp_parameters (function,value)) ret = r;
  98.650 +    if (stream && stream->dtb) {/* if have stream, do for its driver only */
  98.651 +      if (r = (*stream->dtb->parameters) (function,value)) ret = r;
  98.652 +    }
  98.653 +				/* else do all drivers */
  98.654 +    else for (d = maildrivers; d; d = d->next)
  98.655 +      if (r = (d->parameters) (function,value)) ret = r;
  98.656 +    break;
  98.657 +  }
  98.658 +  return ret;
  98.659 +}
  98.660 +
  98.661 +/* Mail validate mailbox name
  98.662 + * Accepts: MAIL stream
  98.663 + *	    mailbox name
  98.664 + *	    purpose string for error message
  98.665 + * Return: driver factory on success, NIL on failure
  98.666 + */
  98.667 +
  98.668 +DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose)
  98.669 +{
  98.670 +  char tmp[MAILTMPLEN];
  98.671 +  DRIVER *factory = NIL;
  98.672 +				/* never allow names with newlines */
  98.673 +  if (strpbrk (mailbox,"\015\012")) {
  98.674 +    if (purpose) {		/* if want an error message */
  98.675 +      sprintf (tmp,"Can't %s with such a name",purpose);
  98.676 +      MM_LOG (tmp,ERROR);
  98.677 +    }
  98.678 +    return NIL;
  98.679 +  }
  98.680 +				/* validate name, find driver factory */
  98.681 +  if (strlen (mailbox) < (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50))
  98.682 +    for (factory = maildrivers; factory && 
  98.683 +	 ((factory->flags & DR_DISABLE) ||
  98.684 +	  ((factory->flags & DR_LOCAL) && (*mailbox == '{')) ||
  98.685 +	  !(*factory->valid) (mailbox));
  98.686 +	 factory = factory->next);
  98.687 +				/* validate factory against non-dummy stream */
  98.688 +  if (factory && stream && stream->dtb && (stream->dtb != factory) &&
  98.689 +      strcmp (stream->dtb->name,"dummy"))
  98.690 +				/* factory invalid; if dummy, use stream */
  98.691 +    factory = strcmp (factory->name,"dummy") ? NIL : stream->dtb;
  98.692 +  if (!factory && purpose) {	/* if want an error message */
  98.693 +    sprintf (tmp,"Can't %s %.80s: %s",purpose,mailbox,(*mailbox == '{') ?
  98.694 +	     "invalid remote specification" : "no such mailbox");
  98.695 +    MM_LOG (tmp,ERROR);
  98.696 +  }
  98.697 +  return factory;		/* return driver factory */
  98.698 +}
  98.699 +
  98.700 +/* Mail validate network mailbox name
  98.701 + * Accepts: mailbox name
  98.702 + *	    mailbox driver to validate against
  98.703 + *	    pointer to where to return host name if non-NIL
  98.704 + *	    pointer to where to return mailbox name if non-NIL
  98.705 + * Returns: driver on success, NIL on failure
  98.706 + */
  98.707 +
  98.708 +DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox)
  98.709 +{
  98.710 +  NETMBX mb;
  98.711 +  if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,drv->name))
  98.712 +    return NIL;
  98.713 +  if (host) strcpy (host,mb.host);
  98.714 +  if (mailbox) strcpy (mailbox,mb.mailbox);
  98.715 +  return drv;
  98.716 +}
  98.717 +
  98.718 +
  98.719 +/* Mail validate network mailbox name
  98.720 + * Accepts: mailbox name
  98.721 + *	    NETMBX structure to return values
  98.722 + * Returns: T on success, NIL on failure
  98.723 + */
  98.724 +
  98.725 +long mail_valid_net_parse (char *name,NETMBX *mb)
  98.726 +{
  98.727 +  return mail_valid_net_parse_work (name,mb,"imap");
  98.728 +}
  98.729 +
  98.730 +/* Mail validate network mailbox name worker routine
  98.731 + * Accepts: mailbox name
  98.732 + *	    NETMBX structure to return values
  98.733 + *	    default service
  98.734 + * Returns: T on success, NIL on failure
  98.735 + */
  98.736 +
  98.737 +long mail_valid_net_parse_work (char *name,NETMBX *mb,char *service)
  98.738 +{
  98.739 +  int i,j;
  98.740 +  char c,*s,*t,*v,tmp[MAILTMPLEN],arg[MAILTMPLEN];
  98.741 +				/* initialize structure */
  98.742 +  memset (mb,'\0',sizeof (NETMBX));
  98.743 +				/* must have host specification */
  98.744 +  if (*name++ != '{') return NIL;
  98.745 +  if (*name == '[') {		/* if domain literal, find its ending */
  98.746 +    if (!((v = strpbrk (name,"]}")) && (*v++ == ']'))) return NIL;
  98.747 +  }
  98.748 +				/* find end of host name */
  98.749 +  else if (!(v = strpbrk (name,"/:}"))) return NIL;
  98.750 +				/* validate length, find mailbox part */
  98.751 +  if (!((i = v - name) && (i < NETMAXHOST) && (t = strchr (v,'}')) &&
  98.752 +	((j = t - v) < MAILTMPLEN) && (strlen (t+1) < (size_t) NETMAXMBX)))
  98.753 +    return NIL;			/* invalid mailbox */
  98.754 +  strncpy (mb->host,name,i);	/* set host name */
  98.755 +  strncpy (mb->orighost,name,i);
  98.756 +  mb->host[i] = mb->orighost[i] = '\0';
  98.757 +  strcpy (mb->mailbox,t+1);	/* set mailbox name */
  98.758 +  if (t - v) {			/* any switches or port specification? */
  98.759 +    strncpy (t = tmp,v,j);	/* copy it */
  98.760 +    tmp[j] = '\0';		/* tie it off */
  98.761 +    c = *t++;			/* get first delimiter */
  98.762 +    do switch (c) {		/* act based upon the character */
  98.763 +    case ':':			/* port specification */
  98.764 +      if (mb->port || !(mb->port = strtoul (t,&t,10))) return NIL;
  98.765 +      c = t ? *t++ : '\0';	/* get delimiter, advance pointer */
  98.766 +      break;
  98.767 +    case '/':			/* switch */
  98.768 +				/* find delimiter */
  98.769 +      if (t = strpbrk (s = t,"/:=")) {
  98.770 +	c = *t;			/* remember delimiter for later */
  98.771 +	*t++ = '\0';		/* tie off switch name */
  98.772 +      }
  98.773 +      else c = '\0';		/* no delimiter */
  98.774 +      if (c == '=') {		/* parse switches which take arguments */
  98.775 +	if (*t == '"') {	/* quoted string? */
  98.776 +	  for (v = arg,i = 0,++t; (c = *t++) != '"';) {
  98.777 +	    if (!c) return NIL;	/* unterminated string */
  98.778 +				/* quote next character */
  98.779 +	    if (c == '\\') c = *t++;
  98.780 +	    if (!c) return NIL;	/* can't quote NUL either */
  98.781 +	    arg[i++] = c;
  98.782 +	  }
  98.783 +	  c = *t++;		/* remember delimiter for later */
  98.784 +	  arg[i] = '\0';	/* tie off argument */
  98.785 +	}
  98.786 +	else {			/* non-quoted argument */
  98.787 +	  if (t = strpbrk (v = t,"/:")) {
  98.788 +	    c = *t;		/* remember delimiter for later */
  98.789 +	    *t++ = '\0';	/* tie off switch name */
  98.790 +	  }
  98.791 +	  else c = '\0';	/* no delimiter */
  98.792 +	  i = strlen (v);	/* length of argument */
  98.793 +	}
  98.794 +	if (!compare_cstring (s,"service") && (i < NETMAXSRV) && !*mb->service)
  98.795 +	  lcase (strcpy (mb->service,v));
  98.796 +	else if (!compare_cstring (s,"user") && (i < NETMAXUSER) && !*mb->user)
  98.797 +	  strcpy (mb->user,v);
  98.798 +	else if (!compare_cstring (s,"authuser") && (i < NETMAXUSER) &&
  98.799 +		 !*mb->authuser) strcpy (mb->authuser,v);
  98.800 +	else return NIL;
  98.801 +      }
  98.802 +
  98.803 +      else {			/* non-argument switch */
  98.804 +	if (!compare_cstring (s,"anonymous")) mb->anoflag = T;
  98.805 +	else if (!compare_cstring (s,"debug")) mb->dbgflag = T;
  98.806 +	else if (!compare_cstring (s,"readonly")) mb->readonlyflag = T;
  98.807 +	else if (!compare_cstring (s,"secure")) mb->secflag = T;
  98.808 +	else if (!compare_cstring (s,"norsh")) mb->norsh = T;
  98.809 +	else if (!compare_cstring (s,"loser")) mb->loser = T;
  98.810 +	else if (!compare_cstring (s,"tls") && !mb->notlsflag)
  98.811 +	  mb->tlsflag = T;
  98.812 +	else if (!compare_cstring (s,"tls-sslv23") && !mb->notlsflag)
  98.813 +	  mb->tlssslv23 = mb->tlsflag = T;
  98.814 +	else if (!compare_cstring (s,"notls") && !mb->tlsflag)
  98.815 +	  mb->notlsflag = T;
  98.816 +	else if (!compare_cstring (s,"tryssl"))
  98.817 +	  mb->trysslflag = mailssldriver? T : NIL;
  98.818 +	else if (mailssldriver && !compare_cstring (s,"ssl") && !mb->tlsflag)
  98.819 +	  mb->sslflag = mb->notlsflag = T;
  98.820 +	else if (mailssldriver && !compare_cstring (s,"novalidate-cert"))
  98.821 +	  mb->novalidate = T;
  98.822 +				/* hack for compatibility with the past */
  98.823 +	else if (mailssldriver && !compare_cstring (s,"validate-cert"));
  98.824 +				/* service switches below here */
  98.825 +	else if (*mb->service) return NIL;
  98.826 +	else if (!compare_cstring (s,"imap") ||
  98.827 +		 !compare_cstring (s,"nntp") ||
  98.828 +		 !compare_cstring (s,"pop3") ||
  98.829 +		 !compare_cstring (s,"smtp") ||
  98.830 +		 !compare_cstring (s,"submit"))
  98.831 +	  lcase (strcpy (mb->service,s));
  98.832 +	else if (!compare_cstring (s,"imap2") ||
  98.833 +		 !compare_cstring (s,"imap2bis") ||
  98.834 +		 !compare_cstring (s,"imap4") ||
  98.835 +		 !compare_cstring (s,"imap4rev1"))
  98.836 +	  strcpy (mb->service,"imap");
  98.837 +	else if (!compare_cstring (s,"pop"))
  98.838 +	  strcpy (mb->service,"pop3");
  98.839 +	else return NIL;	/* invalid non-argument switch */
  98.840 +      }
  98.841 +      break;
  98.842 +    default:			/* anything else is bogus */
  98.843 +      return NIL;
  98.844 +    } while (c);		/* see if anything more to parse */
  98.845 +  }
  98.846 +				/* default mailbox name */
  98.847 +  if (!*mb->mailbox) strcpy (mb->mailbox,"INBOX");
  98.848 +				/* default service name */
  98.849 +  if (!*mb->service) strcpy (mb->service,service);
  98.850 +				/* /norsh only valid if imap */
  98.851 +  if (mb->norsh && strcmp (mb->service,"imap")) return NIL;
  98.852 +  return T;
  98.853 +}
  98.854 +
  98.855 +/* Mail scan mailboxes for string
  98.856 + * Accepts: mail stream
  98.857 + *	    reference
  98.858 + *	    pattern to search
  98.859 + *	    contents to search
  98.860 + */
  98.861 +
  98.862 +void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
  98.863 +{
  98.864 +  int remote = ((*pat == '{') || (ref && *ref == '{'));
  98.865 +  DRIVER *d;
  98.866 +  if (ref && (strlen (ref) > NETMAXMBX)) {
  98.867 +    char tmp[MAILTMPLEN];
  98.868 +    sprintf (tmp,"Invalid LIST reference specification: %.80s",ref);
  98.869 +    MM_LOG (tmp,ERROR);
  98.870 +    return;
  98.871 +  }
  98.872 +  if (strlen (pat) > NETMAXMBX) {
  98.873 +    char tmp[MAILTMPLEN];
  98.874 +    sprintf (tmp,"Invalid LIST pattern specification: %.80s",pat);
  98.875 +    MM_LOG (tmp,ERROR);
  98.876 +    return;
  98.877 +  }
  98.878 +  if (*pat == '{') ref = NIL;	/* ignore reference if pattern is remote */
  98.879 +  if (stream) {			/* if have a stream, do it for that stream */
  98.880 +    if ((d = stream->dtb) && d->scan &&
  98.881 +	!(((d->flags & DR_LOCAL) && remote)))
  98.882 +      (*d->scan) (stream,ref,pat,contents);
  98.883 +  }
  98.884 +				/* otherwise do for all DTB's */
  98.885 +  else for (d = maildrivers; d; d = d->next)
  98.886 +    if (d->scan && !((d->flags & DR_DISABLE) ||
  98.887 +		     ((d->flags & DR_LOCAL) && remote)))
  98.888 +      (d->scan) (NIL,ref,pat,contents);
  98.889 +}
  98.890 +
  98.891 +/* Mail list mailboxes
  98.892 + * Accepts: mail stream
  98.893 + *	    reference
  98.894 + *	    pattern to search
  98.895 + */
  98.896 +
  98.897 +void mail_list (MAILSTREAM *stream,char *ref,char *pat)
  98.898 +{
  98.899 +  int remote = ((*pat == '{') || (ref && *ref == '{'));
  98.900 +  DRIVER *d = maildrivers;
  98.901 +  if (ref && (strlen (ref) > NETMAXMBX)) {
  98.902 +    char tmp[MAILTMPLEN];
  98.903 +    sprintf (tmp,"Invalid LIST reference specification: %.80s",ref);
  98.904 +    MM_LOG (tmp,ERROR);
  98.905 +    return;
  98.906 +  }
  98.907 +  if (strlen (pat) > NETMAXMBX) {
  98.908 +    char tmp[MAILTMPLEN];
  98.909 +    sprintf (tmp,"Invalid LIST pattern specification: %.80s",pat);
  98.910 +    MM_LOG (tmp,ERROR);
  98.911 +    return;
  98.912 +  }
  98.913 +  if (*pat == '{') ref = NIL;	/* ignore reference if pattern is remote */
  98.914 +  if (stream && stream->dtb) {	/* if have a stream, do it for that stream */
  98.915 +    if (!(((d = stream->dtb)->flags & DR_LOCAL) && remote))
  98.916 +      (*d->list) (stream,ref,pat);
  98.917 +  }
  98.918 +				/* otherwise do for all DTB's */
  98.919 +  else do if (!((d->flags & DR_DISABLE) ||
  98.920 +		((d->flags & DR_LOCAL) && remote)))
  98.921 +    (d->list) (NIL,ref,pat);
  98.922 +  while (d = d->next);		/* until at the end */
  98.923 +}
  98.924 +
  98.925 +/* Mail list subscribed mailboxes
  98.926 + * Accepts: mail stream
  98.927 + *	    pattern to search
  98.928 + */
  98.929 +
  98.930 +void mail_lsub (MAILSTREAM *stream,char *ref,char *pat)
  98.931 +{
  98.932 +  int remote = ((*pat == '{') || (ref && *ref == '{'));
  98.933 +  DRIVER *d = maildrivers;
  98.934 +  if (ref && (strlen (ref) > NETMAXMBX)) {
  98.935 +    char tmp[MAILTMPLEN];
  98.936 +    sprintf (tmp,"Invalid LSUB reference specification: %.80s",ref);
  98.937 +    MM_LOG (tmp,ERROR);
  98.938 +    return;
  98.939 +  }
  98.940 +  if (strlen (pat) > NETMAXMBX) {
  98.941 +    char tmp[MAILTMPLEN];
  98.942 +    sprintf (tmp,"Invalid LSUB pattern specification: %.80s",pat);
  98.943 +    MM_LOG (tmp,ERROR);
  98.944 +    return;
  98.945 +  }
  98.946 +  if (*pat == '{') ref = NIL;	/* ignore reference if pattern is remote */
  98.947 +  if (stream && stream->dtb) {	/* if have a stream, do it for that stream */
  98.948 +    if (!(((d = stream->dtb)->flags & DR_LOCAL) && remote))
  98.949 +      (*d->lsub) (stream,ref,pat);
  98.950 +  }
  98.951 +				/* otherwise do for all DTB's */
  98.952 +  else do if (!((d->flags & DR_DISABLE) ||
  98.953 +		((d->flags & DR_LOCAL) && remote)))
  98.954 +    (d->lsub) (NIL,ref,pat);
  98.955 +  while (d = d->next);		/* until at the end */
  98.956 +}
  98.957 +
  98.958 +/* Mail subscribe to mailbox
  98.959 + * Accepts: mail stream
  98.960 + *	    mailbox to add to subscription list
  98.961 + * Returns: T on success, NIL on failure
  98.962 + */
  98.963 +
  98.964 +long mail_subscribe (MAILSTREAM *stream,char *mailbox)
  98.965 +{
  98.966 +  DRIVER *factory = mail_valid (stream,mailbox,"subscribe to mailbox");
  98.967 +  return factory ?
  98.968 +    (factory->subscribe ?
  98.969 +     (*factory->subscribe) (stream,mailbox) : sm_subscribe (mailbox)) : NIL;
  98.970 +}
  98.971 +
  98.972 +
  98.973 +/* Mail unsubscribe to mailbox
  98.974 + * Accepts: mail stream
  98.975 + *	    mailbox to delete from subscription list
  98.976 + * Returns: T on success, NIL on failure
  98.977 + */
  98.978 +
  98.979 +long mail_unsubscribe (MAILSTREAM *stream,char *mailbox)
  98.980 +{
  98.981 +  DRIVER *factory = mail_valid (stream,mailbox,NIL);
  98.982 +  return (factory && factory->unsubscribe) ?
  98.983 +    (*factory->unsubscribe) (stream,mailbox) : sm_unsubscribe (mailbox);
  98.984 +}
  98.985 +
  98.986 +/* Mail create mailbox
  98.987 + * Accepts: mail stream
  98.988 + *	    mailbox name to create
  98.989 + * Returns: T on success, NIL on failure
  98.990 + */
  98.991 +
  98.992 +long mail_create (MAILSTREAM *stream,char *mailbox)
  98.993 +{
  98.994 +  MAILSTREAM *ts;
  98.995 +  char *s,*t,tmp[MAILTMPLEN];
  98.996 +  size_t i;
  98.997 +  DRIVER *d;
  98.998 +				/* never allow names with newlines */
  98.999 +  if (s = strpbrk (mailbox,"\015\012")) {
 98.1000 +    MM_LOG ("Can't create mailbox with such a name",ERROR);
 98.1001 +    return NIL;
 98.1002 +  }
 98.1003 +  if (strlen (mailbox) >= (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) {
 98.1004 +    sprintf (tmp,"Can't create %.80s: %s",mailbox,(*mailbox == '{') ?
 98.1005 +	     "invalid remote specification" : "no such mailbox");
 98.1006 +    MM_LOG (tmp,ERROR);
 98.1007 +    return NIL;
 98.1008 +  }
 98.1009 +				/* create of INBOX invalid */
 98.1010 +  if (!compare_cstring (mailbox,"INBOX")) {
 98.1011 +    MM_LOG ("Can't create INBOX",ERROR);
 98.1012 +    return NIL;
 98.1013 +  }
 98.1014 +				/* validate name */
 98.1015 +  if (s = mail_utf7_valid (mailbox)) {
 98.1016 +    sprintf (tmp,"Can't create %s: %.80s",s,mailbox);
 98.1017 +    MM_LOG (tmp,ERROR);
 98.1018 +    return NIL;
 98.1019 +  }
 98.1020 +
 98.1021 +				/* see if special driver hack */
 98.1022 +  if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) &&
 98.1023 +      ((mailbox[2] == 'r') || (mailbox[2] == 'R')) &&
 98.1024 +      ((mailbox[3] == 'i') || (mailbox[3] == 'I')) &&
 98.1025 +      ((mailbox[4] == 'v') || (mailbox[4] == 'V')) &&
 98.1026 +      ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
 98.1027 +      ((mailbox[6] == 'r') || (mailbox[6] == 'R')) && (mailbox[7] == '.')) {
 98.1028 +				/* copy driver until likely delimiter */
 98.1029 +    if ((s = strpbrk (t = mailbox+8,"/\\:")) && (i = s - t)) {
 98.1030 +      strncpy (tmp,t,i);
 98.1031 +      tmp[i] = '\0';
 98.1032 +    } 
 98.1033 +    else {
 98.1034 +      sprintf (tmp,"Can't create mailbox %.80s: bad driver syntax",mailbox);
 98.1035 +      MM_LOG (tmp,ERROR);
 98.1036 +      return NIL;
 98.1037 +    }
 98.1038 +    for (d = maildrivers; d && strcmp (d->name,tmp); d = d->next);
 98.1039 +    if (d) mailbox = ++s;	/* skip past driver specification */
 98.1040 +    else {
 98.1041 +      sprintf (tmp,"Can't create mailbox %.80s: unknown driver",mailbox);
 98.1042 +      MM_LOG (tmp,ERROR);
 98.1043 +      return NIL;
 98.1044 +    }
 98.1045 +  }
 98.1046 +				/* use stream if one given or deterministic */
 98.1047 +  else if ((stream && stream->dtb) ||
 98.1048 +	   (((*mailbox == '{') || (*mailbox == '#')) &&
 98.1049 +	    (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT))))
 98.1050 +    d = stream->dtb;
 98.1051 +  else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb;
 98.1052 +  else {			/* failed utterly */
 98.1053 +    sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox);
 98.1054 +    MM_LOG (tmp,ERROR);
 98.1055 +    return NIL;
 98.1056 +  }
 98.1057 +  return (*d->create) (stream,mailbox);
 98.1058 +}
 98.1059 +
 98.1060 +/* Mail delete mailbox
 98.1061 + * Accepts: mail stream
 98.1062 + *	    mailbox name to delete
 98.1063 + * Returns: T on success, NIL on failure
 98.1064 + */
 98.1065 +
 98.1066 +long mail_delete (MAILSTREAM *stream,char *mailbox)
 98.1067 +{
 98.1068 +  DRIVER *dtb = mail_valid (stream,mailbox,"delete mailbox");
 98.1069 +  if (!dtb) return NIL;
 98.1070 +  if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
 98.1071 +      ((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
 98.1072 +      ((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
 98.1073 +      ((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
 98.1074 +      ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) {
 98.1075 +    MM_LOG ("Can't delete INBOX",ERROR);
 98.1076 +    return NIL;
 98.1077 +  }
 98.1078 +  return SAFE_DELETE (dtb,stream,mailbox);
 98.1079 +}
 98.1080 +
 98.1081 +
 98.1082 +/* Mail rename mailbox
 98.1083 + * Accepts: mail stream
 98.1084 + *	    old mailbox name
 98.1085 + *	    new mailbox name
 98.1086 + * Returns: T on success, NIL on failure
 98.1087 + */
 98.1088 +
 98.1089 +long mail_rename (MAILSTREAM *stream,char *old,char *newname)
 98.1090 +{
 98.1091 +  char *s,tmp[MAILTMPLEN];
 98.1092 +  DRIVER *dtb = mail_valid (stream,old,"rename mailbox");
 98.1093 +  if (!dtb) return NIL;
 98.1094 +				/* validate name */
 98.1095 +  if (s = mail_utf7_valid (newname)) {
 98.1096 +    sprintf (tmp,"Can't rename to %s: %.80s",s,newname);
 98.1097 +    MM_LOG (tmp,ERROR);
 98.1098 +    return NIL;
 98.1099 +  }
 98.1100 +  if ((*old != '{') && (*old != '#') && mail_valid (NIL,newname,NIL)) {
 98.1101 +    sprintf (tmp,"Can't rename %.80s: mailbox %.80s already exists",
 98.1102 +	     old,newname);
 98.1103 +    MM_LOG (tmp,ERROR);
 98.1104 +    return NIL;
 98.1105 +  }
 98.1106 +  return SAFE_RENAME (dtb,stream,old,newname);
 98.1107 +}
 98.1108 +
 98.1109 +/* Validate mailbox as Modified UTF-7
 98.1110 + * Accepts: candidate mailbox name
 98.1111 + * Returns: error string if error, NIL if valid
 98.1112 + */
 98.1113 +
 98.1114 +char *mail_utf7_valid (char *mailbox)
 98.1115 +{
 98.1116 +  char *s;
 98.1117 +  for (s = mailbox; *s; s++) {	/* make sure valid name */
 98.1118 +				/* reserved for future use with UTF-8 */
 98.1119 +    if (*s & 0x80) return "mailbox name with 8-bit octet";
 98.1120 +				/* validate modified UTF-7 */
 98.1121 +    else if (*s == '&') while (*++s != '-') switch (*s) {
 98.1122 +    case '\0':
 98.1123 +      return "unterminated modified UTF-7 name";
 98.1124 +    case '+':			/* valid modified BASE64 */
 98.1125 +    case ',':
 98.1126 +      break;			/* all OK so far */
 98.1127 +    default:			/* must be alphanumeric */
 98.1128 +      if (!isalnum (*s)) return "invalid modified UTF-7 name";
 98.1129 +      break;
 98.1130 +    }
 98.1131 +  }
 98.1132 +  return NIL;			/* all OK */
 98.1133 +}
 98.1134 +
 98.1135 +/* Mail status of mailbox
 98.1136 + * Accepts: mail stream if open on this mailbox
 98.1137 + *	    mailbox name
 98.1138 + *	    status flags
 98.1139 + * Returns: T on success, NIL on failure
 98.1140 + */
 98.1141 +
 98.1142 +long mail_status (MAILSTREAM *stream,char *mbx,long flags)
 98.1143 +{
 98.1144 +  DRIVER *dtb = mail_valid (stream,mbx,"get status of mailbox");
 98.1145 +  if (!dtb) return NIL;		/* only if valid */
 98.1146 +  if (stream && ((dtb != stream->dtb) ||
 98.1147 +		 ((dtb->flags & DR_LOCAL) && strcmp (mbx,stream->mailbox) &&
 98.1148 +		  strcmp (mbx,stream->original_mailbox))))
 98.1149 +    stream = NIL;		/* stream not suitable */
 98.1150 +  return SAFE_STATUS (dtb,stream,mbx,flags);
 98.1151 +}
 98.1152 +
 98.1153 +
 98.1154 +/* Mail status of mailbox default handler
 98.1155 + * Accepts: mail stream
 98.1156 + *	    mailbox name
 98.1157 + *	    status flags
 98.1158 + * Returns: T on success, NIL on failure
 98.1159 + */
 98.1160 +
 98.1161 +long mail_status_default (MAILSTREAM *stream,char *mbx,long flags)
 98.1162 +{
 98.1163 +  MAILSTATUS status;
 98.1164 +  unsigned long i;
 98.1165 +  MAILSTREAM *tstream = NIL;
 98.1166 +				/* make temporary stream (unless this mbx) */
 98.1167 +  if (!stream && !(stream = tstream =
 98.1168 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
 98.1169 +  status.flags = flags;		/* return status values */
 98.1170 +  status.messages = stream->nmsgs;
 98.1171 +  status.recent = stream->recent;
 98.1172 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 98.1173 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 98.1174 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 98.1175 +  status.uidnext = stream->uid_last + 1;
 98.1176 +  status.uidvalidity = stream->uid_validity;
 98.1177 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 98.1178 +  if (tstream) mail_close (tstream);
 98.1179 +  return T;			/* success */
 98.1180 +}
 98.1181 +
 98.1182 +/* Mail open
 98.1183 + * Accepts: candidate stream for recycling
 98.1184 + *	    mailbox name
 98.1185 + *	    open options
 98.1186 + * Returns: stream to use on success, NIL on failure
 98.1187 + */
 98.1188 +
 98.1189 +MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options)
 98.1190 +{
 98.1191 +  int i;
 98.1192 +  char c,*s,tmp[MAILTMPLEN];
 98.1193 +  NETMBX mb;
 98.1194 +  DRIVER *d;
 98.1195 +  switch (name[0]) {		/* see if special handling */
 98.1196 +  case '#':			/* possible special hacks */
 98.1197 +    if (((name[1] == 'M') || (name[1] == 'm')) &&
 98.1198 +	((name[2] == 'O') || (name[2] == 'o')) &&
 98.1199 +	((name[3] == 'V') || (name[3] == 'v')) &&
 98.1200 +	((name[4] == 'E') || (name[4] == 'e')) && (c = name[5]) &&
 98.1201 +	(s = strchr (name+6,c)) && (i = s - (name + 6)) && (i < MAILTMPLEN)) {
 98.1202 +      if (stream = mail_open (stream,s+1,options)) {
 98.1203 +	strncpy (tmp,name+6,i);	/* copy snarf mailbox name */
 98.1204 +	tmp[i] = '\0';		/* tie off name */
 98.1205 +	mail_parameters (stream,SET_SNARFMAILBOXNAME,(void *) tmp);
 98.1206 +	stream->snarf.options = options;
 98.1207 +	mail_ping (stream);	/* do initial snarf */
 98.1208 +				/* punt if can't do initial snarf */
 98.1209 +	if (!stream->snarf.time) stream = mail_close (stream);
 98.1210 +      }
 98.1211 +      return stream;
 98.1212 +    }
 98.1213 +				/* special POP hack */
 98.1214 +    else if (((name[1] == 'P') || (name[1] == 'p')) &&
 98.1215 +	     ((name[2] == 'O') || (name[2] == 'o')) &&
 98.1216 +	     ((name[3] == 'P') || (name[3] == 'p')) &&
 98.1217 +	     mail_valid_net_parse_work (name+4,&mb,"pop3") &&
 98.1218 +	!strcmp (mb.service,"pop3") && !mb.anoflag && !mb.readonlyflag) {
 98.1219 +      if (stream = mail_open (stream,mb.mailbox,options)) {
 98.1220 +	sprintf (tmp,"{%.255s",mb.host);
 98.1221 +	if (mb.port) sprintf (tmp + strlen (tmp),":%lu",mb.port);
 98.1222 +	if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=%.64s",mb.user);
 98.1223 +	if (mb.dbgflag) strcat (tmp,"/debug");
 98.1224 +	if (mb.secflag) strcat (tmp,"/secure");
 98.1225 +	if (mb.tlsflag) strcat (tmp,"/tls");
 98.1226 +	if (mb.notlsflag) strcat (tmp,"/notls");
 98.1227 +	if (mb.sslflag) strcat (tmp,"/ssl");
 98.1228 +	if (mb.trysslflag) strcat (tmp,"/tryssl");
 98.1229 +	if (mb.novalidate) strcat (tmp,"/novalidate-cert");
 98.1230 +	strcat (tmp,"/pop3/loser}");
 98.1231 +	mail_parameters (stream,SET_SNARFMAILBOXNAME,(void *) tmp);
 98.1232 +	mail_ping (stream);	/* do initial snarf */
 98.1233 +      }
 98.1234 +      return stream;		/* return local mailbox stream */
 98.1235 +    }
 98.1236 +
 98.1237 +    else if ((options & OP_PROTOTYPE) &&
 98.1238 +	     ((name[1] == 'D') || (name[1] == 'd')) &&
 98.1239 +	     ((name[2] == 'R') || (name[2] == 'r')) &&
 98.1240 +	     ((name[3] == 'I') || (name[3] == 'i')) &&
 98.1241 +	     ((name[4] == 'V') || (name[4] == 'v')) &&
 98.1242 +	     ((name[5] == 'E') || (name[5] == 'e')) &&
 98.1243 +	     ((name[6] == 'R') || (name[6] == 'r')) && (name[7] == '.')) {
 98.1244 +      sprintf (tmp,"%.80s",name+8);
 98.1245 +				/* tie off name at likely delimiter */
 98.1246 +      if (s = strpbrk (tmp,"/\\:")) *s++ = '\0';
 98.1247 +      else {
 98.1248 +	sprintf (tmp,"Can't resolve mailbox %.80s: bad driver syntax",name);
 98.1249 +	MM_LOG (tmp,ERROR);
 98.1250 +	return mail_close (stream);
 98.1251 +      }
 98.1252 +      for (d = maildrivers; d && compare_cstring (d->name,tmp); d = d->next);
 98.1253 +      if (d) return (*d->open) (NIL);
 98.1254 +      sprintf (tmp,"Can't resolve mailbox %.80s: unknown driver",name);
 98.1255 +      MM_LOG (tmp,ERROR);
 98.1256 +      return mail_close (stream);
 98.1257 +    }
 98.1258 +				/* fall through to default case */
 98.1259 +  default:			/* not special hack (but could be # name */
 98.1260 +    d = mail_valid (NIL,name,(options & OP_SILENT) ?
 98.1261 +		    (char *) NIL : "open mailbox");
 98.1262 +  }
 98.1263 +  return d ? mail_open_work (d,stream,name,options) : stream;
 98.1264 +}
 98.1265 +
 98.1266 +/* Mail open worker routine
 98.1267 + * Accepts: factory
 98.1268 + *	    candidate stream for recycling
 98.1269 + *	    mailbox name
 98.1270 + *	    open options
 98.1271 + * Returns: stream to use on success, NIL on failure
 98.1272 + */
 98.1273 +
 98.1274 +MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name,
 98.1275 +			    long options)
 98.1276 +{
 98.1277 +  int i;
 98.1278 +  char tmp[MAILTMPLEN];
 98.1279 +  NETMBX mb;
 98.1280 +  if (options & OP_PROTOTYPE) return (*d->open) (NIL);
 98.1281 +  /* name is copied here in case the caller does a re-open using
 98.1282 +   * stream->mailbox or stream->original_mailbox as the argument.
 98.1283 +   */
 98.1284 +  name = cpystr (name);		/* make copy of name */
 98.1285 +  if (stream) {			/* recycling requested? */
 98.1286 +    if ((stream->dtb == d) && (d->flags & DR_RECYCLE) &&
 98.1287 +	((d->flags & DR_HALFOPEN) || !(options & OP_HALFOPEN)) &&
 98.1288 +	mail_usable_network_stream (stream,name)) {
 98.1289 +				/* yes, checkpoint if needed */
 98.1290 +      if (d->flags & DR_XPOINT) mail_check (stream);
 98.1291 +      mail_free_cache (stream);	/* clean up stream */
 98.1292 +      if (stream->mailbox) fs_give ((void **) &stream->mailbox);
 98.1293 +      if (stream->original_mailbox)
 98.1294 +	fs_give ((void **) &stream->original_mailbox);
 98.1295 +				/* flush user flags */
 98.1296 +      for (i = 0; i < NUSERFLAGS; i++)
 98.1297 +	if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]);
 98.1298 +    }
 98.1299 +    else {			/* stream not recycleable, babble if net */
 98.1300 +      if (!stream->silent && stream->dtb && !(stream->dtb->flags&DR_LOCAL) &&
 98.1301 +	  mail_valid_net_parse (stream->mailbox,&mb)) {
 98.1302 +	sprintf (tmp,"Closing connection to %.80s",mb.host);
 98.1303 +	MM_LOG (tmp,(long) NIL);
 98.1304 +      }
 98.1305 +				/* flush the old stream */
 98.1306 +      stream = mail_close (stream);
 98.1307 +    }
 98.1308 +  }
 98.1309 +				/* check if driver does not support halfopen */
 98.1310 +  else if ((options & OP_HALFOPEN) && !(d->flags & DR_HALFOPEN)) {
 98.1311 +    fs_give ((void **) &name);
 98.1312 +    return NIL;
 98.1313 +  }
 98.1314 +
 98.1315 +				/* instantiate new stream if not recycling */
 98.1316 +  if (!stream) (*mailcache) (stream = (MAILSTREAM *)
 98.1317 +			     memset (fs_get (sizeof (MAILSTREAM)),0,
 98.1318 +				     sizeof (MAILSTREAM)),(long) 0,CH_INIT);
 98.1319 +  stream->dtb = d;		/* set dispatch */
 98.1320 +				/* set mailbox name */
 98.1321 +  stream->mailbox = cpystr (stream->original_mailbox = name);
 98.1322 +				/* initialize stream flags */
 98.1323 +  stream->inbox = stream->lock = NIL;
 98.1324 +  stream->debug = (options & OP_DEBUG) ? T : NIL;
 98.1325 +  stream->rdonly = (options & OP_READONLY) ? T : NIL;
 98.1326 +  stream->anonymous = (options & OP_ANONYMOUS) ? T : NIL;
 98.1327 +  stream->scache = (options & OP_SHORTCACHE) ? T : NIL;
 98.1328 +  stream->silent = (options & OP_SILENT) ? T : NIL;
 98.1329 +  stream->halfopen = (options & OP_HALFOPEN) ? T : NIL;
 98.1330 +  stream->secure = (options & OP_SECURE) ? T : NIL;
 98.1331 +  stream->tryssl = (options & OP_TRYSSL) ? T : NIL;
 98.1332 +  stream->mulnewsrc = (options & OP_MULNEWSRC) ? T : NIL;
 98.1333 +  stream->nokod = (options & OP_NOKOD) ? T : NIL;
 98.1334 +  stream->sniff = (options & OP_SNIFF) ? T : NIL;
 98.1335 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 98.1336 +    stream->perm_answered = stream->perm_draft = stream->kwd_create = NIL;
 98.1337 +  stream->uid_nosticky = (d->flags & DR_NOSTICKY) ? T : NIL;
 98.1338 +  stream->uid_last = 0;		/* default UID validity */
 98.1339 +  stream->uid_validity = (unsigned long) time (0);
 98.1340 +				/* have driver open, flush if failed */
 98.1341 +  return ((*d->open) (stream)) ? stream : mail_close (stream);
 98.1342 +}
 98.1343 +
 98.1344 +/* Mail close
 98.1345 + * Accepts: mail stream
 98.1346 + *	    close options
 98.1347 + * Returns: NIL, always
 98.1348 + */
 98.1349 +
 98.1350 +MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options)
 98.1351 +{
 98.1352 +  int i;
 98.1353 +  if (stream) {			/* make sure argument given */
 98.1354 +				/* do the driver's close action */
 98.1355 +    if (stream->dtb) (*stream->dtb->close) (stream,options);
 98.1356 +    stream->dtb = NIL;		/* resign driver */
 98.1357 +    if (stream->mailbox) fs_give ((void **) &stream->mailbox);
 98.1358 +    if (stream->original_mailbox)
 98.1359 +      fs_give ((void **) &stream->original_mailbox);
 98.1360 +    if (stream->snarf.name) fs_give ((void **) &stream->snarf.name);
 98.1361 +    stream->sequence++;		/* invalidate sequence */
 98.1362 +				/* flush user flags */
 98.1363 +    for (i = 0; i < NUSERFLAGS; i++)
 98.1364 +      if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]);
 98.1365 +    mail_free_cache (stream);	/* finally free the stream's storage */
 98.1366 +    if (mailfreestreamsparep && stream->sparep)
 98.1367 +      (*mailfreestreamsparep) (&stream->sparep);
 98.1368 +    if (!stream->use) fs_give ((void **) &stream);
 98.1369 +  }
 98.1370 +  return NIL;
 98.1371 +}
 98.1372 +
 98.1373 +/* Mail make handle
 98.1374 + * Accepts: mail stream
 98.1375 + * Returns: handle
 98.1376 + *
 98.1377 + *  Handles provide a way to have multiple pointers to a stream yet allow the
 98.1378 + * stream's owner to nuke it or recycle it.
 98.1379 + */
 98.1380 +
 98.1381 +MAILHANDLE *mail_makehandle (MAILSTREAM *stream)
 98.1382 +{
 98.1383 +  MAILHANDLE *handle = (MAILHANDLE *) fs_get (sizeof (MAILHANDLE));
 98.1384 +  handle->stream = stream;	/* copy stream */
 98.1385 +				/* and its sequence */
 98.1386 +  handle->sequence = stream->sequence;
 98.1387 +  stream->use++;		/* let stream know another handle exists */
 98.1388 +  return handle;
 98.1389 +}
 98.1390 +
 98.1391 +
 98.1392 +/* Mail release handle
 98.1393 + * Accepts: Mail handle
 98.1394 + */
 98.1395 +
 98.1396 +void mail_free_handle (MAILHANDLE **handle)
 98.1397 +{
 98.1398 +  MAILSTREAM *s;
 98.1399 +  if (*handle) {		/* only free if exists */
 98.1400 +				/* resign stream, flush unreferenced zombies */
 98.1401 +    if ((!--(s = (*handle)->stream)->use) && !s->dtb) fs_give ((void **) &s);
 98.1402 +    fs_give ((void **) handle);	/* now flush the handle */
 98.1403 +  }
 98.1404 +}
 98.1405 +
 98.1406 +
 98.1407 +/* Mail get stream handle
 98.1408 + * Accepts: Mail handle
 98.1409 + * Returns: mail stream or NIL if stream gone
 98.1410 + */
 98.1411 +
 98.1412 +MAILSTREAM *mail_stream (MAILHANDLE *handle)
 98.1413 +{
 98.1414 +  MAILSTREAM *s = handle->stream;
 98.1415 +  return (s->dtb && (handle->sequence == s->sequence)) ? s : NIL;
 98.1416 +}
 98.1417 +
 98.1418 +/* Mail fetch cache element
 98.1419 + * Accepts: mail stream
 98.1420 + *	    message # to fetch
 98.1421 + * Returns: cache element of this message
 98.1422 + * Can also be used to create cache elements for new messages.
 98.1423 + */
 98.1424 +
 98.1425 +MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno)
 98.1426 +{
 98.1427 +  if (msgno < 1 || msgno > stream->nmsgs) {
 98.1428 +    char tmp[MAILTMPLEN];
 98.1429 +    sprintf (tmp,"Bad msgno %lu in mail_elt, nmsgs = %lu, mbx=%.80s",
 98.1430 +	     msgno,stream->nmsgs,stream->mailbox ? stream->mailbox : "???");
 98.1431 +    fatal (tmp);
 98.1432 +  }
 98.1433 +  return (MESSAGECACHE *) (*mailcache) (stream,msgno,CH_MAKEELT);
 98.1434 +}
 98.1435 +
 98.1436 +
 98.1437 +/* Mail fetch fast information
 98.1438 + * Accepts: mail stream
 98.1439 + *	    sequence
 98.1440 + *	    option flags
 98.1441 + *
 98.1442 + * Generally, mail_fetch_structure is preferred
 98.1443 + */
 98.1444 +
 98.1445 +void mail_fetch_fast (MAILSTREAM *stream,char *sequence,long flags)
 98.1446 +{
 98.1447 +  				/* do the driver's action */
 98.1448 +  if (stream->dtb && stream->dtb->fast)
 98.1449 +    (*stream->dtb->fast) (stream,sequence,flags);
 98.1450 +}
 98.1451 +
 98.1452 +
 98.1453 +/* Mail fetch flags
 98.1454 + * Accepts: mail stream
 98.1455 + *	    sequence
 98.1456 + *	    option flags
 98.1457 + */
 98.1458 +
 98.1459 +void mail_fetch_flags (MAILSTREAM *stream,char *sequence,long flags)
 98.1460 +{
 98.1461 +  				/* do the driver's action */
 98.1462 +  if (stream->dtb && stream->dtb->msgflags)
 98.1463 +    (*stream->dtb->msgflags) (stream,sequence,flags);
 98.1464 +}
 98.1465 +
 98.1466 +/* Mail fetch message overview
 98.1467 + * Accepts: mail stream
 98.1468 + *	    UID sequence to fetch
 98.1469 + *	    pointer to overview return function
 98.1470 + */
 98.1471 +
 98.1472 +void mail_fetch_overview (MAILSTREAM *stream,char *sequence,overview_t ofn)
 98.1473 +{
 98.1474 +  if (stream->dtb && mail_uid_sequence (stream,sequence) &&
 98.1475 +      !(stream->dtb->overview && (*stream->dtb->overview) (stream,ofn)) &&
 98.1476 +      mail_ping (stream))
 98.1477 +    mail_fetch_overview_default (stream,ofn);
 98.1478 +}
 98.1479 +
 98.1480 +
 98.1481 +/* Mail fetch message overview using sequence numbers instead of UIDs
 98.1482 + * Accepts: mail stream
 98.1483 + *	    sequence to fetch
 98.1484 + *	    pointer to overview return function
 98.1485 + */
 98.1486 +
 98.1487 +void mail_fetch_overview_sequence (MAILSTREAM *stream,char *sequence,
 98.1488 +				   overview_t ofn)
 98.1489 +{
 98.1490 +  if (stream->dtb && mail_sequence (stream,sequence) &&
 98.1491 +      !(stream->dtb->overview && (*stream->dtb->overview) (stream,ofn)) &&
 98.1492 +      mail_ping (stream))
 98.1493 +    mail_fetch_overview_default (stream,ofn);
 98.1494 +}
 98.1495 +
 98.1496 +
 98.1497 +/* Mail fetch message overview default handler
 98.1498 + * Accepts: mail stream with sequence bits lit
 98.1499 + *	    pointer to overview return function
 98.1500 + */
 98.1501 +
 98.1502 +void mail_fetch_overview_default (MAILSTREAM *stream,overview_t ofn)
 98.1503 +{
 98.1504 +  MESSAGECACHE *elt;
 98.1505 +  ENVELOPE *env;
 98.1506 +  OVERVIEW ov;
 98.1507 +  unsigned long i;
 98.1508 +  ov.optional.lines = 0;
 98.1509 +  ov.optional.xref = NIL;
 98.1510 +  for (i = 1; i <= stream->nmsgs; i++)
 98.1511 +    if (((elt = mail_elt (stream,i))->sequence) &&
 98.1512 +	(env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) {
 98.1513 +      ov.subject = env->subject;
 98.1514 +      ov.from = env->from;
 98.1515 +      ov.date = env->date;
 98.1516 +      ov.message_id = env->message_id;
 98.1517 +      ov.references = env->references;
 98.1518 +      ov.optional.octets = elt->rfc822_size;
 98.1519 +      (*ofn) (stream,mail_uid (stream,i),&ov,i);
 98.1520 +    }
 98.1521 +}
 98.1522 +
 98.1523 +/* Mail fetch message structure
 98.1524 + * Accepts: mail stream
 98.1525 + *	    message # to fetch
 98.1526 + *	    pointer to return body
 98.1527 + *	    option flags
 98.1528 + * Returns: envelope of this message, body returned in body value
 98.1529 + *
 98.1530 + * Fetches the "fast" information as well
 98.1531 + */
 98.1532 +
 98.1533 +ENVELOPE *mail_fetch_structure (MAILSTREAM *stream,unsigned long msgno,
 98.1534 +				BODY **body,long flags)
 98.1535 +{
 98.1536 +  ENVELOPE **env;
 98.1537 +  BODY **b;
 98.1538 +  MESSAGECACHE *elt;
 98.1539 +  char c,*s,*hdr;
 98.1540 +  unsigned long hdrsize;
 98.1541 +  STRING bs;
 98.1542 +				/* do the driver's action if specified */
 98.1543 +  if (stream->dtb && stream->dtb->structure)
 98.1544 +    return (*stream->dtb->structure) (stream,msgno,body,flags);
 98.1545 +  if (flags & FT_UID) {		/* UID form of call */
 98.1546 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.1547 +    else return NIL;		/* must get UID/msgno map first */
 98.1548 +  }
 98.1549 +  elt = mail_elt (stream,msgno);/* get elt for real message number */
 98.1550 +  if (stream->scache) {		/* short caching */
 98.1551 +    if (msgno != stream->msgno){/* garbage collect if not same message */
 98.1552 +      mail_gc (stream,GC_ENV | GC_TEXTS);
 98.1553 +      stream->msgno = msgno;	/* this is the current message now */
 98.1554 +    }
 98.1555 +    env = &stream->env;		/* get pointers to envelope and body */
 98.1556 +    b = &stream->body;
 98.1557 +  }
 98.1558 +  else {			/* get pointers to elt envelope and body */
 98.1559 +    env = &elt->private.msg.env;
 98.1560 +    b = &elt->private.msg.body;
 98.1561 +  }
 98.1562 +
 98.1563 +  if (stream->dtb && ((body && !*b) || !*env || (*env)->incomplete)) {
 98.1564 +    mail_free_envelope (env);	/* flush old envelope and body */
 98.1565 +    mail_free_body (b);
 98.1566 +				/* see if need to fetch the whole thing */
 98.1567 +    if (body || !elt->rfc822_size) {
 98.1568 +      s = (*stream->dtb->header) (stream,msgno,&hdrsize,flags & ~FT_INTERNAL);
 98.1569 +				/* make copy in case body fetch smashes it */
 98.1570 +      hdr = (char *) memcpy (fs_get ((size_t) hdrsize+1),s,(size_t) hdrsize);
 98.1571 +      hdr[hdrsize] = '\0';	/* tie off header */
 98.1572 +      (*stream->dtb->text) (stream,msgno,&bs,(flags & ~FT_INTERNAL) | FT_PEEK);
 98.1573 +      if (!elt->rfc822_size) elt->rfc822_size = hdrsize + SIZE (&bs);
 98.1574 +      if (body)			/* only parse body if requested */
 98.1575 +	rfc822_parse_msg (env,b,hdr,hdrsize,&bs,BADHOST,stream->dtb->flags);
 98.1576 +      else
 98.1577 +	rfc822_parse_msg (env,NIL,hdr,hdrsize,NIL,BADHOST,stream->dtb->flags);
 98.1578 +      fs_give ((void **) &hdr);	/* flush header */
 98.1579 +    }
 98.1580 +    else {			/* can save memory doing it this way */
 98.1581 +      hdr = (*stream->dtb->header) (stream,msgno,&hdrsize,flags | FT_INTERNAL);
 98.1582 +      if (hdrsize) {		/* in case null header */
 98.1583 +	c = hdr[hdrsize];	/* preserve what's there */
 98.1584 +	hdr[hdrsize] = '\0';	/* tie off header */
 98.1585 +	rfc822_parse_msg (env,NIL,hdr,hdrsize,NIL,BADHOST,stream->dtb->flags);
 98.1586 +	hdr[hdrsize] = c;	/* restore in case cached data */
 98.1587 +      }
 98.1588 +      else *env = mail_newenvelope ();
 98.1589 +    }
 98.1590 +  }
 98.1591 +				/* if need date, have date in envelope? */
 98.1592 +  if (!elt->day && *env && (*env)->date) mail_parse_date (elt,(*env)->date);
 98.1593 +				/* sigh, fill in bogus default */
 98.1594 +  if (!elt->day) elt->day = elt->month = 1;
 98.1595 +  if (body) *body = *b;		/* return the body */
 98.1596 +  return *env;			/* return the envelope */
 98.1597 +}
 98.1598 +
 98.1599 +/* Mail mark single message (internal use only)
 98.1600 + * Accepts: mail stream
 98.1601 + *	    elt to mark
 98.1602 + *	    fetch flags
 98.1603 + */
 98.1604 +
 98.1605 +static void markseen (MAILSTREAM *stream,MESSAGECACHE *elt,long flags)
 98.1606 +{
 98.1607 +  unsigned long i;
 98.1608 +  char sequence[20];
 98.1609 +  MESSAGECACHE *e;
 98.1610 +				/* non-peeking and needs to set \Seen? */
 98.1611 +  if (!(flags & FT_PEEK) && !elt->seen) {
 98.1612 +    if (stream->dtb->flagmsg){	/* driver wants per-message call? */
 98.1613 +      elt->valid = NIL;		/* do pre-alteration driver call */
 98.1614 +      (*stream->dtb->flagmsg) (stream,elt);
 98.1615 +				/* set seen, do post-alteration driver call */
 98.1616 +      elt->seen = elt->valid = T;
 98.1617 +      (*stream->dtb->flagmsg) (stream,elt);
 98.1618 +    }
 98.1619 +    if (stream->dtb->flag) {	/* driver wants one-time call?  */
 98.1620 +				/* better safe than sorry, save seq bits */
 98.1621 +      for (i = 1; i <= stream->nmsgs; i++) {
 98.1622 +	e = mail_elt (stream,i);
 98.1623 +	e->private.sequence = e->sequence;
 98.1624 +      }
 98.1625 +				/* call driver to set the message */
 98.1626 +      sprintf (sequence,"%lu",elt->msgno);
 98.1627 +      (*stream->dtb->flag) (stream,sequence,"\\Seen",ST_SET);
 98.1628 +				/* restore sequence bits */
 98.1629 +      for (i = 1; i <= stream->nmsgs; i++) {
 98.1630 +	e = mail_elt (stream,i);
 98.1631 +	e->sequence = e->private.sequence;
 98.1632 +      }
 98.1633 +    }
 98.1634 +				/* notify mail program of flag change */
 98.1635 +    MM_FLAGS (stream,elt->msgno);
 98.1636 +  }
 98.1637 +}
 98.1638 +
 98.1639 +/* Mail fetch message
 98.1640 + * Accepts: mail stream
 98.1641 + *	    message # to fetch
 98.1642 + *	    pointer to returned length
 98.1643 + *	    flags
 98.1644 + * Returns: message text
 98.1645 + */
 98.1646 +
 98.1647 +char *mail_fetch_message (MAILSTREAM *stream,unsigned long msgno,
 98.1648 +			  unsigned long *len,long flags)
 98.1649 +{
 98.1650 +  GETS_DATA md;
 98.1651 +  SIZEDTEXT *t;
 98.1652 +  STRING bs;
 98.1653 +  MESSAGECACHE *elt;
 98.1654 +  char *s,*u;
 98.1655 +  unsigned long i,j;
 98.1656 +  if (len) *len = 0;		/* default return size */
 98.1657 +  if (flags & FT_UID) {		/* UID form of call */
 98.1658 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.1659 +    else return "";		/* must get UID/msgno map first */
 98.1660 +  }
 98.1661 +				/* initialize message data identifier */
 98.1662 +  INIT_GETS (md,stream,msgno,"",0,0);
 98.1663 +				/* is data already cached? */
 98.1664 +  if ((t = &(elt = mail_elt (stream,msgno))->private.msg.full.text)->data) {
 98.1665 +    markseen (stream,elt,flags);/* mark message seen */
 98.1666 +    return mail_fetch_text_return (&md,t,len);
 98.1667 +  }
 98.1668 +  if (!stream->dtb) return "";	/* not in cache, must have live driver */
 98.1669 +  if (stream->dtb->msgdata) return
 98.1670 +    ((*stream->dtb->msgdata) (stream,msgno,"",0,0,NIL,flags) && t->data) ?
 98.1671 +      mail_fetch_text_return (&md,t,len) : "";
 98.1672 +				/* ugh, have to do this the crufty way */
 98.1673 +  u = mail_fetch_header (stream,msgno,NIL,NIL,&i,flags);
 98.1674 +				/* copy in case text method stomps on it */
 98.1675 +  s = (char *) memcpy (fs_get ((size_t) i),u,(size_t) i);
 98.1676 +  if ((*stream->dtb->text) (stream,msgno,&bs,flags)) {
 98.1677 +    t = &stream->text;		/* build combined copy */
 98.1678 +    if (t->data) fs_give ((void **) &t->data);
 98.1679 +    t->data = (unsigned char *) fs_get ((t->size = i + SIZE (&bs)) + 1);
 98.1680 +    if (!elt->rfc822_size) elt->rfc822_size = t->size;
 98.1681 +    else if (elt->rfc822_size != t->size) {
 98.1682 +      char tmp[MAILTMPLEN];
 98.1683 +      sprintf (tmp,"Calculated RFC822.SIZE (%lu) != reported size (%lu)",
 98.1684 +	       t->size,elt->rfc822_size);
 98.1685 +      mm_log (tmp,WARN);	/* bug trap */
 98.1686 +    }
 98.1687 +    memcpy (t->data,s,(size_t) i);
 98.1688 +    for (u = (char *) t->data + i, j = SIZE (&bs); j;) {
 98.1689 +      memcpy (u,bs.curpos,bs.cursize);
 98.1690 +      u += bs.cursize;		/* update text */
 98.1691 +      j -= bs.cursize;
 98.1692 +      bs.curpos += (bs.cursize -1);
 98.1693 +      bs.cursize = 0;
 98.1694 +      (*bs.dtb->next) (&bs);	/* advance to next buffer's worth */
 98.1695 +    } 
 98.1696 +    *u = '\0';			/* tie off data */
 98.1697 +    u = mail_fetch_text_return (&md,t,len);
 98.1698 +  }
 98.1699 +  else u = "";
 98.1700 +  fs_give ((void **) &s);	/* finished with copy of header */
 98.1701 +  return u;
 98.1702 +}
 98.1703 +
 98.1704 +/* Mail fetch message header
 98.1705 + * Accepts: mail stream
 98.1706 + *	    message # to fetch
 98.1707 + *	    MIME section specifier (#.#.#...#)
 98.1708 + *	    list of lines to fetch
 98.1709 + *	    pointer to returned length
 98.1710 + *	    flags
 98.1711 + * Returns: message header in RFC822 format
 98.1712 + *
 98.1713 + * Note: never calls a mailgets routine
 98.1714 + */
 98.1715 +
 98.1716 +char *mail_fetch_header (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.1717 +			 STRINGLIST *lines,unsigned long *len,long flags)
 98.1718 +{
 98.1719 +  STRING bs;
 98.1720 +  BODY *b = NIL;
 98.1721 +  SIZEDTEXT *t = NIL,rt;
 98.1722 +  MESSAGE *m = NIL;
 98.1723 +  MESSAGECACHE *elt;
 98.1724 +  char tmp[MAILTMPLEN];
 98.1725 +  if (len) *len = 0;		/* default return size */
 98.1726 +  if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
 98.1727 +  if (flags & FT_UID) {		/* UID form of call */
 98.1728 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.1729 +    else return "";		/* must get UID/msgno map first */
 98.1730 +  }
 98.1731 +  elt = mail_elt (stream,msgno);/* get cache data */
 98.1732 +  if (section && *section) {	/* nested body header wanted? */
 98.1733 +    if (!((b = mail_body (stream,msgno,section)) &&
 98.1734 +	  (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
 98.1735 +      return "";		/* lose if no body or not MESSAGE/RFC822 */
 98.1736 +    m = b->nested.msg;		/* point to nested message */
 98.1737 +  }
 98.1738 +				/* else top-level message header wanted */
 98.1739 +  else m = &elt->private.msg;
 98.1740 +  if (m->header.text.data && mail_match_lines (lines,m->lines,flags)) {
 98.1741 +    if (lines) textcpy (t = &stream->text,&m->header.text);
 98.1742 +    else t = &m->header.text;	/* in cache, and cache is valid */
 98.1743 +    markseen (stream,elt,flags);/* mark message seen */
 98.1744 +  }
 98.1745 +
 98.1746 +  else if (stream->dtb) {	/* not in cache, has live driver? */
 98.1747 +    if (stream->dtb->msgdata) {	/* has driver section fetch? */
 98.1748 +				/* build driver section specifier */
 98.1749 +      if (section && *section) sprintf (tmp,"%s.HEADER",section);
 98.1750 +      else strcpy (tmp,"HEADER");
 98.1751 +      if ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,lines,flags)) {
 98.1752 +	t = &m->header.text;	/* fetch data */
 98.1753 +				/* don't need to postprocess lines */
 98.1754 +	if (m->lines) lines = NIL;
 98.1755 +	else if (lines) textcpy (t = &stream->text,&m->header.text);
 98.1756 +      }
 98.1757 +    }
 98.1758 +    else if (b) {		/* nested body wanted? */
 98.1759 +      if (stream->private.search.text) {
 98.1760 +	rt.data = (unsigned char *) stream->private.search.text +
 98.1761 +	  b->nested.msg->header.offset;
 98.1762 +	rt.size = b->nested.msg->header.text.size;
 98.1763 +	t = &rt;
 98.1764 +      }
 98.1765 +      else if ((*stream->dtb->text) (stream,msgno,&bs,flags & ~FT_INTERNAL)) {
 98.1766 +	if ((bs.dtb->next == mail_string_next) && !lines) {
 98.1767 +	  rt.data = (unsigned char *) bs.curpos + b->nested.msg->header.offset;
 98.1768 +	  rt.size = b->nested.msg->header.text.size;
 98.1769 +	  if (stream->private.search.string)
 98.1770 +	    stream->private.search.text = bs.curpos;
 98.1771 +	  t = &rt;		/* special hack to avoid extra copy */
 98.1772 +	}
 98.1773 +	else textcpyoffstring (t = &stream->text,&bs,
 98.1774 +			       b->nested.msg->header.offset,
 98.1775 +			       b->nested.msg->header.text.size);
 98.1776 +      }
 98.1777 +    }
 98.1778 +    else {			/* top-level header fetch */
 98.1779 +				/* mark message seen */
 98.1780 +      markseen (stream,elt,flags);
 98.1781 +      if (rt.data = (unsigned char *)
 98.1782 +	  (*stream->dtb->header) (stream,msgno,&rt.size,flags)) {
 98.1783 +				/* make a safe copy if need to filter */
 98.1784 +	if (lines) textcpy (t = &stream->text,&rt);
 98.1785 +	else t = &rt;		/* top level header */
 98.1786 +      }
 98.1787 +    }
 98.1788 +  }
 98.1789 +  if (!t || !t->data) return "";/* error if no string */
 98.1790 +				/* filter headers if requested */
 98.1791 +  if (lines) t->size = mail_filter ((char *) t->data,t->size,lines,flags);
 98.1792 +  if (len) *len = t->size;	/* return size if requested */
 98.1793 +  return (char *) t->data;	/* and text */
 98.1794 +}
 98.1795 +
 98.1796 +/* Mail fetch message text
 98.1797 + * Accepts: mail stream
 98.1798 + *	    message # to fetch
 98.1799 + *	    MIME section specifier (#.#.#...#)
 98.1800 + *	    pointer to returned length
 98.1801 + *	    flags
 98.1802 + * Returns: message text
 98.1803 + */
 98.1804 +
 98.1805 +char *mail_fetch_text (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.1806 +		       unsigned long *len,long flags)
 98.1807 +{
 98.1808 +  GETS_DATA md;
 98.1809 +  PARTTEXT *p;
 98.1810 +  STRING bs;
 98.1811 +  MESSAGECACHE *elt;
 98.1812 +  BODY *b = NIL;
 98.1813 +  char tmp[MAILTMPLEN];
 98.1814 +  unsigned long i;
 98.1815 +  if (len) *len = 0;		/* default return size */
 98.1816 +  memset (&stream->private.string,NIL,sizeof (STRING));
 98.1817 +  if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
 98.1818 +  if (flags & FT_UID) {		/* UID form of call */
 98.1819 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.1820 +    else return "";		/* must get UID/msgno map first */
 98.1821 +  }
 98.1822 +  elt = mail_elt (stream,msgno);/* get cache data */
 98.1823 +  if (section && *section) {	/* nested body text wanted? */
 98.1824 +    if (!((b = mail_body (stream,msgno,section)) &&
 98.1825 +	  (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
 98.1826 +      return "";		/* lose if no body or not MESSAGE/RFC822 */
 98.1827 +    p = &b->nested.msg->text;	/* point at nested message */
 98.1828 +				/* build IMAP-format section specifier */
 98.1829 +    sprintf (tmp,"%s.TEXT",section);
 98.1830 +    flags &= ~FT_INTERNAL;	/* can't win with this set */
 98.1831 +  }
 98.1832 +  else {			/* top-level message text wanted */
 98.1833 +    p = &elt->private.msg.text;
 98.1834 +    strcpy (tmp,"TEXT");
 98.1835 +  }
 98.1836 +				/* initialize message data identifier */
 98.1837 +  INIT_GETS (md,stream,msgno,section,0,0);
 98.1838 +  if (p->text.data) {		/* is data already cached? */
 98.1839 +    markseen (stream,elt,flags);/* mark message seen */
 98.1840 +    return mail_fetch_text_return (&md,&p->text,len);
 98.1841 +  }
 98.1842 +  if (!stream->dtb) return "";	/* not in cache, must have live driver */
 98.1843 +  if (stream->dtb->msgdata) return
 98.1844 +    ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) && p->text.data)?
 98.1845 +      mail_fetch_text_return (&md,&p->text,len) : "";
 98.1846 +  if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return "";
 98.1847 +  if (section && *section) {	/* nested is more complex */
 98.1848 +    SETPOS (&bs,p->offset);
 98.1849 +    i = p->text.size;		/* just want this much */
 98.1850 +  }
 98.1851 +  else i = SIZE (&bs);		/* want entire text */
 98.1852 +  return mail_fetch_string_return (&md,&bs,i,len,flags);
 98.1853 +}
 98.1854 +
 98.1855 +/* Mail fetch message body part MIME headers
 98.1856 + * Accepts: mail stream
 98.1857 + *	    message # to fetch
 98.1858 + *	    MIME section specifier (#.#.#...#)
 98.1859 + *	    pointer to returned length
 98.1860 + *	    flags
 98.1861 + * Returns: message text
 98.1862 + */
 98.1863 +
 98.1864 +char *mail_fetch_mime (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.1865 +		       unsigned long *len,long flags)
 98.1866 +{
 98.1867 +  PARTTEXT *p;
 98.1868 +  STRING bs;
 98.1869 +  BODY *b;
 98.1870 +  char tmp[MAILTMPLEN];
 98.1871 +  if (len) *len = 0;		/* default return size */
 98.1872 +  if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
 98.1873 +  if (flags & FT_UID) {		/* UID form of call */
 98.1874 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.1875 +    else return "";		/* must get UID/msgno map first */
 98.1876 +  }
 98.1877 +  flags &= ~FT_INTERNAL;	/* can't win with this set */
 98.1878 +  if (!(section && *section && (b = mail_body (stream,msgno,section))))
 98.1879 +    return "";			/* not valid section */
 98.1880 +				/* in cache? */
 98.1881 +  if ((p = &b->mime)->text.data) {
 98.1882 +				/* mark message seen */
 98.1883 +    markseen (stream,mail_elt (stream,msgno),flags);
 98.1884 +    if (len) *len = p->text.size;
 98.1885 +    return (char *) p->text.data;
 98.1886 +  }
 98.1887 +  if (!stream->dtb) return "";	/* not in cache, must have live driver */
 98.1888 +  if (stream->dtb->msgdata) {	/* has driver fetch? */
 98.1889 +				/* build driver section specifier */
 98.1890 +    sprintf (tmp,"%s.MIME",section);
 98.1891 +    if ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) &&
 98.1892 +	p->text.data) {
 98.1893 +      if (len) *len = p->text.size;
 98.1894 +      return (char *) p->text.data;
 98.1895 +    }
 98.1896 +    else return "";
 98.1897 +  }
 98.1898 +  if (len) *len = b->mime.text.size;
 98.1899 +  if (!b->mime.text.size) {	/* empty MIME header -- mark seen anyway */
 98.1900 +    markseen (stream,mail_elt (stream,msgno),flags);
 98.1901 +    return "";
 98.1902 +  }
 98.1903 +				/* have to get it from offset */
 98.1904 +  if (stream->private.search.text)
 98.1905 +    return stream->private.search.text + b->mime.offset;
 98.1906 +  if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) {
 98.1907 +    if (len) *len = 0;
 98.1908 +    return "";
 98.1909 +  }
 98.1910 +  if (bs.dtb->next == mail_string_next) {
 98.1911 +    if (stream->private.search.string) stream->private.search.text = bs.curpos;
 98.1912 +    return bs.curpos + b->mime.offset;
 98.1913 +  }
 98.1914 +  return textcpyoffstring (&stream->text,&bs,b->mime.offset,b->mime.text.size);
 98.1915 +}
 98.1916 +
 98.1917 +/* Mail fetch message body part
 98.1918 + * Accepts: mail stream
 98.1919 + *	    message # to fetch
 98.1920 + *	    MIME section specifier (#.#.#...#)
 98.1921 + *	    pointer to returned length
 98.1922 + *	    flags
 98.1923 + * Returns: message body
 98.1924 + */
 98.1925 +
 98.1926 +char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.1927 +		       unsigned long *len,long flags)
 98.1928 +{
 98.1929 +  GETS_DATA md;
 98.1930 +  PARTTEXT *p;
 98.1931 +  STRING bs;
 98.1932 +  BODY *b;
 98.1933 +  SIZEDTEXT *t;
 98.1934 +  char *s,tmp[MAILTMPLEN];
 98.1935 +  memset (&stream->private.string,NIL,sizeof (STRING));
 98.1936 +  if (!(section && *section))	/* top-level text wanted? */
 98.1937 +    return mail_fetch_message (stream,msgno,len,flags);
 98.1938 +  else if (strlen (section) > (MAILTMPLEN - 20)) return "";
 98.1939 +  flags &= ~FT_INTERNAL;	/* can't win with this set */
 98.1940 +				/* initialize message data identifier */
 98.1941 +  INIT_GETS (md,stream,msgno,section,0,0);
 98.1942 +				/* kludge for old section 0 header */
 98.1943 +  if (!strcmp (s = strcpy (tmp,section),"0") ||
 98.1944 +      ((s = strstr (tmp,".0")) && !s[2])) {
 98.1945 +    SIZEDTEXT ht;
 98.1946 +    *s = '\0';			/* tie off section */
 98.1947 +				/* this silly way so it does mailgets */
 98.1948 +    ht.data = (unsigned char *) mail_fetch_header (stream,msgno,
 98.1949 +						   tmp[0] ? tmp : NIL,NIL,
 98.1950 +						   &ht.size,flags);
 98.1951 +				/* may have UIDs here */
 98.1952 +    md.flags = (flags & FT_UID) ? MG_UID : NIL;
 98.1953 +    return mail_fetch_text_return (&md,&ht,len);
 98.1954 +  }
 98.1955 +  if (len) *len = 0;		/* default return size */
 98.1956 +  if (flags & FT_UID) {		/* UID form of call */
 98.1957 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.1958 +    else return "";		/* must get UID/msgno map first */
 98.1959 +  }
 98.1960 +				/* must have body */
 98.1961 +  if (!(b = mail_body (stream,msgno,section))) return "";
 98.1962 +				/* have cached text? */
 98.1963 +  if ((t = &(p = &b->contents)->text)->data) {
 98.1964 +				/* mark message seen */
 98.1965 +    markseen (stream,mail_elt (stream,msgno),flags);
 98.1966 +    return mail_fetch_text_return (&md,t,len);
 98.1967 +  }
 98.1968 +  if (!stream->dtb) return "";	/* not in cache, must have live driver */
 98.1969 +  if (stream->dtb->msgdata) return
 98.1970 +    ((*stream->dtb->msgdata)(stream,msgno,section,0,0,NIL,flags) && t->data) ?
 98.1971 +      mail_fetch_text_return (&md,t,len) : "";
 98.1972 +  if (len) *len = t->size;
 98.1973 +  if (!t->size) {		/* empty body part -- mark seen anyway */
 98.1974 +    markseen (stream,mail_elt (stream,msgno),flags);
 98.1975 +    return "";
 98.1976 +  }
 98.1977 +				/* copy body from stringstruct offset */
 98.1978 +  if (stream->private.search.text)
 98.1979 +    return stream->private.search.text + p->offset;
 98.1980 +  if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) {
 98.1981 +    if (len) *len = 0;
 98.1982 +    return "";
 98.1983 +  }
 98.1984 +  if (bs.dtb->next == mail_string_next) {
 98.1985 +    if (stream->private.search.string) stream->private.search.text = bs.curpos;
 98.1986 +    return bs.curpos + p->offset;
 98.1987 +  }
 98.1988 +  SETPOS (&bs,p->offset);
 98.1989 +  return mail_fetch_string_return (&md,&bs,t->size,len,flags);
 98.1990 +}
 98.1991 +
 98.1992 +/* Mail fetch partial message text
 98.1993 + * Accepts: mail stream
 98.1994 + *	    message # to fetch
 98.1995 + *	    MIME section specifier (#.#.#...#)
 98.1996 + *	    offset of first designed byte or 0 to start at beginning
 98.1997 + *	    maximum number of bytes or 0 for all bytes
 98.1998 + *	    flags
 98.1999 + * Returns: T if successful, else NIL
 98.2000 + */
 98.2001 +
 98.2002 +long mail_partial_text (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.2003 +			unsigned long first,unsigned long last,long flags)
 98.2004 +{
 98.2005 +  GETS_DATA md;
 98.2006 +  PARTTEXT *p = NIL;
 98.2007 +  MESSAGECACHE *elt;
 98.2008 +  STRING bs;
 98.2009 +  BODY *b;
 98.2010 +  char tmp[MAILTMPLEN];
 98.2011 +  unsigned long i;
 98.2012 +  if (!mailgets) fatal ("mail_partial_text() called without a mailgets!");
 98.2013 +  if (section && (strlen (section) > (MAILTMPLEN - 20))) return NIL;
 98.2014 +  if (flags & FT_UID) {		/* UID form of call */
 98.2015 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.2016 +    else return NIL;		/* must get UID/msgno map first */
 98.2017 +  }
 98.2018 +  elt = mail_elt (stream,msgno);/* get cache data */
 98.2019 +  flags &= ~FT_INTERNAL;	/* bogus if this is set */
 98.2020 +  if (section && *section) {	/* nested body text wanted? */
 98.2021 +    if (!((b = mail_body (stream,msgno,section)) &&
 98.2022 +	  (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
 98.2023 +      return NIL;		/* lose if no body or not MESSAGE/RFC822 */
 98.2024 +    p = &b->nested.msg->text;	/* point at nested message */
 98.2025 +				/* build IMAP-format section specifier */
 98.2026 +    sprintf (tmp,"%s.TEXT",section);
 98.2027 +  }
 98.2028 +  else {			/* else top-level message text wanted */
 98.2029 +    p = &elt->private.msg.text;
 98.2030 +    strcpy (tmp,"TEXT");
 98.2031 +  }
 98.2032 +
 98.2033 +				/* initialize message data identifier */
 98.2034 +  INIT_GETS (md,stream,msgno,tmp,first,last);
 98.2035 +  if (p->text.data) {		/* is data already cached? */
 98.2036 +    INIT (&bs,mail_string,p->text.data,i = p->text.size);
 98.2037 +    markseen (stream,elt,flags);/* mark message seen */
 98.2038 +  }
 98.2039 +  else {			/* else get data from driver */
 98.2040 +    if (!stream->dtb) return NIL;
 98.2041 +    if (stream->dtb->msgdata)	/* driver will handle this */
 98.2042 +      return (*stream->dtb->msgdata) (stream,msgno,tmp,first,last,NIL,flags);
 98.2043 +    if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return NIL;
 98.2044 +    if (section && *section) {	/* nexted if more complex */
 98.2045 +      SETPOS (&bs,p->offset);	/* offset stringstruct to data */
 98.2046 +      i = p->text.size;		/* maximum size of data */
 98.2047 +    }
 98.2048 +    else i = SIZE (&bs);	/* just want this much */
 98.2049 +  }
 98.2050 +  if (i <= first) i = first = 0;/* first byte is beyond end of text */
 98.2051 +				/* truncate as needed */
 98.2052 +  else {			/* offset and truncate */
 98.2053 +    SETPOS (&bs,first + GETPOS (&bs));
 98.2054 +    i -= first;			/* reduced size */
 98.2055 +    if (last && (i > last)) i = last;
 98.2056 +  }
 98.2057 +				/* do the mailgets thing */
 98.2058 +  (*mailgets) (mail_read,&bs,i,&md);
 98.2059 +  return T;			/* success */
 98.2060 +}
 98.2061 +
 98.2062 +/* Mail fetch partial message body part
 98.2063 + * Accepts: mail stream
 98.2064 + *	    message # to fetch
 98.2065 + *	    MIME section specifier (#.#.#...#)
 98.2066 + *	    offset of first designed byte or 0 to start at beginning
 98.2067 + *	    maximum number of bytes or 0 for all bytes
 98.2068 + *	    flags
 98.2069 + * Returns: T if successful, else NIL
 98.2070 + */
 98.2071 +
 98.2072 +long mail_partial_body (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.2073 +			unsigned long first,unsigned long last,long flags)
 98.2074 +{
 98.2075 +  GETS_DATA md;
 98.2076 +  PARTTEXT *p;
 98.2077 +  STRING bs;
 98.2078 +  BODY *b;
 98.2079 +  SIZEDTEXT *t;
 98.2080 +  unsigned long i;
 98.2081 +  if (!(section && *section))	/* top-level text wanted? */
 98.2082 +    return mail_partial_text (stream,msgno,NIL,first,last,flags);
 98.2083 +  if (!mailgets) fatal ("mail_partial_body() called without a mailgets!");
 98.2084 +  if (flags & FT_UID) {		/* UID form of call */
 98.2085 +    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
 98.2086 +    else return NIL;		/* must get UID/msgno map first */
 98.2087 +  }
 98.2088 +				/* must have body */
 98.2089 +  if (!(b = mail_body (stream,msgno,section))) return NIL;
 98.2090 +  flags &= ~FT_INTERNAL;	/* bogus if this is set */
 98.2091 +
 98.2092 +				/* initialize message data identifier */
 98.2093 +  INIT_GETS (md,stream,msgno,section,first,last);
 98.2094 +				/* have cached text? */
 98.2095 +  if ((t = &(p = &b->contents)->text)->data) {
 98.2096 +				/* mark message seen */
 98.2097 +    markseen (stream,mail_elt (stream,msgno),flags);
 98.2098 +    INIT (&bs,mail_string,t->data,i = t->size);
 98.2099 +  }
 98.2100 +  else {			/* else get data from driver */
 98.2101 +    if (!stream->dtb) return NIL;
 98.2102 +    if (stream->dtb->msgdata)	/* driver will handle this */
 98.2103 +      return (*stream->dtb->msgdata) (stream,msgno,section,first,last,NIL,
 98.2104 +				      flags);
 98.2105 +    if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return NIL;
 98.2106 +    if (section && *section) {	/* nexted if more complex */
 98.2107 +      SETPOS (&bs,p->offset);	/* offset stringstruct to data */
 98.2108 +      i = t->size;		/* maximum size of data */
 98.2109 +    }
 98.2110 +    else i = SIZE (&bs);	/* just want this much */
 98.2111 +  }
 98.2112 +  if (i <= first) i = first = 0;/* first byte is beyond end of text */
 98.2113 +  else {			/* offset and truncate */
 98.2114 +    SETPOS (&bs,first + GETPOS (&bs));
 98.2115 +    i -= first;			/* reduced size */
 98.2116 +    if (last && (i > last)) i = last;
 98.2117 +  }
 98.2118 +				/* do the mailgets thing */
 98.2119 +  (*mailgets) (mail_read,&bs,i,&md);
 98.2120 +  return T;			/* success */
 98.2121 +}
 98.2122 +
 98.2123 +/* Mail return message text
 98.2124 + * Accepts: identifier data
 98.2125 + *	    sized text
 98.2126 + *	    pointer to returned length
 98.2127 + * Returns: text
 98.2128 + */
 98.2129 +
 98.2130 +char *mail_fetch_text_return (GETS_DATA *md,SIZEDTEXT *t,unsigned long *len)
 98.2131 +{
 98.2132 +  STRING bs;
 98.2133 +  if (len) *len = t->size;	/* return size */
 98.2134 +  if (t->size && mailgets) {	/* have to do the mailgets thing? */
 98.2135 +				/* silly but do it anyway for consistency */
 98.2136 +    INIT (&bs,mail_string,t->data,t->size);
 98.2137 +    return (*mailgets) (mail_read,&bs,t->size,md);
 98.2138 +  }
 98.2139 +  return t->size ? (char *) t->data : "";
 98.2140 +}
 98.2141 +
 98.2142 +
 98.2143 +/* Mail return message string
 98.2144 + * Accepts: identifier data
 98.2145 + *	    stringstruct
 98.2146 + *	    text length
 98.2147 + *	    pointer to returned length
 98.2148 + *	    flags
 98.2149 + * Returns: text, or NIL if stringstruct returned
 98.2150 + */
 98.2151 +
 98.2152 +char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i,
 98.2153 +				unsigned long *len,long flags)
 98.2154 +{
 98.2155 +  char *ret = NIL;
 98.2156 +  if (len) *len = i;		/* return size */
 98.2157 +				/* return stringstruct hack */
 98.2158 +  if (flags & FT_RETURNSTRINGSTRUCT) {
 98.2159 +    memcpy (&md->stream->private.string,bs,sizeof (STRING));
 98.2160 +    SETPOS (&md->stream->private.string,GETPOS (&md->stream->private.string));
 98.2161 +  }
 98.2162 +				/* have to do the mailgets thing? */
 98.2163 +  else if (mailgets) ret = (*mailgets) (mail_read,bs,i,md);
 98.2164 +				/* special hack to avoid extra copy */
 98.2165 +  else if (bs->dtb->next == mail_string_next) ret = bs->curpos;
 98.2166 +				/* make string copy in memory */
 98.2167 +  else ret = textcpyoffstring (&md->stream->text,bs,GETPOS (bs),i);
 98.2168 +  return ret;
 98.2169 +}
 98.2170 +
 98.2171 +/* Read data from stringstruct
 98.2172 + * Accepts: stringstruct
 98.2173 + *	    size of data to read
 98.2174 + *	    buffer to read into
 98.2175 + * Returns: T, always, stringstruct updated
 98.2176 + */
 98.2177 +
 98.2178 +long mail_read (void *stream,unsigned long size,char *buffer)
 98.2179 +{
 98.2180 +  unsigned long i;
 98.2181 +  STRING *s = (STRING *) stream;
 98.2182 +  while (size) {		/* until satisfied */
 98.2183 +    memcpy (buffer,s->curpos,i = min (s->cursize,size));
 98.2184 +    buffer += i;		/* update buffer */
 98.2185 +    size -= i;			/* note that we read this much */
 98.2186 +    s->curpos += --i;		/* advance that many spaces minus 1 */
 98.2187 +    s->cursize -= i;
 98.2188 +    SNX (s);			/* now use SNX to advance the last byte */
 98.2189 +  }
 98.2190 +  return T;
 98.2191 +}
 98.2192 +
 98.2193 +/* Mail fetch UID
 98.2194 + * Accepts: mail stream
 98.2195 + *	    message number
 98.2196 + * Returns: UID or zero if dead stream
 98.2197 + */
 98.2198 +
 98.2199 +unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno)
 98.2200 +{
 98.2201 +  unsigned long uid = mail_elt (stream,msgno)->private.uid;
 98.2202 +  return uid ? uid :
 98.2203 +    (stream->dtb && stream->dtb->uid) ? (*stream->dtb->uid) (stream,msgno) : 0;
 98.2204 +}
 98.2205 +
 98.2206 +
 98.2207 +/* Mail fetch msgno from UID
 98.2208 + * Accepts: mail stream
 98.2209 + *	    UID
 98.2210 + * Returns: msgno or zero if failed
 98.2211 + */
 98.2212 +
 98.2213 +unsigned long mail_msgno (MAILSTREAM *stream,unsigned long uid)
 98.2214 +{
 98.2215 +  unsigned long msgno,delta,first,firstuid,last,lastuid,middle,miduid;
 98.2216 +  if (stream->dtb) {		/* active stream? */
 98.2217 +    if (stream->dtb->msgno)	/* direct way */
 98.2218 +      return (*stream->dtb->msgno) (stream,uid);
 98.2219 +    else if (stream->dtb->uid) {/* indirect way */
 98.2220 +      /* Placeholder for now, since currently there are no drivers which
 98.2221 +       * have a uid method but not a msgno method
 98.2222 +       */
 98.2223 +      for (msgno = 1; msgno <= stream->nmsgs; msgno++)
 98.2224 +	if ((*stream->dtb->uid) (stream,msgno) == uid) return msgno;
 98.2225 +    }
 98.2226 +				/* binary search since have full map */
 98.2227 +    else for (first = 1,last = stream->nmsgs, delta = (first <= last) ? 1 : 0;
 98.2228 +	      delta &&
 98.2229 +	      (uid >= (firstuid = mail_elt (stream,first)->private.uid)) &&
 98.2230 +		(uid <= (lastuid = mail_elt (stream,last)->private.uid));) {
 98.2231 +				/* done if match at an endpoint */
 98.2232 +	if (uid == firstuid) return first;
 98.2233 +	if (uid == lastuid) return last;
 98.2234 +				/* have anything between endpoints? */
 98.2235 +	if (delta = ((last - first) / 2)) {
 98.2236 +	  if ((miduid = mail_elt (stream,middle = first + delta)->private.uid)
 98.2237 +	      == uid)
 98.2238 +	    return middle;	/* found match in middle */
 98.2239 +	  else if (uid < miduid) last = middle - 1;
 98.2240 +	  else first = middle + 1;
 98.2241 +	}
 98.2242 +    }
 98.2243 +  }
 98.2244 +  else {			/* dead stream, do linear search for UID */
 98.2245 +    for (msgno = 1; msgno <= stream->nmsgs; msgno++)
 98.2246 +      if (mail_elt (stream,msgno)->private.uid == uid) return msgno;
 98.2247 +  }
 98.2248 +  return 0;			/* didn't find the UID anywhere */
 98.2249 +}
 98.2250 +
 98.2251 +/* Mail fetch From string for menu
 98.2252 + * Accepts: destination string
 98.2253 + *	    mail stream
 98.2254 + *	    message # to fetch
 98.2255 + *	    desired string length
 98.2256 + * Returns: string of requested length
 98.2257 + */
 98.2258 +
 98.2259 +void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
 98.2260 +		     long length)
 98.2261 +{
 98.2262 +  char *t;
 98.2263 +  char tmp[MAILTMPLEN];
 98.2264 +  ENVELOPE *env = mail_fetchenvelope (stream,msgno);
 98.2265 +  ADDRESS *adr = env ? env->from : NIL;
 98.2266 +  memset (s,' ',(size_t)length);/* fill it with spaces */
 98.2267 +  s[length] = '\0';		/* tie off with null */
 98.2268 +				/* get first from address from envelope */
 98.2269 +  while (adr && !adr->host) adr = adr->next;
 98.2270 +  if (adr) {			/* if a personal name exists use it */
 98.2271 +    if (!(t = adr->personal))
 98.2272 +      sprintf (t = tmp,"%.256s@%.256s",adr->mailbox,adr->host);
 98.2273 +    memcpy (s,t,(size_t) min (length,(long) strlen (t)));
 98.2274 +  }
 98.2275 +}
 98.2276 +
 98.2277 +
 98.2278 +/* Mail fetch Subject string for menu
 98.2279 + * Accepts: destination string
 98.2280 + *	    mail stream
 98.2281 + *	    message # to fetch
 98.2282 + *	    desired string length
 98.2283 + * Returns: string of no more than requested length
 98.2284 + */
 98.2285 +
 98.2286 +void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
 98.2287 +			long length)
 98.2288 +{
 98.2289 +  ENVELOPE *env = mail_fetchenvelope (stream,msgno);
 98.2290 +  memset (s,'\0',(size_t) length+1);
 98.2291 +				/* copy subject from envelope */
 98.2292 +  if (env && env->subject) strncpy (s,env->subject,(size_t) length);
 98.2293 +  else *s = ' ';		/* if no subject then just a space */
 98.2294 +}
 98.2295 +
 98.2296 +/* Mail modify flags
 98.2297 + * Accepts: mail stream
 98.2298 + *	    sequence
 98.2299 + *	    flag(s)
 98.2300 + *	    option flags
 98.2301 + */
 98.2302 +
 98.2303 +void mail_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 98.2304 +{
 98.2305 +  MESSAGECACHE *elt;
 98.2306 +  unsigned long i,uf;
 98.2307 +  long f;
 98.2308 +  short nf;
 98.2309 +  if (!stream->dtb) return;	/* no-op if no stream */
 98.2310 +  if ((stream->dtb->flagmsg || !stream->dtb->flag) &&
 98.2311 +      ((flags & ST_UID) ? mail_uid_sequence (stream,sequence) :
 98.2312 +       mail_sequence (stream,sequence)) &&
 98.2313 +      ((f = mail_parse_flags (stream,flag,&uf)) || uf))
 98.2314 +    for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++)
 98.2315 +      if ((elt = mail_elt (stream,i))->sequence) {
 98.2316 +	struct {		/* old flags */
 98.2317 +	  unsigned int valid : 1;
 98.2318 +	  unsigned int seen : 1;
 98.2319 +	  unsigned int deleted : 1;
 98.2320 +	  unsigned int flagged : 1;
 98.2321 +	  unsigned int answered : 1;
 98.2322 +	  unsigned int draft : 1;
 98.2323 +	  unsigned long user_flags;
 98.2324 +	} old;
 98.2325 +	old.valid = elt->valid; old.seen = elt->seen;
 98.2326 +	old.deleted = elt->deleted; old.flagged = elt->flagged;
 98.2327 +	old.answered = elt->answered; old.draft = elt->draft;
 98.2328 +	old.user_flags = elt->user_flags;
 98.2329 +	elt->valid = NIL;	/* prepare for flag alteration */
 98.2330 +	if (stream->dtb->flagmsg) (*stream->dtb->flagmsg) (stream,elt);
 98.2331 +	if (f&fSEEN) elt->seen = nf;
 98.2332 +	if (f&fDELETED) elt->deleted = nf;
 98.2333 +	if (f&fFLAGGED) elt->flagged = nf;
 98.2334 +	if (f&fANSWERED) elt->answered = nf;
 98.2335 +	if (f&fDRAFT) elt->draft = nf;
 98.2336 +				/* user flags */
 98.2337 +	if (flags & ST_SET) elt->user_flags |= uf;
 98.2338 +	else elt->user_flags &= ~uf;
 98.2339 +	elt->valid = T;		/* flags now altered */
 98.2340 +	if ((old.valid != elt->valid) || (old.seen != elt->seen) ||
 98.2341 +	    (old.deleted != elt->deleted) || (old.flagged != elt->flagged) ||
 98.2342 +	    (old.answered != elt->answered) || (old.draft != elt->draft) ||
 98.2343 +	    (old.user_flags != elt->user_flags))
 98.2344 +	  MM_FLAGS (stream,elt->msgno);
 98.2345 +	if (stream->dtb->flagmsg) (*stream->dtb->flagmsg) (stream,elt);
 98.2346 +      }
 98.2347 +				/* call driver once */
 98.2348 +  if (stream->dtb->flag) (*stream->dtb->flag) (stream,sequence,flag,flags);
 98.2349 +}
 98.2350 +
 98.2351 +/* Mail search for messages
 98.2352 + * Accepts: mail stream
 98.2353 + *	    character set
 98.2354 + *	    search program
 98.2355 + *	    option flags
 98.2356 + * Returns: T if successful, NIL if dead stream, NIL searchpgm or bad charset
 98.2357 + */
 98.2358 +
 98.2359 +long mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
 98.2360 +		       long flags)
 98.2361 +{
 98.2362 +  unsigned long i;
 98.2363 +  long ret = NIL;
 98.2364 +  if (!(flags & SE_RETAIN))	/* clear search vector unless retaining */
 98.2365 +    for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL;
 98.2366 +  if (pgm && stream->dtb)	/* must have a search program and driver */
 98.2367 +    ret = (*(stream->dtb->search ? stream->dtb->search : mail_search_default))
 98.2368 +      (stream,charset,pgm,flags);
 98.2369 +				/* flush search program if requested */
 98.2370 +  if (flags & SE_FREE) mail_free_searchpgm (&pgm);
 98.2371 +  return ret;
 98.2372 +}
 98.2373 +
 98.2374 +
 98.2375 +/* Mail search for messages default handler
 98.2376 + * Accepts: mail stream
 98.2377 + *	    character set
 98.2378 + *	    search program
 98.2379 + *	    option flags
 98.2380 + * Returns: T if successful, NIL if bad charset
 98.2381 + */
 98.2382 +
 98.2383 +long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
 98.2384 +			  long flags)
 98.2385 +{
 98.2386 +  unsigned long i;
 98.2387 +  char *msg;
 98.2388 +				/* make sure that charset is good */
 98.2389 +  if (msg = utf8_badcharset (charset)) {
 98.2390 +    MM_LOG (msg,ERROR);		/* output error */
 98.2391 +    fs_give ((void **) &msg);
 98.2392 +    return NIL;
 98.2393 +  }
 98.2394 +  utf8_searchpgm (pgm,charset);
 98.2395 +  for (i = 1; i <= stream->nmsgs; ++i)
 98.2396 +    if (mail_search_msg (stream,i,NIL,pgm)) {
 98.2397 +      if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i));
 98.2398 +      else {			/* mark as searched, notify mail program */
 98.2399 +	mail_elt (stream,i)->searched = T;
 98.2400 +	if (!stream->silent) mm_searched (stream,i);
 98.2401 +      }
 98.2402 +    }
 98.2403 +  return LONGT;		/* search completed */
 98.2404 +}
 98.2405 +
 98.2406 +/* Mail ping mailbox
 98.2407 + * Accepts: mail stream
 98.2408 + * Returns: stream if still open else NIL
 98.2409 + */
 98.2410 +
 98.2411 +long mail_ping (MAILSTREAM *stream)
 98.2412 +{
 98.2413 +  unsigned long i,n,uf,len;
 98.2414 +  char *s,*f,tmp[MAILTMPLEN],flags[MAILTMPLEN];
 98.2415 +  MAILSTREAM *snarf;
 98.2416 +  MESSAGECACHE *elt;
 98.2417 +  STRING bs;
 98.2418 +  long ret;
 98.2419 +				/* do driver action */
 98.2420 +  if ((ret = ((stream && stream->dtb) ? (stream->dtb->ping) (stream) : NIL)) &&
 98.2421 +      stream->snarf.name &&	/* time to snarf? */
 98.2422 +				/* prohibit faster than once/min */
 98.2423 +      (time (0) > (time_t) (stream->snarf.time + min(60,mailsnarfinterval))) &&
 98.2424 +      (snarf = mail_open (NIL,stream->snarf.name,
 98.2425 +			  stream->snarf.options | OP_SILENT))) {
 98.2426 +    if ((n = snarf->nmsgs) &&	/* yes, have messages to snarf? */
 98.2427 +	mail_search_full (snarf,NIL,mail_criteria ("UNDELETED"),SE_FREE)) {
 98.2428 +      for (i = 1; ret && (i <= n); i++)	/* for each message */
 98.2429 +	if ((elt = mail_elt (snarf,i))->searched &&
 98.2430 +	    (s = mail_fetch_message (snarf,i,&len,FT_PEEK)) && len) {
 98.2431 +	  INIT (&bs,mail_string,s,len);
 98.2432 +	  if (mailsnarfpreserve) {
 98.2433 +				/* yes, make sure have fast data */
 98.2434 +	    if (!elt->valid || !elt->day) {
 98.2435 +	      sprintf (tmp,"%lu",n);
 98.2436 +	      mail_fetch_fast (snarf,tmp,NIL);
 98.2437 +	    }
 98.2438 +				/* initialize flag string */
 98.2439 +	    memset (flags,0,MAILTMPLEN);
 98.2440 +				/* output system flags except \Deleted */
 98.2441 +	    if (elt->seen) strcat (flags," \\Seen");
 98.2442 +	    if (elt->flagged) strcat (flags," \\Flagged");
 98.2443 +	    if (elt->answered) strcat (flags," \\Answered");
 98.2444 +	    if (elt->draft) strcat (flags," \\Draft");
 98.2445 +				/* any user flags? */
 98.2446 +	    for (uf = elt->user_flags,s = flags + strlen (flags);
 98.2447 +		 uf && (f = stream->user_flags[find_rightmost_bit (&uf)]) &&
 98.2448 +		   ((MAILTMPLEN - (s - tmp)) > (long) (2 + strlen (f)));
 98.2449 +		 s += strlen (s)) sprintf (s," %s",f);
 98.2450 +	    ret = mail_append_full (stream,stream->mailbox,flags + 1,
 98.2451 +				    mail_date (tmp,elt),&bs);
 98.2452 +	  }
 98.2453 +	  else ret = mail_append (stream,stream->mailbox,&bs);
 98.2454 +
 98.2455 +	  if (ret) {		/* did snarf succeed? */
 98.2456 +				/* driver has per-message (or no) flag call */
 98.2457 +	    if (snarf->dtb->flagmsg || !snarf->dtb->flag) {
 98.2458 +	      elt->valid = NIL;	/* prepare for flag alteration */
 98.2459 +	      if (snarf->dtb->flagmsg) (*snarf->dtb->flagmsg) (snarf,elt);
 98.2460 +				/* flags now altered */
 98.2461 +	      elt->deleted = elt->seen = elt->valid = T;
 98.2462 +	      if (snarf->dtb->flagmsg) (*snarf->dtb->flagmsg) (snarf,elt);
 98.2463 +	    }
 98.2464 +				/* driver has one-time flag call */
 98.2465 +	    if (snarf->dtb->flag) {
 98.2466 +	      sprintf (tmp,"%lu",i);
 98.2467 +	      (*snarf->dtb->flag) (snarf,tmp,"\\Deleted \\Seen",ST_SET);
 98.2468 +	    }
 98.2469 +	  }
 98.2470 +	  else {		/* copy failed */
 98.2471 +	    sprintf (tmp,"Unable to move message %lu from %s mailbox",
 98.2472 +		     i,snarf->dtb->name);
 98.2473 +	    mm_log (tmp,WARN);
 98.2474 +	  }
 98.2475 +	}
 98.2476 +    }
 98.2477 +				/* expunge the messages */
 98.2478 +    mail_close_full (snarf,n ? CL_EXPUNGE : NIL);
 98.2479 +    stream->snarf.time = (unsigned long) time (0);
 98.2480 +    /* Even if the snarf failed, we don't want to return NIL if the stream
 98.2481 +     * is still alive.  Or at least that's what we currently think.
 98.2482 +     */
 98.2483 +  				/* redo the driver's action */
 98.2484 +    ret = stream->dtb ? (*stream->dtb->ping) (stream) : NIL;
 98.2485 +  }
 98.2486 +  return ret;
 98.2487 +}
 98.2488 +
 98.2489 +/* Mail check mailbox
 98.2490 + * Accepts: mail stream
 98.2491 + */
 98.2492 +
 98.2493 +void mail_check (MAILSTREAM *stream)
 98.2494 +{
 98.2495 +  				/* do the driver's action */
 98.2496 +  if (stream->dtb) (*stream->dtb->check) (stream);
 98.2497 +}
 98.2498 +
 98.2499 +
 98.2500 +/* Mail expunge mailbox
 98.2501 + * Accepts: mail stream
 98.2502 + *	    sequence to expunge if non-NIL
 98.2503 + *	    expunge options
 98.2504 + * Returns: T on success, NIL on failure
 98.2505 + */
 98.2506 +
 98.2507 +long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options)
 98.2508 +{
 98.2509 +  				/* do the driver's action */
 98.2510 +  return stream->dtb ? (*stream->dtb->expunge) (stream,sequence,options) : NIL;
 98.2511 +}
 98.2512 +
 98.2513 +
 98.2514 +/* Mail copy message(s)
 98.2515 + * Accepts: mail stream
 98.2516 + *	    sequence
 98.2517 + *	    destination mailbox
 98.2518 + *	    flags
 98.2519 + */
 98.2520 +
 98.2521 +long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
 98.2522 +		     long options)
 98.2523 +{
 98.2524 +  return stream->dtb ?
 98.2525 +    SAFE_COPY (stream->dtb,stream,sequence,mailbox,options) : NIL;
 98.2526 +}
 98.2527 +
 98.2528 +/* Append data package to use for old single-message mail_append() interface */
 98.2529 +
 98.2530 +typedef struct mail_append_package {
 98.2531 +  char *flags;			/* initial flags */
 98.2532 +  char *date;			/* message internal date */
 98.2533 +  STRING *message;		/* stringstruct of message */
 98.2534 +} APPENDPACKAGE;
 98.2535 +
 98.2536 +
 98.2537 +/* Single append message string
 98.2538 + * Accepts: mail stream
 98.2539 + *	    package pointer (cast as a void *)
 98.2540 + *	    pointer to return initial flags
 98.2541 + *	    pointer to return message internal date
 98.2542 + *	    pointer to return stringstruct of message to append
 98.2543 + * Returns: T, always
 98.2544 + */
 98.2545 +
 98.2546 +static long mail_append_single (MAILSTREAM *stream,void *data,char **flags,
 98.2547 +				char **date,STRING **message)
 98.2548 +{
 98.2549 +  APPENDPACKAGE *ap = (APPENDPACKAGE *) data;
 98.2550 +  *flags = ap->flags;		/* get desired data from the package */
 98.2551 +  *date = ap->date;
 98.2552 +  *message = ap->message;
 98.2553 +  ap->message = NIL;		/* so next callback puts a stop to it */
 98.2554 +  return LONGT;			/* always return success */
 98.2555 +}
 98.2556 +
 98.2557 +
 98.2558 +/* Mail append message string
 98.2559 + * Accepts: mail stream
 98.2560 + *	    destination mailbox
 98.2561 + *	    initial flags
 98.2562 + *	    message internal date
 98.2563 + *	    stringstruct of message to append
 98.2564 + * Returns: T on success, NIL on failure
 98.2565 + */
 98.2566 +
 98.2567 +long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
 98.2568 +		       STRING *message)
 98.2569 +{
 98.2570 +  APPENDPACKAGE ap;
 98.2571 +  ap.flags = flags;		/* load append package */
 98.2572 +  ap.date = date;
 98.2573 +  ap.message = message;
 98.2574 +  return mail_append_multiple (stream,mailbox,mail_append_single,(void *) &ap);
 98.2575 +}
 98.2576 +
 98.2577 +/* Mail append message(s)
 98.2578 + * Accepts: mail stream
 98.2579 + *	    destination mailbox
 98.2580 + *	    append data callback
 98.2581 + *	    arbitrary data for callback use
 98.2582 + * Returns: T on success, NIL on failure
 98.2583 + */
 98.2584 +
 98.2585 +long mail_append_multiple (MAILSTREAM *stream,char *mailbox,append_t af,
 98.2586 +			   void *data)
 98.2587 +{
 98.2588 +  char *s,tmp[MAILTMPLEN];
 98.2589 +  DRIVER *d = NIL;
 98.2590 +  long ret = NIL;
 98.2591 +				/* never allow names with newlines */
 98.2592 +  if (strpbrk (mailbox,"\015\012"))
 98.2593 +    MM_LOG ("Can't append to mailbox with such a name",ERROR);
 98.2594 +  else if (strlen (mailbox) >=
 98.2595 +	   (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) {
 98.2596 +    sprintf (tmp,"Can't append %.80s: %s",mailbox,(*mailbox == '{') ?
 98.2597 +	     "invalid remote specification" : "no such mailbox");
 98.2598 +    MM_LOG (tmp,ERROR);
 98.2599 +  }
 98.2600 +				/* special driver hack? */
 98.2601 +  else if (!strncmp (lcase (strcpy (tmp,mailbox)),"#driver.",8)) {
 98.2602 +				/* yes, tie off name at likely delimiter */
 98.2603 +    if (!(s = strpbrk (tmp+8,"/\\:"))) {
 98.2604 +      sprintf (tmp,"Can't append to mailbox %.80s: bad driver syntax",mailbox);
 98.2605 +      MM_LOG (tmp,ERROR);
 98.2606 +      return NIL;
 98.2607 +    }
 98.2608 +    *s++ = '\0';		/* tie off at delimiter */
 98.2609 +    if (!(d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,tmp+8))) {
 98.2610 +      sprintf (tmp,"Can't append to mailbox %.80s: unknown driver",mailbox);
 98.2611 +      MM_LOG (tmp,ERROR);
 98.2612 +    }
 98.2613 +    else ret = SAFE_APPEND (d,stream,mailbox + (s - tmp),af,data);
 98.2614 +  }
 98.2615 +  else if (d = mail_valid (stream,mailbox,NIL))
 98.2616 +    ret = SAFE_APPEND (d,stream,mailbox,af,data);
 98.2617 +  /* No driver, try for TRYCREATE if no stream.  Note that we use the
 98.2618 +   * createProto here, not the appendProto, since the dummy driver already
 98.2619 +   * took care of the appendProto case.  Otherwise, if appendProto is set to
 98.2620 +   * NIL, we won't get a TRYCREATE.
 98.2621 +   */
 98.2622 +  else if (!stream && (stream = default_proto (NIL)) && stream->dtb &&
 98.2623 +	   SAFE_APPEND (stream->dtb,stream,mailbox,af,data))
 98.2624 +				/* timing race? */
 98.2625 +    MM_NOTIFY (stream,"Append validity confusion",WARN);
 98.2626 +				/* generate error message */
 98.2627 +  else mail_valid (stream,mailbox,"append to mailbox");
 98.2628 +  return ret;
 98.2629 +}
 98.2630 +
 98.2631 +/* Mail garbage collect stream
 98.2632 + * Accepts: mail stream
 98.2633 + *	    garbage collection flags
 98.2634 + */
 98.2635 +
 98.2636 +void mail_gc (MAILSTREAM *stream,long gcflags)
 98.2637 +{
 98.2638 +  MESSAGECACHE *elt;
 98.2639 +  unsigned long i;
 98.2640 +  				/* do the driver's action first */
 98.2641 +  if (stream->dtb && stream->dtb->gc) (*stream->dtb->gc) (stream,gcflags);
 98.2642 +  stream->msgno = 0;		/* nothing cached now */
 98.2643 +  if (gcflags & GC_ENV) {	/* garbage collect envelopes? */
 98.2644 +    if (stream->env) mail_free_envelope (&stream->env);
 98.2645 +    if (stream->body) mail_free_body (&stream->body);
 98.2646 +  }
 98.2647 +  if (gcflags & GC_TEXTS) {	/* free texts */
 98.2648 +    if (stream->text.data) fs_give ((void **) &stream->text.data);
 98.2649 +    stream->text.size = 0;
 98.2650 +  }
 98.2651 +				/* garbage collect per-message stuff */
 98.2652 +  for (i = 1; i <= stream->nmsgs; i++) 
 98.2653 +    if (elt = (MESSAGECACHE *) (*mailcache) (stream,i,CH_ELT))
 98.2654 +      mail_gc_msg (&elt->private.msg,gcflags);
 98.2655 +}
 98.2656 +
 98.2657 +
 98.2658 +/* Mail garbage collect message
 98.2659 + * Accepts: message structure
 98.2660 + *	    garbage collection flags
 98.2661 + */
 98.2662 +
 98.2663 +void mail_gc_msg (MESSAGE *msg,long gcflags)
 98.2664 +{
 98.2665 +  if (gcflags & GC_ENV) {	/* garbage collect envelopes? */
 98.2666 +    mail_free_envelope (&msg->env);
 98.2667 +    mail_free_body (&msg->body);
 98.2668 +  }
 98.2669 +  if (gcflags & GC_TEXTS) {	/* garbage collect texts */
 98.2670 +    if (msg->full.text.data) fs_give ((void **) &msg->full.text.data);
 98.2671 +    if (msg->header.text.data) {
 98.2672 +      mail_free_stringlist (&msg->lines);
 98.2673 +      fs_give ((void **) &msg->header.text.data);
 98.2674 +    }
 98.2675 +    if (msg->text.text.data) fs_give ((void **) &msg->text.text.data);
 98.2676 +				/* now GC all body components */
 98.2677 +    if (msg->body) mail_gc_body (msg->body);
 98.2678 +  }
 98.2679 +}
 98.2680 +
 98.2681 +/* Mail garbage collect texts in BODY structure
 98.2682 + * Accepts: BODY structure
 98.2683 + */
 98.2684 +
 98.2685 +void mail_gc_body (BODY *body)
 98.2686 +{
 98.2687 +  PART *part;
 98.2688 +  switch (body->type) {		/* free contents */
 98.2689 +  case TYPEMULTIPART:		/* multiple part */
 98.2690 +    for (part = body->nested.part; part; part = part->next)
 98.2691 +      mail_gc_body (&part->body);
 98.2692 +    break;
 98.2693 +  case TYPEMESSAGE:		/* encapsulated message */
 98.2694 +    if (body->subtype && !strcmp (body->subtype,"RFC822")) {
 98.2695 +      mail_free_stringlist (&body->nested.msg->lines);
 98.2696 +      mail_gc_msg (body->nested.msg,GC_TEXTS);
 98.2697 +    }
 98.2698 +    break;
 98.2699 +  default:
 98.2700 +    break;
 98.2701 +  }
 98.2702 +  if (body->mime.text.data) fs_give ((void **) &body->mime.text.data);
 98.2703 +  if (body->contents.text.data) fs_give ((void **) &body->contents.text.data);
 98.2704 +}
 98.2705 +
 98.2706 +/* Mail get body part
 98.2707 + * Accepts: mail stream
 98.2708 + *	    message number
 98.2709 + *	    section specifier
 98.2710 + * Returns: pointer to body
 98.2711 + */
 98.2712 +
 98.2713 +BODY *mail_body (MAILSTREAM *stream,unsigned long msgno,unsigned char *section)
 98.2714 +{
 98.2715 +  BODY *b = NIL;
 98.2716 +  PART *pt;
 98.2717 +  unsigned long i;
 98.2718 +				/* make sure have a body */
 98.2719 +  if (section && *section && mail_fetchstructure (stream,msgno,&b) && b)
 98.2720 +    while (*section) {		/* find desired section */
 98.2721 +      if (isdigit (*section)) {	/* get section specifier */
 98.2722 +				/* make sure what follows is valid */
 98.2723 +	if (!(i = strtoul (section,(char **) &section,10)) ||
 98.2724 +	    (*section && ((*section++ != '.') || !*section))) return NIL;
 98.2725 +				/* multipart content? */
 98.2726 +	if (b->type == TYPEMULTIPART) {
 98.2727 +				/* yes, find desired part */
 98.2728 +	  if (pt = b->nested.part) while (--i && (pt = pt->next));
 98.2729 +	  if (!pt) return NIL;	/* bad specifier */
 98.2730 +	  b = &pt->body;	/* note new body */
 98.2731 +	}
 98.2732 +				/* otherwise must be section 1 */
 98.2733 +	else if (i != 1) return NIL;
 98.2734 +				/* need to go down further? */
 98.2735 +	if (*section) switch (b->type) {
 98.2736 +	case TYPEMULTIPART:	/* multipart */
 98.2737 +	  break;
 98.2738 +	case TYPEMESSAGE:	/* embedded message */
 98.2739 +	  if (!strcmp (b->subtype,"RFC822")) {
 98.2740 +	    b = b->nested.msg->body;
 98.2741 +	    break;
 98.2742 +	  }
 98.2743 +	default:		/* bogus subpart specification */
 98.2744 +	  return NIL;
 98.2745 +	}
 98.2746 +      }
 98.2747 +      else return NIL;		/* unknown section specifier */
 98.2748 +    }
 98.2749 +  return b;
 98.2750 +}  
 98.2751 +
 98.2752 +/* Mail output date from elt fields
 98.2753 + * Accepts: character string to write into
 98.2754 + *	    elt to get data data from
 98.2755 + * Returns: the character string
 98.2756 + */
 98.2757 +
 98.2758 +const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
 98.2759 +
 98.2760 +const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 98.2761 +			"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
 98.2762 +
 98.2763 +char *mail_date (char *string,MESSAGECACHE *elt)
 98.2764 +{
 98.2765 +  sprintf (string,"%2d-%s-%d %02d:%02d:%02d %c%02d%02d",
 98.2766 +	   elt->day ? elt->day : 1,
 98.2767 +	   months[elt->month ? (elt->month - 1) : 0],
 98.2768 +	   elt->year + BASEYEAR,elt->hours,elt->minutes,elt->seconds,
 98.2769 +	   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes);
 98.2770 +  return string;
 98.2771 +}
 98.2772 +
 98.2773 +
 98.2774 +/* Mail output extended-ctime format date from elt fields
 98.2775 + * Accepts: character string to write into
 98.2776 + *	    elt to get data data from
 98.2777 + * Returns: the character string
 98.2778 + */
 98.2779 +
 98.2780 +char *mail_cdate (char *string,MESSAGECACHE *elt)
 98.2781 +{
 98.2782 +  char *fmt = "%s %s %2d %02d:%02d:%02d %4d %s%02d%02d\n";
 98.2783 +  int d = elt->day ? elt->day : 1;
 98.2784 +  int m = elt->month ? (elt->month - 1) : 0;
 98.2785 +  int y = elt->year + BASEYEAR;
 98.2786 +  const char *s = months[m];
 98.2787 +  if (m < 2) {			/* if before March, */
 98.2788 +    m += 10;			/* January = month 10 of previous year */
 98.2789 +    y--;
 98.2790 +  }
 98.2791 +  else m -= 2;			/* March is month 0 */
 98.2792 +  sprintf (string,fmt,days[(int) (d + 2 + ((7 + 31 * m) / 12)
 98.2793 +#ifndef USEJULIANCALENDAR
 98.2794 +#ifndef USEORTHODOXCALENDAR	/* Gregorian calendar */
 98.2795 +				  + (y / 400)
 98.2796 +#ifdef Y4KBUGFIX
 98.2797 +				  - (y / 4000)
 98.2798 +#endif
 98.2799 +#else				/* Orthodox calendar */
 98.2800 +				  + (2 * (y / 900)) + ((y % 900) >= 200)
 98.2801 +				  + ((y % 900) >= 600)
 98.2802 +#endif
 98.2803 +				  - (y / 100)
 98.2804 +#endif
 98.2805 +				  + y + (y / 4)) % 7],
 98.2806 +	   s,d,elt->hours,elt->minutes,elt->seconds,elt->year + BASEYEAR,
 98.2807 +	   elt->zoccident ? "-" : "+",elt->zhours,elt->zminutes);
 98.2808 +  return string;
 98.2809 +}
 98.2810 +
 98.2811 +/* Mail parse date into elt fields
 98.2812 + * Accepts: elt to write into
 98.2813 + *	    date string to parse
 98.2814 + * Returns: T if parse successful, else NIL 
 98.2815 + * This routine parses dates as follows:
 98.2816 + * . leading three alphas followed by comma and space are ignored
 98.2817 + * . date accepted in format: mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy,
 98.2818 + *    dd mmm yy, dd mmm yyyy, yyyy-mm-dd, yyyymmdd
 98.2819 + * . two and three digit years interpreted according to RFC 2822 rules
 98.2820 + * . mandatory end of string if yyyy-mm-dd or yyyymmdd; otherwise optional
 98.2821 + *    space followed by time:
 98.2822 + * . time accepted in format hh:mm:ss or hh:mm
 98.2823 + * . end of string accepted
 98.2824 + * . timezone accepted: hyphen followed by symbolic timezone, or space
 98.2825 + *    followed by signed numeric timezone or symbolic timezone
 98.2826 + * Examples of normal input:
 98.2827 + * . IMAP date-only (SEARCH):
 98.2828 + *    dd-mmm-yyyy
 98.2829 + * . IMAP date-time (INTERNALDATE):
 98.2830 + *    dd-mmm-yyyy hh:mm:ss +zzzz
 98.2831 + * . RFC-822:
 98.2832 + *    www, dd mmm yy hh:mm:ss zzz
 98.2833 + * . RFC-2822:
 98.2834 + *    www, dd mmm yyyy hh:mm:ss +zzzz
 98.2835 + */
 98.2836 +
 98.2837 +long mail_parse_date (MESSAGECACHE *elt,unsigned char *s)
 98.2838 +{
 98.2839 +  unsigned long d,m,y;
 98.2840 +  int mi,ms;
 98.2841 +  struct tm *t;
 98.2842 +  time_t tn;
 98.2843 +  char tmp[MAILTMPLEN];
 98.2844 +  static unsigned long maxyear = 0;
 98.2845 +  if (!maxyear) {		/* know the end of time yet? */
 98.2846 +    MESSAGECACHE tmpelt;
 98.2847 +    memset (&tmpelt,0xff,sizeof (MESSAGECACHE));
 98.2848 +    maxyear = BASEYEAR + tmpelt.year;
 98.2849 +  }
 98.2850 +				/* clear elt */
 98.2851 +  elt->zoccident = elt->zhours = elt->zminutes =
 98.2852 +    elt->hours = elt->minutes = elt->seconds =
 98.2853 +      elt->day = elt->month = elt->year = 0;
 98.2854 +				/* make a writeable uppercase copy */
 98.2855 +  if (s && *s && (strlen (s) < (size_t)MAILTMPLEN)) s = ucase (strcpy (tmp,s));
 98.2856 +  else return NIL;
 98.2857 +				/* skip over possible day of week */
 98.2858 +  if (isalpha (*s) && isalpha (s[1]) && isalpha (s[2]) && (s[3] == ',') &&
 98.2859 +      (s[4] == ' ')) s += 5;
 98.2860 +  while (*s == ' ') s++;	/* parse first number (probable month) */
 98.2861 +  if (!(m = strtoul (s,(char **) &s,10))) return NIL;
 98.2862 +
 98.2863 +  switch (*s) {			/* different parse based on delimiter */
 98.2864 +  case '/':			/* mm/dd/yy format */
 98.2865 +    if (isdigit (*++s) && (d = strtoul (s,(char **) &s,10)) &&
 98.2866 +	(*s == '/') && isdigit (*++s)) {
 98.2867 +      y = strtoul (s,(char **) &s,10);
 98.2868 +      if (*s == '\0') break;	/* must end here */
 98.2869 +    }
 98.2870 +    return NIL;			/* bogon */
 98.2871 +  case ' ':			/* dd mmm yy format */
 98.2872 +    while (s[1] == ' ') s++;	/* slurp extra whitespace */
 98.2873 +  case '-':
 98.2874 +    if (isdigit (s[1])) {	/* possible ISO 8601 date format? */
 98.2875 +      y = m;			/* yes, first number is year */
 98.2876 +				/* get month and day */
 98.2877 +      if ((m = strtoul (s+1,(char **) &s,10)) && (*s++ == '-') && 
 98.2878 +	  (d = strtoul (s,(char **) &s,10)) && !*s) break;
 98.2879 +      return NIL;		/* syntax error or time present */
 98.2880 +    }
 98.2881 +    d = m;			/* dd-mmm-yy[yy], so first number is a day */
 98.2882 +				/* make sure string long enough! */
 98.2883 +    if (strlen (s) < (size_t) 5) return NIL;
 98.2884 +    /* Some compilers don't allow `<<' and/or longs in case statements. */
 98.2885 +				/* slurp up the month string */
 98.2886 +    ms = ((s[1] - 'A') * 1024) + ((s[2] - 'A') * 32) + (s[3] - 'A');
 98.2887 +    switch (ms) {		/* determine the month */
 98.2888 +    case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break;
 98.2889 +    case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break;
 98.2890 +    case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break;
 98.2891 +    case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break;
 98.2892 +    case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break;
 98.2893 +    case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break;
 98.2894 +    case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break;
 98.2895 +    case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break;
 98.2896 +    case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break;
 98.2897 +    case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10; break;
 98.2898 +    case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11; break;
 98.2899 +    case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12; break;
 98.2900 +    default: return NIL;	/* unknown month */
 98.2901 +    }
 98.2902 +    if (s[4] == *s) s += 5;	/* advance to year */
 98.2903 +    else {			/* first three were OK, possibly full name */
 98.2904 +      mi = *s;			/* note delimiter, skip alphas */
 98.2905 +      for (s += 4; isalpha (*s); s++);
 98.2906 +				/* error if delimiter not here */
 98.2907 +      if (mi != *s++) return NIL;
 98.2908 +    }
 98.2909 +    while (*s == ' ') s++;	/* parse year */
 98.2910 +    if (isdigit (*s)) {		/* must be a digit here */
 98.2911 +      y = strtoul (s,(char **) &s,10);
 98.2912 +      if (*s == '\0' || *s == ' ') break;
 98.2913 +    }
 98.2914 +  case '\0':			/* ISO 8601 compact date */
 98.2915 +    if (m < (BASEYEAR * 10000)) return NIL;
 98.2916 +    y = m / 10000;		/* get year */
 98.2917 +    d = (m %= 10000) % 100;	/* get day */
 98.2918 +    m /= 100;			/* and month */
 98.2919 +    break;
 98.2920 +  default:
 98.2921 +    return NIL;			/* unknown date format */
 98.2922 +  }
 98.2923 +
 98.2924 +				/* minimal validity check of date */
 98.2925 +  if ((d > 31) || (m > 12)) return NIL; 
 98.2926 +  if (y < 49) y += 2000;	/* RFC 2282 rules for two digit years 00-49 */
 98.2927 +  else if (y < 999) y += 1900;	/* 2-digit years 50-99 and 3-digit years */
 98.2928 +				/* reject prehistoric and far future years */
 98.2929 +  if ((y < BASEYEAR) || (y > maxyear)) return NIL;
 98.2930 +				/* set values in elt */
 98.2931 +  elt->day = d; elt->month = m; elt->year = y - BASEYEAR;
 98.2932 +  ms = '\0';			/* initially no time zone string */
 98.2933 +  if (*s) {			/* time specification present? */
 98.2934 +				/* parse time */
 98.2935 +    d = strtoul (s+1,(char **) &s,10);
 98.2936 +    if (*s != ':') return NIL;
 98.2937 +    m = strtoul (++s,(char **) &s,10);
 98.2938 +    y = (*s == ':') ? strtoul (++s,(char **) &s,10) : 0;
 98.2939 +				/* validity check time */
 98.2940 +    if ((d > 23) || (m > 59) || (y > 60)) return NIL; 
 98.2941 +				/* set values in elt */
 98.2942 +    elt->hours = d; elt->minutes = m; elt->seconds = y;
 98.2943 +    switch (*s) {		/* time zone specifier? */
 98.2944 +    case ' ':			/* numeric time zone */
 98.2945 +      while (s[1] == ' ') s++;	/* slurp extra whitespace */
 98.2946 +      if (!isalpha (s[1])) {	/* treat as '-' case if alphabetic */
 98.2947 +				/* test for sign character */
 98.2948 +	if ((elt->zoccident = (*++s == '-')) || (*s == '+')) s++;
 98.2949 +				/* validate proper timezone */
 98.2950 +	if (isdigit(*s) && isdigit(s[1]) && isdigit(s[2]) && (s[2] < '6') &&
 98.2951 +	    isdigit(s[3])) {
 98.2952 +	  elt->zhours = (*s - '0') * 10 + (s[1] - '0');
 98.2953 +	  elt->zminutes = (s[2] - '0') * 10 + (s[3] - '0');
 98.2954 +	}
 98.2955 +	return T;		/* all done! */
 98.2956 +      }
 98.2957 +				/* falls through */
 98.2958 +    case '-':			/* symbolic time zone */
 98.2959 +      if (!(ms = *++s)) ms = 'Z';
 98.2960 +      else if (*++s) {		/* multi-character? */
 98.2961 +	ms -= 'A'; ms *= 1024;	/* yes, make compressed three-byte form */
 98.2962 +	ms += ((*s++ - 'A') * 32);
 98.2963 +	if (*s) ms += *s++ - 'A';
 98.2964 +	if (*s) ms = '\0';	/* more than three characters */
 98.2965 +      }
 98.2966 +    default:			/* ignore anything else */
 98.2967 +      break;
 98.2968 +    }
 98.2969 +  }
 98.2970 +
 98.2971 +  /*  This is not intended to be a comprehensive list of all possible
 98.2972 +   * timezone strings.  Such a list would be impractical.  Rather, this
 98.2973 +   * listing is intended to incorporate all military, North American, and
 98.2974 +   * a few special cases such as Japan and the major European zone names,
 98.2975 +   * such as what might be expected to be found in a Tenex format mailbox
 98.2976 +   * and spewed from an IMAP server.  The trend is to migrate to numeric
 98.2977 +   * timezones which lack the flavor but also the ambiguity of the names.
 98.2978 +   *
 98.2979 +   *  RFC-822 only recognizes UT, GMT, 1-letter military timezones, and the
 98.2980 +   * 4 CONUS timezones and their summer time variants.  [Sorry, Canadian
 98.2981 +   * Atlantic Provinces, Alaska, and Hawaii.]
 98.2982 +   */
 98.2983 +  switch (ms) {			/* determine the timezone */
 98.2984 +				/* Universal */
 98.2985 +  case (('U'-'A')*1024)+(('T'-'A')*32):
 98.2986 +#ifndef STRICT_RFC822_TIMEZONES
 98.2987 +  case (('U'-'A')*1024)+(('T'-'A')*32)+'C'-'A':
 98.2988 +#endif
 98.2989 +				/* Greenwich */
 98.2990 +  case (('G'-'A')*1024)+(('M'-'A')*32)+'T'-'A':
 98.2991 +  case 'Z': elt->zhours = 0; break;
 98.2992 +
 98.2993 +    /* oriental (from Greenwich) timezones */
 98.2994 +#ifndef STRICT_RFC822_TIMEZONES
 98.2995 +				/* Middle Europe */
 98.2996 +  case (('M'-'A')*1024)+(('E'-'A')*32)+'T'-'A':
 98.2997 +#endif
 98.2998 +#ifdef BRITISH_SUMMER_TIME
 98.2999 +				/* British Summer */
 98.3000 +  case (('B'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3001 +#endif
 98.3002 +  case 'A': elt->zhours = 1; break;
 98.3003 +#ifndef STRICT_RFC822_TIMEZONES
 98.3004 +				/* Eastern Europe */
 98.3005 +  case (('E'-'A')*1024)+(('E'-'A')*32)+'T'-'A':
 98.3006 +#endif
 98.3007 +  case 'B': elt->zhours = 2; break;
 98.3008 +  case 'C': elt->zhours = 3; break;
 98.3009 +  case 'D': elt->zhours = 4; break;
 98.3010 +  case 'E': elt->zhours = 5; break;
 98.3011 +  case 'F': elt->zhours = 6; break;
 98.3012 +  case 'G': elt->zhours = 7; break;
 98.3013 +  case 'H': elt->zhours = 8; break;
 98.3014 +#ifndef STRICT_RFC822_TIMEZONES
 98.3015 +				/* Japan */
 98.3016 +  case (('J'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3017 +#endif
 98.3018 +  case 'I': elt->zhours = 9; break;
 98.3019 +  case 'K': elt->zhours = 10; break;
 98.3020 +  case 'L': elt->zhours = 11; break;
 98.3021 +  case 'M': elt->zhours = 12; break;
 98.3022 +
 98.3023 +	/* occidental (from Greenwich) timezones */
 98.3024 +  case 'N': elt->zoccident = 1; elt->zhours = 1; break;
 98.3025 +  case 'O': elt->zoccident = 1; elt->zhours = 2; break;
 98.3026 +#ifndef STRICT_RFC822_TIMEZONES
 98.3027 +  case (('A'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
 98.3028 +#endif
 98.3029 +  case 'P': elt->zoccident = 1; elt->zhours = 3; break;
 98.3030 +#ifdef NEWFOUNDLAND_STANDARD_TIME
 98.3031 +				/* Newfoundland */
 98.3032 +  case (('N'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3033 +    elt->zoccident = 1; elt->zhours = 3; elt->zminutes = 30; break;
 98.3034 +#endif
 98.3035 +#ifndef STRICT_RFC822_TIMEZONES
 98.3036 +				/* Atlantic */
 98.3037 +  case (('A'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3038 +#endif
 98.3039 +	/* CONUS */
 98.3040 +  case (('E'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
 98.3041 +  case 'Q': elt->zoccident = 1; elt->zhours = 4; break;
 98.3042 +				/* Eastern */
 98.3043 +  case (('E'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3044 +  case (('C'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
 98.3045 +  case 'R': elt->zoccident = 1; elt->zhours = 5; break;
 98.3046 +				/* Central */
 98.3047 +  case (('C'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3048 +  case (('M'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
 98.3049 +  case 'S': elt->zoccident = 1; elt->zhours = 6; break;
 98.3050 +				/* Mountain */
 98.3051 +  case (('M'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3052 +  case (('P'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
 98.3053 +  case 'T': elt->zoccident = 1; elt->zhours = 7; break;
 98.3054 +				/* Pacific */
 98.3055 +  case (('P'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3056 +#ifndef STRICT_RFC822_TIMEZONES
 98.3057 +  case (('Y'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
 98.3058 +#endif
 98.3059 +  case 'U': elt->zoccident = 1; elt->zhours = 8; break;
 98.3060 +#ifndef STRICT_RFC822_TIMEZONES
 98.3061 +				/* Yukon */
 98.3062 +  case (('Y'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3063 +#endif
 98.3064 +  case 'V': elt->zoccident = 1; elt->zhours = 9; break;
 98.3065 +#ifndef STRICT_RFC822_TIMEZONES
 98.3066 +				/* Hawaii */
 98.3067 +  case (('H'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3068 +#endif
 98.3069 +  case 'W': elt->zoccident = 1; elt->zhours = 10; break;
 98.3070 +				/* Nome/Bering/Samoa */
 98.3071 +#ifdef NOME_STANDARD_TIME
 98.3072 +  case (('N'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3073 +#endif
 98.3074 +#ifdef BERING_STANDARD_TIME
 98.3075 +  case (('B'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3076 +#endif
 98.3077 +#ifdef SAMOA_STANDARD_TIME
 98.3078 +  case (('S'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
 98.3079 +#endif
 98.3080 +  case 'X': elt->zoccident = 1; elt->zhours = 11; break;
 98.3081 +  case 'Y': elt->zoccident = 1; elt->zhours = 12; break;
 98.3082 +
 98.3083 +  default:			/* unknown time zones treated as local */
 98.3084 +    tn = time (0);		/* time now... */
 98.3085 +    t = localtime (&tn);	/* get local minutes since midnight */
 98.3086 +    mi = t->tm_hour * 60 + t->tm_min;
 98.3087 +    ms = t->tm_yday;		/* note Julian day */
 98.3088 +    if (t = gmtime (&tn)) {	/* minus UTC minutes since midnight */
 98.3089 +      mi -= t->tm_hour * 60 + t->tm_min;
 98.3090 +	/* ms can be one of:
 98.3091 +	 *  36x  local time is December 31, UTC is January 1, offset -24 hours
 98.3092 +	 *    1  local time is 1 day ahead of UTC, offset +24 hours
 98.3093 +	 *    0  local time is same day as UTC, no offset
 98.3094 +	 *   -1  local time is 1 day behind UTC, offset -24 hours
 98.3095 +	 * -36x  local time is January 1, UTC is December 31, offset +24 hours
 98.3096 +	 */
 98.3097 +      if (ms -= t->tm_yday)	/* correct offset if different Julian day */
 98.3098 +	mi += ((ms < 0) == (abs (ms) == 1)) ? -24*60 : 24*60;
 98.3099 +      if (mi < 0) {		/* occidental? */
 98.3100 +	mi = abs (mi);		/* yup, make positive number */
 98.3101 +	elt->zoccident = 1;	/* and note west of UTC */
 98.3102 +      }
 98.3103 +      elt->zhours = mi / 60;	/* now break into hours and minutes */
 98.3104 +      elt->zminutes = mi % 60;
 98.3105 +    }
 98.3106 +    break;
 98.3107 +  }
 98.3108 +  return T;
 98.3109 +}
 98.3110 +
 98.3111 +/* Mail n messages exist
 98.3112 + * Accepts: mail stream
 98.3113 + *	    number of messages
 98.3114 + */
 98.3115 +
 98.3116 +void mail_exists (MAILSTREAM *stream,unsigned long nmsgs)
 98.3117 +{
 98.3118 +  char tmp[MAILTMPLEN];
 98.3119 +  if (nmsgs > MAXMESSAGES) {
 98.3120 +    sprintf (tmp,"Mailbox has more messages (%lu) exist than maximum (%lu)",
 98.3121 +	     nmsgs,MAXMESSAGES);
 98.3122 +    mm_log (tmp,ERROR);
 98.3123 +    nmsgs = MAXMESSAGES;	/* cap to maximum */
 98.3124 +    /* probably will crash in mail_elt() soon enough... */
 98.3125 +  }
 98.3126 +				/* make sure cache is large enough */
 98.3127 +  (*mailcache) (stream,nmsgs,CH_SIZE);
 98.3128 +  stream->nmsgs = nmsgs;	/* update stream status */
 98.3129 +				/* notify main program of change */
 98.3130 +  if (!stream->silent) MM_EXISTS (stream,nmsgs);
 98.3131 +}
 98.3132 +
 98.3133 +
 98.3134 +/* Mail n messages are recent
 98.3135 + * Accepts: mail stream
 98.3136 + *	    number of recent messages
 98.3137 + */
 98.3138 +
 98.3139 +void mail_recent (MAILSTREAM *stream,unsigned long recent)
 98.3140 +{
 98.3141 +  char tmp[MAILTMPLEN];
 98.3142 +  if (recent <= stream->nmsgs) stream->recent = recent;
 98.3143 +  else {
 98.3144 +    sprintf (tmp,"Non-existent recent message(s) %lu, nmsgs=%lu",
 98.3145 +	     recent,stream->nmsgs);
 98.3146 +    mm_log (tmp,ERROR);
 98.3147 +  }
 98.3148 +}
 98.3149 +
 98.3150 +
 98.3151 +/* Mail message n is expunged
 98.3152 + * Accepts: mail stream
 98.3153 + *	    message #
 98.3154 + */
 98.3155 +
 98.3156 +void mail_expunged (MAILSTREAM *stream,unsigned long msgno)
 98.3157 +{
 98.3158 +  char tmp[MAILTMPLEN];
 98.3159 +  MESSAGECACHE *elt;
 98.3160 +  if (msgno > stream->nmsgs) {
 98.3161 +    sprintf (tmp,"Expunge of non-existent message %lu, nmsgs=%lu",
 98.3162 +	     msgno,stream->nmsgs);
 98.3163 +    mm_log (tmp,ERROR);
 98.3164 +  }
 98.3165 +  else {
 98.3166 +    elt = (MESSAGECACHE *) (*mailcache) (stream,msgno,CH_ELT);
 98.3167 +				/* notify main program of change */
 98.3168 +    if (!stream->silent) MM_EXPUNGED (stream,msgno);
 98.3169 +    if (elt) {			/* if an element is there */
 98.3170 +      elt->msgno = 0;		/* invalidate its message number and free */
 98.3171 +      (*mailcache) (stream,msgno,CH_FREE);
 98.3172 +      (*mailcache) (stream,msgno,CH_FREESORTCACHE);
 98.3173 +    }
 98.3174 +				/* expunge the slot */
 98.3175 +    (*mailcache) (stream,msgno,CH_EXPUNGE);
 98.3176 +    --stream->nmsgs;		/* update stream status */
 98.3177 +    if (stream->msgno) {	/* have stream pointers? */
 98.3178 +				/* make sure the short cache is nuked */
 98.3179 +      if (stream->scache) mail_gc (stream,GC_ENV | GC_TEXTS);
 98.3180 +      else stream->msgno = 0;	/* make sure invalidated in any case */
 98.3181 +    }
 98.3182 +  }
 98.3183 +}
 98.3184 +
 98.3185 +/* Mail stream status routines */
 98.3186 +
 98.3187 +
 98.3188 +/* Mail lock stream
 98.3189 + * Accepts: mail stream
 98.3190 + */
 98.3191 +
 98.3192 +void mail_lock (MAILSTREAM *stream)
 98.3193 +{
 98.3194 +  if (stream->lock) {
 98.3195 +    char tmp[MAILTMPLEN];
 98.3196 +    sprintf (tmp,"Lock when already locked, mbx=%.80s",
 98.3197 +	     stream->mailbox ? stream->mailbox : "???");
 98.3198 +    fatal (tmp);
 98.3199 +  }
 98.3200 +  else stream->lock = T;	/* lock stream */
 98.3201 +}
 98.3202 +
 98.3203 +
 98.3204 +/* Mail unlock stream
 98.3205 + * Accepts: mail stream
 98.3206 + */
 98.3207 + 
 98.3208 +void mail_unlock (MAILSTREAM *stream)
 98.3209 +{
 98.3210 +  if (!stream->lock) fatal ("Unlock when not locked");
 98.3211 +  else stream->lock = NIL;	/* unlock stream */
 98.3212 +}
 98.3213 +
 98.3214 +
 98.3215 +/* Mail turn on debugging telemetry
 98.3216 + * Accepts: mail stream
 98.3217 + */
 98.3218 +
 98.3219 +void mail_debug (MAILSTREAM *stream)
 98.3220 +{
 98.3221 +  stream->debug = T;		/* turn on debugging telemetry */
 98.3222 +  if (stream->dtb) (*stream->dtb->parameters) (ENABLE_DEBUG,stream);
 98.3223 +}
 98.3224 +
 98.3225 +
 98.3226 +/* Mail turn off debugging telemetry
 98.3227 + * Accepts: mail stream
 98.3228 + */
 98.3229 +
 98.3230 +void mail_nodebug (MAILSTREAM *stream)
 98.3231 +{
 98.3232 +  stream->debug = NIL;		/* turn off debugging telemetry */
 98.3233 +  if (stream->dtb) (*stream->dtb->parameters) (DISABLE_DEBUG,stream);
 98.3234 +}
 98.3235 +
 98.3236 +
 98.3237 +/* Mail log to debugging telemetry
 98.3238 + * Accepts: message
 98.3239 + *	    flag that data is "sensitive"
 98.3240 + */
 98.3241 +
 98.3242 +void mail_dlog (char *string,long flag)
 98.3243 +{
 98.3244 +  mm_dlog ((debugsensitive || !flag) ? string : "<suppressed>");
 98.3245 +}
 98.3246 +
 98.3247 +/* Mail parse UID sequence
 98.3248 + * Accepts: mail stream
 98.3249 + *	    sequence to parse
 98.3250 + * Returns: T if parse successful, else NIL
 98.3251 + */
 98.3252 +
 98.3253 +long mail_uid_sequence (MAILSTREAM *stream,unsigned char *sequence)
 98.3254 +{
 98.3255 +  unsigned long i,j,k,x,y;
 98.3256 +  for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL;
 98.3257 +  while (sequence && *sequence){/* while there is something to parse */
 98.3258 +    if (*sequence == '*') {	/* maximum message */
 98.3259 +      i = stream->nmsgs ? mail_uid (stream,stream->nmsgs) : stream->uid_last;
 98.3260 +      sequence++;		/* skip past * */
 98.3261 +    }
 98.3262 +				/* parse and validate message number */
 98.3263 +				/* parse and validate message number */
 98.3264 +    else if (!isdigit (*sequence)) {
 98.3265 +      MM_LOG ("Syntax error in sequence",ERROR);
 98.3266 +      return NIL;
 98.3267 +    }
 98.3268 +    else if (!(i = strtoul (sequence,(char **) &sequence,10))) {
 98.3269 +      MM_LOG ("UID may not be zero",ERROR);
 98.3270 +      return NIL;
 98.3271 +    }
 98.3272 +    switch (*sequence) {	/* see what the delimiter is */
 98.3273 +    case ':':			/* sequence range */
 98.3274 +      if (*++sequence == '*') {	/* maximum message */
 98.3275 +	j = stream->nmsgs ? mail_uid (stream,stream->nmsgs) : stream->uid_last;
 98.3276 +	sequence++;		/* skip past * */
 98.3277 +      }
 98.3278 +				/* parse end of range */
 98.3279 +      else if (!(j = strtoul (sequence,(char **) &sequence,10))) {
 98.3280 +	MM_LOG ("UID sequence range invalid",ERROR);
 98.3281 +	return NIL;
 98.3282 +      }
 98.3283 +      if (*sequence && *sequence++ != ',') {
 98.3284 +	MM_LOG ("UID sequence range syntax error",ERROR);
 98.3285 +	return NIL;
 98.3286 +      }
 98.3287 +      if (i > j) {		/* swap the range if backwards */
 98.3288 +	x = i; i = j; j = x;
 98.3289 +      }
 98.3290 +      x = mail_msgno (stream,i);/* get msgnos */
 98.3291 +      y = mail_msgno (stream,j);/* for both UIDS (don't && it) */
 98.3292 +				/* easy if both UIDs valid */
 98.3293 +      if (x && y) while (x <= y) mail_elt (stream,x++)->sequence = T;
 98.3294 +				/* start UID valid, end is not */
 98.3295 +      else if (x) while ((x <= stream->nmsgs) && (mail_uid (stream,x) <= j))
 98.3296 +	mail_elt (stream,x++)->sequence = T;
 98.3297 +				/* end UID valid, start is not */
 98.3298 +      else if (y) for (x = 1; x <= y; x++) {
 98.3299 +	if (mail_uid (stream,x) >= i) mail_elt (stream,x)->sequence = T;
 98.3300 +      }
 98.3301 +				/* neither is valid, ugh */
 98.3302 +      else for (x = 1; x <= stream->nmsgs; x++)
 98.3303 +	if (((k = mail_uid (stream,x)) >= i) && (k <= j))
 98.3304 +	  mail_elt (stream,x)->sequence = T;
 98.3305 +      break;
 98.3306 +    case ',':			/* single message */
 98.3307 +      ++sequence;		/* skip the delimiter, fall into end case */
 98.3308 +    case '\0':			/* end of sequence, mark this message */
 98.3309 +      if (x = mail_msgno (stream,i)) mail_elt (stream,x)->sequence = T;
 98.3310 +      break;
 98.3311 +    default:			/* anything else is a syntax error! */
 98.3312 +      MM_LOG ("UID sequence syntax error",ERROR);
 98.3313 +      return NIL;
 98.3314 +    }
 98.3315 +  }
 98.3316 +  return T;			/* successfully parsed sequence */
 98.3317 +}
 98.3318 +
 98.3319 +/* Mail see if line list matches that in cache
 98.3320 + * Accepts: candidate line list
 98.3321 + *	    cached line list
 98.3322 + *	    matching flags
 98.3323 + * Returns: T if match, NIL if no match
 98.3324 + */
 98.3325 +
 98.3326 +long mail_match_lines (STRINGLIST *lines,STRINGLIST *msglines,long flags)
 98.3327 +{
 98.3328 +  unsigned long i;
 98.3329 +  unsigned char *s,*t;
 98.3330 +  STRINGLIST *m;
 98.3331 +  if (!msglines) return T;	/* full header is in cache */
 98.3332 +				/* need full header but filtered in cache */
 98.3333 +  if ((flags & FT_NOT) || !lines) return NIL;
 98.3334 +  do {				/* make sure all present & accounted for */
 98.3335 +    for (m = msglines; m; m = m->next) if (lines->text.size == m->text.size) {
 98.3336 +      for (s = lines->text.data,t = m->text.data,i = lines->text.size;
 98.3337 +	   i && !compare_uchar (*s,*t); s++,t++,i--);
 98.3338 +      if (!i) break;		/* this line matches */
 98.3339 +    }
 98.3340 +    if (!m) return NIL;		/* didn't find in the list */
 98.3341 +  }
 98.3342 +  while (lines = lines->next);
 98.3343 +  return T;			/* all lines found */
 98.3344 +}
 98.3345 +
 98.3346 +/* Mail filter text by header lines
 98.3347 + * Accepts: text to filter, with trailing null
 98.3348 + *	    length of text
 98.3349 + *	    list of lines
 98.3350 + *	    fetch flags
 98.3351 + * Returns: new text size, text overwritten
 98.3352 + */
 98.3353 +
 98.3354 +unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
 98.3355 +			   long flags)
 98.3356 +{
 98.3357 +  STRINGLIST *hdrs;
 98.3358 +  int notfound;
 98.3359 +  unsigned long i;
 98.3360 +  char c,*s,*e,*t,tmp[MAILTMPLEN];
 98.3361 +  char *src = text;
 98.3362 +  char *dst = src;
 98.3363 +  char *end = text + len;
 98.3364 +  text[len] = '\012';		/* guard against running off buffer */
 98.3365 +  while (src < end) {		/* process header */
 98.3366 +				/* slurp header line name */
 98.3367 +    for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp;
 98.3368 +	 (s < e) && ((c = (*s ? *s : (*s = ' '))) != ':') &&
 98.3369 +	 ((c > ' ') ||
 98.3370 +	  ((c != ' ') && (c != '\t') && (c != '\015') && (c != '\012')));
 98.3371 +	 *t++ = *s++);
 98.3372 +    *t = '\0';			/* tie off */
 98.3373 +    notfound = T;		/* not found yet */
 98.3374 +    if (i = t - tmp)		/* see if found in header */
 98.3375 +      for (hdrs = lines; hdrs && notfound; hdrs = hdrs->next)
 98.3376 +	if ((hdrs->text.size == i) && !compare_csizedtext (tmp,&hdrs->text))
 98.3377 +	  notfound = NIL;
 98.3378 +				/* skip header line if not wanted */
 98.3379 +    if (i && ((flags & FT_NOT) ? !notfound : notfound))
 98.3380 +      while (((*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
 98.3381 +	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
 98.3382 +	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
 98.3383 +	      (*src++ != '\012')) || ((*src == ' ') || (*src == '\t')));
 98.3384 +    else if (src == dst) {	/* copy to self */
 98.3385 +      while (((*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
 98.3386 +	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
 98.3387 +	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
 98.3388 +	      (*src++ != '\012')) || ((*src == ' ') || (*src == '\t')));
 98.3389 +      dst = src;		/* update destination */
 98.3390 +    }
 98.3391 +    else {			/* copy line and any continuation line */
 98.3392 +      while ((((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
 98.3393 +	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
 98.3394 +	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
 98.3395 +	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
 98.3396 +	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012'))||
 98.3397 +	     ((*src == ' ') || (*src == '\t')));
 98.3398 +				/* in case hit the guard LF */
 98.3399 +      if (src > end) dst -= (src - end);
 98.3400 +    }
 98.3401 +  }
 98.3402 +  *dst = '\0';			/* tie off destination */
 98.3403 +  return dst - text;
 98.3404 +}
 98.3405 +
 98.3406 +/* Local mail search message
 98.3407 + * Accepts: MAIL stream
 98.3408 + *	    message number
 98.3409 + *	    optional section specification
 98.3410 + *	    search program
 98.3411 + * Returns: T if found, NIL otherwise
 98.3412 + */
 98.3413 +
 98.3414 +long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.3415 +		      SEARCHPGM *pgm)
 98.3416 +{
 98.3417 +  unsigned short d;
 98.3418 +  char tmp[MAILTMPLEN];
 98.3419 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
 98.3420 +  SEARCHHEADER *hdr;
 98.3421 +  SEARCHOR *or;
 98.3422 +  SEARCHPGMLIST *not;
 98.3423 +  unsigned long now = (unsigned long) time (0);
 98.3424 +  if (pgm->msgno || pgm->uid) {	/* message set searches */
 98.3425 +    SEARCHSET *set;
 98.3426 +				/* message sequences */
 98.3427 +    if (pgm->msgno) {		/* inside this message sequence set */
 98.3428 +      for (set = pgm->msgno; set; set = set->next)
 98.3429 +	if (set->last ? ((set->first <= set->last) ?
 98.3430 +			 ((msgno >= set->first) && (msgno <= set->last)) :
 98.3431 +			 ((msgno >= set->last) && (msgno <= set->first))) :
 98.3432 +	    msgno == set->first) break;
 98.3433 +      if (!set) return NIL;	/* not found within sequence */
 98.3434 +    }
 98.3435 +    if (pgm->uid) {		/* inside this unique identifier set */
 98.3436 +      unsigned long uid = mail_uid (stream,msgno);
 98.3437 +      for (set = pgm->uid; set; set = set->next)
 98.3438 +	if (set->last ? ((set->first <= set->last) ?
 98.3439 +			 ((uid >= set->first) && (uid <= set->last)) :
 98.3440 +			 ((uid >= set->last) && (uid <= set->first))) :
 98.3441 +	    uid == set->first) break;
 98.3442 +      if (!set) return NIL;	/* not found within sequence */
 98.3443 +    }
 98.3444 +  }
 98.3445 +
 98.3446 +  /* Fast data searches */
 98.3447 +				/* need to fetch fast data? */
 98.3448 +  if ((!elt->rfc822_size && (pgm->larger || pgm->smaller)) ||
 98.3449 +      (!elt->year && (pgm->before || pgm->on || pgm->since ||
 98.3450 +		      pgm->older || pgm->younger)) ||
 98.3451 +      (!elt->valid && (pgm->answered || pgm->unanswered ||
 98.3452 +		       pgm->deleted || pgm->undeleted ||
 98.3453 +		       pgm->draft || pgm->undraft ||
 98.3454 +		       pgm->flagged || pgm->unflagged ||
 98.3455 +		       pgm->recent || pgm->old ||
 98.3456 +		       pgm->seen || pgm->unseen ||
 98.3457 +		       pgm->keyword || pgm->unkeyword))) {
 98.3458 +    unsigned long i;
 98.3459 +    MESSAGECACHE *ielt;
 98.3460 +    for (i = elt->msgno;	/* find last unloaded message in range */
 98.3461 +	 (i < stream->nmsgs) && (ielt = mail_elt (stream,i+1)) &&
 98.3462 +	   ((!ielt->rfc822_size && (pgm->larger || pgm->smaller)) ||
 98.3463 +	    (!ielt->year && (pgm->before || pgm->on || pgm->since ||
 98.3464 +			     pgm->older || pgm->younger)) ||
 98.3465 +	    (!ielt->valid && (pgm->answered || pgm->unanswered ||
 98.3466 +			      pgm->deleted || pgm->undeleted ||
 98.3467 +			      pgm->draft || pgm->undraft ||
 98.3468 +			      pgm->flagged || pgm->unflagged ||
 98.3469 +			      pgm->recent || pgm->old ||
 98.3470 +			      pgm->seen || pgm->unseen ||
 98.3471 +			      pgm->keyword || pgm->unkeyword))); ++i);
 98.3472 +    if (i == elt->msgno) sprintf (tmp,"%lu",elt->msgno);
 98.3473 +    else sprintf (tmp,"%lu:%lu",elt->msgno,i);
 98.3474 +    mail_fetch_fast (stream,tmp,NIL);
 98.3475 +  }
 98.3476 +				/* size ranges */
 98.3477 +  if ((pgm->larger && (elt->rfc822_size <= pgm->larger)) ||
 98.3478 +      (pgm->smaller && (elt->rfc822_size >= pgm->smaller))) return NIL;
 98.3479 +				/* message flags */
 98.3480 +  if ((pgm->answered && !elt->answered) ||
 98.3481 +      (pgm->unanswered && elt->answered) ||
 98.3482 +      (pgm->deleted && !elt->deleted) ||
 98.3483 +      (pgm->undeleted && elt->deleted) ||
 98.3484 +      (pgm->draft && !elt->draft) ||
 98.3485 +      (pgm->undraft && elt->draft) ||
 98.3486 +      (pgm->flagged && !elt->flagged) ||
 98.3487 +      (pgm->unflagged && elt->flagged) ||
 98.3488 +      (pgm->recent && !elt->recent) ||
 98.3489 +      (pgm->old && elt->recent) ||
 98.3490 +      (pgm->seen && !elt->seen) ||
 98.3491 +      (pgm->unseen && elt->seen)) return NIL;
 98.3492 +				/* keywords */
 98.3493 +  if ((pgm->keyword && !mail_search_keyword (stream,elt,pgm->keyword,LONGT)) ||
 98.3494 +      (pgm->unkeyword && !mail_search_keyword (stream,elt,pgm->unkeyword,NIL)))
 98.3495 +    return NIL;
 98.3496 +				/* internal date ranges */
 98.3497 +  if (pgm->before || pgm->on || pgm->since) {
 98.3498 +    d = mail_shortdate (elt->year,elt->month,elt->day);
 98.3499 +    if (pgm->before && (d >= pgm->before)) return NIL;
 98.3500 +    if (pgm->on && (d != pgm->on)) return NIL;
 98.3501 +    if (pgm->since && (d < pgm->since)) return NIL;
 98.3502 +  }
 98.3503 +  if (pgm->older || pgm->younger) {
 98.3504 +    unsigned long msgd = mail_longdate (elt);
 98.3505 +    if (pgm->older && msgd > (now - pgm->older)) return NIL;
 98.3506 +    if (pgm->younger && msgd < (now - pgm->younger)) return NIL;
 98.3507 +  }
 98.3508 +
 98.3509 +				/* envelope searches */
 98.3510 +  if (pgm->sentbefore || pgm->senton || pgm->sentsince ||
 98.3511 +      pgm->bcc || pgm->cc || pgm->from || pgm->to || pgm->subject ||
 98.3512 +      pgm->return_path || pgm->sender || pgm->reply_to || pgm->in_reply_to ||
 98.3513 +      pgm->message_id || pgm->newsgroups || pgm->followup_to ||
 98.3514 +      pgm->references) {
 98.3515 +    ENVELOPE *env;
 98.3516 +    MESSAGECACHE delt;
 98.3517 +    if (section) {		/* use body part envelope */
 98.3518 +      BODY *body = mail_body (stream,msgno,section);
 98.3519 +      env = (body && (body->type == TYPEMESSAGE) && body->subtype &&
 98.3520 +	     !strcmp (body->subtype,"RFC822")) ? body->nested.msg->env : NIL;
 98.3521 +    }
 98.3522 +    else {			/* use top level envelope if no section */
 98.3523 +      if (pgm->header && !stream->scache && !(stream->dtb->flags & DR_LOCAL))
 98.3524 +	mail_fetch_header(stream,msgno,NIL,NIL,NIL,FT_PEEK|FT_SEARCHLOOKAHEAD);
 98.3525 +      env = mail_fetchenvelope (stream,msgno);
 98.3526 +    }
 98.3527 +    if (!env) return NIL;	/* no envelope obtained */
 98.3528 +				/* sent date ranges */
 98.3529 +    if ((pgm->sentbefore || pgm->senton || pgm->sentsince) &&
 98.3530 +	(!mail_parse_date (&delt,env->date) ||
 98.3531 +	 !(d = mail_shortdate (delt.year,delt.month,delt.day)) ||
 98.3532 +	 (pgm->sentbefore && (d >= pgm->sentbefore)) ||
 98.3533 +	 (pgm->senton && (d != pgm->senton)) ||
 98.3534 +	 (pgm->sentsince && (d < pgm->sentsince)))) return NIL;
 98.3535 +				/* search headers */
 98.3536 +    if ((pgm->bcc && !mail_search_addr (env->bcc,pgm->bcc)) ||
 98.3537 +	(pgm->cc && !mail_search_addr (env->cc,pgm->cc)) ||
 98.3538 +	(pgm->from && !mail_search_addr (env->from,pgm->from)) ||
 98.3539 +	(pgm->to && !mail_search_addr (env->to,pgm->to)) ||
 98.3540 +	(pgm->subject && !mail_search_header_text (env->subject,pgm->subject)))
 98.3541 +      return NIL;
 98.3542 +    /* These criteria are not supported by IMAP and have to be emulated */
 98.3543 +    if ((pgm->return_path &&
 98.3544 +	 !mail_search_addr (env->return_path,pgm->return_path)) ||
 98.3545 +	(pgm->sender && !mail_search_addr (env->sender,pgm->sender)) ||
 98.3546 +	(pgm->reply_to && !mail_search_addr (env->reply_to,pgm->reply_to)) ||
 98.3547 +	(pgm->in_reply_to &&
 98.3548 +	 !mail_search_header_text (env->in_reply_to,pgm->in_reply_to)) ||
 98.3549 +	(pgm->message_id &&
 98.3550 +	!mail_search_header_text (env->message_id,pgm->message_id)) ||
 98.3551 +	(pgm->newsgroups &&
 98.3552 +	 !mail_search_header_text (env->newsgroups,pgm->newsgroups)) ||
 98.3553 +	(pgm->followup_to &&
 98.3554 +	 !mail_search_header_text (env->followup_to,pgm->followup_to)) ||
 98.3555 +	(pgm->references &&
 98.3556 +	 !mail_search_header_text (env->references,pgm->references)))
 98.3557 +      return NIL;
 98.3558 +  }
 98.3559 +
 98.3560 +				/* search header lines */
 98.3561 +  for (hdr = pgm->header; hdr; hdr = hdr->next) {
 98.3562 +    char *t,*e,*v;
 98.3563 +    SIZEDTEXT s;
 98.3564 +    STRINGLIST sth,stc;
 98.3565 +    sth.next = stc.next = NIL;	/* only one at a time */
 98.3566 +    sth.text.data = hdr->line.data;
 98.3567 +    sth.text.size = hdr->line.size;
 98.3568 +				/* get the header text */
 98.3569 +    if ((t = mail_fetch_header (stream,msgno,NIL,&sth,&s.size,
 98.3570 +				FT_INTERNAL | FT_PEEK |
 98.3571 +				(section ? NIL : FT_SEARCHLOOKAHEAD))) &&
 98.3572 +	strchr (t,':')) {
 98.3573 +      if (hdr->text.size) {	/* anything matches empty search string */
 98.3574 +				/* non-empty, copy field data */
 98.3575 +	s.data = (unsigned char *) fs_get (s.size + 1);
 98.3576 +				/* for each line */
 98.3577 +	for (v = (char *) s.data, e = t + s.size; t < e;) switch (*t) {
 98.3578 +	default:		/* non-continuation, skip leading field name */
 98.3579 +	  while ((t < e) && (*t++ != ':'));
 98.3580 +	  if ((t < e) && (*t == ':')) t++;
 98.3581 +	case '\t': case ' ':	/* copy field data  */
 98.3582 +	  while ((t < e) && (*t != '\015') && (*t != '\012')) *v++ = *t++;
 98.3583 +	  *v++ = '\n';		/* tie off line */
 98.3584 +	  while (((*t == '\015') || (*t == '\012')) && (t < e)) t++;
 98.3585 +	}
 98.3586 +				/* calculate true size */
 98.3587 +	s.size = v - (char *) s.data;
 98.3588 +	*v = '\0';		/* tie off results */
 98.3589 +	stc.text.data = hdr->text.data;
 98.3590 +	stc.text.size = hdr->text.size;
 98.3591 +				/* search header */
 98.3592 +	if (mail_search_header (&s,&stc)) fs_give ((void **) &s.data);
 98.3593 +	else {			/* search failed */
 98.3594 +	  fs_give ((void **) &s.data);
 98.3595 +	  return NIL;
 98.3596 +	}
 98.3597 +      }
 98.3598 +    }
 98.3599 +    else return NIL;		/* no matching header text */
 98.3600 +  }
 98.3601 +				/* search strings */
 98.3602 +  if ((pgm->text && !mail_search_text (stream,msgno,section,pgm->text,LONGT))||
 98.3603 +      (pgm->body && !mail_search_text (stream,msgno,section,pgm->body,NIL)))
 98.3604 +    return NIL;
 98.3605 +				/* logical conditions */
 98.3606 +  for (or = pgm->or; or; or = or->next)
 98.3607 +    if (!(mail_search_msg (stream,msgno,section,or->first) ||
 98.3608 +	  mail_search_msg (stream,msgno,section,or->second))) return NIL;
 98.3609 +  for (not = pgm->not; not; not = not->next)
 98.3610 +    if (mail_search_msg (stream,msgno,section,not->pgm)) return NIL;
 98.3611 +  return T;
 98.3612 +}
 98.3613 +
 98.3614 +/* Mail search message header null-terminated text
 98.3615 + * Accepts: header text
 98.3616 + *	    strings to search
 98.3617 + * Returns: T if search found a match
 98.3618 + */
 98.3619 +
 98.3620 +long mail_search_header_text (char *s,STRINGLIST *st)
 98.3621 +{
 98.3622 +  SIZEDTEXT h;
 98.3623 +				/* have any text? */
 98.3624 +  if (h.data = (unsigned char *) s) {
 98.3625 +    h.size = strlen (s);	/* yes, get its size */
 98.3626 +    return mail_search_header (&h,st);
 98.3627 +  }
 98.3628 +  return NIL;
 98.3629 +}
 98.3630 +
 98.3631 +
 98.3632 +/* Mail search message header
 98.3633 + * Accepts: header as sized text
 98.3634 + *	    strings to search
 98.3635 + * Returns: T if search found a match
 98.3636 + */
 98.3637 +
 98.3638 +long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st)
 98.3639 +{
 98.3640 +  SIZEDTEXT h;
 98.3641 +  long ret = LONGT;
 98.3642 +				/* make UTF-8 version of header */
 98.3643 +  utf8_mime2text (hdr,&h,U8T_CANONICAL);
 98.3644 +  while (h.size && ((h.data[h.size-1]=='\015') || (h.data[h.size-1]=='\012')))
 98.3645 +    --h.size;			/* slice off trailing newlines */
 98.3646 +  do if (h.size ?		/* search non-empty string */
 98.3647 +	 !ssearch (h.data,h.size,st->text.data,st->text.size) : st->text.size)
 98.3648 +    ret = NIL;
 98.3649 +  while (ret && (st = st->next));
 98.3650 +  if (h.data != hdr->data) fs_give ((void **) &h.data);
 98.3651 +  return ret;
 98.3652 +}
 98.3653 +
 98.3654 +/* Mail search message body
 98.3655 + * Accepts: MAIL stream
 98.3656 + *	    message number
 98.3657 + *	    optional section specification
 98.3658 + *	    string list
 98.3659 + *	    flags
 98.3660 + * Returns: T if search found a match
 98.3661 + */
 98.3662 +
 98.3663 +long mail_search_text (MAILSTREAM *stream,unsigned long msgno,char *section,
 98.3664 +		       STRINGLIST *st,long flags)
 98.3665 +{
 98.3666 +  BODY *body;
 98.3667 +  long ret = NIL;
 98.3668 +  STRINGLIST *s = mail_newstringlist ();
 98.3669 +  mailgets_t omg = mailgets;
 98.3670 +  if (stream->dtb->flags & DR_LOWMEM) mailgets = mail_search_gets;
 98.3671 +				/* strings to search */
 98.3672 +  for (stream->private.search.string = s; st;) {
 98.3673 +    s->text.data = st->text.data;
 98.3674 +    s->text.size = st->text.size;
 98.3675 +    if (st = st->next) s = s->next = mail_newstringlist ();
 98.3676 +  }
 98.3677 +  stream->private.search.text = NIL;
 98.3678 +  if (flags) {			/* want header? */
 98.3679 +    SIZEDTEXT s,t;
 98.3680 +    s.data = (unsigned char *)
 98.3681 +      mail_fetch_header (stream,msgno,section,NIL,&s.size,FT_INTERNAL|FT_PEEK);
 98.3682 +    utf8_mime2text (&s,&t,U8T_CANONICAL);
 98.3683 +    ret = mail_search_string_work (&t,&stream->private.search.string);
 98.3684 +    if (t.data != s.data) fs_give ((void **) &t.data);
 98.3685 +  }
 98.3686 +  if (!ret) {			/* still looking for match? */
 98.3687 +				/* no section, get top-level body */
 98.3688 +    if (!section) mail_fetchstructure (stream,msgno,&body);
 98.3689 +				/* get body of nested message */
 98.3690 +    else if ((body = mail_body (stream,msgno,section)) &&
 98.3691 +	     (body->type == TYPEMULTIPART) && body->subtype &&
 98.3692 +	     !strcmp (body->subtype,"RFC822")) body = body->nested.msg->body;
 98.3693 +    if (body) ret = mail_search_body (stream,msgno,body,NIL,1,flags);
 98.3694 +  }
 98.3695 +  mailgets = omg;		/* restore former gets routine */
 98.3696 +				/* clear searching */
 98.3697 +  for (s = stream->private.search.string; s; s = s->next) s->text.data = NIL;
 98.3698 +  mail_free_stringlist (&stream->private.search.string);
 98.3699 +  stream->private.search.text = NIL;
 98.3700 +  return ret;
 98.3701 +}
 98.3702 +
 98.3703 +/* Mail search message body text parts
 98.3704 + * Accepts: MAIL stream
 98.3705 + *	    message number
 98.3706 + *	    current body pointer
 98.3707 + *	    hierarchical level prefix
 98.3708 + *	    position at current hierarchical level
 98.3709 + *	    string list
 98.3710 + *	    flags
 98.3711 + * Returns: T if search found a match
 98.3712 + */
 98.3713 +
 98.3714 +long mail_search_body (MAILSTREAM *stream,unsigned long msgno,BODY *body,
 98.3715 +		       char *prefix,unsigned long section,long flags)
 98.3716 +{
 98.3717 +  long ret = NIL;
 98.3718 +  unsigned long i;
 98.3719 +  char *s,*t,sect[MAILTMPLEN];
 98.3720 +  SIZEDTEXT st,h;
 98.3721 +  PART *part;
 98.3722 +  PARAMETER *param;
 98.3723 +  if (prefix && (strlen (prefix) > (MAILTMPLEN - 20))) return NIL;
 98.3724 +  sprintf (sect,"%s%lu",prefix ? prefix : "",section++);
 98.3725 +  if (flags && prefix) {	/* want to search MIME header too? */
 98.3726 +    st.data = (unsigned char *) mail_fetch_mime (stream,msgno,sect,&st.size,
 98.3727 +						 FT_INTERNAL | FT_PEEK);
 98.3728 +    if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result;
 98.3729 +    else {
 98.3730 +				/* make UTF-8 version of header */
 98.3731 +      utf8_mime2text (&st,&h,U8T_CANONICAL);
 98.3732 +      ret = mail_search_string_work (&h,&stream->private.search.string);
 98.3733 +      if (h.data != st.data) fs_give ((void **) &h.data);
 98.3734 +    }
 98.3735 +  }
 98.3736 +  if (!ret) switch (body->type) {
 98.3737 +  case TYPEMULTIPART:
 98.3738 +				/* extend prefix if not first time */
 98.3739 +    s = prefix ? strcat (sect,".") : "";
 98.3740 +    for (i = 1,part = body->nested.part; part && !ret; i++,part = part->next)
 98.3741 +      ret = mail_search_body (stream,msgno,&part->body,s,i,flags);
 98.3742 +    break;
 98.3743 +  case TYPEMESSAGE:
 98.3744 +    if (!strcmp (body->subtype,"RFC822")) {
 98.3745 +      if (flags) {		/* want to search nested message header? */
 98.3746 +	st.data = (unsigned char *)
 98.3747 +	  mail_fetch_header (stream,msgno,sect,NIL,&st.size,
 98.3748 +			     FT_INTERNAL | FT_PEEK);
 98.3749 +	if (stream->dtb->flags & DR_LOWMEM) ret =stream->private.search.result;
 98.3750 +	else {
 98.3751 +				/* make UTF-8 version of header */
 98.3752 +	  utf8_mime2text (&st,&h,U8T_CANONICAL);
 98.3753 +	  ret = mail_search_string_work (&h,&stream->private.search.string);
 98.3754 +	  if (h.data != st.data) fs_give ((void **) &h.data);
 98.3755 +	}
 98.3756 +      }
 98.3757 +      if (body = body->nested.msg->body)
 98.3758 +	ret = (body->type == TYPEMULTIPART) ?
 98.3759 +	  mail_search_body (stream,msgno,body,(prefix ? prefix : ""),
 98.3760 +			    section - 1,flags) :
 98.3761 +	mail_search_body (stream,msgno,body,strcat (sect,"."),1,flags);
 98.3762 +      break;
 98.3763 +    }
 98.3764 +				/* non-MESSAGE/RFC822 falls into text case */
 98.3765 +
 98.3766 +  case TYPETEXT:
 98.3767 +    s = mail_fetch_body (stream,msgno,sect,&i,FT_INTERNAL | FT_PEEK);
 98.3768 +    if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result;
 98.3769 +    else {
 98.3770 +      for (t = NIL,param = body->parameter; param && !t; param = param->next)
 98.3771 +	if (!strcmp (param->attribute,"CHARSET")) t = param->value;
 98.3772 +      switch (body->encoding) {	/* what encoding? */
 98.3773 +      case ENCBASE64:
 98.3774 +	if (st.data = (unsigned char *)
 98.3775 +	    rfc822_base64 ((unsigned char *) s,i,&st.size)) {
 98.3776 +	  ret = mail_search_string (&st,t,&stream->private.search.string);
 98.3777 +	  fs_give ((void **) &st.data);
 98.3778 +	}
 98.3779 +	break;
 98.3780 +      case ENCQUOTEDPRINTABLE:
 98.3781 +	if (st.data = rfc822_qprint ((unsigned char *) s,i,&st.size)) {
 98.3782 +	  ret = mail_search_string (&st,t,&stream->private.search.string);
 98.3783 +	  fs_give ((void **) &st.data);
 98.3784 +	}
 98.3785 +	break;
 98.3786 +      default:
 98.3787 +	st.data = (unsigned char *) s;
 98.3788 +	st.size = i;
 98.3789 +	ret = mail_search_string (&st,t,&stream->private.search.string);
 98.3790 +	break;
 98.3791 +      }
 98.3792 +    }
 98.3793 +    break;
 98.3794 +  }
 98.3795 +  return ret;
 98.3796 +}
 98.3797 +
 98.3798 +/* Mail search text
 98.3799 + * Accepts: sized text to search
 98.3800 + *	    character set of sized text
 98.3801 + *	    string list of search keys
 98.3802 + * Returns: T if search found a match
 98.3803 + */
 98.3804 +
 98.3805 +long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st)
 98.3806 +{
 98.3807 +  SIZEDTEXT u;
 98.3808 +  long ret;
 98.3809 +  STRINGLIST **sc = st;
 98.3810 +				/* convert to UTF-8 as best we can */
 98.3811 +  if (!utf8_text (s,charset,&u,U8T_CANONICAL))
 98.3812 +    utf8_text (s,NIL,&u,U8T_CANONICAL);
 98.3813 +  ret = mail_search_string_work (&u,st);
 98.3814 +  if (u.data != s->data) fs_give ((void **) &u.data);
 98.3815 +  return ret;
 98.3816 +}
 98.3817 +
 98.3818 +
 98.3819 +/* Mail search text worker routine
 98.3820 + * Accepts: sized text to search
 98.3821 + *	    string list of search keys
 98.3822 + * Returns: T if search found a match
 98.3823 + */
 98.3824 +
 98.3825 +long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st)
 98.3826 +{
 98.3827 +  void *t;
 98.3828 +  STRINGLIST **sc = st;
 98.3829 +  while (*sc) {			/* run down criteria list */
 98.3830 +    if (ssearch (s->data,s->size,(*sc)->text.data,(*sc)->text.size)) {
 98.3831 +      t = (void *) (*sc);	/* found one, need to flush this */
 98.3832 +      *sc = (*sc)->next;	/* remove it from the list */
 98.3833 +      fs_give (&t);		/* flush the buffer */
 98.3834 +    }
 98.3835 +    else sc = &(*sc)->next;	/* move to next in list */
 98.3836 +  }
 98.3837 +  return *st ? NIL : LONGT;
 98.3838 +}
 98.3839 +
 98.3840 +
 98.3841 +/* Mail search keyword
 98.3842 + * Accepts: MAIL stream
 98.3843 + *	    elt to get flags from
 98.3844 + *	    keyword list
 98.3845 + *	    T for keyword search, NIL for unkeyword search
 98.3846 + * Returns: T if search found a match
 98.3847 + */
 98.3848 +
 98.3849 +long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st,
 98.3850 +			  long flag)
 98.3851 +{
 98.3852 +  int i,j;
 98.3853 +  unsigned long f = 0;
 98.3854 +  unsigned long tf;
 98.3855 +  do {
 98.3856 +    for (i = 0; (j = (i < NUSERFLAGS) && stream->user_flags[i]); ++i)
 98.3857 +      if (!compare_csizedtext (stream->user_flags[i],&st->text)) {
 98.3858 +	f |= (1 << i);
 98.3859 +	break;
 98.3860 +      }
 98.3861 +    if (flag && !j) return NIL;
 98.3862 +  } while (st = st->next);
 98.3863 +  tf = elt->user_flags & f;	/* get set flags which match */
 98.3864 +  return flag ? (f == tf) : !tf;
 98.3865 +}
 98.3866 +
 98.3867 +/* Mail search an address list
 98.3868 + * Accepts: address list
 98.3869 + *	    string list
 98.3870 + * Returns: T if search found a match
 98.3871 + */
 98.3872 +
 98.3873 +#define SEARCHBUFLEN (size_t) 2000
 98.3874 +#define SEARCHBUFSLOP (size_t) 5
 98.3875 +
 98.3876 +long mail_search_addr (ADDRESS *adr,STRINGLIST *st)
 98.3877 +{
 98.3878 +  ADDRESS *a,tadr;
 98.3879 +  SIZEDTEXT txt;
 98.3880 +  char tmp[SENDBUFLEN + 1];
 98.3881 +  size_t i = SEARCHBUFLEN;
 98.3882 +  size_t k;
 98.3883 +  long ret = NIL;
 98.3884 +  if (adr) {
 98.3885 +    txt.data = (unsigned char *) fs_get (i + SEARCHBUFSLOP);
 98.3886 +				/* never an error or next */
 98.3887 +    tadr.error = NIL,tadr.next = NIL;
 98.3888 +				/* write address list */
 98.3889 +    for (txt.size = 0,a = adr; a; a = a->next) {
 98.3890 +      k = (tadr.mailbox = a->mailbox) ? 4 + 2*strlen (a->mailbox) : 3;
 98.3891 +      if (tadr.personal = a->personal) k += 3 + 2*strlen (a->personal);
 98.3892 +      if (tadr.adl = a->adl) k += 3 + 2*strlen (a->adl);
 98.3893 +      if (tadr.host = a->host) k += 3 + 2*strlen (a->host);
 98.3894 +      if (tadr.personal || tadr.adl) k += 2;
 98.3895 +      if (k < (SENDBUFLEN-10)) {/* ignore ridiculous addresses */
 98.3896 +	tmp[0] = '\0';
 98.3897 +	rfc822_write_address (tmp,&tadr);
 98.3898 +				/* resize buffer if necessary */
 98.3899 +	if (((k = strlen (tmp)) + txt.size) > i)
 98.3900 +	  fs_resize ((void **) &txt.data,SEARCHBUFSLOP + (i += SEARCHBUFLEN));
 98.3901 +				/* add new address */
 98.3902 +	memcpy (txt.data + txt.size,tmp,k);
 98.3903 +	txt.size += k;
 98.3904 +				/* another address follows */
 98.3905 +	if (a->next) txt.data[txt.size++] = ',';
 98.3906 +      }
 98.3907 +    }
 98.3908 +    txt.data[txt.size] = '\0';	/* tie off string */
 98.3909 +    ret = mail_search_header (&txt,st);
 98.3910 +    fs_give ((void **) &txt.data);
 98.3911 +  }
 98.3912 +  return ret;
 98.3913 +}
 98.3914 +
 98.3915 +/* Get string for low-memory searching
 98.3916 + * Accepts: readin function pointer
 98.3917 + *	    stream to use
 98.3918 + *	    number of bytes
 98.3919 + *	    gets data packet
 98.3920 +
 98.3921 + *	    mail stream
 98.3922 + *	    message number
 98.3923 + *	    descriptor string
 98.3924 + *	    option flags
 98.3925 + * Returns: NIL, always
 98.3926 + */
 98.3927 +
 98.3928 +#define SEARCHSLOP 128
 98.3929 +
 98.3930 +char *mail_search_gets (readfn_t f,void *stream,unsigned long size,
 98.3931 +			GETS_DATA *md)
 98.3932 +{
 98.3933 +  unsigned long i;
 98.3934 +  char tmp[MAILTMPLEN+SEARCHSLOP+1];
 98.3935 +  SIZEDTEXT st;
 98.3936 +				/* better not be called unless searching */
 98.3937 +  if (!md->stream->private.search.string) {
 98.3938 +    sprintf (tmp,"Search botch, mbx = %.80s, %s = %lu[%.80s]",
 98.3939 +	     md->stream->mailbox,
 98.3940 +	     (md->flags & FT_UID) ? "UID" : "msg",md->msgno,md->what);
 98.3941 +    fatal (tmp);
 98.3942 +  }
 98.3943 +				/* initially no match for search */
 98.3944 +  md->stream->private.search.result = NIL;
 98.3945 +				/* make sure buffer clear */
 98.3946 +  memset (st.data = (unsigned char *) tmp,'\0',
 98.3947 +	  (size_t) MAILTMPLEN+SEARCHSLOP+1);
 98.3948 +				/* read first buffer */
 98.3949 +  (*f) (stream,st.size = i = min (size,(long) MAILTMPLEN),tmp);
 98.3950 +				/* search for text */
 98.3951 +  if (mail_search_string (&st,NIL,&md->stream->private.search.string))
 98.3952 +    md->stream->private.search.result = T;
 98.3953 +  else if (size -= i) {		/* more to do, blat slop down */
 98.3954 +    memmove (tmp,tmp+MAILTMPLEN-SEARCHSLOP,(size_t) SEARCHSLOP);
 98.3955 +    do {			/* read subsequent buffers one at a time */
 98.3956 +      (*f) (stream,i = min (size,(long) MAILTMPLEN),tmp+SEARCHSLOP);
 98.3957 +      st.size = i + SEARCHSLOP;
 98.3958 +      if (mail_search_string (&st,NIL,&md->stream->private.search.string))
 98.3959 +	md->stream->private.search.result = T;
 98.3960 +      else memmove (tmp,tmp+MAILTMPLEN,(size_t) SEARCHSLOP);
 98.3961 +    }
 98.3962 +    while ((size -= i) && !md->stream->private.search.result);
 98.3963 +  }
 98.3964 +  if (size) {			/* toss out everything after that */
 98.3965 +    do (*f) (stream,i = min (size,(long) MAILTMPLEN),tmp);
 98.3966 +    while (size -= i);
 98.3967 +  }
 98.3968 +  return NIL;
 98.3969 +}
 98.3970 +
 98.3971 +/* Mail parse search criteria
 98.3972 + * Accepts: criteria
 98.3973 + * Returns: search program if parse successful, else NIL
 98.3974 + */
 98.3975 +
 98.3976 +SEARCHPGM *mail_criteria (char *criteria)
 98.3977 +{
 98.3978 +  SEARCHPGM *pgm = NIL;
 98.3979 +  char *criterion,*r,tmp[MAILTMPLEN];
 98.3980 +  int f;
 98.3981 +  if (criteria) {		/* only if criteria defined */
 98.3982 +				/* make writeable copy of criteria */
 98.3983 +    criteria = cpystr (criteria);
 98.3984 +				/* for each criterion */
 98.3985 +    for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r);
 98.3986 +	 criterion; (criterion = strtok_r (NIL," ",&r))) {
 98.3987 +      f = NIL;			/* init then scan the criterion */
 98.3988 +      switch (*ucase (criterion)) {
 98.3989 +      case 'A':			/* possible ALL, ANSWERED */
 98.3990 +	if (!strcmp (criterion+1,"LL")) f = T;
 98.3991 +	else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T;
 98.3992 +	break;
 98.3993 +      case 'B':			/* possible BCC, BEFORE, BODY */
 98.3994 +	if (!strcmp (criterion+1,"CC"))
 98.3995 +	  f = mail_criteria_string (&pgm->bcc,&r);
 98.3996 +	else if (!strcmp (criterion+1,"EFORE"))
 98.3997 +	  f = mail_criteria_date (&pgm->before,&r);
 98.3998 +	else if (!strcmp (criterion+1,"ODY"))
 98.3999 +	  f = mail_criteria_string (&pgm->body,&r);
 98.4000 +	break;
 98.4001 +      case 'C':			/* possible CC */
 98.4002 +	if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r);
 98.4003 +	break;
 98.4004 +      case 'D':			/* possible DELETED */
 98.4005 +	if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T;
 98.4006 +	break;
 98.4007 +      case 'F':			/* possible FLAGGED, FROM */
 98.4008 +	if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T;
 98.4009 +	else if (!strcmp (criterion+1,"ROM"))
 98.4010 +	  f = mail_criteria_string (&pgm->from,&r);
 98.4011 +	break;
 98.4012 +      case 'K':			/* possible KEYWORD */
 98.4013 +	if (!strcmp (criterion+1,"EYWORD"))
 98.4014 +	  f = mail_criteria_string (&pgm->keyword,&r);
 98.4015 +	break;
 98.4016 +
 98.4017 +      case 'N':			/* possible NEW */
 98.4018 +	if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T;
 98.4019 +	break;
 98.4020 +      case 'O':			/* possible OLD, ON */
 98.4021 +	if (!strcmp (criterion+1,"LD")) f = pgm->old = T;
 98.4022 +	else if (!strcmp (criterion+1,"N"))
 98.4023 +	  f = mail_criteria_date (&pgm->on,&r);
 98.4024 +	break;
 98.4025 +      case 'R':			/* possible RECENT */
 98.4026 +	if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T;
 98.4027 +	break;
 98.4028 +      case 'S':			/* possible SEEN, SINCE, SUBJECT */
 98.4029 +	if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T;
 98.4030 +	else if (!strcmp (criterion+1,"INCE"))
 98.4031 +	  f = mail_criteria_date (&pgm->since,&r);
 98.4032 +	else if (!strcmp (criterion+1,"UBJECT"))
 98.4033 +	  f = mail_criteria_string (&pgm->subject,&r);
 98.4034 +	break;
 98.4035 +      case 'T':			/* possible TEXT, TO */
 98.4036 +	if (!strcmp (criterion+1,"EXT"))
 98.4037 +	  f = mail_criteria_string (&pgm->text,&r);
 98.4038 +	else if (!strcmp (criterion+1,"O"))
 98.4039 +	  f = mail_criteria_string (&pgm->to,&r);
 98.4040 +	break;
 98.4041 +      case 'U':			/* possible UN* */
 98.4042 +	if (criterion[1] == 'N') {
 98.4043 +	  if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T;
 98.4044 +	  else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T;
 98.4045 +	  else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T;
 98.4046 +	  else if (!strcmp (criterion+2,"KEYWORD"))
 98.4047 +	    f = mail_criteria_string (&pgm->unkeyword,&r);
 98.4048 +	  else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T;
 98.4049 +	}
 98.4050 +	break;
 98.4051 +      default:			/* we will barf below */
 98.4052 +	break;
 98.4053 +      }
 98.4054 +      if (!f) {			/* if can't identify criterion */
 98.4055 +	sprintf (tmp,"Unknown search criterion: %.30s",criterion);
 98.4056 +	MM_LOG (tmp,ERROR);
 98.4057 +	mail_free_searchpgm (&pgm);
 98.4058 +	break;
 98.4059 +      }
 98.4060 +    }
 98.4061 +				/* no longer need copy of criteria */
 98.4062 +    fs_give ((void **) &criteria);
 98.4063 +  }
 98.4064 +  return pgm;
 98.4065 +}
 98.4066 +
 98.4067 +/* Parse a date
 98.4068 + * Accepts: pointer to date integer to return
 98.4069 + *	    pointer to strtok state
 98.4070 + * Returns: T if successful, else NIL
 98.4071 + */
 98.4072 +
 98.4073 +int mail_criteria_date (unsigned short *date,char **r)
 98.4074 +{
 98.4075 +  STRINGLIST *s = NIL;
 98.4076 +  MESSAGECACHE elt;
 98.4077 +				/* parse the date and return fn if OK */
 98.4078 +  int ret = (mail_criteria_string (&s,r) &&
 98.4079 +	     mail_parse_date (&elt,(char *) s->text.data) &&
 98.4080 +	     (*date = mail_shortdate (elt.year,elt.month,elt.day))) ?
 98.4081 +	       T : NIL;
 98.4082 +  if (s) mail_free_stringlist (&s);
 98.4083 +  return ret;
 98.4084 +}
 98.4085 +
 98.4086 +/* Calculate shortdate from elt values
 98.4087 + * Accepts: year (0 = BASEYEAR)
 98.4088 + *	    month (1 = January)
 98.4089 + *	    day
 98.4090 + * Returns: shortdate
 98.4091 + */
 98.4092 +
 98.4093 +unsigned short mail_shortdate (unsigned int year,unsigned int month,
 98.4094 +			       unsigned int day)
 98.4095 +{
 98.4096 +  return (year << 9) + (month << 5) + day;
 98.4097 +}
 98.4098 +
 98.4099 +/* Parse a string
 98.4100 + * Accepts: pointer to stringlist
 98.4101 + *	    pointer to strtok state
 98.4102 + * Returns: T if successful, else NIL
 98.4103 + */
 98.4104 +
 98.4105 +int mail_criteria_string (STRINGLIST **s,char **r)
 98.4106 +{
 98.4107 +  unsigned long n;
 98.4108 +  char e,*d,*end = " ",*c = strtok_r (NIL,"",r);
 98.4109 +  if (!c) return NIL;		/* missing argument */
 98.4110 +  switch (*c) {			/* see what the argument is */
 98.4111 +  case '{':			/* literal string */
 98.4112 +    n = strtoul (c+1,&d,10);	/* get its length */
 98.4113 +    if ((*d++ == '}') && (*d++ == '\015') && (*d++ == '\012') &&
 98.4114 +	(!(*(c = d + n)) || (*c == ' '))) {
 98.4115 +      e = *--c;			/* store old delimiter */
 98.4116 +      *c = '\377';		/* make sure not a space */
 98.4117 +      strtok_r (c," ",r);	/* reset the strtok mechanism */
 98.4118 +      *c = e;			/* put character back */
 98.4119 +      break;
 98.4120 +    }
 98.4121 +  case '\0':			/* catch bogons */
 98.4122 +  case ' ':
 98.4123 +    return NIL;
 98.4124 +  case '"':			/* quoted string */
 98.4125 +    if (strchr (c+1,'"')) end = "\"";
 98.4126 +    else return NIL;		/* falls through */
 98.4127 +  default:			/* atomic string */
 98.4128 +    if (d = strtok_r (c,end,r)) n = strlen (d);
 98.4129 +    else return NIL;
 98.4130 +    break;
 98.4131 +  }
 98.4132 +  while (*s) s = &(*s)->next;	/* find tail of list */
 98.4133 +  *s = mail_newstringlist ();	/* make new entry */
 98.4134 +				/* return the data */
 98.4135 +  (*s)->text.data = (unsigned char *) cpystr (d);
 98.4136 +  (*s)->text.size = n;
 98.4137 +  return T;
 98.4138 +}
 98.4139 +
 98.4140 +/* Mail parse set from string
 98.4141 + * Accepts: string to parse
 98.4142 + *	    pointer to updated string pointer for return
 98.4143 + * Returns: set with pointer updated, or NIL if error
 98.4144 + */
 98.4145 +
 98.4146 +SEARCHSET *mail_parse_set (char *s,char **ret)
 98.4147 +{
 98.4148 +  SEARCHSET *cur;
 98.4149 +  SEARCHSET *set = NIL;
 98.4150 +  while (isdigit (*s)) {
 98.4151 +    if (!set) cur = set = mail_newsearchset ();
 98.4152 +    else cur = cur->next = mail_newsearchset ();
 98.4153 +				/* parse value */
 98.4154 +    if (!(cur->first = strtoul (s,&s,10)) ||
 98.4155 +	((*s == ':') && !(isdigit (*++s) && (cur->last = strtoul (s,&s,10)))))
 98.4156 +      break;			/* bad value or range */
 98.4157 +    if (*s == ',') ++s;		/* point to next value if more */
 98.4158 +    else {			/* end of set */
 98.4159 +      *ret = s;			/* set return pointer */
 98.4160 +      return set;		/* return set */
 98.4161 +    }
 98.4162 +  }
 98.4163 +  mail_free_searchset (&set);	/* failure, punt partial set */
 98.4164 +  return NIL;
 98.4165 +}
 98.4166 +
 98.4167 +
 98.4168 +/* Mail append to set
 98.4169 + * Accepts: head of search set or NIL to do nothing
 98.4170 + *	    message to add
 98.4171 + * Returns: tail of search set or NIL if did nothing
 98.4172 + */
 98.4173 +
 98.4174 +SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno)
 98.4175 +{
 98.4176 +  if (set) {			/* find tail */
 98.4177 +    while (set->next) set = set->next;
 98.4178 +				/* start of set if no first member */
 98.4179 +    if (!set->first) set->first = msgno;
 98.4180 +    else if (msgno == (set->last ? set->last : set->first) + 1)
 98.4181 +      set->last = msgno;	/* extend range if 1 past current */
 98.4182 +    else (set = set->next = mail_newsearchset ())->first = msgno;
 98.4183 +  }
 98.4184 +  return set;
 98.4185 +}
 98.4186 +
 98.4187 +/* Mail sort messages
 98.4188 + * Accepts: mail stream
 98.4189 + *	    character set
 98.4190 + *	    search program
 98.4191 + *	    sort program
 98.4192 + *	    option flags
 98.4193 + * Returns: vector of sorted message sequences or NIL if error
 98.4194 + */
 98.4195 +
 98.4196 +unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 98.4197 +			  SORTPGM *pgm,long flags)
 98.4198 +{
 98.4199 +  unsigned long *ret = NIL;
 98.4200 +  if (stream->dtb)		/* do the driver's action */
 98.4201 +    ret = (*(stream->dtb->sort ? stream->dtb->sort : mail_sort_msgs))
 98.4202 +      (stream,charset,spg,pgm,flags);
 98.4203 +				/* flush search/sort programs if requested */
 98.4204 +  if (spg && (flags & SE_FREE)) mail_free_searchpgm (&spg);
 98.4205 +  if (flags & SO_FREE) mail_free_sortpgm (&pgm);
 98.4206 +  return ret;
 98.4207 +}
 98.4208 +
 98.4209 +/* Mail sort messages work routine
 98.4210 + * Accepts: mail stream
 98.4211 + *	    character set
 98.4212 + *	    search program
 98.4213 + *	    sort program
 98.4214 + *	    option flags
 98.4215 + * Returns: vector of sorted message sequences or NIL if error
 98.4216 + */
 98.4217 +
 98.4218 +unsigned long *mail_sort_msgs (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 98.4219 +			       SORTPGM *pgm,long flags)
 98.4220 +{
 98.4221 +  unsigned long i;
 98.4222 +  SORTCACHE **sc;
 98.4223 +  unsigned long *ret = NIL;
 98.4224 +  if (spg) {			/* only if a search needs to be done */
 98.4225 +    int silent = stream->silent;
 98.4226 +    stream->silent = T;		/* don't pass up mm_searched() events */
 98.4227 +				/* search for messages */
 98.4228 +    mail_search_full (stream,charset,spg,NIL);
 98.4229 +    stream->silent = silent;	/* restore silence state */
 98.4230 +  }
 98.4231 +				/* initialize progress counters */
 98.4232 +  pgm->nmsgs = pgm->progress.cached = 0;
 98.4233 +				/* pass 1: count messages to sort */
 98.4234 +  for (i = 1; i <= stream->nmsgs; ++i)
 98.4235 +    if (mail_elt (stream,i)->searched) pgm->nmsgs++;
 98.4236 +  if (pgm->nmsgs) {		/* pass 2: sort cache */
 98.4237 +    sc = mail_sort_loadcache (stream,pgm);
 98.4238 +				/* pass 3: sort messages */
 98.4239 +    if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags);
 98.4240 +    fs_give ((void **) &sc);	/* don't need sort vector any more */
 98.4241 +  }
 98.4242 +				/* empty sort results */
 98.4243 +  else ret = (unsigned long *) memset (fs_get (sizeof (unsigned long)),0,
 98.4244 +				       sizeof (unsigned long));
 98.4245 +				/* also return via callback if requested */
 98.4246 +  if (mailsortresults) (*mailsortresults) (stream,ret,pgm->nmsgs);
 98.4247 +  return ret;			/* return sort results */
 98.4248 +}
 98.4249 +
 98.4250 +/* Mail sort sortcache vector
 98.4251 + * Accepts: mail stream
 98.4252 + *	    sort program
 98.4253 + *	    sortcache vector
 98.4254 + *	    option flags
 98.4255 + * Returns: vector of sorted message sequences or NIL if error
 98.4256 + */
 98.4257 +
 98.4258 +unsigned long *mail_sort_cache (MAILSTREAM *stream,SORTPGM *pgm,SORTCACHE **sc,
 98.4259 +				long flags)
 98.4260 +{
 98.4261 +  unsigned long i,*ret;
 98.4262 +				/* pass 3: sort messages */
 98.4263 +  qsort ((void *) sc,pgm->nmsgs,sizeof (SORTCACHE *),mail_sort_compare);
 98.4264 +				/* optional post sorting */
 98.4265 +  if (pgm->postsort) (*pgm->postsort) ((void *) sc);
 98.4266 +				/* pass 4: return results */
 98.4267 +  ret = (unsigned long *) fs_get ((pgm->nmsgs+1) * sizeof (unsigned long));
 98.4268 +  if (flags & SE_UID)		/* UID or msgno? */
 98.4269 +    for (i = 0; i < pgm->nmsgs; i++) ret[i] = mail_uid (stream,sc[i]->num);
 98.4270 +  else for (i = 0; i < pgm->nmsgs; i++) ret[i] = sc[i]->num;
 98.4271 +  ret[pgm->nmsgs] = 0;		/* tie off message list */
 98.4272 +  return ret;
 98.4273 +}
 98.4274 +
 98.4275 +/* Mail load sortcache
 98.4276 + * Accepts: mail stream, already searched
 98.4277 + *	    sort program
 98.4278 + * Returns: vector of sortcache pointers matching search
 98.4279 + */
 98.4280 +
 98.4281 +static STRINGLIST maildateline = {{(unsigned char *) "date",4},NIL};
 98.4282 +static STRINGLIST mailrnfromline = {{(unsigned char *) ">from",5},NIL};
 98.4283 +static STRINGLIST mailfromline = {{(unsigned char *) "from",4},
 98.4284 +				    &mailrnfromline};
 98.4285 +static STRINGLIST mailtonline = {{(unsigned char *) "to",2},NIL};
 98.4286 +static STRINGLIST mailccline = {{(unsigned char *) "cc",2},NIL};
 98.4287 +static STRINGLIST mailsubline = {{(unsigned char *) "subject",7},NIL};
 98.4288 +
 98.4289 +SORTCACHE **mail_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm)
 98.4290 +{
 98.4291 +  char *t,*v,*x,tmp[MAILTMPLEN];
 98.4292 +  SORTPGM *pg;
 98.4293 +  SORTCACHE *s,**sc;
 98.4294 +  MESSAGECACHE *elt,telt;
 98.4295 +  ENVELOPE *env;
 98.4296 +  ADDRESS *adr = NIL;
 98.4297 +  unsigned long i = (pgm->nmsgs) * sizeof (SORTCACHE *);
 98.4298 +  sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i);
 98.4299 +				/* see what needs to be loaded */
 98.4300 +  for (i = 1; !pgm->abort && (i <= stream->nmsgs); i++)
 98.4301 +    if ((elt = mail_elt (stream,i))->searched) {
 98.4302 +      sc[pgm->progress.cached++] =
 98.4303 +	s = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE);
 98.4304 +      s->pgm = pgm;		/* note sort program */
 98.4305 +      s->num = i;
 98.4306 +				/* get envelope if cached */
 98.4307 +      if (stream->scache) env = (i == stream->msgno) ? stream->env : NIL;
 98.4308 +      else env = elt->private.msg.env;
 98.4309 +      for (pg = pgm; pg; pg = pg->next) switch (pg->function) {
 98.4310 +      case SORTARRIVAL:		/* sort by arrival date */
 98.4311 +	if (!s->arrival) {
 98.4312 +				/* internal date unknown but can get? */
 98.4313 +	  if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) {
 98.4314 +	    sprintf (tmp,"%lu",i);
 98.4315 +	    mail_fetch_fast (stream,tmp,NIL);
 98.4316 +	  }
 98.4317 +				/* wrong thing before 3-Jan-1970 */
 98.4318 +	  s->arrival = elt->day ? mail_longdate (elt) : 1;
 98.4319 +	  s->dirty = T;
 98.4320 +	}
 98.4321 +	break;
 98.4322 +      case SORTSIZE:		/* sort by message size */
 98.4323 +	if (!s->size) {
 98.4324 +	  if (!elt->rfc822_size) {
 98.4325 +	    sprintf (tmp,"%lu",i);
 98.4326 +	    mail_fetch_fast (stream,tmp,NIL);
 98.4327 +	  }
 98.4328 +	  s->size = elt->rfc822_size ? elt->rfc822_size : 1;
 98.4329 +	  s->dirty = T;
 98.4330 +	}
 98.4331 +	break;
 98.4332 +
 98.4333 +      case SORTDATE:		/* sort by date */
 98.4334 +	if (!s->date) {
 98.4335 +	  if (env) t = env->date;
 98.4336 +	  else if ((t = mail_fetch_header (stream,i,NIL,&maildateline,NIL,
 98.4337 +					   FT_INTERNAL | FT_PEEK)) &&
 98.4338 +		   (t = strchr (t,':')))
 98.4339 +	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
 98.4340 +	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
 98.4341 +	      case ' ':		/* erase continuation newlines */
 98.4342 +	      case '\t':
 98.4343 +		memmove (x,v,strlen (v));
 98.4344 +		break;
 98.4345 +	      default:		/* tie off extraneous text */
 98.4346 +		*x = x[1] = '\0';
 98.4347 +	      }
 98.4348 +				/* skip leading whitespace */
 98.4349 +	  if (t) while ((*t == ' ') || (*t == '\t')) t++;
 98.4350 +				/* parse date from Date: header */
 98.4351 +	  if (!(t && mail_parse_date (&telt,t) && 
 98.4352 +		(s->date = mail_longdate (&telt)))) {
 98.4353 +				/* failed, use internal date */
 98.4354 +	    if (!(s->date = s->arrival)) {
 98.4355 +				/* internal date unknown but can get? */
 98.4356 +	      if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) {
 98.4357 +		sprintf (tmp,"%lu",i);
 98.4358 +		mail_fetch_fast (stream,tmp,NIL);
 98.4359 +	      }
 98.4360 +				/* wrong thing before 3-Jan-1970 */
 98.4361 +	      s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1);
 98.4362 +	    }
 98.4363 +	  }
 98.4364 +	  s->dirty = T;
 98.4365 +	}
 98.4366 +	break;
 98.4367 +
 98.4368 +      case SORTFROM:		/* sort by first from */
 98.4369 +	if (!s->from) {
 98.4370 +	  if (env) s->from = env->from && env->from->mailbox ?
 98.4371 +	    cpystr (env->from->mailbox) : NIL;
 98.4372 +	  else if ((t = mail_fetch_header (stream,i,NIL,&mailfromline,NIL,
 98.4373 +					   FT_INTERNAL | FT_PEEK)) &&
 98.4374 +		   (t = strchr (t,':'))) {
 98.4375 +	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
 98.4376 +	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
 98.4377 +	      case ' ':		/* erase continuation newlines */
 98.4378 +	      case '\t':
 98.4379 +		memmove (x,v,strlen (v));
 98.4380 +		break;
 98.4381 +	      case 'f':		/* continuation but with extra "From:" */
 98.4382 +	      case 'F':
 98.4383 +		if (v = strchr (v,':')) {
 98.4384 +		  memmove (x,v+1,strlen (v+1));
 98.4385 +		  break;
 98.4386 +		}
 98.4387 +	      default:		/* tie off extraneous text */
 98.4388 +		*x = x[1] = '\0';
 98.4389 +	      }
 98.4390 +	    if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
 98.4391 +	      s->from = adr->mailbox;
 98.4392 +	      adr->mailbox = NIL;
 98.4393 +	      mail_free_address (&adr);
 98.4394 +	    }
 98.4395 +	  }
 98.4396 +	  if (!s->from) s->from = cpystr ("");
 98.4397 +	  s->dirty = T;
 98.4398 +	}
 98.4399 +	break;
 98.4400 +
 98.4401 +      case SORTTO:		/* sort by first to */
 98.4402 +	if (!s->to) {
 98.4403 +	  if (env) s->to = env->to && env->to->mailbox ?
 98.4404 +	    cpystr (env->to->mailbox) : NIL;
 98.4405 +	  else if ((t = mail_fetch_header (stream,i,NIL,&mailtonline,NIL,
 98.4406 +					   FT_INTERNAL | FT_PEEK)) &&
 98.4407 +		   (t = strchr (t,':'))) {
 98.4408 +	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
 98.4409 +	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
 98.4410 +	      case ' ':		/* erase continuation newlines */
 98.4411 +	      case '\t':
 98.4412 +		memmove (x,v,strlen (v));
 98.4413 +		break;
 98.4414 +	      case 't':		/* continuation but with extra "To:" */
 98.4415 +	      case 'T':
 98.4416 +		if (v = strchr (v,':')) {
 98.4417 +		  memmove (x,v+1,strlen (v+1));
 98.4418 +		  break;
 98.4419 +		}
 98.4420 +	      default:		/* tie off extraneous text */
 98.4421 +		*x = x[1] = '\0';
 98.4422 +	      }
 98.4423 +	    if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
 98.4424 +	      s->to = adr->mailbox;
 98.4425 +	      adr->mailbox = NIL;
 98.4426 +	      mail_free_address (&adr);
 98.4427 +	    }
 98.4428 +	  }
 98.4429 +	  if (!s->to) s->to = cpystr ("");
 98.4430 +	  s->dirty = T;
 98.4431 +	}
 98.4432 +	break;
 98.4433 +
 98.4434 +      case SORTCC:		/* sort by first cc */
 98.4435 +	if (!s->cc) {
 98.4436 +	  if (env) s->cc = env->cc && env->cc->mailbox ?
 98.4437 +	    cpystr (env->cc->mailbox) : NIL;
 98.4438 +	  else if ((t = mail_fetch_header (stream,i,NIL,&mailccline,NIL,
 98.4439 +					   FT_INTERNAL | FT_PEEK)) &&
 98.4440 +		   (t = strchr (t,':'))) {
 98.4441 +	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
 98.4442 +	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
 98.4443 +	      case ' ':		/* erase continuation newlines */
 98.4444 +	      case '\t':
 98.4445 +		memmove (x,v,strlen (v));
 98.4446 +		break;
 98.4447 +	      case 't':		/* continuation but with extra "To:" */
 98.4448 +	      case 'T':
 98.4449 +		if (v = strchr (v,':')) {
 98.4450 +		  memmove (x,v+1,strlen (v+1));
 98.4451 +		  break;
 98.4452 +		}
 98.4453 +	      default:		/* tie off extraneous text */
 98.4454 +		*x = x[1] = '\0';
 98.4455 +	      }
 98.4456 +	    if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
 98.4457 +	      s->cc = adr->mailbox;
 98.4458 +	      adr->mailbox = NIL;
 98.4459 +	      mail_free_address (&adr);
 98.4460 +	    }
 98.4461 +	  }
 98.4462 +	  if (!s->cc) s->cc = cpystr ("");
 98.4463 +	  s->dirty = T;
 98.4464 +	}
 98.4465 +	break;
 98.4466 +
 98.4467 +      case SORTSUBJECT:		/* sort by subject */
 98.4468 +	if (!s->subject) {
 98.4469 +				/* get subject from envelope if have one */
 98.4470 +	  if (env) t = env->subject ? env->subject : "";
 98.4471 +				/* otherwise snarf from header text */
 98.4472 +	  else if ((t = mail_fetch_header (stream,i,NIL,&mailsubline,
 98.4473 +					   NIL,FT_INTERNAL | FT_PEEK)) &&
 98.4474 +		   (t = strchr (t,':')))
 98.4475 +	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
 98.4476 +	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
 98.4477 +	      case ' ':		/* erase continuation newlines */
 98.4478 +	      case '\t':
 98.4479 +		memmove (x,v,strlen (v));
 98.4480 +		break;
 98.4481 +	      default:		/* tie off extraneous text */
 98.4482 +		*x = x[1] = '\0';
 98.4483 +	      }
 98.4484 +	  else t = "";		/* empty subject */
 98.4485 +				/* strip and cache subject */
 98.4486 +	  s->refwd = mail_strip_subject (t,&s->subject);
 98.4487 +	  s->dirty = T;
 98.4488 +	}
 98.4489 +	break;
 98.4490 +      default:
 98.4491 +	fatal ("Unknown sort function");
 98.4492 +      }
 98.4493 +    }
 98.4494 +  return sc;
 98.4495 +}
 98.4496 +
 98.4497 +/* Strip subjects of extra spaces and leading and trailing cruft for sorting
 98.4498 + * Accepts: unstripped subject
 98.4499 + *	    pointer to return stripped subject, in cpystr form
 98.4500 + * Returns: T if subject had a re/fwd, NIL otherwise
 98.4501 + */
 98.4502 +
 98.4503 +unsigned int mail_strip_subject (char *t,char **ret)
 98.4504 +{
 98.4505 +  SIZEDTEXT src,dst;
 98.4506 +  unsigned long i,slen;
 98.4507 +  char c,*s,*x;
 98.4508 +  unsigned int refwd = NIL;
 98.4509 +  if (src.size = strlen (t)) {	/* have non-empty subject? */
 98.4510 +    src.data = (unsigned char *) t;
 98.4511 +			/* Step 1 */
 98.4512 +				/* make copy, convert MIME2 if needed */
 98.4513 +    *ret = s = (utf8_mime2text (&src,&dst,U8T_CANONICAL) &&
 98.4514 +		(src.data != dst.data)) ? (char *) dst.data : cpystr (t);
 98.4515 +				/* convert spaces to tab, strip extra spaces */
 98.4516 +    for (x = t = s, c = 'x'; *t; t++) {
 98.4517 +      if (c != ' ') c = *x++ = ((*t == '\t') ? ' ' : *t);
 98.4518 +      else if ((*t != '\t') && (*t != ' ')) c = *x++ = *t;
 98.4519 +    }
 98.4520 +    *x = '\0';			/* tie off string */
 98.4521 +			/* Step 2 */
 98.4522 +    for (slen = dst.size; s; slen = strlen (s))  {
 98.4523 +      for (t = s + slen; t > s; ) switch (t[-1]) {
 98.4524 +      case ' ': case '\t':	/* WSP */
 98.4525 +	*--t = '\0';		/* just remove it */
 98.4526 +	break;
 98.4527 +      case ')':			/* possible "(fwd)" */
 98.4528 +	if ((t >= (s + 5)) && (t[-5] == '(') &&
 98.4529 +	    ((t[-4] == 'F') || (t[-4] == 'f')) &&
 98.4530 +	    ((t[-3] == 'W') || (t[-3] == 'w')) &&
 98.4531 +	    ((t[-2] == 'D') || (t[-2] == 'd'))) {
 98.4532 +	  *(t -= 5) = '\0';	/* remove "(fwd)" */
 98.4533 +	  refwd = T;		/* note a re/fwd */
 98.4534 +	  break;
 98.4535 +	}
 98.4536 +      default:			/* not a subj-trailer */
 98.4537 +	t = s;
 98.4538 +	break;
 98.4539 +      }
 98.4540 +			/* Steps 3-5 */
 98.4541 +      for (t = s; t; ) switch (*s) {
 98.4542 +      case ' ': case '\t':	/* WSP */
 98.4543 +	s = t = mail_strip_subject_wsp (s + 1);
 98.4544 +	break;
 98.4545 +      case 'r': case 'R':	/* possible "re" */
 98.4546 +	if (((s[1] == 'E') || (s[1] == 'e')) &&
 98.4547 +	    (t = mail_strip_subject_wsp (s + 2)) &&
 98.4548 +	    (t = mail_strip_subject_blob (t)) && (*t == ':')) {
 98.4549 +	  s = ++t;		/* found "re" */
 98.4550 +	  refwd = T;		/* definitely a re/fwd at this point */
 98.4551 +	}
 98.4552 +	else t = NIL;		/* found subj-middle */
 98.4553 +	break;
 98.4554 +      case 'f': case 'F':	/* possible "fw" or "fwd" */
 98.4555 +	if (((s[1] == 'w') || (s[1] == 'W')) &&
 98.4556 +	    (((s[2] == 'd') || (s[2] == 'D')) ?
 98.4557 +	     (t = mail_strip_subject_wsp (s + 3)) :
 98.4558 +	     (t = mail_strip_subject_wsp (s + 2))) &&
 98.4559 +	    (t = mail_strip_subject_blob (t)) && (*t == ':')) {
 98.4560 +	  s = ++t;		/* found "fwd" */
 98.4561 +	  refwd = T;		/* definitely a re/fwd at this point */
 98.4562 +	}
 98.4563 +	else t = NIL;		/* found subj-middle */
 98.4564 +	break;
 98.4565 +      case '[':			/* possible subj-blob */
 98.4566 +	if ((t = mail_strip_subject_blob (s)) && *t) s = t;
 98.4567 +	else t = NIL;		/* found subj-middle */
 98.4568 +	break;
 98.4569 +      default:
 98.4570 +	t = NIL;		/* found subj-middle */
 98.4571 +	break;
 98.4572 +      }
 98.4573 +			/* Step 6 */
 98.4574 +				/* Netscape-style "[Fwd: ...]"? */
 98.4575 +      if ((*s == '[') && ((s[1] == 'F') || (s[1] == 'f')) &&
 98.4576 +	  ((s[2] == 'W') || (s[2] == 'w')) &&
 98.4577 +	  ((s[3] == 'D') || (s[3] == 'd')) && (s[4] == ':') &&
 98.4578 +	  (s[i = strlen (s) - 1] == ']')) {
 98.4579 +	s[i] = '\0';		/* flush closing "]" */
 98.4580 +	s += 5;			/* and leading "[Fwd:" */
 98.4581 +	refwd = T;		/* definitely a re/fwd at this point */
 98.4582 +      }
 98.4583 +      else break;		/* don't need to loop back to step 2 */
 98.4584 +    }
 98.4585 +    if (s != (t = *ret)) {	/* removed leading text? */
 98.4586 +      s = *ret = cpystr (s);	/* yes, make a fresh return copy */
 98.4587 +      fs_give ((void **) &t);	/* flush old copy */
 98.4588 +    }
 98.4589 +  }
 98.4590 +  else *ret = cpystr ("");	/* empty subject */
 98.4591 +  return refwd;			/* return re/fwd state */
 98.4592 +}
 98.4593 +
 98.4594 +/* Strip subject wsp helper routine
 98.4595 + * Accepts: text
 98.4596 + * Returns: pointer to text after blob
 98.4597 + */
 98.4598 +
 98.4599 +char *mail_strip_subject_wsp (char *s)
 98.4600 +{
 98.4601 +  while ((*s == ' ') || (*s == '\t')) s++;
 98.4602 +  return s;
 98.4603 +}
 98.4604 +
 98.4605 +
 98.4606 +/* Strip subject blob helper routine
 98.4607 + * Accepts: text
 98.4608 + * Returns: pointer to text after any blob, NIL if blob-like but not blob
 98.4609 + */
 98.4610 +
 98.4611 +char *mail_strip_subject_blob (char *s)
 98.4612 +{
 98.4613 +  if (*s != '[') return s;	/* not a blob, ignore */
 98.4614 +				/* search for end of blob */
 98.4615 +  while (*++s != ']') if ((*s == '[') || !*s) return NIL;
 98.4616 +  return mail_strip_subject_wsp (s + 1);
 98.4617 +}
 98.4618 +
 98.4619 +/* Sort compare messages
 98.4620 + * Accept: first message sort cache element
 98.4621 + *	   second message sort cache element
 98.4622 + * Returns: -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2
 98.4623 + */
 98.4624 +
 98.4625 +int mail_sort_compare (const void *a1,const void *a2)
 98.4626 +{
 98.4627 +  int i = 0;
 98.4628 +  SORTCACHE *s1 = *(SORTCACHE **) a1;
 98.4629 +  SORTCACHE *s2 = *(SORTCACHE **) a2;
 98.4630 +  SORTPGM *pgm = s1->pgm;
 98.4631 +  if (!s1->sorted) {		/* this one sorted yet? */
 98.4632 +    s1->sorted = T;
 98.4633 +    pgm->progress.sorted++;	/* another sorted message */
 98.4634 +  }
 98.4635 +  if (!s2->sorted) {		/* this one sorted yet? */
 98.4636 +    s2->sorted = T;
 98.4637 +    pgm->progress.sorted++;	/* another sorted message */
 98.4638 +  }
 98.4639 +  do {
 98.4640 +    switch (pgm->function) {	/* execute search program */
 98.4641 +    case SORTDATE:		/* sort by date */
 98.4642 +      i = compare_ulong (s1->date,s2->date);
 98.4643 +      break;
 98.4644 +    case SORTARRIVAL:		/* sort by arrival date */
 98.4645 +      i = compare_ulong (s1->arrival,s2->arrival);
 98.4646 +      break;
 98.4647 +    case SORTSIZE:		/* sort by message size */
 98.4648 +      i = compare_ulong (s1->size,s2->size);
 98.4649 +      break;
 98.4650 +    case SORTFROM:		/* sort by first from */
 98.4651 +      i = compare_cstring (s1->from,s2->from);
 98.4652 +      break;
 98.4653 +    case SORTTO:		/* sort by first to */
 98.4654 +      i = compare_cstring (s1->to,s2->to);
 98.4655 +      break;
 98.4656 +    case SORTCC:		/* sort by first cc */
 98.4657 +      i = compare_cstring (s1->cc,s2->cc);
 98.4658 +      break;
 98.4659 +    case SORTSUBJECT:		/* sort by subject */
 98.4660 +      i = compare_cstring (s1->subject,s2->subject);
 98.4661 +      break;
 98.4662 +    }
 98.4663 +    if (pgm->reverse) i = -i;	/* flip results if necessary */
 98.4664 +  }
 98.4665 +  while (pgm = i ? NIL : pgm->next);
 98.4666 +				/* return result, avoid 0 if at all possible */
 98.4667 +  return i ? i : compare_ulong (s1->num,s2->num);
 98.4668 +}
 98.4669 +
 98.4670 +/* Return message date as an unsigned long seconds since time began
 98.4671 + * Accepts: message cache pointer
 98.4672 + * Returns: unsigned long of date
 98.4673 + *
 98.4674 + * This routine, like most UNIX systems, is clueless about leap seconds.
 98.4675 + * Thus, it treats 23:59:60 as equivalent to 00:00:00 the next day.
 98.4676 + *
 98.4677 + * This routine forces any early hours on 1-Jan-1970 in oriental timezones
 98.4678 + * to be 1-Jan-1970 00:00:00 UTC, so as to avoid negative longdates.
 98.4679 + */
 98.4680 +
 98.4681 +unsigned long mail_longdate (MESSAGECACHE *elt)
 98.4682 +{
 98.4683 +  unsigned long m = elt->month ? elt->month : 1;
 98.4684 +  unsigned long yr = elt->year + BASEYEAR;
 98.4685 +				/* number of days since time began */
 98.4686 +  unsigned long ret = (elt->day ? (elt->day - 1) : 0)
 98.4687 +    + 30 * (m - 1) + ((m + (m > 8)) / 2)
 98.4688 +#ifndef USEJULIANCALENDAR
 98.4689 +#ifndef USEORTHODOXCALENDAR	/* Gregorian calendar */
 98.4690 +    + ((yr / 400) - (BASEYEAR / 400)) - ((yr / 100) - (BASEYEAR / 100))
 98.4691 +#ifdef Y4KBUGFIX
 98.4692 +    - ((yr / 4000) - (BASEYEAR / 4000))
 98.4693 +#endif
 98.4694 +    - ((m < 3) ?
 98.4695 +       !(yr % 4) && ((yr % 100) || (!(yr % 400)
 98.4696 +#ifdef Y4KBUGFIX
 98.4697 +				    && (yr % 4000)
 98.4698 +#endif
 98.4699 +				    )) : 2)
 98.4700 +#else				/* Orthodox calendar */
 98.4701 +    + ((2*(yr / 900)) - (2*(BASEYEAR / 900)))
 98.4702 +    + (((yr % 900) >= 200) - ((BASEYEAR % 900) >= 200))
 98.4703 +    + (((yr % 900) >= 600) - ((BASEYEAR % 900) >= 600))
 98.4704 +    - ((yr / 100) - (BASEYEAR / 100))
 98.4705 +    - ((m < 3) ?
 98.4706 +       !(yr % 4) && ((yr % 100) || ((yr % 900) == 200) || ((yr % 900) == 600))
 98.4707 +       : 2)
 98.4708 +#endif
 98.4709 +#endif
 98.4710 +    + elt->year * 365 + (((unsigned long) (elt->year + (BASEYEAR % 4))) / 4);
 98.4711 +  ret *= 24; ret += elt->hours;	/* date value in hours */
 98.4712 +  ret *= 60; ret +=elt->minutes;/* date value in minutes */
 98.4713 +  yr = (elt->zhours * 60) + elt->zminutes;
 98.4714 +  if (elt->zoccident) ret += yr;/* occidental timezone, make UTC */
 98.4715 +  else if (ret < yr) return 0;	/* still 31-Dec-1969 in UTC */
 98.4716 +  else ret -= yr;		/* oriental timezone, make UTC */
 98.4717 +  ret *= 60; ret += elt->seconds;
 98.4718 +  return ret;
 98.4719 +}
 98.4720 +
 98.4721 +/* Mail thread messages
 98.4722 + * Accepts: mail stream
 98.4723 + *	    thread type
 98.4724 + *	    character set
 98.4725 + *	    search program
 98.4726 + *	    option flags
 98.4727 + * Returns: thread node tree or NIL if error
 98.4728 + */
 98.4729 +
 98.4730 +THREADNODE *mail_thread (MAILSTREAM *stream,char *type,char *charset,
 98.4731 +			 SEARCHPGM *spg,long flags)
 98.4732 +{
 98.4733 +  THREADNODE *ret = NIL;
 98.4734 +  if (stream->dtb)		/* must have a live driver */
 98.4735 +    ret = stream->dtb->thread ?	/* do driver's action if available */
 98.4736 +      (*stream->dtb->thread) (stream,type,charset,spg,flags) :
 98.4737 +	mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs);
 98.4738 +				/* flush search/sort programs if requested */
 98.4739 +  if (spg && (flags & SE_FREE)) mail_free_searchpgm (&spg);
 98.4740 +  return ret;
 98.4741 +}
 98.4742 +
 98.4743 +
 98.4744 +/* Mail thread messages
 98.4745 + * Accepts: mail stream
 98.4746 + *	    thread type
 98.4747 + *	    character set
 98.4748 + *	    search program
 98.4749 + *	    option flags
 98.4750 + *	    sorter routine
 98.4751 + * Returns: thread node tree or NIL if error
 98.4752 + */
 98.4753 +
 98.4754 +THREADNODE *mail_thread_msgs (MAILSTREAM *stream,char *type,char *charset,
 98.4755 +			      SEARCHPGM *spg,long flags,sorter_t sorter)
 98.4756 +{
 98.4757 +  THREADER *t;
 98.4758 +  for (t = &mailthreadlist; t; t = t->next)
 98.4759 +    if (!compare_cstring (type,t->name)) {
 98.4760 +      THREADNODE *ret = (*t->dispatch) (stream,charset,spg,flags,sorter);
 98.4761 +      if (mailthreadresults) (*mailthreadresults) (stream,ret);
 98.4762 +      return ret;
 98.4763 +    }
 98.4764 +  MM_LOG ("No such thread type",ERROR);
 98.4765 +  return NIL;
 98.4766 +}
 98.4767 +
 98.4768 +/* Mail thread ordered subject
 98.4769 + * Accepts: mail stream
 98.4770 + *	    character set
 98.4771 + *	    search program
 98.4772 + *	    option flags
 98.4773 + *	    sorter routine
 98.4774 + * Returns: thread node tree
 98.4775 + */
 98.4776 +
 98.4777 +THREADNODE *mail_thread_orderedsubject (MAILSTREAM *stream,char *charset,
 98.4778 +					SEARCHPGM *spg,long flags,
 98.4779 +					sorter_t sorter)
 98.4780 +{
 98.4781 +  THREADNODE *thr = NIL;
 98.4782 +  THREADNODE *cur,*top,**tc;
 98.4783 +  SORTPGM pgm,pgm2;
 98.4784 +  SORTCACHE *s;
 98.4785 +  unsigned long i,j,*lst,*ls;
 98.4786 +				/* sort by subject+date */
 98.4787 +  memset (&pgm,0,sizeof (SORTPGM));
 98.4788 +  memset (&pgm2,0,sizeof (SORTPGM));
 98.4789 +  pgm.function = SORTSUBJECT;
 98.4790 +  pgm.next = &pgm2;
 98.4791 +  pgm2.function = SORTDATE;
 98.4792 +  if (lst = (*sorter) (stream,charset,spg,&pgm,flags & ~(SE_FREE | SE_UID))){
 98.4793 +    if (*(ls = lst)) {		/* create thread */
 98.4794 +				/* note first subject */
 98.4795 +      cur = top = thr = mail_newthreadnode
 98.4796 +	((SORTCACHE *) (*mailcache) (stream,*ls++,CH_SORTCACHE));
 98.4797 +				/* note its number */
 98.4798 +      cur->num = (flags & SE_UID) ? mail_uid (stream,*lst) : *lst;
 98.4799 +      i = 1;			/* number of threads */
 98.4800 +      while (*ls) {		/* build tree */
 98.4801 +				/* subjects match? */
 98.4802 +	s = (SORTCACHE *) (*mailcache) (stream,*ls++,CH_SORTCACHE);
 98.4803 +	if (compare_cstring (top->sc->subject,s->subject)) {
 98.4804 +	  i++;			/* have a new thread */
 98.4805 +	  top = top->branch = cur = mail_newthreadnode (s);
 98.4806 +	}
 98.4807 +				/* start a child of the top */
 98.4808 +	else if (cur == top) cur = cur->next = mail_newthreadnode (s);
 98.4809 +				/* sibling of child */
 98.4810 +	else cur = cur->branch = mail_newthreadnode (s);
 98.4811 +				/* set to msgno or UID as needed */
 98.4812 +	cur->num = (flags & SE_UID) ? mail_uid (stream,s->num) : s->num;
 98.4813 +      }
 98.4814 +				/* make threadnode cache */
 98.4815 +      tc = (THREADNODE **) fs_get (i * sizeof (THREADNODE *));
 98.4816 +				/* load threadnode cache */
 98.4817 +      for (j = 0, cur = thr; cur; cur = cur->branch) tc[j++] = cur;
 98.4818 +      if (i != j) fatal ("Threadnode cache confusion");
 98.4819 +      qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date);
 98.4820 +      for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1];
 98.4821 +      tc[j]->branch = NIL;	/* end of root */
 98.4822 +      thr = tc[0];		/* head of data */
 98.4823 +      fs_give ((void **) &tc);
 98.4824 +    }
 98.4825 +    fs_give ((void **) &lst);
 98.4826 +  }
 98.4827 +  return thr;
 98.4828 +}
 98.4829 +
 98.4830 +/* Mail thread references
 98.4831 + * Accepts: mail stream
 98.4832 + *	    character set
 98.4833 + *	    search program
 98.4834 + *	    option flags
 98.4835 + *	    sorter routine
 98.4836 + * Returns: thread node tree
 98.4837 + */
 98.4838 +
 98.4839 +#define REFHASHSIZE 1009	/* arbitrary prime for hash table size */
 98.4840 +
 98.4841 +/*  Reference threading container, as described in Jamie Zawinski's web page
 98.4842 + * (http://www.jwz.org/doc/threading.html) for this algorithm.  These are
 98.4843 + * stored as extended data in the hash table (called "id_table" in JWZ's
 98.4844 + * document) and are maintained by the hash table routines.  The hash table
 98.4845 + * routines implement extended data as additional void* words at the end of
 98.4846 + * each bucket, hence these strange macros instead of a struct which would
 98.4847 + * have been more straightforward.
 98.4848 + */
 98.4849 +
 98.4850 +#define THREADLINKS 3		/* number of thread links */
 98.4851 +
 98.4852 +#define CACHE(data) ((SORTCACHE *) (data)[0])
 98.4853 +#define PARENT(data) ((container_t) (data)[1])
 98.4854 +#define SETPARENT(data,value) ((container_t) (data[1] = value))
 98.4855 +#define SIBLING(data) ((container_t) (data)[2])
 98.4856 +#define SETSIBLING(data,value) ((container_t) (data[2] = value))
 98.4857 +#define CHILD(data) ((container_t) (data)[3])
 98.4858 +#define SETCHILD(data,value) ((container_t) (data[3] = value))
 98.4859 +
 98.4860 +THREADNODE *mail_thread_references (MAILSTREAM *stream,char *charset,
 98.4861 +				    SEARCHPGM *spg,long flags,sorter_t sorter)
 98.4862 +{
 98.4863 +  MESSAGECACHE *elt,telt;
 98.4864 +  ENVELOPE *env;
 98.4865 +  SORTCACHE *s;
 98.4866 +  STRINGLIST *st;
 98.4867 +  HASHENT *he;
 98.4868 +  THREADNODE **tc,*cur,*lst,*nxt,*sis,*msg;
 98.4869 +  container_t con,nxc,prc,sib;
 98.4870 +  void **sub;
 98.4871 +  char *t,tmp[MAILTMPLEN];
 98.4872 +  unsigned long j,nmsgs;
 98.4873 +  unsigned long i = stream->nmsgs * sizeof (SORTCACHE *);
 98.4874 +  SORTCACHE **sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i);
 98.4875 +  HASHTAB *ht = hash_create (REFHASHSIZE);
 98.4876 +  THREADNODE *root = NIL;
 98.4877 +  if (spg) {			/* only if a search needs to be done */
 98.4878 +    int silent = stream->silent;
 98.4879 +    stream->silent = T;		/* don't pass up mm_searched() events */
 98.4880 +				/* search for messages */
 98.4881 +    mail_search_full (stream,charset,spg,NIL);
 98.4882 +    stream->silent = silent;	/* restore silence state */
 98.4883 +  }
 98.4884 +
 98.4885 +				/* create SORTCACHE vector of requested msgs */
 98.4886 +  for (i = 1, nmsgs = 0; i <= stream->nmsgs; ++i)
 98.4887 +    if (mail_elt (stream,i)->searched)
 98.4888 +      (sc[nmsgs++] = (SORTCACHE *)(*mailcache)(stream,i,CH_SORTCACHE))->num =i;
 98.4889 +	/* separate pass so can do overview fetch lookahead */
 98.4890 +  for (i = 0; i < nmsgs; ++i) {	/* for each requested message */
 98.4891 +				/* is anything missing in its SORTCACHE? */
 98.4892 +    if (!((s = sc[i])->date && s->subject && s->message_id && s->references)) {
 98.4893 +				/* driver has an overview mechanism? */
 98.4894 +      if (stream->dtb && stream->dtb->overview) {
 98.4895 +				/* yes, find following unloaded entries */
 98.4896 +	for (j = i + 1; (j < nmsgs) && !sc[j]->references; ++j);
 98.4897 +	sprintf (tmp,"%lu",mail_uid (stream,s->num));
 98.4898 +	if (i != --j)		/* end of range different? */
 98.4899 +	  sprintf (tmp + strlen (tmp),":%lu",mail_uid (stream,sc[j]->num));
 98.4900 +				/* load via overview mechanism */
 98.4901 +	mail_fetch_overview (stream,tmp,mail_thread_loadcache);
 98.4902 +      }
 98.4903 +				/* still missing data? */
 98.4904 +      if (!s->date || !s->subject || !s->message_id || !s->references) {
 98.4905 +				/* try to load data from envelope */
 98.4906 +	if (env = mail_fetch_structure (stream,s->num,NIL,NIL)) {
 98.4907 +	  if (!s->date && env->date && mail_parse_date (&telt,env->date))
 98.4908 +	    s->date = mail_longdate (&telt);
 98.4909 +	  if (!s->subject && env->subject)
 98.4910 +	    s->refwd =
 98.4911 +	      mail_strip_subject (env->subject,&s->subject);
 98.4912 +	  if (!s->message_id && env->message_id && *env->message_id)
 98.4913 +	    s->message_id = mail_thread_parse_msgid (env->message_id,NIL);
 98.4914 +	  if (!s->references &&	/* use References: or In-Reply-To: */
 98.4915 +	      !(s->references = 
 98.4916 +		mail_thread_parse_references (env->references,T)))
 98.4917 +	    s->references = mail_thread_parse_references(env->in_reply_to,NIL);
 98.4918 +	}
 98.4919 +				/* last resort */
 98.4920 +	if (!s->date && !(s->date = s->arrival)) {
 98.4921 +				/* internal date unknown but can get? */
 98.4922 +	  if (!(elt = mail_elt (stream,s->num))->day &&
 98.4923 +	      !(stream->dtb->flags & DR_NOINTDATE)) {
 98.4924 +	    sprintf (tmp,"%lu",s->num);
 98.4925 +	    mail_fetch_fast (stream,tmp,NIL);
 98.4926 +	  }
 98.4927 +				/* wrong thing before 3-Jan-1970 */
 98.4928 +	  s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1);
 98.4929 +	}
 98.4930 +	if (!s->subject) s->subject = cpystr ("");
 98.4931 +	if (!s->references) s->references = mail_newstringlist ();
 98.4932 +	s->dirty = T;
 98.4933 +      }
 98.4934 +    }
 98.4935 +
 98.4936 +			/* Step 1 (preliminary) */
 98.4937 +				/* generate unique string */
 98.4938 +    sprintf (tmp,"%s.%lx.%lx@%s",stream->mailbox,stream->uid_validity,
 98.4939 +	     mail_uid (stream,s->num),mylocalhost ());
 98.4940 +				/* flush old unique string if not message-id */
 98.4941 +    if (s->unique && (s->unique != s->message_id))
 98.4942 +      fs_give ((void **) &s->unique);
 98.4943 +    s->unique = s->message_id ?	/* don't permit Message ID duplicates */
 98.4944 +      (hash_lookup (ht,s->message_id) ? cpystr (tmp) : s->message_id) :
 98.4945 +	(s->message_id = cpystr (tmp));
 98.4946 +				/* add unique string to hash table */
 98.4947 +    hash_add (ht,s->unique,s,THREADLINKS);
 98.4948 +  }
 98.4949 +			/* Step 1 */
 98.4950 +  for (i = 0; i < nmsgs; ++i) {	/* for each message in sortcache */
 98.4951 +			/* Step 1A */
 98.4952 +    if ((st = (s = sc[i])->references) && st->text.data)
 98.4953 +      for (con = hash_lookup_and_add (ht,(char *) st->text.data,NIL,
 98.4954 +				      THREADLINKS); st = st->next; con = nxc) {
 98.4955 +	nxc = hash_lookup_and_add (ht,(char *) st->text.data,NIL,THREADLINKS);
 98.4956 +				/* only if no parent & won't introduce loop */
 98.4957 +	if (!PARENT (nxc) && !mail_thread_check_child (con,nxc)) {
 98.4958 +	  SETPARENT (nxc,con);	/* establish parent/child link */
 98.4959 +				/* other children become sibling of this one */
 98.4960 +	  SETSIBLING (nxc,CHILD (con));
 98.4961 +	  SETCHILD (con,nxc);	/* set as child of parent */
 98.4962 +	}
 98.4963 +      }
 98.4964 +    else con = NIL;		/* else message has no ancestors */
 98.4965 +			/* Step 1B */
 98.4966 +    if ((prc = PARENT ((nxc = hash_lookup (ht,s->unique)))) &&
 98.4967 +	(prc != con)) {		/* break links if have a different parent */
 98.4968 +      SETPARENT (nxc,NIL);	/* easy if direct child */
 98.4969 +      if (nxc == CHILD (prc)) SETCHILD (prc,SIBLING (nxc));
 98.4970 +      else {			/* otherwise hunt through sisters */
 98.4971 +	for (sib = CHILD (prc); nxc != SIBLING (sib); sib = SIBLING (sib));
 98.4972 +	SETSIBLING (sib,SIBLING (nxc));
 98.4973 +      }
 98.4974 +      SETSIBLING (nxc,NIL);	/* no more little sisters either */
 98.4975 +      prc = NIL;		/* no more parent set */
 98.4976 +    }
 98.4977 +				/* need to set parent, and parent is good? */
 98.4978 +    if (!prc && !mail_thread_check_child (con,nxc)) {
 98.4979 +      SETPARENT (nxc,con);	/* establish parent/child link */
 98.4980 +      if (con) {		/* if non-root parent, set parent's child */
 98.4981 +	if (CHILD (con)) {	/* have a child already */
 98.4982 +				/* find youngest daughter */
 98.4983 +	  for (con = CHILD (con); SIBLING (con); con = SIBLING (con));
 98.4984 +	  SETSIBLING (con,nxc);	/* add new baby sister */
 98.4985 +	}
 98.4986 +	else SETCHILD (con,nxc);/* set as only child */
 98.4987 +      }
 98.4988 +    }
 98.4989 +  }
 98.4990 +  fs_give ((void **) &sc);	/* finished with sortcache vector */
 98.4991 +
 98.4992 +			/* Step 2 */
 98.4993 +				/* search hash table for parentless messages */
 98.4994 +  for (i = 0, prc = con = NIL; i < ht->size; i++)
 98.4995 +    for (he = ht->table[i]; he; he = he->next)
 98.4996 +      if (!PARENT ((nxc = he->data))) {
 98.4997 +				/* sibling of previous parentless message */
 98.4998 +	if (con) con = SETSIBLING (con,nxc);
 98.4999 +	else prc = con = nxc;	/* first parentless message */
 98.5000 +      }
 98.5001 +  /*  Once the dummy containers are pruned, we no longer need the parent
 98.5002 +   * information, so we can convert the containers to THREADNODEs.  Since
 98.5003 +   * we don't need the id_table any more either, we can reset the hash table
 98.5004 +   * and reuse it as a subject_table.  Resetting the hash table will also
 98.5005 +   * destroy the containers.
 98.5006 +   */
 98.5007 +			/* Step 3 */
 98.5008 +				/* prune dummies, convert to threadnode */
 98.5009 +  root = mail_thread_c2node (stream,mail_thread_prune_dummy (prc,NIL),flags);
 98.5010 +			/* Step 4 */
 98.5011 +				/* make buffer for sorting */
 98.5012 +  tc = (THREADNODE **) fs_get (nmsgs * sizeof (THREADNODE *));
 98.5013 +				/* load threadcache and count nodes to sort */
 98.5014 +  for (i = 0, cur = root; cur ; cur = cur->branch) tc[i++] = cur;
 98.5015 +  if (i > 1) {			/* only if need to sort */
 98.5016 +    qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date);
 98.5017 +				/* relink siblings */
 98.5018 +    for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1];
 98.5019 +    tc[j]->branch = NIL;	/* end of root */
 98.5020 +    root = tc[0];		/* establish new root */
 98.5021 +  }
 98.5022 +			/* Step 5A */
 98.5023 +  hash_reset (ht);		/* discard containers, reset ht */
 98.5024 +			/* Step 5B */
 98.5025 +  for (cur = root; cur; cur = cur->branch)
 98.5026 +    if ((t = (nxt = (cur->sc ? cur : cur->next))->sc->subject) && *t) {
 98.5027 +				/* add new subject to hash table */
 98.5028 +      if (!(sub = hash_lookup (ht,t))) hash_add (ht,t,cur,0);
 98.5029 +				/* if one in table not dummy and */
 98.5030 +      else if ((s = (lst = (THREADNODE *) sub[0])->sc) &&
 98.5031 +				/* current dummy, or not re/fwd and table is */
 98.5032 +	       (!cur->sc || (!nxt->sc->refwd && s->refwd)))
 98.5033 +	sub[0] = (void *) cur;	/* replace with this message */
 98.5034 +    }
 98.5035 +
 98.5036 +			/* Step 5C */
 98.5037 +  for (cur = root, sis = NIL; cur; cur = msg) {
 98.5038 +				/* do nothing if current message or no sub */
 98.5039 +    if (!(t = (cur->sc ? cur : cur->next)->sc->subject) || !*t ||
 98.5040 +	((lst = (THREADNODE *) (sub = hash_lookup (ht,t))[0]) == cur))
 98.5041 +      msg = (sis = cur)->branch;
 98.5042 +    else if (!lst->sc) {	/* is message in the table a dummy? */
 98.5043 +				/* find youngest daughter of msg in table */
 98.5044 +      for (msg = lst->next; msg->branch; msg = msg->branch);
 98.5045 +      if (!cur->sc) {		/* current message a dummy? */
 98.5046 +	msg->branch = cur->next;/* current's daughter now dummy's youngest */
 98.5047 +	msg = cur->branch;	/* continue scan at younger sister */
 98.5048 +				/* now delete this node */
 98.5049 +	cur->branch = cur->next = NIL;
 98.5050 +	mail_free_threadnode (&cur);
 98.5051 +      }
 98.5052 +      else {			/* current message not a dummy */
 98.5053 +	msg->branch = cur;	/* append as youngest daughter */
 98.5054 +	msg = cur->branch;	/* continue scan at younger sister */
 98.5055 +	cur->branch = NIL;	/* lose our younger sisters */
 98.5056 +      }
 98.5057 +    }
 98.5058 +    else {			/* no dummies, is current re/fwd, table not? */
 98.5059 +      if (cur->sc->refwd && !lst->sc->refwd) {
 98.5060 +	if (lst->next) {	/* find youngest daughter of msg in table */
 98.5061 +	  for (msg = lst->next; msg->branch; msg = msg->branch);
 98.5062 +	  msg->branch = cur;	/* append as youngest daughter */
 98.5063 +	}
 98.5064 +	else lst->next = cur;	/* no children, so make the eldest daughter */
 98.5065 +      }
 98.5066 +
 98.5067 +      else {			/* no re/fwd, create a new dummy */
 98.5068 +	msg = mail_newthreadnode (NIL);
 98.5069 +	if (lst == root) {	/* msg in table is root? */
 98.5070 +	  root = lst->branch;	/* younger sister becomes new root */
 98.5071 +				/* no longer older sister either */
 98.5072 +	  if (lst == sis) sis = NIL;
 98.5073 +	}
 98.5074 +	else {			/* find older sister of msg in table */
 98.5075 +	  for (nxt = root; lst != nxt->branch; nxt = nxt->branch);
 98.5076 +				/* remove from older sister */
 98.5077 +	  nxt->branch = lst->branch;
 98.5078 +	}
 98.5079 +	msg->next = lst;	/* msg in table becomes child */
 98.5080 +	lst->branch = cur;	/* current now little sister of msg in table */
 98.5081 +	if (sis) {		/* have an elder sister? */
 98.5082 +	  if (sis == lst)	/* rescan if lost her */
 98.5083 +	    for (sis = root; cur != sis->branch; sis = sis->branch);
 98.5084 +	  sis->branch = msg;	/* make dummy younger sister of big sister */
 98.5085 +	}
 98.5086 +	else root = msg;	/* otherwise this is the new root */
 98.5087 +	sub[0] = sis = msg;	/* set new msg in table and new big sister */
 98.5088 +      }
 98.5089 +      msg = cur->branch;	/* continue scan at younger sister */
 98.5090 +      cur->branch = NIL;	/* lose our younger sisters */
 98.5091 +    }
 98.5092 +    if (sis) sis->branch = msg;	/* older sister gets this as younger sister */
 98.5093 +    else root = msg;		/* otherwise this is the new root */
 98.5094 +  }
 98.5095 +  hash_destroy (&ht);		/* finished with hash table */
 98.5096 +			/* Step 6 */
 98.5097 +				/* sort threads */
 98.5098 +  root = mail_thread_sort (root,tc);
 98.5099 +  fs_give ((void **) &tc);	/* finished with sort buffer */
 98.5100 +  return root;			/* return sorted list */
 98.5101 +}
 98.5102 +
 98.5103 +/* Fetch overview callback to load sortcache for threading
 98.5104 + * Accepts: MAIL stream
 98.5105 + *	    UID of this message
 98.5106 + *	    overview of this message
 98.5107 + *	    msgno of this message
 98.5108 + */
 98.5109 +
 98.5110 +void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
 98.5111 +			    unsigned long msgno)
 98.5112 +{
 98.5113 +  if (msgno && ov) {		/* just in case */
 98.5114 +    MESSAGECACHE telt;
 98.5115 +    SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
 98.5116 +    if (!s->subject && ov->subject) {
 98.5117 +      s->refwd = mail_strip_subject (ov->subject,&s->subject);
 98.5118 +      s->dirty = T;
 98.5119 +    }
 98.5120 +    if (!s->from && ov->from && ov->from->mailbox) {
 98.5121 +      s->from = cpystr (ov->from->mailbox);
 98.5122 +      s->dirty = T;
 98.5123 +    }
 98.5124 +    if (!s->date && ov->date && mail_parse_date (&telt,ov->date)) {
 98.5125 +      s->date = mail_longdate (&telt);
 98.5126 +      s->dirty = T;
 98.5127 +    }
 98.5128 +    if (!s->message_id && ov->message_id) {
 98.5129 +      s->message_id = mail_thread_parse_msgid (ov->message_id,NIL);
 98.5130 +      s->dirty = T;
 98.5131 +    }
 98.5132 +    if (!s->references &&
 98.5133 +	!(s->references = mail_thread_parse_references (ov->references,T))) {
 98.5134 +				/* don't do In-Reply-To with NNTP mailboxes */
 98.5135 +      s->references = mail_newstringlist ();
 98.5136 +      s->dirty = T;
 98.5137 +    }
 98.5138 +    if (!s->size && ov->optional.octets) {
 98.5139 +      s->size = ov->optional.octets;
 98.5140 +      s->dirty = T;
 98.5141 +    }
 98.5142 +  }
 98.5143 +}
 98.5144 +
 98.5145 +/* Thread parse Message ID
 98.5146 + * Accepts: pointer to purported Message ID
 98.5147 + *	    pointer to return pointer
 98.5148 + * Returns: Message ID or NIL, return pointer updated
 98.5149 + */
 98.5150 +
 98.5151 +char *mail_thread_parse_msgid (char *s,char **ss)
 98.5152 +{
 98.5153 +  char *ret = NIL;
 98.5154 +  char *t = NIL;
 98.5155 +  ADDRESS *adr;
 98.5156 +  if (s) {			/* only for non-NIL strings */
 98.5157 +    rfc822_skipws (&s);		/* skip whitespace */
 98.5158 +				/* ignore phrases */
 98.5159 +    if (((*s == '<') || (s = rfc822_parse_phrase (s))) &&
 98.5160 +	(adr = rfc822_parse_routeaddr (s,&t,BADHOST))) {
 98.5161 +				/* make return msgid */
 98.5162 +      if (adr->mailbox && adr->host)
 98.5163 +	sprintf (ret = (char *) fs_get (strlen (adr->mailbox) +
 98.5164 +					strlen (adr->host) + 2),"%s@%s",
 98.5165 +		 adr->mailbox,adr->host);
 98.5166 +      mail_free_address (&adr);	/* don't need temporary address */
 98.5167 +    }
 98.5168 +  }
 98.5169 +  if (ss) *ss = t;		/* update return pointer */
 98.5170 +  return ret;
 98.5171 +}
 98.5172 +
 98.5173 +
 98.5174 +/* Thread parse references
 98.5175 + * Accepts: pointer to purported references
 98.5176 + *	    parse multiple references flag
 98.5177 + * Returns: references or NIL
 98.5178 + */
 98.5179 +
 98.5180 +STRINGLIST *mail_thread_parse_references (char *s,long flag)
 98.5181 +{
 98.5182 +  char *t;
 98.5183 +  STRINGLIST *ret = NIL;
 98.5184 +  STRINGLIST *cur;
 98.5185 +				/* found first reference? */
 98.5186 +  if (t = mail_thread_parse_msgid (s,&s)) {
 98.5187 +    (ret = mail_newstringlist ())->text.data = (unsigned char *) t;
 98.5188 +    ret->text.size = strlen (t);
 98.5189 +    if (flag)			/* parse subsequent references */
 98.5190 +      for (cur = ret; t = mail_thread_parse_msgid (s,&s); cur = cur->next) {
 98.5191 +	(cur->next = mail_newstringlist ())->text.data = (unsigned char *) t;
 98.5192 +	cur->next->text.size = strlen (t);
 98.5193 +      }
 98.5194 +  }
 98.5195 +  return ret;
 98.5196 +}
 98.5197 +
 98.5198 +/* Prune dummy messages
 98.5199 + * Accepts: candidate container to prune
 98.5200 + *	    older sibling of container, if any
 98.5201 + * Returns: container in this position, possibly pruned
 98.5202 + * All children and younger siblings are also pruned
 98.5203 + */
 98.5204 +
 98.5205 +container_t mail_thread_prune_dummy (container_t msg,container_t ane)
 98.5206 +{
 98.5207 +				/* prune container and children */
 98.5208 +  container_t ret = msg ? mail_thread_prune_dummy_work (msg,ane) : NIL;
 98.5209 +				/* prune all younger sisters */
 98.5210 +  if (ret) for (ane = ret; ane && (msg = SIBLING (ane)); ane = msg)
 98.5211 +    msg = mail_thread_prune_dummy_work (msg,ane);
 98.5212 +  return ret;
 98.5213 +}
 98.5214 +
 98.5215 +
 98.5216 +/* Prune dummy messages worker routine
 98.5217 + * Accepts: candidate container to prune
 98.5218 + *	    older sibling of container, if any
 98.5219 + * Returns: container in this position, possibly pruned
 98.5220 + * All children are also pruned
 98.5221 + */
 98.5222 +
 98.5223 +container_t mail_thread_prune_dummy_work (container_t msg,container_t ane)
 98.5224 +{
 98.5225 +  container_t cur;
 98.5226 +				/* get children, if any */
 98.5227 +  container_t nxt = mail_thread_prune_dummy (CHILD (msg),NIL);
 98.5228 +				/* just update children if container has msg */
 98.5229 +  if (CACHE (msg)) SETCHILD (msg,nxt);
 98.5230 +  else if (!nxt) {		/* delete dummy with no children */
 98.5231 +    nxt = SIBLING (msg);	/* get younger sister */
 98.5232 +    if (ane) SETSIBLING (ane,nxt);
 98.5233 +				/* prune younger sister if exists */
 98.5234 +    msg = nxt ? mail_thread_prune_dummy_work (nxt,ane) : NIL;
 98.5235 +  }
 98.5236 +				/* not if parent root & multiple children */
 98.5237 +  else if ((cur = PARENT (msg)) || !SIBLING (nxt)) {
 98.5238 +				/* OK to promote, try younger sister of aunt */
 98.5239 +    if (ane) SETSIBLING (ane,nxt);
 98.5240 +				/* otherwise promote to child of grandmother */
 98.5241 +    else if (cur) SETCHILD (cur,nxt);
 98.5242 +    SETPARENT (nxt,cur);	/* set parent as well */
 98.5243 +				/* look for end of siblings in new container */
 98.5244 +    for (cur = nxt; SIBLING (cur); cur = SIBLING (cur));
 98.5245 +				/* reattach deleted container's siblings */
 98.5246 +    SETSIBLING (cur,SIBLING (msg));
 98.5247 +				/* prune and return new container */
 98.5248 +    msg = mail_thread_prune_dummy_work (nxt,ane);
 98.5249 +  }
 98.5250 +  else SETCHILD (msg,nxt);	/* in case child pruned */
 98.5251 +  return msg;			/* return this message */
 98.5252 +}
 98.5253 +
 98.5254 +/* Test that purported mother is not a child of purported daughter
 98.5255 + * Accepts: mother
 98.5256 + *	    purported daugher
 98.5257 + * Returns: T if circular parentage exists, else NIL
 98.5258 + */
 98.5259 +
 98.5260 +long mail_thread_check_child (container_t mother,container_t daughter)
 98.5261 +{
 98.5262 +  if (mother) {			/* only if mother non-NIL */
 98.5263 +    if (mother == daughter) return T;
 98.5264 +    for (daughter = CHILD (daughter); daughter; daughter = SIBLING (daughter))
 98.5265 +      if (mail_thread_check_child (mother,daughter)) return T;
 98.5266 +  }
 98.5267 +  return NIL;
 98.5268 +}
 98.5269 +
 98.5270 +
 98.5271 +/* Generate threadnodes from containers
 98.5272 + * Accepts: Mail stream
 98.5273 + *	    container
 98.5274 + *	    flags
 98.5275 + * Return: threadnode list
 98.5276 + */
 98.5277 +
 98.5278 +THREADNODE *mail_thread_c2node (MAILSTREAM *stream,container_t con,long flags)
 98.5279 +{
 98.5280 +  THREADNODE *ret,*cur;
 98.5281 +  SORTCACHE *s;
 98.5282 +  container_t nxt;
 98.5283 +				/* for each container */
 98.5284 +  for (ret = cur = NIL; con; con = SIBLING (con)) {
 98.5285 +    s = CACHE (con);		/* yes, get its sortcache */
 98.5286 +				/* create node for it */
 98.5287 +    if (ret) cur = cur->branch = mail_newthreadnode (s);
 98.5288 +    else ret = cur = mail_newthreadnode (s);
 98.5289 +				/* attach sequence or UID for non-dummy */
 98.5290 +    if (s) cur->num = (flags & SE_UID) ? mail_uid (stream,s->num) : s->num;
 98.5291 +				/* attach the children */
 98.5292 +    if (nxt = CHILD (con)) cur->next = mail_thread_c2node (stream,nxt,flags);
 98.5293 +  }
 98.5294 +  return ret;
 98.5295 +}
 98.5296 +
 98.5297 +/* Sort thread tree by date
 98.5298 + * Accepts: thread tree to sort
 98.5299 + *	    qsort vector to sort
 98.5300 + * Returns: sorted thread tree
 98.5301 + */
 98.5302 +
 98.5303 +THREADNODE *mail_thread_sort (THREADNODE *thr,THREADNODE **tc)
 98.5304 +{
 98.5305 +  unsigned long i,j;
 98.5306 +  THREADNODE *cur;
 98.5307 +				/* sort children of each thread */
 98.5308 +  for (cur = thr; cur; cur = cur->branch)
 98.5309 +    if (cur->next) cur->next = mail_thread_sort (cur->next,tc);
 98.5310 +  /* Must do this in a separate pass since recursive call will clobber tc */
 98.5311 +				/* load threadcache and count nodes to sort */
 98.5312 +  for (i = 0, cur = thr; cur; cur = cur->branch) tc[i++] = cur;
 98.5313 +  if (i > 1) {			/* only if need to sort */
 98.5314 +    qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date);
 98.5315 +				/* relink root siblings */
 98.5316 +    for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1];
 98.5317 +    tc[j]->branch = NIL;	/* end of root */
 98.5318 +  }
 98.5319 +  return i ? tc[0] : NIL;	/* return new head of list */
 98.5320 +}
 98.5321 +
 98.5322 +
 98.5323 +/* Thread compare date
 98.5324 + * Accept: first message sort cache element
 98.5325 + *	   second message sort cache element
 98.5326 + * Returns: -1 if a1 < a2, 1 if a1 > a2
 98.5327 + *
 98.5328 + * This assumes that a sort cache element is either a message (with a
 98.5329 + * sortcache entry) or a dummy with a message (with sortcache entry) child.
 98.5330 + * This is true of both the ORDEREDSUBJECT (no dummies) and REFERENCES
 98.5331 + * (dummies only at top-level, and with non-dummy children).
 98.5332 + *
 98.5333 + * If a new algorithm allows a dummy parent to have a dummy child, this
 98.5334 + * routine must be changed if it is to be used by that algorithm.
 98.5335 + *
 98.5336 + * Messages with bogus dates are always sorted at the top.
 98.5337 + */
 98.5338 +
 98.5339 +int mail_thread_compare_date (const void *a1,const void *a2)
 98.5340 +{
 98.5341 +  THREADNODE *t1 = *(THREADNODE **) a1;
 98.5342 +  THREADNODE *t2 = *(THREADNODE **) a2;
 98.5343 +  SORTCACHE *s1 = t1->sc ? t1->sc : t1->next->sc;
 98.5344 +  SORTCACHE *s2 = t2->sc ? t2->sc : t2->next->sc;
 98.5345 +  int ret = compare_ulong (s1->date,s2->date);
 98.5346 +				/* use number as final tie-breaker */
 98.5347 +  return ret ? ret : compare_ulong (s1->num,s2->num);
 98.5348 +}
 98.5349 +
 98.5350 +/* Mail parse sequence
 98.5351 + * Accepts: mail stream
 98.5352 + *	    sequence to parse
 98.5353 + * Returns: T if parse successful, else NIL
 98.5354 + */
 98.5355 +
 98.5356 +long mail_sequence (MAILSTREAM *stream,unsigned char *sequence)
 98.5357 +{
 98.5358 +  unsigned long i,j,x;
 98.5359 +  for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL;
 98.5360 +  while (sequence && *sequence){/* while there is something to parse */
 98.5361 +    if (*sequence == '*') {	/* maximum message */
 98.5362 +      if (stream->nmsgs) i = stream->nmsgs;
 98.5363 +      else {
 98.5364 +	MM_LOG ("No messages, so no maximum message number",ERROR);
 98.5365 +	return NIL;
 98.5366 +      }
 98.5367 +      sequence++;		/* skip past * */
 98.5368 +    }
 98.5369 +				/* parse and validate message number */
 98.5370 +    else if (!isdigit (*sequence)) {
 98.5371 +      MM_LOG ("Syntax error in sequence",ERROR);
 98.5372 +      return NIL;
 98.5373 +    }
 98.5374 +    else if (!(i = strtoul (sequence,(char **) &sequence,10)) ||
 98.5375 +	     (i > stream->nmsgs)) {
 98.5376 +      MM_LOG ("Sequence out of range",ERROR);
 98.5377 +      return NIL;
 98.5378 +    }
 98.5379 +    switch (*sequence) {	/* see what the delimiter is */
 98.5380 +    case ':':			/* sequence range */
 98.5381 +      if (*++sequence == '*') {	/* maximum message */
 98.5382 +	if (stream->nmsgs) j = stream->nmsgs;
 98.5383 +	else {
 98.5384 +	  MM_LOG ("No messages, so no maximum message number",ERROR);
 98.5385 +	  return NIL;
 98.5386 +	}
 98.5387 +	sequence++;		/* skip past * */
 98.5388 +      }
 98.5389 +				/* parse end of range */
 98.5390 +      else if (!(j = strtoul (sequence,(char **) &sequence,10)) ||
 98.5391 +	       (j > stream->nmsgs)) {
 98.5392 +	MM_LOG ("Sequence range invalid",ERROR);
 98.5393 +	return NIL;
 98.5394 +      }
 98.5395 +      if (*sequence && *sequence++ != ',') {
 98.5396 +	MM_LOG ("Sequence range syntax error",ERROR);
 98.5397 +	return NIL;
 98.5398 +      }
 98.5399 +      if (i > j) {		/* swap the range if backwards */
 98.5400 +	x = i; i = j; j = x;
 98.5401 +      }
 98.5402 +				/* mark each item in the sequence */
 98.5403 +      while (i <= j) mail_elt (stream,j--)->sequence = T;
 98.5404 +      break;
 98.5405 +    case ',':			/* single message */
 98.5406 +      ++sequence;		/* skip the delimiter, fall into end case */
 98.5407 +    case '\0':			/* end of sequence, mark this message */
 98.5408 +      mail_elt (stream,i)->sequence = T;
 98.5409 +      break;
 98.5410 +    default:			/* anything else is a syntax error! */
 98.5411 +      MM_LOG ("Sequence syntax error",ERROR);
 98.5412 +      return NIL;
 98.5413 +    }
 98.5414 +  }
 98.5415 +  return T;			/* successfully parsed sequence */
 98.5416 +}
 98.5417 +
 98.5418 +/* Parse flag list
 98.5419 + * Accepts: MAIL stream
 98.5420 + *	    flag list as a character string
 98.5421 + *	    pointer to user flags to return
 98.5422 + * Returns: system flags
 98.5423 + */
 98.5424 +
 98.5425 +long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf)
 98.5426 +{
 98.5427 +  char *t,*n,*s,tmp[MAILTMPLEN],msg[MAILTMPLEN];
 98.5428 +  short f = 0;
 98.5429 +  long i,j;
 98.5430 +  *uf = 0;			/* initially no user flags */
 98.5431 +  if (flag && *flag) {		/* no-op if no flag string */
 98.5432 +				/* check if a list and make sure valid */
 98.5433 +    if (((i = (*flag == '(')) ^ (flag[strlen (flag)-1] == ')')) ||
 98.5434 +	(strlen (flag) >= MAILTMPLEN)) {
 98.5435 +      MM_LOG ("Bad flag list",ERROR);
 98.5436 +      return NIL;
 98.5437 +    }
 98.5438 +				/* copy the flag string w/o list construct */
 98.5439 +    strncpy (n = tmp,flag+i,(j = strlen (flag) - (2*i)));
 98.5440 +    tmp[j] = '\0';
 98.5441 +    while ((t = n) && *t) {	/* parse the flags */
 98.5442 +				/* find end of flag */
 98.5443 +      if (n = strchr (t,' ')) *n++ = '\0';
 98.5444 +      if (*t == '\\') {		/* system flag? */
 98.5445 +	if (!compare_cstring (t+1,"SEEN")) f |= fSEEN;
 98.5446 +	else if (!compare_cstring (t+1,"DELETED")) f |= fDELETED;
 98.5447 +	else if (!compare_cstring (t+1,"FLAGGED")) f |= fFLAGGED;
 98.5448 +	else if (!compare_cstring (t+1,"ANSWERED")) f |= fANSWERED;
 98.5449 +	else if (!compare_cstring (t+1,"DRAFT")) f |= fDRAFT;
 98.5450 +	else {
 98.5451 +	  sprintf (msg,"Unsupported system flag: %.80s",t);
 98.5452 +	  MM_LOG (msg,WARN);
 98.5453 +	}
 98.5454 +      }
 98.5455 +
 98.5456 +      else {			/* keyword flag */
 98.5457 +	for (i = j = 0;		/* user flag, search through table */
 98.5458 +	     !i && (j < NUSERFLAGS) && (s = stream->user_flags[j]); ++j)
 98.5459 +	  if (!compare_cstring (t,s)) *uf |= i = 1 << j;
 98.5460 +	if (!i) {		/* flag not found, can it be created? */
 98.5461 +	  if (stream->kwd_create && (j < NUSERFLAGS) && *t &&
 98.5462 +	      (strlen (t) <= MAXUSERFLAG)) {
 98.5463 +	    for (s = t; t && *s; s++) switch (*s) {
 98.5464 +	    default:		/* all other characters */
 98.5465 +				/* SPACE, CTL, or not CHAR */
 98.5466 +	      if ((*s > ' ') && (*s < 0x7f)) break;
 98.5467 +	    case '*': case '%':	/* list_wildcards */
 98.5468 +	    case '"': case '\\':/* quoted-specials */
 98.5469 +				/* atom_specials */
 98.5470 +	    case '(': case ')': case '{':
 98.5471 +	    case ']':		/* resp-specials */
 98.5472 +	      sprintf (msg,"Invalid flag: %.80s",t);
 98.5473 +	      MM_LOG (msg,WARN);
 98.5474 +	      t = NIL;
 98.5475 +	    }
 98.5476 +	    if (t) {		/* only if valid */
 98.5477 +	      *uf |= 1 << j;	/* set the bit */
 98.5478 +	      stream->user_flags[j] = cpystr (t);
 98.5479 +				/* if out of user flags */
 98.5480 +	      if (j == NUSERFLAGS - 1) stream->kwd_create = NIL;
 98.5481 +	    }
 98.5482 +	  }
 98.5483 +	  else {
 98.5484 +	    if (*t) sprintf (msg,"Unknown flag: %.80s",t);
 98.5485 +	    else strcpy (msg,"Empty flag invalid");
 98.5486 +	    MM_LOG (msg,WARN);
 98.5487 +	  }
 98.5488 +	}
 98.5489 +      }
 98.5490 +    }
 98.5491 +  }
 98.5492 +  return f;
 98.5493 +}
 98.5494 +
 98.5495 +/* Mail check network stream for usability with new name
 98.5496 + * Accepts: MAIL stream
 98.5497 + *	    candidate new name
 98.5498 + * Returns: T if stream can be used, NIL otherwise
 98.5499 + */
 98.5500 +
 98.5501 +long mail_usable_network_stream (MAILSTREAM *stream,char *name)
 98.5502 +{
 98.5503 +  NETMBX smb,nmb,omb;
 98.5504 +  return (stream && stream->dtb && !(stream->dtb->flags & DR_LOCAL) &&
 98.5505 +	  mail_valid_net_parse (name,&nmb) &&
 98.5506 +	  mail_valid_net_parse (stream->mailbox,&smb) &&
 98.5507 +	  mail_valid_net_parse (stream->original_mailbox,&omb) &&
 98.5508 +	  ((!compare_cstring (smb.host,
 98.5509 +			      trustdns ? tcp_canonical (nmb.host) : nmb.host)&&
 98.5510 +	    !strcmp (smb.service,nmb.service) &&
 98.5511 +	    (!nmb.port || (smb.port == nmb.port)) &&
 98.5512 +	    (nmb.anoflag == stream->anonymous) &&
 98.5513 +	    (!nmb.user[0] || !strcmp (smb.user,nmb.user))) ||
 98.5514 +	   (!compare_cstring (omb.host,nmb.host) &&
 98.5515 +	    !strcmp (omb.service,nmb.service) &&
 98.5516 +	    (!nmb.port || (omb.port == nmb.port)) &&
 98.5517 +	    (nmb.anoflag == stream->anonymous) &&
 98.5518 +	    (!nmb.user[0] || !strcmp (omb.user,nmb.user))))) ? LONGT : NIL;
 98.5519 +}
 98.5520 +
 98.5521 +/* Mail data structure instantiation routines */
 98.5522 +
 98.5523 +
 98.5524 +/* Mail instantiate cache elt
 98.5525 + * Accepts: initial message number
 98.5526 + * Returns: new cache elt
 98.5527 + */
 98.5528 +
 98.5529 +MESSAGECACHE *mail_new_cache_elt (unsigned long msgno)
 98.5530 +{
 98.5531 +  MESSAGECACHE *elt = (MESSAGECACHE *) memset (fs_get (sizeof (MESSAGECACHE)),
 98.5532 +					       0,sizeof (MESSAGECACHE));
 98.5533 +  elt->lockcount = 1;		/* initially only cache references it */
 98.5534 +  elt->msgno = msgno;		/* message number */
 98.5535 +  return elt;
 98.5536 +}
 98.5537 +
 98.5538 +
 98.5539 +/* Mail instantiate envelope
 98.5540 + * Returns: new envelope
 98.5541 + */
 98.5542 +
 98.5543 +ENVELOPE *mail_newenvelope (void)
 98.5544 +{
 98.5545 +  return (ENVELOPE *) memset (fs_get (sizeof (ENVELOPE)),0,sizeof (ENVELOPE));
 98.5546 +}
 98.5547 +
 98.5548 +
 98.5549 +/* Mail instantiate address
 98.5550 + * Returns: new address
 98.5551 + */
 98.5552 +
 98.5553 +ADDRESS *mail_newaddr (void)
 98.5554 +{
 98.5555 +  return (ADDRESS *) memset (fs_get (sizeof (ADDRESS)),0,sizeof (ADDRESS));
 98.5556 +}
 98.5557 +
 98.5558 +/* Mail instantiate body
 98.5559 + * Returns: new body
 98.5560 + */
 98.5561 +
 98.5562 +BODY *mail_newbody (void)
 98.5563 +{
 98.5564 +  return mail_initbody ((BODY *) fs_get (sizeof (BODY)));
 98.5565 +}
 98.5566 +
 98.5567 +
 98.5568 +/* Mail initialize body
 98.5569 + * Accepts: body
 98.5570 + * Returns: body
 98.5571 + */
 98.5572 +
 98.5573 +BODY *mail_initbody (BODY *body)
 98.5574 +{
 98.5575 +  memset ((void *) body,0,sizeof (BODY));
 98.5576 +  body->type = TYPETEXT;	/* content type */
 98.5577 +  body->encoding = ENC7BIT;	/* content encoding */
 98.5578 +  return body;
 98.5579 +}
 98.5580 +
 98.5581 +
 98.5582 +/* Mail instantiate body parameter
 98.5583 + * Returns: new body part
 98.5584 + */
 98.5585 +
 98.5586 +PARAMETER *mail_newbody_parameter (void)
 98.5587 +{
 98.5588 +  return (PARAMETER *) memset (fs_get (sizeof(PARAMETER)),0,sizeof(PARAMETER));
 98.5589 +}
 98.5590 +
 98.5591 +
 98.5592 +/* Mail instantiate body part
 98.5593 + * Returns: new body part
 98.5594 + */
 98.5595 +
 98.5596 +PART *mail_newbody_part (void)
 98.5597 +{
 98.5598 +  PART *part = (PART *) memset (fs_get (sizeof (PART)),0,sizeof (PART));
 98.5599 +  mail_initbody (&part->body);	/* initialize the body */
 98.5600 +  return part;
 98.5601 +}
 98.5602 +
 98.5603 +
 98.5604 +/* Mail instantiate body message part
 98.5605 + * Returns: new body message part
 98.5606 + */
 98.5607 +
 98.5608 +MESSAGE *mail_newmsg (void)
 98.5609 +{
 98.5610 +  return (MESSAGE *) memset (fs_get (sizeof (MESSAGE)),0,sizeof (MESSAGE));
 98.5611 +}
 98.5612 +
 98.5613 +/* Mail instantiate string list
 98.5614 + * Returns: new string list
 98.5615 + */
 98.5616 +
 98.5617 +STRINGLIST *mail_newstringlist (void)
 98.5618 +{
 98.5619 +  return (STRINGLIST *) memset (fs_get (sizeof (STRINGLIST)),0,
 98.5620 +				sizeof (STRINGLIST));
 98.5621 +}
 98.5622 +
 98.5623 +
 98.5624 +/* Mail instantiate new search program
 98.5625 + * Returns: new search program
 98.5626 + */
 98.5627 +
 98.5628 +SEARCHPGM *mail_newsearchpgm (void)
 98.5629 +{
 98.5630 +  return (SEARCHPGM *) memset (fs_get (sizeof(SEARCHPGM)),0,sizeof(SEARCHPGM));
 98.5631 +}
 98.5632 +
 98.5633 +
 98.5634 +/* Mail instantiate new search program
 98.5635 + * Accepts: header line name   
 98.5636 + * Returns: new search program
 98.5637 + */
 98.5638 +
 98.5639 +SEARCHHEADER *mail_newsearchheader (char *line,char *text)
 98.5640 +{
 98.5641 +  SEARCHHEADER *hdr = (SEARCHHEADER *) memset (fs_get (sizeof (SEARCHHEADER)),
 98.5642 +					       0,sizeof (SEARCHHEADER));
 98.5643 +  hdr->line.size = strlen ((char *) (hdr->line.data =
 98.5644 +				     (unsigned char *) cpystr (line)));
 98.5645 +  hdr->text.size = strlen ((char *) (hdr->text.data =
 98.5646 +				     (unsigned char *) cpystr (text)));
 98.5647 +  return hdr;
 98.5648 +}
 98.5649 +
 98.5650 +
 98.5651 +/* Mail instantiate new search set
 98.5652 + * Returns: new search set
 98.5653 + */
 98.5654 +
 98.5655 +SEARCHSET *mail_newsearchset (void)
 98.5656 +{
 98.5657 +  return (SEARCHSET *) memset (fs_get (sizeof(SEARCHSET)),0,sizeof(SEARCHSET));
 98.5658 +}
 98.5659 +
 98.5660 +
 98.5661 +/* Mail instantiate new search or
 98.5662 + * Returns: new search or
 98.5663 + */
 98.5664 +
 98.5665 +SEARCHOR *mail_newsearchor (void)
 98.5666 +{
 98.5667 +  SEARCHOR *or = (SEARCHOR *) memset (fs_get (sizeof (SEARCHOR)),0,
 98.5668 +				      sizeof (SEARCHOR));
 98.5669 +  or->first = mail_newsearchpgm ();
 98.5670 +  or->second = mail_newsearchpgm ();
 98.5671 +  return or;
 98.5672 +}
 98.5673 +
 98.5674 +/* Mail instantiate new searchpgmlist
 98.5675 + * Returns: new searchpgmlist
 98.5676 + */
 98.5677 +
 98.5678 +SEARCHPGMLIST *mail_newsearchpgmlist (void)
 98.5679 +{
 98.5680 +  SEARCHPGMLIST *pgl = (SEARCHPGMLIST *)
 98.5681 +    memset (fs_get (sizeof (SEARCHPGMLIST)),0,sizeof (SEARCHPGMLIST));
 98.5682 +  pgl->pgm = mail_newsearchpgm ();
 98.5683 +  return pgl;
 98.5684 +}
 98.5685 +
 98.5686 +
 98.5687 +/* Mail instantiate new sortpgm
 98.5688 + * Returns: new sortpgm
 98.5689 + */
 98.5690 +
 98.5691 +SORTPGM *mail_newsortpgm (void)
 98.5692 +{
 98.5693 +  return (SORTPGM *) memset (fs_get (sizeof (SORTPGM)),0,sizeof (SORTPGM));
 98.5694 +}
 98.5695 +
 98.5696 +
 98.5697 +/* Mail instantiate new threadnode
 98.5698 + * Accepts: sort cache for thread node
 98.5699 + * Returns: new threadnode
 98.5700 + */
 98.5701 +
 98.5702 +THREADNODE *mail_newthreadnode (SORTCACHE *sc)
 98.5703 +{
 98.5704 +  THREADNODE *thr = (THREADNODE *) memset (fs_get (sizeof (THREADNODE)),0,
 98.5705 +					   sizeof (THREADNODE));
 98.5706 +  if (sc) thr->sc = sc;		/* initialize sortcache */
 98.5707 +  return thr;
 98.5708 +}
 98.5709 +
 98.5710 +
 98.5711 +/* Mail instantiate new acllist
 98.5712 + * Returns: new acllist
 98.5713 + */
 98.5714 +
 98.5715 +ACLLIST *mail_newacllist (void)
 98.5716 +{
 98.5717 +  return (ACLLIST *) memset (fs_get (sizeof (ACLLIST)),0,sizeof (ACLLIST));
 98.5718 +}
 98.5719 +
 98.5720 +
 98.5721 +/* Mail instantiate new quotalist
 98.5722 + * Returns: new quotalist
 98.5723 + */
 98.5724 +
 98.5725 +QUOTALIST *mail_newquotalist (void)
 98.5726 +{
 98.5727 +  return (QUOTALIST *) memset (fs_get (sizeof (QUOTALIST)),0,
 98.5728 +			       sizeof (QUOTALIST));
 98.5729 +}
 98.5730 +
 98.5731 +/* Mail garbage collection routines */
 98.5732 +
 98.5733 +
 98.5734 +/* Mail garbage collect body
 98.5735 + * Accepts: pointer to body pointer
 98.5736 + */
 98.5737 +
 98.5738 +void mail_free_body (BODY **body)
 98.5739 +{
 98.5740 +  if (*body) {			/* only free if exists */
 98.5741 +    mail_free_body_data (*body);/* free its data */
 98.5742 +    fs_give ((void **) body);	/* return body to free storage */
 98.5743 +  }
 98.5744 +}
 98.5745 +
 98.5746 +
 98.5747 +/* Mail garbage collect body data
 98.5748 + * Accepts: body pointer
 98.5749 + */
 98.5750 +
 98.5751 +void mail_free_body_data (BODY *body)
 98.5752 +{
 98.5753 +  switch (body->type) {		/* free contents */
 98.5754 +  case TYPEMULTIPART:		/* multiple part */
 98.5755 +    mail_free_body_part (&body->nested.part);
 98.5756 +    break;
 98.5757 +  case TYPEMESSAGE:		/* encapsulated message */
 98.5758 +    if (body->subtype && !strcmp (body->subtype,"RFC822")) {
 98.5759 +      mail_free_stringlist (&body->nested.msg->lines);
 98.5760 +      mail_gc_msg (body->nested.msg,GC_ENV | GC_TEXTS);
 98.5761 +    }
 98.5762 +    if (body->nested.msg) fs_give ((void **) &body->nested.msg);
 98.5763 +    break;
 98.5764 +  default:
 98.5765 +    break;
 98.5766 +  }
 98.5767 +  if (body->subtype) fs_give ((void **) &body->subtype);
 98.5768 +  mail_free_body_parameter (&body->parameter);
 98.5769 +  if (body->id) fs_give ((void **) &body->id);
 98.5770 +  if (body->description) fs_give ((void **) &body->description);
 98.5771 +  if (body->disposition.type) fs_give ((void **) &body->disposition.type);
 98.5772 +  if (body->disposition.parameter)
 98.5773 +    mail_free_body_parameter (&body->disposition.parameter);
 98.5774 +  if (body->language) mail_free_stringlist (&body->language);
 98.5775 +  if (body->location) fs_give ((void **) &body->location);
 98.5776 +  if (body->mime.text.data) fs_give ((void **) &body->mime.text.data);
 98.5777 +  if (body->contents.text.data) fs_give ((void **) &body->contents.text.data);
 98.5778 +  if (body->md5) fs_give ((void **) &body->md5);
 98.5779 +  if (mailfreebodysparep && body->sparep)
 98.5780 +      (*mailfreebodysparep) (&body->sparep);
 98.5781 +}
 98.5782 +
 98.5783 +/* Mail garbage collect body parameter
 98.5784 + * Accepts: pointer to body parameter pointer
 98.5785 + */
 98.5786 +
 98.5787 +void mail_free_body_parameter (PARAMETER **parameter)
 98.5788 +{
 98.5789 +  if (*parameter) {		/* only free if exists */
 98.5790 +    if ((*parameter)->attribute) fs_give ((void **) &(*parameter)->attribute);
 98.5791 +    if ((*parameter)->value) fs_give ((void **) &(*parameter)->value);
 98.5792 +				/* run down the list as necessary */
 98.5793 +    mail_free_body_parameter (&(*parameter)->next);
 98.5794 +				/* return body part to free storage */
 98.5795 +    fs_give ((void **) parameter);
 98.5796 +  }
 98.5797 +}
 98.5798 +
 98.5799 +
 98.5800 +/* Mail garbage collect body part
 98.5801 + * Accepts: pointer to body part pointer
 98.5802 + */
 98.5803 +
 98.5804 +void mail_free_body_part (PART **part)
 98.5805 +{
 98.5806 +  if (*part) {			/* only free if exists */
 98.5807 +    mail_free_body_data (&(*part)->body);
 98.5808 +				/* run down the list as necessary */
 98.5809 +    mail_free_body_part (&(*part)->next);
 98.5810 +    fs_give ((void **) part);	/* return body part to free storage */
 98.5811 +  }
 98.5812 +}
 98.5813 +
 98.5814 +/* Mail garbage collect message cache
 98.5815 + * Accepts: mail stream
 98.5816 + *
 98.5817 + * The message cache is set to NIL when this function finishes.
 98.5818 + */
 98.5819 +
 98.5820 +void mail_free_cache (MAILSTREAM *stream)
 98.5821 +{
 98.5822 +				/* do driver specific stuff first */
 98.5823 +  mail_gc (stream,GC_ELT | GC_ENV | GC_TEXTS);
 98.5824 +				/* flush the cache */
 98.5825 +  (*mailcache) (stream,(long) 0,CH_INIT);
 98.5826 +}
 98.5827 +
 98.5828 +
 98.5829 +/* Mail garbage collect cache element
 98.5830 + * Accepts: pointer to cache element pointer
 98.5831 + */
 98.5832 +
 98.5833 +void mail_free_elt (MESSAGECACHE **elt)
 98.5834 +{
 98.5835 +				/* only free if exists and no sharers */
 98.5836 +  if (*elt && !--(*elt)->lockcount) {
 98.5837 +    mail_gc_msg (&(*elt)->private.msg,GC_ENV | GC_TEXTS);
 98.5838 +    if (mailfreeeltsparep && (*elt)->sparep)
 98.5839 +      (*mailfreeeltsparep) (&(*elt)->sparep);
 98.5840 +    fs_give ((void **) elt);
 98.5841 +  }
 98.5842 +  else *elt = NIL;		/* else simply drop pointer */
 98.5843 +}
 98.5844 +
 98.5845 +/* Mail garbage collect envelope
 98.5846 + * Accepts: pointer to envelope pointer
 98.5847 + */
 98.5848 +
 98.5849 +void mail_free_envelope (ENVELOPE **env)
 98.5850 +{
 98.5851 +  if (*env) {			/* only free if exists */
 98.5852 +    if ((*env)->remail) fs_give ((void **) &(*env)->remail);
 98.5853 +    mail_free_address (&(*env)->return_path);
 98.5854 +    if ((*env)->date) fs_give ((void **) &(*env)->date);
 98.5855 +    mail_free_address (&(*env)->from);
 98.5856 +    mail_free_address (&(*env)->sender);
 98.5857 +    mail_free_address (&(*env)->reply_to);
 98.5858 +    if ((*env)->subject) fs_give ((void **) &(*env)->subject);
 98.5859 +    mail_free_address (&(*env)->to);
 98.5860 +    mail_free_address (&(*env)->cc);
 98.5861 +    mail_free_address (&(*env)->bcc);
 98.5862 +    if ((*env)->in_reply_to) fs_give ((void **) &(*env)->in_reply_to);
 98.5863 +    if ((*env)->message_id) fs_give ((void **) &(*env)->message_id);
 98.5864 +    if ((*env)->newsgroups) fs_give ((void **) &(*env)->newsgroups);
 98.5865 +    if ((*env)->followup_to) fs_give ((void **) &(*env)->followup_to);
 98.5866 +    if ((*env)->references) fs_give ((void **) &(*env)->references);
 98.5867 +    if (mailfreeenvelopesparep && (*env)->sparep)
 98.5868 +      (*mailfreeenvelopesparep) (&(*env)->sparep);
 98.5869 +    fs_give ((void **) env);	/* return envelope to free storage */
 98.5870 +  }
 98.5871 +}
 98.5872 +
 98.5873 +
 98.5874 +/* Mail garbage collect address
 98.5875 + * Accepts: pointer to address pointer
 98.5876 + */
 98.5877 +
 98.5878 +void mail_free_address (ADDRESS **address)
 98.5879 +{
 98.5880 +  if (*address) {		/* only free if exists */
 98.5881 +    if ((*address)->personal) fs_give ((void **) &(*address)->personal);
 98.5882 +    if ((*address)->adl) fs_give ((void **) &(*address)->adl);
 98.5883 +    if ((*address)->mailbox) fs_give ((void **) &(*address)->mailbox);
 98.5884 +    if ((*address)->host) fs_give ((void **) &(*address)->host);
 98.5885 +    if ((*address)->error) fs_give ((void **) &(*address)->error);
 98.5886 +    if ((*address)->orcpt.type) fs_give ((void **) &(*address)->orcpt.type);
 98.5887 +    if ((*address)->orcpt.addr) fs_give ((void **) &(*address)->orcpt.addr);
 98.5888 +    mail_free_address (&(*address)->next);
 98.5889 +    fs_give ((void **) address);/* return address to free storage */
 98.5890 +  }
 98.5891 +}
 98.5892 +
 98.5893 +
 98.5894 +/* Mail garbage collect stringlist
 98.5895 + * Accepts: pointer to stringlist pointer
 98.5896 + */
 98.5897 +
 98.5898 +void mail_free_stringlist (STRINGLIST **string)
 98.5899 +{
 98.5900 +  if (*string) {		/* only free if exists */
 98.5901 +    if ((*string)->text.data) fs_give ((void **) &(*string)->text.data);
 98.5902 +    mail_free_stringlist (&(*string)->next);
 98.5903 +    fs_give ((void **) string);	/* return string to free storage */
 98.5904 +  }
 98.5905 +}
 98.5906 +
 98.5907 +/* Mail garbage collect searchpgm
 98.5908 + * Accepts: pointer to searchpgm pointer
 98.5909 + */
 98.5910 +
 98.5911 +void mail_free_searchpgm (SEARCHPGM **pgm)
 98.5912 +{
 98.5913 +  if (*pgm) {			/* only free if exists */
 98.5914 +    mail_free_searchset (&(*pgm)->msgno);
 98.5915 +    mail_free_searchset (&(*pgm)->uid);
 98.5916 +    mail_free_searchor (&(*pgm)->or);
 98.5917 +    mail_free_searchpgmlist (&(*pgm)->not);
 98.5918 +    mail_free_searchheader (&(*pgm)->header);
 98.5919 +    mail_free_stringlist (&(*pgm)->bcc);
 98.5920 +    mail_free_stringlist (&(*pgm)->body);
 98.5921 +    mail_free_stringlist (&(*pgm)->cc);
 98.5922 +    mail_free_stringlist (&(*pgm)->from);
 98.5923 +    mail_free_stringlist (&(*pgm)->keyword);
 98.5924 +    mail_free_stringlist (&(*pgm)->subject);
 98.5925 +    mail_free_stringlist (&(*pgm)->text);
 98.5926 +    mail_free_stringlist (&(*pgm)->to);
 98.5927 +    fs_give ((void **) pgm);	/* return program to free storage */
 98.5928 +  }
 98.5929 +}
 98.5930 +
 98.5931 +
 98.5932 +/* Mail garbage collect searchheader
 98.5933 + * Accepts: pointer to searchheader pointer
 98.5934 + */
 98.5935 +
 98.5936 +void mail_free_searchheader (SEARCHHEADER **hdr)
 98.5937 +{
 98.5938 +  if (*hdr) {			/* only free if exists */
 98.5939 +    if ((*hdr)->line.data) fs_give ((void **) &(*hdr)->line.data);
 98.5940 +    if ((*hdr)->text.data) fs_give ((void **) &(*hdr)->text.data);
 98.5941 +    mail_free_searchheader (&(*hdr)->next);
 98.5942 +    fs_give ((void **) hdr);	/* return header to free storage */
 98.5943 +  }
 98.5944 +}
 98.5945 +
 98.5946 +
 98.5947 +/* Mail garbage collect searchset
 98.5948 + * Accepts: pointer to searchset pointer
 98.5949 + */
 98.5950 +
 98.5951 +void mail_free_searchset (SEARCHSET **set)
 98.5952 +{
 98.5953 +  if (*set) {			/* only free if exists */
 98.5954 +    mail_free_searchset (&(*set)->next);
 98.5955 +    fs_give ((void **) set);	/* return set to free storage */
 98.5956 +  }
 98.5957 +}
 98.5958 +
 98.5959 +/* Mail garbage collect searchor
 98.5960 + * Accepts: pointer to searchor pointer
 98.5961 + */
 98.5962 +
 98.5963 +void mail_free_searchor (SEARCHOR **orl)
 98.5964 +{
 98.5965 +  if (*orl) {			/* only free if exists */
 98.5966 +    mail_free_searchpgm (&(*orl)->first);
 98.5967 +    mail_free_searchpgm (&(*orl)->second);
 98.5968 +    mail_free_searchor (&(*orl)->next);
 98.5969 +    fs_give ((void **) orl);	/* return searchor to free storage */
 98.5970 +  }
 98.5971 +}
 98.5972 +
 98.5973 +
 98.5974 +/* Mail garbage collect search program list
 98.5975 + * Accepts: pointer to searchpgmlist pointer
 98.5976 + */
 98.5977 +
 98.5978 +void mail_free_searchpgmlist (SEARCHPGMLIST **pgl)
 98.5979 +{
 98.5980 +  if (*pgl) {			/* only free if exists */
 98.5981 +    mail_free_searchpgm (&(*pgl)->pgm);
 98.5982 +    mail_free_searchpgmlist (&(*pgl)->next);
 98.5983 +    fs_give ((void **) pgl);	/* return searchpgmlist to free storage */
 98.5984 +  }
 98.5985 +}
 98.5986 +
 98.5987 +
 98.5988 +/* Mail garbage collect namespace
 98.5989 + * Accepts: poiner to namespace
 98.5990 + */
 98.5991 +
 98.5992 +void mail_free_namespace (NAMESPACE **n)
 98.5993 +{
 98.5994 +  if (*n) {
 98.5995 +    fs_give ((void **) &(*n)->name);
 98.5996 +    mail_free_namespace (&(*n)->next);
 98.5997 +    mail_free_body_parameter (&(*n)->param);
 98.5998 +    fs_give ((void **) n);	/* return namespace to free storage */
 98.5999 +  }
 98.6000 +}
 98.6001 +
 98.6002 +/* Mail garbage collect sort program
 98.6003 + * Accepts: pointer to sortpgm pointer
 98.6004 + */
 98.6005 +
 98.6006 +void mail_free_sortpgm (SORTPGM **pgm)
 98.6007 +{
 98.6008 +  if (*pgm) {			/* only free if exists */
 98.6009 +    mail_free_sortpgm (&(*pgm)->next);
 98.6010 +    fs_give ((void **) pgm);	/* return sortpgm to free storage */
 98.6011 +  }
 98.6012 +}
 98.6013 +
 98.6014 +
 98.6015 +/* Mail garbage collect thread node
 98.6016 + * Accepts: pointer to threadnode pointer
 98.6017 + */
 98.6018 +
 98.6019 +void mail_free_threadnode (THREADNODE **thr)
 98.6020 +{
 98.6021 +  if (*thr) {			/* only free if exists */
 98.6022 +    mail_free_threadnode (&(*thr)->branch);
 98.6023 +    mail_free_threadnode (&(*thr)->next);
 98.6024 +    fs_give ((void **) thr);	/* return threadnode to free storage */
 98.6025 +  }
 98.6026 +}
 98.6027 +
 98.6028 +
 98.6029 +/* Mail garbage collect acllist
 98.6030 + * Accepts: pointer to acllist pointer
 98.6031 + */
 98.6032 +
 98.6033 +void mail_free_acllist (ACLLIST **al)
 98.6034 +{
 98.6035 +  if (*al) {			/* only free if exists */
 98.6036 +    if ((*al)->identifier) fs_give ((void **) &(*al)->identifier);
 98.6037 +    if ((*al)->rights) fs_give ((void **) &(*al)->rights);
 98.6038 +    mail_free_acllist (&(*al)->next);
 98.6039 +    fs_give ((void **) al);	/* return acllist to free storage */
 98.6040 +  }
 98.6041 +}
 98.6042 +
 98.6043 +
 98.6044 +/* Mail garbage collect quotalist
 98.6045 + * Accepts: pointer to quotalist pointer
 98.6046 + */
 98.6047 +
 98.6048 +void mail_free_quotalist (QUOTALIST **ql)
 98.6049 +{
 98.6050 +  if (*ql) {			/* only free if exists */
 98.6051 +    if ((*ql)->name) fs_give ((void **) &(*ql)->name);
 98.6052 +    mail_free_quotalist (&(*ql)->next);
 98.6053 +    fs_give ((void **) ql);	/* return quotalist to free storage */
 98.6054 +  }
 98.6055 +}
 98.6056 +
 98.6057 +/* Link authenicator
 98.6058 + * Accepts: authenticator to add to list
 98.6059 + */
 98.6060 +
 98.6061 +void auth_link (AUTHENTICATOR *auth)
 98.6062 +{
 98.6063 +  if (!auth->valid || (*auth->valid) ()) {
 98.6064 +    AUTHENTICATOR **a = &mailauthenticators;
 98.6065 +    while (*a) a = &(*a)->next;	/* find end of list of authenticators */
 98.6066 +    *a = auth;			/* put authenticator at the end */
 98.6067 +    auth->next = NIL;		/* this authenticator is the end of the list */
 98.6068 +  }
 98.6069 +}
 98.6070 +
 98.6071 +
 98.6072 +/* Authenticate access
 98.6073 + * Accepts: mechanism name
 98.6074 + *	    responder function
 98.6075 + *	    argument count
 98.6076 + *	    argument vector
 98.6077 + * Returns: authenticated user name or NIL
 98.6078 + */
 98.6079 +
 98.6080 +char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[])
 98.6081 +{
 98.6082 +  AUTHENTICATOR *auth;
 98.6083 +  for (auth = mailauthenticators; auth; auth = auth->next)
 98.6084 +    if (auth->server && !compare_cstring (auth->name,mechanism))
 98.6085 +      return (!(auth->flags & AU_DISABLE) &&
 98.6086 +	      ((auth->flags & AU_SECURE) ||
 98.6087 +	       !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))) ?
 98.6088 +	(*auth->server) (resp,argc,argv) : NIL;
 98.6089 +  return NIL;			/* no authenticator found */
 98.6090 +}
 98.6091 +
 98.6092 +/* Lookup authenticator index
 98.6093 + * Accepts: authenticator index
 98.6094 + * Returns: authenticator, or 0 if not found
 98.6095 + */
 98.6096 +
 98.6097 +AUTHENTICATOR *mail_lookup_auth (unsigned long i)
 98.6098 +{
 98.6099 +  AUTHENTICATOR *auth = mailauthenticators;
 98.6100 +  while (auth && --i) auth = auth->next;
 98.6101 +  return auth;
 98.6102 +}
 98.6103 +
 98.6104 +
 98.6105 +/* Lookup authenticator name
 98.6106 + * Accepts: authenticator name
 98.6107 + *	    required authenticator flags
 98.6108 + * Returns: index in authenticator chain, or 0 if not found
 98.6109 + */
 98.6110 +
 98.6111 +unsigned int mail_lookup_auth_name (char *mechanism,long flags)
 98.6112 +{
 98.6113 +  int i;
 98.6114 +  AUTHENTICATOR *auth;
 98.6115 +  for (i = 1, auth = mailauthenticators; auth; i++, auth = auth->next)
 98.6116 +    if (auth->client && !(flags & ~auth->flags) &&
 98.6117 +	!(auth->flags & AU_DISABLE) && !compare_cstring (auth->name,mechanism))
 98.6118 +      return i;
 98.6119 +  return 0;
 98.6120 +}
 98.6121 +
 98.6122 +/* Standard TCP/IP network driver */
 98.6123 +
 98.6124 +static NETDRIVER tcpdriver = {
 98.6125 +  tcp_open,			/* open connection */
 98.6126 +  tcp_aopen,			/* open preauthenticated connection */
 98.6127 +  tcp_getline,			/* get a line */
 98.6128 +  tcp_getbuffer,		/* get a buffer */
 98.6129 +  tcp_soutr,			/* output pushed data */
 98.6130 +  tcp_sout,			/* output string */
 98.6131 +  tcp_close,			/* close connection */
 98.6132 +  tcp_host,			/* return host name */
 98.6133 +  tcp_remotehost,		/* return remote host name */
 98.6134 +  tcp_port,			/* return port number */
 98.6135 +  tcp_localhost			/* return local host name */
 98.6136 +};
 98.6137 +
 98.6138 +
 98.6139 +/* Network open
 98.6140 + * Accepts: NETMBX specifier to open
 98.6141 + *	    default network driver
 98.6142 + *	    default port
 98.6143 + *	    SSL driver
 98.6144 + *	    SSL service name
 98.6145 + *	    SSL driver port
 98.6146 + * Returns: Network stream if success, else NIL
 98.6147 + */
 98.6148 +
 98.6149 +NETSTREAM *net_open (NETMBX *mb,NETDRIVER *dv,unsigned long port,
 98.6150 +		     NETDRIVER *ssld,char *ssls,unsigned long sslp)
 98.6151 +{
 98.6152 +  NETSTREAM *stream = NIL;
 98.6153 +  char tmp[MAILTMPLEN];
 98.6154 +  unsigned long flags = mb->novalidate ? NET_NOVALIDATECERT : 0;
 98.6155 +  if (strlen (mb->host) >= NETMAXHOST) {
 98.6156 +    sprintf (tmp,"Invalid host name: %.80s",mb->host);
 98.6157 +    MM_LOG (tmp,ERROR);
 98.6158 +  }
 98.6159 +				/* use designated driver if given */
 98.6160 +  else if (dv) stream = net_open_work (dv,mb->host,mb->service,port,mb->port,
 98.6161 +				       flags);
 98.6162 +  else if (mb->sslflag && ssld)	/* use ssl if sslflag lit */
 98.6163 +    stream = net_open_work (ssld,mb->host,ssls,sslp,mb->port,flags);
 98.6164 +				/* if trysslfirst and can open ssl... */
 98.6165 +  else if ((mb->trysslflag || trysslfirst) && ssld &&
 98.6166 +	   (stream = net_open_work (ssld,mb->host,ssls,sslp,mb->port,
 98.6167 +				    flags | NET_SILENT | NET_TRYSSL))) {
 98.6168 +    if (net_sout (stream,"",0)) mb->sslflag = T;
 98.6169 +    else {
 98.6170 +      net_close (stream);	/* flush fake SSL stream */
 98.6171 +      stream = NIL;
 98.6172 +    }
 98.6173 +  }
 98.6174 +				/* default to TCP driver */
 98.6175 +  else stream = net_open_work (&tcpdriver,mb->host,mb->service,port,mb->port,
 98.6176 +			       flags);
 98.6177 +  return stream;
 98.6178 +}
 98.6179 +
 98.6180 +/* Network open worker routine
 98.6181 + * Accepts: network driver
 98.6182 + *	    host name
 98.6183 + *	    service name to look up port
 98.6184 + *	    port number if service name not found
 98.6185 + *	    port number to override service name
 98.6186 + *	    flags (passed on top of port)
 98.6187 + * Returns: Network stream if success, else NIL
 98.6188 + */
 98.6189 +
 98.6190 +NETSTREAM *net_open_work (NETDRIVER *dv,char *host,char *service,
 98.6191 +			  unsigned long port,unsigned long portoverride,
 98.6192 +			  unsigned long flags)
 98.6193 +{
 98.6194 +  NETSTREAM *stream = NIL;
 98.6195 +  void *tstream;
 98.6196 +  if (service && (*service == '*')) {
 98.6197 +    flags |= NET_NOOPENTIMEOUT;	/* mark that no timeout is desired */
 98.6198 +    ++service;			/* no longer need the no timeout indicator */
 98.6199 +  }
 98.6200 +  if (portoverride) {		/* explicit port number? */
 98.6201 +    service = NIL;		/* yes, override service name */
 98.6202 +    port = portoverride;	/* use that instead of default port */
 98.6203 +  }
 98.6204 +  if (tstream = (*dv->open) (host,service,port | flags)) {
 98.6205 +    stream = (NETSTREAM *) fs_get (sizeof (NETSTREAM));
 98.6206 +    stream->stream = tstream;
 98.6207 +    stream->dtb = dv;
 98.6208 +  }
 98.6209 +  return stream;
 98.6210 +}
 98.6211 +
 98.6212 +
 98.6213 +/* Network authenticated open
 98.6214 + * Accepts: network driver
 98.6215 + *	    NETMBX specifier
 98.6216 + *	    service specifier
 98.6217 + *	    return user name buffer
 98.6218 + * Returns: Network stream if success else NIL
 98.6219 + */
 98.6220 +
 98.6221 +NETSTREAM *net_aopen (NETDRIVER *dv,NETMBX *mb,char *service,char *user)
 98.6222 +{
 98.6223 +  NETSTREAM *stream = NIL;
 98.6224 +  void *tstream;
 98.6225 +  if (!dv) dv = &tcpdriver;	/* default to TCP driver */
 98.6226 +  if (tstream = (*dv->aopen) (mb,service,user)) {
 98.6227 +    stream = (NETSTREAM *) fs_get (sizeof (NETSTREAM));
 98.6228 +    stream->stream = tstream;
 98.6229 +    stream->dtb = dv;
 98.6230 +  }
 98.6231 +  return stream;
 98.6232 +}
 98.6233 +
 98.6234 +/* Network receive line
 98.6235 + * Accepts: Network stream
 98.6236 + * Returns: text line string or NIL if failure
 98.6237 + */
 98.6238 +
 98.6239 +char *net_getline (NETSTREAM *stream)
 98.6240 +{
 98.6241 +  return (*stream->dtb->getline) (stream->stream);
 98.6242 +}
 98.6243 +
 98.6244 +
 98.6245 +/* Network receive buffer
 98.6246 + * Accepts: Network stream (must be void * for use as readfn_t)
 98.6247 + *	    size in bytes
 98.6248 + *	    buffer to read into
 98.6249 + * Returns: T if success, NIL otherwise
 98.6250 + */
 98.6251 +
 98.6252 +long net_getbuffer (void *st,unsigned long size,char *buffer)
 98.6253 +{
 98.6254 +  NETSTREAM *stream = (NETSTREAM *) st;
 98.6255 +  return (*stream->dtb->getbuffer) (stream->stream,size,buffer);
 98.6256 +}
 98.6257 +
 98.6258 +
 98.6259 +/* Network send null-terminated string
 98.6260 + * Accepts: Network stream
 98.6261 + *	    string pointer
 98.6262 + * Returns: T if success else NIL
 98.6263 + */
 98.6264 +
 98.6265 +long net_soutr (NETSTREAM *stream,char *string)
 98.6266 +{
 98.6267 +  return (*stream->dtb->soutr) (stream->stream,string);
 98.6268 +}
 98.6269 +
 98.6270 +
 98.6271 +/* Network send string
 98.6272 + * Accepts: Network stream
 98.6273 + *	    string pointer
 98.6274 + *	    byte count
 98.6275 + * Returns: T if success else NIL
 98.6276 + */
 98.6277 +
 98.6278 +long net_sout (NETSTREAM *stream,char *string,unsigned long size)
 98.6279 +{
 98.6280 +  return (*stream->dtb->sout) (stream->stream,string,size);
 98.6281 +}
 98.6282 +
 98.6283 +/* Network close
 98.6284 + * Accepts: Network stream
 98.6285 + */
 98.6286 +
 98.6287 +void net_close (NETSTREAM *stream)
 98.6288 +{
 98.6289 +  if (stream->stream) (*stream->dtb->close) (stream->stream);
 98.6290 +  fs_give ((void **) &stream);
 98.6291 +}
 98.6292 +
 98.6293 +
 98.6294 +/* Network get host name
 98.6295 + * Accepts: Network stream
 98.6296 + * Returns: host name for this stream
 98.6297 + */
 98.6298 +
 98.6299 +char *net_host (NETSTREAM *stream)
 98.6300 +{
 98.6301 +  return (*stream->dtb->host) (stream->stream);
 98.6302 +}
 98.6303 +
 98.6304 +
 98.6305 +/* Network get remote host name
 98.6306 + * Accepts: Network stream
 98.6307 + * Returns: host name for this stream
 98.6308 + */
 98.6309 +
 98.6310 +char *net_remotehost (NETSTREAM *stream)
 98.6311 +{
 98.6312 +  return (*stream->dtb->remotehost) (stream->stream);
 98.6313 +}
 98.6314 +
 98.6315 +/* Network return port for this stream
 98.6316 + * Accepts: Network stream
 98.6317 + * Returns: port number for this stream
 98.6318 + */
 98.6319 +
 98.6320 +unsigned long net_port (NETSTREAM *stream)
 98.6321 +{
 98.6322 +  return (*stream->dtb->port) (stream->stream);
 98.6323 +}
 98.6324 +
 98.6325 +
 98.6326 +/* Network get local host name
 98.6327 + * Accepts: Network stream
 98.6328 + * Returns: local host name
 98.6329 + */
 98.6330 +
 98.6331 +char *net_localhost (NETSTREAM *stream)
 98.6332 +{
 98.6333 +  return (*stream->dtb->localhost) (stream->stream);
 98.6334 +}
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/src/c-client/mail.h	Mon Sep 14 15:17:45 2009 +0900
    99.3 @@ -0,0 +1,1837 @@
    99.4 +/* ========================================================================
    99.5 + * Copyright 1988-2008 University of Washington
    99.6 + *
    99.7 + * Licensed under the Apache License, Version 2.0 (the "License");
    99.8 + * you may not use this file except in compliance with the License.
    99.9 + * You may obtain a copy of the License at
   99.10 + *
   99.11 + *     http://www.apache.org/licenses/LICENSE-2.0
   99.12 + *
   99.13 + * 
   99.14 + * ========================================================================
   99.15 + */
   99.16 +
   99.17 +/*
   99.18 + * Program:	Mailbox Access routines
   99.19 + *
   99.20 + * Author:	Mark Crispin
   99.21 + *		UW Technology
   99.22 + *		University of Washington
   99.23 + *		Seattle, WA  98195
   99.24 + *		Internet: MRC@Washington.EDU
   99.25 + *
   99.26 + * Date:	22 November 1989
   99.27 + * Last Edited:	16 December 2008
   99.28 + */
   99.29 +
   99.30 +/* The Version */
   99.31 +
   99.32 +#define CCLIENTVERSION "2007e"
   99.33 +
   99.34 +/* Build parameters */
   99.35 +
   99.36 +#define CACHEINCREMENT 250	/* cache growth increments */
   99.37 +#define MAILTMPLEN 1024		/* size of a temporary buffer */
   99.38 +#define SENDBUFLEN 16385	/* size of temporary sending buffer, also
   99.39 +				 * used for SMTP commands and NETMBX generation
   99.40 +				 * buffer so shouldn't be made smaller than
   99.41 +				 * MAILTMPLEN.  Note that there's a guard byte,
   99.42 +				 * so this is actually len+1. */
   99.43 +#define MAXAUTHENTICATORS 8	/* maximum number of SASL authenticators */
   99.44 +				/* maximum number of messages */
   99.45 +#define MAXMESSAGES (unsigned long) 1000000
   99.46 +#define MAXLOGINTRIALS 3	/* maximum number of client login attempts */
   99.47 +#define MAXWILDCARDS 10		/* maximum wildcards allowed in LIST/LSUB */
   99.48 +
   99.49 +
   99.50 +/* These can't be changed without changing code */
   99.51 +
   99.52 +#define NUSERFLAGS 30		/* maximum number of user flags */
   99.53 +#define MAXUSERFLAG 50		/* maximum length of a user flag */
   99.54 +#define BASEYEAR 1970		/* the year time began on Unix DON'T CHANGE */
   99.55 +				/* default for unqualified addresses */
   99.56 +#define BADHOST ".MISSING-HOST-NAME."
   99.57 +				/* default for syntax errors in addresses */
   99.58 +#define ERRHOST ".SYNTAX-ERROR."
   99.59 +
   99.60 +
   99.61 +/* Coddle certain compilers' 6-character symbol limitation */
   99.62 +
   99.63 +#ifdef __COMPILER_KCC__
   99.64 +#include "shortsym.h"
   99.65 +#endif
   99.66 +
   99.67 +
   99.68 +/* Function status code */
   99.69 +
   99.70 +#define NIL 0			/* convenient name */
   99.71 +#define T 1			/* opposite of NIL */
   99.72 +#define LONGT (long) 1		/* long T to pacify some compilers */
   99.73 +#define VOIDT (void *) ""	/* void T ditto */
   99.74 +
   99.75 +/* Global and Driver Parameters */
   99.76 +
   99.77 +	/* 0xx: driver and authenticator flags */
   99.78 +#define ENABLE_DRIVER (long) 1
   99.79 +#define DISABLE_DRIVER (long) 2
   99.80 +#define ENABLE_AUTHENTICATOR (long) 3
   99.81 +#define DISABLE_AUTHENTICATOR (long) 4
   99.82 +#define ENABLE_DEBUG (long) 5
   99.83 +#define DISABLE_DEBUG (long) 6
   99.84 +#define HIDE_AUTHENTICATOR (long) 7
   99.85 +#define UNHIDE_AUTHENTICATOR (long) 8
   99.86 +	/* 1xx: c-client globals */
   99.87 +#define GET_DRIVERS (long) 101
   99.88 +#define SET_DRIVERS (long) 102
   99.89 +#define GET_GETS (long) 103
   99.90 +#define SET_GETS (long) 104
   99.91 +#define GET_CACHE (long) 105
   99.92 +#define SET_CACHE (long) 106
   99.93 +#define GET_SMTPVERBOSE (long) 107
   99.94 +#define SET_SMTPVERBOSE (long) 108
   99.95 +#define GET_RFC822OUTPUT (long) 109
   99.96 +#define SET_RFC822OUTPUT (long) 110
   99.97 +#define GET_READPROGRESS (long) 111
   99.98 +#define SET_READPROGRESS (long) 112
   99.99 +#define GET_THREADERS (long) 113
  99.100 +#define SET_THREADERS (long) 114
  99.101 +#define GET_NAMESPACE (long) 115
  99.102 +#define SET_NAMESPACE (long) 116
  99.103 +#define GET_MAILPROXYCOPY (long) 117
  99.104 +#define SET_MAILPROXYCOPY (long) 118
  99.105 +#define GET_SERVICENAME (long) 119
  99.106 +#define SET_SERVICENAME (long) 120
  99.107 +#define GET_DRIVER (long) 121
  99.108 +#define SET_DRIVER (long) 122
  99.109 +#define GET_EXPUNGEATPING (long) 123
  99.110 +#define SET_EXPUNGEATPING (long) 124
  99.111 +#define GET_PARSEPHRASE (long) 125
  99.112 +#define SET_PARSEPHRASE (long) 126
  99.113 +#define GET_SSLDRIVER (long) 127
  99.114 +#define SET_SSLDRIVER (long) 128
  99.115 +#define GET_TRYSSLFIRST (long) 129
  99.116 +#define SET_TRYSSLFIRST (long) 130
  99.117 +#define GET_BLOCKNOTIFY (long) 131
  99.118 +#define SET_BLOCKNOTIFY (long) 132
  99.119 +#define GET_SORTRESULTS (long) 133
  99.120 +#define SET_SORTRESULTS (long) 134
  99.121 +#define GET_THREADRESULTS (long) 135
  99.122 +#define SET_THREADRESULTS (long) 136
  99.123 +#define GET_PARSELINE (long) 137
  99.124 +#define SET_PARSELINE (long) 138
  99.125 +#define GET_NEWSRCQUERY (long) 139
  99.126 +#define SET_NEWSRCQUERY (long) 140
  99.127 +#define GET_FREEENVELOPESPAREP (long) 141
  99.128 +#define SET_FREEENVELOPESPAREP (long) 142
  99.129 +#define GET_FREEELTSPAREP (long) 143
  99.130 +#define SET_FREEELTSPAREP (long) 144
  99.131 +#define GET_SSLSTART (long) 145
  99.132 +#define SET_SSLSTART (long) 146
  99.133 +#define GET_DEBUGSENSITIVE (long) 147
  99.134 +#define SET_DEBUGSENSITIVE (long) 148
  99.135 +#define GET_TCPDEBUG (long) 149
  99.136 +#define SET_TCPDEBUG (long) 150
  99.137 +#define GET_FREESTREAMSPAREP (long) 151
  99.138 +#define SET_FREESTREAMSPAREP (long) 152
  99.139 +#define GET_FREEBODYSPAREP (long) 153
  99.140 +#define SET_FREEBODYSPAREP (long) 154
  99.141 +#define GET_COPYUID (long) 155
  99.142 +#define SET_COPYUID (long) 156
  99.143 +#define GET_APPENDUID (long) 157
  99.144 +#define SET_APPENDUID (long) 158
  99.145 +#define GET_RFC822OUTPUTFULL (long) 159
  99.146 +#define SET_RFC822OUTPUTFULL (long) 160
  99.147 +#define GET_BLOCKENVINIT (long) 161
  99.148 +#define SET_BLOCKENVINIT (long) 162
  99.149 +
  99.150 +	/* 2xx: environment */
  99.151 +#define GET_USERNAME (long) 201
  99.152 +#define SET_USERNAME (long) 202
  99.153 +#define GET_HOMEDIR (long) 203
  99.154 +#define SET_HOMEDIR (long) 204
  99.155 +#define GET_LOCALHOST (long) 205
  99.156 +#define SET_LOCALHOST (long) 206
  99.157 +#define GET_SYSINBOX (long) 207
  99.158 +#define SET_SYSINBOX (long) 208
  99.159 +#define GET_USERPROMPT (long) 209
  99.160 +#define SET_USERPROMPT (long) 210
  99.161 +#define GET_DISABLEPLAINTEXT (long) 211
  99.162 +#define SET_DISABLEPLAINTEXT (long) 212
  99.163 +#define GET_CHROOTSERVER (long) 213
  99.164 +#define SET_CHROOTSERVER (long) 214
  99.165 +#define GET_ADVERTISETHEWORLD (long) 215
  99.166 +#define SET_ADVERTISETHEWORLD (long) 216
  99.167 +#define GET_DISABLEAUTOSHAREDNS (long) 217
  99.168 +#define SET_DISABLEAUTOSHAREDNS (long) 218
  99.169 +#define GET_MAILSUBDIR 219
  99.170 +#define SET_MAILSUBDIR 220
  99.171 +#define GET_DISABLE822TZTEXT 221
  99.172 +#define SET_DISABLE822TZTEXT 222
  99.173 +#define GET_LIMITEDADVERTISE (long) 223
  99.174 +#define SET_LIMITEDADVERTISE (long) 224
  99.175 +#define GET_LOGOUTHOOK (long) 225
  99.176 +#define SET_LOGOUTHOOK (long) 226
  99.177 +#define GET_LOGOUTDATA (long) 227
  99.178 +#define SET_LOGOUTDATA (long) 228
  99.179 +#define GET_EXTERNALAUTHID (long) 229
  99.180 +#define SET_EXTERNALAUTHID (long) 230
  99.181 +#define GET_SSLCAPATH (long) 231
  99.182 +#define SET_SSLCAPATH (long) 232
  99.183 +
  99.184 +	/* 3xx: TCP/IP */
  99.185 +#define GET_OPENTIMEOUT (long) 300
  99.186 +#define SET_OPENTIMEOUT (long) 301
  99.187 +#define GET_READTIMEOUT (long) 302
  99.188 +#define SET_READTIMEOUT (long) 303
  99.189 +#define GET_WRITETIMEOUT (long) 304
  99.190 +#define SET_WRITETIMEOUT (long) 305
  99.191 +#define GET_CLOSETIMEOUT (long) 306
  99.192 +#define SET_CLOSETIMEOUT (long) 307
  99.193 +#define GET_TIMEOUT (long) 308
  99.194 +#define SET_TIMEOUT (long) 309
  99.195 +#define GET_RSHTIMEOUT (long) 310
  99.196 +#define SET_RSHTIMEOUT (long) 311
  99.197 +#define GET_ALLOWREVERSEDNS (long) 312
  99.198 +#define SET_ALLOWREVERSEDNS (long) 313
  99.199 +#define GET_RSHCOMMAND (long) 314
  99.200 +#define SET_RSHCOMMAND (long) 315
  99.201 +#define GET_RSHPATH (long) 316
  99.202 +#define SET_RSHPATH (long) 317
  99.203 +#define GET_SSHTIMEOUT (long) 318
  99.204 +#define SET_SSHTIMEOUT (long) 319
  99.205 +#define GET_SSHCOMMAND (long) 320
  99.206 +#define SET_SSHCOMMAND (long) 321
  99.207 +#define GET_SSHPATH (long) 322
  99.208 +#define SET_SSHPATH (long) 323
  99.209 +#define GET_SSLCERTIFICATEQUERY (long) 324
  99.210 +#define SET_SSLCERTIFICATEQUERY (long) 325
  99.211 +#define GET_SSLFAILURE (long) 326
  99.212 +#define SET_SSLFAILURE (long) 327
  99.213 +#define GET_NEWSRCCANONHOST (long) 328
  99.214 +#define SET_NEWSRCCANONHOST (long) 329
  99.215 +#define GET_KINIT (long) 330
  99.216 +#define SET_KINIT (long) 331
  99.217 +#define GET_SSLCLIENTCERT (long) 332
  99.218 +#define SET_SSLCLIENTCERT (long) 333
  99.219 +#define GET_SSLCLIENTKEY (long) 334
  99.220 +#define SET_SSLCLIENTKEY (long) 335
  99.221 +#define GET_KERBEROS_CP_SVR_NAME (long) 336
  99.222 +#define SET_KERBEROS_CP_SVR_NAME (long) 337
  99.223 +
  99.224 +	/* 4xx: network drivers */
  99.225 +#define GET_MAXLOGINTRIALS (long) 400
  99.226 +#define SET_MAXLOGINTRIALS (long) 401
  99.227 +#define GET_LOOKAHEAD (long) 402
  99.228 +#define SET_LOOKAHEAD (long) 403
  99.229 +#define GET_IMAPPORT (long) 404
  99.230 +#define SET_IMAPPORT (long) 405
  99.231 +#define GET_PREFETCH (long) 406
  99.232 +#define SET_PREFETCH (long) 407
  99.233 +#define GET_CLOSEONERROR (long) 408
  99.234 +#define SET_CLOSEONERROR (long) 409
  99.235 +#define GET_POP3PORT (long) 410
  99.236 +#define SET_POP3PORT (long) 411
  99.237 +#define GET_UIDLOOKAHEAD (long) 412
  99.238 +#define SET_UIDLOOKAHEAD (long) 413
  99.239 +#define GET_NNTPPORT (long) 414
  99.240 +#define SET_NNTPPORT (long) 415
  99.241 +#define GET_IMAPENVELOPE (long) 416
  99.242 +#define SET_IMAPENVELOPE (long) 417
  99.243 +#define GET_IMAPREFERRAL (long) 418
  99.244 +#define SET_IMAPREFERRAL (long) 419
  99.245 +#define GET_SSLIMAPPORT (long) 420
  99.246 +#define SET_SSLIMAPPORT (long) 421
  99.247 +#define GET_SSLPOPPORT (long) 422
  99.248 +#define SET_SSLPOPPORT (long) 423
  99.249 +#define GET_SSLNNTPPORT (long) 424
  99.250 +#define SET_SSLNNTPPORT (long) 425
  99.251 +#define GET_SSLSMTPPORT (long) 426
  99.252 +#define SET_SSLSMTPPORT (long) 427
  99.253 +#define GET_SMTPPORT (long) 428
  99.254 +#define SET_SMTPPORT (long) 429
  99.255 +#define GET_IMAPEXTRAHEADERS (long) 430
  99.256 +#define SET_IMAPEXTRAHEADERS (long) 431
  99.257 +#define GET_ACL (long) 432
  99.258 +#define SET_ACL (long) 433
  99.259 +#define GET_LISTRIGHTS (long) 434
  99.260 +#define SET_LISTRIGHTS (long) 435
  99.261 +#define GET_MYRIGHTS (long) 436
  99.262 +#define SET_MYRIGHTS (long) 437
  99.263 +#define GET_QUOTA (long) 438
  99.264 +#define SET_QUOTA (long) 439
  99.265 +#define GET_QUOTAROOT (long) 440
  99.266 +#define SET_QUOTAROOT (long) 441
  99.267 +#define GET_IMAPTRYSSL (long) 442
  99.268 +#define SET_IMAPTRYSSL (long) 443
  99.269 +#define GET_FETCHLOOKAHEAD (long) 444
  99.270 +#define SET_FETCHLOOKAHEAD (long) 445
  99.271 +#define GET_NNTPRANGE (long) 446
  99.272 +#define SET_NNTPRANGE (long) 447
  99.273 +#define GET_NNTPHIDEPATH (long) 448
  99.274 +#define SET_NNTPHIDEPATH (long) 449
  99.275 +#define GET_SENDCOMMAND (long) 450
  99.276 +#define SET_SENDCOMMAND (long) 451
  99.277 +#define GET_IDLETIMEOUT (long) 452
  99.278 +#define SET_IDLETIMEOUT (long) 453
  99.279 +#define GET_FETCHLOOKAHEADLIMIT (long) 454
  99.280 +#define SET_FETCHLOOKAHEADLIMIT (long) 455
  99.281 +
  99.282 +	/* 5xx: local file drivers */
  99.283 +#define GET_MBXPROTECTION (long) 500
  99.284 +#define SET_MBXPROTECTION (long) 501
  99.285 +#define GET_DIRPROTECTION (long) 502
  99.286 +#define SET_DIRPROTECTION (long) 503
  99.287 +#define GET_LOCKPROTECTION (long) 504
  99.288 +#define SET_LOCKPROTECTION (long) 505
  99.289 +#define GET_FROMWIDGET (long) 506
  99.290 +#define SET_FROMWIDGET (long) 507
  99.291 +#define GET_NEWSACTIVE (long) 508
  99.292 +#define SET_NEWSACTIVE (long) 509
  99.293 +#define GET_NEWSSPOOL (long) 510
  99.294 +#define SET_NEWSSPOOL (long) 511
  99.295 +#define GET_NEWSRC (long) 512
  99.296 +#define SET_NEWSRC (long) 513
  99.297 +#define GET_EXTENSION (long) 514
  99.298 +#define SET_EXTENSION (long) 515
  99.299 +#define GET_DISABLEFCNTLLOCK (long) 516
  99.300 +#define SET_DISABLEFCNTLLOCK (long) 517
  99.301 +#define GET_LOCKEACCESERROR (long) 518
  99.302 +#define SET_LOCKEACCESERROR (long) 519
  99.303 +#define GET_LISTMAXLEVEL (long) 520
  99.304 +#define SET_LISTMAXLEVEL (long) 521
  99.305 +#define GET_ANONYMOUSHOME (long) 522
  99.306 +#define SET_ANONYMOUSHOME (long) 523
  99.307 +#define GET_FTPHOME (long) 524
  99.308 +#define SET_FTPHOME (long) 525
  99.309 +#define GET_PUBLICHOME (long) 526
  99.310 +#define SET_PUBLICHOME (long) 527
  99.311 +#define GET_SHAREDHOME (long) 528
  99.312 +#define SET_SHAREDHOME (long) 529
  99.313 +#define GET_MHPROFILE (long) 530
  99.314 +#define SET_MHPROFILE (long) 531
  99.315 +#define GET_MHPATH (long) 532
  99.316 +#define SET_MHPATH (long) 533
  99.317 +#define GET_ONETIMEEXPUNGEATPING (long) 534
  99.318 +#define SET_ONETIMEEXPUNGEATPING (long) 535
  99.319 +#define GET_USERHASNOLIFE (long) 536
  99.320 +#define SET_USERHASNOLIFE (long) 537
  99.321 +#define GET_FTPPROTECTION (long) 538
  99.322 +#define SET_FTPPROTECTION (long) 539
  99.323 +#define GET_PUBLICPROTECTION (long) 540
  99.324 +#define SET_PUBLICPROTECTION (long) 541
  99.325 +#define GET_SHAREDPROTECTION (long) 542
  99.326 +#define SET_SHAREDPROTECTION (long) 543
  99.327 +#define GET_LOCKTIMEOUT (long) 544
  99.328 +#define SET_LOCKTIMEOUT (long) 545
  99.329 +#define GET_NOTIMEZONES (long) 546
  99.330 +#define SET_NOTIMEZONES (long) 547
  99.331 +#define GET_HIDEDOTFILES (long) 548
  99.332 +#define SET_HIDEDOTFILES (long) 549
  99.333 +#define GET_FTPDIRPROTECTION (long) 550
  99.334 +#define SET_FTPDIRPROTECTION (long) 551
  99.335 +#define GET_PUBLICDIRPROTECTION (long) 552
  99.336 +#define SET_PUBLICDIRPROTECTION (long) 553
  99.337 +#define GET_SHAREDDIRPROTECTION (long) 554
  99.338 +#define SET_SHAREDDIRPROTECTION (long) 555
  99.339 +#define GET_TRUSTDNS (long) 556
  99.340 +#define SET_TRUSTDNS (long) 557
  99.341 +#define GET_SASLUSESPTRNAME (long) 558
  99.342 +#define SET_SASLUSESPTRNAME (long) 559
  99.343 +#define GET_NETFSSTATBUG (long) 560
  99.344 +#define SET_NETFSSTATBUG (long) 561
  99.345 +#define GET_SNARFMAILBOXNAME (long) 562
  99.346 +#define SET_SNARFMAILBOXNAME (long) 563
  99.347 +#define GET_SNARFINTERVAL (long) 564
  99.348 +#define SET_SNARFINTERVAL (long) 565
  99.349 +#define GET_SNARFPRESERVE (long) 566
  99.350 +#define SET_SNARFPRESERVE (long) 567
  99.351 +#define GET_INBOXPATH (long) 568
  99.352 +#define SET_INBOXPATH (long) 569
  99.353 +#define GET_DIRFMTTEST (long) 570
  99.354 +#define SET_DIRFMTTEST (long) 571
  99.355 +#define GET_SCANCONTENTS (long) 572
  99.356 +#define SET_SCANCONTENTS (long) 573
  99.357 +#define GET_MHALLOWINBOX (long) 574
  99.358 +#define SET_MHALLOWINBOX (long) 575
  99.359 +
  99.360 +/* Driver flags */
  99.361 +
  99.362 +#define DR_DISABLE (long) 0x1	/* driver is disabled */
  99.363 +#define DR_LOCAL (long) 0x2	/* local file driver */
  99.364 +#define DR_MAIL (long) 0x4	/* supports mail */
  99.365 +#define DR_NEWS (long) 0x8	/* supports news */
  99.366 +#define DR_READONLY (long) 0x10	/* driver only allows readonly access */
  99.367 +#define DR_NOFAST (long) 0x20	/* "fast" data is slow (whole msg fetch) */
  99.368 +#define DR_NAMESPACE (long) 0x40/* driver has a special namespace */
  99.369 +#define DR_LOWMEM (long) 0x80	/* low amounts of memory available */
  99.370 +#define DR_LOCKING (long) 0x100	/* driver does locking */
  99.371 +#define DR_CRLF (long) 0x200	/* driver internal form uses CRLF newlines */
  99.372 +#define DR_NOSTICKY (long) 0x400/* driver does not support sticky UIDs */
  99.373 +#define DR_RECYCLE (long) 0x800	/* driver does stream recycling */
  99.374 +#define DR_XPOINT (long) 0x1000	/* needs to be checkpointed */
  99.375 +				/* driver has no real internal date */
  99.376 +#define DR_NOINTDATE (long) 0x2000
  99.377 +				/* driver does not announce new mail */
  99.378 +#define DR_NONEWMAIL (long) 0x4000
  99.379 +				/* driver does not announce new mail when RO */
  99.380 +#define DR_NONEWMAILRONLY (long) 0x8000
  99.381 +				/* driver can be halfopen */
  99.382 +#define DR_HALFOPEN (long) 0x10000
  99.383 +#define DR_DIRFMT (long) 0x20000/* driver is a directory-format */
  99.384 +#define DR_MODSEQ (long) 0x40000/* driver supports modseqs */
  99.385 +
  99.386 +
  99.387 +/* Cache management function codes */
  99.388 +
  99.389 +#define CH_INIT (long) 10	/* initialize cache */
  99.390 +#define CH_SIZE (long) 11	/* (re-)size the cache */
  99.391 +#define CH_MAKEELT (long) 30	/* return elt, make if needed */
  99.392 +#define CH_ELT (long) 31	/* return elt if exists */
  99.393 +#define CH_SORTCACHE (long) 35	/* return sortcache entry, make if needed */
  99.394 +#define CH_FREE (long) 40	/* free space used by elt */
  99.395 +				/* free space used by sortcache */
  99.396 +#define CH_FREESORTCACHE (long) 43
  99.397 +#define CH_EXPUNGE (long) 45	/* delete elt pointer from list */
  99.398 +
  99.399 +
  99.400 +/* Mailbox open options
  99.401 + * For compatibility with the past, OP_DEBUG must always be 1.
  99.402 + */
  99.403 +
  99.404 +#define OP_DEBUG (long) 0x1	/* debug protocol negotiations */
  99.405 +#define OP_READONLY (long) 0x2	/* read-only open */
  99.406 +#define OP_ANONYMOUS (long) 0x4	/* anonymous open of newsgroup */
  99.407 +#define OP_SHORTCACHE (long) 0x8/* short (elt-only) caching */
  99.408 +#define OP_SILENT (long) 0x10	/* don't pass up events (internal use) */
  99.409 +#define OP_PROTOTYPE (long) 0x20/* return driver prototype */
  99.410 +#define OP_HALFOPEN (long) 0x40	/* half-open (IMAP connect but no select) */
  99.411 +#define OP_EXPUNGE (long) 0x80	/* silently expunge recycle stream */
  99.412 +#define OP_SECURE (long) 0x100	/* don't do non-secure authentication */
  99.413 +#define OP_TRYSSL (long) 0x200	/* try SSL first */
  99.414 +				/* use multiple newsrc files */
  99.415 +#define OP_MULNEWSRC (long) 0x400
  99.416 +#define OP_NOKOD (long) 0x800	/* suppress kiss-of-death */
  99.417 +#define OP_SNIFF (long) 0x1000	/* metadata only open */
  99.418 +				/* reserved for application use */
  99.419 +#define OP_RESERVED (unsigned long) 0xff000000
  99.420 +
  99.421 +
  99.422 +/* Net open options */
  99.423 +
  99.424 +				/* no error messages */
  99.425 +#define NET_SILENT ((unsigned long) 0x80000000)
  99.426 +				/* no validation of SSL certificates */
  99.427 +#define NET_NOVALIDATECERT ((unsigned long) 0x40000000)
  99.428 +				/* no open timeout */
  99.429 +#define NET_NOOPENTIMEOUT ((unsigned long) 0x20000000)
  99.430 +				/* TLS not SSL */
  99.431 +#define NET_TLSCLIENT ((unsigned long) 0x10000000)
  99.432 +				/* try SSL mode */
  99.433 +#define NET_TRYSSL ((unsigned long) 0x8000000)
  99.434 +
  99.435 +/* Close options */
  99.436 +
  99.437 +#define CL_EXPUNGE (long) 1	/* expunge silently */
  99.438 +
  99.439 +
  99.440 +/* Fetch options */
  99.441 +
  99.442 +#define FT_UID (long) 0x1	/* argument is a UID */
  99.443 +#define FT_PEEK (long) 0x2	/* peek at data */
  99.444 +#define FT_NOT (long) 0x4	/* NOT flag for header lines fetch */
  99.445 +#define FT_INTERNAL (long) 0x8	/* text can be internal strings */
  99.446 +				/* IMAP prefetch text when fetching header */
  99.447 +#define FT_PREFETCHTEXT (long) 0x20
  99.448 +#define FT_NOHDRS (long) 0x40	/* suppress fetching extra headers (note that
  99.449 +				   this breaks news handling) */
  99.450 +#define FT_NEEDENV (long) 0x80	/* (internal use) include envelope */
  99.451 +#define FT_NEEDBODY (long) 0x100/* (internal use) include body structure */
  99.452 +				/* no fetch lookahead */
  99.453 +#define FT_NOLOOKAHEAD (long) 0x200
  99.454 +				/* (internal use) lookahead in hdr searching */
  99.455 +#define FT_SEARCHLOOKAHEAD (long) 0x400
  99.456 +				/* stringstruct return hack */
  99.457 +#define FT_RETURNSTRINGSTRUCT (long) 0x800
  99.458 +
  99.459 +
  99.460 +/* Flagging options */
  99.461 +
  99.462 +#define ST_UID (long) 0x1	/* argument is a UID sequence */
  99.463 +#define ST_SILENT (long) 0x2	/* don't return results */
  99.464 +#define ST_SET (long) 0x4	/* set vs. clear */
  99.465 +
  99.466 +
  99.467 +/* Expunge options */
  99.468 +
  99.469 +#define EX_UID (long) 0x1	/* argument is a UID sequence */
  99.470 +
  99.471 +
  99.472 +/* Copy options */
  99.473 +
  99.474 +#define CP_UID (long) 0x1	/* argument is a UID sequence */
  99.475 +#define CP_MOVE (long) 0x2	/* delete from source after copying */
  99.476 +				/* set debug in any created stream */
  99.477 +#define CP_DEBUG (long) 0x20000000
  99.478 +
  99.479 +/* Search/sort/thread options */
  99.480 +
  99.481 +#define SE_UID (long) 0x1	/* return UID */
  99.482 +#define SE_FREE (long) 0x2	/* free search program after finished */
  99.483 +#define SE_NOPREFETCH (long) 0x4/* no search prefetching */
  99.484 +#define SO_FREE (long) 0x8	/* free sort program after finished */
  99.485 +#define SE_NOSERVER (long) 0x10	/* don't do server-based search/sort/thread */
  99.486 +#define SE_RETAIN (long) 0x20	/* retain previous search results */
  99.487 +#define SO_OVERVIEW (long) 0x40	/* use overviews in searching (NNTP only) */
  99.488 +#define SE_NEEDBODY (long) 0x80	/* include body structure in prefetch */
  99.489 +#define SE_NOHDRS (long) 0x100	/* suppress prefetching extra headers (note
  99.490 +				   that this breaks news handling) */
  99.491 +#define SE_NOLOCAL (long) 0x200	/* no local retry (IMAP only) */
  99.492 +
  99.493 +#define SO_NOSERVER SE_NOSERVER	/* compatibility name */
  99.494 +#define SE_SILLYOK (long) 0x400	/* allow silly searches */
  99.495 +
  99.496 +
  99.497 +/* Status options */
  99.498 +
  99.499 +#define SA_MESSAGES (long) 0x1	/* number of messages */
  99.500 +#define SA_RECENT (long) 0x2	/* number of recent messages */
  99.501 +#define SA_UNSEEN (long) 0x4	/* number of unseen messages */
  99.502 +#define SA_UIDNEXT (long) 0x8	/* next UID to be assigned */
  99.503 +				/* UID validity value */
  99.504 +#define SA_UIDVALIDITY (long) 0x10
  99.505 +				/* set OP_DEBUG on any created stream */
  99.506 +#define SA_DEBUG (long) 0x10000000
  99.507 +				/* use multiple newsrcs */
  99.508 +#define SA_MULNEWSRC (long) 0x20000000
  99.509 +
  99.510 +/* Mailgets flags */
  99.511 +
  99.512 +#define MG_UID (long) 0x1	/* message number is a UID */
  99.513 +#define MG_COPY (long) 0x2	/* must return copy of argument */
  99.514 +
  99.515 +/* SASL authenticator categories */
  99.516 +
  99.517 +#define AU_SECURE (long) 0x1	/* /secure allowed */
  99.518 +#define AU_AUTHUSER (long) 0x2	/* /authuser=xxx allowed */
  99.519 +				/* authenticator hidden */
  99.520 +#define AU_HIDE (long) 0x10000000
  99.521 +				/* authenticator disabled */
  99.522 +#define AU_DISABLE (long) 0x20000000
  99.523 +
  99.524 +
  99.525 +/* Garbage collection flags */
  99.526 +
  99.527 +#define GC_ELT (long) 0x1	/* message cache elements */
  99.528 +#define GC_ENV (long) 0x2	/* envelopes and bodies */
  99.529 +#define GC_TEXTS (long) 0x4	/* cached texts */
  99.530 +
  99.531 +
  99.532 +/* mm_log()/mm_notify() condition codes */
  99.533 +
  99.534 +#define WARN (long) 1		/* mm_log warning type */
  99.535 +#define ERROR (long) 2		/* mm_log error type */
  99.536 +#define PARSE (long) 3		/* mm_log parse error type */
  99.537 +#define BYE (long) 4		/* mm_notify stream dying */
  99.538 +#define TCPDEBUG (long) 5	/* mm_log TCP debug babble */
  99.539 +
  99.540 +
  99.541 +/* Bits from mail_parse_flags().  Don't change these, since the header format
  99.542 + * used by tenex, mtx, and mbx corresponds to these bits.
  99.543 + */
  99.544 +
  99.545 +#define fSEEN 0x1
  99.546 +#define fDELETED 0x2
  99.547 +#define fFLAGGED 0x4
  99.548 +#define fANSWERED 0x8
  99.549 +#define fOLD 0x10
  99.550 +#define fDRAFT 0x20
  99.551 +
  99.552 +#define fEXPUNGED 0x8000	/* internal flag */
  99.553 +
  99.554 +/* Bits for mm_list() and mm_lsub() */
  99.555 +
  99.556 +/* Note that (LATT_NOINFERIORS LATT_HASCHILDREN LATT_HASNOCHILDREN) and
  99.557 + * (LATT_NOSELECT LATT_MARKED LATT_UNMARKED) each have eight possible states,
  99.558 + * but only four of these are valid.  The other four are silly states which
  99.559 + * while invalid can unfortunately be expressed in the IMAP protocol.
  99.560 + */
  99.561 +
  99.562 +				/* terminal node in hierarchy */
  99.563 +#define LATT_NOINFERIORS (long) 0x1
  99.564 +				/* name can not be selected */
  99.565 +#define LATT_NOSELECT (long) 0x2
  99.566 +				/* changed since last accessed */
  99.567 +#define LATT_MARKED (long) 0x4
  99.568 +				/* accessed since last changed */
  99.569 +#define LATT_UNMARKED (long) 0x8
  99.570 +				/* name has referral to remote mailbox */
  99.571 +#define LATT_REFERRAL (long) 0x10
  99.572 +				/* has selectable inferiors */
  99.573 +#define LATT_HASCHILDREN (long) 0x20
  99.574 +				/* has no selectable inferiors */
  99.575 +#define LATT_HASNOCHILDREN (long) 0x40
  99.576 +
  99.577 +
  99.578 +/* Sort functions */
  99.579 +
  99.580 +#define SORTDATE 0		/* date */
  99.581 +#define SORTARRIVAL 1		/* arrival date */
  99.582 +#define SORTFROM 2		/* from */
  99.583 +#define SORTSUBJECT 3		/* subject */
  99.584 +#define SORTTO 4		/* to */
  99.585 +#define SORTCC 5		/* cc */
  99.586 +#define SORTSIZE 6		/* size */
  99.587 +
  99.588 +
  99.589 +/* imapreferral_t codes */
  99.590 +
  99.591 +#define REFAUTHFAILED (long) 0	/* authentication referral -- not logged in */
  99.592 +#define REFAUTH (long) 1	/* authentication referral -- logged in */
  99.593 +#define REFSELECT (long) 2	/* select referral */
  99.594 +#define REFCREATE (long) 3
  99.595 +#define REFDELETE (long) 4
  99.596 +#define REFRENAME (long) 5
  99.597 +#define REFSUBSCRIBE (long) 6
  99.598 +#define REFUNSUBSCRIBE (long) 7
  99.599 +#define REFSTATUS (long) 8
  99.600 +#define REFCOPY (long) 9
  99.601 +#define REFAPPEND (long) 10
  99.602 +
  99.603 +
  99.604 +/* sendcommand_t codes */
  99.605 +
  99.606 +				/* expunge response deferred */
  99.607 +#define SC_EXPUNGEDEFERRED (long) 1
  99.608 +
  99.609 +/* Block notification codes */
  99.610 +
  99.611 +#define BLOCK_NONE 0		/* not blocked */
  99.612 +#define BLOCK_SENSITIVE 1	/* sensitive code, disallow alarms */
  99.613 +#define BLOCK_NONSENSITIVE 2	/* non-sensitive code, allow alarms */
  99.614 +#define BLOCK_DNSLOOKUP 10	/* blocked on DNS lookup */
  99.615 +#define BLOCK_TCPOPEN 11	/* blocked on TCP open */
  99.616 +#define BLOCK_TCPREAD 12	/* blocked on TCP read */
  99.617 +#define BLOCK_TCPWRITE 13	/* blocked on TCP write */
  99.618 +#define BLOCK_TCPCLOSE 14	/* blocked on TCP close */
  99.619 +#define BLOCK_FILELOCK 20	/* blocked on file locking */
  99.620 +
  99.621 +
  99.622 +/* In-memory sized-text */
  99.623 +
  99.624 +#define SIZEDTEXT struct mail_sizedtext
  99.625 +
  99.626 +SIZEDTEXT {
  99.627 +  unsigned char *data;		/* text */
  99.628 +  unsigned long size;		/* size of text in octets */
  99.629 +};
  99.630 +
  99.631 +
  99.632 +/* String list */
  99.633 +
  99.634 +#define STRINGLIST struct string_list
  99.635 +
  99.636 +STRINGLIST {
  99.637 +  SIZEDTEXT text;		/* string text */
  99.638 +  STRINGLIST *next;
  99.639 +};
  99.640 +
  99.641 +
  99.642 +/* Parse results from mail_valid_net_parse */
  99.643 +
  99.644 +#define NETMAXHOST 256
  99.645 +#define NETMAXUSER 65
  99.646 +#define NETMAXMBX (MAILTMPLEN/4)
  99.647 +#define NETMAXSRV 21
  99.648 +typedef struct net_mailbox {
  99.649 +  char host[NETMAXHOST];	/* host name (may be canonicalized) */
  99.650 +  char orighost[NETMAXHOST];	/* host name before canonicalization */
  99.651 +  char user[NETMAXUSER];	/* user name */
  99.652 +  char authuser[NETMAXUSER];	/* authentication user name */
  99.653 +  char mailbox[NETMAXMBX];	/* mailbox name */
  99.654 +  char service[NETMAXSRV];	/* service name */
  99.655 +  unsigned long port;		/* TCP port number */
  99.656 +  unsigned int anoflag : 1;	/* anonymous */
  99.657 +  unsigned int dbgflag : 1;	/* debug flag */
  99.658 +  unsigned int secflag : 1;	/* secure flag */
  99.659 +  unsigned int sslflag : 1;	/* SSL driver flag */
  99.660 +  unsigned int trysslflag : 1;	/* try SSL driver first flag */
  99.661 +  unsigned int novalidate : 1;	/* don't validate certificates */
  99.662 +  unsigned int tlsflag : 1;	/* TLS flag */
  99.663 +  unsigned int notlsflag : 1;	/* do not do TLS flag */
  99.664 +  unsigned int readonlyflag : 1;/* want readonly */
  99.665 +  unsigned int norsh : 1;	/* don't use rsh/ssh */
  99.666 +  unsigned int loser : 1;	/* server is a loser */
  99.667 +  unsigned int tlssslv23 : 1;	/* force SSLv23 client method over TLS */
  99.668 +} NETMBX;
  99.669 +
  99.670 +/* Item in an address list */
  99.671 +
  99.672 +#define ADDRESS struct mail_address
  99.673 +
  99.674 +ADDRESS {
  99.675 +  char *personal;		/* personal name phrase */
  99.676 +  char *adl;			/* at-domain-list source route */
  99.677 +  char *mailbox;		/* mailbox name */
  99.678 +  char *host;			/* domain name of mailbox's host */
  99.679 +  char *error;			/* error in address from SMTP module */
  99.680 +  struct {
  99.681 +    char *type;			/* address type (default "rfc822") */
  99.682 +    char *addr;			/* address as xtext */
  99.683 +  } orcpt;
  99.684 +  ADDRESS *next;		/* pointer to next address in list */
  99.685 +};
  99.686 +
  99.687 +
  99.688 +/* Message envelope */
  99.689 +
  99.690 +typedef struct mail_envelope {
  99.691 +  unsigned int incomplete : 1;	/* envelope may be incomplete */
  99.692 +  unsigned int imapenvonly : 1;	/* envelope only has IMAP envelope */
  99.693 +  char *remail;			/* remail header if any */
  99.694 +  ADDRESS *return_path;		/* error return address */
  99.695 +  unsigned char *date;		/* message composition date string */
  99.696 +  ADDRESS *from;		/* originator address list */
  99.697 +  ADDRESS *sender;		/* sender address list */
  99.698 +  ADDRESS *reply_to;		/* reply address list */
  99.699 +  char *subject;		/* message subject string */
  99.700 +  ADDRESS *to;			/* primary recipient list */
  99.701 +  ADDRESS *cc;			/* secondary recipient list */
  99.702 +  ADDRESS *bcc;			/* blind secondary recipient list */
  99.703 +  char *in_reply_to;		/* replied message ID */
  99.704 +  char *message_id;		/* message ID */
  99.705 +  char *newsgroups;		/* USENET newsgroups */
  99.706 +  char *followup_to;		/* USENET reply newsgroups */
  99.707 +  char *references;		/* USENET references */
  99.708 +  void *sparep;			/* spare pointer reserved for main program */
  99.709 +} ENVELOPE;
  99.710 +
  99.711 +/* Primary body types */
  99.712 +/* If you change any of these you must also change body_types in rfc822.c */
  99.713 +
  99.714 +#define TYPETEXT 0		/* unformatted text */
  99.715 +#define TYPEMULTIPART 1		/* multiple part */
  99.716 +#define TYPEMESSAGE 2		/* encapsulated message */
  99.717 +#define TYPEAPPLICATION 3	/* application data */
  99.718 +#define TYPEAUDIO 4		/* audio */
  99.719 +#define TYPEIMAGE 5		/* static image */
  99.720 +#define TYPEVIDEO 6		/* video */
  99.721 +#define TYPEMODEL 7		/* model */
  99.722 +#define TYPEOTHER 8		/* unknown */
  99.723 +#define TYPEMAX 15		/* maximum type code */
  99.724 +
  99.725 +
  99.726 +/* Body encodings */
  99.727 +/* If you change any of these you must also change body_encodings in rfc822.c
  99.728 + */
  99.729 +
  99.730 +#define ENC7BIT 0		/* 7 bit SMTP semantic data */
  99.731 +#define ENC8BIT 1		/* 8 bit SMTP semantic data */
  99.732 +#define ENCBINARY 2		/* 8 bit binary data */
  99.733 +#define ENCBASE64 3		/* base-64 encoded data */
  99.734 +#define ENCQUOTEDPRINTABLE 4	/* human-readable 8-as-7 bit data */
  99.735 +#define ENCOTHER 5		/* unknown */
  99.736 +#define ENCMAX 10		/* maximum encoding code */
  99.737 +
  99.738 +
  99.739 +/* Body contents */
  99.740 +
  99.741 +#define BODY struct mail_bodystruct
  99.742 +#define MESSAGE struct mail_body_message
  99.743 +#define PARAMETER struct mail_body_parameter
  99.744 +#define PART struct mail_body_part
  99.745 +#define PARTTEXT struct mail_body_text
  99.746 +
  99.747 +/* Message body text */
  99.748 +
  99.749 +PARTTEXT {
  99.750 +  unsigned long offset;		/* offset from body origin */
  99.751 +  SIZEDTEXT text;		/* text */
  99.752 +};
  99.753 +
  99.754 +
  99.755 +/* Message body structure */
  99.756 +
  99.757 +BODY {
  99.758 +  unsigned short type;		/* body primary type */
  99.759 +  unsigned short encoding;	/* body transfer encoding */
  99.760 +  char *subtype;		/* subtype string */
  99.761 +  PARAMETER *parameter;		/* parameter list */
  99.762 +  char *id;			/* body identifier */
  99.763 +  char *description;		/* body description */
  99.764 +  struct {			/* body disposition */
  99.765 +    char *type;			/* disposition type */
  99.766 +    PARAMETER *parameter;	/* disposition parameters */
  99.767 +  } disposition;
  99.768 +  STRINGLIST *language;		/* body language */
  99.769 +  char *location;		/* body content URI */
  99.770 +  PARTTEXT mime;		/* MIME header */
  99.771 +  PARTTEXT contents;		/* body part contents */
  99.772 +  union {			/* different ways of accessing contents */
  99.773 +    PART *part;			/* body part list */
  99.774 +    MESSAGE *msg;		/* body encapsulated message */
  99.775 +  } nested;
  99.776 +  struct {
  99.777 +    unsigned long lines;	/* size of text in lines */
  99.778 +    unsigned long bytes;	/* size of text in octets */
  99.779 +  } size;
  99.780 +  char *md5;			/* MD5 checksum */
  99.781 +  void *sparep;			/* spare pointer reserved for main program */
  99.782 +};
  99.783 +
  99.784 +
  99.785 +/* Parameter list */
  99.786 +
  99.787 +PARAMETER {
  99.788 +  char *attribute;		/* parameter attribute name */
  99.789 +  char *value;			/* parameter value */
  99.790 +  PARAMETER *next;		/* next parameter in list */
  99.791 +};
  99.792 +
  99.793 +
  99.794 +/* Multipart content list */
  99.795 +
  99.796 +PART {
  99.797 +  BODY body;			/* body information for this part */
  99.798 +  PART *next;			/* next body part */
  99.799 +};
  99.800 +
  99.801 +
  99.802 +/* RFC-822 Message */
  99.803 +
  99.804 +MESSAGE {
  99.805 +  ENVELOPE *env;		/* message envelope */
  99.806 +  BODY *body;			/* message body */
  99.807 +  PARTTEXT full;		/* full message */
  99.808 +  STRINGLIST *lines;		/* lines used to filter header */
  99.809 +  PARTTEXT header;		/* header text */
  99.810 +  PARTTEXT text;		/* body text */
  99.811 +};
  99.812 +
  99.813 +/* Entry in the message cache array */
  99.814 +
  99.815 +typedef struct message_cache {
  99.816 +  unsigned long msgno;		/* message number */
  99.817 +  unsigned int lockcount : 8;	/* non-zero if multiple references */
  99.818 +  unsigned long rfc822_size;	/* # of bytes of message as raw RFC822 */
  99.819 +  struct {			/* c-client internal use only */
  99.820 +    unsigned long uid;		/* message unique ID */
  99.821 +    unsigned long mod;		/* modseq */
  99.822 +    PARTTEXT special;		/* special text pointers */
  99.823 +    MESSAGE msg;		/* internal message pointers */
  99.824 +    union {			/* driver internal use */
  99.825 +      unsigned long data;
  99.826 +      void *ptr;
  99.827 +    } spare;
  99.828 +    unsigned int sequence : 1;	/* saved sequence bit */
  99.829 +    unsigned int dirty : 1;	/* driver internal use */
  99.830 +    unsigned int filter : 1;	/* driver internal use */
  99.831 +    unsigned int ghost : 1;	/* driver internal use */
  99.832 +  } private;
  99.833 +			/* internal date */
  99.834 +  unsigned int day : 5;		/* day of month (1-31) */
  99.835 +  unsigned int month : 4;	/* month of year (1-12) */
  99.836 +  unsigned int year : 7;	/* year since BASEYEAR (expires in 127 yrs) */
  99.837 +  unsigned int hours: 5;	/* hours (0-23) */
  99.838 +  unsigned int minutes: 6;	/* minutes (0-59) */
  99.839 +  unsigned int seconds: 6;	/* seconds (0-59) */
  99.840 +  unsigned int zoccident : 1;	/* non-zero if west of UTC */
  99.841 +  unsigned int zhours : 4;	/* hours from UTC (0-12) */
  99.842 +  unsigned int zminutes: 6;	/* minutes (0-59) */
  99.843 +			/* system flags */
  99.844 +  unsigned int seen : 1;	/* system Seen flag */
  99.845 +  unsigned int deleted : 1;	/* system Deleted flag */
  99.846 +  unsigned int flagged : 1; 	/* system Flagged flag */
  99.847 +  unsigned int answered : 1;	/* system Answered flag */
  99.848 +  unsigned int draft : 1;	/* system Draft flag */
  99.849 +  unsigned int recent : 1;	/* system Recent flag */
  99.850 +			/* message status */
  99.851 +  unsigned int valid : 1;	/* elt has valid flags */
  99.852 +  unsigned int searched : 1;	/* message was searched */
  99.853 +  unsigned int sequence : 1;	/* message is in sequence */
  99.854 +			/* reserved for use by main program */
  99.855 +  unsigned int spare : 1;	/* first spare bit */
  99.856 +  unsigned int spare2 : 1;	/* second spare bit */
  99.857 +  unsigned int spare3 : 1;	/* third spare bit */
  99.858 +  unsigned int spare4 : 1;	/* fourth spare bit */
  99.859 +  unsigned int spare5 : 1;	/* fifth spare bit */
  99.860 +  unsigned int spare6 : 1;	/* sixth spare bit */
  99.861 +  unsigned int spare7 : 1;	/* seventh spare bit */
  99.862 +  unsigned int spare8 : 1;	/* eighth spare bit */
  99.863 +  void *sparep;			/* spare pointer */
  99.864 +  unsigned long user_flags;	/* user-assignable flags */
  99.865 +} MESSAGECACHE;
  99.866 +
  99.867 +/* String structure */
  99.868 +
  99.869 +#define STRINGDRIVER struct string_driver
  99.870 +
  99.871 +typedef struct mailstring {
  99.872 +  void *data;			/* driver-dependent data */
  99.873 +  unsigned long data1;		/* driver-dependent data */
  99.874 +  unsigned long size;		/* total length of string */
  99.875 +  char *chunk;			/* base address of chunk */
  99.876 +  unsigned long chunksize;	/* size of chunk */
  99.877 +  unsigned long offset;		/* offset of this chunk in base */
  99.878 +  char *curpos;			/* current position in chunk */
  99.879 +  unsigned long cursize;	/* number of bytes remaining in chunk */
  99.880 +  STRINGDRIVER *dtb;		/* driver that handles this type of string */
  99.881 +} STRING;
  99.882 +
  99.883 +
  99.884 +/* Dispatch table for string driver */
  99.885 +
  99.886 +STRINGDRIVER {
  99.887 +				/* initialize string driver */
  99.888 +  void (*init) (STRING *s,void *data,unsigned long size);
  99.889 +				/* get next character in string */
  99.890 +  char (*next) (STRING *s);
  99.891 +				/* set position in string */
  99.892 +  void (*setpos) (STRING *s,unsigned long i);
  99.893 +};
  99.894 +
  99.895 +
  99.896 +/* Stringstruct access routines */
  99.897 +
  99.898 +#define INIT(s,d,data,size) ((*((s)->dtb = &d)->init) (s,data,size))
  99.899 +#define SIZE(s) ((s)->size - GETPOS (s))
  99.900 +#define CHR(s) (*(s)->curpos)
  99.901 +#define SNX(s) (--(s)->cursize ? *(s)->curpos++ : (*(s)->dtb->next) (s))
  99.902 +#define GETPOS(s) ((s)->offset + ((s)->curpos - (s)->chunk))
  99.903 +#define SETPOS(s,i) (*(s)->dtb->setpos) (s,i)
  99.904 +
  99.905 +/* Search program */
  99.906 +
  99.907 +#define SEARCHPGM struct search_program
  99.908 +#define SEARCHHEADER struct search_header
  99.909 +#define SEARCHSET struct search_set
  99.910 +#define SEARCHOR struct search_or
  99.911 +#define SEARCHPGMLIST struct search_pgm_list
  99.912 +
  99.913 +
  99.914 +SEARCHHEADER {			/* header search */
  99.915 +  SIZEDTEXT line;		/* header line */
  99.916 +  SIZEDTEXT text;		/* text in header */
  99.917 +  SEARCHHEADER *next;		/* next in list */
  99.918 +};
  99.919 +
  99.920 +
  99.921 +SEARCHSET {			/* message set */
  99.922 +  unsigned long first;		/* sequence number */
  99.923 +  unsigned long last;		/* last value, if a range */
  99.924 +  SEARCHSET *next;		/* next in list */
  99.925 +};
  99.926 +
  99.927 +
  99.928 +SEARCHOR {
  99.929 +  SEARCHPGM *first;		/* first program */
  99.930 +  SEARCHPGM *second;		/* second program */
  99.931 +  SEARCHOR *next;		/* next in list */
  99.932 +};
  99.933 +
  99.934 +
  99.935 +SEARCHPGMLIST {
  99.936 +  SEARCHPGM *pgm;		/* search program */
  99.937 +  SEARCHPGMLIST *next;		/* next in list */
  99.938 +};
  99.939 +
  99.940 +SEARCHPGM {			/* search program */
  99.941 +  SEARCHSET *msgno;		/* message numbers */
  99.942 +  SEARCHSET *uid;		/* unique identifiers */
  99.943 +  SEARCHOR *or;			/* or'ed in programs */
  99.944 +  SEARCHPGMLIST *not;		/* and'ed not program */
  99.945 +  SEARCHHEADER *header;		/* list of headers */
  99.946 +  STRINGLIST *bcc;		/* bcc recipients */
  99.947 +  STRINGLIST *body;		/* text in message body */
  99.948 +  STRINGLIST *cc;		/* cc recipients */
  99.949 +  STRINGLIST *from;		/* originator */
  99.950 +  STRINGLIST *keyword;		/* keywords */
  99.951 +  STRINGLIST *unkeyword;	/* unkeywords */
  99.952 +  STRINGLIST *subject;		/* text in subject */
  99.953 +  STRINGLIST *text;		/* text in headers and body */
  99.954 +  STRINGLIST *to;		/* to recipients */
  99.955 +  unsigned long larger;		/* larger than this size */
  99.956 +  unsigned long smaller;	/* smaller than this size */
  99.957 +  unsigned long older;		/* older than this interval */
  99.958 +  unsigned long younger;	/* younger than this interval */
  99.959 +  unsigned short sentbefore;	/* sent before this date */
  99.960 +  unsigned short senton;	/* sent on this date */
  99.961 +  unsigned short sentsince;	/* sent since this date */
  99.962 +  unsigned short before;	/* before this date */
  99.963 +  unsigned short on;		/* on this date */
  99.964 +  unsigned short since;		/* since this date */
  99.965 +  unsigned int answered : 1;	/* answered messages */
  99.966 +  unsigned int unanswered : 1;	/* unanswered messages */
  99.967 +  unsigned int deleted : 1;	/* deleted messages */
  99.968 +  unsigned int undeleted : 1;	/* undeleted messages */
  99.969 +  unsigned int draft : 1;	/* message draft */
  99.970 +  unsigned int undraft : 1;	/* message undraft */
  99.971 +  unsigned int flagged : 1;	/* flagged messages */
  99.972 +  unsigned int unflagged : 1;	/* unflagged messages */
  99.973 +  unsigned int recent : 1;	/* recent messages */
  99.974 +  unsigned int old : 1;		/* old messages */
  99.975 +  unsigned int seen : 1;	/* seen messages */
  99.976 +  unsigned int unseen : 1;	/* unseen messages */
  99.977 +  /* These must be simulated in IMAP */
  99.978 +  STRINGLIST *return_path;	/* error return address */
  99.979 +  STRINGLIST *sender;		/* sender address list */
  99.980 +  STRINGLIST *reply_to;		/* reply address list */
  99.981 +  STRINGLIST *in_reply_to;	/* replied message ID */
  99.982 +  STRINGLIST *message_id;	/* message ID */
  99.983 +  STRINGLIST *newsgroups;	/* USENET newsgroups */
  99.984 +  STRINGLIST *followup_to;	/* USENET reply newsgroups */
  99.985 +  STRINGLIST *references;	/* USENET references */
  99.986 +};
  99.987 +
  99.988 +
  99.989 +/* Mailbox status */
  99.990 +
  99.991 +typedef struct mbx_status {
  99.992 +  long flags;			/* validity flags */
  99.993 +  unsigned long messages;	/* number of messages */
  99.994 +  unsigned long recent;		/* number of recent messages */
  99.995 +  unsigned long unseen;		/* number of unseen messages */
  99.996 +  unsigned long uidnext;	/* next UID to be assigned */
  99.997 +  unsigned long uidvalidity;	/* UID validity value */
  99.998 +} MAILSTATUS;
  99.999 +
 99.1000 +/* Sort program */
 99.1001 +
 99.1002 +typedef void (*postsort_t) (void *sc);
 99.1003 +
 99.1004 +#define SORTPGM struct sort_program
 99.1005 +
 99.1006 +SORTPGM {
 99.1007 +  unsigned int reverse : 1;	/* sort function is to be reversed */
 99.1008 +  unsigned int abort : 1;	/* abort sorting */
 99.1009 +  short function;		/* sort function */
 99.1010 +  unsigned long nmsgs;		/* number of messages being sorted */
 99.1011 +  struct {
 99.1012 +    unsigned long cached;	/* number of messages cached so far */
 99.1013 +    unsigned long sorted;	/* number of messages sorted so far */
 99.1014 +    unsigned long postsorted;	/* number of postsorted messages so far */
 99.1015 +  } progress;
 99.1016 +  postsort_t postsort;		/* post sorter */
 99.1017 +  SORTPGM *next;		/* next function */
 99.1018 +};
 99.1019 +
 99.1020 +
 99.1021 +/* Sort cache */
 99.1022 +
 99.1023 +#define SORTCACHE struct sort_cache
 99.1024 +
 99.1025 +SORTCACHE {
 99.1026 +  unsigned int sorted : 1;	/* message has been sorted */
 99.1027 +  unsigned int postsorted : 1;	/* message has been postsorted */
 99.1028 +  unsigned int refwd : 1;	/* subject is a re or fwd */
 99.1029 +  unsigned int dirty : 1;	/* has data not written to backup */
 99.1030 +  SORTPGM *pgm;			/* sort program */
 99.1031 +  unsigned long num;		/* message number (sequence or UID) */
 99.1032 +  unsigned long date;		/* sent date */
 99.1033 +  unsigned long arrival;	/* arrival date */
 99.1034 +  unsigned long size;		/* message size */
 99.1035 +  char *from;			/* from string */
 99.1036 +  char *to;			/* to string */
 99.1037 +  char *cc;			/* cc string */
 99.1038 +  char *subject;		/* extracted subject string */
 99.1039 +  char *message_id;		/* message-id string */
 99.1040 +  char *unique;			/* unique string, normally message-id */
 99.1041 +  STRINGLIST *references;	/* references string */
 99.1042 +};
 99.1043 +
 99.1044 +/* ACL list */
 99.1045 +
 99.1046 +#define ACLLIST struct acl_list
 99.1047 +
 99.1048 +ACLLIST {
 99.1049 +  char *identifier;		/* authentication identifier */
 99.1050 +  char *rights;			/* access rights */
 99.1051 +  ACLLIST *next;
 99.1052 +};
 99.1053 +
 99.1054 +/* Quota resource list */
 99.1055 +
 99.1056 +#define QUOTALIST struct quota_list
 99.1057 +
 99.1058 +QUOTALIST {
 99.1059 +  char *name;			/* resource name */
 99.1060 +  unsigned long usage;		/* resource usage */
 99.1061 +  unsigned long limit;		/* resource limit */
 99.1062 +  QUOTALIST *next;		/* next resource */
 99.1063 +};
 99.1064 +
 99.1065 +/* Mail Access I/O stream */
 99.1066 +
 99.1067 +
 99.1068 +/* Structure for mail driver dispatch */
 99.1069 +
 99.1070 +#define DRIVER struct driver	
 99.1071 +
 99.1072 +
 99.1073 +/* Mail I/O stream */
 99.1074 +	
 99.1075 +typedef struct mail_stream {
 99.1076 +  DRIVER *dtb;			/* dispatch table for this driver */
 99.1077 +  void *local;			/* pointer to driver local data */
 99.1078 +  char *mailbox;		/* mailbox name (canonicalized) */
 99.1079 +  char *original_mailbox;	/* mailbox name (non-canonicalized) */
 99.1080 +  unsigned short use;		/* stream use count */
 99.1081 +  unsigned short sequence;	/* stream sequence */
 99.1082 +  unsigned int inbox : 1;	/* stream open on an INBOX */
 99.1083 +  unsigned int lock : 1;	/* stream lock flag */
 99.1084 +  unsigned int debug : 1;	/* stream debug flag */
 99.1085 +  unsigned int silent : 1;	/* don't pass events to main program */
 99.1086 +  unsigned int rdonly : 1;	/* stream read-only flag */
 99.1087 +  unsigned int anonymous : 1;	/* stream anonymous access flag */
 99.1088 +  unsigned int scache : 1;	/* stream short cache flag */
 99.1089 +  unsigned int halfopen : 1;	/* stream half-open flag */
 99.1090 +  unsigned int secure : 1;	/* stream secure flag */
 99.1091 +  unsigned int tryssl : 1;	/* stream tryssl flag */
 99.1092 +  unsigned int mulnewsrc : 1;	/* stream use multiple newsrc files */
 99.1093 +  unsigned int perm_seen : 1;	/* permanent Seen flag */
 99.1094 +  unsigned int perm_deleted : 1;/* permanent Deleted flag */
 99.1095 +  unsigned int perm_flagged : 1;/* permanent Flagged flag */
 99.1096 +  unsigned int perm_answered :1;/* permanent Answered flag */
 99.1097 +  unsigned int perm_draft : 1;	/* permanent Draft flag */
 99.1098 +  unsigned int kwd_create : 1;	/* can create new keywords */
 99.1099 +  unsigned int uid_nosticky : 1;/* UIDs are not preserved */
 99.1100 +  unsigned int unhealthy : 1;	/* unhealthy protocol negotiations */
 99.1101 +  unsigned int nokod : 1;	/* suppress kiss-of-death */
 99.1102 +  unsigned int sniff : 1;	/* metadata only */
 99.1103 +  unsigned long perm_user_flags;/* mask of permanent user flags */
 99.1104 +  unsigned long gensym;		/* generated tag */
 99.1105 +  unsigned long nmsgs;		/* # of associated msgs */
 99.1106 +  unsigned long recent;		/* # of recent msgs */
 99.1107 +  unsigned long uid_validity;	/* UID validity sequence */
 99.1108 +  unsigned long uid_last;	/* last assigned UID */
 99.1109 +  char *user_flags[NUSERFLAGS];	/* pointers to user flags in bit order */
 99.1110 +  unsigned long cachesize;	/* size of message cache */
 99.1111 +  MESSAGECACHE **cache;		/* message cache array */
 99.1112 +  SORTCACHE **sc;		/* sort cache array */
 99.1113 +  unsigned long msgno;		/* message number of `current' message */
 99.1114 +  ENVELOPE *env;		/* scratch buffer for envelope */
 99.1115 +  BODY *body;			/* scratch buffer for body */
 99.1116 +  SIZEDTEXT text;		/* scratch buffer for text */
 99.1117 +  struct {
 99.1118 +    char *name;			/* mailbox name to snarf from */
 99.1119 +    unsigned long time;		/* last snarf time */
 99.1120 +    long options;		/* snarf open options */
 99.1121 +  } snarf;
 99.1122 +  struct {			/* internal use only */
 99.1123 +    struct {			/* search temporaries */
 99.1124 +      STRINGLIST *string;	/* string(s) to search */
 99.1125 +      long result;		/* search result */
 99.1126 +      char *text;		/* cache of fetched text */
 99.1127 +    } search;
 99.1128 +    STRING string;		/* stringstruct return hack */
 99.1129 +  } private;
 99.1130 +			/* reserved for use by main program */
 99.1131 +  void *sparep;			/* spare pointer */
 99.1132 +  unsigned int spare : 1;	/* first spare bit */
 99.1133 +  unsigned int spare2 : 1;	/* second spare bit */
 99.1134 +  unsigned int spare3 : 1;	/* third spare bit */
 99.1135 +  unsigned int spare4 : 1;	/* fourth spare bit */
 99.1136 +  unsigned int spare5 : 1;	/* fifth spare bit */
 99.1137 +  unsigned int spare6 : 1;	/* sixth spare bit */
 99.1138 +  unsigned int spare7 : 1;	/* seventh spare bit */
 99.1139 +  unsigned int spare8 : 1;	/* eighth spare bit */
 99.1140 +} MAILSTREAM;
 99.1141 +
 99.1142 +/* Mail I/O stream handle */
 99.1143 +
 99.1144 +typedef struct mail_stream_handle {
 99.1145 +  MAILSTREAM *stream;		/* pointer to mail stream */
 99.1146 +  unsigned short sequence;	/* sequence of what we expect stream to be */
 99.1147 +} MAILHANDLE;
 99.1148 +
 99.1149 +
 99.1150 +/* Message overview */
 99.1151 +
 99.1152 +typedef struct mail_overview {
 99.1153 +  char *subject;		/* message subject string */
 99.1154 +  ADDRESS *from;		/* originator address list */
 99.1155 +  char *date;			/* message composition date string */
 99.1156 +  char *message_id;		/* message ID */
 99.1157 +  char *references;		/* USENET references */
 99.1158 +  struct {			/* may be 0 or NUL if unknown/undefined */
 99.1159 +    unsigned long octets;	/* message octets (probably LF-newline form) */
 99.1160 +    unsigned long lines;	/* message lines */
 99.1161 +    char *xref;			/* cross references */
 99.1162 +  } optional;
 99.1163 +} OVERVIEW;
 99.1164 +
 99.1165 +/* Network access I/O stream */
 99.1166 +
 99.1167 +
 99.1168 +/* Structure for network driver dispatch */
 99.1169 +
 99.1170 +#define NETDRIVER struct net_driver
 99.1171 +
 99.1172 +
 99.1173 +/* Network transport I/O stream */
 99.1174 +
 99.1175 +typedef struct net_stream {
 99.1176 +  void *stream;			/* driver's I/O stream */
 99.1177 +  NETDRIVER *dtb;		/* network driver */
 99.1178 +} NETSTREAM;
 99.1179 +
 99.1180 +
 99.1181 +/* Network transport driver dispatch */
 99.1182 +
 99.1183 +NETDRIVER {
 99.1184 +  void *(*open) (char *host,char *service,unsigned long port);
 99.1185 +  void *(*aopen) (NETMBX *mb,char *service,char *usrbuf);
 99.1186 +  char *(*getline) (void *stream);
 99.1187 +  long (*getbuffer) (void *stream,unsigned long size,char *buffer);
 99.1188 +  long (*soutr) (void *stream,char *string);
 99.1189 +  long (*sout) (void *stream,char *string,unsigned long size);
 99.1190 +  void (*close) (void *stream);
 99.1191 +  char *(*host) (void *stream);
 99.1192 +  char *(*remotehost) (void *stream);
 99.1193 +  unsigned long (*port) (void *stream);
 99.1194 +  char *(*localhost) (void *stream);
 99.1195 +};
 99.1196 +
 99.1197 +
 99.1198 +/* Mailgets data identifier */
 99.1199 +
 99.1200 +typedef struct getsdata {
 99.1201 +  MAILSTREAM *stream;
 99.1202 +  unsigned long msgno;
 99.1203 +  char *what;
 99.1204 +  STRINGLIST *stl;
 99.1205 +  unsigned long first;
 99.1206 +  unsigned long last;
 99.1207 +  long flags;
 99.1208 +} GETS_DATA;
 99.1209 +
 99.1210 +
 99.1211 +#define INIT_GETS(md,s,m,w,f,l) \
 99.1212 +  md.stream = s, md.msgno = m, md.what = w, md.first = f, md.last = l, \
 99.1213 +  md.stl = NIL, md.flags = NIL;
 99.1214 +
 99.1215 +/* Mail delivery I/O stream */
 99.1216 +
 99.1217 +typedef struct send_stream {
 99.1218 +  NETSTREAM *netstream;		/* network I/O stream */
 99.1219 +  char *host;			/* SMTP service host */
 99.1220 +  char *reply;			/* last reply string */
 99.1221 +  long replycode;		/* last reply code */
 99.1222 +  unsigned int debug : 1;	/* stream debug flag */
 99.1223 +  unsigned int sensitive : 1;	/* sensitive data in progress */
 99.1224 +  unsigned int loser : 1;	/* server is a loser */
 99.1225 +  unsigned int saslcancel : 1;	/* SASL cancelled by protocol */
 99.1226 +  union {			/* protocol specific */
 99.1227 +    struct {			/* SMTP specific */
 99.1228 +      unsigned int ok : 1;	/* supports ESMTP */
 99.1229 +      struct {			/* service extensions */
 99.1230 +	unsigned int send : 1;	/* supports SEND */
 99.1231 +	unsigned int soml : 1;	/* supports SOML */
 99.1232 +	unsigned int saml : 1;	/* supports SAML */
 99.1233 +	unsigned int expn : 1;	/* supports EXPN */
 99.1234 +	unsigned int help : 1;	/* supports HELP */
 99.1235 +	unsigned int turn : 1;	/* supports TURN */
 99.1236 +	unsigned int etrn : 1;	/* supports ETRN */
 99.1237 +	unsigned int starttls:1;/* supports STARTTLS */
 99.1238 +	unsigned int relay : 1;	/* supports relaying */
 99.1239 +	unsigned int pipe : 1;	/* supports pipelining */
 99.1240 +	unsigned int ensc : 1;	/* supports enhanced status codes */
 99.1241 +	unsigned int bmime : 1;	/* supports BINARYMIME */
 99.1242 +	unsigned int chunk : 1;	/* supports CHUNKING */
 99.1243 +      } service;
 99.1244 +      struct {			/* 8-bit MIME transport */
 99.1245 +	unsigned int ok : 1;	/* supports 8-bit MIME */
 99.1246 +	unsigned int want : 1;	/* want 8-bit MIME */
 99.1247 +      } eightbit;
 99.1248 +      struct {			/* delivery status notification */
 99.1249 +	unsigned int ok : 1;	/* supports DSN */
 99.1250 +	unsigned int want : 1;	/* want DSN */
 99.1251 +	struct {		/* notification options */
 99.1252 +				/* notify on failure */
 99.1253 +	  unsigned int failure : 1;
 99.1254 +				/* notify on delay */
 99.1255 +	  unsigned int delay : 1;
 99.1256 +				/* notify on success */
 99.1257 +	  unsigned int success : 1;
 99.1258 +	} notify;
 99.1259 +	unsigned int full : 1;	/* return full headers */
 99.1260 +	char *envid;		/* envelope identifier as xtext */
 99.1261 +      } dsn;
 99.1262 +      struct {			/* size declaration */
 99.1263 +	unsigned int ok : 1;	/* supports SIZE */
 99.1264 +	unsigned long limit;	/* maximum size supported */
 99.1265 +      } size;
 99.1266 +      struct {			/* deliverby declaration */
 99.1267 +	unsigned int ok : 1;	/* supports DELIVERBY */
 99.1268 +	unsigned long minby;	/* minimum by-time */
 99.1269 +      } deliverby;
 99.1270 +      struct {			/* authenticated turn */
 99.1271 +	unsigned int ok : 1;	/* supports ATRN */
 99.1272 +	char *domains;		/* domains */
 99.1273 +      } atrn;
 99.1274 +				/* supported SASL authenticators */
 99.1275 +      unsigned int auth : MAXAUTHENTICATORS;
 99.1276 +    } esmtp;
 99.1277 +    struct {			/* NNTP specific */
 99.1278 +      unsigned int post : 1;	/* supports POST */
 99.1279 +      struct {			/* NNTP extensions */
 99.1280 +	unsigned int ok : 1;	/* supports extensions */
 99.1281 +				/* supports LISTGROUP */
 99.1282 +	unsigned int listgroup : 1;
 99.1283 +	unsigned int over : 1;	/* supports OVER */
 99.1284 +	unsigned int hdr : 1;	/* supports HDR */
 99.1285 +	unsigned int pat : 1;	/* supports PAT */
 99.1286 +				/* supports STARTTLS */
 99.1287 +	unsigned int starttls : 1;
 99.1288 +				/* server has MULTIDOMAIN */
 99.1289 +	unsigned int multidomain : 1;
 99.1290 +				/* supports AUTHINFO USER */
 99.1291 +	unsigned int authuser : 1;
 99.1292 +				/* supported authenticators */
 99.1293 +	unsigned int sasl : MAXAUTHENTICATORS;
 99.1294 +      } ext;
 99.1295 +    } nntp;
 99.1296 +  } protocol;
 99.1297 +} SENDSTREAM;
 99.1298 +
 99.1299 +/* Jacket into external interfaces */
 99.1300 +
 99.1301 +typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer);
 99.1302 +typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size,
 99.1303 +			     GETS_DATA *md);
 99.1304 +typedef char *(*readprogress_t) (GETS_DATA *md,unsigned long octets);
 99.1305 +typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
 99.1306 +typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence,
 99.1307 +				 char *mailbox,long options);
 99.1308 +typedef long (*tcptimeout_t) (long overall,long last);
 99.1309 +typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
 99.1310 +typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
 99.1311 +typedef long (*authcheck_t) (void);
 99.1312 +typedef long (*authclient_t) (authchallenge_t challenger,
 99.1313 +			      authrespond_t responder,char *service,NETMBX *mb,
 99.1314 +			      void *s,unsigned long *trial,char *user);
 99.1315 +typedef char *(*authresponse_t) (void *challenge,unsigned long clen,
 99.1316 +				 unsigned long *rlen);
 99.1317 +typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]);
 99.1318 +typedef void (*smtpverbose_t) (char *buffer);
 99.1319 +typedef void (*imapenvelope_t) (MAILSTREAM *stream,unsigned long msgno,
 99.1320 +				ENVELOPE *env);
 99.1321 +typedef char *(*imapreferral_t) (MAILSTREAM *stream,char *url,long code);
 99.1322 +typedef void (*overview_t) (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
 99.1323 +			    unsigned long msgno);
 99.1324 +typedef unsigned long *(*sorter_t) (MAILSTREAM *stream,char *charset,
 99.1325 +				    SEARCHPGM *spg,SORTPGM *pgm,long flags);
 99.1326 +typedef void (*parseline_t) (ENVELOPE *env,char *hdr,char *data,char *host);
 99.1327 +typedef ADDRESS *(*parsephrase_t) (char *phrase,char *end,char *host);
 99.1328 +typedef void *(*blocknotify_t) (int reason,void *data);
 99.1329 +typedef long (*kinit_t) (char *host,char *reason);
 99.1330 +typedef void (*sendcommand_t) (MAILSTREAM *stream,char *cmd,long flags);
 99.1331 +typedef char *(*newsrcquery_t) (MAILSTREAM *stream,char *mulname,char *name);
 99.1332 +typedef void (*getacl_t) (MAILSTREAM *stream,char *mailbox,ACLLIST *acl);
 99.1333 +typedef void (*listrights_t) (MAILSTREAM *stream,char *mailbox,char *id,
 99.1334 +			      char *alwaysrights,STRINGLIST *possiblerights);
 99.1335 +typedef void (*myrights_t) (MAILSTREAM *stream,char *mailbox,char *rights);
 99.1336 +typedef void (*quota_t) (MAILSTREAM *stream,char *qroot,QUOTALIST *qlist);
 99.1337 +typedef void (*quotaroot_t) (MAILSTREAM *stream,char *mbx,STRINGLIST *qroot);
 99.1338 +typedef void (*sortresults_t) (MAILSTREAM *stream,unsigned long *list,
 99.1339 +			       unsigned long size);
 99.1340 +typedef char *(*userprompt_t) (void);
 99.1341 +typedef long (*append_t) (MAILSTREAM *stream,void *data,char **flags,
 99.1342 +			  char **date,STRING **message);
 99.1343 +typedef void (*copyuid_t) (MAILSTREAM *stream,char *mailbox,
 99.1344 +			   unsigned long uidvalidity,SEARCHSET *sourceset,
 99.1345 +			   SEARCHSET *destset);
 99.1346 +typedef void (*appenduid_t) (char *mailbox,unsigned long uidvalidity,
 99.1347 +			     SEARCHSET *set);
 99.1348 +typedef long (*dirfmttest_t) (char *name);
 99.1349 +typedef long (*scancontents_t) (char *name,char *contents,unsigned long csiz,
 99.1350 +				unsigned long fsiz);
 99.1351 +
 99.1352 +typedef void (*freeeltsparep_t) (void **sparep);
 99.1353 +typedef void (*freeenvelopesparep_t) (void **sparep);
 99.1354 +typedef void (*freebodysparep_t) (void **sparep);
 99.1355 +typedef void (*freestreamsparep_t) (void **sparep);
 99.1356 +typedef void *(*sslstart_t) (void *stream,char *host,unsigned long flags);
 99.1357 +typedef long (*sslcertificatequery_t) (char *reason,char *host,char *cert);
 99.1358 +typedef void (*sslfailure_t) (char *host,char *reason,unsigned long flags);
 99.1359 +typedef void (*logouthook_t) (void *data);
 99.1360 +typedef char *(*sslclientcert_t) (void);
 99.1361 +typedef char *(*sslclientkey_t) (void);
 99.1362 +
 99.1363 +/* Globals */
 99.1364 +
 99.1365 +extern char *body_types[];	/* defined body type strings */
 99.1366 +extern char *body_encodings[];	/* defined body encoding strings */
 99.1367 +extern const char *days[];	/* day name strings */
 99.1368 +extern const char *months[];	/* month name strings */
 99.1369 +
 99.1370 +/* Threading */
 99.1371 +
 99.1372 +/* Thread node */
 99.1373 +
 99.1374 +#define THREADNODE struct thread_node
 99.1375 +
 99.1376 +THREADNODE {
 99.1377 +  unsigned long num;		/* message number */
 99.1378 +  SORTCACHE *sc;		/* (internal use) sortcache entry */
 99.1379 +  THREADNODE *branch;		/* branch at this point in tree */
 99.1380 +  THREADNODE *next;		/* next node */
 99.1381 +};
 99.1382 +
 99.1383 +typedef void (*threadresults_t) (MAILSTREAM *stream,THREADNODE *tree);
 99.1384 +
 99.1385 +
 99.1386 +/* Thread dispatch */
 99.1387 +
 99.1388 +#define THREADER struct threader_list
 99.1389 +
 99.1390 +THREADER {
 99.1391 +  char *name;			/* name of threader */
 99.1392 +  THREADNODE *(*dispatch) (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 99.1393 +			   long flags,sorter_t sorter);
 99.1394 +  THREADER *next;
 99.1395 +};
 99.1396 +
 99.1397 +
 99.1398 +/* Container for references threading */
 99.1399 +
 99.1400 +typedef void ** container_t;
 99.1401 +
 99.1402 +/* Namespaces */
 99.1403 +
 99.1404 +#define NAMESPACE struct mail_namespace
 99.1405 +
 99.1406 +NAMESPACE {
 99.1407 +  char *name;			/* name of this namespace */
 99.1408 +  int delimiter;		/* hierarchy delimiter */
 99.1409 +  PARAMETER *param;		/* namespace parameters */
 99.1410 +  NAMESPACE *next;		/* next namespace */
 99.1411 +};
 99.1412 +
 99.1413 +
 99.1414 +/* Authentication */
 99.1415 +
 99.1416 +#define AUTHENTICATOR struct mail_authenticator
 99.1417 +
 99.1418 +AUTHENTICATOR {
 99.1419 +  long flags;			/* authenticator flags */
 99.1420 +  char *name;			/* name of this authenticator */
 99.1421 +  authcheck_t valid;		/* authenticator valid on this system */
 99.1422 +  authclient_t client;		/* client function that supports it */
 99.1423 +  authserver_t server;		/* server function that supports it */
 99.1424 +  AUTHENTICATOR *next;		/* next authenticator */
 99.1425 +};
 99.1426 +
 99.1427 +/* Mail driver dispatch */
 99.1428 +
 99.1429 +DRIVER {
 99.1430 +  char *name;			/* driver name */
 99.1431 +  unsigned long flags;		/* driver flags */
 99.1432 +  DRIVER *next;			/* next driver */
 99.1433 +				/* mailbox is valid for us */
 99.1434 +  DRIVER *(*valid) (char *mailbox);
 99.1435 +				/* manipulate driver parameters */
 99.1436 +  void *(*parameters) (long function,void *value);
 99.1437 +				/* scan mailboxes */
 99.1438 +  void (*scan) (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 99.1439 +				/* list mailboxes */
 99.1440 +  void (*list) (MAILSTREAM *stream,char *ref,char *pat);
 99.1441 +				/* list subscribed mailboxes */
 99.1442 +  void (*lsub) (MAILSTREAM *stream,char *ref,char *pat);
 99.1443 +				/* subscribe to mailbox */
 99.1444 +  long (*subscribe) (MAILSTREAM *stream,char *mailbox);
 99.1445 +				/* unsubscribe from mailbox */
 99.1446 +  long (*unsubscribe) (MAILSTREAM *stream,char *mailbox);
 99.1447 +				/* create mailbox */
 99.1448 +  long (*create) (MAILSTREAM *stream,char *mailbox);
 99.1449 +				/* delete mailbox */
 99.1450 +  long (*mbxdel) (MAILSTREAM *stream,char *mailbox);
 99.1451 +				/* rename mailbox */
 99.1452 +  long (*mbxren) (MAILSTREAM *stream,char *old,char *newname);
 99.1453 +				/* status of mailbox */
 99.1454 +  long (*status) (MAILSTREAM *stream,char *mbx,long flags);
 99.1455 +
 99.1456 +				/* open mailbox */
 99.1457 +  MAILSTREAM *(*open) (MAILSTREAM *stream);
 99.1458 +				/* close mailbox */
 99.1459 +  void (*close) (MAILSTREAM *stream,long options);
 99.1460 +				/* fetch message "fast" attributes */
 99.1461 +  void (*fast) (MAILSTREAM *stream,char *sequence,long flags);
 99.1462 +				/* fetch message flags */
 99.1463 +  void (*msgflags) (MAILSTREAM *stream,char *sequence,long flags);
 99.1464 +				/* fetch message overview */
 99.1465 +  long (*overview) (MAILSTREAM *stream,overview_t ofn);
 99.1466 +				/* fetch message envelopes */
 99.1467 +  ENVELOPE *(*structure) (MAILSTREAM *stream,unsigned long msgno,BODY **body,
 99.1468 +			  long flags);
 99.1469 +				/* return RFC-822 header */
 99.1470 +  char *(*header) (MAILSTREAM *stream,unsigned long msgno,
 99.1471 +		   unsigned long *length,long flags);
 99.1472 +				/* return RFC-822 text */
 99.1473 +  long (*text) (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 99.1474 +				/* load cache */
 99.1475 +  long (*msgdata) (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1476 +		   unsigned long first,unsigned long last,STRINGLIST *lines,
 99.1477 +		   long flags);
 99.1478 +				/* return UID for message */
 99.1479 +  unsigned long (*uid) (MAILSTREAM *stream,unsigned long msgno);
 99.1480 +				/* return message number from UID */
 99.1481 +  unsigned long (*msgno) (MAILSTREAM *stream,unsigned long uid);
 99.1482 +				/* modify flags */
 99.1483 +  void (*flag) (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 99.1484 +				/* per-message modify flags */
 99.1485 +  void (*flagmsg) (MAILSTREAM *stream,MESSAGECACHE *elt);
 99.1486 +				/* search for message based on criteria */
 99.1487 +  long (*search) (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
 99.1488 +				/* sort messages */
 99.1489 +  unsigned long *(*sort) (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 99.1490 +			  SORTPGM *pgm,long flags);
 99.1491 +				/* thread messages */
 99.1492 +  THREADNODE *(*thread) (MAILSTREAM *stream,char *type,char *charset,
 99.1493 +			 SEARCHPGM *spg,long flag);
 99.1494 +				/* ping mailbox to see if still alive */
 99.1495 +  long (*ping) (MAILSTREAM *stream);
 99.1496 +				/* check for new messages */
 99.1497 +  void (*check) (MAILSTREAM *stream);
 99.1498 +				/* expunge deleted messages */
 99.1499 +  long (*expunge) (MAILSTREAM *stream,char *sequence,long options);
 99.1500 +				/* copy messages to another mailbox */
 99.1501 +  long (*copy) (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 99.1502 +				/* append string message to mailbox */
 99.1503 +  long (*append) (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 99.1504 +				/* garbage collect stream */
 99.1505 +  void (*gc) (MAILSTREAM *stream,long gcflags);
 99.1506 +};
 99.1507 +
 99.1508 +
 99.1509 +#include "linkage.h"
 99.1510 +
 99.1511 +/* Compatibility support names for old interfaces */
 99.1512 +
 99.1513 +#define GET_TRYALTFIRST GET_TRYSSLFIRST
 99.1514 +#define SET_TRYALTFIRST SET_TRYSSLFIRST
 99.1515 +#define GET_IMAPTRYALT GET_IMAPTRYSSL
 99.1516 +#define SET_IMAPTRYALT SET_IMAPTRYSSL
 99.1517 +#define OP_TRYALT OP_TRYSSL
 99.1518 +#define altflag sslflag
 99.1519 +
 99.1520 +#define mail_close(stream) \
 99.1521 +  mail_close_full (stream,NIL)
 99.1522 +#define mail_fetchfast(stream,sequence) \
 99.1523 +  mail_fetch_fast (stream,sequence,NIL)
 99.1524 +#define mail_fetchfast_full mail_fetch_fast
 99.1525 +#define mail_fetchflags(stream,sequence) \
 99.1526 +  mail_fetch_flags (stream,sequence,NIL)
 99.1527 +#define mail_fetchflags_full mail_fetch_flags
 99.1528 +#define mail_fetchenvelope(stream,msgno) \
 99.1529 +  mail_fetch_structure (stream,msgno,NIL,NIL)
 99.1530 +#define mail_fetchstructure(stream,msgno,body) \
 99.1531 +  mail_fetch_structure (stream,msgno,body,NIL)
 99.1532 +#define mail_fetchstructure_full mail_fetch_structure
 99.1533 +#define mail_fetchheader(stream,msgno) \
 99.1534 +  mail_fetch_header (stream,msgno,NIL,NIL,NIL,FT_PEEK)
 99.1535 +#define mail_fetchheader_full(stream,msgno,lines,len,flags) \
 99.1536 +  mail_fetch_header (stream,msgno,NIL,lines,len,FT_PEEK | (flags))
 99.1537 +#define mail_fetchtext(stream,msgno) \
 99.1538 +  mail_fetch_text (stream,msgno,NIL,NIL,NIL)
 99.1539 +#define mail_fetchtext_full(stream,msgno,length,flags) \
 99.1540 +  mail_fetch_text (stream,msgno,NIL,length,flags)
 99.1541 +#define mail_fetchbody(stream,msgno,section,length) \
 99.1542 +  mail_fetch_body (stream,msgno,section,length,NIL)
 99.1543 +#define mail_fetchbody_full mail_fetch_body
 99.1544 +#define mail_setflag(stream,sequence,flag) \
 99.1545 +  mail_flag (stream,sequence,flag,ST_SET)
 99.1546 +#define mail_setflag_full(stream,sequence,flag,flags) \
 99.1547 +  mail_flag (stream,sequence,flag,ST_SET | (flags))
 99.1548 +#define mail_clearflag(stream,sequence,flag) \
 99.1549 +  mail_flag (stream,sequence,flag,NIL)
 99.1550 +#define mail_clearflag_full mail_flag
 99.1551 +#define mail_search(stream,criteria) \
 99.1552 +  mail_search_full (stream,NIL,mail_criteria (criteria),SE_FREE);
 99.1553 +#define mail_expunge(stream) \
 99.1554 +  mail_expunge_full (stream,NIL,NIL)
 99.1555 +#define mail_copy(stream,sequence,mailbox) \
 99.1556 +  mail_copy_full (stream,sequence,mailbox,NIL)
 99.1557 +#define mail_move(stream,sequence,mailbox) \
 99.1558 +  mail_copy_full (stream,sequence,mailbox,CP_MOVE)
 99.1559 +#define mail_append(stream,mailbox,message) \
 99.1560 +  mail_append_full (stream,mailbox,NIL,NIL,message)
 99.1561 +
 99.1562 +/* Interfaces for SVR4 locking brain-damage workaround */
 99.1563 +
 99.1564 +/* Driver dispatching */
 99.1565 +
 99.1566 +#define SAFE_DELETE(dtb,stream,mailbox) (*dtb->mbxdel) (stream,mailbox)
 99.1567 +#define SAFE_RENAME(dtb,stream,old,newname) (*dtb->mbxren) (stream,old,newname)
 99.1568 +#define SAFE_STATUS(dtb,stream,mbx,flags) (*dtb->status) (stream,mbx,flags)
 99.1569 +#define SAFE_COPY(dtb,stream,sequence,mailbox,options) \
 99.1570 +  (*dtb->copy) (stream,sequence,mailbox,options)
 99.1571 +#define SAFE_APPEND(dtb,stream,mailbox,af,data) \
 99.1572 +  (*dtb->append) (stream,mailbox,af,data)
 99.1573 +#define SAFE_SCAN_CONTENTS(dtb,name,contents,csiz,fsiz) \
 99.1574 +  scan_contents (dtb,name,contents,csiz,fsiz)
 99.1575 +
 99.1576 +
 99.1577 +/* Driver callbacks */
 99.1578 +
 99.1579 +#define MM_EXISTS mm_exists
 99.1580 +#define MM_EXPUNGED mm_expunged
 99.1581 +#define MM_FLAGS mm_flags
 99.1582 +#define MM_NOTIFY mm_notify
 99.1583 +#define MM_STATUS mm_status
 99.1584 +#define MM_LOG mm_log
 99.1585 +#define MM_CRITICAL mm_critical
 99.1586 +#define MM_NOCRITICAL mm_nocritical
 99.1587 +#define MM_DISKERROR mm_diskerror
 99.1588 +#define MM_FATAL mm_fatal
 99.1589 +#define MM_APPEND(af) (*af)
 99.1590 +
 99.1591 +/* Function prototypes */
 99.1592 +
 99.1593 +void mm_searched (MAILSTREAM *stream,unsigned long number);
 99.1594 +void mm_exists (MAILSTREAM *stream,unsigned long number);
 99.1595 +void mm_expunged (MAILSTREAM *stream,unsigned long number);
 99.1596 +void mm_flags (MAILSTREAM *stream,unsigned long number);
 99.1597 +void mm_notify (MAILSTREAM *stream,char *string,long errflg);
 99.1598 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes);
 99.1599 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes);
 99.1600 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
 99.1601 +void mm_log (char *string,long errflg);
 99.1602 +void mm_dlog (char *string);
 99.1603 +void mm_login (NETMBX *mb,char *user,char *pwd,long trial);
 99.1604 +void mm_critical (MAILSTREAM *stream);
 99.1605 +void mm_nocritical (MAILSTREAM *stream);
 99.1606 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious);
 99.1607 +void mm_fatal (char *string);
 99.1608 +void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op);
 99.1609 +
 99.1610 +extern STRINGDRIVER mail_string;
 99.1611 +void mail_versioncheck (char *version);
 99.1612 +void mail_link (DRIVER *driver);
 99.1613 +void *mail_parameters (MAILSTREAM *stream,long function,void *value);
 99.1614 +DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose);
 99.1615 +DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox);
 99.1616 +long mail_valid_net_parse (char *name,NETMBX *mb);
 99.1617 +long mail_valid_net_parse_work (char *name,NETMBX *mb,char *service);
 99.1618 +void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 99.1619 +void mail_list (MAILSTREAM *stream,char *ref,char *pat);
 99.1620 +void mail_lsub (MAILSTREAM *stream,char *ref,char *pat);
 99.1621 +long mail_subscribe (MAILSTREAM *stream,char *mailbox);
 99.1622 +long mail_unsubscribe (MAILSTREAM *stream,char *mailbox);
 99.1623 +long mail_create (MAILSTREAM *stream,char *mailbox);
 99.1624 +long mail_delete (MAILSTREAM *stream,char *mailbox);
 99.1625 +long mail_rename (MAILSTREAM *stream,char *old,char *newname);
 99.1626 +char *mail_utf7_valid (char *mailbox);
 99.1627 +long mail_status (MAILSTREAM *stream,char *mbx,long flags);
 99.1628 +long mail_status_default (MAILSTREAM *stream,char *mbx,long flags);
 99.1629 +MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options);
 99.1630 +MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name,
 99.1631 +			    long options);
 99.1632 +MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options);
 99.1633 +MAILHANDLE *mail_makehandle (MAILSTREAM *stream);
 99.1634 +void mail_free_handle (MAILHANDLE **handle);
 99.1635 +MAILSTREAM *mail_stream (MAILHANDLE *handle);
 99.1636 +
 99.1637 +void mail_fetch_fast (MAILSTREAM *stream,char *sequence,long flags);
 99.1638 +void mail_fetch_flags (MAILSTREAM *stream,char *sequence,long flags);
 99.1639 +void mail_fetch_overview (MAILSTREAM *stream,char *sequence,overview_t ofn);
 99.1640 +void mail_fetch_overview_sequence (MAILSTREAM *stream,char *sequence,
 99.1641 +				   overview_t ofn);
 99.1642 +void mail_fetch_overview_default (MAILSTREAM *stream,overview_t ofn);
 99.1643 +ENVELOPE *mail_fetch_structure (MAILSTREAM *stream,unsigned long msgno,
 99.1644 +				BODY **body,long flags);
 99.1645 +char *mail_fetch_message (MAILSTREAM *stream,unsigned long msgno,
 99.1646 +			  unsigned long *len,long flags);
 99.1647 +char *mail_fetch_header (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1648 +			 STRINGLIST *lines,unsigned long *len,long flags);
 99.1649 +char *mail_fetch_text (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1650 +		       unsigned long *len,long flags);
 99.1651 +char *mail_fetch_mime (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1652 +		       unsigned long *len,long flags);
 99.1653 +char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1654 +		       unsigned long *len,long flags);
 99.1655 +long mail_partial_text (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1656 +			unsigned long first,unsigned long last,long flags);
 99.1657 +long mail_partial_body (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1658 +			unsigned long first,unsigned long last,long flags);
 99.1659 +char *mail_fetch_text_return (GETS_DATA *md,SIZEDTEXT *t,unsigned long *len);
 99.1660 +char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i,
 99.1661 +				unsigned long *len,long flags);
 99.1662 +long mail_read (void *stream,unsigned long size,char *buffer);
 99.1663 +unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno);
 99.1664 +unsigned long mail_msgno (MAILSTREAM *stream,unsigned long uid);
 99.1665 +void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
 99.1666 +		     long length);
 99.1667 +void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
 99.1668 +			long length);
 99.1669 +MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno);
 99.1670 +void mail_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 99.1671 +long mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
 99.1672 +		       long flags);
 99.1673 +long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
 99.1674 +			  long flags);
 99.1675 +long mail_ping (MAILSTREAM *stream);
 99.1676 +void mail_check (MAILSTREAM *stream);
 99.1677 +long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options);
 99.1678 +long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
 99.1679 +		     long options);
 99.1680 +long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
 99.1681 +		       STRING *message);
 99.1682 +long mail_append_multiple (MAILSTREAM *stream,char *mailbox,append_t af,
 99.1683 +			   void *data);
 99.1684 +void mail_gc (MAILSTREAM *stream,long gcflags);
 99.1685 +void mail_gc_msg (MESSAGE *msg,long gcflags);
 99.1686 +void mail_gc_body (BODY *body);
 99.1687 +
 99.1688 +BODY *mail_body (MAILSTREAM *stream,unsigned long msgno,
 99.1689 +		 unsigned char *section);
 99.1690 +char *mail_date (char *string,MESSAGECACHE *elt);
 99.1691 +char *mail_cdate (char *string,MESSAGECACHE *elt);
 99.1692 +long mail_parse_date (MESSAGECACHE *elt,unsigned char *string);
 99.1693 +void mail_exists (MAILSTREAM *stream,unsigned long nmsgs);
 99.1694 +void mail_recent (MAILSTREAM *stream,unsigned long recent);
 99.1695 +void mail_expunged (MAILSTREAM *stream,unsigned long msgno);
 99.1696 +void mail_lock (MAILSTREAM *stream);
 99.1697 +void mail_unlock (MAILSTREAM *stream);
 99.1698 +void mail_debug (MAILSTREAM *stream);
 99.1699 +void mail_nodebug (MAILSTREAM *stream);
 99.1700 +void mail_dlog (char *string,long flag);
 99.1701 +long mail_match_lines (STRINGLIST *lines,STRINGLIST *msglines,long flags);
 99.1702 +unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
 99.1703 +			   long flags);
 99.1704 +long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1705 +		      SEARCHPGM *pgm);
 99.1706 +long mail_search_header_text (char *s,STRINGLIST *st);
 99.1707 +long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st);
 99.1708 +long mail_search_text (MAILSTREAM *stream,unsigned long msgno,char *section,
 99.1709 +		       STRINGLIST *st,long flags);
 99.1710 +long mail_search_body (MAILSTREAM *stream,unsigned long msgno,BODY *body,
 99.1711 +		       char *prefix,unsigned long section,long flags);
 99.1712 +long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st);
 99.1713 +long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st);
 99.1714 +long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st,
 99.1715 +			  long flag);
 99.1716 +long mail_search_addr (ADDRESS *adr,STRINGLIST *st);
 99.1717 +char *mail_search_gets (readfn_t f,void *stream,unsigned long size,
 99.1718 +			GETS_DATA *md);
 99.1719 +SEARCHPGM *mail_criteria (char *criteria);
 99.1720 +int mail_criteria_date (unsigned short *date,char **r);
 99.1721 +int mail_criteria_string (STRINGLIST **s,char **r);
 99.1722 +unsigned short mail_shortdate (unsigned int year,unsigned int month,
 99.1723 +			       unsigned int day);
 99.1724 +SEARCHSET *mail_parse_set (char *s,char **ret);
 99.1725 +SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno);
 99.1726 +unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 99.1727 +			  SORTPGM *pgm,long flags);
 99.1728 +unsigned long *mail_sort_cache (MAILSTREAM *stream,SORTPGM *pgm,SORTCACHE **sc,
 99.1729 +				long flags);
 99.1730 +unsigned long *mail_sort_msgs (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 99.1731 +			       SORTPGM *pgm,long flags);
 99.1732 +SORTCACHE **mail_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm);
 99.1733 +unsigned int mail_strip_subject (char *t,char **ret);
 99.1734 +char *mail_strip_subject_wsp (char *s);
 99.1735 +char *mail_strip_subject_blob (char *s);
 99.1736 +int mail_sort_compare (const void *a1,const void *a2);
 99.1737 +unsigned long mail_longdate (MESSAGECACHE *elt);
 99.1738 +THREADNODE *mail_thread (MAILSTREAM *stream,char *type,char *charset,
 99.1739 +			 SEARCHPGM *spg,long flags);
 99.1740 +THREADNODE *mail_thread_msgs (MAILSTREAM *stream,char *type,char *charset,
 99.1741 +			      SEARCHPGM *spg,long flags,sorter_t sorter);
 99.1742 +THREADNODE *mail_thread_orderedsubject (MAILSTREAM *stream,char *charset,
 99.1743 +					SEARCHPGM *spg,long flags,
 99.1744 +					sorter_t sorter);
 99.1745 +THREADNODE *mail_thread_references (MAILSTREAM *stream,char *charset,
 99.1746 +				    SEARCHPGM *spg,long flags,
 99.1747 +				    sorter_t sorter);
 99.1748 +void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
 99.1749 +			    unsigned long msgno);
 99.1750 +char *mail_thread_parse_msgid (char *s,char **ss);
 99.1751 +STRINGLIST *mail_thread_parse_references (char *s,long flag);
 99.1752 +long mail_thread_check_child (container_t mother,container_t daughter);
 99.1753 +container_t mail_thread_prune_dummy (container_t msg,container_t ane);
 99.1754 +container_t mail_thread_prune_dummy_work (container_t msg,container_t ane);
 99.1755 +THREADNODE *mail_thread_c2node (MAILSTREAM *stream,container_t con,long flags);
 99.1756 +THREADNODE *mail_thread_sort (THREADNODE *thr,THREADNODE **tc);
 99.1757 +int mail_thread_compare_date (const void *a1,const void *a2);
 99.1758 +long mail_sequence (MAILSTREAM *stream,unsigned char *sequence);
 99.1759 +long mail_uid_sequence (MAILSTREAM *stream,unsigned char *sequence);
 99.1760 +long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf);
 99.1761 +long mail_usable_network_stream (MAILSTREAM *stream,char *name);
 99.1762 +
 99.1763 +MESSAGECACHE *mail_new_cache_elt (unsigned long msgno);
 99.1764 +ENVELOPE *mail_newenvelope (void);
 99.1765 +ADDRESS *mail_newaddr (void);
 99.1766 +BODY *mail_newbody (void);
 99.1767 +BODY *mail_initbody (BODY *body);
 99.1768 +PARAMETER *mail_newbody_parameter (void);
 99.1769 +PART *mail_newbody_part (void);
 99.1770 +MESSAGE *mail_newmsg (void);
 99.1771 +STRINGLIST *mail_newstringlist (void);
 99.1772 +SEARCHPGM *mail_newsearchpgm (void);
 99.1773 +SEARCHHEADER *mail_newsearchheader (char *line,char *text);
 99.1774 +SEARCHSET *mail_newsearchset (void);
 99.1775 +SEARCHOR *mail_newsearchor (void);
 99.1776 +SEARCHPGMLIST *mail_newsearchpgmlist (void);
 99.1777 +SORTPGM *mail_newsortpgm (void);
 99.1778 +THREADNODE *mail_newthreadnode (SORTCACHE *sc);
 99.1779 +ACLLIST *mail_newacllist (void);
 99.1780 +QUOTALIST *mail_newquotalist (void);
 99.1781 +void mail_free_body (BODY **body);
 99.1782 +void mail_free_body_data (BODY *body);
 99.1783 +void mail_free_body_parameter (PARAMETER **parameter);
 99.1784 +void mail_free_body_part (PART **part);
 99.1785 +void mail_free_cache (MAILSTREAM *stream);
 99.1786 +void mail_free_elt (MESSAGECACHE **elt);
 99.1787 +void mail_free_envelope (ENVELOPE **env);
 99.1788 +void mail_free_address (ADDRESS **address);
 99.1789 +void mail_free_stringlist (STRINGLIST **string);
 99.1790 +void mail_free_searchpgm (SEARCHPGM **pgm);
 99.1791 +void mail_free_searchheader (SEARCHHEADER **hdr);
 99.1792 +void mail_free_searchset (SEARCHSET **set);
 99.1793 +void mail_free_searchor (SEARCHOR **orl);
 99.1794 +void mail_free_searchpgmlist (SEARCHPGMLIST **pgl);
 99.1795 +void mail_free_namespace (NAMESPACE **n);
 99.1796 +void mail_free_sortpgm (SORTPGM **pgm);
 99.1797 +void mail_free_threadnode (THREADNODE **thr);
 99.1798 +void mail_free_acllist (ACLLIST **al);
 99.1799 +void mail_free_quotalist (QUOTALIST **ql);
 99.1800 +void auth_link (AUTHENTICATOR *auth);
 99.1801 +char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]);
 99.1802 +AUTHENTICATOR *mail_lookup_auth (unsigned long i);
 99.1803 +unsigned int mail_lookup_auth_name (char *mechanism,long flags);
 99.1804 +
 99.1805 +NETSTREAM *net_open (NETMBX *mb,NETDRIVER *dv,unsigned long port,
 99.1806 +		     NETDRIVER *ssld,char *ssls,unsigned long sslp);
 99.1807 +NETSTREAM *net_open_work (NETDRIVER *dv,char *host,char *service,
 99.1808 +			  unsigned long port,unsigned long portoverride,
 99.1809 +			  unsigned long flags);
 99.1810 +NETSTREAM *net_aopen (NETDRIVER *dv,NETMBX *mb,char *service,char *usrbuf);
 99.1811 +char *net_getline (NETSTREAM *stream);
 99.1812 +				/* stream must be void* for use as readfn_t */
 99.1813 +long net_getbuffer (void *stream,unsigned long size,char *buffer);
 99.1814 +long net_soutr (NETSTREAM *stream,char *string);
 99.1815 +long net_sout (NETSTREAM *stream,char *string,unsigned long size);
 99.1816 +void net_close (NETSTREAM *stream);
 99.1817 +char *net_host (NETSTREAM *stream);
 99.1818 +char *net_remotehost (NETSTREAM *stream);
 99.1819 +unsigned long net_port (NETSTREAM *stream);
 99.1820 +char *net_localhost (NETSTREAM *stream);
 99.1821 +
 99.1822 +long sm_subscribe (char *mailbox);
 99.1823 +long sm_unsubscribe (char *mailbox);
 99.1824 +char *sm_read (void **sdb);
 99.1825 +
 99.1826 +void ssl_onceonlyinit (void);
 99.1827 +char *ssl_start_tls (char *s);
 99.1828 +void ssl_server_init (char *server);
 99.1829 +
 99.1830 +
 99.1831 +/* Server I/O functions */
 99.1832 +
 99.1833 +int PBIN (void);
 99.1834 +char *PSIN (char *s,int n);
 99.1835 +long PSINR (char *s,unsigned long n);
 99.1836 +int PBOUT (int c);
 99.1837 +long INWAIT (long seconds);
 99.1838 +int PSOUT (char *s);
 99.1839 +int PSOUTR (SIZEDTEXT *s);
 99.1840 +int PFLUSH (void);
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/src/c-client/misc.c	Mon Sep 14 15:17:45 2009 +0900
   100.3 @@ -0,0 +1,475 @@
   100.4 +/* ========================================================================
   100.5 + * Copyright 1988-2006 University of Washington
   100.6 + *
   100.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   100.8 + * you may not use this file except in compliance with the License.
   100.9 + * You may obtain a copy of the License at
  100.10 + *
  100.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  100.12 + *
  100.13 + * 
  100.14 + * ========================================================================
  100.15 + */
  100.16 +
  100.17 +/*
  100.18 + * Program:	Miscellaneous utility routines
  100.19 + *
  100.20 + * Author:	Mark Crispin
  100.21 + *		Networks and Distributed Computing
  100.22 + *		Computing & Communications
  100.23 + *		University of Washington
  100.24 + *		Administration Building, AG-44
  100.25 + *		Seattle, WA  98195
  100.26 + *		Internet: MRC@CAC.Washington.EDU
  100.27 + *
  100.28 + * Date:	5 July 1988
  100.29 + * Last Edited:	6 December 2006
  100.30 + *
  100.31 + * This original version of this file is
  100.32 + * Copyright 1988 Stanford University
  100.33 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  100.34 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  100.35 + * Biomedical Research Technology Program of the NationalInstitutes of Health
  100.36 + * under grant number RR-00785.
  100.37 + */
  100.38 +
  100.39 +
  100.40 +#include <ctype.h>
  100.41 +#include "c-client.h"
  100.42 +
  100.43 +/* Convert ASCII string to all uppercase
  100.44 + * Accepts: string pointer
  100.45 + * Returns: string pointer
  100.46 + *
  100.47 + * Don't use islower/toupper since this function must be ASCII only.
  100.48 + */
  100.49 +
  100.50 +unsigned char *ucase (unsigned char *s)
  100.51 +{
  100.52 +  unsigned char *t;
  100.53 +				/* if lowercase covert to upper */
  100.54 +  for (t = s; *t; t++) if ((*t >= 'a') && (*t <= 'z')) *t -= ('a' - 'A');
  100.55 +  return s;			/* return string */
  100.56 +}
  100.57 +
  100.58 +
  100.59 +/* Convert string to all lowercase
  100.60 + * Accepts: string pointer
  100.61 + * Returns: string pointer
  100.62 + *
  100.63 + * Don't use isupper/tolower since this function must be ASCII only.
  100.64 + */
  100.65 +
  100.66 +unsigned char *lcase (unsigned char *s)
  100.67 +{
  100.68 +  unsigned char *t;
  100.69 +				/* if uppercase covert to lower */
  100.70 +  for (t = s; *t; t++) if ((*t >= 'A') && (*t <= 'Z')) *t += ('a' - 'A');
  100.71 +  return s;			/* return string */
  100.72 +}
  100.73 +
  100.74 +/* Copy string to free storage
  100.75 + * Accepts: source string
  100.76 + * Returns: free storage copy of string
  100.77 + */
  100.78 +
  100.79 +char *cpystr (const char *string)
  100.80 +{
  100.81 +  return string ? strcpy ((char *) fs_get (1 + strlen (string)),string) : NIL;
  100.82 +}
  100.83 +
  100.84 +
  100.85 +/* Copy text/size to free storage as sized text
  100.86 + * Accepts: destination sized text
  100.87 + *	    pointer to source text
  100.88 + *	    size of source text
  100.89 + * Returns: text as a char *
  100.90 + */
  100.91 +
  100.92 +char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size)
  100.93 +{
  100.94 +				/* flush old space */
  100.95 +  if (dst->data) fs_give ((void **) &dst->data);
  100.96 +				/* copy data in sized text */
  100.97 +  memcpy (dst->data = (unsigned char *)
  100.98 +	  fs_get ((size_t) (dst->size = size) + 1),text,(size_t) size);
  100.99 +  dst->data[size] = '\0';	/* tie off text */
 100.100 +  return (char *) dst->data;	/* convenience return */
 100.101 +}
 100.102 +
 100.103 +/* Copy sized text to free storage as sized text
 100.104 + * Accepts: destination sized text
 100.105 + *	    source sized text
 100.106 + * Returns: text as a char *
 100.107 + */
 100.108 +
 100.109 +char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src)
 100.110 +{
 100.111 +				/* flush old space */
 100.112 +  if (dst->data) fs_give ((void **) &dst->data);
 100.113 +				/* copy data in sized text */
 100.114 +  memcpy (dst->data = (unsigned char *)
 100.115 +	  fs_get ((size_t) (dst->size = src->size) + 1),
 100.116 +	  src->data,(size_t) src->size);
 100.117 +  dst->data[dst->size] = '\0';	/* tie off text */
 100.118 +  return (char *) dst->data;	/* convenience return */
 100.119 +}
 100.120 +
 100.121 +
 100.122 +/* Copy stringstruct to free storage as sized text
 100.123 + * Accepts: destination sized text
 100.124 + *	    source stringstruct
 100.125 + * Returns: text as a char *
 100.126 + */
 100.127 +
 100.128 +char *textcpystring (SIZEDTEXT *text,STRING *bs)
 100.129 +{
 100.130 +  unsigned long i = 0;
 100.131 +				/* clear old space */
 100.132 +  if (text->data) fs_give ((void **) &text->data);
 100.133 +				/* make free storage space in sized text */
 100.134 +  text->data = (unsigned char *) fs_get ((size_t) (text->size = SIZE (bs)) +1);
 100.135 +  while (i < text->size) text->data[i++] = SNX (bs);
 100.136 +  text->data[i] = '\0';		/* tie off text */
 100.137 +  return (char *) text->data;	/* convenience return */
 100.138 +}
 100.139 +
 100.140 +
 100.141 +/* Copy stringstruct from offset to free storage as sized text
 100.142 + * Accepts: destination sized text
 100.143 + *	    source stringstruct
 100.144 + *	    offset into stringstruct
 100.145 + *	    size of source text
 100.146 + * Returns: text as a char *
 100.147 + */
 100.148 +
 100.149 +char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset,
 100.150 +			unsigned long size)
 100.151 +{
 100.152 +  unsigned long i = 0;
 100.153 +				/* clear old space */
 100.154 +  if (text->data) fs_give ((void **) &text->data);
 100.155 +  SETPOS (bs,offset);		/* offset the string */
 100.156 +				/* make free storage space in sized text */
 100.157 +  text->data = (unsigned char *) fs_get ((size_t) (text->size = size) + 1);
 100.158 +  while (i < size) text->data[i++] = SNX (bs);
 100.159 +  text->data[i] = '\0';		/* tie off text */
 100.160 +  return (char *) text->data;	/* convenience return */
 100.161 +}
 100.162 +
 100.163 +/* Returns index of rightmost bit in word
 100.164 + * Accepts: pointer to a 32 bit value
 100.165 + * Returns: -1 if word is 0, else index of rightmost bit
 100.166 + *
 100.167 + * Bit is cleared in the word
 100.168 + */
 100.169 +
 100.170 +unsigned long find_rightmost_bit (unsigned long *valptr)
 100.171 +{
 100.172 +  unsigned long value = *valptr;
 100.173 +  unsigned long bit = 0;
 100.174 +  if (!(value & 0xffffffff)) return 0xffffffff;
 100.175 +				/* binary search for rightmost bit */
 100.176 +  if (!(value & 0xffff)) value >>= 16, bit += 16;
 100.177 +  if (!(value & 0xff)) value >>= 8, bit += 8;
 100.178 +  if (!(value & 0xf)) value >>= 4, bit += 4;
 100.179 +  if (!(value & 0x3)) value >>= 2, bit += 2;
 100.180 +  if (!(value & 0x1)) value >>= 1, bit += 1;
 100.181 +  *valptr ^= (1 << bit);	/* clear specified bit */
 100.182 +  return bit;
 100.183 +}
 100.184 +
 100.185 +
 100.186 +/* Return minimum of two integers
 100.187 + * Accepts: integer 1
 100.188 + *	    integer 2
 100.189 + * Returns: minimum
 100.190 + */
 100.191 +
 100.192 +long min (long i,long j)
 100.193 +{
 100.194 +  return ((i < j) ? i : j);
 100.195 +}
 100.196 +
 100.197 +
 100.198 +/* Return maximum of two integers
 100.199 + * Accepts: integer 1
 100.200 + *	    integer 2
 100.201 + * Returns: maximum
 100.202 + */
 100.203 +
 100.204 +long max (long i,long j)
 100.205 +{
 100.206 +  return ((i > j) ? i : j);
 100.207 +}
 100.208 +
 100.209 +/* Search, case-insensitive for ASCII characters
 100.210 + * Accepts: base string
 100.211 + *	    length of base string
 100.212 + *	    pattern string
 100.213 + *	    length of pattern string
 100.214 + * Returns: T if pattern exists inside base, else NIL
 100.215 + */
 100.216 +
 100.217 +long search (unsigned char *base,long basec,unsigned char *pat,long patc)
 100.218 +{
 100.219 +  long i,j,k;
 100.220 +  int c;
 100.221 +  unsigned char mask[256];
 100.222 +  static unsigned char alphatab[256] = {
 100.223 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.224 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.225 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.226 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.227 +    255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
 100.228 +    223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255,
 100.229 +    255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
 100.230 +    223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255,
 100.231 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.232 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.233 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.234 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.235 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.236 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.237 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 100.238 +    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
 100.239 +    };
 100.240 +				/* validate arguments */
 100.241 +  if (base && (basec > 0) && pat && (basec >= patc)) {
 100.242 +    if (patc <= 0) return T;	/* empty pattern always succeeds */
 100.243 +    memset (mask,0,256);	/* initialize search validity mask */
 100.244 +    for (i = 0; i < patc; i++) if (!mask[c = pat[i]]) {
 100.245 +				/* mark single character if non-alphabetic */
 100.246 +      if (alphatab[c] & 0x20) mask[c] = T;
 100.247 +				/* else mark both cases */
 100.248 +      else mask[c & 0xdf] = mask[c | 0x20] = T;
 100.249 +    }
 100.250 +				/* Boyer-Moore type search */
 100.251 +    for (i = --patc; i < basec; i += (mask[c] ? 1 : (j + 1)))
 100.252 +      for (j = patc,c = base[k = i]; !((c ^ pat[j]) & alphatab[c]);
 100.253 +	   j--,c = base[--k])
 100.254 +	if (!j) return T;	/* found a match! */
 100.255 +  }
 100.256 +  return NIL;			/* pattern not found */
 100.257 +}
 100.258 +
 100.259 +/* Boyer-Moore string search
 100.260 + * Accepts: base string
 100.261 + *	    length of base string
 100.262 + *	    pattern string
 100.263 + *	    length of pattern string
 100.264 + * Returns: T if pattern exists inside base, else NIL
 100.265 + */
 100.266 +
 100.267 +long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc)
 100.268 +{
 100.269 +  long i,j,k;
 100.270 +  int c;
 100.271 +  unsigned char mask[256];
 100.272 +				/* validate arguments */
 100.273 +  if (base && (basec > 0) && pat && (basec >= patc)) {
 100.274 +    if (patc <= 0) return T;	/* empty pattern always succeeds */
 100.275 +    memset (mask,0,256);	/* initialize search validity mask */
 100.276 +    for (i = 0; i < patc; i++) mask[pat[i]] = T;
 100.277 +				/* Boyer-Moore type search */
 100.278 +    for (i = --patc, c = pat[i]; i < basec; i += (mask[c] ? 1 : (j + 1)))
 100.279 +      for (j = patc,c = base[k = i]; (c == pat[j]); j--,c = base[--k])
 100.280 +	if (!j) return T;	/* found a match! */
 100.281 +  }
 100.282 +  return NIL;			/* pattern not found */
 100.283 +}
 100.284 +
 100.285 +/* Create a hash table
 100.286 + * Accepts: size of new table (note: should be a prime)
 100.287 + * Returns: hash table
 100.288 + */
 100.289 +
 100.290 +HASHTAB *hash_create (size_t size)
 100.291 +{
 100.292 +  size_t i = sizeof (size_t) + size * sizeof (HASHENT *);
 100.293 +  HASHTAB *ret = (HASHTAB *) memset (fs_get (i),0,i);
 100.294 +  ret->size = size;
 100.295 +  return ret;
 100.296 +}
 100.297 +
 100.298 +
 100.299 +/* Destroy hash table
 100.300 + * Accepts: hash table
 100.301 + */
 100.302 +
 100.303 +void hash_destroy (HASHTAB **hashtab)
 100.304 +{
 100.305 +  if (*hashtab) {
 100.306 +    hash_reset (*hashtab);	/* reset hash table */
 100.307 +    fs_give ((void **) hashtab);
 100.308 +  }
 100.309 +}
 100.310 +
 100.311 +
 100.312 +/* Reset hash table
 100.313 + * Accepts: hash table
 100.314 + */
 100.315 +
 100.316 +void hash_reset (HASHTAB *hashtab)
 100.317 +{
 100.318 +  size_t i;
 100.319 +  HASHENT *ent,*nxt;
 100.320 +				/* free each hash entry */
 100.321 +  for (i = 0; i < hashtab->size; i++) if (ent = hashtab->table[i])
 100.322 +    for (hashtab->table[i] = NIL; ent; ent = nxt) {
 100.323 +      nxt = ent->next;		/* get successor */
 100.324 +      fs_give ((void **) &ent);	/* flush this entry */
 100.325 +    }
 100.326 +}
 100.327 +
 100.328 +/* Calculate index into hash table
 100.329 + * Accepts: hash table
 100.330 + *	    entry name
 100.331 + * Returns: index
 100.332 + */
 100.333 +
 100.334 +unsigned long hash_index (HASHTAB *hashtab,char *key)
 100.335 +{
 100.336 +  unsigned long i,ret;
 100.337 +				/* polynomial of letters of the word */
 100.338 +  for (ret = 0; i = (unsigned int) *key++; ret += i) ret *= HASHMULT;
 100.339 +  return ret % (unsigned long) hashtab->size;
 100.340 +}
 100.341 +
 100.342 +
 100.343 +/* Look up name in hash table
 100.344 + * Accepts: hash table
 100.345 + *	    key
 100.346 + * Returns: associated data
 100.347 + */
 100.348 +
 100.349 +void **hash_lookup (HASHTAB *hashtab,char *key)
 100.350 +{
 100.351 +  HASHENT *ret;
 100.352 +  for (ret = hashtab->table[hash_index (hashtab,key)]; ret; ret = ret->next)
 100.353 +    if (!strcmp (key,ret->name)) return ret->data;
 100.354 +  return NIL;
 100.355 +}
 100.356 +
 100.357 +/* Add entry to hash table
 100.358 + * Accepts: hash table
 100.359 + *	    key
 100.360 + *	    associated data
 100.361 + *	    number of extra data slots
 100.362 + * Returns: hash entry
 100.363 + * Caller is responsible for ensuring that entry isn't already in table
 100.364 + */
 100.365 +
 100.366 +HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra)
 100.367 +{
 100.368 +  unsigned long i = hash_index (hashtab,key);
 100.369 +  size_t j = sizeof (HASHENT) + (extra * sizeof (void *));
 100.370 +  HASHENT *ret = (HASHENT *) memset (fs_get (j),0,j);
 100.371 +  ret->next = hashtab->table[i];/* insert as new head in this index */
 100.372 +  ret->name = key;		/* set up hash key */
 100.373 +  ret->data[0] = data;		/* and first data */
 100.374 +  return hashtab->table[i] = ret;
 100.375 +}
 100.376 +
 100.377 +
 100.378 +/* Look up name in hash table
 100.379 + * Accepts: hash table
 100.380 + *	    key
 100.381 + *	    associated data
 100.382 + *	    number of extra data slots
 100.383 + * Returns: associated data
 100.384 + */
 100.385 +
 100.386 +void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra)
 100.387 +{
 100.388 +  HASHENT *ret;
 100.389 +  unsigned long i = hash_index (hashtab,key);
 100.390 +  size_t j = sizeof (HASHENT) + (extra * sizeof (void *));
 100.391 +  for (ret = hashtab->table[i]; ret; ret = ret->next)
 100.392 +    if (!strcmp (key,ret->name)) return ret->data;
 100.393 +  ret = (HASHENT *) memset (fs_get (j),0,j);
 100.394 +  ret->next = hashtab->table[i];/* insert as new head in this index */
 100.395 +  ret->name = key;		/* set up hash key */
 100.396 +  ret->data[0] = data;		/* and first data */
 100.397 +  return (hashtab->table[i] = ret)->data;
 100.398 +}
 100.399 +
 100.400 +/* Convert two hex characters into byte
 100.401 + * Accepts: char for high nybble
 100.402 + *	    char for low nybble
 100.403 + * Returns: byte
 100.404 + *
 100.405 + * Arguments must be isxdigit validated
 100.406 + */
 100.407 +
 100.408 +unsigned char hex2byte (unsigned char c1,unsigned char c2)
 100.409 +{
 100.410 +				/* merge the two nybbles */
 100.411 +  return ((c1 -= (isdigit (c1) ? '0' : ((c1 <= 'Z') ? 'A' : 'a') - 10)) << 4) +
 100.412 +    (c2 - (isdigit (c2) ? '0' : ((c2 <= 'Z') ? 'A' : 'a') - 10));
 100.413 +}
 100.414 +
 100.415 +
 100.416 +/* Compare two unsigned longs
 100.417 + * Accepts: first value
 100.418 + *	    second value
 100.419 + * Returns: -1 if l1 < l2, 0 if l1 == l2, 1 if l1 > l2
 100.420 + */
 100.421 +
 100.422 +int compare_ulong (unsigned long l1,unsigned long l2)
 100.423 +{
 100.424 +  if (l1 < l2) return -1;
 100.425 +  if (l1 > l2) return 1;
 100.426 +  return 0;
 100.427 +}
 100.428 +
 100.429 +
 100.430 +/* Compare two unsigned chars, case-independent
 100.431 + * Accepts: first value
 100.432 + *	    second value
 100.433 + * Returns: -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2
 100.434 + *
 100.435 + * Don't use isupper/tolower since this function must be ASCII only.
 100.436 + */
 100.437 +
 100.438 +int compare_uchar (unsigned char c1,unsigned char c2)
 100.439 +{
 100.440 +  return compare_ulong (((c1 >= 'A') && (c1 <= 'Z')) ? c1 + ('a' - 'A') : c1,
 100.441 +			((c2 >= 'A') && (c2 <= 'Z')) ? c2 + ('a' - 'A') : c2);
 100.442 +}
 100.443 +
 100.444 +/* Compare two case-independent ASCII strings
 100.445 + * Accepts: first string
 100.446 + *	    second string
 100.447 + * Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2
 100.448 + */
 100.449 +
 100.450 +int compare_cstring (unsigned char *s1,unsigned char *s2)
 100.451 +{
 100.452 +  int i;
 100.453 +  if (!s1) return s2 ? -1 : 0;	/* empty string cases */
 100.454 +  else if (!s2) return 1;
 100.455 +  for (; *s1 && *s2; s1++,s2++) if (i = (compare_uchar (*s1,*s2))) return i;
 100.456 +  if (*s1) return 1;		/* first string is longer */
 100.457 +  return *s2 ? -1 : 0;		/* second string longer : strings identical */
 100.458 +}
 100.459 +
 100.460 +
 100.461 +/* Compare case-independent string with sized text
 100.462 + * Accepts: first string
 100.463 + *	    sized text
 100.464 + * Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2
 100.465 + */
 100.466 +
 100.467 +int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2)
 100.468 +{
 100.469 +  int i;
 100.470 +  unsigned char *s;
 100.471 +  unsigned long j;
 100.472 +  if (!s1) return s2 ? -1 : 0;	/* null string cases */
 100.473 +  else if (!s2) return 1;
 100.474 +  for (s = (char *) s2->data,j = s2->size; *s1 && j; ++s1,++s,--j)
 100.475 +    if (i = (compare_uchar (*s1,*s))) return i;
 100.476 +  if (*s1) return 1;		/* first string is longer */
 100.477 +  return j ? -1 : 0;		/* second string longer : strings identical */
 100.478 +}
   101.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   101.2 +++ b/src/c-client/misc.h	Mon Sep 14 15:17:45 2009 +0900
   101.3 @@ -0,0 +1,110 @@
   101.4 +/* ========================================================================
   101.5 + * Copyright 1988-2006 University of Washington
   101.6 + *
   101.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   101.8 + * you may not use this file except in compliance with the License.
   101.9 + * You may obtain a copy of the License at
  101.10 + *
  101.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  101.12 + *
  101.13 + * 
  101.14 + * ========================================================================
  101.15 + */
  101.16 +
  101.17 +/*
  101.18 + * Program:	Miscellaneous utility routines
  101.19 + *
  101.20 + * Author:	Mark Crispin
  101.21 + *		Networks and Distributed Computing
  101.22 + *		Computing & Communications
  101.23 + *		University of Washington
  101.24 + *		Administration Building, AG-44
  101.25 + *		Seattle, WA  98195
  101.26 + *		Internet: MRC@CAC.Washington.EDU
  101.27 + *
  101.28 + * Date:	5 July 1988
  101.29 + * Last Edited:	30 August 2006
  101.30 + *
  101.31 + * This original version of this file is
  101.32 + * Copyright 1988 Stanford University
  101.33 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  101.34 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  101.35 + * Biomedical Research Technology Program of the NationalInstitutes of Health
  101.36 + * under grant number RR-00785.
  101.37 + */
  101.38 +
  101.39 +/* Hash table operations */
  101.40 +
  101.41 +#define HASHMULT 29		/* hash polynomial multiplier */
  101.42 +
  101.43 +#define HASHENT struct hash_entry
  101.44 +
  101.45 +HASHENT {
  101.46 +  HASHENT *next;		/* next entry with same hash code */
  101.47 +  char *name;			/* name of this hash entry */
  101.48 +  void *data[1];		/* data of this hash entry */
  101.49 +};
  101.50 +
  101.51 +
  101.52 +#define HASHTAB struct hash_table
  101.53 +
  101.54 +HASHTAB {
  101.55 +  size_t size;			/* size of this table */
  101.56 +  HASHENT *table[1];		/* table */
  101.57 +};
  101.58 +
  101.59 +
  101.60 +/* KLUDGE ALERT!!!
  101.61 + *
  101.62 + * Yes, write() is overridden here instead of in osdep.  This
  101.63 + * is because misc.h is one of the last files that most things #include, so
  101.64 + * this should avoid problems with some system #include file.
  101.65 + */
  101.66 +
  101.67 +#define write safe_write
  101.68 +
  101.69 +
  101.70 +/* Some C compilers have these as macros */
  101.71 +
  101.72 +#undef min
  101.73 +#undef max
  101.74 +
  101.75 +
  101.76 +/* And some C libraries have these as int functions */
  101.77 +
  101.78 +#define min Min
  101.79 +#define max Max
  101.80 +
  101.81 +
  101.82 +/* Compatibility definitions */
  101.83 +
  101.84 +#define pmatch(s,pat) \
  101.85 +  pmatch_full (s,pat,NIL)
  101.86 +
  101.87 +/* Function prototypes */
  101.88 +
  101.89 +unsigned char *ucase (unsigned char *string);
  101.90 +unsigned char *lcase (unsigned char *string);
  101.91 +char *cpystr (const char *string);
  101.92 +char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size);
  101.93 +char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src);
  101.94 +char *textcpystring (SIZEDTEXT *text,STRING *bs);
  101.95 +char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset,
  101.96 +			unsigned long size);
  101.97 +unsigned long find_rightmost_bit (unsigned long *valptr);
  101.98 +long min (long i,long j);
  101.99 +long max (long i,long j);
 101.100 +long search (unsigned char *base,long basec,unsigned char *pat,long patc);
 101.101 +long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc);
 101.102 +HASHTAB *hash_create (size_t size);
 101.103 +void hash_destroy (HASHTAB **hashtab);
 101.104 +void hash_reset (HASHTAB *hashtab);
 101.105 +unsigned long hash_index (HASHTAB *hashtab,char *key);
 101.106 +void **hash_lookup (HASHTAB *hashtab,char *key);
 101.107 +HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra);
 101.108 +void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra);
 101.109 +unsigned char hex2byte (unsigned char c1,unsigned char c2);
 101.110 +int compare_ulong (unsigned long l1,unsigned long l2);
 101.111 +int compare_uchar (unsigned char c1,unsigned char c2);
 101.112 +int compare_cstring (unsigned char *s1,unsigned char *s2);
 101.113 +int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2);
   102.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   102.2 +++ b/src/c-client/netmsg.c	Mon Sep 14 15:17:45 2009 +0900
   102.3 @@ -0,0 +1,104 @@
   102.4 +/* ========================================================================
   102.5 + * Copyright 1988-2006 University of Washington
   102.6 + *
   102.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   102.8 + * you may not use this file except in compliance with the License.
   102.9 + * You may obtain a copy of the License at
  102.10 + *
  102.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  102.12 + *
  102.13 + * 
  102.14 + * ========================================================================
  102.15 + */
  102.16 +
  102.17 +/*
  102.18 + * Program:	Network message (SMTP/NNTP/POP2/POP3) routines
  102.19 + *
  102.20 + * Author:	Mark Crispin
  102.21 + *		Networks and Distributed Computing
  102.22 + *		Computing & Communications
  102.23 + *		University of Washington
  102.24 + *		Administration Building, AG-44
  102.25 + *		Seattle, WA  98195
  102.26 + *		Internet: MRC@CAC.Washington.EDU
  102.27 + *
  102.28 + * Date:	8 June 1995
  102.29 + * Last Edited:	6 December 2006
  102.30 + */
  102.31 +
  102.32 +
  102.33 +#include <stdio.h>
  102.34 +#include <errno.h>
  102.35 +extern int errno;		/* just in case */
  102.36 +#include "c-client.h"
  102.37 +#include "netmsg.h"
  102.38 +#include "flstring.h"
  102.39 +
  102.40 +/* Network message read
  102.41 + * Accepts: file
  102.42 + *	    number of bytes to read
  102.43 + *	    buffer address
  102.44 + * Returns: T if success, NIL otherwise
  102.45 + */
  102.46 +
  102.47 +long netmsg_read (void *stream,unsigned long count,char *buffer)
  102.48 +{
  102.49 +  return (fread (buffer,(size_t) 1,(size_t) count,(FILE *) stream) == count) ?
  102.50 +    T : NIL;
  102.51 +}
  102.52 +
  102.53 +/* Slurp dot-terminated text from NET
  102.54 + * Accepts: NET stream
  102.55 + *	    place to return size
  102.56 + *	    place to return header size
  102.57 + * Returns: file descriptor
  102.58 + */
  102.59 +
  102.60 +FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz)
  102.61 +{
  102.62 +  unsigned long i;
  102.63 +  char *s,*t,tmp[MAILTMPLEN];
  102.64 +  FILE *f = tmpfile ();
  102.65 +  if (!f) {
  102.66 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
  102.67 +    if (f = fopen (tmp,"wb+")) unlink (tmp);
  102.68 +    else {
  102.69 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
  102.70 +      MM_LOG (tmp,ERROR);
  102.71 +      return NIL;
  102.72 +    }
  102.73 +  }
  102.74 +  *size = 0;			/* initially emtpy */
  102.75 +  if (hsiz) *hsiz = 0;
  102.76 +  while (s = net_getline (stream)) {
  102.77 +    if (*s == '.') {		/* possible end of text? */
  102.78 +      if (s[1]) t = s + 1;	/* pointer to true start of line */
  102.79 +      else {
  102.80 +	fs_give ((void **) &s);	/* free the line */
  102.81 +	break;			/* end of data */
  102.82 +      }
  102.83 +    }
  102.84 +    else t = s;			/* want the entire line */
  102.85 +    if (f) {			/* copy it to the file */
  102.86 +      i = strlen (t);		/* size of line */
  102.87 +      if ((fwrite (t,(size_t) 1,(size_t) i,f) == i) &&
  102.88 +	  (fwrite ("\015\012",(size_t) 1,(size_t) 2,f) == 2)) {
  102.89 +	*size += i + 2;		/* tally up size of data */
  102.90 +				/* note header position */
  102.91 +	if (!i && hsiz && !*hsiz) *hsiz = *size;
  102.92 +      }
  102.93 +      else {
  102.94 +	sprintf (tmp,"Error writing scratch file at byte %lu",*size);
  102.95 +	MM_LOG (tmp,ERROR);
  102.96 +	fclose (f);		/* forget it */
  102.97 +	f = NIL;		/* failure now */
  102.98 +      }
  102.99 +    }
 102.100 +    fs_give ((void **) &s);	/* free the line */
 102.101 +  }
 102.102 +				/* if making a file, rewind to start of file */
 102.103 +  if (f) fseek (f,(unsigned long) 0,SEEK_SET);
 102.104 +				/* header consumes entire message */
 102.105 +  if (hsiz && !*hsiz) *hsiz = *size;
 102.106 +  return f;			/* return the file descriptor */
 102.107 +}
   103.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.2 +++ b/src/c-client/netmsg.h	Mon Sep 14 15:17:45 2009 +0900
   103.3 @@ -0,0 +1,32 @@
   103.4 +/* ========================================================================
   103.5 + * Copyright 1988-2006 University of Washington
   103.6 + *
   103.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   103.8 + * you may not use this file except in compliance with the License.
   103.9 + * You may obtain a copy of the License at
  103.10 + *
  103.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  103.12 + *
  103.13 + * 
  103.14 + * ========================================================================
  103.15 + */
  103.16 +
  103.17 +/*
  103.18 + * Program:	Network message (SMTP/NNTP/POP2/POP3) routines
  103.19 + *
  103.20 + * Author:	Mark Crispin
  103.21 + *		Networks and Distributed Computing
  103.22 + *		Computing & Communications
  103.23 + *		University of Washington
  103.24 + *		Administration Building, AG-44
  103.25 + *		Seattle, WA  98195
  103.26 + *		Internet: MRC@CAC.Washington.EDU
  103.27 + *
  103.28 + * Date:	8 June 1995
  103.29 + * Last Edited:	30 August 2006
  103.30 + */
  103.31 +
  103.32 +
  103.33 +				/* stream must be void* for use as readfn_t */
  103.34 +long netmsg_read (void *stream,unsigned long count,char *buffer);
  103.35 +FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz);
   104.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.2 +++ b/src/c-client/newsrc.c	Mon Sep 14 15:17:45 2009 +0900
   104.3 @@ -0,0 +1,510 @@
   104.4 +/* ========================================================================
   104.5 + * Copyright 1988-2006 University of Washington
   104.6 + *
   104.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   104.8 + * you may not use this file except in compliance with the License.
   104.9 + * You may obtain a copy of the License at
  104.10 + *
  104.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  104.12 + *
  104.13 + * 
  104.14 + * ========================================================================
  104.15 + */
  104.16 +
  104.17 +/*
  104.18 + * Program:	Newsrc manipulation routines
  104.19 + *
  104.20 + * Author:	Mark Crispin
  104.21 + *		Networks and Distributed Computing
  104.22 + *		Computing & Communications
  104.23 + *		University of Washington
  104.24 + *		Administration Building, AG-44
  104.25 + *		Seattle, WA  98195
  104.26 + *		Internet: MRC@CAC.Washington.EDU
  104.27 + *
  104.28 + * Date:	12 September 1994
  104.29 + * Last Edited:	30 August 2006
  104.30 + */
  104.31 +
  104.32 +
  104.33 +#include <ctype.h>
  104.34 +#include <stdio.h>
  104.35 +#include "c-client.h"
  104.36 +#include "newsrc.h"
  104.37 +
  104.38 +#ifndef OLDFILESUFFIX
  104.39 +#define OLDFILESUFFIX ".old"
  104.40 +#endif
  104.41 +
  104.42 +/* Error message
  104.43 + * Accepts: message format
  104.44 + *	    additional message string
  104.45 + *	    message level
  104.46 + * Returns: NIL, always
  104.47 + */
  104.48 +
  104.49 +long newsrc_error (char *fmt,char *text,long errflg)
  104.50 +{
  104.51 +  char tmp[MAILTMPLEN];
  104.52 +  sprintf (tmp,fmt,text);
  104.53 +  MM_LOG (tmp,errflg);
  104.54 +  return NIL;
  104.55 +}
  104.56 +
  104.57 +
  104.58 +/* Write error message
  104.59 + * Accepts: newsrc name
  104.60 + *	    file designator
  104.61 + *	    file designator
  104.62 + * Returns: NIL, always
  104.63 + */
  104.64 +
  104.65 +long newsrc_write_error (char *name,FILE *f1,FILE *f2)
  104.66 +{
  104.67 +  if (f1) fclose (f1);		/* close file designators */
  104.68 +  if (f2) fclose (f2);
  104.69 +  return newsrc_error ("Error writing to %.80s",name,ERROR);
  104.70 +}
  104.71 +
  104.72 +
  104.73 +/* Create newsrc file in local form
  104.74 + * Accepts: MAIL stream
  104.75 + *	    notification flag
  104.76 + * Returns: file designator of newsrc
  104.77 + */
  104.78 +
  104.79 +FILE *newsrc_create (MAILSTREAM *stream,int notify)
  104.80 +{
  104.81 +  char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
  104.82 +  FILE *f = fopen (newsrc,"wb");
  104.83 +  if (!f) newsrc_error ("Unable to create news state %.80s",newsrc,ERROR);
  104.84 +  else if (notify) newsrc_error ("Creating news state %.80s",newsrc,WARN);
  104.85 +  return f;
  104.86 +}
  104.87 +
  104.88 +/* Write new state in newsrc
  104.89 + * Accepts: file designator of newsrc
  104.90 + *	    group
  104.91 + *	    new subscription status character
  104.92 + *	    newline convention
  104.93 + * Returns: T if successful, NIL otherwise
  104.94 + */
  104.95 +
  104.96 +long newsrc_newstate (FILE *f,char *group,char state,char *nl)
  104.97 +{
  104.98 +  long ret = (f && (fputs (group,f) != EOF) && ((putc (state,f)) != EOF) &&
  104.99 +	      ((putc (' ',f)) != EOF) && (fputs (nl,f) != EOF)) ? LONGT : NIL;
 104.100 +  if (fclose (f) == EOF) ret = NIL;
 104.101 +  return ret;
 104.102 +}
 104.103 +
 104.104 +
 104.105 +/* Write messages in newsrc
 104.106 + * Accepts: file designator of newsrc
 104.107 + *	    MAIL stream
 104.108 + *	    message number/newsgroup message map
 104.109 + *	    newline convention
 104.110 + * Returns: T if successful, NIL otherwise
 104.111 + */
 104.112 +
 104.113 +long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl)
 104.114 +{
 104.115 +  unsigned long i,j,k;
 104.116 +  char tmp[MAILTMPLEN];
 104.117 +  MESSAGECACHE *elt;
 104.118 +  int c = ' ';
 104.119 +  if (stream->nmsgs) {		/* have any messages? */
 104.120 +    for (i = 1,j = k = (mail_elt (stream,i)->private.uid > 1) ? 1 : 0;
 104.121 +	 i <= stream->nmsgs; ++i) {
 104.122 +				/* deleted message? */
 104.123 +      if ((elt = mail_elt (stream,i))->deleted) {
 104.124 +	k = elt->private.uid;	/* this is the top of the current range */
 104.125 +	if (!j) j = k;		/* if no range in progress, start one */
 104.126 +      }
 104.127 +      else if (j) {		/* unread message, ending a range */
 104.128 +				/* calculate end of range */
 104.129 +	if (k = elt->private.uid - 1) {
 104.130 +				/* dump range */
 104.131 +	  sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k);
 104.132 +	  if (fputs (tmp,f) == EOF) return NIL;
 104.133 +	  c = ',';		/* need a comma after the first time */
 104.134 +	}
 104.135 +	j = 0;			/* no more range in progress */
 104.136 +      }
 104.137 +    }
 104.138 +    if (j) {			/* dump trailing range */
 104.139 +      sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k);
 104.140 +      if (fputs (tmp,f) == EOF) return NIL;
 104.141 +    }
 104.142 +  }
 104.143 +				/* write trailing newline, return */
 104.144 +  return (fputs (nl,f) == EOF) ? NIL : LONGT;
 104.145 +}
 104.146 +
 104.147 +/* List subscribed newsgroups
 104.148 + * Accepts: MAIL stream
 104.149 + *	    prefix to append name
 104.150 + * 	    pattern to search
 104.151 + */
 104.152 +
 104.153 +void newsrc_lsub (MAILSTREAM *stream,char *pattern)
 104.154 +{
 104.155 +  char *s,*t,*lcl,name[MAILTMPLEN];
 104.156 +  int c = ' ';
 104.157 +  int showuppers = pattern[strlen (pattern) - 1] == '%';
 104.158 +  FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
 104.159 +  if (f) {			/* got file? */
 104.160 +				/* remote name? */
 104.161 +    if (*(lcl = strcpy (name,pattern)) == '{') lcl = strchr (lcl,'}') + 1;
 104.162 +    if (*lcl == '#') lcl += 6;	/* namespace format name? */
 104.163 +    while (c != EOF) {		/* yes, read newsrc */
 104.164 +      for (s = lcl; (s < (name + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
 104.165 +	   (c != ':') && (c != '!') && (c != '\015') && (c != '\012');
 104.166 +	   *s++ = c);
 104.167 +      if (c == ':') {		/* found a subscribed newsgroup? */
 104.168 +	*s = '\0';		/* yes, tie off name */
 104.169 +				/* report if match */
 104.170 +	if (pmatch_full (name,pattern,'.')) mm_lsub (stream,'.',name,NIL);
 104.171 +	else while (showuppers && (t = strrchr (lcl,'.'))) {
 104.172 +	  *t = '\0';		/* tie off the name */
 104.173 +	  if (pmatch_full (name,pattern,'.'))
 104.174 +	    mm_lsub (stream,'.',name,LATT_NOSELECT);
 104.175 +	}
 104.176 +      }
 104.177 +      while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
 104.178 +    }
 104.179 +    fclose (f);
 104.180 +  }
 104.181 +}
 104.182 +
 104.183 +/* Update subscription status of newsrc
 104.184 + * Accepts: MAIL stream
 104.185 + * 	    group
 104.186 + *	    new subscription status character
 104.187 + * Returns: T if successful, NIL otherwise
 104.188 + */
 104.189 +
 104.190 +long newsrc_update (MAILSTREAM *stream,char *group,char state)
 104.191 +{
 104.192 +  char tmp[MAILTMPLEN];
 104.193 +  char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
 104.194 +  long ret = NIL;
 104.195 +  FILE *f = fopen (newsrc,"r+b");
 104.196 +  if (f) {			/* update existing file */
 104.197 +    int c = 0;
 104.198 +    char *s,nl[3];
 104.199 +    long pos = 0;
 104.200 +    nl[0] = nl[1] = nl[2]='\0';	/* no newline known yet */
 104.201 +    do {			/* read newsrc */
 104.202 +      for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
 104.203 +	   (c != ':') && (c != '!') && (c != '\015') && (c != '\012');
 104.204 +	   *s++ = c) pos = ftell (f);
 104.205 +      *s = '\0';		/* tie off name */
 104.206 +				/* found the newsgroup? */
 104.207 +      if (((c == ':') || (c == '!')) && !strcmp (tmp,group)) {
 104.208 +	if (c == state) {	/* already at that state? */
 104.209 +	  if (c == ':') newsrc_error("Already subscribed to %.80s",group,WARN);
 104.210 +	  ret = LONGT;		/* noop the update */
 104.211 +	}
 104.212 +				/* write the character */
 104.213 +	else if (!fseek (f,pos,0)) ret = ((putc (state,f)) == EOF) ? NIL:LONGT;
 104.214 +	if (fclose (f) == EOF) ret = NIL;
 104.215 +	f = NIL;		/* done with file */
 104.216 +	break;
 104.217 +      }
 104.218 +				/* gobble remainder of this line */
 104.219 +      while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
 104.220 +				/* need to know about newlines and found it? */
 104.221 +      if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){
 104.222 +				/* sniff and see if an LF */
 104.223 +	if ((c = getc (f)) == '\012') nl[1] = c;
 104.224 +	else ungetc (c,f);	/* nope, push it back */
 104.225 +      }
 104.226 +    } while (c != EOF);
 104.227 +
 104.228 +    if (f) {			/* still haven't written it yet? */
 104.229 +      if (nl[0]) {		/* know its newline convention? */
 104.230 +	fseek (f,0L,2);		/* yes, seek to end of file */
 104.231 +	ret = newsrc_newstate (f,group,state,nl);
 104.232 +      }
 104.233 +      else {			/* can't find a newline convention */
 104.234 +	fclose (f);		/* punt the file */
 104.235 +				/* can't win if read something */
 104.236 +	if (pos) newsrc_error ("Unknown newline convention in %.80s",
 104.237 +			       newsrc,ERROR);
 104.238 +				/* file must have been empty, rewrite it */
 104.239 +	else ret = newsrc_newstate(newsrc_create(stream,NIL),group,state,"\n");
 104.240 +      }
 104.241 +    }
 104.242 +  }
 104.243 +				/* create new file */
 104.244 +  else ret = newsrc_newstate (newsrc_create (stream,T),group,state,"\n");
 104.245 +  return ret;			/* return with update status */
 104.246 +}
 104.247 +
 104.248 +/* Update newsgroup status in stream
 104.249 + * Accepts: newsgroup name
 104.250 + *	    MAIL stream
 104.251 + * Returns: number of recent messages
 104.252 + */
 104.253 +
 104.254 +long newsrc_read (char *group,MAILSTREAM *stream)
 104.255 +{
 104.256 +  int c = 0;
 104.257 +  char *s,tmp[MAILTMPLEN];
 104.258 +  unsigned long i,j;
 104.259 +  MESSAGECACHE *elt;
 104.260 +  unsigned long m = 1,recent = 0,unseen = 0;
 104.261 +  FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
 104.262 +  if (f) do {			/* read newsrc */
 104.263 +    for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
 104.264 +	 (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
 104.265 +    *s = '\0';			/* tie off name */
 104.266 +    if ((c==':') || (c=='!')) {	/* found newsgroup? */
 104.267 +      if (strcmp (tmp,group))	/* group name match? */
 104.268 +	while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
 104.269 +      else {			/* yes, skip leading whitespace */
 104.270 +	while ((c = getc (f)) == ' ');
 104.271 +				/* only if unprocessed messages */
 104.272 +	if (stream->nmsgs) while (f && (m <= stream->nmsgs)) {
 104.273 +				/* collect a number */
 104.274 +	  if (isdigit (c)) {	/* better have a number */
 104.275 +	    for (i = 0,j = 0; isdigit (c); c = getc (f)) i = i*10 + (c-'0');
 104.276 +	    if (c == '-') for (c = getc (f); isdigit (c); c = getc (f))
 104.277 +	      j = j*10 +(c-'0');/* collect second value if range */
 104.278 +	    if (!unseen && (mail_elt (stream,m)->private.uid < i)) unseen = m;
 104.279 +				/* skip messages before first value */
 104.280 +	    while ((m <= stream->nmsgs) &&
 104.281 +		   ((elt = mail_elt (stream,m))->private.uid < i) && m++)
 104.282 +	      elt->valid = T;
 104.283 +				/* do all messages in range */
 104.284 +	    while ((m <= stream->nmsgs) && (elt = mail_elt (stream,m)) &&
 104.285 +		   (j ? ((elt->private.uid >= i) && (elt->private.uid <= j)) :
 104.286 +		    (elt->private.uid == i)) && m++)
 104.287 +	      elt->valid = elt->deleted = T;
 104.288 +	  }
 104.289 +
 104.290 +	  switch (c) {		/* what is the delimiter? */
 104.291 +	  case ',':		/* more to come */
 104.292 +	    c = getc (f);	/* get first character of number */
 104.293 +	    break;
 104.294 +	  default:		/* bogus character */
 104.295 +	    sprintf (tmp,"Bogus character 0x%x in news state",(unsigned int)c);
 104.296 +	    MM_LOG (tmp,ERROR);
 104.297 +	  case EOF: case '\015': case '\012':
 104.298 +	    fclose (f);		/* all done - close the file */
 104.299 +	    f = NIL;
 104.300 +	    break;
 104.301 +	  }
 104.302 +	}
 104.303 +	else {			/* empty newsgroup */
 104.304 +	  while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
 104.305 +	  fclose (f);		/* all done - close the file */
 104.306 +	  f = NIL;
 104.307 +	}
 104.308 +      }
 104.309 +    }
 104.310 +  } while (f && (c != EOF));	/* until file closed or EOF */
 104.311 +  if (f) {			/* still have file open? */
 104.312 +    sprintf (tmp,"No state for newsgroup %.80s found, reading as new",group);
 104.313 +    MM_LOG (tmp,WARN);
 104.314 +    fclose (f);			/* close the file */
 104.315 +  }
 104.316 +  if (m <= stream->nmsgs) {	/* any messages beyond newsrc range? */
 104.317 +    if (!unseen) unseen = m;	/* then this must be the first unseen one */
 104.318 +    do {
 104.319 +      elt = mail_elt (stream,m++);
 104.320 +      elt->valid = elt->recent = T;
 104.321 +      ++recent;			/* count another recent message */
 104.322 +    }
 104.323 +    while (m <= stream->nmsgs);
 104.324 +  }
 104.325 +  if (unseen) {			/* report first unseen message */
 104.326 +    sprintf (tmp,"[UNSEEN] %lu is first unseen message in %.80s",unseen,group);
 104.327 +    MM_NOTIFY (stream,tmp,(long) NIL);
 104.328 +  }
 104.329 +  return recent;
 104.330 +}
 104.331 +
 104.332 +/* Update newsgroup entry in newsrc
 104.333 + * Accepts: newsgroup name
 104.334 + *	    MAIL stream
 104.335 + * Returns: T if successful, NIL otherwise
 104.336 + */
 104.337 +
 104.338 +long newsrc_write (char *group,MAILSTREAM *stream)
 104.339 +{
 104.340 +  long ret = NIL;
 104.341 +  int c = 0,d = EOF;
 104.342 +  char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
 104.343 +  char *s,tmp[MAILTMPLEN],backup[MAILTMPLEN],nl[3];
 104.344 +  FILE *f,*bf;
 104.345 +  nl[0] = nl[1] = nl[2] = '\0';	/* no newline known yet */
 104.346 +  if (f = fopen (newsrc,"rb")) {/* have existing newsrc file? */
 104.347 +    if (!(bf = fopen ((strcat (strcpy (backup,newsrc),OLDFILESUFFIX)),"wb"))) {
 104.348 +      fclose (f);		/* punt input file */
 104.349 +      return newsrc_error("Can't create backup news state %.80s",backup,ERROR);
 104.350 +    }
 104.351 +				/* copy to backup file */
 104.352 +    while ((c = getc (f)) != EOF) {
 104.353 +				/* need to know about newlines and found it? */
 104.354 +      if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){
 104.355 +				/* sniff and see if an LF */
 104.356 +	if ((c = getc (f)) == '\012') nl[1] = c;
 104.357 +	ungetc (c,f);		/* push it back */
 104.358 +      }
 104.359 +				/* write to backup file */
 104.360 +      if ((d = putc (c,bf)) == EOF) {
 104.361 +	fclose (f);		/* punt input file */
 104.362 +	return newsrc_error ("Error writing backup news state %.80s",
 104.363 +			     newsrc,ERROR);
 104.364 +      }
 104.365 +    }
 104.366 +    fclose (f);			/* close existing file */
 104.367 +    if (fclose (bf) == EOF)	/* and backup file */
 104.368 +      return newsrc_error ("Error closing backup news state %.80s",
 104.369 +			   newsrc,ERROR);
 104.370 +    if (d == EOF) {		/* open for write if empty file */
 104.371 +      if (f = newsrc_create (stream,NIL)) bf = NIL;
 104.372 +      else return NIL;
 104.373 +    }
 104.374 +    else if (!nl[0])		/* make sure newlines valid */
 104.375 +      return newsrc_error ("Unknown newline convention in %.80s",newsrc,ERROR);
 104.376 +				/* now read backup file */
 104.377 +    else if (!(bf = fopen (backup,"rb")))
 104.378 +      return newsrc_error ("Error reading backup news state %.80s",
 104.379 +			   backup,ERROR);
 104.380 +				/* open newsrc for writing */
 104.381 +    else if (!(f = fopen (newsrc,"wb"))) {
 104.382 +      fclose (bf);		/* punt backup */
 104.383 +      return newsrc_error ("Can't rewrite news state %.80s",newsrc,ERROR);
 104.384 +    }
 104.385 +  }
 104.386 +  else {			/* create new newsrc file */
 104.387 +    if (f = newsrc_create (stream,T)) bf = NIL;
 104.388 +    else return NIL;		/* can't create newsrc */
 104.389 +  }
 104.390 +  
 104.391 +  while (bf) {			/* read newsrc */
 104.392 +    for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (bf)) != EOF) &&
 104.393 +	 (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
 104.394 +    *s = '\0';			/* tie off name */
 104.395 +				/* saw correct end of group delimiter? */
 104.396 +    if (tmp[0] && ((c == ':') || (c == '!'))) {
 104.397 +				/* yes, write newsgroup name and delimiter */
 104.398 +      if ((tmp[0] && (fputs (tmp,f) == EOF)) || ((putc (c,f)) == EOF))
 104.399 +	return newsrc_write_error (newsrc,bf,f);
 104.400 +      if (!strcmp (tmp,group)) {/* found correct group? */
 104.401 +				/* yes, write new status */
 104.402 +	if (!newsrc_newmessages (f,stream,nl[0] ? nl : "\n"))
 104.403 +	  return newsrc_write_error (newsrc,bf,f);
 104.404 +				/* skip past old data */
 104.405 +	while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012'));
 104.406 +				/* skip past newline */
 104.407 +	while ((c == '\015') || (c == '\012')) c = getc (bf);
 104.408 +	while (c != EOF) {	/* copy remainder of file */
 104.409 +	  if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
 104.410 +	  c = getc (bf);	/* get next character */
 104.411 +	}
 104.412 +				/* done with file */
 104.413 +	if (fclose (f) == EOF) return newsrc_write_error (newsrc,bf,NIL);
 104.414 +	f = NIL;
 104.415 +      }
 104.416 +				/* copy remainder of line */
 104.417 +      else while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012'))
 104.418 +	if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
 104.419 +      if (c == '\015') {	/* write CR if seen */
 104.420 +	if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
 104.421 +				/* sniff to see if LF */
 104.422 +	if (((c = getc (bf)) != EOF) && (c != '\012')) ungetc (c,bf);
 104.423 +      }
 104.424 +				/* write LF if seen */
 104.425 +      if ((c == '\012') && (putc (c,f) == EOF))
 104.426 +	return newsrc_write_error (newsrc,bf,f);
 104.427 +    }
 104.428 +    if (c == EOF) {		/* hit end of file? */
 104.429 +      fclose (bf);		/* yup, close the file */
 104.430 +      bf = NIL;
 104.431 +    }
 104.432 +  }
 104.433 +  if (f) {			/* still have newsrc file open? */
 104.434 +    ret = ((fputs (group,f) != EOF) && ((putc (':',f)) != EOF) &&
 104.435 +	   newsrc_newmessages (f,stream,nl[0] ? nl : "\n")) ? LONGT : NIL;
 104.436 +    if (fclose (f) == EOF) ret = newsrc_write_error (newsrc,NIL,NIL);
 104.437 +  }
 104.438 +  else ret = LONGT;
 104.439 +  return ret;
 104.440 +}
 104.441 +
 104.442 +/* Get newsgroup state as text stream
 104.443 + * Accepts: MAIL stream
 104.444 + *	    newsgroup name
 104.445 + * Returns: string containing newsgroup state, or NIL if not found
 104.446 + */
 104.447 +
 104.448 +char *newsrc_state (MAILSTREAM *stream,char *group)
 104.449 +{
 104.450 +  int c = 0;
 104.451 +  char *s,tmp[MAILTMPLEN];
 104.452 +  long pos;
 104.453 +  size_t size;
 104.454 +  FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
 104.455 +  if (f) do {			/* read newsrc */
 104.456 +    for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
 104.457 +	 (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
 104.458 +    *s = '\0';			/* tie off name */
 104.459 +    if ((c==':') || (c=='!')) {	/* found newsgroup? */
 104.460 +      if (strcmp (tmp,group))	/* group name match? */
 104.461 +	while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
 104.462 +      else {			/* yes, skip leading whitespace */
 104.463 +	do pos = ftell (f);
 104.464 +	while ((c = getc (f)) == ' ');
 104.465 +				/* count characters in state */
 104.466 +	for (size = 0; (c != '\015') && (c != '\012') && (c != EOF); size++)
 104.467 +	  c = getc (f);
 104.468 +				/* now copy it */
 104.469 +	s = (char *) fs_get (size + 1);
 104.470 +	fseek (f,pos,SEEK_SET);
 104.471 +	fread (s,(size_t) 1,size,f);
 104.472 +	s[size] = '\0';		/* tie off string */
 104.473 +	fclose (f);		/* all done - close the file */
 104.474 +	return s;
 104.475 +      }
 104.476 +    }
 104.477 +  } while (f && (c != EOF));	/* until file closed or EOF */
 104.478 +  sprintf (tmp,"No state for newsgroup %.80s found",group);
 104.479 +  MM_LOG (tmp,WARN);
 104.480 +  if (f) fclose (f);		/* close the file */
 104.481 +  return NIL;			/* not found return */
 104.482 +}
 104.483 +
 104.484 +/* Check UID in newsgroup state
 104.485 + * Accepts: newsgroup state string
 104.486 + *	    uid
 104.487 + *	    returned recent count
 104.488 + *	    returned unseen count
 104.489 + */
 104.490 +
 104.491 +void newsrc_check_uid (unsigned char *state,unsigned long uid,
 104.492 +		       unsigned long *recent,unsigned long *unseen)
 104.493 +{
 104.494 +  unsigned long i,j;
 104.495 +  while (*state) {		/* until run out of state string */
 104.496 +				/* collect a number */
 104.497 +    for (i = 0; isdigit (*state); i = i*10 + (*state++ - '0'));
 104.498 +    if (*state != '-') j = i;	/* coerce single mesage into range */
 104.499 +    else {			/* have a range */
 104.500 +      for (j = 0; isdigit (*++state); j = j*10 + (*state - '0'));
 104.501 +      if (!j) j = i;		/* guard against -0 */
 104.502 +      if (j < i) return;	/* bogon if end less than start */
 104.503 +    }
 104.504 +    if (*state == ',') state++;	/* skip past comma */
 104.505 +    else if (*state) return;	/* otherwise it's a bogon */
 104.506 +    if (uid <= j) {		/* covered by upper bound? */
 104.507 +      if (uid < i) ++*unseen;	/* unseen if not covered by lower bound */
 104.508 +      return;			/* don't need to look further */
 104.509 +    }
 104.510 +  }
 104.511 +  ++*unseen;			/* not found in any range, message is unseen */
 104.512 +  ++*recent;			/* and recent */
 104.513 +}
   105.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   105.2 +++ b/src/c-client/newsrc.h	Mon Sep 14 15:17:45 2009 +0900
   105.3 @@ -0,0 +1,43 @@
   105.4 +/* ========================================================================
   105.5 + * Copyright 1988-2006 University of Washington
   105.6 + *
   105.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   105.8 + * you may not use this file except in compliance with the License.
   105.9 + * You may obtain a copy of the License at
  105.10 + *
  105.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  105.12 + *
  105.13 + * 
  105.14 + * ========================================================================
  105.15 + */
  105.16 +
  105.17 +/*
  105.18 + * Program:	Newsrc manipulation routines
  105.19 + *
  105.20 + * Author:	Mark Crispin
  105.21 + *		Networks and Distributed Computing
  105.22 + *		Computing & Communications
  105.23 + *		University of Washington
  105.24 + *		Administration Building, AG-44
  105.25 + *		Seattle, WA  98195
  105.26 + *		Internet: MRC@CAC.Washington.EDU
  105.27 + *
  105.28 + * Date:	12 September 1994
  105.29 + * Last Edited:	30 August 2006
  105.30 + */
  105.31 +
  105.32 +
  105.33 +/* Function prototypes */
  105.34 +
  105.35 +long newsrc_error (char *fmt,char *text,long errflg);
  105.36 +long newsrc_write_error (char *name,FILE *f1,FILE *f2);
  105.37 +FILE *newsrc_create (MAILSTREAM *stream,int notify);
  105.38 +long newsrc_newstate (FILE *f,char *group,char state,char *nl);
  105.39 +long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl);
  105.40 +void newsrc_lsub (MAILSTREAM *stream,char *pattern);
  105.41 +long newsrc_update (MAILSTREAM *stream,char *group,char state);
  105.42 +long newsrc_read (char *group,MAILSTREAM *stream);
  105.43 +long newsrc_write (char *group,MAILSTREAM *stream);
  105.44 +char *newsrc_state (MAILSTREAM *stream,char *group);
  105.45 +void newsrc_check_uid (unsigned char *state,unsigned long uid,
  105.46 +		       unsigned long *recent,unsigned long *unseen);
   106.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.2 +++ b/src/c-client/nl.h	Mon Sep 14 15:17:45 2009 +0900
   106.3 @@ -0,0 +1,34 @@
   106.4 +/* ========================================================================
   106.5 + * Copyright 1988-2006 University of Washington
   106.6 + *
   106.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   106.8 + * you may not use this file except in compliance with the License.
   106.9 + * You may obtain a copy of the License at
  106.10 + *
  106.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  106.12 + *
  106.13 + * 
  106.14 + * ========================================================================
  106.15 + */
  106.16 +
  106.17 +/*
  106.18 + * Program:	Newline routines
  106.19 + *
  106.20 + * Author:	Mark Crispin
  106.21 + *		Networks and Distributed Computing
  106.22 + *		Computing & Communications
  106.23 + *		University of Washington
  106.24 + *		Administration Building, AG-44
  106.25 + *		Seattle, WA  98195
  106.26 + *		Internet: MRC@CAC.Washington.EDU
  106.27 + *
  106.28 + * Date:	1 August 1988
  106.29 + * Last Edited:	30 August 2006
  106.30 + */
  106.31 +
  106.32 +
  106.33 +/* Function prototypes */
  106.34 +
  106.35 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  106.36 +			  unsigned char *src,unsigned long srcl);
  106.37 +unsigned long strcrlflen (STRING *s);
   107.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.2 +++ b/src/c-client/nntp.c	Mon Sep 14 15:17:45 2009 +0900
   107.3 @@ -0,0 +1,2224 @@
   107.4 +/* ========================================================================
   107.5 + * Copyright 1988-2007 University of Washington
   107.6 + *
   107.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   107.8 + * you may not use this file except in compliance with the License.
   107.9 + * You may obtain a copy of the License at
  107.10 + *
  107.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  107.12 + *
  107.13 + * 
  107.14 + * ========================================================================
  107.15 + */
  107.16 +
  107.17 +/*
  107.18 + * Program:	Network News Transfer Protocol (NNTP) routines
  107.19 + *
  107.20 + * Author:	Mark Crispin
  107.21 + *		Networks and Distributed Computing
  107.22 + *		Computing & Communications
  107.23 + *		University of Washington
  107.24 + *		Administration Building, AG-44
  107.25 + *		Seattle, WA  98195
  107.26 + *		Internet: MRC@CAC.Washington.EDU
  107.27 + *
  107.28 + * Date:	10 February 1992
  107.29 + * Last Edited:	6 September 2007
  107.30 + */
  107.31 +
  107.32 +
  107.33 +#include <ctype.h>
  107.34 +#include <stdio.h>
  107.35 +#include "c-client.h"
  107.36 +#include "newsrc.h"
  107.37 +#include "netmsg.h"
  107.38 +#include "flstring.h"
  107.39 +
  107.40 +/* Constants */
  107.41 +
  107.42 +#define NNTPSSLPORT (long) 563	/* assigned SSL TCP contact port */
  107.43 +#define NNTPGREET (long) 200	/* NNTP successful greeting */
  107.44 +				/* NNTP successful greeting w/o posting priv */
  107.45 +#define NNTPGREETNOPOST (long) 201
  107.46 +#define NNTPEXTOK (long) 202	/* NNTP extensions OK */
  107.47 +#define NNTPGOK (long) 211	/* NNTP group selection OK */
  107.48 +#define NNTPGLIST (long) 215	/* NNTP group list being returned */
  107.49 +#define NNTPARTICLE (long) 220	/* NNTP article file */
  107.50 +#define NNTPHEAD (long) 221	/* NNTP header text */
  107.51 +#define NNTPBODY (long) 222	/* NNTP body text */
  107.52 +#define NNTPOVER (long) 224	/* NNTP overview text */
  107.53 +#define NNTPOK (long) 240	/* NNTP OK code */
  107.54 +#define NNTPAUTHED (long) 281	/* NNTP successful authentication */
  107.55 +				/* NNTP successful authentication with data */
  107.56 +#define NNTPAUTHEDDATA (long) 282
  107.57 +#define NNTPREADY (long) 340	/* NNTP ready for data */
  107.58 +#define NNTPWANTAUTH2 (long) 380/* NNTP authentication needed (old) */
  107.59 +#define NNTPWANTPASS (long) 381	/* NNTP password needed */
  107.60 +#define NNTPTLSSTART (long) 382	/* NNTP continue with TLS negotiation */
  107.61 +#define NNTPCHALLENGE (long) 383/* NNTP challenge, want response */
  107.62 +#define NNTPSOFTFATAL (long) 400/* NNTP soft fatal code */
  107.63 +#define NNTPWANTAUTH (long) 480	/* NNTP authentication needed */
  107.64 +#define NNTPBADCMD (long) 500	/* NNTP unrecognized command */
  107.65 +#define IDLETIMEOUT (long) 3	/* defined in NNTPEXT WG base draft */
  107.66 +
  107.67 +
  107.68 +/* NNTP I/O stream local data */
  107.69 +	
  107.70 +typedef struct nntp_local {
  107.71 +  SENDSTREAM *nntpstream;	/* NNTP stream for I/O */
  107.72 +  unsigned int dirty : 1;	/* disk copy of .newsrc needs updating */
  107.73 +  unsigned int tlsflag : 1;	/* TLS session */
  107.74 +  unsigned int tlssslv23 : 1;	/* TLS using SSLv23 client method */
  107.75 +  unsigned int notlsflag : 1;	/* TLS not used in session */
  107.76 +  unsigned int sslflag : 1;	/* SSL session */
  107.77 +  unsigned int novalidate : 1;	/* certificate not validated */
  107.78 +  unsigned int xover : 1;	/* supports XOVER */
  107.79 +  unsigned int xhdr : 1;	/* supports XHDR */
  107.80 +  char *name;			/* remote newsgroup name */
  107.81 +  char *user;			/* mailbox user */
  107.82 +  char *newsrc;			/* newsrc file */
  107.83 +  char *over_fmt;		/* overview format */
  107.84 +  unsigned long msgno;		/* current text message number */
  107.85 +  FILE *txt;			/* current text */
  107.86 +  unsigned long txtsize;	/* current text size */
  107.87 +} NNTPLOCAL;
  107.88 +
  107.89 +
  107.90 +/* Convenient access to local data */
  107.91 +
  107.92 +#define LOCAL ((NNTPLOCAL *) stream->local)
  107.93 +
  107.94 +
  107.95 +/* Convenient access to protocol-specific data */
  107.96 +
  107.97 +#define NNTP stream->protocol.nntp
  107.98 +
  107.99 +
 107.100 +/* Convenient access to extensions */
 107.101 +
 107.102 +#define EXTENSION LOCAL->nntpstream->protocol.nntp.ext
 107.103 +
 107.104 +/* Function prototypes */
 107.105 +
 107.106 +DRIVER *nntp_valid (char *name);
 107.107 +DRIVER *nntp_isvalid (char *name,char *mbx);
 107.108 +void *nntp_parameters (long function,void *value);
 107.109 +void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 107.110 +void nntp_list (MAILSTREAM *stream,char *ref,char *pat);
 107.111 +void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat);
 107.112 +long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat);
 107.113 +long nntp_subscribe (MAILSTREAM *stream,char *mailbox);
 107.114 +long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox);
 107.115 +long nntp_create (MAILSTREAM *stream,char *mailbox);
 107.116 +long nntp_delete (MAILSTREAM *stream,char *mailbox);
 107.117 +long nntp_rename (MAILSTREAM *stream,char *old,char *newname);
 107.118 +long nntp_status (MAILSTREAM *stream,char *mbx,long flags);
 107.119 +long nntp_getmap (MAILSTREAM *stream,char *name,
 107.120 +		  unsigned long first,unsigned long last,
 107.121 +		  unsigned long rnmsgs,unsigned long nmsgs,char *tmp);
 107.122 +MAILSTREAM *nntp_mopen (MAILSTREAM *stream);
 107.123 +void nntp_mclose (MAILSTREAM *stream,long options);
 107.124 +void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags);
 107.125 +void nntp_flags (MAILSTREAM *stream,char *sequence,long flags);
 107.126 +long nntp_overview (MAILSTREAM *stream,overview_t ofn);
 107.127 +long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt);
 107.128 +long nntp_over (MAILSTREAM *stream,char *sequence);
 107.129 +char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
 107.130 +		   long flags);
 107.131 +long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 107.132 +FILE *nntp_article (MAILSTREAM *stream,char *msgid,unsigned long *size,
 107.133 +		    unsigned long *hsiz);
 107.134 +void nntp_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 107.135 +long nntp_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
 107.136 +long nntp_search_msg (MAILSTREAM *stream,unsigned long msgno,SEARCHPGM *pgm,
 107.137 +		      OVERVIEW *ov);
 107.138 +unsigned long *nntp_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 107.139 +			  SORTPGM *pgm,long flags);
 107.140 +SORTCACHE **nntp_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm,
 107.141 +				 unsigned long start,unsigned long last,
 107.142 +				 long flags);
 107.143 +THREADNODE *nntp_thread (MAILSTREAM *stream,char *type,char *charset,
 107.144 +			 SEARCHPGM *spg,long flags);
 107.145 +long nntp_ping (MAILSTREAM *stream);
 107.146 +void nntp_check (MAILSTREAM *stream);
 107.147 +long nntp_expunge (MAILSTREAM *stream,char *sequence,long options);
 107.148 +long nntp_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 107.149 +long nntp_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 107.150 +
 107.151 +long nntp_extensions (SENDSTREAM *stream,long flags);
 107.152 +long nntp_send (SENDSTREAM *stream,char *command,char *args);
 107.153 +long nntp_send_work (SENDSTREAM *stream,char *command,char *args);
 107.154 +long nntp_send_auth (SENDSTREAM *stream,long flags);
 107.155 +long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags);
 107.156 +void *nntp_challenge (void *s,unsigned long *len);
 107.157 +long nntp_response (void *s,char *response,unsigned long size);
 107.158 +long nntp_reply (SENDSTREAM *stream);
 107.159 +long nntp_fake (SENDSTREAM *stream,char *text);
 107.160 +long nntp_soutr (void *stream,char *s);
 107.161 +
 107.162 +/* Driver dispatch used by MAIL */
 107.163 +
 107.164 +DRIVER nntpdriver = {
 107.165 +  "nntp",			/* driver name */
 107.166 +				/* driver flags */
 107.167 +#ifdef INADEQUATE_MEMORY
 107.168 +  DR_LOWMEM |
 107.169 +#endif
 107.170 +  DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_CRLF|DR_RECYCLE|DR_XPOINT |
 107.171 +    DR_NOINTDATE|DR_NONEWMAIL|DR_HALFOPEN,
 107.172 +  (DRIVER *) NIL,		/* next driver */
 107.173 +  nntp_valid,			/* mailbox is valid for us */
 107.174 +  nntp_parameters,		/* manipulate parameters */
 107.175 +  nntp_scan,			/* scan mailboxes */
 107.176 +  nntp_list,			/* find mailboxes */
 107.177 +  nntp_lsub,			/* find subscribed mailboxes */
 107.178 +  nntp_subscribe,		/* subscribe to mailbox */
 107.179 +  nntp_unsubscribe,		/* unsubscribe from mailbox */
 107.180 +  nntp_create,			/* create mailbox */
 107.181 +  nntp_delete,			/* delete mailbox */
 107.182 +  nntp_rename,			/* rename mailbox */
 107.183 +  nntp_status,			/* status of mailbox */
 107.184 +  nntp_mopen,			/* open mailbox */
 107.185 +  nntp_mclose,			/* close mailbox */
 107.186 +  nntp_fetchfast,		/* fetch message "fast" attributes */
 107.187 +  nntp_flags,			/* fetch message flags */
 107.188 +  nntp_overview,		/* fetch overview */
 107.189 +  NIL,				/* fetch message structure */
 107.190 +  nntp_header,			/* fetch message header */
 107.191 +  nntp_text,			/* fetch message text */
 107.192 +  NIL,				/* fetch message */
 107.193 +  NIL,				/* unique identifier */
 107.194 +  NIL,				/* message number from UID */
 107.195 +  NIL,				/* modify flags */
 107.196 +  nntp_flagmsg,			/* per-message modify flags */
 107.197 +  nntp_search,			/* search for message based on criteria */
 107.198 +  nntp_sort,			/* sort messages */
 107.199 +  nntp_thread,			/* thread messages */
 107.200 +  nntp_ping,			/* ping mailbox to see if still alive */
 107.201 +  nntp_check,			/* check for new messages */
 107.202 +  nntp_expunge,			/* expunge deleted messages */
 107.203 +  nntp_copy,			/* copy messages to another mailbox */
 107.204 +  nntp_append,			/* append string message to mailbox */
 107.205 +  NIL				/* garbage collect stream */
 107.206 +};
 107.207 +
 107.208 +				/* prototype stream */
 107.209 +MAILSTREAM nntpproto = {&nntpdriver};
 107.210 +
 107.211 +
 107.212 +				/* driver parameters */
 107.213 +static unsigned long nntp_maxlogintrials = MAXLOGINTRIALS;
 107.214 +static long nntp_port = 0;
 107.215 +static long nntp_sslport = 0;
 107.216 +static unsigned long nntp_range = 0;
 107.217 +static long nntp_hidepath = 0;
 107.218 +
 107.219 +/* NNTP validate mailbox
 107.220 + * Accepts: mailbox name
 107.221 + * Returns: our driver if name is valid, NIL otherwise
 107.222 + */
 107.223 +
 107.224 +DRIVER *nntp_valid (char *name)
 107.225 +{
 107.226 +  char tmp[MAILTMPLEN];
 107.227 +  return nntp_isvalid (name,tmp);
 107.228 +}
 107.229 +
 107.230 +
 107.231 +/* NNTP validate mailbox work routine
 107.232 + * Accepts: mailbox name
 107.233 + *	    buffer for returned mailbox name
 107.234 + * Returns: our driver if name is valid, NIL otherwise
 107.235 + */
 107.236 +
 107.237 +DRIVER *nntp_isvalid (char *name,char *mbx)
 107.238 +{
 107.239 +  NETMBX mb;
 107.240 +  if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,nntpdriver.name)||
 107.241 +      mb.anoflag) return NIL;
 107.242 +  if (mb.mailbox[0] != '#') strcpy (mbx,mb.mailbox);
 107.243 +			/* namespace format name */
 107.244 +  else if ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') &&
 107.245 +	   (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') &&
 107.246 +	   (mb.mailbox[5] == '.')) strcpy (mbx,mb.mailbox+6);
 107.247 +  else return NIL;		/* bogus name */
 107.248 +  return &nntpdriver;
 107.249 +}
 107.250 +
 107.251 +/* News manipulate driver parameters
 107.252 + * Accepts: function code
 107.253 + *	    function-dependent value
 107.254 + * Returns: function-dependent return value
 107.255 + */
 107.256 +
 107.257 +void *nntp_parameters (long function,void *value)
 107.258 +{
 107.259 +  switch ((int) function) {
 107.260 +  case SET_MAXLOGINTRIALS:
 107.261 +    nntp_maxlogintrials = (unsigned long) value;
 107.262 +    break;
 107.263 +  case GET_MAXLOGINTRIALS:
 107.264 +    value = (void *) nntp_maxlogintrials;
 107.265 +    break;
 107.266 +  case SET_NNTPPORT:
 107.267 +    nntp_port = (long) value;
 107.268 +    break;
 107.269 +  case GET_NNTPPORT:
 107.270 +    value = (void *) nntp_port;
 107.271 +    break;
 107.272 +  case SET_SSLNNTPPORT:
 107.273 +    nntp_sslport = (long) value;
 107.274 +    break;
 107.275 +  case GET_SSLNNTPPORT:
 107.276 +    value = (void *) nntp_sslport;
 107.277 +    break;
 107.278 +  case SET_NNTPRANGE:
 107.279 +    nntp_range = (unsigned long) value;
 107.280 +    break;
 107.281 +  case GET_NNTPRANGE:
 107.282 +    value = (void *) nntp_range;
 107.283 +    break;
 107.284 +  case SET_NNTPHIDEPATH:
 107.285 +    nntp_hidepath = (long) value;
 107.286 +    break;
 107.287 +  case GET_NNTPHIDEPATH:
 107.288 +    value = (void *) nntp_hidepath;
 107.289 +    break;
 107.290 +  case GET_NEWSRC:
 107.291 +    if (value)
 107.292 +      value = (void *) ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->newsrc;
 107.293 +    break;
 107.294 +  case GET_IDLETIMEOUT:
 107.295 +    value = (void *) IDLETIMEOUT;
 107.296 +    break;
 107.297 +  case ENABLE_DEBUG:
 107.298 +    if (value)
 107.299 +      ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->nntpstream->debug = T;
 107.300 +    break;
 107.301 +  case DISABLE_DEBUG:
 107.302 +    if (value)
 107.303 +      ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->nntpstream->debug = NIL;
 107.304 +    break;
 107.305 +  default:
 107.306 +    value = NIL;		/* error case */
 107.307 +    break;
 107.308 +  }
 107.309 +  return value;
 107.310 +}
 107.311 +
 107.312 +/* NNTP mail scan mailboxes for string
 107.313 + * Accepts: mail stream
 107.314 + *	    reference
 107.315 + *	    pattern to search
 107.316 + *	    string to scan
 107.317 + */
 107.318 +
 107.319 +void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 107.320 +{
 107.321 +  char tmp[MAILTMPLEN];
 107.322 +  if (nntp_canonicalize (ref,pat,tmp,NIL))
 107.323 +    mm_log ("Scan not valid for NNTP mailboxes",ERROR);
 107.324 +}
 107.325 +
 107.326 +
 107.327 +/* NNTP list newsgroups
 107.328 + * Accepts: mail stream
 107.329 + *	    reference
 107.330 + *	    pattern to search
 107.331 + */
 107.332 +
 107.333 +void nntp_list (MAILSTREAM *stream,char *ref,char *pat)
 107.334 +{
 107.335 +  MAILSTREAM *st = stream;
 107.336 +  char *s,*t,*lcl,pattern[MAILTMPLEN],name[MAILTMPLEN],wildmat[MAILTMPLEN];
 107.337 +  int showuppers = pat[strlen (pat) - 1] == '%';
 107.338 +  if (!*pat) {
 107.339 +    if (nntp_canonicalize (ref,"*",pattern,NIL)) {
 107.340 +				/* tie off name at root */
 107.341 +      if ((s = strchr (pattern,'}')) && (s = strchr (s+1,'.'))) *++s = '\0';
 107.342 +      else pattern[0] = '\0';
 107.343 +      mm_list (stream,'.',pattern,NIL);
 107.344 +    }
 107.345 +  }
 107.346 +				/* ask server for open newsgroups */
 107.347 +  else if (nntp_canonicalize (ref,pat,pattern,wildmat) &&
 107.348 +	   ((stream && LOCAL && LOCAL->nntpstream) ||
 107.349 +	    (stream = mail_open (NIL,pattern,OP_HALFOPEN|OP_SILENT))) &&
 107.350 +	   ((nntp_send (LOCAL->nntpstream,"LIST ACTIVE",
 107.351 +			wildmat[0] ? wildmat : NIL) == NNTPGLIST) ||
 107.352 +	    (nntp_send (LOCAL->nntpstream,"LIST",NIL) == NNTPGLIST))) {
 107.353 +				/* namespace format name? */
 107.354 +    if (*(lcl = strchr (strcpy (name,pattern),'}') + 1) == '#') lcl += 6;
 107.355 +				/* process data until we see final dot */
 107.356 +    while (s = net_getline (LOCAL->nntpstream->netstream)) {
 107.357 +      if ((*s == '.') && !s[1]){/* end of text */
 107.358 +	fs_give ((void **) &s);
 107.359 +	break;
 107.360 +      }
 107.361 +      if (t = strchr (s,' ')) {	/* tie off after newsgroup name */
 107.362 +	*t = '\0';
 107.363 +	strcpy (lcl,s);		/* make full form of name */
 107.364 +				/* report if match */
 107.365 +	if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL);
 107.366 +	else while (showuppers && (t = strrchr (lcl,'.'))) {
 107.367 +	  *t = '\0';		/* tie off the name */
 107.368 +	  if (pmatch_full (name,pattern,'.'))
 107.369 +	    mm_list (stream,'.',name,LATT_NOSELECT);
 107.370 +	}
 107.371 +      }
 107.372 +      fs_give ((void **) &s);	/* clean up */
 107.373 +    }
 107.374 +    if (stream != st) mail_close (stream);
 107.375 +  }
 107.376 +}
 107.377 +
 107.378 +/* NNTP list subscribed newsgroups
 107.379 + * Accepts: mail stream
 107.380 + *	    reference
 107.381 + *	    pattern to search
 107.382 + */
 107.383 +
 107.384 +void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat)
 107.385 +{
 107.386 +  void *sdb = NIL;
 107.387 +  char *s,mbx[MAILTMPLEN];
 107.388 +				/* return data from newsrc */
 107.389 +  if (nntp_canonicalize (ref,pat,mbx,NIL)) newsrc_lsub (stream,mbx);
 107.390 +  if (*pat == '{') {		/* if remote pattern, must be NNTP */
 107.391 +    if (!nntp_valid (pat)) return;
 107.392 +    ref = NIL;			/* good NNTP pattern, punt reference */
 107.393 +  }
 107.394 +				/* if remote reference, must be valid NNTP */
 107.395 +  if (ref && (*ref == '{') && !nntp_valid (ref)) return;
 107.396 +				/* kludgy application of reference */
 107.397 +  if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
 107.398 +  else strcpy (mbx,pat);
 107.399 +
 107.400 +  if (s = sm_read (&sdb)) do if (nntp_valid (s) && pmatch (s,mbx))
 107.401 +    mm_lsub (stream,NIL,s,NIL);
 107.402 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 107.403 +}
 107.404 +
 107.405 +/* NNTP canonicalize newsgroup name
 107.406 + * Accepts: reference
 107.407 + *	    pattern
 107.408 + *	    returned single pattern
 107.409 + *	    returned wildmat pattern
 107.410 + * Returns: T on success, NIL on failure
 107.411 + */
 107.412 +
 107.413 +long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat)
 107.414 +{
 107.415 +  char *s;
 107.416 +  DRIVER *ret;
 107.417 +  if (ref && *ref) {		/* have a reference */
 107.418 +    if (!nntp_valid (ref)) return NIL;
 107.419 +    strcpy (pattern,ref);	/* copy reference to pattern */
 107.420 +				/* # overrides mailbox field in reference */
 107.421 +    if (*pat == '#') strcpy (strchr (pattern,'}') + 1,pat);
 107.422 +				/* pattern starts, reference ends, with . */
 107.423 +    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
 107.424 +      strcat (pattern,pat + 1);	/* append, omitting one of the period */
 107.425 +    else strcat (pattern,pat);	/* anything else is just appended */
 107.426 +  }
 107.427 +  else strcpy (pattern,pat);	/* just have basic name */
 107.428 +  if ((ret = wildmat ?		/* if valid and wildmat */
 107.429 +       nntp_isvalid (pattern,wildmat) : nntp_valid (pattern)) && wildmat) {
 107.430 +				/* don't return wildmat if specials present */
 107.431 +    if (strpbrk (wildmat,",?![\\]")) wildmat[0] = '\0';
 107.432 +				/* replace all % with * */
 107.433 +    for (s = wildmat; s = strchr (s,'%'); *s = '*');
 107.434 +  }
 107.435 +  return ret ? LONGT : NIL;
 107.436 +}
 107.437 +
 107.438 +/* NNTP subscribe to mailbox
 107.439 + * Accepts: mail stream
 107.440 + *	    mailbox to add to subscription list
 107.441 + * Returns: T on success, NIL on failure
 107.442 + */
 107.443 +
 107.444 +long nntp_subscribe (MAILSTREAM *stream,char *mailbox)
 107.445 +{
 107.446 +  char mbx[MAILTMPLEN];
 107.447 +  return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,':') : NIL;
 107.448 +}
 107.449 +
 107.450 +
 107.451 +/* NNTP unsubscribe to mailbox
 107.452 + * Accepts: mail stream
 107.453 + *	    mailbox to delete from subscription list
 107.454 + * Returns: T on success, NIL on failure
 107.455 + */
 107.456 +
 107.457 +long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox)
 107.458 +{
 107.459 +  char mbx[MAILTMPLEN];
 107.460 +  return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,'!') : NIL;
 107.461 +}
 107.462 +
 107.463 +/* NNTP create mailbox
 107.464 + * Accepts: mail stream
 107.465 + *	    mailbox name to create
 107.466 + * Returns: T on success, NIL on failure
 107.467 + */
 107.468 +
 107.469 +long nntp_create (MAILSTREAM *stream,char *mailbox)
 107.470 +{
 107.471 +  return NIL;			/* never valid for NNTP */
 107.472 +}
 107.473 +
 107.474 +
 107.475 +/* NNTP delete mailbox
 107.476 + *	    mailbox name to delete
 107.477 + * Returns: T on success, NIL on failure
 107.478 + */
 107.479 +
 107.480 +long nntp_delete (MAILSTREAM *stream,char *mailbox)
 107.481 +{
 107.482 +  return NIL;			/* never valid for NNTP */
 107.483 +}
 107.484 +
 107.485 +
 107.486 +/* NNTP rename mailbox
 107.487 + * Accepts: mail stream
 107.488 + *	    old mailbox name
 107.489 + *	    new mailbox name
 107.490 + * Returns: T on success, NIL on failure
 107.491 + */
 107.492 +
 107.493 +long nntp_rename (MAILSTREAM *stream,char *old,char *newname)
 107.494 +{
 107.495 +  return NIL;			/* never valid for NNTP */
 107.496 +}
 107.497 +
 107.498 +/* NNTP status
 107.499 + * Accepts: mail stream
 107.500 + *	    mailbox name
 107.501 + *	    status flags
 107.502 + * Returns: T on success, NIL on failure
 107.503 + */
 107.504 +
 107.505 +long nntp_status (MAILSTREAM *stream,char *mbx,long flags)
 107.506 +{
 107.507 +  MAILSTATUS status;
 107.508 +  NETMBX mb;
 107.509 +  unsigned long i,j,k,rnmsgs;
 107.510 +  long ret = NIL;
 107.511 +  char *s,*name,*state,tmp[MAILTMPLEN];
 107.512 +  char *old = (stream && !stream->halfopen) ? LOCAL->name : NIL;
 107.513 +  MAILSTREAM *tstream = NIL;
 107.514 +  if (!(mail_valid_net_parse (mbx,&mb) && !strcmp (mb.service,"nntp") &&
 107.515 +	*mb.mailbox &&
 107.516 +	((mb.mailbox[0] != '#') ||
 107.517 +	 ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') &&
 107.518 +	  (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') &&
 107.519 +	  (mb.mailbox[5] == '.'))))) {
 107.520 +    sprintf (tmp,"Invalid NNTP name %s",mbx);
 107.521 +    mm_log (tmp,ERROR);
 107.522 +    return NIL;
 107.523 +  }
 107.524 +				/* note mailbox name */
 107.525 +  name = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox;
 107.526 +				/* stream to reuse? */
 107.527 +  if (!(stream && LOCAL->nntpstream &&
 107.528 +	mail_usable_network_stream (stream,mbx)) &&
 107.529 +      !(tstream = stream =
 107.530 +	mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT|
 107.531 +		   ((flags & SA_MULNEWSRC) ? OP_MULNEWSRC : NIL))))
 107.532 +    return NIL;			/* can't reuse or make a new one */
 107.533 +
 107.534 +  if (nntp_send (LOCAL->nntpstream,"GROUP",name) == NNTPGOK) {
 107.535 +    status.flags = flags;	/* status validity flags */
 107.536 +    k = strtoul (LOCAL->nntpstream->reply + 4,&s,10);
 107.537 +    i = strtoul (s,&s,10);	/* first assigned UID */
 107.538 +				/* next UID to be assigned */
 107.539 +    status.uidnext = (j = strtoul (s,NIL,10)) + 1;
 107.540 +				/* maximum number of messages */
 107.541 +    rnmsgs = status.messages = (i | j) ? status.uidnext - i : 0;
 107.542 +    if (k > status.messages) {	/* check for absurdity */
 107.543 +      sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu",
 107.544 +	       k,status.messages);
 107.545 +      mm_log (tmp,WARN);
 107.546 +    }
 107.547 +				/* restrict article range if needed */
 107.548 +    if (nntp_range && (status.messages > nntp_range)) {
 107.549 +      i = status.uidnext - (status.messages = nntp_range);
 107.550 +      if (k > nntp_range) k = nntp_range;
 107.551 +    }
 107.552 +				/* initially zero */
 107.553 +    status.recent = status.unseen = 0;
 107.554 +    if (!status.messages);	/* empty case */
 107.555 +				/* use server guesstimate in simple case */
 107.556 +    else if (!(flags & (SA_RECENT | SA_UNSEEN))) status.messages = k;
 107.557 +
 107.558 +				/* have newsrc state? */
 107.559 +    else if (state = newsrc_state (stream,name)) {
 107.560 +				/* yes, get the UID/sequence map */
 107.561 +      if (nntp_getmap (stream,name,i,status.uidnext - 1,rnmsgs,
 107.562 +		       status.messages,tmp)) {
 107.563 +				/* calculate true count */
 107.564 +	for (status.messages = 0;
 107.565 +	     (s = net_getline (LOCAL->nntpstream->netstream)) &&
 107.566 +	       strcmp (s,"."); ) {
 107.567 +				/* only count if in range */
 107.568 +	  if (((k = atol (s)) >= i) && (k < status.uidnext)) {
 107.569 +	    newsrc_check_uid (state,k,&status.recent,&status.unseen);
 107.570 +	    status.messages++;
 107.571 +	  }
 107.572 +	  fs_give ((void **) &s);
 107.573 +	}
 107.574 +	if (s) fs_give ((void **) &s);
 107.575 +      }
 107.576 +				/* assume c-client/NNTP map is entire range */
 107.577 +      else while (i < status.uidnext)
 107.578 +	newsrc_check_uid (state,i++,&status.recent,&status.unseen);
 107.579 +      fs_give ((void **) &state);
 107.580 +    }
 107.581 +				/* no .newsrc state, all messages new */
 107.582 +    else status.recent = status.unseen = status.messages;
 107.583 +				/* UID validity is a constant */
 107.584 +    status.uidvalidity = stream->uid_validity;
 107.585 +				/* pass status to main program */
 107.586 +    mm_status (stream,mbx,&status);
 107.587 +    ret = T;			/* succes */
 107.588 +  }
 107.589 +				/* flush temporary stream */
 107.590 +  if (tstream) mail_close (tstream);
 107.591 +				/* else reopen old newsgroup */
 107.592 +  else if (old && nntp_send (LOCAL->nntpstream,"GROUP",old) != NNTPGOK) {
 107.593 +    mm_log (LOCAL->nntpstream->reply,ERROR);
 107.594 +    stream->halfopen = T;	/* go halfopen */
 107.595 +  }
 107.596 +  return ret;			/* success */
 107.597 +}
 107.598 +
 107.599 +/* NNTP get map
 107.600 + * Accepts: stream
 107.601 + *	    newsgroup name
 107.602 + *	    first UID in map range
 107.603 + *	    last UID in map range
 107.604 + *	    reported total number of messages in newsgroup
 107.605 + *	    calculated number of messages in range
 107.606 + *	    temporary buffer
 107.607 + * Returns: T on success, NIL on failure
 107.608 + */
 107.609 +
 107.610 +long nntp_getmap (MAILSTREAM *stream,char *name,
 107.611 +		  unsigned long first,unsigned long last,
 107.612 +		  unsigned long rnmsgs,unsigned long nmsgs,char *tmp)
 107.613 +{
 107.614 +  short trylistgroup = NIL;
 107.615 +  if (rnmsgs > (nmsgs * 8))	/* small subrange? */
 107.616 +    trylistgroup = T;		/* yes, can try LISTGROUP if [X]HDR fails */
 107.617 +  else switch ((int) nntp_send (LOCAL->nntpstream,"LISTGROUP",name)) {
 107.618 +  case NNTPGOK:			/* got data */
 107.619 +    return LONGT;
 107.620 +  default:			/* else give up if server claims LISTGROUP */
 107.621 +    if (EXTENSION.listgroup) return NIL;
 107.622 +  }
 107.623 +				/* build range */
 107.624 +  sprintf (tmp,"%lu-%lu",first,last);
 107.625 +  if (EXTENSION.hdr)		/* have HDR extension? */
 107.626 +    return (nntp_send (LOCAL->nntpstream,"HDR Date",tmp) == NNTPHEAD) ?
 107.627 +      LONGT : NIL;
 107.628 +  if (LOCAL->xhdr)		/* try the experimental extension then */
 107.629 +    switch ((int) nntp_send (LOCAL->nntpstream,"XHDR Date",tmp)) {
 107.630 +    case NNTPHEAD:		/* got an overview? */
 107.631 +      return LONGT;
 107.632 +    case NNTPBADCMD:		/* unknown command? */
 107.633 +      LOCAL->xhdr = NIL;	/* disable future XHDR attempts */
 107.634 +    }
 107.635 +  if (trylistgroup &&		/* no [X]HDR, maybe do LISTGROUP after all */
 107.636 +      (nntp_send (LOCAL->nntpstream,"LISTGROUP",name) == NNTPGOK))
 107.637 +    return LONGT;
 107.638 +  return NIL;
 107.639 +}
 107.640 +
 107.641 +/* NNTP open
 107.642 + * Accepts: stream to open
 107.643 + * Returns: stream on success, NIL on failure
 107.644 + */
 107.645 +
 107.646 +MAILSTREAM *nntp_mopen (MAILSTREAM *stream)
 107.647 +{
 107.648 +  unsigned long i,j,k,nmsgs,rnmsgs;
 107.649 +  char *s,*mbx,tmp[MAILTMPLEN];
 107.650 +  FILE *f;
 107.651 +  NETMBX mb;
 107.652 +  char *newsrc = (char *) mail_parameters (NIL,GET_NEWSRC,NIL);
 107.653 +  newsrcquery_t nq = (newsrcquery_t) mail_parameters (NIL,GET_NEWSRCQUERY,NIL);
 107.654 +  SENDSTREAM *nstream = NIL;
 107.655 +				/* return prototype for OP_PROTOTYPE call */
 107.656 +  if (!stream) return &nntpproto;
 107.657 +  mail_valid_net_parse (stream->mailbox,&mb);
 107.658 +				/* note mailbox anme */
 107.659 +  mbx = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox;
 107.660 +  if (LOCAL) {			/* recycle stream */
 107.661 +    nstream = LOCAL->nntpstream;/* remember NNTP protocol stream */
 107.662 +    sprintf (tmp,"Reusing connection to %s",net_host (nstream->netstream));
 107.663 +    if (!stream->silent) mm_log (tmp,(long) NIL);
 107.664 +    if (stream->rdonly) mb.readonlyflag = T;
 107.665 +    if (LOCAL->tlsflag) mb.tlsflag = T;
 107.666 +    if (LOCAL->tlssslv23) mb.tlssslv23 = T;
 107.667 +    if (LOCAL->notlsflag) mb.notlsflag = T;
 107.668 +    if (LOCAL->sslflag) mb.sslflag = T;
 107.669 +    if (LOCAL->novalidate) mb.novalidate = T;
 107.670 +    if (LOCAL->nntpstream->loser) mb.loser = T;
 107.671 +    if (stream->secure) mb.secflag = T;
 107.672 +    LOCAL->nntpstream = NIL;	/* keep nntp_mclose() from punting it */
 107.673 +    nntp_mclose (stream,NIL);	/* do close action */
 107.674 +    stream->dtb = &nntpdriver;	/* reattach this driver */
 107.675 +  }
 107.676 +				/* copy flags */
 107.677 +  if (mb.dbgflag) stream->debug = T;
 107.678 +  if (mb.readonlyflag) stream->rdonly = T;
 107.679 +  if (mb.secflag) stream->secure = T;
 107.680 +  mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL;
 107.681 +  if (!nstream) {		/* open NNTP now if not already open */
 107.682 +    char *hostlist[2];
 107.683 +    hostlist[0] = strcpy (tmp,mb.host);
 107.684 +    if (mb.port || nntp_port)
 107.685 +      sprintf (tmp + strlen (tmp),":%lu",mb.port ? mb.port : nntp_port);
 107.686 +    if (mb.tlsflag) strcat (tmp,"/tls");
 107.687 +    if (mb.tlssslv23) strcat (tmp,"/tls-sslv23");
 107.688 +    if (mb.notlsflag) strcat (tmp,"/notls");
 107.689 +    if (mb.sslflag) strcat (tmp,"/ssl");
 107.690 +    if (mb.novalidate) strcat (tmp,"/novalidate-cert");
 107.691 +    if (mb.loser) strcat (tmp,"/loser");
 107.692 +    if (mb.secflag) strcat (tmp,"/secure");
 107.693 +    if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=\"%s\"",mb.user);
 107.694 +    hostlist[1] = NIL;
 107.695 +    if (!(nstream = nntp_open (hostlist,NOP_READONLY |
 107.696 +			       (stream->debug ? NOP_DEBUG : NIL)))) return NIL;
 107.697 +  }
 107.698 +
 107.699 +				/* always zero messages if halfopen */
 107.700 +  if (stream->halfopen) i = j = k = rnmsgs = nmsgs = 0;
 107.701 +				/* otherwise open the newsgroup */
 107.702 +  else if (nntp_send (nstream,"GROUP",mbx) == NNTPGOK) {
 107.703 +    k = strtoul (nstream->reply + 4,&s,10);
 107.704 +    i = strtoul (s,&s,10);
 107.705 +    stream->uid_last = j = strtoul (s,&s,10);
 107.706 +    rnmsgs = nmsgs = (i | j) ? 1 + j - i : 0;
 107.707 +    if (k > nmsgs) {		/* check for absurdity */
 107.708 +      sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu",
 107.709 +	       k,nmsgs);
 107.710 +      mm_log (tmp,WARN);
 107.711 +    }
 107.712 +				/* restrict article range if needed */
 107.713 +    if (nntp_range && (nmsgs > nntp_range)) i = 1 + j - (nmsgs = nntp_range);
 107.714 +  }
 107.715 +  else {			/* no such newsgroup */
 107.716 +    mm_log (nstream->reply,ERROR);
 107.717 +    nntp_close (nstream);	/* punt stream */
 107.718 +    return NIL;
 107.719 +  }
 107.720 +				/* instantiate local data */
 107.721 +  stream->local = memset (fs_get (sizeof (NNTPLOCAL)),0,sizeof (NNTPLOCAL));
 107.722 +  LOCAL->nntpstream = nstream;
 107.723 +				/* save state for future recycling */
 107.724 +  if (mb.tlsflag) LOCAL->tlsflag = T;
 107.725 +  if (mb.tlssslv23) LOCAL->tlssslv23 = T;
 107.726 +  if (mb.notlsflag) LOCAL->notlsflag = T;
 107.727 +  if (mb.sslflag) LOCAL->sslflag = T;
 107.728 +  if (mb.novalidate) LOCAL->novalidate = T;
 107.729 +  if (mb.loser) LOCAL->nntpstream->loser = T;
 107.730 +				/* assume present until proven otherwise */
 107.731 +  LOCAL->xhdr = LOCAL->xover = T;
 107.732 +  LOCAL->name = cpystr (mbx);	/* copy newsgroup name */
 107.733 +  if (stream->mulnewsrc) {	/* want to use multiple .newsrc files? */
 107.734 +    strcpy (tmp,newsrc);
 107.735 +    s = tmp + strlen (tmp);	/* end of string */
 107.736 +    *s++ = '-';			/* hyphen delimiter and host */
 107.737 +    lcase (strcpy (s,(long) mail_parameters (NIL,GET_NEWSRCCANONHOST,NIL) ?
 107.738 +		   net_host (nstream->netstream) : mb.host));
 107.739 +    LOCAL->newsrc = cpystr (nq ? (*nq) (stream,tmp,newsrc) : tmp);
 107.740 +  }
 107.741 +  else LOCAL->newsrc = cpystr (newsrc);
 107.742 +  if (mb.user[0]) LOCAL->user = cpystr (mb.user);
 107.743 +  stream->sequence++;		/* bump sequence number */
 107.744 +  stream->rdonly = stream->perm_deleted = T;
 107.745 +				/* UIDs are always valid */
 107.746 +  stream->uid_validity = 0xbeefface;
 107.747 +  sprintf (tmp,"{%s:%lu/nntp",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
 107.748 +	   net_host (nstream->netstream) : mb.host,
 107.749 +	   net_port (nstream->netstream));
 107.750 +  if (LOCAL->tlsflag) strcat (tmp,"/tls");
 107.751 +  if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23");
 107.752 +  if (LOCAL->notlsflag) strcat (tmp,"/notls");
 107.753 +  if (LOCAL->sslflag) strcat (tmp,"/ssl");
 107.754 +  if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert");
 107.755 +  if (LOCAL->nntpstream->loser) strcat (tmp,"/loser");
 107.756 +  if (stream->secure) strcat (tmp,"/secure");
 107.757 +  if (stream->rdonly) strcat (tmp,"/readonly");
 107.758 +  if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",LOCAL->user);
 107.759 +  if (stream->halfopen) strcat (tmp,"}<no_mailbox>");
 107.760 +  else sprintf (tmp + strlen (tmp),"}#news.%s",mbx);
 107.761 +  fs_give ((void **) &stream->mailbox);
 107.762 +  stream->mailbox = cpystr (tmp);
 107.763 +
 107.764 +  if (EXTENSION.over &&		/* get overview format if have OVER */
 107.765 +      (nntp_send (LOCAL->nntpstream,"LIST","OVERVIEW.FMT") == NNTPGLIST) &&
 107.766 +      (f = netmsg_slurp (LOCAL->nntpstream->netstream,&k,NIL))) {
 107.767 +    fread (LOCAL->over_fmt = (char *) fs_get ((size_t) k + 3),
 107.768 +	   (size_t) 1,(size_t) k,f);
 107.769 +    LOCAL->over_fmt[k] = '\0';
 107.770 +    fclose (f);			/* flush temp file */
 107.771 +  }
 107.772 +  if (nmsgs) {			/* if any messages exist */
 107.773 +    short silent = stream->silent;
 107.774 +    stream->silent = T;		/* don't notify main program yet */
 107.775 +    mail_exists (stream,nmsgs);	/* silently set the cache to the guesstimate */
 107.776 +				/* get UID/sequence map, nuke holes */
 107.777 +    if (nntp_getmap (stream,mbx,i,j,rnmsgs,nmsgs,tmp)) {
 107.778 +      for (nmsgs = 0;		/* calculate true count */
 107.779 +	   (s = net_getline (nstream->netstream)) && strcmp (s,"."); ) {
 107.780 +	if ((k = atol (s)) > j){/* discard too high article numbers */
 107.781 +	  sprintf (tmp,"NNTP SERVER BUG (out of range article ID): %lu > %lu",
 107.782 +		   k,j);
 107.783 +	  mm_notify (stream,tmp,NIL);
 107.784 +	  stream->unhealthy = T;
 107.785 +	}
 107.786 +	else if (k >= i) {	/* silently ignore too-low article numbers */
 107.787 +				/* guard against server returning extra msgs */
 107.788 +	  if (nmsgs == stream->nmsgs) mail_exists (stream,nmsgs+1);
 107.789 +				/* create elt for this message, set UID */
 107.790 +	  mail_elt (stream,++nmsgs)->private.uid = k;
 107.791 +	}
 107.792 +	fs_give ((void **) &s);
 107.793 +      }
 107.794 +      if (s) fs_give ((void **) &s);
 107.795 +    }
 107.796 +				/* assume c-client/NNTP map is entire range */
 107.797 +    else for (k = 1; k <= nmsgs; k++) mail_elt (stream,k)->private.uid = i++;
 107.798 +    stream->unhealthy = NIL;	/* set healthy */
 107.799 +    stream->nmsgs = 0;		/* whack it back down */
 107.800 +    stream->silent = silent;	/* restore old silent setting */
 107.801 +    mail_exists (stream,nmsgs);	/* notify upper level that messages exist */
 107.802 +				/* read .newsrc entries */
 107.803 +    mail_recent (stream,newsrc_read (mbx,stream));
 107.804 +  }
 107.805 +  else {			/* empty newsgroup or halfopen */
 107.806 +    if (!(stream->silent || stream->halfopen)) {
 107.807 +      sprintf (tmp,"Newsgroup %s is empty",mbx);
 107.808 +      mm_log (tmp,WARN);
 107.809 +    }
 107.810 +    mail_exists (stream,(long) 0);
 107.811 +    mail_recent (stream,(long) 0);
 107.812 +  }
 107.813 +  return stream;		/* return stream to caller */
 107.814 +}
 107.815 +
 107.816 +/* NNTP close
 107.817 + * Accepts: MAIL stream
 107.818 + *	    option flags
 107.819 + */
 107.820 +
 107.821 +void nntp_mclose (MAILSTREAM *stream,long options)
 107.822 +{
 107.823 +  unsigned long i;
 107.824 +  MESSAGECACHE *elt;
 107.825 +  if (LOCAL) {			/* only if a file is open */
 107.826 +    nntp_check (stream);	/* dump final checkpoint */
 107.827 +    if (LOCAL->over_fmt) fs_give ((void **) &LOCAL->over_fmt);
 107.828 +    if (LOCAL->name) fs_give ((void **) &LOCAL->name);
 107.829 +    if (LOCAL->user) fs_give ((void **) &LOCAL->user);
 107.830 +    if (LOCAL->newsrc) fs_give ((void **) &LOCAL->newsrc);
 107.831 +    if (LOCAL->txt) fclose (LOCAL->txt);
 107.832 +				/* close NNTP connection */
 107.833 +    if (LOCAL->nntpstream) nntp_close (LOCAL->nntpstream);
 107.834 +    for (i = 1; i <= stream->nmsgs; i++)
 107.835 +      if ((elt = mail_elt (stream,i))->private.spare.ptr)
 107.836 +	fs_give ((void **) &elt->private.spare.ptr);
 107.837 +				/* nuke the local data */
 107.838 +    fs_give ((void **) &stream->local);
 107.839 +    stream->dtb = NIL;		/* log out the DTB */
 107.840 +  }
 107.841 +}
 107.842 +
 107.843 +/* NNTP fetch fast information
 107.844 + * Accepts: MAIL stream
 107.845 + *	    sequence
 107.846 + *	    option flags
 107.847 + * This is ugly and slow
 107.848 + */
 107.849 +
 107.850 +void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags)
 107.851 +{
 107.852 +  unsigned long i;
 107.853 +  MESSAGECACHE *elt;
 107.854 +				/* get sequence */
 107.855 +  if (stream && LOCAL && ((flags & FT_UID) ?
 107.856 +			  mail_uid_sequence (stream,sequence) :
 107.857 +			  mail_sequence (stream,sequence)))
 107.858 +    for (i = 1; i <= stream->nmsgs; i++) {
 107.859 +      if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) &&
 107.860 +	  !(elt->day && elt->rfc822_size)) {
 107.861 +	ENVELOPE **env = NIL;
 107.862 +	ENVELOPE *e = NIL;
 107.863 +	if (!stream->scache) env = &elt->private.msg.env;
 107.864 +	else if (stream->msgno == i) env = &stream->env;
 107.865 +	else env = &e;
 107.866 +	if (!*env || !elt->rfc822_size) {
 107.867 +	  STRING bs;
 107.868 +	  unsigned long hs;
 107.869 +	  char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
 107.870 +				/* need to make an envelope? */
 107.871 +	  if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
 107.872 +				       stream->dtb->flags);
 107.873 +				/* need message size too, ugh */
 107.874 +	  if (!elt->rfc822_size) {
 107.875 +	    (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
 107.876 +	    elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
 107.877 +	  }
 107.878 +	}
 107.879 +				/* if need date, have date in envelope? */
 107.880 +	if (!elt->day && *env && (*env)->date)
 107.881 +	  mail_parse_date (elt,(*env)->date);
 107.882 +				/* sigh, fill in bogus default */
 107.883 +	if (!elt->day) elt->day = elt->month = 1;
 107.884 +	mail_free_envelope (&e);
 107.885 +      }
 107.886 +    }
 107.887 +}
 107.888 +
 107.889 +/* NNTP fetch flags
 107.890 + * Accepts: MAIL stream
 107.891 + *	    sequence
 107.892 + *	    option flags
 107.893 + */
 107.894 +
 107.895 +void nntp_flags (MAILSTREAM *stream,char *sequence,long flags)
 107.896 +{
 107.897 +  unsigned long i;
 107.898 +  if ((flags & FT_UID) ?	/* validate all elts */
 107.899 +      mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))
 107.900 +    for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;
 107.901 +}
 107.902 +
 107.903 +/* NNTP fetch overview
 107.904 + * Accepts: MAIL stream, sequence bits set
 107.905 + *	    overview return function
 107.906 + * Returns: T if successful, NIL otherwise
 107.907 + */
 107.908 +
 107.909 +long nntp_overview (MAILSTREAM *stream,overview_t ofn)
 107.910 +{
 107.911 +  unsigned long i,j,k,uid;
 107.912 +  char c,*s,*t,*v,tmp[MAILTMPLEN];
 107.913 +  MESSAGECACHE *elt;
 107.914 +  OVERVIEW ov;
 107.915 +  if (!LOCAL->nntpstream->netstream) return NIL;
 107.916 +				/* scan sequence to load cache */
 107.917 +  for (i = 1; i <= stream->nmsgs; i++)
 107.918 +				/* have cached overview yet? */
 107.919 +    if ((elt = mail_elt (stream,i))->sequence && !elt->private.spare.ptr) {
 107.920 +      for (j = i + 1;		/* no, find end of cache gap range */
 107.921 +	   (j <= stream->nmsgs) && (elt = mail_elt (stream,j))->sequence &&
 107.922 +	   !elt->private.spare.ptr; j++);
 107.923 +				/* make NNTP range */
 107.924 +      sprintf (tmp,(i == (j - 1)) ? "%lu" : "%lu-%lu",mail_uid (stream,i),
 107.925 +	       mail_uid (stream,j - 1));
 107.926 +      i = j;			/* advance beyond gap */
 107.927 +				/* ask server for overview data to cache */
 107.928 +      if (nntp_over (stream,tmp)) {
 107.929 +	while ((s = net_getline (LOCAL->nntpstream->netstream)) &&
 107.930 +	       strcmp (s,".")) {
 107.931 +				/* death to embedded newlines */
 107.932 +	  for (t = v = s; c = *v++;)
 107.933 +	    if ((c != '\012') && (c != '\015')) *t++ = c;
 107.934 +	  *t++ = '\0';		/* tie off string in case it was shortened */
 107.935 +				/* cache the overview if found its sequence */
 107.936 +	  if ((uid = atol (s)) && (k = mail_msgno (stream,uid)) &&
 107.937 +	      (t = strchr (s,'\t'))) {
 107.938 +	    if ((elt = mail_elt (stream,k))->private.spare.ptr)
 107.939 +	      fs_give ((void **) &elt->private.spare.ptr);
 107.940 +	    elt->private.spare.ptr = cpystr (t + 1);
 107.941 +	  }
 107.942 +	  else {		/* shouldn't happen, snarl if it does */
 107.943 +	    sprintf (tmp,"Server returned data for unknown UID %lu",uid);
 107.944 +	    mm_notify (stream,tmp,WARN);
 107.945 +	    stream->unhealthy = T;
 107.946 +	  }
 107.947 +				/* flush the overview */
 107.948 +	  fs_give ((void **) &s);
 107.949 +	}
 107.950 +	stream->unhealthy = NIL;/* set healthy */
 107.951 +				/* flush the terminating dot */
 107.952 +	if (s) fs_give ((void **) &s);
 107.953 +      }
 107.954 +      else i = stream->nmsgs;	/* OVER failed, punt cache load */
 107.955 +    }
 107.956 +
 107.957 +				/* now scan sequence to return overviews */
 107.958 +  if (ofn) for (i = 1; i <= stream->nmsgs; i++)
 107.959 +    if ((elt = mail_elt (stream,i))->sequence) {
 107.960 +      uid = mail_uid (stream,i);/* UID for this message */
 107.961 +				/* parse cached overview */
 107.962 +      if (nntp_parse_overview (&ov,s = (char *) elt->private.spare.ptr,elt))
 107.963 +	(*ofn) (stream,uid,&ov,i);
 107.964 +      else {			/* parse failed */
 107.965 +	(*ofn) (stream,uid,NIL,i);
 107.966 +	if (s && *s) {		/* unusable cached entry? */
 107.967 +	  sprintf (tmp,"Unable to parse overview for UID %lu: %.500s",uid,s);
 107.968 +	  mm_notify (stream,tmp,WARN);
 107.969 +	  stream->unhealthy = T;
 107.970 +				/* erase it from the cache */
 107.971 +	  fs_give ((void **) &s);
 107.972 +	}
 107.973 +	stream->unhealthy = NIL;/* set healthy */
 107.974 +				/* insert empty cached text as necessary */
 107.975 +	if (!s) elt->private.spare.ptr = cpystr ("");
 107.976 +      }
 107.977 +				/* clean up overview data */
 107.978 +      if (ov.from) mail_free_address (&ov.from);
 107.979 +      if (ov.subject) fs_give ((void **) &ov.subject);
 107.980 +    }
 107.981 +  return T;
 107.982 +}
 107.983 +
 107.984 +/* Send OVER to NNTP server
 107.985 + * Accepts: mail stream
 107.986 + *	    sequence to send
 107.987 + * Returns: T if success and overviews will follow, else NIL
 107.988 + */
 107.989 +
 107.990 +long nntp_over (MAILSTREAM *stream,char *sequence)
 107.991 +{
 107.992 +  unsigned char *s;
 107.993 +				/* test for Netscape Collabra server */
 107.994 +  if (EXTENSION.over && LOCAL->xover &&
 107.995 +      nntp_send (LOCAL->nntpstream,"OVER","0") == NNTPOVER) {
 107.996 +    /* "Netscape-Collabra/3.52 03615 NNTP" responds to the OVER command with
 107.997 +     * a bogus "Subject:From:Date:Bytes:Lines" response followed by overviews
 107.998 +     * which lack the Message-ID and References:.  This violates the draft
 107.999 +     * NNTP specification (draft-ietf-nntpext-base-18.txt as of this writing).
107.1000 +     * XOVER works fine.
107.1001 +     */
107.1002 +    while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){
107.1003 +      if (!isdigit (*s)) {	/* is it that fetid piece of reptile dung? */
107.1004 +	EXTENSION.over = NIL;	/* sure smells like it */
107.1005 +	mm_log ("Working around Netscape Collabra bug",WARN);
107.1006 +      }
107.1007 +      fs_give ((void **) &s);	/* flush the overview */
107.1008 +    }
107.1009 +    if (s) fs_give ((void **) &s);
107.1010 +				/* don't do this test again */
107.1011 +    if (EXTENSION.over) LOCAL->xover = NIL;
107.1012 +  }
107.1013 +  if (EXTENSION.over)		/* have OVER extension? */
107.1014 +    return (nntp_send (LOCAL->nntpstream,"OVER",sequence) == NNTPOVER) ?
107.1015 +      LONGT : NIL;
107.1016 +  if (LOCAL->xover)		/* try the experiment extension then */
107.1017 +    switch ((int) nntp_send (LOCAL->nntpstream,"XOVER",sequence)) {
107.1018 +    case NNTPOVER:		/* got an overview? */
107.1019 +      return LONGT;
107.1020 +    case NNTPBADCMD:		/* unknown command? */
107.1021 +      LOCAL->xover = NIL;	/* disable future XOVER attempts */
107.1022 +    }
107.1023 +  return NIL;
107.1024 +}
107.1025 +
107.1026 +/* Parse OVERVIEW struct from cached NNTP OVER response
107.1027 + * Accepts: struct to load
107.1028 + *	    cached OVER response
107.1029 + *	    internaldate
107.1030 + * Returns: T if success, NIL if fail
107.1031 + */
107.1032 +
107.1033 +long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt)
107.1034 +{
107.1035 +  char *t;
107.1036 +				/* nothing in overview yet */
107.1037 +  memset ((void *) ov,0,sizeof (OVERVIEW));
107.1038 +				/* no cached data */
107.1039 +  if (!(text && *text)) return NIL;
107.1040 +  ov->subject = cpystr (text);	/* make hackable copy of overview */
107.1041 +				/* find end of Subject */
107.1042 +  if (t = strchr (ov->subject,'\t')) {
107.1043 +    *t++ = '\0';		/* tie off Subject, point to From */
107.1044 +				/* find end of From */
107.1045 +    if (ov->date = strchr (t,'\t')) {
107.1046 +      *ov->date++ = '\0';	/* tie off From, point to Date */
107.1047 +				/* load internaldate too */
107.1048 +      if (!elt->day) mail_parse_date (elt,ov->date);
107.1049 +				/* parse From */
107.1050 +      rfc822_parse_adrlist (&ov->from,t,BADHOST);
107.1051 +				/* find end of Date */
107.1052 +      if (ov->message_id = strchr (ov->date,'\t')) {
107.1053 +				/* tie off Date, point to Message-ID */
107.1054 +	*ov->message_id++ = '\0';
107.1055 +				/* find end of Message-ID */
107.1056 +	if (ov->references = strchr (ov->message_id,'\t')) {
107.1057 +				/* tie off Message-ID, point to References */
107.1058 +	  *ov->references++ = '\0';
107.1059 +				/* fine end of References */
107.1060 +	  if (t = strchr (ov->references,'\t')) {
107.1061 +	    *t++ = '\0';	/* tie off References, point to octet size */
107.1062 +				/* parse size of message in octets */
107.1063 +	    ov->optional.octets = atol (t);
107.1064 +				/* find end of size */
107.1065 +	    if (t = strchr (t,'\t')) {
107.1066 +				/* parse size of message in lines */
107.1067 +	      ov->optional.lines = atol (++t);
107.1068 +				/* find Xref */
107.1069 +	      if (ov->optional.xref = strchr (t,'\t'))
107.1070 +		*ov->optional.xref++ = '\0';
107.1071 +	    }
107.1072 +	  }
107.1073 +	}
107.1074 +      }
107.1075 +    }
107.1076 +  }
107.1077 +  return ov->references ? T : NIL;
107.1078 +}
107.1079 +
107.1080 +/* NNTP fetch header as text
107.1081 + * Accepts: mail stream
107.1082 + *	    message number
107.1083 + *	    pointer to return size
107.1084 + *	    flags
107.1085 + * Returns: header text
107.1086 + */
107.1087 +
107.1088 +char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
107.1089 +		   long flags)
107.1090 +{
107.1091 +  char tmp[MAILTMPLEN];
107.1092 +  MESSAGECACHE *elt;
107.1093 +  FILE *f;
107.1094 +  *size = 0;
107.1095 +  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return "";
107.1096 +				/* have header text? */
107.1097 +  if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) {
107.1098 +    sprintf (tmp,"%lu",mail_uid (stream,msgno));
107.1099 +				/* get header text */
107.1100 +    switch (nntp_send (LOCAL->nntpstream,"HEAD",tmp)) {
107.1101 +    case NNTPHEAD:
107.1102 +      if (f = netmsg_slurp (LOCAL->nntpstream->netstream,size,NIL)) {
107.1103 +	fread (elt->private.msg.header.text.data =
107.1104 +	       (unsigned char *) fs_get ((size_t) *size + 3),
107.1105 +	       (size_t) 1,(size_t) *size,f);
107.1106 +	fclose (f);		/* flush temp file */
107.1107 +				/* tie off header with extra CRLF and NUL */
107.1108 +	elt->private.msg.header.text.data[*size] = '\015';
107.1109 +	elt->private.msg.header.text.data[++*size] = '\012';
107.1110 +	elt->private.msg.header.text.data[++*size] = '\0';
107.1111 +	elt->private.msg.header.text.size = *size;
107.1112 +	elt->valid = T;		/* make elt valid now */
107.1113 +	break;
107.1114 +      }
107.1115 +				/* fall into default case */
107.1116 +    default:			/* failed, mark as deleted and empty */
107.1117 +      elt->valid = elt->deleted = T;
107.1118 +    case NNTPSOFTFATAL:		/* don't mark deleted if stream dead */
107.1119 +      *size = elt->private.msg.header.text.size = 0;
107.1120 +      break;
107.1121 +    }
107.1122 +  }
107.1123 +				/* just return size of text */
107.1124 +  else *size = elt->private.msg.header.text.size;
107.1125 +  return elt->private.msg.header.text.data ?
107.1126 +    (char *) elt->private.msg.header.text.data : "";
107.1127 +}
107.1128 +
107.1129 +/* NNTP fetch body
107.1130 + * Accepts: mail stream
107.1131 + *	    message number
107.1132 + *	    pointer to stringstruct to initialize
107.1133 + *	    flags
107.1134 + * Returns: T if successful, else NIL
107.1135 + */
107.1136 +
107.1137 +long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
107.1138 +{
107.1139 +  char tmp[MAILTMPLEN];
107.1140 +  MESSAGECACHE *elt;
107.1141 +  INIT (bs,mail_string,(void *) "",0);
107.1142 +  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL;
107.1143 +  elt = mail_elt (stream,msgno);
107.1144 +				/* different message, flush cache */
107.1145 +  if (LOCAL->txt && (LOCAL->msgno != msgno)) {
107.1146 +    fclose (LOCAL->txt);
107.1147 +    LOCAL->txt = NIL;
107.1148 +  }
107.1149 +  LOCAL->msgno = msgno;		/* note cached message */
107.1150 +  if (!LOCAL->txt) {		/* have file for this message? */
107.1151 +    sprintf (tmp,"%lu",elt->private.uid);
107.1152 +    switch (nntp_send (LOCAL->nntpstream,"BODY",tmp)) {
107.1153 +    case NNTPBODY:
107.1154 +      if (LOCAL->txt = netmsg_slurp (LOCAL->nntpstream->netstream,
107.1155 +				     &LOCAL->txtsize,NIL)) break;
107.1156 +				/* fall into default case */
107.1157 +    default:			/* failed, mark as deleted */
107.1158 +      elt->deleted = T;
107.1159 +    case NNTPSOFTFATAL:		/* don't mark deleted if stream dead */
107.1160 +      return NIL;
107.1161 +    }
107.1162 +  }
107.1163 +  if (!(flags & FT_PEEK)) {	/* mark seen if needed */
107.1164 +    elt->seen = T;
107.1165 +    mm_flags (stream,elt->msgno);
107.1166 +  }
107.1167 +  INIT (bs,file_string,(void *) LOCAL->txt,LOCAL->txtsize);
107.1168 +  return T;
107.1169 +}
107.1170 +
107.1171 +/* NNTP fetch article from message ID (for news: URL support)
107.1172 + * Accepts: mail stream
107.1173 + *	    message ID
107.1174 + *	    pointer to return total message size
107.1175 + *	    pointer to return file size
107.1176 + * Returns: FILE * to message if successful, else NIL
107.1177 + */
107.1178 +
107.1179 +FILE *nntp_article (MAILSTREAM *stream,char *msgid,unsigned long *size,
107.1180 +		    unsigned long *hsiz)
107.1181 +{
107.1182 +  return (nntp_send (LOCAL->nntpstream,"ARTICLE",msgid) == NNTPARTICLE) ?
107.1183 +    netmsg_slurp (LOCAL->nntpstream->netstream,size,hsiz) : NIL;
107.1184 +}
107.1185 +
107.1186 +
107.1187 +/* NNTP per-message modify flag
107.1188 + * Accepts: MAIL stream
107.1189 + *	    message cache element
107.1190 + */
107.1191 +
107.1192 +void nntp_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
107.1193 +{
107.1194 +  if (!LOCAL->dirty) {		/* only bother checking if not dirty yet */
107.1195 +    if (elt->valid) {		/* if done, see if deleted changed */
107.1196 +      if (elt->sequence != elt->deleted) LOCAL->dirty = T;
107.1197 +      elt->sequence = T;	/* leave the sequence set */
107.1198 +    }
107.1199 +				/* note current setting of deleted flag */
107.1200 +    else elt->sequence = elt->deleted;
107.1201 +  }
107.1202 +}
107.1203 +
107.1204 +/* NNTP search messages
107.1205 + * Accepts: mail stream
107.1206 + *	    character set
107.1207 + *	    search program
107.1208 + *	    option flags
107.1209 + * Returns: T on success, NIL on failure
107.1210 + */
107.1211 +
107.1212 +long nntp_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags)
107.1213 +{
107.1214 +  unsigned long i;
107.1215 +  MESSAGECACHE *elt;
107.1216 +  OVERVIEW ov;
107.1217 +  char *msg;
107.1218 +				/* make sure that charset is good */
107.1219 +  if (msg = utf8_badcharset (charset)) {
107.1220 +    MM_LOG (msg,ERROR);		/* output error */
107.1221 +    fs_give ((void **) &msg);
107.1222 +    return NIL;
107.1223 +  }
107.1224 +  utf8_searchpgm (pgm,charset);
107.1225 +  if (flags & SO_OVERVIEW) {	/* only if specified to use overview */
107.1226 +				/* identify messages that will be searched */
107.1227 +    for (i = 1; i <= stream->nmsgs; ++i)
107.1228 +      mail_elt (stream,i)->sequence = nntp_search_msg (stream,i,pgm,NIL);
107.1229 +    nntp_overview (stream,NIL);	/* load the overview cache */
107.1230 +  }
107.1231 +				/* init in case no overview at cleanup */
107.1232 +  memset ((void *) &ov,0,sizeof (OVERVIEW));
107.1233 +				/* otherwise do default search */
107.1234 +  for (i = 1; i <= stream->nmsgs; ++i) {
107.1235 +    if (((flags & SO_OVERVIEW) && ((elt = mail_elt (stream,i))->sequence) &&
107.1236 +	 nntp_parse_overview (&ov,(char *) elt->private.spare.ptr,elt)) ?
107.1237 +	nntp_search_msg (stream,i,pgm,&ov) :
107.1238 +	mail_search_msg (stream,i,NIL,pgm)) {
107.1239 +      if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i));
107.1240 +      else {			/* mark as searched, notify mail program */
107.1241 +	mail_elt (stream,i)->searched = T;
107.1242 +	if (!stream->silent) mm_searched (stream,i);
107.1243 +      }
107.1244 +    }
107.1245 +				/* clean up overview data */
107.1246 +    if (ov.from) mail_free_address (&ov.from);
107.1247 +    if (ov.subject) fs_give ((void **) &ov.subject);
107.1248 +  }
107.1249 +  return LONGT;
107.1250 +}
107.1251 +
107.1252 +/* NNTP search message
107.1253 + * Accepts: MAIL stream
107.1254 + *	    message number
107.1255 + *	    search program
107.1256 + *	    overview to search (NIL means preliminary pass)
107.1257 + * Returns: T if found, NIL otherwise
107.1258 + */
107.1259 +
107.1260 +long nntp_search_msg (MAILSTREAM *stream,unsigned long msgno,SEARCHPGM *pgm,
107.1261 +		      OVERVIEW *ov)
107.1262 +{
107.1263 +  unsigned short d;
107.1264 +  unsigned long now = (unsigned long) time (0);
107.1265 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
107.1266 +  SEARCHHEADER *hdr;
107.1267 +  SEARCHOR *or;
107.1268 +  SEARCHPGMLIST *not;
107.1269 +  if (pgm->msgno || pgm->uid) {	/* message set searches */
107.1270 +    SEARCHSET *set;
107.1271 +				/* message sequences */
107.1272 +    if (set = pgm->msgno) {	/* must be inside this sequence */
107.1273 +      while (set) {		/* run down until find matching range */
107.1274 +	if (set->last ? ((msgno < set->first) || (msgno > set->last)) :
107.1275 +	    msgno != set->first) set = set->next;
107.1276 +	else break;
107.1277 +      }
107.1278 +      if (!set) return NIL;	/* not found within sequence */
107.1279 +    }
107.1280 +    if (set = pgm->uid) {	/* must be inside this sequence */
107.1281 +      unsigned long uid = mail_uid (stream,msgno);
107.1282 +      while (set) {		/* run down until find matching range */
107.1283 +	if (set->last ? ((uid < set->first) || (uid > set->last)) :
107.1284 +	    uid != set->first) set = set->next;
107.1285 +	else break;
107.1286 +      }
107.1287 +      if (!set) return NIL;	/* not found within sequence */
107.1288 +    }
107.1289 +  }
107.1290 +
107.1291 +  /* Fast data searches */
107.1292 +				/* message flags */
107.1293 +  if ((pgm->answered && !elt->answered) ||
107.1294 +      (pgm->unanswered && elt->answered) ||
107.1295 +      (pgm->deleted && !elt->deleted) ||
107.1296 +      (pgm->undeleted && elt->deleted) ||
107.1297 +      (pgm->draft && !elt->draft) ||
107.1298 +      (pgm->undraft && elt->draft) ||
107.1299 +      (pgm->flagged && !elt->flagged) ||
107.1300 +      (pgm->unflagged && elt->flagged) ||
107.1301 +      (pgm->recent && !elt->recent) ||
107.1302 +      (pgm->old && elt->recent) ||
107.1303 +      (pgm->seen && !elt->seen) ||
107.1304 +      (pgm->unseen && elt->seen)) return NIL;
107.1305 +				/* keywords */
107.1306 +  if ((pgm->keyword && !mail_search_keyword (stream,elt,pgm->keyword,LONGT)) ||
107.1307 +      (pgm->unkeyword && mail_search_keyword (stream,elt,pgm->unkeyword,NIL)))
107.1308 +    return NIL;
107.1309 +  if (ov) {			/* only do this if real searching */
107.1310 +    MESSAGECACHE delt;
107.1311 +				/* size ranges */
107.1312 +    if ((pgm->larger && (ov->optional.octets <= pgm->larger)) ||
107.1313 +	(pgm->smaller && (ov->optional.octets >= pgm->smaller))) return NIL;
107.1314 +				/* date ranges */
107.1315 +    if ((pgm->sentbefore || pgm->senton || pgm->sentsince ||
107.1316 +	 pgm->before || pgm->on || pgm->since) &&
107.1317 +	(!mail_parse_date (&delt,ov->date) ||
107.1318 +	 !(d = mail_shortdate (delt.year,delt.month,delt.day)) ||
107.1319 +	 (pgm->sentbefore && (d >= pgm->sentbefore)) ||
107.1320 +	 (pgm->senton && (d != pgm->senton)) ||
107.1321 +	 (pgm->sentsince && (d < pgm->sentsince)) ||
107.1322 +	 (pgm->before && (d >= pgm->before)) ||
107.1323 +	 (pgm->on && (d != pgm->on)) ||
107.1324 +	 (pgm->since && (d < pgm->since)))) return NIL;
107.1325 +    if (pgm->older || pgm->younger) {
107.1326 +      unsigned long msgd = mail_longdate (elt);
107.1327 +      if (pgm->older && msgd > (now - pgm->older)) return NIL;
107.1328 +      if (pgm->younger && msgd < (now - pgm->younger)) return NIL;
107.1329 +    }
107.1330 +    if ((pgm->from && !mail_search_addr (ov->from,pgm->from)) ||
107.1331 +	(pgm->subject && !mail_search_header_text (ov->subject,pgm->subject))||
107.1332 +	(pgm->message_id &&
107.1333 +	 !mail_search_header_text (ov->message_id,pgm->message_id)) ||
107.1334 +	(pgm->references &&
107.1335 +	 !mail_search_header_text (ov->references,pgm->references)))
107.1336 +      return NIL;
107.1337 +
107.1338 +
107.1339 +				/* envelope searches */
107.1340 +    if (pgm->bcc || pgm->cc || pgm->to || pgm->return_path || pgm->sender ||
107.1341 +	pgm->reply_to || pgm->in_reply_to || pgm->newsgroups ||
107.1342 +	pgm->followup_to) {
107.1343 +      ENVELOPE *env = mail_fetchenvelope (stream,msgno);
107.1344 +      if (!env) return NIL;	/* no envelope obtained */
107.1345 +				/* search headers */
107.1346 +      if ((pgm->bcc && !mail_search_addr (env->bcc,pgm->bcc)) ||
107.1347 +	  (pgm->cc && !mail_search_addr (env->cc,pgm->cc)) ||
107.1348 +	  (pgm->to && !mail_search_addr (env->to,pgm->to)))
107.1349 +	return NIL;
107.1350 +      /* These criteria are not supported by IMAP and have to be emulated */
107.1351 +      if ((pgm->return_path &&
107.1352 +	   !mail_search_addr (env->return_path,pgm->return_path)) ||
107.1353 +	  (pgm->sender && !mail_search_addr (env->sender,pgm->sender)) ||
107.1354 +	  (pgm->reply_to && !mail_search_addr (env->reply_to,pgm->reply_to)) ||
107.1355 +	  (pgm->in_reply_to &&
107.1356 +	   !mail_search_header_text (env->in_reply_to,pgm->in_reply_to)) ||
107.1357 +	  (pgm->newsgroups &&
107.1358 +	   !mail_search_header_text (env->newsgroups,pgm->newsgroups)) ||
107.1359 +	  (pgm->followup_to &&
107.1360 +	   !mail_search_header_text (env->followup_to,pgm->followup_to)))
107.1361 +	return NIL;
107.1362 +    }
107.1363 +
107.1364 +				/* search header lines */
107.1365 +    for (hdr = pgm->header; hdr; hdr = hdr->next) {
107.1366 +      char *t,*e,*v;
107.1367 +      SIZEDTEXT s;
107.1368 +      STRINGLIST sth,stc;
107.1369 +      sth.next = stc.next = NIL;/* only one at a time */
107.1370 +      sth.text.data = hdr->line.data;
107.1371 +      sth.text.size = hdr->line.size;
107.1372 +				/* get the header text */
107.1373 +      if ((t = mail_fetch_header (stream,msgno,NIL,&sth,&s.size,
107.1374 +				  FT_INTERNAL | FT_PEEK)) && strchr (t,':')) {
107.1375 +	if (hdr->text.size) {	/* anything matches empty search string */
107.1376 +				/* non-empty, copy field data */
107.1377 +	  s.data = (unsigned char *) fs_get (s.size + 1);
107.1378 +				/* for each line */
107.1379 +	  for (v = (char *) s.data, e = t + s.size; t < e;) switch (*t) {
107.1380 +	  default:		/* non-continuation, skip leading field name */
107.1381 +	    while ((t < e) && (*t++ != ':'));
107.1382 +	    if ((t < e) && (*t == ':')) t++;
107.1383 +	  case '\t': case ' ':	/* copy field data  */
107.1384 +	    while ((t < e) && (*t != '\015') && (*t != '\012')) *v++ = *t++;
107.1385 +	    *v++ = '\n';	/* tie off line */
107.1386 +	    while (((*t == '\015') || (*t == '\012')) && (t < e)) t++;
107.1387 +	  }
107.1388 +				/* calculate true size */
107.1389 +	  s.size = v - (char *) s.data;
107.1390 +	  *v = '\0';		/* tie off results */
107.1391 +	  stc.text.data = hdr->text.data;
107.1392 +	  stc.text.size = hdr->text.size;
107.1393 +				/* search header */
107.1394 +	  if (mail_search_header (&s,&stc)) fs_give ((void **) &s.data);
107.1395 +	  else {		/* search failed */
107.1396 +	    fs_give ((void **) &s.data);
107.1397 +	    return NIL;
107.1398 +	  }
107.1399 +	}
107.1400 +      }
107.1401 +      else return NIL;		/* no matching header text */
107.1402 +    }
107.1403 +				/* search strings */
107.1404 +    if ((pgm->text &&
107.1405 +	 !mail_search_text (stream,msgno,NIL,pgm->text,LONGT))||
107.1406 +	(pgm->body && !mail_search_text (stream,msgno,NIL,pgm->body,NIL)))
107.1407 +      return NIL;
107.1408 +  }
107.1409 +				/* logical conditions */
107.1410 +  for (or = pgm->or; or; or = or->next)
107.1411 +    if (!(nntp_search_msg (stream,msgno,or->first,ov) ||
107.1412 +	  nntp_search_msg (stream,msgno,or->second,ov))) return NIL;
107.1413 +  for (not = pgm->not; not; not = not->next)
107.1414 +    if (nntp_search_msg (stream,msgno,not->pgm,ov)) return NIL;
107.1415 +  return T;
107.1416 +}
107.1417 +
107.1418 +/* NNTP sort messages
107.1419 + * Accepts: mail stream
107.1420 + *	    character set
107.1421 + *	    search program
107.1422 + *	    sort program
107.1423 + *	    option flags
107.1424 + * Returns: vector of sorted message sequences or NIL if error
107.1425 + */
107.1426 +
107.1427 +unsigned long *nntp_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
107.1428 +			  SORTPGM *pgm,long flags)
107.1429 +{
107.1430 +  unsigned long i,start,last;
107.1431 +  SORTCACHE **sc;
107.1432 +  mailcache_t mailcache = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
107.1433 +  unsigned long *ret = NIL;
107.1434 +  sortresults_t sr = (sortresults_t) mail_parameters (NIL,GET_SORTRESULTS,NIL);
107.1435 +  if (spg) {			/* only if a search needs to be done */
107.1436 +    int silent = stream->silent;
107.1437 +    stream->silent = T;		/* don't pass up mm_searched() events */
107.1438 +				/* search for messages */
107.1439 +    mail_search_full (stream,charset,spg,NIL);
107.1440 +    stream->silent = silent;	/* restore silence state */
107.1441 +  }
107.1442 +				/* initialize progress counters */
107.1443 +  pgm->nmsgs = pgm->progress.cached = 0;
107.1444 +				/* pass 1: count messages to sort */
107.1445 +  for (i = 1,start = last = 0; i <= stream->nmsgs; ++i)
107.1446 +    if (mail_elt (stream,i)->searched) {
107.1447 +      pgm->nmsgs++;
107.1448 +				/* have this in the sortcache already? */
107.1449 +      if (!((SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE))->date) {
107.1450 +				/* no, record as last message */
107.1451 +	last = mail_uid (stream,i);
107.1452 +				/* and as first too if needed */
107.1453 +	if (!start) start = last;
107.1454 +      }
107.1455 +    }
107.1456 +  if (pgm->nmsgs) {		/* pass 2: load sort cache */
107.1457 +    sc = nntp_sort_loadcache (stream,pgm,start,last,flags);
107.1458 +				/* pass 3: sort messages */
107.1459 +    if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags);
107.1460 +    fs_give ((void **) &sc);	/* don't need sort vector any more */
107.1461 +  }
107.1462 +				/* empty sort results */
107.1463 +  else ret = (unsigned long *) memset (fs_get (sizeof (unsigned long)),0,
107.1464 +				       sizeof (unsigned long));
107.1465 +				/* also return via callback if requested */
107.1466 +  if (sr) (*sr) (stream,ret,pgm->nmsgs);
107.1467 +  return ret;
107.1468 +}
107.1469 +
107.1470 +/* Mail load sortcache
107.1471 + * Accepts: mail stream, already searched
107.1472 + *	    sort program
107.1473 + *	    first UID to OVER
107.1474 + *	    last UID to OVER
107.1475 + *	    option flags
107.1476 + * Returns: vector of sortcache pointers matching search
107.1477 + */
107.1478 +
107.1479 +SORTCACHE **nntp_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm,
107.1480 +				 unsigned long start,unsigned long last,
107.1481 +				 long flags)
107.1482 +{
107.1483 +  unsigned long i;
107.1484 +  char c,*s,*t,*v,tmp[MAILTMPLEN];
107.1485 +  SORTPGM *pg;
107.1486 +  SORTCACHE **sc,*r;
107.1487 +  MESSAGECACHE telt;
107.1488 +  ADDRESS *adr = NIL;
107.1489 +  mailcache_t mailcache = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
107.1490 +				/* verify that the sortpgm is OK */
107.1491 +  for (pg = pgm; pg; pg = pg->next) switch (pg->function) {
107.1492 +  case SORTARRIVAL:		/* sort by arrival date */
107.1493 +  case SORTSIZE:		/* sort by message size */
107.1494 +  case SORTDATE:		/* sort by date */
107.1495 +  case SORTFROM:		/* sort by first from */
107.1496 +  case SORTSUBJECT:		/* sort by subject */
107.1497 +    break;
107.1498 +  case SORTTO:			/* sort by first to */
107.1499 +    mm_notify (stream,"[NNTPSORT] Can't do To-field sorting in NNTP",WARN);
107.1500 +    break;
107.1501 +  case SORTCC:			/* sort by first cc */
107.1502 +    mm_notify (stream,"[NNTPSORT] Can't do cc-field sorting in NNTP",WARN);
107.1503 +    break;
107.1504 +  default:
107.1505 +    fatal ("Unknown sort function");
107.1506 +  }
107.1507 +
107.1508 +  if (start) {			/* messages need to be loaded in sortcache? */
107.1509 +				/* yes, build range */
107.1510 +    if (start != last) sprintf (tmp,"%lu-%lu",start,last);
107.1511 +    else sprintf (tmp,"%lu",start);
107.1512 +				/* get it from the NNTP server */
107.1513 +    if (!nntp_over (stream,tmp)) return mail_sort_loadcache (stream,pgm);
107.1514 +    while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){
107.1515 +				/* death to embedded newlines */
107.1516 +      for (t = v = s; c = *v++;) if ((c != '\012') && (c != '\015')) *t++ = c;
107.1517 +      *t++ = '\0';		/* tie off resulting string */
107.1518 +				/* parse OVER response */
107.1519 +      if ((i = mail_msgno (stream,atol (s))) &&
107.1520 +	  (t = strchr (s,'\t')) && (v = strchr (++t,'\t'))) {
107.1521 +	*v++ = '\0';		/* tie off subject */
107.1522 +				/* put stripped subject in sortcache */
107.1523 +	r = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE);
107.1524 +	  r->refwd = mail_strip_subject (t,&r->subject);
107.1525 +	if (t = strchr (v,'\t')) {
107.1526 +	  *t++ = '\0';		/* tie off from */
107.1527 +	  if (adr = rfc822_parse_address (&adr,adr,&v,BADHOST,0)) {
107.1528 +	    r->from = adr->mailbox;
107.1529 +	    adr->mailbox = NIL;
107.1530 +	    mail_free_address (&adr);
107.1531 +	  }
107.1532 +	  if (v = strchr (t,'\t')) {
107.1533 +	    *v++ = '\0';	/* tie off date */
107.1534 +	    if (mail_parse_date (&telt,t)) r->date = mail_longdate (&telt);
107.1535 +	    if ((v = strchr (v,'\t')) && (v = strchr (++v,'\t')))
107.1536 +	      r->size = atol (++v);
107.1537 +	  }
107.1538 +	}
107.1539 +      }
107.1540 +      fs_give ((void **) &s);
107.1541 +    }
107.1542 +    if (s) fs_give ((void **) &s);
107.1543 +  }
107.1544 +
107.1545 +				/* calculate size of sortcache index */
107.1546 +  i = pgm->nmsgs * sizeof (SORTCACHE *);
107.1547 +				/* instantiate the index */
107.1548 +  sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i);
107.1549 +				/* see what needs to be loaded */
107.1550 +  for (i = 1; !pgm->abort && (i <= stream->nmsgs); i++)
107.1551 +    if ((mail_elt (stream,i))->searched) {
107.1552 +      sc[pgm->progress.cached++] =
107.1553 +	r = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE);
107.1554 +      r->pgm = pgm;	/* note sort program */
107.1555 +      r->num = (flags & SE_UID) ? mail_uid (stream,i) : i;
107.1556 +      if (!r->date) r->date = r->num;
107.1557 +      if (!r->arrival) r->arrival = mail_uid (stream,i);
107.1558 +      if (!r->size) r->size = 1;
107.1559 +      if (!r->from) r->from = cpystr ("");
107.1560 +      if (!r->to) r->to = cpystr ("");
107.1561 +      if (!r->cc) r->cc = cpystr ("");
107.1562 +      if (!r->subject) r->subject = cpystr ("");
107.1563 +    }
107.1564 +  return sc;
107.1565 +}
107.1566 +
107.1567 +
107.1568 +/* NNTP thread messages
107.1569 + * Accepts: mail stream
107.1570 + *	    thread type
107.1571 + *	    character set
107.1572 + *	    search program
107.1573 + *	    option flags
107.1574 + * Returns: thread node tree
107.1575 + */
107.1576 +
107.1577 +THREADNODE *nntp_thread (MAILSTREAM *stream,char *type,char *charset,
107.1578 +			 SEARCHPGM *spg,long flags)
107.1579 +{
107.1580 +  return mail_thread_msgs (stream,type,charset,spg,flags,nntp_sort);
107.1581 +}
107.1582 +
107.1583 +/* NNTP ping mailbox
107.1584 + * Accepts: MAIL stream
107.1585 + * Returns: T if stream alive, else NIL
107.1586 + */
107.1587 +
107.1588 +long nntp_ping (MAILSTREAM *stream)
107.1589 +{
107.1590 +  return (nntp_send (LOCAL->nntpstream,"STAT",NIL) != NNTPSOFTFATAL);
107.1591 +}
107.1592 +
107.1593 +
107.1594 +/* NNTP check mailbox
107.1595 + * Accepts: MAIL stream
107.1596 + */
107.1597 +
107.1598 +void nntp_check (MAILSTREAM *stream)
107.1599 +{
107.1600 +				/* never do if no updates */
107.1601 +  if (LOCAL->dirty) newsrc_write (LOCAL->name,stream);
107.1602 +  LOCAL->dirty = NIL;
107.1603 +}
107.1604 +
107.1605 +
107.1606 +/* NNTP expunge mailbox
107.1607 + * Accepts: MAIL stream
107.1608 + *	    sequence to expunge if non-NIL
107.1609 + *	    expunge options
107.1610 + * Returns: T if success, NIL if failure
107.1611 + */
107.1612 +
107.1613 +long nntp_expunge (MAILSTREAM *stream,char *sequence,long options)
107.1614 +{
107.1615 +  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
107.1616 +  return LONGT;
107.1617 +}
107.1618 +
107.1619 +/* NNTP copy message(s)
107.1620 + * Accepts: MAIL stream
107.1621 + *	    sequence
107.1622 + *	    destination mailbox
107.1623 + *	    option flags
107.1624 + * Returns: T if copy successful, else NIL
107.1625 + */
107.1626 +
107.1627 +long nntp_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
107.1628 +{
107.1629 +  mailproxycopy_t pc =
107.1630 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
107.1631 +  if (pc) return (*pc) (stream,sequence,mailbox,options);
107.1632 +  mm_log ("Copy not valid for NNTP",ERROR);
107.1633 +  return NIL;
107.1634 +}
107.1635 +
107.1636 +
107.1637 +/* NNTP append message from stringstruct
107.1638 + * Accepts: MAIL stream
107.1639 + *	    destination mailbox
107.1640 + *	    append callback
107.1641 + *	    data for callback
107.1642 + * Returns: T if append successful, else NIL
107.1643 + */
107.1644 +
107.1645 +long nntp_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
107.1646 +{
107.1647 +  mm_log ("Append not valid for NNTP",ERROR);
107.1648 +  return NIL;
107.1649 +}
107.1650 +
107.1651 +/* NNTP open connection
107.1652 + * Accepts: network driver
107.1653 + *	    service host list
107.1654 + *	    port number
107.1655 + *	    service name
107.1656 + *	    NNTP open options
107.1657 + * Returns: SEND stream on success, NIL on failure
107.1658 + */
107.1659 +
107.1660 +SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service,
107.1661 +			    unsigned long port,long options)
107.1662 +{
107.1663 +  SENDSTREAM *stream = NIL;
107.1664 +  NETSTREAM *netstream = NIL;
107.1665 +  NETMBX mb;
107.1666 +  char tmp[MAILTMPLEN];
107.1667 +  long extok = LONGT;
107.1668 +  NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL);
107.1669 +  sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL);
107.1670 +  if (!(hostlist && *hostlist)) mm_log ("Missing NNTP service host",ERROR);
107.1671 +  else do {			/* try to open connection */
107.1672 +    sprintf (tmp,"{%.200s/%.20s}",*hostlist,service ? service : "nntp");
107.1673 +    if (!mail_valid_net_parse (tmp,&mb) || mb.anoflag) {
107.1674 +      sprintf (tmp,"Invalid host specifier: %.80s",*hostlist);
107.1675 +      mm_log (tmp,ERROR);
107.1676 +    }
107.1677 +    else {			/* light tryssl flag if requested */
107.1678 +      mb.trysslflag = (options & NOP_TRYSSL) ? T : NIL;
107.1679 +				/* default port */
107.1680 +      if (mb.port) port = mb.port;
107.1681 +      else if (!port) port = nntp_port ? nntp_port : NNTPTCPPORT;
107.1682 +      if (netstream =		/* try to open ordinary connection */
107.1683 +	  net_open (&mb,dv,port,
107.1684 +		    (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
107.1685 +		    "*nntps",nntp_sslport ? nntp_sslport : NNTPSSLPORT)) {
107.1686 +	stream = (SENDSTREAM *) fs_get (sizeof (SENDSTREAM));
107.1687 +				/* initialize stream */
107.1688 +	memset ((void *) stream,0,sizeof (SENDSTREAM));
107.1689 +	stream->netstream = netstream;
107.1690 +	stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
107.1691 +			       net_host (netstream) : mb.host);
107.1692 +	stream->debug = (mb.dbgflag || (options & NOP_DEBUG)) ? T : NIL;
107.1693 +	if (mb.loser) stream->loser = T;
107.1694 +				/* process greeting */
107.1695 +	switch ((int) nntp_reply (stream)) {
107.1696 +	case NNTPGREET:		/* allow posting */
107.1697 +	  NNTP.post = T;
107.1698 +	  mm_notify (NIL,stream->reply + 4,(long) NIL);
107.1699 +	  break;
107.1700 +	case NNTPGREETNOPOST:	/* posting not allowed, must be readonly */
107.1701 +	  NNTP.post = NIL;
107.1702 +	  break;
107.1703 +	default:
107.1704 +	  mm_log (stream->reply,ERROR);
107.1705 +	  stream = nntp_close (stream);
107.1706 +	  break;
107.1707 +	}
107.1708 +      }
107.1709 +    }
107.1710 +  } while (!stream && *++hostlist);
107.1711 +
107.1712 +				/* get extensions */
107.1713 +  if (stream && extok)
107.1714 +    extok = nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) |
107.1715 +			     (mb.authuser[0] ? AU_AUTHUSER : NIL));
107.1716 +  if (stream && !dv && stls && NNTP.ext.starttls &&
107.1717 +      !mb.sslflag && !mb.notlsflag &&
107.1718 +      (nntp_send_work (stream,"STARTTLS",NNTP.ext.multidomain ? mb.host : NIL)
107.1719 +       == NNTPTLSSTART)) {
107.1720 +    mb.tlsflag = T;		/* TLS OK, get into TLS at this end */
107.1721 +    stream->netstream->dtb = ssld;
107.1722 +				/* negotiate TLS */
107.1723 +    if (stream->netstream->stream =
107.1724 +	(*stls) (stream->netstream->stream,mb.host,
107.1725 +		 (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
107.1726 +		 (mb.novalidate ? NET_NOVALIDATECERT:NIL)))
107.1727 +      extok = nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) |
107.1728 +			       (mb.authuser[0] ? AU_AUTHUSER : NIL));
107.1729 +    else {
107.1730 +      sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",mb.host);
107.1731 +      mm_log (tmp,ERROR);
107.1732 +				/* close without doing QUIT */
107.1733 +      if (stream->netstream) net_close (stream->netstream);
107.1734 +      stream->netstream = NIL;
107.1735 +      stream = nntp_close (stream);
107.1736 +    }
107.1737 +  }
107.1738 +  else if (mb.tlsflag) {	/* user specified /tls but can't do it */
107.1739 +    mm_log ("Unable to negotiate TLS with this server",ERROR);
107.1740 +    return NIL;
107.1741 +  }
107.1742 +  if (stream) {			/* have a session? */
107.1743 +    if (mb.user[0]) {		/* yes, have user name? */
107.1744 +      if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
107.1745 +				/* remote name for authentication */
107.1746 +	strncpy (mb.host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
107.1747 +		 net_remotehost (netstream) : net_host (netstream),
107.1748 +		 NETMAXHOST-1);
107.1749 +	mb.host[NETMAXHOST-1] = '\0';
107.1750 +      }
107.1751 +      if (!nntp_send_auth_work (stream,&mb,tmp,NIL))
107.1752 +	stream = nntp_close (stream);
107.1753 +    }
107.1754 +				/* authenticate if no-post and not readonly */
107.1755 +    else if (!(NNTP.post || (options & NOP_READONLY) ||
107.1756 +	       nntp_send_auth (stream,NIL))) stream = nntp_close (stream);
107.1757 +  }
107.1758 +
107.1759 +				/* in case server demands MODE READER */
107.1760 +  if (stream) switch ((int) nntp_send_work (stream,"MODE","READER")) {
107.1761 +  case NNTPGREET:
107.1762 +    NNTP.post = T;
107.1763 +    break;
107.1764 +  case NNTPGREETNOPOST:
107.1765 +    NNTP.post = NIL;
107.1766 +    break;
107.1767 +  case NNTPWANTAUTH:		/* server wants auth first, do so and retry */
107.1768 +  case NNTPWANTAUTH2:		/* remote name for authentication */
107.1769 +    if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
107.1770 +      strncpy (mb.host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
107.1771 +	       net_remotehost (netstream) : net_host (netstream),NETMAXHOST-1);
107.1772 +      mb.host[NETMAXHOST-1] = '\0';
107.1773 +    }
107.1774 +    if (nntp_send_auth_work (stream,&mb,tmp,NIL))
107.1775 +      switch ((int) nntp_send (stream,"MODE","READER")) {
107.1776 +      case NNTPGREET:
107.1777 +	NNTP.post = T;
107.1778 +	break;
107.1779 +      case NNTPGREETNOPOST:
107.1780 +	NNTP.post = NIL;
107.1781 +	break;
107.1782 +      }
107.1783 +    else stream = nntp_close (stream);
107.1784 +    break;
107.1785 +  }
107.1786 +  if (stream) {			/* looks like we have a stream? */
107.1787 +				/* yes, make sure can post if not readonly */
107.1788 +    if (!(NNTP.post || (options & NOP_READONLY))) stream = nntp_close (stream);
107.1789 +    else if (extok) nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) |
107.1790 +				     (mb.authuser[0] ? AU_AUTHUSER : NIL));
107.1791 +  }
107.1792 +  return stream;
107.1793 +}
107.1794 +
107.1795 +/* NNTP extensions
107.1796 + * Accepts: stream
107.1797 + *	    authenticator flags
107.1798 + * Returns: T on success, NIL on failure
107.1799 + */
107.1800 +
107.1801 +long nntp_extensions (SENDSTREAM *stream,long flags)
107.1802 +{
107.1803 +  unsigned long i;
107.1804 +  char *t,*r,*args;
107.1805 +				/* zap all old extensions */
107.1806 +  memset (&NNTP.ext,0,sizeof (NNTP.ext));
107.1807 +  if (stream->loser) return NIL;/* nothing at all for losers */
107.1808 +				/* get server extensions */
107.1809 +  switch ((int) nntp_send_work (stream,"LIST","EXTENSIONS")) {
107.1810 +  case NNTPEXTOK:		/* what NNTP base spec says */
107.1811 +  case NNTPGLIST:		/* some servers do this instead */
107.1812 +    break;
107.1813 +  default:			/* no LIST EXTENSIONS on this server */
107.1814 +    return NIL;
107.1815 +  }
107.1816 +  NNTP.ext.ok = T;		/* server offers extensions */
107.1817 +  while ((t = net_getline (stream->netstream)) && (t[1] || (*t != '.'))) {
107.1818 +    if (stream->debug) mm_dlog (t);
107.1819 +				/* get optional capability arguments */
107.1820 +    if (args = strchr (t,' ')) *args++ = '\0';
107.1821 +    if (!compare_cstring (t,"LISTGROUP")) NNTP.ext.listgroup = T;
107.1822 +    else if (!compare_cstring (t,"OVER")) NNTP.ext.over = T;
107.1823 +    else if (!compare_cstring (t,"HDR")) NNTP.ext.hdr = T;
107.1824 +    else if (!compare_cstring (t,"PAT")) NNTP.ext.pat = T;
107.1825 +    else if (!compare_cstring (t,"STARTTLS")) NNTP.ext.starttls = T;
107.1826 +    else if (!compare_cstring (t,"MULTIDOMAIN")) NNTP.ext.multidomain = T;
107.1827 +
107.1828 +    else if (!compare_cstring (t,"AUTHINFO") && args) {
107.1829 +      char *sasl = NIL;
107.1830 +      for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r)) {
107.1831 +	if (!compare_cstring (args,"USER")) NNTP.ext.authuser = T;
107.1832 +	else if (((args[0] == 'S') || (args[0] == 's')) &&
107.1833 +		 ((args[1] == 'A') || (args[1] == 'a')) &&
107.1834 +		 ((args[2] == 'S') || (args[2] == 's')) &&
107.1835 +		 ((args[3] == 'L') || (args[3] == 'l')) && (args[4] == ':'))
107.1836 +	  sasl = args + 5;
107.1837 +      }
107.1838 +      if (sasl) {		/* if SASL, look up authenticators */
107.1839 +	for (sasl = strtok_r (sasl,",",&r); sasl; sasl = strtok_r (NIL,",",&r))
107.1840 +	  if ((i = mail_lookup_auth_name (sasl,flags)) &&
107.1841 +	      (--i < MAXAUTHENTICATORS))
107.1842 +	    NNTP.ext.sasl |= (1 << i);
107.1843 +				/* disable LOGIN if PLAIN also advertised */
107.1844 +	if ((i = mail_lookup_auth_name ("PLAIN",NIL)) &&
107.1845 +	    (--i < MAXAUTHENTICATORS) && (NNTP.ext.sasl & (1 << i)) &&
107.1846 +	    (i = mail_lookup_auth_name ("LOGIN",NIL)) &&
107.1847 +	    (--i < MAXAUTHENTICATORS)) NNTP.ext.sasl &= ~(1 << i);
107.1848 +      }
107.1849 +    }
107.1850 +    fs_give ((void **) &t);
107.1851 +  }
107.1852 +  if (t) {			/* flush end of text indicator */
107.1853 +    if (stream->debug) mm_dlog (t);
107.1854 +    fs_give ((void **) &t);
107.1855 +  }
107.1856 +  return LONGT;
107.1857 +}
107.1858 +
107.1859 +/* NNTP close connection
107.1860 + * Accepts: SEND stream
107.1861 + * Returns: NIL always
107.1862 + */
107.1863 +
107.1864 +SENDSTREAM *nntp_close (SENDSTREAM *stream)
107.1865 +{
107.1866 +  if (stream) {			/* send "QUIT" */
107.1867 +    if (stream->netstream) nntp_send (stream,"QUIT",NIL);
107.1868 +				/* do close actions */
107.1869 +    if (stream->netstream) net_close (stream->netstream);
107.1870 +    if (stream->host) fs_give ((void **) &stream->host);
107.1871 +    if (stream->reply) fs_give ((void **) &stream->reply);
107.1872 +    fs_give ((void **) &stream);/* flush the stream */
107.1873 +  }
107.1874 +  return NIL;
107.1875 +}
107.1876 +
107.1877 +/* NNTP deliver news
107.1878 + * Accepts: SEND stream
107.1879 + *	    message envelope
107.1880 + *	    message body
107.1881 + * Returns: T on success, NIL on failure
107.1882 + */
107.1883 +
107.1884 +long nntp_mail (SENDSTREAM *stream,ENVELOPE *env,BODY *body)
107.1885 +{
107.1886 +  long ret;
107.1887 +  RFC822BUFFER buf;
107.1888 +  char *s,path[MAILTMPLEN],tmp[SENDBUFLEN+1];
107.1889 +  long error = NIL;
107.1890 +  long retry = NIL;
107.1891 +  buf.f = nntp_soutr;		/* initialize buffer */
107.1892 +  buf.s = stream->netstream;
107.1893 +  buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
107.1894 +  tmp[SENDBUFLEN] = '\0';	/* must have additional null guard byte */
107.1895 +  /* Gabba gabba hey, we need some brain damage to send netnews!!!
107.1896 +   *
107.1897 +   * First, we give ourselves a frontal lobotomy, and put in some UUCP
107.1898 +   *  syntax.  It doesn't matter that it's completely bogus UUCP, and
107.1899 +   *  that UUCP has nothing to do with anything we're doing.  It's been
107.1900 +   *  alleged that "Path: not-for-mail" is also acceptable, but we won't
107.1901 +   *  make assumptions unless the user says so.
107.1902 +   *
107.1903 +   * Second, we bop ourselves on the head with a ball-peen hammer.  How
107.1904 +   *  dare we be so presumptious as to insert a *comment* in a Date:
107.1905 +   *  header line.  Why, we were actually trying to be nice to a human
107.1906 +   *  by giving a symbolic timezone (such as PST) in addition to a
107.1907 +   *  numeric timezone (such as -0800).  But the gods of news transport
107.1908 +   *  will have none of this.  Unix weenies, tried and true, rule!!!
107.1909 +   *
107.1910 +   * Third, Netscape Collabra server doesn't give the NNTPWANTAUTH error
107.1911 +   *  until after requesting and receiving the entire message.  So we can't
107.1912 +   *  call rely upon nntp_send() to do the auth retry.
107.1913 +   */
107.1914 +				/* RFC-1036 requires this cretinism */
107.1915 +  sprintf (path,"Path: %s!%s\015\012",net_localhost (stream->netstream),
107.1916 +	   env->sender ? env->sender->mailbox :
107.1917 +	   (env->from ? env->from->mailbox : "not-for-mail"));
107.1918 +				/* here's another cretinism */
107.1919 +  if (s = strstr (env->date," (")) *s = NIL;
107.1920 +  do if ((ret = nntp_send_work (stream,"POST",NIL)) == NNTPREADY)
107.1921 +				/* output data, return success status */
107.1922 +    ret = (net_soutr (stream->netstream,
107.1923 +		      nntp_hidepath ? "Path: not-for-mail\015\012" : path) &&
107.1924 +	   rfc822_output_full (&buf,env,body,T)) ?
107.1925 +      nntp_send_work (stream,".",NIL) :
107.1926 +      nntp_fake (stream,"NNTP connection broken (message text)");
107.1927 +  while (((ret == NNTPWANTAUTH) || (ret == NNTPWANTAUTH2)) &&
107.1928 +	 nntp_send_auth (stream,LONGT));
107.1929 +  if (s) *s = ' ';		/* put the comment in the date back */
107.1930 +  if (ret == NNTPOK) return LONGT;
107.1931 +  else if (ret < 400) {		/* if not an error reply */
107.1932 +    sprintf (tmp,"Unexpected NNTP posting reply code %ld",ret);
107.1933 +    mm_log (tmp,WARN);		/* so someone looks at this eventually */
107.1934 +    if ((ret >= 200) && (ret < 300)) return LONGT;
107.1935 +  }
107.1936 +  return NIL;
107.1937 +}
107.1938 +
107.1939 +/* NNTP send command
107.1940 + * Accepts: SEND stream
107.1941 + *	    text
107.1942 + * Returns: reply code
107.1943 + */
107.1944 +
107.1945 +long nntp_send (SENDSTREAM *stream,char *command,char *args)
107.1946 +{
107.1947 +  long ret;
107.1948 +  switch ((int) (ret = nntp_send_work (stream,command,args))) {
107.1949 +  case NNTPWANTAUTH:		/* authenticate and retry */
107.1950 +  case NNTPWANTAUTH2:
107.1951 +    if (nntp_send_auth (stream,LONGT))
107.1952 +      ret = nntp_send_work (stream,command,args);
107.1953 +    else {			/* we're probably hosed, nuke the session */
107.1954 +      nntp_send (stream,"QUIT",NIL);
107.1955 +				/* close net connection */
107.1956 +      if (stream->netstream) net_close (stream->netstream);
107.1957 +      stream->netstream = NIL;
107.1958 +    }
107.1959 +  default:			/* all others just return */
107.1960 +    break;
107.1961 +  }
107.1962 +  return ret;
107.1963 +}
107.1964 +
107.1965 +
107.1966 +/* NNTP send command worker routine
107.1967 + * Accepts: SEND stream
107.1968 + *	    text
107.1969 + * Returns: reply code
107.1970 + */
107.1971 +
107.1972 +long nntp_send_work (SENDSTREAM *stream,char *command,char *args)
107.1973 +{
107.1974 +  long ret;
107.1975 +  char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0)
107.1976 +			     + 3);
107.1977 +  if (!stream->netstream) ret = nntp_fake (stream,"NNTP connection lost");
107.1978 +  else {			/* build the complete command */
107.1979 +    if (args) sprintf (s,"%s %s",command,args);
107.1980 +    else strcpy (s,command);
107.1981 +    if (stream->debug) mail_dlog (s,stream->sensitive);
107.1982 +    strcat (s,"\015\012");
107.1983 +				/* send the command */
107.1984 +    ret = net_soutr (stream->netstream,s) ? nntp_reply (stream) :
107.1985 +      nntp_fake (stream,"NNTP connection broken (command)");
107.1986 +  }
107.1987 +  fs_give ((void **) &s);
107.1988 +  return ret;
107.1989 +}
107.1990 +
107.1991 +/* NNTP send authentication if needed
107.1992 + * Accepts: SEND stream
107.1993 + *	    flags (non-NIL to get new extensions)
107.1994 + * Returns: T if need to redo command, NIL otherwise
107.1995 + */
107.1996 +
107.1997 +long nntp_send_auth (SENDSTREAM *stream,long flags)
107.1998 +{
107.1999 +  NETMBX mb;
107.2000 +  char tmp[MAILTMPLEN];
107.2001 +				/* remote name for authentication */
107.2002 +  sprintf (tmp,"{%.200s/nntp",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
107.2003 +	   ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
107.2004 +	    net_remotehost (stream->netstream) : net_host (stream->netstream)):
107.2005 +	   stream->host);
107.2006 +  if (stream->netstream->dtb ==
107.2007 +      (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL))
107.2008 +    strcat (tmp,"/ssl");
107.2009 +  strcat (tmp,"}<none>");
107.2010 +  mail_valid_net_parse (tmp,&mb);
107.2011 +  return nntp_send_auth_work (stream,&mb,tmp,flags);
107.2012 +}
107.2013 +
107.2014 +/* NNTP send authentication worker routine
107.2015 + * Accepts: SEND stream
107.2016 + *	    NETMBX structure
107.2017 + *	    scratch buffer of length MAILTMPLEN
107.2018 + *	    flags (non-NIL to get new extensions)
107.2019 + * Returns: T if authenticated, NIL otherwise
107.2020 + */
107.2021 +
107.2022 +long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags)
107.2023 +{
107.2024 +  unsigned long trial,auths;
107.2025 +  char tmp[MAILTMPLEN],usr[MAILTMPLEN];
107.2026 +  AUTHENTICATOR *at;
107.2027 +  char *lsterr = NIL;
107.2028 +  long ret = NIL;
107.2029 +				/* try SASL first */
107.2030 +  for (auths = NNTP.ext.sasl, stream->saslcancel = NIL;
107.2031 +       !ret && stream->netstream && auths &&
107.2032 +       (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) {
107.2033 +    if (lsterr) {		/* previous authenticator failed? */
107.2034 +      sprintf (tmp,"Retrying using %s authentication after %.80s",
107.2035 +	       at->name,lsterr);
107.2036 +      mm_log (tmp,NIL);
107.2037 +      fs_give ((void **) &lsterr);
107.2038 +    }
107.2039 +    trial = 0;			/* initial trial count */
107.2040 +    tmp[0] = '\0';		/* empty buffer */
107.2041 +    if (stream->netstream) do {
107.2042 +      if (lsterr) {
107.2043 +	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
107.2044 +	mm_log (tmp,WARN);
107.2045 +	fs_give ((void **) &lsterr);
107.2046 +      }
107.2047 +      stream->saslcancel = NIL;
107.2048 +      if (nntp_send (stream,"AUTHINFO SASL",at->name) == NNTPCHALLENGE) {
107.2049 +				/* hide client authentication responses */
107.2050 +	if (!(at->flags & AU_SECURE)) stream->sensitive = T;
107.2051 +	if ((*at->client) (nntp_challenge,nntp_response,"nntp",mb,stream,
107.2052 +			   &trial,usr)) {
107.2053 +	  if (stream->replycode == NNTPAUTHED) ret = LONGT;
107.2054 +				/* if main program requested cancellation */
107.2055 +	  else if (!trial) mm_log ("NNTP Authentication cancelled",ERROR);
107.2056 +	}
107.2057 +	stream->sensitive = NIL;/* unhide */
107.2058 +      }
107.2059 +				/* remember response if error and no cancel */
107.2060 +      if (!ret && trial) lsterr = cpystr (stream->reply);
107.2061 +    } while (!ret && stream->netstream && trial &&
107.2062 +	     (trial < nntp_maxlogintrials));
107.2063 +  }
107.2064 +
107.2065 +  if (lsterr) {			/* SAIL failed? */
107.2066 +    if (!stream->saslcancel) {	/* don't do this if a cancel */
107.2067 +      sprintf (tmp,"Can not authenticate to NNTP server: %.80s",lsterr);
107.2068 +      mm_log (tmp,ERROR);
107.2069 +    }
107.2070 +    fs_give ((void **) &lsterr);
107.2071 +  }
107.2072 +  else if (mb->secflag)		/* no SASL, can't do /secure */
107.2073 +    mm_log ("Can't do secure authentication with this server",ERROR);
107.2074 +  else if (mb->authuser[0])	/* or /authuser */
107.2075 +    mm_log ("Can't do /authuser with this server",ERROR);
107.2076 +  /* Always try AUTHINFO USER, even if NNTP.ext.authuser isn't set.  There
107.2077 +   * are servers that require it but don't return it as an extension.
107.2078 +   */
107.2079 +  else for (trial = 0, pwd[0] = 'x';
107.2080 +	    !ret && pwd[0] && (trial < nntp_maxlogintrials) &&
107.2081 +	      stream->netstream; ) {
107.2082 +    pwd[0] = NIL;		/* get user name and password */
107.2083 +    mm_login (mb,usr,pwd,trial++);
107.2084 +				/* do the authentication */
107.2085 +    if (pwd[0]) switch ((int) nntp_send_work (stream,"AUTHINFO USER",usr)) {
107.2086 +    case NNTPBADCMD:		/* give up if unrecognized command */
107.2087 +      mm_log (NNTP.ext.authuser ? stream->reply :
107.2088 +	      "Can't do AUTHINFO USER to this server",ERROR);
107.2089 +      trial = nntp_maxlogintrials;
107.2090 +      break;
107.2091 +    case NNTPAUTHED:		/* successful authentication */
107.2092 +      ret = LONGT;		/* guess no password was needed */
107.2093 +      break;
107.2094 +    case NNTPWANTPASS:		/* wants password */
107.2095 +      stream->sensitive = T;	/* hide this command */
107.2096 +      if (nntp_send_work (stream,"AUTHINFO PASS",pwd) == NNTPAUTHED)
107.2097 +	ret = LONGT;		/* password OK */
107.2098 +      stream->sensitive = NIL;	/* unhide */
107.2099 +      if (ret) break;		/* OK if successful */
107.2100 +    default:			/* authentication failed */
107.2101 +      mm_log (stream->reply,WARN);
107.2102 +      if (trial == nntp_maxlogintrials)
107.2103 +	mm_log ("Too many NNTP authentication failures",ERROR);
107.2104 +    }
107.2105 +				/* user refused to give a password */
107.2106 +    else mm_log ("Login aborted",ERROR);
107.2107 +  }
107.2108 +  memset (pwd,0,MAILTMPLEN);	/* erase password */
107.2109 +				/* get new extensions if needed */
107.2110 +  if (ret && flags) nntp_extensions (stream,(mb->secflag ? AU_SECURE : NIL) |
107.2111 +				     (mb->authuser[0] ? AU_AUTHUSER : NIL));
107.2112 +  return ret;
107.2113 +}
107.2114 +
107.2115 +/* Get challenge to authenticator in binary
107.2116 + * Accepts: stream
107.2117 + *	    pointer to returned size
107.2118 + * Returns: challenge or NIL if not challenge
107.2119 + */
107.2120 +
107.2121 +void *nntp_challenge (void *s,unsigned long *len)
107.2122 +{
107.2123 +  char tmp[MAILTMPLEN];
107.2124 +  void *ret = NIL;
107.2125 +  SENDSTREAM *stream = (SENDSTREAM *) s;
107.2126 +  if ((stream->replycode == NNTPCHALLENGE) &&
107.2127 +      !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4,
107.2128 +			     strlen (stream->reply + 4),len))) {
107.2129 +    sprintf (tmp,"NNTP SERVER BUG (invalid challenge): %.80s",stream->reply+4);
107.2130 +    mm_log (tmp,ERROR);
107.2131 +  }
107.2132 +  return ret;
107.2133 +}
107.2134 +
107.2135 +
107.2136 +/* Send authenticator response in BASE64
107.2137 + * Accepts: MAIL stream
107.2138 + *	    string to send
107.2139 + *	    length of string
107.2140 + * Returns: T, always
107.2141 + */
107.2142 +
107.2143 +long nntp_response (void *s,char *response,unsigned long size)
107.2144 +{
107.2145 +  SENDSTREAM *stream = (SENDSTREAM *) s;
107.2146 +  unsigned long i,j;
107.2147 +  char *t,*u;
107.2148 +  if (response) {		/* make CRLFless BASE64 string */
107.2149 +    if (size) {
107.2150 +      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
107.2151 +	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
107.2152 +      *u = '\0';		/* tie off string */
107.2153 +      i = nntp_send_work (stream,t,NIL);
107.2154 +      fs_give ((void **) &t);
107.2155 +    }
107.2156 +    else i = nntp_send_work (stream,"",NIL);
107.2157 +  }
107.2158 +  else {			/* abort requested */
107.2159 +    i = nntp_send_work (stream,"*",NIL);
107.2160 +    stream->saslcancel = T;	/* mark protocol-requested SASL cancel */
107.2161 +  }
107.2162 +  return LONGT;
107.2163 +}
107.2164 +
107.2165 +/* NNTP get reply
107.2166 + * Accepts: SEND stream
107.2167 + * Returns: reply code
107.2168 + */
107.2169 +
107.2170 +long nntp_reply (SENDSTREAM *stream)
107.2171 +{
107.2172 +				/* flush old reply */
107.2173 +  if (stream->reply) fs_give ((void **) &stream->reply);
107.2174 +  				/* get reply */
107.2175 +  if (!(stream->reply = net_getline (stream->netstream)))
107.2176 +    return nntp_fake (stream,"NNTP connection broken (response)");
107.2177 +  if (stream->debug) mm_dlog (stream->reply);
107.2178 +				/* handle continuation by recursion */
107.2179 +  if (stream->reply[3] == '-') return nntp_reply (stream);
107.2180 +				/* return response code */
107.2181 +  return stream->replycode = atol (stream->reply);
107.2182 +}
107.2183 +
107.2184 +
107.2185 +/* NNTP set fake error
107.2186 + * Accepts: SEND stream
107.2187 + *	    error text
107.2188 + * Returns: error code
107.2189 + */
107.2190 +
107.2191 +long nntp_fake (SENDSTREAM *stream,char *text)
107.2192 +{
107.2193 +  if (stream->netstream) {	/* close net connection if still open */
107.2194 +    net_close (stream->netstream);
107.2195 +    stream->netstream = NIL;
107.2196 +  }
107.2197 +				/* flush any old reply */
107.2198 +  if (stream->reply) fs_give ((void **) &stream->reply);
107.2199 +  				/* set up pseudo-reply string */
107.2200 +  stream->reply = (char *) fs_get (20+strlen (text));
107.2201 +  sprintf (stream->reply,"%ld %s",NNTPSOFTFATAL,text);
107.2202 +  return NNTPSOFTFATAL;		/* return error code */
107.2203 +}
107.2204 +
107.2205 +/* NNTP filter mail
107.2206 + * Accepts: stream
107.2207 + *	    string
107.2208 + * Returns: T on success, NIL on failure
107.2209 + */
107.2210 +
107.2211 +long nntp_soutr (void *stream,char *s)
107.2212 +{
107.2213 +  char c,*t;
107.2214 +				/* "." on first line */
107.2215 +  if (s[0] == '.') net_soutr (stream,".");
107.2216 +				/* find lines beginning with a "." */
107.2217 +  while (t = strstr (s,"\015\012.")) {
107.2218 +    c = *(t += 3);		/* remember next character after "." */
107.2219 +    *t = '\0';			/* tie off string */
107.2220 +				/* output prefix */
107.2221 +    if (!net_soutr (stream,s)) return NIL;
107.2222 +    *t = c;			/* restore delimiter */
107.2223 +    s = t - 1;			/* push pointer up to the "." */
107.2224 +  }
107.2225 +				/* output remainder of text */
107.2226 +  return *s ? net_soutr (stream,s) : T;
107.2227 +}
   108.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   108.2 +++ b/src/c-client/nntp.h	Mon Sep 14 15:17:45 2009 +0900
   108.3 @@ -0,0 +1,56 @@
   108.4 +/* ========================================================================
   108.5 + * Copyright 1988-2006 University of Washington
   108.6 + *
   108.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   108.8 + * you may not use this file except in compliance with the License.
   108.9 + * You may obtain a copy of the License at
  108.10 + *
  108.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  108.12 + *
  108.13 + * 
  108.14 + * ========================================================================
  108.15 + */
  108.16 +
  108.17 +/*
  108.18 + * Program:	Network News Transfer Protocol (NNTP) routines
  108.19 + *
  108.20 + * Author:	Mark Crispin
  108.21 + *		Networks and Distributed Computing
  108.22 + *		Computing & Communications
  108.23 + *		University of Washington
  108.24 + *		Administration Building, AG-44
  108.25 + *		Seattle, WA  98195
  108.26 + *		Internet: MRC@CAC.Washington.EDU
  108.27 + *
  108.28 + * Date:	10 February 1992
  108.29 + * Last Edited:	30 August 2006
  108.30 + */
  108.31 +
  108.32 +/* Constants (should be in nntp.c) */
  108.33 +
  108.34 +#define NNTPTCPPORT (long) 119	/* assigned TCP contact port */
  108.35 +
  108.36 +
  108.37 +/* NNTP open options
  108.38 + * For compatibility with the past, NOP_DEBUG must always be 1.
  108.39 + */
  108.40 +
  108.41 +#define NOP_DEBUG (long) 0x1	/* debug protocol negotiations */
  108.42 +#define NOP_READONLY (long) 0x2	/* read-only open */
  108.43 +#define NOP_TRYSSL (long) 0x4	/* try SSL first */
  108.44 +				/* reserved for application use */
  108.45 +#define NOP_RESERVED (unsigned long) 0xff000000
  108.46 +
  108.47 +
  108.48 +/* Compatibility support names */
  108.49 +
  108.50 +#define nntp_open(hostlist,options) \
  108.51 +  nntp_open_full (NIL,hostlist,"nntp",NIL,options)
  108.52 +
  108.53 +
  108.54 +/* Function prototypes */
  108.55 +
  108.56 +SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service,
  108.57 +			    unsigned long port,long options);
  108.58 +SENDSTREAM *nntp_close (SENDSTREAM *stream);
  108.59 +long nntp_mail (SENDSTREAM *stream,ENVELOPE *msg,BODY *body);
   109.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   109.2 +++ b/src/c-client/pop3.c	Mon Sep 14 15:17:45 2009 +0900
   109.3 @@ -0,0 +1,1091 @@
   109.4 +/* ========================================================================
   109.5 + * Copyright 1988-2007 University of Washington
   109.6 + *
   109.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   109.8 + * you may not use this file except in compliance with the License.
   109.9 + * You may obtain a copy of the License at
  109.10 + *
  109.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  109.12 + *
  109.13 + * 
  109.14 + * ========================================================================
  109.15 + */
  109.16 +
  109.17 +/*
  109.18 + * Program:	Post Office Protocol 3 (POP3) client routines
  109.19 + *
  109.20 + * Author:	Mark Crispin
  109.21 + *		Networks and Distributed Computing
  109.22 + *		Computing & Communications
  109.23 + *		University of Washington
  109.24 + *		Administration Building, AG-44
  109.25 + *		Seattle, WA  98195
  109.26 + *		Internet: MRC@CAC.Washington.EDU
  109.27 + *
  109.28 + * Date:	6 June 1994
  109.29 + * Last Edited:	4 April 2007
  109.30 + */
  109.31 +
  109.32 +
  109.33 +#include <ctype.h>
  109.34 +#include <stdio.h>
  109.35 +#include <time.h>
  109.36 +#include "c-client.h"
  109.37 +#include "flstring.h"
  109.38 +#include "netmsg.h"
  109.39 +
  109.40 +/* Parameters */
  109.41 +
  109.42 +#define POP3TCPPORT (long) 110	/* assigned TCP contact port */
  109.43 +#define POP3SSLPORT (long) 995	/* assigned SSL TCP contact port */
  109.44 +#define IDLETIMEOUT (long) 10	/* defined in RFC 1939 */
  109.45 +
  109.46 +
  109.47 +/* POP3 I/O stream local data */
  109.48 +	
  109.49 +typedef struct pop3_local {
  109.50 +  NETSTREAM *netstream;		/* TCP I/O stream */
  109.51 +  char *response;		/* last server reply */
  109.52 +  char *reply;			/* text of last server reply */
  109.53 +  unsigned long cached;		/* current cached message uid */
  109.54 +  unsigned long hdrsize;	/* current cached header size */
  109.55 +  FILE *txt;			/* current cached file descriptor */
  109.56 +  struct {
  109.57 +    unsigned int capa : 1;	/* server has CAPA, definitely new */
  109.58 +    unsigned int expire : 1;	/* server has EXPIRE */
  109.59 +    unsigned int logindelay : 1;/* server has LOGIN-DELAY */
  109.60 +    unsigned int stls : 1;	/* server has STLS */
  109.61 +    unsigned int pipelining : 1;/* server has PIPELINING */
  109.62 +    unsigned int respcodes : 1;	/* server has RESP-CODES */
  109.63 +    unsigned int top : 1;	/* server has TOP */
  109.64 +    unsigned int uidl : 1;	/* server has UIDL */
  109.65 +    unsigned int user : 1;	/* server has USER */
  109.66 +    char *implementation;	/* server implementation string */
  109.67 +    long delaysecs;		/* minimum time between login (neg variable) */
  109.68 +    long expiredays;		/* server-guaranteed minimum retention days */
  109.69 +				/* supported authenticators */
  109.70 +    unsigned int sasl : MAXAUTHENTICATORS;
  109.71 +  } cap;
  109.72 +  unsigned int sensitive : 1;	/* sensitive data in progress */
  109.73 +  unsigned int loser : 1;	/* server is a loser */
  109.74 +  unsigned int saslcancel : 1;	/* SASL cancelled by protocol */
  109.75 +} POP3LOCAL;
  109.76 +
  109.77 +
  109.78 +/* Convenient access to local data */
  109.79 +
  109.80 +#define LOCAL ((POP3LOCAL *) stream->local)
  109.81 +
  109.82 +/* Function prototypes */
  109.83 +
  109.84 +DRIVER *pop3_valid (char *name);
  109.85 +void *pop3_parameters (long function,void *value);
  109.86 +void pop3_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  109.87 +void pop3_list (MAILSTREAM *stream,char *ref,char *pat);
  109.88 +void pop3_lsub (MAILSTREAM *stream,char *ref,char *pat);
  109.89 +long pop3_subscribe (MAILSTREAM *stream,char *mailbox);
  109.90 +long pop3_unsubscribe (MAILSTREAM *stream,char *mailbox);
  109.91 +long pop3_create (MAILSTREAM *stream,char *mailbox);
  109.92 +long pop3_delete (MAILSTREAM *stream,char *mailbox);
  109.93 +long pop3_rename (MAILSTREAM *stream,char *old,char *newname);
  109.94 +long pop3_status (MAILSTREAM *stream,char *mbx,long flags);
  109.95 +MAILSTREAM *pop3_open (MAILSTREAM *stream);
  109.96 +long pop3_capa (MAILSTREAM *stream,long flags);
  109.97 +long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr);
  109.98 +void *pop3_challenge (void *stream,unsigned long *len);
  109.99 +long pop3_response (void *stream,char *s,unsigned long size);
 109.100 +void pop3_close (MAILSTREAM *stream,long options);
 109.101 +void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags);
 109.102 +char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
 109.103 +		   long flags);
 109.104 +long pop3_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 109.105 +unsigned long pop3_cache (MAILSTREAM *stream,MESSAGECACHE *elt);
 109.106 +long pop3_ping (MAILSTREAM *stream);
 109.107 +void pop3_check (MAILSTREAM *stream);
 109.108 +long pop3_expunge (MAILSTREAM *stream,char *sequence,long options);
 109.109 +long pop3_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 109.110 +long pop3_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 109.111 +
 109.112 +long pop3_send_num (MAILSTREAM *stream,char *command,unsigned long n);
 109.113 +long pop3_send (MAILSTREAM *stream,char *command,char *args);
 109.114 +long pop3_reply (MAILSTREAM *stream);
 109.115 +long pop3_fake (MAILSTREAM *stream,char *text);
 109.116 +
 109.117 +/* POP3 mail routines */
 109.118 +
 109.119 +
 109.120 +/* Driver dispatch used by MAIL */
 109.121 +
 109.122 +DRIVER pop3driver = {
 109.123 +  "pop3",			/* driver name */
 109.124 +				/* driver flags */
 109.125 +#ifdef INADEQUATE_MEMORY
 109.126 +  DR_LOWMEM |
 109.127 +#endif
 109.128 +  DR_MAIL|DR_NOFAST|DR_CRLF|DR_NOSTICKY|DR_NOINTDATE|DR_NONEWMAIL,
 109.129 +  (DRIVER *) NIL,		/* next driver */
 109.130 +  pop3_valid,			/* mailbox is valid for us */
 109.131 +  pop3_parameters,		/* manipulate parameters */
 109.132 +  pop3_scan,			/* scan mailboxes */
 109.133 +  pop3_list,			/* find mailboxes */
 109.134 +  pop3_lsub,			/* find subscribed mailboxes */
 109.135 +  pop3_subscribe,		/* subscribe to mailbox */
 109.136 +  pop3_unsubscribe,		/* unsubscribe from mailbox */
 109.137 +  pop3_create,			/* create mailbox */
 109.138 +  pop3_delete,			/* delete mailbox */
 109.139 +  pop3_rename,			/* rename mailbox */
 109.140 +  pop3_status,			/* status of mailbox */
 109.141 +  pop3_open,			/* open mailbox */
 109.142 +  pop3_close,			/* close mailbox */
 109.143 +  pop3_fetchfast,		/* fetch message "fast" attributes */
 109.144 +  NIL,				/* fetch message flags */
 109.145 +  NIL,				/* fetch overview */
 109.146 +  NIL,				/* fetch message structure */
 109.147 +  pop3_header,			/* fetch message header */
 109.148 +  pop3_text,			/* fetch message text */
 109.149 +  NIL,				/* fetch message */
 109.150 +  NIL,				/* unique identifier */
 109.151 +  NIL,				/* message number from UID */
 109.152 +  NIL,				/* modify flags */
 109.153 +  NIL,				/* per-message modify flags */
 109.154 +  NIL,				/* search for message based on criteria */
 109.155 +  NIL,				/* sort messages */
 109.156 +  NIL,				/* thread messages */
 109.157 +  pop3_ping,			/* ping mailbox to see if still alive */
 109.158 +  pop3_check,			/* check for new messages */
 109.159 +  pop3_expunge,			/* expunge deleted messages */
 109.160 +  pop3_copy,			/* copy messages to another mailbox */
 109.161 +  pop3_append,			/* append string message to mailbox */
 109.162 +  NIL				/* garbage collect stream */
 109.163 +};
 109.164 +
 109.165 +				/* prototype stream */
 109.166 +MAILSTREAM pop3proto = {&pop3driver};
 109.167 +
 109.168 +				/* driver parameters */
 109.169 +static unsigned long pop3_maxlogintrials = MAXLOGINTRIALS;
 109.170 +static long pop3_port = 0;
 109.171 +static long pop3_sslport = 0;
 109.172 +
 109.173 +/* POP3 mail validate mailbox
 109.174 + * Accepts: mailbox name
 109.175 + * Returns: our driver if name is valid, NIL otherwise
 109.176 + */
 109.177 +
 109.178 +DRIVER *pop3_valid (char *name)
 109.179 +{
 109.180 +  NETMBX mb;
 109.181 +  return (mail_valid_net_parse (name,&mb) &&
 109.182 +	  !strcmp (mb.service,pop3driver.name) && !mb.authuser[0] &&
 109.183 +	  !compare_cstring (mb.mailbox,"INBOX")) ? &pop3driver : NIL;
 109.184 +}
 109.185 +
 109.186 +
 109.187 +/* News manipulate driver parameters
 109.188 + * Accepts: function code
 109.189 + *	    function-dependent value
 109.190 + * Returns: function-dependent return value
 109.191 + */
 109.192 +
 109.193 +void *pop3_parameters (long function,void *value)
 109.194 +{
 109.195 +  switch ((int) function) {
 109.196 +  case SET_MAXLOGINTRIALS:
 109.197 +    pop3_maxlogintrials = (unsigned long) value;
 109.198 +    break;
 109.199 +  case GET_MAXLOGINTRIALS:
 109.200 +    value = (void *) pop3_maxlogintrials;
 109.201 +    break;
 109.202 +  case SET_POP3PORT:
 109.203 +    pop3_port = (long) value;
 109.204 +    break;
 109.205 +  case GET_POP3PORT:
 109.206 +    value = (void *) pop3_port;
 109.207 +    break;
 109.208 +  case SET_SSLPOPPORT:
 109.209 +    pop3_sslport = (long) value;
 109.210 +    break;
 109.211 +  case GET_SSLPOPPORT:
 109.212 +    value = (void *) pop3_sslport;
 109.213 +    break;
 109.214 +  case GET_IDLETIMEOUT:
 109.215 +    value = (void *) IDLETIMEOUT;
 109.216 +    break;
 109.217 +  default:
 109.218 +    value = NIL;		/* error case */
 109.219 +    break;
 109.220 +  }
 109.221 +  return value;
 109.222 +}
 109.223 +
 109.224 +/* POP3 mail scan mailboxes for string
 109.225 + * Accepts: mail stream
 109.226 + *	    reference
 109.227 + *	    pattern to search
 109.228 + *	    string to scan
 109.229 + */
 109.230 +
 109.231 +void pop3_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 109.232 +{
 109.233 +  char tmp[MAILTMPLEN];
 109.234 +  if ((ref && *ref) ?		/* have a reference */
 109.235 +      (pop3_valid (ref) && pmatch ("INBOX",pat)) :
 109.236 +      (mail_valid_net (pat,&pop3driver,NIL,tmp) && pmatch ("INBOX",tmp)))
 109.237 +    mm_log ("Scan not valid for POP3 mailboxes",ERROR);
 109.238 +}
 109.239 +
 109.240 +
 109.241 +/* POP3 mail find list of all mailboxes
 109.242 + * Accepts: mail stream
 109.243 + *	    reference
 109.244 + *	    pattern to search
 109.245 + */
 109.246 +
 109.247 +void pop3_list (MAILSTREAM *stream,char *ref,char *pat)
 109.248 +{
 109.249 +  char tmp[MAILTMPLEN];
 109.250 +  if (ref && *ref) {		/* have a reference */
 109.251 +    if (pop3_valid (ref) && pmatch ("INBOX",pat)) {
 109.252 +      strcpy (strchr (strcpy (tmp,ref),'}')+1,"INBOX");
 109.253 +      mm_list (stream,NIL,tmp,LATT_NOINFERIORS);
 109.254 +    }
 109.255 +  }
 109.256 +  else if (mail_valid_net (pat,&pop3driver,NIL,tmp) && pmatch ("INBOX",tmp)) {
 109.257 +    strcpy (strchr (strcpy (tmp,pat),'}')+1,"INBOX");
 109.258 +    mm_list (stream,NIL,tmp,LATT_NOINFERIORS);
 109.259 +  }
 109.260 +}
 109.261 +
 109.262 +/* POP3 mail find list of subscribed mailboxes
 109.263 + * Accepts: mail stream
 109.264 + *	    reference
 109.265 + *	    pattern to search
 109.266 + */
 109.267 +
 109.268 +void pop3_lsub (MAILSTREAM *stream,char *ref,char *pat)
 109.269 +{
 109.270 +  void *sdb = NIL;
 109.271 +  char *s,mbx[MAILTMPLEN];
 109.272 +  if (*pat == '{') {		/* if remote pattern, must be POP3 */
 109.273 +    if (!pop3_valid (pat)) return;
 109.274 +    ref = NIL;			/* good POP3 pattern, punt reference */
 109.275 +  }
 109.276 +				/* if remote reference, must be valid POP3 */
 109.277 +  if (ref && (*ref == '{') && !pop3_valid (ref)) return;
 109.278 +				/* kludgy application of reference */
 109.279 +  if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
 109.280 +  else strcpy (mbx,pat);
 109.281 +
 109.282 +  if (s = sm_read (&sdb)) do if (pop3_valid (s) && pmatch (s,mbx))
 109.283 +    mm_lsub (stream,NIL,s,NIL);
 109.284 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 109.285 +}
 109.286 +
 109.287 +
 109.288 +/* POP3 mail subscribe to mailbox
 109.289 + * Accepts: mail stream
 109.290 + *	    mailbox to add to subscription list
 109.291 + * Returns: T on success, NIL on failure
 109.292 + */
 109.293 +
 109.294 +long pop3_subscribe (MAILSTREAM *stream,char *mailbox)
 109.295 +{
 109.296 +  return sm_subscribe (mailbox);
 109.297 +}
 109.298 +
 109.299 +
 109.300 +/* POP3 mail unsubscribe to mailbox
 109.301 + * Accepts: mail stream
 109.302 + *	    mailbox to delete from subscription list
 109.303 + * Returns: T on success, NIL on failure
 109.304 + */
 109.305 +
 109.306 +long pop3_unsubscribe (MAILSTREAM *stream,char *mailbox)
 109.307 +{
 109.308 +  return sm_unsubscribe (mailbox);
 109.309 +}
 109.310 +
 109.311 +/* POP3 mail create mailbox
 109.312 + * Accepts: mail stream
 109.313 + *	    mailbox name to create
 109.314 + * Returns: T on success, NIL on failure
 109.315 + */
 109.316 +
 109.317 +long pop3_create (MAILSTREAM *stream,char *mailbox)
 109.318 +{
 109.319 +  return NIL;			/* never valid for POP3 */
 109.320 +}
 109.321 +
 109.322 +
 109.323 +/* POP3 mail delete mailbox
 109.324 + *	    mailbox name to delete
 109.325 + * Returns: T on success, NIL on failure
 109.326 + */
 109.327 +
 109.328 +long pop3_delete (MAILSTREAM *stream,char *mailbox)
 109.329 +{
 109.330 +  return NIL;			/* never valid for POP3 */
 109.331 +}
 109.332 +
 109.333 +
 109.334 +/* POP3 mail rename mailbox
 109.335 + * Accepts: mail stream
 109.336 + *	    old mailbox name
 109.337 + *	    new mailbox name
 109.338 + * Returns: T on success, NIL on failure
 109.339 + */
 109.340 +
 109.341 +long pop3_rename (MAILSTREAM *stream,char *old,char *newname)
 109.342 +{
 109.343 +  return NIL;			/* never valid for POP3 */
 109.344 +}
 109.345 +
 109.346 +/* POP3 status
 109.347 + * Accepts: mail stream
 109.348 + *	    mailbox name
 109.349 + *	    status flags
 109.350 + * Returns: T on success, NIL on failure
 109.351 + */
 109.352 +
 109.353 +long pop3_status (MAILSTREAM *stream,char *mbx,long flags)
 109.354 +{
 109.355 +  MAILSTATUS status;
 109.356 +  unsigned long i;
 109.357 +  long ret = NIL;
 109.358 +  MAILSTREAM *tstream =
 109.359 +    (stream && LOCAL->netstream && mail_usable_network_stream (stream,mbx)) ?
 109.360 +      stream : mail_open (NIL,mbx,OP_SILENT);
 109.361 +  if (tstream) {		/* have a usable stream? */
 109.362 +    status.flags = flags;	/* return status values */
 109.363 +    status.messages = tstream->nmsgs;
 109.364 +    status.recent = tstream->recent;
 109.365 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 109.366 +      for (i = 1,status.unseen = 0; i <= tstream->nmsgs; i++)
 109.367 +	if (!mail_elt (tstream,i)->seen) status.unseen++;
 109.368 +    status.uidnext = tstream->uid_last + 1;
 109.369 +    status.uidvalidity = tstream->uid_validity;
 109.370 +				/* pass status to main program */
 109.371 +    mm_status (tstream,mbx,&status);
 109.372 +    if (stream != tstream) mail_close (tstream);
 109.373 +    ret = LONGT;
 109.374 +  }
 109.375 +  return ret;			/* success */
 109.376 +}
 109.377 +
 109.378 +/* POP3 mail open
 109.379 + * Accepts: stream to open
 109.380 + * Returns: stream on success, NIL on failure
 109.381 + */
 109.382 +
 109.383 +MAILSTREAM *pop3_open (MAILSTREAM *stream)
 109.384 +{
 109.385 +  unsigned long i,j;
 109.386 +  char *s,*t,tmp[MAILTMPLEN],usr[MAILTMPLEN];
 109.387 +  NETMBX mb;
 109.388 +  MESSAGECACHE *elt;
 109.389 +				/* return prototype for OP_PROTOTYPE call */
 109.390 +  if (!stream) return &pop3proto;
 109.391 +  mail_valid_net_parse (stream->mailbox,&mb);
 109.392 +  usr[0] = '\0';		/* initially no user name */
 109.393 +  if (stream->local) fatal ("pop3 recycle stream");
 109.394 +				/* /anonymous not supported */
 109.395 +  if (mb.anoflag || stream->anonymous) {
 109.396 +    mm_log ("Anonymous POP3 login not available",ERROR);
 109.397 +    return NIL;
 109.398 +  }
 109.399 +				/* /readonly not supported either */
 109.400 +  if (mb.readonlyflag || stream->rdonly) {
 109.401 +    mm_log ("Read-only POP3 access not available",ERROR);
 109.402 +    return NIL;
 109.403 +  }
 109.404 +				/* copy other switches */
 109.405 +  if (mb.dbgflag) stream->debug = T;
 109.406 +  if (mb.secflag) stream->secure = T;
 109.407 +  mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL;
 109.408 +  stream->local =		/* instantiate localdata */
 109.409 +    (void *) memset (fs_get (sizeof (POP3LOCAL)),0,sizeof (POP3LOCAL));
 109.410 +  stream->sequence++;		/* bump sequence number */
 109.411 +  stream->perm_deleted = T;	/* deleted is only valid flag */
 109.412 +
 109.413 +  if ((LOCAL->netstream =	/* try to open connection */
 109.414 +       net_open (&mb,NIL,pop3_port ? pop3_port : POP3TCPPORT,
 109.415 +		 (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
 109.416 +		 "*pop3s",pop3_sslport ? pop3_sslport : POP3SSLPORT)) &&
 109.417 +      pop3_reply (stream)) {
 109.418 +    mm_log (LOCAL->reply,NIL);	/* give greeting */
 109.419 +    if (!pop3_auth (stream,&mb,tmp,usr)) pop3_close (stream,NIL);
 109.420 +    else if (pop3_send (stream,"STAT",NIL)) {
 109.421 +      int silent = stream->silent;
 109.422 +      stream->silent = T;
 109.423 +      sprintf (tmp,"{%.200s:%lu/pop3",
 109.424 +	       (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
 109.425 +	       net_host (LOCAL->netstream) : mb.host,
 109.426 +	       net_port (LOCAL->netstream));
 109.427 +      if (mb.tlsflag) strcat (tmp,"/tls");
 109.428 +      if (mb.tlssslv23) strcat (tmp,"/tls-sslv23");
 109.429 +      if (mb.notlsflag) strcat (tmp,"/notls");
 109.430 +      if (mb.sslflag) strcat (tmp,"/ssl");
 109.431 +      if (mb.novalidate) strcat (tmp,"/novalidate-cert");
 109.432 +      if (LOCAL->loser = mb.loser) strcat (tmp,"/loser");
 109.433 +      if (stream->secure) strcat (tmp,"/secure");
 109.434 +      sprintf (tmp + strlen (tmp),"/user=\"%s\"}%s",usr,mb.mailbox);
 109.435 +      stream->inbox = T;	/* always INBOX */
 109.436 +      fs_give ((void **) &stream->mailbox);
 109.437 +      stream->mailbox = cpystr (tmp);
 109.438 +				/* notify upper level */
 109.439 +      mail_exists (stream,stream->uid_last = strtoul (LOCAL->reply,NIL,10));
 109.440 +      mail_recent (stream,stream->nmsgs);
 109.441 +				/* instantiate elt */
 109.442 +      for (i = 0; i < stream->nmsgs;) {
 109.443 +	elt = mail_elt (stream,++i);
 109.444 +	elt->valid = elt->recent = T;
 109.445 +	elt->private.uid = i;
 109.446 +      }
 109.447 +
 109.448 +				/* trust LIST output if new server */
 109.449 +      if (!LOCAL->loser && LOCAL->cap.capa && pop3_send (stream,"LIST",NIL)) {
 109.450 +	while ((s = net_getline (LOCAL->netstream)) && (*s != '.')) {
 109.451 +	  if ((i = strtoul (s,&t,10)) && (i <= stream->nmsgs) &&
 109.452 +	      (j = strtoul (t,NIL,10))) mail_elt (stream,i)->rfc822_size = j;
 109.453 +	  fs_give ((void **) &s);
 109.454 +	}
 109.455 +				/* flush final dot */
 109.456 +	if (s) fs_give ((void **) &s);
 109.457 +	else {			/* lost connection */
 109.458 +	  mm_log ("POP3 connection broken while itemizing messages",ERROR);
 109.459 +	  pop3_close (stream,NIL);
 109.460 +	  return NIL;
 109.461 +	}
 109.462 +      }
 109.463 +      stream->silent = silent;	/* notify main program */
 109.464 +      mail_exists (stream,stream->nmsgs);
 109.465 +				/* notify if empty */
 109.466 +      if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",WARN);
 109.467 +    }
 109.468 +    else {			/* error in STAT */
 109.469 +      mm_log (LOCAL->reply,ERROR);
 109.470 +      pop3_close (stream,NIL);	/* too bad */
 109.471 +    }
 109.472 +  }
 109.473 +  else {			/* connection failed */
 109.474 +    if (LOCAL->reply) mm_log (LOCAL->reply,ERROR);
 109.475 +    pop3_close (stream,NIL);	/* failed, clean up */
 109.476 +  }
 109.477 +  return LOCAL ? stream : NIL;	/* if stream is alive, return to caller */
 109.478 +}
 109.479 +
 109.480 +/* POP3 capabilities
 109.481 + * Accepts: stream
 109.482 + *	    authenticator flags
 109.483 + * Returns: T on success, NIL on failure
 109.484 + */
 109.485 +
 109.486 +long pop3_capa (MAILSTREAM *stream,long flags)
 109.487 +{
 109.488 +  unsigned long i;
 109.489 +  char *s,*t,*r,*args;
 109.490 +  if (LOCAL->cap.implementation)/* zap all old capabilities */
 109.491 +    fs_give ((void **) &LOCAL->cap.implementation);
 109.492 +  memset (&LOCAL->cap,0,sizeof (LOCAL->cap));
 109.493 +				/* get server capabilities */
 109.494 +  if (pop3_send (stream,"CAPA",NIL)) LOCAL->cap.capa = T;
 109.495 +  else {
 109.496 +    LOCAL->cap.user = T;	/* guess worst-case old server */
 109.497 +    return NIL;			/* no CAPA on this server */
 109.498 +  }
 109.499 +  while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) {
 109.500 +    if (stream->debug) mm_dlog (t);
 109.501 +				/* get optional capability arguments */
 109.502 +    if (args = strchr (t,' ')) *args++ = '\0';
 109.503 +    if (!compare_cstring (t,"STLS")) LOCAL->cap.stls = T;
 109.504 +    else if (!compare_cstring (t,"PIPELINING")) LOCAL->cap.pipelining = T;
 109.505 +    else if (!compare_cstring (t,"RESP-CODES")) LOCAL->cap.respcodes = T;
 109.506 +    else if (!compare_cstring (t,"TOP")) LOCAL->cap.top = T;
 109.507 +    else if (!compare_cstring (t,"UIDL")) LOCAL->cap.uidl = T;
 109.508 +    else if (!compare_cstring (t,"USER")) LOCAL->cap.user = T;
 109.509 +    else if (!compare_cstring (t,"IMPLEMENTATION") && args)
 109.510 +      LOCAL->cap.implementation = cpystr (args);
 109.511 +    else if (!compare_cstring (t,"EXPIRE") && args) {
 109.512 +      LOCAL->cap.expire = T;	/* note that it is present */
 109.513 +      if (s = strchr(args,' ')){/* separate time from possible USER */
 109.514 +	*s++ = '\0';
 109.515 +				/* in case they add something after USER */
 109.516 +	if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0';
 109.517 +      }
 109.518 +      LOCAL->cap.expire =	/* get expiration time */
 109.519 +	(!compare_cstring (args,"NEVER")) ? 65535 :
 109.520 +	  ((s && !compare_cstring (s,"USER")) ? -atoi (args) : atoi (args));
 109.521 +    }
 109.522 +    else if (!compare_cstring (t,"LOGIN-DELAY") && args) {
 109.523 +      LOCAL->cap.logindelay = T;/* note that it is present */
 109.524 +      if (s = strchr(args,' ')){/* separate time from possible USER */
 109.525 +	*s++ = '\0';
 109.526 +				/* in case they add something after USER */
 109.527 +	if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0';
 109.528 +      }
 109.529 +				/* get delay time */
 109.530 +      LOCAL->cap.delaysecs = (s && !compare_cstring (s,"USER")) ?
 109.531 +	-atoi (args) : atoi (args);
 109.532 +    }
 109.533 +    else if (!compare_cstring (t,"SASL") && args)
 109.534 +      for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r))
 109.535 +	if ((i = mail_lookup_auth_name (args,flags)) &&
 109.536 +	    (--i < MAXAUTHENTICATORS))
 109.537 +	  LOCAL->cap.sasl |= (1 << i);
 109.538 +    fs_give ((void **) &t);
 109.539 +  }
 109.540 +  if (t) {			/* flush end of text indicator */
 109.541 +    if (stream->debug) mm_dlog (t);
 109.542 +    fs_give ((void **) &t);
 109.543 +  }
 109.544 +  return LONGT;
 109.545 +}
 109.546 +
 109.547 +/* POP3 authenticate
 109.548 + * Accepts: stream to login
 109.549 + *	    parsed network mailbox structure
 109.550 + *	    scratch buffer of length MAILTMPLEN
 109.551 + *	    place to return user name
 109.552 + * Returns: T on success, NIL on failure
 109.553 + */
 109.554 +
 109.555 +long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr)
 109.556 +{
 109.557 +  unsigned long i,trial,auths = 0;
 109.558 +  char *t;
 109.559 +  AUTHENTICATOR *at;
 109.560 +  long ret = NIL;
 109.561 +  long flags = (stream->secure ? AU_SECURE : NIL) |
 109.562 +    (mb->authuser[0] ? AU_AUTHUSER : NIL);
 109.563 +  long capaok = pop3_capa (stream,flags);
 109.564 +  NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL);
 109.565 +  sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL);
 109.566 +				/* server has TLS? */
 109.567 +  if (stls && LOCAL->cap.stls && !mb->sslflag && !mb->notlsflag &&
 109.568 +      pop3_send (stream,"STLS",NIL)) {
 109.569 +    mb->tlsflag = T;		/* TLS OK, get into TLS at this end */
 109.570 +    LOCAL->netstream->dtb = ssld;
 109.571 +    if (!(LOCAL->netstream->stream =
 109.572 +	  (*stls) (LOCAL->netstream->stream,mb->host,
 109.573 +		   (mb->tlssslv23 ? NIL : NET_TLSCLIENT) |
 109.574 +		   (mb->novalidate ? NET_NOVALIDATECERT : NIL)))) {
 109.575 +				/* drat, drop this connection */
 109.576 +      if (LOCAL->netstream) net_close (LOCAL->netstream);
 109.577 +      LOCAL->netstream= NIL;
 109.578 +      return NIL;		/* TLS negotiation failed */
 109.579 +    }
 109.580 +    pop3_capa (stream,flags);	/* get capabilities now that TLS in effect */
 109.581 +  }
 109.582 +  else if (mb->tlsflag) {	/* user specified /tls but can't do it */
 109.583 +    mm_log ("Unable to negotiate TLS with this server",ERROR);
 109.584 +    return NIL;
 109.585 +  }
 109.586 +  				/* get authenticators from capabilities */
 109.587 +  if (capaok) auths = LOCAL->cap.sasl;
 109.588 +				/* get list of authenticators */
 109.589 +  else if (pop3_send (stream,"AUTH",NIL)) {
 109.590 +    while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) {
 109.591 +      if (stream->debug) mm_dlog (t);
 109.592 +      if ((i = mail_lookup_auth_name (t,flags)) && (--i < MAXAUTHENTICATORS))
 109.593 +	auths |= (1 << i);
 109.594 +      fs_give ((void **) &t);
 109.595 +    }
 109.596 +    if (t) {			/* flush end of text indicator */
 109.597 +      if (stream->debug) mm_dlog (t);
 109.598 +      fs_give ((void **) &t);
 109.599 +    }
 109.600 +  }
 109.601 +				/* disable LOGIN if PLAIN also advertised */
 109.602 +  if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) &&
 109.603 +      (auths & (1 << i)) &&
 109.604 +      (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS))
 109.605 +    auths &= ~(1 << i);
 109.606 +
 109.607 +  if (auths) {			/* got any authenticators? */
 109.608 +    if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
 109.609 +				/* remote name for authentication */
 109.610 +      strncpy (mb->host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
 109.611 +	       net_remotehost (LOCAL->netstream) : net_host (LOCAL->netstream),
 109.612 +	       NETMAXHOST-1);
 109.613 +      mb->host[NETMAXHOST-1] = '\0';
 109.614 +    }
 109.615 +    for (t = NIL, LOCAL->saslcancel = NIL; !ret && LOCAL->netstream && auths &&
 109.616 +	 (at = mail_lookup_auth (find_rightmost_bit (&auths)+1)); ) {
 109.617 +      if (t) {			/* previous authenticator failed? */
 109.618 +	sprintf (pwd,"Retrying using %.80s authentication after %.80s",
 109.619 +		 at->name,t);
 109.620 +	mm_log (pwd,NIL);
 109.621 +	fs_give ((void **) &t);
 109.622 +      }
 109.623 +      trial = 0;		/* initial trial count */
 109.624 +      do {
 109.625 +	if (t) {
 109.626 +	  sprintf (pwd,"Retrying %s authentication after %.80s",at->name,t);
 109.627 +	  mm_log (pwd,WARN);
 109.628 +	  fs_give ((void **) &t);
 109.629 +	}
 109.630 +	LOCAL->saslcancel = NIL;
 109.631 +	if (pop3_send (stream,"AUTH",at->name)) {
 109.632 +				/* hide client authentication responses */
 109.633 +	  if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T;
 109.634 +	  if ((*at->client) (pop3_challenge,pop3_response,"pop",mb,stream,
 109.635 +			     &trial,usr) && LOCAL->response) {
 109.636 +	    if (*LOCAL->response == '+') ret = LONGT;
 109.637 +				/* if main program requested cancellation */
 109.638 +	    else if (!trial) mm_log ("POP3 Authentication cancelled",ERROR);
 109.639 +	  }
 109.640 +	  LOCAL->sensitive=NIL;	/* unhide */
 109.641 +	}
 109.642 +				/* remember response if error and no cancel */
 109.643 +	if (!ret && trial) t = cpystr (LOCAL->reply);
 109.644 +      } while (!ret && trial && (trial < pop3_maxlogintrials) &&
 109.645 +	       LOCAL->netstream);
 109.646 +    }
 109.647 +    if (t) {			/* previous authenticator failed? */
 109.648 +      if (!LOCAL->saslcancel) {	/* don't do this if a cancel */
 109.649 +	sprintf (pwd,"Can not authenticate to POP3 server: %.80s",t);
 109.650 +	mm_log (pwd,ERROR);
 109.651 +      }
 109.652 +      fs_give ((void **) &t);
 109.653 +    }
 109.654 +  }
 109.655 +
 109.656 +  else if (stream->secure)
 109.657 +    mm_log ("Can't do secure authentication with this server",ERROR);
 109.658 +  else if (mb->authuser[0])
 109.659 +    mm_log ("Can't do /authuser with this server",ERROR);
 109.660 +  else if (!LOCAL->cap.user) mm_log ("Can't login to this server",ERROR);
 109.661 +  else {			/* traditional login */
 109.662 +    trial = 0;			/* initial trial count */
 109.663 +    do {
 109.664 +      pwd[0] = 0;		/* prompt user for password */
 109.665 +      mm_login (mb,usr,pwd,trial++);
 109.666 +      if (pwd[0]) {		/* send login sequence if have password */
 109.667 +	if (pop3_send (stream,"USER",usr)) {
 109.668 +	  LOCAL->sensitive = T;	/* hide this command */
 109.669 +	  if (pop3_send (stream,"PASS",pwd)) ret = LONGT;
 109.670 +	  LOCAL->sensitive=NIL;	/* unhide */
 109.671 +	}
 109.672 +	if (!ret) {		/* failure */
 109.673 +	  mm_log (LOCAL->reply,WARN);
 109.674 +	  if (trial == pop3_maxlogintrials)
 109.675 +	    mm_log ("Too many login failures",ERROR);
 109.676 +	}
 109.677 +      }
 109.678 +				/* user refused to give password */
 109.679 +      else mm_log ("Login aborted",ERROR);
 109.680 +    } while (!ret && pwd[0] && (trial < pop3_maxlogintrials) &&
 109.681 +	     LOCAL->netstream);
 109.682 +  }
 109.683 +  memset (pwd,0,MAILTMPLEN);	/* erase password */
 109.684 +				/* get capabilities if logged in */
 109.685 +  if (ret && capaok) pop3_capa (stream,flags);
 109.686 +  return ret;
 109.687 +}
 109.688 +
 109.689 +/* Get challenge to authenticator in binary
 109.690 + * Accepts: stream
 109.691 + *	    pointer to returned size
 109.692 + * Returns: challenge or NIL if not challenge
 109.693 + */
 109.694 +
 109.695 +void *pop3_challenge (void *s,unsigned long *len)
 109.696 +{
 109.697 +  char tmp[MAILTMPLEN];
 109.698 +  void *ret = NIL;
 109.699 +  MAILSTREAM *stream = (MAILSTREAM *) s;
 109.700 +  if (stream && LOCAL->response &&
 109.701 +      (*LOCAL->response == '+') && (LOCAL->response[1] == ' ') &&
 109.702 +      !(ret = rfc822_base64 ((unsigned char *) LOCAL->reply,
 109.703 +			     strlen (LOCAL->reply),len))) {
 109.704 +    sprintf (tmp,"POP3 SERVER BUG (invalid challenge): %.80s",LOCAL->reply);
 109.705 +    mm_log (tmp,ERROR);
 109.706 +  }
 109.707 +  return ret;
 109.708 +}
 109.709 +
 109.710 +
 109.711 +/* Send authenticator response in BASE64
 109.712 + * Accepts: MAIL stream
 109.713 + *	    string to send
 109.714 + *	    length of string
 109.715 + * Returns: T if successful, else NIL
 109.716 + */
 109.717 +
 109.718 +long pop3_response (void *s,char *response,unsigned long size)
 109.719 +{
 109.720 +  MAILSTREAM *stream = (MAILSTREAM *) s;
 109.721 +  unsigned long i,j,ret;
 109.722 +  char *t,*u;
 109.723 +  if (response) {		/* make CRLFless BASE64 string */
 109.724 +    if (size) {
 109.725 +      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
 109.726 +	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
 109.727 +      *u = '\0';		/* tie off string for mm_dlog() */
 109.728 +      if (stream->debug) mail_dlog (t,LOCAL->sensitive);
 109.729 +				/* append CRLF */
 109.730 +      *u++ = '\015'; *u++ = '\012'; *u = '\0';
 109.731 +      ret = net_sout (LOCAL->netstream,t,u - t);
 109.732 +      fs_give ((void **) &t);
 109.733 +    }
 109.734 +    else ret = net_sout (LOCAL->netstream,"\015\012",2);
 109.735 +  }
 109.736 +  else {			/* abort requested */
 109.737 +    ret = net_sout (LOCAL->netstream,"*\015\012",3);
 109.738 +    LOCAL->saslcancel = T;	/* mark protocol-requested SASL cancel */
 109.739 +  }
 109.740 +  pop3_reply (stream);		/* get response */
 109.741 +  return ret;
 109.742 +}
 109.743 +
 109.744 +/* POP3 mail close
 109.745 + * Accepts: MAIL stream
 109.746 + *	    option flags
 109.747 + */
 109.748 +
 109.749 +void pop3_close (MAILSTREAM *stream,long options)
 109.750 +{
 109.751 +  int silent = stream->silent;
 109.752 +  if (LOCAL) {			/* only if a file is open */
 109.753 +    if (LOCAL->netstream) {	/* close POP3 connection */
 109.754 +      stream->silent = T;
 109.755 +      if (options & CL_EXPUNGE) pop3_expunge (stream,NIL,NIL);
 109.756 +      stream->silent = silent;
 109.757 +      pop3_send (stream,"QUIT",NIL);
 109.758 +      mm_notify (stream,LOCAL->reply,BYE);
 109.759 +    }
 109.760 +				/* close POP3 connection */
 109.761 +    if (LOCAL->netstream) net_close (LOCAL->netstream);
 109.762 +				/* clean up */
 109.763 +    if (LOCAL->cap.implementation)
 109.764 +      fs_give ((void **) &LOCAL->cap.implementation);
 109.765 +    if (LOCAL->txt) fclose (LOCAL->txt);
 109.766 +    LOCAL->txt = NIL;
 109.767 +    if (LOCAL->response) fs_give ((void **) &LOCAL->response);
 109.768 +				/* nuke the local data */
 109.769 +    fs_give ((void **) &stream->local);
 109.770 +    stream->dtb = NIL;		/* log out the DTB */
 109.771 +  }
 109.772 +}
 109.773 +
 109.774 +/* POP3 mail fetch fast information
 109.775 + * Accepts: MAIL stream
 109.776 + *	    sequence
 109.777 + *	    option flags
 109.778 + * This is ugly and slow
 109.779 + */
 109.780 +
 109.781 +void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags)
 109.782 +{
 109.783 +  unsigned long i;
 109.784 +  MESSAGECACHE *elt;
 109.785 +				/* get sequence */
 109.786 +  if (stream && LOCAL && ((flags & FT_UID) ?
 109.787 +			  mail_uid_sequence (stream,sequence) :
 109.788 +			  mail_sequence (stream,sequence)))
 109.789 +    for (i = 1; i <= stream->nmsgs; i++)
 109.790 +      if ((elt = mail_elt (stream,i))->sequence &&
 109.791 +	  !(elt->day && elt->rfc822_size)) {
 109.792 +	ENVELOPE **env = NIL;
 109.793 +	ENVELOPE *e = NIL;
 109.794 +	if (!stream->scache) env = &elt->private.msg.env;
 109.795 +	else if (stream->msgno == i) env = &stream->env;
 109.796 +	else env = &e;
 109.797 +	if (!*env || !elt->rfc822_size) {
 109.798 +	  STRING bs;
 109.799 +	  unsigned long hs;
 109.800 +	  char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
 109.801 +				/* need to make an envelope? */
 109.802 +	  if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
 109.803 +				       stream->dtb->flags);
 109.804 +				/* need message size too, ugh */
 109.805 +	  if (!elt->rfc822_size) {
 109.806 +	    (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
 109.807 +	    elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
 109.808 +	  }
 109.809 +	}
 109.810 +				/* if need date, have date in envelope? */
 109.811 +	if (!elt->day && *env && (*env)->date)
 109.812 +	  mail_parse_date (elt,(*env)->date);
 109.813 +				/* sigh, fill in bogus default */
 109.814 +	if (!elt->day) elt->day = elt->month = 1;
 109.815 +	mail_free_envelope (&e);
 109.816 +      }
 109.817 +}
 109.818 +
 109.819 +/* POP3 fetch header as text
 109.820 + * Accepts: mail stream
 109.821 + *	    message number
 109.822 + *	    pointer to return size
 109.823 + *	    flags
 109.824 + * Returns: header text
 109.825 + */
 109.826 +
 109.827 +char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
 109.828 +		   long flags)
 109.829 +{
 109.830 +  unsigned long i;
 109.831 +  char tmp[MAILTMPLEN];
 109.832 +  MESSAGECACHE *elt;
 109.833 +  FILE *f = NIL;
 109.834 +  *size = 0;			/* initially no header size */
 109.835 +  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return "";
 109.836 +				/* have header text already? */
 109.837 +  if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) {
 109.838 +				/* if have CAPA and TOP, assume good TOP */
 109.839 +    if (!LOCAL->loser && LOCAL->cap.top) {
 109.840 +      sprintf (tmp,"TOP %lu 0",mail_uid (stream,msgno));
 109.841 +      if (pop3_send (stream,tmp,NIL))
 109.842 +	f = netmsg_slurp (LOCAL->netstream,&i,
 109.843 +			  &elt->private.msg.header.text.size);
 109.844 +    }
 109.845 +				/* otherwise load the cache with the message */
 109.846 +    else if (elt->private.msg.header.text.size = pop3_cache (stream,elt))
 109.847 +      f = LOCAL->txt;
 109.848 +    if (f) {			/* got it, make sure at start of file */
 109.849 +      fseek (f,(unsigned long) 0,SEEK_SET);
 109.850 +				/* read header from the cache */
 109.851 +      fread (elt->private.msg.header.text.data = (unsigned char *)
 109.852 +	     fs_get ((size_t) elt->private.msg.header.text.size + 1),
 109.853 +	     (size_t) 1,(size_t) elt->private.msg.header.text.size,f);
 109.854 +				/* tie off header text */
 109.855 +      elt->private.msg.header.text.data[elt->private.msg.header.text.size] =
 109.856 +	'\0';
 109.857 +				/* close if not the cache */
 109.858 +      if (f != LOCAL->txt) fclose (f);
 109.859 +    }
 109.860 +  }
 109.861 +				/* return size of text */
 109.862 +  if (size) *size = elt->private.msg.header.text.size;
 109.863 +  return elt->private.msg.header.text.data ?
 109.864 +    (char *) elt->private.msg.header.text.data : "";
 109.865 +}
 109.866 +
 109.867 +/* POP3 fetch body
 109.868 + * Accepts: mail stream
 109.869 + *	    message number
 109.870 + *	    pointer to stringstruct to initialize
 109.871 + *	    flags
 109.872 + * Returns: T if successful, else NIL
 109.873 + */
 109.874 +
 109.875 +long pop3_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 109.876 +{
 109.877 +  MESSAGECACHE *elt;
 109.878 +  INIT (bs,mail_string,(void *) "",0);
 109.879 +  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL;
 109.880 +  elt = mail_elt (stream,msgno);
 109.881 +  pop3_cache (stream,elt);	/* make sure cache loaded */
 109.882 +  if (!LOCAL->txt) return NIL;	/* error if don't have a file */
 109.883 +  if (!(flags & FT_PEEK)) {	/* mark seen if needed */
 109.884 +    elt->seen = T;
 109.885 +    mm_flags (stream,elt->msgno);
 109.886 +  }
 109.887 +  INIT (bs,file_string,(void *) LOCAL->txt,elt->rfc822_size);
 109.888 +  SETPOS (bs,LOCAL->hdrsize);	/* skip past header */
 109.889 +  return T;
 109.890 +}
 109.891 +
 109.892 +/* POP3 cache message
 109.893 + * Accepts: mail stream
 109.894 + *	    message number
 109.895 + * Returns: header size
 109.896 + */
 109.897 +
 109.898 +unsigned long pop3_cache (MAILSTREAM *stream,MESSAGECACHE *elt)
 109.899 +{
 109.900 +				/* already cached? */
 109.901 +  if (LOCAL->cached != mail_uid (stream,elt->msgno)) {
 109.902 +				/* no, close current file */
 109.903 +    if (LOCAL->txt) fclose (LOCAL->txt);
 109.904 +    LOCAL->txt = NIL;
 109.905 +    LOCAL->cached = LOCAL->hdrsize = 0;
 109.906 +    if (pop3_send_num (stream,"RETR",elt->msgno) &&
 109.907 +	(LOCAL->txt = netmsg_slurp (LOCAL->netstream,&elt->rfc822_size,
 109.908 +				    &LOCAL->hdrsize)))
 109.909 +				/* set as current message number */
 109.910 +      LOCAL->cached = mail_uid (stream,elt->msgno);
 109.911 +    else elt->deleted = T;
 109.912 +  }
 109.913 +  return LOCAL->hdrsize;
 109.914 +}
 109.915 +
 109.916 +/* POP3 mail ping mailbox
 109.917 + * Accepts: MAIL stream
 109.918 + * Returns: T if stream alive, else NIL
 109.919 + */
 109.920 +
 109.921 +long pop3_ping (MAILSTREAM *stream)
 109.922 +{
 109.923 +  return pop3_send (stream,"NOOP",NIL);
 109.924 +}
 109.925 +
 109.926 +
 109.927 +/* POP3 mail check mailbox
 109.928 + * Accepts: MAIL stream
 109.929 + */
 109.930 +
 109.931 +void pop3_check (MAILSTREAM *stream)
 109.932 +{
 109.933 +  if (pop3_ping (stream)) mm_log ("Check completed",NIL);
 109.934 +}
 109.935 +
 109.936 +
 109.937 +/* POP3 mail expunge mailbox
 109.938 + * Accepts: MAIL stream
 109.939 + *	    sequence to expunge if non-NIL
 109.940 + *	    expunge options
 109.941 + * Returns: T if success, NIL if failure
 109.942 + */
 109.943 +
 109.944 +long pop3_expunge (MAILSTREAM *stream,char *sequence,long options)
 109.945 +{
 109.946 +  char tmp[MAILTMPLEN];
 109.947 +  MESSAGECACHE *elt;
 109.948 +  unsigned long i = 1,n = 0;
 109.949 +  long ret;
 109.950 +  if (ret = sequence ? ((options & EX_UID) ?
 109.951 +			mail_uid_sequence (stream,sequence) :
 109.952 +			mail_sequence (stream,sequence)) :
 109.953 +      LONGT) {			/* build selected sequence if needed */
 109.954 +    while (i <= stream->nmsgs) {
 109.955 +      elt = mail_elt (stream,i);
 109.956 +      if (elt->deleted && (sequence ? elt->sequence : T) &&
 109.957 +	  pop3_send_num (stream,"DELE",i)) {
 109.958 +				/* expunging currently cached message? */
 109.959 +	if (LOCAL->cached == mail_uid (stream,i)) {
 109.960 +				/* yes, close current file */
 109.961 +	  if (LOCAL->txt) fclose (LOCAL->txt);
 109.962 +	  LOCAL->txt = NIL;
 109.963 +	  LOCAL->cached = LOCAL->hdrsize = 0;
 109.964 +	}
 109.965 +	mail_expunged (stream,i);
 109.966 +	n++;
 109.967 +      }
 109.968 +      else i++;			/* try next message */
 109.969 +    }
 109.970 +    if (!stream->silent) {	/* only if not silent */
 109.971 +      if (n) {			/* did we expunge anything? */
 109.972 +	sprintf (tmp,"Expunged %lu messages",n);
 109.973 +	mm_log (tmp,(long) NIL);
 109.974 +      }
 109.975 +      else mm_log ("No messages deleted, so no update needed",(long) NIL);
 109.976 +    }
 109.977 +  }
 109.978 +  return ret;
 109.979 +}
 109.980 +
 109.981 +/* POP3 mail copy message(s)
 109.982 + * Accepts: MAIL stream
 109.983 + *	    sequence
 109.984 + *	    destination mailbox
 109.985 + *	    option flags
 109.986 + * Returns: T if copy successful, else NIL
 109.987 + */
 109.988 +
 109.989 +long pop3_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 109.990 +{
 109.991 +  mailproxycopy_t pc =
 109.992 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 109.993 +  if (pc) return (*pc) (stream,sequence,mailbox,options);
 109.994 +  mm_log ("Copy not valid for POP3",ERROR);
 109.995 +  return NIL;
 109.996 +}
 109.997 +
 109.998 +
 109.999 +/* POP3 mail append message from stringstruct
109.1000 + * Accepts: MAIL stream
109.1001 + *	    destination mailbox
109.1002 + *	    append callback
109.1003 + *	    data for callback
109.1004 + * Returns: T if append successful, else NIL
109.1005 + */
109.1006 +
109.1007 +long pop3_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
109.1008 +{
109.1009 +  mm_log ("Append not valid for POP3",ERROR);
109.1010 +  return NIL;
109.1011 +}
109.1012 +
109.1013 +/* Internal routines */
109.1014 +
109.1015 +
109.1016 +/* Post Office Protocol 3 send command with number argument
109.1017 + * Accepts: MAIL stream
109.1018 + *	    command
109.1019 + *	    number
109.1020 + * Returns: T if successful, NIL if failure
109.1021 + */
109.1022 +
109.1023 +long pop3_send_num (MAILSTREAM *stream,char *command,unsigned long n)
109.1024 +{
109.1025 +  char tmp[MAILTMPLEN];
109.1026 +  sprintf (tmp,"%lu",mail_uid (stream,n));
109.1027 +  return pop3_send (stream,command,tmp);
109.1028 +}
109.1029 +
109.1030 +
109.1031 +/* Post Office Protocol 3 send command
109.1032 + * Accepts: MAIL stream
109.1033 + *	    command
109.1034 + *	    command argument
109.1035 + * Returns: T if successful, NIL if failure
109.1036 + */
109.1037 +
109.1038 +long pop3_send (MAILSTREAM *stream,char *command,char *args)
109.1039 +{
109.1040 +  long ret;
109.1041 +  char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1: 0)
109.1042 +			     + 3);
109.1043 +  mail_lock (stream);		/* lock up the stream */
109.1044 +  if (!LOCAL->netstream) ret = pop3_fake (stream,"POP3 connection lost");
109.1045 +  else {			/* build the complete command */
109.1046 +    if (args) sprintf (s,"%s %s",command,args);
109.1047 +    else strcpy (s,command);
109.1048 +    if (stream->debug) mail_dlog (s,LOCAL->sensitive);
109.1049 +    strcat (s,"\015\012");
109.1050 +				/* send the command */
109.1051 +    ret = net_soutr (LOCAL->netstream,s) ? pop3_reply (stream) :
109.1052 +      pop3_fake (stream,"POP3 connection broken in command");
109.1053 +  }
109.1054 +  fs_give ((void **) &s);
109.1055 +  mail_unlock (stream);		/* unlock stream */
109.1056 +  return ret;
109.1057 +}
109.1058 +
109.1059 +/* Post Office Protocol 3 get reply
109.1060 + * Accepts: MAIL stream
109.1061 + * Returns: T if success reply, NIL if error reply
109.1062 + */
109.1063 +
109.1064 +long pop3_reply (MAILSTREAM *stream)
109.1065 +{
109.1066 +  char *s;
109.1067 +				/* flush old reply */
109.1068 +  if (LOCAL->response) fs_give ((void **) &LOCAL->response);
109.1069 +  				/* get reply */
109.1070 +  if (!(LOCAL->response = net_getline (LOCAL->netstream)))
109.1071 +    return pop3_fake (stream,"POP3 connection broken in response");
109.1072 +  if (stream->debug) mm_dlog (LOCAL->response);
109.1073 +  LOCAL->reply = (s = strchr (LOCAL->response,' ')) ? s + 1 : LOCAL->response;
109.1074 +				/* return success or failure */
109.1075 +  return (*LOCAL->response =='+') ? T : NIL;
109.1076 +}
109.1077 +
109.1078 +
109.1079 +/* Post Office Protocol 3 set fake error
109.1080 + * Accepts: MAIL stream
109.1081 + *	    error text
109.1082 + * Returns: NIL, always
109.1083 + */
109.1084 +
109.1085 +long pop3_fake (MAILSTREAM *stream,char *text)
109.1086 +{
109.1087 +  mm_notify (stream,text,BYE);	/* send bye alert */
109.1088 +  if (LOCAL->netstream) net_close (LOCAL->netstream);
109.1089 +  LOCAL->netstream = NIL;	/* farewell, dear TCP stream */
109.1090 +				/* flush any old reply */
109.1091 +  if (LOCAL->response) fs_give ((void **) &LOCAL->response);
109.1092 +  LOCAL->reply = text;		/* set up pseudo-reply string */
109.1093 +  return NIL;			/* return error code */
109.1094 +}
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/src/c-client/rfc822.c	Mon Sep 14 15:17:45 2009 +0900
   110.3 @@ -0,0 +1,2369 @@
   110.4 +/* ========================================================================
   110.5 + * Copyright 1988-2008 University of Washington
   110.6 + *
   110.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   110.8 + * you may not use this file except in compliance with the License.
   110.9 + * You may obtain a copy of the License at
  110.10 + *
  110.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  110.12 + *
  110.13 + * 
  110.14 + * ========================================================================
  110.15 + */
  110.16 +
  110.17 +/*
  110.18 + * Program:	RFC 2822 and MIME routines
  110.19 + *
  110.20 + * Author:	Mark Crispin
  110.21 + *		UW Technology
  110.22 + *		University of Washington
  110.23 + *		Seattle, WA  98195
  110.24 + *		Internet: MRC@Washington.EDU
  110.25 + *
  110.26 + * Date:	27 July 1988
  110.27 + * Last Edited:	14 May 2008
  110.28 + *
  110.29 + * This original version of this file is
  110.30 + * Copyright 1988 Stanford University
  110.31 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  110.32 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  110.33 + * Biomedical Research Technology Program of the NationalInstitutes of Health
  110.34 + * under grant number RR-00785.
  110.35 + */
  110.36 +
  110.37 +
  110.38 +#include <ctype.h>
  110.39 +#include <stdio.h>
  110.40 +#include <time.h>
  110.41 +#include "c-client.h"
  110.42 +
  110.43 +
  110.44 +/* Support for deprecated features in earlier specifications.  Note that this
  110.45 + * module follows RFC 2822, and all use of "rfc822" in function names is
  110.46 + * for compatibility.  Only the code identified by the conditionals below
  110.47 + * follows the earlier documents.
  110.48 + */
  110.49 +
  110.50 +#define RFC733 1		/* parse "at" */
  110.51 +#define RFC822 0		/* generate A-D-L (MUST be 0 for 2822) */
  110.52 +
  110.53 +/* RFC-822 static data */
  110.54 +
  110.55 +#define RFC822CONT "    "	/* RFC 2822 continuation */
  110.56 +
  110.57 +				/* should have been "Remailed-" */
  110.58 +#define RESENTPREFIX "ReSent-"
  110.59 +static char *resentprefix = RESENTPREFIX;
  110.60 +				/* syntax error host string */
  110.61 +static const char *errhst = ERRHOST;
  110.62 +
  110.63 +
  110.64 +/* Body formats constant strings, must match definitions in mail.h */
  110.65 +
  110.66 +char *body_types[TYPEMAX+1] = {
  110.67 +  "TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO",
  110.68 +  "MODEL", "X-UNKNOWN"
  110.69 +};
  110.70 +
  110.71 +
  110.72 +char *body_encodings[ENCMAX+1] = {
  110.73 +  "7BIT", "8BIT", "BINARY", "BASE64", "QUOTED-PRINTABLE", "X-UNKNOWN"
  110.74 +};
  110.75 +
  110.76 +
  110.77 +/* Token delimiting special characters */
  110.78 +
  110.79 +				/* RFC 2822 specials */
  110.80 +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";
  110.81 +				/* RFC 2822 phrase specials (no space) */
  110.82 +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";
  110.83 +				/* RFC 2822 dot-atom specials (no dot) */
  110.84 +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";
  110.85 +				/* RFC 2045 MIME body token specials */
  110.86 +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";
  110.87 +
  110.88 +/* Subtype defaulting (a no-no, but regretably necessary...)
  110.89 + * Accepts: type code
  110.90 + * Returns: default subtype name
  110.91 + */
  110.92 +
  110.93 +char *rfc822_default_subtype (unsigned short type)
  110.94 +{
  110.95 +  switch (type) {
  110.96 +  case TYPETEXT:		/* default is TEXT/PLAIN */
  110.97 +    return "PLAIN";
  110.98 +  case TYPEMULTIPART:		/* default is MULTIPART/MIXED */
  110.99 +    return "MIXED";
 110.100 +  case TYPEMESSAGE:		/* default is MESSAGE/RFC822 */
 110.101 +    return "RFC822";
 110.102 +  case TYPEAPPLICATION:		/* default is APPLICATION/OCTET-STREAM */
 110.103 +    return "OCTET-STREAM";
 110.104 +  case TYPEAUDIO:		/* default is AUDIO/BASIC */
 110.105 +    return "BASIC";
 110.106 +  default:			/* others have no default subtype */
 110.107 +    return "UNKNOWN";
 110.108 +  }
 110.109 +}
 110.110 +
 110.111 +/* RFC 2822 parsing routines */
 110.112 +
 110.113 +
 110.114 +/* Parse an RFC 2822 message
 110.115 + * Accepts: pointer to return envelope
 110.116 + *	    pointer to return body
 110.117 + *	    pointer to header
 110.118 + *	    header byte count
 110.119 + *	    pointer to body stringstruct
 110.120 + *	    pointer to local host name
 110.121 + *	    recursion depth
 110.122 + *	    source driver flags
 110.123 + */
 110.124 +
 110.125 +void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
 110.126 +			    STRING *bs,char *host,unsigned long depth,
 110.127 +			    unsigned long flags)
 110.128 +{
 110.129 +  char c,*t,*d;
 110.130 +  char *tmp = (char *) fs_get ((size_t) i + 100);
 110.131 +  ENVELOPE *env = (*en = mail_newenvelope ());
 110.132 +  BODY *body = bdy ? (*bdy = mail_newbody ()) : NIL;
 110.133 +  long MIMEp = -1;		/* flag that MIME semantics are in effect */
 110.134 +  parseline_t pl = (parseline_t) mail_parameters (NIL,GET_PARSELINE,NIL);
 110.135 +  if (!host) host = BADHOST;	/* make sure that host is non-null */
 110.136 +  while (i && *s != '\n') {	/* until end of header */
 110.137 +    t = tmp;			/* initialize buffer pointer */
 110.138 +    c = ' ';			/* and previous character */
 110.139 +    while (i && c) {		/* collect text until logical end of line */
 110.140 +      switch (c = *s++) {	/* slurp a character */
 110.141 +      case '\015':		/* return, possible end of logical line */
 110.142 +	if (*s == '\n') break;	/* ignore if LF follows */
 110.143 +      case '\012':		/* LF, possible end of logical line */
 110.144 +				/* tie off unless next line starts with WS */
 110.145 +	if (*s != ' ' && *s != '\t') *t++ = c = '\0';
 110.146 +	break;
 110.147 +      case '\t':		/* tab */
 110.148 +	*t++ = ' ';		/* coerce to space */
 110.149 +	break;
 110.150 +      default:			/* all other characters */
 110.151 +	*t++ = c;		/* insert the character into the line */
 110.152 +	break;
 110.153 +      }
 110.154 +      if (!--i) *t++ = '\0';	/* see if end of header */
 110.155 +    }
 110.156 +
 110.157 +				/* find header item type */
 110.158 +    if (t = d = strchr (tmp,':')) {
 110.159 +      *d++ = '\0';		/* tie off header item, point at its data */
 110.160 +      while (*d == ' ') d++;	/* flush whitespace */
 110.161 +      while ((tmp < t--) && (*t == ' ')) *t = '\0';
 110.162 +      ucase (tmp);		/* coerce to uppercase */
 110.163 +				/* external callback */
 110.164 +      if (pl) (*pl) (env,tmp,d,host);
 110.165 +      switch (*tmp) {		/* dispatch based on first character */
 110.166 +      case '>':			/* possible >From: */
 110.167 +	if (!strcmp (tmp+1,"FROM")) rfc822_parse_adrlist (&env->from,d,host);
 110.168 +	break;
 110.169 +      case 'B':			/* possible bcc: */
 110.170 +	if (!strcmp (tmp+1,"CC")) rfc822_parse_adrlist (&env->bcc,d,host);
 110.171 +	break;
 110.172 +      case 'C':			/* possible cc: or Content-<mumble>*/
 110.173 +	if (!strcmp (tmp+1,"C")) rfc822_parse_adrlist (&env->cc,d,host);
 110.174 +	else if ((tmp[1] == 'O') && (tmp[2] == 'N') && (tmp[3] == 'T') &&
 110.175 +		 (tmp[4] == 'E') && (tmp[5] == 'N') && (tmp[6] == 'T') &&
 110.176 +		 (tmp[7] == '-') && body)
 110.177 +	  switch (MIMEp) {
 110.178 +	  case -1:		/* unknown if MIME or not */
 110.179 +	    if (!(MIMEp =	/* see if MIME-Version header exists */
 110.180 +		  search ((unsigned char *) s-1,i,
 110.181 +			  (unsigned char *)"\012MIME-Version",(long) 13))) {
 110.182 +#if 1
 110.183 +	      /* This is a disgusting kludge, and most of the messages which
 110.184 +	       * benefit from it are spam.
 110.185 +	       */
 110.186 +	      if (!strcmp (tmp+8,"TRANSFER-ENCODING") ||
 110.187 +		  (!strcmp (tmp+8,"TYPE") && strchr (d,'/'))) {
 110.188 +		MM_LOG ("Warning: MIME header encountered in non-MIME message",
 110.189 +			PARSE);
 110.190 +		MIMEp = 1;	/* declare MIME now */
 110.191 +	      }
 110.192 +	      else
 110.193 +#endif
 110.194 +		break;		/* non-MIME message */
 110.195 +	    }
 110.196 +	  case T:		/* definitely MIME */
 110.197 +	    rfc822_parse_content_header (body,tmp+8,d);
 110.198 +	  }
 110.199 +	break;
 110.200 +      case 'D':			/* possible Date: */
 110.201 +	if (!env->date && !strcmp (tmp+1,"ATE")) env->date = cpystr (d);
 110.202 +	break;
 110.203 +      case 'F':			/* possible From: */
 110.204 +	if (!strcmp (tmp+1,"ROM")) rfc822_parse_adrlist (&env->from,d,host);
 110.205 +	else if (!strcmp (tmp+1,"OLLOWUP-TO")) {
 110.206 +	  t = env->followup_to = (char *) fs_get (1 + strlen (d));
 110.207 +	  while (c = *d++) if (c != ' ') *t++ = c;
 110.208 +	  *t++ = '\0';
 110.209 +	}
 110.210 +	break;
 110.211 +      case 'I':			/* possible In-Reply-To: */
 110.212 +	if (!env->in_reply_to && !strcmp (tmp+1,"N-REPLY-TO"))
 110.213 +	  env->in_reply_to = cpystr (d);
 110.214 +	break;
 110.215 +
 110.216 +      case 'M':			/* possible Message-ID: or MIME-Version: */
 110.217 +	if (!env->message_id && !strcmp (tmp+1,"ESSAGE-ID"))
 110.218 +	  env->message_id = cpystr (d);
 110.219 +	else if (!strcmp (tmp+1,"IME-VERSION")) {
 110.220 +				/* tie off at end of phrase */
 110.221 +	  if (t = rfc822_parse_phrase (d)) *t = '\0';
 110.222 +	  rfc822_skipws (&d);	/* skip whitespace */
 110.223 +				/* known version? */
 110.224 +	  if (strcmp (d,"1.0") && strcmp (d,"RFC-XXXX"))
 110.225 +	    MM_LOG ("Warning: message has unknown MIME version",PARSE);
 110.226 +	  MIMEp = T;		/* note that we are MIME */
 110.227 +	}
 110.228 +	break;
 110.229 +      case 'N':			/* possible Newsgroups: */
 110.230 +	if (!env->newsgroups && !strcmp (tmp+1,"EWSGROUPS")) {
 110.231 +	  t = env->newsgroups = (char *) fs_get (1 + strlen (d));
 110.232 +	  while (c = *d++) if (c != ' ') *t++ = c;
 110.233 +	  *t++ = '\0';
 110.234 +	}
 110.235 +	break;
 110.236 +      case 'R':			/* possible Reply-To: */
 110.237 +	if (!strcmp (tmp+1,"EPLY-TO"))
 110.238 +	  rfc822_parse_adrlist (&env->reply_to,d,host);
 110.239 +	else if (!env->references && !strcmp (tmp+1,"EFERENCES"))
 110.240 +	  env->references = cpystr (d);
 110.241 +	break;
 110.242 +      case 'S':			/* possible Subject: or Sender: */
 110.243 +	if (!env->subject && !strcmp (tmp+1,"UBJECT"))
 110.244 +	  env->subject = cpystr (d);
 110.245 +	else if (!strcmp (tmp+1,"ENDER"))
 110.246 +	  rfc822_parse_adrlist (&env->sender,d,host);
 110.247 +	break;
 110.248 +      case 'T':			/* possible To: */
 110.249 +	if (!strcmp (tmp+1,"O")) rfc822_parse_adrlist (&env->to,d,host);
 110.250 +	break;
 110.251 +      default:
 110.252 +	break;
 110.253 +      }
 110.254 +    }
 110.255 +  }
 110.256 +  fs_give ((void **) &tmp);	/* done with scratch buffer */
 110.257 +				/* default Sender: and Reply-To: to From: */
 110.258 +  if (!env->sender) env->sender = rfc822_cpy_adr (env->from);
 110.259 +  if (!env->reply_to) env->reply_to = rfc822_cpy_adr (env->from);
 110.260 +				/* now parse the body */
 110.261 +  if (body) rfc822_parse_content (body,bs,host,depth,flags);
 110.262 +}
 110.263 +
 110.264 +/* Parse a message body content
 110.265 + * Accepts: pointer to body structure
 110.266 + *	    body string
 110.267 + *	    pointer to local host name
 110.268 + *	    recursion depth
 110.269 + *	    source driver flags
 110.270 + */
 110.271 +
 110.272 +void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth,
 110.273 +			   unsigned long flags)
 110.274 +{
 110.275 +  char c,c1,*s,*s1;
 110.276 +  int f;
 110.277 +  unsigned long i,j,k,m;
 110.278 +  PARAMETER *param;
 110.279 +  PART *part = NIL;
 110.280 +  if (depth > MAXMIMEDEPTH) {	/* excessively deep recursion? */
 110.281 +    body->type = TYPETEXT;	/* yes, probably a malicious MIMEgram */
 110.282 +    MM_LOG ("Ignoring excessively deep MIME recursion",PARSE);
 110.283 +  }
 110.284 +  if (!body->subtype)		/* default subtype if still unknown */
 110.285 +    body->subtype = cpystr (rfc822_default_subtype (body->type));
 110.286 +				/* note offset and sizes */
 110.287 +  body->contents.offset = GETPOS (bs);
 110.288 +				/* note internal body size in all cases */
 110.289 +  body->size.bytes = body->contents.text.size = i = SIZE (bs);
 110.290 +  if (!(flags & DR_CRLF)) body->size.bytes = strcrlflen (bs);
 110.291 +  switch (body->type) {		/* see if anything else special to do */
 110.292 +  case TYPETEXT:		/* text content */
 110.293 +    if (!body->parameter) {	/* no parameters set */
 110.294 +      body->parameter = mail_newbody_parameter ();
 110.295 +      body->parameter->attribute = cpystr ("CHARSET");
 110.296 +      while (i--) {		/* count lines and guess charset */
 110.297 +	c = SNX (bs);		/* get current character */
 110.298 +				/* charset still unknown? */
 110.299 +	if (!body->parameter->value) {
 110.300 +	  if ((c == I2C_ESC) && (i && i--) && ((c = SNX (bs)) == I2C_MULTI) &&
 110.301 +	      (i && i--) && (((c = SNX (bs)) == I2CS_94x94_JIS_NEW) ||
 110.302 +			     (c == I2CS_94x94_JIS_OLD)))
 110.303 +	    body->parameter->value = cpystr ("ISO-2022-JP");
 110.304 +	  else if (c & 0x80) body->parameter->value = cpystr ("X-UNKNOWN");
 110.305 +	}
 110.306 +	if (c == '\n') body->size.lines++;
 110.307 +      }
 110.308 +				/* 7-bit content */
 110.309 +      if (!body->parameter->value) switch (body->encoding) {
 110.310 +      case ENC7BIT:		/* unadorned 7-bit */
 110.311 +      case ENC8BIT:		/* unadorned 8-bit (but 7-bit content) */
 110.312 +      case ENCBINARY:		/* binary (but 7-bit content( */
 110.313 +	body->parameter->value = cpystr ("US-ASCII");
 110.314 +	break;
 110.315 +      default:			/* QUOTED-PRINTABLE, BASE64, etc. */
 110.316 +	body->parameter->value = cpystr ("X-UNKNOWN");
 110.317 +	break;
 110.318 +      }
 110.319 +    }
 110.320 +				/* just count lines */
 110.321 +    else while (i--) if ((SNX (bs)) == '\n') body->size.lines++;
 110.322 +    break;
 110.323 +
 110.324 +  case TYPEMESSAGE:		/* encapsulated message */
 110.325 +				/* encapsulated RFC-822 message? */
 110.326 +    if (!strcmp (body->subtype,"RFC822")) {
 110.327 +      body->nested.msg = mail_newmsg ();
 110.328 +      switch (body->encoding) {	/* make sure valid encoding */
 110.329 +      case ENC7BIT:		/* these are valid nested encodings */
 110.330 +      case ENC8BIT:
 110.331 +      case ENCBINARY:
 110.332 +	break;
 110.333 +      default:
 110.334 +	MM_LOG ("Ignoring nested encoding of message contents",PARSE);
 110.335 +      }
 110.336 +				/* hunt for blank line */
 110.337 +      for (c = '\012',j = 0; (i > j) && ((c != '\012') || (CHR(bs) != '\012'));
 110.338 +	   j++) if ((c1 = SNX (bs)) != '\015') c = c1;
 110.339 +      if (i > j) {		/* unless no more text */
 110.340 +	c1 = SNX (bs);		/* body starts here */
 110.341 +	j++;			/* advance count */
 110.342 +      }
 110.343 +				/* note body text offset and header size */
 110.344 +      body->nested.msg->header.text.size = j;
 110.345 +      body->nested.msg->text.text.size = body->contents.text.size - j;
 110.346 +      body->nested.msg->text.offset = GETPOS (bs);
 110.347 +      body->nested.msg->full.offset = body->nested.msg->header.offset =
 110.348 +	body->contents.offset;
 110.349 +      body->nested.msg->full.text.size = body->contents.text.size;
 110.350 +				/* copy header string */
 110.351 +      SETPOS (bs,body->contents.offset);
 110.352 +      s = (char *) fs_get ((size_t) j + 1);
 110.353 +      for (s1 = s,k = j; k--; *s1++ = SNX (bs));
 110.354 +      s[j] = '\0';		/* tie off string (not really necessary) */
 110.355 +				/* now parse the body */
 110.356 +      rfc822_parse_msg_full (&body->nested.msg->env,&body->nested.msg->body,s,
 110.357 +			     j,bs,h,depth+1,flags);
 110.358 +      fs_give ((void **) &s);	/* free header string */
 110.359 +				/* restore position */
 110.360 +      SETPOS (bs,body->contents.offset);
 110.361 +    }
 110.362 +				/* count number of lines */
 110.363 +    while (i--) if (SNX (bs) == '\n') body->size.lines++;
 110.364 +    break;
 110.365 +  case TYPEMULTIPART:		/* multiple parts */
 110.366 +    switch (body->encoding) {	/* make sure valid encoding */
 110.367 +    case ENC7BIT:		/* these are valid nested encodings */
 110.368 +    case ENC8BIT:
 110.369 +    case ENCBINARY:
 110.370 +      break;
 110.371 +    default:
 110.372 +      MM_LOG ("Ignoring nested encoding of multipart contents",PARSE);
 110.373 +    }
 110.374 +				/* remember if digest */
 110.375 +    f = !strcmp (body->subtype,"DIGEST");
 110.376 +				/* find cookie */
 110.377 +    for (s1 = NIL,param = body->parameter; param && !s1; param = param->next)
 110.378 +      if (!strcmp (param->attribute,"BOUNDARY")) s1 = param->value;
 110.379 +    if (!s1) s1 = "-";		/* yucky default */
 110.380 +    j = strlen (s1) + 2;	/* length of cookie and header */
 110.381 +    c = '\012';			/* initially at beginning of line */
 110.382 +
 110.383 +    while (i > j) {		/* examine data */
 110.384 +      if (m = GETPOS (bs)) m--;	/* get position in front of character */
 110.385 +      switch (c) {		/* examine each line */
 110.386 +      case '\015':		/* handle CRLF form */
 110.387 +	if (CHR (bs) == '\012'){/* following LF? */
 110.388 +	  c = SNX (bs); i--;	/* yes, slurp it */
 110.389 +	}
 110.390 +      case '\012':		/* at start of a line, start with -- ? */
 110.391 +	if (!(i && i-- && ((c = SNX (bs)) == '-') && i-- &&
 110.392 +	      ((c = SNX (bs)) == '-'))) break;
 110.393 +				/* see if cookie matches */
 110.394 +	if (k = j - 2) for (s = s1; i-- && *s++ == (c = SNX (bs)) && --k;);
 110.395 +	if (k) break;		/* strings didn't match if non-zero */
 110.396 +				/* terminating delimiter? */
 110.397 +	if ((c = ((i && i--) ? (SNX (bs)) : '\012')) == '-') {
 110.398 +	  if ((i && i--) && ((c = SNX (bs)) == '-') &&
 110.399 +	      ((i && i--) ? (((c = SNX (bs)) == '\015') || (c=='\012')):T)) {
 110.400 +				/* if have a final part calculate its size */
 110.401 +	    if (part) part->body.mime.text.size =
 110.402 +	      (m > part->body.mime.offset) ? (m - part->body.mime.offset) :0;
 110.403 +	    part = NIL; i = 1;	/* terminate scan */
 110.404 +	  }
 110.405 +	  break;
 110.406 +	}
 110.407 +				/* swallow trailing whitespace */
 110.408 +	while ((c == ' ') || (c == '\t'))
 110.409 +	  c = ((i && i--) ? (SNX (bs)) : '\012');
 110.410 +	switch (c) {		/* need newline after all of it */
 110.411 +	case '\015':		/* handle CRLF form */
 110.412 +	  if (i && CHR (bs) == '\012') {
 110.413 +	    c = SNX (bs); i--;/* yes, slurp it */
 110.414 +	  }
 110.415 +	case '\012':		/* new line */
 110.416 +	  if (part) {		/* calculate size of previous */
 110.417 +	    part->body.mime.text.size =
 110.418 +	      (m > part->body.mime.offset) ? (m-part->body.mime.offset) : 0;
 110.419 +	    /* instantiate next */
 110.420 +	    part = part->next = mail_newbody_part ();
 110.421 +	  }			/* otherwise start new list */
 110.422 +	  else part = body->nested.part = mail_newbody_part ();
 110.423 +				/* digest has a different default */
 110.424 +	  if (f) part->body.type = TYPEMESSAGE;
 110.425 +				/* note offset from main body */
 110.426 +	  part->body.mime.offset = GETPOS (bs);
 110.427 +	  break;
 110.428 +	default:		/* whatever it was it wasn't valid */
 110.429 +	  break;
 110.430 +	}
 110.431 +	break;
 110.432 +      default:			/* not at a line */
 110.433 +	c = SNX (bs); i--;	/* get next character */
 110.434 +	break;
 110.435 +      }
 110.436 +    }
 110.437 +
 110.438 +				/* calculate size of any final part */
 110.439 +    if (part) part->body.mime.text.size = i +
 110.440 +      ((GETPOS(bs) > part->body.mime.offset) ?
 110.441 +       (GETPOS(bs) - part->body.mime.offset) : 0);
 110.442 +				/* make a scratch buffer */
 110.443 +    s1 = (char *) fs_get ((size_t) (k = MAILTMPLEN));
 110.444 +				/* in case empty multipart */
 110.445 +    if (!body->nested.part) body->nested.part = mail_newbody_part ();
 110.446 +				/* parse non-empty body parts */
 110.447 +    for (part = body->nested.part; part; part = part->next) {
 110.448 +				/* part non-empty (header and/or content)? */
 110.449 +      if (i = part->body.mime.text.size) {
 110.450 +				/* move to that part of the body */
 110.451 +	SETPOS (bs,part->body.mime.offset);
 110.452 +				/* until end of header */
 110.453 +	while (i && ((c = CHR (bs)) != '\015') && (c != '\012')) {
 110.454 +				/* collect text until logical end of line */
 110.455 +	  for (j = 0,c = ' '; c; ) {
 110.456 +				/* make sure buffer big enough */
 110.457 +	    if (j > (k - 10)) fs_resize ((void **) &s1,k += MAILTMPLEN);
 110.458 +	    switch (c1 = SNX (bs)) {
 110.459 +	    case '\015':	/* return */
 110.460 +	      if (i && (CHR (bs) == '\012')) {
 110.461 +		c1 = SNX (bs);	/* eat any LF following */
 110.462 +		i--;
 110.463 +	      }
 110.464 +	    case '\012':	/* newline, possible end of logical line */
 110.465 +				/* tie off unless continuation */
 110.466 +	      if (!i || ((CHR (bs) != ' ') && (CHR (bs) != '\t')))
 110.467 +		s1[j] = c = '\0';
 110.468 +	      break;
 110.469 +	    case '\t':		/* tab */
 110.470 +	    case ' ':		/* insert whitespace if not already there */
 110.471 +	      if (c != ' ') s1[j++] = c = ' ';
 110.472 +	      break;
 110.473 +	    default:		/* all other characters */
 110.474 +	      s1[j++] = c = c1;	/* insert the character into the line */
 110.475 +	      break;
 110.476 +	    }
 110.477 +				/* end of data ties off the header */
 110.478 +	    if (!i || !--i) s1[j++] = c = '\0';
 110.479 +	  }
 110.480 +
 110.481 +				/* find header item type */
 110.482 +	  if (((s1[0] == 'C') || (s1[0] == 'c')) &&
 110.483 +	      ((s1[1] == 'O') || (s1[1] == 'o')) &&
 110.484 +	      ((s1[2] == 'N') || (s1[2] == 'n')) &&
 110.485 +	      ((s1[3] == 'T') || (s1[3] == 't')) &&
 110.486 +	      ((s1[4] == 'E') || (s1[4] == 'e')) &&
 110.487 +	      ((s1[5] == 'N') || (s1[5] == 'n')) &&
 110.488 +	      ((s1[6] == 'T') || (s1[6] == 't')) &&
 110.489 +	      (s1[7] == '-') && (s = strchr (s1+8,':'))) {
 110.490 +				/* tie off and flush whitespace */
 110.491 +	    for (*s++ = '\0'; *s == ' '; s++);
 110.492 +				/* parse the header */
 110.493 +	    rfc822_parse_content_header (&part->body,ucase (s1+8),s);
 110.494 +	  }
 110.495 +	}
 110.496 +				/* skip header trailing (CR)LF */
 110.497 +	if (i && (CHR (bs) =='\015')) {i--; c1 = SNX (bs);}
 110.498 +	if (i && (CHR (bs) =='\012')) {i--; c1 = SNX (bs);}
 110.499 +	j = bs->size;		/* save upper level size */
 110.500 +				/* set offset for next level, fake size to i */
 110.501 +	bs->size = GETPOS (bs) + i;
 110.502 +	part->body.mime.text.size -= i;
 110.503 +				/* now parse it */
 110.504 +	rfc822_parse_content (&part->body,bs,h,depth+1,flags);
 110.505 +	bs->size = j;		/* restore current level size */
 110.506 +      }
 110.507 +      else {			/* zero-length part, use default subtype */
 110.508 +	part->body.subtype = cpystr (rfc822_default_subtype (part->body.type));
 110.509 +				/* see if anything else special to do */
 110.510 +	switch (part->body.type) {
 110.511 +	case TYPETEXT:		/* text content */
 110.512 +				/* default parameters */
 110.513 +	  if (!part->body.parameter) {
 110.514 +	    part->body.parameter = mail_newbody_parameter ();
 110.515 +	    part->body.parameter->attribute = cpystr ("CHARSET");
 110.516 +				/* only assume US-ASCII if 7BIT */
 110.517 +	    part->body.parameter->value =
 110.518 +	      cpystr ((part->body.encoding == ENC7BIT) ?
 110.519 +		      "US-ASCII" : "X-UNKNOWN");
 110.520 +	  }
 110.521 +	  break;
 110.522 +	case TYPEMESSAGE:	/* encapsulated message in digest */
 110.523 +	  part->body.nested.msg = mail_newmsg ();
 110.524 +	  break;
 110.525 +	default:
 110.526 +	  break;
 110.527 +	}
 110.528 +      }
 110.529 +    }
 110.530 +    fs_give ((void **) &s1);	/* finished with scratch buffer */
 110.531 +    break;
 110.532 +  default:			/* nothing special to do in any other case */
 110.533 +    break;
 110.534 +  }
 110.535 +}
 110.536 +
 110.537 +/* Parse RFC 2822 body content header
 110.538 + * Accepts: body to write to
 110.539 + *	    possible content name
 110.540 + *	    remainder of header
 110.541 + */
 110.542 +
 110.543 +void rfc822_parse_content_header (BODY *body,char *name,char *s)
 110.544 +{
 110.545 +  char c,*t,tmp[MAILTMPLEN];
 110.546 +  long i;
 110.547 +  STRINGLIST *stl;
 110.548 +  rfc822_skipws (&s);		/* skip leading comments */
 110.549 +				/* flush whitespace */
 110.550 +  if (t = strchr (name,' ')) *t = '\0';
 110.551 +  switch (*name) {		/* see what kind of content */
 110.552 +  case 'I':			/* possible Content-ID */
 110.553 +    if (!(strcmp (name+1,"D") || body->id)) body->id = cpystr (s);
 110.554 +    break;
 110.555 +  case 'D':			/* possible Content-Description */
 110.556 +    if (!(strcmp (name+1,"ESCRIPTION") || body->description))
 110.557 +      body->description = cpystr (s);
 110.558 +    if (!(strcmp (name+1,"ISPOSITION") || body->disposition.type)) {
 110.559 +				/* get type word */
 110.560 +      if (!(name = rfc822_parse_word (s,tspecials))) break;
 110.561 +      c = *name;		/* remember delimiter */
 110.562 +      *name = '\0';		/* tie off type */
 110.563 +      body->disposition.type = ucase (cpystr (s));
 110.564 +      *name = c;		/* restore delimiter */
 110.565 +      rfc822_skipws (&name);	/* skip whitespace */
 110.566 +      rfc822_parse_parameter (&body->disposition.parameter,name);
 110.567 +    }
 110.568 +    break;
 110.569 +  case 'L':			/* possible Content-Language */
 110.570 +    if (!(strcmp (name+1,"ANGUAGE") || body->language)) {
 110.571 +      stl = NIL;		/* process languages */
 110.572 +      while (s && (name = rfc822_parse_word (s,tspecials))) {
 110.573 +	c = *name;		/* save delimiter */
 110.574 +	*name = '\0';		/* tie off subtype */
 110.575 +	if (stl) stl = stl->next = mail_newstringlist ();
 110.576 +	else stl = body->language = mail_newstringlist ();
 110.577 +	stl->text.data = (unsigned char *) ucase (cpystr (s));
 110.578 +	stl->text.size = strlen ((char *) stl->text.data);
 110.579 +	*name = c;		/* restore delimiter */
 110.580 +	rfc822_skipws (&name);	/* skip whitespace */
 110.581 +	if (*name == ',') {	/* any more languages? */
 110.582 +	  s = ++name;		/* advance to it them */
 110.583 +	  rfc822_skipws (&s);
 110.584 +	}
 110.585 +	else s = NIL;		/* bogus or end of list */
 110.586 +      }
 110.587 +    }
 110.588 +    else if (!(strcmp (name+1,"OCATION") || body->location))
 110.589 +      body->location = cpystr (s);
 110.590 +    break;
 110.591 +  case 'M':			/* possible Content-MD5 */
 110.592 +    if (!(strcmp (name+1,"D5") || body->md5)) body->md5 = cpystr (s);
 110.593 +    break;
 110.594 +
 110.595 +  case 'T':			/* possible Content-Type/Transfer-Encoding */
 110.596 +    if (!(strcmp (name+1,"YPE") || body->subtype || body->parameter)) {
 110.597 +				/* get type word */
 110.598 +      if (!(name = rfc822_parse_word (s,tspecials))) break;
 110.599 +      c = *name;		/* remember delimiter */
 110.600 +      *name = '\0';		/* tie off type */
 110.601 +				/* search for body type */
 110.602 +      for (i = 0,s = rfc822_cpy (s);
 110.603 +	   (i <= TYPEMAX) && body_types[i] &&
 110.604 +	     compare_cstring (s,body_types[i]); i++);
 110.605 +      if (i > TYPEMAX) {	/* fell off end of loop? */
 110.606 +	body->type = TYPEOTHER;	/* coerce to X-UNKNOWN */
 110.607 +	sprintf (tmp,"MIME type table overflow: %.100s",s);
 110.608 +	MM_LOG (tmp,PARSE);
 110.609 +      }
 110.610 +      else {			/* record body type index */
 110.611 +	body->type = (unsigned short) i;
 110.612 +				/* and name if new type */
 110.613 +	if (body_types[body->type]) fs_give ((void **) &s);
 110.614 +	else {			/* major MIME body type unknown to us */
 110.615 +	  body_types[body->type] = ucase (s);
 110.616 +	  sprintf (tmp,"Unknown MIME type: %.100s",s);
 110.617 +	  MM_LOG (tmp,PARSE);
 110.618 +	}
 110.619 +      }
 110.620 +      *name = c;		/* restore delimiter */
 110.621 +      rfc822_skipws (&name);	/* skip whitespace */
 110.622 +      if ((*name == '/') &&	/* subtype? */
 110.623 +	  (name = rfc822_parse_word ((s = ++name),tspecials))) {
 110.624 +	c = *name;		/* save delimiter */
 110.625 +	*name = '\0';		/* tie off subtype */
 110.626 +	rfc822_skipws (&s);	/* copy subtype */
 110.627 +	if (s) body->subtype = ucase (rfc822_cpy (s));
 110.628 +	*name = c;		/* restore delimiter */
 110.629 +	rfc822_skipws (&name);	/* skip whitespace */
 110.630 +      }
 110.631 +      else if (!name) {		/* no subtype, was a subtype delimiter? */
 110.632 +	name = s;		/* barf, restore pointer */
 110.633 +	rfc822_skipws (&name);	/* skip leading whitespace */
 110.634 +      }
 110.635 +      rfc822_parse_parameter (&body->parameter,name);
 110.636 +    }
 110.637 +
 110.638 +    else if (!strcmp (name+1,"RANSFER-ENCODING")) {
 110.639 +      if (!(name = rfc822_parse_word (s,tspecials))) break;
 110.640 +      c = *name;		/* remember delimiter */
 110.641 +      *name = '\0';		/* tie off encoding */
 110.642 +				/* search for body encoding */      
 110.643 +      for (i = 0,s = rfc822_cpy (s);
 110.644 +	   (i <= ENCMAX) && body_encodings[i] &&
 110.645 +	     compare_cstring (s,body_encodings[i]); i++);
 110.646 +      if (i > ENCMAX) {		/* fell off end of loop? */
 110.647 +	body->encoding = ENCOTHER;
 110.648 +	sprintf (tmp,"MIME encoding table overflow: %.100s",s);
 110.649 +	MM_LOG (tmp,PARSE);
 110.650 +      }
 110.651 +      else {			/* record body encoding index */
 110.652 +	body->encoding = (unsigned short) i;
 110.653 +				/* and name if new encoding */
 110.654 +	if (body_encodings[body->encoding]) fs_give ((void **) &s);
 110.655 +	else {
 110.656 +	  body_encodings[body->encoding] = ucase (s);
 110.657 +	  sprintf (tmp,"Unknown MIME transfer encoding: %.100s",s);
 110.658 +	  MM_LOG (tmp,PARSE);
 110.659 +	}
 110.660 +      }
 110.661 +      *name = c;		/* restore delimiter */
 110.662 +      /* ??check for cruft here?? */
 110.663 +    }
 110.664 +    break;
 110.665 +  default:			/* otherwise unknown */
 110.666 +    break;
 110.667 +  }
 110.668 +}
 110.669 +
 110.670 +/* Parse RFC 2822 body parameter list
 110.671 + * Accepts: parameter list to write to
 110.672 + *	    text of list
 110.673 + */
 110.674 +
 110.675 +void rfc822_parse_parameter (PARAMETER **par,char *text)
 110.676 +{
 110.677 +  char c,*s,tmp[MAILTMPLEN];
 110.678 +  PARAMETER *param = NIL;
 110.679 +				/* parameter list? */
 110.680 +  while (text && (*text == ';') &&
 110.681 +	 (text = rfc822_parse_word ((s = ++text),tspecials))) {
 110.682 +    c = *text;			/* remember delimiter */
 110.683 +    *text = '\0';		/* tie off attribute name */
 110.684 +    rfc822_skipws (&s);		/* skip leading attribute whitespace */
 110.685 +    if (!*s) *text = c;		/* must have an attribute name */
 110.686 +    else {			/* instantiate a new parameter */
 110.687 +      if (*par) param = param->next = mail_newbody_parameter ();
 110.688 +      else param = *par = mail_newbody_parameter ();
 110.689 +      param->attribute = ucase (cpystr (s));
 110.690 +      *text = c;		/* restore delimiter */
 110.691 +      rfc822_skipws (&text);	/* skip whitespace before equal sign */
 110.692 +      if ((*text == '=') &&	/* make sure have value */
 110.693 +	  (text = rfc822_parse_word ((s = ++text),tspecials))) {
 110.694 +	c = *text;		/* remember delimiter */
 110.695 +	*text = '\0';		/* tie off value */
 110.696 +	rfc822_skipws (&s);	/* skip leading value whitespace */
 110.697 +	if (*s) param->value = rfc822_cpy (s);
 110.698 +	*text = c;		/* restore delimiter */
 110.699 +	rfc822_skipws (&text);
 110.700 +      }
 110.701 +      if (!param->value) {	/* value not found? */
 110.702 +	param->value = cpystr ("MISSING_PARAMETER_VALUE");
 110.703 +	sprintf (tmp,"Missing parameter value: %.80s",param->attribute);
 110.704 +	MM_LOG (tmp,PARSE);
 110.705 +      }
 110.706 +    }
 110.707 +  }
 110.708 +				/* string not present */
 110.709 +  if (!text) MM_LOG ("Missing parameter",PARSE);
 110.710 +  else if (*text) {		/* must be end of poop */
 110.711 +    sprintf (tmp,"Unexpected characters at end of parameters: %.80s",text);
 110.712 +    MM_LOG (tmp,PARSE);
 110.713 +  }
 110.714 +}
 110.715 +
 110.716 +/* Parse RFC 2822 address list
 110.717 + * Accepts: address list to write to
 110.718 + *	    input string
 110.719 + *	    default host name
 110.720 + */
 110.721 +
 110.722 +void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host)
 110.723 +{
 110.724 +  int c;
 110.725 +  char *s,tmp[MAILTMPLEN];
 110.726 +  ADDRESS *last = *lst;
 110.727 +  ADDRESS *adr;
 110.728 +  if (!string) return;		/* no string */
 110.729 +  rfc822_skipws (&string);	/* skip leading WS */
 110.730 +  if (!*string) return;		/* empty string */
 110.731 +				/* run to tail of list */
 110.732 +  if (last) while (last->next) last = last->next;
 110.733 +  while (string) {		/* loop until string exhausted */
 110.734 +    while (*string == ',') {	/* RFC 822 allowed null addresses!! */
 110.735 +      ++string;			/* skip the comma */
 110.736 +      rfc822_skipws (&string);	/* and any leading WS */
 110.737 +    }
 110.738 +    if (!*string) string = NIL;	/* punt if ran out of string */
 110.739 +				/* got an address? */
 110.740 +    else if (adr = rfc822_parse_address (lst,last,&string,host,0)) {
 110.741 +      last = adr;		/* new tail address */
 110.742 +      if (string) {		/* analyze what follows */
 110.743 +	rfc822_skipws (&string);
 110.744 +	switch (c = *(unsigned char *) string) {
 110.745 +	case ',':		/* comma? */
 110.746 +	  ++string;		/* then another address follows */
 110.747 +	  break;
 110.748 +	default:
 110.749 +	  s = isalnum (c) ? "Must use comma to separate addresses: %.80s" :
 110.750 +	    "Unexpected characters at end of address: %.80s";
 110.751 +	  sprintf (tmp,s,string);
 110.752 +	  MM_LOG (tmp,PARSE);
 110.753 +	  last = last->next = mail_newaddr ();
 110.754 +	  last->mailbox = cpystr ("UNEXPECTED_DATA_AFTER_ADDRESS");
 110.755 +	  last->host = cpystr (errhst);
 110.756 +				/* falls through */
 110.757 +	case '\0':		/* null-specified address? */
 110.758 +	  string = NIL;		/* punt remainder of parse */
 110.759 +	  break;
 110.760 +	}
 110.761 +      }
 110.762 +    }
 110.763 +    else if (string) {		/* bad mailbox */
 110.764 +      rfc822_skipws (&string);	/* skip WS */
 110.765 +      if (!*string) strcpy (tmp,"Missing address after comma");
 110.766 +      else sprintf (tmp,"Invalid mailbox list: %.80s",string);
 110.767 +      MM_LOG (tmp,PARSE);
 110.768 +      string = NIL;
 110.769 +      (adr = mail_newaddr ())->mailbox = cpystr ("INVALID_ADDRESS");
 110.770 +      adr->host = cpystr (errhst);
 110.771 +      if (last) last = last->next = adr;
 110.772 +      else *lst = last = adr;
 110.773 +      break;
 110.774 +    }
 110.775 +  }
 110.776 +}
 110.777 +
 110.778 +/* Parse RFC 2822 address
 110.779 + * Accepts: address list to write to
 110.780 + *	    tail of address list
 110.781 + *	    pointer to input string
 110.782 + *	    default host name
 110.783 + *	    group nesting depth
 110.784 + * Returns: new list tail
 110.785 + */
 110.786 +
 110.787 +ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string,
 110.788 +			       char *defaulthost,unsigned long depth)
 110.789 +{
 110.790 +  ADDRESS *adr;
 110.791 +  if (!*string) return NIL;	/* no string */
 110.792 +  rfc822_skipws (string);	/* skip leading WS */
 110.793 +  if (!**string) return NIL;	/* empty string */
 110.794 +  if (adr = rfc822_parse_group (lst,last,string,defaulthost,depth)) last = adr;
 110.795 +				/* got an address? */
 110.796 +  else if (adr = rfc822_parse_mailbox (string,defaulthost)) {
 110.797 +    if (!*lst) *lst = adr;	/* yes, first time through? */
 110.798 +    else last->next = adr;	/* no, append to the list */
 110.799 +				/* set for subsequent linking */
 110.800 +    for (last = adr; last->next; last = last->next);
 110.801 +  }
 110.802 +  else if (*string) return NIL;
 110.803 +  return last;
 110.804 +}
 110.805 +
 110.806 +/* Parse RFC 2822 group
 110.807 + * Accepts: address list to write to
 110.808 + *	    pointer to tail of address list
 110.809 + *	    pointer to input string
 110.810 + *	    default host name
 110.811 + *	    group nesting depth
 110.812 + */
 110.813 +
 110.814 +ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string,
 110.815 +			     char *defaulthost,unsigned long depth)
 110.816 +{
 110.817 +  char tmp[MAILTMPLEN];
 110.818 +  char *p,*s;
 110.819 +  ADDRESS *adr;
 110.820 +  if (depth > MAXGROUPDEPTH) {	/* excessively deep recursion? */
 110.821 +    MM_LOG ("Ignoring excessively deep group recursion",PARSE);
 110.822 +    return NIL;			/* probably abusive */
 110.823 +  }
 110.824 +  if (!*string) return NIL;	/* no string */
 110.825 +  rfc822_skipws (string);	/* skip leading WS */
 110.826 +  if (!**string ||		/* trailing whitespace or not group */
 110.827 +      ((*(p = *string) != ':') && !(p = rfc822_parse_phrase (*string))))
 110.828 +    return NIL;
 110.829 +  s = p;			/* end of candidate phrase */
 110.830 +  rfc822_skipws (&s);		/* find delimiter */
 110.831 +  if (*s != ':') return NIL;	/* not really a group */
 110.832 +  *p = '\0';			/* tie off group name */
 110.833 +  p = ++s;			/* continue after the delimiter */
 110.834 +  rfc822_skipws (&p);		/* skip subsequent whitespace */
 110.835 +				/* write as address */
 110.836 +  (adr = mail_newaddr ())->mailbox = rfc822_cpy (*string);
 110.837 +  if (!*lst) *lst = adr;	/* first time through? */
 110.838 +  else last->next = adr;	/* no, append to the list */
 110.839 +  last = adr;			/* set for subsequent linking */
 110.840 +  *string = p;			/* continue after this point */
 110.841 +  while (*string && **string && (**string != ';')) {
 110.842 +    if (adr = rfc822_parse_address (lst,last,string,defaulthost,depth+1)) {
 110.843 +      last = adr;		/* new tail address */
 110.844 +      if (*string) {		/* anything more? */
 110.845 +	rfc822_skipws (string);	/* skip whitespace */
 110.846 +	switch (**string) {	/* see what follows */
 110.847 +	case ',':		/* another address? */
 110.848 +	  ++*string;		/* yes, skip past the comma */
 110.849 +	case ';':		/* end of group? */
 110.850 +	case '\0':		/* end of string */
 110.851 +	  break;
 110.852 +	default:
 110.853 +	  sprintf (tmp,"Unexpected characters after address in group: %.80s",
 110.854 +		   *string);
 110.855 +	  MM_LOG (tmp,PARSE);
 110.856 +	  *string = NIL;	/* cancel remainder of parse */
 110.857 +	  last = last->next = mail_newaddr ();
 110.858 +	  last->mailbox = cpystr ("UNEXPECTED_DATA_AFTER_ADDRESS_IN_GROUP");
 110.859 +	  last->host = cpystr (errhst);
 110.860 +	}
 110.861 +      }
 110.862 +    }
 110.863 +    else {			/* bogon */
 110.864 +      sprintf (tmp,"Invalid group mailbox list: %.80s",*string);
 110.865 +      MM_LOG (tmp,PARSE);
 110.866 +      *string = NIL;		/* cancel remainder of parse */
 110.867 +      (adr = mail_newaddr ())->mailbox = cpystr ("INVALID_ADDRESS_IN_GROUP");
 110.868 +      adr->host = cpystr (errhst);
 110.869 +      last = last->next = adr;
 110.870 +    }
 110.871 +  }
 110.872 +  if (*string) {		/* skip close delimiter */
 110.873 +    if (**string == ';') ++*string;
 110.874 +    rfc822_skipws (string);
 110.875 +  }
 110.876 +				/* append end of address mark to the list */
 110.877 +  last->next = (adr = mail_newaddr ());
 110.878 +  last = adr;			/* set for subsequent linking */
 110.879 +  return last;			/* return the tail */
 110.880 +}
 110.881 +
 110.882 +/* Parse RFC 2822 mailbox
 110.883 + * Accepts: pointer to string pointer
 110.884 + *	    default host
 110.885 + * Returns: address list
 110.886 + *
 110.887 + * Updates string pointer
 110.888 + */
 110.889 +
 110.890 +ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost)
 110.891 +{
 110.892 +  ADDRESS *adr = NIL;
 110.893 +  char *s,*end;
 110.894 +  parsephrase_t pp = (parsephrase_t) mail_parameters (NIL,GET_PARSEPHRASE,NIL);
 110.895 +  if (!*string) return NIL;	/* no string */
 110.896 +  rfc822_skipws (string);	/* flush leading whitespace */
 110.897 +  if (!**string) return NIL;	/* empty string */
 110.898 +  if (*(s = *string) == '<') 	/* note start, handle case of phraseless RA */
 110.899 +    adr = rfc822_parse_routeaddr (s,string,defaulthost);
 110.900 +				/* otherwise, expect at least one word */
 110.901 +  else if (end = rfc822_parse_phrase (s)) {
 110.902 +    if ((adr = rfc822_parse_routeaddr (end,string,defaulthost))) {
 110.903 +				/* phrase is a personal name */
 110.904 +      if (adr->personal) fs_give ((void **) &adr->personal);
 110.905 +      *end = '\0';		/* tie off phrase */
 110.906 +      adr->personal = rfc822_cpy (s);
 110.907 +    }
 110.908 +				/* call external phraseparser if phrase only */
 110.909 +    else if (pp && rfc822_phraseonly (end) &&
 110.910 +	     (adr = (*pp) (s,end,defaulthost))) {
 110.911 +      *string = end;		/* update parse pointer */
 110.912 +      rfc822_skipws (string);	/* skip WS in the normal way */
 110.913 +    }
 110.914 +    else adr = rfc822_parse_addrspec (s,string,defaulthost);
 110.915 +  }
 110.916 +  return adr;			/* return the address */
 110.917 +}
 110.918 +
 110.919 +
 110.920 +/* Check if address is a phrase only
 110.921 + * Accepts: pointer to end of phrase
 110.922 + * Returns: T if phrase only, else NIL;
 110.923 + */
 110.924 +
 110.925 +long rfc822_phraseonly (char *end)
 110.926 +{
 110.927 +  while (*end == ' ') ++end;	/* call rfc822_skipws() instead?? */
 110.928 +  switch (*end) {
 110.929 +  case '\0': case ',': case ';':
 110.930 +    return LONGT;		/* is a phrase only */
 110.931 +  }
 110.932 +  return NIL;			/* something other than phase is here */
 110.933 +}
 110.934 +
 110.935 +/* Parse RFC 2822 route-address
 110.936 + * Accepts: string pointer
 110.937 + *	    pointer to string pointer to update
 110.938 + * Returns: address
 110.939 + *
 110.940 + * Updates string pointer
 110.941 + */
 110.942 +
 110.943 +ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost)
 110.944 +{
 110.945 +  char tmp[MAILTMPLEN];
 110.946 +  ADDRESS *adr;
 110.947 +  char *s,*t,*adl;
 110.948 +  size_t adllen,i;
 110.949 +  if (!string) return NIL;
 110.950 +  rfc822_skipws (&string);	/* flush leading whitespace */
 110.951 +				/* must start with open broket */
 110.952 +  if (*string != '<') return NIL;
 110.953 +  t = ++string;			/* see if A-D-L there */
 110.954 +  rfc822_skipws (&t);		/* flush leading whitespace */
 110.955 +  for (adl = NIL,adllen = 0;	/* parse possible A-D-L */
 110.956 +       (*t == '@') && (s = rfc822_parse_domain (t+1,&t));) {
 110.957 +    i = strlen (s) + 2;		/* @ plus domain plus delimiter or NUL */
 110.958 +    if (adl) {			/* have existing A-D-L? */
 110.959 +      fs_resize ((void **) &adl,adllen + i);
 110.960 +      sprintf (adl + adllen - 1,",@%s",s);
 110.961 +    }
 110.962 +				/* write initial A-D-L */
 110.963 +    else sprintf (adl = (char *) fs_get (i),"@%s",s);
 110.964 +    adllen += i;		/* new A-D-L length */
 110.965 +    fs_give ((void **) &s);	/* don't need domain any more */
 110.966 +    rfc822_skipws (&t);		/* skip WS */
 110.967 +    if (*t != ',') break;	/* put if not comma */
 110.968 +    t++;			/* skip the comma */
 110.969 +    rfc822_skipws (&t);		/* skip WS */
 110.970 +  }
 110.971 +  if (adl) {			/* got an A-D-L? */
 110.972 +    if (*t != ':') {		/* make sure syntax good */
 110.973 +      sprintf (tmp,"Unterminated at-domain-list: %.80s%.80s",adl,t);
 110.974 +      MM_LOG (tmp,PARSE);
 110.975 +    }
 110.976 +    else string = ++t;		/* continue parse from this point */
 110.977 +  }
 110.978 +
 110.979 +				/* parse address spec */
 110.980 +  if (!(adr = rfc822_parse_addrspec (string,ret,defaulthost))) {
 110.981 +    if (adl) fs_give ((void **) &adl);
 110.982 +    return NIL;
 110.983 +  }
 110.984 +  if (adl) adr->adl = adl;	/* have an A-D-L? */
 110.985 +  if (*ret) if (**ret == '>') {	/* make sure terminated OK */
 110.986 +    ++*ret;			/* skip past the broket */
 110.987 +    rfc822_skipws (ret);	/* flush trailing WS */
 110.988 +    if (!**ret) *ret = NIL;	/* wipe pointer if at end of string */
 110.989 +    return adr;			/* return the address */
 110.990 +  }
 110.991 +  sprintf (tmp,"Unterminated mailbox: %.80s@%.80s",adr->mailbox,
 110.992 +	   *adr->host == '@' ? "<null>" : adr->host);
 110.993 +  MM_LOG (tmp,PARSE);
 110.994 +  adr->next = mail_newaddr ();
 110.995 +  adr->next->mailbox = cpystr ("MISSING_MAILBOX_TERMINATOR");
 110.996 +  adr->next->host = cpystr (errhst);
 110.997 +  return adr;			/* return the address */
 110.998 +}
 110.999 +
110.1000 +/* Parse RFC 2822 address-spec
110.1001 + * Accepts: string pointer
110.1002 + *	    pointer to string pointer to update
110.1003 + *	    default host
110.1004 + * Returns: address
110.1005 + *
110.1006 + * Updates string pointer
110.1007 + */
110.1008 +
110.1009 +ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost)
110.1010 +{
110.1011 +  ADDRESS *adr;
110.1012 +  char c,*s,*t,*v,*end;
110.1013 +  if (!string) return NIL;	/* no string */
110.1014 +  rfc822_skipws (&string);	/* flush leading whitespace */
110.1015 +  if (!*string) return NIL;	/* empty string */
110.1016 +				/* find end of mailbox */
110.1017 +  if (!(t = rfc822_parse_word (string,wspecials))) return NIL;
110.1018 +  adr = mail_newaddr ();	/* create address block */
110.1019 +  c = *t;			/* remember delimiter */
110.1020 +  *t = '\0';			/* tie off mailbox */
110.1021 +				/* copy mailbox */
110.1022 +  adr->mailbox = rfc822_cpy (string);
110.1023 +  *t = c;			/* restore delimiter */
110.1024 +  end = t;			/* remember end of mailbox */
110.1025 +  rfc822_skipws (&t);		/* skip whitespace */
110.1026 +  while (*t == '.') {		/* some cretin taking RFC 822 too seriously? */
110.1027 +    string = ++t;		/* skip past the dot and any WS */
110.1028 +    rfc822_skipws (&string);
110.1029 +				/* get next word of mailbox */
110.1030 +    if (t = rfc822_parse_word (string,wspecials)) {
110.1031 +      end = t;			/* remember new end of mailbox */
110.1032 +      c = *t;			/* remember delimiter */
110.1033 +      *t = '\0';		/* tie off word */
110.1034 +      s = rfc822_cpy (string);	/* copy successor part */
110.1035 +      *t = c;			/* restore delimiter */
110.1036 +				/* build new mailbox */
110.1037 +      sprintf (v = (char *) fs_get (strlen (adr->mailbox) + strlen (s) + 2),
110.1038 +	       "%s.%s",adr->mailbox,s);
110.1039 +      fs_give ((void **) &adr->mailbox);
110.1040 +      adr->mailbox = v;		/* new host name */
110.1041 +      rfc822_skipws (&t);	/* skip WS after mailbox */
110.1042 +    }
110.1043 +    else {			/* barf */
110.1044 +      MM_LOG ("Invalid mailbox part after .",PARSE);
110.1045 +      break;
110.1046 +    }
110.1047 +  }
110.1048 +  t = end;			/* remember delimiter in case no host */
110.1049 +
110.1050 +  rfc822_skipws (&end);		/* sniff ahead at what follows */
110.1051 +#if RFC733			/* RFC 733 used "at" instead of "@" */
110.1052 +  if (((*end == 'a') || (*end == 'A')) &&
110.1053 +      ((end[1] == 't') || (end[1] == 'T')) &&
110.1054 +      ((end[2] == ' ') || (end[2] == '\t') || (end[2] == '\015') ||
110.1055 +       (end[2] == '\012') || (end[2] == '(')))
110.1056 +    *++end = '@';
110.1057 +#endif
110.1058 +  if (*end != '@') end = t;	/* host name missing */
110.1059 +				/* otherwise parse host name */
110.1060 +  else if (!(adr->host = rfc822_parse_domain (++end,&end)))
110.1061 +    adr->host = cpystr (errhst);
110.1062 +				/* default host if missing */
110.1063 +  if (!adr->host) adr->host = cpystr (defaulthost);
110.1064 +				/* try person name in comments if missing */
110.1065 +  if (end && !(adr->personal && *adr->personal)) {
110.1066 +    while (*end == ' ') ++end;	/* see if we can find a person name here */
110.1067 +    if ((*end == '(') && (s = rfc822_skip_comment (&end,LONGT)) && strlen (s))
110.1068 +      adr->personal = rfc822_cpy (s);
110.1069 +    rfc822_skipws (&end);	/* skip any other WS in the normal way */
110.1070 +  }
110.1071 +				/* set return to end pointer */
110.1072 +  *ret = (end && *end) ? end : NIL;
110.1073 +  return adr;			/* return the address we got */
110.1074 +}
110.1075 +
110.1076 +/* Parse RFC 2822 domain
110.1077 + * Accepts: string pointer
110.1078 + *	    pointer to return end of domain
110.1079 + * Returns: domain name or NIL if failure
110.1080 + */
110.1081 +
110.1082 +char *rfc822_parse_domain (char *string,char **end)
110.1083 +{
110.1084 +  char *ret = NIL;
110.1085 +  char c,*s,*t,*v;
110.1086 +  rfc822_skipws (&string);	/* skip whitespace */
110.1087 +  if (*string == '[') {		/* domain literal? */
110.1088 +    if (!(*end = rfc822_parse_word (string + 1,"]\\")))
110.1089 +      MM_LOG ("Empty domain literal",PARSE);
110.1090 +    else if (**end != ']') MM_LOG ("Unterminated domain literal",PARSE);
110.1091 +    else {
110.1092 +      size_t len = ++*end - string;
110.1093 +      strncpy (ret = (char *) fs_get (len + 1),string,len);
110.1094 +      ret[len] = '\0';		/* tie off literal */
110.1095 +    }
110.1096 +  }
110.1097 +				/* search for end of host */
110.1098 +  else if (t = rfc822_parse_word (string,wspecials)) {
110.1099 +    c = *t;			/* remember delimiter */
110.1100 +    *t = '\0';			/* tie off host */
110.1101 +    ret = rfc822_cpy (string);	/* copy host */
110.1102 +    *t = c;			/* restore delimiter */
110.1103 +    *end = t;			/* remember end of domain */
110.1104 +    rfc822_skipws (&t);		/* skip WS after host */
110.1105 +    while (*t == '.') {		/* some cretin taking RFC 822 too seriously? */
110.1106 +      string = ++t;		/* skip past the dot and any WS */
110.1107 +      rfc822_skipws (&string);
110.1108 +      if (string = rfc822_parse_domain (string,&t)) {
110.1109 +	*end = t;		/* remember new end of domain */
110.1110 +	c = *t;			/* remember delimiter */
110.1111 +	*t = '\0';		/* tie off host */
110.1112 +	s = rfc822_cpy (string);/* copy successor part */
110.1113 +	*t = c;			/* restore delimiter */
110.1114 +				/* build new domain */
110.1115 +	sprintf (v = (char *) fs_get (strlen (ret) + strlen (s) + 2),
110.1116 +		 "%s.%s",ret,s);
110.1117 +	fs_give ((void **) &ret);
110.1118 +	ret = v;		/* new host name */
110.1119 +	rfc822_skipws (&t);	/* skip WS after domain */
110.1120 +      }
110.1121 +      else {			/* barf */
110.1122 +	MM_LOG ("Invalid domain part after .",PARSE);
110.1123 +	break;
110.1124 +      }
110.1125 +    }
110.1126 +  }
110.1127 +  else MM_LOG ("Missing or invalid host name after @",PARSE);
110.1128 +  return ret;
110.1129 +}
110.1130 +
110.1131 +/* Parse RFC 2822 phrase
110.1132 + * Accepts: string pointer
110.1133 + * Returns: pointer to end of phrase
110.1134 + */
110.1135 +
110.1136 +char *rfc822_parse_phrase (char *s)
110.1137 +{
110.1138 +  char *curpos;
110.1139 +  if (!s) return NIL;		/* no-op if no string */
110.1140 +				/* find first word of phrase */
110.1141 +  curpos = rfc822_parse_word (s,NIL);
110.1142 +  if (!curpos) return NIL;	/* no words means no phrase */
110.1143 +  if (!*curpos) return curpos;	/* check if string ends with word */
110.1144 +  s = curpos;			/* sniff past the end of this word and WS */
110.1145 +  rfc822_skipws (&s);		/* skip whitespace */
110.1146 +				/* recurse to see if any more */
110.1147 +  return (s = rfc822_parse_phrase (s)) ? s : curpos;
110.1148 +}
110.1149 +
110.1150 +/* Parse RFC 2822 word
110.1151 + * Accepts: string pointer
110.1152 + *	    delimiter (or NIL for phrase word parsing)
110.1153 + * Returns: pointer to end of word
110.1154 + */
110.1155 +
110.1156 +char *rfc822_parse_word (char *s,const char *delimiters)
110.1157 +{
110.1158 +  char *st,*str;
110.1159 +  if (!s) return NIL;		/* no string */
110.1160 +  rfc822_skipws (&s);		/* flush leading whitespace */
110.1161 +  if (!*s) return NIL;		/* empty string */
110.1162 +  str = s;			/* hunt pointer for strpbrk */
110.1163 +  while (T) {			/* look for delimiter, return if none */
110.1164 +    if (!(st = strpbrk (str,delimiters ? delimiters : wspecials)))
110.1165 +      return str + strlen (str);
110.1166 +				/* ESC in phrase */
110.1167 +    if (!delimiters && (*st == I2C_ESC)) {
110.1168 +      str = ++st;		/* always skip past ESC */
110.1169 +      switch (*st) {		/* special hack for RFC 1468 (ISO-2022-JP) */
110.1170 +      case I2C_MULTI:		/* multi byte sequence */
110.1171 +	switch (*++st) {
110.1172 +	case I2CS_94x94_JIS_OLD:/* old JIS (1978) */
110.1173 +	case I2CS_94x94_JIS_NEW:/* new JIS (1983) */
110.1174 +	  str = ++st;		/* skip past the shift to JIS */
110.1175 +	  while (st = strchr (st,I2C_ESC))
110.1176 +	    if ((*++st == I2C_G0_94) && ((st[1] == I2CS_94_ASCII) ||
110.1177 +					 (st[1] == I2CS_94_JIS_ROMAN) ||
110.1178 +					 (st[1] == I2CS_94_JIS_BUGROM))) {
110.1179 +	      str = st += 2;	/* skip past the shift back to ASCII */
110.1180 +	      break;
110.1181 +	    }
110.1182 +				/* eats entire text if no shift back */
110.1183 +	  if (!st || !*st) return str + strlen (str);
110.1184 +	}
110.1185 +	break;
110.1186 +      case I2C_G0_94:		/* single byte sequence */
110.1187 +	switch (st[1]) {
110.1188 +	case I2CS_94_ASCII:	/* shift to ASCII */
110.1189 +	case I2CS_94_JIS_ROMAN:	/* shift to JIS-Roman */
110.1190 +	case I2CS_94_JIS_BUGROM:/* old buggy definition of JIS-Roman */
110.1191 +	  str = st + 2;		/* skip past the shift */
110.1192 +	  break;
110.1193 +	}
110.1194 +      }
110.1195 +    }
110.1196 +
110.1197 +    else switch (*st) {		/* dispatch based on delimiter */
110.1198 +    case '"':			/* quoted string */
110.1199 +				/* look for close quote */
110.1200 +      while (*++st != '"') switch (*st) {
110.1201 +      case '\0':		/* unbalanced quoted string */
110.1202 +	return NIL;		/* sick sick sick */
110.1203 +      case '\\':		/* quoted character */
110.1204 +	if (!*++st) return NIL;	/* skip the next character */
110.1205 +      default:			/* ordinary character */
110.1206 +	break;			/* no special action */
110.1207 +      }
110.1208 +      str = ++st;		/* continue parse */
110.1209 +      break;
110.1210 +    case '\\':			/* quoted character */
110.1211 +      /* This is wrong; a quoted-pair can not be part of a word.  However,
110.1212 +       * domain-literal is parsed as a word and quoted-pairs can be used
110.1213 +       * *there*.  Either way, it's pretty pathological.
110.1214 +       */
110.1215 +      if (st[1]) {		/* not on NUL though... */
110.1216 +	str = st + 2;		/* skip quoted character and go on */
110.1217 +	break;
110.1218 +      }
110.1219 +    default:			/* found a word delimiter */
110.1220 +      return (st == s) ? NIL : st;
110.1221 +    }
110.1222 +  }
110.1223 +}
110.1224 +
110.1225 +/* Copy an RFC 2822 format string
110.1226 + * Accepts: string
110.1227 + * Returns: copy of string
110.1228 + */
110.1229 +
110.1230 +char *rfc822_cpy (char *src)
110.1231 +{
110.1232 +				/* copy and unquote */
110.1233 +  return rfc822_quote (cpystr (src));
110.1234 +}
110.1235 +
110.1236 +
110.1237 +/* Unquote an RFC 2822 format string
110.1238 + * Accepts: string
110.1239 + * Returns: string
110.1240 + */
110.1241 +
110.1242 +char *rfc822_quote (char *src)
110.1243 +{
110.1244 +  char *ret = src;
110.1245 +  if (strpbrk (src,"\\\"")) {	/* any quoting in string? */
110.1246 +    char *dst = ret;
110.1247 +    while (*src) {		/* copy string */
110.1248 +      if (*src == '\"') src++;	/* skip double quote entirely */
110.1249 +      else {
110.1250 +	if (*src == '\\') src++;/* skip over single quote, copy next always */
110.1251 +	*dst++ = *src++;	/* copy character */
110.1252 +      }
110.1253 +    }
110.1254 +    *dst = '\0';		/* tie off string */
110.1255 +  }
110.1256 +  return ret;			/* return our string */
110.1257 +}
110.1258 +
110.1259 +
110.1260 +/* Copy address list
110.1261 + * Accepts: address list
110.1262 + * Returns: address list
110.1263 + */
110.1264 +
110.1265 +ADDRESS *rfc822_cpy_adr (ADDRESS *adr)
110.1266 +{
110.1267 +  ADDRESS *dadr;
110.1268 +  ADDRESS *ret = NIL;
110.1269 +  ADDRESS *prev = NIL;
110.1270 +  while (adr) {			/* loop while there's still an MAP adr */
110.1271 +    dadr = mail_newaddr ();	/* instantiate a new address */
110.1272 +    if (!ret) ret = dadr;	/* note return */
110.1273 +    if (prev) prev->next = dadr;/* tie on to the end of any previous */
110.1274 +    dadr->personal = cpystr (adr->personal);
110.1275 +    dadr->adl = cpystr (adr->adl);
110.1276 +    dadr->mailbox = cpystr (adr->mailbox);
110.1277 +    dadr->host = cpystr (adr->host);
110.1278 +    prev = dadr;		/* this is now the previous */
110.1279 +    adr = adr->next;		/* go to next address in list */
110.1280 +  }
110.1281 +  return (ret);			/* return the MTP address list */
110.1282 +}
110.1283 +
110.1284 +/* Skips RFC 2822 whitespace
110.1285 + * Accepts: pointer to string pointer
110.1286 + */
110.1287 +
110.1288 +void rfc822_skipws (char **s)
110.1289 +{
110.1290 +  while (T) switch (**s) {
110.1291 +  case ' ': case '\t': case '\015': case '\012':
110.1292 +    ++*s;			/* skip all forms of LWSP */
110.1293 +    break;
110.1294 +  case '(':			/* start of comment */
110.1295 +    if (rfc822_skip_comment (s,(long) NIL)) break;
110.1296 +  default:
110.1297 +    return;			/* end of whitespace */
110.1298 +  }
110.1299 +}
110.1300 +
110.1301 +
110.1302 +/* Skips RFC 2822 comment
110.1303 + * Accepts: pointer to string pointer
110.1304 + *	    trim flag
110.1305 + * Returns: pointer to first non-blank character of comment
110.1306 + */
110.1307 +
110.1308 +char *rfc822_skip_comment (char **s,long trim)
110.1309 +{
110.1310 +  char *ret,tmp[MAILTMPLEN];
110.1311 +  char *s1 = *s;
110.1312 +  char *t = NIL;
110.1313 +				/* skip past whitespace */
110.1314 +  for (ret = ++s1; *ret == ' '; ret++);
110.1315 +  do switch (*s1) {		/* get character of comment */
110.1316 +  case '(':			/* nested comment? */
110.1317 +    if (!rfc822_skip_comment (&s1,(long) NIL)) return NIL;
110.1318 +    t = --s1;			/* last significant char at end of comment */
110.1319 +    break;
110.1320 +  case ')':			/* end of comment? */
110.1321 +    *s = ++s1;			/* skip past end of comment */
110.1322 +    if (trim) {			/* if level 0, must trim */
110.1323 +      if (t) t[1] = '\0';	/* tie off comment string */
110.1324 +      else *ret = '\0';		/* empty comment */
110.1325 +    }
110.1326 +    return ret;
110.1327 +  case '\\':			/* quote next character? */
110.1328 +    if (*++s1) {		/* next character non-null? */
110.1329 +      t = s1;			/* update last significant character pointer */
110.1330 +      break;			/* all OK */
110.1331 +    }
110.1332 +  case '\0':			/* end of string */
110.1333 +    sprintf (tmp,"Unterminated comment: %.80s",*s);
110.1334 +    MM_LOG (tmp,PARSE);
110.1335 +    **s = '\0';			/* nuke duplicate messages in case reparse */
110.1336 +    return NIL;			/* this is wierd if it happens */
110.1337 +  case ' ':			/* whitespace isn't significant */
110.1338 +    break;
110.1339 +  default:			/* random character */
110.1340 +    t = s1;			/* update last significant character pointer */
110.1341 +    break;
110.1342 +  } while (s1++);
110.1343 +  return NIL;			/* impossible, but pacify lint et al */
110.1344 +}
110.1345 +
110.1346 +/* Buffered output routines */
110.1347 +
110.1348 +
110.1349 +/* Output character to buffer
110.1350 + * Accepts: buffer
110.1351 + *	    character to write
110.1352 + * Returns: T if success, NIL if error
110.1353 + */
110.1354 +
110.1355 +static long rfc822_output_char (RFC822BUFFER *buf,int c)
110.1356 +{
110.1357 +  if ((buf->cur == buf->end) && !rfc822_output_flush (buf)) return NIL;
110.1358 +  *buf->cur++ = c;		/* add character, soutr buffer if full */
110.1359 +  return (buf->cur == buf->end) ? rfc822_output_flush (buf) : LONGT;
110.1360 +}
110.1361 +
110.1362 +
110.1363 +/* Output data to buffer
110.1364 + * Accepts: buffer
110.1365 + *	    data to write
110.1366 + *	    size of data
110.1367 + * Returns: T if success, NIL if error
110.1368 + */
110.1369 +
110.1370 +static long rfc822_output_data (RFC822BUFFER *buf,char *string,long len)
110.1371 +{
110.1372 +  while (len) {			/* until request satified */
110.1373 +    long i;
110.1374 +    if (i = min (len,buf->end - buf->cur)) {
110.1375 +      memcpy (buf->cur,string,i);
110.1376 +      buf->cur += i;		/* blat data */
110.1377 +      string += i;
110.1378 +      len -= i;
110.1379 +    }
110.1380 +				/* soutr buffer now if full */
110.1381 +    if ((len || (buf->cur == buf->end)) && !rfc822_output_flush (buf))
110.1382 +      return NIL;
110.1383 +  }
110.1384 +  return LONGT;
110.1385 +}
110.1386 +
110.1387 +/* Output string to buffer
110.1388 + * Accepts: buffer
110.1389 + *	    string to write
110.1390 + * Returns: T if success, NIL if error
110.1391 + */
110.1392 +
110.1393 +static long rfc822_output_string (RFC822BUFFER *buf,char *string)
110.1394 +{
110.1395 +  return rfc822_output_data (buf,string,strlen (string));
110.1396 +}
110.1397 +
110.1398 +
110.1399 +/* Flush buffer
110.1400 + * Accepts: buffer
110.1401 + *	    I/O routine
110.1402 + *	    stream for I/O routine
110.1403 + * Returns: T if success, NIL if error
110.1404 + */
110.1405 +
110.1406 +long rfc822_output_flush (RFC822BUFFER *buf)
110.1407 +{
110.1408 +  *buf->cur = '\0';		/* tie off buffer at this point */
110.1409 +  return (*buf->f) (buf->s,buf->cur = buf->beg);
110.1410 +}
110.1411 +
110.1412 +/* Message writing routines */
110.1413 +
110.1414 +
110.1415 +/* Output RFC 822 message
110.1416 + * Accepts: temporary buffer as a SIZEDTEXT
110.1417 + *	    envelope
110.1418 + *	    body
110.1419 + *	    I/O routine
110.1420 + *	    stream for I/O routine
110.1421 + *	    non-zero if 8-bit output desired
110.1422 + * Returns: T if successful, NIL if failure
110.1423 + *
110.1424 + * This routine always uses standard specials for phrases and does not write
110.1425 + * bcc entries, since it is called from the SMTP and NNTP routines.  If you
110.1426 + * need to do something different you need to arm an rfc822outfull_t and/or
110.1427 + * rfc822out_t function.
110.1428 + */
110.1429 +
110.1430 +long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8)
110.1431 +{
110.1432 +  rfc822outfull_t r822of =
110.1433 +    (rfc822outfull_t) mail_parameters (NIL,GET_RFC822OUTPUTFULL,NIL);
110.1434 +  rfc822out_t r822o = (rfc822out_t) mail_parameters (NIL,GET_RFC822OUTPUT,NIL);
110.1435 +				/* call external RFC 2822 output generator */
110.1436 +  if (r822of) return (*r822of) (buf,env,body,ok8);
110.1437 +  else if (r822o) return (*r822o) (buf->cur,env,body,buf->f,buf->s,ok8);
110.1438 +				/* encode body as necessary */
110.1439 +  if (ok8) rfc822_encode_body_8bit (env,body);
110.1440 +  else rfc822_encode_body_7bit (env,body);
110.1441 +				/* output header and body */
110.1442 +  return rfc822_output_header (buf,env,body,NIL,NIL) &&
110.1443 +    rfc822_output_text (buf,body) && rfc822_output_flush (buf);
110.1444 +}
110.1445 +
110.1446 +/* Output RFC 822 header
110.1447 + * Accepts: buffer
110.1448 + *	    envelope
110.1449 + *	    body
110.1450 + *	    non-standard specials to be used for phrases if non-NIL
110.1451 + *	    flags (non-zero to include bcc
110.1452 + * Returns: T if success, NIL if failure
110.1453 + */
110.1454 +
110.1455 +long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
110.1456 +			   const char *specials,long flags)
110.1457 +{
110.1458 +  long i = env->remail ? strlen (env->remail) : 0;
110.1459 +  return			/* write header */
110.1460 +    (!i ||		      /* snip extra CRLF from remail header */
110.1461 +     rfc822_output_data (buf,env->remail,
110.1462 +			 ((i > 4) && (env->remail[i-4] == '\015')) ?
110.1463 +			 i - 2 : i)) &&
110.1464 +    rfc822_output_header_line (buf,"Newsgroups",i,env->newsgroups) &&
110.1465 +    rfc822_output_header_line (buf,"Date",i,env->date) &&
110.1466 +    rfc822_output_address_line (buf,"From",i,env->from,specials) &&
110.1467 +    rfc822_output_address_line (buf,"Sender",i,env->sender,specials) &&
110.1468 +    rfc822_output_address_line (buf,"Reply-To",i,env->reply_to,specials) &&
110.1469 +    rfc822_output_header_line (buf,"Subject",i,env->subject) &&
110.1470 +    ((env->bcc && !(env->to || env->cc)) ?
110.1471 +     rfc822_output_string (buf,"To: undisclosed recipients: ;\015\012") :
110.1472 +     LONGT) &&
110.1473 +    rfc822_output_address_line (buf,"To",i,env->to,specials) &&
110.1474 +    rfc822_output_address_line (buf,"cc",i,env->cc,specials) &&
110.1475 +    (flags ? rfc822_output_address_line (buf,"bcc",i,env->bcc,specials) : T) &&
110.1476 +    rfc822_output_header_line (buf,"In-Reply-To",i,env->in_reply_to) &&
110.1477 +    rfc822_output_header_line (buf,"Message-ID",i,env->message_id) &&
110.1478 +    rfc822_output_header_line (buf,"Followup-to",i,env->followup_to) &&
110.1479 +    rfc822_output_header_line (buf,"References",i,env->references) &&
110.1480 +    (env->remail || !body ||
110.1481 +     (rfc822_output_string (buf,"MIME-Version: 1.0\015\012") &&
110.1482 +      rfc822_output_body_header (buf,body))) &&
110.1483 +				/* write terminating blank line */
110.1484 +    rfc822_output_string (buf,"\015\012");
110.1485 +}
110.1486 +
110.1487 +/* Output RFC 2822 header text line
110.1488 + * Accepts: buffer
110.1489 + *	    pointer to header type
110.1490 + *	    non-NIL if resending
110.1491 + *	    pointer to text
110.1492 + * Returns: T if success, NIL if failure
110.1493 + */
110.1494 +
110.1495 +long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent,
110.1496 +				char *text)
110.1497 +{
110.1498 +  return !text ||
110.1499 +    ((resent ? rfc822_output_string (buf,resentprefix) : LONGT) &&
110.1500 +     rfc822_output_string (buf,type) && rfc822_output_string (buf,": ") &&
110.1501 +     rfc822_output_string (buf,text) && rfc822_output_string (buf,"\015\012"));
110.1502 +}
110.1503 +
110.1504 +
110.1505 +/* Output RFC 2822 header address line
110.1506 + * Accepts: buffer
110.1507 + *	    pointer to header type
110.1508 + *	    non-NIL if resending
110.1509 + *	    address(s) to interpret
110.1510 + *	    non-standard specials to be used for phrases if non-NIL
110.1511 + * Returns: T if success, NIL if failure
110.1512 + */
110.1513 +
110.1514 +long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent,
110.1515 +				 ADDRESS *adr,const char *specials)
110.1516 +{
110.1517 +  long pretty = strlen (type);
110.1518 +  return !adr ||
110.1519 +    ((resent ? rfc822_output_string (buf,resentprefix) : LONGT) &&
110.1520 +     rfc822_output_data (buf,type,pretty) && rfc822_output_string (buf,": ") &&
110.1521 +     rfc822_output_address_list (buf,adr,
110.1522 +				 resent ? pretty + sizeof (RESENTPREFIX) - 1 :
110.1523 +				 pretty,specials) &&
110.1524 +     rfc822_output_string (buf,"\015\012"));
110.1525 +}
110.1526 +
110.1527 +/* Output RFC 2822 address list
110.1528 + * Accepts: buffer
110.1529 + *	    pointer to address list
110.1530 + *	    non-zero if pretty-printing
110.1531 + *	    non-standard specials to be used for phrases if non-NIL
110.1532 + * Returns: T if success, NIL if failure
110.1533 + */
110.1534 +
110.1535 +long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty,
110.1536 +				 const char *specials)
110.1537 +{
110.1538 +  long n;
110.1539 +				/* default to rspecials */
110.1540 +  if (!specials) specials = rspecials;
110.1541 +  for (n = 0; adr; adr = adr->next) {
110.1542 +    char *base = buf->cur;
110.1543 +    if (adr->host) {		/* ordinary address? */
110.1544 +      if (!(pretty && n)) {	/* suppress if pretty and in group */
110.1545 +	if (			/* use phrase <route-addr> if phrase */
110.1546 +#if RFC822
110.1547 +	    adr->adl ||		/* or A-D-L */
110.1548 +#endif
110.1549 +	    (adr->personal && *adr->personal)) {
110.1550 +	  if (!((adr->personal ? rfc822_output_cat (buf,adr->personal,
110.1551 +						    rspecials) : LONGT) &&
110.1552 +		rfc822_output_string (buf," <") &&
110.1553 +		rfc822_output_address (buf,adr) &&
110.1554 +		rfc822_output_string (buf,">"))) return NIL;
110.1555 +	}
110.1556 +	else if (!rfc822_output_address (buf,adr)) return NIL;
110.1557 +	if (adr->next && adr->next->mailbox &&
110.1558 +	    !rfc822_output_string (buf,", ")) return NIL;
110.1559 +      }
110.1560 +    }
110.1561 +    else if (adr->mailbox) {	/* start of group? */
110.1562 +				/* yes, write group */
110.1563 +      if (!(rfc822_output_cat (buf,adr->mailbox,rspecials) &&
110.1564 +	    rfc822_output_string (buf,": "))) return NIL;
110.1565 +      ++n;			/* in a group now */
110.1566 +    }
110.1567 +    else if (n) {		/* must be end of group (but be paranoid) */
110.1568 +      if (!rfc822_output_char (buf,';') ||
110.1569 +	  ((!--n && adr->next && adr->next->mailbox) &&
110.1570 +	   !rfc822_output_string (buf,", "))) return NIL;
110.1571 +    }
110.1572 +    if (pretty && adr->next &&	/* pretty printing? */
110.1573 +	((pretty += ((buf->cur > base) ? buf->cur - base :
110.1574 +		     (buf->end - base) + (buf->cur - buf->beg))) >= 78)) {
110.1575 +      if (!(rfc822_output_string (buf,"\015\012") &&
110.1576 +	    rfc822_output_string (buf,RFC822CONT))) return NIL;
110.1577 +      base = buf->cur;	/* update base for pretty printing */
110.1578 +      pretty = sizeof (RFC822CONT) - 1;
110.1579 +    }
110.1580 +  }
110.1581 +  return LONGT;
110.1582 +}
110.1583 +
110.1584 +/* Write RFC 2822 route-address to string
110.1585 + * Accepts: buffer
110.1586 + *	    pointer to single address
110.1587 + * Returns: T if success, NIL if failure
110.1588 + */
110.1589 +
110.1590 +long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr)
110.1591 +{
110.1592 +  return !adr || !adr->host ||
110.1593 +    (
110.1594 +#if RFC822			/* old code with A-D-L support */
110.1595 +     (!adr->adl || (rfc822_output_string (buf,adr->adl) &&
110.1596 +		    rfc822_output_char (buf,':'))) &&
110.1597 +#endif
110.1598 +     rfc822_output_cat (buf,adr->mailbox,NIL) &&
110.1599 +     ((*adr->host == '@') ||	/* unless null host (HIGHLY discouraged!) */
110.1600 +      (rfc822_output_char (buf,'@') &&
110.1601 +       rfc822_output_cat (buf,adr->host,NIL))));
110.1602 +}
110.1603 +
110.1604 +
110.1605 +/* Output RFC 2822 string with concatenation
110.1606 + * Accepts: buffer
110.1607 + *	    string to concatenate
110.1608 + *	    list of special characters or NIL for dot-atom format
110.1609 + * Returns: T if success, NIL if failure
110.1610 + */
110.1611 +
110.1612 +long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials)
110.1613 +{
110.1614 +  char *s;
110.1615 +  if (!*src ||			/* empty string or any specials present? */
110.1616 +      (specials ? (T && strpbrk (src,specials)) :
110.1617 +       (strpbrk (src,wspecials) || (*src == '.') || strstr (src,"..") ||
110.1618 +	(src[strlen (src) - 1] == '.')))) {
110.1619 +				/* yes, write as quoted string*/
110.1620 +    if (!rfc822_output_char (buf,'"')) return NIL;
110.1621 +				/* embedded quote characters? */
110.1622 +    for (; s = strpbrk (src,"\\\""); src = s + 1) {
110.1623 +				/* yes, insert quoting */
110.1624 +      if (!(rfc822_output_data (buf,src,s-src) &&
110.1625 +	    rfc822_output_char (buf,'\\') &&
110.1626 +	    rfc822_output_char (buf,*s))) return NIL;
110.1627 +    }
110.1628 +				/* return string and trailing quote*/
110.1629 +    return rfc822_output_string (buf,src) && rfc822_output_char (buf,'"');
110.1630 +  }
110.1631 +				/* easy case */
110.1632 +  return rfc822_output_string (buf,src);
110.1633 +}
110.1634 +
110.1635 +/* Output MIME parameter list
110.1636 + * Accepts: buffer
110.1637 + *	    parameter list
110.1638 + * Returns: T if success, NIL if failure
110.1639 + */
110.1640 +
110.1641 +long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param)
110.1642 +{
110.1643 +  while (param) {
110.1644 +    if (rfc822_output_string (buf,"; ") &&
110.1645 +	rfc822_output_string (buf,param->attribute) &&
110.1646 +	rfc822_output_char (buf,'=') &&
110.1647 +	rfc822_output_cat (buf,param->value,tspecials)) param = param->next;
110.1648 +    else return NIL;
110.1649 +  }
110.1650 +  return LONGT;
110.1651 +}
110.1652 +
110.1653 +
110.1654 +/* Output RFC 2822 stringlist
110.1655 + * Accepts: buffer
110.1656 + *	    stringlist
110.1657 + * Returns: T if success, NIL if failure
110.1658 + */
110.1659 +
110.1660 +long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl)
110.1661 +{
110.1662 +  while (stl)
110.1663 +    if (!rfc822_output_cat (buf,(char *) stl->text.data,tspecials) ||
110.1664 +	((stl = stl->next) && !rfc822_output_string (buf,", ")))
110.1665 +      return NIL;
110.1666 +  return LONGT;
110.1667 +}
110.1668 +
110.1669 +/* Output body content header
110.1670 + * Accepts: buffer
110.1671 + *	    body to interpret
110.1672 + * Returns: T if success, NIL if failure
110.1673 + */
110.1674 +
110.1675 +long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body)
110.1676 +{
110.1677 +  return			/* type and subtype*/
110.1678 +    rfc822_output_string (buf,"Content-Type: ") &&
110.1679 +    rfc822_output_string (buf,body_types[body->type]) &&
110.1680 +    rfc822_output_char (buf,'/') &&
110.1681 +    rfc822_output_string (buf,body->subtype ? body->subtype :
110.1682 +			  rfc822_default_subtype (body->type)) &&
110.1683 +				/* parameters (w/ US-ASCII default */
110.1684 +    (body->parameter ? rfc822_output_parameter (buf,body->parameter) :
110.1685 +     ((body->type != TYPETEXT) ||
110.1686 +      (rfc822_output_string (buf,"; CHARSET=") &&
110.1687 +       rfc822_output_string (buf,(body->encoding == ENC7BIT) ?
110.1688 +			     "US-ASCII" : "X-UNKNOWN")))) &&
110.1689 +    (!body->encoding ||	    /* note: 7BIT never output as encoding! */
110.1690 +     (rfc822_output_string (buf,"\015\012Content-Transfer-Encoding: ") &&
110.1691 +      rfc822_output_string (buf,body_encodings[body->encoding]))) &&
110.1692 +    (!body->id ||		/* identification */
110.1693 +     (rfc822_output_string (buf,"\015\012Content-ID: ") &&
110.1694 +      rfc822_output_string (buf,body->id))) &&
110.1695 +    (!body->description ||	/* description */
110.1696 +     (rfc822_output_string (buf,"\015\012Content-Description: ") &&
110.1697 +      rfc822_output_string (buf,body->description))) &&
110.1698 +    (!body->md5 ||		/* MD5 checksum */
110.1699 +     (rfc822_output_string (buf,"\015\012Content-MD5: ") &&
110.1700 +      rfc822_output_string (buf,body->md5))) &&
110.1701 +    (!body->language ||		/* language */
110.1702 +     (rfc822_output_string (buf,"\015\012Content-Language: ") &&
110.1703 +      rfc822_output_stringlist (buf,body->language))) &&
110.1704 +    (!body->location ||		/* location */
110.1705 +     (rfc822_output_string (buf,"\015\012Content-Location: ") &&
110.1706 +      rfc822_output_string (buf,body->location))) &&
110.1707 +    (!body->disposition.type ||	/* disposition */
110.1708 +     (rfc822_output_string (buf,"\015\012Content-Disposition: ") &&
110.1709 +      rfc822_output_string (buf,body->disposition.type) &&
110.1710 +      rfc822_output_parameter (buf,body->disposition.parameter))) &&
110.1711 +    rfc822_output_string (buf,"\015\012");
110.1712 +}
110.1713 +
110.1714 +/* Encode a body for 7BIT transmittal
110.1715 + * Accepts: envelope
110.1716 + *	    body
110.1717 + */
110.1718 +
110.1719 +void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body)
110.1720 +{
110.1721 +  void *f;
110.1722 +  PART *part;
110.1723 +  PARAMETER **param;
110.1724 +  if (body) switch (body->type) {
110.1725 +  case TYPEMULTIPART:		/* multi-part */
110.1726 +    for (param = &body->parameter;
110.1727 +	 *param && strcmp ((*param)->attribute,"BOUNDARY");
110.1728 +	 param = &(*param)->next);
110.1729 +    if (!*param) {		/* cookie not set up yet? */
110.1730 +      char tmp[MAILTMPLEN];	/* make cookie not in BASE64 or QUOTEPRINT*/
110.1731 +      sprintf (tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (),
110.1732 +	       (unsigned long) random (),(unsigned long) time (0),
110.1733 +	       (unsigned long) getpid ());
110.1734 +      (*param) = mail_newbody_parameter ();
110.1735 +      (*param)->attribute = cpystr ("BOUNDARY");
110.1736 +      (*param)->value = cpystr (tmp);
110.1737 +    }
110.1738 +    part = body->nested.part;	/* encode body parts */
110.1739 +    do rfc822_encode_body_7bit (env,&part->body);
110.1740 +    while (part = part->next);	/* until done */
110.1741 +    break;
110.1742 +  case TYPEMESSAGE:		/* encapsulated message */
110.1743 +    switch (body->encoding) {
110.1744 +    case ENC7BIT:
110.1745 +      break;
110.1746 +    case ENC8BIT:
110.1747 +      MM_LOG ("8-bit included message in 7-bit message body",PARSE);
110.1748 +      break;
110.1749 +    case ENCBINARY:
110.1750 +      MM_LOG ("Binary included message in 7-bit message body",PARSE);
110.1751 +      break;
110.1752 +    default:
110.1753 +      fatal ("Invalid rfc822_encode_body_7bit message encoding");
110.1754 +    }
110.1755 +    break;			/* can't change encoding */
110.1756 +  default:			/* all else has some encoding */
110.1757 +    switch (body->encoding) {
110.1758 +    case ENC8BIT:		/* encode 8BIT into QUOTED-PRINTABLE */
110.1759 +				/* remember old 8-bit contents */
110.1760 +      f = (void *) body->contents.text.data;
110.1761 +      body->contents.text.data =
110.1762 +	rfc822_8bit (body->contents.text.data,
110.1763 +		     body->contents.text.size,&body->contents.text.size);
110.1764 +      body->encoding = ENCQUOTEDPRINTABLE;
110.1765 +      fs_give (&f);		/* flush old binary contents */
110.1766 +      break;
110.1767 +    case ENCBINARY:		/* encode binary into BASE64 */
110.1768 +				/* remember old binary contents */
110.1769 +      f = (void *) body->contents.text.data;
110.1770 +      body->contents.text.data =
110.1771 +	rfc822_binary ((void *) body->contents.text.data,
110.1772 +		       body->contents.text.size,&body->contents.text.size);
110.1773 +      body->encoding = ENCBASE64;
110.1774 +      fs_give (&f);		/* flush old binary contents */
110.1775 +    default:			/* otherwise OK */
110.1776 +      break;
110.1777 +    }
110.1778 +    break;
110.1779 +  }
110.1780 +}
110.1781 +
110.1782 +/* Encode a body for 8BIT transmittal
110.1783 + * Accepts: envelope
110.1784 + *	    body
110.1785 + */
110.1786 +
110.1787 +void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body)
110.1788 +{
110.1789 +  void *f;
110.1790 +  PART *part;
110.1791 +  PARAMETER **param;
110.1792 +  if (body) switch (body->type) {
110.1793 +  case TYPEMULTIPART:		/* multi-part */
110.1794 +    for (param = &body->parameter;
110.1795 +	 *param && strcmp ((*param)->attribute,"BOUNDARY");
110.1796 +	 param = &(*param)->next);
110.1797 +    if (!*param) {		/* cookie not set up yet? */
110.1798 +      char tmp[MAILTMPLEN];	/* make cookie not in BASE64 or QUOTEPRINT*/
110.1799 +      sprintf (tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (),
110.1800 +	       (unsigned long) random (),(unsigned long) time (0),
110.1801 +	       (unsigned long) getpid ());
110.1802 +      (*param) = mail_newbody_parameter ();
110.1803 +      (*param)->attribute = cpystr ("BOUNDARY");
110.1804 +      (*param)->value = cpystr (tmp);
110.1805 +    }
110.1806 +    part = body->nested.part;	/* encode body parts */
110.1807 +    do rfc822_encode_body_8bit (env,&part->body);
110.1808 +    while (part = part->next);	/* until done */
110.1809 +    break;
110.1810 +  case TYPEMESSAGE:		/* encapsulated message */
110.1811 +    switch (body->encoding) {
110.1812 +    case ENC7BIT:
110.1813 +    case ENC8BIT:
110.1814 +      break;
110.1815 +    case ENCBINARY:
110.1816 +      MM_LOG ("Binary included message in 8-bit message body",PARSE);
110.1817 +      break;
110.1818 +    default:
110.1819 +      fatal ("Invalid rfc822_encode_body_7bit message encoding");
110.1820 +    }
110.1821 +    break;			/* can't change encoding */
110.1822 +  default:			/* other type, encode binary into BASE64 */
110.1823 +    if (body->encoding == ENCBINARY) {
110.1824 +				/* remember old binary contents */
110.1825 +      f = (void *) body->contents.text.data;
110.1826 +      body->contents.text.data =
110.1827 +	rfc822_binary ((void *) body->contents.text.data,
110.1828 +		       body->contents.text.size,&body->contents.text.size);
110.1829 +      body->encoding = ENCBASE64;
110.1830 +      fs_give (&f);		/* flush old binary contents */
110.1831 +    }
110.1832 +    break;
110.1833 +  }
110.1834 +}
110.1835 +
110.1836 +/* Output RFC 822 text
110.1837 + * Accepts: buffer
110.1838 + *	    body
110.1839 + * Returns: T if successful, NIL if failure
110.1840 + */
110.1841 +
110.1842 +long rfc822_output_text (RFC822BUFFER *buf,BODY *body)
110.1843 +{
110.1844 +				/* MULTIPART gets special handling */
110.1845 +  if (body->type == TYPEMULTIPART) {
110.1846 +    char *cookie,tmp[MAILTMPLEN];
110.1847 +    PARAMETER *param;
110.1848 +    PART *part;
110.1849 +				/* find cookie */
110.1850 +    for (param = body->parameter; param && strcmp (param->attribute,"BOUNDARY");
110.1851 +	 param = param->next);
110.1852 +    if (param) cookie = param->value;
110.1853 +    else {		  /* make cookie not in BASE64 or QUOTEPRINT*/
110.1854 +      sprintf (cookie = tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (),
110.1855 +	       (unsigned long) random (),(unsigned long) time (0),
110.1856 +	       (unsigned long) getpid ());
110.1857 +      (param = mail_newbody_parameter ())->attribute = cpystr ("BOUNDARY");
110.1858 +      param->value = cpystr (tmp);
110.1859 +      param->next = body->parameter;
110.1860 +      body->parameter = param;
110.1861 +    }
110.1862 +				/* output each part */
110.1863 +    for (part = body->nested.part; part; part = part->next)
110.1864 +      if (!(rfc822_output_string (buf,"--") &&
110.1865 +	    rfc822_output_string (buf,cookie) &&
110.1866 +	    rfc822_output_string (buf,"\015\012") &&
110.1867 +	    rfc822_output_body_header (buf,&part->body) &&
110.1868 +	    rfc822_output_string (buf,"\015\012") &&
110.1869 +	    rfc822_output_text (buf,&part->body))) return NIL;
110.1870 +				/* output trailing cookie */
110.1871 +    return rfc822_output_string (buf,"--") &&
110.1872 +      rfc822_output_string (buf,cookie) &&
110.1873 +      rfc822_output_string (buf,"--\015\012");
110.1874 +  }
110.1875 +				/* output segment and trailing CRLF */
110.1876 +  return (!body->contents.text.data ||
110.1877 +	  rfc822_output_string (buf,(char *) body->contents.text.data)) &&
110.1878 +    rfc822_output_string (buf,"\015\012");
110.1879 +}
110.1880 +
110.1881 +/* Body contents encoding/decoding routines */
110.1882 +
110.1883 +
110.1884 +/* Convert BASE64 contents to binary
110.1885 + * Accepts: source
110.1886 + *	    length of source
110.1887 + *	    pointer to return destination length
110.1888 + * Returns: destination as binary or NIL if error
110.1889 + */
110.1890 +
110.1891 +#define WSP 0176		/* NUL, TAB, LF, FF, CR, SPC */
110.1892 +#define JNK 0177
110.1893 +#define PAD 0100
110.1894 +
110.1895 +void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len)
110.1896 +{
110.1897 +  char c,*s,tmp[MAILTMPLEN];
110.1898 +  void *ret = fs_get ((size_t) ((*len = 4 + ((srcl * 3) / 4))) + 1);
110.1899 +  char *d = (char *) ret;
110.1900 +  int e;
110.1901 +  static char decode[256] = {
110.1902 +   WSP,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,WSP,WSP,JNK,WSP,WSP,JNK,JNK,
110.1903 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1904 +   WSP,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,076,JNK,JNK,JNK,077,
110.1905 +   064,065,066,067,070,071,072,073,074,075,JNK,JNK,JNK,PAD,JNK,JNK,
110.1906 +   JNK,000,001,002,003,004,005,006,007,010,011,012,013,014,015,016,
110.1907 +   017,020,021,022,023,024,025,026,027,030,031,JNK,JNK,JNK,JNK,JNK,
110.1908 +   JNK,032,033,034,035,036,037,040,041,042,043,044,045,046,047,050,
110.1909 +   051,052,053,054,055,056,057,060,061,062,063,JNK,JNK,JNK,JNK,JNK,
110.1910 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1911 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1912 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1913 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1914 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1915 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1916 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
110.1917 +   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK
110.1918 +  };
110.1919 +				/* initialize block */
110.1920 +  memset (ret,0,((size_t) *len) + 1);
110.1921 +  *len = 0;			/* in case we return an error */
110.1922 +
110.1923 +				/* simple-minded decode */
110.1924 +  for (e = 0; srcl--; ) switch (c = decode[*src++]) {
110.1925 +  default:			/* valid BASE64 data character */
110.1926 +    switch (e++) {		/* install based on quantum position */
110.1927 +    case 0:
110.1928 +      *d = c << 2;		/* byte 1: high 6 bits */
110.1929 +      break;
110.1930 +    case 1:
110.1931 +      *d++ |= c >> 4;		/* byte 1: low 2 bits */
110.1932 +      *d = c << 4;		/* byte 2: high 4 bits */
110.1933 +      break;
110.1934 +    case 2:
110.1935 +      *d++ |= c >> 2;		/* byte 2: low 4 bits */
110.1936 +      *d = c << 6;		/* byte 3: high 2 bits */
110.1937 +      break;
110.1938 +    case 3:
110.1939 +      *d++ |= c;		/* byte 3: low 6 bits */
110.1940 +      e = 0;			/* reinitialize mechanism */
110.1941 +      break;
110.1942 +    }
110.1943 +    break;
110.1944 +  case WSP:			/* whitespace */
110.1945 +    break;
110.1946 +  case PAD:			/* padding */
110.1947 +    switch (e++) {		/* check quantum position */
110.1948 +    case 3:			/* one = is good enough in quantum 3 */
110.1949 +				/* make sure no data characters in remainder */
110.1950 +      for (; srcl; --srcl) switch (decode[*src++]) {
110.1951 +				/* ignore space, junk and extraneous padding */
110.1952 +      case WSP: case JNK: case PAD:
110.1953 +	break;
110.1954 +      default:			/* valid BASE64 data character */
110.1955 +	/* This indicates bad MIME.  One way that it can be caused is if
110.1956 +	   a single-section message was BASE64 encoded and then something
110.1957 +	   (e.g. a mailing list processor) appended text.  The problem is
110.1958 +	   that in 1 out of 3 cases, there is no padding and hence no way
110.1959 +	   to detect the end of the data.  Consequently, prudent software
110.1960 +	   will always encapsulate a BASE64 segment inside a MULTIPART.
110.1961 +	   */
110.1962 +	sprintf (tmp,"Possible data truncation in rfc822_base64(): %.80s",
110.1963 +		 (char *) src - 1);
110.1964 +	if (s = strpbrk (tmp,"\015\012")) *s = NIL;
110.1965 +	mm_log (tmp,PARSE);
110.1966 +	srcl = 1;		/* don't issue any more messages */
110.1967 +	break;
110.1968 +      }
110.1969 +      break;
110.1970 +    case 2:			/* expect a second = in quantum 2 */
110.1971 +      if (srcl && (*src == '=')) break;
110.1972 +    default:			/* impossible quantum position */
110.1973 +      fs_give (&ret);
110.1974 +      return NIL;
110.1975 +    }
110.1976 +    break;
110.1977 +  case JNK:			/* junk character */
110.1978 +    fs_give (&ret);
110.1979 +    return NIL;
110.1980 +  }
110.1981 +  *len = d - (char *) ret;	/* calculate data length */
110.1982 +  *d = '\0';			/* NUL terminate just in case */
110.1983 +  return ret;			/* return the string */
110.1984 +}
110.1985 +
110.1986 +/* Convert binary contents to BASE64
110.1987 + * Accepts: source
110.1988 + *	    length of source
110.1989 + *	    pointer to return destination length
110.1990 + * Returns: destination as BASE64
110.1991 + */
110.1992 +
110.1993 +unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len)
110.1994 +{
110.1995 +  unsigned char *ret,*d;
110.1996 +  unsigned char *s = (unsigned char *) src;
110.1997 +  char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
110.1998 +  unsigned long i = ((srcl + 2) / 3) * 4;
110.1999 +  *len = i += 2 * ((i / 60) + 1);
110.2000 +  d = ret = (unsigned char *) fs_get ((size_t) ++i);
110.2001 +				/* process tuplets */
110.2002 +  for (i = 0; srcl >= 3; s += 3, srcl -= 3) {
110.2003 +    *d++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
110.2004 +				/* byte 2: low 2 bits (1), high 4 bits (2) */
110.2005 +    *d++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f];
110.2006 +				/* byte 3: low 4 bits (2), high 2 bits (3) */
110.2007 +    *d++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f];
110.2008 +    *d++ = v[s[2] & 0x3f];	/* byte 4: low 6 bits (3) */
110.2009 +    if ((++i) == 15) {		/* output 60 characters? */
110.2010 +      i = 0;			/* restart line break count, insert CRLF */
110.2011 +      *d++ = '\015'; *d++ = '\012';
110.2012 +    }
110.2013 +  }
110.2014 +  if (srcl) {
110.2015 +    *d++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
110.2016 +				/* byte 2: low 2 bits (1), high 4 bits (2) */
110.2017 +    *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f];
110.2018 +				/* byte 3: low 4 bits (2), high 2 bits (3) */
110.2019 +    *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '=';
110.2020 +				/* byte 4: low 6 bits (3) */
110.2021 +    *d++ = srcl ? v[s[2] & 0x3f] : '=';
110.2022 +    if (srcl) srcl--;		/* count third character if processed */
110.2023 +    if ((++i) == 15) {		/* output 60 characters? */
110.2024 +      i = 0;			/* restart line break count, insert CRLF */
110.2025 +      *d++ = '\015'; *d++ = '\012';
110.2026 +    }
110.2027 +  }
110.2028 +  *d++ = '\015'; *d++ = '\012';	/* insert final CRLF */
110.2029 +  *d = '\0';			/* tie off string */
110.2030 +  if (((unsigned long) (d - ret)) != *len) fatal ("rfc822_binary logic flaw");
110.2031 +  return ret;			/* return the resulting string */
110.2032 +}
110.2033 +
110.2034 +/* Convert QUOTED-PRINTABLE contents to 8BIT
110.2035 + * Accepts: source
110.2036 + *	    length of source
110.2037 + * 	    pointer to return destination length
110.2038 + * Returns: destination as 8-bit text or NIL if error
110.2039 + */
110.2040 +
110.2041 +unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl,
110.2042 +			      unsigned long *len)
110.2043 +{
110.2044 +  char tmp[MAILTMPLEN];
110.2045 +  unsigned int bogon = NIL;
110.2046 +  unsigned char *ret = (unsigned char *) fs_get ((size_t) srcl + 1);
110.2047 +  unsigned char *d = ret;
110.2048 +  unsigned char *t = d;
110.2049 +  unsigned char *s = src;
110.2050 +  unsigned char c,e;
110.2051 +  *len = 0;			/* in case we return an error */
110.2052 +				/* until run out of characters */
110.2053 +  while (((unsigned long) (s - src)) < srcl) {
110.2054 +    switch (c = *s++) {		/* what type of character is it? */
110.2055 +    case '=':			/* quoting character */
110.2056 +      if (((unsigned long) (s - src)) < srcl) switch (c = *s++) {
110.2057 +      case '\0':		/* end of data */
110.2058 +	s--;			/* back up pointer */
110.2059 +	break;
110.2060 +      case '\015':		/* non-significant line break */
110.2061 +	if ((((unsigned long) (s - src)) < srcl) && (*s == '\012')) s++;
110.2062 +      case '\012':		/* bare LF */
110.2063 +	t = d;			/* accept any leading spaces */
110.2064 +	break;
110.2065 +      default:			/* two hex digits then */
110.2066 +	if (!(isxdigit (c) && (((unsigned long) (s - src)) < srcl) &&
110.2067 +	      (e = *s++) && isxdigit (e))) {
110.2068 +	  /* This indicates bad MIME.  One way that it can be caused is if
110.2069 +	     a single-section message was QUOTED-PRINTABLE encoded and then
110.2070 +	     something (e.g. a mailing list processor) appended text.  The
110.2071 +	     problem is that there is no way to determine where the encoded
110.2072 +	     data ended and the appended crud began.  Consequently, prudent
110.2073 +	     software will always encapsulate a QUOTED-PRINTABLE segment
110.2074 +	     inside a MULTIPART.
110.2075 +	   */
110.2076 +	  if (!bogon++) {	/* only do this once */
110.2077 +	    sprintf (tmp,"Invalid quoted-printable sequence: =%.80s",
110.2078 +		   (char *) s - 1);
110.2079 +	    mm_log (tmp,PARSE);
110.2080 +	  }
110.2081 +	  *d++ = '=';		/* treat = as ordinary character */
110.2082 +	  *d++ = c;		/* and the character following */
110.2083 +	  t = d;		/* note point of non-space */
110.2084 +	  break;
110.2085 +	}
110.2086 +	*d++ = hex2byte (c,e);	/* merge the two hex digits */
110.2087 +	t = d;			/* note point of non-space */
110.2088 +	break;
110.2089 +      }
110.2090 +      break;
110.2091 +    case ' ':			/* space, possibly bogus */
110.2092 +      *d++ = c;			/* stash the space but don't update s */
110.2093 +      break;
110.2094 +    case '\015':		/* end of line */
110.2095 +    case '\012':		/* bare LF */
110.2096 +      d = t;			/* slide back to last non-space, drop in */
110.2097 +    default:
110.2098 +      *d++ = c;			/* stash the character */
110.2099 +      t = d;			/* note point of non-space */
110.2100 +    }      
110.2101 +  }
110.2102 +  *d = '\0';			/* tie off results */
110.2103 +  *len = d - ret;		/* calculate length */
110.2104 +  return ret;			/* return the string */
110.2105 +}
110.2106 +
110.2107 +/* Convert 8BIT contents to QUOTED-PRINTABLE
110.2108 + * Accepts: source
110.2109 + *	    length of source
110.2110 + * 	    pointer to return destination length
110.2111 + * Returns: destination as quoted-printable text
110.2112 + */
110.2113 +
110.2114 +#define MAXL (size_t) 75	/* 76th position only used by continuation = */
110.2115 +
110.2116 +unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl,
110.2117 +			    unsigned long *len)
110.2118 +{
110.2119 +  unsigned long lp = 0;
110.2120 +  unsigned char *ret = (unsigned char *)
110.2121 +    fs_get ((size_t) (3*srcl + 3*(((3*srcl)/MAXL) + 1)));
110.2122 +  unsigned char *d = ret;
110.2123 +  char *hex = "0123456789ABCDEF";
110.2124 +  unsigned char c;
110.2125 +  while (srcl--) {		/* for each character */
110.2126 +				/* true line break? */
110.2127 +    if (((c = *src++) == '\015') && (*src == '\012') && srcl) {
110.2128 +      *d++ = '\015'; *d++ = *src++; srcl--;
110.2129 +      lp = 0;			/* reset line count */
110.2130 +    }
110.2131 +    else {			/* not a line break */
110.2132 +				/* quoting required? */
110.2133 +      if (iscntrl (c) || (c == 0x7f) || (c & 0x80) || (c == '=') ||
110.2134 +	  ((c == ' ') && (*src == '\015'))) {
110.2135 +	if ((lp += 3) > MAXL) {	/* yes, would line overflow? */
110.2136 +	  *d++ = '='; *d++ = '\015'; *d++ = '\012';
110.2137 +	  lp = 3;		/* set line count */
110.2138 +	}
110.2139 +	*d++ = '=';		/* quote character */
110.2140 +	*d++ = hex[c >> 4];	/* high order 4 bits */
110.2141 +	*d++ = hex[c & 0xf];	/* low order 4 bits */
110.2142 +      }
110.2143 +      else {			/* ordinary character */
110.2144 +	if ((++lp) > MAXL) {	/* would line overflow? */
110.2145 +	  *d++ = '='; *d++ = '\015'; *d++ = '\012';
110.2146 +	  lp = 1;		/* set line count */
110.2147 +	}
110.2148 +	*d++ = c;		/* ordinary character */
110.2149 +      }
110.2150 +    }
110.2151 +  }
110.2152 +  *d = '\0';			/* tie off destination */
110.2153 +  *len = d - ret;		/* calculate true size */
110.2154 +				/* try to give some space back */
110.2155 +  fs_resize ((void **) &ret,(size_t) *len + 1);
110.2156 +  return ret;
110.2157 +}
110.2158 +
110.2159 +/* Legacy Routines */
110.2160 +
110.2161 +/*
110.2162 + * WARNING: These routines are for compatibility with old software only.
110.2163 + *
110.2164 + * Their use in new software is to be avoided.
110.2165 + *
110.2166 + * These interfaces do not provide satisfactory buffer checking.  In
110.2167 + * versions of c-client prior to imap-2005, they did not provide any
110.2168 + * buffer checking at all.
110.2169 + *
110.2170 + * As a half-hearted attempt, these new compatability functions for the
110.2171 + * legacy interfaces limit what they write to size SENDBUFLEN and will
110.2172 + * fatal() if more than that is written.  However, that isn't good enough
110.2173 + * since several of these functions *append* to the buffer, and return an
110.2174 + * updated pointer.  Consequently, there is no way of knowing what the
110.2175 + * actual available space is in the buffer, yet the function will still
110.2176 + * write up to SENDBUFLEN bytes even if there is much less space actually
110.2177 + * available.  The result is a buffer overflow.
110.2178 + *
110.2179 + * You won't get a buffer overflow if you never attempt to append using
110.2180 + * these interfaces, but you can get the fatal() if it tries to write
110.2181 + * more than SENDBUFLEN bytes.
110.2182 + *
110.2183 + * To avoid this problem, use the corresponding rfc822_output_???()
110.2184 + * functions instead, e.g., rfc822_output_address() instead of
110.2185 + * rfc822_address().
110.2186 + *
110.2187 + */
110.2188 +
110.2189 +/* Flush routine, only called if overflow
110.2190 + * Accepts: stream
110.2191 + *	    string to output
110.2192 + * Returns: never
110.2193 + */
110.2194 +
110.2195 +static long rfc822_legacy_soutr (void *stream,char *string)
110.2196 +{
110.2197 +  fatal ("rfc822.c legacy routine buffer overflow");
110.2198 +  return NIL;
110.2199 +}
110.2200 +
110.2201 +/* Legacy write RFC 2822 header from message structure
110.2202 + * Accepts: scratch buffer to write into
110.2203 + *	    message envelope
110.2204 + *	    message body
110.2205 + */
110.2206 +
110.2207 +void rfc822_header (char *header,ENVELOPE *env,BODY *body)
110.2208 +{
110.2209 +  RFC822BUFFER buf;
110.2210 +				/* write at start of buffer */
110.2211 +  buf.end = (buf.beg = buf.cur = header) + SENDBUFLEN - 1;
110.2212 +  buf.f = rfc822_legacy_soutr;
110.2213 +  buf.s = NIL;
110.2214 +  rfc822_output_header (&buf,env,body,NIL,NIL);
110.2215 +  *buf.cur = '\0';		/* tie off buffer */
110.2216 +}
110.2217 +
110.2218 +
110.2219 +/* Legacy write RFC 2822 text from header line
110.2220 + * Accepts: pointer to destination string pointer
110.2221 + *	    pointer to header type
110.2222 + *	    message to interpret
110.2223 + *	    pointer to text
110.2224 + */
110.2225 +
110.2226 +void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text)
110.2227 +{
110.2228 +  RFC822BUFFER buf;
110.2229 +				/* append to buffer */
110.2230 +  buf.end = (buf.beg = buf.cur = *header + strlen (*header)) + SENDBUFLEN - 1;
110.2231 +  buf.f = rfc822_legacy_soutr;
110.2232 +  buf.s = NIL;
110.2233 +  rfc822_output_header_line (&buf,type,env->remail ? LONGT : NIL,text);
110.2234 +  *(*header = buf.cur) = '\0';	/* tie off buffer */
110.2235 +}
110.2236 +
110.2237 +/* Legacy write RFC 2822 address from header line
110.2238 + * Accepts: pointer to destination string pointer
110.2239 + *	    pointer to header type
110.2240 + *	    message to interpret
110.2241 + *	    address to interpret
110.2242 + */
110.2243 +
110.2244 +void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr)
110.2245 +{
110.2246 +  RFC822BUFFER buf;
110.2247 +				/* append to buffer */
110.2248 +  buf.end = (buf.beg = buf.cur = *header + strlen (*header)) + SENDBUFLEN - 1;
110.2249 +  buf.f = rfc822_legacy_soutr;
110.2250 +  buf.s = NIL;
110.2251 +  rfc822_output_address_line (&buf,type,env->remail ? LONGT : NIL,adr,NIL);
110.2252 +  *(*header = buf.cur) = '\0';	/* tie off buffer */
110.2253 +}
110.2254 +
110.2255 +
110.2256 +/* Legacy write RFC 2822 address list
110.2257 + * Accepts: pointer to destination string
110.2258 + *	    address to interpret
110.2259 + *	    header base if pretty-printing
110.2260 + * Returns: end of destination string
110.2261 + */
110.2262 +
110.2263 +char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base)
110.2264 +{
110.2265 +  RFC822BUFFER buf;
110.2266 +				/* append to buffer */
110.2267 +  buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1;
110.2268 +  buf.f = rfc822_legacy_soutr;
110.2269 +  buf.s = NIL;
110.2270 +  rfc822_output_address_list (&buf,adr,base ? dest - base : 0,NIL);
110.2271 +  *buf.cur = '\0';		/* tie off buffer */
110.2272 +  return buf.cur;
110.2273 +}
110.2274 +
110.2275 +
110.2276 +/* Legacy write RFC 2822 route-address to string
110.2277 + * Accepts: pointer to destination string
110.2278 + *	    address to interpret
110.2279 + */
110.2280 +
110.2281 +void rfc822_address (char *dest,ADDRESS *adr)
110.2282 +{
110.2283 +  RFC822BUFFER buf;
110.2284 +				/* append to buffer */
110.2285 +  buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1;
110.2286 +  buf.f = rfc822_legacy_soutr;
110.2287 +  buf.s = NIL;
110.2288 +  rfc822_output_address (&buf,adr);
110.2289 +  *buf.cur = '\0';		/* tie off buffer */
110.2290 +}
110.2291 +
110.2292 +/* Concatenate RFC 2822 string
110.2293 + * Accepts: pointer to destination string
110.2294 + *	    pointer to string to concatenate
110.2295 + *	    list of special characters or NIL for dot-atom format
110.2296 + */
110.2297 +
110.2298 +void rfc822_cat (char *dest,char *src,const char *specials)
110.2299 +{
110.2300 +  RFC822BUFFER buf;
110.2301 +				/* append to buffer */
110.2302 +  buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1;
110.2303 +  buf.f = rfc822_legacy_soutr;
110.2304 +  buf.s = NIL;
110.2305 +  rfc822_output_cat (&buf,src,specials);
110.2306 +  *buf.cur = '\0';		/* tie off buffer */
110.2307 +}
110.2308 +
110.2309 +
110.2310 +/* Legacy write body content header
110.2311 + * Accepts: pointer to destination string pointer
110.2312 + *	    pointer to body to interpret
110.2313 + */
110.2314 +
110.2315 +void rfc822_write_body_header (char **dst,BODY *body)
110.2316 +{
110.2317 +  RFC822BUFFER buf;
110.2318 +				/* append to buffer */
110.2319 +  buf.end = (buf.beg = buf.cur = *dst + strlen (*dst)) + SENDBUFLEN - 1;
110.2320 +  buf.f = rfc822_legacy_soutr;
110.2321 +  buf.s = NIL;
110.2322 +  rfc822_output_body_header (&buf,body);
110.2323 +  *(*dst = buf.cur) = '\0';	/* tie off buffer */
110.2324 +}
110.2325 +
110.2326 +/* Legacy output RFC 822 message
110.2327 + * Accepts: temporary buffer
110.2328 + *	    envelope
110.2329 + *	    body
110.2330 + *	    I/O routine
110.2331 + *	    stream for I/O routine
110.2332 + *	    non-zero if 8-bit output desired
110.2333 + * Returns: T if successful, NIL if failure
110.2334 + */
110.2335 +
110.2336 +long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
110.2337 +		    long ok8bit)
110.2338 +{
110.2339 +  long ret;
110.2340 +  rfc822out_t r822o = (rfc822out_t) mail_parameters (NIL,GET_RFC822OUTPUT,NIL);
110.2341 +				/* call external RFC 2822 output generator */
110.2342 +  if (r822o) ret = (*r822o) (t,env,body,f,s,ok8bit);
110.2343 +  else {			/* output generator not armed */
110.2344 +    RFC822BUFFER buf;		/* use our own buffer rather than trust */
110.2345 +    char tmp[SENDBUFLEN+1];	/*  client to give us a big enough one */
110.2346 +    buf.f = f;
110.2347 +    buf.s = s;
110.2348 +    buf.end = (buf.beg = buf.cur = t) + SENDBUFLEN - 1;
110.2349 +    tmp[SENDBUFLEN] = '\0';	/* must have additional guard byte */
110.2350 +    ret = rfc822_output_full (&buf,env,body,ok8bit);
110.2351 +  }
110.2352 +  return ret;
110.2353 +}
110.2354 +
110.2355 +
110.2356 +/* Legacy output RFC 822 body
110.2357 + * Accepts: body
110.2358 + *	    I/O routine
110.2359 + *	    stream for I/O routine
110.2360 + * Returns: T if successful, NIL if failure
110.2361 + */
110.2362 +
110.2363 +long rfc822_output_body (BODY *body,soutr_t f,void *s)
110.2364 +{
110.2365 +  RFC822BUFFER buf;
110.2366 +  char tmp[SENDBUFLEN+1];
110.2367 +  buf.f = f;
110.2368 +  buf.s = s;
110.2369 +  buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
110.2370 +  tmp[SENDBUFLEN] = '\0';	/* must have additional guard byte */
110.2371 +  return rfc822_output_text (&buf,body) && rfc822_output_flush (&buf);
110.2372 +}
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/src/c-client/rfc822.h	Mon Sep 14 15:17:45 2009 +0900
   111.3 @@ -0,0 +1,127 @@
   111.4 +/* ========================================================================
   111.5 + * Copyright 1988-2006 University of Washington
   111.6 + *
   111.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   111.8 + * you may not use this file except in compliance with the License.
   111.9 + * You may obtain a copy of the License at
  111.10 + *
  111.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  111.12 + *
  111.13 + * 
  111.14 + * ========================================================================
  111.15 + */
  111.16 +
  111.17 +/*
  111.18 + * Program:	RFC 2822 and MIME routines
  111.19 + *
  111.20 + * Author:	Mark Crispin
  111.21 + *		Networks and Distributed Computing
  111.22 + *		Computing & Communications
  111.23 + *		University of Washington
  111.24 + *		Administration Building, AG-44
  111.25 + *		Seattle, WA  98195
  111.26 + *		Internet: MRC@CAC.Washington.EDU
  111.27 + *
  111.28 + * Date:	27 July 1988
  111.29 + * Last Edited:	30 August 2006
  111.30 + *
  111.31 + * This original version of this file is
  111.32 + * Copyright 1988 Stanford University
  111.33 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  111.34 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  111.35 + * Biomedical Research Technology Program of the NationalInstitutes of Health
  111.36 + * under grant number RR-00785.
  111.37 + */
  111.38 +
  111.39 +#define MAXGROUPDEPTH 50	/* RFC [2]822 doesn't allow any group nesting */
  111.40 +#define MAXMIMEDEPTH 50		/* more than any sane MIMEgram */
  111.41 +
  111.42 +/* Output buffering for RFC [2]822 */
  111.43 +
  111.44 +typedef long (*soutr_t) (void *stream,char *string);
  111.45 +typedef long (*rfc822out_t) (char *tmp,ENVELOPE *env,BODY *body,soutr_t f,
  111.46 +			     void *s,long ok8bit);
  111.47 +
  111.48 +typedef struct rfc822buffer {
  111.49 +  soutr_t f;			/* I/O flush routine */
  111.50 +  void *s;			/* stream for I/O routine */
  111.51 +  char *beg;			/* start of buffer */
  111.52 +  char *cur;			/* current buffer pointer */
  111.53 +  char *end;			/* end of buffer */
  111.54 +} RFC822BUFFER;
  111.55 +
  111.56 +typedef long (*rfc822outfull_t) (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
  111.57 +				 long ok8bit);
  111.58 +
  111.59 +/* Function prototypes */
  111.60 +
  111.61 +char *rfc822_default_subtype (unsigned short type);
  111.62 +void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
  111.63 +			    STRING *bs,char *host,unsigned long depth,
  111.64 +			    unsigned long flags);
  111.65 +void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth,
  111.66 +			   unsigned long flags);
  111.67 +void rfc822_parse_content_header (BODY *body,char *name,char *s);
  111.68 +void rfc822_parse_parameter (PARAMETER **par,char *text);
  111.69 +void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host);
  111.70 +ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string,
  111.71 +			       char *defaulthost,unsigned long depth);
  111.72 +ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string,
  111.73 +			     char *defaulthost,unsigned long depth);
  111.74 +ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost);
  111.75 +long rfc822_phraseonly (char *end);
  111.76 +ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost);
  111.77 +ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost);
  111.78 +char *rfc822_parse_domain (char *string,char **end);
  111.79 +char *rfc822_parse_phrase (char *string);
  111.80 +char *rfc822_parse_word (char *string,const char *delimiters);
  111.81 +char *rfc822_cpy (char *src);
  111.82 +char *rfc822_quote (char *src);
  111.83 +ADDRESS *rfc822_cpy_adr (ADDRESS *adr);
  111.84 +void rfc822_skipws (char **s);
  111.85 +char *rfc822_skip_comment (char **s,long trim);
  111.86 +
  111.87 +long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8);
  111.88 +long rfc822_output_flush (RFC822BUFFER *buf);
  111.89 +long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
  111.90 +			   const char *specials,long flags);
  111.91 +long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent,
  111.92 +				char *text);
  111.93 +long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent,
  111.94 +				 ADDRESS *adr,const char *specials);
  111.95 +long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty,
  111.96 +				 const char *specials);
  111.97 +long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr);
  111.98 +long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials);
  111.99 +long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param);
 111.100 +long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl);
 111.101 +long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body);
 111.102 +void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body);
 111.103 +void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body);
 111.104 +long rfc822_output_text (RFC822BUFFER *buf,BODY *body);
 111.105 +void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len);
 111.106 +unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len);
 111.107 +unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl,
 111.108 +			      unsigned long *len);
 111.109 +unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl,
 111.110 +			    unsigned long *len);
 111.111 +
 111.112 +/* Legacy routines for compatibility with the past */
 111.113 +
 111.114 +void rfc822_header (char *header,ENVELOPE *env,BODY *body);
 111.115 +void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text);
 111.116 +void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr);
 111.117 +char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base);
 111.118 +void rfc822_address (char *dest,ADDRESS *adr);
 111.119 +void rfc822_cat (char *dest,char *src,const char *specials);
 111.120 +void rfc822_write_body_header (char **header,BODY *body);
 111.121 +long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
 111.122 +		    long ok8bit);
 111.123 +long rfc822_output_body (BODY *body,soutr_t f,void *s);
 111.124 +
 111.125 +
 111.126 +#define rfc822_write_address(dest,adr) \
 111.127 +  rfc822_write_address_full (dest,adr,NIL)
 111.128 +
 111.129 +#define rfc822_parse_msg(en,bdy,s,i,bs,host,flags) \
 111.130 +  rfc822_parse_msg_full (en,bdy,s,i,bs,host,0,flags)
   112.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   112.2 +++ b/src/c-client/smanager.c	Mon Sep 14 15:17:45 2009 +0900
   112.3 @@ -0,0 +1,129 @@
   112.4 +/* ========================================================================
   112.5 + * Copyright 1988-2006 University of Washington
   112.6 + *
   112.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   112.8 + * you may not use this file except in compliance with the License.
   112.9 + * You may obtain a copy of the License at
  112.10 + *
  112.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  112.12 + *
  112.13 + * 
  112.14 + * ========================================================================
  112.15 + */
  112.16 +
  112.17 +/*
  112.18 + * Program:	Subscription Manager
  112.19 + *
  112.20 + * Author:	Mark Crispin
  112.21 + *		Networks and Distributed Computing
  112.22 + *		Computing & Communications
  112.23 + *		University of Washington
  112.24 + *		Administration Building, AG-44
  112.25 + *		Seattle, WA  98195
  112.26 + *		Internet: MRC@CAC.Washington.EDU
  112.27 + *
  112.28 + * Date:	3 December 1992
  112.29 + * Last Edited:	6 December 2006
  112.30 + */
  112.31 +
  112.32 +
  112.33 +#include <stdio.h>
  112.34 +#include <ctype.h>
  112.35 +#include "c-client.h"
  112.36 +
  112.37 +/* Subscribe to mailbox
  112.38 + * Accepts: mailbox name
  112.39 + * Returns: T on success, NIL on failure
  112.40 + */
  112.41 +
  112.42 +long sm_subscribe (char *mailbox)
  112.43 +{
  112.44 +  FILE *f;
  112.45 +  char *s,db[MAILTMPLEN],tmp[MAILTMPLEN];
  112.46 +				/* canonicalize INBOX */
  112.47 +  if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX";
  112.48 +  SUBSCRIPTIONFILE (db);	/* open subscription database */
  112.49 +  if (f = fopen (db,"r")) {	/* make sure not already there */
  112.50 +    while (fgets (tmp,MAILTMPLEN,f)) {
  112.51 +      if (s = strchr (tmp,'\n')) *s = '\0';
  112.52 +      if (!strcmp (tmp,mailbox)) {/* already subscribed? */
  112.53 +	sprintf (tmp,"Already subscribed to mailbox %.80s",mailbox);
  112.54 +	MM_LOG (tmp,ERROR);
  112.55 +	fclose (f);
  112.56 +	return NIL;
  112.57 +      }
  112.58 +    }
  112.59 +    fclose (f);
  112.60 +  }
  112.61 +  if (!(f = fopen (db,"a"))) {	/* append new entry */
  112.62 +    MM_LOG ("Can't append to subscription database",ERROR);
  112.63 +    return NIL;
  112.64 +  }
  112.65 +  fprintf (f,"%s\n",mailbox);
  112.66 +  return (fclose (f) == EOF) ? NIL : T;
  112.67 +}
  112.68 +
  112.69 +/* Unsubscribe from mailbox
  112.70 + * Accepts: mailbox name
  112.71 + * Returns: T on success, NIL on failure
  112.72 + */
  112.73 +
  112.74 +long sm_unsubscribe (char *mailbox)
  112.75 +{
  112.76 +  FILE *f,*tf;
  112.77 +  char *s,tmp[MAILTMPLEN],old[MAILTMPLEN],newname[MAILTMPLEN];
  112.78 +  int found = NIL;
  112.79 +				/* canonicalize INBOX */
  112.80 +  if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX";
  112.81 +  SUBSCRIPTIONFILE (old);	/* make file names */
  112.82 +  SUBSCRIPTIONTEMP (newname);
  112.83 +  if (!(f = fopen (old,"r")))	/* open subscription database */
  112.84 +    MM_LOG ("No subscriptions",ERROR);
  112.85 +  else if (!(tf = fopen (newname,"w"))) {
  112.86 +    MM_LOG ("Can't create subscription temporary file",ERROR);
  112.87 +    fclose (f);
  112.88 +  }
  112.89 +  else {
  112.90 +    while (fgets (tmp,MAILTMPLEN,f)) {
  112.91 +      if (s = strchr (tmp,'\n')) *s = '\0';
  112.92 +      if (strcmp (tmp,mailbox)) fprintf (tf,"%s\n",tmp);
  112.93 +      else found = T;		/* found the name */
  112.94 +    }
  112.95 +    fclose (f);
  112.96 +    if (fclose (tf) == EOF)
  112.97 +      MM_LOG ("Can't write subscription temporary file",ERROR);
  112.98 +    else if (!found) {
  112.99 +      sprintf (tmp,"Not subscribed to mailbox %.80s",mailbox);
 112.100 +      MM_LOG (tmp,ERROR);	/* error if at end */
 112.101 +    }
 112.102 +    else if (!unlink (old) && !rename (newname,old)) return LONGT;
 112.103 +    else MM_LOG ("Can't update subscription database",ERROR);
 112.104 +  }
 112.105 +  return NIL;
 112.106 +}
 112.107 +
 112.108 +/* Read subscription database
 112.109 + * Accepts: pointer to subscription database handle (handle NIL if first time)
 112.110 + * Returns: character string for subscription database or NIL if done
 112.111 + */
 112.112 +
 112.113 +static char sbname[MAILTMPLEN];
 112.114 +
 112.115 +char *sm_read (void **sdb)
 112.116 +{
 112.117 +  FILE *f = (FILE *) *sdb;
 112.118 +  char *s;
 112.119 +  if (!f) {			/* first time through? */
 112.120 +    SUBSCRIPTIONFILE (sbname);	/* open subscription database */
 112.121 +				/* make sure not already there */
 112.122 +    if (f = fopen (sbname,"r")) *sdb = (void *) f;
 112.123 +    else return NIL;
 112.124 +  }
 112.125 +  if (fgets (sbname,MAILTMPLEN,f)) {
 112.126 +    if (s = strchr (sbname,'\n')) *s = '\0';
 112.127 +    return sbname;
 112.128 +  }
 112.129 +  fclose (f);			/* all done */
 112.130 +  *sdb = NIL;			/* zap sdb */
 112.131 +  return NIL;
 112.132 +}
   113.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   113.2 +++ b/src/c-client/smtp.c	Mon Sep 14 15:17:45 2009 +0900
   113.3 @@ -0,0 +1,793 @@
   113.4 +/* ========================================================================
   113.5 + * Copyright 1988-2008 University of Washington
   113.6 + *
   113.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   113.8 + * you may not use this file except in compliance with the License.
   113.9 + * You may obtain a copy of the License at
  113.10 + *
  113.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  113.12 + *
  113.13 + * 
  113.14 + * ========================================================================
  113.15 + */
  113.16 +
  113.17 +/*
  113.18 + * Program:	Simple Mail Transfer Protocol (SMTP) routines
  113.19 + *
  113.20 + * Author:	Mark Crispin
  113.21 + *		Networks and Distributed Computing
  113.22 + *		Computing & Communications
  113.23 + *		University of Washington
  113.24 + *		Administration Building, AG-44
  113.25 + *		Seattle, WA  98195
  113.26 + *		Internet: MRC@CAC.Washington.EDU
  113.27 + *
  113.28 + * Date:	27 July 1988
  113.29 + * Last Edited:	28 January 2008
  113.30 + *
  113.31 + * This original version of this file is
  113.32 + * Copyright 1988 Stanford University
  113.33 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  113.34 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  113.35 + * Biomedical Research Technology Program of the National Institutes of Health
  113.36 + * under grant number RR-00785.
  113.37 + */
  113.38 +
  113.39 +
  113.40 +#include <ctype.h>
  113.41 +#include <stdio.h>
  113.42 +#include "c-client.h"
  113.43 +
  113.44 +/* Constants */
  113.45 +
  113.46 +#define SMTPSSLPORT (long) 465	/* former assigned SSL TCP contact port */
  113.47 +#define SMTPGREET (long) 220	/* SMTP successful greeting */
  113.48 +#define SMTPAUTHED (long) 235	/* SMTP successful authentication */
  113.49 +#define SMTPOK (long) 250	/* SMTP OK code */
  113.50 +#define SMTPAUTHREADY (long) 334/* SMTP ready for authentication */
  113.51 +#define SMTPREADY (long) 354	/* SMTP ready for data */
  113.52 +#define SMTPSOFTFATAL (long) 421/* SMTP soft fatal code */
  113.53 +#define SMTPWANTAUTH (long) 505	/* SMTP authentication needed */
  113.54 +#define SMTPWANTAUTH2 (long) 530/* SMTP authentication needed */
  113.55 +#define SMTPUNAVAIL (long) 550	/* SMTP mailbox unavailable */
  113.56 +#define SMTPHARDERROR (long) 554/* SMTP miscellaneous hard failure */
  113.57 +
  113.58 +
  113.59 +/* Convenient access to protocol-specific data */
  113.60 +
  113.61 +#define ESMTP stream->protocol.esmtp
  113.62 +
  113.63 +
  113.64 +/* Function prototypes */
  113.65 +
  113.66 +void *smtp_challenge (void *s,unsigned long *len);
  113.67 +long smtp_response (void *s,char *response,unsigned long size);
  113.68 +long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp);
  113.69 +long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error);
  113.70 +long smtp_send (SENDSTREAM *stream,char *command,char *args);
  113.71 +long smtp_reply (SENDSTREAM *stream);
  113.72 +long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb);
  113.73 +long smtp_fake (SENDSTREAM *stream,char *text);
  113.74 +static long smtp_seterror (SENDSTREAM *stream,long code,char *text);
  113.75 +long smtp_soutr (void *stream,char *s);
  113.76 +
  113.77 +/* Mailer parameters */
  113.78 +
  113.79 +static unsigned long smtp_maxlogintrials = MAXLOGINTRIALS;
  113.80 +static long smtp_port = 0;	/* default port override */
  113.81 +static long smtp_sslport = 0;
  113.82 +
  113.83 +
  113.84 +#ifndef RFC2821
  113.85 +#define RFC2821			/* RFC 2821 compliance */
  113.86 +#endif
  113.87 +
  113.88 +/* SMTP limits, current as of RFC 2821 */
  113.89 +
  113.90 +#define SMTPMAXLOCALPART 64
  113.91 +#define SMTPMAXDOMAIN 255
  113.92 +#define SMTPMAXPATH 256
  113.93 +
  113.94 +
  113.95 +/* I have seen local parts of more than 64 octets, in spite of the SMTP
  113.96 + * limits.  So, we'll have a more generous limit that's still guaranteed
  113.97 + * not to pop the buffer, and let the server worry about it.  As of this
  113.98 + * writing, it comes out to 240.  Anyone with a mailbox name larger than
  113.99 + * that is in serious need of a life or at least a new ISP!  23 June 1998
 113.100 + */
 113.101 +
 113.102 +#define MAXLOCALPART ((MAILTMPLEN - (SMTPMAXDOMAIN + SMTPMAXPATH + 32)) / 2)
 113.103 +
 113.104 +/* Mail Transfer Protocol manipulate driver parameters
 113.105 + * Accepts: function code
 113.106 + *	    function-dependent value
 113.107 + * Returns: function-dependent return value
 113.108 + */
 113.109 +
 113.110 +void *smtp_parameters (long function,void *value)
 113.111 +{
 113.112 +  switch ((int) function) {
 113.113 +  case SET_MAXLOGINTRIALS:
 113.114 +    smtp_maxlogintrials = (unsigned long) value;
 113.115 +    break;
 113.116 +  case GET_MAXLOGINTRIALS:
 113.117 +    value = (void *) smtp_maxlogintrials;
 113.118 +    break;
 113.119 +  case SET_SMTPPORT:
 113.120 +    smtp_port = (long) value;
 113.121 +    break;
 113.122 +  case GET_SMTPPORT:
 113.123 +    value = (void *) smtp_port;
 113.124 +    break;
 113.125 +  case SET_SSLSMTPPORT:
 113.126 +    smtp_sslport = (long) value;
 113.127 +    break;
 113.128 +  case GET_SSLSMTPPORT:
 113.129 +    value = (void *) smtp_sslport;
 113.130 +    break;
 113.131 +  default:
 113.132 +    value = NIL;		/* error case */
 113.133 +    break;
 113.134 +  }
 113.135 +  return value;
 113.136 +}
 113.137 +
 113.138 +/* Mail Transfer Protocol open connection
 113.139 + * Accepts: network driver
 113.140 + *	    service host list
 113.141 + *	    port number
 113.142 + *	    service name
 113.143 + *	    SMTP open options
 113.144 + * Returns: SEND stream on success, NIL on failure
 113.145 + */
 113.146 +
 113.147 +SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,
 113.148 +			    unsigned long port,long options)
 113.149 +{
 113.150 +  SENDSTREAM *stream = NIL;
 113.151 +  long reply;
 113.152 +  char *s,tmp[MAILTMPLEN];
 113.153 +  NETSTREAM *netstream;
 113.154 +  NETMBX mb;
 113.155 +  if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR);
 113.156 +				/* maximum domain name is 64 characters */
 113.157 +  else do if (strlen (*hostlist) < SMTPMAXDOMAIN) {
 113.158 +    sprintf (tmp,"{%.1000s}",*hostlist);
 113.159 +    if (!mail_valid_net_parse_work (tmp,&mb,service ? service : "smtp") ||
 113.160 +	mb.anoflag || mb.readonlyflag) {
 113.161 +      sprintf (tmp,"Invalid host specifier: %.80s",*hostlist);
 113.162 +      mm_log (tmp,ERROR);
 113.163 +    }
 113.164 +    else {			/* light tryssl flag if requested */
 113.165 +      mb.trysslflag = (options & SOP_TRYSSL) ? T : NIL;
 113.166 +				/* explicit port overrides all */
 113.167 +      if (mb.port) port = mb.port;
 113.168 +				/* else /submit overrides port argument */
 113.169 +      else if (!compare_cstring (mb.service,"submit")) {
 113.170 +	port = SUBMITTCPPORT;	/* override port, use IANA name */
 113.171 +	strcpy (mb.service,"submission");
 113.172 +      }
 113.173 +				/* else port argument overrides SMTP port */
 113.174 +      else if (!port) port = smtp_port ? smtp_port : SMTPTCPPORT;
 113.175 +      if (netstream =		/* try to open ordinary connection */
 113.176 +	  net_open (&mb,dv,port,
 113.177 +		    (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
 113.178 +		    "*smtps",smtp_sslport ? smtp_sslport : SMTPSSLPORT)) {
 113.179 +	stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0,
 113.180 +					sizeof (SENDSTREAM));
 113.181 +	stream->netstream = netstream;
 113.182 +	stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
 113.183 +			       net_host (netstream) : mb.host);
 113.184 +	stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL;
 113.185 +	if (options & SOP_SECURE) mb.secflag = T;
 113.186 +				/* get name of local host to use */
 113.187 +	s = compare_cstring ("localhost",mb.host) ?
 113.188 +	  net_localhost (netstream) : "localhost";
 113.189 +
 113.190 +	do reply = smtp_reply (stream);
 113.191 +	while ((reply < 100) || (stream->reply[3] == '-'));
 113.192 +	if (reply != SMTPGREET){/* get SMTP greeting */
 113.193 +	  sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply);
 113.194 +	  mm_log (tmp,ERROR);
 113.195 +	  stream = smtp_close (stream);
 113.196 +	}
 113.197 +				/* try EHLO first, then HELO */
 113.198 +	else if (((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) &&
 113.199 +		 ((reply = smtp_send (stream,"HELO",s)) != SMTPOK)) {
 113.200 +	  sprintf (tmp,"SMTP hello failure: %.80s",stream->reply);
 113.201 +	  mm_log (tmp,ERROR);
 113.202 +	  stream = smtp_close (stream);
 113.203 +	}
 113.204 +	else {
 113.205 +	  NETDRIVER *ssld =(NETDRIVER *)mail_parameters(NIL,GET_SSLDRIVER,NIL);
 113.206 +	  sslstart_t stls = (sslstart_t) mail_parameters(NIL,GET_SSLSTART,NIL);
 113.207 +	  ESMTP.ok = T;		/* ESMTP server, start TLS if present */
 113.208 +	  if (!dv && stls && ESMTP.service.starttls &&
 113.209 +	      !mb.sslflag && !mb.notlsflag &&
 113.210 +	      (smtp_send (stream,"STARTTLS",NIL) == SMTPGREET)) {
 113.211 +	    mb.tlsflag = T;	/* TLS OK, get into TLS at this end */
 113.212 +	    stream->netstream->dtb = ssld;
 113.213 +				/* TLS started, negotiate it */
 113.214 +	    if (!(stream->netstream->stream = (*stls)
 113.215 +		  (stream->netstream->stream,mb.host,
 113.216 +		   (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
 113.217 +		   (mb.novalidate ? NET_NOVALIDATECERT:NIL)))){
 113.218 +				/* TLS negotiation failed after STARTTLS */
 113.219 +	      sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",
 113.220 +		       mb.host);
 113.221 +	      mm_log (tmp,ERROR);
 113.222 +				/* close without doing QUIT */
 113.223 +	      if (stream->netstream) net_close (stream->netstream);
 113.224 +	      stream->netstream = NIL;
 113.225 +	      stream = smtp_close (stream);
 113.226 +	    }
 113.227 +				/* TLS OK, re-negotiate EHLO */
 113.228 +	    else if ((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) {
 113.229 +	      sprintf (tmp,"SMTP EHLO failure after STARTTLS: %.80s",
 113.230 +		       stream->reply);
 113.231 +	      mm_log (tmp,ERROR);
 113.232 +	      stream = smtp_close (stream);
 113.233 +	    }
 113.234 +	    else ESMTP.ok = T;	/* TLS OK and EHLO successful */
 113.235 +	  }
 113.236 +	  else if (mb.tlsflag) {/* user specified /tls but can't do it */
 113.237 +	    sprintf (tmp,"TLS unavailable with this server: %.80s",mb.host);
 113.238 +	    mm_log (tmp,ERROR);
 113.239 +	    stream = smtp_close (stream);
 113.240 +	  }
 113.241 +
 113.242 +				/* remote name for authentication */
 113.243 +	  if (stream && ((mb.secflag || mb.user[0]))) {
 113.244 +	    if (ESMTP.auth) {	/* use authenticator? */
 113.245 +	      if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
 113.246 +				/* remote name for authentication */
 113.247 +		strncpy (mb.host,
 113.248 +			 (long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
 113.249 +			 net_remotehost (netstream) : net_host (netstream),
 113.250 +			 NETMAXHOST-1);
 113.251 +		mb.host[NETMAXHOST-1] = '\0';
 113.252 +	      }
 113.253 +	      if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close (stream);
 113.254 +	    }
 113.255 +	    else {		/* no available authenticators? */
 113.256 +	      sprintf (tmp,"%sSMTP authentication not available: %.80s",
 113.257 +		       mb.secflag ? "Secure " : "",mb.host);
 113.258 +	      mm_log (tmp,ERROR);
 113.259 +	      stream = smtp_close (stream);
 113.260 +	    }
 113.261 +	  }
 113.262 +	}
 113.263 +      }
 113.264 +    }
 113.265 +  } while (!stream && *++hostlist);
 113.266 +  if (stream) {			/* set stream options if have a stream */
 113.267 +    if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY |
 113.268 +		  SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) {
 113.269 +      ESMTP.dsn.want = T;
 113.270 +      if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T;
 113.271 +      if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T;
 113.272 +      if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T;
 113.273 +      if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T;
 113.274 +    }
 113.275 +    if (options & SOP_8BITMIME) ESMTP.eightbit.want = T;
 113.276 +  }
 113.277 +  return stream;
 113.278 +}
 113.279 +
 113.280 +/* SMTP authenticate
 113.281 + * Accepts: stream to login
 113.282 + *	    parsed network mailbox structure
 113.283 + *	    scratch buffer
 113.284 + *	    place to return user name
 113.285 + * Returns: T on success, NIL on failure
 113.286 + */
 113.287 +
 113.288 +long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp)
 113.289 +{
 113.290 +  unsigned long trial,auths;
 113.291 +  char *lsterr = NIL;
 113.292 +  char usr[MAILTMPLEN];
 113.293 +  AUTHENTICATOR *at;
 113.294 +  long ret = NIL;
 113.295 +  for (auths = ESMTP.auth, stream->saslcancel = NIL;
 113.296 +       !ret && stream->netstream && auths &&
 113.297 +       (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) {
 113.298 +    if (lsterr) {		/* previous authenticator failed? */
 113.299 +      sprintf (tmp,"Retrying using %s authentication after %.80s",
 113.300 +	       at->name,lsterr);
 113.301 +      mm_log (tmp,NIL);
 113.302 +      fs_give ((void **) &lsterr);
 113.303 +    }
 113.304 +    trial = 0;			/* initial trial count */
 113.305 +    tmp[0] = '\0';		/* empty buffer */
 113.306 +    if (stream->netstream) do {
 113.307 +      if (lsterr) {
 113.308 +	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
 113.309 +	mm_log (tmp,WARN);
 113.310 +	fs_give ((void **) &lsterr);
 113.311 +      }
 113.312 +      stream->saslcancel = NIL;
 113.313 +      if (smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) {
 113.314 +				/* hide client authentication responses */
 113.315 +	if (!(at->flags & AU_SECURE)) stream->sensitive = T;
 113.316 +	if ((*at->client) (smtp_challenge,smtp_response,"smtp",mb,stream,
 113.317 +			   &trial,usr)) {
 113.318 +	  if (stream->replycode == SMTPAUTHED) {
 113.319 +	    ESMTP.auth = NIL;	/* disable authenticators */
 113.320 +	    ret = LONGT;
 113.321 +	  }
 113.322 +				/* if main program requested cancellation */
 113.323 +	  else if (!trial) mm_log ("SMTP Authentication cancelled",ERROR);
 113.324 +	}
 113.325 +	stream->sensitive = NIL;/* unhide */
 113.326 +      }
 113.327 +				/* remember response if error and no cancel */
 113.328 +      if (!ret && trial) lsterr = cpystr (stream->reply);
 113.329 +    } while (!ret && stream->netstream && trial &&
 113.330 +	     (trial < smtp_maxlogintrials));
 113.331 +  }
 113.332 +  if (lsterr) {			/* previous authenticator failed? */
 113.333 +    if (!stream->saslcancel) {	/* don't do this if a cancel */
 113.334 +      sprintf (tmp,"Can not authenticate to SMTP server: %.80s",lsterr);
 113.335 +      mm_log (tmp,ERROR);
 113.336 +    }
 113.337 +    fs_give ((void **) &lsterr);
 113.338 +  }
 113.339 +  return ret;			/* authentication failed */
 113.340 +}
 113.341 +
 113.342 +/* Get challenge to authenticator in binary
 113.343 + * Accepts: stream
 113.344 + *	    pointer to returned size
 113.345 + * Returns: challenge or NIL if not challenge
 113.346 + */
 113.347 +
 113.348 +void *smtp_challenge (void *s,unsigned long *len)
 113.349 +{
 113.350 +  char tmp[MAILTMPLEN];
 113.351 +  void *ret = NIL;
 113.352 +  SENDSTREAM *stream = (SENDSTREAM *) s;
 113.353 +  if ((stream->replycode == SMTPAUTHREADY) &&
 113.354 +      !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4,
 113.355 +			     strlen (stream->reply + 4),len))) {
 113.356 +    sprintf (tmp,"SMTP SERVER BUG (invalid challenge): %.80s",stream->reply+4);
 113.357 +    mm_log (tmp,ERROR);
 113.358 +  }
 113.359 +  return ret;
 113.360 +}
 113.361 +
 113.362 +
 113.363 +/* Send authenticator response in BASE64
 113.364 + * Accepts: MAIL stream
 113.365 + *	    string to send
 113.366 + *	    length of string
 113.367 + * Returns: T, always
 113.368 + */
 113.369 +
 113.370 +long smtp_response (void *s,char *response,unsigned long size)
 113.371 +{
 113.372 +  SENDSTREAM *stream = (SENDSTREAM *) s;
 113.373 +  unsigned long i,j;
 113.374 +  char *t,*u;
 113.375 +  if (response) {		/* make CRLFless BASE64 string */
 113.376 +    if (size) {
 113.377 +      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
 113.378 +	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
 113.379 +      *u = '\0';		/* tie off string */
 113.380 +      i = smtp_send (stream,t,NIL);
 113.381 +      fs_give ((void **) &t);
 113.382 +    }
 113.383 +    else i = smtp_send (stream,"",NIL);
 113.384 +  }
 113.385 +  else {			/* abort requested */
 113.386 +    i = smtp_send (stream,"*",NIL);
 113.387 +    stream->saslcancel = T;	/* mark protocol-requested SASL cancel */
 113.388 +  }
 113.389 +  return LONGT;
 113.390 +}
 113.391 +
 113.392 +/* Mail Transfer Protocol close connection
 113.393 + * Accepts: SEND stream
 113.394 + * Returns: NIL always
 113.395 + */
 113.396 +
 113.397 +SENDSTREAM *smtp_close (SENDSTREAM *stream)
 113.398 +{
 113.399 +  if (stream) {			/* send "QUIT" */
 113.400 +    if (stream->netstream) {	/* do close actions if have netstream */
 113.401 +      smtp_send (stream,"QUIT",NIL);
 113.402 +      if (stream->netstream)	/* could have been closed during "QUIT" */
 113.403 +        net_close (stream->netstream);
 113.404 +    }
 113.405 +				/* clean up */
 113.406 +    if (stream->host) fs_give ((void **) &stream->host);
 113.407 +    if (stream->reply) fs_give ((void **) &stream->reply);
 113.408 +    if (ESMTP.dsn.envid) fs_give ((void **) &ESMTP.dsn.envid);
 113.409 +    if (ESMTP.atrn.domains) fs_give ((void **) &ESMTP.atrn.domains);
 113.410 +    fs_give ((void **) &stream);/* flush the stream */
 113.411 +  }
 113.412 +  return NIL;
 113.413 +}
 113.414 +
 113.415 +/* Mail Transfer Protocol deliver mail
 113.416 + * Accepts: SEND stream
 113.417 + *	    delivery option (MAIL, SEND, SAML, SOML)
 113.418 + *	    message envelope
 113.419 + *	    message body
 113.420 + * Returns: T on success, NIL on failure
 113.421 + */
 113.422 +
 113.423 +long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *env,BODY *body)
 113.424 +{
 113.425 +  RFC822BUFFER buf;
 113.426 +  char tmp[SENDBUFLEN+1];
 113.427 +  long error = NIL;
 113.428 +  long retry = NIL;
 113.429 +  buf.f = smtp_soutr;		/* initialize buffer */
 113.430 +  buf.s = stream->netstream;
 113.431 +  buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
 113.432 +  tmp[SENDBUFLEN] = '\0';	/* must have additional null guard byte */
 113.433 +  if (!(env->to || env->cc || env->bcc)) {
 113.434 +  				/* no recipients in request */
 113.435 +    smtp_seterror (stream,SMTPHARDERROR,"No recipients specified");
 113.436 +    return NIL;
 113.437 +  }
 113.438 +  do {				/* make sure stream is in good shape */
 113.439 +    smtp_send (stream,"RSET",NIL);
 113.440 +    if (retry) {		/* need to retry with authentication? */
 113.441 +      NETMBX mb;
 113.442 +				/* yes, build remote name for authentication */
 113.443 +      sprintf (tmp,"{%.200s/smtp%s}<none>",
 113.444 +	       (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
 113.445 +	       ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
 113.446 +		net_remotehost (stream->netstream) :
 113.447 +		net_host (stream->netstream)) :
 113.448 +	       stream->host,
 113.449 +	       (stream->netstream->dtb ==
 113.450 +		(NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL)) ?
 113.451 +	       "/ssl" : "");
 113.452 +      mail_valid_net_parse (tmp,&mb);
 113.453 +      if (!smtp_auth (stream,&mb,tmp)) return NIL;
 113.454 +      retry = NIL;		/* no retry at this point */
 113.455 +    }
 113.456 +
 113.457 +    strcpy (tmp,"FROM:<");	/* compose "MAIL FROM:<return-path>" */
 113.458 +#ifdef RFC2821
 113.459 +    if (env->return_path && env->return_path->host &&
 113.460 +	!((strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) ||
 113.461 +	  (strlen (env->return_path->host) > SMTPMAXDOMAIN))) {
 113.462 +      rfc822_cat (tmp,env->return_path->mailbox,NIL);
 113.463 +      sprintf (tmp + strlen (tmp),"@%s",env->return_path->host);
 113.464 +    }
 113.465 +#else				/* old code with A-D-L support */
 113.466 +    if (env->return_path && env->return_path->host &&
 113.467 +	!((env->return_path->adl &&
 113.468 +	   (strlen (env->return_path->adl) > SMTPMAXPATH)) ||
 113.469 +	  (strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) ||
 113.470 +	  (strlen (env->return_path->host) > SMTPMAXDOMAIN)))
 113.471 +      rfc822_address (tmp,env->return_path);
 113.472 +#endif
 113.473 +    strcat (tmp,">");
 113.474 +    if (ESMTP.ok) {
 113.475 +      if (ESMTP.eightbit.ok && ESMTP.eightbit.want)
 113.476 +	strcat (tmp," BODY=8BITMIME");
 113.477 +      if (ESMTP.dsn.ok && ESMTP.dsn.want) {
 113.478 +	strcat (tmp,ESMTP.dsn.full ? " RET=FULL" : " RET=HDRS");
 113.479 +	if (ESMTP.dsn.envid)
 113.480 +	  sprintf (tmp + strlen (tmp)," ENVID=%.100s",ESMTP.dsn.envid);
 113.481 +      }
 113.482 +    }
 113.483 +				/* send "MAIL FROM" command */
 113.484 +    switch (smtp_send (stream,type,tmp)) {
 113.485 +    case SMTPUNAVAIL:		/* mailbox unavailable? */
 113.486 +    case SMTPWANTAUTH:		/* wants authentication? */
 113.487 +    case SMTPWANTAUTH2:
 113.488 +      if (ESMTP.auth) retry = T;/* yes, retry with authentication */
 113.489 +    case SMTPOK:		/* looks good */
 113.490 +      break;
 113.491 +    default:			/* other failure */
 113.492 +      return NIL;
 113.493 +    }
 113.494 +				/* negotiate the recipients */
 113.495 +    if (!retry && env->to) retry = smtp_rcpt (stream,env->to,&error);
 113.496 +    if (!retry && env->cc) retry = smtp_rcpt (stream,env->cc,&error);
 113.497 +    if (!retry && env->bcc) retry = smtp_rcpt (stream,env->bcc,&error);
 113.498 +    if (!retry && error) {	/* any recipients failed? */
 113.499 +      smtp_send (stream,"RSET",NIL);
 113.500 +      smtp_seterror (stream,SMTPHARDERROR,"One or more recipients failed");
 113.501 +      return NIL;
 113.502 +    }
 113.503 +  } while (retry);
 113.504 +				/* negotiate data command */
 113.505 +  if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
 113.506 +				/* send message data */
 113.507 +  if (!rfc822_output_full (&buf,env,body,
 113.508 +			   ESMTP.eightbit.ok && ESMTP.eightbit.want)) {
 113.509 +    smtp_fake (stream,"SMTP connection broken (message data)");
 113.510 +    return NIL;			/* can't do much else here */
 113.511 +  }
 113.512 +				/* send trailing dot */
 113.513 +  return (smtp_send (stream,".",NIL) == SMTPOK) ? LONGT : NIL;
 113.514 +}
 113.515 +
 113.516 +/* Simple Mail Transfer Protocol send VERBose
 113.517 + * Accepts: SMTP stream
 113.518 + * Returns: T if successful, else NIL
 113.519 + *
 113.520 + * Descriptive text formerly in [al]pine sources:
 113.521 + * At worst, this command may cause the SMTP connection to get nuked.  Modern
 113.522 + * sendmail's recognize it, and possibly other SMTP implementations (the "ON"
 113.523 + * arg is for PMDF).  What's more, if it works, the reply code and accompanying
 113.524 + * text may vary from server to server.
 113.525 + */
 113.526 +
 113.527 +long smtp_verbose (SENDSTREAM *stream)
 113.528 +{
 113.529 +				/* accept any 2xx reply code */
 113.530 +  return ((smtp_send (stream,"VERB","ON") / (long) 100) == 2) ? LONGT : NIL;
 113.531 +}
 113.532 +
 113.533 +/* Internal routines */
 113.534 +
 113.535 +
 113.536 +/* Simple Mail Transfer Protocol send recipient
 113.537 + * Accepts: SMTP stream
 113.538 + *	    address list
 113.539 + *	    pointer to error flag
 113.540 + * Returns: T if should retry, else NIL
 113.541 + */
 113.542 +
 113.543 +long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error)
 113.544 +{
 113.545 + char *s,tmp[2*MAILTMPLEN],orcpt[MAILTMPLEN];
 113.546 +  while (adr) {			/* for each address on the list */
 113.547 +				/* clear any former error */
 113.548 +    if (adr->error) fs_give ((void **) &adr->error);
 113.549 +    if (adr->host) {		/* ignore group syntax */
 113.550 +				/* enforce SMTP limits to protect the buffer */
 113.551 +      if (strlen (adr->mailbox) > MAXLOCALPART) {
 113.552 +	adr->error = cpystr ("501 Recipient name too long");
 113.553 +	*error = T;
 113.554 +      }
 113.555 +      else if ((strlen (adr->host) > SMTPMAXDOMAIN)) {
 113.556 +	adr->error = cpystr ("501 Recipient domain too long");
 113.557 +	*error = T;
 113.558 +      }
 113.559 +#ifndef RFC2821			/* old code with A-D-L support */
 113.560 +      else if (adr->adl && (strlen (adr->adl) > SMTPMAXPATH)) {
 113.561 +	adr->error = cpystr ("501 Path too long");
 113.562 +	*error = T;
 113.563 +      }
 113.564 +#endif
 113.565 +
 113.566 +      else {
 113.567 +	strcpy (tmp,"TO:<");	/* compose "RCPT TO:<return-path>" */
 113.568 +#ifdef RFC2821
 113.569 +	rfc822_cat (tmp,adr->mailbox,NIL);
 113.570 +	sprintf (tmp + strlen (tmp),"@%s>",adr->host);
 113.571 +#else				/* old code with A-D-L support */
 113.572 +	rfc822_address (tmp,adr);
 113.573 +	strcat (tmp,">");
 113.574 +#endif
 113.575 +				/* want notifications */
 113.576 +	if (ESMTP.ok && ESMTP.dsn.ok && ESMTP.dsn.want) {
 113.577 +				/* yes, start with prefix */
 113.578 +	  strcat (tmp," NOTIFY=");
 113.579 +	  s = tmp + strlen (tmp);
 113.580 +	  if (ESMTP.dsn.notify.failure) strcat (s,"FAILURE,");
 113.581 +	  if (ESMTP.dsn.notify.delay) strcat (s,"DELAY,");
 113.582 +	  if (ESMTP.dsn.notify.success) strcat (s,"SUCCESS,");
 113.583 +				/* tie off last comma */
 113.584 +	  if (*s) s[strlen (s) - 1] = '\0';
 113.585 +	  else strcat (tmp,"NEVER");
 113.586 +	  if (adr->orcpt.addr) {
 113.587 +	    sprintf (orcpt,"%.498s;%.498s",
 113.588 +		     adr->orcpt.type ? adr->orcpt.type : "rfc822",
 113.589 +		     adr->orcpt.addr);
 113.590 +	    sprintf (tmp + strlen (tmp)," ORCPT=%.500s",orcpt);
 113.591 +	  }
 113.592 +	}
 113.593 +	switch (smtp_send (stream,"RCPT",tmp)) {
 113.594 +	case SMTPOK:		/* looks good */
 113.595 +	  break;
 113.596 +	case SMTPUNAVAIL:	/* mailbox unavailable? */
 113.597 +	case SMTPWANTAUTH:	/* wants authentication? */
 113.598 +	case SMTPWANTAUTH2:
 113.599 +	  if (ESMTP.auth) return T;
 113.600 +	default:		/* other failure */
 113.601 +	  *error = T;		/* note that an error occurred */
 113.602 +	  adr->error = cpystr (stream->reply);
 113.603 +	}
 113.604 +      }
 113.605 +    }
 113.606 +    adr = adr->next;		/* do any subsequent recipients */
 113.607 +  }
 113.608 +  return NIL;			/* no retry called for */
 113.609 +}
 113.610 +
 113.611 +/* Simple Mail Transfer Protocol send command
 113.612 + * Accepts: SEND stream
 113.613 + *	    text
 113.614 + * Returns: reply code
 113.615 + */
 113.616 +
 113.617 +long smtp_send (SENDSTREAM *stream,char *command,char *args)
 113.618 +{
 113.619 +  long ret;
 113.620 +  char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0)
 113.621 +			     + 3);
 113.622 +				/* build the complete command */
 113.623 +  if (args) sprintf (s,"%s %s",command,args);
 113.624 +  else strcpy (s,command);
 113.625 +  if (stream->debug) mail_dlog (s,stream->sensitive);
 113.626 +  strcat (s,"\015\012");
 113.627 +				/* send the command */
 113.628 +  if (stream->netstream && net_soutr (stream->netstream,s)) {
 113.629 +    do stream->replycode = smtp_reply (stream);
 113.630 +    while ((stream->replycode < 100) || (stream->reply[3] == '-'));
 113.631 +    ret = stream->replycode;
 113.632 +  }
 113.633 +  else ret = smtp_fake (stream,"SMTP connection broken (command)");
 113.634 +  fs_give ((void **) &s);
 113.635 +  return ret;
 113.636 +}
 113.637 +
 113.638 +
 113.639 +/* Simple Mail Transfer Protocol get reply
 113.640 + * Accepts: SMTP stream
 113.641 + * Returns: reply code
 113.642 + */
 113.643 +
 113.644 +long smtp_reply (SENDSTREAM *stream)
 113.645 +{
 113.646 +  smtpverbose_t pv = (smtpverbose_t) mail_parameters (NIL,GET_SMTPVERBOSE,NIL);
 113.647 +  long reply;
 113.648 +				/* flush old reply */
 113.649 +  if (stream->reply) fs_give ((void **) &stream->reply);
 113.650 +  				/* get reply */
 113.651 +  if (stream->netstream && (stream->reply = net_getline (stream->netstream))) {
 113.652 +    if (stream->debug) mm_dlog (stream->reply);
 113.653 +				/* return response code */
 113.654 +    reply = atol (stream->reply);
 113.655 +    if (pv && (reply < 100)) (*pv) (stream->reply);
 113.656 +  }
 113.657 +  else reply = smtp_fake (stream,"SMTP connection broken (reply)");
 113.658 +  return reply;
 113.659 +}
 113.660 +
 113.661 +/* Simple Mail Transfer Protocol send EHLO
 113.662 + * Accepts: SMTP stream
 113.663 + *	    host name to use in EHLO
 113.664 + *	    NETMBX structure
 113.665 + * Returns: reply code
 113.666 + */
 113.667 +
 113.668 +long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb)
 113.669 +{
 113.670 +  unsigned long i,j;
 113.671 +  long flags = (mb->secflag ? AU_SECURE : NIL) |
 113.672 +    (mb->authuser[0] ? AU_AUTHUSER : NIL);
 113.673 +  char *s,*t,*r,tmp[MAILTMPLEN];
 113.674 +				/* clear ESMTP data */
 113.675 +  memset (&ESMTP,0,sizeof (ESMTP));
 113.676 +  if (mb->loser) return 500;	/* never do EHLO if a loser */
 113.677 +  sprintf (tmp,"EHLO %s",host);	/* build the complete command */
 113.678 +  if (stream->debug) mm_dlog (tmp);
 113.679 +  strcat (tmp,"\015\012");
 113.680 +				/* send the command */
 113.681 +  if (!net_soutr (stream->netstream,tmp))
 113.682 +    return smtp_fake (stream,"SMTP connection broken (EHLO)");
 113.683 +				/* got an OK reply? */
 113.684 +  do if ((i = smtp_reply (stream)) == SMTPOK) {
 113.685 +				/* hack for AUTH= */
 113.686 +    if (stream->reply[4] && stream->reply[5] && stream->reply[6] &&
 113.687 +	stream->reply[7] && (stream->reply[8] == '=')) stream->reply[8] = ' ';
 113.688 +				/* get option code */
 113.689 +    if (!(s = strtok_r (stream->reply+4," ",&r)));
 113.690 +				/* have option, does it have a value */
 113.691 +    else if ((t = strtok_r (NIL," ",&r)) && *t) {
 113.692 +				/* EHLO options which take arguments */
 113.693 +      if (!compare_cstring (s,"SIZE")) {
 113.694 +	if (isdigit (*t)) ESMTP.size.limit = strtoul (t,&t,10);
 113.695 +	ESMTP.size.ok = T;
 113.696 +      }
 113.697 +      else if (!compare_cstring (s,"DELIVERBY")) {
 113.698 +	if (isdigit (*t)) ESMTP.deliverby.minby = strtoul (t,&t,10);
 113.699 +	ESMTP.deliverby.ok = T;
 113.700 +      }
 113.701 +      else if (!compare_cstring (s,"ATRN")) {
 113.702 +	ESMTP.atrn.domains = cpystr (t);
 113.703 +	ESMTP.atrn.ok = T;
 113.704 +      }
 113.705 +      else if (!compare_cstring (s,"AUTH"))
 113.706 +	do if ((j = mail_lookup_auth_name (t,flags)) &&
 113.707 +	       (--j < MAXAUTHENTICATORS)) ESMTP.auth |= (1 << j);
 113.708 +	while ((t = strtok_r (NIL," ",&r)) && *t);
 113.709 +    }
 113.710 +				/* EHLO options which do not take arguments */
 113.711 +    else if (!compare_cstring (s,"SIZE")) ESMTP.size.ok = T;
 113.712 +    else if (!compare_cstring (s,"8BITMIME")) ESMTP.eightbit.ok = T;
 113.713 +    else if (!compare_cstring (s,"DSN")) ESMTP.dsn.ok = T;
 113.714 +    else if (!compare_cstring (s,"ATRN")) ESMTP.atrn.ok = T;
 113.715 +    else if (!compare_cstring (s,"SEND")) ESMTP.service.send = T;
 113.716 +    else if (!compare_cstring (s,"SOML")) ESMTP.service.soml = T;
 113.717 +    else if (!compare_cstring (s,"SAML")) ESMTP.service.saml = T;
 113.718 +    else if (!compare_cstring (s,"EXPN")) ESMTP.service.expn = T;
 113.719 +    else if (!compare_cstring (s,"HELP")) ESMTP.service.help = T;
 113.720 +    else if (!compare_cstring (s,"TURN")) ESMTP.service.turn = T;
 113.721 +    else if (!compare_cstring (s,"ETRN")) ESMTP.service.etrn = T;
 113.722 +    else if (!compare_cstring (s,"STARTTLS")) ESMTP.service.starttls = T;
 113.723 +    else if (!compare_cstring (s,"RELAY")) ESMTP.service.relay = T;
 113.724 +    else if (!compare_cstring (s,"PIPELINING")) ESMTP.service.pipe = T;
 113.725 +    else if (!compare_cstring (s,"ENHANCEDSTATUSCODES"))
 113.726 +      ESMTP.service.ensc = T;
 113.727 +    else if (!compare_cstring (s,"BINARYMIME")) ESMTP.service.bmime = T;
 113.728 +    else if (!compare_cstring (s,"CHUNKING")) ESMTP.service.chunk = T;
 113.729 +  }
 113.730 +  while ((i < 100) || (stream->reply[3] == '-'));
 113.731 +				/* disable LOGIN if PLAIN also advertised */
 113.732 +  if ((j = mail_lookup_auth_name ("PLAIN",NIL)) && (--j < MAXAUTHENTICATORS) &&
 113.733 +      (ESMTP.auth & (1 << j)) &&
 113.734 +      (j = mail_lookup_auth_name ("LOGIN",NIL)) && (--j < MAXAUTHENTICATORS))
 113.735 +    ESMTP.auth &= ~(1 << j);
 113.736 +  return i;			/* return the response code */
 113.737 +}
 113.738 +
 113.739 +/* Simple Mail Transfer Protocol set fake error and abort
 113.740 + * Accepts: SMTP stream
 113.741 + *	    error text
 113.742 + * Returns: SMTPSOFTFATAL, always
 113.743 + */
 113.744 +
 113.745 +long smtp_fake (SENDSTREAM *stream,char *text)
 113.746 +{
 113.747 +  if (stream->netstream) {	/* close net connection if still open */
 113.748 +    net_close (stream->netstream);
 113.749 +    stream->netstream = NIL;
 113.750 +  }
 113.751 +				/* set last error */
 113.752 +  return smtp_seterror (stream,SMTPSOFTFATAL,text);
 113.753 +}
 113.754 +
 113.755 +
 113.756 +/* Simple Mail Transfer Protocol set error
 113.757 + * Accepts: SMTP stream
 113.758 + *	    SMTP error code
 113.759 + *	    error text
 113.760 + * Returns: error code
 113.761 + */
 113.762 +
 113.763 +static long smtp_seterror (SENDSTREAM *stream,long code,char *text)
 113.764 +{
 113.765 +				/* flush any old reply */
 113.766 +  if (stream->reply ) fs_give ((void **) &stream->reply);
 113.767 +  				/* set up pseudo-reply string */
 113.768 +  stream->reply = (char *) fs_get (20+strlen (text));
 113.769 +  sprintf (stream->reply,"%ld %s",code,text);
 113.770 +  return code;			/* return error code */
 113.771 +}
 113.772 +
 113.773 +
 113.774 +/* Simple Mail Transfer Protocol filter mail
 113.775 + * Accepts: stream
 113.776 + *	    string
 113.777 + * Returns: T on success, NIL on failure
 113.778 + */
 113.779 +
 113.780 +long smtp_soutr (void *stream,char *s)
 113.781 +{
 113.782 +  char c,*t;
 113.783 +				/* "." on first line */
 113.784 +  if (s[0] == '.') net_sout (stream,".",1);
 113.785 +				/* find lines beginning with a "." */
 113.786 +  while (t = strstr (s,"\015\012.")) {
 113.787 +    c = *(t += 3);		/* remember next character after "." */
 113.788 +    *t = '\0';			/* tie off string */
 113.789 +				/* output prefix */
 113.790 +    if (!net_sout (stream,s,t-s)) return NIL;
 113.791 +    *t = c;			/* restore delimiter */
 113.792 +    s = t - 1;			/* push pointer up to the "." */
 113.793 +  }
 113.794 +				/* output remainder of text */
 113.795 +  return *s ? net_soutr (stream,s) : T;
 113.796 +}
   114.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   114.2 +++ b/src/c-client/smtp.h	Mon Sep 14 15:17:45 2009 +0900
   114.3 @@ -0,0 +1,76 @@
   114.4 +/* ========================================================================
   114.5 + * Copyright 1988-2007 University of Washington
   114.6 + *
   114.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   114.8 + * you may not use this file except in compliance with the License.
   114.9 + * You may obtain a copy of the License at
  114.10 + *
  114.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  114.12 + *
  114.13 + * 
  114.14 + * ========================================================================
  114.15 + */
  114.16 +
  114.17 +/*
  114.18 + * Program:	Simple Mail Transfer Protocol (SMTP) routines
  114.19 + *
  114.20 + * Author:	Mark Crispin
  114.21 + *		Networks and Distributed Computing
  114.22 + *		Computing & Communications
  114.23 + *		University of Washington
  114.24 + *		Administration Building, AG-44
  114.25 + *		Seattle, WA  98195
  114.26 + *		Internet: MRC@CAC.Washington.EDU
  114.27 + *
  114.28 + * Date:	27 July 1988
  114.29 + * Last Edited:	15 August 2007
  114.30 + *
  114.31 + * This original version of this file is
  114.32 + * Copyright 1988 Stanford University
  114.33 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  114.34 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  114.35 + * Biomedical Research Technology Program of the NationalInstitutes of Health
  114.36 + * under grant number RR-00785.
  114.37 + */
  114.38 +
  114.39 +/* Constants (should be in smtp.c) */
  114.40 +
  114.41 +#define SMTPTCPPORT (long) 25	/* assigned TCP contact port */
  114.42 +#define SUBMITTCPPORT (long) 587/* assigned TCP contact port */
  114.43 +
  114.44 +
  114.45 +/* SMTP open options
  114.46 + * For compatibility with the past, SOP_DEBUG must always be 1.
  114.47 + */
  114.48 +
  114.49 +#define SOP_DEBUG (long) 1	/* debug protocol negotiations */
  114.50 +#define SOP_DSN (long) 2	/* DSN requested */
  114.51 +				/* DSN notification, none set mean NEVER */
  114.52 +#define SOP_DSN_NOTIFY_FAILURE (long) 4
  114.53 +#define SOP_DSN_NOTIFY_DELAY (long) 8
  114.54 +#define SOP_DSN_NOTIFY_SUCCESS (long) 16
  114.55 +				/* DSN return full msg vs. header */
  114.56 +
  114.57 +#define SOP_DSN_RETURN_FULL (long) 32
  114.58 +#define SOP_8BITMIME (long) 64	/* 8-bit MIME requested */
  114.59 +#define SOP_SECURE (long) 256	/* don't do non-secure authentication */
  114.60 +#define SOP_TRYSSL (long) 512	/* try SSL first */
  114.61 +#define SOP_TRYALT SOP_TRYSSL	/* old name */
  114.62 +				/* reserved for application use */
  114.63 +#define SOP_RESERVED (unsigned long) 0xff000000
  114.64 +
  114.65 +
  114.66 +/* Compatibility support names */
  114.67 +
  114.68 +#define smtp_open(hostlist,options) \
  114.69 +  smtp_open_full (NIL,hostlist,"smtp",NIL,options)
  114.70 +
  114.71 +
  114.72 +/* Function prototypes */
  114.73 +
  114.74 +void *smtp_parameters (long function,void *value);
  114.75 +SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,
  114.76 +			    unsigned long port,long options);
  114.77 +SENDSTREAM *smtp_close (SENDSTREAM *stream);
  114.78 +long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *msg,BODY *body);
  114.79 +long smtp_verbose (SENDSTREAM *stream);
   115.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   115.2 +++ b/src/c-client/sslio.h	Mon Sep 14 15:17:45 2009 +0900
   115.3 @@ -0,0 +1,70 @@
   115.4 +/* ========================================================================
   115.5 + * Copyright 1988-2006 University of Washington
   115.6 + *
   115.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   115.8 + * you may not use this file except in compliance with the License.
   115.9 + * You may obtain a copy of the License at
  115.10 + *
  115.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  115.12 + *
  115.13 + * 
  115.14 + * ========================================================================
  115.15 + */
  115.16 +
  115.17 +/*
  115.18 + * Program:	SSL routines
  115.19 + *
  115.20 + * Author:	Mark Crispin
  115.21 + *		Networks and Distributed Computing
  115.22 + *		Computing & Communications
  115.23 + *		University of Washington
  115.24 + *		Administration Building, AG-44
  115.25 + *		Seattle, WA  98195
  115.26 + *		Internet: MRC@CAC.Washington.EDU
  115.27 + *
  115.28 + * Date:	7 February 2001
  115.29 + * Last Edited:	30 August 2006
  115.30 + */
  115.31 +
  115.32 +/* SSL driver */
  115.33 +
  115.34 +struct ssl_driver {		/* must parallel NETDRIVER in mail.h */
  115.35 +  SSLSTREAM *(*open) (char *host,char *service,unsigned long port);
  115.36 +  SSLSTREAM *(*aopen) (NETMBX *mb,char *service,char *usrbuf);
  115.37 +  char *(*getline) (SSLSTREAM *stream);
  115.38 +  long (*getbuffer) (SSLSTREAM *stream,unsigned long size,char *buffer);
  115.39 +  long (*soutr) (SSLSTREAM *stream,char *string);
  115.40 +  long (*sout) (SSLSTREAM *stream,char *string,unsigned long size);
  115.41 +  void (*close) (SSLSTREAM *stream);
  115.42 +  char *(*host) (SSLSTREAM *stream);
  115.43 +  char *(*remotehost) (SSLSTREAM *stream);
  115.44 +  unsigned long (*port) (SSLSTREAM *stream);
  115.45 +  char *(*localhost) (SSLSTREAM *stream);
  115.46 +};
  115.47 +
  115.48 +
  115.49 +/* SSL stdio stream */
  115.50 +
  115.51 +typedef struct ssl_stdiostream {
  115.52 +  SSLSTREAM *sslstream;		/* SSL stream */
  115.53 +  int octr;			/* output counter */
  115.54 +  char *optr;			/* output pointer */
  115.55 +  char obuf[SSLBUFLEN];		/* output buffer */
  115.56 +} SSLSTDIOSTREAM;
  115.57 +
  115.58 +
  115.59 +/* Function prototypes */
  115.60 +
  115.61 +SSLSTREAM *ssl_open (char *host,char *service,unsigned long port);
  115.62 +SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf);
  115.63 +char *ssl_getline (SSLSTREAM *stream);
  115.64 +long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer);
  115.65 +long ssl_getdata (SSLSTREAM *stream);
  115.66 +long ssl_soutr (SSLSTREAM *stream,char *string);
  115.67 +long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size);
  115.68 +void ssl_close (SSLSTREAM *stream);
  115.69 +char *ssl_host (SSLSTREAM *stream);
  115.70 +char *ssl_remotehost (SSLSTREAM *stream);
  115.71 +unsigned long ssl_port (SSLSTREAM *stream);
  115.72 +char *ssl_localhost (SSLSTREAM *stream);
  115.73 +long ssl_server_input_wait (long seconds);
   116.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   116.2 +++ b/src/c-client/tcp.h	Mon Sep 14 15:17:45 2009 +0900
   116.3 @@ -0,0 +1,59 @@
   116.4 +/* ========================================================================
   116.5 + * Copyright 1988-2007 University of Washington
   116.6 + *
   116.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   116.8 + * you may not use this file except in compliance with the License.
   116.9 + * You may obtain a copy of the License at
  116.10 + *
  116.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  116.12 + *
  116.13 + * 
  116.14 + * ========================================================================
  116.15 + */
  116.16 +
  116.17 +/*
  116.18 + * Program:	TCP/IP routines
  116.19 + *
  116.20 + * Author:	Mark Crispin
  116.21 + *		Networks and Distributed Computing
  116.22 + *		Computing & Communications
  116.23 + *		University of Washington
  116.24 + *		Administration Building, AG-44
  116.25 + *		Seattle, WA  98195
  116.26 + *		Internet: MRC@CAC.Washington.EDU
  116.27 + *
  116.28 + * Date:	1 August 1988
  116.29 + * Last Edited:	31 January 2007
  116.30 + */
  116.31 +
  116.32 +
  116.33 +/* Dummy definition overridden by TCP routines */
  116.34 +
  116.35 +#ifndef TCPSTREAM
  116.36 +#define TCPSTREAM void
  116.37 +#endif
  116.38 +
  116.39 +
  116.40 +/* Function prototypes */
  116.41 +
  116.42 +void *tcp_parameters (long function,void *value);
  116.43 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port);
  116.44 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf);
  116.45 +char *tcp_getline (TCPSTREAM *stream);
  116.46 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer);
  116.47 +long tcp_getdata (TCPSTREAM *stream);
  116.48 +long tcp_soutr (TCPSTREAM *stream,char *string);
  116.49 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size);
  116.50 +void tcp_close (TCPSTREAM *stream);
  116.51 +char *tcp_host (TCPSTREAM *stream);
  116.52 +char *tcp_remotehost (TCPSTREAM *stream);
  116.53 +unsigned long tcp_port (TCPSTREAM *stream);
  116.54 +char *tcp_localhost (TCPSTREAM *stream);
  116.55 +char *tcp_clientaddr (void);
  116.56 +char *tcp_clienthost (void);
  116.57 +long tcp_clientport (void);
  116.58 +char *tcp_serveraddr (void);
  116.59 +char *tcp_serverhost (void);
  116.60 +long tcp_serverport (void);
  116.61 +char *tcp_canonical (char *name);
  116.62 +long tcp_isclienthost (char *host);
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/src/c-client/utf8.c	Mon Sep 14 15:17:45 2009 +0900
   117.3 @@ -0,0 +1,2554 @@
   117.4 +/* ========================================================================
   117.5 + * Copyright 1988-2008 University of Washington
   117.6 + *
   117.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   117.8 + * you may not use this file except in compliance with the License.
   117.9 + * You may obtain a copy of the License at
  117.10 + *
  117.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  117.12 + *
  117.13 + * 
  117.14 + * ========================================================================
  117.15 + */
  117.16 +
  117.17 +/*
  117.18 + * Program:	UTF-8 routines
  117.19 + *
  117.20 + * Author:	Mark Crispin
  117.21 + *		Networks and Distributed Computing
  117.22 + *		Computing & Communications
  117.23 + *		University of Washington
  117.24 + *		Administration Building, AG-44
  117.25 + *		Seattle, WA  98195
  117.26 + *		Internet: MRC@CAC.Washington.EDU
  117.27 + *
  117.28 + * Date:	11 June 1997
  117.29 + * Last Edited:	17 January 2008
  117.30 + */
  117.31 +
  117.32 +
  117.33 +#include <stdio.h>
  117.34 +#include <ctype.h>
  117.35 +#include "c-client.h"
  117.36 +
  117.37 +/*	*** IMPORTANT ***
  117.38 + *
  117.39 + *  There is a very important difference between "character set" and "charset",
  117.40 + * and the comments in this file reflect these differences.  A "character set"
  117.41 + * (also known as "coded character set") is a mapping between codepoints and
  117.42 + * characters.  A "charset" is as defined in MIME, and incorporates one or more
  117.43 + * coded character sets in a character encoding scheme.  See RFC 2130 for more
  117.44 + * details.
  117.45 + */
  117.46 +
  117.47 +
  117.48 +/* Character set conversion tables */
  117.49 +
  117.50 +#include "iso_8859.c"		/* 8-bit single-byte coded graphic */
  117.51 +#include "koi8_r.c"		/* Cyrillic - Russia */
  117.52 +#include "koi8_u.c"		/* Cyrillic - Ukraine */
  117.53 +#include "tis_620.c"		/* Thai */
  117.54 +#include "viscii.c"		/* Vietnamese */
  117.55 +#include "windows.c"		/* Windows */
  117.56 +#include "ibm.c"		/* IBM */
  117.57 +#include "gb_2312.c"		/* Chinese (PRC) - simplified */
  117.58 +#include "gb_12345.c"		/* Chinese (PRC) - traditional */
  117.59 +#include "jis_0208.c"		/* Japanese - basic */
  117.60 +#include "jis_0212.c"		/* Japanese - supplementary */
  117.61 +#include "ksc_5601.c"		/* Korean */
  117.62 +#include "big5.c"		/* Taiwanese (ROC) - industrial standard */
  117.63 +#include "cns11643.c"		/* Taiwanese (ROC) - national standard */
  117.64 +
  117.65 +
  117.66 +#include "widths.c"		/* Unicode character widths */
  117.67 +#include "tmap.c"		/* Unicode titlecase mapping */
  117.68 +#include "decomtab.c"		/* Unicode decomposions */
  117.69 +
  117.70 +/* EUC parameters */
  117.71 +
  117.72 +#ifdef GBTOUNICODE		/* PRC simplified Chinese */
  117.73 +static const struct utf8_eucparam gb_param = {
  117.74 +  BASE_GB2312_KU,BASE_GB2312_TEN,MAX_GB2312_KU,MAX_GB2312_TEN,
  117.75 +  (void *) gb2312tab};
  117.76 +#endif
  117.77 +
  117.78 +
  117.79 +#ifdef GB12345TOUNICODE		/* PRC traditional Chinese */
  117.80 +static const struct utf8_eucparam gbt_param = {
  117.81 +  BASE_GB12345_KU,BASE_GB12345_TEN,MAX_GB12345_KU,MAX_GB12345_TEN,
  117.82 +  (void *) gb12345tab};
  117.83 +#endif
  117.84 +
  117.85 +
  117.86 +#ifdef BIG5TOUNICODE		/* ROC traditional Chinese */
  117.87 +static const struct utf8_eucparam big5_param[] = {
  117.88 +  {BASE_BIG5_KU,BASE_BIG5_TEN_0,MAX_BIG5_KU,MAX_BIG5_TEN_0,(void *) big5tab},
  117.89 +  {BASE_BIG5_KU,BASE_BIG5_TEN_1,MAX_BIG5_KU,MAX_BIG5_TEN_1,NIL}
  117.90 +};
  117.91 +#endif
  117.92 +
  117.93 +
  117.94 +#ifdef JISTOUNICODE		/* Japanese */
  117.95 +static const struct utf8_eucparam jis_param[] = {
  117.96 +  {BASE_JIS0208_KU,BASE_JIS0208_TEN,MAX_JIS0208_KU,MAX_JIS0208_TEN,
  117.97 +     (void *) jis0208tab},
  117.98 +  {MIN_KANA_8,0,MAX_KANA_8,0,(void *) KANA_8},
  117.99 +#ifdef JIS0212TOUNICODE		/* Japanese extended */
 117.100 +  {BASE_JIS0212_KU,BASE_JIS0212_TEN,MAX_JIS0212_KU,MAX_JIS0212_TEN,
 117.101 +     (void *) jis0212tab}
 117.102 +#else
 117.103 +  {0,0,0,0,NIL}
 117.104 +#endif
 117.105 +};
 117.106 +#endif
 117.107 +
 117.108 +
 117.109 +#ifdef KSCTOUNICODE		/* Korean */
 117.110 +static const struct utf8_eucparam ksc_param = {
 117.111 +  BASE_KSC5601_KU,BASE_KSC5601_TEN,MAX_KSC5601_KU,MAX_KSC5601_TEN,
 117.112 +  (void *) ksc5601tab};
 117.113 +#endif
 117.114 +
 117.115 +/* List of supported charsets */
 117.116 +
 117.117 +static const CHARSET utf8_csvalid[] = {
 117.118 +  {"US-ASCII",CT_ASCII,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.119 +   NIL,NIL,NIL},
 117.120 +  {"UTF-8",CT_UTF8,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.121 +   NIL,SC_UNICODE,NIL},
 117.122 +  {"UTF-7",CT_UTF7,CF_PRIMARY | CF_POSTING | CF_UNSUPRT,
 117.123 +   NIL,SC_UNICODE,"UTF-8"},
 117.124 +  {"ISO-8859-1",CT_1BYTE0,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.125 +   NIL,SC_LATIN_1,NIL},
 117.126 +  {"ISO-8859-2",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.127 +   (void *) iso8859_2tab,SC_LATIN_2,NIL},
 117.128 +  {"ISO-8859-3",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.129 +   (void *) iso8859_3tab,SC_LATIN_3,NIL},
 117.130 +  {"ISO-8859-4",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.131 +   (void *) iso8859_4tab,SC_LATIN_4,NIL},
 117.132 +  {"ISO-8859-5",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.133 +   (void *) iso8859_5tab,SC_CYRILLIC,"KOI8-R"},
 117.134 +  {"ISO-8859-6",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.135 +   (void *) iso8859_6tab,SC_ARABIC,NIL},
 117.136 +  {"ISO-8859-7",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.137 +   (void *) iso8859_7tab,SC_GREEK,NIL},
 117.138 +  {"ISO-8859-8",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.139 +   (void *) iso8859_8tab,SC_HEBREW,NIL},
 117.140 +  {"ISO-8859-9",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.141 +   (void *) iso8859_9tab,SC_LATIN_5,NIL},
 117.142 +  {"ISO-8859-10",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.143 +   (void *) iso8859_10tab,SC_LATIN_6,NIL},
 117.144 +  {"ISO-8859-11",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.145 +   (void *) iso8859_11tab,SC_THAI,NIL},
 117.146 +#if 0				/* ISO 8859-12 reserved for ISCII(?) */
 117.147 +  {"ISO-8859-12",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.148 +   (void *) iso8859_12tab,NIL,NIL},
 117.149 +#endif
 117.150 +  {"ISO-8859-13",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.151 +   (void *) iso8859_13tab,SC_LATIN_7,NIL},
 117.152 +  {"ISO-8859-14",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.153 +   (void *) iso8859_14tab,SC_LATIN_8,NIL},
 117.154 +  {"ISO-8859-15",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.155 +   (void *) iso8859_15tab,SC_LATIN_9,NIL},
 117.156 +  {"ISO-8859-16",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.157 +   (void *) iso8859_16tab,SC_LATIN_10,NIL},
 117.158 +  {"KOI8-R",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.159 +   (void *) koi8rtab,SC_CYRILLIC,NIL},
 117.160 +  {"KOI8-U",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.161 +   (void *) koi8utab,SC_CYRILLIC | SC_UKRANIAN,NIL},
 117.162 +  {"KOI8-RU",CT_1BYTE,CF_DISPLAY,
 117.163 +   (void *) koi8utab,SC_CYRILLIC | SC_UKRANIAN,"KOI8-U"},
 117.164 +  {"TIS-620",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.165 +   (void *) tis620tab,SC_THAI,"ISO-8859-11"},
 117.166 +  {"VISCII",CT_1BYTE8,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.167 +   (void *) visciitab,SC_VIETNAMESE,NIL},
 117.168 +
 117.169 +#ifdef GBTOUNICODE
 117.170 +  {"GBK",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.171 +     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,NIL},
 117.172 +  {"GB2312",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.173 +   (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
 117.174 +  {"CN-GB",CT_DBYTE,CF_DISPLAY,
 117.175 +     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
 117.176 +#ifdef CNS1TOUNICODE
 117.177 +  {"ISO-2022-CN",CT_2022,CF_PRIMARY | CF_UNSUPRT,
 117.178 +     NIL,SC_CHINESE_SIMPLIFIED | SC_CHINESE_TRADITIONAL,
 117.179 +   NIL},
 117.180 +#endif
 117.181 +#endif
 117.182 +#ifdef GB12345TOUNICODE
 117.183 +  {"CN-GB-12345",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
 117.184 +     (void *) &gbt_param,SC_CHINESE_TRADITIONAL,"BIG5"},
 117.185 +#endif
 117.186 +#ifdef BIG5TOUNICODE
 117.187 +  {"BIG5",CT_DBYTE2,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.188 +     (void *) big5_param,SC_CHINESE_TRADITIONAL,NIL},
 117.189 +  {"CN-BIG5",CT_DBYTE2,CF_DISPLAY,
 117.190 +     (void *) big5_param,SC_CHINESE_TRADITIONAL,"BIG5"},
 117.191 +  {"BIG-5",CT_DBYTE2,CF_DISPLAY,
 117.192 +     (void *) big5_param,SC_CHINESE_TRADITIONAL,"BIG5"},
 117.193 +#endif
 117.194 +#ifdef JISTOUNICODE
 117.195 +  {"ISO-2022-JP",CT_2022,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.196 +     NIL,SC_JAPANESE,NIL},
 117.197 +  {"EUC-JP",CT_EUC,CF_PRIMARY | CF_DISPLAY,
 117.198 +     (void *) jis_param,SC_JAPANESE,"ISO-2022-JP"},
 117.199 +  {"SHIFT_JIS",CT_SJIS,CF_PRIMARY | CF_DISPLAY,
 117.200 +     NIL,SC_JAPANESE,"ISO-2022-JP"},
 117.201 +  {"SHIFT-JIS",CT_SJIS,CF_PRIMARY | CF_DISPLAY,
 117.202 +     NIL,SC_JAPANESE,"ISO-2022-JP"},
 117.203 +#ifdef JIS0212TOUNICODE
 117.204 +  {"ISO-2022-JP-1",CT_2022,CF_UNSUPRT,
 117.205 +     NIL,SC_JAPANESE,"ISO-2022-JP"},
 117.206 +#ifdef GBTOUNICODE
 117.207 +#ifdef KSCTOUNICODE
 117.208 +  {"ISO-2022-JP-2",CT_2022,CF_UNSUPRT,
 117.209 +     NIL,
 117.210 +     SC_LATIN_1 | SC_LATIN_2 | SC_LATIN_3 | SC_LATIN_4 | SC_LATIN_5 |
 117.211 +       SC_LATIN_6 | SC_LATIN_7 | SC_LATIN_8 | SC_LATIN_9 | SC_LATIN_10 |
 117.212 +	 SC_ARABIC | SC_CYRILLIC | SC_GREEK | SC_HEBREW | SC_THAI |
 117.213 +	   SC_VIETNAMESE | SC_CHINESE_SIMPLIFIED | SC_JAPANESE | SC_KOREAN
 117.214 +#ifdef CNS1TOUNICODE
 117.215 +	     | SC_CHINESE_TRADITIONAL
 117.216 +#endif
 117.217 +	       ,"UTF-8"},
 117.218 +#endif
 117.219 +#endif
 117.220 +#endif
 117.221 +#endif
 117.222 +
 117.223 +#ifdef KSCTOUNICODE
 117.224 +  {"ISO-2022-KR",CT_2022,CF_PRIMARY | CF_DISPLAY | CF_UNSUPRT,
 117.225 +     NIL,SC_KOREAN,"EUC-KR"},
 117.226 +  {"EUC-KR",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.227 +     (void *) &ksc_param,SC_KOREAN,NIL},
 117.228 +  {"KSC5601",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
 117.229 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.230 +  {"KSC_5601",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
 117.231 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.232 +  {"KS_C_5601-1987",CT_DBYTE,CF_DISPLAY,
 117.233 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.234 +  {"KS_C_5601-1989",CT_DBYTE,CF_DISPLAY,
 117.235 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.236 +  {"KS_C_5601-1992",CT_DBYTE,CF_DISPLAY,
 117.237 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.238 +  {"KS_C_5601-1997",CT_DBYTE,CF_DISPLAY,
 117.239 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.240 +#endif
 117.241 +
 117.242 +				/* deep sigh */
 117.243 +  {"WINDOWS-874",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.244 +     (void *) windows_874tab,SC_THAI,"ISO-8859-11"},
 117.245 +  {"CP874",CT_1BYTE,CF_DISPLAY,
 117.246 +     (void *) windows_874tab,SC_THAI,"ISO-8859-11"},
 117.247 +#ifdef GBTOUNICODE
 117.248 +  {"WINDOWS-936",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
 117.249 +     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
 117.250 +  {"CP936",CT_DBYTE,CF_DISPLAY,
 117.251 +     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
 117.252 +#endif
 117.253 +#ifdef KSCTOUNICODE
 117.254 +  {"WINDOWS-949",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
 117.255 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.256 +  {"CP949",CT_DBYTE,CF_DISPLAY,
 117.257 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.258 +  {"X-WINDOWS-949",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
 117.259 +     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
 117.260 +#endif
 117.261 +  {"WINDOWS-1250",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.262 +     (void *) windows_1250tab,SC_LATIN_2,"ISO-8859-2"},
 117.263 +  {"CP1250",CT_1BYTE,CF_DISPLAY,
 117.264 +     (void *) windows_1250tab,SC_LATIN_2,"ISO-8859-2"},
 117.265 +  {"WINDOWS-1251",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
 117.266 +     (void *) windows_1251tab,SC_CYRILLIC,"KOI8-R"},
 117.267 +  {"CP1251",CT_1BYTE,CF_DISPLAY,
 117.268 +     (void *) windows_1251tab,SC_CYRILLIC,"KOI8-R"},
 117.269 +  {"WINDOWS-1252",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.270 +     (void *) windows_1252tab,SC_LATIN_1,"ISO-8859-1"},
 117.271 +  {"CP1252",CT_1BYTE,CF_DISPLAY,
 117.272 +     (void *) windows_1252tab,SC_LATIN_1,"ISO-8859-1"},
 117.273 +  {"WINDOWS-1253",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.274 +     (void *) windows_1253tab,SC_GREEK,"ISO-8859-7"},
 117.275 +  {"CP1253",CT_1BYTE,CF_DISPLAY,
 117.276 +     (void *) windows_1253tab,SC_GREEK,"ISO-8859-7"},
 117.277 +  {"WINDOWS-1254",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.278 +     (void *) windows_1254tab,SC_LATIN_5,"ISO-8859-9"},
 117.279 +  {"CP1254",CT_1BYTE,CF_DISPLAY,
 117.280 +     (void *) windows_1254tab,SC_LATIN_5,"ISO-8859-9"},
 117.281 +  {"WINDOWS-1255",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.282 +     (void *) windows_1255tab,SC_HEBREW,"ISO-8859-8"},
 117.283 +  {"CP1255",CT_1BYTE,CF_DISPLAY,
 117.284 +     (void *) windows_1255tab,SC_HEBREW,"ISO-8859-8"},
 117.285 +  {"WINDOWS-1256",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.286 +     (void *) windows_1256tab,SC_ARABIC,"ISO-8859-6"},
 117.287 +  {"CP1256",CT_1BYTE,CF_DISPLAY,
 117.288 +     (void *) windows_1256tab,SC_ARABIC,"ISO-8859-6"},
 117.289 +  {"WINDOWS-1257",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.290 +     (void *) windows_1257tab,SC_LATIN_7,"ISO-8859-13"},
 117.291 +  {"CP1257",CT_1BYTE,CF_DISPLAY,
 117.292 +     (void *) windows_1257tab,SC_LATIN_7,"ISO-8859-13"},
 117.293 +  {"WINDOWS-1258",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.294 +     (void *) windows_1258tab,SC_VIETNAMESE,"VISCII"},
 117.295 +  {"CP1258",CT_1BYTE,CF_DISPLAY,
 117.296 +     (void *) windows_1258tab,SC_VIETNAMESE,"VISCII"},
 117.297 +
 117.298 +				/* deeper sigh */
 117.299 +  {"IBM367",CT_ASCII,CF_PRIMARY | CF_DISPLAY,
 117.300 +     NIL,NIL,"US-ASCII"},
 117.301 +  {"IBM437",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.302 +     (void *) ibm_437tab,SC_LATIN_1,"ISO-8859-1"},
 117.303 +  {"IBM737",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.304 +     (void *) ibm_737tab,SC_GREEK,"ISO-8859-7"},
 117.305 +  {"IBM775",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.306 +     (void *) ibm_775tab,SC_LATIN_7,"ISO-8859-13"},
 117.307 +  {"IBM850",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.308 +     (void *) ibm_850tab,SC_LATIN_1,"ISO-8859-1"},
 117.309 +  {"IBM852",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.310 +     (void *) ibm_852tab,SC_LATIN_2,"ISO-8859-2"},
 117.311 +  {"IBM855",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.312 +     (void *) ibm_855tab,SC_CYRILLIC,"ISO-8859-5"},
 117.313 +  {"IBM857",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.314 +     (void *) ibm_857tab,SC_LATIN_5,"ISO-8859-9"},
 117.315 +  {"IBM860",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.316 +     (void *) ibm_860tab,SC_LATIN_1,"ISO-8859-1"},
 117.317 +  {"IBM861",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.318 +     (void *) ibm_861tab,SC_LATIN_6,"ISO-8859-10"},
 117.319 +  {"IBM862",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.320 +     (void *) ibm_862tab,SC_HEBREW,"ISO-8859-8"},
 117.321 +  {"IBM863",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.322 +     (void *) ibm_863tab,SC_LATIN_1,"ISO-8859-1"},
 117.323 +  {"IBM864",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.324 +     (void *) ibm_864tab,SC_ARABIC,"ISO-8859-6"},
 117.325 +  {"IBM865",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.326 +     (void *) ibm_865tab,SC_LATIN_6,"ISO-8859-10"},
 117.327 +  {"IBM866",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.328 +     (void *) ibm_866tab,SC_CYRILLIC,"KOI8-R"},
 117.329 +  {"IBM869",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.330 +     (void *) ibm_869tab,SC_GREEK,"ISO-8859-7"},
 117.331 +  {"IBM874",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
 117.332 +     (void *) ibm_874tab,SC_THAI,"ISO-8859-11"},
 117.333 +				/* deepest sigh */
 117.334 +  {"ANSI_X3.4-1968",CT_ASCII,CF_DISPLAY,
 117.335 +     NIL,NIL,"US-ASCII"},
 117.336 +  {"UNICODE-1-1-UTF-7",CT_UTF7,CF_UNSUPRT,
 117.337 +     NIL,SC_UNICODE,"UTF-8"},
 117.338 +				/* these should never appear in email */
 117.339 +  {"UCS-2",CT_UCS2,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL,
 117.340 +     NIL,SC_UNICODE,"UTF-8"},
 117.341 +  {"UCS-4",CT_UCS4,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL,
 117.342 +     NIL,SC_UNICODE,"UTF-8"},
 117.343 +  {"UTF-16",CT_UTF16,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL,
 117.344 +     NIL,SC_UNICODE,"UTF-8"},
 117.345 +  NIL
 117.346 +};
 117.347 +
 117.348 +/* Non-Unicode Script table */
 117.349 +
 117.350 +static const SCRIPT utf8_scvalid[] = {
 117.351 +  {"Arabic",NIL,SC_ARABIC},
 117.352 +  {"Chinese Simplified","China, Singapore",SC_CHINESE_SIMPLIFIED},
 117.353 +  {"Chinese Traditional","Taiwan, Hong Kong, Macao",SC_CHINESE_TRADITIONAL},
 117.354 +  {"Cyrillic",NIL,SC_CYRILLIC},
 117.355 +  {"Cyrillic Ukranian",NIL,SC_UKRANIAN},
 117.356 +  {"Greek",NIL,SC_GREEK},
 117.357 +  {"Hebrew",NIL,SC_HEBREW},
 117.358 +  {"Japanese",NIL,SC_JAPANESE},
 117.359 +  {"Korean",NIL,SC_KOREAN},
 117.360 +  {"Latin-1","Western Europe",SC_LATIN_1},
 117.361 +  {"Latin-2","Eastern Europe",SC_LATIN_2},
 117.362 +  {"Latin-3","Southern Europe",SC_LATIN_3},
 117.363 +  {"Latin-4","Northern Europe",SC_LATIN_4},
 117.364 +  {"Latin-5","Turkish",SC_LATIN_5},
 117.365 +  {"Latin-6","Nordic",SC_LATIN_6},
 117.366 +  {"Latin-7","Baltic",SC_LATIN_7},
 117.367 +  {"Latin-8","Celtic",SC_LATIN_8},
 117.368 +  {"Latin-9","Euro",SC_LATIN_9},
 117.369 +  {"Latin-10","Balkan",SC_LATIN_10},
 117.370 +  {"Thai",NIL,SC_THAI},
 117.371 +  {"Vietnamese",NIL,SC_VIETNAMESE},
 117.372 +  NIL
 117.373 +};
 117.374 +
 117.375 +/* Look up script name or return entire table
 117.376 + * Accepts: script name or NIL
 117.377 + * Returns: pointer to script table entry or NIL if unknown
 117.378 + */
 117.379 +
 117.380 +SCRIPT *utf8_script (char *script)
 117.381 +{
 117.382 +  unsigned long i;
 117.383 +  if (!script) return (SCRIPT *) &utf8_scvalid[0];
 117.384 +  else if (*script && (strlen (script) < 128))
 117.385 +    for (i = 0; utf8_scvalid[i].name; i++)
 117.386 +      if (!compare_cstring (script,utf8_scvalid[i].name))
 117.387 +	return (SCRIPT *) &utf8_scvalid[i];
 117.388 +  return NIL;			/* failed */
 117.389 +}
 117.390 +
 117.391 +
 117.392 +/* Look up charset name or return entire table
 117.393 + * Accepts: charset name or NIL
 117.394 + * Returns: charset table entry or NIL if unknown
 117.395 + */
 117.396 +
 117.397 +const CHARSET *utf8_charset (char *charset)
 117.398 +{
 117.399 +  unsigned long i;
 117.400 +  if (!charset) return (CHARSET *) &utf8_csvalid[0];
 117.401 +  else if (*charset && (strlen (charset) < 128))
 117.402 +    for (i = 0; utf8_csvalid[i].name; i++)
 117.403 +      if (!compare_cstring (charset,utf8_csvalid[i].name))
 117.404 +	return (CHARSET *) &utf8_csvalid[i];
 117.405 +  return NIL;			/* failed */
 117.406 +}
 117.407 +
 117.408 +/* Validate charset and generate error message if invalid
 117.409 + * Accepts: bad character set
 117.410 + * Returns: NIL if good charset, else error message string
 117.411 + */
 117.412 +
 117.413 +#define BADCSS "[BADCHARSET ("
 117.414 +#define BADCSE ")] Unknown charset: "
 117.415 +
 117.416 +char *utf8_badcharset (char *charset)
 117.417 +{
 117.418 +  char *msg = NIL;
 117.419 +  if (!utf8_charset (charset)) {
 117.420 +    char *s,*t;
 117.421 +    unsigned long i,j;
 117.422 +				/* calculate size of header, trailer, and bad
 117.423 +				 * charset plus charset names */
 117.424 +    for (i = 0, j = sizeof (BADCSS) + sizeof (BADCSE) + strlen (charset) - 2;
 117.425 +	 utf8_csvalid[i].name; i++)
 117.426 +      j += strlen (utf8_csvalid[i].name) + 1;
 117.427 +				/* not built right */
 117.428 +    if (!i) fatal ("No valid charsets!");
 117.429 +				/* header */
 117.430 +    for (s = msg = (char *) fs_get (j), t = BADCSS; *t; *s++ = *t++);
 117.431 +				/* each charset */
 117.432 +    for (i = 0; utf8_csvalid[i].name; *s++ = ' ', i++)
 117.433 +      for (t = utf8_csvalid[i].name; *t; *s++ = *t++);
 117.434 +				/* back over last space, trailer */
 117.435 +    for (t = BADCSE, --s; *t; *s++ = *t++);
 117.436 +				/* finally bogus charset */
 117.437 +    for (t = charset; *t; *s++ = *t++);
 117.438 +    *s++ = '\0';		/* finally tie off string */
 117.439 +    if (s != (msg + j)) fatal ("charset msg botch");
 117.440 +  }
 117.441 +  return msg;
 117.442 +}
 117.443 +
 117.444 +/* Convert charset labelled sized text to UTF-8
 117.445 + * Accepts: source sized text
 117.446 + *	    charset
 117.447 + *	    pointer to returned sized text if non-NIL
 117.448 + *	    flags
 117.449 + * Returns: T if successful, NIL if failure
 117.450 + */
 117.451 +
 117.452 +long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags)
 117.453 +{
 117.454 +  ucs4cn_t cv = (flags & U8T_CASECANON) ? ucs4_titlecase : NIL;
 117.455 +  ucs4de_t de = (flags & U8T_DECOMPOSE) ? ucs4_decompose_recursive : NIL;
 117.456 +  const CHARSET *cs = (charset && *charset) ?
 117.457 +    utf8_charset (charset) : utf8_infercharset (text);
 117.458 +  if (cs) return (text && ret) ? utf8_text_cs (text,cs,ret,cv,de) : LONGT;
 117.459 +  if (ret) {			/* no conversion possible */
 117.460 +    ret->data = text->data;	/* so return source */
 117.461 +    ret->size = text->size;
 117.462 +  }
 117.463 +  return NIL;			/* failure */
 117.464 +}
 117.465 +
 117.466 +
 117.467 +/* Operations used in converting data */
 117.468 +
 117.469 +#define UTF8_COUNT_BMP(count,c,cv,de) {		\
 117.470 +  void *more = NIL;				\
 117.471 +  if (cv) c = (*cv) (c);			\
 117.472 +  if (de) c = (*de) (c,&more);			\
 117.473 +  do count += UTF8_SIZE_BMP(c);			\
 117.474 +  while (more && (c = (*de) (U8G_ERROR,&more)));\
 117.475 +}
 117.476 +
 117.477 +#define UTF8_WRITE_BMP(b,c,cv,de) {		\
 117.478 +  void *more = NIL;				\
 117.479 +  if (cv) c = (*cv) (c);			\
 117.480 +  if (de) c = (*de) (c,&more);			\
 117.481 +  do UTF8_PUT_BMP (b,c)				\
 117.482 +  while (more && (c = (*de) (U8G_ERROR,&more)));\
 117.483 +}
 117.484 +
 117.485 +#define UTF8_COUNT(count,c,cv,de) {		\
 117.486 +  void *more = NIL;				\
 117.487 +  if (cv) c = (*cv) (c);			\
 117.488 +  if (de) c = (*de) (c,&more);			\
 117.489 +  do count += utf8_size (c);			\
 117.490 +  while (more && (c = (*de) (U8G_ERROR,&more)));\
 117.491 +}
 117.492 +
 117.493 +#define UTF8_WRITE(b,c,cv,de) {			\
 117.494 +  void *more = NIL;				\
 117.495 +  if (cv) c = (*cv) (c);			\
 117.496 +  if (de) c = (*de) (c,&more);			\
 117.497 +  do b = utf8_put (b,c);			\
 117.498 +  while (more && (c = (*de) (U8G_ERROR,&more)));\
 117.499 +}
 117.500 +
 117.501 +/* Convert sized text to UTF-8 given CHARSET block
 117.502 + * Accepts: source sized text
 117.503 + *	    CHARSET block
 117.504 + *	    pointer to returned sized text 
 117.505 + *	    canonicalization function
 117.506 + *	    decomposition function
 117.507 + * Returns: T if successful, NIL if failure
 117.508 + */
 117.509 +
 117.510 +long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret,
 117.511 +		   ucs4cn_t cv,ucs4de_t de)
 117.512 +{
 117.513 +  ret->data = text->data;	/* default to source */
 117.514 +  ret->size = text->size;
 117.515 +  switch (cs->type) {		/* convert if type known */
 117.516 +  case CT_ASCII:		/* 7-bit ASCII no table */
 117.517 +  case CT_UTF8:			/* variable UTF-8 encoded Unicode no table */
 117.518 +    if (cv || de) utf8_text_utf8 (text,ret,cv,de);
 117.519 +    break;
 117.520 +  case CT_1BYTE0:		/* 1 byte no table */
 117.521 +    utf8_text_1byte0 (text,ret,cv,de);
 117.522 +    break;
 117.523 +  case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
 117.524 +    utf8_text_1byte (text,ret,cs->tab,cv,de);
 117.525 +    break;
 117.526 +  case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
 117.527 +    utf8_text_1byte8 (text,ret,cs->tab,cv,de);
 117.528 +    break;
 117.529 +  case CT_EUC:			/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
 117.530 +    utf8_text_euc (text,ret,cs->tab,cv,de);
 117.531 +    break;
 117.532 +  case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
 117.533 +    utf8_text_dbyte (text,ret,cs->tab,cv,de);
 117.534 +    break;
 117.535 +  case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
 117.536 +    utf8_text_dbyte2 (text,ret,cs->tab,cv,de);
 117.537 +    break;
 117.538 +  case CT_UTF7:			/* variable UTF-7 encoded Unicode no table */
 117.539 +    utf8_text_utf7 (text,ret,cv,de);
 117.540 +    break;
 117.541 +  case CT_UCS2:			/* 2 byte 16-bit Unicode no table */
 117.542 +    utf8_text_ucs2 (text,ret,cv,de);
 117.543 +    break;
 117.544 +  case CT_UCS4:			/* 4 byte 32-bit Unicode no table */
 117.545 +    utf8_text_ucs4 (text,ret,cv,de);
 117.546 +    break;
 117.547 +  case CT_UTF16:		/* variable UTF-16 encoded Unicode no table */
 117.548 +    utf8_text_utf16 (text,ret,cv,de);
 117.549 +    break;
 117.550 +  case CT_2022:			/* variable ISO-2022 encoded no table*/
 117.551 +    utf8_text_2022 (text,ret,cv,de);
 117.552 +    break;
 117.553 +  case CT_SJIS:			/* 2 byte Shift-JIS encoded JIS no table */
 117.554 +    utf8_text_sjis (text,ret,cv,de);
 117.555 +    break;
 117.556 +  default:			/* unknown character set type */
 117.557 +    return NIL;
 117.558 +  }
 117.559 +  return LONGT;			/* return success */
 117.560 +}
 117.561 +
 117.562 +/* Reverse mapping routines
 117.563 + *
 117.564 + * These routines only support character sets, not all possible charsets.  In
 117.565 + * particular, they do not support any Unicode encodings or ISO 2022.
 117.566 + *
 117.567 + * As a special dispensation, utf8_cstext() and utf8_cstocstext() support
 117.568 + * support ISO-2022-JP if EUC-JP can be reverse mapped; and utf8_rmaptext()
 117.569 + * will generated ISO-2022-JP using an EUC-JP rmap if flagged to do so.
 117.570 + *
 117.571 + * No attempt is made to map "equivalent" Unicode characters or Unicode
 117.572 + * characters that have the same glyph; nor is there any attempt to handle
 117.573 + * combining characters or otherwise do any stringprep.  Maybe later.
 117.574 + */
 117.575 +
 117.576 +
 117.577 +/* Convert UTF-8 sized text to charset
 117.578 + * Accepts: source sized text
 117.579 + *	    destination charset
 117.580 + *	    pointer to returned sized text
 117.581 + *	    substitute character if not in cs, else NIL to return failure
 117.582 + * Returns: T if successful, NIL if failure
 117.583 + */
 117.584 +
 117.585 +
 117.586 +long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,
 117.587 +		  unsigned long errch)
 117.588 +{
 117.589 +  short iso2022jp = !compare_cstring (charset,"ISO-2022-JP");
 117.590 +  unsigned short *rmap = utf8_rmap (iso2022jp ? "EUC-JP" : charset);
 117.591 +  return rmap ? utf8_rmaptext (text,rmap,ret,errch,iso2022jp) : NIL;
 117.592 +}
 117.593 +
 117.594 +/* Convert charset labelled sized text to another charset
 117.595 + * Accepts: source sized text
 117.596 + *	    source charset
 117.597 + *	    pointer to returned sized text
 117.598 + *	    destination charset
 117.599 + *	    substitute character if not in dest cs, else NIL to return failure
 117.600 + * Returns: T if successful, NIL if failure
 117.601 + *
 117.602 + * This routine has the same restricts as utf8_cstext().
 117.603 + */
 117.604 +
 117.605 +long utf8_cstocstext (SIZEDTEXT *src,char *sc,SIZEDTEXT *dst,char *dc,
 117.606 +		      unsigned long errch)
 117.607 +{
 117.608 +  SIZEDTEXT utf8;
 117.609 +  const CHARSET *scs,*dcs;
 117.610 +  unsigned short *rmap;
 117.611 +  long ret = NIL;
 117.612 +  long iso2022jp;
 117.613 +				/* lookup charsets and reverse map */
 117.614 +  if ((dc && (dcs = utf8_charset (dc))) &&
 117.615 +      (rmap = (iso2022jp = ((dcs->type == CT_2022) &&
 117.616 +			    !compare_cstring (dcs->name,"ISO-2022-JP"))) ?
 117.617 +       utf8_rmap ("EUC-JP") : utf8_rmap_cs (dcs)) &&
 117.618 +      (scs = (sc && *sc) ? utf8_charset (sc) : utf8_infercharset (src))) {
 117.619 +				/* init temporary buffer */
 117.620 +    memset (&utf8,NIL,sizeof (SIZEDTEXT));
 117.621 +				/* source cs equivalent to dest cs? */
 117.622 +    if ((scs->type == dcs->type) && (scs->tab == dcs->tab)) {
 117.623 +      dst->data = src->data;	/* yes, just copy pointers */
 117.624 +      dst->size = src->size;
 117.625 +      ret = LONGT;
 117.626 +    }
 117.627 +				/* otherwise do the conversion */
 117.628 +    else ret = (utf8_text_cs (src,scs,&utf8,NIL,NIL) &&
 117.629 +		utf8_rmaptext (&utf8,rmap,dst,errch,iso2022jp));
 117.630 +				/* flush temporary buffer */
 117.631 +    if (utf8.data && (utf8.data != src->data) && (utf8.data != dst->data))
 117.632 +      fs_give ((void **) &utf8.data);
 117.633 +  }
 117.634 +  return ret;
 117.635 +}
 117.636 +
 117.637 +/* Cached rmap */
 117.638 +
 117.639 +static const CHARSET *currmapcs = NIL;
 117.640 +static unsigned short *currmap = NIL;
 117.641 +
 117.642 +
 117.643 +/* Cache and return map for UTF-8 -> character set
 117.644 + * Accepts: character set name
 117.645 + * Returns: cached map if character set found, else NIL
 117.646 + */
 117.647 +
 117.648 +unsigned short *utf8_rmap (char *charset)
 117.649 +{
 117.650 +  return (currmapcs && !compare_cstring (charset,currmapcs->name)) ? currmap :
 117.651 +    utf8_rmap_cs (utf8_charset (charset));
 117.652 +}
 117.653 +
 117.654 +
 117.655 +/* Cache and return map for UTF-8 -> character set given CHARSET block
 117.656 + * Accepts: CHARSET block
 117.657 + * Returns: cached map if character set found, else NIL
 117.658 + */
 117.659 +
 117.660 +unsigned short *utf8_rmap_cs (const CHARSET *cs)
 117.661 +{
 117.662 +  unsigned short *ret = NIL;
 117.663 +  if (!cs);			/* have charset? */
 117.664 +  else if (cs == currmapcs) ret = currmap;
 117.665 +  else if (ret = utf8_rmap_gen (cs,currmap)) {
 117.666 +    currmapcs = cs;
 117.667 +    currmap = ret;
 117.668 +  }
 117.669 +  return ret;
 117.670 +}
 117.671 +
 117.672 +/* Return map for UTF-8 -> character set given CHARSET block
 117.673 + * Accepts: CHARSET block
 117.674 + *	    old map to recycle
 117.675 + * Returns: map if character set found, else NIL
 117.676 + */
 117.677 +
 117.678 +unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap)
 117.679 +{
 117.680 +  unsigned short u,*tab,*rmap;
 117.681 +  unsigned int i,m,ku,ten;
 117.682 +  struct utf8_eucparam *param,*p2;
 117.683 +  switch (cs->type) {		/* is a character set? */
 117.684 +  case CT_ASCII:		/* 7-bit ASCII no table */
 117.685 +  case CT_1BYTE0:		/* 1 byte no table */
 117.686 +  case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
 117.687 +  case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
 117.688 +  case CT_EUC:			/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
 117.689 +  case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
 117.690 +  case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
 117.691 +  case CT_SJIS:			/* 2 byte Shift-JIS */
 117.692 +    rmap = oldmap ? oldmap :	/* recycle old map if supplied else make new */
 117.693 +      (unsigned short *) fs_get (65536 * sizeof (unsigned short));
 117.694 +				/* initialize table for ASCII */
 117.695 +    for (i = 0; i < 128; i++) rmap[i] = (unsigned short) i;
 117.696 +				/* populate remainder of table with NOCHAR */
 117.697 +#define NOCHARBYTE (NOCHAR & 0xff)
 117.698 +#if NOCHAR - ((NOCHARBYTE << 8) | NOCHARBYTE)
 117.699 +    while (i < 65536) rmap[i++] = NOCHAR;
 117.700 +#else
 117.701 +    memset (rmap + 128,NOCHARBYTE,(65536 - 128) * sizeof (unsigned short));
 117.702 +#endif
 117.703 +    break;
 117.704 +  default:			/* unsupported charset type */
 117.705 +    rmap = NIL;			/* no map possible */
 117.706 +  }
 117.707 +  if (rmap) {			/* have a map? */
 117.708 +    switch (cs->type) {		/* additional reverse map actions */
 117.709 +    case CT_1BYTE0:		/* 1 byte no table */
 117.710 +      for (i = 128; i < 256; i++) rmap[i] = (unsigned short) i;
 117.711 +      break;
 117.712 +    case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
 117.713 +      for (tab = (unsigned short *) cs->tab,i = 128; i < 256; i++)
 117.714 +	if (tab[i & BITS7] != UBOGON) rmap[tab[i & BITS7]] = (unsigned short)i;
 117.715 +      break;
 117.716 +    case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
 117.717 +      for (tab = (unsigned short *) cs->tab,i = 0; i < 256; i++)
 117.718 +	if (tab[i] != UBOGON) rmap[tab[i]] = (unsigned short) i;
 117.719 +      break;
 117.720 +    case CT_EUC:		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
 117.721 +      for (param = (struct utf8_eucparam *) cs->tab,
 117.722 +	     tab = (unsigned short *) param->tab, ku = 0;
 117.723 +	   ku < param->max_ku; ku++)
 117.724 +	for (ten = 0; ten < param->max_ten; ten++)
 117.725 +	  if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
 117.726 +	    rmap[u] = ((ku + param->base_ku) << 8) +
 117.727 +	      (ten + param->base_ten) + 0x8080;
 117.728 +      break;
 117.729 +
 117.730 +    case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
 117.731 +      for (param = (struct utf8_eucparam *) cs->tab,
 117.732 +	     tab = (unsigned short *) param->tab, ku = 0;
 117.733 +	   ku < param->max_ku; ku++)
 117.734 +	for (ten = 0; ten < param->max_ten; ten++)
 117.735 +	  if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
 117.736 +	    rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten);
 117.737 +      break;
 117.738 +    case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
 117.739 +      param = (struct utf8_eucparam *) cs->tab;
 117.740 +      p2 = param + 1;		/* plane 2 parameters */
 117.741 +				/* only ten parameters should differ */
 117.742 +      if ((param->base_ku != p2->base_ku) || (param->max_ku != p2->max_ku))
 117.743 +	fatal ("ku definition error for CT_DBYTE2 charset");
 117.744 +				/* total codepoints in each ku */
 117.745 +      m = param->max_ten + p2->max_ten;
 117.746 +      tab = (unsigned short *) param->tab;
 117.747 +      for (ku = 0; ku < param->max_ku; ku++) {
 117.748 +	for (ten = 0; ten < param->max_ten; ten++)
 117.749 +	  if ((u = tab[(ku * m) + ten]) != UBOGON)
 117.750 +	    rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten);
 117.751 +	for (ten = 0; ten < p2->max_ten; ten++)
 117.752 +	  if ((u = tab[(ku * m) + param->max_ten + ten]) != UBOGON)
 117.753 +	    rmap[u] = ((ku + param->base_ku) << 8) + (ten + p2->base_ten);
 117.754 +      }
 117.755 +      break;
 117.756 +    case CT_SJIS:		/* 2 byte Shift-JIS */
 117.757 +      for (ku = 0; ku < MAX_JIS0208_KU; ku++)
 117.758 +	for (ten = 0; ten < MAX_JIS0208_TEN; ten++)
 117.759 +	  if ((u = jis0208tab[ku][ten]) != UBOGON) {
 117.760 +	    int sku = ku + BASE_JIS0208_KU;
 117.761 +	    int sten = ten + BASE_JIS0208_TEN;
 117.762 +	    rmap[u] = ((((sku + 1) >> 1) + ((sku < 95) ? 112 : 176)) << 8) +
 117.763 +	      sten + ((sku % 2) ? ((sten > 95) ? 32 : 31) : 126);
 117.764 +	  }
 117.765 +				/* JIS Roman */
 117.766 +      rmap[UCS2_YEN] = JISROMAN_YEN;
 117.767 +      rmap[UCS2_OVERLINE] = JISROMAN_OVERLINE;
 117.768 +				/* JIS hankaku katakana */
 117.769 +      for (u = 0; u < (MAX_KANA_8 - MIN_KANA_8); u++)
 117.770 +	rmap[UCS2_KATAKANA + u] = MIN_KANA_8 + u;
 117.771 +      break;
 117.772 +    }
 117.773 +				/* hack: map NBSP to SP if otherwise no map */
 117.774 +    if (rmap[0x00a0] == NOCHAR) rmap[0x00a0] = rmap[0x0020];
 117.775 +  }
 117.776 +  return rmap;			/* return map */
 117.777 +}
 117.778 +
 117.779 +/* Convert UTF-8 sized text to charset using rmap
 117.780 + * Accepts: source sized text
 117.781 + *	    conversion rmap
 117.782 + *	    pointer to returned sized text
 117.783 + *	    substitute character if not in rmap, else NIL to return failure
 117.784 + *	    ISO-2022-JP conversion flag
 117.785 + * Returns T if successful, NIL if failure
 117.786 + *
 117.787 + * This routine doesn't try to convert to all possible charsets; in particular
 117.788 + * it doesn't support other Unicode encodings or any ISO 2022 other than
 117.789 + * ISO-2022-JP.
 117.790 + */
 117.791 +
 117.792 +long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret,
 117.793 +		    unsigned long errch,long iso2022jp)
 117.794 +{
 117.795 +  unsigned long i,u,c;
 117.796 +				/* get size of buffer */
 117.797 +  if (i = utf8_rmapsize (text,rmap,errch,iso2022jp)) {
 117.798 +    unsigned char *s = text->data;
 117.799 +    unsigned char *t = ret->data = (unsigned char *) fs_get (i);
 117.800 +    ret->size = i - 1;		/* number of octets in destination buffer */
 117.801 +				/* start non-zero ISO-2022-JP state at 1 */
 117.802 +    if (iso2022jp) iso2022jp = 1;
 117.803 +				/* convert string, ignore BOM */
 117.804 +    for (i = text->size; i;) if ((u = utf8_get (&s,&i)) != UCS2_BOM) {
 117.805 +				/* substitute error character for NOCHAR */
 117.806 +      if ((u & U8GM_NONBMP) || ((c = rmap[u]) == NOCHAR)) c = errch;
 117.807 +      switch (iso2022jp) {	/* depends upon ISO 2022 mode */
 117.808 +      case 0:			/* ISO 2022 not in effect */
 117.809 +				/* two-byte character */
 117.810 +	if (c > 0xff) *t++ = (unsigned char) (c >> 8);
 117.811 +				/* single-byte or low-byte of two-byte */
 117.812 +	*t++ = (unsigned char) (c & 0xff);
 117.813 +	break;
 117.814 +      case 1:			/* ISO 2022 Roman */
 117.815 +				/* <ch> */
 117.816 +	if (c < 0x80) *t++ = (unsigned char) c;
 117.817 +	else {			/* JIS character */
 117.818 +	  *t++ = I2C_ESC;	/* ESC $ B <hi> <lo> */
 117.819 +	  *t++ = I2C_MULTI;
 117.820 +	  *t++ = I2CS_94x94_JIS_NEW;
 117.821 +	  *t++ = (unsigned char) (c >> 8) & 0x7f;
 117.822 +	  *t++ = (unsigned char) c & 0x7f;
 117.823 +	  iso2022jp = 2;	/* shift to ISO 2022 JIS */
 117.824 +	}
 117.825 +	break;
 117.826 +      case 2:			/* ISO 2022 JIS */
 117.827 +	if (c > 0x7f) {		/* <hi> <lo> */
 117.828 +	  *t++ = (unsigned char) (c >> 8) & 0x7f;
 117.829 +	  *t++ = (unsigned char) c & 0x7f;
 117.830 +	}
 117.831 +	else {			/* ASCII character */
 117.832 +	  *t++ = I2C_ESC;	/* ESC ( J <ch> */
 117.833 +	  *t++ = I2C_G0_94;
 117.834 +	  *t++ = I2CS_94_JIS_ROMAN;
 117.835 +	  *t++ = (unsigned char) c;
 117.836 +	  iso2022jp = 1;	/* shift to ISO 2022 Roman */
 117.837 +	}
 117.838 +	break;
 117.839 +      }
 117.840 +    }
 117.841 +    if (iso2022jp == 2) {	/* ISO-2022-JP string must end in Roman */
 117.842 +      *t++ = I2C_ESC;		/* ESC ( J */
 117.843 +      *t++ = I2C_G0_94;
 117.844 +      *t++ = I2CS_94_JIS_ROMAN;
 117.845 +    }
 117.846 +    *t++ = NIL;			/* tie off returned data */
 117.847 +    return LONGT;		/* return success */
 117.848 +  }
 117.849 +  ret->data = NIL;
 117.850 +  ret->size = 0;
 117.851 +  return NIL;			/* failure */
 117.852 +}
 117.853 +
 117.854 +/* Calculate size of convertsion of UTF-8 sized text to charset using rmap
 117.855 + * Accepts: source sized text
 117.856 + *	    conversion rmap
 117.857 + *	    pointer to returned sized text
 117.858 + *	    substitute character if not in rmap, else NIL to return failure
 117.859 + *	    ISO-2022-JP conversion flag
 117.860 + * Returns size+1 if successful, NIL if failure
 117.861 + *
 117.862 + * This routine doesn't try to handle to all possible charsets; in particular
 117.863 + * it doesn't support other Unicode encodings or any ISO 2022 other than
 117.864 + * ISO-2022-JP.
 117.865 + */
 117.866 +
 117.867 +unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap,
 117.868 +			     unsigned long errch,long iso2022jp)
 117.869 +{
 117.870 +  unsigned long i,u,c;
 117.871 +  unsigned long ret = 1;	/* terminating NUL */
 117.872 +  unsigned char *s = text->data;
 117.873 +  if (iso2022jp) iso2022jp = 1;	/* start non-zero ISO-2022-JP state at 1 */
 117.874 +  for (i = text->size; i;) if ((u = utf8_get (&s,&i)) != UCS2_BOM) {
 117.875 +    if ((u & U8GM_NONBMP) || (((c = rmap[u]) == NOCHAR) && !(c = errch)))
 117.876 +      return NIL;		/* not in BMP, or NOCHAR and no err char */
 117.877 +    switch (iso2022jp) {	/* depends upon ISO 2022 mode */
 117.878 +    case 0:			/* ISO 2022 not in effect */
 117.879 +      ret += (c > 0xff) ? 2 : 1;
 117.880 +      break;
 117.881 +    case 1:			/* ISO 2022 Roman */
 117.882 +      if (c < 0x80) ret += 1;	/* <ch> */
 117.883 +      else {			/* JIS character */
 117.884 +	ret += 5;		/* ESC $ B <hi> <lo> */
 117.885 +	iso2022jp = 2;		/* shift to ISO 2022 JIS */
 117.886 +      }
 117.887 +      break;
 117.888 +    case 2:			/* ISO 2022 JIS */
 117.889 +      if (c > 0x7f) ret += 2;	/* <hi> <lo> */
 117.890 +      else {			/* ASCII character */
 117.891 +	ret += 4;		/* ESC ( J <ch> */
 117.892 +	iso2022jp = 1;		/* shift to ISO 2022 Roman */
 117.893 +      }
 117.894 +      break;
 117.895 +    }
 117.896 +  }
 117.897 +  if (iso2022jp == 2) {		/* ISO-2022-JP string must end in Roman */
 117.898 +    ret += 3;			/* ESC ( J */
 117.899 +    iso2022jp = 1;		/* reset state to Roman */
 117.900 +  }
 117.901 +  return ret;
 117.902 +}
 117.903 +
 117.904 +/* Convert UCS-4 to charset using rmap
 117.905 + * Accepts: source UCS-4 character(s)
 117.906 + *	    numver of UCS-4 characters
 117.907 + *	    conversion rmap
 117.908 + *	    pointer to returned sized text
 117.909 + *	    substitute character if not in rmap, else NIL to return failure
 117.910 + * Returns T if successful, NIL if failure
 117.911 + *
 117.912 + * Currently only supports BMP characters, and does not support ISO-2022
 117.913 + */
 117.914 +
 117.915 +long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
 117.916 +		    SIZEDTEXT *ret,unsigned long errch)
 117.917 +{
 117.918 +  long size = ucs4_rmaplen (ucs4,len,rmap,errch);
 117.919 +  return (size >= 0) ?		/* build in newly-created buffer */
 117.920 +    ucs4_rmapbuf (ret->data = (unsigned char *) fs_get ((ret->size = size) +1),
 117.921 +		  ucs4,len,rmap,errch) : NIL;
 117.922 +}
 117.923 +
 117.924 +/* Return size of UCS-4 string converted to other CS via rmap
 117.925 + * Accepts: source UCS-4 character(s)
 117.926 + *	    numver of UCS-4 characters
 117.927 + *	    conversion rmap
 117.928 + *	    substitute character if not in rmap, else NIL to return failure
 117.929 + * Returns: length if success, negative if failure (no-convert)
 117.930 + */
 117.931 +
 117.932 +long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
 117.933 +		   unsigned long errch)
 117.934 +{
 117.935 +  long ret;
 117.936 +  unsigned long i,u,c;
 117.937 +				/* count non-BOM characters */
 117.938 +  for (ret = 0,i = 0; i < len; ++i) if ((u = ucs4[i]) != UCS2_BOM) {
 117.939 +    if ((u & U8GM_NONBMP) || (((c = rmap[u]) == NOCHAR) && !(c = errch)))
 117.940 +      return -1;		/* not in BMP, or NOCHAR and no err char? */
 117.941 +    ret += (c > 0xff) ? 2 : 1;
 117.942 +  }
 117.943 +  return ret;
 117.944 +}
 117.945 +
 117.946 +
 117.947 +/* Stuff buffer with UCS-4 string converted to other CS via rmap
 117.948 + * Accepts: destination buffer
 117.949 + *	    source UCS-4 character(s)
 117.950 + *	    number of UCS-4 characters
 117.951 + *	    conversion rmap
 117.952 + *	    substitute character if not in rmap, else NIL to return failure
 117.953 + * Returns: T, always
 117.954 + */
 117.955 +
 117.956 +long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len,
 117.957 +		   unsigned short *rmap,unsigned long errch)
 117.958 +{
 117.959 +  unsigned long i,u,c;
 117.960 +				/* convert non-BOM characters */
 117.961 +  for (i = 0; i < len; ++i) if ((u = ucs4[i]) != UCS2_BOM) {
 117.962 +				/* substitute error character for NOCHAR */
 117.963 +    if ((u & U8GM_NONBMP) || ((c = rmap[u]) == NOCHAR)) c = errch;
 117.964 +				/* two-byte character? */
 117.965 +    if (c > 0xff) *t++ = (unsigned char) (c >> 8);
 117.966 +				/* single-byte or low-byte of two-byte */
 117.967 +    *t++ = (unsigned char) (c & 0xff);
 117.968 +  }
 117.969 +  *t++ = NIL;			/* tie off returned data */
 117.970 +  return LONGT;
 117.971 +}
 117.972 +
 117.973 +/* Return UCS-4 Unicode character from UTF-8 string
 117.974 + * Accepts: pointer to string
 117.975 + *	    remaining octets in string
 117.976 + * Returns: UCS-4 character with pointer and count updated
 117.977 + *	    or error code with pointer and count unchanged
 117.978 + */
 117.979 +
 117.980 +unsigned long utf8_get (unsigned char **s,unsigned long *i)
 117.981 +{
 117.982 +  unsigned char *t = *s;
 117.983 +  unsigned long j = *i;
 117.984 +				/* decode raw UTF-8 string */
 117.985 +  unsigned long ret = utf8_get_raw (&t,&j);
 117.986 +  if (ret & U8G_ERROR);		/* invalid raw UTF-8 decoding? */
 117.987 +				/* no, is it surrogate? */
 117.988 +  else if ((ret >= UTF16_SURR) && (ret <= UTF16_MAXSURR)) ret = U8G_SURROGA;
 117.989 +				/* or in non-Unicode ISO 10646 space? */
 117.990 +  else if (ret > UCS4_MAXUNICODE) ret = U8G_NOTUNIC;
 117.991 +  else {
 117.992 +    *s = t;			/* all is well, update pointer */
 117.993 +    *i = j;			/* and counter */
 117.994 +  }
 117.995 +  return ret;			/* return value */
 117.996 +}
 117.997 +
 117.998 +/* Return raw (including non-Unicode) UCS-4 character from UTF-8 string
 117.999 + * Accepts: pointer to string
117.1000 + *	    remaining octets in string
117.1001 + * Returns: UCS-4 character with pointer and count updated
117.1002 + *	    or error code with pointer and count unchanged
117.1003 + */
117.1004 +
117.1005 +unsigned long utf8_get_raw (unsigned char **s,unsigned long *i)
117.1006 +{
117.1007 +  unsigned char c,c1;
117.1008 +  unsigned char *t = *s;
117.1009 +  unsigned long j = *i;
117.1010 +  unsigned long ret = U8G_NOTUTF8;
117.1011 +  int more = 0;
117.1012 +  do {				/* make sure have source octets available */
117.1013 +    if (!j--) return more ? U8G_ENDSTRI : U8G_ENDSTRG;
117.1014 +				/* UTF-8 continuation? */
117.1015 +    else if (((c = *t++) > 0x7f) && (c < 0xc0)) {
117.1016 +				/* continuation when not in progress */
117.1017 +      if (!more) return U8G_BADCONT;
117.1018 +      --more;			/* found a continuation octet */
117.1019 +      ret <<= 6;		/* shift current value by 6 bits */
117.1020 +      ret |= c & 0x3f;		/* merge continuation octet */
117.1021 +    }
117.1022 +				/* incomplete UTF-8 character */
117.1023 +    else if (more) return U8G_INCMPLT;
117.1024 +    else {			/* start of sequence */
117.1025 +      c1 = j ? *t : 0xbf;	/* assume valid continuation if incomplete */
117.1026 +      if (c < 0x80) ret = c;	/* U+0000 - U+007f */
117.1027 +      else if (c < 0xc2);	/* c0 and c1 never valid */
117.1028 +      else if (c < 0xe0) {	/* U+0080 - U+07ff */
117.1029 +	if (c &= 0x1f) more = 1;
117.1030 +      }
117.1031 +      else if (c < 0xf0) {	/* U+0800 - U+ffff */
117.1032 +	if ((c &= 0x0f) || (c1 >= 0xa0)) more = 2;
117.1033 +      }
117.1034 +      else if (c < 0xf8) {	/* U+10000 - U+10ffff (and 110000 - 1fffff) */
117.1035 +	if ((c &= 0x07) || (c1 >= 0x90)) more = 3;
117.1036 +      }
117.1037 +      else if (c < 0xfc) {	/* ISO 10646 200000 - 3ffffff */
117.1038 +	if ((c &= 0x03) || (c1 >= 0x88)) more = 4;
117.1039 +      }
117.1040 +      else if (c < 0xfe) {	/* ISO 10646 4000000 - 7fffffff */
117.1041 +	if ((c &= 0x01) || (c1 >= 0x84)) more = 5;
117.1042 +      }
117.1043 +				/* fe and ff never valid */
117.1044 +      if (more) {		/* multi-octet, make sure more to come */
117.1045 +	if (!j) return U8G_ENDSTRI;
117.1046 +	ret = c;		/* continuation needed, save start bits */
117.1047 +      }
117.1048 +    }
117.1049 +  } while (more);
117.1050 +  if (!(ret & U8G_ERROR)) {	/* success return? */
117.1051 +    *s = t;			/* yes, update pointer */
117.1052 +    *i = j;			/* and counter */
117.1053 +  }
117.1054 +  return ret;			/* return value */
117.1055 +}
117.1056 +
117.1057 +/* Return UCS-4 character from named charset string
117.1058 + * Accepts: charset
117.1059 + *	    pointer to string
117.1060 + *	    remaining octets in string
117.1061 + * Returns: UCS-4 character with pointer and count updated, negative if error
117.1062 + *
117.1063 + * Error codes are the same as utf8_get().
117.1064 + */
117.1065 +
117.1066 +unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i)
117.1067 +{
117.1068 +  unsigned char c,c1,ku,ten;
117.1069 +  unsigned long ret,d;
117.1070 +  unsigned char *t = *s;
117.1071 +  unsigned long j = *i;
117.1072 +  struct utf8_eucparam *p1,*p2,*p3;
117.1073 +  if (j--) c = *t++;		/* get first octet */
117.1074 +  else return U8G_ENDSTRG;	/* empty string */
117.1075 +  switch (cs->type) {		/* convert if type known */
117.1076 +  case CT_UTF8:			/* variable UTF-8 encoded Unicode no table */
117.1077 +    return utf8_get (s,i);
117.1078 +  case CT_ASCII:		/* 7-bit ASCII no table */
117.1079 +    if (c >= 0x80) return U8G_NOTUTF8;
117.1080 +  case CT_1BYTE0:		/* 1 byte no table */
117.1081 +    ret = c;			/* identity */
117.1082 +    break;
117.1083 +  case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
117.1084 +    ret = (c > 0x80) ? ((unsigned short *) cs->tab)[c & BITS7] : c;
117.1085 +    break;
117.1086 +  case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
117.1087 +    ret = ((unsigned short *) cs->tab)[c];
117.1088 +    break;
117.1089 +
117.1090 +  case CT_EUC:			/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
117.1091 +    if (c & BIT8) {
117.1092 +      p1 = (struct utf8_eucparam *) cs->tab;
117.1093 +      p2 = p1 + 1;
117.1094 +      p3 = p1 + 2;
117.1095 +      if (j--) c1 = *t++;	/* get second octet */
117.1096 +      else return U8G_ENDSTRI;
117.1097 +      if (!(c1 & BIT8)) return U8G_NOTUTF8;
117.1098 +      switch (c) {		/* check 8bit code set */
117.1099 +      case EUC_CS2:		/* CS2 */
117.1100 +	if (p2->base_ku) {	/* CS2 set up? */
117.1101 +	  if (p2->base_ten) {	/* yes, multibyte? */
117.1102 +	    if (j--) c = *t++;	/* get second octet */
117.1103 +	    else return U8G_ENDSTRI;
117.1104 +	    if ((c & BIT8) &&
117.1105 +		((ku = (c1 & BITS7) - p2->base_ku) < p2->max_ku) &&
117.1106 +		((ten = (c & BITS7) - p2->base_ten) < p2->max_ten)) {
117.1107 +	      ret = ((unsigned short *) p2->tab)[(ku*p2->max_ten) + ten];
117.1108 +	      break;
117.1109 +	    }
117.1110 +	  }
117.1111 +	  else if ((c1 >= p2->base_ku) && (c1 < p2->max_ku)) {
117.1112 +	    ret = c1 + ((unsigned long) p2->tab);
117.1113 +	    break;
117.1114 +	  }
117.1115 +	}
117.1116 +	return U8G_NOTUTF8;	/* CS2 not set up or bogus */
117.1117 +      case EUC_CS3:		/* CS3 */
117.1118 +	if (p3->base_ku) {	/* CS3 set up? */
117.1119 +	  if (p3->base_ten) {	/* yes, multibyte? */
117.1120 +	    if (j--) c = *t++;	/* get second octet */
117.1121 +	    else return U8G_ENDSTRI;
117.1122 +	    if ((c & BIT8) &&
117.1123 +		((ku = (c1 & BITS7) - p3->base_ku) < p3->max_ku) &&
117.1124 +		((ten = (c & BITS7) - p3->base_ten) < p3->max_ten)) {
117.1125 +	      ret = ((unsigned short *) p3->tab)[(ku*p3->max_ten) + ten];
117.1126 +	      break;
117.1127 +	    }
117.1128 +	  }
117.1129 +	  else if ((c1 >= p3->base_ku) && (c1 < p3->max_ku)) {
117.1130 +	    ret = c1 + ((unsigned long) p3->tab);
117.1131 +	    break;
117.1132 +	  }
117.1133 +	}
117.1134 +	return U8G_NOTUTF8;	/* CS3 not set up or bogus */
117.1135 +      default:
117.1136 +	if (((ku = (c & BITS7) - p1->base_ku) >= p1->max_ku) ||
117.1137 +	    ((ten = (c1 & BITS7) - p1->base_ten) >= p1->max_ten))
117.1138 +	  return U8G_NOTUTF8;
117.1139 +	ret = ((unsigned short *) p1->tab)[(ku*p1->max_ten) + ten];
117.1140 +		/* special hack for JIS X 0212: merge rows less than 10 */
117.1141 +	if ((ret == UBOGON) && ku && (ku < 10) && p3->tab && p3->base_ten)
117.1142 +	  ret = ((unsigned short *) p3->tab)
117.1143 +	    [((ku - (p3->base_ku - p1->base_ku))*p3->max_ten) + ten];
117.1144 +	break;
117.1145 +      }
117.1146 +    }
117.1147 +    else ret = c;		/* ASCII character */
117.1148 +    break;
117.1149 +
117.1150 +  case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
117.1151 +    if (c & BIT8) {		/* double-byte character? */
117.1152 +      p1 = (struct utf8_eucparam *) cs->tab;
117.1153 +      if (j--) c1 = *t++;	/* get second octet */
117.1154 +      else return U8G_ENDSTRI;
117.1155 +      if (((ku = c - p1->base_ku) < p1->max_ku) &&
117.1156 +	  ((ten = c1 - p1->base_ten) < p1->max_ten))
117.1157 +	ret = ((unsigned short *) p1->tab)[(ku*p1->max_ten) + ten];
117.1158 +      else return U8G_NOTUTF8;
117.1159 +    }
117.1160 +    else ret = c;		/* ASCII character */
117.1161 +    break;
117.1162 +  case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
117.1163 +    if (c & BIT8) {		/* double-byte character? */
117.1164 +      p1 = (struct utf8_eucparam *) cs->tab;
117.1165 +      p2 = p1 + 1;
117.1166 +      if (j--) c1 = *t++;	/* get second octet */
117.1167 +      else return U8G_ENDSTRI;
117.1168 +      if (c1 & BIT8) {		/* high vs. low plane */
117.1169 +	if ((ku = c - p2->base_ku) < p2->max_ku &&
117.1170 +	    ((ten = c1 - p2->base_ten) < p2->max_ten))
117.1171 +	  ret = ((unsigned short *) p1->tab)
117.1172 +	    [(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten];
117.1173 +	else return U8G_NOTUTF8;
117.1174 +      }
117.1175 +      else if ((ku = c - p1->base_ku) < p1->max_ku &&
117.1176 +	       ((ten = c1 - p1->base_ten) < p1->max_ten))
117.1177 +	  ret = ((unsigned short *) p1->tab)
117.1178 +	    [(ku*(p1->max_ten + p2->max_ten)) + ten];
117.1179 +      else return U8G_NOTUTF8;
117.1180 +    }
117.1181 +    else ret = c;		/* ASCII character */
117.1182 +    break;
117.1183 +  case CT_SJIS:			/* 2 byte Shift-JIS encoded JIS no table */
117.1184 +				/* compromise - do yen sign but not overline */
117.1185 +    if (!(c & BIT8)) ret = (c == JISROMAN_YEN) ? UCS2_YEN : c;
117.1186 +				/* half-width katakana? */
117.1187 +    else if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) ret = c + KANA_8;
117.1188 +    else {			/* Shift-JIS */
117.1189 +      if (j--) c1 = *t++;	/* get second octet */
117.1190 +      else return U8G_ENDSTRI;
117.1191 +      SJISTOJIS (c,c1);
117.1192 +      c = JISTOUNICODE (c,c1,ku,ten);
117.1193 +    }
117.1194 +    break;
117.1195 +
117.1196 +  case CT_UCS2:			/* 2 byte 16-bit Unicode no table */
117.1197 +    ret = c << 8;
117.1198 +    if (j--) c = *t++;		/* get second octet */
117.1199 +    else return U8G_ENDSTRI;	/* empty string */
117.1200 +    ret |= c;
117.1201 +    break;
117.1202 +  case CT_UCS4:			/* 4 byte 32-bit Unicode no table */
117.1203 +    if (c & 0x80) return U8G_NOTUTF8;
117.1204 +    if (j < 3) return U8G_ENDSTRI;
117.1205 +    j -= 3;			/* count three octets */
117.1206 +    ret = c << 24;
117.1207 +    ret |= (*t++) << 16;
117.1208 +    ret |= (*t++) << 8;
117.1209 +    ret |= (*t++);
117.1210 +    break;
117.1211 +  case CT_UTF16:		/* variable UTF-16 encoded Unicode no table */
117.1212 +    ret = c << 8;
117.1213 +    if (j--) c = *t++;		/* get second octet */
117.1214 +    else return U8G_ENDSTRI;	/* empty string */
117.1215 +    ret |= c;
117.1216 +				/* surrogate? */
117.1217 +    if ((ret >= UTF16_SURR) && (ret <= UTF16_MAXSURR)) {
117.1218 +				/* invalid first surrogate */
117.1219 +      if ((ret > UTF16_SURRHEND) || (j < 2)) return U8G_NOTUTF8;
117.1220 +      j -= 2;			/* count two octets */
117.1221 +      d = (*t++) << 8;		/* first octet of second surrogate */
117.1222 +      d |= *t++;		/* second octet of second surrogate */
117.1223 +      if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) return U8G_NOTUTF8;
117.1224 +      ret = UTF16_BASE + ((ret & UTF16_MASK) << UTF16_SHIFT) +
117.1225 +	(d & UTF16_MASK);
117.1226 +    }
117.1227 +    break;
117.1228 +  default:			/* unknown/unsupported character set type */
117.1229 +    return U8G_NOTUTF8;
117.1230 +  }
117.1231 +  *s = t;			/* update pointer and counter */
117.1232 +  *i = j;
117.1233 +  return ret;
117.1234 +}
117.1235 +
117.1236 +/* Produce charset validity map for BMP
117.1237 + * Accepts: list of charsets to map
117.1238 + * Returns: validity map, indexed by BMP codepoint
117.1239 + *
117.1240 + * Bit 0x1 is the "not-CJK" character bit
117.1241 + */
117.1242 +
117.1243 +unsigned long *utf8_csvalidmap (char *charsets[])
117.1244 +{
117.1245 +  unsigned short u,*tab;
117.1246 +  unsigned int m,ku,ten;
117.1247 +  unsigned long i,csi,csb;
117.1248 +  struct utf8_eucparam *param,*p2;
117.1249 +  char *s;
117.1250 +  const CHARSET *cs;
117.1251 +  unsigned long *ret = (unsigned long *)
117.1252 +    fs_get (i = 0x10000 * sizeof (unsigned long));
117.1253 +  memset (ret,0,i);		/* zero the entire vector */
117.1254 +				/* mark all the non-CJK codepoints */
117.1255 +	/* U+0000 - U+2E7F non-CJK */
117.1256 +  for (i = 0; i < 0x2E7F; ++i) ret[i] = 0x1;
117.1257 +	/* U+2E80 - U+2EFF CJK Radicals Supplement
117.1258 +	 * U+2F00 - U+2FDF Kangxi Radicals
117.1259 +	 * U+2FE0 - U+2FEF unassigned
117.1260 +	 * U+2FF0 - U+2FFF Ideographic Description Characters
117.1261 +	 * U+3000 - U+303F CJK Symbols and Punctuation
117.1262 +	 * U+3040 - U+309F Hiragana
117.1263 +	 * U+30A0 - U+30FF Katakana
117.1264 +	 * U+3100 - U+312F BoPoMoFo
117.1265 +	 * U+3130 - U+318F Hangul Compatibility Jamo
117.1266 +	 * U+3190 - U+319F Kanbun
117.1267 +	 * U+31A0 - U+31BF BoPoMoFo Extended
117.1268 +	 * U+31C0 - U+31EF CJK Strokes
117.1269 +	 * U+31F0 - U+31FF Katakana Phonetic Extensions
117.1270 +	 * U+3200 - U+32FF Enclosed CJK Letters and Months
117.1271 +	 * U+3300 - U+33FF CJK Compatibility
117.1272 +	 * U+3400 - U+4DBF CJK Unified Ideographs Extension A
117.1273 +	 * U+4DC0 - U+4DFF Yijing Hexagram Symbols
117.1274 +	 * U+4E00 - U+9FFF CJK Unified Ideographs
117.1275 +	 * U+A000 - U+A48F Yi Syllables
117.1276 +	 * U+A490 - U+A4CF Yi Radicals
117.1277 +	 * U+A700 - U+A71F Modifier Tone Letters
117.1278 +	 */
117.1279 +  for (i = 0xa720; i < 0xabff; ++i) ret[i] = 0x1;
117.1280 +	/* U+AC00 - U+D7FF Hangul Syllables */
117.1281 +  for (i = 0xd800; i < 0xf8ff; ++i) ret[i] = 0x1;
117.1282 +	/* U+F900 - U+FAFF CJK Compatibility Ideographs */
117.1283 +  for (i = 0xfb00; i < 0xfe2f; ++i) ret[i] = 0x1;
117.1284 +	/* U+FE30 - U+FE4F CJK Compatibility Forms
117.1285 +	 * U+FE50 - U+FE6F Small Form Variants (for CNS 11643)
117.1286 +	 */
117.1287 +  for (i = 0xfe70; i < 0xfeff; ++i) ret[i] = 0x1;
117.1288 +	/* U+FF00 - U+FFEF CJK Compatibility Ideographs */
117.1289 +  for (i = 0xfff0; i < 0x10000; ++i) ret[i] = 0x1;
117.1290 +
117.1291 +				/* for each supplied charset */
117.1292 +  for (csi = 1; ret && charsets && (s = charsets[csi - 1]); ++csi) {
117.1293 +				/* substitute EUC-JP for ISO-2022-JP */
117.1294 +    if (!compare_cstring (s,"ISO-2022-JP")) s = "EUC-JP";
117.1295 +				/* look up charset */
117.1296 +    if (cs = utf8_charset (s)) {
117.1297 +      csb = 1 << csi;		/* charset bit */
117.1298 +      switch (cs->type) {
117.1299 +      case CT_ASCII:		/* 7-bit ASCII no table */
117.1300 +      case CT_1BYTE0:		/* 1 byte no table */
117.1301 +      case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
117.1302 +      case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
117.1303 +      case CT_EUC:		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
117.1304 +      case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
117.1305 +      case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
117.1306 +      case CT_SJIS:		/* 2 byte Shift-JIS */
117.1307 +				/* supported charset type, all ASCII is OK */
117.1308 +	for (i = 0; i < 128; ++i) ret[i] |= csb;
117.1309 +	break;
117.1310 +      default:			/* unsupported charset type */
117.1311 +	fs_give ((void **) &ret);
117.1312 +	break;
117.1313 +      }
117.1314 +				/* now do additional operations */
117.1315 +      if (ret) switch (cs->type) {
117.1316 +      case CT_1BYTE0:		/* 1 byte no table */
117.1317 +	for (i = 128; i < 256; i++) ret[i] |= csb;
117.1318 +	break;
117.1319 +      case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
117.1320 +	for (tab = (unsigned short *) cs->tab,i = 128; i < 256; i++)
117.1321 +	  if (tab[i & BITS7] != UBOGON) ret[tab[i & BITS7]] |= csb;
117.1322 +	break;
117.1323 +      case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
117.1324 +	for (tab = (unsigned short *) cs->tab,i = 0; i < 256; i++)
117.1325 +	  if (tab[i] != UBOGON) ret[tab[i]] |= csb;
117.1326 +      break;
117.1327 +      case CT_EUC:		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
117.1328 +	for (param = (struct utf8_eucparam *) cs->tab,
117.1329 +	       tab = (unsigned short *) param->tab, ku = 0;
117.1330 +	     ku < param->max_ku; ku++)
117.1331 +	  for (ten = 0; ten < param->max_ten; ten++)
117.1332 +	    if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
117.1333 +	      ret[u] |= csb;
117.1334 +	break;
117.1335 +
117.1336 +      case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
117.1337 +	for (param = (struct utf8_eucparam *) cs->tab,
117.1338 +	       tab = (unsigned short *) param->tab, ku = 0;
117.1339 +	     ku < param->max_ku; ku++)
117.1340 +	  for (ten = 0; ten < param->max_ten; ten++)
117.1341 +	    if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
117.1342 +	      ret[u] |= csb;
117.1343 +      break;
117.1344 +      case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
117.1345 +	param = (struct utf8_eucparam *) cs->tab;
117.1346 +	p2 = param + 1;		/* plane 2 parameters */
117.1347 +				/* only ten parameters should differ */
117.1348 +	if ((param->base_ku != p2->base_ku) || (param->max_ku != p2->max_ku))
117.1349 +	  fatal ("ku definition error for CT_DBYTE2 charset");
117.1350 +				/* total codepoints in each ku */
117.1351 +	m = param->max_ten + p2->max_ten;
117.1352 +	tab = (unsigned short *) param->tab;
117.1353 +	for (ku = 0; ku < param->max_ku; ku++) {
117.1354 +	  for (ten = 0; ten < param->max_ten; ten++)
117.1355 +	    if ((u = tab[(ku * m) + ten]) != UBOGON)
117.1356 +	      ret[u] |= csb;
117.1357 +	  for (ten = 0; ten < p2->max_ten; ten++)
117.1358 +	    if ((u = tab[(ku * m) + param->max_ten + ten]) != UBOGON)
117.1359 +	      ret[u] |= csb;
117.1360 +	}
117.1361 +	break;
117.1362 +      case CT_SJIS:		/* 2 byte Shift-JIS */
117.1363 +	for (ku = 0; ku < MAX_JIS0208_KU; ku++)
117.1364 +	  for (ten = 0; ten < MAX_JIS0208_TEN; ten++)
117.1365 +	    if ((u = jis0208tab[ku][ten]) != UBOGON) ret[u] |= csb;
117.1366 +				/* JIS hankaku katakana */
117.1367 +	for (u = 0; u < (MAX_KANA_8 - MIN_KANA_8); u++)
117.1368 +	  ret[UCS2_KATAKANA + u] |= csb;
117.1369 +	break;
117.1370 +      }
117.1371 +    }
117.1372 +				/* invalid charset, punt */
117.1373 +    else fs_give ((void **) &ret);
117.1374 +  }
117.1375 +  return ret;
117.1376 +}
117.1377 +
117.1378 +/* Infer charset from unlabelled sized text
117.1379 + * Accepts: sized text
117.1380 + * Returns: charset if one inferred, or NIL if unknown
117.1381 + */
117.1382 +
117.1383 +const CHARSET *utf8_infercharset (SIZEDTEXT *src)
117.1384 +{
117.1385 +  long iso2022jp = NIL;
117.1386 +  long eightbit = NIL;
117.1387 +  unsigned long i;
117.1388 +				/* look for ISO 2022 */
117.1389 +  if (src) for (i = 0; i < src->size; i++) {
117.1390 +				/* ESC sequence? */
117.1391 +    if ((src->data[i] == I2C_ESC) && (++i < src->size)) switch (src->data[i]) {
117.1392 +    case I2C_MULTI:		/* yes, multibyte? */
117.1393 +      if (++i < src->size) switch (src->data[i]) {
117.1394 +      case I2CS_94x94_JIS_OLD:	/* JIS X 0208-1978 */
117.1395 +      case I2CS_94x94_JIS_NEW:	/* JIS X 0208-1983 */
117.1396 +      case I2CS_94x94_JIS_EXT:	/* JIS X 0212-1990 (kludge...) */
117.1397 +	iso2022jp = T;		/* found an ISO-2022-JP sequence */
117.1398 +	break;
117.1399 +      default:			/* other multibyte */
117.1400 +	return NIL;		/* definitely invalid */
117.1401 +      }
117.1402 +      break;
117.1403 +    case I2C_G0_94:		/* single byte */
117.1404 +      if (++i < src->size) switch (src->data[i]) {
117.1405 +      case I2CS_94_JIS_BUGROM:	/* in case old buggy software */
117.1406 +      case I2CS_94_JIS_ROMAN:	/* JIS X 0201-1976 left half */
117.1407 +      case I2CS_94_ASCII:	/* ASCII */
117.1408 +      case I2CS_94_BRITISH:	/* good enough for gov't work */
117.1409 +	break;
117.1410 +      default:			/* other 94 single byte */
117.1411 +	return NIL;		/* definitely invalid */
117.1412 +      }
117.1413 +    }
117.1414 +				/* if possible UTF-8 and not ISO-2022-JP */
117.1415 +    else if (!iso2022jp && (eightbit >= 0) && (src->data[i] & BIT8) &&
117.1416 +	     (eightbit = utf8_validate (src->data + i,src->size - i)) > 0)
117.1417 +      i += eightbit - 1;	/* skip past all but last of UTF-8 char */
117.1418 +  }
117.1419 +				/* ISO-2022-JP overrides other guesses */
117.1420 +  if (iso2022jp) return utf8_charset ("ISO-2022-JP");
117.1421 +  if (eightbit > 0) return utf8_charset ("UTF-8");
117.1422 +  return eightbit ? NIL : utf8_charset ("US-ASCII");
117.1423 +}
117.1424 +
117.1425 +
117.1426 +/* Validate that character at this position is UTF-8
117.1427 + * Accepts: string pointer
117.1428 + *	    size of remaining string
117.1429 + * Returns: size of UTF-8 character in octets or -1 if not UTF-8
117.1430 + */
117.1431 +
117.1432 +long utf8_validate (unsigned char *s,unsigned long i)
117.1433 +{
117.1434 +  unsigned long j = i;
117.1435 +  return (utf8_get (&s,&i) & U8G_ERROR) ? -1 : j - i;
117.1436 +}
117.1437 +
117.1438 +/* Convert ISO 8859-1 to UTF-8
117.1439 + * Accepts: source sized text
117.1440 + *	    pointer to return sized text
117.1441 + *	    canonicalization function
117.1442 + */
117.1443 +
117.1444 +void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.1445 +{
117.1446 +  unsigned long i;
117.1447 +  unsigned char *s;
117.1448 +  unsigned int c;
117.1449 +  for (ret->size = i = 0; i < text->size;) {
117.1450 +    c = text->data[i++];
117.1451 +    UTF8_COUNT_BMP (ret->size,c,cv,de)
117.1452 +  }
117.1453 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
117.1454 +  for (i = 0; i < text->size;) {
117.1455 +    c = text->data[i++];
117.1456 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.1457 +  }
117.1458 +}
117.1459 +
117.1460 +
117.1461 +/* Convert single byte ASCII+8bit character set sized text to UTF-8
117.1462 + * Accepts: source sized text
117.1463 + *	    pointer to return sized text
117.1464 + *	    conversion table
117.1465 + *	    canonicalization function
117.1466 + */
117.1467 +
117.1468 +void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
117.1469 +		      ucs4de_t de)
117.1470 +{
117.1471 +  unsigned long i;
117.1472 +  unsigned char *s;
117.1473 +  unsigned int c;
117.1474 +  unsigned short *tbl = (unsigned short *) tab;
117.1475 +  for (ret->size = i = 0; i < text->size;) {
117.1476 +    if ((c = text->data[i++]) & BIT8) c = tbl[c & BITS7];
117.1477 +    UTF8_COUNT_BMP (ret->size,c,cv,de)
117.1478 +  }
117.1479 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
117.1480 +  for (i = 0; i < text->size;) {
117.1481 +    if ((c = text->data[i++]) & BIT8) c = tbl[c & BITS7];
117.1482 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.1483 +  }
117.1484 +}
117.1485 +
117.1486 +/* Convert single byte 8bit character set sized text to UTF-8
117.1487 + * Accepts: source sized text
117.1488 + *	    pointer to return sized text
117.1489 + *	    conversion table
117.1490 + *	    canonicalization function
117.1491 + */
117.1492 +
117.1493 +void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
117.1494 +		       ucs4de_t de)
117.1495 +{
117.1496 +  unsigned long i;
117.1497 +  unsigned char *s;
117.1498 +  unsigned int c;
117.1499 +  unsigned short *tbl = (unsigned short *) tab;
117.1500 +  for (ret->size = i = 0; i < text->size;) {
117.1501 +    c = tbl[text->data[i++]];
117.1502 +    UTF8_COUNT_BMP (ret->size,c,cv,de)
117.1503 +  }
117.1504 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
117.1505 +  for (i = 0; i < text->size;) {
117.1506 +    c = tbl[text->data[i++]];
117.1507 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.1508 +  }
117.1509 +}
117.1510 +
117.1511 +/* Convert EUC sized text to UTF-8
117.1512 + * Accepts: source sized text
117.1513 + *	    pointer to return sized text
117.1514 + *	    EUC parameter table
117.1515 + *	    canonicalization function
117.1516 + */
117.1517 +
117.1518 +void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
117.1519 +		    ucs4de_t de)
117.1520 +{
117.1521 +  unsigned long i;
117.1522 +  unsigned char *s;
117.1523 +  unsigned int pass,c,c1,ku,ten;
117.1524 +  struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab;
117.1525 +  struct utf8_eucparam *p2 = p1 + 1;
117.1526 +  struct utf8_eucparam *p3 = p1 + 2;
117.1527 +  unsigned short *t1 = (unsigned short *) p1->tab;
117.1528 +  unsigned short *t2 = (unsigned short *) p2->tab;
117.1529 +  unsigned short *t3 = (unsigned short *) p3->tab;
117.1530 +  for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) {
117.1531 +    for (i = 0; i < text->size;) {
117.1532 +				/* not CS0? */
117.1533 +      if ((c = text->data[i++]) & BIT8) {
117.1534 +				/* yes, must have another high byte */
117.1535 +	if ((i >= text->size) || !((c1 = text->data[i++]) & BIT8))
117.1536 +	  c = UBOGON;		/* out of space or bogon */
117.1537 +	else switch (c) {	/* check 8bit code set */
117.1538 +	case EUC_CS2:		/* CS2 */
117.1539 +	  if (p2->base_ku) {	/* CS2 set up? */
117.1540 +	    if (p2->base_ten)	/* yes, multibyte? */
117.1541 +	      c = ((i < text->size) && ((c = text->data[i++]) & BIT8) &&
117.1542 +		   ((ku = (c1 & BITS7) - p2->base_ku) < p2->max_ku) &&
117.1543 +		   ((ten = (c & BITS7) - p2->base_ten) < p2->max_ten)) ?
117.1544 +		     t2[(ku*p2->max_ten) + ten] : UBOGON;
117.1545 +	    else c = ((c1 >= p2->base_ku) && (c1 < p2->max_ku)) ?
117.1546 +	      c1 + ((unsigned long) p2->tab) : UBOGON;
117.1547 +	  }	  
117.1548 +	  else {		/* CS2 not set up */
117.1549 +	    c = UBOGON;		/* swallow byte, say bogon */
117.1550 +	    if (i < text->size) i++;
117.1551 +	  }
117.1552 +	  break;
117.1553 +	case EUC_CS3:		/* CS3 */
117.1554 +	  if (p3->base_ku) {	/* CS3 set up? */
117.1555 +	    if (p3->base_ten)	/* yes, multibyte? */
117.1556 +	      c = ((i < text->size) && ((c = text->data[i++]) & BIT8) &&
117.1557 +		   ((ku = (c1 & BITS7) - p3->base_ku) < p3->max_ku) &&
117.1558 +		   ((ten = (c & BITS7) - p3->base_ten) < p3->max_ten)) ?
117.1559 +		     t3[(ku*p3->max_ten) + ten] : UBOGON;
117.1560 +	    else c = ((c1 >= p3->base_ku) && (c1 < p3->max_ku)) ?
117.1561 +	      c1 + ((unsigned long) p3->tab) : UBOGON;
117.1562 +	  }	  
117.1563 +	  else {		/* CS3 not set up */
117.1564 +	    c = UBOGON;		/* swallow byte, say bogon */
117.1565 +	    if (i < text->size) i++;
117.1566 +	  }
117.1567 +	  break;
117.1568 +
117.1569 +	default:
117.1570 +	  if (((ku = (c & BITS7) - p1->base_ku) >= p1->max_ku) ||
117.1571 +	      ((ten = (c1 & BITS7) - p1->base_ten) >= p1->max_ten)) c = UBOGON;
117.1572 +	  else if (((c = t1[(ku*p1->max_ten) + ten]) == UBOGON) &&
117.1573 +		   /* special hack for JIS X 0212: merge rows less than 10 */
117.1574 +		   ku && (ku < 10) && t3 && p3->base_ten)
117.1575 +	    c = t3[((ku - (p3->base_ku - p1->base_ku))*p3->max_ten) + ten];
117.1576 +	}
117.1577 +      }
117.1578 +				/* convert if second pass */
117.1579 +      if (pass) UTF8_WRITE_BMP (s,c,cv,de)
117.1580 +      else UTF8_COUNT_BMP (ret->size,c,cv,de);
117.1581 +    }
117.1582 +    if (!pass) (s = ret->data = (unsigned char *)
117.1583 +		fs_get (ret->size + 1))[ret->size] =NIL;
117.1584 +  }
117.1585 +}
117.1586 +
117.1587 +
117.1588 +/* Convert ASCII + double-byte sized text to UTF-8
117.1589 + * Accepts: source sized text
117.1590 + *	    pointer to return sized text
117.1591 + *	    conversion table
117.1592 + *	    canonicalization function
117.1593 + */
117.1594 +
117.1595 +void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
117.1596 +		      ucs4de_t de)
117.1597 +{
117.1598 +  unsigned long i;
117.1599 +  unsigned char *s;
117.1600 +  unsigned int c,c1,ku,ten;
117.1601 +  struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab;
117.1602 +  unsigned short *t1 = (unsigned short *) p1->tab;
117.1603 +  for (ret->size = i = 0; i < text->size;) {
117.1604 +    if ((c = text->data[i++]) & BIT8) {
117.1605 +				/* special hack for GBK: 0x80 is Euro */
117.1606 +      if ((c == 0x80) && (t1 == (unsigned short *) gb2312tab)) c = UCS2_EURO;
117.1607 +      else c = ((i < text->size) && (c1 = text->data[i++]) &&
117.1608 +		((ku = c - p1->base_ku) < p1->max_ku) &&
117.1609 +		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
117.1610 +	     t1[(ku*p1->max_ten) + ten] : UBOGON;
117.1611 +    }
117.1612 +    UTF8_COUNT_BMP (ret->size,c,cv,de)
117.1613 +  }
117.1614 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
117.1615 +  for (i = 0; i < text->size;) {
117.1616 +    if ((c = text->data[i++]) & BIT8) {
117.1617 +				/* special hack for GBK: 0x80 is Euro */
117.1618 +      if ((c == 0x80) && (t1 == (unsigned short *) gb2312tab)) c = UCS2_EURO;
117.1619 +      else c = ((i < text->size) && (c1 = text->data[i++]) &&
117.1620 +		((ku = c - p1->base_ku) < p1->max_ku) &&
117.1621 +		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
117.1622 +	     t1[(ku*p1->max_ten) + ten] : UBOGON;
117.1623 +    }
117.1624 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.1625 +  }
117.1626 +}
117.1627 +
117.1628 +/* Convert ASCII + double byte 2 plane sized text to UTF-8
117.1629 + * Accepts: source sized text
117.1630 + *	    pointer to return sized text
117.1631 + *	    conversion table
117.1632 + *	    canonicalization function
117.1633 + */
117.1634 +
117.1635 +void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
117.1636 +		       ucs4de_t de)
117.1637 +{
117.1638 +  unsigned long i;
117.1639 +  unsigned char *s;
117.1640 +  unsigned int c,c1,ku,ten;
117.1641 +  struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab;
117.1642 +  struct utf8_eucparam *p2 = p1 + 1;
117.1643 +  unsigned short *t = (unsigned short *) p1->tab;
117.1644 +  for (ret->size = i = 0; i < text->size;) {
117.1645 +    if ((c = text->data[i++]) & BIT8) {
117.1646 +      if ((i >= text->size) || !(c1 = text->data[i++]))
117.1647 +	c = UBOGON;		/* out of space or bogon */
117.1648 +      else if (c1 & BIT8)	/* high vs. low plane */
117.1649 +	c = ((ku = c - p2->base_ku) < p2->max_ku &&
117.1650 +	     ((ten = c1 - p2->base_ten) < p2->max_ten)) ?
117.1651 +	       t[(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten] :UBOGON;
117.1652 +      else c = ((ku = c - p1->base_ku) < p1->max_ku &&
117.1653 +		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
117.1654 +		  t[(ku*(p1->max_ten + p2->max_ten)) + ten] : UBOGON;
117.1655 +    }
117.1656 +    UTF8_COUNT_BMP (ret->size,c,cv,de)
117.1657 +  }
117.1658 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
117.1659 +  for (i = 0; i < text->size;) {
117.1660 +    if ((c = text->data[i++]) & BIT8) {
117.1661 +      if ((i >= text->size) || !(c1 = text->data[i++]))
117.1662 +	c = UBOGON;		/* out of space or bogon */
117.1663 +      else if (c1 & BIT8)	/* high vs. low plane */
117.1664 +	c = ((ku = c - p2->base_ku) < p2->max_ku &&
117.1665 +	     ((ten = c1 - p2->base_ten) < p2->max_ten)) ?
117.1666 +	       t[(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten] :UBOGON;
117.1667 +      else c = ((ku = c - p1->base_ku) < p1->max_ku &&
117.1668 +		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
117.1669 +		  t[(ku*(p1->max_ten + p2->max_ten)) + ten] : UBOGON;
117.1670 +    }
117.1671 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.1672 +  }
117.1673 +}
117.1674 +
117.1675 +#ifdef JISTOUNICODE		/* Japanese */
117.1676 +/* Convert Shift JIS sized text to UTF-8
117.1677 + * Accepts: source sized text
117.1678 + *	    pointer to return sized text
117.1679 + *	    canonicalization function
117.1680 + */
117.1681 +
117.1682 +void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,
117.1683 +		     ucs4de_t de)
117.1684 +{
117.1685 +  unsigned long i;
117.1686 +  unsigned char *s;
117.1687 +  unsigned int c,c1,ku,ten;
117.1688 +  for (ret->size = i = 0; i < text->size;) {
117.1689 +    if ((c = text->data[i++]) & BIT8) {
117.1690 +				/* half-width katakana */
117.1691 +      if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) c += KANA_8;
117.1692 +      else if (i >= text->size) c = UBOGON;
117.1693 +      else {			/* Shift-JIS */
117.1694 +	c1 = text->data[i++];
117.1695 +	SJISTOJIS (c,c1);
117.1696 +	c = JISTOUNICODE (c,c1,ku,ten);
117.1697 +      }
117.1698 +    }
117.1699 +				/* compromise - do yen sign but not overline */
117.1700 +    else if (c == JISROMAN_YEN) c = UCS2_YEN;
117.1701 +    UTF8_COUNT_BMP (ret->size,c,cv,de)
117.1702 +  }
117.1703 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
117.1704 +  for (i = 0; i < text->size;) {
117.1705 +    if ((c = text->data[i++]) & BIT8) {
117.1706 +				/* half-width katakana */
117.1707 +      if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) c += KANA_8;
117.1708 +      else {			/* Shift-JIS */
117.1709 +	c1 = text->data[i++];
117.1710 +	SJISTOJIS (c,c1);
117.1711 +	c = JISTOUNICODE (c,c1,ku,ten);
117.1712 +      }
117.1713 +    }
117.1714 +				/* compromise - do yen sign but not overline */
117.1715 +    else if (c == JISROMAN_YEN) c = UCS2_YEN;
117.1716 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.1717 +  }
117.1718 +}
117.1719 +#endif
117.1720 +
117.1721 +/* Convert ISO-2022 sized text to UTF-8
117.1722 + * Accepts: source sized text
117.1723 + *	    pointer to returned sized text
117.1724 + *	    canonicalization function
117.1725 + */
117.1726 +
117.1727 +void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.1728 +{
117.1729 +  unsigned long i;
117.1730 +  unsigned char *s;
117.1731 +  unsigned int pass,state,c,co,gi,gl,gr,g[4],ku,ten;
117.1732 +  for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) {
117.1733 +    gi = 0;			/* quell compiler warnings */
117.1734 +    state = I2S_CHAR;		/* initialize engine */
117.1735 +    g[0]= g[2] = I2CS_ASCII;	/* G0 and G2 are ASCII */
117.1736 +    g[1]= g[3] = I2CS_ISO8859_1;/* G1 and G3 are ISO-8850-1 */
117.1737 +    gl = I2C_G0; gr = I2C_G1;	/* left is G0, right is G1 */
117.1738 +    for (i = 0; i < text->size;) {
117.1739 +      c = text->data[i++];
117.1740 +      switch (state) {		/* dispatch based upon engine state */
117.1741 +      case I2S_ESC:		/* ESC seen */
117.1742 +	switch (c) {		/* process intermediate character */
117.1743 +	case I2C_MULTI:		/* multibyte character? */
117.1744 +	  state = I2S_MUL;	/* mark multibyte flag seen */
117.1745 +	  break;
117.1746 +        case I2C_SS2:		/* single shift GL to G2 */
117.1747 +	case I2C_SS2_ALT:	/* Taiwan SeedNet */
117.1748 +	  gl |= I2C_SG2;
117.1749 +	  break;
117.1750 +        case I2C_SS3:		/* single shift GL to G3 */
117.1751 +	case I2C_SS3_ALT:	/* Taiwan SeedNet */
117.1752 +	  gl |= I2C_SG3;
117.1753 +	  break;
117.1754 +        case I2C_LS2:		/* shift GL to G2 */
117.1755 +	  gl = I2C_G2;
117.1756 +	  break;
117.1757 +        case I2C_LS3:		/* shift GL to G3 */
117.1758 +	  gl = I2C_G3;
117.1759 +	  break;
117.1760 +        case I2C_LS1R:		/* shift GR to G1 */
117.1761 +	  gr = I2C_G1;
117.1762 +	  break;
117.1763 +        case I2C_LS2R:		/* shift GR to G2 */
117.1764 +	  gr = I2C_G2;
117.1765 +	  break;
117.1766 +        case I2C_LS3R:		/* shift GR to G3 */
117.1767 +	  gr = I2C_G3;
117.1768 +	  break;
117.1769 +	case I2C_G0_94: case I2C_G1_94: case I2C_G2_94:	case I2C_G3_94:
117.1770 +	  g[gi = c - I2C_G0_94] = (state == I2S_MUL) ? I2CS_94x94 : I2CS_94;
117.1771 +	  state = I2S_INT;	/* ready for character set */
117.1772 +	  break;
117.1773 +	case I2C_G0_96:	case I2C_G1_96: case I2C_G2_96:	case I2C_G3_96:
117.1774 +	  g[gi = c - I2C_G0_96] = (state == I2S_MUL) ? I2CS_96x96 : I2CS_96;
117.1775 +	  state = I2S_INT;	/* ready for character set */
117.1776 +	  break;
117.1777 +	default:		/* bogon */
117.1778 +	  if (pass) *s++ = I2C_ESC,*s++ = c;
117.1779 +	  else ret->size += 2;
117.1780 +	  state = I2S_CHAR;	/* return to previous state */
117.1781 +	}
117.1782 +	break;
117.1783 +
117.1784 +      case I2S_MUL:		/* ESC $ */
117.1785 +	switch (c) {		/* process multibyte intermediate character */
117.1786 +	case I2C_G0_94: case I2C_G1_94: case I2C_G2_94:	case I2C_G3_94:
117.1787 +	  g[gi = c - I2C_G0_94] = I2CS_94x94;
117.1788 +	  state = I2S_INT;	/* ready for character set */
117.1789 +	  break;
117.1790 +	case I2C_G0_96:	case I2C_G1_96: case I2C_G2_96:	case I2C_G3_96:
117.1791 +	  g[gi = c - I2C_G0_96] = I2CS_96x96;
117.1792 +	  state = I2S_INT;	/* ready for character set */
117.1793 +	  break;
117.1794 +	default:		/* probably omitted I2CS_94x94 */
117.1795 +	  g[gi = I2C_G0] = I2CS_94x94 | c;
117.1796 +	  state = I2S_CHAR;	/* return to character state */
117.1797 +	}
117.1798 +	break;
117.1799 +      case I2S_INT:
117.1800 +	state = I2S_CHAR;	/* return to character state */
117.1801 +	g[gi] |= c;		/* set character set */
117.1802 +	break;
117.1803 +
117.1804 +      case I2S_CHAR:		/* character data */
117.1805 +	switch (c) {
117.1806 +	case I2C_ESC:		/* ESC character */
117.1807 +	  state = I2S_ESC;	/* see if ISO-2022 prefix */
117.1808 +	  break;
117.1809 +	case I2C_SI:		/* shift GL to G0 */
117.1810 +	  gl = I2C_G0;
117.1811 +	  break;
117.1812 +	case I2C_SO:		/* shift GL to G1 */
117.1813 +	  gl = I2C_G1;
117.1814 +	  break;
117.1815 +        case I2C_SS2_ALT:	/* single shift GL to G2 */
117.1816 +	case I2C_SS2_ALT_7:
117.1817 +	  gl |= I2C_SG2;
117.1818 +	  break;
117.1819 +        case I2C_SS3_ALT:	/* single shift GL to G3 */
117.1820 +	case I2C_SS3_ALT_7:
117.1821 +	  gl |= I2C_SG3;
117.1822 +	  break;
117.1823 +
117.1824 +	default:		/* ordinary character */
117.1825 +	  co = c;		/* note original character */
117.1826 +	  if (gl & (3 << 2)) {	/* single shifted? */
117.1827 +	    gi = g[gl >> 2];	/* get shifted character set */
117.1828 +	    gl &= 0x3;		/* cancel shift */
117.1829 +	  }
117.1830 +				/* select left or right half */
117.1831 +	  else gi = (c & BIT8) ? g[gr] : g[gl];
117.1832 +	  c &= BITS7;		/* make 7-bit */
117.1833 +	  switch (gi) {		/* interpret in character set */
117.1834 +	  case I2CS_ASCII:	/* ASCII */
117.1835 +	    break;		/* easy! */
117.1836 +	  case I2CS_BRITISH:	/* British ASCII */
117.1837 +				/* Pound sterling sign */
117.1838 +	    if (c == BRITISH_POUNDSTERLING) c = UCS2_POUNDSTERLING;
117.1839 +	    break;
117.1840 +	  case I2CS_JIS_ROMAN:	/* JIS Roman */
117.1841 +	  case I2CS_JIS_BUGROM:	/* old bugs */
117.1842 +	    switch (c) {	/* two exceptions to ASCII */
117.1843 +	    case JISROMAN_YEN:	/* Yen sign */
117.1844 +	      c = UCS2_YEN;
117.1845 +	      break;
117.1846 +				/* overline */
117.1847 +	    case JISROMAN_OVERLINE:
117.1848 +	      c = UCS2_OVERLINE;
117.1849 +	      break;
117.1850 +	    }
117.1851 +	    break;
117.1852 +	  case I2CS_JIS_KANA:	/* JIS hankaku katakana */
117.1853 +	    if ((c >= MIN_KANA_7) && (c < MAX_KANA_7)) c += KANA_7;
117.1854 +	    break;
117.1855 +
117.1856 +	  case I2CS_ISO8859_1:	/* Latin-1 (West European) */
117.1857 +	    c |= BIT8;		/* just turn on high bit */
117.1858 +	    break;
117.1859 +	  case I2CS_ISO8859_2:	/* Latin-2 (Czech, Slovak) */
117.1860 +	    c = iso8859_2tab[c];
117.1861 +	    break;
117.1862 +	  case I2CS_ISO8859_3:	/* Latin-3 (Dutch, Turkish) */
117.1863 +	    c = iso8859_3tab[c];
117.1864 +	    break;
117.1865 +	  case I2CS_ISO8859_4:	/* Latin-4 (Scandinavian) */
117.1866 +	    c = iso8859_4tab[c];
117.1867 +	    break;
117.1868 +	  case I2CS_ISO8859_5:	/* Cyrillic */
117.1869 +	    c = iso8859_5tab[c];
117.1870 +	    break;
117.1871 +	  case I2CS_ISO8859_6:	/* Arabic */
117.1872 +	    c = iso8859_6tab[c];
117.1873 +	    break;
117.1874 +	  case I2CS_ISO8859_7:	/* Greek */
117.1875 +	    c = iso8859_7tab[c];
117.1876 +	    break;
117.1877 +	  case I2CS_ISO8859_8:	/* Hebrew */
117.1878 +	    c = iso8859_8tab[c];
117.1879 +	    break;
117.1880 +	  case I2CS_ISO8859_9:	/* Latin-5 (Finnish, Portuguese) */
117.1881 +	    c = iso8859_9tab[c];
117.1882 +	    break;
117.1883 +	  case I2CS_TIS620:	/* Thai */
117.1884 +	    c = tis620tab[c];
117.1885 +	    break;
117.1886 +	  case I2CS_ISO8859_10:	/* Latin-6 (Northern Europe) */
117.1887 +	    c = iso8859_10tab[c];
117.1888 +	    break;
117.1889 +	  case I2CS_ISO8859_13:	/* Latin-7 (Baltic) */
117.1890 +	    c = iso8859_13tab[c];
117.1891 +	    break;
117.1892 +	  case I2CS_VSCII:	/* Vietnamese */
117.1893 +	    c = visciitab[c];
117.1894 +	    break;
117.1895 +	  case I2CS_ISO8859_14:	/* Latin-8 (Celtic) */
117.1896 +	    c = iso8859_14tab[c];
117.1897 +	    break;
117.1898 +	  case I2CS_ISO8859_15:	/* Latin-9 (Euro) */
117.1899 +	    c = iso8859_15tab[c];
117.1900 +	    break;
117.1901 +	  case I2CS_ISO8859_16:	/* Latin-10 (Baltic) */
117.1902 +	    c = iso8859_16tab[c];
117.1903 +	    break;
117.1904 +
117.1905 +	  default:		/* all other character sets */
117.1906 +				/* multibyte character set */
117.1907 +	    if ((gi & I2CS_MUL) && !(c & BIT8) && isgraph (c)) {
117.1908 +	      c = (i < text->size) ? text->data[i++] : 0;
117.1909 +	      switch (gi) {
117.1910 +#ifdef GBTOUNICODE
117.1911 +	      case I2CS_GB:	/* GB 2312 */
117.1912 +		co |= BIT8;	/* make into EUC */
117.1913 +		c |= BIT8;
117.1914 +		c = GBTOUNICODE (co,c,ku,ten);
117.1915 +		break;
117.1916 +#endif
117.1917 +#ifdef JISTOUNICODE
117.1918 +	      case I2CS_JIS_OLD:/* JIS X 0208-1978 */
117.1919 +	      case I2CS_JIS_NEW:/* JIS X 0208-1983 */
117.1920 +		c = JISTOUNICODE (co,c,ku,ten);
117.1921 +		break;
117.1922 +#endif
117.1923 +#ifdef JIS0212TOUNICODE
117.1924 +	      case I2CS_JIS_EXT:/* JIS X 0212-1990 */
117.1925 +		c = JIS0212TOUNICODE (co,c,ku,ten);
117.1926 +		break;
117.1927 +#endif
117.1928 +#ifdef KSCTOUNICODE
117.1929 +	      case I2CS_KSC:	/* KSC 5601 */
117.1930 +		co |= BIT8;	/* make into EUC */
117.1931 +		c |= BIT8;
117.1932 +		c = KSCTOUNICODE (co,c,ku,ten);
117.1933 +		break;
117.1934 +#endif
117.1935 +#ifdef CNS1TOUNICODE
117.1936 +	      case I2CS_CNS1:	/* CNS 11643 plane 1 */
117.1937 +		c = CNS1TOUNICODE (co,c,ku,ten);
117.1938 +		break;
117.1939 +#endif
117.1940 +#ifdef CNS2TOUNICODE
117.1941 +	      case I2CS_CNS2:	/* CNS 11643 plane 2 */
117.1942 +		c = CNS2TOUNICODE (co,c,ku,ten);
117.1943 +		break;
117.1944 +#endif
117.1945 +#ifdef CNS3TOUNICODE
117.1946 +	      case I2CS_CNS3:	/* CNS 11643 plane 3 */
117.1947 +		c = CNS3TOUNICODE (co,c,ku,ten);
117.1948 +		break;
117.1949 +#endif
117.1950 +#ifdef CNS4TOUNICODE
117.1951 +	      case I2CS_CNS4:	/* CNS 11643 plane 4 */
117.1952 +		c = CNS4TOUNICODE (co,c,ku,ten);
117.1953 +		break;
117.1954 +#endif
117.1955 +#ifdef CNS5TOUNICODE
117.1956 +	      case I2CS_CNS5:	/* CNS 11643 plane 5 */
117.1957 +		c = CNS5TOUNICODE (co,c,ku,ten);
117.1958 +		break;
117.1959 +#endif
117.1960 +#ifdef CNS6TOUNICODE
117.1961 +	      case I2CS_CNS6:	/* CNS 11643 plane 6 */
117.1962 +		c = CNS6TOUNICODE (co,c,ku,ten);
117.1963 +		break;
117.1964 +#endif
117.1965 +#ifdef CNS7TOUNICODE
117.1966 +	      case I2CS_CNS7:	/* CNS 11643 plane 7 */
117.1967 +		c = CNS7TOUNICODE (co,c,ku,ten);
117.1968 +		break;
117.1969 +#endif
117.1970 +	      default:		/* unknown multibyte, treat as UCS-2 */
117.1971 +		c |= (co << 8);	/* wrong, but nothing else to do */
117.1972 +		break;
117.1973 +	      }
117.1974 +	    }
117.1975 +	    else c = co;	/* unknown single byte, treat as 8859-1 */
117.1976 +	  }
117.1977 +				/* convert if second pass */
117.1978 +	  if (pass) UTF8_WRITE_BMP (s,c,cv,de)
117.1979 +	  else UTF8_COUNT_BMP (ret->size,c,cv,de);
117.1980 +	}
117.1981 +      }
117.1982 +    }
117.1983 +    if (!pass) (s = ret->data = (unsigned char *)
117.1984 +		fs_get (ret->size + 1))[ret->size] = NIL;
117.1985 +    else if (((unsigned long) (s - ret->data)) != ret->size)
117.1986 +      fatal ("ISO-2022 to UTF-8 botch");
117.1987 +  }
117.1988 +}
117.1989 +
117.1990 +/* Convert UTF-7 sized text to UTF-8
117.1991 + * Accepts: source sized text
117.1992 + *	    pointer to returned sized text
117.1993 + *	    canonicalization function
117.1994 + */
117.1995 +
117.1996 +void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.1997 +{
117.1998 +  unsigned long i;
117.1999 +  unsigned char *s;
117.2000 +  unsigned int c,c1,d,uc,pass,e,e1,state,surrh;
117.2001 +  for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) {
117.2002 +    c1 = d = uc = e = e1 = 0;
117.2003 +    for (i = 0,state = NIL; i < text->size;) {
117.2004 +      c = text->data[i++];	/* get next byte */
117.2005 +      switch (state) {
117.2006 +      case U7_PLUS:		/* previous character was + */
117.2007 +	if (c == '-') {		/* +- means textual + */
117.2008 +	  c = '+';
117.2009 +	  state = U7_ASCII;	/* revert to ASCII */
117.2010 +	  break;
117.2011 +	}
117.2012 +	state = U7_UNICODE;	/* enter Unicode state */
117.2013 +	e = e1 = 0;		/* initialize Unicode quantum position */
117.2014 +      case U7_UNICODE:		/* Unicode state */
117.2015 +	if (c == '-') state = U7_MINUS;
117.2016 +	else {			/* decode Unicode */
117.2017 +	  /* don't use isupper/islower since this is ASCII only */
117.2018 +	  if ((c >= 'A') && (c <= 'Z')) c -= 'A';
117.2019 +	  else if ((c >= 'a') && (c <= 'z')) c -= 'a' - 26;
117.2020 +	  else if (isdigit (c)) c -= '0' - 52;
117.2021 +	  else if (c == '+') c = 62;
117.2022 +	  else if (c == '/') c = 63;
117.2023 +	  else state = U7_ASCII;/* end of modified BASE64 */
117.2024 +	}
117.2025 +	break;
117.2026 +      case U7_MINUS:		/* previous character was absorbed - */
117.2027 +	state = U7_ASCII;	/* revert to ASCII */
117.2028 +      case U7_ASCII:		/* ASCII state */
117.2029 +	if (c == '+') state = U7_PLUS;
117.2030 +	break;
117.2031 +      }
117.2032 +
117.2033 +      switch (state) {		/* store character if in character mode */
117.2034 +      case U7_UNICODE:		/* Unicode */
117.2035 +	switch (e++) {		/* install based on BASE64 state */
117.2036 +	case 0:
117.2037 +	  c1 = c << 2;		/* byte 1: high 6 bits */
117.2038 +	  break;
117.2039 +	case 1:
117.2040 +	  d = c1 | (c >> 4);	/* byte 1: low 2 bits */
117.2041 +	  c1 = c << 4;		/* byte 2: high 4 bits */
117.2042 +	  break;
117.2043 +	case 2:
117.2044 +	  d = c1 | (c >> 2);	/* byte 2: low 4 bits */
117.2045 +	  c1 = c << 6;		/* byte 3: high 2 bits */
117.2046 +	  break;
117.2047 +	case 3:
117.2048 +	  d = c | c1;		/* byte 3: low 6 bits */
117.2049 +	  e = 0;		/* reinitialize mechanism */
117.2050 +	  break;
117.2051 +	}
117.2052 +	if (e == 1) break;	/* done if first BASE64 state */
117.2053 +	if (!e1) {		/* first byte of UCS-2 character */
117.2054 +	  uc = (d & 0xff) << 8;	/* note first byte */
117.2055 +	  e1 = T;		/* enter second UCS-2 state */
117.2056 +	  break;		/* done */
117.2057 +	}
117.2058 +	c = uc | (d & 0xff);	/* build UCS-2 character */
117.2059 +	e1 = NIL;		/* back to first UCS-2 state, drop in */
117.2060 +				/* surrogate pair?  */
117.2061 +	if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) {
117.2062 +				/* save high surrogate for later */
117.2063 +	  if (c < UTF16_SURRL) surrh = c;
117.2064 +	  else c = UTF16_BASE + ((surrh & UTF16_MASK) << UTF16_SHIFT) +
117.2065 +		 (c & UTF16_MASK);
117.2066 +	  break;		/* either way with surrogates, we're done */
117.2067 +	}
117.2068 +      case U7_ASCII:		/* just install if ASCII */
117.2069 +				/* convert if second pass */
117.2070 +	if (pass) UTF8_WRITE_BMP (s,c,cv,de)
117.2071 +	else UTF8_COUNT_BMP (ret->size,c,cv,de);
117.2072 +      }
117.2073 +    }
117.2074 +    if (!pass) (s = ret->data = (unsigned char *)
117.2075 +		fs_get (ret->size + 1))[ret->size] = NIL;
117.2076 +    else if (((unsigned long) (s - ret->data)) != ret->size)
117.2077 +      fatal ("UTF-7 to UTF-8 botch");
117.2078 +  }
117.2079 +}
117.2080 +
117.2081 +
117.2082 +/* Convert UTF-8 sized text to UTF-8
117.2083 + * Accepts: source sized text
117.2084 + *	    pointer to returned sized text
117.2085 + *	    canonicalization function
117.2086 + */
117.2087 +
117.2088 +void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.2089 +{
117.2090 +  unsigned long i,c;
117.2091 +  unsigned char *s,*t;
117.2092 +  for (ret->size = 0, t = text->data, i = text->size; i;) {
117.2093 +    if ((c = utf8_get (&t,&i)) & U8G_ERROR) {
117.2094 +      ret->data = text->data;	/* conversion failed */
117.2095 +      ret->size = text->size;
117.2096 +      return;
117.2097 +    }
117.2098 +    UTF8_COUNT (ret->size,c,cv,de)
117.2099 +  }
117.2100 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
117.2101 +  for (t = text->data, i = text->size; i;) {
117.2102 +    c = utf8_get (&t,&i);
117.2103 +    UTF8_WRITE (s,c,cv,de)	/* convert UCS-4 to UTF-8 */
117.2104 +  }
117.2105 +  if (((unsigned long) (s - ret->data)) != ret->size)
117.2106 +    fatal ("UTF-8 to UTF-8 botch");
117.2107 +}
117.2108 +
117.2109 +/* Convert UCS-2 sized text to UTF-8
117.2110 + * Accepts: source sized text
117.2111 + *	    pointer to returned sized text
117.2112 + *	    canonicalization function
117.2113 + */
117.2114 +
117.2115 +void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.2116 +{
117.2117 +  unsigned long i;
117.2118 +  unsigned char *s,*t;
117.2119 +  unsigned int c;
117.2120 +  for (ret->size = 0, t = text->data, i = text->size / 2; i; --i) {
117.2121 +    c = *t++ << 8;
117.2122 +    c |= *t++;
117.2123 +    UTF8_COUNT_BMP (ret->size,c,cv,de);
117.2124 +  }
117.2125 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
117.2126 +  for (t = text->data, i = text->size / 2; i; --i) {
117.2127 +    c = *t++ << 8;
117.2128 +    c |= *t++;
117.2129 +    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
117.2130 +  }
117.2131 +  if (((unsigned long) (s - ret->data)) != ret->size)
117.2132 +    fatal ("UCS-2 to UTF-8 botch");
117.2133 +}
117.2134 +
117.2135 +
117.2136 +/* Convert UCS-4 sized text to UTF-8
117.2137 + * Accepts: source sized text
117.2138 + *	    pointer to returned sized text
117.2139 + *	    canonicalization function
117.2140 + */
117.2141 +
117.2142 +void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.2143 +{
117.2144 +  unsigned long i;
117.2145 +  unsigned char *s,*t;
117.2146 +  unsigned long c;
117.2147 +  for (ret->size = 0, t = text->data, i = text->size / 4; i; --i) {
117.2148 +    c = *t++ << 24; c |= *t++ << 16; c |= *t++ << 8; c |= *t++;
117.2149 +    UTF8_COUNT (ret->size,c,cv,de);
117.2150 +  }
117.2151 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
117.2152 +  for (t = text->data, i = text->size / 2; i; --i) {
117.2153 +    c = *t++ << 24; c |= *t++ << 16; c |= *t++ << 8; c |= *t++;
117.2154 +    UTF8_WRITE (s,c,cv,de)	/* convert UCS-4 to UTF-8 */
117.2155 +  }
117.2156 +  if (((unsigned long) (s - ret->data)) != ret->size)
117.2157 +    fatal ("UCS-4 to UTF-8 botch");
117.2158 +}
117.2159 +
117.2160 +/* Convert UTF-16 sized text to UTF-8
117.2161 + * Accepts: source sized text
117.2162 + *	    pointer to returned sized text
117.2163 + *	    canonicalization function
117.2164 + */
117.2165 +
117.2166 +void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
117.2167 +{
117.2168 +  unsigned long i;
117.2169 +  unsigned char *s,*t;
117.2170 +  unsigned long c,d;
117.2171 +  for (ret->size = 0, t = text->data, i = text->size / 2; i; --i) {
117.2172 +    c = *t++ << 8;
117.2173 +    c |= *t++;
117.2174 +				/* possible surrogate? */
117.2175 +    if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) {
117.2176 +				/* invalid first surrogate */
117.2177 +      if ((c > UTF16_SURRHEND) || !i) c = UBOGON;
117.2178 +      else {			/* get second surrogate */
117.2179 +	d = *t++ << 8;
117.2180 +	d |= *t++;
117.2181 +	--i;			/* swallowed another 16-bits */
117.2182 +				/* invalid second surrogate */
117.2183 +	if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) c = UBOGON;
117.2184 +	else c = UTF16_BASE + ((c & UTF16_MASK) << UTF16_SHIFT) +
117.2185 +	       (d & UTF16_MASK);
117.2186 +      }
117.2187 +    }
117.2188 +    UTF8_COUNT (ret->size,c,cv,de);
117.2189 +  }
117.2190 +  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
117.2191 +  for (t = text->data, i = text->size / 2; i; --i) {
117.2192 +    c = *t++ << 8;
117.2193 +    c |= *t++;
117.2194 +				/* possible surrogate? */
117.2195 +    if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) {
117.2196 +				/* invalid first surrogate */
117.2197 +      if ((c > UTF16_SURRHEND) || !i) c = UBOGON;
117.2198 +      else {			/* get second surrogate */
117.2199 +	d = *t++ << 8;
117.2200 +	d |= *t++;
117.2201 +	--i;			/* swallowed another 16-bits */
117.2202 +				/* invalid second surrogate */
117.2203 +	if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) c = UBOGON;
117.2204 +	else c = UTF16_BASE + ((c & UTF16_MASK) << UTF16_SHIFT) +
117.2205 +	       (d & UTF16_MASK);
117.2206 +      }
117.2207 +    }
117.2208 +    UTF8_WRITE (s,c,cv,de)	/* convert UCS-4 to UTF-8 */
117.2209 +  }
117.2210 +  if (((unsigned long) (s - ret->data)) != ret->size)
117.2211 +    fatal ("UTF-16 to UTF-8 botch");
117.2212 +}
117.2213 +
117.2214 +/* Size of UCS-4 character, possibly not in BMP, as UTF-8 octets
117.2215 + * Accepts: character
117.2216 + * Returns: size (0 means bogon)
117.2217 + *
117.2218 + * Use UTF8_SIZE macro if known to be in the BMP
117.2219 + */
117.2220 +
117.2221 +unsigned long utf8_size (unsigned long c)
117.2222 +{
117.2223 +  if (c < 0x80) return 1;
117.2224 +  else if (c < 0x800) return 2;
117.2225 +  else if (c < 0x10000) return 3;
117.2226 +  else if (c < 0x200000) return 4;
117.2227 +  else if (c < 0x4000000) return 5;
117.2228 +  else if (c < 0x80000000) return 6;
117.2229 +  return 0;
117.2230 +}
117.2231 +
117.2232 +
117.2233 +/* Put UCS-4 character, possibly not in BMP, as UTF-8 octets
117.2234 + * Accepts: destination string pointer
117.2235 + *	    character
117.2236 + * Returns: updated destination pointer
117.2237 + *
117.2238 + * Use UTF8_PUT_BMP macro if known to be in the BMP
117.2239 + */
117.2240 +
117.2241 +unsigned char *utf8_put (unsigned char *s,unsigned long c)
117.2242 +{
117.2243 +  unsigned char mark[6] = {0x00,0xc0,0xe0,0xf0,0xf8,0xfc};
117.2244 +  unsigned long size = utf8_size (c);
117.2245 +  switch (size) {
117.2246 +  case 6:
117.2247 +    s[5] = 0x80 | (unsigned char) (c & 0x3f);
117.2248 +    c >>= 6;
117.2249 +  case 5:
117.2250 +    s[4] = 0x80 | (unsigned char) (c & 0x3f);
117.2251 +    c >>= 6;
117.2252 +  case 4:
117.2253 +    s[3] = 0x80 | (unsigned char) (c & 0x3f);
117.2254 +    c >>= 6;
117.2255 +  case 3:
117.2256 +    s[2] = 0x80 | (unsigned char) (c & 0x3f);
117.2257 +    c >>= 6;
117.2258 +  case 2:
117.2259 +    s[1] = 0x80 | (unsigned char) (c & 0x3f);
117.2260 +    c >>= 6;
117.2261 +  case 1:
117.2262 +    *s = mark[size-1] | (unsigned char) (c & 0x7f);
117.2263 +    break;
117.2264 +  }
117.2265 +  return s + size;
117.2266 +}
117.2267 +
117.2268 +/* Return title case of a fixed-width UCS-4 character
117.2269 + * Accepts: character
117.2270 + * Returns: title case of character
117.2271 + */
117.2272 +
117.2273 +unsigned long ucs4_titlecase (unsigned long c)
117.2274 +{
117.2275 +  if (c <= UCS4_TMAPMAX) return ucs4_tmaptab[c];
117.2276 +  if (c < UCS4_TMAPHIMIN) return c;
117.2277 +  if (c <= UCS4_TMAPHIMAX) return c - UCS4_TMAPHIMAP;
117.2278 +  if (c < UCS4_TMAPDESERETMIN) return c;
117.2279 +  if (c <= UCS4_TMAPDESERETMAX) return c - UCS4_TMAPDESERETMAP;
117.2280 +  return c;
117.2281 +}
117.2282 +
117.2283 +
117.2284 +/* Return width of a fixed-width UCS-4 character in planes 0-2
117.2285 + * Accepts: character
117.2286 + * Returns: width (0, 1, 2) or negative error condition if not valid
117.2287 + */
117.2288 +
117.2289 +long ucs4_width (unsigned long c)
117.2290 +{
117.2291 +  long ret;
117.2292 +				/* out of range, not-a-char, or surrogates */
117.2293 +  if ((c > UCS4_MAXUNICODE) || ((c & 0xfffe) == 0xfffe) ||
117.2294 +      ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR))) ret = U4W_NOTUNCD;
117.2295 +				/* private-use */
117.2296 +  else if (c >= UCS4_PVTBASE) ret = U4W_PRIVATE;
117.2297 +				/* SSP are not printing characters */
117.2298 +  else if (c >= UCS4_SSPBASE) ret = U4W_SSPCHAR;
117.2299 +				/* unassigned planes */
117.2300 +  else if (c >= UCS4_UNABASE) ret = U4W_UNASSGN;
117.2301 +				/* SIP and reserved plane 3 are wide */
117.2302 +  else if (c >= UCS4_SIPBASE) ret = 2;
117.2303 +#if (UCS4_WIDLEN != UCS4_SIPBASE)
117.2304 +#error "UCS4_WIDLEN != UCS4_SIPBASE"
117.2305 +#endif
117.2306 +				/* C0/C1 controls */
117.2307 +  else if ((c <= UCS2_C0CONTROLEND) ||
117.2308 +	   ((c >= UCS2_C1CONTROL) && (c <= UCS2_C1CONTROLEND)))
117.2309 +    ret = U4W_CONTROL;
117.2310 +				/* BMP and SMP get value from table */
117.2311 +  else switch (ret = (ucs4_widthtab[(c >> 2)] >> ((3 - (c & 0x3)) << 1)) &0x3){
117.2312 +  case 0:			/* zero-width */
117.2313 +    if (c == 0x00ad) ret = 1;	/* force U+00ad (SOFT HYPHEN) to width 1 */
117.2314 +  case 1:			/* single-width */
117.2315 +  case 2:			/* double-width */
117.2316 +    break;
117.2317 +  case 3:			/* ambiguous width */
117.2318 +    ret = (c >= 0x2100) ? 2 : 1;/* need to do something better than this */
117.2319 +    break;
117.2320 +  }
117.2321 +  return ret;
117.2322 +}
117.2323 +
117.2324 +/* Return screen width of UTF-8 string
117.2325 + * Accepts: string
117.2326 + * Returns: width or negative if not valid UTF-8
117.2327 + */
117.2328 +
117.2329 +long utf8_strwidth (unsigned char *s)
117.2330 +{
117.2331 +  unsigned long c,i,ret;
117.2332 +				/* go through string */
117.2333 +  for (ret = 0; *s; ret += ucs4_width (c)) {
117.2334 +    /* It's alright to give a fake value for the byte count to utf8_get()
117.2335 +     * since the null of a null-terminated string will stop processing anyway.
117.2336 +     */
117.2337 +    i = 6;			/* fake value */
117.2338 +    if ((c = utf8_get (&s,&i)) & U8G_ERROR) return -1;
117.2339 +  }
117.2340 +  return ret;
117.2341 +}
117.2342 +
117.2343 +
117.2344 +/* Return screen width of UTF-8 text
117.2345 + * Accepts: SIZEDTEXT to string
117.2346 + * Returns: width or negative if not valid UTF-8
117.2347 + */
117.2348 +
117.2349 +long utf8_textwidth (SIZEDTEXT *utf8)
117.2350 +{
117.2351 +  unsigned long c;
117.2352 +  unsigned char *s = utf8->data;
117.2353 +  unsigned long i = utf8->size;
117.2354 +  unsigned long ret = 0;
117.2355 +  while (i) {			/* while there's a string to process */
117.2356 +    if ((c = utf8_get (&s,&i)) & U8G_ERROR) return -1;
117.2357 +    ret += ucs4_width (c);
117.2358 +  }
117.2359 +  return ret;
117.2360 +}
117.2361 +
117.2362 +/* Decomposition (phew!) */
117.2363 +
117.2364 +#define MORESINGLE 1		/* single UCS-4 tail value */
117.2365 +#define MOREMULTIPLE 2		/* multiple UCS-2 tail values */
117.2366 +
117.2367 +struct decomposemore {
117.2368 +  short type;			/* type of more */
117.2369 +  union {
117.2370 +    unsigned long single;	/* single decomposed value */
117.2371 +    struct {			/* multiple BMP values */
117.2372 +      unsigned short *next;
117.2373 +      unsigned long count;
117.2374 +    } multiple;
117.2375 +  } data;
117.2376 +};
117.2377 +
117.2378 +#define RECURSIVEMORE struct recursivemore
117.2379 +
117.2380 +RECURSIVEMORE {
117.2381 +  struct decomposemore *more;
117.2382 +  RECURSIVEMORE *next;
117.2383 +};
117.2384 +
117.2385 +
117.2386 +/* Return decomposition of a UCS-4 character
117.2387 + * Accepts: character or U8G_ERROR to return next from "more"
117.2388 + *	    pointer to returned more
117.2389 + * Returns: [next] decomposed value, more set if still more decomposition
117.2390 + */
117.2391 +
117.2392 +unsigned long ucs4_decompose (unsigned long c,void **more)
117.2393 +{
117.2394 +  unsigned long i,ix,ret;
117.2395 +  struct decomposemore *m;
117.2396 +  if (c & U8G_ERROR) {		/* want to chase more? */
117.2397 +				/* do sanity check */
117.2398 +    if (m = (struct decomposemore *) *more) switch (m->type) {
117.2399 +    case MORESINGLE:		/* single value */
117.2400 +      ret = m->data.single;
117.2401 +      fs_give (more);		/* no more decomposition */
117.2402 +      break;
117.2403 +    case MOREMULTIPLE:		/* multiple value */
117.2404 +      ret = *m->data.multiple.next++;
117.2405 +      if (!--m->data.multiple.count) fs_give (more);
117.2406 +      break;
117.2407 +    default:			/* uh-oh */
117.2408 +      fatal ("invalid more block argument to ucs4_decompose!");
117.2409 +    }
117.2410 +    else fatal ("no more block provided to ucs4_decompose!");
117.2411 +  }
117.2412 +
117.2413 +  else {			/* start decomposition */
117.2414 +    *more = NIL;		/* initially set no more */
117.2415 +				/* BMP low decompositions */
117.2416 +    if (c < UCS4_BMPLOMIN) ret = c;
117.2417 +				/* fix this someday */
117.2418 +    else if (c == UCS4_BMPLOMIN) ret = ucs4_dbmplotab[0];
117.2419 +    else if (c <= UCS4_BMPLOMAX) {
117.2420 +				/* within range - have a decomposition? */
117.2421 +      if (i = ucs4_dbmploixtab[c - UCS4_BMPLOMIN]) {
117.2422 +				/* get first value of decomposition */
117.2423 +	ret = ucs4_dbmplotab[ix = i & UCS4_BMPLOIXMASK];
117.2424 +				/* has continuation? */
117.2425 +	if (i & UCS4_BMPLOSIZEMASK) {
117.2426 +	  m = (struct decomposemore *)
117.2427 +	    (*more = memset (fs_get (sizeof (struct decomposemore)),0,
117.2428 +			    sizeof (struct decomposemore)));
117.2429 +	  m->type = MOREMULTIPLE;
117.2430 +	  m->data.multiple.next = &ucs4_dbmplotab[++ix];
117.2431 +	  m->data.multiple.count = i >> UCS4_BMPLOSIZESHIFT;
117.2432 +	}
117.2433 +      }
117.2434 +      else ret = c;		/* in range but doesn't decompose */
117.2435 +    }
117.2436 +				/* BMP CJK compatibility */
117.2437 +    else if (c < UCS4_BMPCJKMIN) ret = c;
117.2438 +    else if (c <= UCS4_BMPCJKMAX) {
117.2439 +      if (!(ret = ucs4_bmpcjk1decomptab[c - UCS4_BMPCJKMIN])) ret = c;
117.2440 +    }
117.2441 +				/* BMP CJK compatibility - some not in BMP */
117.2442 +#if UCS4_BMPCJK2MIN - (UCS4_BMPCJKMAX + 1)
117.2443 +    else if (c < UCS4_BMPCJK2MIN) ret = c;
117.2444 +#endif
117.2445 +    else if (c <= UCS4_BMPCJK2MAX)
117.2446 +      ret = ucs4_bmpcjk2decomptab[c - UCS4_BMPCJK2MIN];
117.2447 +				/* BMP high decompositions */
117.2448 +    else if (c < UCS4_BMPHIMIN) ret = c;
117.2449 +    else if (c <= UCS4_BMPHIMAX) {
117.2450 +				/* within range - have a decomposition? */
117.2451 +      if (i = ucs4_dbmphiixtab[c - UCS4_BMPHIMIN]) {
117.2452 +				/* get first value of decomposition */
117.2453 +	ret = ucs4_dbmphitab[ix = i & UCS4_BMPHIIXMASK];
117.2454 +				/* has continuation? */
117.2455 +	if (i & UCS4_BMPHISIZEMASK) {
117.2456 +	  m = (struct decomposemore *)
117.2457 +	    (*more = memset (fs_get (sizeof (struct decomposemore)),0,
117.2458 +			    sizeof (struct decomposemore)));
117.2459 +	  m->type = MOREMULTIPLE;
117.2460 +	  m->data.multiple.next = &ucs4_dbmphitab[++ix];
117.2461 +	  m->data.multiple.count = i >> UCS4_BMPHISIZESHIFT;
117.2462 +	}
117.2463 +      }
117.2464 +      else ret = c;		/* in range but doesn't decompose */
117.2465 +    }
117.2466 +
117.2467 +				/* BMP half and full width forms */
117.2468 +    else if (c < UCS4_BMPHALFFULLMIN) ret = c;
117.2469 +    else if (c <= UCS4_BMPHALFFULLMAX) {
117.2470 +      if (!(ret = ucs4_bmphalffulldecomptab[c - UCS4_BMPHALFFULLMIN])) ret = c;
117.2471 +    }
117.2472 +				/* SMP music */
117.2473 +    else if (c < UCS4_SMPMUSIC1MIN) ret = c;
117.2474 +    else if (c <= UCS4_SMPMUSIC1MAX) {
117.2475 +      ret = ucs4_smpmusic1decomptab[c -= UCS4_SMPMUSIC1MIN][0];
117.2476 +      m = (struct decomposemore *)
117.2477 +	(*more = memset (fs_get (sizeof (struct decomposemore)),0,
117.2478 +			 sizeof (struct decomposemore)));
117.2479 +      m->type = MORESINGLE;
117.2480 +      m->data.single = ucs4_smpmusic1decomptab[c][1];
117.2481 +    }
117.2482 +    else if (c < UCS4_SMPMUSIC2MIN) ret = c;
117.2483 +    else if (c <= UCS4_SMPMUSIC2MAX) {
117.2484 +      ret = ucs4_smpmusic2decomptab[c -= UCS4_SMPMUSIC2MIN][0];
117.2485 +      m = (struct decomposemore *)
117.2486 +	(*more = memset (fs_get (sizeof (struct decomposemore)),0,
117.2487 +			 sizeof (struct decomposemore)));
117.2488 +      m->type = MORESINGLE;
117.2489 +      m->data.single = ucs4_smpmusic2decomptab[c][1];
117.2490 +    }
117.2491 +				/* SMP mathematical forms */
117.2492 +    else if (c < UCS4_SMPMATHMIN) ret = c;
117.2493 +    else if (c <= UCS4_SMPMATHMAX) {
117.2494 +      if (!(ret = ucs4_smpmathdecomptab[c - UCS4_SMPMATHMIN])) ret = c;
117.2495 +    }
117.2496 +				/* CJK compatibility ideographs in SIP */
117.2497 +    else if (!(ret = ((c >= UCS4_SIPMIN) && (c <= UCS4_SIPMAX)) ?
117.2498 +	       ucs4_sipdecomptab[c - UCS4_SIPMIN] : c)) ret = c;
117.2499 +  }
117.2500 +  return ret;
117.2501 +}
117.2502 +
117.2503 +/* Return recursive decomposition of a UCS-4 character
117.2504 + * Accepts: character or U8G_ERROR to return next from "more"
117.2505 + *	    pointer to returned more
117.2506 + * Returns: [next] decomposed value, more set if still more decomposition
117.2507 + */
117.2508 +
117.2509 +unsigned long ucs4_decompose_recursive (unsigned long c,void **more)
117.2510 +{
117.2511 +  unsigned long c1;
117.2512 +  void *m,*mn;
117.2513 +  RECURSIVEMORE *mr;
117.2514 +  if (c & U8G_ERROR) {		/* want to chase more? */
117.2515 +    mn = NIL;
117.2516 +    if (mr = (RECURSIVEMORE *) *more) switch (mr->more->type) {
117.2517 +    case MORESINGLE:		/* decompose single value */
117.2518 +      c = ucs4_decompose_recursive (mr->more->data.single,&mn);
117.2519 +      *more = mr->next;		/* done with this more, remove it */
117.2520 +      fs_give ((void **) &mr->more);
117.2521 +      fs_give ((void **) &mr);
117.2522 +      break;
117.2523 +    case MOREMULTIPLE:		/* decompose current value in multiple */
117.2524 +      c = ucs4_decompose_recursive (*mr->more->data.multiple.next++,&mn);
117.2525 +				/* if done with this multiple decomposition */
117.2526 +      if (!--mr->more->data.multiple.count) {
117.2527 +	*more = mr->next;	/* done with this more, remove it */
117.2528 +	fs_give ((void **) &mr->more);
117.2529 +	fs_give ((void **) &mr);
117.2530 +      }
117.2531 +      break;
117.2532 +    default:			/* uh-oh */
117.2533 +      fatal ("invalid more block argument to ucs4_decompose_recursive!");
117.2534 +    }
117.2535 +    else fatal ("no more block provided to ucs4_decompose_recursive!");
117.2536 +    if (mr = mn) {		/* did this value recurse on us? */
117.2537 +      mr->next = *more;		/* yes, insert new more at head */
117.2538 +      *more = mr;
117.2539 +    }
117.2540 +  }
117.2541 +  else {			/* start decomposition */
117.2542 +    *more = NIL;		/* initially set no more */
117.2543 +    mr = NIL;
117.2544 +    do {			/* repeatedly decompose this codepoint */
117.2545 +      c = ucs4_decompose (c1 = c,&m);
117.2546 +      if (m) {			/* multi-byte decomposition */
117.2547 +	if (c1 == c) fatal ("endless multiple decomposition!");
117.2548 +				/* create a block to stash this more */
117.2549 +	mr = memset (fs_get (sizeof (RECURSIVEMORE)),0,sizeof (RECURSIVEMORE));
117.2550 +	mr->more = m;		/* note the expansion */
117.2551 +	mr->next = *more;	/* old list is the tail */
117.2552 +	*more = mr;		/* and this is the new head */
117.2553 +      }
117.2554 +    } while (c1 != c);		/* until nothing more to decompose */
117.2555 +  }
117.2556 +  return c;
117.2557 +}
   118.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   118.2 +++ b/src/c-client/utf8.h	Mon Sep 14 15:17:45 2009 +0900
   118.3 @@ -0,0 +1,584 @@
   118.4 +/* ========================================================================
   118.5 + * Copyright 1988-2008 University of Washington
   118.6 + *
   118.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   118.8 + * you may not use this file except in compliance with the License.
   118.9 + * You may obtain a copy of the License at
  118.10 + *
  118.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  118.12 + *
  118.13 + * 
  118.14 + * ========================================================================
  118.15 + */
  118.16 +
  118.17 +/*
  118.18 + * Program:	UTF-8 routines
  118.19 + *
  118.20 + * Author:	Mark Crispin
  118.21 + *		Networks and Distributed Computing
  118.22 + *		Computing & Communications
  118.23 + *		University of Washington
  118.24 + *		Administration Building, AG-44
  118.25 + *		Seattle, WA  98195
  118.26 + *		Internet: MRC@CAC.Washington.EDU
  118.27 + *
  118.28 + * Date:	11 June 1997
  118.29 + * Last Edited:	17 January 2008
  118.30 + */
  118.31 +
  118.32 +/* UTF-8 size and conversion routines from UCS-2 values (thus in the BMP).
  118.33 + * Don't use these if UTF-16 data (surrogate pairs) are an issue.
  118.34 + * For UCS-4 values, use the utf8_size() and utf8_put() functions.
  118.35 + */
  118.36 +
  118.37 +#define UTF8_SIZE_BMP(c) ((c & 0xff80) ? ((c & 0xf800) ? 3 : 2) : 1)
  118.38 +
  118.39 +#define UTF8_PUT_BMP(b,c) {				\
  118.40 +  if (c & 0xff80) {		/* non-ASCII? */	\
  118.41 +    if (c & 0xf800) {		/* three byte code */	\
  118.42 +      *b++ = 0xe0 | (c >> 12);				\
  118.43 +      *b++ = 0x80 | ((c >> 6) & 0x3f);			\
  118.44 +    }							\
  118.45 +    else *b++ = 0xc0 | ((c >> 6) & 0x3f);		\
  118.46 +    *b++ = 0x80 | (c & 0x3f); 				\
  118.47 +  }							\
  118.48 +  else *b++ = c;					\
  118.49 +}
  118.50 +
  118.51 +/* utf8_text() flag values */
  118.52 +
  118.53 +#define U8T_CASECANON 2		/* canonicalize case */
  118.54 +#define U8T_DECOMPOSE 4		/* decompose */
  118.55 +				/* full canonicalization */
  118.56 +#define U8T_CANONICAL (U8T_CASECANON | U8T_DECOMPOSE)
  118.57 +
  118.58 +
  118.59 +/* utf8_get() return values */
  118.60 +
  118.61 +				/* 0x0000 - 0xffff BMP plane */
  118.62 +#define U8GM_NONBMP 0xffff0000	/* mask for non-BMP values */
  118.63 +				/* 0x10000 - 0x10ffff extended planes */
  118.64 +				/* 0x110000 - 0x7ffffff non-Unicode */
  118.65 +#define U8G_ERROR 0x80000000	/* error flag */
  118.66 +#define U8G_BADCONT U8G_ERROR+1	/* continuation when not in progress */
  118.67 +#define U8G_INCMPLT U8G_ERROR+2	/* incomplete UTF-8 character */
  118.68 +#define U8G_NOTUTF8 U8G_ERROR+3	/* not a valid UTF-8 octet */
  118.69 +#define U8G_ENDSTRG U8G_ERROR+4	/* end of string */
  118.70 +#define U8G_ENDSTRI U8G_ERROR+5	/* end of string w/ incomplete UTF-8 char */
  118.71 +#define U8G_SURROGA U8G_ERROR+6	/* surrogate codepoint */
  118.72 +#define U8G_NOTUNIC U8G_ERROR+7	/* non-Unicode codepoint */
  118.73 +
  118.74 +
  118.75 +/* ucs4_width() return values */
  118.76 +
  118.77 +#define U4W_ERROR 0x80000000	/* error flags */
  118.78 +#define U4W_NOTUNCD U4W_ERROR+1	/* not a Unicode char */
  118.79 +#define U4W_PRIVATE U4W_ERROR+2	/* private-space plane */
  118.80 +#define U4W_SSPCHAR U4W_ERROR+3	/* Supplementary Special-purpose Plane */
  118.81 +#define U4W_UNASSGN U4W_ERROR+4	/* unassigned space plane */
  118.82 +#define U4W_CONTROL U4W_ERROR+5	/* C0/C1 control */
  118.83 +#define U4W_CTLSRGT U4W_CONTROL	/* in case legacy code references this */
  118.84 +
  118.85 +/* ISO-2022 engine states */
  118.86 +
  118.87 +#define I2S_CHAR 0		/* character */
  118.88 +#define I2S_ESC 1		/* previous character was ESC */
  118.89 +#define I2S_MUL 2		/* previous character was multi-byte code */
  118.90 +#define I2S_INT 3		/* previous character was intermediate */
  118.91 +
  118.92 +
  118.93 +/* ISO-2022 Gn selections */
  118.94 +
  118.95 +#define I2C_G0 0		/* G0 */
  118.96 +#define I2C_G1 1		/* G1 */
  118.97 +#define I2C_G2 2		/* G2 */
  118.98 +#define I2C_G3 3		/* G3 */
  118.99 +#define I2C_SG2 (2 << 2)	/* single shift G2 */
 118.100 +#define I2C_SG3 (3 << 2)	/* single shift G2 */
 118.101 +
 118.102 +
 118.103 +/* ISO-2022 octet definitions */
 118.104 +
 118.105 +#define I2C_ESC 0x1b		/* ESCape */
 118.106 +
 118.107 +	/* Intermediate character */
 118.108 +#define I2C_STRUCTURE 0x20	/* announce code structure */
 118.109 +#define I2C_C0 0x21		/* C0 */
 118.110 +#define I2C_C1 0x22		/* C1 */
 118.111 +#define I2C_CONTROL 0x23	/* single control function */
 118.112 +#define I2C_MULTI 0x24		/* multi-byte character set */
 118.113 +#define I2C_OTHER 0x25		/* other coding system */
 118.114 +#define I2C_REVISED 0x26	/* revised registration */
 118.115 +#define I2C_G0_94 0x28		/* G0 94-character set */
 118.116 +#define I2C_G1_94 0x29		/* G1 94-character set */
 118.117 +#define I2C_G2_94 0x2A		/* G2 94-character set */
 118.118 +#define I2C_G3_94 0x2B		/* G3 94-character set */
 118.119 +#define I2C_G0_96 0x2C		/* (not in ISO-2022) G0 96-character set */
 118.120 +#define I2C_G1_96 0x2D		/* G1 96-character set */
 118.121 +#define I2C_G2_96 0x2E		/* G2 96-character set */
 118.122 +#define I2C_G3_96 0x2F		/* G3 96-character set */
 118.123 +
 118.124 +	/* Locking shifts */
 118.125 +#define I2C_SI 0x0f		/* lock shift to G0 (Shift In) */
 118.126 +#define I2C_SO 0x0e		/* lock shift to G1 (Shift Out) */
 118.127 +	/* prefixed by ESC */
 118.128 +#define I2C_LS2 0x6e		/* lock shift to G2 */
 118.129 +#define I2C_LS3 0x6f		/* lock shift to G3 */
 118.130 +#define I2C_LS1R 0x7e		/* lock shift GR to G1 */
 118.131 +#define I2C_LS2R 0x7d		/* lock shift GR to G2 */
 118.132 +#define I2C_LS3R 0x7c		/* lock shift GR to G3 */
 118.133 +
 118.134 +	/* Single shifts */
 118.135 +#define I2C_SS2_ALT 0x8e	/* single shift to G2 (SS2) */
 118.136 +#define I2C_SS3_ALT 0x8f	/* single shift to G3 (SS3) */
 118.137 +#define I2C_SS2_ALT_7 0x19	/* single shift to G2 (SS2) */
 118.138 +#define I2C_SS3_ALT_7 0x1d	/* single shift to G3 (SS3) */
 118.139 +	/* prefixed by ESC */
 118.140 +#define I2C_SS2 0x4e		/* single shift to G2 (SS2) */
 118.141 +#define I2C_SS3 0x4f		/* single shift to G3 (SS3) */
 118.142 +
 118.143 +/* 94 character sets */
 118.144 +
 118.145 +				/* 4/0 ISO 646 IRV */
 118.146 +#define I2CS_94_BRITISH 0x41	/* 4/1 ISO 646 British */
 118.147 +#define I2CS_94_ASCII 0x42	/* 4/2 ISO 646 USA (ASCII) */
 118.148 +				/* 4/3 NATS Finland/Sweden (primary) */
 118.149 +				/* 4/4 NATS Finland/Sweden (secondary) */
 118.150 +				/* 4/5 NATS Denmark/Norway (primary) */
 118.151 +				/* 4/6 NATS Denmark/Norway (secondary) */
 118.152 +				/* 4/7 ISO 646 Swedish SEN 850200 */
 118.153 +				/* 4/8 ISO 646 Swedish names */
 118.154 +#define I2CS_94_JIS_BUGROM 0x48	/* 4/8 some buggy software does this */
 118.155 +#define I2CS_94_JIS_KANA 0x49	/* 4/9 JIS X 0201-1976 right half */
 118.156 +#define I2CS_94_JIS_ROMAN 0x4a	/* 4/a JIS X 0201-1976 left half */
 118.157 +				/* 4/b ISO 646 German */
 118.158 +				/* 4/c ISO 646 Portuguese (Olivetti) */
 118.159 +				/* 4/d ISO 6438 African */
 118.160 +				/* 4/e ISO 5427 Cyrillic (Honeywell-Bull) */
 118.161 +				/* 4/f DIN 31624 extended bibliography  */
 118.162 +				/* 5/0 ISO 5426-1980 Bibliography */
 118.163 +				/* 5/1 ISO 5427-1981 Cyrillic*/
 118.164 +				/* 5/2 ISO 646 French (withdrawn) */
 118.165 +				/* 5/3 ISO 5428-1980 Greek bibliography */
 118.166 +				/* 5/4 GB 1988-80 Chinese */
 118.167 +				/* 5/5 Latin-Greek (Honeywell-Bull) */
 118.168 +				/* 5/6 UK Viewdata/Teletext */
 118.169 +				/* 5/7 INIS (IRV subset) */
 118.170 +				/* 5/8 ISO 5428 Greek Bibliography */
 118.171 +				/* 5/9 ISO 646 Italian (Olivetti) */
 118.172 +				/* 5/a ISO 646 Spanish (Olivetti) */
 118.173 +				/* 5/b Greek (Olivetti) */
 118.174 +				/* 5/c Latin-Greek (Olivetti) */
 118.175 +				/* 5/d INIS non-standard extension */
 118.176 +				/* 5/e INIS Cyrillic extension */
 118.177 +				/* 5/f Arabic CODAR-U IERA */
 118.178 +				/* 6/0 ISO 646 Norwegian */
 118.179 +				/* 6/1 Norwegian version 2 (withdrawn) */
 118.180 +				/* 6/2 Videotex supplementary */
 118.181 +				/* 6/3 Videotex supplementary #2 */
 118.182 +				/* 6/4 Videotex supplementary #3 */
 118.183 +				/* 6/5 APL */
 118.184 +				/* 6/6 ISO 646 French */
 118.185 +				/* 6/7 ISO 646 Portuguese (IBM) */
 118.186 +				/* 6/8 ISO 646 Spanish (IBM) */
 118.187 +				/* 6/9 ISO 646 Hungarian */
 118.188 +				/* 6/a Greek ELOT (withdrawn) */
 118.189 +				/* 6/b ISO 9036 Arabic 7-bit */
 118.190 +				/* 6/c ISO 646 IRV supplementary set */
 118.191 +				/* 6/d JIS C6229-1984 OCR-A */
 118.192 +				/* 6/e JIS C6229-1984 OCR-B */
 118.193 +				/* 6/f JIS C6229-1984 OCR-B additional */
 118.194 +				/* 7/0 JIS C6229-1984 hand-printed */
 118.195 +				/* 7/1 JIS C6229-1984 additional hand-printd */
 118.196 +				/* 7/2 JIS C6229-1984 katakana hand-printed */
 118.197 +				/* 7/3 E13B Japanese graphic */
 118.198 +				/* 7/4 Supplementary Videotex (withdrawn) */
 118.199 +				/* 7/5 Teletex primary CCITT T.61 */
 118.200 +				/* 7/6 Teletex secondary CCITT T.61 */
 118.201 +				/* 7/7 CSA Z 243.4-1985 Alternate primary #1 */
 118.202 +				/* 7/8 CSA Z 243.4-1985 Alternate primary #2 */
 118.203 +				/* 7/9 Mosaic CCITT T.101 */
 118.204 +				/* 7/a Serbocroatian/Slovenian Latin */
 118.205 +				/* 7/b Serbocroatian Cyrillic */
 118.206 +				/* 7/c Supplementary CCITT T.101 */
 118.207 +				/* 7/d Macedonian Cyrillic */
 118.208 +
 118.209 +/* 94 character sets - second intermediate byte */
 118.210 +
 118.211 +				/* 4/0 Greek primary CCITT */
 118.212 +				/* 4/1 Cuba */
 118.213 +				/* 4/2 ISO/IEC 646 invariant */
 118.214 +				/* 4/3 Irish Gaelic 7-bit */
 118.215 +				/* 4/4 Turkmen */
 118.216 +
 118.217 +
 118.218 +/* 94x94 character sets */
 118.219 +
 118.220 +#define I2CS_94x94_JIS_OLD 0x40	/* 4/0 JIS X 0208-1978 */
 118.221 +#define I2CS_94x94_GB 0x41	/* 4/1 GB 2312 */
 118.222 +#define I2CS_94x94_JIS_NEW 0x42	/* 4/2 JIS X 0208-1983 */
 118.223 +#define I2CS_94x94_KSC 0x43	/* 4/3 KSC 5601 */
 118.224 +#define I2CS_94x94_JIS_EXT 0x44	/* 4/4 JIS X 0212-1990 */
 118.225 +				/* 4/5 CCITT Chinese */
 118.226 +				/* 4/6 Blisssymbol Graphic */
 118.227 +#define I2CS_94x94_CNS1 0x47	/* 4/7 CNS 11643 plane 1 */
 118.228 +#define I2CS_94x94_CNS2 0x48	/* 4/8 CNS 11643 plane 2 */
 118.229 +#define I2CS_94x94_CNS3 0x49	/* 4/9 CNS 11643 plane 3 */
 118.230 +#define I2CS_94x94_CNS4 0x4a	/* 4/a CNS 11643 plane 4 */
 118.231 +#define I2CS_94x94_CNS5 0x4b	/* 4/b CNS 11643 plane 5 */
 118.232 +#define I2CS_94x94_CNS6 0x4c	/* 4/c CNS 11643 plane 6 */
 118.233 +#define I2CS_94x94_CNS7 0x4d	/* 4/d CNS 11643 plane 7 */
 118.234 +				/* 4/e DPRK (North Korea) KGCII */
 118.235 +				/* 4/f JGCII plane 1 */
 118.236 +				/* 5/0 JGCII plane 2 */
 118.237 +
 118.238 +/* 96 character sets */
 118.239 +
 118.240 +#define I2CS_96_ISO8859_1 0x41	/* 4/1 Latin-1 (Western Europe) */
 118.241 +#define I2CS_96_ISO8859_2 0x42	/* 4/2 Latin-2 (Czech, Slovak) */
 118.242 +#define I2CS_96_ISO8859_3 0x43	/* 4/3 Latin-3 (Dutch, Turkish) */
 118.243 +#define I2CS_96_ISO8859_4 0x44	/* 4/4 Latin-4 (Scandinavian) */
 118.244 +				/* 4/5 CSA Z 243.4-1985 */
 118.245 +#define I2CS_96_ISO8859_7 0x46	/* 4/6 Greek */
 118.246 +#define I2CS_96_ISO8859_6 0x47	/* 4/7 Arabic */
 118.247 +#define I2CS_96_ISO8859_8 0x48	/* 4/8 Hebrew */
 118.248 +				/* 4/9 Czechoslovak CSN 369103 */
 118.249 +				/* 4/a Supplementary Latin and non-alpha */
 118.250 +				/* 4/b Technical */
 118.251 +#define I2CS_96_ISO8859_5 0x4c	/* 4/c Cyrillic */
 118.252 +#define I2CS_96_ISO8859_9 0x4d	/* 4/d Latin-5 (Finnish, Portuguese) */
 118.253 +				/* 4/e ISO 6937-2 residual */
 118.254 +				/* 4/f Basic Cyrillic */
 118.255 +				/* 5/0 Supplementary Latin 1, 2 and 5 */
 118.256 +				/* 5/1 Basic Box */
 118.257 +				/* 5/2 Supplementary ISO/IEC 6937 : 1992 */
 118.258 +				/* 5/3 CCITT Hebrew supplementary */
 118.259 +#define I2CS_96_TIS620 0x54	/* 5/4 TIS 620 */
 118.260 +				/* 5/5 Arabic/French/German */
 118.261 +#define I2CS_96_ISO8859_10 0x56	/* 5/6 Latin-6 (Northern Europe) */
 118.262 +				/* 5/7 ??? */
 118.263 +				/* 5/8 Sami (Lappish) supplementary */
 118.264 +#define I2CS_96_ISO8859_13 0x59	/* 5/9 Latin-7 (Baltic) */
 118.265 +#define I2CS_96_VSCII 0x5a	/* 5/a Vietnamese */
 118.266 +				/* 5/b Technical #1 IEC 1289 */
 118.267 +#define I2CS_96_ISO8859_14 0x5c	/* 5/c Latin-8 (Celtic) */
 118.268 +				/* 5/d Sami supplementary Latin */
 118.269 +				/* 5/e Latin/Hebrew */
 118.270 +				/* 5/f Celtic supplementary Latin */
 118.271 +				/* 6/0 Uralic supplementary Cyrillic */
 118.272 +				/* 6/1 Volgaic supplementary Cyrillic */
 118.273 +#define I2CS_96_ISO8859_15 0x62	/* 6/2 Latin-9 (Euro) */
 118.274 +				/* 6/3 Latin-1 with Euro */
 118.275 +				/* 6/4 Latin-4 with Euro */
 118.276 +				/* 6/5 Latin-7 with Euro */
 118.277 +#define I2CS_96_ISO8859_16 0x66	/* 6/6 Latin-10 (Balkan) */
 118.278 +				/* 6/7 Ogham */
 118.279 +				/* 6/8 Sami supplementary Latin #2 */
 118.280 +				/* 7/d Supplementary Mosaic for CCITT 101 */
 118.281 +
 118.282 +/* 96x96 character sets */
 118.283 +
 118.284 +/* Types of character sets */
 118.285 +
 118.286 +#define I2CS_94 0x000		/* 94 character set */
 118.287 +#define I2CS_96 0x100		/* 96 character set */
 118.288 +#define I2CS_MUL 0x200		/* multi-byte */
 118.289 +#define I2CS_94x94 (I2CS_MUL | I2CS_94)
 118.290 +#define I2CS_96x96 (I2CS_MUL | I2CS_96)
 118.291 +
 118.292 +
 118.293 +/* Character set identifiers stored in Gn */
 118.294 +
 118.295 +#define I2CS_BRITISH (I2CS_94 | I2CS_94_BRITISH)
 118.296 +#define I2CS_ASCII (I2CS_94 | I2CS_94_ASCII)
 118.297 +#define I2CS_JIS_BUGROM (I2CS_94 | I2CS_94_JIS_BUGROM)
 118.298 +#define I2CS_JIS_KANA (I2CS_94 | I2CS_94_JIS_KANA)
 118.299 +#define I2CS_JIS_ROMAN (I2CS_94 | I2CS_94_JIS_ROMAN)
 118.300 +#define I2CS_JIS_OLD (I2CS_94x94 | I2CS_94x94_JIS_OLD)
 118.301 +#define I2CS_GB (I2CS_94x94 | I2CS_94x94_GB)
 118.302 +#define I2CS_JIS_NEW (I2CS_94x94 | I2CS_94x94_JIS_NEW)
 118.303 +#define I2CS_KSC (I2CS_94x94 | I2CS_94x94_KSC)
 118.304 +#define I2CS_JIS_EXT (I2CS_94x94 | I2CS_94x94_JIS_EXT)
 118.305 +#define I2CS_CNS1 (I2CS_94x94 | I2CS_94x94_CNS1)
 118.306 +#define I2CS_CNS2 (I2CS_94x94 | I2CS_94x94_CNS2)
 118.307 +#define I2CS_CNS3 (I2CS_94x94 | I2CS_94x94_CNS3)
 118.308 +#define I2CS_CNS4 (I2CS_94x94 | I2CS_94x94_CNS4)
 118.309 +#define I2CS_CNS5 (I2CS_94x94 | I2CS_94x94_CNS5)
 118.310 +#define I2CS_CNS6 (I2CS_94x94 | I2CS_94x94_CNS6)
 118.311 +#define I2CS_CNS7 (I2CS_94x94 | I2CS_94x94_CNS7)
 118.312 +#define I2CS_ISO8859_1 (I2CS_96 | I2CS_96_ISO8859_1)
 118.313 +#define I2CS_ISO8859_2 (I2CS_96 | I2CS_96_ISO8859_2)
 118.314 +#define I2CS_ISO8859_3 (I2CS_96 | I2CS_96_ISO8859_3)
 118.315 +#define I2CS_ISO8859_4 (I2CS_96 | I2CS_96_ISO8859_4)
 118.316 +#define I2CS_ISO8859_7 (I2CS_96 | I2CS_96_ISO8859_7)
 118.317 +#define I2CS_ISO8859_6 (I2CS_96 | I2CS_96_ISO8859_6)
 118.318 +#define I2CS_ISO8859_8 (I2CS_96 | I2CS_96_ISO8859_8)
 118.319 +#define I2CS_ISO8859_5 (I2CS_96 | I2CS_96_ISO8859_5)
 118.320 +#define I2CS_ISO8859_9 (I2CS_96 | I2CS_96_ISO8859_9)
 118.321 +#define I2CS_TIS620 (I2CS_96 | I2CS_96_TIS620)
 118.322 +#define I2CS_ISO8859_10 (I2CS_96 | I2CS_96_ISO8859_10)
 118.323 +#define I2CS_ISO8859_13 (I2CS_96 | I2CS_96_ISO8859_13)
 118.324 +#define I2CS_VSCII (I2CS_96 | I2CS_96_VSCII)
 118.325 +#define I2CS_ISO8859_14 (I2CS_96 | I2CS_96_ISO8859_14)
 118.326 +#define I2CS_ISO8859_15 (I2CS_96 | I2CS_96_ISO8859_15)
 118.327 +#define I2CS_ISO8859_16 (I2CS_96 | I2CS_96_ISO8859_16)
 118.328 +
 118.329 +
 118.330 +/* Miscellaneous ISO 2022 definitions */
 118.331 +
 118.332 +#define EUC_CS2 0x8e		/* single shift CS2 */
 118.333 +#define EUC_CS3 0x8f		/* single shift CS3 */
 118.334 +
 118.335 +#define BITS7 0x7f		/* 7-bit value mask */
 118.336 +#define BIT8 0x80		/* 8th bit mask */
 118.337 +
 118.338 +/* The following saves us from having to have yet more charset tables */
 118.339 +
 118.340 +/* Unicode codepoints */
 118.341 +
 118.342 +#define UCS2_C0CONTROL 0x00	/* first C0 control */
 118.343 +#define UCS2_C0CONTROLEND 0x1F	/* last C0 control */
 118.344 +#define UCS2_C1CONTROL 0x80	/* first C1 control */
 118.345 +#define UCS2_C1CONTROLEND 0x9F	/* last C1 control */
 118.346 +
 118.347 +				/* ISO 646 substituted Unicode codepoints */
 118.348 +#define UCS2_POUNDSTERLING 0x00a3
 118.349 +#define UCS2_YEN 0x00a5
 118.350 +#define UCS2_OVERLINE 0x203e
 118.351 +#define UCS2_EURO 0x20ac
 118.352 +#define UCS2_KATAKANA 0xff61	/* first katakana codepoint */
 118.353 +#define UCS2_BOM 0xfeff		/* byte order mark */
 118.354 +#define UCS2_BOGON 0xfffd	/* replacement character */
 118.355 +				/* next two codepoints are not Unicode chars */
 118.356 +#define UCS2_BOMCHECK 0xfffe	/* used to check byte order with UCS2_BOM */
 118.357 +#define UCS2_NOTCHAR 0xffff	/* not a character */
 118.358 +
 118.359 +#define UCS4_BMPBASE 0x0000	/* Basic Multilingual Plane */
 118.360 +#define UCS4_SMPBASE 0x10000	/* Supplementary Multilinugual Plane */
 118.361 +#define UCS4_SIPBASE 0x20000	/* Supplementary Ideographic Plane */
 118.362 +				/* EastAsianWidth says plane 3 is wide */
 118.363 +#define UCS4_UNABASE 0x40000	/* unassigned space */
 118.364 +#define UCS4_SSPBASE 0xe0000	/* Supplementary Special-purpose Plane */
 118.365 +#define UCS4_PVTBASE 0xf0000	/* private-space (two planes) */
 118.366 +#define UCS4_MAXUNICODE 0x10ffff/* highest Unicode codepoint */
 118.367 +
 118.368 +#define UTF16_BASE 0x10000	/* base of codepoints needing surrogates */
 118.369 +#define UTF16_SHIFT 10		/* surrogate shift */
 118.370 +#define UTF16_MASK 0x3ff	/* surrogate mask */
 118.371 +#define UTF16_SURR 0xd800	/* UTF-16 surrogate area */
 118.372 +#define UTF16_SURRH 0xd800	/* UTF-16 first high surrogate */
 118.373 +#define UTF16_SURRHEND 0xdbff	/* UTF-16 last high surrogate */
 118.374 +#define UTF16_SURRL 0xdc00	/* UTF-16 first low surrogate */
 118.375 +#define UTF16_SURRLEND 0xdfff	/* UTF-16 last low surrogate */
 118.376 +#define UTF16_MAXSURR 0xdfff	/* end of UTF-16 surrogates */
 118.377 +
 118.378 +
 118.379 +/* UBOGON is used to represent a codepoint in a character set which does not
 118.380 + * map to Unicode.  It is also used for mapping failures, e.g. incomplete
 118.381 + * shift sequences.  This name has the same text width as 0x????, for
 118.382 + * convenience in the mapping tables.
 118.383 + *
 118.384 + * NOCHAR is used to represent a codepoint in Unicode which does not map to
 118.385 + * the target character set in a reverse mapping table.  This name has the
 118.386 + * same text width as 0x???? in case we ever add static reverse mapping tables.
 118.387 + */
 118.388 +
 118.389 +#define UBOGON UCS2_BOGON
 118.390 +#define NOCHAR UCS2_NOTCHAR
 118.391 +
 118.392 +/* Codepoints in non-Unicode character sets */
 118.393 +
 118.394 +/* Codepoints in ISO 646 character sets */
 118.395 +
 118.396 +/* British ASCII codepoints */
 118.397 +
 118.398 +#define BRITISH_POUNDSTERLING 0x23
 118.399 +
 118.400 +/* JIS Roman codepoints */
 118.401 +
 118.402 +#define JISROMAN_YEN 0x5c
 118.403 +#define JISROMAN_OVERLINE 0x7e
 118.404 +
 118.405 +
 118.406 +/* Hankaku katakana codepoints & parameters
 118.407 + *
 118.408 + * In earlier versions, MAX_KANA_7 and MAX_KANA_8 were the maximum codepoint
 118.409 + * values.  Although this made sense, it was confusing with the "max ku" and
 118.410 + * "max ten" values used in the double-byte tables; there are 1-origin, but
 118.411 + * the calculated values used for "ku" and "ten" are 0-origin (derived by
 118.412 + * substracting the "base").  What this all meant is that for double byte
 118.413 + * characters the limit test is of the form (value < max_ku), but for single
 118.414 + * byte characters (which used the same cell to hold the max ku) the limit
 118.415 + * test was (value <= max_ku).
 118.416 + *
 118.417 + * By making MAX_KANA_[78] be maximum+1, the same (value < max_ku) limit test
 118.418 + * is used throughout.  - 6/15/2006
 118.419 + */
 118.420 +
 118.421 +#define MIN_KANA_7 0x21
 118.422 +#define MAX_KANA_7 0x60		/* maximum value + 1 */
 118.423 +#define KANA_7 (UCS2_KATAKANA - MIN_KANA_7)
 118.424 +#define MIN_KANA_8 (MIN_KANA_7 | BIT8)
 118.425 +#define MAX_KANA_8 (MAX_KANA_7 | BIT8)
 118.426 +#define KANA_8 (UCS2_KATAKANA - MIN_KANA_8)
 118.427 +
 118.428 +/* Charset scripts */
 118.429 +
 118.430 +/*  The term "script" is used here in a very loose sense, enough to make
 118.431 + * purists cringe.  Basically, the idea is to give the main program some
 118.432 + * idea of how it should treat the characters of text in a charset with
 118.433 + * respect to font, drawing routines, etc.
 118.434 + *
 118.435 + *  In some cases, "script" is associated with a charset; in other cases,
 118.436 + * it's more closely tied to a language.
 118.437 + */
 118.438 +
 118.439 +#define SC_UNICODE 0x1		/* Unicode */
 118.440 +#define SC_LATIN_1 0x10		/* Western Europe */
 118.441 +#define SC_LATIN_2 0x20		/* Eastern Europe */
 118.442 +#define SC_LATIN_3 0x40		/* Southern Europe */
 118.443 +#define SC_LATIN_4 0x80		/* Northern Europe */
 118.444 +#define SC_LATIN_5 0x100	/* Turkish */
 118.445 +#define SC_LATIN_6 0x200	/* Nordic */
 118.446 +#define SC_LATIN_7 0x400	/* Baltic */
 118.447 +#define SC_LATIN_8 0x800	/* Celtic */
 118.448 +#define SC_LATIN_9 0x1000	/* Euro */
 118.449 +#define SC_LATIN_0 SC_LATIN_9	/* colloquial name for Latin-9 */
 118.450 +#define SC_ARABIC 0x2000
 118.451 +#define SC_CYRILLIC 0x4000
 118.452 +#define SC_GREEK 0x8000
 118.453 +#define SC_HEBREW 0x10000
 118.454 +#define SC_THAI 0x20000
 118.455 +#define SC_UKRANIAN 0x40000
 118.456 +#define SC_LATIN_10 0x80000	/* Balkan */
 118.457 +#define SC_VIETNAMESE 0x100000
 118.458 +#define SC_CHINESE_SIMPLIFIED 0x1000000
 118.459 +#define SC_CHINESE_TRADITIONAL 0x2000000
 118.460 +#define SC_JAPANESE 0x4000000
 118.461 +#define SC_KOREAN 0x8000000
 118.462 +
 118.463 +
 118.464 +/* Script table */
 118.465 +
 118.466 +typedef struct utf8_scent {
 118.467 +  char *name;			/* script name */
 118.468 +  char *description;		/* script description */
 118.469 +  unsigned long script;		/* script bitmask */
 118.470 +} SCRIPT;
 118.471 +
 118.472 +/* Character set table support */
 118.473 +
 118.474 +typedef struct utf8_csent {
 118.475 +  char *name;			/* charset name */
 118.476 +  unsigned short type;		/* type of charset */
 118.477 +  unsigned short flags;		/* charset flags */
 118.478 +  void *tab;			/* additional data */
 118.479 +  unsigned long script;		/* script(s) implemented by this charset */
 118.480 +  char *preferred;		/* preferred charset over this one */
 118.481 +} CHARSET;
 118.482 +
 118.483 +
 118.484 +struct utf8_eucparam {
 118.485 +  unsigned int base_ku : 8;	/* base row */
 118.486 +  unsigned int base_ten : 8;	/* base column */
 118.487 +  unsigned int max_ku : 8;	/* maximum row */
 118.488 +  unsigned int max_ten : 8;	/* maximum column */
 118.489 +  void *tab;			/* conversion table */
 118.490 +};
 118.491 +
 118.492 +
 118.493 +/* Charset types */
 118.494 +
 118.495 +#define CT_UNKNOWN 0		/* unknown 8-bit */
 118.496 +#define CT_ASCII 1		/* 7-bit ASCII no table */
 118.497 +#define CT_UCS2 2		/* 2 byte 16-bit Unicode no table */
 118.498 +#define CT_UCS4 3		/* 4 byte 32-bit Unicode no table */
 118.499 +#define CT_1BYTE0 10		/* 1 byte ISO 8859-1 no table */
 118.500 +#define CT_1BYTE 11		/* 1 byte ASCII + table 0x80-0xff */
 118.501 +#define CT_1BYTE8 12		/* 1 byte table 0x00 - 0xff */
 118.502 +#define CT_EUC 100		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
 118.503 +#define CT_DBYTE 101		/* 2 byte ASCII + utf8_eucparam */
 118.504 +#define CT_DBYTE2 102		/* 2 byte ASCII + utf8_eucparam plane1/2 */
 118.505 +#define CT_UTF16 1000		/* variable UTF-16 encoded Unicode no table */
 118.506 +#define CT_UTF8 1001		/* variable UTF-8 encoded Unicode no table */
 118.507 +#define CT_UTF7 1002		/* variable UTF-7 encoded Unicode no table */
 118.508 +#define CT_2022 10000		/* variable ISO-2022 encoded no table */
 118.509 +#define CT_SJIS 10001		/* 2 byte Shift-JIS encoded JIS no table */
 118.510 +
 118.511 +
 118.512 +/* Character set flags */
 118.513 +
 118.514 +#define CF_PRIMARY 0x1		/* primary name for this charset */
 118.515 +#define CF_DISPLAY 0x2		/* charset used in displays */
 118.516 +#define CF_POSTING 0x4		/* charset used in email posting */
 118.517 +#define CF_UNSUPRT 0x8		/* charset unsupported (can't convert to it) */
 118.518 +#define CF_NOEMAIL 0x10		/* charset not used in email */
 118.519 +
 118.520 +
 118.521 +/* UTF-7 engine states */
 118.522 +
 118.523 +#define U7_ASCII 0		/* ASCII character */
 118.524 +#define U7_PLUS 1		/* plus seen */
 118.525 +#define U7_UNICODE 2		/* Unicode characters */
 118.526 +#define U7_MINUS 3		/* absorbed minus seen */
 118.527 +
 118.528 +/* Function prototypes */
 118.529 +
 118.530 +typedef unsigned long (*ucs4cn_t) (unsigned long c);
 118.531 +typedef unsigned long (*ucs4de_t) (unsigned long c,void **more);
 118.532 +
 118.533 +SCRIPT *utf8_script (char *script);
 118.534 +const CHARSET *utf8_charset (char *charset);
 118.535 +char *utf8_badcharset (char *charset);
 118.536 +long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags);
 118.537 +long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret,
 118.538 +		   ucs4cn_t cv,ucs4de_t de);
 118.539 +long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,
 118.540 +		  unsigned long errch);
 118.541 +long utf8_cstocstext (SIZEDTEXT *text,char *sc,SIZEDTEXT *ret,char *dc,
 118.542 +		      unsigned long errch);
 118.543 +unsigned short *utf8_rmap (char *charset);
 118.544 +unsigned short *utf8_rmap_cs (const CHARSET *cs);
 118.545 +unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap);
 118.546 +long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret,
 118.547 +		    unsigned long errch,long iso2022jp);
 118.548 +unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap,
 118.549 +			     unsigned long errch,long iso2022jp);
 118.550 +long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
 118.551 +		    SIZEDTEXT *ret,unsigned long errch);
 118.552 +long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
 118.553 +		   unsigned long errch);
 118.554 +long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len,
 118.555 +		   unsigned short *rmap,unsigned long errch);
 118.556 +unsigned long utf8_get (unsigned char **s,unsigned long *i);
 118.557 +unsigned long utf8_get_raw (unsigned char **s,unsigned long *i);
 118.558 +unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i);
 118.559 +unsigned long *utf8_csvalidmap (char *charsets[]);
 118.560 +const CHARSET *utf8_infercharset (SIZEDTEXT *src);
 118.561 +long utf8_validate (unsigned char *s,unsigned long i);
 118.562 +void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.563 +void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
 118.564 +		      ucs4de_t de);
 118.565 +void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
 118.566 +		       ucs4de_t de);
 118.567 +void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
 118.568 +		    ucs4de_t de);
 118.569 +void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
 118.570 +		      ucs4de_t de);
 118.571 +void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
 118.572 +		       ucs4de_t de);
 118.573 +void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.574 +void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.575 +void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.576 +void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.577 +void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.578 +void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.579 +void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
 118.580 +unsigned long utf8_size (unsigned long c);
 118.581 +unsigned char *utf8_put (unsigned char *s,unsigned long c);
 118.582 +unsigned long ucs4_titlecase (unsigned long c);
 118.583 +long ucs4_width (unsigned long c);
 118.584 +long utf8_strwidth (unsigned char *s);
 118.585 +long utf8_textwidth (SIZEDTEXT *utf8);
 118.586 +unsigned long ucs4_decompose (unsigned long c,void **more);
 118.587 +unsigned long ucs4_decompose_recursive (unsigned long c,void **more);
   119.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   119.2 +++ b/src/c-client/utf8aux.c	Mon Sep 14 15:17:45 2009 +0900
   119.3 @@ -0,0 +1,449 @@
   119.4 +/* ========================================================================
   119.5 + * Copyright 1988-2007 University of Washington
   119.6 + *
   119.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   119.8 + * you may not use this file except in compliance with the License.
   119.9 + * You may obtain a copy of the License at
  119.10 + *
  119.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  119.12 + *
  119.13 + * 
  119.14 + * ========================================================================
  119.15 + */
  119.16 +
  119.17 +/*
  119.18 + * Program:	UTF-8 auxillary routines (c-client and MIME2 support)
  119.19 + *
  119.20 + * Author:	Mark Crispin
  119.21 + *		Networks and Distributed Computing
  119.22 + *		Computing & Communications
  119.23 + *		University of Washington
  119.24 + *		Administration Building, AG-44
  119.25 + *		Seattle, WA  98195
  119.26 + *		Internet: MRC@CAC.Washington.EDU
  119.27 + *
  119.28 + * Date:	11 June 1997
  119.29 + * Last Edited:	12 October 2007
  119.30 + */
  119.31 +
  119.32 +
  119.33 +#include <stdio.h>
  119.34 +#include <ctype.h>
  119.35 +#include "c-client.h"
  119.36 +
  119.37 +/* Convert charset labelled stringlist to UTF-8 in place
  119.38 + * Accepts: string list
  119.39 + *	    charset
  119.40 + */
  119.41 +
  119.42 +static void utf8_stringlist (STRINGLIST *st,char *charset)
  119.43 +{
  119.44 +  SIZEDTEXT txt;
  119.45 +				/* convert entire stringstruct */
  119.46 +  if (st) do if (utf8_text (&st->text,charset,&txt,U8T_CANONICAL)) {
  119.47 +    fs_give ((void **) &st->text.data);
  119.48 +    st->text.data = txt.data; /* transfer this text */
  119.49 +    st->text.size = txt.size;
  119.50 +  } while (st = st->next);
  119.51 +}
  119.52 +
  119.53 +
  119.54 +/* Convert charset labelled searchpgm to UTF-8 in place
  119.55 + * Accepts: search program
  119.56 + *	    charset
  119.57 + */
  119.58 +
  119.59 +void utf8_searchpgm (SEARCHPGM *pgm,char *charset)
  119.60 +{
  119.61 +  SIZEDTEXT txt;
  119.62 +  SEARCHHEADER *hl;
  119.63 +  SEARCHOR *ol;
  119.64 +  SEARCHPGMLIST *pl;
  119.65 +  if (pgm) {			/* must have a search program */
  119.66 +    utf8_stringlist (pgm->bcc,charset);
  119.67 +    utf8_stringlist (pgm->cc,charset);
  119.68 +    utf8_stringlist (pgm->from,charset);
  119.69 +    utf8_stringlist (pgm->to,charset);
  119.70 +    utf8_stringlist (pgm->subject,charset);
  119.71 +    for (hl = pgm->header; hl; hl = hl->next) {
  119.72 +      if (utf8_text (&hl->line,charset,&txt,U8T_CANONICAL)) {
  119.73 +	fs_give ((void **) &hl->line.data);
  119.74 +	hl->line.data = txt.data;
  119.75 +	hl->line.size = txt.size;
  119.76 +      }
  119.77 +      if (utf8_text (&hl->text,charset,&txt,U8T_CANONICAL)) {
  119.78 +	fs_give ((void **) &hl->text.data);
  119.79 +	hl->text.data = txt.data;
  119.80 +	hl->text.size = txt.size;
  119.81 +      }
  119.82 +    }
  119.83 +    utf8_stringlist (pgm->body,charset);
  119.84 +    utf8_stringlist (pgm->text,charset);
  119.85 +    for (ol = pgm->or; ol; ol = ol->next) {
  119.86 +      utf8_searchpgm (ol->first,charset);
  119.87 +      utf8_searchpgm (ol->second,charset);
  119.88 +    }
  119.89 +    for (pl = pgm->not; pl; pl = pl->next) utf8_searchpgm (pl->pgm,charset);
  119.90 +    utf8_stringlist (pgm->return_path,charset);
  119.91 +    utf8_stringlist (pgm->sender,charset);
  119.92 +    utf8_stringlist (pgm->reply_to,charset);
  119.93 +    utf8_stringlist (pgm->in_reply_to,charset);
  119.94 +    utf8_stringlist (pgm->message_id,charset);
  119.95 +    utf8_stringlist (pgm->newsgroups,charset);
  119.96 +    utf8_stringlist (pgm->followup_to,charset);
  119.97 +    utf8_stringlist (pgm->references,charset);
  119.98 +  }
  119.99 +}
 119.100 +
 119.101 +/* Convert MIME-2 sized text to UTF-8
 119.102 + * Accepts: source sized text
 119.103 + *	    charset
 119.104 + *	    flags (same as utf8_text())
 119.105 + * Returns: T if successful, NIL if failure
 119.106 + */
 119.107 +
 119.108 +#define MINENCWORD 9
 119.109 +#define MAXENCWORD 75
 119.110 +
 119.111 +/* This resizing algorithm is stupid, but hopefully it should never be triggered
 119.112 + * except for a pathological header.  The main concern is that we don't get a
 119.113 + * buffer overflow.
 119.114 + */
 119.115 +
 119.116 +#define DSIZE 65536		/* real headers should never be this big */
 119.117 +#define FUZZ 10			/* paranoia fuzz */
 119.118 +
 119.119 +long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags)
 119.120 +{
 119.121 +  unsigned char *s,*se,*e,*ee,*t,*te;
 119.122 +  char *cs,*ce,*ls;
 119.123 +  SIZEDTEXT txt,rtxt;
 119.124 +  unsigned long i;
 119.125 +  size_t dsize = min (DSIZE,((src->size / 4) + 1) * 9);
 119.126 +				/* always create buffer if canonicalizing */
 119.127 +  dst->data = (flags & U8T_CANONICAL) ?
 119.128 +    (unsigned char *) fs_get ((size_t) dsize) : NIL;
 119.129 +  dst->size = 0;		/* nothing written yet */
 119.130 +				/* look for encoded words */
 119.131 +  for (s = src->data, se = src->data + src->size; s < se; s++) {
 119.132 +    if (((se - s) > MINENCWORD) && (*s == '=') && (s[1] == '?') &&
 119.133 +      (cs = (char *) mime2_token (s+2,se,(unsigned char **) &ce)) &&
 119.134 +	(e = mime2_token ((unsigned char *) ce+1,se,&ee)) &&
 119.135 +	(te = mime2_text (t = e+2,se)) && (ee == e + 1) &&
 119.136 +	((te - s) < MAXENCWORD)) {
 119.137 +      if (mime2_decode (e,t,te,&txt)) {
 119.138 +	*ce = '\0';		/* temporarily tie off charset */
 119.139 +	if (ls = strchr (cs,'*')) *ls = '\0';
 119.140 +				/* convert to UTF-8 as best we can */
 119.141 +	if (!utf8_text (&txt,cs,&rtxt,flags)) utf8_text (&txt,NIL,&rtxt,flags);
 119.142 +	if (dst->data) {	/* make sure existing buffer fits */
 119.143 +	  while (dsize <= (dst->size + rtxt.size + FUZZ)) {
 119.144 +	    dsize += DSIZE;	/* kick it up */
 119.145 +	    fs_resize ((void **) &dst->data,dsize);
 119.146 +	  }
 119.147 +	}
 119.148 +	else {			/* make a new buffer */
 119.149 +	  while (dsize <= (dst->size + rtxt.size)) dsize += DSIZE;
 119.150 +	  memcpy (dst->data = (unsigned char *) fs_get (dsize),src->data,
 119.151 +		  dst->size = s - src->data);
 119.152 +	}
 119.153 +	for (i = 0; i < rtxt.size; i++) dst->data[dst->size++] = rtxt.data[i];
 119.154 +
 119.155 +				/* all done with converted text */
 119.156 +	if (rtxt.data != txt.data) fs_give ((void **) &rtxt.data);
 119.157 +	if (ls) *ls = '*';	/* restore language tag delimiter */
 119.158 +	*ce = '?';		/* restore charset delimiter */
 119.159 +				/* all done with decoded text */
 119.160 +	fs_give ((void **) &txt.data);
 119.161 +	s = te+1;		/* continue scan after encoded word */
 119.162 +				/* skip leading whitespace */
 119.163 +	for (t = s + 1; (t < se) && ((*t == ' ') || (*t == '\t')); t++);
 119.164 +				/* see if likely continuation encoded word */
 119.165 +	if (t < (se - MINENCWORD)) switch (*t) {
 119.166 +	case '=':		/* possible encoded word? */
 119.167 +	  if (t[1] == '?') s = t - 1;
 119.168 +	  break;
 119.169 +	case '\015':		/* CR, eat a following LF */
 119.170 +	  if (t[1] == '\012') t++;
 119.171 +	case '\012':		/* possible end of logical line */
 119.172 +	  if ((t[1] == ' ') || (t[1] == '\t')) {
 119.173 +	    do t++;
 119.174 +	    while ((t < (se - MINENCWORD)) && ((t[1] == ' ')||(t[1] == '\t')));
 119.175 +	    if ((t < (se - MINENCWORD)) && (t[1] == '=') && (t[2] == '?'))
 119.176 +	      s = t;		/* definitely looks like continuation */
 119.177 +	  }
 119.178 +	}
 119.179 +      }
 119.180 +      else {			/* restore original text */
 119.181 +	if (dst->data) fs_give ((void **) &dst->data);
 119.182 +	dst->data = src->data;
 119.183 +	dst->size = src->size;
 119.184 +	return NIL;		/* syntax error: MIME-2 decoding failure */
 119.185 +      }
 119.186 +    }
 119.187 +    else do if (dst->data) {	/* stash ASCII characters until LWSP */
 119.188 +      if (dsize < (dst->size + FUZZ)) {
 119.189 +	dsize += DSIZE;		/* kick it up */
 119.190 +	fs_resize ((void **) &dst->data,dsize);
 119.191 +      }
 119.192 +      /* kludge: assumes ASCII doesn't decompose and titlecases to one byte */
 119.193 +      dst->data[dst->size++] = (flags & U8T_CASECANON) ?
 119.194 +	(unsigned char) ucs4_titlecase (*s) : *s;
 119.195 +    }
 119.196 +    while ((*s != ' ') && (*s != '\t') && (*s != '\015') && (*s != '\012') &&
 119.197 +	   (++s < se));
 119.198 +  }
 119.199 +  if (dst->data) dst->data[dst->size] = '\0';
 119.200 +  else {			/* nothing converted, return identity */
 119.201 +    dst->data = src->data;
 119.202 +    dst->size = src->size;
 119.203 +  }
 119.204 +  return T;			/* success */
 119.205 +}
 119.206 +
 119.207 +/* Decode MIME-2 text
 119.208 + * Accepts: Encoding
 119.209 + *	    text
 119.210 + *	    text end
 119.211 + *	    destination sized text
 119.212 + * Returns: T if successful, else NIL
 119.213 + */
 119.214 +
 119.215 +long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te,
 119.216 +		   SIZEDTEXT *txt)
 119.217 +{
 119.218 +  unsigned char *q;
 119.219 +  txt->data = NIL;		/* initially no returned data */
 119.220 +  switch (*e) {			/* dispatch based upon encoding */
 119.221 +  case 'Q': case 'q':		/* sort-of QUOTED-PRINTABLE */
 119.222 +    txt->data = (unsigned char *) fs_get ((size_t) (te - t) + 1);
 119.223 +    for (q = t,txt->size = 0; q < te; q++) switch (*q) {
 119.224 +    case '=':			/* quoted character */
 119.225 +				/* both must be hex */
 119.226 +      if (!isxdigit (q[1]) || !isxdigit (q[2])) {
 119.227 +	fs_give ((void **) &txt->data);
 119.228 +	return NIL;		/* syntax error: bad quoted character */
 119.229 +      }
 119.230 +				/* assemble character */
 119.231 +      txt->data[txt->size++] = hex2byte (q[1],q[2]);
 119.232 +      q += 2;			/* advance past quoted character */
 119.233 +      break;
 119.234 +    case '_':			/* convert to space */
 119.235 +      txt->data[txt->size++] = ' ';
 119.236 +      break;
 119.237 +    default:			/* ordinary character */
 119.238 +      txt->data[txt->size++] = *q;
 119.239 +      break;
 119.240 +    }
 119.241 +    txt->data[txt->size] = '\0';
 119.242 +    break;
 119.243 +  case 'B': case 'b':		/* BASE64 */
 119.244 +    if (txt->data = (unsigned char *) rfc822_base64 (t,te - t,&txt->size))
 119.245 +      break;
 119.246 +  default:			/* any other encoding is unknown */
 119.247 +    return NIL;			/* syntax error: unknown encoding */
 119.248 +  }
 119.249 +  return T;
 119.250 +}
 119.251 +
 119.252 +/* Get MIME-2 token from encoded word
 119.253 + * Accepts: current text pointer
 119.254 + *	    text limit pointer
 119.255 + *	    pointer to returned end pointer
 119.256 + * Returns: current text pointer & end pointer if success, else NIL
 119.257 + */
 119.258 +
 119.259 +unsigned char *mime2_token (unsigned char *s,unsigned char *se,
 119.260 +			    unsigned char **t)
 119.261 +{
 119.262 +  for (*t = s; **t != '?'; ++*t) {
 119.263 +    if ((*t < se) && isgraph (**t)) switch (**t) {
 119.264 +    case '(': case ')': case '<': case '>': case '@': case ',': case ';':
 119.265 +    case ':': case '\\': case '"': case '/': case '[': case ']': case '.':
 119.266 +    case '=':
 119.267 +      return NIL;		/* none of these are valid in tokens */
 119.268 +    }
 119.269 +    else return NIL;		/* out of text or CTL or space */
 119.270 +  }
 119.271 +  return s;
 119.272 +}
 119.273 +
 119.274 +
 119.275 +/* Get MIME-2 text from encoded word
 119.276 + * Accepts: current text pointer
 119.277 + *	    text limit pointer
 119.278 + *	    pointer to returned end pointer
 119.279 + * Returns: end pointer if success, else NIL
 119.280 + */
 119.281 +
 119.282 +unsigned char *mime2_text (unsigned char *s,unsigned char *se)
 119.283 +{
 119.284 +  unsigned char *t = se - 1;
 119.285 +				/* search for closing ?, make sure valid */
 119.286 +  while ((s < t) && (*s != '?') && isgraph (*s++));
 119.287 +  return ((s < t) && (*s == '?') && (s[1] == '=') &&
 119.288 +	  ((se == (s + 2)) || (s[2] == ' ') || (s[2] == '\t') ||
 119.289 +	   (s[2] == '\015') || (s[2] == '\012'))) ? s : NIL;
 119.290 +}
 119.291 +
 119.292 +/* Convert UTF-16 string to Modified Base64
 119.293 + * Accepts: destination pointer
 119.294 + *	    source string
 119.295 + *	    source length in octets
 119.296 + * Returns: updated destination pointer
 119.297 + */
 119.298 +
 119.299 +static unsigned char *utf16_to_mbase64 (unsigned char *t,unsigned char *s,
 119.300 +					size_t i)
 119.301 +{
 119.302 +  char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
 119.303 +  *t++ = '&';			/* write shift-in */
 119.304 +  while (i >= 3) {		/* process tuplets */
 119.305 +    *t++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
 119.306 +				/* byte 2: low 2 bits (1), high 4 bits (2) */
 119.307 +    *t++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f];
 119.308 +				/* byte 3: low 4 bits (2), high 2 bits (3) */
 119.309 +    *t++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f];
 119.310 +    *t++ = v[s[2] & 0x3f];	/* byte 4: low 6 bits (3) */
 119.311 +    s += 3;
 119.312 +    i -= 3;
 119.313 +  }
 119.314 +  if (i) {
 119.315 +    *t++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
 119.316 +				/* byte 2: low 2 bits (1), high 4 bits (2) */
 119.317 +    *t++ = v[((s[0] << 4) + (--i ? (s[1] >> 4) : 0)) & 0x3f];
 119.318 +				/* byte 3: low 4 bits (2) */
 119.319 +    if (i) *t++ = v[(s[1] << 2) & 0x3f];
 119.320 +  }
 119.321 +  *t++ = '-';			/* write shift-out */
 119.322 +  return t;
 119.323 +}
 119.324 +
 119.325 +
 119.326 +/* Poot a UTF-16 value to a buffer
 119.327 + * Accepts: buffer pointer
 119.328 + *	    value
 119.329 + * Returns: updated pointer
 119.330 + */
 119.331 +
 119.332 +static unsigned char *utf16_poot (unsigned char *s,unsigned long c)
 119.333 +{
 119.334 +  *s++ = (unsigned char) (c >> 8);
 119.335 +  *s++ = (unsigned char) (c & 0xff);
 119.336 +  return s;
 119.337 +}
 119.338 +
 119.339 +/* Convert UTF-8 to Modified UTF-7
 119.340 + * Accepts: UTF-8 string
 119.341 + * Returns: Modified UTF-7 string on success, NIL if invalid UTF-8
 119.342 + */
 119.343 +
 119.344 +#define MAXUNIUTF8 4		/* maximum length of Unicode UTF-8 sequence */
 119.345 +
 119.346 +unsigned char *utf8_to_mutf7 (unsigned char *src)
 119.347 +{
 119.348 +  unsigned char *u16buf,*utf16;
 119.349 +  unsigned char *ret,*t;
 119.350 +  unsigned long j,c;
 119.351 +  unsigned char *s = src;
 119.352 +  unsigned long i = 0;
 119.353 +  int nonascii = 0;
 119.354 +  while (*s) {			/* pass one: count destination octets */
 119.355 +    if (*s & 0x80) {		/* non-ASCII character? */
 119.356 +      j = MAXUNIUTF8;		/* get single UCS-4 codepoint */
 119.357 +      if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL;
 119.358 +				/* tally number of UTF-16 octets */
 119.359 +      nonascii += (c & U8GM_NONBMP) ? 4 : 2;
 119.360 +    }
 119.361 +    else {			/* ASCII character */
 119.362 +      if (nonascii) {		/* add pending Modified BASE64 size + shifts */
 119.363 +	i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2;
 119.364 +	nonascii = 0;		/* back to ASCII */
 119.365 +      }
 119.366 +      if (*s == '&') i += 2;	/* two octets if the escape */
 119.367 +      else ++i;			/* otherwise just count another octet */
 119.368 +      ++s;			/* advance to next source octet */
 119.369 +    }
 119.370 +  }
 119.371 +  if (nonascii)			/* add pending Modified BASE64 size + shifts */
 119.372 +    i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2;
 119.373 +
 119.374 +				/* create return buffer */
 119.375 +  t = ret = (unsigned char *) fs_get (i + 1);
 119.376 +				/* and scratch buffer */
 119.377 +  utf16 = u16buf = (unsigned char *) fs_get (i + 1);
 119.378 +  for (s = src; *s;) {		/* pass two: copy destination octets */
 119.379 +    if (*s & 0x80) {		/* non-ASCII character? */
 119.380 +      j = MAXUNIUTF8;		/* get single UCS-4 codepoint */
 119.381 +      if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL;
 119.382 +      if (c & U8GM_NONBMP) {	/* non-BMP? */
 119.383 +	c -= UTF16_BASE;	/* yes, convert to surrogate */
 119.384 +	utf16 = utf16_poot (utf16_poot (utf16,(c >> UTF16_SHIFT)+UTF16_SURRH),
 119.385 +			    (c & UTF16_MASK) + UTF16_SURRL);
 119.386 +      }
 119.387 +      else utf16 = utf16_poot (utf16,c);
 119.388 +    }
 119.389 +    else {			/* ASCII character */
 119.390 +      if (utf16 != u16buf) {	/* add pending Modified BASE64 size + shifts */
 119.391 +	t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf);
 119.392 +	utf16 = u16buf;		/* reset buffer */
 119.393 +      }
 119.394 +      *t++ = *s;		/* copy the character */
 119.395 +      if (*s == '&') *t++ = '-';/* special sequence if the escape */
 119.396 +      ++s;			/* advance to next source octet */
 119.397 +    }
 119.398 +  }
 119.399 +				/* add pending Modified BASE64 size + shifts */
 119.400 +  if (utf16 != u16buf) t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf);
 119.401 +  *t = '\0';			/* tie off destination */
 119.402 +  if (i != (t - ret)) fatal ("utf8_to_mutf7 botch");
 119.403 +  fs_give ((void **) &u16buf);
 119.404 +  return ret;
 119.405 +}
 119.406 +
 119.407 +/* Convert Modified UTF-7 to UTF-8
 119.408 + * Accepts: Modified UTF-7 string
 119.409 + * Returns: UTF-8 string on success, NIL if invalid Modified UTF-7
 119.410 + */
 119.411 +
 119.412 +unsigned char *utf8_from_mutf7 (unsigned char *src)
 119.413 +{
 119.414 +  SIZEDTEXT utf8,utf7;
 119.415 +  unsigned char *s;
 119.416 +  int mbase64 = 0;
 119.417 +				/* disallow bogus strings */
 119.418 +  if (mail_utf7_valid (src)) return NIL;
 119.419 +				/* initialize SIZEDTEXTs */
 119.420 +  memset (&utf7,0,sizeof (SIZEDTEXT));
 119.421 +  memset (&utf8,0,sizeof (SIZEDTEXT));
 119.422 +				/* make copy of source */
 119.423 +  for (s = cpytxt (&utf7,src,strlen (src)); *s; ++s) switch (*s) {
 119.424 +  case '&':			/* Modified UTF-7 uses & instead of + */
 119.425 +    *s = '+';
 119.426 +    mbase64 = T;		/* note that we are in Modified BASE64 */
 119.427 +    break;
 119.428 +  case '+':			/* temporarily swap text + to & */
 119.429 +    if (!mbase64) *s = '&';
 119.430 +    break;
 119.431 +  case '-':			/* shift back to ASCII */
 119.432 +    mbase64 = NIL;
 119.433 +    break;
 119.434 +  case ',':			/* Modified UTF-7 uses , instead of / ... */
 119.435 +    if (mbase64) *s = '/';	/* ...in Modified BASE64 */
 119.436 +    break;
 119.437 +  }
 119.438 +				/* do the conversion */
 119.439 +  utf8_text_utf7 (&utf7,&utf8,NIL,NIL);
 119.440 +				/* no longer need copy of source */
 119.441 +  fs_give ((void **) &utf7.data);
 119.442 +				/* post-process: switch & and + */
 119.443 +  for (s = utf8.data; *s; ++s) switch (*s) {
 119.444 +  case '&':
 119.445 +    *s = '+';
 119.446 +    break;
 119.447 +  case '+':
 119.448 +    *s = '&';
 119.449 +    break;
 119.450 +  }
 119.451 +  return utf8.data;
 119.452 +}
   120.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   120.2 +++ b/src/c-client/utf8aux.h	Mon Sep 14 15:17:45 2009 +0900
   120.3 @@ -0,0 +1,44 @@
   120.4 +/* ========================================================================
   120.5 + * Copyright 1988-2007 University of Washington
   120.6 + *
   120.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   120.8 + * you may not use this file except in compliance with the License.
   120.9 + * You may obtain a copy of the License at
  120.10 + *
  120.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  120.12 + *
  120.13 + * 
  120.14 + * ========================================================================
  120.15 + */
  120.16 +
  120.17 +/*
  120.18 + * Program:	UTF-8 auxillary routines (c-client and MIME2 support)
  120.19 + *
  120.20 + * Author:	Mark Crispin
  120.21 + *		Networks and Distributed Computing
  120.22 + *		Computing & Communications
  120.23 + *		University of Washington
  120.24 + *		Administration Building, AG-44
  120.25 + *		Seattle, WA  98195
  120.26 + *		Internet: MRC@CAC.Washington.EDU
  120.27 + *
  120.28 + * Date:	11 June 1997
  120.29 + * Last Edited:	9 October 2007
  120.30 + */
  120.31 +
  120.32 +
  120.33 +/* Following routines are in utf8aux.c as these depend upon c-client.
  120.34 + * Splitting these routines out makes it possible for pico to link with utf8.o
  120.35 + * and a few rump routines (e.g., fs_get()) but not all the rest of c-client
  120.36 + * (which pico does not need).
  120.37 + */
  120.38 +
  120.39 +void utf8_searchpgm (SEARCHPGM *pgm,char *charset);
  120.40 +long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags);
  120.41 +unsigned char *mime2_token (unsigned char *s,unsigned char *se,
  120.42 +			    unsigned char **t);
  120.43 +unsigned char *mime2_text (unsigned char *s,unsigned char *se);
  120.44 +long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te,
  120.45 +		   SIZEDTEXT *txt);
  120.46 +unsigned char *utf8_to_mutf7 (unsigned char *src);
  120.47 +unsigned char *utf8_from_mutf7 (unsigned char *src);
   121.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.2 +++ b/src/charset/big5.c	Mon Sep 14 15:17:45 2009 +0900
   121.3 @@ -0,0 +1,2016 @@
   121.4 +/* ========================================================================
   121.5 + * Copyright 1988-2006 University of Washington
   121.6 + *
   121.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   121.8 + * you may not use this file except in compliance with the License.
   121.9 + * You may obtain a copy of the License at
  121.10 + *
  121.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  121.12 + *
  121.13 + * 
  121.14 + * ========================================================================
  121.15 + */
  121.16 +
  121.17 +/*
  121.18 + * Program:	BIG-5 conversion table
  121.19 + *
  121.20 + * Author:	Mark Crispin
  121.21 + *		Networks and Distributed Computing
  121.22 + *		Computing & Communications
  121.23 + *		University of Washington
  121.24 + *		Administration Building, AG-44
  121.25 + *		Seattle, WA  98195
  121.26 + *		Internet: MRC@CAC.Washington.EDU
  121.27 + *
  121.28 + * Date:	3 July 1997
  121.29 + * Last Edited:	30 August 2006
  121.30 + */
  121.31 +
  121.32 +/* Big-5 is the de-facto industrial standard of the Republic of China
  121.33 + * (Taiwan), and is commonly used in the Hong Kong Special Administrative
  121.34 + * Region of the People's Republic of China (mainland China).
  121.35 + */
  121.36 +
  121.37 +#define BASE_BIG5_KU 0xa1
  121.38 +#define BASE_BIG5_TEN_0 0x40
  121.39 +#define BASE_BIG5_TEN_1 0xa1
  121.40 +#define MAX_BIG5_KU 89
  121.41 +#define MAX_BIG5_TEN_0 63
  121.42 +#define MAX_BIG5_TEN_1 94
  121.43 +
  121.44 +
  121.45 +#define BIG5TOUNICODE(c,c1,ku,ten)			\
  121.46 +  (((ku = c - BASE_BIG5_KU) < MAX_BIG5_KU) ?		\
  121.47 +   ((c1 & 0x80) ?					\
  121.48 +    (((ten = c1 - BASE_BIG5_TEN_1) < MAX_BIG5_TEN_1) ?	\
  121.49 +     big5tab[ku].plane1[ten] : UBOGON) :		\
  121.50 +    (((ten = c1 - BASE_BIG5_TEN_0) < MAX_BIG5_TEN_0) ?	\
  121.51 +     big5tab[ku].plane0[ten] : UBOGON)) : UBOGON)
  121.52 +
  121.53 +
  121.54 +typedef struct big5_ku {
  121.55 +  unsigned short plane0[MAX_BIG5_TEN_0];
  121.56 +  unsigned short plane1[MAX_BIG5_TEN_1];
  121.57 +} BIG5;
  121.58 +
  121.59 +
  121.60 +static const BIG5 big5tab[MAX_BIG5_KU] = {
  121.61 +  {				/* ku 01 */
  121.62 +    {
  121.63 +      0x3000,0xff0c,0x3001,0x3002,0xff0e,0x2022,0xff1b,0xff1a,0xff1f,0xff01,
  121.64 +      0xfe30,0x2026,0x2025,0xfe50,0xff64,0xfe52,0x00b7,0xfe54,0xfe55,0xfe56,
  121.65 +      0xfe57,0xff5c,0x2013,0xfe31,0x2014,0xfe33,0xfffd,0xfe34,0xfe4f,0xff08,
  121.66 +      0xff09,0xfe35,0xfe36,0xff5b,0xff5d,0xfe37,0xfe38,0x3014,0x3015,0xfe39,
  121.67 +      0xfe3a,0x3010,0x3011,0xfe3b,0xfe3c,0x300a,0x300b,0xfe3d,0xfe3e,0x3008,
  121.68 +      0x3009,0xfe3f,0xfe40,0x300c,0x300d,0xfe41,0xfe42,0x300e,0x300f,0xfe43,
  121.69 +      0xfe44,0xfe59,0xfe5a
  121.70 +    },{
  121.71 +      0xfe5b,0xfe5c,0xfe5d,0xfe5e,0x2018,0x2019,0x201c,0x201d,0x301d,0x301e,
  121.72 +      0x2035,0x2032,0xff03,0xff06,0xff0a,0x203b,0x00a7,0x3003,0x25cb,0x25cf,
  121.73 +      0x25b3,0x25b2,0x25ce,0x2606,0x2605,0x25c7,0x25c6,0x25a1,0x25a0,0x25bd,
  121.74 +      0x25bc,0x32a3,0x2105,0x203e,0xfffd,0xff3f,0xfffd,0xfe49,0xfe4a,0xfe4d,
  121.75 +      0xfe4e,0xfe4b,0xfe4c,0xfe5f,0xfe60,0xfe61,0xff0b,0xff0d,0x00d7,0x00f7,
  121.76 +      0x00b1,0x221a,0xff1c,0xff1e,0xff1d,0x2266,0x2267,0x2260,0x221e,0x2252,
  121.77 +      0x2261,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0x223c,0x2229,0x222a,0x22a5,
  121.78 +      0x2220,0x221f,0x22bf,0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640,
  121.79 +      0x2642,0x2641,0x2609,0x2191,0x2193,0x2190,0x2192,0x2196,0x2197,0x2199,
  121.80 +      0x2198,0x2225,0x2223,0xfffd
  121.81 +    }
  121.82 +  },
  121.83 +  {				/* ku 02 */
  121.84 +    {
  121.85 +      0xfffd,0xff0f,0xff3c,0xff04,0x00a5,0x3012,0x00a2,0x00a3,0xff05,0xff20,
  121.86 +      0x2103,0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c,0x339d,0x339e,0x33ce,
  121.87 +      0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b,0x515e,0x515d,0x5161,
  121.88 +      0x5163,0x55e7,0x74e9,0x7cce,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,
  121.89 +      0x2587,0x2588,0x258f,0x258e,0x258d,0x258c,0x258b,0x258a,0x2589,0x253c,
  121.90 +      0x2534,0x252c,0x2524,0x251c,0x2594,0x2500,0x2502,0x2595,0x250c,0x2510,
  121.91 +      0x2514,0x2518,0x256d
  121.92 +    },{
  121.93 +      0x256e,0x2570,0x256f,0x2550,0x255e,0x256a,0x2561,0x25e2,0x25e3,0x25e5,
  121.94 +      0x25e4,0x2571,0x2572,0x2573,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,
  121.95 +      0xff16,0xff17,0xff18,0xff19,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,
  121.96 +      0x2166,0x2167,0x2168,0x2169,0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,
  121.97 +      0x3027,0x3028,0x3029,0xfffd,0x5344,0xfffd,0xff21,0xff22,0xff23,0xff24,
  121.98 +      0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,
  121.99 +      0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,
 121.100 +      0xff39,0xff3a,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,
 121.101 +      0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,
 121.102 +      0xff53,0xff54,0xff55,0xff56
 121.103 +    }
 121.104 +  },
 121.105 +  {				/* ku 03 */
 121.106 +    {
 121.107 +      0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
 121.108 +      0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
 121.109 +      0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,
 121.110 +      0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,
 121.111 +      0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
 121.112 +      0x03c8,0x03c9,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,0x310b,0x310c,
 121.113 +      0x310d,0x310e,0x310f
 121.114 +    },{
 121.115 +      0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,
 121.116 +      0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,
 121.117 +      0x3124,0x3125,0x3126,0x3127,0x3128,0x3129,0x02d9,0x02c9,0x02ca,0x02c7,
 121.118 +      0x02cb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.119 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.120 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.121 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.122 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.123 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.124 +      UBOGON,UBOGON,UBOGON,UBOGON
 121.125 +    }
 121.126 +  },
 121.127 +  {				/* ku 04 */
 121.128 +    {
 121.129 +      0x4e00,0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba,0x513f,
 121.130 +      0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315,0x5341,0x535c,0x53c8,
 121.131 +      0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b,0x4e38,0x51e1,0x4e45,0x4e48,0x4e5f,
 121.132 +      0x4e5e,0x4e8e,0x4ea1,0x5140,0x5203,0x52fa,0x5343,0x53c9,0x53e3,0x571f,
 121.133 +      0x58eb,0x5915,0x5927,0x5973,0x5b50,0x5b51,0x5b53,0x5bf8,0x5c0f,0x5c22,
 121.134 +      0x5c38,0x5c71,0x5ddd,0x5de5,0x5df1,0x5df2,0x5df3,0x5dfe,0x5e72,0x5efe,
 121.135 +      0x5f0b,0x5f13,0x624d
 121.136 +    },{
 121.137 +      0x4e11,0x4e10,0x4e0d,0x4e2d,0x4e30,0x4e39,0x4e4b,0x5c39,0x4e88,0x4e91,
 121.138 +      0x4e95,0x4e92,0x4e94,0x4ea2,0x4ec1,0x4ec0,0x4ec3,0x4ec6,0x4ec7,0x4ecd,
 121.139 +      0x4eca,0x4ecb,0x4ec4,0x5143,0x5141,0x5167,0x516d,0x516e,0x516c,0x5197,
 121.140 +      0x51f6,0x5206,0x5207,0x5208,0x52fb,0x52fe,0x52ff,0x5316,0x5339,0x5348,
 121.141 +      0x5347,0x5345,0x535e,0x5384,0x53cb,0x53ca,0x53cd,0x58ec,0x5929,0x592b,
 121.142 +      0x592a,0x592d,0x5b54,0x5c11,0x5c24,0x5c3a,0x5c6f,0x5df4,0x5e7b,0x5eff,
 121.143 +      0x5f14,0x5f15,0x5fc3,0x6208,0x6236,0x624b,0x624e,0x652f,0x6587,0x6597,
 121.144 +      0x65a4,0x65b9,0x65e5,0x66f0,0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb,
 121.145 +      0x6bd4,0x6bdb,0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259,
 121.146 +      0x725b,0x72ac,0x738b,0x4e19
 121.147 +    }
 121.148 +  },
 121.149 +  {				/* ku 05 */
 121.150 +    {
 121.151 +      0x4e16,0x4e15,0x4e14,0x4e18,0x4e3b,0x4e4d,0x4e4f,0x4e4e,0x4ee5,0x4ed8,
 121.152 +      0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9,0x4ede,0x5145,0x5144,
 121.153 +      0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a,0x52a0,0x529f,0x5305,
 121.154 +      0x5306,0x5317,0x531d,0x4edf,0x534a,0x5349,0x5361,0x5360,0x536f,0x536e,
 121.155 +      0x53bb,0x53ef,0x53e4,0x53f3,0x53ec,0x53ee,0x53e9,0x53e8,0x53fc,0x53f8,
 121.156 +      0x53f5,0x53eb,0x53e6,0x53ea,0x53f2,0x53f1,0x53f0,0x53e5,0x53ed,0x53fb,
 121.157 +      0x56db,0x56da,0x5916
 121.158 +    },{
 121.159 +      0x592e,0x5931,0x5974,0x5976,0x5b55,0x5b83,0x5c3c,0x5de8,0x5de7,0x5de6,
 121.160 +      0x5e02,0x5e03,0x5e73,0x5e7c,0x5f01,0x5f18,0x5f17,0x5fc5,0x620a,0x6253,
 121.161 +      0x6254,0x6252,0x6251,0x65a5,0x65e6,0x672e,0x672c,0x672a,0x672b,0x672d,
 121.162 +      0x6b63,0x6bcd,0x6c11,0x6c10,0x6c38,0x6c41,0x6c40,0x6c3e,0x72af,0x7384,
 121.163 +      0x7389,0x74dc,0x74e6,0x7518,0x751f,0x7528,0x7529,0x7530,0x7531,0x7532,
 121.164 +      0x7533,0x758b,0x767d,0x76ae,0x76bf,0x76ee,0x77db,0x77e2,0x77f3,0x793a,
 121.165 +      0x79be,0x7a74,0x7acb,0x4e1e,0x4e1f,0x4e52,0x4e53,0x4e69,0x4e99,0x4ea4,
 121.166 +      0x4ea6,0x4ea5,0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15,0x4f0d,0x4f10,0x4f11,
 121.167 +      0x4f0f,0x4ef2,0x4ef6,0x4efb,0x4ef0,0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149,
 121.168 +      0x5147,0x5146,0x5148,0x5168
 121.169 +    }
 121.170 +  },
 121.171 +  {				/* ku 06 */
 121.172 +    {
 121.173 +      0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e,0x5216,0x52a3,0x5308,
 121.174 +      0x5321,0x5320,0x5370,0x5371,0x5409,0x540f,0x540c,0x540a,0x5410,0x5401,
 121.175 +      0x540b,0x5404,0x5411,0x540d,0x5408,0x5403,0x540e,0x5406,0x5412,0x56e0,
 121.176 +      0x56de,0x56dd,0x5733,0x5730,0x5728,0x572d,0x572c,0x572f,0x5729,0x5919,
 121.177 +      0x591a,0x5937,0x5938,0x5984,0x5978,0x5983,0x597d,0x5979,0x5982,0x5981,
 121.178 +      0x5b57,0x5b58,0x5b87,0x5b88,0x5b85,0x5b89,0x5bfa,0x5c16,0x5c79,0x5dde,
 121.179 +      0x5e06,0x5e76,0x5e74
 121.180 +    },{
 121.181 +      0x5f0f,0x5f1b,0x5fd9,0x5fd6,0x620e,0x620c,0x620d,0x6210,0x6263,0x625b,
 121.182 +      0x6258,0x6536,0x65e9,0x65e8,0x65ec,0x65ed,0x66f2,0x66f3,0x6709,0x673d,
 121.183 +      0x6734,0x6731,0x6735,0x6b21,0x6b64,0x6b7b,0x6c16,0x6c5d,0x6c57,0x6c59,
 121.184 +      0x6c5f,0x6c60,0x6c50,0x6c55,0x6c61,0x6c5b,0x6c4d,0x6c4e,0x7070,0x725f,
 121.185 +      0x725d,0x767e,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f8a,0x7fbd,0x8001,0x8003,
 121.186 +      0x800c,0x8012,0x8033,0x807f,0x8089,0x808b,0x808c,0x81e3,0x81ea,0x81f3,
 121.187 +      0x81fc,0x820c,0x821b,0x821f,0x826e,0x8272,0x827e,0x866b,0x8840,0x884c,
 121.188 +      0x8863,0x897f,0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57,0x4f5e,
 121.189 +      0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a,0x4f38,0x4f43,
 121.190 +      0x4f54,0x4f3c,0x4f46,0x4f63
 121.191 +    }
 121.192 +  },
 121.193 +  {				/* ku 07 */
 121.194 +    {
 121.195 +      0x4f5c,0x4f60,0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a,0x514c,
 121.196 +      0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229,0x522a,0x5228,
 121.197 +      0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373,0x5375,0x541d,0x542d,0x541e,
 121.198 +      0x543e,0x5426,0x544e,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442,0x541b,
 121.199 +      0x5429,0x544a,0x5439,0x543b,0x5438,0x542e,0x5435,0x5436,0x5420,0x543c,
 121.200 +      0x5440,0x5431,0x542b,0x541f,0x542c,0x56ea,0x56f0,0x56e4,0x56eb,0x574a,
 121.201 +      0x5751,0x5740,0x574d
 121.202 +    },{
 121.203 +      0x5747,0x574e,0x573e,0x5750,0x574f,0x573b,0x58ef,0x593e,0x599d,0x5992,
 121.204 +      0x59a8,0x599e,0x59a3,0x5999,0x5996,0x598d,0x59a4,0x5993,0x598a,0x59a5,
 121.205 +      0x5b5d,0x5b5c,0x5b5a,0x5b5b,0x5b8c,0x5b8b,0x5b8f,0x5c2c,0x5c40,0x5c41,
 121.206 +      0x5c3f,0x5c3e,0x5c90,0x5c91,0x5c94,0x5c8c,0x5deb,0x5e0c,0x5e8f,0x5e87,
 121.207 +      0x5e8a,0x5ef7,0x5f04,0x5f1f,0x5f64,0x5f62,0x5f77,0x5f79,0x5fd8,0x5fcc,
 121.208 +      0x5fd7,0x5fcd,0x5ff1,0x5feb,0x5ff8,0x5fea,0x6212,0x6211,0x6284,0x6297,
 121.209 +      0x6296,0x6280,0x6276,0x6289,0x626d,0x628a,0x627c,0x627e,0x6279,0x6273,
 121.210 +      0x6292,0x626f,0x6298,0x626e,0x6295,0x6293,0x6291,0x6286,0x6539,0x653b,
 121.211 +      0x6538,0x65f1,0x66f4,0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756,
 121.212 +      0x675e,0x6749,0x6746,0x6760
 121.213 +    }
 121.214 +  },
 121.215 +  {				/* ku 08 */
 121.216 +    {
 121.217 +      0x6753,0x6757,0x6b65,0x6bcf,0x6c42,0x6c5e,0x6c99,0x6c81,0x6c88,0x6c89,
 121.218 +      0x6c85,0x6c9b,0x6c6a,0x6c7a,0x6c90,0x6c70,0x6c8c,0x6c68,0x6c96,0x6c92,
 121.219 +      0x6c7d,0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86,0x6c76,0x6c8d,0x6c94,0x6c98,
 121.220 +      0x6c82,0x7076,0x707c,0x707d,0x7078,0x7262,0x7261,0x7260,0x72c4,0x72c2,
 121.221 +      0x7396,0x752c,0x752b,0x7537,0x7538,0x7682,0x76ef,0x77e3,0x79c1,0x79c0,
 121.222 +      0x79bf,0x7a76,0x7cfb,0x7f55,0x8096,0x8093,0x809d,0x8098,0x809b,0x809a,
 121.223 +      0x80b2,0x826f,0x8292
 121.224 +    },{
 121.225 +      0x828b,0x828d,0x898b,0x89d2,0x8a00,0x8c37,0x8c46,0x8c55,0x8c9d,0x8d64,
 121.226 +      0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fc2,0x8fc6,0x8fc5,0x8fc4,
 121.227 +      0x5de1,0x9091,0x90a2,0x90aa,0x90a6,0x90a3,0x9149,0x91c6,0x91cc,0x9632,
 121.228 +      0x962e,0x9631,0x962a,0x962c,0x4e26,0x4e56,0x4e73,0x4e8b,0x4e9b,0x4e9e,
 121.229 +      0x4eab,0x4eac,0x4f6f,0x4f9d,0x4f8d,0x4f73,0x4f7f,0x4f6c,0x4f9b,0x4f8b,
 121.230 +      0x4f86,0x4f83,0x4f70,0x4f75,0x4f88,0x4f69,0x4f7b,0x4f96,0x4f7e,0x4f8f,
 121.231 +      0x4f91,0x4f7a,0x5154,0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51bd,
 121.232 +      0x51fd,0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236,0x5241,0x52be,
 121.233 +      0x52bb,0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,0x5378,0x5379,0x53d6,
 121.234 +      0x53d4,0x53d7,0x5473,0x5475
 121.235 +    }
 121.236 +  },
 121.237 +  {				/* ku 09 */
 121.238 +    {
 121.239 +      0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484,0x5492,0x5486,0x547c,
 121.240 +      0x5490,0x5471,0x5476,0x548c,0x549a,0x5462,0x5468,0x548b,0x547d,0x548e,
 121.241 +      0x56fa,0x5783,0x5777,0x576a,0x5769,0x5761,0x5766,0x5764,0x577c,0x591c,
 121.242 +      0x5949,0x5947,0x5948,0x5944,0x5954,0x59be,0x59bb,0x59d4,0x59b9,0x59ae,
 121.243 +      0x59d1,0x59c6,0x59d0,0x59cd,0x59cb,0x59d3,0x59ca,0x59af,0x59b3,0x59d2,
 121.244 +      0x59c5,0x5b5f,0x5b64,0x5b63,0x5b97,0x5b9a,0x5b98,0x5b9c,0x5b99,0x5b9b,
 121.245 +      0x5c1a,0x5c48,0x5c45
 121.246 +    },{
 121.247 +      0x5c46,0x5cb7,0x5ca1,0x5cb8,0x5ca9,0x5cab,0x5cb1,0x5cb3,0x5e18,0x5e1a,
 121.248 +      0x5e16,0x5e15,0x5e1b,0x5e11,0x5e78,0x5e9a,0x5e97,0x5e9c,0x5e95,0x5e96,
 121.249 +      0x5ef6,0x5f26,0x5f27,0x5f29,0x5f80,0x5f81,0x5f7f,0x5f7c,0x5fdd,0x5fe0,
 121.250 +      0x5ffd,0x5ff5,0x5fff,0x600f,0x6014,0x602f,0x6035,0x6016,0x602a,0x6015,
 121.251 +      0x6021,0x6027,0x6029,0x602b,0x601b,0x6216,0x6215,0x623f,0x623e,0x6240,
 121.252 +      0x627f,0x62c9,0x62cc,0x62c4,0x62bf,0x62c2,0x62b9,0x62d2,0x62db,0x62ab,
 121.253 +      0x62d3,0x62d4,0x62cb,0x62c8,0x62a8,0x62bd,0x62bc,0x62d0,0x62d9,0x62c7,
 121.254 +      0x62cd,0x62b5,0x62da,0x62b1,0x62d8,0x62d6,0x62d7,0x62c6,0x62ac,0x62ce,
 121.255 +      0x653e,0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606,0x6602,0x660e,
 121.256 +      0x6600,0x660f,0x6615,0x660a
 121.257 +    }
 121.258 +  },
 121.259 +  {				/* ku 0a */
 121.260 +    {
 121.261 +      0x6607,0x670d,0x670b,0x676d,0x678b,0x6795,0x6771,0x679c,0x6773,0x6777,
 121.262 +      0x6787,0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e,0x6790,0x6775,
 121.263 +      0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66,0x6b67,0x6b7f,0x6c13,
 121.264 +      0x6c1b,0x6ce3,0x6ce8,0x6cf3,0x6cb1,0x6ccc,0x6ce5,0x6cb3,0x6cbd,0x6cbe,
 121.265 +      0x6cbc,0x6ce2,0x6cab,0x6cd5,0x6cd3,0x6cb8,0x6cc4,0x6cb9,0x6cc1,0x6cae,
 121.266 +      0x6cd7,0x6cc5,0x6cf1,0x6cbf,0x6cbb,0x6ce1,0x6cdb,0x6cca,0x6cac,0x6cef,
 121.267 +      0x6cdc,0x6cd6,0x6ce0
 121.268 +    },{
 121.269 +      0x7095,0x708e,0x7092,0x708a,0x7099,0x722c,0x722d,0x7238,0x7248,0x7267,
 121.270 +      0x7269,0x72c0,0x72ce,0x72d9,0x72d7,0x72d0,0x73a9,0x73a8,0x739f,0x73ab,
 121.271 +      0x73a5,0x753d,0x759d,0x7599,0x759a,0x7684,0x76c2,0x76f2,0x76f4,0x77e5,
 121.272 +      0x77fd,0x793e,0x7940,0x7941,0x79c9,0x79c8,0x7a7a,0x7a79,0x7afa,0x7cfe,
 121.273 +      0x7f54,0x7f8c,0x7f8b,0x8005,0x80ba,0x80a5,0x80a2,0x80b1,0x80a1,0x80ab,
 121.274 +      0x80a9,0x80b4,0x80aa,0x80af,0x81e5,0x81fe,0x820d,0x82b3,0x829d,0x8299,
 121.275 +      0x82ad,0x82bd,0x829f,0x82b9,0x82b1,0x82ac,0x82a5,0x82af,0x82b8,0x82a3,
 121.276 +      0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d,0x8868,0x8ecb,0x8fce,0x8fd4,
 121.277 +      0x8fd1,0x90b5,0x90b8,0x90b1,0x90b6,0x91c7,0x91d1,0x9577,0x9580,0x961c,
 121.278 +      0x9640,0x963f,0x963b,0x9644
 121.279 +    }
 121.280 +  },
 121.281 +  {				/* ku 0b */
 121.282 +    {
 121.283 +      0x9642,0x96b9,0x96e8,0x9752,0x975e,0x4e9f,0x4ead,0x4eae,0x4fe1,0x4fb5,
 121.284 +      0x4faf,0x4fbf,0x4fe0,0x4fd1,0x4fcf,0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf,
 121.285 +      0x4fca,0x4fd7,0x4fae,0x4fd0,0x4fc4,0x4fc2,0x4fda,0x4fce,0x4fde,0x4fb7,
 121.286 +      0x5157,0x5192,0x5191,0x51a0,0x524e,0x5243,0x524a,0x524d,0x524c,0x524b,
 121.287 +      0x5247,0x52c7,0x52c9,0x52c3,0x52c1,0x530d,0x5357,0x537b,0x539a,0x53db,
 121.288 +      0x54ac,0x54c0,0x54a8,0x54ce,0x54c9,0x54b8,0x54a6,0x54b3,0x54c7,0x54c2,
 121.289 +      0x54bd,0x54aa,0x54c1
 121.290 +    },{
 121.291 +      0x54c4,0x54c8,0x54af,0x54ab,0x54b1,0x54bb,0x54a9,0x54a7,0x54bf,0x56ff,
 121.292 +      0x5782,0x578b,0x57a0,0x57a3,0x57a2,0x57ce,0x57ae,0x5793,0x5955,0x5951,
 121.293 +      0x594f,0x594e,0x5950,0x59dc,0x59d8,0x59ff,0x59e3,0x59e8,0x5a03,0x59e5,
 121.294 +      0x59ea,0x59da,0x59e6,0x5a01,0x59fb,0x5b69,0x5ba3,0x5ba6,0x5ba4,0x5ba2,
 121.295 +      0x5ba5,0x5c01,0x5c4e,0x5c4f,0x5c4d,0x5c4b,0x5cd9,0x5cd2,0x5df7,0x5e1d,
 121.296 +      0x5e25,0x5e1f,0x5e7d,0x5ea0,0x5ea6,0x5efa,0x5f08,0x5f2d,0x5f65,0x5f88,
 121.297 +      0x5f85,0x5f8a,0x5f8b,0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025,
 121.298 +      0x600e,0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c,0x606b,
 121.299 +      0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc,0x62ed,0x6301,0x62ee,
 121.300 +      0x62fd,0x6307,0x62f1,0x62f7
 121.301 +    }
 121.302 +  },
 121.303 +  {				/* ku 0c */
 121.304 +    {
 121.305 +      0x62ef,0x62ec,0x62fe,0x62f4,0x6311,0x6302,0x653f,0x6545,0x65ab,0x65bd,
 121.306 +      0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f,0x661f,0x6628,0x6631,0x6624,
 121.307 +      0x66f7,0x67ff,0x67d3,0x67f1,0x67d4,0x67d0,0x67ec,0x67b6,0x67af,0x67f5,
 121.308 +      0x67e9,0x67ef,0x67c4,0x67d1,0x67b4,0x67da,0x67e5,0x67b8,0x67cf,0x67de,
 121.309 +      0x67f3,0x67b0,0x67d9,0x67e2,0x67dd,0x67d2,0x6b6a,0x6b83,0x6b86,0x6bb5,
 121.310 +      0x6bd2,0x6bd7,0x6c1f,0x6cc9,0x6d0b,0x6d32,0x6d2a,0x6d41,0x6d25,0x6d0c,
 121.311 +      0x6d31,0x6d1e,0x6d17
 121.312 +    },{
 121.313 +      0x6d3b,0x6d3d,0x6d3e,0x6d36,0x6d1b,0x6cf5,0x6d39,0x6d27,0x6d38,0x6d29,
 121.314 +      0x6d2e,0x6d35,0x6d0e,0x6d2b,0x70ab,0x70ba,0x70b3,0x70ac,0x70af,0x70ad,
 121.315 +      0x70b8,0x70ae,0x70a4,0x7230,0x7272,0x726f,0x7274,0x72e9,0x72e0,0x72e1,
 121.316 +      0x73b7,0x73ca,0x73bb,0x73b2,0x73cd,0x73c0,0x73b3,0x751a,0x752d,0x754f,
 121.317 +      0x754c,0x754e,0x754b,0x75ab,0x75a4,0x75a5,0x75a2,0x75a3,0x7678,0x7686,
 121.318 +      0x7687,0x7688,0x76c8,0x76c6,0x76c3,0x76c5,0x7701,0x76f9,0x76f8,0x7709,
 121.319 +      0x770b,0x76fe,0x76fc,0x7707,0x77dc,0x7802,0x7814,0x780c,0x780d,0x7946,
 121.320 +      0x7949,0x7948,0x7947,0x79b9,0x79ba,0x79d1,0x79d2,0x79cb,0x7a7f,0x7a81,
 121.321 +      0x7aff,0x7afd,0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09,0x7d07,0x7d04,0x7d06,
 121.322 +      0x7f38,0x7f8e,0x7fbf,0x8004
 121.323 +    }
 121.324 +  },
 121.325 +  {				/* ku 0d */
 121.326 +    {
 121.327 +      0x8010,0x800d,0x8011,0x8036,0x80d6,0x80e5,0x80da,0x80c3,0x80c4,0x80cc,
 121.328 +      0x80e1,0x80db,0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222,0x82e7,0x8303,
 121.329 +      0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309,0x82d2,0x82d7,
 121.330 +      0x82f1,0x8301,0x82dc,0x82d4,0x82d1,0x82de,0x82d3,0x82df,0x82ef,0x8306,
 121.331 +      0x8650,0x8679,0x867b,0x867a,0x884d,0x886b,0x8981,0x89d4,0x8a08,0x8a02,
 121.332 +      0x8a03,0x8c9e,0x8ca0,0x8d74,0x8d73,0x8db4,0x8ecd,0x8ecc,0x8ff0,0x8fe6,
 121.333 +      0x8fe2,0x8fea,0x8fe5
 121.334 +    },{
 121.335 +      0x8fed,0x8feb,0x8fe4,0x8fe8,0x90ca,0x90ce,0x90c1,0x90c3,0x914b,0x914a,
 121.336 +      0x91cd,0x9582,0x9650,0x964b,0x964c,0x964d,0x9762,0x9769,0x97cb,0x97ed,
 121.337 +      0x97f3,0x9801,0x98a8,0x98db,0x98df,0x9996,0x9999,0x4e58,0x4eb3,0x500c,
 121.338 +      0x500d,0x5023,0x4fef,0x5026,0x5025,0x4ff8,0x5029,0x5016,0x5006,0x503c,
 121.339 +      0x501f,0x501a,0x5012,0x5011,0x4ffa,0x5000,0x5014,0x5028,0x4ff1,0x5021,
 121.340 +      0x500b,0x5019,0x5018,0x4ff3,0x4fee,0x502d,0x502a,0x4ffe,0x502b,0x5009,
 121.341 +      0x517c,0x51a4,0x51a5,0x51a2,0x51cd,0x51cc,0x51c6,0x51cb,0x5256,0x525c,
 121.342 +      0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d,0x53df,0x54e8,0x5510,
 121.343 +      0x5501,0x5537,0x54fc,0x54e5,0x54f2,0x5506,0x54fa,0x5514,0x54e9,0x54ed,
 121.344 +      0x54e1,0x5509,0x54ee,0x54ea
 121.345 +    }
 121.346 +  },
 121.347 +  {				/* ku 0e */
 121.348 +    {
 121.349 +      0x54e6,0x5527,0x5507,0x54fd,0x550f,0x5703,0x5704,0x57c2,0x57d4,0x57cb,
 121.350 +      0x57c3,0x5809,0x590f,0x5957,0x5958,0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f,
 121.351 +      0x5a1b,0x5a13,0x59ec,0x5a20,0x5a23,0x5a29,0x5a25,0x5a0c,0x5a09,0x5b6b,
 121.352 +      0x5c58,0x5bb0,0x5bb3,0x5bb6,0x5bb4,0x5bae,0x5bb5,0x5bb9,0x5bb8,0x5c04,
 121.353 +      0x5c51,0x5c55,0x5c50,0x5ced,0x5cfd,0x5cfb,0x5cea,0x5ce8,0x5cf0,0x5cf6,
 121.354 +      0x5d01,0x5cf4,0x5dee,0x5e2d,0x5e2b,0x5eab,0x5ead,0x5ea7,0x5f31,0x5f92,
 121.355 +      0x5f91,0x5f90,0x6059
 121.356 +    },{
 121.357 +      0x6063,0x6065,0x6050,0x6055,0x606d,0x6069,0x606f,0x6084,0x609f,0x609a,
 121.358 +      0x608d,0x6094,0x608c,0x6085,0x6096,0x6247,0x62f3,0x6308,0x62ff,0x634e,
 121.359 +      0x633e,0x632f,0x6355,0x6342,0x6346,0x634f,0x6349,0x633a,0x6350,0x633d,
 121.360 +      0x632a,0x632b,0x6328,0x634d,0x634c,0x6548,0x6549,0x6599,0x65c1,0x65c5,
 121.361 +      0x6642,0x6649,0x664f,0x6643,0x6652,0x664c,0x6645,0x6641,0x66f8,0x6714,
 121.362 +      0x6715,0x6717,0x6821,0x6838,0x6848,0x6846,0x6853,0x6839,0x6842,0x6854,
 121.363 +      0x6829,0x68b3,0x6817,0x684c,0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c,
 121.364 +      0x6843,0x682a,0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23,
 121.365 +      0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88,0x6d87,0x6d66,
 121.366 +      0x6d78,0x6d77,0x6d59,0x6d93
 121.367 +    }
 121.368 +  },
 121.369 +  {				/* ku 0f */
 121.370 +    {
 121.371 +      0x6d6c,0x6d89,0x6d6e,0x6d5a,0x6d74,0x6d69,0x6d8c,0x6d8a,0x6d79,0x6d85,
 121.372 +      0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9,0x70c8,0x70cf,0x7239,0x7279,
 121.373 +      0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386,0x73ed,0x7409,0x73ee,0x73e0,
 121.374 +      0x73ea,0x73de,0x7554,0x755d,0x755c,0x755a,0x7559,0x75be,0x75c5,0x75c7,
 121.375 +      0x75b2,0x75b3,0x75bd,0x75bc,0x75b9,0x75c2,0x75b8,0x768b,0x76b0,0x76ca,
 121.376 +      0x76cd,0x76ce,0x7729,0x771f,0x7720,0x7728,0x77e9,0x7830,0x7827,0x7838,
 121.377 +      0x781d,0x7834,0x7837
 121.378 +    },{
 121.379 +      0x7825,0x782d,0x7820,0x781f,0x7832,0x7955,0x7950,0x7960,0x795f,0x7956,
 121.380 +      0x795e,0x795d,0x7957,0x795a,0x79e4,0x79e3,0x79e7,0x79df,0x79e6,0x79e9,
 121.381 +      0x79d8,0x7a84,0x7a88,0x7ad9,0x7b06,0x7b11,0x7c89,0x7d21,0x7d17,0x7d0b,
 121.382 +      0x7d0a,0x7d20,0x7d22,0x7d14,0x7d10,0x7d15,0x7d1a,0x7d1c,0x7d0d,0x7d19,
 121.383 +      0x7d1b,0x7f3a,0x7f5f,0x7f94,0x7fc5,0x7fc1,0x8006,0x8018,0x8015,0x8019,
 121.384 +      0x8017,0x803d,0x803f,0x80f1,0x8102,0x80f0,0x8105,0x80ed,0x80f4,0x8106,
 121.385 +      0x80f8,0x80f3,0x8108,0x80fd,0x810a,0x80fc,0x80ef,0x81ed,0x81ec,0x8200,
 121.386 +      0x8210,0x822a,0x822b,0x8228,0x822c,0x82bb,0x832b,0x8352,0x8354,0x834a,
 121.387 +      0x8338,0x8350,0x8349,0x8335,0x8334,0x834f,0x8332,0x8339,0x8336,0x8317,
 121.388 +      0x8340,0x8331,0x8328,0x8343
 121.389 +    }
 121.390 +  },
 121.391 +  {				/* ku 10 */
 121.392 +    {
 121.393 +      0x8654,0x868a,0x86aa,0x8693,0x86a4,0x86a9,0x868c,0x86a3,0x869c,0x8870,
 121.394 +      0x8877,0x8881,0x8882,0x887d,0x8879,0x8a18,0x8a10,0x8a0e,0x8a0c,0x8a15,
 121.395 +      0x8a0a,0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11,0x8c48,0x8c7a,0x8c79,0x8ca1,
 121.396 +      0x8ca2,0x8d77,0x8eac,0x8ed2,0x8ed4,0x8ecf,0x8fb1,0x9001,0x9006,0x8ff7,
 121.397 +      0x9000,0x8ffa,0x8ff4,0x9003,0x8ffd,0x9005,0x8ff8,0x9095,0x90e1,0x90dd,
 121.398 +      0x90e2,0x9152,0x914d,0x914c,0x91d8,0x91dd,0x91d7,0x91dc,0x91d9,0x9583,
 121.399 +      0x9662,0x9663,0x9661
 121.400 +    },{
 121.401 +      0x965b,0x965d,0x9664,0x9658,0x965e,0x96bb,0x98e2,0x99ac,0x9aa8,0x9ad8,
 121.402 +      0x9b25,0x9b32,0x9b3c,0x4e7e,0x507a,0x507d,0x505c,0x5047,0x5043,0x504c,
 121.403 +      0x505a,0x5049,0x5065,0x5076,0x504e,0x5055,0x5075,0x5074,0x5077,0x504f,
 121.404 +      0x500f,0x506f,0x506d,0x515c,0x5195,0x51f0,0x526a,0x526f,0x52d2,0x52d9,
 121.405 +      0x52d8,0x52d5,0x5310,0x530f,0x5319,0x533f,0x5340,0x533e,0x53c3,0x66fc,
 121.406 +      0x5546,0x556a,0x5566,0x5544,0x555e,0x5561,0x5543,0x554a,0x5531,0x5556,
 121.407 +      0x554f,0x5555,0x552f,0x5564,0x5538,0x552e,0x555c,0x552c,0x5563,0x5533,
 121.408 +      0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805,0x580a,0x5806,0x57e0,
 121.409 +      0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9,0x5920,0x5962,0x5a36,0x5a41,
 121.410 +      0x5a49,0x5a66,0x5a6a,0x5a40
 121.411 +    }
 121.412 +  },
 121.413 +  {				/* ku 11 */
 121.414 +    {
 121.415 +      0x5a3c,0x5a62,0x5a5a,0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5,0x5bc4,0x5bc2,
 121.416 +      0x5bbf,0x5bc6,0x5c09,0x5c08,0x5c07,0x5c60,0x5c5c,0x5c5d,0x5d07,0x5d06,
 121.417 +      0x5d0e,0x5d1b,0x5d16,0x5d22,0x5d11,0x5d29,0x5d14,0x5d19,0x5d24,0x5d27,
 121.418 +      0x5d17,0x5de2,0x5e38,0x5e36,0x5e33,0x5e37,0x5eb7,0x5eb8,0x5eb6,0x5eb5,
 121.419 +      0x5ebe,0x5f35,0x5f37,0x5f57,0x5f6c,0x5f69,0x5f6b,0x5f97,0x5f99,0x5f9e,
 121.420 +      0x5f98,0x5fa1,0x5fa0,0x5f9c,0x607f,0x60a3,0x6089,0x60a0,0x60a8,0x60cb,
 121.421 +      0x60b4,0x60e6,0x60bd
 121.422 +    },{
 121.423 +      0x60c5,0x60bb,0x60b5,0x60dc,0x60bc,0x60d8,0x60d5,0x60c6,0x60df,0x60b8,
 121.424 +      0x60da,0x60c7,0x621a,0x621b,0x6248,0x63a0,0x63a7,0x6372,0x6396,0x63a2,
 121.425 +      0x63a5,0x6377,0x6367,0x6398,0x63aa,0x6371,0x63a9,0x6389,0x6383,0x639b,
 121.426 +      0x636b,0x63a8,0x6384,0x6388,0x6399,0x63a1,0x63ac,0x6392,0x638f,0x6380,
 121.427 +      0x637b,0x6369,0x6368,0x637a,0x655d,0x6556,0x6551,0x6559,0x6557,0x555f,
 121.428 +      0x654f,0x6558,0x6555,0x6554,0x659c,0x659b,0x65ac,0x65cf,0x65cb,0x65cc,
 121.429 +      0x65ce,0x665d,0x665a,0x6664,0x6668,0x6666,0x665e,0x66f9,0x52d7,0x671b,
 121.430 +      0x6881,0x68af,0x68a2,0x6893,0x68b5,0x687f,0x6876,0x68b1,0x68a7,0x6897,
 121.431 +      0x68b0,0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d,0x68a8,0x689f,
 121.432 +      0x68a1,0x6882,0x6b32,0x6bba
 121.433 +    }
 121.434 +  },
 121.435 +  {				/* ku 12 */
 121.436 +    {
 121.437 +      0x6beb,0x6bec,0x6c2b,0x6d8e,0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc,
 121.438 +      0x6de4,0x6dfb,0x6dfa,0x6e05,0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae,0x6dde,
 121.439 +      0x6df9,0x6db8,0x6df7,0x6df5,0x6dc5,0x6dd2,0x6e1a,0x6db5,0x6dda,0x6deb,
 121.440 +      0x6dd8,0x6dea,0x6df1,0x6dee,0x6de8,0x6dc6,0x6dc4,0x6daa,0x6dec,0x6dbf,
 121.441 +      0x6de6,0x70f9,0x7109,0x710a,0x70fd,0x70ef,0x723d,0x727d,0x7281,0x731c,
 121.442 +      0x731b,0x7316,0x7313,0x7319,0x7387,0x7405,0x740a,0x7403,0x7406,0x73fe,
 121.443 +      0x740d,0x74e0,0x74f6
 121.444 +    },{
 121.445 +      0x74f7,0x751c,0x7522,0x7565,0x7566,0x7562,0x7570,0x758f,0x75d4,0x75d5,
 121.446 +      0x75b5,0x75ca,0x75cd,0x768e,0x76d4,0x76d2,0x76db,0x7737,0x773e,0x773c,
 121.447 +      0x7736,0x7738,0x773a,0x786b,0x7843,0x784e,0x7965,0x7968,0x796d,0x79fb,
 121.448 +      0x7a92,0x7a95,0x7b20,0x7b28,0x7b1b,0x7b2c,0x7b26,0x7b19,0x7b1e,0x7b2e,
 121.449 +      0x7c92,0x7c97,0x7c95,0x7d46,0x7d43,0x7d71,0x7d2e,0x7d39,0x7d3c,0x7d40,
 121.450 +      0x7d30,0x7d33,0x7d44,0x7d2f,0x7d42,0x7d32,0x7d31,0x7f3d,0x7f9e,0x7f9a,
 121.451 +      0x7fcc,0x7fce,0x7fd2,0x801c,0x804a,0x8046,0x812f,0x8116,0x8123,0x812b,
 121.452 +      0x8129,0x8130,0x8124,0x8202,0x8235,0x8237,0x8236,0x8239,0x838e,0x839e,
 121.453 +      0x8398,0x8378,0x83a2,0x8396,0x83bd,0x83ab,0x8392,0x838a,0x8393,0x8389,
 121.454 +      0x83a0,0x8377,0x837b,0x837c
 121.455 +    }
 121.456 +  },
 121.457 +  {				/* ku 13 */
 121.458 +    {
 121.459 +      0x8386,0x83a7,0x8655,0x5f6a,0x86c7,0x86c0,0x86b6,0x86c4,0x86b5,0x86c6,
 121.460 +      0x86cb,0x86b1,0x86af,0x86c9,0x8853,0x889e,0x8888,0x88ab,0x8892,0x8896,
 121.461 +      0x888d,0x888b,0x8993,0x898f,0x8a2a,0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d,
 121.462 +      0x8a1f,0x8a1b,0x8a22,0x8c49,0x8c5a,0x8ca9,0x8cac,0x8cab,0x8ca8,0x8caa,
 121.463 +      0x8ca7,0x8d67,0x8d66,0x8dbe,0x8dba,0x8edb,0x8edf,0x9019,0x900d,0x901a,
 121.464 +      0x9017,0x9023,0x901f,0x901d,0x9010,0x9015,0x901e,0x9020,0x900f,0x9022,
 121.465 +      0x9016,0x901b,0x9014
 121.466 +    },{
 121.467 +      0x90e8,0x90ed,0x90fd,0x9157,0x91ce,0x91f5,0x91e6,0x91e3,0x91e7,0x91ed,
 121.468 +      0x91e9,0x9589,0x966a,0x9675,0x9673,0x9678,0x9670,0x9674,0x9676,0x9677,
 121.469 +      0x966c,0x96c0,0x96ea,0x96e9,0x7ae0,0x7adf,0x9802,0x9803,0x9b5a,0x9ce5,
 121.470 +      0x9e75,0x9e7f,0x9ea5,0x9ebb,0x50a2,0x508d,0x5085,0x5099,0x5091,0x5080,
 121.471 +      0x5096,0x5098,0x509a,0x6700,0x51f1,0x5272,0x5274,0x5275,0x5269,0x52de,
 121.472 +      0x52dd,0x52db,0x535a,0x53a5,0x557b,0x5580,0x55a7,0x557c,0x558a,0x559d,
 121.473 +      0x5598,0x5582,0x559c,0x55aa,0x5594,0x5587,0x558b,0x5583,0x55b3,0x55ae,
 121.474 +      0x559f,0x553e,0x55b2,0x559a,0x55bb,0x55ac,0x55b1,0x557e,0x5589,0x55ab,
 121.475 +      0x5599,0x570d,0x582f,0x582a,0x5834,0x5824,0x5830,0x5831,0x5821,0x581d,
 121.476 +      0x5820,0x58f9,0x58fa,0x5960
 121.477 +    }
 121.478 +  },
 121.479 +  {				/* ku 14 */
 121.480 +    {
 121.481 +      0x5a77,0x5a9a,0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2,0x5bcc,
 121.482 +      0x5bd3,0x5bd0,0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50,0x5d34,0x5d47,0x5dfd,
 121.483 +      0x5e45,0x5e3d,0x5e40,0x5e43,0x5e7e,0x5eca,0x5ec1,0x5ec2,0x5ec4,0x5f3c,
 121.484 +      0x5f6d,0x5fa9,0x5faa,0x5fa8,0x60d1,0x60e1,0x60b2,0x60b6,0x60e0,0x611c,
 121.485 +      0x6123,0x60fa,0x6115,0x60f0,0x60fb,0x60f4,0x6168,0x60f1,0x610e,0x60f6,
 121.486 +      0x6109,0x6100,0x6112,0x621f,0x6249,0x63a3,0x638c,0x63cf,0x63c0,0x63e9,
 121.487 +      0x63c9,0x63c6,0x63cd
 121.488 +    },{
 121.489 +      0x63d2,0x63e3,0x63d0,0x63e1,0x63d6,0x63ed,0x63ee,0x6376,0x63f4,0x63ea,
 121.490 +      0x63db,0x6452,0x63da,0x63f9,0x655e,0x6566,0x6562,0x6563,0x6591,0x6590,
 121.491 +      0x65af,0x666e,0x6670,0x6674,0x6676,0x666f,0x6691,0x667a,0x667e,0x6677,
 121.492 +      0x66fe,0x66ff,0x671f,0x671d,0x68fa,0x68d5,0x68e0,0x68d8,0x68d7,0x6905,
 121.493 +      0x68df,0x68f5,0x68ee,0x68e7,0x68f9,0x68d2,0x68f2,0x68e3,0x68cb,0x68cd,
 121.494 +      0x690d,0x6912,0x690e,0x68c9,0x68da,0x696e,0x68fb,0x6b3e,0x6b3a,0x6b3d,
 121.495 +      0x6b98,0x6b96,0x6bbc,0x6bef,0x6c2e,0x6c2f,0x6c2c,0x6e2f,0x6e38,0x6e54,
 121.496 +      0x6e21,0x6e32,0x6e67,0x6e4a,0x6e20,0x6e25,0x6e23,0x6e1b,0x6e5b,0x6e58,
 121.497 +      0x6e24,0x6e56,0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34,0x6e4d,0x6e3a,0x6e2c,
 121.498 +      0x6e43,0x6e1d,0x6e3e,0x6ecb
 121.499 +    }
 121.500 +  },
 121.501 +  {				/* ku 15 */
 121.502 +    {
 121.503 +      0x6e89,0x6e19,0x6e4e,0x6e63,0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a,
 121.504 +      0x7126,0x7130,0x7121,0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336,
 121.505 +      0x7325,0x7334,0x7329,0x743a,0x742a,0x7433,0x7422,0x7425,0x7435,0x7436,
 121.506 +      0x7434,0x742f,0x741b,0x7426,0x7428,0x7525,0x7526,0x756b,0x756a,0x75e2,
 121.507 +      0x75db,0x75e3,0x75d9,0x75d8,0x75de,0x75e0,0x767b,0x767c,0x7696,0x7693,
 121.508 +      0x76b4,0x76dc,0x774f,0x77ed,0x785d,0x786c,0x786f,0x7a0d,0x7a08,0x7a0b,
 121.509 +      0x7a05,0x7a00,0x7a98
 121.510 +    },{
 121.511 +      0x7a97,0x7a96,0x7ae5,0x7ae3,0x7b49,0x7b56,0x7b46,0x7b50,0x7b52,0x7b54,
 121.512 +      0x7b4d,0x7b4b,0x7b4f,0x7b51,0x7c9f,0x7ca5,0x7d5e,0x7d50,0x7d68,0x7d55,
 121.513 +      0x7d2b,0x7d6e,0x7d72,0x7d61,0x7d66,0x7d62,0x7d70,0x7d73,0x5584,0x7fd4,
 121.514 +      0x7fd5,0x800b,0x8052,0x8085,0x8155,0x8154,0x814b,0x8151,0x814e,0x8139,
 121.515 +      0x8146,0x813e,0x814c,0x8153,0x8174,0x8212,0x821c,0x83e9,0x8403,0x83f8,
 121.516 +      0x840d,0x83e0,0x83c5,0x840b,0x83c1,0x83ef,0x83f1,0x83f4,0x8457,0x840a,
 121.517 +      0x83f0,0x840c,0x83cc,0x83fd,0x83f2,0x83ca,0x8438,0x840e,0x8404,0x83dc,
 121.518 +      0x8407,0x83d4,0x83df,0x865b,0x86df,0x86d9,0x86ed,0x86d4,0x86db,0x86e4,
 121.519 +      0x86d0,0x86de,0x8857,0x88c1,0x88c2,0x88b1,0x8983,0x8996,0x8a3b,0x8a60,
 121.520 +      0x8a55,0x8a5e,0x8a3c,0x8a41
 121.521 +    }
 121.522 +  },
 121.523 +  {				/* ku 16 */
 121.524 +    {
 121.525 +      0x8a54,0x8a5b,0x8a50,0x8a46,0x8a34,0x8a3a,0x8a36,0x8a56,0x8c61,0x8c82,
 121.526 +      0x8caf,0x8cbc,0x8cb3,0x8cbd,0x8cc1,0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6,
 121.527 +      0x8cbf,0x8cb8,0x8d8a,0x8d85,0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1,
 121.528 +      0x8dcc,0x8ddb,0x8dc6,0x8efb,0x8ef8,0x8efc,0x8f9c,0x902e,0x9035,0x9031,
 121.529 +      0x9038,0x9032,0x9036,0x9102,0x90f5,0x9109,0x90fe,0x9163,0x9165,0x91cf,
 121.530 +      0x9214,0x9215,0x9223,0x9209,0x921e,0x920d,0x9210,0x9207,0x9211,0x9594,
 121.531 +      0x958f,0x958b,0x9591
 121.532 +    },{
 121.533 +      0x9593,0x9592,0x958e,0x968a,0x968e,0x968b,0x967d,0x9685,0x9686,0x968d,
 121.534 +      0x9672,0x9684,0x96c1,0x96c5,0x96c4,0x96c6,0x96c7,0x96ef,0x96f2,0x97cc,
 121.535 +      0x9805,0x9806,0x9808,0x98e7,0x98ea,0x98ef,0x98e9,0x98f2,0x98ed,0x99ae,
 121.536 +      0x99ad,0x9ec3,0x9ecd,0x9ed1,0x4e82,0x50ad,0x50b5,0x50b2,0x50b3,0x50c5,
 121.537 +      0x50be,0x50ac,0x50b7,0x50bb,0x50af,0x50c7,0x527f,0x5277,0x527d,0x52df,
 121.538 +      0x52e6,0x52e4,0x52e2,0x52e3,0x532f,0x55df,0x55e8,0x55d3,0x55e6,0x55ce,
 121.539 +      0x55dc,0x55c7,0x55d1,0x55e3,0x55e4,0x55ef,0x55da,0x55e1,0x55c5,0x55c6,
 121.540 +      0x55e5,0x55c9,0x5712,0x5713,0x585e,0x5851,0x5858,0x5857,0x585a,0x5854,
 121.541 +      0x586b,0x584c,0x586d,0x584a,0x5862,0x5852,0x584b,0x5967,0x5ac1,0x5ac9,
 121.542 +      0x5acc,0x5abe,0x5abd,0x5abc
 121.543 +    }
 121.544 +  },
 121.545 +  {				/* ku 17 */
 121.546 +    {
 121.547 +      0x5ab3,0x5ac2,0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12,
 121.548 +      0x5f59,0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3,0x611b,0x60f9,
 121.549 +      0x6101,0x6108,0x614e,0x614c,0x6144,0x614d,0x613e,0x6134,0x6127,0x610d,
 121.550 +      0x6106,0x6137,0x6221,0x6222,0x6413,0x643e,0x641e,0x642a,0x642d,0x643d,
 121.551 +      0x642c,0x640f,0x641c,0x6414,0x640d,0x6436,0x6416,0x6417,0x6406,0x656c,
 121.552 +      0x659f,0x65b0,0x6697,0x6689,0x6687,0x6688,0x6696,0x6684,0x6698,0x668d,
 121.553 +      0x6703,0x6994,0x696d
 121.554 +    },{
 121.555 +      0x695a,0x6977,0x6960,0x6954,0x6975,0x6930,0x6982,0x694a,0x6968,0x696b,
 121.556 +      0x695e,0x6953,0x6979,0x6986,0x695d,0x6963,0x695b,0x6b47,0x6b72,0x6bc0,
 121.557 +      0x6bbf,0x6bd3,0x6bfd,0x6ea2,0x6eaf,0x6ed3,0x6eb6,0x6ec2,0x6e90,0x6e9d,
 121.558 +      0x6ec7,0x6ec5,0x6ea5,0x6e98,0x6ebc,0x6eba,0x6eab,0x6ed1,0x6e96,0x6e9c,
 121.559 +      0x6ec4,0x6ed4,0x6eaa,0x6ea7,0x6eb4,0x714e,0x7159,0x7169,0x7164,0x7149,
 121.560 +      0x7167,0x715c,0x716c,0x7166,0x714c,0x7165,0x715e,0x7146,0x7168,0x7156,
 121.561 +      0x723a,0x7252,0x7337,0x7345,0x733f,0x733e,0x746f,0x745a,0x7455,0x745f,
 121.562 +      0x745e,0x7441,0x743f,0x7459,0x745b,0x745c,0x7576,0x7578,0x7600,0x75f0,
 121.563 +      0x7601,0x75f2,0x75f1,0x75fa,0x75ff,0x75f4,0x75f3,0x76de,0x76df,0x775b,
 121.564 +      0x776b,0x7766,0x775e,0x7763
 121.565 +    }
 121.566 +  },
 121.567 +  {				/* ku 18 */
 121.568 +    {
 121.569 +      0x7779,0x776a,0x776c,0x775c,0x7765,0x7768,0x7762,0x77ee,0x788e,0x78b0,
 121.570 +      0x7897,0x7898,0x788c,0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f,
 121.571 +      0x7981,0x842c,0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e,0x7a9f,
 121.572 +      0x7aa0,0x7b77,0x7bc0,0x7b60,0x7b6e,0x7b67,0x7cb1,0x7cb3,0x7cb5,0x7d93,
 121.573 +      0x7d79,0x7d91,0x7d81,0x7d8f,0x7d5b,0x7f6e,0x7f69,0x7f6a,0x7f72,0x7fa9,
 121.574 +      0x7fa8,0x7fa4,0x8056,0x8058,0x8086,0x8084,0x8171,0x8170,0x8178,0x8165,
 121.575 +      0x816e,0x8173,0x816b
 121.576 +    },{
 121.577 +      0x8179,0x817a,0x8166,0x8205,0x8247,0x8482,0x8477,0x843d,0x8431,0x8475,
 121.578 +      0x8466,0x846b,0x8449,0x846c,0x845b,0x843c,0x8435,0x8461,0x8463,0x8469,
 121.579 +      0x846d,0x8446,0x865e,0x865c,0x865f,0x86f9,0x8713,0x8708,0x8707,0x8700,
 121.580 +      0x86fe,0x86fb,0x8702,0x8703,0x8706,0x870a,0x8859,0x88df,0x88d4,0x88d9,
 121.581 +      0x88dc,0x88d8,0x88dd,0x88e1,0x88ca,0x88d5,0x88d2,0x899c,0x89e3,0x8a6b,
 121.582 +      0x8a72,0x8a73,0x8a66,0x8a69,0x8a70,0x8a87,0x8a7c,0x8a63,0x8aa0,0x8a71,
 121.583 +      0x8a85,0x8a6d,0x8a62,0x8a6e,0x8a6c,0x8a79,0x8a7b,0x8a3e,0x8a68,0x8c62,
 121.584 +      0x8c8a,0x8c89,0x8cca,0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3,0x8cc2,0x8cc5,
 121.585 +      0x8de1,0x8ddf,0x8de8,0x8def,0x8df3,0x8dfa,0x8dea,0x8de4,0x8de6,0x8eb2,
 121.586 +      0x8f03,0x8f09,0x8efe,0x8f0a
 121.587 +    }
 121.588 +  },
 121.589 +  {				/* ku 19 */
 121.590 +    {
 121.591 +      0x8f9f,0x8fb2,0x904b,0x904a,0x9053,0x9042,0x9054,0x903c,0x9055,0x9050,
 121.592 +      0x9047,0x904f,0x904e,0x904d,0x9051,0x903e,0x9041,0x9112,0x9117,0x916c,
 121.593 +      0x916a,0x9169,0x91c9,0x9237,0x9257,0x9238,0x923d,0x9240,0x923e,0x925b,
 121.594 +      0x924b,0x9264,0x9251,0x9234,0x9249,0x924d,0x9245,0x9239,0x923f,0x925a,
 121.595 +      0x9598,0x9698,0x9694,0x9695,0x96cd,0x96cb,0x96c9,0x96ca,0x96f7,0x96fb,
 121.596 +      0x96f9,0x96f6,0x9756,0x9774,0x9776,0x9810,0x9811,0x9813,0x980a,0x9812,
 121.597 +      0x980c,0x98fc,0x98f4
 121.598 +    },{
 121.599 +      0x98fd,0x98fe,0x99b3,0x99b1,0x99b4,0x9ae1,0x9ce9,0x9e82,0x9f0e,0x9f13,
 121.600 +      0x9f20,0x50e7,0x50ee,0x50e5,0x50d6,0x50ed,0x50da,0x50d5,0x50cf,0x50d1,
 121.601 +      0x50f1,0x50ce,0x50e9,0x5162,0x51f3,0x5283,0x5282,0x5331,0x53ad,0x55fe,
 121.602 +      0x5600,0x561b,0x5617,0x55fd,0x5614,0x5606,0x5609,0x560d,0x560e,0x55f7,
 121.603 +      0x5616,0x561f,0x5608,0x5610,0x55f6,0x5718,0x5716,0x5875,0x587e,0x5883,
 121.604 +      0x5893,0x588a,0x5879,0x5885,0x587d,0x58fd,0x5925,0x5922,0x5924,0x596a,
 121.605 +      0x5969,0x5ae1,0x5ae6,0x5ae9,0x5ad7,0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde,
 121.606 +      0x5be7,0x5be1,0x5be5,0x5be6,0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62,
 121.607 +      0x5d84,0x5d87,0x5e5b,0x5e63,0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6,0x5f0a,
 121.608 +      0x5f46,0x5f70,0x5fb9,0x6147
 121.609 +    }
 121.610 +  },
 121.611 +  {				/* ku 1a */
 121.612 +    {
 121.613 +      0x613f,0x614b,0x6177,0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a,
 121.614 +      0x6487,0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467,0x6434,
 121.615 +      0x646d,0x647b,0x6572,0x65a1,0x65d7,0x65d6,0x66a2,0x66a8,0x669d,0x699c,
 121.616 +      0x69a8,0x6995,0x69c1,0x69ae,0x69d3,0x69cb,0x699b,0x69b7,0x69bb,0x69ab,
 121.617 +      0x69b4,0x69d0,0x69cd,0x69ad,0x69cc,0x69a6,0x69c3,0x69a3,0x6b49,0x6b4c,
 121.618 +      0x6c33,0x6f33,0x6f14,0x6efe,0x6f13,0x6ef4,0x6f29,0x6f3e,0x6f20,0x6f2c,
 121.619 +      0x6f0f,0x6f02,0x6f22
 121.620 +    },{
 121.621 +      0x6eff,0x6eef,0x6f06,0x6f31,0x6f38,0x6f32,0x6f23,0x6f15,0x6f2b,0x6f2f,
 121.622 +      0x6f88,0x6f2a,0x6eec,0x6f01,0x6ef2,0x6ecc,0x6ef7,0x7194,0x7199,0x717d,
 121.623 +      0x718a,0x7184,0x7192,0x723e,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463,
 121.624 +      0x746a,0x7470,0x746d,0x7504,0x7591,0x7627,0x760d,0x760b,0x7609,0x7613,
 121.625 +      0x76e1,0x76e3,0x7784,0x777d,0x777f,0x7761,0x78c1,0x789f,0x78a7,0x78b3,
 121.626 +      0x78a9,0x78a3,0x798e,0x798f,0x798d,0x7a2e,0x7a31,0x7aaa,0x7aa9,0x7aed,
 121.627 +      0x7aef,0x7ba1,0x7b95,0x7b8b,0x7b75,0x7b97,0x7b9d,0x7b94,0x7b8f,0x7bb8,
 121.628 +      0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe,0x7dbb,0x7db0,0x7d9c,0x7dbd,0x7dbe,
 121.629 +      0x7da0,0x7dca,0x7db4,0x7db2,0x7db1,0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8,
 121.630 +      0x7dad,0x7dd2,0x7dc7,0x7dac
 121.631 +    }
 121.632 +  },
 121.633 +  {				/* ku 1b */
 121.634 +    {
 121.635 +      0x7f70,0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a,0x8087,0x8150,0x8180,0x818f,
 121.636 +      0x8188,0x818a,0x817f,0x8182,0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b,
 121.637 +      0x84c9,0x84bf,0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8,
 121.638 +      0x84c0,0x84d3,0x8490,0x84bc,0x84d1,0x84ca,0x873f,0x871c,0x873b,0x8722,
 121.639 +      0x8725,0x8734,0x8718,0x8755,0x8737,0x8729,0x88f3,0x8902,0x88f4,0x88f9,
 121.640 +      0x88f8,0x88fd,0x88e8,0x891a,0x88ef,0x8aa6,0x8a8c,0x8a9e,0x8aa3,0x8a8d,
 121.641 +      0x8aa1,0x8a93,0x8aa4
 121.642 +    },{
 121.643 +      0x8aaa,0x8aa5,0x8aa8,0x8a98,0x8a91,0x8a9a,0x8aa7,0x8c6a,0x8c8d,0x8c8c,
 121.644 +      0x8cd3,0x8cd1,0x8cd2,0x8d6b,0x8d99,0x8d95,0x8dfc,0x8f14,0x8f12,0x8f15,
 121.645 +      0x8f13,0x8fa3,0x9060,0x9058,0x905c,0x9063,0x9059,0x905e,0x9062,0x905d,
 121.646 +      0x905b,0x9119,0x9118,0x911e,0x9175,0x9178,0x9177,0x9174,0x9278,0x9280,
 121.647 +      0x9285,0x9298,0x9296,0x927b,0x9293,0x929c,0x92a8,0x927c,0x9291,0x95a1,
 121.648 +      0x95a8,0x95a9,0x95a3,0x95a5,0x95a4,0x9699,0x969c,0x969b,0x96cc,0x96d2,
 121.649 +      0x9700,0x977c,0x9785,0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905,
 121.650 +      0x990c,0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4,0x9cf6,
 121.651 +      0x9cf3,0x9ebc,0x9f3b,0x9f4a,0x5104,0x5100,0x50fb,0x50f5,0x50f9,0x5102,
 121.652 +      0x5108,0x5109,0x5105,0x51dc
 121.653 +    }
 121.654 +  },
 121.655 +  {				/* ku 1c */
 121.656 +    {
 121.657 +      0x5287,0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b,0x5639,
 121.658 +      0x5632,0x563f,0x5634,0x5629,0x5653,0x564e,0x5657,0x5674,0x5636,0x562f,
 121.659 +      0x5630,0x5880,0x589f,0x589e,0x58b3,0x589c,0x58ae,0x58a9,0x58a6,0x596d,
 121.660 +      0x5b09,0x5afb,0x5b0b,0x5af5,0x5b0c,0x5b08,0x5bee,0x5bec,0x5be9,0x5beb,
 121.661 +      0x5c64,0x5c65,0x5d9d,0x5d94,0x5e62,0x5e5f,0x5e61,0x5ee2,0x5eda,0x5edf,
 121.662 +      0x5edd,0x5ee3,0x5ee0,0x5f48,0x5f71,0x5fb7,0x5fb5,0x6176,0x6167,0x616e,
 121.663 +      0x615d,0x6155,0x6182
 121.664 +    },{
 121.665 +      0x617c,0x6170,0x616b,0x617e,0x61a7,0x6190,0x61ab,0x618e,0x61ac,0x619a,
 121.666 +      0x61a4,0x6194,0x61ae,0x622e,0x6469,0x646f,0x6479,0x649e,0x64b2,0x6488,
 121.667 +      0x6490,0x64b0,0x64a5,0x6493,0x6495,0x64a9,0x6492,0x64ae,0x64ad,0x64ab,
 121.668 +      0x649a,0x64ac,0x6499,0x64a2,0x64b3,0x6575,0x6577,0x6578,0x66ae,0x66ab,
 121.669 +      0x66b4,0x66b1,0x6a23,0x6a1f,0x69e8,0x6a01,0x6a1e,0x6a19,0x69fd,0x6a21,
 121.670 +      0x6a13,0x6a0a,0x69f3,0x6a02,0x6a05,0x69ed,0x6a11,0x6b50,0x6b4e,0x6ba4,
 121.671 +      0x6bc5,0x6bc6,0x6f3f,0x6f7c,0x6f84,0x6f51,0x6f66,0x6f54,0x6f86,0x6f6d,
 121.672 +      0x6f5b,0x6f78,0x6f6e,0x6f8e,0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5,
 121.673 +      0x6f6f,0x6f60,0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e,
 121.674 +      0x7357,0x7469,0x748b,0x7483
 121.675 +    }
 121.676 +  },
 121.677 +  {				/* ku 1d */
 121.678 +    {
 121.679 +      0x747e,0x7480,0x757f,0x7620,0x7629,0x761f,0x7624,0x7626,0x7621,0x7622,
 121.680 +      0x769a,0x76ba,0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b,0x78cb,0x78c5,
 121.681 +      0x78ba,0x78ca,0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c,0x7a40,0x7a3d,
 121.682 +      0x7a37,0x7a3b,0x7aaf,0x7aae,0x7bad,0x7bb1,0x7bc4,0x7bb4,0x7bc6,0x7bc7,
 121.683 +      0x7bc1,0x7ba0,0x7bcc,0x7cca,0x7de0,0x7df4,0x7def,0x7dfb,0x7dd8,0x7dec,
 121.684 +      0x7ddd,0x7de8,0x7de3,0x7dda,0x7dde,0x7de9,0x7d9e,0x7dd9,0x7df2,0x7df9,
 121.685 +      0x7f75,0x7f77,0x7faf
 121.686 +    },{
 121.687 +      0x7fe9,0x8026,0x819b,0x819c,0x819d,0x81a0,0x819a,0x8198,0x8517,0x853d,
 121.688 +      0x851a,0x84ee,0x852c,0x852d,0x8513,0x8511,0x8523,0x8521,0x8514,0x84ec,
 121.689 +      0x8525,0x84ff,0x8506,0x8782,0x8774,0x8776,0x8760,0x8766,0x8778,0x8768,
 121.690 +      0x8759,0x8757,0x874c,0x8753,0x885b,0x885d,0x8910,0x8907,0x8912,0x8913,
 121.691 +      0x8915,0x890a,0x8abc,0x8ad2,0x8ac7,0x8ac4,0x8a95,0x8acb,0x8af8,0x8ab2,
 121.692 +      0x8ac9,0x8ac2,0x8abf,0x8ab0,0x8ad6,0x8acd,0x8ab6,0x8ab9,0x8adb,0x8c4c,
 121.693 +      0x8c4e,0x8c6c,0x8ce0,0x8cde,0x8ce6,0x8ce4,0x8cec,0x8ced,0x8ce2,0x8ce3,
 121.694 +      0x8cdc,0x8cea,0x8ce1,0x8d6d,0x8d9f,0x8da3,0x8e2b,0x8e10,0x8e1d,0x8e22,
 121.695 +      0x8e0f,0x8e29,0x8e1f,0x8e21,0x8e1e,0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29,
 121.696 +      0x8f26,0x8f2a,0x8f1c,0x8f1e
 121.697 +    }
 121.698 +  },
 121.699 +  {				/* ku 1e */
 121.700 +    {
 121.701 +      0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130,0x912d,0x9127,0x9131,
 121.702 +      0x9187,0x9189,0x918b,0x9183,0x92c5,0x92bb,0x92b7,0x92ea,0x92ac,0x92e4,
 121.703 +      0x92c1,0x92b3,0x92bc,0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704,
 121.704 +      0x9706,0x9707,0x9709,0x9760,0x978d,0x978b,0x978f,0x9821,0x982b,0x981c,
 121.705 +      0x98b3,0x990a,0x9913,0x9912,0x9918,0x99dd,0x99d0,0x99df,0x99db,0x99d1,
 121.706 +      0x99d5,0x99d2,0x99d9,0x9ab7,0x9aee,0x9aef,0x9b27,0x9b45,0x9b44,0x9b77,
 121.707 +      0x9b6f,0x9d06,0x9d09
 121.708 +    },{
 121.709 +      0x9d03,0x9ea9,0x9ebe,0x9ece,0x58a8,0x9f52,0x5112,0x5118,0x5114,0x5110,
 121.710 +      0x5115,0x5180,0x51aa,0x51dd,0x5291,0x5293,0x52f3,0x5659,0x566b,0x5679,
 121.711 +      0x5669,0x5664,0x5678,0x566a,0x5668,0x5665,0x5671,0x566f,0x566c,0x5662,
 121.712 +      0x5676,0x58c1,0x58be,0x58c7,0x58c5,0x596e,0x5b1d,0x5b34,0x5b78,0x5bf0,
 121.713 +      0x5c0e,0x5f4a,0x61b2,0x6191,0x61a9,0x618a,0x61cd,0x61b6,0x61be,0x61ca,
 121.714 +      0x61c8,0x6230,0x64c5,0x64c1,0x64cb,0x64bb,0x64bc,0x64da,0x64c4,0x64c7,
 121.715 +      0x64c2,0x64cd,0x64bf,0x64d2,0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9,
 121.716 +      0x66c4,0x66c7,0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39,
 121.717 +      0x6a44,0x6a62,0x6a61,0x6a4b,0x6a47,0x6a35,0x6a5f,0x6a48,0x6b59,0x6b77,
 121.718 +      0x6c05,0x6fc2,0x6fb1,0x6fa1
 121.719 +    }
 121.720 +  },
 121.721 +  {				/* ku 1f */
 121.722 +    {
 121.723 +      0x6fc3,0x6fa4,0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0,
 121.724 +      0x6fb4,0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9,0x71ce,0x71d9,
 121.725 +      0x71dc,0x71c3,0x71c4,0x7368,0x749c,0x74a3,0x7498,0x749f,0x749e,0x74e2,
 121.726 +      0x750c,0x750d,0x7634,0x7638,0x763a,0x76e7,0x76e5,0x77a0,0x779e,0x779f,
 121.727 +      0x77a5,0x78e8,0x78da,0x78ec,0x78e7,0x79a6,0x7a4d,0x7a4e,0x7a46,0x7a4c,
 121.728 +      0x7a4b,0x7aba,0x7bd9,0x7c11,0x7bc9,0x7be4,0x7bdb,0x7be1,0x7be9,0x7be6,
 121.729 +      0x7cd5,0x7cd6,0x7e0a
 121.730 +    },{
 121.731 +      0x7e11,0x7e08,0x7e1b,0x7e23,0x7e1e,0x7e1d,0x7e09,0x7e10,0x7f79,0x7fb2,
 121.732 +      0x7ff0,0x7ff1,0x7fee,0x8028,0x81b3,0x81a9,0x81a8,0x81fb,0x8208,0x8258,
 121.733 +      0x8259,0x854a,0x8559,0x8548,0x8568,0x8569,0x8543,0x8549,0x856d,0x856a,
 121.734 +      0x855e,0x8783,0x879f,0x879e,0x87a2,0x878d,0x8861,0x892a,0x8932,0x8925,
 121.735 +      0x892b,0x8921,0x89aa,0x89a6,0x8ae6,0x8afa,0x8aeb,0x8af1,0x8b00,0x8adc,
 121.736 +      0x8ae7,0x8aee,0x8afe,0x8b01,0x8b02,0x8af7,0x8aed,0x8af3,0x8af6,0x8afc,
 121.737 +      0x8c6b,0x8c6d,0x8c93,0x8cf4,0x8e44,0x8e31,0x8e34,0x8e42,0x8e39,0x8e35,
 121.738 +      0x8f3b,0x8f2f,0x8f38,0x8f33,0x8fa8,0x8fa6,0x9075,0x9074,0x9078,0x9072,
 121.739 +      0x907c,0x907a,0x9134,0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322,
 121.740 +      0x92fc,0x932b,0x9304,0x931a
 121.741 +    }
 121.742 +  },
 121.743 +  {				/* ku 20 */
 121.744 +    {
 121.745 +      0x9310,0x9326,0x9321,0x9315,0x932e,0x9319,0x95bb,0x96a7,0x96a8,0x96aa,
 121.746 +      0x96d5,0x970e,0x9711,0x9716,0x970d,0x9713,0x970f,0x975b,0x975c,0x9766,
 121.747 +      0x9798,0x9830,0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910,0x9928,
 121.748 +      0x991e,0x991b,0x9921,0x991a,0x99ed,0x99e2,0x99f1,0x9ab8,0x9abc,0x9afb,
 121.749 +      0x9aed,0x9b28,0x9b91,0x9d15,0x9d23,0x9d26,0x9d28,0x9d12,0x9d1b,0x9ed8,
 121.750 +      0x9ed4,0x9f8d,0x9f9c,0x512a,0x511f,0x5121,0x5132,0x52f5,0x568e,0x5680,
 121.751 +      0x5690,0x5685,0x5687
 121.752 +    },{
 121.753 +      0x568f,0x58d5,0x58d3,0x58d1,0x58ce,0x5b30,0x5b2a,0x5b24,0x5b7a,0x5c37,
 121.754 +      0x5c68,0x5dbc,0x5dba,0x5dbd,0x5db8,0x5e6b,0x5f4c,0x5fbd,0x61c9,0x61c2,
 121.755 +      0x61c7,0x61e6,0x61cb,0x6232,0x6234,0x64ce,0x64ca,0x64d8,0x64e0,0x64f0,
 121.756 +      0x64e6,0x64ec,0x64f1,0x64e2,0x64ed,0x6582,0x6583,0x66d9,0x66d6,0x6a80,
 121.757 +      0x6a94,0x6a84,0x6aa2,0x6a9c,0x6adb,0x6aa3,0x6a7e,0x6a97,0x6a90,0x6aa0,
 121.758 +      0x6b5c,0x6bae,0x6bda,0x6c08,0x6fd8,0x6ff1,0x6fdf,0x6fe0,0x6fdb,0x6fe4,
 121.759 +      0x6feb,0x6fef,0x6f80,0x6fec,0x6fe1,0x6fe9,0x6fd5,0x6fee,0x6ff0,0x71e7,
 121.760 +      0x71df,0x71ee,0x71e6,0x71e5,0x71ed,0x71ec,0x71f4,0x71e0,0x7235,0x7246,
 121.761 +      0x7370,0x7372,0x74a9,0x74b0,0x74a6,0x74a8,0x7646,0x7642,0x764c,0x76ea,
 121.762 +      0x77b3,0x77aa,0x77b0,0x77ac
 121.763 +    }
 121.764 +  },
 121.765 +  {				/* ku 21 */
 121.766 +    {
 121.767 +      0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901,0x79a7,0x79aa,
 121.768 +      0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7,0x7c0c,0x7be0,0x7ce0,0x7cdc,
 121.769 +      0x7cde,0x7ce2,0x7cdf,0x7cd9,0x7cdd,0x7e2e,0x7e3e,0x7e46,0x7e37,0x7e32,
 121.770 +      0x7e43,0x7e2b,0x7e3d,0x7e31,0x7e45,0x7e41,0x7e34,0x7e39,0x7e48,0x7e35,
 121.771 +      0x7e3f,0x7e2f,0x7f44,0x7ff3,0x7ffc,0x8071,0x8072,0x8070,0x806f,0x8073,
 121.772 +      0x81c6,0x81c3,0x81ba,0x81c2,0x81c0,0x81bf,0x81bd,0x81c9,0x81be,0x81e8,
 121.773 +      0x8209,0x8271,0x85aa
 121.774 +    },{
 121.775 +      0x8584,0x857e,0x859c,0x8591,0x8594,0x85af,0x859b,0x8587,0x85a8,0x858a,
 121.776 +      0x8667,0x87c0,0x87d1,0x87b3,0x87d2,0x87c6,0x87ab,0x87bb,0x87ba,0x87c8,
 121.777 +      0x87cb,0x893b,0x8936,0x8944,0x8938,0x893d,0x89ac,0x8b0e,0x8b17,0x8b19,
 121.778 +      0x8b1b,0x8b0a,0x8b20,0x8b1d,0x8b04,0x8b10,0x8c41,0x8c3f,0x8c73,0x8cfa,
 121.779 +      0x8cfd,0x8cfc,0x8cf8,0x8cfb,0x8da8,0x8e49,0x8e4b,0x8e48,0x8e4a,0x8f44,
 121.780 +      0x8f3e,0x8f42,0x8f45,0x8f3f,0x907f,0x907d,0x9084,0x9081,0x9082,0x9080,
 121.781 +      0x9139,0x91a3,0x919e,0x919c,0x934d,0x9382,0x9328,0x9375,0x934a,0x9365,
 121.782 +      0x934b,0x9318,0x937e,0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca,0x95cb,
 121.783 +      0x95cc,0x95c8,0x95c6,0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0,0x97d3,
 121.784 +      0x9846,0x98b6,0x9935,0x9a01
 121.785 +    }
 121.786 +  },
 121.787 +  {				/* ku 22 */
 121.788 +    {
 121.789 +      0x99ff,0x9bae,0x9bab,0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf,0x9ede,
 121.790 +      0x9edc,0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9,0x58d8,
 121.791 +      0x5b38,0x5f5d,0x61e3,0x6233,0x64f4,0x64f2,0x64fe,0x6506,0x64fa,0x64fb,
 121.792 +      0x64f7,0x65b7,0x66dc,0x6726,0x6ab3,0x6aac,0x6ac3,0x6abb,0x6ab8,0x6ac2,
 121.793 +      0x6aae,0x6aaf,0x6b5f,0x6b78,0x6baf,0x7009,0x700b,0x6ffe,0x7006,0x6ffa,
 121.794 +      0x7011,0x700f,0x71fb,0x71fc,0x71fe,0x71f8,0x7377,0x7375,0x74a7,0x74bf,
 121.795 +      0x7515,0x7656,0x7658
 121.796 +    },{
 121.797 +      0x7652,0x77bd,0x77bf,0x77bb,0x77bc,0x790e,0x79ae,0x7a61,0x7a62,0x7a60,
 121.798 +      0x7ac4,0x7ac5,0x7c2b,0x7c27,0x7c2a,0x7c1e,0x7c23,0x7c21,0x7ce7,0x7e54,
 121.799 +      0x7e55,0x7e5e,0x7e5a,0x7e61,0x7e52,0x7e59,0x7f48,0x7ff9,0x7ffb,0x8077,
 121.800 +      0x8076,0x81cd,0x81cf,0x820a,0x85cf,0x85a9,0x85cd,0x85d0,0x85c9,0x85b0,
 121.801 +      0x85ba,0x85b9,0x85a6,0x87ef,0x87ec,0x87f2,0x87e0,0x8986,0x89b2,0x89f4,
 121.802 +      0x8b28,0x8b39,0x8b2c,0x8b2b,0x8c50,0x8d05,0x8e59,0x8e63,0x8e66,0x8e64,
 121.803 +      0x8e5f,0x8e55,0x8ec0,0x8f49,0x8f4d,0x9087,0x9083,0x9088,0x91ab,0x91ac,
 121.804 +      0x91d0,0x9394,0x938a,0x9396,0x93a2,0x93b3,0x93ae,0x93ac,0x93b0,0x9398,
 121.805 +      0x939a,0x9397,0x95d4,0x95d6,0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db,
 121.806 +      0x96de,0x9724,0x97a3,0x97a6
 121.807 +    }
 121.808 +  },
 121.809 +  {				/* ku 23 */
 121.810 +    {
 121.811 +      0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e,0x9853,0x98ba,0x993e,0x993f,
 121.812 +      0x993d,0x992e,0x99a5,0x9a0e,0x9ac1,0x9b03,0x9b06,0x9b4f,0x9b4e,0x9b4d,
 121.813 +      0x9bca,0x9bc9,0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15,
 121.814 +      0x9f2c,0x5133,0x56a5,0x58de,0x58df,0x58e2,0x5bf5,0x9f90,0x5eec,0x61f2,
 121.815 +      0x61f7,0x61f6,0x61f5,0x6500,0x650f,0x66e0,0x66dd,0x6ae5,0x6add,0x6ada,
 121.816 +      0x6ad3,0x701b,0x701f,0x7028,0x701a,0x701d,0x7015,0x7018,0x7206,0x720d,
 121.817 +      0x7258,0x72a2,0x7378
 121.818 +    },{
 121.819 +      0x737a,0x74bd,0x74ca,0x74e3,0x7587,0x7586,0x765f,0x7661,0x77c7,0x7919,
 121.820 +      0x79b1,0x7a6b,0x7a69,0x7c3e,0x7c3f,0x7c38,0x7c3d,0x7c37,0x7c40,0x7e6b,
 121.821 +      0x7e6d,0x7e79,0x7e69,0x7e6a,0x7f85,0x7e73,0x7fb6,0x7fb9,0x7fb8,0x81d8,
 121.822 +      0x85e9,0x85dd,0x85ea,0x85d5,0x85e4,0x85e5,0x85f7,0x87fb,0x8805,0x880d,
 121.823 +      0x87f9,0x87fe,0x8960,0x895f,0x8956,0x895e,0x8b41,0x8b5c,0x8b58,0x8b49,
 121.824 +      0x8b5a,0x8b4e,0x8b4f,0x8b46,0x8b59,0x8d08,0x8d0a,0x8e7c,0x8e72,0x8e87,
 121.825 +      0x8e76,0x8e6c,0x8e7a,0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1,
 121.826 +      0x91ae,0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6,0x93e2,
 121.827 +      0x93cd,0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4,0x96e3,0x972a,0x9727,
 121.828 +      0x9761,0x97dc,0x97fb,0x985e
 121.829 +    }
 121.830 +  },
 121.831 +  {				/* ku 24 */
 121.832 +    {
 121.833 +      0x9858,0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19,0x9b0d,0x9be8,0x9be7,
 121.834 +      0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c,0x9e92,0x9e97,0x9e93,
 121.835 +      0x9eb4,0x52f8,0x56a8,0x56b7,0x56b6,0x56b4,0x56bc,0x58e4,0x5b40,0x5b43,
 121.836 +      0x5b7d,0x5bf6,0x5dc9,0x61f8,0x61fa,0x6518,0x6514,0x6519,0x66e6,0x6727,
 121.837 +      0x6aec,0x703e,0x7030,0x7032,0x7210,0x737b,0x74cf,0x7662,0x7665,0x7926,
 121.838 +      0x792a,0x792c,0x792b,0x7ac7,0x7af6,0x7c4c,0x7c43,0x7c4d,0x7cef,0x7cf0,
 121.839 +      0x8fae,0x7e7d,0x7e7c
 121.840 +    },{
 121.841 +      0x7e82,0x7f4c,0x8000,0x81da,0x8266,0x85fb,0x85f9,0x8611,0x85fa,0x8606,
 121.842 +      0x860b,0x8607,0x860a,0x8814,0x8815,0x8964,0x89ba,0x89f8,0x8b70,0x8b6c,
 121.843 +      0x8b66,0x8b6f,0x8b5f,0x8b6b,0x8d0f,0x8d0d,0x8e89,0x8e81,0x8e85,0x8e82,
 121.844 +      0x91b4,0x91cb,0x9418,0x9403,0x93fd,0x95e1,0x9730,0x98c4,0x9952,0x9951,
 121.845 +      0x99a8,0x9a2b,0x9a30,0x9a37,0x9a35,0x9c13,0x9c0d,0x9e79,0x9eb5,0x9ee8,
 121.846 +      0x9f2f,0x9f5f,0x9f63,0x9f61,0x5137,0x5138,0x56c1,0x56c0,0x56c2,0x5914,
 121.847 +      0x5c6c,0x5dcd,0x61fc,0x61fe,0x651d,0x651c,0x6595,0x66e9,0x6afb,0x6b04,
 121.848 +      0x6afa,0x6bb2,0x704c,0x721b,0x72a7,0x74d6,0x74d4,0x7669,0x77d3,0x7c50,
 121.849 +      0x7e8f,0x7e8c,0x7fbc,0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f,
 121.850 +      0x896a,0x896c,0x89bd,0x8b74
 121.851 +    }
 121.852 +  },
 121.853 +  {				/* ku 25 */
 121.854 +    {
 121.855 +      0x8b77,0x8b7d,0x8d13,0x8e8a,0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba,0x942e,
 121.856 +      0x9433,0x9435,0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739,0x9732,
 121.857 +      0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e,0x9acf,0x9b54,
 121.858 +      0x9b51,0x9c2d,0x9c25,0x9daf,0x9db4,0x9dc2,0x9db8,0x9e9d,0x9eef,0x9f19,
 121.859 +      0x9f5c,0x9f66,0x9f67,0x513c,0x513b,0x56c8,0x56ca,0x56c9,0x5b7f,0x5dd4,
 121.860 +      0x5dd2,0x5f4e,0x61ff,0x6524,0x6b0a,0x6b61,0x7051,0x7058,0x7380,0x74e4,
 121.861 +      0x758a,0x766e,0x766c
 121.862 +    },{
 121.863 +      0x79b3,0x7c60,0x7c5f,0x807e,0x807d,0x81df,0x8972,0x896f,0x89fc,0x8b80,
 121.864 +      0x8d16,0x8d17,0x8e91,0x8e93,0x8f61,0x9148,0x9444,0x9451,0x9452,0x973d,
 121.865 +      0x973e,0x97c3,0x97c1,0x986b,0x9955,0x9a55,0x9a4d,0x9ad2,0x9b1a,0x9c49,
 121.866 +      0x9c31,0x9c3e,0x9c3b,0x9dd3,0x9dd7,0x9f34,0x9f6c,0x9f6a,0x9f94,0x56cc,
 121.867 +      0x5dd6,0x6200,0x6523,0x652b,0x652a,0x66ec,0x6b10,0x74da,0x7aca,0x7c64,
 121.868 +      0x7c63,0x7c65,0x7e93,0x7e96,0x7e94,0x81e2,0x8638,0x863f,0x8831,0x8b8a,
 121.869 +      0x9090,0x908f,0x9463,0x9460,0x9464,0x9768,0x986f,0x995c,0x9a5a,0x9a5b,
 121.870 +      0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56,0x9de5,0x9e9f,0x9ef4,
 121.871 +      0x56d1,0x58e9,0x652c,0x705e,0x7671,0x7672,0x77d7,0x7f50,0x7f88,0x8836,
 121.872 +      0x8839,0x8862,0x8b93,0x8b92
 121.873 +    }
 121.874 +  },
 121.875 +  {				/* ku 26 */
 121.876 +    {
 121.877 +      0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,0x9748,0x9744,0x97c6,0x9870,
 121.878 +      0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9,0x9dfa,0x9e7c,0x9e7d,0x9f07,0x9f77,
 121.879 +      0x9f72,0x5ef3,0x6b16,0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1,
 121.880 +      0x9472,0x9470,0x9871,0x995e,0x9ad6,0x9b23,0x9ecc,0x7064,0x77da,0x8b9a,
 121.881 +      0x9477,0x97c9,0x9a62,0x9a65,0x7e9c,0x8b9c,0x8eaa,0x91c5,0x947d,0x947e,
 121.882 +      0x947c,0x9c77,0x9c78,0x9ef7,0x8c54,0x947f,0x9e1a,0x7228,0x9a6a,0x9b31,
 121.883 +      0x9e1b,0x9e1e,0x7c72
 121.884 +    },{
 121.885 +      0x30fe,0x309d,0x309e,0x3005,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,
 121.886 +      0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,
 121.887 +      0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,
 121.888 +      0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,
 121.889 +      0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,
 121.890 +      0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,
 121.891 +      0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,
 121.892 +      0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,
 121.893 +      0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,0x30a1,0x30a2,0x30a3,
 121.894 +      0x30a4,0x30a5,0x30a6,0x30a7
 121.895 +    }
 121.896 +  },
 121.897 +  {				/* ku 27 */
 121.898 +    {
 121.899 +      0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,
 121.900 +      0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,
 121.901 +      0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,
 121.902 +      0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,
 121.903 +      0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,
 121.904 +      0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,
 121.905 +      0x30e4,0x30e5,0x30e6
 121.906 +    },{
 121.907 +      0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,
 121.908 +      0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0x0414,0x0415,0x0401,0x0416,
 121.909 +      0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,0x0423,0x0424,0x0425,0x0426,
 121.910 +      0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,0x0430,
 121.911 +      0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,
 121.912 +      0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,
 121.913 +      0x0444,0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,
 121.914 +      0x044e,0x044f,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
 121.915 +      0x2468,0x2469,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b,
 121.916 +      0x247c,0x247d,UBOGON,UBOGON
 121.917 +    }
 121.918 +  },
 121.919 +  {				/* ku 28 */
 121.920 +    {
 121.921 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.922 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.923 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.924 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.925 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.926 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.927 +      UBOGON,UBOGON,UBOGON
 121.928 +    },{
 121.929 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.930 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.931 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.932 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.933 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.934 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.935 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.936 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.937 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 121.938 +      UBOGON,UBOGON,UBOGON,UBOGON
 121.939 +    }
 121.940 +  },
 121.941 +  {				/* ku 29 */
 121.942 +    {
 121.943 +      0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47,0x4e8d,0x56d7,
 121.944 +      0xfa0c,0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e,0x4e2e,0x4e93,0x4ec2,0x4ec9,
 121.945 +      0x4ec8,0x5198,0x52fc,0x536c,0x53b9,0x5720,0x5903,0x592c,0x5c10,0x5dff,
 121.946 +      0x65e1,0x6bb3,0x6bcc,0x6c14,0x723f,0x4e31,0x4e3c,0x4ee8,0x4edc,0x4ee9,
 121.947 +      0x4ee1,0x4edd,0x4eda,0x520c,0x531c,0x534c,0x5722,0x5723,0x5917,0x592f,
 121.948 +      0x5b81,0x5b84,0x5c12,0x5c3b,0x5c74,0x5c73,0x5e04,0x5e80,0x5e82,0x5fc9,
 121.949 +      0x6209,0x6250,0x6c15
 121.950 +    },{
 121.951 +      0x6c36,0x6c43,0x6c3f,0x6c3b,0x72ae,0x72b0,0x738a,0x79b8,0x808a,0x961e,
 121.952 +      0x4f0e,0x4f18,0x4f2c,0x4ef5,0x4f14,0x4ef1,0x4f00,0x4ef7,0x4f08,0x4f1d,
 121.953 +      0x4f02,0x4f05,0x4f22,0x4f13,0x4f04,0x4ef4,0x4f12,0x51b1,0x5213,0x5209,
 121.954 +      0x5210,0x52a6,0x5322,0x531f,0x534d,0x538a,0x5407,0x56e1,0x56df,0x572e,
 121.955 +      0x572a,0x5734,0x593c,0x5980,0x597c,0x5985,0x597b,0x597e,0x5977,0x597f,
 121.956 +      0x5b56,0x5c15,0x5c25,0x5c7c,0x5c7a,0x5c7b,0x5c7e,0x5ddf,0x5e75,0x5e84,
 121.957 +      0x5f02,0x5f1a,0x5f74,0x5fd5,0x5fd4,0x5fcf,0x625c,0x625e,0x6264,0x6261,
 121.958 +      0x6266,0x6262,0x6259,0x6260,0x625a,0x6265,0x65ef,0x65ee,0x673e,0x6739,
 121.959 +      0x6738,0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52,0x6c5c,
 121.960 +      0x6c4f,0x6c4a,0x6c54,0x6c4b
 121.961 +    }
 121.962 +  },
 121.963 +  {				/* ku 2a */
 121.964 +    {
 121.965 +      0x6c4c,0x7071,0x725e,0x72b4,0x72b5,0x738e,0x752a,0x767f,0x7a75,0x7f51,
 121.966 +      0x8278,0x827c,0x8280,0x827d,0x827f,0x864d,0x897e,0x9099,0x9097,0x9098,
 121.967 +      0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56,0x4f3b,0x4f62,0x4f49,
 121.968 +      0x4f53,0x4f64,0x4f3e,0x4f67,0x4f52,0x4f5f,0x4f41,0x4f58,0x4f2d,0x4f33,
 121.969 +      0x4f3f,0x4f61,0x518f,0x51b9,0x521c,0x521e,0x5221,0x52ad,0x52ae,0x5309,
 121.970 +      0x5363,0x5372,0x538e,0x538f,0x5430,0x5437,0x542a,0x5454,0x5445,0x5419,
 121.971 +      0x541c,0x5425,0x5418
 121.972 +    },{
 121.973 +      0x543d,0x544f,0x5441,0x5428,0x5424,0x5447,0x56ee,0x56e7,0x56e5,0x5741,
 121.974 +      0x5745,0x574c,0x5749,0x574b,0x5752,0x5906,0x5940,0x59a6,0x5998,0x59a0,
 121.975 +      0x5997,0x598e,0x59a2,0x5990,0x598f,0x59a7,0x59a1,0x5b8e,0x5b92,0x5c28,
 121.976 +      0x5c2a,0x5c8d,0x5c8f,0x5c88,0x5c8b,0x5c89,0x5c92,0x5c8a,0x5c86,0x5c93,
 121.977 +      0x5c95,0x5de0,0x5e0a,0x5e0e,0x5e8b,0x5e89,0x5e8c,0x5e88,0x5e8d,0x5f05,
 121.978 +      0x5f1d,0x5f78,0x5f76,0x5fd2,0x5fd1,0x5fd0,0x5fed,0x5fe8,0x5fee,0x5ff3,
 121.979 +      0x5fe1,0x5fe4,0x5fe3,0x5ffa,0x5fef,0x5ff7,0x5ffb,0x6000,0x5ff4,0x623a,
 121.980 +      0x6283,0x628c,0x628e,0x628f,0x6294,0x6287,0x6271,0x627b,0x627a,0x6270,
 121.981 +      0x6281,0x6288,0x6277,0x627d,0x6272,0x6274,0x6537,0x65f0,0x65f4,0x65f3,
 121.982 +      0x65f2,0x65f5,0x6745,0x6747
 121.983 +    }
 121.984 +  },
 121.985 +  {				/* ku 2b */
 121.986 +    {
 121.987 +      0x6759,0x6755,0x674c,0x6748,0x675d,0x674d,0x675a,0x674b,0x6bd0,0x6c19,
 121.988 +      0x6c1a,0x6c78,0x6c67,0x6c6b,0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f,0x6c69,
 121.989 +      0x6c9a,0x6c6d,0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b,0x6c8e,
 121.990 +      0x7074,0x707a,0x7263,0x72bf,0x72bd,0x72c3,0x72c6,0x72c1,0x72ba,0x72c5,
 121.991 +      0x7395,0x7397,0x7393,0x7394,0x7392,0x753a,0x7539,0x7594,0x7595,0x7681,
 121.992 +      0x793d,0x8034,0x8095,0x8099,0x8090,0x8092,0x809c,0x8290,0x828f,0x8285,
 121.993 +      0x828e,0x8291,0x8293
 121.994 +    },{
 121.995 +      0x828a,0x8283,0x8284,0x8c78,0x8fc9,0x8fbf,0x909f,0x90a1,0x90a5,0x909e,
 121.996 +      0x90a7,0x90a0,0x9630,0x9628,0x962f,0x962d,0x4e33,0x4f98,0x4f7c,0x4f85,
 121.997 +      0x4f7d,0x4f80,0x4f87,0x4f76,0x4f74,0x4f89,0x4f84,0x4f77,0x4f4c,0x4f97,
 121.998 +      0x4f6a,0x4f9a,0x4f79,0x4f81,0x4f78,0x4f90,0x4f9c,0x4f94,0x4f9e,0x4f92,
 121.999 +      0x4f82,0x4f95,0x4f6b,0x4f6e,0x519e,0x51bc,0x51be,0x5235,0x5232,0x5233,
121.1000 +      0x5246,0x5231,0x52bc,0x530a,0x530b,0x533c,0x5392,0x5394,0x5487,0x547f,
121.1001 +      0x5481,0x5491,0x5482,0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474,
121.1002 +      0x5466,0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,0x56f7,
121.1003 +      0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770,0x5776,0x5780,0x5775,
121.1004 +      0x577b,0x5773,0x5774,0x5762
121.1005 +    }
121.1006 +  },
121.1007 +  {				/* ku 2c */
121.1008 +    {
121.1009 +      0x5768,0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2,0x59cc,
121.1010 +      0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd,0x59c0,0x59c8,0x59b4,
121.1011 +      0x59c7,0x5b62,0x5b65,0x5b93,0x5b95,0x5c44,0x5c47,0x5cae,0x5ca4,0x5ca0,
121.1012 +      0x5cb5,0x5caf,0x5ca8,0x5cac,0x5c9f,0x5ca3,0x5cad,0x5ca2,0x5caa,0x5ca7,
121.1013 +      0x5c9d,0x5ca5,0x5cb6,0x5cb0,0x5ca6,0x5e17,0x5e14,0x5e19,0x5f28,0x5f22,
121.1014 +      0x5f23,0x5f24,0x5f54,0x5f82,0x5f7e,0x5f7d,0x5fde,0x5fe5,0x602d,0x6026,
121.1015 +      0x6019,0x6032,0x600b
121.1016 +    },{
121.1017 +      0x6034,0x600a,0x6017,0x6033,0x601a,0x601e,0x602c,0x6022,0x600d,0x6010,
121.1018 +      0x602e,0x6013,0x6011,0x600c,0x6009,0x601c,0x6214,0x623d,0x62ad,0x62b4,
121.1019 +      0x62d1,0x62be,0x62aa,0x62b6,0x62ca,0x62ae,0x62b3,0x62af,0x62bb,0x62a9,
121.1020 +      0x62b0,0x62b8,0x653d,0x65a8,0x65bb,0x6609,0x65fc,0x6604,0x6612,0x6608,
121.1021 +      0x65fb,0x6603,0x660b,0x660d,0x6605,0x65fd,0x6611,0x6610,0x66f6,0x670a,
121.1022 +      0x6785,0x676c,0x678e,0x6792,0x6776,0x677b,0x6798,0x6786,0x6784,0x6774,
121.1023 +      0x678d,0x678c,0x677a,0x679f,0x6791,0x6799,0x6783,0x677d,0x6781,0x6778,
121.1024 +      0x6779,0x6794,0x6b25,0x6b80,0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb,
121.1025 +      0x6cee,0x6cd9,0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba,
121.1026 +      0x6cc3,0x6cc6,0x6ced,0x6cf2
121.1027 +    }
121.1028 +  },
121.1029 +  {				/* ku 2d */
121.1030 +    {
121.1031 +      0x6cd2,0x6cdd,0x6cb4,0x6c8a,0x6c9d,0x6c80,0x6cde,0x6cc0,0x6d30,0x6ccd,
121.1032 +      0x6cc7,0x6cb0,0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094,0x7098,0x7085,0x7093,
121.1033 +      0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083,0x726a,0x72d6,0x72cb,
121.1034 +      0x72d8,0x72c9,0x72dc,0x72d2,0x72d4,0x72da,0x72cc,0x72d1,0x73a4,0x73a1,
121.1035 +      0x73ad,0x73a6,0x73a2,0x73a0,0x73ac,0x739d,0x74dd,0x74e8,0x753f,0x7540,
121.1036 +      0x753e,0x758c,0x7598,0x76af,0x76f3,0x76f1,0x76f0,0x76f5,0x77f8,0x77fc,
121.1037 +      0x77f9,0x77fb,0x77fa
121.1038 +    },{
121.1039 +      0x77f7,0x7942,0x793f,0x79c5,0x7a78,0x7a7b,0x7afb,0x7c75,0x7cfd,0x8035,
121.1040 +      0x808f,0x80ae,0x80a3,0x80b8,0x80b5,0x80ad,0x8220,0x82a0,0x82c0,0x82ab,
121.1041 +      0x829a,0x8298,0x829b,0x82b5,0x82a7,0x82ae,0x82bc,0x829e,0x82ba,0x82b4,
121.1042 +      0x82a8,0x82a1,0x82a9,0x82c2,0x82a4,0x82c3,0x82b6,0x82a2,0x8670,0x866f,
121.1043 +      0x866d,0x866e,0x8c56,0x8fd2,0x8fcb,0x8fd3,0x8fcd,0x8fd6,0x8fd5,0x8fd7,
121.1044 +      0x90b2,0x90b4,0x90af,0x90b3,0x90b0,0x9639,0x963d,0x963c,0x963a,0x9643,
121.1045 +      0x4fcd,0x4fc5,0x4fd3,0x4fb2,0x4fc9,0x4fcb,0x4fc1,0x4fd4,0x4fdc,0x4fd9,
121.1046 +      0x4fbb,0x4fb3,0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0,0x4fb9,0x4fec,0x5244,
121.1047 +      0x5249,0x52c0,0x52c2,0x533d,0x537c,0x5397,0x5396,0x5399,0x5398,0x54ba,
121.1048 +      0x54a1,0x54ad,0x54a5,0x54cf
121.1049 +    }
121.1050 +  },
121.1051 +  {				/* ku 2e */
121.1052 +    {
121.1053 +      0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5,0x54c6,0x54a0,0x5470,
121.1054 +      0x54bc,0x54a2,0x54be,0x5472,0x54de,0x54b0,0x57b5,0x579e,0x579f,0x57a4,
121.1055 +      0x578c,0x5797,0x579d,0x579b,0x5794,0x5798,0x578f,0x5799,0x57a5,0x579a,
121.1056 +      0x5795,0x58f4,0x590d,0x5953,0x59e1,0x59de,0x59ee,0x5a00,0x59f1,0x59dd,
121.1057 +      0x59fa,0x59fd,0x59fc,0x59f6,0x59e4,0x59f2,0x59f7,0x59db,0x59e9,0x59f3,
121.1058 +      0x59f5,0x59e0,0x59fe,0x59f4,0x59ed,0x5ba8,0x5c4c,0x5cd0,0x5cd8,0x5ccc,
121.1059 +      0x5cd7,0x5ccb,0x5cdb
121.1060 +    },{
121.1061 +      0x5cde,0x5cda,0x5cc9,0x5cc7,0x5cca,0x5cd6,0x5cd3,0x5cd4,0x5ccf,0x5cc8,
121.1062 +      0x5cc6,0x5cce,0x5cdf,0x5cf8,0x5df9,0x5e21,0x5e22,0x5e23,0x5e20,0x5e24,
121.1063 +      0x5eb0,0x5ea4,0x5ea2,0x5e9b,0x5ea3,0x5ea5,0x5f07,0x5f2e,0x5f56,0x5f86,
121.1064 +      0x6037,0x6039,0x6054,0x6072,0x605e,0x6045,0x6053,0x6047,0x6049,0x605b,
121.1065 +      0x604c,0x6040,0x6042,0x605f,0x6024,0x6044,0x6058,0x6066,0x606e,0x6242,
121.1066 +      0x6243,0x62cf,0x630d,0x630b,0x62f5,0x630e,0x6303,0x62eb,0x62f9,0x630f,
121.1067 +      0x630c,0x62f8,0x62f6,0x6300,0x6313,0x6314,0x62fa,0x6315,0x62fb,0x62f0,
121.1068 +      0x6541,0x6543,0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c,0x6626,
121.1069 +      0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e,0x670f,0x6710,
121.1070 +      0x67c1,0x67f2,0x67c8,0x67ba
121.1071 +    }
121.1072 +  },
121.1073 +  {				/* ku 2f */
121.1074 +    {
121.1075 +      0x67dc,0x67bb,0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4,0x67df,
121.1076 +      0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2,0x67b9,0x67ce,
121.1077 +      0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed,0x67cc,0x67ae,0x67e6,0x67db,
121.1078 +      0x67fa,0x67c9,0x67ca,0x67c3,0x67ea,0x67cb,0x6b28,0x6b82,0x6b84,0x6bb6,
121.1079 +      0x6bd6,0x6bd8,0x6be0,0x6c20,0x6c21,0x6d28,0x6d34,0x6d2d,0x6d1f,0x6d3c,
121.1080 +      0x6d3f,0x6d12,0x6d0a,0x6cda,0x6d33,0x6d04,0x6d19,0x6d3a,0x6d1a,0x6d11,
121.1081 +      0x6d00,0x6d1d,0x6d42
121.1082 +    },{
121.1083 +      0x6d01,0x6d18,0x6d37,0x6d03,0x6d0f,0x6d40,0x6d07,0x6d20,0x6d2c,0x6d08,
121.1084 +      0x6d22,0x6d09,0x6d10,0x70b7,0x709f,0x70be,0x70b1,0x70b0,0x70a1,0x70b4,
121.1085 +      0x70b5,0x70a9,0x7241,0x7249,0x724a,0x726c,0x7270,0x7273,0x726e,0x72ca,
121.1086 +      0x72e4,0x72e8,0x72eb,0x72df,0x72ea,0x72e6,0x72e3,0x7385,0x73cc,0x73c2,
121.1087 +      0x73c8,0x73c5,0x73b9,0x73b6,0x73b5,0x73b4,0x73eb,0x73bf,0x73c7,0x73be,
121.1088 +      0x73c3,0x73c6,0x73b8,0x73cb,0x74ec,0x74ee,0x752e,0x7547,0x7548,0x75a7,
121.1089 +      0x75aa,0x7679,0x76c4,0x7708,0x7703,0x7704,0x7705,0x770a,0x76f7,0x76fb,
121.1090 +      0x76fa,0x77e7,0x77e8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780f,0x780e,
121.1091 +      0x7809,0x7803,0x7813,0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd,
121.1092 +      0x79cf,0x79d6,0x79ce,0x7a80
121.1093 +    }
121.1094 +  },
121.1095 +  {				/* ku 30 */
121.1096 +    {
121.1097 +      0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a,0x7c78,0x7c79,0x7c7f,0x7c80,0x7c81,
121.1098 +      0x7d03,0x7d08,0x7d01,0x7f58,0x7f91,0x7f8d,0x7fbe,0x8007,0x800e,0x800f,
121.1099 +      0x8014,0x8037,0x80d8,0x80c7,0x80e0,0x80d1,0x80c8,0x80c2,0x80d0,0x80c5,
121.1100 +      0x80e3,0x80d9,0x80dc,0x80ca,0x80d5,0x80c9,0x80cf,0x80d7,0x80e6,0x80cd,
121.1101 +      0x81ff,0x8221,0x8294,0x82d9,0x82fe,0x82f9,0x8307,0x82e8,0x8300,0x82d5,
121.1102 +      0x833a,0x82eb,0x82d6,0x82f4,0x82ec,0x82e1,0x82f2,0x82f5,0x830c,0x82fb,
121.1103 +      0x82f6,0x82f0,0x82ea
121.1104 +    },{
121.1105 +      0x82e4,0x82e0,0x82fa,0x82f3,0x82ed,0x8677,0x8674,0x867c,0x8673,0x8841,
121.1106 +      0x884e,0x8867,0x886a,0x8869,0x89d3,0x8a04,0x8a07,0x8d72,0x8fe3,0x8fe1,
121.1107 +      0x8fee,0x8fe0,0x90f1,0x90bd,0x90bf,0x90d5,0x90c5,0x90be,0x90c7,0x90cb,
121.1108 +      0x90c8,0x91d4,0x91d3,0x9654,0x964f,0x9651,0x9653,0x964a,0x964e,0x501e,
121.1109 +      0x5005,0x5007,0x5013,0x5022,0x5030,0x501b,0x4ff5,0x4ff4,0x5033,0x5037,
121.1110 +      0x502c,0x4ff6,0x4ff7,0x5017,0x501c,0x5020,0x5027,0x5035,0x502f,0x5031,
121.1111 +      0x500e,0x515a,0x5194,0x5193,0x51ca,0x51c4,0x51c5,0x51c8,0x51ce,0x5261,
121.1112 +      0x525a,0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e,0x539e,0x5526,
121.1113 +      0x54e2,0x5517,0x5512,0x54e7,0x54f3,0x54e4,0x551a,0x54ff,0x5504,0x5508,
121.1114 +      0x54eb,0x5511,0x5505,0x54f1
121.1115 +    }
121.1116 +  },
121.1117 +  {				/* ku 31 */
121.1118 +    {
121.1119 +      0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503,0x550b,0x5701,0x5702,
121.1120 +      0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6,0x57bd,0x57bc,0x57b8,0x57b6,
121.1121 +      0x57bf,0x57c7,0x57d0,0x57b9,0x57c1,0x590e,0x594a,0x5a19,0x5a16,0x5a2d,
121.1122 +      0x5a2e,0x5a15,0x5a0f,0x5a17,0x5a0a,0x5a1e,0x5a33,0x5b6c,0x5ba7,0x5bad,
121.1123 +      0x5bac,0x5c03,0x5c56,0x5c54,0x5cec,0x5cff,0x5cee,0x5cf1,0x5cf7,0x5d00,
121.1124 +      0x5cf9,0x5e29,0x5e28,0x5ea8,0x5eae,0x5eaa,0x5eac,0x5f33,0x5f30,0x5f67,
121.1125 +      0x605d,0x605a,0x6067
121.1126 +    },{
121.1127 +      0x6041,0x60a2,0x6088,0x6080,0x6092,0x6081,0x609d,0x6083,0x6095,0x609b,
121.1128 +      0x6097,0x6087,0x609c,0x608e,0x6219,0x6246,0x62f2,0x6310,0x6356,0x632c,
121.1129 +      0x6344,0x6345,0x6336,0x6343,0x63e4,0x6339,0x634b,0x634a,0x633c,0x6329,
121.1130 +      0x6341,0x6334,0x6358,0x6354,0x6359,0x632d,0x6347,0x6333,0x635a,0x6351,
121.1131 +      0x6338,0x6357,0x6340,0x6348,0x654a,0x6546,0x65c6,0x65c3,0x65c4,0x65c2,
121.1132 +      0x664a,0x665f,0x6647,0x6651,0x6712,0x6713,0x681f,0x681a,0x6849,0x6832,
121.1133 +      0x6833,0x683b,0x684b,0x684f,0x6816,0x6831,0x681c,0x6835,0x682b,0x682d,
121.1134 +      0x682f,0x684e,0x6844,0x6834,0x681d,0x6812,0x6814,0x6826,0x6828,0x682e,
121.1135 +      0x684d,0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31,0x6b34,0x6b6d,
121.1136 +      0x8082,0x6b88,0x6be6,0x6be4
121.1137 +    }
121.1138 +  },
121.1139 +  {				/* ku 32 */
121.1140 +    {
121.1141 +      0x6be8,0x6be3,0x6be2,0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64,0x6d76,0x6d0d,
121.1142 +      0x6d61,0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d,0x6def,0x6d7f,
121.1143 +      0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c,0x6d5f,0x6d82,0x6d98,
121.1144 +      0x6d2f,0x6d68,0x6d8b,0x6d7e,0x6d80,0x6d84,0x6d16,0x6d83,0x6d7b,0x6d7d,
121.1145 +      0x6d75,0x6d90,0x70dc,0x70d3,0x70d1,0x70dd,0x70cb,0x7f39,0x70e2,0x70d7,
121.1146 +      0x70d2,0x70de,0x70e0,0x70d4,0x70cd,0x70c5,0x70c6,0x70c7,0x70da,0x70ce,
121.1147 +      0x70e1,0x7242,0x7278
121.1148 +    },{
121.1149 +      0x7277,0x7276,0x7300,0x72fa,0x72f4,0x72fe,0x72f6,0x72f3,0x72fb,0x7301,
121.1150 +      0x73d3,0x73d9,0x73e5,0x73d6,0x73bc,0x73e7,0x73e3,0x73e9,0x73dc,0x73d2,
121.1151 +      0x73db,0x73d4,0x73dd,0x73da,0x73d7,0x73d8,0x73e8,0x74de,0x74df,0x74f4,
121.1152 +      0x74f5,0x7521,0x755b,0x755f,0x75b0,0x75c1,0x75bb,0x75c4,0x75c0,0x75bf,
121.1153 +      0x75b6,0x75ba,0x768a,0x76c9,0x771d,0x771b,0x7710,0x7713,0x7712,0x7723,
121.1154 +      0x7711,0x7715,0x7719,0x771a,0x7722,0x7727,0x7823,0x782c,0x7822,0x7835,
121.1155 +      0x782f,0x7828,0x782e,0x782b,0x7821,0x7829,0x7833,0x782a,0x7831,0x7954,
121.1156 +      0x795b,0x794f,0x795c,0x7953,0x7952,0x7951,0x79eb,0x79ec,0x79e0,0x79ee,
121.1157 +      0x79ed,0x79ea,0x79dc,0x79de,0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b,0x7a8c,
121.1158 +      0x7a8a,0x7a87,0x7ad8,0x7b10
121.1159 +    }
121.1160 +  },
121.1161 +  {				/* ku 33 */
121.1162 +    {
121.1163 +      0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,0x7b0a,0x7b0e,0x7b09,0x7b12,0x7c84,
121.1164 +      0x7c91,0x7c8a,0x7c8c,0x7c88,0x7c8d,0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e,
121.1165 +      0x7d18,0x7d16,0x7d13,0x7d1f,0x7d12,0x7d0f,0x7d0c,0x7f5c,0x7f61,0x7f5e,
121.1166 +      0x7f60,0x7f5d,0x7f5b,0x7f96,0x7f92,0x7fc3,0x7fc2,0x7fc0,0x8016,0x803e,
121.1167 +      0x8039,0x80fa,0x80f2,0x80f9,0x80f5,0x8101,0x80fb,0x8100,0x8201,0x822f,
121.1168 +      0x8225,0x8333,0x832d,0x8344,0x8319,0x8351,0x8325,0x8356,0x833f,0x8341,
121.1169 +      0x8326,0x831c,0x8322
121.1170 +    },{
121.1171 +      0x8342,0x834e,0x831b,0x832a,0x8308,0x833c,0x834d,0x8316,0x8324,0x8320,
121.1172 +      0x8337,0x832f,0x8329,0x8347,0x8345,0x834c,0x8353,0x831e,0x832c,0x834b,
121.1173 +      0x8327,0x8348,0x8653,0x8652,0x86a2,0x86a8,0x8696,0x868d,0x8691,0x869e,
121.1174 +      0x8687,0x8697,0x8686,0x868b,0x869a,0x8685,0x86a5,0x8699,0x86a1,0x86a7,
121.1175 +      0x8695,0x8698,0x868e,0x869d,0x8690,0x8694,0x8843,0x8844,0x886d,0x8875,
121.1176 +      0x8876,0x8872,0x8880,0x8871,0x887f,0x886f,0x8883,0x887e,0x8874,0x887c,
121.1177 +      0x8a12,0x8c47,0x8c57,0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7,
121.1178 +      0x8db6,0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004,0x8ffc,
121.1179 +      0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df,0x90e5,0x90d8,0x90db,
121.1180 +      0x90d7,0x90dc,0x90e4,0x9150
121.1181 +    }
121.1182 +  },
121.1183 +  {				/* ku 34 */
121.1184 +    {
121.1185 +      0x914e,0x914f,0x91d5,0x91e2,0x91da,0x965c,0x965f,0x96bc,0x98e3,0x9adf,
121.1186 +      0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e,0x5060,0x5053,0x504b,0x505d,
121.1187 +      0x5072,0x5048,0x504d,0x5041,0x505b,0x504a,0x5062,0x5015,0x5045,0x505f,
121.1188 +      0x5069,0x506b,0x5063,0x5064,0x5046,0x5040,0x506e,0x5073,0x5057,0x5051,
121.1189 +      0x51d0,0x526b,0x526d,0x526c,0x526e,0x52d6,0x52d3,0x532d,0x539c,0x5575,
121.1190 +      0x5576,0x553c,0x554d,0x5550,0x5534,0x552a,0x5551,0x5562,0x5536,0x5535,
121.1191 +      0x5530,0x5552,0x5545
121.1192 +    },{
121.1193 +      0x550c,0x5532,0x5565,0x554e,0x5539,0x5548,0x552d,0x553b,0x5540,0x554b,
121.1194 +      0x570a,0x5707,0x57fb,0x5814,0x57e2,0x57f6,0x57dc,0x57f4,0x5800,0x57ed,
121.1195 +      0x57fd,0x5808,0x57f8,0x580b,0x57f3,0x57cf,0x5807,0x57ee,0x57e3,0x57f2,
121.1196 +      0x57e5,0x57ec,0x57e1,0x580e,0x57fc,0x5810,0x57e7,0x5801,0x580c,0x57f1,
121.1197 +      0x57e9,0x57f0,0x580d,0x5804,0x595c,0x5a60,0x5a58,0x5a55,0x5a67,0x5a5e,
121.1198 +      0x5a38,0x5a35,0x5a6d,0x5a50,0x5a5f,0x5a65,0x5a6c,0x5a53,0x5a64,0x5a57,
121.1199 +      0x5a43,0x5a5d,0x5a52,0x5a44,0x5a5b,0x5a48,0x5a8e,0x5a3e,0x5a4d,0x5a39,
121.1200 +      0x5a4c,0x5a70,0x5a69,0x5a47,0x5a51,0x5a56,0x5a42,0x5a5c,0x5b72,0x5b6e,
121.1201 +      0x5bc1,0x5bc0,0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a,0x5d20,0x5d0c,0x5d28,
121.1202 +      0x5d0d,0x5d26,0x5d25,0x5d0f
121.1203 +    }
121.1204 +  },
121.1205 +  {				/* ku 35 */
121.1206 +    {
121.1207 +      0x5d30,0x5d12,0x5d23,0x5d1f,0x5d2e,0x5e3e,0x5e34,0x5eb1,0x5eb4,0x5eb9,
121.1208 +      0x5eb2,0x5eb3,0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f,0x608a,0x6090,0x6086,
121.1209 +      0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4,0x60d9,0x60dd,0x60c8,
121.1210 +      0x60b1,0x60db,0x60b7,0x60ca,0x60bf,0x60c3,0x60cd,0x60c0,0x6332,0x6365,
121.1211 +      0x638a,0x6382,0x637d,0x63bd,0x639e,0x63ad,0x639d,0x6397,0x63ab,0x638e,
121.1212 +      0x636f,0x6387,0x6390,0x636e,0x63af,0x6375,0x639c,0x636d,0x63ae,0x637c,
121.1213 +      0x63a4,0x633b,0x639f
121.1214 +    },{
121.1215 +      0x6378,0x6385,0x6381,0x6391,0x638d,0x6370,0x6553,0x65cd,0x6665,0x6661,
121.1216 +      0x665b,0x6659,0x665c,0x6662,0x6718,0x6879,0x6887,0x6890,0x689c,0x686d,
121.1217 +      0x686e,0x68ae,0x68ab,0x6956,0x686f,0x68a3,0x68ac,0x68a9,0x6875,0x6874,
121.1218 +      0x68b2,0x688f,0x6877,0x6892,0x687c,0x686b,0x6872,0x68aa,0x6880,0x6871,
121.1219 +      0x687e,0x689b,0x6896,0x688b,0x68a0,0x6889,0x68a4,0x6878,0x687b,0x6891,
121.1220 +      0x688c,0x688a,0x687d,0x6b36,0x6b33,0x6b37,0x6b38,0x6b91,0x6b8f,0x6b8d,
121.1221 +      0x6b8e,0x6b8c,0x6c2a,0x6dc0,0x6dab,0x6db4,0x6db3,0x6e74,0x6dac,0x6de9,
121.1222 +      0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0,0x6ddf,0x6dd6,0x6dbe,
121.1223 +      0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4,0x6dca,0x6dbd,0x6ded,0x6df0,0x6dba,
121.1224 +      0x6dd5,0x6dc2,0x6dcf,0x6dc9
121.1225 +    }
121.1226 +  },
121.1227 +  {				/* ku 36 */
121.1228 +    {
121.1229 +      0x6dd0,0x6df2,0x6dd3,0x6dfd,0x6dd7,0x6dcd,0x6de3,0x6dbb,0x70fa,0x710d,
121.1230 +      0x70f7,0x7117,0x70f4,0x710c,0x70f0,0x7104,0x70f3,0x7110,0x70fc,0x70ff,
121.1231 +      0x7106,0x7113,0x7100,0x70f8,0x70f6,0x710b,0x7102,0x710e,0x727e,0x727b,
121.1232 +      0x727c,0x727f,0x731d,0x7317,0x7307,0x7311,0x7318,0x730a,0x7308,0x72ff,
121.1233 +      0x730f,0x731e,0x7388,0x73f6,0x73f8,0x73f5,0x7404,0x7401,0x73fd,0x7407,
121.1234 +      0x7400,0x73fa,0x73fc,0x73ff,0x740c,0x740b,0x73f4,0x7408,0x7564,0x7563,
121.1235 +      0x75ce,0x75d2,0x75cf
121.1236 +    },{
121.1237 +      0x75cb,0x75cc,0x75d1,0x75d0,0x768f,0x7689,0x76d3,0x7739,0x772f,0x772d,
121.1238 +      0x7731,0x7732,0x7734,0x7733,0x773d,0x7725,0x773b,0x7735,0x7848,0x7852,
121.1239 +      0x7849,0x784d,0x784a,0x784c,0x7826,0x7845,0x7850,0x7964,0x7967,0x7969,
121.1240 +      0x796a,0x7963,0x796b,0x7961,0x79bb,0x79fa,0x79f8,0x79f6,0x79f7,0x7a8f,
121.1241 +      0x7a94,0x7a90,0x7b35,0x7b47,0x7b34,0x7b25,0x7b30,0x7b22,0x7b24,0x7b33,
121.1242 +      0x7b18,0x7b2a,0x7b1d,0x7b31,0x7b2b,0x7b2d,0x7b2f,0x7b32,0x7b38,0x7b1a,
121.1243 +      0x7b23,0x7c94,0x7c98,0x7c96,0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36,0x7d3a,
121.1244 +      0x7d45,0x7d2c,0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b,0x7d28,
121.1245 +      0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd,0x7fd0,0x7fd1,
121.1246 +      0x7fc7,0x7fcf,0x7fc9,0x801f
121.1247 +    }
121.1248 +  },
121.1249 +  {				/* ku 37 */
121.1250 +    {
121.1251 +      0x801e,0x801b,0x8047,0x8043,0x8048,0x8118,0x8125,0x8119,0x811b,0x812d,
121.1252 +      0x811f,0x812c,0x811e,0x8121,0x8115,0x8127,0x811d,0x8122,0x8211,0x8238,
121.1253 +      0x8233,0x823a,0x8234,0x8232,0x8274,0x8390,0x83a3,0x83a8,0x838d,0x837a,
121.1254 +      0x8373,0x83a4,0x8374,0x838f,0x8381,0x8395,0x8399,0x8375,0x8394,0x83a9,
121.1255 +      0x837d,0x8383,0x838c,0x839d,0x839b,0x83aa,0x838b,0x837e,0x83a5,0x83af,
121.1256 +      0x8388,0x8397,0x83b0,0x837f,0x83a6,0x8387,0x83ae,0x8376,0x839a,0x8659,
121.1257 +      0x8656,0x86bf,0x86b7
121.1258 +    },{
121.1259 +      0x86c2,0x86c1,0x86c5,0x86ba,0x86b0,0x86c8,0x86b9,0x86b3,0x86b8,0x86cc,
121.1260 +      0x86b4,0x86bb,0x86bc,0x86c3,0x86bd,0x86be,0x8852,0x8889,0x8895,0x88a8,
121.1261 +      0x88a2,0x88aa,0x889a,0x8891,0x88a1,0x889f,0x8898,0x88a7,0x8899,0x889b,
121.1262 +      0x8897,0x88a4,0x88ac,0x888c,0x8893,0x888e,0x8982,0x89d6,0x89d9,0x89d5,
121.1263 +      0x8a30,0x8a27,0x8a2c,0x8a1e,0x8c39,0x8c3b,0x8c5c,0x8c5d,0x8c7d,0x8ca5,
121.1264 +      0x8d7d,0x8d7b,0x8d79,0x8dbc,0x8dc2,0x8db9,0x8dbf,0x8dc1,0x8ed8,0x8ede,
121.1265 +      0x8edd,0x8edc,0x8ed7,0x8ee0,0x8ee1,0x9024,0x900b,0x9011,0x901c,0x900c,
121.1266 +      0x9021,0x90ef,0x90ea,0x90f0,0x90f4,0x90f2,0x90f3,0x90d4,0x90eb,0x90ec,
121.1267 +      0x90e9,0x9156,0x9158,0x915a,0x9153,0x9155,0x91ec,0x91f4,0x91f1,0x91f3,
121.1268 +      0x91f8,0x91e4,0x91f9,0x91ea
121.1269 +    }
121.1270 +  },
121.1271 +  {				/* ku 38 */
121.1272 +    {
121.1273 +      0x91eb,0x91f7,0x91e8,0x91ee,0x957a,0x9586,0x9588,0x967c,0x966d,0x966b,
121.1274 +      0x9671,0x966f,0x96bf,0x976a,0x9804,0x98e5,0x9997,0x509b,0x5095,0x5094,
121.1275 +      0x509e,0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d,0x5068,0x509c,0x5092,
121.1276 +      0x5082,0x5087,0x515f,0x51d4,0x5312,0x5311,0x53a4,0x53a7,0x5591,0x55a8,
121.1277 +      0x55a5,0x55ad,0x5577,0x5645,0x55a2,0x5593,0x5588,0x558f,0x55b5,0x5581,
121.1278 +      0x55a3,0x5592,0x55a4,0x557d,0x558c,0x55a6,0x557f,0x5595,0x55a1,0x558e,
121.1279 +      0x570c,0x5829,0x5837
121.1280 +    },{
121.1281 +      0x5819,0x581e,0x5827,0x5823,0x5828,0x57f5,0x5848,0x5825,0x581c,0x581b,
121.1282 +      0x5833,0x583f,0x5836,0x582e,0x5839,0x5838,0x582d,0x582c,0x583b,0x5961,
121.1283 +      0x5aaf,0x5a94,0x5a9f,0x5a7a,0x5aa2,0x5a9e,0x5a78,0x5aa6,0x5a7c,0x5aa5,
121.1284 +      0x5aac,0x5a95,0x5aae,0x5a37,0x5a84,0x5a8a,0x5a97,0x5a83,0x5a8b,0x5aa9,
121.1285 +      0x5a7b,0x5a7d,0x5a8c,0x5a9c,0x5a8f,0x5a93,0x5a9d,0x5bea,0x5bcd,0x5bcb,
121.1286 +      0x5bd4,0x5bd1,0x5bca,0x5bce,0x5c0c,0x5c30,0x5d37,0x5d43,0x5d6b,0x5d41,
121.1287 +      0x5d4b,0x5d3f,0x5d35,0x5d51,0x5d4e,0x5d55,0x5d33,0x5d3a,0x5d52,0x5d3d,
121.1288 +      0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32,0x5d36,0x5d40,
121.1289 +      0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5,0x5fab,0x60c9,0x60b9,0x60cc,
121.1290 +      0x60e2,0x60ce,0x60c4,0x6114
121.1291 +    }
121.1292 +  },
121.1293 +  {				/* ku 39 */
121.1294 +    {
121.1295 +      0x60f2,0x610a,0x6116,0x6105,0x60f5,0x6113,0x60f8,0x60fc,0x60fe,0x60c1,
121.1296 +      0x6103,0x6118,0x611d,0x6110,0x60ff,0x6104,0x610b,0x624a,0x6394,0x63b1,
121.1297 +      0x63b0,0x63ce,0x63e5,0x63e8,0x63ef,0x63c3,0x649d,0x63f3,0x63ca,0x63e0,
121.1298 +      0x63f6,0x63d5,0x63f2,0x63f5,0x6461,0x63df,0x63be,0x63dd,0x63dc,0x63c4,
121.1299 +      0x63d8,0x63d3,0x63c2,0x63c7,0x63cc,0x63cb,0x63c8,0x63f0,0x63d7,0x63d9,
121.1300 +      0x6532,0x6567,0x656a,0x6564,0x655c,0x6568,0x6565,0x658c,0x659d,0x659e,
121.1301 +      0x65ae,0x65d0,0x65d2
121.1302 +    },{
121.1303 +      0x667c,0x666c,0x667b,0x6680,0x6671,0x6679,0x666a,0x6672,0x6701,0x690c,
121.1304 +      0x68d3,0x6904,0x68dc,0x692a,0x68ec,0x68ea,0x68f1,0x690f,0x68d6,0x68f7,
121.1305 +      0x68eb,0x68e4,0x68f6,0x6913,0x6910,0x68f3,0x68e1,0x6907,0x68cc,0x6908,
121.1306 +      0x6970,0x68b4,0x6911,0x68ef,0x68c6,0x6914,0x68f8,0x68d0,0x68fd,0x68fc,
121.1307 +      0x68e8,0x690b,0x690a,0x6917,0x68ce,0x68c8,0x68dd,0x68de,0x68e6,0x68f4,
121.1308 +      0x68d1,0x6906,0x68d4,0x68e9,0x6915,0x6925,0x68c7,0x6b39,0x6b3b,0x6b3f,
121.1309 +      0x6b3c,0x6b94,0x6b97,0x6b99,0x6b95,0x6bbd,0x6bf0,0x6bf2,0x6bf3,0x6c30,
121.1310 +      0x6dfc,0x6e46,0x6e47,0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45,0x6e62,
121.1311 +      0x6e2b,0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40,0x6e51,
121.1312 +      0x6e3b,0x6e03,0x6e2e,0x6e5e
121.1313 +    }
121.1314 +  },
121.1315 +  {				/* ku 3a */
121.1316 +    {
121.1317 +      0x6e68,0x6e5c,0x6e61,0x6e31,0x6e28,0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22,
121.1318 +      0x6e30,0x6e53,0x6e65,0x6e27,0x6e78,0x6e64,0x6e77,0x6e55,0x6e79,0x6e52,
121.1319 +      0x6e66,0x6e35,0x6e36,0x6e5a,0x7120,0x711e,0x712f,0x70fb,0x712e,0x7131,
121.1320 +      0x7123,0x7125,0x7122,0x7132,0x711f,0x7128,0x713a,0x711b,0x724b,0x725a,
121.1321 +      0x7288,0x7289,0x7286,0x7285,0x728b,0x7312,0x730b,0x7330,0x7322,0x7331,
121.1322 +      0x7333,0x7327,0x7332,0x732d,0x7326,0x7323,0x7335,0x730c,0x742e,0x742c,
121.1323 +      0x7430,0x742b,0x7416
121.1324 +    },{
121.1325 +      0x741a,0x7421,0x742d,0x7431,0x7424,0x7423,0x741d,0x7429,0x7420,0x7432,
121.1326 +      0x74fb,0x752f,0x756f,0x756c,0x75e7,0x75da,0x75e1,0x75e6,0x75dd,0x75df,
121.1327 +      0x75e4,0x75d7,0x7695,0x7692,0x76da,0x7746,0x7747,0x7744,0x774d,0x7745,
121.1328 +      0x774a,0x774e,0x774b,0x774c,0x77de,0x77ec,0x7860,0x7864,0x7865,0x785c,
121.1329 +      0x786d,0x7871,0x786a,0x786e,0x7870,0x7869,0x7868,0x785e,0x7862,0x7974,
121.1330 +      0x7973,0x7972,0x7970,0x7a02,0x7a0a,0x7a03,0x7a0c,0x7a04,0x7a99,0x7ae6,
121.1331 +      0x7ae4,0x7b4a,0x7b3b,0x7b44,0x7b48,0x7b4c,0x7b4e,0x7b40,0x7b58,0x7b45,
121.1332 +      0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f,0x7d63,0x7d53,0x7d56,0x7d67,
121.1333 +      0x7d6a,0x7d4f,0x7d6d,0x7d5c,0x7d6b,0x7d52,0x7d54,0x7d69,0x7d51,0x7d5f,
121.1334 +      0x7d4e,0x7f3e,0x7f3f,0x7f65
121.1335 +    }
121.1336 +  },
121.1337 +  {				/* ku 3b */
121.1338 +    {
121.1339 +      0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051,0x804f,0x8050,0x80fe,0x80d4,
121.1340 +      0x8143,0x814a,0x8152,0x814f,0x8147,0x813d,0x814d,0x813a,0x81e6,0x81ee,
121.1341 +      0x81f7,0x81f8,0x81f9,0x8204,0x823c,0x823d,0x823f,0x8275,0x833b,0x83cf,
121.1342 +      0x83f9,0x8423,0x83c0,0x83e8,0x8412,0x83e7,0x83e4,0x83fc,0x83f6,0x8410,
121.1343 +      0x83c6,0x83c8,0x83eb,0x83e3,0x83bf,0x8401,0x83dd,0x83e5,0x83d8,0x83ff,
121.1344 +      0x83e1,0x83cb,0x83ce,0x83d6,0x83f5,0x83c9,0x8409,0x840f,0x83de,0x8411,
121.1345 +      0x8406,0x83c2,0x83f3
121.1346 +    },{
121.1347 +      0x83d5,0x83fa,0x83c7,0x83d1,0x83ea,0x8413,0x83c3,0x83ec,0x83ee,0x83c4,
121.1348 +      0x83fb,0x83d7,0x83e2,0x841b,0x83db,0x83fe,0x86d8,0x86e2,0x86e6,0x86d3,
121.1349 +      0x86e3,0x86da,0x86ea,0x86dd,0x86eb,0x86dc,0x86ec,0x86e9,0x86d7,0x86e8,
121.1350 +      0x86d1,0x8848,0x8856,0x8855,0x88ba,0x88d7,0x88b9,0x88b8,0x88c0,0x88be,
121.1351 +      0x88b6,0x88bc,0x88b7,0x88bd,0x88b2,0x8901,0x88c9,0x8995,0x8998,0x8997,
121.1352 +      0x89dd,0x89da,0x89db,0x8a4e,0x8a4d,0x8a39,0x8a59,0x8a40,0x8a57,0x8a58,
121.1353 +      0x8a44,0x8a45,0x8a52,0x8a48,0x8a51,0x8a4a,0x8a4c,0x8a4f,0x8c5f,0x8c81,
121.1354 +      0x8c80,0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5,0x8d84,0x8d80,0x8d89,0x8dd8,
121.1355 +      0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf,0x8dd5,0x8dd9,0x8dc8,0x8dd7,
121.1356 +      0x8dc5,0x8eef,0x8ef7,0x8efa
121.1357 +    }
121.1358 +  },
121.1359 +  {				/* ku 3c */
121.1360 +    {
121.1361 +      0x8ef9,0x8ee6,0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb,0x8ef1,
121.1362 +      0x8eec,0x8ef4,0x8ee9,0x902d,0x9034,0x902f,0x9106,0x912c,0x9104,0x90ff,
121.1363 +      0x90fc,0x9108,0x90f9,0x90fb,0x9101,0x9100,0x9107,0x9105,0x9103,0x9161,
121.1364 +      0x9164,0x915f,0x9162,0x9160,0x9201,0x920a,0x9225,0x9203,0x921a,0x9226,
121.1365 +      0x920f,0x920c,0x9200,0x9212,0x91ff,0x91fd,0x9206,0x9204,0x9227,0x9202,
121.1366 +      0x921c,0x9224,0x9219,0x9217,0x9205,0x9216,0x957b,0x958d,0x958c,0x9590,
121.1367 +      0x9687,0x967e,0x9688
121.1368 +    },{
121.1369 +      0x9689,0x9683,0x9680,0x96c2,0x96c8,0x96c3,0x96f1,0x96f0,0x976c,0x9770,
121.1370 +      0x976e,0x9807,0x98a9,0x98eb,0x9ce6,0x9ef9,0x4e83,0x4e84,0x4eb6,0x50bd,
121.1371 +      0x50bf,0x50c6,0x50ae,0x50c4,0x50ca,0x50b4,0x50c8,0x50c2,0x50b0,0x50c1,
121.1372 +      0x50ba,0x50b1,0x50cb,0x50c9,0x50b6,0x50b8,0x51d7,0x527a,0x5278,0x527b,
121.1373 +      0x527c,0x55c3,0x55db,0x55cc,0x55d0,0x55cb,0x55ca,0x55dd,0x55c0,0x55d4,
121.1374 +      0x55c4,0x55e9,0x55bf,0x55d2,0x558d,0x55cf,0x55d5,0x55e2,0x55d6,0x55c8,
121.1375 +      0x55f2,0x55cd,0x55d9,0x55c2,0x5714,0x5853,0x5868,0x5864,0x584f,0x584d,
121.1376 +      0x5849,0x586f,0x5855,0x584e,0x585d,0x5859,0x5865,0x585b,0x583d,0x5863,
121.1377 +      0x5871,0x58fc,0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8,0x5ab1,0x5ab5,0x5ab0,
121.1378 +      0x5abf,0x5ac8,0x5abb,0x5ac6
121.1379 +    }
121.1380 +  },
121.1381 +  {				/* ku 3d */
121.1382 +    {
121.1383 +      0x5ab7,0x5ac0,0x5aca,0x5ab4,0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8,
121.1384 +      0x5bd9,0x5c1f,0x5c33,0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e,
121.1385 +      0x5d68,0x5d67,0x5d62,0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d,0x5e4b,0x5ec5,
121.1386 +      0x5ecc,0x5ec6,0x5ecb,0x5ec7,0x5f40,0x5faf,0x5fad,0x60f7,0x6149,0x614a,
121.1387 +      0x612b,0x6145,0x6136,0x6132,0x612e,0x6146,0x612f,0x614f,0x6129,0x6140,
121.1388 +      0x6220,0x9168,0x6223,0x6225,0x6224,0x63c5,0x63f1,0x63eb,0x6410,0x6412,
121.1389 +      0x6409,0x6420,0x6424
121.1390 +    },{
121.1391 +      0x6433,0x6443,0x641f,0x6415,0x6418,0x6439,0x6437,0x6422,0x6423,0x640c,
121.1392 +      0x6426,0x6430,0x6428,0x6441,0x6435,0x642f,0x640a,0x641a,0x6440,0x6425,
121.1393 +      0x6427,0x640b,0x63e7,0x641b,0x642e,0x6421,0x640e,0x656f,0x6592,0x65d3,
121.1394 +      0x6686,0x668c,0x6695,0x6690,0x668b,0x668a,0x6699,0x6694,0x6678,0x6720,
121.1395 +      0x6966,0x695f,0x6938,0x694e,0x6962,0x6971,0x693f,0x6945,0x696a,0x6939,
121.1396 +      0x6942,0x6957,0x6959,0x697a,0x6948,0x6949,0x6935,0x696c,0x6933,0x693d,
121.1397 +      0x6965,0x68f0,0x6978,0x6934,0x6969,0x6940,0x696f,0x6944,0x6976,0x6958,
121.1398 +      0x6941,0x6974,0x694c,0x693b,0x694b,0x6937,0x695c,0x694f,0x6951,0x6932,
121.1399 +      0x6952,0x692f,0x697b,0x693c,0x6b46,0x6b45,0x6b43,0x6b42,0x6b48,0x6b41,
121.1400 +      0x6b9b,0xfa0d,0x6bfb,0x6bfc
121.1401 +    }
121.1402 +  },
121.1403 +  {				/* ku 3e */
121.1404 +    {
121.1405 +      0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,0x6ec8,0x6e8f,0x6ec0,0x6e9f,0x6e93,
121.1406 +      0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6,0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9,
121.1407 +      0x6eb7,0x6eb0,0x6ecd,0x6ea6,0x6ecf,0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8,
121.1408 +      0x6e99,0x6e92,0x6e8e,0x6e8d,0x6ea4,0x6ea1,0x6ebf,0x6eb3,0x6ed0,0x6eca,
121.1409 +      0x6e97,0x6eae,0x6ea3,0x7147,0x7154,0x7152,0x7163,0x7160,0x7141,0x715d,
121.1410 +      0x7162,0x7172,0x7178,0x716a,0x7161,0x7142,0x7158,0x7143,0x714b,0x7170,
121.1411 +      0x715f,0x7150,0x7153
121.1412 +    },{
121.1413 +      0x7144,0x714d,0x715a,0x724f,0x728d,0x728c,0x7291,0x7290,0x728e,0x733c,
121.1414 +      0x7342,0x733b,0x733a,0x7340,0x734a,0x7349,0x7444,0x744a,0x744b,0x7452,
121.1415 +      0x7451,0x7457,0x7440,0x744f,0x7450,0x744e,0x7442,0x7446,0x744d,0x7454,
121.1416 +      0x74e1,0x74ff,0x74fe,0x74fd,0x751d,0x7579,0x7577,0x6983,0x75ef,0x760f,
121.1417 +      0x7603,0x75f7,0x75fe,0x75fc,0x75f9,0x75f8,0x7610,0x75fb,0x75f6,0x75ed,
121.1418 +      0x75f5,0x75fd,0x7699,0x76b5,0x76dd,0x7755,0x775f,0x7760,0x7752,0x7756,
121.1419 +      0x775a,0x7769,0x7767,0x7754,0x7759,0x776d,0x77e0,0x7887,0x789a,0x7894,
121.1420 +      0x788f,0x7884,0x7895,0x7885,0x7886,0x78a1,0x7883,0x7879,0x7899,0x7880,
121.1421 +      0x7896,0x787b,0x797c,0x7982,0x797d,0x7979,0x7a11,0x7a18,0x7a19,0x7a12,
121.1422 +      0x7a17,0x7a15,0x7a22,0x7a13
121.1423 +    }
121.1424 +  },
121.1425 +  {				/* ku 3f */
121.1426 +    {
121.1427 +      0x7a1b,0x7a10,0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74,
121.1428 +      0x7b69,0x7b72,0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78,0x7b76,0x7b63,
121.1429 +      0x7cb2,0x7cb4,0x7caf,0x7d88,0x7d86,0x7d80,0x7d8d,0x7d7f,0x7d85,0x7d7a,
121.1430 +      0x7d8e,0x7d7b,0x7d83,0x7d7c,0x7d8c,0x7d94,0x7d84,0x7d7d,0x7d92,0x7f6d,
121.1431 +      0x7f6b,0x7f67,0x7f68,0x7f6c,0x7fa6,0x7fa5,0x7fa7,0x7fdb,0x7fdc,0x8021,
121.1432 +      0x8164,0x8160,0x8177,0x815c,0x8169,0x815b,0x8162,0x8172,0x6721,0x815e,
121.1433 +      0x8176,0x8167,0x816f
121.1434 +    },{
121.1435 +      0x8144,0x8161,0x821d,0x8249,0x8244,0x8240,0x8242,0x8245,0x84f1,0x843f,
121.1436 +      0x8456,0x8476,0x8479,0x848f,0x848d,0x8465,0x8451,0x8440,0x8486,0x8467,
121.1437 +      0x8430,0x844d,0x847d,0x845a,0x8459,0x8474,0x8473,0x845d,0x8507,0x845e,
121.1438 +      0x8437,0x843a,0x8434,0x847a,0x8443,0x8478,0x8432,0x8445,0x8429,0x83d9,
121.1439 +      0x844b,0x842f,0x8442,0x842d,0x845f,0x8470,0x8439,0x844e,0x844c,0x8452,
121.1440 +      0x846f,0x84c5,0x848e,0x843b,0x8447,0x8436,0x8433,0x8468,0x847e,0x8444,
121.1441 +      0x842b,0x8460,0x8454,0x846e,0x8450,0x870b,0x8704,0x86f7,0x870c,0x86fa,
121.1442 +      0x86d6,0x86f5,0x874d,0x86f8,0x870e,0x8709,0x8701,0x86f6,0x870d,0x8705,
121.1443 +      0x88d6,0x88cb,0x88cd,0x88ce,0x88de,0x88db,0x88da,0x88cc,0x88d0,0x8985,
121.1444 +      0x899b,0x89df,0x89e5,0x89e4
121.1445 +    }
121.1446 +  },
121.1447 +  {				/* ku 40 */
121.1448 +    {
121.1449 +      0x89e1,0x89e0,0x89e2,0x89dc,0x89e6,0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f,
121.1450 +      0x8a77,0x8a82,0x8a84,0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b,
121.1451 +      0x8c4a,0x8c65,0x8c64,0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68,0x8d69,
121.1452 +      0x8d91,0x8d8c,0x8d8e,0x8d8f,0x8d8d,0x8d93,0x8d94,0x8d90,0x8d92,0x8df0,
121.1453 +      0x8de0,0x8dec,0x8df1,0x8dee,0x8dd0,0x8de9,0x8de3,0x8de2,0x8de7,0x8df2,
121.1454 +      0x8deb,0x8df4,0x8f06,0x8eff,0x8f01,0x8f00,0x8f05,0x8f07,0x8f08,0x8f02,
121.1455 +      0x8f0b,0x9052,0x903f
121.1456 +    },{
121.1457 +      0x9044,0x9049,0x903d,0x9110,0x910d,0x910f,0x9111,0x9116,0x9114,0x910b,
121.1458 +      0x910e,0x916e,0x916f,0x9248,0x9252,0x9230,0x923a,0x9266,0x9233,0x9265,
121.1459 +      0x925e,0x9283,0x922e,0x924a,0x9246,0x926d,0x926c,0x924f,0x9260,0x9267,
121.1460 +      0x926f,0x9236,0x9261,0x9270,0x9231,0x9254,0x9263,0x9250,0x9272,0x924e,
121.1461 +      0x9253,0x924c,0x9256,0x9232,0x959f,0x959c,0x959e,0x959b,0x9692,0x9693,
121.1462 +      0x9691,0x9697,0x96ce,0x96fa,0x96fd,0x96f8,0x96f5,0x9773,0x9777,0x9778,
121.1463 +      0x9772,0x980f,0x980d,0x980e,0x98ac,0x98f6,0x98f9,0x99af,0x99b2,0x99b0,
121.1464 +      0x99b5,0x9aad,0x9aab,0x9b5b,0x9cea,0x9ced,0x9ce7,0x9e80,0x9efd,0x50e6,
121.1465 +      0x50d4,0x50d7,0x50e8,0x50f3,0x50db,0x50ea,0x50dd,0x50e4,0x50d3,0x50ec,
121.1466 +      0x50f0,0x50ef,0x50e3,0x50e0
121.1467 +    }
121.1468 +  },
121.1469 +  {				/* ku 41 */
121.1470 +    {
121.1471 +      0x51d8,0x5280,0x5281,0x52e9,0x52eb,0x5330,0x53ac,0x5627,0x5615,0x560c,
121.1472 +      0x5612,0x55fc,0x560f,0x561c,0x5601,0x5613,0x5602,0x55fa,0x561d,0x5604,
121.1473 +      0x55ff,0x55f9,0x5889,0x587c,0x5890,0x5898,0x5886,0x5881,0x587f,0x5874,
121.1474 +      0x588b,0x587a,0x5887,0x5891,0x588e,0x5876,0x5882,0x5888,0x587b,0x5894,
121.1475 +      0x588f,0x58fe,0x596b,0x5adc,0x5aee,0x5ae5,0x5ad5,0x5aea,0x5ada,0x5aed,
121.1476 +      0x5aeb,0x5af3,0x5ae2,0x5ae0,0x5adb,0x5aec,0x5ade,0x5add,0x5ad9,0x5ae8,
121.1477 +      0x5adf,0x5b77,0x5be0
121.1478 +    },{
121.1479 +      0x5be3,0x5c63,0x5d82,0x5d80,0x5d7d,0x5d86,0x5d7a,0x5d81,0x5d77,0x5d8a,
121.1480 +      0x5d89,0x5d88,0x5d7e,0x5d7c,0x5d8d,0x5d79,0x5d7f,0x5e58,0x5e59,0x5e53,
121.1481 +      0x5ed8,0x5ed1,0x5ed7,0x5ece,0x5edc,0x5ed5,0x5ed9,0x5ed2,0x5ed4,0x5f44,
121.1482 +      0x5f43,0x5f6f,0x5fb6,0x612c,0x6128,0x6141,0x615e,0x6171,0x6173,0x6152,
121.1483 +      0x6153,0x6172,0x616c,0x6180,0x6174,0x6154,0x617a,0x615b,0x6165,0x613b,
121.1484 +      0x616a,0x6161,0x6156,0x6229,0x6227,0x622b,0x642b,0x644d,0x645b,0x645d,
121.1485 +      0x6474,0x6476,0x6472,0x6473,0x647d,0x6475,0x6466,0x64a6,0x644e,0x6482,
121.1486 +      0x645e,0x645c,0x644b,0x6453,0x6460,0x6450,0x647f,0x643f,0x646c,0x646b,
121.1487 +      0x6459,0x6465,0x6477,0x6573,0x65a0,0x66a1,0x66a0,0x669f,0x6705,0x6704,
121.1488 +      0x6722,0x69b1,0x69b6,0x69c9
121.1489 +    }
121.1490 +  },
121.1491 +  {				/* ku 42 */
121.1492 +    {
121.1493 +      0x69a0,0x69ce,0x6996,0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7,
121.1494 +      0x698d,0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4,0x69b9,
121.1495 +      0x69ca,0x699a,0x69cf,0x69b3,0x6993,0x69aa,0x69a1,0x699e,0x69d9,0x6997,
121.1496 +      0x6990,0x69c2,0x69b5,0x69a5,0x69c6,0x6b4a,0x6b4d,0x6b4b,0x6b9e,0x6b9f,
121.1497 +      0x6ba0,0x6bc3,0x6bc4,0x6bfe,0x6ece,0x6ef5,0x6ef1,0x6f03,0x6f25,0x6ef8,
121.1498 +      0x6f37,0x6efb,0x6f2e,0x6f09,0x6f4e,0x6f19,0x6f1a,0x6f27,0x6f18,0x6f3b,
121.1499 +      0x6f12,0x6eed,0x6f0a
121.1500 +    },{
121.1501 +      0x6f36,0x6f73,0x6ef9,0x6eee,0x6f2d,0x6f40,0x6f30,0x6f3c,0x6f35,0x6eeb,
121.1502 +      0x6f07,0x6f0e,0x6f43,0x6f05,0x6efd,0x6ef6,0x6f39,0x6f1c,0x6efc,0x6f3a,
121.1503 +      0x6f1f,0x6f0d,0x6f1e,0x6f08,0x6f21,0x7187,0x7190,0x7189,0x7180,0x7185,
121.1504 +      0x7182,0x718f,0x717b,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,0x7295,
121.1505 +      0x7293,0x7343,0x734d,0x7351,0x734c,0x7462,0x7473,0x7471,0x7475,0x7472,
121.1506 +      0x7467,0x746e,0x7500,0x7502,0x7503,0x757d,0x7590,0x7616,0x7608,0x760c,
121.1507 +      0x7615,0x7611,0x760a,0x7614,0x76b8,0x7781,0x777c,0x7785,0x7782,0x776e,
121.1508 +      0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa,0x78b4,0x78ad,0x78a8,0x787e,
121.1509 +      0x78ab,0x789e,0x78a5,0x78a0,0x78ac,0x78a2,0x78a4,0x7998,0x798a,0x798b,
121.1510 +      0x7996,0x7995,0x7994,0x7993
121.1511 +    }
121.1512 +  },
121.1513 +  {				/* ku 43 */
121.1514 +    {
121.1515 +      0x7997,0x7988,0x7992,0x7990,0x7a2b,0x7a4a,0x7a30,0x7a2f,0x7a28,0x7a26,
121.1516 +      0x7aa8,0x7aab,0x7aac,0x7aee,0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96,
121.1517 +      0x7b8d,0x7b8c,0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82,
121.1518 +      0x7cbb,0x7cbf,0x7cbc,0x7cba,0x7da7,0x7db7,0x7dc2,0x7da3,0x7daa,0x7dc1,
121.1519 +      0x7dc0,0x7dc5,0x7d9d,0x7dce,0x7dc4,0x7dc6,0x7dcb,0x7dcc,0x7daf,0x7db9,
121.1520 +      0x7d96,0x7dbc,0x7d9f,0x7da6,0x7dae,0x7da9,0x7da1,0x7dc9,0x7f73,0x7fe2,
121.1521 +      0x7fe3,0x7fe5,0x7fde
121.1522 +    },{
121.1523 +      0x8024,0x805d,0x805c,0x8189,0x8186,0x8183,0x8187,0x818d,0x818c,0x818b,
121.1524 +      0x8215,0x8497,0x84a4,0x84a1,0x849f,0x84ba,0x84ce,0x84c2,0x84ac,0x84ae,
121.1525 +      0x84ab,0x84b9,0x84b4,0x84c1,0x84cd,0x84aa,0x849a,0x84b1,0x84d0,0x849d,
121.1526 +      0x84a7,0x84bb,0x84a2,0x8494,0x84c7,0x84cc,0x849b,0x84a9,0x84af,0x84a8,
121.1527 +      0x84d6,0x8498,0x84b6,0x84cf,0x84a0,0x84d7,0x84d4,0x84d2,0x84db,0x84b0,
121.1528 +      0x8491,0x8661,0x8733,0x8723,0x8728,0x876b,0x8740,0x872e,0x871e,0x8721,
121.1529 +      0x8719,0x871b,0x8743,0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a,
121.1530 +      0x872d,0x873c,0x8712,0x873a,0x8731,0x8735,0x8742,0x8726,0x8727,0x8738,
121.1531 +      0x8724,0x871a,0x8730,0x8711,0x88f7,0x88e7,0x88f1,0x88f2,0x88fa,0x88fe,
121.1532 +      0x88ee,0x88fc,0x88f6,0x88fb
121.1533 +    }
121.1534 +  },
121.1535 +  {				/* ku 44 */
121.1536 +    {
121.1537 +      0x88f0,0x88ec,0x88eb,0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb,0x89e8,
121.1538 +      0x8aab,0x8a99,0x8a8b,0x8a92,0x8a8f,0x8a96,0x8c3d,0x8c68,0x8c69,0x8cd5,
121.1539 +      0x8ccf,0x8cd7,0x8d96,0x8e09,0x8e02,0x8dff,0x8e0d,0x8dfd,0x8e0a,0x8e03,
121.1540 +      0x8e07,0x8e06,0x8e05,0x8dfe,0x8e00,0x8e04,0x8f10,0x8f11,0x8f0e,0x8f0d,
121.1541 +      0x9123,0x911c,0x9120,0x9122,0x911f,0x911d,0x911a,0x9124,0x9121,0x911b,
121.1542 +      0x917a,0x9172,0x9179,0x9173,0x92a5,0x92a4,0x9276,0x929b,0x927a,0x92a0,
121.1543 +      0x9294,0x92aa,0x928d
121.1544 +    },{
121.1545 +      0x92a6,0x929a,0x92ab,0x9279,0x9297,0x927f,0x92a3,0x92ee,0x928e,0x9282,
121.1546 +      0x9295,0x92a2,0x927d,0x9288,0x92a1,0x928a,0x9286,0x928c,0x9299,0x92a7,
121.1547 +      0x927e,0x9287,0x92a9,0x929d,0x928b,0x922d,0x969e,0x96a1,0x96ff,0x9758,
121.1548 +      0x977d,0x977a,0x977e,0x9783,0x9780,0x9782,0x977b,0x9784,0x9781,0x977f,
121.1549 +      0x97ce,0x97cd,0x9816,0x98ad,0x98ae,0x9902,0x9900,0x9907,0x999d,0x999c,
121.1550 +      0x99c3,0x99b9,0x99bb,0x99ba,0x99c2,0x99bd,0x99c7,0x9ab1,0x9ae3,0x9ae7,
121.1551 +      0x9b3e,0x9b3f,0x9b60,0x9b61,0x9b5f,0x9cf1,0x9cf2,0x9cf5,0x9ea7,0x50ff,
121.1552 +      0x5103,0x5130,0x50f8,0x5106,0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd,
121.1553 +      0x510a,0x528b,0x528c,0x52f1,0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641,
121.1554 +      0x564a,0x5649,0x5646,0x5658
121.1555 +    }
121.1556 +  },
121.1557 +  {				/* ku 45 */
121.1558 +    {
121.1559 +      0x565a,0x5640,0x5633,0x563d,0x562c,0x563e,0x5638,0x562a,0x563a,0x571a,
121.1560 +      0x58ab,0x589d,0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff,
121.1561 +      0x5aff,0x5af4,0x5afd,0x5af7,0x5af6,0x5b03,0x5af8,0x5b02,0x5af9,0x5b01,
121.1562 +      0x5b07,0x5b05,0x5b0f,0x5c67,0x5d99,0x5d97,0x5d9f,0x5d92,0x5da2,0x5d93,
121.1563 +      0x5d95,0x5da0,0x5d9c,0x5da1,0x5d9a,0x5d9e,0x5e69,0x5e5d,0x5e60,0x5e5c,
121.1564 +      0x7df3,0x5edb,0x5ede,0x5ee1,0x5f49,0x5fb2,0x618b,0x6183,0x6179,0x61b1,
121.1565 +      0x61b0,0x61a2,0x6189
121.1566 +    },{
121.1567 +      0x619b,0x6193,0x61af,0x61ad,0x619f,0x6192,0x61aa,0x61a1,0x618d,0x6166,
121.1568 +      0x61b3,0x622d,0x646e,0x6470,0x6496,0x64a0,0x6485,0x6497,0x649c,0x648f,
121.1569 +      0x648b,0x648a,0x648c,0x64a3,0x649f,0x6468,0x64b1,0x6498,0x6576,0x657a,
121.1570 +      0x6579,0x657b,0x65b2,0x65b3,0x66b5,0x66b0,0x66a9,0x66b2,0x66b7,0x66aa,
121.1571 +      0x66af,0x6a00,0x6a06,0x6a17,0x69e5,0x69f8,0x6a15,0x69f1,0x69e4,0x6a20,
121.1572 +      0x69ff,0x69ec,0x69e2,0x6a1b,0x6a1d,0x69fe,0x6a27,0x69f2,0x69ee,0x6a14,
121.1573 +      0x69f7,0x69e7,0x6a40,0x6a08,0x69e6,0x69fb,0x6a0d,0x69fc,0x69eb,0x6a09,
121.1574 +      0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6,0x6a26,0x6a07,0x69f4,0x6a16,0x6b51,
121.1575 +      0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01,0x6c00,0x6bff,0x6c02,0x6f41,0x6f26,
121.1576 +      0x6f7e,0x6f87,0x6fc6,0x6f92
121.1577 +    }
121.1578 +  },
121.1579 +  {				/* ku 46 */
121.1580 +    {
121.1581 +      0x6f8d,0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a,0x6f96,0x6f76,0x6f6c,
121.1582 +      0x6f82,0x6f55,0x6f72,0x6f52,0x6f50,0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00,
121.1583 +      0x6f61,0x6f6b,0x6f7d,0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95,
121.1584 +      0x6f63,0x6f77,0x6f6a,0x6f7b,0x71b2,0x71af,0x719b,0x71b0,0x71a0,0x719a,
121.1585 +      0x71a9,0x71b5,0x719d,0x71a5,0x719e,0x71a4,0x71a1,0x71aa,0x719c,0x71a7,
121.1586 +      0x71b3,0x7298,0x729a,0x7358,0x7352,0x735e,0x735f,0x7360,0x735d,0x735b,
121.1587 +      0x7361,0x735a,0x7359
121.1588 +    },{
121.1589 +      0x7362,0x7487,0x7489,0x748a,0x7486,0x7481,0x747d,0x7485,0x7488,0x747c,
121.1590 +      0x7479,0x7508,0x7507,0x757e,0x7625,0x761e,0x7619,0x761d,0x761c,0x7623,
121.1591 +      0x761a,0x7628,0x761b,0x769c,0x769d,0x769e,0x769b,0x778d,0x778f,0x7789,
121.1592 +      0x7788,0x78cd,0x78bb,0x78cf,0x78cc,0x78d1,0x78ce,0x78d4,0x78c8,0x78c3,
121.1593 +      0x78c4,0x78c9,0x799a,0x79a1,0x79a0,0x799c,0x79a2,0x799b,0x6b76,0x7a39,
121.1594 +      0x7ab2,0x7ab4,0x7ab3,0x7bb7,0x7bcb,0x7bbe,0x7bac,0x7bce,0x7baf,0x7bb9,
121.1595 +      0x7bca,0x7bb5,0x7cc5,0x7cc8,0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7,
121.1596 +      0x7dd7,0x7de1,0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf,
121.1597 +      0x7f76,0x7fac,0x7fb0,0x7fad,0x7fed,0x7feb,0x7fea,0x7fec,0x7fe6,0x7fe8,
121.1598 +      0x8064,0x8067,0x81a3,0x819f
121.1599 +    }
121.1600 +  },
121.1601 +  {				/* ku 47 */
121.1602 +    {
121.1603 +      0x819e,0x8195,0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250,
121.1604 +      0x824e,0x8251,0x8524,0x853b,0x850f,0x8500,0x8529,0x850e,0x8509,0x850d,
121.1605 +      0x851f,0x850a,0x8527,0x851c,0x84fb,0x852b,0x84fa,0x8508,0x850c,0x84f4,
121.1606 +      0x852a,0x84f2,0x8515,0x84f7,0x84eb,0x84f3,0x84fc,0x8512,0x84ea,0x84e9,
121.1607 +      0x8516,0x84fe,0x8528,0x851d,0x852e,0x8502,0x84fd,0x851e,0x84f6,0x8531,
121.1608 +      0x8526,0x84e7,0x84e8,0x84f0,0x84ef,0x84f9,0x8518,0x8520,0x8530,0x850b,
121.1609 +      0x8519,0x852f,0x8662
121.1610 +    },{
121.1611 +      0x8756,0x8763,0x8764,0x8777,0x87e1,0x8773,0x8758,0x8754,0x875b,0x8752,
121.1612 +      0x8761,0x875a,0x8751,0x875e,0x876d,0x876a,0x8750,0x874e,0x875f,0x875d,
121.1613 +      0x876f,0x876c,0x877a,0x876e,0x875c,0x8765,0x874f,0x877b,0x8775,0x8762,
121.1614 +      0x8767,0x8769,0x885a,0x8905,0x890c,0x8914,0x890b,0x8917,0x8918,0x8919,
121.1615 +      0x8906,0x8916,0x8911,0x890e,0x8909,0x89a2,0x89a4,0x89a3,0x89ed,0x89f0,
121.1616 +      0x89ec,0x8acf,0x8ac6,0x8ab8,0x8ad3,0x8ad1,0x8ad4,0x8ad5,0x8abb,0x8ad7,
121.1617 +      0x8abe,0x8ac0,0x8ac5,0x8ad8,0x8ac3,0x8aba,0x8abd,0x8ad9,0x8c3e,0x8c4d,
121.1618 +      0x8c8f,0x8ce5,0x8cdf,0x8cd9,0x8ce8,0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c,
121.1619 +      0x8da1,0x8d9b,0x8e20,0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16,
121.1620 +      0x8e11,0x8e19,0x8e26,0x8e27
121.1621 +    }
121.1622 +  },
121.1623 +  {				/* ku 48 */
121.1624 +    {
121.1625 +      0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c,0x8e17,0x8e1a,0x8f2c,0x8f24,0x8f18,
121.1626 +      0x8f1a,0x8f20,0x8f23,0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067,0x906b,
121.1627 +      0x912f,0x912b,0x9129,0x912a,0x9132,0x9126,0x912e,0x9185,0x9186,0x918a,
121.1628 +      0x9181,0x9182,0x9184,0x9180,0x92d0,0x92c3,0x92c4,0x92c0,0x92d9,0x92b6,
121.1629 +      0x92cf,0x92f1,0x92df,0x92d8,0x92e9,0x92d7,0x92dd,0x92cc,0x92ef,0x92c2,
121.1630 +      0x92e8,0x92ca,0x92c8,0x92ce,0x92e6,0x92cd,0x92d5,0x92c9,0x92e0,0x92de,
121.1631 +      0x92e7,0x92d1,0x92d3
121.1632 +    },{
121.1633 +      0x92b5,0x92e1,0x92c6,0x92b4,0x957c,0x95ac,0x95ab,0x95ae,0x95b0,0x96a4,
121.1634 +      0x96a2,0x96d3,0x9705,0x9708,0x9702,0x975a,0x978a,0x978e,0x9788,0x97d0,
121.1635 +      0x97cf,0x981e,0x981d,0x9826,0x9829,0x9828,0x9820,0x981b,0x9827,0x98b2,
121.1636 +      0x9908,0x98fa,0x9911,0x9914,0x9916,0x9917,0x9915,0x99dc,0x99cd,0x99cf,
121.1637 +      0x99d3,0x99d4,0x99ce,0x99c9,0x99d6,0x99d8,0x99cb,0x99d7,0x99cc,0x9ab3,
121.1638 +      0x9aec,0x9aeb,0x9af3,0x9af2,0x9af1,0x9b46,0x9b43,0x9b67,0x9b74,0x9b71,
121.1639 +      0x9b66,0x9b76,0x9b75,0x9b70,0x9b68,0x9b64,0x9b6c,0x9cfc,0x9cfa,0x9cfd,
121.1640 +      0x9cff,0x9cf7,0x9d07,0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05,0x9d04,0x9e83,
121.1641 +      0x9ed3,0x9f0f,0x9f10,0x511c,0x5113,0x5117,0x511a,0x5111,0x51de,0x5334,
121.1642 +      0x53e1,0x5670,0x5660,0x566e
121.1643 +    }
121.1644 +  },
121.1645 +  {				/* ku 49 */
121.1646 +    {
121.1647 +      0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c,0x571b,0x58c8,
121.1648 +      0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc,0x58c6,0x5b17,0x5b19,0x5b1b,
121.1649 +      0x5b21,0x5b14,0x5b13,0x5b10,0x5b16,0x5b28,0x5b1a,0x5b20,0x5b1e,0x5bef,
121.1650 +      0x5dac,0x5db1,0x5da9,0x5da7,0x5db5,0x5db0,0x5dae,0x5daa,0x5da8,0x5db2,
121.1651 +      0x5dad,0x5daf,0x5db4,0x5e67,0x5e68,0x5e66,0x5e6f,0x5ee9,0x5ee7,0x5ee6,
121.1652 +      0x5ee8,0x5ee5,0x5f4b,0x5fbc,0x619d,0x61a8,0x6196,0x61c5,0x61b4,0x61c6,
121.1653 +      0x61c1,0x61cc,0x61ba
121.1654 +    },{
121.1655 +      0x61bf,0x61b8,0x618c,0x64d7,0x64d6,0x64d0,0x64cf,0x64c9,0x64bd,0x6489,
121.1656 +      0x64c3,0x64db,0x64f3,0x64d9,0x6533,0x657f,0x657c,0x65a2,0x66c8,0x66be,
121.1657 +      0x66c0,0x66ca,0x66cb,0x66cf,0x66bd,0x66bb,0x66ba,0x66cc,0x6723,0x6a34,
121.1658 +      0x6a66,0x6a49,0x6a67,0x6a32,0x6a68,0x6a3e,0x6a5d,0x6a6d,0x6a76,0x6a5b,
121.1659 +      0x6a51,0x6a28,0x6a5a,0x6a3b,0x6a3f,0x6a41,0x6a6a,0x6a64,0x6a50,0x6a4f,
121.1660 +      0x6a54,0x6a6f,0x6a69,0x6a60,0x6a3c,0x6a5e,0x6a56,0x6a55,0x6a4d,0x6a4e,
121.1661 +      0x6a46,0x6b55,0x6b54,0x6b56,0x6ba7,0x6baa,0x6bab,0x6bc8,0x6bc7,0x6c04,
121.1662 +      0x6c03,0x6c06,0x6fad,0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8,0x6f5e,
121.1663 +      0x6fc4,0x6fbd,0x6f9e,0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba,0x6fac,
121.1664 +      0x6faa,0x6fcf,0x6fbf,0x6fb8
121.1665 +    }
121.1666 +  },
121.1667 +  {				/* ku 4a */
121.1668 +    {
121.1669 +      0x6fa2,0x6fc9,0x6fab,0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2,0x71bf,
121.1670 +      0x71b8,0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf,0x71bd,
121.1671 +      0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e,0x7369,0x7366,0x7367,
121.1672 +      0x736c,0x7365,0x736b,0x736a,0x747f,0x749a,0x74a0,0x7494,0x7492,0x7495,
121.1673 +      0x74a1,0x750b,0x7580,0x762f,0x762d,0x7631,0x763d,0x7633,0x763c,0x7635,
121.1674 +      0x7632,0x7630,0x76bb,0x76e6,0x779a,0x779d,0x77a1,0x779c,0x779b,0x77a2,
121.1675 +      0x77a3,0x7795,0x7799
121.1676 +    },{
121.1677 +      0x7797,0x78dd,0x78e9,0x78e5,0x78ea,0x78de,0x78e3,0x78db,0x78e1,0x78e2,
121.1678 +      0x78ed,0x78df,0x78e0,0x79a4,0x7a44,0x7a48,0x7a47,0x7ab6,0x7ab8,0x7ab5,
121.1679 +      0x7ab1,0x7ab7,0x7bde,0x7be3,0x7be7,0x7bdd,0x7bd5,0x7be5,0x7bda,0x7be8,
121.1680 +      0x7bf9,0x7bd4,0x7bea,0x7be2,0x7bdc,0x7beb,0x7bd8,0x7bdf,0x7cd2,0x7cd4,
121.1681 +      0x7cd7,0x7cd0,0x7cd1,0x7e12,0x7e21,0x7e17,0x7e0c,0x7e1f,0x7e20,0x7e13,
121.1682 +      0x7e0e,0x7e1c,0x7e15,0x7e1a,0x7e22,0x7e0b,0x7e0f,0x7e16,0x7e0d,0x7e14,
121.1683 +      0x7e25,0x7e24,0x7f43,0x7f7b,0x7f7c,0x7f7a,0x7fb1,0x7fef,0x802a,0x8029,
121.1684 +      0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5,0x81ab,0x81b0,0x81ac,0x81b4,
121.1685 +      0x81b2,0x81b7,0x81a7,0x81f2,0x8255,0x8256,0x8257,0x8556,0x8545,0x856b,
121.1686 +      0x854d,0x8553,0x8561,0x8558
121.1687 +    }
121.1688 +  },
121.1689 +  {				/* ku 4b */
121.1690 +    {
121.1691 +      0x8540,0x8546,0x8564,0x8541,0x8562,0x8544,0x8551,0x8547,0x8563,0x853e,
121.1692 +      0x855b,0x8571,0x854e,0x856e,0x8575,0x8555,0x8567,0x8560,0x858c,0x8566,
121.1693 +      0x855d,0x8554,0x8565,0x856c,0x8663,0x8665,0x8664,0x879b,0x878f,0x8797,
121.1694 +      0x8793,0x8792,0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87a3,0x8785,
121.1695 +      0x8790,0x8791,0x879d,0x8784,0x8794,0x879c,0x879a,0x8789,0x891e,0x8926,
121.1696 +      0x8930,0x892d,0x892e,0x8927,0x8931,0x8922,0x8929,0x8923,0x892f,0x892c,
121.1697 +      0x891f,0x89f1,0x8ae0
121.1698 +    },{
121.1699 +      0x8ae2,0x8af2,0x8af4,0x8af5,0x8add,0x8b14,0x8ae4,0x8adf,0x8af0,0x8ac8,
121.1700 +      0x8ade,0x8ae1,0x8ae8,0x8aff,0x8aef,0x8afb,0x8c91,0x8c92,0x8c90,0x8cf5,
121.1701 +      0x8cee,0x8cf1,0x8cf0,0x8cf3,0x8d6c,0x8d6e,0x8da5,0x8da7,0x8e33,0x8e3e,
121.1702 +      0x8e38,0x8e40,0x8e45,0x8e36,0x8e3c,0x8e3d,0x8e41,0x8e30,0x8e3f,0x8ebd,
121.1703 +      0x8f36,0x8f2e,0x8f35,0x8f32,0x8f39,0x8f37,0x8f34,0x9076,0x9079,0x907b,
121.1704 +      0x9086,0x90fa,0x9133,0x9135,0x9136,0x9193,0x9190,0x9191,0x918d,0x918f,
121.1705 +      0x9327,0x931e,0x9308,0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b,
121.1706 +      0x9323,0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d,0x92fa,
121.1707 +      0x9325,0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324,0x92ff,0x9329,0x9339,
121.1708 +      0x9335,0x932a,0x9314,0x930c
121.1709 +    }
121.1710 +  },
121.1711 +  {				/* ku 4c */
121.1712 +    {
121.1713 +      0x930b,0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc,0x95cd,0x95be,0x95b9,
121.1714 +      0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4,0x970b,0x9712,0x9710,
121.1715 +      0x9799,0x9797,0x9794,0x97f0,0x97f8,0x9835,0x982f,0x9832,0x9924,0x991f,
121.1716 +      0x9927,0x9929,0x999e,0x99ee,0x99ec,0x99e5,0x99e4,0x99f0,0x99e3,0x99ea,
121.1717 +      0x99e9,0x99e7,0x9ab9,0x9abf,0x9ab4,0x9abb,0x9af6,0x9afa,0x9af9,0x9af7,
121.1718 +      0x9b33,0x9b80,0x9b85,0x9b87,0x9b7c,0x9b7e,0x9b7b,0x9b82,0x9b93,0x9b92,
121.1719 +      0x9b90,0x9b7a,0x9b95
121.1720 +    },{
121.1721 +      0x9b7d,0x9b88,0x9d25,0x9d17,0x9d20,0x9d1e,0x9d14,0x9d29,0x9d1d,0x9d18,
121.1722 +      0x9d22,0x9d10,0x9d19,0x9d1f,0x9e88,0x9e86,0x9e87,0x9eae,0x9ead,0x9ed5,
121.1723 +      0x9ed6,0x9efa,0x9f12,0x9f3d,0x5126,0x5125,0x5122,0x5124,0x5120,0x5129,
121.1724 +      0x52f4,0x5693,0x568c,0x568d,0x5686,0x5684,0x5683,0x567e,0x5682,0x567f,
121.1725 +      0x5681,0x58d6,0x58d4,0x58cf,0x58d2,0x5b2d,0x5b25,0x5b32,0x5b23,0x5b2c,
121.1726 +      0x5b27,0x5b26,0x5b2f,0x5b2e,0x5b7b,0x5bf1,0x5bf2,0x5db7,0x5e6c,0x5e6a,
121.1727 +      0x5fbe,0x5fbb,0x61c3,0x61b5,0x61bc,0x61e7,0x61e0,0x61e5,0x61e4,0x61e8,
121.1728 +      0x61de,0x64ef,0x64e9,0x64e3,0x64eb,0x64e4,0x64e8,0x6581,0x6580,0x65b6,
121.1729 +      0x65da,0x66d2,0x6a8d,0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1,
121.1730 +      0x6a9e,0x6a87,0x6a93,0x6a8e
121.1731 +    }
121.1732 +  },
121.1733 +  {				/* ku 4d */
121.1734 +    {
121.1735 +      0x6a95,0x6a83,0x6aa8,0x6aa4,0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85,0x6a8c,
121.1736 +      0x6a92,0x6b5b,0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3,0x6fdc,
121.1737 +      0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8,0x71e1,0x71f1,
121.1738 +      0x71e8,0x71f2,0x71e4,0x71f0,0x71e2,0x7373,0x736e,0x736f,0x7497,0x74b2,
121.1739 +      0x74ab,0x7490,0x74aa,0x74ad,0x74b1,0x74a5,0x74af,0x7510,0x7511,0x7512,
121.1740 +      0x750f,0x7584,0x7643,0x7648,0x7649,0x7647,0x76a4,0x76e9,0x77b5,0x77ab,
121.1741 +      0x77b2,0x77b7,0x77b6
121.1742 +    },{
121.1743 +      0x77b4,0x77b1,0x77a8,0x77f0,0x78f3,0x78fd,0x7902,0x78fb,0x78fc,0x78f2,
121.1744 +      0x7905,0x78f9,0x78fe,0x7904,0x79ab,0x79a8,0x7a5c,0x7a5b,0x7a56,0x7a58,
121.1745 +      0x7a54,0x7a5a,0x7abe,0x7ac0,0x7ac1,0x7c05,0x7c0f,0x7bf2,0x7c00,0x7bff,
121.1746 +      0x7bfb,0x7c0e,0x7bf4,0x7c0b,0x7bf3,0x7c02,0x7c09,0x7c03,0x7c01,0x7bf8,
121.1747 +      0x7bfd,0x7c06,0x7bf0,0x7bf1,0x7c10,0x7c0a,0x7ce8,0x7e2d,0x7e3c,0x7e42,
121.1748 +      0x7e33,0x9848,0x7e38,0x7e2a,0x7e49,0x7e40,0x7e47,0x7e29,0x7e4c,0x7e30,
121.1749 +      0x7e3b,0x7e36,0x7e44,0x7e3a,0x7f45,0x7f7f,0x7f7e,0x7f7d,0x7ff4,0x7ff2,
121.1750 +      0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7,0x81bc,0x81e9,0x825b,
121.1751 +      0x825a,0x825c,0x8583,0x8580,0x858f,0x85a7,0x8595,0x85a0,0x858b,0x85a3,
121.1752 +      0x857b,0x85a4,0x859a,0x859e
121.1753 +    }
121.1754 +  },
121.1755 +  {				/* ku 4e */
121.1756 +    {
121.1757 +      0x8577,0x857c,0x8589,0x85a1,0x857a,0x8578,0x8557,0x858e,0x8596,0x8586,
121.1758 +      0x858d,0x8599,0x859d,0x8581,0x85a2,0x8582,0x8588,0x8585,0x8579,0x8576,
121.1759 +      0x8598,0x8590,0x859f,0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0,0x87ac,
121.1760 +      0x87b9,0x87b5,0x87bc,0x87ae,0x87c9,0x87c3,0x87c2,0x87cc,0x87b7,0x87af,
121.1761 +      0x87c4,0x87ca,0x87b4,0x87b6,0x87bf,0x87b8,0x87bd,0x87de,0x87b2,0x8935,
121.1762 +      0x8933,0x893c,0x893e,0x8941,0x8952,0x8937,0x8942,0x89ad,0x89af,0x89ae,
121.1763 +      0x89f2,0x89f3,0x8b1e
121.1764 +    },{
121.1765 +      0x8b18,0x8b16,0x8b11,0x8b05,0x8b0b,0x8b22,0x8b0f,0x8b12,0x8b15,0x8b07,
121.1766 +      0x8b0d,0x8b08,0x8b06,0x8b1c,0x8b13,0x8b1a,0x8c4f,0x8c70,0x8c72,0x8c71,
121.1767 +      0x8c6f,0x8c95,0x8c94,0x8cf9,0x8d6f,0x8e4e,0x8e4d,0x8e53,0x8e50,0x8e4c,
121.1768 +      0x8e47,0x8f43,0x8f40,0x9085,0x907e,0x9138,0x919a,0x91a2,0x919b,0x9199,
121.1769 +      0x919f,0x91a1,0x919d,0x91a0,0x93a1,0x9383,0x93af,0x9364,0x9356,0x9347,
121.1770 +      0x937c,0x9358,0x935c,0x9376,0x9349,0x9350,0x9351,0x9360,0x936d,0x938f,
121.1771 +      0x934c,0x936a,0x9379,0x9357,0x9355,0x9352,0x934f,0x9371,0x9377,0x937b,
121.1772 +      0x9361,0x935e,0x9363,0x9367,0x9380,0x934e,0x9359,0x95c7,0x95c0,0x95c9,
121.1773 +      0x95c3,0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f,0x9718,0x971d,
121.1774 +      0x9719,0x979a,0x97a1,0x979c
121.1775 +    }
121.1776 +  },
121.1777 +  {				/* ku 4f */
121.1778 +    {
121.1779 +      0x979e,0x979d,0x97d5,0x97d4,0x97f1,0x9841,0x9844,0x984a,0x9849,0x9845,
121.1780 +      0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932,0x992f,0x992d,0x9931,
121.1781 +      0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa,0x99f4,0x99f7,0x99f9,0x99f8,
121.1782 +      0x99f6,0x99fb,0x99fd,0x99fe,0x99fc,0x9a03,0x9abe,0x9afe,0x9afd,0x9b01,
121.1783 +      0x9afc,0x9b48,0x9b9a,0x9ba8,0x9b9e,0x9b9b,0x9ba6,0x9ba1,0x9ba5,0x9ba4,
121.1784 +      0x9b86,0x9ba2,0x9ba0,0x9baf,0x9d33,0x9d41,0x9d67,0x9d36,0x9d2e,0x9d2f,
121.1785 +      0x9d31,0x9d38,0x9d30
121.1786 +    },{
121.1787 +      0x9d45,0x9d42,0x9d43,0x9d3e,0x9d37,0x9d40,0x9d3d,0x7ff5,0x9d2d,0x9e8a,
121.1788 +      0x9e89,0x9e8d,0x9eb0,0x9ec8,0x9eda,0x9efb,0x9eff,0x9f24,0x9f23,0x9f22,
121.1789 +      0x9f54,0x9fa0,0x5131,0x512d,0x512e,0x5698,0x569c,0x5697,0x569a,0x569d,
121.1790 +      0x5699,0x5970,0x5b3c,0x5c69,0x5c6a,0x5dc0,0x5e6d,0x5e6e,0x61d8,0x61df,
121.1791 +      0x61ed,0x61ee,0x61f1,0x61ea,0x61f0,0x61eb,0x61d6,0x61e9,0x64ff,0x6504,
121.1792 +      0x64fd,0x64f8,0x6501,0x6503,0x64fc,0x6594,0x65db,0x66da,0x66db,0x66d8,
121.1793 +      0x6ac5,0x6ab9,0x6abd,0x6ae1,0x6ac6,0x6aba,0x6ab6,0x6ab7,0x6ac7,0x6ab4,
121.1794 +      0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007,0x700c,0x700d,0x7001,0x7005,0x7014,
121.1795 +      0x700e,0x6fff,0x7000,0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff,
121.1796 +      0x71f9,0x7203,0x71fd,0x7376
121.1797 +    }
121.1798 +  },
121.1799 +  {				/* ku 50 */
121.1800 +    {
121.1801 +      0x74b8,0x74c0,0x74b5,0x74c1,0x74be,0x74b6,0x74bb,0x74c2,0x7514,0x7513,
121.1802 +      0x765c,0x7664,0x7659,0x7650,0x7653,0x7657,0x765a,0x76a6,0x76bd,0x76ec,
121.1803 +      0x77c2,0x77ba,0x78ff,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912,0x7911,
121.1804 +      0x79ad,0x79ac,0x7a5f,0x7c1c,0x7c29,0x7c19,0x7c20,0x7c1f,0x7c2d,0x7c1d,
121.1805 +      0x7c26,0x7c28,0x7c22,0x7c25,0x7c30,0x7e5c,0x7e50,0x7e56,0x7e63,0x7e58,
121.1806 +      0x7e62,0x7e5f,0x7e51,0x7e60,0x7e57,0x7e53,0x7fb5,0x7fb3,0x7ff7,0x7ff8,
121.1807 +      0x8075,0x81d1,0x81d2
121.1808 +    },{
121.1809 +      0x81d0,0x825f,0x825e,0x85b4,0x85c6,0x85c0,0x85c3,0x85c2,0x85b3,0x85b5,
121.1810 +      0x85bd,0x85c7,0x85c4,0x85bf,0x85cb,0x85ce,0x85c8,0x85c5,0x85b1,0x85b6,
121.1811 +      0x85d2,0x8624,0x85b8,0x85b7,0x85be,0x8669,0x87e7,0x87e6,0x87e2,0x87db,
121.1812 +      0x87eb,0x87ea,0x87e5,0x87df,0x87f3,0x87e4,0x87d4,0x87dc,0x87d3,0x87ed,
121.1813 +      0x87d8,0x87e3,0x87a4,0x87d7,0x87d9,0x8801,0x87f4,0x87e8,0x87dd,0x8953,
121.1814 +      0x894b,0x894f,0x894c,0x8946,0x8950,0x8951,0x8949,0x8b2a,0x8b27,0x8b23,
121.1815 +      0x8b33,0x8b30,0x8b35,0x8b47,0x8b2f,0x8b3c,0x8b3e,0x8b31,0x8b25,0x8b37,
121.1816 +      0x8b26,0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42,0x8c75,0x8c99,
121.1817 +      0x8c98,0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00,0x8e5c,0x8e62,0x8e60,0x8e57,
121.1818 +      0x8e56,0x8e5e,0x8e65,0x8e67
121.1819 +    }
121.1820 +  },
121.1821 +  {				/* ku 51 */
121.1822 +    {
121.1823 +      0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46,0x8f47,0x8f48,0x8f4b,
121.1824 +      0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5,0x91a7,0x91af,0x91aa,0x93b5,
121.1825 +      0x938c,0x9392,0x93b7,0x939b,0x939d,0x9389,0x93a7,0x938e,0x93aa,0x939e,
121.1826 +      0x93a6,0x9395,0x9388,0x9399,0x939f,0x938d,0x93b1,0x9391,0x93b2,0x93a4,
121.1827 +      0x93a8,0x93b4,0x93a3,0x93a5,0x95d2,0x95d3,0x95d1,0x96b3,0x96d7,0x96da,
121.1828 +      0x5dc2,0x96df,0x96d8,0x96dd,0x9723,0x9722,0x9725,0x97ac,0x97ae,0x97a8,
121.1829 +      0x97ab,0x97a4,0x97aa
121.1830 +    },{
121.1831 +      0x97a2,0x97a5,0x97d7,0x97d9,0x97d6,0x97d8,0x97fa,0x9850,0x9851,0x9852,
121.1832 +      0x98b8,0x9941,0x993c,0x993a,0x9a0f,0x9a0b,0x9a09,0x9a0d,0x9a04,0x9a11,
121.1833 +      0x9a0a,0x9a05,0x9a07,0x9a06,0x9ac0,0x9adc,0x9b08,0x9b04,0x9b05,0x9b29,
121.1834 +      0x9b35,0x9b4a,0x9b4c,0x9b4b,0x9bc7,0x9bc6,0x9bc3,0x9bbf,0x9bc1,0x9bb5,
121.1835 +      0x9bb8,0x9bd3,0x9bb6,0x9bc4,0x9bb9,0x9bbd,0x9d5c,0x9d53,0x9d4f,0x9d4a,
121.1836 +      0x9d5b,0x9d4b,0x9d59,0x9d56,0x9d4c,0x9d57,0x9d52,0x9d54,0x9d5f,0x9d58,
121.1837 +      0x9d5a,0x9e8e,0x9e8c,0x9edf,0x9f01,0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a,
121.1838 +      0x9f29,0x9f28,0x9f4c,0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab,
121.1839 +      0x56ad,0x56a6,0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912,0x5b3d,
121.1840 +      0x5b3e,0x5b3f,0x5dc3,0x5e70
121.1841 +    }
121.1842 +  },
121.1843 +  {				/* ku 52 */
121.1844 +    {
121.1845 +      0x5fbf,0x61fb,0x6507,0x6510,0x650d,0x6509,0x650c,0x650e,0x6584,0x65de,
121.1846 +      0x65dd,0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb,0x6adf,0x6adc,
121.1847 +      0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0,0x6c0c,0x7019,0x7027,
121.1848 +      0x7020,0x7016,0x702b,0x7021,0x7022,0x7023,0x7029,0x7017,0x7024,0x701c,
121.1849 +      0x702a,0x720c,0x720a,0x7207,0x7202,0x7205,0x72a5,0x72a6,0x72a4,0x72a3,
121.1850 +      0x72a1,0x74cb,0x74c5,0x74b7,0x74c3,0x7516,0x7660,0x77c9,0x77ca,0x77c4,
121.1851 +      0x77f1,0x791d,0x791b
121.1852 +    },{
121.1853 +      0x7921,0x791c,0x7917,0x791e,0x79b0,0x7a67,0x7a68,0x7c33,0x7c3c,0x7c39,
121.1854 +      0x7c2c,0x7c3b,0x7cec,0x7cea,0x7e76,0x7e75,0x7e78,0x7e70,0x7e77,0x7e6f,
121.1855 +      0x7e7a,0x7e72,0x7e74,0x7e68,0x7f4b,0x7f4a,0x7f83,0x7f86,0x7fb7,0x7ffd,
121.1856 +      0x7ffe,0x8078,0x81d7,0x81d5,0x8264,0x8261,0x8263,0x85eb,0x85f1,0x85ed,
121.1857 +      0x85d9,0x85e1,0x85e8,0x85da,0x85d7,0x85ec,0x85f2,0x85f8,0x85d8,0x85df,
121.1858 +      0x85e3,0x85dc,0x85d1,0x85f0,0x85e6,0x85ef,0x85de,0x85e2,0x8800,0x87fa,
121.1859 +      0x8803,0x87f6,0x87f7,0x8809,0x880c,0x880b,0x8806,0x87fc,0x8808,0x87ff,
121.1860 +      0x880a,0x8802,0x8962,0x895a,0x895b,0x8957,0x8961,0x895c,0x8958,0x895d,
121.1861 +      0x8959,0x8988,0x89b7,0x89b6,0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53,
121.1862 +      0x8b56,0x8b54,0x8b4b,0x8b55
121.1863 +    }
121.1864 +  },
121.1865 +  {				/* ku 53 */
121.1866 +    {
121.1867 +      0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77,0x8c76,0x8c9a,0x8d06,0x8d07,
121.1868 +      0x8d09,0x8dac,0x8daa,0x8dad,0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a,0x8e6f,
121.1869 +      0x8e7b,0x8ec2,0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140,0x913f,
121.1870 +      0x91b0,0x91ad,0x93de,0x93c7,0x93cf,0x93c2,0x93da,0x93d0,0x93f9,0x93ec,
121.1871 +      0x93cc,0x93d9,0x93a9,0x93e6,0x93ca,0x93d4,0x93ee,0x93e3,0x93d5,0x93c4,
121.1872 +      0x93ce,0x93c0,0x93d2,0x93e7,0x957d,0x95da,0x95db,0x96e1,0x9729,0x972b,
121.1873 +      0x972c,0x9728,0x9726
121.1874 +    },{
121.1875 +      0x97b3,0x97b7,0x97b6,0x97dd,0x97de,0x97df,0x985c,0x9859,0x985d,0x9857,
121.1876 +      0x98bf,0x98bd,0x98bb,0x98be,0x9948,0x9947,0x9943,0x99a6,0x99a7,0x9a1a,
121.1877 +      0x9a15,0x9a25,0x9a1d,0x9a24,0x9a1b,0x9a22,0x9a20,0x9a27,0x9a23,0x9a1e,
121.1878 +      0x9a1c,0x9a14,0x9ac2,0x9b0b,0x9b0a,0x9b0e,0x9b0c,0x9b37,0x9bea,0x9beb,
121.1879 +      0x9be0,0x9bde,0x9be4,0x9be6,0x9be2,0x9bf0,0x9bd4,0x9bd7,0x9bec,0x9bdc,
121.1880 +      0x9bd9,0x9be5,0x9bd5,0x9be1,0x9bda,0x9d77,0x9d81,0x9d8a,0x9d84,0x9d88,
121.1881 +      0x9d71,0x9d80,0x9d78,0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74,0x9d75,
121.1882 +      0x9d70,0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f,0x9d87,
121.1883 +      0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40,0x9f41,0x9f4d,0x9f56,
121.1884 +      0x9f57,0x9f58,0x5337,0x56b2
121.1885 +    }
121.1886 +  },
121.1887 +  {				/* ku 54 */
121.1888 +    {
121.1889 +      0x56b5,0x56b3,0x58e3,0x5b45,0x5dc6,0x5dc7,0x5eee,0x5eef,0x5fc0,0x5fc1,
121.1890 +      0x61f9,0x6517,0x6516,0x6515,0x6513,0x65df,0x66e8,0x66e3,0x66e4,0x6af3,
121.1891 +      0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1,0x6aee,0x6aef,0x703c,0x7035,0x702f,
121.1892 +      0x7037,0x7034,0x7031,0x7042,0x7038,0x703f,0x703a,0x7039,0x7040,0x703b,
121.1893 +      0x7033,0x7041,0x7213,0x7214,0x72a8,0x737d,0x737c,0x74ba,0x76ab,0x76aa,
121.1894 +      0x76be,0x76ed,0x77cc,0x77ce,0x77cf,0x77cd,0x77f2,0x7925,0x7923,0x7927,
121.1895 +      0x7928,0x7924,0x7929
121.1896 +    },{
121.1897 +      0x79b2,0x7a6e,0x7a6c,0x7a6d,0x7af7,0x7c49,0x7c48,0x7c4a,0x7c47,0x7c45,
121.1898 +      0x7cee,0x7e7b,0x7e7e,0x7e81,0x7e80,0x7fba,0x7fff,0x8079,0x81db,0x81d9,
121.1899 +      0x820b,0x8268,0x8269,0x8622,0x85ff,0x8601,0x85fe,0x861b,0x8600,0x85f6,
121.1900 +      0x8604,0x8609,0x8605,0x860c,0x85fd,0x8819,0x8810,0x8811,0x8817,0x8813,
121.1901 +      0x8816,0x8963,0x8966,0x89b9,0x89f7,0x8b60,0x8b6a,0x8b5d,0x8b68,0x8b63,
121.1902 +      0x8b65,0x8b67,0x8b6d,0x8dae,0x8e86,0x8e88,0x8e84,0x8f59,0x8f56,0x8f57,
121.1903 +      0x8f55,0x8f58,0x8f5a,0x908d,0x9143,0x9141,0x91b7,0x91b5,0x91b2,0x91b3,
121.1904 +      0x940b,0x9413,0x93fb,0x9420,0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428,
121.1905 +      0x9419,0x940d,0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa,
121.1906 +      0x9409,0x93f8,0x940a,0x93ff
121.1907 +    }
121.1908 +  },
121.1909 +  {				/* ku 55 */
121.1910 +    {
121.1911 +      0x93fc,0x940c,0x93f6,0x9411,0x9406,0x95de,0x95e0,0x95df,0x972e,0x972f,
121.1912 +      0x97b9,0x97bb,0x97fd,0x97fe,0x9860,0x9862,0x9863,0x985f,0x98c1,0x98c2,
121.1913 +      0x9950,0x994e,0x9959,0x994c,0x994b,0x9953,0x9a32,0x9a34,0x9a31,0x9a2c,
121.1914 +      0x9a2a,0x9a36,0x9a29,0x9a2e,0x9a38,0x9a2d,0x9ac7,0x9aca,0x9ac6,0x9b10,
121.1915 +      0x9b12,0x9b11,0x9c0b,0x9c08,0x9bf7,0x9c05,0x9c12,0x9bf8,0x9c40,0x9c07,
121.1916 +      0x9c0e,0x9c06,0x9c17,0x9c14,0x9c09,0x9d9f,0x9d99,0x9da4,0x9d9d,0x9d92,
121.1917 +      0x9d98,0x9d90,0x9d9b
121.1918 +    },{
121.1919 +      0x9da0,0x9d94,0x9d9c,0x9daa,0x9d97,0x9da1,0x9d9a,0x9da2,0x9da8,0x9d9e,
121.1920 +      0x9da3,0x9dbf,0x9da9,0x9d96,0x9da6,0x9da7,0x9e99,0x9e9b,0x9e9a,0x9ee5,
121.1921 +      0x9ee4,0x9ee7,0x9ee6,0x9f30,0x9f2e,0x9f5b,0x9f60,0x9f5e,0x9f5d,0x9f59,
121.1922 +      0x9f91,0x513a,0x5139,0x5298,0x5297,0x56c3,0x56bd,0x56be,0x5b48,0x5b47,
121.1923 +      0x5dcb,0x5dcf,0x5ef1,0x61fd,0x651b,0x6b02,0x6afc,0x6b03,0x6af8,0x6b00,
121.1924 +      0x7043,0x7044,0x704a,0x7048,0x7049,0x7045,0x7046,0x721d,0x721a,0x7219,
121.1925 +      0x737e,0x7517,0x766a,0x77d0,0x792d,0x7931,0x792f,0x7c54,0x7c53,0x7cf2,
121.1926 +      0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d,0x7f4d,0x7fbb,0x8030,0x81dd,
121.1927 +      0x8618,0x862a,0x8626,0x861f,0x8623,0x861c,0x8619,0x8627,0x862e,0x8621,
121.1928 +      0x8620,0x8629,0x861e,0x8625
121.1929 +    }
121.1930 +  },
121.1931 +  {				/* ku 56 */
121.1932 +    {
121.1933 +      0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,0x882b,0x884a,0x896d,0x8969,
121.1934 +      0x896e,0x896b,0x89fa,0x8b79,0x8b78,0x8b45,0x8b7a,0x8b7b,0x8d10,0x8d14,
121.1935 +      0x8daf,0x8e8e,0x8e8c,0x8f5e,0x8f5b,0x8f5d,0x9146,0x9144,0x9145,0x91b9,
121.1936 +      0x943f,0x943b,0x9436,0x9429,0x943d,0x943c,0x9430,0x9439,0x942a,0x9437,
121.1937 +      0x942c,0x9440,0x9431,0x95e5,0x95e4,0x95e3,0x9735,0x973a,0x97bf,0x97e1,
121.1938 +      0x9864,0x98c9,0x98c6,0x98c0,0x9958,0x9956,0x9a39,0x9a3d,0x9a46,0x9a44,
121.1939 +      0x9a42,0x9a41,0x9a3a
121.1940 +    },{
121.1941 +      0x9a3f,0x9acd,0x9b15,0x9b17,0x9b18,0x9b16,0x9b3a,0x9b52,0x9c2b,0x9c1d,
121.1942 +      0x9c1c,0x9c2c,0x9c23,0x9c28,0x9c29,0x9c24,0x9c21,0x9db7,0x9db6,0x9dbc,
121.1943 +      0x9dc1,0x9dc7,0x9dca,0x9dcf,0x9dbe,0x9dc5,0x9dc3,0x9dbb,0x9db5,0x9dce,
121.1944 +      0x9db9,0x9dba,0x9dac,0x9dc8,0x9db1,0x9dad,0x9dcc,0x9db3,0x9dcd,0x9db2,
121.1945 +      0x9e7a,0x9e9c,0x9eeb,0x9eee,0x9eed,0x9f1b,0x9f18,0x9f1a,0x9f31,0x9f4e,
121.1946 +      0x9f65,0x9f64,0x9f92,0x4eb9,0x56c6,0x56c5,0x56cb,0x5971,0x5b4b,0x5b4c,
121.1947 +      0x5dd5,0x5dd1,0x5ef2,0x6521,0x6520,0x6526,0x6522,0x6b0b,0x6b08,0x6b09,
121.1948 +      0x6c0d,0x7055,0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9,0x737f,0x74d8,
121.1949 +      0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70,0x7a71,0x7c57,
121.1950 +      0x7c5c,0x7c59,0x7c5b,0x7c5a
121.1951 +    }
121.1952 +  },
121.1953 +  {				/* ku 57 */
121.1954 +    {
121.1955 +      0x7cf4,0x7cf1,0x7e91,0x7f4f,0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633,
121.1956 +      0x862c,0x8632,0x8636,0x882c,0x8828,0x8826,0x882a,0x8825,0x8971,0x89bf,
121.1957 +      0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86,0x8b85,0x8b7f,0x8d15,0x8e95,
121.1958 +      0x8e94,0x8e9a,0x8e92,0x8e90,0x8e96,0x8e97,0x8f60,0x8f62,0x9147,0x944c,
121.1959 +      0x9450,0x944a,0x944b,0x944f,0x9447,0x9445,0x9448,0x9449,0x9446,0x973f,
121.1960 +      0x97e3,0x986a,0x9869,0x98cb,0x9954,0x995b,0x9a4e,0x9a53,0x9a54,0x9a4c,
121.1961 +      0x9a4f,0x9a48,0x9a4a
121.1962 +    },{
121.1963 +      0x9a49,0x9a52,0x9a50,0x9ad0,0x9b19,0x9b2b,0x9b3b,0x9b56,0x9b55,0x9c46,
121.1964 +      0x9c48,0x9c3f,0x9c44,0x9c39,0x9c33,0x9c41,0x9c3c,0x9c37,0x9c34,0x9c32,
121.1965 +      0x9c3d,0x9c36,0x9ddb,0x9dd2,0x9dde,0x9dda,0x9dcb,0x9dd0,0x9ddc,0x9dd1,
121.1966 +      0x9ddf,0x9de9,0x9dd9,0x9dd8,0x9dd6,0x9df5,0x9dd5,0x9ddd,0x9eb6,0x9ef0,
121.1967 +      0x9f35,0x9f33,0x9f32,0x9f42,0x9f6b,0x9f95,0x9fa2,0x513d,0x5299,0x58e8,
121.1968 +      0x58e7,0x5972,0x5b4d,0x5dd8,0x882f,0x5f4f,0x6201,0x6203,0x6204,0x6529,
121.1969 +      0x6525,0x6596,0x66eb,0x6b11,0x6b12,0x6b0f,0x6bca,0x705b,0x705a,0x7222,
121.1970 +      0x7382,0x7381,0x7383,0x7670,0x77d4,0x7c67,0x7c66,0x7e95,0x826c,0x863a,
121.1971 +      0x8640,0x8639,0x863c,0x8631,0x863b,0x863e,0x8830,0x8832,0x882e,0x8833,
121.1972 +      0x8976,0x8974,0x8973,0x89fe
121.1973 +    }
121.1974 +  },
121.1975 +  {				/* ku 58 */
121.1976 +    {
121.1977 +      0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45,0x8d19,0x8e98,0x8f64,0x8f63,0x91bc,
121.1978 +      0x9462,0x9455,0x945d,0x9457,0x945e,0x97c4,0x97c5,0x9800,0x9a56,0x9a59,
121.1979 +      0x9b1e,0x9b1f,0x9b20,0x9c52,0x9c58,0x9c50,0x9c4a,0x9c4d,0x9c4b,0x9c55,
121.1980 +      0x9c59,0x9c4c,0x9c4e,0x9dfb,0x9df7,0x9def,0x9de3,0x9deb,0x9df8,0x9de4,
121.1981 +      0x9df6,0x9de1,0x9dee,0x9de6,0x9df2,0x9df0,0x9de2,0x9dec,0x9df4,0x9df3,
121.1982 +      0x9de8,0x9ded,0x9ec2,0x9ed0,0x9ef2,0x9ef3,0x9f06,0x9f1c,0x9f38,0x9f37,
121.1983 +      0x9f36,0x9f43,0x9f4f
121.1984 +    },{
121.1985 +      0x9f71,0x9f70,0x9f6e,0x9f6f,0x56d3,0x56cd,0x5b4e,0x5c6d,0x652d,0x66ed,
121.1986 +      0x66ee,0x6b13,0x705f,0x7061,0x705d,0x7060,0x7223,0x74db,0x74e5,0x77d5,
121.1987 +      0x7938,0x79b7,0x79b6,0x7c6a,0x7e97,0x7f89,0x826d,0x8643,0x8838,0x8837,
121.1988 +      0x8835,0x884b,0x8b94,0x8b95,0x8e9e,0x8e9f,0x8ea0,0x8e9d,0x91be,0x91bd,
121.1989 +      0x91c2,0x946b,0x9468,0x9469,0x96e5,0x9746,0x9743,0x9747,0x97c7,0x97e5,
121.1990 +      0x9a5e,0x9ad5,0x9b59,0x9c63,0x9c67,0x9c66,0x9c62,0x9c5e,0x9c60,0x9e02,
121.1991 +      0x9dfe,0x9e07,0x9e03,0x9e06,0x9e05,0x9e00,0x9e01,0x9e09,0x9dff,0x9dfd,
121.1992 +      0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75,0x9f76,0x56d4,0x652e,0x65b8,
121.1993 +      0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226,0x72aa,0x77d8,0x77d9,0x7939,
121.1994 +      0x7c69,0x7c6b,0x7cf6,0x7e9a
121.1995 +    }
121.1996 +  },
121.1997 +  {				/* ku 59 */
121.1998 +    {
121.1999 +      0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646,0x8647,0x8648,0x8979,0x897a,
121.2000 +      0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5,0x8ea4,0x8ea3,0x946e,0x946d,
121.2001 +      0x946f,0x9471,0x9473,0x9749,0x9872,0x995f,0x9c68,0x9c6e,0x9c6d,0x9e0b,
121.2002 +      0x9e0d,0x9e10,0x9e0f,0x9e12,0x9e11,0x9ea1,0x9ef5,0x9f09,0x9f47,0x9f78,
121.2003 +      0x9f7b,0x9f7a,0x9f79,0x571e,0x7066,0x7c6f,0x883c,0x8db2,0x8ea6,0x91c3,
121.2004 +      0x9474,0x9478,0x9476,0x9475,0x9a60,0x9c74,0x9c73,0x9c71,0x9c75,0x9e14,
121.2005 +      0x9e13,0x9ef6,0x9f0a
121.2006 +    },{
121.2007 +      0x9fa4,0x7068,0x7065,0x7cf7,0x866a,0x883e,0x883d,0x883f,0x8b9e,0x8c9c,
121.2008 +      0x8ea9,0x8ec9,0x974b,0x9873,0x9874,0x98cc,0x9961,0x99ab,0x9a64,0x9a66,
121.2009 +      0x9a67,0x9b24,0x9e15,0x9e17,0x9f48,0x6207,0x6b1e,0x7227,0x864c,0x8ea8,
121.2010 +      0x9482,0x9480,0x9481,0x9a69,0x9a68,0x9b2e,0x9e19,0x7229,0x864b,0x8b9f,
121.2011 +      0x9483,0x9c79,0x9eb7,0x7675,0x9a6b,0x9c7a,0x9e1d,0x7069,0x706a,0x9ea4,
121.2012 +      0x9f7e,0x9f49,0x9f98,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
121.2013 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
121.2014 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
121.2015 +      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
121.2016 +      UBOGON,UBOGON,UBOGON,UBOGON
121.2017 +    }
121.2018 +  }
121.2019 +};
   122.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.2 +++ b/src/charset/cns11643.c	Mon Sep 14 15:17:45 2009 +0900
   122.3 @@ -0,0 +1,8590 @@
   122.4 +/* ========================================================================
   122.5 + * Copyright 1988-2006 University of Washington
   122.6 + *
   122.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   122.8 + * you may not use this file except in compliance with the License.
   122.9 + * You may obtain a copy of the License at
  122.10 + *
  122.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  122.12 + *
  122.13 + * 
  122.14 + * ========================================================================
  122.15 + */
  122.16 +
  122.17 +/*
  122.18 + * Program:	CSN 11643 conversion table
  122.19 + *
  122.20 + * Author:	Mark Crispin
  122.21 + *		Networks and Distributed Computing
  122.22 + *		Computing & Communications
  122.23 + *		University of Washington
  122.24 + *		Administration Building, AG-44
  122.25 + *		Seattle, WA  98195
  122.26 + *		Internet: MRC@CAC.Washington.EDU
  122.27 + *
  122.28 + * Date:	3 July 1997
  122.29 + * Last Edited:	30 August 2006
  122.30 + */
  122.31 +
  122.32 +/* CNS 11643 is the national standard of the Republic of China (Taiwan).
  122.33 + * Thanks to Emily Hsu of the ROC's Institute for Information Industry for
  122.34 + * this data.
  122.35 + *
  122.36 + * Note: It is assumed that CJK Unified Ideographs Extension A are encoded
  122.37 + * in the BMP at U+3400 to U+4DB5.
  122.38 + */
  122.39 +
  122.40 +#define CNS_EXTENDED 1		/* include extended planes 3-15 */
  122.41 +#define CNS_OBSOLETE 0		/* include obsolete plane 14 */
  122.42 +#define CNS_EXTENSION 0		/* include extension plane 15 */
  122.43 +
  122.44 +#define BASE_CNS11643_KU 0x21
  122.45 +#define BASE_CNS11643_TEN 0x21
  122.46 +#define MAX_CNS11643_KU_1 93
  122.47 +#define MAX_CNS11643_KU_2 82
  122.48 +#if CNS_EXTENDED
  122.49 +#define MAX_CNS11643_KU_3 71
  122.50 +#define MAX_CNS11643_KU_4 78
  122.51 +#define MAX_CNS11643_KU_5 92
  122.52 +#define MAX_CNS11643_KU_6 68
  122.53 +#define MAX_CNS11643_KU_7 69
  122.54 +#if CNS_OBSOLETE
  122.55 +#define MAX_CNS11643_KU_14 71
  122.56 +#endif
  122.57 +#if CNS_EXTENSION
  122.58 +#define MAX_CNS11643_KU_15 77
  122.59 +#endif
  122.60 +#endif
  122.61 +#define MAX_CNS11643_TEN 94
  122.62 +
  122.63 +
  122.64 +#define CNS1TOUNICODE(c,c1,ku,ten)					\
  122.65 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_1) &&	\
  122.66 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
  122.67 +   cns11643_1tab[ku][ten] : UBOGON)
  122.68 +
  122.69 +
  122.70 +#define CNS2TOUNICODE(c,c1,ku,ten)					\
  122.71 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_2) &&	\
  122.72 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
  122.73 +   cns11643_2tab[ku][ten] : UBOGON)
  122.74 +
  122.75 +
  122.76 +#if CNS_EXTENDED
  122.77 +#define CNS3TOUNICODE(c,c1,ku,ten)					\
  122.78 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_3) &&	\
  122.79 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
  122.80 +   cns11643_3tab[ku][ten] : UBOGON)
  122.81 +
  122.82 +
  122.83 +#define CNS4TOUNICODE(c,c1,ku,ten)					\
  122.84 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_4) &&	\
  122.85 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
  122.86 +   cns11643_4tab[ku][ten] : UBOGON)
  122.87 +
  122.88 +
  122.89 +#define CNS5TOUNICODE(c,c1,ku,ten)					\
  122.90 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_5) &&	\
  122.91 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
  122.92 +   cns11643_5tab[ku][ten] : UBOGON)
  122.93 +
  122.94 +
  122.95 +#define CNS6TOUNICODE(c,c1,ku,ten)					\
  122.96 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_6) &&	\
  122.97 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
  122.98 +   cns11643_6tab[ku][ten] : UBOGON)
  122.99 +
 122.100 +
 122.101 +#define CNS7TOUNICODE(c,c1,ku,ten)					\
 122.102 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_7) &&	\
 122.103 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
 122.104 +   cns11643_7tab[ku][ten] : UBOGON)
 122.105 +
 122.106 +
 122.107 +#if CNS_OBSOLETE
 122.108 +#define CNS14TOUNICODE(c,c1,ku,ten)					\
 122.109 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_14) &&	\
 122.110 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
 122.111 +   cns11643_14tab[ku][ten] : UBOGON)
 122.112 +#endif
 122.113 +
 122.114 +
 122.115 +#if CNS_EXTENSION
 122.116 +#define CNS15TOUNICODE(c,c1,ku,ten)					\
 122.117 +  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_15) &&	\
 122.118 +    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
 122.119 +   cns11643_15tab[ku][ten] : UBOGON)
 122.120 +#endif
 122.121 +#endif
 122.122 +
 122.123 +/* CNS 11643 plane 1 conversion table */
 122.124 +
 122.125 +static const unsigned short
 122.126 +  cns11643_1tab[MAX_CNS11643_KU_1][MAX_CNS11643_TEN] = {
 122.127 +  {				/* ku 01 */
 122.128 +    0x3000,0xff0c,0x3001,0x3002,0xff0e,0x30fb,0xff1b,0xff1a,0xff1f,0xff01,
 122.129 +    0xfe30,0x2026,0x2025,0xfe50,0xfe51,0xfe52,0x00b7,0xfe54,0xfe55,0xfe56,
 122.130 +    0xfe57,0xfe31,0x2014,0xfe32,0x2013,UBOGON,UBOGON,UBOGON,UBOGON,0xff08,
 122.131 +    0xff09,0xfe35,0xfe36,0xff5b,0xff5d,0xfe37,0xfe38,0x3014,0x3015,0xfe39,
 122.132 +    0xfe3a,0x3010,0x3011,0xfe3b,0xfe3c,0x300a,0x300b,0xfe3d,0xfe3e,0x3008,
 122.133 +    0x3009,0xfe3f,0xfe40,0x300c,0x300d,0xfe41,0xfe42,0x300e,0x300f,0xfe43,
 122.134 +    0xfe44,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,0x2018,0x2019,0x201c,
 122.135 +    0x201d,0x301d,0x301e,0x2032,0x2035,0xff03,0xff06,0xff0a,0x203b,0x00a7,
 122.136 +    0x3003,0x25cb,0x25cf,0x25b3,0x25b2,0x25ce,0x2606,0x2605,0x25c7,0x25c6,
 122.137 +    0x25a1,0x25a0,0x25bd,0x25bc
 122.138 +  },
 122.139 +  {				/* ku 02 */
 122.140 +    0x32a3,0x2105,0x203e,UBOGON,0xff3f,UBOGON,0xfe49,0xfe4a,0xfe4d,0xfe4e,
 122.141 +    0xfe4b,0xfe4c,0xfe5f,0xfe60,0xfe61,0xff0b,0xff0d,0x00d7,0x00f7,0x00b1,
 122.142 +    0x221a,0xff1c,0xff1e,0xff1d,0x2266,0x2267,0x2260,0x221e,0x2252,0x2261,
 122.143 +    0xfe62,0xfe63,0xfe64,0xfe66,0xfe65,0x223c,0x2229,0x222a,0x22a5,0x2220,
 122.144 +    0x221f,0x22bf,0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640,0x2642,
 122.145 +    0x2641,0x2609,0x2191,0x2193,0x2192,0x2190,0x2196,0x2197,0x2199,0x2198,
 122.146 +    0x2016,0xff5c,0xff0f,0xff3c,0x2215,0xfe68,0xff04,0xffe5,0x3012,0xffe0,
 122.147 +    0xffe1,0xff05,0xff20,0x2103,0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c,
 122.148 +    0x339d,0x339e,0x33ce,0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b,
 122.149 +    0x515e,0x515d,0x5161,0x5163
 122.150 +  },
 122.151 +  {				/* ku 03 */
 122.152 +    0x55e7,0x74e9,0x7cce,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,
 122.153 +    0x2588,0x258f,0x258e,0x258d,0x258c,0x258b,0x258a,0x2589,0x253c,0x2534,
 122.154 +    0x252c,0x2524,0x251c,0x2594,0x2500,0x2502,0x2595,0x250c,0x2510,0x2514,
 122.155 +    0x2518,0x256d,0x256e,0x2570,0x256f,0x2550,0x255e,0x256a,0x2561,0x25e2,
 122.156 +    0x25e3,0x25e5,0x25e4,0x2571,0x2572,0x2573,UBOGON,UBOGON,UBOGON,UBOGON,
 122.157 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.158 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.159 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.160 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.161 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.162 +  },
 122.163 +  {				/* ku 04 */
 122.164 +    0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,0xff19,
 122.165 +    0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
 122.166 +    0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,0x3029,UBOGON,
 122.167 +    0x5344,UBOGON,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,
 122.168 +    0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,
 122.169 +    0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff41,0xff42,
 122.170 +    0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,
 122.171 +    0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,
 122.172 +    0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
 122.173 +    0x0397,0x0398,0x0399,0x039a
 122.174 +  },
 122.175 +  {				/* ku 05 */
 122.176 +    0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,
 122.177 +    0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,
 122.178 +    0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
 122.179 +    0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x3105,0x3106,
 122.180 +    0x3107,0x3108,0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,0x3110,
 122.181 +    0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,0x311a,
 122.182 +    0x311b,0x311c,0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,0x3124,
 122.183 +    0x3125,0x3126,0x3127,0x3128,0x3129,0x02d9,0x02c9,0x02ca,0x02c7,0x02cb,
 122.184 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.185 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.186 +  },
 122.187 +  {				/* ku 06 */
 122.188 +    0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,
 122.189 +    0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,
 122.190 +    0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,
 122.191 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.192 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.193 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.194 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.195 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.196 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.197 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.198 +  },
 122.199 +  {				/* ku 07 */
 122.200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ea0,UBOGON,UBOGON,
 122.201 +    UBOGON,UBOGON,UBOGON,UBOGON,0x51ab,UBOGON,UBOGON,UBOGON,UBOGON,0x52f9,
 122.202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.204 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.205 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.206 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.207 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.208 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.209 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.210 +  },
 122.211 +  {				/* ku 08 */
 122.212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.217 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.218 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.219 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.220 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.221 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.222 +  },
 122.223 +  {				/* ku 09 */
 122.224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.225 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.229 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.230 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.231 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.232 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.233 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.234 +  },
 122.235 +  {				/* ku 0a */
 122.236 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.239 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.241 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.242 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.243 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.244 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.245 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.246 +  },
 122.247 +  {				/* ku 0b */
 122.248 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.249 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.250 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.251 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.252 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.253 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.254 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.255 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.256 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.257 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.258 +  },
 122.259 +  {				/* ku 0c */
 122.260 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.261 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.262 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.263 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.265 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.266 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.267 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.268 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.269 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.270 +  },
 122.271 +  {				/* ku 0d */
 122.272 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.273 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.274 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.275 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.276 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.277 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.278 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.279 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.280 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.281 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.282 +  },
 122.283 +  {				/* ku 0e */
 122.284 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.285 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.286 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.287 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.288 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.289 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.290 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.291 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.292 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.293 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.294 +  },
 122.295 +  {				/* ku 0f */
 122.296 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.297 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.298 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.299 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.300 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.301 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.302 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.303 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.304 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.305 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.306 +  },
 122.307 +  {				/* ku 10 */
 122.308 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.309 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.310 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.311 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.312 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.313 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.314 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.315 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.316 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.317 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.318 +  },
 122.319 +  {				/* ku 11 */
 122.320 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.321 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.322 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.323 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.324 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.325 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.326 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.327 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.328 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.329 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.330 +  },
 122.331 +  {				/* ku 12 */
 122.332 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.333 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.334 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.335 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.336 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.337 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.338 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.339 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.340 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.341 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.342 +  },
 122.343 +  {				/* ku 13 */
 122.344 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.345 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.346 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.347 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.348 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.349 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.350 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.351 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.352 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.353 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.354 +  },
 122.355 +  {				/* ku 14 */
 122.356 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.357 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.358 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.359 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.360 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.361 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.362 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.363 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.364 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.365 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.366 +  },
 122.367 +  {				/* ku 15 */
 122.368 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.369 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.370 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.371 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.372 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.373 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.374 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.375 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.376 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.377 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.378 +  },
 122.379 +  {				/* ku 16 */
 122.380 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.381 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.382 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.383 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.384 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.385 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.386 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.387 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.388 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.389 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.390 +  },
 122.391 +  {				/* ku 17 */
 122.392 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.393 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.394 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.395 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.396 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.397 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.398 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.399 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.400 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.401 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.402 +  },
 122.403 +  {				/* ku 18 */
 122.404 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.405 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.406 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.407 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.408 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.409 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.410 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.411 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.412 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.413 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.414 +  },
 122.415 +  {				/* ku 19 */
 122.416 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.417 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.418 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.419 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.420 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.421 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.422 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.423 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.424 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.425 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.426 +  },
 122.427 +  {				/* ku 1a */
 122.428 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.429 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.430 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.431 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.432 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.433 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.434 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.435 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.436 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.437 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.438 +  },
 122.439 +  {				/* ku 1b */
 122.440 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.441 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.442 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.443 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.444 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.445 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.446 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.447 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.448 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.449 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.450 +  },
 122.451 +  {				/* ku 1c */
 122.452 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.453 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.454 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.455 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.456 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.457 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.458 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.459 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.460 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.461 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.462 +  },
 122.463 +  {				/* ku 1d */
 122.464 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.465 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.466 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.467 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.468 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.469 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.470 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.471 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.472 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.473 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.474 +  },
 122.475 +  {				/* ku 1e */
 122.476 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.477 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.478 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.479 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.480 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.481 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.482 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.483 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.484 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.485 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.486 +  },
 122.487 +  {				/* ku 1f */
 122.488 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.489 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.490 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.491 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.492 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.493 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.494 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.495 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.496 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.497 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.498 +  },
 122.499 +  {				/* ku 20 */
 122.500 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.501 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.502 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.503 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.504 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.505 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.506 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.507 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.508 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.509 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.510 +  },
 122.511 +  {				/* ku 21 */
 122.512 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.513 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.514 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.515 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.516 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.517 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.518 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.519 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.520 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.521 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.522 +  },
 122.523 +  {				/* ku 22 */
 122.524 +    0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,0x2408,0x2409,
 122.525 +    0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,0x2410,0x2411,0x2412,0x2413,
 122.526 +    0x2414,0x2415,0x2416,0x2417,0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,
 122.527 +    0x241e,0x241f,0x2421,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.528 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.529 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.530 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.531 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.532 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.533 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.534 +  },
 122.535 +  {				/* ku 23 */
 122.536 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.537 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.538 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.539 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.540 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.541 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.542 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.543 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.544 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 122.545 +    UBOGON,UBOGON,UBOGON,UBOGON
 122.546 +  },
 122.547 +  {				/* ku 24 */
 122.548 +    0x4e00,0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba,0x513f,
 122.549 +    0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315,0x5341,0x535c,0x53c8,
 122.550 +    0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b,0x4e38,0x51e1,0x4e45,0x4e48,0x4e5f,
 122.551 +    0x4e5e,0x4e8e,0x4ea1,0x5140,0x5203,0x52fa,0x5343,0x53c9,0x53e3,0x571f,
 122.552 +    0x58eb,0x5915,0x5927,0x5973,0x5b50,0x5b51,0x5b53,0x5bf8,0x5c0f,0x5c22,
 122.553 +    0x5c38,0x5c71,0x5ddd,0x5de5,0x5df1,0x5df2,0x5df3,0x5dfe,0x5e72,0x5efe,
 122.554 +    0x5f0b,0x5f13,0x624d,0x4e11,0x4e10,0x4e0d,0x4e2d,0x4e30,0x4e39,0x4e4b,
 122.555 +    0x5c39,0x4e88,0x4e91,0x4e95,0x4e92,0x4e94,0x4ea2,0x4ec1,0x4ec0,0x4ec3,
 122.556 +    0x4ec6,0x4ec7,0x4ecd,0x4eca,0x4ecb,0x4ec4,0x5143,0x5141,0x5167,0x516d,
 122.557 +    0x516e,0x516c,0x5197,0x51f6
 122.558 +  },
 122.559 +  {				/* ku 25 */
 122.560 +    0x5206,0x5207,0x5208,0x52fb,0x52fe,0x52ff,0x5316,0x5339,0x5348,0x5347,
 122.561 +    0x5345,0x535e,0x5384,0x53cb,0x53ca,0x53cd,0x58ec,0x5929,0x592b,0x592a,
 122.562 +    0x592d,0x5b54,0x5c11,0x5c24,0x5c3a,0x5c6f,0x5df4,0x5e7b,0x5eff,0x5f14,
 122.563 +    0x5f15,0x5fc3,0x6208,0x6236,0x624b,0x624e,0x652f,0x6587,0x6597,0x65a4,
 122.564 +    0x65b9,0x65e5,0x66f0,0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb,0x6bd4,
 122.565 +    0x6bdb,0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259,0x725b,
 122.566 +    0x72ac,0x738b,0x4e19,0x4e16,0x4e15,0x4e14,0x4e18,0x4e3b,0x4e4d,0x4e4f,
 122.567 +    0x4e4e,0x4ee5,0x4ed8,0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9,
 122.568 +    0x4ede,0x5145,0x5144,0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a,
 122.569 +    0x52a0,0x529f,0x5305,0x5306
 122.570 +  },
 122.571 +  {				/* ku 26 */
 122.572 +    0x5317,0x531d,0x4edf,0x534a,0x5349,0x5361,0x5360,0x536f,0x536e,0x53bb,
 122.573 +    0x53ef,0x53e4,0x53f3,0x53ec,0x53ee,0x53e9,0x53e8,0x53fc,0x53f8,0x53f5,
 122.574 +    0x53eb,0x53e6,0x53ea,0x53f2,0x53f1,0x53f0,0x53e5,0x53ed,0x53fb,0x56db,
 122.575 +    0x56da,0x5916,0x592e,0x5931,0x5974,0x5976,0x5b55,0x5b83,0x5c3c,0x5de8,
 122.576 +    0x5de7,0x5de6,0x5e02,0x5e03,0x5e73,0x5e7c,0x5f01,0x5f18,0x5f17,0x5fc5,
 122.577 +    0x620a,0x6253,0x6254,0x6252,0x6251,0x65a5,0x65e6,0x672e,0x672c,0x672a,
 122.578 +    0x672b,0x672d,0x6b63,0x6bcd,0x6c11,0x6c10,0x6c38,0x6c41,0x6c40,0x6c3e,
 122.579 +    0x72af,0x7384,0x7389,0x74dc,0x74e6,0x7518,0x751f,0x7528,0x7529,0x7530,
 122.580 +    0x7531,0x7532,0x7533,0x758b,0x767d,0x76ae,0x76bf,0x76ee,0x77db,0x77e2,
 122.581 +    0x77f3,0x793a,0x79be,0x7a74
 122.582 +  },
 122.583 +  {				/* ku 27 */
 122.584 +    0x7acb,0x4e1e,0x4e1f,0x4e52,0x4e53,0x4e69,0x4e99,0x4ea4,0x4ea6,0x4ea5,
 122.585 +    0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15,0x4f0d,0x4f10,0x4f11,0x4f0f,0x4ef2,
 122.586 +    0x4ef6,0x4efb,0x4ef0,0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149,0x5147,0x5146,
 122.587 +    0x5148,0x5168,0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e,0x5216,
 122.588 +    0x52a3,0x5308,0x5321,0x5320,0x5370,0x5371,0x5409,0x540f,0x540c,0x540a,
 122.589 +    0x5410,0x5401,0x540b,0x5404,0x5411,0x540d,0x5408,0x5403,0x540e,0x5406,
 122.590 +    0x5412,0x56e0,0x56de,0x56dd,0x5733,0x5730,0x5728,0x572d,0x572c,0x572f,
 122.591 +    0x5729,0x5919,0x591a,0x5937,0x5938,0x5984,0x5978,0x5983,0x597d,0x5979,
 122.592 +    0x5982,0x5981,0x5b57,0x5b58,0x5b87,0x5b88,0x5b85,0x5b89,0x5bfa,0x5c16,
 122.593 +    0x5c79,0x5dde,0x5e06,0x5e76
 122.594 +  },
 122.595 +  {				/* ku 28 */
 122.596 +    0x5e74,0x5f0f,0x5f1b,0x5fd9,0x5fd6,0x620e,0x620c,0x620d,0x6210,0x6263,
 122.597 +    0x625b,0x6258,0x6536,0x65e9,0x65e8,0x65ec,0x65ed,0x66f2,0x66f3,0x6709,
 122.598 +    0x673d,0x6734,0x6731,0x6735,0x6b21,0x6b64,0x6b7b,0x6c16,0x6c5d,0x6c57,
 122.599 +    0x6c59,0x6c5f,0x6c60,0x6c50,0x6c55,0x6c61,0x6c5b,0x6c4d,0x6c4e,0x7070,
 122.600 +    0x725f,0x725d,0x767e,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f8a,0x7fbd,0x8001,
 122.601 +    0x8003,0x800c,0x8012,0x8033,0x807f,0x8089,0x808b,0x808c,0x81e3,0x81ea,
 122.602 +    0x81f3,0x81fc,0x820c,0x821b,0x821f,0x826e,0x8272,0x827e,0x866b,0x8840,
 122.603 +    0x884c,0x8863,0x897f,0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57,
 122.604 +    0x4f5e,0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a,0x4f38,
 122.605 +    0x4f43,0x4f54,0x4f3c,0x4f46
 122.606 +  },
 122.607 +  {				/* ku 29 */
 122.608 +    0x4f63,0x4f5c,0x4f60,0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a,
 122.609 +    0x514c,0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229,0x522a,
 122.610 +    0x5228,0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373,0x5375,0x541d,0x542d,
 122.611 +    0x541e,0x543e,0x5426,0x544e,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442,
 122.612 +    0x541b,0x5429,0x544a,0x5439,0x543b,0x5438,0x542e,0x5435,0x5436,0x5420,
 122.613 +    0x543c,0x5440,0x5431,0x542b,0x541f,0x542c,0x56ea,0x56f0,0x56e4,0x56eb,
 122.614 +    0x574a,0x5751,0x5740,0x574d,0x5747,0x574e,0x573e,0x5750,0x574f,0x573b,
 122.615 +    0x58ef,0x593e,0x599d,0x5992,0x59a8,0x599e,0x59a3,0x5999,0x5996,0x598d,
 122.616 +    0x59a4,0x5993,0x598a,0x59a5,0x5b5d,0x5b5c,0x5b5a,0x5b5b,0x5b8c,0x5b8b,
 122.617 +    0x5b8f,0x5c2c,0x5c40,0x5c41
 122.618 +  },
 122.619 +  {				/* ku 2a */
 122.620 +    0x5c3f,0x5c3e,0x5c90,0x5c91,0x5c94,0x5c8c,0x5deb,0x5e0c,0x5e8f,0x5e87,
 122.621 +    0x5e8a,0x5ef7,0x5f04,0x5f1f,0x5f64,0x5f62,0x5f77,0x5f79,0x5fd8,0x5fcc,
 122.622 +    0x5fd7,0x5fcd,0x5ff1,0x5feb,0x5ff8,0x5fea,0x6212,0x6211,0x6284,0x6297,
 122.623 +    0x6296,0x6280,0x6276,0x6289,0x626d,0x628a,0x627c,0x627e,0x6279,0x6273,
 122.624 +    0x6292,0x626f,0x6298,0x626e,0x6295,0x6293,0x6291,0x6286,0x6539,0x653b,
 122.625 +    0x6538,0x65f1,0x66f4,0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756,
 122.626 +    0x675e,0x6749,0x6746,0x6760,0x6753,0x6757,0x6b65,0x6bcf,0x6c42,0x6c5e,
 122.627 +    0x6c99,0x6c81,0x6c88,0x6c89,0x6c85,0x6c9b,0x6c6a,0x6c7a,0x6c90,0x6c70,
 122.628 +    0x6c8c,0x6c68,0x6c96,0x6c92,0x6c7d,0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86,
 122.629 +    0x6c76,0x6c8d,0x6c94,0x6c98
 122.630 +  },
 122.631 +  {				/* ku 2b */
 122.632 +    0x6c82,0x7076,0x707c,0x707d,0x7078,0x7262,0x7261,0x7260,0x72c4,0x72c2,
 122.633 +    0x7396,0x752c,0x752b,0x7537,0x7538,0x7682,0x76ef,0x77e3,0x79c1,0x79c0,
 122.634 +    0x79bf,0x7a76,0x7cfb,0x7f55,0x8096,0x8093,0x809d,0x8098,0x809b,0x809a,
 122.635 +    0x80b2,0x826f,0x8292,0x828b,0x828d,0x898b,0x89d2,0x8a00,0x8c37,0x8c46,
 122.636 +    0x8c55,0x8c9d,0x8d64,0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fc2,
 122.637 +    0x8fc6,0x8fc5,0x8fc4,0x5de1,0x9091,0x90a2,0x90aa,0x90a6,0x90a3,0x9149,
 122.638 +    0x91c6,0x91cc,0x9632,0x962e,0x9631,0x962a,0x962c,0x4e26,0x4e56,0x4e73,
 122.639 +    0x4e8b,0x4e9b,0x4e9e,0x4eab,0x4eac,0x4f6f,0x4f9d,0x4f8d,0x4f73,0x4f7f,
 122.640 +    0x4f6c,0x4f9b,0x4f8b,0x4f86,0x4f83,0x4f70,0x4f75,0x4f88,0x4f69,0x4f7b,
 122.641 +    0x4f96,0x4f7e,0x4f8f,0x4f91
 122.642 +  },
 122.643 +  {				/* ku 2c */
 122.644 +    0x4f7a,0x5154,0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51bd,0x51fd,
 122.645 +    0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236,0x5241,0x52be,0x52bb,
 122.646 +    0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,0x5378,0x5379,0x53d6,0x53d4,
 122.647 +    0x53d7,0x5473,0x5475,0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484,
 122.648 +    0x5492,0x5486,0x547c,0x5490,0x5471,0x5476,0x548c,0x549a,0x5462,0x5468,
 122.649 +    0x548b,0x547d,0x548e,0x56fa,0x5783,0x5777,0x576a,0x5769,0x5761,0x5766,
 122.650 +    0x5764,0x577c,0x591c,0x5949,0x5947,0x5948,0x5944,0x5954,0x59be,0x59bb,
 122.651 +    0x59d4,0x59b9,0x59ae,0x59d1,0x59c6,0x59d0,0x59cd,0x59cb,0x59d3,0x59ca,
 122.652 +    0x59af,0x59b3,0x59d2,0x59c5,0x5b5f,0x5b64,0x5b63,0x5b97,0x5b9a,0x5b98,
 122.653 +    0x5b9c,0x5b99,0x5b9b,0x5c1a
 122.654 +  },
 122.655 +  {				/* ku 2d */
 122.656 +    0x5c48,0x5c45,0x5c46,0x5cb7,0x5ca1,0x5cb8,0x5ca9,0x5cab,0x5cb1,0x5cb3,
 122.657 +    0x5e18,0x5e1a,0x5e16,0x5e15,0x5e1b,0x5e11,0x5e78,0x5e9a,0x5e97,0x5e9c,
 122.658 +    0x5e95,0x5e96,0x5ef6,0x5f26,0x5f27,0x5f29,0x5f80,0x5f81,0x5f7f,0x5f7c,
 122.659 +    0x5fdd,0x5fe0,0x5ffd,0x5ff5,0x5fff,0x600f,0x6014,0x602f,0x6035,0x6016,
 122.660 +    0x602a,0x6015,0x6021,0x6027,0x6029,0x602b,0x601b,0x6216,0x6215,0x623f,
 122.661 +    0x623e,0x6240,0x627f,0x62c9,0x62cc,0x62c4,0x62bf,0x62c2,0x62b9,0x62d2,
 122.662 +    0x62db,0x62ab,0x62d3,0x62d4,0x62cb,0x62c8,0x62a8,0x62bd,0x62bc,0x62d0,
 122.663 +    0x62d9,0x62c7,0x62cd,0x62b5,0x62da,0x62b1,0x62d8,0x62d6,0x62d7,0x62c6,
 122.664 +    0x62ac,0x62ce,0x653e,0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606,
 122.665 +    0x6602,0x660e,0x6600,0x660f
 122.666 +  },
 122.667 +  {				/* ku 2e */
 122.668 +    0x6615,0x660a,0x6607,0x670d,0x670b,0x676d,0x678b,0x6795,0x6771,0x679c,
 122.669 +    0x6773,0x6777,0x6787,0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e,
 122.670 +    0x6790,0x6775,0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66,0x6b67,
 122.671 +    0x6b7f,0x6c13,0x6c1b,0x6ce3,0x6ce8,0x6cf3,0x6cb1,0x6ccc,0x6ce5,0x6cb3,
 122.672 +    0x6cbd,0x6cbe,0x6cbc,0x6ce2,0x6cab,0x6cd5,0x6cd3,0x6cb8,0x6cc4,0x6cb9,
 122.673 +    0x6cc1,0x6cae,0x6cd7,0x6cc5,0x6cf1,0x6cbf,0x6cbb,0x6ce1,0x6cdb,0x6cca,
 122.674 +    0x6cac,0x6cef,0x6cdc,0x6cd6,0x6ce0,0x7095,0x708e,0x7092,0x708a,0x7099,
 122.675 +    0x722c,0x722d,0x7238,0x7248,0x7267,0x7269,0x72c0,0x72ce,0x72d9,0x72d7,
 122.676 +    0x72d0,0x73a9,0x73a8,0x739f,0x73ab,0x73a5,0x753d,0x759d,0x7599,0x759a,
 122.677 +    0x7684,0x76c2,0x76f2,0x76f4
 122.678 +  },
 122.679 +  {				/* ku 2f */
 122.680 +    0x77e5,0x77fd,0x793e,0x7940,0x7941,0x79c9,0x79c8,0x7a7a,0x7a79,0x7afa,
 122.681 +    0x7cfe,0x7f54,0x7f8c,0x7f8b,0x8005,0x80ba,0x80a5,0x80a2,0x80b1,0x80a1,
 122.682 +    0x80ab,0x80a9,0x80b4,0x80aa,0x80af,0x81e5,0x81fe,0x820d,0x82b3,0x829d,
 122.683 +    0x8299,0x82ad,0x82bd,0x829f,0x82b9,0x82b1,0x82ac,0x82a5,0x82af,0x82b8,
 122.684 +    0x82a3,0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d,0x8868,0x8ecb,0x8fce,
 122.685 +    0x8fd4,0x8fd1,0x90b5,0x90b8,0x90b1,0x90b6,0x91c7,0x91d1,0x9577,0x9580,
 122.686 +    0x961c,0x9640,0x963f,0x963b,0x9644,0x9642,0x96b9,0x96e8,0x9752,0x975e,
 122.687 +    0x4e9f,0x4ead,0x4eae,0x4fe1,0x4fb5,0x4faf,0x4fbf,0x4fe0,0x4fd1,0x4fcf,
 122.688 +    0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf,0x4fca,0x4fd7,0x4fae,0x4fd0,0x4fc4,
 122.689 +    0x4fc2,0x4fda,0x4fce,0x4fde
 122.690 +  },
 122.691 +  {				/* ku 30 */
 122.692 +    0x4fb7,0x5157,0x5192,0x5191,0x51a0,0x524e,0x5243,0x524a,0x524d,0x524c,
 122.693 +    0x524b,0x5247,0x52c7,0x52c9,0x52c3,0x52c1,0x530d,0x5357,0x537b,0x539a,
 122.694 +    0x53db,0x54ac,0x54c0,0x54a8,0x54ce,0x54c9,0x54b8,0x54a6,0x54b3,0x54c7,
 122.695 +    0x54c2,0x54bd,0x54aa,0x54c1,0x54c4,0x54c8,0x54af,0x54ab,0x54b1,0x54bb,
 122.696 +    0x54a9,0x54a7,0x54bf,0x56ff,0x5782,0x578b,0x57a0,0x57a3,0x57a2,0x57ce,
 122.697 +    0x57ae,0x5793,0x5955,0x5951,0x594f,0x594e,0x5950,0x59dc,0x59d8,0x59ff,
 122.698 +    0x59e3,0x59e8,0x5a03,0x59e5,0x59ea,0x59da,0x59e6,0x5a01,0x59fb,0x5b69,
 122.699 +    0x5ba3,0x5ba6,0x5ba4,0x5ba2,0x5ba5,0x5c01,0x5c4e,0x5c4f,0x5c4d,0x5c4b,
 122.700 +    0x5cd9,0x5cd2,0x5df7,0x5e1d,0x5e25,0x5e1f,0x5e7d,0x5ea0,0x5ea6,0x5efa,
 122.701 +    0x5f08,0x5f2d,0x5f65,0x5f88
 122.702 +  },
 122.703 +  {				/* ku 31 */
 122.704 +    0x5f85,0x5f8a,0x5f8b,0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025,
 122.705 +    0x600e,0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c,0x606b,
 122.706 +    0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc,0x62ed,0x6301,0x62ee,
 122.707 +    0x62fd,0x6307,0x62f1,0x62f7,0x62ef,0x62ec,0x62fe,0x62f4,0x6311,0x6302,
 122.708 +    0x653f,0x6545,0x65ab,0x65bd,0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f,
 122.709 +    0x661f,0x6628,0x6631,0x6624,0x66f7,0x67ff,0x67d3,0x67f1,0x67d4,0x67d0,
 122.710 +    0x67ec,0x67b6,0x67af,0x67f5,0x67e9,0x67ef,0x67c4,0x67d1,0x67b4,0x67da,
 122.711 +    0x67e5,0x67b8,0x67cf,0x67de,0x67f3,0x67b0,0x67d9,0x67e2,0x67dd,0x67d2,
 122.712 +    0x6b6a,0x6b83,0x6b86,0x6bb5,0x6bd2,0x6bd7,0x6c1f,0x6cc9,0x6d0b,0x6d32,
 122.713 +    0x6d2a,0x6d41,0x6d25,0x6d0c
 122.714 +  },
 122.715 +  {				/* ku 32 */
 122.716 +    0x6d31,0x6d1e,0x6d17,0x6d3b,0x6d3d,0x6d3e,0x6d36,0x6d1b,0x6cf5,0x6d39,
 122.717 +    0x6d27,0x6d38,0x6d29,0x6d2e,0x6d35,0x6d0e,0x6d2b,0x70ab,0x70ba,0x70b3,
 122.718 +    0x70ac,0x70af,0x70ad,0x70b8,0x70ae,0x70a4,0x7230,0x7272,0x726f,0x7274,
 122.719 +    0x72e9,0x72e0,0x72e1,0x73b7,0x73ca,0x73bb,0x73b2,0x73cd,0x73c0,0x73b3,
 122.720 +    0x751a,0x752d,0x754f,0x754c,0x754e,0x754b,0x75ab,0x75a4,0x75a5,0x75a2,
 122.721 +    0x75a3,0x7678,0x7686,0x7687,0x7688,0x76c8,0x76c6,0x76c3,0x76c5,0x7701,
 122.722 +    0x76f9,0x76f8,0x7709,0x770b,0x76fe,0x76fc,0x7707,0x77dc,0x7802,0x7814,
 122.723 +    0x780c,0x780d,0x7946,0x7949,0x7948,0x7947,0x79b9,0x79ba,0x79d1,0x79d2,
 122.724 +    0x79cb,0x7a7f,0x7a81,0x7aff,0x7afd,0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09,
 122.725 +    0x7d07,0x7d04,0x7d06,0x7f38
 122.726 +  },
 122.727 +  {				/* ku 33 */
 122.728 +    0x7f8e,0x7fbf,0x8010,0x800d,0x8011,0x8036,0x80d6,0x80e5,0x80da,0x80c3,
 122.729 +    0x80c4,0x80cc,0x80e1,0x80db,0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222,
 122.730 +    0x82e7,0x8303,0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309,
 122.731 +    0x82d2,0x82d7,0x82f1,0x8301,0x82dc,0x82d4,0x82d1,0x82de,0x82d3,0x82df,
 122.732 +    0x82ef,0x8306,0x8650,0x8679,0x867b,0x867a,0x884d,0x886b,0x8981,0x89d4,
 122.733 +    0x8a08,0x8a02,0x8a03,0x8c9e,0x8ca0,0x8d74,0x8d73,0x8db4,0x8ecd,0x8ecc,
 122.734 +    0x8ff0,0x8fe6,0x8fe2,0x8fea,0x8fe5,0x8fed,0x8feb,0x8fe4,0x8fe8,0x90ca,
 122.735 +    0x90ce,0x90c1,0x90c3,0x914b,0x914a,0x91cd,0x9582,0x9650,0x964b,0x964c,
 122.736 +    0x964d,0x9762,0x9769,0x97cb,0x97ed,0x97f3,0x9801,0x98a8,0x98db,0x98df,
 122.737 +    0x9996,0x9999,0x4e58,0x4eb3
 122.738 +  },
 122.739 +  {				/* ku 34 */
 122.740 +    0x500c,0x500d,0x5023,0x4fef,0x5026,0x5025,0x4ff8,0x5029,0x5016,0x5006,
 122.741 +    0x503c,0x501f,0x501a,0x5012,0x5011,0x4ffa,0x5000,0x5014,0x5028,0x4ff1,
 122.742 +    0x5021,0x500b,0x5019,0x5018,0x4ff3,0x4fee,0x502d,0x502a,0x4ffe,0x502b,
 122.743 +    0x5009,0x517c,0x51a4,0x51a5,0x51a2,0x51cd,0x51cc,0x51c6,0x51cb,0x5256,
 122.744 +    0x525c,0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d,0x53df,0x54e8,
 122.745 +    0x5510,0x5501,0x5537,0x54fc,0x54e5,0x54f2,0x5506,0x54fa,0x5514,0x54e9,
 122.746 +    0x54ed,0x54e1,0x5509,0x54ee,0x54ea,0x54e6,0x5527,0x5507,0x54fd,0x550f,
 122.747 +    0x5703,0x5704,0x57c2,0x57d4,0x57cb,0x57c3,0x5809,0x590f,0x5957,0x5958,
 122.748 +    0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f,0x5a1b,0x5a13,0x59ec,0x5a20,0x5a23,
 122.749 +    0x5a29,0x5a25,0x5a0c,0x5a09
 122.750 +  },
 122.751 +  {				/* ku 35 */
 122.752 +    0x5b6b,0x5c58,0x5bb0,0x5bb3,0x5bb6,0x5bb4,0x5bae,0x5bb5,0x5bb9,0x5bb8,
 122.753 +    0x5c04,0x5c51,0x5c55,0x5c50,0x5ced,0x5cfd,0x5cfb,0x5cea,0x5ce8,0x5cf0,
 122.754 +    0x5cf6,0x5d01,0x5cf4,0x5dee,0x5e2d,0x5e2b,0x5eab,0x5ead,0x5ea7,0x5f31,
 122.755 +    0x5f92,0x5f91,0x5f90,0x6059,0x6063,0x6065,0x6050,0x6055,0x606d,0x6069,
 122.756 +    0x606f,0x6084,0x609f,0x609a,0x608d,0x6094,0x608c,0x6085,0x6096,0x6247,
 122.757 +    0x62f3,0x6308,0x62ff,0x634e,0x633e,0x632f,0x6355,0x6342,0x6346,0x634f,
 122.758 +    0x6349,0x633a,0x6350,0x633d,0x632a,0x632b,0x6328,0x634d,0x634c,0x6548,
 122.759 +    0x6549,0x6599,0x65c1,0x65c5,0x6642,0x6649,0x664f,0x6643,0x6652,0x664c,
 122.760 +    0x6645,0x6641,0x66f8,0x6714,0x6715,0x6717,0x6821,0x6838,0x6848,0x6846,
 122.761 +    0x6853,0x6839,0x6842,0x6854
 122.762 +  },
 122.763 +  {				/* ku 36 */
 122.764 +    0x6829,0x68b3,0x6817,0x684c,0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c,
 122.765 +    0x6843,0x682a,0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23,
 122.766 +    0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88,0x6d87,0x6d66,
 122.767 +    0x6d78,0x6d77,0x6d59,0x6d93,0x6d6c,0x6d89,0x6d6e,0x6d5a,0x6d74,0x6d69,
 122.768 +    0x6d8c,0x6d8a,0x6d79,0x6d85,0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9,
 122.769 +    0x70c8,0x70cf,0x7239,0x7279,0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386,
 122.770 +    0x73ed,0x7409,0x73ee,0x73e0,0x73ea,0x73de,0x7554,0x755d,0x755c,0x755a,
 122.771 +    0x7559,0x75be,0x75c5,0x75c7,0x75b2,0x75b3,0x75bd,0x75bc,0x75b9,0x75c2,
 122.772 +    0x75b8,0x768b,0x76b0,0x76ca,0x76cd,0x76ce,0x7729,0x771f,0x7720,0x7728,
 122.773 +    0x77e9,0x7830,0x7827,0x7838
 122.774 +  },
 122.775 +  {				/* ku 37 */
 122.776 +    0x781d,0x7834,0x7837,0x7825,0x782d,0x7820,0x781f,0x7832,0x7955,0x7950,
 122.777 +    0x7960,0x795f,0x7956,0x795e,0x795d,0x7957,0x795a,0x79e4,0x79e3,0x79e7,
 122.778 +    0x79df,0x79e6,0x79e9,0x79d8,0x7a84,0x7a88,0x7ad9,0x7b06,0x7b11,0x7c89,
 122.779 +    0x7d21,0x7d17,0x7d0b,0x7d0a,0x7d20,0x7d22,0x7d14,0x7d10,0x7d15,0x7d1a,
 122.780 +    0x7d1c,0x7d0d,0x7d19,0x7d1b,0x7f3a,0x7f5f,0x7f94,0x7fc5,0x7fc1,0x8006,
 122.781 +    0x8004,0x8018,0x8015,0x8019,0x8017,0x803d,0x803f,0x80f1,0x8102,0x80f0,
 122.782 +    0x8105,0x80ed,0x80f4,0x8106,0x80f8,0x80f3,0x8108,0x80fd,0x810a,0x80fc,
 122.783 +    0x80ef,0x81ed,0x81ec,0x8200,0x8210,0x822a,0x822b,0x8228,0x822c,0x82bb,
 122.784 +    0x832b,0x8352,0x8354,0x834a,0x8338,0x8350,0x8349,0x8335,0x8334,0x834f,
 122.785 +    0x8332,0x8339,0x8336,0x8317
 122.786 +  },
 122.787 +  {				/* ku 38 */
 122.788 +    0x8340,0x8331,0x8328,0x8343,0x8654,0x868a,0x86aa,0x8693,0x86a4,0x86a9,
 122.789 +    0x868c,0x86a3,0x869c,0x8870,0x8877,0x8881,0x8882,0x887d,0x8879,0x8a18,
 122.790 +    0x8a10,0x8a0e,0x8a0c,0x8a15,0x8a0a,0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11,
 122.791 +    0x8c48,0x8c7a,0x8c79,0x8ca1,0x8ca2,0x8d77,0x8eac,0x8ed2,0x8ed4,0x8ecf,
 122.792 +    0x8fb1,0x9001,0x9006,0x8ff7,0x9000,0x8ffa,0x8ff4,0x9003,0x8ffd,0x9005,
 122.793 +    0x8ff8,0x9095,0x90e1,0x90dd,0x90e2,0x9152,0x914d,0x914c,0x91d8,0x91dd,
 122.794 +    0x91d7,0x91dc,0x91d9,0x9583,0x9662,0x9663,0x9661,0x965b,0x965d,0x9664,
 122.795 +    0x9658,0x965e,0x96bb,0x98e2,0x99ac,0x9aa8,0x9ad8,0x9b25,0x9b32,0x9b3c,
 122.796 +    0x4e7e,0x507a,0x507d,0x505c,0x5047,0x5043,0x504c,0x505a,0x5049,0x5065,
 122.797 +    0x5076,0x504e,0x5055,0x5075
 122.798 +  },
 122.799 +  {				/* ku 39 */
 122.800 +    0x5074,0x5077,0x504f,0x500f,0x506f,0x506d,0x515c,0x5195,0x51f0,0x526a,
 122.801 +    0x526f,0x52d2,0x52d9,0x52d8,0x52d5,0x5310,0x530f,0x5319,0x533f,0x5340,
 122.802 +    0x533e,0x53c3,0x66fc,0x5546,0x556a,0x5566,0x5544,0x555e,0x5561,0x5543,
 122.803 +    0x554a,0x5531,0x5556,0x554f,0x5555,0x552f,0x5564,0x5538,0x552e,0x555c,
 122.804 +    0x552c,0x5563,0x5533,0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805,
 122.805 +    0x580a,0x5806,0x57e0,0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9,0x5920,
 122.806 +    0x5962,0x5a36,0x5a41,0x5a49,0x5a66,0x5a6a,0x5a40,0x5a3c,0x5a62,0x5a5a,
 122.807 +    0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5,0x5bc4,0x5bc2,0x5bbf,0x5bc6,0x5c09,
 122.808 +    0x5c08,0x5c07,0x5c60,0x5c5c,0x5c5d,0x5d07,0x5d06,0x5d0e,0x5d1b,0x5d16,
 122.809 +    0x5d22,0x5d11,0x5d29,0x5d14
 122.810 +  },
 122.811 +  {				/* ku 3a */
 122.812 +    0x5d19,0x5d24,0x5d27,0x5d17,0x5de2,0x5e38,0x5e36,0x5e33,0x5e37,0x5eb7,
 122.813 +    0x5eb8,0x5eb6,0x5eb5,0x5ebe,0x5f35,0x5f37,0x5f57,0x5f6c,0x5f69,0x5f6b,
 122.814 +    0x5f97,0x5f99,0x5f9e,0x5f98,0x5fa1,0x5fa0,0x5f9c,0x607f,0x60a3,0x6089,
 122.815 +    0x60a0,0x60a8,0x60cb,0x60b4,0x60e6,0x60bd,0x60c5,0x60bb,0x60b5,0x60dc,
 122.816 +    0x60bc,0x60d8,0x60d5,0x60c6,0x60df,0x60b8,0x60da,0x60c7,0x621a,0x621b,
 122.817 +    0x6248,0x63a0,0x63a7,0x6372,0x6396,0x63a2,0x63a5,0x6377,0x6367,0x6398,
 122.818 +    0x63aa,0x6371,0x63a9,0x6389,0x6383,0x639b,0x636b,0x63a8,0x6384,0x6388,
 122.819 +    0x6399,0x63a1,0x63ac,0x6392,0x638f,0x6380,0x637b,0x6369,0x6368,0x637a,
 122.820 +    0x655d,0x6556,0x6551,0x6559,0x6557,0x555f,0x654f,0x6558,0x6555,0x6554,
 122.821 +    0x659c,0x659b,0x65ac,0x65cf
 122.822 +  },
 122.823 +  {				/* ku 3b */
 122.824 +    0x65cb,0x65cc,0x65ce,0x665d,0x665a,0x6664,0x6668,0x6666,0x665e,0x66f9,
 122.825 +    0x52d7,0x671b,0x6881,0x68af,0x68a2,0x6893,0x68b5,0x687f,0x6876,0x68b1,
 122.826 +    0x68a7,0x6897,0x68b0,0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d,
 122.827 +    0x68a8,0x689f,0x68a1,0x6882,0x6b32,0x6bba,0x6beb,0x6bec,0x6c2b,0x6d8e,
 122.828 +    0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc,0x6de4,0x6dfb,0x6dfa,0x6e05,
 122.829 +    0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae,0x6dde,0x6df9,0x6db8,0x6df7,0x6df5,
 122.830 +    0x6dc5,0x6dd2,0x6e1a,0x6db5,0x6dda,0x6deb,0x6dd8,0x6dea,0x6df1,0x6dee,
 122.831 +    0x6de8,0x6dc6,0x6dc4,0x6daa,0x6dec,0x6dbf,0x6de6,0x70f9,0x7109,0x710a,
 122.832 +    0x70fd,0x70ef,0x723d,0x727d,0x7281,0x731c,0x731b,0x7316,0x7313,0x7319,
 122.833 +    0x7387,0x7405,0x740a,0x7403
 122.834 +  },
 122.835 +  {				/* ku 3c */
 122.836 +    0x7406,0x73fe,0x740d,0x74e0,0x74f6,0x74f7,0x751c,0x7522,0x7565,0x7566,
 122.837 +    0x7562,0x7570,0x758f,0x75d4,0x75d5,0x75b5,0x75ca,0x75cd,0x768e,0x76d4,
 122.838 +    0x76d2,0x76db,0x7737,0x773e,0x773c,0x7736,0x7738,0x773a,0x786b,0x7843,
 122.839 +    0x784e,0x7965,0x7968,0x796d,0x79fb,0x7a92,0x7a95,0x7b20,0x7b28,0x7b1b,
 122.840 +    0x7b2c,0x7b26,0x7b19,0x7b1e,0x7b2e,0x7c92,0x7c97,0x7c95,0x7d46,0x7d43,
 122.841 +    0x7d71,0x7d2e,0x7d39,0x7d3c,0x7d40,0x7d30,0x7d33,0x7d44,0x7d2f,0x7d42,
 122.842 +    0x7d32,0x7d31,0x7f3d,0x7f9e,0x7f9a,0x7fcc,0x7fce,0x7fd2,0x801c,0x804a,
 122.843 +    0x8046,0x812f,0x8116,0x8123,0x812b,0x8129,0x8130,0x8124,0x8202,0x8235,
 122.844 +    0x8237,0x8236,0x8239,0x838e,0x839e,0x8398,0x8378,0x83a2,0x8396,0x83bd,
 122.845 +    0x83ab,0x8392,0x838a,0x8393
 122.846 +  },
 122.847 +  {				/* ku 3d */
 122.848 +    0x8389,0x83a0,0x8377,0x837b,0x837c,0x8386,0x83a7,0x8655,0x5f6a,0x86c7,
 122.849 +    0x86c0,0x86b6,0x86c4,0x86b5,0x86c6,0x86cb,0x86b1,0x86af,0x86c9,0x8853,
 122.850 +    0x889e,0x8888,0x88ab,0x8892,0x8896,0x888d,0x888b,0x8993,0x898f,0x8a2a,
 122.851 +    0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d,0x8a1f,0x8a1b,0x8a22,0x8c49,0x8c5a,
 122.852 +    0x8ca9,0x8cac,0x8cab,0x8ca8,0x8caa,0x8ca7,0x8d67,0x8d66,0x8dbe,0x8dba,
 122.853 +    0x8edb,0x8edf,0x9019,0x900d,0x901a,0x9017,0x9023,0x901f,0x901d,0x9010,
 122.854 +    0x9015,0x901e,0x9020,0x900f,0x9022,0x9016,0x901b,0x9014,0x90e8,0x90ed,
 122.855 +    0x90fd,0x9157,0x91ce,0x91f5,0x91e6,0x91e3,0x91e7,0x91ed,0x91e9,0x9589,
 122.856 +    0x966a,0x9675,0x9673,0x9678,0x9670,0x9674,0x9676,0x9677,0x966c,0x96c0,
 122.857 +    0x96ea,0x96e9,0x7ae0,0x7adf
 122.858 +  },
 122.859 +  {				/* ku 3e */
 122.860 +    0x9802,0x9803,0x9b5a,0x9ce5,0x9e75,0x9e7f,0x9ea5,0x9ebb,0x50a2,0x508d,
 122.861 +    0x5085,0x5099,0x5091,0x5080,0x5096,0x5098,0x509a,0x6700,0x51f1,0x5272,
 122.862 +    0x5274,0x5275,0x5269,0x52de,0x52dd,0x52db,0x535a,0x53a5,0x557b,0x5580,
 122.863 +    0x55a7,0x557c,0x558a,0x559d,0x5598,0x5582,0x559c,0x55aa,0x5594,0x5587,
 122.864 +    0x558b,0x5583,0x55b3,0x55ae,0x559f,0x553e,0x55b2,0x559a,0x55bb,0x55ac,
 122.865 +    0x55b1,0x557e,0x5589,0x55ab,0x5599,0x570d,0x582f,0x582a,0x5834,0x5824,
 122.866 +    0x5830,0x5831,0x5821,0x581d,0x5820,0x58f9,0x58fa,0x5960,0x5a77,0x5a9a,
 122.867 +    0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2,0x5bcc,0x5bd3,0x5bd0,
 122.868 +    0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50,0x5d34,0x5d47,0x5dfd,0x5e45,0x5e3d,
 122.869 +    0x5e40,0x5e43,0x5e7e,0x5eca
 122.870 +  },
 122.871 +  {				/* ku 3f */
 122.872 +    0x5ec1,0x5ec2,0x5ec4,0x5f3c,0x5f6d,0x5fa9,0x5faa,0x5fa8,0x60d1,0x60e1,
 122.873 +    0x60b2,0x60b6,0x60e0,0x611c,0x6123,0x60fa,0x6115,0x60f0,0x60fb,0x60f4,
 122.874 +    0x6168,0x60f1,0x610e,0x60f6,0x6109,0x6100,0x6112,0x621f,0x6249,0x63a3,
 122.875 +    0x638c,0x63cf,0x63c0,0x63e9,0x63c9,0x63c6,0x63cd,0x63d2,0x63e3,0x63d0,
 122.876 +    0x63e1,0x63d6,0x63ed,0x63ee,0x6376,0x63f4,0x63ea,0x63db,0x6452,0x63da,
 122.877 +    0x63f9,0x655e,0x6566,0x6562,0x6563,0x6591,0x6590,0x65af,0x666e,0x6670,
 122.878 +    0x6674,0x6676,0x666f,0x6691,0x667a,0x667e,0x6677,0x66fe,0x66ff,0x671f,
 122.879 +    0x671d,0x68fa,0x68d5,0x68e0,0x68d8,0x68d7,0x6905,0x68df,0x68f5,0x68ee,
 122.880 +    0x68e7,0x68f9,0x68d2,0x68f2,0x68e3,0x68cb,0x68cd,0x690d,0x6912,0x690e,
 122.881 +    0x68c9,0x68da,0x696e,0x68fb
 122.882 +  },
 122.883 +  {				/* ku 40 */
 122.884 +    0x6b3e,0x6b3a,0x6b3d,0x6b98,0x6b96,0x6bbc,0x6bef,0x6c2e,0x6c2f,0x6c2c,
 122.885 +    0x6e2f,0x6e38,0x6e54,0x6e21,0x6e32,0x6e67,0x6e4a,0x6e20,0x6e25,0x6e23,
 122.886 +    0x6e1b,0x6e5b,0x6e58,0x6e24,0x6e56,0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34,
 122.887 +    0x6e4d,0x6e3a,0x6e2c,0x6e43,0x6e1d,0x6e3e,0x6ecb,0x6e89,0x6e19,0x6e4e,
 122.888 +    0x6e63,0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a,0x7126,0x7130,0x7121,
 122.889 +    0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336,0x7325,0x7334,0x7329,
 122.890 +    0x743a,0x742a,0x7433,0x7422,0x7425,0x7435,0x7436,0x7434,0x742f,0x741b,
 122.891 +    0x7426,0x7428,0x7525,0x7526,0x756b,0x756a,0x75e2,0x75db,0x75e3,0x75d9,
 122.892 +    0x75d8,0x75de,0x75e0,0x767b,0x767c,0x7696,0x7693,0x76b4,0x76dc,0x774f,
 122.893 +    0x77ed,0x785d,0x786c,0x786f
 122.894 +  },
 122.895 +  {				/* ku 41 */
 122.896 +    0x7a0d,0x7a08,0x7a0b,0x7a05,0x7a00,0x7a98,0x7a97,0x7a96,0x7ae5,0x7ae3,
 122.897 +    0x7b49,0x7b56,0x7b46,0x7b50,0x7b52,0x7b54,0x7b4d,0x7b4b,0x7b4f,0x7b51,
 122.898 +    0x7c9f,0x7ca5,0x7d5e,0x7d50,0x7d68,0x7d55,0x7d2b,0x7d6e,0x7d72,0x7d61,
 122.899 +    0x7d66,0x7d62,0x7d70,0x7d73,0x5584,0x7fd4,0x7fd5,0x800b,0x8052,0x8085,
 122.900 +    0x8155,0x8154,0x814b,0x8151,0x814e,0x8139,0x8146,0x813e,0x814c,0x8153,
 122.901 +    0x8174,0x8212,0x821c,0x83e9,0x8403,0x83f8,0x840d,0x83e0,0x83c5,0x840b,
 122.902 +    0x83c1,0x83ef,0x83f1,0x83f4,0x8457,0x840a,0x83f0,0x840c,0x83cc,0x83fd,
 122.903 +    0x83f2,0x83ca,0x8438,0x840e,0x8404,0x83dc,0x8407,0x83d4,0x83df,0x865b,
 122.904 +    0x86df,0x86d9,0x86ed,0x86d4,0x86db,0x86e4,0x86d0,0x86de,0x8857,0x88c1,
 122.905 +    0x88c2,0x88b1,0x8983,0x8996
 122.906 +  },
 122.907 +  {				/* ku 42 */
 122.908 +    0x8a3b,0x8a60,0x8a55,0x8a5e,0x8a3c,0x8a41,0x8a54,0x8a5b,0x8a50,0x8a46,
 122.909 +    0x8a34,0x8a3a,0x8a36,0x8a56,0x8c61,0x8c82,0x8caf,0x8cbc,0x8cb3,0x8cbd,
 122.910 +    0x8cc1,0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6,0x8cbf,0x8cb8,0x8d8a,0x8d85,
 122.911 +    0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1,0x8dcc,0x8ddb,0x8dc6,0x8efb,
 122.912 +    0x8ef8,0x8efc,0x8f9c,0x902e,0x9035,0x9031,0x9038,0x9032,0x9036,0x9102,
 122.913 +    0x90f5,0x9109,0x90fe,0x9163,0x9165,0x91cf,0x9214,0x9215,0x9223,0x9209,
 122.914 +    0x921e,0x920d,0x9210,0x9207,0x9211,0x9594,0x958f,0x958b,0x9591,0x9593,
 122.915 +    0x9592,0x958e,0x968a,0x968e,0x968b,0x967d,0x9685,0x9686,0x968d,0x9672,
 122.916 +    0x9684,0x96c1,0x96c5,0x96c4,0x96c6,0x96c7,0x96ef,0x96f2,0x97cc,0x9805,
 122.917 +    0x9806,0x9808,0x98e7,0x98ea
 122.918 +  },
 122.919 +  {				/* ku 43 */
 122.920 +    0x98ef,0x98e9,0x98f2,0x98ed,0x99ae,0x99ad,0x9ec3,0x9ecd,0x9ed1,0x4e82,
 122.921 +    0x50ad,0x50b5,0x50b2,0x50b3,0x50c5,0x50be,0x50ac,0x50b7,0x50bb,0x50af,
 122.922 +    0x50c7,0x527f,0x5277,0x527d,0x52df,0x52e6,0x52e4,0x52e2,0x52e3,0x532f,
 122.923 +    0x55df,0x55e8,0x55d3,0x55e6,0x55ce,0x55dc,0x55c7,0x55d1,0x55e3,0x55e4,
 122.924 +    0x55ef,0x55da,0x55e1,0x55c5,0x55c6,0x55e5,0x55c9,0x5712,0x5713,0x585e,
 122.925 +    0x5851,0x5858,0x5857,0x585a,0x5854,0x586b,0x584c,0x586d,0x584a,0x5862,
 122.926 +    0x5852,0x584b,0x5967,0x5ac1,0x5ac9,0x5acc,0x5abe,0x5abd,0x5abc,0x5ab3,
 122.927 +    0x5ac2,0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12,0x5f59,
 122.928 +    0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3,0x611b,0x60f9,0x6101,
 122.929 +    0x6108,0x614e,0x614c,0x6144
 122.930 +  },
 122.931 +  {				/* ku 44 */
 122.932 +    0x614d,0x613e,0x6134,0x6127,0x610d,0x6106,0x6137,0x6221,0x6222,0x6413,
 122.933 +    0x643e,0x641e,0x642a,0x642d,0x643d,0x642c,0x640f,0x641c,0x6414,0x640d,
 122.934 +    0x6436,0x6416,0x6417,0x6406,0x656c,0x659f,0x65b0,0x6697,0x6689,0x6687,
 122.935 +    0x6688,0x6696,0x6684,0x6698,0x668d,0x6703,0x6994,0x696d,0x695a,0x6977,
 122.936 +    0x6960,0x6954,0x6975,0x6930,0x6982,0x694a,0x6968,0x696b,0x695e,0x6953,
 122.937 +    0x6979,0x6986,0x695d,0x6963,0x695b,0x6b47,0x6b72,0x6bc0,0x6bbf,0x6bd3,
 122.938 +    0x6bfd,0x6ea2,0x6eaf,0x6ed3,0x6eb6,0x6ec2,0x6e90,0x6e9d,0x6ec7,0x6ec5,
 122.939 +    0x6ea5,0x6e98,0x6ebc,0x6eba,0x6eab,0x6ed1,0x6e96,0x6e9c,0x6ec4,0x6ed4,
 122.940 +    0x6eaa,0x6ea7,0x6eb4,0x714e,0x7159,0x7169,0x7164,0x7149,0x7167,0x715c,
 122.941 +    0x716c,0x7166,0x714c,0x7165
 122.942 +  },
 122.943 +  {				/* ku 45 */
 122.944 +    0x715e,0x7146,0x7168,0x7156,0x723a,0x7252,0x7337,0x7345,0x733f,0x733e,
 122.945 +    0x746f,0x745a,0x7455,0x745f,0x745e,0x7441,0x743f,0x7459,0x745b,0x745c,
 122.946 +    0x7576,0x7578,0x7600,0x75f0,0x7601,0x75f2,0x75f1,0x75fa,0x75ff,0x75f4,
 122.947 +    0x75f3,0x76de,0x76df,0x775b,0x776b,0x7766,0x775e,0x7763,0x7779,0x776a,
 122.948 +    0x776c,0x775c,0x7765,0x7768,0x7762,0x77ee,0x788e,0x78b0,0x7897,0x7898,
 122.949 +    0x788c,0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f,0x7981,0x842c,
 122.950 +    0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e,0x7a9f,0x7aa0,0x7b77,
 122.951 +    0x7bc0,0x7b60,0x7b6e,0x7b67,0x7cb1,0x7cb3,0x7cb5,0x7d93,0x7d79,0x7d91,
 122.952 +    0x7d81,0x7d8f,0x7d5b,0x7f6e,0x7f69,0x7f6a,0x7f72,0x7fa9,0x7fa8,0x7fa4,
 122.953 +    0x8056,0x8058,0x8086,0x8084
 122.954 +  },
 122.955 +  {				/* ku 46 */
 122.956 +    0x8171,0x8170,0x8178,0x8165,0x816e,0x8173,0x816b,0x8179,0x817a,0x8166,
 122.957 +    0x8205,0x8247,0x8482,0x8477,0x843d,0x8431,0x8475,0x8466,0x846b,0x8449,
 122.958 +    0x846c,0x845b,0x843c,0x8435,0x8461,0x8463,0x8469,0x846d,0x8446,0x865e,
 122.959 +    0x865c,0x865f,0x86f9,0x8713,0x8708,0x8707,0x8700,0x86fe,0x86fb,0x8702,
 122.960 +    0x8703,0x8706,0x870a,0x8859,0x88df,0x88d4,0x88d9,0x88dc,0x88d8,0x88dd,
 122.961 +    0x88e1,0x88ca,0x88d5,0x88d2,0x899c,0x89e3,0x8a6b,0x8a72,0x8a73,0x8a66,
 122.962 +    0x8a69,0x8a70,0x8a87,0x8a7c,0x8a63,0x8aa0,0x8a71,0x8a85,0x8a6d,0x8a62,
 122.963 +    0x8a6e,0x8a6c,0x8a79,0x8a7b,0x8a3e,0x8a68,0x8c62,0x8c8a,0x8c89,0x8cca,
 122.964 +    0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3,0x8cc2,0x8cc5,0x8de1,0x8ddf,0x8de8,
 122.965 +    0x8def,0x8df3,0x8dfa,0x8dea
 122.966 +  },
 122.967 +  {				/* ku 47 */
 122.968 +    0x8de4,0x8de6,0x8eb2,0x8f03,0x8f09,0x8efe,0x8f0a,0x8f9f,0x8fb2,0x904b,
 122.969 +    0x904a,0x9053,0x9042,0x9054,0x903c,0x9055,0x9050,0x9047,0x904f,0x904e,
 122.970 +    0x904d,0x9051,0x903e,0x9041,0x9112,0x9117,0x916c,0x916a,0x9169,0x91c9,
 122.971 +    0x9237,0x9257,0x9238,0x923d,0x9240,0x923e,0x925b,0x924b,0x9264,0x9251,
 122.972 +    0x9234,0x9249,0x924d,0x9245,0x9239,0x923f,0x925a,0x9598,0x9698,0x9694,
 122.973 +    0x9695,0x96cd,0x96cb,0x96c9,0x96ca,0x96f7,0x96fb,0x96f9,0x96f6,0x9756,
 122.974 +    0x9774,0x9776,0x9810,0x9811,0x9813,0x980a,0x9812,0x980c,0x98fc,0x98f4,
 122.975 +    0x98fd,0x98fe,0x99b3,0x99b1,0x99b4,0x9ae1,0x9ce9,0x9e82,0x9f0e,0x9f13,
 122.976 +    0x9f20,0x50e7,0x50ee,0x50e5,0x50d6,0x50ed,0x50da,0x50d5,0x50cf,0x50d1,
 122.977 +    0x50f1,0x50ce,0x50e9,0x5162
 122.978 +  },
 122.979 +  {				/* ku 48 */
 122.980 +    0x51f3,0x5283,0x5282,0x5331,0x53ad,0x55fe,0x5600,0x561b,0x5617,0x55fd,
 122.981 +    0x5614,0x5606,0x5609,0x560d,0x560e,0x55f7,0x5616,0x561f,0x5608,0x5610,
 122.982 +    0x55f6,0x5718,0x5716,0x5875,0x587e,0x5883,0x5893,0x588a,0x5879,0x5885,
 122.983 +    0x587d,0x58fd,0x5925,0x5922,0x5924,0x596a,0x5969,0x5ae1,0x5ae6,0x5ae9,
 122.984 +    0x5ad7,0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde,0x5be7,0x5be1,0x5be5,0x5be6,
 122.985 +    0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62,0x5d84,0x5d87,0x5e5b,0x5e63,
 122.986 +    0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6,0x5f0a,0x5f46,0x5f70,0x5fb9,0x6147,
 122.987 +    0x613f,0x614b,0x6177,0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a,
 122.988 +    0x6487,0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467,0x6434,
 122.989 +    0x646d,0x647b,0x6572,0x65a1
 122.990 +  },
 122.991 +  {				/* ku 49 */
 122.992 +    0x65d7,0x65d6,0x66a2,0x66a8,0x669d,0x699c,0x69a8,0x6995,0x69c1,0x69ae,
 122.993 +    0x69d3,0x69cb,0x699b,0x69b7,0x69bb,0x69ab,0x69b4,0x69d0,0x69cd,0x69ad,
 122.994 +    0x69cc,0x69a6,0x69c3,0x69a3,0x6b49,0x6b4c,0x6c33,0x6f33,0x6f14,0x6efe,
 122.995 +    0x6f13,0x6ef4,0x6f29,0x6f3e,0x6f20,0x6f2c,0x6f0f,0x6f02,0x6f22,0x6eff,
 122.996 +    0x6eef,0x6f06,0x6f31,0x6f38,0x6f32,0x6f23,0x6f15,0x6f2b,0x6f2f,0x6f88,
 122.997 +    0x6f2a,0x6eec,0x6f01,0x6ef2,0x6ecc,0x6ef7,0x7194,0x7199,0x717d,0x718a,
 122.998 +    0x7184,0x7192,0x723e,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463,0x746a,
 122.999 +    0x7470,0x746d,0x7504,0x7591,0x7627,0x760d,0x760b,0x7609,0x7613,0x76e1,
122.1000 +    0x76e3,0x7784,0x777d,0x777f,0x7761,0x78c1,0x789f,0x78a7,0x78b3,0x78a9,
122.1001 +    0x78a3,0x798e,0x798f,0x798d
122.1002 +  },
122.1003 +  {				/* ku 4a */
122.1004 +    0x7a2e,0x7a31,0x7aaa,0x7aa9,0x7aed,0x7aef,0x7ba1,0x7b95,0x7b8b,0x7b75,
122.1005 +    0x7b97,0x7b9d,0x7b94,0x7b8f,0x7bb8,0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe,
122.1006 +    0x7dbb,0x7db0,0x7d9c,0x7dbd,0x7dbe,0x7da0,0x7dca,0x7db4,0x7db2,0x7db1,
122.1007 +    0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8,0x7dad,0x7dd2,0x7dc7,0x7dac,0x7f70,
122.1008 +    0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a,0x8087,0x8150,0x8180,0x818f,0x8188,
122.1009 +    0x818a,0x817f,0x8182,0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b,0x84c9,
122.1010 +    0x84bf,0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8,0x84c0,
122.1011 +    0x84d3,0x8490,0x84bc,0x84d1,0x84ca,0x873f,0x871c,0x873b,0x8722,0x8725,
122.1012 +    0x8734,0x8718,0x8755,0x8737,0x8729,0x88f3,0x8902,0x88f4,0x88f9,0x88f8,
122.1013 +    0x88fd,0x88e8,0x891a,0x88ef
122.1014 +  },
122.1015 +  {				/* ku 4b */
122.1016 +    0x8aa6,0x8a8c,0x8a9e,0x8aa3,0x8a8d,0x8aa1,0x8a93,0x8aa4,0x8aaa,0x8aa5,
122.1017 +    0x8aa8,0x8a98,0x8a91,0x8a9a,0x8aa7,0x8c6a,0x8c8d,0x8c8c,0x8cd3,0x8cd1,
122.1018 +    0x8cd2,0x8d6b,0x8d99,0x8d95,0x8dfc,0x8f14,0x8f12,0x8f15,0x8f13,0x8fa3,
122.1019 +    0x9060,0x9058,0x905c,0x9063,0x9059,0x905e,0x9062,0x905d,0x905b,0x9119,
122.1020 +    0x9118,0x911e,0x9175,0x9178,0x9177,0x9174,0x9278,0x92ac,0x9280,0x9285,
122.1021 +    0x9298,0x9296,0x927b,0x9293,0x929c,0x92a8,0x927c,0x9291,0x95a1,0x95a8,
122.1022 +    0x95a9,0x95a3,0x95a5,0x95a4,0x9699,0x969c,0x969b,0x96cc,0x96d2,0x9700,
122.1023 +    0x977c,0x9785,0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905,0x990c,
122.1024 +    0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4,0x9cf6,0x9cf3,
122.1025 +    0x9ebc,0x9f3b,0x9f4a,0x5104
122.1026 +  },
122.1027 +  {				/* ku 4c */
122.1028 +    0x5100,0x50fb,0x50f5,0x50f9,0x5102,0x5108,0x5109,0x5105,0x51dc,0x5287,
122.1029 +    0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b,0x5639,0x5632,
122.1030 +    0x563f,0x5634,0x5629,0x5653,0x564e,0x5657,0x5674,0x5636,0x562f,0x5630,
122.1031 +    0x5880,0x589f,0x589e,0x58b3,0x589c,0x58ae,0x58a9,0x58a6,0x596d,0x5b09,
122.1032 +    0x5afb,0x5b0b,0x5af5,0x5b0c,0x5b08,0x5bee,0x5bec,0x5be9,0x5beb,0x5c64,
122.1033 +    0x5c65,0x5d9d,0x5d94,0x5e62,0x5e5f,0x5e61,0x5ee2,0x5eda,0x5edf,0x5edd,
122.1034 +    0x5ee3,0x5ee0,0x5f48,0x5f71,0x5fb7,0x5fb5,0x6176,0x6167,0x616e,0x615d,
122.1035 +    0x6155,0x6182,0x617c,0x6170,0x616b,0x617e,0x61a7,0x6190,0x61ab,0x618e,
122.1036 +    0x61ac,0x619a,0x61a4,0x6194,0x61ae,0x622e,0x6469,0x646f,0x6479,0x649e,
122.1037 +    0x64b2,0x6488,0x6490,0x64b0
122.1038 +  },
122.1039 +  {				/* ku 4d */
122.1040 +    0x64a5,0x6493,0x6495,0x64a9,0x6492,0x64ae,0x64ad,0x64ab,0x649a,0x64ac,
122.1041 +    0x6499,0x64a2,0x64b3,0x6575,0x6577,0x6578,0x66ae,0x66ab,0x66b4,0x66b1,
122.1042 +    0x6a23,0x6a1f,0x69e8,0x6a01,0x6a1e,0x6a19,0x69fd,0x6a21,0x6a13,0x6a0a,
122.1043 +    0x69f3,0x6a02,0x6a05,0x69ed,0x6a11,0x6b50,0x6b4e,0x6ba4,0x6bc5,0x6bc6,
122.1044 +    0x6f3f,0x6f7c,0x6f84,0x6f51,0x6f66,0x6f54,0x6f86,0x6f6d,0x6f5b,0x6f78,
122.1045 +    0x6f6e,0x6f8e,0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5,0x6f6f,0x6f60,
122.1046 +    0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e,0x7357,0x7469,
122.1047 +    0x748b,0x7483,0x747e,0x7480,0x757f,0x7620,0x7629,0x761f,0x7624,0x7626,
122.1048 +    0x7621,0x7622,0x769a,0x76ba,0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b,
122.1049 +    0x78cb,0x78c5,0x78ba,0x78ca
122.1050 +  },
122.1051 +  {				/* ku 4e */
122.1052 +    0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c,0x7a40,0x7a3d,0x7a37,0x7a3b,
122.1053 +    0x7aaf,0x7aae,0x7bad,0x7bb1,0x7bc4,0x7bb4,0x7bc6,0x7bc7,0x7bc1,0x7ba0,
122.1054 +    0x7bcc,0x7cca,0x7de0,0x7df4,0x7def,0x7dfb,0x7dd8,0x7dec,0x7ddd,0x7de8,
122.1055 +    0x7de3,0x7dda,0x7dde,0x7de9,0x7d9e,0x7dd9,0x7df2,0x7df9,0x7f75,0x7f77,
122.1056 +    0x7faf,0x7fe9,0x8026,0x819b,0x819c,0x819d,0x81a0,0x819a,0x8198,0x8517,
122.1057 +    0x853d,0x851a,0x84ee,0x852c,0x852d,0x8513,0x8511,0x8523,0x8521,0x8514,
122.1058 +    0x84ec,0x8525,0x84ff,0x8506,0x8782,0x8774,0x8776,0x8760,0x8766,0x8778,
122.1059 +    0x8768,0x8759,0x8757,0x874c,0x8753,0x885b,0x885d,0x8910,0x8907,0x8912,
122.1060 +    0x8913,0x8915,0x890a,0x8abc,0x8ad2,0x8ac7,0x8ac4,0x8a95,0x8acb,0x8af8,
122.1061 +    0x8ab2,0x8ac9,0x8ac2,0x8abf
122.1062 +  },
122.1063 +  {				/* ku 4f */
122.1064 +    0x8ab0,0x8ad6,0x8acd,0x8ab6,0x8ab9,0x8adb,0x8c4c,0x8c4e,0x8c6c,0x8ce0,
122.1065 +    0x8cde,0x8ce6,0x8ce4,0x8cec,0x8ced,0x8ce2,0x8ce3,0x8cdc,0x8cea,0x8ce1,
122.1066 +    0x8d6d,0x8d9f,0x8da3,0x8e2b,0x8e10,0x8e1d,0x8e22,0x8e0f,0x8e29,0x8e1f,
122.1067 +    0x8e21,0x8e1e,0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29,0x8f26,0x8f2a,0x8f1c,
122.1068 +    0x8f1e,0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130,0x912d,0x9127,
122.1069 +    0x9131,0x9187,0x9189,0x918b,0x9183,0x92c5,0x92bb,0x92b7,0x92ea,0x92e4,
122.1070 +    0x92c1,0x92b3,0x92bc,0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704,
122.1071 +    0x9706,0x9707,0x9709,0x9760,0x978d,0x978b,0x978f,0x9821,0x982b,0x981c,
122.1072 +    0x98b3,0x990a,0x9913,0x9912,0x9918,0x99dd,0x99d0,0x99df,0x99db,0x99d1,
122.1073 +    0x99d5,0x99d2,0x99d9,0x9ab7
122.1074 +  },
122.1075 +  {				/* ku 50 */
122.1076 +    0x9aee,0x9aef,0x9b27,0x9b45,0x9b44,0x9b77,0x9b6f,0x9d06,0x9d09,0x9d03,
122.1077 +    0x9ea9,0x9ebe,0x9ece,0x58a8,0x9f52,0x5112,0x5118,0x5114,0x5110,0x5115,
122.1078 +    0x5180,0x51aa,0x51dd,0x5291,0x5293,0x52f3,0x5659,0x566b,0x5679,0x5669,
122.1079 +    0x5664,0x5678,0x566a,0x5668,0x5665,0x5671,0x566f,0x566c,0x5662,0x5676,
122.1080 +    0x58c1,0x58be,0x58c7,0x58c5,0x596e,0x5b1d,0x5b34,0x5b78,0x5bf0,0x5c0e,
122.1081 +    0x5f4a,0x61b2,0x6191,0x61a9,0x618a,0x61cd,0x61b6,0x61be,0x61ca,0x61c8,
122.1082 +    0x6230,0x64c5,0x64c1,0x64cb,0x64bb,0x64bc,0x64da,0x64c4,0x64c7,0x64c2,
122.1083 +    0x64cd,0x64bf,0x64d2,0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9,0x66c4,
122.1084 +    0x66c7,0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39,0x6a44,
122.1085 +    0x6a62,0x6a61,0x6a4b,0x6a47
122.1086 +  },
122.1087 +  {				/* ku 51 */
122.1088 +    0x6a35,0x6a5f,0x6a48,0x6b59,0x6b77,0x6c05,0x6fc2,0x6fb1,0x6fa1,0x6fc3,
122.1089 +    0x6fa4,0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0,0x6fb4,
122.1090 +    0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9,0x71ce,0x71d9,0x71dc,
122.1091 +    0x71c3,0x71c4,0x7368,0x749c,0x74a3,0x7498,0x749f,0x749e,0x74e2,0x750c,
122.1092 +    0x750d,0x7634,0x7638,0x763a,0x76e7,0x76e5,0x77a0,0x779e,0x779f,0x77a5,
122.1093 +    0x78e8,0x78da,0x78ec,0x78e7,0x79a6,0x7a4d,0x7a4e,0x7a46,0x7a4c,0x7a4b,
122.1094 +    0x7aba,0x7bd9,0x7c11,0x7bc9,0x7be4,0x7bdb,0x7be1,0x7be9,0x7be6,0x7cd5,
122.1095 +    0x7cd6,0x7e0a,0x7e11,0x7e08,0x7e1b,0x7e23,0x7e1e,0x7e1d,0x7e09,0x7e10,
122.1096 +    0x7f79,0x7fb2,0x7ff0,0x7ff1,0x7fee,0x8028,0x81b3,0x81a9,0x81a8,0x81fb,
122.1097 +    0x8208,0x8258,0x8259,0x854a
122.1098 +  },
122.1099 +  {				/* ku 52 */
122.1100 +    0x8559,0x8548,0x8568,0x8569,0x8543,0x8549,0x856d,0x856a,0x855e,0x8783,
122.1101 +    0x879f,0x879e,0x87a2,0x878d,0x8861,0x892a,0x8932,0x8925,0x892b,0x8921,
122.1102 +    0x89aa,0x89a6,0x8ae6,0x8afa,0x8aeb,0x8af1,0x8b00,0x8adc,0x8ae7,0x8aee,
122.1103 +    0x8afe,0x8b01,0x8b02,0x8af7,0x8aed,0x8af3,0x8af6,0x8afc,0x8c6b,0x8c6d,
122.1104 +    0x8c93,0x8cf4,0x8e44,0x8e31,0x8e34,0x8e42,0x8e39,0x8e35,0x8f3b,0x8f2f,
122.1105 +    0x8f38,0x8f33,0x8fa8,0x8fa6,0x9075,0x9074,0x9078,0x9072,0x907c,0x907a,
122.1106 +    0x9134,0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322,0x92fc,0x932b,
122.1107 +    0x9304,0x931a,0x9310,0x9326,0x9321,0x9315,0x932e,0x9319,0x95bb,0x96a7,
122.1108 +    0x96a8,0x96aa,0x96d5,0x970e,0x9711,0x9716,0x970d,0x9713,0x970f,0x975b,
122.1109 +    0x975c,0x9766,0x9798,0x9830
122.1110 +  },
122.1111 +  {				/* ku 53 */
122.1112 +    0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910,0x9928,0x991e,0x991b,
122.1113 +    0x9921,0x991a,0x99ed,0x99e2,0x99f1,0x9ab8,0x9abc,0x9afb,0x9aed,0x9b28,
122.1114 +    0x9b91,0x9d15,0x9d23,0x9d26,0x9d28,0x9d12,0x9d1b,0x9ed8,0x9ed4,0x9f8d,
122.1115 +    0x9f9c,0x512a,0x511f,0x5121,0x5132,0x52f5,0x568e,0x5680,0x5690,0x5685,
122.1116 +    0x5687,0x568f,0x58d5,0x58d3,0x58d1,0x58ce,0x5b30,0x5b2a,0x5b24,0x5b7a,
122.1117 +    0x5c37,0x5c68,0x5dbc,0x5dba,0x5dbd,0x5db8,0x5e6b,0x5f4c,0x5fbd,0x61c9,
122.1118 +    0x61c2,0x61c7,0x61e6,0x61cb,0x6232,0x6234,0x64ce,0x64ca,0x64d8,0x64e0,
122.1119 +    0x64f0,0x64e6,0x64ec,0x64f1,0x64e2,0x64ed,0x6582,0x6583,0x66d9,0x66d6,
122.1120 +    0x6a80,0x6a94,0x6a84,0x6aa2,0x6a9c,0x6adb,0x6aa3,0x6a7e,0x6a97,0x6a90,
122.1121 +    0x6aa0,0x6b5c,0x6bae,0x6bda
122.1122 +  },
122.1123 +  {				/* ku 54 */
122.1124 +    0x6c08,0x6fd8,0x6ff1,0x6fdf,0x6fe0,0x6fdb,0x6fe4,0x6feb,0x6fef,0x6f80,
122.1125 +    0x6fec,0x6fe1,0x6fe9,0x6fd5,0x6fee,0x6ff0,0x71e7,0x71df,0x71ee,0x71e6,
122.1126 +    0x71e5,0x71ed,0x71ec,0x71f4,0x71e0,0x7235,0x7246,0x7370,0x7372,0x74a9,
122.1127 +    0x74b0,0x74a6,0x74a8,0x7646,0x7642,0x764c,0x76ea,0x77b3,0x77aa,0x77b0,
122.1128 +    0x77ac,0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901,0x79a7,
122.1129 +    0x79aa,0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7,0x7c0c,0x7be0,0x7ce0,
122.1130 +    0x7cdc,0x7cde,0x7ce2,0x7cdf,0x7cd9,0x7cdd,0x7e2e,0x7e3e,0x7e46,0x7e37,
122.1131 +    0x7e32,0x7e43,0x7e2b,0x7e3d,0x7e31,0x7e45,0x7e41,0x7e34,0x7e39,0x7e48,
122.1132 +    0x7e35,0x7e3f,0x7e2f,0x7f44,0x7ff3,0x7ffc,0x8071,0x8072,0x8070,0x806f,
122.1133 +    0x8073,0x81c6,0x81c3,0x81ba
122.1134 +  },
122.1135 +  {				/* ku 55 */
122.1136 +    0x81c2,0x81c0,0x81bf,0x81bd,0x81c9,0x81be,0x81e8,0x8209,0x8271,0x85aa,
122.1137 +    0x8584,0x857e,0x859c,0x8591,0x8594,0x85af,0x859b,0x8587,0x85a8,0x858a,
122.1138 +    0x85a6,0x8667,0x87c0,0x87d1,0x87b3,0x87d2,0x87c6,0x87ab,0x87bb,0x87ba,
122.1139 +    0x87c8,0x87cb,0x893b,0x8936,0x8944,0x8938,0x893d,0x89ac,0x8b0e,0x8b17,
122.1140 +    0x8b19,0x8b1b,0x8b0a,0x8b20,0x8b1d,0x8b04,0x8b10,0x8c41,0x8c3f,0x8c73,
122.1141 +    0x8cfa,0x8cfd,0x8cfc,0x8cf8,0x8cfb,0x8da8,0x8e49,0x8e4b,0x8e48,0x8e4a,
122.1142 +    0x8f44,0x8f3e,0x8f42,0x8f45,0x8f3f,0x907f,0x907d,0x9084,0x9081,0x9082,
122.1143 +    0x9080,0x9139,0x91a3,0x919e,0x919c,0x934d,0x9382,0x9328,0x9375,0x934a,
122.1144 +    0x9365,0x934b,0x9318,0x937e,0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca,
122.1145 +    0x95cb,0x95cc,0x95c8,0x95c6
122.1146 +  },
122.1147 +  {				/* ku 56 */
122.1148 +    0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0,0x97d3,0x9846,0x98b6,0x9935,
122.1149 +    0x9a01,0x99ff,0x9bae,0x9bab,0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf,
122.1150 +    0x9ede,0x9edc,0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9,
122.1151 +    0x58d8,0x5b38,0x5f5e,0x61e3,0x6233,0x64f4,0x64f2,0x64fe,0x6506,0x64fa,
122.1152 +    0x64fb,0x64f7,0x65b7,0x66dc,0x6726,0x6ab3,0x6aac,0x6ac3,0x6abb,0x6ab8,
122.1153 +    0x6ac2,0x6aae,0x6aaf,0x6b5f,0x6b78,0x6baf,0x7009,0x700b,0x6ffe,0x7006,
122.1154 +    0x6ffa,0x7011,0x700f,0x71fb,0x71fc,0x71fe,0x71f8,0x7377,0x7375,0x74a7,
122.1155 +    0x74bf,0x7515,0x7656,0x7658,0x7652,0x77bd,0x77bf,0x77bb,0x77bc,0x790e,
122.1156 +    0x79ae,0x7a61,0x7a62,0x7a60,0x7ac4,0x7ac5,0x7c2b,0x7c27,0x7c2a,0x7c1e,
122.1157 +    0x7c23,0x7c21,0x7ce7,0x7e54
122.1158 +  },
122.1159 +  {				/* ku 57 */
122.1160 +    0x7e55,0x7e5e,0x7e5a,0x7e61,0x7e52,0x7e59,0x7f48,0x7ff9,0x7ffb,0x8077,
122.1161 +    0x8076,0x81cd,0x81cf,0x820a,0x85cf,0x85a9,0x85cd,0x85d0,0x85c9,0x85b0,
122.1162 +    0x85ba,0x85b9,0x87ef,0x87ec,0x87f2,0x87e0,0x8986,0x89b2,0x89f4,0x8b28,
122.1163 +    0x8b39,0x8b2c,0x8b2b,0x8c50,0x8d05,0x8e59,0x8e63,0x8e66,0x8e64,0x8e5f,
122.1164 +    0x8e55,0x8ec0,0x8f49,0x8f4d,0x9087,0x9083,0x9088,0x91ab,0x91ac,0x91d0,
122.1165 +    0x9394,0x938a,0x9396,0x93a2,0x93b3,0x93ae,0x93ac,0x93b0,0x9398,0x939a,
122.1166 +    0x9397,0x95d4,0x95d6,0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db,0x96de,
122.1167 +    0x9724,0x97a3,0x97a6,0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e,0x9853,
122.1168 +    0x98ba,0x993e,0x993f,0x993d,0x992e,0x99a5,0x9a0e,0x9ac1,0x9b03,0x9b06,
122.1169 +    0x9b4f,0x9b4e,0x9b4d,0x9bca
122.1170 +  },
122.1171 +  {				/* ku 58 */
122.1172 +    0x9bc9,0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15,0x9f2c,
122.1173 +    0x5133,0x56a5,0x56a8,0x58de,0x58df,0x58e2,0x5bf5,0x9f90,0x5eec,0x61f2,
122.1174 +    0x61f7,0x61f6,0x61f5,0x6500,0x650f,0x66e0,0x66dd,0x6ae5,0x6add,0x6ada,
122.1175 +    0x6ad3,0x701b,0x701f,0x7028,0x701a,0x701d,0x7015,0x7018,0x7206,0x720d,
122.1176 +    0x7258,0x72a2,0x7378,0x737a,0x74bd,0x74ca,0x74e3,0x7587,0x7586,0x765f,
122.1177 +    0x7661,0x77c7,0x7919,0x79b1,0x7a6b,0x7a69,0x7c3e,0x7c3f,0x7c38,0x7c3d,
122.1178 +    0x7c37,0x7c40,0x7e6b,0x7e6d,0x7e79,0x7e69,0x7e6a,0x7e73,0x7f85,0x7fb6,
122.1179 +    0x7fb9,0x7fb8,0x81d8,0x85e9,0x85dd,0x85ea,0x85d5,0x85e4,0x85e5,0x85f7,
122.1180 +    0x87fb,0x8805,0x880d,0x87f9,0x87fe,0x8960,0x895f,0x8956,0x895e,0x8b41,
122.1181 +    0x8b5c,0x8b58,0x8b49,0x8b5a
122.1182 +  },
122.1183 +  {				/* ku 59 */
122.1184 +    0x8b4e,0x8b4f,0x8b46,0x8b59,0x8d08,0x8d0a,0x8e7c,0x8e72,0x8e87,0x8e76,
122.1185 +    0x8e6c,0x8e7a,0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1,0x91ae,
122.1186 +    0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6,0x93e2,0x93cd,
122.1187 +    0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4,0x96e3,0x972a,0x9727,0x9761,
122.1188 +    0x97dc,0x97fb,0x985e,0x9858,0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19,
122.1189 +    0x9b0d,0x9be8,0x9be7,0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c,
122.1190 +    0x9e92,0x9e97,0x9e93,0x9eb4,0x52f8,0x56b7,0x56b6,0x56b4,0x56bc,0x58e4,
122.1191 +    0x5b40,0x5b43,0x5b7d,0x5bf6,0x5dc9,0x61f8,0x61fa,0x6518,0x6514,0x6519,
122.1192 +    0x66e6,0x6727,0x6aec,0x703e,0x7030,0x7032,0x7210,0x737b,0x74cf,0x7662,
122.1193 +    0x7665,0x7926,0x792a,0x792c
122.1194 +  },
122.1195 +  {				/* ku 5a */
122.1196 +    0x792b,0x7ac7,0x7af6,0x7c4c,0x7c43,0x7c4d,0x7cef,0x7cf0,0x8fae,0x7e7d,
122.1197 +    0x7e7c,0x7e82,0x7f4c,0x8000,0x81da,0x8266,0x85fb,0x85f9,0x8611,0x85fa,
122.1198 +    0x8606,0x860b,0x8607,0x860a,0x8814,0x8815,0x8964,0x89ba,0x89f8,0x8b70,
122.1199 +    0x8b6c,0x8b66,0x8b6f,0x8b5f,0x8b6b,0x8d0f,0x8d0d,0x8e89,0x8e81,0x8e85,
122.1200 +    0x8e82,0x91b4,0x91cb,0x9418,0x9403,0x93fd,0x95e1,0x9730,0x98c4,0x9952,
122.1201 +    0x9951,0x99a8,0x9a2b,0x9a30,0x9a37,0x9a35,0x9c13,0x9c0d,0x9e79,0x9eb5,
122.1202 +    0x9ee8,0x9f2f,0x9f5f,0x9f63,0x9f61,0x5137,0x5138,0x56c1,0x56c0,0x56c2,
122.1203 +    0x5914,0x5c6c,0x5dcd,0x61fc,0x61fe,0x651d,0x651c,0x6595,0x66e9,0x6afb,
122.1204 +    0x6b04,0x6afa,0x6bb2,0x704c,0x721b,0x72a7,0x74d6,0x74d4,0x7669,0x77d3,
122.1205 +    0x7c50,0x7e8f,0x7e8c,0x7fbc
122.1206 +  },
122.1207 +  {				/* ku 5b */
122.1208 +    0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f,0x896a,0x896c,0x89bd,
122.1209 +    0x8b74,0x8b77,0x8b7d,0x8d13,0x8e8a,0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba,
122.1210 +    0x942e,0x9433,0x9435,0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739,
122.1211 +    0x9732,0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e,0x9acf,
122.1212 +    0x9b54,0x9b51,0x9c2d,0x9c25,0x9daf,0x9db4,0x9dc2,0x9db8,0x9e9d,0x9eef,
122.1213 +    0x9f19,0x9f5c,0x9f66,0x9f67,0x513c,0x513b,0x56c8,0x56ca,0x56c9,0x5b7f,
122.1214 +    0x5dd4,0x5dd2,0x5f4e,0x61ff,0x6524,0x6b0a,0x6b61,0x7051,0x7058,0x7380,
122.1215 +    0x74e4,0x758a,0x766e,0x766c,0x79b3,0x7c60,0x7c5f,0x807e,0x807d,0x81df,
122.1216 +    0x8972,0x896f,0x89fc,0x8b80,0x8d16,0x8d17,0x8e91,0x8e93,0x8f61,0x9148,
122.1217 +    0x9444,0x9451,0x9452,0x973d
122.1218 +  },
122.1219 +  {				/* ku 5c */
122.1220 +    0x973e,0x97c3,0x97c1,0x986b,0x9955,0x9a55,0x9a4d,0x9ad2,0x9b1a,0x9c49,
122.1221 +    0x9c31,0x9c3e,0x9c3b,0x9dd3,0x9dd7,0x9f34,0x9f6c,0x9f6a,0x9f94,0x56cc,
122.1222 +    0x5dd6,0x6200,0x6523,0x652b,0x652a,0x66ec,0x6b10,0x74da,0x7aca,0x7c64,
122.1223 +    0x7c63,0x7c65,0x7e93,0x7e96,0x7e94,0x81e2,0x8638,0x863f,0x8831,0x8b8a,
122.1224 +    0x9090,0x908f,0x9463,0x9460,0x9464,0x9768,0x986f,0x995c,0x9a5a,0x9a5b,
122.1225 +    0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56,0x9de5,0x9e9f,0x9ef4,
122.1226 +    0x56d1,0x58e9,0x652c,0x705e,0x7671,0x7672,0x77d7,0x7f50,0x7f88,0x8836,
122.1227 +    0x8839,0x8862,0x8b93,0x8b92,0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,
122.1228 +    0x9748,0x9744,0x97c6,0x9870,0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9,0x9dfa,
122.1229 +    0x9e7c,0x9e7d,0x9f07,0x9f77
122.1230 +  },
122.1231 +  {				/* ku 5d */
122.1232 +    0x9f72,0x5ef3,0x6b16,0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1,
122.1233 +    0x9472,0x9470,0x9871,0x995e,0x9ad6,0x9b23,0x9ecc,0x7064,0x77da,0x8b9a,
122.1234 +    0x9477,0x97c9,0x9a62,0x9a65,0x7e9c,0x8b9c,0x8eaa,0x91c5,0x947d,0x947e,
122.1235 +    0x947c,0x9c77,0x9c78,0x9ef7,0x8c54,0x947f,0x9e1a,0x7228,0x9a6a,0x9b31,
122.1236 +    0x9e1b,0x9e1e,0x7c72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.1237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.1238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.1239 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.1240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.1241 +    UBOGON,UBOGON,UBOGON,UBOGON
122.1242 +  }
122.1243 +};
122.1244 +
122.1245 +/* CNS 11643 plane 2 conversion table */
122.1246 +
122.1247 +static const unsigned short
122.1248 + cns11643_2tab[MAX_CNS11643_KU_2][MAX_CNS11643_TEN] = {
122.1249 +  {				/* ku 01 */
122.1250 +    0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47,0x4e8d,0x56d7,
122.1251 +    0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e,0x4e2e,0x4e93,0x4ec2,0x4ec9,0x4ec8,
122.1252 +    0x5198,0x52fc,0x536c,0x53b9,0x5720,0x5903,0x592c,0x5c10,0x5dff,0x65e1,
122.1253 +    0x6bb3,0x6bcc,0x6c14,0x723f,0x4e31,0x4e3c,0x4ee8,0x4edc,0x4ee9,0x4ee1,
122.1254 +    0x4edd,0x4eda,0x520c,0x5209,0x531c,0x534c,0x5722,0x5723,0x5917,0x592f,
122.1255 +    0x5b81,0x5b84,0x5c12,0x5c3b,0x5c74,0x5c73,0x5e04,0x5e80,0x5e82,0x5fc9,
122.1256 +    0x6209,0x6250,0x6c15,0x6c36,0x6c43,0x6c3f,0x6c3b,0x72ae,0x72b0,0x738a,
122.1257 +    0x79b8,0x808a,0x961e,0x4f0e,0x4f18,0x4f2c,0x4ef5,0x4f14,0x4ef1,0x4f00,
122.1258 +    0x4ef7,0x4f08,0x4f1d,0x4f02,0x4f05,0x4f22,0x4f13,0x4f04,0x4ef4,0x4f12,
122.1259 +    0x51b1,0x5213,0x5210,0x52a6
122.1260 +  },
122.1261 +  {				/* ku 02 */
122.1262 +    0x5322,0x531f,0x534d,0x538a,0x5407,0x56e1,0x56df,0x572e,0x572a,0x5734,
122.1263 +    0x593c,0x5980,0x597c,0x5985,0x597b,0x597e,0x5977,0x597f,0x5b56,0x5c15,
122.1264 +    0x5c25,0x5c7c,0x5c7a,0x5c7b,0x5c7e,0x5ddf,0x5e75,0x5e84,0x5f02,0x5f1a,
122.1265 +    0x5f74,0x5fd5,0x5fd4,0x5fcf,0x625c,0x625e,0x6264,0x6261,0x6266,0x6262,
122.1266 +    0x6259,0x6260,0x625a,0x6265,0x6537,0x65ef,0x65ee,0x673e,0x6739,0x6738,
122.1267 +    0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52,0x6c5c,0x6c4f,
122.1268 +    0x6c4a,0x6c54,0x6c4b,0x6c4c,0x7071,0x725e,0x72b4,0x72b5,0x738e,0x752a,
122.1269 +    0x767f,0x7a75,0x7f51,0x8278,0x827c,0x8280,0x827d,0x827f,0x864d,0x897e,
122.1270 +    0x9099,0x9097,0x9098,0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56,
122.1271 +    0x4f3b,0x4f62,0x4f49,0x4f53
122.1272 +  },
122.1273 +  {				/* ku 03 */
122.1274 +    0x4f64,0x4f3e,0x4f67,0x4f52,0x4f5f,0x4f41,0x4f58,0x4f2d,0x4f33,0x4f3f,
122.1275 +    0x4f61,0x518f,0x51b9,0x521c,0x521e,0x5221,0x52ad,0x52ae,0x5309,0x5363,
122.1276 +    0x5372,0x538e,0x538f,0x5430,0x5437,0x542a,0x5454,0x5445,0x5419,0x541c,
122.1277 +    0x5425,0x5418,0x543d,0x544f,0x5441,0x5428,0x5424,0x5447,0x56ee,0x56e7,
122.1278 +    0x56e5,0x5741,0x5745,0x574c,0x5749,0x574b,0x5752,0x5906,0x5940,0x59a6,
122.1279 +    0x5998,0x59a0,0x5997,0x598e,0x59a2,0x5990,0x598f,0x59a7,0x59a1,0x5b8e,
122.1280 +    0x5b92,0x5c28,0x5c2a,0x5c8d,0x5c8f,0x5c88,0x5c8b,0x5c89,0x5c92,0x5c8a,
122.1281 +    0x5c86,0x5c93,0x5c95,0x5de0,0x5e0a,0x5e0e,0x5e8b,0x5e89,0x5e8c,0x5e88,
122.1282 +    0x5e8d,0x5f05,0x5f1d,0x5f78,0x5f76,0x5fd2,0x5fd1,0x5fd0,0x5fed,0x5fe8,
122.1283 +    0x5fee,0x5ff3,0x5fe1,0x5fe4
122.1284 +  },
122.1285 +  {				/* ku 04 */
122.1286 +    0x5fe3,0x5ffa,0x5fef,0x5ff7,0x5ffb,0x6000,0x5ff4,0x623a,0x6283,0x628c,
122.1287 +    0x628e,0x628f,0x6294,0x6287,0x6271,0x627b,0x627a,0x6270,0x6281,0x6288,
122.1288 +    0x6277,0x627d,0x6272,0x6274,0x65f0,0x65f4,0x65f3,0x65f2,0x65f5,0x6745,
122.1289 +    0x6747,0x6759,0x6755,0x674c,0x6748,0x675d,0x674d,0x675a,0x674b,0x6bd0,
122.1290 +    0x6c19,0x6c1a,0x6c78,0x6c67,0x6c6b,0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f,
122.1291 +    0x6c69,0x6c9a,0x6c6d,0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b,
122.1292 +    0x6c8e,0x7074,0x707a,0x7263,0x72bf,0x72bd,0x72c3,0x72c6,0x72c1,0x72ba,
122.1293 +    0x72c5,0x7395,0x7397,0x7393,0x7394,0x7392,0x753a,0x7539,0x7594,0x7595,
122.1294 +    0x7681,0x793d,0x8034,0x8095,0x8099,0x8090,0x8092,0x809c,0x8290,0x828f,
122.1295 +    0x8285,0x828e,0x8291,0x8293
122.1296 +  },
122.1297 +  {				/* ku 05 */
122.1298 +    0x828a,0x8283,0x8284,0x8c78,0x8fc9,0x8fbf,0x909f,0x90a1,0x90a5,0x909e,
122.1299 +    0x90a7,0x90a0,0x9630,0x9628,0x962f,0x962d,0x4e33,0x4f98,0x4f7c,0x4f85,
122.1300 +    0x4f7d,0x4f80,0x4f87,0x4f76,0x4f74,0x4f89,0x4f84,0x4f77,0x4f4c,0x4f97,
122.1301 +    0x4f6a,0x4f9a,0x4f79,0x4f81,0x4f78,0x4f90,0x4f9c,0x4f94,0x4f9e,0x4f92,
122.1302 +    0x4f82,0x4f95,0x4f6b,0x4f6e,0x519e,0x51bc,0x51be,0x5235,0x5232,0x5233,
122.1303 +    0x5246,0x5231,0x52bc,0x530a,0x530b,0x533c,0x5392,0x5394,0x5487,0x547f,
122.1304 +    0x5481,0x5491,0x5482,0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474,
122.1305 +    0x5466,0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,0x56f7,
122.1306 +    0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770,0x5776,0x5780,0x5775,
122.1307 +    0x577b,0x5773,0x5774,0x5762
122.1308 +  },
122.1309 +  {				/* ku 06 */
122.1310 +    0x5768,0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2,0x59cc,
122.1311 +    0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd,0x59c0,0x59c8,0x59b4,
122.1312 +    0x59c7,0x5b62,0x5b65,0x5b93,0x5b95,0x5c44,0x5c47,0x5cae,0x5ca4,0x5ca0,
122.1313 +    0x5cb5,0x5caf,0x5ca8,0x5cac,0x5c9f,0x5ca3,0x5cad,0x5ca2,0x5caa,0x5ca7,
122.1314 +    0x5c9d,0x5ca5,0x5cb6,0x5cb0,0x5ca6,0x5e17,0x5e14,0x5e19,0x5f28,0x5f22,
122.1315 +    0x5f23,0x5f24,0x5f54,0x5f82,0x5f7e,0x5f7d,0x5fde,0x5fe5,0x602d,0x6026,
122.1316 +    0x6019,0x6032,0x600b,0x6034,0x600a,0x6017,0x6033,0x601a,0x601e,0x602c,
122.1317 +    0x6022,0x600d,0x6010,0x602e,0x6013,0x6011,0x600c,0x6009,0x601c,0x6214,
122.1318 +    0x623d,0x62ad,0x62b4,0x62d1,0x62be,0x62aa,0x62b6,0x62ca,0x62ae,0x62b3,
122.1319 +    0x62af,0x62bb,0x62a9,0x62b0
122.1320 +  },
122.1321 +  {				/* ku 07 */
122.1322 +    0x62b8,0x653d,0x65a8,0x65bb,0x6609,0x65fc,0x6604,0x6612,0x6608,0x65fb,
122.1323 +    0x6603,0x660b,0x660d,0x6605,0x65fd,0x6611,0x6610,0x66f6,0x670a,0x6785,
122.1324 +    0x676c,0x678e,0x6792,0x6776,0x677b,0x6798,0x6786,0x6784,0x6774,0x678d,
122.1325 +    0x678c,0x677a,0x679f,0x6791,0x6799,0x6783,0x677d,0x6781,0x6778,0x6779,
122.1326 +    0x6794,0x6b25,0x6b80,0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb,0x6cee,
122.1327 +    0x6cd9,0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba,0x6cc3,
122.1328 +    0x6cc6,0x6ced,0x6cf2,0x6cd2,0x6cdd,0x6cb4,0x6c8a,0x6c9d,0x6c80,0x6cde,
122.1329 +    0x6cc0,0x6d30,0x6ccd,0x6cc7,0x6cb0,0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094,
122.1330 +    0x7098,0x7085,0x7093,0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083,
122.1331 +    0x726a,0x72d6,0x72cb,0x72d8
122.1332 +  },
122.1333 +  {				/* ku 08 */
122.1334 +    0x72c9,0x72dc,0x72d2,0x72d4,0x72da,0x72cc,0x72d1,0x73a4,0x73a1,0x73ad,
122.1335 +    0x73a6,0x73a2,0x73a0,0x73ac,0x739d,0x74dd,0x74e8,0x753f,0x7540,0x753e,
122.1336 +    0x758c,0x7598,0x76af,0x76f3,0x76f1,0x76f0,0x76f5,0x77f8,0x77fc,0x77f9,
122.1337 +    0x77fb,0x77fa,0x77f7,0x7942,0x793f,0x79c5,0x7a78,0x7a7b,0x7afb,0x7c75,
122.1338 +    0x7cfd,0x8035,0x808f,0x80ae,0x80a3,0x80b8,0x80b5,0x80ad,0x8220,0x82a0,
122.1339 +    0x82c0,0x82ab,0x829a,0x8298,0x829b,0x82b5,0x82a7,0x82ae,0x82bc,0x829e,
122.1340 +    0x82ba,0x82b4,0x82a8,0x82a1,0x82a9,0x82c2,0x82a4,0x82c3,0x82b6,0x82a2,
122.1341 +    0x8670,0x866f,0x866d,0x866e,0x8c56,0x8fd2,0x8fcb,0x8fd3,0x8fcd,0x8fd6,
122.1342 +    0x8fd5,0x8fd7,0x90b2,0x90b4,0x90af,0x90b3,0x90b0,0x9639,0x963d,0x963c,
122.1343 +    0x963a,0x9643,0x4fcd,0x4fc5
122.1344 +  },
122.1345 +  {				/* ku 09 */
122.1346 +    0x4fd3,0x4fb2,0x4fc9,0x4fcb,0x4fc1,0x4fd4,0x4fdc,0x4fd9,0x4fbb,0x4fb3,
122.1347 +    0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0,0x4fb9,0x4fec,0x5244,0x5249,0x52c0,
122.1348 +    0x52c2,0x533d,0x537c,0x5397,0x5396,0x5399,0x5398,0x54ba,0x54a1,0x54ad,
122.1349 +    0x54a5,0x54cf,0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5,0x54c6,
122.1350 +    0x54a0,0x5470,0x54bc,0x54a2,0x54be,0x5472,0x54de,0x54b0,0x57b5,0x579e,
122.1351 +    0x579f,0x57a4,0x578c,0x5797,0x579d,0x579b,0x5794,0x5798,0x578f,0x5799,
122.1352 +    0x57a5,0x579a,0x5795,0x58f4,0x590d,0x5953,0x59e1,0x59de,0x59ee,0x5a00,
122.1353 +    0x59f1,0x59dd,0x59fa,0x59fd,0x59fc,0x59f6,0x59e4,0x59f2,0x59f7,0x59db,
122.1354 +    0x59e9,0x59f3,0x59f5,0x59e0,0x59fe,0x59f4,0x59ed,0x5ba8,0x5c4c,0x5cd0,
122.1355 +    0x5cd8,0x5ccc,0x5cd7,0x5ccb
122.1356 +  },
122.1357 +  {				/* ku 0a */
122.1358 +    0x5cdb,0x5cde,0x5cda,0x5cc9,0x5cc7,0x5cca,0x5cd6,0x5cd3,0x5cd4,0x5ccf,
122.1359 +    0x5cc8,0x5cc6,0x5cce,0x5cdf,0x5cf8,0x5df9,0x5e21,0x5e22,0x5e23,0x5e20,
122.1360 +    0x5e24,0x5eb0,0x5ea4,0x5ea2,0x5e9b,0x5ea3,0x5ea5,0x5f07,0x5f2e,0x5f56,
122.1361 +    0x5f86,0x6037,0x6039,0x6054,0x6072,0x605e,0x6045,0x6053,0x6047,0x6049,
122.1362 +    0x605b,0x604c,0x6040,0x6042,0x605f,0x6024,0x6044,0x6058,0x6066,0x606e,
122.1363 +    0x6242,0x6243,0x62cf,0x630d,0x630b,0x62f5,0x630e,0x6303,0x62eb,0x62f9,
122.1364 +    0x630f,0x630c,0x62f8,0x62f6,0x6300,0x6313,0x6314,0x62fa,0x6315,0x62fb,
122.1365 +    0x62f0,0x6541,0x6543,0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c,
122.1366 +    0x6626,0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e,0x670f,
122.1367 +    0x6710,0x67c1,0x67f2,0x67c8
122.1368 +  },
122.1369 +  {				/* ku 0b */
122.1370 +    0x67ba,0x67dc,0x67bb,0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4,
122.1371 +    0x67df,0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2,0x67b9,
122.1372 +    0x67ce,0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed,0x67cc,0x67ae,0x67e6,
122.1373 +    0x67db,0x67fa,0x67c9,0x67ca,0x67c3,0x67ea,0x67cb,0x6b28,0x6b82,0x6b84,
122.1374 +    0x6bb6,0x6bd6,0x6bd8,0x6be0,0x6c20,0x6c21,0x6d28,0x6d34,0x6d2d,0x6d1f,
122.1375 +    0x6d3c,0x6d3f,0x6d12,0x6d0a,0x6cda,0x6d33,0x6d04,0x6d19,0x6d3a,0x6d1a,
122.1376 +    0x6d11,0x6d00,0x6d1d,0x6d42,0x6d01,0x6d18,0x6d37,0x6d03,0x6d0f,0x6d40,
122.1377 +    0x6d07,0x6d20,0x6d2c,0x6d08,0x6d22,0x6d09,0x6d10,0x70b7,0x709f,0x70be,
122.1378 +    0x70b1,0x70b0,0x70a1,0x70b4,0x70b5,0x70a9,0x7241,0x7249,0x724a,0x726c,
122.1379 +    0x7270,0x7273,0x726e,0x72ca
122.1380 +  },
122.1381 +  {				/* ku 0c */
122.1382 +    0x72e4,0x72e8,0x72eb,0x72df,0x72ea,0x72e6,0x72e3,0x7385,0x73cc,0x73c2,
122.1383 +    0x73c8,0x73c5,0x73b9,0x73b6,0x73b5,0x73b4,0x73eb,0x73bf,0x73c7,0x73be,
122.1384 +    0x73c3,0x73c6,0x73b8,0x73cb,0x74ec,0x74ee,0x752e,0x7547,0x7548,0x75a7,
122.1385 +    0x75aa,0x7679,0x76c4,0x7708,0x7703,0x7704,0x7705,0x770a,0x76f7,0x76fb,
122.1386 +    0x76fa,0x77e7,0x77e8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780f,0x780e,
122.1387 +    0x7809,0x7803,0x7813,0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd,
122.1388 +    0x79cf,0x79d6,0x79ce,0x7a80,0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a,0x7c78,
122.1389 +    0x7c79,0x7c7f,0x7c80,0x7c81,0x7d03,0x7d08,0x7d01,0x7f58,0x7f91,0x7f8d,
122.1390 +    0x7fbe,0x8007,0x800e,0x800f,0x8014,0x8037,0x80d8,0x80c7,0x80e0,0x80d1,
122.1391 +    0x80c8,0x80c2,0x80d0,0x80c5
122.1392 +  },
122.1393 +  {				/* ku 0d */
122.1394 +    0x80e3,0x80d9,0x80dc,0x80ca,0x80d5,0x80c9,0x80cf,0x80d7,0x80e6,0x80cd,
122.1395 +    0x81ff,0x8221,0x8294,0x82d9,0x82fe,0x82f9,0x8307,0x82e8,0x8300,0x82d5,
122.1396 +    0x833a,0x82eb,0x82d6,0x82f4,0x82ec,0x82e1,0x82f2,0x82f5,0x830c,0x82fb,
122.1397 +    0x82f6,0x82f0,0x82ea,0x82e4,0x82e0,0x82fa,0x82f3,0x82ed,0x8677,0x8674,
122.1398 +    0x867c,0x8673,0x8841,0x884e,0x8867,0x886a,0x8869,0x89d3,0x8a04,0x8a07,
122.1399 +    0x8d72,0x8fe3,0x8fe1,0x8fee,0x8fe0,0x90f1,0x90bd,0x90bf,0x90d5,0x90c5,
122.1400 +    0x90be,0x90c7,0x90cb,0x90c8,0x91d4,0x91d3,0x9654,0x964f,0x9651,0x9653,
122.1401 +    0x964a,0x964e,0x501e,0x5005,0x5007,0x5013,0x5022,0x5030,0x501b,0x4ff5,
122.1402 +    0x4ff4,0x5033,0x5037,0x502c,0x4ff6,0x4ff7,0x5017,0x501c,0x5020,0x5027,
122.1403 +    0x5035,0x502f,0x5031,0x500e
122.1404 +  },
122.1405 +  {				/* ku 0e */
122.1406 +    0x515a,0x5194,0x5193,0x51ca,0x51c4,0x51c5,0x51c8,0x51ce,0x5261,0x525a,
122.1407 +    0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e,0x539e,0x5526,0x54e2,
122.1408 +    0x5517,0x5512,0x54e7,0x54f3,0x54e4,0x551a,0x54ff,0x5504,0x5508,0x54eb,
122.1409 +    0x5511,0x5505,0x54f1,0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503,
122.1410 +    0x550b,0x5701,0x5702,0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6,0x57bd,
122.1411 +    0x57bc,0x57b8,0x57b6,0x57bf,0x57c7,0x57d0,0x57b9,0x57c1,0x590e,0x594a,
122.1412 +    0x5a19,0x5a16,0x5a2d,0x5a2e,0x5a15,0x5a0f,0x5a17,0x5a0a,0x5a1e,0x5a33,
122.1413 +    0x5b6c,0x5ba7,0x5bad,0x5bac,0x5c03,0x5c56,0x5c54,0x5cec,0x5cff,0x5cee,
122.1414 +    0x5cf1,0x5cf7,0x5d00,0x5cf9,0x5e29,0x5e28,0x5ea8,0x5eae,0x5eaa,0x5eac,
122.1415 +    0x5f33,0x5f30,0x5f67,0x605d
122.1416 +  },
122.1417 +  {				/* ku 0f */
122.1418 +    0x605a,0x6067,0x6041,0x60a2,0x6088,0x6080,0x6092,0x6081,0x609d,0x6083,
122.1419 +    0x6095,0x609b,0x6097,0x6087,0x609c,0x608e,0x6219,0x6246,0x62f2,0x6310,
122.1420 +    0x6356,0x632c,0x6344,0x6345,0x6336,0x6343,0x63e4,0x6339,0x634b,0x634a,
122.1421 +    0x633c,0x6329,0x6341,0x6334,0x6358,0x6354,0x6359,0x632d,0x6347,0x6333,
122.1422 +    0x635a,0x6351,0x6338,0x6357,0x6340,0x6348,0x654a,0x6546,0x65c6,0x65c3,
122.1423 +    0x65c4,0x65c2,0x664a,0x665f,0x6647,0x6651,0x6712,0x6713,0x681f,0x681a,
122.1424 +    0x6849,0x6832,0x6833,0x683b,0x684b,0x684f,0x6816,0x6831,0x681c,0x6835,
122.1425 +    0x682b,0x682d,0x682f,0x684e,0x6844,0x6834,0x681d,0x6812,0x6814,0x6826,
122.1426 +    0x6828,0x682e,0x684d,0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31,
122.1427 +    0x6b34,0x6b6d,0x8082,0x6b88
122.1428 +  },
122.1429 +  {				/* ku 10 */
122.1430 +    0x6be6,0x6be4,0x6be8,0x6be3,0x6be2,0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64,
122.1431 +    0x6d76,0x6d0d,0x6d61,0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d,
122.1432 +    0x6def,0x6d7f,0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c,0x6d5f,
122.1433 +    0x6d82,0x6d98,0x6d2f,0x6d68,0x6d8b,0x6d7e,0x6d80,0x6d84,0x6d16,0x6d83,
122.1434 +    0x6d7b,0x6d7d,0x6d75,0x6d90,0x70dc,0x70d3,0x70d1,0x70dd,0x70cb,0x7f39,
122.1435 +    0x70e2,0x70d7,0x70d2,0x70de,0x70e0,0x70d4,0x70cd,0x70c5,0x70c6,0x70c7,
122.1436 +    0x70da,0x70ce,0x70e1,0x7242,0x7278,0x7277,0x7276,0x7300,0x72fa,0x72f4,
122.1437 +    0x72fe,0x72f6,0x72f3,0x72fb,0x7301,0x73d3,0x73d9,0x73e5,0x73d6,0x73bc,
122.1438 +    0x73e7,0x73e3,0x73e9,0x73dc,0x73d2,0x73db,0x73d4,0x73dd,0x73da,0x73d7,
122.1439 +    0x73d8,0x73e8,0x74de,0x74df
122.1440 +  },
122.1441 +  {				/* ku 11 */
122.1442 +    0x74f4,0x74f5,0x7521,0x755b,0x755f,0x75b0,0x75c1,0x75bb,0x75c4,0x75c0,
122.1443 +    0x75bf,0x75b6,0x75ba,0x768a,0x76c9,0x771d,0x771b,0x7710,0x7713,0x7712,
122.1444 +    0x7723,0x7711,0x7715,0x7719,0x771a,0x7722,0x7727,0x7823,0x782c,0x7822,
122.1445 +    0x7835,0x782f,0x7828,0x782e,0x782b,0x7821,0x7829,0x7833,0x782a,0x7831,
122.1446 +    0x7954,0x795b,0x794f,0x795c,0x7953,0x7952,0x7951,0x79eb,0x79ec,0x79e0,
122.1447 +    0x79ee,0x79ed,0x79ea,0x79dc,0x79de,0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b,
122.1448 +    0x7a8c,0x7a8a,0x7a87,0x7ad8,0x7b10,0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,
122.1449 +    0x7b0a,0x7b0e,0x7b09,0x7b12,0x7c84,0x7c91,0x7c8a,0x7c8c,0x7c88,0x7c8d,
122.1450 +    0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e,0x7d18,0x7d16,0x7d13,0x7d1f,0x7d12,
122.1451 +    0x7d0f,0x7d0c,0x7f5c,0x7f61
122.1452 +  },
122.1453 +  {				/* ku 12 */
122.1454 +    0x7f5e,0x7f60,0x7f5d,0x7f5b,0x7f96,0x7f92,0x7fc3,0x7fc2,0x7fc0,0x8016,
122.1455 +    0x803e,0x8039,0x80fa,0x80f2,0x80f9,0x80f5,0x8101,0x80fb,0x8100,0x8201,
122.1456 +    0x822f,0x8225,0x8333,0x832d,0x8344,0x8319,0x8351,0x8325,0x8356,0x833f,
122.1457 +    0x8341,0x8326,0x831c,0x8322,0x8342,0x834e,0x831b,0x832a,0x8308,0x833c,
122.1458 +    0x834d,0x8316,0x8324,0x8320,0x8337,0x832f,0x8329,0x8347,0x8345,0x834c,
122.1459 +    0x8353,0x831e,0x832c,0x834b,0x8327,0x8348,0x8653,0x8652,0x86a2,0x86a8,
122.1460 +    0x8696,0x868d,0x8691,0x869e,0x8687,0x8697,0x8686,0x868b,0x869a,0x8685,
122.1461 +    0x86a5,0x8699,0x86a1,0x86a7,0x8695,0x8698,0x868e,0x869d,0x8690,0x8694,
122.1462 +    0x8843,0x8844,0x886d,0x8875,0x8876,0x8872,0x8880,0x8871,0x887f,0x886f,
122.1463 +    0x8883,0x887e,0x8874,0x887c
122.1464 +  },
122.1465 +  {				/* ku 13 */
122.1466 +    0x8a12,0x8c47,0x8c57,0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7,
122.1467 +    0x8db6,0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004,0x8ffc,
122.1468 +    0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df,0x90e5,0x90d8,0x90db,
122.1469 +    0x90d7,0x90dc,0x90e4,0x9150,0x914e,0x914f,0x91d5,0x91e2,0x91da,0x965c,
122.1470 +    0x965f,0x96bc,0x98e3,0x9adf,0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e,
122.1471 +    0x5060,0x5053,0x504b,0x505d,0x5072,0x5048,0x504d,0x5041,0x505b,0x504a,
122.1472 +    0x5062,0x5015,0x5045,0x505f,0x5069,0x506b,0x5063,0x5064,0x5046,0x5040,
122.1473 +    0x506e,0x5073,0x5057,0x5051,0x51d0,0x526b,0x526d,0x526c,0x526e,0x52d6,
122.1474 +    0x52d3,0x532d,0x539c,0x5575,0x5576,0x553c,0x554d,0x5550,0x5534,0x552a,
122.1475 +    0x5551,0x5562,0x5536,0x5535
122.1476 +  },
122.1477 +  {				/* ku 14 */
122.1478 +    0x5530,0x5552,0x5545,0x550c,0x5532,0x5565,0x554e,0x5539,0x5548,0x552d,
122.1479 +    0x553b,0x5540,0x554b,0x570a,0x5707,0x57fb,0x5814,0x57e2,0x57f6,0x57dc,
122.1480 +    0x57f4,0x5800,0x57ed,0x57fd,0x5808,0x57f8,0x580b,0x57f3,0x57cf,0x5807,
122.1481 +    0x57ee,0x57e3,0x57f2,0x57e5,0x57ec,0x57e1,0x580e,0x57fc,0x5810,0x57e7,
122.1482 +    0x5801,0x580c,0x57f1,0x57e9,0x57f0,0x580d,0x5804,0x595c,0x5a60,0x5a58,
122.1483 +    0x5a55,0x5a67,0x5a5e,0x5a38,0x5a35,0x5a6d,0x5a50,0x5a5f,0x5a65,0x5a6c,
122.1484 +    0x5a53,0x5a64,0x5a57,0x5a43,0x5a5d,0x5a52,0x5a44,0x5a5b,0x5a48,0x5a8e,
122.1485 +    0x5a3e,0x5a4d,0x5a39,0x5a4c,0x5a70,0x5a69,0x5a47,0x5a51,0x5a56,0x5a42,
122.1486 +    0x5a5c,0x5b72,0x5b6e,0x5bc1,0x5bc0,0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a,
122.1487 +    0x5d20,0x5d0c,0x5d28,0x5d0d
122.1488 +  },
122.1489 +  {				/* ku 15 */
122.1490 +    0x5d26,0x5d25,0x5d0f,0x5d30,0x5d12,0x5d23,0x5d1f,0x5d2e,0x5e3e,0x5e34,
122.1491 +    0x5eb1,0x5eb4,0x5eb9,0x5eb2,0x5eb3,0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f,
122.1492 +    0x608a,0x6090,0x6086,0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4,
122.1493 +    0x60d9,0x60dd,0x60c8,0x60b1,0x60db,0x60b7,0x60ca,0x60bf,0x60c3,0x60cd,
122.1494 +    0x60c0,0x6332,0x6365,0x638a,0x6382,0x637d,0x63bd,0x639e,0x63ad,0x639d,
122.1495 +    0x6397,0x63ab,0x638e,0x636f,0x6387,0x6390,0x636e,0x63af,0x6375,0x639c,
122.1496 +    0x636d,0x63ae,0x637c,0x63a4,0x633b,0x639f,0x6378,0x6385,0x6381,0x6391,
122.1497 +    0x638d,0x6370,0x6553,0x65cd,0x6665,0x6661,0x665b,0x6659,0x665c,0x6662,
122.1498 +    0x6718,0x6879,0x6887,0x6890,0x689c,0x686d,0x686e,0x68ae,0x68ab,0x6956,
122.1499 +    0x686f,0x68a3,0x68ac,0x68a9
122.1500 +  },
122.1501 +  {				/* ku 16 */
122.1502 +    0x6875,0x6874,0x68b2,0x688f,0x6877,0x6892,0x687c,0x686b,0x6872,0x68aa,
122.1503 +    0x6880,0x6871,0x687e,0x689b,0x6896,0x688b,0x68a0,0x6889,0x68a4,0x6878,
122.1504 +    0x687b,0x6891,0x688c,0x688a,0x687d,0x6b36,0x6b33,0x6b37,0x6b38,0x6b91,
122.1505 +    0x6b8f,0x6b8d,0x6b8e,0x6b8c,0x6c2a,0x6dc0,0x6dab,0x6db4,0x6db3,0x6e74,
122.1506 +    0x6dac,0x6de9,0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0,0x6ddf,
122.1507 +    0x6dd6,0x6dbe,0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4,0x6dca,0x6dbd,0x6ded,
122.1508 +    0x6df0,0x6dba,0x6dd5,0x6dc2,0x6dcf,0x6dc9,0x6dd0,0x6df2,0x6dd3,0x6dfd,
122.1509 +    0x6dd7,0x6dcd,0x6de3,0x6dbb,0x70fa,0x710d,0x70f7,0x7117,0x70f4,0x710c,
122.1510 +    0x70f0,0x7104,0x70f3,0x7110,0x70fc,0x70ff,0x7106,0x7113,0x7100,0x70f8,
122.1511 +    0x70f6,0x710b,0x7102,0x710e
122.1512 +  },
122.1513 +  {				/* ku 17 */
122.1514 +    0x727e,0x727b,0x727c,0x727f,0x731d,0x7317,0x7307,0x7311,0x7318,0x730a,
122.1515 +    0x7308,0x72ff,0x730f,0x731e,0x7388,0x73f6,0x73f8,0x73f5,0x7404,0x7401,
122.1516 +    0x73fd,0x7407,0x7400,0x73fa,0x73fc,0x73ff,0x740c,0x740b,0x73f4,0x7408,
122.1517 +    0x7564,0x7563,0x75ce,0x75d2,0x75cf,0x75cb,0x75cc,0x75d1,0x75d0,0x768f,
122.1518 +    0x7689,0x76d3,0x7739,0x772f,0x772d,0x7731,0x7732,0x7734,0x7733,0x773d,
122.1519 +    0x7725,0x773b,0x7735,0x7848,0x7852,0x7849,0x784d,0x784a,0x784c,0x7826,
122.1520 +    0x7845,0x7850,0x7964,0x7967,0x7969,0x796a,0x7963,0x796b,0x7961,0x79bb,
122.1521 +    0x79fa,0x79f8,0x79f6,0x79f7,0x7a8f,0x7a94,0x7a90,0x7b35,0x7b3b,0x7b34,
122.1522 +    0x7b25,0x7b30,0x7b22,0x7b24,0x7b33,0x7b18,0x7b2a,0x7b1d,0x7b31,0x7b2b,
122.1523 +    0x7b2d,0x7b2f,0x7b32,0x7b38
122.1524 +  },
122.1525 +  {				/* ku 18 */
122.1526 +    0x7b1a,0x7b23,0x7c94,0x7c98,0x7c96,0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36,
122.1527 +    0x7d3a,0x7d45,0x7d2c,0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b,
122.1528 +    0x7d28,0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd,0x7fd0,
122.1529 +    0x7fd1,0x7fc7,0x7fcf,0x7fc9,0x801f,0x801e,0x801b,0x8047,0x8043,0x8048,
122.1530 +    0x8118,0x8125,0x8119,0x811b,0x812d,0x811f,0x812c,0x811e,0x8121,0x8115,
122.1531 +    0x8127,0x811d,0x8122,0x8211,0x8238,0x8233,0x823a,0x8234,0x8232,0x8274,
122.1532 +    0x8390,0x83a3,0x83a8,0x838d,0x837a,0x8373,0x83a4,0x8374,0x838f,0x8381,
122.1533 +    0x8395,0x8399,0x8375,0x8394,0x83a9,0x837d,0x8383,0x838c,0x839d,0x839b,
122.1534 +    0x83aa,0x838b,0x837e,0x83a5,0x83af,0x8388,0x8397,0x83b0,0x837f,0x83a6,
122.1535 +    0x8387,0x83ae,0x8376,0x8659
122.1536 +  },
122.1537 +  {				/* ku 19 */
122.1538 +    0x8656,0x86bf,0x86b7,0x86c2,0x86c1,0x86c5,0x86ba,0x86b0,0x86c8,0x86b9,
122.1539 +    0x86b3,0x86b8,0x86cc,0x86b4,0x86bb,0x86bc,0x86c3,0x86bd,0x86be,0x8852,
122.1540 +    0x8889,0x8895,0x88a8,0x88a2,0x88aa,0x889a,0x8891,0x88a1,0x889f,0x8898,
122.1541 +    0x88a7,0x8899,0x889b,0x8897,0x88a4,0x88ac,0x888c,0x8893,0x888e,0x8982,
122.1542 +    0x89d6,0x89d9,0x89d5,0x8a30,0x8a27,0x8a2c,0x8a1e,0x8c39,0x8c3b,0x8c5c,
122.1543 +    0x8c5d,0x8c7d,0x8ca5,0x8d7d,0x8d7b,0x8d79,0x8dbc,0x8dc2,0x8db9,0x8dbf,
122.1544 +    0x8dc1,0x8ed8,0x8ede,0x8edd,0x8edc,0x8ed7,0x8ee0,0x8ee1,0x9024,0x900b,
122.1545 +    0x9011,0x901c,0x900c,0x9021,0x90ef,0x90ea,0x90f0,0x90f4,0x90f2,0x90f3,
122.1546 +    0x90d4,0x90eb,0x90ec,0x90e9,0x9156,0x9158,0x915a,0x9153,0x9155,0x91ec,
122.1547 +    0x91f4,0x91f1,0x91f3,0x91f8
122.1548 +  },
122.1549 +  {				/* ku 1a */
122.1550 +    0x91e4,0x91f9,0x91ea,0x91eb,0x91f7,0x91e8,0x91ee,0x957a,0x9586,0x9588,
122.1551 +    0x967c,0x966d,0x966b,0x9671,0x966f,0x96bf,0x976a,0x9804,0x98e5,0x9997,
122.1552 +    0x509b,0x5095,0x5094,0x509e,0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d,
122.1553 +    0x5068,0x509c,0x5092,0x5082,0x5087,0x515f,0x51d4,0x5312,0x5311,0x53a4,
122.1554 +    0x53a7,0x5591,0x55a8,0x55a5,0x55ad,0x5577,0x5645,0x55a2,0x5593,0x5588,
122.1555 +    0x558f,0x55b5,0x5581,0x55a3,0x5592,0x55a4,0x557d,0x558c,0x55a6,0x557f,
122.1556 +    0x5595,0x55a1,0x558e,0x570c,0x5829,0x5837,0x5819,0x581e,0x5827,0x5823,
122.1557 +    0x5828,0x57f5,0x5848,0x5825,0x581c,0x581b,0x5833,0x583f,0x5836,0x582e,
122.1558 +    0x5839,0x5838,0x582d,0x582c,0x583b,0x5961,0x5aaf,0x5a94,0x5a9f,0x5a7a,
122.1559 +    0x5aa2,0x5a9e,0x5a78,0x5aa6
122.1560 +  },
122.1561 +  {				/* ku 1b */
122.1562 +    0x5a7c,0x5aa5,0x5aac,0x5a95,0x5aae,0x5a37,0x5a84,0x5a8a,0x5a97,0x5a83,
122.1563 +    0x5a8b,0x5aa9,0x5a7b,0x5a7d,0x5a8c,0x5a9c,0x5a8f,0x5a93,0x5a9d,0x5bea,
122.1564 +    0x5bcd,0x5bcb,0x5bd4,0x5bd1,0x5bca,0x5bce,0x5c0c,0x5c30,0x5d37,0x5d43,
122.1565 +    0x5d6b,0x5d41,0x5d4b,0x5d3f,0x5d35,0x5d51,0x5d4e,0x5d55,0x5d33,0x5d3a,
122.1566 +    0x5d52,0x5d3d,0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32,
122.1567 +    0x5d36,0x5d40,0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5,0x5fab,0x60c9,
122.1568 +    0x60b9,0x60cc,0x60e2,0x60ce,0x60c4,0x6114,0x60f2,0x610a,0x6116,0x6105,
122.1569 +    0x60f5,0x6113,0x60f8,0x60fc,0x60fe,0x60c1,0x6103,0x6118,0x611d,0x6110,
122.1570 +    0x60ff,0x6104,0x610b,0x624a,0x6394,0x63b1,0x63b0,0x63ce,0x63e5,0x63e8,
122.1571 +    0x63ef,0x63c3,0x649d,0x63f3
122.1572 +  },
122.1573 +  {				/* ku 1c */
122.1574 +    0x63ca,0x63e0,0x63f6,0x63d5,0x63f2,0x63f5,0x6461,0x63df,0x63be,0x63dd,
122.1575 +    0x63dc,0x63c4,0x63d8,0x63d3,0x63c2,0x63c7,0x63cc,0x63cb,0x63c8,0x63f0,
122.1576 +    0x63d7,0x63d9,0x6532,0x6567,0x656a,0x6564,0x655c,0x6568,0x6565,0x658c,
122.1577 +    0x659d,0x659e,0x65ae,0x65d0,0x65d2,0x667c,0x666c,0x667b,0x6680,0x6671,
122.1578 +    0x6679,0x666a,0x6672,0x6701,0x690c,0x68d3,0x6904,0x68dc,0x692a,0x68ec,
122.1579 +    0x68ea,0x68f1,0x690f,0x68d6,0x68f7,0x68eb,0x68e4,0x68f6,0x6913,0x6910,
122.1580 +    0x68f3,0x68e1,0x6907,0x68cc,0x6908,0x6970,0x68b4,0x6911,0x68ef,0x68c6,
122.1581 +    0x6914,0x68f8,0x68d0,0x68fd,0x68fc,0x68e8,0x690b,0x690a,0x6917,0x68ce,
122.1582 +    0x68c8,0x68dd,0x68de,0x68e6,0x68f4,0x68d1,0x6906,0x68d4,0x68e9,0x6915,
122.1583 +    0x6925,0x68c7,0x6b39,0x6b3b
122.1584 +  },
122.1585 +  {				/* ku 1d */
122.1586 +    0x6b3f,0x6b3c,0x6b94,0x6b97,0x6b99,0x6b95,0x6bbd,0x6bf0,0x6bf2,0x6bf3,
122.1587 +    0x6c30,0x6dfc,0x6e46,0x6e47,0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45,
122.1588 +    0x6e62,0x6e2b,0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40,
122.1589 +    0x6e51,0x6e3b,0x6e03,0x6e2e,0x6e5e,0x6e68,0x6e5c,0x6e61,0x6e31,0x6e28,
122.1590 +    0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22,0x6e30,0x6e53,0x6e65,0x6e27,0x6e78,
122.1591 +    0x6e64,0x6e77,0x6e55,0x6e79,0x6e52,0x6e66,0x6e35,0x6e36,0x6e5a,0x7120,
122.1592 +    0x711e,0x712f,0x70fb,0x712e,0x7131,0x7123,0x7125,0x7122,0x7132,0x711f,
122.1593 +    0x7128,0x713a,0x711b,0x724b,0x725a,0x7288,0x7289,0x7286,0x7285,0x728b,
122.1594 +    0x7312,0x730b,0x7330,0x7322,0x7331,0x7333,0x7327,0x7332,0x732d,0x7326,
122.1595 +    0x7323,0x7335,0x730c,0x742e
122.1596 +  },
122.1597 +  {				/* ku 1e */
122.1598 +    0x742c,0x7430,0x742b,0x7416,0x741a,0x7421,0x742d,0x7431,0x7424,0x7423,
122.1599 +    0x741d,0x7429,0x7420,0x7432,0x74fb,0x752f,0x756f,0x756c,0x75e7,0x75da,
122.1600 +    0x75e1,0x75e6,0x75dd,0x75df,0x75e4,0x75d7,0x7695,0x7692,0x76da,0x7746,
122.1601 +    0x7747,0x7744,0x774d,0x7745,0x774a,0x774e,0x774b,0x774c,0x77de,0x77ec,
122.1602 +    0x7860,0x7864,0x7865,0x785c,0x786d,0x7871,0x786a,0x786e,0x7870,0x7869,
122.1603 +    0x7868,0x785e,0x7862,0x7974,0x7973,0x7972,0x7970,0x7a02,0x7a0a,0x7a03,
122.1604 +    0x7a0c,0x7a04,0x7a99,0x7ae6,0x7ae4,0x7b4a,0x7b47,0x7b44,0x7b48,0x7b4c,
122.1605 +    0x7b4e,0x7b40,0x7b58,0x7b45,0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f,
122.1606 +    0x7d63,0x7d53,0x7d56,0x7d67,0x7d6a,0x7d4f,0x7d6d,0x7d5c,0x7d6b,0x7d52,
122.1607 +    0x7d54,0x7d69,0x7d51,0x7d5f
122.1608 +  },
122.1609 +  {				/* ku 1f */
122.1610 +    0x7d4e,0x7f3e,0x7f3f,0x7f65,0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051,
122.1611 +    0x804f,0x8050,0x80fe,0x80d4,0x8143,0x814a,0x8152,0x814f,0x8147,0x813d,
122.1612 +    0x814d,0x813a,0x81e6,0x81ee,0x81f7,0x81f8,0x81f9,0x8204,0x823c,0x823d,
122.1613 +    0x823f,0x8275,0x833b,0x83cf,0x83f9,0x8423,0x83c0,0x83e8,0x8412,0x83e7,
122.1614 +    0x83e4,0x83fc,0x83f6,0x8410,0x83c6,0x83c8,0x83eb,0x83e3,0x83bf,0x8401,
122.1615 +    0x83dd,0x83e5,0x83d8,0x83ff,0x83e1,0x83cb,0x83ce,0x83d6,0x83f5,0x83c9,
122.1616 +    0x8409,0x840f,0x83de,0x8411,0x8406,0x83c2,0x83f3,0x83d5,0x83fa,0x83c7,
122.1617 +    0x83d1,0x83ea,0x8413,0x839a,0x83c3,0x83ec,0x83ee,0x83c4,0x83fb,0x83d7,
122.1618 +    0x83e2,0x841b,0x83db,0x83fe,0x86d8,0x86e2,0x86e6,0x86d3,0x86e3,0x86da,
122.1619 +    0x86ea,0x86dd,0x86eb,0x86dc
122.1620 +  },
122.1621 +  {				/* ku 20 */
122.1622 +    0x86ec,0x86e9,0x86d7,0x86e8,0x86d1,0x8848,0x8856,0x8855,0x88ba,0x88d7,
122.1623 +    0x88b9,0x88b8,0x88c0,0x88be,0x88b6,0x88bc,0x88b7,0x88bd,0x88b2,0x8901,
122.1624 +    0x88c9,0x8995,0x8998,0x8997,0x89dd,0x89da,0x89db,0x8a4e,0x8a4d,0x8a39,
122.1625 +    0x8a59,0x8a40,0x8a57,0x8a58,0x8a44,0x8a45,0x8a52,0x8a48,0x8a51,0x8a4a,
122.1626 +    0x8a4c,0x8a4f,0x8c5f,0x8c81,0x8c80,0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5,
122.1627 +    0x8d84,0x8d80,0x8d89,0x8dd8,0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf,
122.1628 +    0x8dd5,0x8dd9,0x8dc8,0x8dd7,0x8dc5,0x8eef,0x8ef7,0x8efa,0x8ef9,0x8ee6,
122.1629 +    0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb,0x8ef1,0x8eec,0x8ef4,
122.1630 +    0x8ee9,0x902d,0x9034,0x902f,0x9106,0x912c,0x9104,0x90ff,0x90fc,0x9108,
122.1631 +    0x90f9,0x90fb,0x9101,0x9100
122.1632 +  },
122.1633 +  {				/* ku 21 */
122.1634 +    0x9107,0x9105,0x9103,0x9161,0x9164,0x915f,0x9162,0x9160,0x9201,0x920a,
122.1635 +    0x9225,0x9203,0x921a,0x9226,0x920f,0x920c,0x9200,0x9212,0x91ff,0x91fd,
122.1636 +    0x9206,0x9204,0x9227,0x9202,0x921c,0x9224,0x9219,0x9217,0x9205,0x9216,
122.1637 +    0x957b,0x958d,0x958c,0x9590,0x9687,0x967e,0x9688,0x9689,0x9683,0x9680,
122.1638 +    0x96c2,0x96c8,0x96c3,0x96f1,0x96f0,0x976c,0x9770,0x976e,0x9807,0x98a9,
122.1639 +    0x98eb,0x9ce6,0x9ef9,0x4e83,0x4e84,0x4eb6,0x50bd,0x50bf,0x50c6,0x50ae,
122.1640 +    0x50c4,0x50ca,0x50b4,0x50c8,0x50c2,0x50b0,0x50c1,0x50ba,0x50b1,0x50cb,
122.1641 +    0x50c9,0x50b6,0x50b8,0x51d7,0x527a,0x5278,0x527b,0x527c,0x55c3,0x55db,
122.1642 +    0x55cc,0x55d0,0x55cb,0x55ca,0x55dd,0x55c0,0x55d4,0x55c4,0x55e9,0x55bf,
122.1643 +    0x55d2,0x558d,0x55cf,0x55d5
122.1644 +  },
122.1645 +  {				/* ku 22 */
122.1646 +    0x55e2,0x55d6,0x55c8,0x55f2,0x55cd,0x55d9,0x55c2,0x5714,0x5853,0x5868,
122.1647 +    0x5864,0x584f,0x584d,0x5849,0x586f,0x5855,0x584e,0x585d,0x5859,0x5865,
122.1648 +    0x585b,0x583d,0x5863,0x5871,0x58fc,0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8,
122.1649 +    0x5ab1,0x5ab5,0x5ab0,0x5abf,0x5ac8,0x5abb,0x5ac6,0x5ab7,0x5ac0,0x5aca,
122.1650 +    0x5ab4,0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8,0x5bd9,0x5c1f,0x5c33,
122.1651 +    0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e,0x5d68,0x5d67,0x5d62,
122.1652 +    0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d,0x5e4b,0x5ec5,0x5ecc,0x5ec6,0x5ecb,
122.1653 +    0x5ec7,0x5f40,0x5faf,0x5fad,0x60f7,0x6149,0x614a,0x612b,0x6145,0x6136,
122.1654 +    0x6132,0x612e,0x6146,0x612f,0x614f,0x6129,0x6140,0x6220,0x9168,0x6223,
122.1655 +    0x6225,0x6224,0x63c5,0x63f1
122.1656 +  },
122.1657 +  {				/* ku 23 */
122.1658 +    0x63eb,0x6410,0x6412,0x6409,0x6420,0x6424,0x6433,0x6443,0x641f,0x6415,
122.1659 +    0x6418,0x6439,0x6437,0x6422,0x6423,0x640c,0x6426,0x6430,0x6428,0x6441,
122.1660 +    0x6435,0x642f,0x640a,0x641a,0x6440,0x6425,0x6427,0x640b,0x63e7,0x641b,
122.1661 +    0x642e,0x6421,0x640e,0x656f,0x6592,0x65d3,0x6686,0x668c,0x6695,0x6690,
122.1662 +    0x668b,0x668a,0x6699,0x6694,0x6678,0x6720,0x6966,0x695f,0x6938,0x694e,
122.1663 +    0x6962,0x6971,0x693f,0x6945,0x696a,0x6939,0x6942,0x6957,0x6959,0x697a,
122.1664 +    0x6948,0x6949,0x6935,0x696c,0x6933,0x693d,0x6965,0x68f0,0x6978,0x6934,
122.1665 +    0x6969,0x6940,0x696f,0x6944,0x6976,0x6958,0x6941,0x6974,0x694c,0x693b,
122.1666 +    0x694b,0x6937,0x695c,0x694f,0x6951,0x6932,0x6952,0x692f,0x697b,0x693c,
122.1667 +    0x6b46,0x6b45,0x6b43,0x6b42
122.1668 +  },
122.1669 +  {				/* ku 24 */
122.1670 +    0x6b48,0x6b41,0x6b9b,0x6bfb,0x6bfc,0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,
122.1671 +    0x6ec8,0x6e8f,0x6ec0,0x6e9f,0x6e93,0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6,
122.1672 +    0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9,0x6eb7,0x6eb0,0x6ecd,0x6ea6,0x6ecf,
122.1673 +    0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8,0x6e99,0x6e92,0x6e8e,0x6e8d,0x6ea4,
122.1674 +    0x6ea1,0x6ebf,0x6eb3,0x6ed0,0x6eca,0x6e97,0x6eae,0x6ea3,0x7147,0x7154,
122.1675 +    0x7152,0x7163,0x7160,0x7141,0x715d,0x7162,0x7172,0x7178,0x716a,0x7161,
122.1676 +    0x7142,0x7158,0x7143,0x714b,0x7170,0x715f,0x7150,0x7153,0x7144,0x714d,
122.1677 +    0x715a,0x724f,0x728d,0x728c,0x7291,0x7290,0x728e,0x733c,0x7342,0x733b,
122.1678 +    0x733a,0x7340,0x734a,0x7349,0x7444,0x744a,0x744b,0x7452,0x7451,0x7457,
122.1679 +    0x7440,0x744f,0x7450,0x744e
122.1680 +  },
122.1681 +  {				/* ku 25 */
122.1682 +    0x7442,0x7446,0x744d,0x7454,0x74e1,0x74ff,0x74fe,0x74fd,0x751d,0x7579,
122.1683 +    0x7577,0x6983,0x75ef,0x760f,0x7603,0x75f7,0x75fe,0x75fc,0x75f9,0x75f8,
122.1684 +    0x7610,0x75fb,0x75f6,0x75ed,0x75f5,0x75fd,0x7699,0x76b5,0x76dd,0x7755,
122.1685 +    0x775f,0x7760,0x7752,0x7756,0x775a,0x7769,0x7767,0x7754,0x7759,0x776d,
122.1686 +    0x77e0,0x7887,0x789a,0x7894,0x788f,0x7884,0x7895,0x7885,0x7886,0x78a1,
122.1687 +    0x7883,0x7879,0x7899,0x7880,0x7896,0x787b,0x797c,0x7982,0x797d,0x7979,
122.1688 +    0x7a11,0x7a18,0x7a19,0x7a12,0x7a17,0x7a15,0x7a22,0x7a13,0x7a1b,0x7a10,
122.1689 +    0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74,0x7b69,0x7b72,
122.1690 +    0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78,0x7b76,0x7b63,0x7cb2,0x7cb4,
122.1691 +    0x7caf,0x7d88,0x7d86,0x7d80
122.1692 +  },
122.1693 +  {				/* ku 26 */
122.1694 +    0x7d8d,0x7d7f,0x7d85,0x7d7a,0x7d8e,0x7d7b,0x7d83,0x7d7c,0x7d8c,0x7d94,
122.1695 +    0x7d84,0x7d7d,0x7d92,0x7f6d,0x7f6b,0x7f67,0x7f68,0x7f6c,0x7fa6,0x7fa5,
122.1696 +    0x7fa7,0x7fdb,0x7fdc,0x8021,0x8164,0x8160,0x8177,0x815c,0x8169,0x815b,
122.1697 +    0x8162,0x8172,0x6721,0x815e,0x8176,0x8167,0x816f,0x8144,0x8161,0x821d,
122.1698 +    0x8249,0x8244,0x8240,0x8242,0x8245,0x84f1,0x843f,0x8456,0x8476,0x8479,
122.1699 +    0x848f,0x848d,0x8465,0x8451,0x8440,0x8486,0x8467,0x8430,0x844d,0x847d,
122.1700 +    0x845a,0x8459,0x8474,0x8473,0x845d,0x8507,0x845e,0x8437,0x843a,0x8434,
122.1701 +    0x847a,0x8443,0x8478,0x8432,0x8445,0x8429,0x83d9,0x844b,0x842f,0x8442,
122.1702 +    0x842d,0x845f,0x8470,0x8439,0x844e,0x844c,0x8452,0x846f,0x84c5,0x848e,
122.1703 +    0x843b,0x8447,0x8436,0x8433
122.1704 +  },
122.1705 +  {				/* ku 27 */
122.1706 +    0x8468,0x847e,0x8444,0x842b,0x8460,0x8454,0x846e,0x8450,0x870b,0x8704,
122.1707 +    0x86f7,0x870c,0x86fa,0x86d6,0x86f5,0x874d,0x86f8,0x870e,0x8709,0x8701,
122.1708 +    0x86f6,0x870d,0x8705,0x88d6,0x88cb,0x88cd,0x88ce,0x88de,0x88db,0x88da,
122.1709 +    0x88cc,0x88d0,0x8985,0x899b,0x89df,0x89e5,0x89e4,0x89e1,0x89e0,0x89e2,
122.1710 +    0x89dc,0x89e6,0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f,0x8a77,0x8a82,0x8a84,
122.1711 +    0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b,0x8c4a,0x8c65,0x8c64,
122.1712 +    0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68,0x8d69,0x8d91,0x8d8c,0x8d8e,
122.1713 +    0x8d8f,0x8d8d,0x8d93,0x8d94,0x8d90,0x8d92,0x8df0,0x8de0,0x8dec,0x8df1,
122.1714 +    0x8dee,0x8dd0,0x8de9,0x8de3,0x8de2,0x8de7,0x8df2,0x8deb,0x8df4,0x8f06,
122.1715 +    0x8eff,0x8f01,0x8f00,0x8f05
122.1716 +  },
122.1717 +  {				/* ku 28 */
122.1718 +    0x8f07,0x8f08,0x8f02,0x8f0b,0x9052,0x903f,0x9044,0x9049,0x903d,0x9110,
122.1719 +    0x910d,0x910f,0x9111,0x9116,0x9114,0x910b,0x910e,0x916e,0x916f,0x9248,
122.1720 +    0x9252,0x9230,0x923a,0x9266,0x9233,0x9265,0x925e,0x9283,0x922e,0x924a,
122.1721 +    0x9246,0x926d,0x926c,0x924f,0x9260,0x9267,0x926f,0x9236,0x9261,0x9270,
122.1722 +    0x9231,0x9254,0x9263,0x9250,0x9272,0x924e,0x9253,0x924c,0x9256,0x9232,
122.1723 +    0x959f,0x959c,0x959e,0x959b,0x9692,0x9693,0x9691,0x9697,0x96ce,0x96fa,
122.1724 +    0x96fd,0x96f8,0x96f5,0x9773,0x9777,0x9778,0x9772,0x980f,0x980d,0x980e,
122.1725 +    0x98ac,0x98f6,0x98f9,0x99af,0x99b2,0x99b0,0x99b5,0x9aad,0x9aab,0x9b5b,
122.1726 +    0x9cea,0x9ced,0x9ce7,0x9e80,0x9efd,0x50e6,0x50d4,0x50d7,0x50e8,0x50f3,
122.1727 +    0x50db,0x50ea,0x50dd,0x50e4
122.1728 +  },
122.1729 +  {				/* ku 29 */
122.1730 +    0x50d3,0x50ec,0x50f0,0x50ef,0x50e3,0x50e0,0x51d8,0x5280,0x5281,0x52e9,
122.1731 +    0x52eb,0x5330,0x53ac,0x5627,0x5615,0x560c,0x5612,0x55fc,0x560f,0x561c,
122.1732 +    0x5601,0x5613,0x5602,0x55fa,0x561d,0x5604,0x55ff,0x55f9,0x5889,0x587c,
122.1733 +    0x5890,0x5898,0x5886,0x5881,0x587f,0x5874,0x588b,0x587a,0x5887,0x5891,
122.1734 +    0x588e,0x5876,0x5882,0x5888,0x587b,0x5894,0x588f,0x58fe,0x596b,0x5adc,
122.1735 +    0x5aee,0x5ae5,0x5ad5,0x5aea,0x5ada,0x5aed,0x5aeb,0x5af3,0x5ae2,0x5ae0,
122.1736 +    0x5adb,0x5aec,0x5ade,0x5add,0x5ad9,0x5ae8,0x5adf,0x5b77,0x5be0,0x5be3,
122.1737 +    0x5c63,0x5d82,0x5d80,0x5d7d,0x5d86,0x5d7a,0x5d81,0x5d77,0x5d8a,0x5d89,
122.1738 +    0x5d88,0x5d7e,0x5d7c,0x5d8d,0x5d79,0x5d7f,0x5e58,0x5e59,0x5e53,0x5ed8,
122.1739 +    0x5ed1,0x5ed7,0x5ece,0x5edc
122.1740 +  },
122.1741 +  {				/* ku 2a */
122.1742 +    0x5ed5,0x5ed9,0x5ed2,0x5ed4,0x5f44,0x5f43,0x5f6f,0x5fb6,0x612c,0x6128,
122.1743 +    0x6141,0x615e,0x6171,0x6173,0x6152,0x6153,0x6172,0x616c,0x6180,0x6174,
122.1744 +    0x6154,0x617a,0x615b,0x6165,0x613b,0x616a,0x6161,0x6156,0x6229,0x6227,
122.1745 +    0x622b,0x642b,0x644d,0x645b,0x645d,0x6474,0x6476,0x6472,0x6473,0x647d,
122.1746 +    0x6475,0x6466,0x64a6,0x644e,0x6482,0x645e,0x645c,0x644b,0x6453,0x6460,
122.1747 +    0x6450,0x647f,0x643f,0x646c,0x646b,0x6459,0x6465,0x6477,0x6573,0x65a0,
122.1748 +    0x66a1,0x66a0,0x669f,0x6705,0x6704,0x6722,0x69b1,0x69b6,0x69c9,0x69a0,
122.1749 +    0x69ce,0x6996,0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7,0x698d,
122.1750 +    0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4,0x69b9,0x69ca,
122.1751 +    0x699a,0x69cf,0x69b3,0x6993
122.1752 +  },
122.1753 +  {				/* ku 2b */
122.1754 +    0x69aa,0x69a1,0x699e,0x69d9,0x6997,0x6990,0x69c2,0x69b5,0x69a5,0x69c6,
122.1755 +    0x6b4a,0x6b4d,0x6b4b,0x6b9e,0x6b9f,0x6ba0,0x6bc3,0x6bc4,0x6bfe,0x6ece,
122.1756 +    0x6ef5,0x6ef1,0x6f03,0x6f25,0x6ef8,0x6f37,0x6efb,0x6f2e,0x6f09,0x6f4e,
122.1757 +    0x6f19,0x6f1a,0x6f27,0x6f18,0x6f3b,0x6f12,0x6eed,0x6f0a,0x6f36,0x6f73,
122.1758 +    0x6ef9,0x6eee,0x6f2d,0x6f40,0x6f30,0x6f3c,0x6f35,0x6eeb,0x6f07,0x6f0e,
122.1759 +    0x6f43,0x6f05,0x6efd,0x6ef6,0x6f39,0x6f1c,0x6efc,0x6f3a,0x6f1f,0x6f0d,
122.1760 +    0x6f1e,0x6f08,0x6f21,0x7187,0x7190,0x7189,0x7180,0x7185,0x7182,0x718f,
122.1761 +    0x717b,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,0x7295,0x7293,0x7343,
122.1762 +    0x734d,0x7351,0x734c,0x7462,0x7473,0x7471,0x7475,0x7472,0x7467,0x746e,
122.1763 +    0x7500,0x7502,0x7503,0x757d
122.1764 +  },
122.1765 +  {				/* ku 2c */
122.1766 +    0x7590,0x7616,0x7608,0x760c,0x7615,0x7611,0x760a,0x7614,0x76b8,0x7781,
122.1767 +    0x777c,0x7785,0x7782,0x776e,0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa,
122.1768 +    0x78b4,0x78ad,0x78a8,0x787e,0x78ab,0x789e,0x78a5,0x78a0,0x78ac,0x78a2,
122.1769 +    0x78a4,0x7998,0x798a,0x798b,0x7996,0x7995,0x7994,0x7993,0x7997,0x7988,
122.1770 +    0x7992,0x7990,0x7a2b,0x7a4a,0x7a30,0x7a2f,0x7a28,0x7a26,0x7aa8,0x7aab,
122.1771 +    0x7aac,0x7aee,0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96,0x7b8d,0x7b8c,
122.1772 +    0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82,0x7cbb,0x7cbf,
122.1773 +    0x7cbc,0x7cba,0x7da7,0x7db7,0x7dc2,0x7da3,0x7daa,0x7dc1,0x7dc0,0x7dc5,
122.1774 +    0x7d9d,0x7dce,0x7dc4,0x7dc6,0x7dcb,0x7dcc,0x7daf,0x7db9,0x7d96,0x7dbc,
122.1775 +    0x7d9f,0x7da6,0x7dae,0x7da9
122.1776 +  },
122.1777 +  {				/* ku 2d */
122.1778 +    0x7da1,0x7dc9,0x7f73,0x7fe2,0x7fe3,0x7fe5,0x7fde,0x8024,0x805d,0x805c,
122.1779 +    0x8189,0x8186,0x8183,0x8187,0x818d,0x818c,0x818b,0x8215,0x8497,0x84a4,
122.1780 +    0x84a1,0x849f,0x84ba,0x84ce,0x84c2,0x84ac,0x84ae,0x84ab,0x84b9,0x84b4,
122.1781 +    0x84c1,0x84cd,0x84aa,0x849a,0x84b1,0x84d0,0x849d,0x84a7,0x84bb,0x84a2,
122.1782 +    0x8494,0x84c7,0x84cc,0x849b,0x84a9,0x84af,0x84a8,0x84d6,0x8498,0x84b6,
122.1783 +    0x84cf,0x84a0,0x84d7,0x84d4,0x84d2,0x84db,0x84b0,0x8491,0x8661,0x8733,
122.1784 +    0x8723,0x8728,0x876b,0x8740,0x872e,0x871e,0x8721,0x8719,0x871b,0x8743,
122.1785 +    0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a,0x872d,0x873c,0x8712,
122.1786 +    0x873a,0x8731,0x8735,0x8742,0x8726,0x8727,0x8738,0x8724,0x871a,0x8730,
122.1787 +    0x8711,0x88f7,0x88e7,0x88f1
122.1788 +  },
122.1789 +  {				/* ku 2e */
122.1790 +    0x88f2,0x88fa,0x88fe,0x88ee,0x88fc,0x88f6,0x88fb,0x88f0,0x88ec,0x88eb,
122.1791 +    0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb,0x89e8,0x8aab,0x8a99,0x8a8b,
122.1792 +    0x8a92,0x8a8f,0x8a96,0x8c3d,0x8c68,0x8c69,0x8cd5,0x8ccf,0x8cd7,0x8d96,
122.1793 +    0x8e09,0x8e02,0x8dff,0x8e0d,0x8dfd,0x8e0a,0x8e03,0x8e07,0x8e06,0x8e05,
122.1794 +    0x8dfe,0x8e00,0x8e04,0x8f10,0x8f11,0x8f0e,0x8f0d,0x9123,0x911c,0x9120,
122.1795 +    0x9122,0x911f,0x911d,0x911a,0x9124,0x9121,0x911b,0x917a,0x9172,0x9179,
122.1796 +    0x9173,0x92a5,0x92a4,0x9276,0x929b,0x927a,0x92a0,0x9294,0x92aa,0x928d,
122.1797 +    0x92a6,0x929a,0x92ab,0x9279,0x9297,0x927f,0x92a3,0x92ee,0x928e,0x9282,
122.1798 +    0x9295,0x92a2,0x927d,0x9288,0x92a1,0x928a,0x9286,0x928c,0x9299,0x92a7,
122.1799 +    0x927e,0x9287,0x92a9,0x929d
122.1800 +  },
122.1801 +  {				/* ku 2f */
122.1802 +    0x928b,0x922d,0x969e,0x96a1,0x96ff,0x9758,0x977d,0x977a,0x977e,0x9783,
122.1803 +    0x9780,0x9782,0x977b,0x9784,0x9781,0x977f,0x97ce,0x97cd,0x9816,0x98ad,
122.1804 +    0x98ae,0x9902,0x9900,0x9907,0x999d,0x999c,0x99c3,0x99b9,0x99bb,0x99ba,
122.1805 +    0x99c2,0x99bd,0x99c7,0x9ab1,0x9ae3,0x9ae7,0x9b3e,0x9b3f,0x9b60,0x9b61,
122.1806 +    0x9b5f,0x9cf1,0x9cf2,0x9cf5,0x9ea7,0x50ff,0x5103,0x5130,0x50f8,0x5106,
122.1807 +    0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd,0x510a,0x528b,0x528c,0x52f1,
122.1808 +    0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641,0x564a,0x5649,0x5646,0x5658,
122.1809 +    0x565a,0x5640,0x5633,0x563d,0x562c,0x563e,0x5638,0x562a,0x563a,0x571a,
122.1810 +    0x58ab,0x589d,0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff,
122.1811 +    0x5aff,0x5af4,0x5afd,0x5af7
122.1812 +  },
122.1813 +  {				/* ku 30 */
122.1814 +    0x5af6,0x5b03,0x5af8,0x5b02,0x5af9,0x5b01,0x5b07,0x5b05,0x5b0f,0x5c67,
122.1815 +    0x5d99,0x5d97,0x5d9f,0x5d92,0x5da2,0x5d93,0x5d95,0x5da0,0x5d9c,0x5da1,
122.1816 +    0x5d9a,0x5d9e,0x5e69,0x5e5d,0x5e60,0x5e5c,0x7df3,0x5edb,0x5ede,0x5ee1,
122.1817 +    0x5f49,0x5fb2,0x618b,0x6183,0x6179,0x61b1,0x61b0,0x61a2,0x6189,0x619b,
122.1818 +    0x6193,0x61af,0x61ad,0x619f,0x6192,0x61aa,0x61a1,0x618d,0x6166,0x61b3,
122.1819 +    0x622d,0x646e,0x6470,0x6496,0x64a0,0x6485,0x6497,0x649c,0x648f,0x648b,
122.1820 +    0x648a,0x648c,0x64a3,0x649f,0x6468,0x64b1,0x6498,0x6576,0x657a,0x6579,
122.1821 +    0x657b,0x65b2,0x65b3,0x66b5,0x66b0,0x66a9,0x66b2,0x66b7,0x66aa,0x66af,
122.1822 +    0x6a00,0x6a06,0x6a17,0x69e5,0x69f8,0x6a15,0x69f1,0x69e4,0x6a20,0x69ff,
122.1823 +    0x69ec,0x69e2,0x6a1b,0x6a1d
122.1824 +  },
122.1825 +  {				/* ku 31 */
122.1826 +    0x69fe,0x6a27,0x69f2,0x69ee,0x6a14,0x69f7,0x69e7,0x6a40,0x6a08,0x69e6,
122.1827 +    0x69fb,0x6a0d,0x69fc,0x69eb,0x6a09,0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6,
122.1828 +    0x6a26,0x6a07,0x69f4,0x6a16,0x6b51,0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01,
122.1829 +    0x6c00,0x6bff,0x6c02,0x6f41,0x6f26,0x6f7e,0x6f87,0x6fc6,0x6f92,0x6f8d,
122.1830 +    0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a,0x6f96,0x6f76,0x6f6c,0x6f82,
122.1831 +    0x6f55,0x6f72,0x6f52,0x6f50,0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00,0x6f61,
122.1832 +    0x6f6b,0x6f7d,0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95,0x6f63,
122.1833 +    0x6f77,0x6f6a,0x6f7b,0x71b2,0x71af,0x719b,0x71b0,0x71a0,0x719a,0x71a9,
122.1834 +    0x71b5,0x719d,0x71a5,0x719e,0x71a4,0x71a1,0x71aa,0x719c,0x71a7,0x71b3,
122.1835 +    0x7298,0x729a,0x7358,0x7352
122.1836 +  },
122.1837 +  {				/* ku 32 */
122.1838 +    0x735e,0x735f,0x7360,0x735d,0x735b,0x7361,0x735a,0x7359,0x7362,0x7487,
122.1839 +    0x7489,0x748a,0x7486,0x7481,0x747d,0x7485,0x7488,0x747c,0x7479,0x7508,
122.1840 +    0x7507,0x757e,0x7625,0x761e,0x7619,0x761d,0x761c,0x7623,0x761a,0x7628,
122.1841 +    0x761b,0x769c,0x769d,0x769e,0x769b,0x778d,0x778f,0x7789,0x7788,0x78cd,
122.1842 +    0x78bb,0x78cf,0x78cc,0x78d1,0x78ce,0x78d4,0x78c8,0x78c3,0x78c4,0x78c9,
122.1843 +    0x799a,0x79a1,0x79a0,0x799c,0x79a2,0x799b,0x6b76,0x7a39,0x7ab2,0x7ab4,
122.1844 +    0x7ab3,0x7bb7,0x7bcb,0x7bbe,0x7bac,0x7bce,0x7baf,0x7bb9,0x7bca,0x7bb5,
122.1845 +    0x7cc5,0x7cc8,0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7,0x7dd7,0x7de1,
122.1846 +    0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf,0x7f76,0x7fac,
122.1847 +    0x7fb0,0x7fad,0x7fed,0x7feb
122.1848 +  },
122.1849 +  {				/* ku 33 */
122.1850 +    0x7fea,0x7fec,0x7fe6,0x7fe8,0x8064,0x8067,0x81a3,0x819f,0x819e,0x8195,
122.1851 +    0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250,0x824e,0x8251,
122.1852 +    0x8524,0x853b,0x850f,0x8500,0x8529,0x850e,0x8509,0x850d,0x851f,0x850a,
122.1853 +    0x8527,0x851c,0x84fb,0x852b,0x84fa,0x8508,0x850c,0x84f4,0x852a,0x84f2,
122.1854 +    0x8515,0x84f7,0x84eb,0x84f3,0x84fc,0x8512,0x84ea,0x84e9,0x8516,0x84fe,
122.1855 +    0x8528,0x851d,0x852e,0x8502,0x84fd,0x851e,0x84f6,0x8531,0x8526,0x84e7,
122.1856 +    0x84e8,0x84f0,0x84ef,0x84f9,0x8518,0x8520,0x8530,0x850b,0x8519,0x852f,
122.1857 +    0x8662,0x8756,0x8763,0x8764,0x8777,0x87e1,0x8773,0x8758,0x8754,0x875b,
122.1858 +    0x8752,0x8761,0x875a,0x8751,0x875e,0x876d,0x876a,0x8750,0x874e,0x875f,
122.1859 +    0x875d,0x876f,0x876c,0x877a
122.1860 +  },
122.1861 +  {				/* ku 34 */
122.1862 +    0x876e,0x875c,0x8765,0x874f,0x877b,0x8775,0x8762,0x8767,0x8769,0x885a,
122.1863 +    0x8905,0x890c,0x8914,0x890b,0x8917,0x8918,0x8919,0x8906,0x8916,0x8911,
122.1864 +    0x890e,0x8909,0x89a2,0x89a4,0x89a3,0x89ed,0x89f0,0x89ec,0x8acf,0x8ac6,
122.1865 +    0x8ab8,0x8ad3,0x8ad1,0x8ad4,0x8ad5,0x8abb,0x8ad7,0x8abe,0x8ac0,0x8ac5,
122.1866 +    0x8ad8,0x8ac3,0x8aba,0x8abd,0x8ad9,0x8c3e,0x8c4d,0x8c8f,0x8ce5,0x8cdf,
122.1867 +    0x8cd9,0x8ce8,0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c,0x8da1,0x8d9b,0x8e20,
122.1868 +    0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16,0x8e11,0x8e19,0x8e26,
122.1869 +    0x8e27,0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c,0x8e17,0x8e1a,0x8f2c,0x8f24,
122.1870 +    0x8f18,0x8f1a,0x8f20,0x8f23,0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067,
122.1871 +    0x906b,0x912f,0x912b,0x9129
122.1872 +  },
122.1873 +  {				/* ku 35 */
122.1874 +    0x912a,0x9132,0x9126,0x912e,0x9185,0x9186,0x918a,0x9181,0x9182,0x9184,
122.1875 +    0x9180,0x92d0,0x92c3,0x92c4,0x92c0,0x92d9,0x92b6,0x92cf,0x92f1,0x92df,
122.1876 +    0x92d8,0x92e9,0x92d7,0x92dd,0x92cc,0x92ef,0x92c2,0x92e8,0x92ca,0x92c8,
122.1877 +    0x92ce,0x92e6,0x92cd,0x92d5,0x92c9,0x92e0,0x92de,0x92e7,0x92d1,0x92d3,
122.1878 +    0x92b5,0x92e1,0x9325,0x92c6,0x92b4,0x957c,0x95ac,0x95ab,0x95ae,0x95b0,
122.1879 +    0x96a4,0x96a2,0x96d3,0x9705,0x9708,0x9702,0x975a,0x978a,0x978e,0x9788,
122.1880 +    0x97d0,0x97cf,0x981e,0x981d,0x9826,0x9829,0x9828,0x9820,0x981b,0x9827,
122.1881 +    0x98b2,0x9908,0x98fa,0x9911,0x9914,0x9916,0x9917,0x9915,0x99dc,0x99cd,
122.1882 +    0x99cf,0x99d3,0x99d4,0x99ce,0x99c9,0x99d6,0x99d8,0x99cb,0x99d7,0x99cc,
122.1883 +    0x9ab3,0x9aec,0x9aeb,0x9af3
122.1884 +  },
122.1885 +  {				/* ku 36 */
122.1886 +    0x9af2,0x9af1,0x9b46,0x9b43,0x9b67,0x9b74,0x9b71,0x9b66,0x9b76,0x9b75,
122.1887 +    0x9b70,0x9b68,0x9b64,0x9b6c,0x9cfc,0x9cfa,0x9cfd,0x9cff,0x9cf7,0x9d07,
122.1888 +    0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05,0x9d04,0x9e83,0x9ed3,0x9f0f,0x9f10,
122.1889 +    0x511c,0x5113,0x5117,0x511a,0x5111,0x51de,0x5334,0x53e1,0x5670,0x5660,
122.1890 +    0x566e,0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c,0x571b,
122.1891 +    0x58c8,0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc,0x58c6,0x5b17,0x5b19,
122.1892 +    0x5b1b,0x5b21,0x5b14,0x5b13,0x5b10,0x5b16,0x5b28,0x5b1a,0x5b20,0x5b1e,
122.1893 +    0x5bef,0x5dac,0x5db1,0x5da9,0x5da7,0x5db5,0x5db0,0x5dae,0x5daa,0x5da8,
122.1894 +    0x5db2,0x5dad,0x5daf,0x5db4,0x5e67,0x5e68,0x5e66,0x5e6f,0x5ee9,0x5ee7,
122.1895 +    0x5ee6,0x5ee8,0x5ee5,0x5f4b
122.1896 +  },
122.1897 +  {				/* ku 37 */
122.1898 +    0x5fbc,0x5fbb,0x619d,0x61a8,0x6196,0x61c5,0x61b4,0x61c6,0x61c1,0x61cc,
122.1899 +    0x61ba,0x61bf,0x61b8,0x618c,0x64d7,0x64d6,0x64d0,0x64cf,0x64c9,0x64bd,
122.1900 +    0x6489,0x64c3,0x64db,0x64f3,0x64d9,0x6533,0x657f,0x657c,0x65a2,0x66c8,
122.1901 +    0x66be,0x66c0,0x66ca,0x66cb,0x66cf,0x66bd,0x66bb,0x66ba,0x66cc,0x6723,
122.1902 +    0x6a34,0x6a66,0x6a49,0x6a67,0x6a32,0x6a68,0x6a3e,0x6a5d,0x6a6d,0x6a76,
122.1903 +    0x6a5b,0x6a51,0x6a28,0x6a5a,0x6a3b,0x6a3f,0x6a41,0x6a6a,0x6a64,0x6a50,
122.1904 +    0x6a4f,0x6a54,0x6a6f,0x6a69,0x6a60,0x6a3c,0x6a5e,0x6a56,0x6a55,0x6a4d,
122.1905 +    0x6a4e,0x6a46,0x6b55,0x6b54,0x6b56,0x6ba7,0x6baa,0x6bab,0x6bc8,0x6bc7,
122.1906 +    0x6c04,0x6c03,0x6c06,0x6fad,0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8,
122.1907 +    0x6f5e,0x6fc4,0x6fbd,0x6f9e
122.1908 +  },
122.1909 +  {				/* ku 38 */
122.1910 +    0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba,0x6fac,0x6faa,0x6fcf,0x6fbf,
122.1911 +    0x6fb8,0x6fa2,0x6fc9,0x6fab,0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2,
122.1912 +    0x71bf,0x71b8,0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf,
122.1913 +    0x71bd,0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e,0x7369,0x7366,
122.1914 +    0x7367,0x736c,0x7365,0x736b,0x736a,0x747f,0x749a,0x74a0,0x7494,0x7492,
122.1915 +    0x7495,0x74a1,0x750b,0x7580,0x762f,0x762d,0x7631,0x763d,0x7633,0x763c,
122.1916 +    0x7635,0x7632,0x7630,0x76bb,0x76e6,0x779a,0x779d,0x77a1,0x779c,0x779b,
122.1917 +    0x77a2,0x77a3,0x7795,0x7799,0x7797,0x78dd,0x78e9,0x78e5,0x78ea,0x78de,
122.1918 +    0x78e3,0x78db,0x78e1,0x78e2,0x78ed,0x78df,0x78e0,0x79a4,0x7a44,0x7a48,
122.1919 +    0x7a47,0x7ab6,0x7ab8,0x7ab5
122.1920 +  },
122.1921 +  {				/* ku 39 */
122.1922 +    0x7ab1,0x7ab7,0x7bde,0x7be3,0x7be7,0x7bdd,0x7bd5,0x7be5,0x7bda,0x7be8,
122.1923 +    0x7bf9,0x7bd4,0x7bea,0x7be2,0x7bdc,0x7beb,0x7bd8,0x7bdf,0x7cd2,0x7cd4,
122.1924 +    0x7cd7,0x7cd0,0x7cd1,0x7e12,0x7e21,0x7e17,0x7e0c,0x7e1f,0x7e20,0x7e13,
122.1925 +    0x7e0e,0x7e1c,0x7e15,0x7e1a,0x7e22,0x7e0b,0x7e0f,0x7e16,0x7e0d,0x7e14,
122.1926 +    0x7e25,0x7e24,0x7f43,0x7f7b,0x7f7c,0x7f7a,0x7fb1,0x7fef,0x802a,0x8029,
122.1927 +    0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5,0x81ab,0x81b0,0x81ac,0x81b4,
122.1928 +    0x81b2,0x81b7,0x81a7,0x81f2,0x8255,0x8256,0x8257,0x8556,0x8545,0x856b,
122.1929 +    0x854d,0x8553,0x8561,0x8558,0x8540,0x8546,0x8564,0x8541,0x8562,0x8544,
122.1930 +    0x8551,0x8547,0x8563,0x853e,0x855b,0x8571,0x854e,0x856e,0x8575,0x8555,
122.1931 +    0x8567,0x8560,0x858c,0x8566
122.1932 +  },
122.1933 +  {				/* ku 3a */
122.1934 +    0x855d,0x8554,0x8565,0x856c,0x8663,0x8665,0x8664,0x87a4,0x879b,0x878f,
122.1935 +    0x8797,0x8793,0x8792,0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87a3,
122.1936 +    0x8785,0x8790,0x8791,0x879d,0x8784,0x8794,0x879c,0x879a,0x8789,0x891e,
122.1937 +    0x8926,0x8930,0x892d,0x892e,0x8927,0x8931,0x8922,0x8929,0x8923,0x892f,
122.1938 +    0x892c,0x891f,0x89f1,0x8ae0,0x8ae2,0x8af2,0x8af4,0x8af5,0x8add,0x8b14,
122.1939 +    0x8ae4,0x8adf,0x8af0,0x8ac8,0x8ade,0x8ae1,0x8ae8,0x8aff,0x8aef,0x8afb,
122.1940 +    0x8c91,0x8c92,0x8c90,0x8cf5,0x8cee,0x8cf1,0x8cf0,0x8cf3,0x8d6c,0x8d6e,
122.1941 +    0x8da5,0x8da7,0x8e33,0x8e3e,0x8e38,0x8e40,0x8e45,0x8e36,0x8e3c,0x8e3d,
122.1942 +    0x8e41,0x8e30,0x8e3f,0x8ebd,0x8f36,0x8f2e,0x8f35,0x8f32,0x8f39,0x8f37,
122.1943 +    0x8f34,0x9076,0x9079,0x907b
122.1944 +  },
122.1945 +  {				/* ku 3b */
122.1946 +    0x9086,0x90fa,0x9133,0x9135,0x9136,0x9193,0x9190,0x9191,0x918d,0x918f,
122.1947 +    0x9327,0x931e,0x9308,0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b,
122.1948 +    0x9323,0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d,0x92fa,
122.1949 +    0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324,0x92ff,0x9329,0x9339,0x9335,
122.1950 +    0x932a,0x9314,0x930c,0x930b,0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc,
122.1951 +    0x95cd,0x95be,0x95b9,0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4,
122.1952 +    0x970b,0x9712,0x9710,0x9799,0x9797,0x9794,0x97f0,0x97f8,0x9835,0x982f,
122.1953 +    0x9832,0x9924,0x991f,0x9927,0x9929,0x999e,0x99ee,0x99ec,0x99e5,0x99e4,
122.1954 +    0x99f0,0x99e3,0x99ea,0x99e9,0x99e7,0x9ab9,0x9abf,0x9ab4,0x9abb,0x9af6,
122.1955 +    0x9afa,0x9af9,0x9af7,0x9b33
122.1956 +  },
122.1957 +  {				/* ku 3c */
122.1958 +    0x9b80,0x9b85,0x9b87,0x9b7c,0x9b7e,0x9b7b,0x9b82,0x9b93,0x9b92,0x9b90,
122.1959 +    0x9b7a,0x9b95,0x9b7d,0x9b88,0x9d25,0x9d17,0x9d20,0x9d1e,0x9d14,0x9d29,
122.1960 +    0x9d1d,0x9d18,0x9d22,0x9d10,0x9d19,0x9d1f,0x9e88,0x9e86,0x9e87,0x9eae,
122.1961 +    0x9ead,0x9ed5,0x9ed6,0x9efa,0x9f12,0x9f3d,0x5126,0x5125,0x5122,0x5124,
122.1962 +    0x5120,0x5129,0x52f4,0x5693,0x568c,0x568d,0x5686,0x5684,0x5683,0x567e,
122.1963 +    0x5682,0x567f,0x5681,0x58d6,0x58d4,0x58cf,0x58d2,0x5b2d,0x5b25,0x5b32,
122.1964 +    0x5b23,0x5b2c,0x5b27,0x5b26,0x5b2f,0x5b2e,0x5b7b,0x5bf1,0x5bf2,0x5db7,
122.1965 +    0x5e6c,0x5e6a,0x5fbe,0x61c3,0x61b5,0x61bc,0x61e7,0x61e0,0x61e5,0x61e4,
122.1966 +    0x61e8,0x61de,0x64ef,0x64e9,0x64e3,0x64eb,0x64e4,0x64e8,0x6581,0x6580,
122.1967 +    0x65b6,0x65da,0x66d2,0x6a8d
122.1968 +  },
122.1969 +  {				/* ku 3d */
122.1970 +    0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1,0x6a9e,0x6a87,0x6a93,
122.1971 +    0x6a8e,0x6a95,0x6a83,0x6aa8,0x6aa4,0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85,
122.1972 +    0x6a8c,0x6a92,0x6b5b,0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3,
122.1973 +    0x6fdc,0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8,0x71e1,
122.1974 +    0x71f1,0x71e8,0x71f2,0x71e4,0x71f0,0x71e2,0x7373,0x736e,0x736f,0x7497,
122.1975 +    0x74b2,0x74ab,0x7490,0x74aa,0x74ad,0x74b1,0x74a5,0x74af,0x7510,0x7511,
122.1976 +    0x7512,0x750f,0x7584,0x7643,0x7648,0x7649,0x7647,0x76a4,0x76e9,0x77b5,
122.1977 +    0x77ab,0x77b2,0x77b7,0x77b6,0x77b4,0x77b1,0x77a8,0x77f0,0x78f3,0x78fd,
122.1978 +    0x7902,0x78fb,0x78fc,0x78ff,0x78f2,0x7905,0x78f9,0x78fe,0x7904,0x79ab,
122.1979 +    0x79a8,0x7a5c,0x7a5b,0x7a56
122.1980 +  },
122.1981 +  {				/* ku 3e */
122.1982 +    0x7a58,0x7a54,0x7a5a,0x7abe,0x7ac0,0x7ac1,0x7c05,0x7c0f,0x7bf2,0x7c00,
122.1983 +    0x7bff,0x7bfb,0x7c0e,0x7bf4,0x7c0b,0x7bf3,0x7c02,0x7c09,0x7c03,0x7c01,
122.1984 +    0x7bf8,0x7bfd,0x7c06,0x7bf0,0x7bf1,0x7c10,0x7c0a,0x7ce8,0x7e2d,0x7e3c,
122.1985 +    0x7e42,0x7e33,0x9848,0x7e38,0x7e2a,0x7e49,0x7e40,0x7e47,0x7e29,0x7e4c,
122.1986 +    0x7e30,0x7e3b,0x7e36,0x7e44,0x7e3a,0x7f45,0x7f7f,0x7f7e,0x7f7d,0x7ff4,
122.1987 +    0x7ff2,0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7,0x81bc,0x81e9,
122.1988 +    0x825b,0x825a,0x825c,0x8583,0x8580,0x858f,0x85a7,0x8595,0x85a0,0x858b,
122.1989 +    0x85a3,0x857b,0x85a4,0x859a,0x859e,0x8577,0x857c,0x8589,0x85a1,0x857a,
122.1990 +    0x8578,0x8557,0x858e,0x8596,0x8586,0x858d,0x8599,0x859d,0x8581,0x85a2,
122.1991 +    0x8582,0x8588,0x8585,0x8579
122.1992 +  },
122.1993 +  {				/* ku 3f */
122.1994 +    0x8576,0x8598,0x8590,0x859f,0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0,
122.1995 +    0x87ac,0x87b9,0x87b5,0x87bc,0x87ae,0x87c9,0x87c3,0x87c2,0x87cc,0x87b7,
122.1996 +    0x87af,0x87c4,0x87ca,0x87b4,0x87b6,0x87bf,0x87b8,0x87bd,0x87de,0x87b2,
122.1997 +    0x8935,0x8933,0x893c,0x893e,0x8941,0x8952,0x8937,0x8942,0x89ad,0x89af,
122.1998 +    0x89ae,0x89f2,0x89f3,0x8b1e,0x8b18,0x8b16,0x8b11,0x8b05,0x8b0b,0x8b22,
122.1999 +    0x8b0f,0x8b12,0x8b15,0x8b07,0x8b0d,0x8b08,0x8b06,0x8b1c,0x8b13,0x8b1a,
122.2000 +    0x8c4f,0x8c70,0x8c72,0x8c71,0x8c6f,0x8c95,0x8c94,0x8cf9,0x8d6f,0x8e4e,
122.2001 +    0x8e4d,0x8e53,0x8e50,0x8e4c,0x8e47,0x8f43,0x8f40,0x9085,0x907e,0x9138,
122.2002 +    0x919a,0x91a2,0x919b,0x9199,0x919f,0x91a1,0x919d,0x91a0,0x93a1,0x9383,
122.2003 +    0x93af,0x9364,0x9356,0x9347
122.2004 +  },
122.2005 +  {				/* ku 40 */
122.2006 +    0x937c,0x9358,0x935c,0x9376,0x9349,0x9350,0x9351,0x9360,0x936d,0x938f,
122.2007 +    0x934c,0x936a,0x9379,0x9357,0x9355,0x9352,0x934f,0x9371,0x9377,0x937b,
122.2008 +    0x9361,0x935e,0x9363,0x9367,0x934e,0x9359,0x95c7,0x95c0,0x95c9,0x95c3,
122.2009 +    0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f,0x9718,0x971d,0x9719,
122.2010 +    0x979a,0x97a1,0x979c,0x979e,0x979d,0x97d5,0x97d4,0x97f1,0x9841,0x9844,
122.2011 +    0x984a,0x9849,0x9845,0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932,
122.2012 +    0x992f,0x992d,0x9931,0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa,0x99f4,
122.2013 +    0x99f7,0x99f9,0x99f8,0x99f6,0x99fb,0x99fd,0x99fe,0x99fc,0x9a03,0x9abe,
122.2014 +    0x9afe,0x9afd,0x9b01,0x9afc,0x9b48,0x9b9a,0x9ba8,0x9b9e,0x9b9b,0x9ba6,
122.2015 +    0x9ba1,0x9ba5,0x9ba4,0x9b86
122.2016 +  },
122.2017 +  {				/* ku 41 */
122.2018 +    0x9ba2,0x9ba0,0x9baf,0x9d33,0x9d41,0x9d67,0x9d36,0x9d2e,0x9d2f,0x9d31,
122.2019 +    0x9d38,0x9d30,0x9d45,0x9d42,0x9d43,0x9d3e,0x9d37,0x9d40,0x9d3d,0x7ff5,
122.2020 +    0x9d2d,0x9e8a,0x9e89,0x9e8d,0x9eb0,0x9ec8,0x9eda,0x9efb,0x9eff,0x9f24,
122.2021 +    0x9f23,0x9f22,0x9f54,0x9fa0,0x5131,0x512d,0x512e,0x5698,0x569c,0x5697,
122.2022 +    0x569a,0x569d,0x5699,0x5970,0x5b3c,0x5c69,0x5c6a,0x5dc0,0x5e6d,0x5e6e,
122.2023 +    0x61d8,0x61df,0x61ed,0x61ee,0x61f1,0x61ea,0x61f0,0x61eb,0x61d6,0x61e9,
122.2024 +    0x64ff,0x6504,0x64fd,0x64f8,0x6501,0x6503,0x64fc,0x6594,0x65db,0x66da,
122.2025 +    0x66db,0x66d8,0x6ac5,0x6ab9,0x6abd,0x6ae1,0x6ac6,0x6aba,0x6ab6,0x6ab7,
122.2026 +    0x6ac7,0x6ab4,0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007,0x700c,0x700d,0x7001,
122.2027 +    0x7005,0x7014,0x700e,0x6fff
122.2028 +  },
122.2029 +  {				/* ku 42 */
122.2030 +    0x7000,0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff,0x71f9,0x7203,
122.2031 +    0x71fd,0x7376,0x74b8,0x74c0,0x74b5,0x74c1,0x74be,0x74b6,0x74bb,0x74c2,
122.2032 +    0x7514,0x7513,0x765c,0x7664,0x7659,0x7650,0x7653,0x7657,0x765a,0x76a6,
122.2033 +    0x76bd,0x76ec,0x77c2,0x77ba,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912,
122.2034 +    0x7911,0x79ad,0x79ac,0x7a5f,0x7c1c,0x7c29,0x7c19,0x7c20,0x7c1f,0x7c2d,
122.2035 +    0x7c1d,0x7c26,0x7c28,0x7c22,0x7c25,0x7c30,0x7e5c,0x7e50,0x7e56,0x7e63,
122.2036 +    0x7e58,0x7e62,0x7e5f,0x7e51,0x7e60,0x7e57,0x7e53,0x7fb5,0x7fb3,0x7ff7,
122.2037 +    0x7ff8,0x8075,0x81d1,0x81d2,0x81d0,0x825f,0x825e,0x85b4,0x85c6,0x85c0,
122.2038 +    0x85c3,0x85c2,0x85b3,0x85b5,0x85bd,0x85c7,0x85c4,0x85bf,0x85cb,0x85ce,
122.2039 +    0x85c8,0x85c5,0x85b1,0x85b6
122.2040 +  },
122.2041 +  {				/* ku 43 */
122.2042 +    0x85d2,0x8624,0x85b8,0x85b7,0x85be,0x8669,0x87e7,0x87e6,0x87e2,0x87db,
122.2043 +    0x87eb,0x87ea,0x87e5,0x87df,0x87f3,0x87e4,0x87d4,0x87dc,0x87d3,0x87ed,
122.2044 +    0x87d8,0x87e3,0x87d7,0x87d9,0x8801,0x87f4,0x87e8,0x87dd,0x8953,0x894b,
122.2045 +    0x894f,0x894c,0x8946,0x8950,0x8951,0x8949,0x8b2a,0x8b27,0x8b23,0x8b33,
122.2046 +    0x8b30,0x8b35,0x8b47,0x8b2f,0x8b3c,0x8b3e,0x8b31,0x8b25,0x8b37,0x8b26,
122.2047 +    0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42,0x8c75,0x8c99,0x8c98,
122.2048 +    0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00,0x8e5c,0x8e62,0x8e60,0x8e57,0x8e56,
122.2049 +    0x8e5e,0x8e65,0x8e67,0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46,
122.2050 +    0x8f47,0x8f48,0x8f4b,0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5,0x91a7,
122.2051 +    0x91af,0x91aa,0x93b5,0x938c
122.2052 +  },
122.2053 +  {				/* ku 44 */
122.2054 +    0x9392,0x93b7,0x939b,0x939d,0x9389,0x93a7,0x938e,0x93aa,0x939e,0x93a6,
122.2055 +    0x9395,0x9388,0x9399,0x939f,0x9380,0x938d,0x93b1,0x9391,0x93b2,0x93a4,
122.2056 +    0x93a8,0x93b4,0x93a3,0x95d2,0x95d3,0x95d1,0x96b3,0x96d7,0x96da,0x5dc2,
122.2057 +    0x96df,0x96d8,0x96dd,0x9723,0x9722,0x9725,0x97ac,0x97ae,0x97a8,0x97ab,
122.2058 +    0x97a4,0x97aa,0x97a2,0x97a5,0x97d7,0x97d9,0x97d6,0x97d8,0x97fa,0x9850,
122.2059 +    0x9851,0x9852,0x98b8,0x9941,0x993c,0x993a,0x9a0f,0x9a0b,0x9a09,0x9a0d,
122.2060 +    0x9a04,0x9a11,0x9a0a,0x9a05,0x9a07,0x9a06,0x9ac0,0x9adc,0x9b08,0x9b04,
122.2061 +    0x9b05,0x9b29,0x9b35,0x9b4a,0x9b4c,0x9b4b,0x9bc7,0x9bc6,0x9bc3,0x9bbf,
122.2062 +    0x9bc1,0x9bb5,0x9bb8,0x9bd3,0x9bb6,0x9bc4,0x9bb9,0x9bbd,0x9d5c,0x9d53,
122.2063 +    0x9d4f,0x9d4a,0x9d5b,0x9d4b
122.2064 +  },
122.2065 +  {				/* ku 45 */
122.2066 +    0x9d59,0x9d56,0x9d4c,0x9d57,0x9d52,0x9d54,0x9d5f,0x9d58,0x9d5a,0x9e8e,
122.2067 +    0x9e8c,0x9edf,0x9f01,0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a,0x9f29,0x9f28,
122.2068 +    0x9f4c,0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab,0x56ad,0x56a6,
122.2069 +    0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912,0x5b3d,0x5b3e,0x5b3f,
122.2070 +    0x5dc3,0x5e70,0x5fbf,0x61fb,0x6507,0x6510,0x650d,0x6509,0x650c,0x650e,
122.2071 +    0x6584,0x65de,0x65dd,0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb,
122.2072 +    0x6adf,0x6adc,0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0,0x6c0c,
122.2073 +    0x7019,0x7027,0x7020,0x7016,0x702b,0x7021,0x7022,0x7023,0x7029,0x7017,
122.2074 +    0x7024,0x701c,0x720c,0x720a,0x7207,0x7202,0x7205,0x72a5,0x72a6,0x72a4,
122.2075 +    0x72a3,0x72a1,0x74cb,0x74c5
122.2076 +  },
122.2077 +  {				/* ku 46 */
122.2078 +    0x74b7,0x74c3,0x7516,0x7660,0x77c9,0x77ca,0x77c4,0x77f1,0x791d,0x791b,
122.2079 +    0x7921,0x791c,0x7917,0x791e,0x79b0,0x7a67,0x7a68,0x7c33,0x7c3c,0x7c39,
122.2080 +    0x7c2c,0x7c3b,0x7cec,0x7cea,0x7e76,0x7e75,0x7e78,0x7e70,0x7e77,0x7e6f,
122.2081 +    0x7e7a,0x7e72,0x7e74,0x7e68,0x7f4b,0x7f4a,0x7f83,0x7f86,0x7fb7,0x7ffd,
122.2082 +    0x7ffe,0x8078,0x81d7,0x81d5,0x820b,0x8264,0x8261,0x8263,0x85eb,0x85f1,
122.2083 +    0x85ed,0x85d9,0x85e1,0x85e8,0x85da,0x85d7,0x85ec,0x85f2,0x85f8,0x85d8,
122.2084 +    0x85df,0x85e3,0x85dc,0x85d1,0x85f0,0x85e6,0x85ef,0x85de,0x85e2,0x8800,
122.2085 +    0x87fa,0x8803,0x87f6,0x87f7,0x8809,0x880c,0x880b,0x8806,0x87fc,0x8808,
122.2086 +    0x87ff,0x880a,0x8802,0x8962,0x895a,0x895b,0x8957,0x8961,0x895c,0x8958,
122.2087 +    0x895d,0x8959,0x8988,0x89b7
122.2088 +  },
122.2089 +  {				/* ku 47 */
122.2090 +    0x89b6,0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53,0x8b56,0x8b54,0x8b4b,
122.2091 +    0x8b55,0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77,0x8c76,0x8c9a,0x8d06,
122.2092 +    0x8d07,0x8d09,0x8dac,0x8daa,0x8dad,0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a,
122.2093 +    0x8e6f,0x8e7b,0x8ec2,0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140,
122.2094 +    0x913f,0x91b0,0x91ad,0x93de,0x93c7,0x93cf,0x93c2,0x93da,0x93d0,0x93f9,
122.2095 +    0x93ec,0x93cc,0x93d9,0x93a9,0x93e6,0x93ca,0x93d4,0x93ee,0x93e3,0x93d5,
122.2096 +    0x93c4,0x93ce,0x93c0,0x93d2,0x93a5,0x93e7,0x957d,0x95da,0x95db,0x96e1,
122.2097 +    0x9729,0x972b,0x972c,0x9728,0x9726,0x97b3,0x97b7,0x97b6,0x97dd,0x97de,
122.2098 +    0x97df,0x985c,0x9859,0x985d,0x9857,0x98bf,0x98bd,0x98bb,0x98be,0x9948,
122.2099 +    0x9947,0x9943,0x99a6,0x99a7
122.2100 +  },
122.2101 +  {				/* ku 48 */
122.2102 +    0x9a1a,0x9a15,0x9a25,0x9a1d,0x9a24,0x9a1b,0x9a22,0x9a20,0x9a27,0x9a23,
122.2103 +    0x9a1e,0x9a1c,0x9a14,0x9ac2,0x9b0b,0x9b0a,0x9b0e,0x9b0c,0x9b37,0x9bea,
122.2104 +    0x9beb,0x9be0,0x9bde,0x9be4,0x9be6,0x9be2,0x9bf0,0x9bd4,0x9bd7,0x9bec,
122.2105 +    0x9bdc,0x9bd9,0x9be5,0x9bd5,0x9be1,0x9bda,0x9d77,0x9d81,0x9d8a,0x9d84,
122.2106 +    0x9d88,0x9d71,0x9d80,0x9d78,0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74,
122.2107 +    0x9d75,0x9d70,0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f,
122.2108 +    0x9d87,0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40,0x9f41,0x9f4d,
122.2109 +    0x9f56,0x9f57,0x9f58,0x5337,0x56b2,0x56b5,0x56b3,0x58e3,0x5b45,0x5dc6,
122.2110 +    0x5dc7,0x5eee,0x5eef,0x5fc0,0x5fc1,0x61f9,0x6517,0x6516,0x6515,0x6513,
122.2111 +    0x65df,0x66e8,0x66e3,0x66e4
122.2112 +  },
122.2113 +  {				/* ku 49 */
122.2114 +    0x6af3,0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1,0x6aee,0x6aef,0x703c,0x7035,
122.2115 +    0x702f,0x7037,0x7034,0x7031,0x7042,0x7038,0x703f,0x703a,0x7039,0x702a,
122.2116 +    0x7040,0x703b,0x7033,0x7041,0x7213,0x7214,0x72a8,0x737d,0x737c,0x74ba,
122.2117 +    0x76ab,0x76aa,0x76be,0x76ed,0x77cc,0x77ce,0x77cf,0x77cd,0x77f2,0x7925,
122.2118 +    0x7923,0x7927,0x7928,0x7924,0x7929,0x79b2,0x7a6e,0x7a6c,0x7a6d,0x7af7,
122.2119 +    0x7c49,0x7c48,0x7c4a,0x7c47,0x7c45,0x7cee,0x7e7b,0x7e7e,0x7e81,0x7e80,
122.2120 +    0x7fba,0x7fff,0x8079,0x81db,0x81d9,0x8268,0x8269,0x8622,0x85ff,0x8601,
122.2121 +    0x85fe,0x861b,0x8600,0x85f6,0x8604,0x8609,0x8605,0x860c,0x85fd,0x8819,
122.2122 +    0x8810,0x8811,0x8817,0x8813,0x8816,0x8963,0x8966,0x89b9,0x89f7,0x8b60,
122.2123 +    0x8b6a,0x8b5d,0x8b68,0x8b63
122.2124 +  },
122.2125 +  {				/* ku 4a */
122.2126 +    0x8b65,0x8b67,0x8b6d,0x8dae,0x8e86,0x8e88,0x8e84,0x8f59,0x8f56,0x8f57,
122.2127 +    0x8f55,0x8f58,0x8f5a,0x908d,0x9143,0x9141,0x91b7,0x91b5,0x91b2,0x91b3,
122.2128 +    0x940b,0x9413,0x93fb,0x9420,0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428,
122.2129 +    0x9419,0x940d,0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa,
122.2130 +    0x9409,0x93f8,0x943c,0x940a,0x93ff,0x93fc,0x940c,0x93f6,0x9411,0x9406,
122.2131 +    0x95de,0x95e0,0x95df,0x972e,0x972f,0x97b9,0x97bb,0x97fd,0x97fe,0x9860,
122.2132 +    0x9862,0x9863,0x985f,0x98c1,0x98c2,0x9950,0x994e,0x9959,0x994c,0x994b,
122.2133 +    0x9953,0x9a32,0x9a34,0x9a31,0x9a2c,0x9a2a,0x9a36,0x9a29,0x9a2e,0x9a38,
122.2134 +    0x9a2d,0x9ac7,0x9aca,0x9ac6,0x9b10,0x9b12,0x9b11,0x9c0b,0x9c08,0x9bf7,
122.2135 +    0x9c05,0x9c12,0x9bf8,0x9c40
122.2136 +  },
122.2137 +  {				/* ku 4b */
122.2138 +    0x9c07,0x9c0e,0x9c06,0x9c17,0x9c14,0x9c09,0x9d9f,0x9d99,0x9da4,0x9d9d,
122.2139 +    0x9d92,0x9d98,0x9d90,0x9d9b,0x9da0,0x9d94,0x9d9c,0x9daa,0x9d97,0x9da1,
122.2140 +    0x9d9a,0x9da2,0x9da8,0x9d9e,0x9da3,0x9dbf,0x9da9,0x9d96,0x9da6,0x9da7,
122.2141 +    0x9e99,0x9e9b,0x9e9a,0x9ee5,0x9ee4,0x9ee7,0x9ee6,0x9f30,0x9f2e,0x9f5b,
122.2142 +    0x9f60,0x9f5e,0x9f5d,0x9f59,0x9f91,0x513a,0x5139,0x5298,0x5297,0x56c3,
122.2143 +    0x56bd,0x56be,0x5b48,0x5b47,0x5dcb,0x5dcf,0x5ef1,0x61fd,0x651b,0x6b02,
122.2144 +    0x6afc,0x6b03,0x6af8,0x6b00,0x7043,0x7044,0x704a,0x7048,0x7049,0x7045,
122.2145 +    0x7046,0x721d,0x721a,0x7219,0x737e,0x7517,0x766a,0x77d0,0x792d,0x7931,
122.2146 +    0x792f,0x7c54,0x7c53,0x7cf2,0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d,
122.2147 +    0x7f4d,0x7fbb,0x8030,0x81dd
122.2148 +  },
122.2149 +  {				/* ku 4c */
122.2150 +    0x8618,0x862a,0x8626,0x861f,0x8623,0x861c,0x8619,0x8627,0x862e,0x8621,
122.2151 +    0x8620,0x8629,0x861e,0x8625,0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,
122.2152 +    0x882b,0x884a,0x896d,0x8969,0x896e,0x896b,0x89fa,0x8b79,0x8b78,0x8b45,
122.2153 +    0x8b7a,0x8b7b,0x8d10,0x8d14,0x8daf,0x8e8e,0x8e8c,0x8f5e,0x8f5b,0x8f5d,
122.2154 +    0x9146,0x9144,0x9145,0x91b9,0x943f,0x943b,0x9436,0x9429,0x943d,0x9430,
122.2155 +    0x9439,0x942a,0x9437,0x942c,0x9440,0x9431,0x95e5,0x95e4,0x95e3,0x9735,
122.2156 +    0x973a,0x97bf,0x97e1,0x9864,0x98c9,0x98c6,0x98c0,0x9958,0x9956,0x9a39,
122.2157 +    0x9a3d,0x9a46,0x9a44,0x9a42,0x9a41,0x9a3a,0x9a3f,0x9acd,0x9b15,0x9b17,
122.2158 +    0x9b18,0x9b16,0x9b3a,0x9b52,0x9c2b,0x9c1d,0x9c1c,0x9c2c,0x9c23,0x9c28,
122.2159 +    0x9c29,0x9c24,0x9c21,0x9db7
122.2160 +  },
122.2161 +  {				/* ku 4d */
122.2162 +    0x9db6,0x9dbc,0x9dc1,0x9dc7,0x9dca,0x9dcf,0x9dbe,0x9dc5,0x9dc3,0x9dbb,
122.2163 +    0x9db5,0x9dce,0x9db9,0x9dba,0x9dac,0x9dc8,0x9db1,0x9dad,0x9dcc,0x9db3,
122.2164 +    0x9dcd,0x9db2,0x9e7a,0x9e9c,0x9eeb,0x9eee,0x9eed,0x9f1b,0x9f18,0x9f1a,
122.2165 +    0x9f31,0x9f4e,0x9f65,0x9f64,0x9f92,0x4eb9,0x56c6,0x56c5,0x56cb,0x5971,
122.2166 +    0x5b4b,0x5b4c,0x5dd5,0x5dd1,0x5ef2,0x6521,0x6520,0x6526,0x6522,0x6b0b,
122.2167 +    0x6b08,0x6b09,0x6c0d,0x7055,0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9,
122.2168 +    0x737f,0x74d8,0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70,
122.2169 +    0x7a71,0x7c57,0x7c5c,0x7c59,0x7c5b,0x7c5a,0x7cf4,0x7cf1,0x7e91,0x7f4f,
122.2170 +    0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633,0x862c,0x8632,0x8636,0x882c,
122.2171 +    0x8828,0x8826,0x882a,0x8825
122.2172 +  },
122.2173 +  {				/* ku 4e */
122.2174 +    0x8971,0x89bf,0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86,0x8b85,0x8b7f,
122.2175 +    0x8d15,0x8e95,0x8e94,0x8e9a,0x8e92,0x8e90,0x8e96,0x8e97,0x8f60,0x8f62,
122.2176 +    0x9147,0x944c,0x9450,0x944a,0x944b,0x944f,0x9447,0x9445,0x9448,0x9449,
122.2177 +    0x9446,0x973f,0x97e3,0x986a,0x9869,0x98cb,0x9954,0x995b,0x9a4e,0x9a53,
122.2178 +    0x9a54,0x9a4c,0x9a4f,0x9a48,0x9a4a,0x9a49,0x9a52,0x9a50,0x9ad0,0x9b19,
122.2179 +    0x9b2b,0x9b3b,0x9b56,0x9b55,0x9c46,0x9c48,0x9c3f,0x9c44,0x9c39,0x9c33,
122.2180 +    0x9c41,0x9c3c,0x9c37,0x9c34,0x9c32,0x9c3d,0x9c36,0x9ddb,0x9dd2,0x9dde,
122.2181 +    0x9dda,0x9dcb,0x9dd0,0x9ddc,0x9dd1,0x9ddf,0x9de9,0x9dd9,0x9dd8,0x9dd6,
122.2182 +    0x9df5,0x9dd5,0x9ddd,0x9eb6,0x9ef0,0x9f35,0x9f33,0x9f32,0x9f42,0x9f6b,
122.2183 +    0x9f95,0x9fa2,0x513d,0x5299
122.2184 +  },
122.2185 +  {				/* ku 4f */
122.2186 +    0x58e8,0x58e7,0x5972,0x5b4d,0x5dd8,0x882f,0x5f4f,0x6201,0x6203,0x6204,
122.2187 +    0x6529,0x6525,0x6596,0x66eb,0x6b11,0x6b12,0x6b0f,0x6bca,0x705b,0x705a,
122.2188 +    0x7222,0x7382,0x7381,0x7383,0x7670,0x77d4,0x7c67,0x7c66,0x7e95,0x826c,
122.2189 +    0x863a,0x8640,0x8639,0x863c,0x8631,0x863b,0x863e,0x8830,0x8832,0x882e,
122.2190 +    0x8833,0x8976,0x8974,0x8973,0x89fe,0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45,
122.2191 +    0x8d19,0x8e98,0x8f64,0x8f63,0x91bc,0x9462,0x9455,0x945d,0x9457,0x945e,
122.2192 +    0x97c4,0x97c5,0x9800,0x9a56,0x9a59,0x9b1e,0x9b1f,0x9b20,0x9c52,0x9c58,
122.2193 +    0x9c50,0x9c4a,0x9c4d,0x9c4b,0x9c55,0x9c59,0x9c4c,0x9c4e,0x9dfb,0x9df7,
122.2194 +    0x9def,0x9de3,0x9deb,0x9df8,0x9de4,0x9df6,0x9de1,0x9dee,0x9de6,0x9df2,
122.2195 +    0x9df0,0x9de2,0x9dec,0x9df4
122.2196 +  },
122.2197 +  {				/* ku 50 */
122.2198 +    0x9df3,0x9de8,0x9ded,0x9ec2,0x9ed0,0x9ef2,0x9ef3,0x9f06,0x9f1c,0x9f38,
122.2199 +    0x9f37,0x9f36,0x9f43,0x9f4f,0x9f71,0x9f70,0x9f6e,0x9f6f,0x56d3,0x56cd,
122.2200 +    0x5b4e,0x5c6d,0x652d,0x66ed,0x66ee,0x6b13,0x705f,0x7061,0x705d,0x7060,
122.2201 +    0x7223,0x74db,0x74e5,0x77d5,0x7938,0x79b7,0x79b6,0x7c6a,0x7e97,0x7f89,
122.2202 +    0x826d,0x8643,0x8838,0x8837,0x8835,0x884b,0x8b94,0x8b95,0x8e9e,0x8e9f,
122.2203 +    0x8ea0,0x8e9d,0x91be,0x91bd,0x91c2,0x946b,0x9468,0x9469,0x96e5,0x9746,
122.2204 +    0x9743,0x9747,0x97c7,0x97e5,0x9a5e,0x9ad5,0x9b59,0x9c63,0x9c67,0x9c66,
122.2205 +    0x9c62,0x9c5e,0x9c60,0x9e02,0x9dfe,0x9e07,0x9e03,0x9e06,0x9e05,0x9e00,
122.2206 +    0x9e01,0x9e09,0x9dff,0x9dfd,0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75,
122.2207 +    0x9f76,0x56d4,0x652e,0x65b8
122.2208 +  },
122.2209 +  {				/* ku 51 */
122.2210 +    0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226,0x72aa,0x77d8,0x77d9,0x7939,
122.2211 +    0x7c69,0x7c6b,0x7cf6,0x7e9a,0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646,
122.2212 +    0x8647,0x8648,0x8979,0x897a,0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5,
122.2213 +    0x8ea4,0x8ea3,0x946e,0x946d,0x946f,0x9471,0x9473,0x9749,0x9872,0x995f,
122.2214 +    0x9c68,0x9c6e,0x9c6d,0x9e0b,0x9e0d,0x9e10,0x9e0f,0x9e12,0x9e11,0x9ea1,
122.2215 +    0x9ef5,0x9f09,0x9f47,0x9f78,0x9f7b,0x9f7a,0x9f79,0x571e,0x7066,0x7c6f,
122.2216 +    0x883c,0x8db2,0x8ea6,0x91c3,0x9474,0x9478,0x9476,0x9475,0x9a60,0x9b2e,
122.2217 +    0x9c74,0x9c73,0x9c71,0x9c75,0x9e14,0x9e13,0x9ef6,0x9f0a,0x9fa4,0x7068,
122.2218 +    0x7065,0x7cf7,0x866a,0x883e,0x883d,0x883f,0x8b9e,0x8c9c,0x8ea9,0x8ec9,
122.2219 +    0x974b,0x9873,0x9874,0x98cc
122.2220 +  },
122.2221 +  {				/* ku 52 */
122.2222 +    0x9961,0x99ab,0x9a64,0x9a66,0x9a67,0x9b24,0x9e15,0x9e17,0x9f48,0x6207,
122.2223 +    0x6b1e,0x7227,0x864c,0x8ea8,0x9482,0x9480,0x9481,0x9a69,0x9a68,0x9e19,
122.2224 +    0x864b,0x8b9f,0x9483,0x9c79,0x9eb7,0x7675,0x9a6b,0x9c7a,0x9e1d,0x7069,
122.2225 +    0x706a,0x7229,0x9ea4,0x9f7e,0x9f49,0x9f98,UBOGON,UBOGON,UBOGON,UBOGON,
122.2226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.2227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.2228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.2229 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.2230 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.2231 +    UBOGON,UBOGON,UBOGON,UBOGON
122.2232 +  }
122.2233 +};
122.2234 +
122.2235 +#if CNS_EXTENDED
122.2236 +/* CNS 11643 plane 3 conversion table */
122.2237 +
122.2238 +static const unsigned short
122.2239 + cns11643_3tab[MAX_CNS11643_KU_3][MAX_CNS11643_TEN] = {
122.2240 +  {				/* ku 01 */
122.2241 +    0x4e28,0x4e36,0x4e3f,0x4e85,0x4e05,0x4e04,0x5182,0x5196,0x5338,0x5369,
122.2242 +    0x53b6,0x4e2a,0x4e87,0x4e49,0x51e2,0x4e46,0x4e8f,0x4ebc,0x4ebe,0x5166,
122.2243 +    0x51e3,0x5204,0x529c,0x5344,0x5902,0x590a,0x5b80,0x5ddb,0x5e7a,0x5e7f,
122.2244 +    0x5ef4,0x5f50,0x5f51,0x5f61,0x961d,UBOGON,0x4e63,0x4e62,0x4ea3,0x5185,
122.2245 +    0x4ec5,0x4ecf,0x4ece,0x4ecc,0x5184,0x5186,UBOGON,0x34c5,0x51e4,0x5205,
122.2246 +    0x529e,0x529d,0x52fd,0x5300,0x533a,0x3539,0x5346,0x535d,0x5386,0x53b7,
122.2247 +    0x3555,0x53cc,0x355b,0x53ce,0x5721,0x37a2,0x5e00,0x5f0c,0x6237,0x6238,
122.2248 +    0x6534,0x6535,0x65e0,0x3e26,0x738d,0x4e97,0x4ee0,0x3432,UBOGON,0x4ee7,
122.2249 +    0x3433,0x4ee6,0x3434,0x36a2,0x3431,0x34b0,0x56d8,0x518b,0x518c,0x5199,
122.2250 +    0x51e5,UBOGON,0x520b,0x34dc
122.2251 +  },
122.2252 +  {				/* ku 02 */
122.2253 +    0x361e,0x5304,0x5303,0x5307,UBOGON,0x531e,0x535f,0x536d,0x5389,0x53ba,
122.2254 +    0x53d0,0x3565,0x53f6,0x53f7,0x53f9,0x3564,0x53f4,0x361d,0x3626,0x5724,
122.2255 +    0x5904,0x5918,0x5932,0x5930,0x5934,0x368e,0x5975,0x374a,0x5b82,0x5bf9,
122.2256 +    0x5c14,0x378b,0x37a6,0x37a4,0x37a5,0x37a7,0x382f,0x3832,0x5e81,0x5e83,
122.2257 +    0x5f0d,0x5f52,0x38d4,0x5fca,0x5fc7,0x6239,0x39c5,0x624f,0x65e7,0x672f,
122.2258 +    0x6b7a,0x6c39,0x3cba,0x3cb9,0x6c37,0x6c44,0x6c45,0x738c,0x7592,0x7676,
122.2259 +    0x9093,0x9092,0x48b3,0x49ba,0x4e21,0x4e20,0x4e22,0x4e68,0x4e89,0x4e98,
122.2260 +    0x4ef9,0x4eef,0x343b,0x343c,0x4ef8,0x4f06,0x4f03,0x4efc,0x4eee,0x4f16,
122.2261 +    0x3439,0x4f28,0x4f1c,0x4f07,0x4f1a,0x4efa,0x4f17,0x514a,0x34b2,0x5172,
122.2262 +    UBOGON,0x51b4,0x51b3,0x51b2
122.2263 +  },
122.2264 +  {				/* ku 03 */
122.2265 +    0x34c7,0x51e8,0x342b,0x5214,0x520f,0x5215,0x5218,0x52a8,UBOGON,0x534b,
122.2266 +    0x534f,0x353b,0x5350,0x3544,0x538b,0x3542,0x53be,0x355c,0x53d2,0x5416,
122.2267 +    0x53ff,0x3567,0x5400,0x3566,0x5405,0x5413,0x5415,UBOGON,0x361f,0x56e3,
122.2268 +    0x5735,0x5736,0x5731,0x5732,0x58ee,0x5905,0x4e54,0x368f,0x5936,0x3690,
122.2269 +    0x36a8,0x36a4,0x597a,0x36a3,0x5986,0x373d,0x374c,0x5b86,0x5f53,0x5c18,
122.2270 +    0x378c,0x5c3d,0x5c78,0x37a8,0x37ad,0x37af,UBOGON,0x5c80,0x3829,0x5e08,
122.2271 +    0x3836,0x3871,0x3870,0x386f,0x5ef5,0x5f0e,0x38a9,0x38aa,0x38fb,0x5fd3,
122.2272 +    0x5fda,0x38fc,0x5fdb,0x39ae,0x620f,0x625d,0x625f,0x6267,0x6257,0x9f50,
122.2273 +    0x3ac3,0x65eb,0x65ea,0x3b30,0x6737,0x3b41,0x6732,0x6736,0x6b22,0x6bce,
122.2274 +    0x3c8c,0x6c58,0x6c51,0x6c77
122.2275 +  },
122.2276 +  {				/* ku 04 */
122.2277 +    0x6c3c,0x3cbb,0x6c5a,UBOGON,0x6c53,0x706f,0x7072,0x706e,UBOGON,0x3da1,
122.2278 +    0x7073,0x72b1,0x72b2,0x3ea8,0x738f,0x3eaa,0x3eab,0x4096,0x793c,0x41c2,
122.2279 +    0x808d,0x808e,0x4493,0x827b,0x4494,0x8d71,0x8fb9,0x9096,0x909a,0x49bb,
122.2280 +    0x4e24,0x4e71,UBOGON,0x4e9c,0x4f45,0x4f4a,0x4f39,0x4f37,0x3443,0x4f32,
122.2281 +    0x4f42,0x3442,0x4f44,0x4f4b,0x3444,0x4f40,0x4f35,0x4f31,0x5151,UBOGON,
122.2282 +    0x5150,0x514e,0x34b3,0x34b7,0x519d,0x34c8,0x51b5,0x51b8,0x51ec,0x5223,
122.2283 +    0x5227,0x5226,0x521f,0x522b,0x5220,0x52b4,0x52b3,0x3518,0x5325,0x533b,
122.2284 +    0x5374,0x3547,0x3546,0x3545,0x356b,0x3569,0x544d,0x3572,0x3571,0x543a,
122.2285 +    0x356c,0x356f,0x5444,0x544c,0x5423,0x541a,0x5432,0x544b,0x5421,0x3573,
122.2286 +    0x5434,0x5449,0x5450,0x5422
122.2287 +  },
122.2288 +  {				/* ku 05 */
122.2289 +    0x543f,0x5451,0x545a,0x542f,0x3576,0x56e9,0x56f2,0x56f3,0x56ef,0x56ed,
122.2290 +    0x56ec,0x56e6,0x5748,0x3627,0x5744,0x573f,0x573c,0x5753,0x5756,0x3630,
122.2291 +    0x575f,0x5743,0x5758,0x5757,0x3629,0x362a,0x362f,0x5746,0x362c,0x573d,
122.2292 +    0x362d,0x5742,0x5754,0x5755,0x58f1,0x58f2,0x58f0,0x590b,0x9ea6,0x56f1,
122.2293 +    0x593d,0x3693,0x5994,0x598c,0x36ad,0x599c,0x36ac,0x36ab,0x599f,0x36a9,
122.2294 +    0x599b,0x36ae,0x5989,0x599a,0x36aa,0x6588,0x374e,0x5b8d,0x3750,0x5bfe,
122.2295 +    0x5bff,0x5bfd,0x5c2b,0x37b2,0x5c84,0x5c8e,0x5c9c,0x37b5,0x37b6,0x5c85,
122.2296 +    0x5df5,0x5e09,0x3839,0x383b,0x5e0b,0x3872,0x5e92,0x5e90,0x5f03,0x38ac,
122.2297 +    0x5f1e,0x5f63,0x3908,0x5fe7,0x5ffe,0x5fe6,0x5fdc,0x5fce,0x3903,0x5ffc,
122.2298 +    0x5fdf,0x5fec,0x5ff6,UBOGON
122.2299 +  },
122.2300 +  {				/* ku 06 */
122.2301 +    0x5ff2,0x5ff0,0x5ff9,0x390b,0x6213,0x39af,UBOGON,0x623b,0x623c,0x6282,
122.2302 +    0x39ce,0x39cb,0x39cc,0x6278,0x628b,0x39cd,0x629e,0x62a5,0x629b,0x629c,
122.2303 +    0x6299,0x628d,0x6285,0x629d,0x6275,0x3a80,0x3aaf,0x3ad3,0x65f6,0x3ad5,
122.2304 +    0x3ad4,0x3ad7,0x66f5,0x675b,0x3b42,0x6754,0x6752,0x3b44,0x6758,0x6744,
122.2305 +    0x674a,0x6761,0x3cc6,0x6c7f,0x6c91,0x6c9e,0x3cc0,0x6c6e,0x6c7c,0x6c9f,
122.2306 +    0x6c75,0x3cbe,0x6c56,0x6ca2,0x6c79,0x3cca,0x6ca1,0x3cc4,0x6caa,0x6ca0,
122.2307 +    0x3cc2,0x7079,0x7077,0x707e,0x3da4,0x7075,0x707b,0x7264,0x3e29,0x72bb,
122.2308 +    0x72bc,0x72c7,0x72b9,0x72be,0x72b6,0x3e60,0x3e5e,0x7398,0x3ead,0x3eae,
122.2309 +    0x3eac,0x3f57,0x7593,0x7680,0x3fdd,0x7683,0x76c0,0x76c1,0x400e,0x4097,
122.2310 +    0x77f4,0x77f5,0x4127,0x7acc
122.2311 +  },
122.2312 +  {				/* ku 07 */
122.2313 +    0x7acd,0x7cfa,0x809f,0x8091,0x8097,0x8094,0x4495,0x8286,0x828c,UBOGON,
122.2314 +    0x8295,0x4498,0x866c,0x459d,0x8fb5,0x8fbe,0x8fc7,0x488a,0x8fc1,0x90a9,
122.2315 +    0x90a4,0x48b5,0x48b6,0x48b7,0x90a8,0x9627,0x9626,0x962b,0x9633,0x9634,
122.2316 +    0x9629,0x4e3d,0x3428,0x4e9d,0x4f93,0x4f8a,0x344d,0x3449,0x4f6d,0x4f8e,
122.2317 +    0x4fa0,0x4fa2,0x4fa1,0x4f9f,0x4fa3,UBOGON,0x4f72,0x3451,0x4f8c,0x5156,
122.2318 +    UBOGON,UBOGON,0x5190,0x34cb,0x34ca,0x34cc,0x51ed,0x51fe,0x522f,UBOGON,
122.2319 +    0x523c,0x5234,0x5239,0x52b9,0x52b5,0x52bf,0x5355,0x353d,0x5376,0x537a,
122.2320 +    0x5393,0x3548,0x53c1,0x53c2,0x53d5,0x5485,0x3578,0x545f,0x5493,0x5489,
122.2321 +    0x5479,0x9efe,0x548f,0x5469,0x546d,0x357a,0x5494,0x546a,0x548a,0x3577,
122.2322 +    0x56fd,0x56fb,0x56f8,0x3621
122.2323 +  },
122.2324 +  {				/* ku 08 */
122.2325 +    0x56fc,0x56f6,0x5765,0x5781,0x5763,0x5767,0x3631,0x576e,0x5778,0x577f,
122.2326 +    0x3633,0x3634,0x58f3,0x594b,0x594c,0x36c1,0x36b0,0x36b4,0x59ad,0x36b8,
122.2327 +    0x59c4,0x36bc,0x59c2,0x59b0,0x36bf,0x36b5,0x36b1,0x36bd,0x59bf,0x36bb,
122.2328 +    0x59c9,0x59b8,0x59ac,0x36b3,0x36b6,0x36ba,0x59b7,0x59d7,0x36b7,0x5b60,
122.2329 +    0x3740,0x5b96,0x5b9e,0x5b94,0x5b9f,0x5b9d,0x3752,0x5c00,0x5c19,0x3790,
122.2330 +    0x3791,0x5c49,0x5c4a,0x37be,0x5cbb,0x5cc1,0x37c0,0x37c1,0x37b9,0x5cb9,
122.2331 +    0x5c9e,0x5cb4,0x5cba,0x5df6,0x5e13,0x5e12,0x5e77,0x3879,0x5e98,0x387b,
122.2332 +    0x5e99,0x5e9d,0x5ef8,0x38a0,0x5ef9,0x3429,0x5f06,0x5f21,0x38ae,0x5f25,
122.2333 +    0x5f55,0x38cd,0x38cb,0x38d9,0x5f84,0x5f83,0x6030,0x6007,0x390c,0x6036,
122.2334 +    0x3901,0x3905,0x3902,0x5fe9
122.2335 +  },
122.2336 +  {				/* ku 09 */
122.2337 +    0x603d,0x6008,0x3913,0x3911,0x62ba,0x62b2,0x39e4,0x62b7,0x62e4,0x62a7,
122.2338 +    0x39da,0x39d5,0x39d3,0x62d5,0x62e1,0x62dd,0x62a6,0x62c1,0x62c5,0x62c0,
122.2339 +    0x62df,0x62e0,0x62de,0x39d6,0x6589,0x3ab4,0x65a6,0x65ba,0x3ad9,0x65ff,
122.2340 +    0x3ad8,0x6617,0x6618,0x6601,0x65fe,0x3b33,0x670c,0x3b48,0x676b,0x6796,
122.2341 +    0x6782,0x678a,0x3b47,0x67a3,0x3b4b,0x67a2,0x678f,0x3b4a,0x67f9,0x6780,
122.2342 +    0x6b26,0x6b27,0x6b68,0x6b69,0x3c5a,0x6b81,0x6bb4,0x6bd1,0x3c8e,0x3cb4,
122.2343 +    0x6c1c,0x3ccd,0x3ccc,0x3ccf,0x3ccb,0x3cce,0x6c97,0x6c6c,0x6cdf,0x3cd2,
122.2344 +    0x6cea,0x3cd1,0x6ce4,0x6cd8,0x6cb2,0x6cce,0x6cc8,0x3da6,0x708b,0x7088,
122.2345 +    0x7090,0x708f,0x3daa,0x7087,0x7089,0x708d,0x7081,0x3da8,0x708c,0x3e13,
122.2346 +    0x3e1a,0x7240,0x3e1d,0x3e1e
122.2347 +  },
122.2348 +  {				/* ku 0a */
122.2349 +    0x7265,0x7266,0x7268,0x3e65,0x3e66,0x72cd,0x72d3,0x72db,0x3e64,0x72cf,
122.2350 +    0x73a7,0x73a3,0x739e,0x3eb0,0x73af,0x3eb3,0x3eb5,0x73aa,0x739c,0x3f19,
122.2351 +    0x7542,0x7544,0x753b,0x7541,UBOGON,0x759b,0x759e,0x3f75,0x79c4,0x79c3,
122.2352 +    0x79c6,0x412b,0x412c,0x79c7,0x412d,0x79ca,UBOGON,0x41c3,0x7acf,0x7c76,
122.2353 +    0x7c74,0x7cff,0x7cfc,0x34ba,0x4350,0x7f59,0x80a8,0x43d3,0x43d0,0x80b0,
122.2354 +    0x43dc,0x80b3,0x43d2,0x80a4,0x80b6,0x80a7,0x80ac,0x43db,0x80a6,0x5367,
122.2355 +    0x820e,0x82c4,0x833e,0x829c,0x44a5,0x449f,0x449a,0x449c,0x44a2,0x82aa,
122.2356 +    0x449b,0x82c9,0x44a3,0x449d,0x82a6,0x82b2,0x4588,0x461a,0x488d,0x8fcc,
122.2357 +    0x8fd9,0x8fca,0x8fd8,0x8fcf,0x90b7,0x48b8,0x90ad,0x90b9,0x9637,0x49c3,
122.2358 +    0x9641,0x963e,0x96b6,0x9751
122.2359 +  },
122.2360 +  {				/* ku 0b */
122.2361 +    0x9763,0x4e57,0x4e79,0x4eb2,0x4eb0,0x4eaf,0x4eb1,0x4fd2,0x4fd5,0x345d,
122.2362 +    0x4fbe,0x4fb8,0x4fb0,0x4fb1,0x4fc8,0x345a,0x3457,0x4fc6,0x4fcc,0x4fe5,
122.2363 +    0x4fe3,0x4fb4,0x516a,0x34b8,0x519f,0x34c2,0x51c1,0x34cf,0x51c2,0x51c3,
122.2364 +    0x5245,0x5248,0x34e7,0x34e9,0x524f,0x4452,0x34e8,0x52c5,0x52ca,0x52c4,
122.2365 +    0x5327,0x5358,0x537d,0x354a,0x53dd,0x53dc,0x53da,0x53d9,0x54b9,0x3580,
122.2366 +    0x54d0,0x54b4,0x54ca,0x3587,0x54a3,0x54da,0x54a4,0x3584,0x54b2,0x549e,
122.2367 +    0x549f,0x54b5,0x3582,0x3581,0x54cd,0x3583,0x54cc,0x3622,0x5700,0x57ac,
122.2368 +    0x5791,0x578e,0x578d,0x5792,0x57a1,0x5790,0x57a6,0x57a8,0x363b,0x579c,
122.2369 +    0x5796,0x57a7,0x363a,0x3638,0x3639,0x3636,0x58f5,0x3685,0x5909,0x5908,
122.2370 +    0x3c54,0x5952,0x369a,0x36c4
122.2371 +  },
122.2372 +  {				/* ku 0c */
122.2373 +    0x59df,0x36c5,0x59eb,0x59ef,0x59f0,0x59d5,0x5a0d,0x5a04,0x59f9,0x5a02,
122.2374 +    0x59f8,0x59e2,0x59d9,0x59e7,0x5b6a,0x3754,0x3755,0x5bab,0x3756,0x5c1b,
122.2375 +    0x5c2f,0x3796,0x663c,0x3795,0x3794,0x37c4,0x5cd1,0x5cdc,0x5ce6,0x5ce1,
122.2376 +    0x5ccd,UBOGON,0x5ce2,0x5cdd,0x5ce5,0x5dfb,0x5dfa,0x5e1e,0x3844,0x5ea1,
122.2377 +    0x387d,0x387e,0x5efc,0x5efb,0x5f2f,0x38b2,0x38b6,0x5f66,UBOGON,0x38dc,
122.2378 +    0x38df,0x605c,0x3928,0x604e,0x6051,0x3919,0x3910,0x6023,0x6031,0x607c,
122.2379 +    0x6052,0x392c,0x6060,0x604a,0x6061,0x391b,0x6218,0x39c2,0x39ef,0x39e3,
122.2380 +    0x39e5,0x39ea,0x39e6,0x39ee,0x631f,0x6317,0x62ea,0x6321,0x6304,0x6305,
122.2381 +    0x39e8,0x6531,0x6544,0x6540,0x3a85,0x6542,0x65be,0x3ae0,0x6629,0x661b,
122.2382 +    0x3add,0x6623,0x662c,0x661a
122.2383 +  },
122.2384 +  {				/* ku 0d */
122.2385 +    0x6630,0x663b,0x661e,0x6637,0x6638,0x3ae1,0x670e,0x3b51,0x3b55,0x67e8,
122.2386 +    0x67d6,0x3b52,0x67c7,0x67bc,0x6852,0x67bf,0x67d5,0x67fe,0x8363,0x67fb,
122.2387 +    UBOGON,0x67b1,0x6801,0x6805,0x6800,0x67d7,0x409e,0x6b2a,0x6b6b,0x3c52,
122.2388 +    0x3c5e,0x3c60,0x3c5f,0x6be1,0x3c92,0x3cd6,0x6d23,0x6cff,0x6d14,0x6d05,
122.2389 +    0x6d13,0x6d06,0x6d21,0x3cde,0x6d15,0x6caf,0x6cf4,0x6d02,0x6d45,UBOGON,
122.2390 +    0x6d26,0x3cd9,0x6d44,0x3cdd,0x6d24,0x70a5,0x3dac,0x70a3,0x3db0,0x70a2,
122.2391 +    0x70bb,0x70a0,0x70aa,0x3daf,0x3dae,0x70a8,0x70b6,0x70b2,0x70a7,0x3dad,
122.2392 +    0x3dab,0x70b9,0x722e,0x3e16,0x723c,0x3e30,0x726d,0x3e33,0x3e31,0x72e7,
122.2393 +    0x72ed,0x3e6e,0x72ec,0x72e5,0x72e2,0x3eb1,0x73c4,0x73bd,0x73cf,0x73c9,
122.2394 +    0x73c1,0x73d0,0x3eb7,0x73ce
122.2395 +  },
122.2396 +  {				/* ku 0e */
122.2397 +    0x74ed,0x74eb,0x3f1a,0x74ef,0x7549,0x7550,0x7546,0x754a,0x3f59,0x754d,
122.2398 +    0x75a6,0x3f7a,0x3f78,0x3f7b,0x75a8,0x3fde,0x3fec,0x76c7,0x76ff,0x401e,
122.2399 +    0x76fd,0x77e6,0x780a,0x409b,0x7804,0x780b,0x7807,0x409d,0x7815,0x7808,
122.2400 +    0x40fd,0x79d3,0x79d4,0x79d0,0x79d7,0x7a7c,0x4194,0x4193,0x7a7d,0x7a83,
122.2401 +    0x7a82,0x41c6,0x7ad4,0x7ad5,0x7ad3,0x7ad0,0x7ad2,0x7afe,0x7afc,0x7c77,
122.2402 +    0x7c7c,0x7c7b,0x42b8,UBOGON,0x42b7,0x42b9,0x4353,UBOGON,0x4352,0x4351,
122.2403 +    0x7f8f,0x80d3,0x43e3,0x80cb,0x80d2,0x43e2,0x8109,0x80e2,0x80df,0x80c6,
122.2404 +    0x4463,0x8224,0x82f7,0x82d8,0x82dd,0x44aa,0x44a6,0x82f8,0x82fc,0x44a8,
122.2405 +    0x44a9,0x82e9,0x44ab,0x82ee,0x44ac,0x82d0,0x830e,0x82e2,0x830b,0x82fd,
122.2406 +    0x5179,0x8676,0x459e,0x8678
122.2407 +  },
122.2408 +  {				/* ku 0f */
122.2409 +    0x459f,0x45a0,0x8675,0x867d,0x460f,0x8842,0x8866,0x461c,0x898c,0x8a05,
122.2410 +    0x46ae,0x8a06,0x46b0,0x8c9f,0x47d4,0x8ff1,0x8fe7,0x8fe9,0x8fef,0x90c2,
122.2411 +    0x90bc,0x48bb,0x90c6,0x90c0,0x48c1,0x48c2,0x90cd,0x90c9,0x48be,0x90c4,
122.2412 +    0x48e5,0x9581,0x49c6,0x9cec,0x5032,0x4ff9,0x501d,0x4fff,0x5004,0x4ff0,
122.2413 +    0x5003,0x462e,0x5002,0x4ffc,0x4ff2,0x5024,0x5008,0x5036,0x502e,0x3465,
122.2414 +    0x5010,0x5038,0x5039,0x4ffd,0x5056,0x4ffb,0x51a3,0x51a6,0x51a1,0x34d1,
122.2415 +    0x34d0,0x51c7,0x51c9,0x5260,0x5264,0x5259,0x5265,0x5267,0x5257,0x5263,
122.2416 +    0x34ee,0x5253,0x34ef,0x52cf,0x351e,0x52ce,0x52d0,0x52d1,0x52cc,0x354b,
122.2417 +    0x354d,0x3556,0x550d,0x54f4,0x3592,0x5513,0x54ef,0x54f5,0x54f9,0x5502,
122.2418 +    0x5500,0x3593,0x3590,0x5518
122.2419 +  },
122.2420 +  {				/* ku 10 */
122.2421 +    0x54f0,0x54f6,UBOGON,0x3597,0x5519,0x3623,0x5705,0x57c9,0x363f,0x57b7,
122.2422 +    0x57cd,0x3643,0x3642,0x3644,0x57be,0x57bb,0x3645,0x57db,0x57c8,0x57c4,
122.2423 +    0x57c5,0x57d1,0x57ca,0x57c0,0x36d9,0x36de,0x5a21,0x5a2a,0x36cf,0x5a1d,
122.2424 +    0x36cd,0x5a0b,0x36dd,0x36ce,0x36d3,0x36d6,0x5a22,0x36dc,0x36d1,0x5a24,
122.2425 +    0x36d0,0x5a14,0x5a31,0x36d5,0x5a2f,0x5a1a,0x5a12,0x36d4,0x36db,0x5a26,
122.2426 +    UBOGON,0x3743,0x5bbc,0x5bbb,0x5bb7,0x5c05,0x5c06,0x5c52,0x5c53,0x37cd,
122.2427 +    0x37d1,0x5cfa,0x5ceb,0x37ca,0x5cf3,0x5cf5,0x5ce9,0x5cef,0x37d4,0x5e2a,
122.2428 +    0x5e30,0x5e2e,0x5e2c,0x5e2f,0x5eaf,0x5ea9,0x3886,0x5efd,0x5f32,0x5f8e,
122.2429 +    0x5f93,0x5f8f,0x604f,0x6099,0x3933,0x607e,0x3937,0x6074,0x604b,0x6073,
122.2430 +    0x6075,0x392a,0x391f,0x6056
122.2431 +  },
122.2432 +  {				/* ku 11 */
122.2433 +    0x60a9,0x608b,0x60a6,0x3939,0x6093,0x60ae,0x609e,0x60a7,0x6245,0x39f2,
122.2434 +    0x39f8,0x632e,0x39f7,0x6352,0x6330,0x635b,0x39f4,0x6319,0x631b,0x39f1,
122.2435 +    0x6331,0x635d,0x6337,0x6335,0x6353,0x39f5,0x635c,0x633f,0x654b,0x3a87,
122.2436 +    0x4369,0x658b,0x3ab6,0x659a,0x6650,0x6646,0x664e,0x6640,0x3ae9,0x664b,
122.2437 +    0x6648,0x3aeb,0x6660,0x6644,0x664d,0x3b34,0x6837,0x6824,0x3b62,0x3b5c,
122.2438 +    0x681b,0x6836,0x3b60,0x682c,0x6819,0x6856,0x6847,0x683e,0x681e,UBOGON,
122.2439 +    0x6815,0x6822,0x6827,0x6859,0x6858,0x6855,0x6830,0x6823,0x6b2e,0x6b2b,
122.2440 +    0x6b30,0x6b6c,0x3c61,0x6b8b,0x3c7f,0x6be9,0x6bea,0x6be5,0x6d6b,0x3ce5,
122.2441 +    0x3ce6,0x6d73,0x6d57,0x3ce9,0x3cf3,0x6d5d,0x6d56,0x6d8f,0x6d5b,0x6d1c,
122.2442 +    0x6d9a,0x6d9b,0x6d99,0x3cee
122.2443 +  },
122.2444 +  {				/* ku 12 */
122.2445 +    0x6d81,0x6d71,0x3ced,0x3cec,0x6d72,0x6d5c,0x6d96,0x70c4,0x70db,0x70cc,
122.2446 +    0x70d0,0x70e3,0x70df,0x3db3,0x70d6,0x70ee,0x70d5,0x3db5,0x3e27,0x3e35,
122.2447 +    0x3e36,0x727a,0x3e71,0x72f5,0x7302,0x3eb8,0x3ec2,0x73e2,0x73ec,0x73d5,
122.2448 +    0x73f9,0x73df,0x73e6,0x3ec8,0x3ec0,0x3ec1,0x3ec4,0x73e4,0x73e1,0x74f3,
122.2449 +    0x3f1f,0x3f1c,0x3f1d,0x3f4d,0x7556,0x7555,0x7558,0x7557,0x755e,0x75c3,
122.2450 +    0x3f87,0x3f82,0x75b4,0x3f7d,0x75b1,0x3fdf,0x4000,0x76cb,0x76cc,0x772a,
122.2451 +    0x4020,0x7716,0x770f,0x4022,0x4024,0x773f,0x772b,0x770e,0x7724,0x4021,
122.2452 +    0x7721,0x7718,0x77dd,0x40a4,0x40a5,0x7824,0x7836,0x4101,0x7958,0x7959,
122.2453 +    0x4103,0x7962,0x79da,0x79d9,0x4137,0x79e1,0x79e5,0x79e8,0x79db,0x4138,
122.2454 +    0x79e2,0x79f0,0x4199,0x4198
122.2455 +  },
122.2456 +  {				/* ku 13 */
122.2457 +    0x4197,0x41c9,0x7ada,0x7add,0x41c7,0x7adb,0x7adc,0x41d9,0x41db,0x7b0d,
122.2458 +    0x7b0b,0x7b14,0x7c8e,0x7c86,0x427b,0x7c87,0x7c83,0x7c8b,0x427c,0x42bd,
122.2459 +    0x42bc,0x42c3,0x7d24,0x42c1,0x42bf,0x42c4,0x7d25,0x7f62,0x7f93,0x7f99,
122.2460 +    0x7f97,0x437e,0x437f,0x7fc4,0x7fc6,0x800a,0x43b4,0x43b3,0x8040,0x803c,
122.2461 +    0x803b,0x80f6,0x80ff,0x80ee,0x8104,0x8103,0x8107,UBOGON,0x43e6,0x80f7,
122.2462 +    0x4459,0x445a,0x822d,0x4464,0x8227,0x8229,0x831f,0x8357,0x44b4,0x44b9,
122.2463 +    0x44b7,0x44b5,0x8321,0x44c1,0x44b1,0x8318,0x8358,0x44b3,0x44ba,0x458c,
122.2464 +    0x458b,0x458d,0x8684,0x869f,0x869b,0x8689,0x86a6,0x8692,0x868f,0x86a0,
122.2465 +    0x884f,0x8878,0x887a,0x886e,0x887b,0x8884,0x8873,0x4678,0x4677,0x8a0d,
122.2466 +    0x8a0b,0x8a19,0x46b2,0x47d6
122.2467 +  },
122.2468 +  {				/* ku 14 */
122.2469 +    0x8ed0,0x4845,0x4892,0x4895,0x8ff9,0x9009,0x9008,0x48c6,0x90de,0x9151,
122.2470 +    0x48e7,0x48e8,0x91db,0x91df,0x91de,0x91d6,0x91e0,0x9585,0x9660,0x9659,
122.2471 +    0x49cb,0x9656,0x49cd,0x49f1,0x96bd,0x4b22,0x3421,0x5042,0x5059,0x346f,
122.2472 +    0x5044,0x5066,0x5052,0x5054,0x5071,0x5050,0x507b,0x507c,0x5058,0x3470,
122.2473 +    0x3464,0x5079,0x506c,0x5078,0x51a8,0x51d1,0x51cf,0x5268,0x5276,0x52d4,
122.2474 +    0x352d,0x53a0,0x53c4,0x3558,0x5558,0x554c,0x5568,0x35a6,0x5549,0x35a4,
122.2475 +    0x359f,0x555d,0x5529,UBOGON,0x5554,0x5553,0x35a3,0x555a,0x35a0,0x553a,
122.2476 +    0x553f,0x552b,0x57ea,0x364a,0x57ef,0x3647,0x3648,0x57dd,0x57fe,UBOGON,
122.2477 +    0x57de,0x57e6,0x3649,0x57e8,0x57ff,0x5803,0x58f7,0x68a6,0x591f,0x369e,
122.2478 +    0x595b,0x595d,0x595e,UBOGON
122.2479 +  },
122.2480 +  {				/* ku 15 */
122.2481 +    0x36e8,0x5a2b,0x36ec,0x5a3b,0x36ed,0x36e6,0x5a61,0x5a3a,0x5a6e,0x5a4b,
122.2482 +    0x5a6b,0x36eb,0x36e7,0x5a45,0x5a4e,0x5a68,0x5a3d,0x5a71,0x5a3f,0x5a6f,
122.2483 +    0x5a75,0x36e9,0x5a73,0x5a2c,0x5a59,0x5a54,0x5a4f,0x5a63,0x375c,0x375d,
122.2484 +    0x5bc8,0x3760,0x5bc3,0x375b,0x5c5b,0x5c61,0x3799,0x5d21,0x5d0a,0x5d09,
122.2485 +    0x37d8,0x5d2c,0x5d08,0x37da,0x37dd,0x5d2a,0x5d15,0x37e0,0x5d10,0x5d13,
122.2486 +    0x37e5,0x5d2f,0x5d18,0x37d7,0x5de3,0x5e39,0x5e35,0x5e3a,0x5e32,0x384e,
122.2487 +    0x388c,0x3888,UBOGON,0x5ebb,0x5eba,0x5f34,0x5f39,0x38ce,UBOGON,0x38e5,
122.2488 +    0x38e6,0x6098,0x3932,0x60d0,0x3940,0x3947,0x394c,0x60d7,0x60aa,0x3935,
122.2489 +    0x60a1,0x60a4,0x3930,0x60ee,0x3943,0x60e7,0x394d,0x60e8,0x60de,0x39b7,
122.2490 +    0x39f3,0x637e,0x638b,0x3a02
122.2491 +  },
122.2492 +  {				/* ku 16 */
122.2493 +    0x3a0b,0x6379,0x6386,0x6393,0x3a04,0x6373,0x636a,UBOGON,0x636c,0x3a08,
122.2494 +    0x637f,0x39fc,0x63b2,0x63ba,0x39ff,0x3a00,0x6366,0x6374,0x3a8b,0x655a,
122.2495 +    0x3a8d,0x654e,0x654d,0x658d,0x658e,0x65ad,0x3aca,0x65c7,0x65ca,0x3acb,
122.2496 +    0x65c9,UBOGON,0x65e3,0x6657,0x3af3,0x6663,0x6667,0x671a,0x6719,0x6716,
122.2497 +    0x3b36,0x3b6a,0x689e,0x68b6,0x6898,0x6873,0x3b6b,0x689a,0x688e,0x68b7,
122.2498 +    0x68db,0x68a5,0x686c,0x68c1,0x6884,0x3b71,0x3b68,0x6895,0x687a,0x6899,
122.2499 +    0x3b72,0x68b8,0x68b9,0x6870,0x3c2e,0x6b35,0x3c62,0x6b90,0x6bbb,0x6bed,
122.2500 +    0x3c98,0x3cb5,0x3ceb,0x6dc1,0x6dc3,0x6dce,0x3cfb,0x3cf8,0x6dad,0x6e04,
122.2501 +    0x3cf5,0x6db9,0x3d08,0x6de7,UBOGON,0x6e08,0x6e06,0x3d0a,0x6e0a,0x6db0,
122.2502 +    0x3d06,0x6df8,0x6e0c,0x3cfd
122.2503 +  },
122.2504 +  {				/* ku 17 */
122.2505 +    0x6db1,0x3cfa,0x6e02,0x6e07,0x6e09,0x6e01,0x6e17,0x6dff,0x6e12,0x3dba,
122.2506 +    0x3db9,0x7103,0x7107,0x7101,0x70f5,0x70f1,0x7108,0x70f2,0x710f,0x3dbb,
122.2507 +    0x70fe,0x3e18,0x3e40,0x3e3d,0x731a,0x7310,0x730e,0x7402,0x73f3,0x3ecd,
122.2508 +    0x3ec9,0x73fb,0x3ecb,0x3eca,0x3ece,0x751b,0x7523,0x7561,0x7568,0x3f5e,
122.2509 +    0x7567,0x75d3,0x3f91,0x3f8c,0x7690,0x3fe1,0x4002,0x76d5,0x76d7,0x76d6,
122.2510 +    0x7730,0x402b,0x7726,0x402a,0x7740,0x3e14,0x771e,0x40ad,0x40a3,0x40ab,
122.2511 +    0x7847,0x40af,0x784b,0x7851,0x784f,0x7842,0x7846,0x4104,0x796e,0x796c,
122.2512 +    0x79f2,0x4144,0x79f1,0x79f5,0x79f3,0x79f9,0x413d,0x4147,0x419c,0x7a9a,
122.2513 +    0x7a93,0x7a91,0x7ae1,0x41e0,0x41e4,0x7b21,0x7b1c,0x7b16,0x7b17,0x7b36,
122.2514 +    0x7b1f,0x4280,0x7c93,0x7c99
122.2515 +  },
122.2516 +  {				/* ku 18 */
122.2517 +    0x7c9a,0x7c9c,0x42ca,0x7d49,0x42d4,0x7d34,0x7d37,0x42d2,0x7d2d,0x42cb,
122.2518 +    0x7d4c,0x42ce,0x42d3,0x7d48,0x4344,0x4348,0x7f3b,0x4345,0x4381,0x4386,
122.2519 +    0x4385,0x8008,0x801a,0x43a3,0x801d,0x43b5,0x8049,0x8045,0x8044,0x7c9b,
122.2520 +    0x43fa,0x43f9,0x812a,0x812e,0x43fb,0x43f2,0x8131,0x43ef,0x811a,0x8134,
122.2521 +    0x8117,0x445b,0x4466,0x44ce,0x831d,0x8371,0x8384,0x8380,0x8372,0x83a1,
122.2522 +    0x35b4,0x8379,0x8391,0x44c8,0x839f,0x83ad,0x44d1,0x44c5,0x8323,0x44d2,
122.2523 +    0x8385,0x839c,0x83b7,0x8658,0x865a,0x458f,0x8657,0x86b2,0x45a7,0x86ae,
122.2524 +    0x45a5,0x45a4,0x4611,0x8845,0x889c,0x8894,0x88a3,0x888f,0x88a5,0x88a9,
122.2525 +    0x88a6,0x888a,0x88a0,0x8890,0x8992,0x8991,0x8994,0x46b5,0x8a26,0x8a32,
122.2526 +    0x8a28,0x46b4,0x46bd,0x8a1c
122.2527 +  },
122.2528 +  {				/* ku 19 */
122.2529 +    0x46bb,0x8a2b,0x8a20,0x46b9,0x8a29,0x46c2,0x46be,0x46ba,0x8a21,0x8c3a,
122.2530 +    0x3ab7,0x8c5b,0x8c58,0x8c7c,0x4758,0x8ca6,0x8cae,0x8cad,0x8d65,0x479b,
122.2531 +    0x8d7e,0x479c,0x8d7c,0x8d7f,0x8d7a,0x8dbd,0x47da,0x47de,0x8dc0,0x8dbb,
122.2532 +    0x8ead,0x8eaf,0x8ed6,0x484d,0x4846,0x4847,0x484b,0x484c,0x8ed9,0x4848,
122.2533 +    0x4899,0x9012,0x900e,0x9025,0x489b,0x9013,0x90ee,0x48ce,0x90ab,0x90f7,
122.2534 +    0x48eb,0x9159,0x9154,0x91f2,0x91f0,0x91e5,0x91f6,0x491c,0x498c,0x9587,
122.2535 +    0x49d1,0x965a,0x49d6,0x49d3,0x966e,0x49d4,0x49d0,0x49d5,0x9679,0x4a0b,
122.2536 +    0x98e1,0x98e6,0x4bc6,0x9ec4,0x9ed2,0x4e80,0x3424,0x4e81,0x508f,0x5097,
122.2537 +    0x5088,0x5089,0x3474,0x347a,0x5081,0x5160,UBOGON,0x34c3,0x5e42,0x51d3,
122.2538 +    0x34d4,0x34d5,0x51d2,0x51d6
122.2539 +  },
122.2540 +  {				/* ku 1a */
122.2541 +    0x5273,0x34fb,0x5270,0x34f7,0x3532,UBOGON,0x53a8,0x53a6,0x53c5,0x5597,
122.2542 +    0x55de,0x35ba,0x35bf,0x5596,0x55b4,0x35c7,0x5585,0x35b7,0x559b,0x55a0,
122.2543 +    0x35b9,0x5559,0x35c3,0x5586,0x35bd,0x35d0,0x55af,0x557a,0x35c1,0x35be,
122.2544 +    0x35cd,0x559e,0x35cb,0x55a9,0x570f,0x570e,0x581a,0x364f,0x581f,0x3653,
122.2545 +    0x583c,0x5818,0x583e,0x5826,0x3655,0x583a,UBOGON,0x5822,0x3651,0x58fb,
122.2546 +    0x5963,0x5964,0x369f,0x5aa8,0x5aa3,0x5a82,0x5a88,0x5aa1,0x5a85,0x5a98,
122.2547 +    0x36fe,0x5a99,0x36fb,0x5a89,0x5a81,0x5a96,0x5a80,0x36f1,0x36f5,0x5a91,
122.2548 +    0x36ef,0x3704,0x3703,0x36f4,0x5acf,0x36f3,0x3702,0x36f7,0x36fa,0x36fd,
122.2549 +    0x36ee,0x5a87,0x5aa0,0x36f0,0x5a79,0x36f2,0x5a86,0x5aab,0x5aaa,0x5aa4,
122.2550 +    0x5a8d,0x5a7e,0x3744,0x5bd5
122.2551 +  },
122.2552 +  {				/* ku 1b */
122.2553 +    0x3762,0x3777,0x3dc9,0x5c1e,0x5c5f,0x5c5e,0x5d44,0x5d3e,0x37e8,0x5d48,
122.2554 +    0x5d1c,0x37ef,0x5d5b,0x5d4d,0x37e6,0x37ed,0x5d57,0x37e7,0x5d53,0x5d4f,
122.2555 +    0x37eb,0x5d3b,0x5d46,0x382d,0x3855,0x5e46,0x5e47,0x3853,0x5e48,0x5ec0,
122.2556 +    0x5ebd,0x5ebf,0x3890,0x5f11,0x38be,0x5f3e,0x5f3b,0x38bd,0x5f3a,0x38cf,
122.2557 +    0x38d0,0x38ec,0x5fa7,0x394b,0x60ea,0x3948,0x6107,0x6122,0x610c,0x3955,
122.2558 +    0x3951,0x60b3,0x60d6,0x60d2,0x394e,0x60e3,0x60e5,0x60e9,0x396b,0x395e,
122.2559 +    0x6111,0x60fd,0x3960,0x3967,0x611e,0x6120,0x6121,0x621e,0x39b8,0x63e2,
122.2560 +    0x63de,0x63e6,0x3a14,0x3a0f,0x3a07,0x3a13,0x63f8,0x3a17,0x63fe,0x63c1,
122.2561 +    0x63bf,0x63f7,0x63d1,0x655f,0x6560,0x6561,0x3a9a,0x3ab8,0x65d1,0x3af7,
122.2562 +    0x3af8,0x667d,0x666b,0x667f
122.2563 +  },
122.2564 +  {				/* ku 1c */
122.2565 +    0x3afd,0x3af5,0x6673,0x6681,0x666d,0x6669,0x3afa,0x3b38,0x671e,0x68ed,
122.2566 +    0x3b87,0x3b80,0x3b88,0x3b79,0x6903,0x3b7c,0x68fe,0x68e5,0x691e,0x6902,
122.2567 +    0x3b83,0x3b85,0x6909,0x68ca,0x6900,UBOGON,0x6901,0x6918,0x68e2,0x68cf,
122.2568 +    0x3b7b,0x692e,0x68c5,0x68ff,0x3b86,0x691c,0x68c3,0x3c34,0x6b6f,0x3c55,
122.2569 +    0x6b6e,0x3c68,0x6bbe,0x3c9c,0x6bf4,0x6c2d,0x3cfc,0x6db6,0x6e75,0x6e1e,
122.2570 +    0x3d1a,0x6e18,0x3d17,0x6e48,0x3d1b,0x6e4f,0x3d13,0x6e42,0x6e6a,0x6e70,
122.2571 +    0x6dfe,0x3d05,0x3d07,0x6e6d,0x3d1c,0x6e7b,0x6e7e,0x6e59,0x3d11,0x6e57,
122.2572 +    0x3d16,0x6e80,0x6e50,0x3d15,0x6e29,0x6e76,0x6e2a,0x6e4c,0x712a,0x3dcb,
122.2573 +    0x7135,0x712c,0x7137,0x711d,0x3dc5,0x3dc2,0x7138,0x3dcd,0x7134,0x712b,
122.2574 +    0x7133,0x7127,0x7124,0x3dca
122.2575 +  },
122.2576 +  {				/* ku 1d */
122.2577 +    0x712d,0x7232,0x7283,0x7282,0x7287,0x7306,0x7324,0x7338,0x732a,0x732c,
122.2578 +    0x732b,0x3e83,0x732f,0x7328,0x7417,0x3ed6,0x3ed5,0x7419,0x7438,0x3ed1,
122.2579 +    0x741f,0x7414,0x743c,0x73f7,0x741c,0x7415,0x7418,0x7439,0x74f9,0x7524,
122.2580 +    UBOGON,0x3f52,0x3f5f,0x756e,0x756d,0x7571,0x758e,0x3f95,0x75e5,0x3f9d,
122.2581 +    0x3f98,0x3f9e,0x3f96,0x7694,0x76b3,0x4003,0x76d9,0x402f,0x7748,0x7749,
122.2582 +    0x7743,0x4031,0x4033,0x7742,0x77df,0x40b4,0x7863,0x7876,0x40b0,0x785f,
122.2583 +    0x7866,0x7966,0x7971,0x4108,0x4107,0x7976,0x7984,0x7975,0x79ff,0x7a07,
122.2584 +    0x414e,0x7a0e,0x7a09,0x4150,0x4152,0x41a1,0x41a3,0x41a5,0x41cc,0x7ae7,
122.2585 +    0x7ae2,0x7b55,0x41ef,0x41ea,0x7b43,0x7b57,0x7b6c,0x7b42,0x7b53,0x41ed,
122.2586 +    0x7b41,0x4285,0x4284,0x7ca7
122.2587 +  },
122.2588 +  {				/* ku 1e */
122.2589 +    0x7ca0,0x7ca6,0x7ca4,0x7d74,0x42db,0x7d59,0x42d9,0x7d60,0x7d57,0x7d6c,
122.2590 +    0x7d7e,0x7d64,0x42d7,0x7d5a,0x7d5d,0x42da,0x42de,0x42d8,0x7d76,0x7d4d,
122.2591 +    0x7d75,0x42d5,0x7fd3,0x7fd6,0x439c,0x439d,0x8060,0x804e,0x8145,0x813b,
122.2592 +    0x43fe,0x8148,0x8142,0x8149,0x8140,0x8114,0x8141,0x4407,0x81ef,0x81f6,
122.2593 +    0x8203,0x446a,0x83ed,0x44e7,0x83da,0x8418,0x83d2,0x8408,0x44e2,0x8400,
122.2594 +    0x44df,0x44e1,0x44e5,0x8417,0x8346,0x8414,0x83d3,0x8405,0x841f,0x8402,
122.2595 +    0x8416,0x83cd,0x83e6,0x4591,0x865d,0x86d5,0x86e1,0x45b4,0x45b0,0x45b5,
122.2596 +    0x45ae,0x86ee,0x8847,0x8846,0x462d,0x462c,0x88bb,0x462b,0x88bf,0x88b4,
122.2597 +    0x4629,0x88b5,0x467f,0x899a,0x8a43,0x46c9,0x46cb,0x8a5a,0x46c5,0x46c6,
122.2598 +    0x46ca,0x8a35,0x8a38,0x8a42
122.2599 +  },
122.2600 +  {				/* ku 1f */
122.2601 +    0x8a49,0x8a5d,0x8a4b,0x8a3d,0x46d2,0x46d0,0x472d,0x4735,0x8c60,0x8c5e,
122.2602 +    0x8c7f,0x8c7e,0x8c83,0x476c,0x8cb1,0x8d87,0x479d,0x47a0,0x8d88,0x8d83,
122.2603 +    0x47a2,0x479f,0x8d86,0x8d8b,0x8d82,0x8dca,0x8dd2,0x47eb,0x47e2,0x8dd4,
122.2604 +    0x8dc9,0x8eb0,0x4836,0x4832,0x4850,0x8ef2,0x8ee4,0x8ef3,0x8eea,0x484f,
122.2605 +    0x8efd,0x4852,0x8f9d,0x902b,0x902a,0x489e,0x9028,0x9029,0x902c,0x48a0,
122.2606 +    0x489c,0x903a,0x9030,0x9037,0x903b,0x48d1,0x910a,0x48ef,0x48f0,0x48f1,
122.2607 +    0x91fe,0x9220,0x491d,0x920b,0x491f,0x9218,0x9222,0x491e,0x921b,0x9208,
122.2608 +    0x4920,0x920e,0x9213,0x498e,0x4991,0x9595,UBOGON,0x4990,0x49d7,0x968c,
122.2609 +    0x967b,0x967f,0x9681,0x49d9,0x9682,0x49f4,0x49f6,0x3560,0x49f5,0x49f3,
122.2610 +    0x96ee,0x96ed,0x4a0c,0x96ec
122.2611 +  },
122.2612 +  {				/* ku 20 */
122.2613 +    0x975f,0x976f,0x4a51,0x976d,0x4aa6,0x4aa7,0x4aa8,0x4b27,0x4b24,0x4b25,
122.2614 +    0x98f0,0x4b2a,0x4b74,0x4bc7,0x9aa9,0x4be7,0x4bed,0x9ae0,0x4eb7,0x342e,
122.2615 +    0x347b,0x50cc,0x50bc,0x347c,0x50aa,0x50b9,0x347d,0x50ab,0x50c3,0x50cd,
122.2616 +    0x517e,0x527e,0x5279,0x34fd,UBOGON,0x52e1,0x52e0,0x52e7,0x5380,0x53ab,
122.2617 +    0x53aa,0x53a9,0x53e0,0x55ea,0x35da,0x55d7,0x35d6,0x35db,0x55c1,0x5715,
122.2618 +    0x365b,0x586c,0x365c,0x585c,0x5850,0x5861,0x586a,0x5869,0x5856,0x5860,
122.2619 +    0x5866,0x585f,0x5923,0x5966,0x5968,0x3706,0x370b,0x5ace,0x370d,0x5ac5,
122.2620 +    0x5ac3,0x370a,0x3713,0x5ad0,0x3710,0x3712,0x3709,0x3708,0x3711,0x370f,
122.2621 +    0x5b74,0x5b76,0x5bdc,0x5bd7,0x5bda,0x5bdb,0x3767,0x5c20,0x5d6d,0x5d66,
122.2622 +    0x37f6,0x5d64,0x5d6e,UBOGON
122.2623 +  },
122.2624 +  {				/* ku 21 */
122.2625 +    0x5d60,0x5f42,0x5f5a,0x5f6e,0x3964,0x396c,0x6130,0x613a,0x612a,0x6143,
122.2626 +    0x6119,0x6131,0x396d,0x613d,0x397a,0x3975,0x3a0d,0x6408,0x6432,0x6438,
122.2627 +    0x3a1e,0x6431,0x3a1b,0x6419,0x3a2a,0x6411,0x3a1f,0x3a22,0x6429,0x641d,
122.2628 +    0x3a25,0x3a27,0x3a29,0x643c,0x3a24,0x6446,0x6447,0x3a28,0x3a26,0x643a,
122.2629 +    0x6407,0x3a23,0x656b,0x3a9f,0x6570,0x656d,0x3ab1,0x65e4,0x6693,0x3b03,
122.2630 +    0x3b07,0x3b0c,0x3b06,0x668f,0x3b04,0x3b09,0x6692,0x3b05,0x668e,0x3b08,
122.2631 +    0x6946,0x3b96,0x3b9c,0x3b9f,0x3b9b,0x3b98,0x3b99,0x3b94,0x6931,0x3b8d,
122.2632 +    0x3ba3,0x693e,0x3b93,0x697c,0x6943,0x3b92,0x6973,UBOGON,0x6955,0x3b8e,
122.2633 +    0x3b8c,0x6985,0x694d,0x6950,0x6947,0x6967,0x6936,0x6964,0x6961,0x3b9a,
122.2634 +    0x697d,0x6b44,0x6b40,0x6b71
122.2635 +  },
122.2636 +  {				/* ku 22 */
122.2637 +    0x6b73,0x6b9c,0x3c6a,0x3c6d,0x3c84,0x6bc1,0x3ca0,0x6bfa,0x6c31,0x6c32,
122.2638 +    0x3d1d,0x3d26,0x6eb8,0x6ea8,0x3d33,0x6e91,0x6ebb,0x3d38,0x6e9a,0x3d30,
122.2639 +    0x3d28,0x6ea9,0x3d27,0x3d2a,0x6eb5,0x6e6c,0x6ee8,0x3d31,0x6edd,0x6eda,
122.2640 +    0x6ee6,0x6eac,0x3d34,0x3d2e,0x3d3b,0x6ed9,0x6ee3,0x6ee9,0x6edb,0x3d29,
122.2641 +    0x716f,0x3dd2,0x3dd8,0x7148,0x3dcf,0x714a,0x716b,0x3dd9,0x714f,0x7157,
122.2642 +    0x7174,0x3dce,0x3dd3,0x3dd0,0x7145,0x7151,0x716d,0x3ba1,0x7251,0x7250,
122.2643 +    0x724e,0x3e47,0x7341,0x3e8b,0x732e,0x7346,0x3ed4,0x7427,0x3ede,0x7448,
122.2644 +    0x7453,0x743d,0x3edf,0x745d,0x7456,0x3ed7,0x741e,0x7447,0x7443,0x7458,
122.2645 +    0x7449,0x3ee1,0x744c,0x7445,0x743e,0x3f2f,0x7501,0x751e,0x3f62,0x3f63,
122.2646 +    0x757a,0x75ee,0x7602,0x7697
122.2647 +  },
122.2648 +  {				/* ku 23 */
122.2649 +    0x7698,0x3fe2,0x4004,0x4043,0x775d,0x7764,0x7753,0x7758,0x7882,0x7890,
122.2650 +    0x788a,0x40be,0x787a,0x787d,0x40ba,0x788b,0x7878,0x40bc,UBOGON,0x788d,
122.2651 +    0x7888,0x7892,0x7881,0x797e,0x7983,0x410d,0x410e,0x4111,0x7980,0x410f,
122.2652 +    0x4112,0x4155,0x7a0f,0x4159,0x415b,0x7a1d,0x4157,0x7aa1,0x7aa4,0x41ce,
122.2653 +    0x7ae9,0x7aea,0x41fe,0x7b62,0x7b6b,0x41fc,0x7b5e,0x41f5,0x7b79,0x41f9,
122.2654 +    0x41fa,0x7b6f,0x7b68,0x4288,0x4289,0x7cae,0x428a,0x4287,0x428b,0x7cb0,
122.2655 +    0x42e6,0x7d90,0x42ed,0x7d8a,0x42e5,0x7d8b,0x7d99,0x7d95,0x42e0,0x7d87,
122.2656 +    0x7d78,0x7d97,0x7d89,0x7d98,0x42e1,0x435b,0x435c,0x7fa3,0x438f,0x438b,
122.2657 +    0x438d,0x7fdd,0x8057,0x43b9,0x8163,0x816a,0x816c,0x440f,0x4419,0x4413,
122.2658 +    0x815d,0x8175,0x4418,0x815f
122.2659 +  },
122.2660 +  {				/* ku 24 */
122.2661 +    0x4416,0x817d,0x816d,0x4453,UBOGON,0x8241,0x844f,0x8484,0x44f6,0x847f,
122.2662 +    0x44f5,0x8448,0x842a,0x847b,0x8472,0x8464,0x842e,0x845c,0x8453,0x44f7,
122.2663 +    0x8441,0x84c8,0x44f0,0x8462,0x8480,0x843e,0x8483,0x8471,0x44f9,0x844a,
122.2664 +    0x8455,0x8458,0x4592,0x4595,0x4596,0x86fc,0x86fd,0x8715,0x45b9,0x8716,
122.2665 +    0x86ff,0x45bd,0x45b8,0x4612,0x8858,0x88cf,0x88e0,0x4680,0x4681,0x469a,
122.2666 +    0x4698,0x89e7,0x8a6a,0x8a80,0x46d4,0x8a6f,0x8a65,0x46da,0x8a78,0x8a7d,
122.2667 +    0x8a88,0x46d6,0x46db,0x8a64,0x8a7e,0x46dc,0x8a67,0x8c63,0x8c88,0x4771,
122.2668 +    0x8ccd,0x4772,0x8cc9,0x47a8,0x8ded,0x47f0,UBOGON,0x47f1,0x47fd,0x4838,
122.2669 +    0x4837,0x4839,0x8eb1,0x4855,0x4853,0x8f04,0x8f9e,0x8fa0,0x9043,0x9046,
122.2670 +    0x9048,0x9045,0x9040,0x904c
122.2671 +  },
122.2672 +  {				/* ku 25 */
122.2673 +    0x48d5,0x48bd,0x910c,0x9113,0x9115,0x48f5,0x916b,0x9167,0x925d,0x9255,
122.2674 +    0x9235,0x4921,0x9259,0x922f,0x923c,0x928f,0x925c,0x926a,0x9262,0x925f,
122.2675 +    0x926b,0x926e,0x923b,0x9244,0x9241,0x959a,0x4992,0x9599,0x49de,0x49db,
122.2676 +    0x49da,0x968f,0x49df,0x9696,0x49f9,0x49f8,0x49fa,0x96f4,0x96fc,0x4a0e,
122.2677 +    0x9755,0x4a43,0x9779,0x4a56,0x4a53,0x4a9e,0x97ee,0x97f5,0x4aa9,0x980b,
122.2678 +    0x4afa,0x98f3,0x4b31,0x4b30,0x98f7,0x98ff,0x98f5,0x4b32,0x98ec,0x98f1,
122.2679 +    0x4b29,0x4b2e,0x999a,0x4b76,0x9ae2,0x9b3d,0x9b5d,0x9ce8,0x4ca5,0x9ceb,
122.2680 +    0x9cef,0x9cee,0x9e81,0x9f14,0x50d0,0x50d9,0x50dc,0x50d8,0x348c,0x50e1,
122.2681 +    0x50eb,0x348b,0x3489,0x50f4,0x50e2,0x50de,0x348d,0x3486,0x34d7,0x51f4,
122.2682 +    0x3504,0x3507,0x3503,0x52ed
122.2683 +  },
122.2684 +  {				/* ku 26 */
122.2685 +    0x52ea,0x3522,0x5332,0x3551,0x53ae,0x53b0,0x3561,0x55fb,0x5603,0x560b,
122.2686 +    0x35e9,0x5607,0x35e5,0x55f8,0x35e4,0x5628,0x561e,0x35e3,0x5618,0x5611,
122.2687 +    0x5651,0x5605,0x5717,0x5892,0x3665,0x588c,0x3663,0x5878,0x5884,0x5873,
122.2688 +    0x58ad,0x5897,0x5895,0x5877,0x5872,0x5896,0x588d,0x5910,0x368c,0x596c,
122.2689 +    0x371a,0x5ae7,0x3715,0x5ae4,0x3720,0x3721,0x5aef,0x5626,0x371c,0x371b,
122.2690 +    0x5af0,0x5d7b,0x37fe,0x5d83,0x3804,0x3801,0x5d8b,0x5d8c,0x3800,0x5d78,
122.2691 +    0x5e52,0x386d,0x3893,0x5ed0,0x5ecf,0x38a1,0x5fb3,0x5fb4,0x3976,0x3979,
122.2692 +    0x3972,0x617b,0x3983,0x616f,0x6181,0x613c,0x6142,0x6138,0x6133,UBOGON,
122.2693 +    0x6160,0x6169,0x617d,0x6186,0x622c,0x6228,0x3a38,0x644c,0x3a30,0x6457,
122.2694 +    0x647c,0x3a34,0x3a3a,0x6455
122.2695 +  },
122.2696 +  {				/* ku 27 */
122.2697 +    0x6462,0x6471,0x646a,0x6456,0x643b,0x6481,0x3a35,0x644f,0x647e,0x6464,
122.2698 +    0x3a3f,0x3a40,0x3a32,0x3a31,0x3a36,0x6571,UBOGON,0x3b0f,0x66a5,0x669a,
122.2699 +    0x669c,0x3b10,0x66a6,0x3b0d,0x66a4,0x698f,0x69c5,0x69c8,0x6992,0x69b2,
122.2700 +    0x3ba9,0x3bb4,0x3bac,0x69e3,0x69c0,0x69d6,0x69d1,0x699f,0x69a2,0x69d2,
122.2701 +    0x3bb8,0x3bae,UBOGON,0x69e1,0x69d5,0x699d,0x3bb3,0x3bba,0x6998,0x3c3f,
122.2702 +    0x6b74,0x6ba1,0x3d3c,0x6ef0,0x6ef3,0x3d42,0x3d40,0x6f1b,0x6f0c,0x6f1d,
122.2703 +    0x6f34,0x6f28,0x6f17,0x3d3e,0x6f44,0x6f42,0x6f04,0x6f11,0x6efa,0x6f4a,
122.2704 +    0x7191,0x718e,0x3de1,0x718b,0x718d,0x717f,0x718c,0x717e,0x717c,0x7183,
122.2705 +    0x3de6,0x7188,0x3de0,0x3e15,0x7294,0x3e93,0x7355,0x7353,0x734f,0x7354,
122.2706 +    0x746c,0x7465,0x7466,0x7461
122.2707 +  },
122.2708 +  {				/* ku 28 */
122.2709 +    0x746b,0x7468,0x7476,0x3ee7,0x7460,UBOGON,0x7474,0x7506,0x760e,0x3fad,
122.2710 +    0x7607,0x3fae,0x3fe3,0x76b9,0x3ff5,0x76b7,0x76e2,0x4006,0x7774,0x7777,
122.2711 +    0x7776,0x7775,0x404f,0x7778,0x7771,0x4054,0x777a,0x715b,0x777b,0x78a6,
122.2712 +    0x78ae,0x78b8,0x40cb,0x40e3,0x40c9,0x78b1,0x78af,0x4113,0x7989,0x7987,
122.2713 +    0x4115,0x4161,0x7a29,0x4166,0x7a2a,0x4164,0x7a2d,0x7a2c,0x4160,0x7a32,
122.2714 +    0x4163,0x7aec,0x7af0,0x7b81,0x7b9e,0x7b83,0x420a,0x7b92,0x4204,0x7ba3,
122.2715 +    0x7b9f,0x7b93,0x4207,0x7b86,0x7cb8,0x7cb7,0x428d,0x428f,0x4290,0x4292,
122.2716 +    0x42ec,0x7dc8,0x7db6,UBOGON,0x7dd1,0x42e7,0x7da8,0x7dab,0x42f2,0x7db3,
122.2717 +    0x7dcd,0x42ee,0x7dcf,0x7da4,0x42ef,0x434c,0x7f41,0x7f6f,0x7f71,0x435e,
122.2718 +    0x435f,0x4376,0x4374,0x4372
122.2719 +  },
122.2720 +  {				/* ku 29 */
122.2721 +    0x4390,0x8023,0x805b,0x43be,0x8061,0x805f,0x8181,0x4426,0x4425,0x8184,
122.2722 +    0x8213,0x4474,0x824a,0x824c,0x44fd,0x4505,0x4501,0x84bd,0x8495,0x4509,
122.2723 +    0x8492,0x84c3,0x450c,0x8496,0x84a5,0x84b5,0x84b3,0x84a3,0x84e4,0x84d8,
122.2724 +    0x84d5,0x450d,0x84b7,0x84ad,0x84da,0x8493,0x8736,0x45c0,0x45c5,0x45c9,
122.2725 +    0x873d,0x872b,0x8747,0x8739,0x45d5,0x8745,0x871d,0x4641,0x88ff,0x88ea,
122.2726 +    0x4633,0x88f5,0x463a,0x8900,0x88ed,0x8903,0x88e9,0x4640,0x4642,0x89ea,
122.2727 +    0x46e8,0x8a9b,0x8a8e,0x8aa2,0x46e4,0x8a9c,0x8a94,0x8a90,0x8aa9,0x8aac,
122.2728 +    0x46e7,0x8a9f,0x46e6,0x46e1,0x8a9d,0x4739,0x8c67,0x475c,0x4775,0x8cd0,
122.2729 +    0x8cd6,0x8cd4,0x8d98,0x8d9a,0x8d97,0x47ae,0x47b0,0x47fa,0x8e0b,0x8e08,
122.2730 +    0x8e01,0x8eb4,0x8eb3,0x485b
122.2731 +  },
122.2732 +  {				/* ku 2a */
122.2733 +    0x8fa1,0x8fa2,0x48a5,0x905a,0x48a2,0x9061,0x905f,0x48db,0x48da,0x9125,
122.2734 +    0x917b,0x9176,0x917c,0x4924,0x9289,0x92f6,0x92b1,0x92ad,0x9292,0x9281,
122.2735 +    0x9284,0x4926,0x92ae,0x9290,0x929e,0x4998,0x4996,0x499a,0x95a2,0x95a7,
122.2736 +    0x4997,0x49e1,0x49e0,0x49e3,0x49e2,0x96a0,0x969d,0x969f,0x96d0,0x49fb,
122.2737 +    0x96d1,0x4a12,0x4a14,0x9759,0x4a45,0x9764,0x4a5c,0x4a5d,0x4ab8,0x9819,
122.2738 +    0x4aba,0x9814,0x9815,0x981a,0x4b03,0x4b35,0x4b36,0x4b39,0x9906,0x4b2d,
122.2739 +    0x98f8,0x9901,0x4b7a,0x99be,0x99bc,0x99b7,0x99b6,0x99c0,0x4b78,0x99b8,
122.2740 +    0x4b7b,0x4b7c,0x4b7e,0x99c4,0x4b7d,0x99bf,0x4bc9,0x9ada,0x9ae4,0x9ae9,
122.2741 +    0x9ae8,0x9aea,0x9ae5,0x4bf3,0x9b26,0x4c1a,0x4c19,0x9b40,0x4c1f,0x4ca6,
122.2742 +    0x4ca7,0x4ca8,0x4cab,0x4ca9
122.2743 +  },
122.2744 +  {				/* ku 2b */
122.2745 +    0x4d2e,0x9ebd,0x4d5e,0x3495,0x3493,0x3492,0x510e,0x3496,0x50f7,0x3497,
122.2746 +    0x50fc,0x510d,0x5101,0x51da,0x51d9,0x51db,0x5286,0x528e,0x52ee,0x5333,
122.2747 +    0x53b1,0x35f5,0x5647,0x562d,0x5654,0x35ea,0x564b,0x5652,0x5631,0x5644,
122.2748 +    0x5656,0x5650,0x562b,0x35f3,0x564d,0x5637,0x564f,0x58a2,0x58b7,0x3669,
122.2749 +    0x58b2,0x366b,0x58aa,0x58b5,0x58b0,0x366c,0x58b4,0x58a4,0x58a7,0x3668,
122.2750 +    0x5926,0x5afe,0x3728,0x5b04,0x3726,0x5afc,0x3725,0x5b06,0x5b0a,0x5afa,
122.2751 +    0x5b0d,0x5b00,0x5b0e,0x376b,0x380f,0x3808,0x5d91,0x380c,0x5d8f,0x5d90,
122.2752 +    0x5d98,0x5da4,0x5d9b,0x5da3,0x5d96,0x5de4,0x5e5a,0x3860,0x3862,0x5e5e,
122.2753 +    0x3898,0x5fb8,0x6157,0x615c,0x61a6,0x6195,0x6188,0x398a,0x61a3,0x618f,
122.2754 +    0x3984,0x6164,0x397f,0x6159
122.2755 +  },
122.2756 +  {				/* ku 2c */
122.2757 +    0x6178,0x3982,0x6185,0x6187,0x619e,0x3996,0x3989,0x6198,0x619c,0x398d,
122.2758 +    0x39bc,0x622f,0x6480,0x649b,0x648e,0x648d,0x6494,0x64c6,0x3a44,0x64a8,
122.2759 +    0x6483,0x3a3c,0x64b9,0x6486,0x64b4,0x64af,0x6491,0x3a4e,0x64aa,0x64a1,
122.2760 +    0x64a7,0x66b6,0x66b3,0x3b14,0x66bc,0x66ac,0x3b15,0x66ad,0x6a0e,0x3bce,
122.2761 +    0x6a1c,0x6a1a,0x3be0,0x3bc2,0x6a0b,0x3bbf,0x69ef,0x6a0c,0x69f0,0x6a22,
122.2762 +    0x3bc4,0x69d8,0x3bcf,0x6a12,0x69fa,0x3bc8,0x6a2a,0x3bcc,0x6a10,0x3bcd,
122.2763 +    0x3bc7,0x6a29,0x69f9,0x69ea,0x6a2c,0x6a24,0x4cb7,0x69e9,0x6b52,0x6b4f,
122.2764 +    0x6b53,0x3c43,0x3cb6,0x6f10,0x6f65,0x6f75,0x3d51,0x3d4a,0x3d4d,0x3d56,
122.2765 +    0x6fd0,0x3d53,0x6f5c,0x6f3d,0x6f71,0x3d59,0x6f91,0x6f0b,0x6f79,0x6f81,
122.2766 +    0x6f8f,0x3d4e,0x6f59,0x6f74
122.2767 +  },
122.2768 +  {				/* ku 2d */
122.2769 +    0x3dee,0x71ae,0x3dec,0x71a3,0x71ad,0x3deb,0x3def,0x71ab,0x71a6,0x71a2,
122.2770 +    0x3ded,0x52f2,0x7257,0x7255,0x7299,0x734b,0x747a,0x3ef2,0x3eef,0x3ef1,
122.2771 +    0x748c,0x7484,0x3eed,0x3ef0,0x7482,0x7493,0x747b,0x3eee,0x7509,0x4c1b,
122.2772 +    0x3f50,0x3f66,0x3684,0x3fb8,0x3ff6,0x778a,0x4057,0x7790,0x405e,0x78c6,
122.2773 +    0x78d3,0x78c0,0x78d2,0x78c7,0x78c2,0x4119,0x799f,0x799d,0x799e,0x4170,
122.2774 +    0x7a41,0x416e,0x7a38,0x7a3a,0x7a42,0x4172,0x4176,0x7a3e,0x7ab0,0x7bae,
122.2775 +    0x7bb3,0x4212,0x421f,0x7bbf,0x4211,0x4216,0x7bcd,0x4219,0x7bb2,0x4224,
122.2776 +    0x4214,0x4225,0x4295,0x4296,0x4293,0x4294,0x7cc4,0x7ccd,0x7cc2,0x7cc6,
122.2777 +    0x7cc3,0x7cc9,0x7cc7,0x42a0,0x7df8,0x42fb,0x7ded,0x7de2,0x42fc,0x4300,
122.2778 +    0x42f8,0x7ddc,0x7e02,0x7e01
122.2779 +  },
122.2780 +  {				/* ku 2e */
122.2781 +    0x42f9,0x7dd6,0x4304,0x7de4,0x7dfe,0x4303,0x7e00,0x7dfc,0x7dfd,0x42f3,
122.2782 +    0x7df5,0x7dff,0x42fa,0x7deb,0x7de5,0x7f78,0x7fae,0x7fe7,0x43bf,0x8065,
122.2783 +    0x806a,0x8066,0x8068,0x806b,0x8194,0x81a1,0x8192,0x8196,0x8193,0x4479,
122.2784 +    0x4510,0x8501,0x4514,0x84f8,0x450e,0x84f5,0x451a,0x8504,0x4519,0x4521,
122.2785 +    0x4523,0x451f,0x851b,0x8503,0x8533,0x8534,0x84ed,0x4525,0x452b,0x8535,
122.2786 +    0x4516,0x8505,0x4522,0x451b,0x45ce,0x45cf,0x877d,0x45cb,0x45d1,0x45cc,
122.2787 +    0x8771,0x4617,0x885c,0x88e6,0x890f,0x891b,0x4651,0x89a9,0x89a5,0x89ee,
122.2788 +    0x8ab1,0x46ed,0x8acc,0x8ace,0x46f4,0x8ab7,0x46f1,0x8ab5,0x8ae9,0x8ab4,
122.2789 +    0x46f8,0x8ab3,0x8ac1,0x8aaf,0x8aca,0x8ad0,0x472f,0x475e,0x475d,0x8c8e,
122.2790 +    0x4776,0x4777,0x8ce9,0x8cdb
122.2791 +  },
122.2792 +  {				/* ku 2f */
122.2793 +    0x477e,0x8ceb,0x8da4,0x47b6,0x8da2,0x8d9d,0x47b3,0x47fc,0x4803,0x4800,
122.2794 +    0x8e2a,0x8e28,0x480a,0x4802,0x8eb8,0x8eb6,0x8eb9,0x8eb7,0x8f22,0x8f2b,
122.2795 +    0x8f27,0x8f19,0x8fa4,0x4887,0x8fb3,0x48a6,0x9071,0x906a,0x48a9,0x48de,
122.2796 +    0x9188,0x918c,0x92bf,0x92b8,0x92be,0x92dc,0x92e5,0x492e,0x492d,0x92d4,
122.2797 +    0x92d6,0x4930,0x92da,0x92ed,0x92f3,0x92db,0x492b,0x92b9,0x92e2,0x92eb,
122.2798 +    0x95af,0x499e,0x95b2,0x95b3,0x499f,0x49e5,0x49e4,0x96a3,0x96a5,0x49fd,
122.2799 +    0x49fc,0x4a17,0x4a19,0x970a,0x4a18,0x9787,0x9789,0x978c,0x97ef,0x982a,
122.2800 +    0x9822,0x4abf,0x981f,0x4b3c,0x9919,0x4b6b,0x99ca,0x99da,0x4b83,0x4b81,
122.2801 +    0x4b80,0x99de,0x99c8,0x99e0,0x4bca,0x9ab6,0x9ab5,0x4bce,0x9af4,0x4bf6,
122.2802 +    0x9b6b,0x9b69,0x9b72,0x9b63
122.2803 +  },
122.2804 +  {				/* ku 30 */
122.2805 +    0x4c39,0x9d0d,0x4cae,0x9d01,0x9d0c,0x4cb5,0x9cf8,0x4cb3,0x4cb4,0x9cfe,
122.2806 +    0x9d02,0x9e84,0x4d22,0x9eab,0x9eaa,0x511d,0x5116,0x3499,0x512b,0x511e,
122.2807 +    0x511b,0x5290,0x5294,0x5314,UBOGON,0x3602,0x5667,0x3601,0x567b,0x36a1,
122.2808 +    0x565f,0x5661,0x35fd,0x3673,0x3674,0x3670,0x3676,0x3675,0x3672,0x58c3,
122.2809 +    0x58ca,0x58bb,0x58c0,0x58c4,0x5901,0x5b1f,0x5b18,0x5b11,0x5b15,0x3729,
122.2810 +    0x5b12,0x5b1c,0x372a,0x5b22,0x5b79,0x5da6,0x3816,0x5db3,0x5dab,0x5eea,
122.2811 +    0x3899,0x5f5b,0x38d3,0x38f5,0x61b7,0x61ce,0x61b9,0x61bd,0x61cf,0x61c0,
122.2812 +    0x6199,0x6197,0x3994,0x61bb,0x61d0,0x61c4,0x6231,0x3a56,0x64d3,0x64c0,
122.2813 +    0x3a59,0x3a58,0x3a55,0x3a52,0x64dc,0x64d1,0x64c8,0x3a57,0x64d5,0x66c3,
122.2814 +    0x3b1b,0x3b1c,0x66bf,0x66c5
122.2815 +  },
122.2816 +  {				/* ku 31 */
122.2817 +    0x3b19,0x66cd,0x66c1,0x6706,0x3b3f,0x6724,0x6a63,0x6a42,0x6a52,0x3bdb,
122.2818 +    0x6a43,0x6a33,0x3be2,0x6a6c,0x6a57,0x3bd7,0x6a4c,0x6a6e,0x3bde,0x3be5,
122.2819 +    0x3be4,0x3be6,0x3bd6,0x6a37,0x3bdf,0x6a71,0x6a4a,0x6a36,0x3bdc,0x6a53,
122.2820 +    0x3bda,0x6a45,0x6a70,0x3bd3,0x3bd0,0x6a5c,0x6b58,0x6b57,0x3c86,0x3c87,
122.2821 +    0x3cad,0x3cb7,0x3d58,0x3d6a,0x6fbb,0x3d62,0x3d61,0x6fbe,0x3d69,0x3d6c,
122.2822 +    0x3d65,0x6fb5,0x6fd3,0x6f9f,0x3d66,0x6fb7,0x6ff5,0x71b7,0x3df5,0x71bb,
122.2823 +    0x3df4,0x71d1,0x3df7,0x71ba,0x3df8,0x71b6,0x71cc,0x3dfb,0x3dfc,0x71d3,
122.2824 +    0x749b,0x3ef5,0x3ef8,0x7496,0x74a2,0x749d,0x750a,0x750e,0x3f3c,0x7581,
122.2825 +    0x762c,0x7637,0x7636,0x763b,0x3fc5,0x76a1,0x4062,0x4063,0x7798,0x4067,
122.2826 +    0x7796,0x4066,0x40d9,0x40db
122.2827 +  },
122.2828 +  {				/* ku 32 */
122.2829 +    0x78d6,0x78eb,0x40d8,0x78dc,0x411b,0x79a5,0x79a9,0x9834,0x7a53,0x7a45,
122.2830 +    0x4179,0x7a4f,0x417d,0x7abd,0x7abb,0x7af1,0x422c,0x4237,0x7bec,0x7bed,
122.2831 +    0x4230,0x429a,0x7cd3,0x4a00,0x7ce1,0x4305,0x7e19,0x4307,0x4309,0x430a,
122.2832 +    0x7e27,0x7e26,0x4379,0x43c2,0x806e,0x81af,0x4438,0x4437,0x81ad,0x4421,
122.2833 +    0x81aa,0x8218,0x445e,0x453d,0x4537,0x4540,0x856f,0x854c,0x451d,0x8542,
122.2834 +    0x4533,0x855c,0x8570,0x855f,0x4535,0x855a,0x854b,0x853f,0x878a,0x45d8,
122.2835 +    0x878b,0x87a1,0x878e,0x45dc,0x45de,0x8799,0x885e,0x885f,0x8924,0x89a7,
122.2836 +    0x8aea,0x8afd,0x8af9,0x8ae3,0x8ae5,0x46fa,0x46fb,0x8aec,0x473d,0x473b,
122.2837 +    0x473f,0x475f,0x8cf2,0x477f,0x8cef,0x4784,0x8da6,0x47bc,0x4814,0x480f,
122.2838 +    0x8e3b,0x8e43,0x480e,0x8e32
122.2839 +  },
122.2840 +  {				/* ku 33 */
122.2841 +    0x8f31,0x8f30,0x4860,0x8f2d,0x8f3c,0x8fa7,0x8fa5,0x48ab,0x48ac,0x48aa,
122.2842 +    0x9137,0x9195,0x918e,0x4904,0x9196,0x4908,0x9345,0x930a,0x4933,0x4934,
122.2843 +    0x92fd,0x9317,0x931c,0x9307,0x9331,0x9332,0x932c,0x9330,0x9303,0x9305,
122.2844 +    0x49a2,0x95c2,0x49a4,0x95b8,0x49a5,0x95c1,0x49a7,0x49a6,0x49e7,0x96ab,
122.2845 +    0x96b7,0x49ff,0x49fe,0x9715,0x9714,0x4a1d,0x4a1c,0x970c,0x9717,0x4a67,
122.2846 +    0x9793,0x4a94,0x97d2,0x4ac5,0x4ac8,0x9836,0x9831,0x9833,0x983c,0x982e,
122.2847 +    0x983a,0x4ac9,0x983d,0x4ac7,0x98b5,0x9922,0x9923,0x9920,0x991c,0x991d,
122.2848 +    0x4b6c,0x99a0,0x4b8a,0x99ef,0x99e8,0x99eb,0x4b88,0x4b87,0x4b86,0x99e1,
122.2849 +    0x99e6,0x4bcf,0x4bd0,0x9af8,0x9af5,0x4c1c,0x4c23,0x9b83,0x9b94,0x9b84,
122.2850 +    0x4c49,0x9b8b,0x9b8f,0x4c43
122.2851 +  },
122.2852 +  {				/* ku 34 */
122.2853 +    0x9b8c,0x4c48,0x9b89,0x4c47,0x9b8e,0x4c46,0x4c3f,0x4c44,0x9d24,0x9d0f,
122.2854 +    0x4cbe,0x9d13,0x9d0a,0x4cc2,0x4cba,0x4cbc,0x4cc6,0x9d2a,0x9d1a,0x4cc8,
122.2855 +    0x9d27,0x9d16,0x9d21,0x4d23,0x9e85,0x9eac,0x9ec6,0x9ec5,0x9ed7,0x9f53,
122.2856 +    0x349d,0x5128,0x5127,0x51df,0x3524,0x5335,0x53b3,0x3607,0x568a,0x567d,
122.2857 +    0x5689,0x3679,0x58cd,0x58d0,0x3678,0x5b2b,0x5b33,0x5b29,0x5b35,0x5b31,
122.2858 +    0x5b37,0x5c36,0x5dbe,0x3819,0x5db9,0x381c,0x5dbb,0x3818,0x61e2,0x61db,
122.2859 +    0x61dd,0x61dc,0x61da,UBOGON,0x61d9,0x39bd,0x3a5d,0x64df,0x3a5a,0x3a5e,
122.2860 +    0x64e1,0x3a5c,0x64ee,0x3a5b,0x65b5,0x66d4,0x66d5,0x3b21,0x66d0,0x66d1,
122.2861 +    0x66ce,0x66d7,0x3b20,0x3b32,0x6a7d,0x6a8a,0x3bf2,0x6aa7,0x3bf5,0x6a99,
122.2862 +    0x6a82,0x6a88,0x3bee,0x3bec
122.2863 +  },
122.2864 +  {				/* ku 35 */
122.2865 +    0x6a86,0x3bea,0x6a98,0x6a9d,0x3bed,0x3bf3,0x6a8f,0x3bf6,0x6aaa,0x3c48,
122.2866 +    0x6b5d,0x3c49,0x6c0a,0x3d75,0x6fd7,0x6fd6,0x6fe5,0x3d6f,0x3d7b,0x3d73,
122.2867 +    0x6fd9,0x6fda,0x6fea,0x3d70,0x6ff6,UBOGON,0x3d78,0x71e3,0x3dfe,0x71e9,
122.2868 +    0x3e00,0x71eb,0x71ef,0x71f3,0x71ea,0x3e01,UBOGON,0x3e55,0x3e56,0x3e9d,
122.2869 +    0x7371,0x3ef9,0x74ae,0x3eff,0x74b3,0x3efd,0x74ac,0x3f43,0x3f41,0x7583,
122.2870 +    0x7645,0x764e,0x7644,0x76a3,0x76a5,0x77a6,0x77a4,0x406f,0x77a9,0x77af,
122.2871 +    0x408a,0x40e5,0x40e6,0x78f0,0x78f8,0x78f1,0x417f,0x7a49,0x41b5,0x41b6,
122.2872 +    0x41bb,0x7ac2,0x7af2,0x7af3,0x7bfa,0x4240,0x7bf6,0x7bfc,0x7c18,0x7c08,
122.2873 +    0x7c12,0x429d,0x429c,0x7cdb,0x7cda,0x430f,0x4311,0x430d,0x7e2c,0x7e4d,
122.2874 +    0x4314,0x4313,0x7f46,0x7ff6
122.2875 +  },
122.2876 +  {				/* ku 36 */
122.2877 +    0x802b,0x8074,0x81b8,0x81c8,0x4482,0x4483,0x454d,0x8592,0x8593,0x454f,
122.2878 +    0x857f,0x85ab,0x8597,0x454c,0x4551,0x85ac,0x45ee,0x45e8,0x4ccb,0x87ce,
122.2879 +    0x45eb,0x87cd,0x45e2,0x45e6,0x87c1,0x87b1,0x87c7,0x45ec,0x8940,0x4659,
122.2880 +    0x893f,0x8939,0x465d,0x8943,0x4657,0x465b,0x4656,0x89ab,0x46fe,0x8b1f,
122.2881 +    0x8b09,0x8b0c,0x4700,0x4701,0x8c40,0x4742,0x8c96,0x4760,0x8cf6,0x8cf7,
122.2882 +    0x481d,0x8e46,0x8e4f,0x483e,0x4869,0x4865,0x8f3d,0x8f41,0x9366,0x9378,
122.2883 +    0x935d,0x9369,0x9374,0x937d,0x936e,0x9372,0x9373,0x9362,0x9348,0x9353,
122.2884 +    0x935f,0x9368,0x4938,0x937f,0x936b,0x49ae,0x95c4,0x49ad,0x96af,0x96ad,
122.2885 +    0x96b2,0x4a02,0x4a1f,0x971a,0x971b,0x4a22,0x4a20,UBOGON,0x4a6c,0x979b,
122.2886 +    0x979f,0x4a68,0x4a6d,0x4a6e
122.2887 +  },
122.2888 +  {				/* ku 37 */
122.2889 +    0x4aa0,0x4ace,0x4ad0,0x4ad1,0x4acb,0x9840,0x4ad2,0x9847,0x4ad3,0x98b7,
122.2890 +    0x4b20,0x4b4e,0x4b4b,0x4b72,0x4b70,0x99a2,0x4b92,0x4b8f,0x9a00,0x99f3,
122.2891 +    0x4b90,UBOGON,0x99f5,0x4bd9,0x4bd5,0x9abd,0x9b00,0x9b02,0x4bfa,0x9b34,
122.2892 +    0x9b49,0x9b9f,0x4c4b,0x9ba3,0x9bcd,0x9b99,0x9b9d,0x4cd0,0x4cce,0x9d39,
122.2893 +    0x4ccf,0x9d44,0x4cc4,0x4ccc,0x9d35,0x4cd2,0x4d35,0x9eaf,0x3e03,0x512f,
122.2894 +    0x349e,0x34af,0x9f8e,0x360c,0x569f,0x569b,0x569e,0x5696,0x5694,0x56a0,
122.2895 +    0x367c,0x5b3b,0x3730,0x3731,0x5b3a,0x5dc1,0x5f4d,0x5f5d,0x61f3,0x39a1,
122.2896 +    0x399e,0x3a68,0x3a61,0x64f6,0x64e5,0x64ea,0x64e7,0x6505,0x3a65,0x64f9,
122.2897 +    0x3a66,0x3a6a,0x3aab,0x6aab,0x6aed,0x6ab2,0x6ab0,0x6ab5,0x6abe,0x6ac1,
122.2898 +    0x6ac8,0x3bf9,0x6ac0,0x6abc
122.2899 +  },
122.2900 +  {				/* ku 38 */
122.2901 +    0x6ab1,0x6ac4,0x6abf,0x3c58,0x3c8a,0x7008,0x7003,0x6ffd,0x7010,0x7002,
122.2902 +    0x7013,0x3e04,0x71fa,0x7200,0x74b9,0x74bc,0x3f02,0x765b,0x7651,0x764f,
122.2903 +    0x76eb,0x77b8,0x4079,0x77b9,0x77c1,0x77c0,0x77be,0x790b,0x40eb,0x7907,
122.2904 +    0x790a,0x7908,0x40e9,0x790d,0x7906,0x7915,0x79af,0x4120,0x4121,0x4181,
122.2905 +    0x7af5,0x424d,0x4259,0x7c2e,0x4258,0x7c1b,UBOGON,0x7c1a,0x7c24,0x42a5,
122.2906 +    0x42a9,0x7ce6,0x7ce3,0x431a,0x4319,0x7e5d,0x7e4f,0x7e66,0x7e5b,0x7f47,
122.2907 +    0x7fb4,0x4396,0x4398,0x4397,0x7ffa,0x802e,UBOGON,0x43c8,0x81ce,0x4443,
122.2908 +    0x4445,0x8219,0x4552,0x4557,0x85cc,0x85b2,0x4555,0x85bb,0x85c1,0x4556,
122.2909 +    0x4558,0x45f2,0x87e9,0x87ee,0x87f0,0x87d6,0x880e,0x87da,0x8948,0x894a,
122.2910 +    0x894e,0x894d,0x89b1,0x89b0
122.2911 +  },
122.2912 +  {				/* ku 39 */
122.2913 +    0x89b3,0x4707,0x8b38,0x8b32,0x4708,0x8b2d,0x470a,0x8b34,0x431b,0x8b29,
122.2914 +    0x8c74,0x4761,0x4762,0x8d03,0x47c2,0x47c6,0x8da9,0x8e58,0x481e,0x4825,
122.2915 +    0x8ebf,0x8ec1,0x8f4a,0x8fac,0x48b0,0x9089,0x913d,0x913c,0x91a9,0x93a0,
122.2916 +    0x493d,0x9390,0x493e,0x9393,0x938b,0x93ad,0x93bb,0x93b8,0x4946,0x4945,
122.2917 +    0x939c,0x95d8,0x95d7,0x4a03,0x4a26,0x4a27,0x975d,0x97a9,0x97da,0x4a98,
122.2918 +    0x4aad,0x4ad5,0x4ada,0x9854,0x4ad9,0x9855,0x984b,0x4add,0x983f,0x98b9,
122.2919 +    0x4b15,0x4b16,0x4b17,0x4b21,0x9938,0x9936,0x9940,0x4b4c,0x993b,0x9939,
122.2920 +    0x99a4,0x4b96,0x4b98,0x9a08,0x9a0c,0x4b9b,0x9a10,0x4bff,0x9b07,0x4c25,
122.2921 +    0x9bd2,0x4c4f,0x9bc2,0x9bbb,0x9bcc,0x9bcb,0x4c56,0x4c54,0x9d4d,0x9d63,
122.2922 +    0x9d4e,0x4cd8,0x9d50,0x9d55
122.2923 +  },
122.2924 +  {				/* ku 3a */
122.2925 +    0x4cd7,0x9d5e,0x4d26,0x9e90,0x9eb2,0x9eb1,0x4d38,0x9eca,0x9f02,0x9f27,
122.2926 +    0x9f26,0x4d8a,0x56af,0x58e0,0x58dc,0x3734,0x5b39,0x3735,UBOGON,0x5b7c,
122.2927 +    0x5bf3,UBOGON,0x37a1,0x5c6b,0x5dc4,0x650b,0x6508,0x650a,0x3a6c,0x3a6d,
122.2928 +    0x65dc,0x3b29,0x3b2a,0x66e1,0x66df,0x6ace,0x6ad4,0x6ae3,0x6ad7,0x6ae2,
122.2929 +    0x3c00,0x3c08,0x3c06,0x3c05,0x6ad8,0x6ad5,0x6ad2,0x3cb1,0x3d88,0x701e,
122.2930 +    0x702c,0x7025,0x6ff3,0x7204,0x7208,0x7215,0x3e09,0x74c4,0x74c9,0x74c7,
122.2931 +    0x74c8,0x76a9,0x77c6,0x77c5,0x7918,0x791a,0x7920,0x4122,0x7a66,0x7a64,
122.2932 +    0x7a6a,0x41d5,0x4261,0x425d,0x4262,0x424f,0x4260,0x7c35,0x7c34,0x42aa,
122.2933 +    0x4322,0x7e6c,0x4321,0x7e6e,0x7e71,0x4446,0x81d4,0x81d6,0x821a,0x8262,
122.2934 +    0x8265,0x8276,0x85db,0x85d6
122.2935 +  },
122.2936 +  {				/* ku 3b */
122.2937 +    0x4562,0x85e7,0x4560,0x4564,0x85f4,UBOGON,0x87fd,0x87d5,0x8807,0x45f6,
122.2938 +    0x880f,0x87f8,UBOGON,0x4619,0x8987,0x4691,0x89b5,0x89f5,0x470d,0x8b3f,
122.2939 +    0x8b43,0x8b4c,0x4765,0x8d0b,0x8e6b,0x8e68,0x8e70,0x8e75,0x8e77,0x483f,
122.2940 +    0x8ec3,0x494b,0x93e9,0x93ea,0x93cb,0x93c5,0x93c6,0x4948,0x93ed,0x93d3,
122.2941 +    0x4952,0x93e5,0x494a,0x4951,0x93db,0x93eb,0x93e0,0x93c1,0x4950,0x494c,
122.2942 +    0x95dd,0x49ee,0x4a04,0x4a06,0x4a2d,0x4a2e,0x4a2f,0x4a7b,0x4a78,0x4a77,
122.2943 +    0x97b2,0x97b4,0x97b1,0x97b5,0x97f2,0x4aa2,0x4aa1,0x4ae3,0x9856,0x4b1a,
122.2944 +    0x4b19,0x4b57,0x9944,0x4b9e,0x9a26,0x9a1f,0x9a18,0x9a21,0x9a17,0x4bdd,
122.2945 +    0x9b09,0x4c05,0x4c28,0x9bc5,0x9bdf,0x4c60,0x9be3,0x4c66,0x9be9,0x9bee,
122.2946 +    0x4c67,0x4c68,0x9d66,0x9d7a
122.2947 +  },
122.2948 +  {				/* ku 3c */
122.2949 +    0x4cde,0x9d6e,0x9d91,0x9d83,0x9d76,0x9d7e,0x9d6d,0x4ce1,0x9e95,0x9ee3,
122.2950 +    0x4d69,0x4d77,0x9f03,0x9f04,UBOGON,0x9f17,0x34a6,0x5136,0x34a5,0x5336,
122.2951 +    0x3614,0x5b42,0x3736,0x3738,0x5b44,0x5b46,0x5b7e,0x5dca,0x5dc8,0x5dcc,
122.2952 +    0x5ef0,0x3a70,0x6585,0x66e5,0x66e7,0x3b2b,0x3c11,0x3c0a,0x6af4,0x3c0d,
122.2953 +    0x6ae9,0x3c16,0x3c10,0x3c09,0x3c0e,0x3c7a,0x703d,0x3d8c,0x7036,0x3d91,
122.2954 +    0x7216,0x3e0a,0x7212,0x720f,0x7217,0x7211,0x720b,0x3e08,0x3e0b,0x74cd,
122.2955 +    0x74d0,0x74cc,0x74ce,0x74d1,0x3f07,0x7589,0x40f2,0x7a6f,0x7c4b,0x7c44,
122.2956 +    0x7c55,0x42ae,0x4324,0x4326,0x4327,0x7e7f,0x8b71,0x4399,0x802f,0x807a,
122.2957 +    0x807b,0x807c,0x455f,0x456a,0x4571,0x85fc,0x8610,0x8602,0x456c,0x456f,
122.2958 +    0x85ee,0x8603,0x4568,0x860d
122.2959 +  },
122.2960 +  {				/* ku 3d */
122.2961 +    0x8613,0x8608,0x860f,0x8818,0x8812,0x4601,0x4668,0x8967,0x8965,0x89bb,
122.2962 +    0x8b69,0x8b62,0x4713,0x8b6e,0x4716,0x8b61,0x4718,0x8b64,0x8b4d,0x8c51,
122.2963 +    0x4789,0x47c8,0x8e83,0x8ec6,0x4884,0x941f,0x4954,0x9404,0x9417,0x9408,
122.2964 +    0x9405,0x4956,0x93f3,0x941e,0x9402,0x941a,0x941b,0x9427,0x941c,0x495a,
122.2965 +    0x96b5,0x4a05,0x4a07,0x9733,0x4a31,0x9734,0x9731,0x97b8,0x97ba,0x4aa3,
122.2966 +    0x97fc,0x4aeb,0x4b1c,0x98c3,0x4b5a,0x994d,0x4b5b,0x9a2f,0x4ba6,0x4baa,
122.2967 +    0x4ba5,0x9ac9,0x4be1,0x9ac8,0x9ac4,0x9b2a,0x9b38,0x9b50,0x4c2a,0x9c0a,
122.2968 +    0x9bfb,0x9c04,0x9bfc,0x9bfe,0x4c72,0x4c6f,0x4c73,0x9c02,0x9bf6,0x9c1b,
122.2969 +    0x9bf9,0x9c15,0x9c10,0x9bff,0x9c00,0x9c0c,0x4c6b,0x4ce6,0x9d95,0x9da5,
122.2970 +    0x4ce9,0x4cec,0x4ce8,0x4cf0
122.2971 +  },
122.2972 +  {				/* ku 3e */
122.2973 +    0x9e98,0x9ec1,0x4d8c,0x9f5a,0x5164,0x56bb,0x3615,0x58e6,0x5b49,0x5bf7,
122.2974 +    0x3771,0x3826,0x5dd0,0x38c6,0x5fc2,0x39a8,0x6511,0x3a73,0x6aff,0x6afe,
122.2975 +    0x6afd,0x3c15,0x6b01,0x3d98,0x3d97,0x704b,0x704d,0x7047,0x74d3,0x7668,
122.2976 +    0x7667,0x3fd7,0x4080,0x77d1,0x7930,0x7932,0x792e,0x4188,0x9f9d,0x7ac9,
122.2977 +    0x7ac8,0x4269,0x7c56,0x7c51,0x426b,0x4329,0x4328,0x7e85,0x7e89,0x7e8e,
122.2978 +    0x7e84,0x445f,0x826a,0x862b,0x862f,0x8628,0x4574,0x8616,0x8615,0x861d,
122.2979 +    0x881a,0x4602,0x466a,0x4694,0x89bc,0x8b75,0x8b7c,0x478a,0x8d11,0x8d12,
122.2980 +    0x8f5c,0x91bb,0x4964,0x93f4,0x495e,0x4961,0x942d,0x4965,0x4966,0x96e4,
122.2981 +    0x9737,0x9736,0x9767,0x97be,0x97bd,0x97e2,0x9868,0x9866,0x98c8,0x98ca,
122.2982 +    0x98c7,0x98dc,0x4b5f,0x994f
122.2983 +  },
122.2984 +  {				/* ku 3f */
122.2985 +    0x99a9,0x9a3c,0x4baf,0x9a3b,0x9ace,0x4c0d,0x9b14,0x9b53,0x4c7c,0x9c2e,
122.2986 +    0x4c7a,0x9c1f,0x4c76,0x4c79,0x4c7d,0x4c77,0x9db0,0x9dbd,0x4cf6,0x4cf1,
122.2987 +    0x9dae,0x9dc4,0x9e7b,0x400b,0x4d29,0x9e9e,0x4d6f,0x9f05,0x4d9a,0x9f69,
122.2988 +    0x9fa1,0x56c7,0x571d,0x5b4a,0x5dd3,0x3869,0x5f72,0x6202,0x39ab,0x6235,
122.2989 +    0x6527,0x651e,0x651f,0x3b2c,0x3b2d,0x6b07,0x6b06,0x3c17,0x3d9a,0x7054,
122.2990 +    0x721c,0x7220,0x7af8,0x426e,0x7c5d,0x7c58,0x432c,0x7e92,0x7f4e,0x43ca,
122.2991 +    0x4578,0x4606,0x8827,0x4607,0x8b81,0x8b83,0x4720,0x8c44,0x4753,0x47ce,
122.2992 +    0x487a,0x4879,0x9442,0x944d,0x9454,0x944e,0x496b,0x9443,0x4967,0x496d,
122.2993 +    0x973c,0x9740,0x97c0,0x4a85,0x4ab0,0x4af3,0x4b63,0x995a,0x9a51,0x4bb6,
122.2994 +    0x9add,0x4c82,0x4c7f,0x9c38
122.2995 +  },
122.2996 +  {				/* ku 40 */
122.2997 +    0x4c86,0x9c45,0x9c3a,0x4c84,0x9c35,0x4cfc,0x4cfd,0x4cfa,0x9ef1,0x4d87,
122.2998 +    0x9f93,0x529a,0x361a,0x3619,0x8641,0x5dd7,0x3a75,0x6528,0x3c1a,0x3c1b,
122.2999 +    0x3c19,0x7053,0x7059,0x3d9c,0x7221,0x3e10,0x766f,0x7937,0x79b5,0x7c62,
122.3000 +    0x7c5e,0x7cf5,0x457b,0x457c,0x863d,0x4608,0x882d,0x8989,0x8b8d,0x8b87,
122.3001 +    0x8b90,0x8d1a,0x8e99,0x4841,0x48e3,0x4972,0x945f,0x4973,0x4968,0x9456,
122.3002 +    0x9461,0x945b,0x945a,0x945c,0x9465,0x4a35,0x9741,0x4a88,0x4a9d,0x986e,
122.3003 +    0x986c,0x986d,0x4275,0x99aa,0x9a5c,0x9a58,0x9ade,0x4c8f,0x9c4f,0x9c51,
122.3004 +    0x4c8e,0x9c53,0x4d05,0x4d04,0x4cff,0x9dfc,0x9f39,0x4d9e,0x513e,0x3554,
122.3005 +    0x56d2,0x3681,0x5b4f,0x6b14,0x40fa,0x7a72,0x7a73,0x4332,0x4670,0x466e,
122.3006 +    0x8b91,UBOGON,0x487c,0x91bf
122.3007 +  },
122.3008 +  {				/* ku 41 */
122.3009 +    0x4975,0x946c,0x4974,0x4977,0x96e6,0x9745,0x4a37,0x97c8,0x97e4,0x995d,
122.3010 +    0x4bba,0x9b21,0x4c11,0x9b2c,0x9b57,0x4c92,0x4c99,0x9c5d,0x9c61,0x9c65,
122.3011 +    0x9e08,0x4d0a,0x4d2a,0x4d2b,0x4d44,0x4d79,0x9f45,0x34aa,0x3748,0x6205,
122.3012 +    0x66ef,0x6b1b,0x6b1d,0x7225,0x7224,0x7c6d,0x42b4,0x8642,0x8649,0x460d,
122.3013 +    0x8978,0x898a,0x8b97,0x4754,0x8c9b,0x8d1c,0x4830,0x8ea2,0x4a09,0x4a38,
122.3014 +    0x4a36,0x4a8b,0x4af7,0x4b66,0x4bbd,0x4c1e,0x9c6c,0x4c96,0x9c6f,0x4d0d,
122.3015 +    0x9e0e,0x4d73,0x9f08,0x9f1d,0x9fa3,0x373b,0x373c,0x5f60,0x6b1c,0x3da0,
122.3016 +    0x40fb,UBOGON,0x7cf3,0x4581,0x8b9b,0x8ea7,0x91c4,0x4978,0x947a,0x4a8d,
122.3017 +    0x4b73,0x9a61,0x9a63,0x9ad7,0x9c76,0x4da6,0x9fa5,0x39ad,0x7067,0x3e11,
122.3018 +    0x72ab,0x864a,0x897d,0x8b9d
122.3019 +  },
122.3020 +  {				/* ku 42 */
122.3021 +    0x8c53,0x8f65,0x947b,0x4a39,0x98cd,0x98dd,0x4bbf,0x9b30,0x9e16,0x4d0f,
122.3022 +    0x4da7,0x4db5,0x3fdc,0x4831,0x96e7,0x9e18,0x9ea2,0x4da8,0x9f7c,0x4125,
122.3023 +    0x7e9e,0x9484,0x4bc1,0x9e1c,0x4190,0x7c71,0x97ca,0x4696,0x487f,0x4d10,
122.3024 +    0x9ea3,0x4a0a,0x9c7b,0x9f97,0x4d12,0x4a3a,0x9750,0x4a3b,UBOGON,UBOGON,
122.3025 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3026 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3027 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3030 +    UBOGON,UBOGON,UBOGON,UBOGON
122.3031 +  },
122.3032 +  {				/* ku 43 */
122.3033 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3034 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3035 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3036 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3037 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3038 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3039 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3040 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3041 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3042 +    UBOGON,UBOGON,UBOGON,UBOGON
122.3043 +  },
122.3044 +  {				/* ku 44 */
122.3045 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3046 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3047 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3048 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f66,
122.3049 +    0x4f68,0x4fe7,0x503f,UBOGON,0x50a6,0x510f,0x523e,0x5324,0x5365,0x539b,
122.3050 +    0x517f,0x54cb,0x5573,0x5571,0x556b,0x55f4,0x5622,0x5620,0x5692,0x56ba,
122.3051 +    0x5691,0x56b0,0x5759,0x578a,0x580f,0x5812,0x5813,0x5847,0x589b,0x5900,
122.3052 +    0x594d,0x5ad1,0x5ad3,0x5b67,0x5c57,0x5c77,0x5cd5,0x5d75,0x5d8e,0x5da5,
122.3053 +    0x5db6,0x5dbf,0x5e65,0x5ecd,0x5eed,0x5f94,0x5f9a,0x5fba,0x6125,0x6150,
122.3054 +    0x62a3,0x6360,0x6364,0x63b6
122.3055 +  },
122.3056 +  {				/* ku 45 */
122.3057 +    0x6403,0x64b6,0x651a,0x7a25,0x5c21,0x66e2,0x6702,0x67a4,0x67ac,0x6810,
122.3058 +    0x6806,0x685e,0x685a,0x692c,0x6929,0x6a2d,0x6a77,0x6a7a,0x6aca,0x6ae6,
122.3059 +    0x6af5,0x6b0d,0x6b0e,0x6bdc,0x6bdd,0x6bf6,0x6c1e,0x6c63,0x6da5,0x6e0f,
122.3060 +    0x6e8a,0x6e84,0x6e8b,0x6e7c,0x6f4c,0x6f48,0x6f49,0x6f9d,0x6f99,0x6ff8,
122.3061 +    0x702e,0x702d,0x705c,0x79cc,0x70bf,0x70ea,0x70e5,0x7111,0x7112,0x713f,
122.3062 +    0x7139,0x713b,0x713d,0x7177,0x7175,0x7176,0x7171,0x7196,0x7193,0x71b4,
122.3063 +    0x71dd,0x71de,0x720e,0x5911,0x7218,0x7347,0x7348,0x73ef,0x7412,0x743b,
122.3064 +    0x74a4,0x748d,0x74b4,0x7673,0x7677,0x76bc,0x7819,0x781b,0x783d,0x7853,
122.3065 +    0x7854,0x7858,0x78b7,0x78d8,0x78ee,0x7922,0x794d,0x7986,0x7999,0x79a3,
122.3066 +    0x79bc,0x7aa7,0x7b37,0x7b59
122.3067 +  },
122.3068 +  {				/* ku 46 */
122.3069 +    0x7bd0,0x7c2f,0x7c32,0x7c42,0x7c4e,0x7c68,0x7ca9,0x7ced,0x7dd0,0x7e07,
122.3070 +    0x7dd3,0x7e64,0x7f40,UBOGON,0x8041,0x8063,0x80bb,0x6711,0x6725,0x8248,
122.3071 +    0x8310,0x8362,0x8312,0x8421,0x841e,0x84e2,0x84de,0x84e1,0x8573,0x85d4,
122.3072 +    0x85f5,0x8637,0x8645,0x8672,0x874a,0x87a9,0x87a5,0x87f5,0x8834,0x8850,
122.3073 +    0x8887,0x8954,0x8984,0x8b03,0x8c52,0x8cd8,0x8d0c,0x8d18,0x8db0,0x8ebc,
122.3074 +    0x8ed5,0x8faa,0x909c,UBOGON,0x915c,0x922b,0x9221,0x9273,0x92f4,0x92f5,
122.3075 +    0x933f,0x9342,0x9386,0x93be,0x93bc,0x93bd,0x93f1,0x93f2,0x93ef,0x9422,
122.3076 +    0x9423,0x9424,0x9467,0x9466,0x9597,0x95ce,0x95e7,0x973b,0x974d,0x98e4,
122.3077 +    0x9942,0x9b1d,0x9b98,UBOGON,0x9d49,0x6449,0x5e71,0x5e85,0x61d3,0x990e,
122.3078 +    0x8002,0x781e,UBOGON,UBOGON
122.3079 +  },
122.3080 +  {				/* ku 47 */
122.3081 +    0x5528,0x5572,0x55ba,0x55f0,0x55ee,0x56b8,0x56b9,0x56c4,0x8053,0x92b0,
122.3082 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3083 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3084 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3085 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3086 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3087 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3088 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3089 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3090 +    UBOGON,UBOGON,UBOGON,UBOGON
122.3091 +  }
122.3092 +};
122.3093 +
122.3094 +/* CNS 11643 plane 4 conversion table */
122.3095 +
122.3096 +static const unsigned short
122.3097 + cns11643_4tab[MAX_CNS11643_KU_4][MAX_CNS11643_TEN] = {
122.3098 +  {				/* ku 01 */
122.3099 +    UBOGON,0x4e40,0x4e41,0x4e5a,UBOGON,0x4e02,0x4e29,UBOGON,UBOGON,0x5202,
122.3100 +    0x353e,0x5ddc,UBOGON,UBOGON,UBOGON,0x5342,0x536a,0x5b52,UBOGON,UBOGON,
122.3101 +    UBOGON,0x5fc4,0x624c,0x72ad,0x4e12,0x4e2f,0x4e96,0x4ed0,0x5142,0x5183,
122.3102 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5383,0x53b8,UBOGON,UBOGON,UBOGON,
122.3103 +    0x5928,UBOGON,0x5c23,0x5e01,0x5f00,UBOGON,0x3cb8,0x706c,0x722b,0x5188,
122.3104 +    0x8279,0x8fb6,0x4e17,UBOGON,0x340c,UBOGON,0x3430,0x4ee2,0x4edb,UBOGON,
122.3105 +    UBOGON,0x51ad,UBOGON,0x51f7,0x34da,UBOGON,UBOGON,0x3513,0x531b,0x5388,
122.3106 +    0x5387,UBOGON,0x53cf,0x53fd,0x3563,0x53e7,0x56dc,UBOGON,0x56d9,0x5725,
122.3107 +    0x5727,0x5933,0x5c13,UBOGON,UBOGON,0x5c75,UBOGON,UBOGON,UBOGON,0x39c4,
122.3108 +    0x39c3,0x66f1,UBOGON,UBOGON
122.3109 +  },
122.3110 +  {				/* ku 02 */
122.3111 +    0x7f52,UBOGON,UBOGON,0x3401,UBOGON,UBOGON,0x4e51,0x4e6a,UBOGON,0x4f0c,
122.3112 +    UBOGON,UBOGON,0x4efe,0x4f1b,UBOGON,UBOGON,0x343a,UBOGON,0x34ab,0x5173,
122.3113 +    UBOGON,0x518e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34dd,UBOGON,UBOGON,
122.3114 +    0x52a5,0x3515,0x52a7,0x52a4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53bd,
122.3115 +    UBOGON,UBOGON,UBOGON,0x5402,UBOGON,UBOGON,UBOGON,UBOGON,0x572b,0x591b,
122.3116 +    0x5935,UBOGON,0x36a7,0x36a5,UBOGON,UBOGON,0x36a6,UBOGON,UBOGON,0x5c17,
122.3117 +    0x377c,UBOGON,0x5c70,0x5c7d,0x37a9,UBOGON,0x5de9,UBOGON,0x3834,0x3835,
122.3118 +    UBOGON,UBOGON,UBOGON,0x38a8,0x5f19,0x5f1c,0x5f75,UBOGON,UBOGON,0x38ff,
122.3119 +    0x5fc8,UBOGON,0x39c7,0x39c6,0x39c8,UBOGON,UBOGON,0x3ad0,0x3ad1,UBOGON,
122.3120 +    UBOGON,0x3c59,UBOGON,UBOGON
122.3121 +  },
122.3122 +  {				/* ku 03 */
122.3123 +    0x6c12,0x3cbd,UBOGON,UBOGON,UBOGON,0x3e28,0x72b3,UBOGON,0x3ea9,0x7390,
122.3124 +    0x7536,UBOGON,0x43cc,UBOGON,0x8281,0x8fb8,UBOGON,0x48b4,UBOGON,UBOGON,
122.3125 +    0x4e23,0x3416,0x342c,UBOGON,0x4f2e,UBOGON,0x514f,UBOGON,0x51ba,0x34df,
122.3126 +    0x34e0,0x5222,UBOGON,UBOGON,UBOGON,0x3517,UBOGON,0x52af,0x52b0,0x52b1,
122.3127 +    UBOGON,UBOGON,0x352f,UBOGON,0x5364,UBOGON,0x53d3,UBOGON,0x3574,UBOGON,
122.3128 +    0x3570,0x356d,UBOGON,UBOGON,UBOGON,UBOGON,0x356e,UBOGON,UBOGON,UBOGON,
122.3129 +    UBOGON,0x362b,0x3628,UBOGON,UBOGON,0x593f,UBOGON,UBOGON,0x3692,UBOGON,
122.3130 +    0x598b,UBOGON,0x5991,0x5995,UBOGON,UBOGON,0x373f,UBOGON,0x5b8a,0x374f,
122.3131 +    0x3774,UBOGON,UBOGON,0x377d,UBOGON,0x37b7,0x37a3,0x37b0,0x37b1,0x5c87,
122.3132 +    0x37ab,UBOGON,UBOGON,UBOGON
122.3133 +  },
122.3134 +  {				/* ku 04 */
122.3135 +    0x383a,0x3837,0x5e0d,0x3838,0x3840,UBOGON,UBOGON,0x5e8e,0x389f,UBOGON,
122.3136 +    UBOGON,0x5f7a,UBOGON,0x3904,0x3909,0x3906,0x38fd,0x390a,0x3907,UBOGON,
122.3137 +    UBOGON,0x39ca,UBOGON,UBOGON,0x6290,0x39c9,UBOGON,0x629a,UBOGON,0x653c,
122.3138 +    0x653a,0x3a7f,0x6598,UBOGON,0x3ad2,UBOGON,UBOGON,0x6765,UBOGON,0x3b43,
122.3139 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cc1,UBOGON,0x3cc5,0x3da3,
122.3140 +    UBOGON,UBOGON,0x3e2a,0x3e5f,UBOGON,UBOGON,0x3e5d,UBOGON,UBOGON,UBOGON,
122.3141 +    UBOGON,0x3f17,UBOGON,UBOGON,0x3f71,0x3f72,UBOGON,UBOGON,0x400f,UBOGON,
122.3142 +    UBOGON,0x79c2,0x4191,UBOGON,UBOGON,UBOGON,0x43b2,0x43cf,0x43ce,0x809e,
122.3143 +    UBOGON,UBOGON,0x81eb,UBOGON,0x8289,0x4496,UBOGON,UBOGON,0x8296,UBOGON,
122.3144 +    0x8287,UBOGON,0x4497,UBOGON
122.3145 +  },
122.3146 +  {				/* ku 05 */
122.3147 +    0x8fc0,0x488b,0x8fc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3148 +    0x9578,UBOGON,UBOGON,0x9625,UBOGON,0x4e75,0x4e74,UBOGON,UBOGON,0x342d,
122.3149 +    UBOGON,0x4f99,UBOGON,0x3450,0x344b,UBOGON,0x344f,0x344c,UBOGON,0x4f71,
122.3150 +    0x5153,0x51bf,UBOGON,UBOGON,0x51c0,UBOGON,0x51ee,UBOGON,0x34e4,0x34e3,
122.3151 +    UBOGON,0x34e1,UBOGON,0x34e2,UBOGON,0x523d,0x3519,0x52bd,0x530c,UBOGON,
122.3152 +    UBOGON,UBOGON,UBOGON,0x3541,0x7f37,UBOGON,0x53c0,0x355e,UBOGON,UBOGON,
122.3153 +    0x3579,UBOGON,0x546e,0x5483,UBOGON,UBOGON,0x545e,0x545d,0x577e,0x5779,
122.3154 +    UBOGON,0x577a,0x576c,UBOGON,UBOGON,UBOGON,0x3632,0x5787,UBOGON,0x591d,
122.3155 +    0x3694,0x5946,0x3697,UBOGON,0x5943,UBOGON,0x3696,0x3698,UBOGON,UBOGON,
122.3156 +    0x36b2,UBOGON,UBOGON,UBOGON
122.3157 +  },
122.3158 +  {				/* ku 06 */
122.3159 +    0x36b9,0x5b61,0x5b66,UBOGON,0x5b90,0x3775,0x377f,0x377e,0x5c29,0x378f,
122.3160 +    UBOGON,UBOGON,UBOGON,0x37bd,0x5cb2,UBOGON,0x37bb,0x37bc,UBOGON,0x5cc0,
122.3161 +    UBOGON,0x383d,0x383e,0x3874,UBOGON,0x387a,0x3876,0x3878,0x3875,UBOGON,
122.3162 +    UBOGON,0x38af,0x38b0,0x38c7,0x38cc,UBOGON,UBOGON,0x3916,UBOGON,0x3912,
122.3163 +    0x391d,UBOGON,UBOGON,0x3915,0x390f,0x3914,0x601f,0x5fe2,UBOGON,UBOGON,
122.3164 +    UBOGON,0x39b0,0x39bf,0x39c0,UBOGON,0x39d2,0x39d9,UBOGON,0x3a7a,UBOGON,
122.3165 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6616,0x65f9,0x3ada,UBOGON,0x6788,UBOGON,
122.3166 +    0x679b,UBOGON,0x676e,0x679e,UBOGON,0x3c22,0x3c1f,UBOGON,UBOGON,0x3c21,
122.3167 +    0x6b24,UBOGON,UBOGON,UBOGON,0x3c5c,0x6b7d,UBOGON,0x3c7d,0x3c8d,0x3c8f,
122.3168 +    0x6ce6,UBOGON,0x6ccb,0x3cd0
122.3169 +  },
122.3170 +  {				/* ku 07 */
122.3171 +    UBOGON,0x3cd8,UBOGON,UBOGON,UBOGON,0x6cb5,0x3da7,UBOGON,0x7097,UBOGON,
122.3172 +    0x709b,0x3e12,UBOGON,UBOGON,0x3e2f,UBOGON,0x726b,0x3e2e,0x3e2c,0x3e5c,
122.3173 +    UBOGON,0x72d5,UBOGON,UBOGON,0x3e62,0x3e67,0x3eb4,UBOGON,UBOGON,UBOGON,
122.3174 +    UBOGON,0x7543,UBOGON,UBOGON,0x759c,UBOGON,UBOGON,0x3fea,UBOGON,0x3ffb,
122.3175 +    UBOGON,0x4014,UBOGON,0x4013,0x4012,0x4010,0x4011,UBOGON,0x4086,0x77e4,
122.3176 +    0x4098,UBOGON,UBOGON,0x412a,UBOGON,UBOGON,UBOGON,UBOGON,0x7ace,0x42b5,
122.3177 +    UBOGON,UBOGON,UBOGON,UBOGON,0x8013,0x43d6,0x43d8,0x80b7,0x43d9,0x43d4,
122.3178 +    0x43d7,UBOGON,0x80b9,UBOGON,UBOGON,0x81e4,0x81fd,0x820f,0x4460,UBOGON,
122.3179 +    UBOGON,0x449e,0x44a1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82bf,
122.3180 +    0x82ca,UBOGON,UBOGON,0x82c1
122.3181 +  },
122.3182 +  {				/* ku 08 */
122.3183 +    0x44a0,UBOGON,UBOGON,UBOGON,UBOGON,0x8fd0,UBOGON,UBOGON,0x48b9,UBOGON,
122.3184 +    0x90ae,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x49c1,0x49c2,0x9638,UBOGON,
122.3185 +    0x341c,UBOGON,0x345e,0x4fbc,0x3459,0x345c,UBOGON,0x345f,0x4fe9,0x4fbd,
122.3186 +    0x4fe2,0x5158,UBOGON,UBOGON,0x34ce,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3187 +    0x52c6,UBOGON,0x52c8,UBOGON,UBOGON,0x5328,UBOGON,0x5329,UBOGON,UBOGON,
122.3188 +    UBOGON,UBOGON,UBOGON,UBOGON,0x355f,UBOGON,0x3585,UBOGON,UBOGON,0x3586,
122.3189 +    UBOGON,0x57b4,UBOGON,0x57a9,0x3687,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3190 +    0x36ca,UBOGON,0x36c3,UBOGON,UBOGON,UBOGON,0x36c2,0x5b68,UBOGON,0x3741,
122.3191 +    UBOGON,UBOGON,UBOGON,0x3780,0x3781,UBOGON,UBOGON,0x3793,0x3792,UBOGON,
122.3192 +    0x37c5,UBOGON,UBOGON,UBOGON
122.3193 +  },
122.3194 +  {				/* ku 09 */
122.3195 +    0x3846,0x3841,0x3845,0x3842,0x383f,UBOGON,UBOGON,0x3882,0x3881,0x387f,
122.3196 +    0x38a5,0x5f2b,0x38b3,0x38b5,UBOGON,UBOGON,0x5f8d,0x38da,UBOGON,0x38db,
122.3197 +    0x390d,0x6018,0x390e,UBOGON,0x391e,0x3925,0x3926,0x391c,0x3921,0x6057,
122.3198 +    0x6048,0x3927,0x391a,UBOGON,UBOGON,UBOGON,0x6038,UBOGON,UBOGON,0x3924,
122.3199 +    UBOGON,UBOGON,0x6071,UBOGON,0x39c1,0x39e1,UBOGON,UBOGON,0x6312,0x39eb,
122.3200 +    UBOGON,0x39e2,0x39d7,0x39e9,UBOGON,UBOGON,0x630a,UBOGON,0x6323,UBOGON,
122.3201 +    0x3a84,UBOGON,UBOGON,UBOGON,0x3ab5,0x3abc,0x3adc,0x3ade,0x3adf,UBOGON,
122.3202 +    0x662a,UBOGON,UBOGON,UBOGON,UBOGON,0x3b54,0x67e0,0x67be,0x3b53,0x3c24,
122.3203 +    0x3c25,0x6b29,0x3c28,0x3c27,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3204 +    0x3c8b,UBOGON,UBOGON,0x3cdc
122.3205 +  },
122.3206 +  {				/* ku 0a */
122.3207 +    0x6d43,UBOGON,UBOGON,UBOGON,UBOGON,0x70a6,0x3db2,0x70c0,UBOGON,0x722f,
122.3208 +    UBOGON,0x3e1b,UBOGON,0x3e32,0x7271,UBOGON,UBOGON,0x3e6b,UBOGON,0x3e6c,
122.3209 +    0x3e6d,UBOGON,0x3eb9,0x3eba,0x3f09,0x3f0a,UBOGON,0x74ea,0x3f1b,UBOGON,
122.3210 +    UBOGON,0x7520,0x3f58,UBOGON,0x3f5a,UBOGON,UBOGON,0x3f77,UBOGON,UBOGON,
122.3211 +    0x3f79,0x75a9,UBOGON,0x7685,UBOGON,0x3feb,UBOGON,0x3ffd,0x3ffc,0x7706,
122.3212 +    0x4015,0x4018,0x76f6,0x4016,0x4017,0x4019,0x7700,0x401b,UBOGON,UBOGON,
122.3213 +    0x7702,UBOGON,0x4087,UBOGON,UBOGON,0x409c,UBOGON,0x409a,UBOGON,0x40ff,
122.3214 +    0x40fe,UBOGON,0x4131,0x412e,0x4130,0x4132,UBOGON,UBOGON,0x412f,UBOGON,
122.3215 +    0x4195,0x4196,UBOGON,UBOGON,UBOGON,0x41c5,0x427a,UBOGON,0x4342,UBOGON,
122.3216 +    0x4354,UBOGON,UBOGON,UBOGON
122.3217 +  },
122.3218 +  {				/* ku 0b */
122.3219 +    UBOGON,UBOGON,UBOGON,UBOGON,0x8009,UBOGON,0x439f,0x43a0,0x43a2,0x43e0,
122.3220 +    UBOGON,0x43e1,UBOGON,UBOGON,0x43df,UBOGON,UBOGON,0x4462,0x4461,UBOGON,
122.3221 +    UBOGON,0x44a7,UBOGON,UBOGON,UBOGON,0x82da,UBOGON,UBOGON,0x830a,0x4589,
122.3222 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x461d,UBOGON,UBOGON,
122.3223 +    0x472a,UBOGON,UBOGON,0x47d3,0x4842,0x4843,UBOGON,0x4891,UBOGON,UBOGON,
122.3224 +    0x4890,0x48bf,UBOGON,0x48bc,UBOGON,0x48c0,0x49c7,0x49c5,0x9655,UBOGON,
122.3225 +    0x9652,0x4e35,UBOGON,UBOGON,0x5034,0x5001,UBOGON,0x500a,0x3466,UBOGON,
122.3226 +    UBOGON,UBOGON,0x34ad,UBOGON,UBOGON,UBOGON,UBOGON,0x5258,UBOGON,UBOGON,
122.3227 +    UBOGON,UBOGON,UBOGON,UBOGON,0x351d,UBOGON,0x3531,0x532b,UBOGON,0x354c,
122.3228 +    UBOGON,UBOGON,0x3595,0x3591
122.3229 +  },
122.3230 +  {				/* ku 0c */
122.3231 +    0x3594,UBOGON,UBOGON,UBOGON,0x358f,0x54ec,UBOGON,0x5515,0x54fe,UBOGON,
122.3232 +    UBOGON,UBOGON,0x54e3,0x5516,0x3640,UBOGON,0x3641,UBOGON,0x57d3,UBOGON,
122.3233 +    UBOGON,UBOGON,UBOGON,0x5959,0x5a27,0x36d8,0x36d2,0x36da,0x5a28,0x5a10,
122.3234 +    0x36d7,0x5a0e,0x3742,0x3757,UBOGON,UBOGON,UBOGON,0x5baf,UBOGON,0x5bba,
122.3235 +    0x5bb1,UBOGON,UBOGON,0x3778,0x3782,0x3797,UBOGON,UBOGON,0x37c9,UBOGON,
122.3236 +    0x37c8,0x37d6,0x37cc,UBOGON,0x37d0,UBOGON,UBOGON,0x37ce,0x37c7,0x5cfc,
122.3237 +    UBOGON,0x37cf,0x37cb,0x5cf2,0x5cfe,UBOGON,UBOGON,0x5df8,UBOGON,0x3847,
122.3238 +    UBOGON,0x3848,UBOGON,UBOGON,0x3883,0x3885,0x3884,UBOGON,UBOGON,0x5f2c,
122.3239 +    0x38b8,0x38bc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3240 +    UBOGON,UBOGON,UBOGON,UBOGON
122.3241 +  },
122.3242 +  {				/* ku 0d */
122.3243 +    UBOGON,0x3931,0x3934,0x3936,0x6082,UBOGON,UBOGON,0x3923,UBOGON,UBOGON,
122.3244 +    0x393a,0x6091,0x608f,UBOGON,0x39b4,0x39b5,0x39ed,0x39ec,0x39d8,UBOGON,
122.3245 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39f6,0x39e7,UBOGON,UBOGON,
122.3246 +    0x3a7c,0x3a7b,UBOGON,UBOGON,0x6547,0x654c,UBOGON,UBOGON,0x658a,UBOGON,
122.3247 +    0x3abe,UBOGON,0x3ae7,0x3ae5,0x3aee,0x67e1,0x684a,UBOGON,0x3b59,0x3b5e,
122.3248 +    UBOGON,0x3b5a,0x683f,0x3b61,0x3b58,0x3b5b,0x67bd,UBOGON,0x3b5f,UBOGON,
122.3249 +    0x3c2a,0x3c2d,UBOGON,0x3c23,0x3c2b,0x3c2c,UBOGON,0x3c7e,UBOGON,0x3c93,
122.3250 +    0x3c99,UBOGON,UBOGON,0x3cb3,0x3ce7,0x3cea,UBOGON,UBOGON,UBOGON,UBOGON,
122.3251 +    UBOGON,UBOGON,0x3db4,UBOGON,0x70c9,0x3e17,UBOGON,UBOGON,UBOGON,0x3e21,
122.3252 +    UBOGON,0x3e38,0x3e37,0x3e74
122.3253 +  },
122.3254 +  {				/* ku 0e */
122.3255 +    0x3e73,0x3e75,UBOGON,UBOGON,UBOGON,0x3e76,0x3e78,UBOGON,UBOGON,0x73ba,
122.3256 +    0x3f0c,0x3f20,0x3f1e,UBOGON,0x3f5b,UBOGON,0x3f5c,UBOGON,0x3f83,0x75c6,
122.3257 +    0x3f80,0x3f81,0x3f7e,0x3f88,0x3f85,0x3f89,0x3f7f,0x3f8e,UBOGON,UBOGON,
122.3258 +    0x3f84,0x75b7,0x768c,UBOGON,0x768d,UBOGON,0x3fee,0x3fed,0x3ffe,UBOGON,
122.3259 +    0x3fff,UBOGON,UBOGON,UBOGON,0x4023,UBOGON,0x7717,UBOGON,0x771c,0x401f,
122.3260 +    UBOGON,UBOGON,0x7714,UBOGON,0x408f,0x4090,UBOGON,UBOGON,UBOGON,0x40a0,
122.3261 +    UBOGON,0x40a6,0x409f,UBOGON,0x40a7,0x40a1,UBOGON,0x4102,0x4136,UBOGON,
122.3262 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41c8,UBOGON,UBOGON,0x41d8,
122.3263 +    0x7b0c,0x41dd,0x41dc,UBOGON,0x41d7,UBOGON,0x41da,0x42ba,UBOGON,UBOGON,
122.3264 +    UBOGON,0x42be,0x42c2,0x42bb
122.3265 +  },
122.3266 +  {				/* ku 0f */
122.3267 +    0x42c0,UBOGON,UBOGON,UBOGON,0x7d23,UBOGON,UBOGON,UBOGON,0x4343,0x4355,
122.3268 +    UBOGON,UBOGON,0x4357,0x4368,0x7f98,0x7f90,UBOGON,UBOGON,UBOGON,UBOGON,
122.3269 +    UBOGON,UBOGON,UBOGON,0x43a1,UBOGON,0x803a,UBOGON,UBOGON,UBOGON,UBOGON,
122.3270 +    0x43ea,UBOGON,0x43e7,UBOGON,UBOGON,UBOGON,UBOGON,0x43e8,0x43e9,UBOGON,
122.3271 +    UBOGON,0x4454,UBOGON,UBOGON,UBOGON,UBOGON,0x8226,0x4465,UBOGON,UBOGON,
122.3272 +    0x448a,UBOGON,0x44b0,UBOGON,UBOGON,UBOGON,0x44bc,0x832e,UBOGON,0x8355,
122.3273 +    0x831a,0x44b8,0x833d,UBOGON,0x44b2,UBOGON,0x8330,0x44bd,UBOGON,UBOGON,
122.3274 +    0x458a,0x8651,0x45a1,UBOGON,0x45a2,UBOGON,0x8688,UBOGON,0x4615,UBOGON,
122.3275 +    UBOGON,0x4620,0x4673,UBOGON,0x898e,0x898d,UBOGON,UBOGON,UBOGON,UBOGON,
122.3276 +    UBOGON,0x8a09,0x8a14,0x46b1
122.3277 +  },
122.3278 +  {				/* ku 10 */
122.3279 +    UBOGON,UBOGON,0x472b,UBOGON,0x4745,UBOGON,0x4797,0x4798,UBOGON,0x47d5,
122.3280 +    UBOGON,UBOGON,0x4893,0x4896,0x9007,0x4894,UBOGON,UBOGON,0x48c7,0x48c5,
122.3281 +    UBOGON,UBOGON,UBOGON,0x48c4,UBOGON,0x9579,0x9584,0x49ce,0x49ca,0x49cc,
122.3282 +    0x9657,0x49c9,0x96ba,UBOGON,UBOGON,UBOGON,0x346e,UBOGON,0x5067,UBOGON,
122.3283 +    UBOGON,0x3471,UBOGON,0x34bb,0x34d3,UBOGON,UBOGON,UBOGON,UBOGON,0x34f3,
122.3284 +    0x34ed,0x34f5,UBOGON,UBOGON,0x34f1,0x34f2,0x34f6,0x3520,UBOGON,0x3528,
122.3285 +    UBOGON,0x5318,0x532c,0x5359,UBOGON,UBOGON,UBOGON,0x5368,0x537e,UBOGON,
122.3286 +    UBOGON,0x53a1,UBOGON,0x35a1,0x555b,0x35aa,0x35a9,UBOGON,0x35b5,0x35a5,
122.3287 +    0x35a8,0x5542,0x35a7,0x5547,UBOGON,UBOGON,0x553d,UBOGON,UBOGON,0x5560,
122.3288 +    0x57eb,UBOGON,UBOGON,UBOGON
122.3289 +  },
122.3290 +  {				/* ku 11 */
122.3291 +    0x364d,UBOGON,UBOGON,UBOGON,0x369c,0x595f,UBOGON,0x36ea,0x36e5,UBOGON,
122.3292 +    UBOGON,0x5b6f,UBOGON,0x375e,UBOGON,UBOGON,UBOGON,0x3786,0x3784,UBOGON,
122.3293 +    0x5c5a,UBOGON,0x37d9,UBOGON,0x37de,UBOGON,UBOGON,UBOGON,0x37db,UBOGON,
122.3294 +    UBOGON,UBOGON,UBOGON,0x3831,UBOGON,UBOGON,0x384b,UBOGON,0x3849,0x384a,
122.3295 +    0x384c,UBOGON,UBOGON,0x388a,UBOGON,0x3889,0x388b,UBOGON,0x38bb,0x5fa2,
122.3296 +    0x5f9d,0x38e4,UBOGON,UBOGON,0x5fa3,UBOGON,UBOGON,0x393b,0x392e,0x393e,
122.3297 +    0x3946,0x3953,UBOGON,0x3944,UBOGON,0x393f,0x3942,0x394f,UBOGON,0x3952,
122.3298 +    0x394a,0x60c2,UBOGON,0x395a,0x60a5,0x3949,UBOGON,0x621c,UBOGON,0x621d,
122.3299 +    0x3a03,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6395,0x639a,0x3a01,0x3a06,
122.3300 +    0x39fb,0x39f9,UBOGON,0x3a05
122.3301 +  },
122.3302 +  {				/* ku 12 */
122.3303 +    0x39fa,UBOGON,0x63a6,UBOGON,0x39fe,UBOGON,0x3a7d,UBOGON,UBOGON,UBOGON,
122.3304 +    0x6550,UBOGON,UBOGON,UBOGON,0x6552,UBOGON,UBOGON,UBOGON,UBOGON,0x65c8,
122.3305 +    UBOGON,0x3af0,0x3af2,UBOGON,0x6658,0x3af1,0x3ae6,UBOGON,UBOGON,UBOGON,
122.3306 +    0x6888,UBOGON,0x3b6f,0x3b6d,0x3b69,UBOGON,UBOGON,0x3b6e,UBOGON,0x3c2f,
122.3307 +    0x3c30,0x3c63,UBOGON,UBOGON,UBOGON,0x6bb8,0x3c80,0x6bb9,0x3c9a,0x3c94,
122.3308 +    0x3c96,0x3c95,0x3c97,UBOGON,0x3cf4,0x3cfe,UBOGON,0x3d01,UBOGON,0x3d02,
122.3309 +    UBOGON,0x3cf9,UBOGON,UBOGON,UBOGON,UBOGON,0x3cf6,0x3cf7,UBOGON,UBOGON,
122.3310 +    UBOGON,0x3cff,UBOGON,UBOGON,UBOGON,UBOGON,0x6e0b,UBOGON,UBOGON,0x3dbf,
122.3311 +    0x3dbc,0x7105,UBOGON,UBOGON,UBOGON,0x3dbe,0x3dc0,UBOGON,0x3e3b,0x3e39,
122.3312 +    UBOGON,UBOGON,UBOGON,0x3e3c
122.3313 +  },
122.3314 +  {				/* ku 13 */
122.3315 +    UBOGON,0x7314,0x7304,UBOGON,0x3e7d,UBOGON,0x3e7f,0x3e7a,0x3e7c,0x7305,
122.3316 +    0x3e7e,0x7315,0x730d,0x3e80,0x3ebf,0x3ec3,UBOGON,UBOGON,0x3ecc,0x3f0e,
122.3317 +    0x3f0d,UBOGON,0x3f26,0x3f24,0x3f25,0x3f23,0x3f21,0x3f29,UBOGON,UBOGON,
122.3318 +    0x3f8f,0x3f8d,UBOGON,0x3f8b,0x3f92,UBOGON,0x3f90,UBOGON,0x3fef,0x3ff0,
122.3319 +    UBOGON,UBOGON,0x4001,UBOGON,0x402e,0x402d,0x772e,0x4028,0x4029,0x402c,
122.3320 +    UBOGON,UBOGON,UBOGON,0x7741,0x4088,UBOGON,0x4092,0x4091,0x77ea,UBOGON,
122.3321 +    0x7844,0x40a9,0x40ac,0x40ae,0x40aa,0x4106,0x4105,0x414a,0x413e,0x413c,
122.3322 +    0x413b,UBOGON,0x4142,0x4141,0x4143,UBOGON,0x4145,UBOGON,0x419a,0x419b,
122.3323 +    0x419f,0x419e,UBOGON,UBOGON,UBOGON,0x41de,0x41e2,0x41e6,UBOGON,0x7b29,
122.3324 +    0x41e3,0x7b27,0x41df,UBOGON
122.3325 +  },
122.3326 +  {				/* ku 14 */
122.3327 +    UBOGON,0x7c9d,UBOGON,UBOGON,0x427e,0x42c9,0x42cc,UBOGON,0x42d1,UBOGON,
122.3328 +    0x42d0,UBOGON,0x42cf,0x42c8,UBOGON,0x42cd,UBOGON,UBOGON,0x4349,0x4347,
122.3329 +    0x4358,0x436b,0x436c,0x436a,UBOGON,0x4380,0x4382,0x4384,0x7fc8,0x4383,
122.3330 +    UBOGON,UBOGON,0x43b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8126,0x43f1,
122.3331 +    UBOGON,0x43f6,0x43f3,0x43f0,0x811c,UBOGON,UBOGON,0x8128,0x43f5,0x43f4,
122.3332 +    0x43f7,UBOGON,UBOGON,UBOGON,UBOGON,0x4455,UBOGON,UBOGON,UBOGON,0x448b,
122.3333 +    0x44cb,0x44c2,UBOGON,UBOGON,UBOGON,0x44ca,0x44cc,UBOGON,0x44c7,0x44c9,
122.3334 +    0x8370,UBOGON,0x44c6,UBOGON,UBOGON,0x44c3,0x8382,UBOGON,0x83ac,UBOGON,
122.3335 +    0x44c4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45a9,0x86ad,
122.3336 +    0x45a8,0x45a6,UBOGON,UBOGON
122.3337 +  },
122.3338 +  {				/* ku 15 */
122.3339 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x86ca,0x8851,UBOGON,UBOGON,0x4622,
122.3340 +    UBOGON,0x4626,0x4624,0x4625,0x889d,0x462a,0x4674,UBOGON,0x4679,0x8990,
122.3341 +    0x467a,UBOGON,UBOGON,0x89d8,0x89d7,0x4697,UBOGON,UBOGON,0x8a2e,UBOGON,
122.3342 +    0x46bc,UBOGON,0x46b3,UBOGON,0x46bf,0x46b7,UBOGON,UBOGON,UBOGON,UBOGON,
122.3343 +    UBOGON,0x4734,0x4746,0x4748,0x8c59,UBOGON,UBOGON,0x4756,0x4767,UBOGON,
122.3344 +    UBOGON,0x4768,0x4799,0x479a,UBOGON,UBOGON,0x47d8,UBOGON,0x47db,0x47dc,
122.3345 +    0x47dd,0x47d7,UBOGON,UBOGON,0x4849,0x484a,0x8eda,UBOGON,UBOGON,0x9033,
122.3346 +    UBOGON,0x9018,0x489a,UBOGON,0x48cd,0x48ca,UBOGON,0x48cb,UBOGON,0x48cf,
122.3347 +    UBOGON,UBOGON,0x48cc,0x48ea,0x48ed,UBOGON,UBOGON,0x48e9,UBOGON,0x491a,
122.3348 +    0x91ef,0x498d,0x49d2,UBOGON
122.3349 +  },
122.3350 +  {				/* ku 16 */
122.3351 +    UBOGON,UBOGON,UBOGON,0x49f2,UBOGON,UBOGON,UBOGON,0x4a3d,UBOGON,0x4a3e,
122.3352 +    0x4af8,0x4b23,0x9ad9,0x4eb4,UBOGON,0x50a0,0x5090,0x3475,0x5086,0x5084,
122.3353 +    UBOGON,0x508a,0x3476,0x3473,0x509f,0x50a1,UBOGON,0x5093,0x34bd,UBOGON,
122.3354 +    0x51d5,UBOGON,UBOGON,0x34f9,UBOGON,UBOGON,0x34fa,UBOGON,UBOGON,UBOGON,
122.3355 +    UBOGON,UBOGON,0x3521,UBOGON,0x3529,UBOGON,UBOGON,0x3538,0x354e,UBOGON,
122.3356 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35c8,0x35bc,UBOGON,UBOGON,0x5590,
122.3357 +    UBOGON,0x35bb,0x35c2,0x35c0,UBOGON,UBOGON,0x35ca,UBOGON,0x35c9,UBOGON,
122.3358 +    0x35b8,0x5710,0x5817,UBOGON,0x364e,UBOGON,0x5844,0x3650,0x582b,UBOGON,
122.3359 +    0x5845,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x368a,UBOGON,0x5965,UBOGON,
122.3360 +    UBOGON,UBOGON,0x36fc,0x36f9
122.3361 +  },
122.3362 +  {				/* ku 17 */
122.3363 +    UBOGON,0x3763,UBOGON,0x5bcf,UBOGON,UBOGON,UBOGON,0x3787,0x3788,UBOGON,
122.3364 +    0x379a,UBOGON,UBOGON,UBOGON,0x5d56,UBOGON,UBOGON,0x37e9,UBOGON,0x37ea,
122.3365 +    0x5d54,0x3850,UBOGON,UBOGON,0x3856,0x3852,0x384f,0x3854,0x3851,UBOGON,
122.3366 +    UBOGON,0x388e,0x388f,UBOGON,UBOGON,UBOGON,0x5f3d,UBOGON,UBOGON,0x38ed,
122.3367 +    0x38eb,0x5fa4,UBOGON,UBOGON,UBOGON,0x3962,UBOGON,0x395d,UBOGON,UBOGON,
122.3368 +    UBOGON,0x3961,0x3965,0x395c,UBOGON,UBOGON,0x395f,UBOGON,UBOGON,UBOGON,
122.3369 +    UBOGON,UBOGON,UBOGON,0x63ec,0x3a16,0x3a0a,UBOGON,0x3a0e,0x3a12,UBOGON,
122.3370 +    UBOGON,0x3a11,UBOGON,UBOGON,0x3a10,UBOGON,UBOGON,0x3a09,0x63fa,0x3a15,
122.3371 +    0x63d4,UBOGON,UBOGON,UBOGON,0x3a91,0x3a95,0x3a93,0x3a92,0x3a8f,UBOGON,
122.3372 +    UBOGON,UBOGON,UBOGON,0x3af6
122.3373 +  },
122.3374 +  {				/* ku 18 */
122.3375 +    UBOGON,0x3afb,UBOGON,0x6675,0x3af9,UBOGON,UBOGON,UBOGON,0x671c,0x3b7d,
122.3376 +    UBOGON,0x3b7a,0x3b7f,UBOGON,0x3b78,UBOGON,UBOGON,0x68d9,UBOGON,0x3b70,
122.3377 +    0x3b82,UBOGON,0x3b84,UBOGON,0x3c33,UBOGON,0x3c32,0x3c36,UBOGON,UBOGON,
122.3378 +    0x3c56,UBOGON,UBOGON,0x3c67,UBOGON,0x3c65,0x3c64,0x3c66,UBOGON,UBOGON,
122.3379 +    0x3c81,0x3c82,0x3c83,0x3c9e,UBOGON,0x6bf1,0x3c9d,UBOGON,0x3d0f,0x3d12,
122.3380 +    UBOGON,UBOGON,UBOGON,0x3d10,0x3d18,UBOGON,0x3d14,0x3d19,0x6e37,UBOGON,
122.3381 +    UBOGON,0x6e7d,0x6e86,0x3dc8,0x3dc4,0x3dc6,UBOGON,0x3dc7,0x3dc3,UBOGON,
122.3382 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3e19,0x3e1c,UBOGON,UBOGON,UBOGON,0x3e41,
122.3383 +    UBOGON,0x3e42,0x3e43,UBOGON,UBOGON,UBOGON,0x3e82,UBOGON,0x3e81,0x3e94,
122.3384 +    0x3e84,UBOGON,0x3ed2,0x3f0f
122.3385 +  },
122.3386 +  {				/* ku 19 */
122.3387 +    0x3f22,UBOGON,0x3f27,0x3f2a,0x74fa,0x3f28,UBOGON,0x3f60,UBOGON,UBOGON,
122.3388 +    UBOGON,0x7572,UBOGON,UBOGON,0x3f9b,0x3f9c,UBOGON,0x3f93,0x3f94,0x75dc,
122.3389 +    0x3fa0,0x3f99,UBOGON,0x3fa1,UBOGON,0x3ff1,UBOGON,UBOGON,UBOGON,UBOGON,
122.3390 +    0x4036,UBOGON,0x4037,0x403f,0x403c,UBOGON,0x4034,0x4039,0x403b,0x4035,
122.3391 +    0x4030,0x4032,0x4038,0x403e,0x403a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3392 +    0x40b6,0x7867,UBOGON,UBOGON,UBOGON,0x40b3,0x4109,0x7977,UBOGON,UBOGON,
122.3393 +    UBOGON,0x414c,UBOGON,UBOGON,0x4153,0x414d,0x4151,0x414f,0x7a9b,UBOGON,
122.3394 +    0x41a2,UBOGON,UBOGON,0x41cd,UBOGON,UBOGON,0x41e7,UBOGON,0x41f0,UBOGON,
122.3395 +    0x41e9,0x41ec,UBOGON,0x41e8,0x41ee,0x4202,UBOGON,UBOGON,UBOGON,UBOGON,
122.3396 +    0x4282,0x4283,0x4286,UBOGON
122.3397 +  },
122.3398 +  {				/* ku 1a */
122.3399 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7d2a,0x7d65,0x434a,UBOGON,0x435a,
122.3400 +    0x7f64,UBOGON,0x436e,UBOGON,UBOGON,0x4370,0x436f,UBOGON,0x438a,0x4387,
122.3401 +    0x4388,UBOGON,UBOGON,0x8020,0x43b7,0x43fd,0x8120,UBOGON,0x4405,0x813c,
122.3402 +    0x4408,0x4403,0x4402,0x4404,0x3b39,0x4409,0x43ff,UBOGON,0x813f,UBOGON,
122.3403 +    0x43fc,0x4401,0x440a,0x81f0,0x81f5,0x446b,0x446c,UBOGON,UBOGON,UBOGON,
122.3404 +    UBOGON,UBOGON,UBOGON,0x44de,UBOGON,UBOGON,0x44db,UBOGON,0x44dd,0x44e3,
122.3405 +    UBOGON,0x44e0,0x44d9,0x44d8,0x44e4,UBOGON,UBOGON,0x44da,0x44ef,UBOGON,
122.3406 +    0x8415,0x83be,UBOGON,UBOGON,UBOGON,0x44d7,0x45b3,0x45bb,0x86e5,0x45b2,
122.3407 +    0x86d2,0x45ad,UBOGON,0x45af,UBOGON,0x86e0,UBOGON,0x4616,0x4628,0x4623,
122.3408 +    0x88b3,UBOGON,UBOGON,UBOGON
122.3409 +  },
122.3410 +  {				/* ku 1b */
122.3411 +    0x4675,0x467e,0x467c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46ce,0x46cd,
122.3412 +    0x46cf,0x8a53,UBOGON,UBOGON,0x8a37,0x8a47,0x8a5c,UBOGON,0x46c4,0x46cc,
122.3413 +    0x46c8,0x46c7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x475a,
122.3414 +    0x476a,UBOGON,0x476b,0x476d,0x476f,UBOGON,0x479e,UBOGON,0x47a4,0x47a3,
122.3415 +    0x47e4,0x47e8,0x47e9,0x47e0,0x47e3,UBOGON,0x47ea,0x47e1,0x47ed,0x4834,
122.3416 +    0x4835,0x4851,0x8ef0,UBOGON,0x489d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3417 +    UBOGON,0x48d0,UBOGON,0x48ee,UBOGON,UBOGON,UBOGON,0x48f2,UBOGON,0x921d,
122.3418 +    0x4988,UBOGON,UBOGON,UBOGON,0x498f,UBOGON,0x49d8,UBOGON,UBOGON,UBOGON,
122.3419 +    UBOGON,UBOGON,UBOGON,0x4a3f,UBOGON,0x4a52,0x976b,UBOGON,0x4a50,UBOGON,
122.3420 +    0x4ab1,UBOGON,UBOGON,0x4af9
122.3421 +  },
122.3422 +  {				/* ku 1c */
122.3423 +    UBOGON,UBOGON,UBOGON,0x4b26,0x4b28,UBOGON,UBOGON,0x3480,0x50c0,0x3481,
122.3424 +    UBOGON,0x347e,0x347f,UBOGON,UBOGON,UBOGON,UBOGON,0x34be,UBOGON,0x34d6,
122.3425 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52e5,UBOGON,0x3534,
122.3426 +    UBOGON,0x53af,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35d5,0x35d8,UBOGON,
122.3427 +    UBOGON,0x35d4,0x55d8,0x35d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5711,
122.3428 +    0x5867,UBOGON,UBOGON,0x365d,0x5843,0x365e,0x3659,UBOGON,0x365a,0x36a0,
122.3429 +    UBOGON,UBOGON,0x3705,UBOGON,0x3707,UBOGON,0x370e,0x370c,UBOGON,UBOGON,
122.3430 +    0x3745,UBOGON,UBOGON,0x3764,UBOGON,0x3765,UBOGON,0x5bdd,0x3766,UBOGON,
122.3431 +    0x3789,0x37ec,0x37f1,0x5d70,0x5d6a,0x37f0,0x37f8,0x5d74,0x5d5f,UBOGON,
122.3432 +    0x5d61,0x5d73,UBOGON,0x37f2
122.3433 +  },
122.3434 +  {				/* ku 1d */
122.3435 +    0x37f4,UBOGON,0x3858,UBOGON,UBOGON,0x385a,0x3859,0x3857,0x385b,0x5e50,
122.3436 +    UBOGON,UBOGON,0x38a6,0x38c2,0x38c1,0x5f3f,UBOGON,UBOGON,0x38ef,0x5fb0,
122.3437 +    UBOGON,UBOGON,0x3968,0x6135,0x612d,0x3973,0x396e,0x3974,0x6102,0x3966,
122.3438 +    UBOGON,UBOGON,UBOGON,0x39b9,0x6226,UBOGON,0x3a0c,UBOGON,UBOGON,0x3a20,
122.3439 +    UBOGON,0x3a1d,UBOGON,0x3a1c,UBOGON,0x3a21,0x3a1a,0x3a19,UBOGON,UBOGON,
122.3440 +    UBOGON,0x3a7e,UBOGON,UBOGON,UBOGON,UBOGON,0x3a9d,UBOGON,0x3a9e,UBOGON,
122.3441 +    0x656e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x65b1,0x65d4,0x3acd,UBOGON,
122.3442 +    0x3b0b,0x3b0a,0x6685,UBOGON,0x3b8f,0x6972,0x3b95,0x3b90,0x3b91,UBOGON,
122.3443 +    0x693a,0x3bb9,UBOGON,UBOGON,0x3b97,0x3b9e,UBOGON,0x3b8b,UBOGON,UBOGON,
122.3444 +    0x3c3b,0x3c3a,0x3c3c,0x3c3d
122.3445 +  },
122.3446 +  {				/* ku 1e */
122.3447 +    0x3c39,0x3c3e,0x3c6b,0x3c6c,UBOGON,UBOGON,0x3ca2,0x3ca1,0x3c9f,UBOGON,
122.3448 +    UBOGON,UBOGON,0x3d2d,UBOGON,0x3d36,0x3d2b,UBOGON,0x3d37,UBOGON,UBOGON,
122.3449 +    UBOGON,0x6ead,0x3d25,0x3d2f,0x3d2c,UBOGON,UBOGON,0x3d32,UBOGON,UBOGON,
122.3450 +    0x6e95,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dd5,UBOGON,0x3dd4,
122.3451 +    0x3dd6,UBOGON,0x3dd1,0x7243,UBOGON,0x3e46,0x728f,UBOGON,UBOGON,0x3e8c,
122.3452 +    0x3e8a,0x3e88,UBOGON,UBOGON,UBOGON,UBOGON,0x3edd,UBOGON,UBOGON,UBOGON,
122.3453 +    0x3f2d,UBOGON,UBOGON,0x3f2e,0x3f2c,0x3f2b,0x3f30,UBOGON,0x3f4e,UBOGON,
122.3454 +    UBOGON,0x3f64,0x3f61,UBOGON,0x7575,UBOGON,0x3f70,0x3fa6,0x3fa4,UBOGON,
122.3455 +    UBOGON,UBOGON,0x3fa8,0x3fa2,UBOGON,0x3fa7,0x75ec,0x3fa5,UBOGON,0x3fa9,
122.3456 +    UBOGON,UBOGON,UBOGON,UBOGON
122.3457 +  },
122.3458 +  {				/* ku 1f */
122.3459 +    UBOGON,0x403d,UBOGON,UBOGON,0x4044,0x4045,0x4046,UBOGON,0x7757,UBOGON,
122.3460 +    0x4047,0x4048,0x4042,UBOGON,UBOGON,0x4041,UBOGON,UBOGON,0x4094,UBOGON,
122.3461 +    UBOGON,UBOGON,UBOGON,0x40c0,0x40b8,0x40c1,0x40c2,0x40bb,0x40bd,0x40bf,
122.3462 +    0x40b9,0x40b7,UBOGON,0x40c7,UBOGON,0x410c,0x410b,0x797b,0x4110,UBOGON,
122.3463 +    0x415d,0x7a21,0x415a,0x4158,0x4156,UBOGON,0x4154,0x7a16,UBOGON,0x41a8,
122.3464 +    0x41a7,0x41cf,0x41d0,UBOGON,0x7ae8,UBOGON,UBOGON,0x41d1,0x41eb,UBOGON,
122.3465 +    0x41fb,0x7b6a,UBOGON,0x41fd,0x41f8,0x41f7,0x4200,UBOGON,UBOGON,0x41f6,
122.3466 +    0x7b5f,UBOGON,UBOGON,0x42df,UBOGON,UBOGON,UBOGON,0x42e2,0x42e4,UBOGON,
122.3467 +    0x7d82,UBOGON,0x42e3,UBOGON,0x4359,0x4371,0x438e,0x438c,UBOGON,0x43a4,
122.3468 +    UBOGON,0x8055,0x4414,UBOGON
122.3469 +  },
122.3470 +  {				/* ku 20 */
122.3471 +    UBOGON,UBOGON,0x4411,UBOGON,0x441b,0x4412,0x440e,0x4415,0x8168,0x4410,
122.3472 +    UBOGON,0x4417,0x8246,0x8243,0x4470,0x44ed,UBOGON,0x44ee,UBOGON,UBOGON,
122.3473 +    UBOGON,0x8481,UBOGON,UBOGON,UBOGON,0x44f4,UBOGON,UBOGON,UBOGON,UBOGON,
122.3474 +    UBOGON,UBOGON,0x847c,UBOGON,UBOGON,0x846a,UBOGON,0x8488,0x44f2,0x44f8,
122.3475 +    0x44f3,UBOGON,UBOGON,0x44fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8710,
122.3476 +    UBOGON,UBOGON,0x871f,0x45b6,0x45b7,UBOGON,0x870f,UBOGON,0x45ba,UBOGON,
122.3477 +    0x45bc,UBOGON,UBOGON,0x463b,0x88d3,0x462f,UBOGON,UBOGON,UBOGON,0x4637,
122.3478 +    0x4699,UBOGON,UBOGON,UBOGON,UBOGON,0x46d9,0x46d8,0x46d7,UBOGON,UBOGON,
122.3479 +    UBOGON,UBOGON,UBOGON,0x4736,UBOGON,UBOGON,UBOGON,0x8c87,UBOGON,UBOGON,
122.3480 +    UBOGON,UBOGON,UBOGON,0x8cc6
122.3481 +  },
122.3482 +  {				/* ku 21 */
122.3483 +    0x4770,UBOGON,UBOGON,UBOGON,UBOGON,0x47a5,0x47a6,0x47a9,0x47ee,0x4854,
122.3484 +    UBOGON,0x4857,UBOGON,UBOGON,0x48a1,UBOGON,UBOGON,UBOGON,UBOGON,0x48d3,
122.3485 +    UBOGON,0x48d4,UBOGON,0x48d7,0x90cc,0x916d,0x9170,0x48f7,0x48f6,0x48f9,
122.3486 +    0x48f8,0x9258,0x9242,0x9268,0x9269,UBOGON,UBOGON,0x9243,UBOGON,0x9247,
122.3487 +    0x498a,UBOGON,UBOGON,UBOGON,UBOGON,0x4994,UBOGON,0x4993,UBOGON,UBOGON,
122.3488 +    0x959d,0x49dd,0x49dc,0x49f7,0x96cf,UBOGON,UBOGON,0x4a42,UBOGON,UBOGON,
122.3489 +    0x4a54,UBOGON,0x4a55,UBOGON,0x4a8f,UBOGON,0x97f4,0x4ab4,0x4ab3,UBOGON,
122.3490 +    UBOGON,0x9809,UBOGON,UBOGON,UBOGON,UBOGON,0x4afb,0x4afd,UBOGON,UBOGON,
122.3491 +    0x98ab,0x4afc,UBOGON,0x4b2c,0x4b2f,UBOGON,0x4b2b,UBOGON,0x4b33,0x4b34,
122.3492 +    0x98fb,UBOGON,0x9aac,0x9aae
122.3493 +  },
122.3494 +  {				/* ku 22 */
122.3495 +    0x9aaa,0x4be8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b5c,UBOGON,
122.3496 +    UBOGON,0x4d5d,0x50d2,0x3485,0x3488,UBOGON,UBOGON,0x348e,0x3484,UBOGON,
122.3497 +    0x50df,UBOGON,0x3483,UBOGON,UBOGON,UBOGON,UBOGON,0x3502,UBOGON,0x3506,
122.3498 +    0x3505,UBOGON,0x34fe,0x3501,0x3500,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3499 +    UBOGON,0x35e7,0x5619,UBOGON,UBOGON,UBOGON,0x35e6,UBOGON,0x35ed,0x35e2,
122.3500 +    0x35eb,UBOGON,0x35e8,0x35ec,0x560a,0x3624,0x589a,UBOGON,0x3662,UBOGON,
122.3501 +    0x3661,0x3660,0x3664,0x368b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3719,
122.3502 +    0x3716,0x3718,0x3722,UBOGON,0x371d,0x3717,0x371e,UBOGON,UBOGON,UBOGON,
122.3503 +    UBOGON,UBOGON,UBOGON,0x3769,0x376a,UBOGON,0x376c,0x377a,0x378a,UBOGON,
122.3504 +    UBOGON,UBOGON,0x379c,UBOGON
122.3505 +  },
122.3506 +  {				/* ku 23 */
122.3507 +    0x37fd,0x37f9,UBOGON,0x37ff,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37fc,
122.3508 +    UBOGON,0x5d85,0x37fb,0x3802,0x385f,0x5e56,0x385e,0x385d,0x385c,UBOGON,
122.3509 +    0x5e51,0x3892,UBOGON,UBOGON,0x3894,0x3895,0x38d1,UBOGON,0x38f1,UBOGON,
122.3510 +    0x5fb1,UBOGON,UBOGON,0x3977,0x396f,UBOGON,UBOGON,0x3987,0x397d,0x397c,
122.3511 +    0x397e,0x3985,0x398b,0x3986,0x3980,UBOGON,UBOGON,0x3978,UBOGON,UBOGON,
122.3512 +    UBOGON,0x39ba,UBOGON,0x3a33,UBOGON,0x3a2d,UBOGON,UBOGON,UBOGON,0x3a37,
122.3513 +    0x645a,0x6463,UBOGON,UBOGON,0x3a2e,UBOGON,UBOGON,0x3a3d,UBOGON,0x3aa0,
122.3514 +    UBOGON,UBOGON,0x3aa3,UBOGON,0x669b,UBOGON,0x66a3,0x3b0e,0x669e,UBOGON,
122.3515 +    0x3bb6,UBOGON,0x3bab,0x3bad,0x3ba6,UBOGON,0x69b8,0x3baa,0x69ba,0x3bb1,
122.3516 +    UBOGON,0x3ba8,0x3baf,0x3bb0
122.3517 +  },
122.3518 +  {				/* ku 24 */
122.3519 +    0x3ba7,0x3bb2,0x3b9d,0x3ba5,0x3bb5,UBOGON,0x69c7,0x69d7,UBOGON,0x3c41,
122.3520 +    UBOGON,UBOGON,0x6b70,UBOGON,UBOGON,0x3c72,0x6b9d,0x3c6f,0x3c71,UBOGON,
122.3521 +    0x3c85,UBOGON,UBOGON,0x3ca4,0x3ca5,0x3ca6,UBOGON,0x3ca8,UBOGON,UBOGON,
122.3522 +    0x3ca3,UBOGON,UBOGON,UBOGON,0x6f16,0x6f24,UBOGON,0x3d43,UBOGON,UBOGON,
122.3523 +    0x3d3d,0x3d45,UBOGON,UBOGON,0x3d44,UBOGON,UBOGON,UBOGON,UBOGON,0x6f45,
122.3524 +    UBOGON,UBOGON,UBOGON,0x3de3,0x7179,UBOGON,0x3ddf,0x3de4,0x717a,0x3de5,
122.3525 +    UBOGON,0x7254,0x3e22,0x3e4a,UBOGON,0x3e49,0x3e44,0x3e4b,0x3e87,0x3e89,
122.3526 +    0x3e92,0x3e91,0x3e90,0x3e8e,UBOGON,UBOGON,UBOGON,UBOGON,0x3f12,0x3f10,
122.3527 +    0x3f11,UBOGON,0x3f32,0x3f34,0x3f37,0x3f33,0x3f36,0x3f35,0x3f65,UBOGON,
122.3528 +    0x757c,0x757b,UBOGON,0x7612
122.3529 +  },
122.3530 +  {				/* ku 25 */
122.3531 +    0x3fb0,UBOGON,0x3faf,0x3faa,UBOGON,UBOGON,UBOGON,0x3fab,UBOGON,UBOGON,
122.3532 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ff3,UBOGON,0x3ff4,UBOGON,0x76b6,
122.3533 +    0x76e0,0x4008,0x404e,0x4055,0x404b,UBOGON,UBOGON,0x404d,0x7773,UBOGON,
122.3534 +    0x4052,0x7772,0x404c,0x7770,0x4050,0x4053,UBOGON,0x4051,UBOGON,UBOGON,
122.3535 +    UBOGON,0x4089,UBOGON,0x4095,0x40cc,0x40c8,0x40ce,UBOGON,0x40ca,UBOGON,
122.3536 +    0x789d,UBOGON,0x40cd,UBOGON,0x415c,0x4167,0x4169,0x4165,0x4162,UBOGON,
122.3537 +    0x7a27,0x7a35,UBOGON,0x41aa,UBOGON,UBOGON,0x41d2,0x7ba2,0x4203,0x420c,
122.3538 +    UBOGON,0x4209,0x4206,0x4205,0x7b89,UBOGON,0x420b,0x4208,UBOGON,0x7ba5,
122.3539 +    UBOGON,0x428e,UBOGON,0x7cb6,0x42e8,UBOGON,UBOGON,UBOGON,0x42ea,UBOGON,
122.3540 +    0x7da5,0x7dc3,UBOGON,0x42e9
122.3541 +  },
122.3542 +  {				/* ku 26 */
122.3543 +    0x42eb,UBOGON,0x42f0,UBOGON,0x434b,0x7fab,0x4373,0x4375,0x4392,0x4391,
122.3544 +    0x4393,0x8025,0x43a7,0x43a6,0x43a8,0x43aa,UBOGON,0x43a9,0x8059,0x43bb,
122.3545 +    0x43bc,0x43ba,0x43bd,0x4427,0x8185,UBOGON,0x4424,0x441e,0x441f,0x441d,
122.3546 +    0x4420,0x4423,0x4429,0x4422,UBOGON,UBOGON,0x441c,0x818e,0x4428,UBOGON,
122.3547 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4471,0x4473,0x4472,UBOGON,
122.3548 +    0x4502,UBOGON,UBOGON,UBOGON,0x44fe,0x84be,UBOGON,UBOGON,UBOGON,0x4508,
122.3549 +    UBOGON,UBOGON,UBOGON,0x4507,0x4504,UBOGON,UBOGON,0x4500,0x44fc,UBOGON,
122.3550 +    0x4544,UBOGON,0x44f1,UBOGON,UBOGON,0x84a6,0x4506,UBOGON,UBOGON,0x45c6,
122.3551 +    0x45c3,0x45c1,0x45c2,UBOGON,0x45c4,0x45c7,UBOGON,0x45bf,0x45d2,UBOGON,
122.3552 +    0x45ca,UBOGON,UBOGON,0x872f
122.3553 +  },
122.3554 +  {				/* ku 27 */
122.3555 +    UBOGON,UBOGON,0x4613,UBOGON,0x4630,0x463e,0x4639,UBOGON,UBOGON,0x463c,
122.3556 +    0x463f,UBOGON,0x4634,0x463d,UBOGON,UBOGON,0x4638,UBOGON,UBOGON,UBOGON,
122.3557 +    0x89a0,0x4682,UBOGON,0x4683,UBOGON,0x469b,UBOGON,0x46e0,0x46dd,UBOGON,
122.3558 +    UBOGON,0x46de,UBOGON,0x46e3,0x46e5,UBOGON,0x8a97,0x46e2,UBOGON,UBOGON,
122.3559 +    UBOGON,0x46df,UBOGON,0x472e,UBOGON,0x4737,0x4738,UBOGON,UBOGON,UBOGON,
122.3560 +    UBOGON,0x8c8b,UBOGON,0x3562,UBOGON,0x4794,0x4793,0x47ab,0x47ad,UBOGON,
122.3561 +    UBOGON,0x47f5,0x47f7,UBOGON,0x47f6,0x47f8,UBOGON,0x47fb,0x47f9,0x4858,
122.3562 +    0x485a,UBOGON,0x4859,0x8f0f,0x4885,0x48a4,0x48d8,0x48d9,UBOGON,0x48dd,
122.3563 +    0x48c8,UBOGON,0x48fa,0x48fb,0x9275,0x4927,0x929f,0x492a,0x4925,UBOGON,
122.3564 +    0x4928,UBOGON,UBOGON,UBOGON
122.3565 +  },
122.3566 +  {				/* ku 28 */
122.3567 +    UBOGON,0x95a6,0x4995,0x969a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3568 +    UBOGON,UBOGON,0x4a0f,0x4a11,UBOGON,UBOGON,0x4a10,UBOGON,0x4a15,0x4a13,
122.3569 +    0x9757,UBOGON,0x4a47,0x4a46,UBOGON,0x4a59,0x4a5b,UBOGON,0x4a5e,UBOGON,
122.3570 +    UBOGON,0x4a5a,0x4a91,0x4a92,0x4a90,0x4a93,UBOGON,0x97f7,0x4abe,UBOGON,
122.3571 +    UBOGON,UBOGON,0x4abc,0x4abb,0x4ab7,0x4ab9,UBOGON,0x4b01,0x4afe,UBOGON,
122.3572 +    UBOGON,0x4b02,UBOGON,0x4aff,0x98b0,UBOGON,0x4b00,UBOGON,0x4b37,0x4b3a,
122.3573 +    0x4b6f,0x4b77,0x4b79,0x99c6,UBOGON,0x4bc8,UBOGON,UBOGON,UBOGON,UBOGON,
122.3574 +    0x4bf2,UBOGON,0x4bf1,0x4bf0,0x9b62,UBOGON,0x4c34,UBOGON,UBOGON,UBOGON,
122.3575 +    UBOGON,UBOGON,0x4d2c,0x4d2d,UBOGON,UBOGON,UBOGON,UBOGON,0x50fa,UBOGON,
122.3576 +    0x3491,UBOGON,0x3494,UBOGON
122.3577 +  },
122.3578 +  {				/* ku 29 */
122.3579 +    UBOGON,0x34c4,0x350a,UBOGON,0x5285,UBOGON,0x3552,UBOGON,0x3559,0x366f,
122.3580 +    UBOGON,0x35f2,0x35f4,0x5643,UBOGON,0x35f1,0x563c,UBOGON,0x366a,UBOGON,
122.3581 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3724,UBOGON,0x3723,UBOGON,UBOGON,
122.3582 +    UBOGON,0x3727,UBOGON,UBOGON,0x376d,0x5bed,0x376e,0x376f,UBOGON,UBOGON,
122.3583 +    0x5c35,0x379f,0x380a,0x3806,0x380e,UBOGON,0x380d,0x3805,UBOGON,UBOGON,
122.3584 +    0x380b,0x3810,0x382e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3896,0x3897,
122.3585 +    0x38c4,0x5f47,0x38c5,UBOGON,0x38d2,UBOGON,UBOGON,UBOGON,0x3981,UBOGON,
122.3586 +    0x398e,0x3990,0x398f,UBOGON,0x3991,0x3995,0x3993,UBOGON,0x616d,UBOGON,
122.3587 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3a3b,0x3a48,UBOGON,UBOGON,0x3a46,0x3a47,
122.3588 +    UBOGON,UBOGON,UBOGON,0x3a4c
122.3589 +  },
122.3590 +  {				/* ku 2a */
122.3591 +    UBOGON,0x3a4a,0x3a50,0x3a43,UBOGON,UBOGON,UBOGON,0x3a49,0x3aa6,0x3aa5,
122.3592 +    0x3aa4,UBOGON,UBOGON,0x3ab9,UBOGON,0x3ace,0x3acf,0x3b13,UBOGON,UBOGON,
122.3593 +    UBOGON,0x3bc6,0x3bc5,0x3bca,0x3bd9,0x3bc1,UBOGON,UBOGON,0x69f5,UBOGON,
122.3594 +    UBOGON,UBOGON,UBOGON,0x3bcb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6a03,
122.3595 +    UBOGON,UBOGON,0x6a65,0x3c42,UBOGON,0x6b75,0x3c74,0x3c73,UBOGON,UBOGON,
122.3596 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6f8a,0x6f56,0x3d52,UBOGON,UBOGON,UBOGON,
122.3597 +    0x3d50,UBOGON,0x3d4b,UBOGON,0x3d4c,0x3d6d,UBOGON,0x6f98,UBOGON,UBOGON,
122.3598 +    UBOGON,0x3d4f,0x6f68,0x3df0,UBOGON,0x7234,0x7245,0x3e4d,0x3e4c,UBOGON,
122.3599 +    0x3e4f,0x3e4e,0x3e50,UBOGON,0x735c,0x3e96,0x7356,UBOGON,UBOGON,0x3e97,
122.3600 +    0x3e95,0x3e98,UBOGON,UBOGON
122.3601 +  },
122.3602 +  {				/* ku 2b */
122.3603 +    0x3eec,0x3eeb,0x3f13,0x3f14,0x3f38,0x3f3a,0x3f39,UBOGON,0x3f68,0x3f67,
122.3604 +    UBOGON,UBOGON,UBOGON,0x3fbe,0x3fbc,UBOGON,UBOGON,UBOGON,0x3fbb,UBOGON,
122.3605 +    0x3fba,UBOGON,0x3fb9,0x3fb7,UBOGON,UBOGON,0x3fc1,UBOGON,0x3ff7,UBOGON,
122.3606 +    0x4060,UBOGON,UBOGON,0x4059,0x405c,0x405a,0x4058,UBOGON,0x405b,UBOGON,
122.3607 +    UBOGON,UBOGON,UBOGON,UBOGON,0x405d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3608 +    UBOGON,UBOGON,0x40d4,0x40d3,0x78bf,0x40d2,0x78bd,UBOGON,0x40d7,0x40d1,
122.3609 +    0x78e4,0x40d5,UBOGON,UBOGON,0x416d,0x416f,0x7a34,0x4175,0x416c,0x4174,
122.3610 +    UBOGON,0x4173,UBOGON,UBOGON,0x7a36,0x41ac,UBOGON,UBOGON,UBOGON,0x4210,
122.3611 +    UBOGON,UBOGON,0x7bba,0x7bbc,0x420f,0x7bc8,0x4223,0x7bc3,0x421d,0x7bb6,
122.3612 +    0x420e,UBOGON,UBOGON,0x4215
122.3613 +  },
122.3614 +  {				/* ku 2c */
122.3615 +    0x7bc2,0x4213,UBOGON,UBOGON,0x421b,0x7bc5,0x4222,0x4226,UBOGON,0x7bbd,
122.3616 +    0x7bb0,0x4221,0x421c,0x4217,UBOGON,0x421a,0x7bbb,UBOGON,UBOGON,UBOGON,
122.3617 +    0x4299,UBOGON,0x4297,UBOGON,UBOGON,0x42fd,UBOGON,0x42f6,0x42fe,0x42f5,
122.3618 +    0x42ff,0x42f7,UBOGON,UBOGON,UBOGON,0x4301,0x7e04,UBOGON,UBOGON,UBOGON,
122.3619 +    0x4377,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43ab,UBOGON,UBOGON,0x43c0,
122.3620 +    UBOGON,0x4431,0x442e,UBOGON,UBOGON,0x442c,UBOGON,UBOGON,0x4432,0x442f,
122.3621 +    0x442b,0x442d,0x4433,UBOGON,UBOGON,0x81f1,0x4457,0x445c,0x447b,UBOGON,
122.3622 +    UBOGON,0x447a,UBOGON,0x8522,0x4513,0x451e,0x4517,0x4520,0x452a,0x4511,
122.3623 +    0x4515,0x450f,0x4518,0x8538,UBOGON,UBOGON,0x452c,0x8532,UBOGON,0x8510,
122.3624 +    UBOGON,UBOGON,0x451c,UBOGON
122.3625 +  },
122.3626 +  {				/* ku 2d */
122.3627 +    0x4529,UBOGON,UBOGON,0x4512,0x854f,0x4597,UBOGON,0x8772,UBOGON,UBOGON,
122.3628 +    UBOGON,UBOGON,UBOGON,UBOGON,0x45d4,0x45d0,0x877c,UBOGON,UBOGON,UBOGON,
122.3629 +    UBOGON,0x45d3,0x4614,UBOGON,0x4646,0x4645,UBOGON,0x4643,UBOGON,0x890d,
122.3630 +    0x4644,0x4648,UBOGON,0x4647,UBOGON,UBOGON,UBOGON,0x8908,0x4649,0x4685,
122.3631 +    UBOGON,0x4684,UBOGON,0x469d,UBOGON,0x469e,0x46a0,UBOGON,0x469c,UBOGON,
122.3632 +    0x469f,UBOGON,0x46f7,0x46ea,UBOGON,0x46ef,0x46e9,0x46f3,0x46f0,0x46eb,
122.3633 +    UBOGON,0x46ec,0x46f2,0x46f5,0x46ee,UBOGON,UBOGON,0x473a,0x474b,UBOGON,
122.3634 +    0x474a,0x474c,UBOGON,UBOGON,UBOGON,0x4779,0x477b,0x4778,UBOGON,UBOGON,
122.3635 +    0x47b5,UBOGON,0x47b4,0x47b7,0x8d9e,0x4809,0x47fe,0x4808,0x4807,UBOGON,
122.3636 +    UBOGON,UBOGON,0x4806,0x4804
122.3637 +  },
122.3638 +  {				/* ku 2e */
122.3639 +    0x4805,0x47ff,0x480b,UBOGON,UBOGON,0x483b,0x485d,0x485c,0x485f,0x485e,
122.3640 +    0x8f28,UBOGON,0x8f21,0x4883,UBOGON,UBOGON,0x48a7,0x9066,0x906c,UBOGON,
122.3641 +    0x48a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x90f6,0x48e0,0x48df,0x48fe,
122.3642 +    0x48fc,0x48ff,0x48fd,UBOGON,0x492c,0x92ec,0x92ba,0x92e3,0x92bd,0x499d,
122.3643 +    UBOGON,0x95b4,UBOGON,0x4a40,UBOGON,UBOGON,0x4a5f,UBOGON,UBOGON,UBOGON,
122.3644 +    UBOGON,UBOGON,UBOGON,UBOGON,0x97d1,UBOGON,0x4ac0,0x9823,UBOGON,0x4ac1,
122.3645 +    0x4ac6,UBOGON,UBOGON,0x4b04,0x4b05,UBOGON,0x990b,0x4b3e,0x4b3d,0x4b40,
122.3646 +    0x4b3f,UBOGON,0x4b42,UBOGON,UBOGON,UBOGON,0x4b84,0x4b82,0x4b7f,0x4b85,
122.3647 +    UBOGON,UBOGON,0x4bcc,0x9ab2,0x4bcb,0x4bcd,UBOGON,UBOGON,0x9adb,UBOGON,
122.3648 +    0x4bf5,UBOGON,UBOGON,UBOGON
122.3649 +  },
122.3650 +  {				/* ku 2f */
122.3651 +    0x9af0,UBOGON,UBOGON,0x4c20,0x4c21,UBOGON,UBOGON,0x4c37,0x4c3e,0x9b73,
122.3652 +    0x4c3d,0x9b6e,UBOGON,UBOGON,UBOGON,0x9b65,UBOGON,0x4c3c,UBOGON,0x4c38,
122.3653 +    0x9b6a,UBOGON,0x9b6d,UBOGON,0x4c3b,UBOGON,0x4cb0,UBOGON,UBOGON,UBOGON,
122.3654 +    0x4cad,0x4cb2,0x4cb8,0x9d0b,UBOGON,0x4caf,UBOGON,UBOGON,0x4d1a,0x9e76,
122.3655 +    0x4d20,0x4d21,0x4d30,0x9ea8,0x4d2f,UBOGON,UBOGON,UBOGON,UBOGON,0x4d5f,
122.3656 +    0x4d60,UBOGON,UBOGON,0x9f11,UBOGON,UBOGON,0x348a,0x5119,0x349c,UBOGON,
122.3657 +    0x349a,UBOGON,UBOGON,UBOGON,0x350c,0x350b,0x350d,0x5292,UBOGON,UBOGON,
122.3658 +    0x35fe,UBOGON,UBOGON,0x35ff,0x35fb,0x35fc,0x3609,UBOGON,0x3600,UBOGON,
122.3659 +    0x5675,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3671,UBOGON,UBOGON,
122.3660 +    0x596f,UBOGON,UBOGON,UBOGON
122.3661 +  },
122.3662 +  {				/* ku 30 */
122.3663 +    0x372b,UBOGON,UBOGON,UBOGON,0x3814,0x3811,0x3812,UBOGON,0x3863,UBOGON,
122.3664 +    0x386e,0x389a,UBOGON,0x389b,UBOGON,UBOGON,0x38c8,UBOGON,UBOGON,0x38f6,
122.3665 +    UBOGON,UBOGON,0x61a5,0x398c,0x3997,0x39a2,0x61a0,UBOGON,UBOGON,UBOGON,
122.3666 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a54,UBOGON,UBOGON,UBOGON,
122.3667 +    0x3aa8,UBOGON,UBOGON,0x3aa9,UBOGON,0x65b4,0x65d8,0x66c2,0x3b18,0x3b17,
122.3668 +    0x3b1d,UBOGON,UBOGON,0x3b31,UBOGON,UBOGON,0x3bd8,0x3bd5,UBOGON,UBOGON,
122.3669 +    UBOGON,0x3be1,UBOGON,0x3bd4,UBOGON,UBOGON,UBOGON,0x3be3,UBOGON,0x3c44,
122.3670 +    0x3c45,UBOGON,UBOGON,0x3c76,0x3c75,UBOGON,0x6ba8,0x3c88,0x3caa,UBOGON,
122.3671 +    0x3cab,0x3cac,UBOGON,0x3d57,0x6f83,0x3d60,0x3d5d,0x3d6b,UBOGON,0x3d63,
122.3672 +    0x3d67,UBOGON,0x3d5e,UBOGON
122.3673 +  },
122.3674 +  {				/* ku 31 */
122.3675 +    UBOGON,0x6fc5,0x71cd,0x3df9,0x3df3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3676 +    0x3df6,UBOGON,0x729c,0x3e51,0x3e53,0x3e52,UBOGON,0x3e9b,UBOGON,0x3e9c,
122.3677 +    UBOGON,UBOGON,0x3ef7,0x7499,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3678 +    0x3f3b,UBOGON,0x3f3e,0x3f3d,UBOGON,0x3f69,UBOGON,UBOGON,UBOGON,0x3fc3,
122.3679 +    0x3fc4,0x3fc7,UBOGON,UBOGON,0x7639,0x3fc6,0x762e,0x3fc8,UBOGON,UBOGON,
122.3680 +    UBOGON,0x769f,0x76a0,0x3fe6,0x3ff8,UBOGON,UBOGON,0x4007,UBOGON,0x4064,
122.3681 +    0x4068,UBOGON,0x7794,0x4065,0x77ae,UBOGON,UBOGON,0x4069,UBOGON,UBOGON,
122.3682 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40da,0x40e0,0x78e6,UBOGON,0x40de,
122.3683 +    UBOGON,UBOGON,UBOGON,0x411c,0x411d,0x411a,UBOGON,0x417b,0x417a,0x417c,
122.3684 +    UBOGON,0x4178,0x4177,UBOGON
122.3685 +  },
122.3686 +  {				/* ku 32 */
122.3687 +    UBOGON,0x41b1,UBOGON,0x41b2,0x41b0,UBOGON,0x7abc,UBOGON,0x4236,UBOGON,
122.3688 +    0x422e,UBOGON,0x7bd6,UBOGON,0x4234,UBOGON,UBOGON,UBOGON,UBOGON,0x422a,
122.3689 +    UBOGON,0x4233,0x422d,0x422f,0x4231,0x422b,0x4232,UBOGON,0x4235,UBOGON,
122.3690 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ccf,UBOGON,UBOGON,0x4308,UBOGON,
122.3691 +    0x4306,UBOGON,UBOGON,0x7e18,UBOGON,0x434d,0x4361,UBOGON,UBOGON,UBOGON,
122.3692 +    0x4378,UBOGON,0x4394,0x4395,UBOGON,UBOGON,UBOGON,0x43c1,0x43c3,0x806d,
122.3693 +    UBOGON,0x4439,UBOGON,UBOGON,0x443a,0x443b,0x4435,0x4436,UBOGON,0x443c,
122.3694 +    0x8190,UBOGON,UBOGON,UBOGON,0x4458,0x447c,0x447d,0x448d,0x448c,UBOGON,
122.3695 +    UBOGON,0x453b,0x453f,UBOGON,UBOGON,0x4532,0x452d,UBOGON,0x452f,0x4539,
122.3696 +    0x452e,0x453a,UBOGON,0x4536
122.3697 +  },
122.3698 +  {				/* ku 33 */
122.3699 +    0x4531,0x453e,0x4538,0x8552,0x4534,UBOGON,0x4541,UBOGON,UBOGON,UBOGON,
122.3700 +    UBOGON,0x4530,UBOGON,UBOGON,UBOGON,UBOGON,0x4543,UBOGON,0x8550,UBOGON,
122.3701 +    UBOGON,0x4598,UBOGON,UBOGON,0x87a0,UBOGON,UBOGON,0x8786,0x45da,0x45d7,
122.3702 +    UBOGON,UBOGON,0x8795,UBOGON,UBOGON,0x878c,UBOGON,UBOGON,UBOGON,UBOGON,
122.3703 +    UBOGON,0x4618,0x8860,UBOGON,UBOGON,UBOGON,0x4652,0x8928,UBOGON,0x464e,
122.3704 +    0x8920,UBOGON,0x464f,0x4650,UBOGON,UBOGON,0x89a8,0x4686,0x4687,0x4689,
122.3705 +    UBOGON,UBOGON,UBOGON,UBOGON,0x46a2,0x46a3,UBOGON,0x46a1,UBOGON,UBOGON,
122.3706 +    UBOGON,UBOGON,UBOGON,0x46f9,0x46fd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3707 +    UBOGON,0x473e,0x473c,UBOGON,0x474d,UBOGON,0x474e,UBOGON,0x4781,0x4783,
122.3708 +    0x4782,UBOGON,0x4780,0x4788
122.3709 +  },
122.3710 +  {				/* ku 34 */
122.3711 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b9,UBOGON,UBOGON,0x8e3a,UBOGON,
122.3712 +    UBOGON,UBOGON,0x4811,0x480d,0x4810,0x4813,UBOGON,0x483c,0x4862,0x4863,
122.3713 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4903,0x4906,0x4902,0x4901,UBOGON,
122.3714 +    UBOGON,0x4905,UBOGON,0x9194,0x9311,UBOGON,0x9337,0x4936,UBOGON,0x4935,
122.3715 +    0x9343,UBOGON,0x49a1,0x49a3,UBOGON,UBOGON,0x49a0,UBOGON,0x49ea,0x96a6,
122.3716 +    0x49e8,UBOGON,UBOGON,UBOGON,UBOGON,0x4a21,0x4a1b,UBOGON,UBOGON,0x4a49,
122.3717 +    0x4a48,UBOGON,0x9795,0x4a62,0x4a61,0x4a64,0x4a60,0x4a63,UBOGON,UBOGON,
122.3718 +    0x9796,0x4a66,0x4aac,0x4aab,UBOGON,UBOGON,0x4ac3,UBOGON,0x4ac4,0x9825,
122.3719 +    UBOGON,UBOGON,0x4b08,0x4b09,0x4b0a,0x4b06,0x4b07,0x4b41,UBOGON,0x4b45,
122.3720 +    UBOGON,0x4b43,0x4b44,0x9926
122.3721 +  },
122.3722 +  {				/* ku 35 */
122.3723 +    0x9934,0x4b47,UBOGON,UBOGON,UBOGON,0x4b71,UBOGON,UBOGON,UBOGON,UBOGON,
122.3724 +    UBOGON,UBOGON,0x4b8b,0x4bd4,0x4bd3,0x4bd1,0x9aba,0x4bd2,UBOGON,UBOGON,
122.3725 +    0x4bf7,0x4bf8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3726 +    0x4c22,UBOGON,0x4c45,0x4c41,0x9b81,0x4c40,0x9b8a,UBOGON,0x9b7f,0x4c42,
122.3727 +    UBOGON,0x4cc1,0x4cc5,UBOGON,0x4cbb,0x4cb9,0x4cbd,0x4cc9,UBOGON,0x9d11,
122.3728 +    UBOGON,0x4cbf,0x4cc7,UBOGON,0x4cc3,0x4d24,0x4d31,0x4d33,UBOGON,0x4d32,
122.3729 +    0x4d34,0x4d52,0x4d61,0x9ed9,0x4d7a,0x4d82,0x9f3c,UBOGON,0x5123,UBOGON,
122.3730 +    UBOGON,UBOGON,0x512c,UBOGON,UBOGON,0x350f,0x5295,UBOGON,0x3523,0x3525,
122.3731 +    UBOGON,0x3606,0x3608,0x5688,UBOGON,UBOGON,UBOGON,0x568b,UBOGON,UBOGON,
122.3732 +    0x367a,0x3677,UBOGON,UBOGON
122.3733 +  },
122.3734 +  {				/* ku 36 */
122.3735 +    UBOGON,0x372e,UBOGON,0x372f,UBOGON,UBOGON,0x381b,0x3813,UBOGON,UBOGON,
122.3736 +    0x3866,UBOGON,0x3865,UBOGON,0x38f7,UBOGON,UBOGON,0x61e1,0x61d7,UBOGON,
122.3737 +    UBOGON,0x399c,UBOGON,UBOGON,0x3a53,UBOGON,UBOGON,UBOGON,UBOGON,0x3aba,
122.3738 +    0x65a3,0x3b22,0x66d3,UBOGON,UBOGON,UBOGON,0x6a8b,UBOGON,UBOGON,0x3beb,
122.3739 +    0x3bdd,UBOGON,0x3bef,UBOGON,UBOGON,0x3c47,0x3c46,UBOGON,0x3c78,0x6bac,
122.3740 +    0x3c89,UBOGON,UBOGON,0x3d68,0x3d76,0x3d74,0x3d79,UBOGON,0x3d7a,0x3d77,
122.3741 +    UBOGON,0x3d71,UBOGON,0x3d72,UBOGON,0x3dff,UBOGON,0x3e05,UBOGON,UBOGON,
122.3742 +    0x3e54,UBOGON,UBOGON,0x3e9e,0x3e9f,0x7374,UBOGON,UBOGON,0x3efa,UBOGON,
122.3743 +    0x3f44,0x3f3f,0x3f40,UBOGON,0x3f42,UBOGON,UBOGON,0x3f51,UBOGON,UBOGON,
122.3744 +    UBOGON,UBOGON,UBOGON,UBOGON
122.3745 +  },
122.3746 +  {				/* ku 37 */
122.3747 +    0x7640,0x3fca,UBOGON,0x7641,0x3fce,0x3fc9,UBOGON,UBOGON,UBOGON,UBOGON,
122.3748 +    UBOGON,0x4009,0x76e8,0x406c,0x406e,0x4070,0x406d,0x406b,0x4071,0x4072,
122.3749 +    UBOGON,UBOGON,UBOGON,0x408c,0x40e4,UBOGON,0x40e1,UBOGON,UBOGON,0x78f6,
122.3750 +    0x40e7,0x7900,0x40e2,0x411f,UBOGON,UBOGON,0x417e,UBOGON,0x4180,0x7a59,
122.3751 +    0x7a55,UBOGON,0x41b9,0x41b7,0x41b8,UBOGON,0x41ba,0x7af4,UBOGON,0x41d3,
122.3752 +    0x423f,0x7c04,0x4245,0x4241,0x7c15,0x4242,0x4243,0x423b,0x4238,UBOGON,
122.3753 +    UBOGON,0x423a,0x7bf5,UBOGON,UBOGON,0x423c,UBOGON,UBOGON,0x423e,UBOGON,
122.3754 +    UBOGON,UBOGON,0x429e,0x429f,0x42a1,UBOGON,0x429b,0x4312,UBOGON,UBOGON,
122.3755 +    UBOGON,0x4318,0x430c,UBOGON,0x4362,UBOGON,0x437a,UBOGON,UBOGON,0x43ae,
122.3756 +    0x43af,UBOGON,0x43ad,UBOGON
122.3757 +  },
122.3758 +  {				/* ku 38 */
122.3759 +    0x43c4,0x43c7,0x43c6,0x43c5,UBOGON,UBOGON,0x81c1,0x4440,UBOGON,UBOGON,
122.3760 +    0x443f,0x4441,UBOGON,UBOGON,UBOGON,0x447f,UBOGON,0x4486,0x4481,0x4480,
122.3761 +    0x448e,0x454a,UBOGON,0x4547,UBOGON,UBOGON,0x454b,0x4546,0x454e,0x857d,
122.3762 +    UBOGON,0x85a5,UBOGON,0x4548,UBOGON,0x4545,UBOGON,UBOGON,UBOGON,UBOGON,
122.3763 +    UBOGON,UBOGON,UBOGON,UBOGON,0x45db,0x45e7,0x45e4,UBOGON,UBOGON,0x45e1,
122.3764 +    UBOGON,0x45e9,UBOGON,0x45e5,0x45e0,0x45e3,UBOGON,UBOGON,UBOGON,UBOGON,
122.3765 +    UBOGON,UBOGON,0x45ea,UBOGON,UBOGON,0x893a,0x4654,0x4658,0x465c,UBOGON,
122.3766 +    0x4655,0x468b,0x468c,0x46a6,0x46a5,UBOGON,UBOGON,UBOGON,UBOGON,0x46ff,
122.3767 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4730,0x4740,0x4741,UBOGON,UBOGON,0x4786,
122.3768 +    UBOGON,0x47bf,0x47bd,UBOGON
122.3769 +  },
122.3770 +  {				/* ku 39 */
122.3771 +    UBOGON,UBOGON,UBOGON,UBOGON,0x47be,0x4819,UBOGON,0x481c,UBOGON,0x481b,
122.3772 +    0x4817,0x4818,0x8e51,UBOGON,UBOGON,0x483d,0x486a,0x4866,UBOGON,UBOGON,
122.3773 +    0x4867,UBOGON,0x4868,0x48ad,0x48ae,UBOGON,UBOGON,0x48d6,0x4909,UBOGON,
122.3774 +    0x9198,UBOGON,0x490c,0x490a,UBOGON,0x493b,0x493a,0x9384,0x9381,UBOGON,
122.3775 +    0x936f,UBOGON,UBOGON,UBOGON,0x49af,0x49aa,0x49ab,UBOGON,UBOGON,0x49b1,
122.3776 +    UBOGON,0x49ac,0x49ec,UBOGON,UBOGON,0x4a01,UBOGON,UBOGON,UBOGON,UBOGON,
122.3777 +    0x4a23,UBOGON,0x4a24,0x4a1e,UBOGON,0x4a4a,0x4a65,0x4a6a,UBOGON,UBOGON,
122.3778 +    UBOGON,0x4a69,UBOGON,UBOGON,0x4a95,UBOGON,UBOGON,UBOGON,UBOGON,0x9842,
122.3779 +    UBOGON,UBOGON,0x4acc,UBOGON,UBOGON,UBOGON,0x4acf,UBOGON,UBOGON,0x4b0f,
122.3780 +    UBOGON,0x4b0e,0x4b0b,0x4b10
122.3781 +  },
122.3782 +  {				/* ku 3a */
122.3783 +    0x4b0d,0x4b0c,UBOGON,UBOGON,UBOGON,UBOGON,0x4b46,0x4b48,0x9937,0x4b49,
122.3784 +    UBOGON,UBOGON,0x4b91,0x4b8e,UBOGON,0x4bd8,0x4bd6,UBOGON,0x4bda,UBOGON,
122.3785 +    0x4bd7,UBOGON,0x9aff,0x4bf9,UBOGON,UBOGON,0x4bfc,UBOGON,UBOGON,UBOGON,
122.3786 +    0x9ba9,0x4c4a,0x9ba7,0x4c4e,0x9bb3,0x9bac,0x9bb0,UBOGON,UBOGON,UBOGON,
122.3787 +    0x9b9c,UBOGON,UBOGON,UBOGON,0x9d3c,0x9d1c,0x9d3a,0x4cd3,0x4ccd,0x4cd1,
122.3788 +    UBOGON,UBOGON,0x9d32,0x9d34,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3789 +    0x9ec7,UBOGON,0x4d62,UBOGON,UBOGON,UBOGON,0x4d83,0x9f3f,UBOGON,0x4d92,
122.3790 +    0x349f,0x34a0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3527,UBOGON,0x360b,
122.3791 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x368d,
122.3792 +    UBOGON,UBOGON,0x3770,UBOGON
122.3793 +  },
122.3794 +  {				/* ku 3b */
122.3795 +    0x5eeb,UBOGON,0x399a,0x399f,0x399d,UBOGON,UBOGON,UBOGON,0x399b,UBOGON,
122.3796 +    0x61d5,UBOGON,0x3a60,0x3a64,0x3a69,0x3a63,0x3a67,0x3a62,UBOGON,UBOGON,
122.3797 +    UBOGON,0x6502,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3798 +    0x3b26,0x3b23,0x3b25,UBOGON,UBOGON,0x3bf8,UBOGON,UBOGON,UBOGON,0x3bf7,
122.3799 +    0x3bfb,0x3bfa,UBOGON,UBOGON,UBOGON,UBOGON,0x3cb0,0x3caf,UBOGON,UBOGON,
122.3800 +    UBOGON,0x3d7e,UBOGON,0x3d7d,0x3d80,UBOGON,UBOGON,0x3d7f,0x3d86,UBOGON,
122.3801 +    UBOGON,0x7012,UBOGON,0x3d81,UBOGON,UBOGON,UBOGON,0x3e24,0x3e58,0x3e57,
122.3802 +    0x3ea0,UBOGON,0x3efe,UBOGON,UBOGON,0x3f15,UBOGON,0x3f47,0x3f46,UBOGON,
122.3803 +    UBOGON,0x3f6b,0x3f6c,0x7585,0x7654,UBOGON,0x3fcc,UBOGON,0x7655,UBOGON,
122.3804 +    0x3fcb,0x76a7,0x76a8,0x3ff9
122.3805 +  },
122.3806 +  {				/* ku 3c */
122.3807 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4078,0x407a,0x4075,UBOGON,0x4076,0x4077,
122.3808 +    UBOGON,UBOGON,0x40ea,0x40ee,0x40ed,UBOGON,0x40ec,0x790f,UBOGON,UBOGON,
122.3809 +    0x4184,0x4185,0x4183,UBOGON,0x41bc,0x41bd,0x41d4,UBOGON,UBOGON,UBOGON,
122.3810 +    UBOGON,0x4255,UBOGON,0x4250,0x424c,0x4248,UBOGON,0x4253,UBOGON,0x4257,
122.3811 +    0x4254,0x424e,0x424a,0x4251,UBOGON,UBOGON,0x4249,0x424b,0x4263,UBOGON,
122.3812 +    UBOGON,0x42a7,0x42a6,0x42a4,UBOGON,UBOGON,UBOGON,0x7ce4,0x7ce5,UBOGON,
122.3813 +    UBOGON,0x7e65,0x7e4e,0x4317,UBOGON,0x4316,UBOGON,UBOGON,0x4363,UBOGON,
122.3814 +    UBOGON,0x7f82,UBOGON,0x437b,0x437c,UBOGON,UBOGON,UBOGON,UBOGON,0x43b0,
122.3815 +    0x802d,UBOGON,UBOGON,0x4442,UBOGON,0x4444,UBOGON,UBOGON,UBOGON,UBOGON,
122.3816 +    UBOGON,0x4488,0x448f,0x4553
122.3817 +  },
122.3818 +  {				/* ku 3d */
122.3819 +    0x455b,UBOGON,0x4559,UBOGON,UBOGON,UBOGON,UBOGON,0x85ca,UBOGON,UBOGON,
122.3820 +    0x4554,0x85bc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4599,UBOGON,UBOGON,
122.3821 +    UBOGON,UBOGON,UBOGON,UBOGON,0x45f1,UBOGON,0x45ef,UBOGON,UBOGON,UBOGON,
122.3822 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4662,UBOGON,0x4663,UBOGON,0x4660,
122.3823 +    0x4661,0x465f,UBOGON,UBOGON,UBOGON,0x468d,UBOGON,0x468e,UBOGON,UBOGON,
122.3824 +    UBOGON,0x4709,UBOGON,UBOGON,0x4705,UBOGON,UBOGON,0x4703,0x4706,UBOGON,
122.3825 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4731,UBOGON,UBOGON,0x474f,UBOGON,UBOGON,
122.3826 +    UBOGON,0x4766,0x8cff,0x47c4,UBOGON,0x47c3,0x47c1,0x47c5,UBOGON,UBOGON,
122.3827 +    UBOGON,0x4821,UBOGON,0x481f,0x4822,UBOGON,0x4827,0x4820,UBOGON,0x486d,
122.3828 +    0x486c,0x486b,0x486f,0x4870
122.3829 +  },
122.3830 +  {				/* ku 3e */
122.3831 +    UBOGON,UBOGON,UBOGON,0x91a6,UBOGON,UBOGON,0x4942,UBOGON,0x93b6,UBOGON,
122.3832 +    0x4944,0x4940,UBOGON,UBOGON,0x493f,UBOGON,0x93ab,0x498b,UBOGON,UBOGON,
122.3833 +    0x4a25,0x4a28,UBOGON,0x9721,UBOGON,UBOGON,0x4a75,0x4a72,UBOGON,0x4a6f,
122.3834 +    UBOGON,UBOGON,0x4a76,0x4a71,0x97a7,UBOGON,0x4a97,UBOGON,0x4ad7,UBOGON,
122.3835 +    0x4ad6,UBOGON,0x4ad8,0x4adc,0x4adb,0x4ad4,0x983e,0x4b13,0x4b11,0x4b14,
122.3836 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4b51,0x4b50,0x4b53,0x4b54,0x4b52,UBOGON,
122.3837 +    UBOGON,UBOGON,0x4b6d,UBOGON,UBOGON,0x4b95,0x4b99,UBOGON,0x4b9a,UBOGON,
122.3838 +    0x4b93,0x4b97,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bdc,UBOGON,0x4bfd,
122.3839 +    UBOGON,UBOGON,0x4bfe,0x4c00,0x4c02,0x4c01,0x4c03,UBOGON,UBOGON,UBOGON,
122.3840 +    UBOGON,0x4c27,0x4c26,0x4c24
122.3841 +  },
122.3842 +  {				/* ku 3f */
122.3843 +    0x4c4c,0x9bbc,0x4c50,0x4c55,0x4c53,0x9bb7,0x4c52,UBOGON,0x4c57,0x9bbe,
122.3844 +    0x4c58,0x4cd6,UBOGON,UBOGON,0x4cd4,UBOGON,0x4cda,0x4cd9,UBOGON,0x9d62,
122.3845 +    0x4cd5,0x4ce4,UBOGON,0x4cdc,0x4d1b,0x9e8f,0x4d37,0x4d36,0x4d4b,0x9ecb,
122.3846 +    0x4d66,0x4d76,UBOGON,0x4d7e,0x4d7d,0x4d7f,0x4d84,0x4d8b,UBOGON,0x4d94,
122.3847 +    0x34a1,0x3511,UBOGON,0x3610,0x56a9,UBOGON,UBOGON,UBOGON,UBOGON,0x5913,
122.3848 +    UBOGON,0x3732,0x5bf4,UBOGON,UBOGON,UBOGON,UBOGON,0x3820,UBOGON,UBOGON,
122.3849 +    UBOGON,0x389d,UBOGON,0x61ec,0x61ef,UBOGON,UBOGON,0x39a5,UBOGON,UBOGON,
122.3850 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c02,0x3bfe,0x3c01,
122.3851 +    0x6ad6,0x3c03,0x3bff,UBOGON,0x3c04,UBOGON,0x3c4a,UBOGON,0x3d87,UBOGON,
122.3852 +    0x3d84,UBOGON,0x3d85,0x7209
122.3853 +  },
122.3854 +  {				/* ku 40 */
122.3855 +    UBOGON,UBOGON,UBOGON,0x3e59,0x7379,UBOGON,0x74c6,UBOGON,UBOGON,0x3f04,
122.3856 +    0x3f49,0x3f48,UBOGON,0x3f6d,0x3fd2,0x3fd3,UBOGON,0x3fd1,UBOGON,UBOGON,
122.3857 +    UBOGON,UBOGON,0x3fe7,0x400a,0x77c3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3858 +    0x40f0,UBOGON,UBOGON,0x791f,UBOGON,UBOGON,0x7a65,UBOGON,UBOGON,0x41be,
122.3859 +    0x41bf,UBOGON,0x7ac6,0x7c3a,UBOGON,0x7c36,UBOGON,UBOGON,UBOGON,UBOGON,
122.3860 +    0x425e,UBOGON,UBOGON,0x425b,UBOGON,UBOGON,UBOGON,0x7ceb,0x42ab,UBOGON,
122.3861 +    0x42ac,UBOGON,UBOGON,UBOGON,UBOGON,0x431f,0x431d,UBOGON,UBOGON,0x431c,
122.3862 +    UBOGON,0x431e,UBOGON,UBOGON,UBOGON,UBOGON,0x4364,UBOGON,0x7f84,UBOGON,
122.3863 +    UBOGON,UBOGON,0x4448,0x4447,UBOGON,UBOGON,0x455e,0x4561,UBOGON,0x85e0,
122.3864 +    0x85f3,UBOGON,UBOGON,UBOGON
122.3865 +  },
122.3866 +  {				/* ku 41 */
122.3867 +    0x45f7,UBOGON,UBOGON,0x45f4,0x45f8,0x881e,UBOGON,UBOGON,UBOGON,0x4664,
122.3868 +    UBOGON,0x4692,0x468f,0x4690,0x89b4,0x4693,0x46a8,UBOGON,UBOGON,0x46a9,
122.3869 +    UBOGON,UBOGON,0x89f9,UBOGON,UBOGON,0x8b44,0x470e,UBOGON,0x470f,UBOGON,
122.3870 +    UBOGON,0x470b,UBOGON,UBOGON,UBOGON,UBOGON,0x4710,0x4751,UBOGON,0x4750,
122.3871 +    UBOGON,0x4763,UBOGON,UBOGON,0x47c7,UBOGON,0x8e71,0x4824,0x4826,0x8e6e,
122.3872 +    UBOGON,0x8e79,UBOGON,0x8ec4,0x4874,0x4873,0x4872,UBOGON,UBOGON,UBOGON,
122.3873 +    UBOGON,0x48b1,0x908c,UBOGON,0x490e,0x4911,0x4910,0x490f,0x4912,0x4949,
122.3874 +    0x93c9,0x494f,0x494d,UBOGON,UBOGON,0x4955,UBOGON,UBOGON,UBOGON,UBOGON,
122.3875 +    UBOGON,UBOGON,0x4a2c,0x4a2b,UBOGON,UBOGON,0x4a79,UBOGON,UBOGON,UBOGON,
122.3876 +    0x4a7a,0x97b0,0x4a99,0x4a9a
122.3877 +  },
122.3878 +  {				/* ku 42 */
122.3879 +    UBOGON,0x4aae,0x4aaf,UBOGON,0x4ae4,0x4ae1,0x4ade,0x4ae6,0x4adf,UBOGON,
122.3880 +    0x4ae7,0x4ae2,0x4ae0,UBOGON,0x4ae5,0x985a,UBOGON,0x4b18,UBOGON,UBOGON,
122.3881 +    UBOGON,0x4b56,UBOGON,0x9946,UBOGON,UBOGON,UBOGON,0x4b6e,UBOGON,UBOGON,
122.3882 +    0x4b9d,0x4ba0,0x4b9c,UBOGON,UBOGON,0x4ba1,0x4ba2,0x4b9f,0x4bdf,0x4bde,
122.3883 +    0x9ac3,0x4bea,UBOGON,0x4c06,UBOGON,0x4c04,0x9b0f,UBOGON,UBOGON,UBOGON,
122.3884 +    UBOGON,0x4c5f,0x9bf4,0x9bfa,0x4c5c,UBOGON,0x4c5e,UBOGON,UBOGON,0x9bdd,
122.3885 +    0x4c59,UBOGON,UBOGON,0x4c64,0x4c5d,0x4c62,UBOGON,0x4c65,UBOGON,0x9bed,
122.3886 +    0x4c5b,0x9bef,UBOGON,0x4cdd,UBOGON,0x4cdf,UBOGON,UBOGON,0x4ce2,UBOGON,
122.3887 +    UBOGON,0x4d27,UBOGON,UBOGON,0x9e96,0x4d3a,0x4d3c,UBOGON,0x4d39,UBOGON,
122.3888 +    UBOGON,0x4d3d,0x4d3b,0x9eb3
122.3889 +  },
122.3890 +  {				/* ku 43 */
122.3891 +    0x4d4c,UBOGON,0x4d68,0x9ee2,UBOGON,0x4d80,0x4d85,UBOGON,0x4d95,UBOGON,
122.3892 +    0x4d96,UBOGON,0x9f8f,UBOGON,0x34a4,0x3512,0x56b1,0x3625,UBOGON,0x5b41,
122.3893 +    0x3737,UBOGON,UBOGON,UBOGON,UBOGON,0x3868,0x3867,0x389e,UBOGON,UBOGON,
122.3894 +    UBOGON,0x39aa,UBOGON,0x39a9,0x39a4,UBOGON,UBOGON,0x3a71,0x3a6f,UBOGON,
122.3895 +    UBOGON,UBOGON,UBOGON,0x3aad,UBOGON,0x6af6,0x3c0c,0x6af2,0x3c0b,UBOGON,
122.3896 +    UBOGON,0x3c0f,0x3c79,UBOGON,UBOGON,UBOGON,UBOGON,0x3d8d,0x3d8f,UBOGON,
122.3897 +    UBOGON,0x3d8e,0x3e0c,UBOGON,UBOGON,UBOGON,0x3ea6,UBOGON,0x3ea3,0x3ea4,
122.3898 +    0x3ea5,0x7588,0x3f6e,UBOGON,UBOGON,0x3ffa,UBOGON,0x407c,0x407e,0x407b,
122.3899 +    0x407d,UBOGON,UBOGON,0x408d,0x40f4,0x40f3,UBOGON,UBOGON,0x4189,UBOGON,
122.3900 +    UBOGON,0x41c0,UBOGON,0x4265
122.3901 +  },
122.3902 +  {				/* ku 44 */
122.3903 +    UBOGON,UBOGON,0x42ad,0x4325,UBOGON,UBOGON,UBOGON,0x43c9,UBOGON,0x444a,
122.3904 +    UBOGON,0x8267,0x4489,UBOGON,0x4566,0x4570,UBOGON,0x456d,0x4569,0x4567,
122.3905 +    UBOGON,0x4572,0x860e,0x456e,UBOGON,0x459c,0x45fc,0x45fd,0x4604,0x45ff,
122.3906 +    UBOGON,0x45fe,0x4600,UBOGON,0x4666,0x4669,UBOGON,0x46aa,0x46ab,0x4717,
122.3907 +    UBOGON,UBOGON,UBOGON,0x4715,0x8b5e,0x4712,0x8d0e,UBOGON,UBOGON,UBOGON,
122.3908 +    0x47ca,UBOGON,0x47c9,0x47cb,UBOGON,UBOGON,UBOGON,0x4829,0x4828,UBOGON,
122.3909 +    UBOGON,UBOGON,0x4840,0x4875,0x4876,UBOGON,0x4888,UBOGON,0x91b6,0x4957,
122.3910 +    0x9401,UBOGON,0x495f,UBOGON,0x941d,0x4958,0x495b,UBOGON,0x942f,UBOGON,
122.3911 +    0x49b3,UBOGON,0x49ef,UBOGON,0x4a30,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3912 +    0x4a41,0x4a4b,UBOGON,0x4a7d
122.3913 +  },
122.3914 +  {				/* ku 45 */
122.3915 +    UBOGON,UBOGON,0x4a7c,UBOGON,UBOGON,UBOGON,0x97e0,UBOGON,0x97db,UBOGON,
122.3916 +    UBOGON,0x9861,UBOGON,UBOGON,0x4ae8,0x4aea,0x4ae9,UBOGON,UBOGON,UBOGON,
122.3917 +    UBOGON,0x4b1b,UBOGON,UBOGON,0x4b55,0x994a,0x4b59,0x4b58,UBOGON,UBOGON,
122.3918 +    UBOGON,0x4ba4,0x4ba3,UBOGON,UBOGON,UBOGON,UBOGON,0x9a33,0x4ba7,UBOGON,
122.3919 +    0x4be0,UBOGON,UBOGON,UBOGON,0x4c08,0x4c0a,0x4c09,UBOGON,UBOGON,UBOGON,
122.3920 +    0x4c71,0x9c0f,0x4c6c,UBOGON,0x9c11,UBOGON,0x9c03,0x9c01,0x4c6e,UBOGON,
122.3921 +    0x9c16,UBOGON,UBOGON,UBOGON,0x4ce0,0x4cee,UBOGON,0x4ceb,UBOGON,UBOGON,
122.3922 +    UBOGON,UBOGON,0x9d93,0x4cea,0x4cef,0x4ce7,UBOGON,UBOGON,UBOGON,UBOGON,
122.3923 +    0x4d48,0x4d49,UBOGON,UBOGON,UBOGON,0x4d4d,UBOGON,UBOGON,0x4d55,UBOGON,
122.3924 +    UBOGON,0x4d6a,0x4d6c,UBOGON
122.3925 +  },
122.3926 +  {				/* ku 46 */
122.3927 +    0x4d6b,UBOGON,UBOGON,UBOGON,0x4d98,0x4d99,0x4d97,UBOGON,UBOGON,UBOGON,
122.3928 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x535b,UBOGON,0x3616,UBOGON,0x56bf,
122.3929 +    UBOGON,UBOGON,0x3739,UBOGON,UBOGON,0x3825,0x5dce,UBOGON,UBOGON,UBOGON,
122.3930 +    UBOGON,0x3a74,UBOGON,UBOGON,0x3aae,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3931 +    0x3d92,0x3d94,UBOGON,0x3d95,UBOGON,0x3e0d,UBOGON,0x3e25,UBOGON,UBOGON,
122.3932 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fd5,0x3fd6,0x76ac,0x3fe8,UBOGON,
122.3933 +    0x407f,0x77d2,0x40f5,0x40f6,0x40f7,UBOGON,0x4124,0x418d,0x418a,UBOGON,
122.3934 +    UBOGON,0x426c,0x4266,0x426a,UBOGON,0x4267,0x426d,0x4268,0x7c52,UBOGON,
122.3935 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3936 +    0x4365,UBOGON,0x439a,UBOGON
122.3937 +  },
122.3938 +  {				/* ku 47 */
122.3939 +    0x43b1,0x444b,0x444d,0x444c,0x444e,UBOGON,0x4573,0x4575,UBOGON,UBOGON,
122.3940 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4603,UBOGON,UBOGON,UBOGON,UBOGON,
122.3941 +    UBOGON,UBOGON,UBOGON,UBOGON,0x471e,UBOGON,0x8b73,UBOGON,0x4719,0x471c,
122.3942 +    0x471a,0x471d,0x8b76,UBOGON,UBOGON,0x4743,0x4752,UBOGON,UBOGON,0x4795,
122.3943 +    UBOGON,0x47cc,UBOGON,0x482b,UBOGON,UBOGON,UBOGON,0x482a,0x8ec7,0x4877,
122.3944 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4913,0x4914,0x9434,
122.3945 +    UBOGON,UBOGON,0x495d,UBOGON,0x4960,0x943e,0x4962,UBOGON,UBOGON,0x49b2,
122.3946 +    0x49f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a4c,UBOGON,0x4a82,
122.3947 +    0x97bc,0x4a81,0x4a9b,UBOGON,0x4aa4,0x4aee,0x4aec,UBOGON,0x4aed,UBOGON,
122.3948 +    0x4af0,0x4aef,UBOGON,0x4b1d
122.3949 +  },
122.3950 +  {				/* ku 48 */
122.3951 +    UBOGON,0x4b60,0x4b5e,0x4b5d,UBOGON,UBOGON,UBOGON,0x4bb1,0x4bab,0x4bac,
122.3952 +    0x4bad,UBOGON,0x4bae,UBOGON,UBOGON,0x4be2,UBOGON,UBOGON,UBOGON,UBOGON,
122.3953 +    UBOGON,0x9b39,UBOGON,UBOGON,0x9c2a,0x4c7b,0x9c26,0x4c78,0x4c75,0x9c27,
122.3954 +    UBOGON,0x4cf2,0x4cf4,0x4cf3,0x9dc0,0x9dc9,UBOGON,UBOGON,UBOGON,0x4d3f,
122.3955 +    0x4d3e,0x4d40,0x4d4e,0x4d57,0x4d59,0x4d58,0x4d56,UBOGON,UBOGON,0x4d6e,
122.3956 +    UBOGON,UBOGON,UBOGON,0x9eec,UBOGON,UBOGON,0x4d81,0x4d86,UBOGON,0x4d8f,
122.3957 +    UBOGON,UBOGON,UBOGON,0x9f68,0x4d9b,0x4db1,0x4db3,UBOGON,0x373a,UBOGON,
122.3958 +    UBOGON,0x3827,UBOGON,UBOGON,0x386a,0x39ac,UBOGON,0x3c18,UBOGON,UBOGON,
122.3959 +    0x3c4c,UBOGON,0x3d96,UBOGON,0x3f4a,UBOGON,UBOGON,0x4081,UBOGON,0x4083,
122.3960 +    0x40f9,0x40f8,UBOGON,0x418e
122.3961 +  },
122.3962 +  {				/* ku 49 */
122.3963 +    0x418f,0x41c1,UBOGON,UBOGON,UBOGON,0x4270,UBOGON,0x4271,UBOGON,0x432a,
122.3964 +    0x432d,0x437d,0x8032,0x8031,UBOGON,0x444f,UBOGON,UBOGON,0x4490,UBOGON,
122.3965 +    UBOGON,UBOGON,0x4579,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4605,
122.3966 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x89fd,UBOGON,UBOGON,0x4721,
122.3967 +    UBOGON,UBOGON,UBOGON,0x4732,UBOGON,UBOGON,0x47cf,UBOGON,UBOGON,0x908e,
122.3968 +    0x4916,0x4915,0x49b5,0x4a08,UBOGON,0x4a32,UBOGON,0x4a33,0x4a34,0x4a3c,
122.3969 +    UBOGON,0x97c2,UBOGON,0x4a9c,UBOGON,0x4af4,0x4af2,UBOGON,0x4b62,UBOGON,
122.3970 +    0x4b61,0x4b64,0x4bb5,0x9a4b,0x4bb4,UBOGON,UBOGON,0x4be3,UBOGON,UBOGON,
122.3971 +    0x9b1c,0x4c0e,UBOGON,0x9b1b,UBOGON,0x4c2c,0x4c2b,UBOGON,UBOGON,UBOGON,
122.3972 +    0x4c85,0x4c81,0x4c7e,0x4c83
122.3973 +  },
122.3974 +  {				/* ku 4a */
122.3975 +    0x4c80,UBOGON,0x9c42,UBOGON,0x9dd4,0x4cfb,0x4cf7,UBOGON,UBOGON,UBOGON,
122.3976 +    UBOGON,0x4cf8,UBOGON,UBOGON,UBOGON,UBOGON,0x4d5a,UBOGON,UBOGON,UBOGON,
122.3977 +    UBOGON,UBOGON,0x4d78,UBOGON,UBOGON,UBOGON,UBOGON,0x4d9d,0x4d9c,UBOGON,
122.3978 +    UBOGON,UBOGON,0x34a9,0x34bf,0x56d0,0x56cf,UBOGON,0x5dda,UBOGON,0x3a77,
122.3979 +    0x3a76,UBOGON,0x3abb,0x66ea,UBOGON,0x3d9b,UBOGON,0x3e0f,0x3e5b,UBOGON,
122.3980 +    0x3f4c,0x3f6f,0x3fd9,UBOGON,0x4082,UBOGON,UBOGON,UBOGON,UBOGON,0x4274,
122.3981 +    0x4272,UBOGON,UBOGON,UBOGON,0x4273,UBOGON,UBOGON,UBOGON,0x42b1,0x432e,
122.3982 +    UBOGON,UBOGON,UBOGON,UBOGON,0x434e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3983 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x460b,UBOGON,UBOGON,
122.3984 +    0x466c,0x8b89,UBOGON,UBOGON
122.3985 +  },
122.3986 +  {				/* ku 4b */
122.3987 +    0x478b,UBOGON,0x47d0,0x482d,UBOGON,0x48e4,0x4971,UBOGON,0x9458,0x496f,
122.3988 +    UBOGON,0x4a87,0x4aa5,UBOGON,UBOGON,0x4b1e,0x4b65,0x4bb9,0x4bb7,0x4bb8,
122.3989 +    0x4be4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c8c,0x4c89,0x4c8a,UBOGON,
122.3990 +    UBOGON,0x4c8b,UBOGON,UBOGON,UBOGON,0x4d01,0x4cfe,0x9de7,0x4d03,0x4d06,
122.3991 +    UBOGON,0x9dea,0x9df1,UBOGON,0x4d1d,0x4d43,UBOGON,UBOGON,UBOGON,0x4d4f,
122.3992 +    UBOGON,UBOGON,0x4d5b,0x4d70,UBOGON,0x4d88,UBOGON,UBOGON,0x4d89,0x9f44,
122.3993 +    UBOGON,UBOGON,UBOGON,UBOGON,0x9f6d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.3994 +    UBOGON,0x5dd9,UBOGON,UBOGON,UBOGON,UBOGON,0x3d9e,0x3d9f,0x3ea7,0x3f4b,
122.3995 +    0x3fdb,0x3fda,UBOGON,0x77d6,0x408e,0x4276,UBOGON,0x4330,0x432f,UBOGON,
122.3996 +    0x4366,UBOGON,0x457e,UBOGON
122.3997 +  },
122.3998 +  {				/* ku 4c */
122.3999 +    UBOGON,UBOGON,0x883a,UBOGON,0x8975,0x466f,UBOGON,0x47d1,0x482f,UBOGON,
122.4000 +    UBOGON,0x48b2,0x4918,0x4917,UBOGON,0x4976,UBOGON,UBOGON,0x4a4f,0x4a89,
122.4001 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4af5,0x4b1f,UBOGON,UBOGON,0x9a5d,0x4be5,
122.4002 +    UBOGON,UBOGON,0x4c10,UBOGON,0x4c0f,UBOGON,UBOGON,UBOGON,UBOGON,0x4c2f,
122.4003 +    0x4c30,0x9c64,UBOGON,UBOGON,0x4c93,0x4c94,UBOGON,0x4d07,0x4d09,0x4d08,
122.4004 +    UBOGON,0x4d0b,UBOGON,0x9e0a,UBOGON,UBOGON,UBOGON,0x4d50,0x4d71,UBOGON,
122.4005 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4d7b,0x4d7c,UBOGON,0x9f73,UBOGON,0x4da1,
122.4006 +    UBOGON,UBOGON,0x4da0,0x4da2,UBOGON,0x361b,UBOGON,0x3682,UBOGON,UBOGON,
122.4007 +    UBOGON,UBOGON,0x3fe9,UBOGON,0x4084,0x77e1,UBOGON,UBOGON,UBOGON,0x42b3,
122.4008 +    0x4334,0x4333,0x4580,UBOGON
122.4009 +  },
122.4010 +  {				/* ku 4d */
122.4011 +    UBOGON,0x46ad,UBOGON,0x4744,0x4755,UBOGON,0x47d2,UBOGON,UBOGON,UBOGON,
122.4012 +    UBOGON,UBOGON,0x4a8a,UBOGON,UBOGON,0x4b67,UBOGON,UBOGON,0x4be6,UBOGON,
122.4013 +    0x4c13,UBOGON,0x9b2d,UBOGON,0x4c97,0x9e0c,UBOGON,UBOGON,0x4d0c,UBOGON,
122.4014 +    UBOGON,UBOGON,0x4d46,0x4d5c,0x4d74,0x4d72,UBOGON,UBOGON,UBOGON,0x9f1f,
122.4015 +    UBOGON,UBOGON,0x4da4,0x4da3,UBOGON,UBOGON,UBOGON,UBOGON,0x4db4,UBOGON,
122.4016 +    0x3536,UBOGON,UBOGON,UBOGON,0x3cb2,UBOGON,UBOGON,0x3f16,0x7c70,0x4277,
122.4017 +    UBOGON,0x457f,UBOGON,UBOGON,0x487d,0x9479,UBOGON,0x974a,0x4a8c,UBOGON,
122.4018 +    0x4b68,0x4bbe,0x4c15,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d75,0x4da5,
122.4019 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4278,0x4335,0x7e9d,0x4582,UBOGON,
122.4020 +    0x4583,UBOGON,0x4671,UBOGON
122.4021 +  },
122.4022 +  {				/* ku 4e */
122.4023 +    0x487e,0x4a8e,UBOGON,0x9960,0x4b69,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4024 +    UBOGON,0x4c9a,0x4c9b,UBOGON,UBOGON,UBOGON,0x4d90,UBOGON,0x9f9e,UBOGON,
122.4025 +    UBOGON,0x4586,0x4585,UBOGON,0x460e,UBOGON,0x4695,UBOGON,0x4919,UBOGON,
122.4026 +    0x4bc0,UBOGON,UBOGON,UBOGON,0x9ef8,0x9f3a,0x9f7d,UBOGON,UBOGON,0x400d,
122.4027 +    0x4c16,UBOGON,0x4da9,0x4daa,0x4085,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4028 +    UBOGON,UBOGON,0x9f96,UBOGON,0x4bc2,0x4c31,0x4d11,0x4dab,0x4c9c,UBOGON,
122.4029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4030 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4031 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4032 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4033 +  }
122.4034 +};
122.4035 +
122.4036 +/* CNS 11643 plane 5 conversion table */
122.4037 +
122.4038 +static const unsigned short
122.4039 + cns11643_5tab[MAX_CNS11643_KU_5][MAX_CNS11643_TEN] = {
122.4040 +  {				/* ku 01 */
122.4041 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4042 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4043 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4044 +    UBOGON,UBOGON,0x355a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6729,
122.4045 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4046 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4047 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4048 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4049 +    UBOGON,UBOGON,UBOGON,0x3cbc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4050 +    UBOGON,UBOGON,0x49b9,UBOGON
122.4051 +  },
122.4052 +  {				/* ku 02 */
122.4053 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4054 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34de,UBOGON,UBOGON,UBOGON,UBOGON,
122.4055 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3543,UBOGON,UBOGON,
122.4056 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4057 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37ac,0x37aa,UBOGON,
122.4058 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5e07,
122.4059 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5fcb,
122.4060 +    0x38fe,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4061 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4062 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4063 +  },
122.4064 +  {				/* ku 03 */
122.4065 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4066 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3441,
122.4067 +    UBOGON,UBOGON,0x34b4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4068 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4069 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4070 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4071 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4072 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37b3,
122.4073 +    UBOGON,UBOGON,UBOGON,0x37b4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4074 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4075 +  },
122.4076 +  {				/* ku 04 */
122.4077 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4078 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4079 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4080 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c1d,
122.4081 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c7c,UBOGON,UBOGON,UBOGON,UBOGON,
122.4082 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4083 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f55,UBOGON,UBOGON,UBOGON,
122.4084 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4126,UBOGON,UBOGON,
122.4085 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4086 +    0x49bc,UBOGON,UBOGON,UBOGON
122.4087 +  },
122.4088 +  {				/* ku 05 */
122.4089 +    UBOGON,UBOGON,UBOGON,UBOGON,0x344a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4090 +    0x344e,UBOGON,UBOGON,0x34c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4091 +    UBOGON,UBOGON,0x52b7,0x52b8,UBOGON,0x52b6,0x52ba,UBOGON,UBOGON,UBOGON,
122.4092 +    UBOGON,UBOGON,UBOGON,0x357b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4093 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4094 +    0x3620,UBOGON,UBOGON,UBOGON,UBOGON,0x3689,0x3695,UBOGON,UBOGON,UBOGON,
122.4095 +    0x36be,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4096 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37c3,UBOGON,UBOGON,
122.4097 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4098 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4099 +  },
122.4100 +  {				/* ku 06 */
122.4101 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3877,UBOGON,UBOGON,UBOGON,UBOGON,
122.4102 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4103 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39d4,UBOGON,UBOGON,UBOGON,UBOGON,
122.4104 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4105 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b4c,UBOGON,
122.4106 +    UBOGON,UBOGON,UBOGON,0x3c20,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4107 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c5b,UBOGON,UBOGON,UBOGON,UBOGON,
122.4108 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4109 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e2d,UBOGON,UBOGON,UBOGON,
122.4110 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4111 +  },
122.4112 +  {				/* ku 07 */
122.4113 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4114 +    UBOGON,UBOGON,UBOGON,0x3e63,UBOGON,UBOGON,UBOGON,0x3f18,UBOGON,UBOGON,
122.4115 +    UBOGON,UBOGON,0x3f74,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4116 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4128,UBOGON,UBOGON,
122.4117 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4118 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43da,UBOGON,UBOGON,UBOGON,UBOGON,
122.4119 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44a4,UBOGON,UBOGON,UBOGON,
122.4120 +    UBOGON,UBOGON,0x488e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4121 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4122 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4123 +  },
122.4124 +  {				/* ku 08 */
122.4125 +    0x345b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4126 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4127 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4128 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4129 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4130 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4131 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4132 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3753,UBOGON,UBOGON,
122.4133 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4134 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4135 +  },
122.4136 +  {				/* ku 09 */
122.4137 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3880,UBOGON,UBOGON,UBOGON,UBOGON,
122.4138 +    UBOGON,UBOGON,UBOGON,UBOGON,0x38dd,UBOGON,UBOGON,UBOGON,0x38de,UBOGON,
122.4139 +    0x3922,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4140 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6306,UBOGON,UBOGON,UBOGON,
122.4141 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3adb,UBOGON,UBOGON,UBOGON,
122.4142 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4143 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4144 +    UBOGON,UBOGON,0x6b85,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4145 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4146 +    0x3cda,0x3cdb,UBOGON,UBOGON
122.4147 +  },
122.4148 +  {				/* ku 0a */
122.4149 +    UBOGON,UBOGON,UBOGON,0x3cd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4150 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4151 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4152 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4153 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4154 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4155 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4156 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x401a,UBOGON,UBOGON,UBOGON,
122.4157 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4158 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4159 +  },
122.4160 +  {				/* ku 0b */
122.4161 +    0x41d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4162 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43de,UBOGON,
122.4163 +    UBOGON,UBOGON,UBOGON,UBOGON,0x43e5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4164 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4672,UBOGON,
122.4165 +    0x46af,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4166 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4167 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x49c4,UBOGON,UBOGON,
122.4168 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3463,UBOGON,UBOGON,UBOGON,UBOGON,
122.4169 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4170 +    UBOGON,0x34ec,UBOGON,UBOGON
122.4171 +  },
122.4172 +  {				/* ku 0c */
122.4173 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4174 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4176 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3598,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4180 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4181 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4182 +    UBOGON,0x3758,UBOGON,UBOGON
122.4183 +  },
122.4184 +  {				/* ku 0d */
122.4185 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4186 +    UBOGON,UBOGON,UBOGON,0x37d3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4187 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4188 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38e2,UBOGON,
122.4189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4190 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3954,UBOGON,UBOGON,0x392f,UBOGON,UBOGON,
122.4191 +    0x39b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4192 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4193 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4194 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4195 +  },
122.4196 +  {				/* ku 0e */
122.4197 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3b35,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4198 +    0x3b5d,UBOGON,UBOGON,0x3c29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4199 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4202 +    0x3e1f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e72,
122.4203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f0b,UBOGON,UBOGON,UBOGON,UBOGON,
122.4204 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4205 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4206 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4207 +  },
122.4208 +  {				/* ku 0f */
122.4209 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4210 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40a2,
122.4211 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43ec,UBOGON,UBOGON,UBOGON,
122.4217 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4218 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4219 +  },
122.4220 +  {				/* ku 10 */
122.4221 +    0x44bb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4222 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4223 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4621,UBOGON,UBOGON,UBOGON,0x461f,UBOGON,
122.4224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8c38,UBOGON,UBOGON,
122.4225 +    UBOGON,UBOGON,0x4791,0x4796,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4229 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4230 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4231 +  },
122.4232 +  {				/* ku 11 */
122.4233 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34bc,UBOGON,UBOGON,0x34d8,UBOGON,
122.4234 +    UBOGON,0x34f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4235 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4236 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4239 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4241 +    UBOGON,UBOGON,0x3785,UBOGON,0x3783,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4242 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4243 +  },
122.4244 +  {				/* ku 12 */
122.4245 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4246 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4247 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4248 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38ba,UBOGON,UBOGON,
122.4249 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4250 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3969,UBOGON,UBOGON,0x3945,UBOGON,
122.4251 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4252 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4253 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b6c,UBOGON,
122.4254 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4255 +  },
122.4256 +  {				/* ku 13 */
122.4257 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4258 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4259 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d04,UBOGON,
122.4260 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4261 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3e3a,UBOGON,UBOGON,UBOGON,0x3e79,UBOGON,
122.4262 +    UBOGON,0x7309,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4263 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f5d,UBOGON,UBOGON,
122.4264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f8a,UBOGON,UBOGON,UBOGON,
122.4265 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4027,UBOGON,UBOGON,UBOGON,UBOGON,
122.4266 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4267 +  },
122.4268 +  {				/* ku 14 */
122.4269 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4270 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4271 +    UBOGON,UBOGON,UBOGON,0x4146,0x4140,UBOGON,0x413f,UBOGON,UBOGON,UBOGON,
122.4272 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x419d,0x41cb,UBOGON,0x41e1,
122.4273 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4274 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x427f,UBOGON,UBOGON,UBOGON,
122.4275 +    UBOGON,UBOGON,UBOGON,0x4346,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4276 +    UBOGON,UBOGON,UBOGON,0x441a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4277 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4278 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4279 +  },
122.4280 +  {				/* ku 15 */
122.4281 +    UBOGON,UBOGON,UBOGON,0x44d3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44d0,
122.4282 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4283 +    0x458e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4284 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4285 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4286 +    UBOGON,UBOGON,UBOGON,0x46c3,0x46b6,UBOGON,UBOGON,UBOGON,0x8a2f,UBOGON,
122.4287 +    0x46c0,0x46b8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4288 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4289 +    UBOGON,0x47d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4290 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4291 +  },
122.4292 +  {				/* ku 16 */
122.4293 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4294 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4295 +    UBOGON,0x48ec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4296 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4297 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4298 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4299 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4300 +    UBOGON,UBOGON,UBOGON,0x52dc,UBOGON,UBOGON,UBOGON,0x35cc,UBOGON,0x35a2,
122.4301 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35b6,UBOGON,UBOGON,0x35c5,0x35c6,
122.4302 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4303 +  },
122.4304 +  {				/* ku 17 */
122.4305 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4306 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4307 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3683,0x5921,UBOGON,
122.4308 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36f8,UBOGON,UBOGON,
122.4309 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36f6,UBOGON,UBOGON,UBOGON,UBOGON,
122.4310 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4311 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x379b,
122.4312 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4313 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4314 +    UBOGON,0x5e3f,UBOGON,UBOGON
122.4315 +  },
122.4316 +  {				/* ku 18 */
122.4317 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x388d,UBOGON,
122.4318 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4319 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4320 +    UBOGON,UBOGON,UBOGON,0x3956,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x395b,
122.4321 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4322 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4323 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4324 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4325 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4326 +    UBOGON,0x3a96,UBOGON,UBOGON
122.4327 +  },
122.4328 +  {				/* ku 19 */
122.4329 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4330 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b7e,UBOGON,
122.4331 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3b81,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4332 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3c35,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4333 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4334 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c9b,UBOGON,
122.4335 +    UBOGON,0x3d00,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4336 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4337 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4338 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4339 +  },
122.4340 +  {				/* ku 1a */
122.4341 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4342 +    UBOGON,UBOGON,0x3ed3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4343 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f9f,UBOGON,UBOGON,UBOGON,
122.4344 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4345 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4346 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40b1,UBOGON,UBOGON,UBOGON,
122.4347 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x414b,UBOGON,
122.4348 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4349 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4350 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4351 +  },
122.4352 +  {				/* ku 1b */
122.4353 +    UBOGON,UBOGON,UBOGON,0x7b3f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4354 +    UBOGON,0x42d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4355 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4389,UBOGON,UBOGON,UBOGON,UBOGON,
122.4356 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4357 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4400,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4358 +    UBOGON,UBOGON,UBOGON,0x44dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4359 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4360 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83d0,0x4590,
122.4361 +    UBOGON,UBOGON,UBOGON,0x45b1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4362 +    0x86e7,UBOGON,UBOGON,UBOGON
122.4363 +  },
122.4364 +  {				/* ku 1c */
122.4365 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45aa,UBOGON,UBOGON,UBOGON,UBOGON,
122.4366 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4367 +    0x467d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4368 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4369 +    UBOGON,UBOGON,UBOGON,0x4769,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47a1,
122.4370 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47e7,
122.4371 +    UBOGON,UBOGON,0x47ec,UBOGON,UBOGON,UBOGON,0x47df,UBOGON,UBOGON,UBOGON,
122.4372 +    0x4833,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4373 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4374 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4375 +  },
122.4376 +  {				/* ku 1d */
122.4377 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4378 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4379 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4380 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4381 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bee,
122.4382 +    UBOGON,0x4c32,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4383 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4384 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34fc,
122.4385 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x352a,UBOGON,UBOGON,
122.4386 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4387 +  },
122.4388 +  {				/* ku 1e */
122.4389 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4390 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4391 +    UBOGON,UBOGON,UBOGON,UBOGON,0x35d3,UBOGON,UBOGON,UBOGON,0x35d7,UBOGON,
122.4392 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4393 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4394 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4395 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4396 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37f3,UBOGON,UBOGON,UBOGON,
122.4397 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4398 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4399 +  },
122.4400 +  {				/* ku 1f */
122.4401 +    0x3891,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38c0,UBOGON,
122.4402 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6117,UBOGON,0x3963,UBOGON,UBOGON,
122.4403 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4404 +    UBOGON,UBOGON,UBOGON,0x3970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4405 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4406 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4407 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b02,UBOGON,UBOGON,UBOGON,UBOGON,
122.4408 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4409 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4410 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4411 +  },
122.4412 +  {				/* ku 20 */
122.4413 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d35,UBOGON,UBOGON,UBOGON,
122.4414 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4415 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4416 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4417 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ee0,UBOGON,UBOGON,UBOGON,UBOGON,
122.4418 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4419 +    UBOGON,UBOGON,UBOGON,0x3f9a,UBOGON,UBOGON,UBOGON,0x3fa3,UBOGON,UBOGON,
122.4420 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4005,UBOGON,
122.4421 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4422 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4423 +  },
122.4424 +  {				/* ku 21 */
122.4425 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4426 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x415e,UBOGON,UBOGON,UBOGON,
122.4427 +    UBOGON,UBOGON,UBOGON,UBOGON,0x41a6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4428 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4429 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4430 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4431 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x435d,UBOGON,
122.4432 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43b8,
122.4433 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4434 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4435 +  },
122.4436 +  {				/* ku 22 */
122.4437 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4434,UBOGON,UBOGON,
122.4438 +    UBOGON,UBOGON,0x446f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4439 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4440 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4441 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4442 +    0x4594,0x4593,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4443 +    0x8714,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4444 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x88d1,UBOGON,UBOGON,UBOGON,UBOGON,
122.4445 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4446 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4447 +  },
122.4448 +  {				/* ku 23 */
122.4449 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4450 +    UBOGON,UBOGON,0x8ccb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4792,
122.4451 +    UBOGON,UBOGON,UBOGON,0x47aa,UBOGON,UBOGON,UBOGON,0x47a7,UBOGON,UBOGON,
122.4452 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4453 +    UBOGON,UBOGON,0x47ef,UBOGON,UBOGON,UBOGON,UBOGON,0x8eed,UBOGON,UBOGON,
122.4454 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4455 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4456 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4922,UBOGON,UBOGON,UBOGON,
122.4457 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4458 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4459 +  },
122.4460 +  {				/* ku 24 */
122.4461 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4462 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ab5,
122.4463 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4464 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4465 +    UBOGON,0x4b75,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4466 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3482,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4467 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52ec,UBOGON,UBOGON,UBOGON,
122.4468 +    0x52e8,UBOGON,UBOGON,UBOGON,UBOGON,0x3535,UBOGON,UBOGON,UBOGON,UBOGON,
122.4469 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4470 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4471 +  },
122.4472 +  {				/* ku 25 */
122.4473 +    UBOGON,0x35f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4474 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4475 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4476 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4477 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4478 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4479 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4480 +    UBOGON,UBOGON,0x38f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4481 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4482 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4483 +  },
122.4484 +  {				/* ku 26 */
122.4485 +    UBOGON,UBOGON,0x3a3e,UBOGON,0x3a39,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4486 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3aa1,UBOGON,UBOGON,UBOGON,UBOGON,
122.4487 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4488 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b3b,UBOGON,UBOGON,UBOGON,
122.4489 +    UBOGON,UBOGON,0x3bb7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4490 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4491 +    UBOGON,UBOGON,0x3c57,0x3c70,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4492 +    UBOGON,0x3ca7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4493 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d54,UBOGON,UBOGON,
122.4494 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4495 +  },
122.4496 +  {				/* ku 27 */
122.4497 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4498 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4499 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4500 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f31,
122.4501 +    0x7527,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4502 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fbf,UBOGON,0x3fe4,UBOGON,
122.4503 +    UBOGON,UBOGON,UBOGON,UBOGON,0x404a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4504 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4505 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40cf,UBOGON,UBOGON,UBOGON,UBOGON,
122.4506 +    UBOGON,UBOGON,UBOGON,0x798c
122.4507 +  },
122.4508 +  {				/* ku 28 */
122.4509 +    UBOGON,0x7991,UBOGON,0x4114,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4510 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4511 +    UBOGON,0x420d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4512 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4201,UBOGON,UBOGON,
122.4513 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4514 +    UBOGON,0x42f1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4515 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4516 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4517 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4518 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4519 +  },
122.4520 +  {				/* ku 29 */
122.4521 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4522 +    UBOGON,0x4476,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4523 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x450a,0x4503,UBOGON,UBOGON,
122.4524 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4525 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8660,UBOGON,UBOGON,UBOGON,UBOGON,
122.4526 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4527 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4528 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4635,0x4636,UBOGON,UBOGON,UBOGON,
122.4529 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4530 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4531 +  },
122.4532 +  {				/* ku 2a */
122.4533 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4773,UBOGON,
122.4534 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b1,UBOGON,0x47af,
122.4535 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47f4,
122.4536 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4537 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4538 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4539 +    UBOGON,UBOGON,UBOGON,0x48dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4540 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4999,UBOGON,UBOGON,
122.4541 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4542 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4543 +  },
122.4544 +  {				/* ku 2b */
122.4545 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4546 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4547 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ab6,
122.4548 +    0x4abd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4549 +    UBOGON,UBOGON,UBOGON,0x9904,UBOGON,0x999b,UBOGON,UBOGON,UBOGON,UBOGON,
122.4550 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bf4,UBOGON,UBOGON,UBOGON,
122.4551 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c35,UBOGON,UBOGON,
122.4552 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4caa,UBOGON,0x4d1f,UBOGON,UBOGON,UBOGON,
122.4553 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4554 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4555 +  },
122.4556 +  {				/* ku 2c */
122.4557 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4558 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3550,UBOGON,UBOGON,UBOGON,
122.4559 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4560 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4561 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4562 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4563 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x377b,UBOGON,UBOGON,UBOGON,
122.4564 +    UBOGON,0x3809,UBOGON,UBOGON,UBOGON,0x3807,UBOGON,UBOGON,UBOGON,UBOGON,
122.4565 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4566 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4567 +  },
122.4568 +  {				/* ku 2d */
122.4569 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4570 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4571 +    UBOGON,UBOGON,0x39bb,UBOGON,UBOGON,0x3a4b,UBOGON,UBOGON,UBOGON,0x3a4d,
122.4572 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4573 +    UBOGON,UBOGON,0x3ac2,UBOGON,UBOGON,UBOGON,UBOGON,0x3b1a,UBOGON,UBOGON,
122.4574 +    0x3b12,UBOGON,UBOGON,UBOGON,UBOGON,0x3b3c,UBOGON,UBOGON,UBOGON,UBOGON,
122.4575 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3bc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4576 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bc0,UBOGON,UBOGON,UBOGON,
122.4577 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4578 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4579 +  },
122.4580 +  {				/* ku 2e */
122.4581 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4582 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4583 +    UBOGON,UBOGON,0x729f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4584 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4585 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4586 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fe5,UBOGON,UBOGON,UBOGON,
122.4587 +    UBOGON,UBOGON,UBOGON,0x405f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4588 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4589 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4118,UBOGON,UBOGON,UBOGON,UBOGON,
122.4590 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4591 +  },
122.4592 +  {				/* ku 2f */
122.4593 +    UBOGON,UBOGON,0x41ad,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4594 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x421e,UBOGON,UBOGON,
122.4595 +    UBOGON,0x4227,UBOGON,UBOGON,UBOGON,UBOGON,0x4218,UBOGON,UBOGON,UBOGON,
122.4596 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4220,UBOGON,UBOGON,UBOGON,
122.4597 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4598 +    0x42f4,0x4302,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4599 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4600 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4601 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4602 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4603 +  },
122.4604 +  {				/* ku 30 */
122.4605 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4606 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4607 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4608 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4524,UBOGON,UBOGON,
122.4609 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4610 +    UBOGON,UBOGON,0x8770,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4611 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4612 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4613 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4614 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4615 +  },
122.4616 +  {				/* ku 31 */
122.4617 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4618 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4619 +    UBOGON,UBOGON,UBOGON,UBOGON,0x477d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4620 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8e37,
122.4621 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4622 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4623 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4864,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4624 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4625 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4626 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4627 +  },
122.4628 +  {				/* ku 32 */
122.4629 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4630 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4631 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9703,UBOGON,UBOGON,UBOGON,
122.4632 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4633 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4634 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4635 +    UBOGON,UBOGON,UBOGON,0x4ac2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4636 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4637 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4638 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4639 +  },
122.4640 +  {				/* ku 33 */
122.4641 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4642 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4643 +    UBOGON,UBOGON,UBOGON,0x4cac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4644 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4645 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4646 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x349b,UBOGON,UBOGON,UBOGON,
122.4647 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52f6,0x3526,UBOGON,UBOGON,UBOGON,
122.4648 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4649 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4650 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4651 +  },
122.4652 +  {				/* ku 34 */
122.4653 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4654 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4655 +    UBOGON,0x3815,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4656 +    UBOGON,UBOGON,UBOGON,0x389c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4657 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4658 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4659 +    UBOGON,0x64cc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4660 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4661 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4662 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4663 +  },
122.4664 +  {				/* ku 35 */
122.4665 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4666 +    UBOGON,UBOGON,0x3d64,0x3d6e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4667 +    UBOGON,0x3d5f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4668 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4669 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4670 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4671 +    0x3ef6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4672 +    UBOGON,UBOGON,0x764a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4673 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4674 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4675 +  },
122.4676 +  {				/* ku 36 */
122.4677 +    UBOGON,0x4073,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4678 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40dd,UBOGON,
122.4679 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4680 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4681 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ab9,
122.4682 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4683 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4684 +    UBOGON,UBOGON,0x7bd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4685 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4686 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4687 +  },
122.4688 +  {				/* ku 37 */
122.4689 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4690 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4691 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4692 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4693 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4694 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4695 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4696 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4697 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4698 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4699 +  },
122.4700 +  {				/* ku 38 */
122.4701 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4702 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4688,UBOGON,UBOGON,
122.4703 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4704 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4705 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4706 +    UBOGON,UBOGON,0x47bb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47ba,
122.4707 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4812,UBOGON,UBOGON,UBOGON,UBOGON,
122.4708 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4709 +    UBOGON,0x4861,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4710 +    UBOGON,UBOGON,UBOGON,0x48e1
122.4711 +  },
122.4712 +  {				/* ku 39 */
122.4713 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4714 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4715 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4716 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4717 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4718 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4719 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4720 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4721 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4722 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4723 +  },
122.4724 +  {				/* ku 3a */
122.4725 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x999f,UBOGON,UBOGON,UBOGON,UBOGON,
122.4726 +    UBOGON,0x4b89,UBOGON,0x4b8c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4727 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4728 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4729 +    UBOGON,0x9b8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4730 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9e77,UBOGON,
122.4731 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4732 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4733 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4734 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4735 +  },
122.4736 +  {				/* ku 3b */
122.4737 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4738 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4739 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x381a,UBOGON,UBOGON,
122.4740 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4741 +    UBOGON,UBOGON,UBOGON,0x3998,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4742 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4743 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4744 +    UBOGON,0x3bf1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4745 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4746 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4747 +  },
122.4748 +  {				/* ku 3c */
122.4749 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4750 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3f6a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4751 +    UBOGON,0x764b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4752 +    UBOGON,UBOGON,UBOGON,UBOGON,0x76a2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4753 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4485,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4754 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4755 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4756 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4239,UBOGON,UBOGON,UBOGON,
122.4757 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4758 +    UBOGON,UBOGON,0x423d,0x4244
122.4759 +  },
122.4760 +  {				/* ku 3d */
122.4761 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4762 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4246,UBOGON,UBOGON,UBOGON,UBOGON,
122.4763 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4764 +    0x430e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4310,UBOGON,UBOGON,
122.4765 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4766 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x443e,UBOGON,
122.4767 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4768 +    0x4484,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4769 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4549,UBOGON,
122.4770 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4771 +  },
122.4772 +  {				/* ku 3e */
122.4773 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4774 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45df,UBOGON,UBOGON,
122.4775 +    0x45f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4776 +    UBOGON,UBOGON,UBOGON,UBOGON,0x468a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4777 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4778 +    UBOGON,UBOGON,0x4702,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4779 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4780 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47c0,UBOGON,UBOGON,UBOGON,
122.4781 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4782 +    0x4815,UBOGON,UBOGON,UBOGON
122.4783 +  },
122.4784 +  {				/* ku 3f */
122.4785 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4786 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4787 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48e2,UBOGON,UBOGON,
122.4788 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4789 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4790 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4791 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4792 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4793 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4794 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4795 +  },
122.4796 +  {				/* ku 40 */
122.4797 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4798 +    UBOGON,0x4b4d,UBOGON,UBOGON,UBOGON,UBOGON,0x4b4a,UBOGON,UBOGON,UBOGON,
122.4799 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4800 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4801 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4802 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4803 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4804 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4805 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4806 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4807 +  },
122.4808 +  {				/* ku 41 */
122.4809 +    UBOGON,UBOGON,0x4d63,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4810 +    UBOGON,UBOGON,0x4d93,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4811 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x350e,UBOGON,UBOGON,UBOGON,
122.4812 +    UBOGON,0x360a,UBOGON,UBOGON,UBOGON,UBOGON,0x360d,UBOGON,UBOGON,UBOGON,
122.4813 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4814 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4815 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4816 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4817 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4818 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4819 +  },
122.4820 +  {				/* ku 42 */
122.4821 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4822 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4823 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4824 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4825 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4826 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4827 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4828 +    UBOGON,UBOGON,0x4074,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4829 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4830 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4831 +  },
122.4832 +  {				/* ku 43 */
122.4833 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4834 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4256,
122.4835 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4836 +    UBOGON,UBOGON,0x425a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4837 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42a3,UBOGON,UBOGON,UBOGON,UBOGON,
122.4838 +    UBOGON,0x42a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4839 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4840 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4841 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4842 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4843 +  },
122.4844 +  {				/* ku 44 */
122.4845 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4846 +    UBOGON,UBOGON,0x453c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4847 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x459b,0x459a,UBOGON,UBOGON,UBOGON,
122.4848 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x87f1,
122.4849 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4850 +    UBOGON,UBOGON,UBOGON,0x465e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4851 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46a7,UBOGON,UBOGON,UBOGON,
122.4852 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4853 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4854 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4855 +  },
122.4856 +  {				/* ku 45 */
122.4857 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4858 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4859 +    0x486e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4860 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x490d,UBOGON,UBOGON,UBOGON,
122.4861 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4943,UBOGON,UBOGON,UBOGON,
122.4862 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4863 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4864 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4865 +    UBOGON,UBOGON,0x4a73,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4866 +    0x4a74,UBOGON,UBOGON,0x4a70
122.4867 +  },
122.4868 +  {				/* ku 46 */
122.4869 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4870 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4871 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4872 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4873 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bdb,UBOGON,
122.4874 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4875 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4876 +    UBOGON,0x4c29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c51,UBOGON,UBOGON,
122.4877 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9bba,UBOGON,
122.4878 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4879 +  },
122.4880 +  {				/* ku 47 */
122.4881 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cdb,UBOGON,UBOGON,UBOGON,UBOGON,
122.4882 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4883 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d65,UBOGON,
122.4884 +    UBOGON,0x4d64,0x4d67,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4885 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4886 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3611,UBOGON,UBOGON,UBOGON,
122.4887 +    UBOGON,0x3733,UBOGON,UBOGON,UBOGON,UBOGON,0x3821,0x3822,UBOGON,UBOGON,
122.4888 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4889 +    UBOGON,UBOGON,0x39a6,UBOGON,UBOGON,UBOGON,UBOGON,0x39a3,UBOGON,UBOGON,
122.4890 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4891 +  },
122.4892 +  {				/* ku 48 */
122.4893 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4894 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4895 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ea1,UBOGON,UBOGON,UBOGON,
122.4896 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4897 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4898 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4899 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x425f,
122.4900 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x425c,UBOGON,UBOGON,
122.4901 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4902 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4903 +  },
122.4904 +  {				/* ku 49 */
122.4905 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4906 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4907 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4908 +    UBOGON,UBOGON,0x45f5,UBOGON,0x8804,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4909 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4711,0x470c,
122.4910 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4911 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4912 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4913 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4914 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4915 +  },
122.4916 +  {				/* ku 4a */
122.4917 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4918 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x494e,UBOGON,
122.4919 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4920 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4921 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4922 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4923 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4924 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4b94,UBOGON,UBOGON,
122.4925 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4926 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4927 +  },
122.4928 +  {				/* ku 4b */
122.4929 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4930 +    0x4c63,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c61,UBOGON,0x9bd8,UBOGON,
122.4931 +    0x4c5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ce3,UBOGON,UBOGON,
122.4932 +    0x9d7c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4933 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4934 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4935 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4936 +    UBOGON,UBOGON,0x4daf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4937 +    UBOGON,UBOGON,0x3613,UBOGON,UBOGON,0x3680,UBOGON,UBOGON,UBOGON,UBOGON,
122.4938 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4939 +  },
122.4940 +  {				/* ku 4c */
122.4941 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4942 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4943 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4944 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4db0,UBOGON,UBOGON,UBOGON,UBOGON,
122.4945 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4946 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4947 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4948 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4949 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7c46,UBOGON,
122.4950 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4951 +  },
122.4952 +  {				/* ku 4d */
122.4953 +    UBOGON,0x4323,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4954 +    UBOGON,0x4449,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4955 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4956 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4957 +    UBOGON,UBOGON,0x45fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4958 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4959 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4960 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4961 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4962 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4963 +  },
122.4964 +  {				/* ku 4e */
122.4965 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4966 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4967 +    0x4959,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4968 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4969 +    0x4a7e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4970 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4971 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ba8,
122.4972 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ba9,UBOGON,UBOGON,UBOGON,
122.4973 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4974 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4975 +  },
122.4976 +  {				/* ku 4f */
122.4977 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4978 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4979 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9d8d,UBOGON,UBOGON,UBOGON,UBOGON,
122.4980 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4981 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d54,
122.4982 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d6d,UBOGON,UBOGON,UBOGON,UBOGON,
122.4983 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4d8e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4984 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4985 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4986 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4987 +  },
122.4988 +  {				/* ku 50 */
122.4989 +    UBOGON,UBOGON,UBOGON,0x3a72,UBOGON,UBOGON,0x3c14,UBOGON,UBOGON,UBOGON,
122.4990 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4991 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d93,
122.4992 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4993 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4994 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4995 +    UBOGON,UBOGON,UBOGON,UBOGON,0x426f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.4996 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42b0,
122.4997 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x352e,UBOGON,UBOGON,
122.4998 +    UBOGON,UBOGON,UBOGON,UBOGON
122.4999 +  },
122.5000 +  {				/* ku 51 */
122.5001 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5002 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5003 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5004 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5005 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5006 +    UBOGON,UBOGON,0x4969,0x957e,UBOGON,UBOGON,UBOGON,UBOGON,0x49b4,UBOGON,
122.5007 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a4d,UBOGON,UBOGON,UBOGON,
122.5008 +    UBOGON,UBOGON,0x4a83,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5009 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5010 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5011 +  },
122.5012 +  {				/* ku 52 */
122.5013 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5014 +    UBOGON,UBOGON,0x4bb0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5015 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5016 +    0x4c0c,UBOGON,0x4c18,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5017 +    UBOGON,UBOGON,0x9c20,UBOGON,UBOGON,0x9c22,UBOGON,UBOGON,0x9c1e,UBOGON,
122.5018 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5019 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cf5,UBOGON,UBOGON,UBOGON,
122.5020 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5021 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5022 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5023 +  },
122.5024 +  {				/* ku 53 */
122.5025 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5026 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5027 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5030 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3e0e,UBOGON,UBOGON,UBOGON,UBOGON,0x3fd8,
122.5031 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5032 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5033 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5034 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5035 +  },
122.5036 +  {				/* ku 54 */
122.5037 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5038 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5039 +    UBOGON,UBOGON,UBOGON,0x8970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5040 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5041 +    UBOGON,UBOGON,0x482c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5042 +    UBOGON,UBOGON,0x496e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5043 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a86,UBOGON,UBOGON,UBOGON,UBOGON,
122.5044 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5045 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bb3,UBOGON,UBOGON,UBOGON,0x4beb,
122.5046 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5047 +  },
122.5048 +  {				/* ku 55 */
122.5049 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5050 +    UBOGON,UBOGON,0x9c43,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5051 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5052 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9de0,UBOGON,UBOGON,0x4d42,
122.5053 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4d41,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5054 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5055 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4dac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5056 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b2f,0x3b2e,UBOGON,UBOGON,
122.5057 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c4d,0x3c7b,UBOGON,UBOGON,
122.5058 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5059 +  },
122.5060 +  {				/* ku 56 */
122.5061 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5062 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5063 +    UBOGON,UBOGON,UBOGON,UBOGON,0x42b2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5064 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5065 +    UBOGON,UBOGON,UBOGON,0x4722,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5066 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5067 +    0x9459,UBOGON,0x4970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5068 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5069 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5070 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5071 +  },
122.5072 +  {				/* ku 57 */
122.5073 +    UBOGON,UBOGON,UBOGON,0x4c95,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5074 +    UBOGON,0x4d00,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d02,
122.5075 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5076 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5077 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4d9f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5078 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5079 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5080 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5081 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5082 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5083 +  },
122.5084 +  {				/* ku 58 */
122.5085 +    UBOGON,UBOGON,UBOGON,UBOGON,0x457d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5086 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5087 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5088 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4af6,
122.5089 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c12,
122.5090 +    UBOGON,UBOGON,UBOGON,0x4c91,UBOGON,UBOGON,UBOGON,UBOGON,0x4c90,UBOGON,
122.5091 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5092 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5093 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5094 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5095 +  },
122.5096 +  {				/* ku 59 */
122.5097 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a79,
122.5098 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3c4e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5099 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5100 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5101 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5102 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5103 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5104 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5105 +    UBOGON,UBOGON,0x4d1e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5106 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5107 +  },
122.5108 +  {				/* ku 5a */
122.5109 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5110 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5111 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5112 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5113 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5114 +    0x9c72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5115 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5116 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5117 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5118 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5119 +  },
122.5120 +  {				/* ku 5b */
122.5121 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5122 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5123 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3828,UBOGON,
122.5124 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5125 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5126 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5127 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5128 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5129 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d91,
122.5130 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5131 +  },
122.5132 +  {				/* ku 5c */
122.5133 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5134 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5135 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4587,
122.5136 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5137 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5138 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5139 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5140 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5141 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5142 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5143 +  }
122.5144 +};
122.5145 +
122.5146 +/* CNS 11643 plane 6 conversion table */
122.5147 +
122.5148 +static const unsigned short
122.5149 + cns11643_6tab[MAX_CNS11643_KU_6][MAX_CNS11643_TEN] = {
122.5150 +  {				/* ku 01 */
122.5151 +    UBOGON,UBOGON,0x3405,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5152 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5153 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x353f,UBOGON,UBOGON,UBOGON,
122.5154 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5155 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5156 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5157 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5158 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x382a,UBOGON,UBOGON,
122.5159 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38a7,UBOGON,
122.5160 +    UBOGON,UBOGON,UBOGON,0x38fa
122.5161 +  },
122.5162 +  {				/* ku 02 */
122.5163 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5164 +    UBOGON,0x3400,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5165 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5166 +    UBOGON,UBOGON,0x34db,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5167 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5168 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5169 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5170 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5171 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5172 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5173 +  },
122.5174 +  {				/* ku 03 */
122.5175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5176 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3438,UBOGON,UBOGON,UBOGON,UBOGON,
122.5180 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5181 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5182 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6530,UBOGON,UBOGON,UBOGON,UBOGON,
122.5183 +    0x353a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5184 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5185 +  },
122.5186 +  {				/* ku 04 */
122.5187 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5188 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5190 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5191 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5192 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5193 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5194 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38c9,
122.5195 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5196 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5197 +  },
122.5198 +  {				/* ku 05 */
122.5199 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3c4f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5203 +    0x43cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4492,UBOGON,UBOGON,UBOGON,
122.5204 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5205 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5206 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5207 +    0x3445,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5208 +    0x34b5,UBOGON,0x34b6,UBOGON
122.5209 +  },
122.5210 +  {				/* ku 06 */
122.5211 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5213 +    UBOGON,0x3537,UBOGON,0x3530,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5217 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5218 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5219 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x373e,0x374d,0x3751,
122.5220 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5221 +  },
122.5222 +  {				/* ku 07 */
122.5223 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5225 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3873,UBOGON,
122.5227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5229 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5230 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39be,UBOGON,UBOGON,
122.5231 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5232 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5233 +  },
122.5234 +  {				/* ku 08 */
122.5235 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5236 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c1e,UBOGON,UBOGON,UBOGON,UBOGON,
122.5237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cc8,UBOGON,UBOGON,UBOGON,UBOGON,
122.5239 +    0x3cc3,0x3cc7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5241 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f56,UBOGON,0x3540,UBOGON,UBOGON,
122.5242 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5243 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5244 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5245 +  },
122.5246 +  {				/* ku 09 */
122.5247 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5248 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5249 +    0x49bd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5250 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5251 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5252 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5253 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5254 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x351a,UBOGON,
122.5255 +    UBOGON,0x352c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5256 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5257 +  },
122.5258 +  {				/* ku 0a */
122.5259 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3549,
122.5260 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5261 +    UBOGON,UBOGON,UBOGON,UBOGON,0x357c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5262 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5263 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5265 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5266 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5267 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37bf,UBOGON,UBOGON,UBOGON,UBOGON,
122.5268 +    0x37ba,UBOGON,UBOGON,UBOGON
122.5269 +  },
122.5270 +  {				/* ku 0b */
122.5271 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5272 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5273 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38d8,
122.5274 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5275 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39b2,
122.5276 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5277 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5278 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ac4,
122.5279 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5280 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5281 +  },
122.5282 +  {				/* ku 0c */
122.5283 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5284 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5285 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5286 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5287 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5288 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5289 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5290 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5291 +    0x3e2b,UBOGON,UBOGON,UBOGON,0x3e61,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5292 +    UBOGON,UBOGON,UBOGON,0x72dd
122.5293 +  },
122.5294 +  {				/* ku 0d */
122.5295 +    0x3eb2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5296 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5297 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5298 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5299 +    0x4129,UBOGON,UBOGON,UBOGON,UBOGON,0x4192,UBOGON,UBOGON,UBOGON,UBOGON,
122.5300 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5301 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5302 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5303 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5304 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5305 +  },
122.5306 +  {				/* ku 0e */
122.5307 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5308 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5309 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5310 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5311 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5312 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3458,UBOGON,UBOGON,
122.5313 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5314 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5315 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5316 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5317 +  },
122.5318 +  {				/* ku 0f */
122.5319 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x351c,UBOGON,UBOGON,UBOGON,
122.5320 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5321 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5322 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5323 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5324 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5325 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3637,UBOGON,
122.5326 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5327 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5328 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5329 +  },
122.5330 +  {				/* ku 10 */
122.5331 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5332 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5333 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5334 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5335 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5336 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5337 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3843,UBOGON,UBOGON,UBOGON,
122.5338 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5339 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38b4,
122.5340 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5341 +  },
122.5342 +  {				/* ku 11 */
122.5343 +    UBOGON,UBOGON,UBOGON,UBOGON,0x38e0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5344 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5345 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5346 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5347 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5348 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5349 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5350 +    0x3ae4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5351 +    UBOGON,0x6804,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c26,UBOGON,UBOGON,
122.5352 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5353 +  },
122.5354 +  {				/* ku 12 */
122.5355 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5356 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5357 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5358 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5359 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5360 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5361 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5362 +    0x3e6f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5363 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5364 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5365 +  },
122.5366 +  {				/* ku 13 */
122.5367 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5368 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5369 +    UBOGON,UBOGON,UBOGON,0x401c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5370 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4100,
122.5371 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5372 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5373 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42b6,UBOGON,UBOGON,
122.5374 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5375 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5376 +    UBOGON,UBOGON,0x43e4,UBOGON
122.5377 +  },
122.5378 +  {				/* ku 14 */
122.5379 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5380 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5381 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44ad,UBOGON,0x82ff,UBOGON,UBOGON,
122.5382 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5383 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5384 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5385 +    UBOGON,UBOGON,UBOGON,0x8fec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5386 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48c3,UBOGON,UBOGON,UBOGON,
122.5387 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5388 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5389 +  },
122.5390 +  {				/* ku 15 */
122.5391 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5392 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5393 +    UBOGON,UBOGON,UBOGON,0x3467,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5394 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5395 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5396 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5397 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5398 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5399 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53de,UBOGON,UBOGON,
122.5400 +    UBOGON,UBOGON,0x3596,UBOGON
122.5401 +  },
122.5402 +  {				/* ku 16 */
122.5403 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5404 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5405 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5406 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5407 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5408 +    UBOGON,UBOGON,UBOGON,UBOGON,0x5a30,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5409 +    0x3759,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5bb2,
122.5410 +    UBOGON,0x3776,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5411 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5412 +    UBOGON,0x37d2,UBOGON,UBOGON
122.5413 +  },
122.5414 +  {				/* ku 17 */
122.5415 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5416 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5417 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5418 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5419 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5420 +    UBOGON,0x3920,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3929,UBOGON,UBOGON,
122.5421 +    UBOGON,0x3938,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5422 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5423 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5424 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5425 +  },
122.5426 +  {				/* ku 18 */
122.5427 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5428 +    0x3a89,0x3ab0,UBOGON,UBOGON,UBOGON,0x3abf,UBOGON,UBOGON,UBOGON,0x3ac5,
122.5429 +    UBOGON,UBOGON,0x3aea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5430 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5431 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5432 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5433 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c37,UBOGON,UBOGON,
122.5434 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5435 +    UBOGON,0x3ce4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5436 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5437 +  },
122.5438 +  {				/* ku 19 */
122.5439 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5440 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ce8,UBOGON,
122.5441 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5442 +    UBOGON,0x3e20,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5443 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5444 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5445 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5446 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3f86,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5447 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5448 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5449 +  },
122.5450 +  {				/* ku 1a */
122.5451 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5452 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5453 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5454 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5455 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5456 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5457 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5458 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4356,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5459 +    UBOGON,UBOGON,UBOGON,0x4367,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5460 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5461 +  },
122.5462 +  {				/* ku 1b */
122.5463 +    0x8038,UBOGON,UBOGON,0x8081,UBOGON,UBOGON,UBOGON,0x43d1,UBOGON,UBOGON,
122.5464 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43eb,UBOGON,UBOGON,UBOGON,
122.5465 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5466 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5467 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5468 +    UBOGON,UBOGON,UBOGON,0x44b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5469 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5470 +    UBOGON,UBOGON,0x45a3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5471 +    UBOGON,UBOGON,0x4610,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5472 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5473 +  },
122.5474 +  {				/* ku 1c */
122.5475 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5476 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5477 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5478 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5479 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5480 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5481 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x491b,UBOGON,0x4987,UBOGON,
122.5482 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5483 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5484 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5485 +  },
122.5486 +  {				/* ku 1d */
122.5487 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5488 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5489 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5490 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5491 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5492 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5493 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3557,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5494 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5495 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5496 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5497 +  },
122.5498 +  {				/* ku 1e */
122.5499 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5500 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5501 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5502 +    UBOGON,UBOGON,UBOGON,0x369d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5503 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5504 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x375f,UBOGON,UBOGON,
122.5505 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3779,UBOGON,UBOGON,
122.5506 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3798,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5507 +    UBOGON,UBOGON,UBOGON,UBOGON,0x37dc,UBOGON,UBOGON,0x37df,UBOGON,UBOGON,
122.5508 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5509 +  },
122.5510 +  {				/* ku 1f */
122.5511 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5512 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5513 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5514 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5515 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5516 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5517 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5518 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5519 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5520 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5521 +  },
122.5522 +  {				/* ku 20 */
122.5523 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5524 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39fd,UBOGON,UBOGON,
122.5525 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5526 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5527 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3af4,UBOGON,0x3aef,UBOGON,
122.5528 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5529 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5530 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c31,UBOGON,UBOGON,
122.5531 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5532 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5533 +  },
122.5534 +  {				/* ku 21 */
122.5535 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5536 +    0x3d03,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5537 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5538 +    UBOGON,UBOGON,0x3d09,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5539 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5540 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5541 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e3e,
122.5542 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e77,UBOGON,UBOGON,UBOGON,
122.5543 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3e7b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5544 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5545 +  },
122.5546 +  {				/* ku 22 */
122.5547 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5548 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5549 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5550 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5551 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5552 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5553 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x413a,
122.5554 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41a0,UBOGON,
122.5555 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41e5,UBOGON,UBOGON,UBOGON,UBOGON,
122.5556 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5557 +  },
122.5558 +  {				/* ku 23 */
122.5559 +    UBOGON,0x427d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5560 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5561 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x436d,UBOGON,UBOGON,
122.5562 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5563 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5564 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43f8,UBOGON,0x8158,UBOGON,UBOGON,
122.5565 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4450,UBOGON,UBOGON,
122.5566 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4468,
122.5567 +    0x4467,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5568 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5569 +  },
122.5570 +  {				/* ku 24 */
122.5571 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44cf,UBOGON,UBOGON,
122.5572 +    UBOGON,0x44cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5573 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5574 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45ab,
122.5575 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5576 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5577 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5578 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46c1,UBOGON,UBOGON,0x8a24,
122.5579 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5580 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5581 +  },
122.5582 +  {				/* ku 25 */
122.5583 +    UBOGON,0x4747,UBOGON,0x4757,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5584 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5585 +    UBOGON,UBOGON,UBOGON,0x8dc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5586 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x484e,UBOGON,UBOGON,UBOGON,
122.5587 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5588 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5589 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5590 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5591 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5592 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5593 +  },
122.5594 +  {				/* ku 26 */
122.5595 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5596 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5597 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5598 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5599 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5600 +    UBOGON,UBOGON,0x3477,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5601 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x51f2,UBOGON,
122.5602 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5603 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5604 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5605 +  },
122.5606 +  {				/* ku 27 */
122.5607 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x55b6,UBOGON,
122.5608 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5609 +    UBOGON,UBOGON,UBOGON,UBOGON,0x35c4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5610 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5611 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3652,UBOGON,UBOGON,UBOGON,UBOGON,
122.5612 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5613 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5614 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5615 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5616 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5617 +  },
122.5618 +  {				/* ku 28 */
122.5619 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5620 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5621 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5622 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x386b,0x5ec3,UBOGON,UBOGON,UBOGON,
122.5623 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5624 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5625 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5626 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3941,UBOGON,
122.5627 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3950,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5628 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5629 +  },
122.5630 +  {				/* ku 29 */
122.5631 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5632 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5633 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5634 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5635 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5636 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5637 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3ac0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5638 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5639 +    UBOGON,UBOGON,0x3afc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5640 +    0x3479,UBOGON,UBOGON,0x440b
122.5641 +  },
122.5642 +  {				/* ku 2a */
122.5643 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5644 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5645 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5646 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5647 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5648 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5649 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5650 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d1e,UBOGON,UBOGON,UBOGON,
122.5651 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5652 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5653 +  },
122.5654 +  {				/* ku 2b */
122.5655 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5656 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5657 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5658 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3e85,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5659 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5660 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f97,UBOGON,UBOGON,
122.5661 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5662 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5663 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5664 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5665 +  },
122.5666 +  {				/* ku 2c */
122.5667 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5668 +    0x4093,UBOGON,UBOGON,UBOGON,0x7861,UBOGON,UBOGON,UBOGON,0x40b2,UBOGON,
122.5669 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5670 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a01,
122.5671 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5672 +    0x41a4,UBOGON,UBOGON,0x41f2,UBOGON,UBOGON,UBOGON,UBOGON,0x41f1,UBOGON,
122.5673 +    UBOGON,UBOGON,UBOGON,0x4281,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5674 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5675 +    0x42dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5676 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5677 +  },
122.5678 +  {				/* ku 2d */
122.5679 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5680 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5681 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5682 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5683 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5684 +    UBOGON,0x440c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5685 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x446d,UBOGON,UBOGON,UBOGON,
122.5686 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5687 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5688 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5689 +  },
122.5690 +  {				/* ku 2e */
122.5691 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44e6,UBOGON,UBOGON,UBOGON,
122.5692 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5693 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5694 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5695 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8849,UBOGON,UBOGON,UBOGON,
122.5696 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5697 +    UBOGON,UBOGON,UBOGON,0x8999,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5698 +    UBOGON,UBOGON,UBOGON,UBOGON,0x46d1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5699 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x472c,
122.5700 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5701 +  },
122.5702 +  {				/* ku 2f */
122.5703 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x476e,UBOGON,
122.5704 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5705 +    UBOGON,0x47e5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47e6,UBOGON,UBOGON,
122.5706 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x489f,
122.5707 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5708 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5709 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5710 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x921f,UBOGON,
122.5711 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5712 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5713 +  },
122.5714 +  {				/* ku 30 */
122.5715 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5716 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a0d,UBOGON,UBOGON,UBOGON,
122.5717 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5718 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5719 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5720 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5721 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5722 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34f8,UBOGON,UBOGON,UBOGON,UBOGON,
122.5723 +    UBOGON,UBOGON,UBOGON,0x5313,UBOGON,0x3533,UBOGON,UBOGON,UBOGON,0x353c,
122.5724 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5725 +  },
122.5726 +  {				/* ku 31 */
122.5727 +    UBOGON,0x354f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5728 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35dc,UBOGON,UBOGON,
122.5729 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5730 +    UBOGON,UBOGON,UBOGON,UBOGON,0x55e0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5731 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5732 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5733 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5734 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5735 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5736 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5737 +  },
122.5738 +  {				/* ku 32 */
122.5739 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5740 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37f5,
122.5741 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5742 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5743 +    UBOGON,UBOGON,UBOGON,UBOGON,0x38c3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5744 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5745 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6139,UBOGON,UBOGON,
122.5746 +    UBOGON,UBOGON,0x3971,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5747 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5748 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5749 +  },
122.5750 +  {				/* ku 33 */
122.5751 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5752 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5753 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b01,UBOGON,
122.5754 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5755 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5756 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5757 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5758 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5759 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5760 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5761 +  },
122.5762 +  {				/* ku 34 */
122.5763 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5764 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5765 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5766 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5767 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6ed7,UBOGON,0x3d41,UBOGON,UBOGON,
122.5768 +    UBOGON,0x3dd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5769 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5770 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5771 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e45,UBOGON,UBOGON,
122.5772 +    UBOGON,0x733d,UBOGON,UBOGON
122.5773 +  },
122.5774 +  {				/* ku 35 */
122.5775 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5776 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5777 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5778 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5779 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ff2,
122.5780 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5781 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4049,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5782 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5783 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5784 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5785 +  },
122.5786 +  {				/* ku 36 */
122.5787 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41a9,UBOGON,UBOGON,UBOGON,
122.5788 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5789 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5790 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5791 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5792 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5793 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5794 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43cb,UBOGON,UBOGON,UBOGON,
122.5795 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x440d,UBOGON,UBOGON,UBOGON,UBOGON,
122.5796 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5797 +  },
122.5798 +  {				/* ku 37 */
122.5799 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5800 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5801 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5802 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5803 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5804 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5805 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5806 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5807 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5808 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5809 +  },
122.5810 +  {				/* ku 38 */
122.5811 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5812 +    0x4631,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5813 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5814 +    UBOGON,UBOGON,0x46d5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5815 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5816 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5817 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5818 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5819 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5820 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5821 +  },
122.5822 +  {				/* ku 39 */
122.5823 +    UBOGON,UBOGON,UBOGON,0x4856,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5824 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5825 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5826 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5827 +    UBOGON,UBOGON,UBOGON,0x48f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5828 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5829 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5830 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5831 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5832 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5833 +  },
122.5834 +  {				/* ku 3a */
122.5835 +    UBOGON,UBOGON,UBOGON,0x9775,UBOGON,UBOGON,UBOGON,0x4a58,UBOGON,UBOGON,
122.5836 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5837 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5838 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5839 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5840 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5841 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5842 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5843 +    UBOGON,UBOGON,0x3487,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5844 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5845 +  },
122.5846 +  {				/* ku 3b */
122.5847 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5848 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5849 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5850 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5851 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5852 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5853 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5854 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5855 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5856 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5857 +  },
122.5858 +  {				/* ku 3c */
122.5859 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5860 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5861 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5862 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37fa,UBOGON,UBOGON,UBOGON,UBOGON,
122.5863 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5864 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5865 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5866 +    0x38f2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5867 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5868 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5869 +  },
122.5870 +  {				/* ku 3d */
122.5871 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5872 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a2f,UBOGON,UBOGON,
122.5873 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5874 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5875 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ac1,UBOGON,
122.5876 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5877 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5878 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5879 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c40,UBOGON,UBOGON,UBOGON,
122.5880 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5881 +  },
122.5882 +  {				/* ku 3e */
122.5883 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5884 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5885 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d3f,UBOGON,UBOGON,UBOGON,
122.5886 +    UBOGON,0x3d46,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5887 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5888 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5889 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5890 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e8f,UBOGON,UBOGON,
122.5891 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5892 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5893 +  },
122.5894 +  {				/* ku 3f */
122.5895 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5896 +    UBOGON,UBOGON,0x3fac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5897 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5898 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5899 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5900 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5901 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5902 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4168,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5903 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41ab,UBOGON,UBOGON,
122.5904 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5905 +  },
122.5906 +  {				/* ku 40 */
122.5907 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5908 +    UBOGON,0x4291,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5909 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5910 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5911 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5912 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7fe4,UBOGON,UBOGON,UBOGON,UBOGON,
122.5913 +    UBOGON,UBOGON,UBOGON,0x8088,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5914 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4430,UBOGON,
122.5915 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5916 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5917 +  },
122.5918 +  {				/* ku 41 */
122.5919 +    0x445d,UBOGON,UBOGON,0x4475,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5920 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5921 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5922 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44ff,UBOGON,UBOGON,UBOGON,UBOGON,
122.5923 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5924 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x450b,UBOGON,UBOGON,UBOGON,UBOGON,
122.5925 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5926 +    UBOGON,UBOGON,0x45c8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5927 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5928 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5929 +  },
122.5930 +  {				/* ku 42 */
122.5931 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5932 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5933 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5934 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5935 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5936 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5937 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5938 +    UBOGON,UBOGON,UBOGON,0x4774,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5939 +    UBOGON,UBOGON,UBOGON,UBOGON,0x47ac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5940 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5941 +  },
122.5942 +  {				/* ku 43 */
122.5943 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5944 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5945 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5946 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5947 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5948 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5949 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5950 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5951 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5952 +    0x4a16,UBOGON,UBOGON,UBOGON
122.5953 +  },
122.5954 +  {				/* ku 44 */
122.5955 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5956 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5957 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5958 +    UBOGON,0x4b3b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5959 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5960 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5961 +    UBOGON,0x4bef,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5962 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5963 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5964 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5965 +  }
122.5966 +};
122.5967 +
122.5968 +/* CNS 11643 plane 7 conversion table */
122.5969 +
122.5970 +static const unsigned short
122.5971 + cns11643_7tab[MAX_CNS11643_KU_7][MAX_CNS11643_TEN] = {
122.5972 +  {				/* ku 01 */
122.5973 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5974 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5975 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5976 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5977 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35f6,UBOGON,UBOGON,UBOGON,UBOGON,
122.5978 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5979 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5655,UBOGON,UBOGON,UBOGON,
122.5980 +    UBOGON,UBOGON,UBOGON,0x3667,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5981 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5982 +    UBOGON,UBOGON,UBOGON,UBOGON
122.5983 +  },
122.5984 +  {				/* ku 02 */
122.5985 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5986 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5987 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5988 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5989 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5990 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5991 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5992 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5993 +    0x617f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5994 +    UBOGON,0x3992,UBOGON,UBOGON
122.5995 +  },
122.5996 +  {				/* ku 03 */
122.5997 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5998 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.5999 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a45,UBOGON,UBOGON,UBOGON,UBOGON,
122.6000 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6001 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6002 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6003 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6004 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bc9,UBOGON,
122.6005 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6006 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6007 +  },
122.6008 +  {				/* ku 04 */
122.6009 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6010 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6011 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6012 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6013 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6014 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6015 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3d55,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6016 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6017 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6018 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6019 +  },
122.6020 +  {				/* ku 05 */
122.6021 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6022 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6023 +    UBOGON,UBOGON,0x3ee8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6024 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6025 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6026 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fb6,UBOGON,UBOGON,UBOGON,0x3fbd,
122.6027 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6030 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6031 +  },
122.6032 +  {				/* ku 06 */
122.6033 +    UBOGON,UBOGON,UBOGON,0x40d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6034 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4171,UBOGON,UBOGON,
122.6035 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6036 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6037 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6038 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4298,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6039 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6040 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6041 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6042 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6043 +  },
122.6044 +  {				/* ku 07 */
122.6045 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6046 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6047 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6048 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6049 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6050 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6051 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6052 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6053 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6054 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6055 +  },
122.6056 +  {				/* ku 08 */
122.6057 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6058 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6059 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6060 +    UBOGON,UBOGON,UBOGON,0x45cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6061 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6062 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6063 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6064 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6065 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46f6,UBOGON,
122.6066 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6067 +  },
122.6068 +  {				/* ku 09 */
122.6069 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6070 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6071 +    UBOGON,0x477a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b8,UBOGON,
122.6072 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6073 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4801,UBOGON,UBOGON,UBOGON,UBOGON,
122.6074 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6075 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6076 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6077 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6078 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6079 +  },
122.6080 +  {				/* ku 0a */
122.6081 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6082 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6083 +    UBOGON,UBOGON,UBOGON,0x492f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4931,
122.6084 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x499c,UBOGON,UBOGON,
122.6085 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6086 +    UBOGON,0x49e6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6087 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6088 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6089 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6090 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6091 +  },
122.6092 +  {				/* ku 0b */
122.6093 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6094 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6095 +    UBOGON,UBOGON,UBOGON,0x4b38,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6096 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6097 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6098 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6099 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6100 +    UBOGON,UBOGON,UBOGON,0x4c3a,UBOGON,UBOGON,0x4cb1,UBOGON,UBOGON,UBOGON,
122.6101 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6102 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6103 +  },
122.6104 +  {				/* ku 0c */
122.6105 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6106 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d47,UBOGON,0x4d51,UBOGON,
122.6107 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6108 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6109 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6110 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6111 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6112 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6113 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6114 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6115 +  },
122.6116 +  {				/* ku 0d */
122.6117 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6118 +    UBOGON,UBOGON,0x3747,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6119 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6120 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6121 +    UBOGON,UBOGON,UBOGON,0x3817,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6122 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38a3,UBOGON,
122.6123 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6124 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6125 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6126 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6127 +  },
122.6128 +  {				/* ku 0e */
122.6129 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6130 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6131 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6132 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6133 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6134 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b1e,UBOGON,UBOGON,
122.6135 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6136 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6137 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6138 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6139 +  },
122.6140 +  {				/* ku 0f */
122.6141 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6142 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6143 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6144 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6145 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x71d7,UBOGON,UBOGON,UBOGON,
122.6146 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6147 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6148 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6149 +    UBOGON,UBOGON,UBOGON,0x3e9a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6150 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6151 +  },
122.6152 +  {				/* ku 10 */
122.6153 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6154 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6155 +    UBOGON,0x3fc2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6156 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6157 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6158 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40dc,UBOGON,UBOGON,UBOGON,
122.6159 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6160 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41b3,UBOGON,
122.6161 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6162 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6163 +  },
122.6164 +  {				/* ku 11 */
122.6165 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6166 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6167 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6168 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6169 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6170 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6171 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6172 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6173 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6174 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6175 +  },
122.6176 +  {				/* ku 12 */
122.6177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6180 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6181 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6182 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6183 +    UBOGON,UBOGON,UBOGON,UBOGON,0x8666,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6184 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6185 +    UBOGON,UBOGON,0x45d9,UBOGON,0x45dd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6186 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6187 +  },
122.6188 +  {				/* ku 13 */
122.6189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6190 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6191 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6192 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6193 +    UBOGON,UBOGON,UBOGON,UBOGON,0x46fc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6194 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6195 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6196 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6197 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6198 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6199 +  },
122.6200 +  {				/* ku 14 */
122.6201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8f3a,UBOGON,UBOGON,
122.6203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6204 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6205 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6206 +    UBOGON,0x4907,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6207 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x933d,UBOGON,UBOGON,UBOGON,
122.6208 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6209 +    UBOGON,UBOGON,0x49a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6210 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6211 +  },
122.6212 +  {				/* ku 15 */
122.6213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6217 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4aca,UBOGON,
122.6218 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6219 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6220 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6221 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6222 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6223 +  },
122.6224 +  {				/* ku 16 */
122.6225 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4b8d,UBOGON,UBOGON,
122.6226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6229 +    UBOGON,0x4cc0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cca,UBOGON,
122.6230 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d25,
122.6231 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d4a,UBOGON,
122.6232 +    0x4d53,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6233 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6234 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6235 +  },
122.6236 +  {				/* ku 17 */
122.6237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6239 +    UBOGON,UBOGON,0x3605,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6241 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6242 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6243 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6244 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6245 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6246 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6247 +  },
122.6248 +  {				/* ku 18 */
122.6249 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6250 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6251 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6252 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6253 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6254 +    UBOGON,UBOGON,0x3bf0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6255 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6256 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6257 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6258 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6259 +  },
122.6260 +  {				/* ku 19 */
122.6261 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e02,UBOGON,UBOGON,UBOGON,UBOGON,
122.6262 +    UBOGON,UBOGON,0x3e23,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6263 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6265 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6266 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6267 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6268 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6269 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6270 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6271 +  },
122.6272 +  {				/* ku 1a */
122.6273 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6274 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6275 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4315,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6276 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6277 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6278 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6279 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6280 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6281 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6282 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6283 +  },
122.6284 +  {				/* ku 1b */
122.6285 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6286 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x455d,UBOGON,UBOGON,
122.6287 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6288 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6289 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6290 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x465a,UBOGON,UBOGON,UBOGON,
122.6291 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6292 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6293 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6294 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6295 +  },
122.6296 +  {				/* ku 1c */
122.6297 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6298 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4785,UBOGON,
122.6299 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6300 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6301 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6302 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6303 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6304 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x490b,
122.6305 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4939,UBOGON,UBOGON,UBOGON,
122.6306 +    0x4937,UBOGON,UBOGON,UBOGON
122.6307 +  },
122.6308 +  {				/* ku 1d */
122.6309 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6310 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6311 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6312 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6313 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6314 +    UBOGON,UBOGON,UBOGON,0x4a6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6315 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6316 +    UBOGON,UBOGON,0x4acd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6317 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6318 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6319 +  },
122.6320 +  {				/* ku 1e */
122.6321 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6322 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6323 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6324 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6325 +    0x4c4d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6326 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6327 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6328 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6329 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6330 +    UBOGON,UBOGON,0x3510,UBOGON
122.6331 +  },
122.6332 +  {				/* ku 1f */
122.6333 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6334 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x367b,UBOGON,UBOGON,UBOGON,UBOGON,
122.6335 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6336 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x381d,UBOGON,UBOGON,UBOGON,UBOGON,
122.6337 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6338 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6339 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x64f5,UBOGON,UBOGON,UBOGON,UBOGON,
122.6340 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6341 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b27,UBOGON,UBOGON,UBOGON,UBOGON,
122.6342 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6343 +  },
122.6344 +  {				/* ku 20 */
122.6345 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6346 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6347 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6348 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6349 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6350 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6351 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6352 +    0x3fcf,UBOGON,UBOGON,UBOGON,0x3fcd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6353 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6354 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6355 +  },
122.6356 +  {				/* ku 21 */
122.6357 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6358 +    UBOGON,UBOGON,UBOGON,0x4182,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6359 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6360 +    0x4252,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6361 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6362 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6363 +    UBOGON,UBOGON,UBOGON,UBOGON,0x7f80,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6364 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6365 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6366 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6367 +  },
122.6368 +  {				/* ku 22 */
122.6369 +    UBOGON,UBOGON,UBOGON,0x4451,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6370 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6371 +    UBOGON,UBOGON,UBOGON,0x455a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6372 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6373 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6374 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6375 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6376 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6377 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6378 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6379 +  },
122.6380 +  {				/* ku 23 */
122.6381 +    UBOGON,0x4665,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6382 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6383 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6384 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6385 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d01,
122.6386 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6387 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6388 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6389 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48af,UBOGON,UBOGON,UBOGON,
122.6390 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6391 +  },
122.6392 +  {				/* ku 24 */
122.6393 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6394 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6395 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4941,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6396 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6397 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6398 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a29,UBOGON,UBOGON,UBOGON,UBOGON,
122.6399 +    UBOGON,UBOGON,UBOGON,0x4a2a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6400 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6401 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a96,UBOGON,UBOGON,UBOGON,
122.6402 +    UBOGON,UBOGON,UBOGON,0x4b12
122.6403 +  },
122.6404 +  {				/* ku 25 */
122.6405 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6406 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6407 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6408 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6409 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6410 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6411 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6412 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6413 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6414 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6415 +  },
122.6416 +  {				/* ku 26 */
122.6417 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6418 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6419 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6420 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x367e,0x58e1,UBOGON,UBOGON,UBOGON,
122.6421 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6422 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6423 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6424 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6425 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6426 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6427 +  },
122.6428 +  {				/* ku 27 */
122.6429 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6430 +    UBOGON,0x39a7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6431 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6432 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6433 +    UBOGON,0x4320,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6434 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6435 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6436 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6437 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6438 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6439 +  },
122.6440 +  {				/* ku 28 */
122.6441 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6442 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6443 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6444 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6445 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6446 +    UBOGON,UBOGON,UBOGON,UBOGON,0x7ce9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6447 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6448 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6449 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6450 +    UBOGON,0x81cb,UBOGON,UBOGON
122.6451 +  },
122.6452 +  {				/* ku 29 */
122.6453 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6454 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6455 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6456 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6457 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6458 +    0x4565,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6459 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6460 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6461 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6462 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6463 +  },
122.6464 +  {				/* ku 2a */
122.6465 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4704,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6466 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6467 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6468 +    UBOGON,UBOGON,0x4764,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6469 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6470 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4823,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6471 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6472 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6473 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6474 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6475 +  },
122.6476 +  {				/* ku 2b */
122.6477 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6478 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6479 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6480 +    UBOGON,0x95d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6481 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6482 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6483 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6484 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6485 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6486 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6487 +  },
122.6488 +  {				/* ku 2c */
122.6489 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6490 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6491 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6492 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6493 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6494 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6495 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6496 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6497 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6498 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6499 +  },
122.6500 +  {				/* ku 2d */
122.6501 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6502 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6503 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34b9,UBOGON,
122.6504 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6505 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6506 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6507 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6508 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6509 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6510 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6511 +  },
122.6512 +  {				/* ku 2e */
122.6513 +    UBOGON,0x3c4b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6514 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6515 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6516 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6517 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6518 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40f1,
122.6519 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6520 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6521 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6522 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6523 +  },
122.6524 +  {				/* ku 2f */
122.6525 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6526 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6527 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6528 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6529 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6530 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6531 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6532 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6533 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6534 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6535 +  },
122.6536 +  {				/* ku 30 */
122.6537 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4667,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6538 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4714,UBOGON,UBOGON,UBOGON,
122.6539 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6540 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6541 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6542 +    UBOGON,UBOGON,UBOGON,0x4889,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6543 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6544 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6545 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6546 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6547 +  },
122.6548 +  {				/* ku 31 */
122.6549 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6550 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6551 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6552 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6553 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6554 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6555 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6556 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6557 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c0b,UBOGON,
122.6558 +    UBOGON,UBOGON,0x4c17,UBOGON
122.6559 +  },
122.6560 +  {				/* ku 32 */
122.6561 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6562 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c6d,UBOGON,0x4c70,UBOGON,
122.6563 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6564 +    UBOGON,UBOGON,UBOGON,0x4ced,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6565 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6566 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6567 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6568 +    0x4d8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6569 +    UBOGON,UBOGON,UBOGON,0x34a7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6570 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6571 +  },
122.6572 +  {				/* ku 33 */
122.6573 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6574 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6575 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6576 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6707,UBOGON,
122.6577 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6578 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6579 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6580 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3e5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6581 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6582 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6583 +  },
122.6584 +  {				/* ku 34 */
122.6585 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6586 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6587 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42af,UBOGON,UBOGON,UBOGON,UBOGON,
122.6588 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6589 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6590 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6591 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6592 +    UBOGON,0x456b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6593 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6594 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6595 +  },
122.6596 +  {				/* ku 35 */
122.6597 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6598 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x471b,UBOGON,UBOGON,
122.6599 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6600 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6601 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6602 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6603 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6604 +    UBOGON,0x4963,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6605 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6606 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6607 +  },
122.6608 +  {				/* ku 36 */
122.6609 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4a80,0x4a84,0x4a7f,UBOGON,UBOGON,UBOGON,
122.6610 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4af1,UBOGON,UBOGON,
122.6611 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6612 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6613 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9a47,UBOGON,
122.6614 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6615 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6616 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6617 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6618 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6619 +  },
122.6620 +  {				/* ku 37 */
122.6621 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d1c,UBOGON,
122.6622 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6623 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6624 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6625 +    UBOGON,UBOGON,UBOGON,0x34a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6626 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6627 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6628 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6629 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6630 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6631 +  },
122.6632 +  {				/* ku 38 */
122.6633 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6634 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6635 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6636 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6637 +    UBOGON,UBOGON,UBOGON,0x418b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6638 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x432b,UBOGON,UBOGON,UBOGON,UBOGON,
122.6639 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6640 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6641 +    UBOGON,0x457a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6642 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6643 +  },
122.6644 +  {				/* ku 39 */
122.6645 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4609,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6646 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x466d,UBOGON,UBOGON,
122.6647 +    UBOGON,UBOGON,UBOGON,0x471f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6648 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6649 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6650 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6651 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6652 +    0x496a,0x496c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6653 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6654 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6655 +  },
122.6656 +  {				/* ku 3a */
122.6657 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6658 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6659 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bb2,
122.6660 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6661 +    UBOGON,UBOGON,0x4c1d,UBOGON,UBOGON,UBOGON,0x4c2d,UBOGON,UBOGON,UBOGON,
122.6662 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6663 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6664 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6665 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6666 +    UBOGON,UBOGON,0x4d45,UBOGON
122.6667 +  },
122.6668 +  {				/* ku 3b */
122.6669 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6670 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6671 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6672 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6673 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6674 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6675 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6676 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6677 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6678 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6679 +  },
122.6680 +  {				/* ku 3c */
122.6681 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6682 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6683 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6684 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6685 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6686 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6687 +    UBOGON,0x460a,UBOGON,UBOGON,UBOGON,UBOGON,0x460c,UBOGON,UBOGON,UBOGON,
122.6688 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6689 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x482e,UBOGON,UBOGON,UBOGON,
122.6690 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6691 +  },
122.6692 +  {				/* ku 3d */
122.6693 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6694 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6695 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6696 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6697 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6698 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6699 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6700 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6701 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6702 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6703 +  },
122.6704 +  {				/* ku 3e */
122.6705 +    UBOGON,UBOGON,0x4c8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6706 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6707 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6708 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6709 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6710 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6711 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6712 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6713 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6714 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6715 +  },
122.6716 +  {				/* ku 3f */
122.6717 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6718 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4331,UBOGON,
122.6719 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6720 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6721 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6722 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6723 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6724 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6725 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6726 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6727 +  },
122.6728 +  {				/* ku 40 */
122.6729 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6730 +    UBOGON,UBOGON,0x4bbc,0x4bbb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6731 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6732 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6733 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6734 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6735 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6736 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6737 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6738 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6739 +  },
122.6740 +  {				/* ku 41 */
122.6741 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6742 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6743 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6744 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6745 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6746 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6747 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6748 +    UBOGON,UBOGON,UBOGON,0x4c14,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6749 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6750 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6751 +  },
122.6752 +  {				/* ku 42 */
122.6753 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6754 +    UBOGON,UBOGON,UBOGON,UBOGON,0x361c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6755 +    0x3772,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6756 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6757 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6758 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6759 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6760 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6761 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6762 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6763 +  },
122.6764 +  {				/* ku 43 */
122.6765 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6766 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6767 +    UBOGON,UBOGON,0x4d0e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6768 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6769 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6770 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6771 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6772 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6773 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6774 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6775 +  },
122.6776 +  {				/* ku 44 */
122.6777 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6778 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6779 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6780 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6781 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7674,
122.6782 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6783 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6784 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6785 +    UBOGON,UBOGON,UBOGON,UBOGON,0x4bec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6786 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6787 +  },
122.6788 +  {				/* ku 45 */
122.6789 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6790 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6791 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6792 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6793 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6794 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6795 +    0x4279,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6796 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6797 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6798 +    UBOGON,UBOGON,UBOGON,UBOGON
122.6799 +  }
122.6800 +};
122.6801 +
122.6802 +#if CNS_OBSOLETE
122.6803 +/* CNS 11643 plane 14 conversion table */
122.6804 +
122.6805 +static const unsigned short
122.6806 + cns11643_14tab[MAX_CNS11643_KU_14][MAX_CNS11643_TEN] = {
122.6807 +  {				/* ku 01 */
122.6808 +    0x4e28,0x4e36,0x4e3f,0x4e85,0x4e05,0x4e04,0x5182,0x5196,0x5338,0x5369,
122.6809 +    0x53b6,0x4e2a,0x4e87,0x4e49,0x51e2,0x4e46,0x4e8f,0x4ebc,0x4ebe,0x5166,
122.6810 +    0x51e3,0x5204,0x529c,UBOGON,0x5902,0x590a,0x5b80,0x5ddb,0x5e7a,0x5e7f,
122.6811 +    0x5ef4,0x5f50,0x5f51,0x5f61,0x961d,UBOGON,0x4e63,0x4e62,0x4ea3,0x5185,
122.6812 +    0x4ec5,0x4ecf,0x4ece,0x4ecc,0x5184,0x5186,UBOGON,UBOGON,0x51e4,0x5205,
122.6813 +    0x529e,0x529d,0x52fd,0x5300,0x533a,UBOGON,0x5346,0x535d,0x5386,0x53b7,
122.6814 +    UBOGON,0x53cc,UBOGON,0x53ce,0x5721,UBOGON,0x5e00,0x5f0c,0x6237,0x6238,
122.6815 +    0x6534,0x6535,0x65e0,UBOGON,0x738d,0x4e97,0x4ee0,UBOGON,UBOGON,0x4ee7,
122.6816 +    UBOGON,0x4ee6,UBOGON,UBOGON,UBOGON,UBOGON,0x56d8,0x518b,0x518c,0x5199,
122.6817 +    0x51e5,UBOGON,0x520b,UBOGON
122.6818 +  },
122.6819 +  {				/* ku 02 */
122.6820 +    UBOGON,0x5304,0x5303,0x5307,UBOGON,0x531e,0x535f,0x536d,0x5389,0x53ba,
122.6821 +    0x53d0,UBOGON,0x53f6,0x53f7,0x53f9,UBOGON,0x53f4,UBOGON,UBOGON,0x5724,
122.6822 +    0x5904,0x5918,0x5932,0x5930,0x5934,UBOGON,0x5975,UBOGON,0x5b82,0x5bf9,
122.6823 +    0x5c14,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5e81,0x5e83,
122.6824 +    0x5f0d,0x5f52,UBOGON,0x5fca,0x5fc7,0x6239,UBOGON,0x624f,0x65e7,0x672f,
122.6825 +    0x6b7a,0x6c39,UBOGON,UBOGON,0x6c37,0x6c44,0x6c45,0x738c,0x7592,0x7676,
122.6826 +    0x9093,0x9092,UBOGON,UBOGON,0x4e21,0x4e20,0x4e22,0x4e68,0x4e89,0x4e98,
122.6827 +    0x4ef9,0x4eef,UBOGON,UBOGON,0x4ef8,0x4f06,0x4f03,0x4efc,0x4eee,0x4f16,
122.6828 +    UBOGON,0x4f28,0x4f1c,0x4f07,0x4f1a,0x4efa,0x4f17,0x514a,UBOGON,0x5172,
122.6829 +    UBOGON,0x51b4,0x51b3,0x51b2
122.6830 +  },
122.6831 +  {				/* ku 03 */
122.6832 +    UBOGON,0x51e8,UBOGON,0x5214,0x520f,0x5215,0x5218,0x52a8,UBOGON,0x534b,
122.6833 +    0x534f,UBOGON,0x5350,UBOGON,0x538b,UBOGON,0x53be,UBOGON,0x53d2,0x5416,
122.6834 +    0x53ff,UBOGON,0x5400,UBOGON,0x5405,0x5413,0x5415,UBOGON,UBOGON,0x56e3,
122.6835 +    0x5735,0x5736,0x5731,0x5732,0x58ee,0x5905,0x4e54,UBOGON,0x5936,UBOGON,
122.6836 +    UBOGON,UBOGON,0x597a,UBOGON,0x5986,UBOGON,UBOGON,0x5b86,0x5f53,0x5c18,
122.6837 +    UBOGON,0x5c3d,0x5c78,UBOGON,UBOGON,UBOGON,UBOGON,0x5c80,UBOGON,0x5e08,
122.6838 +    UBOGON,UBOGON,UBOGON,UBOGON,0x5ef5,0x5f0e,UBOGON,UBOGON,UBOGON,0x5fd3,
122.6839 +    0x5fda,UBOGON,0x5fdb,UBOGON,0x620f,0x625d,0x625f,0x6267,0x6257,0x9f50,
122.6840 +    UBOGON,0x65eb,0x65ea,UBOGON,0x6737,UBOGON,0x6732,0x6736,0x6b22,0x6bce,
122.6841 +    UBOGON,0x6c58,0x6c51,0x6c77
122.6842 +  },
122.6843 +  {				/* ku 04 */
122.6844 +    0x6c3c,UBOGON,0x6c5a,UBOGON,0x6c53,0x706f,0x7072,0x706e,UBOGON,UBOGON,
122.6845 +    0x7073,0x72b1,0x72b2,UBOGON,0x738f,UBOGON,UBOGON,UBOGON,0x793c,UBOGON,
122.6846 +    0x808d,0x808e,UBOGON,0x827b,UBOGON,0x8d71,0x8fb9,0x9096,0x909a,UBOGON,
122.6847 +    0x4e24,0x4e71,UBOGON,0x4e9c,0x4f45,0x4f4a,0x4f39,0x4f37,UBOGON,0x4f32,
122.6848 +    0x4f42,UBOGON,0x4f44,0x4f4b,UBOGON,0x4f40,0x4f35,0x4f31,0x5151,UBOGON,
122.6849 +    0x5150,0x514e,UBOGON,UBOGON,0x519d,UBOGON,0x51b5,0x51b8,0x51ec,0x5223,
122.6850 +    0x5227,0x5226,0x521f,0x522b,0x5220,0x52b4,0x52b3,UBOGON,0x5325,0x533b,
122.6851 +    0x5374,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x544d,UBOGON,UBOGON,0x543a,
122.6852 +    UBOGON,UBOGON,0x5444,0x544c,0x5423,0x541a,0x5432,0x544b,0x5421,UBOGON,
122.6853 +    0x5434,0x5449,0x5450,0x5422
122.6854 +  },
122.6855 +  {				/* ku 05 */
122.6856 +    0x543f,0x5451,0x545a,0x542f,UBOGON,0x56e9,0x56f2,0x56f3,0x56ef,0x56ed,
122.6857 +    0x56ec,0x56e6,0x5748,UBOGON,0x5744,0x573f,0x573c,0x5753,0x5756,UBOGON,
122.6858 +    0x575f,0x5743,0x5758,0x5757,UBOGON,UBOGON,UBOGON,0x5746,UBOGON,0x573d,
122.6859 +    UBOGON,0x5742,0x5754,0x5755,0x58f1,0x58f2,0x58f0,0x590b,0x9ea6,0x56f1,
122.6860 +    0x593d,UBOGON,0x5994,0x598c,UBOGON,0x599c,UBOGON,UBOGON,0x599f,UBOGON,
122.6861 +    0x599b,UBOGON,0x5989,0x599a,UBOGON,0x6588,UBOGON,0x5b8d,UBOGON,0x5bfe,
122.6862 +    0x5bff,0x5bfd,0x5c2b,UBOGON,0x5c84,0x5c8e,0x5c9c,UBOGON,UBOGON,0x5c85,
122.6863 +    0x5df5,0x5e09,UBOGON,UBOGON,0x5e0b,UBOGON,0x5e92,0x5e90,0x5f03,UBOGON,
122.6864 +    0x5f1e,0x5f63,UBOGON,0x5fe7,0x5ffe,0x5fe6,0x5fdc,0x5fce,UBOGON,0x5ffc,
122.6865 +    0x5fdf,0x5fec,0x5ff6,UBOGON
122.6866 +  },
122.6867 +  {				/* ku 06 */
122.6868 +    0x5ff2,0x5ff0,0x5ff9,UBOGON,0x6213,UBOGON,UBOGON,0x623b,0x623c,0x6282,
122.6869 +    UBOGON,UBOGON,UBOGON,0x6278,0x628b,UBOGON,0x629e,0x62a5,0x629b,0x629c,
122.6870 +    0x6299,0x628d,0x6285,0x629d,0x6275,UBOGON,UBOGON,UBOGON,0x65f6,UBOGON,
122.6871 +    UBOGON,UBOGON,0x66f5,0x675b,UBOGON,0x6754,0x6752,UBOGON,0x6758,0x6744,
122.6872 +    0x674a,0x6761,UBOGON,0x6c7f,0x6c91,0x6c9e,UBOGON,0x6c6e,0x6c7c,0x6c9f,
122.6873 +    0x6c75,UBOGON,0x6c56,0x6ca2,0x6c79,UBOGON,0x6ca1,UBOGON,0x6caa,0x6ca0,
122.6874 +    UBOGON,0x7079,0x7077,0x707e,UBOGON,0x7075,0x707b,0x7264,UBOGON,0x72bb,
122.6875 +    0x72bc,0x72c7,0x72b9,0x72be,0x72b6,UBOGON,UBOGON,0x7398,UBOGON,UBOGON,
122.6876 +    UBOGON,UBOGON,0x7593,0x7680,UBOGON,0x7683,0x76c0,0x76c1,UBOGON,UBOGON,
122.6877 +    0x77f4,0x77f5,UBOGON,0x7acc
122.6878 +  },
122.6879 +  {				/* ku 07 */
122.6880 +    0x7acd,0x7cfa,0x809f,0x8091,0x8097,0x8094,UBOGON,0x8286,0x828c,UBOGON,
122.6881 +    0x8295,UBOGON,0x866c,UBOGON,0x8fb5,0x8fbe,0x8fc7,UBOGON,0x8fc1,0x90a9,
122.6882 +    0x90a4,UBOGON,UBOGON,UBOGON,0x90a8,0x9627,0x9626,0x962b,0x9633,0x9634,
122.6883 +    0x9629,0x4e3d,UBOGON,0x4e9d,0x4f93,0x4f8a,UBOGON,UBOGON,0x4f6d,0x4f8e,
122.6884 +    0x4fa0,0x4fa2,0x4fa1,0x4f9f,0x4fa3,UBOGON,0x4f72,UBOGON,0x4f8c,0x5156,
122.6885 +    UBOGON,UBOGON,0x5190,UBOGON,UBOGON,UBOGON,0x51ed,0x51fe,0x522f,UBOGON,
122.6886 +    0x523c,0x5234,0x5239,0x52b9,0x52b5,0x52bf,0x5355,UBOGON,0x5376,0x537a,
122.6887 +    0x5393,UBOGON,0x53c1,0x53c2,0x53d5,0x5485,UBOGON,0x545f,0x5493,0x5489,
122.6888 +    0x5479,0x9efe,0x548f,0x5469,0x546d,UBOGON,0x5494,0x546a,0x548a,UBOGON,
122.6889 +    0x56fd,0x56fb,0x56f8,UBOGON
122.6890 +  },
122.6891 +  {				/* ku 08 */
122.6892 +    0x56fc,0x56f6,0x5765,0x5781,0x5763,0x5767,UBOGON,0x576e,0x5778,0x577f,
122.6893 +    UBOGON,UBOGON,0x58f3,0x594b,0x594c,UBOGON,UBOGON,UBOGON,0x59ad,UBOGON,
122.6894 +    0x59c4,UBOGON,0x59c2,0x59b0,UBOGON,UBOGON,UBOGON,UBOGON,0x59bf,UBOGON,
122.6895 +    0x59c9,0x59b8,0x59ac,UBOGON,UBOGON,UBOGON,0x59b7,0x59d7,UBOGON,0x5b60,
122.6896 +    UBOGON,0x5b96,0x5b9e,0x5b94,0x5b9f,0x5b9d,UBOGON,0x5c00,0x5c19,UBOGON,
122.6897 +    UBOGON,0x5c49,0x5c4a,UBOGON,0x5cbb,0x5cc1,UBOGON,UBOGON,UBOGON,0x5cb9,
122.6898 +    0x5c9e,0x5cb4,0x5cba,0x5df6,0x5e13,0x5e12,0x5e77,UBOGON,0x5e98,UBOGON,
122.6899 +    0x5e99,0x5e9d,0x5ef8,UBOGON,0x5ef9,UBOGON,0x5f06,0x5f21,UBOGON,0x5f25,
122.6900 +    0x5f55,UBOGON,UBOGON,UBOGON,0x5f84,0x5f83,0x6030,0x6007,UBOGON,0x6036,
122.6901 +    UBOGON,UBOGON,UBOGON,0x5fe9
122.6902 +  },
122.6903 +  {				/* ku 09 */
122.6904 +    0x603d,0x6008,UBOGON,UBOGON,0x62ba,0x62b2,UBOGON,0x62b7,0x62e4,0x62a7,
122.6905 +    UBOGON,UBOGON,UBOGON,0x62d5,0x62e1,0x62dd,0x62a6,0x62c1,0x62c5,0x62c0,
122.6906 +    0x62df,0x62e0,0x62de,UBOGON,0x6589,UBOGON,0x65a6,0x65ba,UBOGON,0x65ff,
122.6907 +    UBOGON,0x6617,0x6618,0x6601,0x65fe,UBOGON,0x670c,UBOGON,0x676b,0x6796,
122.6908 +    0x6782,0x678a,UBOGON,0x67a3,UBOGON,0x67a2,0x678f,UBOGON,0x67f9,0x6780,
122.6909 +    0x6b26,0x6b27,0x6b68,0x6b69,UBOGON,0x6b81,0x6bb4,0x6bd1,UBOGON,UBOGON,
122.6910 +    0x6c1c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c97,0x6c6c,0x6cdf,UBOGON,
122.6911 +    0x6cea,UBOGON,0x6ce4,0x6cd8,0x6cb2,0x6cce,0x6cc8,UBOGON,0x708b,0x7088,
122.6912 +    0x7090,0x708f,UBOGON,0x7087,0x7089,0x708d,0x7081,UBOGON,0x708c,UBOGON,
122.6913 +    UBOGON,0x7240,UBOGON,UBOGON
122.6914 +  },
122.6915 +  {				/* ku 0a */
122.6916 +    0x7265,0x7266,0x7268,UBOGON,UBOGON,0x72cd,0x72d3,0x72db,UBOGON,0x72cf,
122.6917 +    0x73a7,0x73a3,0x739e,UBOGON,0x73af,UBOGON,UBOGON,0x73aa,0x739c,UBOGON,
122.6918 +    0x7542,0x7544,0x753b,0x7541,UBOGON,0x759b,0x759e,UBOGON,0x79c4,0x79c3,
122.6919 +    0x79c6,UBOGON,UBOGON,0x79c7,UBOGON,0x79ca,UBOGON,UBOGON,0x7acf,0x7c76,
122.6920 +    0x7c74,0x7cff,0x7cfc,UBOGON,UBOGON,0x7f59,0x80a8,UBOGON,UBOGON,0x80b0,
122.6921 +    UBOGON,0x80b3,UBOGON,0x80a4,0x80b6,0x80a7,0x80ac,UBOGON,0x80a6,0x5367,
122.6922 +    0x820e,0x82c4,0x833e,0x829c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82aa,
122.6923 +    UBOGON,0x82c9,UBOGON,UBOGON,0x82a6,0x82b2,UBOGON,UBOGON,UBOGON,0x8fcc,
122.6924 +    0x8fd9,0x8fca,0x8fd8,0x8fcf,0x90b7,UBOGON,0x90ad,0x90b9,0x9637,UBOGON,
122.6925 +    0x9641,0x963e,0x96b6,0x9751
122.6926 +  },
122.6927 +  {				/* ku 0b */
122.6928 +    0x9763,0x4e57,0x4e79,0x4eb2,0x4eb0,0x4eaf,0x4eb1,0x4fd2,0x4fd5,UBOGON,
122.6929 +    0x4fbe,0x4fb8,0x4fb0,0x4fb1,0x4fc8,UBOGON,UBOGON,0x4fc6,0x4fcc,0x4fe5,
122.6930 +    0x4fe3,0x4fb4,0x516a,UBOGON,0x519f,UBOGON,0x51c1,UBOGON,0x51c2,0x51c3,
122.6931 +    0x5245,0x5248,UBOGON,UBOGON,0x524f,UBOGON,UBOGON,0x52c5,0x52ca,0x52c4,
122.6932 +    0x5327,0x5358,0x537d,UBOGON,0x53dd,0x53dc,0x53da,0x53d9,0x54b9,UBOGON,
122.6933 +    0x54d0,0x54b4,0x54ca,UBOGON,0x54a3,0x54da,0x54a4,UBOGON,0x54b2,0x549e,
122.6934 +    0x549f,0x54b5,UBOGON,UBOGON,0x54cd,UBOGON,0x54cc,UBOGON,0x5700,0x57ac,
122.6935 +    0x5791,0x578e,0x578d,0x5792,0x57a1,0x5790,0x57a6,0x57a8,UBOGON,0x579c,
122.6936 +    0x5796,0x57a7,UBOGON,UBOGON,UBOGON,UBOGON,0x58f5,UBOGON,0x5909,0x5908,
122.6937 +    UBOGON,0x5952,UBOGON,UBOGON
122.6938 +  },
122.6939 +  {				/* ku 0c */
122.6940 +    0x59df,UBOGON,0x59eb,0x59ef,0x59f0,0x59d5,0x5a0d,0x5a04,0x59f9,0x5a02,
122.6941 +    0x59f8,0x59e2,0x59d9,0x59e7,0x5b6a,UBOGON,UBOGON,0x5bab,UBOGON,0x5c1b,
122.6942 +    0x5c2f,UBOGON,0x663c,UBOGON,UBOGON,UBOGON,0x5cd1,0x5cdc,0x5ce6,0x5ce1,
122.6943 +    0x5ccd,UBOGON,0x5ce2,0x5cdd,0x5ce5,0x5dfb,0x5dfa,0x5e1e,UBOGON,0x5ea1,
122.6944 +    UBOGON,UBOGON,0x5efc,0x5efb,0x5f2f,UBOGON,UBOGON,0x5f66,UBOGON,UBOGON,
122.6945 +    UBOGON,0x605c,UBOGON,0x604e,0x6051,UBOGON,UBOGON,0x6023,0x6031,0x607c,
122.6946 +    0x6052,UBOGON,0x6060,0x604a,0x6061,UBOGON,0x6218,UBOGON,UBOGON,UBOGON,
122.6947 +    UBOGON,UBOGON,UBOGON,UBOGON,0x631f,0x6317,0x62ea,0x6321,0x6304,0x6305,
122.6948 +    UBOGON,0x6531,0x6544,0x6540,UBOGON,0x6542,0x65be,UBOGON,0x6629,0x661b,
122.6949 +    UBOGON,0x6623,0x662c,0x661a
122.6950 +  },
122.6951 +  {				/* ku 0d */
122.6952 +    0x6630,0x663b,0x661e,0x6637,0x6638,UBOGON,0x670e,UBOGON,UBOGON,0x67e8,
122.6953 +    0x67d6,UBOGON,0x67c7,0x67bc,0x6852,0x67bf,0x67d5,0x67fe,0x8363,0x67fb,
122.6954 +    UBOGON,0x67b1,0x6801,0x6805,0x6800,0x67d7,UBOGON,0x6b2a,0x6b6b,UBOGON,
122.6955 +    UBOGON,UBOGON,UBOGON,0x6be1,UBOGON,UBOGON,0x6d23,0x6cff,0x6d14,0x6d05,
122.6956 +    0x6d13,0x6d06,0x6d21,UBOGON,0x6d15,0x6caf,0x6cf4,0x6d02,0x6d45,UBOGON,
122.6957 +    0x6d26,UBOGON,0x6d44,UBOGON,0x6d24,0x70a5,UBOGON,0x70a3,UBOGON,0x70a2,
122.6958 +    0x70bb,0x70a0,0x70aa,UBOGON,UBOGON,0x70a8,0x70b6,0x70b2,0x70a7,UBOGON,
122.6959 +    UBOGON,0x70b9,0x722e,UBOGON,0x723c,UBOGON,0x726d,UBOGON,UBOGON,0x72e7,
122.6960 +    0x72ed,UBOGON,0x72ec,0x72e5,0x72e2,UBOGON,0x73c4,0x73bd,0x73cf,0x73c9,
122.6961 +    0x73c1,0x73d0,UBOGON,0x73ce
122.6962 +  },
122.6963 +  {				/* ku 0e */
122.6964 +    0x74ed,0x74eb,UBOGON,0x74ef,0x7549,0x7550,0x7546,0x754a,UBOGON,0x754d,
122.6965 +    0x75a6,UBOGON,UBOGON,UBOGON,0x75a8,UBOGON,UBOGON,0x76c7,0x76ff,UBOGON,
122.6966 +    0x76fd,0x77e6,0x780a,UBOGON,0x7804,0x780b,0x7807,UBOGON,0x7815,0x7808,
122.6967 +    UBOGON,0x79d3,0x79d4,0x79d0,0x79d7,0x7a7c,UBOGON,UBOGON,0x7a7d,0x7a83,
122.6968 +    0x7a82,UBOGON,0x7ad4,0x7ad5,0x7ad3,0x7ad0,0x7ad2,0x7afe,0x7afc,0x7c77,
122.6969 +    0x7c7c,0x7c7b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.6970 +    0x7f8f,0x80d3,UBOGON,0x80cb,0x80d2,UBOGON,0x8109,0x80e2,0x80df,0x80c6,
122.6971 +    UBOGON,0x8224,0x82f7,0x82d8,0x82dd,UBOGON,UBOGON,0x82f8,0x82fc,UBOGON,
122.6972 +    UBOGON,0x82e9,UBOGON,0x82ee,UBOGON,0x82d0,0x830e,0x82e2,0x830b,0x82fd,
122.6973 +    0x5179,0x8676,UBOGON,0x8678
122.6974 +  },
122.6975 +  {				/* ku 0f */
122.6976 +    UBOGON,UBOGON,0x8675,0x867d,UBOGON,0x8842,0x8866,UBOGON,0x898c,0x8a05,
122.6977 +    UBOGON,0x8a06,UBOGON,0x8c9f,UBOGON,0x8ff1,0x8fe7,0x8fe9,0x8fef,0x90c2,
122.6978 +    0x90bc,UBOGON,0x90c6,0x90c0,UBOGON,UBOGON,0x90cd,0x90c9,UBOGON,0x90c4,
122.6979 +    UBOGON,0x9581,UBOGON,0x9cec,0x5032,0x4ff9,0x501d,0x4fff,0x5004,0x4ff0,
122.6980 +    0x5003,UBOGON,0x5002,0x4ffc,0x4ff2,0x5024,0x5008,0x5036,0x502e,UBOGON,
122.6981 +    0x5010,0x5038,0x5039,0x4ffd,0x5056,0x4ffb,0x51a3,0x51a6,0x51a1,UBOGON,
122.6982 +    UBOGON,0x51c7,0x51c9,0x5260,0x5264,0x5259,0x5265,0x5267,0x5257,0x5263,
122.6983 +    UBOGON,0x5253,UBOGON,0x52cf,UBOGON,0x52ce,0x52d0,0x52d1,0x52cc,UBOGON,
122.6984 +    UBOGON,UBOGON,0x550d,0x54f4,UBOGON,0x5513,0x54ef,0x54f5,0x54f9,0x5502,
122.6985 +    0x5500,UBOGON,UBOGON,0x5518
122.6986 +  },
122.6987 +  {				/* ku 10 */
122.6988 +    0x54f0,0x54f6,UBOGON,UBOGON,0x5519,UBOGON,0x5705,0x57c9,UBOGON,0x57b7,
122.6989 +    0x57cd,UBOGON,UBOGON,UBOGON,0x57be,0x57bb,UBOGON,0x57db,0x57c8,0x57c4,
122.6990 +    0x57c5,0x57d1,0x57ca,0x57c0,UBOGON,UBOGON,0x5a21,0x5a2a,UBOGON,0x5a1d,
122.6991 +    UBOGON,0x5a0b,UBOGON,UBOGON,UBOGON,UBOGON,0x5a22,UBOGON,UBOGON,0x5a24,
122.6992 +    UBOGON,0x5a14,0x5a31,UBOGON,0x5a2f,0x5a1a,0x5a12,UBOGON,UBOGON,0x5a26,
122.6993 +    UBOGON,UBOGON,0x5bbc,0x5bbb,0x5bb7,0x5c05,0x5c06,0x5c52,0x5c53,UBOGON,
122.6994 +    UBOGON,0x5cfa,0x5ceb,UBOGON,0x5cf3,0x5cf5,0x5ce9,0x5cef,UBOGON,0x5e2a,
122.6995 +    0x5e30,0x5e2e,0x5e2c,0x5e2f,0x5eaf,0x5ea9,UBOGON,0x5efd,0x5f32,0x5f8e,
122.6996 +    0x5f93,0x5f8f,0x604f,0x6099,UBOGON,0x607e,UBOGON,0x6074,0x604b,0x6073,
122.6997 +    0x6075,UBOGON,UBOGON,0x6056
122.6998 +  },
122.6999 +  {				/* ku 11 */
122.7000 +    0x60a9,0x608b,0x60a6,UBOGON,0x6093,0x60ae,0x609e,0x60a7,0x6245,UBOGON,
122.7001 +    UBOGON,0x632e,UBOGON,0x6352,0x6330,0x635b,UBOGON,0x6319,0x631b,UBOGON,
122.7002 +    0x6331,0x635d,0x6337,0x6335,0x6353,UBOGON,0x635c,0x633f,0x654b,UBOGON,
122.7003 +    UBOGON,0x658b,UBOGON,0x659a,0x6650,0x6646,0x664e,0x6640,UBOGON,0x664b,
122.7004 +    0x6648,UBOGON,0x6660,0x6644,0x664d,UBOGON,0x6837,0x6824,UBOGON,UBOGON,
122.7005 +    0x681b,0x6836,UBOGON,0x682c,0x6819,0x6856,0x6847,0x683e,0x681e,UBOGON,
122.7006 +    0x6815,0x6822,0x6827,0x6859,0x6858,0x6855,0x6830,0x6823,0x6b2e,0x6b2b,
122.7007 +    0x6b30,0x6b6c,UBOGON,0x6b8b,UBOGON,0x6be9,0x6bea,0x6be5,0x6d6b,UBOGON,
122.7008 +    UBOGON,0x6d73,0x6d57,UBOGON,UBOGON,0x6d5d,0x6d56,0x6d8f,0x6d5b,0x6d1c,
122.7009 +    0x6d9a,0x6d9b,0x6d99,UBOGON
122.7010 +  },
122.7011 +  {				/* ku 12 */
122.7012 +    0x6d81,0x6d71,UBOGON,UBOGON,0x6d72,0x6d5c,0x6d96,0x70c4,0x70db,0x70cc,
122.7013 +    0x70d0,0x70e3,0x70df,UBOGON,0x70d6,0x70ee,0x70d5,UBOGON,UBOGON,UBOGON,
122.7014 +    UBOGON,0x727a,UBOGON,0x72f5,0x7302,UBOGON,UBOGON,0x73e2,0x73ec,0x73d5,
122.7015 +    0x73f9,0x73df,0x73e6,UBOGON,UBOGON,UBOGON,UBOGON,0x73e4,0x73e1,0x74f3,
122.7016 +    UBOGON,UBOGON,UBOGON,UBOGON,0x7556,0x7555,0x7558,0x7557,0x755e,0x75c3,
122.7017 +    UBOGON,UBOGON,0x75b4,UBOGON,0x75b1,UBOGON,UBOGON,0x76cb,0x76cc,0x772a,
122.7018 +    UBOGON,0x7716,0x770f,UBOGON,UBOGON,0x773f,0x772b,0x770e,0x7724,UBOGON,
122.7019 +    0x7721,0x7718,0x77dd,UBOGON,UBOGON,0x7824,0x7836,UBOGON,0x7958,0x7959,
122.7020 +    UBOGON,0x7962,0x79da,0x79d9,UBOGON,0x79e1,0x79e5,0x79e8,0x79db,UBOGON,
122.7021 +    0x79e2,0x79f0,UBOGON,UBOGON
122.7022 +  },
122.7023 +  {				/* ku 13 */
122.7024 +    UBOGON,UBOGON,0x7ada,0x7add,UBOGON,0x7adb,0x7adc,UBOGON,UBOGON,0x7b0d,
122.7025 +    0x7b0b,0x7b14,0x7c8e,0x7c86,UBOGON,0x7c87,0x7c83,0x7c8b,UBOGON,UBOGON,
122.7026 +    UBOGON,UBOGON,0x7d24,UBOGON,UBOGON,UBOGON,0x7d25,0x7f62,0x7f93,0x7f99,
122.7027 +    0x7f97,UBOGON,UBOGON,0x7fc4,0x7fc6,0x800a,UBOGON,UBOGON,0x8040,0x803c,
122.7028 +    0x803b,0x80f6,0x80ff,0x80ee,0x8104,0x8103,0x8107,UBOGON,UBOGON,0x80f7,
122.7029 +    UBOGON,UBOGON,0x822d,UBOGON,0x8227,0x8229,0x831f,0x8357,UBOGON,UBOGON,
122.7030 +    UBOGON,UBOGON,0x8321,UBOGON,UBOGON,0x8318,0x8358,UBOGON,UBOGON,UBOGON,
122.7031 +    UBOGON,UBOGON,0x8684,0x869f,0x869b,0x8689,0x86a6,0x8692,0x868f,0x86a0,
122.7032 +    0x884f,0x8878,0x887a,0x886e,0x887b,0x8884,0x8873,UBOGON,UBOGON,0x8a0d,
122.7033 +    0x8a0b,0x8a19,UBOGON,UBOGON
122.7034 +  },
122.7035 +  {				/* ku 14 */
122.7036 +    UBOGON,UBOGON,UBOGON,UBOGON,0x8ff9,0x9009,0x9008,UBOGON,0x90de,0x9151,
122.7037 +    UBOGON,UBOGON,0x91db,0x91df,0x91de,0x91d6,0x91e0,0x9585,0x9660,0x9659,
122.7038 +    UBOGON,0x9656,UBOGON,UBOGON,0x96bd,UBOGON,UBOGON,0x5042,0x5059,UBOGON,
122.7039 +    0x5044,0x5066,0x5052,0x5054,0x5071,0x5050,0x507b,0x507c,0x5058,UBOGON,
122.7040 +    UBOGON,0x5079,0x506c,0x5078,0x51a8,0x51d1,0x51cf,0x5268,0x5276,0x52d4,
122.7041 +    UBOGON,0x53a0,0x53c4,UBOGON,0x5558,0x554c,0x5568,UBOGON,0x5549,UBOGON,
122.7042 +    UBOGON,0x555d,0x5529,UBOGON,0x5554,0x5553,UBOGON,0x555a,UBOGON,0x553a,
122.7043 +    0x553f,0x552b,0x57ea,UBOGON,0x57ef,UBOGON,UBOGON,0x57dd,0x57fe,UBOGON,
122.7044 +    0x57de,0x57e6,UBOGON,0x57e8,0x57ff,0x5803,0x58f7,0x68a6,0x591f,UBOGON,
122.7045 +    0x595b,0x595d,0x595e,UBOGON
122.7046 +  },
122.7047 +  {				/* ku 15 */
122.7048 +    UBOGON,0x5a2b,UBOGON,0x5a3b,UBOGON,UBOGON,0x5a61,0x5a3a,0x5a6e,0x5a4b,
122.7049 +    0x5a6b,UBOGON,UBOGON,0x5a45,0x5a4e,0x5a68,0x5a3d,0x5a71,0x5a3f,0x5a6f,
122.7050 +    0x5a75,UBOGON,0x5a73,0x5a2c,0x5a59,0x5a54,0x5a4f,0x5a63,UBOGON,UBOGON,
122.7051 +    0x5bc8,UBOGON,0x5bc3,UBOGON,0x5c5b,0x5c61,UBOGON,0x5d21,0x5d0a,0x5d09,
122.7052 +    UBOGON,0x5d2c,0x5d08,UBOGON,UBOGON,0x5d2a,0x5d15,UBOGON,0x5d10,0x5d13,
122.7053 +    UBOGON,0x5d2f,0x5d18,UBOGON,0x5de3,0x5e39,0x5e35,0x5e3a,0x5e32,UBOGON,
122.7054 +    UBOGON,UBOGON,UBOGON,0x5ebb,0x5eba,0x5f34,0x5f39,UBOGON,UBOGON,UBOGON,
122.7055 +    UBOGON,0x6098,UBOGON,0x60d0,UBOGON,UBOGON,UBOGON,0x60d7,0x60aa,UBOGON,
122.7056 +    0x60a1,0x60a4,UBOGON,0x60ee,UBOGON,0x60e7,UBOGON,UBOGON,0x60de,UBOGON,
122.7057 +    UBOGON,0x637e,0x638b,UBOGON
122.7058 +  },
122.7059 +  {				/* ku 16 */
122.7060 +    UBOGON,0x6379,0x6386,0x6393,UBOGON,0x6373,0x636a,UBOGON,0x636c,UBOGON,
122.7061 +    0x637f,UBOGON,0x63b2,0x63ba,UBOGON,UBOGON,0x6366,0x6374,UBOGON,0x655a,
122.7062 +    UBOGON,0x654e,0x654d,0x658d,0x658e,0x65ad,UBOGON,0x65c7,0x65ca,UBOGON,
122.7063 +    0x65c9,UBOGON,0x65e3,0x6657,UBOGON,0x6663,0x6667,0x671a,0x6719,0x6716,
122.7064 +    UBOGON,UBOGON,0x689e,0x68b6,0x6898,0x6873,UBOGON,0x689a,0x688e,0x68b7,
122.7065 +    0x68db,0x68a5,0x686c,0x68c1,0x6884,UBOGON,UBOGON,0x6895,0x687a,0x6899,
122.7066 +    UBOGON,0x68b8,0x68b9,0x6870,UBOGON,0x6b35,UBOGON,0x6b90,0x6bbb,0x6bed,
122.7067 +    UBOGON,UBOGON,UBOGON,0x6dc1,0x6dc3,0x6dce,UBOGON,UBOGON,0x6dad,0x6e04,
122.7068 +    UBOGON,0x6db9,UBOGON,0x6de7,UBOGON,0x6e08,0x6e06,UBOGON,0x6e0a,0x6db0,
122.7069 +    UBOGON,0x6df8,0x6e0c,UBOGON
122.7070 +  },
122.7071 +  {				/* ku 17 */
122.7072 +    0x6db1,UBOGON,0x6e02,0x6e07,0x6e09,0x6e01,0x6e17,0x6dff,0x6e12,UBOGON,
122.7073 +    UBOGON,0x7103,0x7107,0x7101,0x70f5,0x70f1,0x7108,0x70f2,0x710f,UBOGON,
122.7074 +    0x70fe,UBOGON,UBOGON,UBOGON,0x731a,0x7310,0x730e,0x7402,0x73f3,UBOGON,
122.7075 +    UBOGON,0x73fb,UBOGON,UBOGON,UBOGON,0x751b,0x7523,0x7561,0x7568,UBOGON,
122.7076 +    0x7567,0x75d3,UBOGON,UBOGON,0x7690,UBOGON,UBOGON,0x76d5,0x76d7,0x76d6,
122.7077 +    0x7730,UBOGON,0x7726,UBOGON,0x7740,UBOGON,0x771e,UBOGON,UBOGON,UBOGON,
122.7078 +    0x7847,UBOGON,0x784b,0x7851,0x784f,0x7842,0x7846,UBOGON,0x796e,0x796c,
122.7079 +    0x79f2,UBOGON,0x79f1,0x79f5,0x79f3,0x79f9,UBOGON,UBOGON,UBOGON,0x7a9a,
122.7080 +    0x7a93,0x7a91,0x7ae1,UBOGON,UBOGON,0x7b21,0x7b1c,0x7b16,0x7b17,0x7b36,
122.7081 +    0x7b1f,UBOGON,0x7c93,0x7c99
122.7082 +  },
122.7083 +  {				/* ku 18 */
122.7084 +    0x7c9a,0x7c9c,UBOGON,0x7d49,UBOGON,0x7d34,0x7d37,UBOGON,0x7d2d,UBOGON,
122.7085 +    0x7d4c,UBOGON,UBOGON,0x7d48,UBOGON,UBOGON,0x7f3b,UBOGON,UBOGON,UBOGON,
122.7086 +    UBOGON,0x8008,0x801a,UBOGON,0x801d,UBOGON,0x8049,0x8045,0x8044,0x7c9b,
122.7087 +    UBOGON,UBOGON,0x812a,0x812e,UBOGON,UBOGON,0x8131,UBOGON,0x811a,0x8134,
122.7088 +    0x8117,UBOGON,UBOGON,UBOGON,0x831d,0x8371,0x8384,0x8380,0x8372,0x83a1,
122.7089 +    UBOGON,0x8379,0x8391,UBOGON,0x839f,0x83ad,UBOGON,UBOGON,0x8323,UBOGON,
122.7090 +    0x8385,0x839c,0x83b7,0x8658,0x865a,UBOGON,0x8657,0x86b2,UBOGON,0x86ae,
122.7091 +    UBOGON,UBOGON,UBOGON,0x8845,0x889c,0x8894,0x88a3,0x888f,0x88a5,0x88a9,
122.7092 +    0x88a6,0x888a,0x88a0,0x8890,0x8992,0x8991,0x8994,UBOGON,0x8a26,0x8a32,
122.7093 +    0x8a28,UBOGON,UBOGON,0x8a1c
122.7094 +  },
122.7095 +  {				/* ku 19 */
122.7096 +    UBOGON,0x8a2b,0x8a20,UBOGON,0x8a29,UBOGON,UBOGON,UBOGON,0x8a21,0x8c3a,
122.7097 +    UBOGON,0x8c5b,0x8c58,0x8c7c,UBOGON,0x8ca6,0x8cae,0x8cad,0x8d65,UBOGON,
122.7098 +    0x8d7e,UBOGON,0x8d7c,0x8d7f,0x8d7a,0x8dbd,UBOGON,UBOGON,0x8dc0,0x8dbb,
122.7099 +    0x8ead,0x8eaf,0x8ed6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8ed9,UBOGON,
122.7100 +    UBOGON,0x9012,0x900e,0x9025,UBOGON,0x9013,0x90ee,UBOGON,0x90ab,0x90f7,
122.7101 +    UBOGON,0x9159,0x9154,0x91f2,0x91f0,0x91e5,0x91f6,UBOGON,UBOGON,0x9587,
122.7102 +    UBOGON,0x965a,UBOGON,UBOGON,0x966e,UBOGON,UBOGON,UBOGON,0x9679,UBOGON,
122.7103 +    0x98e1,0x98e6,UBOGON,0x9ec4,0x9ed2,0x4e80,UBOGON,0x4e81,0x508f,0x5097,
122.7104 +    0x5088,0x5089,UBOGON,UBOGON,0x5081,0x5160,UBOGON,UBOGON,0x5e42,0x51d3,
122.7105 +    UBOGON,UBOGON,0x51d2,0x51d6
122.7106 +  },
122.7107 +  {				/* ku 1a */
122.7108 +    0x5273,UBOGON,0x5270,UBOGON,UBOGON,UBOGON,0x53a8,0x53a6,0x53c5,0x5597,
122.7109 +    0x55de,UBOGON,UBOGON,0x5596,0x55b4,UBOGON,0x5585,UBOGON,0x559b,0x55a0,
122.7110 +    UBOGON,0x5559,UBOGON,0x5586,UBOGON,UBOGON,0x55af,0x557a,UBOGON,UBOGON,
122.7111 +    UBOGON,0x559e,UBOGON,0x55a9,0x570f,0x570e,0x581a,UBOGON,0x581f,UBOGON,
122.7112 +    0x583c,0x5818,0x583e,0x5826,UBOGON,0x583a,UBOGON,0x5822,UBOGON,0x58fb,
122.7113 +    0x5963,0x5964,UBOGON,0x5aa8,0x5aa3,0x5a82,0x5a88,0x5aa1,0x5a85,0x5a98,
122.7114 +    UBOGON,0x5a99,UBOGON,0x5a89,0x5a81,0x5a96,0x5a80,UBOGON,UBOGON,0x5a91,
122.7115 +    UBOGON,UBOGON,UBOGON,UBOGON,0x5acf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7116 +    UBOGON,0x5a87,0x5aa0,UBOGON,0x5a79,UBOGON,0x5a86,0x5aab,0x5aaa,0x5aa4,
122.7117 +    0x5a8d,0x5a7e,UBOGON,0x5bd5
122.7118 +  },
122.7119 +  {				/* ku 1b */
122.7120 +    UBOGON,UBOGON,UBOGON,0x5c1e,0x5c5f,0x5c5e,0x5d44,0x5d3e,UBOGON,0x5d48,
122.7121 +    0x5d1c,UBOGON,0x5d5b,0x5d4d,UBOGON,UBOGON,0x5d57,UBOGON,0x5d53,0x5d4f,
122.7122 +    UBOGON,0x5d3b,0x5d46,UBOGON,UBOGON,0x5e46,0x5e47,UBOGON,0x5e48,0x5ec0,
122.7123 +    0x5ebd,0x5ebf,UBOGON,0x5f11,UBOGON,0x5f3e,0x5f3b,UBOGON,0x5f3a,UBOGON,
122.7124 +    UBOGON,UBOGON,0x5fa7,UBOGON,0x60ea,UBOGON,0x6107,0x6122,0x610c,UBOGON,
122.7125 +    UBOGON,0x60b3,0x60d6,0x60d2,UBOGON,0x60e3,0x60e5,0x60e9,UBOGON,UBOGON,
122.7126 +    0x6111,0x60fd,UBOGON,UBOGON,0x611e,0x6120,0x6121,0x621e,UBOGON,0x63e2,
122.7127 +    0x63de,0x63e6,UBOGON,UBOGON,UBOGON,UBOGON,0x63f8,UBOGON,0x63fe,0x63c1,
122.7128 +    0x63bf,0x63f7,0x63d1,0x655f,0x6560,0x6561,UBOGON,UBOGON,0x65d1,UBOGON,
122.7129 +    UBOGON,0x667d,0x666b,0x667f
122.7130 +  },
122.7131 +  {				/* ku 1c */
122.7132 +    UBOGON,UBOGON,0x6673,0x6681,0x666d,0x6669,UBOGON,UBOGON,0x671e,0x68ed,
122.7133 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6903,UBOGON,0x68fe,0x68e5,0x691e,0x6902,
122.7134 +    UBOGON,UBOGON,0x6909,0x68ca,0x6900,UBOGON,0x6901,0x6918,0x68e2,0x68cf,
122.7135 +    UBOGON,0x692e,0x68c5,0x68ff,UBOGON,0x691c,0x68c3,UBOGON,0x6b6f,UBOGON,
122.7136 +    0x6b6e,UBOGON,0x6bbe,UBOGON,0x6bf4,0x6c2d,UBOGON,0x6db6,0x6e75,0x6e1e,
122.7137 +    UBOGON,0x6e18,UBOGON,0x6e48,UBOGON,0x6e4f,UBOGON,0x6e42,0x6e6a,0x6e70,
122.7138 +    0x6dfe,UBOGON,UBOGON,0x6e6d,UBOGON,0x6e7b,0x6e7e,0x6e59,UBOGON,0x6e57,
122.7139 +    UBOGON,0x6e80,0x6e50,UBOGON,0x6e29,0x6e76,0x6e2a,0x6e4c,0x712a,UBOGON,
122.7140 +    0x7135,0x712c,0x7137,0x711d,UBOGON,UBOGON,0x7138,UBOGON,0x7134,0x712b,
122.7141 +    0x7133,0x7127,0x7124,UBOGON
122.7142 +  },
122.7143 +  {				/* ku 1d */
122.7144 +    0x712d,0x7232,0x7283,0x7282,0x7287,0x7306,0x7324,0x7338,0x732a,0x732c,
122.7145 +    0x732b,UBOGON,0x732f,0x7328,0x7417,UBOGON,UBOGON,0x7419,0x7438,UBOGON,
122.7146 +    0x741f,0x7414,0x743c,0x73f7,0x741c,0x7415,0x7418,0x7439,0x74f9,0x7524,
122.7147 +    UBOGON,UBOGON,UBOGON,0x756e,0x756d,0x7571,0x758e,UBOGON,0x75e5,UBOGON,
122.7148 +    UBOGON,UBOGON,UBOGON,0x7694,0x76b3,UBOGON,0x76d9,UBOGON,0x7748,0x7749,
122.7149 +    0x7743,UBOGON,UBOGON,0x7742,0x77df,UBOGON,0x7863,0x7876,UBOGON,0x785f,
122.7150 +    0x7866,0x7966,0x7971,UBOGON,UBOGON,0x7976,0x7984,0x7975,0x79ff,0x7a07,
122.7151 +    UBOGON,0x7a0e,0x7a09,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ae7,
122.7152 +    0x7ae2,0x7b55,UBOGON,UBOGON,0x7b43,0x7b57,0x7b6c,0x7b42,0x7b53,UBOGON,
122.7153 +    0x7b41,UBOGON,UBOGON,0x7ca7
122.7154 +  },
122.7155 +  {				/* ku 1e */
122.7156 +    0x7ca0,0x7ca6,0x7ca4,0x7d74,UBOGON,0x7d59,UBOGON,0x7d60,0x7d57,0x7d6c,
122.7157 +    0x7d7e,0x7d64,UBOGON,0x7d5a,0x7d5d,UBOGON,UBOGON,UBOGON,0x7d76,0x7d4d,
122.7158 +    0x7d75,UBOGON,0x7fd3,0x7fd6,UBOGON,UBOGON,0x8060,0x804e,0x8145,0x813b,
122.7159 +    UBOGON,0x8148,0x8142,0x8149,0x8140,0x8114,0x8141,UBOGON,0x81ef,0x81f6,
122.7160 +    0x8203,UBOGON,0x83ed,UBOGON,0x83da,0x8418,0x83d2,0x8408,UBOGON,0x8400,
122.7161 +    UBOGON,UBOGON,UBOGON,0x8417,0x8346,0x8414,0x83d3,0x8405,0x841f,0x8402,
122.7162 +    0x8416,0x83cd,0x83e6,UBOGON,0x865d,0x86d5,0x86e1,UBOGON,UBOGON,UBOGON,
122.7163 +    UBOGON,0x86ee,0x8847,0x8846,UBOGON,UBOGON,0x88bb,UBOGON,0x88bf,0x88b4,
122.7164 +    UBOGON,0x88b5,UBOGON,0x899a,0x8a43,UBOGON,UBOGON,0x8a5a,UBOGON,UBOGON,
122.7165 +    UBOGON,0x8a35,0x8a38,0x8a42
122.7166 +  },
122.7167 +  {				/* ku 1f */
122.7168 +    0x8a49,0x8a5d,0x8a4b,0x8a3d,UBOGON,UBOGON,UBOGON,UBOGON,0x8c60,0x8c5e,
122.7169 +    0x8c7f,0x8c7e,0x8c83,UBOGON,0x8cb1,0x8d87,UBOGON,UBOGON,0x8d88,0x8d83,
122.7170 +    UBOGON,UBOGON,0x8d86,0x8d8b,0x8d82,0x8dca,0x8dd2,UBOGON,UBOGON,0x8dd4,
122.7171 +    0x8dc9,0x8eb0,UBOGON,UBOGON,UBOGON,0x8ef2,0x8ee4,0x8ef3,0x8eea,UBOGON,
122.7172 +    0x8efd,UBOGON,0x8f9d,0x902b,0x902a,UBOGON,0x9028,0x9029,0x902c,UBOGON,
122.7173 +    UBOGON,0x903a,0x9030,0x9037,0x903b,UBOGON,0x910a,UBOGON,UBOGON,UBOGON,
122.7174 +    0x91fe,0x9220,UBOGON,0x920b,UBOGON,0x9218,0x9222,UBOGON,0x921b,0x9208,
122.7175 +    UBOGON,0x920e,0x9213,UBOGON,UBOGON,0x9595,UBOGON,UBOGON,UBOGON,0x968c,
122.7176 +    0x967b,0x967f,0x9681,UBOGON,0x9682,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7177 +    0x96ee,0x96ed,UBOGON,0x96ec
122.7178 +  },
122.7179 +  {				/* ku 20 */
122.7180 +    0x975f,0x976f,UBOGON,0x976d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7181 +    0x98f0,UBOGON,UBOGON,UBOGON,0x9aa9,UBOGON,UBOGON,0x9ae0,0x4eb7,UBOGON,
122.7182 +    UBOGON,0x50cc,0x50bc,UBOGON,0x50aa,0x50b9,UBOGON,0x50ab,0x50c3,0x50cd,
122.7183 +    0x517e,0x527e,0x5279,UBOGON,UBOGON,0x52e1,0x52e0,0x52e7,0x5380,0x53ab,
122.7184 +    0x53aa,0x53a9,0x53e0,0x55ea,UBOGON,0x55d7,UBOGON,UBOGON,0x55c1,0x5715,
122.7185 +    UBOGON,0x586c,UBOGON,0x585c,0x5850,0x5861,0x586a,0x5869,0x5856,0x5860,
122.7186 +    0x5866,0x585f,0x5923,0x5966,0x5968,UBOGON,UBOGON,0x5ace,UBOGON,0x5ac5,
122.7187 +    0x5ac3,UBOGON,UBOGON,0x5ad0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7188 +    0x5b74,0x5b76,0x5bdc,0x5bd7,0x5bda,0x5bdb,UBOGON,0x5c20,0x5d6d,0x5d66,
122.7189 +    UBOGON,0x5d64,0x5d6e,UBOGON
122.7190 +  },
122.7191 +  {				/* ku 21 */
122.7192 +    0x5d60,0x5f42,0x5f5a,0x5f6e,UBOGON,UBOGON,0x6130,0x613a,0x612a,0x6143,
122.7193 +    0x6119,0x6131,UBOGON,0x613d,UBOGON,UBOGON,UBOGON,0x6408,0x6432,0x6438,
122.7194 +    UBOGON,0x6431,UBOGON,0x6419,UBOGON,0x6411,UBOGON,UBOGON,0x6429,0x641d,
122.7195 +    UBOGON,UBOGON,UBOGON,0x643c,UBOGON,0x6446,0x6447,UBOGON,UBOGON,0x643a,
122.7196 +    0x6407,UBOGON,0x656b,UBOGON,0x6570,0x656d,UBOGON,0x65e4,0x6693,UBOGON,
122.7197 +    UBOGON,UBOGON,UBOGON,0x668f,UBOGON,UBOGON,0x6692,UBOGON,0x668e,UBOGON,
122.7198 +    0x6946,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6931,UBOGON,
122.7199 +    UBOGON,0x693e,UBOGON,0x697c,0x6943,UBOGON,0x6973,UBOGON,0x6955,UBOGON,
122.7200 +    UBOGON,0x6985,0x694d,0x6950,0x6947,0x6967,0x6936,0x6964,0x6961,UBOGON,
122.7201 +    0x697d,0x6b44,0x6b40,0x6b71
122.7202 +  },
122.7203 +  {				/* ku 22 */
122.7204 +    0x6b73,0x6b9c,UBOGON,UBOGON,UBOGON,0x6bc1,UBOGON,0x6bfa,0x6c31,0x6c32,
122.7205 +    UBOGON,UBOGON,0x6eb8,0x6ea8,UBOGON,0x6e91,0x6ebb,UBOGON,0x6e9a,UBOGON,
122.7206 +    UBOGON,0x6ea9,UBOGON,UBOGON,0x6eb5,0x6e6c,0x6ee8,UBOGON,0x6edd,0x6eda,
122.7207 +    0x6ee6,0x6eac,UBOGON,UBOGON,UBOGON,0x6ed9,0x6ee3,0x6ee9,0x6edb,UBOGON,
122.7208 +    0x716f,UBOGON,UBOGON,0x7148,UBOGON,0x714a,0x716b,UBOGON,0x714f,0x7157,
122.7209 +    0x7174,UBOGON,UBOGON,UBOGON,0x7145,0x7151,0x716d,UBOGON,0x7251,0x7250,
122.7210 +    0x724e,UBOGON,0x7341,UBOGON,0x732e,0x7346,UBOGON,0x7427,UBOGON,0x7448,
122.7211 +    0x7453,0x743d,UBOGON,0x745d,0x7456,UBOGON,0x741e,0x7447,0x7443,0x7458,
122.7212 +    0x7449,UBOGON,0x744c,0x7445,0x743e,UBOGON,0x7501,0x751e,UBOGON,UBOGON,
122.7213 +    0x757a,0x75ee,0x7602,0x7697
122.7214 +  },
122.7215 +  {				/* ku 23 */
122.7216 +    0x7698,UBOGON,UBOGON,UBOGON,0x775d,0x7764,0x7753,0x7758,0x7882,0x7890,
122.7217 +    0x788a,UBOGON,0x787a,0x787d,UBOGON,0x788b,0x7878,UBOGON,UBOGON,0x788d,
122.7218 +    0x7888,0x7892,0x7881,0x797e,0x7983,UBOGON,UBOGON,UBOGON,0x7980,UBOGON,
122.7219 +    UBOGON,UBOGON,0x7a0f,UBOGON,UBOGON,0x7a1d,UBOGON,0x7aa1,0x7aa4,UBOGON,
122.7220 +    0x7ae9,0x7aea,UBOGON,0x7b62,0x7b6b,UBOGON,0x7b5e,UBOGON,0x7b79,UBOGON,
122.7221 +    UBOGON,0x7b6f,0x7b68,UBOGON,UBOGON,0x7cae,UBOGON,UBOGON,UBOGON,0x7cb0,
122.7222 +    UBOGON,0x7d90,UBOGON,0x7d8a,UBOGON,0x7d8b,0x7d99,0x7d95,UBOGON,0x7d87,
122.7223 +    0x7d78,0x7d97,0x7d89,0x7d98,UBOGON,UBOGON,UBOGON,0x7fa3,UBOGON,UBOGON,
122.7224 +    UBOGON,0x7fdd,0x8057,UBOGON,0x8163,0x816a,0x816c,UBOGON,UBOGON,UBOGON,
122.7225 +    0x815d,0x8175,UBOGON,0x815f
122.7226 +  },
122.7227 +  {				/* ku 24 */
122.7228 +    UBOGON,0x817d,0x816d,UBOGON,UBOGON,0x8241,0x844f,0x8484,UBOGON,0x847f,
122.7229 +    UBOGON,0x8448,0x842a,0x847b,0x8472,0x8464,0x842e,0x845c,0x8453,UBOGON,
122.7230 +    0x8441,0x84c8,UBOGON,0x8462,0x8480,0x843e,0x8483,0x8471,UBOGON,0x844a,
122.7231 +    0x8455,0x8458,UBOGON,UBOGON,UBOGON,0x86fc,0x86fd,0x8715,UBOGON,0x8716,
122.7232 +    0x86ff,UBOGON,UBOGON,UBOGON,0x8858,0x88cf,0x88e0,UBOGON,UBOGON,UBOGON,
122.7233 +    UBOGON,0x89e7,0x8a6a,0x8a80,UBOGON,0x8a6f,0x8a65,UBOGON,0x8a78,0x8a7d,
122.7234 +    0x8a88,UBOGON,UBOGON,0x8a64,0x8a7e,UBOGON,0x8a67,0x8c63,0x8c88,UBOGON,
122.7235 +    0x8ccd,UBOGON,0x8cc9,UBOGON,0x8ded,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7236 +    UBOGON,UBOGON,0x8eb1,UBOGON,UBOGON,0x8f04,0x8f9e,0x8fa0,0x9043,0x9046,
122.7237 +    0x9048,0x9045,0x9040,0x904c
122.7238 +  },
122.7239 +  {				/* ku 25 */
122.7240 +    UBOGON,UBOGON,0x910c,0x9113,0x9115,UBOGON,0x916b,0x9167,0x925d,0x9255,
122.7241 +    0x9235,UBOGON,0x9259,0x922f,0x923c,0x928f,0x925c,0x926a,0x9262,0x925f,
122.7242 +    0x926b,0x926e,0x923b,0x9244,0x9241,0x959a,UBOGON,0x9599,UBOGON,UBOGON,
122.7243 +    UBOGON,0x968f,UBOGON,0x9696,UBOGON,UBOGON,UBOGON,0x96f4,0x96fc,UBOGON,
122.7244 +    0x9755,UBOGON,0x9779,UBOGON,UBOGON,UBOGON,0x97ee,0x97f5,UBOGON,0x980b,
122.7245 +    UBOGON,0x98f3,UBOGON,UBOGON,0x98f7,0x98ff,0x98f5,UBOGON,0x98ec,0x98f1,
122.7246 +    UBOGON,UBOGON,0x999a,UBOGON,0x9ae2,0x9b3d,0x9b5d,0x9ce8,UBOGON,0x9ceb,
122.7247 +    0x9cef,0x9cee,0x9e81,0x9f14,0x50d0,0x50d9,0x50dc,0x50d8,UBOGON,0x50e1,
122.7248 +    0x50eb,UBOGON,UBOGON,0x50f4,0x50e2,0x50de,UBOGON,UBOGON,UBOGON,0x51f4,
122.7249 +    UBOGON,UBOGON,UBOGON,0x52ed
122.7250 +  },
122.7251 +  {				/* ku 26 */
122.7252 +    0x52ea,UBOGON,0x5332,UBOGON,0x53ae,0x53b0,UBOGON,0x55fb,0x5603,0x560b,
122.7253 +    UBOGON,0x5607,UBOGON,0x55f8,UBOGON,0x5628,0x561e,UBOGON,0x5618,0x5611,
122.7254 +    0x5651,0x5605,0x5717,0x5892,UBOGON,0x588c,UBOGON,0x5878,0x5884,0x5873,
122.7255 +    0x58ad,0x5897,0x5895,0x5877,0x5872,0x5896,0x588d,0x5910,UBOGON,0x596c,
122.7256 +    UBOGON,0x5ae7,UBOGON,0x5ae4,UBOGON,UBOGON,0x5aef,0x5626,UBOGON,UBOGON,
122.7257 +    0x5af0,0x5d7b,UBOGON,0x5d83,UBOGON,UBOGON,0x5d8b,0x5d8c,UBOGON,0x5d78,
122.7258 +    0x5e52,UBOGON,UBOGON,0x5ed0,0x5ecf,UBOGON,0x5fb3,0x5fb4,UBOGON,UBOGON,
122.7259 +    UBOGON,0x617b,UBOGON,0x616f,0x6181,0x613c,0x6142,0x6138,0x6133,UBOGON,
122.7260 +    0x6160,0x6169,0x617d,0x6186,0x622c,0x6228,UBOGON,0x644c,UBOGON,0x6457,
122.7261 +    0x647c,UBOGON,UBOGON,0x6455
122.7262 +  },
122.7263 +  {				/* ku 27 */
122.7264 +    0x6462,0x6471,0x646a,0x6456,0x643b,0x6481,UBOGON,0x644f,0x647e,0x6464,
122.7265 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6571,UBOGON,UBOGON,0x66a5,0x669a,
122.7266 +    0x669c,UBOGON,0x66a6,UBOGON,0x66a4,0x698f,0x69c5,0x69c8,0x6992,0x69b2,
122.7267 +    UBOGON,UBOGON,UBOGON,0x69e3,0x69c0,0x69d6,0x69d1,0x699f,0x69a2,0x69d2,
122.7268 +    UBOGON,UBOGON,UBOGON,0x69e1,0x69d5,0x699d,UBOGON,UBOGON,0x6998,UBOGON,
122.7269 +    0x6b74,0x6ba1,UBOGON,0x6ef0,0x6ef3,UBOGON,UBOGON,0x6f1b,0x6f0c,0x6f1d,
122.7270 +    0x6f34,0x6f28,0x6f17,UBOGON,0x6f44,0x6f42,0x6f04,0x6f11,0x6efa,0x6f4a,
122.7271 +    0x7191,0x718e,UBOGON,0x718b,0x718d,0x717f,0x718c,0x717e,0x717c,0x7183,
122.7272 +    UBOGON,0x7188,UBOGON,UBOGON,0x7294,UBOGON,0x7355,0x7353,0x734f,0x7354,
122.7273 +    0x746c,0x7465,0x7466,0x7461
122.7274 +  },
122.7275 +  {				/* ku 28 */
122.7276 +    0x746b,0x7468,0x7476,UBOGON,0x7460,UBOGON,0x7474,0x7506,0x760e,UBOGON,
122.7277 +    0x7607,UBOGON,UBOGON,0x76b9,UBOGON,0x76b7,0x76e2,UBOGON,0x7774,0x7777,
122.7278 +    0x7776,0x7775,UBOGON,0x7778,0x7771,UBOGON,0x777a,0x715b,0x777b,0x78a6,
122.7279 +    0x78ae,0x78b8,UBOGON,UBOGON,UBOGON,0x78b1,0x78af,UBOGON,0x7989,0x7987,
122.7280 +    UBOGON,UBOGON,0x7a29,UBOGON,0x7a2a,UBOGON,0x7a2d,0x7a2c,UBOGON,0x7a32,
122.7281 +    UBOGON,0x7aec,0x7af0,0x7b81,0x7b9e,0x7b83,UBOGON,0x7b92,UBOGON,0x7ba3,
122.7282 +    0x7b9f,0x7b93,UBOGON,0x7b86,0x7cb8,0x7cb7,UBOGON,UBOGON,UBOGON,UBOGON,
122.7283 +    UBOGON,0x7dc8,0x7db6,UBOGON,0x7dd1,UBOGON,0x7da8,0x7dab,UBOGON,0x7db3,
122.7284 +    0x7dcd,UBOGON,0x7dcf,0x7da4,UBOGON,UBOGON,0x7f41,0x7f6f,0x7f71,UBOGON,
122.7285 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7286 +  },
122.7287 +  {				/* ku 29 */
122.7288 +    UBOGON,0x8023,0x805b,UBOGON,0x8061,0x805f,0x8181,UBOGON,UBOGON,0x8184,
122.7289 +    0x8213,UBOGON,0x824a,0x824c,UBOGON,UBOGON,UBOGON,0x84bd,0x8495,UBOGON,
122.7290 +    0x8492,0x84c3,UBOGON,0x8496,0x84a5,0x84b5,0x84b3,0x84a3,0x84e4,0x84d8,
122.7291 +    0x84d5,UBOGON,0x84b7,0x84ad,0x84da,0x8493,0x8736,UBOGON,UBOGON,UBOGON,
122.7292 +    0x873d,0x872b,0x8747,0x8739,UBOGON,0x8745,0x871d,UBOGON,0x88ff,0x88ea,
122.7293 +    UBOGON,0x88f5,UBOGON,0x8900,0x88ed,0x8903,0x88e9,UBOGON,UBOGON,0x89ea,
122.7294 +    UBOGON,0x8a9b,0x8a8e,0x8aa2,UBOGON,0x8a9c,0x8a94,0x8a90,0x8aa9,0x8aac,
122.7295 +    UBOGON,0x8a9f,UBOGON,UBOGON,0x8a9d,UBOGON,0x8c67,UBOGON,UBOGON,0x8cd0,
122.7296 +    0x8cd6,0x8cd4,0x8d98,0x8d9a,0x8d97,UBOGON,UBOGON,UBOGON,0x8e0b,0x8e08,
122.7297 +    0x8e01,0x8eb4,0x8eb3,UBOGON
122.7298 +  },
122.7299 +  {				/* ku 2a */
122.7300 +    0x8fa1,0x8fa2,UBOGON,0x905a,UBOGON,0x9061,0x905f,UBOGON,UBOGON,0x9125,
122.7301 +    0x917b,0x9176,0x917c,UBOGON,0x9289,0x92f6,0x92b1,0x92ad,0x9292,0x9281,
122.7302 +    0x9284,UBOGON,0x92ae,0x9290,0x929e,UBOGON,UBOGON,UBOGON,0x95a2,0x95a7,
122.7303 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96a0,0x969d,0x969f,0x96d0,UBOGON,
122.7304 +    0x96d1,UBOGON,UBOGON,0x9759,UBOGON,0x9764,UBOGON,UBOGON,UBOGON,0x9819,
122.7305 +    UBOGON,0x9814,0x9815,0x981a,UBOGON,UBOGON,UBOGON,UBOGON,0x9906,UBOGON,
122.7306 +    0x98f8,0x9901,UBOGON,0x99be,0x99bc,0x99b7,0x99b6,0x99c0,UBOGON,0x99b8,
122.7307 +    UBOGON,UBOGON,UBOGON,0x99c4,UBOGON,0x99bf,UBOGON,0x9ada,0x9ae4,0x9ae9,
122.7308 +    0x9ae8,0x9aea,0x9ae5,UBOGON,0x9b26,UBOGON,UBOGON,0x9b40,UBOGON,UBOGON,
122.7309 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7310 +  },
122.7311 +  {				/* ku 2b */
122.7312 +    UBOGON,0x9ebd,UBOGON,UBOGON,UBOGON,UBOGON,0x510e,UBOGON,0x50f7,UBOGON,
122.7313 +    0x50fc,0x510d,0x5101,0x51da,0x51d9,0x51db,0x5286,0x528e,0x52ee,0x5333,
122.7314 +    0x53b1,UBOGON,0x5647,0x562d,0x5654,UBOGON,0x564b,0x5652,0x5631,0x5644,
122.7315 +    0x5656,0x5650,0x562b,UBOGON,0x564d,0x5637,0x564f,0x58a2,0x58b7,UBOGON,
122.7316 +    0x58b2,UBOGON,0x58aa,0x58b5,0x58b0,UBOGON,0x58b4,0x58a4,0x58a7,UBOGON,
122.7317 +    0x5926,0x5afe,UBOGON,0x5b04,UBOGON,0x5afc,UBOGON,0x5b06,0x5b0a,0x5afa,
122.7318 +    0x5b0d,0x5b00,0x5b0e,UBOGON,UBOGON,UBOGON,0x5d91,UBOGON,0x5d8f,0x5d90,
122.7319 +    0x5d98,0x5da4,0x5d9b,0x5da3,0x5d96,0x5de4,0x5e5a,UBOGON,UBOGON,0x5e5e,
122.7320 +    UBOGON,0x5fb8,0x6157,0x615c,0x61a6,0x6195,0x6188,UBOGON,0x61a3,0x618f,
122.7321 +    UBOGON,0x6164,UBOGON,0x6159
122.7322 +  },
122.7323 +  {				/* ku 2c */
122.7324 +    0x6178,UBOGON,0x6185,0x6187,0x619e,UBOGON,UBOGON,0x6198,0x619c,UBOGON,
122.7325 +    UBOGON,0x622f,0x6480,0x649b,0x648e,0x648d,0x6494,0x64c6,UBOGON,0x64a8,
122.7326 +    0x6483,UBOGON,0x64b9,0x6486,0x64b4,0x64af,0x6491,UBOGON,0x64aa,0x64a1,
122.7327 +    0x64a7,0x66b6,0x66b3,UBOGON,0x66bc,0x66ac,UBOGON,0x66ad,0x6a0e,UBOGON,
122.7328 +    0x6a1c,0x6a1a,UBOGON,UBOGON,0x6a0b,UBOGON,0x69ef,0x6a0c,0x69f0,0x6a22,
122.7329 +    UBOGON,0x69d8,UBOGON,0x6a12,0x69fa,UBOGON,0x6a2a,UBOGON,0x6a10,UBOGON,
122.7330 +    UBOGON,0x6a29,0x69f9,0x69ea,0x6a2c,0x6a24,UBOGON,0x69e9,0x6b52,0x6b4f,
122.7331 +    0x6b53,UBOGON,UBOGON,0x6f10,0x6f65,0x6f75,UBOGON,UBOGON,UBOGON,UBOGON,
122.7332 +    0x6fd0,UBOGON,0x6f5c,0x6f3d,0x6f71,UBOGON,0x6f91,0x6f0b,0x6f79,0x6f81,
122.7333 +    0x6f8f,UBOGON,0x6f59,0x6f74
122.7334 +  },
122.7335 +  {				/* ku 2d */
122.7336 +    UBOGON,0x71ae,UBOGON,0x71a3,0x71ad,UBOGON,UBOGON,0x71ab,0x71a6,0x71a2,
122.7337 +    UBOGON,0x52f2,0x7257,0x7255,0x7299,0x734b,0x747a,UBOGON,UBOGON,UBOGON,
122.7338 +    0x748c,0x7484,UBOGON,UBOGON,0x7482,0x7493,0x747b,UBOGON,0x7509,UBOGON,
122.7339 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x778a,UBOGON,0x7790,UBOGON,0x78c6,
122.7340 +    0x78d3,0x78c0,0x78d2,0x78c7,0x78c2,UBOGON,0x799f,0x799d,0x799e,UBOGON,
122.7341 +    0x7a41,UBOGON,0x7a38,0x7a3a,0x7a42,UBOGON,UBOGON,0x7a3e,0x7ab0,0x7bae,
122.7342 +    0x7bb3,UBOGON,UBOGON,0x7bbf,UBOGON,UBOGON,0x7bcd,UBOGON,0x7bb2,UBOGON,
122.7343 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7cc4,0x7ccd,0x7cc2,0x7cc6,
122.7344 +    0x7cc3,0x7cc9,0x7cc7,UBOGON,0x7df8,UBOGON,0x7ded,0x7de2,UBOGON,UBOGON,
122.7345 +    UBOGON,0x7ddc,0x7e02,0x7e01
122.7346 +  },
122.7347 +  {				/* ku 2e */
122.7348 +    UBOGON,0x7dd6,UBOGON,0x7de4,0x7dfe,UBOGON,0x7e00,0x7dfc,0x7dfd,UBOGON,
122.7349 +    0x7df5,0x7dff,UBOGON,0x7deb,0x7de5,0x7f78,0x7fae,0x7fe7,UBOGON,0x8065,
122.7350 +    0x806a,0x8066,0x8068,0x806b,0x8194,0x81a1,0x8192,0x8196,0x8193,UBOGON,
122.7351 +    UBOGON,0x8501,UBOGON,0x84f8,UBOGON,0x84f5,UBOGON,0x8504,UBOGON,UBOGON,
122.7352 +    UBOGON,UBOGON,0x851b,0x8503,0x8533,0x8534,0x84ed,UBOGON,UBOGON,0x8535,
122.7353 +    UBOGON,0x8505,UBOGON,UBOGON,UBOGON,UBOGON,0x877d,UBOGON,UBOGON,UBOGON,
122.7354 +    0x8771,UBOGON,0x885c,0x88e6,0x890f,0x891b,UBOGON,0x89a9,0x89a5,0x89ee,
122.7355 +    0x8ab1,UBOGON,0x8acc,0x8ace,UBOGON,0x8ab7,UBOGON,0x8ab5,0x8ae9,0x8ab4,
122.7356 +    UBOGON,0x8ab3,0x8ac1,0x8aaf,0x8aca,0x8ad0,UBOGON,UBOGON,UBOGON,0x8c8e,
122.7357 +    UBOGON,UBOGON,0x8ce9,0x8cdb
122.7358 +  },
122.7359 +  {				/* ku 2f */
122.7360 +    UBOGON,0x8ceb,0x8da4,UBOGON,0x8da2,0x8d9d,UBOGON,UBOGON,UBOGON,UBOGON,
122.7361 +    0x8e2a,0x8e28,UBOGON,UBOGON,0x8eb8,0x8eb6,0x8eb9,0x8eb7,0x8f22,0x8f2b,
122.7362 +    0x8f27,0x8f19,0x8fa4,UBOGON,0x8fb3,UBOGON,0x9071,0x906a,UBOGON,UBOGON,
122.7363 +    0x9188,0x918c,0x92bf,0x92b8,0x92be,0x92dc,0x92e5,UBOGON,UBOGON,0x92d4,
122.7364 +    0x92d6,UBOGON,0x92da,0x92ed,0x92f3,0x92db,UBOGON,0x92b9,0x92e2,0x92eb,
122.7365 +    0x95af,UBOGON,0x95b2,0x95b3,UBOGON,UBOGON,UBOGON,0x96a3,0x96a5,UBOGON,
122.7366 +    UBOGON,UBOGON,UBOGON,0x970a,UBOGON,0x9787,0x9789,0x978c,0x97ef,0x982a,
122.7367 +    0x9822,UBOGON,0x981f,UBOGON,0x9919,UBOGON,0x99ca,0x99da,UBOGON,UBOGON,
122.7368 +    UBOGON,0x99de,0x99c8,0x99e0,UBOGON,0x9ab6,0x9ab5,UBOGON,0x9af4,UBOGON,
122.7369 +    0x9b6b,0x9b69,0x9b72,0x9b63
122.7370 +  },
122.7371 +  {				/* ku 30 */
122.7372 +    UBOGON,0x9d0d,UBOGON,0x9d01,0x9d0c,UBOGON,0x9cf8,UBOGON,UBOGON,0x9cfe,
122.7373 +    0x9d02,0x9e84,UBOGON,0x9eab,0x9eaa,0x511d,0x5116,UBOGON,0x512b,0x511e,
122.7374 +    0x511b,0x5290,0x5294,0x5314,UBOGON,UBOGON,0x5667,UBOGON,0x567b,UBOGON,
122.7375 +    0x565f,0x5661,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x58c3,
122.7376 +    0x58ca,0x58bb,0x58c0,0x58c4,0x5901,0x5b1f,0x5b18,0x5b11,0x5b15,UBOGON,
122.7377 +    0x5b12,0x5b1c,UBOGON,0x5b22,0x5b79,0x5da6,UBOGON,0x5db3,0x5dab,0x5eea,
122.7378 +    UBOGON,0x5f5b,UBOGON,UBOGON,0x61b7,0x61ce,0x61b9,0x61bd,0x61cf,0x61c0,
122.7379 +    0x6199,0x6197,UBOGON,0x61bb,0x61d0,0x61c4,0x6231,UBOGON,0x64d3,0x64c0,
122.7380 +    UBOGON,UBOGON,UBOGON,UBOGON,0x64dc,0x64d1,0x64c8,UBOGON,0x64d5,0x66c3,
122.7381 +    UBOGON,UBOGON,0x66bf,0x66c5
122.7382 +  },
122.7383 +  {				/* ku 31 */
122.7384 +    UBOGON,0x66cd,0x66c1,0x6706,UBOGON,0x6724,0x6a63,0x6a42,0x6a52,UBOGON,
122.7385 +    0x6a43,0x6a33,UBOGON,0x6a6c,0x6a57,UBOGON,0x6a4c,0x6a6e,UBOGON,UBOGON,
122.7386 +    UBOGON,UBOGON,UBOGON,0x6a37,UBOGON,0x6a71,0x6a4a,0x6a36,UBOGON,0x6a53,
122.7387 +    UBOGON,0x6a45,0x6a70,UBOGON,UBOGON,0x6a5c,0x6b58,0x6b57,UBOGON,UBOGON,
122.7388 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6fbb,UBOGON,UBOGON,0x6fbe,UBOGON,UBOGON,
122.7389 +    UBOGON,0x6fb5,0x6fd3,0x6f9f,UBOGON,0x6fb7,0x6ff5,0x71b7,UBOGON,0x71bb,
122.7390 +    UBOGON,0x71d1,UBOGON,0x71ba,UBOGON,0x71b6,0x71cc,UBOGON,UBOGON,0x71d3,
122.7391 +    0x749b,UBOGON,UBOGON,0x7496,0x74a2,0x749d,0x750a,0x750e,UBOGON,0x7581,
122.7392 +    0x762c,0x7637,0x7636,0x763b,UBOGON,0x76a1,UBOGON,UBOGON,0x7798,UBOGON,
122.7393 +    0x7796,UBOGON,UBOGON,UBOGON
122.7394 +  },
122.7395 +  {				/* ku 32 */
122.7396 +    0x78d6,0x78eb,UBOGON,0x78dc,UBOGON,0x79a5,0x79a9,0x9834,0x7a53,0x7a45,
122.7397 +    UBOGON,0x7a4f,UBOGON,0x7abd,0x7abb,0x7af1,UBOGON,UBOGON,0x7bec,0x7bed,
122.7398 +    UBOGON,UBOGON,0x7cd3,UBOGON,0x7ce1,UBOGON,0x7e19,UBOGON,UBOGON,UBOGON,
122.7399 +    0x7e27,0x7e26,UBOGON,UBOGON,0x806e,0x81af,UBOGON,UBOGON,0x81ad,UBOGON,
122.7400 +    0x81aa,0x8218,UBOGON,UBOGON,UBOGON,UBOGON,0x856f,0x854c,UBOGON,0x8542,
122.7401 +    UBOGON,0x855c,0x8570,0x855f,UBOGON,0x855a,0x854b,0x853f,0x878a,UBOGON,
122.7402 +    0x878b,0x87a1,0x878e,UBOGON,UBOGON,0x8799,0x885e,0x885f,0x8924,0x89a7,
122.7403 +    0x8aea,0x8afd,0x8af9,0x8ae3,0x8ae5,UBOGON,UBOGON,0x8aec,UBOGON,UBOGON,
122.7404 +    UBOGON,UBOGON,0x8cf2,UBOGON,0x8cef,UBOGON,0x8da6,UBOGON,UBOGON,UBOGON,
122.7405 +    0x8e3b,0x8e43,UBOGON,0x8e32
122.7406 +  },
122.7407 +  {				/* ku 33 */
122.7408 +    0x8f31,0x8f30,UBOGON,0x8f2d,0x8f3c,0x8fa7,0x8fa5,UBOGON,UBOGON,UBOGON,
122.7409 +    0x9137,0x9195,0x918e,UBOGON,0x9196,UBOGON,0x9345,0x930a,UBOGON,UBOGON,
122.7410 +    0x92fd,0x9317,0x931c,0x9307,0x9331,0x9332,0x932c,0x9330,0x9303,0x9305,
122.7411 +    UBOGON,0x95c2,UBOGON,0x95b8,UBOGON,0x95c1,UBOGON,UBOGON,UBOGON,0x96ab,
122.7412 +    0x96b7,UBOGON,UBOGON,0x9715,0x9714,UBOGON,UBOGON,0x970c,0x9717,UBOGON,
122.7413 +    0x9793,UBOGON,0x97d2,UBOGON,UBOGON,0x9836,0x9831,0x9833,0x983c,0x982e,
122.7414 +    0x983a,UBOGON,0x983d,UBOGON,0x98b5,0x9922,0x9923,0x9920,0x991c,0x991d,
122.7415 +    UBOGON,0x99a0,UBOGON,0x99ef,0x99e8,0x99eb,UBOGON,UBOGON,UBOGON,0x99e1,
122.7416 +    0x99e6,UBOGON,UBOGON,0x9af8,0x9af5,UBOGON,UBOGON,0x9b83,0x9b94,0x9b84,
122.7417 +    UBOGON,0x9b8b,0x9b8f,UBOGON
122.7418 +  },
122.7419 +  {				/* ku 34 */
122.7420 +    0x9b8c,UBOGON,0x9b89,UBOGON,0x9b8e,UBOGON,UBOGON,UBOGON,0x9d24,0x9d0f,
122.7421 +    UBOGON,0x9d13,0x9d0a,UBOGON,UBOGON,UBOGON,UBOGON,0x9d2a,0x9d1a,UBOGON,
122.7422 +    0x9d27,0x9d16,0x9d21,UBOGON,0x9e85,0x9eac,0x9ec6,0x9ec5,0x9ed7,0x9f53,
122.7423 +    UBOGON,0x5128,0x5127,0x51df,UBOGON,0x5335,0x53b3,UBOGON,0x568a,0x567d,
122.7424 +    0x5689,UBOGON,0x58cd,0x58d0,UBOGON,0x5b2b,0x5b33,0x5b29,0x5b35,0x5b31,
122.7425 +    0x5b37,0x5c36,0x5dbe,UBOGON,0x5db9,UBOGON,0x5dbb,UBOGON,0x61e2,0x61db,
122.7426 +    0x61dd,0x61dc,0x61da,UBOGON,0x61d9,UBOGON,UBOGON,0x64df,UBOGON,UBOGON,
122.7427 +    0x64e1,UBOGON,0x64ee,UBOGON,0x65b5,0x66d4,0x66d5,UBOGON,0x66d0,0x66d1,
122.7428 +    0x66ce,0x66d7,UBOGON,UBOGON,0x6a7d,0x6a8a,UBOGON,0x6aa7,UBOGON,0x6a99,
122.7429 +    0x6a82,0x6a88,UBOGON,UBOGON
122.7430 +  },
122.7431 +  {				/* ku 35 */
122.7432 +    0x6a86,UBOGON,0x6a98,0x6a9d,UBOGON,UBOGON,0x6a8f,UBOGON,0x6aaa,UBOGON,
122.7433 +    0x6b5d,UBOGON,0x6c0a,UBOGON,0x6fd7,0x6fd6,0x6fe5,UBOGON,UBOGON,UBOGON,
122.7434 +    0x6fd9,0x6fda,0x6fea,UBOGON,0x6ff6,UBOGON,UBOGON,0x71e3,UBOGON,0x71e9,
122.7435 +    UBOGON,0x71eb,0x71ef,0x71f3,0x71ea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7436 +    0x7371,UBOGON,0x74ae,UBOGON,0x74b3,UBOGON,0x74ac,UBOGON,UBOGON,0x7583,
122.7437 +    0x7645,0x764e,0x7644,0x76a3,0x76a5,0x77a6,0x77a4,UBOGON,0x77a9,0x77af,
122.7438 +    UBOGON,UBOGON,UBOGON,0x78f0,0x78f8,0x78f1,UBOGON,0x7a49,UBOGON,UBOGON,
122.7439 +    UBOGON,0x7ac2,0x7af2,0x7af3,0x7bfa,UBOGON,0x7bf6,0x7bfc,0x7c18,0x7c08,
122.7440 +    0x7c12,UBOGON,UBOGON,0x7cdb,0x7cda,UBOGON,UBOGON,UBOGON,0x7e2c,0x7e4d,
122.7441 +    UBOGON,UBOGON,0x7f46,0x7ff6
122.7442 +  },
122.7443 +  {				/* ku 36 */
122.7444 +    0x802b,0x8074,0x81b8,0x81c8,UBOGON,UBOGON,UBOGON,0x8592,0x8593,UBOGON,
122.7445 +    0x857f,0x85ab,0x8597,UBOGON,UBOGON,0x85ac,UBOGON,UBOGON,UBOGON,0x87ce,
122.7446 +    UBOGON,0x87cd,UBOGON,UBOGON,0x87c1,0x87b1,0x87c7,UBOGON,0x8940,UBOGON,
122.7447 +    0x893f,0x8939,UBOGON,0x8943,UBOGON,UBOGON,UBOGON,0x89ab,UBOGON,0x8b1f,
122.7448 +    0x8b09,0x8b0c,UBOGON,UBOGON,0x8c40,UBOGON,0x8c96,UBOGON,0x8cf6,0x8cf7,
122.7449 +    UBOGON,0x8e46,0x8e4f,UBOGON,UBOGON,UBOGON,0x8f3d,0x8f41,0x9366,0x9378,
122.7450 +    0x935d,0x9369,0x9374,0x937d,0x936e,0x9372,0x9373,0x9362,0x9348,0x9353,
122.7451 +    0x935f,0x9368,UBOGON,0x937f,0x936b,UBOGON,0x95c4,UBOGON,0x96af,0x96ad,
122.7452 +    0x96b2,UBOGON,UBOGON,0x971a,0x971b,UBOGON,UBOGON,UBOGON,UBOGON,0x979b,
122.7453 +    0x979f,UBOGON,UBOGON,UBOGON
122.7454 +  },
122.7455 +  {				/* ku 37 */
122.7456 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9840,UBOGON,0x9847,UBOGON,0x98b7,
122.7457 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x99a2,UBOGON,UBOGON,0x9a00,0x99f3,
122.7458 +    UBOGON,UBOGON,0x99f5,UBOGON,UBOGON,0x9abd,0x9b00,0x9b02,UBOGON,0x9b34,
122.7459 +    0x9b49,0x9b9f,UBOGON,0x9ba3,0x9bcd,0x9b99,0x9b9d,UBOGON,UBOGON,0x9d39,
122.7460 +    UBOGON,0x9d44,UBOGON,UBOGON,0x9d35,UBOGON,UBOGON,0x9eaf,UBOGON,0x512f,
122.7461 +    UBOGON,UBOGON,0x9f8e,UBOGON,0x569f,0x569b,0x569e,0x5696,0x5694,0x56a0,
122.7462 +    UBOGON,0x5b3b,UBOGON,UBOGON,0x5b3a,0x5dc1,0x5f4d,0x5f5d,0x61f3,UBOGON,
122.7463 +    UBOGON,UBOGON,UBOGON,0x64f6,0x64e5,0x64ea,0x64e7,0x6505,UBOGON,0x64f9,
122.7464 +    UBOGON,UBOGON,UBOGON,0x6aab,0x6aed,0x6ab2,0x6ab0,0x6ab5,0x6abe,0x6ac1,
122.7465 +    0x6ac8,UBOGON,0x6ac0,0x6abc
122.7466 +  },
122.7467 +  {				/* ku 38 */
122.7468 +    0x6ab1,0x6ac4,0x6abf,UBOGON,UBOGON,0x7008,0x7003,0x6ffd,0x7010,0x7002,
122.7469 +    0x7013,UBOGON,0x71fa,0x7200,0x74b9,0x74bc,UBOGON,0x765b,0x7651,0x764f,
122.7470 +    0x76eb,0x77b8,UBOGON,0x77b9,0x77c1,0x77c0,0x77be,0x790b,UBOGON,0x7907,
122.7471 +    0x790a,0x7908,UBOGON,0x790d,0x7906,0x7915,0x79af,UBOGON,UBOGON,UBOGON,
122.7472 +    0x7af5,UBOGON,UBOGON,0x7c2e,UBOGON,0x7c1b,UBOGON,0x7c1a,0x7c24,UBOGON,
122.7473 +    UBOGON,0x7ce6,0x7ce3,UBOGON,UBOGON,0x7e5d,0x7e4f,0x7e66,0x7e5b,0x7f47,
122.7474 +    0x7fb4,UBOGON,UBOGON,UBOGON,0x7ffa,0x802e,UBOGON,UBOGON,0x81ce,UBOGON,
122.7475 +    UBOGON,0x8219,UBOGON,UBOGON,0x85cc,0x85b2,UBOGON,0x85bb,0x85c1,UBOGON,
122.7476 +    UBOGON,UBOGON,0x87e9,0x87ee,0x87f0,0x87d6,0x880e,0x87da,0x8948,0x894a,
122.7477 +    0x894e,0x894d,0x89b1,0x89b0
122.7478 +  },
122.7479 +  {				/* ku 39 */
122.7480 +    0x89b3,UBOGON,0x8b38,0x8b32,UBOGON,0x8b2d,UBOGON,0x8b34,UBOGON,0x8b29,
122.7481 +    0x8c74,UBOGON,UBOGON,0x8d03,UBOGON,UBOGON,0x8da9,0x8e58,UBOGON,UBOGON,
122.7482 +    0x8ebf,0x8ec1,0x8f4a,0x8fac,UBOGON,0x9089,0x913d,0x913c,0x91a9,0x93a0,
122.7483 +    UBOGON,0x9390,UBOGON,0x9393,0x938b,0x93ad,0x93bb,0x93b8,UBOGON,UBOGON,
122.7484 +    0x939c,0x95d8,0x95d7,UBOGON,UBOGON,UBOGON,0x975d,0x97a9,0x97da,UBOGON,
122.7485 +    UBOGON,UBOGON,UBOGON,0x9854,UBOGON,0x9855,0x984b,UBOGON,0x983f,0x98b9,
122.7486 +    UBOGON,UBOGON,UBOGON,UBOGON,0x9938,0x9936,0x9940,UBOGON,0x993b,0x9939,
122.7487 +    0x99a4,UBOGON,UBOGON,0x9a08,0x9a0c,UBOGON,0x9a10,UBOGON,0x9b07,UBOGON,
122.7488 +    0x9bd2,UBOGON,0x9bc2,0x9bbb,0x9bcc,0x9bcb,UBOGON,UBOGON,0x9d4d,0x9d63,
122.7489 +    0x9d4e,UBOGON,0x9d50,0x9d55
122.7490 +  },
122.7491 +  {				/* ku 3a */
122.7492 +    UBOGON,0x9d5e,UBOGON,0x9e90,0x9eb2,0x9eb1,UBOGON,0x9eca,0x9f02,0x9f27,
122.7493 +    0x9f26,UBOGON,0x56af,0x58e0,0x58dc,UBOGON,0x5b39,UBOGON,UBOGON,0x5b7c,
122.7494 +    0x5bf3,UBOGON,UBOGON,0x5c6b,0x5dc4,0x650b,0x6508,0x650a,UBOGON,UBOGON,
122.7495 +    0x65dc,UBOGON,UBOGON,0x66e1,0x66df,0x6ace,0x6ad4,0x6ae3,0x6ad7,0x6ae2,
122.7496 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6ad8,0x6ad5,0x6ad2,UBOGON,UBOGON,0x701e,
122.7497 +    0x702c,0x7025,0x6ff3,0x7204,0x7208,0x7215,UBOGON,0x74c4,0x74c9,0x74c7,
122.7498 +    0x74c8,0x76a9,0x77c6,0x77c5,0x7918,0x791a,0x7920,UBOGON,0x7a66,0x7a64,
122.7499 +    0x7a6a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7c35,0x7c34,UBOGON,
122.7500 +    UBOGON,0x7e6c,UBOGON,0x7e6e,0x7e71,UBOGON,0x81d4,0x81d6,0x821a,0x8262,
122.7501 +    0x8265,0x8276,0x85db,0x85d6
122.7502 +  },
122.7503 +  {				/* ku 3b */
122.7504 +    UBOGON,0x85e7,UBOGON,UBOGON,0x85f4,UBOGON,0x87fd,0x87d5,0x8807,UBOGON,
122.7505 +    0x880f,0x87f8,UBOGON,UBOGON,0x8987,UBOGON,0x89b5,0x89f5,UBOGON,0x8b3f,
122.7506 +    0x8b43,0x8b4c,UBOGON,0x8d0b,0x8e6b,0x8e68,0x8e70,0x8e75,0x8e77,UBOGON,
122.7507 +    0x8ec3,UBOGON,0x93e9,0x93ea,0x93cb,0x93c5,0x93c6,UBOGON,0x93ed,0x93d3,
122.7508 +    UBOGON,0x93e5,UBOGON,UBOGON,0x93db,0x93eb,0x93e0,0x93c1,UBOGON,UBOGON,
122.7509 +    0x95dd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7510 +    0x97b2,0x97b4,0x97b1,0x97b5,0x97f2,UBOGON,UBOGON,UBOGON,0x9856,UBOGON,
122.7511 +    UBOGON,UBOGON,0x9944,UBOGON,0x9a26,0x9a1f,0x9a18,0x9a21,0x9a17,UBOGON,
122.7512 +    0x9b09,UBOGON,UBOGON,0x9bc5,0x9bdf,UBOGON,0x9be3,UBOGON,0x9be9,0x9bee,
122.7513 +    UBOGON,UBOGON,0x9d66,0x9d7a
122.7514 +  },
122.7515 +  {				/* ku 3c */
122.7516 +    UBOGON,0x9d6e,0x9d91,0x9d83,0x9d76,0x9d7e,0x9d6d,UBOGON,0x9e95,0x9ee3,
122.7517 +    UBOGON,UBOGON,0x9f03,0x9f04,UBOGON,0x9f17,UBOGON,0x5136,UBOGON,0x5336,
122.7518 +    UBOGON,0x5b42,UBOGON,UBOGON,0x5b44,0x5b46,0x5b7e,0x5dca,0x5dc8,0x5dcc,
122.7519 +    0x5ef0,UBOGON,0x6585,0x66e5,0x66e7,UBOGON,UBOGON,UBOGON,0x6af4,UBOGON,
122.7520 +    0x6ae9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x703d,UBOGON,0x7036,UBOGON,
122.7521 +    0x7216,UBOGON,0x7212,0x720f,0x7217,0x7211,0x720b,UBOGON,UBOGON,0x74cd,
122.7522 +    0x74d0,0x74cc,0x74ce,0x74d1,UBOGON,0x7589,UBOGON,0x7a6f,0x7c4b,0x7c44,
122.7523 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7e7f,0x8b71,UBOGON,0x802f,0x807a,
122.7524 +    0x807b,0x807c,UBOGON,UBOGON,UBOGON,0x85fc,0x8610,0x8602,UBOGON,UBOGON,
122.7525 +    0x85ee,0x8603,UBOGON,0x860d
122.7526 +  },
122.7527 +  {				/* ku 3d */
122.7528 +    0x8613,0x8608,0x860f,0x8818,0x8812,UBOGON,UBOGON,0x8967,0x8965,0x89bb,
122.7529 +    0x8b69,0x8b62,UBOGON,0x8b6e,UBOGON,0x8b61,UBOGON,0x8b64,0x8b4d,0x8c51,
122.7530 +    UBOGON,UBOGON,0x8e83,0x8ec6,UBOGON,0x941f,UBOGON,0x9404,0x9417,0x9408,
122.7531 +    0x9405,UBOGON,0x93f3,0x941e,0x9402,0x941a,0x941b,0x9427,0x941c,UBOGON,
122.7532 +    0x96b5,UBOGON,UBOGON,0x9733,UBOGON,0x9734,0x9731,0x97b8,0x97ba,UBOGON,
122.7533 +    0x97fc,UBOGON,UBOGON,0x98c3,UBOGON,0x994d,UBOGON,0x9a2f,UBOGON,UBOGON,
122.7534 +    UBOGON,0x9ac9,UBOGON,0x9ac8,0x9ac4,0x9b2a,0x9b38,0x9b50,UBOGON,0x9c0a,
122.7535 +    0x9bfb,0x9c04,0x9bfc,0x9bfe,UBOGON,UBOGON,UBOGON,0x9c02,0x9bf6,0x9c1b,
122.7536 +    0x9bf9,0x9c15,0x9c10,0x9bff,0x9c00,0x9c0c,UBOGON,UBOGON,0x9d95,0x9da5,
122.7537 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7538 +  },
122.7539 +  {				/* ku 3e */
122.7540 +    0x9e98,0x9ec1,UBOGON,0x9f5a,0x5164,0x56bb,UBOGON,0x58e6,0x5b49,0x5bf7,
122.7541 +    UBOGON,UBOGON,0x5dd0,UBOGON,0x5fc2,UBOGON,0x6511,UBOGON,0x6aff,0x6afe,
122.7542 +    0x6afd,UBOGON,0x6b01,UBOGON,UBOGON,0x704b,0x704d,0x7047,0x74d3,0x7668,
122.7543 +    0x7667,UBOGON,UBOGON,0x77d1,0x7930,0x7932,0x792e,UBOGON,0x9f9d,0x7ac9,
122.7544 +    0x7ac8,UBOGON,0x7c56,0x7c51,UBOGON,UBOGON,UBOGON,0x7e85,0x7e89,0x7e8e,
122.7545 +    0x7e84,UBOGON,0x826a,0x862b,0x862f,0x8628,UBOGON,0x8616,0x8615,0x861d,
122.7546 +    0x881a,UBOGON,UBOGON,UBOGON,0x89bc,0x8b75,0x8b7c,UBOGON,0x8d11,0x8d12,
122.7547 +    0x8f5c,0x91bb,UBOGON,0x93f4,UBOGON,UBOGON,0x942d,UBOGON,UBOGON,0x96e4,
122.7548 +    0x9737,0x9736,0x9767,0x97be,0x97bd,0x97e2,0x9868,0x9866,0x98c8,0x98ca,
122.7549 +    0x98c7,0x98dc,UBOGON,0x994f
122.7550 +  },
122.7551 +  {				/* ku 3f */
122.7552 +    0x99a9,0x9a3c,UBOGON,0x9a3b,0x9ace,UBOGON,0x9b14,0x9b53,UBOGON,0x9c2e,
122.7553 +    UBOGON,0x9c1f,UBOGON,UBOGON,UBOGON,UBOGON,0x9db0,0x9dbd,UBOGON,UBOGON,
122.7554 +    0x9dae,0x9dc4,0x9e7b,UBOGON,UBOGON,0x9e9e,UBOGON,0x9f05,UBOGON,0x9f69,
122.7555 +    0x9fa1,0x56c7,0x571d,0x5b4a,0x5dd3,UBOGON,0x5f72,0x6202,UBOGON,0x6235,
122.7556 +    0x6527,0x651e,0x651f,UBOGON,UBOGON,0x6b07,0x6b06,UBOGON,UBOGON,0x7054,
122.7557 +    0x721c,0x7220,0x7af8,UBOGON,0x7c5d,0x7c58,UBOGON,0x7e92,0x7f4e,UBOGON,
122.7558 +    UBOGON,UBOGON,0x8827,UBOGON,0x8b81,0x8b83,UBOGON,0x8c44,UBOGON,UBOGON,
122.7559 +    UBOGON,UBOGON,0x9442,0x944d,0x9454,0x944e,UBOGON,0x9443,UBOGON,UBOGON,
122.7560 +    0x973c,0x9740,0x97c0,UBOGON,UBOGON,UBOGON,UBOGON,0x995a,0x9a51,UBOGON,
122.7561 +    0x9add,UBOGON,UBOGON,0x9c38
122.7562 +  },
122.7563 +  {				/* ku 40 */
122.7564 +    UBOGON,0x9c45,0x9c3a,UBOGON,0x9c35,UBOGON,UBOGON,UBOGON,0x9ef1,UBOGON,
122.7565 +    0x9f93,0x529a,UBOGON,UBOGON,0x8641,0x5dd7,UBOGON,0x6528,UBOGON,UBOGON,
122.7566 +    UBOGON,0x7053,0x7059,UBOGON,0x7221,UBOGON,0x766f,0x7937,0x79b5,0x7c62,
122.7567 +    0x7c5e,0x7cf5,UBOGON,UBOGON,0x863d,UBOGON,0x882d,0x8989,0x8b8d,0x8b87,
122.7568 +    0x8b90,0x8d1a,0x8e99,UBOGON,UBOGON,UBOGON,0x945f,UBOGON,UBOGON,0x9456,
122.7569 +    0x9461,0x945b,0x945a,0x945c,0x9465,UBOGON,0x9741,UBOGON,UBOGON,0x986e,
122.7570 +    0x986c,0x986d,UBOGON,0x99aa,0x9a5c,0x9a58,0x9ade,UBOGON,0x9c4f,0x9c51,
122.7571 +    UBOGON,0x9c53,UBOGON,UBOGON,UBOGON,0x9dfc,0x9f39,UBOGON,0x513e,UBOGON,
122.7572 +    0x56d2,UBOGON,0x5b4f,0x6b14,UBOGON,0x7a72,0x7a73,UBOGON,UBOGON,UBOGON,
122.7573 +    0x8b91,UBOGON,UBOGON,0x91bf
122.7574 +  },
122.7575 +  {				/* ku 41 */
122.7576 +    UBOGON,0x946c,UBOGON,UBOGON,0x96e6,0x9745,UBOGON,0x97c8,0x97e4,0x995d,
122.7577 +    UBOGON,0x9b21,UBOGON,0x9b2c,0x9b57,UBOGON,UBOGON,0x9c5d,0x9c61,0x9c65,
122.7578 +    0x9e08,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9f45,UBOGON,UBOGON,0x6205,
122.7579 +    0x66ef,0x6b1b,0x6b1d,0x7225,0x7224,0x7c6d,UBOGON,0x8642,0x8649,UBOGON,
122.7580 +    0x8978,0x898a,0x8b97,UBOGON,0x8c9b,0x8d1c,UBOGON,0x8ea2,UBOGON,UBOGON,
122.7581 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c6c,UBOGON,0x9c6f,UBOGON,
122.7582 +    0x9e0e,UBOGON,0x9f08,0x9f1d,0x9fa3,UBOGON,UBOGON,0x5f60,0x6b1c,UBOGON,
122.7583 +    UBOGON,UBOGON,0x7cf3,UBOGON,0x8b9b,0x8ea7,0x91c4,UBOGON,0x947a,UBOGON,
122.7584 +    UBOGON,0x9a61,0x9a63,0x9ad7,0x9c76,UBOGON,0x9fa5,UBOGON,0x7067,UBOGON,
122.7585 +    0x72ab,0x864a,0x897d,0x8b9d
122.7586 +  },
122.7587 +  {				/* ku 42 */
122.7588 +    0x8c53,0x8f65,0x947b,UBOGON,0x98cd,0x98dd,UBOGON,0x9b30,0x9e16,UBOGON,
122.7589 +    UBOGON,UBOGON,UBOGON,UBOGON,0x96e7,0x9e18,0x9ea2,UBOGON,0x9f7c,UBOGON,
122.7590 +    0x7e9e,0x9484,UBOGON,0x9e1c,UBOGON,0x7c71,0x97ca,UBOGON,UBOGON,UBOGON,
122.7591 +    0x9ea3,UBOGON,0x9c7b,0x9f97,UBOGON,UBOGON,0x9750,UBOGON,UBOGON,UBOGON,
122.7592 +    0x5727,0x5c13,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5fc8,UBOGON,
122.7593 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6765,UBOGON,UBOGON,0x52bd,UBOGON,0x5b66,
122.7594 +    UBOGON,0x65f9,0x6788,0x6ce6,0x6ccb,UBOGON,0x4fbd,0x5f8d,UBOGON,0x6018,
122.7595 +    0x6048,UBOGON,0x6b29,0x70a6,UBOGON,0x7706,UBOGON,UBOGON,UBOGON,0x5a10,
122.7596 +    0x5cfc,0x5cfe,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x70c9,UBOGON,
122.7597 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7598 +  },
122.7599 +  {				/* ku 43 */
122.7600 +    UBOGON,UBOGON,0x9579,UBOGON,0x96ba,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7601 +    UBOGON,UBOGON,0x7b29,0x8128,UBOGON,0x8a2e,UBOGON,UBOGON,UBOGON,0x9ad9,
122.7602 +    UBOGON,0x582b,0x5845,UBOGON,0x63fa,UBOGON,UBOGON,UBOGON,0x6e86,UBOGON,
122.7603 +    UBOGON,UBOGON,UBOGON,UBOGON,0x5867,UBOGON,0x5bdd,0x656e,UBOGON,UBOGON,
122.7604 +    UBOGON,0x8c87,UBOGON,0x50d2,0x50df,UBOGON,UBOGON,UBOGON,UBOGON,0x69ba,
122.7605 +    UBOGON,0x6b9d,UBOGON,0x8059,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7606 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6f8a,UBOGON,UBOGON,0x7bc3,
122.7607 +    0x7bc2,UBOGON,UBOGON,UBOGON,UBOGON,0x90f6,UBOGON,0x9823,UBOGON,UBOGON,
122.7608 +    UBOGON,UBOGON,UBOGON,0x71cd,0x7499,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7609 +    0x9842,UBOGON,UBOGON,UBOGON
122.7610 +  },
122.7611 +  {				/* ku 44 */
122.7612 +    UBOGON,0x7f84,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d0e,UBOGON,0x9861,
122.7613 +    UBOGON,UBOGON,0x8b73,UBOGON,0x9c27,UBOGON,0x9458,0x77d6,0x9b2d,UBOGON,
122.7614 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7615 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f66,
122.7616 +    0x4f68,0x4fe7,0x503f,UBOGON,0x50a6,0x510f,0x523e,0x5324,0x5365,0x539b,
122.7617 +    0x517f,0x54cb,0x5573,0x5571,0x556b,0x55f4,0x5622,0x5620,0x5692,0x56ba,
122.7618 +    0x5691,0x56b0,0x5759,0x578a,0x580f,0x5812,0x5813,0x5847,0x589b,0x5900,
122.7619 +    0x594d,0x5ad1,0x5ad3,0x5b67,0x5c57,0x5c77,0x5cd5,0x5d75,0x5d8e,0x5da5,
122.7620 +    0x5db6,0x5dbf,0x5e65,0x5ecd,0x5eed,0x5f94,0x5f9a,0x5fba,0x6125,0x6150,
122.7621 +    0x62a3,0x6360,0x6364,0x63b6
122.7622 +  },
122.7623 +  {				/* ku 45 */
122.7624 +    0x6403,0x64b6,0x651a,0x7a25,0x5c21,0x66e2,0x6702,0x67a4,0x67ac,0x6810,
122.7625 +    0x6806,0x685e,0x685a,0x692c,0x6929,0x6a2d,0x6a77,0x6a7a,0x6aca,0x6ae6,
122.7626 +    0x6af5,0x6b0d,0x6b0e,0x6bdc,0x6bdd,0x6bf6,0x6c1e,0x6c63,0x6da5,0x6e0f,
122.7627 +    0x6e8a,0x6e84,0x6e8b,0x6e7c,0x6f4c,0x6f48,0x6f49,0x6f9d,0x6f99,0x6ff8,
122.7628 +    0x702e,0x702d,0x705c,0x79cc,0x70bf,0x70ea,0x70e5,0x7111,0x7112,0x713f,
122.7629 +    0x7139,0x713b,0x713d,0x7177,0x7175,0x7176,0x7171,0x7196,0x7193,0x71b4,
122.7630 +    0x71dd,0x71de,0x720e,0x5911,0x7218,0x7347,0x7348,0x73ef,0x7412,0x743b,
122.7631 +    0x74a4,0x748d,0x74b4,0x7673,0x7677,0x76bc,0x7819,0x781b,0x783d,0x7853,
122.7632 +    0x7854,0x7858,0x78b7,0x78d8,0x78ee,0x7922,0x794d,0x7986,0x7999,0x79a3,
122.7633 +    0x79bc,0x7aa7,0x7b37,0x7b59
122.7634 +  },
122.7635 +  {				/* ku 46 */
122.7636 +    0x7bd0,0x7c2f,0x7c32,0x7c42,0x7c4e,0x7c68,0x7ca9,0x7ced,0x7dd0,0x7e07,
122.7637 +    0x7dd3,0x7e64,0x7f40,UBOGON,0x8041,0x8063,0x80bb,0x6711,0x6725,0x8248,
122.7638 +    0x8310,0x8362,0x8312,0x8421,0x841e,0x84e2,0x84de,0x84e1,0x8573,0x85d4,
122.7639 +    0x85f5,0x8637,0x8645,0x8672,0x874a,0x87a9,0x87a5,0x87f5,0x8834,0x8850,
122.7640 +    0x8887,0x8954,0x8984,0x8b03,0x8c52,0x8cd8,0x8d0c,0x8d18,0x8db0,0x8ebc,
122.7641 +    0x8ed5,0x8faa,0x909c,UBOGON,0x915c,0x922b,0x9221,0x9273,0x92f4,0x92f5,
122.7642 +    0x933f,0x9342,0x9386,0x93be,0x93bc,0x93bd,0x93f1,0x93f2,0x93ef,0x9422,
122.7643 +    0x9423,0x9424,0x9467,0x9466,0x9597,0x95ce,0x95e7,0x973b,0x974d,0x98e4,
122.7644 +    0x9942,0x9b1d,0x9b98,UBOGON,0x9d49,0x6449,0x5e71,0x5e85,0x61d3,0x990e,
122.7645 +    0x8002,0x781e,UBOGON,UBOGON
122.7646 +  },
122.7647 +  {				/* ku 47 */
122.7648 +    0x5528,0x5572,0x55ba,0x55f0,0x55ee,0x56b8,0x56b9,0x56c4,0x8053,0x92b0,
122.7649 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7650 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7651 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7652 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7653 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7654 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7655 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7656 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7657 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7658 +  }
122.7659 +};
122.7660 +#endif
122.7661 +
122.7662 +#if CNS_EXTENSION
122.7663 +/* CNS 11643 plane 15 conversion table */
122.7664 +
122.7665 +static const unsigned short
122.7666 + cns11643_15tab[MAX_CNS11643_KU_15][MAX_CNS11643_TEN] = {
122.7667 +  {				/* ku 01 */
122.7668 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7669 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5301,UBOGON,UBOGON,UBOGON,UBOGON,
122.7670 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7671 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3436,UBOGON,UBOGON,UBOGON,UBOGON,
122.7672 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53fa,UBOGON,UBOGON,
122.7673 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9f99,UBOGON,UBOGON,UBOGON,
122.7674 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c49,
122.7675 +    UBOGON,UBOGON,UBOGON,0x8fb7,UBOGON,0x3406,UBOGON,UBOGON,UBOGON,UBOGON,
122.7676 +    0x4f29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7677 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7678 +  },
122.7679 +  {				/* ku 02 */
122.7680 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7681 +    UBOGON,0x534e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7682 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7683 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5c81,UBOGON,
122.7684 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5f10,UBOGON,UBOGON,0x6268,UBOGON,
122.7685 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6742,0x6740,0x51ea,UBOGON,UBOGON,UBOGON,
122.7686 +    0x6c62,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7391,
122.7687 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7688 +    0x8fbb,0x8fbc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7689 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7690 +  },
122.7691 +  {				/* ku 03 */
122.7692 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7693 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7694 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7695 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7696 +    0x3575,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x56e8,UBOGON,0x575b,
122.7697 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7698 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7699 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7700 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7701 +    UBOGON,0x5c97,UBOGON,UBOGON
122.7702 +  },
122.7703 +  {				/* ku 04 */
122.7704 +    UBOGON,0x6762,UBOGON,UBOGON,0x383c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7705 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7706 +    UBOGON,UBOGON,UBOGON,UBOGON,0x62a4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7707 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7708 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7709 +    0x6766,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7710 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7711 +    UBOGON,0x6ca3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7712 +    0x707f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7713 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7714 +  },
122.7715 +  {				/* ku 05 */
122.7716 +    UBOGON,UBOGON,0x77f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7717 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8fc8,UBOGON,UBOGON,
122.7718 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7719 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4fab,UBOGON,UBOGON,UBOGON,UBOGON,
122.7720 +    UBOGON,0x3453,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7721 +    UBOGON,0x5c2d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7722 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7723 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7724 +    0x549c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7725 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7726 +  },
122.7727 +  {				/* ku 06 */
122.7728 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7729 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5788,UBOGON,
122.7730 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7731 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7732 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7733 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34ac,UBOGON,UBOGON,
122.7734 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7735 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7736 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7737 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7738 +  },
122.7739 +  {				/* ku 07 */
122.7740 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7741 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x62c3,UBOGON,UBOGON,UBOGON,UBOGON,
122.7742 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6619,
122.7743 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7744 +    UBOGON,UBOGON,UBOGON,0x3b49,UBOGON,0x67a1,UBOGON,0x67a6,UBOGON,UBOGON,
122.7745 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c91,UBOGON,
122.7746 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cd3,
122.7747 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7748 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7749 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7750 +  },
122.7751 +  {				/* ku 08 */
122.7752 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7753 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x77fe,
122.7754 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7755 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7756 +    UBOGON,0x7f57,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43d5,
122.7757 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7758 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82c5,UBOGON,UBOGON,UBOGON,
122.7759 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8fdf,UBOGON,UBOGON,
122.7760 +    0x8fdc,0x488c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7761 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7762 +  },
122.7763 +  {				/* ku 09 */
122.7764 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7765 +    UBOGON,UBOGON,0x4fe4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7766 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7767 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7768 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7769 +    UBOGON,0x551b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3588,
122.7770 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7771 +    UBOGON,UBOGON,UBOGON,0x57aa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7772 +    0x57ab,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7773 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7774 +  },
122.7775 +  {				/* ku 0a */
122.7776 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36c9,
122.7777 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7778 +    UBOGON,UBOGON,UBOGON,UBOGON,0x5ba9,UBOGON,UBOGON,UBOGON,UBOGON,0x3917,
122.7779 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7780 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7781 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7782 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7783 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7784 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7785 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7786 +  },
122.7787 +  {				/* ku 0b */
122.7788 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7789 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7790 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7791 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6811,
122.7792 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7793 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7794 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7795 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7796 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7551,
122.7797 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7798 +  },
122.7799 +  {				/* ku 0c */
122.7800 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7801 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ebd,UBOGON,UBOGON,
122.7802 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7803 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7804 +    UBOGON,0x7553,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7805 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7818,
122.7806 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7807 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4133,UBOGON,UBOGON,UBOGON,
122.7808 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ad7,UBOGON,UBOGON,UBOGON,UBOGON,
122.7809 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7810 +  },
122.7811 +  {				/* ku 0d */
122.7812 +    0x7c7e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7813 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7814 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x867e,
122.7815 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7816 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7817 +    0x4844,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7818 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7819 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7820 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7821 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7822 +  },
122.7823 +  {				/* ku 0e */
122.7824 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7825 +    UBOGON,UBOGON,0x5266,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7826 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7827 +    UBOGON,UBOGON,UBOGON,0x5520,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7828 +    UBOGON,0x5521,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7829 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x57d7,
122.7830 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7831 +    UBOGON,UBOGON,UBOGON,UBOGON,0x36e1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7832 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36e2,UBOGON,UBOGON,
122.7833 +    UBOGON,UBOGON,UBOGON,0x5bbe
122.7834 +  },
122.7835 +  {				/* ku 0f */
122.7836 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7837 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7838 +    UBOGON,UBOGON,UBOGON,0x387c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38e3,
122.7839 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7840 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7841 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7842 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7843 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3aec,UBOGON,UBOGON,
122.7844 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7845 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7846 +  },
122.7847 +  {				/* ku 10 */
122.7848 +    UBOGON,UBOGON,UBOGON,0x6857,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7849 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7850 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7851 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7852 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7853 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7854 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7855 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7856 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7857 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7858 +  },
122.7859 +  {				/* ku 11 */
122.7860 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7861 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7862 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7863 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7864 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7865 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7866 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7867 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7868 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7f3c,UBOGON,UBOGON,
122.7869 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7870 +  },
122.7871 +  {				/* ku 12 */
122.7872 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7873 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8273,UBOGON,UBOGON,
122.7874 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7875 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7876 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4627,UBOGON,
122.7877 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7878 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7879 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96be,UBOGON,
122.7880 +    UBOGON,UBOGON,0x66fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7881 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7882 +  },
122.7883 +  {				/* ku 13 */
122.7884 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7885 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7886 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7887 +    UBOGON,UBOGON,UBOGON,UBOGON,0x35ab,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7888 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7889 +    UBOGON,UBOGON,UBOGON,UBOGON,0x364b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7890 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7891 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7892 +    UBOGON,UBOGON,0x5a72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7893 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7894 +  },
122.7895 +  {				/* ku 14 */
122.7896 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7897 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7898 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7899 +    0x37e2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7900 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7901 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7902 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7903 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7904 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7905 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7906 +  },
122.7907 +  {				/* ku 15 */
122.7908 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7909 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7910 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7911 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7912 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7913 +    UBOGON,UBOGON,UBOGON,UBOGON,0x68bd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7914 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7915 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7916 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7917 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7918 +  },
122.7919 +  {				/* ku 16 */
122.7920 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6e15,UBOGON,
122.7921 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7922 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7923 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dc1,
122.7924 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7925 +    UBOGON,UBOGON,UBOGON,UBOGON,0x7413,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7926 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7927 +    0x74f8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7928 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7929 +    UBOGON,UBOGON,UBOGON,0x7b3d
122.7930 +  },
122.7931 +  {				/* ku 17 */
122.7932 +    UBOGON,UBOGON,0x76d8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7933 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7934 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7935 +    0x79fc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7936 +    UBOGON,UBOGON,UBOGON,UBOGON,0x7b39,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7937 +    UBOGON,0x7d4b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7938 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7939 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7940 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83b9,UBOGON,UBOGON,
122.7941 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7942 +  },
122.7943 +  {				/* ku 18 */
122.7944 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7945 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7946 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x86cf,UBOGON,UBOGON,UBOGON,UBOGON,
122.7947 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7948 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7949 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7950 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7951 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8eae,UBOGON,UBOGON,UBOGON,UBOGON,
122.7952 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7953 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7954 +  },
122.7955 +  {				/* ku 19 */
122.7956 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96eb,
122.7957 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7958 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7959 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7960 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7961 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7962 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7963 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7964 +    0x55b0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7965 +    UBOGON,UBOGON,0x5840,0x5842
122.7966 +  },
122.7967 +  {				/* ku 1a */
122.7968 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7969 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7970 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3701,UBOGON,UBOGON,
122.7971 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7972 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7973 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7974 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7975 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7976 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7977 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7978 +  },
122.7979 +  {				/* ku 1b */
122.7980 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7981 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7982 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7983 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7984 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7985 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7986 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7987 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x692b,UBOGON,0x6916,
122.7988 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7989 +    UBOGON,UBOGON,UBOGON,UBOGON
122.7990 +  },
122.7991 +  {				/* ku 1c */
122.7992 +    0x691b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6927,UBOGON,
122.7993 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7994 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6bf5,UBOGON,UBOGON,
122.7995 +    UBOGON,UBOGON,UBOGON,UBOGON,0x3d20,UBOGON,UBOGON,UBOGON,0x6e82,UBOGON,
122.7996 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7997 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d21,UBOGON,UBOGON,
122.7998 +    0x6e7a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.7999 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8000 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8001 +    UBOGON,UBOGON,UBOGON,0x7129
122.8002 +  },
122.8003 +  {				/* ku 1d */
122.8004 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8005 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8006 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3eda,UBOGON,UBOGON,UBOGON,
122.8007 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8008 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8009 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8010 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8011 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8012 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8013 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8014 +  },
122.8015 +  {				/* ku 1e */
122.8016 +    0x7cab,UBOGON,0x7cac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8017 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8018 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8019 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8020 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8021 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8022 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83f7,
122.8023 +    UBOGON,UBOGON,UBOGON,UBOGON,0x44ea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8024 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8025 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8026 +  },
122.8027 +  {				/* ku 1f */
122.8028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8030 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8031 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8032 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8033 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8034 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8035 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8036 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4989,UBOGON,UBOGON,UBOGON,UBOGON,
122.8037 +    UBOGON,UBOGON,UBOGON,0x9596
122.8038 +  },
122.8039 +  {				/* ku 20 */
122.8040 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8041 +    UBOGON,UBOGON,0x4ab2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8042 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8043 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8044 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8045 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8046 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x55f1,UBOGON,UBOGON,UBOGON,UBOGON,
122.8047 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8048 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8049 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8050 +  },
122.8051 +  {				/* ku 21 */
122.8052 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8053 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8054 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8055 +    0x5f41,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8056 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8057 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8058 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8059 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8060 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8061 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8062 +  },
122.8063 +  {				/* ku 22 */
122.8064 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x698a,UBOGON,UBOGON,
122.8065 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8066 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x698c,UBOGON,UBOGON,
122.8067 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6980,UBOGON,
122.8068 +    0x697f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8069 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8070 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8071 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8072 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dda,UBOGON,UBOGON,
122.8073 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8074 +  },
122.8075 +  {				/* ku 23 */
122.8076 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8077 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8078 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ddb,UBOGON,UBOGON,
122.8079 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8080 +    0x3ee2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8081 +    UBOGON,UBOGON,UBOGON,0x3ee3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8082 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8083 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8084 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8085 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8086 +  },
122.8087 +  {				/* ku 24 */
122.8088 +    UBOGON,UBOGON,UBOGON,UBOGON,0x789c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8089 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8090 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8091 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7b7b,UBOGON,UBOGON,UBOGON,
122.8092 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8093 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8094 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8095 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8096 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8097 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8098 +  },
122.8099 +  {				/* ku 25 */
122.8100 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8101 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8102 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8103 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8104 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8105 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47f3,UBOGON,UBOGON,UBOGON,UBOGON,
122.8106 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8107 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x90d2,UBOGON,UBOGON,UBOGON,
122.8108 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8109 +    0x95a0,UBOGON,UBOGON,UBOGON
122.8110 +  },
122.8111 +  {				/* ku 26 */
122.8112 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8113 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a57,UBOGON,UBOGON,
122.8114 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8115 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8116 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8117 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x51a9,
122.8118 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8119 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8120 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8121 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8122 +  },
122.8123 +  {				/* ku 27 */
122.8124 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8125 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8126 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8127 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8128 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8129 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8130 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8131 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8132 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8133 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8134 +  },
122.8135 +  {				/* ku 28 */
122.8136 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8137 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8138 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8139 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8140 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bbc,
122.8141 +    UBOGON,UBOGON,0x3ba4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8142 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8143 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8144 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8145 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8146 +  },
122.8147 +  {				/* ku 29 */
122.8148 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8149 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8150 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8151 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8152 +    UBOGON,UBOGON,0x7195,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8153 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3de8,UBOGON,UBOGON,UBOGON,UBOGON,
122.8154 +    UBOGON,UBOGON,0x7198,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8155 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8156 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7478,UBOGON,UBOGON,UBOGON,UBOGON,
122.8157 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8158 +  },
122.8159 +  {				/* ku 2a */
122.8160 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8161 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8162 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8163 +    0x78b9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8164 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8165 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8166 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a33,UBOGON,UBOGON,
122.8167 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8168 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8169 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8170 +  },
122.8171 +  {				/* ku 2b */
122.8172 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7cc0,UBOGON,UBOGON,UBOGON,
122.8173 +    0x7cc1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8174 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8176 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8180 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8181 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8182 +  },
122.8183 +  {				/* ku 2c */
122.8184 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8185 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8744,UBOGON,
122.8186 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8187 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8188 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8190 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8191 +    0x4886,UBOGON,UBOGON,UBOGON,0x9064,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8192 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8193 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8194 +  },
122.8195 +  {				/* ku 2d */
122.8196 +    UBOGON,0x9277,UBOGON,UBOGON,UBOGON,UBOGON,0x92af,UBOGON,UBOGON,UBOGON,
122.8197 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8198 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8199 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8204 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8205 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8206 +  },
122.8207 +  {				/* ku 2e */
122.8208 +    UBOGON,UBOGON,UBOGON,UBOGON,0x366d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8209 +    UBOGON,UBOGON,UBOGON,0x366e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8210 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8211 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8214 +    UBOGON,0x5e64,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8217 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8218 +  },
122.8219 +  {				/* ku 2f */
122.8220 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8221 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8222 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8223 +    UBOGON,UBOGON,UBOGON,0x6a2b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8225 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6f46,UBOGON,
122.8229 +    UBOGON,UBOGON,0x6f9a,UBOGON
122.8230 +  },
122.8231 +  {				/* ku 30 */
122.8232 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8233 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8234 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8235 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8236 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f53,UBOGON,UBOGON,UBOGON,UBOGON,
122.8237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8239 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8241 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8242 +  },
122.8243 +  {				/* ku 31 */
122.8244 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8245 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8246 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8247 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8248 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8249 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8250 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4526,UBOGON,
122.8251 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8252 +    UBOGON,UBOGON,0x4527,UBOGON,UBOGON,0x4528,UBOGON,UBOGON,UBOGON,UBOGON,
122.8253 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8254 +  },
122.8255 +  {				/* ku 32 */
122.8256 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8257 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8258 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8259 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8260 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8261 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8262 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8263 +    UBOGON,UBOGON,UBOGON,UBOGON,0x92f2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8265 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8266 +  },
122.8267 +  {				/* ku 33 */
122.8268 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8269 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8270 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b79,
122.8271 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8272 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8273 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8274 +    0x567a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8275 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8276 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8277 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8278 +  },
122.8279 +  {				/* ku 34 */
122.8280 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x372c,
122.8281 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8282 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8283 +    UBOGON,UBOGON,UBOGON,UBOGON,0x5f5c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8284 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8285 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8286 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x65d9,UBOGON,UBOGON,
122.8287 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8288 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8289 +    0x6a72,UBOGON,UBOGON,UBOGON
122.8290 +  },
122.8291 +  {				/* ku 35 */
122.8292 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6a78,UBOGON,
122.8293 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8294 +    UBOGON,UBOGON,UBOGON,UBOGON,0x6b5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8295 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8296 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8297 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8298 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8299 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8300 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3efb,
122.8301 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8302 +  },
122.8303 +  {				/* ku 36 */
122.8304 +    UBOGON,0x3efc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8305 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8306 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8307 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8308 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8309 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8310 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8311 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8312 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8313 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8314 +  },
122.8315 +  {				/* ku 37 */
122.8316 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8317 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8318 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8319 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8320 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8321 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8322 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8323 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8324 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8325 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8326 +  },
122.8327 +  {				/* ku 38 */
122.8328 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8329 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8ebe,UBOGON,
122.8330 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8331 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x933b,
122.8332 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8333 +    UBOGON,UBOGON,0x9340,UBOGON,UBOGON,UBOGON,0x933a,UBOGON,UBOGON,UBOGON,
122.8334 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8335 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8336 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8337 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8338 +  },
122.8339 +  {				/* ku 39 */
122.8340 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8341 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8342 +    UBOGON,UBOGON,UBOGON,0x9b96,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8343 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8344 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8345 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8346 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8347 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8348 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8349 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8350 +  },
122.8351 +  {				/* ku 3a */
122.8352 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39a0,UBOGON,
122.8353 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8354 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8355 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8356 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8357 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8358 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8359 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8360 +    UBOGON,UBOGON,0x71f5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8361 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8362 +  },
122.8363 +  {				/* ku 3b */
122.8364 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8365 +    UBOGON,UBOGON,0x3f01,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8366 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8367 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8368 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8369 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a50,UBOGON,UBOGON,UBOGON,
122.8370 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8371 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8372 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8373 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8374 +  },
122.8375 +  {				/* ku 3c */
122.8376 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8377 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8378 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8379 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8380 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8381 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8382 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8383 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8384 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x481a,UBOGON,UBOGON,
122.8385 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8386 +  },
122.8387 +  {				/* ku 3d */
122.8388 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8389 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8390 +    UBOGON,UBOGON,UBOGON,UBOGON,0x9387,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8391 +    UBOGON,UBOGON,0x9385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8392 +    UBOGON,UBOGON,UBOGON,0x493c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8393 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8394 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8395 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8396 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9bb1,UBOGON,UBOGON,UBOGON,UBOGON,
122.8397 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8398 +  },
122.8399 +  {				/* ku 3e */
122.8400 +    UBOGON,UBOGON,UBOGON,0x9d47,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8401 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8402 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8403 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8404 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8405 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8406 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8407 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8408 +    UBOGON,UBOGON,0x3a6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8409 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8410 +  },
122.8411 +  {				/* ku 3f */
122.8412 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8413 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8414 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8415 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8416 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8417 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8418 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8419 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8420 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8421 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8422 +  },
122.8423 +  {				/* ku 40 */
122.8424 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8425 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8426 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8427 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8428 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x455c,UBOGON,UBOGON,UBOGON,UBOGON,
122.8429 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8430 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8431 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8432 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4787,
122.8433 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8434 +  },
122.8435 +  {				/* ku 41 */
122.8436 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8437 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x93b9,UBOGON,
122.8438 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8439 +    UBOGON,UBOGON,UBOGON,UBOGON,0x93bf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8440 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8441 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8442 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8443 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8444 +    UBOGON,0x9bcf,UBOGON,UBOGON,UBOGON,UBOGON,0x9d64,UBOGON,UBOGON,UBOGON,
122.8445 +    UBOGON,0x9ebf,UBOGON,UBOGON
122.8446 +  },
122.8447 +  {				/* ku 42 */
122.8448 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8449 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8450 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8451 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8452 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8453 +    0x3c07,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8454 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8455 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8456 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f05,UBOGON,UBOGON,
122.8457 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8458 +  },
122.8459 +  {				/* ku 43 */
122.8460 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8461 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8462 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8463 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8464 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8465 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8466 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8467 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45f9,UBOGON,UBOGON,
122.8468 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x89b8,UBOGON,UBOGON,UBOGON,
122.8469 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8470 +  },
122.8471 +  {				/* ku 44 */
122.8472 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8473 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4953,
122.8474 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8475 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8476 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8477 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8478 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8479 +    UBOGON,UBOGON,UBOGON,UBOGON,0x9bf3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8480 +    UBOGON,0x4c69,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8481 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8482 +  },
122.8483 +  {				/* ku 45 */
122.8484 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8485 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8486 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c12,
122.8487 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8488 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8489 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8490 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8491 +    0x7c4f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8492 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8493 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8494 +  },
122.8495 +  {				/* ku 46 */
122.8496 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8497 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8498 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8499 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8500 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8501 +    UBOGON,UBOGON,UBOGON,UBOGON,0x9425,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8502 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8503 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8504 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8505 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8506 +  },
122.8507 +  {				/* ku 47 */
122.8508 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8509 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8510 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8511 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8512 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8513 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8514 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8515 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8516 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8517 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8518 +  },
122.8519 +  {				/* ku 48 */
122.8520 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8521 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8522 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8523 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8524 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8525 +    0x4878,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8526 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8527 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8528 +    UBOGON,0x95e6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8529 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8530 +  },
122.8531 +  {				/* ku 49 */
122.8532 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c2f,
122.8533 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8534 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8535 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8536 +    UBOGON,UBOGON,UBOGON,0x6b0c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8537 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8538 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8539 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8540 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8541 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8542 +  },
122.8543 +  {				/* ku 4a */
122.8544 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8545 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8546 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c47,
122.8547 +    0x4c88,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8548 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8549 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8550 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7936,
122.8551 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8552 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8553 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8554 +  },
122.8555 +  {				/* ku 4b */
122.8556 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8557 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8558 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8559 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8560 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6b15,UBOGON,
122.8561 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8562 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8563 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8564 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8565 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8566 +  },
122.8567 +  {				/* ku 4c */
122.8568 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8569 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8570 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8571 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8572 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8573 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8574 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8575 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4584,UBOGON,UBOGON,UBOGON,UBOGON,
122.8576 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8577 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8578 +  },
122.8579 +  {				/* ku 4d */
122.8580 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8581 +    UBOGON,UBOGON,UBOGON,0x53b5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8582 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8583 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8584 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8585 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8586 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8587 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8588 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
122.8589 +    UBOGON,UBOGON,UBOGON,UBOGON
122.8590 +  }
122.8591 +};
122.8592 +#endif
122.8593 +#endif
   123.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   123.2 +++ b/src/charset/decomtab.c	Mon Sep 14 15:17:45 2009 +0900
   123.3 @@ -0,0 +1,2909 @@
   123.4 +/* ========================================================================
   123.5 + * Copyright 1988-2006 University of Washington
   123.6 + *
   123.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   123.8 + * you may not use this file except in compliance with the License.
   123.9 + * You may obtain a copy of the License at
  123.10 + *
  123.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  123.12 + *
  123.13 + * 
  123.14 + * ========================================================================
  123.15 + */
  123.16 +
  123.17 +/*
  123.18 + * Program:	Unicode decomposition tables (current as of Unicode 5.0)
  123.19 + *
  123.20 + * Author:	Mark Crispin
  123.21 + *		Networks and Distributed Computing
  123.22 + *		Computing & Communications
  123.23 + *		University of Washington
  123.24 + *		Administration Building, AG-44
  123.25 + *		Seattle, WA  98195
  123.26 + *		Internet: MRC@CAC.Washington.EDU
  123.27 + *
  123.28 + * Date:	13 April 2006
  123.29 + * Last Edited:	6 December 2006
  123.30 + */
  123.31 +
  123.32 +/* BMP decompositions */
  123.33 +
  123.34 +#define UCS4_BMPLOMIN 0x00a0
  123.35 +#define UCS4_BMPLOMAX 0x33ff
  123.36 +#define UCS4_BMPLOIXMASK 0x1fff
  123.37 +#define UCS4_BMPLOSIZEMASK 0xe000
  123.38 +#define UCS4_BMPLOSIZESHIFT 13
  123.39 +
  123.40 +	/* BMP low decomposition indices - sssi iiii iiii iiii */
  123.41 +static unsigned short ucs4_dbmploixtab[13152] = {
  123.42 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.43 +  0x2001,0x0000,0x0003,0x0000,0x0000,0x0000,0x0000,0x2004,
  123.44 +  0x0000,0x0000,0x0006,0x0007,0x2008,0x000a,0x0000,0x0000,
  123.45 +  0x200b,0x000d,0x000e,0x0000,0x400f,0x4012,0x4015,0x0000,
  123.46 +  0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x0000,0x2024,
  123.47 +  0x2026,0x2028,0x202a,0x202c,0x202e,0x2030,0x2032,0x2034,
  123.48 +  0x0000,0x2036,0x2038,0x203a,0x203c,0x203e,0x2040,0x0000,
  123.49 +  0x0000,0x2042,0x2044,0x2046,0x2048,0x204a,0x0000,0x0000,
  123.50 +  0x204c,0x204e,0x2050,0x2052,0x2054,0x2056,0x0000,0x2058,
  123.51 +  0x205a,0x205c,0x205e,0x2060,0x2062,0x2064,0x2066,0x2068,
  123.52 +  0x0000,0x206a,0x206c,0x206e,0x2070,0x2072,0x2074,0x0000,
  123.53 +  0x0000,0x2076,0x2078,0x207a,0x207c,0x207e,0x0000,0x2080,
  123.54 +  0x2082,0x2084,0x2086,0x2088,0x208a,0x208c,0x208e,0x2090,
  123.55 +  0x2092,0x2094,0x2096,0x2098,0x209a,0x209c,0x209e,0x20a0,
  123.56 +  0x0000,0x0000,0x20a2,0x20a4,0x20a6,0x20a8,0x20aa,0x20ac,
  123.57 +  0x20ae,0x20b0,0x20b2,0x20b4,0x20b6,0x20b8,0x20ba,0x20bc,
  123.58 +  0x20be,0x20c0,0x20c2,0x20c4,0x20c6,0x20c8,0x0000,0x0000,
  123.59 +  0x20ca,0x20cc,0x20ce,0x20d0,0x20d2,0x20d4,0x20d6,0x20d8,
  123.60 +  0x20da,0x0000,0x20dc,0x20de,0x20e0,0x20e2,0x20e4,0x20e6,
  123.61 +  0x0000,0x20e8,0x20ea,0x20ec,0x20ee,0x20f0,0x20f2,0x20f4,
  123.62 +  0x20f6,0x0000,0x0000,0x20f8,0x20fa,0x20fc,0x20fe,0x2100,
  123.63 +  0x2102,0x2104,0x0000,0x0000,0x2106,0x2108,0x210a,0x210c,
  123.64 +  0x210e,0x2110,0x0000,0x0000,0x2112,0x2114,0x2116,0x2118,
  123.65 +  0x211a,0x211c,0x211e,0x2120,0x2122,0x2124,0x2126,0x2128,
  123.66 +  0x212a,0x212c,0x212e,0x2130,0x2132,0x2134,0x0000,0x0000,
  123.67 +  0x2136,0x2138,0x213a,0x213c,0x213e,0x2140,0x2142,0x2144,
  123.68 +  0x2146,0x2148,0x214a,0x214c,0x214e,0x2150,0x2152,0x2154,
  123.69 +  0x2156,0x2158,0x215a,0x215c,0x215e,0x2160,0x2162,0x0164,
  123.70 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.71 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.72 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.73 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.74 +  0x2165,0x2167,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.75 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2169,
  123.76 +  0x216b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.77 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.78 +  0x0000,0x0000,0x0000,0x0000,0x216d,0x216f,0x2171,0x2173,
  123.79 +  0x2175,0x2177,0x2179,0x217b,0x217d,0x217f,0x2181,0x2183,
  123.80 +  0x2185,0x2187,0x2189,0x218b,0x218d,0x218f,0x2191,0x2193,
  123.81 +  0x2195,0x2197,0x2199,0x219b,0x219d,0x0000,0x219f,0x21a1,
  123.82 +  0x21a3,0x21a5,0x21a7,0x21a9,0x0000,0x0000,0x21ab,0x21ad,
  123.83 +  0x21af,0x21b1,0x21b3,0x21b5,0x21b7,0x21b9,0x21bb,0x21bd,
  123.84 +  0x21bf,0x21c1,0x21c3,0x21c5,0x21c7,0x21c9,0x0000,0x0000,
  123.85 +  0x21cb,0x21cd,0x21cf,0x21d1,0x21d3,0x21d5,0x21d7,0x21d9,
  123.86 +  0x21db,0x21dd,0x21df,0x21e1,0x21e3,0x21e5,0x21e7,0x21e9,
  123.87 +  0x21eb,0x21ed,0x21ef,0x21f1,0x21f3,0x21f5,0x21f7,0x21f9,
  123.88 +  0x21fb,0x21fd,0x21ff,0x2201,0x2203,0x2205,0x2207,0x2209,
  123.89 +  0x220b,0x220d,0x220f,0x2211,0x0000,0x0000,0x2213,0x2215,
  123.90 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2217,0x2219,
  123.91 +  0x221b,0x221d,0x221f,0x2221,0x2223,0x2225,0x2227,0x2229,
  123.92 +  0x222b,0x222d,0x222f,0x2231,0x0000,0x0000,0x0000,0x0000,
  123.93 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.94 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.95 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.96 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.97 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.98 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  123.99 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.100 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.101 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.102 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.103 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.104 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.105 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.106 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.107 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.108 +  0x0233,0x0234,0x0235,0x0236,0x0237,0x0238,0x0239,0x023a,
 123.109 +  0x023b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.110 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.111 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.112 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.113 +  0x223c,0x223e,0x2240,0x2242,0x2244,0x2246,0x0000,0x0000,
 123.114 +  0x0248,0x0249,0x024a,0x024b,0x024c,0x0000,0x0000,0x0000,
 123.115 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.116 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.117 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.118 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.119 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.120 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.121 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.122 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.123 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.124 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.125 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.126 +  0x024d,0x024e,0x0000,0x024f,0x2250,0x0000,0x0000,0x0000,
 123.127 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.128 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.129 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.130 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.131 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.132 +  0x0000,0x0000,0x0000,0x0000,0x0252,0x0000,0x0000,0x0000,
 123.133 +  0x0000,0x0000,0x2253,0x0000,0x0000,0x0000,0x0255,0x0000,
 123.134 +  0x0000,0x0000,0x0000,0x0000,0x2256,0x2258,0x225a,0x025c,
 123.135 +  0x225d,0x225f,0x2261,0x0000,0x2263,0x0000,0x2265,0x2267,
 123.136 +  0x2269,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.137 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.138 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.139 +  0x0000,0x0000,0x226b,0x226d,0x226f,0x2271,0x2273,0x2275,
 123.140 +  0x2277,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.141 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.142 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.143 +  0x0000,0x0000,0x2279,0x227b,0x227d,0x227f,0x2281,0x0000,
 123.144 +  0x0283,0x0284,0x0285,0x2286,0x2288,0x028a,0x028b,0x0000,
 123.145 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.146 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.147 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.148 +  0x028c,0x028d,0x028e,0x0000,0x028f,0x0290,0x0000,0x0000,
 123.149 +  0x0000,0x0291,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.150 +  0x2292,0x2294,0x0000,0x2296,0x0000,0x0000,0x0000,0x2298,
 123.151 +  0x0000,0x0000,0x0000,0x0000,0x229a,0x229c,0x229e,0x0000,
 123.152 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.153 +  0x0000,0x22a0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.154 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.155 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.156 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.157 +  0x0000,0x22a2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.158 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.159 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.160 +  0x22a4,0x22a6,0x0000,0x22a8,0x0000,0x0000,0x0000,0x22aa,
 123.161 +  0x0000,0x0000,0x0000,0x0000,0x22ac,0x22ae,0x22b0,0x0000,
 123.162 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.163 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.164 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x22b2,0x22b4,
 123.165 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.166 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.167 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.168 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.169 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.170 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.171 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.172 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.173 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.174 +  0x0000,0x22b6,0x22b8,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.175 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.176 +  0x22ba,0x22bc,0x22be,0x22c0,0x0000,0x0000,0x22c2,0x22c4,
 123.177 +  0x0000,0x0000,0x22c6,0x22c8,0x22ca,0x22cc,0x22ce,0x22d0,
 123.178 +  0x0000,0x0000,0x22d2,0x22d4,0x22d6,0x22d8,0x22da,0x22dc,
 123.179 +  0x0000,0x0000,0x22de,0x22e0,0x22e2,0x22e4,0x22e6,0x22e8,
 123.180 +  0x22ea,0x22ec,0x22ee,0x22f0,0x22f2,0x22f4,0x0000,0x0000,
 123.181 +  0x22f6,0x22f8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.182 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.183 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.184 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.185 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.186 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.187 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.188 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.189 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.190 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.191 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.192 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.193 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.194 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.195 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.196 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.197 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.198 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x22fa,
 123.199 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.200 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.201 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.202 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.203 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.204 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.205 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.206 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.207 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.208 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.209 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.210 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.211 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.212 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.213 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.214 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.215 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.216 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.217 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.218 +  0x0000,0x0000,0x22fc,0x22fe,0x2300,0x2302,0x2304,0x0000,
 123.219 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.220 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.221 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.222 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.223 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.224 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.225 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.226 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.227 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.228 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x2306,0x2308,0x230a,
 123.229 +  0x230c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.230 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.231 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.232 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.233 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.234 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.235 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.236 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.237 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.238 +  0x230e,0x0000,0x2310,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.239 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.240 +  0x0000,0x0000,0x0000,0x2312,0x0000,0x0000,0x0000,0x0000,
 123.241 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.242 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.243 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.244 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.245 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.246 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.247 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.248 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.249 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.250 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.251 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.252 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.253 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.254 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.255 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.256 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.257 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.258 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.259 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.260 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.261 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.262 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.263 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.264 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.265 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.266 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.267 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.268 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.269 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.270 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.271 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.272 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.273 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.274 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.275 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.276 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.277 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.278 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.279 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.280 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.281 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.282 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.283 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.284 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.285 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.286 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.287 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.288 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.289 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.290 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.291 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.292 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.293 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.294 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.295 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.296 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.297 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.298 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.299 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.300 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.301 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.302 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.303 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.304 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.305 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.306 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.307 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.308 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.309 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.310 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.311 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.312 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.313 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.314 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.315 +  0x0000,0x2314,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.316 +  0x0000,0x2316,0x0000,0x0000,0x2318,0x0000,0x0000,0x0000,
 123.317 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.318 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.319 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.320 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.321 +  0x231a,0x231c,0x231e,0x2320,0x2322,0x2324,0x2326,0x2328,
 123.322 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.323 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.324 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.325 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.326 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.327 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.328 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.329 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.330 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.331 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.332 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.333 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.334 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.335 +  0x0000,0x0000,0x0000,0x232a,0x232c,0x0000,0x0000,0x0000,
 123.336 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.337 +  0x0000,0x0000,0x0000,0x0000,0x232e,0x2330,0x0000,0x2332,
 123.338 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.339 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.340 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.341 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.342 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.343 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.344 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.345 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.346 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.347 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.348 +  0x0000,0x0000,0x0000,0x2334,0x0000,0x0000,0x2336,0x0000,
 123.349 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.350 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.351 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.352 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.353 +  0x0000,0x2338,0x233a,0x233c,0x0000,0x0000,0x233e,0x0000,
 123.354 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.355 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.356 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.357 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.358 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.359 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.360 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.361 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.362 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.363 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.364 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.365 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.366 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.367 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.368 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.369 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.370 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.371 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.372 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.373 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.374 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.375 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.376 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.377 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.378 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.379 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.380 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.381 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.382 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.383 +  0x2340,0x0000,0x0000,0x2342,0x2344,0x0000,0x0000,0x0000,
 123.384 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.385 +  0x0000,0x0000,0x0000,0x0000,0x2346,0x2348,0x0000,0x0000,
 123.386 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.387 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.388 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.389 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.390 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.391 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.392 +  0x0000,0x0000,0x0000,0x0000,0x234a,0x0000,0x0000,0x0000,
 123.393 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.394 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.395 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.396 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.397 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.398 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.399 +  0x0000,0x0000,0x234c,0x234e,0x2350,0x0000,0x0000,0x0000,
 123.400 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.401 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.402 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.403 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.404 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.405 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.406 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.407 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.408 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.409 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.410 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.411 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.412 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.413 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.414 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.415 +  0x2352,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.416 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.417 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.418 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.419 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.420 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.421 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.422 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.423 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.424 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.425 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.426 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.427 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.428 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.429 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.430 +  0x2354,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2356,
 123.431 +  0x2358,0x0000,0x235a,0x235c,0x0000,0x0000,0x0000,0x0000,
 123.432 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.433 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.434 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.435 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.436 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.437 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.438 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.439 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.440 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.441 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.442 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.443 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.444 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.445 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.446 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.447 +  0x0000,0x0000,0x235e,0x2360,0x2362,0x0000,0x0000,0x0000,
 123.448 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.449 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.450 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.451 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.452 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.453 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.454 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.455 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.456 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.457 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.458 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.459 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.460 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.461 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.462 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.463 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.464 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.465 +  0x0000,0x0000,0x2364,0x0000,0x2366,0x2368,0x236a,0x0000,
 123.466 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.467 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.468 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.469 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.470 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.471 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.472 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.473 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.474 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.475 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.476 +  0x0000,0x0000,0x0000,0x236c,0x0000,0x0000,0x0000,0x0000,
 123.477 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.478 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.479 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.480 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.481 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.482 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.483 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.484 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.485 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.486 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.487 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.488 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.489 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.490 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.491 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.492 +  0x0000,0x0000,0x0000,0x236e,0x0000,0x0000,0x0000,0x0000,
 123.493 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.494 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.495 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.496 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.497 +  0x0000,0x0000,0x0000,0x0000,0x2370,0x2372,0x0000,0x0000,
 123.498 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.499 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.500 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.501 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.502 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.503 +  0x0000,0x0000,0x0000,0x0000,0x0374,0x0000,0x0000,0x0000,
 123.504 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.505 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.506 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.507 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.508 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.509 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.510 +  0x0000,0x0000,0x0000,0x2375,0x0000,0x0000,0x0000,0x0000,
 123.511 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x2377,0x0000,0x0000,
 123.512 +  0x0000,0x0000,0x2379,0x0000,0x0000,0x0000,0x0000,0x237b,
 123.513 +  0x0000,0x0000,0x0000,0x0000,0x237d,0x0000,0x0000,0x0000,
 123.514 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.515 +  0x0000,0x237f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.516 +  0x0000,0x0000,0x0000,0x2381,0x0000,0x2383,0x2385,0x2387,
 123.517 +  0x2389,0x238b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.518 +  0x0000,0x238d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.519 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.520 +  0x0000,0x0000,0x0000,0x238f,0x0000,0x0000,0x0000,0x0000,
 123.521 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x2391,0x0000,0x0000,
 123.522 +  0x0000,0x0000,0x2393,0x0000,0x0000,0x0000,0x0000,0x2395,
 123.523 +  0x0000,0x0000,0x0000,0x0000,0x2397,0x0000,0x0000,0x0000,
 123.524 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.525 +  0x0000,0x2399,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.526 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.527 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.528 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.529 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.530 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.531 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.532 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.533 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.534 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.535 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.536 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.537 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.538 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x239b,0x0000,
 123.539 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.540 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.541 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.542 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.543 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.544 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.545 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.546 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.547 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.548 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.549 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.550 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.551 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.552 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.553 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.554 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.555 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.556 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.557 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.558 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.559 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.560 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.561 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.562 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.563 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.564 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.565 +  0x0000,0x0000,0x0000,0x0000,0x039d,0x0000,0x0000,0x0000,
 123.566 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.567 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.568 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.569 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.570 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.571 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.572 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.573 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.574 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.575 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.576 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.577 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.578 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.579 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.580 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.581 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.582 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.583 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.584 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.585 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.586 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.587 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.588 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.589 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.590 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.591 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.592 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.593 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.594 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.595 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.596 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.597 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.598 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.599 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.600 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.601 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.602 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.603 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.604 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.605 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.606 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.607 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.608 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.609 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.610 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.611 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.612 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.613 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.614 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.615 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.616 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.617 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.618 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.619 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.620 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.621 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.622 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.623 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.624 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.625 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.626 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.627 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.628 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.629 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.630 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.631 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.632 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.633 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.634 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.635 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.636 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.637 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.638 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.639 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.640 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.641 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.642 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.643 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.644 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.645 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.646 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.647 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.648 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.649 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.650 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.651 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.652 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.653 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.654 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.655 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.656 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.657 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.658 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.659 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.660 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.661 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.662 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.663 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.664 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.665 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.666 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.667 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.668 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.669 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.670 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.671 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.672 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.673 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.674 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.675 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.676 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.677 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.678 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.679 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.680 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.681 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.682 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.683 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.684 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.685 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.686 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.687 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.688 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.689 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.690 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.691 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.692 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.693 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.694 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.695 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.696 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.697 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.698 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.699 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.700 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.701 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.702 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.703 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.704 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.705 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.706 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.707 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.708 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.709 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.710 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.711 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.712 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.713 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.714 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.715 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.716 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.717 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.718 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.719 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.720 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.721 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.722 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.723 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.724 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.725 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.726 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.727 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.728 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.729 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.730 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.731 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.732 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.733 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.734 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.735 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.736 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.737 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.738 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.739 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.740 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.741 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.742 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.743 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.744 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.745 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.746 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.747 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.748 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.749 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.750 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.751 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.752 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.753 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.754 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.755 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.756 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.757 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.758 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.759 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.760 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.761 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.762 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.763 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.764 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.765 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.766 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.767 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.768 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.769 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.770 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.771 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.772 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.773 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.774 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.775 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.776 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.777 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.778 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.779 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.780 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.781 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.782 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.783 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.784 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.785 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.786 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.787 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.788 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.789 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.790 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.791 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.792 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.793 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.794 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.795 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.796 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.797 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.798 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.799 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.800 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.801 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.802 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.803 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.804 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.805 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.806 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.807 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.808 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.809 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.810 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.811 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.812 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.813 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.814 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.815 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.816 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.817 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.818 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.819 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.820 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.821 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.822 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.823 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.824 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.825 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.826 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.827 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.828 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.829 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.830 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.831 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.832 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.833 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.834 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.835 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.836 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.837 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.838 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.839 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.840 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.841 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.842 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.843 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.844 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.845 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.846 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.847 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.848 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.849 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.850 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.851 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.852 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.853 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.854 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.855 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.856 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.857 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.858 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.859 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.860 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.861 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.862 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.863 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.864 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.865 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.866 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.867 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.868 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.869 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.870 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.871 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.872 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.873 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.874 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.875 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.876 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.877 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.878 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.879 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.880 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.881 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.882 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.883 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.884 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.885 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.886 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x239e,0x0000,
 123.887 +  0x23a0,0x0000,0x23a2,0x0000,0x23a4,0x0000,0x23a6,0x0000,
 123.888 +  0x0000,0x0000,0x23a8,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.889 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.890 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.891 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.892 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.893 +  0x0000,0x0000,0x0000,0x23aa,0x0000,0x23ac,0x0000,0x0000,
 123.894 +  0x23ae,0x23b0,0x0000,0x23b2,0x0000,0x0000,0x0000,0x0000,
 123.895 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.896 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.897 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.898 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.899 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.900 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.901 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.902 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.903 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.904 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.905 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.906 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.907 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.908 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.909 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.910 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.911 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.912 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.913 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.914 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.915 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.916 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.917 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.918 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.919 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.920 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.921 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.922 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.923 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.924 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.925 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.926 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.927 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.928 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.929 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.930 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.931 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.932 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.933 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.934 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.935 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.936 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.937 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.938 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.939 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.940 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.941 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.942 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.943 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.944 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.945 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.946 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.947 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.948 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.949 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.950 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.951 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.952 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.953 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.954 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.955 +  0x0000,0x0000,0x0000,0x0000,0x03b4,0x03b5,0x03b6,0x0000,
 123.956 +  0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,
 123.957 +  0x03bf,0x03c0,0x03c1,0x0000,0x03c2,0x03c3,0x03c4,0x03c5,
 123.958 +  0x03c6,0x03c7,0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,
 123.959 +  0x03ce,0x03cf,0x03d0,0x03d1,0x03d2,0x03d3,0x0000,0x03d4,
 123.960 +  0x03d5,0x03d6,0x03d7,0x03d8,0x03d9,0x03da,0x03db,0x03dc,
 123.961 +  0x03dd,0x03de,0x03df,0x03e0,0x03e1,0x03e2,0x03e3,0x03e4,
 123.962 +  0x03e5,0x03e6,0x03e7,0x03e8,0x03e9,0x03ea,0x03eb,0x03ec,
 123.963 +  0x03ed,0x03ee,0x03ef,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.964 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.965 +  0x03f0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.966 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.967 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.968 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.969 +  0x0000,0x0000,0x0000,0x03f1,0x03f2,0x03f3,0x03f4,0x03f5,
 123.970 +  0x03f6,0x03f7,0x03f8,0x03f9,0x03fa,0x03fb,0x03fc,0x03fd,
 123.971 +  0x03fe,0x03ff,0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,
 123.972 +  0x0406,0x0407,0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,
 123.973 +  0x040e,0x040f,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,
 123.974 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.975 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.976 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.977 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.978 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.979 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.980 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.981 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 123.982 +  0x2416,0x2418,0x241a,0x241c,0x241e,0x2420,0x2422,0x2424,
 123.983 +  0x2426,0x2428,0x242a,0x242c,0x242e,0x2430,0x2432,0x2434,
 123.984 +  0x2436,0x2438,0x243a,0x243c,0x243e,0x2440,0x2442,0x2444,
 123.985 +  0x2446,0x2448,0x244a,0x244c,0x244e,0x2450,0x2452,0x2454,
 123.986 +  0x2456,0x2458,0x245a,0x245c,0x245e,0x2460,0x2462,0x2464,
 123.987 +  0x2466,0x2468,0x246a,0x246c,0x246e,0x2470,0x2472,0x2474,
 123.988 +  0x2476,0x2478,0x247a,0x247c,0x247e,0x2480,0x2482,0x2484,
 123.989 +  0x2486,0x2488,0x248a,0x248c,0x248e,0x2490,0x2492,0x2494,
 123.990 +  0x2496,0x2498,0x249a,0x249c,0x249e,0x24a0,0x24a2,0x24a4,
 123.991 +  0x24a6,0x24a8,0x24aa,0x24ac,0x24ae,0x24b0,0x24b2,0x24b4,
 123.992 +  0x24b6,0x24b8,0x24ba,0x24bc,0x24be,0x24c0,0x24c2,0x24c4,
 123.993 +  0x24c6,0x24c8,0x24ca,0x24cc,0x24ce,0x24d0,0x24d2,0x24d4,
 123.994 +  0x24d6,0x24d8,0x24da,0x24dc,0x24de,0x24e0,0x24e2,0x24e4,
 123.995 +  0x24e6,0x24e8,0x24ea,0x24ec,0x24ee,0x24f0,0x24f2,0x24f4,
 123.996 +  0x24f6,0x24f8,0x24fa,0x24fc,0x24fe,0x2500,0x2502,0x2504,
 123.997 +  0x2506,0x2508,0x250a,0x250c,0x250e,0x2510,0x2512,0x2514,
 123.998 +  0x2516,0x2518,0x251a,0x251c,0x251e,0x2520,0x2522,0x2524,
 123.999 +  0x2526,0x2528,0x252a,0x252c,0x252e,0x2530,0x2532,0x2534,
123.1000 +  0x2536,0x2538,0x253a,0x253c,0x253e,0x2540,0x2542,0x2544,
123.1001 +  0x2546,0x2548,0x254a,0x254c,0x0000,0x0000,0x0000,0x0000,
123.1002 +  0x254e,0x2550,0x2552,0x2554,0x2556,0x2558,0x255a,0x255c,
123.1003 +  0x255e,0x2560,0x2562,0x2564,0x2566,0x2568,0x256a,0x256c,
123.1004 +  0x256e,0x2570,0x2572,0x2574,0x2576,0x2578,0x257a,0x257c,
123.1005 +  0x257e,0x2580,0x2582,0x2584,0x2586,0x2588,0x258a,0x258c,
123.1006 +  0x258e,0x2590,0x2592,0x2594,0x2596,0x2598,0x259a,0x259c,
123.1007 +  0x259e,0x25a0,0x25a2,0x25a4,0x25a6,0x25a8,0x25aa,0x25ac,
123.1008 +  0x25ae,0x25b0,0x25b2,0x25b4,0x25b6,0x25b8,0x25ba,0x25bc,
123.1009 +  0x25be,0x25c0,0x25c2,0x25c4,0x25c6,0x25c8,0x25ca,0x25cc,
123.1010 +  0x25ce,0x25d0,0x25d2,0x25d4,0x25d6,0x25d8,0x25da,0x25dc,
123.1011 +  0x25de,0x25e0,0x25e2,0x25e4,0x25e6,0x25e8,0x25ea,0x25ec,
123.1012 +  0x25ee,0x25f0,0x25f2,0x25f4,0x25f6,0x25f8,0x25fa,0x25fc,
123.1013 +  0x25fe,0x2600,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1014 +  0x2602,0x2604,0x2606,0x2608,0x260a,0x260c,0x260e,0x2610,
123.1015 +  0x2612,0x2614,0x2616,0x2618,0x261a,0x261c,0x261e,0x2620,
123.1016 +  0x2622,0x2624,0x2626,0x2628,0x262a,0x262c,0x0000,0x0000,
123.1017 +  0x262e,0x2630,0x2632,0x2634,0x2636,0x2638,0x0000,0x0000,
123.1018 +  0x263a,0x263c,0x263e,0x2640,0x2642,0x2644,0x2646,0x2648,
123.1019 +  0x264a,0x264c,0x264e,0x2650,0x2652,0x2654,0x2656,0x2658,
123.1020 +  0x265a,0x265c,0x265e,0x2660,0x2662,0x2664,0x2666,0x2668,
123.1021 +  0x266a,0x266c,0x266e,0x2670,0x2672,0x2674,0x2676,0x2678,
123.1022 +  0x267a,0x267c,0x267e,0x2680,0x2682,0x2684,0x0000,0x0000,
123.1023 +  0x2686,0x2688,0x268a,0x268c,0x268e,0x2690,0x0000,0x0000,
123.1024 +  0x2692,0x2694,0x2696,0x2698,0x269a,0x269c,0x269e,0x26a0,
123.1025 +  0x0000,0x26a2,0x0000,0x26a4,0x0000,0x26a6,0x0000,0x26a8,
123.1026 +  0x26aa,0x26ac,0x26ae,0x26b0,0x26b2,0x26b4,0x26b6,0x26b8,
123.1027 +  0x26ba,0x26bc,0x26be,0x26c0,0x26c2,0x26c4,0x26c6,0x26c8,
123.1028 +  0x26ca,0x06cc,0x26cd,0x06cf,0x26d0,0x06d2,0x26d3,0x06d5,
123.1029 +  0x26d6,0x06d8,0x26d9,0x06db,0x26dc,0x06de,0x0000,0x0000,
123.1030 +  0x26df,0x26e1,0x26e3,0x26e5,0x26e7,0x26e9,0x26eb,0x26ed,
123.1031 +  0x26ef,0x26f1,0x26f3,0x26f5,0x26f7,0x26f9,0x26fb,0x26fd,
123.1032 +  0x26ff,0x2701,0x2703,0x2705,0x2707,0x2709,0x270b,0x270d,
123.1033 +  0x270f,0x2711,0x2713,0x2715,0x2717,0x2719,0x271b,0x271d,
123.1034 +  0x271f,0x2721,0x2723,0x2725,0x2727,0x2729,0x272b,0x272d,
123.1035 +  0x272f,0x2731,0x2733,0x2735,0x2737,0x2739,0x273b,0x273d,
123.1036 +  0x273f,0x2741,0x2743,0x2745,0x2747,0x0000,0x2749,0x274b,
123.1037 +  0x274d,0x274f,0x2751,0x0753,0x2754,0x2756,0x0758,0x2759,
123.1038 +  0x275b,0x275d,0x275f,0x2761,0x2763,0x0000,0x2765,0x2767,
123.1039 +  0x2769,0x076b,0x276c,0x076e,0x276f,0x2771,0x2773,0x2775,
123.1040 +  0x2777,0x2779,0x277b,0x077d,0x0000,0x0000,0x277e,0x2780,
123.1041 +  0x2782,0x2784,0x2786,0x0788,0x0000,0x2789,0x278b,0x278d,
123.1042 +  0x278f,0x2791,0x2793,0x0795,0x2796,0x2798,0x279a,0x279c,
123.1043 +  0x279e,0x27a0,0x27a2,0x07a4,0x27a5,0x27a7,0x07a9,0x07aa,
123.1044 +  0x0000,0x0000,0x27ab,0x27ad,0x27af,0x0000,0x27b1,0x27b3,
123.1045 +  0x27b5,0x07b7,0x27b8,0x07ba,0x27bb,0x07bd,0x27be,0x0000,
123.1046 +  0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7,
123.1047 +  0x07c8,0x07c9,0x07ca,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1048 +  0x0000,0x07cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x27cc,
123.1049 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1050 +  0x0000,0x0000,0x0000,0x0000,0x07ce,0x27cf,0x47d1,0x0000,
123.1051 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x07d4,
123.1052 +  0x0000,0x0000,0x0000,0x27d5,0x47d7,0x0000,0x27da,0x47dc,
123.1053 +  0x0000,0x0000,0x0000,0x0000,0x27df,0x0000,0x27e1,0x0000,
123.1054 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x27e3,
123.1055 +  0x27e5,0x27e7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1056 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x67e9,
123.1057 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x07ed,
123.1058 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1059 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1060 +  0x07ee,0x07ef,0x0000,0x0000,0x07f0,0x07f1,0x07f2,0x07f3,
123.1061 +  0x07f4,0x07f5,0x07f6,0x07f7,0x07f8,0x07f9,0x07fa,0x07fb,
123.1062 +  0x07fc,0x07fd,0x07fe,0x07ff,0x0800,0x0801,0x0802,0x0803,
123.1063 +  0x0804,0x0805,0x0806,0x0807,0x0808,0x0809,0x080a,0x0000,
123.1064 +  0x080b,0x080c,0x080d,0x080e,0x080f,0x0000,0x0000,0x0000,
123.1065 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1066 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1067 +  0x2810,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1068 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1069 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1070 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1071 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1072 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1073 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1074 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1075 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1076 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1077 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1078 +  0x4812,0x4815,0x0818,0x2819,0x0000,0x481b,0x481e,0x0821,
123.1079 +  0x0000,0x2822,0x0824,0x0825,0x0826,0x0827,0x0828,0x0829,
123.1080 +  0x082a,0x082b,0x082c,0x082d,0x0000,0x082e,0x282f,0x0000,
123.1081 +  0x0000,0x0831,0x0832,0x0833,0x0834,0x0835,0x0000,0x0000,
123.1082 +  0x2836,0x4838,0x283b,0x0000,0x083d,0x0000,0x083e,0x0000,
123.1083 +  0x083f,0x0000,0x0840,0x0841,0x0842,0x0843,0x0000,0x0844,
123.1084 +  0x0845,0x0846,0x0000,0x0847,0x0848,0x0849,0x084a,0x084b,
123.1085 +  0x084c,0x084d,0x0000,0x484e,0x0851,0x0852,0x0853,0x0854,
123.1086 +  0x0855,0x0000,0x0000,0x0000,0x0000,0x0856,0x0857,0x0858,
123.1087 +  0x0859,0x085a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1088 +  0x0000,0x0000,0x0000,0x485b,0x485e,0x4861,0x4864,0x4867,
123.1089 +  0x486a,0x486d,0x4870,0x4873,0x4876,0x4879,0x487c,0x287f,
123.1090 +  0x0881,0x2882,0x4884,0x2887,0x0889,0x288a,0x488c,0x688f,
123.1091 +  0x2893,0x0895,0x2896,0x4898,0x089b,0x089c,0x089d,0x089e,
123.1092 +  0x089f,0x28a0,0x48a2,0x28a5,0x08a7,0x28a8,0x48aa,0x68ad,
123.1093 +  0x28b1,0x08b3,0x28b4,0x48b6,0x08b9,0x08ba,0x08bb,0x08bc,
123.1094 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1095 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1096 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1097 +  0x0000,0x0000,0x28bd,0x28bf,0x0000,0x0000,0x0000,0x0000,
123.1098 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1099 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x28c1,0x0000,
123.1100 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1101 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1102 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1103 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x28c3,0x28c5,0x28c7,
123.1104 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1105 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1106 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1107 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1108 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1109 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1110 +  0x0000,0x0000,0x0000,0x0000,0x28c9,0x0000,0x0000,0x0000,
123.1111 +  0x0000,0x28cb,0x0000,0x0000,0x28cd,0x0000,0x0000,0x0000,
123.1112 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1113 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1114 +  0x0000,0x0000,0x0000,0x0000,0x28cf,0x0000,0x28d1,0x0000,
123.1115 +  0x0000,0x0000,0x0000,0x0000,0x28d3,0x48d5,0x0000,0x28d8,
123.1116 +  0x48da,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1117 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1118 +  0x0000,0x28dd,0x0000,0x0000,0x28df,0x0000,0x0000,0x28e1,
123.1119 +  0x0000,0x28e3,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1120 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1121 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1122 +  0x28e5,0x0000,0x28e7,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1123 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x28e9,0x28eb,0x28ed,
123.1124 +  0x28ef,0x28f1,0x0000,0x0000,0x28f3,0x28f5,0x0000,0x0000,
123.1125 +  0x28f7,0x28f9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1126 +  0x28fb,0x28fd,0x0000,0x0000,0x28ff,0x2901,0x0000,0x0000,
123.1127 +  0x2903,0x2905,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1128 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1129 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1130 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1131 +  0x0000,0x0000,0x0000,0x0000,0x2907,0x2909,0x290b,0x290d,
123.1132 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1133 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1134 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1135 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1136 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1137 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1138 +  0x290f,0x2911,0x2913,0x2915,0x0000,0x0000,0x0000,0x0000,
123.1139 +  0x0000,0x0000,0x2917,0x2919,0x291b,0x291d,0x0000,0x0000,
123.1140 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1141 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1142 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1143 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1144 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1145 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1146 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1147 +  0x0000,0x091f,0x0920,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1148 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1149 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1150 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1151 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1152 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1153 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1154 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1155 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1156 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1157 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1158 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1159 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1160 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1161 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1162 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1163 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1164 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1165 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1166 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1167 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1168 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1169 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1170 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1171 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1172 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1173 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1174 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1175 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1176 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1177 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1178 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1179 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1180 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1181 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1182 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1183 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1184 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1185 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1186 +  0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,0x0928,
123.1187 +  0x0929,0x292a,0x292c,0x292e,0x2930,0x2932,0x2934,0x2936,
123.1188 +  0x2938,0x293a,0x293c,0x293e,0x4940,0x4943,0x4946,0x4949,
123.1189 +  0x494c,0x494f,0x4952,0x4955,0x4958,0x695b,0x695f,0x6963,
123.1190 +  0x6967,0x696b,0x696f,0x6973,0x6977,0x697b,0x697f,0x6983,
123.1191 +  0x2987,0x2989,0x298b,0x298d,0x298f,0x2991,0x2993,0x2995,
123.1192 +  0x2997,0x4999,0x499c,0x499f,0x49a2,0x49a5,0x49a8,0x49ab,
123.1193 +  0x49ae,0x49b1,0x49b4,0x49b7,0x49ba,0x49bd,0x49c0,0x49c3,
123.1194 +  0x49c6,0x49c9,0x49cc,0x49cf,0x49d2,0x49d5,0x49d8,0x49db,
123.1195 +  0x49de,0x49e1,0x49e4,0x49e7,0x49ea,0x49ed,0x49f0,0x49f3,
123.1196 +  0x49f6,0x49f9,0x49fc,0x49ff,0x4a02,0x4a05,0x0a08,0x0a09,
123.1197 +  0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,0x0a10,0x0a11,
123.1198 +  0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,0x0a18,0x0a19,
123.1199 +  0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,0x0a20,0x0a21,
123.1200 +  0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,0x0a28,0x0a29,
123.1201 +  0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,0x0a30,0x0a31,
123.1202 +  0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,0x0a38,0x0a39,
123.1203 +  0x0a3a,0x0a3b,0x0a3c,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1204 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1205 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1206 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1207 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1208 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1209 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1210 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1211 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1212 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1213 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1214 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1215 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1216 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1217 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1218 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1219 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1220 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1221 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1222 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1223 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1224 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1225 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1226 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1227 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1228 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1229 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1230 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1231 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1232 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1233 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1234 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1235 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1236 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1237 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1238 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1239 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1240 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1241 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1242 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1243 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1244 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1245 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1246 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1247 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1248 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1249 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1250 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1251 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1252 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1253 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1254 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1255 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1256 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1257 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1258 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1259 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1260 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1261 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1262 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1263 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1264 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1265 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1266 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1267 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1268 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1269 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1270 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1271 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1272 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1273 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1274 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1275 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1276 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1277 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1278 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1279 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1280 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1281 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1282 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1283 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1284 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1285 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1286 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1287 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1288 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1289 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1290 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1291 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1292 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1293 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1294 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1295 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1296 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1297 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1298 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1299 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1300 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1301 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1302 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1303 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1304 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1305 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1306 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1307 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1308 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1309 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1310 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1311 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1312 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1313 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1314 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1315 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1316 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1317 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1318 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1319 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1320 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1321 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1322 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1323 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1324 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1325 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1326 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1327 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1328 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1329 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1330 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1331 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1332 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1333 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1334 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1335 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1336 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1337 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1338 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1339 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1340 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1341 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1342 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1343 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1344 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1345 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1346 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1347 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1348 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1349 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1350 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1351 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1352 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1353 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1354 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1355 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1356 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1357 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1358 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1359 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1360 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1361 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1362 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1363 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1364 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1365 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1366 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1367 +  0x0000,0x0000,0x0000,0x0000,0x6a3d,0x0000,0x0000,0x0000,
123.1368 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1369 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1370 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1371 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1372 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1373 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1374 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1375 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1376 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1377 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1378 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1379 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1380 +  0x0000,0x0000,0x0000,0x0000,0x4a41,0x2a44,0x4a46,0x0000,
123.1381 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1382 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1383 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1384 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1385 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1386 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1387 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1388 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1389 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1390 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1391 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1392 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1393 +  0x0000,0x0000,0x0000,0x0000,0x2a49,0x0000,0x0000,0x0000,
123.1394 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1395 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1396 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1397 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1398 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1399 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1400 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1401 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1402 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1403 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1404 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1405 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1406 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1407 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1408 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1409 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1410 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1411 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1412 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1413 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1414 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1415 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1416 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1417 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1418 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1419 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1420 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1421 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1422 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1423 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1424 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1425 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1426 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1427 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1428 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1429 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1430 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1431 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1432 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1433 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1434 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1435 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1436 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1437 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1438 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1439 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1440 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1441 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1442 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1443 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1444 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1445 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1446 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1447 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1448 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1449 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1450 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1451 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1452 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1453 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1454 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1455 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1456 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1457 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1458 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1459 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1460 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1461 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1462 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1463 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1464 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1465 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1466 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1467 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1468 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1469 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1470 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1471 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1472 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1473 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1474 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1475 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0a4b,
123.1476 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1477 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1478 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1479 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1480 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1481 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1482 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1483 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1484 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1485 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1486 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1487 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1488 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1489 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1490 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1491 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1492 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1493 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1494 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1495 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1496 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1497 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1498 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1499 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1500 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1501 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1502 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1503 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1504 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1505 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1506 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1507 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1508 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1509 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1510 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1511 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1512 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1513 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0a4c,
123.1514 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1515 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1516 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1517 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1518 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1519 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1520 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1521 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1522 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1523 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1524 +  0x0000,0x0000,0x0000,0x0a4d,0x0000,0x0000,0x0000,0x0000,
123.1525 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1526 +  0x0a4e,0x0a4f,0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,
123.1527 +  0x0a56,0x0a57,0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,
123.1528 +  0x0a5e,0x0a5f,0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,
123.1529 +  0x0a66,0x0a67,0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,
123.1530 +  0x0a6e,0x0a6f,0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,
123.1531 +  0x0a76,0x0a77,0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,
123.1532 +  0x0a7e,0x0a7f,0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,
123.1533 +  0x0a86,0x0a87,0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,
123.1534 +  0x0a8e,0x0a8f,0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,
123.1535 +  0x0a96,0x0a97,0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,
123.1536 +  0x0a9e,0x0a9f,0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,
123.1537 +  0x0aa6,0x0aa7,0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,
123.1538 +  0x0aae,0x0aaf,0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,
123.1539 +  0x0ab6,0x0ab7,0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,
123.1540 +  0x0abe,0x0abf,0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,
123.1541 +  0x0ac6,0x0ac7,0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,
123.1542 +  0x0ace,0x0acf,0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,
123.1543 +  0x0ad6,0x0ad7,0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,
123.1544 +  0x0ade,0x0adf,0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,
123.1545 +  0x0ae6,0x0ae7,0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,
123.1546 +  0x0aee,0x0aef,0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,
123.1547 +  0x0af6,0x0af7,0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,
123.1548 +  0x0afe,0x0aff,0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,
123.1549 +  0x0b06,0x0b07,0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,
123.1550 +  0x0b0e,0x0b0f,0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,
123.1551 +  0x0b16,0x0b17,0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,
123.1552 +  0x0b1e,0x0b1f,0x0b20,0x0b21,0x0b22,0x0b23,0x0000,0x0000,
123.1553 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1554 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1555 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1556 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1557 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1558 +  0x0b24,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1559 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1560 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1561 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1562 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1563 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1564 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0b25,0x0000,
123.1565 +  0x0b26,0x0b27,0x0b28,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1566 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1567 +  0x0000,0x0000,0x0000,0x0000,0x2b29,0x0000,0x2b2b,0x0000,
123.1568 +  0x2b2d,0x0000,0x2b2f,0x0000,0x2b31,0x0000,0x2b33,0x0000,
123.1569 +  0x2b35,0x0000,0x2b37,0x0000,0x2b39,0x0000,0x2b3b,0x0000,
123.1570 +  0x2b3d,0x0000,0x2b3f,0x0000,0x0000,0x2b41,0x0000,0x2b43,
123.1571 +  0x0000,0x2b45,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1572 +  0x2b47,0x2b49,0x0000,0x2b4b,0x2b4d,0x0000,0x2b4f,0x2b51,
123.1573 +  0x0000,0x2b53,0x2b55,0x0000,0x2b57,0x2b59,0x0000,0x0000,
123.1574 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1575 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1576 +  0x0000,0x0000,0x0000,0x0000,0x2b5b,0x0000,0x0000,0x0000,
123.1577 +  0x0000,0x0000,0x0000,0x2b5d,0x2b5f,0x0000,0x2b61,0x2b63,
123.1578 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1579 +  0x0000,0x0000,0x0000,0x0000,0x2b65,0x0000,0x2b67,0x0000,
123.1580 +  0x2b69,0x0000,0x2b6b,0x0000,0x2b6d,0x0000,0x2b6f,0x0000,
123.1581 +  0x2b71,0x0000,0x2b73,0x0000,0x2b75,0x0000,0x2b77,0x0000,
123.1582 +  0x2b79,0x0000,0x2b7b,0x0000,0x0000,0x2b7d,0x0000,0x2b7f,
123.1583 +  0x0000,0x2b81,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1584 +  0x2b83,0x2b85,0x0000,0x2b87,0x2b89,0x0000,0x2b8b,0x2b8d,
123.1585 +  0x0000,0x2b8f,0x2b91,0x0000,0x2b93,0x2b95,0x0000,0x0000,
123.1586 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1587 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1588 +  0x0000,0x0000,0x0000,0x0000,0x2b97,0x0000,0x0000,0x2b99,
123.1589 +  0x2b9b,0x2b9d,0x2b9f,0x0000,0x0000,0x0000,0x2ba1,0x2ba3,
123.1590 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1591 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1592 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1593 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1594 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1595 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1596 +  0x0000,0x0ba5,0x0ba6,0x0ba7,0x0ba8,0x0ba9,0x0baa,0x0bab,
123.1597 +  0x0bac,0x0bad,0x0bae,0x0baf,0x0bb0,0x0bb1,0x0bb2,0x0bb3,
123.1598 +  0x0bb4,0x0bb5,0x0bb6,0x0bb7,0x0bb8,0x0bb9,0x0bba,0x0bbb,
123.1599 +  0x0bbc,0x0bbd,0x0bbe,0x0bbf,0x0bc0,0x0bc1,0x0bc2,0x0bc3,
123.1600 +  0x0bc4,0x0bc5,0x0bc6,0x0bc7,0x0bc8,0x0bc9,0x0bca,0x0bcb,
123.1601 +  0x0bcc,0x0bcd,0x0bce,0x0bcf,0x0bd0,0x0bd1,0x0bd2,0x0bd3,
123.1602 +  0x0bd4,0x0bd5,0x0bd6,0x0bd7,0x0bd8,0x0bd9,0x0bda,0x0bdb,
123.1603 +  0x0bdc,0x0bdd,0x0bde,0x0bdf,0x0be0,0x0be1,0x0be2,0x0be3,
123.1604 +  0x0be4,0x0be5,0x0be6,0x0be7,0x0be8,0x0be9,0x0bea,0x0beb,
123.1605 +  0x0bec,0x0bed,0x0bee,0x0bef,0x0bf0,0x0bf1,0x0bf2,0x0bf3,
123.1606 +  0x0bf4,0x0bf5,0x0bf6,0x0bf7,0x0bf8,0x0bf9,0x0bfa,0x0bfb,
123.1607 +  0x0bfc,0x0bfd,0x0bfe,0x0bff,0x0c00,0x0c01,0x0c02,0x0000,
123.1608 +  0x0000,0x0000,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,0x0c08,
123.1609 +  0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,0x0c10,
123.1610 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1611 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1612 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1613 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1614 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1615 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1616 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1617 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1618 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1619 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1620 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1621 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1622 +  0x4c11,0x4c14,0x4c17,0x4c1a,0x4c1d,0x4c20,0x4c23,0x4c26,
123.1623 +  0x4c29,0x4c2c,0x4c2f,0x4c32,0x4c35,0x4c38,0x6c3b,0x6c3f,
123.1624 +  0x6c43,0x6c47,0x6c4b,0x6c4f,0x6c53,0x6c57,0x6c5b,0x6c5f,
123.1625 +  0x6c63,0x6c67,0x6c6b,0x6c6f,0x6c73,0xcc77,0xac7e,0x0000,
123.1626 +  0x4c84,0x4c87,0x4c8a,0x4c8d,0x4c90,0x4c93,0x4c96,0x4c99,
123.1627 +  0x4c9c,0x4c9f,0x4ca2,0x4ca5,0x4ca8,0x4cab,0x4cae,0x4cb1,
123.1628 +  0x4cb4,0x4cb7,0x4cba,0x4cbd,0x4cc0,0x4cc3,0x4cc6,0x4cc9,
123.1629 +  0x4ccc,0x4ccf,0x4cd2,0x4cd5,0x4cd8,0x4cdb,0x4cde,0x4ce1,
123.1630 +  0x4ce4,0x4ce7,0x4cea,0x4ced,0x0000,0x0000,0x0000,0x0000,
123.1631 +  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.1632 +  0x4cf0,0x2cf3,0x2cf5,0x2cf7,0x2cf9,0x2cfb,0x2cfd,0x2cff,
123.1633 +  0x2d01,0x2d03,0x2d05,0x2d07,0x2d09,0x2d0b,0x2d0d,0x2d0f,
123.1634 +  0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,0x0d18,
123.1635 +  0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x2d1f,0x2d21,
123.1636 +  0x2d23,0x2d25,0x2d27,0x2d29,0x2d2b,0x2d2d,0x2d2f,0x2d31,
123.1637 +  0x2d33,0x2d35,0x2d37,0x2d39,0x8d3b,0x6d40,0x2d44,0x0000,
123.1638 +  0x0d46,0x0d47,0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,
123.1639 +  0x0d4e,0x0d4f,0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,
123.1640 +  0x0d56,0x0d57,0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,
123.1641 +  0x0d5e,0x0d5f,0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,
123.1642 +  0x0d66,0x0d67,0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,
123.1643 +  0x0d6e,0x0d6f,0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,
123.1644 +  0x0d76,0x2d77,0x2d79,0x2d7b,0x2d7d,0x2d7f,0x2d81,0x2d83,
123.1645 +  0x2d85,0x2d87,0x2d89,0x2d8b,0x2d8d,0x2d8f,0x2d91,0x2d93,
123.1646 +  0x2d95,0x2d97,0x2d99,0x2d9b,0x2d9d,0x2d9f,0x2da1,0x2da3,
123.1647 +  0x2da5,0x4da7,0x4daa,0x4dad,0x2db0,0x4db2,0x2db5,0x4db7,
123.1648 +  0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,0x0dc0,0x0dc1,
123.1649 +  0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,0x0dc8,0x0dc9,
123.1650 +  0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,0x0dd0,0x0dd1,
123.1651 +  0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,0x0dd8,0x0dd9,
123.1652 +  0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,0x0de0,0x0de1,
123.1653 +  0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,0x0de8,0x0000,
123.1654 +  0x6de9,0x6ded,0x6df1,0x4df5,0x6df8,0x4dfc,0x4dff,0x8e02,
123.1655 +  0x6e07,0x4e0b,0x4e0e,0x4e11,0x6e14,0x6e18,0x4e1c,0x4e1f,
123.1656 +  0x2e22,0x4e24,0x6e27,0x6e2b,0x2e2f,0x8e31,0xae36,0x8e3c,
123.1657 +  0x4e41,0x8e44,0x8e49,0x6e4e,0x4e52,0x4e55,0x4e58,0x6e5b,
123.1658 +  0x8e5f,0x6e64,0x4e68,0x4e6b,0x4e6e,0x2e71,0x2e73,0x2e75,
123.1659 +  0x2e77,0x4e79,0x4e7c,0x8e7f,0x4e84,0x6e87,0x8e8b,0x4e90,
123.1660 +  0x2e93,0x2e95,0x8e97,0x6e9c,0x8ea0,0x4ea5,0x8ea8,0x2ead,
123.1661 +  0x4eaf,0x4eb2,0x4eb5,0x4eb8,0x4ebb,0x6ebe,0x4ec2,0x2ec5,
123.1662 +  0x4ec7,0x4eca,0x4ecd,0x6ed0,0x4ed4,0x4ed7,0x4eda,0x8edd,
123.1663 +  0x6ee2,0x2ee6,0x8ee8,0x2eed,0x6eef,0x6ef3,0x4ef7,0x4efa,
123.1664 +  0x4efd,0x6f00,0x2f04,0x4f06,0x6f09,0x2f0d,0x8f0f,0x4f14,
123.1665 +  0x2f17,0x2f19,0x2f1b,0x2f1d,0x2f1f,0x2f21,0x2f23,0x2f25,
123.1666 +  0x2f27,0x2f29,0x4f2b,0x4f2e,0x4f31,0x4f34,0x4f37,0x4f3a,
123.1667 +  0x4f3d,0x4f40,0x4f43,0x4f46,0x4f49,0x4f4c,0x4f4f,0x4f52,
123.1668 +  0x4f55,0x4f58,0x2f5b,0x2f5d,0x4f5f,0x2f62,0x2f64,0x2f66,
123.1669 +  0x4f68,0x4f6b,0x2f6e,0x2f70,0x2f72,0x2f74,0x2f76,0x6f78,
123.1670 +  0x2f7c,0x2f7e,0x2f80,0x2f82,0x2f84,0x2f86,0x2f88,0x2f8a,
123.1671 +  0x4f8c,0x6f8f,0x2f93,0x2f95,0x2f97,0x2f99,0x2f9b,0x2f9d,
123.1672 +  0x2f9f,0x4fa1,0x4fa4,0x4fa7,0x4faa,0x2fad,0x2faf,0x2fb1,
123.1673 +  0x2fb3,0x2fb5,0x2fb7,0x2fb9,0x2fbb,0x2fbd,0x2fbf,0x4fc1,
123.1674 +  0x4fc4,0x2fc7,0x4fc9,0x4fcc,0x4fcf,0x2fd2,0x4fd4,0x4fd7,
123.1675 +  0x6fda,0x2fde,0x4fe0,0x4fe3,0x4fe6,0x4fe9,0x8fec,0xaff1,
123.1676 +  0x2ff7,0x2ff9,0x2ffb,0x2ffd,0x2fff,0x3001,0x3003,0x3005,
123.1677 +  0x3007,0x3009,0x300b,0x300d,0x300f,0x3011,0x3013,0x3015,
123.1678 +  0x3017,0x3019,0x701b,0x301f,0x3021,0x3023,0x7025,0x5029,
123.1679 +  0x302c,0x302e,0x3030,0x3032,0x3034,0x3036,0x3038,0x303a,
123.1680 +  0x303c,0x303e,0x5040,0x3043,0x3045,0x5047,0x504a,0x304d,
123.1681 +  0x704f,0x5053,0x3056,0x3058,0x305a,0x305c,0x505e,0x5061,
123.1682 +  0x3064,0x3066,0x3068,0x306a,0x306c,0x306e,0x3070,0x3072,
123.1683 +  0x3074,0x5076,0x5079,0x507c,0x507f,0x5082,0x5085,0x5088,
123.1684 +  0x508b,0x508e,0x5091,0x5094,0x5097,0x509a,0x509d,0x50a0,
123.1685 +  0x50a3,0x50a6,0x50a9,0x50ac,0x50af,0x50b2,0x50b5,0x50b8,
123.1686 +};
123.1687 +
123.1688 +	/* BMP low decompositions */
123.1689 +static unsigned short ucs4_dbmplotab[4283] = {
123.1690 +  0x0020,0x0020,0x0308,0x0061,0x0020,0x0304,0x0032,0x0033,
123.1691 +  0x0020,0x0301,0x03bc,0x0020,0x0327,0x0031,0x006f,0x0031,
123.1692 +  0x2044,0x0034,0x0031,0x2044,0x0032,0x0033,0x2044,0x0034,
123.1693 +  0x0041,0x0300,0x0041,0x0301,0x0041,0x0302,0x0041,0x0303,
123.1694 +  0x0041,0x0308,0x0041,0x030a,0x0043,0x0327,0x0045,0x0300,
123.1695 +  0x0045,0x0301,0x0045,0x0302,0x0045,0x0308,0x0049,0x0300,
123.1696 +  0x0049,0x0301,0x0049,0x0302,0x0049,0x0308,0x004e,0x0303,
123.1697 +  0x004f,0x0300,0x004f,0x0301,0x004f,0x0302,0x004f,0x0303,
123.1698 +  0x004f,0x0308,0x0055,0x0300,0x0055,0x0301,0x0055,0x0302,
123.1699 +  0x0055,0x0308,0x0059,0x0301,0x0061,0x0300,0x0061,0x0301,
123.1700 +  0x0061,0x0302,0x0061,0x0303,0x0061,0x0308,0x0061,0x030a,
123.1701 +  0x0063,0x0327,0x0065,0x0300,0x0065,0x0301,0x0065,0x0302,
123.1702 +  0x0065,0x0308,0x0069,0x0300,0x0069,0x0301,0x0069,0x0302,
123.1703 +  0x0069,0x0308,0x006e,0x0303,0x006f,0x0300,0x006f,0x0301,
123.1704 +  0x006f,0x0302,0x006f,0x0303,0x006f,0x0308,0x0075,0x0300,
123.1705 +  0x0075,0x0301,0x0075,0x0302,0x0075,0x0308,0x0079,0x0301,
123.1706 +  0x0079,0x0308,0x0041,0x0304,0x0061,0x0304,0x0041,0x0306,
123.1707 +  0x0061,0x0306,0x0041,0x0328,0x0061,0x0328,0x0043,0x0301,
123.1708 +  0x0063,0x0301,0x0043,0x0302,0x0063,0x0302,0x0043,0x0307,
123.1709 +  0x0063,0x0307,0x0043,0x030c,0x0063,0x030c,0x0044,0x030c,
123.1710 +  0x0064,0x030c,0x0045,0x0304,0x0065,0x0304,0x0045,0x0306,
123.1711 +  0x0065,0x0306,0x0045,0x0307,0x0065,0x0307,0x0045,0x0328,
123.1712 +  0x0065,0x0328,0x0045,0x030c,0x0065,0x030c,0x0047,0x0302,
123.1713 +  0x0067,0x0302,0x0047,0x0306,0x0067,0x0306,0x0047,0x0307,
123.1714 +  0x0067,0x0307,0x0047,0x0327,0x0067,0x0327,0x0048,0x0302,
123.1715 +  0x0068,0x0302,0x0049,0x0303,0x0069,0x0303,0x0049,0x0304,
123.1716 +  0x0069,0x0304,0x0049,0x0306,0x0069,0x0306,0x0049,0x0328,
123.1717 +  0x0069,0x0328,0x0049,0x0307,0x0049,0x004a,0x0069,0x006a,
123.1718 +  0x004a,0x0302,0x006a,0x0302,0x004b,0x0327,0x006b,0x0327,
123.1719 +  0x004c,0x0301,0x006c,0x0301,0x004c,0x0327,0x006c,0x0327,
123.1720 +  0x004c,0x030c,0x006c,0x030c,0x004c,0x00b7,0x006c,0x00b7,
123.1721 +  0x004e,0x0301,0x006e,0x0301,0x004e,0x0327,0x006e,0x0327,
123.1722 +  0x004e,0x030c,0x006e,0x030c,0x02bc,0x006e,0x004f,0x0304,
123.1723 +  0x006f,0x0304,0x004f,0x0306,0x006f,0x0306,0x004f,0x030b,
123.1724 +  0x006f,0x030b,0x0052,0x0301,0x0072,0x0301,0x0052,0x0327,
123.1725 +  0x0072,0x0327,0x0052,0x030c,0x0072,0x030c,0x0053,0x0301,
123.1726 +  0x0073,0x0301,0x0053,0x0302,0x0073,0x0302,0x0053,0x0327,
123.1727 +  0x0073,0x0327,0x0053,0x030c,0x0073,0x030c,0x0054,0x0327,
123.1728 +  0x0074,0x0327,0x0054,0x030c,0x0074,0x030c,0x0055,0x0303,
123.1729 +  0x0075,0x0303,0x0055,0x0304,0x0075,0x0304,0x0055,0x0306,
123.1730 +  0x0075,0x0306,0x0055,0x030a,0x0075,0x030a,0x0055,0x030b,
123.1731 +  0x0075,0x030b,0x0055,0x0328,0x0075,0x0328,0x0057,0x0302,
123.1732 +  0x0077,0x0302,0x0059,0x0302,0x0079,0x0302,0x0059,0x0308,
123.1733 +  0x005a,0x0301,0x007a,0x0301,0x005a,0x0307,0x007a,0x0307,
123.1734 +  0x005a,0x030c,0x007a,0x030c,0x0073,0x004f,0x031b,0x006f,
123.1735 +  0x031b,0x0055,0x031b,0x0075,0x031b,0x0044,0x017d,0x0044,
123.1736 +  0x017e,0x0064,0x017e,0x004c,0x004a,0x004c,0x006a,0x006c,
123.1737 +  0x006a,0x004e,0x004a,0x004e,0x006a,0x006e,0x006a,0x0041,
123.1738 +  0x030c,0x0061,0x030c,0x0049,0x030c,0x0069,0x030c,0x004f,
123.1739 +  0x030c,0x006f,0x030c,0x0055,0x030c,0x0075,0x030c,0x00dc,
123.1740 +  0x0304,0x00fc,0x0304,0x00dc,0x0301,0x00fc,0x0301,0x00dc,
123.1741 +  0x030c,0x00fc,0x030c,0x00dc,0x0300,0x00fc,0x0300,0x00c4,
123.1742 +  0x0304,0x00e4,0x0304,0x0226,0x0304,0x0227,0x0304,0x00c6,
123.1743 +  0x0304,0x00e6,0x0304,0x0047,0x030c,0x0067,0x030c,0x004b,
123.1744 +  0x030c,0x006b,0x030c,0x004f,0x0328,0x006f,0x0328,0x01ea,
123.1745 +  0x0304,0x01eb,0x0304,0x01b7,0x030c,0x0292,0x030c,0x006a,
123.1746 +  0x030c,0x0044,0x005a,0x0044,0x007a,0x0064,0x007a,0x0047,
123.1747 +  0x0301,0x0067,0x0301,0x004e,0x0300,0x006e,0x0300,0x00c5,
123.1748 +  0x0301,0x00e5,0x0301,0x00c6,0x0301,0x00e6,0x0301,0x00d8,
123.1749 +  0x0301,0x00f8,0x0301,0x0041,0x030f,0x0061,0x030f,0x0041,
123.1750 +  0x0311,0x0061,0x0311,0x0045,0x030f,0x0065,0x030f,0x0045,
123.1751 +  0x0311,0x0065,0x0311,0x0049,0x030f,0x0069,0x030f,0x0049,
123.1752 +  0x0311,0x0069,0x0311,0x004f,0x030f,0x006f,0x030f,0x004f,
123.1753 +  0x0311,0x006f,0x0311,0x0052,0x030f,0x0072,0x030f,0x0052,
123.1754 +  0x0311,0x0072,0x0311,0x0055,0x030f,0x0075,0x030f,0x0055,
123.1755 +  0x0311,0x0075,0x0311,0x0053,0x0326,0x0073,0x0326,0x0054,
123.1756 +  0x0326,0x0074,0x0326,0x0048,0x030c,0x0068,0x030c,0x0041,
123.1757 +  0x0307,0x0061,0x0307,0x0045,0x0327,0x0065,0x0327,0x00d6,
123.1758 +  0x0304,0x00f6,0x0304,0x00d5,0x0304,0x00f5,0x0304,0x004f,
123.1759 +  0x0307,0x006f,0x0307,0x022e,0x0304,0x022f,0x0304,0x0059,
123.1760 +  0x0304,0x0079,0x0304,0x0068,0x0266,0x006a,0x0072,0x0279,
123.1761 +  0x027b,0x0281,0x0077,0x0079,0x0020,0x0306,0x0020,0x0307,
123.1762 +  0x0020,0x030a,0x0020,0x0328,0x0020,0x0303,0x0020,0x030b,
123.1763 +  0x0263,0x006c,0x0073,0x0078,0x0295,0x0300,0x0301,0x0313,
123.1764 +  0x0308,0x0301,0x02b9,0x0020,0x0345,0x003b,0x0020,0x0301,
123.1765 +  0x00a8,0x0301,0x0391,0x0301,0x00b7,0x0395,0x0301,0x0397,
123.1766 +  0x0301,0x0399,0x0301,0x039f,0x0301,0x03a5,0x0301,0x03a9,
123.1767 +  0x0301,0x03ca,0x0301,0x0399,0x0308,0x03a5,0x0308,0x03b1,
123.1768 +  0x0301,0x03b5,0x0301,0x03b7,0x0301,0x03b9,0x0301,0x03cb,
123.1769 +  0x0301,0x03b9,0x0308,0x03c5,0x0308,0x03bf,0x0301,0x03c5,
123.1770 +  0x0301,0x03c9,0x0301,0x03b2,0x03b8,0x03a5,0x03d2,0x0301,
123.1771 +  0x03d2,0x0308,0x03c6,0x03c0,0x03ba,0x03c1,0x03c2,0x0398,
123.1772 +  0x03b5,0x03a3,0x0415,0x0300,0x0415,0x0308,0x0413,0x0301,
123.1773 +  0x0406,0x0308,0x041a,0x0301,0x0418,0x0300,0x0423,0x0306,
123.1774 +  0x0418,0x0306,0x0438,0x0306,0x0435,0x0300,0x0435,0x0308,
123.1775 +  0x0433,0x0301,0x0456,0x0308,0x043a,0x0301,0x0438,0x0300,
123.1776 +  0x0443,0x0306,0x0474,0x030f,0x0475,0x030f,0x0416,0x0306,
123.1777 +  0x0436,0x0306,0x0410,0x0306,0x0430,0x0306,0x0410,0x0308,
123.1778 +  0x0430,0x0308,0x0415,0x0306,0x0435,0x0306,0x04d8,0x0308,
123.1779 +  0x04d9,0x0308,0x0416,0x0308,0x0436,0x0308,0x0417,0x0308,
123.1780 +  0x0437,0x0308,0x0418,0x0304,0x0438,0x0304,0x0418,0x0308,
123.1781 +  0x0438,0x0308,0x041e,0x0308,0x043e,0x0308,0x04e8,0x0308,
123.1782 +  0x04e9,0x0308,0x042d,0x0308,0x044d,0x0308,0x0423,0x0304,
123.1783 +  0x0443,0x0304,0x0423,0x0308,0x0443,0x0308,0x0423,0x030b,
123.1784 +  0x0443,0x030b,0x0427,0x0308,0x0447,0x0308,0x042b,0x0308,
123.1785 +  0x044b,0x0308,0x0565,0x0582,0x0627,0x0653,0x0627,0x0654,
123.1786 +  0x0648,0x0654,0x0627,0x0655,0x064a,0x0654,0x0627,0x0674,
123.1787 +  0x0648,0x0674,0x06c7,0x0674,0x064a,0x0674,0x06d5,0x0654,
123.1788 +  0x06c1,0x0654,0x06d2,0x0654,0x0928,0x093c,0x0930,0x093c,
123.1789 +  0x0933,0x093c,0x0915,0x093c,0x0916,0x093c,0x0917,0x093c,
123.1790 +  0x091c,0x093c,0x0921,0x093c,0x0922,0x093c,0x092b,0x093c,
123.1791 +  0x092f,0x093c,0x09c7,0x09be,0x09c7,0x09d7,0x09a1,0x09bc,
123.1792 +  0x09a2,0x09bc,0x09af,0x09bc,0x0a32,0x0a3c,0x0a38,0x0a3c,
123.1793 +  0x0a16,0x0a3c,0x0a17,0x0a3c,0x0a1c,0x0a3c,0x0a2b,0x0a3c,
123.1794 +  0x0b47,0x0b56,0x0b47,0x0b3e,0x0b47,0x0b57,0x0b21,0x0b3c,
123.1795 +  0x0b22,0x0b3c,0x0b92,0x0bd7,0x0bc6,0x0bbe,0x0bc7,0x0bbe,
123.1796 +  0x0bc6,0x0bd7,0x0c46,0x0c56,0x0cbf,0x0cd5,0x0cc6,0x0cd5,
123.1797 +  0x0cc6,0x0cd6,0x0cc6,0x0cc2,0x0cca,0x0cd5,0x0d46,0x0d3e,
123.1798 +  0x0d47,0x0d3e,0x0d46,0x0d57,0x0dd9,0x0dca,0x0dd9,0x0dcf,
123.1799 +  0x0ddc,0x0dca,0x0dd9,0x0ddf,0x0e4d,0x0e32,0x0ecd,0x0eb2,
123.1800 +  0x0eab,0x0e99,0x0eab,0x0ea1,0x0f0b,0x0f42,0x0fb7,0x0f4c,
123.1801 +  0x0fb7,0x0f51,0x0fb7,0x0f56,0x0fb7,0x0f5b,0x0fb7,0x0f40,
123.1802 +  0x0fb5,0x0f71,0x0f72,0x0f71,0x0f74,0x0fb2,0x0f80,0x0fb2,
123.1803 +  0x0f81,0x0fb3,0x0f80,0x0fb3,0x0f81,0x0f71,0x0f80,0x0f92,
123.1804 +  0x0fb7,0x0f9c,0x0fb7,0x0fa1,0x0fb7,0x0fa6,0x0fb7,0x0fab,
123.1805 +  0x0fb7,0x0f90,0x0fb5,0x1025,0x102e,0x10dc,0x1b05,0x1b35,
123.1806 +  0x1b07,0x1b35,0x1b09,0x1b35,0x1b0b,0x1b35,0x1b0d,0x1b35,
123.1807 +  0x1b11,0x1b35,0x1b3a,0x1b35,0x1b3c,0x1b35,0x1b3e,0x1b35,
123.1808 +  0x1b3f,0x1b35,0x1b42,0x1b35,0x0041,0x00c6,0x0042,0x0044,
123.1809 +  0x0045,0x018e,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
123.1810 +  0x004d,0x004e,0x004f,0x0222,0x0050,0x0052,0x0054,0x0055,
123.1811 +  0x0057,0x0061,0x0250,0x0251,0x1d02,0x0062,0x0064,0x0065,
123.1812 +  0x0259,0x025b,0x025c,0x0067,0x006b,0x006d,0x014b,0x006f,
123.1813 +  0x0254,0x1d16,0x1d17,0x0070,0x0074,0x0075,0x1d1d,0x026f,
123.1814 +  0x0076,0x1d25,0x03b2,0x03b3,0x03b4,0x03c6,0x03c7,0x0069,
123.1815 +  0x0072,0x0075,0x0076,0x03b2,0x03b3,0x03c1,0x03c6,0x03c7,
123.1816 +  0x043d,0x0252,0x0063,0x0255,0x00f0,0x025c,0x0066,0x025f,
123.1817 +  0x0261,0x0265,0x0268,0x0269,0x026a,0x1d7b,0x029d,0x026d,
123.1818 +  0x1d85,0x029f,0x0271,0x0270,0x0272,0x0273,0x0274,0x0275,
123.1819 +  0x0278,0x0282,0x0283,0x01ab,0x0289,0x028a,0x1d1c,0x028b,
123.1820 +  0x028c,0x007a,0x0290,0x0291,0x0292,0x03b8,0x0041,0x0325,
123.1821 +  0x0061,0x0325,0x0042,0x0307,0x0062,0x0307,0x0042,0x0323,
123.1822 +  0x0062,0x0323,0x0042,0x0331,0x0062,0x0331,0x00c7,0x0301,
123.1823 +  0x00e7,0x0301,0x0044,0x0307,0x0064,0x0307,0x0044,0x0323,
123.1824 +  0x0064,0x0323,0x0044,0x0331,0x0064,0x0331,0x0044,0x0327,
123.1825 +  0x0064,0x0327,0x0044,0x032d,0x0064,0x032d,0x0112,0x0300,
123.1826 +  0x0113,0x0300,0x0112,0x0301,0x0113,0x0301,0x0045,0x032d,
123.1827 +  0x0065,0x032d,0x0045,0x0330,0x0065,0x0330,0x0228,0x0306,
123.1828 +  0x0229,0x0306,0x0046,0x0307,0x0066,0x0307,0x0047,0x0304,
123.1829 +  0x0067,0x0304,0x0048,0x0307,0x0068,0x0307,0x0048,0x0323,
123.1830 +  0x0068,0x0323,0x0048,0x0308,0x0068,0x0308,0x0048,0x0327,
123.1831 +  0x0068,0x0327,0x0048,0x032e,0x0068,0x032e,0x0049,0x0330,
123.1832 +  0x0069,0x0330,0x00cf,0x0301,0x00ef,0x0301,0x004b,0x0301,
123.1833 +  0x006b,0x0301,0x004b,0x0323,0x006b,0x0323,0x004b,0x0331,
123.1834 +  0x006b,0x0331,0x004c,0x0323,0x006c,0x0323,0x1e36,0x0304,
123.1835 +  0x1e37,0x0304,0x004c,0x0331,0x006c,0x0331,0x004c,0x032d,
123.1836 +  0x006c,0x032d,0x004d,0x0301,0x006d,0x0301,0x004d,0x0307,
123.1837 +  0x006d,0x0307,0x004d,0x0323,0x006d,0x0323,0x004e,0x0307,
123.1838 +  0x006e,0x0307,0x004e,0x0323,0x006e,0x0323,0x004e,0x0331,
123.1839 +  0x006e,0x0331,0x004e,0x032d,0x006e,0x032d,0x00d5,0x0301,
123.1840 +  0x00f5,0x0301,0x00d5,0x0308,0x00f5,0x0308,0x014c,0x0300,
123.1841 +  0x014d,0x0300,0x014c,0x0301,0x014d,0x0301,0x0050,0x0301,
123.1842 +  0x0070,0x0301,0x0050,0x0307,0x0070,0x0307,0x0052,0x0307,
123.1843 +  0x0072,0x0307,0x0052,0x0323,0x0072,0x0323,0x1e5a,0x0304,
123.1844 +  0x1e5b,0x0304,0x0052,0x0331,0x0072,0x0331,0x0053,0x0307,
123.1845 +  0x0073,0x0307,0x0053,0x0323,0x0073,0x0323,0x015a,0x0307,
123.1846 +  0x015b,0x0307,0x0160,0x0307,0x0161,0x0307,0x1e62,0x0307,
123.1847 +  0x1e63,0x0307,0x0054,0x0307,0x0074,0x0307,0x0054,0x0323,
123.1848 +  0x0074,0x0323,0x0054,0x0331,0x0074,0x0331,0x0054,0x032d,
123.1849 +  0x0074,0x032d,0x0055,0x0324,0x0075,0x0324,0x0055,0x0330,
123.1850 +  0x0075,0x0330,0x0055,0x032d,0x0075,0x032d,0x0168,0x0301,
123.1851 +  0x0169,0x0301,0x016a,0x0308,0x016b,0x0308,0x0056,0x0303,
123.1852 +  0x0076,0x0303,0x0056,0x0323,0x0076,0x0323,0x0057,0x0300,
123.1853 +  0x0077,0x0300,0x0057,0x0301,0x0077,0x0301,0x0057,0x0308,
123.1854 +  0x0077,0x0308,0x0057,0x0307,0x0077,0x0307,0x0057,0x0323,
123.1855 +  0x0077,0x0323,0x0058,0x0307,0x0078,0x0307,0x0058,0x0308,
123.1856 +  0x0078,0x0308,0x0059,0x0307,0x0079,0x0307,0x005a,0x0302,
123.1857 +  0x007a,0x0302,0x005a,0x0323,0x007a,0x0323,0x005a,0x0331,
123.1858 +  0x007a,0x0331,0x0068,0x0331,0x0074,0x0308,0x0077,0x030a,
123.1859 +  0x0079,0x030a,0x0061,0x02be,0x017f,0x0307,0x0041,0x0323,
123.1860 +  0x0061,0x0323,0x0041,0x0309,0x0061,0x0309,0x00c2,0x0301,
123.1861 +  0x00e2,0x0301,0x00c2,0x0300,0x00e2,0x0300,0x00c2,0x0309,
123.1862 +  0x00e2,0x0309,0x00c2,0x0303,0x00e2,0x0303,0x1ea0,0x0302,
123.1863 +  0x1ea1,0x0302,0x0102,0x0301,0x0103,0x0301,0x0102,0x0300,
123.1864 +  0x0103,0x0300,0x0102,0x0309,0x0103,0x0309,0x0102,0x0303,
123.1865 +  0x0103,0x0303,0x1ea0,0x0306,0x1ea1,0x0306,0x0045,0x0323,
123.1866 +  0x0065,0x0323,0x0045,0x0309,0x0065,0x0309,0x0045,0x0303,
123.1867 +  0x0065,0x0303,0x00ca,0x0301,0x00ea,0x0301,0x00ca,0x0300,
123.1868 +  0x00ea,0x0300,0x00ca,0x0309,0x00ea,0x0309,0x00ca,0x0303,
123.1869 +  0x00ea,0x0303,0x1eb8,0x0302,0x1eb9,0x0302,0x0049,0x0309,
123.1870 +  0x0069,0x0309,0x0049,0x0323,0x0069,0x0323,0x004f,0x0323,
123.1871 +  0x006f,0x0323,0x004f,0x0309,0x006f,0x0309,0x00d4,0x0301,
123.1872 +  0x00f4,0x0301,0x00d4,0x0300,0x00f4,0x0300,0x00d4,0x0309,
123.1873 +  0x00f4,0x0309,0x00d4,0x0303,0x00f4,0x0303,0x1ecc,0x0302,
123.1874 +  0x1ecd,0x0302,0x01a0,0x0301,0x01a1,0x0301,0x01a0,0x0300,
123.1875 +  0x01a1,0x0300,0x01a0,0x0309,0x01a1,0x0309,0x01a0,0x0303,
123.1876 +  0x01a1,0x0303,0x01a0,0x0323,0x01a1,0x0323,0x0055,0x0323,
123.1877 +  0x0075,0x0323,0x0055,0x0309,0x0075,0x0309,0x01af,0x0301,
123.1878 +  0x01b0,0x0301,0x01af,0x0300,0x01b0,0x0300,0x01af,0x0309,
123.1879 +  0x01b0,0x0309,0x01af,0x0303,0x01b0,0x0303,0x01af,0x0323,
123.1880 +  0x01b0,0x0323,0x0059,0x0300,0x0079,0x0300,0x0059,0x0323,
123.1881 +  0x0079,0x0323,0x0059,0x0309,0x0079,0x0309,0x0059,0x0303,
123.1882 +  0x0079,0x0303,0x03b1,0x0313,0x03b1,0x0314,0x1f00,0x0300,
123.1883 +  0x1f01,0x0300,0x1f00,0x0301,0x1f01,0x0301,0x1f00,0x0342,
123.1884 +  0x1f01,0x0342,0x0391,0x0313,0x0391,0x0314,0x1f08,0x0300,
123.1885 +  0x1f09,0x0300,0x1f08,0x0301,0x1f09,0x0301,0x1f08,0x0342,
123.1886 +  0x1f09,0x0342,0x03b5,0x0313,0x03b5,0x0314,0x1f10,0x0300,
123.1887 +  0x1f11,0x0300,0x1f10,0x0301,0x1f11,0x0301,0x0395,0x0313,
123.1888 +  0x0395,0x0314,0x1f18,0x0300,0x1f19,0x0300,0x1f18,0x0301,
123.1889 +  0x1f19,0x0301,0x03b7,0x0313,0x03b7,0x0314,0x1f20,0x0300,
123.1890 +  0x1f21,0x0300,0x1f20,0x0301,0x1f21,0x0301,0x1f20,0x0342,
123.1891 +  0x1f21,0x0342,0x0397,0x0313,0x0397,0x0314,0x1f28,0x0300,
123.1892 +  0x1f29,0x0300,0x1f28,0x0301,0x1f29,0x0301,0x1f28,0x0342,
123.1893 +  0x1f29,0x0342,0x03b9,0x0313,0x03b9,0x0314,0x1f30,0x0300,
123.1894 +  0x1f31,0x0300,0x1f30,0x0301,0x1f31,0x0301,0x1f30,0x0342,
123.1895 +  0x1f31,0x0342,0x0399,0x0313,0x0399,0x0314,0x1f38,0x0300,
123.1896 +  0x1f39,0x0300,0x1f38,0x0301,0x1f39,0x0301,0x1f38,0x0342,
123.1897 +  0x1f39,0x0342,0x03bf,0x0313,0x03bf,0x0314,0x1f40,0x0300,
123.1898 +  0x1f41,0x0300,0x1f40,0x0301,0x1f41,0x0301,0x039f,0x0313,
123.1899 +  0x039f,0x0314,0x1f48,0x0300,0x1f49,0x0300,0x1f48,0x0301,
123.1900 +  0x1f49,0x0301,0x03c5,0x0313,0x03c5,0x0314,0x1f50,0x0300,
123.1901 +  0x1f51,0x0300,0x1f50,0x0301,0x1f51,0x0301,0x1f50,0x0342,
123.1902 +  0x1f51,0x0342,0x03a5,0x0314,0x1f59,0x0300,0x1f59,0x0301,
123.1903 +  0x1f59,0x0342,0x03c9,0x0313,0x03c9,0x0314,0x1f60,0x0300,
123.1904 +  0x1f61,0x0300,0x1f60,0x0301,0x1f61,0x0301,0x1f60,0x0342,
123.1905 +  0x1f61,0x0342,0x03a9,0x0313,0x03a9,0x0314,0x1f68,0x0300,
123.1906 +  0x1f69,0x0300,0x1f68,0x0301,0x1f69,0x0301,0x1f68,0x0342,
123.1907 +  0x1f69,0x0342,0x03b1,0x0300,0x03ac,0x03b5,0x0300,0x03ad,
123.1908 +  0x03b7,0x0300,0x03ae,0x03b9,0x0300,0x03af,0x03bf,0x0300,
123.1909 +  0x03cc,0x03c5,0x0300,0x03cd,0x03c9,0x0300,0x03ce,0x1f00,
123.1910 +  0x0345,0x1f01,0x0345,0x1f02,0x0345,0x1f03,0x0345,0x1f04,
123.1911 +  0x0345,0x1f05,0x0345,0x1f06,0x0345,0x1f07,0x0345,0x1f08,
123.1912 +  0x0345,0x1f09,0x0345,0x1f0a,0x0345,0x1f0b,0x0345,0x1f0c,
123.1913 +  0x0345,0x1f0d,0x0345,0x1f0e,0x0345,0x1f0f,0x0345,0x1f20,
123.1914 +  0x0345,0x1f21,0x0345,0x1f22,0x0345,0x1f23,0x0345,0x1f24,
123.1915 +  0x0345,0x1f25,0x0345,0x1f26,0x0345,0x1f27,0x0345,0x1f28,
123.1916 +  0x0345,0x1f29,0x0345,0x1f2a,0x0345,0x1f2b,0x0345,0x1f2c,
123.1917 +  0x0345,0x1f2d,0x0345,0x1f2e,0x0345,0x1f2f,0x0345,0x1f60,
123.1918 +  0x0345,0x1f61,0x0345,0x1f62,0x0345,0x1f63,0x0345,0x1f64,
123.1919 +  0x0345,0x1f65,0x0345,0x1f66,0x0345,0x1f67,0x0345,0x1f68,
123.1920 +  0x0345,0x1f69,0x0345,0x1f6a,0x0345,0x1f6b,0x0345,0x1f6c,
123.1921 +  0x0345,0x1f6d,0x0345,0x1f6e,0x0345,0x1f6f,0x0345,0x03b1,
123.1922 +  0x0306,0x03b1,0x0304,0x1f70,0x0345,0x03b1,0x0345,0x03ac,
123.1923 +  0x0345,0x03b1,0x0342,0x1fb6,0x0345,0x0391,0x0306,0x0391,
123.1924 +  0x0304,0x0391,0x0300,0x0386,0x0391,0x0345,0x0020,0x0313,
123.1925 +  0x03b9,0x0020,0x0313,0x0020,0x0342,0x00a8,0x0342,0x1f74,
123.1926 +  0x0345,0x03b7,0x0345,0x03ae,0x0345,0x03b7,0x0342,0x1fc6,
123.1927 +  0x0345,0x0395,0x0300,0x0388,0x0397,0x0300,0x0389,0x0397,
123.1928 +  0x0345,0x1fbf,0x0300,0x1fbf,0x0301,0x1fbf,0x0342,0x03b9,
123.1929 +  0x0306,0x03b9,0x0304,0x03ca,0x0300,0x0390,0x03b9,0x0342,
123.1930 +  0x03ca,0x0342,0x0399,0x0306,0x0399,0x0304,0x0399,0x0300,
123.1931 +  0x038a,0x1ffe,0x0300,0x1ffe,0x0301,0x1ffe,0x0342,0x03c5,
123.1932 +  0x0306,0x03c5,0x0304,0x03cb,0x0300,0x03b0,0x03c1,0x0313,
123.1933 +  0x03c1,0x0314,0x03c5,0x0342,0x03cb,0x0342,0x03a5,0x0306,
123.1934 +  0x03a5,0x0304,0x03a5,0x0300,0x038e,0x03a1,0x0314,0x00a8,
123.1935 +  0x0300,0x0385,0x0060,0x1f7c,0x0345,0x03c9,0x0345,0x03ce,
123.1936 +  0x0345,0x03c9,0x0342,0x1ff6,0x0345,0x039f,0x0300,0x038c,
123.1937 +  0x03a9,0x0300,0x038f,0x03a9,0x0345,0x00b4,0x0020,0x0314,
123.1938 +  0x2002,0x2003,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,
123.1939 +  0x0020,0x0020,0x0020,0x2010,0x0020,0x0333,0x002e,0x002e,
123.1940 +  0x002e,0x002e,0x002e,0x002e,0x0020,0x2032,0x2032,0x2032,
123.1941 +  0x2032,0x2032,0x2035,0x2035,0x2035,0x2035,0x2035,0x0021,
123.1942 +  0x0021,0x0020,0x0305,0x003f,0x003f,0x003f,0x0021,0x0021,
123.1943 +  0x003f,0x2032,0x2032,0x2032,0x2032,0x0020,0x0030,0x0069,
123.1944 +  0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x002b,0x2212,
123.1945 +  0x003d,0x0028,0x0029,0x006e,0x0030,0x0031,0x0032,0x0033,
123.1946 +  0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x002b,0x2212,
123.1947 +  0x003d,0x0028,0x0029,0x0061,0x0065,0x006f,0x0078,0x0259,
123.1948 +  0x0052,0x0073,0x0061,0x002f,0x0063,0x0061,0x002f,0x0073,
123.1949 +  0x0043,0x00b0,0x0043,0x0063,0x002f,0x006f,0x0063,0x002f,
123.1950 +  0x0075,0x0190,0x00b0,0x0046,0x0067,0x0048,0x0048,0x0048,
123.1951 +  0x0068,0x0127,0x0049,0x0049,0x004c,0x006c,0x004e,0x004e,
123.1952 +  0x006f,0x0050,0x0051,0x0052,0x0052,0x0052,0x0053,0x004d,
123.1953 +  0x0054,0x0045,0x004c,0x0054,0x004d,0x005a,0x03a9,0x005a,
123.1954 +  0x004b,0x00c5,0x0042,0x0043,0x0065,0x0045,0x0046,0x004d,
123.1955 +  0x006f,0x05d0,0x05d1,0x05d2,0x05d3,0x0069,0x0046,0x0041,
123.1956 +  0x0058,0x03c0,0x03b3,0x0393,0x03a0,0x2211,0x0044,0x0064,
123.1957 +  0x0065,0x0069,0x006a,0x0031,0x2044,0x0033,0x0032,0x2044,
123.1958 +  0x0033,0x0031,0x2044,0x0035,0x0032,0x2044,0x0035,0x0033,
123.1959 +  0x2044,0x0035,0x0034,0x2044,0x0035,0x0031,0x2044,0x0036,
123.1960 +  0x0035,0x2044,0x0036,0x0031,0x2044,0x0038,0x0033,0x2044,
123.1961 +  0x0038,0x0035,0x2044,0x0038,0x0037,0x2044,0x0038,0x0031,
123.1962 +  0x2044,0x0049,0x0049,0x0049,0x0049,0x0049,0x0049,0x0049,
123.1963 +  0x0056,0x0056,0x0056,0x0049,0x0056,0x0049,0x0049,0x0056,
123.1964 +  0x0049,0x0049,0x0049,0x0049,0x0058,0x0058,0x0058,0x0049,
123.1965 +  0x0058,0x0049,0x0049,0x004c,0x0043,0x0044,0x004d,0x0069,
123.1966 +  0x0069,0x0069,0x0069,0x0069,0x0069,0x0069,0x0076,0x0076,
123.1967 +  0x0076,0x0069,0x0076,0x0069,0x0069,0x0076,0x0069,0x0069,
123.1968 +  0x0069,0x0069,0x0078,0x0078,0x0078,0x0069,0x0078,0x0069,
123.1969 +  0x0069,0x006c,0x0063,0x0064,0x006d,0x2190,0x0338,0x2192,
123.1970 +  0x0338,0x2194,0x0338,0x21d0,0x0338,0x21d4,0x0338,0x21d2,
123.1971 +  0x0338,0x2203,0x0338,0x2208,0x0338,0x220b,0x0338,0x2223,
123.1972 +  0x0338,0x2225,0x0338,0x222b,0x222b,0x222b,0x222b,0x222b,
123.1973 +  0x222e,0x222e,0x222e,0x222e,0x222e,0x223c,0x0338,0x2243,
123.1974 +  0x0338,0x2245,0x0338,0x2248,0x0338,0x003d,0x0338,0x2261,
123.1975 +  0x0338,0x224d,0x0338,0x003c,0x0338,0x003e,0x0338,0x2264,
123.1976 +  0x0338,0x2265,0x0338,0x2272,0x0338,0x2273,0x0338,0x2276,
123.1977 +  0x0338,0x2277,0x0338,0x227a,0x0338,0x227b,0x0338,0x2282,
123.1978 +  0x0338,0x2283,0x0338,0x2286,0x0338,0x2287,0x0338,0x22a2,
123.1979 +  0x0338,0x22a8,0x0338,0x22a9,0x0338,0x22ab,0x0338,0x227c,
123.1980 +  0x0338,0x227d,0x0338,0x2291,0x0338,0x2292,0x0338,0x22b2,
123.1981 +  0x0338,0x22b3,0x0338,0x22b4,0x0338,0x22b5,0x0338,0x3008,
123.1982 +  0x3009,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
123.1983 +  0x0038,0x0039,0x0031,0x0030,0x0031,0x0031,0x0031,0x0032,
123.1984 +  0x0031,0x0033,0x0031,0x0034,0x0031,0x0035,0x0031,0x0036,
123.1985 +  0x0031,0x0037,0x0031,0x0038,0x0031,0x0039,0x0032,0x0030,
123.1986 +  0x0028,0x0031,0x0029,0x0028,0x0032,0x0029,0x0028,0x0033,
123.1987 +  0x0029,0x0028,0x0034,0x0029,0x0028,0x0035,0x0029,0x0028,
123.1988 +  0x0036,0x0029,0x0028,0x0037,0x0029,0x0028,0x0038,0x0029,
123.1989 +  0x0028,0x0039,0x0029,0x0028,0x0031,0x0030,0x0029,0x0028,
123.1990 +  0x0031,0x0031,0x0029,0x0028,0x0031,0x0032,0x0029,0x0028,
123.1991 +  0x0031,0x0033,0x0029,0x0028,0x0031,0x0034,0x0029,0x0028,
123.1992 +  0x0031,0x0035,0x0029,0x0028,0x0031,0x0036,0x0029,0x0028,
123.1993 +  0x0031,0x0037,0x0029,0x0028,0x0031,0x0038,0x0029,0x0028,
123.1994 +  0x0031,0x0039,0x0029,0x0028,0x0032,0x0030,0x0029,0x0031,
123.1995 +  0x002e,0x0032,0x002e,0x0033,0x002e,0x0034,0x002e,0x0035,
123.1996 +  0x002e,0x0036,0x002e,0x0037,0x002e,0x0038,0x002e,0x0039,
123.1997 +  0x002e,0x0031,0x0030,0x002e,0x0031,0x0031,0x002e,0x0031,
123.1998 +  0x0032,0x002e,0x0031,0x0033,0x002e,0x0031,0x0034,0x002e,
123.1999 +  0x0031,0x0035,0x002e,0x0031,0x0036,0x002e,0x0031,0x0037,
123.2000 +  0x002e,0x0031,0x0038,0x002e,0x0031,0x0039,0x002e,0x0032,
123.2001 +  0x0030,0x002e,0x0028,0x0061,0x0029,0x0028,0x0062,0x0029,
123.2002 +  0x0028,0x0063,0x0029,0x0028,0x0064,0x0029,0x0028,0x0065,
123.2003 +  0x0029,0x0028,0x0066,0x0029,0x0028,0x0067,0x0029,0x0028,
123.2004 +  0x0068,0x0029,0x0028,0x0069,0x0029,0x0028,0x006a,0x0029,
123.2005 +  0x0028,0x006b,0x0029,0x0028,0x006c,0x0029,0x0028,0x006d,
123.2006 +  0x0029,0x0028,0x006e,0x0029,0x0028,0x006f,0x0029,0x0028,
123.2007 +  0x0070,0x0029,0x0028,0x0071,0x0029,0x0028,0x0072,0x0029,
123.2008 +  0x0028,0x0073,0x0029,0x0028,0x0074,0x0029,0x0028,0x0075,
123.2009 +  0x0029,0x0028,0x0076,0x0029,0x0028,0x0077,0x0029,0x0028,
123.2010 +  0x0078,0x0029,0x0028,0x0079,0x0029,0x0028,0x007a,0x0029,
123.2011 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2012 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2013 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2014 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2015 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2016 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2017 +  0x0077,0x0078,0x0079,0x007a,0x0030,0x222b,0x222b,0x222b,
123.2018 +  0x222b,0x003a,0x003a,0x003d,0x003d,0x003d,0x003d,0x003d,
123.2019 +  0x003d,0x2add,0x0338,0x2d61,0x6bcd,0x9f9f,0x4e00,0x4e28,
123.2020 +  0x4e36,0x4e3f,0x4e59,0x4e85,0x4e8c,0x4ea0,0x4eba,0x513f,
123.2021 +  0x5165,0x516b,0x5182,0x5196,0x51ab,0x51e0,0x51f5,0x5200,
123.2022 +  0x529b,0x52f9,0x5315,0x531a,0x5338,0x5341,0x535c,0x5369,
123.2023 +  0x5382,0x53b6,0x53c8,0x53e3,0x56d7,0x571f,0x58eb,0x5902,
123.2024 +  0x590a,0x5915,0x5927,0x5973,0x5b50,0x5b80,0x5bf8,0x5c0f,
123.2025 +  0x5c22,0x5c38,0x5c6e,0x5c71,0x5ddb,0x5de5,0x5df1,0x5dfe,
123.2026 +  0x5e72,0x5e7a,0x5e7f,0x5ef4,0x5efe,0x5f0b,0x5f13,0x5f50,
123.2027 +  0x5f61,0x5f73,0x5fc3,0x6208,0x6236,0x624b,0x652f,0x6534,
123.2028 +  0x6587,0x6597,0x65a4,0x65b9,0x65e0,0x65e5,0x66f0,0x6708,
123.2029 +  0x6728,0x6b20,0x6b62,0x6b79,0x6bb3,0x6bcb,0x6bd4,0x6bdb,
123.2030 +  0x6c0f,0x6c14,0x6c34,0x706b,0x722a,0x7236,0x723b,0x723f,
123.2031 +  0x7247,0x7259,0x725b,0x72ac,0x7384,0x7389,0x74dc,0x74e6,
123.2032 +  0x7518,0x751f,0x7528,0x7530,0x758b,0x7592,0x7676,0x767d,
123.2033 +  0x76ae,0x76bf,0x76ee,0x77db,0x77e2,0x77f3,0x793a,0x79b8,
123.2034 +  0x79be,0x7a74,0x7acb,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f51,
123.2035 +  0x7f8a,0x7fbd,0x8001,0x800c,0x8012,0x8033,0x807f,0x8089,
123.2036 +  0x81e3,0x81ea,0x81f3,0x81fc,0x820c,0x821b,0x821f,0x826e,
123.2037 +  0x8272,0x8278,0x864d,0x866b,0x8840,0x884c,0x8863,0x897e,
123.2038 +  0x898b,0x89d2,0x8a00,0x8c37,0x8c46,0x8c55,0x8c78,0x8c9d,
123.2039 +  0x8d64,0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fb5,
123.2040 +  0x9091,0x9149,0x91c6,0x91cc,0x91d1,0x9577,0x9580,0x961c,
123.2041 +  0x96b6,0x96b9,0x96e8,0x9751,0x975e,0x9762,0x9769,0x97cb,
123.2042 +  0x97ed,0x97f3,0x9801,0x98a8,0x98db,0x98df,0x9996,0x9999,
123.2043 +  0x99ac,0x9aa8,0x9ad8,0x9adf,0x9b25,0x9b2f,0x9b32,0x9b3c,
123.2044 +  0x9b5a,0x9ce5,0x9e75,0x9e7f,0x9ea5,0x9ebb,0x9ec3,0x9ecd,
123.2045 +  0x9ed1,0x9ef9,0x9efd,0x9f0e,0x9f13,0x9f20,0x9f3b,0x9f4a,
123.2046 +  0x9f52,0x9f8d,0x9f9c,0x9fa0,0x0020,0x3012,0x5341,0x5344,
123.2047 +  0x5345,0x304b,0x3099,0x304d,0x3099,0x304f,0x3099,0x3051,
123.2048 +  0x3099,0x3053,0x3099,0x3055,0x3099,0x3057,0x3099,0x3059,
123.2049 +  0x3099,0x305b,0x3099,0x305d,0x3099,0x305f,0x3099,0x3061,
123.2050 +  0x3099,0x3064,0x3099,0x3066,0x3099,0x3068,0x3099,0x306f,
123.2051 +  0x3099,0x306f,0x309a,0x3072,0x3099,0x3072,0x309a,0x3075,
123.2052 +  0x3099,0x3075,0x309a,0x3078,0x3099,0x3078,0x309a,0x307b,
123.2053 +  0x3099,0x307b,0x309a,0x3046,0x3099,0x0020,0x3099,0x0020,
123.2054 +  0x309a,0x309d,0x3099,0x3088,0x308a,0x30ab,0x3099,0x30ad,
123.2055 +  0x3099,0x30af,0x3099,0x30b1,0x3099,0x30b3,0x3099,0x30b5,
123.2056 +  0x3099,0x30b7,0x3099,0x30b9,0x3099,0x30bb,0x3099,0x30bd,
123.2057 +  0x3099,0x30bf,0x3099,0x30c1,0x3099,0x30c4,0x3099,0x30c6,
123.2058 +  0x3099,0x30c8,0x3099,0x30cf,0x3099,0x30cf,0x309a,0x30d2,
123.2059 +  0x3099,0x30d2,0x309a,0x30d5,0x3099,0x30d5,0x309a,0x30d8,
123.2060 +  0x3099,0x30d8,0x309a,0x30db,0x3099,0x30db,0x309a,0x30a6,
123.2061 +  0x3099,0x30ef,0x3099,0x30f0,0x3099,0x30f1,0x3099,0x30f2,
123.2062 +  0x3099,0x30fd,0x3099,0x30b3,0x30c8,0x1100,0x1101,0x11aa,
123.2063 +  0x1102,0x11ac,0x11ad,0x1103,0x1104,0x1105,0x11b0,0x11b1,
123.2064 +  0x11b2,0x11b3,0x11b4,0x11b5,0x111a,0x1106,0x1107,0x1108,
123.2065 +  0x1121,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f,
123.2066 +  0x1110,0x1111,0x1112,0x1161,0x1162,0x1163,0x1164,0x1165,
123.2067 +  0x1166,0x1167,0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,
123.2068 +  0x116e,0x116f,0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,
123.2069 +  0x1160,0x1114,0x1115,0x11c7,0x11c8,0x11cc,0x11ce,0x11d3,
123.2070 +  0x11d7,0x11d9,0x111c,0x11dd,0x11df,0x111d,0x111e,0x1120,
123.2071 +  0x1122,0x1123,0x1127,0x1129,0x112b,0x112c,0x112d,0x112e,
123.2072 +  0x112f,0x1132,0x1136,0x1140,0x1147,0x114c,0x11f1,0x11f2,
123.2073 +  0x1157,0x1158,0x1159,0x1184,0x1185,0x1188,0x1191,0x1192,
123.2074 +  0x1194,0x119e,0x11a1,0x4e00,0x4e8c,0x4e09,0x56db,0x4e0a,
123.2075 +  0x4e2d,0x4e0b,0x7532,0x4e59,0x4e19,0x4e01,0x5929,0x5730,
123.2076 +  0x4eba,0x0028,0x1100,0x0029,0x0028,0x1102,0x0029,0x0028,
123.2077 +  0x1103,0x0029,0x0028,0x1105,0x0029,0x0028,0x1106,0x0029,
123.2078 +  0x0028,0x1107,0x0029,0x0028,0x1109,0x0029,0x0028,0x110b,
123.2079 +  0x0029,0x0028,0x110c,0x0029,0x0028,0x110e,0x0029,0x0028,
123.2080 +  0x110f,0x0029,0x0028,0x1110,0x0029,0x0028,0x1111,0x0029,
123.2081 +  0x0028,0x1112,0x0029,0x0028,0x1100,0x1161,0x0029,0x0028,
123.2082 +  0x1102,0x1161,0x0029,0x0028,0x1103,0x1161,0x0029,0x0028,
123.2083 +  0x1105,0x1161,0x0029,0x0028,0x1106,0x1161,0x0029,0x0028,
123.2084 +  0x1107,0x1161,0x0029,0x0028,0x1109,0x1161,0x0029,0x0028,
123.2085 +  0x110b,0x1161,0x0029,0x0028,0x110c,0x1161,0x0029,0x0028,
123.2086 +  0x110e,0x1161,0x0029,0x0028,0x110f,0x1161,0x0029,0x0028,
123.2087 +  0x1110,0x1161,0x0029,0x0028,0x1111,0x1161,0x0029,0x0028,
123.2088 +  0x1112,0x1161,0x0029,0x0028,0x110c,0x116e,0x0029,0x0028,
123.2089 +  0x110b,0x1169,0x110c,0x1165,0x11ab,0x0029,0x0028,0x110b,
123.2090 +  0x1169,0x1112,0x116e,0x0029,0x0028,0x4e00,0x0029,0x0028,
123.2091 +  0x4e8c,0x0029,0x0028,0x4e09,0x0029,0x0028,0x56db,0x0029,
123.2092 +  0x0028,0x4e94,0x0029,0x0028,0x516d,0x0029,0x0028,0x4e03,
123.2093 +  0x0029,0x0028,0x516b,0x0029,0x0028,0x4e5d,0x0029,0x0028,
123.2094 +  0x5341,0x0029,0x0028,0x6708,0x0029,0x0028,0x706b,0x0029,
123.2095 +  0x0028,0x6c34,0x0029,0x0028,0x6728,0x0029,0x0028,0x91d1,
123.2096 +  0x0029,0x0028,0x571f,0x0029,0x0028,0x65e5,0x0029,0x0028,
123.2097 +  0x682a,0x0029,0x0028,0x6709,0x0029,0x0028,0x793e,0x0029,
123.2098 +  0x0028,0x540d,0x0029,0x0028,0x7279,0x0029,0x0028,0x8ca1,
123.2099 +  0x0029,0x0028,0x795d,0x0029,0x0028,0x52b4,0x0029,0x0028,
123.2100 +  0x4ee3,0x0029,0x0028,0x547c,0x0029,0x0028,0x5b66,0x0029,
123.2101 +  0x0028,0x76e3,0x0029,0x0028,0x4f01,0x0029,0x0028,0x8cc7,
123.2102 +  0x0029,0x0028,0x5354,0x0029,0x0028,0x796d,0x0029,0x0028,
123.2103 +  0x4f11,0x0029,0x0028,0x81ea,0x0029,0x0028,0x81f3,0x0029,
123.2104 +  0x0050,0x0054,0x0045,0x0032,0x0031,0x0032,0x0032,0x0032,
123.2105 +  0x0033,0x0032,0x0034,0x0032,0x0035,0x0032,0x0036,0x0032,
123.2106 +  0x0037,0x0032,0x0038,0x0032,0x0039,0x0033,0x0030,0x0033,
123.2107 +  0x0031,0x0033,0x0032,0x0033,0x0033,0x0033,0x0034,0x0033,
123.2108 +  0x0035,0x1100,0x1102,0x1103,0x1105,0x1106,0x1107,0x1109,
123.2109 +  0x110b,0x110c,0x110e,0x110f,0x1110,0x1111,0x1112,0x1100,
123.2110 +  0x1161,0x1102,0x1161,0x1103,0x1161,0x1105,0x1161,0x1106,
123.2111 +  0x1161,0x1107,0x1161,0x1109,0x1161,0x110b,0x1161,0x110c,
123.2112 +  0x1161,0x110e,0x1161,0x110f,0x1161,0x1110,0x1161,0x1111,
123.2113 +  0x1161,0x1112,0x1161,0x110e,0x1161,0x11b7,0x1100,0x1169,
123.2114 +  0x110c,0x116e,0x110b,0x1174,0x110b,0x116e,0x4e00,0x4e8c,
123.2115 +  0x4e09,0x56db,0x4e94,0x516d,0x4e03,0x516b,0x4e5d,0x5341,
123.2116 +  0x6708,0x706b,0x6c34,0x6728,0x91d1,0x571f,0x65e5,0x682a,
123.2117 +  0x6709,0x793e,0x540d,0x7279,0x8ca1,0x795d,0x52b4,0x79d8,
123.2118 +  0x7537,0x5973,0x9069,0x512a,0x5370,0x6ce8,0x9805,0x4f11,
123.2119 +  0x5199,0x6b63,0x4e0a,0x4e2d,0x4e0b,0x5de6,0x53f3,0x533b,
123.2120 +  0x5b97,0x5b66,0x76e3,0x4f01,0x8cc7,0x5354,0x591c,0x0033,
123.2121 +  0x0036,0x0033,0x0037,0x0033,0x0038,0x0033,0x0039,0x0034,
123.2122 +  0x0030,0x0034,0x0031,0x0034,0x0032,0x0034,0x0033,0x0034,
123.2123 +  0x0034,0x0034,0x0035,0x0034,0x0036,0x0034,0x0037,0x0034,
123.2124 +  0x0038,0x0034,0x0039,0x0035,0x0030,0x0031,0x6708,0x0032,
123.2125 +  0x6708,0x0033,0x6708,0x0034,0x6708,0x0035,0x6708,0x0036,
123.2126 +  0x6708,0x0037,0x6708,0x0038,0x6708,0x0039,0x6708,0x0031,
123.2127 +  0x0030,0x6708,0x0031,0x0031,0x6708,0x0031,0x0032,0x6708,
123.2128 +  0x0048,0x0067,0x0065,0x0072,0x0067,0x0065,0x0056,0x004c,
123.2129 +  0x0054,0x0044,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,
123.2130 +  0x30ad,0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,
123.2131 +  0x30bd,0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,
123.2132 +  0x30cc,0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,
123.2133 +  0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,
123.2134 +  0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f0,0x30f1,
123.2135 +  0x30f2,0x30a2,0x30d1,0x30fc,0x30c8,0x30a2,0x30eb,0x30d5,
123.2136 +  0x30a1,0x30a2,0x30f3,0x30da,0x30a2,0x30a2,0x30fc,0x30eb,
123.2137 +  0x30a4,0x30cb,0x30f3,0x30b0,0x30a4,0x30f3,0x30c1,0x30a6,
123.2138 +  0x30a9,0x30f3,0x30a8,0x30b9,0x30af,0x30fc,0x30c9,0x30a8,
123.2139 +  0x30fc,0x30ab,0x30fc,0x30aa,0x30f3,0x30b9,0x30aa,0x30fc,
123.2140 +  0x30e0,0x30ab,0x30a4,0x30ea,0x30ab,0x30e9,0x30c3,0x30c8,
123.2141 +  0x30ab,0x30ed,0x30ea,0x30fc,0x30ac,0x30ed,0x30f3,0x30ac,
123.2142 +  0x30f3,0x30de,0x30ae,0x30ac,0x30ae,0x30cb,0x30fc,0x30ad,
123.2143 +  0x30e5,0x30ea,0x30fc,0x30ae,0x30eb,0x30c0,0x30fc,0x30ad,
123.2144 +  0x30ed,0x30ad,0x30ed,0x30b0,0x30e9,0x30e0,0x30ad,0x30ed,
123.2145 +  0x30e1,0x30fc,0x30c8,0x30eb,0x30ad,0x30ed,0x30ef,0x30c3,
123.2146 +  0x30c8,0x30b0,0x30e9,0x30e0,0x30b0,0x30e9,0x30e0,0x30c8,
123.2147 +  0x30f3,0x30af,0x30eb,0x30bc,0x30a4,0x30ed,0x30af,0x30ed,
123.2148 +  0x30fc,0x30cd,0x30b1,0x30fc,0x30b9,0x30b3,0x30eb,0x30ca,
123.2149 +  0x30b3,0x30fc,0x30dd,0x30b5,0x30a4,0x30af,0x30eb,0x30b5,
123.2150 +  0x30f3,0x30c1,0x30fc,0x30e0,0x30b7,0x30ea,0x30f3,0x30b0,
123.2151 +  0x30bb,0x30f3,0x30c1,0x30bb,0x30f3,0x30c8,0x30c0,0x30fc,
123.2152 +  0x30b9,0x30c7,0x30b7,0x30c9,0x30eb,0x30c8,0x30f3,0x30ca,
123.2153 +  0x30ce,0x30ce,0x30c3,0x30c8,0x30cf,0x30a4,0x30c4,0x30d1,
123.2154 +  0x30fc,0x30bb,0x30f3,0x30c8,0x30d1,0x30fc,0x30c4,0x30d0,
123.2155 +  0x30fc,0x30ec,0x30eb,0x30d4,0x30a2,0x30b9,0x30c8,0x30eb,
123.2156 +  0x30d4,0x30af,0x30eb,0x30d4,0x30b3,0x30d3,0x30eb,0x30d5,
123.2157 +  0x30a1,0x30e9,0x30c3,0x30c9,0x30d5,0x30a3,0x30fc,0x30c8,
123.2158 +  0x30d6,0x30c3,0x30b7,0x30a7,0x30eb,0x30d5,0x30e9,0x30f3,
123.2159 +  0x30d8,0x30af,0x30bf,0x30fc,0x30eb,0x30da,0x30bd,0x30da,
123.2160 +  0x30cb,0x30d2,0x30d8,0x30eb,0x30c4,0x30da,0x30f3,0x30b9,
123.2161 +  0x30da,0x30fc,0x30b8,0x30d9,0x30fc,0x30bf,0x30dd,0x30a4,
123.2162 +  0x30f3,0x30c8,0x30dc,0x30eb,0x30c8,0x30db,0x30f3,0x30dd,
123.2163 +  0x30f3,0x30c9,0x30db,0x30fc,0x30eb,0x30db,0x30fc,0x30f3,
123.2164 +  0x30de,0x30a4,0x30af,0x30ed,0x30de,0x30a4,0x30eb,0x30de,
123.2165 +  0x30c3,0x30cf,0x30de,0x30eb,0x30af,0x30de,0x30f3,0x30b7,
123.2166 +  0x30e7,0x30f3,0x30df,0x30af,0x30ed,0x30f3,0x30df,0x30ea,
123.2167 +  0x30df,0x30ea,0x30d0,0x30fc,0x30eb,0x30e1,0x30ac,0x30e1,
123.2168 +  0x30ac,0x30c8,0x30f3,0x30e1,0x30fc,0x30c8,0x30eb,0x30e4,
123.2169 +  0x30fc,0x30c9,0x30e4,0x30fc,0x30eb,0x30e6,0x30a2,0x30f3,
123.2170 +  0x30ea,0x30c3,0x30c8,0x30eb,0x30ea,0x30e9,0x30eb,0x30d4,
123.2171 +  0x30fc,0x30eb,0x30fc,0x30d6,0x30eb,0x30ec,0x30e0,0x30ec,
123.2172 +  0x30f3,0x30c8,0x30b2,0x30f3,0x30ef,0x30c3,0x30c8,0x0030,
123.2173 +  0x70b9,0x0031,0x70b9,0x0032,0x70b9,0x0033,0x70b9,0x0034,
123.2174 +  0x70b9,0x0035,0x70b9,0x0036,0x70b9,0x0037,0x70b9,0x0038,
123.2175 +  0x70b9,0x0039,0x70b9,0x0031,0x0030,0x70b9,0x0031,0x0031,
123.2176 +  0x70b9,0x0031,0x0032,0x70b9,0x0031,0x0033,0x70b9,0x0031,
123.2177 +  0x0034,0x70b9,0x0031,0x0035,0x70b9,0x0031,0x0036,0x70b9,
123.2178 +  0x0031,0x0037,0x70b9,0x0031,0x0038,0x70b9,0x0031,0x0039,
123.2179 +  0x70b9,0x0032,0x0030,0x70b9,0x0032,0x0031,0x70b9,0x0032,
123.2180 +  0x0032,0x70b9,0x0032,0x0033,0x70b9,0x0032,0x0034,0x70b9,
123.2181 +  0x0068,0x0050,0x0061,0x0064,0x0061,0x0041,0x0055,0x0062,
123.2182 +  0x0061,0x0072,0x006f,0x0056,0x0070,0x0063,0x0064,0x006d,
123.2183 +  0x0064,0x006d,0x00b2,0x0064,0x006d,0x00b3,0x0049,0x0055,
123.2184 +  0x5e73,0x6210,0x662d,0x548c,0x5927,0x6b63,0x660e,0x6cbb,
123.2185 +  0x682a,0x5f0f,0x4f1a,0x793e,0x0070,0x0041,0x006e,0x0041,
123.2186 +  0x03bc,0x0041,0x006d,0x0041,0x006b,0x0041,0x004b,0x0042,
123.2187 +  0x004d,0x0042,0x0047,0x0042,0x0063,0x0061,0x006c,0x006b,
123.2188 +  0x0063,0x0061,0x006c,0x0070,0x0046,0x006e,0x0046,0x03bc,
123.2189 +  0x0046,0x03bc,0x0067,0x006d,0x0067,0x006b,0x0067,0x0048,
123.2190 +  0x007a,0x006b,0x0048,0x007a,0x004d,0x0048,0x007a,0x0047,
123.2191 +  0x0048,0x007a,0x0054,0x0048,0x007a,0x03bc,0x2113,0x006d,
123.2192 +  0x2113,0x0064,0x2113,0x006b,0x2113,0x0066,0x006d,0x006e,
123.2193 +  0x006d,0x03bc,0x006d,0x006d,0x006d,0x0063,0x006d,0x006b,
123.2194 +  0x006d,0x006d,0x006d,0x00b2,0x0063,0x006d,0x00b2,0x006d,
123.2195 +  0x00b2,0x006b,0x006d,0x00b2,0x006d,0x006d,0x00b3,0x0063,
123.2196 +  0x006d,0x00b3,0x006d,0x00b3,0x006b,0x006d,0x00b3,0x006d,
123.2197 +  0x2215,0x0073,0x006d,0x2215,0x0073,0x00b2,0x0050,0x0061,
123.2198 +  0x006b,0x0050,0x0061,0x004d,0x0050,0x0061,0x0047,0x0050,
123.2199 +  0x0061,0x0072,0x0061,0x0064,0x0072,0x0061,0x0064,0x2215,
123.2200 +  0x0073,0x0072,0x0061,0x0064,0x2215,0x0073,0x00b2,0x0070,
123.2201 +  0x0073,0x006e,0x0073,0x03bc,0x0073,0x006d,0x0073,0x0070,
123.2202 +  0x0056,0x006e,0x0056,0x03bc,0x0056,0x006d,0x0056,0x006b,
123.2203 +  0x0056,0x004d,0x0056,0x0070,0x0057,0x006e,0x0057,0x03bc,
123.2204 +  0x0057,0x006d,0x0057,0x006b,0x0057,0x004d,0x0057,0x006b,
123.2205 +  0x03a9,0x004d,0x03a9,0x0061,0x002e,0x006d,0x002e,0x0042,
123.2206 +  0x0071,0x0063,0x0063,0x0063,0x0064,0x0043,0x2215,0x006b,
123.2207 +  0x0067,0x0043,0x006f,0x002e,0x0064,0x0042,0x0047,0x0079,
123.2208 +  0x0068,0x0061,0x0048,0x0050,0x0069,0x006e,0x004b,0x004b,
123.2209 +  0x004b,0x004d,0x006b,0x0074,0x006c,0x006d,0x006c,0x006e,
123.2210 +  0x006c,0x006f,0x0067,0x006c,0x0078,0x006d,0x0062,0x006d,
123.2211 +  0x0069,0x006c,0x006d,0x006f,0x006c,0x0050,0x0048,0x0070,
123.2212 +  0x002e,0x006d,0x002e,0x0050,0x0050,0x004d,0x0050,0x0052,
123.2213 +  0x0073,0x0072,0x0053,0x0076,0x0057,0x0062,0x0056,0x2215,
123.2214 +  0x006d,0x0041,0x2215,0x006d,0x0031,0x65e5,0x0032,0x65e5,
123.2215 +  0x0033,0x65e5,0x0034,0x65e5,0x0035,0x65e5,0x0036,0x65e5,
123.2216 +  0x0037,0x65e5,0x0038,0x65e5,0x0039,0x65e5,0x0031,0x0030,
123.2217 +  0x65e5,0x0031,0x0031,0x65e5,0x0031,0x0032,0x65e5,0x0031,
123.2218 +  0x0033,0x65e5,0x0031,0x0034,0x65e5,0x0031,0x0035,0x65e5,
123.2219 +  0x0031,0x0036,0x65e5,0x0031,0x0037,0x65e5,0x0031,0x0038,
123.2220 +  0x65e5,0x0031,0x0039,0x65e5,0x0032,0x0030,0x65e5,0x0032,
123.2221 +  0x0031,0x65e5,0x0032,0x0032,0x65e5,0x0032,0x0033,0x65e5,
123.2222 +  0x0032,0x0034,0x65e5,0x0032,0x0035,0x65e5,0x0032,0x0036,
123.2223 +  0x65e5,0x0032,0x0037,0x65e5,0x0032,0x0038,0x65e5,0x0032,
123.2224 +  0x0039,0x65e5,0x0033,0x0030,0x65e5,0x0033,0x0031,0x65e5,
123.2225 +  0x0067,0x0061,0x006c
123.2226 +};
123.2227 +
123.2228 +
123.2229 +#define UCS4_BMPCJKMIN 0xf900
123.2230 +#define UCS4_BMPCJKMAX 0xface
123.2231 +
123.2232 +	/* CJK Compatibility - 0 means hole (no decomposition) */
123.2233 +static const unsigned short ucs4_bmpcjk1decomptab[463] = {
123.2234 +  0x8c48,0x66f4,0x8eca,0x8cc8,0x6ed1,0x4e32,0x53e5,0x9f9c,
123.2235 +  0x9f9c,0x5951,0x91d1,0x5587,0x5948,0x61f6,0x7669,0x7f85,
123.2236 +  0x863f,0x87ba,0x88f8,0x908f,0x6a02,0x6d1b,0x70d9,0x73de,
123.2237 +  0x843d,0x916a,0x99f1,0x4e82,0x5375,0x6b04,0x721b,0x862d,
123.2238 +  0x9e1e,0x5d50,0x6feb,0x85cd,0x8964,0x62c9,0x81d8,0x881f,
123.2239 +  0x5eca,0x6717,0x6d6a,0x72fc,0x90ce,0x4f86,0x51b7,0x52de,
123.2240 +  0x64c4,0x6ad3,0x7210,0x76e7,0x8001,0x8606,0x865c,0x8def,
123.2241 +  0x9732,0x9b6f,0x9dfa,0x788c,0x797f,0x7da0,0x83c9,0x9304,
123.2242 +  0x9e7f,0x8ad6,0x58df,0x5f04,0x7c60,0x807e,0x7262,0x78ca,
123.2243 +  0x8cc2,0x96f7,0x58d8,0x5c62,0x6a13,0x6dda,0x6f0f,0x7d2f,
123.2244 +  0x7e37,0x964b,0x52d2,0x808b,0x51dc,0x51cc,0x7a1c,0x7dbe,
123.2245 +  0x83f1,0x9675,0x8b80,0x62cf,0x6a02,0x8afe,0x4e39,0x5be7,
123.2246 +  0x6012,0x7387,0x7570,0x5317,0x78fb,0x4fbf,0x5fa9,0x4e0d,
123.2247 +  0x6ccc,0x6578,0x7d22,0x53c3,0x585e,0x7701,0x8449,0x8aaa,
123.2248 +  0x6bba,0x8fb0,0x6c88,0x62fe,0x82e5,0x63a0,0x7565,0x4eae,
123.2249 +  0x5169,0x51c9,0x6881,0x7ce7,0x826f,0x8ad2,0x91cf,0x52f5,
123.2250 +  0x5442,0x5973,0x5eec,0x65c5,0x6ffe,0x792a,0x95ad,0x9a6a,
123.2251 +  0x9e97,0x9ece,0x529b,0x66c6,0x6b77,0x8f62,0x5e74,0x6190,
123.2252 +  0x6200,0x649a,0x6f23,0x7149,0x7489,0x79ca,0x7df4,0x806f,
123.2253 +  0x8f26,0x84ee,0x9023,0x934a,0x5217,0x52a3,0x54bd,0x70c8,
123.2254 +  0x88c2,0x8aaa,0x5ec9,0x5ff5,0x637b,0x6bae,0x7c3e,0x7375,
123.2255 +  0x4ee4,0x56f9,0x5be7,0x5dba,0x601c,0x73b2,0x7469,0x7f9a,
123.2256 +  0x8046,0x9234,0x96f6,0x9748,0x9818,0x4f8b,0x79ae,0x91b4,
123.2257 +  0x96b8,0x60e1,0x4e86,0x50da,0x5bee,0x5c3f,0x6599,0x6a02,
123.2258 +  0x71ce,0x7642,0x84fc,0x907c,0x9f8d,0x6688,0x962e,0x5289,
123.2259 +  0x677b,0x67f3,0x6d41,0x6e9c,0x7409,0x7559,0x786b,0x7d10,
123.2260 +  0x985e,0x516d,0x622e,0x9678,0x502b,0x5d19,0x6dea,0x8f2a,
123.2261 +  0x5f8b,0x6144,0x6817,0x7387,0x9686,0x5229,0x540f,0x5c65,
123.2262 +  0x6613,0x674e,0x68a8,0x6ce5,0x7406,0x75e2,0x7f79,0x88cf,
123.2263 +  0x88e1,0x91cc,0x96e2,0x533f,0x6eba,0x541d,0x71d0,0x7498,
123.2264 +  0x85fa,0x96a3,0x9c57,0x9e9f,0x6797,0x6dcb,0x81e8,0x7acb,
123.2265 +  0x7b20,0x7c92,0x72c0,0x7099,0x8b58,0x4ec0,0x8336,0x523a,
123.2266 +  0x5207,0x5ea6,0x62d3,0x7cd6,0x5b85,0x6d1e,0x66b4,0x8f3b,
123.2267 +  0x884c,0x964d,0x898b,0x5ed3,0x5140,0x55c0,0x0000,0x0000,
123.2268 +  0x585a,0x0000,0x6674,0x0000,0x0000,0x51de,0x732a,0x76ca,
123.2269 +  0x793c,0x795e,0x7965,0x798f,0x9756,0x7cbe,0x7fbd,0x0000,
123.2270 +  0x8612,0x0000,0x8af8,0x0000,0x0000,0x9038,0x90fd,0x0000,
123.2271 +  0x0000,0x0000,0x98ef,0x98fc,0x9928,0x9db4,0x0000,0x0000,
123.2272 +  0x4fae,0x50e7,0x514d,0x52c9,0x52e4,0x5351,0x559d,0x5606,
123.2273 +  0x5668,0x5840,0x58a8,0x5c64,0x5c6e,0x6094,0x6168,0x618e,
123.2274 +  0x61f2,0x654f,0x65e2,0x6691,0x6885,0x6d77,0x6e1a,0x6f22,
123.2275 +  0x716e,0x722b,0x7422,0x7891,0x793e,0x7949,0x7948,0x7950,
123.2276 +  0x7956,0x795d,0x798d,0x798e,0x7a40,0x7a81,0x7bc0,0x7df4,
123.2277 +  0x7e09,0x7e41,0x7f72,0x8005,0x81ed,0x8279,0x8279,0x8457,
123.2278 +  0x8910,0x8996,0x8b01,0x8b39,0x8cd3,0x8d08,0x8fb6,0x9038,
123.2279 +  0x96e3,0x97ff,0x983b,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2280 +  0x4e26,0x51b5,0x5168,0x4f80,0x5145,0x5180,0x52c7,0x52fa,
123.2281 +  0x559d,0x5555,0x5599,0x55e2,0x585a,0x58b3,0x5944,0x5954,
123.2282 +  0x5a62,0x5b28,0x5ed2,0x5ed9,0x5f69,0x5fad,0x60d8,0x614e,
123.2283 +  0x6108,0x618e,0x6160,0x61f2,0x6234,0x63c4,0x641c,0x6452,
123.2284 +  0x6556,0x6674,0x6717,0x671b,0x6756,0x6b79,0x6bba,0x6d41,
123.2285 +  0x6edb,0x6ecb,0x6f22,0x701e,0x716e,0x77a7,0x7235,0x72af,
123.2286 +  0x732a,0x7471,0x7506,0x753b,0x761d,0x761f,0x76ca,0x76db,
123.2287 +  0x76f4,0x774a,0x7740,0x78cc,0x7ab1,0x7bc0,0x7c7b,0x7d5b,
123.2288 +  0x7df4,0x7f3e,0x8005,0x8352,0x83ef,0x8779,0x8941,0x8986,
123.2289 +  0x8996,0x8abf,0x8af8,0x8acb,0x8b01,0x8afe,0x8aed,0x8b39,
123.2290 +  0x8b8a,0x8d08,0x8f38,0x9072,0x9199,0x9276,0x967c,0x96e3,
123.2291 +  0x9756,0x97db,0x97ff,0x980b,0x983b,0x9b12,0x9f9c
123.2292 +};
123.2293 +
123.2294 +
123.2295 +#define UCS4_BMPCJK2MIN 0xfacf
123.2296 +#define UCS4_BMPCJK2MAX 0xfad9
123.2297 +
123.2298 +
123.2299 +	/* CJK Compatibility - some values not in BMP */
123.2300 +static const unsigned long ucs4_bmpcjk2decomptab[11] = {
123.2301 +  0x2284a,0x22844,0x233d5, 0x3b9d, 0x4018, 0x4039,
123.2302 +  0x25249,0x25cd0,0x27ed3, 0x9f43, 0x9f8e
123.2303 +};
123.2304 +
123.2305 +
123.2306 +#define UCS4_BMPHIMIN 0xfb00
123.2307 +#define UCS4_BMPHIMAX 0xfefc
123.2308 +#define UCS4_BMPHIIXMASK 0x7ff
123.2309 +#define UCS4_BMPHISIZEMASK 0xf800
123.2310 +#define UCS4_BMPHISIZESHIFT 11
123.2311 +
123.2312 +	/* BMP hi decomposition indices - ssss siii iiii iiii */
123.2313 +static unsigned short ucs4_dbmphiixtab[1021] = {
123.2314 +0x0800,0x0802,0x0804,0x1006,0x1009,0x080c,0x080e,0x0000,
123.2315 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2316 +0x0000,0x0000,0x0000,0x0810,0x0812,0x0814,0x0816,0x0818,
123.2317 +0x0000,0x0000,0x0000,0x0000,0x0000,0x081a,0x0000,0x081c,
123.2318 +0x001e,0x001f,0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,
123.2319 +0x0026,0x0027,0x0828,0x082a,0x082c,0x082e,0x0830,0x0832,
123.2320 +0x0834,0x0836,0x0838,0x083a,0x083c,0x083e,0x0840,0x0000,
123.2321 +0x0842,0x0844,0x0846,0x0848,0x084a,0x0000,0x084c,0x0000,
123.2322 +0x084e,0x0850,0x0000,0x0852,0x0854,0x0000,0x0856,0x0858,
123.2323 +0x085a,0x085c,0x085e,0x0860,0x0862,0x0864,0x0866,0x0868,
123.2324 +0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,
123.2325 +0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,
123.2326 +0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,0x0080,0x0081,
123.2327 +0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,0x0088,0x0089,
123.2328 +0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,0x0090,0x0091,
123.2329 +0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,0x0098,0x0099,
123.2330 +0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,0x00a0,0x00a1,
123.2331 +0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,0x00a8,0x00a9,
123.2332 +0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,0x00b0,0x00b1,
123.2333 +0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,0x00b8,0x00b9,
123.2334 +0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,0x00c0,0x00c1,
123.2335 +0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,0x00c8,0x00c9,
123.2336 +0x00ca,0x00cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2337 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2338 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2339 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2340 +0x0000,0x0000,0x0000,0x00cc,0x00cd,0x00ce,0x00cf,0x00d0,
123.2341 +0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,0x00d8,
123.2342 +0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,0x00e0,
123.2343 +0x00e1,0x00e2,0x08e3,0x08e5,0x08e7,0x08e9,0x08eb,0x08ed,
123.2344 +0x08ef,0x08f1,0x08f3,0x08f5,0x08f7,0x08f9,0x08fb,0x08fd,
123.2345 +0x08ff,0x0901,0x0903,0x0905,0x0107,0x0108,0x0109,0x010a,
123.2346 +0x090b,0x090d,0x090f,0x0911,0x0913,0x0915,0x0917,0x0919,
123.2347 +0x091b,0x091d,0x091f,0x0921,0x0923,0x0925,0x0927,0x0929,
123.2348 +0x092b,0x092d,0x092f,0x0931,0x0933,0x0935,0x0937,0x0939,
123.2349 +0x093b,0x093d,0x093f,0x0941,0x0943,0x0945,0x0947,0x0949,
123.2350 +0x094b,0x094d,0x094f,0x0951,0x0953,0x0955,0x0957,0x0959,
123.2351 +0x095b,0x095d,0x095f,0x0961,0x0963,0x0965,0x0967,0x0969,
123.2352 +0x096b,0x096d,0x096f,0x0971,0x0973,0x0975,0x0977,0x0979,
123.2353 +0x097b,0x097d,0x097f,0x0981,0x0983,0x0985,0x0987,0x0989,
123.2354 +0x098b,0x098d,0x098f,0x0991,0x0993,0x0995,0x0997,0x0999,
123.2355 +0x099b,0x099d,0x099f,0x09a1,0x09a3,0x09a5,0x09a7,0x09a9,
123.2356 +0x09ab,0x09ad,0x09af,0x09b1,0x09b3,0x09b5,0x09b7,0x09b9,
123.2357 +0x09bb,0x09bd,0x09bf,0x09c1,0x09c3,0x09c5,0x11c7,0x11ca,
123.2358 +0x11cd,0x11d0,0x11d3,0x11d6,0x09d9,0x09db,0x09dd,0x09df,
123.2359 +0x09e1,0x09e3,0x09e5,0x09e7,0x09e9,0x09eb,0x09ed,0x09ef,
123.2360 +0x09f1,0x09f3,0x09f5,0x09f7,0x09f9,0x09fb,0x09fd,0x09ff,
123.2361 +0x0a01,0x0a03,0x0a05,0x0a07,0x0a09,0x0a0b,0x0a0d,0x0a0f,
123.2362 +0x0a11,0x0a13,0x0a15,0x0a17,0x0a19,0x0a1b,0x0a1d,0x0a1f,
123.2363 +0x0a21,0x0a23,0x0a25,0x0a27,0x0a29,0x0a2b,0x0a2d,0x0a2f,
123.2364 +0x0a31,0x0a33,0x0a35,0x0a37,0x0a39,0x0a3b,0x0a3d,0x0a3f,
123.2365 +0x0a41,0x0a43,0x0a45,0x0a47,0x0a49,0x0a4b,0x0a4d,0x0a4f,
123.2366 +0x0a51,0x0a53,0x0a55,0x0a57,0x0a59,0x0a5b,0x0a5d,0x0a5f,
123.2367 +0x0a61,0x0a63,0x0a65,0x0a67,0x0a69,0x0a6b,0x0a6d,0x0a6f,
123.2368 +0x0a71,0x0a73,0x0a75,0x0a77,0x0a79,0x0a7b,0x0a7d,0x0a7f,
123.2369 +0x0a81,0x0a83,0x0a85,0x0a87,0x0a89,0x0a8b,0x0a8d,0x0a8f,
123.2370 +0x0a91,0x0a93,0x0a95,0x0a97,0x0a99,0x0a9b,0x0a9d,0x0a9f,
123.2371 +0x0aa1,0x0aa3,0x0aa5,0x0aa7,0x0aa9,0x0aab,0x0aad,0x0aaf,
123.2372 +0x0ab1,0x0ab3,0x0ab5,0x0ab7,0x0ab9,0x0abb,0x0abd,0x0abf,
123.2373 +0x0ac1,0x0ac3,0x0ac5,0x0ac7,0x0ac9,0x0acb,0x0acd,0x0acf,
123.2374 +0x0ad1,0x0ad3,0x0ad5,0x0ad7,0x0ad9,0x0adb,0x0add,0x0adf,
123.2375 +0x0ae1,0x0ae3,0x0ae5,0x0ae7,0x0ae9,0x0aeb,0x0aed,0x0aef,
123.2376 +0x0af1,0x0af3,0x12f5,0x12f8,0x12fb,0x0afe,0x0b00,0x0b02,
123.2377 +0x0b04,0x0b06,0x0b08,0x0b0a,0x0b0c,0x0b0e,0x0b10,0x0b12,
123.2378 +0x0b14,0x0b16,0x0b18,0x0b1a,0x0b1c,0x0b1e,0x0b20,0x0b22,
123.2379 +0x0b24,0x0b26,0x0b28,0x0b2a,0x0b2c,0x0b2e,0x0b30,0x0b32,
123.2380 +0x0b34,0x0b36,0x0b38,0x0b3a,0x0b3c,0x0b3e,0x0b40,0x0b42,
123.2381 +0x0b44,0x0b46,0x0b48,0x0b4a,0x0b4c,0x0b4e,0x0b50,0x0b52,
123.2382 +0x0b54,0x0b56,0x0b58,0x0b5a,0x0b5c,0x0b5e,0x0b60,0x0b62,
123.2383 +0x0b64,0x0b66,0x0b68,0x0b6a,0x0b6c,0x0b6e,0x0b70,0x0b72,
123.2384 +0x0b74,0x0b76,0x0b78,0x0b7a,0x0b7c,0x0b7e,0x0b80,0x0b82,
123.2385 +0x0b84,0x0b86,0x0b88,0x0b8a,0x0b8c,0x0b8e,0x0000,0x0000,
123.2386 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2387 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2388 +0x1390,0x1393,0x1396,0x1399,0x139c,0x139f,0x13a2,0x13a5,
123.2389 +0x13a8,0x13ab,0x13ae,0x13b1,0x13b4,0x13b7,0x13ba,0x13bd,
123.2390 +0x13c0,0x13c3,0x13c6,0x13c9,0x13cc,0x13cf,0x13d2,0x13d5,
123.2391 +0x13d8,0x13db,0x13de,0x13e1,0x13e4,0x13e7,0x13ea,0x13ed,
123.2392 +0x13f0,0x13f3,0x13f6,0x13f9,0x13fc,0x13ff,0x1402,0x1405,
123.2393 +0x1408,0x140b,0x140e,0x1411,0x1414,0x1417,0x141a,0x141d,
123.2394 +0x1420,0x1423,0x1426,0x1429,0x142c,0x142f,0x1432,0x1435,
123.2395 +0x1438,0x143b,0x143e,0x1441,0x1444,0x1447,0x144a,0x144d,
123.2396 +0x0000,0x0000,0x1450,0x1453,0x1456,0x1459,0x145c,0x145f,
123.2397 +0x1462,0x1465,0x1468,0x146b,0x146e,0x1471,0x1474,0x1477,
123.2398 +0x147a,0x147d,0x1480,0x1483,0x1486,0x1489,0x148c,0x148f,
123.2399 +0x1492,0x1495,0x1498,0x149b,0x149e,0x14a1,0x14a4,0x14a7,
123.2400 +0x14aa,0x14ad,0x14b0,0x14b3,0x14b6,0x14b9,0x14bc,0x14bf,
123.2401 +0x14c2,0x14c5,0x14c8,0x14cb,0x14ce,0x14d1,0x14d4,0x14d7,
123.2402 +0x14da,0x14dd,0x14e0,0x14e3,0x14e6,0x14e9,0x14ec,0x14ef,
123.2403 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2404 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2405 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2406 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2407 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2408 +0x14f2,0x14f5,0x1cf8,0x1cfc,0x1d00,0x1d04,0x1d08,0x1d0c,
123.2409 +0x1d10,0x1514,0x8d17,0x3d29,0x1d31,0x0000,0x0000,0x0000,
123.2410 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2411 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2412 +0x0535,0x0536,0x0537,0x0538,0x0539,0x053a,0x053b,0x053c,
123.2413 +0x053d,0x053e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2414 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2415 +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
123.2416 +0x053f,0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,
123.2417 +0x0547,0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,
123.2418 +0x054f,0x0550,0x0551,0x0552,0x0553,0x0000,0x0000,0x0554,
123.2419 +0x0555,0x0556,0x0557,0x0558,0x0559,0x055a,0x055b,0x055c,
123.2420 +0x055d,0x055e,0x055f,0x0000,0x0560,0x0561,0x0562,0x0563,
123.2421 +0x0564,0x0565,0x0566,0x0567,0x0568,0x0569,0x056a,0x056b,
123.2422 +0x056c,0x056d,0x056e,0x056f,0x0570,0x0571,0x0572,0x0000,
123.2423 +0x0573,0x0574,0x0575,0x0576,0x0000,0x0000,0x0000,0x0000,
123.2424 +0x0d77,0x0d79,0x0d7b,0x0000,0x0d7d,0x0000,0x0d7f,0x0d81,
123.2425 +0x0d83,0x0d85,0x0d87,0x0d89,0x0d8b,0x0d8d,0x0d8f,0x0d91,
123.2426 +0x0593,0x0594,0x0595,0x0596,0x0597,0x0598,0x0599,0x059a,
123.2427 +0x059b,0x059c,0x059d,0x059e,0x059f,0x05a0,0x05a1,0x05a2,
123.2428 +0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,0x05a8,0x05a9,0x05aa,
123.2429 +0x05ab,0x05ac,0x05ad,0x05ae,0x05af,0x05b0,0x05b1,0x05b2,
123.2430 +0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,0x05b8,0x05b9,0x05ba,
123.2431 +0x05bb,0x05bc,0x05bd,0x05be,0x05bf,0x05c0,0x05c1,0x05c2,
123.2432 +0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,0x05c8,0x05c9,0x05ca,
123.2433 +0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,0x05d0,0x05d1,0x05d2,
123.2434 +0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,0x05d8,0x05d9,0x05da,
123.2435 +0x05db,0x05dc,0x05dd,0x05de,0x05df,0x05e0,0x05e1,0x05e2,
123.2436 +0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,0x05e8,0x05e9,0x05ea,
123.2437 +0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,0x05f0,0x05f1,0x05f2,
123.2438 +0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,0x05f8,0x05f9,0x05fa,
123.2439 +0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,0x0600,0x0601,0x0602,
123.2440 +0x0603,0x0604,0x0605,0x0606,0x0607,0x0e08,0x0e0a,0x0e0c,
123.2441 +0x0e0e,0x0e10,0x0e12,0x0e14,0x0e16
123.2442 +};
123.2443 +
123.2444 +	/* BMP high decompositions */
123.2445 +static unsigned short ucs4_dbmphitab[1560] = {
123.2446 +0x0066,0x0066,0x0066,0x0069,0x0066,0x006c,0x0066,0x0066,
123.2447 +0x0069,0x0066,0x0066,0x006c,0x017f,0x0074,0x0073,0x0074,
123.2448 +0x0574,0x0576,0x0574,0x0565,0x0574,0x056b,0x057e,0x0576,
123.2449 +0x0574,0x056d,0x05d9,0x05b4,0x05f2,0x05b7,0x05e2,0x05d0,
123.2450 +0x05d3,0x05d4,0x05db,0x05dc,0x05dd,0x05e8,0x05ea,0x002b,
123.2451 +0x05e9,0x05c1,0x05e9,0x05c2,0xfb49,0x05c1,0xfb49,0x05c2,
123.2452 +0x05d0,0x05b7,0x05d0,0x05b8,0x05d0,0x05bc,0x05d1,0x05bc,
123.2453 +0x05d2,0x05bc,0x05d3,0x05bc,0x05d4,0x05bc,0x05d5,0x05bc,
123.2454 +0x05d6,0x05bc,0x05d8,0x05bc,0x05d9,0x05bc,0x05da,0x05bc,
123.2455 +0x05db,0x05bc,0x05dc,0x05bc,0x05de,0x05bc,0x05e0,0x05bc,
123.2456 +0x05e1,0x05bc,0x05e3,0x05bc,0x05e4,0x05bc,0x05e6,0x05bc,
123.2457 +0x05e7,0x05bc,0x05e8,0x05bc,0x05e9,0x05bc,0x05ea,0x05bc,
123.2458 +0x05d5,0x05b9,0x05d1,0x05bf,0x05db,0x05bf,0x05e4,0x05bf,
123.2459 +0x05d0,0x05dc,0x0671,0x0671,0x067b,0x067b,0x067b,0x067b,
123.2460 +0x067e,0x067e,0x067e,0x067e,0x0680,0x0680,0x0680,0x0680,
123.2461 +0x067a,0x067a,0x067a,0x067a,0x067f,0x067f,0x067f,0x067f,
123.2462 +0x0679,0x0679,0x0679,0x0679,0x06a4,0x06a4,0x06a4,0x06a4,
123.2463 +0x06a6,0x06a6,0x06a6,0x06a6,0x0684,0x0684,0x0684,0x0684,
123.2464 +0x0683,0x0683,0x0683,0x0683,0x0686,0x0686,0x0686,0x0686,
123.2465 +0x0687,0x0687,0x0687,0x0687,0x068d,0x068d,0x068c,0x068c,
123.2466 +0x068e,0x068e,0x0688,0x0688,0x0698,0x0698,0x0691,0x0691,
123.2467 +0x06a9,0x06a9,0x06a9,0x06a9,0x06af,0x06af,0x06af,0x06af,
123.2468 +0x06b3,0x06b3,0x06b3,0x06b3,0x06b1,0x06b1,0x06b1,0x06b1,
123.2469 +0x06ba,0x06ba,0x06bb,0x06bb,0x06bb,0x06bb,0x06c0,0x06c0,
123.2470 +0x06c1,0x06c1,0x06c1,0x06c1,0x06be,0x06be,0x06be,0x06be,
123.2471 +0x06d2,0x06d2,0x06d3,0x06d3,0x06ad,0x06ad,0x06ad,0x06ad,
123.2472 +0x06c7,0x06c7,0x06c6,0x06c6,0x06c8,0x06c8,0x0677,0x06cb,
123.2473 +0x06cb,0x06c5,0x06c5,0x06c9,0x06c9,0x06d0,0x06d0,0x06d0,
123.2474 +0x06d0,0x0649,0x0649,0x0626,0x0627,0x0626,0x0627,0x0626,
123.2475 +0x06d5,0x0626,0x06d5,0x0626,0x0648,0x0626,0x0648,0x0626,
123.2476 +0x06c7,0x0626,0x06c7,0x0626,0x06c6,0x0626,0x06c6,0x0626,
123.2477 +0x06c8,0x0626,0x06c8,0x0626,0x06d0,0x0626,0x06d0,0x0626,
123.2478 +0x06d0,0x0626,0x0649,0x0626,0x0649,0x0626,0x0649,0x06cc,
123.2479 +0x06cc,0x06cc,0x06cc,0x0626,0x062c,0x0626,0x062d,0x0626,
123.2480 +0x0645,0x0626,0x0649,0x0626,0x064a,0x0628,0x062c,0x0628,
123.2481 +0x062d,0x0628,0x062e,0x0628,0x0645,0x0628,0x0649,0x0628,
123.2482 +0x064a,0x062a,0x062c,0x062a,0x062d,0x062a,0x062e,0x062a,
123.2483 +0x0645,0x062a,0x0649,0x062a,0x064a,0x062b,0x062c,0x062b,
123.2484 +0x0645,0x062b,0x0649,0x062b,0x064a,0x062c,0x062d,0x062c,
123.2485 +0x0645,0x062d,0x062c,0x062d,0x0645,0x062e,0x062c,0x062e,
123.2486 +0x062d,0x062e,0x0645,0x0633,0x062c,0x0633,0x062d,0x0633,
123.2487 +0x062e,0x0633,0x0645,0x0635,0x062d,0x0635,0x0645,0x0636,
123.2488 +0x062c,0x0636,0x062d,0x0636,0x062e,0x0636,0x0645,0x0637,
123.2489 +0x062d,0x0637,0x0645,0x0638,0x0645,0x0639,0x062c,0x0639,
123.2490 +0x0645,0x063a,0x062c,0x063a,0x0645,0x0641,0x062c,0x0641,
123.2491 +0x062d,0x0641,0x062e,0x0641,0x0645,0x0641,0x0649,0x0641,
123.2492 +0x064a,0x0642,0x062d,0x0642,0x0645,0x0642,0x0649,0x0642,
123.2493 +0x064a,0x0643,0x0627,0x0643,0x062c,0x0643,0x062d,0x0643,
123.2494 +0x062e,0x0643,0x0644,0x0643,0x0645,0x0643,0x0649,0x0643,
123.2495 +0x064a,0x0644,0x062c,0x0644,0x062d,0x0644,0x062e,0x0644,
123.2496 +0x0645,0x0644,0x0649,0x0644,0x064a,0x0645,0x062c,0x0645,
123.2497 +0x062d,0x0645,0x062e,0x0645,0x0645,0x0645,0x0649,0x0645,
123.2498 +0x064a,0x0646,0x062c,0x0646,0x062d,0x0646,0x062e,0x0646,
123.2499 +0x0645,0x0646,0x0649,0x0646,0x064a,0x0647,0x062c,0x0647,
123.2500 +0x0645,0x0647,0x0649,0x0647,0x064a,0x064a,0x062c,0x064a,
123.2501 +0x062d,0x064a,0x062e,0x064a,0x0645,0x064a,0x0649,0x064a,
123.2502 +0x064a,0x0630,0x0670,0x0631,0x0670,0x0649,0x0670,0x0020,
123.2503 +0x064c,0x0651,0x0020,0x064d,0x0651,0x0020,0x064e,0x0651,
123.2504 +0x0020,0x064f,0x0651,0x0020,0x0650,0x0651,0x0020,0x0651,
123.2505 +0x0670,0x0626,0x0631,0x0626,0x0632,0x0626,0x0645,0x0626,
123.2506 +0x0646,0x0626,0x0649,0x0626,0x064a,0x0628,0x0631,0x0628,
123.2507 +0x0632,0x0628,0x0645,0x0628,0x0646,0x0628,0x0649,0x0628,
123.2508 +0x064a,0x062a,0x0631,0x062a,0x0632,0x062a,0x0645,0x062a,
123.2509 +0x0646,0x062a,0x0649,0x062a,0x064a,0x062b,0x0631,0x062b,
123.2510 +0x0632,0x062b,0x0645,0x062b,0x0646,0x062b,0x0649,0x062b,
123.2511 +0x064a,0x0641,0x0649,0x0641,0x064a,0x0642,0x0649,0x0642,
123.2512 +0x064a,0x0643,0x0627,0x0643,0x0644,0x0643,0x0645,0x0643,
123.2513 +0x0649,0x0643,0x064a,0x0644,0x0645,0x0644,0x0649,0x0644,
123.2514 +0x064a,0x0645,0x0627,0x0645,0x0645,0x0646,0x0631,0x0646,
123.2515 +0x0632,0x0646,0x0645,0x0646,0x0646,0x0646,0x0649,0x0646,
123.2516 +0x064a,0x0649,0x0670,0x064a,0x0631,0x064a,0x0632,0x064a,
123.2517 +0x0645,0x064a,0x0646,0x064a,0x0649,0x064a,0x064a,0x0626,
123.2518 +0x062c,0x0626,0x062d,0x0626,0x062e,0x0626,0x0645,0x0626,
123.2519 +0x0647,0x0628,0x062c,0x0628,0x062d,0x0628,0x062e,0x0628,
123.2520 +0x0645,0x0628,0x0647,0x062a,0x062c,0x062a,0x062d,0x062a,
123.2521 +0x062e,0x062a,0x0645,0x062a,0x0647,0x062b,0x0645,0x062c,
123.2522 +0x062d,0x062c,0x0645,0x062d,0x062c,0x062d,0x0645,0x062e,
123.2523 +0x062c,0x062e,0x0645,0x0633,0x062c,0x0633,0x062d,0x0633,
123.2524 +0x062e,0x0633,0x0645,0x0635,0x062d,0x0635,0x062e,0x0635,
123.2525 +0x0645,0x0636,0x062c,0x0636,0x062d,0x0636,0x062e,0x0636,
123.2526 +0x0645,0x0637,0x062d,0x0638,0x0645,0x0639,0x062c,0x0639,
123.2527 +0x0645,0x063a,0x062c,0x063a,0x0645,0x0641,0x062c,0x0641,
123.2528 +0x062d,0x0641,0x062e,0x0641,0x0645,0x0642,0x062d,0x0642,
123.2529 +0x0645,0x0643,0x062c,0x0643,0x062d,0x0643,0x062e,0x0643,
123.2530 +0x0644,0x0643,0x0645,0x0644,0x062c,0x0644,0x062d,0x0644,
123.2531 +0x062e,0x0644,0x0645,0x0644,0x0647,0x0645,0x062c,0x0645,
123.2532 +0x062d,0x0645,0x062e,0x0645,0x0645,0x0646,0x062c,0x0646,
123.2533 +0x062d,0x0646,0x062e,0x0646,0x0645,0x0646,0x0647,0x0647,
123.2534 +0x062c,0x0647,0x0645,0x0647,0x0670,0x064a,0x062c,0x064a,
123.2535 +0x062d,0x064a,0x062e,0x064a,0x0645,0x064a,0x0647,0x0626,
123.2536 +0x0645,0x0626,0x0647,0x0628,0x0645,0x0628,0x0647,0x062a,
123.2537 +0x0645,0x062a,0x0647,0x062b,0x0645,0x062b,0x0647,0x0633,
123.2538 +0x0645,0x0633,0x0647,0x0634,0x0645,0x0634,0x0647,0x0643,
123.2539 +0x0644,0x0643,0x0645,0x0644,0x0645,0x0646,0x0645,0x0646,
123.2540 +0x0647,0x064a,0x0645,0x064a,0x0647,0x0640,0x064e,0x0651,
123.2541 +0x0640,0x064f,0x0651,0x0640,0x0650,0x0651,0x0637,0x0649,
123.2542 +0x0637,0x064a,0x0639,0x0649,0x0639,0x064a,0x063a,0x0649,
123.2543 +0x063a,0x064a,0x0633,0x0649,0x0633,0x064a,0x0634,0x0649,
123.2544 +0x0634,0x064a,0x062d,0x0649,0x062d,0x064a,0x062c,0x0649,
123.2545 +0x062c,0x064a,0x062e,0x0649,0x062e,0x064a,0x0635,0x0649,
123.2546 +0x0635,0x064a,0x0636,0x0649,0x0636,0x064a,0x0634,0x062c,
123.2547 +0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0634,0x0631,
123.2548 +0x0633,0x0631,0x0635,0x0631,0x0636,0x0631,0x0637,0x0649,
123.2549 +0x0637,0x064a,0x0639,0x0649,0x0639,0x064a,0x063a,0x0649,
123.2550 +0x063a,0x064a,0x0633,0x0649,0x0633,0x064a,0x0634,0x0649,
123.2551 +0x0634,0x064a,0x062d,0x0649,0x062d,0x064a,0x062c,0x0649,
123.2552 +0x062c,0x064a,0x062e,0x0649,0x062e,0x064a,0x0635,0x0649,
123.2553 +0x0635,0x064a,0x0636,0x0649,0x0636,0x064a,0x0634,0x062c,
123.2554 +0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0634,0x0631,
123.2555 +0x0633,0x0631,0x0635,0x0631,0x0636,0x0631,0x0634,0x062c,
123.2556 +0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0633,0x0647,
123.2557 +0x0634,0x0647,0x0637,0x0645,0x0633,0x062c,0x0633,0x062d,
123.2558 +0x0633,0x062e,0x0634,0x062c,0x0634,0x062d,0x0634,0x062e,
123.2559 +0x0637,0x0645,0x0638,0x0645,0x0627,0x064b,0x0627,0x064b,
123.2560 +0x062a,0x062c,0x0645,0x062a,0x062d,0x062c,0x062a,0x062d,
123.2561 +0x062c,0x062a,0x062d,0x0645,0x062a,0x062e,0x0645,0x062a,
123.2562 +0x0645,0x062c,0x062a,0x0645,0x062d,0x062a,0x0645,0x062e,
123.2563 +0x062c,0x0645,0x062d,0x062c,0x0645,0x062d,0x062d,0x0645,
123.2564 +0x064a,0x062d,0x0645,0x0649,0x0633,0x062d,0x062c,0x0633,
123.2565 +0x062c,0x062d,0x0633,0x062c,0x0649,0x0633,0x0645,0x062d,
123.2566 +0x0633,0x0645,0x062d,0x0633,0x0645,0x062c,0x0633,0x0645,
123.2567 +0x0645,0x0633,0x0645,0x0645,0x0635,0x062d,0x062d,0x0635,
123.2568 +0x062d,0x062d,0x0635,0x0645,0x0645,0x0634,0x062d,0x0645,
123.2569 +0x0634,0x062d,0x0645,0x0634,0x062c,0x064a,0x0634,0x0645,
123.2570 +0x062e,0x0634,0x0645,0x062e,0x0634,0x0645,0x0645,0x0634,
123.2571 +0x0645,0x0645,0x0636,0x062d,0x0649,0x0636,0x062e,0x0645,
123.2572 +0x0636,0x062e,0x0645,0x0637,0x0645,0x062d,0x0637,0x0645,
123.2573 +0x062d,0x0637,0x0645,0x0645,0x0637,0x0645,0x064a,0x0639,
123.2574 +0x062c,0x0645,0x0639,0x0645,0x0645,0x0639,0x0645,0x0645,
123.2575 +0x0639,0x0645,0x0649,0x063a,0x0645,0x0645,0x063a,0x0645,
123.2576 +0x064a,0x063a,0x0645,0x0649,0x0641,0x062e,0x0645,0x0641,
123.2577 +0x062e,0x0645,0x0642,0x0645,0x062d,0x0642,0x0645,0x0645,
123.2578 +0x0644,0x062d,0x0645,0x0644,0x062d,0x064a,0x0644,0x062d,
123.2579 +0x0649,0x0644,0x062c,0x062c,0x0644,0x062c,0x062c,0x0644,
123.2580 +0x062e,0x0645,0x0644,0x062e,0x0645,0x0644,0x0645,0x062d,
123.2581 +0x0644,0x0645,0x062d,0x0645,0x062d,0x062c,0x0645,0x062d,
123.2582 +0x0645,0x0645,0x062d,0x064a,0x0645,0x062c,0x062d,0x0645,
123.2583 +0x062c,0x0645,0x0645,0x062e,0x062c,0x0645,0x062e,0x0645,
123.2584 +0x0645,0x062c,0x062e,0x0647,0x0645,0x062c,0x0647,0x0645,
123.2585 +0x0645,0x0646,0x062d,0x0645,0x0646,0x062d,0x0649,0x0646,
123.2586 +0x062c,0x0645,0x0646,0x062c,0x0645,0x0646,0x062c,0x0649,
123.2587 +0x0646,0x0645,0x064a,0x0646,0x0645,0x0649,0x064a,0x0645,
123.2588 +0x0645,0x064a,0x0645,0x0645,0x0628,0x062e,0x064a,0x062a,
123.2589 +0x062c,0x064a,0x062a,0x062c,0x0649,0x062a,0x062e,0x064a,
123.2590 +0x062a,0x062e,0x0649,0x062a,0x0645,0x064a,0x062a,0x0645,
123.2591 +0x0649,0x062c,0x0645,0x064a,0x062c,0x062d,0x0649,0x062c,
123.2592 +0x0645,0x0649,0x0633,0x062e,0x0649,0x0635,0x062d,0x064a,
123.2593 +0x0634,0x062d,0x064a,0x0636,0x062d,0x064a,0x0644,0x062c,
123.2594 +0x064a,0x0644,0x0645,0x064a,0x064a,0x062d,0x064a,0x064a,
123.2595 +0x062c,0x064a,0x064a,0x0645,0x064a,0x0645,0x0645,0x064a,
123.2596 +0x0642,0x0645,0x064a,0x0646,0x062d,0x064a,0x0642,0x0645,
123.2597 +0x062d,0x0644,0x062d,0x0645,0x0639,0x0645,0x064a,0x0643,
123.2598 +0x0645,0x064a,0x0646,0x062c,0x062d,0x0645,0x062e,0x064a,
123.2599 +0x0644,0x062c,0x0645,0x0643,0x0645,0x0645,0x0644,0x062c,
123.2600 +0x0645,0x0646,0x062c,0x062d,0x062c,0x062d,0x064a,0x062d,
123.2601 +0x062c,0x064a,0x0645,0x062c,0x064a,0x0641,0x0645,0x064a,
123.2602 +0x0628,0x062d,0x064a,0x0643,0x0645,0x0645,0x0639,0x062c,
123.2603 +0x0645,0x0635,0x0645,0x0645,0x0633,0x062e,0x064a,0x0646,
123.2604 +0x062c,0x064a,0x0635,0x0644,0x06d2,0x0642,0x0644,0x06d2,
123.2605 +0x0627,0x0644,0x0644,0x0647,0x0627,0x0643,0x0628,0x0631,
123.2606 +0x0645,0x062d,0x0645,0x062f,0x0635,0x0644,0x0639,0x0645,
123.2607 +0x0631,0x0633,0x0648,0x0644,0x0639,0x0644,0x064a,0x0647,
123.2608 +0x0648,0x0633,0x0644,0x0645,0x0635,0x0644,0x0649,0x0635,
123.2609 +0x0644,0x0649,0x0020,0x0627,0x0644,0x0644,0x0647,0x0020,
123.2610 +0x0639,0x0644,0x064a,0x0647,0x0020,0x0648,0x0633,0x0644,
123.2611 +0x0645,0x062c,0x0644,0x0020,0x062c,0x0644,0x0627,0x0644,
123.2612 +0x0647,0x0631,0x06cc,0x0627,0x0644,0x002c,0x3001,0x3002,
123.2613 +0x003a,0x003b,0x0021,0x003f,0x3016,0x3017,0x2026,0x2025,
123.2614 +0x2014,0x2013,0x005f,0x005f,0x0028,0x0029,0x007b,0x007d,
123.2615 +0x3014,0x3015,0x3010,0x3011,0x300a,0x300b,0x3008,0x3009,
123.2616 +0x300c,0x300d,0x300e,0x300f,0x005b,0x005d,0x203e,0x203e,
123.2617 +0x203e,0x203e,0x005f,0x005f,0x005f,0x002c,0x3001,0x002e,
123.2618 +0x003b,0x003a,0x003f,0x0021,0x2014,0x0028,0x0029,0x007b,
123.2619 +0x007d,0x3014,0x3015,0x0023,0x0026,0x002a,0x002b,0x002d,
123.2620 +0x003c,0x003e,0x003d,0x005c,0x0024,0x0025,0x0040,0x0020,
123.2621 +0x064b,0x0640,0x064b,0x0020,0x064c,0x0020,0x064d,0x0020,
123.2622 +0x064e,0x0640,0x064e,0x0020,0x064f,0x0640,0x064f,0x0020,
123.2623 +0x0650,0x0640,0x0650,0x0020,0x0651,0x0640,0x0651,0x0020,
123.2624 +0x0652,0x0640,0x0652,0x0621,0x0622,0x0622,0x0623,0x0623,
123.2625 +0x0624,0x0624,0x0625,0x0625,0x0626,0x0626,0x0626,0x0626,
123.2626 +0x0627,0x0627,0x0628,0x0628,0x0628,0x0628,0x0629,0x0629,
123.2627 +0x062a,0x062a,0x062a,0x062a,0x062b,0x062b,0x062b,0x062b,
123.2628 +0x062c,0x062c,0x062c,0x062c,0x062d,0x062d,0x062d,0x062d,
123.2629 +0x062e,0x062e,0x062e,0x062e,0x062f,0x062f,0x0630,0x0630,
123.2630 +0x0631,0x0631,0x0632,0x0632,0x0633,0x0633,0x0633,0x0633,
123.2631 +0x0634,0x0634,0x0634,0x0634,0x0635,0x0635,0x0635,0x0635,
123.2632 +0x0636,0x0636,0x0636,0x0636,0x0637,0x0637,0x0637,0x0637,
123.2633 +0x0638,0x0638,0x0638,0x0638,0x0639,0x0639,0x0639,0x0639,
123.2634 +0x063a,0x063a,0x063a,0x063a,0x0641,0x0641,0x0641,0x0641,
123.2635 +0x0642,0x0642,0x0642,0x0642,0x0643,0x0643,0x0643,0x0643,
123.2636 +0x0644,0x0644,0x0644,0x0644,0x0645,0x0645,0x0645,0x0645,
123.2637 +0x0646,0x0646,0x0646,0x0646,0x0647,0x0647,0x0647,0x0647,
123.2638 +0x0648,0x0648,0x0649,0x0649,0x064a,0x064a,0x064a,0x064a,
123.2639 +0x0644,0x0622,0x0644,0x0622,0x0644,0x0623,0x0644,0x0623,
123.2640 +0x0644,0x0625,0x0644,0x0625,0x0644,0x0627,0x0644,0x0627,
123.2641 +};
123.2642 +
123.2643 +
123.2644 +#define UCS4_BMPHALFFULLMIN 0xff00
123.2645 +#define UCS4_BMPHALFFULLMAX 0xffef
123.2646 +
123.2647 +static const unsigned short ucs4_bmphalffulldecomptab[240] = {
123.2648 +  0x0000,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
123.2649 +  0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
123.2650 +  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
123.2651 +  0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
123.2652 +  0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
123.2653 +  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
123.2654 +  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
123.2655 +  0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
123.2656 +  0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
123.2657 +  0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
123.2658 +  0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
123.2659 +  0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2985,
123.2660 +  0x2986,0x3002,0x300c,0x300d,0x3001,0x30fb,0x30f2,0x30a1,
123.2661 +  0x30a3,0x30a5,0x30a7,0x30a9,0x30e3,0x30e5,0x30e7,0x30c3,
123.2662 +  0x30fc,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,0x30ad,
123.2663 +  0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,0x30bd,
123.2664 +  0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,0x30cc,
123.2665 +  0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,0x30de,
123.2666 +  0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,0x30e9,
123.2667 +  0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f3,0x3099,0x309a,
123.2668 +  0x3164,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,
123.2669 +  0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f,
123.2670 +  0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,
123.2671 +  0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x0000,
123.2672 +  0x0000,0x0000,0x314f,0x3150,0x3151,0x3152,0x3153,0x3154,
123.2673 +  0x0000,0x0000,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,
123.2674 +  0x0000,0x0000,0x315b,0x315c,0x315d,0x315e,0x315f,0x3160,
123.2675 +  0x0000,0x0000,0x3161,0x3162,0x3163,0x0000,0x0000,0x0000,
123.2676 +  0x00a2,0x00a3,0x00ac,0x00af,0x00a6,0x00a5,0x20a9,0x0000,
123.2677 +  0x2502,0x2190,0x2191,0x2192,0x2193,0x25a0,0x25cb,0x0000
123.2678 +};
123.2679 +
123.2680 +/* SMP decompositions */
123.2681 +
123.2682 +	/* Musical */
123.2683 +
123.2684 +#define UCS4_SMPMUSIC1MIN 0x1d15e
123.2685 +#define UCS4_SMPMUSIC1MAX 0x1d164
123.2686 +
123.2687 +static const unsigned long ucs4_smpmusic1decomptab[7][2] = {
123.2688 +  {0x1d157,0x1d165},{0x1d158,0x1d165},{0x1d15f,0x1d16e},{0x1d15f,0x1d16f},
123.2689 +  {0x1d15f,0x1d170},{0x1d15f,0x1d171},{0x1d15f,0x1d172}
123.2690 +};
123.2691 +
123.2692 +
123.2693 +#define UCS4_SMPMUSIC2MIN 0x1d1bb
123.2694 +#define UCS4_SMPMUSIC2MAX 0x1d1c0
123.2695 +
123.2696 +static const unsigned long ucs4_smpmusic2decomptab[6][2] = {
123.2697 +  {0x1d1b9,0x1d165},{0x1d1ba,0x1d165},{0x1d1bb,0x1d16e},
123.2698 +  {0x1d1bc,0x1d16e},{0x1d1bb,0x1d16f},{0x1d1bc,0x1d16f}
123.2699 +};
123.2700 +
123.2701 +
123.2702 +#define UCS4_SMPMATHMIN 0x1d400
123.2703 +#define UCS4_SMPMATHMAX 0x1d7ff
123.2704 +
123.2705 +	/* Mathematical - 0 means hole (no decomposition) */
123.2706 +static const unsigned short ucs4_smpmathdecomptab[1024] = {
123.2707 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2708 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2709 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2710 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2711 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2712 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2713 +  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
123.2714 +  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
123.2715 +  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
123.2716 +  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
123.2717 +  0x0063,0x0064,0x0065,0x0066,0x0067,0x0000,0x0069,0x006a,
123.2718 +  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
123.2719 +  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
123.2720 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2721 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2722 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2723 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2724 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2725 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2726 +  0x0077,0x0078,0x0079,0x007a,0x0041,0x0000,0x0043,0x0044,
123.2727 +  0x0000,0x0000,0x0047,0x0000,0x004a,0x004b,0x0000,0x0000,
123.2728 +  0x004e,0x004f,0x0050,0x0051,0x0000,0x0053,0x0054,0x0055,
123.2729 +  0x0000,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
123.2730 +  0x0063,0x0064,0x0000,0x0066,0x0000,0x0068,0x0069,0x006a,
123.2731 +  0x006b,0x006c,0x006d,0x006e,0x0000,0x0070,0x0071,0x0072,
123.2732 +  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
123.2733 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2734 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2735 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2736 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2737 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2738 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2739 +  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0000,0x0044,
123.2740 +  0x0045,0x0046,0x0047,0x0000,0x004a,0x004b,0x004c,0x004d,
123.2741 +  0x0000,0x004e,0x004f,0x0050,0x0051,0x0000,0x0053,0x0054,
123.2742 +  0x0055,0x0056,0x0057,0x0058,0x0059,0x0000,0x0061,0x0062,
123.2743 +  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
123.2744 +  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
123.2745 +  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
123.2746 +  0x0041,0x0042,0x0000,0x0044,0x0045,0x0046,0x0047,0x0000,
123.2747 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x0000,0x004f,0x0000,
123.2748 +  0x0000,0x0000,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2749 +  0x0059,0x0000,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2750 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2751 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2752 +  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
123.2753 +  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
123.2754 +  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
123.2755 +  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
123.2756 +  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
123.2757 +  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
123.2758 +  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
123.2759 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2760 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2761 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2762 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2763 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2764 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2765 +  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
123.2766 +  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
123.2767 +  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
123.2768 +  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
123.2769 +  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
123.2770 +  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
123.2771 +  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
123.2772 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2773 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2774 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2775 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2776 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2777 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2778 +  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
123.2779 +  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
123.2780 +  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
123.2781 +  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
123.2782 +  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
123.2783 +  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
123.2784 +  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
123.2785 +  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
123.2786 +  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
123.2787 +  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
123.2788 +  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
123.2789 +  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
123.2790 +  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
123.2791 +  0x0077,0x0078,0x0079,0x007a,0x0131,0x0237,0x0000,0x0000,
123.2792 +  0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
123.2793 +  0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
123.2794 +  0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,
123.2795 +  0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,
123.2796 +  0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,
123.2797 +  0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,
123.2798 +  0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,
123.2799 +  0x03f1,0x03d6,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
123.2800 +  0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,
123.2801 +  0x039f,0x03a0,0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,
123.2802 +  0x03a7,0x03a8,0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,
123.2803 +  0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,
123.2804 +  0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,
123.2805 +  0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,
123.2806 +  0x03f0,0x03d5,0x03f1,0x03d6,0x0391,0x0392,0x0393,0x0394,
123.2807 +  0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,
123.2808 +  0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03f4,0x03a3,0x03a4,
123.2809 +  0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x2207,0x03b1,0x03b2,
123.2810 +  0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,
123.2811 +  0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c2,
123.2812 +  0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x2202,
123.2813 +  0x03f5,0x03d1,0x03f0,0x03d5,0x03f1,0x03d6,0x0391,0x0392,
123.2814 +  0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,
123.2815 +  0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03f4,
123.2816 +  0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x2207,
123.2817 +  0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
123.2818 +  0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
123.2819 +  0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,
123.2820 +  0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,0x03f1,0x03d6,
123.2821 +  0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
123.2822 +  0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
123.2823 +  0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,
123.2824 +  0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,
123.2825 +  0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,
123.2826 +  0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,
123.2827 +  0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,
123.2828 +  0x03f1,0x03d6,0x03dc,0x03dd,0x0000,0x0000,0x0030,0x0031,
123.2829 +  0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,
123.2830 +  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
123.2831 +  0x0038,0x0039,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,
123.2832 +  0x0036,0x0037,0x0038,0x0039,0x0030,0x0031,0x0032,0x0033,
123.2833 +  0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x0030,0x0031,
123.2834 +  0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039
123.2835 +};
123.2836 +
123.2837 +/* SIP decompositions */
123.2838 +
123.2839 +#define UCS4_SIPMIN 0x2f800
123.2840 +#define UCS4_SIPMAX 0x2fa1d
123.2841 +
123.2842 +	/* CJK compatibility ideographs - no holes */
123.2843 +static const unsigned long ucs4_sipdecomptab[542] = {
123.2844 +   0x4e3d, 0x4e38, 0x4e41,0x20122, 0x4f60, 0x4fae, 0x4fbb, 0x5002,
123.2845 +   0x507a, 0x5099, 0x50e7, 0x50cf, 0x349e,0x2063a, 0x514d, 0x5154,
123.2846 +   0x5164, 0x5177,0x2051c, 0x34b9, 0x5167, 0x518d,0x2054b, 0x5197,
123.2847 +   0x51a4, 0x4ecc, 0x51ac, 0x51b5,0x291df, 0x51f5, 0x5203, 0x34df,
123.2848 +   0x523b, 0x5246, 0x5272, 0x5277, 0x3515, 0x52c7, 0x52c9, 0x52e4,
123.2849 +   0x52fa, 0x5305, 0x5306, 0x5317, 0x5349, 0x5351, 0x535a, 0x5373,
123.2850 +   0x537d, 0x537f, 0x537f, 0x537f,0x20a2c, 0x7070, 0x53ca, 0x53df,
123.2851 +  0x20b63, 0x53eb, 0x53f1, 0x5406, 0x549e, 0x5438, 0x5448, 0x5468,
123.2852 +   0x54a2, 0x54f6, 0x5510, 0x5553, 0x5563, 0x5584, 0x5584, 0x5599,
123.2853 +   0x55ab, 0x55b3, 0x55c2, 0x5716, 0x5606, 0x5717, 0x5651, 0x5674,
123.2854 +   0x5207, 0x58ee, 0x57ce, 0x57f4, 0x580d, 0x578b, 0x5832, 0x5831,
123.2855 +   0x58ac,0x214e4, 0x58f2, 0x58f7, 0x5906, 0x591a, 0x5922, 0x5962,
123.2856 +  0x216a8,0x216ea, 0x59ec, 0x5a1b, 0x5a27, 0x59d8, 0x5a66, 0x36ee,
123.2857 +   0x36fc, 0x5b08, 0x5b3e, 0x5b3e,0x219c8, 0x5bc3, 0x5bd8, 0x5be7,
123.2858 +   0x5bf3,0x21b18, 0x5bff, 0x5c06, 0x5f53, 0x5c22, 0x3781, 0x5c60,
123.2859 +   0x5c6e, 0x5cc0, 0x5c8d,0x21de4, 0x5d43,0x21de6, 0x5d6e, 0x5d6b,
123.2860 +   0x5d7c, 0x5de1, 0x5de2, 0x382f, 0x5dfd, 0x5e28, 0x5e3d, 0x5e69,
123.2861 +   0x3862,0x22183, 0x387c, 0x5eb0, 0x5eb3, 0x5eb6, 0x5eca,0x2a392,
123.2862 +   0x5efe,0x22331,0x22331, 0x8201, 0x5f22, 0x5f22, 0x38c7,0x232b8,
123.2863 +  0x261da, 0x5f62, 0x5f6b, 0x38e3, 0x5f9a, 0x5fcd, 0x5fd7, 0x5ff9,
123.2864 +   0x6081, 0x393a, 0x391c, 0x6094,0x226d4, 0x60c7, 0x6148, 0x614c,
123.2865 +   0x614e, 0x614c, 0x617a, 0x618e, 0x61b2, 0x61a4, 0x61af, 0x61de,
123.2866 +   0x61f2, 0x61f6, 0x6210, 0x621b, 0x625d, 0x62b1, 0x62d4, 0x6350,
123.2867 +  0x22b0c, 0x633d, 0x62fc, 0x6368, 0x6383, 0x63e4,0x22bf1, 0x6422,
123.2868 +   0x63c5, 0x63a9, 0x3a2e, 0x6469, 0x647e, 0x649d, 0x6477, 0x3a6c,
123.2869 +   0x654f, 0x656c,0x2300a, 0x65e3, 0x66f8, 0x6649, 0x3b19, 0x6691,
123.2870 +   0x3b08, 0x3ae4, 0x5192, 0x5195, 0x6700, 0x669c, 0x80ad, 0x43d9,
123.2871 +   0x6717, 0x671b, 0x6721, 0x675e, 0x6753,0x233c3, 0x3b49, 0x67fa,
123.2872 +   0x6785, 0x6852, 0x6885,0x2346d, 0x688e, 0x681f, 0x6914, 0x3b9d,
123.2873 +   0x6942, 0x69a3, 0x69ea, 0x6aa8,0x236a3, 0x6adb, 0x3c18, 0x6b21,
123.2874 +  0x238a7, 0x6b54, 0x3c4e, 0x6b72, 0x6b9f, 0x6bba, 0x6bbb,0x23a8d,
123.2875 +  0x21d0b,0x23afa, 0x6c4e,0x23cbc, 0x6cbf, 0x6ccd, 0x6c67, 0x6d16,
123.2876 +   0x6d3e, 0x6d77, 0x6d41, 0x6d69, 0x6d78, 0x6d85,0x23d1e, 0x6d34,
123.2877 +   0x6e2f, 0x6e6e, 0x3d33, 0x6ecb, 0x6ec7,0x23ed1, 0x6df9, 0x6f6e,
123.2878 +  0x23f5e,0x23f8e, 0x6fc6, 0x7039, 0x701e, 0x701b, 0x3d96, 0x704a,
123.2879 +   0x707d, 0x7077, 0x70ad,0x20525, 0x7145,0x24263, 0x719c,0x243ab,
123.2880 +   0x7228, 0x7235, 0x7250,0x24608, 0x7280, 0x7295,0x24735,0x24814,
123.2881 +   0x737a, 0x738b, 0x3eac, 0x73a5, 0x3eb8, 0x3eb8, 0x7447, 0x745c,
123.2882 +   0x7471, 0x7485, 0x74ca, 0x3f1b, 0x7524,0x24c36, 0x753e,0x24c92,
123.2883 +   0x7570,0x2219f, 0x7610,0x24fa1,0x24fb8,0x25044, 0x3ffc, 0x4008,
123.2884 +   0x76f4,0x250f3,0x250f2,0x25119,0x25133, 0x771e, 0x771f, 0x771f,
123.2885 +   0x774a, 0x4039, 0x778b, 0x4046, 0x4096,0x2541d, 0x784e, 0x788c,
123.2886 +   0x78cc, 0x40e3,0x25626, 0x7956,0x2569a,0x256c5, 0x798f, 0x79eb,
123.2887 +   0x412f, 0x7a40, 0x7a4a, 0x7a4f,0x2597c,0x25aa7,0x25aa7, 0x7aee,
123.2888 +   0x4202,0x25bab, 0x7bc6, 0x7bc9, 0x4227,0x25c80, 0x7cd2, 0x42a0,
123.2889 +   0x7ce8, 0x7ce3, 0x7d00,0x25f86, 0x7d63, 0x4301, 0x7dc7, 0x7e02,
123.2890 +   0x7e45, 0x4334,0x26228,0x26247, 0x4359,0x262d9, 0x7f7a,0x2633e,
123.2891 +   0x7f95, 0x7ffa, 0x8005,0x264da,0x26523, 0x8060,0x265a8, 0x8070,
123.2892 +  0x2335f, 0x43d5, 0x80b2, 0x8103, 0x440b, 0x813e, 0x5ab5,0x267a7,
123.2893 +  0x267b5,0x23393,0x2339c, 0x8201, 0x8204, 0x8f9e, 0x446b, 0x8291,
123.2894 +   0x828b, 0x829d, 0x52b3, 0x82b1, 0x82b3, 0x82bd, 0x82e6,0x26b3c,
123.2895 +   0x82e5, 0x831d, 0x8363, 0x83ad, 0x8323, 0x83bd, 0x83e7, 0x8457,
123.2896 +   0x8353, 0x83ca, 0x83cc, 0x83dc,0x26c36,0x26d6b,0x26cd5, 0x452b,
123.2897 +   0x84f1, 0x84f3, 0x8516,0x273ca, 0x8564,0x26f2c, 0x455d, 0x4561,
123.2898 +  0x26fb1,0x270d2, 0x456b, 0x8650, 0x865c, 0x8667, 0x8669, 0x86a9,
123.2899 +   0x8688, 0x870e, 0x86e2, 0x8779, 0x8728, 0x876b, 0x8786, 0x45d7,
123.2900 +   0x87e1, 0x8801, 0x45f9, 0x8860, 0x8863,0x27667, 0x88d7, 0x88de,
123.2901 +   0x4635, 0x88fa, 0x34bb,0x278ae,0x27966, 0x46be, 0x46c7, 0x8aa0,
123.2902 +   0x8aed, 0x8b8a, 0x8c55,0x27ca8, 0x8cab, 0x8cc1, 0x8d1b, 0x8d77,
123.2903 +  0x27f2f,0x20804, 0x8dcb, 0x8dbc, 0x8df0,0x208de, 0x8ed4, 0x8f38,
123.2904 +  0x285d2,0x285ed, 0x9094, 0x90f1, 0x9111,0x2872e, 0x911b, 0x9238,
123.2905 +   0x92d7, 0x92d8, 0x927c, 0x93f9, 0x9415,0x28bfa, 0x958b, 0x4995,
123.2906 +   0x95b7,0x28d77, 0x49e6, 0x96c3, 0x5db2, 0x9723,0x29145,0x2921a,
123.2907 +   0x4a6e, 0x4a76, 0x97e0,0x2940a, 0x4ab2,0x29496, 0x980b, 0x980b,
123.2908 +   0x9829,0x295b6, 0x98e2, 0x4b33, 0x9929, 0x99a7, 0x99c2, 0x99fe,
123.2909 +   0x4bce,0x29b30, 0x9b12, 0x9c40, 0x9cfd, 0x4cce, 0x4ced, 0x9d67,
123.2910 +  0x2a0ce, 0x4cf8,0x2a105,0x2a20e,0x2a291, 0x9ebb, 0x4d56, 0x9ef9,
123.2911 +   0x9efe, 0x9f05, 0x9f0f, 0x9f16, 0x9f3b,0x2a600
123.2912 +};
   124.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   124.2 +++ b/src/charset/gb_12345.c	Mon Sep 14 15:17:45 2009 +0900
   124.3 @@ -0,0 +1,1114 @@
   124.4 +/* ========================================================================
   124.5 + * Copyright 1988-2006 University of Washington
   124.6 + *
   124.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   124.8 + * you may not use this file except in compliance with the License.
   124.9 + * You may obtain a copy of the License at
  124.10 + *
  124.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  124.12 + *
  124.13 + * 
  124.14 + * ========================================================================
  124.15 + */
  124.16 +
  124.17 +/*
  124.18 + * Program:	GB 12345 conversion table
  124.19 + *
  124.20 + * Author:	Mark Crispin
  124.21 + *		Networks and Distributed Computing
  124.22 + *		Computing & Communications
  124.23 + *		University of Washington
  124.24 + *		Administration Building, AG-44
  124.25 + *		Seattle, WA  98195
  124.26 + *		Internet: MRC@CAC.Washington.EDU
  124.27 + *
  124.28 + * Date:	15 May 1998
  124.29 + * Last Edited:	30 August 2006
  124.30 + */
  124.31 +
  124.32 +/* GB 12345 is the national standard of the People's Republic of China
  124.33 + * (mainland China) for traditional Chinese characters.
  124.34 + */
  124.35 +
  124.36 +#define BASE_GB12345_KU 0xa1
  124.37 +#define BASE_GB12345_TEN 0xa1
  124.38 +#define MAX_GB12345_KU 89
  124.39 +#define MAX_GB12345_TEN 94
  124.40 +
  124.41 +
  124.42 +#define GB12345TOUNICODE(c,c1,ku,ten)					\
  124.43 +  ((((ku = (c & 0x7f) - BASE_GB12345_KU) < MAX_GB12345_KU) &&		\
  124.44 +    ((ten = (c1 & 0x7f) - BASE_GB12345_TEN) < MAX_GB12345_TEN)) ?	\
  124.45 +   gb12345tab[ku][ten] : UBOGON)
  124.46 +
  124.47 +
  124.48 +static const unsigned short gb12345tab[MAX_GB12345_KU][MAX_GB12345_TEN] = {
  124.49 +  {				/* ku 01 */
  124.50 +    0x3000,0x3001,0x3002,0x30fb,0x02c9,0x02c7,0x00a8,0x3003,0x3005,0x2015,
  124.51 +    0xff5e,0x2225,0x2026,0x2018,0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,
  124.52 +    0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3016,0x3017,0x3010,
  124.53 +    0x3011,0x00b1,0x00d7,0x00f7,0x2236,0x2227,0x2228,0x2211,0x220f,0x222a,
  124.54 +    0x2229,0x2208,0x2237,0x221a,0x22a5,0x2225,0x2220,0x2312,0x2299,0x222b,
  124.55 +    0x222e,0x2261,0x224c,0x2248,0x223d,0x221d,0x2260,0x226e,0x226f,0x2264,
  124.56 +    0x2265,0x221e,0x2235,0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,
  124.57 +    0xff04,0x00a4,0xffe0,0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605,0x25cb,
  124.58 +    0x25cf,0x25ce,0x25c7,0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x203b,0x2192,
  124.59 +    0x2190,0x2191,0x2193,0x3013
  124.60 +  },
  124.61 +  {				/* ku 02 */
  124.62 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  124.63 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2488,0x2489,0x248a,0x248b,
  124.64 +    0x248c,0x248d,0x248e,0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,
  124.65 +    0x2496,0x2497,0x2498,0x2499,0x249a,0x249b,0x2474,0x2475,0x2476,0x2477,
  124.66 +    0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,
  124.67 +    0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,0x2460,0x2461,0x2462,0x2463,
  124.68 +    0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,UBOGON,UBOGON,0x3220,0x3221,
  124.69 +    0x3222,0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,0x3229,UBOGON,UBOGON,
  124.70 +    0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
  124.71 +    0x216a,0x216b,UBOGON,UBOGON
  124.72 +  },
  124.73 +  {				/* ku 03 */
  124.74 +    0xff01,0xff02,0xff03,0xffe5,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,
  124.75 +    0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,
  124.76 +    0xff15,0xff16,0xff17,0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,
  124.77 +    0xff1f,0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,
  124.78 +    0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,
  124.79 +    0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,
  124.80 +    0xff3d,0xff3e,0xff3f,0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,
  124.81 +    0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,
  124.82 +    0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,
  124.83 +    0xff5b,0xff5c,0xff5d,0xffe3
  124.84 +  },
  124.85 +  {				/* ku 04 */
  124.86 +    0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,
  124.87 +    0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,
  124.88 +    0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,
  124.89 +    0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,
  124.90 +    0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,
  124.91 +    0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,
  124.92 +    0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,
  124.93 +    0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,
  124.94 +    0x3091,0x3092,0x3093,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  124.95 +    UBOGON,UBOGON,UBOGON,UBOGON
  124.96 +  },
  124.97 +  {				/* ku 05 */
  124.98 +    0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,
  124.99 +    0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,
 124.100 +    0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,
 124.101 +    0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,
 124.102 +    0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,
 124.103 +    0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,
 124.104 +    0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,
 124.105 +    0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,
 124.106 +    0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,
 124.107 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.108 +  },
 124.109 +  {				/* ku 06 */
 124.110 +    0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,
 124.111 +    0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,
 124.112 +    0x03a6,0x03a7,0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.113 +    UBOGON,UBOGON,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
 124.114 +    0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,
 124.115 +    0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,
 124.116 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.117 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.118 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.119 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.120 +  },
 124.121 +  {				/* ku 07 */
 124.122 +    0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,
 124.123 +    0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,
 124.124 +    0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,
 124.125 +    0x042d,0x042e,0x042f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.126 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,
 124.127 +    0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,
 124.128 +    0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,
 124.129 +    0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,
 124.130 +    0x044f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.131 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.132 +  },
 124.133 +  {				/* ku 08 */
 124.134 +    0x0101,0x00e1,0x01ce,0x00e0,0x0113,0x00e9,0x011b,0x00e8,0x012b,0x00ed,
 124.135 +    0x01d0,0x00ec,0x014d,0x00f3,0x01d2,0x00f2,0x016b,0x00fa,0x01d4,0x00f9,
 124.136 +    0x01d6,0x01d8,0x01da,0x01dc,0x00fc,0x00ea,UBOGON,UBOGON,UBOGON,UBOGON,
 124.137 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3105,0x3106,0x3107,0x3108,
 124.138 +    0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112,
 124.139 +    0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c,
 124.140 +    0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,
 124.141 +    0x3127,0x3128,0x3129,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.142 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.143 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.144 +  },
 124.145 +  {				/* ku 09 */
 124.146 +    UBOGON,UBOGON,UBOGON,0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,
 124.147 +    0x2507,0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,0x2510,
 124.148 +    0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a,
 124.149 +    0x251b,0x251c,0x251d,0x251e,0x251f,0x2520,0x2521,0x2522,0x2523,0x2524,
 124.150 +    0x2525,0x2526,0x2527,0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,
 124.151 +    0x252f,0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538,
 124.152 +    0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542,
 124.153 +    0x2543,0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254a,0x254b,UBOGON,
 124.154 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.155 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.156 +  },
 124.157 +  {				/* ku 0a */
 124.158 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.159 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.160 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.161 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.162 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.163 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.164 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.165 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.166 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.167 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.168 +  },
 124.169 +  {				/* ku 0b */
 124.170 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.171 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.172 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.173 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.174 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.176 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.179 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.180 +  },
 124.181 +  {				/* ku 0c */
 124.182 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.183 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.184 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.185 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.186 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.187 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.188 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.190 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.191 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.192 +  },
 124.193 +  {				/* ku 0d */
 124.194 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.195 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.196 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.197 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.198 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.199 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.203 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.204 +  },
 124.205 +  {				/* ku 0e */
 124.206 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.207 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.208 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.209 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.210 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.211 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.215 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.216 +  },
 124.217 +  {				/* ku 0f */
 124.218 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.219 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.220 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.221 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.222 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.223 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.225 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 124.227 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.228 +  },
 124.229 +  {				/* ku 10 */
 124.230 +    0x554a,0x963f,0x57c3,0x6328,0x54ce,0x5509,0x54c0,0x769a,0x764c,0x85f9,
 124.231 +    0x77ee,0x827e,0x7919,0x611b,0x9698,0x978d,0x6c28,0x5b89,0x4ffa,0x6309,
 124.232 +    0x6697,0x5cb8,0x80fa,0x6848,0x9aaf,0x6602,0x76ce,0x51f9,0x6556,0x71ac,
 124.233 +    0x7ff1,0x8956,0x50b2,0x5965,0x61ca,0x6fb3,0x82ad,0x634c,0x6252,0x53ed,
 124.234 +    0x5427,0x7b06,0x516b,0x75a4,0x5df4,0x62d4,0x8dcb,0x9776,0x628a,0x8019,
 124.235 +    0x58e9,0x9738,0x7f77,0x7238,0x767d,0x67cf,0x767e,0x64fa,0x4f70,0x6557,
 124.236 +    0x62dc,0x7a17,0x6591,0x73ed,0x642c,0x6273,0x822c,0x9812,0x677f,0x7248,
 124.237 +    0x626e,0x62cc,0x4f34,0x74e3,0x534a,0x8fa6,0x7d46,0x90a6,0x5e6b,0x6886,
 124.238 +    0x699c,0x8180,0x7d81,0x68d2,0x78c5,0x868c,0x938a,0x508d,0x8b17,0x82de,
 124.239 +    0x80de,0x5305,0x8912,0x5265
 124.240 +  },
 124.241 +  {				/* ku 11 */
 124.242 +    0x8584,0x96f9,0x4fdd,0x5821,0x98fd,0x5bf6,0x62b1,0x5831,0x66b4,0x8c79,
 124.243 +    0x9b91,0x7206,0x676f,0x7891,0x60b2,0x5351,0x5317,0x8f29,0x80cc,0x8c9d,
 124.244 +    0x92c7,0x500d,0x72fd,0x5099,0x618a,0x7119,0x88ab,0x5954,0x82ef,0x672c,
 124.245 +    0x7b28,0x5d29,0x7db3,0x752d,0x6cf5,0x8e66,0x8ff8,0x903c,0x9f3b,0x6bd4,
 124.246 +    0x9119,0x7b46,0x5f7c,0x78a7,0x84d6,0x853d,0x7562,0x6583,0x6bd6,0x5e63,
 124.247 +    0x5e87,0x75f9,0x9589,0x655d,0x5f0a,0x5fc5,0x8f9f,0x58c1,0x81c2,0x907f,
 124.248 +    0x965b,0x97ad,0x908a,0x7de8,0x8cb6,0x6241,0x4fbf,0x8b8a,0x535e,0x8fa8,
 124.249 +    0x8faf,0x8fae,0x904d,0x6a19,0x5f6a,0x8198,0x8868,0x9c49,0x618b,0x522b,
 124.250 +    0x765f,0x5f6c,0x658c,0x7015,0x6ff1,0x8cd3,0x64ef,0x5175,0x51b0,0x67c4,
 124.251 +    0x4e19,0x79c9,0x9905,0x70b3
 124.252 +  },
 124.253 +  {				/* ku 12 */
 124.254 +    0x75c5,0x5e76,0x73bb,0x83e0,0x64ad,0x64a5,0x9262,0x6ce2,0x535a,0x52c3,
 124.255 +    0x640f,0x9251,0x7b94,0x4f2f,0x5e1b,0x8236,0x8116,0x818a,0x6e24,0x6cca,
 124.256 +    0x99c1,0x6355,0x535c,0x54fa,0x88dc,0x57e0,0x4e0d,0x5e03,0x6b65,0x7c3f,
 124.257 +    0x90e8,0x6016,0x64e6,0x731c,0x88c1,0x6750,0x624d,0x8ca1,0x776c,0x8e29,
 124.258 +    0x91c7,0x5f69,0x83dc,0x8521,0x9910,0x53c3,0x8836,0x6b98,0x615a,0x6158,
 124.259 +    0x71e6,0x84bc,0x8259,0x5009,0x6ec4,0x85cf,0x64cd,0x7cd9,0x69fd,0x66f9,
 124.260 +    0x8349,0x53a0,0x7b56,0x5074,0x518c,0x6e2c,0x5c64,0x8e6d,0x63d2,0x53c9,
 124.261 +    0x832c,0x8336,0x67e5,0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8a6b,0x62c6,
 124.262 +    0x67f4,0x8c7a,0x6519,0x647b,0x87ec,0x995e,0x8b92,0x7e8f,0x93df,0x7523,
 124.263 +    0x95e1,0x986b,0x660c,0x7316
 124.264 +  },
 124.265 +  {				/* ku 13 */
 124.266 +    0x5834,0x5617,0x5e38,0x9577,0x511f,0x8178,0x5ee0,0x655e,0x66a2,0x5531,
 124.267 +    0x5021,0x8d85,0x6284,0x9214,0x671d,0x5632,0x6f6e,0x5de2,0x5435,0x7092,
 124.268 +    0x8eca,0x626f,0x64a4,0x63a3,0x5fb9,0x6f88,0x90f4,0x81e3,0x8fb0,0x5875,
 124.269 +    0x6668,0x5ff1,0x6c89,0x9673,0x8d81,0x896f,0x6491,0x7a31,0x57ce,0x6a59,
 124.270 +    0x6210,0x5448,0x4e58,0x7a0b,0x61f2,0x6f84,0x8aa0,0x627f,0x901e,0x9a01,
 124.271 +    0x79e4,0x5403,0x75f4,0x6301,0x5319,0x6c60,0x9072,0x5f1b,0x99b3,0x803b,
 124.272 +    0x9f52,0x4f88,0x5c3a,0x8d64,0x7fc5,0x65a5,0x71be,0x5145,0x885d,0x87f2,
 124.273 +    0x5d07,0x5bf5,0x62bd,0x916c,0x7587,0x8e8a,0x7a20,0x6101,0x7c4c,0x4ec7,
 124.274 +    0x7da2,0x7785,0x919c,0x81ed,0x521d,0x51fa,0x6a71,0x53a8,0x8e87,0x92e4,
 124.275 +    0x96db,0x6ec1,0x9664,0x695a
 124.276 +  },
 124.277 +  {				/* ku 14 */
 124.278 +    0x790e,0x5132,0x77d7,0x6410,0x89f8,0x8655,0x63e3,0x5ddd,0x7a7f,0x693d,
 124.279 +    0x50b3,0x8239,0x5598,0x4e32,0x7621,0x7a97,0x5e62,0x5e8a,0x95d6,0x5275,
 124.280 +    0x5439,0x708a,0x6376,0x9318,0x5782,0x6625,0x693f,0x9187,0x5507,0x6df3,
 124.281 +    0x7d14,0x8822,0x6233,0x7dbd,0x75b5,0x8328,0x78c1,0x96cc,0x8fad,0x6148,
 124.282 +    0x74f7,0x8a5e,0x6b64,0x523a,0x8cdc,0x6b21,0x8070,0x8471,0x56f1,0x5306,
 124.283 +    0x5f9e,0x53e2,0x51d1,0x7c97,0x918b,0x7c07,0x4fc3,0x8ea5,0x7be1,0x7ac4,
 124.284 +    0x6467,0x5d14,0x50ac,0x8106,0x7601,0x7cb9,0x6dec,0x7fe0,0x6751,0x5b58,
 124.285 +    0x5bf8,0x78cb,0x64ae,0x6413,0x63aa,0x632b,0x932f,0x642d,0x9054,0x7b54,
 124.286 +    0x7629,0x6253,0x5927,0x5446,0x6b79,0x50a3,0x6234,0x5e36,0x6b86,0x4ee3,
 124.287 +    0x8cb8,0x888b,0x5f85,0x902e
 124.288 +  },
 124.289 +  {				/* ku 15 */
 124.290 +    0x6020,0x803d,0x64d4,0x4e39,0x55ae,0x9132,0x64a3,0x81bd,0x65e6,0x6c2e,
 124.291 +    0x4f46,0x619a,0x6de1,0x8a95,0x5f48,0x86cb,0x7576,0x64cb,0x9ee8,0x8569,
 124.292 +    0x6a94,0x5200,0x6417,0x8e48,0x5012,0x5cf6,0x79b1,0x5c0e,0x5230,0x7a3b,
 124.293 +    0x60bc,0x9053,0x76d7,0x5fb7,0x5f97,0x7684,0x8e6c,0x71c8,0x767b,0x7b49,
 124.294 +    0x77aa,0x51f3,0x9127,0x5824,0x4f4e,0x6ef4,0x8fea,0x6575,0x7b1b,0x72c4,
 124.295 +    0x6ecc,0x7fdf,0x5ae1,0x62b5,0x5e95,0x5730,0x8482,0x7b2c,0x5e1d,0x5f1f,
 124.296 +    0x905e,0x7de0,0x985b,0x6382,0x6ec7,0x7898,0x9ede,0x5178,0x975b,0x588a,
 124.297 +    0x96fb,0x4f43,0x7538,0x5e97,0x60e6,0x5960,0x6fb1,0x6bbf,0x7889,0x53fc,
 124.298 +    0x96d5,0x51cb,0x5201,0x6389,0x540a,0x91e3,0x8abf,0x8dcc,0x7239,0x789f,
 124.299 +    0x8776,0x8fed,0x8adc,0x758a
 124.300 +  },
 124.301 +  {				/* ku 16 */
 124.302 +    0x4e01,0x76ef,0x53ee,0x91d8,0x9802,0x9f0e,0x9320,0x5b9a,0x8a02,0x4e22,
 124.303 +    0x6771,0x51ac,0x8463,0x61c2,0x52d5,0x68df,0x4f97,0x606b,0x51cd,0x6d1e,
 124.304 +    0x515c,0x6296,0x9b25,0x9661,0x8c46,0x9017,0x75d8,0x90fd,0x7763,0x6bd2,
 124.305 +    0x72a2,0x7368,0x8b80,0x5835,0x7779,0x8ced,0x675c,0x934d,0x809a,0x5ea6,
 124.306 +    0x6e21,0x5992,0x7aef,0x77ed,0x935b,0x6bb5,0x65b7,0x7dde,0x5806,0x5151,
 124.307 +    0x968a,0x5c0d,0x58a9,0x5678,0x8e72,0x6566,0x9813,0x56e4,0x920d,0x76fe,
 124.308 +    0x9041,0x6387,0x54c6,0x591a,0x596a,0x579b,0x8eb2,0x6735,0x8dfa,0x8235,
 124.309 +    0x5241,0x60f0,0x58ae,0x86fe,0x5ce8,0x9d5d,0x4fc4,0x984d,0x8a1b,0x5a25,
 124.310 +    0x60e1,0x5384,0x627c,0x904f,0x9102,0x9913,0x6069,0x800c,0x5152,0x8033,
 124.311 +    0x723e,0x990c,0x6d31,0x4e8c
 124.312 +  },
 124.313 +  {				/* ku 17 */
 124.314 +    0x8cb3,0x767c,0x7f70,0x7b4f,0x4f10,0x4e4f,0x95a5,0x6cd5,0x73d0,0x85e9,
 124.315 +    0x5e06,0x756a,0x7ffb,0x6a0a,0x792c,0x91e9,0x7e41,0x51e1,0x7169,0x53cd,
 124.316 +    0x8fd4,0x7bc4,0x8ca9,0x72af,0x98ef,0x6cdb,0x574a,0x82b3,0x65b9,0x80aa,
 124.317 +    0x623f,0x9632,0x59a8,0x4eff,0x8a2a,0x7d21,0x653e,0x83f2,0x975e,0x5561,
 124.318 +    0x98db,0x80a5,0x532a,0x8ab9,0x5420,0x80ba,0x5ee2,0x6cb8,0x8cbb,0x82ac,
 124.319 +    0x915a,0x5429,0x6c1b,0x5206,0x7d1b,0x58b3,0x711a,0x6c7e,0x7c89,0x596e,
 124.320 +    0x4efd,0x5fff,0x61a4,0x7cde,0x8c50,0x5c01,0x6953,0x8702,0x5cf0,0x92d2,
 124.321 +    0x98a8,0x760b,0x70fd,0x9022,0x99ae,0x7e2b,0x8af7,0x5949,0x9cf3,0x4f5b,
 124.322 +    0x5426,0x592b,0x6577,0x819a,0x5b75,0x6276,0x62c2,0x8f3b,0x5e45,0x6c1f,
 124.323 +    0x7b26,0x4f0f,0x4fd8,0x670d
 124.324 +  },
 124.325 +  {				/* ku 18 */
 124.326 +    0x6d6e,0x6daa,0x798f,0x88b1,0x5f17,0x752b,0x64ab,0x8f14,0x4fef,0x91dc,
 124.327 +    0x65a7,0x812f,0x8151,0x5e9c,0x8150,0x8d74,0x526f,0x8986,0x8ce6,0x5fa9,
 124.328 +    0x5085,0x4ed8,0x961c,0x7236,0x8179,0x8ca0,0x5bcc,0x8a03,0x9644,0x5a66,
 124.329 +    0x7e1b,0x5490,0x5676,0x560e,0x8a72,0x6539,0x6982,0x9223,0x84cb,0x6e89,
 124.330 +    0x5e79,0x7518,0x6746,0x67d1,0x7aff,0x809d,0x8d95,0x611f,0x79c6,0x6562,
 124.331 +    0x8d1b,0x5ca1,0x525b,0x92fc,0x7f38,0x809b,0x7db1,0x5d17,0x6e2f,0x6760,
 124.332 +    0x7bd9,0x768b,0x9ad8,0x818f,0x7f94,0x7cd5,0x641e,0x93ac,0x7a3f,0x544a,
 124.333 +    0x54e5,0x6b4c,0x64f1,0x6208,0x9d3f,0x80f3,0x7599,0x5272,0x9769,0x845b,
 124.334 +    0x683c,0x86e4,0x95a3,0x9694,0x927b,0x500b,0x5404,0x7d66,0x6839,0x8ddf,
 124.335 +    0x8015,0x66f4,0x5e9a,0x7fb9
 124.336 +  },
 124.337 +  {				/* ku 19 */
 124.338 +    0x57c2,0x803f,0x6897,0x5de5,0x653b,0x529f,0x606d,0x9f94,0x4f9b,0x8eac,
 124.339 +    0x516c,0x5bab,0x5f13,0x978f,0x6c5e,0x62f1,0x8ca2,0x5171,0x920e,0x52fe,
 124.340 +    0x6e9d,0x82df,0x72d7,0x57a2,0x69cb,0x8cfc,0x591f,0x8f9c,0x83c7,0x5495,
 124.341 +    0x7b8d,0x4f30,0x6cbd,0x5b64,0x59d1,0x9f13,0x53e4,0x8831,0x9aa8,0x8c37,
 124.342 +    0x80a1,0x6545,0x9867,0x56fa,0x96c7,0x522e,0x74dc,0x526e,0x5be1,0x6302,
 124.343 +    0x8902,0x4e56,0x62d0,0x602a,0x68fa,0x95dc,0x5b98,0x51a0,0x89c0,0x7ba1,
 124.344 +    0x9928,0x7f50,0x6163,0x704c,0x8cab,0x5149,0x5ee3,0x901b,0x7470,0x898f,
 124.345 +    0x572d,0x7845,0x6b78,0x9f9c,0x95a8,0x8ecc,0x9b3c,0x8a6d,0x7678,0x6842,
 124.346 +    0x6ac3,0x8dea,0x8cb4,0x528a,0x8f25,0x6eda,0x68cd,0x934b,0x90ed,0x570b,
 124.347 +    0x679c,0x88f9,0x904e,0x54c8
 124.348 +  },
 124.349 +  {				/* ku 1a */
 124.350 +    0x9ab8,0x5b69,0x6d77,0x6c26,0x4ea5,0x5bb3,0x99ed,0x9163,0x61a8,0x90af,
 124.351 +    0x97d3,0x542b,0x6db5,0x5bd2,0x51fd,0x558a,0x7f55,0x7ff0,0x64bc,0x634d,
 124.352 +    0x65f1,0x61be,0x608d,0x710a,0x6c57,0x6f22,0x592f,0x676d,0x822a,0x58d5,
 124.353 +    0x568e,0x8c6a,0x6beb,0x90dd,0x597d,0x8017,0x865f,0x6d69,0x5475,0x559d,
 124.354 +    0x8377,0x83cf,0x6838,0x79be,0x548c,0x4f55,0x5408,0x76d2,0x8c89,0x95a1,
 124.355 +    0x6cb3,0x6db8,0x8d6b,0x8910,0x9db4,0x8cc0,0x563f,0x9ed1,0x75d5,0x5f88,
 124.356 +    0x72e0,0x6068,0x54fc,0x4ea8,0x6a2a,0x8861,0x6052,0x8f5f,0x54c4,0x70d8,
 124.357 +    0x8679,0x9d3b,0x6d2a,0x5b8f,0x5f18,0x7d05,0x5589,0x4faf,0x7334,0x543c,
 124.358 +    0x539a,0x5019,0x5f8c,0x547c,0x4e4e,0x5ffd,0x745a,0x58fa,0x846b,0x80e1,
 124.359 +    0x8774,0x72d0,0x7cca,0x6e56
 124.360 +  },
 124.361 +  {				/* ku 1b */
 124.362 +    0x5f27,0x864e,0x552c,0x8b77,0x4e92,0x6eec,0x6237,0x82b1,0x5629,0x83ef,
 124.363 +    0x733e,0x6ed1,0x756b,0x5283,0x5316,0x8a71,0x69d0,0x5f8a,0x61f7,0x6dee,
 124.364 +    0x58de,0x6b61,0x74b0,0x6853,0x9084,0x7de9,0x63db,0x60a3,0x559a,0x7613,
 124.365 +    0x8c62,0x7165,0x6e19,0x5ba6,0x5e7b,0x8352,0x614c,0x9ec4,0x78fa,0x8757,
 124.366 +    0x7c27,0x7687,0x51f0,0x60f6,0x714c,0x6643,0x5e4c,0x604d,0x8b0a,0x7070,
 124.367 +    0x63ee,0x8f1d,0x5fbd,0x6062,0x86d4,0x56de,0x6bc1,0x6094,0x6167,0x5349,
 124.368 +    0x60e0,0x6666,0x8cc4,0x7a62,0x6703,0x71f4,0x532f,0x8af1,0x8aa8,0x7e6a,
 124.369 +    0x8477,0x660f,0x5a5a,0x9b42,0x6e3e,0x6df7,0x8c41,0x6d3b,0x4f19,0x706b,
 124.370 +    0x7372,0x6216,0x60d1,0x970d,0x8ca8,0x798d,0x64ca,0x573e,0x57fa,0x6a5f,
 124.371 +    0x7578,0x7a3d,0x7a4d,0x7b95
 124.372 +  },
 124.373 +  {				/* ku 1c */
 124.374 +    0x808c,0x9951,0x8ff9,0x6fc0,0x8b4f,0x9dc4,0x59ec,0x7e3e,0x7ddd,0x5409,
 124.375 +    0x6975,0x68d8,0x8f2f,0x7c4d,0x96c6,0x53ca,0x6025,0x75be,0x6c72,0x5373,
 124.376 +    0x5ac9,0x7d1a,0x64e0,0x5e7e,0x810a,0x5df1,0x858a,0x6280,0x5180,0x5b63,
 124.377 +    0x4f0e,0x796d,0x5291,0x60b8,0x6fdf,0x5bc4,0x5bc2,0x8a08,0x8a18,0x65e2,
 124.378 +    0x5fcc,0x969b,0x5993,0x7e7c,0x7d00,0x5609,0x67b7,0x593e,0x4f73,0x5bb6,
 124.379 +    0x52a0,0x83a2,0x9830,0x8cc8,0x7532,0x9240,0x5047,0x7a3c,0x50f9,0x67b6,
 124.380 +    0x99d5,0x5ac1,0x6bb2,0x76e3,0x5805,0x5c16,0x7b8b,0x9593,0x714e,0x517c,
 124.381 +    0x80a9,0x8271,0x5978,0x7dd8,0x7e6d,0x6aa2,0x67ec,0x78b1,0x9e7c,0x63c0,
 124.382 +    0x64bf,0x7c21,0x5109,0x526a,0x51cf,0x85a6,0x6abb,0x9452,0x8e10,0x8ce4,
 124.383 +    0x898b,0x9375,0x7bad,0x4ef6
 124.384 +  },
 124.385 +  {				/* ku 1d */
 124.386 +    0x5065,0x8266,0x528d,0x991e,0x6f38,0x6ffa,0x6f97,0x5efa,0x50f5,0x59dc,
 124.387 +    0x5c07,0x6f3f,0x6c5f,0x7586,0x8523,0x69f3,0x596c,0x8b1b,0x5320,0x91ac,
 124.388 +    0x964d,0x8549,0x6912,0x7901,0x7126,0x81a0,0x4ea4,0x90ca,0x6f86,0x9a55,
 124.389 +    0x5b0c,0x56bc,0x652a,0x9278,0x77ef,0x50e5,0x811a,0x72e1,0x89d2,0x9903,
 124.390 +    0x7e73,0x7d5e,0x527f,0x6559,0x9175,0x8f4e,0x8f03,0x53eb,0x7a96,0x63ed,
 124.391 +    0x63a5,0x7686,0x79f8,0x8857,0x968e,0x622a,0x52ab,0x7bc0,0x6854,0x6770,
 124.392 +    0x6377,0x776b,0x7aed,0x6f54,0x7d50,0x89e3,0x59d0,0x6212,0x85c9,0x82a5,
 124.393 +    0x754c,0x501f,0x4ecb,0x75a5,0x8aa1,0x5c4a,0x5dfe,0x7b4b,0x65a4,0x91d1,
 124.394 +    0x4eca,0x6d25,0x895f,0x7dca,0x9326,0x50c5,0x8b39,0x9032,0x9773,0x6649,
 124.395 +    0x7981,0x8fd1,0x71fc,0x6d78
 124.396 +  },
 124.397 +  {				/* ku 1e */
 124.398 +    0x76e1,0x52c1,0x8346,0x5162,0x8396,0x775b,0x6676,0x9be8,0x4eac,0x9a5a,
 124.399 +    0x7cbe,0x7cb3,0x7d93,0x4e95,0x8b66,0x666f,0x9838,0x975c,0x5883,0x656c,
 124.400 +    0x93e1,0x5f91,0x75d9,0x9756,0x7adf,0x7af6,0x51c8,0x70af,0x7a98,0x63ea,
 124.401 +    0x7a76,0x7cfe,0x7396,0x97ed,0x4e45,0x7078,0x4e5d,0x9152,0x53a9,0x6551,
 124.402 +    0x820a,0x81fc,0x8205,0x548e,0x5c31,0x759a,0x97a0,0x62d8,0x72d9,0x75bd,
 124.403 +    0x5c45,0x99d2,0x83ca,0x5c40,0x5480,0x77e9,0x8209,0x6cae,0x805a,0x62d2,
 124.404 +    0x64da,0x5de8,0x5177,0x8ddd,0x8e1e,0x92f8,0x4ff1,0x53e5,0x61fc,0x70ac,
 124.405 +    0x5287,0x6350,0x9d51,0x5a1f,0x5026,0x7737,0x5377,0x7d79,0x6485,0x652b,
 124.406 +    0x6289,0x6398,0x5014,0x7235,0x89ba,0x51b3,0x8a23,0x7d76,0x5747,0x83cc,
 124.407 +    0x921e,0x8ecd,0x541b,0x5cfb
 124.408 +  },
 124.409 +  {				/* ku 1f */
 124.410 +    0x4fca,0x7ae3,0x6d5a,0x90e1,0x99ff,0x5580,0x5496,0x5361,0x54af,0x958b,
 124.411 +    0x63e9,0x6977,0x51f1,0x6168,0x520a,0x582a,0x52d8,0x574e,0x780d,0x770b,
 124.412 +    0x5eb7,0x6177,0x7ce0,0x625b,0x6297,0x4ea2,0x7095,0x8003,0x62f7,0x70e4,
 124.413 +    0x9760,0x5777,0x82db,0x67ef,0x68f5,0x78d5,0x9846,0x79d1,0x6bbb,0x54b3,
 124.414 +    0x53ef,0x6e34,0x514b,0x523b,0x5ba2,0x8ab2,0x80af,0x5543,0x58be,0x61c7,
 124.415 +    0x5751,0x542d,0x7a7a,0x6050,0x5b54,0x63a7,0x6473,0x53e3,0x6263,0x5bc7,
 124.416 +    0x67af,0x54ed,0x7a9f,0x82e6,0x9177,0x5eab,0x8932,0x8a87,0x57ae,0x630e,
 124.417 +    0x8de8,0x80ef,0x584a,0x7b77,0x5108,0x5feb,0x5bec,0x6b3e,0x5321,0x7b50,
 124.418 +    0x72c2,0x6846,0x7926,0x7736,0x66e0,0x51b5,0x8667,0x76d4,0x5dcb,0x7aba,
 124.419 +    0x8475,0x594e,0x9b41,0x5080
 124.420 +  },
 124.421 +  {				/* ku 20 */
 124.422 +    0x994b,0x6127,0x6f70,0x5764,0x6606,0x6346,0x56f0,0x62ec,0x64f4,0x5ed3,
 124.423 +    0x95ca,0x5783,0x62c9,0x5587,0x881f,0x81d8,0x8fa3,0x5566,0x840a,0x4f86,
 124.424 +    0x8cf4,0x85cd,0x5a6a,0x6b04,0x6514,0x7c43,0x95cc,0x862d,0x703e,0x8b95,
 124.425 +    0x652c,0x89bd,0x61f6,0x7e9c,0x721b,0x6feb,0x7405,0x6994,0x72fc,0x5eca,
 124.426 +    0x90ce,0x6717,0x6d6a,0x6488,0x52de,0x7262,0x8001,0x4f6c,0x59e5,0x916a,
 124.427 +    0x70d9,0x6f87,0x52d2,0x6a02,0x96f7,0x9433,0x857e,0x78ca,0x7d2f,0x5121,
 124.428 +    0x58d8,0x64c2,0x808b,0x985e,0x6cea,0x68f1,0x695e,0x51b7,0x5398,0x68a8,
 124.429 +    0x7281,0x9ece,0x7c6c,0x72f8,0x96e2,0x7055,0x7406,0x674e,0x88cf,0x9bc9,
 124.430 +    0x79ae,0x8389,0x8354,0x540f,0x6817,0x9e97,0x53b2,0x52f5,0x792b,0x6b77,
 124.431 +    0x5229,0x5088,0x4f8b,0x4fd0
 124.432 +  },
 124.433 +  {				/* ku 21 */
 124.434 +    0x75e2,0x7acb,0x7c92,0x701d,0x96b8,0x529b,0x7483,0x54e9,0x5006,0x806f,
 124.435 +    0x84ee,0x9023,0x942e,0x5ec9,0x6190,0x6f23,0x7c3e,0x6582,0x81c9,0x93c8,
 124.436 +    0x6200,0x7149,0x7df4,0x7ce7,0x51c9,0x6881,0x7cb1,0x826f,0x5169,0x8f1b,
 124.437 +    0x91cf,0x667e,0x4eae,0x8ad2,0x64a9,0x804a,0x50da,0x7642,0x71ce,0x5be5,
 124.438 +    0x907c,0x6f66,0x4e86,0x6482,0x9410,0x5ed6,0x6599,0x5217,0x88c2,0x70c8,
 124.439 +    0x52a3,0x7375,0x7433,0x6797,0x78f7,0x9716,0x81e8,0x9130,0x9c57,0x6dcb,
 124.440 +    0x51db,0x8cc3,0x541d,0x62ce,0x73b2,0x83f1,0x96f6,0x9f61,0x9234,0x4f36,
 124.441 +    0x7f9a,0x51cc,0x9748,0x9675,0x5dba,0x9818,0x53e6,0x4ee4,0x6e9c,0x7409,
 124.442 +    0x69b4,0x786b,0x993e,0x7559,0x5289,0x7624,0x6d41,0x67f3,0x516d,0x9f8d,
 124.443 +    0x807e,0x56a8,0x7c60,0x7abf
 124.444 +  },
 124.445 +  {				/* ku 22 */
 124.446 +    0x9686,0x58df,0x650f,0x96b4,0x6a13,0x5a41,0x645f,0x7c0d,0x6f0f,0x964b,
 124.447 +    0x8606,0x76e7,0x9871,0x5eec,0x7210,0x64c4,0x6ef7,0x865c,0x9b6f,0x9e93,
 124.448 +    0x788c,0x9732,0x8def,0x8cc2,0x9e7f,0x6f5e,0x7984,0x9332,0x9678,0x622e,
 124.449 +    0x9a62,0x5415,0x92c1,0x4fa3,0x65c5,0x5c65,0x5c62,0x7e37,0x616e,0x6c2f,
 124.450 +    0x5f8b,0x7387,0x6ffe,0x7dd1,0x5dd2,0x6523,0x5b7f,0x7064,0x5375,0x4e82,
 124.451 +    0x63a0,0x7565,0x6384,0x8f2a,0x502b,0x4f96,0x6dea,0x7db8,0x8ad6,0x863f,
 124.452 +    0x87ba,0x7f85,0x908f,0x947c,0x7c6e,0x9a3e,0x88f8,0x843d,0x6d1b,0x99f1,
 124.453 +    0x7d61,0x5abd,0x9ebb,0x746a,0x78bc,0x879e,0x99ac,0x99e1,0x561b,0x55ce,
 124.454 +    0x57cb,0x8cb7,0x9ea5,0x8ce3,0x9081,0x8109,0x779e,0x9945,0x883b,0x6eff,
 124.455 +    0x8513,0x66fc,0x6162,0x6f2b
 124.456 +  },
 124.457 +  {				/* ku 23 */
 124.458 +    0x8b3e,0x8292,0x832b,0x76f2,0x6c13,0x5fd9,0x83bd,0x732b,0x8305,0x9328,
 124.459 +    0x6bdb,0x77db,0x925a,0x536f,0x8302,0x5192,0x5e3d,0x8c8c,0x8cbf,0x9ebd,
 124.460 +    0x73ab,0x679a,0x6885,0x9176,0x9709,0x7164,0x6ca1,0x7709,0x5a92,0x9382,
 124.461 +    0x6bcf,0x7f8e,0x6627,0x5bd0,0x59b9,0x5a9a,0x9580,0x60b6,0x5011,0x840c,
 124.462 +    0x8499,0x6aac,0x76df,0x9333,0x731b,0x5922,0x5b5f,0x772f,0x919a,0x9761,
 124.463 +    0x7cdc,0x8ff7,0x8b0e,0x5f4c,0x7c73,0x79d8,0x8993,0x6ccc,0x871c,0x5bc6,
 124.464 +    0x5e42,0x68c9,0x7720,0x7dbf,0x5195,0x514d,0x52c9,0x5a29,0x7dec,0x9762,
 124.465 +    0x82d7,0x63cf,0x7784,0x85d0,0x79d2,0x6e3a,0x5edf,0x5999,0x8511,0x6ec5,
 124.466 +    0x6c11,0x62bf,0x76bf,0x654f,0x61ab,0x95a9,0x660e,0x879f,0x9cf4,0x9298,
 124.467 +    0x540d,0x547d,0x8b2c,0x6478
 124.468 +  },
 124.469 +  {				/* ku 24 */
 124.470 +    0x6479,0x8611,0x6a21,0x819c,0x78e8,0x6469,0x9b54,0x62b9,0x672b,0x83ab,
 124.471 +    0x58a8,0x9ed8,0x6cab,0x6f20,0x5bde,0x964c,0x8b00,0x725f,0x67d0,0x62c7,
 124.472 +    0x7261,0x755d,0x59c6,0x6bcd,0x5893,0x66ae,0x5e55,0x52df,0x6155,0x6728,
 124.473 +    0x76ee,0x7766,0x7267,0x7a46,0x62ff,0x54ea,0x5450,0x9209,0x90a3,0x5a1c,
 124.474 +    0x7d0d,0x6c16,0x4e43,0x5976,0x8010,0x5948,0x5357,0x7537,0x96e3,0x56ca,
 124.475 +    0x6493,0x8166,0x60f1,0x9b27,0x6dd6,0x5462,0x9912,0x5185,0x5ae9,0x80fd,
 124.476 +    0x59ae,0x9713,0x502a,0x6ce5,0x5c3c,0x64ec,0x4f60,0x533f,0x81a9,0x9006,
 124.477 +    0x6eba,0x852b,0x62c8,0x5e74,0x78be,0x6506,0x637b,0x5ff5,0x5a18,0x91c0,
 124.478 +    0x9ce5,0x5c3f,0x634f,0x8076,0x5b7d,0x5699,0x9477,0x93b3,0x6d85,0x60a8,
 124.479 +    0x6ab8,0x7370,0x51dd,0x5be7
 124.480 +  },
 124.481 +  {				/* ku 25 */
 124.482 +    0x64f0,0x6fd8,0x725b,0x626d,0x9215,0x7d10,0x81bf,0x6fc3,0x8fb2,0x5f04,
 124.483 +    0x5974,0x52aa,0x6012,0x5973,0x6696,0x8650,0x7627,0x632a,0x61e6,0x7cef,
 124.484 +    0x8afe,0x54e6,0x6b50,0x9dd7,0x6bc6,0x85d5,0x5614,0x5076,0x6f1a,0x556a,
 124.485 +    0x8db4,0x722c,0x5e15,0x6015,0x7436,0x62cd,0x6392,0x724c,0x5f98,0x6e43,
 124.486 +    0x6d3e,0x6500,0x6f58,0x76e4,0x78d0,0x76fc,0x7554,0x5224,0x53db,0x4e53,
 124.487 +    0x9f90,0x65c1,0x802a,0x80d6,0x629b,0x5486,0x5228,0x70ae,0x888d,0x8dd1,
 124.488 +    0x6ce1,0x5478,0x80da,0x57f9,0x88f4,0x8ce0,0x966a,0x914d,0x4f69,0x6c9b,
 124.489 +    0x5674,0x76c6,0x7830,0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da,0x787c,
 124.490 +    0x7bf7,0x81a8,0x670b,0x9d6c,0x6367,0x78b0,0x576f,0x7812,0x9739,0x6279,
 124.491 +    0x62ab,0x5288,0x7435,0x6bd7
 124.492 +  },
 124.493 +  {				/* ku 26 */
 124.494 +    0x5564,0x813e,0x75b2,0x76ae,0x5339,0x75de,0x50fb,0x5c41,0x8b6c,0x7bc7,
 124.495 +    0x504f,0x7247,0x9a19,0x98c4,0x6f02,0x74e2,0x7968,0x6487,0x77a5,0x62fc,
 124.496 +    0x983b,0x8ca7,0x54c1,0x8058,0x4e52,0x576a,0x860b,0x840d,0x5e73,0x6191,
 124.497 +    0x74f6,0x8a55,0x5c4f,0x5761,0x6f51,0x9817,0x5a46,0x7834,0x9b44,0x8feb,
 124.498 +    0x7c95,0x5256,0x64b2,0x92ea,0x50d5,0x8386,0x8461,0x83e9,0x84b2,0x57d4,
 124.499 +    0x6a38,0x5703,0x666e,0x6d66,0x8b5c,0x66dd,0x7011,0x671f,0x6b3a,0x68f2,
 124.500 +    0x621a,0x59bb,0x4e03,0x51c4,0x6f06,0x67d2,0x6c8f,0x5176,0x68cb,0x5947,
 124.501 +    0x6b67,0x7566,0x5d0e,0x81cd,0x9f4a,0x65d7,0x7948,0x7941,0x9a0e,0x8d77,
 124.502 +    0x8c48,0x4e5e,0x4f01,0x5553,0x5951,0x780c,0x5668,0x6c23,0x8fc4,0x68c4,
 124.503 +    0x6c7d,0x6ce3,0x8a16,0x6390
 124.504 +  },
 124.505 +  {				/* ku 27 */
 124.506 +    0x6070,0x6d3d,0x727d,0x6266,0x91fa,0x925b,0x5343,0x9077,0x7c3d,0x4edf,
 124.507 +    0x8b19,0x4e7e,0x9ed4,0x9322,0x9257,0x524d,0x6f5b,0x9063,0x6dfa,0x8b74,
 124.508 +    0x5879,0x5d4c,0x6b20,0x6b49,0x69cd,0x55c6,0x8154,0x7f8c,0x58bb,0x8594,
 124.509 +    0x5f3a,0x6436,0x6a47,0x936c,0x6572,0x6084,0x6a4b,0x77a7,0x55ac,0x50d1,
 124.510 +    0x5de7,0x9798,0x64ac,0x7ff9,0x5ced,0x4fcf,0x7ac5,0x5207,0x8304,0x4e14,
 124.511 +    0x602f,0x7aca,0x6b3d,0x4fb5,0x89aa,0x79e6,0x7434,0x52e4,0x82b9,0x64d2,
 124.512 +    0x79bd,0x5be2,0x6c81,0x9752,0x8f15,0x6c2b,0x50be,0x537f,0x6e05,0x64ce,
 124.513 +    0x6674,0x6c30,0x60c5,0x9803,0x8acb,0x6176,0x74ca,0x7aae,0x79cb,0x4e18,
 124.514 +    0x90b1,0x7403,0x6c42,0x56da,0x914b,0x6cc5,0x8da8,0x5340,0x86c6,0x66f2,
 124.515 +    0x8ec0,0x5c48,0x9a45,0x6e20
 124.516 +  },
 124.517 +  {				/* ku 28 */
 124.518 +    0x53d6,0x5a36,0x9f72,0x8da3,0x53bb,0x5708,0x9874,0x6b0a,0x919b,0x6cc9,
 124.519 +    0x5168,0x75ca,0x62f3,0x72ac,0x5238,0x52f8,0x7f3a,0x7094,0x7638,0x5374,
 124.520 +    0x9d72,0x69b7,0x78ba,0x96c0,0x88d9,0x7fa4,0x7136,0x71c3,0x5189,0x67d3,
 124.521 +    0x74e4,0x58e4,0x6518,0x56b7,0x8b93,0x9952,0x64fe,0x7e5e,0x60f9,0x71b1,
 124.522 +    0x58ec,0x4ec1,0x4eba,0x5fcd,0x97cc,0x4efb,0x8a8d,0x5203,0x598a,0x7d09,
 124.523 +    0x6254,0x4ecd,0x65e5,0x620e,0x8338,0x84c9,0x69ae,0x878d,0x7194,0x6eb6,
 124.524 +    0x5bb9,0x7d68,0x5197,0x63c9,0x67d4,0x8089,0x8339,0x8815,0x5112,0x5b7a,
 124.525 +    0x5982,0x8fb1,0x4e73,0x6c5d,0x5165,0x8925,0x8edf,0x962e,0x854a,0x745e,
 124.526 +    0x92ed,0x958f,0x6f64,0x82e5,0x5f31,0x6492,0x7051,0x85a9,0x816e,0x9c13,
 124.527 +    0x585e,0x8cfd,0x4e09,0x53c1
 124.528 +  },
 124.529 +  {				/* ku 29 */
 124.530 +    0x5098,0x6563,0x6851,0x55d3,0x55aa,0x6414,0x9a37,0x6383,0x5ac2,0x745f,
 124.531 +    0x8272,0x6f80,0x68ee,0x50e7,0x838e,0x7802,0x6bba,0x5239,0x6c99,0x7d17,
 124.532 +    0x50bb,0x5565,0x715e,0x7be9,0x66ec,0x73ca,0x82eb,0x6749,0x5c71,0x5220,
 124.533 +    0x717d,0x886b,0x9583,0x965d,0x64c5,0x8d0d,0x81b3,0x5584,0x6c55,0x6247,
 124.534 +    0x7e55,0x5892,0x50b7,0x5546,0x8cde,0x664c,0x4e0a,0x5c1a,0x88f3,0x68a2,
 124.535 +    0x634e,0x7a0d,0x71d2,0x828d,0x52fa,0x97f6,0x5c11,0x54e8,0x90b5,0x7d39,
 124.536 +    0x5962,0x8cd2,0x86c7,0x820c,0x6368,0x8d66,0x651d,0x5c04,0x61fe,0x6d89,
 124.537 +    0x793e,0x8a2d,0x7837,0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20,0x7d33,
 124.538 +    0x795e,0x6c88,0x5be9,0x5b38,0x751a,0x814e,0x614e,0x6ef2,0x8072,0x751f,
 124.539 +    0x7525,0x7272,0x5347,0x7e69
 124.540 +  },
 124.541 +  {				/* ku 2a */
 124.542 +    0x7701,0x76db,0x5269,0x52dd,0x8056,0x5e2b,0x5931,0x7345,0x65bd,0x6fd5,
 124.543 +    0x8a69,0x5c38,0x8671,0x5341,0x77f3,0x62fe,0x6642,0x4ec0,0x98df,0x8755,
 124.544 +    0x5be6,0x8b58,0x53f2,0x77e2,0x4f7f,0x5c4e,0x99db,0x59cb,0x5f0f,0x793a,
 124.545 +    0x58eb,0x4e16,0x67ff,0x4e8b,0x62ed,0x8a93,0x901d,0x52e2,0x662f,0x55dc,
 124.546 +    0x566c,0x9069,0x4ed5,0x4f8d,0x91cb,0x98fe,0x6c0f,0x5e02,0x6043,0x5ba4,
 124.547 +    0x8996,0x8a66,0x6536,0x624b,0x9996,0x5b88,0x58fd,0x6388,0x552e,0x53d7,
 124.548 +    0x7626,0x7378,0x852c,0x6a1e,0x68b3,0x6b8a,0x6292,0x8f38,0x53d4,0x8212,
 124.549 +    0x6dd1,0x758f,0x66f8,0x8d16,0x5b70,0x719f,0x85af,0x6691,0x66d9,0x7f72,
 124.550 +    0x8700,0x9ecd,0x9f20,0x5c6c,0x8853,0x8ff0,0x6a39,0x675f,0x620d,0x7aea,
 124.551 +    0x5885,0x5eb6,0x6578,0x6f31
 124.552 +  },
 124.553 +  {				/* ku 2b */
 124.554 +    0x6055,0x5237,0x800d,0x6454,0x8870,0x7529,0x5e25,0x6813,0x62f4,0x971c,
 124.555 +    0x96d9,0x723d,0x8ab0,0x6c34,0x7761,0x7a0e,0x542e,0x77ac,0x9806,0x821c,
 124.556 +    0x8aac,0x78a9,0x6714,0x720d,0x65af,0x6495,0x5636,0x601d,0x79c1,0x53f8,
 124.557 +    0x7d72,0x6b7b,0x8086,0x5bfa,0x55e3,0x56db,0x4f3a,0x4f3c,0x98fc,0x5df3,
 124.558 +    0x9b06,0x8073,0x616b,0x980c,0x9001,0x5b8b,0x8a1f,0x8aa6,0x641c,0x8258,
 124.559 +    0x64fb,0x55fd,0x8607,0x9165,0x4fd7,0x7d20,0x901f,0x7c9f,0x50f3,0x5851,
 124.560 +    0x6eaf,0x5bbf,0x8a34,0x8085,0x9178,0x849c,0x7b97,0x96d6,0x968b,0x96a8,
 124.561 +    0x7d8f,0x9ad3,0x788e,0x6b72,0x7a57,0x9042,0x96a7,0x795f,0x5b6b,0x640d,
 124.562 +    0x7b0b,0x84d1,0x68ad,0x5506,0x7e2e,0x7463,0x7d22,0x9396,0x6240,0x584c,
 124.563 +    0x4ed6,0x5b83,0x5979,0x5854
 124.564 +  },
 124.565 +  {				/* ku 2c */
 124.566 +    0x737a,0x64bb,0x8e4b,0x8e0f,0x80ce,0x82d4,0x62ac,0x81fa,0x6cf0,0x915e,
 124.567 +    0x592a,0x614b,0x6c70,0x574d,0x6524,0x8caa,0x7671,0x7058,0x58c7,0x6a80,
 124.568 +    0x75f0,0x6f6d,0x8b5a,0x8ac7,0x5766,0x6bef,0x8892,0x78b3,0x63a2,0x5606,
 124.569 +    0x70ad,0x6e6f,0x5858,0x642a,0x5802,0x68e0,0x819b,0x5510,0x7cd6,0x5018,
 124.570 +    0x8eba,0x6dcc,0x8d9f,0x71d9,0x638f,0x6fe4,0x6ed4,0x7e27,0x8404,0x6843,
 124.571 +    0x9003,0x6dd8,0x9676,0x8a0e,0x5957,0x7279,0x85e4,0x9a30,0x75bc,0x8b04,
 124.572 +    0x68af,0x5254,0x8e22,0x92bb,0x63d0,0x984c,0x8e44,0x557c,0x9ad4,0x66ff,
 124.573 +    0x568f,0x60d5,0x6d95,0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530,0x751c,
 124.574 +    0x606c,0x8214,0x8146,0x6311,0x689d,0x8fe2,0x773a,0x8df3,0x8cbc,0x9435,
 124.575 +    0x5e16,0x5ef3,0x807d,0x70f4
 124.576 +  },
 124.577 +  {				/* ku 2d */
 124.578 +    0x6c40,0x5ef7,0x505c,0x4ead,0x5ead,0x633a,0x8247,0x901a,0x6850,0x916e,
 124.579 +    0x77b3,0x540c,0x9285,0x5f64,0x7ae5,0x6876,0x6345,0x7b52,0x7d71,0x75db,
 124.580 +    0x5077,0x6295,0x982d,0x900f,0x51f8,0x79c3,0x7a81,0x5716,0x5f92,0x9014,
 124.581 +    0x5857,0x5c60,0x571f,0x5410,0x5154,0x6e4d,0x5718,0x63a8,0x983d,0x817f,
 124.582 +    0x8715,0x892a,0x9000,0x541e,0x5c6f,0x81c0,0x62d6,0x6258,0x8131,0x9d15,
 124.583 +    0x9640,0x99b1,0x99dd,0x6a62,0x59a5,0x62d3,0x553e,0x6316,0x54c7,0x86d9,
 124.584 +    0x7aaa,0x5a03,0x74e6,0x896a,0x6b6a,0x5916,0x8c4c,0x5f4e,0x7063,0x73a9,
 124.585 +    0x9811,0x4e38,0x70f7,0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb,0x5b9b,
 124.586 +    0x5a49,0x842c,0x8155,0x6c6a,0x738b,0x4ea1,0x6789,0x7db2,0x5f80,0x65fa,
 124.587 +    0x671b,0x5fd8,0x5984,0x5a01
 124.588 +  },
 124.589 +  {				/* ku 2e */
 124.590 +    0x5dcd,0x5fae,0x5371,0x97cb,0x9055,0x6845,0x570d,0x552f,0x60df,0x7232,
 124.591 +    0x6ff0,0x7dad,0x8466,0x840e,0x59d4,0x5049,0x50de,0x5c3e,0x7def,0x672a,
 124.592 +    0x851a,0x5473,0x754f,0x80c3,0x5582,0x9b4f,0x4f4d,0x6e2d,0x8b02,0x5c09,
 124.593 +    0x6170,0x885b,0x761f,0x6e29,0x868a,0x6587,0x805e,0x7d0b,0x543b,0x7a69,
 124.594 +    0x7d0a,0x554f,0x55e1,0x7fc1,0x74ee,0x64be,0x8778,0x6e26,0x7aa9,0x6211,
 124.595 +    0x65a1,0x5367,0x63e1,0x6c83,0x5deb,0x55da,0x93a2,0x70cf,0x6c61,0x8aa3,
 124.596 +    0x5c4b,0x7121,0x856a,0x68a7,0x543e,0x5434,0x6bcb,0x6b66,0x4e94,0x6342,
 124.597 +    0x5348,0x821e,0x4f0d,0x4fae,0x5862,0x620a,0x9727,0x6664,0x7269,0x52ff,
 124.598 +    0x52d9,0x609f,0x8aa4,0x6614,0x7199,0x6790,0x897f,0x7852,0x77fd,0x6670,
 124.599 +    0x563b,0x5438,0x932b,0x72a7
 124.600 +  },
 124.601 +  {				/* ku 2f */
 124.602 +    0x7a00,0x606f,0x5e0c,0x6089,0x819d,0x5915,0x60dc,0x7184,0x70ef,0x6eaa,
 124.603 +    0x6c50,0x7280,0x6a84,0x8972,0x5e2d,0x7fd2,0x5ab3,0x559c,0x9291,0x6d17,
 124.604 +    0x7cfb,0x9699,0x6232,0x7d30,0x778e,0x8766,0x5323,0x971e,0x8f44,0x6687,
 124.605 +    0x5cfd,0x4fe0,0x72f9,0x4e0b,0x53a6,0x590f,0x5687,0x6380,0x9341,0x5148,
 124.606 +    0x4ed9,0x9bae,0x7e96,0x54b8,0x8ce2,0x929c,0x8237,0x9591,0x6d8e,0x5f26,
 124.607 +    0x5acc,0x986f,0x96aa,0x73fe,0x737b,0x7e23,0x817a,0x9921,0x7fa1,0x61b2,
 124.608 +    0x9677,0x9650,0x7dab,0x76f8,0x53a2,0x9472,0x9999,0x7bb1,0x8944,0x6e58,
 124.609 +    0x9109,0x7fd4,0x7965,0x8a73,0x60f3,0x97ff,0x4eab,0x9805,0x5df7,0x6a61,
 124.610 +    0x50cf,0x5411,0x8c61,0x856d,0x785d,0x9704,0x524a,0x54ee,0x56c2,0x92b7,
 124.611 +    0x6d88,0x5bb5,0x6dc6,0x66c9
 124.612 +  },
 124.613 +  {				/* ku 30 */
 124.614 +    0x5c0f,0x5b5d,0x6821,0x8096,0x562f,0x7b11,0x6548,0x6954,0x4e9b,0x6b47,
 124.615 +    0x874e,0x978b,0x5354,0x633e,0x643a,0x90aa,0x659c,0x8105,0x8ae7,0x5beb,
 124.616 +    0x68b0,0x5378,0x87f9,0x61c8,0x6cc4,0x7009,0x8b1d,0x5c51,0x85aa,0x82af,
 124.617 +    0x92c5,0x6b23,0x8f9b,0x65b0,0x5ffb,0x5fc3,0x4fe1,0x91c1,0x661f,0x8165,
 124.618 +    0x7329,0x60fa,0x8208,0x5211,0x578b,0x5f62,0x90a2,0x884c,0x9192,0x5e78,
 124.619 +    0x674f,0x6027,0x59d3,0x5144,0x51f6,0x80f8,0x5308,0x6c79,0x96c4,0x718a,
 124.620 +    0x4f11,0x4fee,0x7f9e,0x673d,0x55c5,0x92b9,0x79c0,0x8896,0x7d89,0x589f,
 124.621 +    0x620c,0x9700,0x865a,0x5618,0x9808,0x5f90,0x8a31,0x84c4,0x9157,0x53d9,
 124.622 +    0x65ed,0x5e8f,0x755c,0x6064,0x7d6e,0x5a7f,0x7dd2,0x7e8c,0x8ed2,0x55a7,
 124.623 +    0x5ba3,0x61f8,0x65cb,0x7384
 124.624 +  },
 124.625 +  {				/* ku 31 */
 124.626 +    0x9078,0x766c,0x7729,0x7d62,0x9774,0x859b,0x5b78,0x7a74,0x96ea,0x8840,
 124.627 +    0x52db,0x718f,0x5faa,0x65ec,0x8a62,0x5c0b,0x99b4,0x5de1,0x6b89,0x6c5b,
 124.628 +    0x8a13,0x8a0a,0x905c,0x8fc5,0x58d3,0x62bc,0x9d09,0x9d28,0x5440,0x4e2b,
 124.629 +    0x82bd,0x7259,0x869c,0x5d16,0x8859,0x6daf,0x96c5,0x555e,0x4e9e,0x8a1d,
 124.630 +    0x7109,0x54bd,0x95b9,0x70df,0x6df9,0x9e7d,0x56b4,0x7814,0x8712,0x5ca9,
 124.631 +    0x5ef6,0x8a00,0x9854,0x95bb,0x708e,0x6cbf,0x5944,0x63a9,0x773c,0x884d,
 124.632 +    0x6f14,0x8277,0x5830,0x71d5,0x53ad,0x786f,0x96c1,0x5501,0x5f66,0x7130,
 124.633 +    0x5bb4,0x8afa,0x9a57,0x6b83,0x592e,0x9d26,0x79e7,0x694a,0x63da,0x4f6f,
 124.634 +    0x760d,0x7f8a,0x6d0b,0x967d,0x6c27,0x4ef0,0x7662,0x990a,0x6a23,0x6f3e,
 124.635 +    0x9080,0x8170,0x5996,0x7476
 124.636 +  },
 124.637 +  {				/* ku 32 */
 124.638 +    0x6447,0x582f,0x9065,0x7a91,0x8b21,0x59da,0x54ac,0x8200,0x85e5,0x8981,
 124.639 +    0x8000,0x6930,0x564e,0x8036,0x723a,0x91ce,0x51b6,0x4e5f,0x9801,0x6396,
 124.640 +    0x696d,0x8449,0x66f3,0x814b,0x591c,0x6db2,0x4e00,0x58f9,0x91ab,0x63d6,
 124.641 +    0x92a5,0x4f9d,0x4f0a,0x8863,0x9824,0x5937,0x907a,0x79fb,0x5100,0x80f0,
 124.642 +    0x7591,0x6c82,0x5b9c,0x59e8,0x5f5d,0x6905,0x87fb,0x501a,0x5df2,0x4e59,
 124.643 +    0x77e3,0x4ee5,0x85dd,0x6291,0x6613,0x9091,0x5c79,0x5104,0x5f79,0x81c6,
 124.644 +    0x9038,0x8084,0x75ab,0x4ea6,0x88d4,0x610f,0x6bc5,0x61b6,0x7fa9,0x76ca,
 124.645 +    0x6ea2,0x8a63,0x8b70,0x8abc,0x8b6f,0x5f02,0x7ffc,0x7fcc,0x7e79,0x8335,
 124.646 +    0x852d,0x56e0,0x6bb7,0x97f3,0x9670,0x59fb,0x541f,0x9280,0x6deb,0x5bc5,
 124.647 +    0x98f2,0x5c39,0x5f15,0x96b1
 124.648 +  },
 124.649 +  {				/* ku 33 */
 124.650 +    0x5370,0x82f1,0x6afb,0x5b30,0x9df9,0x61c9,0x7e93,0x7469,0x87a2,0x71df,
 124.651 +    0x7192,0x8805,0x8fce,0x8d0f,0x76c8,0x5f71,0x7a4e,0x786c,0x6620,0x55b2,
 124.652 +    0x64c1,0x50ad,0x81c3,0x7670,0x5eb8,0x96cd,0x8e34,0x86f9,0x548f,0x6cf3,
 124.653 +    0x6d8c,0x6c38,0x607f,0x52c7,0x7528,0x5e7d,0x512a,0x60a0,0x6182,0x5c24,
 124.654 +    0x7531,0x90f5,0x923e,0x7336,0x6cb9,0x6e38,0x9149,0x6709,0x53cb,0x53f3,
 124.655 +    0x4f51,0x91c9,0x8a98,0x53c8,0x5e7c,0x8fc2,0x6de4,0x4e8e,0x76c2,0x6986,
 124.656 +    0x865e,0x611a,0x8f3f,0x9918,0x4fde,0x903e,0x9b5a,0x6109,0x6e1d,0x6f01,
 124.657 +    0x9685,0x4e88,0x5a31,0x96e8,0x8207,0x5dbc,0x79b9,0x5b87,0x8a9e,0x7fbd,
 124.658 +    0x7389,0x57df,0x828b,0x9b31,0x5401,0x9047,0x55bb,0x5cea,0x5fa1,0x6108,
 124.659 +    0x6b32,0x7344,0x80b2,0x8b7d
 124.660 +  },
 124.661 +  {				/* ku 34 */
 124.662 +    0x6d74,0x5bd3,0x88d5,0x9810,0x8c6b,0x99ad,0x9d1b,0x6df5,0x51a4,0x5143,
 124.663 +    0x57a3,0x8881,0x539f,0x63f4,0x8f45,0x5712,0x54e1,0x5713,0x733f,0x6e90,
 124.664 +    0x7de3,0x9060,0x82d1,0x9858,0x6028,0x9662,0x66f0,0x7d04,0x8d8a,0x8e8d,
 124.665 +    0x9470,0x5cb3,0x7ca4,0x6708,0x60a6,0x95b2,0x8018,0x96f2,0x9116,0x5300,
 124.666 +    0x9695,0x5141,0x904b,0x85f4,0x9196,0x6688,0x97f5,0x5b55,0x531d,0x7838,
 124.667 +    0x96dc,0x683d,0x54c9,0x707e,0x5bb0,0x8f09,0x518d,0x5728,0x54b1,0x6522,
 124.668 +    0x66ab,0x8d0a,0x8d1c,0x81df,0x846c,0x906d,0x7cdf,0x947f,0x85fb,0x68d7,
 124.669 +    0x65e9,0x6fa1,0x86a4,0x8e81,0x566a,0x9020,0x7682,0x7ac8,0x71e5,0x8cac,
 124.670 +    0x64c7,0x5247,0x6fa4,0x8cca,0x600e,0x589e,0x618e,0x66fe,0x8d08,0x624e,
 124.671 +    0x55b3,0x6e23,0x672d,0x8ecb
 124.672 +  },
 124.673 +  {				/* ku 35 */
 124.674 +    0x9358,0x9598,0x7728,0x6805,0x69a8,0x548b,0x4e4d,0x70b8,0x8a50,0x6458,
 124.675 +    0x9f4b,0x5b85,0x7a84,0x50b5,0x5be8,0x77bb,0x6c08,0x8a79,0x7c98,0x6cbe,
 124.676 +    0x76de,0x65ac,0x8f3e,0x5d84,0x5c55,0x8638,0x68e7,0x5360,0x6230,0x7ad9,
 124.677 +    0x6e5b,0x7dbb,0x6a1f,0x7ae0,0x5f70,0x6f33,0x5f35,0x638c,0x6f32,0x6756,
 124.678 +    0x4e08,0x5e33,0x8cec,0x4ed7,0x8139,0x7634,0x969c,0x62db,0x662d,0x627e,
 124.679 +    0x6cbc,0x8d99,0x7167,0x7f69,0x5146,0x8087,0x53ec,0x906e,0x6298,0x54f2,
 124.680 +    0x87c4,0x8f4d,0x8005,0x937a,0x8517,0x9019,0x6d59,0x73cd,0x659f,0x771f,
 124.681 +    0x7504,0x7827,0x81fb,0x8c9e,0x91dd,0x5075,0x6795,0x75b9,0x8a3a,0x9707,
 124.682 +    0x632f,0x93ae,0x9663,0x84b8,0x6399,0x775c,0x5f81,0x7319,0x722d,0x6014,
 124.683 +    0x6574,0x62ef,0x6b63,0x653f
 124.684 +  },
 124.685 +  {				/* ku 36 */
 124.686 +    0x5e40,0x7665,0x912d,0x8b49,0x829d,0x679d,0x652f,0x5431,0x8718,0x77e5,
 124.687 +    0x80a2,0x8102,0x6c41,0x4e4b,0x7e54,0x8077,0x76f4,0x690d,0x6b96,0x57f7,
 124.688 +    0x503c,0x4f84,0x5740,0x6307,0x6b62,0x8dbe,0x8879,0x65e8,0x7d19,0x5fd7,
 124.689 +    0x646f,0x64f2,0x81f3,0x81f4,0x7f6e,0x5e5f,0x5cd9,0x5236,0x667a,0x79e9,
 124.690 +    0x7a1a,0x8cea,0x7099,0x75d4,0x6eef,0x6cbb,0x7a92,0x4e2d,0x76c5,0x5fe0,
 124.691 +    0x9418,0x8877,0x7d42,0x7a2e,0x816b,0x91cd,0x4ef2,0x8846,0x821f,0x5468,
 124.692 +    0x5dde,0x6d32,0x8b05,0x7ca5,0x8ef8,0x8098,0x5e1a,0x5492,0x76ba,0x5b99,
 124.693 +    0x665d,0x9a5f,0x73e0,0x682a,0x86db,0x6731,0x732a,0x8af8,0x8a85,0x9010,
 124.694 +    0x7af9,0x71ed,0x716e,0x62c4,0x77da,0x56d1,0x4e3b,0x8457,0x67f1,0x52a9,
 124.695 +    0x86c0,0x8caf,0x9444,0x7bc9
 124.696 +  },
 124.697 +  {				/* ku 37 */
 124.698 +    0x4f4f,0x6ce8,0x795d,0x99d0,0x6293,0x722a,0x62fd,0x5c08,0x78da,0x8f49,
 124.699 +    0x64b0,0x8cfa,0x7bc6,0x6a01,0x838a,0x88dd,0x599d,0x649e,0x58ef,0x72c0,
 124.700 +    0x690e,0x9310,0x8ffd,0x8d05,0x589c,0x7db4,0x8ac4,0x6e96,0x6349,0x62d9,
 124.701 +    0x5353,0x684c,0x7422,0x8301,0x914c,0x5544,0x7740,0x707c,0x6fc1,0x5179,
 124.702 +    0x54a8,0x8cc7,0x59ff,0x6ecb,0x6dc4,0x5b5c,0x7d2b,0x4ed4,0x7c7d,0x6ed3,
 124.703 +    0x5b50,0x81ea,0x6f2c,0x5b57,0x9b03,0x68d5,0x8e2a,0x5b97,0x7d9c,0x7e3d,
 124.704 +    0x7e31,0x9112,0x8d70,0x594f,0x63cd,0x79df,0x8db3,0x5352,0x65cf,0x7956,
 124.705 +    0x8a5b,0x963b,0x7d44,0x947d,0x7e82,0x5634,0x9189,0x6700,0x7f6a,0x5c0a,
 124.706 +    0x9075,0x6628,0x5de6,0x4f50,0x67de,0x505a,0x4f5c,0x5750,0x5ea7,UBOGON,
 124.707 +    UBOGON,UBOGON,UBOGON,UBOGON
 124.708 +  },
 124.709 +  {				/* ku 38 */
 124.710 +    0x4e8d,0x4e0c,0x5140,0x4e10,0x5eff,0x5345,0x4e15,0x4e98,0x4e1e,0x9b32,
 124.711 +    0x5b6c,0x5669,0x4e28,0x79ba,0x4e3f,0x5315,0x4e47,0x592d,0x723b,0x536e,
 124.712 +    0x6c10,0x56df,0x80e4,0x9997,0x6bd3,0x777e,0x9f17,0x4e36,0x4e9f,0x9f10,
 124.713 +    0x4e5c,0x4e69,0x4e93,0x8288,0x5b5b,0x55c7,0x560f,0x4ec4,0x5399,0x539d,
 124.714 +    0x53b4,0x53a5,0x53ae,0x9768,0x8d0b,0x531a,0x53f5,0x532d,0x5331,0x533e,
 124.715 +    0x8cfe,0x5366,0x5363,0x5202,0x5208,0x520e,0x5244,0x5233,0x528c,0x5274,
 124.716 +    0x524c,0x525e,0x5261,0x525c,0x84af,0x527d,0x5282,0x5281,0x5290,0x5293,
 124.717 +    0x5182,0x7f54,0x4ebb,0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb,0x4ede,
 124.718 +    0x50b4,0x4ef3,0x4f22,0x4f64,0x4ef5,0x5000,0x5096,0x4f09,0x4f47,0x4f5e,
 124.719 +    0x4f67,0x6538,0x4f5a,0x4f5d
 124.720 +  },
 124.721 +  {				/* ku 39 */
 124.722 +    0x4f5f,0x4f57,0x4f32,0x4f3d,0x4f76,0x4f74,0x4f91,0x4f89,0x4f83,0x4f8f,
 124.723 +    0x4f7e,0x4f7b,0x5115,0x4f7c,0x5102,0x4f94,0x5114,0x513c,0x5137,0x4fc5,
 124.724 +    0x4fda,0x4fe3,0x4fdc,0x4fd1,0x4fdf,0x4ff8,0x5029,0x504c,0x4ff3,0x502c,
 124.725 +    0x500f,0x502e,0x502d,0x4ffe,0x501c,0x500c,0x5025,0x5028,0x50e8,0x5043,
 124.726 +    0x5055,0x5048,0x504e,0x506c,0x50c2,0x513b,0x5110,0x513a,0x50ba,0x50d6,
 124.727 +    0x5106,0x50ed,0x50ec,0x50e6,0x50ee,0x5107,0x510b,0x4edd,0x6c3d,0x4f58,
 124.728 +    0x50c9,0x4fce,0x9fa0,0x6c46,0x7cf4,0x516e,0x5dfd,0x9ecc,0x9998,0x56c5,
 124.729 +    0x5914,0x52f9,0x530d,0x8a07,0x5310,0x9cec,0x5919,0x5155,0x4ea0,0x5156,
 124.730 +    0x4eb3,0x886e,0x88a4,0x893b,0x81e0,0x88d2,0x7980,0x5b34,0x8803,0x7fb8,
 124.731 +    0x51ab,0x51b1,0x51bd,0x51bc
 124.732 +  },
 124.733 +  {				/* ku 3a */
 124.734 +    0x51c7,0x5196,0x51a2,0x51a5,0x8a01,0x8a10,0x8a0c,0x8a15,0x8b33,0x8a4e,
 124.735 +    0x8a25,0x8a41,0x8a36,0x8a46,0x8a54,0x8a58,0x8a52,0x8a86,0x8a84,0x8a7f,
 124.736 +    0x8a70,0x8a7c,0x8a75,0x8a6c,0x8a6e,0x8acd,0x8ae2,0x8a61,0x8a9a,0x8aa5,
 124.737 +    0x8a91,0x8a92,0x8acf,0x8ad1,0x8ac9,0x8adb,0x8ad7,0x8ac2,0x8ab6,0x8af6,
 124.738 +    0x8aeb,0x8b14,0x8b01,0x8ae4,0x8aed,0x8afc,0x8af3,0x8ae6,0x8aee,0x8ade,
 124.739 +    0x8b28,0x8b9c,0x8b16,0x8b1a,0x8b10,0x8b2b,0x8b2d,0x8b56,0x8b59,0x8b4e,
 124.740 +    0x8b9e,0x8b6b,0x8b96,0x5369,0x537a,0x961d,0x9622,0x9621,0x9631,0x962a,
 124.741 +    0x963d,0x963c,0x9642,0x9658,0x9654,0x965f,0x9689,0x966c,0x9672,0x9674,
 124.742 +    0x9688,0x968d,0x9697,0x96b0,0x9097,0x909b,0x913a,0x9099,0x9114,0x90a1,
 124.743 +    0x90b4,0x90b3,0x90b6,0x9134
 124.744 +  },
 124.745 +  {				/* ku 3b */
 124.746 +    0x90b8,0x90b0,0x90df,0x90c5,0x90be,0x9136,0x90c4,0x90c7,0x9106,0x9148,
 124.747 +    0x90e2,0x90dc,0x90d7,0x90db,0x90eb,0x90ef,0x90fe,0x9104,0x9122,0x911e,
 124.748 +    0x9123,0x9131,0x912f,0x9139,0x9143,0x9146,0x82bb,0x5950,0x52f1,0x52ac,
 124.749 +    0x52ad,0x52be,0x54ff,0x52d0,0x52d6,0x52f0,0x53df,0x71ee,0x77cd,0x5ef4,
 124.750 +    0x51f5,0x51fc,0x9b2f,0x53b6,0x5f01,0x755a,0x5df0,0x574c,0x580a,0x57a1,
 124.751 +    0x587e,0x58bc,0x58c5,0x58d1,0x5729,0x572c,0x572a,0x5733,0x58d9,0x572e,
 124.752 +    0x572f,0x58e2,0x573b,0x5742,0x5769,0x58e0,0x576b,0x58da,0x577c,0x577b,
 124.753 +    0x5768,0x576d,0x5776,0x5773,0x57e1,0x57a4,0x578c,0x584f,0x57cf,0x57a7,
 124.754 +    0x5816,0x5793,0x57a0,0x57d5,0x5852,0x581d,0x5864,0x57d2,0x57b8,0x57f4,
 124.755 +    0x57ef,0x57f8,0x57e4,0x57dd
 124.756 +  },
 124.757 +  {				/* ku 3c */
 124.758 +    0x580b,0x580d,0x57fd,0x57ed,0x5800,0x581e,0x5819,0x5844,0x5820,0x5865,
 124.759 +    0x586c,0x5881,0x5889,0x589a,0x5880,0x99a8,0x9f19,0x61ff,0x8279,0x827d,
 124.760 +    0x827f,0x828f,0x828a,0x82a8,0x8284,0x828e,0x8291,0x858c,0x8299,0x82ab,
 124.761 +    0x8553,0x82be,0x82b0,0x85f6,0x82ca,0x82e3,0x8298,0x82b7,0x82ae,0x83a7,
 124.762 +    0x8407,0x84ef,0x82a9,0x82b4,0x82a1,0x82aa,0x829f,0x82c4,0x82e7,0x82a4,
 124.763 +    0x82e1,0x8309,0x82f7,0x82e4,0x8622,0x8307,0x82dc,0x82f4,0x82d2,0x82d8,
 124.764 +    0x830c,0x82fb,0x82d3,0x8526,0x831a,0x8306,0x584b,0x7162,0x82e0,0x82d5,
 124.765 +    0x831c,0x8351,0x8558,0x84fd,0x8308,0x8392,0x833c,0x8334,0x8331,0x839b,
 124.766 +    0x854e,0x832f,0x834f,0x8347,0x8343,0x8588,0x8340,0x8317,0x85ba,0x832d,
 124.767 +    0x833a,0x8333,0x7296,0x6ece
 124.768 +  },
 124.769 +  {				/* ku 3d */
 124.770 +    0x8541,0x831b,0x85ce,0x8552,0x84c0,0x8452,0x8464,0x83b0,0x8378,0x8494,
 124.771 +    0x8435,0x83a0,0x83aa,0x8393,0x839c,0x8385,0x837c,0x859f,0x83a9,0x837d,
 124.772 +    0x8555,0x837b,0x8398,0x839e,0x83a8,0x9daf,0x8493,0x83c1,0x8401,0x83e5,
 124.773 +    0x83d8,0x5807,0x8418,0x840b,0x83dd,0x83fd,0x83d6,0x841c,0x8438,0x8411,
 124.774 +    0x8406,0x83d4,0x83df,0x840f,0x8403,0x83f8,0x83f9,0x83ea,0x83c5,0x83c0,
 124.775 +    0x7e08,0x83f0,0x83e1,0x845c,0x8451,0x845a,0x8459,0x8473,0x8546,0x8488,
 124.776 +    0x847a,0x8562,0x8478,0x843c,0x8446,0x8469,0x8476,0x851e,0x848e,0x8431,
 124.777 +    0x846d,0x84c1,0x84cd,0x84d0,0x9a40,0x84bd,0x84d3,0x84ca,0x84bf,0x84ba,
 124.778 +    0x863a,0x84a1,0x84b9,0x84b4,0x8497,0x93a3,0x8577,0x850c,0x750d,0x8538,
 124.779 +    0x84f0,0x861e,0x851f,0x85fa
 124.780 +  },
 124.781 +  {				/* ku 3e */
 124.782 +    0x8556,0x853b,0x84ff,0x84fc,0x8559,0x8548,0x8568,0x8564,0x855e,0x857a,
 124.783 +    0x77a2,0x8543,0x8604,0x857b,0x85a4,0x85a8,0x8587,0x858f,0x8579,0x85ea,
 124.784 +    0x859c,0x8585,0x85b9,0x85b7,0x85b0,0x861a,0x85c1,0x85dc,0x85ff,0x8627,
 124.785 +    0x8605,0x8629,0x8616,0x863c,0x5efe,0x5f08,0x593c,0x5969,0x8037,0x5955,
 124.786 +    0x595a,0x5958,0x530f,0x5c22,0x5c25,0x5c2c,0x5c37,0x624c,0x636b,0x6476,
 124.787 +    0x62bb,0x62ca,0x62da,0x62d7,0x62ee,0x649f,0x62f6,0x6339,0x634b,0x6343,
 124.788 +    0x63ad,0x63f6,0x6371,0x637a,0x638e,0x6451,0x636d,0x63ac,0x638a,0x6369,
 124.789 +    0x63ae,0x645c,0x63f2,0x63f8,0x63e0,0x64b3,0x63c4,0x63de,0x63ce,0x6452,
 124.790 +    0x63c6,0x63be,0x6504,0x6441,0x640b,0x641b,0x6420,0x640c,0x6426,0x6421,
 124.791 +    0x645e,0x6516,0x646d,0x6496
 124.792 +  },
 124.793 +  {				/* ku 3f */
 124.794 +    0x647a,0x64f7,0x64fc,0x6499,0x651b,0x64c0,0x64d0,0x64d7,0x64e4,0x64e2,
 124.795 +    0x6509,0x6525,0x652e,0x5f0b,0x5fd2,0x7519,0x5f11,0x535f,0x53f1,0x5630,
 124.796 +    0x53e9,0x53e8,0x53fb,0x5412,0x5416,0x5406,0x544b,0x5638,0x56c8,0x5454,
 124.797 +    0x56a6,0x5443,0x5421,0x5504,0x54bc,0x5423,0x5432,0x5482,0x5494,0x5477,
 124.798 +    0x5471,0x5464,0x549a,0x5680,0x5484,0x5476,0x5466,0x565d,0x54d0,0x54ad,
 124.799 +    0x54c2,0x54b4,0x5660,0x54a7,0x54a6,0x5635,0x55f6,0x5472,0x54a3,0x5666,
 124.800 +    0x54bb,0x54bf,0x54cc,0x5672,0x54da,0x568c,0x54a9,0x54aa,0x54a4,0x5665,
 124.801 +    0x54cf,0x54de,0x561c,0x54e7,0x562e,0x54fd,0x5514,0x54f3,0x55e9,0x5523,
 124.802 +    0x550f,0x5511,0x5527,0x552a,0x5616,0x558f,0x55b5,0x5549,0x56c0,0x5541,
 124.803 +    0x5555,0x553f,0x5550,0x553c
 124.804 +  },
 124.805 +  {				/* ku 40 */
 124.806 +    0x5537,0x5556,0x5575,0x5576,0x5577,0x5533,0x5530,0x555c,0x558b,0x55d2,
 124.807 +    0x5583,0x55b1,0x55b9,0x5588,0x5581,0x559f,0x557e,0x55d6,0x5591,0x557b,
 124.808 +    0x55df,0x560d,0x56b3,0x5594,0x5599,0x55ea,0x55f7,0x55c9,0x561f,0x55d1,
 124.809 +    0x56c1,0x55ec,0x55d4,0x55e6,0x55dd,0x55c4,0x55ef,0x55e5,0x55f2,0x566f,
 124.810 +    0x55cc,0x55cd,0x55e8,0x55f5,0x55e4,0x8f61,0x561e,0x5608,0x560c,0x5601,
 124.811 +    0x56b6,0x5623,0x55fe,0x5600,0x5627,0x562d,0x5658,0x5639,0x5657,0x562c,
 124.812 +    0x564d,0x5662,0x5659,0x5695,0x564c,0x5654,0x5686,0x5664,0x5671,0x566b,
 124.813 +    0x567b,0x567c,0x5685,0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1,0x5707,
 124.814 +    0x56eb,0x56f9,0x56ff,0x5704,0x570a,0x5709,0x571c,0x5e43,0x5e19,0x5e14,
 124.815 +    0x5e11,0x5e6c,0x5e58,0x5e57
 124.816 +  },
 124.817 +  {				/* ku 41 */
 124.818 +    0x5e37,0x5e44,0x5e54,0x5e5b,0x5e5e,0x5e61,0x5c8c,0x5c7a,0x5c8d,0x5c90,
 124.819 +    0x5d87,0x5c88,0x5cf4,0x5c99,0x5c91,0x5d50,0x5c9c,0x5cb5,0x5ca2,0x5d2c,
 124.820 +    0x5cac,0x5cab,0x5cb1,0x5ca3,0x5cc1,0x5cb7,0x5da7,0x5cd2,0x5da0,0x5ccb,
 124.821 +    0x5d22,0x5d97,0x5d0d,0x5d27,0x5d26,0x5d2e,0x5d24,0x5d1e,0x5d06,0x5d1b,
 124.822 +    0x5db8,0x5d3e,0x5d34,0x5d3d,0x5d6c,0x5d5b,0x5d6f,0x5d81,0x5d6b,0x5d4b,
 124.823 +    0x5d4a,0x5d69,0x5d74,0x5d82,0x5d99,0x5d9d,0x8c73,0x5db7,0x5dd4,0x5f73,
 124.824 +    0x5f77,0x5f82,0x5f87,0x5f89,0x540e,0x5fa0,0x5f99,0x5f9c,0x5fa8,0x5fad,
 124.825 +    0x5fb5,0x5fbc,0x8862,0x5f61,0x72ad,0x72b0,0x72b4,0x7377,0x7341,0x72c3,
 124.826 +    0x72c1,0x72ce,0x72cd,0x72d2,0x72e8,0x736a,0x72e9,0x733b,0x72f4,0x72f7,
 124.827 +    0x7301,0x72f3,0x736b,0x72fa
 124.828 +  },
 124.829 +  {				/* ku 42 */
 124.830 +    0x72fb,0x7317,0x7313,0x7380,0x730a,0x731e,0x731d,0x737c,0x7322,0x7339,
 124.831 +    0x7325,0x732c,0x7338,0x7331,0x7350,0x734d,0x7357,0x7360,0x736c,0x736f,
 124.832 +    0x737e,0x821b,0x5925,0x98e7,0x5924,0x5902,0x98e0,0x9933,0x98e9,0x993c,
 124.833 +    0x98ea,0x98eb,0x98ed,0x98f4,0x9909,0x9911,0x4f59,0x991b,0x9937,0x993f,
 124.834 +    0x9943,0x9948,0x9949,0x994a,0x994c,0x9962,0x5e80,0x5ee1,0x5e8b,0x5e96,
 124.835 +    0x5ea5,0x5ea0,0x5eb9,0x5eb5,0x5ebe,0x5eb3,0x8ce1,0x5ed2,0x5ed1,0x5edb,
 124.836 +    0x5ee8,0x5eea,0x81ba,0x5fc4,0x5fc9,0x5fd6,0x61fa,0x61ae,0x5fee,0x616a,
 124.837 +    0x5fe1,0x5fe4,0x613e,0x60b5,0x6134,0x5fea,0x5fed,0x5ff8,0x6019,0x6035,
 124.838 +    0x6026,0x601b,0x600f,0x600d,0x6029,0x602b,0x600a,0x61cc,0x6021,0x615f,
 124.839 +    0x61e8,0x60fb,0x6137,0x6042
 124.840 +  },
 124.841 +  {				/* ku 43 */
 124.842 +    0x606a,0x60f2,0x6096,0x609a,0x6173,0x609d,0x6083,0x6092,0x608c,0x609b,
 124.843 +    0x611c,0x60bb,0x60b1,0x60dd,0x60d8,0x60c6,0x60da,0x60b4,0x6120,0x6192,
 124.844 +    0x6115,0x6123,0x60f4,0x6100,0x610e,0x612b,0x614a,0x6175,0x61ac,0x6194,
 124.845 +    0x61a7,0x61b7,0x61d4,0x61f5,0x5fdd,0x96b3,0x9582,0x9586,0x95c8,0x958e,
 124.846 +    0x9594,0x958c,0x95e5,0x95ad,0x95ab,0x9b2e,0x95ac,0x95be,0x95b6,0x9b29,
 124.847 +    0x95bf,0x95bd,0x95bc,0x95c3,0x95cb,0x95d4,0x95d0,0x95d5,0x95de,0x4e2c,
 124.848 +    0x723f,0x6215,0x6c35,0x6c54,0x6c5c,0x6c4a,0x7043,0x6c85,0x6c90,0x6c94,
 124.849 +    0x6c8c,0x6c68,0x6c69,0x6c74,0x6c76,0x6c86,0x6f59,0x6cd0,0x6cd4,0x6cad,
 124.850 +    0x7027,0x7018,0x6cf1,0x6cd7,0x6cb2,0x6ce0,0x6cd6,0x6ffc,0x6ceb,0x6cee,
 124.851 +    0x6cb1,0x6cd3,0x6cef,0x6d87
 124.852 +  },
 124.853 +  {				/* ku 44 */
 124.854 +    0x6d39,0x6d27,0x6d0c,0x6d79,0x6e5e,0x6d07,0x6d04,0x6d19,0x6d0e,0x6d2b,
 124.855 +    0x6fae,0x6d2e,0x6d35,0x6d1a,0x700f,0x6ef8,0x6f6f,0x6d33,0x6d91,0x6d6f,
 124.856 +    0x6df6,0x6f7f,0x6d5e,0x6d93,0x6d94,0x6d5c,0x6d60,0x6d7c,0x6d63,0x6e1a,
 124.857 +    0x6dc7,0x6dc5,0x6dde,0x7006,0x6dbf,0x6de0,0x6fa0,0x6de6,0x6ddd,0x6dd9,
 124.858 +    0x700b,0x6dab,0x6e0c,0x6dae,0x6e2b,0x6e6e,0x6e4e,0x6e6b,0x6eb2,0x6e5f,
 124.859 +    0x6e86,0x6e53,0x6e54,0x6e32,0x6e25,0x6e44,0x7067,0x6eb1,0x6e98,0x7044,
 124.860 +    0x6f2d,0x7005,0x6ea5,0x6ea7,0x6ebd,0x6ebb,0x6eb7,0x6f77,0x6eb4,0x6ecf,
 124.861 +    0x6e8f,0x6ec2,0x6e9f,0x6f62,0x7020,0x701f,0x6f24,0x6f15,0x6ef9,0x6f2f,
 124.862 +    0x6f36,0x7032,0x6f74,0x6f2a,0x6f09,0x6f29,0x6f89,0x6f8d,0x6f8c,0x6f78,
 124.863 +    0x6f72,0x6f7c,0x6f7a,0x7028
 124.864 +  },
 124.865 +  {				/* ku 45 */
 124.866 +    0x6fc9,0x6fa7,0x6fb9,0x6fb6,0x6fc2,0x6fe1,0x6fee,0x6fde,0x6fe0,0x6fef,
 124.867 +    0x701a,0x7023,0x701b,0x7039,0x7035,0x705d,0x705e,0x5b80,0x5b84,0x5b95,
 124.868 +    0x5b93,0x5ba5,0x5bb8,0x752f,0x9a2b,0x6434,0x5be4,0x5bee,0x8930,0x5bf0,
 124.869 +    0x8e47,0x8b07,0x8fb6,0x8fd3,0x8fd5,0x8fe5,0x8fee,0x8fe4,0x9087,0x8fe6,
 124.870 +    0x9015,0x8fe8,0x9005,0x9004,0x900b,0x9090,0x9011,0x900d,0x9016,0x9021,
 124.871 +    0x9035,0x9036,0x902d,0x902f,0x9044,0x9051,0x9052,0x9050,0x9068,0x9058,
 124.872 +    0x9062,0x905b,0x66b9,0x9074,0x907d,0x9082,0x9088,0x9083,0x908b,0x5f50,
 124.873 +    0x5f57,0x5f56,0x5f58,0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63,0x5c68,
 124.874 +    0x7fbc,0x5f33,0x5f29,0x5f2d,0x8274,0x5f3c,0x9b3b,0x5c6e,0x5981,0x5983,
 124.875 +    0x598d,0x5af5,0x5ad7,0x59a3
 124.876 +  },
 124.877 +  {				/* ku 46 */
 124.878 +    0x5997,0x59ca,0x5b00,0x599e,0x59a4,0x59d2,0x59b2,0x59af,0x59d7,0x59be,
 124.879 +    0x5a6d,0x5b08,0x59dd,0x5b4c,0x59e3,0x59d8,0x59f9,0x5a0c,0x5a09,0x5aa7,
 124.880 +    0x5afb,0x5a11,0x5a23,0x5a13,0x5a40,0x5a67,0x5a4a,0x5a55,0x5a3c,0x5a62,
 124.881 +    0x5b0b,0x80ec,0x5aaa,0x5a9b,0x5a77,0x5a7a,0x5abe,0x5aeb,0x5ab2,0x5b21,
 124.882 +    0x5b2a,0x5ab8,0x5ae0,0x5ae3,0x5b19,0x5ad6,0x5ae6,0x5ad8,0x5adc,0x5b09,
 124.883 +    0x5b17,0x5b16,0x5b32,0x5b37,0x5b40,0x5c15,0x5c1c,0x5b5a,0x5b65,0x5b73,
 124.884 +    0x5b51,0x5b53,0x5b62,0x99d4,0x99df,0x99d9,0x9a36,0x9a5b,0x99d1,0x99d8,
 124.885 +    0x9a4d,0x9a4a,0x99e2,0x9a6a,0x9a0f,0x9a0d,0x9a05,0x9a42,0x9a2d,0x9a16,
 124.886 +    0x9a41,0x9a2e,0x9a38,0x9a43,0x9a44,0x9a4f,0x9a65,0x9a64,0x7cf9,0x7d06,
 124.887 +    0x7d02,0x7d07,0x7d08,0x7e8a
 124.888 +  },
 124.889 +  {				/* ku 47 */
 124.890 +    0x7d1c,0x7d15,0x7d13,0x7d3a,0x7d32,0x7d31,0x7e10,0x7d3c,0x7d40,0x7d3f,
 124.891 +    0x7d5d,0x7d4e,0x7d73,0x7d86,0x7d83,0x7d88,0x7dbe,0x7dba,0x7dcb,0x7dd4,
 124.892 +    0x7dc4,0x7d9e,0x7dac,0x7db9,0x7da3,0x7db0,0x7dc7,0x7dd9,0x7dd7,0x7df9,
 124.893 +    0x7df2,0x7e62,0x7de6,0x7df6,0x7df1,0x7e0b,0x7de1,0x7e09,0x7e1d,0x7e1f,
 124.894 +    0x7e1e,0x7e2d,0x7e0a,0x7e11,0x7e7d,0x7e39,0x7e35,0x7e32,0x7e46,0x7e45,
 124.895 +    0x7e88,0x7e5a,0x7e52,0x7e6e,0x7e7e,0x7e70,0x7e6f,0x7e98,0x5e7a,0x757f,
 124.896 +    0x5ddb,0x753e,0x9095,0x738e,0x74a3,0x744b,0x73a2,0x739f,0x73cf,0x73c2,
 124.897 +    0x74cf,0x73b7,0x73b3,0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x980a,0x740a,
 124.898 +    0x73e9,0x73e7,0x73de,0x74bd,0x743f,0x7489,0x742a,0x745b,0x7426,0x7425,
 124.899 +    0x7428,0x7430,0x742e,0x742c
 124.900 +  },
 124.901 +  {				/* ku 48 */
 124.902 +    0x741b,0x741a,0x7441,0x745c,0x7457,0x7455,0x7459,0x74a6,0x746d,0x747e,
 124.903 +    0x749c,0x74d4,0x7480,0x7481,0x7487,0x748b,0x749e,0x74a8,0x74a9,0x7490,
 124.904 +    0x74a7,0x74da,0x74ba,0x97d9,0x97de,0x97dc,0x674c,0x6753,0x675e,0x6748,
 124.905 +    0x69aa,0x6aea,0x6787,0x676a,0x6773,0x6798,0x6898,0x6775,0x68d6,0x6a05,
 124.906 +    0x689f,0x678b,0x6777,0x677c,0x67f0,0x6adb,0x67d8,0x6af3,0x67e9,0x67b0,
 124.907 +    0x6ae8,0x67d9,0x67b5,0x67da,0x67b3,0x67dd,0x6800,0x67c3,0x67b8,0x67e2,
 124.908 +    0x6adf,0x67c1,0x6a89,0x6832,0x6833,0x690f,0x6a48,0x684e,0x6968,0x6844,
 124.909 +    0x69bf,0x6883,0x681d,0x6855,0x6a3a,0x6841,0x6a9c,0x6840,0x6b12,0x684a,
 124.910 +    0x6849,0x6829,0x68b5,0x688f,0x6874,0x6877,0x6893,0x686b,0x6b1e,0x696e,
 124.911 +    0x68fc,0x6add,0x69e7,0x68f9
 124.912 +  },
 124.913 +  {				/* ku 49 */
 124.914 +    0x6b0f,0x68f0,0x690b,0x6901,0x6957,0x68e3,0x6910,0x6971,0x6939,0x6960,
 124.915 +    0x6942,0x695d,0x6b16,0x696b,0x6980,0x6998,0x6978,0x6934,0x69cc,0x6aec,
 124.916 +    0x6ada,0x69ce,0x6af8,0x6966,0x6963,0x6979,0x699b,0x69a7,0x69bb,0x69ab,
 124.917 +    0x69ad,0x69d4,0x69b1,0x69c1,0x69ca,0x6ab3,0x6995,0x6ae7,0x698d,0x69ff,
 124.918 +    0x6aa3,0x69ed,0x6a17,0x6a18,0x6a65,0x69f2,0x6a44,0x6a3e,0x6aa0,0x6a50,
 124.919 +    0x6a5b,0x6a35,0x6a8e,0x6ad3,0x6a3d,0x6a28,0x6a58,0x6ade,0x6a91,0x6a90,
 124.920 +    0x6aa9,0x6a97,0x6aab,0x7337,0x7352,0x6b81,0x6b82,0x6ba4,0x6b84,0x6b9e,
 124.921 +    0x6bae,0x6b8d,0x6bab,0x6b9b,0x6baf,0x6baa,0x8ed4,0x8edb,0x8ef2,0x8efb,
 124.922 +    0x8f64,0x8ef9,0x8efc,0x8eeb,0x8ee4,0x8f62,0x8efa,0x8efe,0x8f0a,0x8f07,
 124.923 +    0x8f05,0x8f12,0x8f26,0x8f1e
 124.924 +  },
 124.925 +  {				/* ku 4a */
 124.926 +    0x8f1f,0x8f1c,0x8f33,0x8f46,0x8f54,0x8ece,0x6214,0x6227,0x621b,0x621f,
 124.927 +    0x6222,0x6221,0x6225,0x6224,0x6229,0x81e7,0x750c,0x74f4,0x74ff,0x750f,
 124.928 +    0x7511,0x7513,0x6534,0x65ee,0x65ef,0x65f0,0x660a,0x66c7,0x6772,0x6603,
 124.929 +    0x6615,0x6600,0x7085,0x66f7,0x661d,0x6634,0x6631,0x6636,0x6635,0x8006,
 124.930 +    0x665f,0x66c4,0x6641,0x664f,0x6689,0x6661,0x6657,0x6677,0x6684,0x668c,
 124.931 +    0x66d6,0x669d,0x66be,0x66db,0x66dc,0x66e6,0x66e9,0x8cc1,0x8cb0,0x8cba,
 124.932 +    0x8cbd,0x8d04,0x8cb2,0x8cc5,0x8d10,0x8cd1,0x8cda,0x8cd5,0x8ceb,0x8ce7,
 124.933 +    0x8cfb,0x8998,0x89ac,0x89a1,0x89bf,0x89a6,0x89af,0x89b2,0x89b7,0x726e,
 124.934 +    0x729f,0x725d,0x7266,0x726f,0x727e,0x727f,0x7284,0x728b,0x728d,0x728f,
 124.935 +    0x7292,0x6308,0x6332,0x63b0
 124.936 +  },
 124.937 +  {				/* ku 4b */
 124.938 +    0x643f,0x64d8,0x8004,0x6bea,0x6bf3,0x6bfd,0x6bff,0x6bf9,0x6c05,0x6c0c,
 124.939 +    0x6c06,0x6c0d,0x6c15,0x6c18,0x6c19,0x6c1a,0x6c21,0x6c2c,0x6c24,0x6c2a,
 124.940 +    0x6c32,0x6535,0x6555,0x656b,0x7258,0x7252,0x7256,0x7230,0x8662,0x5216,
 124.941 +    0x809f,0x809c,0x8093,0x80bc,0x670a,0x80bd,0x80b1,0x80ab,0x80ad,0x80b4,
 124.942 +    0x80b7,0x6727,0x8156,0x80e9,0x81da,0x80db,0x80c2,0x80c4,0x80d9,0x80cd,
 124.943 +    0x80d7,0x6710,0x80dd,0x811b,0x80f1,0x80f4,0x80ed,0x81be,0x810e,0x80f2,
 124.944 +    0x80fc,0x6715,0x8112,0x8c5a,0x8161,0x811e,0x812c,0x8118,0x8132,0x8148,
 124.945 +    0x814c,0x8153,0x8174,0x8159,0x815a,0x8171,0x8160,0x8169,0x817c,0x817d,
 124.946 +    0x816d,0x8167,0x584d,0x5ab5,0x8188,0x8182,0x81cf,0x6ed5,0x81a3,0x81aa,
 124.947 +    0x81cc,0x6726,0x81ca,0x81bb
 124.948 +  },
 124.949 +  {				/* ku 4c */
 124.950 +    0x81c1,0x81a6,0x6b5f,0x6b37,0x6b39,0x6b43,0x6b46,0x6b59,0x98ae,0x98af,
 124.951 +    0x98b6,0x98bc,0x98c6,0x98c8,0x6bb3,0x5f40,0x8f42,0x89f3,0x6590,0x9f4f,
 124.952 +    0x6595,0x65bc,0x65c6,0x65c4,0x65c3,0x65cc,0x65ce,0x65d2,0x65d6,0x716c,
 124.953 +    0x7152,0x7096,0x7197,0x70bb,0x70c0,0x70b7,0x70ab,0x70b1,0x71c1,0x70ca,
 124.954 +    0x7110,0x7113,0x71dc,0x712f,0x7131,0x7173,0x715c,0x7168,0x7145,0x7172,
 124.955 +    0x714a,0x7178,0x717a,0x7198,0x71b3,0x71b5,0x71a8,0x71a0,0x71e0,0x71d4,
 124.956 +    0x71e7,0x71f9,0x721d,0x7228,0x706c,0x71fe,0x7166,0x71b9,0x623e,0x623d,
 124.957 +    0x6243,0x6248,0x6249,0x793b,0x7940,0x7946,0x7949,0x795b,0x795c,0x7953,
 124.958 +    0x795a,0x79b0,0x7957,0x7960,0x798e,0x7967,0x797a,0x79aa,0x798a,0x799a,
 124.959 +    0x79a7,0x79b3,0x5fd1,0x5fd0
 124.960 +  },
 124.961 +  {				/* ku 4d */
 124.962 +    0x61df,0x605d,0x605a,0x6067,0x6041,0x6059,0x6063,0x6164,0x6106,0x610d,
 124.963 +    0x615d,0x61a9,0x619d,0x61cb,0x61e3,0x6207,0x8080,0x807f,0x6c93,0x6fa9,
 124.964 +    0x6dfc,0x78ef,0x77f8,0x78ad,0x7809,0x7868,0x7818,0x7811,0x65ab,0x782d,
 124.965 +    0x78b8,0x781d,0x7839,0x792a,0x7931,0x781f,0x783c,0x7825,0x782c,0x7823,
 124.966 +    0x7829,0x784e,0x786d,0x7864,0x78fd,0x7826,0x7850,0x7847,0x784c,0x786a,
 124.967 +    0x78e7,0x7893,0x789a,0x7887,0x78e3,0x78a1,0x78a3,0x78b2,0x78b9,0x78a5,
 124.968 +    0x78d4,0x78d9,0x78c9,0x78ec,0x78f2,0x7905,0x78f4,0x7913,0x7924,0x791e,
 124.969 +    0x7934,0x9f95,0x9ef9,0x9efb,0x9efc,0x76f1,0x7704,0x7798,0x76f9,0x7707,
 124.970 +    0x7708,0x771a,0x7722,0x7719,0x772d,0x7726,0x7735,0x7738,0x775e,0x77bc,
 124.971 +    0x7747,0x7743,0x775a,0x7768
 124.972 +  },
 124.973 +  {				/* ku 4e */
 124.974 +    0x7762,0x7765,0x777f,0x778d,0x777d,0x7780,0x778c,0x7791,0x779f,0x77a0,
 124.975 +    0x77b0,0x77b5,0x77bd,0x753a,0x7540,0x754e,0x754b,0x7548,0x755b,0x7572,
 124.976 +    0x7579,0x7583,0x7f58,0x7f61,0x7f5f,0x8a48,0x7f68,0x7f86,0x7f71,0x7f79,
 124.977 +    0x7f88,0x7f7e,0x76cd,0x76e5,0x8832,0x91d2,0x91d3,0x91d4,0x91d9,0x91d7,
 124.978 +    0x91d5,0x91f7,0x91e7,0x91e4,0x9346,0x91f5,0x91f9,0x9208,0x9226,0x9245,
 124.979 +    0x9211,0x9210,0x9201,0x9227,0x9204,0x9225,0x9200,0x923a,0x9266,0x9237,
 124.980 +    0x9233,0x9255,0x923d,0x9238,0x925e,0x926c,0x926d,0x923f,0x9460,0x9230,
 124.981 +    0x9249,0x9248,0x924d,0x922e,0x9239,0x9438,0x92ac,0x92a0,0x927a,0x92aa,
 124.982 +    0x92ee,0x92cf,0x9403,0x92e3,0x943a,0x92b1,0x92a6,0x93a7,0x9296,0x92cc,
 124.983 +    0x92a9,0x93f5,0x9293,0x927f
 124.984 +  },
 124.985 +  {				/* ku 4f */
 124.986 +    0x93a9,0x929a,0x931a,0x92ab,0x9283,0x940b,0x92a8,0x92a3,0x9412,0x9338,
 124.987 +    0x92f1,0x93d7,0x92e5,0x92f0,0x92ef,0x92e8,0x92bc,0x92dd,0x92f6,0x9426,
 124.988 +    0x9427,0x92c3,0x92df,0x92e6,0x9312,0x9306,0x9369,0x931b,0x9340,0x9301,
 124.989 +    0x9315,0x932e,0x9343,0x9307,0x9308,0x931f,0x9319,0x9365,0x9347,0x9376,
 124.990 +    0x9354,0x9364,0x93aa,0x9370,0x9384,0x93e4,0x93d8,0x9428,0x9387,0x93cc,
 124.991 +    0x9398,0x93b8,0x93bf,0x93a6,0x93b0,0x93b5,0x944c,0x93e2,0x93dc,0x93dd,
 124.992 +    0x93cd,0x93de,0x93c3,0x93c7,0x93d1,0x9414,0x941d,0x93f7,0x9465,0x9413,
 124.993 +    0x946d,0x9420,0x9479,0x93f9,0x9419,0x944a,0x9432,0x943f,0x9454,0x9463,
 124.994 +    0x937e,0x77e7,0x77ec,0x96c9,0x79d5,0x79ed,0x79e3,0x79eb,0x7a06,0x5d47,
 124.995 +    0x7a03,0x7a02,0x7a1e,0x7a14
 124.996 +  },
 124.997 +  {				/* ku 50 */
 124.998 +    0x7a39,0x7a37,0x7a61,0x9ecf,0x99a5,0x7a70,0x7688,0x768e,0x7693,0x7699,
 124.999 +    0x76a4,0x74de,0x74e0,0x752c,0x9ce9,0x9cf6,0x9d07,0x9d06,0x9d23,0x9d87,
124.1000 +    0x9e15,0x9d1d,0x9d1f,0x9de5,0x9d2f,0x9dd9,0x9d30,0x9d42,0x9e1e,0x9d53,
124.1001 +    0x9e1d,0x9d60,0x9d52,0x9df3,0x9d5c,0x9d61,0x9d93,0x9d6a,0x9d6f,0x9d89,
124.1002 +    0x9d98,0x9d9a,0x9dc0,0x9da5,0x9da9,0x9dc2,0x9dbc,0x9e1a,0x9dd3,0x9dda,
124.1003 +    0x9def,0x9de6,0x9df2,0x9df8,0x9e0c,0x9dfa,0x9e1b,0x7592,0x7594,0x7664,
124.1004 +    0x7658,0x759d,0x7667,0x75a3,0x75b3,0x75b4,0x75b8,0x75c4,0x75b1,0x75b0,
124.1005 +    0x75c3,0x75c2,0x7602,0x75cd,0x75e3,0x7646,0x75e6,0x75e4,0x7647,0x75e7,
124.1006 +    0x7603,0x75f1,0x75fc,0x75ff,0x7610,0x7600,0x7649,0x760c,0x761e,0x760a,
124.1007 +    0x7625,0x763b,0x7615,0x7619
124.1008 +  },
124.1009 +  {				/* ku 51 */
124.1010 +    0x761b,0x763c,0x7622,0x7620,0x7640,0x762d,0x7630,0x766d,0x7635,0x7643,
124.1011 +    0x766e,0x7633,0x764d,0x7669,0x7654,0x765c,0x7656,0x7672,0x766f,0x7fca,
124.1012 +    0x7ae6,0x7a78,0x7a79,0x7a80,0x7a86,0x7a88,0x7a95,0x7ac7,0x7aa0,0x7aac,
124.1013 +    0x7aa8,0x7ab6,0x7ab3,0x8864,0x8869,0x8872,0x887d,0x887f,0x8882,0x88a2,
124.1014 +    0x8960,0x88b7,0x88bc,0x88c9,0x8933,0x88ce,0x895d,0x8947,0x88f1,0x891a,
124.1015 +    0x88fc,0x88e8,0x88fe,0x88f0,0x8921,0x8919,0x8913,0x8938,0x890a,0x8964,
124.1016 +    0x892b,0x8936,0x8941,0x8966,0x897b,0x758b,0x80e5,0x76b8,0x76b4,0x77dc,
124.1017 +    0x8012,0x8014,0x8016,0x801c,0x8020,0x802e,0x8025,0x8026,0x802c,0x8029,
124.1018 +    0x8028,0x8031,0x800b,0x8035,0x8043,0x8046,0x8079,0x8052,0x8075,0x8071,
124.1019 +    0x8983,0x9807,0x980e,0x980f
124.1020 +  },
124.1021 +  {				/* ku 52 */
124.1022 +    0x9821,0x981c,0x6f41,0x9826,0x9837,0x984e,0x9853,0x9873,0x9862,0x9859,
124.1023 +    0x9865,0x986c,0x9870,0x864d,0x8654,0x866c,0x87e3,0x8806,0x867a,0x867c,
124.1024 +    0x867b,0x86a8,0x868d,0x868b,0x8706,0x869d,0x86a7,0x86a3,0x86aa,0x8693,
124.1025 +    0x86a9,0x86b6,0x86c4,0x86b5,0x8823,0x86b0,0x86ba,0x86b1,0x86af,0x86c9,
124.1026 +    0x87f6,0x86b4,0x86e9,0x86fa,0x87ef,0x86ed,0x8784,0x86d0,0x8713,0x86de,
124.1027 +    0x8810,0x86df,0x86d8,0x86d1,0x8703,0x8707,0x86f8,0x8708,0x870a,0x870d,
124.1028 +    0x8709,0x8723,0x873b,0x871e,0x8725,0x872e,0x871a,0x873e,0x87c8,0x8734,
124.1029 +    0x8731,0x8729,0x8737,0x873f,0x8782,0x8722,0x877d,0x8811,0x877b,0x8760,
124.1030 +    0x8770,0x874c,0x876e,0x878b,0x8753,0x8763,0x87bb,0x8764,0x8759,0x8765,
124.1031 +    0x8793,0x87af,0x87ce,0x87d2
124.1032 +  },
124.1033 +  {				/* ku 53 */
124.1034 +    0x87c6,0x8788,0x8785,0x87ad,0x8797,0x8783,0x87ab,0x87e5,0x87ac,0x87b5,
124.1035 +    0x87b3,0x87cb,0x87d3,0x87bd,0x87d1,0x87c0,0x87ca,0x87db,0x87ea,0x87e0,
124.1036 +    0x87ee,0x8816,0x8813,0x87fe,0x880a,0x881b,0x8821,0x8839,0x883c,0x7f36,
124.1037 +    0x7f4c,0x7f44,0x7f45,0x8210,0x7afa,0x7afd,0x7b08,0x7be4,0x7b04,0x7b67,
124.1038 +    0x7b0a,0x7b2b,0x7b0f,0x7b47,0x7b38,0x7b2a,0x7b19,0x7b2e,0x7b31,0x7b20,
124.1039 +    0x7b25,0x7b24,0x7b33,0x7c69,0x7b1e,0x7b58,0x7bf3,0x7b45,0x7b75,0x7b4c,
124.1040 +    0x7b8f,0x7b60,0x7b6e,0x7b7b,0x7b62,0x7b72,0x7b71,0x7b90,0x7c00,0x7bcb,
124.1041 +    0x7bb8,0x7bac,0x7b9d,0x7c5c,0x7b85,0x7c1e,0x7b9c,0x7ba2,0x7c2b,0x7bb4,
124.1042 +    0x7c23,0x7bc1,0x7bcc,0x7bdd,0x7bda,0x7be5,0x7be6,0x7bea,0x7c0c,0x7bfe,
124.1043 +    0x7bfc,0x7c0f,0x7c6a,0x7c0b
124.1044 +  },
124.1045 +  {				/* ku 54 */
124.1046 +    0x7c1f,0x7c2a,0x7c26,0x7c38,0x7c5f,0x7c40,0x81fe,0x8201,0x8202,0x8204,
124.1047 +    0x81ec,0x8844,0x8221,0x8222,0x8264,0x822d,0x822f,0x8228,0x822b,0x8238,
124.1048 +    0x826b,0x8233,0x8234,0x823e,0x8244,0x8249,0x824b,0x824f,0x825a,0x825f,
124.1049 +    0x8268,0x887e,0x88ca,0x8888,0x88d8,0x88df,0x895e,0x7f9d,0x7fa5,0x7fa7,
124.1050 +    0x7faf,0x7fb0,0x7fb2,0x7c7c,0x6549,0x7c91,0x7cf2,0x7cf6,0x7c9e,0x7ca2,
124.1051 +    0x7cb2,0x7cbc,0x7cbd,0x7cdd,0x7cc7,0x7ccc,0x7ccd,0x7cc8,0x7cc5,0x7cd7,
124.1052 +    0x7ce8,0x826e,0x66a8,0x7fbf,0x7fce,0x7fd5,0x7fe5,0x7fe1,0x7fe6,0x7fe9,
124.1053 +    0x7fee,0x7ff3,0x7cf8,0x7e36,0x7da6,0x7dae,0x7e47,0x7e9b,0x9ea9,0x9eb4,
124.1054 +    0x8d73,0x8d84,0x8d94,0x8d91,0x8db2,0x8d67,0x8d6d,0x8c47,0x8c49,0x914a,
124.1055 +    0x9150,0x914e,0x914f,0x9164
124.1056 +  },
124.1057 +  {				/* ku 55 */
124.1058 +    0x9162,0x9161,0x9170,0x9169,0x916f,0x91c5,0x91c3,0x9172,0x9174,0x9179,
124.1059 +    0x918c,0x9185,0x9190,0x918d,0x9191,0x91a2,0x91a3,0x91aa,0x91ad,0x91ae,
124.1060 +    0x91af,0x91b5,0x91b4,0x91ba,0x8c55,0x9e7a,0x8e89,0x8deb,0x8e05,0x8e59,
124.1061 +    0x8e69,0x8db5,0x8dbf,0x8dbc,0x8dba,0x8e4c,0x8dd6,0x8dd7,0x8dda,0x8e92,
124.1062 +    0x8dce,0x8dcf,0x8ddb,0x8dc6,0x8dec,0x8e7a,0x8e55,0x8de3,0x8e9a,0x8e8b,
124.1063 +    0x8de4,0x8e09,0x8dfd,0x8e14,0x8e1d,0x8e1f,0x8e93,0x8e2e,0x8e23,0x8e91,
124.1064 +    0x8e3a,0x8e40,0x8e39,0x8e35,0x8e3d,0x8e31,0x8e49,0x8e41,0x8e42,0x8ea1,
124.1065 +    0x8e63,0x8e4a,0x8e70,0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8eaa,0x8e94,
124.1066 +    0x8e90,0x8ea6,0x8e9e,0x8c78,0x8c82,0x8c8a,0x8c85,0x8c98,0x8c94,0x659b,
124.1067 +    0x89d6,0x89f4,0x89da,0x89dc
124.1068 +  },
124.1069 +  {				/* ku 56 */
124.1070 +    0x89e5,0x89eb,0x89f6,0x8a3e,0x8b26,0x975a,0x96e9,0x9742,0x96ef,0x9706,
124.1071 +    0x973d,0x9708,0x970f,0x970e,0x972a,0x9744,0x9730,0x973e,0x9f54,0x9f5f,
124.1072 +    0x9f59,0x9f60,0x9f5c,0x9f66,0x9f6c,0x9f6a,0x9f77,0x9efd,0x9eff,0x9f09,
124.1073 +    0x96b9,0x96bc,0x96bd,0x96ce,0x96d2,0x77bf,0x8b8e,0x928e,0x947e,0x92c8,
124.1074 +    0x93e8,0x936a,0x93ca,0x938f,0x943e,0x946b,0x9b77,0x9b74,0x9b81,0x9b83,
124.1075 +    0x9b8e,0x9c78,0x7a4c,0x9b92,0x9c5f,0x9b90,0x9bad,0x9b9a,0x9baa,0x9b9e,
124.1076 +    0x9c6d,0x9bab,0x9b9d,0x9c58,0x9bc1,0x9c7a,0x9c31,0x9c39,0x9c23,0x9c37,
124.1077 +    0x9bc0,0x9bca,0x9bc7,0x9bfd,0x9bd6,0x9bea,0x9beb,0x9be1,0x9be4,0x9be7,
124.1078 +    0x9bdd,0x9be2,0x9bf0,0x9bdb,0x9bf4,0x9bd4,0x9c5d,0x9c08,0x9c10,0x9c0d,
124.1079 +    0x9c12,0x9c09,0x9bff,0x9c20
124.1080 +  },
124.1081 +  {				/* ku 57 */
124.1082 +    0x9c32,0x9c2d,0x9c28,0x9c25,0x9c29,0x9c33,0x9c3e,0x9c48,0x9c3b,0x9c35,
124.1083 +    0x9c45,0x9c56,0x9c54,0x9c52,0x9c67,0x977c,0x9785,0x97c3,0x97bd,0x9794,
124.1084 +    0x97c9,0x97ab,0x97a3,0x97b2,0x97b4,0x9ab1,0x9ab0,0x9ab7,0x9dbb,0x9ab6,
124.1085 +    0x9aba,0x9abc,0x9ac1,0x9ac0,0x9acf,0x9ac2,0x9ad6,0x9ad5,0x9ad1,0x9b45,
124.1086 +    0x9b43,0x9b58,0x9b4e,0x9b48,0x9b4d,0x9b51,0x9957,0x995c,0x992e,0x9955,
124.1087 +    0x9954,0x9adf,0x9ae1,0x9ae6,0x9aef,0x9aeb,0x9afb,0x9aed,0x9af9,0x9b08,
124.1088 +    0x9b0f,0x9b22,0x9b1f,0x9b23,0x4e48,0x9ebe,0x7e3b,0x9e82,0x9e87,0x9e88,
124.1089 +    0x9e8b,0x9e92,0x93d6,0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0,0x9edf,
124.1090 +    0x9ee2,0x9ef7,0x9ee7,0x9ee5,0x9ef2,0x9eef,0x9f22,0x9f2c,0x9f2f,0x9f39,
124.1091 +    0x9f37,0x9f3d,0x9f3e,0x9f44
124.1092 +  },
124.1093 +  {				/* ku 58 */
124.1094 +    0x896c,0x95c6,0x9336,0x5f46,0x8514,0x7e94,0x5382,0x51b2,0x4e11,0x9f63,
124.1095 +    0x5679,0x515a,0x6dc0,0x9f15,0x6597,0x5641,0x9aee,0x8303,0x4e30,0x8907,
124.1096 +    0x5e72,0x7a40,0x98b3,0x5e7f,0x95a4,0x9b0d,0x5212,0x8ff4,0x5f59,0x7a6b,
124.1097 +    0x98e2,0x51e0,0x50a2,0x4ef7,0x8350,0x8591,0x5118,0x636e,0x6372,0x524b,
124.1098 +    0x5938,0x774f,0x8721,0x814a,0x7e8d,0x91cc,0x66c6,0x5e18,0x77ad,0x9e75,
124.1099 +    0x56c9,0x9ef4,0x6fdb,0x61de,0x77c7,0x7030,0x9eb5,0x884a,0x95e2,0x82f9,
124.1100 +    0x51ed,0x6251,0x4ec6,0x6734,0x97c6,0x7c64,0x7e34,0x97a6,0x9eaf,0x786e,
124.1101 +    0x820d,0x672f,0x677e,0x56cc,0x53f0,0x98b1,0x6aaf,0x7f4e,0x6d82,0x7cf0,
124.1102 +    0x4e07,0x4fc2,0x7e6b,0x9e79,0x56ae,0x9b1a,0x846f,0x53f6,0x90c1,0x79a6,
124.1103 +    0x7c72,0x613f,0x4e91,0x9ad2
124.1104 +  },
124.1105 +  {				/* ku 59 */
124.1106 +    0x75c7,0x96bb,0x53ea,0x7dfb,0x88fd,0x79cd,0x7843,0x7b51,0x51c6,UBOGON,
124.1107 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1108 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1109 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1110 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1111 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1112 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1113 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1114 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
124.1115 +    UBOGON,UBOGON,UBOGON,UBOGON
124.1116 +  }
124.1117 +};
   125.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   125.2 +++ b/src/charset/gb_2312.c	Mon Sep 14 15:17:45 2009 +0900
   125.3 @@ -0,0 +1,2795 @@
   125.4 +/* ========================================================================
   125.5 + * Copyright 1988-2006 University of Washington
   125.6 + *
   125.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   125.8 + * you may not use this file except in compliance with the License.
   125.9 + * You may obtain a copy of the License at
  125.10 + *
  125.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  125.12 + *
  125.13 + * 
  125.14 + * ========================================================================
  125.15 + */
  125.16 +
  125.17 +/*
  125.18 + * Program:	GBK conversion table
  125.19 + *
  125.20 + * Author:	Mark Crispin
  125.21 + *		Networks and Distributed Computing
  125.22 + *		Computing & Communications
  125.23 + *		University of Washington
  125.24 + *		Administration Building, AG-44
  125.25 + *		Seattle, WA  98195
  125.26 + *		Internet: MRC@CAC.Washington.EDU
  125.27 + *
  125.28 + * Date:	3 July 1997
  125.29 + * Last Edited:	30 August 2006
  125.30 + */
  125.31 +
  125.32 +/* GB 2312 is the national standard of the People's Republic of China
  125.33 + * (mainland China).  This is actually the GBK extended version.
  125.34 + */
  125.35 +
  125.36 +#define BASE_GB2312_KU 0x81
  125.37 +#define BASE_GB2312_TEN 0x40
  125.38 +#define MAX_GB2312_KU 125
  125.39 +#define MAX_GB2312_TEN 191
  125.40 +
  125.41 +
  125.42 +#define GBTOUNICODE(c,c1,ku,ten)				\
  125.43 +  ((((ku = c - BASE_GB2312_KU) < MAX_GB2312_KU) &&		\
  125.44 +    ((ten = c1 - BASE_GB2312_TEN) < MAX_GB2312_TEN)) ?		\
  125.45 +   gb2312tab[ku][ten] : UBOGON)
  125.46 +
  125.47 +static const unsigned short gb2312tab[MAX_GB2312_KU][MAX_GB2312_TEN] = {
  125.48 +  {				/* ku 01 */
  125.49 +    0x4e02,0x4e04,0x4e05,0x4e06,0x4e0f,0x4e12,0x4e17,0x4e1f,0x4e20,0x4e21,
  125.50 +    0x4e23,0x4e26,0x4e29,0x4e2e,0x4e2f,0x4e31,0x4e33,0x4e35,0x4e37,0x4e3c,
  125.51 +    0x4e40,0x4e41,0x4e42,0x4e44,0x4e46,0x4e4a,0x4e51,0x4e55,0x4e57,0x4e5a,
  125.52 +    0x4e5b,0x4e62,0x4e63,0x4e64,0x4e65,0x4e67,0x4e68,0x4e6a,0x4e6b,0x4e6c,
  125.53 +    0x4e6d,0x4e6e,0x4e6f,0x4e72,0x4e74,0x4e75,0x4e76,0x4e77,0x4e78,0x4e79,
  125.54 +    0x4e7a,0x4e7b,0x4e7c,0x4e7d,0x4e7f,0x4e80,0x4e81,0x4e82,0x4e83,0x4e84,
  125.55 +    0x4e85,0x4e87,0x4e8a,UBOGON,0x4e90,0x4e96,0x4e97,0x4e99,0x4e9c,0x4e9d,
  125.56 +    0x4e9e,0x4ea3,0x4eaa,0x4eaf,0x4eb0,0x4eb1,0x4eb4,0x4eb6,0x4eb7,0x4eb8,
  125.57 +    0x4eb9,0x4ebc,0x4ebd,0x4ebe,0x4ec8,0x4ecc,0x4ecf,0x4ed0,0x4ed2,0x4eda,
  125.58 +    0x4edb,0x4edc,0x4ee0,0x4ee2,0x4ee6,0x4ee7,0x4ee9,0x4eed,0x4eee,0x4eef,
  125.59 +    0x4ef1,0x4ef4,0x4ef8,0x4ef9,0x4efa,0x4efc,0x4efe,0x4f00,0x4f02,0x4f03,
  125.60 +    0x4f04,0x4f05,0x4f06,0x4f07,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f13,0x4f14,
  125.61 +    0x4f15,0x4f16,0x4f1c,0x4f1d,0x4f21,0x4f23,0x4f28,0x4f29,0x4f2c,0x4f2d,
  125.62 +    0x4f2e,0x4f31,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f3f,0x4f40,
  125.63 +    0x4f41,0x4f42,0x4f44,0x4f45,0x4f47,0x4f48,0x4f49,0x4f4a,0x4f4b,0x4f4c,
  125.64 +    0x4f52,0x4f54,0x4f56,0x4f61,0x4f62,0x4f66,0x4f68,0x4f6a,0x4f6b,0x4f6d,
  125.65 +    0x4f6e,0x4f71,0x4f72,0x4f75,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d,0x4f80,
  125.66 +    0x4f81,0x4f82,0x4f85,0x4f86,0x4f87,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92,
  125.67 +    0x4f93,0x4f95,0x4f96,0x4f98,0x4f99,0x4f9a,0x4f9c,0x4f9e,0x4f9f,0x4fa1,
  125.68 +    0x4fa2
  125.69 +  },
  125.70 +  {				/* ku 02 */
  125.71 +    0x4fa4,0x4fab,0x4fad,0x4fb0,0x4fb1,0x4fb2,0x4fb3,0x4fb4,0x4fb6,0x4fb7,
  125.72 +    0x4fb8,0x4fb9,0x4fba,0x4fbb,0x4fbc,0x4fbd,0x4fbe,0x4fc0,0x4fc1,0x4fc2,
  125.73 +    0x4fc6,0x4fc7,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd,0x4fd2,0x4fd3,0x4fd4,
  125.74 +    0x4fd5,0x4fd6,0x4fd9,0x4fdb,0x4fe0,0x4fe2,0x4fe4,0x4fe5,0x4fe7,0x4feb,
  125.75 +    0x4fec,0x4ff0,0x4ff2,0x4ff4,0x4ff5,0x4ff6,0x4ff7,0x4ff9,0x4ffb,0x4ffc,
  125.76 +    0x4ffd,0x4fff,0x5000,0x5001,0x5002,0x5003,0x5004,0x5005,0x5006,0x5007,
  125.77 +    0x5008,0x5009,0x500a,UBOGON,0x500b,0x500e,0x5010,0x5011,0x5013,0x5015,
  125.78 +    0x5016,0x5017,0x501b,0x501d,0x501e,0x5020,0x5022,0x5023,0x5024,0x5027,
  125.79 +    0x502b,0x502f,0x5030,0x5031,0x5032,0x5033,0x5034,0x5035,0x5036,0x5037,
  125.80 +    0x5038,0x5039,0x503b,0x503d,0x503f,0x5040,0x5041,0x5042,0x5044,0x5045,
  125.81 +    0x5046,0x5049,0x504a,0x504b,0x504d,0x5050,0x5051,0x5052,0x5053,0x5054,
  125.82 +    0x5056,0x5057,0x5058,0x5059,0x505b,0x505d,0x505e,0x505f,0x5060,0x5061,
  125.83 +    0x5062,0x5063,0x5064,0x5066,0x5067,0x5068,0x5069,0x506a,0x506b,0x506d,
  125.84 +    0x506e,0x506f,0x5070,0x5071,0x5072,0x5073,0x5074,0x5075,0x5078,0x5079,
  125.85 +    0x507a,0x507c,0x507d,0x5081,0x5082,0x5083,0x5084,0x5086,0x5087,0x5089,
  125.86 +    0x508a,0x508b,0x508c,0x508e,0x508f,0x5090,0x5091,0x5092,0x5093,0x5094,
  125.87 +    0x5095,0x5096,0x5097,0x5098,0x5099,0x509a,0x509b,0x509c,0x509d,0x509e,
  125.88 +    0x509f,0x50a0,0x50a1,0x50a2,0x50a4,0x50a6,0x50aa,0x50ab,0x50ad,0x50ae,
  125.89 +    0x50af,0x50b0,0x50b1,0x50b3,0x50b4,0x50b5,0x50b6,0x50b7,0x50b8,0x50b9,
  125.90 +    0x50bc
  125.91 +  },
  125.92 +  {				/* ku 03 */
  125.93 +    0x50bd,0x50be,0x50bf,0x50c0,0x50c1,0x50c2,0x50c3,0x50c4,0x50c5,0x50c6,
  125.94 +    0x50c7,0x50c8,0x50c9,0x50ca,0x50cb,0x50cc,0x50cd,0x50ce,0x50d0,0x50d1,
  125.95 +    0x50d2,0x50d3,0x50d4,0x50d5,0x50d7,0x50d8,0x50d9,0x50db,0x50dc,0x50dd,
  125.96 +    0x50de,0x50df,0x50e0,0x50e1,0x50e2,0x50e3,0x50e4,0x50e5,0x50e8,0x50e9,
  125.97 +    0x50ea,0x50eb,0x50ef,0x50f0,0x50f1,0x50f2,0x50f4,0x50f6,0x50f7,0x50f8,
  125.98 +    0x50f9,0x50fa,0x50fc,0x50fd,0x50fe,0x50ff,0x5100,0x5101,0x5102,0x5103,
  125.99 +    0x5104,0x5105,0x5108,UBOGON,0x5109,0x510a,0x510c,0x510d,0x510e,0x510f,
 125.100 +    0x5110,0x5111,0x5113,0x5114,0x5115,0x5116,0x5117,0x5118,0x5119,0x511a,
 125.101 +    0x511b,0x511c,0x511d,0x511e,0x511f,0x5120,0x5122,0x5123,0x5124,0x5125,
 125.102 +    0x5126,0x5127,0x5128,0x5129,0x512a,0x512b,0x512c,0x512d,0x512e,0x512f,
 125.103 +    0x5130,0x5131,0x5132,0x5133,0x5134,0x5135,0x5136,0x5137,0x5138,0x5139,
 125.104 +    0x513a,0x513b,0x513c,0x513d,0x513e,0x5142,0x5147,0x514a,0x514c,0x514e,
 125.105 +    0x514f,0x5150,0x5152,0x5153,0x5157,0x5158,0x5159,0x515b,0x515d,0x515e,
 125.106 +    0x515f,0x5160,0x5161,0x5163,0x5164,0x5166,0x5167,0x5169,0x516a,0x516f,
 125.107 +    0x5172,0x517a,0x517e,0x517f,0x5183,0x5184,0x5186,0x5187,0x518a,0x518b,
 125.108 +    0x518e,0x518f,0x5190,0x5191,0x5193,0x5194,0x5198,0x519a,0x519d,0x519e,
 125.109 +    0x519f,0x51a1,0x51a3,0x51a6,0x51a7,0x51a8,0x51a9,0x51aa,0x51ad,0x51ae,
 125.110 +    0x51b4,0x51b8,0x51b9,0x51ba,0x51be,0x51bf,0x51c1,0x51c2,0x51c3,0x51c5,
 125.111 +    0x51c8,0x51ca,0x51cd,0x51ce,0x51d0,0x51d2,0x51d3,0x51d4,0x51d5,0x51d6,
 125.112 +    0x51d7
 125.113 +  },
 125.114 +  {				/* ku 04 */
 125.115 +    0x51d8,0x51d9,0x51da,0x51dc,0x51de,0x51df,0x51e2,0x51e3,0x51e5,0x51e6,
 125.116 +    0x51e7,0x51e8,0x51e9,0x51ea,0x51ec,0x51ee,0x51f1,0x51f2,0x51f4,0x51f7,
 125.117 +    0x51fe,0x5204,0x5205,0x5209,0x520b,0x520c,0x520f,0x5210,0x5213,0x5214,
 125.118 +    0x5215,0x521c,0x521e,0x521f,0x5221,0x5222,0x5223,0x5225,0x5226,0x5227,
 125.119 +    0x522a,0x522c,0x522f,0x5231,0x5232,0x5234,0x5235,0x523c,0x523e,0x5244,
 125.120 +    0x5245,0x5246,0x5247,0x5248,0x5249,0x524b,0x524e,0x524f,0x5252,0x5253,
 125.121 +    0x5255,0x5257,0x5258,UBOGON,0x5259,0x525a,0x525b,0x525d,0x525f,0x5260,
 125.122 +    0x5262,0x5263,0x5264,0x5266,0x5268,0x526b,0x526c,0x526d,0x526e,0x5270,
 125.123 +    0x5271,0x5273,0x5274,0x5275,0x5276,0x5277,0x5278,0x5279,0x527a,0x527b,
 125.124 +    0x527c,0x527e,0x5280,0x5283,0x5284,0x5285,0x5286,0x5287,0x5289,0x528a,
 125.125 +    0x528b,0x528c,0x528d,0x528e,0x528f,0x5291,0x5292,0x5294,0x5295,0x5296,
 125.126 +    0x5297,0x5298,0x5299,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7,0x52ae,
 125.127 +    0x52af,0x52b0,0x52b4,0x52b5,0x52b6,0x52b7,0x52b8,0x52b9,0x52ba,0x52bb,
 125.128 +    0x52bc,0x52bd,0x52c0,0x52c1,0x52c2,0x52c4,0x52c5,0x52c6,0x52c8,0x52ca,
 125.129 +    0x52cc,0x52cd,0x52ce,0x52cf,0x52d1,0x52d3,0x52d4,0x52d5,0x52d7,0x52d9,
 125.130 +    0x52da,0x52db,0x52dc,0x52dd,0x52de,0x52e0,0x52e1,0x52e2,0x52e3,0x52e5,
 125.131 +    0x52e6,0x52e7,0x52e8,0x52e9,0x52ea,0x52eb,0x52ec,0x52ed,0x52ee,0x52ef,
 125.132 +    0x52f1,0x52f2,0x52f3,0x52f4,0x52f5,0x52f6,0x52f7,0x52f8,0x52fb,0x52fc,
 125.133 +    0x52fd,0x5301,0x5302,0x5303,0x5304,0x5307,0x5309,0x530a,0x530b,0x530c,
 125.134 +    0x530e
 125.135 +  },
 125.136 +  {				/* ku 05 */
 125.137 +    0x5311,0x5312,0x5313,0x5314,0x5318,0x531b,0x531c,0x531e,0x531f,0x5322,
 125.138 +    0x5324,0x5325,0x5327,0x5328,0x5329,0x532b,0x532c,0x532d,0x532f,0x5330,
 125.139 +    0x5331,0x5332,0x5333,0x5334,0x5335,0x5336,0x5337,0x5338,0x533c,0x533d,
 125.140 +    0x5340,0x5342,0x5344,0x5346,0x534b,0x534c,0x534d,0x5350,0x5354,0x5358,
 125.141 +    0x5359,0x535b,0x535d,0x5365,0x5368,0x536a,0x536c,0x536d,0x5372,0x5376,
 125.142 +    0x5379,0x537b,0x537c,0x537d,0x537e,0x5380,0x5381,0x5383,0x5387,0x5388,
 125.143 +    0x538a,0x538e,0x538f,UBOGON,0x5390,0x5391,0x5392,0x5393,0x5394,0x5396,
 125.144 +    0x5397,0x5399,0x539b,0x539c,0x539e,0x53a0,0x53a1,0x53a4,0x53a7,0x53aa,
 125.145 +    0x53ab,0x53ac,0x53ad,0x53af,0x53b0,0x53b1,0x53b2,0x53b3,0x53b4,0x53b5,
 125.146 +    0x53b7,0x53b8,0x53b9,0x53ba,0x53bc,0x53bd,0x53be,0x53c0,0x53c3,0x53c4,
 125.147 +    0x53c5,0x53c6,0x53c7,0x53ce,0x53cf,0x53d0,0x53d2,0x53d3,0x53d5,0x53da,
 125.148 +    0x53dc,0x53dd,0x53de,0x53e1,0x53e2,0x53e7,0x53f4,0x53fa,0x53fe,0x53ff,
 125.149 +    0x5400,0x5402,0x5405,0x5407,0x540b,0x5414,0x5418,0x5419,0x541a,0x541c,
 125.150 +    0x5422,0x5424,0x5425,0x542a,0x5430,0x5433,0x5436,0x5437,0x543a,0x543d,
 125.151 +    0x543f,0x5441,0x5442,0x5444,0x5445,0x5447,0x5449,0x544c,0x544d,0x544e,
 125.152 +    0x544f,0x5451,0x545a,0x545d,0x545e,0x545f,0x5460,0x5461,0x5463,0x5465,
 125.153 +    0x5467,0x5469,0x546a,0x546b,0x546c,0x546d,0x546e,0x546f,0x5470,0x5474,
 125.154 +    0x5479,0x547a,0x547e,0x547f,0x5481,0x5483,0x5485,0x5487,0x5488,0x5489,
 125.155 +    0x548a,0x548d,0x5491,0x5493,0x5497,0x5498,0x549c,0x549e,0x549f,0x54a0,
 125.156 +    0x54a1
 125.157 +  },
 125.158 +  {				/* ku 06 */
 125.159 +    0x54a2,0x54a5,0x54ae,0x54b0,0x54b2,0x54b5,0x54b6,0x54b7,0x54b9,0x54ba,
 125.160 +    0x54bc,0x54be,0x54c3,0x54c5,0x54ca,0x54cb,0x54d6,0x54d8,0x54db,0x54e0,
 125.161 +    0x54e1,0x54e2,0x54e3,0x54e4,0x54eb,0x54ec,0x54ef,0x54f0,0x54f1,0x54f4,
 125.162 +    0x54f5,0x54f6,0x54f7,0x54f8,0x54f9,0x54fb,0x54fe,0x5500,0x5502,0x5503,
 125.163 +    0x5504,0x5505,0x5508,0x550a,0x550b,0x550c,0x550d,0x550e,0x5512,0x5513,
 125.164 +    0x5515,0x5516,0x5517,0x5518,0x5519,0x551a,0x551c,0x551d,0x551e,0x551f,
 125.165 +    0x5521,0x5525,0x5526,UBOGON,0x5528,0x5529,0x552b,0x552d,0x5532,0x5534,
 125.166 +    0x5535,0x5536,0x5538,0x5539,0x553a,0x553b,0x553d,0x5540,0x5542,0x5545,
 125.167 +    0x5547,0x5548,0x554b,0x554c,0x554d,0x554e,0x554f,0x5551,0x5552,0x5553,
 125.168 +    0x5554,0x5557,0x5558,0x5559,0x555a,0x555b,0x555d,0x555e,0x555f,0x5560,
 125.169 +    0x5562,0x5563,0x5568,0x5569,0x556b,0x556f,0x5570,0x5571,0x5572,0x5573,
 125.170 +    0x5574,0x5579,0x557a,0x557d,0x557f,0x5585,0x5586,0x558c,0x558d,0x558e,
 125.171 +    0x5590,0x5592,0x5593,0x5595,0x5596,0x5597,0x559a,0x559b,0x559e,0x55a0,
 125.172 +    0x55a1,0x55a2,0x55a3,0x55a4,0x55a5,0x55a6,0x55a8,0x55a9,0x55aa,0x55ab,
 125.173 +    0x55ac,0x55ad,0x55ae,0x55af,0x55b0,0x55b2,0x55b4,0x55b6,0x55b8,0x55ba,
 125.174 +    0x55bc,0x55bf,0x55c0,0x55c1,0x55c2,0x55c3,0x55c6,0x55c7,0x55c8,0x55ca,
 125.175 +    0x55cb,0x55ce,0x55cf,0x55d0,0x55d5,0x55d7,0x55d8,0x55d9,0x55da,0x55db,
 125.176 +    0x55de,0x55e0,0x55e2,0x55e7,0x55e9,0x55ed,0x55ee,0x55f0,0x55f1,0x55f4,
 125.177 +    0x55f6,0x55f8,0x55f9,0x55fa,0x55fb,0x55fc,0x55ff,0x5602,0x5603,0x5604,
 125.178 +    0x5605
 125.179 +  },
 125.180 +  {				/* ku 07 */
 125.181 +    0x5606,0x5607,0x560a,0x560b,0x560d,0x5610,0x5611,0x5612,0x5613,0x5614,
 125.182 +    0x5615,0x5616,0x5617,0x5619,0x561a,0x561c,0x561d,0x5620,0x5621,0x5622,
 125.183 +    0x5625,0x5626,0x5628,0x5629,0x562a,0x562b,0x562e,0x562f,0x5630,0x5633,
 125.184 +    0x5635,0x5637,0x5638,0x563a,0x563c,0x563d,0x563e,0x5640,0x5641,0x5642,
 125.185 +    0x5643,0x5644,0x5645,0x5646,0x5647,0x5648,0x5649,0x564a,0x564b,0x564f,
 125.186 +    0x5650,0x5651,0x5652,0x5653,0x5655,0x5656,0x565a,0x565b,0x565d,0x565e,
 125.187 +    0x565f,0x5660,0x5661,UBOGON,0x5663,0x5665,0x5666,0x5667,0x566d,0x566e,
 125.188 +    0x566f,0x5670,0x5672,0x5673,0x5674,0x5675,0x5677,0x5678,0x5679,0x567a,
 125.189 +    0x567d,0x567e,0x567f,0x5680,0x5681,0x5682,0x5683,0x5684,0x5687,0x5688,
 125.190 +    0x5689,0x568a,0x568b,0x568c,0x568d,0x5690,0x5691,0x5692,0x5694,0x5695,
 125.191 +    0x5696,0x5697,0x5698,0x5699,0x569a,0x569b,0x569c,0x569d,0x569e,0x569f,
 125.192 +    0x56a0,0x56a1,0x56a2,0x56a4,0x56a5,0x56a6,0x56a7,0x56a8,0x56a9,0x56aa,
 125.193 +    0x56ab,0x56ac,0x56ad,0x56ae,0x56b0,0x56b1,0x56b2,0x56b3,0x56b4,0x56b5,
 125.194 +    0x56b6,0x56b8,0x56b9,0x56ba,0x56bb,0x56bd,0x56be,0x56bf,0x56c0,0x56c1,
 125.195 +    0x56c2,0x56c3,0x56c4,0x56c5,0x56c6,0x56c7,0x56c8,0x56c9,0x56cb,0x56cc,
 125.196 +    0x56cd,0x56ce,0x56cf,0x56d0,0x56d1,0x56d2,0x56d3,0x56d5,0x56d6,0x56d8,
 125.197 +    0x56d9,0x56dc,0x56e3,0x56e5,0x56e6,0x56e7,0x56e8,0x56e9,0x56ea,0x56ec,
 125.198 +    0x56ee,0x56ef,0x56f2,0x56f3,0x56f6,0x56f7,0x56f8,0x56fb,0x56fc,0x5700,
 125.199 +    0x5701,0x5702,0x5705,0x5707,0x570b,0x570c,0x570d,0x570e,0x570f,0x5710,
 125.200 +    0x5711
 125.201 +  },
 125.202 +  {				/* ku 08 */
 125.203 +    0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,0x5718,0x5719,0x571a,0x571b,
 125.204 +    0x571d,0x571e,0x5720,0x5721,0x5722,0x5724,0x5725,0x5726,0x5727,0x572b,
 125.205 +    0x5731,0x5732,0x5734,0x5735,0x5736,0x5737,0x5738,0x573c,0x573d,0x573f,
 125.206 +    0x5741,0x5743,0x5744,0x5745,0x5746,0x5748,0x5749,0x574b,0x5752,0x5753,
 125.207 +    0x5754,0x5755,0x5756,0x5758,0x5759,0x5762,0x5763,0x5765,0x5767,0x576c,
 125.208 +    0x576e,0x5770,0x5771,0x5772,0x5774,0x5775,0x5778,0x5779,0x577a,0x577d,
 125.209 +    0x577e,0x577f,0x5780,UBOGON,0x5781,0x5787,0x5788,0x5789,0x578a,0x578d,
 125.210 +    0x578e,0x578f,0x5790,0x5791,0x5794,0x5795,0x5796,0x5797,0x5798,0x5799,
 125.211 +    0x579a,0x579c,0x579d,0x579e,0x579f,0x57a5,0x57a8,0x57aa,0x57ac,0x57af,
 125.212 +    0x57b0,0x57b1,0x57b3,0x57b5,0x57b6,0x57b7,0x57b9,0x57ba,0x57bb,0x57bc,
 125.213 +    0x57bd,0x57be,0x57bf,0x57c0,0x57c1,0x57c4,0x57c5,0x57c6,0x57c7,0x57c8,
 125.214 +    0x57c9,0x57ca,0x57cc,0x57cd,0x57d0,0x57d1,0x57d3,0x57d6,0x57d7,0x57db,
 125.215 +    0x57dc,0x57de,0x57e1,0x57e2,0x57e3,0x57e5,0x57e6,0x57e7,0x57e8,0x57e9,
 125.216 +    0x57ea,0x57eb,0x57ec,0x57ee,0x57f0,0x57f1,0x57f2,0x57f3,0x57f5,0x57f6,
 125.217 +    0x57f7,0x57fb,0x57fc,0x57fe,0x57ff,0x5801,0x5803,0x5804,0x5805,0x5808,
 125.218 +    0x5809,0x580a,0x580c,0x580e,0x580f,0x5810,0x5812,0x5813,0x5814,0x5816,
 125.219 +    0x5817,0x5818,0x581a,0x581b,0x581c,0x581d,0x581f,0x5822,0x5823,0x5825,
 125.220 +    0x5826,0x5827,0x5828,0x5829,0x582b,0x582c,0x582d,0x582e,0x582f,0x5831,
 125.221 +    0x5832,0x5833,0x5834,0x5836,0x5837,0x5838,0x5839,0x583a,0x583b,0x583c,
 125.222 +    0x583d
 125.223 +  },
 125.224 +  {				/* ku 09 */
 125.225 +    0x583e,0x583f,0x5840,0x5841,0x5842,0x5843,0x5845,0x5846,0x5847,0x5848,
 125.226 +    0x5849,0x584a,0x584b,0x584e,0x584f,0x5850,0x5852,0x5853,0x5855,0x5856,
 125.227 +    0x5857,0x5859,0x585a,0x585b,0x585c,0x585d,0x585f,0x5860,0x5861,0x5862,
 125.228 +    0x5863,0x5864,0x5866,0x5867,0x5868,0x5869,0x586a,0x586d,0x586e,0x586f,
 125.229 +    0x5870,0x5871,0x5872,0x5873,0x5874,0x5875,0x5876,0x5877,0x5878,0x5879,
 125.230 +    0x587a,0x587b,0x587c,0x587d,0x587f,0x5882,0x5884,0x5886,0x5887,0x5888,
 125.231 +    0x588a,0x588b,0x588c,UBOGON,0x588d,0x588e,0x588f,0x5890,0x5891,0x5894,
 125.232 +    0x5895,0x5896,0x5897,0x5898,0x589b,0x589c,0x589d,0x58a0,0x58a1,0x58a2,
 125.233 +    0x58a3,0x58a4,0x58a5,0x58a6,0x58a7,0x58aa,0x58ab,0x58ac,0x58ad,0x58ae,
 125.234 +    0x58af,0x58b0,0x58b1,0x58b2,0x58b3,0x58b4,0x58b5,0x58b6,0x58b7,0x58b8,
 125.235 +    0x58b9,0x58ba,0x58bb,0x58bd,0x58be,0x58bf,0x58c0,0x58c2,0x58c3,0x58c4,
 125.236 +    0x58c6,0x58c7,0x58c8,0x58c9,0x58ca,0x58cb,0x58cc,0x58cd,0x58ce,0x58cf,
 125.237 +    0x58d0,0x58d2,0x58d3,0x58d4,0x58d6,0x58d7,0x58d8,0x58d9,0x58da,0x58db,
 125.238 +    0x58dc,0x58dd,0x58de,0x58df,0x58e0,0x58e1,0x58e2,0x58e3,0x58e5,0x58e6,
 125.239 +    0x58e7,0x58e8,0x58e9,0x58ea,0x58ed,0x58ef,0x58f1,0x58f2,0x58f4,0x58f5,
 125.240 +    0x58f7,0x58f8,0x58fa,0x58fb,0x58fc,0x58fd,0x58fe,0x58ff,0x5900,0x5901,
 125.241 +    0x5903,0x5905,0x5906,0x5908,0x5909,0x590a,0x590b,0x590c,0x590e,0x5910,
 125.242 +    0x5911,0x5912,0x5913,0x5917,0x5918,0x591b,0x591d,0x591e,0x5920,0x5921,
 125.243 +    0x5922,0x5923,0x5926,0x5928,0x592c,0x5930,0x5932,0x5933,0x5935,0x5936,
 125.244 +    0x593b
 125.245 +  },
 125.246 +  {				/* ku 0a */
 125.247 +    0x593d,0x593e,0x593f,0x5940,0x5943,0x5945,0x5946,0x594a,0x594c,0x594d,
 125.248 +    0x5950,0x5952,0x5953,0x5959,0x595b,0x595c,0x595d,0x595e,0x595f,0x5961,
 125.249 +    0x5963,0x5964,0x5966,0x5967,0x5968,0x5969,0x596a,0x596b,0x596c,0x596d,
 125.250 +    0x596e,0x596f,0x5970,0x5971,0x5972,0x5975,0x5977,0x597a,0x597b,0x597c,
 125.251 +    0x597e,0x597f,0x5980,0x5985,0x5989,0x598b,0x598c,0x598e,0x598f,0x5990,
 125.252 +    0x5991,0x5994,0x5995,0x5998,0x599a,0x599b,0x599c,0x599d,0x599f,0x59a0,
 125.253 +    0x59a1,0x59a2,0x59a6,UBOGON,0x59a7,0x59ac,0x59ad,0x59b0,0x59b1,0x59b3,
 125.254 +    0x59b4,0x59b5,0x59b6,0x59b7,0x59b8,0x59ba,0x59bc,0x59bd,0x59bf,0x59c0,
 125.255 +    0x59c1,0x59c2,0x59c3,0x59c4,0x59c5,0x59c7,0x59c8,0x59c9,0x59cc,0x59cd,
 125.256 +    0x59ce,0x59cf,0x59d5,0x59d6,0x59d9,0x59db,0x59de,0x59df,0x59e0,0x59e1,
 125.257 +    0x59e2,0x59e4,0x59e6,0x59e7,0x59e9,0x59ea,0x59eb,0x59ed,0x59ee,0x59ef,
 125.258 +    0x59f0,0x59f1,0x59f2,0x59f3,0x59f4,0x59f5,0x59f6,0x59f7,0x59f8,0x59fa,
 125.259 +    0x59fc,0x59fd,0x59fe,0x5a00,0x5a02,0x5a0a,0x5a0b,0x5a0d,0x5a0e,0x5a0f,
 125.260 +    0x5a10,0x5a12,0x5a14,0x5a15,0x5a16,0x5a17,0x5a19,0x5a1a,0x5a1b,0x5a1d,
 125.261 +    0x5a1e,0x5a21,0x5a22,0x5a24,0x5a26,0x5a27,0x5a28,0x5a2a,0x5a2b,0x5a2c,
 125.262 +    0x5a2d,0x5a2e,0x5a2f,0x5a30,0x5a33,0x5a35,0x5a37,0x5a38,0x5a39,0x5a3a,
 125.263 +    0x5a3b,0x5a3d,0x5a3e,0x5a3f,0x5a41,0x5a42,0x5a43,0x5a44,0x5a45,0x5a47,
 125.264 +    0x5a48,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,0x5a50,0x5a51,0x5a52,0x5a53,
 125.265 +    0x5a54,0x5a56,0x5a57,0x5a58,0x5a59,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5a5f,
 125.266 +    0x5a60
 125.267 +  },
 125.268 +  {				/* ku 0b */
 125.269 +    0x5a61,0x5a63,0x5a64,0x5a65,0x5a66,0x5a68,0x5a69,0x5a6b,0x5a6c,0x5a6d,
 125.270 +    0x5a6e,0x5a6f,0x5a70,0x5a71,0x5a72,0x5a73,0x5a78,0x5a79,0x5a7b,0x5a7c,
 125.271 +    0x5a7d,0x5a7e,0x5a80,0x5a81,0x5a82,0x5a83,0x5a84,0x5a85,0x5a86,0x5a87,
 125.272 +    0x5a88,0x5a89,0x5a8a,0x5a8b,0x5a8c,0x5a8d,0x5a8e,0x5a8f,0x5a90,0x5a91,
 125.273 +    0x5a93,0x5a94,0x5a95,0x5a96,0x5a97,0x5a98,0x5a99,0x5a9c,0x5a9d,0x5a9e,
 125.274 +    0x5a9f,0x5aa0,0x5aa1,0x5aa2,0x5aa3,0x5aa4,0x5aa5,0x5aa6,0x5aa7,0x5aa8,
 125.275 +    0x5aa9,0x5aab,0x5aac,UBOGON,0x5aad,0x5aae,0x5aaf,0x5ab0,0x5ab1,0x5ab4,
 125.276 +    0x5ab6,0x5ab7,0x5ab9,0x5aba,0x5abb,0x5abc,0x5abd,0x5abf,0x5ac0,0x5ac3,
 125.277 +    0x5ac4,0x5ac5,0x5ac6,0x5ac7,0x5ac8,0x5aca,0x5acb,0x5acd,0x5ace,0x5acf,
 125.278 +    0x5ad0,0x5ad1,0x5ad3,0x5ad5,0x5ad7,0x5ad9,0x5ada,0x5adb,0x5add,0x5ade,
 125.279 +    0x5adf,0x5ae2,0x5ae4,0x5ae5,0x5ae7,0x5ae8,0x5aea,0x5aec,0x5aed,0x5aee,
 125.280 +    0x5aef,0x5af0,0x5af2,0x5af3,0x5af4,0x5af5,0x5af6,0x5af7,0x5af8,0x5af9,
 125.281 +    0x5afa,0x5afb,0x5afc,0x5afd,0x5afe,0x5aff,0x5b00,0x5b01,0x5b02,0x5b03,
 125.282 +    0x5b04,0x5b05,0x5b06,0x5b07,0x5b08,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e,
 125.283 +    0x5b0f,0x5b10,0x5b11,0x5b12,0x5b13,0x5b14,0x5b15,0x5b18,0x5b19,0x5b1a,
 125.284 +    0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,0x5b20,0x5b21,0x5b22,0x5b23,0x5b24,
 125.285 +    0x5b25,0x5b26,0x5b27,0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e,
 125.286 +    0x5b2f,0x5b30,0x5b31,0x5b33,0x5b35,0x5b36,0x5b38,0x5b39,0x5b3a,0x5b3b,
 125.287 +    0x5b3c,0x5b3d,0x5b3e,0x5b3f,0x5b41,0x5b42,0x5b43,0x5b44,0x5b45,0x5b46,
 125.288 +    0x5b47
 125.289 +  },
 125.290 +  {				/* ku 0c */
 125.291 +    0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,0x5b52,0x5b56,
 125.292 +    0x5b5e,0x5b60,0x5b61,0x5b67,0x5b68,0x5b6b,0x5b6d,0x5b6e,0x5b6f,0x5b72,
 125.293 +    0x5b74,0x5b76,0x5b77,0x5b78,0x5b79,0x5b7b,0x5b7c,0x5b7e,0x5b7f,0x5b82,
 125.294 +    0x5b86,0x5b8a,0x5b8d,0x5b8e,0x5b90,0x5b91,0x5b92,0x5b94,0x5b96,0x5b9f,
 125.295 +    0x5ba7,0x5ba8,0x5ba9,0x5bac,0x5bad,0x5bae,0x5baf,0x5bb1,0x5bb2,0x5bb7,
 125.296 +    0x5bba,0x5bbb,0x5bbc,0x5bc0,0x5bc1,0x5bc3,0x5bc8,0x5bc9,0x5bca,0x5bcb,
 125.297 +    0x5bcd,0x5bce,0x5bcf,UBOGON,0x5bd1,0x5bd4,0x5bd5,0x5bd6,0x5bd7,0x5bd8,
 125.298 +    0x5bd9,0x5bda,0x5bdb,0x5bdc,0x5be0,0x5be2,0x5be3,0x5be6,0x5be7,0x5be9,
 125.299 +    0x5bea,0x5beb,0x5bec,0x5bed,0x5bef,0x5bf1,0x5bf2,0x5bf3,0x5bf4,0x5bf5,
 125.300 +    0x5bf6,0x5bf7,0x5bfd,0x5bfe,0x5c00,0x5c02,0x5c03,0x5c05,0x5c07,0x5c08,
 125.301 +    0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c10,0x5c12,0x5c13,0x5c17,0x5c19,0x5c1b,
 125.302 +    0x5c1e,0x5c1f,0x5c20,0x5c21,0x5c23,0x5c26,0x5c28,0x5c29,0x5c2a,0x5c2b,
 125.303 +    0x5c2d,0x5c2e,0x5c2f,0x5c30,0x5c32,0x5c33,0x5c35,0x5c36,0x5c37,0x5c43,
 125.304 +    0x5c44,0x5c46,0x5c47,0x5c4c,0x5c4d,0x5c52,0x5c53,0x5c54,0x5c56,0x5c57,
 125.305 +    0x5c58,0x5c5a,0x5c5b,0x5c5c,0x5c5d,0x5c5f,0x5c62,0x5c64,0x5c67,0x5c68,
 125.306 +    0x5c69,0x5c6a,0x5c6b,0x5c6c,0x5c6d,0x5c70,0x5c72,0x5c73,0x5c74,0x5c75,
 125.307 +    0x5c76,0x5c77,0x5c78,0x5c7b,0x5c7c,0x5c7d,0x5c7e,0x5c80,0x5c83,0x5c84,
 125.308 +    0x5c85,0x5c86,0x5c87,0x5c89,0x5c8a,0x5c8b,0x5c8e,0x5c8f,0x5c92,0x5c93,
 125.309 +    0x5c95,0x5c9d,0x5c9e,0x5c9f,0x5ca0,0x5ca1,0x5ca4,0x5ca5,0x5ca6,0x5ca7,
 125.310 +    0x5ca8
 125.311 +  },
 125.312 +  {				/* ku 0d */
 125.313 +    0x5caa,0x5cae,0x5caf,0x5cb0,0x5cb2,0x5cb4,0x5cb6,0x5cb9,0x5cba,0x5cbb,
 125.314 +    0x5cbc,0x5cbe,0x5cc0,0x5cc2,0x5cc3,0x5cc5,0x5cc6,0x5cc7,0x5cc8,0x5cc9,
 125.315 +    0x5cca,0x5ccc,0x5ccd,0x5cce,0x5ccf,0x5cd0,0x5cd1,0x5cd3,0x5cd4,0x5cd5,
 125.316 +    0x5cd6,0x5cd7,0x5cd8,0x5cda,0x5cdb,0x5cdc,0x5cdd,0x5cde,0x5cdf,0x5ce0,
 125.317 +    0x5ce2,0x5ce3,0x5ce7,0x5ce9,0x5ceb,0x5cec,0x5cee,0x5cef,0x5cf1,0x5cf2,
 125.318 +    0x5cf3,0x5cf4,0x5cf5,0x5cf6,0x5cf7,0x5cf8,0x5cf9,0x5cfa,0x5cfc,0x5cfd,
 125.319 +    0x5cfe,0x5cff,0x5d00,UBOGON,0x5d01,0x5d04,0x5d05,0x5d08,0x5d09,0x5d0a,
 125.320 +    0x5d0b,0x5d0c,0x5d0d,0x5d0f,0x5d10,0x5d11,0x5d12,0x5d13,0x5d15,0x5d17,
 125.321 +    0x5d18,0x5d19,0x5d1a,0x5d1c,0x5d1d,0x5d1f,0x5d20,0x5d21,0x5d22,0x5d23,
 125.322 +    0x5d25,0x5d28,0x5d2a,0x5d2b,0x5d2c,0x5d2f,0x5d30,0x5d31,0x5d32,0x5d33,
 125.323 +    0x5d35,0x5d36,0x5d37,0x5d38,0x5d39,0x5d3a,0x5d3b,0x5d3c,0x5d3f,0x5d40,
 125.324 +    0x5d41,0x5d42,0x5d43,0x5d44,0x5d45,0x5d46,0x5d48,0x5d49,0x5d4d,0x5d4e,
 125.325 +    0x5d4f,0x5d50,0x5d51,0x5d52,0x5d53,0x5d54,0x5d55,0x5d56,0x5d57,0x5d59,
 125.326 +    0x5d5a,0x5d5c,0x5d5e,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d63,0x5d64,0x5d65,
 125.327 +    0x5d66,0x5d67,0x5d68,0x5d6a,0x5d6d,0x5d6e,0x5d70,0x5d71,0x5d72,0x5d73,
 125.328 +    0x5d75,0x5d76,0x5d77,0x5d78,0x5d79,0x5d7a,0x5d7b,0x5d7c,0x5d7d,0x5d7e,
 125.329 +    0x5d7f,0x5d80,0x5d81,0x5d83,0x5d84,0x5d85,0x5d86,0x5d87,0x5d88,0x5d89,
 125.330 +    0x5d8a,0x5d8b,0x5d8c,0x5d8d,0x5d8e,0x5d8f,0x5d90,0x5d91,0x5d92,0x5d93,
 125.331 +    0x5d94,0x5d95,0x5d96,0x5d97,0x5d98,0x5d9a,0x5d9b,0x5d9c,0x5d9e,0x5d9f,
 125.332 +    0x5da0
 125.333 +  },
 125.334 +  {				/* ku 0e */
 125.335 +    0x5da1,0x5da2,0x5da3,0x5da4,0x5da5,0x5da6,0x5da7,0x5da8,0x5da9,0x5daa,
 125.336 +    0x5dab,0x5dac,0x5dad,0x5dae,0x5daf,0x5db0,0x5db1,0x5db2,0x5db3,0x5db4,
 125.337 +    0x5db5,0x5db6,0x5db8,0x5db9,0x5dba,0x5dbb,0x5dbc,0x5dbd,0x5dbe,0x5dbf,
 125.338 +    0x5dc0,0x5dc1,0x5dc2,0x5dc3,0x5dc4,0x5dc6,0x5dc7,0x5dc8,0x5dc9,0x5dca,
 125.339 +    0x5dcb,0x5dcc,0x5dce,0x5dcf,0x5dd0,0x5dd1,0x5dd2,0x5dd3,0x5dd4,0x5dd5,
 125.340 +    0x5dd6,0x5dd7,0x5dd8,0x5dd9,0x5dda,0x5ddc,0x5ddf,0x5de0,0x5de3,0x5de4,
 125.341 +    0x5dea,0x5dec,0x5ded,UBOGON,0x5df0,0x5df5,0x5df6,0x5df8,0x5df9,0x5dfa,
 125.342 +    0x5dfb,0x5dfc,0x5dff,0x5e00,0x5e04,0x5e07,0x5e09,0x5e0a,0x5e0b,0x5e0d,
 125.343 +    0x5e0e,0x5e12,0x5e13,0x5e17,0x5e1e,0x5e1f,0x5e20,0x5e21,0x5e22,0x5e23,
 125.344 +    0x5e24,0x5e25,0x5e28,0x5e29,0x5e2a,0x5e2b,0x5e2c,0x5e2f,0x5e30,0x5e32,
 125.345 +    0x5e33,0x5e34,0x5e35,0x5e36,0x5e39,0x5e3a,0x5e3e,0x5e3f,0x5e40,0x5e41,
 125.346 +    0x5e43,0x5e46,0x5e47,0x5e48,0x5e49,0x5e4a,0x5e4b,0x5e4d,0x5e4e,0x5e4f,
 125.347 +    0x5e50,0x5e51,0x5e52,0x5e53,0x5e56,0x5e57,0x5e58,0x5e59,0x5e5a,0x5e5c,
 125.348 +    0x5e5d,0x5e5f,0x5e60,0x5e63,0x5e64,0x5e65,0x5e66,0x5e67,0x5e68,0x5e69,
 125.349 +    0x5e6a,0x5e6b,0x5e6c,0x5e6d,0x5e6e,0x5e6f,0x5e70,0x5e71,0x5e75,0x5e77,
 125.350 +    0x5e79,0x5e7e,0x5e81,0x5e82,0x5e83,0x5e85,0x5e88,0x5e89,0x5e8c,0x5e8d,
 125.351 +    0x5e8e,0x5e92,0x5e98,0x5e9b,0x5e9d,0x5ea1,0x5ea2,0x5ea3,0x5ea4,0x5ea8,
 125.352 +    0x5ea9,0x5eaa,0x5eab,0x5eac,0x5eae,0x5eaf,0x5eb0,0x5eb1,0x5eb2,0x5eb4,
 125.353 +    0x5eba,0x5ebb,0x5ebc,0x5ebd,0x5ebf,0x5ec0,0x5ec1,0x5ec2,0x5ec3,0x5ec4,
 125.354 +    0x5ec5
 125.355 +  },
 125.356 +  {				/* ku 0f */
 125.357 +    0x5ec6,0x5ec7,0x5ec8,0x5ecb,0x5ecc,0x5ecd,0x5ece,0x5ecf,0x5ed0,0x5ed4,
 125.358 +    0x5ed5,0x5ed7,0x5ed8,0x5ed9,0x5eda,0x5edc,0x5edd,0x5ede,0x5edf,0x5ee0,
 125.359 +    0x5ee1,0x5ee2,0x5ee3,0x5ee4,0x5ee5,0x5ee6,0x5ee7,0x5ee9,0x5eeb,0x5eec,
 125.360 +    0x5eed,0x5eee,0x5eef,0x5ef0,0x5ef1,0x5ef2,0x5ef3,0x5ef5,0x5ef8,0x5ef9,
 125.361 +    0x5efb,0x5efc,0x5efd,0x5f05,0x5f06,0x5f07,0x5f09,0x5f0c,0x5f0d,0x5f0e,
 125.362 +    0x5f10,0x5f12,0x5f14,0x5f16,0x5f19,0x5f1a,0x5f1c,0x5f1d,0x5f1e,0x5f21,
 125.363 +    0x5f22,0x5f23,0x5f24,UBOGON,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f32,
 125.364 +    0x5f33,0x5f34,0x5f35,0x5f36,0x5f37,0x5f38,0x5f3b,0x5f3d,0x5f3e,0x5f3f,
 125.365 +    0x5f41,0x5f42,0x5f43,0x5f44,0x5f45,0x5f46,0x5f47,0x5f48,0x5f49,0x5f4a,
 125.366 +    0x5f4b,0x5f4c,0x5f4d,0x5f4e,0x5f4f,0x5f51,0x5f54,0x5f59,0x5f5a,0x5f5b,
 125.367 +    0x5f5c,0x5f5e,0x5f5f,0x5f60,0x5f63,0x5f65,0x5f67,0x5f68,0x5f6b,0x5f6e,
 125.368 +    0x5f6f,0x5f72,0x5f74,0x5f75,0x5f76,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f7f,
 125.369 +    0x5f83,0x5f86,0x5f8d,0x5f8e,0x5f8f,0x5f91,0x5f93,0x5f94,0x5f96,0x5f9a,
 125.370 +    0x5f9b,0x5f9d,0x5f9e,0x5f9f,0x5fa0,0x5fa2,0x5fa3,0x5fa4,0x5fa5,0x5fa6,
 125.371 +    0x5fa7,0x5fa9,0x5fab,0x5fac,0x5faf,0x5fb0,0x5fb1,0x5fb2,0x5fb3,0x5fb4,
 125.372 +    0x5fb6,0x5fb8,0x5fb9,0x5fba,0x5fbb,0x5fbe,0x5fbf,0x5fc0,0x5fc1,0x5fc2,
 125.373 +    0x5fc7,0x5fc8,0x5fca,0x5fcb,0x5fce,0x5fd3,0x5fd4,0x5fd5,0x5fda,0x5fdb,
 125.374 +    0x5fdc,0x5fde,0x5fdf,0x5fe2,0x5fe3,0x5fe5,0x5fe6,0x5fe8,0x5fe9,0x5fec,
 125.375 +    0x5fef,0x5ff0,0x5ff2,0x5ff3,0x5ff4,0x5ff6,0x5ff7,0x5ff9,0x5ffa,0x5ffc,
 125.376 +    0x6007
 125.377 +  },
 125.378 +  {				/* ku 10 */
 125.379 +    0x6008,0x6009,0x600b,0x600c,0x6010,0x6011,0x6013,0x6017,0x6018,0x601a,
 125.380 +    0x601e,0x601f,0x6022,0x6023,0x6024,0x602c,0x602d,0x602e,0x6030,0x6031,
 125.381 +    0x6032,0x6033,0x6034,0x6036,0x6037,0x6038,0x6039,0x603a,0x603d,0x603e,
 125.382 +    0x6040,0x6044,0x6045,0x6046,0x6047,0x6048,0x6049,0x604a,0x604c,0x604e,
 125.383 +    0x604f,0x6051,0x6053,0x6054,0x6056,0x6057,0x6058,0x605b,0x605c,0x605e,
 125.384 +    0x605f,0x6060,0x6061,0x6065,0x6066,0x606e,0x6071,0x6072,0x6074,0x6075,
 125.385 +    0x6077,0x607e,0x6080,UBOGON,0x6081,0x6082,0x6085,0x6086,0x6087,0x6088,
 125.386 +    0x608a,0x608b,0x608e,0x608f,0x6090,0x6091,0x6093,0x6095,0x6097,0x6098,
 125.387 +    0x6099,0x609c,0x609e,0x60a1,0x60a2,0x60a4,0x60a5,0x60a7,0x60a9,0x60aa,
 125.388 +    0x60ae,0x60b0,0x60b3,0x60b5,0x60b6,0x60b7,0x60b9,0x60ba,0x60bd,0x60be,
 125.389 +    0x60bf,0x60c0,0x60c1,0x60c2,0x60c3,0x60c4,0x60c7,0x60c8,0x60c9,0x60cc,
 125.390 +    0x60cd,0x60ce,0x60cf,0x60d0,0x60d2,0x60d3,0x60d4,0x60d6,0x60d7,0x60d9,
 125.391 +    0x60db,0x60de,0x60e1,0x60e2,0x60e3,0x60e4,0x60e5,0x60ea,0x60f1,0x60f2,
 125.392 +    0x60f5,0x60f7,0x60f8,0x60fb,0x60fc,0x60fd,0x60fe,0x60ff,0x6102,0x6103,
 125.393 +    0x6104,0x6105,0x6107,0x610a,0x610b,0x610c,0x6110,0x6111,0x6112,0x6113,
 125.394 +    0x6114,0x6116,0x6117,0x6118,0x6119,0x611b,0x611c,0x611d,0x611e,0x6121,
 125.395 +    0x6122,0x6125,0x6128,0x6129,0x612a,0x612c,0x612d,0x612e,0x612f,0x6130,
 125.396 +    0x6131,0x6132,0x6133,0x6134,0x6135,0x6136,0x6137,0x6138,0x6139,0x613a,
 125.397 +    0x613b,0x613c,0x613d,0x613e,0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,
 125.398 +    0x6146
 125.399 +  },
 125.400 +  {				/* ku 11 */
 125.401 +    0x6147,0x6149,0x614b,0x614d,0x614f,0x6150,0x6152,0x6153,0x6154,0x6156,
 125.402 +    0x6157,0x6158,0x6159,0x615a,0x615b,0x615c,0x615e,0x615f,0x6160,0x6161,
 125.403 +    0x6163,0x6164,0x6165,0x6166,0x6169,0x616a,0x616b,0x616c,0x616d,0x616e,
 125.404 +    0x616f,0x6171,0x6172,0x6173,0x6174,0x6176,0x6178,0x6179,0x617a,0x617b,
 125.405 +    0x617c,0x617d,0x617e,0x617f,0x6180,0x6181,0x6182,0x6183,0x6184,0x6185,
 125.406 +    0x6186,0x6187,0x6188,0x6189,0x618a,0x618c,0x618d,0x618f,0x6190,0x6191,
 125.407 +    0x6192,0x6193,0x6195,UBOGON,0x6196,0x6197,0x6198,0x6199,0x619a,0x619b,
 125.408 +    0x619c,0x619e,0x619f,0x61a0,0x61a1,0x61a2,0x61a3,0x61a4,0x61a5,0x61a6,
 125.409 +    0x61aa,0x61ab,0x61ad,0x61ae,0x61af,0x61b0,0x61b1,0x61b2,0x61b3,0x61b4,
 125.410 +    0x61b5,0x61b6,0x61b8,0x61b9,0x61ba,0x61bb,0x61bc,0x61bd,0x61bf,0x61c0,
 125.411 +    0x61c1,0x61c3,0x61c4,0x61c5,0x61c6,0x61c7,0x61c9,0x61cc,0x61cd,0x61ce,
 125.412 +    0x61cf,0x61d0,0x61d3,0x61d5,0x61d6,0x61d7,0x61d8,0x61d9,0x61da,0x61db,
 125.413 +    0x61dc,0x61dd,0x61de,0x61df,0x61e0,0x61e1,0x61e2,0x61e3,0x61e4,0x61e5,
 125.414 +    0x61e7,0x61e8,0x61e9,0x61ea,0x61eb,0x61ec,0x61ed,0x61ee,0x61ef,0x61f0,
 125.415 +    0x61f1,0x61f2,0x61f3,0x61f4,0x61f6,0x61f7,0x61f8,0x61f9,0x61fa,0x61fb,
 125.416 +    0x61fc,0x61fd,0x61fe,0x6200,0x6201,0x6202,0x6203,0x6204,0x6205,0x6207,
 125.417 +    0x6209,0x6213,0x6214,0x6219,0x621c,0x621d,0x621e,0x6220,0x6223,0x6226,
 125.418 +    0x6227,0x6228,0x6229,0x622b,0x622d,0x622f,0x6230,0x6231,0x6232,0x6235,
 125.419 +    0x6236,0x6238,0x6239,0x623a,0x623b,0x623c,0x6242,0x6244,0x6245,0x6246,
 125.420 +    0x624a
 125.421 +  },
 125.422 +  {				/* ku 12 */
 125.423 +    0x624f,0x6250,0x6255,0x6256,0x6257,0x6259,0x625a,0x625c,0x625d,0x625e,
 125.424 +    0x625f,0x6260,0x6261,0x6262,0x6264,0x6265,0x6268,0x6271,0x6272,0x6274,
 125.425 +    0x6275,0x6277,0x6278,0x627a,0x627b,0x627d,0x6281,0x6282,0x6283,0x6285,
 125.426 +    0x6286,0x6287,0x6288,0x628b,0x628c,0x628d,0x628e,0x628f,0x6290,0x6294,
 125.427 +    0x6299,0x629c,0x629d,0x629e,0x62a3,0x62a6,0x62a7,0x62a9,0x62aa,0x62ad,
 125.428 +    0x62ae,0x62af,0x62b0,0x62b2,0x62b3,0x62b4,0x62b6,0x62b7,0x62b8,0x62ba,
 125.429 +    0x62be,0x62c0,0x62c1,UBOGON,0x62c3,0x62cb,0x62cf,0x62d1,0x62d5,0x62dd,
 125.430 +    0x62de,0x62e0,0x62e1,0x62e4,0x62ea,0x62eb,0x62f0,0x62f2,0x62f5,0x62f8,
 125.431 +    0x62f9,0x62fa,0x62fb,0x6300,0x6303,0x6304,0x6305,0x6306,0x630a,0x630b,
 125.432 +    0x630c,0x630d,0x630f,0x6310,0x6312,0x6313,0x6314,0x6315,0x6317,0x6318,
 125.433 +    0x6319,0x631c,0x6326,0x6327,0x6329,0x632c,0x632d,0x632e,0x6330,0x6331,
 125.434 +    0x6333,0x6334,0x6335,0x6336,0x6337,0x6338,0x633b,0x633c,0x633e,0x633f,
 125.435 +    0x6340,0x6341,0x6344,0x6347,0x6348,0x634a,0x6351,0x6352,0x6353,0x6354,
 125.436 +    0x6356,0x6357,0x6358,0x6359,0x635a,0x635b,0x635c,0x635d,0x6360,0x6364,
 125.437 +    0x6365,0x6366,0x6368,0x636a,0x636b,0x636c,0x636f,0x6370,0x6372,0x6373,
 125.438 +    0x6374,0x6375,0x6378,0x6379,0x637c,0x637d,0x637e,0x637f,0x6381,0x6383,
 125.439 +    0x6384,0x6385,0x6386,0x638b,0x638d,0x6391,0x6393,0x6394,0x6395,0x6397,
 125.440 +    0x6399,0x639a,0x639b,0x639c,0x639d,0x639e,0x639f,0x63a1,0x63a4,0x63a6,
 125.441 +    0x63ab,0x63af,0x63b1,0x63b2,0x63b5,0x63b6,0x63b9,0x63bb,0x63bd,0x63bf,
 125.442 +    0x63c0
 125.443 +  },
 125.444 +  {				/* ku 13 */
 125.445 +    0x63c1,0x63c2,0x63c3,0x63c5,0x63c7,0x63c8,0x63ca,0x63cb,0x63cc,0x63d1,
 125.446 +    0x63d3,0x63d4,0x63d5,0x63d7,0x63d8,0x63d9,0x63da,0x63db,0x63dc,0x63dd,
 125.447 +    0x63df,0x63e2,0x63e4,0x63e5,0x63e6,0x63e7,0x63e8,0x63eb,0x63ec,0x63ee,
 125.448 +    0x63ef,0x63f0,0x63f1,0x63f3,0x63f5,0x63f7,0x63f9,0x63fa,0x63fb,0x63fc,
 125.449 +    0x63fe,0x6403,0x6404,0x6406,0x6407,0x6408,0x6409,0x640a,0x640d,0x640e,
 125.450 +    0x6411,0x6412,0x6415,0x6416,0x6417,0x6418,0x6419,0x641a,0x641d,0x641f,
 125.451 +    0x6422,0x6423,0x6424,UBOGON,0x6425,0x6427,0x6428,0x6429,0x642b,0x642e,
 125.452 +    0x642f,0x6430,0x6431,0x6432,0x6433,0x6435,0x6436,0x6437,0x6438,0x6439,
 125.453 +    0x643b,0x643c,0x643e,0x6440,0x6442,0x6443,0x6449,0x644b,0x644c,0x644d,
 125.454 +    0x644e,0x644f,0x6450,0x6451,0x6453,0x6455,0x6456,0x6457,0x6459,0x645a,
 125.455 +    0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6462,0x6463,0x6464,0x6465,
 125.456 +    0x6466,0x6468,0x646a,0x646b,0x646c,0x646e,0x646f,0x6470,0x6471,0x6472,
 125.457 +    0x6473,0x6474,0x6475,0x6476,0x6477,0x647b,0x647c,0x647d,0x647e,0x647f,
 125.458 +    0x6480,0x6481,0x6483,0x6486,0x6488,0x6489,0x648a,0x648b,0x648c,0x648d,
 125.459 +    0x648e,0x648f,0x6490,0x6493,0x6494,0x6497,0x6498,0x649a,0x649b,0x649c,
 125.460 +    0x649d,0x649f,0x64a0,0x64a1,0x64a2,0x64a3,0x64a5,0x64a6,0x64a7,0x64a8,
 125.461 +    0x64aa,0x64ab,0x64af,0x64b1,0x64b2,0x64b3,0x64b4,0x64b6,0x64b9,0x64bb,
 125.462 +    0x64bd,0x64be,0x64bf,0x64c1,0x64c3,0x64c4,0x64c6,0x64c7,0x64c8,0x64c9,
 125.463 +    0x64ca,0x64cb,0x64cc,0x64cf,0x64d1,0x64d3,0x64d4,0x64d5,0x64d6,0x64d9,
 125.464 +    0x64da
 125.465 +  },
 125.466 +  {				/* ku 14 */
 125.467 +    0x64db,0x64dc,0x64dd,0x64df,0x64e0,0x64e1,0x64e3,0x64e5,0x64e7,0x64e8,
 125.468 +    0x64e9,0x64ea,0x64eb,0x64ec,0x64ed,0x64ee,0x64ef,0x64f0,0x64f1,0x64f2,
 125.469 +    0x64f3,0x64f4,0x64f5,0x64f6,0x64f7,0x64f8,0x64f9,0x64fa,0x64fb,0x64fc,
 125.470 +    0x64fd,0x64fe,0x64ff,0x6501,0x6502,0x6503,0x6504,0x6505,0x6506,0x6507,
 125.471 +    0x6508,0x650a,0x650b,0x650c,0x650d,0x650e,0x650f,0x6510,0x6511,0x6513,
 125.472 +    0x6514,0x6515,0x6516,0x6517,0x6519,0x651a,0x651b,0x651c,0x651d,0x651e,
 125.473 +    0x651f,0x6520,0x6521,UBOGON,0x6522,0x6523,0x6524,0x6526,0x6527,0x6528,
 125.474 +    0x6529,0x652a,0x652c,0x652d,0x6530,0x6531,0x6532,0x6533,0x6537,0x653a,
 125.475 +    0x653c,0x653d,0x6540,0x6541,0x6542,0x6543,0x6544,0x6546,0x6547,0x654a,
 125.476 +    0x654b,0x654d,0x654e,0x6550,0x6552,0x6553,0x6554,0x6557,0x6558,0x655a,
 125.477 +    0x655c,0x655f,0x6560,0x6561,0x6564,0x6565,0x6567,0x6568,0x6569,0x656a,
 125.478 +    0x656d,0x656e,0x656f,0x6571,0x6573,0x6575,0x6576,0x6578,0x6579,0x657a,
 125.479 +    0x657b,0x657c,0x657d,0x657e,0x657f,0x6580,0x6581,0x6582,0x6583,0x6584,
 125.480 +    0x6585,0x6586,0x6588,0x6589,0x658a,0x658d,0x658e,0x658f,0x6592,0x6594,
 125.481 +    0x6595,0x6596,0x6598,0x659a,0x659d,0x659e,0x65a0,0x65a2,0x65a3,0x65a6,
 125.482 +    0x65a8,0x65aa,0x65ac,0x65ae,0x65b1,0x65b2,0x65b3,0x65b4,0x65b5,0x65b6,
 125.483 +    0x65b7,0x65b8,0x65ba,0x65bb,0x65be,0x65bf,0x65c0,0x65c2,0x65c7,0x65c8,
 125.484 +    0x65c9,0x65ca,0x65cd,0x65d0,0x65d1,0x65d3,0x65d4,0x65d5,0x65d8,0x65d9,
 125.485 +    0x65da,0x65db,0x65dc,0x65dd,0x65de,0x65df,0x65e1,0x65e3,0x65e4,0x65ea,
 125.486 +    0x65eb
 125.487 +  },
 125.488 +  {				/* ku 15 */
 125.489 +    0x65f2,0x65f3,0x65f4,0x65f5,0x65f8,0x65f9,0x65fb,0x65fc,0x65fd,0x65fe,
 125.490 +    0x65ff,0x6601,0x6604,0x6605,0x6607,0x6608,0x6609,0x660b,0x660d,0x6610,
 125.491 +    0x6611,0x6612,0x6616,0x6617,0x6618,0x661a,0x661b,0x661c,0x661e,0x6621,
 125.492 +    0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c,0x662e,0x6630,
 125.493 +    0x6632,0x6633,0x6637,0x6638,0x6639,0x663a,0x663b,0x663d,0x663f,0x6640,
 125.494 +    0x6642,0x6644,0x6645,0x6646,0x6647,0x6648,0x6649,0x664a,0x664d,0x664e,
 125.495 +    0x6650,0x6651,0x6658,UBOGON,0x6659,0x665b,0x665c,0x665d,0x665e,0x6660,
 125.496 +    0x6662,0x6663,0x6665,0x6667,0x6669,0x666a,0x666b,0x666c,0x666d,0x6671,
 125.497 +    0x6672,0x6673,0x6675,0x6678,0x6679,0x667b,0x667c,0x667d,0x667f,0x6680,
 125.498 +    0x6681,0x6683,0x6685,0x6686,0x6688,0x6689,0x668a,0x668b,0x668d,0x668e,
 125.499 +    0x668f,0x6690,0x6692,0x6693,0x6694,0x6695,0x6698,0x6699,0x669a,0x669b,
 125.500 +    0x669c,0x669e,0x669f,0x66a0,0x66a1,0x66a2,0x66a3,0x66a4,0x66a5,0x66a6,
 125.501 +    0x66a9,0x66aa,0x66ab,0x66ac,0x66ad,0x66af,0x66b0,0x66b1,0x66b2,0x66b3,
 125.502 +    0x66b5,0x66b6,0x66b7,0x66b8,0x66ba,0x66bb,0x66bc,0x66bd,0x66bf,0x66c0,
 125.503 +    0x66c1,0x66c2,0x66c3,0x66c4,0x66c5,0x66c6,0x66c7,0x66c8,0x66c9,0x66ca,
 125.504 +    0x66cb,0x66cc,0x66cd,0x66ce,0x66cf,0x66d0,0x66d1,0x66d2,0x66d3,0x66d4,
 125.505 +    0x66d5,0x66d6,0x66d7,0x66d8,0x66da,0x66de,0x66df,0x66e0,0x66e1,0x66e2,
 125.506 +    0x66e3,0x66e4,0x66e5,0x66e7,0x66e8,0x66ea,0x66eb,0x66ec,0x66ed,0x66ee,
 125.507 +    0x66ef,0x66f1,0x66f5,0x66f6,0x66f8,0x66fa,0x66fb,0x66fd,0x6701,0x6702,
 125.508 +    0x6703
 125.509 +  },
 125.510 +  {				/* ku 16 */
 125.511 +    0x6704,0x6705,0x6706,0x6707,0x670c,0x670e,0x670f,0x6711,0x6712,0x6713,
 125.512 +    0x6716,0x6718,0x6719,0x671a,0x671c,0x671e,0x6720,0x6721,0x6722,0x6723,
 125.513 +    0x6724,0x6725,0x6727,0x6729,0x672e,0x6730,0x6732,0x6733,0x6736,0x6737,
 125.514 +    0x6738,0x6739,0x673b,0x673c,0x673e,0x673f,0x6741,0x6744,0x6745,0x6747,
 125.515 +    0x674a,0x674b,0x674d,0x6752,0x6754,0x6755,0x6757,0x6758,0x6759,0x675a,
 125.516 +    0x675b,0x675d,0x6762,0x6763,0x6764,0x6766,0x6767,0x676b,0x676c,0x676e,
 125.517 +    0x6771,0x6774,0x6776,UBOGON,0x6778,0x6779,0x677a,0x677b,0x677d,0x6780,
 125.518 +    0x6782,0x6783,0x6785,0x6786,0x6788,0x678a,0x678c,0x678d,0x678e,0x678f,
 125.519 +    0x6791,0x6792,0x6793,0x6794,0x6796,0x6799,0x679b,0x679f,0x67a0,0x67a1,
 125.520 +    0x67a4,0x67a6,0x67a9,0x67ac,0x67ae,0x67b1,0x67b2,0x67b4,0x67b9,0x67ba,
 125.521 +    0x67bb,0x67bc,0x67bd,0x67be,0x67bf,0x67c0,0x67c2,0x67c5,0x67c6,0x67c7,
 125.522 +    0x67c8,0x67c9,0x67ca,0x67cb,0x67cc,0x67cd,0x67ce,0x67d5,0x67d6,0x67d7,
 125.523 +    0x67db,0x67df,0x67e1,0x67e3,0x67e4,0x67e6,0x67e7,0x67e8,0x67ea,0x67eb,
 125.524 +    0x67ed,0x67ee,0x67f2,0x67f5,0x67f6,0x67f7,0x67f8,0x67f9,0x67fa,0x67fb,
 125.525 +    0x67fc,0x67fe,0x6801,0x6802,0x6803,0x6804,0x6806,0x680d,0x6810,0x6812,
 125.526 +    0x6814,0x6815,0x6818,0x6819,0x681a,0x681b,0x681c,0x681e,0x681f,0x6820,
 125.527 +    0x6822,0x6823,0x6824,0x6825,0x6826,0x6827,0x6828,0x682b,0x682c,0x682d,
 125.528 +    0x682e,0x682f,0x6830,0x6831,0x6834,0x6835,0x6836,0x683a,0x683b,0x683f,
 125.529 +    0x6847,0x684b,0x684d,0x684f,0x6852,0x6856,0x6857,0x6858,0x6859,0x685a,
 125.530 +    0x685b
 125.531 +  },
 125.532 +  {				/* ku 17 */
 125.533 +    0x685c,0x685d,0x685e,0x685f,0x686a,0x686c,0x686d,0x686e,0x686f,0x6870,
 125.534 +    0x6871,0x6872,0x6873,0x6875,0x6878,0x6879,0x687a,0x687b,0x687c,0x687d,
 125.535 +    0x687e,0x687f,0x6880,0x6882,0x6884,0x6887,0x6888,0x6889,0x688a,0x688b,
 125.536 +    0x688c,0x688d,0x688e,0x6890,0x6891,0x6892,0x6894,0x6895,0x6896,0x6898,
 125.537 +    0x6899,0x689a,0x689b,0x689c,0x689d,0x689e,0x689f,0x68a0,0x68a1,0x68a3,
 125.538 +    0x68a4,0x68a5,0x68a9,0x68aa,0x68ab,0x68ac,0x68ae,0x68b1,0x68b2,0x68b4,
 125.539 +    0x68b6,0x68b7,0x68b8,UBOGON,0x68b9,0x68ba,0x68bb,0x68bc,0x68bd,0x68be,
 125.540 +    0x68bf,0x68c1,0x68c3,0x68c4,0x68c5,0x68c6,0x68c7,0x68c8,0x68ca,0x68cc,
 125.541 +    0x68ce,0x68cf,0x68d0,0x68d1,0x68d3,0x68d4,0x68d6,0x68d7,0x68d9,0x68db,
 125.542 +    0x68dc,0x68dd,0x68de,0x68df,0x68e1,0x68e2,0x68e4,0x68e5,0x68e6,0x68e7,
 125.543 +    0x68e8,0x68e9,0x68ea,0x68eb,0x68ec,0x68ed,0x68ef,0x68f2,0x68f3,0x68f4,
 125.544 +    0x68f6,0x68f7,0x68f8,0x68fb,0x68fd,0x68fe,0x68ff,0x6900,0x6902,0x6903,
 125.545 +    0x6904,0x6906,0x6907,0x6908,0x6909,0x690a,0x690c,0x690f,0x6911,0x6913,
 125.546 +    0x6914,0x6915,0x6916,0x6917,0x6918,0x6919,0x691a,0x691b,0x691c,0x691d,
 125.547 +    0x691e,0x6921,0x6922,0x6923,0x6925,0x6926,0x6927,0x6928,0x6929,0x692a,
 125.548 +    0x692b,0x692c,0x692e,0x692f,0x6931,0x6932,0x6933,0x6935,0x6936,0x6937,
 125.549 +    0x6938,0x693a,0x693b,0x693c,0x693e,0x6940,0x6941,0x6943,0x6944,0x6945,
 125.550 +    0x6946,0x6947,0x6948,0x6949,0x694a,0x694b,0x694c,0x694d,0x694e,0x694f,
 125.551 +    0x6950,0x6951,0x6952,0x6953,0x6955,0x6956,0x6958,0x6959,0x695b,0x695c,
 125.552 +    0x695f
 125.553 +  },
 125.554 +  {				/* ku 18 */
 125.555 +    0x6961,0x6962,0x6964,0x6965,0x6967,0x6968,0x6969,0x696a,0x696c,0x696d,
 125.556 +    0x696f,0x6970,0x6972,0x6973,0x6974,0x6975,0x6976,0x697a,0x697b,0x697d,
 125.557 +    0x697e,0x697f,0x6981,0x6983,0x6985,0x698a,0x698b,0x698c,0x698e,0x698f,
 125.558 +    0x6990,0x6991,0x6992,0x6993,0x6996,0x6997,0x6999,0x699a,0x699d,0x699e,
 125.559 +    0x699f,0x69a0,0x69a1,0x69a2,0x69a3,0x69a4,0x69a5,0x69a6,0x69a9,0x69aa,
 125.560 +    0x69ac,0x69ae,0x69af,0x69b0,0x69b2,0x69b3,0x69b5,0x69b6,0x69b8,0x69b9,
 125.561 +    0x69ba,0x69bc,0x69bd,UBOGON,0x69be,0x69bf,0x69c0,0x69c2,0x69c3,0x69c4,
 125.562 +    0x69c5,0x69c6,0x69c7,0x69c8,0x69c9,0x69cb,0x69cd,0x69cf,0x69d1,0x69d2,
 125.563 +    0x69d3,0x69d5,0x69d6,0x69d7,0x69d8,0x69d9,0x69da,0x69dc,0x69dd,0x69de,
 125.564 +    0x69e1,0x69e2,0x69e3,0x69e4,0x69e5,0x69e6,0x69e7,0x69e8,0x69e9,0x69ea,
 125.565 +    0x69eb,0x69ec,0x69ee,0x69ef,0x69f0,0x69f1,0x69f3,0x69f4,0x69f5,0x69f6,
 125.566 +    0x69f7,0x69f8,0x69f9,0x69fa,0x69fb,0x69fc,0x69fe,0x6a00,0x6a01,0x6a02,
 125.567 +    0x6a03,0x6a04,0x6a05,0x6a06,0x6a07,0x6a08,0x6a09,0x6a0b,0x6a0c,0x6a0d,
 125.568 +    0x6a0e,0x6a0f,0x6a10,0x6a11,0x6a12,0x6a13,0x6a14,0x6a15,0x6a16,0x6a19,
 125.569 +    0x6a1a,0x6a1b,0x6a1c,0x6a1d,0x6a1e,0x6a20,0x6a22,0x6a23,0x6a24,0x6a25,
 125.570 +    0x6a26,0x6a27,0x6a29,0x6a2b,0x6a2c,0x6a2d,0x6a2e,0x6a30,0x6a32,0x6a33,
 125.571 +    0x6a34,0x6a36,0x6a37,0x6a38,0x6a39,0x6a3a,0x6a3b,0x6a3c,0x6a3f,0x6a40,
 125.572 +    0x6a41,0x6a42,0x6a43,0x6a45,0x6a46,0x6a48,0x6a49,0x6a4a,0x6a4b,0x6a4c,
 125.573 +    0x6a4d,0x6a4e,0x6a4f,0x6a51,0x6a52,0x6a53,0x6a54,0x6a55,0x6a56,0x6a57,
 125.574 +    0x6a5a
 125.575 +  },
 125.576 +  {				/* ku 19 */
 125.577 +    0x6a5c,0x6a5d,0x6a5e,0x6a5f,0x6a60,0x6a62,0x6a63,0x6a64,0x6a66,0x6a67,
 125.578 +    0x6a68,0x6a69,0x6a6a,0x6a6b,0x6a6c,0x6a6d,0x6a6e,0x6a6f,0x6a70,0x6a72,
 125.579 +    0x6a73,0x6a74,0x6a75,0x6a76,0x6a77,0x6a78,0x6a7a,0x6a7b,0x6a7d,0x6a7e,
 125.580 +    0x6a7f,0x6a81,0x6a82,0x6a83,0x6a85,0x6a86,0x6a87,0x6a88,0x6a89,0x6a8a,
 125.581 +    0x6a8b,0x6a8c,0x6a8d,0x6a8f,0x6a92,0x6a93,0x6a94,0x6a95,0x6a96,0x6a98,
 125.582 +    0x6a99,0x6a9a,0x6a9b,0x6a9c,0x6a9d,0x6a9e,0x6a9f,0x6aa1,0x6aa2,0x6aa3,
 125.583 +    0x6aa4,0x6aa5,0x6aa6,UBOGON,0x6aa7,0x6aa8,0x6aaa,0x6aad,0x6aae,0x6aaf,
 125.584 +    0x6ab0,0x6ab1,0x6ab2,0x6ab3,0x6ab4,0x6ab5,0x6ab6,0x6ab7,0x6ab8,0x6ab9,
 125.585 +    0x6aba,0x6abb,0x6abc,0x6abd,0x6abe,0x6abf,0x6ac0,0x6ac1,0x6ac2,0x6ac3,
 125.586 +    0x6ac4,0x6ac5,0x6ac6,0x6ac7,0x6ac8,0x6ac9,0x6aca,0x6acb,0x6acc,0x6acd,
 125.587 +    0x6ace,0x6acf,0x6ad0,0x6ad1,0x6ad2,0x6ad3,0x6ad4,0x6ad5,0x6ad6,0x6ad7,
 125.588 +    0x6ad8,0x6ad9,0x6ada,0x6adb,0x6adc,0x6add,0x6ade,0x6adf,0x6ae0,0x6ae1,
 125.589 +    0x6ae2,0x6ae3,0x6ae4,0x6ae5,0x6ae6,0x6ae7,0x6ae8,0x6ae9,0x6aea,0x6aeb,
 125.590 +    0x6aec,0x6aed,0x6aee,0x6aef,0x6af0,0x6af1,0x6af2,0x6af3,0x6af4,0x6af5,
 125.591 +    0x6af6,0x6af7,0x6af8,0x6af9,0x6afa,0x6afb,0x6afc,0x6afd,0x6afe,0x6aff,
 125.592 +    0x6b00,0x6b01,0x6b02,0x6b03,0x6b04,0x6b05,0x6b06,0x6b07,0x6b08,0x6b09,
 125.593 +    0x6b0a,0x6b0b,0x6b0c,0x6b0d,0x6b0e,0x6b0f,0x6b10,0x6b11,0x6b12,0x6b13,
 125.594 +    0x6b14,0x6b15,0x6b16,0x6b17,0x6b18,0x6b19,0x6b1a,0x6b1b,0x6b1c,0x6b1d,
 125.595 +    0x6b1e,0x6b1f,0x6b25,0x6b26,0x6b28,0x6b29,0x6b2a,0x6b2b,0x6b2c,0x6b2d,
 125.596 +    0x6b2e
 125.597 +  },
 125.598 +  {				/* ku 1a */
 125.599 +    0x6b2f,0x6b30,0x6b31,0x6b33,0x6b34,0x6b35,0x6b36,0x6b38,0x6b3b,0x6b3c,
 125.600 +    0x6b3d,0x6b3f,0x6b40,0x6b41,0x6b42,0x6b44,0x6b45,0x6b48,0x6b4a,0x6b4b,
 125.601 +    0x6b4d,0x6b4e,0x6b4f,0x6b50,0x6b51,0x6b52,0x6b53,0x6b54,0x6b55,0x6b56,
 125.602 +    0x6b57,0x6b58,0x6b5a,0x6b5b,0x6b5c,0x6b5d,0x6b5e,0x6b5f,0x6b60,0x6b61,
 125.603 +    0x6b68,0x6b69,0x6b6b,0x6b6c,0x6b6d,0x6b6e,0x6b6f,0x6b70,0x6b71,0x6b72,
 125.604 +    0x6b73,0x6b74,0x6b75,0x6b76,0x6b77,0x6b78,0x6b7a,0x6b7d,0x6b7e,0x6b7f,
 125.605 +    0x6b80,0x6b85,0x6b88,UBOGON,0x6b8c,0x6b8e,0x6b8f,0x6b90,0x6b91,0x6b94,
 125.606 +    0x6b95,0x6b97,0x6b98,0x6b99,0x6b9c,0x6b9d,0x6b9e,0x6b9f,0x6ba0,0x6ba2,
 125.607 +    0x6ba3,0x6ba4,0x6ba5,0x6ba6,0x6ba7,0x6ba8,0x6ba9,0x6bab,0x6bac,0x6bad,
 125.608 +    0x6bae,0x6baf,0x6bb0,0x6bb1,0x6bb2,0x6bb6,0x6bb8,0x6bb9,0x6bba,0x6bbb,
 125.609 +    0x6bbc,0x6bbd,0x6bbe,0x6bc0,0x6bc3,0x6bc4,0x6bc6,0x6bc7,0x6bc8,0x6bc9,
 125.610 +    0x6bca,0x6bcc,0x6bce,0x6bd0,0x6bd1,0x6bd8,0x6bda,0x6bdc,0x6bdd,0x6bde,
 125.611 +    0x6bdf,0x6be0,0x6be2,0x6be3,0x6be4,0x6be5,0x6be6,0x6be7,0x6be8,0x6be9,
 125.612 +    0x6bec,0x6bed,0x6bee,0x6bf0,0x6bf1,0x6bf2,0x6bf4,0x6bf6,0x6bf7,0x6bf8,
 125.613 +    0x6bfa,0x6bfb,0x6bfc,0x6bfe,0x6bff,0x6c00,0x6c01,0x6c02,0x6c03,0x6c04,
 125.614 +    0x6c08,0x6c09,0x6c0a,0x6c0b,0x6c0c,0x6c0e,0x6c12,0x6c17,0x6c1c,0x6c1d,
 125.615 +    0x6c1e,0x6c20,0x6c23,0x6c25,0x6c2b,0x6c2c,0x6c2d,0x6c31,0x6c33,0x6c36,
 125.616 +    0x6c37,0x6c39,0x6c3a,0x6c3b,0x6c3c,0x6c3e,0x6c3f,0x6c43,0x6c44,0x6c45,
 125.617 +    0x6c48,0x6c4b,0x6c4c,0x6c4d,0x6c4e,0x6c4f,0x6c51,0x6c52,0x6c53,0x6c56,
 125.618 +    0x6c58
 125.619 +  },
 125.620 +  {				/* ku 1b */
 125.621 +    0x6c59,0x6c5a,0x6c62,0x6c63,0x6c65,0x6c66,0x6c67,0x6c6b,0x6c6c,0x6c6d,
 125.622 +    0x6c6e,0x6c6f,0x6c71,0x6c73,0x6c75,0x6c77,0x6c78,0x6c7a,0x6c7b,0x6c7c,
 125.623 +    0x6c7f,0x6c80,0x6c84,0x6c87,0x6c8a,0x6c8b,0x6c8d,0x6c8e,0x6c91,0x6c92,
 125.624 +    0x6c95,0x6c96,0x6c97,0x6c98,0x6c9a,0x6c9c,0x6c9d,0x6c9e,0x6ca0,0x6ca2,
 125.625 +    0x6ca8,0x6cac,0x6caf,0x6cb0,0x6cb4,0x6cb5,0x6cb6,0x6cb7,0x6cba,0x6cc0,
 125.626 +    0x6cc1,0x6cc2,0x6cc3,0x6cc6,0x6cc7,0x6cc8,0x6ccb,0x6ccd,0x6cce,0x6ccf,
 125.627 +    0x6cd1,0x6cd2,0x6cd8,UBOGON,0x6cd9,0x6cda,0x6cdc,0x6cdd,0x6cdf,0x6ce4,
 125.628 +    0x6ce6,0x6ce7,0x6ce9,0x6cec,0x6ced,0x6cf2,0x6cf4,0x6cf9,0x6cff,0x6d00,
 125.629 +    0x6d02,0x6d03,0x6d05,0x6d06,0x6d08,0x6d09,0x6d0a,0x6d0d,0x6d0f,0x6d10,
 125.630 +    0x6d11,0x6d13,0x6d14,0x6d15,0x6d16,0x6d18,0x6d1c,0x6d1d,0x6d1f,0x6d20,
 125.631 +    0x6d21,0x6d22,0x6d23,0x6d24,0x6d26,0x6d28,0x6d29,0x6d2c,0x6d2d,0x6d2f,
 125.632 +    0x6d30,0x6d34,0x6d36,0x6d37,0x6d38,0x6d3a,0x6d3f,0x6d40,0x6d42,0x6d44,
 125.633 +    0x6d49,0x6d4c,0x6d50,0x6d55,0x6d56,0x6d57,0x6d58,0x6d5b,0x6d5d,0x6d5f,
 125.634 +    0x6d61,0x6d62,0x6d64,0x6d65,0x6d67,0x6d68,0x6d6b,0x6d6c,0x6d6d,0x6d70,
 125.635 +    0x6d71,0x6d72,0x6d73,0x6d75,0x6d76,0x6d79,0x6d7a,0x6d7b,0x6d7d,0x6d7e,
 125.636 +    0x6d7f,0x6d80,0x6d81,0x6d83,0x6d84,0x6d86,0x6d87,0x6d8a,0x6d8b,0x6d8d,
 125.637 +    0x6d8f,0x6d90,0x6d92,0x6d96,0x6d97,0x6d98,0x6d99,0x6d9a,0x6d9c,0x6da2,
 125.638 +    0x6da5,0x6dac,0x6dad,0x6db0,0x6db1,0x6db3,0x6db4,0x6db6,0x6db7,0x6db9,
 125.639 +    0x6dba,0x6dbb,0x6dbc,0x6dbd,0x6dbe,0x6dc1,0x6dc2,0x6dc3,0x6dc8,0x6dc9,
 125.640 +    0x6dca
 125.641 +  },
 125.642 +  {				/* ku 1c */
 125.643 +    0x6dcd,0x6dce,0x6dcf,0x6dd0,0x6dd2,0x6dd3,0x6dd4,0x6dd5,0x6dd7,0x6dda,
 125.644 +    0x6ddb,0x6ddc,0x6ddf,0x6de2,0x6de3,0x6de5,0x6de7,0x6de8,0x6de9,0x6dea,
 125.645 +    0x6ded,0x6def,0x6df0,0x6df2,0x6df4,0x6df5,0x6df6,0x6df8,0x6dfa,0x6dfd,
 125.646 +    0x6dfe,0x6dff,0x6e00,0x6e01,0x6e02,0x6e03,0x6e04,0x6e06,0x6e07,0x6e08,
 125.647 +    0x6e09,0x6e0b,0x6e0f,0x6e12,0x6e13,0x6e15,0x6e18,0x6e19,0x6e1b,0x6e1c,
 125.648 +    0x6e1e,0x6e1f,0x6e22,0x6e26,0x6e27,0x6e28,0x6e2a,0x6e2c,0x6e2e,0x6e30,
 125.649 +    0x6e31,0x6e33,0x6e35,UBOGON,0x6e36,0x6e37,0x6e39,0x6e3b,0x6e3c,0x6e3d,
 125.650 +    0x6e3e,0x6e3f,0x6e40,0x6e41,0x6e42,0x6e45,0x6e46,0x6e47,0x6e48,0x6e49,
 125.651 +    0x6e4a,0x6e4b,0x6e4c,0x6e4f,0x6e50,0x6e51,0x6e52,0x6e55,0x6e57,0x6e59,
 125.652 +    0x6e5a,0x6e5c,0x6e5d,0x6e5e,0x6e60,0x6e61,0x6e62,0x6e63,0x6e64,0x6e65,
 125.653 +    0x6e66,0x6e67,0x6e68,0x6e69,0x6e6a,0x6e6c,0x6e6d,0x6e6f,0x6e70,0x6e71,
 125.654 +    0x6e72,0x6e73,0x6e74,0x6e75,0x6e76,0x6e77,0x6e78,0x6e79,0x6e7a,0x6e7b,
 125.655 +    0x6e7c,0x6e7d,0x6e80,0x6e81,0x6e82,0x6e84,0x6e87,0x6e88,0x6e8a,0x6e8b,
 125.656 +    0x6e8c,0x6e8d,0x6e8e,0x6e91,0x6e92,0x6e93,0x6e94,0x6e95,0x6e96,0x6e97,
 125.657 +    0x6e99,0x6e9a,0x6e9b,0x6e9d,0x6e9e,0x6ea0,0x6ea1,0x6ea3,0x6ea4,0x6ea6,
 125.658 +    0x6ea8,0x6ea9,0x6eab,0x6eac,0x6ead,0x6eae,0x6eb0,0x6eb3,0x6eb5,0x6eb8,
 125.659 +    0x6eb9,0x6ebc,0x6ebe,0x6ebf,0x6ec0,0x6ec3,0x6ec4,0x6ec5,0x6ec6,0x6ec8,
 125.660 +    0x6ec9,0x6eca,0x6ecc,0x6ecd,0x6ece,0x6ed0,0x6ed2,0x6ed6,0x6ed8,0x6ed9,
 125.661 +    0x6edb,0x6edc,0x6edd,0x6ee3,0x6ee7,0x6eea,0x6eeb,0x6eec,0x6eed,0x6eee,
 125.662 +    0x6eef
 125.663 +  },
 125.664 +  {				/* ku 1d */
 125.665 +    0x6ef0,0x6ef1,0x6ef2,0x6ef3,0x6ef5,0x6ef6,0x6ef7,0x6ef8,0x6efa,0x6efb,
 125.666 +    0x6efc,0x6efd,0x6efe,0x6eff,0x6f00,0x6f01,0x6f03,0x6f04,0x6f05,0x6f07,
 125.667 +    0x6f08,0x6f0a,0x6f0b,0x6f0c,0x6f0d,0x6f0e,0x6f10,0x6f11,0x6f12,0x6f16,
 125.668 +    0x6f17,0x6f18,0x6f19,0x6f1a,0x6f1b,0x6f1c,0x6f1d,0x6f1e,0x6f1f,0x6f21,
 125.669 +    0x6f22,0x6f23,0x6f25,0x6f26,0x6f27,0x6f28,0x6f2c,0x6f2e,0x6f30,0x6f32,
 125.670 +    0x6f34,0x6f35,0x6f37,0x6f38,0x6f39,0x6f3a,0x6f3b,0x6f3c,0x6f3d,0x6f3f,
 125.671 +    0x6f40,0x6f41,0x6f42,UBOGON,0x6f43,0x6f44,0x6f45,0x6f48,0x6f49,0x6f4a,
 125.672 +    0x6f4c,0x6f4e,0x6f4f,0x6f50,0x6f51,0x6f52,0x6f53,0x6f54,0x6f55,0x6f56,
 125.673 +    0x6f57,0x6f59,0x6f5a,0x6f5b,0x6f5d,0x6f5f,0x6f60,0x6f61,0x6f63,0x6f64,
 125.674 +    0x6f65,0x6f67,0x6f68,0x6f69,0x6f6a,0x6f6b,0x6f6c,0x6f6f,0x6f70,0x6f71,
 125.675 +    0x6f73,0x6f75,0x6f76,0x6f77,0x6f79,0x6f7b,0x6f7d,0x6f7e,0x6f7f,0x6f80,
 125.676 +    0x6f81,0x6f82,0x6f83,0x6f85,0x6f86,0x6f87,0x6f8a,0x6f8b,0x6f8f,0x6f90,
 125.677 +    0x6f91,0x6f92,0x6f93,0x6f94,0x6f95,0x6f96,0x6f97,0x6f98,0x6f99,0x6f9a,
 125.678 +    0x6f9b,0x6f9d,0x6f9e,0x6f9f,0x6fa0,0x6fa2,0x6fa3,0x6fa4,0x6fa5,0x6fa6,
 125.679 +    0x6fa8,0x6fa9,0x6faa,0x6fab,0x6fac,0x6fad,0x6fae,0x6faf,0x6fb0,0x6fb1,
 125.680 +    0x6fb2,0x6fb4,0x6fb5,0x6fb7,0x6fb8,0x6fba,0x6fbb,0x6fbc,0x6fbd,0x6fbe,
 125.681 +    0x6fbf,0x6fc1,0x6fc3,0x6fc4,0x6fc5,0x6fc6,0x6fc7,0x6fc8,0x6fca,0x6fcb,
 125.682 +    0x6fcc,0x6fcd,0x6fce,0x6fcf,0x6fd0,0x6fd3,0x6fd4,0x6fd5,0x6fd6,0x6fd7,
 125.683 +    0x6fd8,0x6fd9,0x6fda,0x6fdb,0x6fdc,0x6fdd,0x6fdf,0x6fe2,0x6fe3,0x6fe4,
 125.684 +    0x6fe5
 125.685 +  },
 125.686 +  {				/* ku 1e */
 125.687 +    0x6fe6,0x6fe7,0x6fe8,0x6fe9,0x6fea,0x6feb,0x6fec,0x6fed,0x6ff0,0x6ff1,
 125.688 +    0x6ff2,0x6ff3,0x6ff4,0x6ff5,0x6ff6,0x6ff7,0x6ff8,0x6ff9,0x6ffa,0x6ffb,
 125.689 +    0x6ffc,0x6ffd,0x6ffe,0x6fff,0x7000,0x7001,0x7002,0x7003,0x7004,0x7005,
 125.690 +    0x7006,0x7007,0x7008,0x7009,0x700a,0x700b,0x700c,0x700d,0x700e,0x700f,
 125.691 +    0x7010,0x7012,0x7013,0x7014,0x7015,0x7016,0x7017,0x7018,0x7019,0x701c,
 125.692 +    0x701d,0x701e,0x701f,0x7020,0x7021,0x7022,0x7024,0x7025,0x7026,0x7027,
 125.693 +    0x7028,0x7029,0x702a,UBOGON,0x702b,0x702c,0x702d,0x702e,0x702f,0x7030,
 125.694 +    0x7031,0x7032,0x7033,0x7034,0x7036,0x7037,0x7038,0x703a,0x703b,0x703c,
 125.695 +    0x703d,0x703e,0x703f,0x7040,0x7041,0x7042,0x7043,0x7044,0x7045,0x7046,
 125.696 +    0x7047,0x7048,0x7049,0x704a,0x704b,0x704d,0x704e,0x7050,0x7051,0x7052,
 125.697 +    0x7053,0x7054,0x7055,0x7056,0x7057,0x7058,0x7059,0x705a,0x705b,0x705c,
 125.698 +    0x705d,0x705f,0x7060,0x7061,0x7062,0x7063,0x7064,0x7065,0x7066,0x7067,
 125.699 +    0x7068,0x7069,0x706a,0x706e,0x7071,0x7072,0x7073,0x7074,0x7077,0x7079,
 125.700 +    0x707a,0x707b,0x707d,0x7081,0x7082,0x7083,0x7084,0x7086,0x7087,0x7088,
 125.701 +    0x708b,0x708c,0x708d,0x708f,0x7090,0x7091,0x7093,0x7097,0x7098,0x709a,
 125.702 +    0x709b,0x709e,0x709f,0x70a0,0x70a1,0x70a2,0x70a3,0x70a4,0x70a5,0x70a6,
 125.703 +    0x70a7,0x70a8,0x70a9,0x70aa,0x70b0,0x70b2,0x70b4,0x70b5,0x70b6,0x70ba,
 125.704 +    0x70be,0x70bf,0x70c4,0x70c5,0x70c6,0x70c7,0x70c9,0x70cb,0x70cc,0x70cd,
 125.705 +    0x70ce,0x70cf,0x70d0,0x70d1,0x70d2,0x70d3,0x70d4,0x70d5,0x70d6,0x70d7,
 125.706 +    0x70da
 125.707 +  },
 125.708 +  {				/* ku 1f */
 125.709 +    0x70dc,0x70dd,0x70de,0x70e0,0x70e1,0x70e2,0x70e3,0x70e5,0x70ea,0x70ee,
 125.710 +    0x70f0,0x70f1,0x70f2,0x70f3,0x70f4,0x70f5,0x70f6,0x70f8,0x70fa,0x70fb,
 125.711 +    0x70fc,0x70fe,0x70ff,0x7100,0x7101,0x7102,0x7103,0x7104,0x7105,0x7106,
 125.712 +    0x7107,0x7108,0x710b,0x710c,0x710d,0x710e,0x710f,0x7111,0x7112,0x7114,
 125.713 +    0x7117,0x711b,0x711c,0x711d,0x711e,0x711f,0x7120,0x7121,0x7122,0x7123,
 125.714 +    0x7124,0x7125,0x7127,0x7128,0x7129,0x712a,0x712b,0x712c,0x712d,0x712e,
 125.715 +    0x7132,0x7133,0x7134,UBOGON,0x7135,0x7137,0x7138,0x7139,0x713a,0x713b,
 125.716 +    0x713c,0x713d,0x713e,0x713f,0x7140,0x7141,0x7142,0x7143,0x7144,0x7146,
 125.717 +    0x7147,0x7148,0x7149,0x714b,0x714d,0x714f,0x7150,0x7151,0x7152,0x7153,
 125.718 +    0x7154,0x7155,0x7156,0x7157,0x7158,0x7159,0x715a,0x715b,0x715d,0x715f,
 125.719 +    0x7160,0x7161,0x7162,0x7163,0x7165,0x7169,0x716a,0x716b,0x716c,0x716d,
 125.720 +    0x716f,0x7170,0x7171,0x7174,0x7175,0x7176,0x7177,0x7179,0x717b,0x717c,
 125.721 +    0x717e,0x717f,0x7180,0x7181,0x7182,0x7183,0x7185,0x7186,0x7187,0x7188,
 125.722 +    0x7189,0x718b,0x718c,0x718d,0x718e,0x7190,0x7191,0x7192,0x7193,0x7195,
 125.723 +    0x7196,0x7197,0x719a,0x719b,0x719c,0x719d,0x719e,0x71a1,0x71a2,0x71a3,
 125.724 +    0x71a4,0x71a5,0x71a6,0x71a7,0x71a9,0x71aa,0x71ab,0x71ad,0x71ae,0x71af,
 125.725 +    0x71b0,0x71b1,0x71b2,0x71b4,0x71b6,0x71b7,0x71b8,0x71ba,0x71bb,0x71bc,
 125.726 +    0x71bd,0x71be,0x71bf,0x71c0,0x71c1,0x71c2,0x71c4,0x71c5,0x71c6,0x71c7,
 125.727 +    0x71c8,0x71c9,0x71ca,0x71cb,0x71cc,0x71cd,0x71cf,0x71d0,0x71d1,0x71d2,
 125.728 +    0x71d3
 125.729 +  },
 125.730 +  {				/* ku 20 */
 125.731 +    0x71d6,0x71d7,0x71d8,0x71d9,0x71da,0x71db,0x71dc,0x71dd,0x71de,0x71df,
 125.732 +    0x71e1,0x71e2,0x71e3,0x71e4,0x71e6,0x71e8,0x71e9,0x71ea,0x71eb,0x71ec,
 125.733 +    0x71ed,0x71ef,0x71f0,0x71f1,0x71f2,0x71f3,0x71f4,0x71f5,0x71f6,0x71f7,
 125.734 +    0x71f8,0x71fa,0x71fb,0x71fc,0x71fd,0x71fe,0x71ff,0x7200,0x7201,0x7202,
 125.735 +    0x7203,0x7204,0x7205,0x7207,0x7208,0x7209,0x720a,0x720b,0x720c,0x720d,
 125.736 +    0x720e,0x720f,0x7210,0x7211,0x7212,0x7213,0x7214,0x7215,0x7216,0x7217,
 125.737 +    0x7218,0x7219,0x721a,UBOGON,0x721b,0x721c,0x721e,0x721f,0x7220,0x7221,
 125.738 +    0x7222,0x7223,0x7224,0x7225,0x7226,0x7227,0x7229,0x722b,0x722d,0x722e,
 125.739 +    0x722f,0x7232,0x7233,0x7234,0x723a,0x723c,0x723e,0x7240,0x7241,0x7242,
 125.740 +    0x7243,0x7244,0x7245,0x7246,0x7249,0x724a,0x724b,0x724e,0x724f,0x7250,
 125.741 +    0x7251,0x7253,0x7254,0x7255,0x7257,0x7258,0x725a,0x725c,0x725e,0x7260,
 125.742 +    0x7263,0x7264,0x7265,0x7268,0x726a,0x726b,0x726c,0x726d,0x7270,0x7271,
 125.743 +    0x7273,0x7274,0x7276,0x7277,0x7278,0x727b,0x727c,0x727d,0x7282,0x7283,
 125.744 +    0x7285,0x7286,0x7287,0x7288,0x7289,0x728c,0x728e,0x7290,0x7291,0x7293,
 125.745 +    0x7294,0x7295,0x7296,0x7297,0x7298,0x7299,0x729a,0x729b,0x729c,0x729d,
 125.746 +    0x729e,0x72a0,0x72a1,0x72a2,0x72a3,0x72a4,0x72a5,0x72a6,0x72a7,0x72a8,
 125.747 +    0x72a9,0x72aa,0x72ab,0x72ae,0x72b1,0x72b2,0x72b3,0x72b5,0x72ba,0x72bb,
 125.748 +    0x72bc,0x72bd,0x72be,0x72bf,0x72c0,0x72c5,0x72c6,0x72c7,0x72c9,0x72ca,
 125.749 +    0x72cb,0x72cc,0x72cf,0x72d1,0x72d3,0x72d4,0x72d5,0x72d6,0x72d8,0x72da,
 125.750 +    0x72db
 125.751 +  },
 125.752 +  {				/* ku 21 */
 125.753 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.754 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.755 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.756 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.757 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.758 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.759 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.760 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.761 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.762 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3000,0x3001,0x3002,
 125.763 +    0x00b7,0x02c9,0x02c7,0x00a8,0x3003,0x3005,0x2014,0xff5e,0x2016,0x2026,
 125.764 +    0x2018,0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,0x3009,0x300a,0x300b,
 125.765 +    0x300c,0x300d,0x300e,0x300f,0x3016,0x3017,0x3010,0x3011,0x00b1,0x00d7,
 125.766 +    0x00f7,0x2236,0x2227,0x2228,0x2211,0x220f,0x222a,0x2229,0x2208,0x2237,
 125.767 +    0x221a,0x22a5,0x2225,0x2220,0x2312,0x2299,0x222b,0x222e,0x2261,0x224c,
 125.768 +    0x2248,0x223d,0x221d,0x2260,0x226e,0x226f,0x2264,0x2265,0x221e,0x2235,
 125.769 +    0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,0xff04,0x00a4,0xffe0,
 125.770 +    0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605,0x25cb,0x25cf,0x25ce,0x25c7,
 125.771 +    0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x203b,0x2192,0x2190,0x2191,0x2193,
 125.772 +    0x3013
 125.773 +  },
 125.774 +  {				/* ku 22 */
 125.775 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.776 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.777 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.778 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.779 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.780 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.781 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.782 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.783 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.784 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2170,0x2171,0x2172,
 125.785 +    0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,UBOGON,UBOGON,UBOGON,
 125.786 +    UBOGON,UBOGON,UBOGON,0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,
 125.787 +    0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,0x2498,
 125.788 +    0x2499,0x249a,0x249b,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,
 125.789 +    0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,0x2482,0x2483,0x2484,
 125.790 +    0x2485,0x2486,0x2487,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,
 125.791 +    0x2467,0x2468,0x2469,UBOGON,UBOGON,0x3220,0x3221,0x3222,0x3223,0x3224,
 125.792 +    0x3225,0x3226,0x3227,0x3228,0x3229,UBOGON,UBOGON,0x2160,0x2161,0x2162,
 125.793 +    0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216a,0x216b,UBOGON,
 125.794 +    UBOGON
 125.795 +  },
 125.796 +  {				/* ku 23 */
 125.797 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.798 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.799 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.800 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.801 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.802 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.803 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.804 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.805 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.806 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xff01,0xff02,0xff03,
 125.807 +    0xffe5,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,
 125.808 +    0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,
 125.809 +    0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21,
 125.810 +    0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,
 125.811 +    0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,
 125.812 +    0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,
 125.813 +    0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,
 125.814 +    0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,
 125.815 +    0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,
 125.816 +    0xffe3
 125.817 +  },
 125.818 +  {				/* ku 24 */
 125.819 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.820 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.821 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.822 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.823 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.824 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.825 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.826 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.827 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.828 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3041,0x3042,0x3043,
 125.829 +    0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,
 125.830 +    0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,
 125.831 +    0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,
 125.832 +    0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,
 125.833 +    0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,
 125.834 +    0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,
 125.835 +    0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,
 125.836 +    0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,
 125.837 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.838 +    UBOGON
 125.839 +  },
 125.840 +  {				/* ku 25 */
 125.841 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.842 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.843 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.844 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.845 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.846 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.847 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.848 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.849 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.850 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30a1,0x30a2,0x30a3,
 125.851 +    0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,
 125.852 +    0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,
 125.853 +    0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,
 125.854 +    0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,
 125.855 +    0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,
 125.856 +    0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,
 125.857 +    0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,0x30e9,
 125.858 +    0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,0x30f3,
 125.859 +    0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.860 +    UBOGON
 125.861 +  },
 125.862 +  {				/* ku 26 */
 125.863 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.864 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.865 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.866 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.867 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.868 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.869 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.870 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.871 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.872 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0391,0x0392,0x0393,
 125.873 +    0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,
 125.874 +    0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,
 125.875 +    0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x03b1,
 125.876 +    0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,
 125.877 +    0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,
 125.878 +    0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.879 +    0xfe35,0xfe36,0xfe39,0xfe3a,0xfe3f,0xfe40,0xfe3d,0xfe3e,0xfe41,0xfe42,
 125.880 +    0xfe43,0xfe44,UBOGON,UBOGON,0xfe3b,0xfe3c,0xfe37,0xfe38,0xfe31,UBOGON,
 125.881 +    0xfe33,0xfe34,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.882 +    UBOGON
 125.883 +  },
 125.884 +  {				/* ku 27 */
 125.885 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.886 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.887 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.888 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.889 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.890 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.891 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.892 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.893 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.894 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0410,0x0411,0x0412,
 125.895 +    0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,0x0419,0x041a,0x041b,
 125.896 +    0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,
 125.897 +    0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
 125.898 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.899 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,0x0432,0x0433,0x0434,
 125.900 +    0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,
 125.901 +    0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
 125.902 +    0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,UBOGON,UBOGON,
 125.903 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.904 +    UBOGON
 125.905 +  },
 125.906 +  {				/* ku 28 */
 125.907 +    0x02ca,0x02cb,0x02d9,0x2013,0x2015,0x2025,0x2035,0x2105,0x2109,0x2196,
 125.908 +    0x2197,0x2198,0x2199,0x2215,0x221f,0x2223,0x2252,0x2266,0x2267,0x22bf,
 125.909 +    0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,0x2558,0x2559,
 125.910 +    0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,0x2560,0x2561,0x2562,0x2563,
 125.911 +    0x2564,0x2565,0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,
 125.912 +    0x256e,0x256f,0x2570,0x2571,0x2572,0x2573,0x2581,0x2582,0x2583,0x2584,
 125.913 +    0x2585,0x2586,0x2587,UBOGON,0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,
 125.914 +    0x258e,0x258f,0x2593,0x2594,0x2595,0x25bc,0x25bd,0x25e2,0x25e3,0x25e4,
 125.915 +    0x25e5,0x2609,0x2295,0x3012,0x301d,0x301e,UBOGON,UBOGON,UBOGON,UBOGON,
 125.916 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0101,0x00e1,0x01ce,
 125.917 +    0x00e0,0x0113,0x00e9,0x011b,0x00e8,0x012b,0x00ed,0x01d0,0x00ec,0x014d,
 125.918 +    0x00f3,0x01d2,0x00f2,0x016b,0x00fa,0x01d4,0x00f9,0x01d6,0x01d8,0x01da,
 125.919 +    0x01dc,0x00fc,0x00ea,0x0251,UBOGON,0x0144,0x0148,UBOGON,0x0261,UBOGON,
 125.920 +    UBOGON,UBOGON,UBOGON,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,0x310b,
 125.921 +    0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,
 125.922 +    0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,
 125.923 +    0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,0x3128,0x3129,
 125.924 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.925 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.926 +    UBOGON
 125.927 +  },
 125.928 +  {				/* ku 29 */
 125.929 +    0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,0x3029,0x32a3,
 125.930 +    0x338e,0x338f,0x339c,0x339d,0x339e,0x33a1,0x33c4,0x33ce,0x33d1,0x33d2,
 125.931 +    0x33d5,0xfe30,0xffe2,0xffe4,UBOGON,0x2121,0x3231,UBOGON,0x2010,UBOGON,
 125.932 +    UBOGON,UBOGON,0x30fc,0x309b,0x309c,0x30fd,0x30fe,0x3006,0x309d,0x309e,
 125.933 +    0xfe49,0xfe4a,0xfe4b,0xfe4c,0xfe4d,0xfe4e,0xfe4f,0xfe50,0xfe51,0xfe52,
 125.934 +    0xfe54,0xfe55,0xfe56,0xfe57,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,
 125.935 +    0xfe5f,0xfe60,0xfe61,UBOGON,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0xfe68,
 125.936 +    0xfe69,0xfe6a,0xfe6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.937 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3007,UBOGON,UBOGON,UBOGON,
 125.938 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.939 +    0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,0x2508,0x2509,
 125.940 +    0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,0x2510,0x2511,0x2512,0x2513,
 125.941 +    0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,
 125.942 +    0x251e,0x251f,0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
 125.943 +    0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,0x2530,0x2531,
 125.944 +    0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538,0x2539,0x253a,0x253b,
 125.945 +    0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,
 125.946 +    0x2546,0x2547,0x2548,0x2549,0x254a,0x254b,UBOGON,UBOGON,UBOGON,UBOGON,
 125.947 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.948 +    UBOGON
 125.949 +  },
 125.950 +  {				/* ku 2a */
 125.951 +    0x72dc,0x72dd,0x72df,0x72e2,0x72e3,0x72e4,0x72e5,0x72e6,0x72e7,0x72ea,
 125.952 +    0x72eb,0x72f5,0x72f6,0x72f9,0x72fd,0x72fe,0x72ff,0x7300,0x7302,0x7304,
 125.953 +    0x7305,0x7306,0x7307,0x7308,0x7309,0x730b,0x730c,0x730d,0x730f,0x7310,
 125.954 +    0x7311,0x7312,0x7314,0x7318,0x7319,0x731a,0x731f,0x7320,0x7323,0x7324,
 125.955 +    0x7326,0x7327,0x7328,0x732d,0x732f,0x7330,0x7332,0x7333,0x7335,0x7336,
 125.956 +    0x733a,0x733b,0x733c,0x733d,0x7340,0x7341,0x7342,0x7343,0x7344,0x7345,
 125.957 +    0x7346,0x7347,0x7348,UBOGON,0x7349,0x734a,0x734b,0x734c,0x734e,0x734f,
 125.958 +    0x7351,0x7353,0x7354,0x7355,0x7356,0x7358,0x7359,0x735a,0x735b,0x735c,
 125.959 +    0x735d,0x735e,0x735f,0x7361,0x7362,0x7363,0x7364,0x7365,0x7366,0x7367,
 125.960 +    0x7368,0x7369,0x736a,0x736b,0x736e,0x7370,0x7371,UBOGON,UBOGON,UBOGON,
 125.961 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.962 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.963 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.964 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.965 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.966 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.967 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.968 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.969 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.970 +    UBOGON
 125.971 +  },
 125.972 +  {				/* ku 2b */
 125.973 +    0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,0x7378,0x7379,0x737a,0x737b,
 125.974 +    0x737c,0x737d,0x737f,0x7380,0x7381,0x7382,0x7383,0x7385,0x7386,0x7388,
 125.975 +    0x738a,0x738c,0x738d,0x738f,0x7390,0x7392,0x7393,0x7394,0x7395,0x7397,
 125.976 +    0x7398,0x7399,0x739a,0x739c,0x739d,0x739e,0x73a0,0x73a1,0x73a3,0x73a4,
 125.977 +    0x73a5,0x73a6,0x73a7,0x73a8,0x73aa,0x73ac,0x73ad,0x73b1,0x73b4,0x73b5,
 125.978 +    0x73b6,0x73b8,0x73b9,0x73bc,0x73bd,0x73be,0x73bf,0x73c1,0x73c3,0x73c4,
 125.979 +    0x73c5,0x73c6,0x73c7,UBOGON,0x73cb,0x73cc,0x73ce,0x73d2,0x73d3,0x73d4,
 125.980 +    0x73d5,0x73d6,0x73d7,0x73d8,0x73da,0x73db,0x73dc,0x73dd,0x73df,0x73e1,
 125.981 +    0x73e2,0x73e3,0x73e4,0x73e6,0x73e8,0x73ea,0x73eb,0x73ec,0x73ee,0x73ef,
 125.982 +    0x73f0,0x73f1,0x73f3,0x73f4,0x73f5,0x73f6,0x73f7,UBOGON,UBOGON,UBOGON,
 125.983 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.984 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.985 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.986 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.987 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.988 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.989 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.990 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.991 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 125.992 +    UBOGON
 125.993 +  },
 125.994 +  {				/* ku 2c */
 125.995 +    0x73f8,0x73f9,0x73fa,0x73fb,0x73fc,0x73fd,0x73fe,0x73ff,0x7400,0x7401,
 125.996 +    0x7402,0x7404,0x7407,0x7408,0x740b,0x740c,0x740d,0x740e,0x7411,0x7412,
 125.997 +    0x7413,0x7414,0x7415,0x7416,0x7417,0x7418,0x7419,0x741c,0x741d,0x741e,
 125.998 +    0x741f,0x7420,0x7421,0x7423,0x7424,0x7427,0x7429,0x742b,0x742d,0x742f,
 125.999 +    0x7431,0x7432,0x7437,0x7438,0x7439,0x743a,0x743b,0x743d,0x743e,0x743f,
125.1000 +    0x7440,0x7442,0x7443,0x7444,0x7445,0x7446,0x7447,0x7448,0x7449,0x744a,
125.1001 +    0x744b,0x744c,0x744d,UBOGON,0x744e,0x744f,0x7450,0x7451,0x7452,0x7453,
125.1002 +    0x7454,0x7456,0x7458,0x745d,0x7460,0x7461,0x7462,0x7463,0x7464,0x7465,
125.1003 +    0x7466,0x7467,0x7468,0x7469,0x746a,0x746b,0x746c,0x746e,0x746f,0x7471,
125.1004 +    0x7472,0x7473,0x7474,0x7475,0x7478,0x7479,0x747a,UBOGON,UBOGON,UBOGON,
125.1005 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1006 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1007 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1008 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1009 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1010 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1011 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1012 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1013 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1014 +    UBOGON
125.1015 +  },
125.1016 +  {				/* ku 2d */
125.1017 +    0x747b,0x747c,0x747d,0x747f,0x7482,0x7484,0x7485,0x7486,0x7488,0x7489,
125.1018 +    0x748a,0x748c,0x748d,0x748f,0x7491,0x7492,0x7493,0x7494,0x7495,0x7496,
125.1019 +    0x7497,0x7498,0x7499,0x749a,0x749b,0x749d,0x749f,0x74a0,0x74a1,0x74a2,
125.1020 +    0x74a3,0x74a4,0x74a5,0x74a6,0x74aa,0x74ab,0x74ac,0x74ad,0x74ae,0x74af,
125.1021 +    0x74b0,0x74b1,0x74b2,0x74b3,0x74b4,0x74b5,0x74b6,0x74b7,0x74b8,0x74b9,
125.1022 +    0x74bb,0x74bc,0x74bd,0x74be,0x74bf,0x74c0,0x74c1,0x74c2,0x74c3,0x74c4,
125.1023 +    0x74c5,0x74c6,0x74c7,UBOGON,0x74c8,0x74c9,0x74ca,0x74cb,0x74cc,0x74cd,
125.1024 +    0x74ce,0x74cf,0x74d0,0x74d1,0x74d3,0x74d4,0x74d5,0x74d6,0x74d7,0x74d8,
125.1025 +    0x74d9,0x74da,0x74db,0x74dd,0x74df,0x74e1,0x74e5,0x74e7,0x74e8,0x74e9,
125.1026 +    0x74ea,0x74eb,0x74ec,0x74ed,0x74f0,0x74f1,0x74f2,UBOGON,UBOGON,UBOGON,
125.1027 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1030 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1031 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1032 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1033 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1034 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1035 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1036 +    UBOGON
125.1037 +  },
125.1038 +  {				/* ku 2e */
125.1039 +    0x74f3,0x74f5,0x74f8,0x74f9,0x74fa,0x74fb,0x74fc,0x74fd,0x74fe,0x7500,
125.1040 +    0x7501,0x7502,0x7503,0x7505,0x7506,0x7507,0x7508,0x7509,0x750a,0x750b,
125.1041 +    0x750c,0x750e,0x7510,0x7512,0x7514,0x7515,0x7516,0x7517,0x751b,0x751d,
125.1042 +    0x751e,0x7520,0x7521,0x7522,0x7523,0x7524,0x7526,0x7527,0x752a,0x752e,
125.1043 +    0x7534,0x7536,0x7539,0x753c,0x753d,0x753f,0x7541,0x7542,0x7543,0x7544,
125.1044 +    0x7546,0x7547,0x7549,0x754a,0x754d,0x7550,0x7551,0x7552,0x7553,0x7555,
125.1045 +    0x7556,0x7557,0x7558,UBOGON,0x755d,0x755e,0x755f,0x7560,0x7561,0x7562,
125.1046 +    0x7563,0x7564,0x7567,0x7568,0x7569,0x756b,0x756c,0x756d,0x756e,0x756f,
125.1047 +    0x7570,0x7571,0x7573,0x7575,0x7576,0x7577,0x757a,0x757b,0x757c,0x757d,
125.1048 +    0x757e,0x7580,0x7581,0x7582,0x7584,0x7585,0x7587,UBOGON,UBOGON,UBOGON,
125.1049 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1050 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1051 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1052 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1053 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1054 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1055 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1056 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1057 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1058 +    UBOGON
125.1059 +  },
125.1060 +  {				/* ku 2f */
125.1061 +    0x7588,0x7589,0x758a,0x758c,0x758d,0x758e,0x7590,0x7593,0x7595,0x7598,
125.1062 +    0x759b,0x759c,0x759e,0x75a2,0x75a6,0x75a7,0x75a8,0x75a9,0x75aa,0x75ad,
125.1063 +    0x75b6,0x75b7,0x75ba,0x75bb,0x75bf,0x75c0,0x75c1,0x75c6,0x75cb,0x75cc,
125.1064 +    0x75ce,0x75cf,0x75d0,0x75d1,0x75d3,0x75d7,0x75d9,0x75da,0x75dc,0x75dd,
125.1065 +    0x75df,0x75e0,0x75e1,0x75e5,0x75e9,0x75ec,0x75ed,0x75ee,0x75ef,0x75f2,
125.1066 +    0x75f3,0x75f5,0x75f6,0x75f7,0x75f8,0x75fa,0x75fb,0x75fd,0x75fe,0x7602,
125.1067 +    0x7604,0x7606,0x7607,UBOGON,0x7608,0x7609,0x760b,0x760d,0x760e,0x760f,
125.1068 +    0x7611,0x7612,0x7613,0x7614,0x7616,0x761a,0x761c,0x761d,0x761e,0x7621,
125.1069 +    0x7623,0x7627,0x7628,0x762c,0x762e,0x762f,0x7631,0x7632,0x7636,0x7637,
125.1070 +    0x7639,0x763a,0x763b,0x763d,0x7641,0x7642,0x7644,UBOGON,UBOGON,UBOGON,
125.1071 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1072 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1073 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1074 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1075 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1076 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1077 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1078 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1079 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.1080 +    UBOGON
125.1081 +  },
125.1082 +  {				/* ku 30 */
125.1083 +    0x7645,0x7646,0x7647,0x7648,0x7649,0x764a,0x764b,0x764e,0x764f,0x7650,
125.1084 +    0x7651,0x7652,0x7653,0x7655,0x7657,0x7658,0x7659,0x765a,0x765b,0x765d,
125.1085 +    0x765f,0x7660,0x7661,0x7662,0x7664,0x7665,0x7666,0x7667,0x7668,0x7669,
125.1086 +    0x766a,0x766c,0x766d,0x766e,0x7670,0x7671,0x7672,0x7673,0x7674,0x7675,
125.1087 +    0x7676,0x7677,0x7679,0x767a,0x767c,0x767f,0x7680,0x7681,0x7683,0x7685,
125.1088 +    0x7689,0x768a,0x768c,0x768d,0x768f,0x7690,0x7692,0x7694,0x7695,0x7697,
125.1089 +    0x7698,0x769a,0x769b,UBOGON,0x769c,0x769d,0x769e,0x769f,0x76a0,0x76a1,
125.1090 +    0x76a2,0x76a3,0x76a5,0x76a6,0x76a7,0x76a8,0x76a9,0x76aa,0x76ab,0x76ac,
125.1091 +    0x76ad,0x76af,0x76b0,0x76b3,0x76b5,0x76b6,0x76b7,0x76b8,0x76b9,0x76ba,
125.1092 +    0x76bb,0x76bc,0x76bd,0x76be,0x76c0,0x76c1,0x76c3,0x554a,0x963f,0x57c3,
125.1093 +    0x6328,0x54ce,0x5509,0x54c0,0x7691,0x764c,0x853c,0x77ee,0x827e,0x788d,
125.1094 +    0x7231,0x9698,0x978d,0x6c28,0x5b89,0x4ffa,0x6309,0x6697,0x5cb8,0x80fa,
125.1095 +    0x6848,0x80ae,0x6602,0x76ce,0x51f9,0x6556,0x71ac,0x7ff1,0x8884,0x50b2,
125.1096 +    0x5965,0x61ca,0x6fb3,0x82ad,0x634c,0x6252,0x53ed,0x5427,0x7b06,0x516b,
125.1097 +    0x75a4,0x5df4,0x62d4,0x8dcb,0x9776,0x628a,0x8019,0x575d,0x9738,0x7f62,
125.1098 +    0x7238,0x767d,0x67cf,0x767e,0x6446,0x4f70,0x8d25,0x62dc,0x7a17,0x6591,
125.1099 +    0x73ed,0x642c,0x6273,0x822c,0x9881,0x677f,0x7248,0x626e,0x62cc,0x4f34,
125.1100 +    0x74e3,0x534a,0x529e,0x7eca,0x90a6,0x5e2e,0x6886,0x699c,0x8180,0x7ed1,
125.1101 +    0x68d2,0x78c5,0x868c,0x9551,0x508d,0x8c24,0x82de,0x80de,0x5305,0x8912,
125.1102 +    0x5265
125.1103 +  },
125.1104 +  {				/* ku 31 */
125.1105 +    0x76c4,0x76c7,0x76c9,0x76cb,0x76cc,0x76d3,0x76d5,0x76d9,0x76da,0x76dc,
125.1106 +    0x76dd,0x76de,0x76e0,0x76e1,0x76e2,0x76e3,0x76e4,0x76e6,0x76e7,0x76e8,
125.1107 +    0x76e9,0x76ea,0x76eb,0x76ec,0x76ed,0x76f0,0x76f3,0x76f5,0x76f6,0x76f7,
125.1108 +    0x76fa,0x76fb,0x76fd,0x76ff,0x7700,0x7702,0x7703,0x7705,0x7706,0x770a,
125.1109 +    0x770c,0x770e,0x770f,0x7710,0x7711,0x7712,0x7713,0x7714,0x7715,0x7716,
125.1110 +    0x7717,0x7718,0x771b,0x771c,0x771d,0x771e,0x7721,0x7723,0x7724,0x7725,
125.1111 +    0x7727,0x772a,0x772b,UBOGON,0x772c,0x772e,0x7730,0x7731,0x7732,0x7733,
125.1112 +    0x7734,0x7739,0x773b,0x773d,0x773e,0x773f,0x7742,0x7744,0x7745,0x7746,
125.1113 +    0x7748,0x7749,0x774a,0x774b,0x774c,0x774d,0x774e,0x774f,0x7752,0x7753,
125.1114 +    0x7754,0x7755,0x7756,0x7757,0x7758,0x7759,0x775c,0x8584,0x96f9,0x4fdd,
125.1115 +    0x5821,0x9971,0x5b9d,0x62b1,0x62a5,0x66b4,0x8c79,0x9c8d,0x7206,0x676f,
125.1116 +    0x7891,0x60b2,0x5351,0x5317,0x8f88,0x80cc,0x8d1d,0x94a1,0x500d,0x72c8,
125.1117 +    0x5907,0x60eb,0x7119,0x88ab,0x5954,0x82ef,0x672c,0x7b28,0x5d29,0x7ef7,
125.1118 +    0x752d,0x6cf5,0x8e66,0x8ff8,0x903c,0x9f3b,0x6bd4,0x9119,0x7b14,0x5f7c,
125.1119 +    0x78a7,0x84d6,0x853d,0x6bd5,0x6bd9,0x6bd6,0x5e01,0x5e87,0x75f9,0x95ed,
125.1120 +    0x655d,0x5f0a,0x5fc5,0x8f9f,0x58c1,0x81c2,0x907f,0x965b,0x97ad,0x8fb9,
125.1121 +    0x7f16,0x8d2c,0x6241,0x4fbf,0x53d8,0x535e,0x8fa8,0x8fa9,0x8fab,0x904d,
125.1122 +    0x6807,0x5f6a,0x8198,0x8868,0x9cd6,0x618b,0x522b,0x762a,0x5f6c,0x658c,
125.1123 +    0x6fd2,0x6ee8,0x5bbe,0x6448,0x5175,0x51b0,0x67c4,0x4e19,0x79c9,0x997c,
125.1124 +    0x70b3
125.1125 +  },
125.1126 +  {				/* ku 32 */
125.1127 +    0x775d,0x775e,0x775f,0x7760,0x7764,0x7767,0x7769,0x776a,0x776d,0x776e,
125.1128 +    0x776f,0x7770,0x7771,0x7772,0x7773,0x7774,0x7775,0x7776,0x7777,0x7778,
125.1129 +    0x777a,0x777b,0x777c,0x7781,0x7782,0x7783,0x7786,0x7787,0x7788,0x7789,
125.1130 +    0x778a,0x778b,0x778f,0x7790,0x7793,0x7794,0x7795,0x7796,0x7797,0x7798,
125.1131 +    0x7799,0x779a,0x779b,0x779c,0x779d,0x779e,0x77a1,0x77a3,0x77a4,0x77a6,
125.1132 +    0x77a8,0x77ab,0x77ad,0x77ae,0x77af,0x77b1,0x77b2,0x77b4,0x77b6,0x77b7,
125.1133 +    0x77b8,0x77b9,0x77ba,UBOGON,0x77bc,0x77be,0x77c0,0x77c1,0x77c2,0x77c3,
125.1134 +    0x77c4,0x77c5,0x77c6,0x77c7,0x77c8,0x77c9,0x77ca,0x77cb,0x77cc,0x77ce,
125.1135 +    0x77cf,0x77d0,0x77d1,0x77d2,0x77d3,0x77d4,0x77d5,0x77d6,0x77d8,0x77d9,
125.1136 +    0x77da,0x77dd,0x77de,0x77df,0x77e0,0x77e1,0x77e4,0x75c5,0x5e76,0x73bb,
125.1137 +    0x83e0,0x64ad,0x62e8,0x94b5,0x6ce2,0x535a,0x52c3,0x640f,0x94c2,0x7b94,
125.1138 +    0x4f2f,0x5e1b,0x8236,0x8116,0x818a,0x6e24,0x6cca,0x9a73,0x6355,0x535c,
125.1139 +    0x54fa,0x8865,0x57e0,0x4e0d,0x5e03,0x6b65,0x7c3f,0x90e8,0x6016,0x64e6,
125.1140 +    0x731c,0x88c1,0x6750,0x624d,0x8d22,0x776c,0x8e29,0x91c7,0x5f69,0x83dc,
125.1141 +    0x8521,0x9910,0x53c2,0x8695,0x6b8b,0x60ed,0x60e8,0x707f,0x82cd,0x8231,
125.1142 +    0x4ed3,0x6ca7,0x85cf,0x64cd,0x7cd9,0x69fd,0x66f9,0x8349,0x5395,0x7b56,
125.1143 +    0x4fa7,0x518c,0x6d4b,0x5c42,0x8e6d,0x63d2,0x53c9,0x832c,0x8336,0x67e5,
125.1144 +    0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8be7,0x62c6,0x67f4,0x8c7a,0x6400,
125.1145 +    0x63ba,0x8749,0x998b,0x8c17,0x7f20,0x94f2,0x4ea7,0x9610,0x98a4,0x660c,
125.1146 +    0x7316
125.1147 +  },
125.1148 +  {				/* ku 33 */
125.1149 +    0x77e6,0x77e8,0x77ea,0x77ef,0x77f0,0x77f1,0x77f2,0x77f4,0x77f5,0x77f7,
125.1150 +    0x77f9,0x77fa,0x77fb,0x77fc,0x7803,0x7804,0x7805,0x7806,0x7807,0x7808,
125.1151 +    0x780a,0x780b,0x780e,0x780f,0x7810,0x7813,0x7815,0x7819,0x781b,0x781e,
125.1152 +    0x7820,0x7821,0x7822,0x7824,0x7828,0x782a,0x782b,0x782e,0x782f,0x7831,
125.1153 +    0x7832,0x7833,0x7835,0x7836,0x783d,0x783f,0x7841,0x7842,0x7843,0x7844,
125.1154 +    0x7846,0x7848,0x7849,0x784a,0x784b,0x784d,0x784f,0x7851,0x7853,0x7854,
125.1155 +    0x7858,0x7859,0x785a,UBOGON,0x785b,0x785c,0x785e,0x785f,0x7860,0x7861,
125.1156 +    0x7862,0x7863,0x7864,0x7865,0x7866,0x7867,0x7868,0x7869,0x786f,0x7870,
125.1157 +    0x7871,0x7872,0x7873,0x7874,0x7875,0x7876,0x7878,0x7879,0x787a,0x787b,
125.1158 +    0x787d,0x787e,0x787f,0x7880,0x7881,0x7882,0x7883,0x573a,0x5c1d,0x5e38,
125.1159 +    0x957f,0x507f,0x80a0,0x5382,0x655e,0x7545,0x5531,0x5021,0x8d85,0x6284,
125.1160 +    0x949e,0x671d,0x5632,0x6f6e,0x5de2,0x5435,0x7092,0x8f66,0x626f,0x64a4,
125.1161 +    0x63a3,0x5f7b,0x6f88,0x90f4,0x81e3,0x8fb0,0x5c18,0x6668,0x5ff1,0x6c89,
125.1162 +    0x9648,0x8d81,0x886c,0x6491,0x79f0,0x57ce,0x6a59,0x6210,0x5448,0x4e58,
125.1163 +    0x7a0b,0x60e9,0x6f84,0x8bda,0x627f,0x901e,0x9a8b,0x79e4,0x5403,0x75f4,
125.1164 +    0x6301,0x5319,0x6c60,0x8fdf,0x5f1b,0x9a70,0x803b,0x9f7f,0x4f88,0x5c3a,
125.1165 +    0x8d64,0x7fc5,0x65a5,0x70bd,0x5145,0x51b2,0x866b,0x5d07,0x5ba0,0x62bd,
125.1166 +    0x916c,0x7574,0x8e0c,0x7a20,0x6101,0x7b79,0x4ec7,0x7ef8,0x7785,0x4e11,
125.1167 +    0x81ed,0x521d,0x51fa,0x6a71,0x53a8,0x8e87,0x9504,0x96cf,0x6ec1,0x9664,
125.1168 +    0x695a
125.1169 +  },
125.1170 +  {				/* ku 34 */
125.1171 +    0x7884,0x7885,0x7886,0x7888,0x788a,0x788b,0x788f,0x7890,0x7892,0x7894,
125.1172 +    0x7895,0x7896,0x7899,0x789d,0x789e,0x78a0,0x78a2,0x78a4,0x78a6,0x78a8,
125.1173 +    0x78a9,0x78aa,0x78ab,0x78ac,0x78ad,0x78ae,0x78af,0x78b5,0x78b6,0x78b7,
125.1174 +    0x78b8,0x78ba,0x78bb,0x78bc,0x78bd,0x78bf,0x78c0,0x78c2,0x78c3,0x78c4,
125.1175 +    0x78c6,0x78c7,0x78c8,0x78cc,0x78cd,0x78ce,0x78cf,0x78d1,0x78d2,0x78d3,
125.1176 +    0x78d6,0x78d7,0x78d8,0x78da,0x78db,0x78dc,0x78dd,0x78de,0x78df,0x78e0,
125.1177 +    0x78e1,0x78e2,0x78e3,UBOGON,0x78e4,0x78e5,0x78e6,0x78e7,0x78e9,0x78ea,
125.1178 +    0x78eb,0x78ed,0x78ee,0x78ef,0x78f0,0x78f1,0x78f3,0x78f5,0x78f6,0x78f8,
125.1179 +    0x78f9,0x78fb,0x78fc,0x78fd,0x78fe,0x78ff,0x7900,0x7902,0x7903,0x7904,
125.1180 +    0x7906,0x7907,0x7908,0x7909,0x790a,0x790b,0x790c,0x7840,0x50a8,0x77d7,
125.1181 +    0x6410,0x89e6,0x5904,0x63e3,0x5ddd,0x7a7f,0x693d,0x4f20,0x8239,0x5598,
125.1182 +    0x4e32,0x75ae,0x7a97,0x5e62,0x5e8a,0x95ef,0x521b,0x5439,0x708a,0x6376,
125.1183 +    0x9524,0x5782,0x6625,0x693f,0x9187,0x5507,0x6df3,0x7eaf,0x8822,0x6233,
125.1184 +    0x7ef0,0x75b5,0x8328,0x78c1,0x96cc,0x8f9e,0x6148,0x74f7,0x8bcd,0x6b64,
125.1185 +    0x523a,0x8d50,0x6b21,0x806a,0x8471,0x56f1,0x5306,0x4ece,0x4e1b,0x51d1,
125.1186 +    0x7c97,0x918b,0x7c07,0x4fc3,0x8e7f,0x7be1,0x7a9c,0x6467,0x5d14,0x50ac,
125.1187 +    0x8106,0x7601,0x7cb9,0x6dec,0x7fe0,0x6751,0x5b58,0x5bf8,0x78cb,0x64ae,
125.1188 +    0x6413,0x63aa,0x632b,0x9519,0x642d,0x8fbe,0x7b54,0x7629,0x6253,0x5927,
125.1189 +    0x5446,0x6b79,0x50a3,0x6234,0x5e26,0x6b86,0x4ee3,0x8d37,0x888b,0x5f85,
125.1190 +    0x902e
125.1191 +  },
125.1192 +  {				/* ku 35 */
125.1193 +    0x790d,0x790e,0x790f,0x7910,0x7911,0x7912,0x7914,0x7915,0x7916,0x7917,
125.1194 +    0x7918,0x7919,0x791a,0x791b,0x791c,0x791d,0x791f,0x7920,0x7921,0x7922,
125.1195 +    0x7923,0x7925,0x7926,0x7927,0x7928,0x7929,0x792a,0x792b,0x792c,0x792d,
125.1196 +    0x792e,0x792f,0x7930,0x7931,0x7932,0x7933,0x7935,0x7936,0x7937,0x7938,
125.1197 +    0x7939,0x793d,0x793f,0x7942,0x7943,0x7944,0x7945,0x7947,0x794a,0x794b,
125.1198 +    0x794c,0x794d,0x794e,0x794f,0x7950,0x7951,0x7952,0x7954,0x7955,0x7958,
125.1199 +    0x7959,0x7961,0x7963,UBOGON,0x7964,0x7966,0x7969,0x796a,0x796b,0x796c,
125.1200 +    0x796e,0x7970,0x7971,0x7972,0x7973,0x7974,0x7975,0x7976,0x7979,0x797b,
125.1201 +    0x797c,0x797d,0x797e,0x797f,0x7982,0x7983,0x7986,0x7987,0x7988,0x7989,
125.1202 +    0x798b,0x798c,0x798d,0x798e,0x7990,0x7991,0x7992,0x6020,0x803d,0x62c5,
125.1203 +    0x4e39,0x5355,0x90f8,0x63b8,0x80c6,0x65e6,0x6c2e,0x4f46,0x60ee,0x6de1,
125.1204 +    0x8bde,0x5f39,0x86cb,0x5f53,0x6321,0x515a,0x8361,0x6863,0x5200,0x6363,
125.1205 +    0x8e48,0x5012,0x5c9b,0x7977,0x5bfc,0x5230,0x7a3b,0x60bc,0x9053,0x76d7,
125.1206 +    0x5fb7,0x5f97,0x7684,0x8e6c,0x706f,0x767b,0x7b49,0x77aa,0x51f3,0x9093,
125.1207 +    0x5824,0x4f4e,0x6ef4,0x8fea,0x654c,0x7b1b,0x72c4,0x6da4,0x7fdf,0x5ae1,
125.1208 +    0x62b5,0x5e95,0x5730,0x8482,0x7b2c,0x5e1d,0x5f1f,0x9012,0x7f14,0x98a0,
125.1209 +    0x6382,0x6ec7,0x7898,0x70b9,0x5178,0x975b,0x57ab,0x7535,0x4f43,0x7538,
125.1210 +    0x5e97,0x60e6,0x5960,0x6dc0,0x6bbf,0x7889,0x53fc,0x96d5,0x51cb,0x5201,
125.1211 +    0x6389,0x540a,0x9493,0x8c03,0x8dcc,0x7239,0x789f,0x8776,0x8fed,0x8c0d,
125.1212 +    0x53e0
125.1213 +  },
125.1214 +  {				/* ku 36 */
125.1215 +    0x7993,0x7994,0x7995,0x7996,0x7997,0x7998,0x7999,0x799b,0x799c,0x799d,
125.1216 +    0x799e,0x799f,0x79a0,0x79a1,0x79a2,0x79a3,0x79a4,0x79a5,0x79a6,0x79a8,
125.1217 +    0x79a9,0x79aa,0x79ab,0x79ac,0x79ad,0x79ae,0x79af,0x79b0,0x79b1,0x79b2,
125.1218 +    0x79b4,0x79b5,0x79b6,0x79b7,0x79b8,0x79bc,0x79bf,0x79c2,0x79c4,0x79c5,
125.1219 +    0x79c7,0x79c8,0x79ca,0x79cc,0x79ce,0x79cf,0x79d0,0x79d3,0x79d4,0x79d6,
125.1220 +    0x79d7,0x79d9,0x79da,0x79db,0x79dc,0x79dd,0x79de,0x79e0,0x79e1,0x79e2,
125.1221 +    0x79e5,0x79e8,0x79ea,UBOGON,0x79ec,0x79ee,0x79f1,0x79f2,0x79f3,0x79f4,
125.1222 +    0x79f5,0x79f6,0x79f7,0x79f9,0x79fa,0x79fc,0x79fe,0x79ff,0x7a01,0x7a04,
125.1223 +    0x7a05,0x7a07,0x7a08,0x7a09,0x7a0a,0x7a0c,0x7a0f,0x7a10,0x7a11,0x7a12,
125.1224 +    0x7a13,0x7a15,0x7a16,0x7a18,0x7a19,0x7a1b,0x7a1c,0x4e01,0x76ef,0x53ee,
125.1225 +    0x9489,0x9876,0x9f0e,0x952d,0x5b9a,0x8ba2,0x4e22,0x4e1c,0x51ac,0x8463,
125.1226 +    0x61c2,0x52a8,0x680b,0x4f97,0x606b,0x51bb,0x6d1e,0x515c,0x6296,0x6597,
125.1227 +    0x9661,0x8c46,0x9017,0x75d8,0x90fd,0x7763,0x6bd2,0x728a,0x72ec,0x8bfb,
125.1228 +    0x5835,0x7779,0x8d4c,0x675c,0x9540,0x809a,0x5ea6,0x6e21,0x5992,0x7aef,
125.1229 +    0x77ed,0x953b,0x6bb5,0x65ad,0x7f0e,0x5806,0x5151,0x961f,0x5bf9,0x58a9,
125.1230 +    0x5428,0x8e72,0x6566,0x987f,0x56e4,0x949d,0x76fe,0x9041,0x6387,0x54c6,
125.1231 +    0x591a,0x593a,0x579b,0x8eb2,0x6735,0x8dfa,0x8235,0x5241,0x60f0,0x5815,
125.1232 +    0x86fe,0x5ce8,0x9e45,0x4fc4,0x989d,0x8bb9,0x5a25,0x6076,0x5384,0x627c,
125.1233 +    0x904f,0x9102,0x997f,0x6069,0x800c,0x513f,0x8033,0x5c14,0x9975,0x6d31,
125.1234 +    0x4e8c
125.1235 +  },
125.1236 +  {				/* ku 37 */
125.1237 +    0x7a1d,0x7a1f,0x7a21,0x7a22,0x7a24,0x7a25,0x7a26,0x7a27,0x7a28,0x7a29,
125.1238 +    0x7a2a,0x7a2b,0x7a2c,0x7a2d,0x7a2e,0x7a2f,0x7a30,0x7a31,0x7a32,0x7a34,
125.1239 +    0x7a35,0x7a36,0x7a38,0x7a3a,0x7a3e,0x7a40,0x7a41,0x7a42,0x7a43,0x7a44,
125.1240 +    0x7a45,0x7a47,0x7a48,0x7a49,0x7a4a,0x7a4b,0x7a4c,0x7a4d,0x7a4e,0x7a4f,
125.1241 +    0x7a50,0x7a52,0x7a53,0x7a54,0x7a55,0x7a56,0x7a58,0x7a59,0x7a5a,0x7a5b,
125.1242 +    0x7a5c,0x7a5d,0x7a5e,0x7a5f,0x7a60,0x7a61,0x7a62,0x7a63,0x7a64,0x7a65,
125.1243 +    0x7a66,0x7a67,0x7a68,UBOGON,0x7a69,0x7a6a,0x7a6b,0x7a6c,0x7a6d,0x7a6e,
125.1244 +    0x7a6f,0x7a71,0x7a72,0x7a73,0x7a75,0x7a7b,0x7a7c,0x7a7d,0x7a7e,0x7a82,
125.1245 +    0x7a85,0x7a87,0x7a89,0x7a8a,0x7a8b,0x7a8c,0x7a8e,0x7a8f,0x7a90,0x7a93,
125.1246 +    0x7a94,0x7a99,0x7a9a,0x7a9b,0x7a9e,0x7aa1,0x7aa2,0x8d30,0x53d1,0x7f5a,
125.1247 +    0x7b4f,0x4f10,0x4e4f,0x9600,0x6cd5,0x73d0,0x85e9,0x5e06,0x756a,0x7ffb,
125.1248 +    0x6a0a,0x77fe,0x9492,0x7e41,0x51e1,0x70e6,0x53cd,0x8fd4,0x8303,0x8d29,
125.1249 +    0x72af,0x996d,0x6cdb,0x574a,0x82b3,0x65b9,0x80aa,0x623f,0x9632,0x59a8,
125.1250 +    0x4eff,0x8bbf,0x7eba,0x653e,0x83f2,0x975e,0x5561,0x98de,0x80a5,0x532a,
125.1251 +    0x8bfd,0x5420,0x80ba,0x5e9f,0x6cb8,0x8d39,0x82ac,0x915a,0x5429,0x6c1b,
125.1252 +    0x5206,0x7eb7,0x575f,0x711a,0x6c7e,0x7c89,0x594b,0x4efd,0x5fff,0x6124,
125.1253 +    0x7caa,0x4e30,0x5c01,0x67ab,0x8702,0x5cf0,0x950b,0x98ce,0x75af,0x70fd,
125.1254 +    0x9022,0x51af,0x7f1d,0x8bbd,0x5949,0x51e4,0x4f5b,0x5426,0x592b,0x6577,
125.1255 +    0x80a4,0x5b75,0x6276,0x62c2,0x8f90,0x5e45,0x6c1f,0x7b26,0x4f0f,0x4fd8,
125.1256 +    0x670d
125.1257 +  },
125.1258 +  {				/* ku 38 */
125.1259 +    0x7aa3,0x7aa4,0x7aa7,0x7aa9,0x7aaa,0x7aab,0x7aae,0x7aaf,0x7ab0,0x7ab1,
125.1260 +    0x7ab2,0x7ab4,0x7ab5,0x7ab6,0x7ab7,0x7ab8,0x7ab9,0x7aba,0x7abb,0x7abc,
125.1261 +    0x7abd,0x7abe,0x7ac0,0x7ac1,0x7ac2,0x7ac3,0x7ac4,0x7ac5,0x7ac6,0x7ac7,
125.1262 +    0x7ac8,0x7ac9,0x7aca,0x7acc,0x7acd,0x7ace,0x7acf,0x7ad0,0x7ad1,0x7ad2,
125.1263 +    0x7ad3,0x7ad4,0x7ad5,0x7ad7,0x7ad8,0x7ada,0x7adb,0x7adc,0x7add,0x7ae1,
125.1264 +    0x7ae2,0x7ae4,0x7ae7,0x7ae8,0x7ae9,0x7aea,0x7aeb,0x7aec,0x7aee,0x7af0,
125.1265 +    0x7af1,0x7af2,0x7af3,UBOGON,0x7af4,0x7af5,0x7af6,0x7af7,0x7af8,0x7afb,
125.1266 +    0x7afc,0x7afe,0x7b00,0x7b01,0x7b02,0x7b05,0x7b07,0x7b09,0x7b0c,0x7b0d,
125.1267 +    0x7b0e,0x7b10,0x7b12,0x7b13,0x7b16,0x7b17,0x7b18,0x7b1a,0x7b1c,0x7b1d,
125.1268 +    0x7b1f,0x7b21,0x7b22,0x7b23,0x7b27,0x7b29,0x7b2d,0x6d6e,0x6daa,0x798f,
125.1269 +    0x88b1,0x5f17,0x752b,0x629a,0x8f85,0x4fef,0x91dc,0x65a7,0x812f,0x8151,
125.1270 +    0x5e9c,0x8150,0x8d74,0x526f,0x8986,0x8d4b,0x590d,0x5085,0x4ed8,0x961c,
125.1271 +    0x7236,0x8179,0x8d1f,0x5bcc,0x8ba3,0x9644,0x5987,0x7f1a,0x5490,0x5676,
125.1272 +    0x560e,0x8be5,0x6539,0x6982,0x9499,0x76d6,0x6e89,0x5e72,0x7518,0x6746,
125.1273 +    0x67d1,0x7aff,0x809d,0x8d76,0x611f,0x79c6,0x6562,0x8d63,0x5188,0x521a,
125.1274 +    0x94a2,0x7f38,0x809b,0x7eb2,0x5c97,0x6e2f,0x6760,0x7bd9,0x768b,0x9ad8,
125.1275 +    0x818f,0x7f94,0x7cd5,0x641e,0x9550,0x7a3f,0x544a,0x54e5,0x6b4c,0x6401,
125.1276 +    0x6208,0x9e3d,0x80f3,0x7599,0x5272,0x9769,0x845b,0x683c,0x86e4,0x9601,
125.1277 +    0x9694,0x94ec,0x4e2a,0x5404,0x7ed9,0x6839,0x8ddf,0x8015,0x66f4,0x5e9a,
125.1278 +    0x7fb9
125.1279 +  },
125.1280 +  {				/* ku 39 */
125.1281 +    0x7b2f,0x7b30,0x7b32,0x7b34,0x7b35,0x7b36,0x7b37,0x7b39,0x7b3b,0x7b3d,
125.1282 +    0x7b3f,0x7b40,0x7b41,0x7b42,0x7b43,0x7b44,0x7b46,0x7b48,0x7b4a,0x7b4d,
125.1283 +    0x7b4e,0x7b53,0x7b55,0x7b57,0x7b59,0x7b5c,0x7b5e,0x7b5f,0x7b61,0x7b63,
125.1284 +    0x7b64,0x7b65,0x7b66,0x7b67,0x7b68,0x7b69,0x7b6a,0x7b6b,0x7b6c,0x7b6d,
125.1285 +    0x7b6f,0x7b70,0x7b73,0x7b74,0x7b76,0x7b78,0x7b7a,0x7b7c,0x7b7d,0x7b7f,
125.1286 +    0x7b81,0x7b82,0x7b83,0x7b84,0x7b86,0x7b87,0x7b88,0x7b89,0x7b8a,0x7b8b,
125.1287 +    0x7b8c,0x7b8e,0x7b8f,UBOGON,0x7b91,0x7b92,0x7b93,0x7b96,0x7b98,0x7b99,
125.1288 +    0x7b9a,0x7b9b,0x7b9e,0x7b9f,0x7ba0,0x7ba3,0x7ba4,0x7ba5,0x7bae,0x7baf,
125.1289 +    0x7bb0,0x7bb2,0x7bb3,0x7bb5,0x7bb6,0x7bb7,0x7bb9,0x7bba,0x7bbb,0x7bbc,
125.1290 +    0x7bbd,0x7bbe,0x7bbf,0x7bc0,0x7bc2,0x7bc3,0x7bc4,0x57c2,0x803f,0x6897,
125.1291 +    0x5de5,0x653b,0x529f,0x606d,0x9f9a,0x4f9b,0x8eac,0x516c,0x5bab,0x5f13,
125.1292 +    0x5de9,0x6c5e,0x62f1,0x8d21,0x5171,0x94a9,0x52fe,0x6c9f,0x82df,0x72d7,
125.1293 +    0x57a2,0x6784,0x8d2d,0x591f,0x8f9c,0x83c7,0x5495,0x7b8d,0x4f30,0x6cbd,
125.1294 +    0x5b64,0x59d1,0x9f13,0x53e4,0x86ca,0x9aa8,0x8c37,0x80a1,0x6545,0x987e,
125.1295 +    0x56fa,0x96c7,0x522e,0x74dc,0x5250,0x5be1,0x6302,0x8902,0x4e56,0x62d0,
125.1296 +    0x602a,0x68fa,0x5173,0x5b98,0x51a0,0x89c2,0x7ba1,0x9986,0x7f50,0x60ef,
125.1297 +    0x704c,0x8d2f,0x5149,0x5e7f,0x901b,0x7470,0x89c4,0x572d,0x7845,0x5f52,
125.1298 +    0x9f9f,0x95fa,0x8f68,0x9b3c,0x8be1,0x7678,0x6842,0x67dc,0x8dea,0x8d35,
125.1299 +    0x523d,0x8f8a,0x6eda,0x68cd,0x9505,0x90ed,0x56fd,0x679c,0x88f9,0x8fc7,
125.1300 +    0x54c8
125.1301 +  },
125.1302 +  {				/* ku 3a */
125.1303 +    0x7bc5,0x7bc8,0x7bc9,0x7bca,0x7bcb,0x7bcd,0x7bce,0x7bcf,0x7bd0,0x7bd2,
125.1304 +    0x7bd4,0x7bd5,0x7bd6,0x7bd7,0x7bd8,0x7bdb,0x7bdc,0x7bde,0x7bdf,0x7be0,
125.1305 +    0x7be2,0x7be3,0x7be4,0x7be7,0x7be8,0x7be9,0x7beb,0x7bec,0x7bed,0x7bef,
125.1306 +    0x7bf0,0x7bf2,0x7bf3,0x7bf4,0x7bf5,0x7bf6,0x7bf8,0x7bf9,0x7bfa,0x7bfb,
125.1307 +    0x7bfd,0x7bff,0x7c00,0x7c01,0x7c02,0x7c03,0x7c04,0x7c05,0x7c06,0x7c08,
125.1308 +    0x7c09,0x7c0a,0x7c0d,0x7c0e,0x7c10,0x7c11,0x7c12,0x7c13,0x7c14,0x7c15,
125.1309 +    0x7c17,0x7c18,0x7c19,UBOGON,0x7c1a,0x7c1b,0x7c1c,0x7c1d,0x7c1e,0x7c20,
125.1310 +    0x7c21,0x7c22,0x7c23,0x7c24,0x7c25,0x7c28,0x7c29,0x7c2b,0x7c2c,0x7c2d,
125.1311 +    0x7c2e,0x7c2f,0x7c30,0x7c31,0x7c32,0x7c33,0x7c34,0x7c35,0x7c36,0x7c37,
125.1312 +    0x7c39,0x7c3a,0x7c3b,0x7c3c,0x7c3d,0x7c3e,0x7c42,0x9ab8,0x5b69,0x6d77,
125.1313 +    0x6c26,0x4ea5,0x5bb3,0x9a87,0x9163,0x61a8,0x90af,0x97e9,0x542b,0x6db5,
125.1314 +    0x5bd2,0x51fd,0x558a,0x7f55,0x7ff0,0x64bc,0x634d,0x65f1,0x61be,0x608d,
125.1315 +    0x710a,0x6c57,0x6c49,0x592f,0x676d,0x822a,0x58d5,0x568e,0x8c6a,0x6beb,
125.1316 +    0x90dd,0x597d,0x8017,0x53f7,0x6d69,0x5475,0x559d,0x8377,0x83cf,0x6838,
125.1317 +    0x79be,0x548c,0x4f55,0x5408,0x76d2,0x8c89,0x9602,0x6cb3,0x6db8,0x8d6b,
125.1318 +    0x8910,0x9e64,0x8d3a,0x563f,0x9ed1,0x75d5,0x5f88,0x72e0,0x6068,0x54fc,
125.1319 +    0x4ea8,0x6a2a,0x8861,0x6052,0x8f70,0x54c4,0x70d8,0x8679,0x9e3f,0x6d2a,
125.1320 +    0x5b8f,0x5f18,0x7ea2,0x5589,0x4faf,0x7334,0x543c,0x539a,0x5019,0x540e,
125.1321 +    0x547c,0x4e4e,0x5ffd,0x745a,0x58f6,0x846b,0x80e1,0x8774,0x72d0,0x7cca,
125.1322 +    0x6e56
125.1323 +  },
125.1324 +  {				/* ku 3b */
125.1325 +    0x7c43,0x7c44,0x7c45,0x7c46,0x7c47,0x7c48,0x7c49,0x7c4a,0x7c4b,0x7c4c,
125.1326 +    0x7c4e,0x7c4f,0x7c50,0x7c51,0x7c52,0x7c53,0x7c54,0x7c55,0x7c56,0x7c57,
125.1327 +    0x7c58,0x7c59,0x7c5a,0x7c5b,0x7c5c,0x7c5d,0x7c5e,0x7c5f,0x7c60,0x7c61,
125.1328 +    0x7c62,0x7c63,0x7c64,0x7c65,0x7c66,0x7c67,0x7c68,0x7c69,0x7c6a,0x7c6b,
125.1329 +    0x7c6c,0x7c6d,0x7c6e,0x7c6f,0x7c70,0x7c71,0x7c72,0x7c75,0x7c76,0x7c77,
125.1330 +    0x7c78,0x7c79,0x7c7a,0x7c7e,0x7c7f,0x7c80,0x7c81,0x7c82,0x7c83,0x7c84,
125.1331 +    0x7c85,0x7c86,0x7c87,UBOGON,0x7c88,0x7c8a,0x7c8b,0x7c8c,0x7c8d,0x7c8e,
125.1332 +    0x7c8f,0x7c90,0x7c93,0x7c94,0x7c96,0x7c99,0x7c9a,0x7c9b,0x7ca0,0x7ca1,
125.1333 +    0x7ca3,0x7ca6,0x7ca7,0x7ca8,0x7ca9,0x7cab,0x7cac,0x7cad,0x7caf,0x7cb0,
125.1334 +    0x7cb4,0x7cb5,0x7cb6,0x7cb7,0x7cb8,0x7cba,0x7cbb,0x5f27,0x864e,0x552c,
125.1335 +    0x62a4,0x4e92,0x6caa,0x6237,0x82b1,0x54d7,0x534e,0x733e,0x6ed1,0x753b,
125.1336 +    0x5212,0x5316,0x8bdd,0x69d0,0x5f8a,0x6000,0x6dee,0x574f,0x6b22,0x73af,
125.1337 +    0x6853,0x8fd8,0x7f13,0x6362,0x60a3,0x5524,0x75ea,0x8c62,0x7115,0x6da3,
125.1338 +    0x5ba6,0x5e7b,0x8352,0x614c,0x9ec4,0x78fa,0x8757,0x7c27,0x7687,0x51f0,
125.1339 +    0x60f6,0x714c,0x6643,0x5e4c,0x604d,0x8c0e,0x7070,0x6325,0x8f89,0x5fbd,
125.1340 +    0x6062,0x86d4,0x56de,0x6bc1,0x6094,0x6167,0x5349,0x60e0,0x6666,0x8d3f,
125.1341 +    0x79fd,0x4f1a,0x70e9,0x6c47,0x8bb3,0x8bf2,0x7ed8,0x8364,0x660f,0x5a5a,
125.1342 +    0x9b42,0x6d51,0x6df7,0x8c41,0x6d3b,0x4f19,0x706b,0x83b7,0x6216,0x60d1,
125.1343 +    0x970d,0x8d27,0x7978,0x51fb,0x573e,0x57fa,0x673a,0x7578,0x7a3d,0x79ef,
125.1344 +    0x7b95
125.1345 +  },
125.1346 +  {				/* ku 3c */
125.1347 +    0x7cbf,0x7cc0,0x7cc2,0x7cc3,0x7cc4,0x7cc6,0x7cc9,0x7ccb,0x7cce,0x7ccf,
125.1348 +    0x7cd0,0x7cd1,0x7cd2,0x7cd3,0x7cd4,0x7cd8,0x7cda,0x7cdb,0x7cdd,0x7cde,
125.1349 +    0x7ce1,0x7ce2,0x7ce3,0x7ce4,0x7ce5,0x7ce6,0x7ce7,0x7ce9,0x7cea,0x7ceb,
125.1350 +    0x7cec,0x7ced,0x7cee,0x7cf0,0x7cf1,0x7cf2,0x7cf3,0x7cf4,0x7cf5,0x7cf6,
125.1351 +    0x7cf7,0x7cf9,0x7cfa,0x7cfc,0x7cfd,0x7cfe,0x7cff,0x7d00,0x7d01,0x7d02,
125.1352 +    0x7d03,0x7d04,0x7d05,0x7d06,0x7d07,0x7d08,0x7d09,0x7d0b,0x7d0c,0x7d0d,
125.1353 +    0x7d0e,0x7d0f,0x7d10,UBOGON,0x7d11,0x7d12,0x7d13,0x7d14,0x7d15,0x7d16,
125.1354 +    0x7d17,0x7d18,0x7d19,0x7d1a,0x7d1b,0x7d1c,0x7d1d,0x7d1e,0x7d1f,0x7d21,
125.1355 +    0x7d23,0x7d24,0x7d25,0x7d26,0x7d28,0x7d29,0x7d2a,0x7d2c,0x7d2d,0x7d2e,
125.1356 +    0x7d30,0x7d31,0x7d32,0x7d33,0x7d34,0x7d35,0x7d36,0x808c,0x9965,0x8ff9,
125.1357 +    0x6fc0,0x8ba5,0x9e21,0x59ec,0x7ee9,0x7f09,0x5409,0x6781,0x68d8,0x8f91,
125.1358 +    0x7c4d,0x96c6,0x53ca,0x6025,0x75be,0x6c72,0x5373,0x5ac9,0x7ea7,0x6324,
125.1359 +    0x51e0,0x810a,0x5df1,0x84df,0x6280,0x5180,0x5b63,0x4f0e,0x796d,0x5242,
125.1360 +    0x60b8,0x6d4e,0x5bc4,0x5bc2,0x8ba1,0x8bb0,0x65e2,0x5fcc,0x9645,0x5993,
125.1361 +    0x7ee7,0x7eaa,0x5609,0x67b7,0x5939,0x4f73,0x5bb6,0x52a0,0x835a,0x988a,
125.1362 +    0x8d3e,0x7532,0x94be,0x5047,0x7a3c,0x4ef7,0x67b6,0x9a7e,0x5ac1,0x6b7c,
125.1363 +    0x76d1,0x575a,0x5c16,0x7b3a,0x95f4,0x714e,0x517c,0x80a9,0x8270,0x5978,
125.1364 +    0x7f04,0x8327,0x68c0,0x67ec,0x78b1,0x7877,0x62e3,0x6361,0x7b80,0x4fed,
125.1365 +    0x526a,0x51cf,0x8350,0x69db,0x9274,0x8df5,0x8d31,0x89c1,0x952e,0x7bad,
125.1366 +    0x4ef6
125.1367 +  },
125.1368 +  {				/* ku 3d */
125.1369 +    0x7d37,0x7d38,0x7d39,0x7d3a,0x7d3b,0x7d3c,0x7d3d,0x7d3e,0x7d3f,0x7d40,
125.1370 +    0x7d41,0x7d42,0x7d43,0x7d44,0x7d45,0x7d46,0x7d47,0x7d48,0x7d49,0x7d4a,
125.1371 +    0x7d4b,0x7d4c,0x7d4d,0x7d4e,0x7d4f,0x7d50,0x7d51,0x7d52,0x7d53,0x7d54,
125.1372 +    0x7d55,0x7d56,0x7d57,0x7d58,0x7d59,0x7d5a,0x7d5b,0x7d5c,0x7d5d,0x7d5e,
125.1373 +    0x7d5f,0x7d60,0x7d61,0x7d62,0x7d63,0x7d64,0x7d65,0x7d66,0x7d67,0x7d68,
125.1374 +    0x7d69,0x7d6a,0x7d6b,0x7d6c,0x7d6d,0x7d6f,0x7d70,0x7d71,0x7d72,0x7d73,
125.1375 +    0x7d74,0x7d75,0x7d76,UBOGON,0x7d78,0x7d79,0x7d7a,0x7d7b,0x7d7c,0x7d7d,
125.1376 +    0x7d7e,0x7d7f,0x7d80,0x7d81,0x7d82,0x7d83,0x7d84,0x7d85,0x7d86,0x7d87,
125.1377 +    0x7d88,0x7d89,0x7d8a,0x7d8b,0x7d8c,0x7d8d,0x7d8e,0x7d8f,0x7d90,0x7d91,
125.1378 +    0x7d92,0x7d93,0x7d94,0x7d95,0x7d96,0x7d97,0x7d98,0x5065,0x8230,0x5251,
125.1379 +    0x996f,0x6e10,0x6e85,0x6da7,0x5efa,0x50f5,0x59dc,0x5c06,0x6d46,0x6c5f,
125.1380 +    0x7586,0x848b,0x6868,0x5956,0x8bb2,0x5320,0x9171,0x964d,0x8549,0x6912,
125.1381 +    0x7901,0x7126,0x80f6,0x4ea4,0x90ca,0x6d47,0x9a84,0x5a07,0x56bc,0x6405,
125.1382 +    0x94f0,0x77eb,0x4fa5,0x811a,0x72e1,0x89d2,0x997a,0x7f34,0x7ede,0x527f,
125.1383 +    0x6559,0x9175,0x8f7f,0x8f83,0x53eb,0x7a96,0x63ed,0x63a5,0x7686,0x79f8,
125.1384 +    0x8857,0x9636,0x622a,0x52ab,0x8282,0x6854,0x6770,0x6377,0x776b,0x7aed,
125.1385 +    0x6d01,0x7ed3,0x89e3,0x59d0,0x6212,0x85c9,0x82a5,0x754c,0x501f,0x4ecb,
125.1386 +    0x75a5,0x8beb,0x5c4a,0x5dfe,0x7b4b,0x65a4,0x91d1,0x4eca,0x6d25,0x895f,
125.1387 +    0x7d27,0x9526,0x4ec5,0x8c28,0x8fdb,0x9773,0x664b,0x7981,0x8fd1,0x70ec,
125.1388 +    0x6d78
125.1389 +  },
125.1390 +  {				/* ku 3e */
125.1391 +    0x7d99,0x7d9a,0x7d9b,0x7d9c,0x7d9d,0x7d9e,0x7d9f,0x7da0,0x7da1,0x7da2,
125.1392 +    0x7da3,0x7da4,0x7da5,0x7da7,0x7da8,0x7da9,0x7daa,0x7dab,0x7dac,0x7dad,
125.1393 +    0x7daf,0x7db0,0x7db1,0x7db2,0x7db3,0x7db4,0x7db5,0x7db6,0x7db7,0x7db8,
125.1394 +    0x7db9,0x7dba,0x7dbb,0x7dbc,0x7dbd,0x7dbe,0x7dbf,0x7dc0,0x7dc1,0x7dc2,
125.1395 +    0x7dc3,0x7dc4,0x7dc5,0x7dc6,0x7dc7,0x7dc8,0x7dc9,0x7dca,0x7dcb,0x7dcc,
125.1396 +    0x7dcd,0x7dce,0x7dcf,0x7dd0,0x7dd1,0x7dd2,0x7dd3,0x7dd4,0x7dd5,0x7dd6,
125.1397 +    0x7dd7,0x7dd8,0x7dd9,UBOGON,0x7dda,0x7ddb,0x7ddc,0x7ddd,0x7dde,0x7ddf,
125.1398 +    0x7de0,0x7de1,0x7de2,0x7de3,0x7de4,0x7de5,0x7de6,0x7de7,0x7de8,0x7de9,
125.1399 +    0x7dea,0x7deb,0x7dec,0x7ded,0x7dee,0x7def,0x7df0,0x7df1,0x7df2,0x7df3,
125.1400 +    0x7df4,0x7df5,0x7df6,0x7df7,0x7df8,0x7df9,0x7dfa,0x5c3d,0x52b2,0x8346,
125.1401 +    0x5162,0x830e,0x775b,0x6676,0x9cb8,0x4eac,0x60ca,0x7cbe,0x7cb3,0x7ecf,
125.1402 +    0x4e95,0x8b66,0x666f,0x9888,0x9759,0x5883,0x656c,0x955c,0x5f84,0x75c9,
125.1403 +    0x9756,0x7adf,0x7ade,0x51c0,0x70af,0x7a98,0x63ea,0x7a76,0x7ea0,0x7396,
125.1404 +    0x97ed,0x4e45,0x7078,0x4e5d,0x9152,0x53a9,0x6551,0x65e7,0x81fc,0x8205,
125.1405 +    0x548e,0x5c31,0x759a,0x97a0,0x62d8,0x72d9,0x75bd,0x5c45,0x9a79,0x83ca,
125.1406 +    0x5c40,0x5480,0x77e9,0x4e3e,0x6cae,0x805a,0x62d2,0x636e,0x5de8,0x5177,
125.1407 +    0x8ddd,0x8e1e,0x952f,0x4ff1,0x53e5,0x60e7,0x70ac,0x5267,0x6350,0x9e43,
125.1408 +    0x5a1f,0x5026,0x7737,0x5377,0x7ee2,0x6485,0x652b,0x6289,0x6398,0x5014,
125.1409 +    0x7235,0x89c9,0x51b3,0x8bc0,0x7edd,0x5747,0x83cc,0x94a7,0x519b,0x541b,
125.1410 +    0x5cfb
125.1411 +  },
125.1412 +  {				/* ku 3f */
125.1413 +    0x7dfb,0x7dfc,0x7dfd,0x7dfe,0x7dff,0x7e00,0x7e01,0x7e02,0x7e03,0x7e04,
125.1414 +    0x7e05,0x7e06,0x7e07,0x7e08,0x7e09,0x7e0a,0x7e0b,0x7e0c,0x7e0d,0x7e0e,
125.1415 +    0x7e0f,0x7e10,0x7e11,0x7e12,0x7e13,0x7e14,0x7e15,0x7e16,0x7e17,0x7e18,
125.1416 +    0x7e19,0x7e1a,0x7e1b,0x7e1c,0x7e1d,0x7e1e,0x7e1f,0x7e20,0x7e21,0x7e22,
125.1417 +    0x7e23,0x7e24,0x7e25,0x7e26,0x7e27,0x7e28,0x7e29,0x7e2a,0x7e2b,0x7e2c,
125.1418 +    0x7e2d,0x7e2e,0x7e2f,0x7e30,0x7e31,0x7e32,0x7e33,0x7e34,0x7e35,0x7e36,
125.1419 +    0x7e37,0x7e38,0x7e39,UBOGON,0x7e3a,0x7e3c,0x7e3d,0x7e3e,0x7e3f,0x7e40,
125.1420 +    0x7e42,0x7e43,0x7e44,0x7e45,0x7e46,0x7e48,0x7e49,0x7e4a,0x7e4b,0x7e4c,
125.1421 +    0x7e4d,0x7e4e,0x7e4f,0x7e50,0x7e51,0x7e52,0x7e53,0x7e54,0x7e55,0x7e56,
125.1422 +    0x7e57,0x7e58,0x7e59,0x7e5a,0x7e5b,0x7e5c,0x7e5d,0x4fca,0x7ae3,0x6d5a,
125.1423 +    0x90e1,0x9a8f,0x5580,0x5496,0x5361,0x54af,0x5f00,0x63e9,0x6977,0x51ef,
125.1424 +    0x6168,0x520a,0x582a,0x52d8,0x574e,0x780d,0x770b,0x5eb7,0x6177,0x7ce0,
125.1425 +    0x625b,0x6297,0x4ea2,0x7095,0x8003,0x62f7,0x70e4,0x9760,0x5777,0x82db,
125.1426 +    0x67ef,0x68f5,0x78d5,0x9897,0x79d1,0x58f3,0x54b3,0x53ef,0x6e34,0x514b,
125.1427 +    0x523b,0x5ba2,0x8bfe,0x80af,0x5543,0x57a6,0x6073,0x5751,0x542d,0x7a7a,
125.1428 +    0x6050,0x5b54,0x63a7,0x62a0,0x53e3,0x6263,0x5bc7,0x67af,0x54ed,0x7a9f,
125.1429 +    0x82e6,0x9177,0x5e93,0x88e4,0x5938,0x57ae,0x630e,0x8de8,0x80ef,0x5757,
125.1430 +    0x7b77,0x4fa9,0x5feb,0x5bbd,0x6b3e,0x5321,0x7b50,0x72c2,0x6846,0x77ff,
125.1431 +    0x7736,0x65f7,0x51b5,0x4e8f,0x76d4,0x5cbf,0x7aa5,0x8475,0x594e,0x9b41,
125.1432 +    0x5080
125.1433 +  },
125.1434 +  {				/* ku 40 */
125.1435 +    0x7e5e,0x7e5f,0x7e60,0x7e61,0x7e62,0x7e63,0x7e64,0x7e65,0x7e66,0x7e67,
125.1436 +    0x7e68,0x7e69,0x7e6a,0x7e6b,0x7e6c,0x7e6d,0x7e6e,0x7e6f,0x7e70,0x7e71,
125.1437 +    0x7e72,0x7e73,0x7e74,0x7e75,0x7e76,0x7e77,0x7e78,0x7e79,0x7e7a,0x7e7b,
125.1438 +    0x7e7c,0x7e7d,0x7e7e,0x7e7f,0x7e80,0x7e81,0x7e83,0x7e84,0x7e85,0x7e86,
125.1439 +    0x7e87,0x7e88,0x7e89,0x7e8a,0x7e8b,0x7e8c,0x7e8d,0x7e8e,0x7e8f,0x7e90,
125.1440 +    0x7e91,0x7e92,0x7e93,0x7e94,0x7e95,0x7e96,0x7e97,0x7e98,0x7e99,0x7e9a,
125.1441 +    0x7e9c,0x7e9d,0x7e9e,UBOGON,0x7eae,0x7eb4,0x7ebb,0x7ebc,0x7ed6,0x7ee4,
125.1442 +    0x7eec,0x7ef9,0x7f0a,0x7f10,0x7f1e,0x7f37,0x7f39,0x7f3b,0x7f3c,0x7f3d,
125.1443 +    0x7f3e,0x7f3f,0x7f40,0x7f41,0x7f43,0x7f46,0x7f47,0x7f48,0x7f49,0x7f4a,
125.1444 +    0x7f4b,0x7f4c,0x7f4d,0x7f4e,0x7f4f,0x7f52,0x7f53,0x9988,0x6127,0x6e83,
125.1445 +    0x5764,0x6606,0x6346,0x56f0,0x62ec,0x6269,0x5ed3,0x9614,0x5783,0x62c9,
125.1446 +    0x5587,0x8721,0x814a,0x8fa3,0x5566,0x83b1,0x6765,0x8d56,0x84dd,0x5a6a,
125.1447 +    0x680f,0x62e6,0x7bee,0x9611,0x5170,0x6f9c,0x8c30,0x63fd,0x89c8,0x61d2,
125.1448 +    0x7f06,0x70c2,0x6ee5,0x7405,0x6994,0x72fc,0x5eca,0x90ce,0x6717,0x6d6a,
125.1449 +    0x635e,0x52b3,0x7262,0x8001,0x4f6c,0x59e5,0x916a,0x70d9,0x6d9d,0x52d2,
125.1450 +    0x4e50,0x96f7,0x956d,0x857e,0x78ca,0x7d2f,0x5121,0x5792,0x64c2,0x808b,
125.1451 +    0x7c7b,0x6cea,0x68f1,0x695e,0x51b7,0x5398,0x68a8,0x7281,0x9ece,0x7bf1,
125.1452 +    0x72f8,0x79bb,0x6f13,0x7406,0x674e,0x91cc,0x9ca4,0x793c,0x8389,0x8354,
125.1453 +    0x540f,0x6817,0x4e3d,0x5389,0x52b1,0x783e,0x5386,0x5229,0x5088,0x4f8b,
125.1454 +    0x4fd0
125.1455 +  },
125.1456 +  {				/* ku 41 */
125.1457 +    0x7f56,0x7f59,0x7f5b,0x7f5c,0x7f5d,0x7f5e,0x7f60,0x7f63,0x7f64,0x7f65,
125.1458 +    0x7f66,0x7f67,0x7f6b,0x7f6c,0x7f6d,0x7f6f,0x7f70,0x7f73,0x7f75,0x7f76,
125.1459 +    0x7f77,0x7f78,0x7f7a,0x7f7b,0x7f7c,0x7f7d,0x7f7f,0x7f80,0x7f82,0x7f83,
125.1460 +    0x7f84,0x7f85,0x7f86,0x7f87,0x7f88,0x7f89,0x7f8b,0x7f8d,0x7f8f,0x7f90,
125.1461 +    0x7f91,0x7f92,0x7f93,0x7f95,0x7f96,0x7f97,0x7f98,0x7f99,0x7f9b,0x7f9c,
125.1462 +    0x7fa0,0x7fa2,0x7fa3,0x7fa5,0x7fa6,0x7fa8,0x7fa9,0x7faa,0x7fab,0x7fac,
125.1463 +    0x7fad,0x7fae,0x7fb1,UBOGON,0x7fb3,0x7fb4,0x7fb5,0x7fb6,0x7fb7,0x7fba,
125.1464 +    0x7fbb,0x7fbe,0x7fc0,0x7fc2,0x7fc3,0x7fc4,0x7fc6,0x7fc7,0x7fc8,0x7fc9,
125.1465 +    0x7fcb,0x7fcd,0x7fcf,0x7fd0,0x7fd1,0x7fd2,0x7fd3,0x7fd6,0x7fd7,0x7fd9,
125.1466 +    0x7fda,0x7fdb,0x7fdc,0x7fdd,0x7fde,0x7fe2,0x7fe3,0x75e2,0x7acb,0x7c92,
125.1467 +    0x6ca5,0x96b6,0x529b,0x7483,0x54e9,0x4fe9,0x8054,0x83b2,0x8fde,0x9570,
125.1468 +    0x5ec9,0x601c,0x6d9f,0x5e18,0x655b,0x8138,0x94fe,0x604b,0x70bc,0x7ec3,
125.1469 +    0x7cae,0x51c9,0x6881,0x7cb1,0x826f,0x4e24,0x8f86,0x91cf,0x667e,0x4eae,
125.1470 +    0x8c05,0x64a9,0x804a,0x50da,0x7597,0x71ce,0x5be5,0x8fbd,0x6f66,0x4e86,
125.1471 +    0x6482,0x9563,0x5ed6,0x6599,0x5217,0x88c2,0x70c8,0x52a3,0x730e,0x7433,
125.1472 +    0x6797,0x78f7,0x9716,0x4e34,0x90bb,0x9cde,0x6dcb,0x51db,0x8d41,0x541d,
125.1473 +    0x62ce,0x73b2,0x83f1,0x96f6,0x9f84,0x94c3,0x4f36,0x7f9a,0x51cc,0x7075,
125.1474 +    0x9675,0x5cad,0x9886,0x53e6,0x4ee4,0x6e9c,0x7409,0x69b4,0x786b,0x998f,
125.1475 +    0x7559,0x5218,0x7624,0x6d41,0x67f3,0x516d,0x9f99,0x804b,0x5499,0x7b3c,
125.1476 +    0x7abf
125.1477 +  },
125.1478 +  {				/* ku 42 */
125.1479 +    0x7fe4,0x7fe7,0x7fe8,0x7fea,0x7feb,0x7fec,0x7fed,0x7fef,0x7ff2,0x7ff4,
125.1480 +    0x7ff5,0x7ff6,0x7ff7,0x7ff8,0x7ff9,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8002,
125.1481 +    0x8007,0x8008,0x8009,0x800a,0x800e,0x800f,0x8011,0x8013,0x801a,0x801b,
125.1482 +    0x801d,0x801e,0x801f,0x8021,0x8023,0x8024,0x802b,0x802c,0x802d,0x802e,
125.1483 +    0x802f,0x8030,0x8032,0x8034,0x8039,0x803a,0x803c,0x803e,0x8040,0x8041,
125.1484 +    0x8044,0x8045,0x8047,0x8048,0x8049,0x804e,0x804f,0x8050,0x8051,0x8053,
125.1485 +    0x8055,0x8056,0x8057,UBOGON,0x8059,0x805b,0x805c,0x805d,0x805e,0x805f,
125.1486 +    0x8060,0x8061,0x8062,0x8063,0x8064,0x8065,0x8066,0x8067,0x8068,0x806b,
125.1487 +    0x806c,0x806d,0x806e,0x806f,0x8070,0x8072,0x8073,0x8074,0x8075,0x8076,
125.1488 +    0x8077,0x8078,0x8079,0x807a,0x807b,0x807c,0x807d,0x9686,0x5784,0x62e2,
125.1489 +    0x9647,0x697c,0x5a04,0x6402,0x7bd3,0x6f0f,0x964b,0x82a6,0x5362,0x9885,
125.1490 +    0x5e90,0x7089,0x63b3,0x5364,0x864f,0x9c81,0x9e93,0x788c,0x9732,0x8def,
125.1491 +    0x8d42,0x9e7f,0x6f5e,0x7984,0x5f55,0x9646,0x622e,0x9a74,0x5415,0x94dd,
125.1492 +    0x4fa3,0x65c5,0x5c65,0x5c61,0x7f15,0x8651,0x6c2f,0x5f8b,0x7387,0x6ee4,
125.1493 +    0x7eff,0x5ce6,0x631b,0x5b6a,0x6ee6,0x5375,0x4e71,0x63a0,0x7565,0x62a1,
125.1494 +    0x8f6e,0x4f26,0x4ed1,0x6ca6,0x7eb6,0x8bba,0x841d,0x87ba,0x7f57,0x903b,
125.1495 +    0x9523,0x7ba9,0x9aa1,0x88f8,0x843d,0x6d1b,0x9a86,0x7edc,0x5988,0x9ebb,
125.1496 +    0x739b,0x7801,0x8682,0x9a6c,0x9a82,0x561b,0x5417,0x57cb,0x4e70,0x9ea6,
125.1497 +    0x5356,0x8fc8,0x8109,0x7792,0x9992,0x86ee,0x6ee1,0x8513,0x66fc,0x6162,
125.1498 +    0x6f2b
125.1499 +  },
125.1500 +  {				/* ku 43 */
125.1501 +    0x807e,0x8081,0x8082,0x8085,0x8088,0x808a,0x808d,0x808e,0x808f,0x8090,
125.1502 +    0x8091,0x8092,0x8094,0x8095,0x8097,0x8099,0x809e,0x80a3,0x80a6,0x80a7,
125.1503 +    0x80a8,0x80ac,0x80b0,0x80b3,0x80b5,0x80b6,0x80b8,0x80b9,0x80bb,0x80c5,
125.1504 +    0x80c7,0x80c8,0x80c9,0x80ca,0x80cb,0x80cf,0x80d0,0x80d1,0x80d2,0x80d3,
125.1505 +    0x80d4,0x80d5,0x80d8,0x80df,0x80e0,0x80e2,0x80e3,0x80e6,0x80ee,0x80f5,
125.1506 +    0x80f7,0x80f9,0x80fb,0x80fe,0x80ff,0x8100,0x8101,0x8103,0x8104,0x8105,
125.1507 +    0x8107,0x8108,0x810b,UBOGON,0x810c,0x8115,0x8117,0x8119,0x811b,0x811c,
125.1508 +    0x811d,0x811f,0x8120,0x8121,0x8122,0x8123,0x8124,0x8125,0x8126,0x8127,
125.1509 +    0x8128,0x8129,0x812a,0x812b,0x812d,0x812e,0x8130,0x8133,0x8134,0x8135,
125.1510 +    0x8137,0x8139,0x813a,0x813b,0x813c,0x813d,0x813f,0x8c29,0x8292,0x832b,
125.1511 +    0x76f2,0x6c13,0x5fd9,0x83bd,0x732b,0x8305,0x951a,0x6bdb,0x77db,0x94c6,
125.1512 +    0x536f,0x8302,0x5192,0x5e3d,0x8c8c,0x8d38,0x4e48,0x73ab,0x679a,0x6885,
125.1513 +    0x9176,0x9709,0x7164,0x6ca1,0x7709,0x5a92,0x9541,0x6bcf,0x7f8e,0x6627,
125.1514 +    0x5bd0,0x59b9,0x5a9a,0x95e8,0x95f7,0x4eec,0x840c,0x8499,0x6aac,0x76df,
125.1515 +    0x9530,0x731b,0x68a6,0x5b5f,0x772f,0x919a,0x9761,0x7cdc,0x8ff7,0x8c1c,
125.1516 +    0x5f25,0x7c73,0x79d8,0x89c5,0x6ccc,0x871c,0x5bc6,0x5e42,0x68c9,0x7720,
125.1517 +    0x7ef5,0x5195,0x514d,0x52c9,0x5a29,0x7f05,0x9762,0x82d7,0x63cf,0x7784,
125.1518 +    0x85d0,0x79d2,0x6e3a,0x5e99,0x5999,0x8511,0x706d,0x6c11,0x62bf,0x76bf,
125.1519 +    0x654f,0x60af,0x95fd,0x660e,0x879f,0x9e23,0x94ed,0x540d,0x547d,0x8c2c,
125.1520 +    0x6478
125.1521 +  },
125.1522 +  {				/* ku 44 */
125.1523 +    0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8147,0x8149,0x814d,0x814e,
125.1524 +    0x814f,0x8152,0x8156,0x8157,0x8158,0x815b,0x815c,0x815d,0x815e,0x815f,
125.1525 +    0x8161,0x8162,0x8163,0x8164,0x8166,0x8168,0x816a,0x816b,0x816c,0x816f,
125.1526 +    0x8172,0x8173,0x8175,0x8176,0x8177,0x8178,0x8181,0x8183,0x8184,0x8185,
125.1527 +    0x8186,0x8187,0x8189,0x818b,0x818c,0x818d,0x818e,0x8190,0x8192,0x8193,
125.1528 +    0x8194,0x8195,0x8196,0x8197,0x8199,0x819a,0x819e,0x819f,0x81a0,0x81a1,
125.1529 +    0x81a2,0x81a4,0x81a5,UBOGON,0x81a7,0x81a9,0x81ab,0x81ac,0x81ad,0x81ae,
125.1530 +    0x81af,0x81b0,0x81b1,0x81b2,0x81b4,0x81b5,0x81b6,0x81b7,0x81b8,0x81b9,
125.1531 +    0x81bc,0x81bd,0x81be,0x81bf,0x81c4,0x81c5,0x81c7,0x81c8,0x81c9,0x81cb,
125.1532 +    0x81cd,0x81ce,0x81cf,0x81d0,0x81d1,0x81d2,0x81d3,0x6479,0x8611,0x6a21,
125.1533 +    0x819c,0x78e8,0x6469,0x9b54,0x62b9,0x672b,0x83ab,0x58a8,0x9ed8,0x6cab,
125.1534 +    0x6f20,0x5bde,0x964c,0x8c0b,0x725f,0x67d0,0x62c7,0x7261,0x4ea9,0x59c6,
125.1535 +    0x6bcd,0x5893,0x66ae,0x5e55,0x52df,0x6155,0x6728,0x76ee,0x7766,0x7267,
125.1536 +    0x7a46,0x62ff,0x54ea,0x5450,0x94a0,0x90a3,0x5a1c,0x7eb3,0x6c16,0x4e43,
125.1537 +    0x5976,0x8010,0x5948,0x5357,0x7537,0x96be,0x56ca,0x6320,0x8111,0x607c,
125.1538 +    0x95f9,0x6dd6,0x5462,0x9981,0x5185,0x5ae9,0x80fd,0x59ae,0x9713,0x502a,
125.1539 +    0x6ce5,0x5c3c,0x62df,0x4f60,0x533f,0x817b,0x9006,0x6eba,0x852b,0x62c8,
125.1540 +    0x5e74,0x78be,0x64b5,0x637b,0x5ff5,0x5a18,0x917f,0x9e1f,0x5c3f,0x634f,
125.1541 +    0x8042,0x5b7d,0x556e,0x954a,0x954d,0x6d85,0x60a8,0x67e0,0x72de,0x51dd,
125.1542 +    0x5b81
125.1543 +  },
125.1544 +  {				/* ku 45 */
125.1545 +    0x81d4,0x81d5,0x81d6,0x81d7,0x81d8,0x81d9,0x81da,0x81db,0x81dc,0x81dd,
125.1546 +    0x81de,0x81df,0x81e0,0x81e1,0x81e2,0x81e4,0x81e5,0x81e6,0x81e8,0x81e9,
125.1547 +    0x81eb,0x81ee,0x81ef,0x81f0,0x81f1,0x81f2,0x81f5,0x81f6,0x81f7,0x81f8,
125.1548 +    0x81f9,0x81fa,0x81fd,0x81ff,0x8203,0x8207,0x8208,0x8209,0x820a,0x820b,
125.1549 +    0x820e,0x820f,0x8211,0x8213,0x8215,0x8216,0x8217,0x8218,0x8219,0x821a,
125.1550 +    0x821d,0x8220,0x8224,0x8225,0x8226,0x8227,0x8229,0x822e,0x8232,0x823a,
125.1551 +    0x823c,0x823d,0x823f,UBOGON,0x8240,0x8241,0x8242,0x8243,0x8245,0x8246,
125.1552 +    0x8248,0x824a,0x824c,0x824d,0x824e,0x8250,0x8251,0x8252,0x8253,0x8254,
125.1553 +    0x8255,0x8256,0x8257,0x8259,0x825b,0x825c,0x825d,0x825e,0x8260,0x8261,
125.1554 +    0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,0x8269,0x62e7,0x6cde,0x725b,
125.1555 +    0x626d,0x94ae,0x7ebd,0x8113,0x6d53,0x519c,0x5f04,0x5974,0x52aa,0x6012,
125.1556 +    0x5973,0x6696,0x8650,0x759f,0x632a,0x61e6,0x7cef,0x8bfa,0x54e6,0x6b27,
125.1557 +    0x9e25,0x6bb4,0x85d5,0x5455,0x5076,0x6ca4,0x556a,0x8db4,0x722c,0x5e15,
125.1558 +    0x6015,0x7436,0x62cd,0x6392,0x724c,0x5f98,0x6e43,0x6d3e,0x6500,0x6f58,
125.1559 +    0x76d8,0x78d0,0x76fc,0x7554,0x5224,0x53db,0x4e53,0x5e9e,0x65c1,0x802a,
125.1560 +    0x80d6,0x629b,0x5486,0x5228,0x70ae,0x888d,0x8dd1,0x6ce1,0x5478,0x80da,
125.1561 +    0x57f9,0x88f4,0x8d54,0x966a,0x914d,0x4f69,0x6c9b,0x55b7,0x76c6,0x7830,
125.1562 +    0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da,0x787c,0x7bf7,0x81a8,0x670b,
125.1563 +    0x9e4f,0x6367,0x78b0,0x576f,0x7812,0x9739,0x6279,0x62ab,0x5288,0x7435,
125.1564 +    0x6bd7
125.1565 +  },
125.1566 +  {				/* ku 46 */
125.1567 +    0x826a,0x826b,0x826c,0x826d,0x8271,0x8275,0x8276,0x8277,0x8278,0x827b,
125.1568 +    0x827c,0x8280,0x8281,0x8283,0x8285,0x8286,0x8287,0x8289,0x828c,0x8290,
125.1569 +    0x8293,0x8294,0x8295,0x8296,0x829a,0x829b,0x829e,0x82a0,0x82a2,0x82a3,
125.1570 +    0x82a7,0x82b2,0x82b5,0x82b6,0x82ba,0x82bb,0x82bc,0x82bf,0x82c0,0x82c2,
125.1571 +    0x82c3,0x82c5,0x82c6,0x82c9,0x82d0,0x82d6,0x82d9,0x82da,0x82dd,0x82e2,
125.1572 +    0x82e7,0x82e8,0x82e9,0x82ea,0x82ec,0x82ed,0x82ee,0x82f0,0x82f2,0x82f3,
125.1573 +    0x82f5,0x82f6,0x82f8,UBOGON,0x82fa,0x82fc,0x82fd,0x82fe,0x82ff,0x8300,
125.1574 +    0x830a,0x830b,0x830d,0x8310,0x8312,0x8313,0x8316,0x8318,0x8319,0x831d,
125.1575 +    0x831e,0x831f,0x8320,0x8321,0x8322,0x8323,0x8324,0x8325,0x8326,0x8329,
125.1576 +    0x832a,0x832e,0x8330,0x8332,0x8337,0x833b,0x833d,0x5564,0x813e,0x75b2,
125.1577 +    0x76ae,0x5339,0x75de,0x50fb,0x5c41,0x8b6c,0x7bc7,0x504f,0x7247,0x9a97,
125.1578 +    0x98d8,0x6f02,0x74e2,0x7968,0x6487,0x77a5,0x62fc,0x9891,0x8d2b,0x54c1,
125.1579 +    0x8058,0x4e52,0x576a,0x82f9,0x840d,0x5e73,0x51ed,0x74f6,0x8bc4,0x5c4f,
125.1580 +    0x5761,0x6cfc,0x9887,0x5a46,0x7834,0x9b44,0x8feb,0x7c95,0x5256,0x6251,
125.1581 +    0x94fa,0x4ec6,0x8386,0x8461,0x83e9,0x84b2,0x57d4,0x6734,0x5703,0x666e,
125.1582 +    0x6d66,0x8c31,0x66dd,0x7011,0x671f,0x6b3a,0x6816,0x621a,0x59bb,0x4e03,
125.1583 +    0x51c4,0x6f06,0x67d2,0x6c8f,0x5176,0x68cb,0x5947,0x6b67,0x7566,0x5d0e,
125.1584 +    0x8110,0x9f50,0x65d7,0x7948,0x7941,0x9a91,0x8d77,0x5c82,0x4e5e,0x4f01,
125.1585 +    0x542f,0x5951,0x780c,0x5668,0x6c14,0x8fc4,0x5f03,0x6c7d,0x6ce3,0x8bab,
125.1586 +    0x6390
125.1587 +  },
125.1588 +  {				/* ku 47 */
125.1589 +    0x833e,0x833f,0x8341,0x8342,0x8344,0x8345,0x8348,0x834a,0x834b,0x834c,
125.1590 +    0x834d,0x834e,0x8353,0x8355,0x8356,0x8357,0x8358,0x8359,0x835d,0x8362,
125.1591 +    0x8370,0x8371,0x8372,0x8373,0x8374,0x8375,0x8376,0x8379,0x837a,0x837e,
125.1592 +    0x837f,0x8380,0x8381,0x8382,0x8383,0x8384,0x8387,0x8388,0x838a,0x838b,
125.1593 +    0x838c,0x838d,0x838f,0x8390,0x8391,0x8394,0x8395,0x8396,0x8397,0x8399,
125.1594 +    0x839a,0x839d,0x839f,0x83a1,0x83a2,0x83a3,0x83a4,0x83a5,0x83a6,0x83a7,
125.1595 +    0x83ac,0x83ad,0x83ae,UBOGON,0x83af,0x83b5,0x83bb,0x83be,0x83bf,0x83c2,
125.1596 +    0x83c3,0x83c4,0x83c6,0x83c8,0x83c9,0x83cb,0x83cd,0x83ce,0x83d0,0x83d1,
125.1597 +    0x83d2,0x83d3,0x83d5,0x83d7,0x83d9,0x83da,0x83db,0x83de,0x83e2,0x83e3,
125.1598 +    0x83e4,0x83e6,0x83e7,0x83e8,0x83eb,0x83ec,0x83ed,0x6070,0x6d3d,0x7275,
125.1599 +    0x6266,0x948e,0x94c5,0x5343,0x8fc1,0x7b7e,0x4edf,0x8c26,0x4e7e,0x9ed4,
125.1600 +    0x94b1,0x94b3,0x524d,0x6f5c,0x9063,0x6d45,0x8c34,0x5811,0x5d4c,0x6b20,
125.1601 +    0x6b49,0x67aa,0x545b,0x8154,0x7f8c,0x5899,0x8537,0x5f3a,0x62a2,0x6a47,
125.1602 +    0x9539,0x6572,0x6084,0x6865,0x77a7,0x4e54,0x4fa8,0x5de7,0x9798,0x64ac,
125.1603 +    0x7fd8,0x5ced,0x4fcf,0x7a8d,0x5207,0x8304,0x4e14,0x602f,0x7a83,0x94a6,
125.1604 +    0x4fb5,0x4eb2,0x79e6,0x7434,0x52e4,0x82b9,0x64d2,0x79bd,0x5bdd,0x6c81,
125.1605 +    0x9752,0x8f7b,0x6c22,0x503e,0x537f,0x6e05,0x64ce,0x6674,0x6c30,0x60c5,
125.1606 +    0x9877,0x8bf7,0x5e86,0x743c,0x7a77,0x79cb,0x4e18,0x90b1,0x7403,0x6c42,
125.1607 +    0x56da,0x914b,0x6cc5,0x8d8b,0x533a,0x86c6,0x66f2,0x8eaf,0x5c48,0x9a71,
125.1608 +    0x6e20
125.1609 +  },
125.1610 +  {				/* ku 48 */
125.1611 +    0x83ee,0x83ef,0x83f3,0x83f4,0x83f5,0x83f6,0x83f7,0x83fa,0x83fb,0x83fc,
125.1612 +    0x83fe,0x83ff,0x8400,0x8402,0x8405,0x8407,0x8408,0x8409,0x840a,0x8410,
125.1613 +    0x8412,0x8413,0x8414,0x8415,0x8416,0x8417,0x8419,0x841a,0x841b,0x841e,
125.1614 +    0x841f,0x8420,0x8421,0x8422,0x8423,0x8429,0x842a,0x842b,0x842c,0x842d,
125.1615 +    0x842e,0x842f,0x8430,0x8432,0x8433,0x8434,0x8435,0x8436,0x8437,0x8439,
125.1616 +    0x843a,0x843b,0x843e,0x843f,0x8440,0x8441,0x8442,0x8443,0x8444,0x8445,
125.1617 +    0x8447,0x8448,0x8449,UBOGON,0x844a,0x844b,0x844c,0x844d,0x844e,0x844f,
125.1618 +    0x8450,0x8452,0x8453,0x8454,0x8455,0x8456,0x8458,0x845d,0x845e,0x845f,
125.1619 +    0x8460,0x8462,0x8464,0x8465,0x8466,0x8467,0x8468,0x846a,0x846e,0x846f,
125.1620 +    0x8470,0x8472,0x8474,0x8477,0x8479,0x847b,0x847c,0x53d6,0x5a36,0x9f8b,
125.1621 +    0x8da3,0x53bb,0x5708,0x98a7,0x6743,0x919b,0x6cc9,0x5168,0x75ca,0x62f3,
125.1622 +    0x72ac,0x5238,0x529d,0x7f3a,0x7094,0x7638,0x5374,0x9e4a,0x69b7,0x786e,
125.1623 +    0x96c0,0x88d9,0x7fa4,0x7136,0x71c3,0x5189,0x67d3,0x74e4,0x58e4,0x6518,
125.1624 +    0x56b7,0x8ba9,0x9976,0x6270,0x7ed5,0x60f9,0x70ed,0x58ec,0x4ec1,0x4eba,
125.1625 +    0x5fcd,0x97e7,0x4efb,0x8ba4,0x5203,0x598a,0x7eab,0x6254,0x4ecd,0x65e5,
125.1626 +    0x620e,0x8338,0x84c9,0x8363,0x878d,0x7194,0x6eb6,0x5bb9,0x7ed2,0x5197,
125.1627 +    0x63c9,0x67d4,0x8089,0x8339,0x8815,0x5112,0x5b7a,0x5982,0x8fb1,0x4e73,
125.1628 +    0x6c5d,0x5165,0x8925,0x8f6f,0x962e,0x854a,0x745e,0x9510,0x95f0,0x6da6,
125.1629 +    0x82e5,0x5f31,0x6492,0x6d12,0x8428,0x816e,0x9cc3,0x585e,0x8d5b,0x4e09,
125.1630 +    0x53c1
125.1631 +  },
125.1632 +  {				/* ku 49 */
125.1633 +    0x847d,0x847e,0x847f,0x8480,0x8481,0x8483,0x8484,0x8485,0x8486,0x848a,
125.1634 +    0x848d,0x848f,0x8490,0x8491,0x8492,0x8493,0x8494,0x8495,0x8496,0x8498,
125.1635 +    0x849a,0x849b,0x849d,0x849e,0x849f,0x84a0,0x84a2,0x84a3,0x84a4,0x84a5,
125.1636 +    0x84a6,0x84a7,0x84a8,0x84a9,0x84aa,0x84ab,0x84ac,0x84ad,0x84ae,0x84b0,
125.1637 +    0x84b1,0x84b3,0x84b5,0x84b6,0x84b7,0x84bb,0x84bc,0x84be,0x84c0,0x84c2,
125.1638 +    0x84c3,0x84c5,0x84c6,0x84c7,0x84c8,0x84cb,0x84cc,0x84ce,0x84cf,0x84d2,
125.1639 +    0x84d4,0x84d5,0x84d7,UBOGON,0x84d8,0x84d9,0x84da,0x84db,0x84dc,0x84de,
125.1640 +    0x84e1,0x84e2,0x84e4,0x84e7,0x84e8,0x84e9,0x84ea,0x84eb,0x84ed,0x84ee,
125.1641 +    0x84ef,0x84f1,0x84f2,0x84f3,0x84f4,0x84f5,0x84f6,0x84f7,0x84f8,0x84f9,
125.1642 +    0x84fa,0x84fb,0x84fd,0x84fe,0x8500,0x8501,0x8502,0x4f1e,0x6563,0x6851,
125.1643 +    0x55d3,0x4e27,0x6414,0x9a9a,0x626b,0x5ac2,0x745f,0x8272,0x6da9,0x68ee,
125.1644 +    0x50e7,0x838e,0x7802,0x6740,0x5239,0x6c99,0x7eb1,0x50bb,0x5565,0x715e,
125.1645 +    0x7b5b,0x6652,0x73ca,0x82eb,0x6749,0x5c71,0x5220,0x717d,0x886b,0x95ea,
125.1646 +    0x9655,0x64c5,0x8d61,0x81b3,0x5584,0x6c55,0x6247,0x7f2e,0x5892,0x4f24,
125.1647 +    0x5546,0x8d4f,0x664c,0x4e0a,0x5c1a,0x88f3,0x68a2,0x634e,0x7a0d,0x70e7,
125.1648 +    0x828d,0x52fa,0x97f6,0x5c11,0x54e8,0x90b5,0x7ecd,0x5962,0x8d4a,0x86c7,
125.1649 +    0x820c,0x820d,0x8d66,0x6444,0x5c04,0x6151,0x6d89,0x793e,0x8bbe,0x7837,
125.1650 +    0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20,0x7ec5,0x795e,0x6c88,0x5ba1,
125.1651 +    0x5a76,0x751a,0x80be,0x614e,0x6e17,0x58f0,0x751f,0x7525,0x7272,0x5347,
125.1652 +    0x7ef3
125.1653 +  },
125.1654 +  {				/* ku 4a */
125.1655 +    0x8503,0x8504,0x8505,0x8506,0x8507,0x8508,0x8509,0x850a,0x850b,0x850d,
125.1656 +    0x850e,0x850f,0x8510,0x8512,0x8514,0x8515,0x8516,0x8518,0x8519,0x851b,
125.1657 +    0x851c,0x851d,0x851e,0x8520,0x8522,0x8523,0x8524,0x8525,0x8526,0x8527,
125.1658 +    0x8528,0x8529,0x852a,0x852d,0x852e,0x852f,0x8530,0x8531,0x8532,0x8533,
125.1659 +    0x8534,0x8535,0x8536,0x853e,0x853f,0x8540,0x8541,0x8542,0x8544,0x8545,
125.1660 +    0x8546,0x8547,0x854b,0x854c,0x854d,0x854e,0x854f,0x8550,0x8551,0x8552,
125.1661 +    0x8553,0x8554,0x8555,UBOGON,0x8557,0x8558,0x855a,0x855b,0x855c,0x855d,
125.1662 +    0x855f,0x8560,0x8561,0x8562,0x8563,0x8565,0x8566,0x8567,0x8569,0x856a,
125.1663 +    0x856b,0x856c,0x856d,0x856e,0x856f,0x8570,0x8571,0x8573,0x8575,0x8576,
125.1664 +    0x8577,0x8578,0x857c,0x857d,0x857f,0x8580,0x8581,0x7701,0x76db,0x5269,
125.1665 +    0x80dc,0x5723,0x5e08,0x5931,0x72ee,0x65bd,0x6e7f,0x8bd7,0x5c38,0x8671,
125.1666 +    0x5341,0x77f3,0x62fe,0x65f6,0x4ec0,0x98df,0x8680,0x5b9e,0x8bc6,0x53f2,
125.1667 +    0x77e2,0x4f7f,0x5c4e,0x9a76,0x59cb,0x5f0f,0x793a,0x58eb,0x4e16,0x67ff,
125.1668 +    0x4e8b,0x62ed,0x8a93,0x901d,0x52bf,0x662f,0x55dc,0x566c,0x9002,0x4ed5,
125.1669 +    0x4f8d,0x91ca,0x9970,0x6c0f,0x5e02,0x6043,0x5ba4,0x89c6,0x8bd5,0x6536,
125.1670 +    0x624b,0x9996,0x5b88,0x5bff,0x6388,0x552e,0x53d7,0x7626,0x517d,0x852c,
125.1671 +    0x67a2,0x68b3,0x6b8a,0x6292,0x8f93,0x53d4,0x8212,0x6dd1,0x758f,0x4e66,
125.1672 +    0x8d4e,0x5b70,0x719f,0x85af,0x6691,0x66d9,0x7f72,0x8700,0x9ecd,0x9f20,
125.1673 +    0x5c5e,0x672f,0x8ff0,0x6811,0x675f,0x620d,0x7ad6,0x5885,0x5eb6,0x6570,
125.1674 +    0x6f31
125.1675 +  },
125.1676 +  {				/* ku 4b */
125.1677 +    0x8582,0x8583,0x8586,0x8588,0x8589,0x858a,0x858b,0x858c,0x858d,0x858e,
125.1678 +    0x8590,0x8591,0x8592,0x8593,0x8594,0x8595,0x8596,0x8597,0x8598,0x8599,
125.1679 +    0x859a,0x859d,0x859e,0x859f,0x85a0,0x85a1,0x85a2,0x85a3,0x85a5,0x85a6,
125.1680 +    0x85a7,0x85a9,0x85ab,0x85ac,0x85ad,0x85b1,0x85b2,0x85b3,0x85b4,0x85b5,
125.1681 +    0x85b6,0x85b8,0x85ba,0x85bb,0x85bc,0x85bd,0x85be,0x85bf,0x85c0,0x85c2,
125.1682 +    0x85c3,0x85c4,0x85c5,0x85c6,0x85c7,0x85c8,0x85ca,0x85cb,0x85cc,0x85cd,
125.1683 +    0x85ce,0x85d1,0x85d2,UBOGON,0x85d4,0x85d6,0x85d7,0x85d8,0x85d9,0x85da,
125.1684 +    0x85db,0x85dd,0x85de,0x85df,0x85e0,0x85e1,0x85e2,0x85e3,0x85e5,0x85e6,
125.1685 +    0x85e7,0x85e8,0x85ea,0x85eb,0x85ec,0x85ed,0x85ee,0x85ef,0x85f0,0x85f1,
125.1686 +    0x85f2,0x85f3,0x85f4,0x85f5,0x85f6,0x85f7,0x85f8,0x6055,0x5237,0x800d,
125.1687 +    0x6454,0x8870,0x7529,0x5e05,0x6813,0x62f4,0x971c,0x53cc,0x723d,0x8c01,
125.1688 +    0x6c34,0x7761,0x7a0e,0x542e,0x77ac,0x987a,0x821c,0x8bf4,0x7855,0x6714,
125.1689 +    0x70c1,0x65af,0x6495,0x5636,0x601d,0x79c1,0x53f8,0x4e1d,0x6b7b,0x8086,
125.1690 +    0x5bfa,0x55e3,0x56db,0x4f3a,0x4f3c,0x9972,0x5df3,0x677e,0x8038,0x6002,
125.1691 +    0x9882,0x9001,0x5b8b,0x8bbc,0x8bf5,0x641c,0x8258,0x64de,0x55fd,0x82cf,
125.1692 +    0x9165,0x4fd7,0x7d20,0x901f,0x7c9f,0x50f3,0x5851,0x6eaf,0x5bbf,0x8bc9,
125.1693 +    0x8083,0x9178,0x849c,0x7b97,0x867d,0x968b,0x968f,0x7ee5,0x9ad3,0x788e,
125.1694 +    0x5c81,0x7a57,0x9042,0x96a7,0x795f,0x5b59,0x635f,0x7b0b,0x84d1,0x68ad,
125.1695 +    0x5506,0x7f29,0x7410,0x7d22,0x9501,0x6240,0x584c,0x4ed6,0x5b83,0x5979,
125.1696 +    0x5854
125.1697 +  },
125.1698 +  {				/* ku 4c */
125.1699 +    0x85f9,0x85fa,0x85fc,0x85fd,0x85fe,0x8600,0x8601,0x8602,0x8603,0x8604,
125.1700 +    0x8606,0x8607,0x8608,0x8609,0x860a,0x860b,0x860c,0x860d,0x860e,0x860f,
125.1701 +    0x8610,0x8612,0x8613,0x8614,0x8615,0x8617,0x8618,0x8619,0x861a,0x861b,
125.1702 +    0x861c,0x861d,0x861e,0x861f,0x8620,0x8621,0x8622,0x8623,0x8624,0x8625,
125.1703 +    0x8626,0x8628,0x862a,0x862b,0x862c,0x862d,0x862e,0x862f,0x8630,0x8631,
125.1704 +    0x8632,0x8633,0x8634,0x8635,0x8636,0x8637,0x8639,0x863a,0x863b,0x863d,
125.1705 +    0x863e,0x863f,0x8640,UBOGON,0x8641,0x8642,0x8643,0x8644,0x8645,0x8646,
125.1706 +    0x8647,0x8648,0x8649,0x864a,0x864b,0x864c,0x8652,0x8653,0x8655,0x8656,
125.1707 +    0x8657,0x8658,0x8659,0x865b,0x865c,0x865d,0x865f,0x8660,0x8661,0x8663,
125.1708 +    0x8664,0x8665,0x8666,0x8667,0x8668,0x8669,0x866a,0x736d,0x631e,0x8e4b,
125.1709 +    0x8e0f,0x80ce,0x82d4,0x62ac,0x53f0,0x6cf0,0x915e,0x592a,0x6001,0x6c70,
125.1710 +    0x574d,0x644a,0x8d2a,0x762b,0x6ee9,0x575b,0x6a80,0x75f0,0x6f6d,0x8c2d,
125.1711 +    0x8c08,0x5766,0x6bef,0x8892,0x78b3,0x63a2,0x53f9,0x70ad,0x6c64,0x5858,
125.1712 +    0x642a,0x5802,0x68e0,0x819b,0x5510,0x7cd6,0x5018,0x8eba,0x6dcc,0x8d9f,
125.1713 +    0x70eb,0x638f,0x6d9b,0x6ed4,0x7ee6,0x8404,0x6843,0x9003,0x6dd8,0x9676,
125.1714 +    0x8ba8,0x5957,0x7279,0x85e4,0x817e,0x75bc,0x8a8a,0x68af,0x5254,0x8e22,
125.1715 +    0x9511,0x63d0,0x9898,0x8e44,0x557c,0x4f53,0x66ff,0x568f,0x60d5,0x6d95,
125.1716 +    0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530,0x751c,0x606c,0x8214,0x8146,
125.1717 +    0x6311,0x6761,0x8fe2,0x773a,0x8df3,0x8d34,0x94c1,0x5e16,0x5385,0x542c,
125.1718 +    0x70c3
125.1719 +  },
125.1720 +  {				/* ku 4d */
125.1721 +    0x866d,0x866f,0x8670,0x8672,0x8673,0x8674,0x8675,0x8676,0x8677,0x8678,
125.1722 +    0x8683,0x8684,0x8685,0x8686,0x8687,0x8688,0x8689,0x868e,0x868f,0x8690,
125.1723 +    0x8691,0x8692,0x8694,0x8696,0x8697,0x8698,0x8699,0x869a,0x869b,0x869e,
125.1724 +    0x869f,0x86a0,0x86a1,0x86a2,0x86a5,0x86a6,0x86ab,0x86ad,0x86ae,0x86b2,
125.1725 +    0x86b3,0x86b7,0x86b8,0x86b9,0x86bb,0x86bc,0x86bd,0x86be,0x86bf,0x86c1,
125.1726 +    0x86c2,0x86c3,0x86c5,0x86c8,0x86cc,0x86cd,0x86d2,0x86d3,0x86d5,0x86d6,
125.1727 +    0x86d7,0x86da,0x86dc,UBOGON,0x86dd,0x86e0,0x86e1,0x86e2,0x86e3,0x86e5,
125.1728 +    0x86e6,0x86e7,0x86e8,0x86ea,0x86eb,0x86ec,0x86ef,0x86f5,0x86f6,0x86f7,
125.1729 +    0x86fa,0x86fb,0x86fc,0x86fd,0x86ff,0x8701,0x8704,0x8705,0x8706,0x870b,
125.1730 +    0x870c,0x870e,0x870f,0x8710,0x8711,0x8714,0x8716,0x6c40,0x5ef7,0x505c,
125.1731 +    0x4ead,0x5ead,0x633a,0x8247,0x901a,0x6850,0x916e,0x77b3,0x540c,0x94dc,
125.1732 +    0x5f64,0x7ae5,0x6876,0x6345,0x7b52,0x7edf,0x75db,0x5077,0x6295,0x5934,
125.1733 +    0x900f,0x51f8,0x79c3,0x7a81,0x56fe,0x5f92,0x9014,0x6d82,0x5c60,0x571f,
125.1734 +    0x5410,0x5154,0x6e4d,0x56e2,0x63a8,0x9893,0x817f,0x8715,0x892a,0x9000,
125.1735 +    0x541e,0x5c6f,0x81c0,0x62d6,0x6258,0x8131,0x9e35,0x9640,0x9a6e,0x9a7c,
125.1736 +    0x692d,0x59a5,0x62d3,0x553e,0x6316,0x54c7,0x86d9,0x6d3c,0x5a03,0x74e6,
125.1737 +    0x889c,0x6b6a,0x5916,0x8c4c,0x5f2f,0x6e7e,0x73a9,0x987d,0x4e38,0x70f7,
125.1738 +    0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb,0x5b9b,0x5a49,0x4e07,0x8155,
125.1739 +    0x6c6a,0x738b,0x4ea1,0x6789,0x7f51,0x5f80,0x65fa,0x671b,0x5fd8,0x5984,
125.1740 +    0x5a01
125.1741 +  },
125.1742 +  {				/* ku 4e */
125.1743 +    0x8719,0x871b,0x871d,0x871f,0x8720,0x8724,0x8726,0x8727,0x8728,0x872a,
125.1744 +    0x872b,0x872c,0x872d,0x872f,0x8730,0x8732,0x8733,0x8735,0x8736,0x8738,
125.1745 +    0x8739,0x873a,0x873c,0x873d,0x8740,0x8741,0x8742,0x8743,0x8744,0x8745,
125.1746 +    0x8746,0x874a,0x874b,0x874d,0x874f,0x8750,0x8751,0x8752,0x8754,0x8755,
125.1747 +    0x8756,0x8758,0x875a,0x875b,0x875c,0x875d,0x875e,0x875f,0x8761,0x8762,
125.1748 +    0x8766,0x8767,0x8768,0x8769,0x876a,0x876b,0x876c,0x876d,0x876f,0x8771,
125.1749 +    0x8772,0x8773,0x8775,UBOGON,0x8777,0x8778,0x8779,0x877a,0x877f,0x8780,
125.1750 +    0x8781,0x8784,0x8786,0x8787,0x8789,0x878a,0x878c,0x878e,0x878f,0x8790,
125.1751 +    0x8791,0x8792,0x8794,0x8795,0x8796,0x8798,0x8799,0x879a,0x879b,0x879c,
125.1752 +    0x879d,0x879e,0x87a0,0x87a1,0x87a2,0x87a3,0x87a4,0x5dcd,0x5fae,0x5371,
125.1753 +    0x97e6,0x8fdd,0x6845,0x56f4,0x552f,0x60df,0x4e3a,0x6f4d,0x7ef4,0x82c7,
125.1754 +    0x840e,0x59d4,0x4f1f,0x4f2a,0x5c3e,0x7eac,0x672a,0x851a,0x5473,0x754f,
125.1755 +    0x80c3,0x5582,0x9b4f,0x4f4d,0x6e2d,0x8c13,0x5c09,0x6170,0x536b,0x761f,
125.1756 +    0x6e29,0x868a,0x6587,0x95fb,0x7eb9,0x543b,0x7a33,0x7d0a,0x95ee,0x55e1,
125.1757 +    0x7fc1,0x74ee,0x631d,0x8717,0x6da1,0x7a9d,0x6211,0x65a1,0x5367,0x63e1,
125.1758 +    0x6c83,0x5deb,0x545c,0x94a8,0x4e4c,0x6c61,0x8bec,0x5c4b,0x65e0,0x829c,
125.1759 +    0x68a7,0x543e,0x5434,0x6bcb,0x6b66,0x4e94,0x6342,0x5348,0x821e,0x4f0d,
125.1760 +    0x4fae,0x575e,0x620a,0x96fe,0x6664,0x7269,0x52ff,0x52a1,0x609f,0x8bef,
125.1761 +    0x6614,0x7199,0x6790,0x897f,0x7852,0x77fd,0x6670,0x563b,0x5438,0x9521,
125.1762 +    0x727a
125.1763 +  },
125.1764 +  {				/* ku 4f */
125.1765 +    0x87a5,0x87a6,0x87a7,0x87a9,0x87aa,0x87ae,0x87b0,0x87b1,0x87b2,0x87b4,
125.1766 +    0x87b6,0x87b7,0x87b8,0x87b9,0x87bb,0x87bc,0x87be,0x87bf,0x87c1,0x87c2,
125.1767 +    0x87c3,0x87c4,0x87c5,0x87c7,0x87c8,0x87c9,0x87cc,0x87cd,0x87ce,0x87cf,
125.1768 +    0x87d0,0x87d4,0x87d5,0x87d6,0x87d7,0x87d8,0x87d9,0x87da,0x87dc,0x87dd,
125.1769 +    0x87de,0x87df,0x87e1,0x87e2,0x87e3,0x87e4,0x87e6,0x87e7,0x87e8,0x87e9,
125.1770 +    0x87eb,0x87ec,0x87ed,0x87ef,0x87f0,0x87f1,0x87f2,0x87f3,0x87f4,0x87f5,
125.1771 +    0x87f6,0x87f7,0x87f8,UBOGON,0x87fa,0x87fb,0x87fc,0x87fd,0x87ff,0x8800,
125.1772 +    0x8801,0x8802,0x8804,0x8805,0x8806,0x8807,0x8808,0x8809,0x880b,0x880c,
125.1773 +    0x880d,0x880e,0x880f,0x8810,0x8811,0x8812,0x8814,0x8817,0x8818,0x8819,
125.1774 +    0x881a,0x881c,0x881d,0x881e,0x881f,0x8820,0x8823,0x7a00,0x606f,0x5e0c,
125.1775 +    0x6089,0x819d,0x5915,0x60dc,0x7184,0x70ef,0x6eaa,0x6c50,0x7280,0x6a84,
125.1776 +    0x88ad,0x5e2d,0x4e60,0x5ab3,0x559c,0x94e3,0x6d17,0x7cfb,0x9699,0x620f,
125.1777 +    0x7ec6,0x778e,0x867e,0x5323,0x971e,0x8f96,0x6687,0x5ce1,0x4fa0,0x72ed,
125.1778 +    0x4e0b,0x53a6,0x590f,0x5413,0x6380,0x9528,0x5148,0x4ed9,0x9c9c,0x7ea4,
125.1779 +    0x54b8,0x8d24,0x8854,0x8237,0x95f2,0x6d8e,0x5f26,0x5acc,0x663e,0x9669,
125.1780 +    0x73b0,0x732e,0x53bf,0x817a,0x9985,0x7fa1,0x5baa,0x9677,0x9650,0x7ebf,
125.1781 +    0x76f8,0x53a2,0x9576,0x9999,0x7bb1,0x8944,0x6e58,0x4e61,0x7fd4,0x7965,
125.1782 +    0x8be6,0x60f3,0x54cd,0x4eab,0x9879,0x5df7,0x6a61,0x50cf,0x5411,0x8c61,
125.1783 +    0x8427,0x785d,0x9704,0x524a,0x54ee,0x56a3,0x9500,0x6d88,0x5bb5,0x6dc6,
125.1784 +    0x6653
125.1785 +  },
125.1786 +  {				/* ku 50 */
125.1787 +    0x8824,0x8825,0x8826,0x8827,0x8828,0x8829,0x882a,0x882b,0x882c,0x882d,
125.1788 +    0x882e,0x882f,0x8830,0x8831,0x8833,0x8834,0x8835,0x8836,0x8837,0x8838,
125.1789 +    0x883a,0x883b,0x883d,0x883e,0x883f,0x8841,0x8842,0x8843,0x8846,0x8847,
125.1790 +    0x8848,0x8849,0x884a,0x884b,0x884e,0x884f,0x8850,0x8851,0x8852,0x8853,
125.1791 +    0x8855,0x8856,0x8858,0x885a,0x885b,0x885c,0x885d,0x885e,0x885f,0x8860,
125.1792 +    0x8866,0x8867,0x886a,0x886d,0x886f,0x8871,0x8873,0x8874,0x8875,0x8876,
125.1793 +    0x8878,0x8879,0x887a,UBOGON,0x887b,0x887c,0x8880,0x8883,0x8886,0x8887,
125.1794 +    0x8889,0x888a,0x888c,0x888e,0x888f,0x8890,0x8891,0x8893,0x8894,0x8895,
125.1795 +    0x8897,0x8898,0x8899,0x889a,0x889b,0x889d,0x889e,0x889f,0x88a0,0x88a1,
125.1796 +    0x88a3,0x88a5,0x88a6,0x88a7,0x88a8,0x88a9,0x88aa,0x5c0f,0x5b5d,0x6821,
125.1797 +    0x8096,0x5578,0x7b11,0x6548,0x6954,0x4e9b,0x6b47,0x874e,0x978b,0x534f,
125.1798 +    0x631f,0x643a,0x90aa,0x659c,0x80c1,0x8c10,0x5199,0x68b0,0x5378,0x87f9,
125.1799 +    0x61c8,0x6cc4,0x6cfb,0x8c22,0x5c51,0x85aa,0x82af,0x950c,0x6b23,0x8f9b,
125.1800 +    0x65b0,0x5ffb,0x5fc3,0x4fe1,0x8845,0x661f,0x8165,0x7329,0x60fa,0x5174,
125.1801 +    0x5211,0x578b,0x5f62,0x90a2,0x884c,0x9192,0x5e78,0x674f,0x6027,0x59d3,
125.1802 +    0x5144,0x51f6,0x80f8,0x5308,0x6c79,0x96c4,0x718a,0x4f11,0x4fee,0x7f9e,
125.1803 +    0x673d,0x55c5,0x9508,0x79c0,0x8896,0x7ee3,0x589f,0x620c,0x9700,0x865a,
125.1804 +    0x5618,0x987b,0x5f90,0x8bb8,0x84c4,0x9157,0x53d9,0x65ed,0x5e8f,0x755c,
125.1805 +    0x6064,0x7d6e,0x5a7f,0x7eea,0x7eed,0x8f69,0x55a7,0x5ba3,0x60ac,0x65cb,
125.1806 +    0x7384
125.1807 +  },
125.1808 +  {				/* ku 51 */
125.1809 +    0x88ac,0x88ae,0x88af,0x88b0,0x88b2,0x88b3,0x88b4,0x88b5,0x88b6,0x88b8,
125.1810 +    0x88b9,0x88ba,0x88bb,0x88bd,0x88be,0x88bf,0x88c0,0x88c3,0x88c4,0x88c7,
125.1811 +    0x88c8,0x88ca,0x88cb,0x88cc,0x88cd,0x88cf,0x88d0,0x88d1,0x88d3,0x88d6,
125.1812 +    0x88d7,0x88da,0x88db,0x88dc,0x88dd,0x88de,0x88e0,0x88e1,0x88e6,0x88e7,
125.1813 +    0x88e9,0x88ea,0x88eb,0x88ec,0x88ed,0x88ee,0x88ef,0x88f2,0x88f5,0x88f6,
125.1814 +    0x88f7,0x88fa,0x88fb,0x88fd,0x88ff,0x8900,0x8901,0x8903,0x8904,0x8905,
125.1815 +    0x8906,0x8907,0x8908,UBOGON,0x8909,0x890b,0x890c,0x890d,0x890e,0x890f,
125.1816 +    0x8911,0x8914,0x8915,0x8916,0x8917,0x8918,0x891c,0x891d,0x891e,0x891f,
125.1817 +    0x8920,0x8922,0x8923,0x8924,0x8926,0x8927,0x8928,0x8929,0x892c,0x892d,
125.1818 +    0x892e,0x892f,0x8931,0x8932,0x8933,0x8935,0x8937,0x9009,0x7663,0x7729,
125.1819 +    0x7eda,0x9774,0x859b,0x5b66,0x7a74,0x96ea,0x8840,0x52cb,0x718f,0x5faa,
125.1820 +    0x65ec,0x8be2,0x5bfb,0x9a6f,0x5de1,0x6b89,0x6c5b,0x8bad,0x8baf,0x900a,
125.1821 +    0x8fc5,0x538b,0x62bc,0x9e26,0x9e2d,0x5440,0x4e2b,0x82bd,0x7259,0x869c,
125.1822 +    0x5d16,0x8859,0x6daf,0x96c5,0x54d1,0x4e9a,0x8bb6,0x7109,0x54bd,0x9609,
125.1823 +    0x70df,0x6df9,0x76d0,0x4e25,0x7814,0x8712,0x5ca9,0x5ef6,0x8a00,0x989c,
125.1824 +    0x960e,0x708e,0x6cbf,0x5944,0x63a9,0x773c,0x884d,0x6f14,0x8273,0x5830,
125.1825 +    0x71d5,0x538c,0x781a,0x96c1,0x5501,0x5f66,0x7130,0x5bb4,0x8c1a,0x9a8c,
125.1826 +    0x6b83,0x592e,0x9e2f,0x79e7,0x6768,0x626c,0x4f6f,0x75a1,0x7f8a,0x6d0b,
125.1827 +    0x9633,0x6c27,0x4ef0,0x75d2,0x517b,0x6837,0x6f3e,0x9080,0x8170,0x5996,
125.1828 +    0x7476
125.1829 +  },
125.1830 +  {				/* ku 52 */
125.1831 +    0x8938,0x8939,0x893a,0x893b,0x893c,0x893d,0x893e,0x893f,0x8940,0x8942,
125.1832 +    0x8943,0x8945,0x8946,0x8947,0x8948,0x8949,0x894a,0x894b,0x894c,0x894d,
125.1833 +    0x894e,0x894f,0x8950,0x8951,0x8952,0x8953,0x8954,0x8955,0x8956,0x8957,
125.1834 +    0x8958,0x8959,0x895a,0x895b,0x895c,0x895d,0x8960,0x8961,0x8962,0x8963,
125.1835 +    0x8964,0x8965,0x8967,0x8968,0x8969,0x896a,0x896b,0x896c,0x896d,0x896e,
125.1836 +    0x896f,0x8970,0x8971,0x8972,0x8973,0x8974,0x8975,0x8976,0x8977,0x8978,
125.1837 +    0x8979,0x897a,0x897c,UBOGON,0x897d,0x897e,0x8980,0x8982,0x8984,0x8985,
125.1838 +    0x8987,0x8988,0x8989,0x898a,0x898b,0x898c,0x898d,0x898e,0x898f,0x8990,
125.1839 +    0x8991,0x8992,0x8993,0x8994,0x8995,0x8996,0x8997,0x8998,0x8999,0x899a,
125.1840 +    0x899b,0x899c,0x899d,0x899e,0x899f,0x89a0,0x89a1,0x6447,0x5c27,0x9065,
125.1841 +    0x7a91,0x8c23,0x59da,0x54ac,0x8200,0x836f,0x8981,0x8000,0x6930,0x564e,
125.1842 +    0x8036,0x7237,0x91ce,0x51b6,0x4e5f,0x9875,0x6396,0x4e1a,0x53f6,0x66f3,
125.1843 +    0x814b,0x591c,0x6db2,0x4e00,0x58f9,0x533b,0x63d6,0x94f1,0x4f9d,0x4f0a,
125.1844 +    0x8863,0x9890,0x5937,0x9057,0x79fb,0x4eea,0x80f0,0x7591,0x6c82,0x5b9c,
125.1845 +    0x59e8,0x5f5d,0x6905,0x8681,0x501a,0x5df2,0x4e59,0x77e3,0x4ee5,0x827a,
125.1846 +    0x6291,0x6613,0x9091,0x5c79,0x4ebf,0x5f79,0x81c6,0x9038,0x8084,0x75ab,
125.1847 +    0x4ea6,0x88d4,0x610f,0x6bc5,0x5fc6,0x4e49,0x76ca,0x6ea2,0x8be3,0x8bae,
125.1848 +    0x8c0a,0x8bd1,0x5f02,0x7ffc,0x7fcc,0x7ece,0x8335,0x836b,0x56e0,0x6bb7,
125.1849 +    0x97f3,0x9634,0x59fb,0x541f,0x94f6,0x6deb,0x5bc5,0x996e,0x5c39,0x5f15,
125.1850 +    0x9690
125.1851 +  },
125.1852 +  {				/* ku 53 */
125.1853 +    0x89a2,0x89a3,0x89a4,0x89a5,0x89a6,0x89a7,0x89a8,0x89a9,0x89aa,0x89ab,
125.1854 +    0x89ac,0x89ad,0x89ae,0x89af,0x89b0,0x89b1,0x89b2,0x89b3,0x89b4,0x89b5,
125.1855 +    0x89b6,0x89b7,0x89b8,0x89b9,0x89ba,0x89bb,0x89bc,0x89bd,0x89be,0x89bf,
125.1856 +    0x89c0,0x89c3,0x89cd,0x89d3,0x89d4,0x89d5,0x89d7,0x89d8,0x89d9,0x89db,
125.1857 +    0x89dd,0x89df,0x89e0,0x89e1,0x89e2,0x89e4,0x89e7,0x89e8,0x89e9,0x89ea,
125.1858 +    0x89ec,0x89ed,0x89ee,0x89f0,0x89f1,0x89f2,0x89f4,0x89f5,0x89f6,0x89f7,
125.1859 +    0x89f8,0x89f9,0x89fa,UBOGON,0x89fb,0x89fc,0x89fd,0x89fe,0x89ff,0x8a01,
125.1860 +    0x8a02,0x8a03,0x8a04,0x8a05,0x8a06,0x8a08,0x8a09,0x8a0a,0x8a0b,0x8a0c,
125.1861 +    0x8a0d,0x8a0e,0x8a0f,0x8a10,0x8a11,0x8a12,0x8a13,0x8a14,0x8a15,0x8a16,
125.1862 +    0x8a17,0x8a18,0x8a19,0x8a1a,0x8a1b,0x8a1c,0x8a1d,0x5370,0x82f1,0x6a31,
125.1863 +    0x5a74,0x9e70,0x5e94,0x7f28,0x83b9,0x8424,0x8425,0x8367,0x8747,0x8fce,
125.1864 +    0x8d62,0x76c8,0x5f71,0x9896,0x786c,0x6620,0x54df,0x62e5,0x4f63,0x81c3,
125.1865 +    0x75c8,0x5eb8,0x96cd,0x8e0a,0x86f9,0x548f,0x6cf3,0x6d8c,0x6c38,0x607f,
125.1866 +    0x52c7,0x7528,0x5e7d,0x4f18,0x60a0,0x5fe7,0x5c24,0x7531,0x90ae,0x94c0,
125.1867 +    0x72b9,0x6cb9,0x6e38,0x9149,0x6709,0x53cb,0x53f3,0x4f51,0x91c9,0x8bf1,
125.1868 +    0x53c8,0x5e7c,0x8fc2,0x6de4,0x4e8e,0x76c2,0x6986,0x865e,0x611a,0x8206,
125.1869 +    0x4f59,0x4fde,0x903e,0x9c7c,0x6109,0x6e1d,0x6e14,0x9685,0x4e88,0x5a31,
125.1870 +    0x96e8,0x4e0e,0x5c7f,0x79b9,0x5b87,0x8bed,0x7fbd,0x7389,0x57df,0x828b,
125.1871 +    0x90c1,0x5401,0x9047,0x55bb,0x5cea,0x5fa1,0x6108,0x6b32,0x72f1,0x80b2,
125.1872 +    0x8a89
125.1873 +  },
125.1874 +  {				/* ku 54 */
125.1875 +    0x8a1e,0x8a1f,0x8a20,0x8a21,0x8a22,0x8a23,0x8a24,0x8a25,0x8a26,0x8a27,
125.1876 +    0x8a28,0x8a29,0x8a2a,0x8a2b,0x8a2c,0x8a2d,0x8a2e,0x8a2f,0x8a30,0x8a31,
125.1877 +    0x8a32,0x8a33,0x8a34,0x8a35,0x8a36,0x8a37,0x8a38,0x8a39,0x8a3a,0x8a3b,
125.1878 +    0x8a3c,0x8a3d,0x8a3f,0x8a40,0x8a41,0x8a42,0x8a43,0x8a44,0x8a45,0x8a46,
125.1879 +    0x8a47,0x8a49,0x8a4a,0x8a4b,0x8a4c,0x8a4d,0x8a4e,0x8a4f,0x8a50,0x8a51,
125.1880 +    0x8a52,0x8a53,0x8a54,0x8a55,0x8a56,0x8a57,0x8a58,0x8a59,0x8a5a,0x8a5b,
125.1881 +    0x8a5c,0x8a5d,0x8a5e,UBOGON,0x8a5f,0x8a60,0x8a61,0x8a62,0x8a63,0x8a64,
125.1882 +    0x8a65,0x8a66,0x8a67,0x8a68,0x8a69,0x8a6a,0x8a6b,0x8a6c,0x8a6d,0x8a6e,
125.1883 +    0x8a6f,0x8a70,0x8a71,0x8a72,0x8a73,0x8a74,0x8a75,0x8a76,0x8a77,0x8a78,
125.1884 +    0x8a7a,0x8a7b,0x8a7c,0x8a7d,0x8a7e,0x8a7f,0x8a80,0x6d74,0x5bd3,0x88d5,
125.1885 +    0x9884,0x8c6b,0x9a6d,0x9e33,0x6e0a,0x51a4,0x5143,0x57a3,0x8881,0x539f,
125.1886 +    0x63f4,0x8f95,0x56ed,0x5458,0x5706,0x733f,0x6e90,0x7f18,0x8fdc,0x82d1,
125.1887 +    0x613f,0x6028,0x9662,0x66f0,0x7ea6,0x8d8a,0x8dc3,0x94a5,0x5cb3,0x7ca4,
125.1888 +    0x6708,0x60a6,0x9605,0x8018,0x4e91,0x90e7,0x5300,0x9668,0x5141,0x8fd0,
125.1889 +    0x8574,0x915d,0x6655,0x97f5,0x5b55,0x531d,0x7838,0x6742,0x683d,0x54c9,
125.1890 +    0x707e,0x5bb0,0x8f7d,0x518d,0x5728,0x54b1,0x6512,0x6682,0x8d5e,0x8d43,
125.1891 +    0x810f,0x846c,0x906d,0x7cdf,0x51ff,0x85fb,0x67a3,0x65e9,0x6fa1,0x86a4,
125.1892 +    0x8e81,0x566a,0x9020,0x7682,0x7076,0x71e5,0x8d23,0x62e9,0x5219,0x6cfd,
125.1893 +    0x8d3c,0x600e,0x589e,0x618e,0x66fe,0x8d60,0x624e,0x55b3,0x6e23,0x672d,
125.1894 +    0x8f67
125.1895 +  },
125.1896 +  {				/* ku 55 */
125.1897 +    0x8a81,0x8a82,0x8a83,0x8a84,0x8a85,0x8a86,0x8a87,0x8a88,0x8a8b,0x8a8c,
125.1898 +    0x8a8d,0x8a8e,0x8a8f,0x8a90,0x8a91,0x8a92,0x8a94,0x8a95,0x8a96,0x8a97,
125.1899 +    0x8a98,0x8a99,0x8a9a,0x8a9b,0x8a9c,0x8a9d,0x8a9e,0x8a9f,0x8aa0,0x8aa1,
125.1900 +    0x8aa2,0x8aa3,0x8aa4,0x8aa5,0x8aa6,0x8aa7,0x8aa8,0x8aa9,0x8aaa,0x8aab,
125.1901 +    0x8aac,0x8aad,0x8aae,0x8aaf,0x8ab0,0x8ab1,0x8ab2,0x8ab3,0x8ab4,0x8ab5,
125.1902 +    0x8ab6,0x8ab7,0x8ab8,0x8ab9,0x8aba,0x8abb,0x8abc,0x8abd,0x8abe,0x8abf,
125.1903 +    0x8ac0,0x8ac1,0x8ac2,UBOGON,0x8ac3,0x8ac4,0x8ac5,0x8ac6,0x8ac7,0x8ac8,
125.1904 +    0x8ac9,0x8aca,0x8acb,0x8acc,0x8acd,0x8ace,0x8acf,0x8ad0,0x8ad1,0x8ad2,
125.1905 +    0x8ad3,0x8ad4,0x8ad5,0x8ad6,0x8ad7,0x8ad8,0x8ad9,0x8ada,0x8adb,0x8adc,
125.1906 +    0x8add,0x8ade,0x8adf,0x8ae0,0x8ae1,0x8ae2,0x8ae3,0x94e1,0x95f8,0x7728,
125.1907 +    0x6805,0x69a8,0x548b,0x4e4d,0x70b8,0x8bc8,0x6458,0x658b,0x5b85,0x7a84,
125.1908 +    0x503a,0x5be8,0x77bb,0x6be1,0x8a79,0x7c98,0x6cbe,0x76cf,0x65a9,0x8f97,
125.1909 +    0x5d2d,0x5c55,0x8638,0x6808,0x5360,0x6218,0x7ad9,0x6e5b,0x7efd,0x6a1f,
125.1910 +    0x7ae0,0x5f70,0x6f33,0x5f20,0x638c,0x6da8,0x6756,0x4e08,0x5e10,0x8d26,
125.1911 +    0x4ed7,0x80c0,0x7634,0x969c,0x62db,0x662d,0x627e,0x6cbc,0x8d75,0x7167,
125.1912 +    0x7f69,0x5146,0x8087,0x53ec,0x906e,0x6298,0x54f2,0x86f0,0x8f99,0x8005,
125.1913 +    0x9517,0x8517,0x8fd9,0x6d59,0x73cd,0x659f,0x771f,0x7504,0x7827,0x81fb,
125.1914 +    0x8d1e,0x9488,0x4fa6,0x6795,0x75b9,0x8bca,0x9707,0x632f,0x9547,0x9635,
125.1915 +    0x84b8,0x6323,0x7741,0x5f81,0x72f0,0x4e89,0x6014,0x6574,0x62ef,0x6b63,
125.1916 +    0x653f
125.1917 +  },
125.1918 +  {				/* ku 56 */
125.1919 +    0x8ae4,0x8ae5,0x8ae6,0x8ae7,0x8ae8,0x8ae9,0x8aea,0x8aeb,0x8aec,0x8aed,
125.1920 +    0x8aee,0x8aef,0x8af0,0x8af1,0x8af2,0x8af3,0x8af4,0x8af5,0x8af6,0x8af7,
125.1921 +    0x8af8,0x8af9,0x8afa,0x8afb,0x8afc,0x8afd,0x8afe,0x8aff,0x8b00,0x8b01,
125.1922 +    0x8b02,0x8b03,0x8b04,0x8b05,0x8b06,0x8b08,0x8b09,0x8b0a,0x8b0b,0x8b0c,
125.1923 +    0x8b0d,0x8b0e,0x8b0f,0x8b10,0x8b11,0x8b12,0x8b13,0x8b14,0x8b15,0x8b16,
125.1924 +    0x8b17,0x8b18,0x8b19,0x8b1a,0x8b1b,0x8b1c,0x8b1d,0x8b1e,0x8b1f,0x8b20,
125.1925 +    0x8b21,0x8b22,0x8b23,UBOGON,0x8b24,0x8b25,0x8b27,0x8b28,0x8b29,0x8b2a,
125.1926 +    0x8b2b,0x8b2c,0x8b2d,0x8b2e,0x8b2f,0x8b30,0x8b31,0x8b32,0x8b33,0x8b34,
125.1927 +    0x8b35,0x8b36,0x8b37,0x8b38,0x8b39,0x8b3a,0x8b3b,0x8b3c,0x8b3d,0x8b3e,
125.1928 +    0x8b3f,0x8b40,0x8b41,0x8b42,0x8b43,0x8b44,0x8b45,0x5e27,0x75c7,0x90d1,
125.1929 +    0x8bc1,0x829d,0x679d,0x652f,0x5431,0x8718,0x77e5,0x80a2,0x8102,0x6c41,
125.1930 +    0x4e4b,0x7ec7,0x804c,0x76f4,0x690d,0x6b96,0x6267,0x503c,0x4f84,0x5740,
125.1931 +    0x6307,0x6b62,0x8dbe,0x53ea,0x65e8,0x7eb8,0x5fd7,0x631a,0x63b7,0x81f3,
125.1932 +    0x81f4,0x7f6e,0x5e1c,0x5cd9,0x5236,0x667a,0x79e9,0x7a1a,0x8d28,0x7099,
125.1933 +    0x75d4,0x6ede,0x6cbb,0x7a92,0x4e2d,0x76c5,0x5fe0,0x949f,0x8877,0x7ec8,
125.1934 +    0x79cd,0x80bf,0x91cd,0x4ef2,0x4f17,0x821f,0x5468,0x5dde,0x6d32,0x8bcc,
125.1935 +    0x7ca5,0x8f74,0x8098,0x5e1a,0x5492,0x76b1,0x5b99,0x663c,0x9aa4,0x73e0,
125.1936 +    0x682a,0x86db,0x6731,0x732a,0x8bf8,0x8bdb,0x9010,0x7af9,0x70db,0x716e,
125.1937 +    0x62c4,0x77a9,0x5631,0x4e3b,0x8457,0x67f1,0x52a9,0x86c0,0x8d2e,0x94f8,
125.1938 +    0x7b51
125.1939 +  },
125.1940 +  {				/* ku 57 */
125.1941 +    0x8b46,0x8b47,0x8b48,0x8b49,0x8b4a,0x8b4b,0x8b4c,0x8b4d,0x8b4e,0x8b4f,
125.1942 +    0x8b50,0x8b51,0x8b52,0x8b53,0x8b54,0x8b55,0x8b56,0x8b57,0x8b58,0x8b59,
125.1943 +    0x8b5a,0x8b5b,0x8b5c,0x8b5d,0x8b5e,0x8b5f,0x8b60,0x8b61,0x8b62,0x8b63,
125.1944 +    0x8b64,0x8b65,0x8b67,0x8b68,0x8b69,0x8b6a,0x8b6b,0x8b6d,0x8b6e,0x8b6f,
125.1945 +    0x8b70,0x8b71,0x8b72,0x8b73,0x8b74,0x8b75,0x8b76,0x8b77,0x8b78,0x8b79,
125.1946 +    0x8b7a,0x8b7b,0x8b7c,0x8b7d,0x8b7e,0x8b7f,0x8b80,0x8b81,0x8b82,0x8b83,
125.1947 +    0x8b84,0x8b85,0x8b86,UBOGON,0x8b87,0x8b88,0x8b89,0x8b8a,0x8b8b,0x8b8c,
125.1948 +    0x8b8d,0x8b8e,0x8b8f,0x8b90,0x8b91,0x8b92,0x8b93,0x8b94,0x8b95,0x8b96,
125.1949 +    0x8b97,0x8b98,0x8b99,0x8b9a,0x8b9b,0x8b9c,0x8b9d,0x8b9e,0x8b9f,0x8bac,
125.1950 +    0x8bb1,0x8bbb,0x8bc7,0x8bd0,0x8bea,0x8c09,0x8c1e,0x4f4f,0x6ce8,0x795d,
125.1951 +    0x9a7b,0x6293,0x722a,0x62fd,0x4e13,0x7816,0x8f6c,0x64b0,0x8d5a,0x7bc6,
125.1952 +    0x6869,0x5e84,0x88c5,0x5986,0x649e,0x58ee,0x72b6,0x690e,0x9525,0x8ffd,
125.1953 +    0x8d58,0x5760,0x7f00,0x8c06,0x51c6,0x6349,0x62d9,0x5353,0x684c,0x7422,
125.1954 +    0x8301,0x914c,0x5544,0x7740,0x707c,0x6d4a,0x5179,0x54a8,0x8d44,0x59ff,
125.1955 +    0x6ecb,0x6dc4,0x5b5c,0x7d2b,0x4ed4,0x7c7d,0x6ed3,0x5b50,0x81ea,0x6e0d,
125.1956 +    0x5b57,0x9b03,0x68d5,0x8e2a,0x5b97,0x7efc,0x603b,0x7eb5,0x90b9,0x8d70,
125.1957 +    0x594f,0x63cd,0x79df,0x8db3,0x5352,0x65cf,0x7956,0x8bc5,0x963b,0x7ec4,
125.1958 +    0x94bb,0x7e82,0x5634,0x9189,0x6700,0x7f6a,0x5c0a,0x9075,0x6628,0x5de6,
125.1959 +    0x4f50,0x67de,0x505a,0x4f5c,0x5750,0x5ea7,UBOGON,UBOGON,UBOGON,UBOGON,
125.1960 +    UBOGON
125.1961 +  },
125.1962 +  {				/* ku 58 */
125.1963 +    0x8c38,0x8c39,0x8c3a,0x8c3b,0x8c3c,0x8c3d,0x8c3e,0x8c3f,0x8c40,0x8c42,
125.1964 +    0x8c43,0x8c44,0x8c45,0x8c48,0x8c4a,0x8c4b,0x8c4d,0x8c4e,0x8c4f,0x8c50,
125.1965 +    0x8c51,0x8c52,0x8c53,0x8c54,0x8c56,0x8c57,0x8c58,0x8c59,0x8c5b,0x8c5c,
125.1966 +    0x8c5d,0x8c5e,0x8c5f,0x8c60,0x8c63,0x8c64,0x8c65,0x8c66,0x8c67,0x8c68,
125.1967 +    0x8c69,0x8c6c,0x8c6d,0x8c6e,0x8c6f,0x8c70,0x8c71,0x8c72,0x8c74,0x8c75,
125.1968 +    0x8c76,0x8c77,0x8c7b,0x8c7c,0x8c7d,0x8c7e,0x8c7f,0x8c80,0x8c81,0x8c83,
125.1969 +    0x8c84,0x8c86,0x8c87,UBOGON,0x8c88,0x8c8b,0x8c8d,0x8c8e,0x8c8f,0x8c90,
125.1970 +    0x8c91,0x8c92,0x8c93,0x8c95,0x8c96,0x8c97,0x8c99,0x8c9a,0x8c9b,0x8c9c,
125.1971 +    0x8c9d,0x8c9e,0x8c9f,0x8ca0,0x8ca1,0x8ca2,0x8ca3,0x8ca4,0x8ca5,0x8ca6,
125.1972 +    0x8ca7,0x8ca8,0x8ca9,0x8caa,0x8cab,0x8cac,0x8cad,0x4e8d,0x4e0c,0x5140,
125.1973 +    0x4e10,0x5eff,0x5345,0x4e15,0x4e98,0x4e1e,0x9b32,0x5b6c,0x5669,0x4e28,
125.1974 +    0x79ba,0x4e3f,0x5315,0x4e47,0x592d,0x723b,0x536e,0x6c10,0x56df,0x80e4,
125.1975 +    0x9997,0x6bd3,0x777e,0x9f17,0x4e36,0x4e9f,0x9f10,0x4e5c,0x4e69,0x4e93,
125.1976 +    0x8288,0x5b5b,0x556c,0x560f,0x4ec4,0x538d,0x539d,0x53a3,0x53a5,0x53ae,
125.1977 +    0x9765,0x8d5d,0x531a,0x53f5,0x5326,0x532e,0x533e,0x8d5c,0x5366,0x5363,
125.1978 +    0x5202,0x5208,0x520e,0x522d,0x5233,0x523f,0x5240,0x524c,0x525e,0x5261,
125.1979 +    0x525c,0x84af,0x527d,0x5282,0x5281,0x5290,0x5293,0x5182,0x7f54,0x4ebb,
125.1980 +    0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb,0x4ede,0x4f1b,0x4ef3,0x4f22,
125.1981 +    0x4f64,0x4ef5,0x4f25,0x4f27,0x4f09,0x4f2b,0x4f5e,0x4f67,0x6538,0x4f5a,
125.1982 +    0x4f5d
125.1983 +  },
125.1984 +  {				/* ku 59 */
125.1985 +    0x8cae,0x8caf,0x8cb0,0x8cb1,0x8cb2,0x8cb3,0x8cb4,0x8cb5,0x8cb6,0x8cb7,
125.1986 +    0x8cb8,0x8cb9,0x8cba,0x8cbb,0x8cbc,0x8cbd,0x8cbe,0x8cbf,0x8cc0,0x8cc1,
125.1987 +    0x8cc2,0x8cc3,0x8cc4,0x8cc5,0x8cc6,0x8cc7,0x8cc8,0x8cc9,0x8cca,0x8ccb,
125.1988 +    0x8ccc,0x8ccd,0x8cce,0x8ccf,0x8cd0,0x8cd1,0x8cd2,0x8cd3,0x8cd4,0x8cd5,
125.1989 +    0x8cd6,0x8cd7,0x8cd8,0x8cd9,0x8cda,0x8cdb,0x8cdc,0x8cdd,0x8cde,0x8cdf,
125.1990 +    0x8ce0,0x8ce1,0x8ce2,0x8ce3,0x8ce4,0x8ce5,0x8ce6,0x8ce7,0x8ce8,0x8ce9,
125.1991 +    0x8cea,0x8ceb,0x8cec,UBOGON,0x8ced,0x8cee,0x8cef,0x8cf0,0x8cf1,0x8cf2,
125.1992 +    0x8cf3,0x8cf4,0x8cf5,0x8cf6,0x8cf7,0x8cf8,0x8cf9,0x8cfa,0x8cfb,0x8cfc,
125.1993 +    0x8cfd,0x8cfe,0x8cff,0x8d00,0x8d01,0x8d02,0x8d03,0x8d04,0x8d05,0x8d06,
125.1994 +    0x8d07,0x8d08,0x8d09,0x8d0a,0x8d0b,0x8d0c,0x8d0d,0x4f5f,0x4f57,0x4f32,
125.1995 +    0x4f3d,0x4f76,0x4f74,0x4f91,0x4f89,0x4f83,0x4f8f,0x4f7e,0x4f7b,0x4faa,
125.1996 +    0x4f7c,0x4fac,0x4f94,0x4fe6,0x4fe8,0x4fea,0x4fc5,0x4fda,0x4fe3,0x4fdc,
125.1997 +    0x4fd1,0x4fdf,0x4ff8,0x5029,0x504c,0x4ff3,0x502c,0x500f,0x502e,0x502d,
125.1998 +    0x4ffe,0x501c,0x500c,0x5025,0x5028,0x507e,0x5043,0x5055,0x5048,0x504e,
125.1999 +    0x506c,0x507b,0x50a5,0x50a7,0x50a9,0x50ba,0x50d6,0x5106,0x50ed,0x50ec,
125.2000 +    0x50e6,0x50ee,0x5107,0x510b,0x4edd,0x6c3d,0x4f58,0x4f65,0x4fce,0x9fa0,
125.2001 +    0x6c46,0x7c74,0x516e,0x5dfd,0x9ec9,0x9998,0x5181,0x5914,0x52f9,0x530d,
125.2002 +    0x8a07,0x5310,0x51eb,0x5919,0x5155,0x4ea0,0x5156,0x4eb3,0x886e,0x88a4,
125.2003 +    0x4eb5,0x8114,0x88d2,0x7980,0x5b34,0x8803,0x7fb8,0x51ab,0x51b1,0x51bd,
125.2004 +    0x51bc
125.2005 +  },
125.2006 +  {				/* ku 5a */
125.2007 +    0x8d0e,0x8d0f,0x8d10,0x8d11,0x8d12,0x8d13,0x8d14,0x8d15,0x8d16,0x8d17,
125.2008 +    0x8d18,0x8d19,0x8d1a,0x8d1b,0x8d1c,0x8d20,0x8d51,0x8d52,0x8d57,0x8d5f,
125.2009 +    0x8d65,0x8d68,0x8d69,0x8d6a,0x8d6c,0x8d6e,0x8d6f,0x8d71,0x8d72,0x8d78,
125.2010 +    0x8d79,0x8d7a,0x8d7b,0x8d7c,0x8d7d,0x8d7e,0x8d7f,0x8d80,0x8d82,0x8d83,
125.2011 +    0x8d86,0x8d87,0x8d88,0x8d89,0x8d8c,0x8d8d,0x8d8e,0x8d8f,0x8d90,0x8d92,
125.2012 +    0x8d93,0x8d95,0x8d96,0x8d97,0x8d98,0x8d99,0x8d9a,0x8d9b,0x8d9c,0x8d9d,
125.2013 +    0x8d9e,0x8da0,0x8da1,UBOGON,0x8da2,0x8da4,0x8da5,0x8da6,0x8da7,0x8da8,
125.2014 +    0x8da9,0x8daa,0x8dab,0x8dac,0x8dad,0x8dae,0x8daf,0x8db0,0x8db2,0x8db6,
125.2015 +    0x8db7,0x8db9,0x8dbb,0x8dbd,0x8dc0,0x8dc1,0x8dc2,0x8dc5,0x8dc7,0x8dc8,
125.2016 +    0x8dc9,0x8dca,0x8dcd,0x8dd0,0x8dd2,0x8dd3,0x8dd4,0x51c7,0x5196,0x51a2,
125.2017 +    0x51a5,0x8ba0,0x8ba6,0x8ba7,0x8baa,0x8bb4,0x8bb5,0x8bb7,0x8bc2,0x8bc3,
125.2018 +    0x8bcb,0x8bcf,0x8bce,0x8bd2,0x8bd3,0x8bd4,0x8bd6,0x8bd8,0x8bd9,0x8bdc,
125.2019 +    0x8bdf,0x8be0,0x8be4,0x8be8,0x8be9,0x8bee,0x8bf0,0x8bf3,0x8bf6,0x8bf9,
125.2020 +    0x8bfc,0x8bff,0x8c00,0x8c02,0x8c04,0x8c07,0x8c0c,0x8c0f,0x8c11,0x8c12,
125.2021 +    0x8c14,0x8c15,0x8c16,0x8c19,0x8c1b,0x8c18,0x8c1d,0x8c1f,0x8c20,0x8c21,
125.2022 +    0x8c25,0x8c27,0x8c2a,0x8c2b,0x8c2e,0x8c2f,0x8c32,0x8c33,0x8c35,0x8c36,
125.2023 +    0x5369,0x537a,0x961d,0x9622,0x9621,0x9631,0x962a,0x963d,0x963c,0x9642,
125.2024 +    0x9649,0x9654,0x965f,0x9667,0x966c,0x9672,0x9674,0x9688,0x968d,0x9697,
125.2025 +    0x96b0,0x9097,0x909b,0x909d,0x9099,0x90ac,0x90a1,0x90b4,0x90b3,0x90b6,
125.2026 +    0x90ba
125.2027 +  },
125.2028 +  {				/* ku 5b */
125.2029 +    0x8dd5,0x8dd8,0x8dd9,0x8ddc,0x8de0,0x8de1,0x8de2,0x8de5,0x8de6,0x8de7,
125.2030 +    0x8de9,0x8ded,0x8dee,0x8df0,0x8df1,0x8df2,0x8df4,0x8df6,0x8dfc,0x8dfe,
125.2031 +    0x8dff,0x8e00,0x8e01,0x8e02,0x8e03,0x8e04,0x8e06,0x8e07,0x8e08,0x8e0b,
125.2032 +    0x8e0d,0x8e0e,0x8e10,0x8e11,0x8e12,0x8e13,0x8e15,0x8e16,0x8e17,0x8e18,
125.2033 +    0x8e19,0x8e1a,0x8e1b,0x8e1c,0x8e20,0x8e21,0x8e24,0x8e25,0x8e26,0x8e27,
125.2034 +    0x8e28,0x8e2b,0x8e2d,0x8e30,0x8e32,0x8e33,0x8e34,0x8e36,0x8e37,0x8e38,
125.2035 +    0x8e3b,0x8e3c,0x8e3e,UBOGON,0x8e3f,0x8e43,0x8e45,0x8e46,0x8e4c,0x8e4d,
125.2036 +    0x8e4e,0x8e4f,0x8e50,0x8e53,0x8e54,0x8e55,0x8e56,0x8e57,0x8e58,0x8e5a,
125.2037 +    0x8e5b,0x8e5c,0x8e5d,0x8e5e,0x8e5f,0x8e60,0x8e61,0x8e62,0x8e63,0x8e64,
125.2038 +    0x8e65,0x8e67,0x8e68,0x8e6a,0x8e6b,0x8e6e,0x8e71,0x90b8,0x90b0,0x90cf,
125.2039 +    0x90c5,0x90be,0x90d0,0x90c4,0x90c7,0x90d3,0x90e6,0x90e2,0x90dc,0x90d7,
125.2040 +    0x90db,0x90eb,0x90ef,0x90fe,0x9104,0x9122,0x911e,0x9123,0x9131,0x912f,
125.2041 +    0x9139,0x9143,0x9146,0x520d,0x5942,0x52a2,0x52ac,0x52ad,0x52be,0x54ff,
125.2042 +    0x52d0,0x52d6,0x52f0,0x53df,0x71ee,0x77cd,0x5ef4,0x51f5,0x51fc,0x9b2f,
125.2043 +    0x53b6,0x5f01,0x755a,0x5def,0x574c,0x57a9,0x57a1,0x587e,0x58bc,0x58c5,
125.2044 +    0x58d1,0x5729,0x572c,0x572a,0x5733,0x5739,0x572e,0x572f,0x575c,0x573b,
125.2045 +    0x5742,0x5769,0x5785,0x576b,0x5786,0x577c,0x577b,0x5768,0x576d,0x5776,
125.2046 +    0x5773,0x57ad,0x57a4,0x578c,0x57b2,0x57cf,0x57a7,0x57b4,0x5793,0x57a0,
125.2047 +    0x57d5,0x57d8,0x57da,0x57d9,0x57d2,0x57b8,0x57f4,0x57ef,0x57f8,0x57e4,
125.2048 +    0x57dd
125.2049 +  },
125.2050 +  {				/* ku 5c */
125.2051 +    0x8e73,0x8e75,0x8e77,0x8e78,0x8e79,0x8e7a,0x8e7b,0x8e7d,0x8e7e,0x8e80,
125.2052 +    0x8e82,0x8e83,0x8e84,0x8e86,0x8e88,0x8e89,0x8e8a,0x8e8b,0x8e8c,0x8e8d,
125.2053 +    0x8e8e,0x8e91,0x8e92,0x8e93,0x8e95,0x8e96,0x8e97,0x8e98,0x8e99,0x8e9a,
125.2054 +    0x8e9b,0x8e9d,0x8e9f,0x8ea0,0x8ea1,0x8ea2,0x8ea3,0x8ea4,0x8ea5,0x8ea6,
125.2055 +    0x8ea7,0x8ea8,0x8ea9,0x8eaa,0x8ead,0x8eae,0x8eb0,0x8eb1,0x8eb3,0x8eb4,
125.2056 +    0x8eb5,0x8eb6,0x8eb7,0x8eb8,0x8eb9,0x8ebb,0x8ebc,0x8ebd,0x8ebe,0x8ebf,
125.2057 +    0x8ec0,0x8ec1,0x8ec2,UBOGON,0x8ec3,0x8ec4,0x8ec5,0x8ec6,0x8ec7,0x8ec8,
125.2058 +    0x8ec9,0x8eca,0x8ecb,0x8ecc,0x8ecd,0x8ecf,0x8ed0,0x8ed1,0x8ed2,0x8ed3,
125.2059 +    0x8ed4,0x8ed5,0x8ed6,0x8ed7,0x8ed8,0x8ed9,0x8eda,0x8edb,0x8edc,0x8edd,
125.2060 +    0x8ede,0x8edf,0x8ee0,0x8ee1,0x8ee2,0x8ee3,0x8ee4,0x580b,0x580d,0x57fd,
125.2061 +    0x57ed,0x5800,0x581e,0x5819,0x5844,0x5820,0x5865,0x586c,0x5881,0x5889,
125.2062 +    0x589a,0x5880,0x99a8,0x9f19,0x61ff,0x8279,0x827d,0x827f,0x828f,0x828a,
125.2063 +    0x82a8,0x8284,0x828e,0x8291,0x8297,0x8299,0x82ab,0x82b8,0x82be,0x82b0,
125.2064 +    0x82c8,0x82ca,0x82e3,0x8298,0x82b7,0x82ae,0x82cb,0x82cc,0x82c1,0x82a9,
125.2065 +    0x82b4,0x82a1,0x82aa,0x829f,0x82c4,0x82ce,0x82a4,0x82e1,0x8309,0x82f7,
125.2066 +    0x82e4,0x830f,0x8307,0x82dc,0x82f4,0x82d2,0x82d8,0x830c,0x82fb,0x82d3,
125.2067 +    0x8311,0x831a,0x8306,0x8314,0x8315,0x82e0,0x82d5,0x831c,0x8351,0x835b,
125.2068 +    0x835c,0x8308,0x8392,0x833c,0x8334,0x8331,0x839b,0x835e,0x832f,0x834f,
125.2069 +    0x8347,0x8343,0x835f,0x8340,0x8317,0x8360,0x832d,0x833a,0x8333,0x8366,
125.2070 +    0x8365
125.2071 +  },
125.2072 +  {				/* ku 5d */
125.2073 +    0x8ee5,0x8ee6,0x8ee7,0x8ee8,0x8ee9,0x8eea,0x8eeb,0x8eec,0x8eed,0x8eee,
125.2074 +    0x8eef,0x8ef0,0x8ef1,0x8ef2,0x8ef3,0x8ef4,0x8ef5,0x8ef6,0x8ef7,0x8ef8,
125.2075 +    0x8ef9,0x8efa,0x8efb,0x8efc,0x8efd,0x8efe,0x8eff,0x8f00,0x8f01,0x8f02,
125.2076 +    0x8f03,0x8f04,0x8f05,0x8f06,0x8f07,0x8f08,0x8f09,0x8f0a,0x8f0b,0x8f0c,
125.2077 +    0x8f0d,0x8f0e,0x8f0f,0x8f10,0x8f11,0x8f12,0x8f13,0x8f14,0x8f15,0x8f16,
125.2078 +    0x8f17,0x8f18,0x8f19,0x8f1a,0x8f1b,0x8f1c,0x8f1d,0x8f1e,0x8f1f,0x8f20,
125.2079 +    0x8f21,0x8f22,0x8f23,UBOGON,0x8f24,0x8f25,0x8f26,0x8f27,0x8f28,0x8f29,
125.2080 +    0x8f2a,0x8f2b,0x8f2c,0x8f2d,0x8f2e,0x8f2f,0x8f30,0x8f31,0x8f32,0x8f33,
125.2081 +    0x8f34,0x8f35,0x8f36,0x8f37,0x8f38,0x8f39,0x8f3a,0x8f3b,0x8f3c,0x8f3d,
125.2082 +    0x8f3e,0x8f3f,0x8f40,0x8f41,0x8f42,0x8f43,0x8f44,0x8368,0x831b,0x8369,
125.2083 +    0x836c,0x836a,0x836d,0x836e,0x83b0,0x8378,0x83b3,0x83b4,0x83a0,0x83aa,
125.2084 +    0x8393,0x839c,0x8385,0x837c,0x83b6,0x83a9,0x837d,0x83b8,0x837b,0x8398,
125.2085 +    0x839e,0x83a8,0x83ba,0x83bc,0x83c1,0x8401,0x83e5,0x83d8,0x5807,0x8418,
125.2086 +    0x840b,0x83dd,0x83fd,0x83d6,0x841c,0x8438,0x8411,0x8406,0x83d4,0x83df,
125.2087 +    0x840f,0x8403,0x83f8,0x83f9,0x83ea,0x83c5,0x83c0,0x8426,0x83f0,0x83e1,
125.2088 +    0x845c,0x8451,0x845a,0x8459,0x8473,0x8487,0x8488,0x847a,0x8489,0x8478,
125.2089 +    0x843c,0x8446,0x8469,0x8476,0x848c,0x848e,0x8431,0x846d,0x84c1,0x84cd,
125.2090 +    0x84d0,0x84e6,0x84bd,0x84d3,0x84ca,0x84bf,0x84ba,0x84e0,0x84a1,0x84b9,
125.2091 +    0x84b4,0x8497,0x84e5,0x84e3,0x850c,0x750d,0x8538,0x84f0,0x8539,0x851f,
125.2092 +    0x853a
125.2093 +  },
125.2094 +  {				/* ku 5e */
125.2095 +    0x8f45,0x8f46,0x8f47,0x8f48,0x8f49,0x8f4a,0x8f4b,0x8f4c,0x8f4d,0x8f4e,
125.2096 +    0x8f4f,0x8f50,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f56,0x8f57,0x8f58,
125.2097 +    0x8f59,0x8f5a,0x8f5b,0x8f5c,0x8f5d,0x8f5e,0x8f5f,0x8f60,0x8f61,0x8f62,
125.2098 +    0x8f63,0x8f64,0x8f65,0x8f6a,0x8f80,0x8f8c,0x8f92,0x8f9d,0x8fa0,0x8fa1,
125.2099 +    0x8fa2,0x8fa4,0x8fa5,0x8fa6,0x8fa7,0x8faa,0x8fac,0x8fad,0x8fae,0x8faf,
125.2100 +    0x8fb2,0x8fb3,0x8fb4,0x8fb5,0x8fb7,0x8fb8,0x8fba,0x8fbb,0x8fbc,0x8fbf,
125.2101 +    0x8fc0,0x8fc3,0x8fc6,UBOGON,0x8fc9,0x8fca,0x8fcb,0x8fcc,0x8fcd,0x8fcf,
125.2102 +    0x8fd2,0x8fd6,0x8fd7,0x8fda,0x8fe0,0x8fe1,0x8fe3,0x8fe7,0x8fec,0x8fef,
125.2103 +    0x8ff1,0x8ff2,0x8ff4,0x8ff5,0x8ff6,0x8ffa,0x8ffb,0x8ffc,0x8ffe,0x8fff,
125.2104 +    0x9007,0x9008,0x900c,0x900e,0x9013,0x9015,0x9018,0x8556,0x853b,0x84ff,
125.2105 +    0x84fc,0x8559,0x8548,0x8568,0x8564,0x855e,0x857a,0x77a2,0x8543,0x8572,
125.2106 +    0x857b,0x85a4,0x85a8,0x8587,0x858f,0x8579,0x85ae,0x859c,0x8585,0x85b9,
125.2107 +    0x85b7,0x85b0,0x85d3,0x85c1,0x85dc,0x85ff,0x8627,0x8605,0x8629,0x8616,
125.2108 +    0x863c,0x5efe,0x5f08,0x593c,0x5941,0x8037,0x5955,0x595a,0x5958,0x530f,
125.2109 +    0x5c22,0x5c25,0x5c2c,0x5c34,0x624c,0x626a,0x629f,0x62bb,0x62ca,0x62da,
125.2110 +    0x62d7,0x62ee,0x6322,0x62f6,0x6339,0x634b,0x6343,0x63ad,0x63f6,0x6371,
125.2111 +    0x637a,0x638e,0x63b4,0x636d,0x63ac,0x638a,0x6369,0x63ae,0x63bc,0x63f2,
125.2112 +    0x63f8,0x63e0,0x63ff,0x63c4,0x63de,0x63ce,0x6452,0x63c6,0x63be,0x6445,
125.2113 +    0x6441,0x640b,0x641b,0x6420,0x640c,0x6426,0x6421,0x645e,0x6484,0x646d,
125.2114 +    0x6496
125.2115 +  },
125.2116 +  {				/* ku 5f */
125.2117 +    0x9019,0x901c,0x9023,0x9024,0x9025,0x9027,0x9028,0x9029,0x902a,0x902b,
125.2118 +    0x902c,0x9030,0x9031,0x9032,0x9033,0x9034,0x9037,0x9039,0x903a,0x903d,
125.2119 +    0x903f,0x9040,0x9043,0x9045,0x9046,0x9048,0x9049,0x904a,0x904b,0x904c,
125.2120 +    0x904e,0x9054,0x9055,0x9056,0x9059,0x905a,0x905c,0x905d,0x905e,0x905f,
125.2121 +    0x9060,0x9061,0x9064,0x9066,0x9067,0x9069,0x906a,0x906b,0x906c,0x906f,
125.2122 +    0x9070,0x9071,0x9072,0x9073,0x9076,0x9077,0x9078,0x9079,0x907a,0x907b,
125.2123 +    0x907c,0x907e,0x9081,UBOGON,0x9084,0x9085,0x9086,0x9087,0x9089,0x908a,
125.2124 +    0x908c,0x908d,0x908e,0x908f,0x9090,0x9092,0x9094,0x9096,0x9098,0x909a,
125.2125 +    0x909c,0x909e,0x909f,0x90a0,0x90a4,0x90a5,0x90a7,0x90a8,0x90a9,0x90ab,
125.2126 +    0x90ad,0x90b2,0x90b7,0x90bc,0x90bd,0x90bf,0x90c0,0x647a,0x64b7,0x64b8,
125.2127 +    0x6499,0x64ba,0x64c0,0x64d0,0x64d7,0x64e4,0x64e2,0x6509,0x6525,0x652e,
125.2128 +    0x5f0b,0x5fd2,0x7519,0x5f11,0x535f,0x53f1,0x53fd,0x53e9,0x53e8,0x53fb,
125.2129 +    0x5412,0x5416,0x5406,0x544b,0x5452,0x5453,0x5454,0x5456,0x5443,0x5421,
125.2130 +    0x5457,0x5459,0x5423,0x5432,0x5482,0x5494,0x5477,0x5471,0x5464,0x549a,
125.2131 +    0x549b,0x5484,0x5476,0x5466,0x549d,0x54d0,0x54ad,0x54c2,0x54b4,0x54d2,
125.2132 +    0x54a7,0x54a6,0x54d3,0x54d4,0x5472,0x54a3,0x54d5,0x54bb,0x54bf,0x54cc,
125.2133 +    0x54d9,0x54da,0x54dc,0x54a9,0x54aa,0x54a4,0x54dd,0x54cf,0x54de,0x551b,
125.2134 +    0x54e7,0x5520,0x54fd,0x5514,0x54f3,0x5522,0x5523,0x550f,0x5511,0x5527,
125.2135 +    0x552a,0x5567,0x558f,0x55b5,0x5549,0x556d,0x5541,0x5555,0x553f,0x5550,
125.2136 +    0x553c
125.2137 +  },
125.2138 +  {				/* ku 60 */
125.2139 +    0x90c2,0x90c3,0x90c6,0x90c8,0x90c9,0x90cb,0x90cc,0x90cd,0x90d2,0x90d4,
125.2140 +    0x90d5,0x90d6,0x90d8,0x90d9,0x90da,0x90de,0x90df,0x90e0,0x90e3,0x90e4,
125.2141 +    0x90e5,0x90e9,0x90ea,0x90ec,0x90ee,0x90f0,0x90f1,0x90f2,0x90f3,0x90f5,
125.2142 +    0x90f6,0x90f7,0x90f9,0x90fa,0x90fb,0x90fc,0x90ff,0x9100,0x9101,0x9103,
125.2143 +    0x9105,0x9106,0x9107,0x9108,0x9109,0x910a,0x910b,0x910c,0x910d,0x910e,
125.2144 +    0x910f,0x9110,0x9111,0x9112,0x9113,0x9114,0x9115,0x9116,0x9117,0x9118,
125.2145 +    0x911a,0x911b,0x911c,UBOGON,0x911d,0x911f,0x9120,0x9121,0x9124,0x9125,
125.2146 +    0x9126,0x9127,0x9128,0x9129,0x912a,0x912b,0x912c,0x912d,0x912e,0x9130,
125.2147 +    0x9132,0x9133,0x9134,0x9135,0x9136,0x9137,0x9138,0x913a,0x913b,0x913c,
125.2148 +    0x913d,0x913e,0x913f,0x9140,0x9141,0x9142,0x9144,0x5537,0x5556,0x5575,
125.2149 +    0x5576,0x5577,0x5533,0x5530,0x555c,0x558b,0x55d2,0x5583,0x55b1,0x55b9,
125.2150 +    0x5588,0x5581,0x559f,0x557e,0x55d6,0x5591,0x557b,0x55df,0x55bd,0x55be,
125.2151 +    0x5594,0x5599,0x55ea,0x55f7,0x55c9,0x561f,0x55d1,0x55eb,0x55ec,0x55d4,
125.2152 +    0x55e6,0x55dd,0x55c4,0x55ef,0x55e5,0x55f2,0x55f3,0x55cc,0x55cd,0x55e8,
125.2153 +    0x55f5,0x55e4,0x8f94,0x561e,0x5608,0x560c,0x5601,0x5624,0x5623,0x55fe,
125.2154 +    0x5600,0x5627,0x562d,0x5658,0x5639,0x5657,0x562c,0x564d,0x5662,0x5659,
125.2155 +    0x565c,0x564c,0x5654,0x5686,0x5664,0x5671,0x566b,0x567b,0x567c,0x5685,
125.2156 +    0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1,0x56f5,0x56eb,0x56f9,0x56ff,
125.2157 +    0x5704,0x570a,0x5709,0x571c,0x5e0f,0x5e19,0x5e14,0x5e11,0x5e31,0x5e3b,
125.2158 +    0x5e3c
125.2159 +  },
125.2160 +  {				/* ku 61 */
125.2161 +    0x9145,0x9147,0x9148,0x9151,0x9153,0x9154,0x9155,0x9156,0x9158,0x9159,
125.2162 +    0x915b,0x915c,0x915f,0x9160,0x9166,0x9167,0x9168,0x916b,0x916d,0x9173,
125.2163 +    0x917a,0x917b,0x917c,0x9180,0x9181,0x9182,0x9183,0x9184,0x9186,0x9188,
125.2164 +    0x918a,0x918e,0x918f,0x9193,0x9194,0x9195,0x9196,0x9197,0x9198,0x9199,
125.2165 +    0x919c,0x919d,0x919e,0x919f,0x91a0,0x91a1,0x91a4,0x91a5,0x91a6,0x91a7,
125.2166 +    0x91a8,0x91a9,0x91ab,0x91ac,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6,0x91b7,
125.2167 +    0x91b8,0x91b9,0x91bb,UBOGON,0x91bc,0x91bd,0x91be,0x91bf,0x91c0,0x91c1,
125.2168 +    0x91c2,0x91c3,0x91c4,0x91c5,0x91c6,0x91c8,0x91cb,0x91d0,0x91d2,0x91d3,
125.2169 +    0x91d4,0x91d5,0x91d6,0x91d7,0x91d8,0x91d9,0x91da,0x91db,0x91dd,0x91de,
125.2170 +    0x91df,0x91e0,0x91e1,0x91e2,0x91e3,0x91e4,0x91e5,0x5e37,0x5e44,0x5e54,
125.2171 +    0x5e5b,0x5e5e,0x5e61,0x5c8c,0x5c7a,0x5c8d,0x5c90,0x5c96,0x5c88,0x5c98,
125.2172 +    0x5c99,0x5c91,0x5c9a,0x5c9c,0x5cb5,0x5ca2,0x5cbd,0x5cac,0x5cab,0x5cb1,
125.2173 +    0x5ca3,0x5cc1,0x5cb7,0x5cc4,0x5cd2,0x5ce4,0x5ccb,0x5ce5,0x5d02,0x5d03,
125.2174 +    0x5d27,0x5d26,0x5d2e,0x5d24,0x5d1e,0x5d06,0x5d1b,0x5d58,0x5d3e,0x5d34,
125.2175 +    0x5d3d,0x5d6c,0x5d5b,0x5d6f,0x5d5d,0x5d6b,0x5d4b,0x5d4a,0x5d69,0x5d74,
125.2176 +    0x5d82,0x5d99,0x5d9d,0x8c73,0x5db7,0x5dc5,0x5f73,0x5f77,0x5f82,0x5f87,
125.2177 +    0x5f89,0x5f8c,0x5f95,0x5f99,0x5f9c,0x5fa8,0x5fad,0x5fb5,0x5fbc,0x8862,
125.2178 +    0x5f61,0x72ad,0x72b0,0x72b4,0x72b7,0x72b8,0x72c3,0x72c1,0x72ce,0x72cd,
125.2179 +    0x72d2,0x72e8,0x72ef,0x72e9,0x72f2,0x72f4,0x72f7,0x7301,0x72f3,0x7303,
125.2180 +    0x72fa
125.2181 +  },
125.2182 +  {				/* ku 62 */
125.2183 +    0x91e6,0x91e7,0x91e8,0x91e9,0x91ea,0x91eb,0x91ec,0x91ed,0x91ee,0x91ef,
125.2184 +    0x91f0,0x91f1,0x91f2,0x91f3,0x91f4,0x91f5,0x91f6,0x91f7,0x91f8,0x91f9,
125.2185 +    0x91fa,0x91fb,0x91fc,0x91fd,0x91fe,0x91ff,0x9200,0x9201,0x9202,0x9203,
125.2186 +    0x9204,0x9205,0x9206,0x9207,0x9208,0x9209,0x920a,0x920b,0x920c,0x920d,
125.2187 +    0x920e,0x920f,0x9210,0x9211,0x9212,0x9213,0x9214,0x9215,0x9216,0x9217,
125.2188 +    0x9218,0x9219,0x921a,0x921b,0x921c,0x921d,0x921e,0x921f,0x9220,0x9221,
125.2189 +    0x9222,0x9223,0x9224,UBOGON,0x9225,0x9226,0x9227,0x9228,0x9229,0x922a,
125.2190 +    0x922b,0x922c,0x922d,0x922e,0x922f,0x9230,0x9231,0x9232,0x9233,0x9234,
125.2191 +    0x9235,0x9236,0x9237,0x9238,0x9239,0x923a,0x923b,0x923c,0x923d,0x923e,
125.2192 +    0x923f,0x9240,0x9241,0x9242,0x9243,0x9244,0x9245,0x72fb,0x7317,0x7313,
125.2193 +    0x7321,0x730a,0x731e,0x731d,0x7315,0x7322,0x7339,0x7325,0x732c,0x7338,
125.2194 +    0x7331,0x7350,0x734d,0x7357,0x7360,0x736c,0x736f,0x737e,0x821b,0x5925,
125.2195 +    0x98e7,0x5924,0x5902,0x9963,0x9967,0x9968,0x9969,0x996a,0x996b,0x996c,
125.2196 +    0x9974,0x9977,0x997d,0x9980,0x9984,0x9987,0x998a,0x998d,0x9990,0x9991,
125.2197 +    0x9993,0x9994,0x9995,0x5e80,0x5e91,0x5e8b,0x5e96,0x5ea5,0x5ea0,0x5eb9,
125.2198 +    0x5eb5,0x5ebe,0x5eb3,0x8d53,0x5ed2,0x5ed1,0x5edb,0x5ee8,0x5eea,0x81ba,
125.2199 +    0x5fc4,0x5fc9,0x5fd6,0x5fcf,0x6003,0x5fee,0x6004,0x5fe1,0x5fe4,0x5ffe,
125.2200 +    0x6005,0x6006,0x5fea,0x5fed,0x5ff8,0x6019,0x6035,0x6026,0x601b,0x600f,
125.2201 +    0x600d,0x6029,0x602b,0x600a,0x603f,0x6021,0x6078,0x6079,0x607b,0x607a,
125.2202 +    0x6042
125.2203 +  },
125.2204 +  {				/* ku 63 */
125.2205 +    0x9246,0x9247,0x9248,0x9249,0x924a,0x924b,0x924c,0x924d,0x924e,0x924f,
125.2206 +    0x9250,0x9251,0x9252,0x9253,0x9254,0x9255,0x9256,0x9257,0x9258,0x9259,
125.2207 +    0x925a,0x925b,0x925c,0x925d,0x925e,0x925f,0x9260,0x9261,0x9262,0x9263,
125.2208 +    0x9264,0x9265,0x9266,0x9267,0x9268,0x9269,0x926a,0x926b,0x926c,0x926d,
125.2209 +    0x926e,0x926f,0x9270,0x9271,0x9272,0x9273,0x9275,0x9276,0x9277,0x9278,
125.2210 +    0x9279,0x927a,0x927b,0x927c,0x927d,0x927e,0x927f,0x9280,0x9281,0x9282,
125.2211 +    0x9283,0x9284,0x9285,UBOGON,0x9286,0x9287,0x9288,0x9289,0x928a,0x928b,
125.2212 +    0x928c,0x928d,0x928f,0x9290,0x9291,0x9292,0x9293,0x9294,0x9295,0x9296,
125.2213 +    0x9297,0x9298,0x9299,0x929a,0x929b,0x929c,0x929d,0x929e,0x929f,0x92a0,
125.2214 +    0x92a1,0x92a2,0x92a3,0x92a4,0x92a5,0x92a6,0x92a7,0x606a,0x607d,0x6096,
125.2215 +    0x609a,0x60ad,0x609d,0x6083,0x6092,0x608c,0x609b,0x60ec,0x60bb,0x60b1,
125.2216 +    0x60dd,0x60d8,0x60c6,0x60da,0x60b4,0x6120,0x6126,0x6115,0x6123,0x60f4,
125.2217 +    0x6100,0x610e,0x612b,0x614a,0x6175,0x61ac,0x6194,0x61a7,0x61b7,0x61d4,
125.2218 +    0x61f5,0x5fdd,0x96b3,0x95e9,0x95eb,0x95f1,0x95f3,0x95f5,0x95f6,0x95fc,
125.2219 +    0x95fe,0x9603,0x9604,0x9606,0x9608,0x960a,0x960b,0x960c,0x960d,0x960f,
125.2220 +    0x9612,0x9615,0x9616,0x9617,0x9619,0x961a,0x4e2c,0x723f,0x6215,0x6c35,
125.2221 +    0x6c54,0x6c5c,0x6c4a,0x6ca3,0x6c85,0x6c90,0x6c94,0x6c8c,0x6c68,0x6c69,
125.2222 +    0x6c74,0x6c76,0x6c86,0x6ca9,0x6cd0,0x6cd4,0x6cad,0x6cf7,0x6cf8,0x6cf1,
125.2223 +    0x6cd7,0x6cb2,0x6ce0,0x6cd6,0x6cfa,0x6ceb,0x6cee,0x6cb1,0x6cd3,0x6cef,
125.2224 +    0x6cfe
125.2225 +  },
125.2226 +  {				/* ku 64 */
125.2227 +    0x92a8,0x92a9,0x92aa,0x92ab,0x92ac,0x92ad,0x92af,0x92b0,0x92b1,0x92b2,
125.2228 +    0x92b3,0x92b4,0x92b5,0x92b6,0x92b7,0x92b8,0x92b9,0x92ba,0x92bb,0x92bc,
125.2229 +    0x92bd,0x92be,0x92bf,0x92c0,0x92c1,0x92c2,0x92c3,0x92c4,0x92c5,0x92c6,
125.2230 +    0x92c7,0x92c9,0x92ca,0x92cb,0x92cc,0x92cd,0x92ce,0x92cf,0x92d0,0x92d1,
125.2231 +    0x92d2,0x92d3,0x92d4,0x92d5,0x92d6,0x92d7,0x92d8,0x92d9,0x92da,0x92db,
125.2232 +    0x92dc,0x92dd,0x92de,0x92df,0x92e0,0x92e1,0x92e2,0x92e3,0x92e4,0x92e5,
125.2233 +    0x92e6,0x92e7,0x92e8,UBOGON,0x92e9,0x92ea,0x92eb,0x92ec,0x92ed,0x92ee,
125.2234 +    0x92ef,0x92f0,0x92f1,0x92f2,0x92f3,0x92f4,0x92f5,0x92f6,0x92f7,0x92f8,
125.2235 +    0x92f9,0x92fa,0x92fb,0x92fc,0x92fd,0x92fe,0x92ff,0x9300,0x9301,0x9302,
125.2236 +    0x9303,0x9304,0x9305,0x9306,0x9307,0x9308,0x9309,0x6d39,0x6d27,0x6d0c,
125.2237 +    0x6d43,0x6d48,0x6d07,0x6d04,0x6d19,0x6d0e,0x6d2b,0x6d4d,0x6d2e,0x6d35,
125.2238 +    0x6d1a,0x6d4f,0x6d52,0x6d54,0x6d33,0x6d91,0x6d6f,0x6d9e,0x6da0,0x6d5e,
125.2239 +    0x6d93,0x6d94,0x6d5c,0x6d60,0x6d7c,0x6d63,0x6e1a,0x6dc7,0x6dc5,0x6dde,
125.2240 +    0x6e0e,0x6dbf,0x6de0,0x6e11,0x6de6,0x6ddd,0x6dd9,0x6e16,0x6dab,0x6e0c,
125.2241 +    0x6dae,0x6e2b,0x6e6e,0x6e4e,0x6e6b,0x6eb2,0x6e5f,0x6e86,0x6e53,0x6e54,
125.2242 +    0x6e32,0x6e25,0x6e44,0x6edf,0x6eb1,0x6e98,0x6ee0,0x6f2d,0x6ee2,0x6ea5,
125.2243 +    0x6ea7,0x6ebd,0x6ebb,0x6eb7,0x6ed7,0x6eb4,0x6ecf,0x6e8f,0x6ec2,0x6e9f,
125.2244 +    0x6f62,0x6f46,0x6f47,0x6f24,0x6f15,0x6ef9,0x6f2f,0x6f36,0x6f4b,0x6f74,
125.2245 +    0x6f2a,0x6f09,0x6f29,0x6f89,0x6f8d,0x6f8c,0x6f78,0x6f72,0x6f7c,0x6f7a,
125.2246 +    0x6fd1
125.2247 +  },
125.2248 +  {				/* ku 65 */
125.2249 +    0x930a,0x930b,0x930c,0x930d,0x930e,0x930f,0x9310,0x9311,0x9312,0x9313,
125.2250 +    0x9314,0x9315,0x9316,0x9317,0x9318,0x9319,0x931a,0x931b,0x931c,0x931d,
125.2251 +    0x931e,0x931f,0x9320,0x9321,0x9322,0x9323,0x9324,0x9325,0x9326,0x9327,
125.2252 +    0x9328,0x9329,0x932a,0x932b,0x932c,0x932d,0x932e,0x932f,0x9330,0x9331,
125.2253 +    0x9332,0x9333,0x9334,0x9335,0x9336,0x9337,0x9338,0x9339,0x933a,0x933b,
125.2254 +    0x933c,0x933d,0x933f,0x9340,0x9341,0x9342,0x9343,0x9344,0x9345,0x9346,
125.2255 +    0x9347,0x9348,0x9349,UBOGON,0x934a,0x934b,0x934c,0x934d,0x934e,0x934f,
125.2256 +    0x9350,0x9351,0x9352,0x9353,0x9354,0x9355,0x9356,0x9357,0x9358,0x9359,
125.2257 +    0x935a,0x935b,0x935c,0x935d,0x935e,0x935f,0x9360,0x9361,0x9362,0x9363,
125.2258 +    0x9364,0x9365,0x9366,0x9367,0x9368,0x9369,0x936b,0x6fc9,0x6fa7,0x6fb9,
125.2259 +    0x6fb6,0x6fc2,0x6fe1,0x6fee,0x6fde,0x6fe0,0x6fef,0x701a,0x7023,0x701b,
125.2260 +    0x7039,0x7035,0x704f,0x705e,0x5b80,0x5b84,0x5b95,0x5b93,0x5ba5,0x5bb8,
125.2261 +    0x752f,0x9a9e,0x6434,0x5be4,0x5bee,0x8930,0x5bf0,0x8e47,0x8b07,0x8fb6,
125.2262 +    0x8fd3,0x8fd5,0x8fe5,0x8fee,0x8fe4,0x8fe9,0x8fe6,0x8ff3,0x8fe8,0x9005,
125.2263 +    0x9004,0x900b,0x9026,0x9011,0x900d,0x9016,0x9021,0x9035,0x9036,0x902d,
125.2264 +    0x902f,0x9044,0x9051,0x9052,0x9050,0x9068,0x9058,0x9062,0x905b,0x66b9,
125.2265 +    0x9074,0x907d,0x9082,0x9088,0x9083,0x908b,0x5f50,0x5f57,0x5f56,0x5f58,
125.2266 +    0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63,0x5c66,0x7fbc,0x5f2a,0x5f29,
125.2267 +    0x5f2d,0x8274,0x5f3c,0x9b3b,0x5c6e,0x5981,0x5983,0x598d,0x59a9,0x59aa,
125.2268 +    0x59a3
125.2269 +  },
125.2270 +  {				/* ku 66 */
125.2271 +    0x936c,0x936d,0x936e,0x936f,0x9370,0x9371,0x9372,0x9373,0x9374,0x9375,
125.2272 +    0x9376,0x9377,0x9378,0x9379,0x937a,0x937b,0x937c,0x937d,0x937e,0x937f,
125.2273 +    0x9380,0x9381,0x9382,0x9383,0x9384,0x9385,0x9386,0x9387,0x9388,0x9389,
125.2274 +    0x938a,0x938b,0x938c,0x938d,0x938e,0x9390,0x9391,0x9392,0x9393,0x9394,
125.2275 +    0x9395,0x9396,0x9397,0x9398,0x9399,0x939a,0x939b,0x939c,0x939d,0x939e,
125.2276 +    0x939f,0x93a0,0x93a1,0x93a2,0x93a3,0x93a4,0x93a5,0x93a6,0x93a7,0x93a8,
125.2277 +    0x93a9,0x93aa,0x93ab,UBOGON,0x93ac,0x93ad,0x93ae,0x93af,0x93b0,0x93b1,
125.2278 +    0x93b2,0x93b3,0x93b4,0x93b5,0x93b6,0x93b7,0x93b8,0x93b9,0x93ba,0x93bb,
125.2279 +    0x93bc,0x93bd,0x93be,0x93bf,0x93c0,0x93c1,0x93c2,0x93c3,0x93c4,0x93c5,
125.2280 +    0x93c6,0x93c7,0x93c8,0x93c9,0x93cb,0x93cc,0x93cd,0x5997,0x59ca,0x59ab,
125.2281 +    0x599e,0x59a4,0x59d2,0x59b2,0x59af,0x59d7,0x59be,0x5a05,0x5a06,0x59dd,
125.2282 +    0x5a08,0x59e3,0x59d8,0x59f9,0x5a0c,0x5a09,0x5a32,0x5a34,0x5a11,0x5a23,
125.2283 +    0x5a13,0x5a40,0x5a67,0x5a4a,0x5a55,0x5a3c,0x5a62,0x5a75,0x80ec,0x5aaa,
125.2284 +    0x5a9b,0x5a77,0x5a7a,0x5abe,0x5aeb,0x5ab2,0x5ad2,0x5ad4,0x5ab8,0x5ae0,
125.2285 +    0x5ae3,0x5af1,0x5ad6,0x5ae6,0x5ad8,0x5adc,0x5b09,0x5b17,0x5b16,0x5b32,
125.2286 +    0x5b37,0x5b40,0x5c15,0x5c1c,0x5b5a,0x5b65,0x5b73,0x5b51,0x5b53,0x5b62,
125.2287 +    0x9a75,0x9a77,0x9a78,0x9a7a,0x9a7f,0x9a7d,0x9a80,0x9a81,0x9a85,0x9a88,
125.2288 +    0x9a8a,0x9a90,0x9a92,0x9a93,0x9a96,0x9a98,0x9a9b,0x9a9c,0x9a9d,0x9a9f,
125.2289 +    0x9aa0,0x9aa2,0x9aa3,0x9aa5,0x9aa7,0x7e9f,0x7ea1,0x7ea3,0x7ea5,0x7ea8,
125.2290 +    0x7ea9
125.2291 +  },
125.2292 +  {				/* ku 67 */
125.2293 +    0x93ce,0x93cf,0x93d0,0x93d1,0x93d2,0x93d3,0x93d4,0x93d5,0x93d7,0x93d8,
125.2294 +    0x93d9,0x93da,0x93db,0x93dc,0x93dd,0x93de,0x93df,0x93e0,0x93e1,0x93e2,
125.2295 +    0x93e3,0x93e4,0x93e5,0x93e6,0x93e7,0x93e8,0x93e9,0x93ea,0x93eb,0x93ec,
125.2296 +    0x93ed,0x93ee,0x93ef,0x93f0,0x93f1,0x93f2,0x93f3,0x93f4,0x93f5,0x93f6,
125.2297 +    0x93f7,0x93f8,0x93f9,0x93fa,0x93fb,0x93fc,0x93fd,0x93fe,0x93ff,0x9400,
125.2298 +    0x9401,0x9402,0x9403,0x9404,0x9405,0x9406,0x9407,0x9408,0x9409,0x940a,
125.2299 +    0x940b,0x940c,0x940d,UBOGON,0x940e,0x940f,0x9410,0x9411,0x9412,0x9413,
125.2300 +    0x9414,0x9415,0x9416,0x9417,0x9418,0x9419,0x941a,0x941b,0x941c,0x941d,
125.2301 +    0x941e,0x941f,0x9420,0x9421,0x9422,0x9423,0x9424,0x9425,0x9426,0x9427,
125.2302 +    0x9428,0x9429,0x942a,0x942b,0x942c,0x942d,0x942e,0x7ead,0x7eb0,0x7ebe,
125.2303 +    0x7ec0,0x7ec1,0x7ec2,0x7ec9,0x7ecb,0x7ecc,0x7ed0,0x7ed4,0x7ed7,0x7edb,
125.2304 +    0x7ee0,0x7ee1,0x7ee8,0x7eeb,0x7eee,0x7eef,0x7ef1,0x7ef2,0x7f0d,0x7ef6,
125.2305 +    0x7efa,0x7efb,0x7efe,0x7f01,0x7f02,0x7f03,0x7f07,0x7f08,0x7f0b,0x7f0c,
125.2306 +    0x7f0f,0x7f11,0x7f12,0x7f17,0x7f19,0x7f1c,0x7f1b,0x7f1f,0x7f21,0x7f22,
125.2307 +    0x7f23,0x7f24,0x7f25,0x7f26,0x7f27,0x7f2a,0x7f2b,0x7f2c,0x7f2d,0x7f2f,
125.2308 +    0x7f30,0x7f31,0x7f32,0x7f33,0x7f35,0x5e7a,0x757f,0x5ddb,0x753e,0x9095,
125.2309 +    0x738e,0x7391,0x73ae,0x73a2,0x739f,0x73cf,0x73c2,0x73d1,0x73b7,0x73b3,
125.2310 +    0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x987c,0x740a,0x73e9,0x73e7,0x73de,
125.2311 +    0x73ba,0x73f2,0x740f,0x742a,0x745b,0x7426,0x7425,0x7428,0x7430,0x742e,
125.2312 +    0x742c
125.2313 +  },
125.2314 +  {				/* ku 68 */
125.2315 +    0x942f,0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436,0x9437,0x9438,
125.2316 +    0x9439,0x943a,0x943b,0x943c,0x943d,0x943f,0x9440,0x9441,0x9442,0x9443,
125.2317 +    0x9444,0x9445,0x9446,0x9447,0x9448,0x9449,0x944a,0x944b,0x944c,0x944d,
125.2318 +    0x944e,0x944f,0x9450,0x9451,0x9452,0x9453,0x9454,0x9455,0x9456,0x9457,
125.2319 +    0x9458,0x9459,0x945a,0x945b,0x945c,0x945d,0x945e,0x945f,0x9460,0x9461,
125.2320 +    0x9462,0x9463,0x9464,0x9465,0x9466,0x9467,0x9468,0x9469,0x946a,0x946c,
125.2321 +    0x946d,0x946e,0x946f,UBOGON,0x9470,0x9471,0x9472,0x9473,0x9474,0x9475,
125.2322 +    0x9476,0x9477,0x9478,0x9479,0x947a,0x947b,0x947c,0x947d,0x947e,0x947f,
125.2323 +    0x9480,0x9481,0x9482,0x9483,0x9484,0x9491,0x9496,0x9498,0x94c7,0x94cf,
125.2324 +    0x94d3,0x94d4,0x94da,0x94e6,0x94fb,0x951c,0x9520,0x741b,0x741a,0x7441,
125.2325 +    0x745c,0x7457,0x7455,0x7459,0x7477,0x746d,0x747e,0x749c,0x748e,0x7480,
125.2326 +    0x7481,0x7487,0x748b,0x749e,0x74a8,0x74a9,0x7490,0x74a7,0x74d2,0x74ba,
125.2327 +    0x97ea,0x97eb,0x97ec,0x674c,0x6753,0x675e,0x6748,0x6769,0x67a5,0x6787,
125.2328 +    0x676a,0x6773,0x6798,0x67a7,0x6775,0x67a8,0x679e,0x67ad,0x678b,0x6777,
125.2329 +    0x677c,0x67f0,0x6809,0x67d8,0x680a,0x67e9,0x67b0,0x680c,0x67d9,0x67b5,
125.2330 +    0x67da,0x67b3,0x67dd,0x6800,0x67c3,0x67b8,0x67e2,0x680e,0x67c1,0x67fd,
125.2331 +    0x6832,0x6833,0x6860,0x6861,0x684e,0x6862,0x6844,0x6864,0x6883,0x681d,
125.2332 +    0x6855,0x6866,0x6841,0x6867,0x6840,0x683e,0x684a,0x6849,0x6829,0x68b5,
125.2333 +    0x688f,0x6874,0x6877,0x6893,0x686b,0x68c2,0x696e,0x68fc,0x691f,0x6920,
125.2334 +    0x68f9
125.2335 +  },
125.2336 +  {				/* ku 69 */
125.2337 +    0x9527,0x9533,0x953d,0x9543,0x9548,0x954b,0x9555,0x955a,0x9560,0x956e,
125.2338 +    0x9574,0x9575,0x9577,0x9578,0x9579,0x957a,0x957b,0x957c,0x957d,0x957e,
125.2339 +    0x9580,0x9581,0x9582,0x9583,0x9584,0x9585,0x9586,0x9587,0x9588,0x9589,
125.2340 +    0x958a,0x958b,0x958c,0x958d,0x958e,0x958f,0x9590,0x9591,0x9592,0x9593,
125.2341 +    0x9594,0x9595,0x9596,0x9597,0x9598,0x9599,0x959a,0x959b,0x959c,0x959d,
125.2342 +    0x959e,0x959f,0x95a0,0x95a1,0x95a2,0x95a3,0x95a4,0x95a5,0x95a6,0x95a7,
125.2343 +    0x95a8,0x95a9,0x95aa,UBOGON,0x95ab,0x95ac,0x95ad,0x95ae,0x95af,0x95b0,
125.2344 +    0x95b1,0x95b2,0x95b3,0x95b4,0x95b5,0x95b6,0x95b7,0x95b8,0x95b9,0x95ba,
125.2345 +    0x95bb,0x95bc,0x95bd,0x95be,0x95bf,0x95c0,0x95c1,0x95c2,0x95c3,0x95c4,
125.2346 +    0x95c5,0x95c6,0x95c7,0x95c8,0x95c9,0x95ca,0x95cb,0x6924,0x68f0,0x690b,
125.2347 +    0x6901,0x6957,0x68e3,0x6910,0x6971,0x6939,0x6960,0x6942,0x695d,0x6984,
125.2348 +    0x696b,0x6980,0x6998,0x6978,0x6934,0x69cc,0x6987,0x6988,0x69ce,0x6989,
125.2349 +    0x6966,0x6963,0x6979,0x699b,0x69a7,0x69bb,0x69ab,0x69ad,0x69d4,0x69b1,
125.2350 +    0x69c1,0x69ca,0x69df,0x6995,0x69e0,0x698d,0x69ff,0x6a2f,0x69ed,0x6a17,
125.2351 +    0x6a18,0x6a65,0x69f2,0x6a44,0x6a3e,0x6aa0,0x6a50,0x6a5b,0x6a35,0x6a8e,
125.2352 +    0x6a79,0x6a3d,0x6a28,0x6a58,0x6a7c,0x6a91,0x6a90,0x6aa9,0x6a97,0x6aab,
125.2353 +    0x7337,0x7352,0x6b81,0x6b82,0x6b87,0x6b84,0x6b92,0x6b93,0x6b8d,0x6b9a,
125.2354 +    0x6b9b,0x6ba1,0x6baa,0x8f6b,0x8f6d,0x8f71,0x8f72,0x8f73,0x8f75,0x8f76,
125.2355 +    0x8f78,0x8f77,0x8f79,0x8f7a,0x8f7c,0x8f7e,0x8f81,0x8f82,0x8f84,0x8f87,
125.2356 +    0x8f8b
125.2357 +  },
125.2358 +  {				/* ku 6a */
125.2359 +    0x95cc,0x95cd,0x95ce,0x95cf,0x95d0,0x95d1,0x95d2,0x95d3,0x95d4,0x95d5,
125.2360 +    0x95d6,0x95d7,0x95d8,0x95d9,0x95da,0x95db,0x95dc,0x95dd,0x95de,0x95df,
125.2361 +    0x95e0,0x95e1,0x95e2,0x95e3,0x95e4,0x95e5,0x95e6,0x95e7,0x95ec,0x95ff,
125.2362 +    0x9607,0x9613,0x9618,0x961b,0x961e,0x9620,0x9623,0x9624,0x9625,0x9626,
125.2363 +    0x9627,0x9628,0x9629,0x962b,0x962c,0x962d,0x962f,0x9630,0x9637,0x9638,
125.2364 +    0x9639,0x963a,0x963e,0x9641,0x9643,0x964a,0x964e,0x964f,0x9651,0x9652,
125.2365 +    0x9653,0x9656,0x9657,UBOGON,0x9658,0x9659,0x965a,0x965c,0x965d,0x965e,
125.2366 +    0x9660,0x9663,0x9665,0x9666,0x966b,0x966d,0x966e,0x966f,0x9670,0x9671,
125.2367 +    0x9673,0x9678,0x9679,0x967a,0x967b,0x967c,0x967d,0x967e,0x967f,0x9680,
125.2368 +    0x9681,0x9682,0x9683,0x9684,0x9687,0x9689,0x968a,0x8f8d,0x8f8e,0x8f8f,
125.2369 +    0x8f98,0x8f9a,0x8ece,0x620b,0x6217,0x621b,0x621f,0x6222,0x6221,0x6225,
125.2370 +    0x6224,0x622c,0x81e7,0x74ef,0x74f4,0x74ff,0x750f,0x7511,0x7513,0x6534,
125.2371 +    0x65ee,0x65ef,0x65f0,0x660a,0x6619,0x6772,0x6603,0x6615,0x6600,0x7085,
125.2372 +    0x66f7,0x661d,0x6634,0x6631,0x6636,0x6635,0x8006,0x665f,0x6654,0x6641,
125.2373 +    0x664f,0x6656,0x6661,0x6657,0x6677,0x6684,0x668c,0x66a7,0x669d,0x66be,
125.2374 +    0x66db,0x66dc,0x66e6,0x66e9,0x8d32,0x8d33,0x8d36,0x8d3b,0x8d3d,0x8d40,
125.2375 +    0x8d45,0x8d46,0x8d48,0x8d49,0x8d47,0x8d4d,0x8d55,0x8d59,0x89c7,0x89ca,
125.2376 +    0x89cb,0x89cc,0x89ce,0x89cf,0x89d0,0x89d1,0x726e,0x729f,0x725d,0x7266,
125.2377 +    0x726f,0x727e,0x727f,0x7284,0x728b,0x728d,0x728f,0x7292,0x6308,0x6332,
125.2378 +    0x63b0
125.2379 +  },
125.2380 +  {				/* ku 6b */
125.2381 +    0x968c,0x968e,0x9691,0x9692,0x9693,0x9695,0x9696,0x969a,0x969b,0x969d,
125.2382 +    0x969e,0x969f,0x96a0,0x96a1,0x96a2,0x96a3,0x96a4,0x96a5,0x96a6,0x96a8,
125.2383 +    0x96a9,0x96aa,0x96ab,0x96ac,0x96ad,0x96ae,0x96af,0x96b1,0x96b2,0x96b4,
125.2384 +    0x96b5,0x96b7,0x96b8,0x96ba,0x96bb,0x96bf,0x96c2,0x96c3,0x96c8,0x96ca,
125.2385 +    0x96cb,0x96d0,0x96d1,0x96d3,0x96d4,0x96d6,0x96d7,0x96d8,0x96d9,0x96da,
125.2386 +    0x96db,0x96dc,0x96dd,0x96de,0x96df,0x96e1,0x96e2,0x96e3,0x96e4,0x96e5,
125.2387 +    0x96e6,0x96e7,0x96eb,UBOGON,0x96ec,0x96ed,0x96ee,0x96f0,0x96f1,0x96f2,
125.2388 +    0x96f4,0x96f5,0x96f8,0x96fa,0x96fb,0x96fc,0x96fd,0x96ff,0x9702,0x9703,
125.2389 +    0x9705,0x970a,0x970b,0x970c,0x9710,0x9711,0x9712,0x9714,0x9715,0x9717,
125.2390 +    0x9718,0x9719,0x971a,0x971b,0x971d,0x971f,0x9720,0x643f,0x64d8,0x8004,
125.2391 +    0x6bea,0x6bf3,0x6bfd,0x6bf5,0x6bf9,0x6c05,0x6c07,0x6c06,0x6c0d,0x6c15,
125.2392 +    0x6c18,0x6c19,0x6c1a,0x6c21,0x6c29,0x6c24,0x6c2a,0x6c32,0x6535,0x6555,
125.2393 +    0x656b,0x724d,0x7252,0x7256,0x7230,0x8662,0x5216,0x809f,0x809c,0x8093,
125.2394 +    0x80bc,0x670a,0x80bd,0x80b1,0x80ab,0x80ad,0x80b4,0x80b7,0x80e7,0x80e8,
125.2395 +    0x80e9,0x80ea,0x80db,0x80c2,0x80c4,0x80d9,0x80cd,0x80d7,0x6710,0x80dd,
125.2396 +    0x80eb,0x80f1,0x80f4,0x80ed,0x810d,0x810e,0x80f2,0x80fc,0x6715,0x8112,
125.2397 +    0x8c5a,0x8136,0x811e,0x812c,0x8118,0x8132,0x8148,0x814c,0x8153,0x8174,
125.2398 +    0x8159,0x815a,0x8171,0x8160,0x8169,0x817c,0x817d,0x816d,0x8167,0x584d,
125.2399 +    0x5ab5,0x8188,0x8182,0x8191,0x6ed5,0x81a3,0x81aa,0x81cc,0x6726,0x81ca,
125.2400 +    0x81bb
125.2401 +  },
125.2402 +  {				/* ku 6c */
125.2403 +    0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,0x9728,0x9729,0x972b,
125.2404 +    0x972c,0x972e,0x972f,0x9731,0x9733,0x9734,0x9735,0x9736,0x9737,0x973a,
125.2405 +    0x973b,0x973c,0x973d,0x973f,0x9740,0x9741,0x9742,0x9743,0x9744,0x9745,
125.2406 +    0x9746,0x9747,0x9748,0x9749,0x974a,0x974b,0x974c,0x974d,0x974e,0x974f,
125.2407 +    0x9750,0x9751,0x9754,0x9755,0x9757,0x9758,0x975a,0x975c,0x975d,0x975f,
125.2408 +    0x9763,0x9764,0x9766,0x9767,0x9768,0x976a,0x976b,0x976c,0x976d,0x976e,
125.2409 +    0x976f,0x9770,0x9771,UBOGON,0x9772,0x9775,0x9777,0x9778,0x9779,0x977a,
125.2410 +    0x977b,0x977d,0x977e,0x977f,0x9780,0x9781,0x9782,0x9783,0x9784,0x9786,
125.2411 +    0x9787,0x9788,0x9789,0x978a,0x978c,0x978e,0x978f,0x9790,0x9793,0x9795,
125.2412 +    0x9796,0x9797,0x9799,0x979a,0x979b,0x979c,0x979d,0x81c1,0x81a6,0x6b24,
125.2413 +    0x6b37,0x6b39,0x6b43,0x6b46,0x6b59,0x98d1,0x98d2,0x98d3,0x98d5,0x98d9,
125.2414 +    0x98da,0x6bb3,0x5f40,0x6bc2,0x89f3,0x6590,0x9f51,0x6593,0x65bc,0x65c6,
125.2415 +    0x65c4,0x65c3,0x65cc,0x65ce,0x65d2,0x65d6,0x7080,0x709c,0x7096,0x709d,
125.2416 +    0x70bb,0x70c0,0x70b7,0x70ab,0x70b1,0x70e8,0x70ca,0x7110,0x7113,0x7116,
125.2417 +    0x712f,0x7131,0x7173,0x715c,0x7168,0x7145,0x7172,0x714a,0x7178,0x717a,
125.2418 +    0x7198,0x71b3,0x71b5,0x71a8,0x71a0,0x71e0,0x71d4,0x71e7,0x71f9,0x721d,
125.2419 +    0x7228,0x706c,0x7118,0x7166,0x71b9,0x623e,0x623d,0x6243,0x6248,0x6249,
125.2420 +    0x793b,0x7940,0x7946,0x7949,0x795b,0x795c,0x7953,0x795a,0x7962,0x7957,
125.2421 +    0x7960,0x796f,0x7967,0x797a,0x7985,0x798a,0x799a,0x79a7,0x79b3,0x5fd1,
125.2422 +    0x5fd0
125.2423 +  },
125.2424 +  {				/* ku 6d */
125.2425 +    0x979e,0x979f,0x97a1,0x97a2,0x97a4,0x97a5,0x97a6,0x97a7,0x97a8,0x97a9,
125.2426 +    0x97aa,0x97ac,0x97ae,0x97b0,0x97b1,0x97b3,0x97b5,0x97b6,0x97b7,0x97b8,
125.2427 +    0x97b9,0x97ba,0x97bb,0x97bc,0x97bd,0x97be,0x97bf,0x97c0,0x97c1,0x97c2,
125.2428 +    0x97c3,0x97c4,0x97c5,0x97c6,0x97c7,0x97c8,0x97c9,0x97ca,0x97cb,0x97cc,
125.2429 +    0x97cd,0x97ce,0x97cf,0x97d0,0x97d1,0x97d2,0x97d3,0x97d4,0x97d5,0x97d6,
125.2430 +    0x97d7,0x97d8,0x97d9,0x97da,0x97db,0x97dc,0x97dd,0x97de,0x97df,0x97e0,
125.2431 +    0x97e1,0x97e2,0x97e3,UBOGON,0x97e4,0x97e5,0x97e8,0x97ee,0x97ef,0x97f0,
125.2432 +    0x97f1,0x97f2,0x97f4,0x97f7,0x97f8,0x97f9,0x97fa,0x97fb,0x97fc,0x97fd,
125.2433 +    0x97fe,0x97ff,0x9800,0x9801,0x9802,0x9803,0x9804,0x9805,0x9806,0x9807,
125.2434 +    0x9808,0x9809,0x980a,0x980b,0x980c,0x980d,0x980e,0x603c,0x605d,0x605a,
125.2435 +    0x6067,0x6041,0x6059,0x6063,0x60ab,0x6106,0x610d,0x615d,0x61a9,0x619d,
125.2436 +    0x61cb,0x61d1,0x6206,0x8080,0x807f,0x6c93,0x6cf6,0x6dfc,0x77f6,0x77f8,
125.2437 +    0x7800,0x7809,0x7817,0x7818,0x7811,0x65ab,0x782d,0x781c,0x781d,0x7839,
125.2438 +    0x783a,0x783b,0x781f,0x783c,0x7825,0x782c,0x7823,0x7829,0x784e,0x786d,
125.2439 +    0x7856,0x7857,0x7826,0x7850,0x7847,0x784c,0x786a,0x789b,0x7893,0x789a,
125.2440 +    0x7887,0x789c,0x78a1,0x78a3,0x78b2,0x78b9,0x78a5,0x78d4,0x78d9,0x78c9,
125.2441 +    0x78ec,0x78f2,0x7905,0x78f4,0x7913,0x7924,0x791e,0x7934,0x9f9b,0x9ef9,
125.2442 +    0x9efb,0x9efc,0x76f1,0x7704,0x770d,0x76f9,0x7707,0x7708,0x771a,0x7722,
125.2443 +    0x7719,0x772d,0x7726,0x7735,0x7738,0x7750,0x7751,0x7747,0x7743,0x775a,
125.2444 +    0x7768
125.2445 +  },
125.2446 +  {				/* ku 6e */
125.2447 +    0x980f,0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816,0x9817,0x9818,
125.2448 +    0x9819,0x981a,0x981b,0x981c,0x981d,0x981e,0x981f,0x9820,0x9821,0x9822,
125.2449 +    0x9823,0x9824,0x9825,0x9826,0x9827,0x9828,0x9829,0x982a,0x982b,0x982c,
125.2450 +    0x982d,0x982e,0x982f,0x9830,0x9831,0x9832,0x9833,0x9834,0x9835,0x9836,
125.2451 +    0x9837,0x9838,0x9839,0x983a,0x983b,0x983c,0x983d,0x983e,0x983f,0x9840,
125.2452 +    0x9841,0x9842,0x9843,0x9844,0x9845,0x9846,0x9847,0x9848,0x9849,0x984a,
125.2453 +    0x984b,0x984c,0x984d,UBOGON,0x984e,0x984f,0x9850,0x9851,0x9852,0x9853,
125.2454 +    0x9854,0x9855,0x9856,0x9857,0x9858,0x9859,0x985a,0x985b,0x985c,0x985d,
125.2455 +    0x985e,0x985f,0x9860,0x9861,0x9862,0x9863,0x9864,0x9865,0x9866,0x9867,
125.2456 +    0x9868,0x9869,0x986a,0x986b,0x986c,0x986d,0x986e,0x7762,0x7765,0x777f,
125.2457 +    0x778d,0x777d,0x7780,0x778c,0x7791,0x779f,0x77a0,0x77b0,0x77b5,0x77bd,
125.2458 +    0x753a,0x7540,0x754e,0x754b,0x7548,0x755b,0x7572,0x7579,0x7583,0x7f58,
125.2459 +    0x7f61,0x7f5f,0x8a48,0x7f68,0x7f74,0x7f71,0x7f79,0x7f81,0x7f7e,0x76cd,
125.2460 +    0x76e5,0x8832,0x9485,0x9486,0x9487,0x948b,0x948a,0x948c,0x948d,0x948f,
125.2461 +    0x9490,0x9494,0x9497,0x9495,0x949a,0x949b,0x949c,0x94a3,0x94a4,0x94ab,
125.2462 +    0x94aa,0x94ad,0x94ac,0x94af,0x94b0,0x94b2,0x94b4,0x94b6,0x94b7,0x94b8,
125.2463 +    0x94b9,0x94ba,0x94bc,0x94bd,0x94bf,0x94c4,0x94c8,0x94c9,0x94ca,0x94cb,
125.2464 +    0x94cc,0x94cd,0x94ce,0x94d0,0x94d1,0x94d2,0x94d5,0x94d6,0x94d7,0x94d9,
125.2465 +    0x94d8,0x94db,0x94de,0x94df,0x94e0,0x94e2,0x94e4,0x94e5,0x94e7,0x94e8,
125.2466 +    0x94ea
125.2467 +  },
125.2468 +  {				/* ku 6f */
125.2469 +    0x986f,0x9870,0x9871,0x9872,0x9873,0x9874,0x988b,0x988e,0x9892,0x9895,
125.2470 +    0x9899,0x98a3,0x98a8,0x98a9,0x98aa,0x98ab,0x98ac,0x98ad,0x98ae,0x98af,
125.2471 +    0x98b0,0x98b1,0x98b2,0x98b3,0x98b4,0x98b5,0x98b6,0x98b7,0x98b8,0x98b9,
125.2472 +    0x98ba,0x98bb,0x98bc,0x98bd,0x98be,0x98bf,0x98c0,0x98c1,0x98c2,0x98c3,
125.2473 +    0x98c4,0x98c5,0x98c6,0x98c7,0x98c8,0x98c9,0x98ca,0x98cb,0x98cc,0x98cd,
125.2474 +    0x98cf,0x98d0,0x98d4,0x98d6,0x98d7,0x98db,0x98dc,0x98dd,0x98e0,0x98e1,
125.2475 +    0x98e2,0x98e3,0x98e4,UBOGON,0x98e5,0x98e6,0x98e9,0x98ea,0x98eb,0x98ec,
125.2476 +    0x98ed,0x98ee,0x98ef,0x98f0,0x98f1,0x98f2,0x98f3,0x98f4,0x98f5,0x98f6,
125.2477 +    0x98f7,0x98f8,0x98f9,0x98fa,0x98fb,0x98fc,0x98fd,0x98fe,0x98ff,0x9900,
125.2478 +    0x9901,0x9902,0x9903,0x9904,0x9905,0x9906,0x9907,0x94e9,0x94eb,0x94ee,
125.2479 +    0x94ef,0x94f3,0x94f4,0x94f5,0x94f7,0x94f9,0x94fc,0x94fd,0x94ff,0x9503,
125.2480 +    0x9502,0x9506,0x9507,0x9509,0x950a,0x950d,0x950e,0x950f,0x9512,0x9513,
125.2481 +    0x9514,0x9515,0x9516,0x9518,0x951b,0x951d,0x951e,0x951f,0x9522,0x952a,
125.2482 +    0x952b,0x9529,0x952c,0x9531,0x9532,0x9534,0x9536,0x9537,0x9538,0x953c,
125.2483 +    0x953e,0x953f,0x9542,0x9535,0x9544,0x9545,0x9546,0x9549,0x954c,0x954e,
125.2484 +    0x954f,0x9552,0x9553,0x9554,0x9556,0x9557,0x9558,0x9559,0x955b,0x955e,
125.2485 +    0x955f,0x955d,0x9561,0x9562,0x9564,0x9565,0x9566,0x9567,0x9568,0x9569,
125.2486 +    0x956a,0x956b,0x956c,0x956f,0x9571,0x9572,0x9573,0x953a,0x77e7,0x77ec,
125.2487 +    0x96c9,0x79d5,0x79ed,0x79e3,0x79eb,0x7a06,0x5d47,0x7a03,0x7a02,0x7a1e,
125.2488 +    0x7a14
125.2489 +  },
125.2490 +  {				/* ku 70 */
125.2491 +    0x9908,0x9909,0x990a,0x990b,0x990c,0x990e,0x990f,0x9911,0x9912,0x9913,
125.2492 +    0x9914,0x9915,0x9916,0x9917,0x9918,0x9919,0x991a,0x991b,0x991c,0x991d,
125.2493 +    0x991e,0x991f,0x9920,0x9921,0x9922,0x9923,0x9924,0x9925,0x9926,0x9927,
125.2494 +    0x9928,0x9929,0x992a,0x992b,0x992c,0x992d,0x992f,0x9930,0x9931,0x9932,
125.2495 +    0x9933,0x9934,0x9935,0x9936,0x9937,0x9938,0x9939,0x993a,0x993b,0x993c,
125.2496 +    0x993d,0x993e,0x993f,0x9940,0x9941,0x9942,0x9943,0x9944,0x9945,0x9946,
125.2497 +    0x9947,0x9948,0x9949,UBOGON,0x994a,0x994b,0x994c,0x994d,0x994e,0x994f,
125.2498 +    0x9950,0x9951,0x9952,0x9953,0x9956,0x9957,0x9958,0x9959,0x995a,0x995b,
125.2499 +    0x995c,0x995d,0x995e,0x995f,0x9960,0x9961,0x9962,0x9964,0x9966,0x9973,
125.2500 +    0x9978,0x9979,0x997b,0x997e,0x9982,0x9983,0x9989,0x7a39,0x7a37,0x7a51,
125.2501 +    0x9ecf,0x99a5,0x7a70,0x7688,0x768e,0x7693,0x7699,0x76a4,0x74de,0x74e0,
125.2502 +    0x752c,0x9e20,0x9e22,0x9e28,0x9e29,0x9e2a,0x9e2b,0x9e2c,0x9e32,0x9e31,
125.2503 +    0x9e36,0x9e38,0x9e37,0x9e39,0x9e3a,0x9e3e,0x9e41,0x9e42,0x9e44,0x9e46,
125.2504 +    0x9e47,0x9e48,0x9e49,0x9e4b,0x9e4c,0x9e4e,0x9e51,0x9e55,0x9e57,0x9e5a,
125.2505 +    0x9e5b,0x9e5c,0x9e5e,0x9e63,0x9e66,0x9e67,0x9e68,0x9e69,0x9e6a,0x9e6b,
125.2506 +    0x9e6c,0x9e71,0x9e6d,0x9e73,0x7592,0x7594,0x7596,0x75a0,0x759d,0x75ac,
125.2507 +    0x75a3,0x75b3,0x75b4,0x75b8,0x75c4,0x75b1,0x75b0,0x75c3,0x75c2,0x75d6,
125.2508 +    0x75cd,0x75e3,0x75e8,0x75e6,0x75e4,0x75eb,0x75e7,0x7603,0x75f1,0x75fc,
125.2509 +    0x75ff,0x7610,0x7600,0x7605,0x760c,0x7617,0x760a,0x7625,0x7618,0x7615,
125.2510 +    0x7619
125.2511 +  },
125.2512 +  {				/* ku 71 */
125.2513 +    0x998c,0x998e,0x999a,0x999b,0x999c,0x999d,0x999e,0x999f,0x99a0,0x99a1,
125.2514 +    0x99a2,0x99a3,0x99a4,0x99a6,0x99a7,0x99a9,0x99aa,0x99ab,0x99ac,0x99ad,
125.2515 +    0x99ae,0x99af,0x99b0,0x99b1,0x99b2,0x99b3,0x99b4,0x99b5,0x99b6,0x99b7,
125.2516 +    0x99b8,0x99b9,0x99ba,0x99bb,0x99bc,0x99bd,0x99be,0x99bf,0x99c0,0x99c1,
125.2517 +    0x99c2,0x99c3,0x99c4,0x99c5,0x99c6,0x99c7,0x99c8,0x99c9,0x99ca,0x99cb,
125.2518 +    0x99cc,0x99cd,0x99ce,0x99cf,0x99d0,0x99d1,0x99d2,0x99d3,0x99d4,0x99d5,
125.2519 +    0x99d6,0x99d7,0x99d8,UBOGON,0x99d9,0x99da,0x99db,0x99dc,0x99dd,0x99de,
125.2520 +    0x99df,0x99e0,0x99e1,0x99e2,0x99e3,0x99e4,0x99e5,0x99e6,0x99e7,0x99e8,
125.2521 +    0x99e9,0x99ea,0x99eb,0x99ec,0x99ed,0x99ee,0x99ef,0x99f0,0x99f1,0x99f2,
125.2522 +    0x99f3,0x99f4,0x99f5,0x99f6,0x99f7,0x99f8,0x99f9,0x761b,0x763c,0x7622,
125.2523 +    0x7620,0x7640,0x762d,0x7630,0x763f,0x7635,0x7643,0x763e,0x7633,0x764d,
125.2524 +    0x765e,0x7654,0x765c,0x7656,0x766b,0x766f,0x7fca,0x7ae6,0x7a78,0x7a79,
125.2525 +    0x7a80,0x7a86,0x7a88,0x7a95,0x7aa6,0x7aa0,0x7aac,0x7aa8,0x7aad,0x7ab3,
125.2526 +    0x8864,0x8869,0x8872,0x887d,0x887f,0x8882,0x88a2,0x88c6,0x88b7,0x88bc,
125.2527 +    0x88c9,0x88e2,0x88ce,0x88e3,0x88e5,0x88f1,0x891a,0x88fc,0x88e8,0x88fe,
125.2528 +    0x88f0,0x8921,0x8919,0x8913,0x891b,0x890a,0x8934,0x892b,0x8936,0x8941,
125.2529 +    0x8966,0x897b,0x758b,0x80e5,0x76b2,0x76b4,0x77dc,0x8012,0x8014,0x8016,
125.2530 +    0x801c,0x8020,0x8022,0x8025,0x8026,0x8027,0x8029,0x8028,0x8031,0x800b,
125.2531 +    0x8035,0x8043,0x8046,0x804d,0x8052,0x8069,0x8071,0x8983,0x9878,0x9880,
125.2532 +    0x9883
125.2533 +  },
125.2534 +  {				/* ku 72 */
125.2535 +    0x99fa,0x99fb,0x99fc,0x99fd,0x99fe,0x99ff,0x9a00,0x9a01,0x9a02,0x9a03,
125.2536 +    0x9a04,0x9a05,0x9a06,0x9a07,0x9a08,0x9a09,0x9a0a,0x9a0b,0x9a0c,0x9a0d,
125.2537 +    0x9a0e,0x9a0f,0x9a10,0x9a11,0x9a12,0x9a13,0x9a14,0x9a15,0x9a16,0x9a17,
125.2538 +    0x9a18,0x9a19,0x9a1a,0x9a1b,0x9a1c,0x9a1d,0x9a1e,0x9a1f,0x9a20,0x9a21,
125.2539 +    0x9a22,0x9a23,0x9a24,0x9a25,0x9a26,0x9a27,0x9a28,0x9a29,0x9a2a,0x9a2b,
125.2540 +    0x9a2c,0x9a2d,0x9a2e,0x9a2f,0x9a30,0x9a31,0x9a32,0x9a33,0x9a34,0x9a35,
125.2541 +    0x9a36,0x9a37,0x9a38,UBOGON,0x9a39,0x9a3a,0x9a3b,0x9a3c,0x9a3d,0x9a3e,
125.2542 +    0x9a3f,0x9a40,0x9a41,0x9a42,0x9a43,0x9a44,0x9a45,0x9a46,0x9a47,0x9a48,
125.2543 +    0x9a49,0x9a4a,0x9a4b,0x9a4c,0x9a4d,0x9a4e,0x9a4f,0x9a50,0x9a51,0x9a52,
125.2544 +    0x9a53,0x9a54,0x9a55,0x9a56,0x9a57,0x9a58,0x9a59,0x9889,0x988c,0x988d,
125.2545 +    0x988f,0x9894,0x989a,0x989b,0x989e,0x989f,0x98a1,0x98a2,0x98a5,0x98a6,
125.2546 +    0x864d,0x8654,0x866c,0x866e,0x867f,0x867a,0x867c,0x867b,0x86a8,0x868d,
125.2547 +    0x868b,0x86ac,0x869d,0x86a7,0x86a3,0x86aa,0x8693,0x86a9,0x86b6,0x86c4,
125.2548 +    0x86b5,0x86ce,0x86b0,0x86ba,0x86b1,0x86af,0x86c9,0x86cf,0x86b4,0x86e9,
125.2549 +    0x86f1,0x86f2,0x86ed,0x86f3,0x86d0,0x8713,0x86de,0x86f4,0x86df,0x86d8,
125.2550 +    0x86d1,0x8703,0x8707,0x86f8,0x8708,0x870a,0x870d,0x8709,0x8723,0x873b,
125.2551 +    0x871e,0x8725,0x872e,0x871a,0x873e,0x8748,0x8734,0x8731,0x8729,0x8737,
125.2552 +    0x873f,0x8782,0x8722,0x877d,0x877e,0x877b,0x8760,0x8770,0x874c,0x876e,
125.2553 +    0x878b,0x8753,0x8763,0x877c,0x8764,0x8759,0x8765,0x8793,0x87af,0x87a8,
125.2554 +    0x87d2
125.2555 +  },
125.2556 +  {				/* ku 73 */
125.2557 +    0x9a5a,0x9a5b,0x9a5c,0x9a5d,0x9a5e,0x9a5f,0x9a60,0x9a61,0x9a62,0x9a63,
125.2558 +    0x9a64,0x9a65,0x9a66,0x9a67,0x9a68,0x9a69,0x9a6a,0x9a6b,0x9a72,0x9a83,
125.2559 +    0x9a89,0x9a8d,0x9a8e,0x9a94,0x9a95,0x9a99,0x9aa6,0x9aa9,0x9aaa,0x9aab,
125.2560 +    0x9aac,0x9aad,0x9aae,0x9aaf,0x9ab2,0x9ab3,0x9ab4,0x9ab5,0x9ab9,0x9abb,
125.2561 +    0x9abd,0x9abe,0x9abf,0x9ac3,0x9ac4,0x9ac6,0x9ac7,0x9ac8,0x9ac9,0x9aca,
125.2562 +    0x9acd,0x9ace,0x9acf,0x9ad0,0x9ad2,0x9ad4,0x9ad5,0x9ad6,0x9ad7,0x9ad9,
125.2563 +    0x9ada,0x9adb,0x9adc,UBOGON,0x9add,0x9ade,0x9ae0,0x9ae2,0x9ae3,0x9ae4,
125.2564 +    0x9ae5,0x9ae7,0x9ae8,0x9ae9,0x9aea,0x9aec,0x9aee,0x9af0,0x9af1,0x9af2,
125.2565 +    0x9af3,0x9af4,0x9af5,0x9af6,0x9af7,0x9af8,0x9afa,0x9afc,0x9afd,0x9afe,
125.2566 +    0x9aff,0x9b00,0x9b01,0x9b02,0x9b04,0x9b05,0x9b06,0x87c6,0x8788,0x8785,
125.2567 +    0x87ad,0x8797,0x8783,0x87ab,0x87e5,0x87ac,0x87b5,0x87b3,0x87cb,0x87d3,
125.2568 +    0x87bd,0x87d1,0x87c0,0x87ca,0x87db,0x87ea,0x87e0,0x87ee,0x8816,0x8813,
125.2569 +    0x87fe,0x880a,0x881b,0x8821,0x8839,0x883c,0x7f36,0x7f42,0x7f44,0x7f45,
125.2570 +    0x8210,0x7afa,0x7afd,0x7b08,0x7b03,0x7b04,0x7b15,0x7b0a,0x7b2b,0x7b0f,
125.2571 +    0x7b47,0x7b38,0x7b2a,0x7b19,0x7b2e,0x7b31,0x7b20,0x7b25,0x7b24,0x7b33,
125.2572 +    0x7b3e,0x7b1e,0x7b58,0x7b5a,0x7b45,0x7b75,0x7b4c,0x7b5d,0x7b60,0x7b6e,
125.2573 +    0x7b7b,0x7b62,0x7b72,0x7b71,0x7b90,0x7ba6,0x7ba7,0x7bb8,0x7bac,0x7b9d,
125.2574 +    0x7ba8,0x7b85,0x7baa,0x7b9c,0x7ba2,0x7bab,0x7bb4,0x7bd1,0x7bc1,0x7bcc,
125.2575 +    0x7bdd,0x7bda,0x7be5,0x7be6,0x7bea,0x7c0c,0x7bfe,0x7bfc,0x7c0f,0x7c16,
125.2576 +    0x7c0b
125.2577 +  },
125.2578 +  {				/* ku 74 */
125.2579 +    0x9b07,0x9b09,0x9b0a,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b11,0x9b12,
125.2580 +    0x9b14,0x9b15,0x9b16,0x9b17,0x9b18,0x9b19,0x9b1a,0x9b1b,0x9b1c,0x9b1d,
125.2581 +    0x9b1e,0x9b20,0x9b21,0x9b22,0x9b24,0x9b25,0x9b26,0x9b27,0x9b28,0x9b29,
125.2582 +    0x9b2a,0x9b2b,0x9b2c,0x9b2d,0x9b2e,0x9b30,0x9b31,0x9b33,0x9b34,0x9b35,
125.2583 +    0x9b36,0x9b37,0x9b38,0x9b39,0x9b3a,0x9b3d,0x9b3e,0x9b3f,0x9b40,0x9b46,
125.2584 +    0x9b4a,0x9b4b,0x9b4c,0x9b4e,0x9b50,0x9b52,0x9b53,0x9b55,0x9b56,0x9b57,
125.2585 +    0x9b58,0x9b59,0x9b5a,UBOGON,0x9b5b,0x9b5c,0x9b5d,0x9b5e,0x9b5f,0x9b60,
125.2586 +    0x9b61,0x9b62,0x9b63,0x9b64,0x9b65,0x9b66,0x9b67,0x9b68,0x9b69,0x9b6a,
125.2587 +    0x9b6b,0x9b6c,0x9b6d,0x9b6e,0x9b6f,0x9b70,0x9b71,0x9b72,0x9b73,0x9b74,
125.2588 +    0x9b75,0x9b76,0x9b77,0x9b78,0x9b79,0x9b7a,0x9b7b,0x7c1f,0x7c2a,0x7c26,
125.2589 +    0x7c38,0x7c41,0x7c40,0x81fe,0x8201,0x8202,0x8204,0x81ec,0x8844,0x8221,
125.2590 +    0x8222,0x8223,0x822d,0x822f,0x8228,0x822b,0x8238,0x823b,0x8233,0x8234,
125.2591 +    0x823e,0x8244,0x8249,0x824b,0x824f,0x825a,0x825f,0x8268,0x887e,0x8885,
125.2592 +    0x8888,0x88d8,0x88df,0x895e,0x7f9d,0x7f9f,0x7fa7,0x7faf,0x7fb0,0x7fb2,
125.2593 +    0x7c7c,0x6549,0x7c91,0x7c9d,0x7c9c,0x7c9e,0x7ca2,0x7cb2,0x7cbc,0x7cbd,
125.2594 +    0x7cc1,0x7cc7,0x7ccc,0x7ccd,0x7cc8,0x7cc5,0x7cd7,0x7ce8,0x826e,0x66a8,
125.2595 +    0x7fbf,0x7fce,0x7fd5,0x7fe5,0x7fe1,0x7fe6,0x7fe9,0x7fee,0x7ff3,0x7cf8,
125.2596 +    0x7d77,0x7da6,0x7dae,0x7e47,0x7e9b,0x9eb8,0x9eb4,0x8d73,0x8d84,0x8d94,
125.2597 +    0x8d91,0x8db1,0x8d67,0x8d6d,0x8c47,0x8c49,0x914a,0x9150,0x914e,0x914f,
125.2598 +    0x9164
125.2599 +  },
125.2600 +  {				/* ku 75 */
125.2601 +    0x9b7c,0x9b7d,0x9b7e,0x9b7f,0x9b80,0x9b81,0x9b82,0x9b83,0x9b84,0x9b85,
125.2602 +    0x9b86,0x9b87,0x9b88,0x9b89,0x9b8a,0x9b8b,0x9b8c,0x9b8d,0x9b8e,0x9b8f,
125.2603 +    0x9b90,0x9b91,0x9b92,0x9b93,0x9b94,0x9b95,0x9b96,0x9b97,0x9b98,0x9b99,
125.2604 +    0x9b9a,0x9b9b,0x9b9c,0x9b9d,0x9b9e,0x9b9f,0x9ba0,0x9ba1,0x9ba2,0x9ba3,
125.2605 +    0x9ba4,0x9ba5,0x9ba6,0x9ba7,0x9ba8,0x9ba9,0x9baa,0x9bab,0x9bac,0x9bad,
125.2606 +    0x9bae,0x9baf,0x9bb0,0x9bb1,0x9bb2,0x9bb3,0x9bb4,0x9bb5,0x9bb6,0x9bb7,
125.2607 +    0x9bb8,0x9bb9,0x9bba,UBOGON,0x9bbb,0x9bbc,0x9bbd,0x9bbe,0x9bbf,0x9bc0,
125.2608 +    0x9bc1,0x9bc2,0x9bc3,0x9bc4,0x9bc5,0x9bc6,0x9bc7,0x9bc8,0x9bc9,0x9bca,
125.2609 +    0x9bcb,0x9bcc,0x9bcd,0x9bce,0x9bcf,0x9bd0,0x9bd1,0x9bd2,0x9bd3,0x9bd4,
125.2610 +    0x9bd5,0x9bd6,0x9bd7,0x9bd8,0x9bd9,0x9bda,0x9bdb,0x9162,0x9161,0x9170,
125.2611 +    0x9169,0x916f,0x917d,0x917e,0x9172,0x9174,0x9179,0x918c,0x9185,0x9190,
125.2612 +    0x918d,0x9191,0x91a2,0x91a3,0x91aa,0x91ad,0x91ae,0x91af,0x91b5,0x91b4,
125.2613 +    0x91ba,0x8c55,0x9e7e,0x8db8,0x8deb,0x8e05,0x8e59,0x8e69,0x8db5,0x8dbf,
125.2614 +    0x8dbc,0x8dba,0x8dc4,0x8dd6,0x8dd7,0x8dda,0x8dde,0x8dce,0x8dcf,0x8ddb,
125.2615 +    0x8dc6,0x8dec,0x8df7,0x8df8,0x8de3,0x8df9,0x8dfb,0x8de4,0x8e09,0x8dfd,
125.2616 +    0x8e14,0x8e1d,0x8e1f,0x8e2c,0x8e2e,0x8e23,0x8e2f,0x8e3a,0x8e40,0x8e39,
125.2617 +    0x8e35,0x8e3d,0x8e31,0x8e49,0x8e41,0x8e42,0x8e51,0x8e52,0x8e4a,0x8e70,
125.2618 +    0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8e8f,0x8e94,0x8e90,0x8e9c,0x8e9e,
125.2619 +    0x8c78,0x8c82,0x8c8a,0x8c85,0x8c98,0x8c94,0x659b,0x89d6,0x89de,0x89da,
125.2620 +    0x89dc
125.2621 +  },
125.2622 +  {				/* ku 76 */
125.2623 +    0x9bdc,0x9bdd,0x9bde,0x9bdf,0x9be0,0x9be1,0x9be2,0x9be3,0x9be4,0x9be5,
125.2624 +    0x9be6,0x9be7,0x9be8,0x9be9,0x9bea,0x9beb,0x9bec,0x9bed,0x9bee,0x9bef,
125.2625 +    0x9bf0,0x9bf1,0x9bf2,0x9bf3,0x9bf4,0x9bf5,0x9bf6,0x9bf7,0x9bf8,0x9bf9,
125.2626 +    0x9bfa,0x9bfb,0x9bfc,0x9bfd,0x9bfe,0x9bff,0x9c00,0x9c01,0x9c02,0x9c03,
125.2627 +    0x9c04,0x9c05,0x9c06,0x9c07,0x9c08,0x9c09,0x9c0a,0x9c0b,0x9c0c,0x9c0d,
125.2628 +    0x9c0e,0x9c0f,0x9c10,0x9c11,0x9c12,0x9c13,0x9c14,0x9c15,0x9c16,0x9c17,
125.2629 +    0x9c18,0x9c19,0x9c1a,UBOGON,0x9c1b,0x9c1c,0x9c1d,0x9c1e,0x9c1f,0x9c20,
125.2630 +    0x9c21,0x9c22,0x9c23,0x9c24,0x9c25,0x9c26,0x9c27,0x9c28,0x9c29,0x9c2a,
125.2631 +    0x9c2b,0x9c2c,0x9c2d,0x9c2e,0x9c2f,0x9c30,0x9c31,0x9c32,0x9c33,0x9c34,
125.2632 +    0x9c35,0x9c36,0x9c37,0x9c38,0x9c39,0x9c3a,0x9c3b,0x89e5,0x89eb,0x89ef,
125.2633 +    0x8a3e,0x8b26,0x9753,0x96e9,0x96f3,0x96ef,0x9706,0x9701,0x9708,0x970f,
125.2634 +    0x970e,0x972a,0x972d,0x9730,0x973e,0x9f80,0x9f83,0x9f85,0x9f86,0x9f87,
125.2635 +    0x9f88,0x9f89,0x9f8a,0x9f8c,0x9efe,0x9f0b,0x9f0d,0x96b9,0x96bc,0x96bd,
125.2636 +    0x96ce,0x96d2,0x77bf,0x96e0,0x928e,0x92ae,0x92c8,0x933e,0x936a,0x93ca,
125.2637 +    0x938f,0x943e,0x946b,0x9c7f,0x9c82,0x9c85,0x9c86,0x9c87,0x9c88,0x7a23,
125.2638 +    0x9c8b,0x9c8e,0x9c90,0x9c91,0x9c92,0x9c94,0x9c95,0x9c9a,0x9c9b,0x9c9e,
125.2639 +    0x9c9f,0x9ca0,0x9ca1,0x9ca2,0x9ca3,0x9ca5,0x9ca6,0x9ca7,0x9ca8,0x9ca9,
125.2640 +    0x9cab,0x9cad,0x9cae,0x9cb0,0x9cb1,0x9cb2,0x9cb3,0x9cb4,0x9cb5,0x9cb6,
125.2641 +    0x9cb7,0x9cba,0x9cbb,0x9cbc,0x9cbd,0x9cc4,0x9cc5,0x9cc6,0x9cc7,0x9cca,
125.2642 +    0x9ccb
125.2643 +  },
125.2644 +  {				/* ku 77 */
125.2645 +    0x9c3c,0x9c3d,0x9c3e,0x9c3f,0x9c40,0x9c41,0x9c42,0x9c43,0x9c44,0x9c45,
125.2646 +    0x9c46,0x9c47,0x9c48,0x9c49,0x9c4a,0x9c4b,0x9c4c,0x9c4d,0x9c4e,0x9c4f,
125.2647 +    0x9c50,0x9c51,0x9c52,0x9c53,0x9c54,0x9c55,0x9c56,0x9c57,0x9c58,0x9c59,
125.2648 +    0x9c5a,0x9c5b,0x9c5c,0x9c5d,0x9c5e,0x9c5f,0x9c60,0x9c61,0x9c62,0x9c63,
125.2649 +    0x9c64,0x9c65,0x9c66,0x9c67,0x9c68,0x9c69,0x9c6a,0x9c6b,0x9c6c,0x9c6d,
125.2650 +    0x9c6e,0x9c6f,0x9c70,0x9c71,0x9c72,0x9c73,0x9c74,0x9c75,0x9c76,0x9c77,
125.2651 +    0x9c78,0x9c79,0x9c7a,UBOGON,0x9c7b,0x9c7d,0x9c7e,0x9c80,0x9c83,0x9c84,
125.2652 +    0x9c89,0x9c8a,0x9c8c,0x9c8f,0x9c93,0x9c96,0x9c97,0x9c98,0x9c99,0x9c9d,
125.2653 +    0x9caa,0x9cac,0x9caf,0x9cb9,0x9cbe,0x9cbf,0x9cc0,0x9cc1,0x9cc2,0x9cc8,
125.2654 +    0x9cc9,0x9cd1,0x9cd2,0x9cda,0x9cdb,0x9ce0,0x9ce1,0x9ccc,0x9ccd,0x9cce,
125.2655 +    0x9ccf,0x9cd0,0x9cd3,0x9cd4,0x9cd5,0x9cd7,0x9cd8,0x9cd9,0x9cdc,0x9cdd,
125.2656 +    0x9cdf,0x9ce2,0x977c,0x9785,0x9791,0x9792,0x9794,0x97af,0x97ab,0x97a3,
125.2657 +    0x97b2,0x97b4,0x9ab1,0x9ab0,0x9ab7,0x9e58,0x9ab6,0x9aba,0x9abc,0x9ac1,
125.2658 +    0x9ac0,0x9ac5,0x9ac2,0x9acb,0x9acc,0x9ad1,0x9b45,0x9b43,0x9b47,0x9b49,
125.2659 +    0x9b48,0x9b4d,0x9b51,0x98e8,0x990d,0x992e,0x9955,0x9954,0x9adf,0x9ae1,
125.2660 +    0x9ae6,0x9aef,0x9aeb,0x9afb,0x9aed,0x9af9,0x9b08,0x9b0f,0x9b13,0x9b1f,
125.2661 +    0x9b23,0x9ebd,0x9ebe,0x7e3b,0x9e82,0x9e87,0x9e88,0x9e8b,0x9e92,0x93d6,
125.2662 +    0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0,0x9edf,0x9ee2,0x9ee9,0x9ee7,
125.2663 +    0x9ee5,0x9eea,0x9eef,0x9f22,0x9f2c,0x9f2f,0x9f39,0x9f37,0x9f3d,0x9f3e,
125.2664 +    0x9f44
125.2665 +  },
125.2666 +  {				/* ku 78 */
125.2667 +    0x9ce3,0x9ce4,0x9ce5,0x9ce6,0x9ce7,0x9ce8,0x9ce9,0x9cea,0x9ceb,0x9cec,
125.2668 +    0x9ced,0x9cee,0x9cef,0x9cf0,0x9cf1,0x9cf2,0x9cf3,0x9cf4,0x9cf5,0x9cf6,
125.2669 +    0x9cf7,0x9cf8,0x9cf9,0x9cfa,0x9cfb,0x9cfc,0x9cfd,0x9cfe,0x9cff,0x9d00,
125.2670 +    0x9d01,0x9d02,0x9d03,0x9d04,0x9d05,0x9d06,0x9d07,0x9d08,0x9d09,0x9d0a,
125.2671 +    0x9d0b,0x9d0c,0x9d0d,0x9d0e,0x9d0f,0x9d10,0x9d11,0x9d12,0x9d13,0x9d14,
125.2672 +    0x9d15,0x9d16,0x9d17,0x9d18,0x9d19,0x9d1a,0x9d1b,0x9d1c,0x9d1d,0x9d1e,
125.2673 +    0x9d1f,0x9d20,0x9d21,UBOGON,0x9d22,0x9d23,0x9d24,0x9d25,0x9d26,0x9d27,
125.2674 +    0x9d28,0x9d29,0x9d2a,0x9d2b,0x9d2c,0x9d2d,0x9d2e,0x9d2f,0x9d30,0x9d31,
125.2675 +    0x9d32,0x9d33,0x9d34,0x9d35,0x9d36,0x9d37,0x9d38,0x9d39,0x9d3a,0x9d3b,
125.2676 +    0x9d3c,0x9d3d,0x9d3e,0x9d3f,0x9d40,0x9d41,0x9d42,UBOGON,UBOGON,UBOGON,
125.2677 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2678 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2679 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2680 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2681 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2682 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2683 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2684 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2685 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2686 +    UBOGON
125.2687 +  },
125.2688 +  {				/* ku 79 */
125.2689 +    0x9d43,0x9d44,0x9d45,0x9d46,0x9d47,0x9d48,0x9d49,0x9d4a,0x9d4b,0x9d4c,
125.2690 +    0x9d4d,0x9d4e,0x9d4f,0x9d50,0x9d51,0x9d52,0x9d53,0x9d54,0x9d55,0x9d56,
125.2691 +    0x9d57,0x9d58,0x9d59,0x9d5a,0x9d5b,0x9d5c,0x9d5d,0x9d5e,0x9d5f,0x9d60,
125.2692 +    0x9d61,0x9d62,0x9d63,0x9d64,0x9d65,0x9d66,0x9d67,0x9d68,0x9d69,0x9d6a,
125.2693 +    0x9d6b,0x9d6c,0x9d6d,0x9d6e,0x9d6f,0x9d70,0x9d71,0x9d72,0x9d73,0x9d74,
125.2694 +    0x9d75,0x9d76,0x9d77,0x9d78,0x9d79,0x9d7a,0x9d7b,0x9d7c,0x9d7d,0x9d7e,
125.2695 +    0x9d7f,0x9d80,0x9d81,UBOGON,0x9d82,0x9d83,0x9d84,0x9d85,0x9d86,0x9d87,
125.2696 +    0x9d88,0x9d89,0x9d8a,0x9d8b,0x9d8c,0x9d8d,0x9d8e,0x9d8f,0x9d90,0x9d91,
125.2697 +    0x9d92,0x9d93,0x9d94,0x9d95,0x9d96,0x9d97,0x9d98,0x9d99,0x9d9a,0x9d9b,
125.2698 +    0x9d9c,0x9d9d,0x9d9e,0x9d9f,0x9da0,0x9da1,0x9da2,UBOGON,UBOGON,UBOGON,
125.2699 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2700 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2701 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2702 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2703 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2704 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2705 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2706 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2707 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2708 +    UBOGON
125.2709 +  },
125.2710 +  {				/* ku 7a */
125.2711 +    0x9da3,0x9da4,0x9da5,0x9da6,0x9da7,0x9da8,0x9da9,0x9daa,0x9dab,0x9dac,
125.2712 +    0x9dad,0x9dae,0x9daf,0x9db0,0x9db1,0x9db2,0x9db3,0x9db4,0x9db5,0x9db6,
125.2713 +    0x9db7,0x9db8,0x9db9,0x9dba,0x9dbb,0x9dbc,0x9dbd,0x9dbe,0x9dbf,0x9dc0,
125.2714 +    0x9dc1,0x9dc2,0x9dc3,0x9dc4,0x9dc5,0x9dc6,0x9dc7,0x9dc8,0x9dc9,0x9dca,
125.2715 +    0x9dcb,0x9dcc,0x9dcd,0x9dce,0x9dcf,0x9dd0,0x9dd1,0x9dd2,0x9dd3,0x9dd4,
125.2716 +    0x9dd5,0x9dd6,0x9dd7,0x9dd8,0x9dd9,0x9dda,0x9ddb,0x9ddc,0x9ddd,0x9dde,
125.2717 +    0x9ddf,0x9de0,0x9de1,UBOGON,0x9de2,0x9de3,0x9de4,0x9de5,0x9de6,0x9de7,
125.2718 +    0x9de8,0x9de9,0x9dea,0x9deb,0x9dec,0x9ded,0x9dee,0x9def,0x9df0,0x9df1,
125.2719 +    0x9df2,0x9df3,0x9df4,0x9df5,0x9df6,0x9df7,0x9df8,0x9df9,0x9dfa,0x9dfb,
125.2720 +    0x9dfc,0x9dfd,0x9dfe,0x9dff,0x9e00,0x9e01,0x9e02,UBOGON,UBOGON,UBOGON,
125.2721 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2722 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2723 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2724 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2725 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2726 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2727 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2728 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2729 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2730 +    UBOGON
125.2731 +  },
125.2732 +  {				/* ku 7b */
125.2733 +    0x9e03,0x9e04,0x9e05,0x9e06,0x9e07,0x9e08,0x9e09,0x9e0a,0x9e0b,0x9e0c,
125.2734 +    0x9e0d,0x9e0e,0x9e0f,0x9e10,0x9e11,0x9e12,0x9e13,0x9e14,0x9e15,0x9e16,
125.2735 +    0x9e17,0x9e18,0x9e19,0x9e1a,0x9e1b,0x9e1c,0x9e1d,0x9e1e,0x9e24,0x9e27,
125.2736 +    0x9e2e,0x9e30,0x9e34,0x9e3b,0x9e3c,0x9e40,0x9e4d,0x9e50,0x9e52,0x9e53,
125.2737 +    0x9e54,0x9e56,0x9e59,0x9e5d,0x9e5f,0x9e60,0x9e61,0x9e62,0x9e65,0x9e6e,
125.2738 +    0x9e6f,0x9e72,0x9e74,0x9e75,0x9e76,0x9e77,0x9e78,0x9e79,0x9e7a,0x9e7b,
125.2739 +    0x9e7c,0x9e7d,0x9e80,UBOGON,0x9e81,0x9e83,0x9e84,0x9e85,0x9e86,0x9e89,
125.2740 +    0x9e8a,0x9e8c,0x9e8d,0x9e8e,0x9e8f,0x9e90,0x9e91,0x9e94,0x9e95,0x9e96,
125.2741 +    0x9e97,0x9e98,0x9e99,0x9e9a,0x9e9b,0x9e9c,0x9e9e,0x9ea0,0x9ea1,0x9ea2,
125.2742 +    0x9ea3,0x9ea4,0x9ea5,0x9ea7,0x9ea8,0x9ea9,0x9eaa,UBOGON,UBOGON,UBOGON,
125.2743 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2744 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2745 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2746 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2747 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2748 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2749 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2750 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2751 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2752 +    UBOGON
125.2753 +  },
125.2754 +  {				/* ku 7c */
125.2755 +    0x9eab,0x9eac,0x9ead,0x9eae,0x9eaf,0x9eb0,0x9eb1,0x9eb2,0x9eb3,0x9eb5,
125.2756 +    0x9eb6,0x9eb7,0x9eb9,0x9eba,0x9ebc,0x9ebf,0x9ec0,0x9ec1,0x9ec2,0x9ec3,
125.2757 +    0x9ec5,0x9ec6,0x9ec7,0x9ec8,0x9eca,0x9ecb,0x9ecc,0x9ed0,0x9ed2,0x9ed3,
125.2758 +    0x9ed5,0x9ed6,0x9ed7,0x9ed9,0x9eda,0x9ede,0x9ee1,0x9ee3,0x9ee4,0x9ee6,
125.2759 +    0x9ee8,0x9eeb,0x9eec,0x9eed,0x9eee,0x9ef0,0x9ef1,0x9ef2,0x9ef3,0x9ef4,
125.2760 +    0x9ef5,0x9ef6,0x9ef7,0x9ef8,0x9efa,0x9efd,0x9eff,0x9f00,0x9f01,0x9f02,
125.2761 +    0x9f03,0x9f04,0x9f05,UBOGON,0x9f06,0x9f07,0x9f08,0x9f09,0x9f0a,0x9f0c,
125.2762 +    0x9f0f,0x9f11,0x9f12,0x9f14,0x9f15,0x9f16,0x9f18,0x9f1a,0x9f1b,0x9f1c,
125.2763 +    0x9f1d,0x9f1e,0x9f1f,0x9f21,0x9f23,0x9f24,0x9f25,0x9f26,0x9f27,0x9f28,
125.2764 +    0x9f29,0x9f2a,0x9f2b,0x9f2d,0x9f2e,0x9f30,0x9f31,UBOGON,UBOGON,UBOGON,
125.2765 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2766 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2767 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2768 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2769 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2770 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2771 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2772 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2773 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2774 +    UBOGON
125.2775 +  },
125.2776 +  {				/* ku 7d */
125.2777 +    0x9f32,0x9f33,0x9f34,0x9f35,0x9f36,0x9f38,0x9f3a,0x9f3c,0x9f3f,0x9f40,
125.2778 +    0x9f41,0x9f42,0x9f43,0x9f45,0x9f46,0x9f47,0x9f48,0x9f49,0x9f4a,0x9f4b,
125.2779 +    0x9f4c,0x9f4d,0x9f4e,0x9f4f,0x9f52,0x9f53,0x9f54,0x9f55,0x9f56,0x9f57,
125.2780 +    0x9f58,0x9f59,0x9f5a,0x9f5b,0x9f5c,0x9f5d,0x9f5e,0x9f5f,0x9f60,0x9f61,
125.2781 +    0x9f62,0x9f63,0x9f64,0x9f65,0x9f66,0x9f67,0x9f68,0x9f69,0x9f6a,0x9f6b,
125.2782 +    0x9f6c,0x9f6d,0x9f6e,0x9f6f,0x9f70,0x9f71,0x9f72,0x9f73,0x9f74,0x9f75,
125.2783 +    0x9f76,0x9f77,0x9f78,UBOGON,0x9f79,0x9f7a,0x9f7b,0x9f7c,0x9f7d,0x9f7e,
125.2784 +    0x9f81,0x9f82,0x9f8d,0x9f8e,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f93,0x9f94,
125.2785 +    0x9f95,0x9f96,0x9f97,0x9f98,0x9f9c,0x9f9d,0x9f9e,0x9fa1,0x9fa2,0x9fa3,
125.2786 +    0x9fa4,0x9fa5,0xf92c,0xf979,0xf995,0xf9e7,0xf9f1,UBOGON,UBOGON,UBOGON,
125.2787 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2788 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2789 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2790 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2791 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2792 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2793 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2794 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2795 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
125.2796 +    UBOGON
125.2797 +  }
125.2798 +};
   126.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   126.2 +++ b/src/charset/ibm.c	Mon Sep 14 15:17:45 2009 +0900
   126.3 @@ -0,0 +1,347 @@
   126.4 +/* ========================================================================
   126.5 + * Copyright 1988-2006 University of Washington
   126.6 + *
   126.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   126.8 + * you may not use this file except in compliance with the License.
   126.9 + * You may obtain a copy of the License at
  126.10 + *
  126.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  126.12 + *
  126.13 + * 
  126.14 + * ========================================================================
  126.15 + */
  126.16 +
  126.17 +/*
  126.18 + * Program:	IBM conversion tables
  126.19 + *
  126.20 + * Author:	Mark Crispin
  126.21 + *		Networks and Distributed Computing
  126.22 + *		Computing & Communications
  126.23 + *		University of Washington
  126.24 + *		Administration Building, AG-44
  126.25 + *		Seattle, WA  98195
  126.26 + *		Internet: MRC@CAC.Washington.EDU
  126.27 + *
  126.28 + * Date:	4 November 2002
  126.29 + * Last Edited:	30 August 2006
  126.30 + */
  126.31 +
  126.32 +				/* IBM Latin US */
  126.33 +static const unsigned short ibm_437tab[128] = {
  126.34 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
  126.35 +  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
  126.36 +  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
  126.37 +  0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
  126.38 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
  126.39 +  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
  126.40 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
  126.41 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
  126.42 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
  126.43 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
  126.44 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
  126.45 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
  126.46 +  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
  126.47 +  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
  126.48 +  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
  126.49 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
  126.50 +};
  126.51 +
  126.52 +				/* IBM Greek */
  126.53 +static const unsigned short ibm_737tab[128] = {
  126.54 +  0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
  126.55 +  0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
  126.56 +  0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,
  126.57 +  0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
  126.58 +  0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
  126.59 +  0x03c1,0x03c3,0x03c2,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,
  126.60 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
  126.61 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
  126.62 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
  126.63 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
  126.64 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
  126.65 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
  126.66 +  0x03c9,0x03ac,0x03ad,0x03ae,0x03ca,0x03af,0x03cc,0x03cd,
  126.67 +  0x03cb,0x03ce,0x0386,0x0388,0x0389,0x038a,0x038c,0x038e,
  126.68 +  0x038f,0x00b1,0x2265,0x2264,0x03aa,0x03ab,0x00f7,0x2248,
  126.69 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
  126.70 +};
  126.71 +
  126.72 +				/* IBM Baltic Rim */
  126.73 +static const unsigned short ibm_775tab[128] = {
  126.74 +  0x0106,0x00fc,0x00e9,0x0101,0x00e4,0x0123,0x00e5,0x0107,
  126.75 +  0x0142,0x0113,0x0156,0x0157,0x012b,0x0179,0x00c4,0x00c5,
  126.76 +  0x00c9,0x00e6,0x00c6,0x014d,0x00f6,0x0122,0x00a2,0x015a,
  126.77 +  0x015b,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x00a4,
  126.78 +  0x0100,0x012a,0x00f3,0x017b,0x017c,0x017a,0x201d,0x00a6,
  126.79 +  0x00a9,0x00ae,0x00ac,0x00bd,0x00bc,0x0141,0x00ab,0x00bb,
  126.80 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x0104,0x010c,0x0118,
  126.81 +  0x0116,0x2563,0x2551,0x2557,0x255d,0x012e,0x0160,0x2510,
  126.82 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0172,0x016a,
  126.83 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x017d,
  126.84 +  0x0105,0x010d,0x0119,0x0117,0x012f,0x0161,0x0173,0x016b,
  126.85 +  0x017e,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
  126.86 +  0x00d3,0x00df,0x014c,0x0143,0x00f5,0x00d5,0x00b5,0x0144,
  126.87 +  0x0136,0x0137,0x013b,0x013c,0x0146,0x0112,0x0145,0x2019,
  126.88 +  0x00ad,0x00b1,0x201c,0x00be,0x00b6,0x00a7,0x00f7,0x201e,
  126.89 +  0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
  126.90 +};
  126.91 +
  126.92 +				/* IBM Latin 1 */
  126.93 +static const unsigned short ibm_850tab[128] = {
  126.94 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
  126.95 +  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
  126.96 +  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
  126.97 +  0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192,
  126.98 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
  126.99 +  0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
 126.100 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0,
 126.101 +  0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510,
 126.102 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3,
 126.103 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
 126.104 +  0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce,
 126.105 +  0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580,
 126.106 +  0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe,
 126.107 +  0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4,
 126.108 +  0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8,
 126.109 +  0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
 126.110 +};
 126.111 +
 126.112 +				/* IBM Latin 2 */
 126.113 +static const unsigned short ibm_852tab[128] = {
 126.114 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x016f,0x0107,0x00e7,
 126.115 +  0x0142,0x00eb,0x0150,0x0151,0x00ee,0x0179,0x00c4,0x0106,
 126.116 +  0x00c9,0x0139,0x013a,0x00f4,0x00f6,0x013d,0x013e,0x015a,
 126.117 +  0x015b,0x00d6,0x00dc,0x0164,0x0165,0x0141,0x00d7,0x010d,
 126.118 +  0x00e1,0x00ed,0x00f3,0x00fa,0x0104,0x0105,0x017d,0x017e,
 126.119 +  0x0118,0x0119,0x00ac,0x017a,0x010c,0x015f,0x00ab,0x00bb,
 126.120 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x011a,
 126.121 +  0x015e,0x2563,0x2551,0x2557,0x255d,0x017b,0x017c,0x2510,
 126.122 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0102,0x0103,
 126.123 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
 126.124 +  0x0111,0x0110,0x010e,0x00cb,0x010f,0x0147,0x00cd,0x00ce,
 126.125 +  0x011b,0x2518,0x250c,0x2588,0x2584,0x0162,0x016e,0x2580,
 126.126 +  0x00d3,0x00df,0x00d4,0x0143,0x0144,0x0148,0x0160,0x0161,
 126.127 +  0x0154,0x00da,0x0155,0x0170,0x00fd,0x00dd,0x0163,0x00b4,
 126.128 +  0x00ad,0x02dd,0x02db,0x02c7,0x02d8,0x00a7,0x00f7,0x00b8,
 126.129 +  0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0
 126.130 +};
 126.131 +
 126.132 +				/* IBM Cyrillic */
 126.133 +static const unsigned short ibm_855tab[128] = {
 126.134 +  0x0452,0x0402,0x0453,0x0403,0x0451,0x0401,0x0454,0x0404,
 126.135 +  0x0455,0x0405,0x0456,0x0406,0x0457,0x0407,0x0458,0x0408,
 126.136 +  0x0459,0x0409,0x045a,0x040a,0x045b,0x040b,0x045c,0x040c,
 126.137 +  0x045e,0x040e,0x045f,0x040f,0x044e,0x042e,0x044a,0x042a,
 126.138 +  0x0430,0x0410,0x0431,0x0411,0x0446,0x0426,0x0434,0x0414,
 126.139 +  0x0435,0x0415,0x0444,0x0424,0x0433,0x0413,0x00ab,0x00bb,
 126.140 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x0445,0x0425,0x0438,
 126.141 +  0x0418,0x2563,0x2551,0x2557,0x255d,0x0439,0x0419,0x2510,
 126.142 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x043a,0x041a,
 126.143 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
 126.144 +  0x043b,0x041b,0x043c,0x041c,0x043d,0x041d,0x043e,0x041e,
 126.145 +  0x043f,0x2518,0x250c,0x2588,0x2584,0x041f,0x044f,0x2580,
 126.146 +  0x042f,0x0440,0x0420,0x0441,0x0421,0x0442,0x0422,0x0443,
 126.147 +  0x0423,0x0436,0x0416,0x0432,0x0412,0x044c,0x042c,0x2116,
 126.148 +  0x00ad,0x044b,0x042b,0x0437,0x0417,0x0448,0x0428,0x044d,
 126.149 +  0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0
 126.150 +};
 126.151 +
 126.152 +				/* IBM Turkish */
 126.153 +static const unsigned short ibm_857tab[128] = {
 126.154 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
 126.155 +  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x0131,0x00c4,0x00c5,
 126.156 +  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
 126.157 +  0x0130,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x015e,0x015f,
 126.158 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x011e,0x011f,
 126.159 +  0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
 126.160 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0,
 126.161 +  0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510,
 126.162 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3,
 126.163 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
 126.164 +  0x00ba,0x00aa,0x00ca,0x00cb,0x00c8,UBOGON,0x00cd,0x00ce,
 126.165 +  0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580,
 126.166 +  0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,UBOGON,
 126.167 +  0x00d7,0x00da,0x00db,0x00d9,0x00ec,0x00ff,0x00af,0x00b4,
 126.168 +  0x00ad,0x00b1,UBOGON,0x00be,0x00b6,0x00a7,0x00f7,0x00b8,
 126.169 +  0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
 126.170 +};
 126.171 +
 126.172 +				/* IBM Portuguese */
 126.173 +static const unsigned short ibm_860tab[128] = {
 126.174 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e3,0x00e0,0x00c1,0x00e7,
 126.175 +  0x00ea,0x00ca,0x00e8,0x00cd,0x00d4,0x00ec,0x00c3,0x00c2,
 126.176 +  0x00c9,0x00c0,0x00c8,0x00f4,0x00f5,0x00f2,0x00da,0x00f9,
 126.177 +  0x00cc,0x00d5,0x00dc,0x00a2,0x00a3,0x00d9,0x20a7,0x00d3,
 126.178 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
 126.179 +  0x00bf,0x00d2,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
 126.180 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
 126.181 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
 126.182 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
 126.183 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
 126.184 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
 126.185 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
 126.186 +  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
 126.187 +  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
 126.188 +  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
 126.189 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
 126.190 +};
 126.191 +
 126.192 +				/* IBM Icelandic */
 126.193 +static const unsigned short ibm_861tab[128] = {
 126.194 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
 126.195 +  0x00ea,0x00eb,0x00e8,0x00d0,0x00f0,0x00de,0x00c4,0x00c5,
 126.196 +  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00fe,0x00fb,0x00dd,
 126.197 +  0x00fd,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192,
 126.198 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00c1,0x00cd,0x00d3,0x00da,
 126.199 +  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
 126.200 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
 126.201 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
 126.202 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
 126.203 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
 126.204 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
 126.205 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
 126.206 +  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
 126.207 +  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
 126.208 +  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
 126.209 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
 126.210 +};
 126.211 +
 126.212 +				/* IBM Hebrew */
 126.213 +static const unsigned short ibm_862tab[128] = {
 126.214 +  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
 126.215 +  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
 126.216 +  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
 126.217 +  0x05e8,0x05e9,0x05ea,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
 126.218 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
 126.219 +  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
 126.220 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
 126.221 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
 126.222 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
 126.223 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
 126.224 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
 126.225 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
 126.226 +  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
 126.227 +  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
 126.228 +  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
 126.229 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
 126.230 +};
 126.231 +
 126.232 +				/* IBM Canada/French */
 126.233 +static const unsigned short ibm_863tab[128] = {
 126.234 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00c2,0x00e0,0x00b6,0x00e7,
 126.235 +  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x2017,0x00c0,0x00a7,
 126.236 +  0x00c9,0x00c8,0x00ca,0x00f4,0x00cb,0x00cf,0x00fb,0x00f9,
 126.237 +  0x00a4,0x00d4,0x00dc,0x00a2,0x00a3,0x00d9,0x00db,0x0192,
 126.238 +  0x00a6,0x00b4,0x00f3,0x00fa,0x00a8,0x00b8,0x00b3,0x00af,
 126.239 +  0x00ce,0x2310,0x00ac,0x00bd,0x00bc,0x00be,0x00ab,0x00bb,
 126.240 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
 126.241 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
 126.242 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
 126.243 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
 126.244 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
 126.245 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
 126.246 +  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
 126.247 +  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
 126.248 +  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
 126.249 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
 126.250 +};
 126.251 +
 126.252 +				/* IBM Arabic */
 126.253 +static const unsigned short ibm_864tab[128] = {
 126.254 +  0x00b0,0x00b7,0x2219,0x221a,0x2592,0x2500,0x2502,0x253c,
 126.255 +  0x2524,0x252c,0x251c,0x2534,0x2510,0x250c,0x2514,0x2518,
 126.256 +  0x03b2,0x221e,0x03c6,0x00b1,0x00bd,0x00bc,0x2248,0x00ab,
 126.257 +  0x00bb,0xfef7,0xfef8,UBOGON,UBOGON,0xfefb,0xfefc,UBOGON,
 126.258 +  0x00a0,0x00ad,0xfe82,0x00a3,0x00a4,0xfe84,UBOGON,UBOGON,
 126.259 +  0xfe8e,0xfe8f,0xfe95,0xfe99,0x060c,0xfe9d,0xfea1,0xfea5,
 126.260 +  0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
 126.261 +  0x0668,0x0669,0xfed1,0x061b,0xfeb1,0xfeb5,0xfeb9,0x061f,
 126.262 +  0x00a2,0xfe80,0xfe81,0xfe83,0xfe85,0xfeca,0xfe8b,0xfe8d,
 126.263 +  0xfe91,0xfe93,0xfe97,0xfe9b,0xfe9f,0xfea3,0xfea7,0xfea9,
 126.264 +  0xfeab,0xfead,0xfeaf,0xfeb3,0xfeb7,0xfebb,0xfebf,0xfec1,
 126.265 +  0xfec5,0xfecb,0xfecf,0x00a6,0x00ac,0x00f7,0x00d7,0xfec9,
 126.266 +  0x0640,0xfed3,0xfed7,0xfedb,0xfedf,0xfee3,0xfee7,0xfeeb,
 126.267 +  0xfeed,0xfeef,0xfef3,0xfebd,0xfecc,0xfece,0xfecd,0xfee1,
 126.268 +  0xfe7d,0x0651,0xfee5,0xfee9,0xfeec,0xfef0,0xfef2,0xfed0,
 126.269 +  0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,UBOGON
 126.270 +};
 126.271 +
 126.272 +				/* IBM Nordic */
 126.273 +static const unsigned short ibm_865tab[128] = {
 126.274 +  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
 126.275 +  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
 126.276 +  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
 126.277 +  0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192,
 126.278 +  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
 126.279 +  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00a4,
 126.280 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
 126.281 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
 126.282 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
 126.283 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
 126.284 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
 126.285 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
 126.286 +  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
 126.287 +  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
 126.288 +  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
 126.289 +  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
 126.290 +};
 126.291 +
 126.292 +				/* IBM Cyrillic/Russian */
 126.293 +static const unsigned short ibm_866tab[128] = {
 126.294 +  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
 126.295 +  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
 126.296 +  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
 126.297 +  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
 126.298 +  0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
 126.299 +  0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
 126.300 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
 126.301 +  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
 126.302 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
 126.303 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
 126.304 +  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
 126.305 +  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
 126.306 +  0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
 126.307 +  0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
 126.308 +  0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040e,0x045e,
 126.309 +  0x00b0,0x2219,0x00b7,0x221a,0x2116,0x00a4,0x25a0,0x00a0
 126.310 +};
 126.311 +
 126.312 +				/* IBM Greek 2 */
 126.313 +static const unsigned short ibm_869tab[128] = {
 126.314 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0386,UBOGON,
 126.315 +  0x00b7,0x00ac,0x00a6,0x2018,0x2019,0x0388,0x2015,0x0389,
 126.316 +  0x038a,0x03aa,0x038c,UBOGON,UBOGON,0x038e,0x03ab,0x00a9,
 126.317 +  0x038f,0x00b2,0x00b3,0x03ac,0x00a3,0x03ad,0x03ae,0x03af,
 126.318 +  0x03ca,0x0390,0x03cc,0x03cd,0x0391,0x0392,0x0393,0x0394,
 126.319 +  0x0395,0x0396,0x0397,0x00bd,0x0398,0x0399,0x00ab,0x00bb,
 126.320 +  0x2591,0x2592,0x2593,0x2502,0x2524,0x039a,0x039b,0x039c,
 126.321 +  0x039d,0x2563,0x2551,0x2557,0x255d,0x039e,0x039f,0x2510,
 126.322 +  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x03a0,0x03a1,
 126.323 +  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x03a3,
 126.324 +  0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,
 126.325 +  0x03b3,0x2518,0x250c,0x2588,0x2584,0x03b4,0x03b5,0x2580,
 126.326 +  0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,
 126.327 +  0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c2,0x03c4,0x0384,
 126.328 +  0x00ad,0x00b1,0x03c5,0x03c6,0x03c7,0x00a7,0x03c8,0x0385,
 126.329 +  0x00b0,0x00a8,0x03c9,0x03cb,0x03b0,0x03ce,0x25a0,0x00a0
 126.330 +};
 126.331 +
 126.332 +				/* IBM Thai */
 126.333 +static const unsigned short ibm_874tab[128] = {
 126.334 +  0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON,
 126.335 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 126.336 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 126.337 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 126.338 +  0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
 126.339 +  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
 126.340 +  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
 126.341 +  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
 126.342 +  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
 126.343 +  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
 126.344 +  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
 126.345 +  0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
 126.346 +  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
 126.347 +  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
 126.348 +  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
 126.349 +  0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
 126.350 +};
   127.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   127.2 +++ b/src/charset/iso_8859.c	Mon Sep 14 15:17:45 2009 +0900
   127.3 @@ -0,0 +1,308 @@
   127.4 +/* ========================================================================
   127.5 + * Copyright 1988-2006 University of Washington
   127.6 + *
   127.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   127.8 + * you may not use this file except in compliance with the License.
   127.9 + * You may obtain a copy of the License at
  127.10 + *
  127.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  127.12 + *
  127.13 + * 
  127.14 + * ========================================================================
  127.15 + */
  127.16 +
  127.17 +/*
  127.18 + * Program:	ISO-8859 conversion tables
  127.19 + *
  127.20 + * Author:	Mark Crispin
  127.21 + *		Networks and Distributed Computing
  127.22 + *		Computing & Communications
  127.23 + *		University of Washington
  127.24 + *		Administration Building, AG-44
  127.25 + *		Seattle, WA  98195
  127.26 + *		Internet: MRC@CAC.Washington.EDU
  127.27 + *
  127.28 + * Date:	3 July 1997
  127.29 + * Last Edited:	30 August 2006
  127.30 + */
  127.31 +
  127.32 +/* ISO-8859 conversion tables */
  127.33 +
  127.34 +				/* Latin-2 (East European) */
  127.35 +static const unsigned short iso8859_2tab[128] = {
  127.36 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
  127.37 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
  127.38 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
  127.39 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
  127.40 +  0x00a0,0x0104,0x02d8,0x0141,0x00a4,0x013d,0x015a,0x00a7,
  127.41 +  0x00a8,0x0160,0x015e,0x0164,0x0179,0x00ad,0x017d,0x017b,
  127.42 +  0x00b0,0x0105,0x02db,0x0142,0x00b4,0x013e,0x015b,0x02c7,
  127.43 +  0x00b8,0x0161,0x015f,0x0165,0x017a,0x02dd,0x017e,0x017c,
  127.44 +  0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7,
  127.45 +  0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e,
  127.46 +  0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7,
  127.47 +  0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df,
  127.48 +  0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7,
  127.49 +  0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f,
  127.50 +  0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7,
  127.51 +  0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9
  127.52 +};
  127.53 +
  127.54 +
  127.55 +				/* Latin-3 (South European) */
  127.56 +static const unsigned short iso8859_3tab[128] = {
  127.57 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
  127.58 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
  127.59 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
  127.60 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
  127.61 +  0x00a0,0x0126,0x02d8,0x00a3,0x00a4,UBOGON,0x0124,0x00a7,
  127.62 +  0x00a8,0x0130,0x015e,0x011e,0x0134,0x00ad,UBOGON,0x017b,
  127.63 +  0x00b0,0x0127,0x00b2,0x00b3,0x00b4,0x00b5,0x0125,0x00b7,
  127.64 +  0x00b8,0x0131,0x015f,0x011f,0x0135,0x00bd,UBOGON,0x017c,
  127.65 +  0x00c0,0x00c1,0x00c2,UBOGON,0x00c4,0x010a,0x0108,0x00c7,
  127.66 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
  127.67 +  UBOGON,0x00d1,0x00d2,0x00d3,0x00d4,0x0120,0x00d6,0x00d7,
  127.68 +  0x011c,0x00d9,0x00da,0x00db,0x00dc,0x016c,0x015c,0x00df,
  127.69 +  0x00e0,0x00e1,0x00e2,UBOGON,0x00e4,0x010b,0x0109,0x00e7,
  127.70 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
  127.71 +  UBOGON,0x00f1,0x00f2,0x00f3,0x00f4,0x0121,0x00f6,0x00f7,
  127.72 +  0x011d,0x00f9,0x00fa,0x00fb,0x00fc,0x016d,0x015d,0x02d9
  127.73 +};
  127.74 +
  127.75 +
  127.76 +				/* Latin-4 (North European) */
  127.77 +static const unsigned short iso8859_4tab[128] = {
  127.78 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
  127.79 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
  127.80 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
  127.81 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
  127.82 +  0x00a0,0x0104,0x0138,0x0156,0x00a4,0x0128,0x013b,0x00a7,
  127.83 +  0x00a8,0x0160,0x0112,0x0122,0x0166,0x00ad,0x017d,0x00af,
  127.84 +  0x00b0,0x0105,0x02db,0x0157,0x00b4,0x0129,0x013c,0x02c7,
  127.85 +  0x00b8,0x0161,0x0113,0x0123,0x0167,0x014a,0x017e,0x014b,
  127.86 +  0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e,
  127.87 +  0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x012a,
  127.88 +  0x0110,0x0145,0x014c,0x0136,0x00d4,0x00d5,0x00d6,0x00d7,
  127.89 +  0x00d8,0x0172,0x00da,0x00db,0x00dc,0x0168,0x016a,0x00df,
  127.90 +  0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f,
  127.91 +  0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x012b,
  127.92 +  0x0111,0x0146,0x014d,0x0137,0x00f4,0x00f5,0x00f6,0x00f7,
  127.93 +  0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x0169,0x016b,0x02d9
  127.94 +};
  127.95 +
  127.96 +
  127.97 +				/* Cyrillic */
  127.98 +static const unsigned short iso8859_5tab[128] = {
  127.99 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.100 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.101 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.102 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.103 +  0x00a0,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
 127.104 +  0x0408,0x0409,0x040a,0x040b,0x040c,0x00ad,0x040e,0x040f,
 127.105 +  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
 127.106 +  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
 127.107 +  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
 127.108 +  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
 127.109 +  0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
 127.110 +  0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
 127.111 +  0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
 127.112 +  0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
 127.113 +  0x2116,0x0451,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,
 127.114 +  0x0458,0x0459,0x045a,0x045b,0x045c,0x00a7,0x045e,0x045f
 127.115 +};
 127.116 +
 127.117 +
 127.118 +				/* Arabic */
 127.119 +static const unsigned short iso8859_6tab[128] = {
 127.120 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.121 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.122 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.123 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.124 +  0x00a0,UBOGON,UBOGON,UBOGON,0x00a4,UBOGON,UBOGON,UBOGON,
 127.125 +  UBOGON,UBOGON,UBOGON,UBOGON,0x060c,0x00ad,UBOGON,UBOGON,
 127.126 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 127.127 +  UBOGON,UBOGON,UBOGON,0x061b,UBOGON,UBOGON,UBOGON,0x061f,
 127.128 +  UBOGON,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
 127.129 +  0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
 127.130 +  0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
 127.131 +  0x0638,0x0639,0x063a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 127.132 +  0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
 127.133 +  0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
 127.134 +  0x0650,0x0651,0x0652,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 127.135 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 127.136 +};
 127.137 +
 127.138 +
 127.139 +				/* Greek */
 127.140 +static const unsigned short iso8859_7tab[128] = {
 127.141 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.142 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.143 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.144 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.145 +  0x00a0,0x2018,0x2019,0x00a3,UBOGON,UBOGON,0x00a6,0x00a7,
 127.146 +  0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,UBOGON,0x2015,
 127.147 +  0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x0385,0x0386,0x00b7,
 127.148 +  0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f,
 127.149 +  0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
 127.150 +  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
 127.151 +  0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
 127.152 +  0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
 127.153 +  0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
 127.154 +  0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
 127.155 +  0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
 127.156 +  0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON
 127.157 +};
 127.158 +
 127.159 +
 127.160 +				/* Hebrew */
 127.161 +static const unsigned short iso8859_8tab[128] = {
 127.162 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.163 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.164 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.165 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.166 +  0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
 127.167 +  0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 127.168 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 127.169 +  0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,UBOGON,
 127.170 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 127.171 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 127.172 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 127.173 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2017,
 127.174 +  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
 127.175 +  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
 127.176 +  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
 127.177 +  0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON
 127.178 +};
 127.179 +
 127.180 +
 127.181 +				/* Latin-5 (Turkish) */
 127.182 +static const unsigned short iso8859_9tab[128] = {
 127.183 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.184 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.185 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.186 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.187 +  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
 127.188 +  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 127.189 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 127.190 +  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
 127.191 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
 127.192 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
 127.193 +  0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
 127.194 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df,
 127.195 +  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
 127.196 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
 127.197 +  0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
 127.198 +  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff
 127.199 +};
 127.200 +
 127.201 +
 127.202 +				/* Latin-6 (Nordic) */
 127.203 +static const unsigned short iso8859_10tab[128] = {
 127.204 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.205 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.206 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.207 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.208 +  0x00a0,0x0104,0x0112,0x0122,0x012a,0x0128,0x0136,0x00a7,
 127.209 +  0x013b,0x0110,0x0160,0x0166,0x017d,0x00ad,0x016a,0x014a,
 127.210 +  0x00b0,0x0105,0x0113,0x0123,0x012b,0x0129,0x0137,0x00b7,
 127.211 +  0x013c,0x0111,0x0161,0x0167,0x017e,0x2015,0x016b,0x014b,
 127.212 +  0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e,
 127.213 +  0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x00cf,
 127.214 +  0x00d0,0x0145,0x014c,0x00d3,0x00d4,0x00d5,0x00d6,0x0168,
 127.215 +  0x00d8,0x0172,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
 127.216 +  0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f,
 127.217 +  0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x00ef,
 127.218 +  0x00f0,0x0146,0x014d,0x00f3,0x00f4,0x00f5,0x00f6,0x0169,
 127.219 +  0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x0138
 127.220 +};
 127.221 +
 127.222 +
 127.223 +				/* Thai */
 127.224 +#define iso8859_11tab tis620tab
 127.225 +
 127.226 +				/* reserved for ISCII Indian */
 127.227 +
 127.228 +				/* Latin-7 (Baltic) */
 127.229 +static const unsigned short iso8859_13tab[128] = {
 127.230 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.231 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.232 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.233 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.234 +  0x00a0,0x201d,0x00a2,0x00a3,0x00a4,0x201e,0x00a6,0x00a7,
 127.235 +  0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6,
 127.236 +  0x00b0,0x00b1,0x00b2,0x00b3,0x201c,0x00b5,0x00b6,0x00b7,
 127.237 +  0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6,
 127.238 +  0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112,
 127.239 +  0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b,
 127.240 +  0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7,
 127.241 +  0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df,
 127.242 +  0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113,
 127.243 +  0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c,
 127.244 +  0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7,
 127.245 +  0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x2019
 127.246 +};
 127.247 +
 127.248 +
 127.249 +				/* Latin-8 (Celtic) */
 127.250 +
 127.251 +static const unsigned short iso8859_14tab[128] = {
 127.252 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.253 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.254 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.255 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.256 +  0x00a0,0x1e02,0x1e03,0x00a3,0x010a,0x010b,0x1e0a,0x00a7,
 127.257 +  0x1e80,0x00a9,0x1e82,0x1e0b,0x1ef2,0x00ad,0x00ae,0x0178,
 127.258 +  0x1e1e,0x1e1f,0x0120,0x0121,0x1e40,0x1e41,0x00b6,0x1e56,
 127.259 +  0x1e81,0x1e57,0x1e83,0x1e60,0x1ef3,0x1e84,0x1e85,0x1e61,
 127.260 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
 127.261 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
 127.262 +  0x0174,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x1e6a,
 127.263 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x0176,0x00df,
 127.264 +  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
 127.265 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
 127.266 +  0x0175,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x1e6b,
 127.267 +  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x0177,0x00ff
 127.268 +};
 127.269 +
 127.270 +
 127.271 +				/* Latin-9 a.k.a. Latin-0 (Euro) */
 127.272 +static const unsigned short iso8859_15tab[128] = {
 127.273 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.274 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.275 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.276 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.277 +  0x00a0,0x00a1,0x00a2,0x00a3,0x20ac,0x00a5,0x0160,0x00a7,
 127.278 +  0x0161,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 127.279 +  0x00b0,0x00b1,0x00b2,0x00b3,0x017d,0x00b5,0x00b6,0x00b7,
 127.280 +  0x017e,0x00b9,0x00ba,0x00bb,0x0152,0x0153,0x0178,0x00bf,
 127.281 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
 127.282 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
 127.283 +  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
 127.284 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
 127.285 +  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
 127.286 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
 127.287 +  0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
 127.288 +  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff
 127.289 +};
 127.290 +
 127.291 +
 127.292 +				/* Latin-10 (Balkan) */
 127.293 +
 127.294 +static const unsigned short iso8859_16tab[128] = {
 127.295 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
 127.296 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
 127.297 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
 127.298 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
 127.299 +  0x00a0,0x0104,0x0105,0x0141,0x20ac,0x201e,0x0160,0x00a7,
 127.300 +  0x0161,0x00a9,0x0218,0x00ab,0x0179,0x00ad,0x017a,0x017b,
 127.301 +  0x00b0,0x00b1,0x010c,0x0142,0x017d,0x201d,0x00b6,0x00b7,
 127.302 +  0x017e,0x010d,0x0219,0x00bb,0x0152,0x0153,0x0178,0x017c,
 127.303 +  0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x0106,0x00c6,0x00c7,
 127.304 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
 127.305 +  0x0110,0x0143,0x00d2,0x00d3,0x00d4,0x0150,0x00d6,0x015a,
 127.306 +  0x0170,0x00d9,0x00da,0x00db,0x00dc,0x0118,0x021a,0x00df,
 127.307 +  0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x0107,0x00e6,0x00e7,
 127.308 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
 127.309 +  0x0111,0x0144,0x00f2,0x00f3,0x00f4,0x0151,0x00f6,0x015b,
 127.310 +  0x0171,0x00f9,0x00fa,0x00fb,0x00fc,0x0119,0x021b,0x00ff
 127.311 +};
   128.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   128.2 +++ b/src/charset/jis_0208.c	Mon Sep 14 15:17:45 2009 +0900
   128.3 @@ -0,0 +1,1092 @@
   128.4 +/* ========================================================================
   128.5 + * Copyright 1988-2006 University of Washington
   128.6 + *
   128.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   128.8 + * you may not use this file except in compliance with the License.
   128.9 + * You may obtain a copy of the License at
  128.10 + *
  128.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  128.12 + *
  128.13 + * 
  128.14 + * ========================================================================
  128.15 + */
  128.16 +
  128.17 +/*
  128.18 + * Program:	JIS X0208 conversion table
  128.19 + *
  128.20 + * Author:	Mark Crispin
  128.21 + *		Networks and Distributed Computing
  128.22 + *		Computing & Communications
  128.23 + *		University of Washington
  128.24 + *		Administration Building, AG-44
  128.25 + *		Seattle, WA  98195
  128.26 + *		Internet: MRC@CAC.Washington.EDU
  128.27 + *
  128.28 + * Date:	3 July 1997
  128.29 + * Last Edited:	30 August 2006
  128.30 + */
  128.31 +
  128.32 +/* JIS X0208 is the industrial standard of Japan. */
  128.33 +
  128.34 +#define BASE_JIS0208_KU 0x21
  128.35 +#define BASE_JIS0208_TEN 0x21
  128.36 +#define MAX_JIS0208_KU 84
  128.37 +#define MAX_JIS0208_TEN 94
  128.38 +
  128.39 +
  128.40 +#define SJISTOJIS(c,c1)							\
  128.41 +  c = ((c - ((c < 0xa0) ? 0x70 : 0xb0)) << 1);				\
  128.42 +  if (c1 < 0x9f) {							\
  128.43 +    c--;								\
  128.44 +    c1 -= 0x1f + (c1 > 0x7f);						\
  128.45 +  }									\
  128.46 +  else c1 -= 0x7e;
  128.47 +
  128.48 +
  128.49 +#define JISTOUNICODE(c,c1,ku,ten)					\
  128.50 +  ((((ku = (c & 0x7f) - BASE_JIS0208_KU) < MAX_JIS0208_KU) &&		\
  128.51 +    ((ten = (c1 & 0x7f) - BASE_JIS0208_TEN) < MAX_JIS0208_TEN)) ?	\
  128.52 +   jis0208tab[ku][ten] : UBOGON)
  128.53 +
  128.54 +
  128.55 +static const unsigned short jis0208tab[MAX_JIS0208_KU][MAX_JIS0208_TEN] = {
  128.56 +  {				/* ku 01 */
  128.57 +    0x3000,0x3001,0x3002,0xff0c,0xff0e,0x30fb,0xff1a,0xff1b,0xff1f,0xff01,
  128.58 +    0x309b,0x309c,0x00b4,0xff40,0x00a8,0xff3e,0xffe3,0xff3f,0x30fd,0x30fe,
  128.59 +    0x309d,0x309e,0x3003,0x4edd,0x3005,0x3006,0x3007,0x30fc,0x2015,0x2010,
  128.60 +    /* Fullwidth/halfwidth correction:
  128.61 +     * JIS0208.TXT shows 01/32 as U+005C instead of U+FF3C.
  128.62 +     *
  128.63 +     * AOL suggests that 01/33 should be U+FF5E instead of U+301C and
  128.64 +     * 01/34 should be U+2225 instead of U+2016.
  128.65 +     * I disagree; 01/33 is JIS punctuation (not a tilde); and 01/34 is
  128.66 +     * double vertical line.
  128.67 +     */
  128.68 +    0xff0f,0xff3c,0x301c,0x2016,0xff5c,0x2026,0x2025,0x2018,0x2019,0x201c,
  128.69 +    0x201d,0xff08,0xff09,0x3014,0x3015,0xff3b,0xff3d,0xff5b,0xff5d,0x3008,
  128.70 +    0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3010,0x3011,0xff0b,
  128.71 +    /* Fullwidth/halfwidth correction:
  128.72 +     * JIS0208.TXT 01/61 has U+2212 instead of U+FF0D.
  128.73 +     */
  128.74 +    0xff0d,0x00b1,0x00d7,0x00f7,0xff1d,0x2260,0xff1c,0xff1e,0x2266,0x2267,
  128.75 +    0x221e,0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,0xffe5,0xff04,
  128.76 +    /* Fullwidth/halfwidth correction:
  128.77 +     * JIS 0208 shows 01/81 as U+00A2 instead of U+FFE0, and
  128.78 +     * 01/82 as U+00A3 instead of U+FFE1.
  128.79 +     */
  128.80 +    0xffe0,0xffe1,0xff05,0xff03,0xff06,0xff0a,0xff20,0x00a7,0x2606,0x2605,
  128.81 +    0x25cb,0x25cf,0x25ce,0x25c7
  128.82 +  },
  128.83 +  {				/* ku 02 */
  128.84 +    0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x25bd,0x25bc,0x203b,0x3012,0x2192,
  128.85 +    0x2190,0x2191,0x2193,0x3013,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  128.86 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2208,0x220b,0x2286,0x2287,0x2282,
  128.87 +    0x2283,0x222a,0x2229,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  128.88 +    /* Fullwidth/halfwidth correction:
  128.89 +     * JIS0208.TXT shows 02/44 as U+00AC instead of U+FFE2.
  128.90 +     */
  128.91 +    UBOGON,0x2227,0x2228,0xffe2,0x21d2,0x21d4,0x2200,0x2203,UBOGON,UBOGON,
  128.92 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2220,
  128.93 +    0x22a5,0x2312,0x2202,0x2207,0x2261,0x2252,0x226a,0x226b,0x221a,0x223d,
  128.94 +    0x221d,0x2235,0x222b,0x222c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  128.95 +    UBOGON,0x212b,0x2030,0x266f,0x266d,0x266a,0x2020,0x2021,0x00b6,UBOGON,
  128.96 +    UBOGON,UBOGON,UBOGON,0x25ef
  128.97 +  },
  128.98 +  {				/* ku 03 */
  128.99 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.100 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xff10,0xff11,0xff12,0xff13,0xff14,
 128.101 +    0xff15,0xff16,0xff17,0xff18,0xff19,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.102 +    UBOGON,UBOGON,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,
 128.103 +    0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,
 128.104 +    0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,UBOGON,UBOGON,
 128.105 +    UBOGON,UBOGON,UBOGON,UBOGON,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,
 128.106 +    0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,
 128.107 +    0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,
 128.108 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.109 +  },
 128.110 +  {				/* ku 04 */
 128.111 +    0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,
 128.112 +    0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,
 128.113 +    0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,
 128.114 +    0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,
 128.115 +    0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,
 128.116 +    0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,
 128.117 +    0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,
 128.118 +    0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,
 128.119 +    0x3091,0x3092,0x3093,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.120 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.121 +  },
 128.122 +  {				/* ku 05 */
 128.123 +    0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,
 128.124 +    0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,
 128.125 +    0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,
 128.126 +    0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,
 128.127 +    0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,
 128.128 +    0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,
 128.129 +    0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,
 128.130 +    0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,
 128.131 +    0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,
 128.132 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.133 +  },
 128.134 +  {				/* ku 06 */
 128.135 +    0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,
 128.136 +    0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,
 128.137 +    0x03a6,0x03a7,0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.138 +    UBOGON,UBOGON,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
 128.139 +    0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,
 128.140 +    0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,
 128.141 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.142 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.143 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.144 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.145 +  },
 128.146 +  {				/* ku 07 */
 128.147 +    0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,
 128.148 +    0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,
 128.149 +    0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,
 128.150 +    0x042d,0x042e,0x042f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.151 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,
 128.152 +    0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,
 128.153 +    0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,
 128.154 +    0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,
 128.155 +    0x044f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.156 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.157 +  },
 128.158 +  {				/* ku 08 */
 128.159 +    0x2500,0x2502,0x250c,0x2510,0x2518,0x2514,0x251c,0x252c,0x2524,0x2534,
 128.160 +    0x253c,0x2501,0x2503,0x250f,0x2513,0x251b,0x2517,0x2523,0x2533,0x252b,
 128.161 +    0x253b,0x254b,0x2520,0x252f,0x2528,0x2537,0x253f,0x251d,0x2530,0x2525,
 128.162 +    0x2538,0x2542,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.163 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.164 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.165 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.166 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.167 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.168 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.169 +  },
 128.170 +  {				/* ku 09 */
 128.171 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.172 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.173 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.174 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.176 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.180 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.181 +  },
 128.182 +  {				/* ku 0a */
 128.183 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.184 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.185 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.186 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.187 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.188 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.190 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.191 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.192 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.193 +  },
 128.194 +  {				/* ku 0b */
 128.195 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.196 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.197 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.198 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.199 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.204 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.205 +  },
 128.206 +  {				/* ku 0c */
 128.207 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.208 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.209 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.210 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.211 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.216 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.217 +  },
 128.218 +  {				/* ku 0d */
 128.219 +#if 0
 128.220 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.221 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.222 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.223 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.225 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.226 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.227 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.228 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.229 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.230 +#else	/* additional mappings suggested by AOL */
 128.231 +   0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,
 128.232 +   0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,0x2470,0x2471,0x2472,0x2473,
 128.233 +   0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
 128.234 +   UBOGON,0x3349,0x3314,0x3322,0x334d,0x3318,0x3327,0x3303,0x3336,0x3351,
 128.235 +   0x3357,0x330d,0x3326,0x3323,0x332b,0x334a,0x333b,0x339c,0x339d,0x339e,
 128.236 +   0x338e,0x338f,0x33c4,0x33a1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.237 +   UBOGON,UBOGON,0x337b,0x301d,0x301f,0x2116,0x33cd,0x2121,0x32a4,0x32a5,
 128.238 +   0x32a6,0x32a7,0x32a8,0x3231,0x3232,0x3239,0x337e,0x337d,0x337c,UBOGON,
 128.239 +   UBOGON,UBOGON,0x222e,0x2211,UBOGON,UBOGON,UBOGON,0x221f,0x22bf,UBOGON,
 128.240 +   UBOGON,UBOGON,UBOGON,UBOGON
 128.241 +#endif
 128.242 +  },
 128.243 +  {				/* ku 0e */
 128.244 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.245 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.246 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.247 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.248 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.249 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.250 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.251 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.252 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.253 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.254 +  },
 128.255 +  {				/* ku 0f */
 128.256 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.257 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.258 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.259 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.260 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.261 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.262 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.263 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.265 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.266 +  },
 128.267 +  {				/* ku 10 */
 128.268 +    0x4e9c,0x5516,0x5a03,0x963f,0x54c0,0x611b,0x6328,0x59f6,0x9022,0x8475,
 128.269 +    0x831c,0x7a50,0x60aa,0x63e1,0x6e25,0x65ed,0x8466,0x82a6,0x9bf5,0x6893,
 128.270 +    0x5727,0x65a1,0x6271,0x5b9b,0x59d0,0x867b,0x98f4,0x7d62,0x7dbe,0x9b8e,
 128.271 +    0x6216,0x7c9f,0x88b7,0x5b89,0x5eb5,0x6309,0x6697,0x6848,0x95c7,0x978d,
 128.272 +    0x674f,0x4ee5,0x4f0a,0x4f4d,0x4f9d,0x5049,0x56f2,0x5937,0x59d4,0x5a01,
 128.273 +    0x5c09,0x60df,0x610f,0x6170,0x6613,0x6905,0x70ba,0x754f,0x7570,0x79fb,
 128.274 +    0x7dad,0x7def,0x80c3,0x840e,0x8863,0x8b02,0x9055,0x907a,0x533b,0x4e95,
 128.275 +    0x4ea5,0x57df,0x80b2,0x90c1,0x78ef,0x4e00,0x58f1,0x6ea2,0x9038,0x7a32,
 128.276 +    0x8328,0x828b,0x9c2f,0x5141,0x5370,0x54bd,0x54e1,0x56e0,0x59fb,0x5f15,
 128.277 +    0x98f2,0x6deb,0x80e4,0x852d
 128.278 +  },
 128.279 +  {				/* ku 11 */
 128.280 +    0x9662,0x9670,0x96a0,0x97fb,0x540b,0x53f3,0x5b87,0x70cf,0x7fbd,0x8fc2,
 128.281 +    0x96e8,0x536f,0x9d5c,0x7aba,0x4e11,0x7893,0x81fc,0x6e26,0x5618,0x5504,
 128.282 +    0x6b1d,0x851a,0x9c3b,0x59e5,0x53a9,0x6d66,0x74dc,0x958f,0x5642,0x4e91,
 128.283 +    0x904b,0x96f2,0x834f,0x990c,0x53e1,0x55b6,0x5b30,0x5f71,0x6620,0x66f3,
 128.284 +    0x6804,0x6c38,0x6cf3,0x6d29,0x745b,0x76c8,0x7a4e,0x9834,0x82f1,0x885b,
 128.285 +    0x8a60,0x92ed,0x6db2,0x75ab,0x76ca,0x99c5,0x60a6,0x8b01,0x8d8a,0x95b2,
 128.286 +    0x698e,0x53ad,0x5186,0x5712,0x5830,0x5944,0x5bb4,0x5ef6,0x6028,0x63a9,
 128.287 +    0x63f4,0x6cbf,0x6f14,0x708e,0x7114,0x7159,0x71d5,0x733f,0x7e01,0x8276,
 128.288 +    0x82d1,0x8597,0x9060,0x925b,0x9d1b,0x5869,0x65bc,0x6c5a,0x7525,0x51f9,
 128.289 +    0x592e,0x5965,0x5f80,0x5fdc
 128.290 +  },
 128.291 +  {				/* ku 12 */
 128.292 +    0x62bc,0x65fa,0x6a2a,0x6b27,0x6bb4,0x738b,0x7fc1,0x8956,0x9d2c,0x9d0e,
 128.293 +    0x9ec4,0x5ca1,0x6c96,0x837b,0x5104,0x5c4b,0x61b6,0x81c6,0x6876,0x7261,
 128.294 +    0x4e59,0x4ffa,0x5378,0x6069,0x6e29,0x7a4f,0x97f3,0x4e0b,0x5316,0x4eee,
 128.295 +    0x4f55,0x4f3d,0x4fa1,0x4f73,0x52a0,0x53ef,0x5609,0x590f,0x5ac1,0x5bb6,
 128.296 +    0x5be1,0x79d1,0x6687,0x679c,0x67b6,0x6b4c,0x6cb3,0x706b,0x73c2,0x798d,
 128.297 +    0x79be,0x7a3c,0x7b87,0x82b1,0x82db,0x8304,0x8377,0x83ef,0x83d3,0x8766,
 128.298 +    0x8ab2,0x5629,0x8ca8,0x8fe6,0x904e,0x971e,0x868a,0x4fc4,0x5ce8,0x6211,
 128.299 +    0x7259,0x753b,0x81e5,0x82bd,0x86fe,0x8cc0,0x96c5,0x9913,0x99d5,0x4ecb,
 128.300 +    0x4f1a,0x89e3,0x56de,0x584a,0x58ca,0x5efb,0x5feb,0x602a,0x6094,0x6062,
 128.301 +    0x61d0,0x6212,0x62d0,0x6539
 128.302 +  },
 128.303 +  {				/* ku 13 */
 128.304 +    0x9b41,0x6666,0x68b0,0x6d77,0x7070,0x754c,0x7686,0x7d75,0x82a5,0x87f9,
 128.305 +    0x958b,0x968e,0x8c9d,0x51f1,0x52be,0x5916,0x54b3,0x5bb3,0x5d16,0x6168,
 128.306 +    0x6982,0x6daf,0x788d,0x84cb,0x8857,0x8a72,0x93a7,0x9ab8,0x6d6c,0x99a8,
 128.307 +    0x86d9,0x57a3,0x67ff,0x86ce,0x920e,0x5283,0x5687,0x5404,0x5ed3,0x62e1,
 128.308 +    0x64b9,0x683c,0x6838,0x6bbb,0x7372,0x78ba,0x7a6b,0x899a,0x89d2,0x8d6b,
 128.309 +    0x8f03,0x90ed,0x95a3,0x9694,0x9769,0x5b66,0x5cb3,0x697d,0x984d,0x984e,
 128.310 +    0x639b,0x7b20,0x6a2b,0x6a7f,0x68b6,0x9c0d,0x6f5f,0x5272,0x559d,0x6070,
 128.311 +    0x62ec,0x6d3b,0x6e07,0x6ed1,0x845b,0x8910,0x8f44,0x4e14,0x9c39,0x53f6,
 128.312 +    0x691b,0x6a3a,0x9784,0x682a,0x515c,0x7ac3,0x84b2,0x91dc,0x938c,0x565b,
 128.313 +    0x9d28,0x6822,0x8305,0x8431
 128.314 +  },
 128.315 +  {				/* ku 14 */
 128.316 +    0x7ca5,0x5208,0x82c5,0x74e6,0x4e7e,0x4f83,0x51a0,0x5bd2,0x520a,0x52d8,
 128.317 +    0x52e7,0x5dfb,0x559a,0x582a,0x59e6,0x5b8c,0x5b98,0x5bdb,0x5e72,0x5e79,
 128.318 +    0x60a3,0x611f,0x6163,0x61be,0x63db,0x6562,0x67d1,0x6853,0x68fa,0x6b3e,
 128.319 +    0x6b53,0x6c57,0x6f22,0x6f97,0x6f45,0x74b0,0x7518,0x76e3,0x770b,0x7aff,
 128.320 +    0x7ba1,0x7c21,0x7de9,0x7f36,0x7ff0,0x809d,0x8266,0x839e,0x89b3,0x8acc,
 128.321 +    0x8cab,0x9084,0x9451,0x9593,0x9591,0x95a2,0x9665,0x97d3,0x9928,0x8218,
 128.322 +    0x4e38,0x542b,0x5cb8,0x5dcc,0x73a9,0x764c,0x773c,0x5ca9,0x7feb,0x8d0b,
 128.323 +    0x96c1,0x9811,0x9854,0x9858,0x4f01,0x4f0e,0x5371,0x559c,0x5668,0x57fa,
 128.324 +    0x5947,0x5b09,0x5bc4,0x5c90,0x5e0c,0x5e7e,0x5fcc,0x63ee,0x673a,0x65d7,
 128.325 +    0x65e2,0x671f,0x68cb,0x68c4
 128.326 +  },
 128.327 +  {				/* ku 15 */
 128.328 +    0x6a5f,0x5e30,0x6bc5,0x6c17,0x6c7d,0x757f,0x7948,0x5b63,0x7a00,0x7d00,
 128.329 +    0x5fbd,0x898f,0x8a18,0x8cb4,0x8d77,0x8ecc,0x8f1d,0x98e2,0x9a0e,0x9b3c,
 128.330 +    0x4e80,0x507d,0x5100,0x5993,0x5b9c,0x622f,0x6280,0x64ec,0x6b3a,0x72a0,
 128.331 +    0x7591,0x7947,0x7fa9,0x87fb,0x8abc,0x8b70,0x63ac,0x83ca,0x97a0,0x5409,
 128.332 +    0x5403,0x55ab,0x6854,0x6a58,0x8a70,0x7827,0x6775,0x9ecd,0x5374,0x5ba2,
 128.333 +    0x811a,0x8650,0x9006,0x4e18,0x4e45,0x4ec7,0x4f11,0x53ca,0x5438,0x5bae,
 128.334 +    0x5f13,0x6025,0x6551,0x673d,0x6c42,0x6c72,0x6ce3,0x7078,0x7403,0x7a76,
 128.335 +    0x7aae,0x7b08,0x7d1a,0x7cfe,0x7d66,0x65e7,0x725b,0x53bb,0x5c45,0x5de8,
 128.336 +    0x62d2,0x62e0,0x6319,0x6e20,0x865a,0x8a31,0x8ddd,0x92f8,0x6f01,0x79a6,
 128.337 +    0x9b5a,0x4ea8,0x4eab,0x4eac
 128.338 +  },
 128.339 +  {				/* ku 16 */
 128.340 +    0x4f9b,0x4fa0,0x50d1,0x5147,0x7af6,0x5171,0x51f6,0x5354,0x5321,0x537f,
 128.341 +    0x53eb,0x55ac,0x5883,0x5ce1,0x5f37,0x5f4a,0x602f,0x6050,0x606d,0x631f,
 128.342 +    0x6559,0x6a4b,0x6cc1,0x72c2,0x72ed,0x77ef,0x80f8,0x8105,0x8208,0x854e,
 128.343 +    0x90f7,0x93e1,0x97ff,0x9957,0x9a5a,0x4ef0,0x51dd,0x5c2d,0x6681,0x696d,
 128.344 +    0x5c40,0x66f2,0x6975,0x7389,0x6850,0x7c81,0x50c5,0x52e4,0x5747,0x5dfe,
 128.345 +    0x9326,0x65a4,0x6b23,0x6b3d,0x7434,0x7981,0x79bd,0x7b4b,0x7dca,0x82b9,
 128.346 +    0x83cc,0x887f,0x895f,0x8b39,0x8fd1,0x91d1,0x541f,0x9280,0x4e5d,0x5036,
 128.347 +    0x53e5,0x533a,0x72d7,0x7396,0x77e9,0x82e6,0x8eaf,0x99c6,0x99c8,0x99d2,
 128.348 +    0x5177,0x611a,0x865e,0x55b0,0x7a7a,0x5076,0x5bd3,0x9047,0x9685,0x4e32,
 128.349 +    0x6adb,0x91e7,0x5c51,0x5c48
 128.350 +  },
 128.351 +  {				/* ku 17 */
 128.352 +    0x6398,0x7a9f,0x6c93,0x9774,0x8f61,0x7aaa,0x718a,0x9688,0x7c82,0x6817,
 128.353 +    0x7e70,0x6851,0x936c,0x52f2,0x541b,0x85ab,0x8a13,0x7fa4,0x8ecd,0x90e1,
 128.354 +    0x5366,0x8888,0x7941,0x4fc2,0x50be,0x5211,0x5144,0x5553,0x572d,0x73ea,
 128.355 +    0x578b,0x5951,0x5f62,0x5f84,0x6075,0x6176,0x6167,0x61a9,0x63b2,0x643a,
 128.356 +    0x656c,0x666f,0x6842,0x6e13,0x7566,0x7a3d,0x7cfb,0x7d4c,0x7d99,0x7e4b,
 128.357 +    0x7f6b,0x830e,0x834a,0x86cd,0x8a08,0x8a63,0x8b66,0x8efd,0x981a,0x9d8f,
 128.358 +    0x82b8,0x8fce,0x9be8,0x5287,0x621f,0x6483,0x6fc0,0x9699,0x6841,0x5091,
 128.359 +    0x6b20,0x6c7a,0x6f54,0x7a74,0x7d50,0x8840,0x8a23,0x6708,0x4ef6,0x5039,
 128.360 +    0x5026,0x5065,0x517c,0x5238,0x5263,0x55a7,0x570f,0x5805,0x5acc,0x5efa,
 128.361 +    0x61b2,0x61f8,0x62f3,0x6372
 128.362 +  },
 128.363 +  {				/* ku 18 */
 128.364 +    0x691c,0x6a29,0x727d,0x72ac,0x732e,0x7814,0x786f,0x7d79,0x770c,0x80a9,
 128.365 +    0x898b,0x8b19,0x8ce2,0x8ed2,0x9063,0x9375,0x967a,0x9855,0x9a13,0x9e78,
 128.366 +    0x5143,0x539f,0x53b3,0x5e7b,0x5f26,0x6e1b,0x6e90,0x7384,0x73fe,0x7d43,
 128.367 +    0x8237,0x8a00,0x8afa,0x9650,0x4e4e,0x500b,0x53e4,0x547c,0x56fa,0x59d1,
 128.368 +    0x5b64,0x5df1,0x5eab,0x5f27,0x6238,0x6545,0x67af,0x6e56,0x72d0,0x7cca,
 128.369 +    0x88b4,0x80a1,0x80e1,0x83f0,0x864e,0x8a87,0x8de8,0x9237,0x96c7,0x9867,
 128.370 +    0x9f13,0x4e94,0x4e92,0x4f0d,0x5348,0x5449,0x543e,0x5a2f,0x5f8c,0x5fa1,
 128.371 +    0x609f,0x68a7,0x6a8e,0x745a,0x7881,0x8a9e,0x8aa4,0x8b77,0x9190,0x4e5e,
 128.372 +    0x9bc9,0x4ea4,0x4f7c,0x4faf,0x5019,0x5016,0x5149,0x516c,0x529f,0x52b9,
 128.373 +    0x52fe,0x539a,0x53e3,0x5411
 128.374 +  },
 128.375 +  {				/* ku 19 */
 128.376 +    0x540e,0x5589,0x5751,0x57a2,0x597d,0x5b54,0x5b5d,0x5b8f,0x5de5,0x5de7,
 128.377 +    0x5df7,0x5e78,0x5e83,0x5e9a,0x5eb7,0x5f18,0x6052,0x614c,0x6297,0x62d8,
 128.378 +    0x63a7,0x653b,0x6602,0x6643,0x66f4,0x676d,0x6821,0x6897,0x69cb,0x6c5f,
 128.379 +    0x6d2a,0x6d69,0x6e2f,0x6e9d,0x7532,0x7687,0x786c,0x7a3f,0x7ce0,0x7d05,
 128.380 +    0x7d18,0x7d5e,0x7db1,0x8015,0x8003,0x80af,0x80b1,0x8154,0x818f,0x822a,
 128.381 +    0x8352,0x884c,0x8861,0x8b1b,0x8ca2,0x8cfc,0x90ca,0x9175,0x9271,0x783f,
 128.382 +    0x92fc,0x95a4,0x964d,0x9805,0x9999,0x9ad8,0x9d3b,0x525b,0x52ab,0x53f7,
 128.383 +    0x5408,0x58d5,0x62f7,0x6fe0,0x8c6a,0x8f5f,0x9eb9,0x514b,0x523b,0x544a,
 128.384 +    0x56fd,0x7a40,0x9177,0x9d60,0x9ed2,0x7344,0x6f09,0x8170,0x7511,0x5ffd,
 128.385 +    0x60da,0x9aa8,0x72db,0x8fbc
 128.386 +  },
 128.387 +  {				/* ku 1a */
 128.388 +    0x6b64,0x9803,0x4eca,0x56f0,0x5764,0x58be,0x5a5a,0x6068,0x61c7,0x660f,
 128.389 +    0x6606,0x6839,0x68b1,0x6df7,0x75d5,0x7d3a,0x826e,0x9b42,0x4e9b,0x4f50,
 128.390 +    0x53c9,0x5506,0x5d6f,0x5de6,0x5dee,0x67fb,0x6c99,0x7473,0x7802,0x8a50,
 128.391 +    0x9396,0x88df,0x5750,0x5ea7,0x632b,0x50b5,0x50ac,0x518d,0x6700,0x54c9,
 128.392 +    0x585e,0x59bb,0x5bb0,0x5f69,0x624d,0x63a1,0x683d,0x6b73,0x6e08,0x707d,
 128.393 +    0x91c7,0x7280,0x7815,0x7826,0x796d,0x658e,0x7d30,0x83dc,0x88c1,0x8f09,
 128.394 +    0x969b,0x5264,0x5728,0x6750,0x7f6a,0x8ca1,0x51b4,0x5742,0x962a,0x583a,
 128.395 +    0x698a,0x80b4,0x54b2,0x5d0e,0x57fc,0x7895,0x9dfa,0x4f5c,0x524a,0x548b,
 128.396 +    0x643e,0x6628,0x6714,0x67f5,0x7a84,0x7b56,0x7d22,0x932f,0x685c,0x9bad,
 128.397 +    0x7b39,0x5319,0x518a,0x5237
 128.398 +  },
 128.399 +  {				/* ku 1b */
 128.400 +    0x5bdf,0x62f6,0x64ae,0x64e6,0x672d,0x6bba,0x85a9,0x96d1,0x7690,0x9bd6,
 128.401 +    0x634c,0x9306,0x9bab,0x76bf,0x6652,0x4e09,0x5098,0x53c2,0x5c71,0x60e8,
 128.402 +    0x6492,0x6563,0x685f,0x71e6,0x73ca,0x7523,0x7b97,0x7e82,0x8695,0x8b83,
 128.403 +    0x8cdb,0x9178,0x9910,0x65ac,0x66ab,0x6b8b,0x4ed5,0x4ed4,0x4f3a,0x4f7f,
 128.404 +    0x523a,0x53f8,0x53f2,0x55e3,0x56db,0x58eb,0x59cb,0x59c9,0x59ff,0x5b50,
 128.405 +    0x5c4d,0x5e02,0x5e2b,0x5fd7,0x601d,0x6307,0x652f,0x5b5c,0x65af,0x65bd,
 128.406 +    0x65e8,0x679d,0x6b62,0x6b7b,0x6c0f,0x7345,0x7949,0x79c1,0x7cf8,0x7d19,
 128.407 +    0x7d2b,0x80a2,0x8102,0x81f3,0x8996,0x8a5e,0x8a69,0x8a66,0x8a8c,0x8aee,
 128.408 +    0x8cc7,0x8cdc,0x96cc,0x98fc,0x6b6f,0x4e8b,0x4f3c,0x4f8d,0x5150,0x5b57,
 128.409 +    0x5bfa,0x6148,0x6301,0x6642
 128.410 +  },
 128.411 +  {				/* ku 1c */
 128.412 +    0x6b21,0x6ecb,0x6cbb,0x723e,0x74bd,0x75d4,0x78c1,0x793a,0x800c,0x8033,
 128.413 +    0x81ea,0x8494,0x8f9e,0x6c50,0x9e7f,0x5f0f,0x8b58,0x9d2b,0x7afa,0x8ef8,
 128.414 +    0x5b8d,0x96eb,0x4e03,0x53f1,0x57f7,0x5931,0x5ac9,0x5ba4,0x6089,0x6e7f,
 128.415 +    0x6f06,0x75be,0x8cea,0x5b9f,0x8500,0x7be0,0x5072,0x67f4,0x829d,0x5c61,
 128.416 +    0x854a,0x7e1e,0x820e,0x5199,0x5c04,0x6368,0x8d66,0x659c,0x716e,0x793e,
 128.417 +    0x7d17,0x8005,0x8b1d,0x8eca,0x906e,0x86c7,0x90aa,0x501f,0x52fa,0x5c3a,
 128.418 +    0x6753,0x707c,0x7235,0x914c,0x91c8,0x932b,0x82e5,0x5bc2,0x5f31,0x60f9,
 128.419 +    0x4e3b,0x53d6,0x5b88,0x624b,0x6731,0x6b8a,0x72e9,0x73e0,0x7a2e,0x816b,
 128.420 +    0x8da3,0x9152,0x9996,0x5112,0x53d7,0x546a,0x5bff,0x6388,0x6a39,0x7dac,
 128.421 +    0x9700,0x56da,0x53ce,0x5468
 128.422 +  },
 128.423 +  {				/* ku 1d */
 128.424 +    0x5b97,0x5c31,0x5dde,0x4fee,0x6101,0x62fe,0x6d32,0x79c0,0x79cb,0x7d42,
 128.425 +    0x7e4d,0x7fd2,0x81ed,0x821f,0x8490,0x8846,0x8972,0x8b90,0x8e74,0x8f2f,
 128.426 +    0x9031,0x914b,0x916c,0x96c6,0x919c,0x4ec0,0x4f4f,0x5145,0x5341,0x5f93,
 128.427 +    0x620e,0x67d4,0x6c41,0x6e0b,0x7363,0x7e26,0x91cd,0x9283,0x53d4,0x5919,
 128.428 +    0x5bbf,0x6dd1,0x795d,0x7e2e,0x7c9b,0x587e,0x719f,0x51fa,0x8853,0x8ff0,
 128.429 +    0x4fca,0x5cfb,0x6625,0x77ac,0x7ae3,0x821c,0x99ff,0x51c6,0x5faa,0x65ec,
 128.430 +    0x696f,0x6b89,0x6df3,0x6e96,0x6f64,0x76fe,0x7d14,0x5de1,0x9075,0x9187,
 128.431 +    0x9806,0x51e6,0x521d,0x6240,0x6691,0x66d9,0x6e1a,0x5eb6,0x7dd2,0x7f72,
 128.432 +    0x66f8,0x85af,0x85f7,0x8af8,0x52a9,0x53d9,0x5973,0x5e8f,0x5f90,0x6055,
 128.433 +    0x92e4,0x9664,0x50b7,0x511f
 128.434 +  },
 128.435 +  {				/* ku 1e */
 128.436 +    0x52dd,0x5320,0x5347,0x53ec,0x54e8,0x5546,0x5531,0x5617,0x5968,0x59be,
 128.437 +    0x5a3c,0x5bb5,0x5c06,0x5c0f,0x5c11,0x5c1a,0x5e84,0x5e8a,0x5ee0,0x5f70,
 128.438 +    0x627f,0x6284,0x62db,0x638c,0x6377,0x6607,0x660c,0x662d,0x6676,0x677e,
 128.439 +    0x68a2,0x6a1f,0x6a35,0x6cbc,0x6d88,0x6e09,0x6e58,0x713c,0x7126,0x7167,
 128.440 +    0x75c7,0x7701,0x785d,0x7901,0x7965,0x79f0,0x7ae0,0x7b11,0x7ca7,0x7d39,
 128.441 +    0x8096,0x83d6,0x848b,0x8549,0x885d,0x88f3,0x8a1f,0x8a3c,0x8a54,0x8a73,
 128.442 +    0x8c61,0x8cde,0x91a4,0x9266,0x937e,0x9418,0x969c,0x9798,0x4e0a,0x4e08,
 128.443 +    0x4e1e,0x4e57,0x5197,0x5270,0x57ce,0x5834,0x58cc,0x5b22,0x5e38,0x60c5,
 128.444 +    0x64fe,0x6761,0x6756,0x6d44,0x72b6,0x7573,0x7a63,0x84b8,0x8b72,0x91b8,
 128.445 +    0x9320,0x5631,0x57f4,0x98fe
 128.446 +  },
 128.447 +  {				/* ku 1f */
 128.448 +    0x62ed,0x690d,0x6b96,0x71ed,0x7e54,0x8077,0x8272,0x89e6,0x98df,0x8755,
 128.449 +    0x8fb1,0x5c3b,0x4f38,0x4fe1,0x4fb5,0x5507,0x5a20,0x5bdd,0x5be9,0x5fc3,
 128.450 +    0x614e,0x632f,0x65b0,0x664b,0x68ee,0x699b,0x6d78,0x6df1,0x7533,0x75b9,
 128.451 +    0x771f,0x795e,0x79e6,0x7d33,0x81e3,0x82af,0x85aa,0x89aa,0x8a3a,0x8eab,
 128.452 +    0x8f9b,0x9032,0x91dd,0x9707,0x4eba,0x4ec1,0x5203,0x5875,0x58ec,0x5c0b,
 128.453 +    0x751a,0x5c3d,0x814e,0x8a0a,0x8fc5,0x9663,0x976d,0x7b25,0x8acf,0x9808,
 128.454 +    0x9162,0x56f3,0x53a8,0x9017,0x5439,0x5782,0x5e25,0x63a8,0x6c34,0x708a,
 128.455 +    0x7761,0x7c8b,0x7fe0,0x8870,0x9042,0x9154,0x9310,0x9318,0x968f,0x745e,
 128.456 +    0x9ac4,0x5d07,0x5d69,0x6570,0x67a2,0x8da8,0x96db,0x636e,0x6749,0x6919,
 128.457 +    0x83c5,0x9817,0x96c0,0x88fe
 128.458 +  },
 128.459 +  {				/* ku 20 */
 128.460 +    0x6f84,0x647a,0x5bf8,0x4e16,0x702c,0x755d,0x662f,0x51c4,0x5236,0x52e2,
 128.461 +    0x59d3,0x5f81,0x6027,0x6210,0x653f,0x6574,0x661f,0x6674,0x68f2,0x6816,
 128.462 +    0x6b63,0x6e05,0x7272,0x751f,0x76db,0x7cbe,0x8056,0x58f0,0x88fd,0x897f,
 128.463 +    0x8aa0,0x8a93,0x8acb,0x901d,0x9192,0x9752,0x9759,0x6589,0x7a0e,0x8106,
 128.464 +    0x96bb,0x5e2d,0x60dc,0x621a,0x65a5,0x6614,0x6790,0x77f3,0x7a4d,0x7c4d,
 128.465 +    0x7e3e,0x810a,0x8cac,0x8d64,0x8de1,0x8e5f,0x78a9,0x5207,0x62d9,0x63a5,
 128.466 +    0x6442,0x6298,0x8a2d,0x7a83,0x7bc0,0x8aac,0x96ea,0x7d76,0x820c,0x8749,
 128.467 +    0x4ed9,0x5148,0x5343,0x5360,0x5ba3,0x5c02,0x5c16,0x5ddd,0x6226,0x6247,
 128.468 +    0x64b0,0x6813,0x6834,0x6cc9,0x6d45,0x6d17,0x67d3,0x6f5c,0x714e,0x717d,
 128.469 +    0x65cb,0x7a7f,0x7bad,0x7dda
 128.470 +  },
 128.471 +  {				/* ku 21 */
 128.472 +    0x7e4a,0x7fa8,0x817a,0x821b,0x8239,0x85a6,0x8a6e,0x8cce,0x8df5,0x9078,
 128.473 +    0x9077,0x92ad,0x9291,0x9583,0x9bae,0x524d,0x5584,0x6f38,0x7136,0x5168,
 128.474 +    0x7985,0x7e55,0x81b3,0x7cce,0x564c,0x5851,0x5ca8,0x63aa,0x66fe,0x66fd,
 128.475 +    0x695a,0x72d9,0x758f,0x758e,0x790e,0x7956,0x79df,0x7c97,0x7d20,0x7d44,
 128.476 +    0x8607,0x8a34,0x963b,0x9061,0x9f20,0x50e7,0x5275,0x53cc,0x53e2,0x5009,
 128.477 +    0x55aa,0x58ee,0x594f,0x723d,0x5b8b,0x5c64,0x531d,0x60e3,0x60f3,0x635c,
 128.478 +    0x6383,0x633f,0x63bb,0x64cd,0x65e9,0x66f9,0x5de3,0x69cd,0x69fd,0x6f15,
 128.479 +    0x71e5,0x4e89,0x75e9,0x76f8,0x7a93,0x7cdf,0x7dcf,0x7d9c,0x8061,0x8349,
 128.480 +    0x8358,0x846c,0x84bc,0x85fb,0x88c5,0x8d70,0x9001,0x906d,0x9397,0x971c,
 128.481 +    0x9a12,0x50cf,0x5897,0x618e
 128.482 +  },
 128.483 +  {				/* ku 22 */
 128.484 +    0x81d3,0x8535,0x8d08,0x9020,0x4fc3,0x5074,0x5247,0x5373,0x606f,0x6349,
 128.485 +    0x675f,0x6e2c,0x8db3,0x901f,0x4fd7,0x5c5e,0x8cca,0x65cf,0x7d9a,0x5352,
 128.486 +    0x8896,0x5176,0x63c3,0x5b58,0x5b6b,0x5c0a,0x640d,0x6751,0x905c,0x4ed6,
 128.487 +    0x591a,0x592a,0x6c70,0x8a51,0x553e,0x5815,0x59a5,0x60f0,0x6253,0x67c1,
 128.488 +    0x8235,0x6955,0x9640,0x99c4,0x9a28,0x4f53,0x5806,0x5bfe,0x8010,0x5cb1,
 128.489 +    0x5e2f,0x5f85,0x6020,0x614b,0x6234,0x66ff,0x6cf0,0x6ede,0x80ce,0x817f,
 128.490 +    0x82d4,0x888b,0x8cb8,0x9000,0x902e,0x968a,0x9edb,0x9bdb,0x4ee3,0x53f0,
 128.491 +    0x5927,0x7b2c,0x918d,0x984c,0x9df9,0x6edd,0x7027,0x5353,0x5544,0x5b85,
 128.492 +    0x6258,0x629e,0x62d3,0x6ca2,0x6fef,0x7422,0x8a17,0x9438,0x6fc1,0x8afe,
 128.493 +    0x8338,0x51e7,0x86f8,0x53ea
 128.494 +  },
 128.495 +  {				/* ku 23 */
 128.496 +    0x53e9,0x4f46,0x9054,0x8fb0,0x596a,0x8131,0x5dfd,0x7aea,0x8fbf,0x68da,
 128.497 +    0x8c37,0x72f8,0x9c48,0x6a3d,0x8ab0,0x4e39,0x5358,0x5606,0x5766,0x62c5,
 128.498 +    0x63a2,0x65e6,0x6b4e,0x6de1,0x6e5b,0x70ad,0x77ed,0x7aef,0x7baa,0x7dbb,
 128.499 +    0x803d,0x80c6,0x86cb,0x8a95,0x935b,0x56e3,0x58c7,0x5f3e,0x65ad,0x6696,
 128.500 +    0x6a80,0x6bb5,0x7537,0x8ac7,0x5024,0x77e5,0x5730,0x5f1b,0x6065,0x667a,
 128.501 +    0x6c60,0x75f4,0x7a1a,0x7f6e,0x81f4,0x8718,0x9045,0x99b3,0x7bc9,0x755c,
 128.502 +    0x7af9,0x7b51,0x84c4,0x9010,0x79e9,0x7a92,0x8336,0x5ae1,0x7740,0x4e2d,
 128.503 +    0x4ef2,0x5b99,0x5fe0,0x62bd,0x663c,0x67f1,0x6ce8,0x866b,0x8877,0x8a3b,
 128.504 +    0x914e,0x92f3,0x99d0,0x6a17,0x7026,0x732a,0x82e7,0x8457,0x8caf,0x4e01,
 128.505 +    0x5146,0x51cb,0x558b,0x5bf5
 128.506 +  },
 128.507 +  {				/* ku 24 */
 128.508 +    0x5e16,0x5e33,0x5e81,0x5f14,0x5f35,0x5f6b,0x5fb4,0x61f2,0x6311,0x66a2,
 128.509 +    0x671d,0x6f6e,0x7252,0x753a,0x773a,0x8074,0x8139,0x8178,0x8776,0x8abf,
 128.510 +    0x8adc,0x8d85,0x8df3,0x929a,0x9577,0x9802,0x9ce5,0x52c5,0x6357,0x76f4,
 128.511 +    0x6715,0x6c88,0x73cd,0x8cc3,0x93ae,0x9673,0x6d25,0x589c,0x690e,0x69cc,
 128.512 +    0x8ffd,0x939a,0x75db,0x901a,0x585a,0x6802,0x63b4,0x69fb,0x4f43,0x6f2c,
 128.513 +    0x67d8,0x8fbb,0x8526,0x7db4,0x9354,0x693f,0x6f70,0x576a,0x58f7,0x5b2c,
 128.514 +    0x7d2c,0x722a,0x540a,0x91e3,0x9db4,0x4ead,0x4f4e,0x505c,0x5075,0x5243,
 128.515 +    0x8c9e,0x5448,0x5824,0x5b9a,0x5e1d,0x5e95,0x5ead,0x5ef7,0x5f1f,0x608c,
 128.516 +    0x62b5,0x633a,0x63d0,0x68af,0x6c40,0x7887,0x798e,0x7a0b,0x7de0,0x8247,
 128.517 +    0x8a02,0x8ae6,0x8e44,0x9013
 128.518 +  },
 128.519 +  {				/* ku 25 */
 128.520 +    0x90b8,0x912d,0x91d8,0x9f0e,0x6ce5,0x6458,0x64e2,0x6575,0x6ef4,0x7684,
 128.521 +    0x7b1b,0x9069,0x93d1,0x6eba,0x54f2,0x5fb9,0x64a4,0x8f4d,0x8fed,0x9244,
 128.522 +    0x5178,0x586b,0x5929,0x5c55,0x5e97,0x6dfb,0x7e8f,0x751c,0x8cbc,0x8ee2,
 128.523 +    0x985b,0x70b9,0x4f1d,0x6bbf,0x6fb1,0x7530,0x96fb,0x514e,0x5410,0x5835,
 128.524 +    0x5857,0x59ac,0x5c60,0x5f92,0x6597,0x675c,0x6e21,0x767b,0x83df,0x8ced,
 128.525 +    0x9014,0x90fd,0x934d,0x7825,0x783a,0x52aa,0x5ea6,0x571f,0x5974,0x6012,
 128.526 +    0x5012,0x515a,0x51ac,0x51cd,0x5200,0x5510,0x5854,0x5858,0x5957,0x5b95,
 128.527 +    0x5cf6,0x5d8b,0x60bc,0x6295,0x642d,0x6771,0x6843,0x68bc,0x68df,0x76d7,
 128.528 +    0x6dd8,0x6e6f,0x6d9b,0x706f,0x71c8,0x5f53,0x75d8,0x7977,0x7b49,0x7b54,
 128.529 +    0x7b52,0x7cd6,0x7d71,0x5230
 128.530 +  },
 128.531 +  {				/* ku 26 */
 128.532 +    0x8463,0x8569,0x85e4,0x8a0e,0x8b04,0x8c46,0x8e0f,0x9003,0x900f,0x9419,
 128.533 +    0x9676,0x982d,0x9a30,0x95d8,0x50cd,0x52d5,0x540c,0x5802,0x5c0e,0x61a7,
 128.534 +    0x649e,0x6d1e,0x77b3,0x7ae5,0x80f4,0x8404,0x9053,0x9285,0x5ce0,0x9d07,
 128.535 +    0x533f,0x5f97,0x5fb3,0x6d9c,0x7279,0x7763,0x79bf,0x7be4,0x6bd2,0x72ec,
 128.536 +    0x8aad,0x6803,0x6a61,0x51f8,0x7a81,0x6934,0x5c4a,0x9cf6,0x82eb,0x5bc5,
 128.537 +    0x9149,0x701e,0x5678,0x5c6f,0x60c7,0x6566,0x6c8c,0x8c5a,0x9041,0x9813,
 128.538 +    0x5451,0x66c7,0x920d,0x5948,0x90a3,0x5185,0x4e4d,0x51ea,0x8599,0x8b0e,
 128.539 +    0x7058,0x637a,0x934b,0x6962,0x99b4,0x7e04,0x7577,0x5357,0x6960,0x8edf,
 128.540 +    0x96e3,0x6c5d,0x4e8c,0x5c3c,0x5f10,0x8fe9,0x5302,0x8cd1,0x8089,0x8679,
 128.541 +    0x5eff,0x65e5,0x4e73,0x5165
 128.542 +  },
 128.543 +  {				/* ku 27 */
 128.544 +    0x5982,0x5c3f,0x97ee,0x4efb,0x598a,0x5fcd,0x8a8d,0x6fe1,0x79b0,0x7962,
 128.545 +    0x5be7,0x8471,0x732b,0x71b1,0x5e74,0x5ff5,0x637b,0x649a,0x71c3,0x7c98,
 128.546 +    0x4e43,0x5efc,0x4e4b,0x57dc,0x56a2,0x60a9,0x6fc3,0x7d0d,0x80fd,0x8133,
 128.547 +    0x81bf,0x8fb2,0x8997,0x86a4,0x5df4,0x628a,0x64ad,0x8987,0x6777,0x6ce2,
 128.548 +    0x6d3e,0x7436,0x7834,0x5a46,0x7f75,0x82ad,0x99ac,0x4ff3,0x5ec3,0x62dd,
 128.549 +    0x6392,0x6557,0x676f,0x76c3,0x724c,0x80cc,0x80ba,0x8f29,0x914d,0x500d,
 128.550 +    0x57f9,0x5a92,0x6885,0x6973,0x7164,0x72fd,0x8cb7,0x58f2,0x8ce0,0x966a,
 128.551 +    0x9019,0x877f,0x79e4,0x77e7,0x8429,0x4f2f,0x5265,0x535a,0x62cd,0x67cf,
 128.552 +    0x6cca,0x767d,0x7b94,0x7c95,0x8236,0x8584,0x8feb,0x66dd,0x6f20,0x7206,
 128.553 +    0x7e1b,0x83ab,0x99c1,0x9ea6
 128.554 +  },
 128.555 +  {				/* ku 28 */
 128.556 +    0x51fd,0x7bb1,0x7872,0x7bb8,0x8087,0x7b48,0x6ae8,0x5e61,0x808c,0x7551,
 128.557 +    0x7560,0x516b,0x9262,0x6e8c,0x767a,0x9197,0x9aea,0x4f10,0x7f70,0x629c,
 128.558 +    0x7b4f,0x95a5,0x9ce9,0x567a,0x5859,0x86e4,0x96bc,0x4f34,0x5224,0x534a,
 128.559 +    0x53cd,0x53db,0x5e06,0x642c,0x6591,0x677f,0x6c3e,0x6c4e,0x7248,0x72af,
 128.560 +    0x73ed,0x7554,0x7e41,0x822c,0x85e9,0x8ca9,0x7bc4,0x91c6,0x7169,0x9812,
 128.561 +    0x98ef,0x633d,0x6669,0x756a,0x76e4,0x78d0,0x8543,0x86ee,0x532a,0x5351,
 128.562 +    0x5426,0x5983,0x5e87,0x5f7c,0x60b2,0x6249,0x6279,0x62ab,0x6590,0x6bd4,
 128.563 +    0x6ccc,0x75b2,0x76ae,0x7891,0x79d8,0x7dcb,0x7f77,0x80a5,0x88ab,0x8ab9,
 128.564 +    0x8cbb,0x907f,0x975e,0x98db,0x6a0b,0x7c38,0x5099,0x5c3e,0x5fae,0x6787,
 128.565 +    0x6bd8,0x7435,0x7709,0x7f8e
 128.566 +  },
 128.567 +  {				/* ku 29 */
 128.568 +    0x9f3b,0x67ca,0x7a17,0x5339,0x758b,0x9aed,0x5f66,0x819d,0x83f1,0x8098,
 128.569 +    0x5f3c,0x5fc5,0x7562,0x7b46,0x903c,0x6867,0x59eb,0x5a9b,0x7d10,0x767e,
 128.570 +    0x8b2c,0x4ff5,0x5f6a,0x6a19,0x6c37,0x6f02,0x74e2,0x7968,0x8868,0x8a55,
 128.571 +    0x8c79,0x5edf,0x63cf,0x75c5,0x79d2,0x82d7,0x9328,0x92f2,0x849c,0x86ed,
 128.572 +    0x9c2d,0x54c1,0x5f6c,0x658c,0x6d5c,0x7015,0x8ca7,0x8cd3,0x983b,0x654f,
 128.573 +    0x74f6,0x4e0d,0x4ed8,0x57e0,0x592b,0x5a66,0x5bcc,0x51a8,0x5e03,0x5e9c,
 128.574 +    0x6016,0x6276,0x6577,0x65a7,0x666e,0x6d6e,0x7236,0x7b26,0x8150,0x819a,
 128.575 +    0x8299,0x8b5c,0x8ca0,0x8ce6,0x8d74,0x961c,0x9644,0x4fae,0x64ab,0x6b66,
 128.576 +    0x821e,0x8461,0x856a,0x90e8,0x5c01,0x6953,0x98a8,0x847a,0x8557,0x4f0f,
 128.577 +    0x526f,0x5fa9,0x5e45,0x670d
 128.578 +  },
 128.579 +  {				/* ku 2a */
 128.580 +    0x798f,0x8179,0x8907,0x8986,0x6df5,0x5f17,0x6255,0x6cb8,0x4ecf,0x7269,
 128.581 +    0x9b92,0x5206,0x543b,0x5674,0x58b3,0x61a4,0x626e,0x711a,0x596e,0x7c89,
 128.582 +    0x7cde,0x7d1b,0x96f0,0x6587,0x805e,0x4e19,0x4f75,0x5175,0x5840,0x5e63,
 128.583 +    0x5e73,0x5f0a,0x67c4,0x4e26,0x853d,0x9589,0x965b,0x7c73,0x9801,0x50fb,
 128.584 +    0x58c1,0x7656,0x78a7,0x5225,0x77a5,0x8511,0x7b86,0x504f,0x5909,0x7247,
 128.585 +    0x7bc7,0x7de8,0x8fba,0x8fd4,0x904d,0x4fbf,0x52c9,0x5a29,0x5f01,0x97ad,
 128.586 +    0x4fdd,0x8217,0x92ea,0x5703,0x6355,0x6b69,0x752b,0x88dc,0x8f14,0x7a42,
 128.587 +    0x52df,0x5893,0x6155,0x620a,0x66ae,0x6bcd,0x7c3f,0x83e9,0x5023,0x4ff8,
 128.588 +    0x5305,0x5446,0x5831,0x5949,0x5b9d,0x5cf0,0x5cef,0x5d29,0x5e96,0x62b1,
 128.589 +    0x6367,0x653e,0x65b9,0x670b
 128.590 +  },
 128.591 +  {				/* ku 2b */
 128.592 +    0x6cd5,0x6ce1,0x70f9,0x7832,0x7e2b,0x80de,0x82b3,0x840c,0x84ec,0x8702,
 128.593 +    0x8912,0x8a2a,0x8c4a,0x90a6,0x92d2,0x98fd,0x9cf3,0x9d6c,0x4e4f,0x4ea1,
 128.594 +    0x508d,0x5256,0x574a,0x59a8,0x5e3d,0x5fd8,0x5fd9,0x623f,0x66b4,0x671b,
 128.595 +    0x67d0,0x68d2,0x5192,0x7d21,0x80aa,0x81a8,0x8b00,0x8c8c,0x8cbf,0x927e,
 128.596 +    0x9632,0x5420,0x982c,0x5317,0x50d5,0x535c,0x58a8,0x64b2,0x6734,0x7267,
 128.597 +    0x7766,0x7a46,0x91e6,0x52c3,0x6ca1,0x6b86,0x5800,0x5e4c,0x5954,0x672c,
 128.598 +    0x7ffb,0x51e1,0x76c6,0x6469,0x78e8,0x9b54,0x9ebb,0x57cb,0x59b9,0x6627,
 128.599 +    0x679a,0x6bce,0x54e9,0x69d9,0x5e55,0x819c,0x6795,0x9baa,0x67fe,0x9c52,
 128.600 +    0x685d,0x4ea6,0x4fe3,0x53c8,0x62b9,0x672b,0x6cab,0x8fc4,0x4fad,0x7e6d,
 128.601 +    0x9ebf,0x4e07,0x6162,0x6e80
 128.602 +  },
 128.603 +  {				/* ku 2c */
 128.604 +    0x6f2b,0x8513,0x5473,0x672a,0x9b45,0x5df3,0x7b95,0x5cac,0x5bc6,0x871c,
 128.605 +    0x6e4a,0x84d1,0x7a14,0x8108,0x5999,0x7c8d,0x6c11,0x7720,0x52d9,0x5922,
 128.606 +    0x7121,0x725f,0x77db,0x9727,0x9d61,0x690b,0x5a7f,0x5a18,0x51a5,0x540d,
 128.607 +    0x547d,0x660e,0x76df,0x8ff7,0x9298,0x9cf4,0x59ea,0x725d,0x6ec5,0x514d,
 128.608 +    0x68c9,0x7dbf,0x7dec,0x9762,0x9eba,0x6478,0x6a21,0x8302,0x5984,0x5b5f,
 128.609 +    0x6bdb,0x731b,0x76f2,0x7db2,0x8017,0x8499,0x5132,0x6728,0x9ed9,0x76ee,
 128.610 +    0x6762,0x52ff,0x9905,0x5c24,0x623b,0x7c7e,0x8cb0,0x554f,0x60b6,0x7d0b,
 128.611 +    0x9580,0x5301,0x4e5f,0x51b6,0x591c,0x723a,0x8036,0x91ce,0x5f25,0x77e2,
 128.612 +    0x5384,0x5f79,0x7d04,0x85ac,0x8a33,0x8e8d,0x9756,0x67f3,0x85ae,0x9453,
 128.613 +    0x6109,0x6108,0x6cb9,0x7652
 128.614 +  },
 128.615 +  {				/* ku 2d */
 128.616 +    0x8aed,0x8f38,0x552f,0x4f51,0x512a,0x52c7,0x53cb,0x5ba5,0x5e7d,0x60a0,
 128.617 +    0x6182,0x63d6,0x6709,0x67da,0x6e67,0x6d8c,0x7336,0x7337,0x7531,0x7950,
 128.618 +    0x88d5,0x8a98,0x904a,0x9091,0x90f5,0x96c4,0x878d,0x5915,0x4e88,0x4f59,
 128.619 +    0x4e0e,0x8a89,0x8f3f,0x9810,0x50ad,0x5e7c,0x5996,0x5bb9,0x5eb8,0x63da,
 128.620 +    0x63fa,0x64c1,0x66dc,0x694a,0x69d8,0x6d0b,0x6eb6,0x7194,0x7528,0x7aaf,
 128.621 +    0x7f8a,0x8000,0x8449,0x84c9,0x8981,0x8b21,0x8e0a,0x9065,0x967d,0x990a,
 128.622 +    0x617e,0x6291,0x6b32,0x6c83,0x6d74,0x7fcc,0x7ffc,0x6dc0,0x7f85,0x87ba,
 128.623 +    0x88f8,0x6765,0x83b1,0x983c,0x96f7,0x6d1b,0x7d61,0x843d,0x916a,0x4e71,
 128.624 +    0x5375,0x5d50,0x6b04,0x6feb,0x85cd,0x862d,0x89a7,0x5229,0x540f,0x5c65,
 128.625 +    0x674e,0x68a8,0x7406,0x7483
 128.626 +  },
 128.627 +  {				/* ku 2e */
 128.628 +    0x75e2,0x88cf,0x88e1,0x91cc,0x96e2,0x9678,0x5f8b,0x7387,0x7acb,0x844e,
 128.629 +    0x63a0,0x7565,0x5289,0x6d41,0x6e9c,0x7409,0x7559,0x786b,0x7c92,0x9686,
 128.630 +    0x7adc,0x9f8d,0x4fb6,0x616e,0x65c5,0x865c,0x4e86,0x4eae,0x50da,0x4e21,
 128.631 +    0x51cc,0x5bee,0x6599,0x6881,0x6dbc,0x731f,0x7642,0x77ad,0x7a1c,0x7ce7,
 128.632 +    0x826f,0x8ad2,0x907c,0x91cf,0x9675,0x9818,0x529b,0x7dd1,0x502b,0x5398,
 128.633 +    0x6797,0x6dcb,0x71d0,0x7433,0x81e8,0x8f2a,0x96a3,0x9c57,0x9e9f,0x7460,
 128.634 +    0x5841,0x6d99,0x7d2f,0x985e,0x4ee4,0x4f36,0x4f8b,0x51b7,0x52b1,0x5dba,
 128.635 +    0x601c,0x73b2,0x793c,0x82d3,0x9234,0x96b7,0x96f6,0x970a,0x9e97,0x9f62,
 128.636 +    0x66a6,0x6b74,0x5217,0x52a3,0x70c8,0x88c2,0x5ec9,0x604b,0x6190,0x6f23,
 128.637 +    0x7149,0x7c3e,0x7df4,0x806f
 128.638 +  },
 128.639 +  {				/* ku 2f */
 128.640 +    0x84ee,0x9023,0x932c,0x5442,0x9b6f,0x6ad3,0x7089,0x8cc2,0x8def,0x9732,
 128.641 +    0x52b4,0x5a41,0x5eca,0x5f04,0x6717,0x697c,0x6994,0x6d6a,0x6f0f,0x7262,
 128.642 +    0x72fc,0x7bed,0x8001,0x807e,0x874b,0x90ce,0x516d,0x9e93,0x7984,0x808b,
 128.643 +    0x9332,0x8ad6,0x502d,0x548c,0x8a71,0x6b6a,0x8cc4,0x8107,0x60d1,0x67a0,
 128.644 +    0x9df2,0x4e99,0x4e98,0x9c10,0x8a6b,0x85c1,0x8568,0x6900,0x6e7e,0x7897,
 128.645 +    0x8155,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.646 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.647 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.648 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 128.649 +    UBOGON,UBOGON,UBOGON,UBOGON
 128.650 +  },
 128.651 +  {				/* ku 30 */
 128.652 +    0x5f0c,0x4e10,0x4e15,0x4e2a,0x4e31,0x4e36,0x4e3c,0x4e3f,0x4e42,0x4e56,
 128.653 +    0x4e58,0x4e82,0x4e85,0x8c6b,0x4e8a,0x8212,0x5f0d,0x4e8e,0x4e9e,0x4e9f,
 128.654 +    0x4ea0,0x4ea2,0x4eb0,0x4eb3,0x4eb6,0x4ece,0x4ecd,0x4ec4,0x4ec6,0x4ec2,
 128.655 +    0x4ed7,0x4ede,0x4eed,0x4edf,0x4ef7,0x4f09,0x4f5a,0x4f30,0x4f5b,0x4f5d,
 128.656 +    0x4f57,0x4f47,0x4f76,0x4f88,0x4f8f,0x4f98,0x4f7b,0x4f69,0x4f70,0x4f91,
 128.657 +    0x4f6f,0x4f86,0x4f96,0x5118,0x4fd4,0x4fdf,0x4fce,0x4fd8,0x4fdb,0x4fd1,
 128.658 +    0x4fda,0x4fd0,0x4fe4,0x4fe5,0x501a,0x5028,0x5014,0x502a,0x5025,0x5005,
 128.659 +    0x4f1c,0x4ff6,0x5021,0x5029,0x502c,0x4ffe,0x4fef,0x5011,0x5006,0x5043,
 128.660 +    0x5047,0x6703,0x5055,0x5050,0x5048,0x505a,0x5056,0x506c,0x5078,0x5080,
 128.661 +    0x509a,0x5085,0x50b4,0x50b2
 128.662 +  },
 128.663 +  {				/* ku 31 */
 128.664 +    0x50c9,0x50ca,0x50b3,0x50c2,0x50d6,0x50de,0x50e5,0x50ed,0x50e3,0x50ee,
 128.665 +    0x50f9,0x50f5,0x5109,0x5101,0x5102,0x5116,0x5115,0x5114,0x511a,0x5121,
 128.666 +    0x513a,0x5137,0x513c,0x513b,0x513f,0x5140,0x5152,0x514c,0x5154,0x5162,
 128.667 +    0x7af8,0x5169,0x516a,0x516e,0x5180,0x5182,0x56d8,0x518c,0x5189,0x518f,
 128.668 +    0x5191,0x5193,0x5195,0x5196,0x51a4,0x51a6,0x51a2,0x51a9,0x51aa,0x51ab,
 128.669 +    0x51b3,0x51b1,0x51b2,0x51b0,0x51b5,0x51bd,0x51c5,0x51c9,0x51db,0x51e0,
 128.670 +    0x8655,0x51e9,0x51ed,0x51f0,0x51f5,0x51fe,0x5204,0x520b,0x5214,0x520e,
 128.671 +    0x5227,0x522a,0x522e,0x5233,0x5239,0x524f,0x5244,0x524b,0x524c,0x525e,
 128.672 +    0x5254,0x526a,0x5274,0x5269,0x5273,0x527f,0x527d,0x528d,0x5294,0x5292,
 128.673 +    0x5271,0x5288,0x5291,0x8fa8
 128.674 +  },
 128.675 +  {				/* ku 32 */
 128.676 +    0x8fa7,0x52ac,0x52ad,0x52bc,0x52b5,0x52c1,0x52cd,0x52d7,0x52de,0x52e3,
 128.677 +    0x52e6,0x98ed,0x52e0,0x52f3,0x52f5,0x52f8,0x52f9,0x5306,0x5308,0x7538,
 128.678 +    0x530d,0x5310,0x530f,0x5315,0x531a,0x5323,0x532f,0x5331,0x5333,0x5338,
 128.679 +    0x5340,0x5346,0x5345,0x4e17,0x5349,0x534d,0x51d6,0x535e,0x5369,0x536e,
 128.680 +    0x5918,0x537b,0x5377,0x5382,0x5396,0x53a0,0x53a6,0x53a5,0x53ae,0x53b0,
 128.681 +    0x53b6,0x53c3,0x7c12,0x96d9,0x53df,0x66fc,0x71ee,0x53ee,0x53e8,0x53ed,
 128.682 +    0x53fa,0x5401,0x543d,0x5440,0x542c,0x542d,0x543c,0x542e,0x5436,0x5429,
 128.683 +    0x541d,0x544e,0x548f,0x5475,0x548e,0x545f,0x5471,0x5477,0x5470,0x5492,
 128.684 +    0x547b,0x5480,0x5476,0x5484,0x5490,0x5486,0x54c7,0x54a2,0x54b8,0x54a5,
 128.685 +    0x54ac,0x54c4,0x54c8,0x54a8
 128.686 +  },
 128.687 +  {				/* ku 33 */
 128.688 +    0x54ab,0x54c2,0x54a4,0x54be,0x54bc,0x54d8,0x54e5,0x54e6,0x550f,0x5514,
 128.689 +    0x54fd,0x54ee,0x54ed,0x54fa,0x54e2,0x5539,0x5540,0x5563,0x554c,0x552e,
 128.690 +    0x555c,0x5545,0x5556,0x5557,0x5538,0x5533,0x555d,0x5599,0x5580,0x54af,
 128.691 +    0x558a,0x559f,0x557b,0x557e,0x5598,0x559e,0x55ae,0x557c,0x5583,0x55a9,
 128.692 +    0x5587,0x55a8,0x55da,0x55c5,0x55df,0x55c4,0x55dc,0x55e4,0x55d4,0x5614,
 128.693 +    0x55f7,0x5616,0x55fe,0x55fd,0x561b,0x55f9,0x564e,0x5650,0x71df,0x5634,
 128.694 +    0x5636,0x5632,0x5638,0x566b,0x5664,0x562f,0x566c,0x566a,0x5686,0x5680,
 128.695 +    0x568a,0x56a0,0x5694,0x568f,0x56a5,0x56ae,0x56b6,0x56b4,0x56c2,0x56bc,
 128.696 +    0x56c1,0x56c3,0x56c0,0x56c8,0x56ce,0x56d1,0x56d3,0x56d7,0x56ee,0x56f9,
 128.697 +    0x5700,0x56ff,0x5704,0x5709
 128.698 +  },
 128.699 +  {				/* ku 34 */
 128.700 +    0x5708,0x570b,0x570d,0x5713,0x5718,0x5716,0x55c7,0x571c,0x5726,0x5737,
 128.701 +    0x5738,0x574e,0x573b,0x5740,0x574f,0x5769,0x57c0,0x5788,0x5761,0x577f,
 128.702 +    0x5789,0x5793,0x57a0,0x57b3,0x57a4,0x57aa,0x57b0,0x57c3,0x57c6,0x57d4,
 128.703 +    0x57d2,0x57d3,0x580a,0x57d6,0x57e3,0x580b,0x5819,0x581d,0x5872,0x5821,
 128.704 +    0x5862,0x584b,0x5870,0x6bc0,0x5852,0x583d,0x5879,0x5885,0x58b9,0x589f,
 128.705 +    0x58ab,0x58ba,0x58de,0x58bb,0x58b8,0x58ae,0x58c5,0x58d3,0x58d1,0x58d7,
 128.706 +    0x58d9,0x58d8,0x58e5,0x58dc,0x58e4,0x58df,0x58ef,0x58fa,0x58f9,0x58fb,
 128.707 +    0x58fc,0x58fd,0x5902,0x590a,0x5910,0x591b,0x68a6,0x5925,0x592c,0x592d,
 128.708 +    0x5932,0x5938,0x593e,0x7ad2,0x5955,0x5950,0x594e,0x595a,0x5958,0x5962,
 128.709 +    0x5960,0x5967,0x596c,0x5969
 128.710 +  },
 128.711 +  {				/* ku 35 */
 128.712 +    0x5978,0x5981,0x599d,0x4f5e,0x4fab,0x59a3,0x59b2,0x59c6,0x59e8,0x59dc,
 128.713 +    0x598d,0x59d9,0x59da,0x5a25,0x5a1f,0x5a11,0x5a1c,0x5a09,0x5a1a,0x5a40,
 128.714 +    0x5a6c,0x5a49,0x5a35,0x5a36,0x5a62,0x5a6a,0x5a9a,0x5abc,0x5abe,0x5acb,
 128.715 +    0x5ac2,0x5abd,0x5ae3,0x5ad7,0x5ae6,0x5ae9,0x5ad6,0x5afa,0x5afb,0x5b0c,
 128.716 +    0x5b0b,0x5b16,0x5b32,0x5ad0,0x5b2a,0x5b36,0x5b3e,0x5b43,0x5b45,0x5b40,
 128.717 +    0x5b51,0x5b55,0x5b5a,0x5b5b,0x5b65,0x5b69,0x5b70,0x5b73,0x5b75,0x5b78,
 128.718 +    0x6588,0x5b7a,0x5b80,0x5b83,0x5ba6,0x5bb8,0x5bc3,0x5bc7,0x5bc9,0x5bd4,
 128.719 +    0x5bd0,0x5be4,0x5be6,0x5be2,0x5bde,0x5be5,0x5beb,0x5bf0,0x5bf6,0x5bf3,
 128.720 +    0x5c05,0x5c07,0x5c08,0x5c0d,0x5c13,0x5c20,0x5c22,0x5c28,0x5c38,0x5c39,
 128.721 +    0x5c41,0x5c46,0x5c4e,0x5c53
 128.722 +  },
 128.723 +  {				/* ku 36 */
 128.724 +    0x5c50,0x5c4f,0x5b71,0x5c6c,0x5c6e,0x4e62,0x5c76,0x5c79,0x5c8c,0x5c91,
 128.725 +    0x5c94,0x599b,0x5cab,0x5cbb,0x5cb6,0x5cbc,0x5cb7,0x5cc5,0x5cbe,0x5cc7,
 128.726 +    0x5cd9,0x5ce9,0x5cfd,0x5cfa,0x5ced,0x5d8c,0x5cea,0x5d0b,0x5d15,0x5d17,
 128.727 +    0x5d5c,0x5d1f,0x5d1b,0x5d11,0x5d14,0x5d22,0x5d1a,0x5d19,0x5d18,0x5d4c,
 128.728 +    0x5d52,0x5d4e,0x5d4b,0x5d6c,0x5d73,0x5d76,0x5d87,0x5d84,0x5d82,0x5da2,
 128.729 +    0x5d9d,0x5dac,0x5dae,0x5dbd,0x5d90,0x5db7,0x5dbc,0x5dc9,0x5dcd,0x5dd3,
 128.730 +    0x5dd2,0x5dd6,0x5ddb,0x5deb,0x5df2,0x5df5,0x5e0b,0x5e1a,0x5e19,0x5e11,
 128.731 +    0x5e1b,0x5e36,0x5e37,0x5e44,0x5e43,0x5e40,0x5e4e,0x5e57,0x5e54,0x5e5f,
 128.732 +    0x5e62,0x5e64,0x5e47,0x5e75,0x5e76,0x5e7a,0x9ebc,0x5e7f,0x5ea0,0x5ec1,
 128.733 +    0x5ec2,0x5ec8,0x5ed0,0x5ecf
 128.734 +  },
 128.735 +  {				/* ku 37 */
 128.736 +    0x5ed6,0x5ee3,0x5edd,0x5eda,0x5edb,0x5ee2,0x5ee1,0x5ee8,0x5ee9,0x5eec,
 128.737 +    0x5ef1,0x5ef3,0x5ef0,0x5ef4,0x5ef8,0x5efe,0x5f03,0x5f09,0x5f5d,0x5f5c,
 128.738 +    0x5f0b,0x5f11,0x5f16,0x5f29,0x5f2d,0x5f38,0x5f41,0x5f48,0x5f4c,0x5f4e,
 128.739 +    0x5f2f,0x5f51,0x5f56,0x5f57,0x5f59,0x5f61,0x5f6d,0x5f73,0x5f77,0x5f83,
 128.740 +    0x5f82,0x5f7f,0x5f8a,0x5f88,0x5f91,0x5f87,0x5f9e,0x5f99,0x5f98,0x5fa0,
 128.741 +    0x5fa8,0x5fad,0x5fbc,0x5fd6,0x5ffb,0x5fe4,0x5ff8,0x5ff1,0x5fdd,0x60b3,
 128.742 +    0x5fff,0x6021,0x6060,0x6019,0x6010,0x6029,0x600e,0x6031,0x601b,0x6015,
 128.743 +    0x602b,0x6026,0x600f,0x603a,0x605a,0x6041,0x606a,0x6077,0x605f,0x604a,
 128.744 +    0x6046,0x604d,0x6063,0x6043,0x6064,0x6042,0x606c,0x606b,0x6059,0x6081,
 128.745 +    0x608d,0x60e7,0x6083,0x609a
 128.746 +  },
 128.747 +  {				/* ku 38 */
 128.748 +    0x6084,0x609b,0x6096,0x6097,0x6092,0x60a7,0x608b,0x60e1,0x60b8,0x60e0,
 128.749 +    0x60d3,0x60b4,0x5ff0,0x60bd,0x60c6,0x60b5,0x60d8,0x614d,0x6115,0x6106,
 128.750 +    0x60f6,0x60f7,0x6100,0x60f4,0x60fa,0x6103,0x6121,0x60fb,0x60f1,0x610d,
 128.751 +    0x610e,0x6147,0x613e,0x6128,0x6127,0x614a,0x613f,0x613c,0x612c,0x6134,
 128.752 +    0x613d,0x6142,0x6144,0x6173,0x6177,0x6158,0x6159,0x615a,0x616b,0x6174,
 128.753 +    0x616f,0x6165,0x6171,0x615f,0x615d,0x6153,0x6175,0x6199,0x6196,0x6187,
 128.754 +    0x61ac,0x6194,0x619a,0x618a,0x6191,0x61ab,0x61ae,0x61cc,0x61ca,0x61c9,
 128.755 +    0x61f7,0x61c8,0x61c3,0x61c6,0x61ba,0x61cb,0x7f79,0x61cd,0x61e6,0x61e3,
 128.756 +    0x61f6,0x61fa,0x61f4,0x61ff,0x61fd,0x61fc,0x61fe,0x6200,0x6208,0x6209,
 128.757 +    0x620d,0x620c,0x6214,0x621b
 128.758 +  },
 128.759 +  {				/* ku 39 */
 128.760 +    0x621e,0x6221,0x622a,0x622e,0x6230,0x6232,0x6233,0x6241,0x624e,0x625e,
 128.761 +    0x6263,0x625b,0x6260,0x6268,0x627c,0x6282,0x6289,0x627e,0x6292,0x6293,
 128.762 +    0x6296,0x62d4,0x6283,0x6294,0x62d7,0x62d1,0x62bb,0x62cf,0x62ff,0x62c6,
 128.763 +    0x64d4,0x62c8,0x62dc,0x62cc,0x62ca,0x62c2,0x62c7,0x629b,0x62c9,0x630c,
 128.764 +    0x62ee,0x62f1,0x6327,0x6302,0x6308,0x62ef,0x62f5,0x6350,0x633e,0x634d,
 128.765 +    0x641c,0x634f,0x6396,0x638e,0x6380,0x63ab,0x6376,0x63a3,0x638f,0x6389,
 128.766 +    0x639f,0x63b5,0x636b,0x6369,0x63be,0x63e9,0x63c0,0x63c6,0x63e3,0x63c9,
 128.767 +    0x63d2,0x63f6,0x63c4,0x6416,0x6434,0x6406,0x6413,0x6426,0x6436,0x651d,
 128.768 +    0x6417,0x6428,0x640f,0x6467,0x646f,0x6476,0x644e,0x652a,0x6495,0x6493,
 128.769 +    0x64a5,0x64a9,0x6488,0x64bc
 128.770 +  },
 128.771 +  {				/* ku 3a */
 128.772 +    0x64da,0x64d2,0x64c5,0x64c7,0x64bb,0x64d8,0x64c2,0x64f1,0x64e7,0x8209,
 128.773 +    0x64e0,0x64e1,0x62ac,0x64e3,0x64ef,0x652c,0x64f6,0x64f4,0x64f2,0x64fa,
 128.774 +    0x6500,0x64fd,0x6518,0x651c,0x6505,0x6524,0x6523,0x652b,0x6534,0x6535,
 128.775 +    0x6537,0x6536,0x6538,0x754b,0x6548,0x6556,0x6555,0x654d,0x6558,0x655e,
 128.776 +    0x655d,0x6572,0x6578,0x6582,0x6583,0x8b8a,0x659b,0x659f,0x65ab,0x65b7,
 128.777 +    0x65c3,0x65c6,0x65c1,0x65c4,0x65cc,0x65d2,0x65db,0x65d9,0x65e0,0x65e1,
 128.778 +    0x65f1,0x6772,0x660a,0x6603,0x65fb,0x6773,0x6635,0x6636,0x6634,0x661c,
 128.779 +    0x664f,0x6644,0x6649,0x6641,0x665e,0x665d,0x6664,0x6667,0x6668,0x665f,
 128.780 +    0x6662,0x6670,0x6683,0x6688,0x668e,0x6689,0x6684,0x6698,0x669d,0x66c1,
 128.781 +    0x66b9,0x66c9,0x66be,0x66bc
 128.782 +  },
 128.783 +  {				/* ku 3b */
 128.784 +    0x66c4,0x66b8,0x66d6,0x66da,0x66e0,0x663f,0x66e6,0x66e9,0x66f0,0x66f5,
 128.785 +    0x66f7,0x670f,0x6716,0x671e,0x6726,0x6727,0x9738,0x672e,0x673f,0x6736,
 128.786 +    0x6741,0x6738,0x6737,0x6746,0x675e,0x6760,0x6759,0x6763,0x6764,0x6789,
 128.787 +    0x6770,0x67a9,0x677c,0x676a,0x678c,0x678b,0x67a6,0x67a1,0x6785,0x67b7,
 128.788 +    0x67ef,0x67b4,0x67ec,0x67b3,0x67e9,0x67b8,0x67e4,0x67de,0x67dd,0x67e2,
 128.789 +    0x67ee,0x67b9,0x67ce,0x67c6,0x67e7,0x6a9c,0x681e,0x6846,0x6829,0x6840,
 128.790 +    0x684d,0x6832,0x684e,0x68b3,0x682b,0x6859,0x6863,0x6877,0x687f,0x689f,
 128.791 +    0x688f,0x68ad,0x6894,0x689d,0x689b,0x6883,0x6aae,0x68b9,0x6874,0x68b5,
 128.792 +    0x68a0,0x68ba,0x690f,0x688d,0x687e,0x6901,0x68ca,0x6908,0x68d8,0x6922,
 128.793 +    0x6926,0x68e1,0x690c,0x68cd
 128.794 +  },
 128.795 +  {				/* ku 3c */
 128.796 +    0x68d4,0x68e7,0x68d5,0x6936,0x6912,0x6904,0x68d7,0x68e3,0x6925,0x68f9,
 128.797 +    0x68e0,0x68ef,0x6928,0x692a,0x691a,0x6923,0x6921,0x68c6,0x6979,0x6977,
 128.798 +    0x695c,0x6978,0x696b,0x6954,0x697e,0x696e,0x6939,0x6974,0x693d,0x6959,
 128.799 +    0x6930,0x6961,0x695e,0x695d,0x6981,0x696a,0x69b2,0x69ae,0x69d0,0x69bf,
 128.800 +    0x69c1,0x69d3,0x69be,0x69ce,0x5be8,0x69ca,0x69dd,0x69bb,0x69c3,0x69a7,
 128.801 +    0x6a2e,0x6991,0x69a0,0x699c,0x6995,0x69b4,0x69de,0x69e8,0x6a02,0x6a1b,
 128.802 +    0x69ff,0x6b0a,0x69f9,0x69f2,0x69e7,0x6a05,0x69b1,0x6a1e,0x69ed,0x6a14,
 128.803 +    0x69eb,0x6a0a,0x6a12,0x6ac1,0x6a23,0x6a13,0x6a44,0x6a0c,0x6a72,0x6a36,
 128.804 +    0x6a78,0x6a47,0x6a62,0x6a59,0x6a66,0x6a48,0x6a38,0x6a22,0x6a90,0x6a8d,
 128.805 +    0x6aa0,0x6a84,0x6aa2,0x6aa3
 128.806 +  },
 128.807 +  {				/* ku 3d */
 128.808 +    0x6a97,0x8617,0x6abb,0x6ac3,0x6ac2,0x6ab8,0x6ab3,0x6aac,0x6ade,0x6ad1,
 128.809 +    0x6adf,0x6aaa,0x6ada,0x6aea,0x6afb,0x6b05,0x8616,0x6afa,0x6b12,0x6b16,
 128.810 +    0x9b31,0x6b1f,0x6b38,0x6b37,0x76dc,0x6b39,0x98ee,0x6b47,0x6b43,0x6b49,
 128.811 +    0x6b50,0x6b59,0x6b54,0x6b5b,0x6b5f,0x6b61,0x6b78,0x6b79,0x6b7f,0x6b80,
 128.812 +    0x6b84,0x6b83,0x6b8d,0x6b98,0x6b95,0x6b9e,0x6ba4,0x6baa,0x6bab,0x6baf,
 128.813 +    0x6bb2,0x6bb1,0x6bb3,0x6bb7,0x6bbc,0x6bc6,0x6bcb,0x6bd3,0x6bdf,0x6bec,
 128.814 +    0x6beb,0x6bf3,0x6bef,0x9ebe,0x6c08,0x6c13,0x6c14,0x6c1b,0x6c24,0x6c23,
 128.815 +    0x6c5e,0x6c55,0x6c62,0x6c6a,0x6c82,0x6c8d,0x6c9a,0x6c81,0x6c9b,0x6c7e,
 128.816 +    0x6c68,0x6c73,0x6c92,0x6c90,0x6cc4,0x6cf1,0x6cd3,0x6cbd,0x6cd7,0x6cc5,
 128.817 +    0x6cdd,0x6cae,0x6cb1,0x6cbe
 128.818 +  },
 128.819 +  {				/* ku 3e */
 128.820 +    0x6cba,0x6cdb,0x6cef,0x6cd9,0x6cea,0x6d1f,0x884d,0x6d36,0x6d2b,0x6d3d,
 128.821 +    0x6d38,0x6d19,0x6d35,0x6d33,0x6d12,0x6d0c,0x6d63,0x6d93,0x6d64,0x6d5a,
 128.822 +    0x6d79,0x6d59,0x6d8e,0x6d95,0x6fe4,0x6d85,0x6df9,0x6e15,0x6e0a,0x6db5,
 128.823 +    0x6dc7,0x6de6,0x6db8,0x6dc6,0x6dec,0x6dde,0x6dcc,0x6de8,0x6dd2,0x6dc5,
 128.824 +    0x6dfa,0x6dd9,0x6de4,0x6dd5,0x6dea,0x6dee,0x6e2d,0x6e6e,0x6e2e,0x6e19,
 128.825 +    0x6e72,0x6e5f,0x6e3e,0x6e23,0x6e6b,0x6e2b,0x6e76,0x6e4d,0x6e1f,0x6e43,
 128.826 +    0x6e3a,0x6e4e,0x6e24,0x6eff,0x6e1d,0x6e38,0x6e82,0x6eaa,0x6e98,0x6ec9,
 128.827 +    0x6eb7,0x6ed3,0x6ebd,0x6eaf,0x6ec4,0x6eb2,0x6ed4,0x6ed5,0x6e8f,0x6ea5,
 128.828 +    0x6ec2,0x6e9f,0x6f41,0x6f11,0x704c,0x6eec,0x6ef8,0x6efe,0x6f3f,0x6ef2,
 128.829 +    0x6f31,0x6eef,0x6f32,0x6ecc
 128.830 +  },
 128.831 +  {				/* ku 3f */
 128.832 +    0x6f3e,0x6f13,0x6ef7,0x6f86,0x6f7a,0x6f78,0x6f81,0x6f80,0x6f6f,0x6f5b,
 128.833 +    0x6ff3,0x6f6d,0x6f82,0x6f7c,0x6f58,0x6f8e,0x6f91,0x6fc2,0x6f66,0x6fb3,
 128.834 +    0x6fa3,0x6fa1,0x6fa4,0x6fb9,0x6fc6,0x6faa,0x6fdf,0x6fd5,0x6fec,0x6fd4,
 128.835 +    0x6fd8,0x6ff1,0x6fee,0x6fdb,0x7009,0x700b,0x6ffa,0x7011,0x7001,0x700f,
 128.836 +    0x6ffe,0x701b,0x701a,0x6f74,0x701d,0x7018,0x701f,0x7030,0x703e,0x7032,
 128.837 +    0x7051,0x7063,0x7099,0x7092,0x70af,0x70f1,0x70ac,0x70b8,0x70b3,0x70ae,
 128.838 +    0x70df,0x70cb,0x70dd,0x70d9,0x7109,0x70fd,0x711c,0x7119,0x7165,0x7155,
 128.839 +    0x7188,0x7166,0x7162,0x714c,0x7156,0x716c,0x718f,0x71fb,0x7184,0x7195,
 128.840 +    0x71a8,0x71ac,0x71d7,0x71b9,0x71be,0x71d2,0x71c9,0x71d4,0x71ce,0x71e0,
 128.841 +    0x71ec,0x71e7,0x71f5,0x71fc
 128.842 +  },
 128.843 +  {				/* ku 40 */
 128.844 +    0x71f9,0x71ff,0x720d,0x7210,0x721b,0x7228,0x722d,0x722c,0x7230,0x7232,
 128.845 +    0x723b,0x723c,0x723f,0x7240,0x7246,0x724b,0x7258,0x7274,0x727e,0x7282,
 128.846 +    0x7281,0x7287,0x7292,0x7296,0x72a2,0x72a7,0x72b9,0x72b2,0x72c3,0x72c6,
 128.847 +    0x72c4,0x72ce,0x72d2,0x72e2,0x72e0,0x72e1,0x72f9,0x72f7,0x500f,0x7317,
 128.848 +    0x730a,0x731c,0x7316,0x731d,0x7334,0x732f,0x7329,0x7325,0x733e,0x734e,
 128.849 +    0x734f,0x9ed8,0x7357,0x736a,0x7368,0x7370,0x7378,0x7375,0x737b,0x737a,
 128.850 +    0x73c8,0x73b3,0x73ce,0x73bb,0x73c0,0x73e5,0x73ee,0x73de,0x74a2,0x7405,
 128.851 +    0x746f,0x7425,0x73f8,0x7432,0x743a,0x7455,0x743f,0x745f,0x7459,0x7441,
 128.852 +    0x745c,0x7469,0x7470,0x7463,0x746a,0x7476,0x747e,0x748b,0x749e,0x74a7,
 128.853 +    0x74ca,0x74cf,0x74d4,0x73f1
 128.854 +  },
 128.855 +  {				/* ku 41 */
 128.856 +    0x74e0,0x74e3,0x74e7,0x74e9,0x74ee,0x74f2,0x74f0,0x74f1,0x74f8,0x74f7,
 128.857 +    0x7504,0x7503,0x7505,0x750c,0x750e,0x750d,0x7515,0x7513,0x751e,0x7526,
 128.858 +    0x752c,0x753c,0x7544,0x754d,0x754a,0x7549,0x755b,0x7546,0x755a,0x7569,
 128.859 +    0x7564,0x7567,0x756b,0x756d,0x7578,0x7576,0x7586,0x7587,0x7574,0x758a,
 128.860 +    0x7589,0x7582,0x7594,0x759a,0x759d,0x75a5,0x75a3,0x75c2,0x75b3,0x75c3,
 128.861 +    0x75b5,0x75bd,0x75b8,0x75bc,0x75b1,0x75cd,0x75ca,0x75d2,0x75d9,0x75e3,
 128.862 +    0x75de,0x75fe,0x75ff,0x75fc,0x7601,0x75f0,0x75fa,0x75f2,0x75f3,0x760b,
 128.863 +    0x760d,0x7609,0x761f,0x7627,0x7620,0x7621,0x7622,0x7624,0x7634,0x7630,
 128.864 +    0x763b,0x7647,0x7648,0x7646,0x765c,0x7658,0x7661,0x7662,0x7668,0x7669,
 128.865 +    0x766a,0x7667,0x766c,0x7670
 128.866 +  },
 128.867 +  {				/* ku 42 */
 128.868 +    0x7672,0x7676,0x7678,0x767c,0x7680,0x7683,0x7688,0x768b,0x768e,0x7696,
 128.869 +    0x7693,0x7699,0x769a,0x76b0,0x76b4,0x76b8,0x76b9,0x76ba,0x76c2,0x76cd,
 128.870 +    0x76d6,0x76d2,0x76de,0x76e1,0x76e5,0x76e7,0x76ea,0x862f,0x76fb,0x7708,
 128.871 +    0x7707,0x7704,0x7729,0x7724,0x771e,0x7725,0x7726,0x771b,0x7737,0x7738,
 128.872 +    0x7747,0x775a,0x7768,0x776b,0x775b,0x7765,0x777f,0x777e,0x7779,0x778e,
 128.873 +    0x778b,0x7791,0x77a0,0x779e,0x77b0,0x77b6,0x77b9,0x77bf,0x77bc,0x77bd,
 128.874 +    0x77bb,0x77c7,0x77cd,0x77d7,0x77da,0x77dc,0x77e3,0x77ee,0x77fc,0x780c,
 128.875 +    0x7812,0x7926,0x7820,0x792a,0x7845,0x788e,0x7874,0x7886,0x787c,0x789a,
 128.876 +    0x788c,0x78a3,0x78b5,0x78aa,0x78af,0x78d1,0x78c6,0x78cb,0x78d4,0x78be,
 128.877 +    0x78bc,0x78c5,0x78ca,0x78ec
 128.878 +  },
 128.879 +  {				/* ku 43 */
 128.880 +    0x78e7,0x78da,0x78fd,0x78f4,0x7907,0x7912,0x7911,0x7919,0x792c,0x792b,
 128.881 +    0x7940,0x7960,0x7957,0x795f,0x795a,0x7955,0x7953,0x797a,0x797f,0x798a,
 128.882 +    0x799d,0x79a7,0x9f4b,0x79aa,0x79ae,0x79b3,0x79b9,0x79ba,0x79c9,0x79d5,
 128.883 +    0x79e7,0x79ec,0x79e1,0x79e3,0x7a08,0x7a0d,0x7a18,0x7a19,0x7a20,0x7a1f,
 128.884 +    0x7980,0x7a31,0x7a3b,0x7a3e,0x7a37,0x7a43,0x7a57,0x7a49,0x7a61,0x7a62,
 128.885 +    0x7a69,0x9f9d,0x7a70,0x7a79,0x7a7d,0x7a88,0x7a97,0x7a95,0x7a98,0x7a96,
 128.886 +    0x7aa9,0x7ac8,0x7ab0,0x7ab6,0x7ac5,0x7ac4,0x7abf,0x9083,0x7ac7,0x7aca,
 128.887 +    0x7acd,0x7acf,0x7ad5,0x7ad3,0x7ad9,0x7ada,0x7add,0x7ae1,0x7ae2,0x7ae6,
 128.888 +    0x7aed,0x7af0,0x7b02,0x7b0f,0x7b0a,0x7b06,0x7b33,0x7b18,0x7b19,0x7b1e,
 128.889 +    0x7b35,0x7b28,0x7b36,0x7b50
 128.890 +  },
 128.891 +  {				/* ku 44 */
 128.892 +    0x7b7a,0x7b04,0x7b4d,0x7b0b,0x7b4c,0x7b45,0x7b75,0x7b65,0x7b74,0x7b67,
 128.893 +    0x7b70,0x7b71,0x7b6c,0x7b6e,0x7b9d,0x7b98,0x7b9f,0x7b8d,0x7b9c,0x7b9a,
 128.894 +    0x7b8b,0x7b92,0x7b8f,0x7b5d,0x7b99,0x7bcb,0x7bc1,0x7bcc,0x7bcf,0x7bb4,
 128.895 +    0x7bc6,0x7bdd,0x7be9,0x7c11,0x7c14,0x7be6,0x7be5,0x7c60,0x7c00,0x7c07,
 128.896 +    0x7c13,0x7bf3,0x7bf7,0x7c17,0x7c0d,0x7bf6,0x7c23,0x7c27,0x7c2a,0x7c1f,
 128.897 +    0x7c37,0x7c2b,0x7c3d,0x7c4c,0x7c43,0x7c54,0x7c4f,0x7c40,0x7c50,0x7c58,
 128.898 +    0x7c5f,0x7c64,0x7c56,0x7c65,0x7c6c,0x7c75,0x7c83,0x7c90,0x7ca4,0x7cad,
 128.899 +    0x7ca2,0x7cab,0x7ca1,0x7ca8,0x7cb3,0x7cb2,0x7cb1,0x7cae,0x7cb9,0x7cbd,
 128.900 +    0x7cc0,0x7cc5,0x7cc2,0x7cd8,0x7cd2,0x7cdc,0x7ce2,0x9b3b,0x7cef,0x7cf2,
 128.901 +    0x7cf4,0x7cf6,0x7cfa,0x7d06
 128.902 +  },
 128.903 +  {				/* ku 45 */
 128.904 +    0x7d02,0x7d1c,0x7d15,0x7d0a,0x7d45,0x7d4b,0x7d2e,0x7d32,0x7d3f,0x7d35,
 128.905 +    0x7d46,0x7d73,0x7d56,0x7d4e,0x7d72,0x7d68,0x7d6e,0x7d4f,0x7d63,0x7d93,
 128.906 +    0x7d89,0x7d5b,0x7d8f,0x7d7d,0x7d9b,0x7dba,0x7dae,0x7da3,0x7db5,0x7dc7,
 128.907 +    0x7dbd,0x7dab,0x7e3d,0x7da2,0x7daf,0x7ddc,0x7db8,0x7d9f,0x7db0,0x7dd8,
 128.908 +    0x7ddd,0x7de4,0x7dde,0x7dfb,0x7df2,0x7de1,0x7e05,0x7e0a,0x7e23,0x7e21,
 128.909 +    0x7e12,0x7e31,0x7e1f,0x7e09,0x7e0b,0x7e22,0x7e46,0x7e66,0x7e3b,0x7e35,
 128.910 +    0x7e39,0x7e43,0x7e37,0x7e32,0x7e3a,0x7e67,0x7e5d,0x7e56,0x7e5e,0x7e59,
 128.911 +    0x7e5a,0x7e79,0x7e6a,0x7e69,0x7e7c,0x7e7b,0x7e83,0x7dd5,0x7e7d,0x8fae,
 128.912 +    0x7e7f,0x7e88,0x7e89,0x7e8c,0x7e92,0x7e90,0x7e93,0x7e94,0x7e96,0x7e8e,
 128.913 +    0x7e9b,0x7e9c,0x7f38,0x7f3a
 128.914 +  },
 128.915 +  {				/* ku 46 */
 128.916 +    0x7f45,0x7f4c,0x7f4d,0x7f4e,0x7f50,0x7f51,0x7f55,0x7f54,0x7f58,0x7f5f,
 128.917 +    0x7f60,0x7f68,0x7f69,0x7f67,0x7f78,0x7f82,0x7f86,0x7f83,0x7f88,0x7f87,
 128.918 +    0x7f8c,0x7f94,0x7f9e,0x7f9d,0x7f9a,0x7fa3,0x7faf,0x7fb2,0x7fb9,0x7fae,
 128.919 +    0x7fb6,0x7fb8,0x8b71,0x7fc5,0x7fc6,0x7fca,0x7fd5,0x7fd4,0x7fe1,0x7fe6,
 128.920 +    0x7fe9,0x7ff3,0x7ff9,0x98dc,0x8006,0x8004,0x800b,0x8012,0x8018,0x8019,
 128.921 +    0x801c,0x8021,0x8028,0x803f,0x803b,0x804a,0x8046,0x8052,0x8058,0x805a,
 128.922 +    0x805f,0x8062,0x8068,0x8073,0x8072,0x8070,0x8076,0x8079,0x807d,0x807f,
 128.923 +    0x8084,0x8086,0x8085,0x809b,0x8093,0x809a,0x80ad,0x5190,0x80ac,0x80db,
 128.924 +    0x80e5,0x80d9,0x80dd,0x80c4,0x80da,0x80d6,0x8109,0x80ef,0x80f1,0x811b,
 128.925 +    0x8129,0x8123,0x812f,0x814b
 128.926 +  },
 128.927 +  {				/* ku 47 */
 128.928 +    0x968b,0x8146,0x813e,0x8153,0x8151,0x80fc,0x8171,0x816e,0x8165,0x8166,
 128.929 +    0x8174,0x8183,0x8188,0x818a,0x8180,0x8182,0x81a0,0x8195,0x81a4,0x81a3,
 128.930 +    0x815f,0x8193,0x81a9,0x81b0,0x81b5,0x81be,0x81b8,0x81bd,0x81c0,0x81c2,
 128.931 +    0x81ba,0x81c9,0x81cd,0x81d1,0x81d9,0x81d8,0x81c8,0x81da,0x81df,0x81e0,
 128.932 +    0x81e7,0x81fa,0x81fb,0x81fe,0x8201,0x8202,0x8205,0x8207,0x820a,0x820d,
 128.933 +    0x8210,0x8216,0x8229,0x822b,0x8238,0x8233,0x8240,0x8259,0x8258,0x825d,
 128.934 +    0x825a,0x825f,0x8264,0x8262,0x8268,0x826a,0x826b,0x822e,0x8271,0x8277,
 128.935 +    0x8278,0x827e,0x828d,0x8292,0x82ab,0x829f,0x82bb,0x82ac,0x82e1,0x82e3,
 128.936 +    0x82df,0x82d2,0x82f4,0x82f3,0x82fa,0x8393,0x8303,0x82fb,0x82f9,0x82de,
 128.937 +    0x8306,0x82dc,0x8309,0x82d9
 128.938 +  },
 128.939 +  {				/* ku 48 */
 128.940 +    0x8335,0x8334,0x8316,0x8332,0x8331,0x8340,0x8339,0x8350,0x8345,0x832f,
 128.941 +    0x832b,0x8317,0x8318,0x8385,0x839a,0x83aa,0x839f,0x83a2,0x8396,0x8323,
 128.942 +    0x838e,0x8387,0x838a,0x837c,0x83b5,0x8373,0x8375,0x83a0,0x8389,0x83a8,
 128.943 +    0x83f4,0x8413,0x83eb,0x83ce,0x83fd,0x8403,0x83d8,0x840b,0x83c1,0x83f7,
 128.944 +    0x8407,0x83e0,0x83f2,0x840d,0x8422,0x8420,0x83bd,0x8438,0x8506,0x83fb,
 128.945 +    0x846d,0x842a,0x843c,0x855a,0x8484,0x8477,0x846b,0x84ad,0x846e,0x8482,
 128.946 +    0x8469,0x8446,0x842c,0x846f,0x8479,0x8435,0x84ca,0x8462,0x84b9,0x84bf,
 128.947 +    0x849f,0x84d9,0x84cd,0x84bb,0x84da,0x84d0,0x84c1,0x84c6,0x84d6,0x84a1,
 128.948 +    0x8521,0x84ff,0x84f4,0x8517,0x8518,0x852c,0x851f,0x8515,0x8514,0x84fc,
 128.949 +    0x8540,0x8563,0x8558,0x8548
 128.950 +  },
 128.951 +  {				/* ku 49 */
 128.952 +    0x8541,0x8602,0x854b,0x8555,0x8580,0x85a4,0x8588,0x8591,0x858a,0x85a8,
 128.953 +    0x856d,0x8594,0x859b,0x85ea,0x8587,0x859c,0x8577,0x857e,0x8590,0x85c9,
 128.954 +    0x85ba,0x85cf,0x85b9,0x85d0,0x85d5,0x85dd,0x85e5,0x85dc,0x85f9,0x860a,
 128.955 +    0x8613,0x860b,0x85fe,0x85fa,0x8606,0x8622,0x861a,0x8630,0x863f,0x864d,
 128.956 +    0x4e55,0x8654,0x865f,0x8667,0x8671,0x8693,0x86a3,0x86a9,0x86aa,0x868b,
 128.957 +    0x868c,0x86b6,0x86af,0x86c4,0x86c6,0x86b0,0x86c9,0x8823,0x86ab,0x86d4,
 128.958 +    0x86de,0x86e9,0x86ec,0x86df,0x86db,0x86ef,0x8712,0x8706,0x8708,0x8700,
 128.959 +    0x8703,0x86fb,0x8711,0x8709,0x870d,0x86f9,0x870a,0x8734,0x873f,0x8737,
 128.960 +    0x873b,0x8725,0x8729,0x871a,0x8760,0x875f,0x8778,0x874c,0x874e,0x8774,
 128.961 +    0x8757,0x8768,0x876e,0x8759
 128.962 +  },
 128.963 +  {				/* ku 4a */
 128.964 +    0x8753,0x8763,0x876a,0x8805,0x87a2,0x879f,0x8782,0x87af,0x87cb,0x87bd,
 128.965 +    0x87c0,0x87d0,0x96d6,0x87ab,0x87c4,0x87b3,0x87c7,0x87c6,0x87bb,0x87ef,
 128.966 +    0x87f2,0x87e0,0x880f,0x880d,0x87fe,0x87f6,0x87f7,0x880e,0x87d2,0x8811,
 128.967 +    0x8816,0x8815,0x8822,0x8821,0x8831,0x8836,0x8839,0x8827,0x883b,0x8844,
 128.968 +    0x8842,0x8852,0x8859,0x885e,0x8862,0x886b,0x8881,0x887e,0x889e,0x8875,
 128.969 +    0x887d,0x88b5,0x8872,0x8882,0x8897,0x8892,0x88ae,0x8899,0x88a2,0x888d,
 128.970 +    0x88a4,0x88b0,0x88bf,0x88b1,0x88c3,0x88c4,0x88d4,0x88d8,0x88d9,0x88dd,
 128.971 +    0x88f9,0x8902,0x88fc,0x88f4,0x88e8,0x88f2,0x8904,0x890c,0x890a,0x8913,
 128.972 +    0x8943,0x891e,0x8925,0x892a,0x892b,0x8941,0x8944,0x893b,0x8936,0x8938,
 128.973 +    0x894c,0x891d,0x8960,0x895e
 128.974 +  },
 128.975 +  {				/* ku 4b */
 128.976 +    0x8966,0x8964,0x896d,0x896a,0x896f,0x8974,0x8977,0x897e,0x8983,0x8988,
 128.977 +    0x898a,0x8993,0x8998,0x89a1,0x89a9,0x89a6,0x89ac,0x89af,0x89b2,0x89ba,
 128.978 +    0x89bd,0x89bf,0x89c0,0x89da,0x89dc,0x89dd,0x89e7,0x89f4,0x89f8,0x8a03,
 128.979 +    0x8a16,0x8a10,0x8a0c,0x8a1b,0x8a1d,0x8a25,0x8a36,0x8a41,0x8a5b,0x8a52,
 128.980 +    0x8a46,0x8a48,0x8a7c,0x8a6d,0x8a6c,0x8a62,0x8a85,0x8a82,0x8a84,0x8aa8,
 128.981 +    0x8aa1,0x8a91,0x8aa5,0x8aa6,0x8a9a,0x8aa3,0x8ac4,0x8acd,0x8ac2,0x8ada,
 128.982 +    0x8aeb,0x8af3,0x8ae7,0x8ae4,0x8af1,0x8b14,0x8ae0,0x8ae2,0x8af7,0x8ade,
 128.983 +    0x8adb,0x8b0c,0x8b07,0x8b1a,0x8ae1,0x8b16,0x8b10,0x8b17,0x8b20,0x8b33,
 128.984 +    0x97ab,0x8b26,0x8b2b,0x8b3e,0x8b28,0x8b41,0x8b4c,0x8b4f,0x8b4e,0x8b49,
 128.985 +    0x8b56,0x8b5b,0x8b5a,0x8b6b
 128.986 +  },
 128.987 +  {				/* ku 4c */
 128.988 +    0x8b5f,0x8b6c,0x8b6f,0x8b74,0x8b7d,0x8b80,0x8b8c,0x8b8e,0x8b92,0x8b93,
 128.989 +    0x8b96,0x8b99,0x8b9a,0x8c3a,0x8c41,0x8c3f,0x8c48,0x8c4c,0x8c4e,0x8c50,
 128.990 +    0x8c55,0x8c62,0x8c6c,0x8c78,0x8c7a,0x8c82,0x8c89,0x8c85,0x8c8a,0x8c8d,
 128.991 +    0x8c8e,0x8c94,0x8c7c,0x8c98,0x621d,0x8cad,0x8caa,0x8cbd,0x8cb2,0x8cb3,
 128.992 +    0x8cae,0x8cb6,0x8cc8,0x8cc1,0x8ce4,0x8ce3,0x8cda,0x8cfd,0x8cfa,0x8cfb,
 128.993 +    0x8d04,0x8d05,0x8d0a,0x8d07,0x8d0f,0x8d0d,0x8d10,0x9f4e,0x8d13,0x8ccd,
 128.994 +    0x8d14,0x8d16,0x8d67,0x8d6d,0x8d71,0x8d73,0x8d81,0x8d99,0x8dc2,0x8dbe,
 128.995 +    0x8dba,0x8dcf,0x8dda,0x8dd6,0x8dcc,0x8ddb,0x8dcb,0x8dea,0x8deb,0x8ddf,
 128.996 +    0x8de3,0x8dfc,0x8e08,0x8e09,0x8dff,0x8e1d,0x8e1e,0x8e10,0x8e1f,0x8e42,
 128.997 +    0x8e35,0x8e30,0x8e34,0x8e4a
 128.998 +  },
 128.999 +  {				/* ku 4d */
128.1000 +    0x8e47,0x8e49,0x8e4c,0x8e50,0x8e48,0x8e59,0x8e64,0x8e60,0x8e2a,0x8e63,
128.1001 +    0x8e55,0x8e76,0x8e72,0x8e7c,0x8e81,0x8e87,0x8e85,0x8e84,0x8e8b,0x8e8a,
128.1002 +    0x8e93,0x8e91,0x8e94,0x8e99,0x8eaa,0x8ea1,0x8eac,0x8eb0,0x8ec6,0x8eb1,
128.1003 +    0x8ebe,0x8ec5,0x8ec8,0x8ecb,0x8edb,0x8ee3,0x8efc,0x8efb,0x8eeb,0x8efe,
128.1004 +    0x8f0a,0x8f05,0x8f15,0x8f12,0x8f19,0x8f13,0x8f1c,0x8f1f,0x8f1b,0x8f0c,
128.1005 +    0x8f26,0x8f33,0x8f3b,0x8f39,0x8f45,0x8f42,0x8f3e,0x8f4c,0x8f49,0x8f46,
128.1006 +    0x8f4e,0x8f57,0x8f5c,0x8f62,0x8f63,0x8f64,0x8f9c,0x8f9f,0x8fa3,0x8fad,
128.1007 +    0x8faf,0x8fb7,0x8fda,0x8fe5,0x8fe2,0x8fea,0x8fef,0x9087,0x8ff4,0x9005,
128.1008 +    0x8ff9,0x8ffa,0x9011,0x9015,0x9021,0x900d,0x901e,0x9016,0x900b,0x9027,
128.1009 +    0x9036,0x9035,0x9039,0x8ff8
128.1010 +  },
128.1011 +  {				/* ku 4e */
128.1012 +    0x904f,0x9050,0x9051,0x9052,0x900e,0x9049,0x903e,0x9056,0x9058,0x905e,
128.1013 +    0x9068,0x906f,0x9076,0x96a8,0x9072,0x9082,0x907d,0x9081,0x9080,0x908a,
128.1014 +    0x9089,0x908f,0x90a8,0x90af,0x90b1,0x90b5,0x90e2,0x90e4,0x6248,0x90db,
128.1015 +    0x9102,0x9112,0x9119,0x9132,0x9130,0x914a,0x9156,0x9158,0x9163,0x9165,
128.1016 +    0x9169,0x9173,0x9172,0x918b,0x9189,0x9182,0x91a2,0x91ab,0x91af,0x91aa,
128.1017 +    0x91b5,0x91b4,0x91ba,0x91c0,0x91c1,0x91c9,0x91cb,0x91d0,0x91d6,0x91df,
128.1018 +    0x91e1,0x91db,0x91fc,0x91f5,0x91f6,0x921e,0x91ff,0x9214,0x922c,0x9215,
128.1019 +    0x9211,0x925e,0x9257,0x9245,0x9249,0x9264,0x9248,0x9295,0x923f,0x924b,
128.1020 +    0x9250,0x929c,0x9296,0x9293,0x929b,0x925a,0x92cf,0x92b9,0x92b7,0x92e9,
128.1021 +    0x930f,0x92fa,0x9344,0x932e
128.1022 +  },
128.1023 +  {				/* ku 4f */
128.1024 +    0x9319,0x9322,0x931a,0x9323,0x933a,0x9335,0x933b,0x935c,0x9360,0x937c,
128.1025 +    0x936e,0x9356,0x93b0,0x93ac,0x93ad,0x9394,0x93b9,0x93d6,0x93d7,0x93e8,
128.1026 +    0x93e5,0x93d8,0x93c3,0x93dd,0x93d0,0x93c8,0x93e4,0x941a,0x9414,0x9413,
128.1027 +    0x9403,0x9407,0x9410,0x9436,0x942b,0x9435,0x9421,0x943a,0x9441,0x9452,
128.1028 +    0x9444,0x945b,0x9460,0x9462,0x945e,0x946a,0x9229,0x9470,0x9475,0x9477,
128.1029 +    0x947d,0x945a,0x947c,0x947e,0x9481,0x947f,0x9582,0x9587,0x958a,0x9594,
128.1030 +    0x9596,0x9598,0x9599,0x95a0,0x95a8,0x95a7,0x95ad,0x95bc,0x95bb,0x95b9,
128.1031 +    0x95be,0x95ca,0x6ff6,0x95c3,0x95cd,0x95cc,0x95d5,0x95d4,0x95d6,0x95dc,
128.1032 +    0x95e1,0x95e5,0x95e2,0x9621,0x9628,0x962e,0x962f,0x9642,0x964c,0x964f,
128.1033 +    0x964b,0x9677,0x965c,0x965e
128.1034 +  },
128.1035 +  {				/* ku 50 */
128.1036 +    0x965d,0x965f,0x9666,0x9672,0x966c,0x968d,0x9698,0x9695,0x9697,0x96aa,
128.1037 +    0x96a7,0x96b1,0x96b2,0x96b0,0x96b4,0x96b6,0x96b8,0x96b9,0x96ce,0x96cb,
128.1038 +    0x96c9,0x96cd,0x894d,0x96dc,0x970d,0x96d5,0x96f9,0x9704,0x9706,0x9708,
128.1039 +    0x9713,0x970e,0x9711,0x970f,0x9716,0x9719,0x9724,0x972a,0x9730,0x9739,
128.1040 +    0x973d,0x973e,0x9744,0x9746,0x9748,0x9742,0x9749,0x975c,0x9760,0x9764,
128.1041 +    0x9766,0x9768,0x52d2,0x976b,0x9771,0x9779,0x9785,0x977c,0x9781,0x977a,
128.1042 +    0x9786,0x978b,0x978f,0x9790,0x979c,0x97a8,0x97a6,0x97a3,0x97b3,0x97b4,
128.1043 +    0x97c3,0x97c6,0x97c8,0x97cb,0x97dc,0x97ed,0x9f4f,0x97f2,0x7adf,0x97f6,
128.1044 +    0x97f5,0x980f,0x980c,0x9838,0x9824,0x9821,0x9837,0x983d,0x9846,0x984f,
128.1045 +    0x984b,0x986b,0x986f,0x9870
128.1046 +  },
128.1047 +  {				/* ku 51 */
128.1048 +    0x9871,0x9874,0x9873,0x98aa,0x98af,0x98b1,0x98b6,0x98c4,0x98c3,0x98c6,
128.1049 +    0x98e9,0x98eb,0x9903,0x9909,0x9912,0x9914,0x9918,0x9921,0x991d,0x991e,
128.1050 +    0x9924,0x9920,0x992c,0x992e,0x993d,0x993e,0x9942,0x9949,0x9945,0x9950,
128.1051 +    0x994b,0x9951,0x9952,0x994c,0x9955,0x9997,0x9998,0x99a5,0x99ad,0x99ae,
128.1052 +    0x99bc,0x99df,0x99db,0x99dd,0x99d8,0x99d1,0x99ed,0x99ee,0x99f1,0x99f2,
128.1053 +    0x99fb,0x99f8,0x9a01,0x9a0f,0x9a05,0x99e2,0x9a19,0x9a2b,0x9a37,0x9a45,
128.1054 +    0x9a42,0x9a40,0x9a43,0x9a3e,0x9a55,0x9a4d,0x9a5b,0x9a57,0x9a5f,0x9a62,
128.1055 +    0x9a65,0x9a64,0x9a69,0x9a6b,0x9a6a,0x9aad,0x9ab0,0x9abc,0x9ac0,0x9acf,
128.1056 +    0x9ad1,0x9ad3,0x9ad4,0x9ade,0x9adf,0x9ae2,0x9ae3,0x9ae6,0x9aef,0x9aeb,
128.1057 +    0x9aee,0x9af4,0x9af1,0x9af7
128.1058 +  },
128.1059 +  {				/* ku 52 */
128.1060 +    0x9afb,0x9b06,0x9b18,0x9b1a,0x9b1f,0x9b22,0x9b23,0x9b25,0x9b27,0x9b28,
128.1061 +    0x9b29,0x9b2a,0x9b2e,0x9b2f,0x9b32,0x9b44,0x9b43,0x9b4f,0x9b4d,0x9b4e,
128.1062 +    0x9b51,0x9b58,0x9b74,0x9b93,0x9b83,0x9b91,0x9b96,0x9b97,0x9b9f,0x9ba0,
128.1063 +    0x9ba8,0x9bb4,0x9bc0,0x9bca,0x9bb9,0x9bc6,0x9bcf,0x9bd1,0x9bd2,0x9be3,
128.1064 +    0x9be2,0x9be4,0x9bd4,0x9be1,0x9c3a,0x9bf2,0x9bf1,0x9bf0,0x9c15,0x9c14,
128.1065 +    0x9c09,0x9c13,0x9c0c,0x9c06,0x9c08,0x9c12,0x9c0a,0x9c04,0x9c2e,0x9c1b,
128.1066 +    0x9c25,0x9c24,0x9c21,0x9c30,0x9c47,0x9c32,0x9c46,0x9c3e,0x9c5a,0x9c60,
128.1067 +    0x9c67,0x9c76,0x9c78,0x9ce7,0x9cec,0x9cf0,0x9d09,0x9d08,0x9ceb,0x9d03,
128.1068 +    0x9d06,0x9d2a,0x9d26,0x9daf,0x9d23,0x9d1f,0x9d44,0x9d15,0x9d12,0x9d41,
128.1069 +    0x9d3f,0x9d3e,0x9d46,0x9d48
128.1070 +  },
128.1071 +  {				/* ku 53 */
128.1072 +    0x9d5d,0x9d5e,0x9d64,0x9d51,0x9d50,0x9d59,0x9d72,0x9d89,0x9d87,0x9dab,
128.1073 +    0x9d6f,0x9d7a,0x9d9a,0x9da4,0x9da9,0x9db2,0x9dc4,0x9dc1,0x9dbb,0x9db8,
128.1074 +    0x9dba,0x9dc6,0x9dcf,0x9dc2,0x9dd9,0x9dd3,0x9df8,0x9de6,0x9ded,0x9def,
128.1075 +    0x9dfd,0x9e1a,0x9e1b,0x9e1e,0x9e75,0x9e79,0x9e7d,0x9e81,0x9e88,0x9e8b,
128.1076 +    0x9e8c,0x9e92,0x9e95,0x9e91,0x9e9d,0x9ea5,0x9ea9,0x9eb8,0x9eaa,0x9ead,
128.1077 +    0x9761,0x9ecc,0x9ece,0x9ecf,0x9ed0,0x9ed4,0x9edc,0x9ede,0x9edd,0x9ee0,
128.1078 +    0x9ee5,0x9ee8,0x9eef,0x9ef4,0x9ef6,0x9ef7,0x9ef9,0x9efb,0x9efc,0x9efd,
128.1079 +    0x9f07,0x9f08,0x76b7,0x9f15,0x9f21,0x9f2c,0x9f3e,0x9f4a,0x9f52,0x9f54,
128.1080 +    0x9f63,0x9f5f,0x9f60,0x9f61,0x9f66,0x9f67,0x9f6c,0x9f6a,0x9f77,0x9f72,
128.1081 +    0x9f76,0x9f95,0x9f9c,0x9fa0
128.1082 +  },
128.1083 +  {				/* ku 54 */
128.1084 +    0x582f,0x69c7,0x9059,0x7464,0x51dc,0x7199,UBOGON,UBOGON,UBOGON,UBOGON,
128.1085 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1086 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1087 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1088 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1089 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1090 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1091 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1092 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
128.1093 +    UBOGON,UBOGON,UBOGON,UBOGON
128.1094 +  }
128.1095 +};
   129.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   129.2 +++ b/src/charset/jis_0212.c	Mon Sep 14 15:17:45 2009 +0900
   129.3 @@ -0,0 +1,962 @@
   129.4 +/* ========================================================================
   129.5 + * Copyright 1988-2006 University of Washington
   129.6 + *
   129.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   129.8 + * you may not use this file except in compliance with the License.
   129.9 + * You may obtain a copy of the License at
  129.10 + *
  129.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  129.12 + *
  129.13 + * 
  129.14 + * ========================================================================
  129.15 + */
  129.16 +
  129.17 +/*
  129.18 + * Program:	JIS X0212 conversion table
  129.19 + *
  129.20 + * Author:	Mark Crispin
  129.21 + *		Networks and Distributed Computing
  129.22 + *		Computing & Communications
  129.23 + *		University of Washington
  129.24 + *		Administration Building, AG-44
  129.25 + *		Seattle, WA  98195
  129.26 + *		Internet: MRC@CAC.Washington.EDU
  129.27 + *
  129.28 + * Date:	4 August 1997
  129.29 + * Last Edited:	30 August 2006
  129.30 + */
  129.31 +
  129.32 +/* JIS X0212 is the supplemental industrial standard of Japan. */
  129.33 +
  129.34 +#define BASE_JIS0212_KU 0x22
  129.35 +#define BASE_JIS0212_TEN 0x21
  129.36 +#define MAX_JIS0212_KU 76
  129.37 +#define MAX_JIS0212_TEN 94
  129.38 +
  129.39 +
  129.40 +#define JIS0212TOUNICODE(c,c1,ku,ten)					\
  129.41 +  ((((ku = (c & 0x7f) - BASE_JIS0212_KU) < MAX_JIS0212_KU) &&		\
  129.42 +    ((ten = (c1 & 0x7f) - BASE_JIS0212_TEN) < MAX_JIS0212_TEN)) ?	\
  129.43 +   jis0212tab[ku][ten] : UBOGON)
  129.44 +
  129.45 +
  129.46 +static const unsigned short jis0212tab[MAX_JIS0212_KU][MAX_JIS0212_TEN] = {
  129.47 +  {				/* ku 02 */
  129.48 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.49 +    UBOGON,UBOGON,UBOGON,UBOGON,0x02d8,0x02c7,0x00b8,0x02d9,0x02dd,0x00af,
  129.50 +    0x02db,0x02da,0x007e,0x0384,0x0385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.51 +    UBOGON,UBOGON,UBOGON,0x00a1,0x00a6,0x00bf,UBOGON,UBOGON,UBOGON,UBOGON,
  129.52 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.53 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.54 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.55 +    UBOGON,UBOGON,UBOGON,UBOGON,0x00ba,0x00aa,0x00a9,0x00ae,0x2122,0x00a4,
  129.56 +    0x2116,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.57 +    UBOGON,UBOGON,UBOGON,UBOGON
  129.58 +  },
  129.59 +  {				/* ku 03 */
  129.60 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.61 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.62 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.63 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.64 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.65 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.66 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.67 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.68 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.69 +    UBOGON,UBOGON,UBOGON,UBOGON
  129.70 +  },
  129.71 +  {				/* ku 04 */
  129.72 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.73 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.74 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.75 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.76 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.77 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.78 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.79 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.80 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.81 +    UBOGON,UBOGON,UBOGON,UBOGON
  129.82 +  },
  129.83 +  {				/* ku 05 */
  129.84 +    /* Note: ku/ten codepoints 05/87 - 05/90 are proposed for addition to
  129.85 +     * JIS X 0212; I don't know if they've been formally accepted yet.
  129.86 +     * They represent katakana VA, VI, VE, and VO, and are in the BMP but
  129.87 +     * not in Unicode's JIS conversion tables.  They're useful enough that
  129.88 +     * I decided to put them here.
  129.89 +     */
  129.90 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.91 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.92 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.93 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.94 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.95 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.96 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.97 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  129.98 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30f7,0x30f8,0x30f9,0x30fa,
  129.99 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.100 +  },
 129.101 +  {				/* ku 06 */
 129.102 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.103 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.104 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.105 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.106 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.107 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.108 +    UBOGON,UBOGON,UBOGON,UBOGON,0x0386,0x0388,0x0389,0x038a,0x03aa,UBOGON,
 129.109 +    0x038c,UBOGON,0x038e,0x03ab,UBOGON,0x038f,UBOGON,UBOGON,UBOGON,UBOGON,
 129.110 +    0x03ac,0x03ad,0x03ae,0x03af,0x03ca,0x0390,0x03cc,0x03c2,0x03cd,0x03cb,
 129.111 +    0x03b0,0x03ce,UBOGON,UBOGON
 129.112 +  },
 129.113 +  {				/* ku 07 */
 129.114 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.115 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.116 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.117 +    UBOGON,UBOGON,UBOGON,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,0x0408,
 129.118 +    0x0409,0x040a,0x040b,0x040c,0x040e,0x040f,UBOGON,UBOGON,UBOGON,UBOGON,
 129.119 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.120 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.121 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.122 +    UBOGON,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,0x0458,0x0459,0x045a,
 129.123 +    0x045b,0x045c,0x045e,0x045f
 129.124 +  },
 129.125 +  {				/* ku 08 */
 129.126 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.127 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.128 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.129 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.130 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.131 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.132 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.133 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.134 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.135 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.136 +  },
 129.137 +  {				/* ku 09 */
 129.138 +    0x00c6,0x0110,UBOGON,0x0126,UBOGON,0x0132,UBOGON,0x0141,0x013f,UBOGON,
 129.139 +    0x014a,0x00d8,0x0152,UBOGON,0x0166,0x00de,UBOGON,UBOGON,UBOGON,UBOGON,
 129.140 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.141 +    UBOGON,UBOGON,0x00e6,0x0111,0x00f0,0x0127,0x0131,0x0133,0x0138,0x0142,
 129.142 +    0x0140,0x0149,0x014b,0x00f8,0x0153,0x00df,0x0167,0x00fe,UBOGON,UBOGON,
 129.143 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.144 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.145 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.146 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.147 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.148 +  },
 129.149 +  {				/* ku 0a */
 129.150 +    0x00c1,0x00c0,0x00c4,0x00c2,0x0102,0x01cd,0x0100,0x0104,0x00c5,0x00c3,
 129.151 +    0x0106,0x0108,0x010c,0x00c7,0x010a,0x010e,0x00c9,0x00c8,0x00cb,0x00ca,
 129.152 +    0x011a,0x0116,0x0112,0x0118,UBOGON,0x011c,0x011e,0x0122,0x0120,0x0124,
 129.153 +    0x00cd,0x00cc,0x00cf,0x00ce,0x01cf,0x0130,0x012a,0x012e,0x0128,0x0134,
 129.154 +    0x0136,0x0139,0x013d,0x013b,0x0143,0x0147,0x0145,0x00d1,0x00d3,0x00d2,
 129.155 +    0x00d6,0x00d4,0x01d1,0x0150,0x014c,0x00d5,0x0154,0x0158,0x0156,0x015a,
 129.156 +    0x015c,0x0160,0x015e,0x0164,0x0162,0x00da,0x00d9,0x00dc,0x00db,0x016c,
 129.157 +    0x01d3,0x0170,0x016a,0x0172,0x016e,0x0168,0x01d7,0x01db,0x01d9,0x01d5,
 129.158 +    0x0174,0x00dd,0x0178,0x0176,0x0179,0x017d,0x017b,UBOGON,UBOGON,UBOGON,
 129.159 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.160 +  },
 129.161 +  {				/* ku 0b */
 129.162 +    0x00e1,0x00e0,0x00e4,0x00e2,0x0103,0x01ce,0x0101,0x0105,0x00e5,0x00e3,
 129.163 +    0x0107,0x0109,0x010d,0x00e7,0x010b,0x010f,0x00e9,0x00e8,0x00eb,0x00ea,
 129.164 +    0x011b,0x0117,0x0113,0x0119,0x01f5,0x011d,0x011f,UBOGON,0x0121,0x0125,
 129.165 +    0x00ed,0x00ec,0x00ef,0x00ee,0x01d0,UBOGON,0x012b,0x012f,0x0129,0x0135,
 129.166 +    0x0137,0x013a,0x013e,0x013c,0x0144,0x0148,0x0146,0x00f1,0x00f3,0x00f2,
 129.167 +    0x00f6,0x00f4,0x01d2,0x0151,0x014d,0x00f5,0x0155,0x0159,0x0157,0x015b,
 129.168 +    0x015d,0x0161,0x015f,0x0165,0x0163,0x00fa,0x00f9,0x00fc,0x00fb,0x016d,
 129.169 +    0x01d4,0x0171,0x016b,0x0173,0x016f,0x0169,0x01d8,0x01dc,0x01da,0x01d6,
 129.170 +    0x0175,0x00fd,0x00ff,0x0177,0x017a,0x017e,0x017c,UBOGON,UBOGON,UBOGON,
 129.171 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.172 +  },
 129.173 +  {				/* ku 0c */
 129.174 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.176 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.180 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.181 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.182 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.183 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.184 +  },
 129.185 +  {				/* ku 0d */
 129.186 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.187 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.188 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.189 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.190 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.191 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.192 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.193 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.194 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.195 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.196 +  },
 129.197 +  {				/* ku 0e */
 129.198 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.199 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.204 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.205 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.206 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.207 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.208 +  },
 129.209 +  {				/* ku 0f */
 129.210 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.211 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.212 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.213 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.214 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.217 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.218 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.219 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.220 +  },
 129.221 +  {				/* ku 10 */
 129.222 +    0x4e02,0x4e04,0x4e05,0x4e0c,0x4e12,0x4e1f,0x4e23,0x4e24,0x4e28,0x4e2b,
 129.223 +    0x4e2e,0x4e2f,0x4e30,0x4e35,0x4e40,0x4e41,0x4e44,0x4e47,0x4e51,0x4e5a,
 129.224 +    0x4e5c,0x4e63,0x4e68,0x4e69,0x4e74,0x4e75,0x4e79,0x4e7f,0x4e8d,0x4e96,
 129.225 +    0x4e97,0x4e9d,0x4eaf,0x4eb9,0x4ec3,0x4ed0,0x4eda,0x4edb,0x4ee0,0x4ee1,
 129.226 +    0x4ee2,0x4ee8,0x4eef,0x4ef1,0x4ef3,0x4ef5,0x4efd,0x4efe,0x4eff,0x4f00,
 129.227 +    0x4f02,0x4f03,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f15,0x4f16,0x4f17,0x4f19,
 129.228 +    0x4f2e,0x4f31,0x4f60,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f40,
 129.229 +    0x4f42,0x4f48,0x4f49,0x4f4b,0x4f4c,0x4f52,0x4f54,0x4f56,0x4f58,0x4f5f,
 129.230 +    0x4f63,0x4f6a,0x4f6c,0x4f6e,0x4f71,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d,
 129.231 +    0x4f7e,0x4f81,0x4f82,0x4f84
 129.232 +  },
 129.233 +  {				/* ku 11 */
 129.234 +    0x4f85,0x4f89,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92,0x4f93,0x4f94,0x4f97,
 129.235 +    0x4f99,0x4f9a,0x4f9e,0x4f9f,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbc,0x4fbd,
 129.236 +    0x4fbe,0x4fc0,0x4fc1,0x4fc5,0x4fc6,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd,
 129.237 +    0x4fcf,0x4fd2,0x4fdc,0x4fe0,0x4fe2,0x4ff0,0x4ff2,0x4ffc,0x4ffd,0x4fff,
 129.238 +    0x5000,0x5001,0x5004,0x5007,0x500a,0x500c,0x500e,0x5010,0x5013,0x5017,
 129.239 +    0x5018,0x501b,0x501c,0x501d,0x501e,0x5022,0x5027,0x502e,0x5030,0x5032,
 129.240 +    0x5033,0x5035,0x5040,0x5041,0x5042,0x5045,0x5046,0x504a,0x504c,0x504e,
 129.241 +    0x5051,0x5052,0x5053,0x5057,0x5059,0x505f,0x5060,0x5062,0x5063,0x5066,
 129.242 +    0x5067,0x506a,0x506d,0x5070,0x5071,0x503b,0x5081,0x5083,0x5084,0x5086,
 129.243 +    0x508a,0x508e,0x508f,0x5090
 129.244 +  },
 129.245 +  {				/* ku 12 */
 129.246 +    0x5092,0x5093,0x5094,0x5096,0x509b,0x509c,0x509e,0x509f,0x50a0,0x50a1,
 129.247 +    0x50a2,0x50aa,0x50af,0x50b0,0x50b9,0x50ba,0x50bd,0x50c0,0x50c3,0x50c4,
 129.248 +    0x50c7,0x50cc,0x50ce,0x50d0,0x50d3,0x50d4,0x50d8,0x50dc,0x50dd,0x50df,
 129.249 +    0x50e2,0x50e4,0x50e6,0x50e8,0x50e9,0x50ef,0x50f1,0x50f6,0x50fa,0x50fe,
 129.250 +    0x5103,0x5106,0x5107,0x5108,0x510b,0x510c,0x510d,0x510e,0x50f2,0x5110,
 129.251 +    0x5117,0x5119,0x511b,0x511c,0x511d,0x511e,0x5123,0x5127,0x5128,0x512c,
 129.252 +    0x512d,0x512f,0x5131,0x5133,0x5134,0x5135,0x5138,0x5139,0x5142,0x514a,
 129.253 +    0x514f,0x5153,0x5155,0x5157,0x5158,0x515f,0x5164,0x5166,0x517e,0x5183,
 129.254 +    0x5184,0x518b,0x518e,0x5198,0x519d,0x51a1,0x51a3,0x51ad,0x51b8,0x51ba,
 129.255 +    0x51bc,0x51be,0x51bf,0x51c2
 129.256 +  },
 129.257 +  {				/* ku 13 */
 129.258 +    0x51c8,0x51cf,0x51d1,0x51d2,0x51d3,0x51d5,0x51d8,0x51de,0x51e2,0x51e5,
 129.259 +    0x51ee,0x51f2,0x51f3,0x51f4,0x51f7,0x5201,0x5202,0x5205,0x5212,0x5213,
 129.260 +    0x5215,0x5216,0x5218,0x5222,0x5228,0x5231,0x5232,0x5235,0x523c,0x5245,
 129.261 +    0x5249,0x5255,0x5257,0x5258,0x525a,0x525c,0x525f,0x5260,0x5261,0x5266,
 129.262 +    0x526e,0x5277,0x5278,0x5279,0x5280,0x5282,0x5285,0x528a,0x528c,0x5293,
 129.263 +    0x5295,0x5296,0x5297,0x5298,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7,
 129.264 +    0x52af,0x52b0,0x52b6,0x52b7,0x52b8,0x52ba,0x52bb,0x52bd,0x52c0,0x52c4,
 129.265 +    0x52c6,0x52c8,0x52cc,0x52cf,0x52d1,0x52d4,0x52d6,0x52db,0x52dc,0x52e1,
 129.266 +    0x52e5,0x52e8,0x52e9,0x52ea,0x52ec,0x52f0,0x52f1,0x52f4,0x52f6,0x52f7,
 129.267 +    0x5300,0x5303,0x530a,0x530b
 129.268 +  },
 129.269 +  {				/* ku 14 */
 129.270 +    0x530c,0x5311,0x5313,0x5318,0x531b,0x531c,0x531e,0x531f,0x5325,0x5327,
 129.271 +    0x5328,0x5329,0x532b,0x532c,0x532d,0x5330,0x5332,0x5335,0x533c,0x533d,
 129.272 +    0x533e,0x5342,0x534c,0x534b,0x5359,0x535b,0x5361,0x5363,0x5365,0x536c,
 129.273 +    0x536d,0x5372,0x5379,0x537e,0x5383,0x5387,0x5388,0x538e,0x5393,0x5394,
 129.274 +    0x5399,0x539d,0x53a1,0x53a4,0x53aa,0x53ab,0x53af,0x53b2,0x53b4,0x53b5,
 129.275 +    0x53b7,0x53b8,0x53ba,0x53bd,0x53c0,0x53c5,0x53cf,0x53d2,0x53d3,0x53d5,
 129.276 +    0x53da,0x53dd,0x53de,0x53e0,0x53e6,0x53e7,0x53f5,0x5402,0x5413,0x541a,
 129.277 +    0x5421,0x5427,0x5428,0x542a,0x542f,0x5431,0x5434,0x5435,0x5443,0x5444,
 129.278 +    0x5447,0x544d,0x544f,0x545e,0x5462,0x5464,0x5466,0x5467,0x5469,0x546b,
 129.279 +    0x546d,0x546e,0x5474,0x547f
 129.280 +  },
 129.281 +  {				/* ku 15 */
 129.282 +    0x5481,0x5483,0x5485,0x5488,0x5489,0x548d,0x5491,0x5495,0x5496,0x549c,
 129.283 +    0x549f,0x54a1,0x54a6,0x54a7,0x54a9,0x54aa,0x54ad,0x54ae,0x54b1,0x54b7,
 129.284 +    0x54b9,0x54ba,0x54bb,0x54bf,0x54c6,0x54ca,0x54cd,0x54ce,0x54e0,0x54ea,
 129.285 +    0x54ec,0x54ef,0x54f6,0x54fc,0x54fe,0x54ff,0x5500,0x5501,0x5505,0x5508,
 129.286 +    0x5509,0x550c,0x550d,0x550e,0x5515,0x552a,0x552b,0x5532,0x5535,0x5536,
 129.287 +    0x553b,0x553c,0x553d,0x5541,0x5547,0x5549,0x554a,0x554d,0x5550,0x5551,
 129.288 +    0x5558,0x555a,0x555b,0x555e,0x5560,0x5561,0x5564,0x5566,0x557f,0x5581,
 129.289 +    0x5582,0x5586,0x5588,0x558e,0x558f,0x5591,0x5592,0x5593,0x5594,0x5597,
 129.290 +    0x55a3,0x55a4,0x55ad,0x55b2,0x55bf,0x55c1,0x55c3,0x55c6,0x55c9,0x55cb,
 129.291 +    0x55cc,0x55ce,0x55d1,0x55d2
 129.292 +  },
 129.293 +  {				/* ku 16 */
 129.294 +    0x55d3,0x55d7,0x55d8,0x55db,0x55de,0x55e2,0x55e9,0x55f6,0x55ff,0x5605,
 129.295 +    0x5608,0x560a,0x560d,0x560e,0x560f,0x5610,0x5611,0x5612,0x5619,0x562c,
 129.296 +    0x5630,0x5633,0x5635,0x5637,0x5639,0x563b,0x563c,0x563d,0x563f,0x5640,
 129.297 +    0x5641,0x5643,0x5644,0x5646,0x5649,0x564b,0x564d,0x564f,0x5654,0x565e,
 129.298 +    0x5660,0x5661,0x5662,0x5663,0x5666,0x5669,0x566d,0x566f,0x5671,0x5672,
 129.299 +    0x5675,0x5684,0x5685,0x5688,0x568b,0x568c,0x5695,0x5699,0x569a,0x569d,
 129.300 +    0x569e,0x569f,0x56a6,0x56a7,0x56a8,0x56a9,0x56ab,0x56ac,0x56ad,0x56b1,
 129.301 +    0x56b3,0x56b7,0x56be,0x56c5,0x56c9,0x56ca,0x56cb,0x56cf,0x56d0,0x56cc,
 129.302 +    0x56cd,0x56d9,0x56dc,0x56dd,0x56df,0x56e1,0x56e4,0x56e5,0x56e6,0x56e7,
 129.303 +    0x56e8,0x56f1,0x56eb,0x56ed
 129.304 +  },
 129.305 +  {				/* ku 17 */
 129.306 +    0x56f6,0x56f7,0x5701,0x5702,0x5707,0x570a,0x570c,0x5711,0x5715,0x571a,
 129.307 +    0x571b,0x571d,0x5720,0x5722,0x5723,0x5724,0x5725,0x5729,0x572a,0x572c,
 129.308 +    0x572e,0x572f,0x5733,0x5734,0x573d,0x573e,0x573f,0x5745,0x5746,0x574c,
 129.309 +    0x574d,0x5752,0x5762,0x5765,0x5767,0x5768,0x576b,0x576d,0x576e,0x576f,
 129.310 +    0x5770,0x5771,0x5773,0x5774,0x5775,0x5777,0x5779,0x577a,0x577b,0x577c,
 129.311 +    0x577e,0x5781,0x5783,0x578c,0x5794,0x5797,0x5799,0x579a,0x579c,0x579d,
 129.312 +    0x579e,0x579f,0x57a1,0x5795,0x57a7,0x57a8,0x57a9,0x57ac,0x57b8,0x57bd,
 129.313 +    0x57c7,0x57c8,0x57cc,0x57cf,0x57d5,0x57dd,0x57de,0x57e4,0x57e6,0x57e7,
 129.314 +    0x57e9,0x57ed,0x57f0,0x57f5,0x57f6,0x57f8,0x57fd,0x57fe,0x57ff,0x5803,
 129.315 +    0x5804,0x5808,0x5809,0x57e1
 129.316 +  },
 129.317 +  {				/* ku 18 */
 129.318 +    0x580c,0x580d,0x581b,0x581e,0x581f,0x5820,0x5826,0x5827,0x582d,0x5832,
 129.319 +    0x5839,0x583f,0x5849,0x584c,0x584d,0x584f,0x5850,0x5855,0x585f,0x5861,
 129.320 +    0x5864,0x5867,0x5868,0x5878,0x587c,0x587f,0x5880,0x5881,0x5887,0x5888,
 129.321 +    0x5889,0x588a,0x588c,0x588d,0x588f,0x5890,0x5894,0x5896,0x589d,0x58a0,
 129.322 +    0x58a1,0x58a2,0x58a6,0x58a9,0x58b1,0x58b2,0x58c4,0x58bc,0x58c2,0x58c8,
 129.323 +    0x58cd,0x58ce,0x58d0,0x58d2,0x58d4,0x58d6,0x58da,0x58dd,0x58e1,0x58e2,
 129.324 +    0x58e9,0x58f3,0x5905,0x5906,0x590b,0x590c,0x5912,0x5913,0x5914,0x8641,
 129.325 +    0x591d,0x5921,0x5923,0x5924,0x5928,0x592f,0x5930,0x5933,0x5935,0x5936,
 129.326 +    0x593f,0x5943,0x5946,0x5952,0x5953,0x5959,0x595b,0x595d,0x595e,0x595f,
 129.327 +    0x5961,0x5963,0x596b,0x596d
 129.328 +  },
 129.329 +  {				/* ku 19 */
 129.330 +    0x596f,0x5972,0x5975,0x5976,0x5979,0x597b,0x597c,0x598b,0x598c,0x598e,
 129.331 +    0x5992,0x5995,0x5997,0x599f,0x59a4,0x59a7,0x59ad,0x59ae,0x59af,0x59b0,
 129.332 +    0x59b3,0x59b7,0x59ba,0x59bc,0x59c1,0x59c3,0x59c4,0x59c8,0x59ca,0x59cd,
 129.333 +    0x59d2,0x59dd,0x59de,0x59df,0x59e3,0x59e4,0x59e7,0x59ee,0x59ef,0x59f1,
 129.334 +    0x59f2,0x59f4,0x59f7,0x5a00,0x5a04,0x5a0c,0x5a0d,0x5a0e,0x5a12,0x5a13,
 129.335 +    0x5a1e,0x5a23,0x5a24,0x5a27,0x5a28,0x5a2a,0x5a2d,0x5a30,0x5a44,0x5a45,
 129.336 +    0x5a47,0x5a48,0x5a4c,0x5a50,0x5a55,0x5a5e,0x5a63,0x5a65,0x5a67,0x5a6d,
 129.337 +    0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a8b,0x5a90,0x5a93,0x5a96,0x5a99,0x5a9c,
 129.338 +    0x5a9e,0x5a9f,0x5aa0,0x5aa2,0x5aa7,0x5aac,0x5ab1,0x5ab2,0x5ab3,0x5ab5,
 129.339 +    0x5ab8,0x5aba,0x5abb,0x5abf
 129.340 +  },
 129.341 +  {				/* ku 1a */
 129.342 +    0x5ac4,0x5ac6,0x5ac8,0x5acf,0x5ada,0x5adc,0x5ae0,0x5ae5,0x5aea,0x5aee,
 129.343 +    0x5af5,0x5af6,0x5afd,0x5b00,0x5b01,0x5b08,0x5b17,0x5b34,0x5b19,0x5b1b,
 129.344 +    0x5b1d,0x5b21,0x5b25,0x5b2d,0x5b38,0x5b41,0x5b4b,0x5b4c,0x5b52,0x5b56,
 129.345 +    0x5b5e,0x5b68,0x5b6e,0x5b6f,0x5b7c,0x5b7d,0x5b7e,0x5b7f,0x5b81,0x5b84,
 129.346 +    0x5b86,0x5b8a,0x5b8e,0x5b90,0x5b91,0x5b93,0x5b94,0x5b96,0x5ba8,0x5ba9,
 129.347 +    0x5bac,0x5bad,0x5baf,0x5bb1,0x5bb2,0x5bb7,0x5bba,0x5bbc,0x5bc0,0x5bc1,
 129.348 +    0x5bcd,0x5bcf,0x5bd6,0x5bd7,0x5bd8,0x5bd9,0x5bda,0x5be0,0x5bef,0x5bf1,
 129.349 +    0x5bf4,0x5bfd,0x5c0c,0x5c17,0x5c1e,0x5c1f,0x5c23,0x5c26,0x5c29,0x5c2b,
 129.350 +    0x5c2c,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c59,0x5c5a,0x5c5c,0x5c62,
 129.351 +    0x5c63,0x5c67,0x5c68,0x5c69
 129.352 +  },
 129.353 +  {				/* ku 1b */
 129.354 +    0x5c6d,0x5c70,0x5c74,0x5c75,0x5c7a,0x5c7b,0x5c7c,0x5c7d,0x5c87,0x5c88,
 129.355 +    0x5c8a,0x5c8f,0x5c92,0x5c9d,0x5c9f,0x5ca0,0x5ca2,0x5ca3,0x5ca6,0x5caa,
 129.356 +    0x5cb2,0x5cb4,0x5cb5,0x5cba,0x5cc9,0x5ccb,0x5cd2,0x5cdd,0x5cd7,0x5cee,
 129.357 +    0x5cf1,0x5cf2,0x5cf4,0x5d01,0x5d06,0x5d0d,0x5d12,0x5d2b,0x5d23,0x5d24,
 129.358 +    0x5d26,0x5d27,0x5d31,0x5d34,0x5d39,0x5d3d,0x5d3f,0x5d42,0x5d43,0x5d46,
 129.359 +    0x5d48,0x5d55,0x5d51,0x5d59,0x5d4a,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d64,
 129.360 +    0x5d6a,0x5d6d,0x5d70,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d83,0x5d88,
 129.361 +    0x5d8a,0x5d92,0x5d93,0x5d94,0x5d95,0x5d99,0x5d9b,0x5d9f,0x5da0,0x5da7,
 129.362 +    0x5dab,0x5db0,0x5db4,0x5db8,0x5db9,0x5dc3,0x5dc7,0x5dcb,0x5dd0,0x5dce,
 129.363 +    0x5dd8,0x5dd9,0x5de0,0x5de4
 129.364 +  },
 129.365 +  {				/* ku 1c */
 129.366 +    0x5de9,0x5df8,0x5df9,0x5e00,0x5e07,0x5e0d,0x5e12,0x5e14,0x5e15,0x5e18,
 129.367 +    0x5e1f,0x5e20,0x5e2e,0x5e28,0x5e32,0x5e35,0x5e3e,0x5e4b,0x5e50,0x5e49,
 129.368 +    0x5e51,0x5e56,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e68,0x5e6a,0x5e6b,0x5e6c,
 129.369 +    0x5e6d,0x5e6e,0x5e70,0x5e80,0x5e8b,0x5e8e,0x5ea2,0x5ea4,0x5ea5,0x5ea8,
 129.370 +    0x5eaa,0x5eac,0x5eb1,0x5eb3,0x5ebd,0x5ebe,0x5ebf,0x5ec6,0x5ecc,0x5ecb,
 129.371 +    0x5ece,0x5ed1,0x5ed2,0x5ed4,0x5ed5,0x5edc,0x5ede,0x5ee5,0x5eeb,0x5f02,
 129.372 +    0x5f06,0x5f07,0x5f08,0x5f0e,0x5f19,0x5f1c,0x5f1d,0x5f21,0x5f22,0x5f23,
 129.373 +    0x5f24,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f34,0x5f36,0x5f3b,0x5f3d,
 129.374 +    0x5f3f,0x5f40,0x5f44,0x5f45,0x5f47,0x5f4d,0x5f50,0x5f54,0x5f58,0x5f5b,
 129.375 +    0x5f60,0x5f63,0x5f64,0x5f67
 129.376 +  },
 129.377 +  {				/* ku 1d */
 129.378 +    0x5f6f,0x5f72,0x5f74,0x5f75,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f89,0x5f8d,
 129.379 +    0x5f8f,0x5f96,0x5f9c,0x5f9d,0x5fa2,0x5fa7,0x5fab,0x5fa4,0x5fac,0x5faf,
 129.380 +    0x5fb0,0x5fb1,0x5fb8,0x5fc4,0x5fc7,0x5fc8,0x5fc9,0x5fcb,0x5fd0,0x5fd1,
 129.381 +    0x5fd2,0x5fd3,0x5fd4,0x5fde,0x5fe1,0x5fe2,0x5fe8,0x5fe9,0x5fea,0x5fec,
 129.382 +    0x5fed,0x5fee,0x5fef,0x5ff2,0x5ff3,0x5ff6,0x5ffa,0x5ffc,0x6007,0x600a,
 129.383 +    0x600d,0x6013,0x6014,0x6017,0x6018,0x601a,0x601f,0x6024,0x602d,0x6033,
 129.384 +    0x6035,0x6040,0x6047,0x6048,0x6049,0x604c,0x6051,0x6054,0x6056,0x6057,
 129.385 +    0x605d,0x6061,0x6067,0x6071,0x607e,0x607f,0x6082,0x6086,0x6088,0x608a,
 129.386 +    0x608e,0x6091,0x6093,0x6095,0x6098,0x609d,0x609e,0x60a2,0x60a4,0x60a5,
 129.387 +    0x60a8,0x60b0,0x60b1,0x60b7
 129.388 +  },
 129.389 +  {				/* ku 1e */
 129.390 +    0x60bb,0x60be,0x60c2,0x60c4,0x60c8,0x60c9,0x60ca,0x60cb,0x60ce,0x60cf,
 129.391 +    0x60d4,0x60d5,0x60d9,0x60db,0x60dd,0x60de,0x60e2,0x60e5,0x60f2,0x60f5,
 129.392 +    0x60f8,0x60fc,0x60fd,0x6102,0x6107,0x610a,0x610c,0x6110,0x6111,0x6112,
 129.393 +    0x6113,0x6114,0x6116,0x6117,0x6119,0x611c,0x611e,0x6122,0x612a,0x612b,
 129.394 +    0x6130,0x6131,0x6135,0x6136,0x6137,0x6139,0x6141,0x6145,0x6146,0x6149,
 129.395 +    0x615e,0x6160,0x616c,0x6172,0x6178,0x617b,0x617c,0x617f,0x6180,0x6181,
 129.396 +    0x6183,0x6184,0x618b,0x618d,0x6192,0x6193,0x6197,0x6198,0x619c,0x619d,
 129.397 +    0x619f,0x61a0,0x61a5,0x61a8,0x61aa,0x61ad,0x61b8,0x61b9,0x61bc,0x61c0,
 129.398 +    0x61c1,0x61c2,0x61ce,0x61cf,0x61d5,0x61dc,0x61dd,0x61de,0x61df,0x61e1,
 129.399 +    0x61e2,0x61e7,0x61e9,0x61e5
 129.400 +  },
 129.401 +  {				/* ku 1f */
 129.402 +    0x61ec,0x61ed,0x61ef,0x6201,0x6203,0x6204,0x6207,0x6213,0x6215,0x621c,
 129.403 +    0x6220,0x6222,0x6223,0x6227,0x6229,0x622b,0x6239,0x623d,0x6242,0x6243,
 129.404 +    0x6244,0x6246,0x624c,0x6250,0x6251,0x6252,0x6254,0x6256,0x625a,0x625c,
 129.405 +    0x6264,0x626d,0x626f,0x6273,0x627a,0x627d,0x628d,0x628e,0x628f,0x6290,
 129.406 +    0x62a6,0x62a8,0x62b3,0x62b6,0x62b7,0x62ba,0x62be,0x62bf,0x62c4,0x62ce,
 129.407 +    0x62d5,0x62d6,0x62da,0x62ea,0x62f2,0x62f4,0x62fc,0x62fd,0x6303,0x6304,
 129.408 +    0x630a,0x630b,0x630d,0x6310,0x6313,0x6316,0x6318,0x6329,0x632a,0x632d,
 129.409 +    0x6335,0x6336,0x6339,0x633c,0x6341,0x6342,0x6343,0x6344,0x6346,0x634a,
 129.410 +    0x634b,0x634e,0x6352,0x6353,0x6354,0x6358,0x635b,0x6365,0x6366,0x636c,
 129.411 +    0x636d,0x6371,0x6374,0x6375
 129.412 +  },
 129.413 +  {				/* ku 20 */
 129.414 +    0x6378,0x637c,0x637d,0x637f,0x6382,0x6384,0x6387,0x638a,0x6390,0x6394,
 129.415 +    0x6395,0x6399,0x639a,0x639e,0x63a4,0x63a6,0x63ad,0x63ae,0x63af,0x63bd,
 129.416 +    0x63c1,0x63c5,0x63c8,0x63ce,0x63d1,0x63d3,0x63d4,0x63d5,0x63dc,0x63e0,
 129.417 +    0x63e5,0x63ea,0x63ec,0x63f2,0x63f3,0x63f5,0x63f8,0x63f9,0x6409,0x640a,
 129.418 +    0x6410,0x6412,0x6414,0x6418,0x641e,0x6420,0x6422,0x6424,0x6425,0x6429,
 129.419 +    0x642a,0x642f,0x6430,0x6435,0x643d,0x643f,0x644b,0x644f,0x6451,0x6452,
 129.420 +    0x6453,0x6454,0x645a,0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6463,
 129.421 +    0x646d,0x6473,0x6474,0x647b,0x647d,0x6485,0x6487,0x648f,0x6490,0x6491,
 129.422 +    0x6498,0x6499,0x649b,0x649d,0x649f,0x64a1,0x64a3,0x64a6,0x64a8,0x64ac,
 129.423 +    0x64b3,0x64bd,0x64be,0x64bf
 129.424 +  },
 129.425 +  {				/* ku 21 */
 129.426 +    0x64c4,0x64c9,0x64ca,0x64cb,0x64cc,0x64ce,0x64d0,0x64d1,0x64d5,0x64d7,
 129.427 +    0x64e4,0x64e5,0x64e9,0x64ea,0x64ed,0x64f0,0x64f5,0x64f7,0x64fb,0x64ff,
 129.428 +    0x6501,0x6504,0x6508,0x6509,0x650a,0x650f,0x6513,0x6514,0x6516,0x6519,
 129.429 +    0x651b,0x651e,0x651f,0x6522,0x6526,0x6529,0x652e,0x6531,0x653a,0x653c,
 129.430 +    0x653d,0x6543,0x6547,0x6549,0x6550,0x6552,0x6554,0x655f,0x6560,0x6567,
 129.431 +    0x656b,0x657a,0x657d,0x6581,0x6585,0x658a,0x6592,0x6595,0x6598,0x659d,
 129.432 +    0x65a0,0x65a3,0x65a6,0x65ae,0x65b2,0x65b3,0x65b4,0x65bf,0x65c2,0x65c8,
 129.433 +    0x65c9,0x65ce,0x65d0,0x65d4,0x65d6,0x65d8,0x65df,0x65f0,0x65f2,0x65f4,
 129.434 +    0x65f5,0x65f9,0x65fe,0x65ff,0x6600,0x6604,0x6608,0x6609,0x660d,0x6611,
 129.435 +    0x6612,0x6615,0x6616,0x661d
 129.436 +  },
 129.437 +  {				/* ku 22 */
 129.438 +    0x661e,0x6621,0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c,
 129.439 +    0x662e,0x6630,0x6631,0x6633,0x6639,0x6637,0x6640,0x6645,0x6646,0x664a,
 129.440 +    0x664c,0x6651,0x664e,0x6657,0x6658,0x6659,0x665b,0x665c,0x6660,0x6661,
 129.441 +    0x66fb,0x666a,0x666b,0x666c,0x667e,0x6673,0x6675,0x667f,0x6677,0x6678,
 129.442 +    0x6679,0x667b,0x6680,0x667c,0x668b,0x668c,0x668d,0x6690,0x6692,0x6699,
 129.443 +    0x669a,0x669b,0x669c,0x669f,0x66a0,0x66a4,0x66ad,0x66b1,0x66b2,0x66b5,
 129.444 +    0x66bb,0x66bf,0x66c0,0x66c2,0x66c3,0x66c8,0x66cc,0x66ce,0x66cf,0x66d4,
 129.445 +    0x66db,0x66df,0x66e8,0x66eb,0x66ec,0x66ee,0x66fa,0x6705,0x6707,0x670e,
 129.446 +    0x6713,0x6719,0x671c,0x6720,0x6722,0x6733,0x673e,0x6745,0x6747,0x6748,
 129.447 +    0x674c,0x6754,0x6755,0x675d
 129.448 +  },
 129.449 +  {				/* ku 23 */
 129.450 +    0x6766,0x676c,0x676e,0x6774,0x6776,0x677b,0x6781,0x6784,0x678e,0x678f,
 129.451 +    0x6791,0x6793,0x6796,0x6798,0x6799,0x679b,0x67b0,0x67b1,0x67b2,0x67b5,
 129.452 +    0x67bb,0x67bc,0x67bd,0x67f9,0x67c0,0x67c2,0x67c3,0x67c5,0x67c8,0x67c9,
 129.453 +    0x67d2,0x67d7,0x67d9,0x67dc,0x67e1,0x67e6,0x67f0,0x67f2,0x67f6,0x67f7,
 129.454 +    0x6852,0x6814,0x6819,0x681d,0x681f,0x6828,0x6827,0x682c,0x682d,0x682f,
 129.455 +    0x6830,0x6831,0x6833,0x683b,0x683f,0x6844,0x6845,0x684a,0x684c,0x6855,
 129.456 +    0x6857,0x6858,0x685b,0x686b,0x686e,0x686f,0x6870,0x6871,0x6872,0x6875,
 129.457 +    0x6879,0x687a,0x687b,0x687c,0x6882,0x6884,0x6886,0x6888,0x6896,0x6898,
 129.458 +    0x689a,0x689c,0x68a1,0x68a3,0x68a5,0x68a9,0x68aa,0x68ae,0x68b2,0x68bb,
 129.459 +    0x68c5,0x68c8,0x68cc,0x68cf
 129.460 +  },
 129.461 +  {				/* ku 24 */
 129.462 +    0x68d0,0x68d1,0x68d3,0x68d6,0x68d9,0x68dc,0x68dd,0x68e5,0x68e8,0x68ea,
 129.463 +    0x68eb,0x68ec,0x68ed,0x68f0,0x68f1,0x68f5,0x68f6,0x68fb,0x68fc,0x68fd,
 129.464 +    0x6906,0x6909,0x690a,0x6910,0x6911,0x6913,0x6916,0x6917,0x6931,0x6933,
 129.465 +    0x6935,0x6938,0x693b,0x6942,0x6945,0x6949,0x694e,0x6957,0x695b,0x6963,
 129.466 +    0x6964,0x6965,0x6966,0x6968,0x6969,0x696c,0x6970,0x6971,0x6972,0x697a,
 129.467 +    0x697b,0x697f,0x6980,0x698d,0x6992,0x6996,0x6998,0x69a1,0x69a5,0x69a6,
 129.468 +    0x69a8,0x69ab,0x69ad,0x69af,0x69b7,0x69b8,0x69ba,0x69bc,0x69c5,0x69c8,
 129.469 +    0x69d1,0x69d6,0x69d7,0x69e2,0x69e5,0x69ee,0x69ef,0x69f1,0x69f3,0x69f5,
 129.470 +    0x69fe,0x6a00,0x6a01,0x6a03,0x6a0f,0x6a11,0x6a15,0x6a1a,0x6a1d,0x6a20,
 129.471 +    0x6a24,0x6a28,0x6a30,0x6a32
 129.472 +  },
 129.473 +  {				/* ku 25 */
 129.474 +    0x6a34,0x6a37,0x6a3b,0x6a3e,0x6a3f,0x6a45,0x6a46,0x6a49,0x6a4a,0x6a4e,
 129.475 +    0x6a50,0x6a51,0x6a52,0x6a55,0x6a56,0x6a5b,0x6a64,0x6a67,0x6a6a,0x6a71,
 129.476 +    0x6a73,0x6a7e,0x6a81,0x6a83,0x6a86,0x6a87,0x6a89,0x6a8b,0x6a91,0x6a9b,
 129.477 +    0x6a9d,0x6a9e,0x6a9f,0x6aa5,0x6aab,0x6aaf,0x6ab0,0x6ab1,0x6ab4,0x6abd,
 129.478 +    0x6abe,0x6abf,0x6ac6,0x6ac9,0x6ac8,0x6acc,0x6ad0,0x6ad4,0x6ad5,0x6ad6,
 129.479 +    0x6adc,0x6add,0x6ae4,0x6ae7,0x6aec,0x6af0,0x6af1,0x6af2,0x6afc,0x6afd,
 129.480 +    0x6b02,0x6b03,0x6b06,0x6b07,0x6b09,0x6b0f,0x6b10,0x6b11,0x6b17,0x6b1b,
 129.481 +    0x6b1e,0x6b24,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b35,0x6b36,0x6b3b,0x6b3f,
 129.482 +    0x6b46,0x6b4a,0x6b4d,0x6b52,0x6b56,0x6b58,0x6b5d,0x6b60,0x6b67,0x6b6b,
 129.483 +    0x6b6e,0x6b70,0x6b75,0x6b7d
 129.484 +  },
 129.485 +  {				/* ku 26 */
 129.486 +    0x6b7e,0x6b82,0x6b85,0x6b97,0x6b9b,0x6b9f,0x6ba0,0x6ba2,0x6ba3,0x6ba8,
 129.487 +    0x6ba9,0x6bac,0x6bad,0x6bae,0x6bb0,0x6bb8,0x6bb9,0x6bbd,0x6bbe,0x6bc3,
 129.488 +    0x6bc4,0x6bc9,0x6bcc,0x6bd6,0x6bda,0x6be1,0x6be3,0x6be6,0x6be7,0x6bee,
 129.489 +    0x6bf1,0x6bf7,0x6bf9,0x6bff,0x6c02,0x6c04,0x6c05,0x6c09,0x6c0d,0x6c0e,
 129.490 +    0x6c10,0x6c12,0x6c19,0x6c1f,0x6c26,0x6c27,0x6c28,0x6c2c,0x6c2e,0x6c33,
 129.491 +    0x6c35,0x6c36,0x6c3a,0x6c3b,0x6c3f,0x6c4a,0x6c4b,0x6c4d,0x6c4f,0x6c52,
 129.492 +    0x6c54,0x6c59,0x6c5b,0x6c5c,0x6c6b,0x6c6d,0x6c6f,0x6c74,0x6c76,0x6c78,
 129.493 +    0x6c79,0x6c7b,0x6c85,0x6c86,0x6c87,0x6c89,0x6c94,0x6c95,0x6c97,0x6c98,
 129.494 +    0x6c9c,0x6c9f,0x6cb0,0x6cb2,0x6cb4,0x6cc2,0x6cc6,0x6ccd,0x6ccf,0x6cd0,
 129.495 +    0x6cd1,0x6cd2,0x6cd4,0x6cd6
 129.496 +  },
 129.497 +  {				/* ku 27 */
 129.498 +    0x6cda,0x6cdc,0x6ce0,0x6ce7,0x6ce9,0x6ceb,0x6cec,0x6cee,0x6cf2,0x6cf4,
 129.499 +    0x6d04,0x6d07,0x6d0a,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d1a,0x6d26,0x6d27,
 129.500 +    0x6d28,0x6c67,0x6d2e,0x6d2f,0x6d31,0x6d39,0x6d3c,0x6d3f,0x6d57,0x6d5e,
 129.501 +    0x6d5f,0x6d61,0x6d65,0x6d67,0x6d6f,0x6d70,0x6d7c,0x6d82,0x6d87,0x6d91,
 129.502 +    0x6d92,0x6d94,0x6d96,0x6d97,0x6d98,0x6daa,0x6dac,0x6db4,0x6db7,0x6db9,
 129.503 +    0x6dbd,0x6dbf,0x6dc4,0x6dc8,0x6dca,0x6dce,0x6dcf,0x6dd6,0x6ddb,0x6ddd,
 129.504 +    0x6ddf,0x6de0,0x6de2,0x6de5,0x6de9,0x6def,0x6df0,0x6df4,0x6df6,0x6dfc,
 129.505 +    0x6e00,0x6e04,0x6e1e,0x6e22,0x6e27,0x6e32,0x6e36,0x6e39,0x6e3b,0x6e3c,
 129.506 +    0x6e44,0x6e45,0x6e48,0x6e49,0x6e4b,0x6e4f,0x6e51,0x6e52,0x6e53,0x6e54,
 129.507 +    0x6e57,0x6e5c,0x6e5d,0x6e5e
 129.508 +  },
 129.509 +  {				/* ku 28 */
 129.510 +    0x6e62,0x6e63,0x6e68,0x6e73,0x6e7b,0x6e7d,0x6e8d,0x6e93,0x6e99,0x6ea0,
 129.511 +    0x6ea7,0x6ead,0x6eae,0x6eb1,0x6eb3,0x6ebb,0x6ebf,0x6ec0,0x6ec1,0x6ec3,
 129.512 +    0x6ec7,0x6ec8,0x6eca,0x6ecd,0x6ece,0x6ecf,0x6eeb,0x6eed,0x6eee,0x6ef9,
 129.513 +    0x6efb,0x6efd,0x6f04,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f16,0x6f18,0x6f1a,
 129.514 +    0x6f1b,0x6f26,0x6f29,0x6f2a,0x6f2f,0x6f30,0x6f33,0x6f36,0x6f3b,0x6f3c,
 129.515 +    0x6f2d,0x6f4f,0x6f51,0x6f52,0x6f53,0x6f57,0x6f59,0x6f5a,0x6f5d,0x6f5e,
 129.516 +    0x6f61,0x6f62,0x6f68,0x6f6c,0x6f7d,0x6f7e,0x6f83,0x6f87,0x6f88,0x6f8b,
 129.517 +    0x6f8c,0x6f8d,0x6f90,0x6f92,0x6f93,0x6f94,0x6f96,0x6f9a,0x6f9f,0x6fa0,
 129.518 +    0x6fa5,0x6fa6,0x6fa7,0x6fa8,0x6fae,0x6faf,0x6fb0,0x6fb5,0x6fb6,0x6fbc,
 129.519 +    0x6fc5,0x6fc7,0x6fc8,0x6fca
 129.520 +  },
 129.521 +  {				/* ku 29 */
 129.522 +    0x6fda,0x6fde,0x6fe8,0x6fe9,0x6ff0,0x6ff5,0x6ff9,0x6ffc,0x6ffd,0x7000,
 129.523 +    0x7005,0x7006,0x7007,0x700d,0x7017,0x7020,0x7023,0x702f,0x7034,0x7037,
 129.524 +    0x7039,0x703c,0x7043,0x7044,0x7048,0x7049,0x704a,0x704b,0x7054,0x7055,
 129.525 +    0x705d,0x705e,0x704e,0x7064,0x7065,0x706c,0x706e,0x7075,0x7076,0x707e,
 129.526 +    0x7081,0x7085,0x7086,0x7094,0x7095,0x7096,0x7097,0x7098,0x709b,0x70a4,
 129.527 +    0x70ab,0x70b0,0x70b1,0x70b4,0x70b7,0x70ca,0x70d1,0x70d3,0x70d4,0x70d5,
 129.528 +    0x70d6,0x70d8,0x70dc,0x70e4,0x70fa,0x7103,0x7104,0x7105,0x7106,0x7107,
 129.529 +    0x710b,0x710c,0x710f,0x711e,0x7120,0x712b,0x712d,0x712f,0x7130,0x7131,
 129.530 +    0x7138,0x7141,0x7145,0x7146,0x7147,0x714a,0x714b,0x7150,0x7152,0x7157,
 129.531 +    0x715a,0x715c,0x715e,0x7160
 129.532 +  },
 129.533 +  {				/* ku 2a */
 129.534 +    0x7168,0x7179,0x7180,0x7185,0x7187,0x718c,0x7192,0x719a,0x719b,0x71a0,
 129.535 +    0x71a2,0x71af,0x71b0,0x71b2,0x71b3,0x71ba,0x71bf,0x71c0,0x71c1,0x71c4,
 129.536 +    0x71cb,0x71cc,0x71d3,0x71d6,0x71d9,0x71da,0x71dc,0x71f8,0x71fe,0x7200,
 129.537 +    0x7207,0x7208,0x7209,0x7213,0x7217,0x721a,0x721d,0x721f,0x7224,0x722b,
 129.538 +    0x722f,0x7234,0x7238,0x7239,0x7241,0x7242,0x7243,0x7245,0x724e,0x724f,
 129.539 +    0x7250,0x7253,0x7255,0x7256,0x725a,0x725c,0x725e,0x7260,0x7263,0x7268,
 129.540 +    0x726b,0x726e,0x726f,0x7271,0x7277,0x7278,0x727b,0x727c,0x727f,0x7284,
 129.541 +    0x7289,0x728d,0x728e,0x7293,0x729b,0x72a8,0x72ad,0x72ae,0x72b1,0x72b4,
 129.542 +    0x72be,0x72c1,0x72c7,0x72c9,0x72cc,0x72d5,0x72d6,0x72d8,0x72df,0x72e5,
 129.543 +    0x72f3,0x72f4,0x72fa,0x72fb
 129.544 +  },
 129.545 +  {				/* ku 2b */
 129.546 +    0x72fe,0x7302,0x7304,0x7305,0x7307,0x730b,0x730d,0x7312,0x7313,0x7318,
 129.547 +    0x7319,0x731e,0x7322,0x7324,0x7327,0x7328,0x732c,0x7331,0x7332,0x7335,
 129.548 +    0x733a,0x733b,0x733d,0x7343,0x734d,0x7350,0x7352,0x7356,0x7358,0x735d,
 129.549 +    0x735e,0x735f,0x7360,0x7366,0x7367,0x7369,0x736b,0x736c,0x736e,0x736f,
 129.550 +    0x7371,0x7377,0x7379,0x737c,0x7380,0x7381,0x7383,0x7385,0x7386,0x738e,
 129.551 +    0x7390,0x7393,0x7395,0x7397,0x7398,0x739c,0x739e,0x739f,0x73a0,0x73a2,
 129.552 +    0x73a5,0x73a6,0x73aa,0x73ab,0x73ad,0x73b5,0x73b7,0x73b9,0x73bc,0x73bd,
 129.553 +    0x73bf,0x73c5,0x73c6,0x73c9,0x73cb,0x73cc,0x73cf,0x73d2,0x73d3,0x73d6,
 129.554 +    0x73d9,0x73dd,0x73e1,0x73e3,0x73e6,0x73e7,0x73e9,0x73f4,0x73f5,0x73f7,
 129.555 +    0x73f9,0x73fa,0x73fb,0x73fd
 129.556 +  },
 129.557 +  {				/* ku 2c */
 129.558 +    0x73ff,0x7400,0x7401,0x7404,0x7407,0x740a,0x7411,0x741a,0x741b,0x7424,
 129.559 +    0x7426,0x7428,0x7429,0x742a,0x742b,0x742c,0x742d,0x742e,0x742f,0x7430,
 129.560 +    0x7431,0x7439,0x7440,0x7443,0x7444,0x7446,0x7447,0x744b,0x744d,0x7451,
 129.561 +    0x7452,0x7457,0x745d,0x7462,0x7466,0x7467,0x7468,0x746b,0x746d,0x746e,
 129.562 +    0x7471,0x7472,0x7480,0x7481,0x7485,0x7486,0x7487,0x7489,0x748f,0x7490,
 129.563 +    0x7491,0x7492,0x7498,0x7499,0x749a,0x749c,0x749f,0x74a0,0x74a1,0x74a3,
 129.564 +    0x74a6,0x74a8,0x74a9,0x74aa,0x74ab,0x74ae,0x74af,0x74b1,0x74b2,0x74b5,
 129.565 +    0x74b9,0x74bb,0x74bf,0x74c8,0x74c9,0x74cc,0x74d0,0x74d3,0x74d8,0x74da,
 129.566 +    0x74db,0x74de,0x74df,0x74e4,0x74e8,0x74ea,0x74eb,0x74ef,0x74f4,0x74fa,
 129.567 +    0x74fb,0x74fc,0x74ff,0x7506
 129.568 +  },
 129.569 +  {				/* ku 2d */
 129.570 +    0x7512,0x7516,0x7517,0x7520,0x7521,0x7524,0x7527,0x7529,0x752a,0x752f,
 129.571 +    0x7536,0x7539,0x753d,0x753e,0x753f,0x7540,0x7543,0x7547,0x7548,0x754e,
 129.572 +    0x7550,0x7552,0x7557,0x755e,0x755f,0x7561,0x756f,0x7571,0x7579,0x757a,
 129.573 +    0x757b,0x757c,0x757d,0x757e,0x7581,0x7585,0x7590,0x7592,0x7593,0x7595,
 129.574 +    0x7599,0x759c,0x75a2,0x75a4,0x75b4,0x75ba,0x75bf,0x75c0,0x75c1,0x75c4,
 129.575 +    0x75c6,0x75cc,0x75ce,0x75cf,0x75d7,0x75dc,0x75df,0x75e0,0x75e1,0x75e4,
 129.576 +    0x75e7,0x75ec,0x75ee,0x75ef,0x75f1,0x75f9,0x7600,0x7602,0x7603,0x7604,
 129.577 +    0x7607,0x7608,0x760a,0x760c,0x760f,0x7612,0x7613,0x7615,0x7616,0x7619,
 129.578 +    0x761b,0x761c,0x761d,0x761e,0x7623,0x7625,0x7626,0x7629,0x762d,0x7632,
 129.579 +    0x7633,0x7635,0x7638,0x7639
 129.580 +  },
 129.581 +  {				/* ku 2e */
 129.582 +    0x763a,0x763c,0x764a,0x7640,0x7641,0x7643,0x7644,0x7645,0x7649,0x764b,
 129.583 +    0x7655,0x7659,0x765f,0x7664,0x7665,0x766d,0x766e,0x766f,0x7671,0x7674,
 129.584 +    0x7681,0x7685,0x768c,0x768d,0x7695,0x769b,0x769c,0x769d,0x769f,0x76a0,
 129.585 +    0x76a2,0x76a3,0x76a4,0x76a5,0x76a6,0x76a7,0x76a8,0x76aa,0x76ad,0x76bd,
 129.586 +    0x76c1,0x76c5,0x76c9,0x76cb,0x76cc,0x76ce,0x76d4,0x76d9,0x76e0,0x76e6,
 129.587 +    0x76e8,0x76ec,0x76f0,0x76f1,0x76f6,0x76f9,0x76fc,0x7700,0x7706,0x770a,
 129.588 +    0x770e,0x7712,0x7714,0x7715,0x7717,0x7719,0x771a,0x771c,0x7722,0x7728,
 129.589 +    0x772d,0x772e,0x772f,0x7734,0x7735,0x7736,0x7739,0x773d,0x773e,0x7742,
 129.590 +    0x7745,0x7746,0x774a,0x774d,0x774e,0x774f,0x7752,0x7756,0x7757,0x775c,
 129.591 +    0x775e,0x775f,0x7760,0x7762
 129.592 +  },
 129.593 +  {				/* ku 2f */
 129.594 +    0x7764,0x7767,0x776a,0x776c,0x7770,0x7772,0x7773,0x7774,0x777a,0x777d,
 129.595 +    0x7780,0x7784,0x778c,0x778d,0x7794,0x7795,0x7796,0x779a,0x779f,0x77a2,
 129.596 +    0x77a7,0x77aa,0x77ae,0x77af,0x77b1,0x77b5,0x77be,0x77c3,0x77c9,0x77d1,
 129.597 +    0x77d2,0x77d5,0x77d9,0x77de,0x77df,0x77e0,0x77e4,0x77e6,0x77ea,0x77ec,
 129.598 +    0x77f0,0x77f1,0x77f4,0x77f8,0x77fb,0x7805,0x7806,0x7809,0x780d,0x780e,
 129.599 +    0x7811,0x781d,0x7821,0x7822,0x7823,0x782d,0x782e,0x7830,0x7835,0x7837,
 129.600 +    0x7843,0x7844,0x7847,0x7848,0x784c,0x784e,0x7852,0x785c,0x785e,0x7860,
 129.601 +    0x7861,0x7863,0x7864,0x7868,0x786a,0x786e,0x787a,0x787e,0x788a,0x788f,
 129.602 +    0x7894,0x7898,0x78a1,0x789d,0x789e,0x789f,0x78a4,0x78a8,0x78ac,0x78ad,
 129.603 +    0x78b0,0x78b1,0x78b2,0x78b3
 129.604 +  },
 129.605 +  {				/* ku 30 */
 129.606 +    0x78bb,0x78bd,0x78bf,0x78c7,0x78c8,0x78c9,0x78cc,0x78ce,0x78d2,0x78d3,
 129.607 +    0x78d5,0x78d6,0x78e4,0x78db,0x78df,0x78e0,0x78e1,0x78e6,0x78ea,0x78f2,
 129.608 +    0x78f3,0x7900,0x78f6,0x78f7,0x78fa,0x78fb,0x78ff,0x7906,0x790c,0x7910,
 129.609 +    0x791a,0x791c,0x791e,0x791f,0x7920,0x7925,0x7927,0x7929,0x792d,0x7931,
 129.610 +    0x7934,0x7935,0x793b,0x793d,0x793f,0x7944,0x7945,0x7946,0x794a,0x794b,
 129.611 +    0x794f,0x7951,0x7954,0x7958,0x795b,0x795c,0x7967,0x7969,0x796b,0x7972,
 129.612 +    0x7979,0x797b,0x797c,0x797e,0x798b,0x798c,0x7991,0x7993,0x7994,0x7995,
 129.613 +    0x7996,0x7998,0x799b,0x799c,0x79a1,0x79a8,0x79a9,0x79ab,0x79af,0x79b1,
 129.614 +    0x79b4,0x79b8,0x79bb,0x79c2,0x79c4,0x79c7,0x79c8,0x79ca,0x79cf,0x79d4,
 129.615 +    0x79d6,0x79da,0x79dd,0x79de
 129.616 +  },
 129.617 +  {				/* ku 31 */
 129.618 +    0x79e0,0x79e2,0x79e5,0x79ea,0x79eb,0x79ed,0x79f1,0x79f8,0x79fc,0x7a02,
 129.619 +    0x7a03,0x7a07,0x7a09,0x7a0a,0x7a0c,0x7a11,0x7a15,0x7a1b,0x7a1e,0x7a21,
 129.620 +    0x7a27,0x7a2b,0x7a2d,0x7a2f,0x7a30,0x7a34,0x7a35,0x7a38,0x7a39,0x7a3a,
 129.621 +    0x7a44,0x7a45,0x7a47,0x7a48,0x7a4c,0x7a55,0x7a56,0x7a59,0x7a5c,0x7a5d,
 129.622 +    0x7a5f,0x7a60,0x7a65,0x7a67,0x7a6a,0x7a6d,0x7a75,0x7a78,0x7a7e,0x7a80,
 129.623 +    0x7a82,0x7a85,0x7a86,0x7a8a,0x7a8b,0x7a90,0x7a91,0x7a94,0x7a9e,0x7aa0,
 129.624 +    0x7aa3,0x7aac,0x7ab3,0x7ab5,0x7ab9,0x7abb,0x7abc,0x7ac6,0x7ac9,0x7acc,
 129.625 +    0x7ace,0x7ad1,0x7adb,0x7ae8,0x7ae9,0x7aeb,0x7aec,0x7af1,0x7af4,0x7afb,
 129.626 +    0x7afd,0x7afe,0x7b07,0x7b14,0x7b1f,0x7b23,0x7b27,0x7b29,0x7b2a,0x7b2b,
 129.627 +    0x7b2d,0x7b2e,0x7b2f,0x7b30
 129.628 +  },
 129.629 +  {				/* ku 32 */
 129.630 +    0x7b31,0x7b34,0x7b3d,0x7b3f,0x7b40,0x7b41,0x7b47,0x7b4e,0x7b55,0x7b60,
 129.631 +    0x7b64,0x7b66,0x7b69,0x7b6a,0x7b6d,0x7b6f,0x7b72,0x7b73,0x7b77,0x7b84,
 129.632 +    0x7b89,0x7b8e,0x7b90,0x7b91,0x7b96,0x7b9b,0x7b9e,0x7ba0,0x7ba5,0x7bac,
 129.633 +    0x7baf,0x7bb0,0x7bb2,0x7bb5,0x7bb6,0x7bba,0x7bbb,0x7bbc,0x7bbd,0x7bc2,
 129.634 +    0x7bc5,0x7bc8,0x7bca,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bda,0x7bdb,0x7be8,
 129.635 +    0x7bea,0x7bf2,0x7bf4,0x7bf5,0x7bf8,0x7bf9,0x7bfa,0x7bfc,0x7bfe,0x7c01,
 129.636 +    0x7c02,0x7c03,0x7c04,0x7c06,0x7c09,0x7c0b,0x7c0c,0x7c0e,0x7c0f,0x7c19,
 129.637 +    0x7c1b,0x7c20,0x7c25,0x7c26,0x7c28,0x7c2c,0x7c31,0x7c33,0x7c34,0x7c36,
 129.638 +    0x7c39,0x7c3a,0x7c46,0x7c4a,0x7c55,0x7c51,0x7c52,0x7c53,0x7c59,0x7c5a,
 129.639 +    0x7c5b,0x7c5c,0x7c5d,0x7c5e
 129.640 +  },
 129.641 +  {				/* ku 33 */
 129.642 +    0x7c61,0x7c63,0x7c67,0x7c69,0x7c6d,0x7c6e,0x7c70,0x7c72,0x7c79,0x7c7c,
 129.643 +    0x7c7d,0x7c86,0x7c87,0x7c8f,0x7c94,0x7c9e,0x7ca0,0x7ca6,0x7cb0,0x7cb6,
 129.644 +    0x7cb7,0x7cba,0x7cbb,0x7cbc,0x7cbf,0x7cc4,0x7cc7,0x7cc8,0x7cc9,0x7ccd,
 129.645 +    0x7ccf,0x7cd3,0x7cd4,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdd,0x7ce6,0x7ce9,
 129.646 +    0x7ceb,0x7cf5,0x7d03,0x7d07,0x7d08,0x7d09,0x7d0f,0x7d11,0x7d12,0x7d13,
 129.647 +    0x7d16,0x7d1d,0x7d1e,0x7d23,0x7d26,0x7d2a,0x7d2d,0x7d31,0x7d3c,0x7d3d,
 129.648 +    0x7d3e,0x7d40,0x7d41,0x7d47,0x7d48,0x7d4d,0x7d51,0x7d53,0x7d57,0x7d59,
 129.649 +    0x7d5a,0x7d5c,0x7d5d,0x7d65,0x7d67,0x7d6a,0x7d70,0x7d78,0x7d7a,0x7d7b,
 129.650 +    0x7d7f,0x7d81,0x7d82,0x7d83,0x7d85,0x7d86,0x7d88,0x7d8b,0x7d8c,0x7d8d,
 129.651 +    0x7d91,0x7d96,0x7d97,0x7d9d
 129.652 +  },
 129.653 +  {				/* ku 34 */
 129.654 +    0x7d9e,0x7da6,0x7da7,0x7daa,0x7db3,0x7db6,0x7db7,0x7db9,0x7dc2,0x7dc3,
 129.655 +    0x7dc4,0x7dc5,0x7dc6,0x7dcc,0x7dcd,0x7dce,0x7dd7,0x7dd9,0x7e00,0x7de2,
 129.656 +    0x7de5,0x7de6,0x7dea,0x7deb,0x7ded,0x7df1,0x7df5,0x7df6,0x7df9,0x7dfa,
 129.657 +    0x7e08,0x7e10,0x7e11,0x7e15,0x7e17,0x7e1c,0x7e1d,0x7e20,0x7e27,0x7e28,
 129.658 +    0x7e2c,0x7e2d,0x7e2f,0x7e33,0x7e36,0x7e3f,0x7e44,0x7e45,0x7e47,0x7e4e,
 129.659 +    0x7e50,0x7e52,0x7e58,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e6b,0x7e6e,0x7e6f,
 129.660 +    0x7e73,0x7e78,0x7e7e,0x7e81,0x7e86,0x7e87,0x7e8a,0x7e8d,0x7e91,0x7e95,
 129.661 +    0x7e98,0x7e9a,0x7e9d,0x7e9e,0x7f3c,0x7f3b,0x7f3d,0x7f3e,0x7f3f,0x7f43,
 129.662 +    0x7f44,0x7f47,0x7f4f,0x7f52,0x7f53,0x7f5b,0x7f5c,0x7f5d,0x7f61,0x7f63,
 129.663 +    0x7f64,0x7f65,0x7f66,0x7f6d
 129.664 +  },
 129.665 +  {				/* ku 35 */
 129.666 +    0x7f71,0x7f7d,0x7f7e,0x7f7f,0x7f80,0x7f8b,0x7f8d,0x7f8f,0x7f90,0x7f91,
 129.667 +    0x7f96,0x7f97,0x7f9c,0x7fa1,0x7fa2,0x7fa6,0x7faa,0x7fad,0x7fb4,0x7fbc,
 129.668 +    0x7fbf,0x7fc0,0x7fc3,0x7fc8,0x7fce,0x7fcf,0x7fdb,0x7fdf,0x7fe3,0x7fe5,
 129.669 +    0x7fe8,0x7fec,0x7fee,0x7fef,0x7ff2,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8007,
 129.670 +    0x8008,0x800a,0x800d,0x800e,0x800f,0x8011,0x8013,0x8014,0x8016,0x801d,
 129.671 +    0x801e,0x801f,0x8020,0x8024,0x8026,0x802c,0x802e,0x8030,0x8034,0x8035,
 129.672 +    0x8037,0x8039,0x803a,0x803c,0x803e,0x8040,0x8044,0x8060,0x8064,0x8066,
 129.673 +    0x806d,0x8071,0x8075,0x8081,0x8088,0x808e,0x809c,0x809e,0x80a6,0x80a7,
 129.674 +    0x80ab,0x80b8,0x80b9,0x80c8,0x80cd,0x80cf,0x80d2,0x80d4,0x80d5,0x80d7,
 129.675 +    0x80d8,0x80e0,0x80ed,0x80ee
 129.676 +  },
 129.677 +  {				/* ku 36 */
 129.678 +    0x80f0,0x80f2,0x80f3,0x80f6,0x80f9,0x80fa,0x80fe,0x8103,0x810b,0x8116,
 129.679 +    0x8117,0x8118,0x811c,0x811e,0x8120,0x8124,0x8127,0x812c,0x8130,0x8135,
 129.680 +    0x813a,0x813c,0x8145,0x8147,0x814a,0x814c,0x8152,0x8157,0x8160,0x8161,
 129.681 +    0x8167,0x8168,0x8169,0x816d,0x816f,0x8177,0x8181,0x8190,0x8184,0x8185,
 129.682 +    0x8186,0x818b,0x818e,0x8196,0x8198,0x819b,0x819e,0x81a2,0x81ae,0x81b2,
 129.683 +    0x81b4,0x81bb,0x81cb,0x81c3,0x81c5,0x81ca,0x81ce,0x81cf,0x81d5,0x81d7,
 129.684 +    0x81db,0x81dd,0x81de,0x81e1,0x81e4,0x81eb,0x81ec,0x81f0,0x81f1,0x81f2,
 129.685 +    0x81f5,0x81f6,0x81f8,0x81f9,0x81fd,0x81ff,0x8200,0x8203,0x820f,0x8213,
 129.686 +    0x8214,0x8219,0x821a,0x821d,0x8221,0x8222,0x8228,0x8232,0x8234,0x823a,
 129.687 +    0x8243,0x8244,0x8245,0x8246
 129.688 +  },
 129.689 +  {				/* ku 37 */
 129.690 +    0x824b,0x824e,0x824f,0x8251,0x8256,0x825c,0x8260,0x8263,0x8267,0x826d,
 129.691 +    0x8274,0x827b,0x827d,0x827f,0x8280,0x8281,0x8283,0x8284,0x8287,0x8289,
 129.692 +    0x828a,0x828e,0x8291,0x8294,0x8296,0x8298,0x829a,0x829b,0x82a0,0x82a1,
 129.693 +    0x82a3,0x82a4,0x82a7,0x82a8,0x82a9,0x82aa,0x82ae,0x82b0,0x82b2,0x82b4,
 129.694 +    0x82b7,0x82ba,0x82bc,0x82be,0x82bf,0x82c6,0x82d0,0x82d5,0x82da,0x82e0,
 129.695 +    0x82e2,0x82e4,0x82e8,0x82ea,0x82ed,0x82ef,0x82f6,0x82f7,0x82fd,0x82fe,
 129.696 +    0x8300,0x8301,0x8307,0x8308,0x830a,0x830b,0x8354,0x831b,0x831d,0x831e,
 129.697 +    0x831f,0x8321,0x8322,0x832c,0x832d,0x832e,0x8330,0x8333,0x8337,0x833a,
 129.698 +    0x833c,0x833d,0x8342,0x8343,0x8344,0x8347,0x834d,0x834e,0x8351,0x8355,
 129.699 +    0x8356,0x8357,0x8370,0x8378
 129.700 +  },
 129.701 +  {				/* ku 38 */
 129.702 +    0x837d,0x837f,0x8380,0x8382,0x8384,0x8386,0x838d,0x8392,0x8394,0x8395,
 129.703 +    0x8398,0x8399,0x839b,0x839c,0x839d,0x83a6,0x83a7,0x83a9,0x83ac,0x83be,
 129.704 +    0x83bf,0x83c0,0x83c7,0x83c9,0x83cf,0x83d0,0x83d1,0x83d4,0x83dd,0x8353,
 129.705 +    0x83e8,0x83ea,0x83f6,0x83f8,0x83f9,0x83fc,0x8401,0x8406,0x840a,0x840f,
 129.706 +    0x8411,0x8415,0x8419,0x83ad,0x842f,0x8439,0x8445,0x8447,0x8448,0x844a,
 129.707 +    0x844d,0x844f,0x8451,0x8452,0x8456,0x8458,0x8459,0x845a,0x845c,0x8460,
 129.708 +    0x8464,0x8465,0x8467,0x846a,0x8470,0x8473,0x8474,0x8476,0x8478,0x847c,
 129.709 +    0x847d,0x8481,0x8485,0x8492,0x8493,0x8495,0x849e,0x84a6,0x84a8,0x84a9,
 129.710 +    0x84aa,0x84af,0x84b1,0x84b4,0x84ba,0x84bd,0x84be,0x84c0,0x84c2,0x84c7,
 129.711 +    0x84c8,0x84cc,0x84cf,0x84d3
 129.712 +  },
 129.713 +  {				/* ku 39 */
 129.714 +    0x84dc,0x84e7,0x84ea,0x84ef,0x84f0,0x84f1,0x84f2,0x84f7,0x8532,0x84fa,
 129.715 +    0x84fb,0x84fd,0x8502,0x8503,0x8507,0x850c,0x850e,0x8510,0x851c,0x851e,
 129.716 +    0x8522,0x8523,0x8524,0x8525,0x8527,0x852a,0x852b,0x852f,0x8533,0x8534,
 129.717 +    0x8536,0x853f,0x8546,0x854f,0x8550,0x8551,0x8552,0x8553,0x8556,0x8559,
 129.718 +    0x855c,0x855d,0x855e,0x855f,0x8560,0x8561,0x8562,0x8564,0x856b,0x856f,
 129.719 +    0x8579,0x857a,0x857b,0x857d,0x857f,0x8581,0x8585,0x8586,0x8589,0x858b,
 129.720 +    0x858c,0x858f,0x8593,0x8598,0x859d,0x859f,0x85a0,0x85a2,0x85a5,0x85a7,
 129.721 +    0x85b4,0x85b6,0x85b7,0x85b8,0x85bc,0x85bd,0x85be,0x85bf,0x85c2,0x85c7,
 129.722 +    0x85ca,0x85cb,0x85ce,0x85ad,0x85d8,0x85da,0x85df,0x85e0,0x85e6,0x85e8,
 129.723 +    0x85ed,0x85f3,0x85f6,0x85fc
 129.724 +  },
 129.725 +  {				/* ku 3a */
 129.726 +    0x85ff,0x8600,0x8604,0x8605,0x860d,0x860e,0x8610,0x8611,0x8612,0x8618,
 129.727 +    0x8619,0x861b,0x861e,0x8621,0x8627,0x8629,0x8636,0x8638,0x863a,0x863c,
 129.728 +    0x863d,0x8640,0x8642,0x8646,0x8652,0x8653,0x8656,0x8657,0x8658,0x8659,
 129.729 +    0x865d,0x8660,0x8661,0x8662,0x8663,0x8664,0x8669,0x866c,0x866f,0x8675,
 129.730 +    0x8676,0x8677,0x867a,0x868d,0x8691,0x8696,0x8698,0x869a,0x869c,0x86a1,
 129.731 +    0x86a6,0x86a7,0x86a8,0x86ad,0x86b1,0x86b3,0x86b4,0x86b5,0x86b7,0x86b8,
 129.732 +    0x86b9,0x86bf,0x86c0,0x86c1,0x86c3,0x86c5,0x86d1,0x86d2,0x86d5,0x86d7,
 129.733 +    0x86da,0x86dc,0x86e0,0x86e3,0x86e5,0x86e7,0x8688,0x86fa,0x86fc,0x86fd,
 129.734 +    0x8704,0x8705,0x8707,0x870b,0x870e,0x870f,0x8710,0x8713,0x8714,0x8719,
 129.735 +    0x871e,0x871f,0x8721,0x8723
 129.736 +  },
 129.737 +  {				/* ku 3b */
 129.738 +    0x8728,0x872e,0x872f,0x8731,0x8732,0x8739,0x873a,0x873c,0x873d,0x873e,
 129.739 +    0x8740,0x8743,0x8745,0x874d,0x8758,0x875d,0x8761,0x8764,0x8765,0x876f,
 129.740 +    0x8771,0x8772,0x877b,0x8783,0x8784,0x8785,0x8786,0x8787,0x8788,0x8789,
 129.741 +    0x878b,0x878c,0x8790,0x8793,0x8795,0x8797,0x8798,0x8799,0x879e,0x87a0,
 129.742 +    0x87a3,0x87a7,0x87ac,0x87ad,0x87ae,0x87b1,0x87b5,0x87be,0x87bf,0x87c1,
 129.743 +    0x87c8,0x87c9,0x87ca,0x87ce,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87df,
 129.744 +    0x87e2,0x87e3,0x87e4,0x87ea,0x87eb,0x87ed,0x87f1,0x87f3,0x87f8,0x87fa,
 129.745 +    0x87ff,0x8801,0x8803,0x8806,0x8809,0x880a,0x880b,0x8810,0x8819,0x8812,
 129.746 +    0x8813,0x8814,0x8818,0x881a,0x881b,0x881c,0x881e,0x881f,0x8828,0x882d,
 129.747 +    0x882e,0x8830,0x8832,0x8835
 129.748 +  },
 129.749 +  {				/* ku 3c */
 129.750 +    0x883a,0x883c,0x8841,0x8843,0x8845,0x8848,0x8849,0x884a,0x884b,0x884e,
 129.751 +    0x8851,0x8855,0x8856,0x8858,0x885a,0x885c,0x885f,0x8860,0x8864,0x8869,
 129.752 +    0x8871,0x8879,0x887b,0x8880,0x8898,0x889a,0x889b,0x889c,0x889f,0x88a0,
 129.753 +    0x88a8,0x88aa,0x88ba,0x88bd,0x88be,0x88c0,0x88ca,0x88cb,0x88cc,0x88cd,
 129.754 +    0x88ce,0x88d1,0x88d2,0x88d3,0x88db,0x88de,0x88e7,0x88ef,0x88f0,0x88f1,
 129.755 +    0x88f5,0x88f7,0x8901,0x8906,0x890d,0x890e,0x890f,0x8915,0x8916,0x8918,
 129.756 +    0x8919,0x891a,0x891c,0x8920,0x8926,0x8927,0x8928,0x8930,0x8931,0x8932,
 129.757 +    0x8935,0x8939,0x893a,0x893e,0x8940,0x8942,0x8945,0x8946,0x8949,0x894f,
 129.758 +    0x8952,0x8957,0x895a,0x895b,0x895c,0x8961,0x8962,0x8963,0x896b,0x896e,
 129.759 +    0x8970,0x8973,0x8975,0x897a
 129.760 +  },
 129.761 +  {				/* ku 3d */
 129.762 +    0x897b,0x897c,0x897d,0x8989,0x898d,0x8990,0x8994,0x8995,0x899b,0x899c,
 129.763 +    0x899f,0x89a0,0x89a5,0x89b0,0x89b4,0x89b5,0x89b6,0x89b7,0x89bc,0x89d4,
 129.764 +    0x89d5,0x89d6,0x89d7,0x89d8,0x89e5,0x89e9,0x89eb,0x89ed,0x89f1,0x89f3,
 129.765 +    0x89f6,0x89f9,0x89fd,0x89ff,0x8a04,0x8a05,0x8a07,0x8a0f,0x8a11,0x8a12,
 129.766 +    0x8a14,0x8a15,0x8a1e,0x8a20,0x8a22,0x8a24,0x8a26,0x8a2b,0x8a2c,0x8a2f,
 129.767 +    0x8a35,0x8a37,0x8a3d,0x8a3e,0x8a40,0x8a43,0x8a45,0x8a47,0x8a49,0x8a4d,
 129.768 +    0x8a4e,0x8a53,0x8a56,0x8a57,0x8a58,0x8a5c,0x8a5d,0x8a61,0x8a65,0x8a67,
 129.769 +    0x8a75,0x8a76,0x8a77,0x8a79,0x8a7a,0x8a7b,0x8a7e,0x8a7f,0x8a80,0x8a83,
 129.770 +    0x8a86,0x8a8b,0x8a8f,0x8a90,0x8a92,0x8a96,0x8a97,0x8a99,0x8a9f,0x8aa7,
 129.771 +    0x8aa9,0x8aae,0x8aaf,0x8ab3
 129.772 +  },
 129.773 +  {				/* ku 3e */
 129.774 +    0x8ab6,0x8ab7,0x8abb,0x8abe,0x8ac3,0x8ac6,0x8ac8,0x8ac9,0x8aca,0x8ad1,
 129.775 +    0x8ad3,0x8ad4,0x8ad5,0x8ad7,0x8add,0x8adf,0x8aec,0x8af0,0x8af4,0x8af5,
 129.776 +    0x8af6,0x8afc,0x8aff,0x8b05,0x8b06,0x8b0b,0x8b11,0x8b1c,0x8b1e,0x8b1f,
 129.777 +    0x8b0a,0x8b2d,0x8b30,0x8b37,0x8b3c,0x8b42,0x8b43,0x8b44,0x8b45,0x8b46,
 129.778 +    0x8b48,0x8b52,0x8b53,0x8b54,0x8b59,0x8b4d,0x8b5e,0x8b63,0x8b6d,0x8b76,
 129.779 +    0x8b78,0x8b79,0x8b7c,0x8b7e,0x8b81,0x8b84,0x8b85,0x8b8b,0x8b8d,0x8b8f,
 129.780 +    0x8b94,0x8b95,0x8b9c,0x8b9e,0x8b9f,0x8c38,0x8c39,0x8c3d,0x8c3e,0x8c45,
 129.781 +    0x8c47,0x8c49,0x8c4b,0x8c4f,0x8c51,0x8c53,0x8c54,0x8c57,0x8c58,0x8c5b,
 129.782 +    0x8c5d,0x8c59,0x8c63,0x8c64,0x8c66,0x8c68,0x8c69,0x8c6d,0x8c73,0x8c75,
 129.783 +    0x8c76,0x8c7b,0x8c7e,0x8c86
 129.784 +  },
 129.785 +  {				/* ku 3f */
 129.786 +    0x8c87,0x8c8b,0x8c90,0x8c92,0x8c93,0x8c99,0x8c9b,0x8c9c,0x8ca4,0x8cb9,
 129.787 +    0x8cba,0x8cc5,0x8cc6,0x8cc9,0x8ccb,0x8ccf,0x8cd6,0x8cd5,0x8cd9,0x8cdd,
 129.788 +    0x8ce1,0x8ce8,0x8cec,0x8cef,0x8cf0,0x8cf2,0x8cf5,0x8cf7,0x8cf8,0x8cfe,
 129.789 +    0x8cff,0x8d01,0x8d03,0x8d09,0x8d12,0x8d17,0x8d1b,0x8d65,0x8d69,0x8d6c,
 129.790 +    0x8d6e,0x8d7f,0x8d82,0x8d84,0x8d88,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d9e,
 129.791 +    0x8d9f,0x8da0,0x8da6,0x8dab,0x8dac,0x8daf,0x8db2,0x8db5,0x8db7,0x8db9,
 129.792 +    0x8dbb,0x8dc0,0x8dc5,0x8dc6,0x8dc7,0x8dc8,0x8dca,0x8dce,0x8dd1,0x8dd4,
 129.793 +    0x8dd5,0x8dd7,0x8dd9,0x8de4,0x8de5,0x8de7,0x8dec,0x8df0,0x8dbc,0x8df1,
 129.794 +    0x8df2,0x8df4,0x8dfd,0x8e01,0x8e04,0x8e05,0x8e06,0x8e0b,0x8e11,0x8e14,
 129.795 +    0x8e16,0x8e20,0x8e21,0x8e22
 129.796 +  },
 129.797 +  {				/* ku 40 */
 129.798 +    0x8e23,0x8e26,0x8e27,0x8e31,0x8e33,0x8e36,0x8e37,0x8e38,0x8e39,0x8e3d,
 129.799 +    0x8e40,0x8e41,0x8e4b,0x8e4d,0x8e4e,0x8e4f,0x8e54,0x8e5b,0x8e5c,0x8e5d,
 129.800 +    0x8e5e,0x8e61,0x8e62,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e70,0x8e71,0x8e79,
 129.801 +    0x8e7a,0x8e7b,0x8e82,0x8e83,0x8e89,0x8e90,0x8e92,0x8e95,0x8e9a,0x8e9b,
 129.802 +    0x8e9d,0x8e9e,0x8ea2,0x8ea7,0x8ea9,0x8ead,0x8eae,0x8eb3,0x8eb5,0x8eba,
 129.803 +    0x8ebb,0x8ec0,0x8ec1,0x8ec3,0x8ec4,0x8ec7,0x8ecf,0x8ed1,0x8ed4,0x8edc,
 129.804 +    0x8ee8,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8ef9,0x8efa,0x8eed,0x8f00,0x8f02,
 129.805 +    0x8f07,0x8f08,0x8f0f,0x8f10,0x8f16,0x8f17,0x8f18,0x8f1e,0x8f20,0x8f21,
 129.806 +    0x8f23,0x8f25,0x8f27,0x8f28,0x8f2c,0x8f2d,0x8f2e,0x8f34,0x8f35,0x8f36,
 129.807 +    0x8f37,0x8f3a,0x8f40,0x8f41
 129.808 +  },
 129.809 +  {				/* ku 41 */
 129.810 +    0x8f43,0x8f47,0x8f4f,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f58,0x8f5d,
 129.811 +    0x8f5e,0x8f65,0x8f9d,0x8fa0,0x8fa1,0x8fa4,0x8fa5,0x8fa6,0x8fb5,0x8fb6,
 129.812 +    0x8fb8,0x8fbe,0x8fc0,0x8fc1,0x8fc6,0x8fca,0x8fcb,0x8fcd,0x8fd0,0x8fd2,
 129.813 +    0x8fd3,0x8fd5,0x8fe0,0x8fe3,0x8fe4,0x8fe8,0x8fee,0x8ff1,0x8ff5,0x8ff6,
 129.814 +    0x8ffb,0x8ffe,0x9002,0x9004,0x9008,0x900c,0x9018,0x901b,0x9028,0x9029,
 129.815 +    0x902f,0x902a,0x902c,0x902d,0x9033,0x9034,0x9037,0x903f,0x9043,0x9044,
 129.816 +    0x904c,0x905b,0x905d,0x9062,0x9066,0x9067,0x906c,0x9070,0x9074,0x9079,
 129.817 +    0x9085,0x9088,0x908b,0x908c,0x908e,0x9090,0x9095,0x9097,0x9098,0x9099,
 129.818 +    0x909b,0x90a0,0x90a1,0x90a2,0x90a5,0x90b0,0x90b2,0x90b3,0x90b4,0x90b6,
 129.819 +    0x90bd,0x90cc,0x90be,0x90c3
 129.820 +  },
 129.821 +  {				/* ku 42 */
 129.822 +    0x90c4,0x90c5,0x90c7,0x90c8,0x90d5,0x90d7,0x90d8,0x90d9,0x90dc,0x90dd,
 129.823 +    0x90df,0x90e5,0x90d2,0x90f6,0x90eb,0x90ef,0x90f0,0x90f4,0x90fe,0x90ff,
 129.824 +    0x9100,0x9104,0x9105,0x9106,0x9108,0x910d,0x9110,0x9114,0x9116,0x9117,
 129.825 +    0x9118,0x911a,0x911c,0x911e,0x9120,0x9125,0x9122,0x9123,0x9127,0x9129,
 129.826 +    0x912e,0x912f,0x9131,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d,
 129.827 +    0x9143,0x9147,0x9148,0x914f,0x9153,0x9157,0x9159,0x915a,0x915b,0x9161,
 129.828 +    0x9164,0x9167,0x916d,0x9174,0x9179,0x917a,0x917b,0x9181,0x9183,0x9185,
 129.829 +    0x9186,0x918a,0x918e,0x9191,0x9193,0x9194,0x9195,0x9198,0x919e,0x91a1,
 129.830 +    0x91a6,0x91a8,0x91ac,0x91ad,0x91ae,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6,
 129.831 +    0x91bb,0x91bc,0x91bd,0x91bf
 129.832 +  },
 129.833 +  {				/* ku 43 */
 129.834 +    0x91c2,0x91c3,0x91c5,0x91d3,0x91d4,0x91d7,0x91d9,0x91da,0x91de,0x91e4,
 129.835 +    0x91e5,0x91e9,0x91ea,0x91ec,0x91ed,0x91ee,0x91ef,0x91f0,0x91f1,0x91f7,
 129.836 +    0x91f9,0x91fb,0x91fd,0x9200,0x9201,0x9204,0x9205,0x9206,0x9207,0x9209,
 129.837 +    0x920a,0x920c,0x9210,0x9212,0x9213,0x9216,0x9218,0x921c,0x921d,0x9223,
 129.838 +    0x9224,0x9225,0x9226,0x9228,0x922e,0x922f,0x9230,0x9233,0x9235,0x9236,
 129.839 +    0x9238,0x9239,0x923a,0x923c,0x923e,0x9240,0x9242,0x9243,0x9246,0x9247,
 129.840 +    0x924a,0x924d,0x924e,0x924f,0x9251,0x9258,0x9259,0x925c,0x925d,0x9260,
 129.841 +    0x9261,0x9265,0x9267,0x9268,0x9269,0x926e,0x926f,0x9270,0x9275,0x9276,
 129.842 +    0x9277,0x9278,0x9279,0x927b,0x927c,0x927d,0x927f,0x9288,0x9289,0x928a,
 129.843 +    0x928d,0x928e,0x9292,0x9297
 129.844 +  },
 129.845 +  {				/* ku 44 */
 129.846 +    0x9299,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92af,0x92b2,
 129.847 +    0x92b6,0x92b8,0x92ba,0x92bb,0x92bc,0x92bd,0x92bf,0x92c0,0x92c1,0x92c2,
 129.848 +    0x92c3,0x92c5,0x92c6,0x92c7,0x92c8,0x92cb,0x92cc,0x92cd,0x92ce,0x92d0,
 129.849 +    0x92d3,0x92d5,0x92d7,0x92d8,0x92d9,0x92dc,0x92dd,0x92df,0x92e0,0x92e1,
 129.850 +    0x92e3,0x92e5,0x92e7,0x92e8,0x92ec,0x92ee,0x92f0,0x92f9,0x92fb,0x92ff,
 129.851 +    0x9300,0x9302,0x9308,0x930d,0x9311,0x9314,0x9315,0x931c,0x931d,0x931e,
 129.852 +    0x931f,0x9321,0x9324,0x9325,0x9327,0x9329,0x932a,0x9333,0x9334,0x9336,
 129.853 +    0x9337,0x9347,0x9348,0x9349,0x9350,0x9351,0x9352,0x9355,0x9357,0x9358,
 129.854 +    0x935a,0x935e,0x9364,0x9365,0x9367,0x9369,0x936a,0x936d,0x936f,0x9370,
 129.855 +    0x9371,0x9373,0x9374,0x9376
 129.856 +  },
 129.857 +  {				/* ku 45 */
 129.858 +    0x937a,0x937d,0x937f,0x9380,0x9381,0x9382,0x9388,0x938a,0x938b,0x938d,
 129.859 +    0x938f,0x9392,0x9395,0x9398,0x939b,0x939e,0x93a1,0x93a3,0x93a4,0x93a6,
 129.860 +    0x93a8,0x93ab,0x93b4,0x93b5,0x93b6,0x93ba,0x93a9,0x93c1,0x93c4,0x93c5,
 129.861 +    0x93c6,0x93c7,0x93c9,0x93ca,0x93cb,0x93cc,0x93cd,0x93d3,0x93d9,0x93dc,
 129.862 +    0x93de,0x93df,0x93e2,0x93e6,0x93e7,0x93f9,0x93f7,0x93f8,0x93fa,0x93fb,
 129.863 +    0x93fd,0x9401,0x9402,0x9404,0x9408,0x9409,0x940d,0x940e,0x940f,0x9415,
 129.864 +    0x9416,0x9417,0x941f,0x942e,0x942f,0x9431,0x9432,0x9433,0x9434,0x943b,
 129.865 +    0x943f,0x943d,0x9443,0x9445,0x9448,0x944a,0x944c,0x9455,0x9459,0x945c,
 129.866 +    0x945f,0x9461,0x9463,0x9468,0x946b,0x946d,0x946e,0x946f,0x9471,0x9472,
 129.867 +    0x9484,0x9483,0x9578,0x9579
 129.868 +  },
 129.869 +  {				/* ku 46 */
 129.870 +    0x957e,0x9584,0x9588,0x958c,0x958d,0x958e,0x959d,0x959e,0x959f,0x95a1,
 129.871 +    0x95a6,0x95a9,0x95ab,0x95ac,0x95b4,0x95b6,0x95ba,0x95bd,0x95bf,0x95c6,
 129.872 +    0x95c8,0x95c9,0x95cb,0x95d0,0x95d1,0x95d2,0x95d3,0x95d9,0x95da,0x95dd,
 129.873 +    0x95de,0x95df,0x95e0,0x95e4,0x95e6,0x961d,0x961e,0x9622,0x9624,0x9625,
 129.874 +    0x9626,0x962c,0x9631,0x9633,0x9637,0x9638,0x9639,0x963a,0x963c,0x963d,
 129.875 +    0x9641,0x9652,0x9654,0x9656,0x9657,0x9658,0x9661,0x966e,0x9674,0x967b,
 129.876 +    0x967c,0x967e,0x967f,0x9681,0x9682,0x9683,0x9684,0x9689,0x9691,0x9696,
 129.877 +    0x969a,0x969d,0x969f,0x96a4,0x96a5,0x96a6,0x96a9,0x96ae,0x96af,0x96b3,
 129.878 +    0x96ba,0x96ca,0x96d2,0x5db2,0x96d8,0x96da,0x96dd,0x96de,0x96df,0x96e9,
 129.879 +    0x96ef,0x96f1,0x96fa,0x9702
 129.880 +  },
 129.881 +  {				/* ku 47 */
 129.882 +    0x9703,0x9705,0x9709,0x971a,0x971b,0x971d,0x9721,0x9722,0x9723,0x9728,
 129.883 +    0x9731,0x9733,0x9741,0x9743,0x974a,0x974e,0x974f,0x9755,0x9757,0x9758,
 129.884 +    0x975a,0x975b,0x9763,0x9767,0x976a,0x976e,0x9773,0x9776,0x9777,0x9778,
 129.885 +    0x977b,0x977d,0x977f,0x9780,0x9789,0x9795,0x9796,0x9797,0x9799,0x979a,
 129.886 +    0x979e,0x979f,0x97a2,0x97ac,0x97ae,0x97b1,0x97b2,0x97b5,0x97b6,0x97b8,
 129.887 +    0x97b9,0x97ba,0x97bc,0x97be,0x97bf,0x97c1,0x97c4,0x97c5,0x97c7,0x97c9,
 129.888 +    0x97ca,0x97cc,0x97cd,0x97ce,0x97d0,0x97d1,0x97d4,0x97d7,0x97d8,0x97d9,
 129.889 +    0x97dd,0x97de,0x97e0,0x97db,0x97e1,0x97e4,0x97ef,0x97f1,0x97f4,0x97f7,
 129.890 +    0x97f8,0x97fa,0x9807,0x980a,0x9819,0x980d,0x980e,0x9814,0x9816,0x981c,
 129.891 +    0x981e,0x9820,0x9823,0x9826
 129.892 +  },
 129.893 +  {				/* ku 48 */
 129.894 +    0x982b,0x982e,0x982f,0x9830,0x9832,0x9833,0x9835,0x9825,0x983e,0x9844,
 129.895 +    0x9847,0x984a,0x9851,0x9852,0x9853,0x9856,0x9857,0x9859,0x985a,0x9862,
 129.896 +    0x9863,0x9865,0x9866,0x986a,0x986c,0x98ab,0x98ad,0x98ae,0x98b0,0x98b4,
 129.897 +    0x98b7,0x98b8,0x98ba,0x98bb,0x98bf,0x98c2,0x98c5,0x98c8,0x98cc,0x98e1,
 129.898 +    0x98e3,0x98e5,0x98e6,0x98e7,0x98ea,0x98f3,0x98f6,0x9902,0x9907,0x9908,
 129.899 +    0x9911,0x9915,0x9916,0x9917,0x991a,0x991b,0x991c,0x991f,0x9922,0x9926,
 129.900 +    0x9927,0x992b,0x9931,0x9932,0x9933,0x9934,0x9935,0x9939,0x993a,0x993b,
 129.901 +    0x993c,0x9940,0x9941,0x9946,0x9947,0x9948,0x994d,0x994e,0x9954,0x9958,
 129.902 +    0x9959,0x995b,0x995c,0x995e,0x995f,0x9960,0x999b,0x999d,0x999f,0x99a6,
 129.903 +    0x99b0,0x99b1,0x99b2,0x99b5
 129.904 +  },
 129.905 +  {				/* ku 49 */
 129.906 +    0x99b9,0x99ba,0x99bd,0x99bf,0x99c3,0x99c9,0x99d3,0x99d4,0x99d9,0x99da,
 129.907 +    0x99dc,0x99de,0x99e7,0x99ea,0x99eb,0x99ec,0x99f0,0x99f4,0x99f5,0x99f9,
 129.908 +    0x99fd,0x99fe,0x9a02,0x9a03,0x9a04,0x9a0b,0x9a0c,0x9a10,0x9a11,0x9a16,
 129.909 +    0x9a1e,0x9a20,0x9a22,0x9a23,0x9a24,0x9a27,0x9a2d,0x9a2e,0x9a33,0x9a35,
 129.910 +    0x9a36,0x9a38,0x9a47,0x9a41,0x9a44,0x9a4a,0x9a4b,0x9a4c,0x9a4e,0x9a51,
 129.911 +    0x9a54,0x9a56,0x9a5d,0x9aaa,0x9aac,0x9aae,0x9aaf,0x9ab2,0x9ab4,0x9ab5,
 129.912 +    0x9ab6,0x9ab9,0x9abb,0x9abe,0x9abf,0x9ac1,0x9ac3,0x9ac6,0x9ac8,0x9ace,
 129.913 +    0x9ad0,0x9ad2,0x9ad5,0x9ad6,0x9ad7,0x9adb,0x9adc,0x9ae0,0x9ae4,0x9ae5,
 129.914 +    0x9ae7,0x9ae9,0x9aec,0x9af2,0x9af3,0x9af5,0x9af9,0x9afa,0x9afd,0x9aff,
 129.915 +    0x9b00,0x9b01,0x9b02,0x9b03
 129.916 +  },
 129.917 +  {				/* ku 4a */
 129.918 +    0x9b04,0x9b05,0x9b08,0x9b09,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b12,
 129.919 +    0x9b16,0x9b19,0x9b1b,0x9b1c,0x9b20,0x9b26,0x9b2b,0x9b2d,0x9b33,0x9b34,
 129.920 +    0x9b35,0x9b37,0x9b39,0x9b3a,0x9b3d,0x9b48,0x9b4b,0x9b4c,0x9b55,0x9b56,
 129.921 +    0x9b57,0x9b5b,0x9b5e,0x9b61,0x9b63,0x9b65,0x9b66,0x9b68,0x9b6a,0x9b6b,
 129.922 +    0x9b6c,0x9b6d,0x9b6e,0x9b73,0x9b75,0x9b77,0x9b78,0x9b79,0x9b7f,0x9b80,
 129.923 +    0x9b84,0x9b85,0x9b86,0x9b87,0x9b89,0x9b8a,0x9b8b,0x9b8d,0x9b8f,0x9b90,
 129.924 +    0x9b94,0x9b9a,0x9b9d,0x9b9e,0x9ba6,0x9ba7,0x9ba9,0x9bac,0x9bb0,0x9bb1,
 129.925 +    0x9bb2,0x9bb7,0x9bb8,0x9bbb,0x9bbc,0x9bbe,0x9bbf,0x9bc1,0x9bc7,0x9bc8,
 129.926 +    0x9bce,0x9bd0,0x9bd7,0x9bd8,0x9bdd,0x9bdf,0x9be5,0x9be7,0x9bea,0x9beb,
 129.927 +    0x9bef,0x9bf3,0x9bf7,0x9bf8
 129.928 +  },
 129.929 +  {				/* ku 4b */
 129.930 +    0x9bf9,0x9bfa,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c0b,0x9c0f,0x9c11,0x9c16,
 129.931 +    0x9c18,0x9c19,0x9c1a,0x9c1c,0x9c1e,0x9c22,0x9c23,0x9c26,0x9c27,0x9c28,
 129.932 +    0x9c29,0x9c2a,0x9c31,0x9c35,0x9c36,0x9c37,0x9c3d,0x9c41,0x9c43,0x9c44,
 129.933 +    0x9c45,0x9c49,0x9c4a,0x9c4e,0x9c4f,0x9c50,0x9c53,0x9c54,0x9c56,0x9c58,
 129.934 +    0x9c5b,0x9c5d,0x9c5e,0x9c5f,0x9c63,0x9c69,0x9c6a,0x9c5c,0x9c6b,0x9c68,
 129.935 +    0x9c6e,0x9c70,0x9c72,0x9c75,0x9c77,0x9c7b,0x9ce6,0x9cf2,0x9cf7,0x9cf9,
 129.936 +    0x9d0b,0x9d02,0x9d11,0x9d17,0x9d18,0x9d1c,0x9d1d,0x9d1e,0x9d2f,0x9d30,
 129.937 +    0x9d32,0x9d33,0x9d34,0x9d3a,0x9d3c,0x9d45,0x9d3d,0x9d42,0x9d43,0x9d47,
 129.938 +    0x9d4a,0x9d53,0x9d54,0x9d5f,0x9d63,0x9d62,0x9d65,0x9d69,0x9d6a,0x9d6b,
 129.939 +    0x9d70,0x9d76,0x9d77,0x9d7b
 129.940 +  },
 129.941 +  {				/* ku 4c */
 129.942 +    0x9d7c,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d8a,0x9d8d,0x9d8e,0x9d92,0x9d93,
 129.943 +    0x9d95,0x9d96,0x9d97,0x9d98,0x9da1,0x9daa,0x9dac,0x9dae,0x9db1,0x9db5,
 129.944 +    0x9db9,0x9dbc,0x9dbf,0x9dc3,0x9dc7,0x9dc9,0x9dca,0x9dd4,0x9dd5,0x9dd6,
 129.945 +    0x9dd7,0x9dda,0x9dde,0x9ddf,0x9de0,0x9de5,0x9de7,0x9de9,0x9deb,0x9dee,
 129.946 +    0x9df0,0x9df3,0x9df4,0x9dfe,0x9e0a,0x9e02,0x9e07,0x9e0e,0x9e10,0x9e11,
 129.947 +    0x9e12,0x9e15,0x9e16,0x9e19,0x9e1c,0x9e1d,0x9e7a,0x9e7b,0x9e7c,0x9e80,
 129.948 +    0x9e82,0x9e83,0x9e84,0x9e85,0x9e87,0x9e8e,0x9e8f,0x9e96,0x9e98,0x9e9b,
 129.949 +    0x9e9e,0x9ea4,0x9ea8,0x9eac,0x9eae,0x9eaf,0x9eb0,0x9eb3,0x9eb4,0x9eb5,
 129.950 +    0x9ec6,0x9ec8,0x9ecb,0x9ed5,0x9edf,0x9ee4,0x9ee7,0x9eec,0x9eed,0x9eee,
 129.951 +    0x9ef0,0x9ef1,0x9ef2,0x9ef5
 129.952 +  },
 129.953 +  {				/* ku 4d */
 129.954 +    0x9ef8,0x9eff,0x9f02,0x9f03,0x9f09,0x9f0f,0x9f10,0x9f11,0x9f12,0x9f14,
 129.955 +    0x9f16,0x9f17,0x9f19,0x9f1a,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f2a,0x9f2b,
 129.956 +    0x9f2f,0x9f31,0x9f32,0x9f34,0x9f37,0x9f39,0x9f3a,0x9f3c,0x9f3d,0x9f3f,
 129.957 +    0x9f41,0x9f43,0x9f44,0x9f45,0x9f46,0x9f47,0x9f53,0x9f55,0x9f56,0x9f57,
 129.958 +    0x9f58,0x9f5a,0x9f5d,0x9f5e,0x9f68,0x9f69,0x9f6d,0x9f6e,0x9f6f,0x9f70,
 129.959 +    0x9f71,0x9f73,0x9f75,0x9f7a,0x9f7d,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f94,
 129.960 +    0x9f96,0x9f97,0x9f9e,0x9fa1,0x9fa2,0x9fa3,0x9fa5,UBOGON,UBOGON,UBOGON,
 129.961 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.962 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 129.963 +    UBOGON,UBOGON,UBOGON,UBOGON
 129.964 +  }
 129.965 +};
   130.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   130.2 +++ b/src/charset/koi8_r.c	Mon Sep 14 15:17:45 2009 +0900
   130.3 @@ -0,0 +1,48 @@
   130.4 +/* ========================================================================
   130.5 + * Copyright 1988-2006 University of Washington
   130.6 + *
   130.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   130.8 + * you may not use this file except in compliance with the License.
   130.9 + * You may obtain a copy of the License at
  130.10 + *
  130.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  130.12 + *
  130.13 + * 
  130.14 + * ========================================================================
  130.15 + */
  130.16 +
  130.17 +/*
  130.18 + * Program:	KOI8-R conversion table
  130.19 + *
  130.20 + * Author:	Mark Crispin
  130.21 + *		Networks and Distributed Computing
  130.22 + *		Computing & Communications
  130.23 + *		University of Washington
  130.24 + *		Administration Building, AG-44
  130.25 + *		Seattle, WA  98195
  130.26 + *		Internet: MRC@CAC.Washington.EDU
  130.27 + *
  130.28 + * Date:	3 July 1997
  130.29 + * Last Edited:	30 August 2006
  130.30 + */
  130.31 +
  130.32 +/* KOI8-R is a de-facto standard of Russia */
  130.33 +
  130.34 +static const unsigned short koi8rtab[128] = {
  130.35 +  0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
  130.36 +  0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
  130.37 +  0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
  130.38 +  0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
  130.39 +  0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556,
  130.40 +  0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,
  130.41 +  0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565,
  130.42 +  0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9,
  130.43 +  0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
  130.44 +  0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
  130.45 +  0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
  130.46 +  0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
  130.47 +  0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
  130.48 +  0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
  130.49 +  0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
  130.50 +  0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
  130.51 +};
   131.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   131.2 +++ b/src/charset/koi8_u.c	Mon Sep 14 15:17:45 2009 +0900
   131.3 @@ -0,0 +1,48 @@
   131.4 +/* ========================================================================
   131.5 + * Copyright 1988-2006 University of Washington
   131.6 + *
   131.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   131.8 + * you may not use this file except in compliance with the License.
   131.9 + * You may obtain a copy of the License at
  131.10 + *
  131.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  131.12 + *
  131.13 + * 
  131.14 + * ========================================================================
  131.15 + */
  131.16 +
  131.17 +/*
  131.18 + * Program:	KOI8-U conversion table
  131.19 + *
  131.20 + * Author:	Mark Crispin
  131.21 + *		Networks and Distributed Computing
  131.22 + *		Computing & Communications
  131.23 + *		University of Washington
  131.24 + *		Administration Building, AG-44
  131.25 + *		Seattle, WA  98195
  131.26 + *		Internet: MRC@CAC.Washington.EDU
  131.27 + *
  131.28 + * Date:	25 August 1997
  131.29 + * Last Edited:	30 August 2006
  131.30 + */
  131.31 +
  131.32 +/* KOI8-U is a de-facto standard of Ukraine */
  131.33 +
  131.34 +static const unsigned short koi8utab[128] = {
  131.35 +  0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
  131.36 +  0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
  131.37 +  0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
  131.38 +  0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
  131.39 +  0x2550,0x2551,0x2552,0x0451,0x0454,0x2554,0x0456,0x0457,
  131.40 +  0x2557,0x2558,0x2559,0x255a,0x255b,0x0491,0x255d,0x255e,
  131.41 +  0x255f,0x2560,0x2561,0x0401,0x0403,0x2563,0x0406,0x0407,
  131.42 +  0x2566,0x2567,0x2568,0x2569,0x256a,0x0490,0x256c,0x00a9,
  131.43 +  0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
  131.44 +  0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
  131.45 +  0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
  131.46 +  0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
  131.47 +  0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
  131.48 +  0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
  131.49 +  0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
  131.50 +  0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
  131.51 +};
   132.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   132.2 +++ b/src/charset/ksc_5601.c	Mon Sep 14 15:17:45 2009 +0900
   132.3 @@ -0,0 +1,2673 @@
   132.4 +/* ========================================================================
   132.5 + * Copyright 1988-2006 University of Washington
   132.6 + *
   132.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   132.8 + * you may not use this file except in compliance with the License.
   132.9 + * You may obtain a copy of the License at
  132.10 + *
  132.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  132.12 + *
  132.13 + * 
  132.14 + * ========================================================================
  132.15 + */
  132.16 +
  132.17 +/*
  132.18 + * Program:	KSC 5601 conversion table
  132.19 + *
  132.20 + * Author:	Mark Crispin
  132.21 + *		Networks and Distributed Computing
  132.22 + *		Computing & Communications
  132.23 + *		University of Washington
  132.24 + *		Administration Building, AG-44
  132.25 + *		Seattle, WA  98195
  132.26 + *		Internet: MRC@CAC.Washington.EDU
  132.27 + *
  132.28 + * Date:	3 July 1997
  132.29 + * Last Edited:	30 August 2006
  132.30 + */
  132.31 +
  132.32 +/* KSC 5601 is the national standard of the Republic of Korea (South Korea).
  132.33 + * It is believed that it is also the de-facto standard of the Democratic
  132.34 + * People's Republic of Korea (North Korea), although North Korea has its
  132.35 + * own official national standard (KPS 9566-97).
  132.36 + */
  132.37 +
  132.38 +#define BASE_KSC5601_KU 0x81
  132.39 +#define BASE_KSC5601_TEN 0x41
  132.40 +#define MAX_KSC5601_KU 125
  132.41 +#define MAX_KSC5601_TEN 190
  132.42 +
  132.43 +
  132.44 +#define KSCTOUNICODE(c,c1,ku,ten)				\
  132.45 +  ((((ku = c - BASE_KSC5601_KU) < MAX_KSC5601_KU) &&		\
  132.46 +    ((ten = c1 - BASE_KSC5601_TEN) < MAX_KSC5601_TEN)) ?	\
  132.47 +   ksc5601tab[ku][ten] : UBOGON)
  132.48 +
  132.49 +
  132.50 +static const unsigned short ksc5601tab[MAX_KSC5601_KU][MAX_KSC5601_TEN] = {
  132.51 +  {				/* ku 01 */
  132.52 +    0xac02,0xac03,0xac05,0xac06,0xac0b,0xac0c,0xac0d,0xac0e,0xac0f,0xac18,
  132.53 +    0xac1e,0xac1f,0xac21,0xac22,0xac23,0xac25,0xac26,0xac27,0xac28,0xac29,
  132.54 +    0xac2a,0xac2b,0xac2e,0xac32,0xac33,0xac34,UBOGON,UBOGON,UBOGON,UBOGON,
  132.55 +    UBOGON,UBOGON,0xac35,0xac36,0xac37,0xac3a,0xac3b,0xac3d,0xac3e,0xac3f,
  132.56 +    0xac41,0xac42,0xac43,0xac44,0xac45,0xac46,0xac47,0xac48,0xac49,0xac4a,
  132.57 +    0xac4c,0xac4e,0xac4f,0xac50,0xac51,0xac52,0xac53,0xac55,UBOGON,UBOGON,
  132.58 +    UBOGON,UBOGON,UBOGON,UBOGON,0xac56,0xac57,0xac59,0xac5a,0xac5b,0xac5d,
  132.59 +    0xac5e,0xac5f,0xac60,0xac61,0xac62,0xac63,0xac64,0xac65,0xac66,0xac67,
  132.60 +    0xac68,0xac69,0xac6a,0xac6b,0xac6c,0xac6d,0xac6e,0xac6f,0xac72,0xac73,
  132.61 +    0xac75,0xac76,0xac79,0xac7b,0xac7c,0xac7d,0xac7e,0xac7f,0xac82,0xac87,
  132.62 +    0xac88,0xac8d,0xac8e,0xac8f,0xac91,0xac92,0xac93,0xac95,0xac96,0xac97,
  132.63 +    0xac98,0xac99,0xac9a,0xac9b,0xac9e,0xaca2,0xaca3,0xaca4,0xaca5,0xaca6,
  132.64 +    0xaca7,0xacab,0xacad,0xacae,0xacb1,0xacb2,0xacb3,0xacb4,0xacb5,0xacb6,
  132.65 +    0xacb7,0xacba,0xacbe,0xacbf,0xacc0,0xacc2,0xacc3,0xacc5,0xacc6,0xacc7,
  132.66 +    0xacc9,0xacca,0xaccb,0xaccd,0xacce,0xaccf,0xacd0,0xacd1,0xacd2,0xacd3,
  132.67 +    0xacd4,0xacd6,0xacd8,0xacd9,0xacda,0xacdb,0xacdc,0xacdd,0xacde,0xacdf,
  132.68 +    0xace2,0xace3,0xace5,0xace6,0xace9,0xaceb,0xaced,0xacee,0xacf2,0xacf4,
  132.69 +    0xacf7,0xacf8,0xacf9,0xacfa,0xacfb,0xacfe,0xacff,0xad01,0xad02,0xad03,
  132.70 +    0xad05,0xad07,0xad08,0xad09,0xad0a,0xad0b,0xad0e,0xad10,0xad12,0xad13
  132.71 +  },
  132.72 +  {				/* ku 02 */
  132.73 +    0xad14,0xad15,0xad16,0xad17,0xad19,0xad1a,0xad1b,0xad1d,0xad1e,0xad1f,
  132.74 +    0xad21,0xad22,0xad23,0xad24,0xad25,0xad26,0xad27,0xad28,0xad2a,0xad2b,
  132.75 +    0xad2e,0xad2f,0xad30,0xad31,0xad32,0xad33,UBOGON,UBOGON,UBOGON,UBOGON,
  132.76 +    UBOGON,UBOGON,0xad36,0xad37,0xad39,0xad3a,0xad3b,0xad3d,0xad3e,0xad3f,
  132.77 +    0xad40,0xad41,0xad42,0xad43,0xad46,0xad48,0xad4a,0xad4b,0xad4c,0xad4d,
  132.78 +    0xad4e,0xad4f,0xad51,0xad52,0xad53,0xad55,0xad56,0xad57,UBOGON,UBOGON,
  132.79 +    UBOGON,UBOGON,UBOGON,UBOGON,0xad59,0xad5a,0xad5b,0xad5c,0xad5d,0xad5e,
  132.80 +    0xad5f,0xad60,0xad62,0xad64,0xad65,0xad66,0xad67,0xad68,0xad69,0xad6a,
  132.81 +    0xad6b,0xad6e,0xad6f,0xad71,0xad72,0xad77,0xad78,0xad79,0xad7a,0xad7e,
  132.82 +    0xad80,0xad83,0xad84,0xad85,0xad86,0xad87,0xad8a,0xad8b,0xad8d,0xad8e,
  132.83 +    0xad8f,0xad91,0xad92,0xad93,0xad94,0xad95,0xad96,0xad97,0xad98,0xad99,
  132.84 +    0xad9a,0xad9b,0xad9e,0xad9f,0xada0,0xada1,0xada2,0xada3,0xada5,0xada6,
  132.85 +    0xada7,0xada8,0xada9,0xadaa,0xadab,0xadac,0xadad,0xadae,0xadaf,0xadb0,
  132.86 +    0xadb1,0xadb2,0xadb3,0xadb4,0xadb5,0xadb6,0xadb8,0xadb9,0xadba,0xadbb,
  132.87 +    0xadbc,0xadbd,0xadbe,0xadbf,0xadc2,0xadc3,0xadc5,0xadc6,0xadc7,0xadc9,
  132.88 +    0xadca,0xadcb,0xadcc,0xadcd,0xadce,0xadcf,0xadd2,0xadd4,0xadd5,0xadd6,
  132.89 +    0xadd7,0xadd8,0xadd9,0xadda,0xaddb,0xaddd,0xadde,0xaddf,0xade1,0xade2,
  132.90 +    0xade3,0xade5,0xade6,0xade7,0xade8,0xade9,0xadea,0xadeb,0xadec,0xaded,
  132.91 +    0xadee,0xadef,0xadf0,0xadf1,0xadf2,0xadf3,0xadf4,0xadf5,0xadf6,0xadf7
  132.92 +  },
  132.93 +  {				/* ku 03 */
  132.94 +    0xadfa,0xadfb,0xadfd,0xadfe,0xae02,0xae03,0xae04,0xae05,0xae06,0xae07,
  132.95 +    0xae0a,0xae0c,0xae0e,0xae0f,0xae10,0xae11,0xae12,0xae13,0xae15,0xae16,
  132.96 +    0xae17,0xae18,0xae19,0xae1a,0xae1b,0xae1c,UBOGON,UBOGON,UBOGON,UBOGON,
  132.97 +    UBOGON,UBOGON,0xae1d,0xae1e,0xae1f,0xae20,0xae21,0xae22,0xae23,0xae24,
  132.98 +    0xae25,0xae26,0xae27,0xae28,0xae29,0xae2a,0xae2b,0xae2c,0xae2d,0xae2e,
  132.99 +    0xae2f,0xae32,0xae33,0xae35,0xae36,0xae39,0xae3b,0xae3c,UBOGON,UBOGON,
 132.100 +    UBOGON,UBOGON,UBOGON,UBOGON,0xae3d,0xae3e,0xae3f,0xae42,0xae44,0xae47,
 132.101 +    0xae48,0xae49,0xae4b,0xae4f,0xae51,0xae52,0xae53,0xae55,0xae57,0xae58,
 132.102 +    0xae59,0xae5a,0xae5b,0xae5e,0xae62,0xae63,0xae64,0xae66,0xae67,0xae6a,
 132.103 +    0xae6b,0xae6d,0xae6e,0xae6f,0xae71,0xae72,0xae73,0xae74,0xae75,0xae76,
 132.104 +    0xae77,0xae7a,0xae7e,0xae7f,0xae80,0xae81,0xae82,0xae83,0xae86,0xae87,
 132.105 +    0xae88,0xae89,0xae8a,0xae8b,0xae8d,0xae8e,0xae8f,0xae90,0xae91,0xae92,
 132.106 +    0xae93,0xae94,0xae95,0xae96,0xae97,0xae98,0xae99,0xae9a,0xae9b,0xae9c,
 132.107 +    0xae9d,0xae9e,0xae9f,0xaea0,0xaea1,0xaea2,0xaea3,0xaea4,0xaea5,0xaea6,
 132.108 +    0xaea7,0xaea8,0xaea9,0xaeaa,0xaeab,0xaeac,0xaead,0xaeae,0xaeaf,0xaeb0,
 132.109 +    0xaeb1,0xaeb2,0xaeb3,0xaeb4,0xaeb5,0xaeb6,0xaeb7,0xaeb8,0xaeb9,0xaeba,
 132.110 +    0xaebb,0xaebf,0xaec1,0xaec2,0xaec3,0xaec5,0xaec6,0xaec7,0xaec8,0xaec9,
 132.111 +    0xaeca,0xaecb,0xaece,0xaed2,0xaed3,0xaed4,0xaed5,0xaed6,0xaed7,0xaeda,
 132.112 +    0xaedb,0xaedd,0xaede,0xaedf,0xaee0,0xaee1,0xaee2,0xaee3,0xaee4,0xaee5
 132.113 +  },
 132.114 +  {				/* ku 04 */
 132.115 +    0xaee6,0xaee7,0xaee9,0xaeea,0xaeec,0xaeee,0xaeef,0xaef0,0xaef1,0xaef2,
 132.116 +    0xaef3,0xaef5,0xaef6,0xaef7,0xaef9,0xaefa,0xaefb,0xaefd,0xaefe,0xaeff,
 132.117 +    0xaf00,0xaf01,0xaf02,0xaf03,0xaf04,0xaf05,UBOGON,UBOGON,UBOGON,UBOGON,
 132.118 +    UBOGON,UBOGON,0xaf06,0xaf09,0xaf0a,0xaf0b,0xaf0c,0xaf0e,0xaf0f,0xaf11,
 132.119 +    0xaf12,0xaf13,0xaf14,0xaf15,0xaf16,0xaf17,0xaf18,0xaf19,0xaf1a,0xaf1b,
 132.120 +    0xaf1c,0xaf1d,0xaf1e,0xaf1f,0xaf20,0xaf21,0xaf22,0xaf23,UBOGON,UBOGON,
 132.121 +    UBOGON,UBOGON,UBOGON,UBOGON,0xaf24,0xaf25,0xaf26,0xaf27,0xaf28,0xaf29,
 132.122 +    0xaf2a,0xaf2b,0xaf2e,0xaf2f,0xaf31,0xaf33,0xaf35,0xaf36,0xaf37,0xaf38,
 132.123 +    0xaf39,0xaf3a,0xaf3b,0xaf3e,0xaf40,0xaf44,0xaf45,0xaf46,0xaf47,0xaf4a,
 132.124 +    0xaf4b,0xaf4c,0xaf4d,0xaf4e,0xaf4f,0xaf51,0xaf52,0xaf53,0xaf54,0xaf55,
 132.125 +    0xaf56,0xaf57,0xaf58,0xaf59,0xaf5a,0xaf5b,0xaf5e,0xaf5f,0xaf60,0xaf61,
 132.126 +    0xaf62,0xaf63,0xaf66,0xaf67,0xaf68,0xaf69,0xaf6a,0xaf6b,0xaf6c,0xaf6d,
 132.127 +    0xaf6e,0xaf6f,0xaf70,0xaf71,0xaf72,0xaf73,0xaf74,0xaf75,0xaf76,0xaf77,
 132.128 +    0xaf78,0xaf7a,0xaf7b,0xaf7c,0xaf7d,0xaf7e,0xaf7f,0xaf81,0xaf82,0xaf83,
 132.129 +    0xaf85,0xaf86,0xaf87,0xaf89,0xaf8a,0xaf8b,0xaf8c,0xaf8d,0xaf8e,0xaf8f,
 132.130 +    0xaf92,0xaf93,0xaf94,0xaf96,0xaf97,0xaf98,0xaf99,0xaf9a,0xaf9b,0xaf9d,
 132.131 +    0xaf9e,0xaf9f,0xafa0,0xafa1,0xafa2,0xafa3,0xafa4,0xafa5,0xafa6,0xafa7,
 132.132 +    0xafa8,0xafa9,0xafaa,0xafab,0xafac,0xafad,0xafae,0xafaf,0xafb0,0xafb1,
 132.133 +    0xafb2,0xafb3,0xafb4,0xafb5,0xafb6,0xafb7,0xafba,0xafbb,0xafbd,0xafbe
 132.134 +  },
 132.135 +  {				/* ku 05 */
 132.136 +    0xafbf,0xafc1,0xafc2,0xafc3,0xafc4,0xafc5,0xafc6,0xafca,0xafcc,0xafcf,
 132.137 +    0xafd0,0xafd1,0xafd2,0xafd3,0xafd5,0xafd6,0xafd7,0xafd8,0xafd9,0xafda,
 132.138 +    0xafdb,0xafdd,0xafde,0xafdf,0xafe0,0xafe1,UBOGON,UBOGON,UBOGON,UBOGON,
 132.139 +    UBOGON,UBOGON,0xafe2,0xafe3,0xafe4,0xafe5,0xafe6,0xafe7,0xafea,0xafeb,
 132.140 +    0xafec,0xafed,0xafee,0xafef,0xaff2,0xaff3,0xaff5,0xaff6,0xaff7,0xaff9,
 132.141 +    0xaffa,0xaffb,0xaffc,0xaffd,0xaffe,0xafff,0xb002,0xb003,UBOGON,UBOGON,
 132.142 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb005,0xb006,0xb007,0xb008,0xb009,0xb00a,
 132.143 +    0xb00b,0xb00d,0xb00e,0xb00f,0xb011,0xb012,0xb013,0xb015,0xb016,0xb017,
 132.144 +    0xb018,0xb019,0xb01a,0xb01b,0xb01e,0xb01f,0xb020,0xb021,0xb022,0xb023,
 132.145 +    0xb024,0xb025,0xb026,0xb027,0xb029,0xb02a,0xb02b,0xb02c,0xb02d,0xb02e,
 132.146 +    0xb02f,0xb030,0xb031,0xb032,0xb033,0xb034,0xb035,0xb036,0xb037,0xb038,
 132.147 +    0xb039,0xb03a,0xb03b,0xb03c,0xb03d,0xb03e,0xb03f,0xb040,0xb041,0xb042,
 132.148 +    0xb043,0xb046,0xb047,0xb049,0xb04b,0xb04d,0xb04f,0xb050,0xb051,0xb052,
 132.149 +    0xb056,0xb058,0xb05a,0xb05b,0xb05c,0xb05e,0xb05f,0xb060,0xb061,0xb062,
 132.150 +    0xb063,0xb064,0xb065,0xb066,0xb067,0xb068,0xb069,0xb06a,0xb06b,0xb06c,
 132.151 +    0xb06d,0xb06e,0xb06f,0xb070,0xb071,0xb072,0xb073,0xb074,0xb075,0xb076,
 132.152 +    0xb077,0xb078,0xb079,0xb07a,0xb07b,0xb07e,0xb07f,0xb081,0xb082,0xb083,
 132.153 +    0xb085,0xb086,0xb087,0xb088,0xb089,0xb08a,0xb08b,0xb08e,0xb090,0xb092,
 132.154 +    0xb093,0xb094,0xb095,0xb096,0xb097,0xb09b,0xb09d,0xb09e,0xb0a3,0xb0a4
 132.155 +  },
 132.156 +  {				/* ku 06 */
 132.157 +    0xb0a5,0xb0a6,0xb0a7,0xb0aa,0xb0b0,0xb0b2,0xb0b6,0xb0b7,0xb0b9,0xb0ba,
 132.158 +    0xb0bb,0xb0bd,0xb0be,0xb0bf,0xb0c0,0xb0c1,0xb0c2,0xb0c3,0xb0c6,0xb0ca,
 132.159 +    0xb0cb,0xb0cc,0xb0cd,0xb0ce,0xb0cf,0xb0d2,UBOGON,UBOGON,UBOGON,UBOGON,
 132.160 +    UBOGON,UBOGON,0xb0d3,0xb0d5,0xb0d6,0xb0d7,0xb0d9,0xb0da,0xb0db,0xb0dc,
 132.161 +    0xb0dd,0xb0de,0xb0df,0xb0e1,0xb0e2,0xb0e3,0xb0e4,0xb0e6,0xb0e7,0xb0e8,
 132.162 +    0xb0e9,0xb0ea,0xb0eb,0xb0ec,0xb0ed,0xb0ee,0xb0ef,0xb0f0,UBOGON,UBOGON,
 132.163 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb0f1,0xb0f2,0xb0f3,0xb0f4,0xb0f5,0xb0f6,
 132.164 +    0xb0f7,0xb0f8,0xb0f9,0xb0fa,0xb0fb,0xb0fc,0xb0fd,0xb0fe,0xb0ff,0xb100,
 132.165 +    0xb101,0xb102,0xb103,0xb104,0xb105,0xb106,0xb107,0xb10a,0xb10d,0xb10e,
 132.166 +    0xb10f,0xb111,0xb114,0xb115,0xb116,0xb117,0xb11a,0xb11e,0xb11f,0xb120,
 132.167 +    0xb121,0xb122,0xb126,0xb127,0xb129,0xb12a,0xb12b,0xb12d,0xb12e,0xb12f,
 132.168 +    0xb130,0xb131,0xb132,0xb133,0xb136,0xb13a,0xb13b,0xb13c,0xb13d,0xb13e,
 132.169 +    0xb13f,0xb142,0xb143,0xb145,0xb146,0xb147,0xb149,0xb14a,0xb14b,0xb14c,
 132.170 +    0xb14d,0xb14e,0xb14f,0xb152,0xb153,0xb156,0xb157,0xb159,0xb15a,0xb15b,
 132.171 +    0xb15d,0xb15e,0xb15f,0xb161,0xb162,0xb163,0xb164,0xb165,0xb166,0xb167,
 132.172 +    0xb168,0xb169,0xb16a,0xb16b,0xb16c,0xb16d,0xb16e,0xb16f,0xb170,0xb171,
 132.173 +    0xb172,0xb173,0xb174,0xb175,0xb176,0xb177,0xb17a,0xb17b,0xb17d,0xb17e,
 132.174 +    0xb17f,0xb181,0xb183,0xb184,0xb185,0xb186,0xb187,0xb18a,0xb18c,0xb18e,
 132.175 +    0xb18f,0xb190,0xb191,0xb195,0xb196,0xb197,0xb199,0xb19a,0xb19b,0xb19d
 132.176 +  },
 132.177 +  {				/* ku 07 */
 132.178 +    0xb19e,0xb19f,0xb1a0,0xb1a1,0xb1a2,0xb1a3,0xb1a4,0xb1a5,0xb1a6,0xb1a7,
 132.179 +    0xb1a9,0xb1aa,0xb1ab,0xb1ac,0xb1ad,0xb1ae,0xb1af,0xb1b0,0xb1b1,0xb1b2,
 132.180 +    0xb1b3,0xb1b4,0xb1b5,0xb1b6,0xb1b7,0xb1b8,UBOGON,UBOGON,UBOGON,UBOGON,
 132.181 +    UBOGON,UBOGON,0xb1b9,0xb1ba,0xb1bb,0xb1bc,0xb1bd,0xb1be,0xb1bf,0xb1c0,
 132.182 +    0xb1c1,0xb1c2,0xb1c3,0xb1c4,0xb1c5,0xb1c6,0xb1c7,0xb1c8,0xb1c9,0xb1ca,
 132.183 +    0xb1cb,0xb1cd,0xb1ce,0xb1cf,0xb1d1,0xb1d2,0xb1d3,0xb1d5,UBOGON,UBOGON,
 132.184 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb1d6,0xb1d7,0xb1d8,0xb1d9,0xb1da,0xb1db,
 132.185 +    0xb1de,0xb1e0,0xb1e1,0xb1e2,0xb1e3,0xb1e4,0xb1e5,0xb1e6,0xb1e7,0xb1ea,
 132.186 +    0xb1eb,0xb1ed,0xb1ee,0xb1ef,0xb1f1,0xb1f2,0xb1f3,0xb1f4,0xb1f5,0xb1f6,
 132.187 +    0xb1f7,0xb1f8,0xb1fa,0xb1fc,0xb1fe,0xb1ff,0xb200,0xb201,0xb202,0xb203,
 132.188 +    0xb206,0xb207,0xb209,0xb20a,0xb20d,0xb20e,0xb20f,0xb210,0xb211,0xb212,
 132.189 +    0xb213,0xb216,0xb218,0xb21a,0xb21b,0xb21c,0xb21d,0xb21e,0xb21f,0xb221,
 132.190 +    0xb222,0xb223,0xb224,0xb225,0xb226,0xb227,0xb228,0xb229,0xb22a,0xb22b,
 132.191 +    0xb22c,0xb22d,0xb22e,0xb22f,0xb230,0xb231,0xb232,0xb233,0xb235,0xb236,
 132.192 +    0xb237,0xb238,0xb239,0xb23a,0xb23b,0xb23d,0xb23e,0xb23f,0xb240,0xb241,
 132.193 +    0xb242,0xb243,0xb244,0xb245,0xb246,0xb247,0xb248,0xb249,0xb24a,0xb24b,
 132.194 +    0xb24c,0xb24d,0xb24e,0xb24f,0xb250,0xb251,0xb252,0xb253,0xb254,0xb255,
 132.195 +    0xb256,0xb257,0xb259,0xb25a,0xb25b,0xb25d,0xb25e,0xb25f,0xb261,0xb262,
 132.196 +    0xb263,0xb264,0xb265,0xb266,0xb267,0xb26a,0xb26b,0xb26c,0xb26d,0xb26e
 132.197 +  },
 132.198 +  {				/* ku 08 */
 132.199 +    0xb26f,0xb270,0xb271,0xb272,0xb273,0xb276,0xb277,0xb278,0xb279,0xb27a,
 132.200 +    0xb27b,0xb27d,0xb27e,0xb27f,0xb280,0xb281,0xb282,0xb283,0xb286,0xb287,
 132.201 +    0xb288,0xb28a,0xb28b,0xb28c,0xb28d,0xb28e,UBOGON,UBOGON,UBOGON,UBOGON,
 132.202 +    UBOGON,UBOGON,0xb28f,0xb292,0xb293,0xb295,0xb296,0xb297,0xb29b,0xb29c,
 132.203 +    0xb29d,0xb29e,0xb29f,0xb2a2,0xb2a4,0xb2a7,0xb2a8,0xb2a9,0xb2ab,0xb2ad,
 132.204 +    0xb2ae,0xb2af,0xb2b1,0xb2b2,0xb2b3,0xb2b5,0xb2b6,0xb2b7,UBOGON,UBOGON,
 132.205 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb2b8,0xb2b9,0xb2ba,0xb2bb,0xb2bc,0xb2bd,
 132.206 +    0xb2be,0xb2bf,0xb2c0,0xb2c1,0xb2c2,0xb2c3,0xb2c4,0xb2c5,0xb2c6,0xb2c7,
 132.207 +    0xb2ca,0xb2cb,0xb2cd,0xb2ce,0xb2cf,0xb2d1,0xb2d3,0xb2d4,0xb2d5,0xb2d6,
 132.208 +    0xb2d7,0xb2da,0xb2dc,0xb2de,0xb2df,0xb2e0,0xb2e1,0xb2e3,0xb2e7,0xb2e9,
 132.209 +    0xb2ea,0xb2f0,0xb2f1,0xb2f2,0xb2f6,0xb2fc,0xb2fd,0xb2fe,0xb302,0xb303,
 132.210 +    0xb305,0xb306,0xb307,0xb309,0xb30a,0xb30b,0xb30c,0xb30d,0xb30e,0xb30f,
 132.211 +    0xb312,0xb316,0xb317,0xb318,0xb319,0xb31a,0xb31b,0xb31d,0xb31e,0xb31f,
 132.212 +    0xb320,0xb321,0xb322,0xb323,0xb324,0xb325,0xb326,0xb327,0xb328,0xb329,
 132.213 +    0xb32a,0xb32b,0xb32c,0xb32d,0xb32e,0xb32f,0xb330,0xb331,0xb332,0xb333,
 132.214 +    0xb334,0xb335,0xb336,0xb337,0xb338,0xb339,0xb33a,0xb33b,0xb33c,0xb33d,
 132.215 +    0xb33e,0xb33f,0xb340,0xb341,0xb342,0xb343,0xb344,0xb345,0xb346,0xb347,
 132.216 +    0xb348,0xb349,0xb34a,0xb34b,0xb34c,0xb34d,0xb34e,0xb34f,0xb350,0xb351,
 132.217 +    0xb352,0xb353,0xb357,0xb359,0xb35a,0xb35d,0xb360,0xb361,0xb362,0xb363
 132.218 +  },
 132.219 +  {				/* ku 09 */
 132.220 +    0xb366,0xb368,0xb36a,0xb36c,0xb36d,0xb36f,0xb372,0xb373,0xb375,0xb376,
 132.221 +    0xb377,0xb379,0xb37a,0xb37b,0xb37c,0xb37d,0xb37e,0xb37f,0xb382,0xb386,
 132.222 +    0xb387,0xb388,0xb389,0xb38a,0xb38b,0xb38d,UBOGON,UBOGON,UBOGON,UBOGON,
 132.223 +    UBOGON,UBOGON,0xb38e,0xb38f,0xb391,0xb392,0xb393,0xb395,0xb396,0xb397,
 132.224 +    0xb398,0xb399,0xb39a,0xb39b,0xb39c,0xb39d,0xb39e,0xb39f,0xb3a2,0xb3a3,
 132.225 +    0xb3a4,0xb3a5,0xb3a6,0xb3a7,0xb3a9,0xb3aa,0xb3ab,0xb3ad,UBOGON,UBOGON,
 132.226 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb3ae,0xb3af,0xb3b0,0xb3b1,0xb3b2,0xb3b3,
 132.227 +    0xb3b4,0xb3b5,0xb3b6,0xb3b7,0xb3b8,0xb3b9,0xb3ba,0xb3bb,0xb3bc,0xb3bd,
 132.228 +    0xb3be,0xb3bf,0xb3c0,0xb3c1,0xb3c2,0xb3c3,0xb3c6,0xb3c7,0xb3c9,0xb3ca,
 132.229 +    0xb3cd,0xb3cf,0xb3d1,0xb3d2,0xb3d3,0xb3d6,0xb3d8,0xb3da,0xb3dc,0xb3de,
 132.230 +    0xb3df,0xb3e1,0xb3e2,0xb3e3,0xb3e5,0xb3e6,0xb3e7,0xb3e9,0xb3ea,0xb3eb,
 132.231 +    0xb3ec,0xb3ed,0xb3ee,0xb3ef,0xb3f0,0xb3f1,0xb3f2,0xb3f3,0xb3f4,0xb3f5,
 132.232 +    0xb3f6,0xb3f7,0xb3f8,0xb3f9,0xb3fa,0xb3fb,0xb3fd,0xb3fe,0xb3ff,0xb400,
 132.233 +    0xb401,0xb402,0xb403,0xb404,0xb405,0xb406,0xb407,0xb408,0xb409,0xb40a,
 132.234 +    0xb40b,0xb40c,0xb40d,0xb40e,0xb40f,0xb411,0xb412,0xb413,0xb414,0xb415,
 132.235 +    0xb416,0xb417,0xb419,0xb41a,0xb41b,0xb41d,0xb41e,0xb41f,0xb421,0xb422,
 132.236 +    0xb423,0xb424,0xb425,0xb426,0xb427,0xb42a,0xb42c,0xb42d,0xb42e,0xb42f,
 132.237 +    0xb430,0xb431,0xb432,0xb433,0xb435,0xb436,0xb437,0xb438,0xb439,0xb43a,
 132.238 +    0xb43b,0xb43c,0xb43d,0xb43e,0xb43f,0xb440,0xb441,0xb442,0xb443,0xb444
 132.239 +  },
 132.240 +  {				/* ku 0a */
 132.241 +    0xb445,0xb446,0xb447,0xb448,0xb449,0xb44a,0xb44b,0xb44c,0xb44d,0xb44e,
 132.242 +    0xb44f,0xb452,0xb453,0xb455,0xb456,0xb457,0xb459,0xb45a,0xb45b,0xb45c,
 132.243 +    0xb45d,0xb45e,0xb45f,0xb462,0xb464,0xb466,UBOGON,UBOGON,UBOGON,UBOGON,
 132.244 +    UBOGON,UBOGON,0xb467,0xb468,0xb469,0xb46a,0xb46b,0xb46d,0xb46e,0xb46f,
 132.245 +    0xb470,0xb471,0xb472,0xb473,0xb474,0xb475,0xb476,0xb477,0xb478,0xb479,
 132.246 +    0xb47a,0xb47b,0xb47c,0xb47d,0xb47e,0xb47f,0xb481,0xb482,UBOGON,UBOGON,
 132.247 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb483,0xb484,0xb485,0xb486,0xb487,0xb489,
 132.248 +    0xb48a,0xb48b,0xb48c,0xb48d,0xb48e,0xb48f,0xb490,0xb491,0xb492,0xb493,
 132.249 +    0xb494,0xb495,0xb496,0xb497,0xb498,0xb499,0xb49a,0xb49b,0xb49c,0xb49e,
 132.250 +    0xb49f,0xb4a0,0xb4a1,0xb4a2,0xb4a3,0xb4a5,0xb4a6,0xb4a7,0xb4a9,0xb4aa,
 132.251 +    0xb4ab,0xb4ad,0xb4ae,0xb4af,0xb4b0,0xb4b1,0xb4b2,0xb4b3,0xb4b4,0xb4b6,
 132.252 +    0xb4b8,0xb4ba,0xb4bb,0xb4bc,0xb4bd,0xb4be,0xb4bf,0xb4c1,0xb4c2,0xb4c3,
 132.253 +    0xb4c5,0xb4c6,0xb4c7,0xb4c9,0xb4ca,0xb4cb,0xb4cc,0xb4cd,0xb4ce,0xb4cf,
 132.254 +    0xb4d1,0xb4d2,0xb4d3,0xb4d4,0xb4d6,0xb4d7,0xb4d8,0xb4d9,0xb4da,0xb4db,
 132.255 +    0xb4de,0xb4df,0xb4e1,0xb4e2,0xb4e5,0xb4e7,0xb4e8,0xb4e9,0xb4ea,0xb4eb,
 132.256 +    0xb4ee,0xb4f0,0xb4f2,0xb4f3,0xb4f4,0xb4f5,0xb4f6,0xb4f7,0xb4f9,0xb4fa,
 132.257 +    0xb4fb,0xb4fc,0xb4fd,0xb4fe,0xb4ff,0xb500,0xb501,0xb502,0xb503,0xb504,
 132.258 +    0xb505,0xb506,0xb507,0xb508,0xb509,0xb50a,0xb50b,0xb50c,0xb50d,0xb50e,
 132.259 +    0xb50f,0xb510,0xb511,0xb512,0xb513,0xb516,0xb517,0xb519,0xb51a,0xb51d
 132.260 +  },
 132.261 +  {				/* ku 0b */
 132.262 +    0xb51e,0xb51f,0xb520,0xb521,0xb522,0xb523,0xb526,0xb52b,0xb52c,0xb52d,
 132.263 +    0xb52e,0xb52f,0xb532,0xb533,0xb535,0xb536,0xb537,0xb539,0xb53a,0xb53b,
 132.264 +    0xb53c,0xb53d,0xb53e,0xb53f,0xb542,0xb546,UBOGON,UBOGON,UBOGON,UBOGON,
 132.265 +    UBOGON,UBOGON,0xb547,0xb548,0xb549,0xb54a,0xb54e,0xb54f,0xb551,0xb552,
 132.266 +    0xb553,0xb555,0xb556,0xb557,0xb558,0xb559,0xb55a,0xb55b,0xb55e,0xb562,
 132.267 +    0xb563,0xb564,0xb565,0xb566,0xb567,0xb568,0xb569,0xb56a,UBOGON,UBOGON,
 132.268 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb56b,0xb56c,0xb56d,0xb56e,0xb56f,0xb570,
 132.269 +    0xb571,0xb572,0xb573,0xb574,0xb575,0xb576,0xb577,0xb578,0xb579,0xb57a,
 132.270 +    0xb57b,0xb57c,0xb57d,0xb57e,0xb57f,0xb580,0xb581,0xb582,0xb583,0xb584,
 132.271 +    0xb585,0xb586,0xb587,0xb588,0xb589,0xb58a,0xb58b,0xb58c,0xb58d,0xb58e,
 132.272 +    0xb58f,0xb590,0xb591,0xb592,0xb593,0xb594,0xb595,0xb596,0xb597,0xb598,
 132.273 +    0xb599,0xb59a,0xb59b,0xb59c,0xb59d,0xb59e,0xb59f,0xb5a2,0xb5a3,0xb5a5,
 132.274 +    0xb5a6,0xb5a7,0xb5a9,0xb5ac,0xb5ad,0xb5ae,0xb5af,0xb5b2,0xb5b6,0xb5b7,
 132.275 +    0xb5b8,0xb5b9,0xb5ba,0xb5be,0xb5bf,0xb5c1,0xb5c2,0xb5c3,0xb5c5,0xb5c6,
 132.276 +    0xb5c7,0xb5c8,0xb5c9,0xb5ca,0xb5cb,0xb5ce,0xb5d2,0xb5d3,0xb5d4,0xb5d5,
 132.277 +    0xb5d6,0xb5d7,0xb5d9,0xb5da,0xb5db,0xb5dc,0xb5dd,0xb5de,0xb5df,0xb5e0,
 132.278 +    0xb5e1,0xb5e2,0xb5e3,0xb5e4,0xb5e5,0xb5e6,0xb5e7,0xb5e8,0xb5e9,0xb5ea,
 132.279 +    0xb5eb,0xb5ed,0xb5ee,0xb5ef,0xb5f0,0xb5f1,0xb5f2,0xb5f3,0xb5f4,0xb5f5,
 132.280 +    0xb5f6,0xb5f7,0xb5f8,0xb5f9,0xb5fa,0xb5fb,0xb5fc,0xb5fd,0xb5fe,0xb5ff
 132.281 +  },
 132.282 +  {				/* ku 0c */
 132.283 +    0xb600,0xb601,0xb602,0xb603,0xb604,0xb605,0xb606,0xb607,0xb608,0xb609,
 132.284 +    0xb60a,0xb60b,0xb60c,0xb60d,0xb60e,0xb60f,0xb612,0xb613,0xb615,0xb616,
 132.285 +    0xb617,0xb619,0xb61a,0xb61b,0xb61c,0xb61d,UBOGON,UBOGON,UBOGON,UBOGON,
 132.286 +    UBOGON,UBOGON,0xb61e,0xb61f,0xb620,0xb621,0xb622,0xb623,0xb624,0xb626,
 132.287 +    0xb627,0xb628,0xb629,0xb62a,0xb62b,0xb62d,0xb62e,0xb62f,0xb630,0xb631,
 132.288 +    0xb632,0xb633,0xb635,0xb636,0xb637,0xb638,0xb639,0xb63a,UBOGON,UBOGON,
 132.289 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb63b,0xb63c,0xb63d,0xb63e,0xb63f,0xb640,
 132.290 +    0xb641,0xb642,0xb643,0xb644,0xb645,0xb646,0xb647,0xb649,0xb64a,0xb64b,
 132.291 +    0xb64c,0xb64d,0xb64e,0xb64f,0xb650,0xb651,0xb652,0xb653,0xb654,0xb655,
 132.292 +    0xb656,0xb657,0xb658,0xb659,0xb65a,0xb65b,0xb65c,0xb65d,0xb65e,0xb65f,
 132.293 +    0xb660,0xb661,0xb662,0xb663,0xb665,0xb666,0xb667,0xb669,0xb66a,0xb66b,
 132.294 +    0xb66c,0xb66d,0xb66e,0xb66f,0xb670,0xb671,0xb672,0xb673,0xb674,0xb675,
 132.295 +    0xb676,0xb677,0xb678,0xb679,0xb67a,0xb67b,0xb67c,0xb67d,0xb67e,0xb67f,
 132.296 +    0xb680,0xb681,0xb682,0xb683,0xb684,0xb685,0xb686,0xb687,0xb688,0xb689,
 132.297 +    0xb68a,0xb68b,0xb68c,0xb68d,0xb68e,0xb68f,0xb690,0xb691,0xb692,0xb693,
 132.298 +    0xb694,0xb695,0xb696,0xb697,0xb698,0xb699,0xb69a,0xb69b,0xb69e,0xb69f,
 132.299 +    0xb6a1,0xb6a2,0xb6a3,0xb6a5,0xb6a6,0xb6a7,0xb6a8,0xb6a9,0xb6aa,0xb6ad,
 132.300 +    0xb6ae,0xb6af,0xb6b0,0xb6b2,0xb6b3,0xb6b4,0xb6b5,0xb6b6,0xb6b7,0xb6b8,
 132.301 +    0xb6b9,0xb6ba,0xb6bb,0xb6bc,0xb6bd,0xb6be,0xb6bf,0xb6c0,0xb6c1,0xb6c2
 132.302 +  },
 132.303 +  {				/* ku 0d */
 132.304 +    0xb6c3,0xb6c4,0xb6c5,0xb6c6,0xb6c7,0xb6c8,0xb6c9,0xb6ca,0xb6cb,0xb6cc,
 132.305 +    0xb6cd,0xb6ce,0xb6cf,0xb6d0,0xb6d1,0xb6d2,0xb6d3,0xb6d5,0xb6d6,0xb6d7,
 132.306 +    0xb6d8,0xb6d9,0xb6da,0xb6db,0xb6dc,0xb6dd,UBOGON,UBOGON,UBOGON,UBOGON,
 132.307 +    UBOGON,UBOGON,0xb6de,0xb6df,0xb6e0,0xb6e1,0xb6e2,0xb6e3,0xb6e4,0xb6e5,
 132.308 +    0xb6e6,0xb6e7,0xb6e8,0xb6e9,0xb6ea,0xb6eb,0xb6ec,0xb6ed,0xb6ee,0xb6ef,
 132.309 +    0xb6f1,0xb6f2,0xb6f3,0xb6f5,0xb6f6,0xb6f7,0xb6f9,0xb6fa,UBOGON,UBOGON,
 132.310 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb6fb,0xb6fc,0xb6fd,0xb6fe,0xb6ff,0xb702,
 132.311 +    0xb703,0xb704,0xb706,0xb707,0xb708,0xb709,0xb70a,0xb70b,0xb70c,0xb70d,
 132.312 +    0xb70e,0xb70f,0xb710,0xb711,0xb712,0xb713,0xb714,0xb715,0xb716,0xb717,
 132.313 +    0xb718,0xb719,0xb71a,0xb71b,0xb71c,0xb71d,0xb71e,0xb71f,0xb720,0xb721,
 132.314 +    0xb722,0xb723,0xb724,0xb725,0xb726,0xb727,0xb72a,0xb72b,0xb72d,0xb72e,
 132.315 +    0xb731,0xb732,0xb733,0xb734,0xb735,0xb736,0xb737,0xb73a,0xb73c,0xb73d,
 132.316 +    0xb73e,0xb73f,0xb740,0xb741,0xb742,0xb743,0xb745,0xb746,0xb747,0xb749,
 132.317 +    0xb74a,0xb74b,0xb74d,0xb74e,0xb74f,0xb750,0xb751,0xb752,0xb753,0xb756,
 132.318 +    0xb757,0xb758,0xb759,0xb75a,0xb75b,0xb75c,0xb75d,0xb75e,0xb75f,0xb761,
 132.319 +    0xb762,0xb763,0xb765,0xb766,0xb767,0xb769,0xb76a,0xb76b,0xb76c,0xb76d,
 132.320 +    0xb76e,0xb76f,0xb772,0xb774,0xb776,0xb777,0xb778,0xb779,0xb77a,0xb77b,
 132.321 +    0xb77e,0xb77f,0xb781,0xb782,0xb783,0xb785,0xb786,0xb787,0xb788,0xb789,
 132.322 +    0xb78a,0xb78b,0xb78e,0xb793,0xb794,0xb795,0xb79a,0xb79b,0xb79d,0xb79e
 132.323 +  },
 132.324 +  {				/* ku 0e */
 132.325 +    0xb79f,0xb7a1,0xb7a2,0xb7a3,0xb7a4,0xb7a5,0xb7a6,0xb7a7,0xb7aa,0xb7ae,
 132.326 +    0xb7af,0xb7b0,0xb7b1,0xb7b2,0xb7b3,0xb7b6,0xb7b7,0xb7b9,0xb7ba,0xb7bb,
 132.327 +    0xb7bc,0xb7bd,0xb7be,0xb7bf,0xb7c0,0xb7c1,UBOGON,UBOGON,UBOGON,UBOGON,
 132.328 +    UBOGON,UBOGON,0xb7c2,0xb7c3,0xb7c4,0xb7c5,0xb7c6,0xb7c8,0xb7ca,0xb7cb,
 132.329 +    0xb7cc,0xb7cd,0xb7ce,0xb7cf,0xb7d0,0xb7d1,0xb7d2,0xb7d3,0xb7d4,0xb7d5,
 132.330 +    0xb7d6,0xb7d7,0xb7d8,0xb7d9,0xb7da,0xb7db,0xb7dc,0xb7dd,UBOGON,UBOGON,
 132.331 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb7de,0xb7df,0xb7e0,0xb7e1,0xb7e2,0xb7e3,
 132.332 +    0xb7e4,0xb7e5,0xb7e6,0xb7e7,0xb7e8,0xb7e9,0xb7ea,0xb7eb,0xb7ee,0xb7ef,
 132.333 +    0xb7f1,0xb7f2,0xb7f3,0xb7f5,0xb7f6,0xb7f7,0xb7f8,0xb7f9,0xb7fa,0xb7fb,
 132.334 +    0xb7fe,0xb802,0xb803,0xb804,0xb805,0xb806,0xb80a,0xb80b,0xb80d,0xb80e,
 132.335 +    0xb80f,0xb811,0xb812,0xb813,0xb814,0xb815,0xb816,0xb817,0xb81a,0xb81c,
 132.336 +    0xb81e,0xb81f,0xb820,0xb821,0xb822,0xb823,0xb826,0xb827,0xb829,0xb82a,
 132.337 +    0xb82b,0xb82d,0xb82e,0xb82f,0xb830,0xb831,0xb832,0xb833,0xb836,0xb83a,
 132.338 +    0xb83b,0xb83c,0xb83d,0xb83e,0xb83f,0xb841,0xb842,0xb843,0xb845,0xb846,
 132.339 +    0xb847,0xb848,0xb849,0xb84a,0xb84b,0xb84c,0xb84d,0xb84e,0xb84f,0xb850,
 132.340 +    0xb852,0xb854,0xb855,0xb856,0xb857,0xb858,0xb859,0xb85a,0xb85b,0xb85e,
 132.341 +    0xb85f,0xb861,0xb862,0xb863,0xb865,0xb866,0xb867,0xb868,0xb869,0xb86a,
 132.342 +    0xb86b,0xb86e,0xb870,0xb872,0xb873,0xb874,0xb875,0xb876,0xb877,0xb879,
 132.343 +    0xb87a,0xb87b,0xb87d,0xb87e,0xb87f,0xb880,0xb881,0xb882,0xb883,0xb884
 132.344 +  },
 132.345 +  {				/* ku 0f */
 132.346 +    0xb885,0xb886,0xb887,0xb888,0xb889,0xb88a,0xb88b,0xb88c,0xb88e,0xb88f,
 132.347 +    0xb890,0xb891,0xb892,0xb893,0xb894,0xb895,0xb896,0xb897,0xb898,0xb899,
 132.348 +    0xb89a,0xb89b,0xb89c,0xb89d,0xb89e,0xb89f,UBOGON,UBOGON,UBOGON,UBOGON,
 132.349 +    UBOGON,UBOGON,0xb8a0,0xb8a1,0xb8a2,0xb8a3,0xb8a4,0xb8a5,0xb8a6,0xb8a7,
 132.350 +    0xb8a9,0xb8aa,0xb8ab,0xb8ac,0xb8ad,0xb8ae,0xb8af,0xb8b1,0xb8b2,0xb8b3,
 132.351 +    0xb8b5,0xb8b6,0xb8b7,0xb8b9,0xb8ba,0xb8bb,0xb8bc,0xb8bd,UBOGON,UBOGON,
 132.352 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb8be,0xb8bf,0xb8c2,0xb8c4,0xb8c6,0xb8c7,
 132.353 +    0xb8c8,0xb8c9,0xb8ca,0xb8cb,0xb8cd,0xb8ce,0xb8cf,0xb8d1,0xb8d2,0xb8d3,
 132.354 +    0xb8d5,0xb8d6,0xb8d7,0xb8d8,0xb8d9,0xb8da,0xb8db,0xb8dc,0xb8de,0xb8e0,
 132.355 +    0xb8e2,0xb8e3,0xb8e4,0xb8e5,0xb8e6,0xb8e7,0xb8ea,0xb8eb,0xb8ed,0xb8ee,
 132.356 +    0xb8ef,0xb8f1,0xb8f2,0xb8f3,0xb8f4,0xb8f5,0xb8f6,0xb8f7,0xb8fa,0xb8fc,
 132.357 +    0xb8fe,0xb8ff,0xb900,0xb901,0xb902,0xb903,0xb905,0xb906,0xb907,0xb908,
 132.358 +    0xb909,0xb90a,0xb90b,0xb90c,0xb90d,0xb90e,0xb90f,0xb910,0xb911,0xb912,
 132.359 +    0xb913,0xb914,0xb915,0xb916,0xb917,0xb919,0xb91a,0xb91b,0xb91c,0xb91d,
 132.360 +    0xb91e,0xb91f,0xb921,0xb922,0xb923,0xb924,0xb925,0xb926,0xb927,0xb928,
 132.361 +    0xb929,0xb92a,0xb92b,0xb92c,0xb92d,0xb92e,0xb92f,0xb930,0xb931,0xb932,
 132.362 +    0xb933,0xb934,0xb935,0xb936,0xb937,0xb938,0xb939,0xb93a,0xb93b,0xb93e,
 132.363 +    0xb93f,0xb941,0xb942,0xb943,0xb945,0xb946,0xb947,0xb948,0xb949,0xb94a,
 132.364 +    0xb94b,0xb94d,0xb94e,0xb950,0xb952,0xb953,0xb954,0xb955,0xb956,0xb957
 132.365 +  },
 132.366 +  {				/* ku 10 */
 132.367 +    0xb95a,0xb95b,0xb95d,0xb95e,0xb95f,0xb961,0xb962,0xb963,0xb964,0xb965,
 132.368 +    0xb966,0xb967,0xb96a,0xb96c,0xb96e,0xb96f,0xb970,0xb971,0xb972,0xb973,
 132.369 +    0xb976,0xb977,0xb979,0xb97a,0xb97b,0xb97d,UBOGON,UBOGON,UBOGON,UBOGON,
 132.370 +    UBOGON,UBOGON,0xb97e,0xb97f,0xb980,0xb981,0xb982,0xb983,0xb986,0xb988,
 132.371 +    0xb98b,0xb98c,0xb98f,0xb990,0xb991,0xb992,0xb993,0xb994,0xb995,0xb996,
 132.372 +    0xb997,0xb998,0xb999,0xb99a,0xb99b,0xb99c,0xb99d,0xb99e,UBOGON,UBOGON,
 132.373 +    UBOGON,UBOGON,UBOGON,UBOGON,0xb99f,0xb9a0,0xb9a1,0xb9a2,0xb9a3,0xb9a4,
 132.374 +    0xb9a5,0xb9a6,0xb9a7,0xb9a8,0xb9a9,0xb9aa,0xb9ab,0xb9ae,0xb9af,0xb9b1,
 132.375 +    0xb9b2,0xb9b3,0xb9b5,0xb9b6,0xb9b7,0xb9b8,0xb9b9,0xb9ba,0xb9bb,0xb9be,
 132.376 +    0xb9c0,0xb9c2,0xb9c3,0xb9c4,0xb9c5,0xb9c6,0xb9c7,0xb9ca,0xb9cb,0xb9cd,
 132.377 +    0xb9d3,0xb9d4,0xb9d5,0xb9d6,0xb9d7,0xb9da,0xb9dc,0xb9df,0xb9e0,0xb9e2,
 132.378 +    0xb9e6,0xb9e7,0xb9e9,0xb9ea,0xb9eb,0xb9ed,0xb9ee,0xb9ef,0xb9f0,0xb9f1,
 132.379 +    0xb9f2,0xb9f3,0xb9f6,0xb9fb,0xb9fc,0xb9fd,0xb9fe,0xb9ff,0xba02,0xba03,
 132.380 +    0xba04,0xba05,0xba06,0xba07,0xba09,0xba0a,0xba0b,0xba0c,0xba0d,0xba0e,
 132.381 +    0xba0f,0xba10,0xba11,0xba12,0xba13,0xba14,0xba16,0xba17,0xba18,0xba19,
 132.382 +    0xba1a,0xba1b,0xba1c,0xba1d,0xba1e,0xba1f,0xba20,0xba21,0xba22,0xba23,
 132.383 +    0xba24,0xba25,0xba26,0xba27,0xba28,0xba29,0xba2a,0xba2b,0xba2c,0xba2d,
 132.384 +    0xba2e,0xba2f,0xba30,0xba31,0xba32,0xba33,0xba34,0xba35,0xba36,0xba37,
 132.385 +    0xba3a,0xba3b,0xba3d,0xba3e,0xba3f,0xba41,0xba43,0xba44,0xba45,0xba46
 132.386 +  },
 132.387 +  {				/* ku 11 */
 132.388 +    0xba47,0xba4a,0xba4c,0xba4f,0xba50,0xba51,0xba52,0xba56,0xba57,0xba59,
 132.389 +    0xba5a,0xba5b,0xba5d,0xba5e,0xba5f,0xba60,0xba61,0xba62,0xba63,0xba66,
 132.390 +    0xba6a,0xba6b,0xba6c,0xba6d,0xba6e,0xba6f,UBOGON,UBOGON,UBOGON,UBOGON,
 132.391 +    UBOGON,UBOGON,0xba72,0xba73,0xba75,0xba76,0xba77,0xba79,0xba7a,0xba7b,
 132.392 +    0xba7c,0xba7d,0xba7e,0xba7f,0xba80,0xba81,0xba82,0xba86,0xba88,0xba89,
 132.393 +    0xba8a,0xba8b,0xba8d,0xba8e,0xba8f,0xba90,0xba91,0xba92,UBOGON,UBOGON,
 132.394 +    UBOGON,UBOGON,UBOGON,UBOGON,0xba93,0xba94,0xba95,0xba96,0xba97,0xba98,
 132.395 +    0xba99,0xba9a,0xba9b,0xba9c,0xba9d,0xba9e,0xba9f,0xbaa0,0xbaa1,0xbaa2,
 132.396 +    0xbaa3,0xbaa4,0xbaa5,0xbaa6,0xbaa7,0xbaaa,0xbaad,0xbaae,0xbaaf,0xbab1,
 132.397 +    0xbab3,0xbab4,0xbab5,0xbab6,0xbab7,0xbaba,0xbabc,0xbabe,0xbabf,0xbac0,
 132.398 +    0xbac1,0xbac2,0xbac3,0xbac5,0xbac6,0xbac7,0xbac9,0xbaca,0xbacb,0xbacc,
 132.399 +    0xbacd,0xbace,0xbacf,0xbad0,0xbad1,0xbad2,0xbad3,0xbad4,0xbad5,0xbad6,
 132.400 +    0xbad7,0xbada,0xbadb,0xbadc,0xbadd,0xbade,0xbadf,0xbae0,0xbae1,0xbae2,
 132.401 +    0xbae3,0xbae4,0xbae5,0xbae6,0xbae7,0xbae8,0xbae9,0xbaea,0xbaeb,0xbaec,
 132.402 +    0xbaed,0xbaee,0xbaef,0xbaf0,0xbaf1,0xbaf2,0xbaf3,0xbaf4,0xbaf5,0xbaf6,
 132.403 +    0xbaf7,0xbaf8,0xbaf9,0xbafa,0xbafb,0xbafd,0xbafe,0xbaff,0xbb01,0xbb02,
 132.404 +    0xbb03,0xbb05,0xbb06,0xbb07,0xbb08,0xbb09,0xbb0a,0xbb0b,0xbb0c,0xbb0e,
 132.405 +    0xbb10,0xbb12,0xbb13,0xbb14,0xbb15,0xbb16,0xbb17,0xbb19,0xbb1a,0xbb1b,
 132.406 +    0xbb1d,0xbb1e,0xbb1f,0xbb21,0xbb22,0xbb23,0xbb24,0xbb25,0xbb26,0xbb27
 132.407 +  },
 132.408 +  {				/* ku 12 */
 132.409 +    0xbb28,0xbb2a,0xbb2c,0xbb2d,0xbb2e,0xbb2f,0xbb30,0xbb31,0xbb32,0xbb33,
 132.410 +    0xbb37,0xbb39,0xbb3a,0xbb3f,0xbb40,0xbb41,0xbb42,0xbb43,0xbb46,0xbb48,
 132.411 +    0xbb4a,0xbb4b,0xbb4c,0xbb4e,0xbb51,0xbb52,UBOGON,UBOGON,UBOGON,UBOGON,
 132.412 +    UBOGON,UBOGON,0xbb53,0xbb55,0xbb56,0xbb57,0xbb59,0xbb5a,0xbb5b,0xbb5c,
 132.413 +    0xbb5d,0xbb5e,0xbb5f,0xbb60,0xbb62,0xbb64,0xbb65,0xbb66,0xbb67,0xbb68,
 132.414 +    0xbb69,0xbb6a,0xbb6b,0xbb6d,0xbb6e,0xbb6f,0xbb70,0xbb71,UBOGON,UBOGON,
 132.415 +    UBOGON,UBOGON,UBOGON,UBOGON,0xbb72,0xbb73,0xbb74,0xbb75,0xbb76,0xbb77,
 132.416 +    0xbb78,0xbb79,0xbb7a,0xbb7b,0xbb7c,0xbb7d,0xbb7e,0xbb7f,0xbb80,0xbb81,
 132.417 +    0xbb82,0xbb83,0xbb84,0xbb85,0xbb86,0xbb87,0xbb89,0xbb8a,0xbb8b,0xbb8d,
 132.418 +    0xbb8e,0xbb8f,0xbb91,0xbb92,0xbb93,0xbb94,0xbb95,0xbb96,0xbb97,0xbb98,
 132.419 +    0xbb99,0xbb9a,0xbb9b,0xbb9c,0xbb9d,0xbb9e,0xbb9f,0xbba0,0xbba1,0xbba2,
 132.420 +    0xbba3,0xbba5,0xbba6,0xbba7,0xbba9,0xbbaa,0xbbab,0xbbad,0xbbae,0xbbaf,
 132.421 +    0xbbb0,0xbbb1,0xbbb2,0xbbb3,0xbbb5,0xbbb6,0xbbb8,0xbbb9,0xbbba,0xbbbb,
 132.422 +    0xbbbc,0xbbbd,0xbbbe,0xbbbf,0xbbc1,0xbbc2,0xbbc3,0xbbc5,0xbbc6,0xbbc7,
 132.423 +    0xbbc9,0xbbca,0xbbcb,0xbbcc,0xbbcd,0xbbce,0xbbcf,0xbbd1,0xbbd2,0xbbd4,
 132.424 +    0xbbd5,0xbbd6,0xbbd7,0xbbd8,0xbbd9,0xbbda,0xbbdb,0xbbdc,0xbbdd,0xbbde,
 132.425 +    0xbbdf,0xbbe0,0xbbe1,0xbbe2,0xbbe3,0xbbe4,0xbbe5,0xbbe6,0xbbe7,0xbbe8,
 132.426 +    0xbbe9,0xbbea,0xbbeb,0xbbec,0xbbed,0xbbee,0xbbef,0xbbf0,0xbbf1,0xbbf2,
 132.427 +    0xbbf3,0xbbf4,0xbbf5,0xbbf6,0xbbf7,0xbbfa,0xbbfb,0xbbfd,0xbbfe,0xbc01
 132.428 +  },
 132.429 +  {				/* ku 13 */
 132.430 +    0xbc03,0xbc04,0xbc05,0xbc06,0xbc07,0xbc0a,0xbc0e,0xbc10,0xbc12,0xbc13,
 132.431 +    0xbc19,0xbc1a,0xbc20,0xbc21,0xbc22,0xbc23,0xbc26,0xbc28,0xbc2a,0xbc2b,
 132.432 +    0xbc2c,0xbc2e,0xbc2f,0xbc32,0xbc33,0xbc35,UBOGON,UBOGON,UBOGON,UBOGON,
 132.433 +    UBOGON,UBOGON,0xbc36,0xbc37,0xbc39,0xbc3a,0xbc3b,0xbc3c,0xbc3d,0xbc3e,
 132.434 +    0xbc3f,0xbc42,0xbc46,0xbc47,0xbc48,0xbc4a,0xbc4b,0xbc4e,0xbc4f,0xbc51,
 132.435 +    0xbc52,0xbc53,0xbc54,0xbc55,0xbc56,0xbc57,0xbc58,0xbc59,UBOGON,UBOGON,
 132.436 +    UBOGON,UBOGON,UBOGON,UBOGON,0xbc5a,0xbc5b,0xbc5c,0xbc5e,0xbc5f,0xbc60,
 132.437 +    0xbc61,0xbc62,0xbc63,0xbc64,0xbc65,0xbc66,0xbc67,0xbc68,0xbc69,0xbc6a,
 132.438 +    0xbc6b,0xbc6c,0xbc6d,0xbc6e,0xbc6f,0xbc70,0xbc71,0xbc72,0xbc73,0xbc74,
 132.439 +    0xbc75,0xbc76,0xbc77,0xbc78,0xbc79,0xbc7a,0xbc7b,0xbc7c,0xbc7d,0xbc7e,
 132.440 +    0xbc7f,0xbc80,0xbc81,0xbc82,0xbc83,0xbc86,0xbc87,0xbc89,0xbc8a,0xbc8d,
 132.441 +    0xbc8f,0xbc90,0xbc91,0xbc92,0xbc93,0xbc96,0xbc98,0xbc9b,0xbc9c,0xbc9d,
 132.442 +    0xbc9e,0xbc9f,0xbca2,0xbca3,0xbca5,0xbca6,0xbca9,0xbcaa,0xbcab,0xbcac,
 132.443 +    0xbcad,0xbcae,0xbcaf,0xbcb2,0xbcb6,0xbcb7,0xbcb8,0xbcb9,0xbcba,0xbcbb,
 132.444 +    0xbcbe,0xbcbf,0xbcc1,0xbcc2,0xbcc3,0xbcc5,0xbcc6,0xbcc7,0xbcc8,0xbcc9,
 132.445 +    0xbcca,0xbccb,0xbccc,0xbcce,0xbcd2,0xbcd3,0xbcd4,0xbcd6,0xbcd7,0xbcd9,
 132.446 +    0xbcda,0xbcdb,0xbcdd,0xbcde,0xbcdf,0xbce0,0xbce1,0xbce2,0xbce3,0xbce4,
 132.447 +    0xbce5,0xbce6,0xbce7,0xbce8,0xbce9,0xbcea,0xbceb,0xbcec,0xbced,0xbcee,
 132.448 +    0xbcef,0xbcf0,0xbcf1,0xbcf2,0xbcf3,0xbcf7,0xbcf9,0xbcfa,0xbcfb,0xbcfd
 132.449 +  },
 132.450 +  {				/* ku 14 */
 132.451 +    0xbcfe,0xbcff,0xbd00,0xbd01,0xbd02,0xbd03,0xbd06,0xbd08,0xbd0a,0xbd0b,
 132.452 +    0xbd0c,0xbd0d,0xbd0e,0xbd0f,0xbd11,0xbd12,0xbd13,0xbd15,0xbd16,0xbd17,
 132.453 +    0xbd18,0xbd19,0xbd1a,0xbd1b,0xbd1c,0xbd1d,UBOGON,UBOGON,UBOGON,UBOGON,
 132.454 +    UBOGON,UBOGON,0xbd1e,0xbd1f,0xbd20,0xbd21,0xbd22,0xbd23,0xbd25,0xbd26,
 132.455 +    0xbd27,0xbd28,0xbd29,0xbd2a,0xbd2b,0xbd2d,0xbd2e,0xbd2f,0xbd30,0xbd31,
 132.456 +    0xbd32,0xbd33,0xbd34,0xbd35,0xbd36,0xbd37,0xbd38,0xbd39,UBOGON,UBOGON,
 132.457 +    UBOGON,UBOGON,UBOGON,UBOGON,0xbd3a,0xbd3b,0xbd3c,0xbd3d,0xbd3e,0xbd3f,
 132.458 +    0xbd41,0xbd42,0xbd43,0xbd44,0xbd45,0xbd46,0xbd47,0xbd4a,0xbd4b,0xbd4d,
 132.459 +    0xbd4e,0xbd4f,0xbd51,0xbd52,0xbd53,0xbd54,0xbd55,0xbd56,0xbd57,0xbd5a,
 132.460 +    0xbd5b,0xbd5c,0xbd5d,0xbd5e,0xbd5f,0xbd60,0xbd61,0xbd62,0xbd63,0xbd65,
 132.461 +    0xbd66,0xbd67,0xbd69,0xbd6a,0xbd6b,0xbd6c,0xbd6d,0xbd6e,0xbd6f,0xbd70,
 132.462 +    0xbd71,0xbd72,0xbd73,0xbd74,0xbd75,0xbd76,0xbd77,0xbd78,0xbd79,0xbd7a,
 132.463 +    0xbd7b,0xbd7c,0xbd7d,0xbd7e,0xbd7f,0xbd82,0xbd83,0xbd85,0xbd86,0xbd8b,
 132.464 +    0xbd8c,0xbd8d,0xbd8e,0xbd8f,0xbd92,0xbd94,0xbd96,0xbd97,0xbd98,0xbd9b,
 132.465 +    0xbd9d,0xbd9e,0xbd9f,0xbda0,0xbda1,0xbda2,0xbda3,0xbda5,0xbda6,0xbda7,
 132.466 +    0xbda8,0xbda9,0xbdaa,0xbdab,0xbdac,0xbdad,0xbdae,0xbdaf,0xbdb1,0xbdb2,
 132.467 +    0xbdb3,0xbdb4,0xbdb5,0xbdb6,0xbdb7,0xbdb9,0xbdba,0xbdbb,0xbdbc,0xbdbd,
 132.468 +    0xbdbe,0xbdbf,0xbdc0,0xbdc1,0xbdc2,0xbdc3,0xbdc4,0xbdc5,0xbdc6,0xbdc7,
 132.469 +    0xbdc8,0xbdc9,0xbdca,0xbdcb,0xbdcc,0xbdcd,0xbdce,0xbdcf,0xbdd0,0xbdd1
 132.470 +  },
 132.471 +  {				/* ku 15 */
 132.472 +    0xbdd2,0xbdd3,0xbdd6,0xbdd7,0xbdd9,0xbdda,0xbddb,0xbddd,0xbdde,0xbddf,
 132.473 +    0xbde0,0xbde1,0xbde2,0xbde3,0xbde4,0xbde5,0xbde6,0xbde7,0xbde8,0xbdea,
 132.474 +    0xbdeb,0xbdec,0xbded,0xbdee,0xbdef,0xbdf1,UBOGON,UBOGON,UBOGON,UBOGON,
 132.475 +    UBOGON,UBOGON,0xbdf2,0xbdf3,0xbdf5,0xbdf6,0xbdf7,0xbdf9,0xbdfa,0xbdfb,
 132.476 +    0xbdfc,0xbdfd,0xbdfe,0xbdff,0xbe01,0xbe02,0xbe04,0xbe06,0xbe07,0xbe08,
 132.477 +    0xbe09,0xbe0a,0xbe0b,0xbe0e,0xbe0f,0xbe11,0xbe12,0xbe13,UBOGON,UBOGON,
 132.478 +    UBOGON,UBOGON,UBOGON,UBOGON,0xbe15,0xbe16,0xbe17,0xbe18,0xbe19,0xbe1a,
 132.479 +    0xbe1b,0xbe1e,0xbe20,0xbe21,0xbe22,0xbe23,0xbe24,0xbe25,0xbe26,0xbe27,
 132.480 +    0xbe28,0xbe29,0xbe2a,0xbe2b,0xbe2c,0xbe2d,0xbe2e,0xbe2f,0xbe30,0xbe31,
 132.481 +    0xbe32,0xbe33,0xbe34,0xbe35,0xbe36,0xbe37,0xbe38,0xbe39,0xbe3a,0xbe3b,
 132.482 +    0xbe3c,0xbe3d,0xbe3e,0xbe3f,0xbe40,0xbe41,0xbe42,0xbe43,0xbe46,0xbe47,
 132.483 +    0xbe49,0xbe4a,0xbe4b,0xbe4d,0xbe4f,0xbe50,0xbe51,0xbe52,0xbe53,0xbe56,
 132.484 +    0xbe58,0xbe5c,0xbe5d,0xbe5e,0xbe5f,0xbe62,0xbe63,0xbe65,0xbe66,0xbe67,
 132.485 +    0xbe69,0xbe6b,0xbe6c,0xbe6d,0xbe6e,0xbe6f,0xbe72,0xbe76,0xbe77,0xbe78,
 132.486 +    0xbe79,0xbe7a,0xbe7e,0xbe7f,0xbe81,0xbe82,0xbe83,0xbe85,0xbe86,0xbe87,
 132.487 +    0xbe88,0xbe89,0xbe8a,0xbe8b,0xbe8e,0xbe92,0xbe93,0xbe94,0xbe95,0xbe96,
 132.488 +    0xbe97,0xbe9a,0xbe9b,0xbe9c,0xbe9d,0xbe9e,0xbe9f,0xbea0,0xbea1,0xbea2,
 132.489 +    0xbea3,0xbea4,0xbea5,0xbea6,0xbea7,0xbea9,0xbeaa,0xbeab,0xbeac,0xbead,
 132.490 +    0xbeae,0xbeaf,0xbeb0,0xbeb1,0xbeb2,0xbeb3,0xbeb4,0xbeb5,0xbeb6,0xbeb7
 132.491 +  },
 132.492 +  {				/* ku 16 */
 132.493 +    0xbeb8,0xbeb9,0xbeba,0xbebb,0xbebc,0xbebd,0xbebe,0xbebf,0xbec0,0xbec1,
 132.494 +    0xbec2,0xbec3,0xbec4,0xbec5,0xbec6,0xbec7,0xbec8,0xbec9,0xbeca,0xbecb,
 132.495 +    0xbecc,0xbecd,0xbece,0xbecf,0xbed2,0xbed3,UBOGON,UBOGON,UBOGON,UBOGON,
 132.496 +    UBOGON,UBOGON,0xbed5,0xbed6,0xbed9,0xbeda,0xbedb,0xbedc,0xbedd,0xbede,
 132.497 +    0xbedf,0xbee1,0xbee2,0xbee6,0xbee7,0xbee8,0xbee9,0xbeea,0xbeeb,0xbeed,
 132.498 +    0xbeee,0xbeef,0xbef0,0xbef1,0xbef2,0xbef3,0xbef4,0xbef5,UBOGON,UBOGON,
 132.499 +    UBOGON,UBOGON,UBOGON,UBOGON,0xbef6,0xbef7,0xbef8,0xbef9,0xbefa,0xbefb,
 132.500 +    0xbefc,0xbefd,0xbefe,0xbeff,0xbf00,0xbf02,0xbf03,0xbf04,0xbf05,0xbf06,
 132.501 +    0xbf07,0xbf0a,0xbf0b,0xbf0c,0xbf0d,0xbf0e,0xbf0f,0xbf10,0xbf11,0xbf12,
 132.502 +    0xbf13,0xbf14,0xbf15,0xbf16,0xbf17,0xbf1a,0xbf1e,0xbf1f,0xbf20,0xbf21,
 132.503 +    0xbf22,0xbf23,0xbf24,0xbf25,0xbf26,0xbf27,0xbf28,0xbf29,0xbf2a,0xbf2b,
 132.504 +    0xbf2c,0xbf2d,0xbf2e,0xbf2f,0xbf30,0xbf31,0xbf32,0xbf33,0xbf34,0xbf35,
 132.505 +    0xbf36,0xbf37,0xbf38,0xbf39,0xbf3a,0xbf3b,0xbf3c,0xbf3d,0xbf3e,0xbf3f,
 132.506 +    0xbf42,0xbf43,0xbf45,0xbf46,0xbf47,0xbf49,0xbf4a,0xbf4b,0xbf4c,0xbf4d,
 132.507 +    0xbf4e,0xbf4f,0xbf52,0xbf53,0xbf54,0xbf56,0xbf57,0xbf58,0xbf59,0xbf5a,
 132.508 +    0xbf5b,0xbf5c,0xbf5d,0xbf5e,0xbf5f,0xbf60,0xbf61,0xbf62,0xbf63,0xbf64,
 132.509 +    0xbf65,0xbf66,0xbf67,0xbf68,0xbf69,0xbf6a,0xbf6b,0xbf6c,0xbf6d,0xbf6e,
 132.510 +    0xbf6f,0xbf70,0xbf71,0xbf72,0xbf73,0xbf74,0xbf75,0xbf76,0xbf77,0xbf78,
 132.511 +    0xbf79,0xbf7a,0xbf7b,0xbf7c,0xbf7d,0xbf7e,0xbf7f,0xbf80,0xbf81,0xbf82
 132.512 +  },
 132.513 +  {				/* ku 17 */
 132.514 +    0xbf83,0xbf84,0xbf85,0xbf86,0xbf87,0xbf88,0xbf89,0xbf8a,0xbf8b,0xbf8c,
 132.515 +    0xbf8d,0xbf8e,0xbf8f,0xbf90,0xbf91,0xbf92,0xbf93,0xbf95,0xbf96,0xbf97,
 132.516 +    0xbf98,0xbf99,0xbf9a,0xbf9b,0xbf9c,0xbf9d,UBOGON,UBOGON,UBOGON,UBOGON,
 132.517 +    UBOGON,UBOGON,0xbf9e,0xbf9f,0xbfa0,0xbfa1,0xbfa2,0xbfa3,0xbfa4,0xbfa5,
 132.518 +    0xbfa6,0xbfa7,0xbfa8,0xbfa9,0xbfaa,0xbfab,0xbfac,0xbfad,0xbfae,0xbfaf,
 132.519 +    0xbfb1,0xbfb2,0xbfb3,0xbfb4,0xbfb5,0xbfb6,0xbfb7,0xbfb8,UBOGON,UBOGON,
 132.520 +    UBOGON,UBOGON,UBOGON,UBOGON,0xbfb9,0xbfba,0xbfbb,0xbfbc,0xbfbd,0xbfbe,
 132.521 +    0xbfbf,0xbfc0,0xbfc1,0xbfc2,0xbfc3,0xbfc4,0xbfc6,0xbfc7,0xbfc8,0xbfc9,
 132.522 +    0xbfca,0xbfcb,0xbfce,0xbfcf,0xbfd1,0xbfd2,0xbfd3,0xbfd5,0xbfd6,0xbfd7,
 132.523 +    0xbfd8,0xbfd9,0xbfda,0xbfdb,0xbfdd,0xbfde,0xbfe0,0xbfe2,0xbfe3,0xbfe4,
 132.524 +    0xbfe5,0xbfe6,0xbfe7,0xbfe8,0xbfe9,0xbfea,0xbfeb,0xbfec,0xbfed,0xbfee,
 132.525 +    0xbfef,0xbff0,0xbff1,0xbff2,0xbff3,0xbff4,0xbff5,0xbff6,0xbff7,0xbff8,
 132.526 +    0xbff9,0xbffa,0xbffb,0xbffc,0xbffd,0xbffe,0xbfff,0xc000,0xc001,0xc002,
 132.527 +    0xc003,0xc004,0xc005,0xc006,0xc007,0xc008,0xc009,0xc00a,0xc00b,0xc00c,
 132.528 +    0xc00d,0xc00e,0xc00f,0xc010,0xc011,0xc012,0xc013,0xc014,0xc015,0xc016,
 132.529 +    0xc017,0xc018,0xc019,0xc01a,0xc01b,0xc01c,0xc01d,0xc01e,0xc01f,0xc020,
 132.530 +    0xc021,0xc022,0xc023,0xc024,0xc025,0xc026,0xc027,0xc028,0xc029,0xc02a,
 132.531 +    0xc02b,0xc02c,0xc02d,0xc02e,0xc02f,0xc030,0xc031,0xc032,0xc033,0xc034,
 132.532 +    0xc035,0xc036,0xc037,0xc038,0xc039,0xc03a,0xc03b,0xc03d,0xc03e,0xc03f
 132.533 +  },
 132.534 +  {				/* ku 18 */
 132.535 +    0xc040,0xc041,0xc042,0xc043,0xc044,0xc045,0xc046,0xc047,0xc048,0xc049,
 132.536 +    0xc04a,0xc04b,0xc04c,0xc04d,0xc04e,0xc04f,0xc050,0xc052,0xc053,0xc054,
 132.537 +    0xc055,0xc056,0xc057,0xc059,0xc05a,0xc05b,UBOGON,UBOGON,UBOGON,UBOGON,
 132.538 +    UBOGON,UBOGON,0xc05d,0xc05e,0xc05f,0xc061,0xc062,0xc063,0xc064,0xc065,
 132.539 +    0xc066,0xc067,0xc06a,0xc06b,0xc06c,0xc06d,0xc06e,0xc06f,0xc070,0xc071,
 132.540 +    0xc072,0xc073,0xc074,0xc075,0xc076,0xc077,0xc078,0xc079,UBOGON,UBOGON,
 132.541 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc07a,0xc07b,0xc07c,0xc07d,0xc07e,0xc07f,
 132.542 +    0xc080,0xc081,0xc082,0xc083,0xc084,0xc085,0xc086,0xc087,0xc088,0xc089,
 132.543 +    0xc08a,0xc08b,0xc08c,0xc08d,0xc08e,0xc08f,0xc092,0xc093,0xc095,0xc096,
 132.544 +    0xc097,0xc099,0xc09a,0xc09b,0xc09c,0xc09d,0xc09e,0xc09f,0xc0a2,0xc0a4,
 132.545 +    0xc0a6,0xc0a7,0xc0a8,0xc0a9,0xc0aa,0xc0ab,0xc0ae,0xc0b1,0xc0b2,0xc0b7,
 132.546 +    0xc0b8,0xc0b9,0xc0ba,0xc0bb,0xc0be,0xc0c2,0xc0c3,0xc0c4,0xc0c6,0xc0c7,
 132.547 +    0xc0ca,0xc0cb,0xc0cd,0xc0ce,0xc0cf,0xc0d1,0xc0d2,0xc0d3,0xc0d4,0xc0d5,
 132.548 +    0xc0d6,0xc0d7,0xc0da,0xc0de,0xc0df,0xc0e0,0xc0e1,0xc0e2,0xc0e3,0xc0e6,
 132.549 +    0xc0e7,0xc0e9,0xc0ea,0xc0eb,0xc0ed,0xc0ee,0xc0ef,0xc0f0,0xc0f1,0xc0f2,
 132.550 +    0xc0f3,0xc0f6,0xc0f8,0xc0fa,0xc0fb,0xc0fc,0xc0fd,0xc0fe,0xc0ff,0xc101,
 132.551 +    0xc102,0xc103,0xc105,0xc106,0xc107,0xc109,0xc10a,0xc10b,0xc10c,0xc10d,
 132.552 +    0xc10e,0xc10f,0xc111,0xc112,0xc113,0xc114,0xc116,0xc117,0xc118,0xc119,
 132.553 +    0xc11a,0xc11b,0xc121,0xc122,0xc125,0xc128,0xc129,0xc12a,0xc12b,0xc12e
 132.554 +  },
 132.555 +  {				/* ku 19 */
 132.556 +    0xc132,0xc133,0xc134,0xc135,0xc137,0xc13a,0xc13b,0xc13d,0xc13e,0xc13f,
 132.557 +    0xc141,0xc142,0xc143,0xc144,0xc145,0xc146,0xc147,0xc14a,0xc14e,0xc14f,
 132.558 +    0xc150,0xc151,0xc152,0xc153,0xc156,0xc157,UBOGON,UBOGON,UBOGON,UBOGON,
 132.559 +    UBOGON,UBOGON,0xc159,0xc15a,0xc15b,0xc15d,0xc15e,0xc15f,0xc160,0xc161,
 132.560 +    0xc162,0xc163,0xc166,0xc16a,0xc16b,0xc16c,0xc16d,0xc16e,0xc16f,0xc171,
 132.561 +    0xc172,0xc173,0xc175,0xc176,0xc177,0xc179,0xc17a,0xc17b,UBOGON,UBOGON,
 132.562 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc17c,0xc17d,0xc17e,0xc17f,0xc180,0xc181,
 132.563 +    0xc182,0xc183,0xc184,0xc186,0xc187,0xc188,0xc189,0xc18a,0xc18b,0xc18f,
 132.564 +    0xc191,0xc192,0xc193,0xc195,0xc197,0xc198,0xc199,0xc19a,0xc19b,0xc19e,
 132.565 +    0xc1a0,0xc1a2,0xc1a3,0xc1a4,0xc1a6,0xc1a7,0xc1aa,0xc1ab,0xc1ad,0xc1ae,
 132.566 +    0xc1af,0xc1b1,0xc1b2,0xc1b3,0xc1b4,0xc1b5,0xc1b6,0xc1b7,0xc1b8,0xc1b9,
 132.567 +    0xc1ba,0xc1bb,0xc1bc,0xc1be,0xc1bf,0xc1c0,0xc1c1,0xc1c2,0xc1c3,0xc1c5,
 132.568 +    0xc1c6,0xc1c7,0xc1c9,0xc1ca,0xc1cb,0xc1cd,0xc1ce,0xc1cf,0xc1d0,0xc1d1,
 132.569 +    0xc1d2,0xc1d3,0xc1d5,0xc1d6,0xc1d9,0xc1da,0xc1db,0xc1dc,0xc1dd,0xc1de,
 132.570 +    0xc1df,0xc1e1,0xc1e2,0xc1e3,0xc1e5,0xc1e6,0xc1e7,0xc1e9,0xc1ea,0xc1eb,
 132.571 +    0xc1ec,0xc1ed,0xc1ee,0xc1ef,0xc1f2,0xc1f4,0xc1f5,0xc1f6,0xc1f7,0xc1f8,
 132.572 +    0xc1f9,0xc1fa,0xc1fb,0xc1fe,0xc1ff,0xc201,0xc202,0xc203,0xc205,0xc206,
 132.573 +    0xc207,0xc208,0xc209,0xc20a,0xc20b,0xc20e,0xc210,0xc212,0xc213,0xc214,
 132.574 +    0xc215,0xc216,0xc217,0xc21a,0xc21b,0xc21d,0xc21e,0xc221,0xc222,0xc223
 132.575 +  },
 132.576 +  {				/* ku 1a */
 132.577 +    0xc224,0xc225,0xc226,0xc227,0xc22a,0xc22c,0xc22e,0xc230,0xc233,0xc235,
 132.578 +    0xc236,0xc237,0xc238,0xc239,0xc23a,0xc23b,0xc23c,0xc23d,0xc23e,0xc23f,
 132.579 +    0xc240,0xc241,0xc242,0xc243,0xc244,0xc245,UBOGON,UBOGON,UBOGON,UBOGON,
 132.580 +    UBOGON,UBOGON,0xc246,0xc247,0xc249,0xc24a,0xc24b,0xc24c,0xc24d,0xc24e,
 132.581 +    0xc24f,0xc252,0xc253,0xc255,0xc256,0xc257,0xc259,0xc25a,0xc25b,0xc25c,
 132.582 +    0xc25d,0xc25e,0xc25f,0xc261,0xc262,0xc263,0xc264,0xc266,UBOGON,UBOGON,
 132.583 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc267,0xc268,0xc269,0xc26a,0xc26b,0xc26e,
 132.584 +    0xc26f,0xc271,0xc272,0xc273,0xc275,0xc276,0xc277,0xc278,0xc279,0xc27a,
 132.585 +    0xc27b,0xc27e,0xc280,0xc282,0xc283,0xc284,0xc285,0xc286,0xc287,0xc28a,
 132.586 +    0xc28b,0xc28c,0xc28d,0xc28e,0xc28f,0xc291,0xc292,0xc293,0xc294,0xc295,
 132.587 +    0xc296,0xc297,0xc299,0xc29a,0xc29c,0xc29e,0xc29f,0xc2a0,0xc2a1,0xc2a2,
 132.588 +    0xc2a3,0xc2a6,0xc2a7,0xc2a9,0xc2aa,0xc2ab,0xc2ae,0xc2af,0xc2b0,0xc2b1,
 132.589 +    0xc2b2,0xc2b3,0xc2b6,0xc2b8,0xc2ba,0xc2bb,0xc2bc,0xc2bd,0xc2be,0xc2bf,
 132.590 +    0xc2c0,0xc2c1,0xc2c2,0xc2c3,0xc2c4,0xc2c5,0xc2c6,0xc2c7,0xc2c8,0xc2c9,
 132.591 +    0xc2ca,0xc2cb,0xc2cc,0xc2cd,0xc2ce,0xc2cf,0xc2d0,0xc2d1,0xc2d2,0xc2d3,
 132.592 +    0xc2d4,0xc2d5,0xc2d6,0xc2d7,0xc2d8,0xc2d9,0xc2da,0xc2db,0xc2de,0xc2df,
 132.593 +    0xc2e1,0xc2e2,0xc2e5,0xc2e6,0xc2e7,0xc2e8,0xc2e9,0xc2ea,0xc2ee,0xc2f0,
 132.594 +    0xc2f2,0xc2f3,0xc2f4,0xc2f5,0xc2f7,0xc2fa,0xc2fd,0xc2fe,0xc2ff,0xc301,
 132.595 +    0xc302,0xc303,0xc304,0xc305,0xc306,0xc307,0xc30a,0xc30b,0xc30e,0xc30f
 132.596 +  },
 132.597 +  {				/* ku 1b */
 132.598 +    0xc310,0xc311,0xc312,0xc316,0xc317,0xc319,0xc31a,0xc31b,0xc31d,0xc31e,
 132.599 +    0xc31f,0xc320,0xc321,0xc322,0xc323,0xc326,0xc327,0xc32a,0xc32b,0xc32c,
 132.600 +    0xc32d,0xc32e,0xc32f,0xc330,0xc331,0xc332,UBOGON,UBOGON,UBOGON,UBOGON,
 132.601 +    UBOGON,UBOGON,0xc333,0xc334,0xc335,0xc336,0xc337,0xc338,0xc339,0xc33a,
 132.602 +    0xc33b,0xc33c,0xc33d,0xc33e,0xc33f,0xc340,0xc341,0xc342,0xc343,0xc344,
 132.603 +    0xc346,0xc347,0xc348,0xc349,0xc34a,0xc34b,0xc34c,0xc34d,UBOGON,UBOGON,
 132.604 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc34e,0xc34f,0xc350,0xc351,0xc352,0xc353,
 132.605 +    0xc354,0xc355,0xc356,0xc357,0xc358,0xc359,0xc35a,0xc35b,0xc35c,0xc35d,
 132.606 +    0xc35e,0xc35f,0xc360,0xc361,0xc362,0xc363,0xc364,0xc365,0xc366,0xc367,
 132.607 +    0xc36a,0xc36b,0xc36d,0xc36e,0xc36f,0xc371,0xc373,0xc374,0xc375,0xc376,
 132.608 +    0xc377,0xc37a,0xc37b,0xc37e,0xc37f,0xc380,0xc381,0xc382,0xc383,0xc385,
 132.609 +    0xc386,0xc387,0xc389,0xc38a,0xc38b,0xc38d,0xc38e,0xc38f,0xc390,0xc391,
 132.610 +    0xc392,0xc393,0xc394,0xc395,0xc396,0xc397,0xc398,0xc399,0xc39a,0xc39b,
 132.611 +    0xc39c,0xc39d,0xc39e,0xc39f,0xc3a0,0xc3a1,0xc3a2,0xc3a3,0xc3a4,0xc3a5,
 132.612 +    0xc3a6,0xc3a7,0xc3a8,0xc3a9,0xc3aa,0xc3ab,0xc3ac,0xc3ad,0xc3ae,0xc3af,
 132.613 +    0xc3b0,0xc3b1,0xc3b2,0xc3b3,0xc3b4,0xc3b5,0xc3b6,0xc3b7,0xc3b8,0xc3b9,
 132.614 +    0xc3ba,0xc3bb,0xc3bc,0xc3bd,0xc3be,0xc3bf,0xc3c1,0xc3c2,0xc3c3,0xc3c4,
 132.615 +    0xc3c5,0xc3c6,0xc3c7,0xc3c8,0xc3c9,0xc3ca,0xc3cb,0xc3cc,0xc3cd,0xc3ce,
 132.616 +    0xc3cf,0xc3d0,0xc3d1,0xc3d2,0xc3d3,0xc3d4,0xc3d5,0xc3d6,0xc3d7,0xc3da
 132.617 +  },
 132.618 +  {				/* ku 1c */
 132.619 +    0xc3db,0xc3dd,0xc3de,0xc3e1,0xc3e3,0xc3e4,0xc3e5,0xc3e6,0xc3e7,0xc3ea,
 132.620 +    0xc3eb,0xc3ec,0xc3ee,0xc3ef,0xc3f0,0xc3f1,0xc3f2,0xc3f3,0xc3f6,0xc3f7,
 132.621 +    0xc3f9,0xc3fa,0xc3fb,0xc3fc,0xc3fd,0xc3fe,UBOGON,UBOGON,UBOGON,UBOGON,
 132.622 +    UBOGON,UBOGON,0xc3ff,0xc400,0xc401,0xc402,0xc403,0xc404,0xc405,0xc406,
 132.623 +    0xc407,0xc409,0xc40a,0xc40b,0xc40c,0xc40d,0xc40e,0xc40f,0xc411,0xc412,
 132.624 +    0xc413,0xc414,0xc415,0xc416,0xc417,0xc418,0xc419,0xc41a,UBOGON,UBOGON,
 132.625 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc41b,0xc41c,0xc41d,0xc41e,0xc41f,0xc420,
 132.626 +    0xc421,0xc422,0xc423,0xc425,0xc426,0xc427,0xc428,0xc429,0xc42a,0xc42b,
 132.627 +    0xc42d,0xc42e,0xc42f,0xc431,0xc432,0xc433,0xc435,0xc436,0xc437,0xc438,
 132.628 +    0xc439,0xc43a,0xc43b,0xc43e,0xc43f,0xc440,0xc441,0xc442,0xc443,0xc444,
 132.629 +    0xc445,0xc446,0xc447,0xc449,0xc44a,0xc44b,0xc44c,0xc44d,0xc44e,0xc44f,
 132.630 +    0xc450,0xc451,0xc452,0xc453,0xc454,0xc455,0xc456,0xc457,0xc458,0xc459,
 132.631 +    0xc45a,0xc45b,0xc45c,0xc45d,0xc45e,0xc45f,0xc460,0xc461,0xc462,0xc463,
 132.632 +    0xc466,0xc467,0xc469,0xc46a,0xc46b,0xc46d,0xc46e,0xc46f,0xc470,0xc471,
 132.633 +    0xc472,0xc473,0xc476,0xc477,0xc478,0xc47a,0xc47b,0xc47c,0xc47d,0xc47e,
 132.634 +    0xc47f,0xc481,0xc482,0xc483,0xc484,0xc485,0xc486,0xc487,0xc488,0xc489,
 132.635 +    0xc48a,0xc48b,0xc48c,0xc48d,0xc48e,0xc48f,0xc490,0xc491,0xc492,0xc493,
 132.636 +    0xc495,0xc496,0xc497,0xc498,0xc499,0xc49a,0xc49b,0xc49d,0xc49e,0xc49f,
 132.637 +    0xc4a0,0xc4a1,0xc4a2,0xc4a3,0xc4a4,0xc4a5,0xc4a6,0xc4a7,0xc4a8,0xc4a9
 132.638 +  },
 132.639 +  {				/* ku 1d */
 132.640 +    0xc4aa,0xc4ab,0xc4ac,0xc4ad,0xc4ae,0xc4af,0xc4b0,0xc4b1,0xc4b2,0xc4b3,
 132.641 +    0xc4b4,0xc4b5,0xc4b6,0xc4b7,0xc4b9,0xc4ba,0xc4bb,0xc4bd,0xc4be,0xc4bf,
 132.642 +    0xc4c0,0xc4c1,0xc4c2,0xc4c3,0xc4c4,0xc4c5,UBOGON,UBOGON,UBOGON,UBOGON,
 132.643 +    UBOGON,UBOGON,0xc4c6,0xc4c7,0xc4c8,0xc4c9,0xc4ca,0xc4cb,0xc4cc,0xc4cd,
 132.644 +    0xc4ce,0xc4cf,0xc4d0,0xc4d1,0xc4d2,0xc4d3,0xc4d4,0xc4d5,0xc4d6,0xc4d7,
 132.645 +    0xc4d8,0xc4d9,0xc4da,0xc4db,0xc4dc,0xc4dd,0xc4de,0xc4df,UBOGON,UBOGON,
 132.646 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc4e0,0xc4e1,0xc4e2,0xc4e3,0xc4e4,0xc4e5,
 132.647 +    0xc4e6,0xc4e7,0xc4e8,0xc4ea,0xc4eb,0xc4ec,0xc4ed,0xc4ee,0xc4ef,0xc4f2,
 132.648 +    0xc4f3,0xc4f5,0xc4f6,0xc4f7,0xc4f9,0xc4fb,0xc4fc,0xc4fd,0xc4fe,0xc502,
 132.649 +    0xc503,0xc504,0xc505,0xc506,0xc507,0xc508,0xc509,0xc50a,0xc50b,0xc50d,
 132.650 +    0xc50e,0xc50f,0xc511,0xc512,0xc513,0xc515,0xc516,0xc517,0xc518,0xc519,
 132.651 +    0xc51a,0xc51b,0xc51d,0xc51e,0xc51f,0xc520,0xc521,0xc522,0xc523,0xc524,
 132.652 +    0xc525,0xc526,0xc527,0xc52a,0xc52b,0xc52d,0xc52e,0xc52f,0xc531,0xc532,
 132.653 +    0xc533,0xc534,0xc535,0xc536,0xc537,0xc53a,0xc53c,0xc53e,0xc53f,0xc540,
 132.654 +    0xc541,0xc542,0xc543,0xc546,0xc547,0xc54b,0xc54f,0xc550,0xc551,0xc552,
 132.655 +    0xc556,0xc55a,0xc55b,0xc55c,0xc55f,0xc562,0xc563,0xc565,0xc566,0xc567,
 132.656 +    0xc569,0xc56a,0xc56b,0xc56c,0xc56d,0xc56e,0xc56f,0xc572,0xc576,0xc577,
 132.657 +    0xc578,0xc579,0xc57a,0xc57b,0xc57e,0xc57f,0xc581,0xc582,0xc583,0xc585,
 132.658 +    0xc586,0xc588,0xc589,0xc58a,0xc58b,0xc58e,0xc590,0xc592,0xc593,0xc594
 132.659 +  },
 132.660 +  {				/* ku 1e */
 132.661 +    0xc596,0xc599,0xc59a,0xc59b,0xc59d,0xc59e,0xc59f,0xc5a1,0xc5a2,0xc5a3,
 132.662 +    0xc5a4,0xc5a5,0xc5a6,0xc5a7,0xc5a8,0xc5aa,0xc5ab,0xc5ac,0xc5ad,0xc5ae,
 132.663 +    0xc5af,0xc5b0,0xc5b1,0xc5b2,0xc5b3,0xc5b6,UBOGON,UBOGON,UBOGON,UBOGON,
 132.664 +    UBOGON,UBOGON,0xc5b7,0xc5ba,0xc5bf,0xc5c0,0xc5c1,0xc5c2,0xc5c3,0xc5cb,
 132.665 +    0xc5cd,0xc5cf,0xc5d2,0xc5d3,0xc5d5,0xc5d6,0xc5d7,0xc5d9,0xc5da,0xc5db,
 132.666 +    0xc5dc,0xc5dd,0xc5de,0xc5df,0xc5e2,0xc5e4,0xc5e6,0xc5e7,UBOGON,UBOGON,
 132.667 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc5e8,0xc5e9,0xc5ea,0xc5eb,0xc5ef,0xc5f1,
 132.668 +    0xc5f2,0xc5f3,0xc5f5,0xc5f8,0xc5f9,0xc5fa,0xc5fb,0xc602,0xc603,0xc604,
 132.669 +    0xc609,0xc60a,0xc60b,0xc60d,0xc60e,0xc60f,0xc611,0xc612,0xc613,0xc614,
 132.670 +    0xc615,0xc616,0xc617,0xc61a,0xc61d,0xc61e,0xc61f,0xc620,0xc621,0xc622,
 132.671 +    0xc623,0xc626,0xc627,0xc629,0xc62a,0xc62b,0xc62f,0xc631,0xc632,0xc636,
 132.672 +    0xc638,0xc63a,0xc63c,0xc63d,0xc63e,0xc63f,0xc642,0xc643,0xc645,0xc646,
 132.673 +    0xc647,0xc649,0xc64a,0xc64b,0xc64c,0xc64d,0xc64e,0xc64f,0xc652,0xc656,
 132.674 +    0xc657,0xc658,0xc659,0xc65a,0xc65b,0xc65e,0xc65f,0xc661,0xc662,0xc663,
 132.675 +    0xc664,0xc665,0xc666,0xc667,0xc668,0xc669,0xc66a,0xc66b,0xc66d,0xc66e,
 132.676 +    0xc670,0xc672,0xc673,0xc674,0xc675,0xc676,0xc677,0xc67a,0xc67b,0xc67d,
 132.677 +    0xc67e,0xc67f,0xc681,0xc682,0xc683,0xc684,0xc685,0xc686,0xc687,0xc68a,
 132.678 +    0xc68c,0xc68e,0xc68f,0xc690,0xc691,0xc692,0xc693,0xc696,0xc697,0xc699,
 132.679 +    0xc69a,0xc69b,0xc69d,0xc69e,0xc69f,0xc6a0,0xc6a1,0xc6a2,0xc6a3,0xc6a6
 132.680 +  },
 132.681 +  {				/* ku 1f */
 132.682 +    0xc6a8,0xc6aa,0xc6ab,0xc6ac,0xc6ad,0xc6ae,0xc6af,0xc6b2,0xc6b3,0xc6b5,
 132.683 +    0xc6b6,0xc6b7,0xc6bb,0xc6bc,0xc6bd,0xc6be,0xc6bf,0xc6c2,0xc6c4,0xc6c6,
 132.684 +    0xc6c7,0xc6c8,0xc6c9,0xc6ca,0xc6cb,0xc6ce,UBOGON,UBOGON,UBOGON,UBOGON,
 132.685 +    UBOGON,UBOGON,0xc6cf,0xc6d1,0xc6d2,0xc6d3,0xc6d5,0xc6d6,0xc6d7,0xc6d8,
 132.686 +    0xc6d9,0xc6da,0xc6db,0xc6de,0xc6df,0xc6e2,0xc6e3,0xc6e4,0xc6e5,0xc6e6,
 132.687 +    0xc6e7,0xc6ea,0xc6eb,0xc6ed,0xc6ee,0xc6ef,0xc6f1,0xc6f2,UBOGON,UBOGON,
 132.688 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc6f3,0xc6f4,0xc6f5,0xc6f6,0xc6f7,0xc6fa,
 132.689 +    0xc6fb,0xc6fc,0xc6fe,0xc6ff,0xc700,0xc701,0xc702,0xc703,0xc706,0xc707,
 132.690 +    0xc709,0xc70a,0xc70b,0xc70d,0xc70e,0xc70f,0xc710,0xc711,0xc712,0xc713,
 132.691 +    0xc716,0xc718,0xc71a,0xc71b,0xc71c,0xc71d,0xc71e,0xc71f,0xc722,0xc723,
 132.692 +    0xc725,0xc726,0xc727,0xc729,0xc72a,0xc72b,0xc72c,0xc72d,0xc72e,0xc72f,
 132.693 +    0xc732,0xc734,0xc736,0xc738,0xc739,0xc73a,0xc73b,0xc73e,0xc73f,0xc741,
 132.694 +    0xc742,0xc743,0xc745,0xc746,0xc747,0xc748,0xc749,0xc74b,0xc74e,0xc750,
 132.695 +    0xc759,0xc75a,0xc75b,0xc75d,0xc75e,0xc75f,0xc761,0xc762,0xc763,0xc764,
 132.696 +    0xc765,0xc766,0xc767,0xc769,0xc76a,0xc76c,0xc76d,0xc76e,0xc76f,0xc770,
 132.697 +    0xc771,0xc772,0xc773,0xc776,0xc777,0xc779,0xc77a,0xc77b,0xc77f,0xc780,
 132.698 +    0xc781,0xc782,0xc786,0xc78b,0xc78c,0xc78d,0xc78f,0xc792,0xc793,0xc795,
 132.699 +    0xc799,0xc79b,0xc79c,0xc79d,0xc79e,0xc79f,0xc7a2,0xc7a7,0xc7a8,0xc7a9,
 132.700 +    0xc7aa,0xc7ab,0xc7ae,0xc7af,0xc7b1,0xc7b2,0xc7b3,0xc7b5,0xc7b6,0xc7b7
 132.701 +  },
 132.702 +  {				/* ku 20 */
 132.703 +    0xc7b8,0xc7b9,0xc7ba,0xc7bb,0xc7be,0xc7c2,0xc7c3,0xc7c4,0xc7c5,0xc7c6,
 132.704 +    0xc7c7,0xc7ca,0xc7cb,0xc7cd,0xc7cf,0xc7d1,0xc7d2,0xc7d3,0xc7d4,0xc7d5,
 132.705 +    0xc7d6,0xc7d7,0xc7d9,0xc7da,0xc7db,0xc7dc,UBOGON,UBOGON,UBOGON,UBOGON,
 132.706 +    UBOGON,UBOGON,0xc7de,0xc7df,0xc7e0,0xc7e1,0xc7e2,0xc7e3,0xc7e5,0xc7e6,
 132.707 +    0xc7e7,0xc7e9,0xc7ea,0xc7eb,0xc7ed,0xc7ee,0xc7ef,0xc7f0,0xc7f1,0xc7f2,
 132.708 +    0xc7f3,0xc7f4,0xc7f5,0xc7f6,0xc7f7,0xc7f8,0xc7f9,0xc7fa,UBOGON,UBOGON,
 132.709 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc7fb,0xc7fc,0xc7fd,0xc7fe,0xc7ff,0xc802,
 132.710 +    0xc803,0xc805,0xc806,0xc807,0xc809,0xc80b,0xc80c,0xc80d,0xc80e,0xc80f,
 132.711 +    0xc812,0xc814,0xc817,0xc818,0xc819,0xc81a,0xc81b,0xc81e,0xc81f,0xc821,
 132.712 +    0xc822,0xc823,0xc825,0xc826,0xc827,0xc828,0xc829,0xc82a,0xc82b,0xc82e,
 132.713 +    0xc830,0xc832,0xc833,0xc834,0xc835,0xc836,0xc837,0xc839,0xc83a,0xc83b,
 132.714 +    0xc83d,0xc83e,0xc83f,0xc841,0xc842,0xc843,0xc844,0xc845,0xc846,0xc847,
 132.715 +    0xc84a,0xc84b,0xc84e,0xc84f,0xc850,0xc851,0xc852,0xc853,0xc855,0xc856,
 132.716 +    0xc857,0xc858,0xc859,0xc85a,0xc85b,0xc85c,0xc85d,0xc85e,0xc85f,0xc860,
 132.717 +    0xc861,0xc862,0xc863,0xc864,0xc865,0xc866,0xc867,0xc868,0xc869,0xc86a,
 132.718 +    0xc86b,0xc86c,0xc86d,0xc86e,0xc86f,0xc872,0xc873,0xc875,0xc876,0xc877,
 132.719 +    0xc879,0xc87b,0xc87c,0xc87d,0xc87e,0xc87f,0xc882,0xc884,0xc888,0xc889,
 132.720 +    0xc88a,0xc88e,0xc88f,0xc890,0xc891,0xc892,0xc893,0xc895,0xc896,0xc897,
 132.721 +    0xc898,0xc899,0xc89a,0xc89b,0xc89c,0xc89e,0xc8a0,0xc8a2,0xc8a3,0xc8a4
 132.722 +  },
 132.723 +  {				/* ku 21 */
 132.724 +    0xc8a5,0xc8a6,0xc8a7,0xc8a9,0xc8aa,0xc8ab,0xc8ac,0xc8ad,0xc8ae,0xc8af,
 132.725 +    0xc8b0,0xc8b1,0xc8b2,0xc8b3,0xc8b4,0xc8b5,0xc8b6,0xc8b7,0xc8b8,0xc8b9,
 132.726 +    0xc8ba,0xc8bb,0xc8be,0xc8bf,0xc8c0,0xc8c1,UBOGON,UBOGON,UBOGON,UBOGON,
 132.727 +    UBOGON,UBOGON,0xc8c2,0xc8c3,0xc8c5,0xc8c6,0xc8c7,0xc8c9,0xc8ca,0xc8cb,
 132.728 +    0xc8cd,0xc8ce,0xc8cf,0xc8d0,0xc8d1,0xc8d2,0xc8d3,0xc8d6,0xc8d8,0xc8da,
 132.729 +    0xc8db,0xc8dc,0xc8dd,0xc8de,0xc8df,0xc8e2,0xc8e3,0xc8e5,UBOGON,UBOGON,
 132.730 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc8e6,0xc8e7,0xc8e8,0xc8e9,0xc8ea,0xc8eb,
 132.731 +    0xc8ec,0xc8ed,0xc8ee,0xc8ef,0xc8f0,0xc8f1,0xc8f2,0xc8f3,0xc8f4,0xc8f6,
 132.732 +    0xc8f7,0xc8f8,0xc8f9,0xc8fa,0xc8fb,0xc8fe,0xc8ff,0xc901,0xc902,0xc903,
 132.733 +    0xc907,0xc908,0xc909,0xc90a,0xc90b,0xc90e,0x3000,0x3001,0x3002,0x00b7,
 132.734 +    0x2025,0x2026,0x00a8,0x3003,0x00ad,0x2015,0x2225,0xff3c,0x223c,0x2018,
 132.735 +    0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,0x3009,0x300a,0x300b,0x300c,
 132.736 +    0x300d,0x300e,0x300f,0x3010,0x3011,0x00b1,0x00d7,0x00f7,0x2260,0x2264,
 132.737 +    0x2265,0x221e,0x2234,0x00b0,0x2032,0x2033,0x2103,0x212b,0xffe0,0xffe1,
 132.738 +    0xffe5,0x2642,0x2640,0x2220,0x22a5,0x2312,0x2202,0x2207,0x2261,0x2252,
 132.739 +    0x00a7,0x203b,0x2606,0x2605,0x25cb,0x25cf,0x25ce,0x25c7,0x25c6,0x25a1,
 132.740 +    0x25a0,0x25b3,0x25b2,0x25bd,0x25bc,0x2192,0x2190,0x2191,0x2193,0x2194,
 132.741 +    0x3013,0x226a,0x226b,0x221a,0x223d,0x221d,0x2235,0x222b,0x222c,0x2208,
 132.742 +    0x220b,0x2286,0x2287,0x2282,0x2283,0x222a,0x2229,0x2227,0x2228,0xffe2
 132.743 +  },
 132.744 +  {				/* ku 22 */
 132.745 +    0xc910,0xc912,0xc913,0xc914,0xc915,0xc916,0xc917,0xc919,0xc91a,0xc91b,
 132.746 +    0xc91c,0xc91d,0xc91e,0xc91f,0xc920,0xc921,0xc922,0xc923,0xc924,0xc925,
 132.747 +    0xc926,0xc927,0xc928,0xc929,0xc92a,0xc92b,UBOGON,UBOGON,UBOGON,UBOGON,
 132.748 +    UBOGON,UBOGON,0xc92d,0xc92e,0xc92f,0xc930,0xc931,0xc932,0xc933,0xc935,
 132.749 +    0xc936,0xc937,0xc938,0xc939,0xc93a,0xc93b,0xc93c,0xc93d,0xc93e,0xc93f,
 132.750 +    0xc940,0xc941,0xc942,0xc943,0xc944,0xc945,0xc946,0xc947,UBOGON,UBOGON,
 132.751 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc948,0xc949,0xc94a,0xc94b,0xc94c,0xc94d,
 132.752 +    0xc94e,0xc94f,0xc952,0xc953,0xc955,0xc956,0xc957,0xc959,0xc95a,0xc95b,
 132.753 +    0xc95c,0xc95d,0xc95e,0xc95f,0xc962,0xc964,0xc965,0xc966,0xc967,0xc968,
 132.754 +    0xc969,0xc96a,0xc96b,0xc96d,0xc96e,0xc96f,0x21d2,0x21d4,0x2200,0x2203,
 132.755 +    0x00b4,0xff5e,0x02c7,0x02d8,0x02dd,0x02da,0x02d9,0x00b8,0x02db,0x00a1,
 132.756 +    0x00bf,0x02d0,0x222e,0x2211,0x220f,0x00a4,0x2109,0x2030,0x25c1,0x25c0,
 132.757 +    0x25b7,0x25b6,0x2664,0x2660,0x2661,0x2665,0x2667,0x2663,0x2299,0x25c8,
 132.758 +    0x25a3,0x25d0,0x25d1,0x2592,0x25a4,0x25a5,0x25a8,0x25a7,0x25a6,0x25a9,
 132.759 +    0x2668,0x260f,0x260e,0x261c,0x261e,0x00b6,0x2020,0x2021,0x2195,0x2197,
 132.760 +    0x2199,0x2196,0x2198,0x266d,0x2669,0x266a,0x266c,0x327f,0x321c,0x2116,
 132.761 +    0x33c7,0x2122,0x33c2,0x33d8,0x2121,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.762 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.763 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.764 +  },
 132.765 +  {				/* ku 23 */
 132.766 +    0xc971,0xc972,0xc973,0xc975,0xc976,0xc977,0xc978,0xc979,0xc97a,0xc97b,
 132.767 +    0xc97d,0xc97e,0xc97f,0xc980,0xc981,0xc982,0xc983,0xc984,0xc985,0xc986,
 132.768 +    0xc987,0xc98a,0xc98b,0xc98d,0xc98e,0xc98f,UBOGON,UBOGON,UBOGON,UBOGON,
 132.769 +    UBOGON,UBOGON,0xc991,0xc992,0xc993,0xc994,0xc995,0xc996,0xc997,0xc99a,
 132.770 +    0xc99c,0xc99e,0xc99f,0xc9a0,0xc9a1,0xc9a2,0xc9a3,0xc9a4,0xc9a5,0xc9a6,
 132.771 +    0xc9a7,0xc9a8,0xc9a9,0xc9aa,0xc9ab,0xc9ac,0xc9ad,0xc9ae,UBOGON,UBOGON,
 132.772 +    UBOGON,UBOGON,UBOGON,UBOGON,0xc9af,0xc9b0,0xc9b1,0xc9b2,0xc9b3,0xc9b4,
 132.773 +    0xc9b5,0xc9b6,0xc9b7,0xc9b8,0xc9b9,0xc9ba,0xc9bb,0xc9bc,0xc9bd,0xc9be,
 132.774 +    0xc9bf,0xc9c2,0xc9c3,0xc9c5,0xc9c6,0xc9c9,0xc9cb,0xc9cc,0xc9cd,0xc9ce,
 132.775 +    0xc9cf,0xc9d2,0xc9d4,0xc9d7,0xc9d8,0xc9db,0xff01,0xff02,0xff03,0xff04,
 132.776 +    0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,
 132.777 +    0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,
 132.778 +    0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21,0xff22,
 132.779 +    0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,
 132.780 +    0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,
 132.781 +    0xff37,0xff38,0xff39,0xff3a,0xff3b,0xffe6,0xff3d,0xff3e,0xff3f,0xff40,
 132.782 +    0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,
 132.783 +    0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,
 132.784 +    0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xffe3
 132.785 +  },
 132.786 +  {				/* ku 24 */
 132.787 +    0xc9de,0xc9df,0xc9e1,0xc9e3,0xc9e5,0xc9e6,0xc9e8,0xc9e9,0xc9ea,0xc9eb,
 132.788 +    0xc9ee,0xc9f2,0xc9f3,0xc9f4,0xc9f5,0xc9f6,0xc9f7,0xc9fa,0xc9fb,0xc9fd,
 132.789 +    0xc9fe,0xc9ff,0xca01,0xca02,0xca03,0xca04,UBOGON,UBOGON,UBOGON,UBOGON,
 132.790 +    UBOGON,UBOGON,0xca05,0xca06,0xca07,0xca0a,0xca0e,0xca0f,0xca10,0xca11,
 132.791 +    0xca12,0xca13,0xca15,0xca16,0xca17,0xca19,0xca1a,0xca1b,0xca1c,0xca1d,
 132.792 +    0xca1e,0xca1f,0xca20,0xca21,0xca22,0xca23,0xca24,0xca25,UBOGON,UBOGON,
 132.793 +    UBOGON,UBOGON,UBOGON,UBOGON,0xca26,0xca27,0xca28,0xca2a,0xca2b,0xca2c,
 132.794 +    0xca2d,0xca2e,0xca2f,0xca30,0xca31,0xca32,0xca33,0xca34,0xca35,0xca36,
 132.795 +    0xca37,0xca38,0xca39,0xca3a,0xca3b,0xca3c,0xca3d,0xca3e,0xca3f,0xca40,
 132.796 +    0xca41,0xca42,0xca43,0xca44,0xca45,0xca46,0x3131,0x3132,0x3133,0x3134,
 132.797 +    0x3135,0x3136,0x3137,0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,
 132.798 +    0x313f,0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,0x3148,
 132.799 +    0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x314f,0x3150,0x3151,0x3152,
 132.800 +    0x3153,0x3154,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,0x315b,0x315c,
 132.801 +    0x315d,0x315e,0x315f,0x3160,0x3161,0x3162,0x3163,0x3164,0x3165,0x3166,
 132.802 +    0x3167,0x3168,0x3169,0x316a,0x316b,0x316c,0x316d,0x316e,0x316f,0x3170,
 132.803 +    0x3171,0x3172,0x3173,0x3174,0x3175,0x3176,0x3177,0x3178,0x3179,0x317a,
 132.804 +    0x317b,0x317c,0x317d,0x317e,0x317f,0x3180,0x3181,0x3182,0x3183,0x3184,
 132.805 +    0x3185,0x3186,0x3187,0x3188,0x3189,0x318a,0x318b,0x318c,0x318d,0x318e
 132.806 +  },
 132.807 +  {				/* ku 25 */
 132.808 +    0xca47,0xca48,0xca49,0xca4a,0xca4b,0xca4e,0xca4f,0xca51,0xca52,0xca53,
 132.809 +    0xca55,0xca56,0xca57,0xca58,0xca59,0xca5a,0xca5b,0xca5e,0xca62,0xca63,
 132.810 +    0xca64,0xca65,0xca66,0xca67,0xca69,0xca6a,UBOGON,UBOGON,UBOGON,UBOGON,
 132.811 +    UBOGON,UBOGON,0xca6b,0xca6c,0xca6d,0xca6e,0xca6f,0xca70,0xca71,0xca72,
 132.812 +    0xca73,0xca74,0xca75,0xca76,0xca77,0xca78,0xca79,0xca7a,0xca7b,0xca7c,
 132.813 +    0xca7e,0xca7f,0xca80,0xca81,0xca82,0xca83,0xca85,0xca86,UBOGON,UBOGON,
 132.814 +    UBOGON,UBOGON,UBOGON,UBOGON,0xca87,0xca88,0xca89,0xca8a,0xca8b,0xca8c,
 132.815 +    0xca8d,0xca8e,0xca8f,0xca90,0xca91,0xca92,0xca93,0xca94,0xca95,0xca96,
 132.816 +    0xca97,0xca99,0xca9a,0xca9b,0xca9c,0xca9d,0xca9e,0xca9f,0xcaa0,0xcaa1,
 132.817 +    0xcaa2,0xcaa3,0xcaa4,0xcaa5,0xcaa6,0xcaa7,0x2170,0x2171,0x2172,0x2173,
 132.818 +    0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,UBOGON,UBOGON,UBOGON,UBOGON,
 132.819 +    UBOGON,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,
 132.820 +    0x2169,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0391,0x0392,
 132.821 +    0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,
 132.822 +    0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
 132.823 +    0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.824 +    0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,
 132.825 +    0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,
 132.826 +    0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.827 +  },
 132.828 +  {				/* ku 26 */
 132.829 +    0xcaa8,0xcaa9,0xcaaa,0xcaab,0xcaac,0xcaad,0xcaae,0xcaaf,0xcab0,0xcab1,
 132.830 +    0xcab2,0xcab3,0xcab4,0xcab5,0xcab6,0xcab7,0xcab8,0xcab9,0xcaba,0xcabb,
 132.831 +    0xcabe,0xcabf,0xcac1,0xcac2,0xcac3,0xcac5,UBOGON,UBOGON,UBOGON,UBOGON,
 132.832 +    UBOGON,UBOGON,0xcac6,0xcac7,0xcac8,0xcac9,0xcaca,0xcacb,0xcace,0xcad0,
 132.833 +    0xcad2,0xcad4,0xcad5,0xcad6,0xcad7,0xcada,0xcadb,0xcadc,0xcadd,0xcade,
 132.834 +    0xcadf,0xcae1,0xcae2,0xcae3,0xcae4,0xcae5,0xcae6,0xcae7,UBOGON,UBOGON,
 132.835 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcae8,0xcae9,0xcaea,0xcaeb,0xcaed,0xcaee,
 132.836 +    0xcaef,0xcaf0,0xcaf1,0xcaf2,0xcaf3,0xcaf5,0xcaf6,0xcaf7,0xcaf8,0xcaf9,
 132.837 +    0xcafa,0xcafb,0xcafc,0xcafd,0xcafe,0xcaff,0xcb00,0xcb01,0xcb02,0xcb03,
 132.838 +    0xcb04,0xcb05,0xcb06,0xcb07,0xcb09,0xcb0a,0x2500,0x2502,0x250c,0x2510,
 132.839 +    0x2518,0x2514,0x251c,0x252c,0x2524,0x2534,0x253c,0x2501,0x2503,0x250f,
 132.840 +    0x2513,0x251b,0x2517,0x2523,0x2533,0x252b,0x253b,0x254b,0x2520,0x252f,
 132.841 +    0x2528,0x2537,0x253f,0x251d,0x2530,0x2525,0x2538,0x2542,0x2512,0x2511,
 132.842 +    0x251a,0x2519,0x2516,0x2515,0x250e,0x250d,0x251e,0x251f,0x2521,0x2522,
 132.843 +    0x2526,0x2527,0x2529,0x252a,0x252d,0x252e,0x2531,0x2532,0x2535,0x2536,
 132.844 +    0x2539,0x253a,0x253d,0x253e,0x2540,0x2541,0x2543,0x2544,0x2545,0x2546,
 132.845 +    0x2547,0x2548,0x2549,0x254a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.846 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.847 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.848 +  },
 132.849 +  {				/* ku 27 */
 132.850 +    0xcb0b,0xcb0c,0xcb0d,0xcb0e,0xcb0f,0xcb11,0xcb12,0xcb13,0xcb15,0xcb16,
 132.851 +    0xcb17,0xcb19,0xcb1a,0xcb1b,0xcb1c,0xcb1d,0xcb1e,0xcb1f,0xcb22,0xcb23,
 132.852 +    0xcb24,0xcb25,0xcb26,0xcb27,0xcb28,0xcb29,UBOGON,UBOGON,UBOGON,UBOGON,
 132.853 +    UBOGON,UBOGON,0xcb2a,0xcb2b,0xcb2c,0xcb2d,0xcb2e,0xcb2f,0xcb30,0xcb31,
 132.854 +    0xcb32,0xcb33,0xcb34,0xcb35,0xcb36,0xcb37,0xcb38,0xcb39,0xcb3a,0xcb3b,
 132.855 +    0xcb3c,0xcb3d,0xcb3e,0xcb3f,0xcb40,0xcb42,0xcb43,0xcb44,UBOGON,UBOGON,
 132.856 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcb45,0xcb46,0xcb47,0xcb4a,0xcb4b,0xcb4d,
 132.857 +    0xcb4e,0xcb4f,0xcb51,0xcb52,0xcb53,0xcb54,0xcb55,0xcb56,0xcb57,0xcb5a,
 132.858 +    0xcb5b,0xcb5c,0xcb5e,0xcb5f,0xcb60,0xcb61,0xcb62,0xcb63,0xcb65,0xcb66,
 132.859 +    0xcb67,0xcb68,0xcb69,0xcb6a,0xcb6b,0xcb6c,0x3395,0x3396,0x3397,0x2113,
 132.860 +    0x3398,0x33c4,0x33a3,0x33a4,0x33a5,0x33a6,0x3399,0x339a,0x339b,0x339c,
 132.861 +    0x339d,0x339e,0x339f,0x33a0,0x33a1,0x33a2,0x33ca,0x338d,0x338e,0x338f,
 132.862 +    0x33cf,0x3388,0x3389,0x33c8,0x33a7,0x33a8,0x33b0,0x33b1,0x33b2,0x33b3,
 132.863 +    0x33b4,0x33b5,0x33b6,0x33b7,0x33b8,0x33b9,0x3380,0x3381,0x3382,0x3383,
 132.864 +    0x3384,0x33ba,0x33bb,0x33bc,0x33bd,0x33be,0x33bf,0x3390,0x3391,0x3392,
 132.865 +    0x3393,0x3394,0x2126,0x33c0,0x33c1,0x338a,0x338b,0x338c,0x33d6,0x33c5,
 132.866 +    0x33ad,0x33ae,0x33af,0x33db,0x33a9,0x33aa,0x33ab,0x33ac,0x33dd,0x33d0,
 132.867 +    0x33d3,0x33c3,0x33c9,0x33dc,0x33c6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.868 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.869 +  },
 132.870 +  {				/* ku 28 */
 132.871 +    0xcb6d,0xcb6e,0xcb6f,0xcb70,0xcb71,0xcb72,0xcb73,0xcb74,0xcb75,0xcb76,
 132.872 +    0xcb77,0xcb7a,0xcb7b,0xcb7c,0xcb7d,0xcb7e,0xcb7f,0xcb80,0xcb81,0xcb82,
 132.873 +    0xcb83,0xcb84,0xcb85,0xcb86,0xcb87,0xcb88,UBOGON,UBOGON,UBOGON,UBOGON,
 132.874 +    UBOGON,UBOGON,0xcb89,0xcb8a,0xcb8b,0xcb8c,0xcb8d,0xcb8e,0xcb8f,0xcb90,
 132.875 +    0xcb91,0xcb92,0xcb93,0xcb94,0xcb95,0xcb96,0xcb97,0xcb98,0xcb99,0xcb9a,
 132.876 +    0xcb9b,0xcb9d,0xcb9e,0xcb9f,0xcba0,0xcba1,0xcba2,0xcba3,UBOGON,UBOGON,
 132.877 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcba4,0xcba5,0xcba6,0xcba7,0xcba8,0xcba9,
 132.878 +    0xcbaa,0xcbab,0xcbac,0xcbad,0xcbae,0xcbaf,0xcbb0,0xcbb1,0xcbb2,0xcbb3,
 132.879 +    0xcbb4,0xcbb5,0xcbb6,0xcbb7,0xcbb9,0xcbba,0xcbbb,0xcbbc,0xcbbd,0xcbbe,
 132.880 +    0xcbbf,0xcbc0,0xcbc1,0xcbc2,0xcbc3,0xcbc4,0x00c6,0x00d0,0x00aa,0x0126,
 132.881 +    UBOGON,0x0132,UBOGON,0x013f,0x0141,0x00d8,0x0152,0x00ba,0x00de,0x0166,
 132.882 +    0x014a,UBOGON,0x3260,0x3261,0x3262,0x3263,0x3264,0x3265,0x3266,0x3267,
 132.883 +    0x3268,0x3269,0x326a,0x326b,0x326c,0x326d,0x326e,0x326f,0x3270,0x3271,
 132.884 +    0x3272,0x3273,0x3274,0x3275,0x3276,0x3277,0x3278,0x3279,0x327a,0x327b,
 132.885 +    0x24d0,0x24d1,0x24d2,0x24d3,0x24d4,0x24d5,0x24d6,0x24d7,0x24d8,0x24d9,
 132.886 +    0x24da,0x24db,0x24dc,0x24dd,0x24de,0x24df,0x24e0,0x24e1,0x24e2,0x24e3,
 132.887 +    0x24e4,0x24e5,0x24e6,0x24e7,0x24e8,0x24e9,0x2460,0x2461,0x2462,0x2463,
 132.888 +    0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,
 132.889 +    0x246e,0x00bd,0x2153,0x2154,0x00bc,0x00be,0x215b,0x215c,0x215d,0x215e
 132.890 +  },
 132.891 +  {				/* ku 29 */
 132.892 +    0xcbc5,0xcbc6,0xcbc7,0xcbc8,0xcbc9,0xcbca,0xcbcb,0xcbcc,0xcbcd,0xcbce,
 132.893 +    0xcbcf,0xcbd0,0xcbd1,0xcbd2,0xcbd3,0xcbd5,0xcbd6,0xcbd7,0xcbd8,0xcbd9,
 132.894 +    0xcbda,0xcbdb,0xcbdc,0xcbdd,0xcbde,0xcbdf,UBOGON,UBOGON,UBOGON,UBOGON,
 132.895 +    UBOGON,UBOGON,0xcbe0,0xcbe1,0xcbe2,0xcbe3,0xcbe5,0xcbe6,0xcbe8,0xcbea,
 132.896 +    0xcbeb,0xcbec,0xcbed,0xcbee,0xcbef,0xcbf0,0xcbf1,0xcbf2,0xcbf3,0xcbf4,
 132.897 +    0xcbf5,0xcbf6,0xcbf7,0xcbf8,0xcbf9,0xcbfa,0xcbfb,0xcbfc,UBOGON,UBOGON,
 132.898 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcbfd,0xcbfe,0xcbff,0xcc00,0xcc01,0xcc02,
 132.899 +    0xcc03,0xcc04,0xcc05,0xcc06,0xcc07,0xcc08,0xcc09,0xcc0a,0xcc0b,0xcc0e,
 132.900 +    0xcc0f,0xcc11,0xcc12,0xcc13,0xcc15,0xcc16,0xcc17,0xcc18,0xcc19,0xcc1a,
 132.901 +    0xcc1b,0xcc1e,0xcc1f,0xcc20,0xcc23,0xcc24,0x00e6,0x0111,0x00f0,0x0127,
 132.902 +    0x0131,0x0133,0x0138,0x0140,0x0142,0x00f8,0x0153,0x00df,0x00fe,0x0167,
 132.903 +    0x014b,0x0149,0x3200,0x3201,0x3202,0x3203,0x3204,0x3205,0x3206,0x3207,
 132.904 +    0x3208,0x3209,0x320a,0x320b,0x320c,0x320d,0x320e,0x320f,0x3210,0x3211,
 132.905 +    0x3212,0x3213,0x3214,0x3215,0x3216,0x3217,0x3218,0x3219,0x321a,0x321b,
 132.906 +    0x249c,0x249d,0x249e,0x249f,0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,
 132.907 +    0x24a6,0x24a7,0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af,
 132.908 +    0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x2474,0x2475,0x2476,0x2477,
 132.909 +    0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,
 132.910 +    0x2482,0x00b9,0x00b2,0x00b3,0x2074,0x207f,0x2081,0x2082,0x2083,0x2084
 132.911 +  },
 132.912 +  {				/* ku 2a */
 132.913 +    0xcc25,0xcc26,0xcc2a,0xcc2b,0xcc2d,0xcc2f,0xcc31,0xcc32,0xcc33,0xcc34,
 132.914 +    0xcc35,0xcc36,0xcc37,0xcc3a,0xcc3f,0xcc40,0xcc41,0xcc42,0xcc43,0xcc46,
 132.915 +    0xcc47,0xcc49,0xcc4a,0xcc4b,0xcc4d,0xcc4e,UBOGON,UBOGON,UBOGON,UBOGON,
 132.916 +    UBOGON,UBOGON,0xcc4f,0xcc50,0xcc51,0xcc52,0xcc53,0xcc56,0xcc5a,0xcc5b,
 132.917 +    0xcc5c,0xcc5d,0xcc5e,0xcc5f,0xcc61,0xcc62,0xcc63,0xcc65,0xcc67,0xcc69,
 132.918 +    0xcc6a,0xcc6b,0xcc6c,0xcc6d,0xcc6e,0xcc6f,0xcc71,0xcc72,UBOGON,UBOGON,
 132.919 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcc73,0xcc74,0xcc76,0xcc77,0xcc78,0xcc79,
 132.920 +    0xcc7a,0xcc7b,0xcc7c,0xcc7d,0xcc7e,0xcc7f,0xcc80,0xcc81,0xcc82,0xcc83,
 132.921 +    0xcc84,0xcc85,0xcc86,0xcc87,0xcc88,0xcc89,0xcc8a,0xcc8b,0xcc8c,0xcc8d,
 132.922 +    0xcc8e,0xcc8f,0xcc90,0xcc91,0xcc92,0xcc93,0x3041,0x3042,0x3043,0x3044,
 132.923 +    0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,
 132.924 +    0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,
 132.925 +    0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062,
 132.926 +    0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c,
 132.927 +    0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,
 132.928 +    0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080,
 132.929 +    0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,
 132.930 +    0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,UBOGON,
 132.931 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.932 +  },
 132.933 +  {				/* ku 2b */
 132.934 +    0xcc94,0xcc95,0xcc96,0xcc97,0xcc9a,0xcc9b,0xcc9d,0xcc9e,0xcc9f,0xcca1,
 132.935 +    0xcca2,0xcca3,0xcca4,0xcca5,0xcca6,0xcca7,0xccaa,0xccae,0xccaf,0xccb0,
 132.936 +    0xccb1,0xccb2,0xccb3,0xccb6,0xccb7,0xccb9,UBOGON,UBOGON,UBOGON,UBOGON,
 132.937 +    UBOGON,UBOGON,0xccba,0xccbb,0xccbd,0xccbe,0xccbf,0xccc0,0xccc1,0xccc2,
 132.938 +    0xccc3,0xccc6,0xccc8,0xccca,0xcccb,0xcccc,0xcccd,0xccce,0xcccf,0xccd1,
 132.939 +    0xccd2,0xccd3,0xccd5,0xccd6,0xccd7,0xccd8,0xccd9,0xccda,UBOGON,UBOGON,
 132.940 +    UBOGON,UBOGON,UBOGON,UBOGON,0xccdb,0xccdc,0xccdd,0xccde,0xccdf,0xcce0,
 132.941 +    0xcce1,0xcce2,0xcce3,0xcce5,0xcce6,0xcce7,0xcce8,0xcce9,0xccea,0xcceb,
 132.942 +    0xcced,0xccee,0xccef,0xccf1,0xccf2,0xccf3,0xccf4,0xccf5,0xccf6,0xccf7,
 132.943 +    0xccf8,0xccf9,0xccfa,0xccfb,0xccfc,0xccfd,0x30a1,0x30a2,0x30a3,0x30a4,
 132.944 +    0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,
 132.945 +    0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8,
 132.946 +    0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,0x30c2,
 132.947 +    0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,
 132.948 +    0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,
 132.949 +    0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,0x30e0,
 132.950 +    0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,0x30e9,0x30ea,
 132.951 +    0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,0x30f3,0x30f4,
 132.952 +    0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.953 +  },
 132.954 +  {				/* ku 2c */
 132.955 +    0xccfe,0xccff,0xcd00,0xcd02,0xcd03,0xcd04,0xcd05,0xcd06,0xcd07,0xcd0a,
 132.956 +    0xcd0b,0xcd0d,0xcd0e,0xcd0f,0xcd11,0xcd12,0xcd13,0xcd14,0xcd15,0xcd16,
 132.957 +    0xcd17,0xcd1a,0xcd1c,0xcd1e,0xcd1f,0xcd20,UBOGON,UBOGON,UBOGON,UBOGON,
 132.958 +    UBOGON,UBOGON,0xcd21,0xcd22,0xcd23,0xcd25,0xcd26,0xcd27,0xcd29,0xcd2a,
 132.959 +    0xcd2b,0xcd2d,0xcd2e,0xcd2f,0xcd30,0xcd31,0xcd32,0xcd33,0xcd34,0xcd35,
 132.960 +    0xcd36,0xcd37,0xcd38,0xcd3a,0xcd3b,0xcd3c,0xcd3d,0xcd3e,UBOGON,UBOGON,
 132.961 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcd3f,0xcd40,0xcd41,0xcd42,0xcd43,0xcd44,
 132.962 +    0xcd45,0xcd46,0xcd47,0xcd48,0xcd49,0xcd4a,0xcd4b,0xcd4c,0xcd4d,0xcd4e,
 132.963 +    0xcd4f,0xcd50,0xcd51,0xcd52,0xcd53,0xcd54,0xcd55,0xcd56,0xcd57,0xcd58,
 132.964 +    0xcd59,0xcd5a,0xcd5b,0xcd5d,0xcd5e,0xcd5f,0x0410,0x0411,0x0412,0x0413,
 132.965 +    0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,
 132.966 +    0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,
 132.967 +    0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,UBOGON,
 132.968 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.969 +    UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,
 132.970 +    0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
 132.971 +    0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448,
 132.972 +    0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,UBOGON,UBOGON,UBOGON,
 132.973 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.974 +  },
 132.975 +  {				/* ku 2d */
 132.976 +    0xcd61,0xcd62,0xcd63,0xcd65,0xcd66,0xcd67,0xcd68,0xcd69,0xcd6a,0xcd6b,
 132.977 +    0xcd6e,0xcd70,0xcd72,0xcd73,0xcd74,0xcd75,0xcd76,0xcd77,0xcd79,0xcd7a,
 132.978 +    0xcd7b,0xcd7c,0xcd7d,0xcd7e,0xcd7f,0xcd80,UBOGON,UBOGON,UBOGON,UBOGON,
 132.979 +    UBOGON,UBOGON,0xcd81,0xcd82,0xcd83,0xcd84,0xcd85,0xcd86,0xcd87,0xcd89,
 132.980 +    0xcd8a,0xcd8b,0xcd8c,0xcd8d,0xcd8e,0xcd8f,0xcd90,0xcd91,0xcd92,0xcd93,
 132.981 +    0xcd96,0xcd97,0xcd99,0xcd9a,0xcd9b,0xcd9d,0xcd9e,0xcd9f,UBOGON,UBOGON,
 132.982 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcda0,0xcda1,0xcda2,0xcda3,0xcda6,0xcda8,
 132.983 +    0xcdaa,0xcdab,0xcdac,0xcdad,0xcdae,0xcdaf,0xcdb1,0xcdb2,0xcdb3,0xcdb4,
 132.984 +    0xcdb5,0xcdb6,0xcdb7,0xcdb8,0xcdb9,0xcdba,0xcdbb,0xcdbc,0xcdbd,0xcdbe,
 132.985 +    0xcdbf,0xcdc0,0xcdc1,0xcdc2,0xcdc3,0xcdc5,UBOGON,UBOGON,UBOGON,UBOGON,
 132.986 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.987 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.988 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.989 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.990 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.991 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.992 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.993 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 132.994 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
 132.995 +  },
 132.996 +  {				/* ku 2e */
 132.997 +    0xcdc6,0xcdc7,0xcdc8,0xcdc9,0xcdca,0xcdcb,0xcdcd,0xcdce,0xcdcf,0xcdd1,
 132.998 +    0xcdd2,0xcdd3,0xcdd4,0xcdd5,0xcdd6,0xcdd7,0xcdd8,0xcdd9,0xcdda,0xcddb,
 132.999 +    0xcddc,0xcddd,0xcdde,0xcddf,0xcde0,0xcde1,UBOGON,UBOGON,UBOGON,UBOGON,
132.1000 +    UBOGON,UBOGON,0xcde2,0xcde3,0xcde4,0xcde5,0xcde6,0xcde7,0xcde9,0xcdea,
132.1001 +    0xcdeb,0xcded,0xcdee,0xcdef,0xcdf1,0xcdf2,0xcdf3,0xcdf4,0xcdf5,0xcdf6,
132.1002 +    0xcdf7,0xcdfa,0xcdfc,0xcdfe,0xcdff,0xce00,0xce01,0xce02,UBOGON,UBOGON,
132.1003 +    UBOGON,UBOGON,UBOGON,UBOGON,0xce03,0xce05,0xce06,0xce07,0xce09,0xce0a,
132.1004 +    0xce0b,0xce0d,0xce0e,0xce0f,0xce10,0xce11,0xce12,0xce13,0xce15,0xce16,
132.1005 +    0xce17,0xce18,0xce1a,0xce1b,0xce1c,0xce1d,0xce1e,0xce1f,0xce22,0xce23,
132.1006 +    0xce25,0xce26,0xce27,0xce29,0xce2a,0xce2b,UBOGON,UBOGON,UBOGON,UBOGON,
132.1007 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1008 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1009 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1010 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1011 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1012 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1013 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1014 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1015 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
132.1016 +  },
132.1017 +  {				/* ku 2f */
132.1018 +    0xce2c,0xce2d,0xce2e,0xce2f,0xce32,0xce34,0xce36,0xce37,0xce38,0xce39,
132.1019 +    0xce3a,0xce3b,0xce3c,0xce3d,0xce3e,0xce3f,0xce40,0xce41,0xce42,0xce43,
132.1020 +    0xce44,0xce45,0xce46,0xce47,0xce48,0xce49,UBOGON,UBOGON,UBOGON,UBOGON,
132.1021 +    UBOGON,UBOGON,0xce4a,0xce4b,0xce4c,0xce4d,0xce4e,0xce4f,0xce50,0xce51,
132.1022 +    0xce52,0xce53,0xce54,0xce55,0xce56,0xce57,0xce5a,0xce5b,0xce5d,0xce5e,
132.1023 +    0xce62,0xce63,0xce64,0xce65,0xce66,0xce67,0xce6a,0xce6c,UBOGON,UBOGON,
132.1024 +    UBOGON,UBOGON,UBOGON,UBOGON,0xce6e,0xce6f,0xce70,0xce71,0xce72,0xce73,
132.1025 +    0xce76,0xce77,0xce79,0xce7a,0xce7b,0xce7d,0xce7e,0xce7f,0xce80,0xce81,
132.1026 +    0xce82,0xce83,0xce86,0xce88,0xce8a,0xce8b,0xce8c,0xce8d,0xce8e,0xce8f,
132.1027 +    0xce92,0xce93,0xce95,0xce96,0xce97,0xce99,UBOGON,UBOGON,UBOGON,UBOGON,
132.1028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1030 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1031 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1032 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1033 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1034 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1035 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1036 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
132.1037 +  },
132.1038 +  {				/* ku 30 */
132.1039 +    0xce9a,0xce9b,0xce9c,0xce9d,0xce9e,0xce9f,0xcea2,0xcea6,0xcea7,0xcea8,
132.1040 +    0xcea9,0xceaa,0xceab,0xceae,0xceaf,0xceb0,0xceb1,0xceb2,0xceb3,0xceb4,
132.1041 +    0xceb5,0xceb6,0xceb7,0xceb8,0xceb9,0xceba,UBOGON,UBOGON,UBOGON,UBOGON,
132.1042 +    UBOGON,UBOGON,0xcebb,0xcebc,0xcebd,0xcebe,0xcebf,0xcec0,0xcec2,0xcec3,
132.1043 +    0xcec4,0xcec5,0xcec6,0xcec7,0xcec8,0xcec9,0xceca,0xcecb,0xcecc,0xcecd,
132.1044 +    0xcece,0xcecf,0xced0,0xced1,0xced2,0xced3,0xced4,0xced5,UBOGON,UBOGON,
132.1045 +    UBOGON,UBOGON,UBOGON,UBOGON,0xced6,0xced7,0xced8,0xced9,0xceda,0xcedb,
132.1046 +    0xcedc,0xcedd,0xcede,0xcedf,0xcee0,0xcee1,0xcee2,0xcee3,0xcee6,0xcee7,
132.1047 +    0xcee9,0xceea,0xceed,0xceee,0xceef,0xcef0,0xcef1,0xcef2,0xcef3,0xcef6,
132.1048 +    0xcefa,0xcefb,0xcefc,0xcefd,0xcefe,0xceff,0xac00,0xac01,0xac04,0xac07,
132.1049 +    0xac08,0xac09,0xac0a,0xac10,0xac11,0xac12,0xac13,0xac14,0xac15,0xac16,
132.1050 +    0xac17,0xac19,0xac1a,0xac1b,0xac1c,0xac1d,0xac20,0xac24,0xac2c,0xac2d,
132.1051 +    0xac2f,0xac30,0xac31,0xac38,0xac39,0xac3c,0xac40,0xac4b,0xac4d,0xac54,
132.1052 +    0xac58,0xac5c,0xac70,0xac71,0xac74,0xac77,0xac78,0xac7a,0xac80,0xac81,
132.1053 +    0xac83,0xac84,0xac85,0xac86,0xac89,0xac8a,0xac8b,0xac8c,0xac90,0xac94,
132.1054 +    0xac9c,0xac9d,0xac9f,0xaca0,0xaca1,0xaca8,0xaca9,0xacaa,0xacac,0xacaf,
132.1055 +    0xacb0,0xacb8,0xacb9,0xacbb,0xacbc,0xacbd,0xacc1,0xacc4,0xacc8,0xaccc,
132.1056 +    0xacd5,0xacd7,0xace0,0xace1,0xace4,0xace7,0xace8,0xacea,0xacec,0xacef,
132.1057 +    0xacf0,0xacf1,0xacf3,0xacf5,0xacf6,0xacfc,0xacfd,0xad00,0xad04,0xad06
132.1058 +  },
132.1059 +  {				/* ku 31 */
132.1060 +    0xcf02,0xcf03,0xcf05,0xcf06,0xcf07,0xcf09,0xcf0a,0xcf0b,0xcf0c,0xcf0d,
132.1061 +    0xcf0e,0xcf0f,0xcf12,0xcf14,0xcf16,0xcf17,0xcf18,0xcf19,0xcf1a,0xcf1b,
132.1062 +    0xcf1d,0xcf1e,0xcf1f,0xcf21,0xcf22,0xcf23,UBOGON,UBOGON,UBOGON,UBOGON,
132.1063 +    UBOGON,UBOGON,0xcf25,0xcf26,0xcf27,0xcf28,0xcf29,0xcf2a,0xcf2b,0xcf2e,
132.1064 +    0xcf32,0xcf33,0xcf34,0xcf35,0xcf36,0xcf37,0xcf39,0xcf3a,0xcf3b,0xcf3c,
132.1065 +    0xcf3d,0xcf3e,0xcf3f,0xcf40,0xcf41,0xcf42,0xcf43,0xcf44,UBOGON,UBOGON,
132.1066 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcf45,0xcf46,0xcf47,0xcf48,0xcf49,0xcf4a,
132.1067 +    0xcf4b,0xcf4c,0xcf4d,0xcf4e,0xcf4f,0xcf50,0xcf51,0xcf52,0xcf53,0xcf56,
132.1068 +    0xcf57,0xcf59,0xcf5a,0xcf5b,0xcf5d,0xcf5e,0xcf5f,0xcf60,0xcf61,0xcf62,
132.1069 +    0xcf63,0xcf66,0xcf68,0xcf6a,0xcf6b,0xcf6c,0xad0c,0xad0d,0xad0f,0xad11,
132.1070 +    0xad18,0xad1c,0xad20,0xad29,0xad2c,0xad2d,0xad34,0xad35,0xad38,0xad3c,
132.1071 +    0xad44,0xad45,0xad47,0xad49,0xad50,0xad54,0xad58,0xad61,0xad63,0xad6c,
132.1072 +    0xad6d,0xad70,0xad73,0xad74,0xad75,0xad76,0xad7b,0xad7c,0xad7d,0xad7f,
132.1073 +    0xad81,0xad82,0xad88,0xad89,0xad8c,0xad90,0xad9c,0xad9d,0xada4,0xadb7,
132.1074 +    0xadc0,0xadc1,0xadc4,0xadc8,0xadd0,0xadd1,0xadd3,0xaddc,0xade0,0xade4,
132.1075 +    0xadf8,0xadf9,0xadfc,0xadff,0xae00,0xae01,0xae08,0xae09,0xae0b,0xae0d,
132.1076 +    0xae14,0xae30,0xae31,0xae34,0xae37,0xae38,0xae3a,0xae40,0xae41,0xae43,
132.1077 +    0xae45,0xae46,0xae4a,0xae4c,0xae4d,0xae4e,0xae50,0xae54,0xae56,0xae5c,
132.1078 +    0xae5d,0xae5f,0xae60,0xae61,0xae65,0xae68,0xae69,0xae6c,0xae70,0xae78
132.1079 +  },
132.1080 +  {				/* ku 32 */
132.1081 +    0xcf6d,0xcf6e,0xcf6f,0xcf72,0xcf73,0xcf75,0xcf76,0xcf77,0xcf79,0xcf7a,
132.1082 +    0xcf7b,0xcf7c,0xcf7d,0xcf7e,0xcf7f,0xcf81,0xcf82,0xcf83,0xcf84,0xcf86,
132.1083 +    0xcf87,0xcf88,0xcf89,0xcf8a,0xcf8b,0xcf8d,UBOGON,UBOGON,UBOGON,UBOGON,
132.1084 +    UBOGON,UBOGON,0xcf8e,0xcf8f,0xcf90,0xcf91,0xcf92,0xcf93,0xcf94,0xcf95,
132.1085 +    0xcf96,0xcf97,0xcf98,0xcf99,0xcf9a,0xcf9b,0xcf9c,0xcf9d,0xcf9e,0xcf9f,
132.1086 +    0xcfa0,0xcfa2,0xcfa3,0xcfa4,0xcfa5,0xcfa6,0xcfa7,0xcfa9,UBOGON,UBOGON,
132.1087 +    UBOGON,UBOGON,UBOGON,UBOGON,0xcfaa,0xcfab,0xcfac,0xcfad,0xcfae,0xcfaf,
132.1088 +    0xcfb1,0xcfb2,0xcfb3,0xcfb4,0xcfb5,0xcfb6,0xcfb7,0xcfb8,0xcfb9,0xcfba,
132.1089 +    0xcfbb,0xcfbc,0xcfbd,0xcfbe,0xcfbf,0xcfc0,0xcfc1,0xcfc2,0xcfc3,0xcfc5,
132.1090 +    0xcfc6,0xcfc7,0xcfc8,0xcfc9,0xcfca,0xcfcb,0xae79,0xae7b,0xae7c,0xae7d,
132.1091 +    0xae84,0xae85,0xae8c,0xaebc,0xaebd,0xaebe,0xaec0,0xaec4,0xaecc,0xaecd,
132.1092 +    0xaecf,0xaed0,0xaed1,0xaed8,0xaed9,0xaedc,0xaee8,0xaeeb,0xaeed,0xaef4,
132.1093 +    0xaef8,0xaefc,0xaf07,0xaf08,0xaf0d,0xaf10,0xaf2c,0xaf2d,0xaf30,0xaf32,
132.1094 +    0xaf34,0xaf3c,0xaf3d,0xaf3f,0xaf41,0xaf42,0xaf43,0xaf48,0xaf49,0xaf50,
132.1095 +    0xaf5c,0xaf5d,0xaf64,0xaf65,0xaf79,0xaf80,0xaf84,0xaf88,0xaf90,0xaf91,
132.1096 +    0xaf95,0xaf9c,0xafb8,0xafb9,0xafbc,0xafc0,0xafc7,0xafc8,0xafc9,0xafcb,
132.1097 +    0xafcd,0xafce,0xafd4,0xafdc,0xafe8,0xafe9,0xaff0,0xaff1,0xaff4,0xaff8,
132.1098 +    0xb000,0xb001,0xb004,0xb00c,0xb010,0xb014,0xb01c,0xb01d,0xb028,0xb044,
132.1099 +    0xb045,0xb048,0xb04a,0xb04c,0xb04e,0xb053,0xb054,0xb055,0xb057,0xb059
132.1100 +  },
132.1101 +  {				/* ku 33 */
132.1102 +    0xcfcc,0xcfcd,0xcfce,0xcfcf,0xcfd0,0xcfd1,0xcfd2,0xcfd3,0xcfd4,0xcfd5,
132.1103 +    0xcfd6,0xcfd7,0xcfd8,0xcfd9,0xcfda,0xcfdb,0xcfdc,0xcfdd,0xcfde,0xcfdf,
132.1104 +    0xcfe2,0xcfe3,0xcfe5,0xcfe6,0xcfe7,0xcfe9,UBOGON,UBOGON,UBOGON,UBOGON,
132.1105 +    UBOGON,UBOGON,0xcfea,0xcfeb,0xcfec,0xcfed,0xcfee,0xcfef,0xcff2,0xcff4,
132.1106 +    0xcff6,0xcff7,0xcff8,0xcff9,0xcffa,0xcffb,0xcffd,0xcffe,0xcfff,0xd001,
132.1107 +    0xd002,0xd003,0xd005,0xd006,0xd007,0xd008,0xd009,0xd00a,UBOGON,UBOGON,
132.1108 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd00b,0xd00c,0xd00d,0xd00e,0xd00f,0xd010,
132.1109 +    0xd012,0xd013,0xd014,0xd015,0xd016,0xd017,0xd019,0xd01a,0xd01b,0xd01c,
132.1110 +    0xd01d,0xd01e,0xd01f,0xd020,0xd021,0xd022,0xd023,0xd024,0xd025,0xd026,
132.1111 +    0xd027,0xd028,0xd029,0xd02a,0xd02b,0xd02c,0xb05d,0xb07c,0xb07d,0xb080,
132.1112 +    0xb084,0xb08c,0xb08d,0xb08f,0xb091,0xb098,0xb099,0xb09a,0xb09c,0xb09f,
132.1113 +    0xb0a0,0xb0a1,0xb0a2,0xb0a8,0xb0a9,0xb0ab,0xb0ac,0xb0ad,0xb0ae,0xb0af,
132.1114 +    0xb0b1,0xb0b3,0xb0b4,0xb0b5,0xb0b8,0xb0bc,0xb0c4,0xb0c5,0xb0c7,0xb0c8,
132.1115 +    0xb0c9,0xb0d0,0xb0d1,0xb0d4,0xb0d8,0xb0e0,0xb0e5,0xb108,0xb109,0xb10b,
132.1116 +    0xb10c,0xb110,0xb112,0xb113,0xb118,0xb119,0xb11b,0xb11c,0xb11d,0xb123,
132.1117 +    0xb124,0xb125,0xb128,0xb12c,0xb134,0xb135,0xb137,0xb138,0xb139,0xb140,
132.1118 +    0xb141,0xb144,0xb148,0xb150,0xb151,0xb154,0xb155,0xb158,0xb15c,0xb160,
132.1119 +    0xb178,0xb179,0xb17c,0xb180,0xb182,0xb188,0xb189,0xb18b,0xb18d,0xb192,
132.1120 +    0xb193,0xb194,0xb198,0xb19c,0xb1a8,0xb1cc,0xb1d0,0xb1d4,0xb1dc,0xb1dd
132.1121 +  },
132.1122 +  {				/* ku 34 */
132.1123 +    0xd02e,0xd02f,0xd030,0xd031,0xd032,0xd033,0xd036,0xd037,0xd039,0xd03a,
132.1124 +    0xd03b,0xd03d,0xd03e,0xd03f,0xd040,0xd041,0xd042,0xd043,0xd046,0xd048,
132.1125 +    0xd04a,0xd04b,0xd04c,0xd04d,0xd04e,0xd04f,UBOGON,UBOGON,UBOGON,UBOGON,
132.1126 +    UBOGON,UBOGON,0xd051,0xd052,0xd053,0xd055,0xd056,0xd057,0xd059,0xd05a,
132.1127 +    0xd05b,0xd05c,0xd05d,0xd05e,0xd05f,0xd061,0xd062,0xd063,0xd064,0xd065,
132.1128 +    0xd066,0xd067,0xd068,0xd069,0xd06a,0xd06b,0xd06e,0xd06f,UBOGON,UBOGON,
132.1129 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd071,0xd072,0xd073,0xd075,0xd076,0xd077,
132.1130 +    0xd078,0xd079,0xd07a,0xd07b,0xd07e,0xd07f,0xd080,0xd082,0xd083,0xd084,
132.1131 +    0xd085,0xd086,0xd087,0xd088,0xd089,0xd08a,0xd08b,0xd08c,0xd08d,0xd08e,
132.1132 +    0xd08f,0xd090,0xd091,0xd092,0xd093,0xd094,0xb1df,0xb1e8,0xb1e9,0xb1ec,
132.1133 +    0xb1f0,0xb1f9,0xb1fb,0xb1fd,0xb204,0xb205,0xb208,0xb20b,0xb20c,0xb214,
132.1134 +    0xb215,0xb217,0xb219,0xb220,0xb234,0xb23c,0xb258,0xb25c,0xb260,0xb268,
132.1135 +    0xb269,0xb274,0xb275,0xb27c,0xb284,0xb285,0xb289,0xb290,0xb291,0xb294,
132.1136 +    0xb298,0xb299,0xb29a,0xb2a0,0xb2a1,0xb2a3,0xb2a5,0xb2a6,0xb2aa,0xb2ac,
132.1137 +    0xb2b0,0xb2b4,0xb2c8,0xb2c9,0xb2cc,0xb2d0,0xb2d2,0xb2d8,0xb2d9,0xb2db,
132.1138 +    0xb2dd,0xb2e2,0xb2e4,0xb2e5,0xb2e6,0xb2e8,0xb2eb,0xb2ec,0xb2ed,0xb2ee,
132.1139 +    0xb2ef,0xb2f3,0xb2f4,0xb2f5,0xb2f7,0xb2f8,0xb2f9,0xb2fa,0xb2fb,0xb2ff,
132.1140 +    0xb300,0xb301,0xb304,0xb308,0xb310,0xb311,0xb313,0xb314,0xb315,0xb31c,
132.1141 +    0xb354,0xb355,0xb356,0xb358,0xb35b,0xb35c,0xb35e,0xb35f,0xb364,0xb365
132.1142 +  },
132.1143 +  {				/* ku 35 */
132.1144 +    0xd095,0xd096,0xd097,0xd098,0xd099,0xd09a,0xd09b,0xd09c,0xd09d,0xd09e,
132.1145 +    0xd09f,0xd0a0,0xd0a1,0xd0a2,0xd0a3,0xd0a6,0xd0a7,0xd0a9,0xd0aa,0xd0ab,
132.1146 +    0xd0ad,0xd0ae,0xd0af,0xd0b0,0xd0b1,0xd0b2,UBOGON,UBOGON,UBOGON,UBOGON,
132.1147 +    UBOGON,UBOGON,0xd0b3,0xd0b6,0xd0b8,0xd0ba,0xd0bb,0xd0bc,0xd0bd,0xd0be,
132.1148 +    0xd0bf,0xd0c2,0xd0c3,0xd0c5,0xd0c6,0xd0c7,0xd0ca,0xd0cb,0xd0cc,0xd0cd,
132.1149 +    0xd0ce,0xd0cf,0xd0d2,0xd0d6,0xd0d7,0xd0d8,0xd0d9,0xd0da,UBOGON,UBOGON,
132.1150 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd0db,0xd0de,0xd0df,0xd0e1,0xd0e2,0xd0e3,
132.1151 +    0xd0e5,0xd0e6,0xd0e7,0xd0e8,0xd0e9,0xd0ea,0xd0eb,0xd0ee,0xd0f2,0xd0f3,
132.1152 +    0xd0f4,0xd0f5,0xd0f6,0xd0f7,0xd0f9,0xd0fa,0xd0fb,0xd0fc,0xd0fd,0xd0fe,
132.1153 +    0xd0ff,0xd100,0xd101,0xd102,0xd103,0xd104,0xb367,0xb369,0xb36b,0xb36e,
132.1154 +    0xb370,0xb371,0xb374,0xb378,0xb380,0xb381,0xb383,0xb384,0xb385,0xb38c,
132.1155 +    0xb390,0xb394,0xb3a0,0xb3a1,0xb3a8,0xb3ac,0xb3c4,0xb3c5,0xb3c8,0xb3cb,
132.1156 +    0xb3cc,0xb3ce,0xb3d0,0xb3d4,0xb3d5,0xb3d7,0xb3d9,0xb3db,0xb3dd,0xb3e0,
132.1157 +    0xb3e4,0xb3e8,0xb3fc,0xb410,0xb418,0xb41c,0xb420,0xb428,0xb429,0xb42b,
132.1158 +    0xb434,0xb450,0xb451,0xb454,0xb458,0xb460,0xb461,0xb463,0xb465,0xb46c,
132.1159 +    0xb480,0xb488,0xb49d,0xb4a4,0xb4a8,0xb4ac,0xb4b5,0xb4b7,0xb4b9,0xb4c0,
132.1160 +    0xb4c4,0xb4c8,0xb4d0,0xb4d5,0xb4dc,0xb4dd,0xb4e0,0xb4e3,0xb4e4,0xb4e6,
132.1161 +    0xb4ec,0xb4ed,0xb4ef,0xb4f1,0xb4f8,0xb514,0xb515,0xb518,0xb51b,0xb51c,
132.1162 +    0xb524,0xb525,0xb527,0xb528,0xb529,0xb52a,0xb530,0xb531,0xb534,0xb538
132.1163 +  },
132.1164 +  {				/* ku 36 */
132.1165 +    0xd105,0xd106,0xd107,0xd108,0xd109,0xd10a,0xd10b,0xd10c,0xd10e,0xd10f,
132.1166 +    0xd110,0xd111,0xd112,0xd113,0xd114,0xd115,0xd116,0xd117,0xd118,0xd119,
132.1167 +    0xd11a,0xd11b,0xd11c,0xd11d,0xd11e,0xd11f,UBOGON,UBOGON,UBOGON,UBOGON,
132.1168 +    UBOGON,UBOGON,0xd120,0xd121,0xd122,0xd123,0xd124,0xd125,0xd126,0xd127,
132.1169 +    0xd128,0xd129,0xd12a,0xd12b,0xd12c,0xd12d,0xd12e,0xd12f,0xd132,0xd133,
132.1170 +    0xd135,0xd136,0xd137,0xd139,0xd13b,0xd13c,0xd13d,0xd13e,UBOGON,UBOGON,
132.1171 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd13f,0xd142,0xd146,0xd147,0xd148,0xd149,
132.1172 +    0xd14a,0xd14b,0xd14e,0xd14f,0xd151,0xd152,0xd153,0xd155,0xd156,0xd157,
132.1173 +    0xd158,0xd159,0xd15a,0xd15b,0xd15e,0xd160,0xd162,0xd163,0xd164,0xd165,
132.1174 +    0xd166,0xd167,0xd169,0xd16a,0xd16b,0xd16d,0xb540,0xb541,0xb543,0xb544,
132.1175 +    0xb545,0xb54b,0xb54c,0xb54d,0xb550,0xb554,0xb55c,0xb55d,0xb55f,0xb560,
132.1176 +    0xb561,0xb5a0,0xb5a1,0xb5a4,0xb5a8,0xb5aa,0xb5ab,0xb5b0,0xb5b1,0xb5b3,
132.1177 +    0xb5b4,0xb5b5,0xb5bb,0xb5bc,0xb5bd,0xb5c0,0xb5c4,0xb5cc,0xb5cd,0xb5cf,
132.1178 +    0xb5d0,0xb5d1,0xb5d8,0xb5ec,0xb610,0xb611,0xb614,0xb618,0xb625,0xb62c,
132.1179 +    0xb634,0xb648,0xb664,0xb668,0xb69c,0xb69d,0xb6a0,0xb6a4,0xb6ab,0xb6ac,
132.1180 +    0xb6b1,0xb6d4,0xb6f0,0xb6f4,0xb6f8,0xb700,0xb701,0xb705,0xb728,0xb729,
132.1181 +    0xb72c,0xb72f,0xb730,0xb738,0xb739,0xb73b,0xb744,0xb748,0xb74c,0xb754,
132.1182 +    0xb755,0xb760,0xb764,0xb768,0xb770,0xb771,0xb773,0xb775,0xb77c,0xb77d,
132.1183 +    0xb780,0xb784,0xb78c,0xb78d,0xb78f,0xb790,0xb791,0xb792,0xb796,0xb797
132.1184 +  },
132.1185 +  {				/* ku 37 */
132.1186 +    0xd16e,0xd16f,0xd170,0xd171,0xd172,0xd173,0xd174,0xd175,0xd176,0xd177,
132.1187 +    0xd178,0xd179,0xd17a,0xd17b,0xd17d,0xd17e,0xd17f,0xd180,0xd181,0xd182,
132.1188 +    0xd183,0xd185,0xd186,0xd187,0xd189,0xd18a,UBOGON,UBOGON,UBOGON,UBOGON,
132.1189 +    UBOGON,UBOGON,0xd18b,0xd18c,0xd18d,0xd18e,0xd18f,0xd190,0xd191,0xd192,
132.1190 +    0xd193,0xd194,0xd195,0xd196,0xd197,0xd198,0xd199,0xd19a,0xd19b,0xd19c,
132.1191 +    0xd19d,0xd19e,0xd19f,0xd1a2,0xd1a3,0xd1a5,0xd1a6,0xd1a7,UBOGON,UBOGON,
132.1192 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd1a9,0xd1aa,0xd1ab,0xd1ac,0xd1ad,0xd1ae,
132.1193 +    0xd1af,0xd1b2,0xd1b4,0xd1b6,0xd1b7,0xd1b8,0xd1b9,0xd1bb,0xd1bd,0xd1be,
132.1194 +    0xd1bf,0xd1c1,0xd1c2,0xd1c3,0xd1c4,0xd1c5,0xd1c6,0xd1c7,0xd1c8,0xd1c9,
132.1195 +    0xd1ca,0xd1cb,0xd1cc,0xd1cd,0xd1ce,0xd1cf,0xb798,0xb799,0xb79c,0xb7a0,
132.1196 +    0xb7a8,0xb7a9,0xb7ab,0xb7ac,0xb7ad,0xb7b4,0xb7b5,0xb7b8,0xb7c7,0xb7c9,
132.1197 +    0xb7ec,0xb7ed,0xb7f0,0xb7f4,0xb7fc,0xb7fd,0xb7ff,0xb800,0xb801,0xb807,
132.1198 +    0xb808,0xb809,0xb80c,0xb810,0xb818,0xb819,0xb81b,0xb81d,0xb824,0xb825,
132.1199 +    0xb828,0xb82c,0xb834,0xb835,0xb837,0xb838,0xb839,0xb840,0xb844,0xb851,
132.1200 +    0xb853,0xb85c,0xb85d,0xb860,0xb864,0xb86c,0xb86d,0xb86f,0xb871,0xb878,
132.1201 +    0xb87c,0xb88d,0xb8a8,0xb8b0,0xb8b4,0xb8b8,0xb8c0,0xb8c1,0xb8c3,0xb8c5,
132.1202 +    0xb8cc,0xb8d0,0xb8d4,0xb8dd,0xb8df,0xb8e1,0xb8e8,0xb8e9,0xb8ec,0xb8f0,
132.1203 +    0xb8f8,0xb8f9,0xb8fb,0xb8fd,0xb904,0xb918,0xb920,0xb93c,0xb93d,0xb940,
132.1204 +    0xb944,0xb94c,0xb94f,0xb951,0xb958,0xb959,0xb95c,0xb960,0xb968,0xb969
132.1205 +  },
132.1206 +  {				/* ku 38 */
132.1207 +    0xd1d0,0xd1d1,0xd1d2,0xd1d3,0xd1d4,0xd1d5,0xd1d6,0xd1d7,0xd1d9,0xd1da,
132.1208 +    0xd1db,0xd1dc,0xd1dd,0xd1de,0xd1df,0xd1e0,0xd1e1,0xd1e2,0xd1e3,0xd1e4,
132.1209 +    0xd1e5,0xd1e6,0xd1e7,0xd1e8,0xd1e9,0xd1ea,UBOGON,UBOGON,UBOGON,UBOGON,
132.1210 +    UBOGON,UBOGON,0xd1eb,0xd1ec,0xd1ed,0xd1ee,0xd1ef,0xd1f0,0xd1f1,0xd1f2,
132.1211 +    0xd1f3,0xd1f5,0xd1f6,0xd1f7,0xd1f9,0xd1fa,0xd1fb,0xd1fc,0xd1fd,0xd1fe,
132.1212 +    0xd1ff,0xd200,0xd201,0xd202,0xd203,0xd204,0xd205,0xd206,UBOGON,UBOGON,
132.1213 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd208,0xd20a,0xd20b,0xd20c,0xd20d,0xd20e,
132.1214 +    0xd20f,0xd211,0xd212,0xd213,0xd214,0xd215,0xd216,0xd217,0xd218,0xd219,
132.1215 +    0xd21a,0xd21b,0xd21c,0xd21d,0xd21e,0xd21f,0xd220,0xd221,0xd222,0xd223,
132.1216 +    0xd224,0xd225,0xd226,0xd227,0xd228,0xd229,0xb96b,0xb96d,0xb974,0xb975,
132.1217 +    0xb978,0xb97c,0xb984,0xb985,0xb987,0xb989,0xb98a,0xb98d,0xb98e,0xb9ac,
132.1218 +    0xb9ad,0xb9b0,0xb9b4,0xb9bc,0xb9bd,0xb9bf,0xb9c1,0xb9c8,0xb9c9,0xb9cc,
132.1219 +    0xb9ce,0xb9cf,0xb9d0,0xb9d1,0xb9d2,0xb9d8,0xb9d9,0xb9db,0xb9dd,0xb9de,
132.1220 +    0xb9e1,0xb9e3,0xb9e4,0xb9e5,0xb9e8,0xb9ec,0xb9f4,0xb9f5,0xb9f7,0xb9f8,
132.1221 +    0xb9f9,0xb9fa,0xba00,0xba01,0xba08,0xba15,0xba38,0xba39,0xba3c,0xba40,
132.1222 +    0xba42,0xba48,0xba49,0xba4b,0xba4d,0xba4e,0xba53,0xba54,0xba55,0xba58,
132.1223 +    0xba5c,0xba64,0xba65,0xba67,0xba68,0xba69,0xba70,0xba71,0xba74,0xba78,
132.1224 +    0xba83,0xba84,0xba85,0xba87,0xba8c,0xbaa8,0xbaa9,0xbaab,0xbaac,0xbab0,
132.1225 +    0xbab2,0xbab8,0xbab9,0xbabb,0xbabd,0xbac4,0xbac8,0xbad8,0xbad9,0xbafc
132.1226 +  },
132.1227 +  {				/* ku 39 */
132.1228 +    0xd22a,0xd22b,0xd22e,0xd22f,0xd231,0xd232,0xd233,0xd235,0xd236,0xd237,
132.1229 +    0xd238,0xd239,0xd23a,0xd23b,0xd23e,0xd240,0xd242,0xd243,0xd244,0xd245,
132.1230 +    0xd246,0xd247,0xd249,0xd24a,0xd24b,0xd24c,UBOGON,UBOGON,UBOGON,UBOGON,
132.1231 +    UBOGON,UBOGON,0xd24d,0xd24e,0xd24f,0xd250,0xd251,0xd252,0xd253,0xd254,
132.1232 +    0xd255,0xd256,0xd257,0xd258,0xd259,0xd25a,0xd25b,0xd25d,0xd25e,0xd25f,
132.1233 +    0xd260,0xd261,0xd262,0xd263,0xd265,0xd266,0xd267,0xd268,UBOGON,UBOGON,
132.1234 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd269,0xd26a,0xd26b,0xd26c,0xd26d,0xd26e,
132.1235 +    0xd26f,0xd270,0xd271,0xd272,0xd273,0xd274,0xd275,0xd276,0xd277,0xd278,
132.1236 +    0xd279,0xd27a,0xd27b,0xd27c,0xd27d,0xd27e,0xd27f,0xd282,0xd283,0xd285,
132.1237 +    0xd286,0xd287,0xd289,0xd28a,0xd28b,0xd28c,0xbb00,0xbb04,0xbb0d,0xbb0f,
132.1238 +    0xbb11,0xbb18,0xbb1c,0xbb20,0xbb29,0xbb2b,0xbb34,0xbb35,0xbb36,0xbb38,
132.1239 +    0xbb3b,0xbb3c,0xbb3d,0xbb3e,0xbb44,0xbb45,0xbb47,0xbb49,0xbb4d,0xbb4f,
132.1240 +    0xbb50,0xbb54,0xbb58,0xbb61,0xbb63,0xbb6c,0xbb88,0xbb8c,0xbb90,0xbba4,
132.1241 +    0xbba8,0xbbac,0xbbb4,0xbbb7,0xbbc0,0xbbc4,0xbbc8,0xbbd0,0xbbd3,0xbbf8,
132.1242 +    0xbbf9,0xbbfc,0xbbff,0xbc00,0xbc02,0xbc08,0xbc09,0xbc0b,0xbc0c,0xbc0d,
132.1243 +    0xbc0f,0xbc11,0xbc14,0xbc15,0xbc16,0xbc17,0xbc18,0xbc1b,0xbc1c,0xbc1d,
132.1244 +    0xbc1e,0xbc1f,0xbc24,0xbc25,0xbc27,0xbc29,0xbc2d,0xbc30,0xbc31,0xbc34,
132.1245 +    0xbc38,0xbc40,0xbc41,0xbc43,0xbc44,0xbc45,0xbc49,0xbc4c,0xbc4d,0xbc50,
132.1246 +    0xbc5d,0xbc84,0xbc85,0xbc88,0xbc8b,0xbc8c,0xbc8e,0xbc94,0xbc95,0xbc97
132.1247 +  },
132.1248 +  {				/* ku 3a */
132.1249 +    0xd28d,0xd28e,0xd28f,0xd292,0xd293,0xd294,0xd296,0xd297,0xd298,0xd299,
132.1250 +    0xd29a,0xd29b,0xd29d,0xd29e,0xd29f,0xd2a1,0xd2a2,0xd2a3,0xd2a5,0xd2a6,
132.1251 +    0xd2a7,0xd2a8,0xd2a9,0xd2aa,0xd2ab,0xd2ad,UBOGON,UBOGON,UBOGON,UBOGON,
132.1252 +    UBOGON,UBOGON,0xd2ae,0xd2af,0xd2b0,0xd2b2,0xd2b3,0xd2b4,0xd2b5,0xd2b6,
132.1253 +    0xd2b7,0xd2ba,0xd2bb,0xd2bd,0xd2be,0xd2c1,0xd2c3,0xd2c4,0xd2c5,0xd2c6,
132.1254 +    0xd2c7,0xd2ca,0xd2cc,0xd2cd,0xd2ce,0xd2cf,0xd2d0,0xd2d1,UBOGON,UBOGON,
132.1255 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd2d2,0xd2d3,0xd2d5,0xd2d6,0xd2d7,0xd2d9,
132.1256 +    0xd2da,0xd2db,0xd2dd,0xd2de,0xd2df,0xd2e0,0xd2e1,0xd2e2,0xd2e3,0xd2e6,
132.1257 +    0xd2e7,0xd2e8,0xd2e9,0xd2ea,0xd2eb,0xd2ec,0xd2ed,0xd2ee,0xd2ef,0xd2f2,
132.1258 +    0xd2f3,0xd2f5,0xd2f6,0xd2f7,0xd2f9,0xd2fa,0xbc99,0xbc9a,0xbca0,0xbca1,
132.1259 +    0xbca4,0xbca7,0xbca8,0xbcb0,0xbcb1,0xbcb3,0xbcb4,0xbcb5,0xbcbc,0xbcbd,
132.1260 +    0xbcc0,0xbcc4,0xbccd,0xbccf,0xbcd0,0xbcd1,0xbcd5,0xbcd8,0xbcdc,0xbcf4,
132.1261 +    0xbcf5,0xbcf6,0xbcf8,0xbcfc,0xbd04,0xbd05,0xbd07,0xbd09,0xbd10,0xbd14,
132.1262 +    0xbd24,0xbd2c,0xbd40,0xbd48,0xbd49,0xbd4c,0xbd50,0xbd58,0xbd59,0xbd64,
132.1263 +    0xbd68,0xbd80,0xbd81,0xbd84,0xbd87,0xbd88,0xbd89,0xbd8a,0xbd90,0xbd91,
132.1264 +    0xbd93,0xbd95,0xbd99,0xbd9a,0xbd9c,0xbda4,0xbdb0,0xbdb8,0xbdd4,0xbdd5,
132.1265 +    0xbdd8,0xbddc,0xbde9,0xbdf0,0xbdf4,0xbdf8,0xbe00,0xbe03,0xbe05,0xbe0c,
132.1266 +    0xbe0d,0xbe10,0xbe14,0xbe1c,0xbe1d,0xbe1f,0xbe44,0xbe45,0xbe48,0xbe4c,
132.1267 +    0xbe4e,0xbe54,0xbe55,0xbe57,0xbe59,0xbe5a,0xbe5b,0xbe60,0xbe61,0xbe64
132.1268 +  },
132.1269 +  {				/* ku 3b */
132.1270 +    0xd2fb,0xd2fc,0xd2fd,0xd2fe,0xd2ff,0xd302,0xd304,0xd306,0xd307,0xd308,
132.1271 +    0xd309,0xd30a,0xd30b,0xd30f,0xd311,0xd312,0xd313,0xd315,0xd317,0xd318,
132.1272 +    0xd319,0xd31a,0xd31b,0xd31e,0xd322,0xd323,UBOGON,UBOGON,UBOGON,UBOGON,
132.1273 +    UBOGON,UBOGON,0xd324,0xd326,0xd327,0xd32a,0xd32b,0xd32d,0xd32e,0xd32f,
132.1274 +    0xd331,0xd332,0xd333,0xd334,0xd335,0xd336,0xd337,0xd33a,0xd33e,0xd33f,
132.1275 +    0xd340,0xd341,0xd342,0xd343,0xd346,0xd347,0xd348,0xd349,UBOGON,UBOGON,
132.1276 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd34a,0xd34b,0xd34c,0xd34d,0xd34e,0xd34f,
132.1277 +    0xd350,0xd351,0xd352,0xd353,0xd354,0xd355,0xd356,0xd357,0xd358,0xd359,
132.1278 +    0xd35a,0xd35b,0xd35c,0xd35d,0xd35e,0xd35f,0xd360,0xd361,0xd362,0xd363,
132.1279 +    0xd364,0xd365,0xd366,0xd367,0xd368,0xd369,0xbe68,0xbe6a,0xbe70,0xbe71,
132.1280 +    0xbe73,0xbe74,0xbe75,0xbe7b,0xbe7c,0xbe7d,0xbe80,0xbe84,0xbe8c,0xbe8d,
132.1281 +    0xbe8f,0xbe90,0xbe91,0xbe98,0xbe99,0xbea8,0xbed0,0xbed1,0xbed4,0xbed7,
132.1282 +    0xbed8,0xbee0,0xbee3,0xbee4,0xbee5,0xbeec,0xbf01,0xbf08,0xbf09,0xbf18,
132.1283 +    0xbf19,0xbf1b,0xbf1c,0xbf1d,0xbf40,0xbf41,0xbf44,0xbf48,0xbf50,0xbf51,
132.1284 +    0xbf55,0xbf94,0xbfb0,0xbfc5,0xbfcc,0xbfcd,0xbfd0,0xbfd4,0xbfdc,0xbfdf,
132.1285 +    0xbfe1,0xc03c,0xc051,0xc058,0xc05c,0xc060,0xc068,0xc069,0xc090,0xc091,
132.1286 +    0xc094,0xc098,0xc0a0,0xc0a1,0xc0a3,0xc0a5,0xc0ac,0xc0ad,0xc0af,0xc0b0,
132.1287 +    0xc0b3,0xc0b4,0xc0b5,0xc0b6,0xc0bc,0xc0bd,0xc0bf,0xc0c0,0xc0c1,0xc0c5,
132.1288 +    0xc0c8,0xc0c9,0xc0cc,0xc0d0,0xc0d8,0xc0d9,0xc0db,0xc0dc,0xc0dd,0xc0e4
132.1289 +  },
132.1290 +  {				/* ku 3c */
132.1291 +    0xd36a,0xd36b,0xd36c,0xd36d,0xd36e,0xd36f,0xd370,0xd371,0xd372,0xd373,
132.1292 +    0xd374,0xd375,0xd376,0xd377,0xd378,0xd379,0xd37a,0xd37b,0xd37e,0xd37f,
132.1293 +    0xd381,0xd382,0xd383,0xd385,0xd386,0xd387,UBOGON,UBOGON,UBOGON,UBOGON,
132.1294 +    UBOGON,UBOGON,0xd388,0xd389,0xd38a,0xd38b,0xd38e,0xd392,0xd393,0xd394,
132.1295 +    0xd395,0xd396,0xd397,0xd39a,0xd39b,0xd39d,0xd39e,0xd39f,0xd3a1,0xd3a2,
132.1296 +    0xd3a3,0xd3a4,0xd3a5,0xd3a6,0xd3a7,0xd3aa,0xd3ac,0xd3ae,UBOGON,UBOGON,
132.1297 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd3af,0xd3b0,0xd3b1,0xd3b2,0xd3b3,0xd3b5,
132.1298 +    0xd3b6,0xd3b7,0xd3b9,0xd3ba,0xd3bb,0xd3bd,0xd3be,0xd3bf,0xd3c0,0xd3c1,
132.1299 +    0xd3c2,0xd3c3,0xd3c6,0xd3c7,0xd3ca,0xd3cb,0xd3cc,0xd3cd,0xd3ce,0xd3cf,
132.1300 +    0xd3d1,0xd3d2,0xd3d3,0xd3d4,0xd3d5,0xd3d6,0xc0e5,0xc0e8,0xc0ec,0xc0f4,
132.1301 +    0xc0f5,0xc0f7,0xc0f9,0xc100,0xc104,0xc108,0xc110,0xc115,0xc11c,0xc11d,
132.1302 +    0xc11e,0xc11f,0xc120,0xc123,0xc124,0xc126,0xc127,0xc12c,0xc12d,0xc12f,
132.1303 +    0xc130,0xc131,0xc136,0xc138,0xc139,0xc13c,0xc140,0xc148,0xc149,0xc14b,
132.1304 +    0xc14c,0xc14d,0xc154,0xc155,0xc158,0xc15c,0xc164,0xc165,0xc167,0xc168,
132.1305 +    0xc169,0xc170,0xc174,0xc178,0xc185,0xc18c,0xc18d,0xc18e,0xc190,0xc194,
132.1306 +    0xc196,0xc19c,0xc19d,0xc19f,0xc1a1,0xc1a5,0xc1a8,0xc1a9,0xc1ac,0xc1b0,
132.1307 +    0xc1bd,0xc1c4,0xc1c8,0xc1cc,0xc1d4,0xc1d7,0xc1d8,0xc1e0,0xc1e4,0xc1e8,
132.1308 +    0xc1f0,0xc1f1,0xc1f3,0xc1fc,0xc1fd,0xc200,0xc204,0xc20c,0xc20d,0xc20f,
132.1309 +    0xc211,0xc218,0xc219,0xc21c,0xc21f,0xc220,0xc228,0xc229,0xc22b,0xc22d
132.1310 +  },
132.1311 +  {				/* ku 3d */
132.1312 +    0xd3d7,0xd3d9,0xd3da,0xd3db,0xd3dc,0xd3dd,0xd3de,0xd3df,0xd3e0,0xd3e2,
132.1313 +    0xd3e4,0xd3e5,0xd3e6,0xd3e7,0xd3e8,0xd3e9,0xd3ea,0xd3eb,0xd3ee,0xd3ef,
132.1314 +    0xd3f1,0xd3f2,0xd3f3,0xd3f5,0xd3f6,0xd3f7,UBOGON,UBOGON,UBOGON,UBOGON,
132.1315 +    UBOGON,UBOGON,0xd3f8,0xd3f9,0xd3fa,0xd3fb,0xd3fe,0xd400,0xd402,0xd403,
132.1316 +    0xd404,0xd405,0xd406,0xd407,0xd409,0xd40a,0xd40b,0xd40c,0xd40d,0xd40e,
132.1317 +    0xd40f,0xd410,0xd411,0xd412,0xd413,0xd414,0xd415,0xd416,UBOGON,UBOGON,
132.1318 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd417,0xd418,0xd419,0xd41a,0xd41b,0xd41c,
132.1319 +    0xd41e,0xd41f,0xd420,0xd421,0xd422,0xd423,0xd424,0xd425,0xd426,0xd427,
132.1320 +    0xd428,0xd429,0xd42a,0xd42b,0xd42c,0xd42d,0xd42e,0xd42f,0xd430,0xd431,
132.1321 +    0xd432,0xd433,0xd434,0xd435,0xd436,0xd437,0xc22f,0xc231,0xc232,0xc234,
132.1322 +    0xc248,0xc250,0xc251,0xc254,0xc258,0xc260,0xc265,0xc26c,0xc26d,0xc270,
132.1323 +    0xc274,0xc27c,0xc27d,0xc27f,0xc281,0xc288,0xc289,0xc290,0xc298,0xc29b,
132.1324 +    0xc29d,0xc2a4,0xc2a5,0xc2a8,0xc2ac,0xc2ad,0xc2b4,0xc2b5,0xc2b7,0xc2b9,
132.1325 +    0xc2dc,0xc2dd,0xc2e0,0xc2e3,0xc2e4,0xc2eb,0xc2ec,0xc2ed,0xc2ef,0xc2f1,
132.1326 +    0xc2f6,0xc2f8,0xc2f9,0xc2fb,0xc2fc,0xc300,0xc308,0xc309,0xc30c,0xc30d,
132.1327 +    0xc313,0xc314,0xc315,0xc318,0xc31c,0xc324,0xc325,0xc328,0xc329,0xc345,
132.1328 +    0xc368,0xc369,0xc36c,0xc370,0xc372,0xc378,0xc379,0xc37c,0xc37d,0xc384,
132.1329 +    0xc388,0xc38c,0xc3c0,0xc3d8,0xc3d9,0xc3dc,0xc3df,0xc3e0,0xc3e2,0xc3e8,
132.1330 +    0xc3e9,0xc3ed,0xc3f4,0xc3f5,0xc3f8,0xc408,0xc410,0xc424,0xc42c,0xc430
132.1331 +  },
132.1332 +  {				/* ku 3e */
132.1333 +    0xd438,0xd439,0xd43a,0xd43b,0xd43c,0xd43d,0xd43e,0xd43f,0xd441,0xd442,
132.1334 +    0xd443,0xd445,0xd446,0xd447,0xd448,0xd449,0xd44a,0xd44b,0xd44c,0xd44d,
132.1335 +    0xd44e,0xd44f,0xd450,0xd451,0xd452,0xd453,UBOGON,UBOGON,UBOGON,UBOGON,
132.1336 +    UBOGON,UBOGON,0xd454,0xd455,0xd456,0xd457,0xd458,0xd459,0xd45a,0xd45b,
132.1337 +    0xd45d,0xd45e,0xd45f,0xd461,0xd462,0xd463,0xd465,0xd466,0xd467,0xd468,
132.1338 +    0xd469,0xd46a,0xd46b,0xd46c,0xd46e,0xd470,0xd471,0xd472,UBOGON,UBOGON,
132.1339 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd473,0xd474,0xd475,0xd476,0xd477,0xd47a,
132.1340 +    0xd47b,0xd47d,0xd47e,0xd481,0xd483,0xd484,0xd485,0xd486,0xd487,0xd48a,
132.1341 +    0xd48c,0xd48e,0xd48f,0xd490,0xd491,0xd492,0xd493,0xd495,0xd496,0xd497,
132.1342 +    0xd498,0xd499,0xd49a,0xd49b,0xd49c,0xd49d,0xc434,0xc43c,0xc43d,0xc448,
132.1343 +    0xc464,0xc465,0xc468,0xc46c,0xc474,0xc475,0xc479,0xc480,0xc494,0xc49c,
132.1344 +    0xc4b8,0xc4bc,0xc4e9,0xc4f0,0xc4f1,0xc4f4,0xc4f8,0xc4fa,0xc4ff,0xc500,
132.1345 +    0xc501,0xc50c,0xc510,0xc514,0xc51c,0xc528,0xc529,0xc52c,0xc530,0xc538,
132.1346 +    0xc539,0xc53b,0xc53d,0xc544,0xc545,0xc548,0xc549,0xc54a,0xc54c,0xc54d,
132.1347 +    0xc54e,0xc553,0xc554,0xc555,0xc557,0xc558,0xc559,0xc55d,0xc55e,0xc560,
132.1348 +    0xc561,0xc564,0xc568,0xc570,0xc571,0xc573,0xc574,0xc575,0xc57c,0xc57d,
132.1349 +    0xc580,0xc584,0xc587,0xc58c,0xc58d,0xc58f,0xc591,0xc595,0xc597,0xc598,
132.1350 +    0xc59c,0xc5a0,0xc5a9,0xc5b4,0xc5b5,0xc5b8,0xc5b9,0xc5bb,0xc5bc,0xc5bd,
132.1351 +    0xc5be,0xc5c4,0xc5c5,0xc5c6,0xc5c7,0xc5c8,0xc5c9,0xc5ca,0xc5cc,0xc5ce
132.1352 +  },
132.1353 +  {				/* ku 3f */
132.1354 +    0xd49e,0xd49f,0xd4a0,0xd4a1,0xd4a2,0xd4a3,0xd4a4,0xd4a5,0xd4a6,0xd4a7,
132.1355 +    0xd4a8,0xd4aa,0xd4ab,0xd4ac,0xd4ad,0xd4ae,0xd4af,0xd4b0,0xd4b1,0xd4b2,
132.1356 +    0xd4b3,0xd4b4,0xd4b5,0xd4b6,0xd4b7,0xd4b8,UBOGON,UBOGON,UBOGON,UBOGON,
132.1357 +    UBOGON,UBOGON,0xd4b9,0xd4ba,0xd4bb,0xd4bc,0xd4bd,0xd4be,0xd4bf,0xd4c0,
132.1358 +    0xd4c1,0xd4c2,0xd4c3,0xd4c4,0xd4c5,0xd4c6,0xd4c7,0xd4c8,0xd4c9,0xd4ca,
132.1359 +    0xd4cb,0xd4cd,0xd4ce,0xd4cf,0xd4d1,0xd4d2,0xd4d3,0xd4d5,UBOGON,UBOGON,
132.1360 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd4d6,0xd4d7,0xd4d8,0xd4d9,0xd4da,0xd4db,
132.1361 +    0xd4dd,0xd4de,0xd4e0,0xd4e1,0xd4e2,0xd4e3,0xd4e4,0xd4e5,0xd4e6,0xd4e7,
132.1362 +    0xd4e9,0xd4ea,0xd4eb,0xd4ed,0xd4ee,0xd4ef,0xd4f1,0xd4f2,0xd4f3,0xd4f4,
132.1363 +    0xd4f5,0xd4f6,0xd4f7,0xd4f9,0xd4fa,0xd4fc,0xc5d0,0xc5d1,0xc5d4,0xc5d8,
132.1364 +    0xc5e0,0xc5e1,0xc5e3,0xc5e5,0xc5ec,0xc5ed,0xc5ee,0xc5f0,0xc5f4,0xc5f6,
132.1365 +    0xc5f7,0xc5fc,0xc5fd,0xc5fe,0xc5ff,0xc600,0xc601,0xc605,0xc606,0xc607,
132.1366 +    0xc608,0xc60c,0xc610,0xc618,0xc619,0xc61b,0xc61c,0xc624,0xc625,0xc628,
132.1367 +    0xc62c,0xc62d,0xc62e,0xc630,0xc633,0xc634,0xc635,0xc637,0xc639,0xc63b,
132.1368 +    0xc640,0xc641,0xc644,0xc648,0xc650,0xc651,0xc653,0xc654,0xc655,0xc65c,
132.1369 +    0xc65d,0xc660,0xc66c,0xc66f,0xc671,0xc678,0xc679,0xc67c,0xc680,0xc688,
132.1370 +    0xc689,0xc68b,0xc68d,0xc694,0xc695,0xc698,0xc69c,0xc6a4,0xc6a5,0xc6a7,
132.1371 +    0xc6a9,0xc6b0,0xc6b1,0xc6b4,0xc6b8,0xc6b9,0xc6ba,0xc6c0,0xc6c1,0xc6c3,
132.1372 +    0xc6c5,0xc6cc,0xc6cd,0xc6d0,0xc6d4,0xc6dc,0xc6dd,0xc6e0,0xc6e1,0xc6e8
132.1373 +  },
132.1374 +  {				/* ku 40 */
132.1375 +    0xd4fe,0xd4ff,0xd500,0xd501,0xd502,0xd503,0xd505,0xd506,0xd507,0xd509,
132.1376 +    0xd50a,0xd50b,0xd50d,0xd50e,0xd50f,0xd510,0xd511,0xd512,0xd513,0xd516,
132.1377 +    0xd518,0xd519,0xd51a,0xd51b,0xd51c,0xd51d,UBOGON,UBOGON,UBOGON,UBOGON,
132.1378 +    UBOGON,UBOGON,0xd51e,0xd51f,0xd520,0xd521,0xd522,0xd523,0xd524,0xd525,
132.1379 +    0xd526,0xd527,0xd528,0xd529,0xd52a,0xd52b,0xd52c,0xd52d,0xd52e,0xd52f,
132.1380 +    0xd530,0xd531,0xd532,0xd533,0xd534,0xd535,0xd536,0xd537,UBOGON,UBOGON,
132.1381 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd538,0xd539,0xd53a,0xd53b,0xd53e,0xd53f,
132.1382 +    0xd541,0xd542,0xd543,0xd545,0xd546,0xd547,0xd548,0xd549,0xd54a,0xd54b,
132.1383 +    0xd54e,0xd550,0xd552,0xd553,0xd554,0xd555,0xd556,0xd557,0xd55a,0xd55b,
132.1384 +    0xd55d,0xd55e,0xd55f,0xd561,0xd562,0xd563,0xc6e9,0xc6ec,0xc6f0,0xc6f8,
132.1385 +    0xc6f9,0xc6fd,0xc704,0xc705,0xc708,0xc70c,0xc714,0xc715,0xc717,0xc719,
132.1386 +    0xc720,0xc721,0xc724,0xc728,0xc730,0xc731,0xc733,0xc735,0xc737,0xc73c,
132.1387 +    0xc73d,0xc740,0xc744,0xc74a,0xc74c,0xc74d,0xc74f,0xc751,0xc752,0xc753,
132.1388 +    0xc754,0xc755,0xc756,0xc757,0xc758,0xc75c,0xc760,0xc768,0xc76b,0xc774,
132.1389 +    0xc775,0xc778,0xc77c,0xc77d,0xc77e,0xc783,0xc784,0xc785,0xc787,0xc788,
132.1390 +    0xc789,0xc78a,0xc78e,0xc790,0xc791,0xc794,0xc796,0xc797,0xc798,0xc79a,
132.1391 +    0xc7a0,0xc7a1,0xc7a3,0xc7a4,0xc7a5,0xc7a6,0xc7ac,0xc7ad,0xc7b0,0xc7b4,
132.1392 +    0xc7bc,0xc7bd,0xc7bf,0xc7c0,0xc7c1,0xc7c8,0xc7c9,0xc7cc,0xc7ce,0xc7d0,
132.1393 +    0xc7d8,0xc7dd,0xc7e4,0xc7e8,0xc7ec,0xc800,0xc801,0xc804,0xc808,0xc80a
132.1394 +  },
132.1395 +  {				/* ku 41 */
132.1396 +    0xd564,0xd566,0xd567,0xd56a,0xd56c,0xd56e,0xd56f,0xd570,0xd571,0xd572,
132.1397 +    0xd573,0xd576,0xd577,0xd579,0xd57a,0xd57b,0xd57d,0xd57e,0xd57f,0xd580,
132.1398 +    0xd581,0xd582,0xd583,0xd586,0xd58a,0xd58b,UBOGON,UBOGON,UBOGON,UBOGON,
132.1399 +    UBOGON,UBOGON,0xd58c,0xd58d,0xd58e,0xd58f,0xd591,0xd592,0xd593,0xd594,
132.1400 +    0xd595,0xd596,0xd597,0xd598,0xd599,0xd59a,0xd59b,0xd59c,0xd59d,0xd59e,
132.1401 +    0xd59f,0xd5a0,0xd5a1,0xd5a2,0xd5a3,0xd5a4,0xd5a6,0xd5a7,UBOGON,UBOGON,
132.1402 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd5a8,0xd5a9,0xd5aa,0xd5ab,0xd5ac,0xd5ad,
132.1403 +    0xd5ae,0xd5af,0xd5b0,0xd5b1,0xd5b2,0xd5b3,0xd5b4,0xd5b5,0xd5b6,0xd5b7,
132.1404 +    0xd5b8,0xd5b9,0xd5ba,0xd5bb,0xd5bc,0xd5bd,0xd5be,0xd5bf,0xd5c0,0xd5c1,
132.1405 +    0xd5c2,0xd5c3,0xd5c4,0xd5c5,0xd5c6,0xd5c7,0xc810,0xc811,0xc813,0xc815,
132.1406 +    0xc816,0xc81c,0xc81d,0xc820,0xc824,0xc82c,0xc82d,0xc82f,0xc831,0xc838,
132.1407 +    0xc83c,0xc840,0xc848,0xc849,0xc84c,0xc84d,0xc854,0xc870,0xc871,0xc874,
132.1408 +    0xc878,0xc87a,0xc880,0xc881,0xc883,0xc885,0xc886,0xc887,0xc88b,0xc88c,
132.1409 +    0xc88d,0xc894,0xc89d,0xc89f,0xc8a1,0xc8a8,0xc8bc,0xc8bd,0xc8c4,0xc8c8,
132.1410 +    0xc8cc,0xc8d4,0xc8d5,0xc8d7,0xc8d9,0xc8e0,0xc8e1,0xc8e4,0xc8f5,0xc8fc,
132.1411 +    0xc8fd,0xc900,0xc904,0xc905,0xc906,0xc90c,0xc90d,0xc90f,0xc911,0xc918,
132.1412 +    0xc92c,0xc934,0xc950,0xc951,0xc954,0xc958,0xc960,0xc961,0xc963,0xc96c,
132.1413 +    0xc970,0xc974,0xc97c,0xc988,0xc989,0xc98c,0xc990,0xc998,0xc999,0xc99b,
132.1414 +    0xc99d,0xc9c0,0xc9c1,0xc9c4,0xc9c7,0xc9c8,0xc9ca,0xc9d0,0xc9d1,0xc9d3
132.1415 +  },
132.1416 +  {				/* ku 42 */
132.1417 +    0xd5ca,0xd5cb,0xd5cd,0xd5ce,0xd5cf,0xd5d1,0xd5d3,0xd5d4,0xd5d5,0xd5d6,
132.1418 +    0xd5d7,0xd5da,0xd5dc,0xd5de,0xd5df,0xd5e0,0xd5e1,0xd5e2,0xd5e3,0xd5e6,
132.1419 +    0xd5e7,0xd5e9,0xd5ea,0xd5eb,0xd5ed,0xd5ee,UBOGON,UBOGON,UBOGON,UBOGON,
132.1420 +    UBOGON,UBOGON,0xd5ef,0xd5f0,0xd5f1,0xd5f2,0xd5f3,0xd5f6,0xd5f8,0xd5fa,
132.1421 +    0xd5fb,0xd5fc,0xd5fd,0xd5fe,0xd5ff,0xd602,0xd603,0xd605,0xd606,0xd607,
132.1422 +    0xd609,0xd60a,0xd60b,0xd60c,0xd60d,0xd60e,0xd60f,0xd612,UBOGON,UBOGON,
132.1423 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd616,0xd617,0xd618,0xd619,0xd61a,0xd61b,
132.1424 +    0xd61d,0xd61e,0xd61f,0xd621,0xd622,0xd623,0xd625,0xd626,0xd627,0xd628,
132.1425 +    0xd629,0xd62a,0xd62b,0xd62c,0xd62e,0xd62f,0xd630,0xd631,0xd632,0xd633,
132.1426 +    0xd634,0xd635,0xd636,0xd637,0xd63a,0xd63b,0xc9d5,0xc9d6,0xc9d9,0xc9da,
132.1427 +    0xc9dc,0xc9dd,0xc9e0,0xc9e2,0xc9e4,0xc9e7,0xc9ec,0xc9ed,0xc9ef,0xc9f0,
132.1428 +    0xc9f1,0xc9f8,0xc9f9,0xc9fc,0xca00,0xca08,0xca09,0xca0b,0xca0c,0xca0d,
132.1429 +    0xca14,0xca18,0xca29,0xca4c,0xca4d,0xca50,0xca54,0xca5c,0xca5d,0xca5f,
132.1430 +    0xca60,0xca61,0xca68,0xca7d,0xca84,0xca98,0xcabc,0xcabd,0xcac0,0xcac4,
132.1431 +    0xcacc,0xcacd,0xcacf,0xcad1,0xcad3,0xcad8,0xcad9,0xcae0,0xcaec,0xcaf4,
132.1432 +    0xcb08,0xcb10,0xcb14,0xcb18,0xcb20,0xcb21,0xcb41,0xcb48,0xcb49,0xcb4c,
132.1433 +    0xcb50,0xcb58,0xcb59,0xcb5d,0xcb64,0xcb78,0xcb79,0xcb9c,0xcbb8,0xcbd4,
132.1434 +    0xcbe4,0xcbe7,0xcbe9,0xcc0c,0xcc0d,0xcc10,0xcc14,0xcc1c,0xcc1d,0xcc21,
132.1435 +    0xcc22,0xcc27,0xcc28,0xcc29,0xcc2c,0xcc2e,0xcc30,0xcc38,0xcc39,0xcc3b
132.1436 +  },
132.1437 +  {				/* ku 43 */
132.1438 +    0xd63d,0xd63e,0xd63f,0xd641,0xd642,0xd643,0xd644,0xd646,0xd647,0xd64a,
132.1439 +    0xd64c,0xd64e,0xd64f,0xd650,0xd652,0xd653,0xd656,0xd657,0xd659,0xd65a,
132.1440 +    0xd65b,0xd65d,0xd65e,0xd65f,0xd660,0xd661,UBOGON,UBOGON,UBOGON,UBOGON,
132.1441 +    UBOGON,UBOGON,0xd662,0xd663,0xd664,0xd665,0xd666,0xd668,0xd66a,0xd66b,
132.1442 +    0xd66c,0xd66d,0xd66e,0xd66f,0xd672,0xd673,0xd675,0xd676,0xd677,0xd678,
132.1443 +    0xd679,0xd67a,0xd67b,0xd67c,0xd67d,0xd67e,0xd67f,0xd680,UBOGON,UBOGON,
132.1444 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd681,0xd682,0xd684,0xd686,0xd687,0xd688,
132.1445 +    0xd689,0xd68a,0xd68b,0xd68e,0xd68f,0xd691,0xd692,0xd693,0xd695,0xd696,
132.1446 +    0xd697,0xd698,0xd699,0xd69a,0xd69b,0xd69c,0xd69e,0xd6a0,0xd6a2,0xd6a3,
132.1447 +    0xd6a4,0xd6a5,0xd6a6,0xd6a7,0xd6a9,0xd6aa,0xcc3c,0xcc3d,0xcc3e,0xcc44,
132.1448 +    0xcc45,0xcc48,0xcc4c,0xcc54,0xcc55,0xcc57,0xcc58,0xcc59,0xcc60,0xcc64,
132.1449 +    0xcc66,0xcc68,0xcc70,0xcc75,0xcc98,0xcc99,0xcc9c,0xcca0,0xcca8,0xcca9,
132.1450 +    0xccab,0xccac,0xccad,0xccb4,0xccb5,0xccb8,0xccbc,0xccc4,0xccc5,0xccc7,
132.1451 +    0xccc9,0xccd0,0xccd4,0xcce4,0xccec,0xccf0,0xcd01,0xcd08,0xcd09,0xcd0c,
132.1452 +    0xcd10,0xcd18,0xcd19,0xcd1b,0xcd1d,0xcd24,0xcd28,0xcd2c,0xcd39,0xcd5c,
132.1453 +    0xcd60,0xcd64,0xcd6c,0xcd6d,0xcd6f,0xcd71,0xcd78,0xcd88,0xcd94,0xcd95,
132.1454 +    0xcd98,0xcd9c,0xcda4,0xcda5,0xcda7,0xcda9,0xcdb0,0xcdc4,0xcdcc,0xcdd0,
132.1455 +    0xcde8,0xcdec,0xcdf0,0xcdf8,0xcdf9,0xcdfb,0xcdfd,0xce04,0xce08,0xce0c,
132.1456 +    0xce14,0xce19,0xce20,0xce21,0xce24,0xce28,0xce30,0xce31,0xce33,0xce35
132.1457 +  },
132.1458 +  {				/* ku 44 */
132.1459 +    0xd6ab,0xd6ad,0xd6ae,0xd6af,0xd6b1,0xd6b2,0xd6b3,0xd6b4,0xd6b5,0xd6b6,
132.1460 +    0xd6b7,0xd6b8,0xd6ba,0xd6bc,0xd6bd,0xd6be,0xd6bf,0xd6c0,0xd6c1,0xd6c2,
132.1461 +    0xd6c3,0xd6c6,0xd6c7,0xd6c9,0xd6ca,0xd6cb,UBOGON,UBOGON,UBOGON,UBOGON,
132.1462 +    UBOGON,UBOGON,0xd6cd,0xd6ce,0xd6cf,0xd6d0,0xd6d2,0xd6d3,0xd6d5,0xd6d6,
132.1463 +    0xd6d8,0xd6da,0xd6db,0xd6dc,0xd6dd,0xd6de,0xd6df,0xd6e1,0xd6e2,0xd6e3,
132.1464 +    0xd6e5,0xd6e6,0xd6e7,0xd6e9,0xd6ea,0xd6eb,0xd6ec,0xd6ed,UBOGON,UBOGON,
132.1465 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd6ee,0xd6ef,0xd6f1,0xd6f2,0xd6f3,0xd6f4,
132.1466 +    0xd6f6,0xd6f7,0xd6f8,0xd6f9,0xd6fa,0xd6fb,0xd6fe,0xd6ff,0xd701,0xd702,
132.1467 +    0xd703,0xd705,0xd706,0xd707,0xd708,0xd709,0xd70a,0xd70b,0xd70c,0xd70d,
132.1468 +    0xd70e,0xd70f,0xd710,0xd712,0xd713,0xd714,0xce58,0xce59,0xce5c,0xce5f,
132.1469 +    0xce60,0xce61,0xce68,0xce69,0xce6b,0xce6d,0xce74,0xce75,0xce78,0xce7c,
132.1470 +    0xce84,0xce85,0xce87,0xce89,0xce90,0xce91,0xce94,0xce98,0xcea0,0xcea1,
132.1471 +    0xcea3,0xcea4,0xcea5,0xceac,0xcead,0xcec1,0xcee4,0xcee5,0xcee8,0xceeb,
132.1472 +    0xceec,0xcef4,0xcef5,0xcef7,0xcef8,0xcef9,0xcf00,0xcf01,0xcf04,0xcf08,
132.1473 +    0xcf10,0xcf11,0xcf13,0xcf15,0xcf1c,0xcf20,0xcf24,0xcf2c,0xcf2d,0xcf2f,
132.1474 +    0xcf30,0xcf31,0xcf38,0xcf54,0xcf55,0xcf58,0xcf5c,0xcf64,0xcf65,0xcf67,
132.1475 +    0xcf69,0xcf70,0xcf71,0xcf74,0xcf78,0xcf80,0xcf85,0xcf8c,0xcfa1,0xcfa8,
132.1476 +    0xcfb0,0xcfc4,0xcfe0,0xcfe1,0xcfe4,0xcfe8,0xcff0,0xcff1,0xcff3,0xcff5,
132.1477 +    0xcffc,0xd000,0xd004,0xd011,0xd018,0xd02d,0xd034,0xd035,0xd038,0xd03c
132.1478 +  },
132.1479 +  {				/* ku 45 */
132.1480 +    0xd715,0xd716,0xd717,0xd71a,0xd71b,0xd71d,0xd71e,0xd71f,0xd721,0xd722,
132.1481 +    0xd723,0xd724,0xd725,0xd726,0xd727,0xd72a,0xd72c,0xd72e,0xd72f,0xd730,
132.1482 +    0xd731,0xd732,0xd733,0xd736,0xd737,0xd739,UBOGON,UBOGON,UBOGON,UBOGON,
132.1483 +    UBOGON,UBOGON,0xd73a,0xd73b,0xd73d,0xd73e,0xd73f,0xd740,0xd741,0xd742,
132.1484 +    0xd743,0xd745,0xd746,0xd748,0xd74a,0xd74b,0xd74c,0xd74d,0xd74e,0xd74f,
132.1485 +    0xd752,0xd753,0xd755,0xd75a,0xd75b,0xd75c,0xd75d,0xd75e,UBOGON,UBOGON,
132.1486 +    UBOGON,UBOGON,UBOGON,UBOGON,0xd75f,0xd762,0xd764,0xd766,0xd767,0xd768,
132.1487 +    0xd76a,0xd76b,0xd76d,0xd76e,0xd76f,0xd771,0xd772,0xd773,0xd775,0xd776,
132.1488 +    0xd777,0xd778,0xd779,0xd77a,0xd77b,0xd77e,0xd77f,0xd780,0xd782,0xd783,
132.1489 +    0xd784,0xd785,0xd786,0xd787,0xd78a,0xd78b,0xd044,0xd045,0xd047,0xd049,
132.1490 +    0xd050,0xd054,0xd058,0xd060,0xd06c,0xd06d,0xd070,0xd074,0xd07c,0xd07d,
132.1491 +    0xd081,0xd0a4,0xd0a5,0xd0a8,0xd0ac,0xd0b4,0xd0b5,0xd0b7,0xd0b9,0xd0c0,
132.1492 +    0xd0c1,0xd0c4,0xd0c8,0xd0c9,0xd0d0,0xd0d1,0xd0d3,0xd0d4,0xd0d5,0xd0dc,
132.1493 +    0xd0dd,0xd0e0,0xd0e4,0xd0ec,0xd0ed,0xd0ef,0xd0f0,0xd0f1,0xd0f8,0xd10d,
132.1494 +    0xd130,0xd131,0xd134,0xd138,0xd13a,0xd140,0xd141,0xd143,0xd144,0xd145,
132.1495 +    0xd14c,0xd14d,0xd150,0xd154,0xd15c,0xd15d,0xd15f,0xd161,0xd168,0xd16c,
132.1496 +    0xd17c,0xd184,0xd188,0xd1a0,0xd1a1,0xd1a4,0xd1a8,0xd1b0,0xd1b1,0xd1b3,
132.1497 +    0xd1b5,0xd1ba,0xd1bc,0xd1c0,0xd1d8,0xd1f4,0xd1f8,0xd207,0xd209,0xd210,
132.1498 +    0xd22c,0xd22d,0xd230,0xd234,0xd23c,0xd23d,0xd23f,0xd241,0xd248,0xd25c
132.1499 +  },
132.1500 +  {				/* ku 46 */
132.1501 +    0xd78d,0xd78e,0xd78f,0xd791,0xd792,0xd793,0xd794,0xd795,0xd796,0xd797,
132.1502 +    0xd79a,0xd79c,0xd79e,0xd79f,0xd7a0,0xd7a1,0xd7a2,0xd7a3,UBOGON,UBOGON,
132.1503 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1504 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1505 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1506 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1507 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1508 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1509 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1510 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd264,0xd280,0xd281,0xd284,
132.1511 +    0xd288,0xd290,0xd291,0xd295,0xd29c,0xd2a0,0xd2a4,0xd2ac,0xd2b1,0xd2b8,
132.1512 +    0xd2b9,0xd2bc,0xd2bf,0xd2c0,0xd2c2,0xd2c8,0xd2c9,0xd2cb,0xd2d4,0xd2d8,
132.1513 +    0xd2dc,0xd2e4,0xd2e5,0xd2f0,0xd2f1,0xd2f4,0xd2f8,0xd300,0xd301,0xd303,
132.1514 +    0xd305,0xd30c,0xd30d,0xd30e,0xd310,0xd314,0xd316,0xd31c,0xd31d,0xd31f,
132.1515 +    0xd320,0xd321,0xd325,0xd328,0xd329,0xd32c,0xd330,0xd338,0xd339,0xd33b,
132.1516 +    0xd33c,0xd33d,0xd344,0xd345,0xd37c,0xd37d,0xd380,0xd384,0xd38c,0xd38d,
132.1517 +    0xd38f,0xd390,0xd391,0xd398,0xd399,0xd39c,0xd3a0,0xd3a8,0xd3a9,0xd3ab,
132.1518 +    0xd3ad,0xd3b4,0xd3b8,0xd3bc,0xd3c4,0xd3c5,0xd3c8,0xd3c9,0xd3d0,0xd3d8,
132.1519 +    0xd3e1,0xd3e3,0xd3ec,0xd3ed,0xd3f0,0xd3f4,0xd3fc,0xd3fd,0xd3ff,0xd401
132.1520 +  },
132.1521 +  {				/* ku 47 */
132.1522 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1523 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1524 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1525 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1526 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1527 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1528 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1529 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1530 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1531 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd408,0xd41d,0xd440,0xd444,
132.1532 +    0xd45c,0xd460,0xd464,0xd46d,0xd46f,0xd478,0xd479,0xd47c,0xd47f,0xd480,
132.1533 +    0xd482,0xd488,0xd489,0xd48b,0xd48d,0xd494,0xd4a9,0xd4cc,0xd4d0,0xd4d4,
132.1534 +    0xd4dc,0xd4df,0xd4e8,0xd4ec,0xd4f0,0xd4f8,0xd4fb,0xd4fd,0xd504,0xd508,
132.1535 +    0xd50c,0xd514,0xd515,0xd517,0xd53c,0xd53d,0xd540,0xd544,0xd54c,0xd54d,
132.1536 +    0xd54f,0xd551,0xd558,0xd559,0xd55c,0xd560,0xd565,0xd568,0xd569,0xd56b,
132.1537 +    0xd56d,0xd574,0xd575,0xd578,0xd57c,0xd584,0xd585,0xd587,0xd588,0xd589,
132.1538 +    0xd590,0xd5a5,0xd5c8,0xd5c9,0xd5cc,0xd5d0,0xd5d2,0xd5d8,0xd5d9,0xd5db,
132.1539 +    0xd5dd,0xd5e4,0xd5e5,0xd5e8,0xd5ec,0xd5f4,0xd5f5,0xd5f7,0xd5f9,0xd600,
132.1540 +    0xd601,0xd604,0xd608,0xd610,0xd611,0xd613,0xd614,0xd615,0xd61c,0xd620
132.1541 +  },
132.1542 +  {				/* ku 48 */
132.1543 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1544 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1545 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1546 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1547 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1548 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1549 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1550 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1551 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1552 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd624,0xd62d,0xd638,0xd639,
132.1553 +    0xd63c,0xd640,0xd645,0xd648,0xd649,0xd64b,0xd64d,0xd651,0xd654,0xd655,
132.1554 +    0xd658,0xd65c,0xd667,0xd669,0xd670,0xd671,0xd674,0xd683,0xd685,0xd68c,
132.1555 +    0xd68d,0xd690,0xd694,0xd69d,0xd69f,0xd6a1,0xd6a8,0xd6ac,0xd6b0,0xd6b9,
132.1556 +    0xd6bb,0xd6c4,0xd6c5,0xd6c8,0xd6cc,0xd6d1,0xd6d4,0xd6d7,0xd6d9,0xd6e0,
132.1557 +    0xd6e4,0xd6e8,0xd6f0,0xd6f5,0xd6fc,0xd6fd,0xd700,0xd704,0xd711,0xd718,
132.1558 +    0xd719,0xd71c,0xd720,0xd728,0xd729,0xd72b,0xd72d,0xd734,0xd735,0xd738,
132.1559 +    0xd73c,0xd744,0xd747,0xd749,0xd750,0xd751,0xd754,0xd756,0xd757,0xd758,
132.1560 +    0xd759,0xd760,0xd761,0xd763,0xd765,0xd769,0xd76c,0xd770,0xd774,0xd77c,
132.1561 +    0xd77d,0xd781,0xd788,0xd789,0xd78c,0xd790,0xd798,0xd799,0xd79b,0xd79d
132.1562 +  },
132.1563 +  {				/* ku 49 */
132.1564 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1565 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1566 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1567 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1568 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1569 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1570 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1571 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1572 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1573 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1574 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1575 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1576 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1577 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1578 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1579 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1580 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1581 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1582 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
132.1583 +  },
132.1584 +  {				/* ku 4a */
132.1585 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1586 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1587 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1588 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1589 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1590 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1591 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1592 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1593 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1594 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f3d,0x4f73,0x5047,0x50f9,
132.1595 +    0x52a0,0x53ef,0x5475,0x54e5,0x5609,0x5ac1,0x5bb6,0x6687,0x67b6,0x67b7,
132.1596 +    0x67ef,0x6b4c,0x73c2,0x75c2,0x7a3c,0x82db,0x8304,0x8857,0x8888,0x8a36,
132.1597 +    0x8cc8,0x8dcf,0x8efb,0x8fe6,0x99d5,0x523b,0x5374,0x5404,0x606a,0x6164,
132.1598 +    0x6bbc,0x73cf,0x811a,0x89ba,0x89d2,0x95a3,0x4f83,0x520a,0x58be,0x5978,
132.1599 +    0x59e6,0x5e72,0x5e79,0x61c7,0x63c0,0x6746,0x67ec,0x687f,0x6f97,0x764e,
132.1600 +    0x770b,0x78f5,0x7a08,0x7aff,0x7c21,0x809d,0x826e,0x8271,0x8aeb,0x9593,
132.1601 +    0x4e6b,0x559d,0x66f7,0x6e34,0x78a3,0x7aed,0x845b,0x8910,0x874e,0x97a8,
132.1602 +    0x52d8,0x574e,0x582a,0x5d4c,0x611f,0x61be,0x6221,0x6562,0x67d1,0x6a44,
132.1603 +    0x6e1b,0x7518,0x75b3,0x76e3,0x77b0,0x7d3a,0x90af,0x9451,0x9452,0x9f95
132.1604 +  },
132.1605 +  {				/* ku 4b */
132.1606 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1607 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1608 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1609 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1610 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1611 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1612 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1613 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1614 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1615 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5323,0x5cac,0x7532,0x80db,
132.1616 +    0x9240,0x9598,0x525b,0x5808,0x59dc,0x5ca1,0x5d17,0x5eb7,0x5f3a,0x5f4a,
132.1617 +    0x6177,0x6c5f,0x757a,0x7586,0x7ce0,0x7d73,0x7db1,0x7f8c,0x8154,0x8221,
132.1618 +    0x8591,0x8941,0x8b1b,0x92fc,0x964d,0x9c47,0x4ecb,0x4ef7,0x500b,0x51f1,
132.1619 +    0x584f,0x6137,0x613e,0x6168,0x6539,0x69ea,0x6f11,0x75a5,0x7686,0x76d6,
132.1620 +    0x7b87,0x82a5,0x84cb,0xf900,0x93a7,0x958b,0x5580,0x5ba2,0x5751,0xf901,
132.1621 +    0x7cb3,0x7fb9,0x91b5,0x5028,0x53bb,0x5c45,0x5de8,0x62d2,0x636e,0x64da,
132.1622 +    0x64e7,0x6e20,0x70ac,0x795b,0x8ddd,0x8e1e,0xf902,0x907d,0x9245,0x92f8,
132.1623 +    0x4e7e,0x4ef6,0x5065,0x5dfe,0x5efa,0x6106,0x6957,0x8171,0x8654,0x8e47,
132.1624 +    0x9375,0x9a2b,0x4e5e,0x5091,0x6770,0x6840,0x5109,0x528d,0x5292,0x6aa2
132.1625 +  },
132.1626 +  {				/* ku 4c */
132.1627 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1628 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1629 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1630 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1631 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1632 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1633 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1634 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1635 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1636 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x77bc,0x9210,0x9ed4,0x52ab,
132.1637 +    0x602f,0x8ff2,0x5048,0x61a9,0x63ed,0x64ca,0x683c,0x6a84,0x6fc0,0x8188,
132.1638 +    0x89a1,0x9694,0x5805,0x727d,0x72ac,0x7504,0x7d79,0x7e6d,0x80a9,0x898b,
132.1639 +    0x8b74,0x9063,0x9d51,0x6289,0x6c7a,0x6f54,0x7d50,0x7f3a,0x8a23,0x517c,
132.1640 +    0x614a,0x7b9d,0x8b19,0x9257,0x938c,0x4eac,0x4fd3,0x501e,0x50be,0x5106,
132.1641 +    0x52c1,0x52cd,0x537f,0x5770,0x5883,0x5e9a,0x5f91,0x6176,0x61ac,0x64ce,
132.1642 +    0x656c,0x666f,0x66bb,0x66f4,0x6897,0x6d87,0x7085,0x70f1,0x749f,0x74a5,
132.1643 +    0x74ca,0x75d9,0x786c,0x78ec,0x7adf,0x7af6,0x7d45,0x7d93,0x8015,0x803f,
132.1644 +    0x811b,0x8396,0x8b66,0x8f15,0x9015,0x93e1,0x9803,0x9838,0x9a5a,0x9be8,
132.1645 +    0x4fc2,0x5553,0x583a,0x5951,0x5b63,0x5c46,0x60b8,0x6212,0x6842,0x68b0
132.1646 +  },
132.1647 +  {				/* ku 4d */
132.1648 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1649 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1650 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1651 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1652 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1653 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1654 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1655 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1656 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1657 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x68e8,0x6eaa,0x754c,0x7678,
132.1658 +    0x78ce,0x7a3d,0x7cfb,0x7e6b,0x7e7c,0x8a08,0x8aa1,0x8c3f,0x968e,0x9dc4,
132.1659 +    0x53e4,0x53e9,0x544a,0x5471,0x56fa,0x59d1,0x5b64,0x5c3b,0x5eab,0x62f7,
132.1660 +    0x6537,0x6545,0x6572,0x66a0,0x67af,0x69c1,0x6cbd,0x75fc,0x7690,0x777e,
132.1661 +    0x7a3f,0x7f94,0x8003,0x80a1,0x818f,0x82e6,0x82fd,0x83f0,0x85c1,0x8831,
132.1662 +    0x88b4,0x8aa5,0xf903,0x8f9c,0x932e,0x96c7,0x9867,0x9ad8,0x9f13,0x54ed,
132.1663 +    0x659b,0x66f2,0x688f,0x7a40,0x8c37,0x9d60,0x56f0,0x5764,0x5d11,0x6606,
132.1664 +    0x68b1,0x68cd,0x6efe,0x7428,0x889e,0x9be4,0x6c68,0xf904,0x9aa8,0x4f9b,
132.1665 +    0x516c,0x5171,0x529f,0x5b54,0x5de5,0x6050,0x606d,0x62f1,0x63a7,0x653b,
132.1666 +    0x73d9,0x7a7a,0x86a3,0x8ca2,0x978f,0x4e32,0x5be1,0x6208,0x679c,0x74dc
132.1667 +  },
132.1668 +  {				/* ku 4e */
132.1669 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1670 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1671 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1672 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1673 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1674 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1675 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1676 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1677 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1678 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x79d1,0x83d3,0x8a87,0x8ab2,
132.1679 +    0x8de8,0x904e,0x934b,0x9846,0x5ed3,0x69e8,0x85ff,0x90ed,0xf905,0x51a0,
132.1680 +    0x5b98,0x5bec,0x6163,0x68fa,0x6b3e,0x704c,0x742f,0x74d8,0x7ba1,0x7f50,
132.1681 +    0x83c5,0x89c0,0x8cab,0x95dc,0x9928,0x522e,0x605d,0x62ec,0x9002,0x4f8a,
132.1682 +    0x5149,0x5321,0x58d9,0x5ee3,0x66e0,0x6d38,0x709a,0x72c2,0x73d6,0x7b50,
132.1683 +    0x80f1,0x945b,0x5366,0x639b,0x7f6b,0x4e56,0x5080,0x584a,0x58de,0x602a,
132.1684 +    0x6127,0x62d0,0x69d0,0x9b41,0x5b8f,0x7d18,0x80b1,0x8f5f,0x4ea4,0x50d1,
132.1685 +    0x54ac,0x55ac,0x5b0c,0x5da0,0x5de7,0x652a,0x654e,0x6821,0x6a4b,0x72e1,
132.1686 +    0x768e,0x77ef,0x7d5e,0x7ff9,0x81a0,0x854e,0x86df,0x8f03,0x8f4e,0x90ca,
132.1687 +    0x9903,0x9a55,0x9bab,0x4e18,0x4e45,0x4e5d,0x4ec7,0x4ff1,0x5177,0x52fe
132.1688 +  },
132.1689 +  {				/* ku 4f */
132.1690 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1691 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1692 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1693 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1694 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1695 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1696 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1697 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1698 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1699 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5340,0x53e3,0x53e5,0x548e,
132.1700 +    0x5614,0x5775,0x57a2,0x5bc7,0x5d87,0x5ed0,0x61fc,0x62d8,0x6551,0x67b8,
132.1701 +    0x67e9,0x69cb,0x6b50,0x6bc6,0x6bec,0x6c42,0x6e9d,0x7078,0x72d7,0x7396,
132.1702 +    0x7403,0x77bf,0x77e9,0x7a76,0x7d7f,0x8009,0x81fc,0x8205,0x820a,0x82df,
132.1703 +    0x8862,0x8b33,0x8cfc,0x8ec0,0x9011,0x90b1,0x9264,0x92b6,0x99d2,0x9a45,
132.1704 +    0x9ce9,0x9dd7,0x9f9c,0x570b,0x5c40,0x83ca,0x97a0,0x97ab,0x9eb4,0x541b,
132.1705 +    0x7a98,0x7fa4,0x88d9,0x8ecd,0x90e1,0x5800,0x5c48,0x6398,0x7a9f,0x5bae,
132.1706 +    0x5f13,0x7a79,0x7aae,0x828e,0x8eac,0x5026,0x5238,0x52f8,0x5377,0x5708,
132.1707 +    0x62f3,0x6372,0x6b0a,0x6dc3,0x7737,0x53a5,0x7357,0x8568,0x8e76,0x95d5,
132.1708 +    0x673a,0x6ac3,0x6f70,0x8a6d,0x8ecc,0x994b,0xf906,0x6677,0x6b78,0x8cb4
132.1709 +  },
132.1710 +  {				/* ku 50 */
132.1711 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1712 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1713 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1714 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1715 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1716 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1717 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1718 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1719 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1720 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b3c,0xf907,0x53eb,0x572d,
132.1721 +    0x594e,0x63c6,0x69fb,0x73ea,0x7845,0x7aba,0x7ac5,0x7cfe,0x8475,0x898f,
132.1722 +    0x8d73,0x9035,0x95a8,0x52fb,0x5747,0x7547,0x7b60,0x83cc,0x921e,0xf908,
132.1723 +    0x6a58,0x514b,0x524b,0x5287,0x621f,0x68d8,0x6975,0x9699,0x50c5,0x52a4,
132.1724 +    0x52e4,0x61c3,0x65a4,0x6839,0x69ff,0x747e,0x7b4b,0x82b9,0x83eb,0x89b2,
132.1725 +    0x8b39,0x8fd1,0x9949,0xf909,0x4eca,0x5997,0x64d2,0x6611,0x6a8e,0x7434,
132.1726 +    0x7981,0x79bd,0x82a9,0x887e,0x887f,0x895f,0xf90a,0x9326,0x4f0b,0x53ca,
132.1727 +    0x6025,0x6271,0x6c72,0x7d1a,0x7d66,0x4e98,0x5162,0x77dc,0x80af,0x4f01,
132.1728 +    0x4f0e,0x5176,0x5180,0x55dc,0x5668,0x573b,0x57fa,0x57fc,0x5914,0x5947,
132.1729 +    0x5993,0x5bc4,0x5c90,0x5d0e,0x5df1,0x5e7e,0x5fcc,0x6280,0x65d7,0x65e3
132.1730 +  },
132.1731 +  {				/* ku 51 */
132.1732 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1733 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1734 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1735 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1736 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1737 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1738 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1739 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1740 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1741 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x671e,0x671f,0x675e,0x68cb,
132.1742 +    0x68c4,0x6a5f,0x6b3a,0x6c23,0x6c7d,0x6c82,0x6dc7,0x7398,0x7426,0x742a,
132.1743 +    0x7482,0x74a3,0x7578,0x757f,0x7881,0x78ef,0x7941,0x7947,0x7948,0x797a,
132.1744 +    0x7b95,0x7d00,0x7dba,0x7f88,0x8006,0x802d,0x808c,0x8a18,0x8b4f,0x8c48,
132.1745 +    0x8d77,0x9321,0x9324,0x98e2,0x9951,0x9a0e,0x9a0f,0x9a65,0x9e92,0x7dca,
132.1746 +    0x4f76,0x5409,0x62ee,0x6854,0x91d1,0x55ab,0x513a,0xf90b,0xf90c,0x5a1c,
132.1747 +    0x61e6,0xf90d,0x62cf,0x62ff,0xf90e,0xf90f,0xf910,0xf911,0xf912,0xf913,
132.1748 +    0x90a3,0xf914,0xf915,0xf916,0xf917,0xf918,0x8afe,0xf919,0xf91a,0xf91b,
132.1749 +    0xf91c,0x6696,0xf91d,0x7156,0xf91e,0xf91f,0x96e3,0xf920,0x634f,0x637a,
132.1750 +    0x5357,0xf921,0x678f,0x6960,0x6e73,0xf922,0x7537,0xf923,0xf924,0xf925
132.1751 +  },
132.1752 +  {				/* ku 52 */
132.1753 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1754 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1755 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1756 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1757 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1758 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1759 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1760 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1761 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1762 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7d0d,0xf926,0xf927,0x8872,
132.1763 +    0x56ca,0x5a18,0xf928,0xf929,0xf92a,0xf92b,0xf92c,0x4e43,0xf92d,0x5167,
132.1764 +    0x5948,0x67f0,0x8010,0xf92e,0x5973,0x5e74,0x649a,0x79ca,0x5ff5,0x606c,
132.1765 +    0x62c8,0x637b,0x5be7,0x5bd7,0x52aa,0xf92f,0x5974,0x5f29,0x6012,0xf930,
132.1766 +    0xf931,0xf932,0x7459,0xf933,0xf934,0xf935,0xf936,0xf937,0xf938,0x99d1,
132.1767 +    0xf939,0xf93a,0xf93b,0xf93c,0xf93d,0xf93e,0xf93f,0xf940,0xf941,0xf942,
132.1768 +    0xf943,0x6fc3,0xf944,0xf945,0x81bf,0x8fb2,0x60f1,0xf946,0xf947,0x8166,
132.1769 +    0xf948,0xf949,0x5c3f,0xf94a,0xf94b,0xf94c,0xf94d,0xf94e,0xf94f,0xf950,
132.1770 +    0xf951,0x5ae9,0x8a25,0x677b,0x7d10,0xf952,0xf953,0xf954,0xf955,0xf956,
132.1771 +    0xf957,0x80fd,0xf958,0xf959,0x5c3c,0x6ce5,0x533f,0x6eba,0x591a,0x8336
132.1772 +  },
132.1773 +  {				/* ku 53 */
132.1774 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1775 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1776 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1777 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1778 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1779 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1780 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1781 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1782 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1783 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4e39,0x4eb6,0x4f46,0x55ae,
132.1784 +    0x5718,0x58c7,0x5f56,0x65b7,0x65e6,0x6a80,0x6bb5,0x6e4d,0x77ed,0x7aef,
132.1785 +    0x7c1e,0x7dde,0x86cb,0x8892,0x9132,0x935b,0x64bb,0x6fbe,0x737a,0x75b8,
132.1786 +    0x9054,0x5556,0x574d,0x61ba,0x64d4,0x66c7,0x6de1,0x6e5b,0x6f6d,0x6fb9,
132.1787 +    0x75f0,0x8043,0x81bd,0x8541,0x8983,0x8ac7,0x8b5a,0x931f,0x6c93,0x7553,
132.1788 +    0x7b54,0x8e0f,0x905d,0x5510,0x5802,0x5858,0x5e62,0x6207,0x649e,0x68e0,
132.1789 +    0x7576,0x7cd6,0x87b3,0x9ee8,0x4ee3,0x5788,0x576e,0x5927,0x5c0d,0x5cb1,
132.1790 +    0x5e36,0x5f85,0x6234,0x64e1,0x73b3,0x81fa,0x888b,0x8cb8,0x968a,0x9edb,
132.1791 +    0x5b85,0x5fb7,0x60b3,0x5012,0x5200,0x5230,0x5716,0x5835,0x5857,0x5c0e,
132.1792 +    0x5c60,0x5cf6,0x5d8b,0x5ea6,0x5f92,0x60bc,0x6311,0x6389,0x6417,0x6843
132.1793 +  },
132.1794 +  {				/* ku 54 */
132.1795 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1796 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1797 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1798 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1799 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1800 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1801 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1802 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1803 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1804 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x68f9,0x6ac2,0x6dd8,0x6e21,
132.1805 +    0x6ed4,0x6fe4,0x71fe,0x76dc,0x7779,0x79b1,0x7a3b,0x8404,0x89a9,0x8ced,
132.1806 +    0x8df3,0x8e48,0x9003,0x9014,0x9053,0x90fd,0x934d,0x9676,0x97dc,0x6bd2,
132.1807 +    0x7006,0x7258,0x72a2,0x7368,0x7763,0x79bf,0x7be4,0x7e9b,0x8b80,0x58a9,
132.1808 +    0x60c7,0x6566,0x65fd,0x66be,0x6c8c,0x711e,0x71c9,0x8c5a,0x9813,0x4e6d,
132.1809 +    0x7a81,0x4edd,0x51ac,0x51cd,0x52d5,0x540c,0x61a7,0x6771,0x6850,0x68df,
132.1810 +    0x6d1e,0x6f7c,0x75bc,0x77b3,0x7ae5,0x80f4,0x8463,0x9285,0x515c,0x6597,
132.1811 +    0x675c,0x6793,0x75d8,0x7ac7,0x8373,0xf95a,0x8c46,0x9017,0x982d,0x5c6f,
132.1812 +    0x81c0,0x829a,0x9041,0x906f,0x920d,0x5f97,0x5d9d,0x6a59,0x71c8,0x767b,
132.1813 +    0x7b49,0x85e4,0x8b04,0x9127,0x9a30,0x5587,0x61f6,0xf95b,0x7669,0x7f85
132.1814 +  },
132.1815 +  {				/* ku 55 */
132.1816 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1817 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1818 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1819 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1820 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1821 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1822 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1823 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1824 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1825 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x863f,0x87ba,0x88f8,0x908f,
132.1826 +    0xf95c,0x6d1b,0x70d9,0x73de,0x7d61,0x843d,0xf95d,0x916a,0x99f1,0xf95e,
132.1827 +    0x4e82,0x5375,0x6b04,0x6b12,0x703e,0x721b,0x862d,0x9e1e,0x524c,0x8fa3,
132.1828 +    0x5d50,0x64e5,0x652c,0x6b16,0x6feb,0x7c43,0x7e9c,0x85cd,0x8964,0x89bd,
132.1829 +    0x62c9,0x81d8,0x881f,0x5eca,0x6717,0x6d6a,0x72fc,0x7405,0x746f,0x8782,
132.1830 +    0x90de,0x4f86,0x5d0d,0x5fa0,0x840a,0x51b7,0x63a0,0x7565,0x4eae,0x5006,
132.1831 +    0x5169,0x51c9,0x6881,0x6a11,0x7cae,0x7cb1,0x7ce7,0x826f,0x8ad2,0x8f1b,
132.1832 +    0x91cf,0x4fb6,0x5137,0x52f5,0x5442,0x5eec,0x616e,0x623e,0x65c5,0x6ada,
132.1833 +    0x6ffe,0x792a,0x85dc,0x8823,0x95ad,0x9a62,0x9a6a,0x9e97,0x9ece,0x529b,
132.1834 +    0x66c6,0x6b77,0x701d,0x792b,0x8f62,0x9742,0x6190,0x6200,0x6523,0x6f23
132.1835 +  },
132.1836 +  {				/* ku 56 */
132.1837 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1838 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1839 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1840 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1841 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1842 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1843 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1844 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1845 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1846 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7149,0x7489,0x7df4,0x806f,
132.1847 +    0x84ee,0x8f26,0x9023,0x934a,0x51bd,0x5217,0x52a3,0x6d0c,0x70c8,0x88c2,
132.1848 +    0x5ec9,0x6582,0x6bae,0x6fc2,0x7c3e,0x7375,0x4ee4,0x4f36,0x56f9,0xf95f,
132.1849 +    0x5cba,0x5dba,0x601c,0x73b2,0x7b2d,0x7f9a,0x7fce,0x8046,0x901e,0x9234,
132.1850 +    0x96f6,0x9748,0x9818,0x9f61,0x4f8b,0x6fa7,0x79ae,0x91b4,0x96b7,0x52de,
132.1851 +    0xf960,0x6488,0x64c4,0x6ad3,0x6f5e,0x7018,0x7210,0x76e7,0x8001,0x8606,
132.1852 +    0x865c,0x8def,0x8f05,0x9732,0x9b6f,0x9dfa,0x9e75,0x788c,0x797f,0x7da0,
132.1853 +    0x83c9,0x9304,0x9e7f,0x9e93,0x8ad6,0x58df,0x5f04,0x6727,0x7027,0x74cf,
132.1854 +    0x7c60,0x807e,0x5121,0x7028,0x7262,0x78ca,0x8cc2,0x8cda,0x8cf4,0x96f7,
132.1855 +    0x4e86,0x50da,0x5bee,0x5ed6,0x6599,0x71ce,0x7642,0x77ad,0x804a,0x84fc
132.1856 +  },
132.1857 +  {				/* ku 57 */
132.1858 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1859 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1860 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1861 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1862 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1863 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1864 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1865 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1866 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1867 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x907c,0x9b27,0x9f8d,0x58d8,
132.1868 +    0x5a41,0x5c62,0x6a13,0x6dda,0x6f0f,0x763b,0x7d2f,0x7e37,0x851e,0x8938,
132.1869 +    0x93e4,0x964b,0x5289,0x65d2,0x67f3,0x69b4,0x6d41,0x6e9c,0x700f,0x7409,
132.1870 +    0x7460,0x7559,0x7624,0x786b,0x8b2c,0x985e,0x516d,0x622e,0x9678,0x4f96,
132.1871 +    0x502b,0x5d19,0x6dea,0x7db8,0x8f2a,0x5f8b,0x6144,0x6817,0xf961,0x9686,
132.1872 +    0x52d2,0x808b,0x51dc,0x51cc,0x695e,0x7a1c,0x7dbe,0x83f1,0x9675,0x4fda,
132.1873 +    0x5229,0x5398,0x540f,0x550e,0x5c65,0x60a7,0x674e,0x68a8,0x6d6c,0x7281,
132.1874 +    0x72f8,0x7406,0x7483,0xf962,0x75e2,0x7c6c,0x7f79,0x7fb8,0x8389,0x88cf,
132.1875 +    0x88e1,0x91cc,0x91d0,0x96e2,0x9bc9,0x541d,0x6f7e,0x71d0,0x7498,0x85fa,
132.1876 +    0x8eaa,0x96a3,0x9c57,0x9e9f,0x6797,0x6dcb,0x7433,0x81e8,0x9716,0x782c
132.1877 +  },
132.1878 +  {				/* ku 58 */
132.1879 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1880 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1881 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1882 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1883 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1884 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1885 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1886 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1887 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1888 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7acb,0x7b20,0x7c92,0x6469,
132.1889 +    0x746a,0x75f2,0x78bc,0x78e8,0x99ac,0x9b54,0x9ebb,0x5bde,0x5e55,0x6f20,
132.1890 +    0x819c,0x83ab,0x9088,0x4e07,0x534d,0x5a29,0x5dd2,0x5f4e,0x6162,0x633d,
132.1891 +    0x6669,0x66fc,0x6eff,0x6f2b,0x7063,0x779e,0x842c,0x8513,0x883b,0x8f13,
132.1892 +    0x9945,0x9c3b,0x551c,0x62b9,0x672b,0x6cab,0x8309,0x896a,0x977a,0x4ea1,
132.1893 +    0x5984,0x5fd8,0x5fd9,0x671b,0x7db2,0x7f54,0x8292,0x832b,0x83bd,0x8f1e,
132.1894 +    0x9099,0x57cb,0x59b9,0x5a92,0x5bd0,0x6627,0x679a,0x6885,0x6bcf,0x7164,
132.1895 +    0x7f75,0x8cb7,0x8ce3,0x9081,0x9b45,0x8108,0x8c8a,0x964c,0x9a40,0x9ea5,
132.1896 +    0x5b5f,0x6c13,0x731b,0x76f2,0x76df,0x840c,0x51aa,0x8993,0x514d,0x5195,
132.1897 +    0x52c9,0x68c9,0x6c94,0x7704,0x7720,0x7dbf,0x7dec,0x9762,0x9eb5,0x6ec5
132.1898 +  },
132.1899 +  {				/* ku 59 */
132.1900 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1901 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1902 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1903 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1904 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1905 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1906 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1907 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1908 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1909 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8511,0x51a5,0x540d,0x547d,
132.1910 +    0x660e,0x669d,0x6927,0x6e9f,0x76bf,0x7791,0x8317,0x84c2,0x879f,0x9169,
132.1911 +    0x9298,0x9cf4,0x8882,0x4fae,0x5192,0x52df,0x59c6,0x5e3d,0x6155,0x6478,
132.1912 +    0x6479,0x66ae,0x67d0,0x6a21,0x6bcd,0x6bdb,0x725f,0x7261,0x7441,0x7738,
132.1913 +    0x77db,0x8017,0x82bc,0x8305,0x8b00,0x8b28,0x8c8c,0x6728,0x6c90,0x7267,
132.1914 +    0x76ee,0x7766,0x7a46,0x9da9,0x6b7f,0x6c92,0x5922,0x6726,0x8499,0x536f,
132.1915 +    0x5893,0x5999,0x5edf,0x63cf,0x6634,0x6773,0x6e3a,0x732b,0x7ad7,0x82d7,
132.1916 +    0x9328,0x52d9,0x5deb,0x61ae,0x61cb,0x620a,0x62c7,0x64ab,0x65e0,0x6959,
132.1917 +    0x6b66,0x6bcb,0x7121,0x73f7,0x755d,0x7e46,0x821e,0x8302,0x856a,0x8aa3,
132.1918 +    0x8cbf,0x9727,0x9d61,0x58a8,0x9ed8,0x5011,0x520e,0x543b,0x554f,0x6587
132.1919 +  },
132.1920 +  {				/* ku 5a */
132.1921 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1922 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1923 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1924 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1925 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1926 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1927 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1928 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1929 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1930 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c76,0x7d0a,0x7d0b,0x805e,
132.1931 +    0x868a,0x9580,0x96ef,0x52ff,0x6c95,0x7269,0x5473,0x5a9a,0x5c3e,0x5d4b,
132.1932 +    0x5f4c,0x5fae,0x672a,0x68b6,0x6963,0x6e3c,0x6e44,0x7709,0x7c73,0x7f8e,
132.1933 +    0x8587,0x8b0e,0x8ff7,0x9761,0x9ef4,0x5cb7,0x60b6,0x610d,0x61ab,0x654f,
132.1934 +    0x65fb,0x65fc,0x6c11,0x6cef,0x739f,0x73c9,0x7de1,0x9594,0x5bc6,0x871c,
132.1935 +    0x8b10,0x525d,0x535a,0x62cd,0x640f,0x64b2,0x6734,0x6a38,0x6cca,0x73c0,
132.1936 +    0x749e,0x7b94,0x7c95,0x7e1b,0x818a,0x8236,0x8584,0x8feb,0x96f9,0x99c1,
132.1937 +    0x4f34,0x534a,0x53cd,0x53db,0x62cc,0x642c,0x6500,0x6591,0x69c3,0x6cee,
132.1938 +    0x6f58,0x73ed,0x7554,0x7622,0x76e4,0x76fc,0x78d0,0x78fb,0x792c,0x7d46,
132.1939 +    0x822c,0x87e0,0x8fd4,0x9812,0x98ef,0x52c3,0x62d4,0x64a5,0x6e24,0x6f51
132.1940 +  },
132.1941 +  {				/* ku 5b */
132.1942 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1943 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1944 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1945 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1946 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1947 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1948 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1949 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1950 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1951 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x767c,0x8dcb,0x91b1,0x9262,
132.1952 +    0x9aee,0x9b43,0x5023,0x508d,0x574a,0x59a8,0x5c28,0x5e47,0x5f77,0x623f,
132.1953 +    0x653e,0x65b9,0x65c1,0x6609,0x678b,0x699c,0x6ec2,0x78c5,0x7d21,0x80aa,
132.1954 +    0x8180,0x822b,0x82b3,0x84a1,0x868c,0x8a2a,0x8b17,0x90a6,0x9632,0x9f90,
132.1955 +    0x500d,0x4ff3,0xf963,0x57f9,0x5f98,0x62dc,0x6392,0x676f,0x6e43,0x7119,
132.1956 +    0x76c3,0x80cc,0x80da,0x88f4,0x88f5,0x8919,0x8ce0,0x8f29,0x914d,0x966a,
132.1957 +    0x4f2f,0x4f70,0x5e1b,0x67cf,0x6822,0x767d,0x767e,0x9b44,0x5e61,0x6a0a,
132.1958 +    0x7169,0x71d4,0x756a,0xf964,0x7e41,0x8543,0x85e9,0x98dc,0x4f10,0x7b4f,
132.1959 +    0x7f70,0x95a5,0x51e1,0x5e06,0x68b5,0x6c3e,0x6c4e,0x6cdb,0x72af,0x7bc4,
132.1960 +    0x8303,0x6cd5,0x743a,0x50fb,0x5288,0x58c1,0x64d8,0x6a97,0x74a7,0x7656
132.1961 +  },
132.1962 +  {				/* ku 5c */
132.1963 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1964 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1965 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1966 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1967 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1968 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1969 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1970 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1971 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1972 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x78a7,0x8617,0x95e2,0x9739,
132.1973 +    0xf965,0x535e,0x5f01,0x8b8a,0x8fa8,0x8faf,0x908a,0x5225,0x77a5,0x9c49,
132.1974 +    0x9f08,0x4e19,0x5002,0x5175,0x5c5b,0x5e77,0x661e,0x663a,0x67c4,0x68c5,
132.1975 +    0x70b3,0x7501,0x75c5,0x79c9,0x7add,0x8f27,0x9920,0x9a08,0x4fdd,0x5821,
132.1976 +    0x5831,0x5bf6,0x666e,0x6b65,0x6d11,0x6e7a,0x6f7d,0x73e4,0x752b,0x83e9,
132.1977 +    0x88dc,0x8913,0x8b5c,0x8f14,0x4f0f,0x50d5,0x5310,0x535c,0x5b93,0x5fa9,
132.1978 +    0x670d,0x798f,0x8179,0x832f,0x8514,0x8907,0x8986,0x8f39,0x8f3b,0x99a5,
132.1979 +    0x9c12,0x672c,0x4e76,0x4ff8,0x5949,0x5c01,0x5cef,0x5cf0,0x6367,0x68d2,
132.1980 +    0x70fd,0x71a2,0x742b,0x7e2b,0x84ec,0x8702,0x9022,0x92d2,0x9cf3,0x4e0d,
132.1981 +    0x4ed8,0x4fef,0x5085,0x5256,0x526f,0x5426,0x5490,0x57e0,0x592b,0x5a66
132.1982 +  },
132.1983 +  {				/* ku 5d */
132.1984 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1985 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1986 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1987 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1988 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1989 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1990 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1991 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1992 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.1993 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5b5a,0x5b75,0x5bcc,0x5e9c,
132.1994 +    0xf966,0x6276,0x6577,0x65a7,0x6d6e,0x6ea5,0x7236,0x7b26,0x7c3f,0x7f36,
132.1995 +    0x8150,0x8151,0x819a,0x8240,0x8299,0x83a9,0x8a03,0x8ca0,0x8ce6,0x8cfb,
132.1996 +    0x8d74,0x8dba,0x90e8,0x91dc,0x961c,0x9644,0x99d9,0x9ce7,0x5317,0x5206,
132.1997 +    0x5429,0x5674,0x58b3,0x5954,0x596e,0x5fff,0x61a4,0x626e,0x6610,0x6c7e,
132.1998 +    0x711a,0x76c6,0x7c89,0x7cde,0x7d1b,0x82ac,0x8cc1,0x96f0,0xf967,0x4f5b,
132.1999 +    0x5f17,0x5f7f,0x62c2,0x5d29,0x670b,0x68da,0x787c,0x7e43,0x9d6c,0x4e15,
132.2000 +    0x5099,0x5315,0x532a,0x5351,0x5983,0x5a62,0x5e87,0x60b2,0x618a,0x6249,
132.2001 +    0x6279,0x6590,0x6787,0x69a7,0x6bd4,0x6bd6,0x6bd7,0x6bd8,0x6cb8,0xf968,
132.2002 +    0x7435,0x75fa,0x7812,0x7891,0x79d5,0x79d8,0x7c83,0x7dcb,0x7fe1,0x80a5
132.2003 +  },
132.2004 +  {				/* ku 5e */
132.2005 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2006 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2007 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2008 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2009 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2010 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2011 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2012 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2013 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2014 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x813e,0x81c2,0x83f2,0x871a,
132.2015 +    0x88e8,0x8ab9,0x8b6c,0x8cbb,0x9119,0x975e,0x98db,0x9f3b,0x56ac,0x5b2a,
132.2016 +    0x5f6c,0x658c,0x6ab3,0x6baf,0x6d5c,0x6ff1,0x7015,0x725d,0x73ad,0x8ca7,
132.2017 +    0x8cd3,0x983b,0x6191,0x6c37,0x8058,0x9a01,0x4e4d,0x4e8b,0x4e9b,0x4ed5,
132.2018 +    0x4f3a,0x4f3c,0x4f7f,0x4fdf,0x50ff,0x53f2,0x53f8,0x5506,0x55e3,0x56db,
132.2019 +    0x58eb,0x5962,0x5a11,0x5beb,0x5bfa,0x5c04,0x5df3,0x5e2b,0x5f99,0x601d,
132.2020 +    0x6368,0x659c,0x65af,0x67f6,0x67fb,0x68ad,0x6b7b,0x6c99,0x6cd7,0x6e23,
132.2021 +    0x7009,0x7345,0x7802,0x793e,0x7940,0x7960,0x79c1,0x7be9,0x7d17,0x7d72,
132.2022 +    0x8086,0x820d,0x838e,0x84d1,0x86c7,0x88df,0x8a50,0x8a5e,0x8b1d,0x8cdc,
132.2023 +    0x8d66,0x8fad,0x90aa,0x98fc,0x99df,0x9e9d,0x524a,0xf969,0x6714,0xf96a
132.2024 +  },
132.2025 +  {				/* ku 5f */
132.2026 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2027 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2028 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2029 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2030 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2031 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2032 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2033 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2034 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2035 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5098,0x522a,0x5c71,0x6563,
132.2036 +    0x6c55,0x73ca,0x7523,0x759d,0x7b97,0x849c,0x9178,0x9730,0x4e77,0x6492,
132.2037 +    0x6bba,0x715e,0x85a9,0x4e09,0xf96b,0x6749,0x68ee,0x6e17,0x829f,0x8518,
132.2038 +    0x886b,0x63f7,0x6f81,0x9212,0x98af,0x4e0a,0x50b7,0x50cf,0x511f,0x5546,
132.2039 +    0x55aa,0x5617,0x5b40,0x5c19,0x5ce0,0x5e38,0x5e8a,0x5ea0,0x5ec2,0x60f3,
132.2040 +    0x6851,0x6a61,0x6e58,0x723d,0x7240,0x72c0,0x76f8,0x7965,0x7bb1,0x7fd4,
132.2041 +    0x88f3,0x89f4,0x8a73,0x8c61,0x8cde,0x971c,0x585e,0x74bd,0x8cfd,0x55c7,
132.2042 +    0xf96c,0x7a61,0x7d22,0x8272,0x7272,0x751f,0x7525,0xf96d,0x7b19,0x5885,
132.2043 +    0x58fb,0x5dbc,0x5e8f,0x5eb6,0x5f90,0x6055,0x6292,0x637f,0x654d,0x6691,
132.2044 +    0x66d9,0x66f8,0x6816,0x68f2,0x7280,0x745e,0x7b6e,0x7d6e,0x7dd6,0x7f72
132.2045 +  },
132.2046 +  {				/* ku 60 */
132.2047 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2048 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2049 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2050 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2051 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2052 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2053 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2054 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2055 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2056 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x80e5,0x8212,0x85af,0x897f,
132.2057 +    0x8a93,0x901d,0x92e4,0x9ecd,0x9f20,0x5915,0x596d,0x5e2d,0x60dc,0x6614,
132.2058 +    0x6673,0x6790,0x6c50,0x6dc5,0x6f5f,0x77f3,0x78a9,0x84c6,0x91cb,0x932b,
132.2059 +    0x4ed9,0x50ca,0x5148,0x5584,0x5b0b,0x5ba3,0x6247,0x657e,0x65cb,0x6e32,
132.2060 +    0x717d,0x7401,0x7444,0x7487,0x74bf,0x766c,0x79aa,0x7dda,0x7e55,0x7fa8,
132.2061 +    0x817a,0x81b3,0x8239,0x861a,0x87ec,0x8a75,0x8de3,0x9078,0x9291,0x9425,
132.2062 +    0x994d,0x9bae,0x5368,0x5c51,0x6954,0x6cc4,0x6d29,0x6e2b,0x820c,0x859b,
132.2063 +    0x893b,0x8a2d,0x8aaa,0x96ea,0x9f67,0x5261,0x66b9,0x6bb2,0x7e96,0x87fe,
132.2064 +    0x8d0d,0x9583,0x965d,0x651d,0x6d89,0x71ee,0xf96e,0x57ce,0x59d3,0x5bac,
132.2065 +    0x6027,0x60fa,0x6210,0x661f,0x665f,0x7329,0x73f9,0x76db,0x7701,0x7b6c
132.2066 +  },
132.2067 +  {				/* ku 61 */
132.2068 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2069 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2070 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2071 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2072 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2073 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2074 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2075 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2076 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2077 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8056,0x8072,0x8165,0x8aa0,
132.2078 +    0x9192,0x4e16,0x52e2,0x6b72,0x6d17,0x7a05,0x7b39,0x7d30,0xf96f,0x8cb0,
132.2079 +    0x53ec,0x562f,0x5851,0x5bb5,0x5c0f,0x5c11,0x5de2,0x6240,0x6383,0x6414,
132.2080 +    0x662d,0x68b3,0x6cbc,0x6d88,0x6eaf,0x701f,0x70a4,0x71d2,0x7526,0x758f,
132.2081 +    0x758e,0x7619,0x7b11,0x7be0,0x7c2b,0x7d20,0x7d39,0x852c,0x856d,0x8607,
132.2082 +    0x8a34,0x900d,0x9061,0x90b5,0x92b7,0x97f6,0x9a37,0x4fd7,0x5c6c,0x675f,
132.2083 +    0x6d91,0x7c9f,0x7e8c,0x8b16,0x8d16,0x901f,0x5b6b,0x5dfd,0x640d,0x84c0,
132.2084 +    0x905c,0x98e1,0x7387,0x5b8b,0x609a,0x677e,0x6dde,0x8a1f,0x8aa6,0x9001,
132.2085 +    0x980c,0x5237,0xf970,0x7051,0x788e,0x9396,0x8870,0x91d7,0x4fee,0x53d7,
132.2086 +    0x55fd,0x56da,0x5782,0x58fd,0x5ac2,0x5b88,0x5cab,0x5cc0,0x5e25,0x6101
132.2087 +  },
132.2088 +  {				/* ku 62 */
132.2089 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2090 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2091 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2092 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2093 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2094 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2095 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2096 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2097 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2098 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x620d,0x624b,0x6388,0x641c,
132.2099 +    0x6536,0x6578,0x6a39,0x6b8a,0x6c34,0x6d19,0x6f31,0x71e7,0x72e9,0x7378,
132.2100 +    0x7407,0x74b2,0x7626,0x7761,0x79c0,0x7a57,0x7aea,0x7cb9,0x7d8f,0x7dac,
132.2101 +    0x7e61,0x7f9e,0x8129,0x8331,0x8490,0x84da,0x85ea,0x8896,0x8ab0,0x8b90,
132.2102 +    0x8f38,0x9042,0x9083,0x916c,0x9296,0x92b9,0x968b,0x96a7,0x96a8,0x96d6,
132.2103 +    0x9700,0x9808,0x9996,0x9ad3,0x9b1a,0x53d4,0x587e,0x5919,0x5b70,0x5bbf,
132.2104 +    0x6dd1,0x6f5a,0x719f,0x7421,0x74b9,0x8085,0x83fd,0x5de1,0x5f87,0x5faa,
132.2105 +    0x6042,0x65ec,0x6812,0x696f,0x6a53,0x6b89,0x6d35,0x6df3,0x73e3,0x76fe,
132.2106 +    0x77ac,0x7b4d,0x7d14,0x8123,0x821c,0x8340,0x84f4,0x8563,0x8a62,0x8ac4,
132.2107 +    0x9187,0x931e,0x9806,0x99b4,0x620c,0x8853,0x8ff0,0x9265,0x5d07,0x5d27
132.2108 +  },
132.2109 +  {				/* ku 63 */
132.2110 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2111 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2112 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2113 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2114 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2115 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2116 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2117 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2118 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2119 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5d69,0x745f,0x819d,0x8768,
132.2120 +    0x6fd5,0x62fe,0x7fd2,0x8936,0x8972,0x4e1e,0x4e58,0x50e7,0x52dd,0x5347,
132.2121 +    0x627f,0x6607,0x7e69,0x8805,0x965e,0x4f8d,0x5319,0x5636,0x59cb,0x5aa4,
132.2122 +    0x5c38,0x5c4e,0x5c4d,0x5e02,0x5f11,0x6043,0x65bd,0x662f,0x6642,0x67be,
132.2123 +    0x67f4,0x731c,0x77e2,0x793a,0x7fc5,0x8494,0x84cd,0x8996,0x8a66,0x8a69,
132.2124 +    0x8ae1,0x8c55,0x8c7a,0x57f4,0x5bd4,0x5f0f,0x606f,0x62ed,0x690d,0x6b96,
132.2125 +    0x6e5c,0x7184,0x7bd2,0x8755,0x8b58,0x8efe,0x98df,0x98fe,0x4f38,0x4f81,
132.2126 +    0x4fe1,0x547b,0x5a20,0x5bb8,0x613c,0x65b0,0x6668,0x71fc,0x7533,0x795e,
132.2127 +    0x7d33,0x814e,0x81e3,0x8398,0x85aa,0x85ce,0x8703,0x8a0a,0x8eab,0x8f9b,
132.2128 +    0xf971,0x8fc5,0x5931,0x5ba4,0x5be6,0x6089,0x5be9,0x5c0b,0x5fc3,0x6c81
132.2129 +  },
132.2130 +  {				/* ku 64 */
132.2131 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2132 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2133 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2134 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2135 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2136 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2137 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2138 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2139 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2140 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf972,0x6df1,0x700b,0x751a,
132.2141 +    0x82af,0x8af6,0x4ec0,0x5341,0xf973,0x96d9,0x6c0f,0x4e9e,0x4fc4,0x5152,
132.2142 +    0x555e,0x5a25,0x5ce8,0x6211,0x7259,0x82bd,0x83aa,0x86fe,0x8859,0x8a1d,
132.2143 +    0x963f,0x96c5,0x9913,0x9d09,0x9d5d,0x580a,0x5cb3,0x5dbd,0x5e44,0x60e1,
132.2144 +    0x6115,0x63e1,0x6a02,0x6e25,0x9102,0x9354,0x984e,0x9c10,0x9f77,0x5b89,
132.2145 +    0x5cb8,0x6309,0x664f,0x6848,0x773c,0x96c1,0x978d,0x9854,0x9b9f,0x65a1,
132.2146 +    0x8b01,0x8ecb,0x95bc,0x5535,0x5ca9,0x5dd6,0x5eb5,0x6697,0x764c,0x83f4,
132.2147 +    0x95c7,0x58d3,0x62bc,0x72ce,0x9d28,0x4ef0,0x592e,0x600f,0x663b,0x6b83,
132.2148 +    0x79e7,0x9d26,0x5393,0x54c0,0x57c3,0x5d16,0x611b,0x66d6,0x6daf,0x788d,
132.2149 +    0x827e,0x9698,0x9744,0x5384,0x627c,0x6396,0x6db2,0x7e0a,0x814b,0x984d
132.2150 +  },
132.2151 +  {				/* ku 65 */
132.2152 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2153 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2154 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2155 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2156 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2157 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2158 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2159 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2160 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2161 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6afb,0x7f4c,0x9daf,0x9e1a,
132.2162 +    0x4e5f,0x503b,0x51b6,0x591c,0x60f9,0x63f6,0x6930,0x723a,0x8036,0xf974,
132.2163 +    0x91ce,0x5f31,0xf975,0xf976,0x7d04,0x82e5,0x846f,0x84bb,0x85e5,0x8e8d,
132.2164 +    0xf977,0x4f6f,0xf978,0xf979,0x58e4,0x5b43,0x6059,0x63da,0x6518,0x656d,
132.2165 +    0x6698,0xf97a,0x694a,0x6a23,0x6d0b,0x7001,0x716c,0x75d2,0x760d,0x79b3,
132.2166 +    0x7a70,0xf97b,0x7f8a,0xf97c,0x8944,0xf97d,0x8b93,0x91c0,0x967d,0xf97e,
132.2167 +    0x990a,0x5704,0x5fa1,0x65bc,0x6f01,0x7600,0x79a6,0x8a9e,0x99ad,0x9b5a,
132.2168 +    0x9f6c,0x5104,0x61b6,0x6291,0x6a8d,0x81c6,0x5043,0x5830,0x5f66,0x7109,
132.2169 +    0x8a00,0x8afa,0x5b7c,0x8616,0x4ffa,0x513c,0x56b4,0x5944,0x63a9,0x6df9,
132.2170 +    0x5daa,0x696d,0x5186,0x4e88,0x4f59,0xf97f,0xf980,0xf981,0x5982,0xf982
132.2171 +  },
132.2172 +  {				/* ku 66 */
132.2173 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2174 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2175 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2176 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2177 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2178 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2179 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2180 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2181 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2182 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf983,0x6b5f,0x6c5d,0xf984,
132.2183 +    0x74b5,0x7916,0xf985,0x8207,0x8245,0x8339,0x8f3f,0x8f5d,0xf986,0x9918,
132.2184 +    0xf987,0xf988,0xf989,0x4ea6,0xf98a,0x57df,0x5f79,0x6613,0xf98b,0xf98c,
132.2185 +    0x75ab,0x7e79,0x8b6f,0xf98d,0x9006,0x9a5b,0x56a5,0x5827,0x59f8,0x5a1f,
132.2186 +    0x5bb4,0xf98e,0x5ef6,0xf98f,0xf990,0x6350,0x633b,0xf991,0x693d,0x6c87,
132.2187 +    0x6cbf,0x6d8e,0x6d93,0x6df5,0x6f14,0xf992,0x70df,0x7136,0x7159,0xf993,
132.2188 +    0x71c3,0x71d5,0xf994,0x784f,0x786f,0xf995,0x7b75,0x7de3,0xf996,0x7e2f,
132.2189 +    0xf997,0x884d,0x8edf,0xf998,0xf999,0xf99a,0x925b,0xf99b,0x9cf6,0xf99c,
132.2190 +    0xf99d,0xf99e,0x6085,0x6d85,0xf99f,0x71b1,0xf9a0,0xf9a1,0x95b1,0x53ad,
132.2191 +    0xf9a2,0xf9a3,0xf9a4,0x67d3,0xf9a5,0x708e,0x7130,0x7430,0x8276,0x82d2
132.2192 +  },
132.2193 +  {				/* ku 67 */
132.2194 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2195 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2196 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2197 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2198 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2199 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2200 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2201 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2202 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2203 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf9a6,0x95bb,0x9ae5,0x9e7d,
132.2204 +    0x66c4,0xf9a7,0x71c1,0x8449,0xf9a8,0xf9a9,0x584b,0xf9aa,0xf9ab,0x5db8,
132.2205 +    0x5f71,0xf9ac,0x6620,0x668e,0x6979,0x69ae,0x6c38,0x6cf3,0x6e36,0x6f41,
132.2206 +    0x6fda,0x701b,0x702f,0x7150,0x71df,0x7370,0xf9ad,0x745b,0xf9ae,0x74d4,
132.2207 +    0x76c8,0x7a4e,0x7e93,0xf9af,0xf9b0,0x82f1,0x8a60,0x8fce,0xf9b1,0x9348,
132.2208 +    0xf9b2,0x9719,0xf9b3,0xf9b4,0x4e42,0x502a,0xf9b5,0x5208,0x53e1,0x66f3,
132.2209 +    0x6c6d,0x6fca,0x730a,0x777f,0x7a62,0x82ae,0x85dd,0x8602,0xf9b6,0x88d4,
132.2210 +    0x8a63,0x8b7d,0x8c6b,0xf9b7,0x92b3,0xf9b8,0x9713,0x9810,0x4e94,0x4f0d,
132.2211 +    0x4fc9,0x50b2,0x5348,0x543e,0x5433,0x55da,0x5862,0x58ba,0x5967,0x5a1b,
132.2212 +    0x5be4,0x609f,0xf9b9,0x61ca,0x6556,0x65ff,0x6664,0x68a7,0x6c5a,0x6fb3
132.2213 +  },
132.2214 +  {				/* ku 68 */
132.2215 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2216 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2217 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2218 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2219 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2220 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2221 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2222 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2223 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2224 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x70cf,0x71ac,0x7352,0x7b7d,
132.2225 +    0x8708,0x8aa4,0x9c32,0x9f07,0x5c4b,0x6c83,0x7344,0x7389,0x923a,0x6eab,
132.2226 +    0x7465,0x761f,0x7a69,0x7e15,0x860a,0x5140,0x58c5,0x64c1,0x74ee,0x7515,
132.2227 +    0x7670,0x7fc1,0x9095,0x96cd,0x9954,0x6e26,0x74e6,0x7aa9,0x7aaa,0x81e5,
132.2228 +    0x86d9,0x8778,0x8a1b,0x5a49,0x5b8c,0x5b9b,0x68a1,0x6900,0x6d63,0x73a9,
132.2229 +    0x7413,0x742c,0x7897,0x7de9,0x7feb,0x8118,0x8155,0x839e,0x8c4c,0x962e,
132.2230 +    0x9811,0x66f0,0x5f80,0x65fa,0x6789,0x6c6a,0x738b,0x502d,0x5a03,0x6b6a,
132.2231 +    0x77ee,0x5916,0x5d6c,0x5dcd,0x7325,0x754f,0xf9ba,0xf9bb,0x50e5,0x51f9,
132.2232 +    0x582f,0x592d,0x5996,0x59da,0x5be5,0xf9bc,0xf9bd,0x5da2,0x62d7,0x6416,
132.2233 +    0x6493,0x64fe,0xf9be,0x66dc,0xf9bf,0x6a48,0xf9c0,0x71ff,0x7464,0xf9c1
132.2234 +  },
132.2235 +  {				/* ku 69 */
132.2236 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2237 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2238 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2239 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2240 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2241 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2242 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2243 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2244 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2245 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a88,0x7aaf,0x7e47,0x7e5e,
132.2246 +    0x8000,0x8170,0xf9c2,0x87ef,0x8981,0x8b20,0x9059,0xf9c3,0x9080,0x9952,
132.2247 +    0x617e,0x6b32,0x6d74,0x7e1f,0x8925,0x8fb1,0x4fd1,0x50ad,0x5197,0x52c7,
132.2248 +    0x57c7,0x5889,0x5bb9,0x5eb8,0x6142,0x6995,0x6d8c,0x6e67,0x6eb6,0x7194,
132.2249 +    0x7462,0x7528,0x752c,0x8073,0x8338,0x84c9,0x8e0a,0x9394,0x93de,0xf9c4,
132.2250 +    0x4e8e,0x4f51,0x5076,0x512a,0x53c8,0x53cb,0x53f3,0x5b87,0x5bd3,0x5c24,
132.2251 +    0x611a,0x6182,0x65f4,0x725b,0x7397,0x7440,0x76c2,0x7950,0x7991,0x79b9,
132.2252 +    0x7d06,0x7fbd,0x828b,0x85d5,0x865e,0x8fc2,0x9047,0x90f5,0x91ea,0x9685,
132.2253 +    0x96e8,0x96e9,0x52d6,0x5f67,0x65ed,0x6631,0x682f,0x715c,0x7a36,0x90c1,
132.2254 +    0x980a,0x4e91,0xf9c5,0x6a52,0x6b9e,0x6f90,0x7189,0x8018,0x82b8,0x8553
132.2255 +  },
132.2256 +  {				/* ku 6a */
132.2257 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2258 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2259 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2260 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2261 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2262 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2263 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2264 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2265 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2266 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x904b,0x9695,0x96f2,0x97fb,
132.2267 +    0x851a,0x9b31,0x4e90,0x718a,0x96c4,0x5143,0x539f,0x54e1,0x5713,0x5712,
132.2268 +    0x57a3,0x5a9b,0x5ac4,0x5bc3,0x6028,0x613f,0x63f4,0x6c85,0x6d39,0x6e72,
132.2269 +    0x6e90,0x7230,0x733f,0x7457,0x82d1,0x8881,0x8f45,0x9060,0xf9c6,0x9662,
132.2270 +    0x9858,0x9d1b,0x6708,0x8d8a,0x925e,0x4f4d,0x5049,0x50de,0x5371,0x570d,
132.2271 +    0x59d4,0x5a01,0x5c09,0x6170,0x6690,0x6e2d,0x7232,0x744b,0x7def,0x80c3,
132.2272 +    0x840e,0x8466,0x853f,0x875f,0x885b,0x8918,0x8b02,0x9055,0x97cb,0x9b4f,
132.2273 +    0x4e73,0x4f91,0x5112,0x516a,0xf9c7,0x552f,0x55a9,0x5b7a,0x5ba5,0x5e7c,
132.2274 +    0x5e7d,0x5ebe,0x60a0,0x60df,0x6108,0x6109,0x63c4,0x6538,0x6709,0xf9c8,
132.2275 +    0x67d4,0x67da,0xf9c9,0x6961,0x6962,0x6cb9,0x6d27,0xf9ca,0x6e38,0xf9cb
132.2276 +  },
132.2277 +  {				/* ku 6b */
132.2278 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2279 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2280 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2281 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2282 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2283 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2284 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2285 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2286 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2287 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6fe1,0x7336,0x7337,0xf9cc,
132.2288 +    0x745c,0x7531,0xf9cd,0x7652,0xf9ce,0xf9cf,0x7dad,0x81fe,0x8438,0x88d5,
132.2289 +    0x8a98,0x8adb,0x8aed,0x8e30,0x8e42,0x904a,0x903e,0x907a,0x9149,0x91c9,
132.2290 +    0x936e,0xf9d0,0xf9d1,0x5809,0xf9d2,0x6bd3,0x8089,0x80b2,0xf9d3,0xf9d4,
132.2291 +    0x5141,0x596b,0x5c39,0xf9d5,0xf9d6,0x6f64,0x73a7,0x80e4,0x8d07,0xf9d7,
132.2292 +    0x9217,0x958f,0xf9d8,0xf9d9,0xf9da,0xf9db,0x807f,0x620e,0x701c,0x7d68,
132.2293 +    0x878d,0xf9dc,0x57a0,0x6069,0x6147,0x6bb7,0x8abe,0x9280,0x96b1,0x4e59,
132.2294 +    0x541f,0x6deb,0x852d,0x9670,0x97f3,0x98ee,0x63d6,0x6ce3,0x9091,0x51dd,
132.2295 +    0x61c9,0x81ba,0x9df9,0x4f9d,0x501a,0x5100,0x5b9c,0x610f,0x61ff,0x64ec,
132.2296 +    0x6905,0x6bc5,0x7591,0x77e3,0x7fa9,0x8264,0x858f,0x87fb,0x8863,0x8abc
132.2297 +  },
132.2298 +  {				/* ku 6c */
132.2299 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2300 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2301 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2302 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2303 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2304 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2305 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2306 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2307 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2308 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8b70,0x91ab,0x4e8c,0x4ee5,
132.2309 +    0x4f0a,0xf9dd,0xf9de,0x5937,0x59e8,0xf9df,0x5df2,0x5f1b,0x5f5b,0x6021,
132.2310 +    0xf9e0,0xf9e1,0xf9e2,0xf9e3,0x723e,0x73e5,0xf9e4,0x7570,0x75cd,0xf9e5,
132.2311 +    0x79fb,0xf9e6,0x800c,0x8033,0x8084,0x82e1,0x8351,0xf9e7,0xf9e8,0x8cbd,
132.2312 +    0x8cb3,0x9087,0xf9e9,0xf9ea,0x98f4,0x990c,0xf9eb,0xf9ec,0x7037,0x76ca,
132.2313 +    0x7fca,0x7fcc,0x7ffc,0x8b1a,0x4eba,0x4ec1,0x5203,0x5370,0xf9ed,0x54bd,
132.2314 +    0x56e0,0x59fb,0x5bc5,0x5f15,0x5fcd,0x6e6e,0xf9ee,0xf9ef,0x7d6a,0x8335,
132.2315 +    0xf9f0,0x8693,0x8a8d,0xf9f1,0x976d,0x9777,0xf9f2,0xf9f3,0x4e00,0x4f5a,
132.2316 +    0x4f7e,0x58f9,0x65e5,0x6ea2,0x9038,0x93b0,0x99b9,0x4efb,0x58ec,0x598a,
132.2317 +    0x59d9,0x6041,0xf9f4,0xf9f5,0x7a14,0xf9f6,0x834f,0x8cc3,0x5165,0x5344
132.2318 +  },
132.2319 +  {				/* ku 6d */
132.2320 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2321 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2322 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2323 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2324 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2325 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2326 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2327 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2328 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2329 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf9f7,0xf9f8,0xf9f9,0x4ecd,
132.2330 +    0x5269,0x5b55,0x82bf,0x4ed4,0x523a,0x54a8,0x59c9,0x59ff,0x5b50,0x5b57,
132.2331 +    0x5b5c,0x6063,0x6148,0x6ecb,0x7099,0x716e,0x7386,0x74f7,0x75b5,0x78c1,
132.2332 +    0x7d2b,0x8005,0x81ea,0x8328,0x8517,0x85c9,0x8aee,0x8cc7,0x96cc,0x4f5c,
132.2333 +    0x52fa,0x56bc,0x65ab,0x6628,0x707c,0x70b8,0x7235,0x7dbd,0x828d,0x914c,
132.2334 +    0x96c0,0x9d72,0x5b71,0x68e7,0x6b98,0x6f7a,0x76de,0x5c91,0x66ab,0x6f5b,
132.2335 +    0x7bb4,0x7c2a,0x8836,0x96dc,0x4e08,0x4ed7,0x5320,0x5834,0x58bb,0x58ef,
132.2336 +    0x596c,0x5c07,0x5e33,0x5e84,0x5f35,0x638c,0x66b2,0x6756,0x6a1f,0x6aa3,
132.2337 +    0x6b0c,0x6f3f,0x7246,0xf9fa,0x7350,0x748b,0x7ae0,0x7ca7,0x8178,0x81df,
132.2338 +    0x81e7,0x838a,0x846c,0x8523,0x8594,0x85cf,0x88dd,0x8d13,0x91ac,0x9577
132.2339 +  },
132.2340 +  {				/* ku 6e */
132.2341 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2342 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2343 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2344 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2345 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2346 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2347 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2348 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2349 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2350 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x969c,0x518d,0x54c9,0x5728,
132.2351 +    0x5bb0,0x624d,0x6750,0x683d,0x6893,0x6e3d,0x6ed3,0x707d,0x7e21,0x88c1,
132.2352 +    0x8ca1,0x8f09,0x9f4b,0x9f4e,0x722d,0x7b8f,0x8acd,0x931a,0x4f47,0x4f4e,
132.2353 +    0x5132,0x5480,0x59d0,0x5e95,0x62b5,0x6775,0x696e,0x6a17,0x6cae,0x6e1a,
132.2354 +    0x72d9,0x732a,0x75bd,0x7bb8,0x7d35,0x82e7,0x83f9,0x8457,0x85f7,0x8a5b,
132.2355 +    0x8caf,0x8e87,0x9019,0x90b8,0x96ce,0x9f5f,0x52e3,0x540a,0x5ae1,0x5bc2,
132.2356 +    0x6458,0x6575,0x6ef4,0x72c4,0xf9fb,0x7684,0x7a4d,0x7b1b,0x7c4d,0x7e3e,
132.2357 +    0x7fdf,0x837b,0x8b2b,0x8cca,0x8d64,0x8de1,0x8e5f,0x8fea,0x8ff9,0x9069,
132.2358 +    0x93d1,0x4f43,0x4f7a,0x50b3,0x5168,0x5178,0x524d,0x526a,0x5861,0x587c,
132.2359 +    0x5960,0x5c08,0x5c55,0x5edb,0x609b,0x6230,0x6813,0x6bbf,0x6c08,0x6fb1
132.2360 +  },
132.2361 +  {				/* ku 6f */
132.2362 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2363 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2364 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2365 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2366 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2367 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2368 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2369 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2370 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2371 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x714e,0x7420,0x7530,0x7538,
132.2372 +    0x7551,0x7672,0x7b4c,0x7b8b,0x7bad,0x7bc6,0x7e8f,0x8a6e,0x8f3e,0x8f49,
132.2373 +    0x923f,0x9293,0x9322,0x942b,0x96fb,0x985a,0x986b,0x991e,0x5207,0x622a,
132.2374 +    0x6298,0x6d59,0x7664,0x7aca,0x7bc0,0x7d76,0x5360,0x5cbe,0x5e97,0x6f38,
132.2375 +    0x70b9,0x7c98,0x9711,0x9b8e,0x9ede,0x63a5,0x647a,0x8776,0x4e01,0x4e95,
132.2376 +    0x4ead,0x505c,0x5075,0x5448,0x59c3,0x5b9a,0x5e40,0x5ead,0x5ef7,0x5f81,
132.2377 +    0x60c5,0x633a,0x653f,0x6574,0x65cc,0x6676,0x6678,0x67fe,0x6968,0x6a89,
132.2378 +    0x6b63,0x6c40,0x6dc0,0x6de8,0x6e1f,0x6e5e,0x701e,0x70a1,0x738e,0x73fd,
132.2379 +    0x753a,0x775b,0x7887,0x798e,0x7a0b,0x7a7d,0x7cbe,0x7d8e,0x8247,0x8a02,
132.2380 +    0x8aea,0x8c9e,0x912d,0x914a,0x91d8,0x9266,0x92cc,0x9320,0x9706,0x9756
132.2381 +  },
132.2382 +  {				/* ku 70 */
132.2383 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2384 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2385 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2386 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2387 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2388 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2389 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2390 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2391 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2392 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x975c,0x9802,0x9f0e,0x5236,
132.2393 +    0x5291,0x557c,0x5824,0x5e1d,0x5f1f,0x608c,0x63d0,0x68af,0x6fdf,0x796d,
132.2394 +    0x7b2c,0x81cd,0x85ba,0x88fd,0x8af8,0x8e44,0x918d,0x9664,0x969b,0x973d,
132.2395 +    0x984c,0x9f4a,0x4fce,0x5146,0x51cb,0x52a9,0x5632,0x5f14,0x5f6b,0x63aa,
132.2396 +    0x64cd,0x65e9,0x6641,0x66fa,0x66f9,0x671d,0x689d,0x68d7,0x69fd,0x6f15,
132.2397 +    0x6f6e,0x7167,0x71e5,0x722a,0x74aa,0x773a,0x7956,0x795a,0x79df,0x7a20,
132.2398 +    0x7a95,0x7c97,0x7cdf,0x7d44,0x7e70,0x8087,0x85fb,0x86a4,0x8a54,0x8abf,
132.2399 +    0x8d99,0x8e81,0x9020,0x906d,0x91e3,0x963b,0x96d5,0x9ce5,0x65cf,0x7c07,
132.2400 +    0x8db3,0x93c3,0x5b58,0x5c0a,0x5352,0x62d9,0x731d,0x5027,0x5b97,0x5f9e,
132.2401 +    0x60b0,0x616b,0x68d5,0x6dd9,0x742e,0x7a2e,0x7d42,0x7d9c,0x7e31,0x816b
132.2402 +  },
132.2403 +  {				/* ku 71 */
132.2404 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2405 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2406 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2407 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2408 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2409 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2410 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2411 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2412 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2413 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8e2a,0x8e35,0x937e,0x9418,
132.2414 +    0x4f50,0x5750,0x5de6,0x5ea7,0x632b,0x7f6a,0x4e3b,0x4f4f,0x4f8f,0x505a,
132.2415 +    0x59dd,0x80c4,0x546a,0x5468,0x55fe,0x594f,0x5b99,0x5dde,0x5eda,0x665d,
132.2416 +    0x6731,0x67f1,0x682a,0x6ce8,0x6d32,0x6e4a,0x6f8d,0x70b7,0x73e0,0x7587,
132.2417 +    0x7c4c,0x7d02,0x7d2c,0x7da2,0x821f,0x86db,0x8a3b,0x8a85,0x8d70,0x8e8a,
132.2418 +    0x8f33,0x9031,0x914e,0x9152,0x9444,0x99d0,0x7af9,0x7ca5,0x4fca,0x5101,
132.2419 +    0x51c6,0x57c8,0x5bef,0x5cfb,0x6659,0x6a3d,0x6d5a,0x6e96,0x6fec,0x710c,
132.2420 +    0x756f,0x7ae3,0x8822,0x9021,0x9075,0x96cb,0x99ff,0x8301,0x4e2d,0x4ef2,
132.2421 +    0x8846,0x91cd,0x537d,0x6adb,0x696b,0x6c41,0x847a,0x589e,0x618e,0x66fe,
132.2422 +    0x62ef,0x70dd,0x7511,0x75c7,0x7e52,0x84b8,0x8b49,0x8d08,0x4e4b,0x53ea
132.2423 +  },
132.2424 +  {				/* ku 72 */
132.2425 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2426 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2427 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2428 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2429 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2430 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2431 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2432 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2433 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2434 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x54ab,0x5730,0x5740,0x5fd7,
132.2435 +    0x6301,0x6307,0x646f,0x652f,0x65e8,0x667a,0x679d,0x67b3,0x6b62,0x6c60,
132.2436 +    0x6c9a,0x6f2c,0x77e5,0x7825,0x7949,0x7957,0x7d19,0x80a2,0x8102,0x81f3,
132.2437 +    0x829d,0x82b7,0x8718,0x8a8c,0xf9fc,0x8d04,0x8dbe,0x9072,0x76f4,0x7a19,
132.2438 +    0x7a37,0x7e54,0x8077,0x5507,0x55d4,0x5875,0x632f,0x6422,0x6649,0x664b,
132.2439 +    0x686d,0x699b,0x6b84,0x6d25,0x6eb1,0x73cd,0x7468,0x74a1,0x755b,0x75b9,
132.2440 +    0x76e1,0x771e,0x778b,0x79e6,0x7e09,0x7e1d,0x81fb,0x852f,0x8897,0x8a3a,
132.2441 +    0x8cd1,0x8eeb,0x8fb0,0x9032,0x93ad,0x9663,0x9673,0x9707,0x4f84,0x53f1,
132.2442 +    0x59ea,0x5ac9,0x5e19,0x684e,0x74c6,0x75be,0x79e9,0x7a92,0x81a3,0x86ed,
132.2443 +    0x8cea,0x8dcc,0x8fed,0x659f,0x6715,0xf9fd,0x57f7,0x6f57,0x7ddd,0x8f2f
132.2444 +  },
132.2445 +  {				/* ku 73 */
132.2446 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2447 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2448 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2449 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2450 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2451 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2452 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2453 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2454 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2455 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x93f6,0x96c6,0x5fb5,0x61f2,
132.2456 +    0x6f84,0x4e14,0x4f98,0x501f,0x53c9,0x55df,0x5d6f,0x5dee,0x6b21,0x6b64,
132.2457 +    0x78cb,0x7b9a,0xf9fe,0x8e49,0x8eca,0x906e,0x6349,0x643e,0x7740,0x7a84,
132.2458 +    0x932f,0x947f,0x9f6a,0x64b0,0x6faf,0x71e6,0x74a8,0x74da,0x7ac4,0x7c12,
132.2459 +    0x7e82,0x7cb2,0x7e98,0x8b9a,0x8d0a,0x947d,0x9910,0x994c,0x5239,0x5bdf,
132.2460 +    0x64e6,0x672d,0x7d2e,0x50ed,0x53c3,0x5879,0x6158,0x6159,0x61fa,0x65ac,
132.2461 +    0x7ad9,0x8b92,0x8b96,0x5009,0x5021,0x5275,0x5531,0x5a3c,0x5ee0,0x5f70,
132.2462 +    0x6134,0x655e,0x660c,0x6636,0x66a2,0x69cd,0x6ec4,0x6f32,0x7316,0x7621,
132.2463 +    0x7a93,0x8139,0x8259,0x83d6,0x84bc,0x50b5,0x57f0,0x5bc0,0x5be8,0x5f69,
132.2464 +    0x63a1,0x7826,0x7db5,0x83dc,0x8521,0x91c7,0x91f5,0x518a,0x67f5,0x7b56
132.2465 +  },
132.2466 +  {				/* ku 74 */
132.2467 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2468 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2469 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2470 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2471 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2472 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2473 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2474 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2475 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2476 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8cac,0x51c4,0x59bb,0x60bd,
132.2477 +    0x8655,0x501c,0xf9ff,0x5254,0x5c3a,0x617d,0x621a,0x62d3,0x64f2,0x65a5,
132.2478 +    0x6ecc,0x7620,0x810a,0x8e60,0x965f,0x96bb,0x4edf,0x5343,0x5598,0x5929,
132.2479 +    0x5ddd,0x64c5,0x6cc9,0x6dfa,0x7394,0x7a7f,0x821b,0x85a6,0x8ce4,0x8e10,
132.2480 +    0x9077,0x91e7,0x95e1,0x9621,0x97c6,0x51f8,0x54f2,0x5586,0x5fb9,0x64a4,
132.2481 +    0x6f88,0x7db4,0x8f1f,0x8f4d,0x9435,0x50c9,0x5c16,0x6cbe,0x6dfb,0x751b,
132.2482 +    0x77bb,0x7c3d,0x7c64,0x8a79,0x8ac2,0x581e,0x59be,0x5e16,0x6377,0x7252,
132.2483 +    0x758a,0x776b,0x8adc,0x8cbc,0x8f12,0x5ef3,0x6674,0x6df8,0x807d,0x83c1,
132.2484 +    0x8acb,0x9751,0x9bd6,0xfa00,0x5243,0x66ff,0x6d95,0x6eef,0x7de0,0x8ae6,
132.2485 +    0x902e,0x905e,0x9ad4,0x521d,0x527f,0x54e8,0x6194,0x6284,0x62db,0x68a2
132.2486 +  },
132.2487 +  {				/* ku 75 */
132.2488 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2489 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2490 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2491 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2492 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2493 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2494 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2495 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2496 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2497 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6912,0x695a,0x6a35,0x7092,
132.2498 +    0x7126,0x785d,0x7901,0x790e,0x79d2,0x7a0d,0x8096,0x8278,0x82d5,0x8349,
132.2499 +    0x8549,0x8c82,0x8d85,0x9162,0x918b,0x91ae,0x4fc3,0x56d1,0x71ed,0x77d7,
132.2500 +    0x8700,0x89f8,0x5bf8,0x5fd6,0x6751,0x90a8,0x53e2,0x585a,0x5bf5,0x60a4,
132.2501 +    0x6181,0x6460,0x7e3d,0x8070,0x8525,0x9283,0x64ae,0x50ac,0x5d14,0x6700,
132.2502 +    0x589c,0x62bd,0x63a8,0x690e,0x6978,0x6a1e,0x6e6b,0x76ba,0x79cb,0x82bb,
132.2503 +    0x8429,0x8acf,0x8da8,0x8ffd,0x9112,0x914b,0x919c,0x9310,0x9318,0x939a,
132.2504 +    0x96db,0x9a36,0x9c0d,0x4e11,0x755c,0x795d,0x7afa,0x7b51,0x7bc9,0x7e2e,
132.2505 +    0x84c4,0x8e59,0x8e74,0x8ef8,0x9010,0x6625,0x693f,0x7443,0x51fa,0x672e,
132.2506 +    0x9edc,0x5145,0x5fe0,0x6c96,0x87f2,0x885d,0x8877,0x60b4,0x81b5,0x8403
132.2507 +  },
132.2508 +  {				/* ku 76 */
132.2509 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2510 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2511 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2512 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2513 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2514 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2515 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2516 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2517 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2518 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d05,0x53d6,0x5439,0x5634,
132.2519 +    0x5a36,0x5c31,0x708a,0x7fe0,0x805a,0x8106,0x81ed,0x8da3,0x9189,0x9a5f,
132.2520 +    0x9df2,0x5074,0x4ec4,0x53a0,0x60fb,0x6e2c,0x5c64,0x4f88,0x5024,0x55e4,
132.2521 +    0x5cd9,0x5e5f,0x6065,0x6894,0x6cbb,0x6dc4,0x71be,0x75d4,0x75f4,0x7661,
132.2522 +    0x7a1a,0x7a49,0x7dc7,0x7dfb,0x7f6e,0x81f4,0x86a9,0x8f1c,0x96c9,0x99b3,
132.2523 +    0x9f52,0x5247,0x52c5,0x98ed,0x89aa,0x4e03,0x67d2,0x6f06,0x4fb5,0x5be2,
132.2524 +    0x6795,0x6c88,0x6d78,0x741b,0x7827,0x91dd,0x937c,0x87c4,0x79e4,0x7a31,
132.2525 +    0x5feb,0x4ed6,0x54a4,0x553e,0x58ae,0x59a5,0x60f0,0x6253,0x62d6,0x6736,
132.2526 +    0x6955,0x8235,0x9640,0x99b1,0x99dd,0x502c,0x5353,0x5544,0x577c,0xfa01,
132.2527 +    0x6258,0xfa02,0x64e2,0x666b,0x67dd,0x6fc1,0x6fef,0x7422,0x7438,0x8a17
132.2528 +  },
132.2529 +  {				/* ku 77 */
132.2530 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2531 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2532 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2533 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2534 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2535 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2536 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2537 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2538 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2539 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9438,0x5451,0x5606,0x5766,
132.2540 +    0x5f48,0x619a,0x6b4e,0x7058,0x70ad,0x7dbb,0x8a95,0x596a,0x812b,0x63a2,
132.2541 +    0x7708,0x803d,0x8caa,0x5854,0x642d,0x69bb,0x5b95,0x5e11,0x6e6f,0xfa03,
132.2542 +    0x8569,0x514c,0x53f0,0x592a,0x6020,0x614b,0x6b86,0x6c70,0x6cf0,0x7b1e,
132.2543 +    0x80ce,0x82d4,0x8dc6,0x90b0,0x98b1,0xfa04,0x64c7,0x6fa4,0x6491,0x6504,
132.2544 +    0x514e,0x5410,0x571f,0x8a0e,0x615f,0x6876,0xfa05,0x75db,0x7b52,0x7d71,
132.2545 +    0x901a,0x5806,0x69cc,0x817f,0x892a,0x9000,0x9839,0x5078,0x5957,0x59ac,
132.2546 +    0x6295,0x900f,0x9b2a,0x615d,0x7279,0x95d6,0x5761,0x5a46,0x5df4,0x628a,
132.2547 +    0x64ad,0x64fa,0x6777,0x6ce2,0x6d3e,0x722c,0x7436,0x7834,0x7f77,0x82ad,
132.2548 +    0x8ddb,0x9817,0x5224,0x5742,0x677f,0x7248,0x74e3,0x8ca9,0x8fa6,0x9211
132.2549 +  },
132.2550 +  {				/* ku 78 */
132.2551 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2552 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2553 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2554 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2555 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2556 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2557 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2558 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2559 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2560 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x962a,0x516b,0x53ed,0x634c,
132.2561 +    0x4f69,0x5504,0x6096,0x6557,0x6c9b,0x6d7f,0x724c,0x72fd,0x7a17,0x8987,
132.2562 +    0x8c9d,0x5f6d,0x6f8e,0x70f9,0x81a8,0x610e,0x4fbf,0x504f,0x6241,0x7247,
132.2563 +    0x7bc7,0x7de8,0x7fe9,0x904d,0x97ad,0x9a19,0x8cb6,0x576a,0x5e73,0x67b0,
132.2564 +    0x840d,0x8a55,0x5420,0x5b16,0x5e63,0x5ee2,0x5f0a,0x6583,0x80ba,0x853d,
132.2565 +    0x9589,0x965b,0x4f48,0x5305,0x530d,0x530f,0x5486,0x54fa,0x5703,0x5e03,
132.2566 +    0x6016,0x629b,0x62b1,0x6355,0xfa06,0x6ce1,0x6d66,0x75b1,0x7832,0x80de,
132.2567 +    0x812f,0x82de,0x8461,0x84b2,0x888d,0x8912,0x900b,0x92ea,0x98fd,0x9b91,
132.2568 +    0x5e45,0x66b4,0x66dd,0x7011,0x7206,0xfa07,0x4ff5,0x527d,0x5f6a,0x6153,
132.2569 +    0x6753,0x6a19,0x6f02,0x74e2,0x7968,0x8868,0x8c79,0x98c7,0x98c4,0x9a43
132.2570 +  },
132.2571 +  {				/* ku 79 */
132.2572 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2573 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2574 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2575 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2576 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2577 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2578 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2579 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2580 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2581 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x54c1,0x7a1f,0x6953,0x8af7,
132.2582 +    0x8c4a,0x98a8,0x99ae,0x5f7c,0x62ab,0x75b2,0x76ae,0x88ab,0x907f,0x9642,
132.2583 +    0x5339,0x5f3c,0x5fc5,0x6ccc,0x73cc,0x7562,0x758b,0x7b46,0x82fe,0x999d,
132.2584 +    0x4e4f,0x903c,0x4e0b,0x4f55,0x53a6,0x590f,0x5ec8,0x6630,0x6cb3,0x7455,
132.2585 +    0x8377,0x8766,0x8cc0,0x9050,0x971e,0x9c15,0x58d1,0x5b78,0x8650,0x8b14,
132.2586 +    0x9db4,0x5bd2,0x6068,0x608d,0x65f1,0x6c57,0x6f22,0x6fa3,0x701a,0x7f55,
132.2587 +    0x7ff0,0x9591,0x9592,0x9650,0x97d3,0x5272,0x8f44,0x51fd,0x542b,0x54b8,
132.2588 +    0x5563,0x558a,0x6abb,0x6db5,0x7dd8,0x8266,0x929c,0x9677,0x9e79,0x5408,
132.2589 +    0x54c8,0x76d2,0x86e4,0x95a4,0x95d4,0x965c,0x4ea2,0x4f09,0x59ee,0x5ae6,
132.2590 +    0x5df7,0x6052,0x6297,0x676d,0x6841,0x6c86,0x6e2f,0x7f38,0x809b,0x822a
132.2591 +  },
132.2592 +  {				/* ku 7a */
132.2593 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2594 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2595 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2596 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2597 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2598 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2599 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2600 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2601 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2602 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xfa08,0xfa09,0x9805,0x4ea5,
132.2603 +    0x5055,0x54b3,0x5793,0x595a,0x5b69,0x5bb3,0x61c8,0x6977,0x6d77,0x7023,
132.2604 +    0x87f9,0x89e3,0x8a72,0x8ae7,0x9082,0x99ed,0x9ab8,0x52be,0x6838,0x5016,
132.2605 +    0x5e78,0x674f,0x8347,0x884c,0x4eab,0x5411,0x56ae,0x73e6,0x9115,0x97ff,
132.2606 +    0x9909,0x9957,0x9999,0x5653,0x589f,0x865b,0x8a31,0x61b2,0x6af6,0x737b,
132.2607 +    0x8ed2,0x6b47,0x96aa,0x9a57,0x5955,0x7200,0x8d6b,0x9769,0x4fd4,0x5cf4,
132.2608 +    0x5f26,0x61f8,0x665b,0x6ceb,0x70ab,0x7384,0x73b9,0x73fe,0x7729,0x774d,
132.2609 +    0x7d43,0x7d62,0x7e23,0x8237,0x8852,0xfa0a,0x8ce2,0x9249,0x986f,0x5b51,
132.2610 +    0x7a74,0x8840,0x9801,0x5acc,0x4fe0,0x5354,0x593e,0x5cfd,0x633e,0x6d79,
132.2611 +    0x72f9,0x8105,0x8107,0x83a2,0x92cf,0x9830,0x4ea8,0x5144,0x5211,0x578b
132.2612 +  },
132.2613 +  {				/* ku 7b */
132.2614 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2615 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2616 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2617 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2618 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2619 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2620 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2621 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2622 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2623 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5f62,0x6cc2,0x6ece,0x7005,
132.2624 +    0x7050,0x70af,0x7192,0x73e9,0x7469,0x834a,0x87a2,0x8861,0x9008,0x90a2,
132.2625 +    0x93a3,0x99a8,0x516e,0x5f57,0x60e0,0x6167,0x66b3,0x8559,0x8e4a,0x91af,
132.2626 +    0x978b,0x4e4e,0x4e92,0x547c,0x58d5,0x58fa,0x597d,0x5cb5,0x5f27,0x6236,
132.2627 +    0x6248,0x660a,0x6667,0x6beb,0x6d69,0x6dcf,0x6e56,0x6ef8,0x6f94,0x6fe0,
132.2628 +    0x6fe9,0x705d,0x72d0,0x7425,0x745a,0x74e0,0x7693,0x795c,0x7cca,0x7e1e,
132.2629 +    0x80e1,0x82a6,0x846b,0x84bf,0x864e,0x865f,0x8774,0x8b77,0x8c6a,0x93ac,
132.2630 +    0x9800,0x9865,0x60d1,0x6216,0x9177,0x5a5a,0x660f,0x6df7,0x6e3e,0x743f,
132.2631 +    0x9b42,0x5ffd,0x60da,0x7b0f,0x54c4,0x5f18,0x6c5e,0x6cd3,0x6d2a,0x70d8,
132.2632 +    0x7d05,0x8679,0x8a0c,0x9d3b,0x5316,0x548c,0x5b05,0x6a3a,0x706b,0x7575
132.2633 +  },
132.2634 +  {				/* ku 7c */
132.2635 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2636 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2637 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2638 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2639 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2640 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2641 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2642 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2643 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2644 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x798d,0x79be,0x82b1,0x83ef,
132.2645 +    0x8a71,0x8b41,0x8ca8,0x9774,0xfa0b,0x64f4,0x652b,0x78ba,0x78bb,0x7a6b,
132.2646 +    0x4e38,0x559a,0x5950,0x5ba6,0x5e7b,0x60a3,0x63db,0x6b61,0x6665,0x6853,
132.2647 +    0x6e19,0x7165,0x74b0,0x7d08,0x9084,0x9a69,0x9c25,0x6d3b,0x6ed1,0x733e,
132.2648 +    0x8c41,0x95ca,0x51f0,0x5e4c,0x5fa8,0x604d,0x60f6,0x6130,0x614c,0x6643,
132.2649 +    0x6644,0x69a5,0x6cc1,0x6e5f,0x6ec9,0x6f62,0x714c,0x749c,0x7687,0x7bc1,
132.2650 +    0x7c27,0x8352,0x8757,0x9051,0x968d,0x9ec3,0x532f,0x56de,0x5efb,0x5f8a,
132.2651 +    0x6062,0x6094,0x61f7,0x6666,0x6703,0x6a9c,0x6dee,0x6fae,0x7070,0x736a,
132.2652 +    0x7e6a,0x81be,0x8334,0x86d4,0x8aa8,0x8cc4,0x5283,0x7372,0x5b96,0x6a6b,
132.2653 +    0x9404,0x54ee,0x5686,0x5b5d,0x6548,0x6585,0x66c9,0x689f,0x6d8d,0x6dc6
132.2654 +  },
132.2655 +  {				/* ku 7d */
132.2656 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2657 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2658 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2659 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2660 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2661 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2662 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2663 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2664 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
132.2665 +    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x723b,0x80b4,0x9175,0x9a4d,
132.2666 +    0x4faf,0x5019,0x539a,0x540e,0x543c,0x5589,0x55c5,0x5e3f,0x5f8c,0x673d,
132.2667 +    0x7166,0x73dd,0x9005,0x52db,0x52f3,0x5864,0x58ce,0x7104,0x718f,0x71fb,
132.2668 +    0x85b0,0x8a13,0x6688,0x85a8,0x55a7,0x6684,0x714a,0x8431,0x5349,0x5599,
132.2669 +    0x6bc1,0x5f59,0x5fbd,0x63ee,0x6689,0x7147,0x8af1,0x8f1d,0x9ebe,0x4f11,
132.2670 +    0x643a,0x70cb,0x7566,0x8667,0x6064,0x8b4e,0x9df8,0x5147,0x51f6,0x5308,
132.2671 +    0x6d36,0x80f8,0x9ed1,0x6615,0x6b23,0x7098,0x75d5,0x5403,0x5c79,0x7d07,
132.2672 +    0x8a16,0x6b20,0x6b3d,0x6b46,0x5438,0x6070,0x6d3d,0x7fd5,0x8208,0x50d6,
132.2673 +    0x51de,0x559c,0x566b,0x56cd,0x59ec,0x5b09,0x5e0c,0x6199,0x6198,0x6231,
132.2674 +    0x665e,0x66e6,0x7199,0x71b9,0x71ba,0x72a7,0x79a7,0x7a00,0x7fb2,0x8a70
132.2675 +  }
132.2676 +};
   133.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   133.2 +++ b/src/charset/tis_620.c	Mon Sep 14 15:17:45 2009 +0900
   133.3 @@ -0,0 +1,51 @@
   133.4 +/* ========================================================================
   133.5 + * Copyright 1988-2006 University of Washington
   133.6 + *
   133.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   133.8 + * you may not use this file except in compliance with the License.
   133.9 + * You may obtain a copy of the License at
  133.10 + *
  133.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  133.12 + *
  133.13 + * 
  133.14 + * ========================================================================
  133.15 + */
  133.16 +
  133.17 +/*
  133.18 + * Program:	TIS 620-2529 conversion table
  133.19 + *
  133.20 + * Author:	Mark Crispin
  133.21 + *		Networks and Distributed Computing
  133.22 + *		Computing & Communications
  133.23 + *		University of Washington
  133.24 + *		Administration Building, AG-44
  133.25 + *		Seattle, WA  98195
  133.26 + *		Internet: MRC@CAC.Washington.EDU
  133.27 + *
  133.28 + * Date:	24 October 1997
  133.29 + * Last Edited:	30 August 2006
  133.30 + */
  133.31 +
  133.32 +/* TIS 620-2529 is the "Thai Industrial Standard for Thai Character Code
  133.33 + * for Computer", published by the Thai Industrial Standards Institute,
  133.34 + * Ministry of Industry of Thailand.
  133.35 + */
  133.36 +
  133.37 +static const unsigned short tis620tab[128] = {
  133.38 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
  133.39 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
  133.40 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
  133.41 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
  133.42 +  UBOGON,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
  133.43 +  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
  133.44 +  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
  133.45 +  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
  133.46 +  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
  133.47 +  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
  133.48 +  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
  133.49 +  0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
  133.50 +  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
  133.51 +  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
  133.52 +  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
  133.53 +  0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
  133.54 +};
   134.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   134.2 +++ b/src/charset/tmap.c	Mon Sep 14 15:17:45 2009 +0900
   134.3 @@ -0,0 +1,1487 @@
   134.4 +/* ========================================================================
   134.5 + * Copyright 1988-2006 University of Washington
   134.6 + *
   134.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   134.8 + * you may not use this file except in compliance with the License.
   134.9 + * You may obtain a copy of the License at
  134.10 + *
  134.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  134.12 + *
  134.13 + * 
  134.14 + * ========================================================================
  134.15 + */
  134.16 +
  134.17 +/*
  134.18 + * Program:	Unicode title case mapping table (current as of Unicode 5.0)
  134.19 + *
  134.20 + * Author:	Mark Crispin
  134.21 + *		Networks and Distributed Computing
  134.22 + *		Computing & Communications
  134.23 + *		University of Washington
  134.24 + *		Administration Building, AG-44
  134.25 + *		Seattle, WA  98195
  134.26 + *		Internet: MRC@CAC.Washington.EDU
  134.27 + *
  134.28 + * Date:	7 April 2006
  134.29 + * Last Edited:	6 December 2006
  134.30 + */
  134.31 +
  134.32 +			
  134.33 +#define UCS4_TMAPMAX 0x2d25	/* size of mapping table */
  134.34 +
  134.35 +#define UCS4_TMAPHIMIN 0xff41	/* high mapping minimum */
  134.36 +#define UCS4_TMAPHIMAX 0xff5a	/* high mapping maximum */
  134.37 +#define UCS4_TMAPHIMAP 0x20	/* high mapping offset */
  134.38 +
  134.39 +				/* Values for Deseret */
  134.40 +#define UCS4_TMAPDESERETMIN 0x10428
  134.41 +#define UCS4_TMAPDESERETMAX 0x1044f
  134.42 +#define UCS4_TMAPDESERETMAP 0x28
  134.43 +
  134.44 +static const unsigned short ucs4_tmaptab[UCS4_TMAPMAX+1] = {
  134.45 +  0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
  134.46 +  0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
  134.47 +  0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
  134.48 +  0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f,
  134.49 +  0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
  134.50 +  0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
  134.51 +  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
  134.52 +  0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
  134.53 +  0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
  134.54 +  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
  134.55 +  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
  134.56 +  0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
  134.57 +  0x0060,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
  134.58 +  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
  134.59 +  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
  134.60 +  0x0058,0x0059,0x005a,0x007b,0x007c,0x007d,0x007e,0x007f,
  134.61 +  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
  134.62 +  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
  134.63 +  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
  134.64 +  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
  134.65 +  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
  134.66 +  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
  134.67 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x039c,0x00b6,0x00b7,
  134.68 +  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
  134.69 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
  134.70 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
  134.71 +  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
  134.72 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
  134.73 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
  134.74 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
  134.75 +  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00f7,
  134.76 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x0178,
  134.77 +  0x0100,0x0100,0x0102,0x0102,0x0104,0x0104,0x0106,0x0106,
  134.78 +  0x0108,0x0108,0x010a,0x010a,0x010c,0x010c,0x010e,0x010e,
  134.79 +  0x0110,0x0110,0x0112,0x0112,0x0114,0x0114,0x0116,0x0116,
  134.80 +  0x0118,0x0118,0x011a,0x011a,0x011c,0x011c,0x011e,0x011e,
  134.81 +  0x0120,0x0120,0x0122,0x0122,0x0124,0x0124,0x0126,0x0126,
  134.82 +  0x0128,0x0128,0x012a,0x012a,0x012c,0x012c,0x012e,0x012e,
  134.83 +  0x0130,0x0049,0x0132,0x0132,0x0134,0x0134,0x0136,0x0136,
  134.84 +  0x0138,0x0139,0x0139,0x013b,0x013b,0x013d,0x013d,0x013f,
  134.85 +  0x013f,0x0141,0x0141,0x0143,0x0143,0x0145,0x0145,0x0147,
  134.86 +  0x0147,0x0149,0x014a,0x014a,0x014c,0x014c,0x014e,0x014e,
  134.87 +  0x0150,0x0150,0x0152,0x0152,0x0154,0x0154,0x0156,0x0156,
  134.88 +  0x0158,0x0158,0x015a,0x015a,0x015c,0x015c,0x015e,0x015e,
  134.89 +  0x0160,0x0160,0x0162,0x0162,0x0164,0x0164,0x0166,0x0166,
  134.90 +  0x0168,0x0168,0x016a,0x016a,0x016c,0x016c,0x016e,0x016e,
  134.91 +  0x0170,0x0170,0x0172,0x0172,0x0174,0x0174,0x0176,0x0176,
  134.92 +  0x0178,0x0179,0x0179,0x017b,0x017b,0x017d,0x017d,0x0053,
  134.93 +  0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,
  134.94 +  0x0187,0x0189,0x018a,0x018b,0x018b,0x018d,0x018e,0x018f,
  134.95 +  0x0190,0x0191,0x0191,0x0193,0x0194,0x01f6,0x0196,0x0197,
  134.96 +  0x0198,0x0198,0x023d,0x019b,0x019c,0x019d,0x0220,0x019f,
  134.97 +  0x01a0,0x01a0,0x01a2,0x01a2,0x01a4,0x01a4,0x01a6,0x01a7,
  134.98 +  0x01a7,0x01a9,0x01aa,0x01ab,0x01ac,0x01ac,0x01ae,0x01af,
  134.99 +  0x01af,0x01b1,0x01b2,0x01b3,0x01b3,0x01b5,0x01b5,0x01b7,
 134.100 +  0x01b8,0x01b8,0x01ba,0x01bb,0x01bc,0x01bc,0x01be,0x01f7,
 134.101 +  0x01c0,0x01c1,0x01c2,0x01c3,0x01c5,0x01c5,0x01c5,0x01c8,
 134.102 +  0x01c8,0x01c8,0x01cb,0x01cb,0x01cb,0x01cd,0x01cd,0x01cf,
 134.103 +  0x01cf,0x01d1,0x01d1,0x01d3,0x01d3,0x01d5,0x01d5,0x01d7,
 134.104 +  0x01d7,0x01d9,0x01d9,0x01db,0x01db,0x018e,0x01de,0x01de,
 134.105 +  0x01e0,0x01e0,0x01e2,0x01e2,0x01e4,0x01e4,0x01e6,0x01e6,
 134.106 +  0x01e8,0x01e8,0x01ea,0x01ea,0x01ec,0x01ec,0x01ee,0x01ee,
 134.107 +  0x01f0,0x01f2,0x01f2,0x01f2,0x01f4,0x01f4,0x01f6,0x01f7,
 134.108 +  0x01f8,0x01f8,0x01fa,0x01fa,0x01fc,0x01fc,0x01fe,0x01fe,
 134.109 +  0x0200,0x0200,0x0202,0x0202,0x0204,0x0204,0x0206,0x0206,
 134.110 +  0x0208,0x0208,0x020a,0x020a,0x020c,0x020c,0x020e,0x020e,
 134.111 +  0x0210,0x0210,0x0212,0x0212,0x0214,0x0214,0x0216,0x0216,
 134.112 +  0x0218,0x0218,0x021a,0x021a,0x021c,0x021c,0x021e,0x021e,
 134.113 +  0x0220,0x0221,0x0222,0x0222,0x0224,0x0224,0x0226,0x0226,
 134.114 +  0x0228,0x0228,0x022a,0x022a,0x022c,0x022c,0x022e,0x022e,
 134.115 +  0x0230,0x0230,0x0232,0x0232,0x0234,0x0235,0x0236,0x0237,
 134.116 +  0x0238,0x0239,0x023a,0x023b,0x023b,0x023d,0x023e,0x023f,
 134.117 +  0x0240,0x0241,0x0241,0x0243,0x0244,0x0245,0x0246,0x0246,
 134.118 +  0x0248,0x0248,0x024a,0x024a,0x024c,0x024c,0x024e,0x024e,
 134.119 +  0x0250,0x0251,0x0252,0x0181,0x0186,0x0255,0x0189,0x018a,
 134.120 +  0x0258,0x018f,0x025a,0x0190,0x025c,0x025d,0x025e,0x025f,
 134.121 +  0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,
 134.122 +  0x0197,0x0196,0x026a,0x2c62,0x026c,0x026d,0x026e,0x019c,
 134.123 +  0x0270,0x0271,0x019d,0x0273,0x0274,0x019f,0x0276,0x0277,
 134.124 +  0x0278,0x0279,0x027a,0x027b,0x027c,0x2c64,0x027e,0x027f,
 134.125 +  0x01a6,0x0281,0x0282,0x01a9,0x0284,0x0285,0x0286,0x0287,
 134.126 +  0x01ae,0x0244,0x01b1,0x01b2,0x0245,0x028d,0x028e,0x028f,
 134.127 +  0x0290,0x0291,0x01b7,0x0293,0x0294,0x0295,0x0296,0x0297,
 134.128 +  0x0298,0x0299,0x029a,0x029b,0x029c,0x029d,0x029e,0x029f,
 134.129 +  0x02a0,0x02a1,0x02a2,0x02a3,0x02a4,0x02a5,0x02a6,0x02a7,
 134.130 +  0x02a8,0x02a9,0x02aa,0x02ab,0x02ac,0x02ad,0x02ae,0x02af,
 134.131 +  0x02b0,0x02b1,0x02b2,0x02b3,0x02b4,0x02b5,0x02b6,0x02b7,
 134.132 +  0x02b8,0x02b9,0x02ba,0x02bb,0x02bc,0x02bd,0x02be,0x02bf,
 134.133 +  0x02c0,0x02c1,0x02c2,0x02c3,0x02c4,0x02c5,0x02c6,0x02c7,
 134.134 +  0x02c8,0x02c9,0x02ca,0x02cb,0x02cc,0x02cd,0x02ce,0x02cf,
 134.135 +  0x02d0,0x02d1,0x02d2,0x02d3,0x02d4,0x02d5,0x02d6,0x02d7,
 134.136 +  0x02d8,0x02d9,0x02da,0x02db,0x02dc,0x02dd,0x02de,0x02df,
 134.137 +  0x02e0,0x02e1,0x02e2,0x02e3,0x02e4,0x02e5,0x02e6,0x02e7,
 134.138 +  0x02e8,0x02e9,0x02ea,0x02eb,0x02ec,0x02ed,0x02ee,0x02ef,
 134.139 +  0x02f0,0x02f1,0x02f2,0x02f3,0x02f4,0x02f5,0x02f6,0x02f7,
 134.140 +  0x02f8,0x02f9,0x02fa,0x02fb,0x02fc,0x02fd,0x02fe,0x02ff,
 134.141 +  0x0300,0x0301,0x0302,0x0303,0x0304,0x0305,0x0306,0x0307,
 134.142 +  0x0308,0x0309,0x030a,0x030b,0x030c,0x030d,0x030e,0x030f,
 134.143 +  0x0310,0x0311,0x0312,0x0313,0x0314,0x0315,0x0316,0x0317,
 134.144 +  0x0318,0x0319,0x031a,0x031b,0x031c,0x031d,0x031e,0x031f,
 134.145 +  0x0320,0x0321,0x0322,0x0323,0x0324,0x0325,0x0326,0x0327,
 134.146 +  0x0328,0x0329,0x032a,0x032b,0x032c,0x032d,0x032e,0x032f,
 134.147 +  0x0330,0x0331,0x0332,0x0333,0x0334,0x0335,0x0336,0x0337,
 134.148 +  0x0338,0x0339,0x033a,0x033b,0x033c,0x033d,0x033e,0x033f,
 134.149 +  0x0340,0x0341,0x0342,0x0343,0x0344,0x0399,0x0346,0x0347,
 134.150 +  0x0348,0x0349,0x034a,0x034b,0x034c,0x034d,0x034e,0x034f,
 134.151 +  0x0350,0x0351,0x0352,0x0353,0x0354,0x0355,0x0356,0x0357,
 134.152 +  0x0358,0x0359,0x035a,0x035b,0x035c,0x035d,0x035e,0x035f,
 134.153 +  0x0360,0x0361,0x0362,0x0363,0x0364,0x0365,0x0366,0x0367,
 134.154 +  0x0368,0x0369,0x036a,0x036b,0x036c,0x036d,0x036e,0x036f,
 134.155 +  0x0370,0x0371,0x0372,0x0373,0x0374,0x0375,0x0376,0x0377,
 134.156 +  0x0378,0x0379,0x037a,0x03fd,0x03fe,0x03ff,0x037e,0x037f,
 134.157 +  0x0380,0x0381,0x0382,0x0383,0x0384,0x0385,0x0386,0x0387,
 134.158 +  0x0388,0x0389,0x038a,0x038b,0x038c,0x038d,0x038e,0x038f,
 134.159 +  0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
 134.160 +  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
 134.161 +  0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
 134.162 +  0x03a8,0x03a9,0x03aa,0x03ab,0x0386,0x0388,0x0389,0x038a,
 134.163 +  0x03b0,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
 134.164 +  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
 134.165 +  0x03a0,0x03a1,0x03a3,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
 134.166 +  0x03a8,0x03a9,0x03aa,0x03ab,0x038c,0x038e,0x038f,0x03cf,
 134.167 +  0x0392,0x0398,0x03d2,0x03d3,0x03d4,0x03a6,0x03a0,0x03d7,
 134.168 +  0x03d8,0x03d8,0x03da,0x03da,0x03dc,0x03dc,0x03de,0x03de,
 134.169 +  0x03e0,0x03e0,0x03e2,0x03e2,0x03e4,0x03e4,0x03e6,0x03e6,
 134.170 +  0x03e8,0x03e8,0x03ea,0x03ea,0x03ec,0x03ec,0x03ee,0x03ee,
 134.171 +  0x039a,0x03a1,0x03f9,0x03f3,0x03f4,0x0395,0x03f6,0x03f7,
 134.172 +  0x03f7,0x03f9,0x03fa,0x03fa,0x03fc,0x03fd,0x03fe,0x03ff,
 134.173 +  0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
 134.174 +  0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f,
 134.175 +  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
 134.176 +  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
 134.177 +  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
 134.178 +  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
 134.179 +  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
 134.180 +  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
 134.181 +  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
 134.182 +  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
 134.183 +  0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
 134.184 +  0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f,
 134.185 +  0x0460,0x0460,0x0462,0x0462,0x0464,0x0464,0x0466,0x0466,
 134.186 +  0x0468,0x0468,0x046a,0x046a,0x046c,0x046c,0x046e,0x046e,
 134.187 +  0x0470,0x0470,0x0472,0x0472,0x0474,0x0474,0x0476,0x0476,
 134.188 +  0x0478,0x0478,0x047a,0x047a,0x047c,0x047c,0x047e,0x047e,
 134.189 +  0x0480,0x0480,0x0482,0x0483,0x0484,0x0485,0x0486,0x0487,
 134.190 +  0x0488,0x0489,0x048a,0x048a,0x048c,0x048c,0x048e,0x048e,
 134.191 +  0x0490,0x0490,0x0492,0x0492,0x0494,0x0494,0x0496,0x0496,
 134.192 +  0x0498,0x0498,0x049a,0x049a,0x049c,0x049c,0x049e,0x049e,
 134.193 +  0x04a0,0x04a0,0x04a2,0x04a2,0x04a4,0x04a4,0x04a6,0x04a6,
 134.194 +  0x04a8,0x04a8,0x04aa,0x04aa,0x04ac,0x04ac,0x04ae,0x04ae,
 134.195 +  0x04b0,0x04b0,0x04b2,0x04b2,0x04b4,0x04b4,0x04b6,0x04b6,
 134.196 +  0x04b8,0x04b8,0x04ba,0x04ba,0x04bc,0x04bc,0x04be,0x04be,
 134.197 +  0x04c0,0x04c1,0x04c1,0x04c3,0x04c3,0x04c5,0x04c5,0x04c7,
 134.198 +  0x04c7,0x04c9,0x04c9,0x04cb,0x04cb,0x04cd,0x04cd,0x04c0,
 134.199 +  0x04d0,0x04d0,0x04d2,0x04d2,0x04d4,0x04d4,0x04d6,0x04d6,
 134.200 +  0x04d8,0x04d8,0x04da,0x04da,0x04dc,0x04dc,0x04de,0x04de,
 134.201 +  0x04e0,0x04e0,0x04e2,0x04e2,0x04e4,0x04e4,0x04e6,0x04e6,
 134.202 +  0x04e8,0x04e8,0x04ea,0x04ea,0x04ec,0x04ec,0x04ee,0x04ee,
 134.203 +  0x04f0,0x04f0,0x04f2,0x04f2,0x04f4,0x04f4,0x04f6,0x04f6,
 134.204 +  0x04f8,0x04f8,0x04fa,0x04fa,0x04fc,0x04fc,0x04fe,0x04fe,
 134.205 +  0x0500,0x0500,0x0502,0x0502,0x0504,0x0504,0x0506,0x0506,
 134.206 +  0x0508,0x0508,0x050a,0x050a,0x050c,0x050c,0x050e,0x050e,
 134.207 +  0x0510,0x0510,0x0512,0x0512,0x0514,0x0515,0x0516,0x0517,
 134.208 +  0x0518,0x0519,0x051a,0x051b,0x051c,0x051d,0x051e,0x051f,
 134.209 +  0x0520,0x0521,0x0522,0x0523,0x0524,0x0525,0x0526,0x0527,
 134.210 +  0x0528,0x0529,0x052a,0x052b,0x052c,0x052d,0x052e,0x052f,
 134.211 +  0x0530,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537,
 134.212 +  0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f,
 134.213 +  0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547,
 134.214 +  0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f,
 134.215 +  0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0557,
 134.216 +  0x0558,0x0559,0x055a,0x055b,0x055c,0x055d,0x055e,0x055f,
 134.217 +  0x0560,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537,
 134.218 +  0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f,
 134.219 +  0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547,
 134.220 +  0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f,
 134.221 +  0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0587,
 134.222 +  0x0588,0x0589,0x058a,0x058b,0x058c,0x058d,0x058e,0x058f,
 134.223 +  0x0590,0x0591,0x0592,0x0593,0x0594,0x0595,0x0596,0x0597,
 134.224 +  0x0598,0x0599,0x059a,0x059b,0x059c,0x059d,0x059e,0x059f,
 134.225 +  0x05a0,0x05a1,0x05a2,0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,
 134.226 +  0x05a8,0x05a9,0x05aa,0x05ab,0x05ac,0x05ad,0x05ae,0x05af,
 134.227 +  0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
 134.228 +  0x05b8,0x05b9,0x05ba,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
 134.229 +  0x05c0,0x05c1,0x05c2,0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,
 134.230 +  0x05c8,0x05c9,0x05ca,0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,
 134.231 +  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
 134.232 +  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
 134.233 +  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
 134.234 +  0x05e8,0x05e9,0x05ea,0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,
 134.235 +  0x05f0,0x05f1,0x05f2,0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,
 134.236 +  0x05f8,0x05f9,0x05fa,0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,
 134.237 +  0x0600,0x0601,0x0602,0x0603,0x0604,0x0605,0x0606,0x0607,
 134.238 +  0x0608,0x0609,0x060a,0x060b,0x060c,0x060d,0x060e,0x060f,
 134.239 +  0x0610,0x0611,0x0612,0x0613,0x0614,0x0615,0x0616,0x0617,
 134.240 +  0x0618,0x0619,0x061a,0x061b,0x061c,0x061d,0x061e,0x061f,
 134.241 +  0x0620,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
 134.242 +  0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
 134.243 +  0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
 134.244 +  0x0638,0x0639,0x063a,0x063b,0x063c,0x063d,0x063e,0x063f,
 134.245 +  0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
 134.246 +  0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
 134.247 +  0x0650,0x0651,0x0652,0x0653,0x0654,0x0655,0x0656,0x0657,
 134.248 +  0x0658,0x0659,0x065a,0x065b,0x065c,0x065d,0x065e,0x065f,
 134.249 +  0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
 134.250 +  0x0668,0x0669,0x066a,0x066b,0x066c,0x066d,0x066e,0x066f,
 134.251 +  0x0670,0x0671,0x0672,0x0673,0x0674,0x0675,0x0676,0x0677,
 134.252 +  0x0678,0x0679,0x067a,0x067b,0x067c,0x067d,0x067e,0x067f,
 134.253 +  0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0686,0x0687,
 134.254 +  0x0688,0x0689,0x068a,0x068b,0x068c,0x068d,0x068e,0x068f,
 134.255 +  0x0690,0x0691,0x0692,0x0693,0x0694,0x0695,0x0696,0x0697,
 134.256 +  0x0698,0x0699,0x069a,0x069b,0x069c,0x069d,0x069e,0x069f,
 134.257 +  0x06a0,0x06a1,0x06a2,0x06a3,0x06a4,0x06a5,0x06a6,0x06a7,
 134.258 +  0x06a8,0x06a9,0x06aa,0x06ab,0x06ac,0x06ad,0x06ae,0x06af,
 134.259 +  0x06b0,0x06b1,0x06b2,0x06b3,0x06b4,0x06b5,0x06b6,0x06b7,
 134.260 +  0x06b8,0x06b9,0x06ba,0x06bb,0x06bc,0x06bd,0x06be,0x06bf,
 134.261 +  0x06c0,0x06c1,0x06c2,0x06c3,0x06c4,0x06c5,0x06c6,0x06c7,
 134.262 +  0x06c8,0x06c9,0x06ca,0x06cb,0x06cc,0x06cd,0x06ce,0x06cf,
 134.263 +  0x06d0,0x06d1,0x06d2,0x06d3,0x06d4,0x06d5,0x06d6,0x06d7,
 134.264 +  0x06d8,0x06d9,0x06da,0x06db,0x06dc,0x06dd,0x06de,0x06df,
 134.265 +  0x06e0,0x06e1,0x06e2,0x06e3,0x06e4,0x06e5,0x06e6,0x06e7,
 134.266 +  0x06e8,0x06e9,0x06ea,0x06eb,0x06ec,0x06ed,0x06ee,0x06ef,
 134.267 +  0x06f0,0x06f1,0x06f2,0x06f3,0x06f4,0x06f5,0x06f6,0x06f7,
 134.268 +  0x06f8,0x06f9,0x06fa,0x06fb,0x06fc,0x06fd,0x06fe,0x06ff,
 134.269 +  0x0700,0x0701,0x0702,0x0703,0x0704,0x0705,0x0706,0x0707,
 134.270 +  0x0708,0x0709,0x070a,0x070b,0x070c,0x070d,0x070e,0x070f,
 134.271 +  0x0710,0x0711,0x0712,0x0713,0x0714,0x0715,0x0716,0x0717,
 134.272 +  0x0718,0x0719,0x071a,0x071b,0x071c,0x071d,0x071e,0x071f,
 134.273 +  0x0720,0x0721,0x0722,0x0723,0x0724,0x0725,0x0726,0x0727,
 134.274 +  0x0728,0x0729,0x072a,0x072b,0x072c,0x072d,0x072e,0x072f,
 134.275 +  0x0730,0x0731,0x0732,0x0733,0x0734,0x0735,0x0736,0x0737,
 134.276 +  0x0738,0x0739,0x073a,0x073b,0x073c,0x073d,0x073e,0x073f,
 134.277 +  0x0740,0x0741,0x0742,0x0743,0x0744,0x0745,0x0746,0x0747,
 134.278 +  0x0748,0x0749,0x074a,0x074b,0x074c,0x074d,0x074e,0x074f,
 134.279 +  0x0750,0x0751,0x0752,0x0753,0x0754,0x0755,0x0756,0x0757,
 134.280 +  0x0758,0x0759,0x075a,0x075b,0x075c,0x075d,0x075e,0x075f,
 134.281 +  0x0760,0x0761,0x0762,0x0763,0x0764,0x0765,0x0766,0x0767,
 134.282 +  0x0768,0x0769,0x076a,0x076b,0x076c,0x076d,0x076e,0x076f,
 134.283 +  0x0770,0x0771,0x0772,0x0773,0x0774,0x0775,0x0776,0x0777,
 134.284 +  0x0778,0x0779,0x077a,0x077b,0x077c,0x077d,0x077e,0x077f,
 134.285 +  0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0786,0x0787,
 134.286 +  0x0788,0x0789,0x078a,0x078b,0x078c,0x078d,0x078e,0x078f,
 134.287 +  0x0790,0x0791,0x0792,0x0793,0x0794,0x0795,0x0796,0x0797,
 134.288 +  0x0798,0x0799,0x079a,0x079b,0x079c,0x079d,0x079e,0x079f,
 134.289 +  0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a6,0x07a7,
 134.290 +  0x07a8,0x07a9,0x07aa,0x07ab,0x07ac,0x07ad,0x07ae,0x07af,
 134.291 +  0x07b0,0x07b1,0x07b2,0x07b3,0x07b4,0x07b5,0x07b6,0x07b7,
 134.292 +  0x07b8,0x07b9,0x07ba,0x07bb,0x07bc,0x07bd,0x07be,0x07bf,
 134.293 +  0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7,
 134.294 +  0x07c8,0x07c9,0x07ca,0x07cb,0x07cc,0x07cd,0x07ce,0x07cf,
 134.295 +  0x07d0,0x07d1,0x07d2,0x07d3,0x07d4,0x07d5,0x07d6,0x07d7,
 134.296 +  0x07d8,0x07d9,0x07da,0x07db,0x07dc,0x07dd,0x07de,0x07df,
 134.297 +  0x07e0,0x07e1,0x07e2,0x07e3,0x07e4,0x07e5,0x07e6,0x07e7,
 134.298 +  0x07e8,0x07e9,0x07ea,0x07eb,0x07ec,0x07ed,0x07ee,0x07ef,
 134.299 +  0x07f0,0x07f1,0x07f2,0x07f3,0x07f4,0x07f5,0x07f6,0x07f7,
 134.300 +  0x07f8,0x07f9,0x07fa,0x07fb,0x07fc,0x07fd,0x07fe,0x07ff,
 134.301 +  0x0800,0x0801,0x0802,0x0803,0x0804,0x0805,0x0806,0x0807,
 134.302 +  0x0808,0x0809,0x080a,0x080b,0x080c,0x080d,0x080e,0x080f,
 134.303 +  0x0810,0x0811,0x0812,0x0813,0x0814,0x0815,0x0816,0x0817,
 134.304 +  0x0818,0x0819,0x081a,0x081b,0x081c,0x081d,0x081e,0x081f,
 134.305 +  0x0820,0x0821,0x0822,0x0823,0x0824,0x0825,0x0826,0x0827,
 134.306 +  0x0828,0x0829,0x082a,0x082b,0x082c,0x082d,0x082e,0x082f,
 134.307 +  0x0830,0x0831,0x0832,0x0833,0x0834,0x0835,0x0836,0x0837,
 134.308 +  0x0838,0x0839,0x083a,0x083b,0x083c,0x083d,0x083e,0x083f,
 134.309 +  0x0840,0x0841,0x0842,0x0843,0x0844,0x0845,0x0846,0x0847,
 134.310 +  0x0848,0x0849,0x084a,0x084b,0x084c,0x084d,0x084e,0x084f,
 134.311 +  0x0850,0x0851,0x0852,0x0853,0x0854,0x0855,0x0856,0x0857,
 134.312 +  0x0858,0x0859,0x085a,0x085b,0x085c,0x085d,0x085e,0x085f,
 134.313 +  0x0860,0x0861,0x0862,0x0863,0x0864,0x0865,0x0866,0x0867,
 134.314 +  0x0868,0x0869,0x086a,0x086b,0x086c,0x086d,0x086e,0x086f,
 134.315 +  0x0870,0x0871,0x0872,0x0873,0x0874,0x0875,0x0876,0x0877,
 134.316 +  0x0878,0x0879,0x087a,0x087b,0x087c,0x087d,0x087e,0x087f,
 134.317 +  0x0880,0x0881,0x0882,0x0883,0x0884,0x0885,0x0886,0x0887,
 134.318 +  0x0888,0x0889,0x088a,0x088b,0x088c,0x088d,0x088e,0x088f,
 134.319 +  0x0890,0x0891,0x0892,0x0893,0x0894,0x0895,0x0896,0x0897,
 134.320 +  0x0898,0x0899,0x089a,0x089b,0x089c,0x089d,0x089e,0x089f,
 134.321 +  0x08a0,0x08a1,0x08a2,0x08a3,0x08a4,0x08a5,0x08a6,0x08a7,
 134.322 +  0x08a8,0x08a9,0x08aa,0x08ab,0x08ac,0x08ad,0x08ae,0x08af,
 134.323 +  0x08b0,0x08b1,0x08b2,0x08b3,0x08b4,0x08b5,0x08b6,0x08b7,
 134.324 +  0x08b8,0x08b9,0x08ba,0x08bb,0x08bc,0x08bd,0x08be,0x08bf,
 134.325 +  0x08c0,0x08c1,0x08c2,0x08c3,0x08c4,0x08c5,0x08c6,0x08c7,
 134.326 +  0x08c8,0x08c9,0x08ca,0x08cb,0x08cc,0x08cd,0x08ce,0x08cf,
 134.327 +  0x08d0,0x08d1,0x08d2,0x08d3,0x08d4,0x08d5,0x08d6,0x08d7,
 134.328 +  0x08d8,0x08d9,0x08da,0x08db,0x08dc,0x08dd,0x08de,0x08df,
 134.329 +  0x08e0,0x08e1,0x08e2,0x08e3,0x08e4,0x08e5,0x08e6,0x08e7,
 134.330 +  0x08e8,0x08e9,0x08ea,0x08eb,0x08ec,0x08ed,0x08ee,0x08ef,
 134.331 +  0x08f0,0x08f1,0x08f2,0x08f3,0x08f4,0x08f5,0x08f6,0x08f7,
 134.332 +  0x08f8,0x08f9,0x08fa,0x08fb,0x08fc,0x08fd,0x08fe,0x08ff,
 134.333 +  0x0900,0x0901,0x0902,0x0903,0x0904,0x0905,0x0906,0x0907,
 134.334 +  0x0908,0x0909,0x090a,0x090b,0x090c,0x090d,0x090e,0x090f,
 134.335 +  0x0910,0x0911,0x0912,0x0913,0x0914,0x0915,0x0916,0x0917,
 134.336 +  0x0918,0x0919,0x091a,0x091b,0x091c,0x091d,0x091e,0x091f,
 134.337 +  0x0920,0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,
 134.338 +  0x0928,0x0929,0x092a,0x092b,0x092c,0x092d,0x092e,0x092f,
 134.339 +  0x0930,0x0931,0x0932,0x0933,0x0934,0x0935,0x0936,0x0937,
 134.340 +  0x0938,0x0939,0x093a,0x093b,0x093c,0x093d,0x093e,0x093f,
 134.341 +  0x0940,0x0941,0x0942,0x0943,0x0944,0x0945,0x0946,0x0947,
 134.342 +  0x0948,0x0949,0x094a,0x094b,0x094c,0x094d,0x094e,0x094f,
 134.343 +  0x0950,0x0951,0x0952,0x0953,0x0954,0x0955,0x0956,0x0957,
 134.344 +  0x0958,0x0959,0x095a,0x095b,0x095c,0x095d,0x095e,0x095f,
 134.345 +  0x0960,0x0961,0x0962,0x0963,0x0964,0x0965,0x0966,0x0967,
 134.346 +  0x0968,0x0969,0x096a,0x096b,0x096c,0x096d,0x096e,0x096f,
 134.347 +  0x0970,0x0971,0x0972,0x0973,0x0974,0x0975,0x0976,0x0977,
 134.348 +  0x0978,0x0979,0x097a,0x097b,0x097c,0x097d,0x097e,0x097f,
 134.349 +  0x0980,0x0981,0x0982,0x0983,0x0984,0x0985,0x0986,0x0987,
 134.350 +  0x0988,0x0989,0x098a,0x098b,0x098c,0x098d,0x098e,0x098f,
 134.351 +  0x0990,0x0991,0x0992,0x0993,0x0994,0x0995,0x0996,0x0997,
 134.352 +  0x0998,0x0999,0x099a,0x099b,0x099c,0x099d,0x099e,0x099f,
 134.353 +  0x09a0,0x09a1,0x09a2,0x09a3,0x09a4,0x09a5,0x09a6,0x09a7,
 134.354 +  0x09a8,0x09a9,0x09aa,0x09ab,0x09ac,0x09ad,0x09ae,0x09af,
 134.355 +  0x09b0,0x09b1,0x09b2,0x09b3,0x09b4,0x09b5,0x09b6,0x09b7,
 134.356 +  0x09b8,0x09b9,0x09ba,0x09bb,0x09bc,0x09bd,0x09be,0x09bf,
 134.357 +  0x09c0,0x09c1,0x09c2,0x09c3,0x09c4,0x09c5,0x09c6,0x09c7,
 134.358 +  0x09c8,0x09c9,0x09ca,0x09cb,0x09cc,0x09cd,0x09ce,0x09cf,
 134.359 +  0x09d0,0x09d1,0x09d2,0x09d3,0x09d4,0x09d5,0x09d6,0x09d7,
 134.360 +  0x09d8,0x09d9,0x09da,0x09db,0x09dc,0x09dd,0x09de,0x09df,
 134.361 +  0x09e0,0x09e1,0x09e2,0x09e3,0x09e4,0x09e5,0x09e6,0x09e7,
 134.362 +  0x09e8,0x09e9,0x09ea,0x09eb,0x09ec,0x09ed,0x09ee,0x09ef,
 134.363 +  0x09f0,0x09f1,0x09f2,0x09f3,0x09f4,0x09f5,0x09f6,0x09f7,
 134.364 +  0x09f8,0x09f9,0x09fa,0x09fb,0x09fc,0x09fd,0x09fe,0x09ff,
 134.365 +  0x0a00,0x0a01,0x0a02,0x0a03,0x0a04,0x0a05,0x0a06,0x0a07,
 134.366 +  0x0a08,0x0a09,0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,
 134.367 +  0x0a10,0x0a11,0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,
 134.368 +  0x0a18,0x0a19,0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,
 134.369 +  0x0a20,0x0a21,0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,
 134.370 +  0x0a28,0x0a29,0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,
 134.371 +  0x0a30,0x0a31,0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,
 134.372 +  0x0a38,0x0a39,0x0a3a,0x0a3b,0x0a3c,0x0a3d,0x0a3e,0x0a3f,
 134.373 +  0x0a40,0x0a41,0x0a42,0x0a43,0x0a44,0x0a45,0x0a46,0x0a47,
 134.374 +  0x0a48,0x0a49,0x0a4a,0x0a4b,0x0a4c,0x0a4d,0x0a4e,0x0a4f,
 134.375 +  0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,0x0a56,0x0a57,
 134.376 +  0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,0x0a5e,0x0a5f,
 134.377 +  0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,0x0a66,0x0a67,
 134.378 +  0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,0x0a6e,0x0a6f,
 134.379 +  0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,0x0a76,0x0a77,
 134.380 +  0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,0x0a7e,0x0a7f,
 134.381 +  0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,0x0a86,0x0a87,
 134.382 +  0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,0x0a8e,0x0a8f,
 134.383 +  0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,0x0a96,0x0a97,
 134.384 +  0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,0x0a9e,0x0a9f,
 134.385 +  0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,0x0aa6,0x0aa7,
 134.386 +  0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,0x0aae,0x0aaf,
 134.387 +  0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,0x0ab6,0x0ab7,
 134.388 +  0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,0x0abe,0x0abf,
 134.389 +  0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,0x0ac6,0x0ac7,
 134.390 +  0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,0x0ace,0x0acf,
 134.391 +  0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,0x0ad6,0x0ad7,
 134.392 +  0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,0x0ade,0x0adf,
 134.393 +  0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,0x0ae6,0x0ae7,
 134.394 +  0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,0x0aee,0x0aef,
 134.395 +  0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,0x0af6,0x0af7,
 134.396 +  0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,0x0afe,0x0aff,
 134.397 +  0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,0x0b06,0x0b07,
 134.398 +  0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,0x0b0e,0x0b0f,
 134.399 +  0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,0x0b16,0x0b17,
 134.400 +  0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,0x0b1e,0x0b1f,
 134.401 +  0x0b20,0x0b21,0x0b22,0x0b23,0x0b24,0x0b25,0x0b26,0x0b27,
 134.402 +  0x0b28,0x0b29,0x0b2a,0x0b2b,0x0b2c,0x0b2d,0x0b2e,0x0b2f,
 134.403 +  0x0b30,0x0b31,0x0b32,0x0b33,0x0b34,0x0b35,0x0b36,0x0b37,
 134.404 +  0x0b38,0x0b39,0x0b3a,0x0b3b,0x0b3c,0x0b3d,0x0b3e,0x0b3f,
 134.405 +  0x0b40,0x0b41,0x0b42,0x0b43,0x0b44,0x0b45,0x0b46,0x0b47,
 134.406 +  0x0b48,0x0b49,0x0b4a,0x0b4b,0x0b4c,0x0b4d,0x0b4e,0x0b4f,
 134.407 +  0x0b50,0x0b51,0x0b52,0x0b53,0x0b54,0x0b55,0x0b56,0x0b57,
 134.408 +  0x0b58,0x0b59,0x0b5a,0x0b5b,0x0b5c,0x0b5d,0x0b5e,0x0b5f,
 134.409 +  0x0b60,0x0b61,0x0b62,0x0b63,0x0b64,0x0b65,0x0b66,0x0b67,
 134.410 +  0x0b68,0x0b69,0x0b6a,0x0b6b,0x0b6c,0x0b6d,0x0b6e,0x0b6f,
 134.411 +  0x0b70,0x0b71,0x0b72,0x0b73,0x0b74,0x0b75,0x0b76,0x0b77,
 134.412 +  0x0b78,0x0b79,0x0b7a,0x0b7b,0x0b7c,0x0b7d,0x0b7e,0x0b7f,
 134.413 +  0x0b80,0x0b81,0x0b82,0x0b83,0x0b84,0x0b85,0x0b86,0x0b87,
 134.414 +  0x0b88,0x0b89,0x0b8a,0x0b8b,0x0b8c,0x0b8d,0x0b8e,0x0b8f,
 134.415 +  0x0b90,0x0b91,0x0b92,0x0b93,0x0b94,0x0b95,0x0b96,0x0b97,
 134.416 +  0x0b98,0x0b99,0x0b9a,0x0b9b,0x0b9c,0x0b9d,0x0b9e,0x0b9f,
 134.417 +  0x0ba0,0x0ba1,0x0ba2,0x0ba3,0x0ba4,0x0ba5,0x0ba6,0x0ba7,
 134.418 +  0x0ba8,0x0ba9,0x0baa,0x0bab,0x0bac,0x0bad,0x0bae,0x0baf,
 134.419 +  0x0bb0,0x0bb1,0x0bb2,0x0bb3,0x0bb4,0x0bb5,0x0bb6,0x0bb7,
 134.420 +  0x0bb8,0x0bb9,0x0bba,0x0bbb,0x0bbc,0x0bbd,0x0bbe,0x0bbf,
 134.421 +  0x0bc0,0x0bc1,0x0bc2,0x0bc3,0x0bc4,0x0bc5,0x0bc6,0x0bc7,
 134.422 +  0x0bc8,0x0bc9,0x0bca,0x0bcb,0x0bcc,0x0bcd,0x0bce,0x0bcf,
 134.423 +  0x0bd0,0x0bd1,0x0bd2,0x0bd3,0x0bd4,0x0bd5,0x0bd6,0x0bd7,
 134.424 +  0x0bd8,0x0bd9,0x0bda,0x0bdb,0x0bdc,0x0bdd,0x0bde,0x0bdf,
 134.425 +  0x0be0,0x0be1,0x0be2,0x0be3,0x0be4,0x0be5,0x0be6,0x0be7,
 134.426 +  0x0be8,0x0be9,0x0bea,0x0beb,0x0bec,0x0bed,0x0bee,0x0bef,
 134.427 +  0x0bf0,0x0bf1,0x0bf2,0x0bf3,0x0bf4,0x0bf5,0x0bf6,0x0bf7,
 134.428 +  0x0bf8,0x0bf9,0x0bfa,0x0bfb,0x0bfc,0x0bfd,0x0bfe,0x0bff,
 134.429 +  0x0c00,0x0c01,0x0c02,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,
 134.430 +  0x0c08,0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,
 134.431 +  0x0c10,0x0c11,0x0c12,0x0c13,0x0c14,0x0c15,0x0c16,0x0c17,
 134.432 +  0x0c18,0x0c19,0x0c1a,0x0c1b,0x0c1c,0x0c1d,0x0c1e,0x0c1f,
 134.433 +  0x0c20,0x0c21,0x0c22,0x0c23,0x0c24,0x0c25,0x0c26,0x0c27,
 134.434 +  0x0c28,0x0c29,0x0c2a,0x0c2b,0x0c2c,0x0c2d,0x0c2e,0x0c2f,
 134.435 +  0x0c30,0x0c31,0x0c32,0x0c33,0x0c34,0x0c35,0x0c36,0x0c37,
 134.436 +  0x0c38,0x0c39,0x0c3a,0x0c3b,0x0c3c,0x0c3d,0x0c3e,0x0c3f,
 134.437 +  0x0c40,0x0c41,0x0c42,0x0c43,0x0c44,0x0c45,0x0c46,0x0c47,
 134.438 +  0x0c48,0x0c49,0x0c4a,0x0c4b,0x0c4c,0x0c4d,0x0c4e,0x0c4f,
 134.439 +  0x0c50,0x0c51,0x0c52,0x0c53,0x0c54,0x0c55,0x0c56,0x0c57,
 134.440 +  0x0c58,0x0c59,0x0c5a,0x0c5b,0x0c5c,0x0c5d,0x0c5e,0x0c5f,
 134.441 +  0x0c60,0x0c61,0x0c62,0x0c63,0x0c64,0x0c65,0x0c66,0x0c67,
 134.442 +  0x0c68,0x0c69,0x0c6a,0x0c6b,0x0c6c,0x0c6d,0x0c6e,0x0c6f,
 134.443 +  0x0c70,0x0c71,0x0c72,0x0c73,0x0c74,0x0c75,0x0c76,0x0c77,
 134.444 +  0x0c78,0x0c79,0x0c7a,0x0c7b,0x0c7c,0x0c7d,0x0c7e,0x0c7f,
 134.445 +  0x0c80,0x0c81,0x0c82,0x0c83,0x0c84,0x0c85,0x0c86,0x0c87,
 134.446 +  0x0c88,0x0c89,0x0c8a,0x0c8b,0x0c8c,0x0c8d,0x0c8e,0x0c8f,
 134.447 +  0x0c90,0x0c91,0x0c92,0x0c93,0x0c94,0x0c95,0x0c96,0x0c97,
 134.448 +  0x0c98,0x0c99,0x0c9a,0x0c9b,0x0c9c,0x0c9d,0x0c9e,0x0c9f,
 134.449 +  0x0ca0,0x0ca1,0x0ca2,0x0ca3,0x0ca4,0x0ca5,0x0ca6,0x0ca7,
 134.450 +  0x0ca8,0x0ca9,0x0caa,0x0cab,0x0cac,0x0cad,0x0cae,0x0caf,
 134.451 +  0x0cb0,0x0cb1,0x0cb2,0x0cb3,0x0cb4,0x0cb5,0x0cb6,0x0cb7,
 134.452 +  0x0cb8,0x0cb9,0x0cba,0x0cbb,0x0cbc,0x0cbd,0x0cbe,0x0cbf,
 134.453 +  0x0cc0,0x0cc1,0x0cc2,0x0cc3,0x0cc4,0x0cc5,0x0cc6,0x0cc7,
 134.454 +  0x0cc8,0x0cc9,0x0cca,0x0ccb,0x0ccc,0x0ccd,0x0cce,0x0ccf,
 134.455 +  0x0cd0,0x0cd1,0x0cd2,0x0cd3,0x0cd4,0x0cd5,0x0cd6,0x0cd7,
 134.456 +  0x0cd8,0x0cd9,0x0cda,0x0cdb,0x0cdc,0x0cdd,0x0cde,0x0cdf,
 134.457 +  0x0ce0,0x0ce1,0x0ce2,0x0ce3,0x0ce4,0x0ce5,0x0ce6,0x0ce7,
 134.458 +  0x0ce8,0x0ce9,0x0cea,0x0ceb,0x0cec,0x0ced,0x0cee,0x0cef,
 134.459 +  0x0cf0,0x0cf1,0x0cf2,0x0cf3,0x0cf4,0x0cf5,0x0cf6,0x0cf7,
 134.460 +  0x0cf8,0x0cf9,0x0cfa,0x0cfb,0x0cfc,0x0cfd,0x0cfe,0x0cff,
 134.461 +  0x0d00,0x0d01,0x0d02,0x0d03,0x0d04,0x0d05,0x0d06,0x0d07,
 134.462 +  0x0d08,0x0d09,0x0d0a,0x0d0b,0x0d0c,0x0d0d,0x0d0e,0x0d0f,
 134.463 +  0x0d10,0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,
 134.464 +  0x0d18,0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x0d1f,
 134.465 +  0x0d20,0x0d21,0x0d22,0x0d23,0x0d24,0x0d25,0x0d26,0x0d27,
 134.466 +  0x0d28,0x0d29,0x0d2a,0x0d2b,0x0d2c,0x0d2d,0x0d2e,0x0d2f,
 134.467 +  0x0d30,0x0d31,0x0d32,0x0d33,0x0d34,0x0d35,0x0d36,0x0d37,
 134.468 +  0x0d38,0x0d39,0x0d3a,0x0d3b,0x0d3c,0x0d3d,0x0d3e,0x0d3f,
 134.469 +  0x0d40,0x0d41,0x0d42,0x0d43,0x0d44,0x0d45,0x0d46,0x0d47,
 134.470 +  0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,0x0d4e,0x0d4f,
 134.471 +  0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,0x0d56,0x0d57,
 134.472 +  0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,0x0d5e,0x0d5f,
 134.473 +  0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,0x0d66,0x0d67,
 134.474 +  0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,0x0d6e,0x0d6f,
 134.475 +  0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,0x0d76,0x0d77,
 134.476 +  0x0d78,0x0d79,0x0d7a,0x0d7b,0x0d7c,0x0d7d,0x0d7e,0x0d7f,
 134.477 +  0x0d80,0x0d81,0x0d82,0x0d83,0x0d84,0x0d85,0x0d86,0x0d87,
 134.478 +  0x0d88,0x0d89,0x0d8a,0x0d8b,0x0d8c,0x0d8d,0x0d8e,0x0d8f,
 134.479 +  0x0d90,0x0d91,0x0d92,0x0d93,0x0d94,0x0d95,0x0d96,0x0d97,
 134.480 +  0x0d98,0x0d99,0x0d9a,0x0d9b,0x0d9c,0x0d9d,0x0d9e,0x0d9f,
 134.481 +  0x0da0,0x0da1,0x0da2,0x0da3,0x0da4,0x0da5,0x0da6,0x0da7,
 134.482 +  0x0da8,0x0da9,0x0daa,0x0dab,0x0dac,0x0dad,0x0dae,0x0daf,
 134.483 +  0x0db0,0x0db1,0x0db2,0x0db3,0x0db4,0x0db5,0x0db6,0x0db7,
 134.484 +  0x0db8,0x0db9,0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,
 134.485 +  0x0dc0,0x0dc1,0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,
 134.486 +  0x0dc8,0x0dc9,0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,
 134.487 +  0x0dd0,0x0dd1,0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,
 134.488 +  0x0dd8,0x0dd9,0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,
 134.489 +  0x0de0,0x0de1,0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,
 134.490 +  0x0de8,0x0de9,0x0dea,0x0deb,0x0dec,0x0ded,0x0dee,0x0def,
 134.491 +  0x0df0,0x0df1,0x0df2,0x0df3,0x0df4,0x0df5,0x0df6,0x0df7,
 134.492 +  0x0df8,0x0df9,0x0dfa,0x0dfb,0x0dfc,0x0dfd,0x0dfe,0x0dff,
 134.493 +  0x0e00,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
 134.494 +  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
 134.495 +  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
 134.496 +  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
 134.497 +  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
 134.498 +  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
 134.499 +  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
 134.500 +  0x0e38,0x0e39,0x0e3a,0x0e3b,0x0e3c,0x0e3d,0x0e3e,0x0e3f,
 134.501 +  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
 134.502 +  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
 134.503 +  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
 134.504 +  0x0e58,0x0e59,0x0e5a,0x0e5b,0x0e5c,0x0e5d,0x0e5e,0x0e5f,
 134.505 +  0x0e60,0x0e61,0x0e62,0x0e63,0x0e64,0x0e65,0x0e66,0x0e67,
 134.506 +  0x0e68,0x0e69,0x0e6a,0x0e6b,0x0e6c,0x0e6d,0x0e6e,0x0e6f,
 134.507 +  0x0e70,0x0e71,0x0e72,0x0e73,0x0e74,0x0e75,0x0e76,0x0e77,
 134.508 +  0x0e78,0x0e79,0x0e7a,0x0e7b,0x0e7c,0x0e7d,0x0e7e,0x0e7f,
 134.509 +  0x0e80,0x0e81,0x0e82,0x0e83,0x0e84,0x0e85,0x0e86,0x0e87,
 134.510 +  0x0e88,0x0e89,0x0e8a,0x0e8b,0x0e8c,0x0e8d,0x0e8e,0x0e8f,
 134.511 +  0x0e90,0x0e91,0x0e92,0x0e93,0x0e94,0x0e95,0x0e96,0x0e97,
 134.512 +  0x0e98,0x0e99,0x0e9a,0x0e9b,0x0e9c,0x0e9d,0x0e9e,0x0e9f,
 134.513 +  0x0ea0,0x0ea1,0x0ea2,0x0ea3,0x0ea4,0x0ea5,0x0ea6,0x0ea7,
 134.514 +  0x0ea8,0x0ea9,0x0eaa,0x0eab,0x0eac,0x0ead,0x0eae,0x0eaf,
 134.515 +  0x0eb0,0x0eb1,0x0eb2,0x0eb3,0x0eb4,0x0eb5,0x0eb6,0x0eb7,
 134.516 +  0x0eb8,0x0eb9,0x0eba,0x0ebb,0x0ebc,0x0ebd,0x0ebe,0x0ebf,
 134.517 +  0x0ec0,0x0ec1,0x0ec2,0x0ec3,0x0ec4,0x0ec5,0x0ec6,0x0ec7,
 134.518 +  0x0ec8,0x0ec9,0x0eca,0x0ecb,0x0ecc,0x0ecd,0x0ece,0x0ecf,
 134.519 +  0x0ed0,0x0ed1,0x0ed2,0x0ed3,0x0ed4,0x0ed5,0x0ed6,0x0ed7,
 134.520 +  0x0ed8,0x0ed9,0x0eda,0x0edb,0x0edc,0x0edd,0x0ede,0x0edf,
 134.521 +  0x0ee0,0x0ee1,0x0ee2,0x0ee3,0x0ee4,0x0ee5,0x0ee6,0x0ee7,
 134.522 +  0x0ee8,0x0ee9,0x0eea,0x0eeb,0x0eec,0x0eed,0x0eee,0x0eef,
 134.523 +  0x0ef0,0x0ef1,0x0ef2,0x0ef3,0x0ef4,0x0ef5,0x0ef6,0x0ef7,
 134.524 +  0x0ef8,0x0ef9,0x0efa,0x0efb,0x0efc,0x0efd,0x0efe,0x0eff,
 134.525 +  0x0f00,0x0f01,0x0f02,0x0f03,0x0f04,0x0f05,0x0f06,0x0f07,
 134.526 +  0x0f08,0x0f09,0x0f0a,0x0f0b,0x0f0c,0x0f0d,0x0f0e,0x0f0f,
 134.527 +  0x0f10,0x0f11,0x0f12,0x0f13,0x0f14,0x0f15,0x0f16,0x0f17,
 134.528 +  0x0f18,0x0f19,0x0f1a,0x0f1b,0x0f1c,0x0f1d,0x0f1e,0x0f1f,
 134.529 +  0x0f20,0x0f21,0x0f22,0x0f23,0x0f24,0x0f25,0x0f26,0x0f27,
 134.530 +  0x0f28,0x0f29,0x0f2a,0x0f2b,0x0f2c,0x0f2d,0x0f2e,0x0f2f,
 134.531 +  0x0f30,0x0f31,0x0f32,0x0f33,0x0f34,0x0f35,0x0f36,0x0f37,
 134.532 +  0x0f38,0x0f39,0x0f3a,0x0f3b,0x0f3c,0x0f3d,0x0f3e,0x0f3f,
 134.533 +  0x0f40,0x0f41,0x0f42,0x0f43,0x0f44,0x0f45,0x0f46,0x0f47,
 134.534 +  0x0f48,0x0f49,0x0f4a,0x0f4b,0x0f4c,0x0f4d,0x0f4e,0x0f4f,
 134.535 +  0x0f50,0x0f51,0x0f52,0x0f53,0x0f54,0x0f55,0x0f56,0x0f57,
 134.536 +  0x0f58,0x0f59,0x0f5a,0x0f5b,0x0f5c,0x0f5d,0x0f5e,0x0f5f,
 134.537 +  0x0f60,0x0f61,0x0f62,0x0f63,0x0f64,0x0f65,0x0f66,0x0f67,
 134.538 +  0x0f68,0x0f69,0x0f6a,0x0f6b,0x0f6c,0x0f6d,0x0f6e,0x0f6f,
 134.539 +  0x0f70,0x0f71,0x0f72,0x0f73,0x0f74,0x0f75,0x0f76,0x0f77,
 134.540 +  0x0f78,0x0f79,0x0f7a,0x0f7b,0x0f7c,0x0f7d,0x0f7e,0x0f7f,
 134.541 +  0x0f80,0x0f81,0x0f82,0x0f83,0x0f84,0x0f85,0x0f86,0x0f87,
 134.542 +  0x0f88,0x0f89,0x0f8a,0x0f8b,0x0f8c,0x0f8d,0x0f8e,0x0f8f,
 134.543 +  0x0f90,0x0f91,0x0f92,0x0f93,0x0f94,0x0f95,0x0f96,0x0f97,
 134.544 +  0x0f98,0x0f99,0x0f9a,0x0f9b,0x0f9c,0x0f9d,0x0f9e,0x0f9f,
 134.545 +  0x0fa0,0x0fa1,0x0fa2,0x0fa3,0x0fa4,0x0fa5,0x0fa6,0x0fa7,
 134.546 +  0x0fa8,0x0fa9,0x0faa,0x0fab,0x0fac,0x0fad,0x0fae,0x0faf,
 134.547 +  0x0fb0,0x0fb1,0x0fb2,0x0fb3,0x0fb4,0x0fb5,0x0fb6,0x0fb7,
 134.548 +  0x0fb8,0x0fb9,0x0fba,0x0fbb,0x0fbc,0x0fbd,0x0fbe,0x0fbf,
 134.549 +  0x0fc0,0x0fc1,0x0fc2,0x0fc3,0x0fc4,0x0fc5,0x0fc6,0x0fc7,
 134.550 +  0x0fc8,0x0fc9,0x0fca,0x0fcb,0x0fcc,0x0fcd,0x0fce,0x0fcf,
 134.551 +  0x0fd0,0x0fd1,0x0fd2,0x0fd3,0x0fd4,0x0fd5,0x0fd6,0x0fd7,
 134.552 +  0x0fd8,0x0fd9,0x0fda,0x0fdb,0x0fdc,0x0fdd,0x0fde,0x0fdf,
 134.553 +  0x0fe0,0x0fe1,0x0fe2,0x0fe3,0x0fe4,0x0fe5,0x0fe6,0x0fe7,
 134.554 +  0x0fe8,0x0fe9,0x0fea,0x0feb,0x0fec,0x0fed,0x0fee,0x0fef,
 134.555 +  0x0ff0,0x0ff1,0x0ff2,0x0ff3,0x0ff4,0x0ff5,0x0ff6,0x0ff7,
 134.556 +  0x0ff8,0x0ff9,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,
 134.557 +  0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007,
 134.558 +  0x1008,0x1009,0x100a,0x100b,0x100c,0x100d,0x100e,0x100f,
 134.559 +  0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017,
 134.560 +  0x1018,0x1019,0x101a,0x101b,0x101c,0x101d,0x101e,0x101f,
 134.561 +  0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027,
 134.562 +  0x1028,0x1029,0x102a,0x102b,0x102c,0x102d,0x102e,0x102f,
 134.563 +  0x1030,0x1031,0x1032,0x1033,0x1034,0x1035,0x1036,0x1037,
 134.564 +  0x1038,0x1039,0x103a,0x103b,0x103c,0x103d,0x103e,0x103f,
 134.565 +  0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047,
 134.566 +  0x1048,0x1049,0x104a,0x104b,0x104c,0x104d,0x104e,0x104f,
 134.567 +  0x1050,0x1051,0x1052,0x1053,0x1054,0x1055,0x1056,0x1057,
 134.568 +  0x1058,0x1059,0x105a,0x105b,0x105c,0x105d,0x105e,0x105f,
 134.569 +  0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
 134.570 +  0x1068,0x1069,0x106a,0x106b,0x106c,0x106d,0x106e,0x106f,
 134.571 +  0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
 134.572 +  0x1078,0x1079,0x107a,0x107b,0x107c,0x107d,0x107e,0x107f,
 134.573 +  0x1080,0x1081,0x1082,0x1083,0x1084,0x1085,0x1086,0x1087,
 134.574 +  0x1088,0x1089,0x108a,0x108b,0x108c,0x108d,0x108e,0x108f,
 134.575 +  0x1090,0x1091,0x1092,0x1093,0x1094,0x1095,0x1096,0x1097,
 134.576 +  0x1098,0x1099,0x109a,0x109b,0x109c,0x109d,0x109e,0x109f,
 134.577 +  0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7,
 134.578 +  0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af,
 134.579 +  0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7,
 134.580 +  0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf,
 134.581 +  0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5,0x10c6,0x10c7,
 134.582 +  0x10c8,0x10c9,0x10ca,0x10cb,0x10cc,0x10cd,0x10ce,0x10cf,
 134.583 +  0x10d0,0x10d1,0x10d2,0x10d3,0x10d4,0x10d5,0x10d6,0x10d7,
 134.584 +  0x10d8,0x10d9,0x10da,0x10db,0x10dc,0x10dd,0x10de,0x10df,
 134.585 +  0x10e0,0x10e1,0x10e2,0x10e3,0x10e4,0x10e5,0x10e6,0x10e7,
 134.586 +  0x10e8,0x10e9,0x10ea,0x10eb,0x10ec,0x10ed,0x10ee,0x10ef,
 134.587 +  0x10f0,0x10f1,0x10f2,0x10f3,0x10f4,0x10f5,0x10f6,0x10f7,
 134.588 +  0x10f8,0x10f9,0x10fa,0x10fb,0x10fc,0x10fd,0x10fe,0x10ff,
 134.589 +  0x1100,0x1101,0x1102,0x1103,0x1104,0x1105,0x1106,0x1107,
 134.590 +  0x1108,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f,
 134.591 +  0x1110,0x1111,0x1112,0x1113,0x1114,0x1115,0x1116,0x1117,
 134.592 +  0x1118,0x1119,0x111a,0x111b,0x111c,0x111d,0x111e,0x111f,
 134.593 +  0x1120,0x1121,0x1122,0x1123,0x1124,0x1125,0x1126,0x1127,
 134.594 +  0x1128,0x1129,0x112a,0x112b,0x112c,0x112d,0x112e,0x112f,
 134.595 +  0x1130,0x1131,0x1132,0x1133,0x1134,0x1135,0x1136,0x1137,
 134.596 +  0x1138,0x1139,0x113a,0x113b,0x113c,0x113d,0x113e,0x113f,
 134.597 +  0x1140,0x1141,0x1142,0x1143,0x1144,0x1145,0x1146,0x1147,
 134.598 +  0x1148,0x1149,0x114a,0x114b,0x114c,0x114d,0x114e,0x114f,
 134.599 +  0x1150,0x1151,0x1152,0x1153,0x1154,0x1155,0x1156,0x1157,
 134.600 +  0x1158,0x1159,0x115a,0x115b,0x115c,0x115d,0x115e,0x115f,
 134.601 +  0x1160,0x1161,0x1162,0x1163,0x1164,0x1165,0x1166,0x1167,
 134.602 +  0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,0x116e,0x116f,
 134.603 +  0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,0x1176,0x1177,
 134.604 +  0x1178,0x1179,0x117a,0x117b,0x117c,0x117d,0x117e,0x117f,
 134.605 +  0x1180,0x1181,0x1182,0x1183,0x1184,0x1185,0x1186,0x1187,
 134.606 +  0x1188,0x1189,0x118a,0x118b,0x118c,0x118d,0x118e,0x118f,
 134.607 +  0x1190,0x1191,0x1192,0x1193,0x1194,0x1195,0x1196,0x1197,
 134.608 +  0x1198,0x1199,0x119a,0x119b,0x119c,0x119d,0x119e,0x119f,
 134.609 +  0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a7,
 134.610 +  0x11a8,0x11a9,0x11aa,0x11ab,0x11ac,0x11ad,0x11ae,0x11af,
 134.611 +  0x11b0,0x11b1,0x11b2,0x11b3,0x11b4,0x11b5,0x11b6,0x11b7,
 134.612 +  0x11b8,0x11b9,0x11ba,0x11bb,0x11bc,0x11bd,0x11be,0x11bf,
 134.613 +  0x11c0,0x11c1,0x11c2,0x11c3,0x11c4,0x11c5,0x11c6,0x11c7,
 134.614 +  0x11c8,0x11c9,0x11ca,0x11cb,0x11cc,0x11cd,0x11ce,0x11cf,
 134.615 +  0x11d0,0x11d1,0x11d2,0x11d3,0x11d4,0x11d5,0x11d6,0x11d7,
 134.616 +  0x11d8,0x11d9,0x11da,0x11db,0x11dc,0x11dd,0x11de,0x11df,
 134.617 +  0x11e0,0x11e1,0x11e2,0x11e3,0x11e4,0x11e5,0x11e6,0x11e7,
 134.618 +  0x11e8,0x11e9,0x11ea,0x11eb,0x11ec,0x11ed,0x11ee,0x11ef,
 134.619 +  0x11f0,0x11f1,0x11f2,0x11f3,0x11f4,0x11f5,0x11f6,0x11f7,
 134.620 +  0x11f8,0x11f9,0x11fa,0x11fb,0x11fc,0x11fd,0x11fe,0x11ff,
 134.621 +  0x1200,0x1201,0x1202,0x1203,0x1204,0x1205,0x1206,0x1207,
 134.622 +  0x1208,0x1209,0x120a,0x120b,0x120c,0x120d,0x120e,0x120f,
 134.623 +  0x1210,0x1211,0x1212,0x1213,0x1214,0x1215,0x1216,0x1217,
 134.624 +  0x1218,0x1219,0x121a,0x121b,0x121c,0x121d,0x121e,0x121f,
 134.625 +  0x1220,0x1221,0x1222,0x1223,0x1224,0x1225,0x1226,0x1227,
 134.626 +  0x1228,0x1229,0x122a,0x122b,0x122c,0x122d,0x122e,0x122f,
 134.627 +  0x1230,0x1231,0x1232,0x1233,0x1234,0x1235,0x1236,0x1237,
 134.628 +  0x1238,0x1239,0x123a,0x123b,0x123c,0x123d,0x123e,0x123f,
 134.629 +  0x1240,0x1241,0x1242,0x1243,0x1244,0x1245,0x1246,0x1247,
 134.630 +  0x1248,0x1249,0x124a,0x124b,0x124c,0x124d,0x124e,0x124f,
 134.631 +  0x1250,0x1251,0x1252,0x1253,0x1254,0x1255,0x1256,0x1257,
 134.632 +  0x1258,0x1259,0x125a,0x125b,0x125c,0x125d,0x125e,0x125f,
 134.633 +  0x1260,0x1261,0x1262,0x1263,0x1264,0x1265,0x1266,0x1267,
 134.634 +  0x1268,0x1269,0x126a,0x126b,0x126c,0x126d,0x126e,0x126f,
 134.635 +  0x1270,0x1271,0x1272,0x1273,0x1274,0x1275,0x1276,0x1277,
 134.636 +  0x1278,0x1279,0x127a,0x127b,0x127c,0x127d,0x127e,0x127f,
 134.637 +  0x1280,0x1281,0x1282,0x1283,0x1284,0x1285,0x1286,0x1287,
 134.638 +  0x1288,0x1289,0x128a,0x128b,0x128c,0x128d,0x128e,0x128f,
 134.639 +  0x1290,0x1291,0x1292,0x1293,0x1294,0x1295,0x1296,0x1297,
 134.640 +  0x1298,0x1299,0x129a,0x129b,0x129c,0x129d,0x129e,0x129f,
 134.641 +  0x12a0,0x12a1,0x12a2,0x12a3,0x12a4,0x12a5,0x12a6,0x12a7,
 134.642 +  0x12a8,0x12a9,0x12aa,0x12ab,0x12ac,0x12ad,0x12ae,0x12af,
 134.643 +  0x12b0,0x12b1,0x12b2,0x12b3,0x12b4,0x12b5,0x12b6,0x12b7,
 134.644 +  0x12b8,0x12b9,0x12ba,0x12bb,0x12bc,0x12bd,0x12be,0x12bf,
 134.645 +  0x12c0,0x12c1,0x12c2,0x12c3,0x12c4,0x12c5,0x12c6,0x12c7,
 134.646 +  0x12c8,0x12c9,0x12ca,0x12cb,0x12cc,0x12cd,0x12ce,0x12cf,
 134.647 +  0x12d0,0x12d1,0x12d2,0x12d3,0x12d4,0x12d5,0x12d6,0x12d7,
 134.648 +  0x12d8,0x12d9,0x12da,0x12db,0x12dc,0x12dd,0x12de,0x12df,
 134.649 +  0x12e0,0x12e1,0x12e2,0x12e3,0x12e4,0x12e5,0x12e6,0x12e7,
 134.650 +  0x12e8,0x12e9,0x12ea,0x12eb,0x12ec,0x12ed,0x12ee,0x12ef,
 134.651 +  0x12f0,0x12f1,0x12f2,0x12f3,0x12f4,0x12f5,0x12f6,0x12f7,
 134.652 +  0x12f8,0x12f9,0x12fa,0x12fb,0x12fc,0x12fd,0x12fe,0x12ff,
 134.653 +  0x1300,0x1301,0x1302,0x1303,0x1304,0x1305,0x1306,0x1307,
 134.654 +  0x1308,0x1309,0x130a,0x130b,0x130c,0x130d,0x130e,0x130f,
 134.655 +  0x1310,0x1311,0x1312,0x1313,0x1314,0x1315,0x1316,0x1317,
 134.656 +  0x1318,0x1319,0x131a,0x131b,0x131c,0x131d,0x131e,0x131f,
 134.657 +  0x1320,0x1321,0x1322,0x1323,0x1324,0x1325,0x1326,0x1327,
 134.658 +  0x1328,0x1329,0x132a,0x132b,0x132c,0x132d,0x132e,0x132f,
 134.659 +  0x1330,0x1331,0x1332,0x1333,0x1334,0x1335,0x1336,0x1337,
 134.660 +  0x1338,0x1339,0x133a,0x133b,0x133c,0x133d,0x133e,0x133f,
 134.661 +  0x1340,0x1341,0x1342,0x1343,0x1344,0x1345,0x1346,0x1347,
 134.662 +  0x1348,0x1349,0x134a,0x134b,0x134c,0x134d,0x134e,0x134f,
 134.663 +  0x1350,0x1351,0x1352,0x1353,0x1354,0x1355,0x1356,0x1357,
 134.664 +  0x1358,0x1359,0x135a,0x135b,0x135c,0x135d,0x135e,0x135f,
 134.665 +  0x1360,0x1361,0x1362,0x1363,0x1364,0x1365,0x1366,0x1367,
 134.666 +  0x1368,0x1369,0x136a,0x136b,0x136c,0x136d,0x136e,0x136f,
 134.667 +  0x1370,0x1371,0x1372,0x1373,0x1374,0x1375,0x1376,0x1377,
 134.668 +  0x1378,0x1379,0x137a,0x137b,0x137c,0x137d,0x137e,0x137f,
 134.669 +  0x1380,0x1381,0x1382,0x1383,0x1384,0x1385,0x1386,0x1387,
 134.670 +  0x1388,0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f,
 134.671 +  0x1390,0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397,
 134.672 +  0x1398,0x1399,0x139a,0x139b,0x139c,0x139d,0x139e,0x139f,
 134.673 +  0x13a0,0x13a1,0x13a2,0x13a3,0x13a4,0x13a5,0x13a6,0x13a7,
 134.674 +  0x13a8,0x13a9,0x13aa,0x13ab,0x13ac,0x13ad,0x13ae,0x13af,
 134.675 +  0x13b0,0x13b1,0x13b2,0x13b3,0x13b4,0x13b5,0x13b6,0x13b7,
 134.676 +  0x13b8,0x13b9,0x13ba,0x13bb,0x13bc,0x13bd,0x13be,0x13bf,
 134.677 +  0x13c0,0x13c1,0x13c2,0x13c3,0x13c4,0x13c5,0x13c6,0x13c7,
 134.678 +  0x13c8,0x13c9,0x13ca,0x13cb,0x13cc,0x13cd,0x13ce,0x13cf,
 134.679 +  0x13d0,0x13d1,0x13d2,0x13d3,0x13d4,0x13d5,0x13d6,0x13d7,
 134.680 +  0x13d8,0x13d9,0x13da,0x13db,0x13dc,0x13dd,0x13de,0x13df,
 134.681 +  0x13e0,0x13e1,0x13e2,0x13e3,0x13e4,0x13e5,0x13e6,0x13e7,
 134.682 +  0x13e8,0x13e9,0x13ea,0x13eb,0x13ec,0x13ed,0x13ee,0x13ef,
 134.683 +  0x13f0,0x13f1,0x13f2,0x13f3,0x13f4,0x13f5,0x13f6,0x13f7,
 134.684 +  0x13f8,0x13f9,0x13fa,0x13fb,0x13fc,0x13fd,0x13fe,0x13ff,
 134.685 +  0x1400,0x1401,0x1402,0x1403,0x1404,0x1405,0x1406,0x1407,
 134.686 +  0x1408,0x1409,0x140a,0x140b,0x140c,0x140d,0x140e,0x140f,
 134.687 +  0x1410,0x1411,0x1412,0x1413,0x1414,0x1415,0x1416,0x1417,
 134.688 +  0x1418,0x1419,0x141a,0x141b,0x141c,0x141d,0x141e,0x141f,
 134.689 +  0x1420,0x1421,0x1422,0x1423,0x1424,0x1425,0x1426,0x1427,
 134.690 +  0x1428,0x1429,0x142a,0x142b,0x142c,0x142d,0x142e,0x142f,
 134.691 +  0x1430,0x1431,0x1432,0x1433,0x1434,0x1435,0x1436,0x1437,
 134.692 +  0x1438,0x1439,0x143a,0x143b,0x143c,0x143d,0x143e,0x143f,
 134.693 +  0x1440,0x1441,0x1442,0x1443,0x1444,0x1445,0x1446,0x1447,
 134.694 +  0x1448,0x1449,0x144a,0x144b,0x144c,0x144d,0x144e,0x144f,
 134.695 +  0x1450,0x1451,0x1452,0x1453,0x1454,0x1455,0x1456,0x1457,
 134.696 +  0x1458,0x1459,0x145a,0x145b,0x145c,0x145d,0x145e,0x145f,
 134.697 +  0x1460,0x1461,0x1462,0x1463,0x1464,0x1465,0x1466,0x1467,
 134.698 +  0x1468,0x1469,0x146a,0x146b,0x146c,0x146d,0x146e,0x146f,
 134.699 +  0x1470,0x1471,0x1472,0x1473,0x1474,0x1475,0x1476,0x1477,
 134.700 +  0x1478,0x1479,0x147a,0x147b,0x147c,0x147d,0x147e,0x147f,
 134.701 +  0x1480,0x1481,0x1482,0x1483,0x1484,0x1485,0x1486,0x1487,
 134.702 +  0x1488,0x1489,0x148a,0x148b,0x148c,0x148d,0x148e,0x148f,
 134.703 +  0x1490,0x1491,0x1492,0x1493,0x1494,0x1495,0x1496,0x1497,
 134.704 +  0x1498,0x1499,0x149a,0x149b,0x149c,0x149d,0x149e,0x149f,
 134.705 +  0x14a0,0x14a1,0x14a2,0x14a3,0x14a4,0x14a5,0x14a6,0x14a7,
 134.706 +  0x14a8,0x14a9,0x14aa,0x14ab,0x14ac,0x14ad,0x14ae,0x14af,
 134.707 +  0x14b0,0x14b1,0x14b2,0x14b3,0x14b4,0x14b5,0x14b6,0x14b7,
 134.708 +  0x14b8,0x14b9,0x14ba,0x14bb,0x14bc,0x14bd,0x14be,0x14bf,
 134.709 +  0x14c0,0x14c1,0x14c2,0x14c3,0x14c4,0x14c5,0x14c6,0x14c7,
 134.710 +  0x14c8,0x14c9,0x14ca,0x14cb,0x14cc,0x14cd,0x14ce,0x14cf,
 134.711 +  0x14d0,0x14d1,0x14d2,0x14d3,0x14d4,0x14d5,0x14d6,0x14d7,
 134.712 +  0x14d8,0x14d9,0x14da,0x14db,0x14dc,0x14dd,0x14de,0x14df,
 134.713 +  0x14e0,0x14e1,0x14e2,0x14e3,0x14e4,0x14e5,0x14e6,0x14e7,
 134.714 +  0x14e8,0x14e9,0x14ea,0x14eb,0x14ec,0x14ed,0x14ee,0x14ef,
 134.715 +  0x14f0,0x14f1,0x14f2,0x14f3,0x14f4,0x14f5,0x14f6,0x14f7,
 134.716 +  0x14f8,0x14f9,0x14fa,0x14fb,0x14fc,0x14fd,0x14fe,0x14ff,
 134.717 +  0x1500,0x1501,0x1502,0x1503,0x1504,0x1505,0x1506,0x1507,
 134.718 +  0x1508,0x1509,0x150a,0x150b,0x150c,0x150d,0x150e,0x150f,
 134.719 +  0x1510,0x1511,0x1512,0x1513,0x1514,0x1515,0x1516,0x1517,
 134.720 +  0x1518,0x1519,0x151a,0x151b,0x151c,0x151d,0x151e,0x151f,
 134.721 +  0x1520,0x1521,0x1522,0x1523,0x1524,0x1525,0x1526,0x1527,
 134.722 +  0x1528,0x1529,0x152a,0x152b,0x152c,0x152d,0x152e,0x152f,
 134.723 +  0x1530,0x1531,0x1532,0x1533,0x1534,0x1535,0x1536,0x1537,
 134.724 +  0x1538,0x1539,0x153a,0x153b,0x153c,0x153d,0x153e,0x153f,
 134.725 +  0x1540,0x1541,0x1542,0x1543,0x1544,0x1545,0x1546,0x1547,
 134.726 +  0x1548,0x1549,0x154a,0x154b,0x154c,0x154d,0x154e,0x154f,
 134.727 +  0x1550,0x1551,0x1552,0x1553,0x1554,0x1555,0x1556,0x1557,
 134.728 +  0x1558,0x1559,0x155a,0x155b,0x155c,0x155d,0x155e,0x155f,
 134.729 +  0x1560,0x1561,0x1562,0x1563,0x1564,0x1565,0x1566,0x1567,
 134.730 +  0x1568,0x1569,0x156a,0x156b,0x156c,0x156d,0x156e,0x156f,
 134.731 +  0x1570,0x1571,0x1572,0x1573,0x1574,0x1575,0x1576,0x1577,
 134.732 +  0x1578,0x1579,0x157a,0x157b,0x157c,0x157d,0x157e,0x157f,
 134.733 +  0x1580,0x1581,0x1582,0x1583,0x1584,0x1585,0x1586,0x1587,
 134.734 +  0x1588,0x1589,0x158a,0x158b,0x158c,0x158d,0x158e,0x158f,
 134.735 +  0x1590,0x1591,0x1592,0x1593,0x1594,0x1595,0x1596,0x1597,
 134.736 +  0x1598,0x1599,0x159a,0x159b,0x159c,0x159d,0x159e,0x159f,
 134.737 +  0x15a0,0x15a1,0x15a2,0x15a3,0x15a4,0x15a5,0x15a6,0x15a7,
 134.738 +  0x15a8,0x15a9,0x15aa,0x15ab,0x15ac,0x15ad,0x15ae,0x15af,
 134.739 +  0x15b0,0x15b1,0x15b2,0x15b3,0x15b4,0x15b5,0x15b6,0x15b7,
 134.740 +  0x15b8,0x15b9,0x15ba,0x15bb,0x15bc,0x15bd,0x15be,0x15bf,
 134.741 +  0x15c0,0x15c1,0x15c2,0x15c3,0x15c4,0x15c5,0x15c6,0x15c7,
 134.742 +  0x15c8,0x15c9,0x15ca,0x15cb,0x15cc,0x15cd,0x15ce,0x15cf,
 134.743 +  0x15d0,0x15d1,0x15d2,0x15d3,0x15d4,0x15d5,0x15d6,0x15d7,
 134.744 +  0x15d8,0x15d9,0x15da,0x15db,0x15dc,0x15dd,0x15de,0x15df,
 134.745 +  0x15e0,0x15e1,0x15e2,0x15e3,0x15e4,0x15e5,0x15e6,0x15e7,
 134.746 +  0x15e8,0x15e9,0x15ea,0x15eb,0x15ec,0x15ed,0x15ee,0x15ef,
 134.747 +  0x15f0,0x15f1,0x15f2,0x15f3,0x15f4,0x15f5,0x15f6,0x15f7,
 134.748 +  0x15f8,0x15f9,0x15fa,0x15fb,0x15fc,0x15fd,0x15fe,0x15ff,
 134.749 +  0x1600,0x1601,0x1602,0x1603,0x1604,0x1605,0x1606,0x1607,
 134.750 +  0x1608,0x1609,0x160a,0x160b,0x160c,0x160d,0x160e,0x160f,
 134.751 +  0x1610,0x1611,0x1612,0x1613,0x1614,0x1615,0x1616,0x1617,
 134.752 +  0x1618,0x1619,0x161a,0x161b,0x161c,0x161d,0x161e,0x161f,
 134.753 +  0x1620,0x1621,0x1622,0x1623,0x1624,0x1625,0x1626,0x1627,
 134.754 +  0x1628,0x1629,0x162a,0x162b,0x162c,0x162d,0x162e,0x162f,
 134.755 +  0x1630,0x1631,0x1632,0x1633,0x1634,0x1635,0x1636,0x1637,
 134.756 +  0x1638,0x1639,0x163a,0x163b,0x163c,0x163d,0x163e,0x163f,
 134.757 +  0x1640,0x1641,0x1642,0x1643,0x1644,0x1645,0x1646,0x1647,
 134.758 +  0x1648,0x1649,0x164a,0x164b,0x164c,0x164d,0x164e,0x164f,
 134.759 +  0x1650,0x1651,0x1652,0x1653,0x1654,0x1655,0x1656,0x1657,
 134.760 +  0x1658,0x1659,0x165a,0x165b,0x165c,0x165d,0x165e,0x165f,
 134.761 +  0x1660,0x1661,0x1662,0x1663,0x1664,0x1665,0x1666,0x1667,
 134.762 +  0x1668,0x1669,0x166a,0x166b,0x166c,0x166d,0x166e,0x166f,
 134.763 +  0x1670,0x1671,0x1672,0x1673,0x1674,0x1675,0x1676,0x1677,
 134.764 +  0x1678,0x1679,0x167a,0x167b,0x167c,0x167d,0x167e,0x167f,
 134.765 +  0x1680,0x1681,0x1682,0x1683,0x1684,0x1685,0x1686,0x1687,
 134.766 +  0x1688,0x1689,0x168a,0x168b,0x168c,0x168d,0x168e,0x168f,
 134.767 +  0x1690,0x1691,0x1692,0x1693,0x1694,0x1695,0x1696,0x1697,
 134.768 +  0x1698,0x1699,0x169a,0x169b,0x169c,0x169d,0x169e,0x169f,
 134.769 +  0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0x16a6,0x16a7,
 134.770 +  0x16a8,0x16a9,0x16aa,0x16ab,0x16ac,0x16ad,0x16ae,0x16af,
 134.771 +  0x16b0,0x16b1,0x16b2,0x16b3,0x16b4,0x16b5,0x16b6,0x16b7,
 134.772 +  0x16b8,0x16b9,0x16ba,0x16bb,0x16bc,0x16bd,0x16be,0x16bf,
 134.773 +  0x16c0,0x16c1,0x16c2,0x16c3,0x16c4,0x16c5,0x16c6,0x16c7,
 134.774 +  0x16c8,0x16c9,0x16ca,0x16cb,0x16cc,0x16cd,0x16ce,0x16cf,
 134.775 +  0x16d0,0x16d1,0x16d2,0x16d3,0x16d4,0x16d5,0x16d6,0x16d7,
 134.776 +  0x16d8,0x16d9,0x16da,0x16db,0x16dc,0x16dd,0x16de,0x16df,
 134.777 +  0x16e0,0x16e1,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
 134.778 +  0x16e8,0x16e9,0x16ea,0x16eb,0x16ec,0x16ed,0x16ee,0x16ef,
 134.779 +  0x16f0,0x16f1,0x16f2,0x16f3,0x16f4,0x16f5,0x16f6,0x16f7,
 134.780 +  0x16f8,0x16f9,0x16fa,0x16fb,0x16fc,0x16fd,0x16fe,0x16ff,
 134.781 +  0x1700,0x1701,0x1702,0x1703,0x1704,0x1705,0x1706,0x1707,
 134.782 +  0x1708,0x1709,0x170a,0x170b,0x170c,0x170d,0x170e,0x170f,
 134.783 +  0x1710,0x1711,0x1712,0x1713,0x1714,0x1715,0x1716,0x1717,
 134.784 +  0x1718,0x1719,0x171a,0x171b,0x171c,0x171d,0x171e,0x171f,
 134.785 +  0x1720,0x1721,0x1722,0x1723,0x1724,0x1725,0x1726,0x1727,
 134.786 +  0x1728,0x1729,0x172a,0x172b,0x172c,0x172d,0x172e,0x172f,
 134.787 +  0x1730,0x1731,0x1732,0x1733,0x1734,0x1735,0x1736,0x1737,
 134.788 +  0x1738,0x1739,0x173a,0x173b,0x173c,0x173d,0x173e,0x173f,
 134.789 +  0x1740,0x1741,0x1742,0x1743,0x1744,0x1745,0x1746,0x1747,
 134.790 +  0x1748,0x1749,0x174a,0x174b,0x174c,0x174d,0x174e,0x174f,
 134.791 +  0x1750,0x1751,0x1752,0x1753,0x1754,0x1755,0x1756,0x1757,
 134.792 +  0x1758,0x1759,0x175a,0x175b,0x175c,0x175d,0x175e,0x175f,
 134.793 +  0x1760,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
 134.794 +  0x1768,0x1769,0x176a,0x176b,0x176c,0x176d,0x176e,0x176f,
 134.795 +  0x1770,0x1771,0x1772,0x1773,0x1774,0x1775,0x1776,0x1777,
 134.796 +  0x1778,0x1779,0x177a,0x177b,0x177c,0x177d,0x177e,0x177f,
 134.797 +  0x1780,0x1781,0x1782,0x1783,0x1784,0x1785,0x1786,0x1787,
 134.798 +  0x1788,0x1789,0x178a,0x178b,0x178c,0x178d,0x178e,0x178f,
 134.799 +  0x1790,0x1791,0x1792,0x1793,0x1794,0x1795,0x1796,0x1797,
 134.800 +  0x1798,0x1799,0x179a,0x179b,0x179c,0x179d,0x179e,0x179f,
 134.801 +  0x17a0,0x17a1,0x17a2,0x17a3,0x17a4,0x17a5,0x17a6,0x17a7,
 134.802 +  0x17a8,0x17a9,0x17aa,0x17ab,0x17ac,0x17ad,0x17ae,0x17af,
 134.803 +  0x17b0,0x17b1,0x17b2,0x17b3,0x17b4,0x17b5,0x17b6,0x17b7,
 134.804 +  0x17b8,0x17b9,0x17ba,0x17bb,0x17bc,0x17bd,0x17be,0x17bf,
 134.805 +  0x17c0,0x17c1,0x17c2,0x17c3,0x17c4,0x17c5,0x17c6,0x17c7,
 134.806 +  0x17c8,0x17c9,0x17ca,0x17cb,0x17cc,0x17cd,0x17ce,0x17cf,
 134.807 +  0x17d0,0x17d1,0x17d2,0x17d3,0x17d4,0x17d5,0x17d6,0x17d7,
 134.808 +  0x17d8,0x17d9,0x17da,0x17db,0x17dc,0x17dd,0x17de,0x17df,
 134.809 +  0x17e0,0x17e1,0x17e2,0x17e3,0x17e4,0x17e5,0x17e6,0x17e7,
 134.810 +  0x17e8,0x17e9,0x17ea,0x17eb,0x17ec,0x17ed,0x17ee,0x17ef,
 134.811 +  0x17f0,0x17f1,0x17f2,0x17f3,0x17f4,0x17f5,0x17f6,0x17f7,
 134.812 +  0x17f8,0x17f9,0x17fa,0x17fb,0x17fc,0x17fd,0x17fe,0x17ff,
 134.813 +  0x1800,0x1801,0x1802,0x1803,0x1804,0x1805,0x1806,0x1807,
 134.814 +  0x1808,0x1809,0x180a,0x180b,0x180c,0x180d,0x180e,0x180f,
 134.815 +  0x1810,0x1811,0x1812,0x1813,0x1814,0x1815,0x1816,0x1817,
 134.816 +  0x1818,0x1819,0x181a,0x181b,0x181c,0x181d,0x181e,0x181f,
 134.817 +  0x1820,0x1821,0x1822,0x1823,0x1824,0x1825,0x1826,0x1827,
 134.818 +  0x1828,0x1829,0x182a,0x182b,0x182c,0x182d,0x182e,0x182f,
 134.819 +  0x1830,0x1831,0x1832,0x1833,0x1834,0x1835,0x1836,0x1837,
 134.820 +  0x1838,0x1839,0x183a,0x183b,0x183c,0x183d,0x183e,0x183f,
 134.821 +  0x1840,0x1841,0x1842,0x1843,0x1844,0x1845,0x1846,0x1847,
 134.822 +  0x1848,0x1849,0x184a,0x184b,0x184c,0x184d,0x184e,0x184f,
 134.823 +  0x1850,0x1851,0x1852,0x1853,0x1854,0x1855,0x1856,0x1857,
 134.824 +  0x1858,0x1859,0x185a,0x185b,0x185c,0x185d,0x185e,0x185f,
 134.825 +  0x1860,0x1861,0x1862,0x1863,0x1864,0x1865,0x1866,0x1867,
 134.826 +  0x1868,0x1869,0x186a,0x186b,0x186c,0x186d,0x186e,0x186f,
 134.827 +  0x1870,0x1871,0x1872,0x1873,0x1874,0x1875,0x1876,0x1877,
 134.828 +  0x1878,0x1879,0x187a,0x187b,0x187c,0x187d,0x187e,0x187f,
 134.829 +  0x1880,0x1881,0x1882,0x1883,0x1884,0x1885,0x1886,0x1887,
 134.830 +  0x1888,0x1889,0x188a,0x188b,0x188c,0x188d,0x188e,0x188f,
 134.831 +  0x1890,0x1891,0x1892,0x1893,0x1894,0x1895,0x1896,0x1897,
 134.832 +  0x1898,0x1899,0x189a,0x189b,0x189c,0x189d,0x189e,0x189f,
 134.833 +  0x18a0,0x18a1,0x18a2,0x18a3,0x18a4,0x18a5,0x18a6,0x18a7,
 134.834 +  0x18a8,0x18a9,0x18aa,0x18ab,0x18ac,0x18ad,0x18ae,0x18af,
 134.835 +  0x18b0,0x18b1,0x18b2,0x18b3,0x18b4,0x18b5,0x18b6,0x18b7,
 134.836 +  0x18b8,0x18b9,0x18ba,0x18bb,0x18bc,0x18bd,0x18be,0x18bf,
 134.837 +  0x18c0,0x18c1,0x18c2,0x18c3,0x18c4,0x18c5,0x18c6,0x18c7,
 134.838 +  0x18c8,0x18c9,0x18ca,0x18cb,0x18cc,0x18cd,0x18ce,0x18cf,
 134.839 +  0x18d0,0x18d1,0x18d2,0x18d3,0x18d4,0x18d5,0x18d6,0x18d7,
 134.840 +  0x18d8,0x18d9,0x18da,0x18db,0x18dc,0x18dd,0x18de,0x18df,
 134.841 +  0x18e0,0x18e1,0x18e2,0x18e3,0x18e4,0x18e5,0x18e6,0x18e7,
 134.842 +  0x18e8,0x18e9,0x18ea,0x18eb,0x18ec,0x18ed,0x18ee,0x18ef,
 134.843 +  0x18f0,0x18f1,0x18f2,0x18f3,0x18f4,0x18f5,0x18f6,0x18f7,
 134.844 +  0x18f8,0x18f9,0x18fa,0x18fb,0x18fc,0x18fd,0x18fe,0x18ff,
 134.845 +  0x1900,0x1901,0x1902,0x1903,0x1904,0x1905,0x1906,0x1907,
 134.846 +  0x1908,0x1909,0x190a,0x190b,0x190c,0x190d,0x190e,0x190f,
 134.847 +  0x1910,0x1911,0x1912,0x1913,0x1914,0x1915,0x1916,0x1917,
 134.848 +  0x1918,0x1919,0x191a,0x191b,0x191c,0x191d,0x191e,0x191f,
 134.849 +  0x1920,0x1921,0x1922,0x1923,0x1924,0x1925,0x1926,0x1927,
 134.850 +  0x1928,0x1929,0x192a,0x192b,0x192c,0x192d,0x192e,0x192f,
 134.851 +  0x1930,0x1931,0x1932,0x1933,0x1934,0x1935,0x1936,0x1937,
 134.852 +  0x1938,0x1939,0x193a,0x193b,0x193c,0x193d,0x193e,0x193f,
 134.853 +  0x1940,0x1941,0x1942,0x1943,0x1944,0x1945,0x1946,0x1947,
 134.854 +  0x1948,0x1949,0x194a,0x194b,0x194c,0x194d,0x194e,0x194f,
 134.855 +  0x1950,0x1951,0x1952,0x1953,0x1954,0x1955,0x1956,0x1957,
 134.856 +  0x1958,0x1959,0x195a,0x195b,0x195c,0x195d,0x195e,0x195f,
 134.857 +  0x1960,0x1961,0x1962,0x1963,0x1964,0x1965,0x1966,0x1967,
 134.858 +  0x1968,0x1969,0x196a,0x196b,0x196c,0x196d,0x196e,0x196f,
 134.859 +  0x1970,0x1971,0x1972,0x1973,0x1974,0x1975,0x1976,0x1977,
 134.860 +  0x1978,0x1979,0x197a,0x197b,0x197c,0x197d,0x197e,0x197f,
 134.861 +  0x1980,0x1981,0x1982,0x1983,0x1984,0x1985,0x1986,0x1987,
 134.862 +  0x1988,0x1989,0x198a,0x198b,0x198c,0x198d,0x198e,0x198f,
 134.863 +  0x1990,0x1991,0x1992,0x1993,0x1994,0x1995,0x1996,0x1997,
 134.864 +  0x1998,0x1999,0x199a,0x199b,0x199c,0x199d,0x199e,0x199f,
 134.865 +  0x19a0,0x19a1,0x19a2,0x19a3,0x19a4,0x19a5,0x19a6,0x19a7,
 134.866 +  0x19a8,0x19a9,0x19aa,0x19ab,0x19ac,0x19ad,0x19ae,0x19af,
 134.867 +  0x19b0,0x19b1,0x19b2,0x19b3,0x19b4,0x19b5,0x19b6,0x19b7,
 134.868 +  0x19b8,0x19b9,0x19ba,0x19bb,0x19bc,0x19bd,0x19be,0x19bf,
 134.869 +  0x19c0,0x19c1,0x19c2,0x19c3,0x19c4,0x19c5,0x19c6,0x19c7,
 134.870 +  0x19c8,0x19c9,0x19ca,0x19cb,0x19cc,0x19cd,0x19ce,0x19cf,
 134.871 +  0x19d0,0x19d1,0x19d2,0x19d3,0x19d4,0x19d5,0x19d6,0x19d7,
 134.872 +  0x19d8,0x19d9,0x19da,0x19db,0x19dc,0x19dd,0x19de,0x19df,
 134.873 +  0x19e0,0x19e1,0x19e2,0x19e3,0x19e4,0x19e5,0x19e6,0x19e7,
 134.874 +  0x19e8,0x19e9,0x19ea,0x19eb,0x19ec,0x19ed,0x19ee,0x19ef,
 134.875 +  0x19f0,0x19f1,0x19f2,0x19f3,0x19f4,0x19f5,0x19f6,0x19f7,
 134.876 +  0x19f8,0x19f9,0x19fa,0x19fb,0x19fc,0x19fd,0x19fe,0x19ff,
 134.877 +  0x1a00,0x1a01,0x1a02,0x1a03,0x1a04,0x1a05,0x1a06,0x1a07,
 134.878 +  0x1a08,0x1a09,0x1a0a,0x1a0b,0x1a0c,0x1a0d,0x1a0e,0x1a0f,
 134.879 +  0x1a10,0x1a11,0x1a12,0x1a13,0x1a14,0x1a15,0x1a16,0x1a17,
 134.880 +  0x1a18,0x1a19,0x1a1a,0x1a1b,0x1a1c,0x1a1d,0x1a1e,0x1a1f,
 134.881 +  0x1a20,0x1a21,0x1a22,0x1a23,0x1a24,0x1a25,0x1a26,0x1a27,
 134.882 +  0x1a28,0x1a29,0x1a2a,0x1a2b,0x1a2c,0x1a2d,0x1a2e,0x1a2f,
 134.883 +  0x1a30,0x1a31,0x1a32,0x1a33,0x1a34,0x1a35,0x1a36,0x1a37,
 134.884 +  0x1a38,0x1a39,0x1a3a,0x1a3b,0x1a3c,0x1a3d,0x1a3e,0x1a3f,
 134.885 +  0x1a40,0x1a41,0x1a42,0x1a43,0x1a44,0x1a45,0x1a46,0x1a47,
 134.886 +  0x1a48,0x1a49,0x1a4a,0x1a4b,0x1a4c,0x1a4d,0x1a4e,0x1a4f,
 134.887 +  0x1a50,0x1a51,0x1a52,0x1a53,0x1a54,0x1a55,0x1a56,0x1a57,
 134.888 +  0x1a58,0x1a59,0x1a5a,0x1a5b,0x1a5c,0x1a5d,0x1a5e,0x1a5f,
 134.889 +  0x1a60,0x1a61,0x1a62,0x1a63,0x1a64,0x1a65,0x1a66,0x1a67,
 134.890 +  0x1a68,0x1a69,0x1a6a,0x1a6b,0x1a6c,0x1a6d,0x1a6e,0x1a6f,
 134.891 +  0x1a70,0x1a71,0x1a72,0x1a73,0x1a74,0x1a75,0x1a76,0x1a77,
 134.892 +  0x1a78,0x1a79,0x1a7a,0x1a7b,0x1a7c,0x1a7d,0x1a7e,0x1a7f,
 134.893 +  0x1a80,0x1a81,0x1a82,0x1a83,0x1a84,0x1a85,0x1a86,0x1a87,
 134.894 +  0x1a88,0x1a89,0x1a8a,0x1a8b,0x1a8c,0x1a8d,0x1a8e,0x1a8f,
 134.895 +  0x1a90,0x1a91,0x1a92,0x1a93,0x1a94,0x1a95,0x1a96,0x1a97,
 134.896 +  0x1a98,0x1a99,0x1a9a,0x1a9b,0x1a9c,0x1a9d,0x1a9e,0x1a9f,
 134.897 +  0x1aa0,0x1aa1,0x1aa2,0x1aa3,0x1aa4,0x1aa5,0x1aa6,0x1aa7,
 134.898 +  0x1aa8,0x1aa9,0x1aaa,0x1aab,0x1aac,0x1aad,0x1aae,0x1aaf,
 134.899 +  0x1ab0,0x1ab1,0x1ab2,0x1ab3,0x1ab4,0x1ab5,0x1ab6,0x1ab7,
 134.900 +  0x1ab8,0x1ab9,0x1aba,0x1abb,0x1abc,0x1abd,0x1abe,0x1abf,
 134.901 +  0x1ac0,0x1ac1,0x1ac2,0x1ac3,0x1ac4,0x1ac5,0x1ac6,0x1ac7,
 134.902 +  0x1ac8,0x1ac9,0x1aca,0x1acb,0x1acc,0x1acd,0x1ace,0x1acf,
 134.903 +  0x1ad0,0x1ad1,0x1ad2,0x1ad3,0x1ad4,0x1ad5,0x1ad6,0x1ad7,
 134.904 +  0x1ad8,0x1ad9,0x1ada,0x1adb,0x1adc,0x1add,0x1ade,0x1adf,
 134.905 +  0x1ae0,0x1ae1,0x1ae2,0x1ae3,0x1ae4,0x1ae5,0x1ae6,0x1ae7,
 134.906 +  0x1ae8,0x1ae9,0x1aea,0x1aeb,0x1aec,0x1aed,0x1aee,0x1aef,
 134.907 +  0x1af0,0x1af1,0x1af2,0x1af3,0x1af4,0x1af5,0x1af6,0x1af7,
 134.908 +  0x1af8,0x1af9,0x1afa,0x1afb,0x1afc,0x1afd,0x1afe,0x1aff,
 134.909 +  0x1b00,0x1b01,0x1b02,0x1b03,0x1b04,0x1b05,0x1b06,0x1b07,
 134.910 +  0x1b08,0x1b09,0x1b0a,0x1b0b,0x1b0c,0x1b0d,0x1b0e,0x1b0f,
 134.911 +  0x1b10,0x1b11,0x1b12,0x1b13,0x1b14,0x1b15,0x1b16,0x1b17,
 134.912 +  0x1b18,0x1b19,0x1b1a,0x1b1b,0x1b1c,0x1b1d,0x1b1e,0x1b1f,
 134.913 +  0x1b20,0x1b21,0x1b22,0x1b23,0x1b24,0x1b25,0x1b26,0x1b27,
 134.914 +  0x1b28,0x1b29,0x1b2a,0x1b2b,0x1b2c,0x1b2d,0x1b2e,0x1b2f,
 134.915 +  0x1b30,0x1b31,0x1b32,0x1b33,0x1b34,0x1b35,0x1b36,0x1b37,
 134.916 +  0x1b38,0x1b39,0x1b3a,0x1b3b,0x1b3c,0x1b3d,0x1b3e,0x1b3f,
 134.917 +  0x1b40,0x1b41,0x1b42,0x1b43,0x1b44,0x1b45,0x1b46,0x1b47,
 134.918 +  0x1b48,0x1b49,0x1b4a,0x1b4b,0x1b4c,0x1b4d,0x1b4e,0x1b4f,
 134.919 +  0x1b50,0x1b51,0x1b52,0x1b53,0x1b54,0x1b55,0x1b56,0x1b57,
 134.920 +  0x1b58,0x1b59,0x1b5a,0x1b5b,0x1b5c,0x1b5d,0x1b5e,0x1b5f,
 134.921 +  0x1b60,0x1b61,0x1b62,0x1b63,0x1b64,0x1b65,0x1b66,0x1b67,
 134.922 +  0x1b68,0x1b69,0x1b6a,0x1b6b,0x1b6c,0x1b6d,0x1b6e,0x1b6f,
 134.923 +  0x1b70,0x1b71,0x1b72,0x1b73,0x1b74,0x1b75,0x1b76,0x1b77,
 134.924 +  0x1b78,0x1b79,0x1b7a,0x1b7b,0x1b7c,0x1b7d,0x1b7e,0x1b7f,
 134.925 +  0x1b80,0x1b81,0x1b82,0x1b83,0x1b84,0x1b85,0x1b86,0x1b87,
 134.926 +  0x1b88,0x1b89,0x1b8a,0x1b8b,0x1b8c,0x1b8d,0x1b8e,0x1b8f,
 134.927 +  0x1b90,0x1b91,0x1b92,0x1b93,0x1b94,0x1b95,0x1b96,0x1b97,
 134.928 +  0x1b98,0x1b99,0x1b9a,0x1b9b,0x1b9c,0x1b9d,0x1b9e,0x1b9f,
 134.929 +  0x1ba0,0x1ba1,0x1ba2,0x1ba3,0x1ba4,0x1ba5,0x1ba6,0x1ba7,
 134.930 +  0x1ba8,0x1ba9,0x1baa,0x1bab,0x1bac,0x1bad,0x1bae,0x1baf,
 134.931 +  0x1bb0,0x1bb1,0x1bb2,0x1bb3,0x1bb4,0x1bb5,0x1bb6,0x1bb7,
 134.932 +  0x1bb8,0x1bb9,0x1bba,0x1bbb,0x1bbc,0x1bbd,0x1bbe,0x1bbf,
 134.933 +  0x1bc0,0x1bc1,0x1bc2,0x1bc3,0x1bc4,0x1bc5,0x1bc6,0x1bc7,
 134.934 +  0x1bc8,0x1bc9,0x1bca,0x1bcb,0x1bcc,0x1bcd,0x1bce,0x1bcf,
 134.935 +  0x1bd0,0x1bd1,0x1bd2,0x1bd3,0x1bd4,0x1bd5,0x1bd6,0x1bd7,
 134.936 +  0x1bd8,0x1bd9,0x1bda,0x1bdb,0x1bdc,0x1bdd,0x1bde,0x1bdf,
 134.937 +  0x1be0,0x1be1,0x1be2,0x1be3,0x1be4,0x1be5,0x1be6,0x1be7,
 134.938 +  0x1be8,0x1be9,0x1bea,0x1beb,0x1bec,0x1bed,0x1bee,0x1bef,
 134.939 +  0x1bf0,0x1bf1,0x1bf2,0x1bf3,0x1bf4,0x1bf5,0x1bf6,0x1bf7,
 134.940 +  0x1bf8,0x1bf9,0x1bfa,0x1bfb,0x1bfc,0x1bfd,0x1bfe,0x1bff,
 134.941 +  0x1c00,0x1c01,0x1c02,0x1c03,0x1c04,0x1c05,0x1c06,0x1c07,
 134.942 +  0x1c08,0x1c09,0x1c0a,0x1c0b,0x1c0c,0x1c0d,0x1c0e,0x1c0f,
 134.943 +  0x1c10,0x1c11,0x1c12,0x1c13,0x1c14,0x1c15,0x1c16,0x1c17,
 134.944 +  0x1c18,0x1c19,0x1c1a,0x1c1b,0x1c1c,0x1c1d,0x1c1e,0x1c1f,
 134.945 +  0x1c20,0x1c21,0x1c22,0x1c23,0x1c24,0x1c25,0x1c26,0x1c27,
 134.946 +  0x1c28,0x1c29,0x1c2a,0x1c2b,0x1c2c,0x1c2d,0x1c2e,0x1c2f,
 134.947 +  0x1c30,0x1c31,0x1c32,0x1c33,0x1c34,0x1c35,0x1c36,0x1c37,
 134.948 +  0x1c38,0x1c39,0x1c3a,0x1c3b,0x1c3c,0x1c3d,0x1c3e,0x1c3f,
 134.949 +  0x1c40,0x1c41,0x1c42,0x1c43,0x1c44,0x1c45,0x1c46,0x1c47,
 134.950 +  0x1c48,0x1c49,0x1c4a,0x1c4b,0x1c4c,0x1c4d,0x1c4e,0x1c4f,
 134.951 +  0x1c50,0x1c51,0x1c52,0x1c53,0x1c54,0x1c55,0x1c56,0x1c57,
 134.952 +  0x1c58,0x1c59,0x1c5a,0x1c5b,0x1c5c,0x1c5d,0x1c5e,0x1c5f,
 134.953 +  0x1c60,0x1c61,0x1c62,0x1c63,0x1c64,0x1c65,0x1c66,0x1c67,
 134.954 +  0x1c68,0x1c69,0x1c6a,0x1c6b,0x1c6c,0x1c6d,0x1c6e,0x1c6f,
 134.955 +  0x1c70,0x1c71,0x1c72,0x1c73,0x1c74,0x1c75,0x1c76,0x1c77,
 134.956 +  0x1c78,0x1c79,0x1c7a,0x1c7b,0x1c7c,0x1c7d,0x1c7e,0x1c7f,
 134.957 +  0x1c80,0x1c81,0x1c82,0x1c83,0x1c84,0x1c85,0x1c86,0x1c87,
 134.958 +  0x1c88,0x1c89,0x1c8a,0x1c8b,0x1c8c,0x1c8d,0x1c8e,0x1c8f,
 134.959 +  0x1c90,0x1c91,0x1c92,0x1c93,0x1c94,0x1c95,0x1c96,0x1c97,
 134.960 +  0x1c98,0x1c99,0x1c9a,0x1c9b,0x1c9c,0x1c9d,0x1c9e,0x1c9f,
 134.961 +  0x1ca0,0x1ca1,0x1ca2,0x1ca3,0x1ca4,0x1ca5,0x1ca6,0x1ca7,
 134.962 +  0x1ca8,0x1ca9,0x1caa,0x1cab,0x1cac,0x1cad,0x1cae,0x1caf,
 134.963 +  0x1cb0,0x1cb1,0x1cb2,0x1cb3,0x1cb4,0x1cb5,0x1cb6,0x1cb7,
 134.964 +  0x1cb8,0x1cb9,0x1cba,0x1cbb,0x1cbc,0x1cbd,0x1cbe,0x1cbf,
 134.965 +  0x1cc0,0x1cc1,0x1cc2,0x1cc3,0x1cc4,0x1cc5,0x1cc6,0x1cc7,
 134.966 +  0x1cc8,0x1cc9,0x1cca,0x1ccb,0x1ccc,0x1ccd,0x1cce,0x1ccf,
 134.967 +  0x1cd0,0x1cd1,0x1cd2,0x1cd3,0x1cd4,0x1cd5,0x1cd6,0x1cd7,
 134.968 +  0x1cd8,0x1cd9,0x1cda,0x1cdb,0x1cdc,0x1cdd,0x1cde,0x1cdf,
 134.969 +  0x1ce0,0x1ce1,0x1ce2,0x1ce3,0x1ce4,0x1ce5,0x1ce6,0x1ce7,
 134.970 +  0x1ce8,0x1ce9,0x1cea,0x1ceb,0x1cec,0x1ced,0x1cee,0x1cef,
 134.971 +  0x1cf0,0x1cf1,0x1cf2,0x1cf3,0x1cf4,0x1cf5,0x1cf6,0x1cf7,
 134.972 +  0x1cf8,0x1cf9,0x1cfa,0x1cfb,0x1cfc,0x1cfd,0x1cfe,0x1cff,
 134.973 +  0x1d00,0x1d01,0x1d02,0x1d03,0x1d04,0x1d05,0x1d06,0x1d07,
 134.974 +  0x1d08,0x1d09,0x1d0a,0x1d0b,0x1d0c,0x1d0d,0x1d0e,0x1d0f,
 134.975 +  0x1d10,0x1d11,0x1d12,0x1d13,0x1d14,0x1d15,0x1d16,0x1d17,
 134.976 +  0x1d18,0x1d19,0x1d1a,0x1d1b,0x1d1c,0x1d1d,0x1d1e,0x1d1f,
 134.977 +  0x1d20,0x1d21,0x1d22,0x1d23,0x1d24,0x1d25,0x1d26,0x1d27,
 134.978 +  0x1d28,0x1d29,0x1d2a,0x1d2b,0x1d2c,0x1d2d,0x1d2e,0x1d2f,
 134.979 +  0x1d30,0x1d31,0x1d32,0x1d33,0x1d34,0x1d35,0x1d36,0x1d37,
 134.980 +  0x1d38,0x1d39,0x1d3a,0x1d3b,0x1d3c,0x1d3d,0x1d3e,0x1d3f,
 134.981 +  0x1d40,0x1d41,0x1d42,0x1d43,0x1d44,0x1d45,0x1d46,0x1d47,
 134.982 +  0x1d48,0x1d49,0x1d4a,0x1d4b,0x1d4c,0x1d4d,0x1d4e,0x1d4f,
 134.983 +  0x1d50,0x1d51,0x1d52,0x1d53,0x1d54,0x1d55,0x1d56,0x1d57,
 134.984 +  0x1d58,0x1d59,0x1d5a,0x1d5b,0x1d5c,0x1d5d,0x1d5e,0x1d5f,
 134.985 +  0x1d60,0x1d61,0x1d62,0x1d63,0x1d64,0x1d65,0x1d66,0x1d67,
 134.986 +  0x1d68,0x1d69,0x1d6a,0x1d6b,0x1d6c,0x1d6d,0x1d6e,0x1d6f,
 134.987 +  0x1d70,0x1d71,0x1d72,0x1d73,0x1d74,0x1d75,0x1d76,0x1d77,
 134.988 +  0x1d78,0x1d79,0x1d7a,0x1d7b,0x1d7c,0x2c63,0x1d7e,0x1d7f,
 134.989 +  0x1d80,0x1d81,0x1d82,0x1d83,0x1d84,0x1d85,0x1d86,0x1d87,
 134.990 +  0x1d88,0x1d89,0x1d8a,0x1d8b,0x1d8c,0x1d8d,0x1d8e,0x1d8f,
 134.991 +  0x1d90,0x1d91,0x1d92,0x1d93,0x1d94,0x1d95,0x1d96,0x1d97,
 134.992 +  0x1d98,0x1d99,0x1d9a,0x1d9b,0x1d9c,0x1d9d,0x1d9e,0x1d9f,
 134.993 +  0x1da0,0x1da1,0x1da2,0x1da3,0x1da4,0x1da5,0x1da6,0x1da7,
 134.994 +  0x1da8,0x1da9,0x1daa,0x1dab,0x1dac,0x1dad,0x1dae,0x1daf,
 134.995 +  0x1db0,0x1db1,0x1db2,0x1db3,0x1db4,0x1db5,0x1db6,0x1db7,
 134.996 +  0x1db8,0x1db9,0x1dba,0x1dbb,0x1dbc,0x1dbd,0x1dbe,0x1dbf,
 134.997 +  0x1dc0,0x1dc1,0x1dc2,0x1dc3,0x1dc4,0x1dc5,0x1dc6,0x1dc7,
 134.998 +  0x1dc8,0x1dc9,0x1dca,0x1dcb,0x1dcc,0x1dcd,0x1dce,0x1dcf,
 134.999 +  0x1dd0,0x1dd1,0x1dd2,0x1dd3,0x1dd4,0x1dd5,0x1dd6,0x1dd7,
134.1000 +  0x1dd8,0x1dd9,0x1dda,0x1ddb,0x1ddc,0x1ddd,0x1dde,0x1ddf,
134.1001 +  0x1de0,0x1de1,0x1de2,0x1de3,0x1de4,0x1de5,0x1de6,0x1de7,
134.1002 +  0x1de8,0x1de9,0x1dea,0x1deb,0x1dec,0x1ded,0x1dee,0x1def,
134.1003 +  0x1df0,0x1df1,0x1df2,0x1df3,0x1df4,0x1df5,0x1df6,0x1df7,
134.1004 +  0x1df8,0x1df9,0x1dfa,0x1dfb,0x1dfc,0x1dfd,0x1dfe,0x1dff,
134.1005 +  0x1e00,0x1e00,0x1e02,0x1e02,0x1e04,0x1e04,0x1e06,0x1e06,
134.1006 +  0x1e08,0x1e08,0x1e0a,0x1e0a,0x1e0c,0x1e0c,0x1e0e,0x1e0e,
134.1007 +  0x1e10,0x1e10,0x1e12,0x1e12,0x1e14,0x1e14,0x1e16,0x1e16,
134.1008 +  0x1e18,0x1e18,0x1e1a,0x1e1a,0x1e1c,0x1e1c,0x1e1e,0x1e1e,
134.1009 +  0x1e20,0x1e20,0x1e22,0x1e22,0x1e24,0x1e24,0x1e26,0x1e26,
134.1010 +  0x1e28,0x1e28,0x1e2a,0x1e2a,0x1e2c,0x1e2c,0x1e2e,0x1e2e,
134.1011 +  0x1e30,0x1e30,0x1e32,0x1e32,0x1e34,0x1e34,0x1e36,0x1e36,
134.1012 +  0x1e38,0x1e38,0x1e3a,0x1e3a,0x1e3c,0x1e3c,0x1e3e,0x1e3e,
134.1013 +  0x1e40,0x1e40,0x1e42,0x1e42,0x1e44,0x1e44,0x1e46,0x1e46,
134.1014 +  0x1e48,0x1e48,0x1e4a,0x1e4a,0x1e4c,0x1e4c,0x1e4e,0x1e4e,
134.1015 +  0x1e50,0x1e50,0x1e52,0x1e52,0x1e54,0x1e54,0x1e56,0x1e56,
134.1016 +  0x1e58,0x1e58,0x1e5a,0x1e5a,0x1e5c,0x1e5c,0x1e5e,0x1e5e,
134.1017 +  0x1e60,0x1e60,0x1e62,0x1e62,0x1e64,0x1e64,0x1e66,0x1e66,
134.1018 +  0x1e68,0x1e68,0x1e6a,0x1e6a,0x1e6c,0x1e6c,0x1e6e,0x1e6e,
134.1019 +  0x1e70,0x1e70,0x1e72,0x1e72,0x1e74,0x1e74,0x1e76,0x1e76,
134.1020 +  0x1e78,0x1e78,0x1e7a,0x1e7a,0x1e7c,0x1e7c,0x1e7e,0x1e7e,
134.1021 +  0x1e80,0x1e80,0x1e82,0x1e82,0x1e84,0x1e84,0x1e86,0x1e86,
134.1022 +  0x1e88,0x1e88,0x1e8a,0x1e8a,0x1e8c,0x1e8c,0x1e8e,0x1e8e,
134.1023 +  0x1e90,0x1e90,0x1e92,0x1e92,0x1e94,0x1e94,0x1e96,0x1e97,
134.1024 +  0x1e98,0x1e99,0x1e9a,0x1e60,0x1e9c,0x1e9d,0x1e9e,0x1e9f,
134.1025 +  0x1ea0,0x1ea0,0x1ea2,0x1ea2,0x1ea4,0x1ea4,0x1ea6,0x1ea6,
134.1026 +  0x1ea8,0x1ea8,0x1eaa,0x1eaa,0x1eac,0x1eac,0x1eae,0x1eae,
134.1027 +  0x1eb0,0x1eb0,0x1eb2,0x1eb2,0x1eb4,0x1eb4,0x1eb6,0x1eb6,
134.1028 +  0x1eb8,0x1eb8,0x1eba,0x1eba,0x1ebc,0x1ebc,0x1ebe,0x1ebe,
134.1029 +  0x1ec0,0x1ec0,0x1ec2,0x1ec2,0x1ec4,0x1ec4,0x1ec6,0x1ec6,
134.1030 +  0x1ec8,0x1ec8,0x1eca,0x1eca,0x1ecc,0x1ecc,0x1ece,0x1ece,
134.1031 +  0x1ed0,0x1ed0,0x1ed2,0x1ed2,0x1ed4,0x1ed4,0x1ed6,0x1ed6,
134.1032 +  0x1ed8,0x1ed8,0x1eda,0x1eda,0x1edc,0x1edc,0x1ede,0x1ede,
134.1033 +  0x1ee0,0x1ee0,0x1ee2,0x1ee2,0x1ee4,0x1ee4,0x1ee6,0x1ee6,
134.1034 +  0x1ee8,0x1ee8,0x1eea,0x1eea,0x1eec,0x1eec,0x1eee,0x1eee,
134.1035 +  0x1ef0,0x1ef0,0x1ef2,0x1ef2,0x1ef4,0x1ef4,0x1ef6,0x1ef6,
134.1036 +  0x1ef8,0x1ef8,0x1efa,0x1efb,0x1efc,0x1efd,0x1efe,0x1eff,
134.1037 +  0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f,
134.1038 +  0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f,
134.1039 +  0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f16,0x1f17,
134.1040 +  0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f1e,0x1f1f,
134.1041 +  0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f,
134.1042 +  0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f,
134.1043 +  0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f,
134.1044 +  0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f,
134.1045 +  0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f46,0x1f47,
134.1046 +  0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f4e,0x1f4f,
134.1047 +  0x1f50,0x1f59,0x1f52,0x1f5b,0x1f54,0x1f5d,0x1f56,0x1f5f,
134.1048 +  0x1f58,0x1f59,0x1f5a,0x1f5b,0x1f5c,0x1f5d,0x1f5e,0x1f5f,
134.1049 +  0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f,
134.1050 +  0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f,
134.1051 +  0x1fba,0x1fbb,0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fda,0x1fdb,
134.1052 +  0x1ff8,0x1ff9,0x1fea,0x1feb,0x1ffa,0x1ffb,0x1f7e,0x1f7f,
134.1053 +  0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f,
134.1054 +  0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f,
134.1055 +  0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f,
134.1056 +  0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f,
134.1057 +  0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf,
134.1058 +  0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf,
134.1059 +  0x1fb8,0x1fb9,0x1fb2,0x1fbc,0x1fb4,0x1fb5,0x1fb6,0x1fb7,
134.1060 +  0x1fb8,0x1fb9,0x1fba,0x1fbb,0x1fbc,0x1fbd,0x0399,0x1fbf,
134.1061 +  0x1fc0,0x1fc1,0x1fc2,0x1fcc,0x1fc4,0x1fc5,0x1fc6,0x1fc7,
134.1062 +  0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fcc,0x1fcd,0x1fce,0x1fcf,
134.1063 +  0x1fd8,0x1fd9,0x1fd2,0x1fd3,0x1fd4,0x1fd5,0x1fd6,0x1fd7,
134.1064 +  0x1fd8,0x1fd9,0x1fda,0x1fdb,0x1fdc,0x1fdd,0x1fde,0x1fdf,
134.1065 +  0x1fe8,0x1fe9,0x1fe2,0x1fe3,0x1fe4,0x1fec,0x1fe6,0x1fe7,
134.1066 +  0x1fe8,0x1fe9,0x1fea,0x1feb,0x1fec,0x1fed,0x1fee,0x1fef,
134.1067 +  0x1ff0,0x1ff1,0x1ff2,0x1ffc,0x1ff4,0x1ff5,0x1ff6,0x1ff7,
134.1068 +  0x1ff8,0x1ff9,0x1ffa,0x1ffb,0x1ffc,0x1ffd,0x1ffe,0x1fff,
134.1069 +  0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,
134.1070 +  0x2008,0x2009,0x200a,0x200b,0x200c,0x200d,0x200e,0x200f,
134.1071 +  0x2010,0x2011,0x2012,0x2013,0x2014,0x2015,0x2016,0x2017,
134.1072 +  0x2018,0x2019,0x201a,0x201b,0x201c,0x201d,0x201e,0x201f,
134.1073 +  0x2020,0x2021,0x2022,0x2023,0x2024,0x2025,0x2026,0x2027,
134.1074 +  0x2028,0x2029,0x202a,0x202b,0x202c,0x202d,0x202e,0x202f,
134.1075 +  0x2030,0x2031,0x2032,0x2033,0x2034,0x2035,0x2036,0x2037,
134.1076 +  0x2038,0x2039,0x203a,0x203b,0x203c,0x203d,0x203e,0x203f,
134.1077 +  0x2040,0x2041,0x2042,0x2043,0x2044,0x2045,0x2046,0x2047,
134.1078 +  0x2048,0x2049,0x204a,0x204b,0x204c,0x204d,0x204e,0x204f,
134.1079 +  0x2050,0x2051,0x2052,0x2053,0x2054,0x2055,0x2056,0x2057,
134.1080 +  0x2058,0x2059,0x205a,0x205b,0x205c,0x205d,0x205e,0x205f,
134.1081 +  0x2060,0x2061,0x2062,0x2063,0x2064,0x2065,0x2066,0x2067,
134.1082 +  0x2068,0x2069,0x206a,0x206b,0x206c,0x206d,0x206e,0x206f,
134.1083 +  0x2070,0x2071,0x2072,0x2073,0x2074,0x2075,0x2076,0x2077,
134.1084 +  0x2078,0x2079,0x207a,0x207b,0x207c,0x207d,0x207e,0x207f,
134.1085 +  0x2080,0x2081,0x2082,0x2083,0x2084,0x2085,0x2086,0x2087,
134.1086 +  0x2088,0x2089,0x208a,0x208b,0x208c,0x208d,0x208e,0x208f,
134.1087 +  0x2090,0x2091,0x2092,0x2093,0x2094,0x2095,0x2096,0x2097,
134.1088 +  0x2098,0x2099,0x209a,0x209b,0x209c,0x209d,0x209e,0x209f,
134.1089 +  0x20a0,0x20a1,0x20a2,0x20a3,0x20a4,0x20a5,0x20a6,0x20a7,
134.1090 +  0x20a8,0x20a9,0x20aa,0x20ab,0x20ac,0x20ad,0x20ae,0x20af,
134.1091 +  0x20b0,0x20b1,0x20b2,0x20b3,0x20b4,0x20b5,0x20b6,0x20b7,
134.1092 +  0x20b8,0x20b9,0x20ba,0x20bb,0x20bc,0x20bd,0x20be,0x20bf,
134.1093 +  0x20c0,0x20c1,0x20c2,0x20c3,0x20c4,0x20c5,0x20c6,0x20c7,
134.1094 +  0x20c8,0x20c9,0x20ca,0x20cb,0x20cc,0x20cd,0x20ce,0x20cf,
134.1095 +  0x20d0,0x20d1,0x20d2,0x20d3,0x20d4,0x20d5,0x20d6,0x20d7,
134.1096 +  0x20d8,0x20d9,0x20da,0x20db,0x20dc,0x20dd,0x20de,0x20df,
134.1097 +  0x20e0,0x20e1,0x20e2,0x20e3,0x20e4,0x20e5,0x20e6,0x20e7,
134.1098 +  0x20e8,0x20e9,0x20ea,0x20eb,0x20ec,0x20ed,0x20ee,0x20ef,
134.1099 +  0x20f0,0x20f1,0x20f2,0x20f3,0x20f4,0x20f5,0x20f6,0x20f7,
134.1100 +  0x20f8,0x20f9,0x20fa,0x20fb,0x20fc,0x20fd,0x20fe,0x20ff,
134.1101 +  0x2100,0x2101,0x2102,0x2103,0x2104,0x2105,0x2106,0x2107,
134.1102 +  0x2108,0x2109,0x210a,0x210b,0x210c,0x210d,0x210e,0x210f,
134.1103 +  0x2110,0x2111,0x2112,0x2113,0x2114,0x2115,0x2116,0x2117,
134.1104 +  0x2118,0x2119,0x211a,0x211b,0x211c,0x211d,0x211e,0x211f,
134.1105 +  0x2120,0x2121,0x2122,0x2123,0x2124,0x2125,0x2126,0x2127,
134.1106 +  0x2128,0x2129,0x212a,0x212b,0x212c,0x212d,0x212e,0x212f,
134.1107 +  0x2130,0x2131,0x2132,0x2133,0x2134,0x2135,0x2136,0x2137,
134.1108 +  0x2138,0x2139,0x213a,0x213b,0x213c,0x213d,0x213e,0x213f,
134.1109 +  0x2140,0x2141,0x2142,0x2143,0x2144,0x2145,0x2146,0x2147,
134.1110 +  0x2148,0x2149,0x214a,0x214b,0x214c,0x214d,0x2132,0x214f,
134.1111 +  0x2150,0x2151,0x2152,0x2153,0x2154,0x2155,0x2156,0x2157,
134.1112 +  0x2158,0x2159,0x215a,0x215b,0x215c,0x215d,0x215e,0x215f,
134.1113 +  0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,
134.1114 +  0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f,
134.1115 +  0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,
134.1116 +  0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f,
134.1117 +  0x2180,0x2181,0x2182,0x2183,0x2183,0x2185,0x2186,0x2187,
134.1118 +  0x2188,0x2189,0x218a,0x218b,0x218c,0x218d,0x218e,0x218f,
134.1119 +  0x2190,0x2191,0x2192,0x2193,0x2194,0x2195,0x2196,0x2197,
134.1120 +  0x2198,0x2199,0x219a,0x219b,0x219c,0x219d,0x219e,0x219f,
134.1121 +  0x21a0,0x21a1,0x21a2,0x21a3,0x21a4,0x21a5,0x21a6,0x21a7,
134.1122 +  0x21a8,0x21a9,0x21aa,0x21ab,0x21ac,0x21ad,0x21ae,0x21af,
134.1123 +  0x21b0,0x21b1,0x21b2,0x21b3,0x21b4,0x21b5,0x21b6,0x21b7,
134.1124 +  0x21b8,0x21b9,0x21ba,0x21bb,0x21bc,0x21bd,0x21be,0x21bf,
134.1125 +  0x21c0,0x21c1,0x21c2,0x21c3,0x21c4,0x21c5,0x21c6,0x21c7,
134.1126 +  0x21c8,0x21c9,0x21ca,0x21cb,0x21cc,0x21cd,0x21ce,0x21cf,
134.1127 +  0x21d0,0x21d1,0x21d2,0x21d3,0x21d4,0x21d5,0x21d6,0x21d7,
134.1128 +  0x21d8,0x21d9,0x21da,0x21db,0x21dc,0x21dd,0x21de,0x21df,
134.1129 +  0x21e0,0x21e1,0x21e2,0x21e3,0x21e4,0x21e5,0x21e6,0x21e7,
134.1130 +  0x21e8,0x21e9,0x21ea,0x21eb,0x21ec,0x21ed,0x21ee,0x21ef,
134.1131 +  0x21f0,0x21f1,0x21f2,0x21f3,0x21f4,0x21f5,0x21f6,0x21f7,
134.1132 +  0x21f8,0x21f9,0x21fa,0x21fb,0x21fc,0x21fd,0x21fe,0x21ff,
134.1133 +  0x2200,0x2201,0x2202,0x2203,0x2204,0x2205,0x2206,0x2207,
134.1134 +  0x2208,0x2209,0x220a,0x220b,0x220c,0x220d,0x220e,0x220f,
134.1135 +  0x2210,0x2211,0x2212,0x2213,0x2214,0x2215,0x2216,0x2217,
134.1136 +  0x2218,0x2219,0x221a,0x221b,0x221c,0x221d,0x221e,0x221f,
134.1137 +  0x2220,0x2221,0x2222,0x2223,0x2224,0x2225,0x2226,0x2227,
134.1138 +  0x2228,0x2229,0x222a,0x222b,0x222c,0x222d,0x222e,0x222f,
134.1139 +  0x2230,0x2231,0x2232,0x2233,0x2234,0x2235,0x2236,0x2237,
134.1140 +  0x2238,0x2239,0x223a,0x223b,0x223c,0x223d,0x223e,0x223f,
134.1141 +  0x2240,0x2241,0x2242,0x2243,0x2244,0x2245,0x2246,0x2247,
134.1142 +  0x2248,0x2249,0x224a,0x224b,0x224c,0x224d,0x224e,0x224f,
134.1143 +  0x2250,0x2251,0x2252,0x2253,0x2254,0x2255,0x2256,0x2257,
134.1144 +  0x2258,0x2259,0x225a,0x225b,0x225c,0x225d,0x225e,0x225f,
134.1145 +  0x2260,0x2261,0x2262,0x2263,0x2264,0x2265,0x2266,0x2267,
134.1146 +  0x2268,0x2269,0x226a,0x226b,0x226c,0x226d,0x226e,0x226f,
134.1147 +  0x2270,0x2271,0x2272,0x2273,0x2274,0x2275,0x2276,0x2277,
134.1148 +  0x2278,0x2279,0x227a,0x227b,0x227c,0x227d,0x227e,0x227f,
134.1149 +  0x2280,0x2281,0x2282,0x2283,0x2284,0x2285,0x2286,0x2287,
134.1150 +  0x2288,0x2289,0x228a,0x228b,0x228c,0x228d,0x228e,0x228f,
134.1151 +  0x2290,0x2291,0x2292,0x2293,0x2294,0x2295,0x2296,0x2297,
134.1152 +  0x2298,0x2299,0x229a,0x229b,0x229c,0x229d,0x229e,0x229f,
134.1153 +  0x22a0,0x22a1,0x22a2,0x22a3,0x22a4,0x22a5,0x22a6,0x22a7,
134.1154 +  0x22a8,0x22a9,0x22aa,0x22ab,0x22ac,0x22ad,0x22ae,0x22af,
134.1155 +  0x22b0,0x22b1,0x22b2,0x22b3,0x22b4,0x22b5,0x22b6,0x22b7,
134.1156 +  0x22b8,0x22b9,0x22ba,0x22bb,0x22bc,0x22bd,0x22be,0x22bf,
134.1157 +  0x22c0,0x22c1,0x22c2,0x22c3,0x22c4,0x22c5,0x22c6,0x22c7,
134.1158 +  0x22c8,0x22c9,0x22ca,0x22cb,0x22cc,0x22cd,0x22ce,0x22cf,
134.1159 +  0x22d0,0x22d1,0x22d2,0x22d3,0x22d4,0x22d5,0x22d6,0x22d7,
134.1160 +  0x22d8,0x22d9,0x22da,0x22db,0x22dc,0x22dd,0x22de,0x22df,
134.1161 +  0x22e0,0x22e1,0x22e2,0x22e3,0x22e4,0x22e5,0x22e6,0x22e7,
134.1162 +  0x22e8,0x22e9,0x22ea,0x22eb,0x22ec,0x22ed,0x22ee,0x22ef,
134.1163 +  0x22f0,0x22f1,0x22f2,0x22f3,0x22f4,0x22f5,0x22f6,0x22f7,
134.1164 +  0x22f8,0x22f9,0x22fa,0x22fb,0x22fc,0x22fd,0x22fe,0x22ff,
134.1165 +  0x2300,0x2301,0x2302,0x2303,0x2304,0x2305,0x2306,0x2307,
134.1166 +  0x2308,0x2309,0x230a,0x230b,0x230c,0x230d,0x230e,0x230f,
134.1167 +  0x2310,0x2311,0x2312,0x2313,0x2314,0x2315,0x2316,0x2317,
134.1168 +  0x2318,0x2319,0x231a,0x231b,0x231c,0x231d,0x231e,0x231f,
134.1169 +  0x2320,0x2321,0x2322,0x2323,0x2324,0x2325,0x2326,0x2327,
134.1170 +  0x2328,0x2329,0x232a,0x232b,0x232c,0x232d,0x232e,0x232f,
134.1171 +  0x2330,0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337,
134.1172 +  0x2338,0x2339,0x233a,0x233b,0x233c,0x233d,0x233e,0x233f,
134.1173 +  0x2340,0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347,
134.1174 +  0x2348,0x2349,0x234a,0x234b,0x234c,0x234d,0x234e,0x234f,
134.1175 +  0x2350,0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357,
134.1176 +  0x2358,0x2359,0x235a,0x235b,0x235c,0x235d,0x235e,0x235f,
134.1177 +  0x2360,0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367,
134.1178 +  0x2368,0x2369,0x236a,0x236b,0x236c,0x236d,0x236e,0x236f,
134.1179 +  0x2370,0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377,
134.1180 +  0x2378,0x2379,0x237a,0x237b,0x237c,0x237d,0x237e,0x237f,
134.1181 +  0x2380,0x2381,0x2382,0x2383,0x2384,0x2385,0x2386,0x2387,
134.1182 +  0x2388,0x2389,0x238a,0x238b,0x238c,0x238d,0x238e,0x238f,
134.1183 +  0x2390,0x2391,0x2392,0x2393,0x2394,0x2395,0x2396,0x2397,
134.1184 +  0x2398,0x2399,0x239a,0x239b,0x239c,0x239d,0x239e,0x239f,
134.1185 +  0x23a0,0x23a1,0x23a2,0x23a3,0x23a4,0x23a5,0x23a6,0x23a7,
134.1186 +  0x23a8,0x23a9,0x23aa,0x23ab,0x23ac,0x23ad,0x23ae,0x23af,
134.1187 +  0x23b0,0x23b1,0x23b2,0x23b3,0x23b4,0x23b5,0x23b6,0x23b7,
134.1188 +  0x23b8,0x23b9,0x23ba,0x23bb,0x23bc,0x23bd,0x23be,0x23bf,
134.1189 +  0x23c0,0x23c1,0x23c2,0x23c3,0x23c4,0x23c5,0x23c6,0x23c7,
134.1190 +  0x23c8,0x23c9,0x23ca,0x23cb,0x23cc,0x23cd,0x23ce,0x23cf,
134.1191 +  0x23d0,0x23d1,0x23d2,0x23d3,0x23d4,0x23d5,0x23d6,0x23d7,
134.1192 +  0x23d8,0x23d9,0x23da,0x23db,0x23dc,0x23dd,0x23de,0x23df,
134.1193 +  0x23e0,0x23e1,0x23e2,0x23e3,0x23e4,0x23e5,0x23e6,0x23e7,
134.1194 +  0x23e8,0x23e9,0x23ea,0x23eb,0x23ec,0x23ed,0x23ee,0x23ef,
134.1195 +  0x23f0,0x23f1,0x23f2,0x23f3,0x23f4,0x23f5,0x23f6,0x23f7,
134.1196 +  0x23f8,0x23f9,0x23fa,0x23fb,0x23fc,0x23fd,0x23fe,0x23ff,
134.1197 +  0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,
134.1198 +  0x2408,0x2409,0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,
134.1199 +  0x2410,0x2411,0x2412,0x2413,0x2414,0x2415,0x2416,0x2417,
134.1200 +  0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,0x241e,0x241f,
134.1201 +  0x2420,0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427,
134.1202 +  0x2428,0x2429,0x242a,0x242b,0x242c,0x242d,0x242e,0x242f,
134.1203 +  0x2430,0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437,
134.1204 +  0x2438,0x2439,0x243a,0x243b,0x243c,0x243d,0x243e,0x243f,
134.1205 +  0x2440,0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447,
134.1206 +  0x2448,0x2449,0x244a,0x244b,0x244c,0x244d,0x244e,0x244f,
134.1207 +  0x2450,0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457,
134.1208 +  0x2458,0x2459,0x245a,0x245b,0x245c,0x245d,0x245e,0x245f,
134.1209 +  0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
134.1210 +  0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,
134.1211 +  0x2470,0x2471,0x2472,0x2473,0x2474,0x2475,0x2476,0x2477,
134.1212 +  0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,
134.1213 +  0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,
134.1214 +  0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,0x248f,
134.1215 +  0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,
134.1216 +  0x2498,0x2499,0x249a,0x249b,0x249c,0x249d,0x249e,0x249f,
134.1217 +  0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,0x24a6,0x24a7,
134.1218 +  0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af,
134.1219 +  0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x24b6,0x24b7,
134.1220 +  0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,0x24be,0x24bf,
134.1221 +  0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,0x24c6,0x24c7,
134.1222 +  0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,0x24ce,0x24cf,
134.1223 +  0x24b6,0x24b7,0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,
134.1224 +  0x24be,0x24bf,0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,
134.1225 +  0x24c6,0x24c7,0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,
134.1226 +  0x24ce,0x24cf,0x24ea,0x24eb,0x24ec,0x24ed,0x24ee,0x24ef,
134.1227 +  0x24f0,0x24f1,0x24f2,0x24f3,0x24f4,0x24f5,0x24f6,0x24f7,
134.1228 +  0x24f8,0x24f9,0x24fa,0x24fb,0x24fc,0x24fd,0x24fe,0x24ff,
134.1229 +  0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,
134.1230 +  0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,
134.1231 +  0x2510,0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,
134.1232 +  0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,0x251e,0x251f,
134.1233 +  0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
134.1234 +  0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,
134.1235 +  0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,
134.1236 +  0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,
134.1237 +  0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,
134.1238 +  0x2548,0x2549,0x254a,0x254b,0x254c,0x254d,0x254e,0x254f,
134.1239 +  0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,
134.1240 +  0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,
134.1241 +  0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,
134.1242 +  0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,0x256e,0x256f,
134.1243 +  0x2570,0x2571,0x2572,0x2573,0x2574,0x2575,0x2576,0x2577,
134.1244 +  0x2578,0x2579,0x257a,0x257b,0x257c,0x257d,0x257e,0x257f,
134.1245 +  0x2580,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,
134.1246 +  0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,0x258e,0x258f,
134.1247 +  0x2590,0x2591,0x2592,0x2593,0x2594,0x2595,0x2596,0x2597,
134.1248 +  0x2598,0x2599,0x259a,0x259b,0x259c,0x259d,0x259e,0x259f,
134.1249 +  0x25a0,0x25a1,0x25a2,0x25a3,0x25a4,0x25a5,0x25a6,0x25a7,
134.1250 +  0x25a8,0x25a9,0x25aa,0x25ab,0x25ac,0x25ad,0x25ae,0x25af,
134.1251 +  0x25b0,0x25b1,0x25b2,0x25b3,0x25b4,0x25b5,0x25b6,0x25b7,
134.1252 +  0x25b8,0x25b9,0x25ba,0x25bb,0x25bc,0x25bd,0x25be,0x25bf,
134.1253 +  0x25c0,0x25c1,0x25c2,0x25c3,0x25c4,0x25c5,0x25c6,0x25c7,
134.1254 +  0x25c8,0x25c9,0x25ca,0x25cb,0x25cc,0x25cd,0x25ce,0x25cf,
134.1255 +  0x25d0,0x25d1,0x25d2,0x25d3,0x25d4,0x25d5,0x25d6,0x25d7,
134.1256 +  0x25d8,0x25d9,0x25da,0x25db,0x25dc,0x25dd,0x25de,0x25df,
134.1257 +  0x25e0,0x25e1,0x25e2,0x25e3,0x25e4,0x25e5,0x25e6,0x25e7,
134.1258 +  0x25e8,0x25e9,0x25ea,0x25eb,0x25ec,0x25ed,0x25ee,0x25ef,
134.1259 +  0x25f0,0x25f1,0x25f2,0x25f3,0x25f4,0x25f5,0x25f6,0x25f7,
134.1260 +  0x25f8,0x25f9,0x25fa,0x25fb,0x25fc,0x25fd,0x25fe,0x25ff,
134.1261 +  0x2600,0x2601,0x2602,0x2603,0x2604,0x2605,0x2606,0x2607,
134.1262 +  0x2608,0x2609,0x260a,0x260b,0x260c,0x260d,0x260e,0x260f,
134.1263 +  0x2610,0x2611,0x2612,0x2613,0x2614,0x2615,0x2616,0x2617,
134.1264 +  0x2618,0x2619,0x261a,0x261b,0x261c,0x261d,0x261e,0x261f,
134.1265 +  0x2620,0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627,
134.1266 +  0x2628,0x2629,0x262a,0x262b,0x262c,0x262d,0x262e,0x262f,
134.1267 +  0x2630,0x2631,0x2632,0x2633,0x2634,0x2635,0x2636,0x2637,
134.1268 +  0x2638,0x2639,0x263a,0x263b,0x263c,0x263d,0x263e,0x263f,
134.1269 +  0x2640,0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647,
134.1270 +  0x2648,0x2649,0x264a,0x264b,0x264c,0x264d,0x264e,0x264f,
134.1271 +  0x2650,0x2651,0x2652,0x2653,0x2654,0x2655,0x2656,0x2657,
134.1272 +  0x2658,0x2659,0x265a,0x265b,0x265c,0x265d,0x265e,0x265f,
134.1273 +  0x2660,0x2661,0x2662,0x2663,0x2664,0x2665,0x2666,0x2667,
134.1274 +  0x2668,0x2669,0x266a,0x266b,0x266c,0x266d,0x266e,0x266f,
134.1275 +  0x2670,0x2671,0x2672,0x2673,0x2674,0x2675,0x2676,0x2677,
134.1276 +  0x2678,0x2679,0x267a,0x267b,0x267c,0x267d,0x267e,0x267f,
134.1277 +  0x2680,0x2681,0x2682,0x2683,0x2684,0x2685,0x2686,0x2687,
134.1278 +  0x2688,0x2689,0x268a,0x268b,0x268c,0x268d,0x268e,0x268f,
134.1279 +  0x2690,0x2691,0x2692,0x2693,0x2694,0x2695,0x2696,0x2697,
134.1280 +  0x2698,0x2699,0x269a,0x269b,0x269c,0x269d,0x269e,0x269f,
134.1281 +  0x26a0,0x26a1,0x26a2,0x26a3,0x26a4,0x26a5,0x26a6,0x26a7,
134.1282 +  0x26a8,0x26a9,0x26aa,0x26ab,0x26ac,0x26ad,0x26ae,0x26af,
134.1283 +  0x26b0,0x26b1,0x26b2,0x26b3,0x26b4,0x26b5,0x26b6,0x26b7,
134.1284 +  0x26b8,0x26b9,0x26ba,0x26bb,0x26bc,0x26bd,0x26be,0x26bf,
134.1285 +  0x26c0,0x26c1,0x26c2,0x26c3,0x26c4,0x26c5,0x26c6,0x26c7,
134.1286 +  0x26c8,0x26c9,0x26ca,0x26cb,0x26cc,0x26cd,0x26ce,0x26cf,
134.1287 +  0x26d0,0x26d1,0x26d2,0x26d3,0x26d4,0x26d5,0x26d6,0x26d7,
134.1288 +  0x26d8,0x26d9,0x26da,0x26db,0x26dc,0x26dd,0x26de,0x26df,
134.1289 +  0x26e0,0x26e1,0x26e2,0x26e3,0x26e4,0x26e5,0x26e6,0x26e7,
134.1290 +  0x26e8,0x26e9,0x26ea,0x26eb,0x26ec,0x26ed,0x26ee,0x26ef,
134.1291 +  0x26f0,0x26f1,0x26f2,0x26f3,0x26f4,0x26f5,0x26f6,0x26f7,
134.1292 +  0x26f8,0x26f9,0x26fa,0x26fb,0x26fc,0x26fd,0x26fe,0x26ff,
134.1293 +  0x2700,0x2701,0x2702,0x2703,0x2704,0x2705,0x2706,0x2707,
134.1294 +  0x2708,0x2709,0x270a,0x270b,0x270c,0x270d,0x270e,0x270f,
134.1295 +  0x2710,0x2711,0x2712,0x2713,0x2714,0x2715,0x2716,0x2717,
134.1296 +  0x2718,0x2719,0x271a,0x271b,0x271c,0x271d,0x271e,0x271f,
134.1297 +  0x2720,0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2727,
134.1298 +  0x2728,0x2729,0x272a,0x272b,0x272c,0x272d,0x272e,0x272f,
134.1299 +  0x2730,0x2731,0x2732,0x2733,0x2734,0x2735,0x2736,0x2737,
134.1300 +  0x2738,0x2739,0x273a,0x273b,0x273c,0x273d,0x273e,0x273f,
134.1301 +  0x2740,0x2741,0x2742,0x2743,0x2744,0x2745,0x2746,0x2747,
134.1302 +  0x2748,0x2749,0x274a,0x274b,0x274c,0x274d,0x274e,0x274f,
134.1303 +  0x2750,0x2751,0x2752,0x2753,0x2754,0x2755,0x2756,0x2757,
134.1304 +  0x2758,0x2759,0x275a,0x275b,0x275c,0x275d,0x275e,0x275f,
134.1305 +  0x2760,0x2761,0x2762,0x2763,0x2764,0x2765,0x2766,0x2767,
134.1306 +  0x2768,0x2769,0x276a,0x276b,0x276c,0x276d,0x276e,0x276f,
134.1307 +  0x2770,0x2771,0x2772,0x2773,0x2774,0x2775,0x2776,0x2777,
134.1308 +  0x2778,0x2779,0x277a,0x277b,0x277c,0x277d,0x277e,0x277f,
134.1309 +  0x2780,0x2781,0x2782,0x2783,0x2784,0x2785,0x2786,0x2787,
134.1310 +  0x2788,0x2789,0x278a,0x278b,0x278c,0x278d,0x278e,0x278f,
134.1311 +  0x2790,0x2791,0x2792,0x2793,0x2794,0x2795,0x2796,0x2797,
134.1312 +  0x2798,0x2799,0x279a,0x279b,0x279c,0x279d,0x279e,0x279f,
134.1313 +  0x27a0,0x27a1,0x27a2,0x27a3,0x27a4,0x27a5,0x27a6,0x27a7,
134.1314 +  0x27a8,0x27a9,0x27aa,0x27ab,0x27ac,0x27ad,0x27ae,0x27af,
134.1315 +  0x27b0,0x27b1,0x27b2,0x27b3,0x27b4,0x27b5,0x27b6,0x27b7,
134.1316 +  0x27b8,0x27b9,0x27ba,0x27bb,0x27bc,0x27bd,0x27be,0x27bf,
134.1317 +  0x27c0,0x27c1,0x27c2,0x27c3,0x27c4,0x27c5,0x27c6,0x27c7,
134.1318 +  0x27c8,0x27c9,0x27ca,0x27cb,0x27cc,0x27cd,0x27ce,0x27cf,
134.1319 +  0x27d0,0x27d1,0x27d2,0x27d3,0x27d4,0x27d5,0x27d6,0x27d7,
134.1320 +  0x27d8,0x27d9,0x27da,0x27db,0x27dc,0x27dd,0x27de,0x27df,
134.1321 +  0x27e0,0x27e1,0x27e2,0x27e3,0x27e4,0x27e5,0x27e6,0x27e7,
134.1322 +  0x27e8,0x27e9,0x27ea,0x27eb,0x27ec,0x27ed,0x27ee,0x27ef,
134.1323 +  0x27f0,0x27f1,0x27f2,0x27f3,0x27f4,0x27f5,0x27f6,0x27f7,
134.1324 +  0x27f8,0x27f9,0x27fa,0x27fb,0x27fc,0x27fd,0x27fe,0x27ff,
134.1325 +  0x2800,0x2801,0x2802,0x2803,0x2804,0x2805,0x2806,0x2807,
134.1326 +  0x2808,0x2809,0x280a,0x280b,0x280c,0x280d,0x280e,0x280f,
134.1327 +  0x2810,0x2811,0x2812,0x2813,0x2814,0x2815,0x2816,0x2817,
134.1328 +  0x2818,0x2819,0x281a,0x281b,0x281c,0x281d,0x281e,0x281f,
134.1329 +  0x2820,0x2821,0x2822,0x2823,0x2824,0x2825,0x2826,0x2827,
134.1330 +  0x2828,0x2829,0x282a,0x282b,0x282c,0x282d,0x282e,0x282f,
134.1331 +  0x2830,0x2831,0x2832,0x2833,0x2834,0x2835,0x2836,0x2837,
134.1332 +  0x2838,0x2839,0x283a,0x283b,0x283c,0x283d,0x283e,0x283f,
134.1333 +  0x2840,0x2841,0x2842,0x2843,0x2844,0x2845,0x2846,0x2847,
134.1334 +  0x2848,0x2849,0x284a,0x284b,0x284c,0x284d,0x284e,0x284f,
134.1335 +  0x2850,0x2851,0x2852,0x2853,0x2854,0x2855,0x2856,0x2857,
134.1336 +  0x2858,0x2859,0x285a,0x285b,0x285c,0x285d,0x285e,0x285f,
134.1337 +  0x2860,0x2861,0x2862,0x2863,0x2864,0x2865,0x2866,0x2867,
134.1338 +  0x2868,0x2869,0x286a,0x286b,0x286c,0x286d,0x286e,0x286f,
134.1339 +  0x2870,0x2871,0x2872,0x2873,0x2874,0x2875,0x2876,0x2877,
134.1340 +  0x2878,0x2879,0x287a,0x287b,0x287c,0x287d,0x287e,0x287f,
134.1341 +  0x2880,0x2881,0x2882,0x2883,0x2884,0x2885,0x2886,0x2887,
134.1342 +  0x2888,0x2889,0x288a,0x288b,0x288c,0x288d,0x288e,0x288f,
134.1343 +  0x2890,0x2891,0x2892,0x2893,0x2894,0x2895,0x2896,0x2897,
134.1344 +  0x2898,0x2899,0x289a,0x289b,0x289c,0x289d,0x289e,0x289f,
134.1345 +  0x28a0,0x28a1,0x28a2,0x28a3,0x28a4,0x28a5,0x28a6,0x28a7,
134.1346 +  0x28a8,0x28a9,0x28aa,0x28ab,0x28ac,0x28ad,0x28ae,0x28af,
134.1347 +  0x28b0,0x28b1,0x28b2,0x28b3,0x28b4,0x28b5,0x28b6,0x28b7,
134.1348 +  0x28b8,0x28b9,0x28ba,0x28bb,0x28bc,0x28bd,0x28be,0x28bf,
134.1349 +  0x28c0,0x28c1,0x28c2,0x28c3,0x28c4,0x28c5,0x28c6,0x28c7,
134.1350 +  0x28c8,0x28c9,0x28ca,0x28cb,0x28cc,0x28cd,0x28ce,0x28cf,
134.1351 +  0x28d0,0x28d1,0x28d2,0x28d3,0x28d4,0x28d5,0x28d6,0x28d7,
134.1352 +  0x28d8,0x28d9,0x28da,0x28db,0x28dc,0x28dd,0x28de,0x28df,
134.1353 +  0x28e0,0x28e1,0x28e2,0x28e3,0x28e4,0x28e5,0x28e6,0x28e7,
134.1354 +  0x28e8,0x28e9,0x28ea,0x28eb,0x28ec,0x28ed,0x28ee,0x28ef,
134.1355 +  0x28f0,0x28f1,0x28f2,0x28f3,0x28f4,0x28f5,0x28f6,0x28f7,
134.1356 +  0x28f8,0x28f9,0x28fa,0x28fb,0x28fc,0x28fd,0x28fe,0x28ff,
134.1357 +  0x2900,0x2901,0x2902,0x2903,0x2904,0x2905,0x2906,0x2907,
134.1358 +  0x2908,0x2909,0x290a,0x290b,0x290c,0x290d,0x290e,0x290f,
134.1359 +  0x2910,0x2911,0x2912,0x2913,0x2914,0x2915,0x2916,0x2917,
134.1360 +  0x2918,0x2919,0x291a,0x291b,0x291c,0x291d,0x291e,0x291f,
134.1361 +  0x2920,0x2921,0x2922,0x2923,0x2924,0x2925,0x2926,0x2927,
134.1362 +  0x2928,0x2929,0x292a,0x292b,0x292c,0x292d,0x292e,0x292f,
134.1363 +  0x2930,0x2931,0x2932,0x2933,0x2934,0x2935,0x2936,0x2937,
134.1364 +  0x2938,0x2939,0x293a,0x293b,0x293c,0x293d,0x293e,0x293f,
134.1365 +  0x2940,0x2941,0x2942,0x2943,0x2944,0x2945,0x2946,0x2947,
134.1366 +  0x2948,0x2949,0x294a,0x294b,0x294c,0x294d,0x294e,0x294f,
134.1367 +  0x2950,0x2951,0x2952,0x2953,0x2954,0x2955,0x2956,0x2957,
134.1368 +  0x2958,0x2959,0x295a,0x295b,0x295c,0x295d,0x295e,0x295f,
134.1369 +  0x2960,0x2961,0x2962,0x2963,0x2964,0x2965,0x2966,0x2967,
134.1370 +  0x2968,0x2969,0x296a,0x296b,0x296c,0x296d,0x296e,0x296f,
134.1371 +  0x2970,0x2971,0x2972,0x2973,0x2974,0x2975,0x2976,0x2977,
134.1372 +  0x2978,0x2979,0x297a,0x297b,0x297c,0x297d,0x297e,0x297f,
134.1373 +  0x2980,0x2981,0x2982,0x2983,0x2984,0x2985,0x2986,0x2987,
134.1374 +  0x2988,0x2989,0x298a,0x298b,0x298c,0x298d,0x298e,0x298f,
134.1375 +  0x2990,0x2991,0x2992,0x2993,0x2994,0x2995,0x2996,0x2997,
134.1376 +  0x2998,0x2999,0x299a,0x299b,0x299c,0x299d,0x299e,0x299f,
134.1377 +  0x29a0,0x29a1,0x29a2,0x29a3,0x29a4,0x29a5,0x29a6,0x29a7,
134.1378 +  0x29a8,0x29a9,0x29aa,0x29ab,0x29ac,0x29ad,0x29ae,0x29af,
134.1379 +  0x29b0,0x29b1,0x29b2,0x29b3,0x29b4,0x29b5,0x29b6,0x29b7,
134.1380 +  0x29b8,0x29b9,0x29ba,0x29bb,0x29bc,0x29bd,0x29be,0x29bf,
134.1381 +  0x29c0,0x29c1,0x29c2,0x29c3,0x29c4,0x29c5,0x29c6,0x29c7,
134.1382 +  0x29c8,0x29c9,0x29ca,0x29cb,0x29cc,0x29cd,0x29ce,0x29cf,
134.1383 +  0x29d0,0x29d1,0x29d2,0x29d3,0x29d4,0x29d5,0x29d6,0x29d7,
134.1384 +  0x29d8,0x29d9,0x29da,0x29db,0x29dc,0x29dd,0x29de,0x29df,
134.1385 +  0x29e0,0x29e1,0x29e2,0x29e3,0x29e4,0x29e5,0x29e6,0x29e7,
134.1386 +  0x29e8,0x29e9,0x29ea,0x29eb,0x29ec,0x29ed,0x29ee,0x29ef,
134.1387 +  0x29f0,0x29f1,0x29f2,0x29f3,0x29f4,0x29f5,0x29f6,0x29f7,
134.1388 +  0x29f8,0x29f9,0x29fa,0x29fb,0x29fc,0x29fd,0x29fe,0x29ff,
134.1389 +  0x2a00,0x2a01,0x2a02,0x2a03,0x2a04,0x2a05,0x2a06,0x2a07,
134.1390 +  0x2a08,0x2a09,0x2a0a,0x2a0b,0x2a0c,0x2a0d,0x2a0e,0x2a0f,
134.1391 +  0x2a10,0x2a11,0x2a12,0x2a13,0x2a14,0x2a15,0x2a16,0x2a17,
134.1392 +  0x2a18,0x2a19,0x2a1a,0x2a1b,0x2a1c,0x2a1d,0x2a1e,0x2a1f,
134.1393 +  0x2a20,0x2a21,0x2a22,0x2a23,0x2a24,0x2a25,0x2a26,0x2a27,
134.1394 +  0x2a28,0x2a29,0x2a2a,0x2a2b,0x2a2c,0x2a2d,0x2a2e,0x2a2f,
134.1395 +  0x2a30,0x2a31,0x2a32,0x2a33,0x2a34,0x2a35,0x2a36,0x2a37,
134.1396 +  0x2a38,0x2a39,0x2a3a,0x2a3b,0x2a3c,0x2a3d,0x2a3e,0x2a3f,
134.1397 +  0x2a40,0x2a41,0x2a42,0x2a43,0x2a44,0x2a45,0x2a46,0x2a47,
134.1398 +  0x2a48,0x2a49,0x2a4a,0x2a4b,0x2a4c,0x2a4d,0x2a4e,0x2a4f,
134.1399 +  0x2a50,0x2a51,0x2a52,0x2a53,0x2a54,0x2a55,0x2a56,0x2a57,
134.1400 +  0x2a58,0x2a59,0x2a5a,0x2a5b,0x2a5c,0x2a5d,0x2a5e,0x2a5f,
134.1401 +  0x2a60,0x2a61,0x2a62,0x2a63,0x2a64,0x2a65,0x2a66,0x2a67,
134.1402 +  0x2a68,0x2a69,0x2a6a,0x2a6b,0x2a6c,0x2a6d,0x2a6e,0x2a6f,
134.1403 +  0x2a70,0x2a71,0x2a72,0x2a73,0x2a74,0x2a75,0x2a76,0x2a77,
134.1404 +  0x2a78,0x2a79,0x2a7a,0x2a7b,0x2a7c,0x2a7d,0x2a7e,0x2a7f,
134.1405 +  0x2a80,0x2a81,0x2a82,0x2a83,0x2a84,0x2a85,0x2a86,0x2a87,
134.1406 +  0x2a88,0x2a89,0x2a8a,0x2a8b,0x2a8c,0x2a8d,0x2a8e,0x2a8f,
134.1407 +  0x2a90,0x2a91,0x2a92,0x2a93,0x2a94,0x2a95,0x2a96,0x2a97,
134.1408 +  0x2a98,0x2a99,0x2a9a,0x2a9b,0x2a9c,0x2a9d,0x2a9e,0x2a9f,
134.1409 +  0x2aa0,0x2aa1,0x2aa2,0x2aa3,0x2aa4,0x2aa5,0x2aa6,0x2aa7,
134.1410 +  0x2aa8,0x2aa9,0x2aaa,0x2aab,0x2aac,0x2aad,0x2aae,0x2aaf,
134.1411 +  0x2ab0,0x2ab1,0x2ab2,0x2ab3,0x2ab4,0x2ab5,0x2ab6,0x2ab7,
134.1412 +  0x2ab8,0x2ab9,0x2aba,0x2abb,0x2abc,0x2abd,0x2abe,0x2abf,
134.1413 +  0x2ac0,0x2ac1,0x2ac2,0x2ac3,0x2ac4,0x2ac5,0x2ac6,0x2ac7,
134.1414 +  0x2ac8,0x2ac9,0x2aca,0x2acb,0x2acc,0x2acd,0x2ace,0x2acf,
134.1415 +  0x2ad0,0x2ad1,0x2ad2,0x2ad3,0x2ad4,0x2ad5,0x2ad6,0x2ad7,
134.1416 +  0x2ad8,0x2ad9,0x2ada,0x2adb,0x2adc,0x2add,0x2ade,0x2adf,
134.1417 +  0x2ae0,0x2ae1,0x2ae2,0x2ae3,0x2ae4,0x2ae5,0x2ae6,0x2ae7,
134.1418 +  0x2ae8,0x2ae9,0x2aea,0x2aeb,0x2aec,0x2aed,0x2aee,0x2aef,
134.1419 +  0x2af0,0x2af1,0x2af2,0x2af3,0x2af4,0x2af5,0x2af6,0x2af7,
134.1420 +  0x2af8,0x2af9,0x2afa,0x2afb,0x2afc,0x2afd,0x2afe,0x2aff,
134.1421 +  0x2b00,0x2b01,0x2b02,0x2b03,0x2b04,0x2b05,0x2b06,0x2b07,
134.1422 +  0x2b08,0x2b09,0x2b0a,0x2b0b,0x2b0c,0x2b0d,0x2b0e,0x2b0f,
134.1423 +  0x2b10,0x2b11,0x2b12,0x2b13,0x2b14,0x2b15,0x2b16,0x2b17,
134.1424 +  0x2b18,0x2b19,0x2b1a,0x2b1b,0x2b1c,0x2b1d,0x2b1e,0x2b1f,
134.1425 +  0x2b20,0x2b21,0x2b22,0x2b23,0x2b24,0x2b25,0x2b26,0x2b27,
134.1426 +  0x2b28,0x2b29,0x2b2a,0x2b2b,0x2b2c,0x2b2d,0x2b2e,0x2b2f,
134.1427 +  0x2b30,0x2b31,0x2b32,0x2b33,0x2b34,0x2b35,0x2b36,0x2b37,
134.1428 +  0x2b38,0x2b39,0x2b3a,0x2b3b,0x2b3c,0x2b3d,0x2b3e,0x2b3f,
134.1429 +  0x2b40,0x2b41,0x2b42,0x2b43,0x2b44,0x2b45,0x2b46,0x2b47,
134.1430 +  0x2b48,0x2b49,0x2b4a,0x2b4b,0x2b4c,0x2b4d,0x2b4e,0x2b4f,
134.1431 +  0x2b50,0x2b51,0x2b52,0x2b53,0x2b54,0x2b55,0x2b56,0x2b57,
134.1432 +  0x2b58,0x2b59,0x2b5a,0x2b5b,0x2b5c,0x2b5d,0x2b5e,0x2b5f,
134.1433 +  0x2b60,0x2b61,0x2b62,0x2b63,0x2b64,0x2b65,0x2b66,0x2b67,
134.1434 +  0x2b68,0x2b69,0x2b6a,0x2b6b,0x2b6c,0x2b6d,0x2b6e,0x2b6f,
134.1435 +  0x2b70,0x2b71,0x2b72,0x2b73,0x2b74,0x2b75,0x2b76,0x2b77,
134.1436 +  0x2b78,0x2b79,0x2b7a,0x2b7b,0x2b7c,0x2b7d,0x2b7e,0x2b7f,
134.1437 +  0x2b80,0x2b81,0x2b82,0x2b83,0x2b84,0x2b85,0x2b86,0x2b87,
134.1438 +  0x2b88,0x2b89,0x2b8a,0x2b8b,0x2b8c,0x2b8d,0x2b8e,0x2b8f,
134.1439 +  0x2b90,0x2b91,0x2b92,0x2b93,0x2b94,0x2b95,0x2b96,0x2b97,
134.1440 +  0x2b98,0x2b99,0x2b9a,0x2b9b,0x2b9c,0x2b9d,0x2b9e,0x2b9f,
134.1441 +  0x2ba0,0x2ba1,0x2ba2,0x2ba3,0x2ba4,0x2ba5,0x2ba6,0x2ba7,
134.1442 +  0x2ba8,0x2ba9,0x2baa,0x2bab,0x2bac,0x2bad,0x2bae,0x2baf,
134.1443 +  0x2bb0,0x2bb1,0x2bb2,0x2bb3,0x2bb4,0x2bb5,0x2bb6,0x2bb7,
134.1444 +  0x2bb8,0x2bb9,0x2bba,0x2bbb,0x2bbc,0x2bbd,0x2bbe,0x2bbf,
134.1445 +  0x2bc0,0x2bc1,0x2bc2,0x2bc3,0x2bc4,0x2bc5,0x2bc6,0x2bc7,
134.1446 +  0x2bc8,0x2bc9,0x2bca,0x2bcb,0x2bcc,0x2bcd,0x2bce,0x2bcf,
134.1447 +  0x2bd0,0x2bd1,0x2bd2,0x2bd3,0x2bd4,0x2bd5,0x2bd6,0x2bd7,
134.1448 +  0x2bd8,0x2bd9,0x2bda,0x2bdb,0x2bdc,0x2bdd,0x2bde,0x2bdf,
134.1449 +  0x2be0,0x2be1,0x2be2,0x2be3,0x2be4,0x2be5,0x2be6,0x2be7,
134.1450 +  0x2be8,0x2be9,0x2bea,0x2beb,0x2bec,0x2bed,0x2bee,0x2bef,
134.1451 +  0x2bf0,0x2bf1,0x2bf2,0x2bf3,0x2bf4,0x2bf5,0x2bf6,0x2bf7,
134.1452 +  0x2bf8,0x2bf9,0x2bfa,0x2bfb,0x2bfc,0x2bfd,0x2bfe,0x2bff,
134.1453 +  0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07,
134.1454 +  0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f,
134.1455 +  0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17,
134.1456 +  0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f,
134.1457 +  0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27,
134.1458 +  0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c2f,
134.1459 +  0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07,
134.1460 +  0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f,
134.1461 +  0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17,
134.1462 +  0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f,
134.1463 +  0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27,
134.1464 +  0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c5f,
134.1465 +  0x2c60,0x2c60,0x2c62,0x2c63,0x2c64,0x023a,0x023e,0x2c67,
134.1466 +  0x2c67,0x2c69,0x2c69,0x2c6b,0x2c6b,0x2c6d,0x2c6e,0x2c6f,
134.1467 +  0x2c70,0x2c71,0x2c72,0x2c73,0x2c74,0x2c75,0x2c75,0x2c77,
134.1468 +  0x2c78,0x2c79,0x2c7a,0x2c7b,0x2c7c,0x2c7d,0x2c7e,0x2c7f,
134.1469 +  0x2c80,0x2c80,0x2c82,0x2c82,0x2c84,0x2c84,0x2c86,0x2c86,
134.1470 +  0x2c88,0x2c88,0x2c8a,0x2c8a,0x2c8c,0x2c8c,0x2c8e,0x2c8e,
134.1471 +  0x2c90,0x2c90,0x2c92,0x2c92,0x2c94,0x2c94,0x2c96,0x2c96,
134.1472 +  0x2c98,0x2c98,0x2c9a,0x2c9a,0x2c9c,0x2c9c,0x2c9e,0x2c9e,
134.1473 +  0x2ca0,0x2ca0,0x2ca2,0x2ca2,0x2ca4,0x2ca4,0x2ca6,0x2ca6,
134.1474 +  0x2ca8,0x2ca8,0x2caa,0x2caa,0x2cac,0x2cac,0x2cae,0x2cae,
134.1475 +  0x2cb0,0x2cb0,0x2cb2,0x2cb2,0x2cb4,0x2cb4,0x2cb6,0x2cb6,
134.1476 +  0x2cb8,0x2cb8,0x2cba,0x2cba,0x2cbc,0x2cbc,0x2cbe,0x2cbe,
134.1477 +  0x2cc0,0x2cc0,0x2cc2,0x2cc2,0x2cc4,0x2cc4,0x2cc6,0x2cc6,
134.1478 +  0x2cc8,0x2cc8,0x2cca,0x2cca,0x2ccc,0x2ccc,0x2cce,0x2cce,
134.1479 +  0x2cd0,0x2cd0,0x2cd2,0x2cd2,0x2cd4,0x2cd4,0x2cd6,0x2cd6,
134.1480 +  0x2cd8,0x2cd8,0x2cda,0x2cda,0x2cdc,0x2cdc,0x2cde,0x2cde,
134.1481 +  0x2ce0,0x2ce0,0x2ce2,0x2ce2,0x2ce4,0x2ce5,0x2ce6,0x2ce7,
134.1482 +  0x2ce8,0x2ce9,0x2cea,0x2ceb,0x2cec,0x2ced,0x2cee,0x2cef,
134.1483 +  0x2cf0,0x2cf1,0x2cf2,0x2cf3,0x2cf4,0x2cf5,0x2cf6,0x2cf7,
134.1484 +  0x2cf8,0x2cf9,0x2cfa,0x2cfb,0x2cfc,0x2cfd,0x2cfe,0x2cff,
134.1485 +  0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7,
134.1486 +  0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af,
134.1487 +  0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7,
134.1488 +  0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf,
134.1489 +  0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5
134.1490 +};
   135.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.2 +++ b/src/charset/viscii.c	Mon Sep 14 15:17:45 2009 +0900
   135.3 @@ -0,0 +1,67 @@
   135.4 +/* ========================================================================
   135.5 + * Copyright 1988-2006 University of Washington
   135.6 + *
   135.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   135.8 + * you may not use this file except in compliance with the License.
   135.9 + * You may obtain a copy of the License at
  135.10 + *
  135.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  135.12 + *
  135.13 + * 
  135.14 + * ========================================================================
  135.15 + */
  135.16 +
  135.17 +/*
  135.18 + * Program:	VISCII conversion table
  135.19 + *
  135.20 + * Author:	Mark Crispin
  135.21 + *		Networks and Distributed Computing
  135.22 + *		Computing & Communications
  135.23 + *		University of Washington
  135.24 + *		Administration Building, AG-44
  135.25 + *		Seattle, WA  98195
  135.26 + *		Internet: MRC@CAC.Washington.EDU
  135.27 + *
  135.28 + * Date:	2 June 1998
  135.29 + * Last Edited:	30 August 2006
  135.30 + */
  135.31 +
  135.32 +/* VISCII is the VIetnamese Standard Code for Information Interchange,
  135.33 + * defined by the Vietnamese Standardization Working Group, RFC-1456,
  135.34 + * May 1993.
  135.35 + */
  135.36 +
  135.37 +static const unsigned short visciitab[256] = {
  135.38 +  0x0000,0x0001,0x1eb2,0x0003,0x0004,0x1eb4,0x1eaa,0x0007,
  135.39 +  0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
  135.40 +  0x0010,0x0011,0x0012,0x0013,0x1ef6,0x0015,0x0016,0x0017,
  135.41 +  0x0018,0x1ef8,0x001a,0x001b,0x001c,0x001d,0x1ef4,0x001f,
  135.42 +  0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
  135.43 +  0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
  135.44 +  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
  135.45 +  0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
  135.46 +  0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
  135.47 +  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
  135.48 +  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
  135.49 +  0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
  135.50 +  0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
  135.51 +  0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
  135.52 +  0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
  135.53 +  0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,
  135.54 +  0x1ea0,0x1eae,0x1eb0,0x1eb6,0x1ea4,0x1ea6,0x1ea8,0x1eac,
  135.55 +  0x1ebc,0x1eb8,0x1ebe,0x1ec0,0x1ec2,0x1ec4,0x1ec6,0x1ed0,
  135.56 +  0x1ed2,0x1ed4,0x1ed6,0x1ed8,0x1ee2,0x1eda,0x1edc,0x1ede,
  135.57 +  0x1eca,0x1ece,0x1ecc,0x1ec8,0x1ee6,0x0168,0x1ee4,0x1ef2,
  135.58 +  0x00d5,0x1eaf,0x1eb1,0x1eb7,0x1ea5,0x1ea7,0x1ea9,0x1ead,
  135.59 +  0x1ebd,0x1eb9,0x1ebf,0x1ec1,0x1ec3,0x1ec5,0x1ec7,0x1ed1,
  135.60 +  0x1ed3,0x1ed5,0x1ed7,0x1ee0,0x01a0,0x1ed9,0x1edd,0x1edf,
  135.61 +  0x1ecb,0x1ef0,0x1ee8,0x1eea,0x1eec,0x01a1,0x1edb,0x01af,
  135.62 +  0x00c0,0x00c1,0x00c2,0x00c3,0x1ea2,0x0102,0x1eb3,0x1eb5,
  135.63 +  0x00c8,0x00c9,0x00ca,0x1eba,0x00cc,0x00cd,0x0128,0x1ef3,
  135.64 +  0x0110,0x1ee9,0x00d2,0x00d3,0x00d4,0x1ea1,0x1ef7,0x1eeb,
  135.65 +  0x1eed,0x00d9,0x00da,0x1ef9,0x1ef5,0x00dd,0x1ee1,0x01b0,
  135.66 +  0x00e0,0x00e1,0x00e2,0x00e3,0x1ea3,0x0103,0x1eef,0x1eab,
  135.67 +  0x00e8,0x00e9,0x00ea,0x1ebb,0x00ec,0x00ed,0x0129,0x1ec9,
  135.68 +  0x0111,0x1ef1,0x00f2,0x00f3,0x00f4,0x00f5,0x1ecf,0x1ecd,
  135.69 +  0x1ee5,0x00f9,0x00fa,0x0169,0x1ee7,0x00fd,0x1ee3,0x1eee
  135.70 +};
   136.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   136.2 +++ b/src/charset/widths.c	Mon Sep 14 15:17:45 2009 +0900
   136.3 @@ -0,0 +1,4136 @@
   136.4 +/* ========================================================================
   136.5 + * Copyright 1988-2007 University of Washington
   136.6 + *
   136.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   136.8 + * you may not use this file except in compliance with the License.
   136.9 + * You may obtain a copy of the License at
  136.10 + *
  136.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  136.12 + *
  136.13 + * 
  136.14 + * ========================================================================
  136.15 + */
  136.16 +
  136.17 +/*
  136.18 + * Program:	Unicode width table (current as of Unicode 5.0)
  136.19 + *
  136.20 + * Author:	Mark Crispin
  136.21 + *		Networks and Distributed Computing
  136.22 + *		Computing & Communications
  136.23 + *		University of Washington
  136.24 + *		Administration Building, AG-44
  136.25 + *		Seattle, WA  98195
  136.26 + *		Internet: MRC@CAC.Washington.EDU
  136.27 + *
  136.28 + * Date:	20 March 2006
  136.29 + * Last Edited:	1 March 2007
  136.30 + */
  136.31 +
  136.32 +/* Table of 2-bit character widths, indexed by Unicode codepoint and
  136.33 + * big-endian within bytes:
  136.34 + *  0	zero-width
  136.35 + *  1	single-width (half-width)
  136.36 + *  2	double-width (full-width)
  136.37 + *  3	ambiguous
  136.38 + */
  136.39 +
  136.40 +#define UCS4_WIDLEN 131072
  136.41 +
  136.42 +static const unsigned char ucs4_widthtab[32768] = {
  136.43 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0000 - U+001f */
  136.44 +  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+0020 - U+003f */
  136.45 +  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+0040 - U+005f */
  136.46 +  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,	/* U+0060 - U+007f */
  136.47 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0080 - U+009f */
  136.48 +  0xf5,0xd7,0xff,0x4d,0xff,0xff,0xff,0xff,	/* U+00a0 - U+00bf */
  136.49 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+00c0 - U+00df */
  136.50 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+00e0 - U+00ff */
  136.51 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0100 - U+011f */
  136.52 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0120 - U+013f */
  136.53 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0140 - U+015f */
  136.54 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0160 - U+017f */
  136.55 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0180 - U+019f */
  136.56 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+01a0 - U+01bf */
  136.57 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+01c0 - U+01df */
  136.58 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+01e0 - U+01ff */
  136.59 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0200 - U+021f */
  136.60 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0220 - U+023f */
  136.61 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0240 - U+025f */
  136.62 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0260 - U+027f */
  136.63 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0280 - U+029f */
  136.64 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+02a0 - U+02bf */
  136.65 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+02c0 - U+02df */
  136.66 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+02e0 - U+02ff */
  136.67 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0300 - U+031f */
  136.68 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0320 - U+033f */
  136.69 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0340 - U+035f */
  136.70 +  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,	/* U+0360 - U+037f */
  136.71 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0380 - U+039f */
  136.72 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+03a0 - U+03bf */
  136.73 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+03c0 - U+03df */
  136.74 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+03e0 - U+03ff */
  136.75 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0400 - U+041f */
  136.76 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0420 - U+043f */
  136.77 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0440 - U+045f */
  136.78 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0460 - U+047f */
  136.79 +  0xfc,0x03,0x0f,0xff,0xff,0xff,0xff,0xff,	/* U+0480 - U+049f */
  136.80 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+04a0 - U+04bf */
  136.81 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+04c0 - U+04df */
  136.82 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+04e0 - U+04ff */
  136.83 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0500 - U+051f */
  136.84 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0520 - U+053f */
  136.85 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0540 - U+055f */
  136.86 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0560 - U+057f */
  136.87 +  0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,	/* U+0580 - U+059f */
  136.88 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,	/* U+05a0 - U+05bf */
  136.89 +  0xc3,0x0c,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+05c0 - U+05df */
  136.90 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+05e0 - U+05ff */
  136.91 +  0x00,0xff,0xff,0xff,0x00,0x0f,0xff,0xff,	/* U+0600 - U+061f */
  136.92 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0620 - U+063f */
  136.93 +  0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x03,	/* U+0640 - U+065f */
  136.94 +  0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,	/* U+0660 - U+067f */
  136.95 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0680 - U+069f */
  136.96 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+06a0 - U+06bf */
  136.97 +  0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,	/* U+06c0 - U+06df */
  136.98 +  0x00,0x3c,0x30,0x0f,0xff,0xff,0xff,0xff,	/* U+06e0 - U+06ff */
  136.99 +  0xff,0xff,0xff,0xfc,0xcf,0xff,0xff,0xff,	/* U+0700 - U+071f */
 136.100 +  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,	/* U+0720 - U+073f */
 136.101 +  0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,	/* U+0740 - U+075f */
 136.102 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0760 - U+077f */
 136.103 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0780 - U+079f */
 136.104 +  0xff,0xf0,0x00,0x00,0x3f,0xff,0xff,0xff,	/* U+07a0 - U+07bf */
 136.105 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+07c0 - U+07df */
 136.106 +  0xff,0xff,0xfc,0x00,0x00,0xff,0xff,0xff,	/* U+07e0 - U+07ff */
 136.107 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0800 - U+081f */
 136.108 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0820 - U+083f */
 136.109 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0840 - U+085f */
 136.110 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0860 - U+087f */
 136.111 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0880 - U+089f */
 136.112 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+08a0 - U+08bf */
 136.113 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+08c0 - U+08df */
 136.114 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+08e0 - U+08ff */
 136.115 +  0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0900 - U+091f */
 136.116 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0920 - U+093f */
 136.117 +  0xc0,0x00,0x3f,0xcf,0xc0,0x3f,0xff,0xff,	/* U+0940 - U+095f */
 136.118 +  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0960 - U+097f */
 136.119 +  0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0980 - U+099f */
 136.120 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+09a0 - U+09bf */
 136.121 +  0xc0,0x3f,0xff,0xcf,0xff,0xff,0xff,0xff,	/* U+09c0 - U+09df */
 136.122 +  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+09e0 - U+09ff */
 136.123 +  0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0a00 - U+0a1f */
 136.124 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0a20 - U+0a3f */
 136.125 +  0xc3,0xfc,0x3c,0x0f,0xff,0xff,0xff,0xff,	/* U+0a40 - U+0a5f */
 136.126 +  0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,	/* U+0a60 - U+0a7f */
 136.127 +  0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0a80 - U+0a9f */
 136.128 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0aa0 - U+0abf */
 136.129 +  0xc0,0x0c,0x3f,0xcf,0xff,0xff,0xff,0xff,	/* U+0ac0 - U+0adf */
 136.130 +  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ae0 - U+0aff */
 136.131 +  0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0b00 - U+0b1f */
 136.132 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3c,	/* U+0b20 - U+0b3f */
 136.133 +  0xc0,0xff,0xff,0xcf,0xff,0xf3,0xff,0xff,	/* U+0b40 - U+0b5f */
 136.134 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0b60 - U+0b7f */
 136.135 +  0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0b80 - U+0b9f */
 136.136 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ba0 - U+0bbf */
 136.137 +  0x3f,0xff,0xff,0xcf,0xff,0xff,0xff,0xff,	/* U+0bc0 - U+0bdf */
 136.138 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0be0 - U+0bff */
 136.139 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0c00 - U+0c1f */
 136.140 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,	/* U+0c20 - U+0c3f */
 136.141 +  0x3f,0xf0,0x30,0x0f,0xff,0xc3,0xff,0xff,	/* U+0c40 - U+0c5f */
 136.142 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0c60 - U+0c7f */
 136.143 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0c80 - U+0c9f */
 136.144 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0ca0 - U+0cbf */
 136.145 +  0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,	/* U+0cc0 - U+0cdf */
 136.146 +  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ce0 - U+0cff */
 136.147 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d00 - U+0d1f */
 136.148 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d20 - U+0d3f */
 136.149 +  0xc0,0xff,0xff,0xcf,0xff,0xff,0xff,0xff,	/* U+0d40 - U+0d5f */
 136.150 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d60 - U+0d7f */
 136.151 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d80 - U+0d9f */
 136.152 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0da0 - U+0dbf */
 136.153 +  0xff,0xff,0xf3,0xff,0xf0,0x33,0xff,0xff,	/* U+0dc0 - U+0ddf */
 136.154 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0de0 - U+0dff */
 136.155 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0e00 - U+0e1f */
 136.156 +  0xff,0xff,0xff,0xff,0xcf,0x00,0x03,0xff,	/* U+0e20 - U+0e3f */
 136.157 +  0xff,0xfc,0x00,0x03,0xff,0xff,0xff,0xff,	/* U+0e40 - U+0e5f */
 136.158 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0e60 - U+0e7f */
 136.159 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0e80 - U+0e9f */
 136.160 +  0xff,0xff,0xff,0xff,0xcf,0x00,0x0c,0x3f,	/* U+0ea0 - U+0ebf */
 136.161 +  0xff,0xff,0x00,0x0f,0xff,0xff,0xff,0xff,	/* U+0ec0 - U+0edf */
 136.162 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ee0 - U+0eff */
 136.163 +  0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,	/* U+0f00 - U+0f1f */
 136.164 +  0xff,0xff,0xff,0xff,0xff,0xcc,0xcf,0xff,	/* U+0f20 - U+0f3f */
 136.165 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0f40 - U+0f5f */
 136.166 +  0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x03,	/* U+0f60 - U+0f7f */
 136.167 +  0x00,0x30,0xff,0xff,0x00,0x00,0xc0,0x00,	/* U+0f80 - U+0f9f */
 136.168 +  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,	/* U+0fa0 - U+0fbf */
 136.169 +  0xff,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0fc0 - U+0fdf */
 136.170 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0fe0 - U+0fff */
 136.171 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1000 - U+101f */
 136.172 +  0xff,0xff,0xff,0xc0,0x33,0xf0,0xcf,0xff,	/* U+1020 - U+103f */
 136.173 +  0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,	/* U+1040 - U+105f */
 136.174 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1060 - U+107f */
 136.175 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1080 - U+109f */
 136.176 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a0 - U+10bf */
 136.177 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c0 - U+10df */
 136.178 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e0 - U+10ff */
 136.179 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+1100 - U+111f */
 136.180 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+1120 - U+113f */
 136.181 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xfe,	/* U+1140 - U+115f */
 136.182 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1160 - U+117f */
 136.183 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1180 - U+119f */
 136.184 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a0 - U+11bf */
 136.185 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c0 - U+11df */
 136.186 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e0 - U+11ff */
 136.187 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1200 - U+121f */
 136.188 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1220 - U+123f */
 136.189 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1240 - U+125f */
 136.190 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1260 - U+127f */
 136.191 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1280 - U+129f */
 136.192 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a0 - U+12bf */
 136.193 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c0 - U+12df */
 136.194 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e0 - U+12ff */
 136.195 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1300 - U+131f */
 136.196 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1320 - U+133f */
 136.197 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+1340 - U+135f */
 136.198 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1360 - U+137f */
 136.199 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1380 - U+139f */
 136.200 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a0 - U+13bf */
 136.201 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c0 - U+13df */
 136.202 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e0 - U+13ff */
 136.203 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1400 - U+141f */
 136.204 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1420 - U+143f */
 136.205 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1440 - U+145f */
 136.206 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1460 - U+147f */
 136.207 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1480 - U+149f */
 136.208 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a0 - U+14bf */
 136.209 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c0 - U+14df */
 136.210 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e0 - U+14ff */
 136.211 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1500 - U+151f */
 136.212 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1520 - U+153f */
 136.213 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1540 - U+155f */
 136.214 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1560 - U+157f */
 136.215 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1580 - U+159f */
 136.216 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a0 - U+15bf */
 136.217 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c0 - U+15df */
 136.218 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e0 - U+15ff */
 136.219 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1600 - U+161f */
 136.220 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1620 - U+163f */
 136.221 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1640 - U+165f */
 136.222 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1660 - U+167f */
 136.223 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1680 - U+169f */
 136.224 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a0 - U+16bf */
 136.225 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c0 - U+16df */
 136.226 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e0 - U+16ff */
 136.227 +  0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,	/* U+1700 - U+171f */
 136.228 +  0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,	/* U+1720 - U+173f */
 136.229 +  0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,	/* U+1740 - U+175f */
 136.230 +  0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,	/* U+1760 - U+177f */
 136.231 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1780 - U+179f */
 136.232 +  0xff,0xff,0xff,0xff,0xff,0x0c,0x00,0x0f,	/* U+17a0 - U+17bf */
 136.233 +  0xff,0xf3,0xc0,0x00,0x00,0xff,0xff,0xcf,	/* U+17c0 - U+17df */
 136.234 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e0 - U+17ff */
 136.235 +  0xff,0xff,0xfc,0x0f,0xff,0xff,0xff,0xff,	/* U+1800 - U+181f */
 136.236 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1820 - U+183f */
 136.237 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1840 - U+185f */
 136.238 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1860 - U+187f */
 136.239 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1880 - U+189f */
 136.240 +  0xff,0xff,0xcf,0xff,0xff,0xff,0xff,0xff,	/* U+18a0 - U+18bf */
 136.241 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c0 - U+18df */
 136.242 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e0 - U+18ff */
 136.243 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1900 - U+191f */
 136.244 +  0x03,0xfc,0x00,0xff,0xf3,0xff,0xc0,0xff,	/* U+1920 - U+193f */
 136.245 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1940 - U+195f */
 136.246 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1960 - U+197f */
 136.247 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1980 - U+199f */
 136.248 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a0 - U+19bf */
 136.249 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c0 - U+19df */
 136.250 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e0 - U+19ff */
 136.251 +  0xff,0xff,0xff,0xff,0xff,0xfc,0x3f,0xff,	/* U+1a00 - U+1a1f */
 136.252 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a20 - U+1a3f */
 136.253 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a40 - U+1a5f */
 136.254 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a60 - U+1a7f */
 136.255 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a80 - U+1a9f */
 136.256 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa0 - U+1abf */
 136.257 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac0 - U+1adf */
 136.258 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae0 - U+1aff */
 136.259 +  0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b00 - U+1b1f */
 136.260 +  0xff,0xff,0xff,0xff,0xff,0x30,0x03,0x3f,	/* U+1b20 - U+1b3f */
 136.261 +  0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b40 - U+1b5f */
 136.262 +  0xff,0xff,0xfc,0x00,0x00,0xff,0xff,0xff,	/* U+1b60 - U+1b7f */
 136.263 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b80 - U+1b9f */
 136.264 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba0 - U+1bbf */
 136.265 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc0 - U+1bdf */
 136.266 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be0 - U+1bff */
 136.267 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c00 - U+1c1f */
 136.268 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c20 - U+1c3f */
 136.269 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c40 - U+1c5f */
 136.270 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c60 - U+1c7f */
 136.271 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c80 - U+1c9f */
 136.272 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca0 - U+1cbf */
 136.273 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc0 - U+1cdf */
 136.274 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce0 - U+1cff */
 136.275 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d00 - U+1d1f */
 136.276 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d20 - U+1d3f */
 136.277 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d40 - U+1d5f */
 136.278 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d60 - U+1d7f */
 136.279 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d80 - U+1d9f */
 136.280 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da0 - U+1dbf */
 136.281 +  0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,	/* U+1dc0 - U+1ddf */
 136.282 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,	/* U+1de0 - U+1dff */
 136.283 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e00 - U+1e1f */
 136.284 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e20 - U+1e3f */
 136.285 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e40 - U+1e5f */
 136.286 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e60 - U+1e7f */
 136.287 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e80 - U+1e9f */
 136.288 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea0 - U+1ebf */
 136.289 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec0 - U+1edf */
 136.290 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee0 - U+1eff */
 136.291 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f00 - U+1f1f */
 136.292 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f20 - U+1f3f */
 136.293 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f40 - U+1f5f */
 136.294 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f60 - U+1f7f */
 136.295 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f80 - U+1f9f */
 136.296 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa0 - U+1fbf */
 136.297 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc0 - U+1fdf */
 136.298 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe0 - U+1fff */
 136.299 +  0xff,0xff,0xfc,0x00,0xff,0xff,0xff,0xff,	/* U+2000 - U+201f */
 136.300 +  0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,	/* U+2020 - U+203f */
 136.301 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2040 - U+205f */
 136.302 +  0x00,0xff,0xf0,0x00,0xff,0xff,0xff,0xff,	/* U+2060 - U+207f */
 136.303 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2080 - U+209f */
 136.304 +  0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,	/* U+20a0 - U+20bf */
 136.305 +  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,	/* U+20c0 - U+20df */
 136.306 +  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,	/* U+20e0 - U+20ff */
 136.307 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2100 - U+211f */
 136.308 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2120 - U+213f */
 136.309 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2140 - U+215f */
 136.310 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2160 - U+217f */
 136.311 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2180 - U+219f */
 136.312 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+21a0 - U+21bf */
 136.313 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+21c0 - U+21df */
 136.314 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+21e0 - U+21ff */
 136.315 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2200 - U+221f */
 136.316 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2220 - U+223f */
 136.317 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2240 - U+225f */
 136.318 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2260 - U+227f */
 136.319 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2280 - U+229f */
 136.320 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+22a0 - U+22bf */
 136.321 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+22c0 - U+22df */
 136.322 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+22e0 - U+22ff */
 136.323 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2300 - U+231f */
 136.324 +  0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,	/* U+2320 - U+233f */
 136.325 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2340 - U+235f */
 136.326 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2360 - U+237f */
 136.327 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2380 - U+239f */
 136.328 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+23a0 - U+23bf */
 136.329 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+23c0 - U+23df */
 136.330 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+23e0 - U+23ff */
 136.331 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2400 - U+241f */
 136.332 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2420 - U+243f */
 136.333 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2440 - U+245f */
 136.334 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2460 - U+247f */
 136.335 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2480 - U+249f */
 136.336 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+24a0 - U+24bf */
 136.337 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+24c0 - U+24df */
 136.338 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+24e0 - U+24ff */
 136.339 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2500 - U+251f */
 136.340 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2520 - U+253f */
 136.341 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2540 - U+255f */
 136.342 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2560 - U+257f */
 136.343 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2580 - U+259f */
 136.344 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+25a0 - U+25bf */
 136.345 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+25c0 - U+25df */
 136.346 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+25e0 - U+25ff */
 136.347 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2600 - U+261f */
 136.348 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2620 - U+263f */
 136.349 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2640 - U+265f */
 136.350 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2660 - U+267f */
 136.351 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2680 - U+269f */
 136.352 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+26a0 - U+26bf */
 136.353 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+26c0 - U+26df */
 136.354 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+26e0 - U+26ff */
 136.355 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2700 - U+271f */
 136.356 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2720 - U+273f */
 136.357 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2740 - U+275f */
 136.358 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2760 - U+277f */
 136.359 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2780 - U+279f */
 136.360 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+27a0 - U+27bf */
 136.361 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+27c0 - U+27df */
 136.362 +  0xff,0xf5,0x55,0xff,0xff,0xff,0xff,0xff,	/* U+27e0 - U+27ff */
 136.363 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2800 - U+281f */
 136.364 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2820 - U+283f */
 136.365 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2840 - U+285f */
 136.366 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2860 - U+287f */
 136.367 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2880 - U+289f */
 136.368 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+28a0 - U+28bf */
 136.369 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+28c0 - U+28df */
 136.370 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+28e0 - U+28ff */
 136.371 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2900 - U+291f */
 136.372 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2920 - U+293f */
 136.373 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2940 - U+295f */
 136.374 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2960 - U+297f */
 136.375 +  0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2980 - U+299f */
 136.376 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+29a0 - U+29bf */
 136.377 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+29c0 - U+29df */
 136.378 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+29e0 - U+29ff */
 136.379 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a00 - U+2a1f */
 136.380 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a20 - U+2a3f */
 136.381 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a40 - U+2a5f */
 136.382 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a60 - U+2a7f */
 136.383 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a80 - U+2a9f */
 136.384 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2aa0 - U+2abf */
 136.385 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ac0 - U+2adf */
 136.386 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ae0 - U+2aff */
 136.387 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b00 - U+2b1f */
 136.388 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b20 - U+2b3f */
 136.389 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b40 - U+2b5f */
 136.390 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b60 - U+2b7f */
 136.391 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b80 - U+2b9f */
 136.392 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ba0 - U+2bbf */
 136.393 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2bc0 - U+2bdf */
 136.394 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2be0 - U+2bff */
 136.395 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c00 - U+2c1f */
 136.396 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c20 - U+2c3f */
 136.397 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c40 - U+2c5f */
 136.398 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c60 - U+2c7f */
 136.399 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c80 - U+2c9f */
 136.400 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ca0 - U+2cbf */
 136.401 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2cc0 - U+2cdf */
 136.402 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ce0 - U+2cff */
 136.403 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d00 - U+2d1f */
 136.404 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d20 - U+2d3f */
 136.405 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d40 - U+2d5f */
 136.406 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d60 - U+2d7f */
 136.407 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d80 - U+2d9f */
 136.408 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2da0 - U+2dbf */
 136.409 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2dc0 - U+2ddf */
 136.410 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2de0 - U+2dff */
 136.411 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e00 - U+2e1f */
 136.412 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e20 - U+2e3f */
 136.413 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e40 - U+2e5f */
 136.414 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e60 - U+2e7f */
 136.415 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xae,0xaa,	/* U+2e80 - U+2e9f */
 136.416 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2ea0 - U+2ebf */
 136.417 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2ec0 - U+2edf */
 136.418 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,	/* U+2ee0 - U+2eff */
 136.419 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f00 - U+2f1f */
 136.420 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f20 - U+2f3f */
 136.421 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f40 - U+2f5f */
 136.422 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f60 - U+2f7f */
 136.423 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f80 - U+2f9f */
 136.424 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2fa0 - U+2fbf */
 136.425 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,0xff,	/* U+2fc0 - U+2fdf */
 136.426 +  0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xff,	/* U+2fe0 - U+2fff */
 136.427 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3000 - U+301f */
 136.428 +  0xaa,0xaa,0xa0,0x00,0xaa,0xaa,0xaa,0xab,	/* U+3020 - U+303f */
 136.429 +  0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3040 - U+305f */
 136.430 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3060 - U+307f */
 136.431 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xab,0xc2,0xaa,	/* U+3080 - U+309f */
 136.432 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+30a0 - U+30bf */
 136.433 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+30c0 - U+30df */
 136.434 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+30e0 - U+30ff */
 136.435 +  0xff,0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3100 - U+311f */
 136.436 +  0xaa,0xaa,0xaa,0xbf,0xea,0xaa,0xaa,0xaa,	/* U+3120 - U+313f */
 136.437 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3140 - U+315f */
 136.438 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3160 - U+317f */
 136.439 +  0xaa,0xaa,0xaa,0xab,0xaa,0xaa,0xaa,0xaa,	/* U+3180 - U+319f */
 136.440 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xff,0xff,	/* U+31a0 - U+31bf */
 136.441 +  0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,	/* U+31c0 - U+31df */
 136.442 +  0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+31e0 - U+31ff */
 136.443 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab,	/* U+3200 - U+321f */
 136.444 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3220 - U+323f */
 136.445 +  0xaa,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+3240 - U+325f */
 136.446 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3260 - U+327f */
 136.447 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3280 - U+329f */
 136.448 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+32a0 - U+32bf */
 136.449 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+32c0 - U+32df */
 136.450 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab,	/* U+32e0 - U+32ff */
 136.451 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3300 - U+331f */
 136.452 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3320 - U+333f */
 136.453 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3340 - U+335f */
 136.454 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3360 - U+337f */
 136.455 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3380 - U+339f */
 136.456 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+33a0 - U+33bf */
 136.457 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+33c0 - U+33df */
 136.458 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+33e0 - U+33ff */
 136.459 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3400 - U+341f */
 136.460 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3420 - U+343f */
 136.461 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3440 - U+345f */
 136.462 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3460 - U+347f */
 136.463 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3480 - U+349f */
 136.464 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+34a0 - U+34bf */
 136.465 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+34c0 - U+34df */
 136.466 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+34e0 - U+34ff */
 136.467 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3500 - U+351f */
 136.468 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3520 - U+353f */
 136.469 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3540 - U+355f */
 136.470 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3560 - U+357f */
 136.471 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3580 - U+359f */
 136.472 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+35a0 - U+35bf */
 136.473 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+35c0 - U+35df */
 136.474 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+35e0 - U+35ff */
 136.475 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3600 - U+361f */
 136.476 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3620 - U+363f */
 136.477 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3640 - U+365f */
 136.478 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3660 - U+367f */
 136.479 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3680 - U+369f */
 136.480 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+36a0 - U+36bf */
 136.481 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+36c0 - U+36df */
 136.482 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+36e0 - U+36ff */
 136.483 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3700 - U+371f */
 136.484 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3720 - U+373f */
 136.485 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3740 - U+375f */
 136.486 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3760 - U+377f */
 136.487 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3780 - U+379f */
 136.488 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+37a0 - U+37bf */
 136.489 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+37c0 - U+37df */
 136.490 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+37e0 - U+37ff */
 136.491 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3800 - U+381f */
 136.492 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3820 - U+383f */
 136.493 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3840 - U+385f */
 136.494 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3860 - U+387f */
 136.495 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3880 - U+389f */
 136.496 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+38a0 - U+38bf */
 136.497 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+38c0 - U+38df */
 136.498 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+38e0 - U+38ff */
 136.499 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3900 - U+391f */
 136.500 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3920 - U+393f */
 136.501 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3940 - U+395f */
 136.502 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3960 - U+397f */
 136.503 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3980 - U+399f */
 136.504 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+39a0 - U+39bf */
 136.505 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+39c0 - U+39df */
 136.506 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+39e0 - U+39ff */
 136.507 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a00 - U+3a1f */
 136.508 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a20 - U+3a3f */
 136.509 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a40 - U+3a5f */
 136.510 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a60 - U+3a7f */
 136.511 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a80 - U+3a9f */
 136.512 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3aa0 - U+3abf */
 136.513 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ac0 - U+3adf */
 136.514 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ae0 - U+3aff */
 136.515 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b00 - U+3b1f */
 136.516 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b20 - U+3b3f */
 136.517 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b40 - U+3b5f */
 136.518 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b60 - U+3b7f */
 136.519 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b80 - U+3b9f */
 136.520 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ba0 - U+3bbf */
 136.521 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3bc0 - U+3bdf */
 136.522 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3be0 - U+3bff */
 136.523 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c00 - U+3c1f */
 136.524 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c20 - U+3c3f */
 136.525 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c40 - U+3c5f */
 136.526 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c60 - U+3c7f */
 136.527 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c80 - U+3c9f */
 136.528 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ca0 - U+3cbf */
 136.529 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3cc0 - U+3cdf */
 136.530 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ce0 - U+3cff */
 136.531 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d00 - U+3d1f */
 136.532 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d20 - U+3d3f */
 136.533 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d40 - U+3d5f */
 136.534 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d60 - U+3d7f */
 136.535 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d80 - U+3d9f */
 136.536 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3da0 - U+3dbf */
 136.537 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3dc0 - U+3ddf */
 136.538 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3de0 - U+3dff */
 136.539 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e00 - U+3e1f */
 136.540 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e20 - U+3e3f */
 136.541 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e40 - U+3e5f */
 136.542 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e60 - U+3e7f */
 136.543 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e80 - U+3e9f */
 136.544 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ea0 - U+3ebf */
 136.545 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ec0 - U+3edf */
 136.546 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ee0 - U+3eff */
 136.547 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f00 - U+3f1f */
 136.548 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f20 - U+3f3f */
 136.549 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f40 - U+3f5f */
 136.550 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f60 - U+3f7f */
 136.551 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f80 - U+3f9f */
 136.552 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3fa0 - U+3fbf */
 136.553 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3fc0 - U+3fdf */
 136.554 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3fe0 - U+3fff */
 136.555 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4000 - U+401f */
 136.556 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4020 - U+403f */
 136.557 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4040 - U+405f */
 136.558 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4060 - U+407f */
 136.559 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4080 - U+409f */
 136.560 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+40a0 - U+40bf */
 136.561 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+40c0 - U+40df */
 136.562 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+40e0 - U+40ff */
 136.563 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4100 - U+411f */
 136.564 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4120 - U+413f */
 136.565 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4140 - U+415f */
 136.566 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4160 - U+417f */
 136.567 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4180 - U+419f */
 136.568 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+41a0 - U+41bf */
 136.569 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+41c0 - U+41df */
 136.570 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+41e0 - U+41ff */
 136.571 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4200 - U+421f */
 136.572 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4220 - U+423f */
 136.573 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4240 - U+425f */
 136.574 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4260 - U+427f */
 136.575 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4280 - U+429f */
 136.576 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+42a0 - U+42bf */
 136.577 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+42c0 - U+42df */
 136.578 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+42e0 - U+42ff */
 136.579 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4300 - U+431f */
 136.580 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4320 - U+433f */
 136.581 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4340 - U+435f */
 136.582 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4360 - U+437f */
 136.583 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4380 - U+439f */
 136.584 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+43a0 - U+43bf */
 136.585 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+43c0 - U+43df */
 136.586 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+43e0 - U+43ff */
 136.587 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4400 - U+441f */
 136.588 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4420 - U+443f */
 136.589 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4440 - U+445f */
 136.590 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4460 - U+447f */
 136.591 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4480 - U+449f */
 136.592 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+44a0 - U+44bf */
 136.593 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+44c0 - U+44df */
 136.594 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+44e0 - U+44ff */
 136.595 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4500 - U+451f */
 136.596 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4520 - U+453f */
 136.597 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4540 - U+455f */
 136.598 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4560 - U+457f */
 136.599 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4580 - U+459f */
 136.600 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+45a0 - U+45bf */
 136.601 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+45c0 - U+45df */
 136.602 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+45e0 - U+45ff */
 136.603 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4600 - U+461f */
 136.604 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4620 - U+463f */
 136.605 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4640 - U+465f */
 136.606 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4660 - U+467f */
 136.607 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4680 - U+469f */
 136.608 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+46a0 - U+46bf */
 136.609 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+46c0 - U+46df */
 136.610 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+46e0 - U+46ff */
 136.611 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4700 - U+471f */
 136.612 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4720 - U+473f */
 136.613 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4740 - U+475f */
 136.614 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4760 - U+477f */
 136.615 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4780 - U+479f */
 136.616 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+47a0 - U+47bf */
 136.617 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+47c0 - U+47df */
 136.618 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+47e0 - U+47ff */
 136.619 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4800 - U+481f */
 136.620 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4820 - U+483f */
 136.621 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4840 - U+485f */
 136.622 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4860 - U+487f */
 136.623 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4880 - U+489f */
 136.624 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+48a0 - U+48bf */
 136.625 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+48c0 - U+48df */
 136.626 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+48e0 - U+48ff */
 136.627 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4900 - U+491f */
 136.628 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4920 - U+493f */
 136.629 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4940 - U+495f */
 136.630 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4960 - U+497f */
 136.631 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4980 - U+499f */
 136.632 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+49a0 - U+49bf */
 136.633 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+49c0 - U+49df */
 136.634 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+49e0 - U+49ff */
 136.635 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a00 - U+4a1f */
 136.636 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a20 - U+4a3f */
 136.637 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a40 - U+4a5f */
 136.638 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a60 - U+4a7f */
 136.639 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a80 - U+4a9f */
 136.640 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4aa0 - U+4abf */
 136.641 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ac0 - U+4adf */
 136.642 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ae0 - U+4aff */
 136.643 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b00 - U+4b1f */
 136.644 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b20 - U+4b3f */
 136.645 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b40 - U+4b5f */
 136.646 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b60 - U+4b7f */
 136.647 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b80 - U+4b9f */
 136.648 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ba0 - U+4bbf */
 136.649 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4bc0 - U+4bdf */
 136.650 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4be0 - U+4bff */
 136.651 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c00 - U+4c1f */
 136.652 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c20 - U+4c3f */
 136.653 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c40 - U+4c5f */
 136.654 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c60 - U+4c7f */
 136.655 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c80 - U+4c9f */
 136.656 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ca0 - U+4cbf */
 136.657 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4cc0 - U+4cdf */
 136.658 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ce0 - U+4cff */
 136.659 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d00 - U+4d1f */
 136.660 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d20 - U+4d3f */
 136.661 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d40 - U+4d5f */
 136.662 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d60 - U+4d7f */
 136.663 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d80 - U+4d9f */
 136.664 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,0xff,	/* U+4da0 - U+4dbf */
 136.665 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+4dc0 - U+4ddf */
 136.666 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+4de0 - U+4dff */
 136.667 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e00 - U+4e1f */
 136.668 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e20 - U+4e3f */
 136.669 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e40 - U+4e5f */
 136.670 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e60 - U+4e7f */
 136.671 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e80 - U+4e9f */
 136.672 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ea0 - U+4ebf */
 136.673 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ec0 - U+4edf */
 136.674 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ee0 - U+4eff */
 136.675 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f00 - U+4f1f */
 136.676 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f20 - U+4f3f */
 136.677 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f40 - U+4f5f */
 136.678 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f60 - U+4f7f */
 136.679 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f80 - U+4f9f */
 136.680 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4fa0 - U+4fbf */
 136.681 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4fc0 - U+4fdf */
 136.682 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4fe0 - U+4fff */
 136.683 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5000 - U+501f */
 136.684 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5020 - U+503f */
 136.685 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5040 - U+505f */
 136.686 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5060 - U+507f */
 136.687 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5080 - U+509f */
 136.688 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+50a0 - U+50bf */
 136.689 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+50c0 - U+50df */
 136.690 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+50e0 - U+50ff */
 136.691 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5100 - U+511f */
 136.692 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5120 - U+513f */
 136.693 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5140 - U+515f */
 136.694 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5160 - U+517f */
 136.695 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5180 - U+519f */
 136.696 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+51a0 - U+51bf */
 136.697 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+51c0 - U+51df */
 136.698 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+51e0 - U+51ff */
 136.699 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5200 - U+521f */
 136.700 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5220 - U+523f */
 136.701 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5240 - U+525f */
 136.702 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5260 - U+527f */
 136.703 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5280 - U+529f */
 136.704 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+52a0 - U+52bf */
 136.705 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+52c0 - U+52df */
 136.706 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+52e0 - U+52ff */
 136.707 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5300 - U+531f */
 136.708 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5320 - U+533f */
 136.709 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5340 - U+535f */
 136.710 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5360 - U+537f */
 136.711 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5380 - U+539f */
 136.712 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+53a0 - U+53bf */
 136.713 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+53c0 - U+53df */
 136.714 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+53e0 - U+53ff */
 136.715 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5400 - U+541f */
 136.716 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5420 - U+543f */
 136.717 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5440 - U+545f */
 136.718 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5460 - U+547f */
 136.719 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5480 - U+549f */
 136.720 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+54a0 - U+54bf */
 136.721 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+54c0 - U+54df */
 136.722 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+54e0 - U+54ff */
 136.723 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5500 - U+551f */
 136.724 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5520 - U+553f */
 136.725 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5540 - U+555f */
 136.726 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5560 - U+557f */
 136.727 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5580 - U+559f */
 136.728 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+55a0 - U+55bf */
 136.729 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+55c0 - U+55df */
 136.730 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+55e0 - U+55ff */
 136.731 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5600 - U+561f */
 136.732 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5620 - U+563f */
 136.733 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5640 - U+565f */
 136.734 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5660 - U+567f */
 136.735 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5680 - U+569f */
 136.736 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+56a0 - U+56bf */
 136.737 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+56c0 - U+56df */
 136.738 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+56e0 - U+56ff */
 136.739 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5700 - U+571f */
 136.740 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5720 - U+573f */
 136.741 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5740 - U+575f */
 136.742 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5760 - U+577f */
 136.743 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5780 - U+579f */
 136.744 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+57a0 - U+57bf */
 136.745 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+57c0 - U+57df */
 136.746 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+57e0 - U+57ff */
 136.747 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5800 - U+581f */
 136.748 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5820 - U+583f */
 136.749 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5840 - U+585f */
 136.750 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5860 - U+587f */
 136.751 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5880 - U+589f */
 136.752 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+58a0 - U+58bf */
 136.753 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+58c0 - U+58df */
 136.754 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+58e0 - U+58ff */
 136.755 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5900 - U+591f */
 136.756 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5920 - U+593f */
 136.757 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5940 - U+595f */
 136.758 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5960 - U+597f */
 136.759 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5980 - U+599f */
 136.760 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+59a0 - U+59bf */
 136.761 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+59c0 - U+59df */
 136.762 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+59e0 - U+59ff */
 136.763 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a00 - U+5a1f */
 136.764 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a20 - U+5a3f */
 136.765 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a40 - U+5a5f */
 136.766 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a60 - U+5a7f */
 136.767 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a80 - U+5a9f */
 136.768 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5aa0 - U+5abf */
 136.769 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ac0 - U+5adf */
 136.770 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ae0 - U+5aff */
 136.771 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b00 - U+5b1f */
 136.772 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b20 - U+5b3f */
 136.773 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b40 - U+5b5f */
 136.774 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b60 - U+5b7f */
 136.775 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b80 - U+5b9f */
 136.776 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ba0 - U+5bbf */
 136.777 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5bc0 - U+5bdf */
 136.778 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5be0 - U+5bff */
 136.779 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c00 - U+5c1f */
 136.780 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c20 - U+5c3f */
 136.781 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c40 - U+5c5f */
 136.782 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c60 - U+5c7f */
 136.783 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c80 - U+5c9f */
 136.784 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ca0 - U+5cbf */
 136.785 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5cc0 - U+5cdf */
 136.786 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ce0 - U+5cff */
 136.787 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d00 - U+5d1f */
 136.788 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d20 - U+5d3f */
 136.789 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d40 - U+5d5f */
 136.790 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d60 - U+5d7f */
 136.791 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d80 - U+5d9f */
 136.792 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5da0 - U+5dbf */
 136.793 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5dc0 - U+5ddf */
 136.794 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5de0 - U+5dff */
 136.795 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e00 - U+5e1f */
 136.796 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e20 - U+5e3f */
 136.797 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e40 - U+5e5f */
 136.798 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e60 - U+5e7f */
 136.799 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e80 - U+5e9f */
 136.800 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ea0 - U+5ebf */
 136.801 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ec0 - U+5edf */
 136.802 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ee0 - U+5eff */
 136.803 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f00 - U+5f1f */
 136.804 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f20 - U+5f3f */
 136.805 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f40 - U+5f5f */
 136.806 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f60 - U+5f7f */
 136.807 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f80 - U+5f9f */
 136.808 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5fa0 - U+5fbf */
 136.809 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5fc0 - U+5fdf */
 136.810 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5fe0 - U+5fff */
 136.811 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6000 - U+601f */
 136.812 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6020 - U+603f */
 136.813 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6040 - U+605f */
 136.814 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6060 - U+607f */
 136.815 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6080 - U+609f */
 136.816 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+60a0 - U+60bf */
 136.817 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+60c0 - U+60df */
 136.818 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+60e0 - U+60ff */
 136.819 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6100 - U+611f */
 136.820 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6120 - U+613f */
 136.821 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6140 - U+615f */
 136.822 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6160 - U+617f */
 136.823 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6180 - U+619f */
 136.824 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+61a0 - U+61bf */
 136.825 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+61c0 - U+61df */
 136.826 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+61e0 - U+61ff */
 136.827 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6200 - U+621f */
 136.828 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6220 - U+623f */
 136.829 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6240 - U+625f */
 136.830 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6260 - U+627f */
 136.831 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6280 - U+629f */
 136.832 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+62a0 - U+62bf */
 136.833 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+62c0 - U+62df */
 136.834 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+62e0 - U+62ff */
 136.835 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6300 - U+631f */
 136.836 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6320 - U+633f */
 136.837 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6340 - U+635f */
 136.838 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6360 - U+637f */
 136.839 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6380 - U+639f */
 136.840 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+63a0 - U+63bf */
 136.841 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+63c0 - U+63df */
 136.842 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+63e0 - U+63ff */
 136.843 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6400 - U+641f */
 136.844 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6420 - U+643f */
 136.845 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6440 - U+645f */
 136.846 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6460 - U+647f */
 136.847 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6480 - U+649f */
 136.848 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+64a0 - U+64bf */
 136.849 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+64c0 - U+64df */
 136.850 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+64e0 - U+64ff */
 136.851 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6500 - U+651f */
 136.852 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6520 - U+653f */
 136.853 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6540 - U+655f */
 136.854 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6560 - U+657f */
 136.855 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6580 - U+659f */
 136.856 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+65a0 - U+65bf */
 136.857 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+65c0 - U+65df */
 136.858 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+65e0 - U+65ff */
 136.859 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6600 - U+661f */
 136.860 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6620 - U+663f */
 136.861 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6640 - U+665f */
 136.862 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6660 - U+667f */
 136.863 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6680 - U+669f */
 136.864 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+66a0 - U+66bf */
 136.865 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+66c0 - U+66df */
 136.866 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+66e0 - U+66ff */
 136.867 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6700 - U+671f */
 136.868 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6720 - U+673f */
 136.869 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6740 - U+675f */
 136.870 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6760 - U+677f */
 136.871 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6780 - U+679f */
 136.872 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+67a0 - U+67bf */
 136.873 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+67c0 - U+67df */
 136.874 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+67e0 - U+67ff */
 136.875 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6800 - U+681f */
 136.876 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6820 - U+683f */
 136.877 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6840 - U+685f */
 136.878 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6860 - U+687f */
 136.879 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6880 - U+689f */
 136.880 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+68a0 - U+68bf */
 136.881 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+68c0 - U+68df */
 136.882 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+68e0 - U+68ff */
 136.883 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6900 - U+691f */
 136.884 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6920 - U+693f */
 136.885 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6940 - U+695f */
 136.886 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6960 - U+697f */
 136.887 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6980 - U+699f */
 136.888 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+69a0 - U+69bf */
 136.889 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+69c0 - U+69df */
 136.890 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+69e0 - U+69ff */
 136.891 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a00 - U+6a1f */
 136.892 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a20 - U+6a3f */
 136.893 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a40 - U+6a5f */
 136.894 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a60 - U+6a7f */
 136.895 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a80 - U+6a9f */
 136.896 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6aa0 - U+6abf */
 136.897 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ac0 - U+6adf */
 136.898 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ae0 - U+6aff */
 136.899 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b00 - U+6b1f */
 136.900 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b20 - U+6b3f */
 136.901 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b40 - U+6b5f */
 136.902 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b60 - U+6b7f */
 136.903 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b80 - U+6b9f */
 136.904 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ba0 - U+6bbf */
 136.905 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6bc0 - U+6bdf */
 136.906 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6be0 - U+6bff */
 136.907 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c00 - U+6c1f */
 136.908 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c20 - U+6c3f */
 136.909 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c40 - U+6c5f */
 136.910 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c60 - U+6c7f */
 136.911 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c80 - U+6c9f */
 136.912 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ca0 - U+6cbf */
 136.913 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6cc0 - U+6cdf */
 136.914 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ce0 - U+6cff */
 136.915 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d00 - U+6d1f */
 136.916 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d20 - U+6d3f */
 136.917 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d40 - U+6d5f */
 136.918 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d60 - U+6d7f */
 136.919 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d80 - U+6d9f */
 136.920 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6da0 - U+6dbf */
 136.921 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6dc0 - U+6ddf */
 136.922 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6de0 - U+6dff */
 136.923 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e00 - U+6e1f */
 136.924 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e20 - U+6e3f */
 136.925 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e40 - U+6e5f */
 136.926 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e60 - U+6e7f */
 136.927 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e80 - U+6e9f */
 136.928 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ea0 - U+6ebf */
 136.929 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ec0 - U+6edf */
 136.930 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ee0 - U+6eff */
 136.931 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f00 - U+6f1f */
 136.932 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f20 - U+6f3f */
 136.933 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f40 - U+6f5f */
 136.934 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f60 - U+6f7f */
 136.935 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f80 - U+6f9f */
 136.936 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6fa0 - U+6fbf */
 136.937 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6fc0 - U+6fdf */
 136.938 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6fe0 - U+6fff */
 136.939 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7000 - U+701f */
 136.940 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7020 - U+703f */
 136.941 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7040 - U+705f */
 136.942 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7060 - U+707f */
 136.943 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7080 - U+709f */
 136.944 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+70a0 - U+70bf */
 136.945 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+70c0 - U+70df */
 136.946 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+70e0 - U+70ff */
 136.947 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7100 - U+711f */
 136.948 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7120 - U+713f */
 136.949 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7140 - U+715f */
 136.950 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7160 - U+717f */
 136.951 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7180 - U+719f */
 136.952 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+71a0 - U+71bf */
 136.953 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+71c0 - U+71df */
 136.954 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+71e0 - U+71ff */
 136.955 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7200 - U+721f */
 136.956 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7220 - U+723f */
 136.957 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7240 - U+725f */
 136.958 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7260 - U+727f */
 136.959 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7280 - U+729f */
 136.960 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+72a0 - U+72bf */
 136.961 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+72c0 - U+72df */
 136.962 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+72e0 - U+72ff */
 136.963 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7300 - U+731f */
 136.964 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7320 - U+733f */
 136.965 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7340 - U+735f */
 136.966 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7360 - U+737f */
 136.967 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7380 - U+739f */
 136.968 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+73a0 - U+73bf */
 136.969 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+73c0 - U+73df */
 136.970 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+73e0 - U+73ff */
 136.971 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7400 - U+741f */
 136.972 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7420 - U+743f */
 136.973 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7440 - U+745f */
 136.974 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7460 - U+747f */
 136.975 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7480 - U+749f */
 136.976 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+74a0 - U+74bf */
 136.977 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+74c0 - U+74df */
 136.978 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+74e0 - U+74ff */
 136.979 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7500 - U+751f */
 136.980 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7520 - U+753f */
 136.981 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7540 - U+755f */
 136.982 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7560 - U+757f */
 136.983 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7580 - U+759f */
 136.984 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+75a0 - U+75bf */
 136.985 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+75c0 - U+75df */
 136.986 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+75e0 - U+75ff */
 136.987 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7600 - U+761f */
 136.988 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7620 - U+763f */
 136.989 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7640 - U+765f */
 136.990 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7660 - U+767f */
 136.991 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7680 - U+769f */
 136.992 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+76a0 - U+76bf */
 136.993 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+76c0 - U+76df */
 136.994 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+76e0 - U+76ff */
 136.995 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7700 - U+771f */
 136.996 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7720 - U+773f */
 136.997 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7740 - U+775f */
 136.998 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7760 - U+777f */
 136.999 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7780 - U+779f */
136.1000 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+77a0 - U+77bf */
136.1001 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+77c0 - U+77df */
136.1002 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+77e0 - U+77ff */
136.1003 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7800 - U+781f */
136.1004 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7820 - U+783f */
136.1005 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7840 - U+785f */
136.1006 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7860 - U+787f */
136.1007 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7880 - U+789f */
136.1008 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+78a0 - U+78bf */
136.1009 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+78c0 - U+78df */
136.1010 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+78e0 - U+78ff */
136.1011 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7900 - U+791f */
136.1012 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7920 - U+793f */
136.1013 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7940 - U+795f */
136.1014 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7960 - U+797f */
136.1015 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7980 - U+799f */
136.1016 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+79a0 - U+79bf */
136.1017 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+79c0 - U+79df */
136.1018 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+79e0 - U+79ff */
136.1019 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a00 - U+7a1f */
136.1020 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a20 - U+7a3f */
136.1021 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a40 - U+7a5f */
136.1022 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a60 - U+7a7f */
136.1023 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a80 - U+7a9f */
136.1024 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7aa0 - U+7abf */
136.1025 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ac0 - U+7adf */
136.1026 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ae0 - U+7aff */
136.1027 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b00 - U+7b1f */
136.1028 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b20 - U+7b3f */
136.1029 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b40 - U+7b5f */
136.1030 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b60 - U+7b7f */
136.1031 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b80 - U+7b9f */
136.1032 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ba0 - U+7bbf */
136.1033 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7bc0 - U+7bdf */
136.1034 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7be0 - U+7bff */
136.1035 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c00 - U+7c1f */
136.1036 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c20 - U+7c3f */
136.1037 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c40 - U+7c5f */
136.1038 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c60 - U+7c7f */
136.1039 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c80 - U+7c9f */
136.1040 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ca0 - U+7cbf */
136.1041 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7cc0 - U+7cdf */
136.1042 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ce0 - U+7cff */
136.1043 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d00 - U+7d1f */
136.1044 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d20 - U+7d3f */
136.1045 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d40 - U+7d5f */
136.1046 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d60 - U+7d7f */
136.1047 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d80 - U+7d9f */
136.1048 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7da0 - U+7dbf */
136.1049 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7dc0 - U+7ddf */
136.1050 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7de0 - U+7dff */
136.1051 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e00 - U+7e1f */
136.1052 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e20 - U+7e3f */
136.1053 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e40 - U+7e5f */
136.1054 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e60 - U+7e7f */
136.1055 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e80 - U+7e9f */
136.1056 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ea0 - U+7ebf */
136.1057 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ec0 - U+7edf */
136.1058 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ee0 - U+7eff */
136.1059 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f00 - U+7f1f */
136.1060 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f20 - U+7f3f */
136.1061 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f40 - U+7f5f */
136.1062 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f60 - U+7f7f */
136.1063 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f80 - U+7f9f */
136.1064 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7fa0 - U+7fbf */
136.1065 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7fc0 - U+7fdf */
136.1066 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7fe0 - U+7fff */
136.1067 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8000 - U+801f */
136.1068 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8020 - U+803f */
136.1069 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8040 - U+805f */
136.1070 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8060 - U+807f */
136.1071 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8080 - U+809f */
136.1072 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+80a0 - U+80bf */
136.1073 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+80c0 - U+80df */
136.1074 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+80e0 - U+80ff */
136.1075 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8100 - U+811f */
136.1076 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8120 - U+813f */
136.1077 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8140 - U+815f */
136.1078 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8160 - U+817f */
136.1079 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8180 - U+819f */
136.1080 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+81a0 - U+81bf */
136.1081 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+81c0 - U+81df */
136.1082 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+81e0 - U+81ff */
136.1083 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8200 - U+821f */
136.1084 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8220 - U+823f */
136.1085 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8240 - U+825f */
136.1086 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8260 - U+827f */
136.1087 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8280 - U+829f */
136.1088 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+82a0 - U+82bf */
136.1089 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+82c0 - U+82df */
136.1090 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+82e0 - U+82ff */
136.1091 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8300 - U+831f */
136.1092 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8320 - U+833f */
136.1093 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8340 - U+835f */
136.1094 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8360 - U+837f */
136.1095 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8380 - U+839f */
136.1096 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+83a0 - U+83bf */
136.1097 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+83c0 - U+83df */
136.1098 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+83e0 - U+83ff */
136.1099 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8400 - U+841f */
136.1100 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8420 - U+843f */
136.1101 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8440 - U+845f */
136.1102 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8460 - U+847f */
136.1103 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8480 - U+849f */
136.1104 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+84a0 - U+84bf */
136.1105 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+84c0 - U+84df */
136.1106 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+84e0 - U+84ff */
136.1107 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8500 - U+851f */
136.1108 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8520 - U+853f */
136.1109 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8540 - U+855f */
136.1110 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8560 - U+857f */
136.1111 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8580 - U+859f */
136.1112 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+85a0 - U+85bf */
136.1113 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+85c0 - U+85df */
136.1114 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+85e0 - U+85ff */
136.1115 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8600 - U+861f */
136.1116 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8620 - U+863f */
136.1117 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8640 - U+865f */
136.1118 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8660 - U+867f */
136.1119 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8680 - U+869f */
136.1120 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+86a0 - U+86bf */
136.1121 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+86c0 - U+86df */
136.1122 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+86e0 - U+86ff */
136.1123 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8700 - U+871f */
136.1124 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8720 - U+873f */
136.1125 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8740 - U+875f */
136.1126 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8760 - U+877f */
136.1127 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8780 - U+879f */
136.1128 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+87a0 - U+87bf */
136.1129 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+87c0 - U+87df */
136.1130 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+87e0 - U+87ff */
136.1131 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8800 - U+881f */
136.1132 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8820 - U+883f */
136.1133 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8840 - U+885f */
136.1134 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8860 - U+887f */
136.1135 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8880 - U+889f */
136.1136 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+88a0 - U+88bf */
136.1137 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+88c0 - U+88df */
136.1138 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+88e0 - U+88ff */
136.1139 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8900 - U+891f */
136.1140 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8920 - U+893f */
136.1141 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8940 - U+895f */
136.1142 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8960 - U+897f */
136.1143 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8980 - U+899f */
136.1144 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+89a0 - U+89bf */
136.1145 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+89c0 - U+89df */
136.1146 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+89e0 - U+89ff */
136.1147 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a00 - U+8a1f */
136.1148 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a20 - U+8a3f */
136.1149 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a40 - U+8a5f */
136.1150 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a60 - U+8a7f */
136.1151 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a80 - U+8a9f */
136.1152 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8aa0 - U+8abf */
136.1153 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ac0 - U+8adf */
136.1154 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ae0 - U+8aff */
136.1155 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b00 - U+8b1f */
136.1156 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b20 - U+8b3f */
136.1157 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b40 - U+8b5f */
136.1158 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b60 - U+8b7f */
136.1159 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b80 - U+8b9f */
136.1160 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ba0 - U+8bbf */
136.1161 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8bc0 - U+8bdf */
136.1162 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8be0 - U+8bff */
136.1163 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c00 - U+8c1f */
136.1164 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c20 - U+8c3f */
136.1165 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c40 - U+8c5f */
136.1166 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c60 - U+8c7f */
136.1167 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c80 - U+8c9f */
136.1168 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ca0 - U+8cbf */
136.1169 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8cc0 - U+8cdf */
136.1170 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ce0 - U+8cff */
136.1171 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d00 - U+8d1f */
136.1172 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d20 - U+8d3f */
136.1173 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d40 - U+8d5f */
136.1174 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d60 - U+8d7f */
136.1175 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d80 - U+8d9f */
136.1176 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8da0 - U+8dbf */
136.1177 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8dc0 - U+8ddf */
136.1178 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8de0 - U+8dff */
136.1179 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e00 - U+8e1f */
136.1180 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e20 - U+8e3f */
136.1181 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e40 - U+8e5f */
136.1182 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e60 - U+8e7f */
136.1183 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e80 - U+8e9f */
136.1184 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ea0 - U+8ebf */
136.1185 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ec0 - U+8edf */
136.1186 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ee0 - U+8eff */
136.1187 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f00 - U+8f1f */
136.1188 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f20 - U+8f3f */
136.1189 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f40 - U+8f5f */
136.1190 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f60 - U+8f7f */
136.1191 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f80 - U+8f9f */
136.1192 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8fa0 - U+8fbf */
136.1193 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8fc0 - U+8fdf */
136.1194 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8fe0 - U+8fff */
136.1195 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9000 - U+901f */
136.1196 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9020 - U+903f */
136.1197 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9040 - U+905f */
136.1198 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9060 - U+907f */
136.1199 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9080 - U+909f */
136.1200 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+90a0 - U+90bf */
136.1201 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+90c0 - U+90df */
136.1202 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+90e0 - U+90ff */
136.1203 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9100 - U+911f */
136.1204 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9120 - U+913f */
136.1205 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9140 - U+915f */
136.1206 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9160 - U+917f */
136.1207 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9180 - U+919f */
136.1208 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+91a0 - U+91bf */
136.1209 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+91c0 - U+91df */
136.1210 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+91e0 - U+91ff */
136.1211 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9200 - U+921f */
136.1212 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9220 - U+923f */
136.1213 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9240 - U+925f */
136.1214 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9260 - U+927f */
136.1215 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9280 - U+929f */
136.1216 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+92a0 - U+92bf */
136.1217 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+92c0 - U+92df */
136.1218 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+92e0 - U+92ff */
136.1219 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9300 - U+931f */
136.1220 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9320 - U+933f */
136.1221 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9340 - U+935f */
136.1222 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9360 - U+937f */
136.1223 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9380 - U+939f */
136.1224 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+93a0 - U+93bf */
136.1225 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+93c0 - U+93df */
136.1226 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+93e0 - U+93ff */
136.1227 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9400 - U+941f */
136.1228 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9420 - U+943f */
136.1229 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9440 - U+945f */
136.1230 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9460 - U+947f */
136.1231 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9480 - U+949f */
136.1232 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+94a0 - U+94bf */
136.1233 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+94c0 - U+94df */
136.1234 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+94e0 - U+94ff */
136.1235 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9500 - U+951f */
136.1236 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9520 - U+953f */
136.1237 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9540 - U+955f */
136.1238 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9560 - U+957f */
136.1239 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9580 - U+959f */
136.1240 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+95a0 - U+95bf */
136.1241 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+95c0 - U+95df */
136.1242 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+95e0 - U+95ff */
136.1243 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9600 - U+961f */
136.1244 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9620 - U+963f */
136.1245 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9640 - U+965f */
136.1246 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9660 - U+967f */
136.1247 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9680 - U+969f */
136.1248 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+96a0 - U+96bf */
136.1249 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+96c0 - U+96df */
136.1250 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+96e0 - U+96ff */
136.1251 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9700 - U+971f */
136.1252 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9720 - U+973f */
136.1253 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9740 - U+975f */
136.1254 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9760 - U+977f */
136.1255 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9780 - U+979f */
136.1256 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+97a0 - U+97bf */
136.1257 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+97c0 - U+97df */
136.1258 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+97e0 - U+97ff */
136.1259 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9800 - U+981f */
136.1260 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9820 - U+983f */
136.1261 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9840 - U+985f */
136.1262 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9860 - U+987f */
136.1263 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9880 - U+989f */
136.1264 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+98a0 - U+98bf */
136.1265 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+98c0 - U+98df */
136.1266 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+98e0 - U+98ff */
136.1267 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9900 - U+991f */
136.1268 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9920 - U+993f */
136.1269 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9940 - U+995f */
136.1270 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9960 - U+997f */
136.1271 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9980 - U+999f */
136.1272 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+99a0 - U+99bf */
136.1273 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+99c0 - U+99df */
136.1274 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+99e0 - U+99ff */
136.1275 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a00 - U+9a1f */
136.1276 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a20 - U+9a3f */
136.1277 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a40 - U+9a5f */
136.1278 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a60 - U+9a7f */
136.1279 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a80 - U+9a9f */
136.1280 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9aa0 - U+9abf */
136.1281 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ac0 - U+9adf */
136.1282 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ae0 - U+9aff */
136.1283 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b00 - U+9b1f */
136.1284 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b20 - U+9b3f */
136.1285 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b40 - U+9b5f */
136.1286 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b60 - U+9b7f */
136.1287 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b80 - U+9b9f */
136.1288 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ba0 - U+9bbf */
136.1289 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9bc0 - U+9bdf */
136.1290 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9be0 - U+9bff */
136.1291 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c00 - U+9c1f */
136.1292 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c20 - U+9c3f */
136.1293 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c40 - U+9c5f */
136.1294 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c60 - U+9c7f */
136.1295 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c80 - U+9c9f */
136.1296 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ca0 - U+9cbf */
136.1297 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9cc0 - U+9cdf */
136.1298 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ce0 - U+9cff */
136.1299 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d00 - U+9d1f */
136.1300 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d20 - U+9d3f */
136.1301 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d40 - U+9d5f */
136.1302 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d60 - U+9d7f */
136.1303 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d80 - U+9d9f */
136.1304 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9da0 - U+9dbf */
136.1305 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9dc0 - U+9ddf */
136.1306 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9de0 - U+9dff */
136.1307 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e00 - U+9e1f */
136.1308 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e20 - U+9e3f */
136.1309 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e40 - U+9e5f */
136.1310 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e60 - U+9e7f */
136.1311 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e80 - U+9e9f */
136.1312 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ea0 - U+9ebf */
136.1313 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ec0 - U+9edf */
136.1314 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ee0 - U+9eff */
136.1315 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f00 - U+9f1f */
136.1316 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f20 - U+9f3f */
136.1317 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f40 - U+9f5f */
136.1318 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f60 - U+9f7f */
136.1319 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f80 - U+9f9f */
136.1320 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xff,	/* U+9fa0 - U+9fbf */
136.1321 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+9fc0 - U+9fdf */
136.1322 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+9fe0 - U+9fff */
136.1323 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a000 - U+a01f */
136.1324 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a020 - U+a03f */
136.1325 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a040 - U+a05f */
136.1326 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a060 - U+a07f */
136.1327 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a080 - U+a09f */
136.1328 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a0a0 - U+a0bf */
136.1329 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a0c0 - U+a0df */
136.1330 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a0e0 - U+a0ff */
136.1331 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a100 - U+a11f */
136.1332 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a120 - U+a13f */
136.1333 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a140 - U+a15f */
136.1334 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a160 - U+a17f */
136.1335 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a180 - U+a19f */
136.1336 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a1a0 - U+a1bf */
136.1337 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a1c0 - U+a1df */
136.1338 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a1e0 - U+a1ff */
136.1339 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a200 - U+a21f */
136.1340 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a220 - U+a23f */
136.1341 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a240 - U+a25f */
136.1342 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a260 - U+a27f */
136.1343 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a280 - U+a29f */
136.1344 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a2a0 - U+a2bf */
136.1345 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a2c0 - U+a2df */
136.1346 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a2e0 - U+a2ff */
136.1347 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a300 - U+a31f */
136.1348 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a320 - U+a33f */
136.1349 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a340 - U+a35f */
136.1350 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a360 - U+a37f */
136.1351 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a380 - U+a39f */
136.1352 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a3a0 - U+a3bf */
136.1353 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a3c0 - U+a3df */
136.1354 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a3e0 - U+a3ff */
136.1355 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a400 - U+a41f */
136.1356 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a420 - U+a43f */
136.1357 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a440 - U+a45f */
136.1358 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a460 - U+a47f */
136.1359 +  0xaa,0xaa,0xaa,0xbf,0xaa,0xaa,0xaa,0xaa,	/* U+a480 - U+a49f */
136.1360 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a4a0 - U+a4bf */
136.1361 +  0xaa,0xab,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a4c0 - U+a4df */
136.1362 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a4e0 - U+a4ff */
136.1363 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a500 - U+a51f */
136.1364 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a520 - U+a53f */
136.1365 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a540 - U+a55f */
136.1366 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a560 - U+a57f */
136.1367 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a580 - U+a59f */
136.1368 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a5a0 - U+a5bf */
136.1369 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a5c0 - U+a5df */
136.1370 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a5e0 - U+a5ff */
136.1371 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a600 - U+a61f */
136.1372 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a620 - U+a63f */
136.1373 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a640 - U+a65f */
136.1374 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a660 - U+a67f */
136.1375 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a680 - U+a69f */
136.1376 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a6a0 - U+a6bf */
136.1377 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a6c0 - U+a6df */
136.1378 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a6e0 - U+a6ff */
136.1379 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a700 - U+a71f */
136.1380 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a720 - U+a73f */
136.1381 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a740 - U+a75f */
136.1382 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a760 - U+a77f */
136.1383 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a780 - U+a79f */
136.1384 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a7a0 - U+a7bf */
136.1385 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a7c0 - U+a7df */
136.1386 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a7e0 - U+a7ff */
136.1387 +  0xf3,0xf3,0xfc,0xff,0xff,0xff,0xff,0xff,	/* U+a800 - U+a81f */
136.1388 +  0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a820 - U+a83f */
136.1389 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a840 - U+a85f */
136.1390 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a860 - U+a87f */
136.1391 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a880 - U+a89f */
136.1392 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a8a0 - U+a8bf */
136.1393 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a8c0 - U+a8df */
136.1394 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a8e0 - U+a8ff */
136.1395 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a900 - U+a91f */
136.1396 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a920 - U+a93f */
136.1397 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a940 - U+a95f */
136.1398 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a960 - U+a97f */
136.1399 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a980 - U+a99f */
136.1400 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a9a0 - U+a9bf */
136.1401 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a9c0 - U+a9df */
136.1402 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a9e0 - U+a9ff */
136.1403 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa00 - U+aa1f */
136.1404 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa20 - U+aa3f */
136.1405 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa40 - U+aa5f */
136.1406 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa60 - U+aa7f */
136.1407 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa80 - U+aa9f */
136.1408 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aaa0 - U+aabf */
136.1409 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aac0 - U+aadf */
136.1410 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aae0 - U+aaff */
136.1411 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab00 - U+ab1f */
136.1412 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab20 - U+ab3f */
136.1413 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab40 - U+ab5f */
136.1414 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab60 - U+ab7f */
136.1415 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab80 - U+ab9f */
136.1416 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aba0 - U+abbf */
136.1417 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+abc0 - U+abdf */
136.1418 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+abe0 - U+abff */
136.1419 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac00 - U+ac1f */
136.1420 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac20 - U+ac3f */
136.1421 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac40 - U+ac5f */
136.1422 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac60 - U+ac7f */
136.1423 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac80 - U+ac9f */
136.1424 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aca0 - U+acbf */
136.1425 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+acc0 - U+acdf */
136.1426 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ace0 - U+acff */
136.1427 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad00 - U+ad1f */
136.1428 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad20 - U+ad3f */
136.1429 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad40 - U+ad5f */
136.1430 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad60 - U+ad7f */
136.1431 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad80 - U+ad9f */
136.1432 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ada0 - U+adbf */
136.1433 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+adc0 - U+addf */
136.1434 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ade0 - U+adff */
136.1435 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae00 - U+ae1f */
136.1436 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae20 - U+ae3f */
136.1437 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae40 - U+ae5f */
136.1438 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae60 - U+ae7f */
136.1439 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae80 - U+ae9f */
136.1440 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aea0 - U+aebf */
136.1441 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aec0 - U+aedf */
136.1442 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aee0 - U+aeff */
136.1443 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af00 - U+af1f */
136.1444 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af20 - U+af3f */
136.1445 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af40 - U+af5f */
136.1446 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af60 - U+af7f */
136.1447 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af80 - U+af9f */
136.1448 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+afa0 - U+afbf */
136.1449 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+afc0 - U+afdf */
136.1450 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+afe0 - U+afff */
136.1451 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b000 - U+b01f */
136.1452 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b020 - U+b03f */
136.1453 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b040 - U+b05f */
136.1454 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b060 - U+b07f */
136.1455 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b080 - U+b09f */
136.1456 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b0a0 - U+b0bf */
136.1457 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b0c0 - U+b0df */
136.1458 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b0e0 - U+b0ff */
136.1459 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b100 - U+b11f */
136.1460 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b120 - U+b13f */
136.1461 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b140 - U+b15f */
136.1462 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b160 - U+b17f */
136.1463 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b180 - U+b19f */
136.1464 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b1a0 - U+b1bf */
136.1465 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b1c0 - U+b1df */
136.1466 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b1e0 - U+b1ff */
136.1467 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b200 - U+b21f */
136.1468 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b220 - U+b23f */
136.1469 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b240 - U+b25f */
136.1470 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b260 - U+b27f */
136.1471 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b280 - U+b29f */
136.1472 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b2a0 - U+b2bf */
136.1473 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b2c0 - U+b2df */
136.1474 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b2e0 - U+b2ff */
136.1475 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b300 - U+b31f */
136.1476 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b320 - U+b33f */
136.1477 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b340 - U+b35f */
136.1478 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b360 - U+b37f */
136.1479 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b380 - U+b39f */
136.1480 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b3a0 - U+b3bf */
136.1481 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b3c0 - U+b3df */
136.1482 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b3e0 - U+b3ff */
136.1483 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b400 - U+b41f */
136.1484 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b420 - U+b43f */
136.1485 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b440 - U+b45f */
136.1486 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b460 - U+b47f */
136.1487 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b480 - U+b49f */
136.1488 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b4a0 - U+b4bf */
136.1489 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b4c0 - U+b4df */
136.1490 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b4e0 - U+b4ff */
136.1491 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b500 - U+b51f */
136.1492 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b520 - U+b53f */
136.1493 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b540 - U+b55f */
136.1494 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b560 - U+b57f */
136.1495 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b580 - U+b59f */
136.1496 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b5a0 - U+b5bf */
136.1497 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b5c0 - U+b5df */
136.1498 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b5e0 - U+b5ff */
136.1499 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b600 - U+b61f */
136.1500 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b620 - U+b63f */
136.1501 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b640 - U+b65f */
136.1502 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b660 - U+b67f */
136.1503 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b680 - U+b69f */
136.1504 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b6a0 - U+b6bf */
136.1505 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b6c0 - U+b6df */
136.1506 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b6e0 - U+b6ff */
136.1507 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b700 - U+b71f */
136.1508 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b720 - U+b73f */
136.1509 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b740 - U+b75f */
136.1510 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b760 - U+b77f */
136.1511 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b780 - U+b79f */
136.1512 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b7a0 - U+b7bf */
136.1513 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b7c0 - U+b7df */
136.1514 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b7e0 - U+b7ff */
136.1515 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b800 - U+b81f */
136.1516 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b820 - U+b83f */
136.1517 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b840 - U+b85f */
136.1518 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b860 - U+b87f */
136.1519 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b880 - U+b89f */
136.1520 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b8a0 - U+b8bf */
136.1521 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b8c0 - U+b8df */
136.1522 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b8e0 - U+b8ff */
136.1523 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b900 - U+b91f */
136.1524 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b920 - U+b93f */
136.1525 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b940 - U+b95f */
136.1526 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b960 - U+b97f */
136.1527 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b980 - U+b99f */
136.1528 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b9a0 - U+b9bf */
136.1529 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b9c0 - U+b9df */
136.1530 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b9e0 - U+b9ff */
136.1531 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba00 - U+ba1f */
136.1532 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba20 - U+ba3f */
136.1533 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba40 - U+ba5f */
136.1534 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba60 - U+ba7f */
136.1535 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba80 - U+ba9f */
136.1536 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+baa0 - U+babf */
136.1537 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bac0 - U+badf */
136.1538 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bae0 - U+baff */
136.1539 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb00 - U+bb1f */
136.1540 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb20 - U+bb3f */
136.1541 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb40 - U+bb5f */
136.1542 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb60 - U+bb7f */
136.1543 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb80 - U+bb9f */
136.1544 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bba0 - U+bbbf */
136.1545 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bbc0 - U+bbdf */
136.1546 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bbe0 - U+bbff */
136.1547 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc00 - U+bc1f */
136.1548 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc20 - U+bc3f */
136.1549 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc40 - U+bc5f */
136.1550 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc60 - U+bc7f */
136.1551 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc80 - U+bc9f */
136.1552 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bca0 - U+bcbf */
136.1553 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bcc0 - U+bcdf */
136.1554 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bce0 - U+bcff */
136.1555 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd00 - U+bd1f */
136.1556 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd20 - U+bd3f */
136.1557 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd40 - U+bd5f */
136.1558 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd60 - U+bd7f */
136.1559 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd80 - U+bd9f */
136.1560 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bda0 - U+bdbf */
136.1561 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bdc0 - U+bddf */
136.1562 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bde0 - U+bdff */
136.1563 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be00 - U+be1f */
136.1564 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be20 - U+be3f */
136.1565 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be40 - U+be5f */
136.1566 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be60 - U+be7f */
136.1567 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be80 - U+be9f */
136.1568 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bea0 - U+bebf */
136.1569 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bec0 - U+bedf */
136.1570 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bee0 - U+beff */
136.1571 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf00 - U+bf1f */
136.1572 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf20 - U+bf3f */
136.1573 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf40 - U+bf5f */
136.1574 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf60 - U+bf7f */
136.1575 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf80 - U+bf9f */
136.1576 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bfa0 - U+bfbf */
136.1577 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bfc0 - U+bfdf */
136.1578 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bfe0 - U+bfff */
136.1579 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c000 - U+c01f */
136.1580 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c020 - U+c03f */
136.1581 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c040 - U+c05f */
136.1582 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c060 - U+c07f */
136.1583 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c080 - U+c09f */
136.1584 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c0a0 - U+c0bf */
136.1585 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c0c0 - U+c0df */
136.1586 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c0e0 - U+c0ff */
136.1587 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c100 - U+c11f */
136.1588 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c120 - U+c13f */
136.1589 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c140 - U+c15f */
136.1590 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c160 - U+c17f */
136.1591 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c180 - U+c19f */
136.1592 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c1a0 - U+c1bf */
136.1593 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c1c0 - U+c1df */
136.1594 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c1e0 - U+c1ff */
136.1595 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c200 - U+c21f */
136.1596 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c220 - U+c23f */
136.1597 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c240 - U+c25f */
136.1598 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c260 - U+c27f */
136.1599 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c280 - U+c29f */
136.1600 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c2a0 - U+c2bf */
136.1601 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c2c0 - U+c2df */
136.1602 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c2e0 - U+c2ff */
136.1603 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c300 - U+c31f */
136.1604 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c320 - U+c33f */
136.1605 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c340 - U+c35f */
136.1606 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c360 - U+c37f */
136.1607 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c380 - U+c39f */
136.1608 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c3a0 - U+c3bf */
136.1609 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c3c0 - U+c3df */
136.1610 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c3e0 - U+c3ff */
136.1611 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c400 - U+c41f */
136.1612 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c420 - U+c43f */
136.1613 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c440 - U+c45f */
136.1614 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c460 - U+c47f */
136.1615 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c480 - U+c49f */
136.1616 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c4a0 - U+c4bf */
136.1617 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c4c0 - U+c4df */
136.1618 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c4e0 - U+c4ff */
136.1619 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c500 - U+c51f */
136.1620 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c520 - U+c53f */
136.1621 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c540 - U+c55f */
136.1622 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c560 - U+c57f */
136.1623 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c580 - U+c59f */
136.1624 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c5a0 - U+c5bf */
136.1625 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c5c0 - U+c5df */
136.1626 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c5e0 - U+c5ff */
136.1627 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c600 - U+c61f */
136.1628 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c620 - U+c63f */
136.1629 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c640 - U+c65f */
136.1630 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c660 - U+c67f */
136.1631 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c680 - U+c69f */
136.1632 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c6a0 - U+c6bf */
136.1633 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c6c0 - U+c6df */
136.1634 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c6e0 - U+c6ff */
136.1635 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c700 - U+c71f */
136.1636 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c720 - U+c73f */
136.1637 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c740 - U+c75f */
136.1638 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c760 - U+c77f */
136.1639 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c780 - U+c79f */
136.1640 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c7a0 - U+c7bf */
136.1641 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c7c0 - U+c7df */
136.1642 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c7e0 - U+c7ff */
136.1643 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c800 - U+c81f */
136.1644 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c820 - U+c83f */
136.1645 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c840 - U+c85f */
136.1646 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c860 - U+c87f */
136.1647 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c880 - U+c89f */
136.1648 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c8a0 - U+c8bf */
136.1649 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c8c0 - U+c8df */
136.1650 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c8e0 - U+c8ff */
136.1651 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c900 - U+c91f */
136.1652 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c920 - U+c93f */
136.1653 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c940 - U+c95f */
136.1654 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c960 - U+c97f */
136.1655 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c980 - U+c99f */
136.1656 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c9a0 - U+c9bf */
136.1657 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c9c0 - U+c9df */
136.1658 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c9e0 - U+c9ff */
136.1659 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca00 - U+ca1f */
136.1660 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca20 - U+ca3f */
136.1661 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca40 - U+ca5f */
136.1662 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca60 - U+ca7f */
136.1663 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca80 - U+ca9f */
136.1664 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+caa0 - U+cabf */
136.1665 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cac0 - U+cadf */
136.1666 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cae0 - U+caff */
136.1667 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb00 - U+cb1f */
136.1668 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb20 - U+cb3f */
136.1669 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb40 - U+cb5f */
136.1670 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb60 - U+cb7f */
136.1671 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb80 - U+cb9f */
136.1672 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cba0 - U+cbbf */
136.1673 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cbc0 - U+cbdf */
136.1674 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cbe0 - U+cbff */
136.1675 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc00 - U+cc1f */
136.1676 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc20 - U+cc3f */
136.1677 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc40 - U+cc5f */
136.1678 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc60 - U+cc7f */
136.1679 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc80 - U+cc9f */
136.1680 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cca0 - U+ccbf */
136.1681 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ccc0 - U+ccdf */
136.1682 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cce0 - U+ccff */
136.1683 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd00 - U+cd1f */
136.1684 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd20 - U+cd3f */
136.1685 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd40 - U+cd5f */
136.1686 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd60 - U+cd7f */
136.1687 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd80 - U+cd9f */
136.1688 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cda0 - U+cdbf */
136.1689 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cdc0 - U+cddf */
136.1690 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cde0 - U+cdff */
136.1691 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce00 - U+ce1f */
136.1692 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce20 - U+ce3f */
136.1693 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce40 - U+ce5f */
136.1694 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce60 - U+ce7f */
136.1695 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce80 - U+ce9f */
136.1696 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cea0 - U+cebf */
136.1697 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cec0 - U+cedf */
136.1698 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cee0 - U+ceff */
136.1699 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf00 - U+cf1f */
136.1700 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf20 - U+cf3f */
136.1701 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf40 - U+cf5f */
136.1702 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf60 - U+cf7f */
136.1703 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf80 - U+cf9f */
136.1704 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cfa0 - U+cfbf */
136.1705 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cfc0 - U+cfdf */
136.1706 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cfe0 - U+cfff */
136.1707 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d000 - U+d01f */
136.1708 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d020 - U+d03f */
136.1709 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d040 - U+d05f */
136.1710 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d060 - U+d07f */
136.1711 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d080 - U+d09f */
136.1712 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d0a0 - U+d0bf */
136.1713 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d0c0 - U+d0df */
136.1714 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d0e0 - U+d0ff */
136.1715 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d100 - U+d11f */
136.1716 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d120 - U+d13f */
136.1717 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d140 - U+d15f */
136.1718 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d160 - U+d17f */
136.1719 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d180 - U+d19f */
136.1720 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d1a0 - U+d1bf */
136.1721 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d1c0 - U+d1df */
136.1722 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d1e0 - U+d1ff */
136.1723 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d200 - U+d21f */
136.1724 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d220 - U+d23f */
136.1725 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d240 - U+d25f */
136.1726 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d260 - U+d27f */
136.1727 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d280 - U+d29f */
136.1728 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d2a0 - U+d2bf */
136.1729 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d2c0 - U+d2df */
136.1730 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d2e0 - U+d2ff */
136.1731 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d300 - U+d31f */
136.1732 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d320 - U+d33f */
136.1733 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d340 - U+d35f */
136.1734 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d360 - U+d37f */
136.1735 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d380 - U+d39f */
136.1736 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d3a0 - U+d3bf */
136.1737 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d3c0 - U+d3df */
136.1738 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d3e0 - U+d3ff */
136.1739 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d400 - U+d41f */
136.1740 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d420 - U+d43f */
136.1741 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d440 - U+d45f */
136.1742 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d460 - U+d47f */
136.1743 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d480 - U+d49f */
136.1744 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d4a0 - U+d4bf */
136.1745 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d4c0 - U+d4df */
136.1746 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d4e0 - U+d4ff */
136.1747 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d500 - U+d51f */
136.1748 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d520 - U+d53f */
136.1749 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d540 - U+d55f */
136.1750 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d560 - U+d57f */
136.1751 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d580 - U+d59f */
136.1752 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d5a0 - U+d5bf */
136.1753 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d5c0 - U+d5df */
136.1754 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d5e0 - U+d5ff */
136.1755 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d600 - U+d61f */
136.1756 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d620 - U+d63f */
136.1757 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d640 - U+d65f */
136.1758 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d660 - U+d67f */
136.1759 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d680 - U+d69f */
136.1760 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d6a0 - U+d6bf */
136.1761 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d6c0 - U+d6df */
136.1762 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d6e0 - U+d6ff */
136.1763 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d700 - U+d71f */
136.1764 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d720 - U+d73f */
136.1765 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d740 - U+d75f */
136.1766 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d760 - U+d77f */
136.1767 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d780 - U+d79f */
136.1768 +  0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d7a0 - U+d7bf */
136.1769 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d7c0 - U+d7df */
136.1770 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d7e0 - U+d7ff */
136.1771 +  0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d800 - U+d81f */
136.1772 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d820 - U+d83f */
136.1773 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d840 - U+d85f */
136.1774 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d860 - U+d87f */
136.1775 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d880 - U+d89f */
136.1776 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d8a0 - U+d8bf */
136.1777 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d8c0 - U+d8df */
136.1778 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d8e0 - U+d8ff */
136.1779 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d900 - U+d91f */
136.1780 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d920 - U+d93f */
136.1781 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d940 - U+d95f */
136.1782 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d960 - U+d97f */
136.1783 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d980 - U+d99f */
136.1784 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d9a0 - U+d9bf */
136.1785 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d9c0 - U+d9df */
136.1786 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d9e0 - U+d9ff */
136.1787 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da00 - U+da1f */
136.1788 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da20 - U+da3f */
136.1789 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da40 - U+da5f */
136.1790 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da60 - U+da7f */
136.1791 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da80 - U+da9f */
136.1792 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+daa0 - U+dabf */
136.1793 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dac0 - U+dadf */
136.1794 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dae0 - U+daff */
136.1795 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db00 - U+db1f */
136.1796 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db20 - U+db3f */
136.1797 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db40 - U+db5f */
136.1798 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+db60 - U+db7f */
136.1799 +  0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db80 - U+db9f */
136.1800 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dba0 - U+dbbf */
136.1801 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dbc0 - U+dbdf */
136.1802 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+dbe0 - U+dbff */
136.1803 +  0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc00 - U+dc1f */
136.1804 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc20 - U+dc3f */
136.1805 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc40 - U+dc5f */
136.1806 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc60 - U+dc7f */
136.1807 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc80 - U+dc9f */
136.1808 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dca0 - U+dcbf */
136.1809 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dcc0 - U+dcdf */
136.1810 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dce0 - U+dcff */
136.1811 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd00 - U+dd1f */
136.1812 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd20 - U+dd3f */
136.1813 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd40 - U+dd5f */
136.1814 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd60 - U+dd7f */
136.1815 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd80 - U+dd9f */
136.1816 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dda0 - U+ddbf */
136.1817 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ddc0 - U+dddf */
136.1818 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dde0 - U+ddff */
136.1819 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de00 - U+de1f */
136.1820 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de20 - U+de3f */
136.1821 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de40 - U+de5f */
136.1822 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de60 - U+de7f */
136.1823 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de80 - U+de9f */
136.1824 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dea0 - U+debf */
136.1825 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dec0 - U+dedf */
136.1826 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dee0 - U+deff */
136.1827 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df00 - U+df1f */
136.1828 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df20 - U+df3f */
136.1829 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df40 - U+df5f */
136.1830 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df60 - U+df7f */
136.1831 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df80 - U+df9f */
136.1832 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dfa0 - U+dfbf */
136.1833 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dfc0 - U+dfdf */
136.1834 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+dfe0 - U+dfff */
136.1835 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e000 - U+e01f */
136.1836 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e020 - U+e03f */
136.1837 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e040 - U+e05f */
136.1838 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e060 - U+e07f */
136.1839 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e080 - U+e09f */
136.1840 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e0a0 - U+e0bf */
136.1841 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e0c0 - U+e0df */
136.1842 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e0e0 - U+e0ff */
136.1843 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e100 - U+e11f */
136.1844 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e120 - U+e13f */
136.1845 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e140 - U+e15f */
136.1846 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e160 - U+e17f */
136.1847 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e180 - U+e19f */
136.1848 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e1a0 - U+e1bf */
136.1849 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e1c0 - U+e1df */
136.1850 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e1e0 - U+e1ff */
136.1851 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e200 - U+e21f */
136.1852 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e220 - U+e23f */
136.1853 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e240 - U+e25f */
136.1854 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e260 - U+e27f */
136.1855 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e280 - U+e29f */
136.1856 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e2a0 - U+e2bf */
136.1857 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e2c0 - U+e2df */
136.1858 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e2e0 - U+e2ff */
136.1859 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e300 - U+e31f */
136.1860 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e320 - U+e33f */
136.1861 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e340 - U+e35f */
136.1862 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e360 - U+e37f */
136.1863 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e380 - U+e39f */
136.1864 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e3a0 - U+e3bf */
136.1865 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e3c0 - U+e3df */
136.1866 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e3e0 - U+e3ff */
136.1867 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e400 - U+e41f */
136.1868 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e420 - U+e43f */
136.1869 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e440 - U+e45f */
136.1870 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e460 - U+e47f */
136.1871 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e480 - U+e49f */
136.1872 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e4a0 - U+e4bf */
136.1873 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e4c0 - U+e4df */
136.1874 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e4e0 - U+e4ff */
136.1875 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e500 - U+e51f */
136.1876 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e520 - U+e53f */
136.1877 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e540 - U+e55f */
136.1878 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e560 - U+e57f */
136.1879 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e580 - U+e59f */
136.1880 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e5a0 - U+e5bf */
136.1881 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e5c0 - U+e5df */
136.1882 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e5e0 - U+e5ff */
136.1883 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e600 - U+e61f */
136.1884 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e620 - U+e63f */
136.1885 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e640 - U+e65f */
136.1886 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e660 - U+e67f */
136.1887 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e680 - U+e69f */
136.1888 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e6a0 - U+e6bf */
136.1889 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e6c0 - U+e6df */
136.1890 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e6e0 - U+e6ff */
136.1891 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e700 - U+e71f */
136.1892 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e720 - U+e73f */
136.1893 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e740 - U+e75f */
136.1894 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e760 - U+e77f */
136.1895 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e780 - U+e79f */
136.1896 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e7a0 - U+e7bf */
136.1897 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e7c0 - U+e7df */
136.1898 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e7e0 - U+e7ff */
136.1899 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e800 - U+e81f */
136.1900 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e820 - U+e83f */
136.1901 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e840 - U+e85f */
136.1902 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e860 - U+e87f */
136.1903 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e880 - U+e89f */
136.1904 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e8a0 - U+e8bf */
136.1905 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e8c0 - U+e8df */
136.1906 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e8e0 - U+e8ff */
136.1907 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e900 - U+e91f */
136.1908 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e920 - U+e93f */
136.1909 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e940 - U+e95f */
136.1910 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e960 - U+e97f */
136.1911 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e980 - U+e99f */
136.1912 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e9a0 - U+e9bf */
136.1913 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e9c0 - U+e9df */
136.1914 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e9e0 - U+e9ff */
136.1915 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea00 - U+ea1f */
136.1916 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea20 - U+ea3f */
136.1917 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea40 - U+ea5f */
136.1918 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea60 - U+ea7f */
136.1919 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea80 - U+ea9f */
136.1920 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eaa0 - U+eabf */
136.1921 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eac0 - U+eadf */
136.1922 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eae0 - U+eaff */
136.1923 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb00 - U+eb1f */
136.1924 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb20 - U+eb3f */
136.1925 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb40 - U+eb5f */
136.1926 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb60 - U+eb7f */
136.1927 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb80 - U+eb9f */
136.1928 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eba0 - U+ebbf */
136.1929 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ebc0 - U+ebdf */
136.1930 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ebe0 - U+ebff */
136.1931 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec00 - U+ec1f */
136.1932 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec20 - U+ec3f */
136.1933 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec40 - U+ec5f */
136.1934 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec60 - U+ec7f */
136.1935 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec80 - U+ec9f */
136.1936 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eca0 - U+ecbf */
136.1937 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ecc0 - U+ecdf */
136.1938 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ece0 - U+ecff */
136.1939 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed00 - U+ed1f */
136.1940 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed20 - U+ed3f */
136.1941 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed40 - U+ed5f */
136.1942 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed60 - U+ed7f */
136.1943 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed80 - U+ed9f */
136.1944 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eda0 - U+edbf */
136.1945 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+edc0 - U+eddf */
136.1946 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ede0 - U+edff */
136.1947 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee00 - U+ee1f */
136.1948 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee20 - U+ee3f */
136.1949 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee40 - U+ee5f */
136.1950 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee60 - U+ee7f */
136.1951 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee80 - U+ee9f */
136.1952 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eea0 - U+eebf */
136.1953 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eec0 - U+eedf */
136.1954 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eee0 - U+eeff */
136.1955 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef00 - U+ef1f */
136.1956 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef20 - U+ef3f */
136.1957 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef40 - U+ef5f */
136.1958 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef60 - U+ef7f */
136.1959 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef80 - U+ef9f */
136.1960 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+efa0 - U+efbf */
136.1961 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+efc0 - U+efdf */
136.1962 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+efe0 - U+efff */
136.1963 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f000 - U+f01f */
136.1964 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f020 - U+f03f */
136.1965 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f040 - U+f05f */
136.1966 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f060 - U+f07f */
136.1967 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f080 - U+f09f */
136.1968 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f0a0 - U+f0bf */
136.1969 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f0c0 - U+f0df */
136.1970 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f0e0 - U+f0ff */
136.1971 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f100 - U+f11f */
136.1972 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f120 - U+f13f */
136.1973 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f140 - U+f15f */
136.1974 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f160 - U+f17f */
136.1975 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f180 - U+f19f */
136.1976 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f1a0 - U+f1bf */
136.1977 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f1c0 - U+f1df */
136.1978 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f1e0 - U+f1ff */
136.1979 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f200 - U+f21f */
136.1980 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f220 - U+f23f */
136.1981 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f240 - U+f25f */
136.1982 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f260 - U+f27f */
136.1983 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f280 - U+f29f */
136.1984 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f2a0 - U+f2bf */
136.1985 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f2c0 - U+f2df */
136.1986 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f2e0 - U+f2ff */
136.1987 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f300 - U+f31f */
136.1988 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f320 - U+f33f */
136.1989 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f340 - U+f35f */
136.1990 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f360 - U+f37f */
136.1991 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f380 - U+f39f */
136.1992 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f3a0 - U+f3bf */
136.1993 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f3c0 - U+f3df */
136.1994 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f3e0 - U+f3ff */
136.1995 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f400 - U+f41f */
136.1996 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f420 - U+f43f */
136.1997 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f440 - U+f45f */
136.1998 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f460 - U+f47f */
136.1999 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f480 - U+f49f */
136.2000 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f4a0 - U+f4bf */
136.2001 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f4c0 - U+f4df */
136.2002 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f4e0 - U+f4ff */
136.2003 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f500 - U+f51f */
136.2004 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f520 - U+f53f */
136.2005 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f540 - U+f55f */
136.2006 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f560 - U+f57f */
136.2007 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f580 - U+f59f */
136.2008 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f5a0 - U+f5bf */
136.2009 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f5c0 - U+f5df */
136.2010 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f5e0 - U+f5ff */
136.2011 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f600 - U+f61f */
136.2012 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f620 - U+f63f */
136.2013 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f640 - U+f65f */
136.2014 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f660 - U+f67f */
136.2015 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f680 - U+f69f */
136.2016 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f6a0 - U+f6bf */
136.2017 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f6c0 - U+f6df */
136.2018 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f6e0 - U+f6ff */
136.2019 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f700 - U+f71f */
136.2020 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f720 - U+f73f */
136.2021 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f740 - U+f75f */
136.2022 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f760 - U+f77f */
136.2023 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f780 - U+f79f */
136.2024 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f7a0 - U+f7bf */
136.2025 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f7c0 - U+f7df */
136.2026 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f7e0 - U+f7ff */
136.2027 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f800 - U+f81f */
136.2028 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f820 - U+f83f */
136.2029 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f840 - U+f85f */
136.2030 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f860 - U+f87f */
136.2031 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f880 - U+f89f */
136.2032 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f8a0 - U+f8bf */
136.2033 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f8c0 - U+f8df */
136.2034 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f8e0 - U+f8ff */
136.2035 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f900 - U+f91f */
136.2036 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f920 - U+f93f */
136.2037 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f940 - U+f95f */
136.2038 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f960 - U+f97f */
136.2039 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f980 - U+f99f */
136.2040 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f9a0 - U+f9bf */
136.2041 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f9c0 - U+f9df */
136.2042 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f9e0 - U+f9ff */
136.2043 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+fa00 - U+fa1f */
136.2044 +  0xaa,0xaa,0xaa,0xaf,0xaa,0xaa,0xaa,0xaa,	/* U+fa20 - U+fa3f */
136.2045 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+fa40 - U+fa5f */
136.2046 +  0xaa,0xaa,0xab,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+fa60 - U+fa7f */
136.2047 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+fa80 - U+fa9f */
136.2048 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+faa0 - U+fabf */
136.2049 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,	/* U+fac0 - U+fadf */
136.2050 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fae0 - U+faff */
136.2051 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf3,	/* U+fb00 - U+fb1f */
136.2052 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb20 - U+fb3f */
136.2053 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb40 - U+fb5f */
136.2054 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb60 - U+fb7f */
136.2055 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb80 - U+fb9f */
136.2056 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fba0 - U+fbbf */
136.2057 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fbc0 - U+fbdf */
136.2058 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fbe0 - U+fbff */
136.2059 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc00 - U+fc1f */
136.2060 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc20 - U+fc3f */
136.2061 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc40 - U+fc5f */
136.2062 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc60 - U+fc7f */
136.2063 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc80 - U+fc9f */
136.2064 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fca0 - U+fcbf */
136.2065 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fcc0 - U+fcdf */
136.2066 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fce0 - U+fcff */
136.2067 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd00 - U+fd1f */
136.2068 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd20 - U+fd3f */
136.2069 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd40 - U+fd5f */
136.2070 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd60 - U+fd7f */
136.2071 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd80 - U+fd9f */
136.2072 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fda0 - U+fdbf */
136.2073 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fdc0 - U+fddf */
136.2074 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fde0 - U+fdff */
136.2075 +  0x00,0x00,0x00,0x00,0xaa,0xaa,0xaf,0xff,	/* U+fe00 - U+fe1f */
136.2076 +  0x00,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+fe20 - U+fe3f */
136.2077 +  0xaa,0xaa,0xaa,0xaa,0xab,0xaa,0xaa,0xaa,	/* U+fe40 - U+fe5f */
136.2078 +  0xaa,0xab,0xaa,0xff,0xff,0xff,0xff,0xff,	/* U+fe60 - U+fe7f */
136.2079 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fe80 - U+fe9f */
136.2080 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fea0 - U+febf */
136.2081 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fec0 - U+fedf */
136.2082 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+fee0 - U+feff */
136.2083 +  0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ff00 - U+ff1f */
136.2084 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ff20 - U+ff3f */
136.2085 +  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ff40 - U+ff5f */
136.2086 +  0x95,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+ff60 - U+ff7f */
136.2087 +  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+ff80 - U+ff9f */
136.2088 +  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x57,	/* U+ffa0 - U+ffbf */
136.2089 +  0xf5,0x55,0xf5,0x55,0xf5,0x55,0xf5,0x7f,	/* U+ffc0 - U+ffdf */
136.2090 +  0xaa,0xab,0x55,0x57,0xff,0xff,0xc0,0xff,	/* U+ffe0 - U+ffff */
136.2091 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10000 - U+1001f */
136.2092 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10020 - U+1003f */
136.2093 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10040 - U+1005f */
136.2094 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10060 - U+1007f */
136.2095 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10080 - U+1009f */
136.2096 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+100a0 - U+100bf */
136.2097 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+100c0 - U+100df */
136.2098 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+100e0 - U+100ff */
136.2099 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10100 - U+1011f */
136.2100 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10120 - U+1013f */
136.2101 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10140 - U+1015f */
136.2102 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10160 - U+1017f */
136.2103 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10180 - U+1019f */
136.2104 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+101a0 - U+101bf */
136.2105 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+101c0 - U+101df */
136.2106 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+101e0 - U+101ff */
136.2107 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10200 - U+1021f */
136.2108 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10220 - U+1023f */
136.2109 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10240 - U+1025f */
136.2110 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10260 - U+1027f */
136.2111 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10280 - U+1029f */
136.2112 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+102a0 - U+102bf */
136.2113 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+102c0 - U+102df */
136.2114 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+102e0 - U+102ff */
136.2115 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10300 - U+1031f */
136.2116 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10320 - U+1033f */
136.2117 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10340 - U+1035f */
136.2118 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10360 - U+1037f */
136.2119 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10380 - U+1039f */
136.2120 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+103a0 - U+103bf */
136.2121 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+103c0 - U+103df */
136.2122 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+103e0 - U+103ff */
136.2123 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10400 - U+1041f */
136.2124 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10420 - U+1043f */
136.2125 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10440 - U+1045f */
136.2126 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10460 - U+1047f */
136.2127 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10480 - U+1049f */
136.2128 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+104a0 - U+104bf */
136.2129 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+104c0 - U+104df */
136.2130 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+104e0 - U+104ff */
136.2131 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10500 - U+1051f */
136.2132 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10520 - U+1053f */
136.2133 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10540 - U+1055f */
136.2134 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10560 - U+1057f */
136.2135 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10580 - U+1059f */
136.2136 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+105a0 - U+105bf */
136.2137 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+105c0 - U+105df */
136.2138 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+105e0 - U+105ff */
136.2139 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10600 - U+1061f */
136.2140 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10620 - U+1063f */
136.2141 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10640 - U+1065f */
136.2142 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10660 - U+1067f */
136.2143 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10680 - U+1069f */
136.2144 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+106a0 - U+106bf */
136.2145 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+106c0 - U+106df */
136.2146 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+106e0 - U+106ff */
136.2147 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10700 - U+1071f */
136.2148 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10720 - U+1073f */
136.2149 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10740 - U+1075f */
136.2150 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10760 - U+1077f */
136.2151 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10780 - U+1079f */
136.2152 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+107a0 - U+107bf */
136.2153 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+107c0 - U+107df */
136.2154 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+107e0 - U+107ff */
136.2155 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10800 - U+1081f */
136.2156 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10820 - U+1083f */
136.2157 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10840 - U+1085f */
136.2158 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10860 - U+1087f */
136.2159 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10880 - U+1089f */
136.2160 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+108a0 - U+108bf */
136.2161 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+108c0 - U+108df */
136.2162 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+108e0 - U+108ff */
136.2163 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10900 - U+1091f */
136.2164 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10920 - U+1093f */
136.2165 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10940 - U+1095f */
136.2166 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10960 - U+1097f */
136.2167 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10980 - U+1099f */
136.2168 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+109a0 - U+109bf */
136.2169 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+109c0 - U+109df */
136.2170 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+109e0 - U+109ff */
136.2171 +  0xc0,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,	/* U+10a00 - U+10a1f */
136.2172 +  0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc,	/* U+10a20 - U+10a3f */
136.2173 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a40 - U+10a5f */
136.2174 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a60 - U+10a7f */
136.2175 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a80 - U+10a9f */
136.2176 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10aa0 - U+10abf */
136.2177 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ac0 - U+10adf */
136.2178 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ae0 - U+10aff */
136.2179 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b00 - U+10b1f */
136.2180 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b20 - U+10b3f */
136.2181 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b40 - U+10b5f */
136.2182 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b60 - U+10b7f */
136.2183 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b80 - U+10b9f */
136.2184 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ba0 - U+10bbf */
136.2185 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10bc0 - U+10bdf */
136.2186 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10be0 - U+10bff */
136.2187 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c00 - U+10c1f */
136.2188 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c20 - U+10c3f */
136.2189 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c40 - U+10c5f */
136.2190 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c60 - U+10c7f */
136.2191 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c80 - U+10c9f */
136.2192 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ca0 - U+10cbf */
136.2193 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10cc0 - U+10cdf */
136.2194 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ce0 - U+10cff */
136.2195 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d00 - U+10d1f */
136.2196 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d20 - U+10d3f */
136.2197 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d40 - U+10d5f */
136.2198 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d60 - U+10d7f */
136.2199 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d80 - U+10d9f */
136.2200 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10da0 - U+10dbf */
136.2201 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10dc0 - U+10ddf */
136.2202 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10de0 - U+10dff */
136.2203 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e00 - U+10e1f */
136.2204 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e20 - U+10e3f */
136.2205 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e40 - U+10e5f */
136.2206 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e60 - U+10e7f */
136.2207 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e80 - U+10e9f */
136.2208 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ea0 - U+10ebf */
136.2209 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ec0 - U+10edf */
136.2210 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ee0 - U+10eff */
136.2211 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f00 - U+10f1f */
136.2212 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f20 - U+10f3f */
136.2213 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f40 - U+10f5f */
136.2214 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f60 - U+10f7f */
136.2215 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f80 - U+10f9f */
136.2216 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10fa0 - U+10fbf */
136.2217 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10fc0 - U+10fdf */
136.2218 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10fe0 - U+10fff */
136.2219 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11000 - U+1101f */
136.2220 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11020 - U+1103f */
136.2221 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11040 - U+1105f */
136.2222 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11060 - U+1107f */
136.2223 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11080 - U+1109f */
136.2224 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+110a0 - U+110bf */
136.2225 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+110c0 - U+110df */
136.2226 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+110e0 - U+110ff */
136.2227 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11100 - U+1111f */
136.2228 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11120 - U+1113f */
136.2229 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11140 - U+1115f */
136.2230 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11160 - U+1117f */
136.2231 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11180 - U+1119f */
136.2232 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+111a0 - U+111bf */
136.2233 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+111c0 - U+111df */
136.2234 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+111e0 - U+111ff */
136.2235 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11200 - U+1121f */
136.2236 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11220 - U+1123f */
136.2237 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11240 - U+1125f */
136.2238 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11260 - U+1127f */
136.2239 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11280 - U+1129f */
136.2240 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+112a0 - U+112bf */
136.2241 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+112c0 - U+112df */
136.2242 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+112e0 - U+112ff */
136.2243 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11300 - U+1131f */
136.2244 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11320 - U+1133f */
136.2245 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11340 - U+1135f */
136.2246 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11360 - U+1137f */
136.2247 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11380 - U+1139f */
136.2248 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+113a0 - U+113bf */
136.2249 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+113c0 - U+113df */
136.2250 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+113e0 - U+113ff */
136.2251 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11400 - U+1141f */
136.2252 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11420 - U+1143f */
136.2253 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11440 - U+1145f */
136.2254 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11460 - U+1147f */
136.2255 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11480 - U+1149f */
136.2256 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+114a0 - U+114bf */
136.2257 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+114c0 - U+114df */
136.2258 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+114e0 - U+114ff */
136.2259 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11500 - U+1151f */
136.2260 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11520 - U+1153f */
136.2261 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11540 - U+1155f */
136.2262 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11560 - U+1157f */
136.2263 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11580 - U+1159f */
136.2264 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+115a0 - U+115bf */
136.2265 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+115c0 - U+115df */
136.2266 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+115e0 - U+115ff */
136.2267 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11600 - U+1161f */
136.2268 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11620 - U+1163f */
136.2269 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11640 - U+1165f */
136.2270 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11660 - U+1167f */
136.2271 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11680 - U+1169f */
136.2272 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+116a0 - U+116bf */
136.2273 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+116c0 - U+116df */
136.2274 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+116e0 - U+116ff */
136.2275 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11700 - U+1171f */
136.2276 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11720 - U+1173f */
136.2277 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11740 - U+1175f */
136.2278 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11760 - U+1177f */
136.2279 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11780 - U+1179f */
136.2280 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+117a0 - U+117bf */
136.2281 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+117c0 - U+117df */
136.2282 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+117e0 - U+117ff */
136.2283 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11800 - U+1181f */
136.2284 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11820 - U+1183f */
136.2285 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11840 - U+1185f */
136.2286 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11860 - U+1187f */
136.2287 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11880 - U+1189f */
136.2288 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+118a0 - U+118bf */
136.2289 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+118c0 - U+118df */
136.2290 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+118e0 - U+118ff */
136.2291 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11900 - U+1191f */
136.2292 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11920 - U+1193f */
136.2293 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11940 - U+1195f */
136.2294 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11960 - U+1197f */
136.2295 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11980 - U+1199f */
136.2296 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+119a0 - U+119bf */
136.2297 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+119c0 - U+119df */
136.2298 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+119e0 - U+119ff */
136.2299 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a00 - U+11a1f */
136.2300 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a20 - U+11a3f */
136.2301 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a40 - U+11a5f */
136.2302 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a60 - U+11a7f */
136.2303 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a80 - U+11a9f */
136.2304 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11aa0 - U+11abf */
136.2305 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ac0 - U+11adf */
136.2306 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ae0 - U+11aff */
136.2307 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b00 - U+11b1f */
136.2308 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b20 - U+11b3f */
136.2309 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b40 - U+11b5f */
136.2310 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b60 - U+11b7f */
136.2311 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b80 - U+11b9f */
136.2312 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ba0 - U+11bbf */
136.2313 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11bc0 - U+11bdf */
136.2314 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11be0 - U+11bff */
136.2315 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c00 - U+11c1f */
136.2316 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c20 - U+11c3f */
136.2317 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c40 - U+11c5f */
136.2318 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c60 - U+11c7f */
136.2319 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c80 - U+11c9f */
136.2320 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ca0 - U+11cbf */
136.2321 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11cc0 - U+11cdf */
136.2322 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ce0 - U+11cff */
136.2323 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d00 - U+11d1f */
136.2324 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d20 - U+11d3f */
136.2325 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d40 - U+11d5f */
136.2326 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d60 - U+11d7f */
136.2327 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d80 - U+11d9f */
136.2328 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11da0 - U+11dbf */
136.2329 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11dc0 - U+11ddf */
136.2330 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11de0 - U+11dff */
136.2331 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e00 - U+11e1f */
136.2332 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e20 - U+11e3f */
136.2333 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e40 - U+11e5f */
136.2334 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e60 - U+11e7f */
136.2335 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e80 - U+11e9f */
136.2336 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ea0 - U+11ebf */
136.2337 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ec0 - U+11edf */
136.2338 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ee0 - U+11eff */
136.2339 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f00 - U+11f1f */
136.2340 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f20 - U+11f3f */
136.2341 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f40 - U+11f5f */
136.2342 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f60 - U+11f7f */
136.2343 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f80 - U+11f9f */
136.2344 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11fa0 - U+11fbf */
136.2345 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11fc0 - U+11fdf */
136.2346 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11fe0 - U+11fff */
136.2347 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12000 - U+1201f */
136.2348 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12020 - U+1203f */
136.2349 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12040 - U+1205f */
136.2350 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12060 - U+1207f */
136.2351 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12080 - U+1209f */
136.2352 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+120a0 - U+120bf */
136.2353 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+120c0 - U+120df */
136.2354 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+120e0 - U+120ff */
136.2355 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12100 - U+1211f */
136.2356 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12120 - U+1213f */
136.2357 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12140 - U+1215f */
136.2358 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12160 - U+1217f */
136.2359 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12180 - U+1219f */
136.2360 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+121a0 - U+121bf */
136.2361 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+121c0 - U+121df */
136.2362 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+121e0 - U+121ff */
136.2363 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12200 - U+1221f */
136.2364 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12220 - U+1223f */
136.2365 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12240 - U+1225f */
136.2366 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12260 - U+1227f */
136.2367 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12280 - U+1229f */
136.2368 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+122a0 - U+122bf */
136.2369 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+122c0 - U+122df */
136.2370 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+122e0 - U+122ff */
136.2371 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12300 - U+1231f */
136.2372 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12320 - U+1233f */
136.2373 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12340 - U+1235f */
136.2374 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12360 - U+1237f */
136.2375 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12380 - U+1239f */
136.2376 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+123a0 - U+123bf */
136.2377 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+123c0 - U+123df */
136.2378 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+123e0 - U+123ff */
136.2379 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12400 - U+1241f */
136.2380 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12420 - U+1243f */
136.2381 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12440 - U+1245f */
136.2382 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12460 - U+1247f */
136.2383 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12480 - U+1249f */
136.2384 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+124a0 - U+124bf */
136.2385 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+124c0 - U+124df */
136.2386 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+124e0 - U+124ff */
136.2387 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12500 - U+1251f */
136.2388 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12520 - U+1253f */
136.2389 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12540 - U+1255f */
136.2390 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12560 - U+1257f */
136.2391 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12580 - U+1259f */
136.2392 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+125a0 - U+125bf */
136.2393 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+125c0 - U+125df */
136.2394 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+125e0 - U+125ff */
136.2395 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12600 - U+1261f */
136.2396 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12620 - U+1263f */
136.2397 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12640 - U+1265f */
136.2398 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12660 - U+1267f */
136.2399 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12680 - U+1269f */
136.2400 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+126a0 - U+126bf */
136.2401 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+126c0 - U+126df */
136.2402 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+126e0 - U+126ff */
136.2403 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12700 - U+1271f */
136.2404 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12720 - U+1273f */
136.2405 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12740 - U+1275f */
136.2406 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12760 - U+1277f */
136.2407 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12780 - U+1279f */
136.2408 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+127a0 - U+127bf */
136.2409 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+127c0 - U+127df */
136.2410 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+127e0 - U+127ff */
136.2411 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12800 - U+1281f */
136.2412 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12820 - U+1283f */
136.2413 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12840 - U+1285f */
136.2414 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12860 - U+1287f */
136.2415 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12880 - U+1289f */
136.2416 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+128a0 - U+128bf */
136.2417 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+128c0 - U+128df */
136.2418 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+128e0 - U+128ff */
136.2419 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12900 - U+1291f */
136.2420 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12920 - U+1293f */
136.2421 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12940 - U+1295f */
136.2422 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12960 - U+1297f */
136.2423 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12980 - U+1299f */
136.2424 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+129a0 - U+129bf */
136.2425 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+129c0 - U+129df */
136.2426 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+129e0 - U+129ff */
136.2427 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a00 - U+12a1f */
136.2428 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a20 - U+12a3f */
136.2429 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a40 - U+12a5f */
136.2430 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a60 - U+12a7f */
136.2431 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a80 - U+12a9f */
136.2432 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12aa0 - U+12abf */
136.2433 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ac0 - U+12adf */
136.2434 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ae0 - U+12aff */
136.2435 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b00 - U+12b1f */
136.2436 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b20 - U+12b3f */
136.2437 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b40 - U+12b5f */
136.2438 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b60 - U+12b7f */
136.2439 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b80 - U+12b9f */
136.2440 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ba0 - U+12bbf */
136.2441 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12bc0 - U+12bdf */
136.2442 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12be0 - U+12bff */
136.2443 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c00 - U+12c1f */
136.2444 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c20 - U+12c3f */
136.2445 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c40 - U+12c5f */
136.2446 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c60 - U+12c7f */
136.2447 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c80 - U+12c9f */
136.2448 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ca0 - U+12cbf */
136.2449 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12cc0 - U+12cdf */
136.2450 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ce0 - U+12cff */
136.2451 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d00 - U+12d1f */
136.2452 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d20 - U+12d3f */
136.2453 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d40 - U+12d5f */
136.2454 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d60 - U+12d7f */
136.2455 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d80 - U+12d9f */
136.2456 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12da0 - U+12dbf */
136.2457 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12dc0 - U+12ddf */
136.2458 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12de0 - U+12dff */
136.2459 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e00 - U+12e1f */
136.2460 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e20 - U+12e3f */
136.2461 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e40 - U+12e5f */
136.2462 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e60 - U+12e7f */
136.2463 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e80 - U+12e9f */
136.2464 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ea0 - U+12ebf */
136.2465 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ec0 - U+12edf */
136.2466 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ee0 - U+12eff */
136.2467 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f00 - U+12f1f */
136.2468 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f20 - U+12f3f */
136.2469 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f40 - U+12f5f */
136.2470 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f60 - U+12f7f */
136.2471 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f80 - U+12f9f */
136.2472 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12fa0 - U+12fbf */
136.2473 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12fc0 - U+12fdf */
136.2474 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12fe0 - U+12fff */
136.2475 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13000 - U+1301f */
136.2476 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13020 - U+1303f */
136.2477 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13040 - U+1305f */
136.2478 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13060 - U+1307f */
136.2479 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13080 - U+1309f */
136.2480 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+130a0 - U+130bf */
136.2481 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+130c0 - U+130df */
136.2482 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+130e0 - U+130ff */
136.2483 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13100 - U+1311f */
136.2484 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13120 - U+1313f */
136.2485 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13140 - U+1315f */
136.2486 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13160 - U+1317f */
136.2487 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13180 - U+1319f */
136.2488 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+131a0 - U+131bf */
136.2489 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+131c0 - U+131df */
136.2490 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+131e0 - U+131ff */
136.2491 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13200 - U+1321f */
136.2492 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13220 - U+1323f */
136.2493 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13240 - U+1325f */
136.2494 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13260 - U+1327f */
136.2495 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13280 - U+1329f */
136.2496 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+132a0 - U+132bf */
136.2497 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+132c0 - U+132df */
136.2498 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+132e0 - U+132ff */
136.2499 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13300 - U+1331f */
136.2500 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13320 - U+1333f */
136.2501 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13340 - U+1335f */
136.2502 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13360 - U+1337f */
136.2503 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13380 - U+1339f */
136.2504 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+133a0 - U+133bf */
136.2505 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+133c0 - U+133df */
136.2506 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+133e0 - U+133ff */
136.2507 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13400 - U+1341f */
136.2508 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13420 - U+1343f */
136.2509 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13440 - U+1345f */
136.2510 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13460 - U+1347f */
136.2511 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13480 - U+1349f */
136.2512 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+134a0 - U+134bf */
136.2513 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+134c0 - U+134df */
136.2514 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+134e0 - U+134ff */
136.2515 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13500 - U+1351f */
136.2516 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13520 - U+1353f */
136.2517 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13540 - U+1355f */
136.2518 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13560 - U+1357f */
136.2519 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13580 - U+1359f */
136.2520 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+135a0 - U+135bf */
136.2521 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+135c0 - U+135df */
136.2522 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+135e0 - U+135ff */
136.2523 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13600 - U+1361f */
136.2524 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13620 - U+1363f */
136.2525 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13640 - U+1365f */
136.2526 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13660 - U+1367f */
136.2527 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13680 - U+1369f */
136.2528 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+136a0 - U+136bf */
136.2529 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+136c0 - U+136df */
136.2530 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+136e0 - U+136ff */
136.2531 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13700 - U+1371f */
136.2532 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13720 - U+1373f */
136.2533 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13740 - U+1375f */
136.2534 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13760 - U+1377f */
136.2535 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13780 - U+1379f */
136.2536 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+137a0 - U+137bf */
136.2537 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+137c0 - U+137df */
136.2538 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+137e0 - U+137ff */
136.2539 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13800 - U+1381f */
136.2540 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13820 - U+1383f */
136.2541 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13840 - U+1385f */
136.2542 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13860 - U+1387f */
136.2543 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13880 - U+1389f */
136.2544 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+138a0 - U+138bf */
136.2545 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+138c0 - U+138df */
136.2546 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+138e0 - U+138ff */
136.2547 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13900 - U+1391f */
136.2548 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13920 - U+1393f */
136.2549 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13940 - U+1395f */
136.2550 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13960 - U+1397f */
136.2551 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13980 - U+1399f */
136.2552 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+139a0 - U+139bf */
136.2553 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+139c0 - U+139df */
136.2554 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+139e0 - U+139ff */
136.2555 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a00 - U+13a1f */
136.2556 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a20 - U+13a3f */
136.2557 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a40 - U+13a5f */
136.2558 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a60 - U+13a7f */
136.2559 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a80 - U+13a9f */
136.2560 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13aa0 - U+13abf */
136.2561 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ac0 - U+13adf */
136.2562 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ae0 - U+13aff */
136.2563 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b00 - U+13b1f */
136.2564 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b20 - U+13b3f */
136.2565 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b40 - U+13b5f */
136.2566 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b60 - U+13b7f */
136.2567 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b80 - U+13b9f */
136.2568 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ba0 - U+13bbf */
136.2569 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13bc0 - U+13bdf */
136.2570 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13be0 - U+13bff */
136.2571 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c00 - U+13c1f */
136.2572 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c20 - U+13c3f */
136.2573 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c40 - U+13c5f */
136.2574 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c60 - U+13c7f */
136.2575 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c80 - U+13c9f */
136.2576 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ca0 - U+13cbf */
136.2577 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13cc0 - U+13cdf */
136.2578 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ce0 - U+13cff */
136.2579 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d00 - U+13d1f */
136.2580 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d20 - U+13d3f */
136.2581 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d40 - U+13d5f */
136.2582 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d60 - U+13d7f */
136.2583 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d80 - U+13d9f */
136.2584 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13da0 - U+13dbf */
136.2585 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13dc0 - U+13ddf */
136.2586 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13de0 - U+13dff */
136.2587 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e00 - U+13e1f */
136.2588 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e20 - U+13e3f */
136.2589 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e40 - U+13e5f */
136.2590 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e60 - U+13e7f */
136.2591 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e80 - U+13e9f */
136.2592 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ea0 - U+13ebf */
136.2593 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ec0 - U+13edf */
136.2594 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ee0 - U+13eff */
136.2595 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f00 - U+13f1f */
136.2596 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f20 - U+13f3f */
136.2597 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f40 - U+13f5f */
136.2598 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f60 - U+13f7f */
136.2599 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f80 - U+13f9f */
136.2600 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13fa0 - U+13fbf */
136.2601 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13fc0 - U+13fdf */
136.2602 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13fe0 - U+13fff */
136.2603 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14000 - U+1401f */
136.2604 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14020 - U+1403f */
136.2605 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14040 - U+1405f */
136.2606 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14060 - U+1407f */
136.2607 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14080 - U+1409f */
136.2608 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+140a0 - U+140bf */
136.2609 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+140c0 - U+140df */
136.2610 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+140e0 - U+140ff */
136.2611 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14100 - U+1411f */
136.2612 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14120 - U+1413f */
136.2613 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14140 - U+1415f */
136.2614 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14160 - U+1417f */
136.2615 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14180 - U+1419f */
136.2616 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+141a0 - U+141bf */
136.2617 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+141c0 - U+141df */
136.2618 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+141e0 - U+141ff */
136.2619 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14200 - U+1421f */
136.2620 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14220 - U+1423f */
136.2621 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14240 - U+1425f */
136.2622 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14260 - U+1427f */
136.2623 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14280 - U+1429f */
136.2624 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+142a0 - U+142bf */
136.2625 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+142c0 - U+142df */
136.2626 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+142e0 - U+142ff */
136.2627 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14300 - U+1431f */
136.2628 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14320 - U+1433f */
136.2629 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14340 - U+1435f */
136.2630 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14360 - U+1437f */
136.2631 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14380 - U+1439f */
136.2632 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+143a0 - U+143bf */
136.2633 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+143c0 - U+143df */
136.2634 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+143e0 - U+143ff */
136.2635 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14400 - U+1441f */
136.2636 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14420 - U+1443f */
136.2637 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14440 - U+1445f */
136.2638 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14460 - U+1447f */
136.2639 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14480 - U+1449f */
136.2640 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+144a0 - U+144bf */
136.2641 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+144c0 - U+144df */
136.2642 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+144e0 - U+144ff */
136.2643 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14500 - U+1451f */
136.2644 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14520 - U+1453f */
136.2645 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14540 - U+1455f */
136.2646 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14560 - U+1457f */
136.2647 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14580 - U+1459f */
136.2648 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+145a0 - U+145bf */
136.2649 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+145c0 - U+145df */
136.2650 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+145e0 - U+145ff */
136.2651 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14600 - U+1461f */
136.2652 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14620 - U+1463f */
136.2653 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14640 - U+1465f */
136.2654 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14660 - U+1467f */
136.2655 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14680 - U+1469f */
136.2656 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+146a0 - U+146bf */
136.2657 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+146c0 - U+146df */
136.2658 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+146e0 - U+146ff */
136.2659 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14700 - U+1471f */
136.2660 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14720 - U+1473f */
136.2661 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14740 - U+1475f */
136.2662 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14760 - U+1477f */
136.2663 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14780 - U+1479f */
136.2664 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+147a0 - U+147bf */
136.2665 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+147c0 - U+147df */
136.2666 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+147e0 - U+147ff */
136.2667 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14800 - U+1481f */
136.2668 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14820 - U+1483f */
136.2669 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14840 - U+1485f */
136.2670 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14860 - U+1487f */
136.2671 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14880 - U+1489f */
136.2672 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+148a0 - U+148bf */
136.2673 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+148c0 - U+148df */
136.2674 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+148e0 - U+148ff */
136.2675 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14900 - U+1491f */
136.2676 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14920 - U+1493f */
136.2677 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14940 - U+1495f */
136.2678 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14960 - U+1497f */
136.2679 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14980 - U+1499f */
136.2680 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+149a0 - U+149bf */
136.2681 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+149c0 - U+149df */
136.2682 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+149e0 - U+149ff */
136.2683 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a00 - U+14a1f */
136.2684 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a20 - U+14a3f */
136.2685 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a40 - U+14a5f */
136.2686 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a60 - U+14a7f */
136.2687 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a80 - U+14a9f */
136.2688 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14aa0 - U+14abf */
136.2689 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ac0 - U+14adf */
136.2690 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ae0 - U+14aff */
136.2691 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b00 - U+14b1f */
136.2692 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b20 - U+14b3f */
136.2693 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b40 - U+14b5f */
136.2694 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b60 - U+14b7f */
136.2695 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b80 - U+14b9f */
136.2696 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ba0 - U+14bbf */
136.2697 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14bc0 - U+14bdf */
136.2698 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14be0 - U+14bff */
136.2699 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c00 - U+14c1f */
136.2700 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c20 - U+14c3f */
136.2701 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c40 - U+14c5f */
136.2702 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c60 - U+14c7f */
136.2703 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c80 - U+14c9f */
136.2704 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ca0 - U+14cbf */
136.2705 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14cc0 - U+14cdf */
136.2706 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ce0 - U+14cff */
136.2707 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d00 - U+14d1f */
136.2708 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d20 - U+14d3f */
136.2709 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d40 - U+14d5f */
136.2710 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d60 - U+14d7f */
136.2711 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d80 - U+14d9f */
136.2712 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14da0 - U+14dbf */
136.2713 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14dc0 - U+14ddf */
136.2714 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14de0 - U+14dff */
136.2715 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e00 - U+14e1f */
136.2716 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e20 - U+14e3f */
136.2717 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e40 - U+14e5f */
136.2718 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e60 - U+14e7f */
136.2719 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e80 - U+14e9f */
136.2720 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ea0 - U+14ebf */
136.2721 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ec0 - U+14edf */
136.2722 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ee0 - U+14eff */
136.2723 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f00 - U+14f1f */
136.2724 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f20 - U+14f3f */
136.2725 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f40 - U+14f5f */
136.2726 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f60 - U+14f7f */
136.2727 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f80 - U+14f9f */
136.2728 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14fa0 - U+14fbf */
136.2729 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14fc0 - U+14fdf */
136.2730 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14fe0 - U+14fff */
136.2731 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15000 - U+1501f */
136.2732 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15020 - U+1503f */
136.2733 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15040 - U+1505f */
136.2734 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15060 - U+1507f */
136.2735 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15080 - U+1509f */
136.2736 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+150a0 - U+150bf */
136.2737 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+150c0 - U+150df */
136.2738 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+150e0 - U+150ff */
136.2739 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15100 - U+1511f */
136.2740 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15120 - U+1513f */
136.2741 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15140 - U+1515f */
136.2742 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15160 - U+1517f */
136.2743 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15180 - U+1519f */
136.2744 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+151a0 - U+151bf */
136.2745 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+151c0 - U+151df */
136.2746 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+151e0 - U+151ff */
136.2747 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15200 - U+1521f */
136.2748 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15220 - U+1523f */
136.2749 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15240 - U+1525f */
136.2750 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15260 - U+1527f */
136.2751 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15280 - U+1529f */
136.2752 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+152a0 - U+152bf */
136.2753 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+152c0 - U+152df */
136.2754 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+152e0 - U+152ff */
136.2755 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15300 - U+1531f */
136.2756 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15320 - U+1533f */
136.2757 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15340 - U+1535f */
136.2758 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15360 - U+1537f */
136.2759 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15380 - U+1539f */
136.2760 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+153a0 - U+153bf */
136.2761 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+153c0 - U+153df */
136.2762 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+153e0 - U+153ff */
136.2763 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15400 - U+1541f */
136.2764 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15420 - U+1543f */
136.2765 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15440 - U+1545f */
136.2766 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15460 - U+1547f */
136.2767 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15480 - U+1549f */
136.2768 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+154a0 - U+154bf */
136.2769 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+154c0 - U+154df */
136.2770 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+154e0 - U+154ff */
136.2771 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15500 - U+1551f */
136.2772 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15520 - U+1553f */
136.2773 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15540 - U+1555f */
136.2774 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15560 - U+1557f */
136.2775 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15580 - U+1559f */
136.2776 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+155a0 - U+155bf */
136.2777 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+155c0 - U+155df */
136.2778 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+155e0 - U+155ff */
136.2779 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15600 - U+1561f */
136.2780 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15620 - U+1563f */
136.2781 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15640 - U+1565f */
136.2782 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15660 - U+1567f */
136.2783 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15680 - U+1569f */
136.2784 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+156a0 - U+156bf */
136.2785 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+156c0 - U+156df */
136.2786 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+156e0 - U+156ff */
136.2787 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15700 - U+1571f */
136.2788 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15720 - U+1573f */
136.2789 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15740 - U+1575f */
136.2790 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15760 - U+1577f */
136.2791 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15780 - U+1579f */
136.2792 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+157a0 - U+157bf */
136.2793 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+157c0 - U+157df */
136.2794 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+157e0 - U+157ff */
136.2795 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15800 - U+1581f */
136.2796 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15820 - U+1583f */
136.2797 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15840 - U+1585f */
136.2798 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15860 - U+1587f */
136.2799 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15880 - U+1589f */
136.2800 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+158a0 - U+158bf */
136.2801 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+158c0 - U+158df */
136.2802 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+158e0 - U+158ff */
136.2803 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15900 - U+1591f */
136.2804 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15920 - U+1593f */
136.2805 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15940 - U+1595f */
136.2806 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15960 - U+1597f */
136.2807 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15980 - U+1599f */
136.2808 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+159a0 - U+159bf */
136.2809 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+159c0 - U+159df */
136.2810 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+159e0 - U+159ff */
136.2811 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a00 - U+15a1f */
136.2812 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a20 - U+15a3f */
136.2813 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a40 - U+15a5f */
136.2814 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a60 - U+15a7f */
136.2815 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a80 - U+15a9f */
136.2816 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15aa0 - U+15abf */
136.2817 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ac0 - U+15adf */
136.2818 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ae0 - U+15aff */
136.2819 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b00 - U+15b1f */
136.2820 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b20 - U+15b3f */
136.2821 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b40 - U+15b5f */
136.2822 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b60 - U+15b7f */
136.2823 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b80 - U+15b9f */
136.2824 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ba0 - U+15bbf */
136.2825 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15bc0 - U+15bdf */
136.2826 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15be0 - U+15bff */
136.2827 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c00 - U+15c1f */
136.2828 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c20 - U+15c3f */
136.2829 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c40 - U+15c5f */
136.2830 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c60 - U+15c7f */
136.2831 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c80 - U+15c9f */
136.2832 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ca0 - U+15cbf */
136.2833 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15cc0 - U+15cdf */
136.2834 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ce0 - U+15cff */
136.2835 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d00 - U+15d1f */
136.2836 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d20 - U+15d3f */
136.2837 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d40 - U+15d5f */
136.2838 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d60 - U+15d7f */
136.2839 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d80 - U+15d9f */
136.2840 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15da0 - U+15dbf */
136.2841 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15dc0 - U+15ddf */
136.2842 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15de0 - U+15dff */
136.2843 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e00 - U+15e1f */
136.2844 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e20 - U+15e3f */
136.2845 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e40 - U+15e5f */
136.2846 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e60 - U+15e7f */
136.2847 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e80 - U+15e9f */
136.2848 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ea0 - U+15ebf */
136.2849 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ec0 - U+15edf */
136.2850 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ee0 - U+15eff */
136.2851 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f00 - U+15f1f */
136.2852 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f20 - U+15f3f */
136.2853 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f40 - U+15f5f */
136.2854 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f60 - U+15f7f */
136.2855 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f80 - U+15f9f */
136.2856 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15fa0 - U+15fbf */
136.2857 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15fc0 - U+15fdf */
136.2858 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15fe0 - U+15fff */
136.2859 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16000 - U+1601f */
136.2860 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16020 - U+1603f */
136.2861 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16040 - U+1605f */
136.2862 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16060 - U+1607f */
136.2863 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16080 - U+1609f */
136.2864 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+160a0 - U+160bf */
136.2865 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+160c0 - U+160df */
136.2866 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+160e0 - U+160ff */
136.2867 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16100 - U+1611f */
136.2868 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16120 - U+1613f */
136.2869 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16140 - U+1615f */
136.2870 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16160 - U+1617f */
136.2871 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16180 - U+1619f */
136.2872 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+161a0 - U+161bf */
136.2873 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+161c0 - U+161df */
136.2874 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+161e0 - U+161ff */
136.2875 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16200 - U+1621f */
136.2876 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16220 - U+1623f */
136.2877 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16240 - U+1625f */
136.2878 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16260 - U+1627f */
136.2879 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16280 - U+1629f */
136.2880 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+162a0 - U+162bf */
136.2881 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+162c0 - U+162df */
136.2882 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+162e0 - U+162ff */
136.2883 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16300 - U+1631f */
136.2884 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16320 - U+1633f */
136.2885 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16340 - U+1635f */
136.2886 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16360 - U+1637f */
136.2887 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16380 - U+1639f */
136.2888 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+163a0 - U+163bf */
136.2889 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+163c0 - U+163df */
136.2890 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+163e0 - U+163ff */
136.2891 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16400 - U+1641f */
136.2892 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16420 - U+1643f */
136.2893 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16440 - U+1645f */
136.2894 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16460 - U+1647f */
136.2895 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16480 - U+1649f */
136.2896 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+164a0 - U+164bf */
136.2897 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+164c0 - U+164df */
136.2898 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+164e0 - U+164ff */
136.2899 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16500 - U+1651f */
136.2900 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16520 - U+1653f */
136.2901 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16540 - U+1655f */
136.2902 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16560 - U+1657f */
136.2903 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16580 - U+1659f */
136.2904 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+165a0 - U+165bf */
136.2905 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+165c0 - U+165df */
136.2906 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+165e0 - U+165ff */
136.2907 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16600 - U+1661f */
136.2908 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16620 - U+1663f */
136.2909 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16640 - U+1665f */
136.2910 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16660 - U+1667f */
136.2911 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16680 - U+1669f */
136.2912 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+166a0 - U+166bf */
136.2913 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+166c0 - U+166df */
136.2914 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+166e0 - U+166ff */
136.2915 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16700 - U+1671f */
136.2916 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16720 - U+1673f */
136.2917 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16740 - U+1675f */
136.2918 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16760 - U+1677f */
136.2919 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16780 - U+1679f */
136.2920 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+167a0 - U+167bf */
136.2921 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+167c0 - U+167df */
136.2922 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+167e0 - U+167ff */
136.2923 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16800 - U+1681f */
136.2924 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16820 - U+1683f */
136.2925 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16840 - U+1685f */
136.2926 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16860 - U+1687f */
136.2927 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16880 - U+1689f */
136.2928 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+168a0 - U+168bf */
136.2929 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+168c0 - U+168df */
136.2930 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+168e0 - U+168ff */
136.2931 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16900 - U+1691f */
136.2932 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16920 - U+1693f */
136.2933 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16940 - U+1695f */
136.2934 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16960 - U+1697f */
136.2935 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16980 - U+1699f */
136.2936 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+169a0 - U+169bf */
136.2937 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+169c0 - U+169df */
136.2938 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+169e0 - U+169ff */
136.2939 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a00 - U+16a1f */
136.2940 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a20 - U+16a3f */
136.2941 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a40 - U+16a5f */
136.2942 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a60 - U+16a7f */
136.2943 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a80 - U+16a9f */
136.2944 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16aa0 - U+16abf */
136.2945 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ac0 - U+16adf */
136.2946 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ae0 - U+16aff */
136.2947 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b00 - U+16b1f */
136.2948 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b20 - U+16b3f */
136.2949 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b40 - U+16b5f */
136.2950 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b60 - U+16b7f */
136.2951 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b80 - U+16b9f */
136.2952 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ba0 - U+16bbf */
136.2953 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16bc0 - U+16bdf */
136.2954 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16be0 - U+16bff */
136.2955 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c00 - U+16c1f */
136.2956 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c20 - U+16c3f */
136.2957 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c40 - U+16c5f */
136.2958 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c60 - U+16c7f */
136.2959 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c80 - U+16c9f */
136.2960 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ca0 - U+16cbf */
136.2961 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16cc0 - U+16cdf */
136.2962 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ce0 - U+16cff */
136.2963 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d00 - U+16d1f */
136.2964 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d20 - U+16d3f */
136.2965 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d40 - U+16d5f */
136.2966 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d60 - U+16d7f */
136.2967 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d80 - U+16d9f */
136.2968 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16da0 - U+16dbf */
136.2969 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16dc0 - U+16ddf */
136.2970 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16de0 - U+16dff */
136.2971 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e00 - U+16e1f */
136.2972 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e20 - U+16e3f */
136.2973 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e40 - U+16e5f */
136.2974 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e60 - U+16e7f */
136.2975 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e80 - U+16e9f */
136.2976 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ea0 - U+16ebf */
136.2977 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ec0 - U+16edf */
136.2978 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ee0 - U+16eff */
136.2979 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f00 - U+16f1f */
136.2980 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f20 - U+16f3f */
136.2981 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f40 - U+16f5f */
136.2982 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f60 - U+16f7f */
136.2983 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f80 - U+16f9f */
136.2984 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16fa0 - U+16fbf */
136.2985 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16fc0 - U+16fdf */
136.2986 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16fe0 - U+16fff */
136.2987 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17000 - U+1701f */
136.2988 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17020 - U+1703f */
136.2989 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17040 - U+1705f */
136.2990 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17060 - U+1707f */
136.2991 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17080 - U+1709f */
136.2992 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+170a0 - U+170bf */
136.2993 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+170c0 - U+170df */
136.2994 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+170e0 - U+170ff */
136.2995 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17100 - U+1711f */
136.2996 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17120 - U+1713f */
136.2997 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17140 - U+1715f */
136.2998 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17160 - U+1717f */
136.2999 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17180 - U+1719f */
136.3000 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+171a0 - U+171bf */
136.3001 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+171c0 - U+171df */
136.3002 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+171e0 - U+171ff */
136.3003 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17200 - U+1721f */
136.3004 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17220 - U+1723f */
136.3005 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17240 - U+1725f */
136.3006 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17260 - U+1727f */
136.3007 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17280 - U+1729f */
136.3008 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+172a0 - U+172bf */
136.3009 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+172c0 - U+172df */
136.3010 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+172e0 - U+172ff */
136.3011 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17300 - U+1731f */
136.3012 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17320 - U+1733f */
136.3013 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17340 - U+1735f */
136.3014 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17360 - U+1737f */
136.3015 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17380 - U+1739f */
136.3016 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+173a0 - U+173bf */
136.3017 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+173c0 - U+173df */
136.3018 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+173e0 - U+173ff */
136.3019 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17400 - U+1741f */
136.3020 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17420 - U+1743f */
136.3021 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17440 - U+1745f */
136.3022 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17460 - U+1747f */
136.3023 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17480 - U+1749f */
136.3024 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+174a0 - U+174bf */
136.3025 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+174c0 - U+174df */
136.3026 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+174e0 - U+174ff */
136.3027 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17500 - U+1751f */
136.3028 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17520 - U+1753f */
136.3029 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17540 - U+1755f */
136.3030 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17560 - U+1757f */
136.3031 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17580 - U+1759f */
136.3032 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+175a0 - U+175bf */
136.3033 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+175c0 - U+175df */
136.3034 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+175e0 - U+175ff */
136.3035 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17600 - U+1761f */
136.3036 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17620 - U+1763f */
136.3037 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17640 - U+1765f */
136.3038 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17660 - U+1767f */
136.3039 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17680 - U+1769f */
136.3040 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+176a0 - U+176bf */
136.3041 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+176c0 - U+176df */
136.3042 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+176e0 - U+176ff */
136.3043 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17700 - U+1771f */
136.3044 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17720 - U+1773f */
136.3045 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17740 - U+1775f */
136.3046 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17760 - U+1777f */
136.3047 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17780 - U+1779f */
136.3048 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+177a0 - U+177bf */
136.3049 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+177c0 - U+177df */
136.3050 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+177e0 - U+177ff */
136.3051 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17800 - U+1781f */
136.3052 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17820 - U+1783f */
136.3053 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17840 - U+1785f */
136.3054 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17860 - U+1787f */
136.3055 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17880 - U+1789f */
136.3056 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+178a0 - U+178bf */
136.3057 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+178c0 - U+178df */
136.3058 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+178e0 - U+178ff */
136.3059 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17900 - U+1791f */
136.3060 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17920 - U+1793f */
136.3061 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17940 - U+1795f */
136.3062 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17960 - U+1797f */
136.3063 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17980 - U+1799f */
136.3064 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+179a0 - U+179bf */
136.3065 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+179c0 - U+179df */
136.3066 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+179e0 - U+179ff */
136.3067 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a00 - U+17a1f */
136.3068 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a20 - U+17a3f */
136.3069 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a40 - U+17a5f */
136.3070 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a60 - U+17a7f */
136.3071 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a80 - U+17a9f */
136.3072 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17aa0 - U+17abf */
136.3073 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ac0 - U+17adf */
136.3074 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ae0 - U+17aff */
136.3075 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b00 - U+17b1f */
136.3076 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b20 - U+17b3f */
136.3077 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b40 - U+17b5f */
136.3078 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b60 - U+17b7f */
136.3079 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b80 - U+17b9f */
136.3080 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ba0 - U+17bbf */
136.3081 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17bc0 - U+17bdf */
136.3082 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17be0 - U+17bff */
136.3083 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c00 - U+17c1f */
136.3084 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c20 - U+17c3f */
136.3085 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c40 - U+17c5f */
136.3086 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c60 - U+17c7f */
136.3087 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c80 - U+17c9f */
136.3088 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ca0 - U+17cbf */
136.3089 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17cc0 - U+17cdf */
136.3090 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ce0 - U+17cff */
136.3091 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d00 - U+17d1f */
136.3092 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d20 - U+17d3f */
136.3093 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d40 - U+17d5f */
136.3094 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d60 - U+17d7f */
136.3095 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d80 - U+17d9f */
136.3096 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17da0 - U+17dbf */
136.3097 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17dc0 - U+17ddf */
136.3098 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17de0 - U+17dff */
136.3099 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e00 - U+17e1f */
136.3100 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e20 - U+17e3f */
136.3101 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e40 - U+17e5f */
136.3102 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e60 - U+17e7f */
136.3103 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e80 - U+17e9f */
136.3104 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ea0 - U+17ebf */
136.3105 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ec0 - U+17edf */
136.3106 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ee0 - U+17eff */
136.3107 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f00 - U+17f1f */
136.3108 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f20 - U+17f3f */
136.3109 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f40 - U+17f5f */
136.3110 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f60 - U+17f7f */
136.3111 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f80 - U+17f9f */
136.3112 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17fa0 - U+17fbf */
136.3113 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17fc0 - U+17fdf */
136.3114 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17fe0 - U+17fff */
136.3115 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18000 - U+1801f */
136.3116 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18020 - U+1803f */
136.3117 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18040 - U+1805f */
136.3118 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18060 - U+1807f */
136.3119 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18080 - U+1809f */
136.3120 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+180a0 - U+180bf */
136.3121 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+180c0 - U+180df */
136.3122 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+180e0 - U+180ff */
136.3123 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18100 - U+1811f */
136.3124 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18120 - U+1813f */
136.3125 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18140 - U+1815f */
136.3126 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18160 - U+1817f */
136.3127 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18180 - U+1819f */
136.3128 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+181a0 - U+181bf */
136.3129 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+181c0 - U+181df */
136.3130 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+181e0 - U+181ff */
136.3131 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18200 - U+1821f */
136.3132 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18220 - U+1823f */
136.3133 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18240 - U+1825f */
136.3134 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18260 - U+1827f */
136.3135 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18280 - U+1829f */
136.3136 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+182a0 - U+182bf */
136.3137 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+182c0 - U+182df */
136.3138 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+182e0 - U+182ff */
136.3139 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18300 - U+1831f */
136.3140 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18320 - U+1833f */
136.3141 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18340 - U+1835f */
136.3142 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18360 - U+1837f */
136.3143 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18380 - U+1839f */
136.3144 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+183a0 - U+183bf */
136.3145 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+183c0 - U+183df */
136.3146 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+183e0 - U+183ff */
136.3147 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18400 - U+1841f */
136.3148 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18420 - U+1843f */
136.3149 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18440 - U+1845f */
136.3150 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18460 - U+1847f */
136.3151 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18480 - U+1849f */
136.3152 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+184a0 - U+184bf */
136.3153 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+184c0 - U+184df */
136.3154 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+184e0 - U+184ff */
136.3155 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18500 - U+1851f */
136.3156 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18520 - U+1853f */
136.3157 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18540 - U+1855f */
136.3158 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18560 - U+1857f */
136.3159 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18580 - U+1859f */
136.3160 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+185a0 - U+185bf */
136.3161 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+185c0 - U+185df */
136.3162 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+185e0 - U+185ff */
136.3163 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18600 - U+1861f */
136.3164 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18620 - U+1863f */
136.3165 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18640 - U+1865f */
136.3166 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18660 - U+1867f */
136.3167 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18680 - U+1869f */
136.3168 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+186a0 - U+186bf */
136.3169 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+186c0 - U+186df */
136.3170 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+186e0 - U+186ff */
136.3171 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18700 - U+1871f */
136.3172 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18720 - U+1873f */
136.3173 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18740 - U+1875f */
136.3174 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18760 - U+1877f */
136.3175 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18780 - U+1879f */
136.3176 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+187a0 - U+187bf */
136.3177 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+187c0 - U+187df */
136.3178 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+187e0 - U+187ff */
136.3179 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18800 - U+1881f */
136.3180 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18820 - U+1883f */
136.3181 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18840 - U+1885f */
136.3182 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18860 - U+1887f */
136.3183 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18880 - U+1889f */
136.3184 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+188a0 - U+188bf */
136.3185 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+188c0 - U+188df */
136.3186 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+188e0 - U+188ff */
136.3187 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18900 - U+1891f */
136.3188 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18920 - U+1893f */
136.3189 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18940 - U+1895f */
136.3190 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18960 - U+1897f */
136.3191 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18980 - U+1899f */
136.3192 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+189a0 - U+189bf */
136.3193 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+189c0 - U+189df */
136.3194 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+189e0 - U+189ff */
136.3195 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a00 - U+18a1f */
136.3196 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a20 - U+18a3f */
136.3197 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a40 - U+18a5f */
136.3198 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a60 - U+18a7f */
136.3199 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a80 - U+18a9f */
136.3200 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18aa0 - U+18abf */
136.3201 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ac0 - U+18adf */
136.3202 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ae0 - U+18aff */
136.3203 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b00 - U+18b1f */
136.3204 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b20 - U+18b3f */
136.3205 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b40 - U+18b5f */
136.3206 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b60 - U+18b7f */
136.3207 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b80 - U+18b9f */
136.3208 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ba0 - U+18bbf */
136.3209 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18bc0 - U+18bdf */
136.3210 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18be0 - U+18bff */
136.3211 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c00 - U+18c1f */
136.3212 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c20 - U+18c3f */
136.3213 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c40 - U+18c5f */
136.3214 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c60 - U+18c7f */
136.3215 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c80 - U+18c9f */
136.3216 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ca0 - U+18cbf */
136.3217 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18cc0 - U+18cdf */
136.3218 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ce0 - U+18cff */
136.3219 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d00 - U+18d1f */
136.3220 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d20 - U+18d3f */
136.3221 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d40 - U+18d5f */
136.3222 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d60 - U+18d7f */
136.3223 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d80 - U+18d9f */
136.3224 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18da0 - U+18dbf */
136.3225 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18dc0 - U+18ddf */
136.3226 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18de0 - U+18dff */
136.3227 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e00 - U+18e1f */
136.3228 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e20 - U+18e3f */
136.3229 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e40 - U+18e5f */
136.3230 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e60 - U+18e7f */
136.3231 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e80 - U+18e9f */
136.3232 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ea0 - U+18ebf */
136.3233 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ec0 - U+18edf */
136.3234 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ee0 - U+18eff */
136.3235 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f00 - U+18f1f */
136.3236 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f20 - U+18f3f */
136.3237 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f40 - U+18f5f */
136.3238 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f60 - U+18f7f */
136.3239 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f80 - U+18f9f */
136.3240 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18fa0 - U+18fbf */
136.3241 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18fc0 - U+18fdf */
136.3242 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18fe0 - U+18fff */
136.3243 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19000 - U+1901f */
136.3244 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19020 - U+1903f */
136.3245 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19040 - U+1905f */
136.3246 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19060 - U+1907f */
136.3247 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19080 - U+1909f */
136.3248 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+190a0 - U+190bf */
136.3249 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+190c0 - U+190df */
136.3250 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+190e0 - U+190ff */
136.3251 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19100 - U+1911f */
136.3252 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19120 - U+1913f */
136.3253 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19140 - U+1915f */
136.3254 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19160 - U+1917f */
136.3255 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19180 - U+1919f */
136.3256 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+191a0 - U+191bf */
136.3257 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+191c0 - U+191df */
136.3258 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+191e0 - U+191ff */
136.3259 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19200 - U+1921f */
136.3260 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19220 - U+1923f */
136.3261 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19240 - U+1925f */
136.3262 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19260 - U+1927f */
136.3263 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19280 - U+1929f */
136.3264 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+192a0 - U+192bf */
136.3265 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+192c0 - U+192df */
136.3266 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+192e0 - U+192ff */
136.3267 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19300 - U+1931f */
136.3268 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19320 - U+1933f */
136.3269 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19340 - U+1935f */
136.3270 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19360 - U+1937f */
136.3271 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19380 - U+1939f */
136.3272 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+193a0 - U+193bf */
136.3273 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+193c0 - U+193df */
136.3274 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+193e0 - U+193ff */
136.3275 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19400 - U+1941f */
136.3276 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19420 - U+1943f */
136.3277 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19440 - U+1945f */
136.3278 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19460 - U+1947f */
136.3279 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19480 - U+1949f */
136.3280 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+194a0 - U+194bf */
136.3281 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+194c0 - U+194df */
136.3282 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+194e0 - U+194ff */
136.3283 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19500 - U+1951f */
136.3284 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19520 - U+1953f */
136.3285 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19540 - U+1955f */
136.3286 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19560 - U+1957f */
136.3287 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19580 - U+1959f */
136.3288 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+195a0 - U+195bf */
136.3289 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+195c0 - U+195df */
136.3290 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+195e0 - U+195ff */
136.3291 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19600 - U+1961f */
136.3292 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19620 - U+1963f */
136.3293 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19640 - U+1965f */
136.3294 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19660 - U+1967f */
136.3295 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19680 - U+1969f */
136.3296 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+196a0 - U+196bf */
136.3297 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+196c0 - U+196df */
136.3298 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+196e0 - U+196ff */
136.3299 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19700 - U+1971f */
136.3300 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19720 - U+1973f */
136.3301 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19740 - U+1975f */
136.3302 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19760 - U+1977f */
136.3303 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19780 - U+1979f */
136.3304 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+197a0 - U+197bf */
136.3305 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+197c0 - U+197df */
136.3306 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+197e0 - U+197ff */
136.3307 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19800 - U+1981f */
136.3308 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19820 - U+1983f */
136.3309 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19840 - U+1985f */
136.3310 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19860 - U+1987f */
136.3311 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19880 - U+1989f */
136.3312 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+198a0 - U+198bf */
136.3313 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+198c0 - U+198df */
136.3314 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+198e0 - U+198ff */
136.3315 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19900 - U+1991f */
136.3316 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19920 - U+1993f */
136.3317 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19940 - U+1995f */
136.3318 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19960 - U+1997f */
136.3319 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19980 - U+1999f */
136.3320 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+199a0 - U+199bf */
136.3321 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+199c0 - U+199df */
136.3322 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+199e0 - U+199ff */
136.3323 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a00 - U+19a1f */
136.3324 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a20 - U+19a3f */
136.3325 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a40 - U+19a5f */
136.3326 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a60 - U+19a7f */
136.3327 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a80 - U+19a9f */
136.3328 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19aa0 - U+19abf */
136.3329 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ac0 - U+19adf */
136.3330 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ae0 - U+19aff */
136.3331 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b00 - U+19b1f */
136.3332 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b20 - U+19b3f */
136.3333 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b40 - U+19b5f */
136.3334 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b60 - U+19b7f */
136.3335 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b80 - U+19b9f */
136.3336 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ba0 - U+19bbf */
136.3337 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19bc0 - U+19bdf */
136.3338 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19be0 - U+19bff */
136.3339 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c00 - U+19c1f */
136.3340 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c20 - U+19c3f */
136.3341 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c40 - U+19c5f */
136.3342 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c60 - U+19c7f */
136.3343 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c80 - U+19c9f */
136.3344 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ca0 - U+19cbf */
136.3345 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19cc0 - U+19cdf */
136.3346 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ce0 - U+19cff */
136.3347 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d00 - U+19d1f */
136.3348 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d20 - U+19d3f */
136.3349 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d40 - U+19d5f */
136.3350 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d60 - U+19d7f */
136.3351 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d80 - U+19d9f */
136.3352 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19da0 - U+19dbf */
136.3353 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19dc0 - U+19ddf */
136.3354 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19de0 - U+19dff */
136.3355 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e00 - U+19e1f */
136.3356 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e20 - U+19e3f */
136.3357 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e40 - U+19e5f */
136.3358 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e60 - U+19e7f */
136.3359 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e80 - U+19e9f */
136.3360 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ea0 - U+19ebf */
136.3361 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ec0 - U+19edf */
136.3362 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ee0 - U+19eff */
136.3363 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f00 - U+19f1f */
136.3364 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f20 - U+19f3f */
136.3365 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f40 - U+19f5f */
136.3366 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f60 - U+19f7f */
136.3367 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f80 - U+19f9f */
136.3368 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19fa0 - U+19fbf */
136.3369 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19fc0 - U+19fdf */
136.3370 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19fe0 - U+19fff */
136.3371 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a000 - U+1a01f */
136.3372 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a020 - U+1a03f */
136.3373 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a040 - U+1a05f */
136.3374 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a060 - U+1a07f */
136.3375 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a080 - U+1a09f */
136.3376 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a0a0 - U+1a0bf */
136.3377 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a0c0 - U+1a0df */
136.3378 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a0e0 - U+1a0ff */
136.3379 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a100 - U+1a11f */
136.3380 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a120 - U+1a13f */
136.3381 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a140 - U+1a15f */
136.3382 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a160 - U+1a17f */
136.3383 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a180 - U+1a19f */
136.3384 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a1a0 - U+1a1bf */
136.3385 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a1c0 - U+1a1df */
136.3386 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a1e0 - U+1a1ff */
136.3387 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a200 - U+1a21f */
136.3388 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a220 - U+1a23f */
136.3389 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a240 - U+1a25f */
136.3390 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a260 - U+1a27f */
136.3391 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a280 - U+1a29f */
136.3392 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a2a0 - U+1a2bf */
136.3393 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a2c0 - U+1a2df */
136.3394 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a2e0 - U+1a2ff */
136.3395 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a300 - U+1a31f */
136.3396 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a320 - U+1a33f */
136.3397 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a340 - U+1a35f */
136.3398 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a360 - U+1a37f */
136.3399 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a380 - U+1a39f */
136.3400 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a3a0 - U+1a3bf */
136.3401 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a3c0 - U+1a3df */
136.3402 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a3e0 - U+1a3ff */
136.3403 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a400 - U+1a41f */
136.3404 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a420 - U+1a43f */
136.3405 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a440 - U+1a45f */
136.3406 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a460 - U+1a47f */
136.3407 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a480 - U+1a49f */
136.3408 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a4a0 - U+1a4bf */
136.3409 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a4c0 - U+1a4df */
136.3410 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a4e0 - U+1a4ff */
136.3411 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a500 - U+1a51f */
136.3412 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a520 - U+1a53f */
136.3413 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a540 - U+1a55f */
136.3414 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a560 - U+1a57f */
136.3415 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a580 - U+1a59f */
136.3416 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a5a0 - U+1a5bf */
136.3417 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a5c0 - U+1a5df */
136.3418 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a5e0 - U+1a5ff */
136.3419 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a600 - U+1a61f */
136.3420 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a620 - U+1a63f */
136.3421 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a640 - U+1a65f */
136.3422 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a660 - U+1a67f */
136.3423 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a680 - U+1a69f */
136.3424 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a6a0 - U+1a6bf */
136.3425 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a6c0 - U+1a6df */
136.3426 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a6e0 - U+1a6ff */
136.3427 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a700 - U+1a71f */
136.3428 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a720 - U+1a73f */
136.3429 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a740 - U+1a75f */
136.3430 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a760 - U+1a77f */
136.3431 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a780 - U+1a79f */
136.3432 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a7a0 - U+1a7bf */
136.3433 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a7c0 - U+1a7df */
136.3434 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a7e0 - U+1a7ff */
136.3435 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a800 - U+1a81f */
136.3436 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a820 - U+1a83f */
136.3437 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a840 - U+1a85f */
136.3438 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a860 - U+1a87f */
136.3439 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a880 - U+1a89f */
136.3440 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a8a0 - U+1a8bf */
136.3441 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a8c0 - U+1a8df */
136.3442 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a8e0 - U+1a8ff */
136.3443 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a900 - U+1a91f */
136.3444 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a920 - U+1a93f */
136.3445 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a940 - U+1a95f */
136.3446 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a960 - U+1a97f */
136.3447 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a980 - U+1a99f */
136.3448 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a9a0 - U+1a9bf */
136.3449 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a9c0 - U+1a9df */
136.3450 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a9e0 - U+1a9ff */
136.3451 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa00 - U+1aa1f */
136.3452 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa20 - U+1aa3f */
136.3453 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa40 - U+1aa5f */
136.3454 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa60 - U+1aa7f */
136.3455 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa80 - U+1aa9f */
136.3456 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aaa0 - U+1aabf */
136.3457 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aac0 - U+1aadf */
136.3458 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aae0 - U+1aaff */
136.3459 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab00 - U+1ab1f */
136.3460 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab20 - U+1ab3f */
136.3461 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab40 - U+1ab5f */
136.3462 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab60 - U+1ab7f */
136.3463 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab80 - U+1ab9f */
136.3464 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aba0 - U+1abbf */
136.3465 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1abc0 - U+1abdf */
136.3466 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1abe0 - U+1abff */
136.3467 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac00 - U+1ac1f */
136.3468 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac20 - U+1ac3f */
136.3469 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac40 - U+1ac5f */
136.3470 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac60 - U+1ac7f */
136.3471 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac80 - U+1ac9f */
136.3472 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aca0 - U+1acbf */
136.3473 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1acc0 - U+1acdf */
136.3474 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ace0 - U+1acff */
136.3475 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad00 - U+1ad1f */
136.3476 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad20 - U+1ad3f */
136.3477 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad40 - U+1ad5f */
136.3478 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad60 - U+1ad7f */
136.3479 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad80 - U+1ad9f */
136.3480 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ada0 - U+1adbf */
136.3481 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1adc0 - U+1addf */
136.3482 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ade0 - U+1adff */
136.3483 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae00 - U+1ae1f */
136.3484 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae20 - U+1ae3f */
136.3485 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae40 - U+1ae5f */
136.3486 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae60 - U+1ae7f */
136.3487 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae80 - U+1ae9f */
136.3488 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aea0 - U+1aebf */
136.3489 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aec0 - U+1aedf */
136.3490 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aee0 - U+1aeff */
136.3491 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af00 - U+1af1f */
136.3492 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af20 - U+1af3f */
136.3493 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af40 - U+1af5f */
136.3494 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af60 - U+1af7f */
136.3495 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af80 - U+1af9f */
136.3496 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1afa0 - U+1afbf */
136.3497 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1afc0 - U+1afdf */
136.3498 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1afe0 - U+1afff */
136.3499 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b000 - U+1b01f */
136.3500 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b020 - U+1b03f */
136.3501 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b040 - U+1b05f */
136.3502 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b060 - U+1b07f */
136.3503 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b080 - U+1b09f */
136.3504 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b0a0 - U+1b0bf */
136.3505 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b0c0 - U+1b0df */
136.3506 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b0e0 - U+1b0ff */
136.3507 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b100 - U+1b11f */
136.3508 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b120 - U+1b13f */
136.3509 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b140 - U+1b15f */
136.3510 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b160 - U+1b17f */
136.3511 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b180 - U+1b19f */
136.3512 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b1a0 - U+1b1bf */
136.3513 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b1c0 - U+1b1df */
136.3514 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b1e0 - U+1b1ff */
136.3515 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b200 - U+1b21f */
136.3516 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b220 - U+1b23f */
136.3517 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b240 - U+1b25f */
136.3518 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b260 - U+1b27f */
136.3519 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b280 - U+1b29f */
136.3520 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b2a0 - U+1b2bf */
136.3521 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b2c0 - U+1b2df */
136.3522 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b2e0 - U+1b2ff */
136.3523 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b300 - U+1b31f */
136.3524 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b320 - U+1b33f */
136.3525 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b340 - U+1b35f */
136.3526 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b360 - U+1b37f */
136.3527 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b380 - U+1b39f */
136.3528 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b3a0 - U+1b3bf */
136.3529 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b3c0 - U+1b3df */
136.3530 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b3e0 - U+1b3ff */
136.3531 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b400 - U+1b41f */
136.3532 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b420 - U+1b43f */
136.3533 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b440 - U+1b45f */
136.3534 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b460 - U+1b47f */
136.3535 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b480 - U+1b49f */
136.3536 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b4a0 - U+1b4bf */
136.3537 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b4c0 - U+1b4df */
136.3538 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b4e0 - U+1b4ff */
136.3539 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b500 - U+1b51f */
136.3540 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b520 - U+1b53f */
136.3541 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b540 - U+1b55f */
136.3542 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b560 - U+1b57f */
136.3543 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b580 - U+1b59f */
136.3544 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b5a0 - U+1b5bf */
136.3545 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b5c0 - U+1b5df */
136.3546 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b5e0 - U+1b5ff */
136.3547 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b600 - U+1b61f */
136.3548 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b620 - U+1b63f */
136.3549 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b640 - U+1b65f */
136.3550 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b660 - U+1b67f */
136.3551 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b680 - U+1b69f */
136.3552 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b6a0 - U+1b6bf */
136.3553 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b6c0 - U+1b6df */
136.3554 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b6e0 - U+1b6ff */
136.3555 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b700 - U+1b71f */
136.3556 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b720 - U+1b73f */
136.3557 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b740 - U+1b75f */
136.3558 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b760 - U+1b77f */
136.3559 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b780 - U+1b79f */
136.3560 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b7a0 - U+1b7bf */
136.3561 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b7c0 - U+1b7df */
136.3562 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b7e0 - U+1b7ff */
136.3563 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b800 - U+1b81f */
136.3564 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b820 - U+1b83f */
136.3565 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b840 - U+1b85f */
136.3566 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b860 - U+1b87f */
136.3567 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b880 - U+1b89f */
136.3568 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b8a0 - U+1b8bf */
136.3569 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b8c0 - U+1b8df */
136.3570 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b8e0 - U+1b8ff */
136.3571 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b900 - U+1b91f */
136.3572 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b920 - U+1b93f */
136.3573 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b940 - U+1b95f */
136.3574 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b960 - U+1b97f */
136.3575 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b980 - U+1b99f */
136.3576 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b9a0 - U+1b9bf */
136.3577 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b9c0 - U+1b9df */
136.3578 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b9e0 - U+1b9ff */
136.3579 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba00 - U+1ba1f */
136.3580 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba20 - U+1ba3f */
136.3581 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba40 - U+1ba5f */
136.3582 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba60 - U+1ba7f */
136.3583 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba80 - U+1ba9f */
136.3584 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1baa0 - U+1babf */
136.3585 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bac0 - U+1badf */
136.3586 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bae0 - U+1baff */
136.3587 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb00 - U+1bb1f */
136.3588 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb20 - U+1bb3f */
136.3589 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb40 - U+1bb5f */
136.3590 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb60 - U+1bb7f */
136.3591 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb80 - U+1bb9f */
136.3592 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bba0 - U+1bbbf */
136.3593 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bbc0 - U+1bbdf */
136.3594 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bbe0 - U+1bbff */
136.3595 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc00 - U+1bc1f */
136.3596 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc20 - U+1bc3f */
136.3597 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc40 - U+1bc5f */
136.3598 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc60 - U+1bc7f */
136.3599 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc80 - U+1bc9f */
136.3600 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bca0 - U+1bcbf */
136.3601 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bcc0 - U+1bcdf */
136.3602 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bce0 - U+1bcff */
136.3603 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd00 - U+1bd1f */
136.3604 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd20 - U+1bd3f */
136.3605 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd40 - U+1bd5f */
136.3606 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd60 - U+1bd7f */
136.3607 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd80 - U+1bd9f */
136.3608 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bda0 - U+1bdbf */
136.3609 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bdc0 - U+1bddf */
136.3610 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bde0 - U+1bdff */
136.3611 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be00 - U+1be1f */
136.3612 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be20 - U+1be3f */
136.3613 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be40 - U+1be5f */
136.3614 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be60 - U+1be7f */
136.3615 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be80 - U+1be9f */
136.3616 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bea0 - U+1bebf */
136.3617 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bec0 - U+1bedf */
136.3618 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bee0 - U+1beff */
136.3619 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf00 - U+1bf1f */
136.3620 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf20 - U+1bf3f */
136.3621 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf40 - U+1bf5f */
136.3622 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf60 - U+1bf7f */
136.3623 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf80 - U+1bf9f */
136.3624 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bfa0 - U+1bfbf */
136.3625 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bfc0 - U+1bfdf */
136.3626 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bfe0 - U+1bfff */
136.3627 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c000 - U+1c01f */
136.3628 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c020 - U+1c03f */
136.3629 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c040 - U+1c05f */
136.3630 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c060 - U+1c07f */
136.3631 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c080 - U+1c09f */
136.3632 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c0a0 - U+1c0bf */
136.3633 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c0c0 - U+1c0df */
136.3634 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c0e0 - U+1c0ff */
136.3635 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c100 - U+1c11f */
136.3636 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c120 - U+1c13f */
136.3637 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c140 - U+1c15f */
136.3638 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c160 - U+1c17f */
136.3639 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c180 - U+1c19f */
136.3640 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c1a0 - U+1c1bf */
136.3641 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c1c0 - U+1c1df */
136.3642 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c1e0 - U+1c1ff */
136.3643 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c200 - U+1c21f */
136.3644 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c220 - U+1c23f */
136.3645 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c240 - U+1c25f */
136.3646 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c260 - U+1c27f */
136.3647 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c280 - U+1c29f */
136.3648 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c2a0 - U+1c2bf */
136.3649 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c2c0 - U+1c2df */
136.3650 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c2e0 - U+1c2ff */
136.3651 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c300 - U+1c31f */
136.3652 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c320 - U+1c33f */
136.3653 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c340 - U+1c35f */
136.3654 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c360 - U+1c37f */
136.3655 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c380 - U+1c39f */
136.3656 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c3a0 - U+1c3bf */
136.3657 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c3c0 - U+1c3df */
136.3658 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c3e0 - U+1c3ff */
136.3659 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c400 - U+1c41f */
136.3660 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c420 - U+1c43f */
136.3661 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c440 - U+1c45f */
136.3662 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c460 - U+1c47f */
136.3663 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c480 - U+1c49f */
136.3664 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c4a0 - U+1c4bf */
136.3665 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c4c0 - U+1c4df */
136.3666 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c4e0 - U+1c4ff */
136.3667 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c500 - U+1c51f */
136.3668 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c520 - U+1c53f */
136.3669 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c540 - U+1c55f */
136.3670 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c560 - U+1c57f */
136.3671 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c580 - U+1c59f */
136.3672 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c5a0 - U+1c5bf */
136.3673 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c5c0 - U+1c5df */
136.3674 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c5e0 - U+1c5ff */
136.3675 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c600 - U+1c61f */
136.3676 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c620 - U+1c63f */
136.3677 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c640 - U+1c65f */
136.3678 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c660 - U+1c67f */
136.3679 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c680 - U+1c69f */
136.3680 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c6a0 - U+1c6bf */
136.3681 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c6c0 - U+1c6df */
136.3682 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c6e0 - U+1c6ff */
136.3683 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c700 - U+1c71f */
136.3684 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c720 - U+1c73f */
136.3685 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c740 - U+1c75f */
136.3686 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c760 - U+1c77f */
136.3687 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c780 - U+1c79f */
136.3688 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c7a0 - U+1c7bf */
136.3689 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c7c0 - U+1c7df */
136.3690 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c7e0 - U+1c7ff */
136.3691 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c800 - U+1c81f */
136.3692 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c820 - U+1c83f */
136.3693 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c840 - U+1c85f */
136.3694 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c860 - U+1c87f */
136.3695 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c880 - U+1c89f */
136.3696 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c8a0 - U+1c8bf */
136.3697 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c8c0 - U+1c8df */
136.3698 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c8e0 - U+1c8ff */
136.3699 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c900 - U+1c91f */
136.3700 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c920 - U+1c93f */
136.3701 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c940 - U+1c95f */
136.3702 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c960 - U+1c97f */
136.3703 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c980 - U+1c99f */
136.3704 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c9a0 - U+1c9bf */
136.3705 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c9c0 - U+1c9df */
136.3706 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c9e0 - U+1c9ff */
136.3707 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca00 - U+1ca1f */
136.3708 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca20 - U+1ca3f */
136.3709 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca40 - U+1ca5f */
136.3710 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca60 - U+1ca7f */
136.3711 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca80 - U+1ca9f */
136.3712 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1caa0 - U+1cabf */
136.3713 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cac0 - U+1cadf */
136.3714 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cae0 - U+1caff */
136.3715 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb00 - U+1cb1f */
136.3716 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb20 - U+1cb3f */
136.3717 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb40 - U+1cb5f */
136.3718 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb60 - U+1cb7f */
136.3719 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb80 - U+1cb9f */
136.3720 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cba0 - U+1cbbf */
136.3721 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cbc0 - U+1cbdf */
136.3722 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cbe0 - U+1cbff */
136.3723 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc00 - U+1cc1f */
136.3724 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc20 - U+1cc3f */
136.3725 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc40 - U+1cc5f */
136.3726 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc60 - U+1cc7f */
136.3727 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc80 - U+1cc9f */
136.3728 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cca0 - U+1ccbf */
136.3729 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ccc0 - U+1ccdf */
136.3730 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cce0 - U+1ccff */
136.3731 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd00 - U+1cd1f */
136.3732 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd20 - U+1cd3f */
136.3733 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd40 - U+1cd5f */
136.3734 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd60 - U+1cd7f */
136.3735 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd80 - U+1cd9f */
136.3736 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cda0 - U+1cdbf */
136.3737 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cdc0 - U+1cddf */
136.3738 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cde0 - U+1cdff */
136.3739 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce00 - U+1ce1f */
136.3740 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce20 - U+1ce3f */
136.3741 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce40 - U+1ce5f */
136.3742 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce60 - U+1ce7f */
136.3743 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce80 - U+1ce9f */
136.3744 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cea0 - U+1cebf */
136.3745 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cec0 - U+1cedf */
136.3746 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cee0 - U+1ceff */
136.3747 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf00 - U+1cf1f */
136.3748 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf20 - U+1cf3f */
136.3749 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf40 - U+1cf5f */
136.3750 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf60 - U+1cf7f */
136.3751 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf80 - U+1cf9f */
136.3752 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cfa0 - U+1cfbf */
136.3753 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cfc0 - U+1cfdf */
136.3754 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cfe0 - U+1cfff */
136.3755 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d000 - U+1d01f */
136.3756 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d020 - U+1d03f */
136.3757 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d040 - U+1d05f */
136.3758 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d060 - U+1d07f */
136.3759 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d080 - U+1d09f */
136.3760 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d0a0 - U+1d0bf */
136.3761 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d0c0 - U+1d0df */
136.3762 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d0e0 - U+1d0ff */
136.3763 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d100 - U+1d11f */
136.3764 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d120 - U+1d13f */
136.3765 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d140 - U+1d15f */
136.3766 +  0xff,0xfc,0x0f,0xff,0xfc,0x00,0x00,0x00,	/* U+1d160 - U+1d17f */
136.3767 +  0x03,0xc0,0x00,0xff,0xff,0xff,0xff,0xff,	/* U+1d180 - U+1d19f */
136.3768 +  0xff,0xff,0xf0,0x0f,0xff,0xff,0xff,0xff,	/* U+1d1a0 - U+1d1bf */
136.3769 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d1c0 - U+1d1df */
136.3770 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d1e0 - U+1d1ff */
136.3771 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d200 - U+1d21f */
136.3772 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d220 - U+1d23f */
136.3773 +  0xf0,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d240 - U+1d25f */
136.3774 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d260 - U+1d27f */
136.3775 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d280 - U+1d29f */
136.3776 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d2a0 - U+1d2bf */
136.3777 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d2c0 - U+1d2df */
136.3778 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d2e0 - U+1d2ff */
136.3779 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d300 - U+1d31f */
136.3780 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d320 - U+1d33f */
136.3781 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d340 - U+1d35f */
136.3782 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d360 - U+1d37f */
136.3783 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d380 - U+1d39f */
136.3784 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d3a0 - U+1d3bf */
136.3785 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d3c0 - U+1d3df */
136.3786 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d3e0 - U+1d3ff */
136.3787 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d400 - U+1d41f */
136.3788 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d420 - U+1d43f */
136.3789 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d440 - U+1d45f */
136.3790 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d460 - U+1d47f */
136.3791 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d480 - U+1d49f */
136.3792 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d4a0 - U+1d4bf */
136.3793 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d4c0 - U+1d4df */
136.3794 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d4e0 - U+1d4ff */
136.3795 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d500 - U+1d51f */
136.3796 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d520 - U+1d53f */
136.3797 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d540 - U+1d55f */
136.3798 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d560 - U+1d57f */
136.3799 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d580 - U+1d59f */
136.3800 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d5a0 - U+1d5bf */
136.3801 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d5c0 - U+1d5df */
136.3802 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d5e0 - U+1d5ff */
136.3803 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d600 - U+1d61f */
136.3804 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d620 - U+1d63f */
136.3805 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d640 - U+1d65f */
136.3806 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d660 - U+1d67f */
136.3807 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d680 - U+1d69f */
136.3808 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d6a0 - U+1d6bf */
136.3809 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d6c0 - U+1d6df */
136.3810 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d6e0 - U+1d6ff */
136.3811 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d700 - U+1d71f */
136.3812 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d720 - U+1d73f */
136.3813 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d740 - U+1d75f */
136.3814 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d760 - U+1d77f */
136.3815 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d780 - U+1d79f */
136.3816 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d7a0 - U+1d7bf */
136.3817 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d7c0 - U+1d7df */
136.3818 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d7e0 - U+1d7ff */
136.3819 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d800 - U+1d81f */
136.3820 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d820 - U+1d83f */
136.3821 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d840 - U+1d85f */
136.3822 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d860 - U+1d87f */
136.3823 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d880 - U+1d89f */
136.3824 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d8a0 - U+1d8bf */
136.3825 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d8c0 - U+1d8df */
136.3826 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d8e0 - U+1d8ff */
136.3827 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d900 - U+1d91f */
136.3828 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d920 - U+1d93f */
136.3829 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d940 - U+1d95f */
136.3830 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d960 - U+1d97f */
136.3831 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d980 - U+1d99f */
136.3832 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d9a0 - U+1d9bf */
136.3833 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d9c0 - U+1d9df */
136.3834 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d9e0 - U+1d9ff */
136.3835 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da00 - U+1da1f */
136.3836 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da20 - U+1da3f */
136.3837 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da40 - U+1da5f */
136.3838 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da60 - U+1da7f */
136.3839 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da80 - U+1da9f */
136.3840 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1daa0 - U+1dabf */
136.3841 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dac0 - U+1dadf */
136.3842 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dae0 - U+1daff */
136.3843 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db00 - U+1db1f */
136.3844 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db20 - U+1db3f */
136.3845 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db40 - U+1db5f */
136.3846 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db60 - U+1db7f */
136.3847 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db80 - U+1db9f */
136.3848 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dba0 - U+1dbbf */
136.3849 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dbc0 - U+1dbdf */
136.3850 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dbe0 - U+1dbff */
136.3851 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc00 - U+1dc1f */
136.3852 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc20 - U+1dc3f */
136.3853 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc40 - U+1dc5f */
136.3854 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc60 - U+1dc7f */
136.3855 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc80 - U+1dc9f */
136.3856 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dca0 - U+1dcbf */
136.3857 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dcc0 - U+1dcdf */
136.3858 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dce0 - U+1dcff */
136.3859 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd00 - U+1dd1f */
136.3860 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd20 - U+1dd3f */
136.3861 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd40 - U+1dd5f */
136.3862 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd60 - U+1dd7f */
136.3863 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd80 - U+1dd9f */
136.3864 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dda0 - U+1ddbf */
136.3865 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ddc0 - U+1dddf */
136.3866 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dde0 - U+1ddff */
136.3867 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de00 - U+1de1f */
136.3868 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de20 - U+1de3f */
136.3869 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de40 - U+1de5f */
136.3870 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de60 - U+1de7f */
136.3871 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de80 - U+1de9f */
136.3872 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dea0 - U+1debf */
136.3873 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dec0 - U+1dedf */
136.3874 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dee0 - U+1deff */
136.3875 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df00 - U+1df1f */
136.3876 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df20 - U+1df3f */
136.3877 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df40 - U+1df5f */
136.3878 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df60 - U+1df7f */
136.3879 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df80 - U+1df9f */
136.3880 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dfa0 - U+1dfbf */
136.3881 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dfc0 - U+1dfdf */
136.3882 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dfe0 - U+1dfff */
136.3883 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e000 - U+1e01f */
136.3884 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e020 - U+1e03f */
136.3885 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e040 - U+1e05f */
136.3886 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e060 - U+1e07f */
136.3887 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e080 - U+1e09f */
136.3888 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e0a0 - U+1e0bf */
136.3889 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e0c0 - U+1e0df */
136.3890 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e0e0 - U+1e0ff */
136.3891 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e100 - U+1e11f */
136.3892 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e120 - U+1e13f */
136.3893 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e140 - U+1e15f */
136.3894 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e160 - U+1e17f */
136.3895 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e180 - U+1e19f */
136.3896 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e1a0 - U+1e1bf */
136.3897 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e1c0 - U+1e1df */
136.3898 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e1e0 - U+1e1ff */
136.3899 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e200 - U+1e21f */
136.3900 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e220 - U+1e23f */
136.3901 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e240 - U+1e25f */
136.3902 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e260 - U+1e27f */
136.3903 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e280 - U+1e29f */
136.3904 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e2a0 - U+1e2bf */
136.3905 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e2c0 - U+1e2df */
136.3906 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e2e0 - U+1e2ff */
136.3907 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e300 - U+1e31f */
136.3908 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e320 - U+1e33f */
136.3909 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e340 - U+1e35f */
136.3910 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e360 - U+1e37f */
136.3911 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e380 - U+1e39f */
136.3912 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e3a0 - U+1e3bf */
136.3913 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e3c0 - U+1e3df */
136.3914 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e3e0 - U+1e3ff */
136.3915 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e400 - U+1e41f */
136.3916 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e420 - U+1e43f */
136.3917 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e440 - U+1e45f */
136.3918 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e460 - U+1e47f */
136.3919 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e480 - U+1e49f */
136.3920 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e4a0 - U+1e4bf */
136.3921 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e4c0 - U+1e4df */
136.3922 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e4e0 - U+1e4ff */
136.3923 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e500 - U+1e51f */
136.3924 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e520 - U+1e53f */
136.3925 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e540 - U+1e55f */
136.3926 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e560 - U+1e57f */
136.3927 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e580 - U+1e59f */
136.3928 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e5a0 - U+1e5bf */
136.3929 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e5c0 - U+1e5df */
136.3930 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e5e0 - U+1e5ff */
136.3931 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e600 - U+1e61f */
136.3932 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e620 - U+1e63f */
136.3933 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e640 - U+1e65f */
136.3934 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e660 - U+1e67f */
136.3935 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e680 - U+1e69f */
136.3936 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e6a0 - U+1e6bf */
136.3937 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e6c0 - U+1e6df */
136.3938 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e6e0 - U+1e6ff */
136.3939 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e700 - U+1e71f */
136.3940 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e720 - U+1e73f */
136.3941 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e740 - U+1e75f */
136.3942 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e760 - U+1e77f */
136.3943 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e780 - U+1e79f */
136.3944 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e7a0 - U+1e7bf */
136.3945 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e7c0 - U+1e7df */
136.3946 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e7e0 - U+1e7ff */
136.3947 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e800 - U+1e81f */
136.3948 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e820 - U+1e83f */
136.3949 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e840 - U+1e85f */
136.3950 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e860 - U+1e87f */
136.3951 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e880 - U+1e89f */
136.3952 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e8a0 - U+1e8bf */
136.3953 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e8c0 - U+1e8df */
136.3954 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e8e0 - U+1e8ff */
136.3955 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e900 - U+1e91f */
136.3956 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e920 - U+1e93f */
136.3957 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e940 - U+1e95f */
136.3958 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e960 - U+1e97f */
136.3959 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e980 - U+1e99f */
136.3960 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e9a0 - U+1e9bf */
136.3961 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e9c0 - U+1e9df */
136.3962 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e9e0 - U+1e9ff */
136.3963 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea00 - U+1ea1f */
136.3964 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea20 - U+1ea3f */
136.3965 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea40 - U+1ea5f */
136.3966 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea60 - U+1ea7f */
136.3967 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea80 - U+1ea9f */
136.3968 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eaa0 - U+1eabf */
136.3969 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eac0 - U+1eadf */
136.3970 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eae0 - U+1eaff */
136.3971 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb00 - U+1eb1f */
136.3972 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb20 - U+1eb3f */
136.3973 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb40 - U+1eb5f */
136.3974 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb60 - U+1eb7f */
136.3975 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb80 - U+1eb9f */
136.3976 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eba0 - U+1ebbf */
136.3977 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ebc0 - U+1ebdf */
136.3978 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ebe0 - U+1ebff */
136.3979 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec00 - U+1ec1f */
136.3980 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec20 - U+1ec3f */
136.3981 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec40 - U+1ec5f */
136.3982 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec60 - U+1ec7f */
136.3983 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec80 - U+1ec9f */
136.3984 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eca0 - U+1ecbf */
136.3985 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ecc0 - U+1ecdf */
136.3986 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ece0 - U+1ecff */
136.3987 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed00 - U+1ed1f */
136.3988 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed20 - U+1ed3f */
136.3989 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed40 - U+1ed5f */
136.3990 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed60 - U+1ed7f */
136.3991 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed80 - U+1ed9f */
136.3992 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eda0 - U+1edbf */
136.3993 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1edc0 - U+1eddf */
136.3994 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ede0 - U+1edff */
136.3995 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee00 - U+1ee1f */
136.3996 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee20 - U+1ee3f */
136.3997 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee40 - U+1ee5f */
136.3998 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee60 - U+1ee7f */
136.3999 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee80 - U+1ee9f */
136.4000 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eea0 - U+1eebf */
136.4001 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eec0 - U+1eedf */
136.4002 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eee0 - U+1eeff */
136.4003 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef00 - U+1ef1f */
136.4004 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef20 - U+1ef3f */
136.4005 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef40 - U+1ef5f */
136.4006 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef60 - U+1ef7f */
136.4007 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef80 - U+1ef9f */
136.4008 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1efa0 - U+1efbf */
136.4009 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1efc0 - U+1efdf */
136.4010 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1efe0 - U+1efff */
136.4011 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f000 - U+1f01f */
136.4012 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f020 - U+1f03f */
136.4013 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f040 - U+1f05f */
136.4014 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f060 - U+1f07f */
136.4015 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f080 - U+1f09f */
136.4016 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f0a0 - U+1f0bf */
136.4017 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f0c0 - U+1f0df */
136.4018 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f0e0 - U+1f0ff */
136.4019 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f100 - U+1f11f */
136.4020 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f120 - U+1f13f */
136.4021 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f140 - U+1f15f */
136.4022 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f160 - U+1f17f */
136.4023 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f180 - U+1f19f */
136.4024 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f1a0 - U+1f1bf */
136.4025 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f1c0 - U+1f1df */
136.4026 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f1e0 - U+1f1ff */
136.4027 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f200 - U+1f21f */
136.4028 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f220 - U+1f23f */
136.4029 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f240 - U+1f25f */
136.4030 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f260 - U+1f27f */
136.4031 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f280 - U+1f29f */
136.4032 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f2a0 - U+1f2bf */
136.4033 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f2c0 - U+1f2df */
136.4034 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f2e0 - U+1f2ff */
136.4035 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f300 - U+1f31f */
136.4036 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f320 - U+1f33f */
136.4037 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f340 - U+1f35f */
136.4038 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f360 - U+1f37f */
136.4039 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f380 - U+1f39f */
136.4040 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f3a0 - U+1f3bf */
136.4041 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f3c0 - U+1f3df */
136.4042 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f3e0 - U+1f3ff */
136.4043 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f400 - U+1f41f */
136.4044 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f420 - U+1f43f */
136.4045 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f440 - U+1f45f */
136.4046 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f460 - U+1f47f */
136.4047 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f480 - U+1f49f */
136.4048 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f4a0 - U+1f4bf */
136.4049 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f4c0 - U+1f4df */
136.4050 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f4e0 - U+1f4ff */
136.4051 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f500 - U+1f51f */
136.4052 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f520 - U+1f53f */
136.4053 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f540 - U+1f55f */
136.4054 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f560 - U+1f57f */
136.4055 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f580 - U+1f59f */
136.4056 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f5a0 - U+1f5bf */
136.4057 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f5c0 - U+1f5df */
136.4058 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f5e0 - U+1f5ff */
136.4059 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f600 - U+1f61f */
136.4060 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f620 - U+1f63f */
136.4061 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f640 - U+1f65f */
136.4062 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f660 - U+1f67f */
136.4063 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f680 - U+1f69f */
136.4064 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f6a0 - U+1f6bf */
136.4065 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f6c0 - U+1f6df */
136.4066 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f6e0 - U+1f6ff */
136.4067 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f700 - U+1f71f */
136.4068 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f720 - U+1f73f */
136.4069 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f740 - U+1f75f */
136.4070 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f760 - U+1f77f */
136.4071 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f780 - U+1f79f */
136.4072 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f7a0 - U+1f7bf */
136.4073 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f7c0 - U+1f7df */
136.4074 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f7e0 - U+1f7ff */
136.4075 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f800 - U+1f81f */
136.4076 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f820 - U+1f83f */
136.4077 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f840 - U+1f85f */
136.4078 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f860 - U+1f87f */
136.4079 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f880 - U+1f89f */
136.4080 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f8a0 - U+1f8bf */
136.4081 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f8c0 - U+1f8df */
136.4082 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f8e0 - U+1f8ff */
136.4083 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f900 - U+1f91f */
136.4084 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f920 - U+1f93f */
136.4085 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f940 - U+1f95f */
136.4086 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f960 - U+1f97f */
136.4087 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f980 - U+1f99f */
136.4088 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f9a0 - U+1f9bf */
136.4089 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f9c0 - U+1f9df */
136.4090 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f9e0 - U+1f9ff */
136.4091 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa00 - U+1fa1f */
136.4092 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa20 - U+1fa3f */
136.4093 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa40 - U+1fa5f */
136.4094 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa60 - U+1fa7f */
136.4095 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa80 - U+1fa9f */
136.4096 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1faa0 - U+1fabf */
136.4097 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fac0 - U+1fadf */
136.4098 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fae0 - U+1faff */
136.4099 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb00 - U+1fb1f */
136.4100 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb20 - U+1fb3f */
136.4101 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb40 - U+1fb5f */
136.4102 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb60 - U+1fb7f */
136.4103 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb80 - U+1fb9f */
136.4104 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fba0 - U+1fbbf */
136.4105 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fbc0 - U+1fbdf */
136.4106 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fbe0 - U+1fbff */
136.4107 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc00 - U+1fc1f */
136.4108 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc20 - U+1fc3f */
136.4109 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc40 - U+1fc5f */
136.4110 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc60 - U+1fc7f */
136.4111 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc80 - U+1fc9f */
136.4112 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fca0 - U+1fcbf */
136.4113 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fcc0 - U+1fcdf */
136.4114 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fce0 - U+1fcff */
136.4115 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd00 - U+1fd1f */
136.4116 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd20 - U+1fd3f */
136.4117 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd40 - U+1fd5f */
136.4118 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd60 - U+1fd7f */
136.4119 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd80 - U+1fd9f */
136.4120 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fda0 - U+1fdbf */
136.4121 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fdc0 - U+1fddf */
136.4122 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fde0 - U+1fdff */
136.4123 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe00 - U+1fe1f */
136.4124 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe20 - U+1fe3f */
136.4125 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe40 - U+1fe5f */
136.4126 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe60 - U+1fe7f */
136.4127 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe80 - U+1fe9f */
136.4128 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fea0 - U+1febf */
136.4129 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fec0 - U+1fedf */
136.4130 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fee0 - U+1feff */
136.4131 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff00 - U+1ff1f */
136.4132 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff20 - U+1ff3f */
136.4133 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff40 - U+1ff5f */
136.4134 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff60 - U+1ff7f */
136.4135 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff80 - U+1ff9f */
136.4136 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ffa0 - U+1ffbf */
136.4137 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ffc0 - U+1ffdf */
136.4138 +  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff	/* U+1ffe0 - U+1ffff */
136.4139 +};
   137.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   137.2 +++ b/src/charset/windows.c	Mon Sep 14 15:17:45 2009 +0900
   137.3 @@ -0,0 +1,228 @@
   137.4 +/* ========================================================================
   137.5 + * Copyright 1988-2006 University of Washington
   137.6 + *
   137.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   137.8 + * you may not use this file except in compliance with the License.
   137.9 + * You may obtain a copy of the License at
  137.10 + *
  137.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  137.12 + *
  137.13 + * 
  137.14 + * ========================================================================
  137.15 + */
  137.16 +
  137.17 +/*
  137.18 + * Program:	Windows conversion tables
  137.19 + *
  137.20 + * Author:	Mark Crispin
  137.21 + *		Networks and Distributed Computing
  137.22 + *		Computing & Communications
  137.23 + *		University of Washington
  137.24 + *		Administration Building, AG-44
  137.25 + *		Seattle, WA  98195
  137.26 + *		Internet: MRC@CAC.Washington.EDU
  137.27 + *
  137.28 + * Date:	16 October 2000
  137.29 + * Last Edited:	30 August 2006
  137.30 + */
  137.31 +
  137.32 +				/* Windows Thai */
  137.33 +static const unsigned short windows_874tab[128] = {
  137.34 +  0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON,
  137.35 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  137.36 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
  137.37 +  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
  137.38 +  0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
  137.39 +  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
  137.40 +  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
  137.41 +  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
  137.42 +  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
  137.43 +  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
  137.44 +  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
  137.45 +  0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
  137.46 +  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
  137.47 +  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
  137.48 +  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
  137.49 +  0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
  137.50 +};
  137.51 +
  137.52 +				/* Windows Latin-2 */
  137.53 +static const unsigned short windows_1250tab[128] = {
  137.54 +  0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021,
  137.55 +  UBOGON,0x2030,0x0160,0x2039,0x015a,0x0164,0x017d,0x0179,
  137.56 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
  137.57 +  UBOGON,0x2122,0x0161,0x203a,0x015b,0x0165,0x017e,0x017a,
  137.58 +  0x00a0,0x02c7,0x02d8,0x0141,0x00a4,0x0104,0x00a6,0x00a7,
  137.59 +  0x00a8,0x00a9,0x015e,0x00ab,0x00ac,0x00ad,0x00ae,0x017b,
  137.60 +  0x00b0,0x00b1,0x02db,0x0142,0x00b4,0x00b5,0x00b6,0x00b7,
  137.61 +  0x00b8,0x0105,0x015f,0x00bb,0x013d,0x02dd,0x013e,0x017c,
  137.62 +  0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7,
  137.63 +  0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e,
  137.64 +  0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7,
  137.65 +  0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df,
  137.66 +  0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7,
  137.67 +  0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f,
  137.68 +  0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7,
  137.69 +  0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9
  137.70 +};
  137.71 +
  137.72 +				/* Windows Cyrillic */
  137.73 +static const unsigned short windows_1251tab[128] = {
  137.74 +  0x0402,0x0403,0x201a,0x0453,0x201e,0x2026,0x2020,0x2021,
  137.75 +  0x20ac,0x2030,0x0409,0x2039,0x040a,0x040c,0x040b,0x040f,
  137.76 +  0x0452,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
  137.77 +  UBOGON,0x2122,0x0459,0x203a,0x045a,0x045c,0x045b,0x045f,
  137.78 +  0x00a0,0x040e,0x045e,0x0408,0x00a4,0x0490,0x00a6,0x00a7,
  137.79 +  0x0401,0x00a9,0x0404,0x00ab,0x00ac,0x00ad,0x00ae,0x0407,
  137.80 +  0x00b0,0x00b1,0x0406,0x0456,0x0491,0x00b5,0x00b6,0x00b7,
  137.81 +  0x0451,0x2116,0x0454,0x00bb,0x0458,0x0405,0x0455,0x0457,
  137.82 +  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
  137.83 +  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
  137.84 +  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
  137.85 +  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
  137.86 +  0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
  137.87 +  0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
  137.88 +  0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
  137.89 +  0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f
  137.90 +};
  137.91 +
  137.92 +				/* Windows Latin-1 */
  137.93 +static const unsigned short windows_1252tab[128] = {
  137.94 +  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
  137.95 +  0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,0x017d,UBOGON,
  137.96 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
  137.97 +  0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,0x017e,0x0178,
  137.98 +  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
  137.99 +  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 137.100 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 137.101 +  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
 137.102 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
 137.103 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
 137.104 +  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
 137.105 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
 137.106 +  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
 137.107 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
 137.108 +  0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
 137.109 +  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff
 137.110 +};
 137.111 +
 137.112 +
 137.113 +				/* Windows Greek */
 137.114 +static const unsigned short windows_1253tab[128] = {
 137.115 +  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
 137.116 +  UBOGON,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON,
 137.117 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 137.118 +  UBOGON,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON,
 137.119 +  0x00a0,0x0385,0x0386,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
 137.120 +  0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,0x00ae,0x2015,
 137.121 +  0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x00b5,0x00b6,0x00b7,
 137.122 +  0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f,
 137.123 +  0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
 137.124 +  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
 137.125 +  0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
 137.126 +  0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
 137.127 +  0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
 137.128 +  0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
 137.129 +  0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
 137.130 +  0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON
 137.131 +};
 137.132 +
 137.133 +				/* Windows Turkish */
 137.134 +static const unsigned short windows_1254tab[128] = {
 137.135 +  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
 137.136 +  0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,UBOGON,UBOGON,
 137.137 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 137.138 +  0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,UBOGON,0x0178,
 137.139 +  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
 137.140 +  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 137.141 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 137.142 +  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
 137.143 +  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
 137.144 +  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
 137.145 +  0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
 137.146 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df,
 137.147 +  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
 137.148 +  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
 137.149 +  0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
 137.150 +  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff
 137.151 +};
 137.152 +
 137.153 +				/* Windows Hebrew */
 137.154 +static const unsigned short windows_1255tab[128] = {
 137.155 +  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
 137.156 +  0x02c6,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON,
 137.157 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 137.158 +  0x02dc,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON,
 137.159 +  0x00a0,0x00a1,0x00a2,0x00a3,0x20aa,0x00a5,0x00a6,0x00a7,
 137.160 +  0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 137.161 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 137.162 +  0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
 137.163 +  0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
 137.164 +  0x05b8,0x05b9,UBOGON,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
 137.165 +  0x05c0,0x05c1,0x05c2,0x05c3,0x05f0,0x05f1,0x05f2,0x05f3,
 137.166 +  0x05f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
 137.167 +  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
 137.168 +  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
 137.169 +  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
 137.170 +  0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON
 137.171 +};
 137.172 +
 137.173 +				/* Windows Arabic */
 137.174 +static const unsigned short windows_1256tab[128] = {
 137.175 +  0x20ac,0x067e,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
 137.176 +  0x02c6,0x2030,0x0679,0x2039,0x0152,0x0686,0x0698,0x0688,
 137.177 +  0x06af,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 137.178 +  0x06a9,0x2122,0x0691,0x203a,0x0153,0x200c,0x200d,0x06ba,
 137.179 +  0x00a0,0x060c,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
 137.180 +  0x00a8,0x00a9,0x06be,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 137.181 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 137.182 +  0x00b8,0x00b9,0x061b,0x00bb,0x00bc,0x00bd,0x00be,0x061f,
 137.183 +  0x06c1,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
 137.184 +  0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
 137.185 +  0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x00d7,
 137.186 +  0x0637,0x0638,0x0639,0x063a,0x0640,0x0641,0x0642,0x0643,
 137.187 +  0x00e0,0x0644,0x00e2,0x0645,0x0646,0x0647,0x0648,0x00e7,
 137.188 +  0x00e8,0x00e9,0x00ea,0x00eb,0x0649,0x064a,0x00ee,0x00ef,
 137.189 +  0x064b,0x064c,0x064d,0x064e,0x00f4,0x064f,0x0650,0x00f7,
 137.190 +  0x0651,0x00f9,0x0652,0x00fb,0x00fc,0x200e,0x200f,0x06d2
 137.191 +};
 137.192 +
 137.193 +				/* Windows Baltic */
 137.194 +static const unsigned short windows_1257tab[128] = {
 137.195 +  0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021,
 137.196 +  UBOGON,0x2030,UBOGON,0x2039,UBOGON,0x00a8,0x02c7,0x00b8,
 137.197 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 137.198 +  UBOGON,0x2122,UBOGON,0x203a,UBOGON,0x00af,0x02db,UBOGON,
 137.199 +  0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,UBOGON,0x00a6,0x00a7,
 137.200 +  0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6,
 137.201 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 137.202 +  0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6,
 137.203 +  0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112,
 137.204 +  0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b,
 137.205 +  0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7,
 137.206 +  0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df,
 137.207 +  0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113,
 137.208 +  0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c,
 137.209 +  0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7,
 137.210 +  0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x02d9
 137.211 +};
 137.212 +
 137.213 +				/* Windows Vietnamese */
 137.214 +static const unsigned short windows_1258tab[128] = {
 137.215 +  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
 137.216 +  0x02c6,0x2030,UBOGON,0x2039,0x0152,UBOGON,UBOGON,UBOGON,
 137.217 +  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
 137.218 +  0x02dc,0x2122,UBOGON,0x203a,0x0153,UBOGON,UBOGON,0x0178,
 137.219 +  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
 137.220 +  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
 137.221 +  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
 137.222 +  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
 137.223 +  0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x00c5,0x00c6,0x00c7,
 137.224 +  0x00c8,0x00c9,0x00ca,0x00cb,0x0300,0x00cd,0x00ce,0x00cf,
 137.225 +  0x0110,0x00d1,0x0309,0x00d3,0x00d4,0x01a0,0x00d6,0x00d7,
 137.226 +  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x01af,0x0303,0x00df,
 137.227 +  0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x00e5,0x00e6,0x00e7,
 137.228 +  0x00e8,0x00e9,0x00ea,0x00eb,0x0301,0x00ed,0x00ee,0x00ef,
 137.229 +  0x0111,0x00f1,0x0323,0x00f3,0x00f4,0x01a1,0x00f6,0x00f7,
 137.230 +  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x01b0,0x20ab,0x00ff
 137.231 +};
   138.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   138.2 +++ b/src/dmail/Makefile	Mon Sep 14 15:17:45 2009 +0900
   138.3 @@ -0,0 +1,53 @@
   138.4 +# ========================================================================
   138.5 +# Copyright 1988-2006 University of Washington
   138.6 +#
   138.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   138.8 +# you may not use this file except in compliance with the License.
   138.9 +# You may obtain a copy of the License at
  138.10 +#
  138.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  138.12 +#
  138.13 +# 
  138.14 +# ========================================================================
  138.15 +
  138.16 +
  138.17 +# Program:	dmail Makefile
  138.18 +#
  138.19 +# Author:	Mark Crispin
  138.20 +#		Networks and Distributed Computing
  138.21 +#		Computing & Communications
  138.22 +#		University of Washington
  138.23 +#		Administration Building, AG-44
  138.24 +#		Seattle, WA  98195
  138.25 +#		Internet: MRC@CAC.Washington.EDU
  138.26 +#
  138.27 +# Date:		5 April 1993
  138.28 +# Last Edited:	10 September 2007
  138.29 +
  138.30 +
  138.31 +C = ../c-client
  138.32 +CCLIENTLIB = $C/c-client.a
  138.33 +SHELL = /bin/sh
  138.34 +
  138.35 +# Get local definitions from c-client directory
  138.36 +
  138.37 +CC = `cat $C/CCTYPE`
  138.38 +CFLAGS = -I$C `cat $C/CFLAGS`
  138.39 +LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
  138.40 +
  138.41 +dmail: $(CCLIENTLIB) dmail.o dquota.o
  138.42 +	$(CC) $(CFLAGS) -o dmail dmail.o dquota.o $(LDFLAGS)
  138.43 +
  138.44 +dmail.o: $C/mail.h $C/misc.h $C/osdep.h dquota.h
  138.45 +
  138.46 +dquota.o: dquota.h
  138.47 +
  138.48 +$(CCLIENTLIB):
  138.49 +	cd $C;make
  138.50 +
  138.51 +clean:
  138.52 +	rm -f *.o dmail
  138.53 +
  138.54 +# A monument to a hack of long ago and far away...
  138.55 +love:
  138.56 +	@echo 'not war?'
   139.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   139.2 +++ b/src/dmail/dmail.1	Mon Sep 14 15:17:45 2009 +0900
   139.3 @@ -0,0 +1,121 @@
   139.4 +.ig
   139.5 + * ========================================================================
   139.6 + * Copyright 1988-2007 University of Washington
   139.7 + *
   139.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   139.9 + * you may not use this file except in compliance with the License.
  139.10 + * You may obtain a copy of the License at
  139.11 + *
  139.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  139.13 + *
  139.14 + * 
  139.15 + * ========================================================================
  139.16 +..
  139.17 +.TH DMAIL 1 "June 18, 2007"
  139.18 +.SH NAME
  139.19 +dmail \- procmail Mail Delivery Module
  139.20 +.nh
  139.21 +.SH SYNOPSIS
  139.22 +.B dmail
  139.23 +.I [\-D] [\-f from_name] [-s] [-k keyword_list] [user][+folder]
  139.24 +.SH DESCRIPTION
  139.25 +.I dmail
  139.26 +delivers mail to a user's INBOX or a designated folder.
  139.27 +.I dmail
  139.28 +may be configured as a drop-in replacement for
  139.29 +.IR binmail (1),
  139.30 +.IR mail.local (1)
  139.31 +for use with a mail delivery filter such as
  139.32 +.IR procmail (1) .
  139.33 +.PP
  139.34 +Because of security considerations (see below)
  139.35 +.I dmail
  139.36 +is not intended to be used for direct delivery by the mailer daemon;
  139.37 +.IR tmail (1)
  139.38 +is the preferred tool for this purpose.  If
  139.39 +.I dmail
  139.40 +is used for mailer daemon delivery, the mailer daemon must invoke
  139.41 +.I dmail
  139.42 +with the
  139.43 +.I dmail
  139.44 +process' user id set to the recipient's user id.
  139.45 +.PP
  139.46 +When
  139.47 +.I dmail
  139.48 +exits, it returns exit status values to enable
  139.49 +.IR procmail (1)
  139.50 +to determine whether a message was delivered successfully or had a
  139.51 +temporary (requeue for later delivery) or permanent (return to sender)
  139.52 +failure.
  139.53 +.PP
  139.54 +If the
  139.55 +.I user
  139.56 +name is present, it must be the same as the logged-in user name.
  139.57 +.PP
  139.58 +If the 
  139.59 +.I +folder
  139.60 +extension is included in the user argument (or appears by itself if there
  139.61 +is no user argument), 
  139.62 +.I dmail
  139.63 +will attempt to deliver to the designated folder.  If the folder does not 
  139.64 +exist or the extension is not included, the message is delivered to the 
  139.65 +user's INBOX.
  139.66 +If delivery is to INBOX and no INBOX currently exists,
  139.67 +.I dmail
  139.68 +will create a new INBOX.
  139.69 +.I dmail
  139.70 +recognizes the format of an existing INBOX or folder, and appends the new
  139.71 +message in that format.
  139.72 +.PP
  139.73 +The \fB-D\fR flag specifies debugging; this enables additional message
  139.74 +telemetry.
  139.75 +.PP
  139.76 +The \fB-f\fR or \fB-r\fR flag is used to specify a Return-Path.  The header
  139.77 +.br
  139.78 +   Return-Path: <\fIfrom_name\fR> 
  139.79 +.br 
  139.80 +is prepended to the message before delivery.
  139.81 +.PP
  139.82 +The
  139.83 +.B -s
  139.84 +flag specifies that the message will be flagged as being "seen".
  139.85 +.PP
  139.86 +The \fB-k\fR flag is used to specify delivery keywords, which are set on
  139.87 +the message at delivery time if and
  139.88 +.B only
  139.89 +if the keywords are already defined in the mailbox.  Multiple keywords can be
  139.90 +specified by using a quoted string, e.g.,
  139.91 +.br
  139.92 +   dmail -k "$Junk Discard" +junkbox
  139.93 +.br 
  139.94 +.SH RESTRICTIONS
  139.95 +Absolute pathnames and 
  139.96 +.I ~user
  139.97 +specifications are not permitted in
  139.98 +.I +folder
  139.99 +extensions.
 139.100 +.SH SECURITY CONSIDERATIONS
 139.101 +Unlike
 139.102 +.I tmail
 139.103 +you can use
 139.104 +.I dmail
 139.105 +to deliver to IMAP4 namespace names via
 139.106 +.I +folder
 139.107 +extensions.  This means that it is possible to deliver to
 139.108 +.IR mh (1)
 139.109 +format mailboxes.
 139.110 +.PP
 139.111 +However, this can also include such namespaces as #shared, #public,
 139.112 +and #ftp.  In most cases, it is undesirable to allow anybody sending
 139.113 +mail to the user to deliver to these namespaces.  Consequently, there
 139.114 +needs to be a rule in place in the configuration of either
 139.115 +.IR sendmail (8)
 139.116 +or
 139.117 +.IR procmail (1)
 139.118 +to prevent such abuse.
 139.119 +.SH AUTHOR
 139.120 +Mark Crispin, MRC@CAC.Washington.EDU
 139.121 +.SH "SEE ALSO"
 139.122 +binmail(1)
 139.123 +.br
 139.124 +procmail(1)
   140.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   140.2 +++ b/src/dmail/dmail.c	Mon Sep 14 15:17:45 2009 +0900
   140.3 @@ -0,0 +1,661 @@
   140.4 +/* ========================================================================
   140.5 + * Copyright 1988-2007 University of Washington
   140.6 + *
   140.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   140.8 + * you may not use this file except in compliance with the License.
   140.9 + * You may obtain a copy of the License at
  140.10 + *
  140.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  140.12 + *
  140.13 + * 
  140.14 + * ========================================================================
  140.15 + */
  140.16 +
  140.17 +/*
  140.18 + * Program:	Procmail-Callable Mail Delivery Module
  140.19 + *
  140.20 + * Author:	Mark Crispin
  140.21 + *		Networks and Distributed Computing
  140.22 + *		Computing & Communications
  140.23 + *		University of Washington
  140.24 + *		Administration Building, AG-44
  140.25 + *		Seattle, WA  98195
  140.26 + *		Internet: MRC@CAC.Washington.EDU
  140.27 + *
  140.28 + * Date:	5 April 1993
  140.29 + * Last Edited:	30 October 2008
  140.30 + */
  140.31 +
  140.32 +#include <stdio.h>
  140.33 +#include <pwd.h>
  140.34 +#include <errno.h>
  140.35 +extern int errno;		/* just in case */
  140.36 +#include <sysexits.h>
  140.37 +#include <sys/file.h>
  140.38 +#include <sys/stat.h>
  140.39 +#include "c-client.h"
  140.40 +#include "dquota.h"
  140.41 +
  140.42 +
  140.43 +/* Globals */
  140.44 +
  140.45 +char *version = "18";		/* dmail edit version */
  140.46 +int debug = NIL;		/* debugging (don't fork) */
  140.47 +int flagseen = NIL;		/* flag message as seen */
  140.48 +int trycreate = NIL;		/* flag saying gotta create before appending */
  140.49 +int critical = NIL;		/* flag saying in critical code */
  140.50 +char *sender = NIL;		/* message origin */
  140.51 +char *keywords = NIL;		/* keyword list */
  140.52 +long precedence = 0;		/* delivery precedence - used by quota hook */
  140.53 +
  140.54 +
  140.55 +/* Function prototypes */
  140.56 +
  140.57 +void file_string_init (STRING *s,void *data,unsigned long size);
  140.58 +char file_string_next (STRING *s);
  140.59 +void file_string_setpos (STRING *s,unsigned long i);
  140.60 +int main (int argc,char *argv[]);
  140.61 +int deliver (FILE *f,unsigned long msglen,char *user);
  140.62 +long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
  140.63 +int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
  140.64 +		    char *tmp);
  140.65 +int delivery_unsafe (char *path,struct stat *sbuf,char *tmp);
  140.66 +int fail (char *string,int code);
  140.67 +
  140.68 +
  140.69 +/* File string driver for file stringstructs */
  140.70 +
  140.71 +STRINGDRIVER file_string = {
  140.72 +  file_string_init,		/* initialize string structure */
  140.73 +  file_string_next,		/* get next byte in string structure */
  140.74 +  file_string_setpos		/* set position in string structure */
  140.75 +};
  140.76 +
  140.77 +
  140.78 +/* Cache buffer for file stringstructs */
  140.79 +
  140.80 +#define CHUNKLEN 16384
  140.81 +char chunk[CHUNKLEN];
  140.82 +
  140.83 +/* Initialize file string structure for file stringstruct
  140.84 + * Accepts: string structure
  140.85 + *	    pointer to string
  140.86 + *	    size of string
  140.87 + */
  140.88 +
  140.89 +void file_string_init (STRING *s,void *data,unsigned long size)
  140.90 +{
  140.91 +  s->data = data;		/* note fd */
  140.92 +  s->size = size;		/* note size */
  140.93 +  s->chunk = chunk;
  140.94 +  s->chunksize = (unsigned long) CHUNKLEN;
  140.95 +  SETPOS (s,0);			/* set initial position */
  140.96 +}
  140.97 +
  140.98 +
  140.99 +/* Get next character from file stringstruct
 140.100 + * Accepts: string structure
 140.101 + * Returns: character, string structure chunk refreshed
 140.102 + */
 140.103 +
 140.104 +char file_string_next (STRING *s)
 140.105 +{
 140.106 +  char c = *s->curpos++;	/* get next byte */
 140.107 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
 140.108 +  return c;			/* return the byte */
 140.109 +}
 140.110 +
 140.111 +
 140.112 +/* Set string pointer position for file stringstruct
 140.113 + * Accepts: string structure
 140.114 + *	    new position
 140.115 + */
 140.116 +
 140.117 +void file_string_setpos (STRING *s,unsigned long i)
 140.118 +{
 140.119 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
 140.120 +  s->offset = i;		/* set new offset */
 140.121 +  s->curpos = s->chunk;		/* reset position */
 140.122 +				/* set size of data */
 140.123 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
 140.124 +				/* move to that position in the file */
 140.125 +    fseek ((FILE *) s->data,s->offset,SEEK_SET);
 140.126 +    fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
 140.127 +  }
 140.128 +}
 140.129 +
 140.130 +/* Main program */
 140.131 +
 140.132 +int main (int argc,char *argv[])
 140.133 +{
 140.134 +  FILE *f = NIL;
 140.135 +  int c,ret = 0;
 140.136 +  unsigned long msglen;
 140.137 +  char *s,tmp[MAILTMPLEN];
 140.138 +  uid_t ruid = getuid ();
 140.139 +  struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL;
 140.140 +  openlog ("dmail",LOG_PID,LOG_MAIL);
 140.141 +				/* must not be root or daemon! */
 140.142 +  if (!ruid || (pwd && (pwd->pw_uid == ruid)))
 140.143 +    _exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE));
 140.144 +#include "linkage.c"
 140.145 +				/* process all flags */
 140.146 +  for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) {
 140.147 +  case 'D':			/* debug */
 140.148 +    debug = T;			/* extra debugging */
 140.149 +    break;
 140.150 +  case 's':			/* deliver as seen */
 140.151 +    flagseen = T;
 140.152 +    break;
 140.153 +  case 'f':
 140.154 +  case 'r':			/* flag giving return path */
 140.155 +    if (sender) _exit (fail ("duplicate -r",EX_USAGE));
 140.156 +    if (argc--) sender = cpystr (*++argv);
 140.157 +    else _exit (fail ("missing argument to -r",EX_USAGE));
 140.158 +    break;
 140.159 +  case 'k':
 140.160 +    if (keywords) _exit (fail ("duplicate -k",EX_USAGE));
 140.161 +    if (argc--) keywords = cpystr (*++argv);
 140.162 +    else _exit (fail ("missing argument to -k",EX_USAGE));
 140.163 +    break;
 140.164 +  case 'p':
 140.165 +    if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
 140.166 +    else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
 140.167 +      precedence = atol (s);
 140.168 +    else _exit (fail ("missing argument to -p",EX_USAGE));
 140.169 +    break;
 140.170 +  default:			/* anything else */
 140.171 +    _exit (fail ("unknown switch",EX_USAGE));
 140.172 +  }
 140.173 +
 140.174 +  if (argc > 1) _exit (fail ("too many recipients",EX_USAGE));
 140.175 +  else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL));
 140.176 +				/* build delivery headers */
 140.177 +  if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
 140.178 +				/* start Received line: */
 140.179 +  fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version,
 140.180 +	   (argc == 1) ? *argv : myusername ());
 140.181 +  rfc822_date (tmp);
 140.182 +  fputs (tmp,f);
 140.183 +  fputs ("\015\012",f);
 140.184 +				/* copy text from standard input */
 140.185 +  if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
 140.186 +      (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
 140.187 +  else if (s[-1] == '\015') {	/* nuke leading "From " line */
 140.188 +    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
 140.189 +	(tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
 140.190 +    while ((c = getchar ()) != EOF) putc (c,f);
 140.191 +  }
 140.192 +  else {
 140.193 +    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
 140.194 +	(tmp[3] != 'm') || (tmp[4] != ' ')) {
 140.195 +      *s++ = '\015';		/* overwrite NL with CRLF */
 140.196 +      *s++ = '\012';
 140.197 +      *s = '\0';		/* tie off string */
 140.198 +      fputs (tmp,f);		/* write line */
 140.199 +    }
 140.200 +  }
 140.201 +				/* copy text from standard input */
 140.202 +  while ((c = getchar ()) != EOF) {
 140.203 +				/* add CR if needed */
 140.204 +    if (c == '\012') putc ('\015',f);
 140.205 +    putc (c,f);
 140.206 +  }
 140.207 +  msglen = ftell (f);		/* size of message */
 140.208 +  fflush (f);			/* make sure all changes written out */
 140.209 +  if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
 140.210 +  else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
 140.211 +				/* single delivery */
 140.212 +  else ret = deliver (f,msglen,argc ? *argv : myusername ());
 140.213 +  fclose (f);			/* all done with temporary file */
 140.214 +  _exit (ret);			/* normal exit */
 140.215 +  return 0;			/* stupid gcc */
 140.216 +}
 140.217 +
 140.218 +/* Deliver message to recipient list
 140.219 + * Accepts: file description of message temporary file
 140.220 + *	    size of message temporary file in bytes
 140.221 + *	    recipient name
 140.222 + * Returns: NIL if success, else error code
 140.223 + */
 140.224 +
 140.225 +int deliver (FILE *f,unsigned long msglen,char *user)
 140.226 +{
 140.227 +  MAILSTREAM *ds = NIL;
 140.228 +  char *s,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
 140.229 +  STRING st;
 140.230 +  struct stat sbuf;
 140.231 +				/* have a mailbox specifier? */
 140.232 +  if (mailbox = strchr (user,'+')) {
 140.233 +    *mailbox++ = '\0';		/* yes, tie off user name */
 140.234 +    if (!*mailbox || !compare_cstring ((unsigned char *) mailbox,"INBOX"))
 140.235 +      mailbox = NIL;		/* user+ and user+INBOX same as user */
 140.236 +  }
 140.237 +  if (!*user) user = myusername ();
 140.238 +  else if (strcmp (user,myusername ()))
 140.239 +    return fail ("can't deliver to other user",EX_CANTCREAT);
 140.240 +  sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
 140.241 +  mm_dlog (tmp);
 140.242 +				/* prepare stringstruct */
 140.243 +  INIT (&st,file_string,(void *) f,msglen);
 140.244 +  if (mailbox) {		/* non-INBOX name */
 140.245 +    switch (mailbox[0]) {	/* make sure a valid name */
 140.246 +    default:			/* other names, try to deliver if not INBOX */
 140.247 +      if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
 140.248 +	  !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
 140.249 +	  !deliver_safely (NIL,&st,mailbox,path,tmp)) return NIL;
 140.250 +    case '%': case '*':		/* wildcards not valid */
 140.251 +    case '/':			/* absolute path names not valid */
 140.252 +    case '~':			/* user names not valid */
 140.253 +      sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
 140.254 +      mm_log (tmp,WARN);
 140.255 +      break;
 140.256 +    }
 140.257 +    mm_dlog ("retrying delivery to INBOX");
 140.258 +    SETPOS (&st,0);		/* rewind stringstruct just in case */
 140.259 +  }
 140.260 +
 140.261 +				/* no -I, resolve "INBOX" into path */
 140.262 +  if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
 140.263 +				/* clear box, get generic INBOX prototype */
 140.264 +    if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
 140.265 +      fatal ("no INBOX prototype");
 140.266 +				/* standard system driver? */
 140.267 +    if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
 140.268 +      strcpy (path,sysinbox ());/* use system INBOX */
 140.269 +      if (!lstat (path,&sbuf))	/* deliver to existing system INBOX */
 140.270 +	return deliver_safely (ds,&st,mailbox,path,tmp);
 140.271 +    }
 140.272 +    else {			/* other driver, try ~/INBOX */
 140.273 +      if ((mailboxfile (path,"&&&&&") == path) &&
 140.274 +	  (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
 140.275 +	  !lstat (path,&sbuf)){	/* deliver to existing ~/INBOX */
 140.276 +	sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
 140.277 +	return deliver_safely (ds,&st,cpystr (tmp),path,tmp);
 140.278 +      }
 140.279 +    }
 140.280 +				/* not dummy, deliver to driver imputed path */
 140.281 +    if (strcmp (ds->dtb->name,"dummy"))
 140.282 +      return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
 140.283 +	deliver_safely (ds,&st,mailbox,path,tmp) :
 140.284 +	  fail ("unable to resolve INBOX path",EX_CANTCREAT);
 140.285 +				/* dummy, empty imputed append path exist? */
 140.286 +    if (ibxpath (ds = default_proto (T),&mailbox,path) &&
 140.287 +	!lstat (path,&sbuf) && !sbuf.st_size)
 140.288 +      return deliver_safely (ds,&st,mailbox,path,tmp);
 140.289 +				/* impute path that we will create */
 140.290 +    if (!ibxpath (ds = default_proto (NIL),&mailbox,path))
 140.291 +      return fail ("unable to resolve INBOX",EX_CANTCREAT);
 140.292 +  }
 140.293 +				/* black box, must create, get create proto */
 140.294 +  else if (lstat (path,&sbuf)) ds = default_proto (NIL);
 140.295 +  else {			/* black box, existing file */
 140.296 +				/* empty file, get append prototype */
 140.297 +    if (!sbuf.st_size) ds = default_proto (T);
 140.298 +				/* non-empty, get prototype from its data */
 140.299 +    else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
 140.300 +      fatal ("no INBOX prototype");
 140.301 +				/* error if unknown format */
 140.302 +    if (!strcmp (ds->dtb->name,"phile"))
 140.303 +      return fail ("unknown format INBOX",EX_UNAVAILABLE);
 140.304 +				/* otherwise can deliver to it */
 140.305 +    return deliver_safely (ds,&st,mailbox,path,tmp);
 140.306 +  }
 140.307 +  sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
 140.308 +  mm_dlog (tmp);
 140.309 +				/* supplicate to the Evil One */
 140.310 +  if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
 140.311 +  sprintf (tmp,"created %.80s",path);
 140.312 +  mm_dlog (tmp);
 140.313 +				/* deliver the message */
 140.314 +  return deliver_safely (ds,&st,mailbox,path,tmp);
 140.315 +}
 140.316 +
 140.317 +/* Resolve INBOX from driver prototype into mailbox name and filesystem path
 140.318 + * Accepts: driver prototype
 140.319 + * 	    pointer to mailbox name string pointer
 140.320 + *	    buffer to return mailbox path
 140.321 + * Returns: T if success, NIL if error
 140.322 + */
 140.323 +
 140.324 +long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
 140.325 +{
 140.326 +  char *s,tmp[MAILTMPLEN];
 140.327 +  long ret = T;
 140.328 +  if (!ds) return NIL;
 140.329 +  else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
 140.330 +    strcpy (path,sysinbox ());	/* use system INBOX for unix and MMDF */
 140.331 +  else if (!strcmp (ds->dtb->name,"tenex"))
 140.332 +    ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
 140.333 +  else if (!strcmp (ds->dtb->name,"mtx"))
 140.334 +    ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
 140.335 +  else if (!strcmp (ds->dtb->name,"mbox"))
 140.336 +    ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
 140.337 +				/* better not be a namespace driver */
 140.338 +  else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
 140.339 +				/* INBOX in home directory */
 140.340 +  else ret = ((mailboxfile (path,"&&&&&") == path) &&
 140.341 +	      (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
 140.342 +  if (ret) {			/* don't bother if lossage */
 140.343 +    sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
 140.344 +    *mailbox = cpystr (tmp);	/* name of INBOX in this namespace */
 140.345 +  }
 140.346 +  return ret;
 140.347 +}
 140.348 +
 140.349 +/* Deliver safely
 140.350 + * Accepts: prototype stream to force mailbox format
 140.351 + *	    stringstruct of message temporary file or NIL for check only
 140.352 + *	    mailbox name
 140.353 + *	    filesystem path name
 140.354 + *	    scratch buffer for messages
 140.355 + * Returns: NIL if success, else error code
 140.356 + */
 140.357 +
 140.358 +int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
 140.359 +		    char *tmp)
 140.360 +{
 140.361 +  struct stat sbuf;
 140.362 +  char *flags = NIL;
 140.363 +  int i = delivery_unsafe (path,&sbuf,tmp);
 140.364 +  if (i) return i;		/* give up now if delivery unsafe */
 140.365 +				/* directory, not file */
 140.366 +  if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
 140.367 +    if (sbuf.st_mode & 0001) {	/* listable directories may be worrisome */
 140.368 +      sprintf (tmp,"WARNING: directory %.80s is listable",path);
 140.369 +      mm_log (tmp,WARN);
 140.370 +    }
 140.371 +  }
 140.372 +  else {			/* file, not directory */
 140.373 +    if (sbuf.st_nlink != 1) {	/* multiple links may be worrisome */
 140.374 +      sprintf (tmp,"WARNING: multiple links to file %.80s",path);
 140.375 +      mm_log (tmp,WARN);
 140.376 +    }
 140.377 +    if (sbuf.st_mode & 0111) {	/* executable files may be worrisome */
 140.378 +      sprintf (tmp,"WARNING: file %.80s is executable",path);
 140.379 +      mm_log (tmp,WARN);
 140.380 +    }
 140.381 +  }
 140.382 +  if (sbuf.st_mode & 0002) {	/* public-write files may be worrisome */
 140.383 +    sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
 140.384 +    mm_log (tmp,WARN);
 140.385 +  }
 140.386 +  if (sbuf.st_mode & 0004) {	/* public-write files may be worrisome */
 140.387 +    sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
 140.388 +    mm_log (tmp,WARN);
 140.389 +  }
 140.390 +				/* check site-written quota procedure */
 140.391 +  if (!dmail_quota (st,path,tmp,sender,precedence))
 140.392 +    return fail (tmp,EX_CANTCREAT);
 140.393 +				/* so far, so good */
 140.394 +  sprintf (tmp,"%s appending to %.80s (%s %.80s)",
 140.395 +	   prt ? prt->dtb->name : "default",mailbox,
 140.396 +	   ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
 140.397 +  mm_dlog (tmp);
 140.398 +  if (keywords) {		/* any keywords requested? */
 140.399 +    if (flagseen) sprintf (flags = tmp,"\\Seen %.1000s",keywords);
 140.400 +    else flags = keywords;
 140.401 +  }
 140.402 +  else if (flagseen) flags = "\\Seen";
 140.403 +				/* do the append now! */
 140.404 +  if (!mail_append_full (prt,mailbox,flags,NIL,st)) {
 140.405 +    sprintf (tmp,"message delivery failed to %.80s",path);
 140.406 +    return fail (tmp,EX_CANTCREAT);
 140.407 +  }
 140.408 +				/* note success */
 140.409 +  sprintf (tmp,"delivered to %.80s",path);
 140.410 +  mm_log (tmp,NIL);
 140.411 +				/* make sure nothing evil this way comes */
 140.412 +  return delivery_unsafe (path,&sbuf,tmp);
 140.413 +}
 140.414 +
 140.415 +/* Verify that delivery is safe
 140.416 + * Accepts: path name
 140.417 + *	    stat buffer
 140.418 + *	    scratch buffer for messages
 140.419 + * Returns: NIL if delivery is safe, error code if unsafe
 140.420 + */
 140.421 +
 140.422 +int delivery_unsafe (char *path,struct stat *sbuf,char *tmp)
 140.423 +{
 140.424 +  u_short type;
 140.425 +  sprintf (tmp,"Verifying safe delivery to %.80s",path);
 140.426 +  mm_dlog (tmp);
 140.427 +				/* prepare message just in case */
 140.428 +  sprintf (tmp,"delivery to %.80s unsafe: ",path);
 140.429 +				/* unsafe if can't get its status */
 140.430 +  if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
 140.431 +				/* check file type */
 140.432 +  else switch (sbuf->st_mode & S_IFMT) {
 140.433 +  case S_IFDIR:			/* directory is always OK */
 140.434 +    return NIL;
 140.435 +  case S_IFREG:			/* file is unsafe if setuid */
 140.436 +    if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
 140.437 +				/* or setgid */
 140.438 +    else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
 140.439 +    else return NIL;		/* otherwise safe */
 140.440 +    break;
 140.441 +  case S_IFCHR: strcat (tmp,"character special"); break;
 140.442 +  case S_IFBLK: strcat (tmp,"block special"); break;
 140.443 +  case S_IFLNK: strcat (tmp,"symbolic link"); break;
 140.444 +  case S_IFSOCK: strcat (tmp,"socket"); break;
 140.445 +  default:
 140.446 +    sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
 140.447 +  }
 140.448 +  return fail (tmp,EX_CANTCREAT);
 140.449 +}
 140.450 +
 140.451 +/* Report an error
 140.452 + * Accepts: string to output
 140.453 + */
 140.454 +
 140.455 +int fail (char *string,int code)
 140.456 +{
 140.457 +  mm_log (string,ERROR);	/* pass up the string */
 140.458 +  switch (code) {
 140.459 +#if T
 140.460 +  case EX_USAGE:
 140.461 +  case EX_OSERR:
 140.462 +  case EX_SOFTWARE:
 140.463 +  case EX_NOUSER:
 140.464 +  case EX_CANTCREAT:
 140.465 +    code = EX_TEMPFAIL;		/* coerce these to TEMPFAIL */
 140.466 +    break;
 140.467 +#endif
 140.468 +  case -1:			/* quota failure... */
 140.469 +    code = EX_CANTCREAT;	/* ...really returns this code */
 140.470 +    break;
 140.471 +  default:
 140.472 +    break;
 140.473 +  }
 140.474 +  return code;			/* error code to return */
 140.475 +}
 140.476 +
 140.477 +/* Co-routines from MAIL library */
 140.478 +
 140.479 +
 140.480 +/* Message matches a search
 140.481 + * Accepts: MAIL stream
 140.482 + *	    message number
 140.483 + */
 140.484 +
 140.485 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
 140.486 +{
 140.487 +  fatal ("mm_searched() call");
 140.488 +}
 140.489 +
 140.490 +
 140.491 +/* Message exists (i.e. there are that many messages in the mailbox)
 140.492 + * Accepts: MAIL stream
 140.493 + *	    message number
 140.494 + */
 140.495 +
 140.496 +void mm_exists (MAILSTREAM *stream,unsigned long number)
 140.497 +{
 140.498 +  fatal ("mm_exists() call");
 140.499 +}
 140.500 +
 140.501 +
 140.502 +/* Message expunged
 140.503 + * Accepts: MAIL stream
 140.504 + *	    message number
 140.505 + */
 140.506 +
 140.507 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
 140.508 +{
 140.509 +  fatal ("mm_expunged() call");
 140.510 +}
 140.511 +
 140.512 +
 140.513 +/* Message flags update seen
 140.514 + * Accepts: MAIL stream
 140.515 + *	    message number
 140.516 + */
 140.517 +
 140.518 +void mm_flags (MAILSTREAM *stream,unsigned long number)
 140.519 +{
 140.520 +}
 140.521 +
 140.522 +/* Mailbox found
 140.523 + * Accepts: MAIL stream
 140.524 + *	    delimiter
 140.525 + *	    mailbox name
 140.526 + *	    mailbox attributes
 140.527 + */
 140.528 +
 140.529 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 140.530 +{
 140.531 +  fatal ("mm_list() call");
 140.532 +}
 140.533 +
 140.534 +
 140.535 +/* Subscribed mailbox found
 140.536 + * Accepts: MAIL stream
 140.537 + *	    delimiter
 140.538 + *	    mailbox name
 140.539 + *	    mailbox attributes
 140.540 + */
 140.541 +
 140.542 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 140.543 +{
 140.544 +  fatal ("mm_lsub() call");
 140.545 +}
 140.546 +
 140.547 +
 140.548 +/* Mailbox status
 140.549 + * Accepts: MAIL stream
 140.550 + *	    mailbox name
 140.551 + *	    mailbox status
 140.552 + */
 140.553 +
 140.554 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 140.555 +{
 140.556 +  fatal ("mm_status() call");
 140.557 +}
 140.558 +
 140.559 +/* Notification event
 140.560 + * Accepts: MAIL stream
 140.561 + *	    string to log
 140.562 + *	    error flag
 140.563 + */
 140.564 +
 140.565 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
 140.566 +{
 140.567 +  char tmp[MAILTMPLEN];
 140.568 +  tmp[11] = '\0';		/* see if TRYCREATE */
 140.569 +  if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
 140.570 +  mm_log (string,errflg);	/* just do mm_log action */
 140.571 +}
 140.572 +
 140.573 +
 140.574 +/* Log an event for the user to see
 140.575 + * Accepts: string to log
 140.576 + *	    error flag
 140.577 + */
 140.578 +
 140.579 +void mm_log (char *string,long errflg)
 140.580 +{
 140.581 +  if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
 140.582 +  else {			/* ordinary logging */
 140.583 +    fprintf (stderr,"%s\n",string);
 140.584 +    switch (errflg) {  
 140.585 +    case NIL:			/* no error */
 140.586 +      syslog (LOG_INFO,"%s",string);
 140.587 +      break;
 140.588 +    case PARSE:			/* parsing problem */
 140.589 +    case WARN:			/* warning */
 140.590 +      syslog (LOG_WARNING,"%s",string);
 140.591 +      break;
 140.592 +    case ERROR:			/* error */
 140.593 +    default:
 140.594 +      syslog (LOG_ERR,"%s",string);
 140.595 +      break;
 140.596 +    }
 140.597 +  }
 140.598 +}
 140.599 +
 140.600 +
 140.601 +/* Log an event to debugging telemetry
 140.602 + * Accepts: string to log
 140.603 + */
 140.604 +
 140.605 +void mm_dlog (char *string)
 140.606 +{
 140.607 +  if (debug) fprintf (stderr,"%s\n",string);
 140.608 +  syslog (LOG_DEBUG,"%s",string);
 140.609 +}
 140.610 +
 140.611 +/* Get user name and password for this host
 140.612 + * Accepts: parse of network mailbox name
 140.613 + *	    where to return user name
 140.614 + *	    where to return password
 140.615 + *	    trial count
 140.616 + */
 140.617 +
 140.618 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
 140.619 +{
 140.620 +  fatal ("mm_login() call");
 140.621 +}
 140.622 +
 140.623 +
 140.624 +/* About to enter critical code
 140.625 + * Accepts: stream
 140.626 + */
 140.627 +
 140.628 +void mm_critical (MAILSTREAM *stream)
 140.629 +{
 140.630 +  critical = T;			/* note in critical code */
 140.631 +}
 140.632 +
 140.633 +
 140.634 +/* About to exit critical code
 140.635 + * Accepts: stream
 140.636 + */
 140.637 +
 140.638 +void mm_nocritical (MAILSTREAM *stream)
 140.639 +{
 140.640 +  critical = NIL;		/* note not in critical code */
 140.641 +}
 140.642 +
 140.643 +
 140.644 +/* Disk error found
 140.645 + * Accepts: stream
 140.646 + *	    system error code
 140.647 + *	    flag indicating that mailbox may be clobbered
 140.648 + * Returns: T if user wants to abort
 140.649 + */
 140.650 +
 140.651 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
 140.652 +{
 140.653 +  return T;
 140.654 +}
 140.655 +
 140.656 +
 140.657 +/* Log a fatal error event
 140.658 + * Accepts: string to log
 140.659 + */
 140.660 +
 140.661 +void mm_fatal (char *string)
 140.662 +{
 140.663 +  printf ("?%s\n",string);	/* shouldn't happen normally */
 140.664 +}
   141.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   141.2 +++ b/src/dmail/dquota.c	Mon Sep 14 15:17:45 2009 +0900
   141.3 @@ -0,0 +1,44 @@
   141.4 +/* ========================================================================
   141.5 + * Copyright 1988-2007 University of Washington
   141.6 + *
   141.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   141.8 + * you may not use this file except in compliance with the License.
   141.9 + * You may obtain a copy of the License at
  141.10 + *
  141.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  141.12 + *
  141.13 + * 
  141.14 + * ========================================================================
  141.15 + */
  141.16 +
  141.17 +/*
  141.18 + * Program:	Procmail-Callable Mail Delivery Module Quota Hook
  141.19 + *
  141.20 + * Author:	Mark Crispin
  141.21 + *		Networks and Distributed Computing
  141.22 + *		Computing & Communications
  141.23 + *		University of Washington
  141.24 + *		Administration Building, AG-44
  141.25 + *		Seattle, WA  98195
  141.26 + *		Internet: MRC@CAC.Washington.EDU
  141.27 + *
  141.28 + * Date:	10 September 2007
  141.29 + * Last Edited:	10 September 2007
  141.30 + */
  141.31 +
  141.32 +#include "c-client.h"
  141.33 +
  141.34 +/* Site-written routine to validate delivery per quota and policy
  141.35 + * Accepts: stringstruct of message temporary file
  141.36 + *	    filesystem path
  141.37 + *	    return path
  141.38 + *	    buffer to write error message
  141.39 + *	    precedence setting
  141.40 + * Returns: T if can deliver, or NIL if quota issue and must bounce
  141.41 + */
  141.42 +
  141.43 +long dmail_quota (STRING *msg,char *path,char *tmp,char *sender,
  141.44 +		  long precedence)
  141.45 +{
  141.46 +  return LONGT;			/* dummy success return */
  141.47 +}
   142.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   142.2 +++ b/src/dmail/dquota.h	Mon Sep 14 15:17:45 2009 +0900
   142.3 @@ -0,0 +1,32 @@
   142.4 +/* ========================================================================
   142.5 + * Copyright 1988-2007 University of Washington
   142.6 + *
   142.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   142.8 + * you may not use this file except in compliance with the License.
   142.9 + * You may obtain a copy of the License at
  142.10 + *
  142.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  142.12 + *
  142.13 + * 
  142.14 + * ========================================================================
  142.15 + */
  142.16 +
  142.17 +/*
  142.18 + * Program:	Procmail-Callable Mail Delivery Module Quota Hook
  142.19 + *
  142.20 + * Author:	Mark Crispin
  142.21 + *		Networks and Distributed Computing
  142.22 + *		Computing & Communications
  142.23 + *		University of Washington
  142.24 + *		Administration Building, AG-44
  142.25 + *		Seattle, WA  98195
  142.26 + *		Internet: MRC@CAC.Washington.EDU
  142.27 + *
  142.28 + * Date:	10 September 2007
  142.29 + * Last Edited:	10 September 2007
  142.30 + */
  142.31 +
  142.32 +/* Function prototypes */
  142.33 +
  142.34 +long dmail_quota (STRING *msg,char *path,char *tmp,char *sender,
  142.35 +		  long precedence);
   143.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.2 +++ b/src/imapd/Makefile	Mon Sep 14 15:17:45 2009 +0900
   143.3 @@ -0,0 +1,68 @@
   143.4 +# ========================================================================
   143.5 +# Copyright 1988-2006 University of Washington
   143.6 +#
   143.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   143.8 +# you may not use this file except in compliance with the License.
   143.9 +# You may obtain a copy of the License at
  143.10 +#
  143.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  143.12 +#
  143.13 +# 
  143.14 +# ========================================================================
  143.15 +
  143.16 +
  143.17 +# Program:	IMAPD Makefile
  143.18 +#
  143.19 +# Author:	Mark Crispin
  143.20 +#		Networks and Distributed Computing
  143.21 +#		Computing & Communications
  143.22 +#		University of Washington
  143.23 +#		Administration Building, AG-44
  143.24 +#		Seattle, WA  98195
  143.25 +#		Internet: MRC@CAC.Washington.EDU
  143.26 +#
  143.27 +# Date:		5 November 1990
  143.28 +# Last Edited:	30 August 2006
  143.29 +
  143.30 +
  143.31 +ALERT=/etc/imapd.alert
  143.32 +USERALERT=.imapalert
  143.33 +SHUTDOWN=/etc/nologin
  143.34 +ANO=/etc/anonymous.newsgroups
  143.35 +NNTP=/etc/imapd.nntp
  143.36 +SHELL= /bin/sh
  143.37 +
  143.38 +
  143.39 +# Un-comment this to get somewhat better interoperability with Netscape.  It
  143.40 +# causes the "Manage Mail" menu item to open the given URL, e.g. to point to
  143.41 +# an alternative IMAP client (e.g. Pine) or perhaps to a homebrew mail
  143.42 +# account management page.
  143.43 +#NSBD= -DNETSCAPE_BRAIN_DAMAGE=\"http://www.washington.edu/pine\"
  143.44 +
  143.45 +
  143.46 +# Get local definitions from c-client directory
  143.47 +
  143.48 +C = ../c-client
  143.49 +CCLIENTLIB = $C/c-client.a
  143.50 +CC = `cat $C/CCTYPE`
  143.51 +CFLAGS = -I$C `cat $C/CFLAGS` $(NSBD) $(ENBD) -DANOFILE=\"$(ANO)\" \
  143.52 +	-DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" \
  143.53 +	-DUSERALERTFILE=\"$(USERALERT)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
  143.54 +LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
  143.55 +
  143.56 +all:	imapd
  143.57 +
  143.58 +imapd: $(CCLIENTLIB) imapd.o
  143.59 +	$(CC) $(CFLAGS) -o imapd imapd.o $(LDFLAGS)
  143.60 +
  143.61 +imapd.o: $C/mail.h $C/misc.h $C/osdep.h
  143.62 +
  143.63 +$(CCLIENTLIB):
  143.64 +	cd $C;make
  143.65 +
  143.66 +clean:
  143.67 +	rm -f *.o imapd || true
  143.68 +
  143.69 +# A monument to a hack of long ago and far away...
  143.70 +love:
  143.71 +	@echo 'not war?'
   144.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   144.2 +++ b/src/imapd/imapd.8	Mon Sep 14 15:17:45 2009 +0900
   144.3 @@ -0,0 +1,48 @@
   144.4 +.ig
   144.5 + * ========================================================================
   144.6 + * Copyright 1988-2006 University of Washington
   144.7 + *
   144.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   144.9 + * you may not use this file except in compliance with the License.
  144.10 + * You may obtain a copy of the License at
  144.11 + *
  144.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  144.13 + *
  144.14 + * 
  144.15 + * ========================================================================
  144.16 +..
  144.17 +.TH IMAPD 8 "August 30, 2006"
  144.18 +.UC 5
  144.19 +.SH NAME
  144.20 +IMAPd \- Internet Message Access Protocol server
  144.21 +.SH SYNOPSIS
  144.22 +.B /usr/etc/imapd
  144.23 +.SH DESCRIPTION
  144.24 +.I imapd
  144.25 +is a server which supports the
  144.26 +.B IMAP4rev1
  144.27 +remote mail access protocol as documented in RFC-3501.
  144.28 +.I imapd
  144.29 +is invoked by the internet server (see
  144.30 +.IR inetd (8)),
  144.31 +normally for requests to connect to the
  144.32 +.B IMAP
  144.33 +port as indicated by the
  144.34 +.I /etc/services
  144.35 +file (see
  144.36 +.IR services (5)).
  144.37 +Normally, this is port 143 for plaintext IMAP and 993 for SSL IMAP.
  144.38 +.PP
  144.39 +This daemons contains CRAM-MD5 support.  See the md5.txt documentation
  144.40 +file for additional information.
  144.41 +.PP
  144.42 +.I imapd
  144.43 +can also be accessed via
  144.44 +.IR rsh (1)
  144.45 +by many Unix-based clients.  To do this, the
  144.46 +.I imapd
  144.47 +binary must have a link to
  144.48 +.I /etc/rimapd
  144.49 +since this is where this software expects it to be located.
  144.50 +.SH "SEE ALSO"
  144.51 +rsh(1) ipopd(8)
   145.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   145.2 +++ b/src/imapd/imapd.c	Mon Sep 14 15:17:45 2009 +0900
   145.3 @@ -0,0 +1,4608 @@
   145.4 +/* ========================================================================
   145.5 + * Copyright 1988-2008 University of Washington
   145.6 + *
   145.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   145.8 + * you may not use this file except in compliance with the License.
   145.9 + * You may obtain a copy of the License at
  145.10 + *
  145.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  145.12 + *
  145.13 + * 
  145.14 + * ========================================================================
  145.15 + */
  145.16 +
  145.17 +/*
  145.18 + * Program:	IMAP4rev1 server
  145.19 + *
  145.20 + * Author:	Mark Crispin
  145.21 + *		UW Technology
  145.22 + *		University of Washington
  145.23 + *		Seattle, WA  98195
  145.24 + *		Internet: MRC@Washington.EDU
  145.25 + *
  145.26 + * Date:	5 November 1990
  145.27 + * Last Edited:	3 March 2008
  145.28 + */
  145.29 +
  145.30 +/* Parameter files */
  145.31 +
  145.32 +#include <stdio.h>
  145.33 +#include <ctype.h>
  145.34 +#include <errno.h>
  145.35 +extern int errno;		/* just in case */
  145.36 +#include <signal.h>
  145.37 +#include <setjmp.h>
  145.38 +#include <time.h>
  145.39 +#include "c-client.h"
  145.40 +#include "newsrc.h"
  145.41 +#include <sys/stat.h>
  145.42 +
  145.43 +
  145.44 +#define CRLF PSOUT ("\015\012")	/* primary output terpri */
  145.45 +
  145.46 +
  145.47 +/* Timeouts and timers */
  145.48 +
  145.49 +#define MINUTES *60
  145.50 +
  145.51 +#define LOGINTIMEOUT 3 MINUTES	/* not logged in autologout timer */
  145.52 +#define TIMEOUT 30 MINUTES	/* RFC 3501 minimum autologout timer */
  145.53 +#define INPUTTIMEOUT 5 MINUTES	/* timer for additional command input */
  145.54 +#define ALERTTIMER 1 MINUTES	/* alert check timer */
  145.55 +#define SHUTDOWNTIMER 1 MINUTES	/* shutdown dally timer */
  145.56 +#define IDLETIMER 1 MINUTES	/* IDLE command poll timer */
  145.57 +#define CHECKTIMER 15 MINUTES	/* IDLE command last checkpoint timer */
  145.58 +
  145.59 +
  145.60 +#define LITSTKLEN 20		/* length of literal stack */
  145.61 +#define MAXCLIENTLIT 10000	/* maximum non-APPEND client literal size
  145.62 +				 * must be smaller than 4294967295
  145.63 +				 */
  145.64 +#define MAXAPPENDTXT 0x40000000	/* maximum APPEND literal size
  145.65 +				 * must be smaller than 4294967295
  145.66 +				 */
  145.67 +#define CMDLEN 65536		/* size of command buffer */
  145.68 +
  145.69 +
  145.70 +/* Server states */
  145.71 +
  145.72 +#define LOGIN 0
  145.73 +#define SELECT 1
  145.74 +#define OPEN 2
  145.75 +#define LOGOUT 3
  145.76 +
  145.77 +/* Body text fetching */
  145.78 +
  145.79 +typedef struct text_args {
  145.80 +  char *section;		/* body section */
  145.81 +  STRINGLIST *lines;		/* header lines */
  145.82 +  unsigned long first;		/* first octet to fetch */
  145.83 +  unsigned long last;		/* number of octets to fetch */
  145.84 +  long flags;			/* fetch flags */
  145.85 +  long binary;			/* binary flags */
  145.86 +} TEXTARGS;
  145.87 +
  145.88 +#define FTB_BINARY 0x1		/* fetch as binary */
  145.89 +#define FTB_SIZE 0x2		/* fetch size only */
  145.90 +
  145.91 +
  145.92 +/* Append data */
  145.93 +
  145.94 +typedef struct append_data {
  145.95 +  unsigned char *arg;		/* append argument pointer */
  145.96 +  char *flags;			/* message flags */
  145.97 +  char *date;			/* message date */
  145.98 +  char *msg;			/* message text */
  145.99 +  STRING *message;		/* message stringstruct */
 145.100 +} APPENDDATA;
 145.101 +
 145.102 +
 145.103 +/* Message pointer */
 145.104 +
 145.105 +typedef struct msg_data {
 145.106 +  MAILSTREAM *stream;		/* stream */
 145.107 +  unsigned long msgno;		/* message number */
 145.108 +  char *flags;			/* current flags */
 145.109 +  char *date;			/* current date */
 145.110 +  STRING *message;		/* stringstruct of message */
 145.111 +} MSGDATA;
 145.112 +
 145.113 +/* Function prototypes */
 145.114 +
 145.115 +int main (int argc,char *argv[]);
 145.116 +void ping_mailbox (unsigned long uid);
 145.117 +time_t palert (char *file,time_t oldtime);
 145.118 +void msg_string_init (STRING *s,void *data,unsigned long size);
 145.119 +char msg_string_next (STRING *s);
 145.120 +void msg_string_setpos (STRING *s,unsigned long i);
 145.121 +void new_flags (MAILSTREAM *stream);
 145.122 +void settimeout (unsigned int i);
 145.123 +void clkint (void);
 145.124 +void kodint (void);
 145.125 +void hupint (void);
 145.126 +void trmint (void);
 145.127 +void staint (void);
 145.128 +char *sout (char *s,char *t);
 145.129 +char *nout (char *s,unsigned long n,unsigned long base);
 145.130 +void slurp (char *s,int n,unsigned long timeout);
 145.131 +void inliteral (char *s,unsigned long n);
 145.132 +unsigned char *flush (void);
 145.133 +void ioerror (FILE *f,char *reason);
 145.134 +unsigned char *parse_astring (unsigned char **arg,unsigned long *i,
 145.135 +			      unsigned char *del);
 145.136 +unsigned char *snarf (unsigned char **arg);
 145.137 +unsigned char *snarf_base64 (unsigned char **arg);
 145.138 +unsigned char *snarf_list (unsigned char **arg);
 145.139 +STRINGLIST *parse_stringlist (unsigned char **s,int *list);
 145.140 +unsigned long uidmax (MAILSTREAM *stream);
 145.141 +long parse_criteria (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg,
 145.142 +		     unsigned long maxuid,unsigned long depth);
 145.143 +long parse_criterion (SEARCHPGM *pgm,unsigned char **arg,unsigned long msgmsg,
 145.144 +		      unsigned long maxuid,unsigned long depth);
 145.145 +long crit_date (unsigned short *date,unsigned char **arg);
 145.146 +long crit_date_work (unsigned short *date,unsigned char **arg);
 145.147 +long crit_set (SEARCHSET **set,unsigned char **arg,unsigned long maxima);
 145.148 +long crit_number (unsigned long *number,unsigned char **arg);
 145.149 +long crit_string (STRINGLIST **string,unsigned char **arg);
 145.150 +
 145.151 +void fetch (char *t,unsigned long uid);
 145.152 +typedef void (*fetchfn_t) (unsigned long i,void *args);
 145.153 +void fetch_work (char *t,unsigned long uid,fetchfn_t f[],void *fa[]);
 145.154 +void fetch_bodystructure (unsigned long i,void *args);
 145.155 +void fetch_body (unsigned long i,void *args);
 145.156 +void fetch_body_part_mime (unsigned long i,void *args);
 145.157 +void fetch_body_part_contents (unsigned long i,void *args);
 145.158 +void fetch_body_part_binary (unsigned long i,void *args);
 145.159 +void fetch_body_part_header (unsigned long i,void *args);
 145.160 +void fetch_body_part_text (unsigned long i,void *args);
 145.161 +void remember (unsigned long uid,char *id,SIZEDTEXT *st);
 145.162 +void fetch_envelope (unsigned long i,void *args);
 145.163 +void fetch_encoding (unsigned long i,void *args);
 145.164 +void changed_flags (unsigned long i,int f);
 145.165 +void fetch_flags (unsigned long i,void *args);
 145.166 +void put_flag (int *c,char *s);
 145.167 +void fetch_internaldate (unsigned long i,void *args);
 145.168 +void fetch_uid (unsigned long i,void *args);
 145.169 +void fetch_rfc822 (unsigned long i,void *args);
 145.170 +void fetch_rfc822_header (unsigned long i,void *args);
 145.171 +void fetch_rfc822_size (unsigned long i,void *args);
 145.172 +void fetch_rfc822_text (unsigned long i,void *args);
 145.173 +void penv (ENVELOPE *env);
 145.174 +void pbodystructure (BODY *body);
 145.175 +void pbody (BODY *body);
 145.176 +void pparam (PARAMETER *param);
 145.177 +void paddr (ADDRESS *a);
 145.178 +void pset (SEARCHSET **set);
 145.179 +void pnum (unsigned long i);
 145.180 +void pstring (char *s);
 145.181 +void pnstring (char *s);
 145.182 +void pastring (char *s);
 145.183 +void psizedquoted (SIZEDTEXT *s);
 145.184 +void psizedliteral (SIZEDTEXT *s,STRING *st);
 145.185 +void psizedstring (SIZEDTEXT *s,STRING *st);
 145.186 +void psizedastring (SIZEDTEXT *s);
 145.187 +void pastringlist (STRINGLIST *s);
 145.188 +void pnstringorlist (STRINGLIST *s);
 145.189 +void pbodypartstring (unsigned long msgno,char *id,SIZEDTEXT *st,STRING *bs,
 145.190 +		      TEXTARGS *ta);
 145.191 +void ptext (SIZEDTEXT *s,STRING *st);
 145.192 +void pthread (THREADNODE *thr);
 145.193 +void pcapability (long flag);
 145.194 +long nameok (char *ref,char *name);
 145.195 +char *bboardname (char *cmd,char *name);
 145.196 +long isnewsproxy (char *name);
 145.197 +long newsproxypattern (char *ref,char *pat,char *pattern,long flag);
 145.198 +char *imap_responder (void *challenge,unsigned long clen,unsigned long *rlen);
 145.199 +long proxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 145.200 +long proxy_append (MAILSTREAM *stream,void *data,char **flags,char **date,
 145.201 +		   STRING **message);
 145.202 +long append_msg (MAILSTREAM *stream,void *data,char **flags,char **date,
 145.203 +		 STRING **message);
 145.204 +void copyuid (MAILSTREAM *stream,char *mailbox,unsigned long uidvalidity,
 145.205 +	      SEARCHSET *sourceset,SEARCHSET *destset);
 145.206 +void appenduid (char *mailbox,unsigned long uidvalidity,SEARCHSET *set);
 145.207 +char *referral (MAILSTREAM *stream,char *url,long code);
 145.208 +void mm_list_work (char *what,int delimiter,char *name,long attributes);
 145.209 +char *lasterror (void);
 145.210 +
 145.211 +/* Global storage */
 145.212 +
 145.213 +char *version = "404";		/* edit number of this server */
 145.214 +char *logout = "Logout";	/* syslogreason for logout */
 145.215 +char *goodbye = NIL;		/* bye reason */
 145.216 +time_t alerttime = 0;		/* time of last alert */
 145.217 +time_t sysalerttime = 0;	/* time of last system alert */
 145.218 +time_t useralerttime = 0;	/* time of last user alert */
 145.219 +time_t lastcheck = 0;		/* time of last checkpoint */
 145.220 +time_t shutdowntime = 0;	/* time of last shutdown */
 145.221 +int state = LOGIN;		/* server state */
 145.222 +int cancelled = NIL;		/* authenticate cancelled */
 145.223 +int trycreate = 0;		/* saw a trycreate */
 145.224 +int finding = NIL;		/* doing old FIND command */
 145.225 +int anonymous = 0;		/* non-zero if anonymous */
 145.226 +int critical = NIL;		/* non-zero if in critical code */
 145.227 +int quell_events = NIL;		/* non-zero if in FETCH response */
 145.228 +int existsquelled = NIL;	/* non-zero if an EXISTS was quelled */
 145.229 +int proxylist = NIL;		/* doing a proxy LIST */
 145.230 +MAILSTREAM *stream = NIL;	/* mailbox stream */
 145.231 +DRIVER *curdriver = NIL;	/* note current driver */
 145.232 +MAILSTREAM *tstream = NIL;	/* temporary mailbox stream */
 145.233 +unsigned int nflags = 0;	/* current number of keywords */
 145.234 +unsigned long nmsgs =0xffffffff;/* last reported # of messages and recent */
 145.235 +unsigned long recent = 0xffffffff;
 145.236 +char *nntpproxy = NIL;		/* NNTP proxy name */
 145.237 +unsigned char *user = NIL;	/* user name */
 145.238 +unsigned char *pass = NIL;	/* password */
 145.239 +unsigned char *initial = NIL;	/* initial response */
 145.240 +unsigned char cmdbuf[CMDLEN];	/* command buffer */
 145.241 +char *status = "starting up";	/* server status */
 145.242 +char *tag;			/* tag portion of command */
 145.243 +unsigned char *cmd;		/* command portion of command */
 145.244 +unsigned char *arg;		/* pointer to current argument of command */
 145.245 +char *lstwrn = NIL;		/* last warning message from c-client */
 145.246 +char *lsterr = NIL;		/* last error message from c-client */
 145.247 +char *lstref = NIL;		/* last referral from c-client */
 145.248 +char *response = NIL;		/* command response */
 145.249 +struct {
 145.250 +  unsigned long size;		/* size of current LITERAL+ */
 145.251 +  unsigned int ok : 1;		/* LITERAL+ in effect */
 145.252 +} litplus;
 145.253 +int litsp = 0;			/* literal stack pointer */
 145.254 +char *litstk[LITSTKLEN];	/* stack to hold literals */
 145.255 +unsigned long uidvalidity = 0;	/* last reported UID validity */
 145.256 +unsigned long lastuid = 0;	/* last fetched uid */
 145.257 +char *lastid = NIL;		/* last fetched body id for this message */
 145.258 +char *lastsel = NIL;		/* last selected mailbox name */
 145.259 +SIZEDTEXT lastst = {NIL,0};	/* last sizedtext */
 145.260 +unsigned long cauidvalidity = 0;/* UIDVALIDITY for COPYUID/APPENDUID */
 145.261 +SEARCHSET *csset = NIL;		/* COPYUID source set */
 145.262 +SEARCHSET *caset = NIL;		/* COPYUID/APPENDUID destination set */
 145.263 +jmp_buf jmpenv;			/* stack context for setjmp */
 145.264 +
 145.265 +
 145.266 +/* Response texts which appear in multiple places */
 145.267 +
 145.268 +char *win = "%.80s OK ";
 145.269 +char *rowin = "%.80s OK [READ-ONLY] %.80s completed\015\012";
 145.270 +char *rwwin = "%.80s OK [READ-WRITE] %.80s completed\015\012";
 145.271 +char *lose = "%.80s NO ";
 145.272 +char *logwin = "%.80s OK [";
 145.273 +char *losetry = "%.80s NO [TRYCREATE] %.80s failed: %.900s\015\012";
 145.274 +char *loseunknowncte = "%.80s NO [UNKNOWN-CTE] %.80s failed: %.900s\015\012";
 145.275 +char *badcmd = "%.80s BAD Command unrecognized: %.80s\015\012";
 145.276 +char *misarg = "%.80s BAD Missing or invalid argument to %.80s\015\012";
 145.277 +char *badarg = "%.80s BAD Argument given to %.80s when none expected\015\012";
 145.278 +char *badseq = "%.80s BAD Bogus sequence in %.80s: %.80s\015\012";
 145.279 +char *badatt = "%.80s BAD Bogus attribute list in %.80s\015\012";
 145.280 +char *badbin = "%.80s BAD Syntax error in binary specifier\015\012";
 145.281 +
 145.282 +/* Message string driver for message stringstructs */
 145.283 +
 145.284 +STRINGDRIVER msg_string = {
 145.285 +  msg_string_init,		/* initialize string structure */
 145.286 +  msg_string_next,		/* get next byte in string structure */
 145.287 +  msg_string_setpos		/* set position in string structure */
 145.288 +};
 145.289 +
 145.290 +/* Main program */
 145.291 +
 145.292 +int main (int argc,char *argv[])
 145.293 +{
 145.294 +  unsigned long i,uid;
 145.295 +  long f;
 145.296 +  unsigned char *s,*t,*u,*v,tmp[MAILTMPLEN];
 145.297 +  struct stat sbuf;
 145.298 +  logouthook_t lgoh;
 145.299 +  int ret = 0;
 145.300 +  time_t autologouttime = 0;
 145.301 +  char *pgmname;
 145.302 +				/* if case we get borked immediately */
 145.303 +  if (setjmp (jmpenv)) _exit (1);
 145.304 +  pgmname = (argc && argv[0]) ?
 145.305 +    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
 145.306 +     (char *) s+1 : argv[0]) : "imapd";
 145.307 +				/* set service name before linkage */
 145.308 +  mail_parameters (NIL,SET_SERVICENAME,(void *) "imap");
 145.309 +#include "linkage.c"
 145.310 +  rfc822_date (tmp);		/* get date/time at startup */
 145.311 +				/* initialize server */
 145.312 +  server_init (pgmname,"imap","imaps",clkint,kodint,hupint,trmint,staint);
 145.313 +				/* forbid automatic untagged expunge */
 145.314 +  mail_parameters (NIL,SET_EXPUNGEATPING,NIL);
 145.315 +				/* arm proxy copy callback */
 145.316 +  mail_parameters (NIL,SET_MAILPROXYCOPY,(void *) proxycopy);
 145.317 +				/* arm referral callback */
 145.318 +  mail_parameters (NIL,SET_IMAPREFERRAL,(void *) referral);
 145.319 +				/* arm COPYUID callback */
 145.320 +  mail_parameters (NIL,SET_COPYUID,(void *) copyuid);
 145.321 +				/* arm APPENDUID callback */
 145.322 +  mail_parameters (NIL,SET_APPENDUID,(void *) appenduid);
 145.323 +
 145.324 +  if (stat (SHUTDOWNFILE,&sbuf)) {
 145.325 +    char proxy[MAILTMPLEN];
 145.326 +    FILE *nntp = fopen (NNTPFILE,"r");
 145.327 +    if (nntp) {			/* desire NNTP proxy? */
 145.328 +      if (fgets (proxy,MAILTMPLEN,nntp)) {
 145.329 +				/* remove newline and set NNTP proxy */
 145.330 +	if (s = strchr (proxy,'\n')) *s = '\0';
 145.331 +	nntpproxy = cpystr (proxy);
 145.332 +				/* disable the news driver */
 145.333 +	mail_parameters (NIL,DISABLE_DRIVER,"news");
 145.334 +      }
 145.335 +      fclose (nntp);		/* done reading proxy name */
 145.336 +    }
 145.337 +    s = myusername_full (&i);	/* get user name and flags */
 145.338 +    switch (i) {
 145.339 +    case MU_NOTLOGGEDIN:
 145.340 +      PSOUT ("* OK [");		/* not logged in, ordinary startup */
 145.341 +      pcapability (-1);
 145.342 +      break;
 145.343 +    case MU_ANONYMOUS:
 145.344 +      anonymous = T;		/* anonymous user, fall into default */
 145.345 +      s = "ANONYMOUS";
 145.346 +    case MU_LOGGEDIN:
 145.347 +      PSOUT ("* PREAUTH [");	/* already logged in, pre-authorized */
 145.348 +      pcapability (1);
 145.349 +      user = cpystr (s);	/* copy user name */
 145.350 +      pass = cpystr ("*");	/* set fake password */
 145.351 +      state = SELECT;		/* enter select state */
 145.352 +      break;
 145.353 +    default:
 145.354 +      fatal ("Unknown state from myusername_full()");
 145.355 +    }
 145.356 +    PSOUT ("] ");
 145.357 +    if (user) {			/* preauthenticated as someone? */
 145.358 +      PSOUT ("Pre-authenticated user ");
 145.359 +      PSOUT (user);
 145.360 +      PBOUT (' ');
 145.361 +    }
 145.362 +  }
 145.363 +  else {			/* login disabled */
 145.364 +    PSOUT ("* BYE Service not available ");
 145.365 +    state = LOGOUT;
 145.366 +  }
 145.367 +  PSOUT (tcp_serverhost ());
 145.368 +  PSOUT (" IMAP4rev1 ");
 145.369 +  PSOUT (CCLIENTVERSION);
 145.370 +  PBOUT ('.');
 145.371 +  PSOUT (version);
 145.372 +  PSOUT (" at ");
 145.373 +  PSOUT (tmp);
 145.374 +  CRLF;
 145.375 +  PFLUSH ();			/* dump output buffer */
 145.376 +  switch (state) {		/* do this after the banner */
 145.377 +  case LOGIN:
 145.378 +    autologouttime = time (0) + LOGINTIMEOUT;
 145.379 +    break;
 145.380 +  case SELECT:
 145.381 +    syslog (LOG_INFO,"Preauthenticated user=%.80s host=%.80s",
 145.382 +	    user,tcp_clienthost ());
 145.383 +    break;
 145.384 +  }
 145.385 +
 145.386 +  if (setjmp (jmpenv)) {	/* die if a signal handler say so */
 145.387 +				/* in case we get borked now */
 145.388 +    if (setjmp (jmpenv)) _exit (1);
 145.389 +				/* need to close stream gracefully? */
 145.390 +    if (stream && !stream->lock && (stream->dtb->flags & DR_XPOINT))
 145.391 +      stream = mail_close (stream);
 145.392 +    ret = 1;			/* set exit status */
 145.393 +  }
 145.394 +  else while (state != LOGOUT) {/* command processing loop */
 145.395 +    slurp (cmdbuf,CMDLEN,TIMEOUT);
 145.396 +				/* no more last error or literal */
 145.397 +    if (lstwrn) fs_give ((void **) &lstwrn);
 145.398 +    if (lsterr) fs_give ((void **) &lsterr);
 145.399 +    if (lstref) fs_give ((void **) &lstref);
 145.400 +    while (litsp) fs_give ((void **) &litstk[--litsp]);
 145.401 +				/* find end of line */
 145.402 +    if (!strchr (cmdbuf,'\012')) {
 145.403 +      if (t = strchr (cmdbuf,' ')) *t = '\0';
 145.404 +      if ((t - cmdbuf) > 100) t = NIL;
 145.405 +      flush ();			/* flush excess */
 145.406 +      if (state == LOGIN)	/* error if NLI */
 145.407 +	syslog (LOG_INFO,"Line too long before authentication host=%.80s",
 145.408 +		tcp_clienthost ());
 145.409 +      sprintf (tmp,response,t ? (char *) cmdbuf : "*");
 145.410 +      PSOUT (tmp);
 145.411 +    }
 145.412 +    else if (!(tag = strtok (cmdbuf," \015\012"))) {
 145.413 +      if (state == LOGIN)	/* error if NLI */
 145.414 +	syslog (LOG_INFO,"Null command before authentication host=%.80s",
 145.415 +		tcp_clienthost ());
 145.416 +      PSOUT ("* BAD Null command\015\012");
 145.417 +    }
 145.418 +    else if (strlen (tag) > 50) PSOUT ("* BAD Excessively long tag\015\012");
 145.419 +    else if (!(s = strtok (NIL," \015\012"))) {
 145.420 +      if (state == LOGIN)	/* error if NLI */
 145.421 +	syslog (LOG_INFO,"Missing command before authentication host=%.80s",
 145.422 +		tcp_clienthost ());
 145.423 +      PSOUT (tag);
 145.424 +      PSOUT (" BAD Missing command\015\012");
 145.425 +    }
 145.426 +    else {			/* parse command */
 145.427 +      response = win;		/* set default response */
 145.428 +      finding = NIL;		/* no longer FINDing */
 145.429 +      ucase (s);		/* canonicalize command case */
 145.430 +				/* UID command? */
 145.431 +      if (!strcmp (s,"UID") && strtok (NIL," \015\012")) {
 145.432 +	uid = T;		/* a UID command */
 145.433 +	s[3] = ' ';		/* restore the space delimiter */
 145.434 +	ucase (s);		/* make sure command all uppercase */
 145.435 +      }
 145.436 +      else uid = NIL;		/* not a UID command */
 145.437 +				/* flush previous saved command */
 145.438 +      if (cmd) fs_give ((void **) &cmd);
 145.439 +      cmd = cpystr (s);		/* save current command */
 145.440 +				/* snarf argument, see if possible litplus */
 145.441 +      if ((arg = strtok (NIL,"\015\012")) && ((i = strlen (arg)) > 3) &&
 145.442 +	  (arg[i - 1] == '}') && (arg[i - 2] == '+') && isdigit (arg[i - 3])) {
 145.443 +				/* back over possible count */
 145.444 +	for (i -= 4; i && isdigit (arg[i]); i--);
 145.445 +	if (arg[i] == '{') {	/* found a literal? */
 145.446 +	  litplus.ok = T;	/* yes, note LITERAL+ in effect, set size */
 145.447 +	  litplus.size = strtoul (arg + i + 1,NIL,10);
 145.448 +	}
 145.449 +      }
 145.450 +
 145.451 +				/* these commands always valid */
 145.452 +      if (!strcmp (cmd,"NOOP")) {
 145.453 +	if (arg) response = badarg;
 145.454 +	else if (stream)	/* allow untagged EXPUNGE */
 145.455 +	  mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
 145.456 +      }
 145.457 +      else if (!strcmp (cmd,"LOGOUT")) {
 145.458 +	if (arg) response = badarg;
 145.459 +	else {			/* time to say farewell */
 145.460 +	  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 145.461 +	  if (lastsel) fs_give ((void **) &lastsel);
 145.462 +	  if (state == OPEN) stream = mail_close (stream);
 145.463 +	  state = LOGOUT;
 145.464 +	  PSOUT ("* BYE ");
 145.465 +	  PSOUT (mylocalhost ());
 145.466 +	  PSOUT (" IMAP4rev1 server terminating connection\015\012");
 145.467 +	}
 145.468 +      }
 145.469 +      else if (!strcmp (cmd,"CAPABILITY")) {
 145.470 +	if (arg) response = badarg;
 145.471 +	else {
 145.472 +	  PSOUT ("* ");
 145.473 +	  pcapability (0);	/* print capabilities */
 145.474 +	  CRLF;
 145.475 +	}
 145.476 +	if (stream)		/* allow untagged EXPUNGE */
 145.477 +	  mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
 145.478 +      }
 145.479 +#ifdef NETSCAPE_BRAIN_DAMAGE
 145.480 +      else if (!strcmp (cmd,"NETSCAPE")) {
 145.481 +	PSOUT ("* OK [NETSCAPE]\015\012* VERSION 1.0 UNIX\015\012* ACCOUNT-URL \"");
 145.482 +	PSOUT (NETSCAPE_BRAIN_DAMAGE);
 145.483 +	PBOUT ('"');
 145.484 +	CRLF;
 145.485 +      }
 145.486 +#endif
 145.487 +
 145.488 +      else switch (state) {	/* dispatch depending upon state */
 145.489 +      case LOGIN:		/* waiting to get logged in */
 145.490 +				/* new style authentication */
 145.491 +	if (!strcmp (cmd,"AUTHENTICATE")) {
 145.492 +	  if (user) fs_give ((void **) &user);
 145.493 +	  if (pass) fs_give ((void **) &pass);
 145.494 +	  initial = NIL;	/* no initial argument */
 145.495 +	  cancelled = NIL;	/* not cancelled */
 145.496 +				/* mandatory first argument */
 145.497 +	  if (!(s = snarf (&arg))) response = misarg;
 145.498 +	  else if (arg && !(initial = snarf_base64 (&arg)))
 145.499 +	    response = misarg;	/* optional second argument */
 145.500 +	  else if (arg) response = badarg;
 145.501 +	  else if (!strcmp (ucase (s),"ANONYMOUS") && !stat (ANOFILE,&sbuf)) {
 145.502 +	    if (!(s = imap_responder ("",0,NIL)))
 145.503 +	      response ="%.80s BAD AUTHENTICATE ANONYMOUS cancelled\015\012";
 145.504 +	    else if (anonymous_login (argc,argv)) {
 145.505 +	      anonymous = T;	/* note we are anonymous */
 145.506 +	      user = cpystr ("ANONYMOUS");
 145.507 +	      pass = cpystr ("*");
 145.508 +	      state = SELECT;	/* make select */
 145.509 +	      alerttime = 0;	/* force alert */
 145.510 +	      response = logwin;/* return logged-in capabilities */
 145.511 +	      syslog (LOG_INFO,"Authenticated anonymous=%.80s host=%.80s",s,
 145.512 +		      tcp_clienthost ());
 145.513 +	      fs_give ((void **) &s);
 145.514 +	    }
 145.515 +	    else response ="%.80s NO AUTHENTICATE ANONYMOUS failed\015\012";
 145.516 +	  }
 145.517 +	  else if (user = cpystr (mail_auth (s,imap_responder,argc,argv))) {
 145.518 +	    pass = cpystr ("*");
 145.519 +	    state = SELECT;	/* make select */
 145.520 +	    alerttime = 0;	/* force alert */
 145.521 +	    response = logwin;	/* return logged-in capabilities */
 145.522 +	    syslog (LOG_INFO,"Authenticated user=%.80s host=%.80s mech=%.80s",
 145.523 +		    user,tcp_clienthost (),s);
 145.524 +	  }
 145.525 +
 145.526 +	  else {
 145.527 +	    AUTHENTICATOR *auth = mail_lookup_auth (1);
 145.528 +	    char *msg = (char *) fs_get (strlen (cmd) + strlen (s) + 2);
 145.529 +	    sprintf (msg,"%s %s",cmd,s);
 145.530 +	    fs_give ((void **) &cmd);
 145.531 +	    cmd = msg;
 145.532 +	    for (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL);
 145.533 +		 auth && compare_cstring (s,auth->name); auth = auth->next);
 145.534 +	    /* Failed authentication when hidden looks like invalid command.
 145.535 +	     * This is intentional but confused me when I was debugging.
 145.536 +	     */
 145.537 +	    if (auth && auth->server && !(auth->flags & AU_DISABLE) &&
 145.538 +		!(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
 145.539 +	      response = lose;
 145.540 +	      if (cancelled) {
 145.541 +		if (lsterr) fs_give ((void **) &lsterr);
 145.542 +		lsterr = cpystr ("cancelled by user");
 145.543 +	      }
 145.544 +	      if (!lsterr)	/* catch-all */
 145.545 +		lsterr = cpystr ("Invalid authentication credentials");
 145.546 +	      syslog (LOG_INFO,"AUTHENTICATE %.80s failure host=%.80s",s,
 145.547 +		      tcp_clienthost ());
 145.548 +	    }
 145.549 +	    else {
 145.550 +	      response = badcmd;
 145.551 +	      syslog (LOG_INFO,"AUTHENTICATE %.80s invalid host=%.80s",s,
 145.552 +		      tcp_clienthost ());
 145.553 +	    }
 145.554 +	  }
 145.555 +	}
 145.556 +
 145.557 +				/* plaintext login with password */
 145.558 +	else if (!strcmp (cmd,"LOGIN")) {
 145.559 +	  if (user) fs_give ((void **) &user);
 145.560 +	  if (pass) fs_give ((void **) &pass);
 145.561 +				/* two arguments */
 145.562 +	  if (!((user = cpystr (snarf (&arg))) &&
 145.563 +		(pass = cpystr (snarf (&arg))))) response = misarg;
 145.564 +	  else if (arg) response = badarg;
 145.565 +				/* see if we allow anonymous */
 145.566 +	  else if (!compare_cstring (user,"ANONYMOUS") &&
 145.567 +		   !stat (ANOFILE,&sbuf) && anonymous_login (argc,argv)) {
 145.568 +	    anonymous = T;	/* note we are anonymous */
 145.569 +	    ucase (user);	/* make all uppercase for consistency */
 145.570 +	    state = SELECT;	/* make select */
 145.571 +	    alerttime = 0;	/* force alert */
 145.572 +	    response = logwin;	/* return logged-in capabilities */
 145.573 +	    syslog (LOG_INFO,"Login anonymous=%.80s host=%.80s",pass,
 145.574 +		    tcp_clienthost ());
 145.575 +	  }
 145.576 +	  else {		/* delimit user from possible admin */
 145.577 +	    if (s = strchr (user,'*')) *s++ ='\0';
 145.578 +				/* see if username and password are OK */
 145.579 +	    if (server_login (user,pass,s,argc,argv)) {
 145.580 +	      state = SELECT;	/* make select */
 145.581 +	      alerttime = 0;	/* force alert */
 145.582 +	      response = logwin;/* return logged-in capabilities */
 145.583 +	      syslog (LOG_INFO,"Login user=%.80s host=%.80s",user,
 145.584 +		      tcp_clienthost ());
 145.585 +	    }
 145.586 +	    else {
 145.587 +	      response = lose;
 145.588 +	      if (!lsterr) lsterr = cpystr ("Invalid login credentials");
 145.589 +	    }
 145.590 +	  }
 145.591 +	}
 145.592 +				/* start TLS security */
 145.593 +	else if (!strcmp (cmd,"STARTTLS")) {
 145.594 +	  if (arg) response = badarg;
 145.595 +	  else if (lsterr = ssl_start_tls (pgmname)) response = lose;
 145.596 +	}
 145.597 +	else response = badcmd;
 145.598 +	break;
 145.599 +
 145.600 +      case OPEN:		/* valid only when mailbox open */
 145.601 +				/* fetch mailbox attributes */
 145.602 +	if (!strcmp (cmd,"FETCH") || !strcmp (cmd,"UID FETCH")) {
 145.603 +	  if (!(arg && (s = strtok (arg," ")) && (t = strtok(NIL,"\015\012"))))
 145.604 +	    response = misarg;
 145.605 +	  else if (uid ? mail_uid_sequence (stream,s) :
 145.606 +		   mail_sequence (stream,s)) fetch (t,uid);
 145.607 +	  else response = badseq;
 145.608 +	}
 145.609 +				/* store mailbox attributes */
 145.610 +	else if (!strcmp (cmd,"STORE") || !strcmp (cmd,"UID STORE")) {
 145.611 +				/* must have three arguments */
 145.612 +	  if (!(arg && (s = strtok (arg," ")) && (v = strtok (NIL," ")) &&
 145.613 +		(t = strtok (NIL,"\015\012")))) response = misarg;
 145.614 +	  else if (!(uid ? mail_uid_sequence (stream,s) :
 145.615 +		     mail_sequence (stream,s))) response = badseq;
 145.616 +	  else {
 145.617 +	    f = ST_SET | (uid ? ST_UID : NIL)|((v[5]&&v[6]) ? ST_SILENT : NIL);
 145.618 +	    if (!strcmp (ucase (v),"FLAGS") || !strcmp (v,"FLAGS.SILENT")) {
 145.619 +	      strcpy (tmp,"\\Answered \\Flagged \\Deleted \\Draft \\Seen");
 145.620 +	      for (i = 0, u = tmp;
 145.621 +		   (i < NUSERFLAGS) && (v = stream->user_flags[i]); i++)
 145.622 +	        if (strlen (v) <
 145.623 +		    ((size_t) (MAILTMPLEN - ((u += strlen (u)) + 2 - tmp)))) {
 145.624 +		  *u++ = ' ';	/* write next flag */
 145.625 +		  strcpy (u,v);
 145.626 +		}
 145.627 +	      mail_flag (stream,s,tmp,f & ~ST_SET);
 145.628 +	    }
 145.629 +	    else if (!strcmp (v,"-FLAGS") || !strcmp (v,"-FLAGS.SILENT"))
 145.630 +	      f &= ~ST_SET;	/* clear flags */
 145.631 +	    else if (strcmp (v,"+FLAGS") && strcmp (v,"+FLAGS.SILENT")) {
 145.632 +	      response = badatt;
 145.633 +	      break;
 145.634 +	    }
 145.635 +				/* find last keyword */
 145.636 +	    for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; i++);
 145.637 +	    mail_flag (stream,s,t,f);
 145.638 +				/* any new keywords appeared? */
 145.639 +	    if (i < NUSERFLAGS && stream->user_flags[i]) new_flags (stream);
 145.640 +				/* return flags if silence not wanted */
 145.641 +	    if (uid ? mail_uid_sequence (stream,s) : mail_sequence (stream,s))
 145.642 +	      for (i = 1; i <= nmsgs; i++) if (mail_elt(stream,i)->sequence)
 145.643 +		mail_elt (stream,i)->spare2 = (f & ST_SILENT) ? NIL : T;
 145.644 +	  }
 145.645 +	}
 145.646 +
 145.647 +				/* check for new mail */
 145.648 +	else if (!strcmp (cmd,"CHECK")) {
 145.649 +				/* no arguments */
 145.650 +	  if (arg) response = badarg;
 145.651 +	  else if (!anonymous) {
 145.652 +	    mail_check (stream);
 145.653 +				/* remember last check time */
 145.654 +	    lastcheck = time (0);
 145.655 +	  }
 145.656 +	}
 145.657 +				/* expunge deleted messages */
 145.658 +	else if (!(anonymous || (strcmp (cmd,"EXPUNGE") &&
 145.659 +				 strcmp (cmd,"UID EXPUNGE")))) {
 145.660 +	  if (uid && !arg) response = misarg;
 145.661 +	  else if (!uid && arg) response = badarg;
 145.662 +	  else {		/* expunge deleted or specified UIDs */
 145.663 +	    mail_expunge_full (stream,arg,arg ? EX_UID : NIL);
 145.664 +				/* remember last checkpoint */
 145.665 +	    lastcheck = time (0);
 145.666 +	  }
 145.667 +	}
 145.668 +				/* close mailbox */
 145.669 +	else if (!strcmp (cmd,"CLOSE") || !strcmp (cmd,"UNSELECT")) {
 145.670 +				/* no arguments */
 145.671 +	  if (arg) response = badarg;
 145.672 +	  else {
 145.673 +				/* no last uid */
 145.674 +	    uidvalidity = lastuid = 0;
 145.675 +	    if (lastsel) fs_give ((void **) &lastsel);
 145.676 +	    if (lastid) fs_give ((void **) &lastid);
 145.677 +	    if (lastst.data) fs_give ((void **) &lastst.data);
 145.678 +	    stream = mail_close_full (stream,((*cmd == 'C') && !anonymous) ?
 145.679 +				      CL_EXPUNGE : NIL);
 145.680 +	    state = SELECT;	/* no longer opened */
 145.681 +	    lastcheck = 0;	/* no last checkpoint */
 145.682 +	  }
 145.683 +	}
 145.684 +	else if (!anonymous &&	/* copy message(s) */
 145.685 +		 (!strcmp (cmd,"COPY") || !strcmp (cmd,"UID COPY"))) {
 145.686 +	  trycreate = NIL;	/* no trycreate status */
 145.687 +	  if (!(arg && (s = strtok (arg," ")) && (arg = strtok(NIL,"\015\012"))
 145.688 +		&& (t = snarf (&arg)))) response = misarg;
 145.689 +	  else if (arg) response = badarg;
 145.690 +	  else if (!nmsgs) {
 145.691 +	    response = lose;
 145.692 +	    if (!lsterr) lsterr = cpystr ("Mailbox is empty");
 145.693 +	  }
 145.694 +	  else if (!(uid ? mail_uid_sequence (stream,s) :
 145.695 +		     mail_sequence (stream,s))) response = badseq;
 145.696 +				/* try copy */
 145.697 +	  else if (!mail_copy_full (stream,s,t,uid ? CP_UID : NIL)) {
 145.698 +	    response = trycreate ? losetry : lose;
 145.699 +	    if (!lsterr) lsterr = cpystr ("No such destination mailbox");
 145.700 +	  }
 145.701 +	}
 145.702 +
 145.703 +				/* sort mailbox */
 145.704 +	else if (!strcmp (cmd,"SORT") || !strcmp (cmd,"UID SORT")) {
 145.705 +				/* must have four arguments */
 145.706 +	  if (!(arg && (*arg == '(') && (t = strchr (s = arg + 1,')')) &&
 145.707 +		(t[1] == ' ') && (*(arg = t + 2)))) response = misarg;
 145.708 +	  else {		/* read criteria */
 145.709 +	    SEARCHPGM *spg = NIL;
 145.710 +	    char *cs = NIL;
 145.711 +	    SORTPGM *pgm = NIL,*pg = NIL;
 145.712 +	    unsigned long *slst,*sl;
 145.713 +	    *t = NIL;		/* tie off criteria list */
 145.714 +	    if (!(s = strtok (ucase (s)," "))) response = badatt;
 145.715 +	    else {
 145.716 +	      do {		/* parse sort attributes */
 145.717 +		if (pg) pg = pg->next = mail_newsortpgm ();
 145.718 +		else pgm = pg = mail_newsortpgm ();
 145.719 +		if (!strcmp (s,"REVERSE")) {
 145.720 +		  pg->reverse = T;
 145.721 +		  if (!(s = strtok (NIL," "))) {
 145.722 +		    s = "";	/* end of attributes */
 145.723 +		    break;
 145.724 +		  }
 145.725 +		}
 145.726 +		if (!strcmp (s,"DATE")) pg->function = SORTDATE;
 145.727 +		else if (!strcmp (s,"ARRIVAL")) pg->function = SORTARRIVAL;
 145.728 +		else if (!strcmp (s,"FROM")) pg->function = SORTFROM;
 145.729 +		else if (!strcmp (s,"SUBJECT")) pg->function = SORTSUBJECT;
 145.730 +		else if (!strcmp (s,"TO")) pg->function = SORTTO;
 145.731 +		else if (!strcmp (s,"CC")) pg->function = SORTCC;
 145.732 +		else if (!strcmp (s,"SIZE")) pg->function = SORTSIZE;
 145.733 +		else break;
 145.734 +	      } while (s = strtok (NIL," "));
 145.735 +				/* bad SORT attribute */
 145.736 +	      if (s) response = badatt;
 145.737 +				/* get charset and search criteria */
 145.738 +	      else if (!((t = snarf (&arg)) && (cs = cpystr (t)) && arg &&
 145.739 +			 *arg)) response = misarg;
 145.740 +				/* parse search criteria  */
 145.741 +	      else if (!parse_criteria (spg = mail_newsearchpgm (),&arg,nmsgs,
 145.742 +					uidmax (stream),0)) response = badatt;
 145.743 +	      else if (arg && *arg) response = badarg;
 145.744 +	      else if (slst = mail_sort (stream,cs,spg,pgm,uid ? SE_UID:NIL)) {
 145.745 +		PSOUT ("* SORT");
 145.746 +		for (sl = slst; *sl; sl++) {
 145.747 +		  PBOUT (' ');
 145.748 +		  pnum (*sl);
 145.749 +		}
 145.750 +		CRLF;
 145.751 +		fs_give ((void **) &slst);
 145.752 +	      }
 145.753 +	    }
 145.754 +	    if (pgm) mail_free_sortpgm (&pgm);
 145.755 +	    if (spg) mail_free_searchpgm (&spg);
 145.756 +	    if (cs) fs_give ((void **) &cs);
 145.757 +	  }
 145.758 +	}
 145.759 +
 145.760 +				/* thread mailbox */
 145.761 +	else if (!strcmp (cmd,"THREAD") || !strcmp (cmd,"UID THREAD")) {
 145.762 +	  THREADNODE *thr;
 145.763 +	  SEARCHPGM *spg = NIL;
 145.764 +	  char *cs = NIL;
 145.765 +				/* must have four arguments */
 145.766 +	  if (!(arg && (s = strtok (arg," ")) && (cs = strtok (NIL," ")) &&
 145.767 +		(cs = cpystr (cs)) && (arg = strtok (NIL,"\015\012"))))
 145.768 +	    response = misarg;
 145.769 +	  else if (!parse_criteria (spg = mail_newsearchpgm (),&arg,nmsgs,
 145.770 +				    uidmax (stream),0)) response = badatt;
 145.771 +	  else if (arg && *arg) response = badarg;
 145.772 +	  else {
 145.773 +	    if (thr = mail_thread (stream,s,cs,spg,uid ? SE_UID : NIL)) {
 145.774 +	      PSOUT ("* THREAD ");
 145.775 +	      pthread (thr);
 145.776 +	      mail_free_threadnode (&thr);
 145.777 +	    }
 145.778 +	    else PSOUT ("* THREAD");
 145.779 +	    CRLF;
 145.780 +	  }
 145.781 +	  if (spg) mail_free_searchpgm (&spg);
 145.782 +	  if (cs) fs_give ((void **) &cs);
 145.783 +	}
 145.784 +
 145.785 +				/* search mailbox */
 145.786 +        else if (!strcmp (cmd,"SEARCH") || !strcmp (cmd,"UID SEARCH")) {
 145.787 +	  int retval = NIL;
 145.788 +	  char *charset = NIL;
 145.789 +	  SEARCHPGM *pgm;
 145.790 +	  response = misarg;	/* assume failure */
 145.791 +	  if (!arg) break;	/* one or more arguments required */
 145.792 +	  if (((arg[0] == 'R') || (arg[0] == 'r')) &&
 145.793 +	      ((arg[1] == 'E') || (arg[1] == 'e')) &&
 145.794 +	      ((arg[2] == 'T') || (arg[2] == 't')) &&
 145.795 +	      ((arg[3] == 'U') || (arg[3] == 'u')) &&
 145.796 +	      ((arg[4] == 'R') || (arg[4] == 'r')) &&
 145.797 +	      ((arg[5] == 'N') || (arg[5] == 'n')) &&
 145.798 +	      (arg[6] == ' ') && (arg[7] == '(')) {
 145.799 +	    retval = 0x4000;	/* return is specified */
 145.800 +	    for (arg += 8; *arg && (*arg != ')'); ) {
 145.801 +	      if (((arg[0] == 'M') || (arg[0] == 'm')) &&
 145.802 +		  ((arg[1] == 'I') || (arg[1] == 'i')) &&
 145.803 +		  ((arg[2] == 'N') || (arg[2] == 'n')) &&
 145.804 +		  ((arg[3] == ' ') || (arg[3] == ')'))) {
 145.805 +		retval |= 0x1;
 145.806 +		arg += 3;
 145.807 +	      }
 145.808 +	      else if (((arg[0] == 'M') || (arg[0] == 'm')) &&
 145.809 +		       ((arg[1] == 'A') || (arg[1] == 'a')) &&
 145.810 +		       ((arg[2] == 'X') || (arg[2] == 'x')) &&
 145.811 +		       ((arg[3] == ' ') || (arg[3] == ')'))) {
 145.812 +		retval |= 0x2;
 145.813 +		arg += 3;
 145.814 +	      }
 145.815 +	      else if (((arg[0] == 'A') || (arg[0] == 'a')) &&
 145.816 +		       ((arg[1] == 'L') || (arg[1] == 'l')) &&
 145.817 +		       ((arg[2] == 'L') || (arg[2] == 'l')) &&
 145.818 +		       ((arg[3] == ' ') || (arg[3] == ')'))) {
 145.819 +		retval |= 0x4;
 145.820 +		arg += 3;
 145.821 +	      }
 145.822 +	      else if (((arg[0] == 'C') || (arg[0] == 'c')) &&
 145.823 +		       ((arg[1] == 'O') || (arg[1] == 'o')) &&
 145.824 +		       ((arg[2] == 'U') || (arg[2] == 'u')) &&
 145.825 +		       ((arg[3] == 'N') || (arg[3] == 'n')) &&
 145.826 +		       ((arg[4] == 'T') || (arg[4] == 't')) &&
 145.827 +		       ((arg[5] == ' ') || (arg[5] == ')'))) {
 145.828 +		retval |= 0x10;
 145.829 +		arg += 5;
 145.830 +	      }
 145.831 +	      else break;	/* unknown return value */
 145.832 +				/* more return values to come */
 145.833 +	      if ((*arg == ' ') && (arg[1] != ')')) ++arg;
 145.834 +	    }
 145.835 +				/* RETURN list must be properly terminated */
 145.836 +	    if ((*arg++ != ')') || (*arg++ != ' ')) break;
 145.837 +				/* default return value is ALL */
 145.838 +	    if (!(retval &= 0x3fff)) retval = 0x4;
 145.839 +	  }
 145.840 +
 145.841 +				/* character set specified? */
 145.842 +	  if (((arg[0] == 'C') || (arg[0] == 'c')) &&
 145.843 +	      ((arg[1] == 'H') || (arg[1] == 'h')) &&
 145.844 +	      ((arg[2] == 'A') || (arg[2] == 'a')) &&
 145.845 +	      ((arg[3] == 'R') || (arg[3] == 'r')) &&
 145.846 +	      ((arg[4] == 'S') || (arg[4] == 's')) &&
 145.847 +	      ((arg[5] == 'E') || (arg[5] == 'e')) &&
 145.848 +	      ((arg[6] == 'T') || (arg[6] == 't')) &&
 145.849 +	      (arg[7] == ' ')) {
 145.850 +	    arg += 8;		/* yes, skip over CHARSET token */
 145.851 +	    if (s = snarf (&arg)) charset = cpystr (s);
 145.852 +	    else break;		/* missing character set */
 145.853 +	  }
 145.854 +				/* must have arguments here */
 145.855 +	  if (!(arg && *arg)) break;
 145.856 +	  if (parse_criteria (pgm = mail_newsearchpgm (),&arg,nmsgs,
 145.857 +			      uidmax (stream),0) && !*arg) {
 145.858 +	    response = win;	/* looks good, try the search */
 145.859 +	    mail_search_full (stream,charset,pgm,SE_FREE);
 145.860 +				/* output search results if success */
 145.861 +	    if (response == win) {
 145.862 +	      if (retval) {	/* ESEARCH desired */
 145.863 +		PSOUT ("* ESEARCH (TAG ");
 145.864 +		pstring (tag);
 145.865 +		PBOUT (')');
 145.866 +		if (uid) PSOUT (" UID");
 145.867 +				/* wants MIN */
 145.868 +		if (retval & 0x1) {
 145.869 +		  for (i = 1; (i <= nmsgs) && !mail_elt (stream,i)->searched;
 145.870 +		       ++i);
 145.871 +		  if (i <= nmsgs) {
 145.872 +		    PSOUT (" MIN ");
 145.873 +		    pnum (uid ? mail_uid (stream,i) : i);
 145.874 +		  }
 145.875 +		}
 145.876 +				/* wants MAX */
 145.877 +		if (retval & 0x2) {
 145.878 +		  for (i = nmsgs; i && !mail_elt (stream,i)->searched; --i);
 145.879 +		  if (i) {
 145.880 +		    PSOUT (" MAX ");
 145.881 +		    pnum (uid ? mail_uid (stream,i) : i);
 145.882 +		  }
 145.883 +		}
 145.884 +
 145.885 +				/* wants ALL */
 145.886 +		if (retval & 0x4) {
 145.887 +		  unsigned long j;
 145.888 +				/* find first match */
 145.889 +		  for (i = 1; (i <= nmsgs) && !mail_elt (stream,i)->searched;
 145.890 +		       ++i);
 145.891 +		  if (i <= nmsgs) {
 145.892 +		    PSOUT (" ALL ");
 145.893 +		    pnum (uid ? mail_uid (stream,i) : i);
 145.894 +		    j = i;	/* last message output */
 145.895 +		  }
 145.896 +		  while (++i <= nmsgs) {
 145.897 +		    if (mail_elt (stream,i)->searched) {
 145.898 +		      while ((++i <= nmsgs) && mail_elt (stream,i)->searched);
 145.899 +				/* previous message is end of range */
 145.900 +		      if (j != --i) {
 145.901 +			PBOUT (':');
 145.902 +			pnum (uid ? mail_uid (stream,i) : i);
 145.903 +		      }
 145.904 +		    }
 145.905 +				/* search for next match */
 145.906 +		    while ((++i <= nmsgs) && !mail_elt (stream,i)->searched);
 145.907 +		    if (i <= nmsgs) {
 145.908 +		      PBOUT (',');
 145.909 +		      pnum (uid ? mail_uid (stream,i) : i);
 145.910 +		      j = i;	/* last message output */
 145.911 +		    }
 145.912 +		  }
 145.913 +		}
 145.914 +				/* wants COUNT */
 145.915 +		if (retval & 0x10) {
 145.916 +		  unsigned long j;
 145.917 +		  for (i = 1, j = 0; i <= nmsgs; ++i)
 145.918 +		    if (mail_elt (stream,i)->searched) ++j;
 145.919 +		  PSOUT (" COUNT ");
 145.920 +		  pnum (j);
 145.921 +		}
 145.922 +	      }
 145.923 +	      else {		/* standard search */
 145.924 +		PSOUT ("* SEARCH");
 145.925 +		for (i = 1; i <= nmsgs; ++i)
 145.926 +		  if (mail_elt (stream,i)->searched) {
 145.927 +		    PBOUT (' ');
 145.928 +		    pnum (uid ? mail_uid (stream,i) : i);
 145.929 +		  }
 145.930 +	      }
 145.931 +	      CRLF;
 145.932 +	    }
 145.933 +	  }
 145.934 +	  else mail_free_searchpgm (&pgm);
 145.935 +	  if (charset) fs_give ((void **) &charset);
 145.936 +	}
 145.937 +
 145.938 +	else			/* fall into select case */
 145.939 +      case SELECT:		/* valid whenever logged in */
 145.940 +				/* select new mailbox */
 145.941 +	  if (!(strcmp (cmd,"SELECT") && strcmp (cmd,"EXAMINE") &&
 145.942 +		strcmp (cmd,"BBOARD"))) {
 145.943 +				/* single argument */
 145.944 +	  if (!(s = snarf (&arg))) response = misarg;
 145.945 +	  else if (arg) response = badarg;
 145.946 +	  else if (nameok (NIL,s = bboardname (cmd,s))) {
 145.947 +	    DRIVER *factory = mail_valid (NIL,s,NIL);
 145.948 +	    f = (anonymous ? OP_ANONYMOUS + OP_READONLY : NIL) |
 145.949 +	      ((*cmd == 'S') ? NIL : OP_READONLY);
 145.950 +	    curdriver = NIL;	/* no drivers known */
 145.951 +				/* no last uid */
 145.952 +	    uidvalidity = lastuid = 0;
 145.953 +	    if (lastid) fs_give ((void **) &lastid);
 145.954 +	    if (lastst.data) fs_give ((void **) &lastst.data);
 145.955 +	    nflags = 0;		/* force update */
 145.956 +	    nmsgs = recent = 0xffffffff;
 145.957 +	    if (factory && !strcmp (factory->name,"phile") &&
 145.958 +		(stream = mail_open (stream,s,f | OP_SILENT)) &&
 145.959 +		(response == win)) {
 145.960 +	      BODY *b;
 145.961 +				/* see if proxy open */
 145.962 +	      if ((mail_elt (stream,1)->rfc822_size < 400) &&
 145.963 +		  mail_fetchstructure (stream,1,&b) && (b->type == TYPETEXT) &&
 145.964 +		  (t = mail_fetch_text (stream,1,NIL,&i,NIL)) &&
 145.965 +		  (i < MAILTMPLEN) && (t[0] == '{')) {
 145.966 +				/* copy and tie off */
 145.967 +		strncpy (tmp,t,i)[i] = '\0';
 145.968 +				/* nuke any trailing newline */
 145.969 +		if (t = strpbrk (tmp,"\r\n")) *t = '\0';
 145.970 +				/* try to open proxy */
 145.971 +		if ((tstream = mail_open (NIL,tmp,f | OP_SILENT)) &&
 145.972 +		    (response == win) && tstream->nmsgs) {
 145.973 +		  s = tmp;	/* got it, close the link */
 145.974 +		  mail_close (stream);
 145.975 +		  stream = tstream;
 145.976 +		  tstream = NIL;
 145.977 +		}
 145.978 +	      }
 145.979 +				/* now give the exists event */
 145.980 +	      stream->silent = NIL;
 145.981 +	      mm_exists (stream,stream->nmsgs);
 145.982 +	    }
 145.983 +	    else if (!factory && isnewsproxy (s)) {
 145.984 +	      sprintf (tmp,"{%.300s/nntp}%.300s",nntpproxy,(char *) s+6);
 145.985 +	      stream = mail_open (stream,tmp,f);
 145.986 +	    }
 145.987 +				/* open stream normally then */
 145.988 +	    else stream = mail_open (stream,s,f);
 145.989 +
 145.990 +	    if (stream && (response == win)) {
 145.991 +	      state = OPEN;	/* note state open */
 145.992 +	      if (lastsel) fs_give ((void **) &lastsel);
 145.993 +				/* canonicalize INBOX */
 145.994 +	      if (!compare_cstring (s,"#MHINBOX"))
 145.995 +		lastsel = cpystr ("#MHINBOX");
 145.996 +	      else lastsel = cpystr (compare_cstring (s,"INBOX") ?
 145.997 +				     (char *) s : "INBOX");
 145.998 +				/* note readonly/readwrite */
 145.999 +	      response = stream->rdonly ? rowin : rwwin;
145.1000 +	      if (anonymous)
145.1001 +		syslog (LOG_INFO,"Anonymous select of %.80s host=%.80s",
145.1002 +			stream->mailbox,tcp_clienthost ());
145.1003 +	      lastcheck = 0;	/* no last check */
145.1004 +	    }
145.1005 +	    else {		/* failed, nuke old selection */
145.1006 +	      if (stream) stream = mail_close (stream);
145.1007 +	      state = SELECT;	/* no mailbox open now */
145.1008 +	      if (lastsel) fs_give ((void **) &lastsel);
145.1009 +	      response = lose;	/* open failed */
145.1010 +	    }
145.1011 +	  }
145.1012 +	}
145.1013 +
145.1014 +				/* APPEND message to mailbox */
145.1015 +	else if (!(anonymous || strcmp (cmd,"APPEND"))) {
145.1016 +				/* parse mailbox name */
145.1017 +	  if ((s = snarf (&arg)) && arg) {
145.1018 +	    STRING st;		/* message stringstruct */
145.1019 +	    APPENDDATA ad;
145.1020 +	    ad.arg = arg;	/* command arguments */
145.1021 +				/* no message yet */
145.1022 +	    ad.flags = ad.date = ad.msg = NIL;
145.1023 +	    ad.message = &st;	/* pointer to stringstruct to use */
145.1024 +	    trycreate = NIL;	/* no trycreate status */
145.1025 +	    if (!mail_append_multiple (NIL,s,append_msg,(void *) &ad)) {
145.1026 +	      if (response == win) response = trycreate ? losetry : lose;
145.1027 +				/* this can happen with #driver. hack */
145.1028 +	      if (!lsterr) lsterr = cpystr ("No such destination mailbox");
145.1029 +	    }
145.1030 +				/* clean up any message text left behind */
145.1031 +	    if (ad.flags) fs_give ((void **) &ad.flags);
145.1032 +	    if (ad.date) fs_give ((void **) &ad.date);
145.1033 +	    if (ad.msg) fs_give ((void **) &ad.msg);
145.1034 +	  }
145.1035 +	  else response = misarg;
145.1036 +	  if (stream)		/* allow untagged EXPUNGE */
145.1037 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1038 +	}
145.1039 +				/* list mailboxes */
145.1040 +	else if (!strcmp (cmd,"LIST") || !strcmp (cmd,"RLIST")) {
145.1041 +				/* get reference and mailbox argument */
145.1042 +	  if (!((s = snarf (&arg)) && (t = snarf_list (&arg))))
145.1043 +	    response = misarg;
145.1044 +	  else if (arg) response = badarg;
145.1045 +				/* make sure anonymous can't do bad things */
145.1046 +	  else if (nameok (s,t)) {
145.1047 +	    if (newsproxypattern (s,t,tmp,LONGT)) {
145.1048 +	      proxylist = T;
145.1049 +	      mail_list (NIL,"",tmp);
145.1050 +	      proxylist = NIL;
145.1051 +	    }
145.1052 +	    else mail_list (NIL,s,t);
145.1053 +	  }
145.1054 +	  if (stream)		/* allow untagged EXPUNGE */
145.1055 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1056 +	}
145.1057 +				/* scan mailboxes */
145.1058 +	else if (!strcmp (cmd,"SCAN")) {
145.1059 +				/* get arguments */
145.1060 +	  if (!((s = snarf (&arg)) && (t = snarf_list (&arg)) &&
145.1061 +		(u = snarf (&arg)))) response = misarg;
145.1062 +	  else if (arg) response = badarg;
145.1063 +				/* make sure anonymous can't do bad things */
145.1064 +	  else if (nameok (s,t)) {
145.1065 +	    if (newsproxypattern (s,t,tmp,NIL))
145.1066 +	      mm_log ("SCAN not permitted for news",ERROR);
145.1067 +	    else mail_scan (NIL,s,t,u);
145.1068 +	  }
145.1069 +	  if (stream)		/* allow untagged EXPUNGE */
145.1070 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1071 +	}
145.1072 +				/* list subscribed mailboxes */
145.1073 +	else if (!strcmp (cmd,"LSUB") || !strcmp (cmd,"RLSUB")) {
145.1074 +				/* get reference and mailbox argument */
145.1075 +	  if (!((s = snarf (&arg)) && (t = snarf_list (&arg))))
145.1076 +	    response = misarg;
145.1077 +	  else if (arg) response = badarg;
145.1078 +				/* make sure anonymous can't do bad things */
145.1079 +	  else if (nameok (s,t)) {
145.1080 +	    if (newsproxypattern (s,t,tmp,NIL)) newsrc_lsub (NIL,tmp);
145.1081 +	    else mail_lsub (NIL,s,t);
145.1082 +	  }
145.1083 +	  if (stream)		/* allow untagged EXPUNGE */
145.1084 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1085 +	}
145.1086 +
145.1087 +				/* find mailboxes */
145.1088 +	else if (!strcmp (cmd,"FIND")) {
145.1089 +				/* get subcommand and true argument */
145.1090 +	  if (!(arg && (s = strtok (arg," \015\012")) && (s == cmd + 5) &&
145.1091 +		(cmd[4] = ' ') && ucase (s) &&
145.1092 +		(arg = strtok (NIL,"\015\012")) && (s = snarf_list (&arg))))
145.1093 +	    response = misarg;	/* missing required argument */
145.1094 +	  else if (arg) response = badarg;
145.1095 +				/* punt on single-char wildcards */
145.1096 +	  else if (strpbrk (s,"%?")) response =
145.1097 +	    "%.80s NO IMAP2 ? and %% wildcards not supported: %.80s\015\012";
145.1098 +	  else if (nameok (NIL,s)) {
145.1099 +	    finding = T;	/* note that we are FINDing */
145.1100 +				/* dispatch based on type */
145.1101 +	    if (!strcmp (cmd,"FIND MAILBOXES") && !anonymous)
145.1102 +	      mail_lsub (NIL,NIL,s);
145.1103 +	    else if (!strcmp (cmd,"FIND ALL.MAILBOXES")) {
145.1104 +				/* convert * to % for compatible behavior */
145.1105 +	      for (t = s; *t; t++) if (*t == '*') *t = '%';
145.1106 +	      mail_list (NIL,NIL,s);
145.1107 +	    }
145.1108 +	    else response = badcmd;
145.1109 +	  }
145.1110 +	  if (stream)		/* allow untagged EXPUNGE */
145.1111 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1112 +	}
145.1113 +
145.1114 +				/* status of mailbox */
145.1115 +	else if (!strcmp (cmd,"STATUS")) {
145.1116 +	  if (!((s = snarf (&arg)) && arg && (*arg++ == '(') &&
145.1117 +		(t = strchr (arg,')')) && (t - arg) && !t[1]))
145.1118 +	    response = misarg;
145.1119 +	  else {
145.1120 +	    f = NIL;		/* initially no flags */
145.1121 +	    *t = '\0';		/* tie off flag string */
145.1122 +				/* read flags */
145.1123 +	    t = strtok (ucase (arg)," ");
145.1124 +	    do {		/* parse each one; unknown generate warning */
145.1125 +	      if (!strcmp (t,"MESSAGES")) f |= SA_MESSAGES;
145.1126 +	      else if (!strcmp (t,"RECENT")) f |= SA_RECENT;
145.1127 +	      else if (!strcmp (t,"UNSEEN")) f |= SA_UNSEEN;
145.1128 +	      else if (!strcmp (t,"UIDNEXT")) f |= SA_UIDNEXT;
145.1129 +	      else if (!strcmp (t,"UIDVALIDITY")) f |= SA_UIDVALIDITY;
145.1130 +	      else {
145.1131 +		PSOUT ("* NO Unknown status flag ");
145.1132 +		PSOUT (t);
145.1133 +		CRLF;
145.1134 +	      }
145.1135 +	    } while (t = strtok (NIL," "));
145.1136 +	    ping_mailbox (uid);	/* in case the fool did STATUS on open mbx */
145.1137 +	    PFLUSH ();		/* make sure stdout is dumped in case slave */
145.1138 +	    if (!compare_cstring (s,"INBOX")) s = "INBOX";
145.1139 +	    else if (!compare_cstring (s,"#MHINBOX")) s = "#MHINBOX";
145.1140 +	    if (state == LOGOUT) response = lose;
145.1141 +				/* get mailbox status */
145.1142 +	    else if (lastsel && (!strcmp (s,lastsel) ||
145.1143 +				 (stream && !strcmp (s,stream->mailbox)))) {
145.1144 +	      unsigned long unseen;
145.1145 +				/* snarl at cretins which do this */
145.1146 +	      PSOUT ("* NO CLIENT BUG DETECTED: STATUS on selected mailbox: ");
145.1147 +	      PSOUT (s);
145.1148 +	      CRLF;
145.1149 +	      tmp[0] = ' '; tmp[1] = '\0';
145.1150 +	      if (f & SA_MESSAGES)
145.1151 +		sprintf (tmp + strlen (tmp)," MESSAGES %lu",stream->nmsgs);
145.1152 +	      if (f & SA_RECENT)
145.1153 +		sprintf (tmp + strlen (tmp)," RECENT %lu",stream->recent);
145.1154 +	      if (f & SA_UNSEEN) {
145.1155 +		for (i = 1,unseen = 0; i <= stream->nmsgs; i++)
145.1156 +		  if (!mail_elt (stream,i)->seen) unseen++;
145.1157 +		sprintf (tmp + strlen (tmp)," UNSEEN %lu",unseen);
145.1158 +	      }
145.1159 +	      if (f & SA_UIDNEXT)
145.1160 +		sprintf (tmp + strlen (tmp)," UIDNEXT %lu",stream->uid_last+1);
145.1161 +	      if (f & SA_UIDVALIDITY)
145.1162 +		sprintf (tmp + strlen(tmp)," UIDVALIDITY %lu",
145.1163 +			 stream->uid_validity);
145.1164 +	      tmp[1] = '(';
145.1165 +	      strcat (tmp,")\015\012");
145.1166 +	      PSOUT ("* STATUS ");
145.1167 +	      pastring (s);
145.1168 +	      PSOUT (tmp);
145.1169 +	    }
145.1170 +	    else if (isnewsproxy (s)) {
145.1171 +	      sprintf (tmp,"{%.300s/nntp}%.300s",nntpproxy,(char *) s+6);
145.1172 +	      if (!mail_status (NIL,tmp,f)) response = lose;
145.1173 +	    }
145.1174 +	    else if (!mail_status (NIL,s,f)) response = lose;
145.1175 +	  }
145.1176 +	  if (stream)		/* allow untagged EXPUNGE */
145.1177 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1178 +	}
145.1179 +
145.1180 +				/* subscribe to mailbox */
145.1181 +	else if (!(anonymous || strcmp (cmd,"SUBSCRIBE"))) {
145.1182 +				/* get <mailbox> or MAILBOX <mailbox> */
145.1183 +	  if (!(s = snarf (&arg))) response = misarg;
145.1184 +	  else if (arg) {	/* IMAP2bis form */
145.1185 +	    if (compare_cstring (s,"MAILBOX")) response = badarg;
145.1186 +	    else if (!(s = snarf (&arg))) response = misarg;
145.1187 +	    else if (arg) response = badarg;
145.1188 +	    else mail_subscribe (NIL,s);
145.1189 +	  }
145.1190 +	  else if (isnewsproxy (s)) newsrc_update (NIL,s+6,':');
145.1191 +	  else mail_subscribe (NIL,s);
145.1192 +	  if (stream)		/* allow untagged EXPUNGE */
145.1193 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1194 +	}
145.1195 +				/* unsubscribe to mailbox */
145.1196 +	else if (!(anonymous || strcmp (cmd,"UNSUBSCRIBE"))) {
145.1197 +				/* get <mailbox> or MAILBOX <mailbox> */
145.1198 +	  if (!(s = snarf (&arg))) response = misarg;
145.1199 +	  else if (arg) {	/* IMAP2bis form */
145.1200 +	    if (compare_cstring (s,"MAILBOX")) response = badarg;
145.1201 +	    else if (!(s = snarf (&arg))) response = misarg;
145.1202 +	    else if (arg) response = badarg;
145.1203 +	    else if (isnewsproxy (s)) newsrc_update (NIL,s+6,'!');
145.1204 +	    else mail_unsubscribe (NIL,s);
145.1205 +	  }
145.1206 +	  else mail_unsubscribe (NIL,s);
145.1207 +	  if (stream)		/* allow untagged EXPUNGE */
145.1208 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1209 +	}
145.1210 +
145.1211 +	else if (!strcmp (cmd,"NAMESPACE")) {
145.1212 +	  if (arg) response = badarg;
145.1213 +	  else {
145.1214 +	    NAMESPACE **ns = (NAMESPACE **) mail_parameters(NIL,GET_NAMESPACE,
145.1215 +							     NIL);
145.1216 +	    NAMESPACE *n;
145.1217 +	    PARAMETER *p;
145.1218 +	    PSOUT ("* NAMESPACE");
145.1219 +	    if (ns) for (i = 0; i < 3; i++) {
145.1220 +	      if (n = ns[i]) {
145.1221 +		PSOUT (" (");
145.1222 +		do {
145.1223 +		  PBOUT ('(');
145.1224 +		  pstring (n->name);
145.1225 +		  switch (n->delimiter) {
145.1226 +		  case '\\':	/* quoted delimiter */
145.1227 +		  case '"':
145.1228 +		    PSOUT (" \"\\\\\"");
145.1229 +		    break;
145.1230 +		  case '\0':	/* no delimiter */
145.1231 +		    PSOUT (" NIL");
145.1232 +		    break;
145.1233 +		  default:	/* unquoted delimiter */
145.1234 +		    PSOUT (" \"");
145.1235 +		    PBOUT (n->delimiter);
145.1236 +		    PBOUT ('"');
145.1237 +		    break;
145.1238 +		  }
145.1239 +				/* NAMESPACE extensions are hairy */
145.1240 +		  if (p = n->param) do {
145.1241 +		    PBOUT (' ');
145.1242 +		    pstring (p->attribute);
145.1243 +		    PSOUT (" (");
145.1244 +		    do pstring (p->value);
145.1245 +		    while (p->next && !p->next->attribute && (p = p->next));
145.1246 +		    PBOUT (')');
145.1247 +		  } while (p = p->next);
145.1248 +		  PBOUT (')');
145.1249 +		} while (n = n->next);
145.1250 +		PBOUT (')');
145.1251 +	      }
145.1252 +	      else PSOUT (" NIL");
145.1253 +	    }
145.1254 +	    else PSOUT (" NIL NIL NIL");
145.1255 +	    CRLF;
145.1256 +	  }
145.1257 +	  if (stream)		/* allow untagged EXPUNGE */
145.1258 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1259 +	}
145.1260 +
145.1261 +				/* create mailbox */
145.1262 +	else if (!(anonymous || strcmp (cmd,"CREATE"))) {
145.1263 +	  if (!(s = snarf (&arg))) response = misarg;
145.1264 +	  else if (arg) response = badarg;
145.1265 +	  else mail_create (NIL,s);
145.1266 +	  if (stream)		/* allow untagged EXPUNGE */
145.1267 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1268 +	}
145.1269 +				/* delete mailbox */
145.1270 +	else if (!(anonymous || strcmp (cmd,"DELETE"))) {
145.1271 +	  if (!(s = snarf (&arg))) response = misarg;
145.1272 +	  else if (arg) response = badarg;
145.1273 +	  else {		/* make sure not selected */
145.1274 +	    if (lastsel && (!strcmp (s,lastsel) ||
145.1275 +			    (stream && !strcmp (s,stream->mailbox))))
145.1276 +	      mm_log ("Can not DELETE the selected mailbox",ERROR);
145.1277 +	    else mail_delete (NIL,s);
145.1278 +	  }
145.1279 +	  if (stream)		/* allow untagged EXPUNGE */
145.1280 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1281 +	}
145.1282 +				/* rename mailbox */
145.1283 +	else if (!(anonymous || strcmp (cmd,"RENAME"))) {
145.1284 +	  if (!((s = snarf (&arg)) && (t = snarf (&arg)))) response = misarg;
145.1285 +	  else if (arg) response = badarg;
145.1286 +	  else {		/* make sure not selected */
145.1287 +	    if (!compare_cstring (s,"INBOX")) s = "INBOX";
145.1288 +	    else if (!compare_cstring (s,"#MHINBOX")) s = "#MHINBOX";
145.1289 +	    if (lastsel && (!strcmp (s,lastsel) ||
145.1290 +			    (stream && !strcmp (s,stream->mailbox))))
145.1291 +	      mm_log ("Can not RENAME the selected mailbox",ERROR);
145.1292 +	    else mail_rename (NIL,s,t);
145.1293 +	  }
145.1294 +	  if (stream)		/* allow untagged EXPUNGE */
145.1295 +	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
145.1296 +	}
145.1297 +
145.1298 +				/* idle mode */
145.1299 +	else if (!strcmp (cmd,"IDLE")) {
145.1300 +				/* no arguments */
145.1301 +	  if (arg) response = badarg;
145.1302 +	  else {		/* tell client ready for argument */
145.1303 +	    unsigned long donefake = 0;
145.1304 +	    PSOUT ("+ Waiting for DONE\015\012");
145.1305 +	    PFLUSH ();		/* dump output buffer */
145.1306 +				/* inactivity countdown */
145.1307 +	    i = ((TIMEOUT) / (IDLETIMER)) + 1;
145.1308 +	    do {		/* main idle loop */
145.1309 +	      if (!donefake) {	/* don't ping mailbox if faking */
145.1310 +		mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,
145.1311 +				 (void *) stream);
145.1312 +		ping_mailbox (uid);
145.1313 +				/* maybe do a checkpoint if not anonymous */
145.1314 +		if (!anonymous && stream && (time (0) > lastcheck + CHECKTIMER)) {
145.1315 +		  mail_check (stream);
145.1316 +				/* cancel likely altwin from mail_check() */
145.1317 +		  if (lsterr) fs_give ((void **) &lsterr);
145.1318 +		  if (lstwrn) fs_give ((void **) &lstwrn);
145.1319 +				/* remember last checkpoint */
145.1320 +		  lastcheck = time (0);
145.1321 +		}
145.1322 +	      }
145.1323 +	      if (lstwrn) {	/* have a warning? */
145.1324 +		PSOUT ("* NO ");
145.1325 +		PSOUT (lstwrn);
145.1326 +		CRLF;
145.1327 +		fs_give ((void **) &lstwrn);
145.1328 +	      }
145.1329 +	      if (!(i % 2)) {	/* prevent NAT timeouts */
145.1330 +		sprintf (tmp,"* OK Timeout in %lu minutes\015\012",
145.1331 +			 (i * IDLETIMER) / 60);
145.1332 +		PSOUT (tmp);
145.1333 +	      }
145.1334 +				/* two minutes before the end... */
145.1335 +	      if ((state == OPEN) && (i <= 2)) {
145.1336 +		sprintf (tmp,"* %lu EXISTS\015\012* %lu RECENT\015\012",
145.1337 +			 donefake = nmsgs + 1,recent + 1);
145.1338 +		PSOUT (tmp);	/* prod client to wake up */
145.1339 +	      }
145.1340 +	      PFLUSH ();	/* dump output buffer */
145.1341 +	    } while ((state != LOGOUT) && !INWAIT (IDLETIMER) && --i);
145.1342 +
145.1343 +				/* time to exit idle loop */
145.1344 +	    if (state != LOGOUT) {
145.1345 +	      if (i) {		/* still have time left? */
145.1346 +				/* yes, read expected DONE */
145.1347 +		slurp (tmp,MAILTMPLEN,INPUTTIMEOUT);
145.1348 +		if (((tmp[0] != 'D') && (tmp[0] != 'd')) ||
145.1349 +		    ((tmp[1] != 'O') && (tmp[1] != 'o')) ||
145.1350 +		    ((tmp[2] != 'N') && (tmp[2] != 'n')) ||
145.1351 +		    ((tmp[3] != 'E') && (tmp[3] != 'e')) ||
145.1352 +		    (((tmp[4] != '\015') || (tmp[5] != '\012')) &&
145.1353 +		     (tmp[4] != '\012')))
145.1354 +		  response = "%.80s BAD Bogus IDLE continuation\015\012";
145.1355 +		if (donefake) {	/* if faking at the end */
145.1356 +				/* send EXPUNGE (should be just 1) */
145.1357 +		  while (donefake > nmsgs) {
145.1358 +		    sprintf (tmp,"* %lu EXPUNGE\015\012",donefake--);
145.1359 +		    PSOUT (tmp);
145.1360 +		  }
145.1361 +		  sprintf (tmp,"* %lu EXISTS\015\012* %lu RECENT\015\012",
145.1362 +			   nmsgs,recent);
145.1363 +		  PSOUT (tmp);
145.1364 +		}
145.1365 +	      }
145.1366 +	      else clkint ();	/* otherwise do autologout action */
145.1367 +	    }
145.1368 +	  }
145.1369 +	}
145.1370 +	else response = badcmd;
145.1371 +	break;
145.1372 +      default:
145.1373 +        response = "%.80s BAD Unknown state for %.80s command\015\012";
145.1374 +	break;
145.1375 +      }
145.1376 +
145.1377 +      while (litplus.ok) {	/* any unread LITERAL+? */
145.1378 +	litplus.ok = NIL;	/* yes, cancel it now */
145.1379 +	clearerr (stdin);	/* clear stdin errors */
145.1380 +	status = "discarding unread literal";
145.1381 +				/* read literal and discard it */
145.1382 +	while (i = (litplus.size > MAILTMPLEN) ? MAILTMPLEN : litplus.size) {
145.1383 +	  if (state == LOGOUT) litplus.size = 0;
145.1384 +	  else {
145.1385 +	    settimeout (INPUTTIMEOUT);
145.1386 +	    if (PSINR (tmp,i)) litplus.size -= i;
145.1387 +	    else {
145.1388 +	      ioerror (stdin,status);
145.1389 +	      litplus.size = 0;	/* in case it continues */
145.1390 +	    }
145.1391 +	  }
145.1392 +	}
145.1393 +	settimeout (0);		/* stop timeout */
145.1394 +				/* get new command tail */
145.1395 +	slurp (tmp,MAILTMPLEN,INPUTTIMEOUT);
145.1396 +				/* locate end of line */
145.1397 +	if (t = strchr (tmp,'\012')) {
145.1398 +				/* back over CR */
145.1399 +	  if ((t > tmp) && (t[-1] == '\015')) --t;
145.1400 +	  *t = NIL;		/* tie off CRLF */
145.1401 +				/* possible LITERAL+? */
145.1402 +	  if (((i = strlen (tmp)) > 3) && (tmp[i - 1] == '}') &&
145.1403 +	      (tmp[i - 2] == '+') && isdigit (tmp[i - 3])) {
145.1404 +				/* back over possible count */
145.1405 +	    for (i -= 4; i && isdigit (tmp[i]); i--);
145.1406 +	    if (tmp[i] == '{') {	/* found a literal? */
145.1407 +	      litplus.ok = T;	/* yes, note LITERAL+ in effect, set size */
145.1408 +	      litplus.size = strtoul (tmp + i + 1,NIL,10);
145.1409 +	    }
145.1410 +	  }
145.1411 +	}
145.1412 +	else flush ();		/* overlong line after LITERAL+, punt */
145.1413 +      }
145.1414 +      ping_mailbox (uid);	/* update mailbox status before response */
145.1415 +      if (lstwrn && lsterr) {	/* output most recent warning */
145.1416 +	PSOUT ("* NO ");
145.1417 +	PSOUT (lstwrn);
145.1418 +	CRLF;
145.1419 +	fs_give ((void **) &lstwrn);
145.1420 +      }
145.1421 +
145.1422 +      if (response == logwin) {	/* authentication win message */
145.1423 +	sprintf (tmp,response,lstref ? "*" : tag);
145.1424 +	PSOUT (tmp);		/* start response */
145.1425 +	pcapability (1);	/* print logged-in capabilities */
145.1426 +	PSOUT ("] User ");
145.1427 +	PSOUT (user);
145.1428 +	PSOUT (" authenticated\015\012");
145.1429 +	if (lstref) {
145.1430 +	  sprintf (tmp,response,tag);
145.1431 +	  PSOUT (tmp);		/* start response */
145.1432 +	  PSOUT ("[REFERRAL ");
145.1433 +	  PSOUT (lstref);
145.1434 +	  PSOUT ("] ");
145.1435 +	  PSOUT (lasterror ());
145.1436 +	  CRLF;
145.1437 +	}
145.1438 +      }
145.1439 +      else if ((response == win) || (response == lose)) {
145.1440 +	sprintf (tmp,response,tag);
145.1441 +	PSOUT (tmp);
145.1442 +	if (cauidvalidity) {	/* COPYUID/APPENDUID response? */
145.1443 +	  sprintf (tmp,"[%.80sUID %lu ",(char *)
145.1444 +		   ((s = strchr (cmd,' ')) ? s+1 : cmd),cauidvalidity);
145.1445 +	  PSOUT (tmp);
145.1446 +	  cauidvalidity = 0;	/* cancel response for future */
145.1447 +	  if (csset) {
145.1448 +	    pset (&csset);
145.1449 +	    PBOUT (' ');
145.1450 +	  }
145.1451 +	  pset (&caset);
145.1452 +	  PSOUT ("] ");
145.1453 +	}
145.1454 +	else if (lstref) {	/* have a referral? */
145.1455 +	  PSOUT ("[REFERRAL ");
145.1456 +	  PSOUT (lstref);
145.1457 +	  PSOUT ("] ");
145.1458 +	}
145.1459 +	if (lsterr || lstwrn) PSOUT (lasterror ());
145.1460 +	else {
145.1461 +	  PSOUT (cmd);
145.1462 +	  PSOUT ((response == win) ? " completed" : "failed");
145.1463 +	}
145.1464 +	CRLF;
145.1465 +      }
145.1466 +      else {			/* normal response */
145.1467 +	if ((response == rowin) || (response == rwwin)) {
145.1468 +	  if (lstwrn) {		/* output most recent warning */
145.1469 +	    PSOUT ("* NO ");
145.1470 +	    PSOUT (lstwrn);
145.1471 +	    CRLF;
145.1472 +	    fs_give ((void **) &lstwrn);
145.1473 +	  }
145.1474 +	}
145.1475 +	sprintf (tmp,response,tag,cmd,lasterror ());
145.1476 +	PSOUT (tmp);		/* output response */
145.1477 +      }
145.1478 +    }
145.1479 +    PFLUSH ();			/* make sure output blatted */
145.1480 +
145.1481 +    if (autologouttime) {	/* have an autologout in effect? */
145.1482 +				/* cancel if no longer waiting for login */
145.1483 +      if (state != LOGIN) autologouttime = 0;
145.1484 +				/* took too long to login */
145.1485 +      else if (autologouttime < time (0)) {
145.1486 +	logout = goodbye = "Autologout";
145.1487 +	stream = NIL;
145.1488 +	state = LOGOUT;		/* sayonara */
145.1489 +      }
145.1490 +    }
145.1491 +  }
145.1492 +  if (goodbye && !quell_events){/* have a goodbye message? */
145.1493 +    PSOUT ("* BYE ");		/* utter it */
145.1494 +    PSOUT (goodbye);
145.1495 +    CRLF;
145.1496 +    PFLUSH ();			/* make sure blatted */
145.1497 +  }
145.1498 +  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
145.1499 +	  user ? (char *) user : "???",tcp_clienthost ());
145.1500 +				/* do logout hook if needed */
145.1501 +  if (lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL))
145.1502 +    (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
145.1503 +  _exit (ret);			/* all done */
145.1504 +  return ret;			/* stupid compilers */
145.1505 +}
145.1506 +
145.1507 +/* Ping mailbox during each cycle.  Also check alerts
145.1508 + * Accepts: last command was UID flag
145.1509 + */
145.1510 +
145.1511 +void ping_mailbox (unsigned long uid)
145.1512 +{
145.1513 +  unsigned long i;
145.1514 +  char tmp[MAILTMPLEN];
145.1515 +  if (state == OPEN) {
145.1516 +    if (!mail_ping (stream)) {	/* make sure stream still alive */
145.1517 +      PSOUT ("* BYE ");
145.1518 +      PSOUT (mylocalhost ());
145.1519 +      PSOUT (" Fatal mailbox error: ");
145.1520 +      PSOUT (lasterror ());
145.1521 +      CRLF;
145.1522 +      stream = NIL;		/* don't try to clean up stream */
145.1523 +      state = LOGOUT;		/* go away */
145.1524 +      syslog (LOG_INFO,
145.1525 +	      "Fatal mailbox error user=%.80s host=%.80s mbx=%.80s: %.80s",
145.1526 +	      user ? (char *) user : "???",tcp_clienthost (),
145.1527 +	      (stream && stream->mailbox) ? stream->mailbox : "???",
145.1528 +	      lasterror ());
145.1529 +      return;
145.1530 +    }
145.1531 +				/* change in number of messages? */
145.1532 +    if (existsquelled || (nmsgs != stream->nmsgs)) {
145.1533 +      PSOUT ("* ");
145.1534 +      pnum (nmsgs = stream->nmsgs);
145.1535 +      PSOUT (" EXISTS\015\012");
145.1536 +    }
145.1537 +				/* change in recent messages? */
145.1538 +    if (existsquelled || (recent != stream->recent)) {
145.1539 +      PSOUT ("* ");
145.1540 +      pnum (recent = stream->recent);
145.1541 +      PSOUT (" RECENT\015\012");
145.1542 +    }
145.1543 +    existsquelled = NIL;	/* don't do this until asked again */
145.1544 +    if (stream->uid_validity && (stream->uid_validity != uidvalidity)) {
145.1545 +      PSOUT ("* OK [UIDVALIDITY ");
145.1546 +      pnum (stream->uid_validity);
145.1547 +      PSOUT ("] UID validity status\015\012* OK [UIDNEXT ");
145.1548 +      pnum (stream->uid_last + 1);
145.1549 +      PSOUT ("] Predicted next UID\015\012");
145.1550 +      if (stream->uid_nosticky) {
145.1551 +	PSOUT ("* NO [UIDNOTSTICKY] Non-permanent unique identifiers: ");
145.1552 +	PSOUT (stream->mailbox);
145.1553 +	CRLF;
145.1554 +      }
145.1555 +      uidvalidity = stream->uid_validity;
145.1556 +    }
145.1557 +
145.1558 +				/* don't bother if driver changed */
145.1559 +    if (curdriver == stream->dtb) {
145.1560 +				/* first report any new flags */
145.1561 +      if ((nflags < NUSERFLAGS) && stream->user_flags[nflags])
145.1562 +	new_flags (stream);
145.1563 +      for (i = 1; i <= nmsgs; i++) if (mail_elt (stream,i)->spare2) {
145.1564 +	PSOUT ("* ");
145.1565 +	pnum (i);
145.1566 +	PSOUT (" FETCH (");
145.1567 +	fetch_flags (i,NIL);	/* output changed flags */
145.1568 +	if (uid) {		/* need to include UIDs in response? */
145.1569 +	  PBOUT (' ');
145.1570 +	  fetch_uid (i,NIL);
145.1571 +	}
145.1572 +	PSOUT (")\015\012");
145.1573 +      }
145.1574 +    }
145.1575 +    else {			/* driver changed */
145.1576 +      new_flags (stream);	/* send mailbox flags */
145.1577 +      if (curdriver) {		/* note readonly/write if possible change */
145.1578 +	PSOUT ("* OK [READ-");
145.1579 +	PSOUT (stream->rdonly ? "ONLY" : "WRITE");
145.1580 +	PSOUT ("] Mailbox status\015\012");
145.1581 +      }
145.1582 +      curdriver = stream->dtb;
145.1583 +      if (nmsgs) {		/* get flags for all messages */
145.1584 +	sprintf (tmp,"1:%lu",nmsgs);
145.1585 +	mail_fetch_flags (stream,tmp,NIL);
145.1586 +				/* don't do this if newsrc already did */
145.1587 +	if (!(curdriver->flags & DR_NEWS)) {
145.1588 +				/* find first unseen message */
145.1589 +	  for (i = 1; i <= nmsgs && mail_elt (stream,i)->seen; i++);
145.1590 +	  if (i <= nmsgs) {
145.1591 +	    PSOUT ("* OK [UNSEEN ");
145.1592 +	    pnum (i);
145.1593 +	    PSOUT ("] first unseen message in ");
145.1594 +	    PSOUT (stream->mailbox);
145.1595 +	    CRLF;
145.1596 +	  }
145.1597 +	}
145.1598 +      }
145.1599 +    }
145.1600 +  }
145.1601 +  if (shutdowntime && (time (0) > shutdowntime + SHUTDOWNTIMER)) {
145.1602 +    PSOUT ("* BYE Server shutting down\015\012");
145.1603 +    state = LOGOUT;
145.1604 +  }
145.1605 +				/* don't do these stat()s every cycle */
145.1606 +  else if (time (0) > alerttime + ALERTTIMER) { 
145.1607 +    struct stat sbuf;
145.1608 +				/* have a shutdown file? */
145.1609 +    if (!stat (SHUTDOWNFILE,&sbuf)) {
145.1610 +      PSOUT ("* OK [ALERT] Server shutting down shortly\015\012");
145.1611 +      shutdowntime = time (0);
145.1612 +    }
145.1613 +    alerttime = time (0);	/* output any new alerts */
145.1614 +    sysalerttime = palert (ALERTFILE,sysalerttime);
145.1615 +    if (state != LOGIN)		/* do user alert if logged in */
145.1616 +      useralerttime = palert (mailboxfile (tmp,USERALERTFILE),useralerttime);
145.1617 +  }
145.1618 +}
145.1619 +
145.1620 +/* Print an alert file
145.1621 + * Accepts: path of alert file
145.1622 + *	    time of last printed alert file
145.1623 + * Returns: updated time of last printed alert file
145.1624 + */
145.1625 +
145.1626 +time_t palert (char *file,time_t oldtime)
145.1627 +{
145.1628 +  FILE *alf;
145.1629 +  struct stat sbuf;
145.1630 +  int c,lc = '\012';
145.1631 +				/* have a new alert file? */
145.1632 +  if (stat (file,&sbuf) || (sbuf.st_mtime <= oldtime) ||
145.1633 +      !(alf = fopen (file,"r"))) return oldtime;
145.1634 +				/* yes, display it */
145.1635 +  while ((c = getc (alf)) != EOF) {
145.1636 +    if (lc == '\012') PSOUT ("* OK [ALERT] ");
145.1637 +    switch (c) {		/* output character */
145.1638 +    case '\012':		/* newline means do CRLF */
145.1639 +      CRLF;
145.1640 +    case '\015':		/* flush CRs */
145.1641 +    case '\0':			/* flush nulls */
145.1642 +      break;
145.1643 +    default:
145.1644 +      PBOUT (c);		/* output all other characters */
145.1645 +      break;
145.1646 +    }
145.1647 +    lc = c;			/* note previous character */
145.1648 +  }
145.1649 +  fclose (alf);
145.1650 +  if (lc != '\012') CRLF;	/* final terminating CRLF */
145.1651 +  return sbuf.st_mtime;		/* return updated last alert time */
145.1652 +}
145.1653 +
145.1654 +/* Initialize file string structure for file stringstruct
145.1655 + * Accepts: string structure
145.1656 + *	    pointer to message data structure
145.1657 + *	    size of string
145.1658 + */
145.1659 +
145.1660 +void msg_string_init (STRING *s,void *data,unsigned long size)
145.1661 +{
145.1662 +  MSGDATA *md = (MSGDATA *) data;
145.1663 +  s->data = data;		/* note stream/msgno and header length */
145.1664 +#if 0
145.1665 +  s->size = size;		/* message size */
145.1666 +  s->curpos = s->chunk =	/* load header */
145.1667 +    mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,
145.1668 +			   FT_PREFETCHTEXT | FT_PEEK);
145.1669 +#else	/* This kludge is necessary because of broken mail stores */
145.1670 +  mail_fetchtext_full (md->stream,md->msgno,&s->size,FT_PEEK);
145.1671 +  s->curpos = s->chunk =	/* load header */
145.1672 +    mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,FT_PEEK);
145.1673 +  s->size += s->data1;		/* header + body size */
145.1674 +#endif
145.1675 +  s->cursize = s->chunksize = s->data1;
145.1676 +  s->offset = 0;		/* offset is start of message */
145.1677 +}
145.1678 +
145.1679 +
145.1680 +/* Get next character from file stringstruct
145.1681 + * Accepts: string structure
145.1682 + * Returns: character, string structure chunk refreshed
145.1683 + */
145.1684 +
145.1685 +char msg_string_next (STRING *s)
145.1686 +{
145.1687 +  char c = *s->curpos++;	/* get next byte */
145.1688 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
145.1689 +  return c;			/* return the byte */
145.1690 +}
145.1691 +
145.1692 +
145.1693 +/* Set string pointer position for file stringstruct
145.1694 + * Accepts: string structure
145.1695 + *	    new position
145.1696 + */
145.1697 +
145.1698 +void msg_string_setpos (STRING *s,unsigned long i)
145.1699 +{
145.1700 +  MSGDATA *md = (MSGDATA *) s->data;
145.1701 +  if (i < s->data1) {		/* want header? */
145.1702 +    s->chunk = mail_fetchheader_full (md->stream,md->msgno,NIL,NIL,FT_PEEK);
145.1703 +    s->chunksize = s->data1;	/* header length */
145.1704 +    s->offset = 0;		/* offset is start of message */
145.1705 +  }
145.1706 +  else if (i < s->size) {	/* want body */
145.1707 +    s->chunk = mail_fetchtext_full (md->stream,md->msgno,NIL,FT_PEEK);
145.1708 +    s->chunksize = s->size - s->data1;
145.1709 +    s->offset = s->data1;	/* offset is end of header */
145.1710 +  }
145.1711 +  else {			/* off end of message */
145.1712 +    s->chunk = NIL;		/* make sure that we crack on this then */
145.1713 +    s->chunksize = 1;		/* make sure SNX cracks the right way... */
145.1714 +    s->offset = i;
145.1715 +  }
145.1716 +				/* initial position and size */
145.1717 +  s->curpos = s->chunk + (i -= s->offset);
145.1718 +  s->cursize = s->chunksize - i;
145.1719 +}
145.1720 +
145.1721 +/* Send flags for stream
145.1722 + * Accepts: MAIL stream
145.1723 + *	    scratch buffer
145.1724 + */
145.1725 +
145.1726 +void new_flags (MAILSTREAM *stream)
145.1727 +{
145.1728 +  int i,c;
145.1729 +  PSOUT ("* FLAGS (");
145.1730 +  for (i = 0; i < NUSERFLAGS; i++) if (stream->user_flags[i]) {
145.1731 +    PSOUT (stream->user_flags[i]);
145.1732 +    PBOUT (' ');
145.1733 +    nflags = i + 1;
145.1734 +  }
145.1735 +  PSOUT ("\\Answered \\Flagged \\Deleted \\Draft \\Seen)\015\012* OK [PERMANENTFLAGS (");
145.1736 +  for (i = c = 0; i < NUSERFLAGS; i++)
145.1737 +    if ((stream->perm_user_flags & (1 << i)) && stream->user_flags[i])
145.1738 +      put_flag (&c,stream->user_flags[i]);
145.1739 +  if (stream->kwd_create) put_flag (&c,"\\*");
145.1740 +  if (stream->perm_answered) put_flag (&c,"\\Answered");
145.1741 +  if (stream->perm_flagged) put_flag (&c,"\\Flagged");
145.1742 +  if (stream->perm_deleted) put_flag (&c,"\\Deleted");
145.1743 +  if (stream->perm_draft) put_flag (&c,"\\Draft");
145.1744 +  if (stream->perm_seen) put_flag (&c,"\\Seen");
145.1745 +  PSOUT (")] Permanent flags\015\012");
145.1746 +}
145.1747 +
145.1748 +/* Set timeout
145.1749 + * Accepts: desired interval
145.1750 + */
145.1751 +
145.1752 +void settimeout (unsigned int i)
145.1753 +{
145.1754 +				/* limit if not logged in */
145.1755 +  if (i) alarm ((state == LOGIN) ? LOGINTIMEOUT : i);
145.1756 +  else alarm (0);
145.1757 +}
145.1758 +
145.1759 +
145.1760 +/* Clock interrupt
145.1761 + * Returns only if critical code in progress
145.1762 + */
145.1763 +
145.1764 +void clkint (void)
145.1765 +{
145.1766 +  settimeout (0);		/* disable all interrupts */
145.1767 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
145.1768 +  logout = "Autologout";
145.1769 +  goodbye = "Autologout (idle for too long)";
145.1770 +  if (critical) {		/* must defer if in critical code(?) */
145.1771 +    close (0);			/* kill stdin */
145.1772 +    state = LOGOUT;		/* die as soon as we can */
145.1773 +  }
145.1774 +  else longjmp (jmpenv,1);	/* die now */
145.1775 +}
145.1776 +
145.1777 +
145.1778 +/* Kiss Of Death interrupt
145.1779 + * Returns only if critical code in progress
145.1780 + */
145.1781 +
145.1782 +void kodint (void)
145.1783 +{
145.1784 +  settimeout (0);		/* disable all interrupts */
145.1785 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
145.1786 +  logout = goodbye = "Killed (lost mailbox lock)";
145.1787 +  if (critical) {		/* must defer if in critical code */
145.1788 +    close (0);			/* kill stdin */
145.1789 +    state = LOGOUT;		/* die as soon as we can */
145.1790 +  }
145.1791 +  else longjmp (jmpenv,1);	/* die now */
145.1792 +}
145.1793 +
145.1794 +/* Hangup interrupt
145.1795 + * Returns only if critical code in progress
145.1796 + */
145.1797 +
145.1798 +void hupint (void)
145.1799 +{
145.1800 +  settimeout (0);		/* disable all interrupts */
145.1801 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
145.1802 +  logout = "Hangup";
145.1803 +  goodbye = NIL;		/* other end is already gone */
145.1804 +  if (critical) {		/* must defer if in critical code */
145.1805 +    close (0);			/* kill stdin */
145.1806 +    close (1);			/* and stdout */
145.1807 +    state = LOGOUT;		/* die as soon as we can */
145.1808 +  }
145.1809 +  else longjmp (jmpenv,1);	/* die now */
145.1810 +}
145.1811 +
145.1812 +
145.1813 +/* Termination interrupt
145.1814 + * Returns only if critical code in progress
145.1815 + */
145.1816 +
145.1817 +void trmint (void)
145.1818 +{
145.1819 +  settimeout (0);		/* disable all interrupts */
145.1820 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
145.1821 +  logout = goodbye = "Killed (terminated)";
145.1822 +  /* Make no attempt at graceful closure since a shutdown may be in
145.1823 +   * progress, and we won't have any time to do mail_close() actions
145.1824 +   */
145.1825 +  stream = NIL;
145.1826 +  if (critical) {		/* must defer if in critical code */
145.1827 +    close (0);			/* kill stdin */
145.1828 +    close (1);			/* and stdout */
145.1829 +    state = LOGOUT;		/* die as soon as we can */
145.1830 +  }
145.1831 +  else longjmp (jmpenv,1);	/* die now */
145.1832 +}
145.1833 +
145.1834 +/* The routines on this and the next page eschew the use of non-syscall libc
145.1835 + * routines (especially stdio) for a reason.  Also, these hideous #if
145.1836 + * condtionals need to be replaced.
145.1837 + */
145.1838 +
145.1839 +#ifndef unix
145.1840 +#define unix 0
145.1841 +#endif
145.1842 +
145.1843 +
145.1844 +/* Status request interrupt
145.1845 + * Always returns
145.1846 + */
145.1847 +
145.1848 +void staint (void)
145.1849 +{
145.1850 +#if unix
145.1851 +  int fd;
145.1852 +  char *s,buf[8*MAILTMPLEN];
145.1853 +  unsigned long pid = getpid ();
145.1854 +				/* build file name */
145.1855 +  s = nout (sout (buf,"/tmp/imapd-status."),pid,10);
145.1856 +  if (user) s = sout (sout (s,"."),user);
145.1857 +  *s = '\0';			/* tie off file name */
145.1858 +  if ((fd = open (buf,O_WRONLY | O_CREAT | O_TRUNC,0666)) >= 0) {
145.1859 +    fchmod (fd,0666);
145.1860 +    s = nout (sout (buf,"PID="),pid,10);
145.1861 +    if (user) s = sout (sout (s,", user="),user);
145.1862 +    switch (state) {
145.1863 +    case LOGIN:
145.1864 +      s = sout (s,", not logged in");
145.1865 +      break;
145.1866 +    case SELECT:
145.1867 +      s = sout (s,", logged in");
145.1868 +      break;
145.1869 +    case OPEN:
145.1870 +      s = sout (s,", mailbox open");
145.1871 +      break;
145.1872 +    case LOGOUT:
145.1873 +      s = sout (s,", logging out");
145.1874 +      break;
145.1875 +    }
145.1876 +    if (stream && stream->mailbox)
145.1877 +      s = sout (sout (s,"\nmailbox="),stream->mailbox);
145.1878 +    *s++ = '\n';
145.1879 +    if (status) {
145.1880 +      s = sout (s,status);
145.1881 +      if (cmd) s = sout (sout (s,", last command="),cmd);
145.1882 +    }
145.1883 +    else s = sout (sout (s,cmd)," in progress");
145.1884 +    *s++ = '\n';
145.1885 +    write (fd,buf,s-buf);
145.1886 +    close (fd);
145.1887 +  }
145.1888 +#endif
145.1889 +}
145.1890 +
145.1891 +/* Write string
145.1892 + * Accepts: destination string pointer
145.1893 + *	    string
145.1894 + * Returns: updated string pointer
145.1895 + */
145.1896 +
145.1897 +char *sout (char *s,char *t)
145.1898 +{
145.1899 +  while (*t) *s++ = *t++;
145.1900 +  return s;
145.1901 +}
145.1902 +
145.1903 +
145.1904 +/* Write number
145.1905 + * Accepts: destination string pointer
145.1906 + *	    number
145.1907 + *	    base
145.1908 + * Returns: updated string pointer
145.1909 + */
145.1910 +
145.1911 +char *nout (char *s,unsigned long n,unsigned long base)
145.1912 +{
145.1913 +  char stack[256];
145.1914 +  char *t = stack;
145.1915 +				/* push PID digits on stack */
145.1916 +  do *t++ = (char) (n % base) + '0';
145.1917 +  while (n /= base);
145.1918 +				/* pop digits from stack */
145.1919 +  while (t > stack) *s++ = *--t;
145.1920 +  return s;
145.1921 +}
145.1922 +
145.1923 +/* Slurp a command line
145.1924 + * Accepts: buffer pointer
145.1925 + *	    buffer size
145.1926 + *	    input timeout
145.1927 + */
145.1928 +
145.1929 +void slurp (char *s,int n,unsigned long timeout)
145.1930 +{
145.1931 +  memset (s,'\0',n);		/* zap buffer */
145.1932 +  if (state != LOGOUT) {	/* get a command under timeout */
145.1933 +    settimeout (timeout);
145.1934 +    clearerr (stdin);		/* clear stdin errors */
145.1935 +    status = "reading line";
145.1936 +    if (!PSIN (s,n-1)) ioerror (stdin,status);
145.1937 +    settimeout (0);		/* make sure timeout disabled */
145.1938 +    status = NIL;
145.1939 +  }
145.1940 +}
145.1941 +
145.1942 +
145.1943 +/* Read a literal
145.1944 + * Accepts: destination buffer (must be size+1 for trailing NUL)
145.1945 + *	    size of buffer (must be less than 4294967295)
145.1946 + */
145.1947 +
145.1948 +void inliteral (char *s,unsigned long n)
145.1949 +{
145.1950 +  unsigned long i;
145.1951 +  if (litplus.ok) {		/* no more LITERAL+ to worry about */
145.1952 +    litplus.ok = NIL;
145.1953 +    litplus.size = 0;
145.1954 +  }
145.1955 +  else {			/* otherwise tell client ready for argument */
145.1956 +    PSOUT ("+ Ready for argument\015\012");
145.1957 +    PFLUSH ();			/* dump output buffer */
145.1958 +  }
145.1959 +  clearerr (stdin);		/* clear stdin errors */
145.1960 +  memset (s,'\0',n+1);		/* zap buffer */
145.1961 +  status = "reading literal";
145.1962 +  while (n) {			/* get data under timeout */
145.1963 +    if (state == LOGOUT) n = 0;
145.1964 +    else {
145.1965 +      settimeout (INPUTTIMEOUT);
145.1966 +      i = min (n,8192);		/* must read at least 8K within timeout */
145.1967 +      if (PSINR (s,i)) {
145.1968 +	s += i;
145.1969 +	n -= i;
145.1970 +      }
145.1971 +      else {
145.1972 +	ioerror (stdin,status);
145.1973 +	n = 0;			/* in case it continues */
145.1974 +      }
145.1975 +      settimeout (0);		/* stop timeout */
145.1976 +    }
145.1977 +  }
145.1978 +}
145.1979 +
145.1980 +/* Flush until newline seen
145.1981 + * Returns: NIL, always
145.1982 + */
145.1983 +
145.1984 +unsigned char *flush (void)
145.1985 +{
145.1986 +  int c;
145.1987 +  if (state != LOGOUT) {
145.1988 +    settimeout (INPUTTIMEOUT);
145.1989 +    clearerr (stdin);		/* clear stdin errors */
145.1990 +    status = "flushing line";
145.1991 +    while ((c = PBIN ()) != '\012') if (c == EOF) ioerror (stdin,status);
145.1992 +    settimeout (0);		/* make sure timeout disabled */
145.1993 +  }
145.1994 +  response = "%.80s BAD Command line too long\015\012";
145.1995 +  status = NIL;
145.1996 +  return NIL;
145.1997 +}
145.1998 +
145.1999 +
145.2000 +/* Report command stream error and die
145.2001 + * Accepts: stdin or stdout (whichever got the error)
145.2002 + *	    reason (what caller was doing)
145.2003 + */
145.2004 +
145.2005 +void ioerror (FILE *f,char *reason)
145.2006 +{
145.2007 +  static char msg[MAILTMPLEN];
145.2008 +  char *s,*t;
145.2009 +  if (logout) {			/* say nothing if already dying */
145.2010 +    settimeout (0);		/* disable all interrupts */
145.2011 +    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
145.2012 +				/* write error string */
145.2013 +    for (s = ferror (f) ? strerror (errno) : "Unexpected client disconnect",
145.2014 +	   t = logout = msg; *s; *t++ = *s++);
145.2015 +    for (s = ", while "; *s; *t++ = *s++);
145.2016 +    for (s = reason; *s; *t++ = *s++);
145.2017 +    if (critical) {		/* must defer if in critical code */
145.2018 +      close (0);		/* kill stdin */
145.2019 +      close (1);		/* and stdout */
145.2020 +      state = LOGOUT;		/* die as soon as we can */
145.2021 +    }
145.2022 +    else longjmp (jmpenv,1);	/* die now */
145.2023 +  }
145.2024 +}
145.2025 +
145.2026 +/* Parse an IMAP astring
145.2027 + * Accepts: pointer to argument text pointer
145.2028 + *	    pointer to returned size
145.2029 + *	    pointer to returned delimiter
145.2030 + * Returns: argument
145.2031 + */
145.2032 +
145.2033 +unsigned char *parse_astring (unsigned char **arg,unsigned long *size,
145.2034 +			      unsigned char *del)
145.2035 +{
145.2036 +  unsigned long i;
145.2037 +  unsigned char c,*s,*t,*v;
145.2038 +  if (!*arg) return NIL;	/* better be an argument */
145.2039 +  switch (**arg) {		/* see what the argument is */
145.2040 +  default:			/* atom */
145.2041 +    for (s = t = *arg, i = 0;
145.2042 +	 (*t > ' ') && (*t < 0x7f) && (*t != '(') && (*t != ')') &&
145.2043 +	 (*t != '{') && (*t != '%') && (*t != '*') && (*t != '"') &&
145.2044 +	 (*t != '\\'); ++t,++i);
145.2045 +    if (*size = i) break;	/* got atom if non-empty */
145.2046 +  case ')': case '%': case '*': case '\\': case '\0': case ' ':
145.2047 +   return NIL;			/* empty atom is a bogon */
145.2048 +  case '"':			/* hunt for trailing quote */
145.2049 +    for (s = t = v = *arg + 1; (c = *t++) != '"'; *v++ = c) {
145.2050 +				/* quote next character */
145.2051 +      if (c == '\\') switch (c = *t++) {
145.2052 +      case '"': case '\\': break;
145.2053 +      default: return NIL;	/* invalid quote-next */
145.2054 +      }
145.2055 +				/* else must be a CHAR */
145.2056 +      if (!c || (c & 0x80)) return NIL;
145.2057 +    }
145.2058 +    *v = '\0';			/* tie off string */
145.2059 +    *size = v - s;		/* return size */
145.2060 +    break;
145.2061 +
145.2062 +  case '{':			/* literal string */
145.2063 +    s = *arg + 1;		/* get size */
145.2064 +    if (!isdigit (*s)) return NIL;
145.2065 +    if ((*size = i = strtoul (s,(char **) &t,10)) > MAXCLIENTLIT) {
145.2066 +      mm_notify (NIL,"Absurdly long client literal",ERROR);
145.2067 +      syslog (LOG_INFO,"Overlong (%lu) client literal user=%.80s host=%.80s",
145.2068 +	      i,user ? (char *) user : "???",tcp_clienthost ());
145.2069 +      return NIL;
145.2070 +    }
145.2071 +    switch (*t) {		/* validate end of literal */
145.2072 +    case '+':			/* non-blocking literal */
145.2073 +      if (*++t != '}') return NIL;
145.2074 +    case '}':
145.2075 +      if (!t[1]) break;		/* OK if end of line */
145.2076 +    default:
145.2077 +      return NIL;		/* bad literal */
145.2078 +    }
145.2079 +    if (litsp >= LITSTKLEN) {	/* make sure don't overflow stack */
145.2080 +      mm_notify (NIL,"Too many literals in command",ERROR);
145.2081 +      return NIL;
145.2082 +    }
145.2083 +				/* get a literal buffer */
145.2084 +    inliteral (s = litstk[litsp++] = (char *) fs_get (i+1),i);
145.2085 +    				/* get new command tail */
145.2086 +    slurp (*arg = t,CMDLEN - (t - cmdbuf),INPUTTIMEOUT);
145.2087 +    if (!strchr (t,'\012')) return flush ();
145.2088 +				/* reset strtok mechanism, tie off if done */
145.2089 +    if (!strtok (t,"\015\012")) *t = '\0';
145.2090 +				/* possible LITERAL+? */
145.2091 +    if (((i = strlen (t)) > 3) && (t[i - 1] == '}') &&
145.2092 +	(t[i - 2] == '+') && isdigit (t[i - 3])) {
145.2093 +				/* back over possible count */
145.2094 +      for (i -= 4; i && isdigit (t[i]); i--);
145.2095 +      if (t[i] == '{') {	/* found a literal? */
145.2096 +	litplus.ok = T;		/* yes, note LITERAL+ in effect, set size */
145.2097 +	litplus.size = strtoul (t + i + 1,NIL,10);
145.2098 +      }
145.2099 +    }
145.2100 +    break;
145.2101 +  }
145.2102 +  if (*del = *t) {		/* have a delimiter? */
145.2103 +    *t++ = '\0';		/* yes, stomp on it */
145.2104 +    *arg = t;			/* update argument pointer */
145.2105 +  }
145.2106 +  else *arg = NIL;		/* no more arguments */
145.2107 +  return s;
145.2108 +}
145.2109 +
145.2110 +/* Snarf a command argument (simple jacket into parse_astring())
145.2111 + * Accepts: pointer to argument text pointer
145.2112 + * Returns: argument
145.2113 + */
145.2114 +
145.2115 +unsigned char *snarf (unsigned char **arg)
145.2116 +{
145.2117 +  unsigned long i;
145.2118 +  unsigned char c;
145.2119 +  unsigned char *s = parse_astring (arg,&i,&c);
145.2120 +  return ((c == ' ') || !c) ? s : NIL;
145.2121 +}
145.2122 +
145.2123 +
145.2124 +/* Snarf a BASE64 argument for SASL-IR
145.2125 + * Accepts: pointer to argument text pointer
145.2126 + * Returns: argument
145.2127 + */
145.2128 +
145.2129 +unsigned char *snarf_base64 (unsigned char **arg)
145.2130 +{
145.2131 +  unsigned char *ret = *arg;
145.2132 +  unsigned char *s = ret + 1;
145.2133 +  static char base64mask[256] = {
145.2134 +   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,
145.2135 +   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,
145.2136 +   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,
145.2137 +   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,
145.2138 +   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,
145.2139 +   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,
145.2140 +   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,
145.2141 +   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
145.2142 +  };
145.2143 +  if (*(ret = *arg) == '=');	/* easy case if zero-length argument */
145.2144 +				/* must be at least one BASE64 char */
145.2145 +  else if (!base64mask[*ret]) return NIL;
145.2146 +  else {			/* quick and dirty */
145.2147 +    while (base64mask[*s++]);	/* scan until end of BASE64 */
145.2148 +    if (*s == '=') ++s;		/* allow up to two padding chars */
145.2149 +    if (*s == '=') ++s;
145.2150 +  }
145.2151 +  switch (*s) {			/* anything following the argument? */
145.2152 +  case ' ':			/* another argument */
145.2153 +    *s++ = '\0';		/* tie off previous argument */
145.2154 +    *arg = s;			/* and update argument pointer */
145.2155 +    break;
145.2156 +  case '\0':			/* end of command */
145.2157 +    *arg = NIL;
145.2158 +    break;
145.2159 +  default:			/* syntax error */
145.2160 +    return NIL;
145.2161 +  }
145.2162 +  return ret;			/* return BASE64 string */
145.2163 +}
145.2164 +
145.2165 +/* Snarf a list command argument (simple jacket into parse_astring())
145.2166 + * Accepts: pointer to argument text pointer
145.2167 + * Returns: argument
145.2168 + */
145.2169 +
145.2170 +unsigned char *snarf_list (unsigned char **arg)
145.2171 +{
145.2172 +  unsigned long i;
145.2173 +  unsigned char c,*s,*t;
145.2174 +  if (!*arg) return NIL;	/* better be an argument */
145.2175 +  switch (**arg) {
145.2176 +  default:			/* atom and/or wildcard chars */
145.2177 +    for (s = t = *arg, i = 0;
145.2178 +	 (*t > ' ') && (*t != '(') && (*t != ')') && (*t != '{') &&
145.2179 +	 (*t != '"') && (*t != '\\'); ++t,++i);
145.2180 +    if (c = *t) {		/* have a delimiter? */
145.2181 +      *t++ = '\0';		/* stomp on it */
145.2182 +      *arg = t;			/* update argument pointer */
145.2183 +    }
145.2184 +    else *arg = NIL;
145.2185 +    break;
145.2186 +  case ')': case '\\': case '\0': case ' ':
145.2187 +    return NIL;			/* empty name is bogus */
145.2188 +  case '"':			/* quoted string? */
145.2189 +  case '{':			/* or literal? */
145.2190 +    s = parse_astring (arg,&i,&c);
145.2191 +    break;
145.2192 +  }
145.2193 +  return ((c == ' ') || !c) ? s : NIL;
145.2194 +}
145.2195 +
145.2196 +/* Get a list of header lines
145.2197 + * Accepts: pointer to string pointer
145.2198 + *	    pointer to list flag
145.2199 + * Returns: string list
145.2200 + */
145.2201 +
145.2202 +STRINGLIST *parse_stringlist (unsigned char **s,int *list)
145.2203 +{
145.2204 +  char c = ' ',*t;
145.2205 +  unsigned long i;
145.2206 +  STRINGLIST *ret = NIL,*cur = NIL;
145.2207 +  if (*s && **s == '(') {	/* proper list? */
145.2208 +    ++*s;			/* for each item in list */
145.2209 +    while ((c == ' ') && (t = parse_astring (s,&i,&c))) {
145.2210 +				/* get new block */
145.2211 +      if (cur) cur = cur->next = mail_newstringlist ();
145.2212 +      else cur = ret = mail_newstringlist ();
145.2213 +				/* note text */
145.2214 +      cur->text.data = (unsigned char *) fs_get (i + 1);
145.2215 +      memcpy (cur->text.data,t,i);
145.2216 +      cur->text.size = i;		/* and size */
145.2217 +    }
145.2218 +				/* must be end of list */
145.2219 +    if (c != ')') mail_free_stringlist (&ret);
145.2220 +  }
145.2221 +  if (t = *s) {			/* need to reload strtok() state? */
145.2222 +				/* end of a list? */
145.2223 +    if (*list && (*t == ')') && !t[1]) *list = NIL;
145.2224 +    else {
145.2225 +      *--t = ' ';		/* patch a space back in */
145.2226 +      *--t = 'x';		/* and a hokey character before that */
145.2227 +      t = strtok (t," ");	/* reset to *s */
145.2228 +    }
145.2229 +  }
145.2230 +  return ret;
145.2231 +}
145.2232 +
145.2233 +/* Get value of UID * for criteria parsing
145.2234 + * Accepts: stream
145.2235 + * Returns: maximum UID
145.2236 + */
145.2237 +
145.2238 +unsigned long uidmax (MAILSTREAM *stream)
145.2239 +{
145.2240 +  return stream->nmsgs ? mail_uid (stream,stream->nmsgs) : 0xffffffff;
145.2241 +}
145.2242 +
145.2243 +
145.2244 +/* Parse search criteria
145.2245 + * Accepts: search program to write criteria into
145.2246 + *	    pointer to argument text pointer
145.2247 + *	    maximum message number
145.2248 + *	    maximum UID
145.2249 + *	    logical nesting depth
145.2250 + * Returns: T if success, NIL if error
145.2251 + */
145.2252 +
145.2253 +long parse_criteria (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg,
145.2254 +		     unsigned long maxuid,unsigned long depth)
145.2255 +{
145.2256 +  if (arg && *arg) {		/* must be an argument */
145.2257 +				/* parse criteria */
145.2258 +    do if (!parse_criterion (pgm,arg,maxmsg,maxuid,depth)) return NIL;
145.2259 +				/* as long as a space delimiter */
145.2260 +    while (**arg == ' ' && (*arg)++);
145.2261 +				/* failed if not end of criteria */
145.2262 +    if (**arg && **arg != ')') return NIL;
145.2263 +  }
145.2264 +  return T;			/* success */
145.2265 +}
145.2266 +
145.2267 +/* Parse a search criterion
145.2268 + * Accepts: search program to write criterion into
145.2269 + *	    pointer to argument text pointer
145.2270 + *	    maximum message number
145.2271 + *	    maximum UID
145.2272 + *	    logical nesting depth
145.2273 + * Returns: T if success, NIL if error
145.2274 + */
145.2275 +
145.2276 +long parse_criterion (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg,
145.2277 +		      unsigned long maxuid,unsigned long depth)
145.2278 +{
145.2279 +  unsigned long i;
145.2280 +  unsigned char c = NIL,*s,*t,*v,*tail,*del;
145.2281 +  SEARCHSET **set;
145.2282 +  SEARCHPGMLIST **not;
145.2283 +  SEARCHOR **or;
145.2284 +  SEARCHHEADER **hdr;
145.2285 +  long ret = NIL;
145.2286 +				/* better be an argument */
145.2287 +  if ((depth > 500) || !(arg && *arg));
145.2288 +  else if (**arg == '(') {	/* list of criteria? */
145.2289 +    (*arg)++;			/* yes, parse the criteria */
145.2290 +    if (parse_criteria (pgm,arg,maxmsg,maxuid,depth+1) && **arg == ')') {
145.2291 +      (*arg)++;			/* skip closing paren */
145.2292 +      ret = T;			/* successful parse of list */
145.2293 +    }
145.2294 +  }
145.2295 +  else {			/* find end of criterion */
145.2296 +    if (!(tail = strpbrk ((s = *arg)," )"))) tail = *arg + strlen (*arg);
145.2297 +    c = *(del = tail);		/* remember the delimiter */
145.2298 +    *del = '\0';		/* tie off criterion */
145.2299 +    switch (*ucase (s)) {	/* dispatch based on character */
145.2300 +    case '*':			/* sequence */
145.2301 +    case '0': case '1': case '2': case '3': case '4':
145.2302 +    case '5': case '6': case '7': case '8': case '9':
145.2303 +      if (*(set = &pgm->msgno)){/* already a sequence? */
145.2304 +				/* silly, but not as silly as the client! */
145.2305 +	for (not = &pgm->not; *not; not = &(*not)->next);
145.2306 +	*not = mail_newsearchpgmlist ();
145.2307 +	set = &((*not)->pgm->not = mail_newsearchpgmlist ())->pgm->msgno;
145.2308 +      }
145.2309 +      ret = crit_set (set,&s,maxmsg) && (tail == s);
145.2310 +      break;
145.2311 +    case 'A':			/* possible ALL, ANSWERED */
145.2312 +      if (!strcmp (s+1,"LL")) ret = T;
145.2313 +      else if (!strcmp (s+1,"NSWERED")) ret = pgm->answered = T;
145.2314 +      break;
145.2315 +
145.2316 +    case 'B':			/* possible BCC, BEFORE, BODY */
145.2317 +      if (!strcmp (s+1,"CC") && c == ' ' && *++tail)
145.2318 +	ret = crit_string (&pgm->bcc,&tail);
145.2319 +      else if (!strcmp (s+1,"EFORE") && c == ' ' && *++tail)
145.2320 +	ret = crit_date (&pgm->before,&tail);
145.2321 +      else if (!strcmp (s+1,"ODY") && c == ' ' && *++tail)
145.2322 +	ret = crit_string (&pgm->body,&tail);
145.2323 +      break;
145.2324 +    case 'C':			/* possible CC */
145.2325 +      if (!strcmp (s+1,"C") && c == ' ' && *++tail)
145.2326 +	ret = crit_string (&pgm->cc,&tail);
145.2327 +      break;
145.2328 +    case 'D':			/* possible DELETED */
145.2329 +      if (!strcmp (s+1,"ELETED")) ret = pgm->deleted = T;
145.2330 +      if (!strcmp (s+1,"RAFT")) ret = pgm->draft = T;
145.2331 +      break;
145.2332 +    case 'F':			/* possible FLAGGED, FROM */
145.2333 +      if (!strcmp (s+1,"LAGGED")) ret = pgm->flagged = T;
145.2334 +      else if (!strcmp (s+1,"ROM") && c == ' ' && *++tail)
145.2335 +	ret = crit_string (&pgm->from,&tail);
145.2336 +      break;
145.2337 +    case 'H':			/* possible HEADER */
145.2338 +      if (!strcmp (s+1,"EADER") && c == ' ' && *(v = tail + 1) &&
145.2339 +	  (s = parse_astring (&v,&i,&c)) && i && c == ' ' &&
145.2340 +	  (t = parse_astring (&v,&i,&c))) {
145.2341 +	for (hdr = &pgm->header; *hdr; hdr = &(*hdr)->next);
145.2342 +	*hdr = mail_newsearchheader (s,t);
145.2343 +				/* update tail, restore delimiter */
145.2344 +	*(tail = v ? v - 1 : t + i) = c;
145.2345 +	ret = T;		/* success */
145.2346 +      }
145.2347 +      break;
145.2348 +    case 'K':			/* possible KEYWORD */
145.2349 +      if (!strcmp (s+1,"EYWORD") && c == ' ' && *++tail)
145.2350 +	ret = crit_string (&pgm->keyword,&tail);
145.2351 +      break;
145.2352 +    case 'L':
145.2353 +      if (!strcmp (s+1,"ARGER") && c == ' ' && *++tail)
145.2354 +	ret = crit_number (&pgm->larger,&tail);
145.2355 +      break;
145.2356 +    case 'N':			/* possible NEW, NOT */
145.2357 +      if (!strcmp (s+1,"EW")) ret = pgm->recent = pgm->unseen = T;
145.2358 +      else if (!strcmp (s+1,"OT") && c == ' ' && *++tail) {
145.2359 +	for (not = &pgm->not; *not; not = &(*not)->next);
145.2360 +	*not = mail_newsearchpgmlist ();
145.2361 +	ret = parse_criterion ((*not)->pgm,&tail,maxmsg,maxuid,depth+1);
145.2362 +      }
145.2363 +      break;
145.2364 +
145.2365 +    case 'O':			/* possible OLD, ON */
145.2366 +      if (!strcmp (s+1,"LD")) ret = pgm->old = T;
145.2367 +      else if (!strcmp (s+1,"N") && c == ' ' && *++tail)
145.2368 +	ret = crit_date (&pgm->on,&tail);
145.2369 +      else if (!strcmp (s+1,"R") && c == ' ') {
145.2370 +	for (or = &pgm->or; *or; or = &(*or)->next);
145.2371 +	*or = mail_newsearchor ();
145.2372 +	ret = *++tail && parse_criterion((*or)->first,&tail,maxmsg,maxuid,
145.2373 +					 depth+1) &&
145.2374 +	  (*tail == ' ') && *++tail &&
145.2375 +	  parse_criterion ((*or)->second,&tail,maxmsg,maxuid,depth+1);
145.2376 +      }
145.2377 +      else if (!strcmp (s+1,"LDER") && c == ' ' && *++tail)
145.2378 +	ret = crit_number (&pgm->older,&tail);
145.2379 +      break;
145.2380 +    case 'R':			/* possible RECENT */
145.2381 +      if (!strcmp (s+1,"ECENT")) ret = pgm->recent = T;
145.2382 +      break;
145.2383 +    case 'S':			/* possible SEEN, SINCE, SUBJECT */
145.2384 +      if (!strcmp (s+1,"EEN")) ret = pgm->seen = T;
145.2385 +      else if (!strcmp (s+1,"ENTBEFORE") && c == ' ' && *++tail)
145.2386 +	ret = crit_date (&pgm->sentbefore,&tail);
145.2387 +      else if (!strcmp (s+1,"ENTON") && c == ' ' && *++tail)
145.2388 +	ret = crit_date (&pgm->senton,&tail);
145.2389 +      else if (!strcmp (s+1,"ENTSINCE") && c == ' ' && *++tail)
145.2390 +	ret = crit_date (&pgm->sentsince,&tail);
145.2391 +      else if (!strcmp (s+1,"INCE") && c == ' ' && *++tail)
145.2392 +	ret = crit_date (&pgm->since,&tail);
145.2393 +      else if (!strcmp (s+1,"MALLER") && c == ' ' && *++tail)
145.2394 +	ret = crit_number (&pgm->smaller,&tail);
145.2395 +      else if (!strcmp (s+1,"UBJECT") && c == ' ' && *++tail)
145.2396 +	ret = crit_string (&pgm->subject,&tail);
145.2397 +      break;
145.2398 +    case 'T':			/* possible TEXT, TO */
145.2399 +      if (!strcmp (s+1,"EXT") && c == ' ' && *++tail)
145.2400 +	ret = crit_string (&pgm->text,&tail);
145.2401 +      else if (!strcmp (s+1,"O") && c == ' ' && *++tail)
145.2402 +	ret = crit_string (&pgm->to,&tail);
145.2403 +      break;
145.2404 +
145.2405 +    case 'U':			/* possible UID, UN* */
145.2406 +      if (!strcmp (s+1,"ID") && c== ' ' && *++tail) {
145.2407 +	if (*(set = &pgm->uid)){/* already a sequence? */
145.2408 +				/* silly, but not as silly as the client! */
145.2409 +	  for (not = &pgm->not; *not; not = &(*not)->next);
145.2410 +	  *not = mail_newsearchpgmlist ();
145.2411 +	  set = &((*not)->pgm->not = mail_newsearchpgmlist ())->pgm->uid;
145.2412 +	}
145.2413 +	ret = crit_set (set,&tail,maxuid);
145.2414 +      }
145.2415 +      else if (!strcmp (s+1,"NANSWERED")) ret = pgm->unanswered = T;
145.2416 +      else if (!strcmp (s+1,"NDELETED")) ret = pgm->undeleted = T;
145.2417 +      else if (!strcmp (s+1,"NDRAFT")) ret = pgm->undraft = T;
145.2418 +      else if (!strcmp (s+1,"NFLAGGED")) ret = pgm->unflagged = T;
145.2419 +      else if (!strcmp (s+1,"NKEYWORD") && c == ' ' && *++tail)
145.2420 +	ret = crit_string (&pgm->unkeyword,&tail);
145.2421 +      else if (!strcmp (s+1,"NSEEN")) ret = pgm->unseen = T;
145.2422 +      break;
145.2423 +    case 'Y':			/* possible YOUNGER */
145.2424 +      if (!strcmp (s+1,"OUNGER") && c == ' ' && *++tail)
145.2425 +	ret = crit_number (&pgm->younger,&tail);
145.2426 +      break;
145.2427 +    default:			/* oh dear */
145.2428 +      break;
145.2429 +    }
145.2430 +    if (ret) {			/* only bother if success */
145.2431 +      *del = c;			/* restore delimiter */
145.2432 +      *arg = tail;		/* update argument pointer */
145.2433 +    }
145.2434 +  }
145.2435 +  return ret;			/* return more to come */
145.2436 +}
145.2437 +
145.2438 +/* Parse a search date criterion
145.2439 + * Accepts: date to write into
145.2440 + *	    pointer to argument text pointer
145.2441 + * Returns: T if success, NIL if error
145.2442 + */
145.2443 +
145.2444 +long crit_date (unsigned short *date,unsigned char **arg)
145.2445 +{
145.2446 +  if (*date) return NIL;	/* can't double this value */
145.2447 +				/* handle quoted form */
145.2448 +  if (**arg != '"') return crit_date_work (date,arg);
145.2449 +  (*arg)++;			/* skip past opening quote */
145.2450 +  if (!(crit_date_work (date,arg) && (**arg == '"'))) return NIL;
145.2451 +  (*arg)++;			/* skip closing quote */
145.2452 +  return T;
145.2453 +}
145.2454 +
145.2455 +/* Worker routine to parse a search date criterion
145.2456 + * Accepts: date to write into
145.2457 + *	    pointer to argument text pointer
145.2458 + * Returns: T if success, NIL if error
145.2459 + */
145.2460 +
145.2461 +long crit_date_work (unsigned short *date,unsigned char **arg)
145.2462 +{
145.2463 +  int d,m,y;
145.2464 +				/* day */
145.2465 +  if (isdigit (d = *(*arg)++) || ((d == ' ') && isdigit (**arg))) {
145.2466 +    if (d == ' ') d = 0;	/* leading space */
145.2467 +    else d -= '0';		/* first digit */
145.2468 +    if (isdigit (**arg)) {	/* if a second digit */
145.2469 +      d *= 10;			/* slide over first digit */
145.2470 +      d += *(*arg)++ - '0';	/* second digit */
145.2471 +    }
145.2472 +    if ((**arg == '-') && (y = *++(*arg))) {
145.2473 +      m = (y >= 'a' ? y - 'a' : y - 'A') * 1024;
145.2474 +      if ((y = *++(*arg))) {
145.2475 +	m += (y >= 'a' ? y - 'a' : y - 'A') * 32;
145.2476 +	if ((y = *++(*arg))) {
145.2477 +	  m += (y >= 'a' ? y - 'a' : y - 'A');
145.2478 +	  switch (m) {		/* determine the month */
145.2479 +	  case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break;
145.2480 +	  case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break;
145.2481 +	  case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break;
145.2482 +	  case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break;
145.2483 +	  case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break;
145.2484 +	  case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break;
145.2485 +	  case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break;
145.2486 +	  case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break;
145.2487 +	  case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break;
145.2488 +	  case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10;break;
145.2489 +	  case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11;break;
145.2490 +	  case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12;break;
145.2491 +	  default: return NIL;
145.2492 +	  }
145.2493 +	  if ((*++(*arg) == '-') && isdigit (*++(*arg))) {
145.2494 +	    y = 0;		/* init year */
145.2495 +	    do {
145.2496 +	      y *= 10;		/* add this number */
145.2497 +	      y += *(*arg)++ - '0';
145.2498 +	    }
145.2499 +	    while (isdigit (**arg));
145.2500 +				/* minimal validity check of date */
145.2501 +	    if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0) return NIL; 
145.2502 +				/* time began on UNIX in 1970 */
145.2503 +	    if (y < 100) y += (y >= (BASEYEAR - 1900)) ? 1900 : 2000;
145.2504 +				/* return value */
145.2505 +	    *date = mail_shortdate (y - BASEYEAR,m,d);
145.2506 +	    return T;		/* success */
145.2507 +	  }
145.2508 +	}
145.2509 +      }
145.2510 +    }
145.2511 +  }
145.2512 +  return NIL;			/* else error */
145.2513 +}
145.2514 +
145.2515 +/* Parse a search set criterion
145.2516 + * Accepts: set to write into
145.2517 + *	    pointer to argument text pointer
145.2518 + *	    maximum value permitted
145.2519 + * Returns: T if success, NIL if error
145.2520 + */
145.2521 +
145.2522 +long crit_set (SEARCHSET **set,unsigned char **arg,unsigned long maxima)
145.2523 +{
145.2524 +  unsigned long i = 0;
145.2525 +  if (*set) return NIL;		/* can't double this value */
145.2526 +  *set = mail_newsearchset ();	/* instantiate a new search set */
145.2527 +  if (**arg == '*') {		/* maxnum? */
145.2528 +    (*arg)++;			/* skip past that number */
145.2529 +    (*set)->first = maxima;
145.2530 +  }
145.2531 +  else if (crit_number (&i,arg) && i) (*set)->first = i;
145.2532 +  else return NIL;		/* bogon */
145.2533 +  switch (**arg) {		/* decide based on delimiter */
145.2534 +  case ':':			/* sequence range */
145.2535 +    i = 0;			/* reset for crit_number() */
145.2536 +    if (*++(*arg) == '*') {	/* maxnum? */
145.2537 +      (*arg)++;			/* skip past that number */
145.2538 +      (*set)->last = maxima;
145.2539 +    }
145.2540 +    else if (crit_number (&i,arg) && i) {
145.2541 +      if (i < (*set)->first) {	/* backwards range */
145.2542 +	(*set)->last = (*set)->first;
145.2543 +	(*set)->first = i;
145.2544 +      }
145.2545 +      else (*set)->last = i;	/* set last number */
145.2546 +    }
145.2547 +    else return NIL;		/* bogon */
145.2548 +    if (**arg != ',') break;	/* drop into comma case if comma seen */
145.2549 +  case ',':
145.2550 +    (*arg)++;			/* skip past delimiter */
145.2551 +    return crit_set (&(*set)->next,arg,maxima);
145.2552 +  default:
145.2553 +    break;
145.2554 +  }
145.2555 +  return T;			/* return success */
145.2556 +}
145.2557 +
145.2558 +/* Parse a search number criterion
145.2559 + * Accepts: number to write into
145.2560 + *	    pointer to argument text pointer
145.2561 + * Returns: T if success, NIL if error
145.2562 + */
145.2563 +
145.2564 +long crit_number (unsigned long *number,unsigned char **arg)
145.2565 +{
145.2566 +				/* can't double this value */
145.2567 +  if (*number || !isdigit (**arg)) return NIL;
145.2568 +  *number = 0;
145.2569 +  while (isdigit (**arg)) {	/* found a digit? */
145.2570 +    *number *= 10;		/* add a decade */
145.2571 +    *number += *(*arg)++ - '0';	/* add number */
145.2572 +  }
145.2573 +  return T;
145.2574 +}
145.2575 +
145.2576 +
145.2577 +/* Parse a search string criterion
145.2578 + * Accepts: date to write into
145.2579 + *	    pointer to argument text pointer
145.2580 + * Returns: T if success, NIL if error
145.2581 + */
145.2582 +
145.2583 +long crit_string (STRINGLIST **string,unsigned char **arg)
145.2584 +{
145.2585 +  unsigned long i;
145.2586 +  char c;
145.2587 +  char *s = parse_astring (arg,&i,&c);
145.2588 +  if (!s) return NIL;
145.2589 +				/* find tail of list */
145.2590 +  while (*string) string = &(*string)->next;
145.2591 +  *string = mail_newstringlist ();
145.2592 +  (*string)->text.data = (unsigned char *) fs_get (i + 1);
145.2593 +  memcpy ((*string)->text.data,s,i);
145.2594 +  (*string)->text.data[i] = '\0';
145.2595 +  (*string)->text.size = i;
145.2596 +				/* if end of arguments, wrap it up here */
145.2597 +  if (!*arg) *arg = (char *) (*string)->text.data + i;
145.2598 +  else (*--(*arg) = c);		/* back up pointer, restore delimiter */
145.2599 +  return T;
145.2600 +}
145.2601 +
145.2602 +/* Fetch message data
145.2603 + * Accepts: string of data items to be fetched (must be writeable)
145.2604 + *	    UID fetch flag
145.2605 + */
145.2606 +
145.2607 +#define MAXFETCH 100
145.2608 +
145.2609 +void fetch (char *t,unsigned long uid)
145.2610 +{
145.2611 +  fetchfn_t f[MAXFETCH +2];
145.2612 +  void *fa[MAXFETCH + 2];
145.2613 +  int k;
145.2614 +  memset ((void *) f,NIL,sizeof (f));
145.2615 +  memset ((void *) fa,NIL,sizeof (fa));
145.2616 +  fetch_work (t,uid,f,fa);	/* do the work */
145.2617 +				/* clean up arguments */
145.2618 +  for (k = 1; f[k]; k++) if (fa[k]) (*f[k]) (0,fa[k]);
145.2619 +}
145.2620 +
145.2621 +
145.2622 +/* Fetch message data worker routine
145.2623 + * Accepts: string of data items to be fetched (must be writeable)
145.2624 + *	    UID fetch flag
145.2625 + *	    function dispatch vector
145.2626 + *	    function argument vector
145.2627 + */
145.2628 +
145.2629 +void fetch_work (char *t,unsigned long uid,fetchfn_t f[],void *fa[])
145.2630 +{
145.2631 +  unsigned char *s,*v;
145.2632 +  unsigned long i;
145.2633 +  unsigned long k = 0;
145.2634 +  BODY *b;
145.2635 +  int list = NIL;
145.2636 +  int parse_envs = NIL;
145.2637 +  int parse_bodies = NIL;
145.2638 +  if (uid) {			/* need to fetch UIDs? */
145.2639 +    fa[k] = NIL;		/* no argument */
145.2640 +    f[k++] = fetch_uid;		/* push a UID fetch on the stack */
145.2641 +  }
145.2642 +
145.2643 +				/* process macros */
145.2644 +  if (!strcmp (ucase (t),"ALL"))
145.2645 +    strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)");
145.2646 +  else if (!strcmp (t,"FULL"))
145.2647 +    strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)");
145.2648 +  else if (!strcmp (t,"FAST")) strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE)");
145.2649 +  if (list = (*t == '(')) t++;	/* skip open paren */
145.2650 +  if (s = strtok (t," ")) do {	/* parse attribute list */
145.2651 +    if (list && (i = strlen (s)) && (s[i-1] == ')')) {
145.2652 +      list = NIL;		/* done with list */
145.2653 +      s[i-1] = '\0';		/* tie off last item */
145.2654 +    }
145.2655 +    fa[k] = NIL;		/* default to no argument */
145.2656 +    if (!strcmp (s,"UID")) {	/* no-op if implicit */
145.2657 +      if (!uid) f[k++] = fetch_uid;
145.2658 +    }
145.2659 +    else if (!strcmp (s,"FLAGS")) f[k++] = fetch_flags;
145.2660 +    else if (!strcmp (s,"INTERNALDATE")) f[k++] = fetch_internaldate;
145.2661 +    else if (!strcmp (s,"RFC822.SIZE")) f[k++] = fetch_rfc822_size;
145.2662 +    else if (!strcmp (s,"ENVELOPE")) {
145.2663 +      parse_envs = T;		/* we will need to parse envelopes */
145.2664 +      f[k++] = fetch_envelope;
145.2665 +    }
145.2666 +    else if (!strcmp (s,"BODY")) {
145.2667 +      parse_envs = parse_bodies = T;
145.2668 +      f[k++] = fetch_body;
145.2669 +    }
145.2670 +    else if (!strcmp (s,"BODYSTRUCTURE")) {
145.2671 +      parse_envs = parse_bodies = T;
145.2672 +      f[k++] = fetch_bodystructure;
145.2673 +    }
145.2674 +    else if (!strcmp (s,"RFC822")) {
145.2675 +      fa[k] = s[6] ? (void *) FT_PEEK : NIL;
145.2676 +      f[k++] = fetch_rfc822;
145.2677 +    }
145.2678 +    else if (!strcmp (s,"RFC822.HEADER")) f[k++] = fetch_rfc822_header;
145.2679 +    else if (!strcmp (s,"RFC822.TEXT")) {
145.2680 +      fa[k] = s[11] ? (void *) FT_PEEK : NIL;
145.2681 +      f[k++] = fetch_rfc822_text;
145.2682 +    }
145.2683 +
145.2684 +    else if (!strncmp (s,"BODY[",5) || !strncmp (s,"BODY.PEEK[",10) ||
145.2685 +	     !strncmp (s,"BINARY[",7) || !strncmp (s,"BINARY.PEEK[",12) ||
145.2686 +	     !strncmp (s,"BINARY.SIZE[",12)) {
145.2687 +      TEXTARGS *ta = (TEXTARGS *)
145.2688 +	memset (fs_get (sizeof (TEXTARGS)),0,sizeof (TEXTARGS));
145.2689 +      if (s[1] == 'I') {	/* body or binary? */
145.2690 +	ta->binary = FTB_BINARY;/* binary */
145.2691 +	f[k] = fetch_body_part_binary;
145.2692 +	if (s[6] == '.') {	/* wanted peek or size? */
145.2693 +	  if (s[7] == 'P') ta->flags = FT_PEEK;
145.2694 +	  else ta->binary |= FTB_SIZE;
145.2695 +	  s += 12;		/* skip to section specifier */
145.2696 +	}
145.2697 +	else s += 7;		/* skip to section specifier */
145.2698 +	if (!isdigit (*s)) {	/* make sure top-level digit */
145.2699 +	  fs_give ((void **) &ta);
145.2700 +	  response = badbin;
145.2701 +	  return;
145.2702 +	}
145.2703 +      }
145.2704 +      else {			/* body */
145.2705 +	f[k] = fetch_body_part_contents;
145.2706 +	if (s[4] == '.') {	/* wanted peek? */
145.2707 +	  ta->flags = FT_PEEK;
145.2708 +	  s += 10;		/* skip to section specifier */
145.2709 +	}
145.2710 +	else s += 5;		/* skip to section specifier */
145.2711 +      }
145.2712 +      if (*(v = s) != ']') {	/* non-empty section specifier? */
145.2713 +	if (isdigit (*v)) {	/* have section specifier? */
145.2714 +				/* need envelopes and bodies */
145.2715 +	  parse_envs = parse_bodies = T;
145.2716 +	  while (isdigit (*v))	/* scan to end of section specifier */
145.2717 +	    if ((*++v == '.') && isdigit (v[1])) v++;
145.2718 +				/* any IMAP4rev1 stuff following? */
145.2719 +	  if ((*v == '.') && isalpha (v[1])) {
145.2720 +	    if (ta->binary) {	/* not if binary you don't */
145.2721 +	      fs_give ((void **) &ta);
145.2722 +	      response = badbin;
145.2723 +	      return;
145.2724 +	    }
145.2725 +	    *v++ = '\0';	/* yes, tie off section specifier */
145.2726 +	    if (!strncmp (v,"MIME",4)) {
145.2727 +	      v += 4;		/* found <section>.MIME */
145.2728 +	      f[k] = fetch_body_part_mime;
145.2729 +	    }
145.2730 +	  }
145.2731 +	  else if (*v != ']') {	/* better be the end if no IMAP4rev1 stuff */
145.2732 +	    fs_give ((void **) &ta);/* clean up */
145.2733 +	    response = "%.80s BAD Syntax error in section specifier\015\012";
145.2734 +	    return;
145.2735 +	  }
145.2736 +	}
145.2737 +
145.2738 +	if (*v != ']') {	/* IMAP4rev1 stuff here? */
145.2739 +	  if (!strncmp (v,"HEADER",6)) {
145.2740 +	    *v = '\0';		/* tie off in case top level */
145.2741 +	    v += 6;		/* found [<section>.]HEADER */
145.2742 +	    f[k] = fetch_body_part_header;
145.2743 +				/* partial headers wanted? */
145.2744 +	    if (!strncmp (v,".FIELDS",7)) {
145.2745 +	      v += 7;		/* yes */
145.2746 +	      if (!strncmp (v,".NOT",4)) {
145.2747 +		v += 4;		/* want to exclude named headers */
145.2748 +		ta->flags |= FT_NOT;
145.2749 +	      }
145.2750 +	      if (*v || !(v = strtok (NIL,"\015\012")) ||
145.2751 +		  !(ta->lines = parse_stringlist (&v,&list))) {
145.2752 +		fs_give ((void **) &ta);/* clean up */
145.2753 +		response = "%.80s BAD Syntax error in header fields\015\012";
145.2754 +		return;
145.2755 +	      }
145.2756 +	    }
145.2757 +	  }
145.2758 +	  else if (!strncmp (v,"TEXT",4)) {
145.2759 +	    *v = '\0';		/* tie off in case top level */
145.2760 +	    v += 4;		/* found [<section>.]TEXT */
145.2761 +	    f[k] = fetch_body_part_text;
145.2762 +	  }
145.2763 +	  else {
145.2764 +	    fs_give ((void **) &ta);/* clean up */
145.2765 +	    response = "%.80s BAD Unknown section text specifier\015\012";
145.2766 +	    return;
145.2767 +	  }
145.2768 +	}
145.2769 +      }
145.2770 +				/* tie off section */
145.2771 +      if (*v == ']') *v++ = '\0';
145.2772 +      else {			/* bogon */
145.2773 +	if (ta->lines) mail_free_stringlist (&ta->lines);
145.2774 +	fs_give ((void **) &ta);/* clean up */
145.2775 +	response = "%.80s BAD Section specifier not terminated\015\012";
145.2776 +	return;
145.2777 +      }
145.2778 +
145.2779 +      if ((*v == '<') &&	/* partial specifier? */
145.2780 +	  ((ta->binary & FTB_SIZE) ||
145.2781 +	   !(isdigit (v[1]) && ((ta->first = strtoul (v+1,(char **) &v,10)) ||
145.2782 +				v) &&
145.2783 +	     (*v++ == '.') && (ta->last = strtoul (v,(char **) &v,10)) &&
145.2784 +	     (*v++ == '>')))) {
145.2785 +	if (ta->lines) mail_free_stringlist (&ta->lines);
145.2786 +	fs_give ((void **) &ta);
145.2787 +	response ="%.80s BAD Syntax error in partial text specifier\015\012";
145.2788 +	return;
145.2789 +      }
145.2790 +      switch (*v) {		/* what's there now? */
145.2791 +      case ' ':			/* more follows */
145.2792 +	*--v = ' ';		/* patch a space back in */
145.2793 +	*--v = 'x';		/* and a hokey character before that */
145.2794 +	strtok (v," ");		/* reset strtok mechanism */
145.2795 +	break;
145.2796 +      case '\0':		/* none */
145.2797 +	break;
145.2798 +      case ')':			/* end of list */
145.2799 +	if (list && !v[1]) {	/* make sure of that */
145.2800 +	  list = NIL;
145.2801 +	  strtok (v," ");	/* reset strtok mechanism */
145.2802 +	  break;		/* all done */
145.2803 +	}
145.2804 +				/* otherwise it's a bogon, drop in */
145.2805 +      default:			/* bogon */
145.2806 +	if (ta->lines) mail_free_stringlist (&ta->lines);
145.2807 +	fs_give ((void **) &ta);
145.2808 +	response = "%.80s BAD Syntax error after section specifier\015\012";
145.2809 +	return;
145.2810 +      }
145.2811 +				/* make copy of section specifier */
145.2812 +      if (s && *s) ta->section = cpystr (s);
145.2813 +      fa[k++] = (void *) ta;	/* set argument */
145.2814 +    }
145.2815 +    else {			/* unknown attribute */
145.2816 +      response = badatt;
145.2817 +      return;
145.2818 +    }
145.2819 +  } while ((s = strtok (NIL," ")) && (k < MAXFETCH) && list);
145.2820 +  else {
145.2821 +    response = misarg;		/* missing attribute list */
145.2822 +    return;
145.2823 +  }
145.2824 +
145.2825 +  if (s) {			/* too many attributes? */
145.2826 +    response = "%.80s BAD Excessively complex FETCH attribute list\015\012";
145.2827 +    return;
145.2828 +  }
145.2829 +  if (list) {			/* too many attributes? */
145.2830 +    response = "%.80s BAD Unterminated FETCH attribute list\015\012";
145.2831 +    return;
145.2832 +  }
145.2833 +  f[k] = NIL;			/* tie off attribute list */
145.2834 +				/* c-client clobbers sequence, use spare */
145.2835 +  for (i = 1; i <= nmsgs; i++)
145.2836 +    mail_elt (stream,i)->spare = mail_elt (stream,i)->sequence;
145.2837 +				/* for each requested message */
145.2838 +  for (i = 1; (i <= nmsgs) && (response != loseunknowncte); i++) {
145.2839 +				/* kill if dying */
145.2840 +    if (state == LOGOUT) longjmp (jmpenv,1);
145.2841 +    if (mail_elt (stream,i)->spare) {
145.2842 +				/* parse envelope, set body, do warnings */
145.2843 +      if (parse_envs) mail_fetchstructure (stream,i,parse_bodies ? &b : NIL);
145.2844 +      quell_events = T;		/* can't do any events now */
145.2845 +      PSOUT ("* ");		/* leader */
145.2846 +      pnum (i);
145.2847 +      PSOUT (" FETCH (");
145.2848 +      (*f[0]) (i,fa[0]);	/* do first attribute */
145.2849 +				/* for each subsequent attribute */
145.2850 +      for (k = 1; f[k] && (response != loseunknowncte); k++) {
145.2851 +	PBOUT (' ');		/* delimit with space */
145.2852 +	(*f[k]) (i,fa[k]);	/* do that attribute */
145.2853 +      }
145.2854 +      PSOUT (")\015\012");	/* trailer */
145.2855 +      quell_events = NIL;	/* events alright now */
145.2856 +    }
145.2857 +  }
145.2858 +}
145.2859 +
145.2860 +/* Fetch message body structure (extensible)
145.2861 + * Accepts: message number
145.2862 + *	    extra argument
145.2863 + */
145.2864 +
145.2865 +void fetch_bodystructure (unsigned long i,void *args)
145.2866 +{
145.2867 +  BODY *body;
145.2868 +  mail_fetchstructure (stream,i,&body);
145.2869 +  PSOUT ("BODYSTRUCTURE ");
145.2870 +  pbodystructure (body);	/* output body */
145.2871 +}
145.2872 +
145.2873 +
145.2874 +/* Fetch message body structure (non-extensible)
145.2875 + * Accepts: message number
145.2876 + *	    extra argument
145.2877 + */
145.2878 +
145.2879 +
145.2880 +void fetch_body (unsigned long i,void *args)
145.2881 +{
145.2882 +  BODY *body;
145.2883 +  mail_fetchstructure (stream,i,&body);
145.2884 +  PSOUT ("BODY ");		/* output attribute */
145.2885 +  pbody (body);			/* output body */
145.2886 +}
145.2887 +
145.2888 +/* Fetch body part MIME header
145.2889 + * Accepts: message number
145.2890 + *	    extra argument
145.2891 + */
145.2892 +
145.2893 +void fetch_body_part_mime (unsigned long i,void *args)
145.2894 +{
145.2895 +  TEXTARGS *ta = (TEXTARGS *) args;
145.2896 +  if (i) {			/* do work? */
145.2897 +    SIZEDTEXT st;
145.2898 +    unsigned long uid = mail_uid (stream,i);
145.2899 +    char *tmp = (char *) fs_get (100 + strlen (ta->section));
145.2900 +    sprintf (tmp,"BODY[%s.MIME]",ta->section);
145.2901 +				/* try to use remembered text */
145.2902 +    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
145.2903 +    else {			/* get data */
145.2904 +      st.data = (unsigned char *)
145.2905 +	mail_fetch_mime (stream,i,ta->section,&st.size,ta->flags);
145.2906 +      if (ta->first || ta->last) remember (uid,tmp,&st);
145.2907 +    }
145.2908 +    pbodypartstring (i,tmp,&st,NIL,ta);
145.2909 +    fs_give ((void **) &tmp);
145.2910 +  }
145.2911 +  else {			/* clean up the arguments */
145.2912 +    fs_give ((void **) &ta->section);
145.2913 +    fs_give ((void **) &args);
145.2914 +  }
145.2915 +}
145.2916 +
145.2917 +
145.2918 +/* Fetch body part contents
145.2919 + * Accepts: message number
145.2920 + *	    extra argument
145.2921 + */
145.2922 +
145.2923 +void fetch_body_part_contents (unsigned long i,void *args)
145.2924 +{
145.2925 +  TEXTARGS *ta = (TEXTARGS *) args;
145.2926 +  if (i) {			/* do work? */
145.2927 +    SIZEDTEXT st;
145.2928 +    char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0));
145.2929 +    unsigned long uid = mail_uid (stream,i);
145.2930 +    sprintf (tmp,"BODY[%s]",ta->section ? ta->section : "");
145.2931 +				/* try to use remembered text */
145.2932 +    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
145.2933 +				/* get data */
145.2934 +    else if ((st.data = (unsigned char *)
145.2935 +	      mail_fetch_body (stream,i,ta->section,&st.size,
145.2936 +			       ta->flags | FT_RETURNSTRINGSTRUCT)) &&
145.2937 +	     (ta->first || ta->last)) remember (uid,tmp,&st);
145.2938 +    pbodypartstring (i,tmp,&st,&stream->private.string,ta);
145.2939 +    fs_give ((void **) &tmp);
145.2940 +  }
145.2941 +  else {			/* clean up the arguments */
145.2942 +    if (ta->section) fs_give ((void **) &ta->section);
145.2943 +    fs_give ((void **) &args);
145.2944 +  }
145.2945 +}
145.2946 +
145.2947 +/* Fetch body part binary
145.2948 + * Accepts: message number
145.2949 + *	    extra argument
145.2950 + * Someday fix this to use stringstruct instead of memory
145.2951 + */
145.2952 +
145.2953 +void fetch_body_part_binary (unsigned long i,void *args)
145.2954 +{
145.2955 +  TEXTARGS *ta = (TEXTARGS *) args;
145.2956 +  if (i) {			/* do work? */
145.2957 +    SIZEDTEXT st,cst;
145.2958 +    BODY *body = mail_body (stream,i,ta->section);
145.2959 +    char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0));
145.2960 +    unsigned long uid = mail_uid (stream,i);
145.2961 +				/* try to use remembered text */
145.2962 +    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
145.2963 +    else {			/* get data */
145.2964 +      st.data = (unsigned char *)
145.2965 +	mail_fetch_body (stream,i,ta->section,&st.size,ta->flags);
145.2966 +      if (ta->first || ta->last) remember (uid,tmp,&st);
145.2967 +    }
145.2968 +				/* what encoding was used? */
145.2969 +    if (body) switch (body->encoding) {
145.2970 +    case ENCBASE64:
145.2971 +      if (cst.data = rfc822_base64 (st.data,st.size,&cst.size)) break;
145.2972 +      fetch_uid (i,NIL);	/* wrote a space, so must do something */
145.2973 +      if (lsterr) fs_give ((void **) &lsterr);
145.2974 +      lsterr = cpystr ("Undecodable BASE64 contents");
145.2975 +      response = loseunknowncte;
145.2976 +      fs_give ((void **) &tmp);
145.2977 +      return;
145.2978 +    case ENCQUOTEDPRINTABLE:
145.2979 +      if (cst.data = rfc822_qprint (st.data,st.size,&cst.size)) break;
145.2980 +      fetch_uid (i,NIL);	/* wrote a space, so must do something */
145.2981 +      if (lsterr) fs_give ((void **) &lsterr);
145.2982 +      lsterr = cpystr ("Undecodable QUOTED-PRINTABLE contents");
145.2983 +      response = loseunknowncte;
145.2984 +      fs_give ((void **) &tmp);
145.2985 +      return;
145.2986 +    case ENC7BIT:		/* no need to convert any of these */
145.2987 +    case ENC8BIT:
145.2988 +    case ENCBINARY:
145.2989 +      cst.data = NIL;		/* no converted data to free */
145.2990 +      break;
145.2991 +    default:			/* unknown encoding, oops */
145.2992 +      fetch_uid (i,NIL);	/* wrote a space, so must do something */
145.2993 +      if (lsterr) fs_give ((void **) &lsterr);
145.2994 +      lsterr = cpystr ("Unknown Content-Transfer-Encoding");
145.2995 +      response = loseunknowncte;
145.2996 +      fs_give ((void **) &tmp);
145.2997 +      return;
145.2998 +    }
145.2999 +    else {
145.3000 +      if (lsterr) fs_give ((void **) &lsterr);
145.3001 +      lsterr = cpystr ("Invalid body part");
145.3002 +      response = loseunknowncte;
145.3003 +      fs_give ((void **) &tmp);
145.3004 +      return;
145.3005 +    }
145.3006 +
145.3007 +				/* use decoded version if exists */
145.3008 +    if (cst.data) memcpy ((void *) &st,(void *) &cst,sizeof (SIZEDTEXT));
145.3009 +    if (ta->binary & FTB_SIZE) {/* just want size? */
145.3010 +      sprintf (tmp,"BINARY.SIZE[%s] %lu",ta->section ? ta->section : "",
145.3011 +	       st.size);
145.3012 +      PSOUT (tmp);
145.3013 +    }
145.3014 +    else {			/* no, blat binary data */
145.3015 +      int f = mail_elt (stream,i)->seen;
145.3016 +      if (st.data) {		/* only if have useful data */
145.3017 +				/* partial specifier */
145.3018 +	if (ta->first || ta->last)
145.3019 +	  sprintf (tmp,"BINARY[%s]<%lu> ",
145.3020 +		   ta->section ? ta->section : "",ta->first);
145.3021 +	else sprintf (tmp,"BINARY[%s] ",ta->section ? ta->section : "");
145.3022 +  				/* in case first byte beyond end of text */
145.3023 +	if (st.size <= ta->first) st.size = ta->first = 0;
145.3024 +	else {			/* offset and truncate */
145.3025 +	  st.data += ta->first;	/* move to desired position */
145.3026 +	  st.size -= ta->first;	/* reduced size */
145.3027 +	  if (ta->last && (st.size > ta->last)) st.size = ta->last;
145.3028 +	}
145.3029 +	if (st.size) sprintf (tmp + strlen (tmp),"{%lu}\015\012",st.size);
145.3030 +	else strcat (tmp,"\"\"");
145.3031 +	PSOUT (tmp);		/* write binary output */
145.3032 +	if (st.size && (PSOUTR (&st) == EOF)) ioerror(stdout,"writing binary");
145.3033 +      }
145.3034 +      else {
145.3035 +	sprintf (tmp,"BINARY[%s] NIL",ta->section ? ta->section : "");
145.3036 +	PSOUT (tmp);
145.3037 +      }
145.3038 +      changed_flags (i,f);	/* write changed flags */
145.3039 +    }
145.3040 +				/* free converted data */
145.3041 +    if (cst.data) fs_give ((void **) &cst.data);
145.3042 +    fs_give ((void **) &tmp);	/* and temporary string */
145.3043 +  }
145.3044 +  else {			/* clean up the arguments */
145.3045 +    if (ta->section) fs_give ((void **) &ta->section);
145.3046 +    fs_give ((void **) &args);
145.3047 +  }
145.3048 +}
145.3049 +
145.3050 +/* Fetch MESSAGE/RFC822 body part header
145.3051 + * Accepts: message number
145.3052 + *	    extra argument
145.3053 + */
145.3054 +
145.3055 +void fetch_body_part_header (unsigned long i,void *args)
145.3056 +{
145.3057 +  TEXTARGS *ta = (TEXTARGS *) args;
145.3058 +  unsigned long len = 100 + (ta->section ? strlen (ta->section) : 0);
145.3059 +  STRINGLIST *s;
145.3060 +  for (s = ta->lines; s; s = s->next) len += s->text.size + 1;
145.3061 +  if (i) {			/* do work? */
145.3062 +    SIZEDTEXT st;
145.3063 +    char *tmp = (char *) fs_get (len);
145.3064 +    PSOUT ("BODY[");
145.3065 +				/* output attribute */
145.3066 +    if (ta->section && *ta->section) {
145.3067 +      PSOUT (ta->section);
145.3068 +      PBOUT ('.');
145.3069 +    }
145.3070 +    PSOUT ("HEADER");
145.3071 +    if (ta->lines) {
145.3072 +      PSOUT ((ta->flags & FT_NOT) ? ".FIELDS.NOT " : ".FIELDS ");
145.3073 +      pastringlist (ta->lines);
145.3074 +    }
145.3075 +    strcpy (tmp,"]");		/* close section specifier */
145.3076 +    st.data = (unsigned char *)	/* get data (no hope in using remember here) */
145.3077 +      mail_fetch_header (stream,i,ta->section,ta->lines,&st.size,ta->flags);
145.3078 +    pbodypartstring (i,tmp,&st,NIL,ta);
145.3079 +    fs_give ((void **) &tmp);
145.3080 +  }
145.3081 +  else {			/* clean up the arguments */
145.3082 +    if (ta->lines) mail_free_stringlist (&ta->lines);
145.3083 +    if (ta->section) fs_give ((void **) &ta->section);
145.3084 +    fs_give ((void **) &args);
145.3085 +  }
145.3086 +}
145.3087 +
145.3088 +/* Fetch MESSAGE/RFC822 body part text
145.3089 + * Accepts: message number
145.3090 + *	    extra argument
145.3091 + */
145.3092 +
145.3093 +void fetch_body_part_text (unsigned long i,void *args)
145.3094 +{
145.3095 +  TEXTARGS *ta = (TEXTARGS *) args;
145.3096 +  if (i) {			/* do work? */
145.3097 +    SIZEDTEXT st;
145.3098 +    char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0));
145.3099 +    unsigned long uid = mail_uid (stream,i);
145.3100 +				/* output attribute */
145.3101 +    if (ta->section && *ta->section) sprintf (tmp,"BODY[%s.TEXT]",ta->section);
145.3102 +    else strcpy (tmp,"BODY[TEXT]");
145.3103 +				/* try to use remembered text */
145.3104 +    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
145.3105 +				/* get data */
145.3106 +    else if ((st.data = (unsigned char *)
145.3107 +	      mail_fetch_text (stream,i,ta->section,&st.size,
145.3108 +			       ta->flags | FT_RETURNSTRINGSTRUCT)) &&
145.3109 +	     (ta->first || ta->last)) remember (uid,tmp,&st);
145.3110 +    pbodypartstring (i,tmp,&st,&stream->private.string,ta);
145.3111 +    fs_give ((void **) &tmp);
145.3112 +  }
145.3113 +  else {			/* clean up the arguments */
145.3114 +    if (ta->section) fs_give ((void **) &ta->section);
145.3115 +    fs_give ((void **) &args);
145.3116 +  }
145.3117 +}
145.3118 +
145.3119 +
145.3120 +/* Remember body part text for subsequent partial fetching
145.3121 + * Accepts: message UID
145.3122 + *	    body part id
145.3123 + *	    text
145.3124 + *	    string
145.3125 + */
145.3126 +
145.3127 +void remember (unsigned long uid,char *id,SIZEDTEXT *st)
145.3128 +{
145.3129 +  lastuid = uid;		/* remember UID */
145.3130 +  if (lastid) fs_give ((void **) &lastid);
145.3131 +  lastid = cpystr (id);		/* remember body part id */
145.3132 +  if (lastst.data) fs_give ((void **) &lastst.data);
145.3133 +				/* remember text */
145.3134 +  lastst.data = (unsigned char *)
145.3135 +    memcpy (fs_get (st->size + 1),st->data,st->size);
145.3136 +  lastst.size = st->size;
145.3137 +}
145.3138 +
145.3139 +
145.3140 +/* Fetch envelope
145.3141 + * Accepts: message number
145.3142 + *	    extra argument
145.3143 + */
145.3144 +
145.3145 +void fetch_envelope (unsigned long i,void *args)
145.3146 +{
145.3147 +  ENVELOPE *env = mail_fetchenvelope (stream,i);
145.3148 +  PSOUT ("ENVELOPE ");		/* output attribute */
145.3149 +  penv (env);			/* output envelope */
145.3150 +}
145.3151 +
145.3152 +/* Fetch flags
145.3153 + * Accepts: message number
145.3154 + *	    extra argument
145.3155 + */
145.3156 +
145.3157 +void fetch_flags (unsigned long i,void *args)
145.3158 +{
145.3159 +  unsigned long u;
145.3160 +  char *t,tmp[MAILTMPLEN];
145.3161 +  int c = NIL;
145.3162 +  MESSAGECACHE *elt = mail_elt (stream,i);
145.3163 +  if (!elt->valid) {		/* have valid flags yet? */
145.3164 +    sprintf (tmp,"%lu",i);
145.3165 +    mail_fetch_flags (stream,tmp,NIL);
145.3166 +  }
145.3167 +  PSOUT ("FLAGS (");		/* output attribute */
145.3168 +				/* output system flags */
145.3169 +  if (elt->recent) put_flag (&c,"\\Recent");
145.3170 +  if (elt->seen) put_flag (&c,"\\Seen");
145.3171 +  if (elt->deleted) put_flag (&c,"\\Deleted");
145.3172 +  if (elt->flagged) put_flag (&c,"\\Flagged");
145.3173 +  if (elt->answered) put_flag (&c,"\\Answered");
145.3174 +  if (elt->draft) put_flag (&c,"\\Draft");
145.3175 +  if (u = elt->user_flags) do	/* any user flags? */
145.3176 +    if (t = stream->user_flags[find_rightmost_bit (&u)]) put_flag (&c,t);
145.3177 +  while (u);			/* until no more user flags */
145.3178 +  PBOUT (')');			/* end of flags */
145.3179 +  elt->spare2 = NIL;		/* we've sent the update */
145.3180 +}
145.3181 +
145.3182 +
145.3183 +/* Output a flag
145.3184 + * Accepts: pointer to current delimiter character
145.3185 + *	    flag to output
145.3186 + * Changes delimiter character to space
145.3187 + */
145.3188 +
145.3189 +void put_flag (int *c,char *s)
145.3190 +{
145.3191 +  if (*c) PBOUT (*c);		/* put delimiter */
145.3192 +  PSOUT (s);			/* dump flag */
145.3193 +  *c = ' ';			/* change delimiter if necessary */
145.3194 +}
145.3195 +
145.3196 +
145.3197 +/* Output flags if was unseen
145.3198 + * Accepts: message number
145.3199 + *	    prior value of Seen flag
145.3200 + */
145.3201 +
145.3202 +void changed_flags (unsigned long i,int f)
145.3203 +{
145.3204 +				/* was unseen, now seen? */
145.3205 +  if (!f && mail_elt (stream,i)->seen) {
145.3206 +    PBOUT (' ');		/* yes, delimit with space */
145.3207 +    fetch_flags (i,NIL);	/* output flags */
145.3208 +  }
145.3209 +}
145.3210 +
145.3211 +/* Fetch message internal date
145.3212 + * Accepts: message number
145.3213 + *	    extra argument
145.3214 + */
145.3215 +
145.3216 +void fetch_internaldate (unsigned long i,void *args)
145.3217 +{
145.3218 +  char tmp[MAILTMPLEN];
145.3219 +  MESSAGECACHE *elt = mail_elt (stream,i);
145.3220 +  if (!elt->day) {		/* have internal date yet? */
145.3221 +    sprintf (tmp,"%lu",i);
145.3222 +    mail_fetch_fast (stream,tmp,NIL);
145.3223 +  }
145.3224 +  PSOUT ("INTERNALDATE \"");
145.3225 +  PSOUT (mail_date (tmp,elt));
145.3226 +  PBOUT ('"');
145.3227 +}
145.3228 +
145.3229 +
145.3230 +/* Fetch unique identifier
145.3231 + * Accepts: message number
145.3232 + *	    extra argument
145.3233 + */
145.3234 +
145.3235 +void fetch_uid (unsigned long i,void *args)
145.3236 +{
145.3237 +  PSOUT ("UID ");
145.3238 +  pnum (mail_uid (stream,i));
145.3239 +}
145.3240 +
145.3241 +/* Fetch complete RFC-822 format message
145.3242 + * Accepts: message number
145.3243 + *	    extra argument
145.3244 + */
145.3245 +
145.3246 +void fetch_rfc822 (unsigned long i,void *args)
145.3247 +{
145.3248 +  if (i) {			/* do work? */
145.3249 +    int f = mail_elt (stream,i)->seen;
145.3250 +#if 0
145.3251 +    SIZEDTEXT st;
145.3252 +    st.data = (unsigned char *)
145.3253 +      mail_fetch_message (stream,i,&st.size,(long) args);
145.3254 +    pbodypartstring (i,"RFC822",&st,NIL,NIL);
145.3255 +#else
145.3256 +    /* Yes, this version is bletcherous, but mail_fetch_message() requires
145.3257 +       too much memory */
145.3258 +    SIZEDTEXT txt,hdr;
145.3259 +    char *s = mail_fetch_header (stream,i,NIL,NIL,&hdr.size,FT_PEEK);
145.3260 +    hdr.data = (unsigned char *) memcpy (fs_get (hdr.size),s,hdr.size);
145.3261 +    txt.data = (unsigned char *)
145.3262 +      mail_fetch_text (stream,i,NIL,&txt.size,
145.3263 +		       ((long) args) | FT_RETURNSTRINGSTRUCT);
145.3264 +    PSOUT ("RFC822 {");
145.3265 +    pnum (hdr.size + txt.size);
145.3266 +    PSOUT ("}\015\012");
145.3267 +    ptext (&hdr,NIL);
145.3268 +    ptext (&txt,&stream->private.string);
145.3269 +    fs_give ((void **) &hdr.data);
145.3270 +#endif
145.3271 +    changed_flags (i,f);	/* output changed flags */
145.3272 +  }
145.3273 +}
145.3274 +
145.3275 +
145.3276 +/* Fetch RFC-822 header
145.3277 + * Accepts: message number
145.3278 + *	    extra argument
145.3279 + */
145.3280 +
145.3281 +void fetch_rfc822_header (unsigned long i,void *args)
145.3282 +{
145.3283 +  SIZEDTEXT st;
145.3284 +  st.data = (unsigned char *)
145.3285 +    mail_fetch_header (stream,i,NIL,NIL,&st.size,FT_PEEK);
145.3286 +  pbodypartstring (i,"RFC822.HEADER",&st,NIL,NIL);
145.3287 +}
145.3288 +
145.3289 +
145.3290 +/* Fetch RFC-822 message length
145.3291 + * Accepts: message number
145.3292 + *	    extra argument
145.3293 + */
145.3294 +
145.3295 +void fetch_rfc822_size (unsigned long i,void *args)
145.3296 +{
145.3297 +  char tmp[MAILTMPLEN];
145.3298 +  MESSAGECACHE *elt = mail_elt (stream,i);
145.3299 +  if (!elt->rfc822_size) {	/* have message size yet? */
145.3300 +    sprintf (tmp,"%lu",i);
145.3301 +    mail_fetch_fast (stream,tmp,NIL);
145.3302 +  }
145.3303 +  PSOUT ("RFC822.SIZE ");
145.3304 +  pnum (elt->rfc822_size);
145.3305 +}
145.3306 +
145.3307 +/* Fetch RFC-822 text only
145.3308 + * Accepts: message number
145.3309 + *	    extra argument
145.3310 + */
145.3311 +
145.3312 +void fetch_rfc822_text (unsigned long i,void *args)
145.3313 +{
145.3314 +  if (i) {			/* do work? */
145.3315 +    int f = mail_elt (stream,i)->seen;
145.3316 +    SIZEDTEXT st;
145.3317 +    st.data = (unsigned char *)
145.3318 +      mail_fetch_text (stream,i,NIL,&st.size,
145.3319 +		       ((long) args) | FT_RETURNSTRINGSTRUCT);
145.3320 +    pbodypartstring (i,"RFC822.TEXT",&st,&stream->private.string,NIL);
145.3321 +  }
145.3322 +}
145.3323 +
145.3324 +/* Print envelope
145.3325 + * Accepts: body
145.3326 + */
145.3327 +
145.3328 +void penv (ENVELOPE *env)
145.3329 +{
145.3330 +  PBOUT ('(');			/* delimiter */
145.3331 +  if (env) {			/* only if there is an envelope */
145.3332 +    pnstring (env->date);	/* output envelope fields */
145.3333 +    PBOUT (' ');
145.3334 +    pnstring (env->subject);
145.3335 +    PBOUT (' ');
145.3336 +    paddr (env->from);
145.3337 +    PBOUT (' ');
145.3338 +    paddr (env->sender);
145.3339 +    PBOUT (' ');
145.3340 +    paddr (env->reply_to);
145.3341 +    PBOUT (' ');
145.3342 +    paddr (env->to);
145.3343 +    PBOUT (' ');
145.3344 +    paddr (env->cc);
145.3345 +    PBOUT (' ');
145.3346 +    paddr (env->bcc);
145.3347 +    PBOUT (' ');
145.3348 +    pnstring (env->in_reply_to);
145.3349 +    PBOUT (' ');
145.3350 +    pnstring (env->message_id);
145.3351 +  }
145.3352 +				/* no envelope */
145.3353 +  else PSOUT ("NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL");
145.3354 +  PBOUT (')');			/* end of envelope */
145.3355 +}
145.3356 +
145.3357 +/* Print body structure (extensible)
145.3358 + * Accepts: body
145.3359 + */
145.3360 +
145.3361 +void pbodystructure (BODY *body)
145.3362 +{
145.3363 +  PBOUT ('(');			/* delimiter */
145.3364 +  if (body) {			/* only if there is a body */
145.3365 +    PART *part;
145.3366 +				/* multipart type? */
145.3367 +    if (body->type == TYPEMULTIPART) {
145.3368 +				/* print each part */
145.3369 +      if (part = body->nested.part)
145.3370 +	for (; part; part = part->next) pbodystructure (&(part->body));
145.3371 +      else pbodystructure (NIL);
145.3372 +      PBOUT (' ');		/* space delimiter */
145.3373 +      pstring (body->subtype);	/* subtype */
145.3374 +      PBOUT (' ');
145.3375 +      pparam (body->parameter);	/* multipart body extension data */
145.3376 +      PBOUT (' ');
145.3377 +      if (body->disposition.type) {
145.3378 +	PBOUT ('(');
145.3379 +	pstring (body->disposition.type);
145.3380 +	PBOUT (' ');
145.3381 +	pparam (body->disposition.parameter);
145.3382 +	PBOUT (')');
145.3383 +      }
145.3384 +      else PSOUT ("NIL");
145.3385 +      PBOUT (' ');
145.3386 +      pnstringorlist (body->language);
145.3387 +      PBOUT (' ');
145.3388 +      pnstring (body->location);
145.3389 +    }
145.3390 +
145.3391 +    else {			/* non-multipart body type */
145.3392 +      pstring ((char *) body_types[body->type]);
145.3393 +      PBOUT (' ');
145.3394 +      pstring (body->subtype);
145.3395 +      PBOUT (' ');
145.3396 +      pparam (body->parameter);
145.3397 +      PBOUT (' ');
145.3398 +      pnstring (body->id);
145.3399 +      PBOUT (' ');
145.3400 +      pnstring (body->description);
145.3401 +      PBOUT (' ');
145.3402 +      pstring ((char *) body_encodings[body->encoding]);
145.3403 +      PBOUT (' ');
145.3404 +      pnum (body->size.bytes);
145.3405 +      switch (body->type) {	/* extra stuff depends upon body type */
145.3406 +      case TYPEMESSAGE:
145.3407 +				/* can't do this if not RFC822 */
145.3408 +	if (strcmp (body->subtype,"RFC822")) break;
145.3409 +	PBOUT (' ');
145.3410 +	penv (body->nested.msg->env);
145.3411 +	PBOUT (' ');
145.3412 +	pbodystructure (body->nested.msg->body);
145.3413 +      case TYPETEXT:
145.3414 +	PBOUT (' ');
145.3415 +	pnum (body->size.lines);
145.3416 +	break;
145.3417 +      default:
145.3418 +	break;
145.3419 +      }
145.3420 +      PBOUT (' ');
145.3421 +      pnstring (body->md5);
145.3422 +      PBOUT (' ');
145.3423 +      if (body->disposition.type) {
145.3424 +	PBOUT ('(');
145.3425 +	pstring (body->disposition.type);
145.3426 +	PBOUT (' ');
145.3427 +	pparam (body->disposition.parameter);
145.3428 +	PBOUT (')');
145.3429 +      }
145.3430 +      else PSOUT ("NIL");
145.3431 +      PBOUT (' ');
145.3432 +      pnstringorlist (body->language);
145.3433 +      PBOUT (' ');
145.3434 +      pnstring (body->location);
145.3435 +    }
145.3436 +  }
145.3437 +				/* no body */
145.3438 +  else PSOUT ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" 0 0 NIL NIL NIL NIL");
145.3439 +  PBOUT (')');			/* end of body */
145.3440 +}
145.3441 +
145.3442 +/* Print body (non-extensible)
145.3443 + * Accepts: body
145.3444 + */
145.3445 +
145.3446 +void pbody (BODY *body)
145.3447 +{
145.3448 +  PBOUT ('(');			/* delimiter */
145.3449 +  if (body) {			/* only if there is a body */
145.3450 +    PART *part;
145.3451 +				/* multipart type? */
145.3452 +    if (body->type == TYPEMULTIPART) {
145.3453 +				/* print each part */
145.3454 +      if (part = body->nested.part)
145.3455 +	for (; part; part = part->next) pbody (&(part->body));
145.3456 +      else pbody (NIL);
145.3457 +      PBOUT (' ');		/* space delimiter */
145.3458 +      pstring (body->subtype);	/* and finally the subtype */
145.3459 +    }
145.3460 +    else {			/* non-multipart body type */
145.3461 +      pstring ((char *) body_types[body->type]);
145.3462 +      PBOUT (' ');
145.3463 +      pstring (body->subtype);
145.3464 +      PBOUT (' ');
145.3465 +      pparam (body->parameter);
145.3466 +      PBOUT (' ');
145.3467 +      pnstring (body->id);
145.3468 +      PBOUT (' ');
145.3469 +      pnstring (body->description);
145.3470 +      PBOUT (' ');
145.3471 +      pstring ((char *) body_encodings[body->encoding]);
145.3472 +      PBOUT (' ');
145.3473 +      pnum (body->size.bytes);
145.3474 +      switch (body->type) {	/* extra stuff depends upon body type */
145.3475 +      case TYPEMESSAGE:
145.3476 +				/* can't do this if not RFC822 */
145.3477 +	if (strcmp (body->subtype,"RFC822")) break;
145.3478 +	PBOUT (' ');
145.3479 +	penv (body->nested.msg ? body->nested.msg->env : NIL);
145.3480 +	PBOUT (' ');
145.3481 +	pbody (body->nested.msg ? body->nested.msg->body : NIL);
145.3482 +      case TYPETEXT:
145.3483 +	PBOUT (' ');
145.3484 +	pnum (body->size.lines);
145.3485 +	break;
145.3486 +      default:
145.3487 +	break;
145.3488 +      }
145.3489 +    }
145.3490 +  }
145.3491 +				/* no body */
145.3492 +  else PSOUT ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" 0 0");
145.3493 +  PBOUT (')');			/* end of body */
145.3494 +}
145.3495 +
145.3496 +/* Print parameter list
145.3497 + * Accepts: paramter
145.3498 + */
145.3499 +
145.3500 +void pparam (PARAMETER *param)
145.3501 +{
145.3502 +  if (param) {			/* one specified? */
145.3503 +    PBOUT ('(');
145.3504 +    do {
145.3505 +      pstring (param->attribute);
145.3506 +      PBOUT (' ');
145.3507 +      pstring (param->value);
145.3508 +      if (param = param->next) PBOUT (' ');
145.3509 +    } while (param);
145.3510 +    PBOUT (')');		/* end of parameters */
145.3511 +  }
145.3512 +  else PSOUT ("NIL");
145.3513 +}
145.3514 +
145.3515 +
145.3516 +/* Print address list
145.3517 + * Accepts: address list
145.3518 + */
145.3519 +
145.3520 +void paddr (ADDRESS *a)
145.3521 +{
145.3522 +  if (a) {			/* have anything in address? */
145.3523 +    PBOUT ('(');		/* open the address list */
145.3524 +    do {			/* for each address */
145.3525 +      PBOUT ('(');		/* open the address */
145.3526 +      pnstring (a->personal);	/* personal name */
145.3527 +      PBOUT (' ');
145.3528 +      pnstring (a->adl);	/* at-domain-list */
145.3529 +      PBOUT (' ');
145.3530 +      pnstring (a->mailbox);	/* mailbox */
145.3531 +      PBOUT (' ');
145.3532 +      pnstring (a->host);	/* domain name of mailbox's host */
145.3533 +      PBOUT (')');		/* terminate address */
145.3534 +    } while (a = a->next);	/* until end of address */
145.3535 +    PBOUT (')');		/* close address list */
145.3536 +  }
145.3537 +  else PSOUT ("NIL");		/* empty address */
145.3538 +}
145.3539 +
145.3540 +/* Print set
145.3541 + * Accepts: set
145.3542 + */
145.3543 +
145.3544 +void pset (SEARCHSET **set)
145.3545 +{
145.3546 +  SEARCHSET *cur = *set;
145.3547 +  while (cur) {			/* while there's a set to do */
145.3548 +    pnum (cur->first);		/* output first value */
145.3549 +    if (cur->last) {		/* if range, output second value of range */
145.3550 +      PBOUT (':');
145.3551 +      pnum (cur->last);
145.3552 +    }
145.3553 +    if (cur = cur->next) PBOUT (',');
145.3554 +  }
145.3555 +  mail_free_searchset (set);	/* flush set */
145.3556 +}
145.3557 +
145.3558 +
145.3559 +/* Print number
145.3560 + * Accepts: number
145.3561 + */
145.3562 +
145.3563 +void pnum (unsigned long i)
145.3564 +{
145.3565 +  char tmp[MAILTMPLEN];
145.3566 +  sprintf (tmp,"%lu",i);
145.3567 +  PSOUT (tmp);
145.3568 +}
145.3569 +
145.3570 +
145.3571 +/* Print string
145.3572 + * Accepts: string
145.3573 + */
145.3574 +
145.3575 +void pstring (char *s)
145.3576 +{
145.3577 +  SIZEDTEXT st;
145.3578 +  st.data = (unsigned char *) s;/* set up sized text */
145.3579 +  st.size = strlen (s);
145.3580 +  psizedstring (&st,NIL);	/* print string */
145.3581 +}
145.3582 +
145.3583 +
145.3584 +/* Print nstring
145.3585 + * Accepts: string or NIL
145.3586 + */
145.3587 +
145.3588 +void pnstring (char *s)
145.3589 +{
145.3590 +  if (s) pstring (s);		/* print string */
145.3591 +  else PSOUT ("NIL");
145.3592 +}
145.3593 +
145.3594 +
145.3595 +/* Print atom or string
145.3596 + * Accepts: astring
145.3597 + */
145.3598 +
145.3599 +void pastring (char *s)
145.3600 +{
145.3601 +  char *t;
145.3602 +  if (!*s) PSOUT ("\"\"");	/* empty string */
145.3603 +  else {			/* see if atom */
145.3604 +    for (t = s; (*t > ' ') && !(*t & 0x80) &&
145.3605 +	 (*t != '"') && (*t != '\\') && (*t != '(') && (*t != ')') &&
145.3606 +	 (*t != '{') && (*t != '%') && (*t != '*'); t++);
145.3607 +    if (*t) pstring (s);	/* not an atom */
145.3608 +    else PSOUT (s);		/* else plop down as atomic */
145.3609 +  }
145.3610 +}
145.3611 +
145.3612 +/* Print sized text as quoted
145.3613 + * Accepts: sized text
145.3614 + */
145.3615 +
145.3616 +void psizedquoted (SIZEDTEXT *s)
145.3617 +{
145.3618 +  PBOUT ('"');			/* use quoted string */
145.3619 +  ptext (s,NIL);
145.3620 +  PBOUT ('"');
145.3621 +}
145.3622 +
145.3623 +
145.3624 +/* Print sized text as literal
145.3625 + * Accepts: sized text
145.3626 + */
145.3627 +
145.3628 +void psizedliteral (SIZEDTEXT *s,STRING *st)
145.3629 +{
145.3630 +  PBOUT ('{');			/* print literal size */
145.3631 +  pnum (s->size);
145.3632 +  PSOUT ("}\015\012");
145.3633 +  ptext (s,st);
145.3634 +}
145.3635 +
145.3636 +/* Print sized text as literal or quoted string
145.3637 + * Accepts: sized text
145.3638 + *	    alternative stringstruct of text
145.3639 + */
145.3640 +
145.3641 +void psizedstring (SIZEDTEXT *s,STRING *st)
145.3642 +{
145.3643 +  unsigned char c;
145.3644 +  unsigned long i;
145.3645 +		
145.3646 +  if (s->data) {		/* if text, check if must use literal */
145.3647 +    for (i = 0; ((i < s->size) && ((c = s->data[i]) & 0xe0) &&
145.3648 +		 !(c & 0x80) && (c != '"') && (c != '\\')); ++i);
145.3649 +				/* must use literal if not all QUOTED-CHAR */
145.3650 +    if (i < s->size) psizedliteral (s,st);
145.3651 +    else psizedquoted (s);
145.3652 +  }
145.3653 +  else psizedliteral (s,st);
145.3654 +}
145.3655 +
145.3656 +
145.3657 +/* Print sized text as literal or quoted string
145.3658 + * Accepts: sized text
145.3659 + */
145.3660 +
145.3661 +void psizedastring (SIZEDTEXT *s)
145.3662 +{
145.3663 +  unsigned long i;
145.3664 +  unsigned int atomp = s->size ? T : NIL;
145.3665 +  for (i = 0; i < s->size; i++){/* check if must use literal */
145.3666 +    if (!(s->data[i] & 0xe0) || (s->data[i] & 0x80) ||
145.3667 +	(s->data[i] == '"') || (s->data[i] == '\\')) {
145.3668 +      psizedliteral (s,NIL);
145.3669 +      return;
145.3670 +    }
145.3671 +    else switch (s->data[i]) {	/* else see if any atom-specials */
145.3672 +    case '(': case ')': case '{': case ' ':
145.3673 +    case '%': case '*':		/* list-wildcards */
145.3674 +    case ']':			/* resp-specials */
145.3675 +				/* CTL and quoted-specials in literal check */
145.3676 +      atomp = NIL;		/* not an atom */
145.3677 +    }
145.3678 +  }
145.3679 +  if (atomp) ptext (s,NIL);	/* print as atom */
145.3680 +  else psizedquoted (s);	/* print as quoted string */
145.3681 +}
145.3682 +
145.3683 +/* Print string list
145.3684 + * Accepts: string list
145.3685 + */
145.3686 +
145.3687 +void pastringlist (STRINGLIST *s)
145.3688 +{
145.3689 +  PBOUT ('(');			/* start list */
145.3690 +  do {
145.3691 +    psizedastring (&s->text);	/* output list member */
145.3692 +    if (s->next) PBOUT (' ');
145.3693 +  } while (s = s->next);
145.3694 +  PBOUT (')');			/* terminate list */
145.3695 +}
145.3696 +
145.3697 +
145.3698 +/* Print nstring or list of strings
145.3699 + * Accepts: string / string list
145.3700 + */
145.3701 +
145.3702 +void pnstringorlist (STRINGLIST *s)
145.3703 +{
145.3704 +  if (!s) PSOUT ("NIL");	/* no argument given */
145.3705 +  else if (s->next) {		/* output list as list of strings*/
145.3706 +    PBOUT ('(');		/* start list */
145.3707 +    do {			/* output list member */
145.3708 +      psizedstring (&s->text,NIL);
145.3709 +      if (s->next) PBOUT (' ');
145.3710 +    } while (s = s->next);
145.3711 +    PBOUT (')');		/* terminate list */
145.3712 +  } 
145.3713 +				/* and single-element list as string */
145.3714 +  else psizedstring (&s->text,NIL);
145.3715 +}
145.3716 +
145.3717 +/* Print body part string
145.3718 + * Accepts: message number
145.3719 + *	    body part id (note: must have space at end to append stuff)
145.3720 + *	    sized text of string
145.3721 + *	    alternative stringstruct of string
145.3722 + *	    text printing arguments
145.3723 + */
145.3724 +
145.3725 +void pbodypartstring (unsigned long msgno,char *id,SIZEDTEXT *st,STRING *bs,
145.3726 +		      TEXTARGS *ta)
145.3727 +{
145.3728 +  int f = mail_elt (stream,msgno)->seen;
145.3729 +				/* ignore stringstruct if non-initialized */
145.3730 +  if (bs && !bs->curpos) bs = NIL;
145.3731 +  if (ta && st->size) {		/* only if have useful data */
145.3732 +				/* partial specifier */
145.3733 +    if (ta->first || ta->last) sprintf (id + strlen (id),"<%lu>",ta->first);
145.3734 +  				/* in case first byte beyond end of text */
145.3735 +    if (st->size <= ta->first) st->size = ta->first = 0;
145.3736 +    else {
145.3737 +      if (st->data) {		/* offset and truncate */
145.3738 +	st->data += ta->first;	/* move to desired position */
145.3739 +	st->size -= ta->first;	/* reduced size */
145.3740 +      }
145.3741 +      else if (bs && (SIZE (bs) >= ta->first))
145.3742 +	SETPOS (bs,ta->first + GETPOS (bs));
145.3743 +      else st->size = 0;	/* shouldn't happen */
145.3744 +      if (ta->last && (st->size > ta->last)) st->size = ta->last;
145.3745 +    }
145.3746 +  }
145.3747 +  PSOUT (id);
145.3748 +  PBOUT (' ');
145.3749 +  psizedstring (st,bs);		/* output string */
145.3750 +  changed_flags (msgno,f);	/* and changed flags */
145.3751 +}
145.3752 +
145.3753 +/*  RFC 3501 technically forbids NULs in literals.  Normally, the delivering
145.3754 + * MTA would take care of MIME converting the message text so that it is
145.3755 + * NUL-free.  If it doesn't, then we have the choice of either violating
145.3756 + * IMAP by sending NULs, corrupting the data, or going to lots of work to do
145.3757 + * MIME conversion in the IMAP server.
145.3758 + */
145.3759 +
145.3760 +/* Print raw sized text
145.3761 + * Accepts: sizedtext
145.3762 + */
145.3763 +
145.3764 +void ptext (SIZEDTEXT *txt,STRING *st)
145.3765 +{
145.3766 +  unsigned char c,*s;
145.3767 +  unsigned long i = txt->size;
145.3768 +  if (s = txt->data) while (i && ((PBOUT ((c = *s++) ? c : 0x80) != EOF))) --i;
145.3769 +  else if (st) while (i && (PBOUT ((c = SNX (st)) ? c : 0x80) != EOF)) --i;
145.3770 +				/* failed to complete? */
145.3771 +  if (i) ioerror (stdout,"writing text");
145.3772 +}
145.3773 +
145.3774 +/* Print thread
145.3775 + * Accepts: thread
145.3776 + */
145.3777 +
145.3778 +void pthread (THREADNODE *thr)
145.3779 +{
145.3780 +  THREADNODE *t;
145.3781 +  while (thr) {			/* for each branch */
145.3782 +    PBOUT ('(');		/* open branch */
145.3783 +    if (thr->num) {		/* first node message number */
145.3784 +      pnum (thr->num);
145.3785 +      if (t = thr->next) {	/* any subsequent nodes? */
145.3786 +	PBOUT (' ');
145.3787 +	while (t) {		/* for each subsequent node */
145.3788 +	  if (t->branch) {	/* branches? */
145.3789 +	    pthread (t);	/* yes, recurse to do branch */
145.3790 +	    t = NIL;		/* done */
145.3791 +	  }
145.3792 +	  else {		/* just output this number */
145.3793 +	    pnum (t->num);
145.3794 +	    t = t->next;	/* and do next message */
145.3795 +	  }
145.3796 +	  if (t) PBOUT (' ');	/* delimit if more to come */
145.3797 +	}
145.3798 +      }
145.3799 +    }
145.3800 +    else pthread (thr->next);	/* nest for dummy */
145.3801 +    PBOUT (')');		/* done with this branch */
145.3802 +    thr = thr->branch;		/* do next branch */
145.3803 +  }
145.3804 +}
145.3805 +
145.3806 +/* Print capabilities
145.3807 + * Accepts: option flag
145.3808 + */
145.3809 +
145.3810 +void pcapability (long flag)
145.3811 +{
145.3812 +  unsigned long i;
145.3813 +  char *s;
145.3814 +  struct stat sbuf;
145.3815 +  AUTHENTICATOR *auth;
145.3816 +  THREADER *thr = (THREADER *) mail_parameters (NIL,GET_THREADERS,NIL);
145.3817 +				/* always output protocol level */
145.3818 +  PSOUT ("CAPABILITY IMAP4REV1 I18NLEVEL=1 LITERAL+");
145.3819 +#ifdef NETSCAPE_BRAIN_DAMAGE
145.3820 +  PSOUT (" X-NETSCAPE");
145.3821 +#endif
145.3822 +  if (flag >= 0) {		/* want post-authentication capabilities? */
145.3823 +    PSOUT (" IDLE UIDPLUS NAMESPACE CHILDREN MAILBOX-REFERRALS BINARY UNSELECT ESEARCH WITHIN SCAN SORT");
145.3824 +    while (thr) {		/* threaders */
145.3825 +      PSOUT (" THREAD=");
145.3826 +      PSOUT (thr->name);
145.3827 +      thr = thr->next;
145.3828 +    }
145.3829 +    if (!anonymous) PSOUT (" MULTIAPPEND");
145.3830 +  }
145.3831 +  if (flag <= 0) {		/* want pre-authentication capabilities? */
145.3832 +    PSOUT (" SASL-IR LOGIN-REFERRALS");
145.3833 +    if (s = ssl_start_tls (NIL)) fs_give ((void **) &s);
145.3834 +    else PSOUT (" STARTTLS");
145.3835 +				/* disable plaintext */
145.3836 +    if (!(i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)))
145.3837 +      PSOUT (" LOGINDISABLED");
145.3838 +    for (auth = mail_lookup_auth (1); auth; auth = auth->next)
145.3839 +      if (auth->server && !(auth->flags & AU_DISABLE) &&
145.3840 +	  !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
145.3841 +	PSOUT (" AUTH=");
145.3842 +	PSOUT (auth->name);
145.3843 +      }
145.3844 +    if (!stat (ANOFILE,&sbuf)) PSOUT (" AUTH=ANONYMOUS");
145.3845 +  }
145.3846 +}
145.3847 +
145.3848 +/* Anonymous users may only use these mailboxes in these namespaces */
145.3849 +
145.3850 +char *oktab[] = {"#news.", "#ftp/", "#public/", 0};
145.3851 +
145.3852 +
145.3853 +/* Check if mailbox name is OK
145.3854 + * Accepts: reference name
145.3855 + *	    mailbox name
145.3856 + */
145.3857 +
145.3858 +long nameok (char *ref,char *name)
145.3859 +{
145.3860 +  int i;
145.3861 +  unsigned char *s,*t;
145.3862 +  if (!name) return NIL;	/* failure if missing name */
145.3863 +  if (!anonymous) return T;	/* otherwise OK if not anonymous */
145.3864 +				/* validate reference */
145.3865 +  if (ref && ((*ref == '#') || (*ref == '{')))
145.3866 +    for (i = 0; oktab[i]; i++) {
145.3867 +      for (s = ref, t = oktab[i]; *t && !compare_uchar (*s,*t); s++, t++);
145.3868 +      if (!*t) {		/* reference OK */
145.3869 +	if (*name == '#') break;/* check name if override */
145.3870 +	else return T;		/* otherwise done */
145.3871 +      }
145.3872 +    }
145.3873 +				/* ordinary names are OK */
145.3874 +  if ((*name != '#') && (*name != '{')) return T;
145.3875 +  for (i = 0; oktab[i]; i++) {	/* validate mailbox */
145.3876 +    for (s = name, t = oktab[i]; *t && !compare_uchar (*s,*t); s++, t++);
145.3877 +    if (!*t) return T;		/* name is OK */
145.3878 +  }
145.3879 +  response = "%.80s NO Anonymous may not %.80s this name\015\012";
145.3880 +  return NIL;
145.3881 +}
145.3882 +
145.3883 +
145.3884 +/* Convert possible BBoard name to actual name
145.3885 + * Accepts: command
145.3886 + *	    mailbox name
145.3887 + * Returns: maibox name
145.3888 + */
145.3889 +
145.3890 +char *bboardname (char *cmd,char *name)
145.3891 +{
145.3892 +  if (cmd[0] == 'B') {		/* want bboard? */
145.3893 +    char *s = litstk[litsp++] = (char *) fs_get (strlen (name) + 9);
145.3894 +    sprintf (s,"#public/%s",(*name == '/') ? name+1 : name);
145.3895 +    name = s;
145.3896 +  }
145.3897 +  return name;
145.3898 +}
145.3899 +
145.3900 +/* Test if name is news proxy
145.3901 + * Accepts: name
145.3902 + * Returns: T if news proxy, NIL otherwise
145.3903 + */
145.3904 +
145.3905 +long isnewsproxy (char *name)
145.3906 +{
145.3907 +  return (nntpproxy && (name[0] == '#') &&
145.3908 +	  ((name[1] == 'N') || (name[1] == 'n')) &&
145.3909 +	  ((name[2] == 'E') || (name[2] == 'e')) &&
145.3910 +	  ((name[3] == 'W') || (name[3] == 'w')) &&
145.3911 +	  ((name[4] == 'S') || (name[4] == 's')) && (name[5] == '.')) ?
145.3912 +    LONGT : NIL;
145.3913 +}
145.3914 +
145.3915 +
145.3916 +/* News proxy generate canonical pattern
145.3917 + * Accepts: reference
145.3918 + *	    pattern
145.3919 + *	    buffer to return canonical pattern
145.3920 + * Returns: T on success with pattern in buffer, NIL on failure
145.3921 + */
145.3922 +
145.3923 +long newsproxypattern (char *ref,char *pat,char *pattern,long flag)
145.3924 +{
145.3925 +  if (!nntpproxy) return NIL;
145.3926 +  if (strlen (ref) > NETMAXMBX) {
145.3927 +    sprintf (pattern,"Invalid reference specification: %.80s",ref);
145.3928 +    mm_log (pattern,ERROR);
145.3929 +    return NIL;
145.3930 +  }
145.3931 +  if (strlen (pat) > NETMAXMBX) {
145.3932 +    sprintf (pattern,"Invalid pattern specification: %.80s",pat);
145.3933 +    mm_log (pattern,ERROR);
145.3934 +    return NIL;
145.3935 +  }
145.3936 +  if (flag) {			/* prepend proxy specifier */
145.3937 +    sprintf (pattern,"{%.300s/nntp}",nntpproxy);
145.3938 +    pattern += strlen (pattern);
145.3939 +  }
145.3940 +  if (*ref) {			/* have a reference */
145.3941 +    strcpy (pattern,ref);	/* copy reference to pattern */
145.3942 +				/* # overrides mailbox field in reference */
145.3943 +    if (*pat == '#') strcpy (pattern,pat);
145.3944 +				/* pattern starts, reference ends, with . */
145.3945 +    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
145.3946 +      strcat (pattern,pat + 1);	/* append, omitting one of the period */
145.3947 +    else strcat (pattern,pat);	/* anything else is just appended */
145.3948 +  }
145.3949 +  else strcpy (pattern,pat);	/* just have basic name */
145.3950 +  return isnewsproxy (pattern);
145.3951 +}
145.3952 +
145.3953 +/* IMAP4rev1 Authentication responder
145.3954 + * Accepts: challenge
145.3955 + *	    length of challenge
145.3956 + *	    pointer to response length return location if non-NIL
145.3957 + * Returns: response
145.3958 + */
145.3959 +
145.3960 +#define RESPBUFLEN 8*MAILTMPLEN
145.3961 +
145.3962 +char *imap_responder (void *challenge,unsigned long clen,unsigned long *rlen)
145.3963 +{
145.3964 +  unsigned long i,j;
145.3965 +  unsigned char *t,resp[RESPBUFLEN];
145.3966 +  if (initial) {		/* initial response given? */
145.3967 +    if (clen) return NIL;	/* not permitted */
145.3968 +				/* set up response */
145.3969 +    i = strlen ((char *) (t = initial));
145.3970 +    initial = NIL;		/* no more initial response */
145.3971 +    if ((*t == '=') && !t[1]) {	/* SASL-IR does this for 0-length response */
145.3972 +      if (rlen) *rlen = 0;	/* set length zero if empty */
145.3973 +      return cpystr ("");	/* and return empty string as response */
145.3974 +    }
145.3975 +  }
145.3976 +  else {			/* issue challenge, get response */
145.3977 +    PSOUT ("+ ");
145.3978 +    for (t = rfc822_binary ((void *) challenge,clen,&i),j = 0; j < i; j++)
145.3979 +      if (t[j] > ' ') PBOUT (t[j]);
145.3980 +    fs_give ((void **) &t);
145.3981 +    CRLF;
145.3982 +    PFLUSH ();			/* dump output buffer */
145.3983 +				/* slurp response buffer */
145.3984 +    slurp ((char *) resp,RESPBUFLEN,INPUTTIMEOUT);
145.3985 +    if (!(t = (unsigned char *) strchr ((char *) resp,'\012')))
145.3986 +      return (char *) flush ();
145.3987 +    if (t[-1] == '\015') --t;	/* remove CR */
145.3988 +    *t = '\0';			/* tie off buffer */
145.3989 +    if (resp[0] == '*') {
145.3990 +      cancelled = T;
145.3991 +      return NIL;
145.3992 +    }
145.3993 +    i = t - resp;		/* length of response */
145.3994 +    t = resp;			/* set up for return call */
145.3995 +  }
145.3996 +  return (i % 4) ? NIL :	/* return if valid BASE64 */
145.3997 +    (char *) rfc822_base64 (t,i,rlen ? rlen : &i);
145.3998 +}
145.3999 +
145.4000 +/* Proxy copy across mailbox formats
145.4001 + * Accepts: mail stream
145.4002 + *	    sequence to copy on this stream
145.4003 + *	    destination mailbox
145.4004 + *	    option flags
145.4005 + * Returns: T if success, else NIL
145.4006 + */
145.4007 +
145.4008 +long proxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
145.4009 +{
145.4010 +  MAILSTREAM *ts;
145.4011 +  STRING st;
145.4012 +  MSGDATA md;
145.4013 +  SEARCHSET *set;
145.4014 +  char tmp[MAILTMPLEN];
145.4015 +  unsigned long i,j;
145.4016 +  md.stream = stream;
145.4017 +  md.msgno = 0;
145.4018 +  md.flags = md.date = NIL;
145.4019 +  md.message = &st;
145.4020 +  /* Currently ignores CP_MOVE and CP_DEBUG */
145.4021 +  if (!((options & CP_UID) ?	/* validate sequence */
145.4022 +	mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))
145.4023 +    return NIL;
145.4024 +  response = win;		/* cancel previous errors */
145.4025 +  if (lsterr) fs_give ((void **) &lsterr);
145.4026 +				/* c-client clobbers sequence, use spare */
145.4027 +  for (i = 1,j = 0,set = mail_newsearchset (); i <= nmsgs; i++)
145.4028 +    if (mail_elt (stream,i)->spare = mail_elt (stream,i)->sequence) {
145.4029 +      mail_append_set (set,mail_uid (stream,i));
145.4030 +      if (!j) md.msgno = (j = i) - 1;
145.4031 +    }
145.4032 +				/* only if at least one message to copy */
145.4033 +  if (j && !mail_append_multiple (NIL,mailbox,proxy_append,(void *) &md)) {
145.4034 +    response = trycreate ? losetry : lose;
145.4035 +    if (set) mail_free_searchset (&set);
145.4036 +    return NIL;
145.4037 +  }
145.4038 +  if (caset) csset = set;	/* set for return value now */
145.4039 +  else if (set) mail_free_searchset (&set);
145.4040 +  response = win;		/* stomp any previous babble */
145.4041 +  if (md.msgno) {		/* get new driver name if was dummy */
145.4042 +    sprintf (tmp,"Cross-format (%.80s -> %.80s) COPY completed",
145.4043 +	     stream->dtb->name,(ts = mail_open (NIL,mailbox,OP_PROTOTYPE)) ?
145.4044 +	     ts->dtb->name : "unknown");
145.4045 +    mm_log (tmp,NIL);
145.4046 +  }
145.4047 +  return LONGT;
145.4048 +}
145.4049 +
145.4050 +/* Proxy append message callback
145.4051 + * Accepts: MAIL stream
145.4052 + *	    append data package
145.4053 + *	    pointer to return initial flags
145.4054 + *	    pointer to return message internal date
145.4055 + *	    pointer to return stringstruct of message or NIL to stop
145.4056 + * Returns: T if success (have message or stop), NIL if error
145.4057 + */
145.4058 +
145.4059 +long proxy_append (MAILSTREAM *stream,void *data,char **flags,char **date,
145.4060 +		   STRING **message)
145.4061 +{
145.4062 +  MESSAGECACHE *elt;
145.4063 +  unsigned long i;
145.4064 +  char *s,*t,tmp[MAILTMPLEN];
145.4065 +  MSGDATA *md = (MSGDATA *) data;
145.4066 +  if (md->flags) fs_give ((void **) &md->flags);
145.4067 +  if (md->date) fs_give ((void **) &md->date);
145.4068 +  *message = NIL;		/* assume all done */
145.4069 +  *flags = *date = NIL;
145.4070 +  while (++md->msgno <= nmsgs)
145.4071 +    if ((elt = mail_elt (md->stream,md->msgno))->spare) {
145.4072 +      if (!(elt->valid && elt->day)) {
145.4073 +	sprintf (tmp,"%lu",md->msgno);
145.4074 +	mail_fetch_fast (md->stream,tmp,NIL);
145.4075 +      }
145.4076 +      memset (s = tmp,0,MAILTMPLEN);
145.4077 +				/* copy flags */
145.4078 +      if (elt->seen) strcat (s," \\Seen");
145.4079 +      if (elt->deleted) strcat (s," \\Deleted");
145.4080 +      if (elt->flagged) strcat (s," \\Flagged");
145.4081 +      if (elt->answered) strcat (s," \\Answered");
145.4082 +      if (elt->draft) strcat (s," \\Draft");
145.4083 +      if (i = elt->user_flags) do 
145.4084 +	if ((t = md->stream->user_flags[find_rightmost_bit (&i)]) && *t &&
145.4085 +	    (strlen (t) < ((size_t) (MAILTMPLEN-((s += strlen (s))+2-tmp))))) {
145.4086 +	*s++ = ' ';		/* space delimiter */
145.4087 +	strcpy (s,t);
145.4088 +      } while (i);		/* until no more user flags */
145.4089 +      *message = md->message;	/* set up return values */
145.4090 +      *flags = md->flags = cpystr (tmp + 1);
145.4091 +      *date = md->date = cpystr (mail_date (tmp,elt));
145.4092 +      INIT (md->message,msg_string,(void *) md,elt->rfc822_size);
145.4093 +      break;			/* process this message */
145.4094 +    }
145.4095 +  return LONGT;
145.4096 +}
145.4097 +
145.4098 +/* Append message callback
145.4099 + * Accepts: MAIL stream
145.4100 + *	    append data package
145.4101 + *	    pointer to return initial flags
145.4102 + *	    pointer to return message internal date
145.4103 + *	    pointer to return stringstruct of message or NIL to stop
145.4104 + * Returns: T if success (have message or stop), NIL if error
145.4105 + */
145.4106 +
145.4107 +long append_msg (MAILSTREAM *stream,void *data,char **flags,char **date,
145.4108 +		 STRING **message)
145.4109 +{
145.4110 +  unsigned long i,j;
145.4111 +  char *t;
145.4112 +  APPENDDATA *ad = (APPENDDATA *) data;
145.4113 +  unsigned char *arg = ad->arg;
145.4114 +				/* flush text of previous message */
145.4115 +  if (t = ad->flags) fs_give ((void **) &ad->flags);
145.4116 +  if (t = ad->date) fs_give ((void **) &ad->date);
145.4117 +  if (t = ad->msg) fs_give ((void **) &ad->msg);
145.4118 +  *flags = *date = NIL;		/* assume no flags or date */
145.4119 +  if (t) {			/* have previous message? */
145.4120 +    if (!*arg) {		/* if least one message, and no more coming */
145.4121 +      *message = NIL;		/* set stop */
145.4122 +      return LONGT;		/* return success */
145.4123 +    }
145.4124 +    else if (*arg++ != ' ') {	/* must have a delimiter to next argument */
145.4125 +      response = misarg;	/* oops */
145.4126 +      return NIL;
145.4127 +    }
145.4128 +  }
145.4129 +  *message = ad->message;	/* return pointer to message stringstruct */
145.4130 +  if (*arg == '(') {		/* parse optional flag list */
145.4131 +    t = ++arg;			/* pointer to flag list contents */
145.4132 +    while (*arg && (*arg != ')')) arg++;
145.4133 +    if (*arg) *arg++ = '\0';
145.4134 +    if (*arg == ' ') arg++;
145.4135 +    *flags = ad->flags = cpystr (t);
145.4136 +  }
145.4137 +				/* parse optional date */
145.4138 +  if (*arg == '"') *date = ad->date = cpystr (snarf (&arg));
145.4139 +  if (!arg || (*arg != '{'))	/* parse message */
145.4140 +    response = "%.80s BAD Missing literal in %.80s\015\012";
145.4141 +  else if (!isdigit (arg[1]))
145.4142 +    response = "%.80s BAD Missing message to %.80s\015\012";
145.4143 +  else if (!(i = strtoul (arg+1,&t,10)))
145.4144 +    response = "%.80s NO Empty message to %.80s\015\012";
145.4145 +  else if (i > MAXAPPENDTXT)	/* maybe relax this a little */
145.4146 +    response = "%.80s NO Excessively large message to %.80s\015\012";
145.4147 +  else if (((*t == '+') && (t[1] == '}') && !t[2]) || ((*t == '}') && !t[1])) {
145.4148 +				/* get a literal buffer */
145.4149 +    inliteral (ad->msg = (char *) fs_get (i+1),i);
145.4150 +    				/* get new command tail */
145.4151 +    slurp (ad->arg,CMDLEN - (ad->arg - cmdbuf),INPUTTIMEOUT);
145.4152 +    if (strchr (ad->arg,'\012')) {
145.4153 +				/* reset strtok mechanism, tie off if done */
145.4154 +      if (!strtok (ad->arg,"\015\012")) *ad->arg = '\0';
145.4155 +				/* possible LITERAL+? */
145.4156 +      if (((j = strlen (ad->arg)) > 3) && (ad->arg[j - 1] == '}') &&
145.4157 +	  (ad->arg[j - 2] == '+') && isdigit (ad->arg[j - 3])) {
145.4158 +				/* back over possible count */
145.4159 +	for (j -= 4; j && isdigit (ad->arg[j]); j--);
145.4160 +	if (ad->arg[j] == '{') {/* found a literal? */
145.4161 +	  litplus.ok = T;	/* yes, note LITERAL+ in effect, set size */
145.4162 +	  litplus.size = strtoul (ad->arg + j + 1,NIL,10);
145.4163 +	}
145.4164 +      }
145.4165 +				/* initialize stringstruct */
145.4166 +      INIT (ad->message,mail_string,(void *) ad->msg,i);
145.4167 +      return LONGT;		/* ready to go */
145.4168 +    }
145.4169 +    flush ();			/* didn't find end of line? */
145.4170 +    fs_give ((void **) &ad->msg);
145.4171 +  }
145.4172 +  else response = badarg;	/* not a literal */
145.4173 +  return NIL;			/* error */
145.4174 +}
145.4175 +
145.4176 +/* Got COPY UID data
145.4177 + * Accepts: MAIL stream
145.4178 + *	    mailbox name
145.4179 + *	    UID validity
145.4180 + *	    source set of UIDs
145.4181 + *	    destination set of UIDs
145.4182 + */
145.4183 +
145.4184 +void copyuid (MAILSTREAM *stream,char *mailbox,unsigned long uidvalidity,
145.4185 +	      SEARCHSET *sourceset,SEARCHSET *destset)
145.4186 +{
145.4187 +  if (cauidvalidity) fatal ("duplicate COPYUID/APPENDUID data");
145.4188 +  cauidvalidity = uidvalidity;
145.4189 +  csset = sourceset;
145.4190 +  caset = destset;
145.4191 +}
145.4192 +
145.4193 +
145.4194 +/* Got APPEND UID data
145.4195 + * Accepts: mailbox name
145.4196 + *	    UID validity
145.4197 + *	    destination set of UIDs
145.4198 + */
145.4199 +
145.4200 +void appenduid (char *mailbox,unsigned long uidvalidity,SEARCHSET *set)
145.4201 +{
145.4202 +  copyuid (NIL,mailbox,uidvalidity,NIL,set);
145.4203 +}
145.4204 +
145.4205 +
145.4206 +/* Got a referral
145.4207 + * Accepts: MAIL stream
145.4208 + *	    URL
145.4209 + *	    referral type code
145.4210 + */
145.4211 +
145.4212 +char *referral (MAILSTREAM *stream,char *url,long code)
145.4213 +{
145.4214 +  if (lstref) fs_give ((void **) &lstref);
145.4215 +  lstref = cpystr (url);	/* set referral */
145.4216 +				/* set error if not a logged in referral */
145.4217 +  if (code != REFAUTH) response = lose;
145.4218 +  if (!lsterr) lsterr = cpystr ("Try referral URL");
145.4219 +  return NIL;			/* don't chase referrals for now */
145.4220 +}
145.4221 +
145.4222 +/* Co-routines from MAIL library */
145.4223 +
145.4224 +
145.4225 +/* Message matches a search
145.4226 + * Accepts: MAIL stream
145.4227 + *	    message number
145.4228 + */
145.4229 +
145.4230 +void mm_searched (MAILSTREAM *s,unsigned long msgno)
145.4231 +{
145.4232 +				/* nothing to do here */
145.4233 +}
145.4234 +
145.4235 +
145.4236 +/* Message exists (i.e. there are that many messages in the mailbox)
145.4237 + * Accepts: MAIL stream
145.4238 + *	    message number
145.4239 + */
145.4240 +
145.4241 +void mm_exists (MAILSTREAM *s,unsigned long number)
145.4242 +{
145.4243 +				/* note change in number of messages */
145.4244 +  if ((s != tstream) && (nmsgs != number)) {
145.4245 +    nmsgs = number;		/* always update number of messages */
145.4246 +    if (quell_events) existsquelled = T;
145.4247 +    else {
145.4248 +      PSOUT ("* ");
145.4249 +      pnum (nmsgs);
145.4250 +      PSOUT (" EXISTS\015\012");
145.4251 +    }
145.4252 +    recent = 0xffffffff;	/* make sure update recent too */
145.4253 +  }
145.4254 +}
145.4255 +
145.4256 +
145.4257 +/* Message expunged
145.4258 + * Accepts: MAIL stream
145.4259 + *	    message number
145.4260 + */
145.4261 +
145.4262 +void mm_expunged (MAILSTREAM *s,unsigned long number)
145.4263 +{
145.4264 +  if (quell_events) fatal ("Impossible EXPUNGE event");
145.4265 +  if (s != tstream) {
145.4266 +    PSOUT ("* ");
145.4267 +    pnum (number);
145.4268 +    PSOUT (" EXPUNGE\015\012");
145.4269 +  }
145.4270 +  nmsgs--;
145.4271 +  existsquelled = T;		/* do EXISTS when command done */
145.4272 +}
145.4273 +
145.4274 +
145.4275 +/* Message status changed
145.4276 + * Accepts: MAIL stream
145.4277 + *	    message number
145.4278 + */
145.4279 +
145.4280 +void mm_flags (MAILSTREAM *s,unsigned long number)
145.4281 +{
145.4282 +  if (s != tstream) mail_elt (s,number)->spare2 = T;
145.4283 +}
145.4284 +
145.4285 +/* Mailbox found
145.4286 + * Accepts: hierarchy delimiter
145.4287 + *	    mailbox name
145.4288 + *	    attributes
145.4289 + */
145.4290 +
145.4291 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
145.4292 +{
145.4293 +  mm_list_work ("LIST",delimiter,name,attributes);
145.4294 +}
145.4295 +
145.4296 +
145.4297 +/* Subscribed mailbox found
145.4298 + * Accepts: hierarchy delimiter
145.4299 + *	    mailbox name
145.4300 + *	    attributes
145.4301 + */
145.4302 +
145.4303 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
145.4304 +{
145.4305 +  mm_list_work ("LSUB",delimiter,name,attributes);
145.4306 +}
145.4307 +
145.4308 +
145.4309 +/* Mailbox status
145.4310 + * Accepts: MAIL stream
145.4311 + *	    mailbox name
145.4312 + *	    mailbox status
145.4313 + */
145.4314 +
145.4315 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
145.4316 +{
145.4317 +  if (!quell_events) {
145.4318 +    char tmp[MAILTMPLEN];
145.4319 +    tmp[0] = tmp[1] = '\0';
145.4320 +    if (status->flags & SA_MESSAGES)
145.4321 +      sprintf (tmp + strlen (tmp)," MESSAGES %lu",status->messages);
145.4322 +    if (status->flags & SA_RECENT)
145.4323 +      sprintf (tmp + strlen (tmp)," RECENT %lu",status->recent);
145.4324 +    if (status->flags & SA_UNSEEN)
145.4325 +      sprintf (tmp + strlen (tmp)," UNSEEN %lu",status->unseen);
145.4326 +    if (status->flags & SA_UIDNEXT)
145.4327 +      sprintf (tmp + strlen (tmp)," UIDNEXT %lu",status->uidnext);
145.4328 +    if (status->flags & SA_UIDVALIDITY)
145.4329 +      sprintf (tmp + strlen(tmp)," UIDVALIDITY %lu",status->uidvalidity);
145.4330 +    PSOUT ("* STATUS ");
145.4331 +    pastring (mailbox);
145.4332 +    PSOUT (" (");
145.4333 +    PSOUT (tmp+1);
145.4334 +    PBOUT (')');
145.4335 +    CRLF;
145.4336 +  }
145.4337 +}
145.4338 +
145.4339 +/* Worker routine for LIST and LSUB
145.4340 + * Accepts: name of response
145.4341 + *	    hierarchy delimiter
145.4342 + *	    mailbox name
145.4343 + *	    attributes
145.4344 + */
145.4345 +
145.4346 +void mm_list_work (char *what,int delimiter,char *name,long attributes)
145.4347 +{
145.4348 +  char *s;
145.4349 +  if (!quell_events) {
145.4350 +    char tmp[MAILTMPLEN];
145.4351 +    if (finding) {
145.4352 +      PSOUT ("* MAILBOX ");
145.4353 +      PSOUT (name);
145.4354 +    }
145.4355 +				/* new form */
145.4356 +    else if ((cmd[0] == 'R') || !(attributes & LATT_REFERRAL)) {
145.4357 +      PSOUT ("* ");
145.4358 +      PSOUT (what);
145.4359 +      PSOUT (" (");
145.4360 +      tmp[0] = tmp[1] = '\0';
145.4361 +      if (attributes & LATT_NOINFERIORS) strcat (tmp," \\NoInferiors");
145.4362 +      if (attributes & LATT_NOSELECT) strcat (tmp," \\NoSelect");
145.4363 +      if (attributes & LATT_MARKED) strcat (tmp," \\Marked");
145.4364 +      if (attributes & LATT_UNMARKED) strcat (tmp," \\UnMarked");
145.4365 +      if (attributes & LATT_HASCHILDREN) strcat (tmp," \\HasChildren");
145.4366 +      if (attributes & LATT_HASNOCHILDREN) strcat (tmp," \\HasNoChildren");
145.4367 +      PSOUT (tmp+1);
145.4368 +      switch (delimiter) {
145.4369 +      case '\\':		/* quoted delimiter */
145.4370 +      case '"':
145.4371 +	PSOUT (") \"\\");
145.4372 +	PBOUT (delimiter);
145.4373 +	PBOUT ('"');
145.4374 +	break;
145.4375 +      case '\0':		/* no delimiter */
145.4376 +	PSOUT (") NIL");
145.4377 +	break;
145.4378 +      default:			/* unquoted delimiter */
145.4379 +	PSOUT (") \"");
145.4380 +	PBOUT (delimiter);
145.4381 +	PBOUT ('"');
145.4382 +	break;
145.4383 +      }
145.4384 +      PBOUT (' ');
145.4385 +				/* output mailbox name */
145.4386 +      if (proxylist && (s = strchr (name,'}'))) pastring (s+1);
145.4387 +      else pastring (name);
145.4388 +    }
145.4389 +    CRLF;
145.4390 +  }
145.4391 +}
145.4392 +
145.4393 +/* Notification event
145.4394 + * Accepts: MAIL stream
145.4395 + *	    string to log
145.4396 + *	    error flag
145.4397 + */
145.4398 +
145.4399 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
145.4400 +{
145.4401 +  SIZEDTEXT msg;
145.4402 +  char *s,*code;
145.4403 +  if (!quell_events && (!tstream || (stream != tstream))) {
145.4404 +    switch (errflg) {
145.4405 +    case NIL:			/* information message, set as OK response */
145.4406 +      if ((string[0] == '[') &&
145.4407 +	  ((string[1] == 'T') || (string[1] == 't')) &&
145.4408 +	  ((string[2] == 'R') || (string[2] == 'r')) &&
145.4409 +	  ((string[3] == 'Y') || (string[3] == 'y')) &&
145.4410 +	  ((string[4] == 'C') || (string[4] == 'c')) &&
145.4411 +	  ((string[5] == 'R') || (string[5] == 'r')) &&
145.4412 +	  ((string[6] == 'E') || (string[6] == 'e')) &&
145.4413 +	  ((string[7] == 'A') || (string[7] == 'a')) &&
145.4414 +	  ((string[8] == 'T') || (string[8] == 't')) &&
145.4415 +	  ((string[9] == 'E') || (string[9] == 'e')) && (string[10] == ']'))
145.4416 +	trycreate = T;
145.4417 +    case BYE:			/* some other server signing off */
145.4418 +    case PARSE:			/* parse glitch, output unsolicited OK */
145.4419 +      code = "* OK ";
145.4420 +      break;
145.4421 +    case WARN:			/* warning, output unsolicited NO (kludge!) */
145.4422 +      code = "* NO ";
145.4423 +      break;
145.4424 +    case ERROR:			/* error that broke command */
145.4425 +    default:			/* default should never happen */
145.4426 +      code = "* BAD ";
145.4427 +      break;
145.4428 +    }
145.4429 +    PSOUT (code);
145.4430 +    msg.size = (s = strpbrk ((char *) (msg.data = (unsigned char *) string),
145.4431 +			     "\015\012")) ?
145.4432 +      (s - string) : strlen (string);
145.4433 +    PSOUTR (&msg);
145.4434 +    CRLF;
145.4435 +    PFLUSH ();			/* let client see it immediately */
145.4436 +  }
145.4437 +}
145.4438 +
145.4439 +/* Log an event for the user to see
145.4440 + * Accepts: string to log
145.4441 + *	    error flag
145.4442 + */
145.4443 +
145.4444 +void mm_log (char *string,long errflg)
145.4445 +{
145.4446 +  SIZEDTEXT msg;
145.4447 +  char *s;
145.4448 +  msg.size = 
145.4449 +    (s = strpbrk ((char *) (msg.data = (unsigned char *) string),"\015\012")) ?
145.4450 +      (s - string) : strlen (string);
145.4451 +  switch (errflg) {
145.4452 +  case NIL:			/* information message, set as OK response */
145.4453 +    if (response == win) {	/* only if no other response yet */
145.4454 +      if (lsterr) {		/* if there was a previous message */
145.4455 +	if (!quell_events) {
145.4456 +	  PSOUT ("* OK ");	/* blat it out */
145.4457 +	  PSOUT (lsterr);
145.4458 +	  CRLF;
145.4459 +	  PFLUSH ();		/* let client see it immediately */
145.4460 +	}
145.4461 +	fs_give ((void **) &lsterr);
145.4462 +      }
145.4463 +      lsterr = cpystr (string); /* copy string for later use */
145.4464 +      if (s) lsterr[s - string] = NIL;
145.4465 +    }
145.4466 +    break;
145.4467 +  case PARSE:			/* parse glitch, output unsolicited OK */
145.4468 +    if (!quell_events) {
145.4469 +      PSOUT ("* OK [PARSE] ");
145.4470 +      PSOUTR (&msg);
145.4471 +      CRLF;
145.4472 +      PFLUSH ();		/* let client see it immediately */
145.4473 +    }
145.4474 +    break;
145.4475 +  case WARN:			/* warning, output unsolicited NO */
145.4476 +				/* ignore "Mailbox is empty" (KLUDGE!) */
145.4477 +    if (strcmp (string,"Mailbox is empty")) {
145.4478 +      if (lstwrn) {		/* have previous warning? */
145.4479 +	if (!quell_events) {
145.4480 +	  PSOUT ("* NO ");
145.4481 +	  PSOUT (lstwrn);
145.4482 +	  CRLF;
145.4483 +	  PFLUSH ();		/* make sure client sees it immediately */
145.4484 +	}
145.4485 +	fs_give ((void **) &lstwrn);
145.4486 +      }
145.4487 +      lstwrn = cpystr (string); /* note last warning */
145.4488 +      if (s) lstwrn[s - string] = NIL;
145.4489 +    }
145.4490 +    break;
145.4491 +  case ERROR:			/* error that broke command */
145.4492 +  default:			/* default should never happen */
145.4493 +    response = trycreate ? losetry : lose;
145.4494 +    if (lsterr) fs_give ((void **) &lsterr);
145.4495 +    lsterr = cpystr (string);	/* note last error */
145.4496 +    if (s) lsterr[s - string] = NIL;
145.4497 +    break;
145.4498 +  }
145.4499 +}
145.4500 +
145.4501 +/* Return last error
145.4502 + */
145.4503 +
145.4504 +char *lasterror (void)
145.4505 +{
145.4506 +  if (lsterr) return lsterr;
145.4507 +  if (lstwrn) return lstwrn;
145.4508 +  return "<unknown>";
145.4509 +}
145.4510 +
145.4511 +
145.4512 +/* Log an event to debugging telemetry
145.4513 + * Accepts: string to log
145.4514 + */
145.4515 +
145.4516 +void mm_dlog (char *string)
145.4517 +{
145.4518 +  mm_log (string,WARN);		/* shouldn't happen normally */
145.4519 +}
145.4520 +
145.4521 +/* Get user name and password for this host
145.4522 + * Accepts: parse of network user name
145.4523 + *	    where to return user name
145.4524 + *	    where to return password
145.4525 + *	    trial count
145.4526 + */
145.4527 +
145.4528 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
145.4529 +{
145.4530 +				/* set user name */
145.4531 +  strncpy (username,*mb->user ? mb->user : (char *) user,NETMAXUSER);
145.4532 +  strncpy (password,pass,256);	/* and password */
145.4533 +}
145.4534 +
145.4535 +
145.4536 +/* About to enter critical code
145.4537 + * Accepts: stream
145.4538 + */
145.4539 +
145.4540 +void mm_critical (MAILSTREAM *s)
145.4541 +{
145.4542 +  ++critical;
145.4543 +}
145.4544 +
145.4545 +
145.4546 +/* About to exit critical code
145.4547 + * Accepts: stream
145.4548 + */
145.4549 +
145.4550 +void mm_nocritical (MAILSTREAM *s)
145.4551 +{
145.4552 +				/* go non-critical, pending death? */
145.4553 +  if (!--critical && (state == LOGOUT)) {
145.4554 +				/* clean up iff needed */
145.4555 +    if (s && (stream != s) && !s->lock && (s->dtb->flags & DR_XPOINT))
145.4556 +      s = mail_close (s);
145.4557 +    longjmp (jmpenv,1);		/* die now */
145.4558 +  }
145.4559 +}
145.4560 +
145.4561 +/* Disk error found
145.4562 + * Accepts: stream
145.4563 + *	    system error code
145.4564 + *	    flag indicating that mailbox may be clobbered
145.4565 + * Returns: abort flag
145.4566 + */
145.4567 +
145.4568 +long mm_diskerror (MAILSTREAM *s,long errcode,long serious)
145.4569 +{
145.4570 +  if (serious) {		/* try your damnest if clobberage likely */
145.4571 +    mm_notify (s,"Retrying to fix probable mailbox damage!",ERROR);
145.4572 +    PFLUSH ();			/* dump output buffer */
145.4573 +    syslog (LOG_ALERT,
145.4574 +	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
145.4575 +	    user ? (char *) user : "???",tcp_clienthost (),
145.4576 +	    (stream && stream->mailbox) ? stream->mailbox : "???",
145.4577 +	    strerror (errcode));
145.4578 +    settimeout (0);		/* make damn sure timeout disabled */
145.4579 +    sleep (60);			/* give it some time to clear up */
145.4580 +    return NIL;
145.4581 +  }
145.4582 +  if (!quell_events) {		/* otherwise die before more damage is done */
145.4583 +    PSOUT ("* NO Disk error: ");
145.4584 +    PSOUT (strerror (errcode));
145.4585 +    CRLF;
145.4586 +  }
145.4587 +  return T;
145.4588 +}
145.4589 +
145.4590 +
145.4591 +/* Log a fatal error event
145.4592 + * Accepts: string to log
145.4593 + */
145.4594 +
145.4595 +void mm_fatal (char *string)
145.4596 +{
145.4597 +  SIZEDTEXT msg;
145.4598 +  char *s;
145.4599 +  msg.size = 
145.4600 +    (s = strpbrk ((char *) (msg.data = (unsigned char *) string),"\015\012")) ?
145.4601 +      (s - string) : strlen (string);
145.4602 +  if (!quell_events) {
145.4603 +    PSOUT ("* BYE [ALERT] IMAP4rev1 server crashing: ");
145.4604 +    PSOUTR (&msg);
145.4605 +    CRLF;
145.4606 +    PFLUSH ();
145.4607 +  }
145.4608 +  syslog (LOG_ALERT,"Fatal error user=%.80s host=%.80s mbx=%.80s: %.80s",
145.4609 +	  user ? (char *) user : "???",tcp_clienthost (),
145.4610 +	  (stream && stream->mailbox) ? stream->mailbox : "???",string);
145.4611 +}
   146.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   146.2 +++ b/src/imapd/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
   146.3 @@ -0,0 +1,55 @@
   146.4 +# ========================================================================
   146.5 +# Copyright 1988-2006 University of Washington
   146.6 +#
   146.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   146.8 +# you may not use this file except in compliance with the License.
   146.9 +# You may obtain a copy of the License at
  146.10 +#
  146.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  146.12 +#
  146.13 +# 
  146.14 +# ========================================================================
  146.15 +
  146.16 +
  146.17 +# Program:	IMAPD Makefile for Windows 9x and Windows NT
  146.18 +#
  146.19 +# Author:	Mark Crispin
  146.20 +#		Networks and Distributed Computing
  146.21 +#		Computing & Communications
  146.22 +#		University of Washington
  146.23 +#		Administration Building, AG-44
  146.24 +#		Seattle, WA  98195
  146.25 +#		Internet: MRC@CAC.Washington.EDU
  146.26 +#
  146.27 +# Date:		5 November 1990
  146.28 +# Last Edited:	30 August 2006
  146.29 +
  146.30 +
  146.31 +ALERT=\\imapd.alert
  146.32 +USERALERT=alert.txt
  146.33 +SHUTDOWN=\\nologin
  146.34 +ANO=\\anonymous.newsgroups
  146.35 +NNTP=\\imapd.nntp
  146.36 +
  146.37 +C = ..\c-client
  146.38 +CCLIENTLIB = $C\cclient.lib
  146.39 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
  146.40 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  146.41 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  146.42 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
  146.43 +
  146.44 +imapd: $(CCLIENTLIB) imapd.obj
  146.45 +	LINK /NOLOGO imapd.obj $(LIBS)
  146.46 +
  146.47 +imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
  146.48 +
  146.49 +$(CCLIENTLIB):
  146.50 +	@echo Make c-client first
  146.51 +	false
  146.52 +
  146.53 +clean:
  146.54 +	del *.obj *.exe *.lib *.exp || rem
  146.55 +
  146.56 +# A monument to a hack of long ago and far away...
  146.57 +love:
  146.58 +	@echo not war?
   147.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   147.2 +++ b/src/imapd/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
   147.3 @@ -0,0 +1,58 @@
   147.4 +# ========================================================================
   147.5 +# Copyright 1988-2006 University of Washington
   147.6 +#
   147.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   147.8 +# you may not use this file except in compliance with the License.
   147.9 +# You may obtain a copy of the License at
  147.10 +#
  147.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  147.12 +#
  147.13 +# 
  147.14 +# ========================================================================
  147.15 +
  147.16 +
  147.17 +# Program:	IMAPD Makefile for Windows 9x and Windows NT + Kerberos
  147.18 +#
  147.19 +# Author:	Mark Crispin
  147.20 +#		Networks and Distributed Computing
  147.21 +#		Computing & Communications
  147.22 +#		University of Washington
  147.23 +#		Administration Building, AG-44
  147.24 +#		Seattle, WA  98195
  147.25 +#		Internet: MRC@CAC.Washington.EDU
  147.26 +#
  147.27 +# Date:		5 November 1990
  147.28 +# Last Edited:	30 August 2006
  147.29 +
  147.30 +
  147.31 +ALERT=\\imapd.alert
  147.32 +USERALERT=alert.txt
  147.33 +SHUTDOWN=\\nologin
  147.34 +ANO=\\anonymous.newsgroups
  147.35 +NNTP=\\imapd.nntp
  147.36 +
  147.37 +
  147.38 +C = ..\c-client
  147.39 +CCLIENTLIB = $C\cclient.lib
  147.40 +K5 =  \k5\lib
  147.41 +K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
  147.42 +LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
  147.43 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  147.44 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  147.45 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
  147.46 +
  147.47 +imapd: $(CCLIENTLIB) imapd.obj
  147.48 +	LINK /NOLOGO imapd.obj $(LIBS)
  147.49 +
  147.50 +imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
  147.51 +
  147.52 +$(CCLIENTLIB):
  147.53 +	@echo Make c-client first
  147.54 +	false
  147.55 +
  147.56 +clean:
  147.57 +	del *.obj *.exe *.lib *.exp || rem
  147.58 +
  147.59 +# A monument to a hack of long ago and far away...
  147.60 +love:
  147.61 +	@echo not war?
   148.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   148.2 +++ b/src/imapd/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
   148.3 @@ -0,0 +1,56 @@
   148.4 +# ========================================================================
   148.5 +# Copyright 1988-2006 University of Washington
   148.6 +#
   148.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   148.8 +# you may not use this file except in compliance with the License.
   148.9 +# You may obtain a copy of the License at
  148.10 +#
  148.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  148.12 +#
  148.13 +# 
  148.14 +# ========================================================================
  148.15 +
  148.16 +
  148.17 +# Program:	IMAPD Makefile for Windows 2000/XP
  148.18 +#
  148.19 +# Author:	Mark Crispin
  148.20 +#		Networks and Distributed Computing
  148.21 +#		Computing & Communications
  148.22 +#		University of Washington
  148.23 +#		Administration Building, AG-44
  148.24 +#		Seattle, WA  98195
  148.25 +#		Internet: MRC@CAC.Washington.EDU
  148.26 +#
  148.27 +# Date:		5 November 1990
  148.28 +# Last Edited:	30 August 2006
  148.29 +
  148.30 +
  148.31 +ALERT=\\imapd.alert
  148.32 +USERALERT=alert.txt
  148.33 +SHUTDOWN=\\nologin
  148.34 +ANO=\\anonymous.newsgroups
  148.35 +NNTP=\\imapd.nntp
  148.36 +
  148.37 +
  148.38 +C = ..\c-client
  148.39 +CCLIENTLIB = $C\cclient.lib
  148.40 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
  148.41 +OSCOMPAT = /DWIN32
  148.42 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  148.43 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
  148.44 +
  148.45 +imapd: $(CCLIENTLIB) imapd.obj
  148.46 +	LINK /NOLOGO imapd.obj $(LIBS)
  148.47 +
  148.48 +imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
  148.49 +
  148.50 +$(CCLIENTLIB):
  148.51 +	@echo Make c-client first
  148.52 +	false
  148.53 +
  148.54 +clean:
  148.55 +	del *.obj *.exe *.lib *.exp || rem
  148.56 +
  148.57 +# A monument to a hack of long ago and far away...
  148.58 +love:
  148.59 +	@echo not war?
   149.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   149.2 +++ b/src/ipopd/Makefile	Mon Sep 14 15:17:45 2009 +0900
   149.3 @@ -0,0 +1,58 @@
   149.4 +# ========================================================================
   149.5 +# Copyright 1988-2006 University of Washington
   149.6 +#
   149.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   149.8 +# you may not use this file except in compliance with the License.
   149.9 +# You may obtain a copy of the License at
  149.10 +#
  149.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  149.12 +#
  149.13 +# 
  149.14 +# ========================================================================
  149.15 +
  149.16 +
  149.17 +# Program:	IPOPD client Makefile
  149.18 +#
  149.19 +# Author:	Mark Crispin
  149.20 +#		Networks and Distributed Computing
  149.21 +#		Computing & Communications
  149.22 +#		University of Washington
  149.23 +#		Administration Building, AG-44
  149.24 +#		Seattle, WA  98195
  149.25 +#		Internet: MRC@CAC.Washington.EDU
  149.26 +#
  149.27 +# Date:		28 October 1990
  149.28 +# Last Edited:	30 August 2006
  149.29 +
  149.30 +
  149.31 +C = ../c-client
  149.32 +CCLIENTLIB = $C/c-client.a
  149.33 +SHELL = /bin/sh
  149.34 +
  149.35 +# Get local definitions from c-client directory
  149.36 +
  149.37 +CC = `cat $C/CCTYPE`
  149.38 +CFLAGS = -I$C `cat $C/CFLAGS`
  149.39 +LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
  149.40 +
  149.41 +ipopd: ipop2d ipop3d
  149.42 +
  149.43 +ipop2d: $(CCLIENTLIB) ipop2d.o
  149.44 +	$(CC) $(CFLAGS) -o ipop2d ipop2d.o $(LDFLAGS)
  149.45 +
  149.46 +ipop3d: $(CCLIENTLIB) ipop3d.o
  149.47 +	$(CC) $(CFLAGS) -o ipop3d ipop3d.o $(LDFLAGS)
  149.48 +
  149.49 +ipop2d.o: $C/mail.h $C/misc.h $C/osdep.h
  149.50 +
  149.51 +ipop3d.o: $C/mail.h $C/misc.h $C/osdep.h
  149.52 +
  149.53 +$(CCLIENTLIB):
  149.54 +	cd $C;make
  149.55 +
  149.56 +clean:
  149.57 +	rm -f *.o ipop2d ipop3d || true
  149.58 +
  149.59 +# A monument to a hack of long ago and far away...
  149.60 +love:
  149.61 +	@echo 'not war?'
   150.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   150.2 +++ b/src/ipopd/ipop2d.c	Mon Sep 14 15:17:45 2009 +0900
   150.3 @@ -0,0 +1,711 @@
   150.4 +/* ========================================================================
   150.5 + * Copyright 1988-2008 University of Washington
   150.6 + *
   150.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   150.8 + * you may not use this file except in compliance with the License.
   150.9 + * You may obtain a copy of the License at
  150.10 + *
  150.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  150.12 + *
  150.13 + * 
  150.14 + * ========================================================================
  150.15 + */
  150.16 +
  150.17 +/*
  150.18 + * Program:	IPOP2D - IMAP to POP2 conversion server
  150.19 + *
  150.20 + * Author:	Mark Crispin
  150.21 + *		UW Technology
  150.22 + *		University of Washington
  150.23 + *		Seattle, WA  98195
  150.24 + *		Internet: MRC@Washington.EDU
  150.25 + *
  150.26 + * Date:	28 October 1990
  150.27 + * Last Edited:	13 February 2008
  150.28 + */
  150.29 +
  150.30 +
  150.31 +/* Parameter files */
  150.32 +
  150.33 +#include <stdio.h>
  150.34 +#include <ctype.h>
  150.35 +#include <errno.h>
  150.36 +extern int errno;		/* just in case */
  150.37 +#include <signal.h>
  150.38 +#include <time.h>
  150.39 +#include "c-client.h"
  150.40 +
  150.41 +
  150.42 +/* Autologout timer */
  150.43 +#define KODTIMEOUT 60*5
  150.44 +#define LOGINTIMEOUT 60*3
  150.45 +#define TIMEOUT 60*30
  150.46 +
  150.47 +
  150.48 +/* Size of temporary buffers */
  150.49 +#define TMPLEN 1024
  150.50 +
  150.51 +
  150.52 +/* Server states */
  150.53 +
  150.54 +#define LISN 0
  150.55 +#define AUTH 1
  150.56 +#define MBOX 2
  150.57 +#define ITEM 3
  150.58 +#define NEXT 4
  150.59 +#define DONE 5
  150.60 +
  150.61 +/* Global storage */
  150.62 +
  150.63 +char *version = "75";		/* edit number of this server */
  150.64 +short state = LISN;		/* server state */
  150.65 +short critical = NIL;		/* non-zero if in critical code */
  150.66 +MAILSTREAM *stream = NIL;	/* mailbox stream */
  150.67 +time_t idletime = 0;		/* time we went idle */
  150.68 +unsigned long nmsgs = 0;	/* number of messages */
  150.69 +unsigned long current = 1;	/* current message number */
  150.70 +unsigned long size = 0;		/* size of current message */
  150.71 +char status[MAILTMPLEN];	/* space for status string */
  150.72 +char *user = "";		/* user name */
  150.73 +char *pass = "";		/* password */
  150.74 +unsigned long *msg = NIL;	/* message translation vector */
  150.75 +char *logout = "Logout";
  150.76 +char *goodbye = "+ Sayonara\015\012";
  150.77 +
  150.78 +
  150.79 +/* Function prototypes */
  150.80 +
  150.81 +int main (int argc,char *argv[]);
  150.82 +void sayonara (int status);
  150.83 +void clkint ();
  150.84 +void kodint ();
  150.85 +void hupint ();
  150.86 +void trmint ();
  150.87 +short c_helo (char *t,int argc,char *argv[]);
  150.88 +short c_fold (char *t);
  150.89 +short c_read (char *t);
  150.90 +short c_retr (char *t);
  150.91 +short c_acks (char *t);
  150.92 +short c_ackd (char *t);
  150.93 +short c_nack (char *t);
  150.94 +
  150.95 +/* Main program */
  150.96 +
  150.97 +int main (int argc,char *argv[])
  150.98 +{
  150.99 +  char *s,*t;
 150.100 +  char cmdbuf[TMPLEN];
 150.101 +  char *pgmname = (argc && argv[0]) ?
 150.102 +    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
 150.103 +     s+1 : argv[0]) : "ipop2d";
 150.104 +				/* set service name before linkage */
 150.105 +  mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
 150.106 +#include "linkage.c"
 150.107 +  if (mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) {
 150.108 +    goodbye = "- POP2 server disabled on this system\015\012";
 150.109 +    sayonara (1);
 150.110 +  }
 150.111 +				/* initialize server */
 150.112 +  server_init (pgmname,"pop",NIL,clkint,kodint,hupint,trmint,NIL);
 150.113 +  /* There are reports of POP2 clients which get upset if anything appears
 150.114 +   * between the "+" and the "POP2" in the greeting.
 150.115 +   */
 150.116 +  printf ("+ POP2 %s %s.%s server ready\015\012",tcp_serverhost (),
 150.117 +	  CCLIENTVERSION,version);
 150.118 +  fflush (stdout);		/* dump output buffer */
 150.119 +  state = AUTH;			/* initial server state */
 150.120 +  while (state != DONE) {	/* command processing loop */
 150.121 +    idletime = time (0);	/* get a command under timeout */
 150.122 +    alarm ((state != AUTH) ? TIMEOUT : LOGINTIMEOUT);
 150.123 +    clearerr (stdin);		/* clear stdin errors */
 150.124 +    while (!fgets (cmdbuf,TMPLEN-1,stdin)) {
 150.125 +      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
 150.126 +      else {
 150.127 +	char *e = ferror (stdin) ?
 150.128 +	  strerror (errno) : "Unexpected client disconnect";
 150.129 +	alarm (0);		/* disable all interrupts */
 150.130 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.131 +	sprintf (logout = cmdbuf,"%.80s while reading line",e);
 150.132 +	state = DONE;
 150.133 +	stream = mail_close (stream);
 150.134 +	goodbye = NIL;
 150.135 +	sayonara (1);
 150.136 +      }
 150.137 +    }
 150.138 +    alarm (0);			/* make sure timeout disabled */
 150.139 +    idletime = 0;		/* no longer idle */
 150.140 +				/* find end of line */
 150.141 +    if (!strchr (cmdbuf,'\012')) {
 150.142 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.143 +      logout = "- Command line too long\015\012";
 150.144 +      state = DONE;
 150.145 +    }
 150.146 +    else if (!(s = strtok (cmdbuf," \015\012"))) {
 150.147 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.148 +      goodbye = "- Missing or null command\015\012";
 150.149 +      state = DONE;
 150.150 +    }
 150.151 +    else {			/* dispatch based on command */
 150.152 +      ucase (s);		/* canonicalize case */
 150.153 +				/* snarf argument */
 150.154 +      t = strtok (NIL,"\015\012");
 150.155 +      if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv);
 150.156 +      else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD"))
 150.157 + 	state = c_fold (t);
 150.158 +      else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ"))
 150.159 +	state = c_read (t);
 150.160 +      else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t);
 150.161 +      else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t);
 150.162 +      else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t);
 150.163 +      else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t);
 150.164 +      else if ((state == AUTH || state == MBOX || state == ITEM) &&
 150.165 +	       !strcmp (s,"QUIT")) {
 150.166 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.167 +	state = DONE;		/* done in either case */
 150.168 +	if (t) goodbye = "- Bogus argument given to QUIT\015\012";
 150.169 +	else {			/* expunge the stream */
 150.170 +	  if (stream && nmsgs) stream = mail_close_full (stream,CL_EXPUNGE);
 150.171 +	  stream = NIL;		/* don't repeat it */
 150.172 +	}
 150.173 +      }
 150.174 +      else {			/* some other or inappropriate command */
 150.175 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.176 +	goodbye = "- Bogus or out of sequence command\015\012";
 150.177 +	state = DONE;
 150.178 +      }
 150.179 +    }
 150.180 +    fflush (stdout);		/* make sure output blatted */
 150.181 +  }
 150.182 +				/* clean up the stream */
 150.183 +  if (stream) mail_close (stream);
 150.184 +  sayonara (0);
 150.185 +  return 0;			/* stupid compilers */
 150.186 +}
 150.187 +
 150.188 +
 150.189 +/* Say goodbye
 150.190 + * Accepts: exit status
 150.191 + *
 150.192 + * Does not return
 150.193 + */
 150.194 +
 150.195 +void sayonara (int status)
 150.196 +{
 150.197 +  logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
 150.198 +  if (goodbye) {		/* have a goodbye message? */
 150.199 +    fputs (goodbye,stdout);
 150.200 +    fflush (stdout);		/* make sure blatted */
 150.201 +  }
 150.202 +  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
 150.203 +	  user ? (char *) user : "???",tcp_clienthost ());
 150.204 +				/* do logout hook if needed */
 150.205 +  if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
 150.206 +  _exit (status);		/* all done */
 150.207 +}
 150.208 +
 150.209 +/* Clock interrupt
 150.210 + */
 150.211 +
 150.212 +void clkint ()
 150.213 +{
 150.214 +  alarm (0);		/* disable all interrupts */
 150.215 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.216 +  goodbye = "- Autologout; idle for too long\015\012";
 150.217 +  logout = "Autologout";
 150.218 +  state = DONE;			/* mark state done in either case */
 150.219 +  if (!critical) {		/* badly host if in critical code */
 150.220 +    if (stream && !stream->lock) mail_close (stream);
 150.221 +    stream = NIL;
 150.222 +    sayonara (1);		/* die die die */
 150.223 +  }
 150.224 +}
 150.225 +
 150.226 +
 150.227 +/* Kiss Of Death interrupt
 150.228 + */
 150.229 +
 150.230 +void kodint ()
 150.231 +{
 150.232 +				/* only if in command wait */
 150.233 +  if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
 150.234 +    alarm (0);		/* disable all interrupts */
 150.235 +    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.236 +    goodbye = "- Killed (lost mailbox lock)\015\012";
 150.237 +    logout = "Killed (lost mailbox lock)";
 150.238 +    state = DONE;		/* mark state done in either case */
 150.239 +    if (!critical) {		/* badly host if in critical code */
 150.240 +      if (stream && !stream->lock) mail_close (stream);
 150.241 +      stream = NIL;
 150.242 +      sayonara (1);		/* die die die */
 150.243 +    }
 150.244 +  }
 150.245 +}
 150.246 +
 150.247 +
 150.248 +/* Hangup interrupt
 150.249 + */
 150.250 +
 150.251 +void hupint ()
 150.252 +{
 150.253 +  alarm (0);		/* disable all interrupts */
 150.254 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.255 +  goodbye = NIL;
 150.256 +  logout = "Hangup";
 150.257 +  state = DONE;			/* mark state done in either case */
 150.258 +  if (!critical) {		/* badly host if in critical code */
 150.259 +    if (stream && !stream->lock) mail_close (stream);
 150.260 +    stream = NIL;
 150.261 +    sayonara (1);		/* die die die */
 150.262 +  }
 150.263 +}
 150.264 +
 150.265 +
 150.266 +/* Termination interrupt
 150.267 + */
 150.268 +
 150.269 +void trmint ()
 150.270 +{
 150.271 +  alarm (0);		/* disable all interrupts */
 150.272 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.273 +  goodbye = "- Killed (terminated)\015\012";
 150.274 +  logout = "Killed (terminated)";
 150.275 +  if (critical) state = DONE;	/* mark state done in either case */
 150.276 +  /* Make no attempt at graceful closure since a shutdown may be in
 150.277 +   * progress, and we won't have any time to do mail_close() actions.
 150.278 +   */
 150.279 +  else sayonara (1);		/* die die die */
 150.280 +}
 150.281 +
 150.282 +/* Parse HELO command
 150.283 + * Accepts: pointer to command argument
 150.284 + * Returns: new state
 150.285 + */
 150.286 +
 150.287 +short c_helo (char *t,int argc,char *argv[])
 150.288 +{
 150.289 +  char *s,*u,*p;
 150.290 +  char tmp[TMPLEN];
 150.291 +  if ((!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) ||
 150.292 +      (strlen (p) >= TMPLEN)) {	/* get user name and password */
 150.293 +    fputs ("- Missing user or password\015\012",stdout);
 150.294 +    return DONE;
 150.295 +  }
 150.296 +				/* copy password, handle quoting */
 150.297 +  for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p;
 150.298 +  *s = '\0';			/* tie off string */
 150.299 +  pass = cpystr (tmp);
 150.300 +  if (!(s = strchr (u,':'))) {	/* want remote mailbox? */
 150.301 +				/* no, delimit user from possible admin */
 150.302 +    if (s = strchr (u,'*')) *s++ = '\0';
 150.303 +    if (server_login (user = cpystr (u),pass,s,argc,argv)) {
 150.304 +      syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s",s ? "Admin " : "",
 150.305 +	      user,tcp_clienthost ());
 150.306 +      return c_fold ("INBOX");	/* local; select INBOX */
 150.307 +    }
 150.308 +  }
 150.309 +#ifndef DISABLE_POP_PROXY
 150.310 +				/* can't do if can't log in as anonymous */
 150.311 +  else if (anonymous_login (argc,argv)) {
 150.312 +    *s++ = '\0';		/* separate host name from user name */
 150.313 +    user = cpystr (s);		/* note user name */
 150.314 +    syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",u,user,
 150.315 +	    tcp_clienthost ());
 150.316 +				/* initially remote INBOX */
 150.317 +    sprintf (tmp,"{%.128s/user=%.128s}INBOX",u,user);
 150.318 +				/* disable rimap just in case */
 150.319 +    mail_parameters (NIL,SET_RSHTIMEOUT,0);
 150.320 +    return c_fold (tmp);
 150.321 +  }
 150.322 +#endif
 150.323 +  fputs ("- Bad login\015\012",stdout);
 150.324 +  return DONE;
 150.325 +}
 150.326 +
 150.327 +/* Parse FOLD command
 150.328 + * Accepts: pointer to command argument
 150.329 + * Returns: new state
 150.330 + */
 150.331 +
 150.332 +short c_fold (char *t)
 150.333 +{
 150.334 +  unsigned long i,j,flags;
 150.335 +  char *s = NIL,tmp[2*TMPLEN];
 150.336 +  NETMBX mb;
 150.337 +  if (!(t && *t)) {		/* make sure there's an argument */
 150.338 +    fputs ("- Missing mailbox name\015\012",stdout);
 150.339 +    return DONE;
 150.340 +  }
 150.341 +  myusername_full (&flags);	/* get user type flags */
 150.342 +				/* expunge old stream */
 150.343 +  if (stream && nmsgs) mail_expunge (stream);
 150.344 +  nmsgs = 0;			/* no more messages */
 150.345 +  if (msg) fs_give ((void **) &msg);
 150.346 +#ifndef DISABLE_POP_PROXY
 150.347 +  if (flags == MU_ANONYMOUS) {	/* don't permit proxy to leave IMAP */
 150.348 +    if (stream) {		/* not first time */
 150.349 +      if (!(stream->mailbox && (s = strchr (stream->mailbox,'}'))))
 150.350 +	fatal ("bad previous mailbox name");
 150.351 +      strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox));
 150.352 +      if (i >= TMPLEN) fatal ("ridiculous network prefix");
 150.353 +      strcpy (tmp+i,t);		/* append mailbox to initial spec */
 150.354 +      t = tmp;
 150.355 +    }
 150.356 +				/* must be net name first time */
 150.357 +    else if (!mail_valid_net_parse (t,&mb)) fatal ("anonymous folder bogon");
 150.358 +  }
 150.359 +#endif
 150.360 +				/* open mailbox, note # of messages */
 150.361 +  if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) {
 150.362 +    sprintf (tmp,"1:%lu",j);	/* fetch fast information for all messages */
 150.363 +    mail_fetch_fast (stream,tmp,NIL);
 150.364 +    msg = (unsigned long *) fs_get ((stream->nmsgs + 1) *
 150.365 +				    sizeof (unsigned long));
 150.366 +    for (i = 1; i <= j; i++)	/* find undeleted messages, add to vector */
 150.367 +      if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i;
 150.368 +  }
 150.369 +#ifndef DISABLE_POP_PROXY
 150.370 +  if (!stream && (flags == MU_ANONYMOUS)) {
 150.371 +    fputs ("- Bad login\015\012",stdout);
 150.372 +    return DONE;
 150.373 +  }
 150.374 +#endif
 150.375 +  printf ("#%lu messages in %s\015\012",nmsgs,stream ? stream->mailbox :
 150.376 +	  "<none>");
 150.377 +  return MBOX;
 150.378 +}
 150.379 +
 150.380 +/* Parse READ command
 150.381 + * Accepts: pointer to command argument
 150.382 + * Returns: new state
 150.383 + */
 150.384 +
 150.385 +short c_read (char *t)
 150.386 +{
 150.387 +  MESSAGECACHE *elt = NIL;
 150.388 +  if (t && *t) {		/* have a message number argument? */
 150.389 +				/* validity check message number */
 150.390 +    if (((current = strtoul (t,NIL,10)) < 1) || (current > nmsgs)) {
 150.391 +      fputs ("- Invalid message number given to READ\015\012",stdout);
 150.392 +      return DONE;
 150.393 +    }
 150.394 +  }
 150.395 +  else if (current > nmsgs) {	/* at end of mailbox? */
 150.396 +    fputs ("=0 No more messages\015\012",stdout);
 150.397 +    return MBOX;
 150.398 +  }
 150.399 +				/* set size if message valid and exists */
 150.400 +  size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0;
 150.401 +  if (elt) sprintf (status,"Status: %s%s\015\012",
 150.402 +		    elt->seen ? "R" : " ",elt->recent ? " " : "O");
 150.403 +  else status[0] = '\0';	/* no status */
 150.404 +  size += strlen (status);	/* update size to reflect status */
 150.405 +				/* display results */
 150.406 +  printf ("=%lu characters in message %lu\015\012",size + 2,current);
 150.407 +  return ITEM;
 150.408 +}
 150.409 +
 150.410 +
 150.411 +/* Parse RETR command
 150.412 + * Accepts: pointer to command argument
 150.413 + * Returns: new state
 150.414 + */
 150.415 +
 150.416 +short c_retr (char *t)
 150.417 +{
 150.418 +  unsigned long i,j;
 150.419 +  STRING *bs;
 150.420 +  if (t) {			/* disallow argument */
 150.421 +    fputs ("- Bogus argument given to RETR\015\012",stdout);
 150.422 +    return DONE;
 150.423 +  }
 150.424 +  if (size) {			/* message size valid? */
 150.425 +    t = mail_fetch_header (stream,msg[current],NIL,NIL,&i,FT_PEEK);
 150.426 +    if (i > 2) {		/* only if there is something */
 150.427 +      i -= 2;			/* lop off last two octets */
 150.428 +      while (i) {		/* blat the header */
 150.429 +	if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
 150.430 +	if (i -= j) t += j;	/* advance to incomplete data */
 150.431 +      }
 150.432 +    }
 150.433 +    fputs (status,stdout);	/* yes, output message */
 150.434 +    fputs ("\015\012",stdout);	/* delimit header from text */
 150.435 +    if (t = mail_fetch_text (stream,msg[current],NIL,&i,FT_RETURNSTRINGSTRUCT))
 150.436 +      while (i) {		/* blat the text */
 150.437 +	if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
 150.438 +	if (i -= j) t += j;	/* advance to incomplete data */
 150.439 +      }
 150.440 +    else for (bs = &stream->private.string; i--; )
 150.441 +      if (putc (SNX (bs),stdout) == EOF) return DONE;
 150.442 +    fputs ("\015\012",stdout);	/* trailer to coddle PCNFS' NFSMAIL */
 150.443 +  }
 150.444 +  else return DONE;		/* otherwise go away */
 150.445 +  return NEXT;
 150.446 +}
 150.447 +
 150.448 +/* Parse ACKS command
 150.449 + * Accepts: pointer to command argument
 150.450 + * Returns: new state
 150.451 + */
 150.452 +
 150.453 +short c_acks (char *t)
 150.454 +{
 150.455 +  char tmp[TMPLEN];
 150.456 +  if (t) {			/* disallow argument */
 150.457 +    fputs ("- Bogus argument given to ACKS\015\012",stdout);
 150.458 +    return DONE;
 150.459 +  }
 150.460 +				/* mark message as seen */
 150.461 +  sprintf (tmp,"%lu",msg[current++]);
 150.462 +  mail_setflag (stream,tmp,"\\Seen");
 150.463 +  return c_read (NIL);		/* end message reading transaction */
 150.464 +}
 150.465 +
 150.466 +
 150.467 +/* Parse ACKD command
 150.468 + * Accepts: pointer to command argument
 150.469 + * Returns: new state
 150.470 + */
 150.471 +
 150.472 +short c_ackd (char *t)
 150.473 +{
 150.474 +  char tmp[TMPLEN];
 150.475 +  if (t) {			/* disallow argument */
 150.476 +    fputs ("- Bogus argument given to ACKD\015\012",stdout);
 150.477 +    return DONE;
 150.478 +  }
 150.479 +				/* mark message as seen and deleted */
 150.480 +  sprintf (tmp,"%lu",msg[current]);
 150.481 +  mail_setflag (stream,tmp,"\\Seen \\Deleted");
 150.482 +  msg[current++] = 0;		/* mark message as deleted */
 150.483 +  return c_read (NIL);		/* end message reading transaction */
 150.484 +}
 150.485 +
 150.486 +
 150.487 +/* Parse NACK command
 150.488 + * Accepts: pointer to command argument
 150.489 + * Returns: new state
 150.490 + */
 150.491 +
 150.492 +short c_nack (char *t)
 150.493 +{
 150.494 +  if (t) {			/* disallow argument */
 150.495 +    fputs ("- Bogus argument given to NACK\015\012",stdout);
 150.496 +    return DONE;
 150.497 +  }
 150.498 +  return c_read (NIL);		/* end message reading transaction */
 150.499 +}
 150.500 +
 150.501 +/* Co-routines from MAIL library */
 150.502 +
 150.503 +
 150.504 +/* Message matches a search
 150.505 + * Accepts: MAIL stream
 150.506 + *	    message number
 150.507 + */
 150.508 +
 150.509 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
 150.510 +{
 150.511 +  /* Never called */
 150.512 +}
 150.513 +
 150.514 +
 150.515 +/* Message exists (i.e. there are that many messages in the mailbox)
 150.516 + * Accepts: MAIL stream
 150.517 + *	    message number
 150.518 + */
 150.519 +
 150.520 +void mm_exists (MAILSTREAM *stream,unsigned long number)
 150.521 +{
 150.522 +  /* Can't use this mechanism.  POP has no means of notifying the client of
 150.523 +     new mail during the session. */
 150.524 +}
 150.525 +
 150.526 +
 150.527 +/* Message expunged
 150.528 + * Accepts: MAIL stream
 150.529 + *	    message number
 150.530 + */
 150.531 +
 150.532 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
 150.533 +{
 150.534 +  if (state != DONE) {		/* ignore if closing */
 150.535 +				/* someone else screwed us */
 150.536 +    goodbye = "- Mailbox expunged from under me!\015\012";
 150.537 +    if (stream && !stream->lock) mail_close (stream);
 150.538 +    stream = NIL;
 150.539 +    sayonara (1);
 150.540 +  }
 150.541 +}
 150.542 +
 150.543 +
 150.544 +/* Message status changed
 150.545 + * Accepts: MAIL stream
 150.546 + *	    message number
 150.547 + */
 150.548 +
 150.549 +void mm_flags (MAILSTREAM *stream,unsigned long number)
 150.550 +{
 150.551 +  /* This isn't used */
 150.552 +}
 150.553 +
 150.554 +
 150.555 +/* Mailbox found
 150.556 + * Accepts: MAIL stream
 150.557 + *	    hierarchy delimiter
 150.558 + *	    mailbox name
 150.559 + *	    mailbox attributes
 150.560 + */
 150.561 +
 150.562 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 150.563 +{
 150.564 +  /* This isn't used */
 150.565 +}
 150.566 +
 150.567 +
 150.568 +/* Subscribe mailbox found
 150.569 + * Accepts: MAIL stream
 150.570 + *	    hierarchy delimiter
 150.571 + *	    mailbox name
 150.572 + *	    mailbox attributes
 150.573 + */
 150.574 +
 150.575 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 150.576 +{
 150.577 +  /* This isn't used */
 150.578 +}
 150.579 +
 150.580 +
 150.581 +/* Mailbox status
 150.582 + * Accepts: MAIL stream
 150.583 + *	    mailbox name
 150.584 + *	    mailbox status
 150.585 + */
 150.586 +
 150.587 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 150.588 +{
 150.589 +  /* This isn't used */
 150.590 +}
 150.591 +
 150.592 +/* Notification event
 150.593 + * Accepts: MAIL stream
 150.594 + *	    string to log
 150.595 + *	    error flag
 150.596 + */
 150.597 +
 150.598 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
 150.599 +{
 150.600 +  mm_log (string,errflg);	/* just do mm_log action */
 150.601 +}
 150.602 +
 150.603 +
 150.604 +/* Log an event for the user to see
 150.605 + * Accepts: string to log
 150.606 + *	    error flag
 150.607 + */
 150.608 +
 150.609 +void mm_log (char *string,long errflg)
 150.610 +{
 150.611 +  switch (errflg) {
 150.612 +  case NIL:			/* information message */
 150.613 +  case PARSE:			/* parse glitch */
 150.614 +    break;			/* too many of these to log */
 150.615 +  case WARN:			/* warning */
 150.616 +    syslog (LOG_DEBUG,"%s",string);
 150.617 +    break;
 150.618 +  case BYE:			/* driver broke connection */
 150.619 +    if (state != DONE) {
 150.620 +      char tmp[MAILTMPLEN];
 150.621 +      alarm (0);		/* disable all interrupts */
 150.622 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 150.623 +      sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
 150.624 +      sayonara (1);
 150.625 +    }
 150.626 +    break;
 150.627 +  case ERROR:			/* error that broke command */
 150.628 +  default:			/* default should never happen */
 150.629 +    syslog (LOG_NOTICE,"%s",string);
 150.630 +    break;
 150.631 +  }
 150.632 +}
 150.633 +
 150.634 +
 150.635 +/* Log an event to debugging telemetry
 150.636 + * Accepts: string to log
 150.637 + */
 150.638 +
 150.639 +void mm_dlog (char *string)
 150.640 +{
 150.641 +  /* Not doing anything here for now */
 150.642 +}
 150.643 +
 150.644 +
 150.645 +/* Get user name and password for this host
 150.646 + * Accepts: parse of network mailbox name
 150.647 + *	    where to return user name
 150.648 + *	    where to return password
 150.649 + *	    trial count
 150.650 + */
 150.651 +
 150.652 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
 150.653 +{
 150.654 +				/* set user name */
 150.655 +  strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
 150.656 +  strncpy (password,pass,255);	/* and password */
 150.657 +  username[NETMAXUSER] = password[255] = '\0';
 150.658 +}
 150.659 +
 150.660 +/* About to enter critical code
 150.661 + * Accepts: stream
 150.662 + */
 150.663 +
 150.664 +void mm_critical (MAILSTREAM *stream)
 150.665 +{
 150.666 +  ++critical;
 150.667 +}
 150.668 +
 150.669 +
 150.670 +/* About to exit critical code
 150.671 + * Accepts: stream
 150.672 + */
 150.673 +
 150.674 +void mm_nocritical (MAILSTREAM *stream)
 150.675 +{
 150.676 +  --critical;
 150.677 +}
 150.678 +
 150.679 +
 150.680 +/* Disk error found
 150.681 + * Accepts: stream
 150.682 + *	    system error code
 150.683 + *	    flag indicating that mailbox may be clobbered
 150.684 + * Returns: abort flag
 150.685 + */
 150.686 +
 150.687 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
 150.688 +{
 150.689 +  if (serious) {		/* try your damnest if clobberage likely */
 150.690 +    syslog (LOG_ALERT,
 150.691 +	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
 150.692 +	    user,tcp_clienthost (),
 150.693 +	    (stream && stream->mailbox) ? stream->mailbox : "???",
 150.694 +	    strerror (errcode));
 150.695 +    alarm (0);			/* make damn sure timeout disabled */
 150.696 +    sleep (60);			/* give it some time to clear up */
 150.697 +    return NIL;
 150.698 +  }
 150.699 +  syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
 150.700 +	  user,tcp_clienthost (),
 150.701 +	  (stream && stream->mailbox) ? stream->mailbox : "???",
 150.702 +	  strerror (errcode));
 150.703 +  return T;
 150.704 +}
 150.705 +
 150.706 +
 150.707 +/* Log a fatal error event
 150.708 + * Accepts: string to log
 150.709 + */
 150.710 +
 150.711 +void mm_fatal (char *string)
 150.712 +{
 150.713 +  mm_log (string,ERROR);	/* shouldn't happen normally */
 150.714 +}
   151.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   151.2 +++ b/src/ipopd/ipop3d.c	Mon Sep 14 15:17:45 2009 +0900
   151.3 @@ -0,0 +1,1082 @@
   151.4 +/* ========================================================================
   151.5 + * Copyright 1988-2008 University of Washington
   151.6 + *
   151.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   151.8 + * you may not use this file except in compliance with the License.
   151.9 + * You may obtain a copy of the License at
  151.10 + *
  151.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  151.12 + *
  151.13 + * 
  151.14 + * ========================================================================
  151.15 + */
  151.16 +
  151.17 +/*
  151.18 + * Program:	IPOP3D - IMAP to POP3 conversion server
  151.19 + *
  151.20 + * Author:	Mark Crispin
  151.21 + *		UW Technology
  151.22 + *		University of Washington
  151.23 + *		Seattle, WA  98195
  151.24 + *		Internet: MRC@Washington.EDU
  151.25 + *
  151.26 + * Date:	1 November 1990
  151.27 + * Last Edited:	19 February 2008
  151.28 + */
  151.29 +
  151.30 +/* Parameter files */
  151.31 +
  151.32 +#include <stdio.h>
  151.33 +#include <ctype.h>
  151.34 +#include <errno.h>
  151.35 +extern int errno;		/* just in case */
  151.36 +#include <signal.h>
  151.37 +#include <time.h>
  151.38 +#include "c-client.h"
  151.39 +
  151.40 +
  151.41 +#define CRLF PSOUT ("\015\012")	/* primary output terpri */
  151.42 +
  151.43 +
  151.44 +/* Autologout timer */
  151.45 +#define KODTIMEOUT 60*5
  151.46 +#define LOGINTIMEOUT 60*3
  151.47 +#define TIMEOUT 60*10
  151.48 +
  151.49 +
  151.50 +/* Server states */
  151.51 +
  151.52 +#define AUTHORIZATION 0
  151.53 +#define TRANSACTION 1
  151.54 +#define UPDATE 2
  151.55 +#define LOGOUT 3
  151.56 +
  151.57 +/* Eudora food */
  151.58 +
  151.59 +#define STATUS "Status: %s%s\015\012"
  151.60 +#define SLEN (sizeof (STATUS)-3)
  151.61 +
  151.62 +
  151.63 +/* Global storage */
  151.64 +
  151.65 +char *version = "104";		/* edit number of this server */
  151.66 +short state = AUTHORIZATION;	/* server state */
  151.67 +short critical = NIL;		/* non-zero if in critical code */
  151.68 +MAILSTREAM *stream = NIL;	/* mailbox stream */
  151.69 +time_t idletime = 0;		/* time we went idle */
  151.70 +unsigned long nmsgs = 0;	/* current number of messages */
  151.71 +unsigned long ndele = 0;	/* number of deletes */
  151.72 +unsigned long nseen = 0;	/* number of mark-seens */
  151.73 +unsigned long last = 0;		/* highest message accessed */
  151.74 +unsigned long il = 0;		/* initial last message */
  151.75 +char challenge[128];		/* challenge */
  151.76 +char *host = NIL;		/* remote host name */
  151.77 +char *user = NIL;		/* user name */
  151.78 +char *pass = NIL;		/* password */
  151.79 +char *initial = NIL;		/* initial response */
  151.80 +long *msg = NIL;		/* message translation vector */
  151.81 +short *flags = NIL;		/* flags */
  151.82 +char *logout = "Logout";
  151.83 +char *goodbye = "+OK Sayonara\015\012";
  151.84 +
  151.85 +
  151.86 +/* POP3 flags */
  151.87 +
  151.88 +#define DELE 0x1
  151.89 +#define SEEN 0x2
  151.90 +
  151.91 +
  151.92 +/* Function prototypes */
  151.93 +
  151.94 +int main (int argc,char *argv[]);
  151.95 +void sayonara (int status);
  151.96 +void clkint ();
  151.97 +void kodint ();
  151.98 +void hupint ();
  151.99 +void trmint ();
 151.100 +int pass_login (char *t,int argc,char *argv[]);
 151.101 +char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
 151.102 +char *responder (void *challenge,unsigned long clen,unsigned long *rlen);
 151.103 +int mbxopen (char *mailbox);
 151.104 +long blat (char *text,long lines,unsigned long size,STRING *st);
 151.105 +void rset ();
 151.106 +
 151.107 +/* Main program */
 151.108 +
 151.109 +int main (int argc,char *argv[])
 151.110 +{
 151.111 +  unsigned long i,j,k;
 151.112 +  char *s,*t;
 151.113 +  char tmp[MAILTMPLEN];
 151.114 +  time_t autologouttime;
 151.115 +  char *pgmname = (argc && argv[0]) ?
 151.116 +    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
 151.117 +     s+1 : argv[0]) : "ipop3d";
 151.118 +				/* set service name before linkage */
 151.119 +  mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
 151.120 +#include "linkage.c"
 151.121 +				/* initialize server */
 151.122 +  server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint,NIL);
 151.123 +  mail_parameters (NIL,SET_BLOCKENVINIT,VOIDT);
 151.124 +  s = myusername_full (&i);	/* get user name and flags */
 151.125 +  mail_parameters (NIL,SET_BLOCKENVINIT,NIL);
 151.126 +  if (i == MU_LOGGEDIN) {	/* allow EXTERNAL if logged in already */
 151.127 +    mail_parameters (NIL,UNHIDE_AUTHENTICATOR,(void *) "EXTERNAL");
 151.128 +    mail_parameters (NIL,SET_EXTERNALAUTHID,(void *) s);
 151.129 +  }
 151.130 +  {				/* set up MD5 challenge */
 151.131 +    AUTHENTICATOR *auth = mail_lookup_auth (1);
 151.132 +    while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->next;
 151.133 +				/* build challenge -- less than 128 chars */
 151.134 +    if (auth && auth->server && !(auth->flags & AU_DISABLE))
 151.135 +      sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (),
 151.136 +	       (unsigned long) time (0),tcp_serverhost ());
 151.137 +    else challenge[0] = '\0';	/* no MD5 authentication */
 151.138 +  }
 151.139 +  /* There are reports of POP3 clients which get upset if anything appears
 151.140 +   * between the "+OK" and the "POP3" in the greeting.
 151.141 +   */
 151.142 +  PSOUT ("+OK POP3 ");
 151.143 +  if (!challenge[0]) {		/* if no MD5 enable, output host name */
 151.144 +    PSOUT (tcp_serverhost ());
 151.145 +    PBOUT (' ');
 151.146 +  }
 151.147 +  PSOUT (CCLIENTVERSION);
 151.148 +  PBOUT ('.');
 151.149 +  PSOUT (version);
 151.150 +  PSOUT (" server ready");
 151.151 +  if (challenge[0]) {		/* if MD5 enable, output challenge here */
 151.152 +    PBOUT (' ');
 151.153 +    PSOUT (challenge);
 151.154 +  }
 151.155 +  CRLF;
 151.156 +  PFLUSH ();			/* dump output buffer */
 151.157 +  autologouttime = time (0) + LOGINTIMEOUT;
 151.158 +				/* command processing loop */
 151.159 +  while ((state != UPDATE) && (state != LOGOUT)) {
 151.160 +    idletime = time (0);	/* get a command under timeout */
 151.161 +    alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT);
 151.162 +    clearerr (stdin);		/* clear stdin errors */
 151.163 +				/* read command line */
 151.164 +    while (!PSIN (tmp,MAILTMPLEN)) {
 151.165 +				/* ignore if some interrupt */
 151.166 +      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
 151.167 +      else {
 151.168 +	char *e = ferror (stdin) ?
 151.169 +	  strerror (errno) : "Unexpected client disconnect";
 151.170 +	alarm (0);		/* disable all interrupts */
 151.171 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.172 +	sprintf (logout = tmp,"%.80s, while reading line",e);
 151.173 +	goodbye = NIL;
 151.174 +	rset ();		/* try to gracefully close the stream */
 151.175 +	if (state == TRANSACTION) mail_close (stream);
 151.176 +	stream = NIL;
 151.177 +	state = LOGOUT;
 151.178 +	sayonara (1);
 151.179 +      }
 151.180 +    }
 151.181 +    alarm (0);			/* make sure timeout disabled */
 151.182 +    idletime = 0;		/* no longer idle */
 151.183 +
 151.184 +    if (!strchr (tmp,'\012'))	/* find end of line */
 151.185 +      PSOUT ("-ERR Command line too long\015\012");
 151.186 +    else if (!(s = strtok (tmp," \015\012")))
 151.187 +      PSOUT ("-ERR Null command\015\012");
 151.188 +    else {			/* dispatch based on command */
 151.189 +      ucase (s);		/* canonicalize case */
 151.190 +				/* snarf argument */
 151.191 +      t = strtok (NIL,"\015\012");
 151.192 +				/* QUIT command always valid */
 151.193 +      if (!strcmp (s,"QUIT")) state = UPDATE;
 151.194 +      else if (!strcmp (s,"CAPA")) {
 151.195 +	AUTHENTICATOR *auth;
 151.196 +	PSOUT ("+OK Capability list follows:\015\012");
 151.197 +	PSOUT ("TOP\015\012LOGIN-DELAY 180\015\012UIDL\015\012");
 151.198 +	if (s = ssl_start_tls (NIL)) fs_give ((void **) &s);
 151.199 +	else PSOUT ("STLS\015\012");
 151.200 +	if (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))
 151.201 +	  PSOUT ("USER\015\012");
 151.202 +				/* display secure server authenticators */
 151.203 +	for (auth = mail_lookup_auth (1), s = "SASL"; auth; auth = auth->next)
 151.204 +	  if (auth->server && !(auth->flags & AU_DISABLE) &&
 151.205 +	      !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
 151.206 +	    if (s) {
 151.207 +	      PSOUT (s);
 151.208 +	      s = NIL;
 151.209 +	    }
 151.210 +	    PBOUT (' ');
 151.211 +	    PSOUT (auth->name);
 151.212 +	  }
 151.213 +	PSOUT (s ? ".\015\012" : "\015\012.\015\012");
 151.214 +      }
 151.215 +
 151.216 +      else switch (state) {	/* else dispatch based on state */
 151.217 +      case AUTHORIZATION:	/* waiting to get logged in */
 151.218 +	if (!strcmp (s,"AUTH")) {
 151.219 +	  if (t && *t) {	/* mechanism given? */
 151.220 +	    if (host) fs_give ((void **) &host);
 151.221 +	    if (user) fs_give ((void **) &user);
 151.222 +	    if (pass) fs_give ((void **) &pass);
 151.223 +	    s = strtok (t," ");	/* get mechanism name */
 151.224 +				/* get initial response */
 151.225 +	    if (initial = strtok (NIL,"\015\012")) {
 151.226 +	      if ((*initial == '=') && !initial[1]) ++initial;
 151.227 +	      else if (!*initial) initial = NIL;
 151.228 +	    }
 151.229 +	    if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
 151.230 +	      PSOUT ("-ERR Bad authentication\015\012");
 151.231 +	      syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s,
 151.232 +		      tcp_clienthost ());
 151.233 +	    }
 151.234 +	    else if ((state = mbxopen ("INBOX")) == TRANSACTION)
 151.235 +	      syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu",
 151.236 +		      user,tcp_clienthost (),nmsgs,stream->nmsgs);
 151.237 +	    else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox",
 151.238 +			 user,tcp_clienthost ());
 151.239 +	  }
 151.240 +	  else {
 151.241 +	    AUTHENTICATOR *auth;
 151.242 +	    PSOUT ("+OK Supported authentication mechanisms:\015\012");
 151.243 +	    i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL);
 151.244 +	    for (auth = mail_lookup_auth (1); auth; auth = auth->next)
 151.245 +	      if (auth->server && !(auth->flags & AU_DISABLE) &&
 151.246 +		  !(auth->flags & AU_HIDE) &&
 151.247 +		  (i || (auth->flags & AU_SECURE))) {
 151.248 +		PSOUT (auth->name);
 151.249 +		CRLF;
 151.250 +	      }
 151.251 +	    PBOUT ('.');
 151.252 +	    CRLF;
 151.253 +	  }
 151.254 +	}
 151.255 +
 151.256 +	else if (!strcmp (s,"APOP")) {
 151.257 +	  if (challenge[0]) {	/* can do it if have an MD5 challenge */
 151.258 +	    if (host) fs_give ((void **) &host);
 151.259 +	    if (user) fs_give ((void **) &user);
 151.260 +	    if (pass) fs_give ((void **) &pass);
 151.261 +				/* get user name */
 151.262 +	    if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"\012"))))
 151.263 +	      PSOUT ("-ERR Missing APOP argument\015\012");
 151.264 +	    else if (!(user = apop_login (challenge,s,t,argc,argv)))
 151.265 +	      PSOUT ("-ERR Bad APOP\015\012");
 151.266 +	    else if ((state = mbxopen ("INBOX")) == TRANSACTION)
 151.267 +	      syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%lu/%lu",
 151.268 +		      user,tcp_clienthost (),nmsgs,stream->nmsgs);
 151.269 +	    else syslog (LOG_INFO,"APOP user=%.80s host=%.80s no mailbox",
 151.270 +			 user,tcp_clienthost ());
 151.271 +	  }
 151.272 +	  else PSOUT ("-ERR Not supported\015\012");
 151.273 +	}
 151.274 +				/* (chuckle) */
 151.275 +	else if (!strcmp (s,"RPOP"))
 151.276 +	  PSOUT ("-ERR Nice try, bunkie\015\012");
 151.277 +	else if (!strcmp (s,"STLS")) {
 151.278 +	  if (t = ssl_start_tls (pgmname)) {
 151.279 +	    PSOUT ("-ERR STLS failed: ");
 151.280 +	    PSOUT (t);
 151.281 +	    CRLF;
 151.282 +	  }
 151.283 +	  else PSOUT ("+OK STLS completed\015\012");
 151.284 +	}
 151.285 +	else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
 151.286 +		 !strcmp (s,"USER")) {
 151.287 +	  if (host) fs_give ((void **) &host);
 151.288 +	  if (user) fs_give ((void **) &user);
 151.289 +	  if (pass) fs_give ((void **) &pass);
 151.290 +	  if (t && *t) {	/* if user name given */
 151.291 +				/* skip leading whitespace (bogus clients!) */
 151.292 +	    while (*t == ' ') ++t;
 151.293 +				/* remote user name? */
 151.294 +	    if (s = strchr (t,':')) {
 151.295 +	      *s++ = '\0';	/* tie off host name */
 151.296 +	      host = cpystr (t);/* copy host name */
 151.297 +	      user = cpystr (s);/* copy user name */
 151.298 +	    }
 151.299 +				/* local user name */
 151.300 +	    else user = cpystr (t);
 151.301 +	    PSOUT ("+OK User name accepted, password please\015\012");
 151.302 +	  }
 151.303 +	  else PSOUT ("-ERR Missing username argument\015\012");
 151.304 +	}
 151.305 +	else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
 151.306 +		 user && *user && !strcmp (s,"PASS"))
 151.307 +	  state = pass_login (t,argc,argv);
 151.308 +	else PSOUT ("-ERR Unknown AUTHORIZATION state command\015\012");
 151.309 +	break;
 151.310 +
 151.311 +      case TRANSACTION:		/* logged in */
 151.312 +	if (!strcmp (s,"STAT")) {
 151.313 +	  for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
 151.314 +				/* message still exists? */
 151.315 +	    if (msg[i] && !(flags[i] & DELE)) {
 151.316 +	      j++;		/* count one more undeleted message */
 151.317 +	      k += mail_elt (stream,msg[i])->rfc822_size + SLEN;
 151.318 +	    }
 151.319 +	  sprintf (tmp,"+OK %lu %lu\015\012",j,k);
 151.320 +	  PSOUT (tmp);
 151.321 +	}
 151.322 +	else if (!strcmp (s,"LIST")) {
 151.323 +	  if (t && *t) {	/* argument do single message */
 151.324 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
 151.325 +		!(flags[i] & DELE)) {
 151.326 +	      sprintf (tmp,"+OK %lu %lu\015\012",i,
 151.327 +		       mail_elt(stream,msg[i])->rfc822_size + SLEN);
 151.328 +	      PSOUT (tmp);
 151.329 +	    }
 151.330 +	    else PSOUT ("-ERR No such message\015\012");
 151.331 +	  }
 151.332 +	  else {		/* entire mailbox */
 151.333 +	    PSOUT ("+OK Mailbox scan listing follows\015\012");
 151.334 +	    for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
 151.335 +	      if (msg[i] && !(flags[i] & DELE)) {
 151.336 +		sprintf (tmp,"%lu %lu\015\012",i,
 151.337 +			 mail_elt (stream,msg[i])->rfc822_size + SLEN);
 151.338 +		PSOUT (tmp);
 151.339 +	      }
 151.340 +	    PBOUT ('.');	/* end of list */
 151.341 +	    CRLF;
 151.342 +	  }
 151.343 +	}
 151.344 +	else if (!strcmp (s,"UIDL")) {
 151.345 +	  if (t && *t) {	/* argument do single message */
 151.346 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
 151.347 +		!(flags[i] & DELE)) {
 151.348 +	      sprintf (tmp,"+OK %lu %08lx%08lx\015\012",i,stream->uid_validity,
 151.349 +		       mail_uid (stream,msg[i]));
 151.350 +	      PSOUT (tmp);
 151.351 +	    }
 151.352 +	    else PSOUT ("-ERR No such message\015\012");
 151.353 +	  }
 151.354 +	  else {		/* entire mailbox */
 151.355 +	    PSOUT ("+OK Unique-ID listing follows\015\012");
 151.356 +	    for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
 151.357 +	      if (msg[i] && !(flags[i] & DELE)) {
 151.358 +		sprintf (tmp,"%lu %08lx%08lx\015\012",i,stream->uid_validity,
 151.359 +			 mail_uid (stream,msg[i]));
 151.360 +		PSOUT (tmp);
 151.361 +	      }
 151.362 +	    PBOUT ('.');	/* end of list */
 151.363 +	    CRLF;
 151.364 +	  }
 151.365 +	}
 151.366 +
 151.367 +	else if (!strcmp (s,"RETR")) {
 151.368 +	  if (t && *t) {	/* must have an argument */
 151.369 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
 151.370 +		!(flags[i] & DELE)) {
 151.371 +	      MESSAGECACHE *elt;
 151.372 +				/* update highest message accessed */
 151.373 +	      if (i > last) last = i;
 151.374 +	      sprintf (tmp,"+OK %lu octets\015\012",
 151.375 +		       (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN);
 151.376 +	      PSOUT (tmp);
 151.377 +				/* if not marked seen or noted to be marked */
 151.378 +	      if (!(elt->seen || (flags[i] & SEEN))) {
 151.379 +		++nseen;	/* note that we need to mark it seen */
 151.380 +		flags[i] |= SEEN;
 151.381 +	      }
 151.382 +				/* get header */
 151.383 +	      t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
 151.384 +	      blat (t,-1,k,NIL);/* write up to trailing CRLF */
 151.385 +				/* build status */
 151.386 +	      sprintf (tmp,STATUS,elt->seen ? "R" : " ",
 151.387 +		       elt->recent ? " " : "O");
 151.388 +	      if (k < 4) CRLF;	/* don't write Status: if no header */
 151.389 +				/* normal header ending with CRLF CRLF? */
 151.390 +	      else if (t[k-3] == '\012') {
 151.391 +		PSOUT (tmp);	/* write status */
 151.392 +		CRLF;		/* then write second CRLF */
 151.393 +	      }
 151.394 +	      else {		/* abnormal - no blank line at end of header */
 151.395 +		CRLF;		/* write CRLF first then */
 151.396 +		PSOUT (tmp);
 151.397 +	      }
 151.398 +				/* output text */
 151.399 +	      t = mail_fetch_text (stream,msg[i],NIL,&k,
 151.400 +				   FT_RETURNSTRINGSTRUCT | FT_PEEK);
 151.401 +	      if (k) {		/* only if there is a text body */
 151.402 +		blat (t,-1,k,&stream->private.string);
 151.403 +		CRLF;		/* end of list */
 151.404 +	      }
 151.405 +	      PBOUT ('.');
 151.406 +	      CRLF;
 151.407 +	    }
 151.408 +	    else PSOUT ("-ERR No such message\015\012");
 151.409 +	  }
 151.410 +	  else PSOUT ("-ERR Missing message number argument\015\012");
 151.411 +	}
 151.412 +
 151.413 +	else if (!strcmp (s,"DELE")) {
 151.414 +	  if (t && *t) {	/* must have an argument */
 151.415 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
 151.416 +		!(flags[i] & DELE)) {
 151.417 +				/* update highest message accessed */
 151.418 +	      if (i > last) last = i;
 151.419 +	      flags[i] |= DELE;	/* note that deletion is requested */
 151.420 +	      PSOUT ("+OK Message deleted\015\012");
 151.421 +	      ++ndele;		/* one more message deleted */
 151.422 +	    }
 151.423 +	    else PSOUT ("-ERR No such message\015\012");
 151.424 +	  }
 151.425 +	  else PSOUT ("-ERR Missing message number argument\015\012");
 151.426 +	}
 151.427 +	else if (!strcmp (s,"NOOP"))
 151.428 +	  PSOUT ("+OK No-op to you too!\015\012");
 151.429 +	else if (!strcmp (s,"LAST")) {
 151.430 +	  sprintf (tmp,"+OK %lu\015\012",last);
 151.431 +	  PSOUT (tmp);
 151.432 +	}
 151.433 +	else if (!strcmp (s,"RSET")) {
 151.434 +	  rset ();		/* reset the mailbox */
 151.435 +	  PSOUT ("+OK Reset state\015\012");
 151.436 +	}
 151.437 +
 151.438 +	else if (!strcmp (s,"TOP")) {
 151.439 +	  if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) && msg[i] &&
 151.440 +	      !(flags[i] & DELE)) {
 151.441 +				/* skip whitespace */
 151.442 +	    while (*s == ' ') s++;
 151.443 +				/* make sure line count argument good */
 151.444 +	    if ((*s >= '0') && (*s <= '9')) {
 151.445 +	      MESSAGECACHE *elt = mail_elt (stream,msg[i]);
 151.446 +	      j = strtoul (s,NIL,10);
 151.447 +				/* update highest message accessed */
 151.448 +	      if (i > last) last = i;
 151.449 +	      PSOUT ("+OK Top of message follows\015\012");
 151.450 +				/* get header */
 151.451 +	      t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
 151.452 +	      blat (t,-1,k,NIL);/* write up to trailing CRLF */
 151.453 +				/* build status */
 151.454 +	      sprintf (tmp,STATUS,elt->seen ? "R" : " ",
 151.455 +		       elt->recent ? " " : "O");
 151.456 +	      if (k < 4) CRLF;	/* don't write Status: if no header */
 151.457 +				/* normal header ending with CRLF CRLF? */
 151.458 +	      else if (t[k-3] == '\012') {
 151.459 +		PSOUT (tmp);	/* write status */
 151.460 +		CRLF;		/* then write second CRLF */
 151.461 +	      }
 151.462 +	      else {		/* abnormal - no blank line at end of header */
 151.463 +		CRLF;		/* write CRLF first then */
 151.464 +		PSOUT (tmp);
 151.465 +	      }
 151.466 +	      if (j) {		/* want any text lines? */
 151.467 +				/* output text */
 151.468 +		t = mail_fetch_text (stream,msg[i],NIL,&k,
 151.469 +				     FT_PEEK | FT_RETURNSTRINGSTRUCT);
 151.470 +				/* tie off final line if full text output */
 151.471 +		if (k && (j -= blat (t,j,k,&stream->private.string))) CRLF;
 151.472 +	      }
 151.473 +	      PBOUT ('.');	/* end of list */
 151.474 +	      CRLF;
 151.475 +	    }
 151.476 +	    else PSOUT ("-ERR Bad line count argument\015\012");
 151.477 +	  }
 151.478 +	  else PSOUT ("-ERR Bad message number argument\015\012");
 151.479 +	}
 151.480 +
 151.481 +	else if (!strcmp (s,"XTND"))
 151.482 +	  PSOUT ("-ERR Sorry I can't do that\015\012");
 151.483 +	else PSOUT ("-ERR Unknown TRANSACTION state command\015\012");
 151.484 +	break;
 151.485 +      default:
 151.486 +        PSOUT ("-ERR Server in unknown state\015\012");
 151.487 +	break;
 151.488 +      }
 151.489 +    }
 151.490 +    PFLUSH ();			/* make sure output finished */
 151.491 +    if (autologouttime) {	/* have an autologout in effect? */
 151.492 +				/* cancel if no longer waiting for login */
 151.493 +      if (state != AUTHORIZATION) autologouttime = 0;
 151.494 +				/* took too long to login */
 151.495 +      else if (autologouttime < time (0)) {
 151.496 +	goodbye = "-ERR Autologout\015\012";
 151.497 +	logout = "Autologout";
 151.498 +	state = LOGOUT;		/* sayonara */
 151.499 +      }
 151.500 +    }
 151.501 +  }
 151.502 +
 151.503 +				/* open and need to update? */
 151.504 +  if (stream && (state == UPDATE)) {
 151.505 +    if (nseen) {		/* only bother if messages need marking seen */
 151.506 +      *(s = tmp) = '\0';	/* clear sequence */
 151.507 +      for (i = 1; i <= nmsgs; ++i) if (flags[i] & SEEN) {
 151.508 +	for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & SEEN); ++j) k = j;
 151.509 +	if (k) sprintf (s,",%lu:%lu",i,k);
 151.510 +	else sprintf (s,",%lu",i);
 151.511 +	s += strlen (s);		/* point to end of string */
 151.512 +	if ((s - tmp) > (MAILTMPLEN - 30)) {
 151.513 +	  mail_setflag (stream,tmp + 1,"\\Seen");
 151.514 +	  *(s = tmp) = '\0';	/* restart sequence */
 151.515 +	}
 151.516 +	i = j;			/* continue after the range */
 151.517 +      }
 151.518 +      if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Seen");
 151.519 +    }
 151.520 +    if (ndele) {		/* any messages to delete? */
 151.521 +      *(s = tmp) = '\0';	/* clear sequence */
 151.522 +      for (i = 1; i <= nmsgs; ++i) if (flags[i] & DELE) {
 151.523 +	for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & DELE); ++j) k = j;
 151.524 +	if (k) sprintf (s,",%lu:%lu",i,k);
 151.525 +	else sprintf (s,",%lu",i);
 151.526 +	s += strlen (s);	/* point to end of string */
 151.527 +	if ((s - tmp) > (MAILTMPLEN - 30)) {
 151.528 +	  mail_setflag (stream,tmp + 1,"\\Deleted");
 151.529 +	  *(s = tmp) = '\0';	/* restart sequence */
 151.530 +	}
 151.531 +	i = j;			/* continue after the range */
 151.532 +      }
 151.533 +      if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Deleted");
 151.534 +      mail_expunge (stream);
 151.535 +    }
 151.536 +    syslog (LOG_INFO,"Update user=%.80s host=%.80s nmsgs=%lu ndele=%lu nseen=%lu",
 151.537 +	    user,tcp_clienthost (),stream->nmsgs,ndele,nseen);
 151.538 +    mail_close (stream);
 151.539 +  }
 151.540 +  sayonara (0);
 151.541 +  return 0;			/* stupid compilers */
 151.542 +}
 151.543 +
 151.544 +
 151.545 +/* Say goodbye
 151.546 + * Accepts: exit status
 151.547 + *
 151.548 + * Does not return
 151.549 + */
 151.550 +
 151.551 +void sayonara (int status)
 151.552 +{
 151.553 +  logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
 151.554 +  if (goodbye) {		/* have a goodbye message? */
 151.555 +    PSOUT (goodbye);
 151.556 +    PFLUSH ();			/* make sure blatted */
 151.557 +  }
 151.558 +  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
 151.559 +	  user ? (char *) user : "???",tcp_clienthost ());
 151.560 +				/* do logout hook if needed */
 151.561 +  if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
 151.562 +  _exit (status);		/* all done */
 151.563 +}
 151.564 +
 151.565 +/* Clock interrupt
 151.566 + */
 151.567 +
 151.568 +void clkint ()
 151.569 +{
 151.570 +  alarm (0);			/* disable all interrupts */
 151.571 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.572 +  goodbye = "-ERR Autologout; idle for too long\015\012";
 151.573 +  logout = "Autologout";
 151.574 +  if (critical) state = LOGOUT;	/* badly hosed if in critical code */
 151.575 +  else {			/* try to gracefully close the stream */
 151.576 +    if ((state == TRANSACTION) && !stream->lock) {
 151.577 +      rset ();
 151.578 +      mail_close (stream);
 151.579 +    }
 151.580 +    state = LOGOUT;
 151.581 +    stream = NIL;
 151.582 +    sayonara (1);
 151.583 +  }
 151.584 +}
 151.585 +
 151.586 +
 151.587 +/* Kiss Of Death interrupt
 151.588 + */
 151.589 +
 151.590 +void kodint ()
 151.591 +{
 151.592 +				/* only if idle */
 151.593 +  if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
 151.594 +    alarm (0);			/* disable all interrupts */
 151.595 +    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.596 +    goodbye = "-ERR Received Kiss of Death\015\012";
 151.597 +    logout = "Killed (lost mailbox lock)";
 151.598 +    if (critical) state =LOGOUT;/* must defer if in critical code */
 151.599 +    else {			/* try to gracefully close the stream */
 151.600 +      if ((state == TRANSACTION) && !stream->lock) {
 151.601 +	rset ();
 151.602 +	mail_close (stream);
 151.603 +      }
 151.604 +      state = LOGOUT;
 151.605 +      stream = NIL;
 151.606 +      sayonara (1);		/* die die die */
 151.607 +    }
 151.608 +  }
 151.609 +}
 151.610 +
 151.611 +
 151.612 +/* Hangup interrupt
 151.613 + */
 151.614 +
 151.615 +void hupint ()
 151.616 +{
 151.617 +  alarm (0);			/* disable all interrupts */
 151.618 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.619 +  goodbye = NIL;		/* nobody left to talk to */
 151.620 +  logout = "Hangup";
 151.621 +  if (critical) state = LOGOUT;	/* must defer if in critical code */
 151.622 +  else {			/* try to gracefully close the stream */
 151.623 +    if ((state == TRANSACTION) && !stream->lock) {
 151.624 +      rset ();
 151.625 +      mail_close (stream);
 151.626 +    }
 151.627 +    state = LOGOUT;
 151.628 +    stream = NIL;
 151.629 +    sayonara (1);		/* die die die */
 151.630 +  }
 151.631 +}
 151.632 +
 151.633 +
 151.634 +/* Termination interrupt
 151.635 + */
 151.636 +
 151.637 +void trmint ()
 151.638 +{
 151.639 +  alarm (0);			/* disable all interrupts */
 151.640 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.641 +  goodbye = "-ERR Killed\015\012";
 151.642 +  logout = "Killed";
 151.643 +  if (critical) state = LOGOUT;	/* must defer if in critical code */
 151.644 +  /* Make no attempt at graceful closure since a shutdown may be in
 151.645 +   * progress, and we won't have any time to do mail_close() actions.
 151.646 +   */
 151.647 +  else sayonara (1);		/* die die die */
 151.648 +}
 151.649 +
 151.650 +/* Parse PASS command
 151.651 + * Accepts: pointer to command argument
 151.652 + * Returns: new state
 151.653 + */
 151.654 +
 151.655 +int pass_login (char *t,int argc,char *argv[])
 151.656 +{
 151.657 +  char tmp[MAILTMPLEN];
 151.658 +				/* flush old passowrd */
 151.659 +  if (pass) fs_give ((void **) &pass);
 151.660 +  if (!(t && *t)) {		/* if no password given */
 151.661 +    PSOUT ("-ERR Missing password argument\015\012");
 151.662 +    return AUTHORIZATION;
 151.663 +  }
 151.664 +  pass = cpystr (t);		/* copy password argument */
 151.665 +  if (!host) {			/* want remote mailbox? */
 151.666 +				/* no, delimit user from possible admin */
 151.667 +    if (t = strchr (user,'*')) *t++ ='\0';
 151.668 +				/* attempt the login */
 151.669 +    if (server_login (user,pass,t,argc,argv)) {
 151.670 +      int ret = mbxopen ("INBOX");
 151.671 +      if (ret == TRANSACTION)	/* mailbox opened OK? */
 151.672 +	syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s nmsgs=%lu/%lu",
 151.673 +		t ? "Admin " : "",user,tcp_clienthost (),nmsgs,stream->nmsgs);
 151.674 +      else syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s no mailbox",
 151.675 +		   t ? "Admin " : "",user,tcp_clienthost ());
 151.676 +      return ret;
 151.677 +    }
 151.678 +  }
 151.679 +#ifndef DISABLE_POP_PROXY
 151.680 +				/* remote; build remote INBOX */
 151.681 +  else if (anonymous_login (argc,argv)) {
 151.682 +    syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host,
 151.683 +	    user,tcp_clienthost ());
 151.684 +    sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user);
 151.685 +				/* disable rimap just in case */
 151.686 +    mail_parameters (NIL,SET_RSHTIMEOUT,0);
 151.687 +    return mbxopen (tmp);
 151.688 +  }
 151.689 +#endif
 151.690 +				/* vague error message to confuse crackers */
 151.691 +  PSOUT ("-ERR Bad login\015\012");
 151.692 +  return AUTHORIZATION;
 151.693 +}
 151.694 +
 151.695 +/* Authentication responder
 151.696 + * Accepts: challenge
 151.697 + *	    length of challenge
 151.698 + *	    pointer to response length return location if non-NIL
 151.699 + * Returns: response
 151.700 + */
 151.701 +
 151.702 +#define RESPBUFLEN 8*MAILTMPLEN
 151.703 +
 151.704 +char *responder (void *challenge,unsigned long clen,unsigned long *rlen)
 151.705 +{
 151.706 +  unsigned long i,j;
 151.707 +  unsigned char *t,resp[RESPBUFLEN];
 151.708 +  char tmp[MAILTMPLEN];
 151.709 +  if (initial) {		/* initial response given? */
 151.710 +    if (clen) return NIL;	/* not permitted */
 151.711 +				/* set up response */
 151.712 +    t = (unsigned char *) initial;
 151.713 +    initial = NIL;		/* no more initial response */
 151.714 +    return (char *) rfc822_base64 (t,strlen ((char *) t),rlen ? rlen : &i);
 151.715 +  }
 151.716 +  PSOUT ("+ ");
 151.717 +  for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++)
 151.718 +    if (t[j] > ' ') PBOUT (t[j]);
 151.719 +  fs_give ((void **) &t);
 151.720 +  CRLF;
 151.721 +  PFLUSH ();			/* dump output buffer */
 151.722 +  resp[RESPBUFLEN-1] = '\0';	/* last buffer character is guaranteed NUL */
 151.723 +  alarm (LOGINTIMEOUT);		/* get a response under timeout */
 151.724 +  clearerr (stdin);		/* clear stdin errors */
 151.725 +				/* read buffer */
 151.726 +  while (!PSIN ((char *) resp,RESPBUFLEN)) {
 151.727 +				/* ignore if some interrupt */
 151.728 +    if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
 151.729 +    else {
 151.730 +      char *e = ferror (stdin) ?
 151.731 +	strerror (errno) : "Command stream end of file";
 151.732 +      alarm (0);		/* disable all interrupts */
 151.733 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.734 +      sprintf (logout = tmp,"%.80s, while reading authentication",e);
 151.735 +      goodbye = NIL;
 151.736 +      state = LOGOUT;
 151.737 +      sayonara (1);
 151.738 +    }
 151.739 +  }
 151.740 +  if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) {
 151.741 +    int c;
 151.742 +    while ((c = PBIN ()) != '\012') if (c == EOF) {
 151.743 +				/* ignore if some interrupt */
 151.744 +      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
 151.745 +      else {
 151.746 +	char *e = ferror (stdin) ?
 151.747 +	  strerror (errno) : "Command stream end of file";
 151.748 +	alarm (0);		/* disable all interrupts */
 151.749 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.750 +	sprintf (logout = tmp,"%.80s, while reading auth char",e);
 151.751 +	goodbye = NIL;
 151.752 +	state = LOGOUT;
 151.753 +	sayonara (1);
 151.754 +      }
 151.755 +    }
 151.756 +    return NIL;
 151.757 +  }
 151.758 +  alarm (0);			/* make sure timeout disabled */
 151.759 +  if (t[-1] == '\015') --t;	/* remove CR */
 151.760 +  *t = '\0';			/* tie off buffer */
 151.761 +  return (resp[0] != '*') ?
 151.762 +    (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL;
 151.763 +}
 151.764 +
 151.765 +/* Select mailbox
 151.766 + * Accepts: mailbox name
 151.767 + * Returns: new state
 151.768 + */
 151.769 +
 151.770 +int mbxopen (char *mailbox)
 151.771 +{
 151.772 +  unsigned long i,j;
 151.773 +  char tmp[MAILTMPLEN];
 151.774 +  MESSAGECACHE *elt;
 151.775 +  if (msg) fs_give ((void **) &msg);
 151.776 +				/* open mailbox */
 151.777 +  if (!(stream = mail_open (stream,mailbox,NIL)))
 151.778 +    goodbye = "-ERR Unable to open user's INBOX\015\012";
 151.779 +  else if (stream->rdonly)	/* make sure not readonly */
 151.780 +    goodbye = "-ERR Can't get lock.  Mailbox in use\015\012";
 151.781 +  else {
 151.782 +    nmsgs = 0;			/* no messages yet */
 151.783 +    if (j = stream->nmsgs) {	/* if mailbox non-empty */
 151.784 +      sprintf (tmp,"1:%lu",j);	/* fetch fast information for all messages */
 151.785 +      mail_fetch_fast (stream,tmp,NIL);
 151.786 +    }
 151.787 +				/* create 1-origin tables */
 151.788 +    msg = (long *) fs_get (++j * sizeof (long));
 151.789 +    flags = (short *) fs_get (j * sizeof (short));
 151.790 +				/* build map */
 151.791 +    for (i = 1; i < j; ++i) if (!(elt = mail_elt (stream,i))->deleted) {
 151.792 +      msg[++nmsgs] = i;		/* note the presence of this message */
 151.793 +      if (elt->seen) il = nmsgs;/* and set up initial LAST */
 151.794 +    }
 151.795 +				/* make sure unused map entries are zero */
 151.796 +    for (i = nmsgs + 1; i < j; ++i) msg[i] = 0;
 151.797 +    rset ();			/* do implicit RSET */
 151.798 +    sprintf (tmp,"+OK Mailbox open, %lu messages\015\012",nmsgs);
 151.799 +    PSOUT (tmp);
 151.800 +    return TRANSACTION;
 151.801 +  }
 151.802 +  syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s",
 151.803 +	  user,tcp_clienthost ());
 151.804 +  return UPDATE;
 151.805 +}
 151.806 +
 151.807 +/* Blat a string with dot checking
 151.808 + * Accepts: string
 151.809 + *	    maximum number of lines if greater than zero
 151.810 + *	    maximum number of bytes to output
 151.811 + *	    alternative stringstruct
 151.812 + * Returns: number of lines output
 151.813 + *
 151.814 + * This routine is uglier and kludgier than it should be, just to be robust
 151.815 + * in the case of a message which doesn't end in a newline.  Yes, this routine
 151.816 + * does truncate the last two bytes from the text.  Since it is normally a
 151.817 + * newline and the main routine adds it back, it usually does not make a
 151.818 + * difference.  But if it isn't, since the newline is required and the octet
 151.819 + * counts have to match, there's no choice but to truncate.
 151.820 + */
 151.821 +
 151.822 +long blat (char *text,long lines,unsigned long size,STRING *st)
 151.823 +{
 151.824 +  char c,d,e;
 151.825 +  long ret = 0;
 151.826 +				/* no-op if zero lines or empty string */
 151.827 +  if (!(lines && (size-- > 2))) return 0;
 151.828 +  if (text) {
 151.829 +    c = *text++; d = *text++;	/* collect first two bytes */
 151.830 +    if (c == '.') PBOUT ('.');	/* double string-leading dot if necessary */
 151.831 +    while (lines && --size) {	/* copy loop */
 151.832 +      e = *text++;		/* get next byte */
 151.833 +      PBOUT (c);		/* output character */
 151.834 +      if (c == '\012') {	/* end of line? */
 151.835 +	ret++; --lines;		/* count another line */
 151.836 +				/* double leading dot as necessary */
 151.837 +	if (lines && size && (d == '.')) PBOUT ('.');
 151.838 +      }
 151.839 +      c = d; d = e;		/* move to next character */
 151.840 +    }
 151.841 +  }
 151.842 +  else {
 151.843 +    c = SNX (st); d = SNX (st);	/* collect first two bytes */
 151.844 +    if (c == '.') PBOUT ('.');	/* double string-leading dot if necessary */
 151.845 +    while (lines && --size) {	/* copy loop */
 151.846 +      e = SNX (st);		/* get next byte */
 151.847 +      PBOUT (c);		/* output character */
 151.848 +      if (c == '\012') {	/* end of line? */
 151.849 +	ret++; --lines;		/* count another line */
 151.850 +				/* double leading dot as necessary */
 151.851 +	if (lines && size && (d == '.')) PBOUT ('.');
 151.852 +      }
 151.853 +      c = d; d = e;		/* move to next character */
 151.854 +    }
 151.855 +  }
 151.856 +  return ret;
 151.857 +}
 151.858 +
 151.859 +/* Reset mailbox
 151.860 + */
 151.861 +
 151.862 +void rset ()
 151.863 +{
 151.864 +				/* clear all flags */
 151.865 +  if (flags) memset ((void *) flags,0,(nmsgs + 1) * sizeof (short));
 151.866 +  ndele = nseen = 0;		/* no more deleted or seen messages */
 151.867 +  last = il;			/* restore previous LAST value */
 151.868 +}
 151.869 +
 151.870 +/* Co-routines from MAIL library */
 151.871 +
 151.872 +
 151.873 +/* Message matches a search
 151.874 + * Accepts: MAIL stream
 151.875 + *	    message number
 151.876 + */
 151.877 +
 151.878 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
 151.879 +{
 151.880 +  /* Never called */
 151.881 +}
 151.882 +
 151.883 +
 151.884 +/* Message exists (i.e. there are that many messages in the mailbox)
 151.885 + * Accepts: MAIL stream
 151.886 + *	    message number
 151.887 + */
 151.888 +
 151.889 +void mm_exists (MAILSTREAM *stream,unsigned long number)
 151.890 +{
 151.891 +  /* Can't use this mechanism.  POP has no means of notifying the client of
 151.892 +     new mail during the session. */
 151.893 +}
 151.894 +
 151.895 +
 151.896 +/* Message expunged
 151.897 + * Accepts: MAIL stream
 151.898 + *	    message number
 151.899 + */
 151.900 +
 151.901 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
 151.902 +{
 151.903 +  unsigned long i = number + 1;
 151.904 +  msg[number] = 0;		/* I bet that this will annoy someone */
 151.905 +  while (i <= nmsgs) --msg[i++];
 151.906 +}
 151.907 +
 151.908 +
 151.909 +/* Message flag status change
 151.910 + * Accepts: MAIL stream
 151.911 + *	    message number
 151.912 + */
 151.913 +
 151.914 +void mm_flags (MAILSTREAM *stream,unsigned long number)
 151.915 +{
 151.916 +  /* This isn't used */
 151.917 +}
 151.918 +
 151.919 +
 151.920 +/* Mailbox found
 151.921 + * Accepts: MAIL stream
 151.922 + *	    hierarchy delimiter
 151.923 + *	    mailbox name
 151.924 + *	    mailbox attributes
 151.925 + */
 151.926 +
 151.927 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 151.928 +{
 151.929 +  /* This isn't used */
 151.930 +}
 151.931 +
 151.932 +
 151.933 +/* Subscribe mailbox found
 151.934 + * Accepts: MAIL stream
 151.935 + *	    hierarchy delimiter
 151.936 + *	    mailbox name
 151.937 + *	    mailbox attributes
 151.938 + */
 151.939 +
 151.940 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 151.941 +{
 151.942 +  /* This isn't used */
 151.943 +}
 151.944 +
 151.945 +
 151.946 +/* Mailbox status
 151.947 + * Accepts: MAIL stream
 151.948 + *	    mailbox name
 151.949 + *	    mailbox status
 151.950 + */
 151.951 +
 151.952 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 151.953 +{
 151.954 +  /* This isn't used */
 151.955 +}
 151.956 +
 151.957 +/* Notification event
 151.958 + * Accepts: MAIL stream
 151.959 + *	    string to log
 151.960 + *	    error flag
 151.961 + */
 151.962 +
 151.963 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
 151.964 +{
 151.965 +  mm_log (string,errflg);	/* just do mm_log action */
 151.966 +}
 151.967 +
 151.968 +
 151.969 +/* Log an event for the user to see
 151.970 + * Accepts: string to log
 151.971 + *	    error flag
 151.972 + */
 151.973 +
 151.974 +void mm_log (char *string,long errflg)
 151.975 +{
 151.976 +  switch (errflg) {
 151.977 +  case NIL:			/* information message */
 151.978 +  case PARSE:			/* parse glitch */
 151.979 +    break;			/* too many of these to log */
 151.980 +  case WARN:			/* warning */
 151.981 +    syslog (LOG_DEBUG,"%s",string);
 151.982 +    break;
 151.983 +  case BYE:			/* driver broke connection */
 151.984 +    if (state != UPDATE) {
 151.985 +      char tmp[MAILTMPLEN];
 151.986 +      alarm (0);		/* disable all interrupts */
 151.987 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
 151.988 +      sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
 151.989 +      goodbye = NIL;
 151.990 +      state = LOGOUT;
 151.991 +      sayonara (1);
 151.992 +    }
 151.993 +    break;
 151.994 +  case ERROR:			/* error that broke command */
 151.995 +  default:			/* default should never happen */
 151.996 +    syslog (LOG_NOTICE,"%s",string);
 151.997 +    break;
 151.998 +  }
 151.999 +}    
151.1000 +
151.1001 +
151.1002 +/* Log an event to debugging telemetry
151.1003 + * Accepts: string to log
151.1004 + */
151.1005 +
151.1006 +void mm_dlog (char *string)
151.1007 +{
151.1008 +  /* Not doing anything here for now */
151.1009 +}
151.1010 +
151.1011 +
151.1012 +/* Get user name and password for this host
151.1013 + * Accepts: parse of network mailbox name
151.1014 + *	    where to return user name
151.1015 + *	    where to return password
151.1016 + *	    trial count
151.1017 + */
151.1018 +
151.1019 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
151.1020 +{
151.1021 +				/* set user name */
151.1022 +  strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
151.1023 +  if (pass) {
151.1024 +    strncpy (password,pass,255);/* and password */
151.1025 +    fs_give ((void **) &pass);
151.1026 +  }
151.1027 +  else memset (password,0,256);	/* no password to send, abort login */
151.1028 +  username[NETMAXUSER] = password[255] = '\0';
151.1029 +}
151.1030 +
151.1031 +/* About to enter critical code
151.1032 + * Accepts: stream
151.1033 + */
151.1034 +
151.1035 +void mm_critical (MAILSTREAM *stream)
151.1036 +{
151.1037 +  ++critical;
151.1038 +}
151.1039 +
151.1040 +
151.1041 +/* About to exit critical code
151.1042 + * Accepts: stream
151.1043 + */
151.1044 +
151.1045 +void mm_nocritical (MAILSTREAM *stream)
151.1046 +{
151.1047 +  --critical;
151.1048 +}
151.1049 +
151.1050 +
151.1051 +/* Disk error found
151.1052 + * Accepts: stream
151.1053 + *	    system error code
151.1054 + *	    flag indicating that mailbox may be clobbered
151.1055 + * Returns: abort flag
151.1056 + */
151.1057 +
151.1058 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
151.1059 +{
151.1060 +  if (serious) {		/* try your damnest if clobberage likely */
151.1061 +    syslog (LOG_ALERT,
151.1062 +	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
151.1063 +	    user,tcp_clienthost (),
151.1064 +	    (stream && stream->mailbox) ? stream->mailbox : "???",
151.1065 +	    strerror (errcode));
151.1066 +    alarm (0);			/* make damn sure timeout disabled */
151.1067 +    sleep (60);			/* give it some time to clear up */
151.1068 +    return NIL;
151.1069 +  }
151.1070 +  syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
151.1071 +	  user,tcp_clienthost (),
151.1072 +	  (stream && stream->mailbox) ? stream->mailbox : "???",
151.1073 +	  strerror (errcode));
151.1074 +  return T;
151.1075 +}
151.1076 +
151.1077 +
151.1078 +/* Log a fatal error event
151.1079 + * Accepts: string to log
151.1080 + */
151.1081 +
151.1082 +void mm_fatal (char *string)
151.1083 +{
151.1084 +  mm_log (string,ERROR);	/* shouldn't happen normally */
151.1085 +}
   152.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   152.2 +++ b/src/ipopd/ipopd.8	Mon Sep 14 15:17:45 2009 +0900
   152.3 @@ -0,0 +1,75 @@
   152.4 +.ig
   152.5 + * ========================================================================
   152.6 + * Copyright 1988-2006 University of Washington
   152.7 + *
   152.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   152.9 + * you may not use this file except in compliance with the License.
  152.10 + * You may obtain a copy of the License at
  152.11 + *
  152.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  152.13 + *
  152.14 + * 
  152.15 + * ========================================================================
  152.16 +..
  152.17 +.TH IPOPD 8 "August 30, 2006"
  152.18 +.UC 5
  152.19 +.SH NAME
  152.20 +IPOPd \- Post Office Protocol server
  152.21 +.SH SYNOPSIS
  152.22 +.B /usr/etc/ipop2d
  152.23 +.PP
  152.24 +.B /usr/etc/ipop3d
  152.25 +.SH DESCRIPTION
  152.26 +.I ipop2d
  152.27 +and
  152.28 +.I ipop3d
  152.29 +are servers which support the
  152.30 +.B POP2
  152.31 +and
  152.32 +.B POP3
  152.33 +remote mail access protocols respectively.
  152.34 +.I ipop2d
  152.35 +and
  152.36 +.I ipop3d
  152.37 +can also be used by
  152.38 +.B POP2
  152.39 +and
  152.40 +.B POP3
  152.41 +clients respecitively to access mailboxes on
  152.42 +.B IMAP
  152.43 +servers by specifying a login user name in the form <host>:<user>
  152.44 +e.g.,
  152.45 +.B SERVER.WASHINGTON.EDU:SMITH.
  152.46 +.PP
  152.47 +These daemons contain CRAM-MD5 and APOP support.  See the md5.txt
  152.48 +documentation file for additional information.
  152.49 +.PP
  152.50 +.I ipop2d
  152.51 +and
  152.52 +.I ipop3d
  152.53 +are invoked by the internet server (see
  152.54 +.IR inetd (8)),
  152.55 +normally for requests to connect to the
  152.56 +.B POP
  152.57 +port as indicated by the
  152.58 +.I /etc/services
  152.59 +file (see
  152.60 +.IR services (5)).
  152.61 +.SH "SEE ALSO"
  152.62 +imapd(8)
  152.63 +.SH BUGS
  152.64 +The
  152.65 +.B POP2
  152.66 +and
  152.67 +.B POP3
  152.68 +protocols are intrinsically less flexible than
  152.69 +.B IMAP
  152.70 +and do not maintain `read' vs `unread' state on the server.  As a result,
  152.71 +most
  152.72 +.B POP
  152.73 +based software transfers all the mail from the server to the client and
  152.74 +deletes it from the server.  This necessarily locks the user into using only
  152.75 +a single client.
  152.76 +.PP
  152.77 +.B POP3
  152.78 +does not allow you to specify an alternate folder from the user's default.
   153.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   153.2 +++ b/src/ipopd/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
   153.3 @@ -0,0 +1,57 @@
   153.4 +# ========================================================================
   153.5 +# Copyright 1988-2006 University of Washington
   153.6 +#
   153.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   153.8 +# you may not use this file except in compliance with the License.
   153.9 +# You may obtain a copy of the License at
  153.10 +#
  153.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  153.12 +#
  153.13 +# 
  153.14 +# ========================================================================
  153.15 +
  153.16 +
  153.17 +# Program:	IPOPD Makefile for Windows 9x and Windows NT
  153.18 +#
  153.19 +# Author:	Mark Crispin
  153.20 +#		Networks and Distributed Computing
  153.21 +#		Computing & Communications
  153.22 +#		University of Washington
  153.23 +#		Administration Building, AG-44
  153.24 +#		Seattle, WA  98195
  153.25 +#		Internet: MRC@CAC.Washington.EDU
  153.26 +#
  153.27 +# Date:		28 October 1990
  153.28 +# Last Edited:	30 August 2006
  153.29 +
  153.30 +
  153.31 +C = ..\c-client
  153.32 +CCLIENTLIB = $C\cclient.lib
  153.33 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
  153.34 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  153.35 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  153.36 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  153.37 +
  153.38 +
  153.39 +ipopd: ipop2d ipop3d
  153.40 +
  153.41 +ipop2d: $(CCLIENTLIB) ipop2d.obj
  153.42 +	LINK /NOLOGO ipop2d.obj $(LIBS)
  153.43 +
  153.44 +ipop3d: $(CCLIENTLIB) ipop3d.obj
  153.45 +	LINK /NOLOGO ipop3d.obj $(LIBS)
  153.46 +
  153.47 +ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
  153.48 +
  153.49 +ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
  153.50 +
  153.51 +$(CCLIENTLIB):
  153.52 +	@echo Make c-client first
  153.53 +	false
  153.54 +
  153.55 +clean:
  153.56 +	del *.obj *.exe *.lib *.exp || rem
  153.57 +
  153.58 +# A monument to a hack of long ago and far away...
  153.59 +love:
  153.60 +	@echo not war?
   154.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   154.2 +++ b/src/ipopd/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
   154.3 @@ -0,0 +1,58 @@
   154.4 +# ========================================================================
   154.5 +# Copyright 1988-2006 University of Washington
   154.6 +#
   154.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   154.8 +# you may not use this file except in compliance with the License.
   154.9 +# You may obtain a copy of the License at
  154.10 +#
  154.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  154.12 +#
  154.13 +# 
  154.14 +# ========================================================================
  154.15 +
  154.16 +
  154.17 +# Program:	IPOPD Makefile for Windows 9x and Windows NT + Kerberos
  154.18 +#
  154.19 +# Author:	Mark Crispin
  154.20 +#		Networks and Distributed Computing
  154.21 +#		Computing & Communications
  154.22 +#		University of Washington
  154.23 +#		Administration Building, AG-44
  154.24 +#		Seattle, WA  98195
  154.25 +#		Internet: MRC@CAC.Washington.EDU
  154.26 +#
  154.27 +# Date:		28 October 1990
  154.28 +# Last Edited:	30 August 2006
  154.29 +
  154.30 +
  154.31 +C = ..\c-client
  154.32 +CCLIENTLIB = $C\cclient.lib
  154.33 +K5 = \k5\lib
  154.34 +K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
  154.35 +LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
  154.36 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  154.37 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  154.38 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  154.39 +
  154.40 +ipopd: ipop2d ipop3d
  154.41 +
  154.42 +ipop2d: $(CCLIENTLIB) ipop2d.obj
  154.43 +	LINK /NOLOGO ipop2d.obj $(LIBS)
  154.44 +
  154.45 +ipop3d: $(CCLIENTLIB) ipop3d.obj
  154.46 +	LINK /NOLOGO ipop3d.obj $(LIBS)
  154.47 +
  154.48 +ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
  154.49 +
  154.50 +ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
  154.51 +
  154.52 +$(CCLIENTLIB):
  154.53 +	@echo Make c-client first
  154.54 +	false
  154.55 +
  154.56 +clean:
  154.57 +	del *.obj *.exe *.lib *.exp || rem
  154.58 +
  154.59 +# A monument to a hack of long ago and far away...
  154.60 +love:
  154.61 +	@echo not war?
   155.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   155.2 +++ b/src/ipopd/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
   155.3 @@ -0,0 +1,56 @@
   155.4 +# ========================================================================
   155.5 +# Copyright 1988-2006 University of Washington
   155.6 +#
   155.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   155.8 +# you may not use this file except in compliance with the License.
   155.9 +# You may obtain a copy of the License at
  155.10 +#
  155.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  155.12 +#
  155.13 +# 
  155.14 +# ========================================================================
  155.15 +
  155.16 +
  155.17 +# Program:	IPOPD Makefile for Windows 2000/XP
  155.18 +#
  155.19 +# Author:	Mark Crispin
  155.20 +#		Networks and Distributed Computing
  155.21 +#		Computing & Communications
  155.22 +#		University of Washington
  155.23 +#		Administration Building, AG-44
  155.24 +#		Seattle, WA  98195
  155.25 +#		Internet: MRC@CAC.Washington.EDU
  155.26 +#
  155.27 +# Date:		28 October 1990
  155.28 +# Last Edited:	30 August 2006
  155.29 +
  155.30 +
  155.31 +C = ..\c-client
  155.32 +CCLIENTLIB = $C\cclient.lib
  155.33 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
  155.34 +OSCOMPAT = /DWIN32
  155.35 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  155.36 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  155.37 +
  155.38 +ipopd: ipop2d ipop3d
  155.39 +
  155.40 +ipop2d: $(CCLIENTLIB) ipop2d.obj
  155.41 +	LINK /NOLOGO ipop2d.obj $(LIBS)
  155.42 +
  155.43 +ipop3d: $(CCLIENTLIB) ipop3d.obj
  155.44 +	LINK /NOLOGO ipop3d.obj $(LIBS)
  155.45 +
  155.46 +ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
  155.47 +
  155.48 +ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
  155.49 +
  155.50 +$(CCLIENTLIB):
  155.51 +	@echo Make c-client first
  155.52 +	false
  155.53 +
  155.54 +clean:
  155.55 +	del *.obj *.exe *.lib *.exp || rem
  155.56 +
  155.57 +# A monument to a hack of long ago and far away...
  155.58 +love:
  155.59 +	@echo not war?
   156.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   156.2 +++ b/src/mailutil/Makefile	Mon Sep 14 15:17:45 2009 +0900
   156.3 @@ -0,0 +1,51 @@
   156.4 +# ========================================================================
   156.5 +# Copyright 1988-2006 University of Washington
   156.6 +#
   156.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   156.8 +# you may not use this file except in compliance with the License.
   156.9 +# You may obtain a copy of the License at
  156.10 +#
  156.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  156.12 +#
  156.13 +# 
  156.14 +# ========================================================================
  156.15 +
  156.16 +
  156.17 +# Program:	mailutil Makefile
  156.18 +#
  156.19 +# Author:	Mark Crispin
  156.20 +#		Networks and Distributed Computing
  156.21 +#		Computing & Communications
  156.22 +#		University of Washington
  156.23 +#		Administration Building, AG-44
  156.24 +#		Seattle, WA  98195
  156.25 +#		Internet: MRC@CAC.Washington.EDU
  156.26 +#
  156.27 +# Date:		2 February 1993
  156.28 +# Last Edited:	30 August 2006
  156.29 +
  156.30 +
  156.31 +C = ../c-client
  156.32 +CCLIENTLIB = $C/c-client.a
  156.33 +SHELL = /bin/sh
  156.34 +
  156.35 +# Get local definitions from c-client directory
  156.36 +
  156.37 +CC = `cat $C/CCTYPE`
  156.38 +CFLAGS = -I$C `cat $C/CFLAGS`
  156.39 +LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
  156.40 +
  156.41 +mailutil: $(CCLIENTLIB) mailutil.o
  156.42 +	$(CC) $(CFLAGS) -o mailutil mailutil.o $(LDFLAGS)
  156.43 +
  156.44 +mailutil.o: $C/mail.h $C/misc.h $C/osdep.h
  156.45 +
  156.46 +$(CCLIENTLIB):
  156.47 +	cd $C;make
  156.48 +
  156.49 +clean:
  156.50 +	rm -f *.o mailutil
  156.51 +
  156.52 +# A monument to a hack of long ago and far away...
  156.53 +love:
  156.54 +	@echo 'not war?'
   157.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   157.2 +++ b/src/mailutil/mailutil.1	Mon Sep 14 15:17:45 2009 +0900
   157.3 @@ -0,0 +1,264 @@
   157.4 +.ig
   157.5 + * ========================================================================
   157.6 + * Copyright 1988-2008 University of Washington
   157.7 + *
   157.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   157.9 + * you may not use this file except in compliance with the License.
  157.10 + * You may obtain a copy of the License at
  157.11 + *
  157.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  157.13 + *
  157.14 + * 
  157.15 + * ========================================================================
  157.16 +..
  157.17 +.TH mailutil 1 "March 3, 2008" 
  157.18 +.SH NAME
  157.19 +mailutil - mail utility program
  157.20 +.nh
  157.21 +.SH SYNTAX
  157.22 +.B mailutil command [switches] [arguments]
  157.23 +.PP
  157.24 +All commands accept the -d, -v, and -u switches in addition to any
  157.25 +command-specific switches.
  157.26 +.PP
  157.27 +.B mailutil check [MAILBOX]
  157.28 +.PP
  157.29 +.B mailutil create MAILBOX
  157.30 +.PP
  157.31 +.B mailutil delete MAILBOX
  157.32 +.PP
  157.33 +.B mailutil rename SOURCE DESTINATION
  157.34 +.PP
  157.35 +.B mailutil copy [-rw] [-kw] [-ig] SOURCE DESTINATION
  157.36 +.PP
  157.37 +.B mailutil move [-rw] [-kw] [-ig] SOURCE DESTINATION
  157.38 +.PP
  157.39 +.B mailutil append [-rw] [-kw] [-ig] SOURCE DESTINATION
  157.40 +.PP
  157.41 +.B mailutil appenddelete [-rw] [-kw] [-ig] SOURCE DESTINATION
  157.42 +.PP
  157.43 +.B mailutil prune MAILBOX CRITERIA
  157.44 +.PP
  157.45 +.B mailutil transfer [-m mode] [-rw] [-kw] [-ig] SOURCE DESTINATION
  157.46 +.SH DESCRIPTION
  157.47 +.B mailutil
  157.48 +replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy,
  157.49 +mbxcreat, and mbxcvt programs.
  157.50 +.PP
  157.51 +.B mailutil check
  157.52 +determines whether new mail exists in the given mailbox (the default
  157.53 +is INBOX).  The number of new messages is defined as the number of
  157.54 +messages that have "Recent" status set.  If the mailbox contains no
  157.55 +new messages, 
  157.56 +.B mailutil check
  157.57 +will indicate that no new mail is present;
  157.58 +otherwise, it will report the number of new messages.  In either case,
  157.59 +it will also indicate the canonical form of the name of the mailbox.
  157.60 +.PP
  157.61 +.B mailutil create
  157.62 +creates a new
  157.63 +.I mailbox
  157.64 +with the given name.  The mailbox name must not already exist.  A mailbox
  157.65 +can be created in a particular format by prefixing the name with 
  157.66 +.I #driver.
  157.67 +followed by the format name and a
  157.68 +.I /
  157.69 +character.  For example, the command
  157.70 +.br
  157.71 +   mailutil create #driver.mbx/junkmail
  157.72 +.br
  157.73 +will create a new mailbox named "junkmail" in mbx format.
  157.74 +.PP
  157.75 +.B mailutil delete
  157.76 +deletes an existing
  157.77 +.I mailbox
  157.78 +with the given name.
  157.79 +.PP
  157.80 +.B mailutil rename
  157.81 +renames an existing mailbox to a new name (which must not already exist).
  157.82 +This only works if the old and new names are in the same mail store.  A
  157.83 +more general means to rename a mailbox is to do a
  157.84 +.B mailutil copy
  157.85 +of the old name to the new name, followed by a
  157.86 +.B mailutil delete
  157.87 +of the old name.
  157.88 +.PP
  157.89 +.B mailutil copy
  157.90 +creates a new mailbox and copies messages from the old mailbox to the
  157.91 +new mailbox.  As in
  157.92 +.B mailutil create
  157.93 +a mailbox format can be specified with the new mailbox.  For example, the
  157.94 +command
  157.95 +.br
  157.96 +   mailutil copy INBOX #driver.mbx/INBOX
  157.97 +.br
  157.98 +will copy messages from your existing INBOX to an mbx-format INBOX.
  157.99 +.PP
 157.100 +.B mailutil move
 157.101 +is similar to
 157.102 +.B mailutil copy
 157.103 +but in addition will also remove (delete and expunge) the messages from the
 157.104 +old mailbox after copying them to the new mailbox.
 157.105 +.PP
 157.106 +.B mailutil append
 157.107 +and
 157.108 +.B mailutil appenddelete
 157.109 +are similar to
 157.110 +.B mailutil copy
 157.111 +and
 157.112 +.B mailutil move
 157.113 +respectively except that they do not create the destination mailbox.
 157.114 +.PP
 157.115 +.B mailutil prune
 157.116 +prunes the mailbox of messages which match certain criteria, which are
 157.117 +in the form of IMAP2 (RFC 1176) SEARCH arguments.  For example, the
 157.118 +command.
 157.119 +.br
 157.120 +  mailutil prune INBOX "before 1-jan-2004"
 157.121 +.br
 157.122 +will delete and expunge all messages written before January 1, 2004.
 157.123 +.PP
 157.124 +Note that mailutil implements pruning by deleting the matching messages,
 157.125 +and then expunging the mailbox.  Consequently, mailutil will also expunge
 157.126 +any messages which were deleted at the time of the pruning.
 157.127 +.PP
 157.128 +.B mailutil transfer
 157.129 +copies an entire hierarchy of mailboxes from the named source to the
 157.130 +named destination.  Mailboxes are created on the destination as
 157.131 +needed.  Any error in copying messages will cause the transfer to stop.
 157.132 +.PP
 157.133 +Normally, any error in creation will cause the transfer to stop.
 157.134 +However, if
 157.135 +.B -m MODE
 157.136 +or
 157.137 +.B -merge MODE
 157.138 +is specified, a merging transfer is performed.  The
 157.139 +.B MODE
 157.140 +argument indicats the type of merge:
 157.141 +.PP
 157.142 +.B -m[erge] prompt
 157.143 +indicates that the user should be asked for an alternative name to create.
 157.144 +If creating the new name fails, the user will be asked again.
 157.145 +.PP
 157.146 +.B -m[erge] append
 157.147 +indicates that it's alright to copy the messages into an existing mailbox
 157.148 +with that name.  If the mailbox does not exist, the user will be prompted
 157.149 +for an alternative name.
 157.150 +.PP
 157.151 +.B -m[erge] suffix=XXXX
 157.152 +where XXXX is any string, indicates that an alternative name should be
 157.153 +built by appending the given suffix to the name.  It that alternative name
 157.154 +can't be created, then the user will be prompted for an alternative name.
 157.155 +.PP
 157.156 +The source hierarchy consists of all mailboxes which start
 157.157 +with the given source name.  With the exception of a remote system
 157.158 +specification (within "{}" braces), the source name is used as the
 157.159 +name of the destination.  The destination hierarchy is a prefix
 157.160 +applied to any new names being created.  For example,
 157.161 +.br
 157.162 +   mailutil transfer foo bar
 157.163 +.br
 157.164 +will copy all mailboxes with names beginning with "foo" to names
 157.165 +beginning with "bar" (hence "foobar" will be copied to "barfoobar").
 157.166 +Similarly,
 157.167 +.br
 157.168 +   mailutil transfer "{imap.foo.com}" "{imap.bar.com}old/"
 157.169 +.br
 157.170 +will copy all mailboxes from the imap.foo.com IMAP server to
 157.171 +equivalent names starting with "old/" on the imap.bar.com IMAP server.
 157.172 +.SH FLAGS
 157.173 +The
 157.174 +.B -d
 157.175 +or
 157.176 +.B -debug
 157.177 +flag prints full debugging telemetry including protocol operations.
 157.178 +.PP
 157.179 +The
 157.180 +.B -v
 157.181 +or
 157.182 +.B -verbose
 157.183 +flag prints verbose (non-error) telemetry.
 157.184 +.PP
 157.185 +The
 157.186 +.B -u USERID
 157.187 +or
 157.188 +.B -user USERID
 157.189 +switch attempts to become the indicated user.  This is for the benefit of
 157.190 +system administrators who want to do mailutil operations on a userid that
 157.191 +does not normally have shell access.
 157.192 +.PP
 157.193 +The
 157.194 +.B -rw
 157.195 +or
 157.196 +.B -rwcopy
 157.197 +flag causes the source mailbox to be open in readwrite mode rather than
 157.198 +readonly mode.  Normally, mailutil tries to use readonly mode to avoid
 157.199 +altering any flags in the source mailbox, but some mailbox types, e.g.
 157.200 +POP3, can't be open in readonly mode.
 157.201 +.PP
 157.202 +The
 157.203 +.B -kw
 157.204 +or
 157.205 +.B -kwcopy
 157.206 +flag causes the keywords of the source mailbox to be created in the
 157.207 +destination mailbox.  Normally, mailutil does not create keywords in
 157.208 +the destination mailbox so only those keywords that are already defined
 157.209 +in the destination mailbox will be preserved.  Note that some IMAP servers
 157.210 +may automatically create keywords, so this flag may not be necessary.
 157.211 +.PP
 157.212 +The
 157.213 +.B -ig
 157.214 +or
 157.215 +.B -ignore
 157.216 +flag causes the keywords of the source mailbox to be ignored completely
 157.217 +and no attempt is made to copy them to the destination mailbox.
 157.218 +.PP
 157.219 +The
 157.220 +.B -ig[nore]
 157.221 +and
 157.222 +.B -kw[copy]
 157.223 +flags are mutually exclusive.
 157.224 +.SH ARGUMENTS
 157.225 +The arguments are standard c-client mailbox names.  A
 157.226 +variety of mailbox name formats and types of mailboxes are supported
 157.227 +by c-client; examples of the most common forms of names are:
 157.228 +.PP
 157.229 +.I
 157.230 +.IP Name 15
 157.231 +.I Meaning
 157.232 +.IP INBOX
 157.233 +primary incoming mail folder on the local system
 157.234 +.IP archive/tx-project
 157.235 +mail folder named "tx-project" in "archive" subdirectory of local
 157.236 +filesystem home directory
 157.237 +.IP {imapserver.foo.com}INBOX
 157.238 +primary incoming mail folder on IMAP server system
 157.239 +"imapserver.foo.com"
 157.240 +.IP {imapserver.foo.com}archive/tx-project
 157.241 +mail folder named "tx-project" in "archive" subdirectory on IMAP
 157.242 +server system "imapserver.foo.com"
 157.243 +.IP #news.comp.mail.misc
 157.244 +newsgroup "comp.mail.misc" on local filesystem
 157.245 +.IP {newserver.foo.com/nntp}comp.mail.misc
 157.246 +newsgroup "comp.mail.misc" on NNTP server system "newserver.foo.com"
 157.247 +.IP {popserver.foo.com/pop3}
 157.248 +mail folder on POP3 server system "popserver.foo.com"
 157.249 +.LP
 157.250 +See your system manager for more information about the types of
 157.251 +mailboxes which are available on your system.
 157.252 +.SH RESTRICTIONS
 157.253 +You must surround a
 157.254 +.I {host}mailbox
 157.255 +argument with quotation marks if you run
 157.256 +.B mailutil
 157.257 +from
 157.258 +.IR csh (1)
 157.259 +or another shell for which braces have special meaning.
 157.260 +.PP
 157.261 +You must surround a
 157.262 +.I #driver.format/mailbox
 157.263 +argument with quotation marks if you run
 157.264 +.B mailutil
 157.265 +from a shell in which "#" is the comment character.
 157.266 +.SH AUTHOR
 157.267 +Mark Crispin, MRC@Washington.EDU
   158.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   158.2 +++ b/src/mailutil/mailutil.c	Mon Sep 14 15:17:45 2009 +0900
   158.3 @@ -0,0 +1,942 @@
   158.4 +/* ========================================================================
   158.5 + * Copyright 1988-2008 University of Washington
   158.6 + *
   158.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   158.8 + * you may not use this file except in compliance with the License.
   158.9 + * You may obtain a copy of the License at
  158.10 + *
  158.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  158.12 + *
  158.13 + * 
  158.14 + * ========================================================================
  158.15 + */
  158.16 +
  158.17 +/*
  158.18 + * Program:	Mail utility
  158.19 + *
  158.20 + * Author:	Mark Crispin
  158.21 + *		UW Technology
  158.22 + *		University of Washington
  158.23 + *		Seattle, WA  98195
  158.24 + *		Internet: MRC@Washington.EDU
  158.25 + *
  158.26 + * Date:	2 February 1994
  158.27 + * Last Edited:	19 February 2008
  158.28 + */
  158.29 +
  158.30 +
  158.31 +#include <stdio.h>
  158.32 +#include <errno.h>
  158.33 +extern int errno;		/* just in case */
  158.34 +#include "c-client.h"
  158.35 +#ifdef SYSCONFIG		/* defined in env_unix.h */
  158.36 +#include <pwd.h>
  158.37 +#endif
  158.38 +
  158.39 +/* Globals */
  158.40 +
  158.41 +char *version = "13";		/* edit number */
  158.42 +int debugp = NIL;		/* flag saying debug */
  158.43 +int verbosep = NIL;		/* flag saying verbose */
  158.44 +int rwcopyp = NIL;		/* flag saying readwrite copy (for POP) */
  158.45 +int kwcopyp = NIL;		/* flag saying keyword copy */
  158.46 +int ignorep = NIL;		/* flag saying ignore keywords */
  158.47 +int critical = NIL;		/* flag saying in critical code */
  158.48 +int trycreate = NIL;		/* [TRYCREATE] seen */
  158.49 +char *suffix = NIL;		/* suffer merge mode suffix text */
  158.50 +int ddelim = -1;		/* destination delimiter */
  158.51 +FILE *f = NIL;
  158.52 +
  158.53 +/* Usage strings */
  158.54 +
  158.55 +char *usage2 = "usage: %s %s\n\n%s\n";
  158.56 +char *usage3 = "usage: %s %s %s\n\n%s\n";
  158.57 +char *usgchk = "check [MAILBOX]";
  158.58 +char *usgcre = "create MAILBOX";
  158.59 +char *usgdel = "delete MAILBOX";
  158.60 +char *usgren = "rename SOURCE DESTINATION";
  158.61 +char *usgcpymov = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";
  158.62 +char *usgappdel = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";
  158.63 +char *usgprn = "prune mailbox SEARCH_CRITERIA";
  158.64 +char *usgxfr = "transfer [-rw[copy]] [-kw[copy]] [-ig[nore]] [-m[erge] m] SOURCE DEST";
  158.65 +#ifdef SYSCONFIG
  158.66 +char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]] [-u[ser] userid] [--]";
  158.67 +#else
  158.68 +char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]]";
  158.69 +#endif
  158.70 +
  158.71 +/* Merge modes */
  158.72 +
  158.73 +#define mPROMPT 1
  158.74 +#define mAPPEND 2
  158.75 +#define mSUFFIX 3
  158.76 +
  158.77 +
  158.78 +/* Function prototypes */
  158.79 +
  158.80 +void ms_init (STRING *s,void *data,unsigned long size);
  158.81 +char ms_next (STRING *s);
  158.82 +void ms_setpos (STRING *s,unsigned long i);
  158.83 +int main (int argc,char *argv[]);
  158.84 +SEARCHPGM *prune_criteria (char *criteria);
  158.85 +int prune_criteria_number (unsigned long *number,char **r);
  158.86 +int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
  158.87 +	     int mode);
  158.88 +long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date,
  158.89 +		STRING **message);
  158.90 +
  158.91 +
  158.92 +/* Append package */
  158.93 +
  158.94 +typedef struct append_package {
  158.95 +  MAILSTREAM *stream;		/* source stream */
  158.96 +  unsigned long msgno;		/* current message number */
  158.97 +  unsigned long msgmax;		/* maximum message number */
  158.98 +  char *flags;			/* current flags */
  158.99 +  char *date;			/* message internal date */
 158.100 +  STRING *message;		/* stringstruct of message */
 158.101 +} APPENDPACKAGE;
 158.102 +
 158.103 +
 158.104 +/* Message string driver for message stringstructs */
 158.105 +
 158.106 +STRINGDRIVER mstring = {
 158.107 +  ms_init,			/* initialize string structure */
 158.108 +  ms_next,			/* get next byte in string structure */
 158.109 +  ms_setpos			/* set position in string structure */
 158.110 +};
 158.111 +
 158.112 +/* Initialize file string structure for file stringstruct
 158.113 + * Accepts: string structure
 158.114 + *	    pointer to message data structure
 158.115 + *	    size of string
 158.116 + */
 158.117 +
 158.118 +void ms_init (STRING *s,void *data,unsigned long size)
 158.119 +{
 158.120 +  APPENDPACKAGE *md = (APPENDPACKAGE *) data;
 158.121 +  s->data = data;		/* note stream/msgno and header length */
 158.122 +  mail_fetch_header (md->stream,md->msgno,NIL,NIL,&s->data1,
 158.123 +		     FT_PREFETCHTEXT|FT_PEEK);
 158.124 +#if 0
 158.125 +  s->size = size;		/* message size */
 158.126 +#else	/* This kludge is necessary because of broken IMAP servers (sigh!) */
 158.127 +  mail_fetch_text (md->stream,md->msgno,NIL,&s->size,FT_PEEK);
 158.128 +  s->size += s->data1;		/* header + body size */
 158.129 +#endif
 158.130 +  SETPOS (s,0);
 158.131 +}
 158.132 +
 158.133 +
 158.134 +/* Get next character from file stringstruct
 158.135 + * Accepts: string structure
 158.136 + * Returns: character, string structure chunk refreshed
 158.137 + */
 158.138 +
 158.139 +char ms_next (STRING *s)
 158.140 +{
 158.141 +  char c = *s->curpos++;	/* get next byte */
 158.142 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
 158.143 +  return c;			/* return the byte */
 158.144 +}
 158.145 +
 158.146 +
 158.147 +/* Set string pointer position for file stringstruct
 158.148 + * Accepts: string structure
 158.149 + *	    new position
 158.150 + */
 158.151 +
 158.152 +void ms_setpos (STRING *s,unsigned long i)
 158.153 +{
 158.154 +  APPENDPACKAGE *md = (APPENDPACKAGE *) s->data;
 158.155 +  if (i < s->data1) {		/* want header? */
 158.156 +    s->chunk = mail_fetch_header (md->stream,md->msgno,NIL,NIL,NIL,FT_PEEK);
 158.157 +    s->chunksize = s->data1;	/* header length */
 158.158 +    s->offset = 0;		/* offset is start of message */
 158.159 +  }
 158.160 +  else if (i < s->size) {	/* want body */
 158.161 +    s->chunk = mail_fetch_text (md->stream,md->msgno,NIL,NIL,FT_PEEK);
 158.162 +    s->chunksize = s->size - s->data1;
 158.163 +    s->offset = s->data1;	/* offset is end of header */
 158.164 +  }
 158.165 +  else {			/* off end of message */
 158.166 +    s->chunk = NIL;		/* make sure that we crack on this then */
 158.167 +    s->chunksize = 1;		/* make sure SNX cracks the right way... */
 158.168 +    s->offset = i;
 158.169 +  }
 158.170 +				/* initial position and size */
 158.171 +  s->curpos = s->chunk + (i -= s->offset);
 158.172 +  s->cursize = s->chunksize - i;
 158.173 +}
 158.174 +
 158.175 +/* Main program */
 158.176 +
 158.177 +int main (int argc,char *argv[])
 158.178 +{
 158.179 +  MAILSTREAM *source = NIL;
 158.180 +  MAILSTREAM *dest = NIL;
 158.181 +  SEARCHPGM *criteria;
 158.182 +  char c,*s,*dp,*t,*t1,tmp[MAILTMPLEN],mbx[MAILTMPLEN];
 158.183 +  unsigned long m,len,curlen,start,last;
 158.184 +  int i;
 158.185 +  int merge = NIL;
 158.186 +  int retcode = 1;
 158.187 +  int moreswitchp = T;
 158.188 +  char *cmd = NIL;
 158.189 +  char *src = NIL;
 158.190 +  char *dst = NIL;
 158.191 +  char *pgm = argc ? argv[0] : "mailutil";
 158.192 +#include "linkage.c"
 158.193 +  for (i = 1; i < argc; i++) {
 158.194 +    s = argv[i];		/* pick up argument */
 158.195 +				/* parse switches */
 158.196 +    if (moreswitchp && (*s == '-')) {
 158.197 +      if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T;
 158.198 +      else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T;
 158.199 +      else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T;
 158.200 +      else if (!strcmp (s,"-kwcopy") || !strcmp (s,"-kw")) kwcopyp = T;
 158.201 +      else if (!strcmp (s,"-ignore") || !strcmp (s,"-ig")) ignorep = T;
 158.202 +      else if ((!strcmp (s,"-merge") || !strcmp (s,"-m")) && (++i < argc)) {
 158.203 +	if (!strcmp (s = argv[i],"prompt")) merge = mPROMPT;
 158.204 +	else if (!strcmp (s,"append")) merge = mAPPEND;
 158.205 +	else if (!strncmp (s,"suffix=",7) && s[7]) {
 158.206 +	  merge = mSUFFIX;
 158.207 +	  suffix = cpystr (s+7);
 158.208 +	}
 158.209 +	else {
 158.210 +	  printf ("unknown merge option: %s\n",s);
 158.211 +	  exit (retcode);
 158.212 +	}
 158.213 +      }
 158.214 +
 158.215 +#ifdef SYSCONFIG
 158.216 +      else if ((!strcmp (s,"-user") || !strcmp (s,"-u")) && (++i < argc)) {
 158.217 +	struct passwd *pw = getpwnam (s = argv[i]);
 158.218 +	if (!pw) {
 158.219 +	  printf ("unknown user id: %s\n",argv[i]);
 158.220 +	  exit (retcode);
 158.221 +	}
 158.222 +	else if (setuid (pw->pw_uid)) {
 158.223 +	  perror ("unable to change user id");
 158.224 +	  exit (retcode);
 158.225 +	}
 158.226 +      }
 158.227 +#endif
 158.228 +				/* -- means no more switches, so mailbox
 158.229 +				   name can start with "-" */
 158.230 +      else if ((s[1] == '-') && !s[2]) moreswitchp = NIL;
 158.231 +      else {
 158.232 +	printf ("unknown switch: %s\n",s);
 158.233 +	exit (retcode);
 158.234 +      }
 158.235 +    }
 158.236 +    else if (!cmd) cmd = s;	/* first non-switch is command */
 158.237 +    else if (!src) src = s;	/* second non-switch is source */
 158.238 +    else if (!dst) dst = s;	/* third non-switch is destination */
 158.239 +    else {
 158.240 +      printf ("unknown argument: %s\n",s);
 158.241 +      exit (retcode);
 158.242 +    }
 158.243 +  }
 158.244 +  if (kwcopyp && ignorep) {
 158.245 +    puts ("-kwcopy and -ignore are mutually exclusive");
 158.246 +    exit (retcode);
 158.247 +  }
 158.248 +  if (!cmd) cmd = "";		/* prevent SEGV */
 158.249 +
 158.250 +  if (!strcmp (cmd,"check")) {	/* check for new messages */
 158.251 +    if (!src) src = "INBOX";
 158.252 +    if (dst || merge || rwcopyp || kwcopyp || ignorep)
 158.253 +      printf (usage2,pgm,usgchk,stdsw);
 158.254 +    else if (mail_status (source = (*src == '{') ?
 158.255 +			  mail_open (NIL,src,OP_HALFOPEN |
 158.256 +				     (debugp ? OP_DEBUG : NIL)) : NIL,
 158.257 +			  src,SA_MESSAGES | SA_RECENT | SA_UNSEEN))
 158.258 +      retcode = 0;
 158.259 +  }
 158.260 +  else if (!strcmp (cmd,"create")) {
 158.261 +    if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
 158.262 +      printf (usage2,pgm,usgcre,stdsw);
 158.263 +    else if (mail_create (source = (*src == '{') ?
 158.264 +			  mail_open (NIL,src,OP_HALFOPEN |
 158.265 +				     (debugp ? OP_DEBUG : NIL)) : NIL,src))
 158.266 +      retcode = 0;
 158.267 +  }
 158.268 +  else if (!strcmp (cmd,"delete")) {
 158.269 +    if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
 158.270 +      printf (usage2,pgm,usgdel,stdsw);
 158.271 +    else if (mail_delete (source = (*src == '{') ?
 158.272 +			  mail_open (NIL,src,OP_HALFOPEN |
 158.273 +				     (debugp ? OP_DEBUG : NIL)) : NIL,src))
 158.274 +      retcode = 0;
 158.275 +  }
 158.276 +  else if (!strcmp (cmd,"rename")) {
 158.277 +    if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep)
 158.278 +      printf (usage2,pgm,usgren,stdsw);
 158.279 +    else if (mail_rename (source = (*src == '{') ?
 158.280 +			  mail_open (NIL,src,OP_HALFOPEN |
 158.281 +				     (debugp ? OP_DEBUG : NIL)) : NIL,src,dst))
 158.282 +      retcode = 0;
 158.283 +  }
 158.284 +
 158.285 +  else if ((i = !strcmp (cmd,"move")) || !strcmp (cmd,"copy")) {
 158.286 +    if (!src || !dst || merge) printf (usage3,pgm,cmd,usgcpymov,stdsw);
 158.287 +    else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
 158.288 +				 (debugp ? OP_DEBUG : NIL))) {
 158.289 +      dest = NIL;		/* open destination stream if network */
 158.290 +      if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
 158.291 +					      (debugp ? OP_DEBUG : NIL)))) {
 158.292 +	if (mbxcopy (source,dest,dst,T,i,merge)) retcode = 0;
 158.293 +      }
 158.294 +    }
 158.295 +  }
 158.296 +  else if ((i = !strcmp (cmd,"appenddelete")) || !strcmp (cmd,"append")) {
 158.297 +    if (!src || !dst || merge) printf (usage3,pgm,cmd,usgappdel,stdsw);
 158.298 +    else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
 158.299 +				 (debugp ? OP_DEBUG : NIL))) {
 158.300 +      dest = NIL;		/* open destination stream if network */
 158.301 +      if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
 158.302 +					      (debugp ? OP_DEBUG : NIL)))) {
 158.303 +	if (mbxcopy (source,dest,dst,NIL,i,merge)) retcode = 0;
 158.304 +      }
 158.305 +    }
 158.306 +  }
 158.307 +
 158.308 +  else if (!strcmp (cmd,"prune")) {
 158.309 +    if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep ||
 158.310 +	!(criteria = prune_criteria (dst))) printf (usage2,pgm,usgprn,stdsw);
 158.311 +    else if ((source = mail_open (NIL,src,(debugp ? OP_DEBUG : NIL))) &&
 158.312 +	     mail_search_full (source,NIL,criteria,SE_FREE)) {
 158.313 +      for (m = 1, s = t = NIL, len = start = last = 0; m <= source->nmsgs; m++)
 158.314 +	if (mail_elt (source,m)->searched) {
 158.315 +	  if (s) {		/* continuing a range? */
 158.316 +	    if (m == last + 1) last = m;
 158.317 +	    else {		/* no, end of previous range? */
 158.318 +	      if (last != start) sprintf (t,":%lu,%lu",last,m);
 158.319 +				/* no, just this message */
 158.320 +	      else sprintf (t,",%lu",m);
 158.321 +	      start = last = m;	/* either way, start new range */
 158.322 +				/* running out of space? */
 158.323 +	      if ((len - (curlen = (t += strlen (t)) - s)) < 20) {
 158.324 +		fs_resize ((void **) &s,len += MAILTMPLEN);
 158.325 +		t = s + curlen;	/* relocate current pointer */
 158.326 +	      }
 158.327 +	    }
 158.328 +	  }
 158.329 +	  else {		/* first time, start new buffer */
 158.330 +	    s = (char *) fs_get (len = MAILTMPLEN);
 158.331 +	    sprintf (s,"%lu",start = last = m);
 158.332 +	    t = s + strlen (s);	/* end of buffer */
 158.333 +	  }
 158.334 +	}
 158.335 +				/* finish last range if necessary */
 158.336 +      if (last != start) sprintf (t,":%lu",last);
 158.337 +      if (s) {			/* delete/expunge any matching messages */
 158.338 +	mail_flag (source,s,"\\Deleted",ST_SET);
 158.339 +	m = source->nmsgs;	/* get number of messages before purge */
 158.340 +	mail_expunge (source);
 158.341 +	printf ("%lu message(s) purged\n",m - source->nmsgs);
 158.342 +	fs_give ((void **) &s);	/* flush buffer */
 158.343 +      }
 158.344 +      else puts ("No matching messages, so nothing purged");
 158.345 +      source = mail_close (source);
 158.346 +    }
 158.347 +  }
 158.348 +
 158.349 +  else if (!strcmp (cmd,"transfer")) {
 158.350 +    if (!src || !dst) printf (usage2,pgm,usgxfr,stdsw);
 158.351 +    else if ((*src == '{') &&	/* open source mailbox */
 158.352 +	     !(source = mail_open (NIL,src,OP_HALFOPEN |
 158.353 +				   (debugp ? OP_DEBUG : NIL))));
 158.354 +    else if ((*dst == '{') &&	/* open destination server */
 158.355 +	     !(dest = mail_open (NIL,dst,OP_HALFOPEN |
 158.356 +				 (debugp ? OP_DEBUG : NIL))));
 158.357 +    else if (!(f = tmpfile ())) puts ("can't open temporary file");
 158.358 +    else {
 158.359 +      if (verbosep) puts ("Listing mailboxes...");
 158.360 +      if (dest) strcpy (strchr (strcpy (tmp,dest->mailbox),'}') + 1,
 158.361 +			dp = strchr (dst,'}') + 1);
 158.362 +      else {
 158.363 +	dp = dst;
 158.364 +	tmp[0] = '\0';
 158.365 +      }
 158.366 +      mail_list (dest,tmp,"");
 158.367 +      rewind (f);		/* list all mailboxes matching prefix */
 158.368 +      if (ddelim < 0) {		/* if server failed to give delimiter */
 158.369 +	puts ("warning: unable to get destination hierarchy delimiter!");
 158.370 +	ddelim = 0;		/* default to none */
 158.371 +      }
 158.372 +      if (source) strcpy (strchr (strcpy (tmp,source->mailbox),'}') + 1,
 158.373 +			  strchr (src,'}') + 1);
 158.374 +      else strcpy (tmp,src);
 158.375 +      mail_list (source,tmp,"*");
 158.376 +      rewind (f);
 158.377 +				/* read back mailbox names */
 158.378 +      for (retcode = 0; !retcode && (fgets (tmp,MAILTMPLEN-1,f)); ) {
 158.379 +	if (t = strchr (tmp+1,'\n')) *t = '\0';
 158.380 +	for (t = mbx,t1 = dest ? dest->mailbox : "",c = NIL; (c != '}') && *t1;
 158.381 +	     *t++ = c= *t1++);
 158.382 +	for (t1 = dp; *t1; *t++ = *t1++);
 158.383 +				/* point to name without delim or netspec */
 158.384 +	t1 = source ? (strchr (tmp+1,'}') + 1) : tmp + 1;
 158.385 +				/* src and mbx have different delimiters? */
 158.386 +	if (ddelim && (ddelim != tmp[0]))
 158.387 +	  while (c = *t1++) {	/* swap delimiters then */
 158.388 +	    if (c == ddelim) c = tmp[0] ? tmp[0] : 'x';
 158.389 +	    else if (c == tmp[0]) c = ddelim;
 158.390 +	    *t++ = c;
 158.391 +	  }
 158.392 +				/* easy case */
 158.393 +	else while (*t1) *t++ = *t1++;
 158.394 +	*t++ = '\0';
 158.395 +	if (verbosep) {
 158.396 +	  printf ("Copying %s\n  => %s\n",tmp+1,mbx);
 158.397 +	  fflush (stdout);
 158.398 +	}
 158.399 +	if (source = mail_open (source,tmp+1,(debugp ? OP_DEBUG : NIL) | 
 158.400 +				(rwcopyp ? NIL : OP_READONLY))) {
 158.401 +	  if (!mbxcopy (source,dest,mbx,T,NIL,merge)) retcode = 1;
 158.402 +	  if (source->dtb->flags & DR_LOCAL) source = mail_close (source);
 158.403 +	}
 158.404 +	else printf ("can't open source mailbox %s\n",tmp+1);
 158.405 +      }
 158.406 +    }
 158.407 +  }
 158.408 +
 158.409 +  else {
 158.410 +    printf ("%s version %s.%s\n\n",pgm,CCLIENTVERSION,version);
 158.411 +    printf (usage2,pgm,"command [switches] arguments",stdsw);
 158.412 +    printf ("\nCommands:\n %s\n",usgchk);
 158.413 +    puts   ("   ;; report number of messages and new messages");
 158.414 +    printf (" %s\n",usgcre);
 158.415 +    puts   ("   ;; create new mailbox");
 158.416 +    printf (" %s\n",usgdel);
 158.417 +    puts   ("   ;; delete existing mailbox");
 158.418 +    printf (" %s\n",usgren);
 158.419 +    puts   ("   ;; rename mailbox to a new name");
 158.420 +    printf (" copy %s\n",usgcpymov);
 158.421 +    printf (" move %s\n",usgcpymov);
 158.422 +    puts   ("   ;; create new mailbox and copy/move messages");
 158.423 +    printf (" append %s\n",usgappdel);
 158.424 +    printf (" appenddelete %s\n",usgappdel);
 158.425 +    puts   ("   ;; copy/move messages to existing mailbox");
 158.426 +    printf (" %s\n",usgprn);
 158.427 +    puts   ("   ;; prune mailbox of messages matching criteria");
 158.428 +    printf (" %s\n",usgxfr);
 158.429 +    puts   ("   ;; copy source hierarchy to destination");
 158.430 +    puts   ("   ;;  -merge modes are prompt, append, or suffix=xxxx");
 158.431 +  }
 158.432 +				/* close streams */
 158.433 +  if (source) mail_close (source);
 158.434 +  if (dest) mail_close (dest);
 158.435 +  exit (retcode);
 158.436 +  return retcode;		/* stupid compilers */
 158.437 +}
 158.438 +
 158.439 +/* Pruning criteria, somewhat extended from mail_criteria()
 158.440 + * Accepts: criteria
 158.441 + * Returns: search program if parse successful, else NIL
 158.442 + */
 158.443 +
 158.444 +SEARCHPGM *prune_criteria (char *criteria)
 158.445 +{
 158.446 +  SEARCHPGM *pgm = NIL;
 158.447 +  char *criterion,*r,tmp[MAILTMPLEN];
 158.448 +  int f;
 158.449 +  if (criteria) {		/* only if criteria defined */
 158.450 +				/* make writeable copy of criteria */
 158.451 +    criteria = cpystr (criteria);
 158.452 +				/* for each criterion */
 158.453 +    for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r);
 158.454 +	 criterion; (criterion = strtok_r (NIL," ",&r))) {
 158.455 +      f = NIL;			/* init then scan the criterion */
 158.456 +      switch (*ucase (criterion)) {
 158.457 +      case 'A':			/* possible ALL, ANSWERED */
 158.458 +	if (!strcmp (criterion+1,"LL")) f = T;
 158.459 +	else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T;
 158.460 +	break;
 158.461 +      case 'B':			/* possible BCC, BEFORE, BODY */
 158.462 +	if (!strcmp (criterion+1,"CC"))
 158.463 +	  f = mail_criteria_string (&pgm->bcc,&r);
 158.464 +	else if (!strcmp (criterion+1,"EFORE"))
 158.465 +	  f = mail_criteria_date (&pgm->before,&r);
 158.466 +	else if (!strcmp (criterion+1,"ODY"))
 158.467 +	  f = mail_criteria_string (&pgm->body,&r);
 158.468 +	break;
 158.469 +      case 'C':			/* possible CC */
 158.470 +	if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r);
 158.471 +	break;
 158.472 +      case 'D':			/* possible DELETED, DRAFT */
 158.473 +	if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T;
 158.474 +	else if (!strcmp (criterion+1,"RAFT")) f = pgm->draft = T;
 158.475 +	break;
 158.476 +      case 'F':			/* possible FLAGGED, FROM */
 158.477 +	if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T;
 158.478 +	else if (!strcmp (criterion+1,"ROM"))
 158.479 +	  f = mail_criteria_string (&pgm->from,&r);
 158.480 +	break;
 158.481 +      case 'K':			/* possible KEYWORD */
 158.482 +	if (!strcmp (criterion+1,"EYWORD"))
 158.483 +	  f = mail_criteria_string (&pgm->keyword,&r);
 158.484 +	break;
 158.485 +      case 'L':			/* possible LARGER */
 158.486 +	if (!strcmp (criterion+1,"ARGER"))
 158.487 +	  f = prune_criteria_number (&pgm->larger,&r);
 158.488 +
 158.489 +      case 'N':			/* possible NEW */
 158.490 +	if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T;
 158.491 +	break;
 158.492 +      case 'O':			/* possible OLD, ON */
 158.493 +	if (!strcmp (criterion+1,"LD")) f = pgm->old = T;
 158.494 +	else if (!strcmp (criterion+1,"N"))
 158.495 +	  f = mail_criteria_date (&pgm->on,&r);
 158.496 +	break;
 158.497 +      case 'R':			/* possible RECENT */
 158.498 +	if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T;
 158.499 +	break;
 158.500 +      case 'S':			/* possible SEEN, SENT*, SINCE, SMALLER,
 158.501 +				   SUBJECT */
 158.502 +	if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T;
 158.503 +	else if (!strncmp (criterion+1,"ENT",3)) {
 158.504 +	  if (!strcmp (criterion+4,"BEFORE"))
 158.505 +	    f = mail_criteria_date (&pgm->sentbefore,&r);
 158.506 +	  else if (!strcmp (criterion+4,"ON"))
 158.507 +	    f = mail_criteria_date (&pgm->senton,&r);
 158.508 +	  else if (!strcmp (criterion+4,"SINCE"))
 158.509 +	    f = mail_criteria_date (&pgm->sentsince,&r);
 158.510 +	}
 158.511 +	else if (!strcmp (criterion+1,"INCE"))
 158.512 +	  f = mail_criteria_date (&pgm->since,&r);
 158.513 +	else if (!strcmp (criterion+1,"MALLER"))
 158.514 +	  f = prune_criteria_number (&pgm->smaller,&r);
 158.515 +	else if (!strcmp (criterion+1,"UBJECT"))
 158.516 +	  f = mail_criteria_string (&pgm->subject,&r);
 158.517 +	break;
 158.518 +      case 'T':			/* possible TEXT, TO */
 158.519 +	if (!strcmp (criterion+1,"EXT"))
 158.520 +	  f = mail_criteria_string (&pgm->text,&r);
 158.521 +	else if (!strcmp (criterion+1,"O"))
 158.522 +	  f = mail_criteria_string (&pgm->to,&r);
 158.523 +	break;
 158.524 +      case 'U':			/* possible UN* */
 158.525 +	if (criterion[1] == 'N') {
 158.526 +	  if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T;
 158.527 +	  else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T;
 158.528 +	  else if (!strcmp (criterion+2,"DRAFT")) f = pgm->undraft = T;
 158.529 +	  else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T;
 158.530 +	  else if (!strcmp (criterion+2,"KEYWORD"))
 158.531 +	    f = mail_criteria_string (&pgm->unkeyword,&r);
 158.532 +	  else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T;
 158.533 +	}
 158.534 +	break;
 158.535 +      default:			/* we will barf below */
 158.536 +	break;
 158.537 +      }
 158.538 +
 158.539 +      if (!f) {			/* if can't identify criterion */
 158.540 +	sprintf (tmp,"Unknown search criterion: %.30s",criterion);
 158.541 +	MM_LOG (tmp,ERROR);
 158.542 +	mail_free_searchpgm (&pgm);
 158.543 +	break;
 158.544 +      }
 158.545 +    }
 158.546 +				/* no longer need copy of criteria */
 158.547 +    fs_give ((void **) &criteria);
 158.548 +  }
 158.549 +  return pgm;
 158.550 +}
 158.551 +
 158.552 +
 158.553 +/* Parse a number
 158.554 + * Accepts: pointer to integer to return
 158.555 + *	    pointer to strtok state
 158.556 + * Returns: T if successful, else NIL
 158.557 + */
 158.558 +
 158.559 +int prune_criteria_number (unsigned long *number,char **r)
 158.560 +{
 158.561 +  char *t;
 158.562 +  STRINGLIST *s = NIL;
 158.563 +				/* parse the date and return fn if OK */
 158.564 +  int ret = (mail_criteria_string (&s,r) &&
 158.565 +	     (*number = strtoul ((char *) s->text.data,&t,10)) && !*t) ?
 158.566 +	       T : NIL;
 158.567 +  if (s) mail_free_stringlist (&s);
 158.568 +  return ret;
 158.569 +}
 158.570 +
 158.571 +/* Copy mailbox
 158.572 + * Accepts: stream open on source
 158.573 + *	    halfopen stream for destination or NIL
 158.574 + *	    destination mailbox name
 158.575 + *	    non-zero to create destination mailbox
 158.576 + *	    non-zero to delete messages from source after copying
 158.577 + *	    merge mode
 158.578 + * Returns: T if success, NIL if error
 158.579 + */
 158.580 +
 158.581 +int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
 158.582 +	     int mode)
 158.583 +{
 158.584 +  char *s,tmp[MAILTMPLEN];
 158.585 +  APPENDPACKAGE ap;
 158.586 +  STRING st;
 158.587 +  char *ndst = NIL;
 158.588 +  int ret = NIL;
 158.589 +  trycreate = NIL;		/* no TRYCREATE yet */
 158.590 +  if (create) while (!mail_create (dest,dst) && (mode != mAPPEND)) {
 158.591 +    switch (mode) {
 158.592 +    case mPROMPT:		/* prompt user for new name */
 158.593 +      tmp[0] = '\0';
 158.594 +      while (!tmp[0]) {		/* read name */
 158.595 +	fputs ("alternative name: ",stdout);
 158.596 +	fflush (stdout);
 158.597 +	fgets (tmp,MAILTMPLEN-1,stdin);
 158.598 +	if (s = strchr (tmp,'\n')) *s = '\0';
 158.599 +      }
 158.600 +      if (ndst) fs_give ((void **) &ndst);
 158.601 +      ndst = cpystr (tmp);
 158.602 +      break;
 158.603 +    case mSUFFIX:		/* try again with new suffix */
 158.604 +      if (ndst) fs_give ((void **) &ndst);
 158.605 +      sprintf (ndst = (char *) fs_get (strlen (dst) + strlen (suffix) + 1),
 158.606 +	       "%s%s",dst,suffix);
 158.607 +      printf ("retry to create %s\n",ndst);
 158.608 +      mode = mPROMPT;		/* switch to prompt mode if name fails */
 158.609 +      break;
 158.610 +    case NIL:			/* not merging */
 158.611 +      return NIL;
 158.612 +    }
 158.613 +    if (ndst) dst = ndst;	/* if alternative name given, use it */
 158.614 +  }
 158.615 +
 158.616 +  if (kwcopyp) {
 158.617 +    int i;
 158.618 +    size_t len;
 158.619 +    char *dummymsg = "Date: Thu, 18 May 2006 00:00 -0700\r\nFrom: dummy@example.com\r\nSubject: dummy\r\n\r\ndummy\r\n";
 158.620 +    for (i = 0,len = 0; i < NUSERFLAGS; ++i)
 158.621 +      if (source->user_flags[i]) len += strlen (source->user_flags[i]) + 1;
 158.622 +    if (len) {			/* easy if no user flags to copy... */
 158.623 +      char *t;
 158.624 +      char *tail = "\\Deleted)";
 158.625 +      char *flags = (char *) fs_get (1 + len + strlen (tail) + 1);
 158.626 +      s = flags; *s++ = '(';
 158.627 +      for (i = 0; i < NUSERFLAGS; ++i) if (t = source->user_flags[i]) {
 158.628 +	while (*t) *s++ = *t++;
 158.629 +	*s++ = ' ';
 158.630 +      }
 158.631 +      strcpy (s,tail);		/* terminate flags list */
 158.632 +      if ((dst[0] == '#') && ((dst[1] == 'D') || (dst[1] == 'd')) &&
 158.633 +	  ((dst[2] == 'R') || (dst[2] == 'r')) &&
 158.634 +	  ((dst[3] == 'I') || (dst[3] == 'i')) &&
 158.635 +	  ((dst[4] == 'V') || (dst[4] == 'v')) &&
 158.636 +	  ((dst[5] == 'E') || (dst[5] == 'e')) &&
 158.637 +	  ((dst[6] == 'R') || (dst[6] == 'r')) && (dst[7] == '.') &&
 158.638 +	  (t = strchr (dst+8,'/'))) ++t;
 158.639 +      else t = dst;
 158.640 +      INIT (&st,mail_string,dummymsg,strlen (dummymsg));
 158.641 +      if (!(mail_append (dest,dst,&st) &&
 158.642 +	    (dest = mail_open (dest,t,debugp ? OP_DEBUG : NIL)))) {
 158.643 +	fs_give ((void **) &flags);
 158.644 +	return NIL;
 158.645 +      }
 158.646 +      mail_setflag (dest,"*",flags);
 158.647 +      mail_expunge (dest);
 158.648 +      fs_give ((void **) &flags);
 158.649 +    }
 158.650 +  }
 158.651 +
 158.652 +  if (source->nmsgs) {		/* non-empty source */
 158.653 +    if (verbosep) printf ("%s [%lu message(s)] => %s\n",
 158.654 +			      source->mailbox,source->nmsgs,dst);
 158.655 +    ap.stream = source;		/* prepare append package */
 158.656 +    ap.msgno = 0;
 158.657 +    ap.msgmax = source->nmsgs;
 158.658 +    ap.flags = ap.date = NIL;
 158.659 +    ap.message = &st;
 158.660 +				/* make sure we have all messages */
 158.661 +    sprintf (tmp,"1:%lu",ap.msgmax);
 158.662 +    mail_fetchfast (source,tmp);
 158.663 +    if (mail_append_multiple (dest,dst,mm_append,(void *) &ap)) {
 158.664 +      --ap.msgno;		/* make sure user knows it won */
 158.665 +      if (verbosep) printf ("[Ok %lu messages(s)]\n",ap.msgno);
 158.666 +      if (del && ap.msgno) {	/* delete source messages */
 158.667 +	sprintf (tmp,"1:%lu",ap.msgno);
 158.668 +	mail_flag (source,tmp,"\\Deleted",ST_SET);
 158.669 +				/* flush moved messages */
 158.670 +	mail_expunge (source);
 158.671 +      }
 158.672 +      ret = T;
 158.673 +    }
 158.674 +    else if ((mode == mAPPEND) && trycreate)
 158.675 +      ret = mbxcopy (source,dest,dst,create,del,mPROMPT);
 158.676 +    else if (verbosep) puts ("[Failed]");
 158.677 +  }
 158.678 +  else {			/* empty source */
 158.679 +    if (verbosep) printf ("%s [empty] => %s\n",source->mailbox,dst);
 158.680 +    ret = T;
 158.681 +  }
 158.682 +  if (ndst) fs_give ((void **) &ndst);
 158.683 +  return ret;
 158.684 +}
 158.685 +
 158.686 +/* Append callback
 158.687 + * Accepts: mail stream
 158.688 + *	    append package
 158.689 + *	    pointer to return flags
 158.690 + *	    pointer to return date
 158.691 + *	    pointer to return message stringstruct
 158.692 + * Returns: T on success
 158.693 + */
 158.694 +
 158.695 +long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date,
 158.696 +		STRING **message)
 158.697 +{
 158.698 +  char *t,*t1,tmp[MAILTMPLEN];
 158.699 +  unsigned long u;
 158.700 +  MESSAGECACHE *elt;
 158.701 +  APPENDPACKAGE *ap = (APPENDPACKAGE *) data;
 158.702 +  *flags = *date = NIL;		/* assume no flags or date */
 158.703 +  if (ap->flags) fs_give ((void **) &ap->flags);
 158.704 +  if (ap->date) fs_give ((void **) &ap->date);
 158.705 +  mail_gc (ap->stream,GC_TEXTS);
 158.706 +  if (++ap->msgno <= ap->msgmax) {
 158.707 +				/* initialize flag string */
 158.708 +    memset (t = tmp,0,MAILTMPLEN);
 158.709 +				/* output system flags */
 158.710 +    if ((elt = mail_elt (ap->stream,ap->msgno))->seen) strcat (t," \\Seen");
 158.711 +    if (elt->deleted) strcat (t," \\Deleted");
 158.712 +    if (elt->flagged) strcat (t," \\Flagged");
 158.713 +    if (elt->answered) strcat (t," \\Answered");
 158.714 +    if (elt->draft) strcat (t," \\Draft");
 158.715 +				/* any user flags? */
 158.716 +    if (!ignorep && (u = elt->user_flags)) do
 158.717 +      if ((t1 = ap->stream->user_flags[find_rightmost_bit (&u)]) &&
 158.718 +	  (MAILTMPLEN - ((t += strlen (t)) - tmp)) > (long) (2 + strlen (t1))){
 158.719 +	*t++ = ' ';		/* space delimiter */
 158.720 +	strcpy (t,t1);		/* copy the user flag */
 158.721 +      }
 158.722 +    while (u);			/* until no more user flags */
 158.723 +    *flags = ap->flags = cpystr (tmp + 1);
 158.724 +    *date = ap->date = cpystr (mail_date (tmp,elt));
 158.725 +    *message = ap->message;	/* message stringstruct */
 158.726 +    INIT (ap->message,mstring,(void *) ap,elt->rfc822_size);
 158.727 +  }
 158.728 +  else *message = NIL;		/* all done */
 158.729 +  return LONGT;
 158.730 +}
 158.731 +
 158.732 +/* Co-routines from MAIL library */
 158.733 +
 158.734 +
 158.735 +/* Message matches a search
 158.736 + * Accepts: MAIL stream
 158.737 + *	    message number
 158.738 + */
 158.739 +
 158.740 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
 158.741 +{
 158.742 +				/* dummy routine */
 158.743 +}
 158.744 +
 158.745 +
 158.746 +/* Message exists (i.e. there are that many messages in the mailbox)
 158.747 + * Accepts: MAIL stream
 158.748 + *	    message number
 158.749 + */
 158.750 +
 158.751 +void mm_exists (MAILSTREAM *stream,unsigned long number)
 158.752 +{
 158.753 +				/* dummy routine */
 158.754 +}
 158.755 +
 158.756 +
 158.757 +/* Message expunged
 158.758 + * Accepts: MAIL stream
 158.759 + *	    message number
 158.760 + */
 158.761 +
 158.762 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
 158.763 +{
 158.764 +				/* dummy routine */
 158.765 +}
 158.766 +
 158.767 +
 158.768 +/* Message flags update seen
 158.769 + * Accepts: MAIL stream
 158.770 + *	    message number
 158.771 + */
 158.772 +
 158.773 +void mm_flags (MAILSTREAM *stream,unsigned long number)
 158.774 +{
 158.775 +				/* dummy routine */
 158.776 +}
 158.777 +
 158.778 +/* Mailbox found
 158.779 + * Accepts: MAIL stream
 158.780 + *	    hierarchy delimiter
 158.781 + *	    mailbox name
 158.782 + *	    mailbox attributes
 158.783 + */
 158.784 +
 158.785 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 158.786 +{
 158.787 +				/* note destination delimiter */
 158.788 +  if (ddelim < 0) ddelim = delimiter;
 158.789 +				/* if got a selectable name */
 158.790 +  else if (!(attributes & LATT_NOSELECT) && *name)
 158.791 +    fprintf (f,"%c%s\n",delimiter,name);
 158.792 +}
 158.793 +
 158.794 +
 158.795 +/* Subscribe mailbox found
 158.796 + * Accepts: MAIL stream
 158.797 + *	    hierarchy delimiter
 158.798 + *	    mailbox name
 158.799 + *	    mailbox attributes
 158.800 + */
 158.801 +
 158.802 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 158.803 +{
 158.804 +				/* dummy routine */
 158.805 +}
 158.806 +
 158.807 +
 158.808 +/* Mailbox status
 158.809 + * Accepts: MAIL stream
 158.810 + *	    mailbox name
 158.811 + *	    mailbox status
 158.812 + */
 158.813 +
 158.814 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 158.815 +{
 158.816 +  if (status->recent || status->unseen)
 158.817 +    printf ("%lu new message(s) (%lu unseen),",status->recent,status->unseen);
 158.818 +  else fputs ("No new messages,",stdout);
 158.819 +  printf (" %lu total in %s\n",status->messages,mailbox);
 158.820 +}
 158.821 +
 158.822 +/* Notification event
 158.823 + * Accepts: MAIL stream
 158.824 + *	    string to log
 158.825 + *	    error flag
 158.826 + */
 158.827 +
 158.828 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
 158.829 +{
 158.830 +  if (!errflg && (string[0] == '[') &&
 158.831 +      ((string[1] == 'T') || (string[1] == 't')) &&
 158.832 +      ((string[2] == 'R') || (string[2] == 'r')) &&
 158.833 +      ((string[3] == 'Y') || (string[3] == 'y')) &&
 158.834 +      ((string[4] == 'C') || (string[4] == 'c')) &&
 158.835 +      ((string[5] == 'R') || (string[5] == 'r')) &&
 158.836 +      ((string[6] == 'E') || (string[6] == 'e')) &&
 158.837 +      ((string[7] == 'A') || (string[7] == 'a')) &&
 158.838 +      ((string[8] == 'T') || (string[8] == 't')) &&
 158.839 +      ((string[9] == 'E') || (string[9] == 'e')) &&
 158.840 +      (string[10] == ']'))
 158.841 +    trycreate = T;  
 158.842 +  mm_log (string,errflg);	/* just do mm_log action */
 158.843 +}
 158.844 +
 158.845 +
 158.846 +/* Log an event for the user to see
 158.847 + * Accepts: string to log
 158.848 + *	    error flag
 158.849 + */
 158.850 +
 158.851 +void mm_log (char *string,long errflg)
 158.852 +{
 158.853 +  switch (errflg) {  
 158.854 +  case BYE:
 158.855 +  case NIL:			/* no error */
 158.856 +    if (verbosep) fprintf (stderr,"[%s]\n",string);
 158.857 +    break;
 158.858 +  case PARSE:			/* parsing problem */
 158.859 +  case WARN:			/* warning */
 158.860 +    fprintf (stderr,"warning: %s\n",string);
 158.861 +    break;
 158.862 +  case ERROR:			/* error */
 158.863 +  default:
 158.864 +    fprintf (stderr,"%s\n",string);
 158.865 +    break;
 158.866 +  }
 158.867 +}
 158.868 +
 158.869 +
 158.870 +/* Log an event to debugging telemetry
 158.871 + * Accepts: string to log
 158.872 + */
 158.873 +
 158.874 +void mm_dlog (char *string)
 158.875 +{
 158.876 +  fprintf (stderr,"%s\n",string);
 158.877 +}
 158.878 +
 158.879 +/* Get user name and password for this host
 158.880 + * Accepts: parse of network mailbox name
 158.881 + *	    where to return user name
 158.882 + *	    where to return password
 158.883 + *	    trial count
 158.884 + */
 158.885 +
 158.886 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
 158.887 +{
 158.888 +  char *s,tmp[MAILTMPLEN];
 158.889 +  sprintf (s = tmp,"{%s/%s",mb->host,mb->service);
 158.890 +  if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",
 158.891 +			  strcpy (username,mb->user));
 158.892 +  if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser);
 158.893 +  if (*mb->user) strcat (s = tmp,"} password:");
 158.894 +  else {
 158.895 +    printf ("%s} username: ",tmp);
 158.896 +    fgets (username,NETMAXUSER-1,stdin);
 158.897 +    username[NETMAXUSER-1] = '\0';
 158.898 +    if (s = strchr (username,'\n')) *s = '\0';
 158.899 +    s = "password: ";
 158.900 +  }
 158.901 +  strcpy (password,getpass (s));
 158.902 +}
 158.903 +
 158.904 +
 158.905 +/* About to enter critical code
 158.906 + * Accepts: stream
 158.907 + */
 158.908 +
 158.909 +void mm_critical (MAILSTREAM *stream)
 158.910 +{
 158.911 +  critical = T;			/* note in critical code */
 158.912 +}
 158.913 +
 158.914 +
 158.915 +/* About to exit critical code
 158.916 + * Accepts: stream
 158.917 + */
 158.918 +
 158.919 +void mm_nocritical (MAILSTREAM *stream)
 158.920 +{
 158.921 +  critical = NIL;		/* note not in critical code */
 158.922 +}
 158.923 +
 158.924 +
 158.925 +/* Disk error found
 158.926 + * Accepts: stream
 158.927 + *	    system error code
 158.928 + *	    flag indicating that mailbox may be clobbered
 158.929 + * Returns: T if user wants to abort
 158.930 + */
 158.931 +
 158.932 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
 158.933 +{
 158.934 +  return T;
 158.935 +}
 158.936 +
 158.937 +
 158.938 +/* Log a fatal error event
 158.939 + * Accepts: string to log
 158.940 + */
 158.941 +
 158.942 +void mm_fatal (char *string)
 158.943 +{
 158.944 +  fprintf (stderr,"FATAL: %s\n",string);
 158.945 +}
   159.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   159.2 +++ b/src/mailutil/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
   159.3 @@ -0,0 +1,50 @@
   159.4 +# ========================================================================
   159.5 +# Copyright 1988-2006 University of Washington
   159.6 +#
   159.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   159.8 +# you may not use this file except in compliance with the License.
   159.9 +# You may obtain a copy of the License at
  159.10 +#
  159.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  159.12 +#
  159.13 +# 
  159.14 +# ========================================================================
  159.15 +
  159.16 +
  159.17 +# Program:	MAILUTIL Makefile for Windows 9x and Windows NT
  159.18 +#
  159.19 +# Author:	Mark Crispin
  159.20 +#		Networks and Distributed Computing
  159.21 +#		Computing & Communications
  159.22 +#		University of Washington
  159.23 +#		Administration Building, AG-44
  159.24 +#		Seattle, WA  98195
  159.25 +#		Internet: MRC@CAC.Washington.EDU
  159.26 +#
  159.27 +# Date:		25 February 1996
  159.28 +# Last Edited:	30 August 2006
  159.29 +
  159.30 +
  159.31 +C = ..\c-client
  159.32 +CCLIENTLIB = $C\cclient.lib
  159.33 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
  159.34 +CFLAGS= -I$C /MT /W3 /DWIN32 /D_WIN32_WINNT=0x0400 -nologo $(EXTRACFLAGS)
  159.35 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  159.36 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  159.37 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  159.38 +
  159.39 +mailutil: $(CCLIENTLIB) mailutil.obj
  159.40 +	LINK /NOLOGO mailutil.obj $(LIBS)
  159.41 +
  159.42 +mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
  159.43 +
  159.44 +$(CCLIENTLIB):
  159.45 +	@echo Make c-client first
  159.46 +	false
  159.47 +
  159.48 +clean:
  159.49 +	del *.obj *.exe *.lib *.exp || rem
  159.50 +
  159.51 +# A monument to a hack of long ago and far away...
  159.52 +love:
  159.53 +	@echo not war?
   160.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   160.2 +++ b/src/mailutil/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
   160.3 @@ -0,0 +1,51 @@
   160.4 +# ========================================================================
   160.5 +# Copyright 1988-2006 University of Washington
   160.6 +#
   160.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   160.8 +# you may not use this file except in compliance with the License.
   160.9 +# You may obtain a copy of the License at
  160.10 +#
  160.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  160.12 +#
  160.13 +# 
  160.14 +# ========================================================================
  160.15 +
  160.16 +
  160.17 +# Program:	MAILUTIL Makefile for Windows 9x and Windows NT + Kerberos
  160.18 +#
  160.19 +# Author:	Mark Crispin
  160.20 +#		Networks and Distributed Computing
  160.21 +#		Computing & Communications
  160.22 +#		University of Washington
  160.23 +#		Administration Building, AG-44
  160.24 +#		Seattle, WA  98195
  160.25 +#		Internet: MRC@CAC.Washington.EDU
  160.26 +#
  160.27 +# Date:		25 February 1996
  160.28 +# Last Edited:	30 August 2006
  160.29 +
  160.30 +
  160.31 +C = ..\c-client
  160.32 +CCLIENTLIB = $C\cclient.lib
  160.33 +K5 = \k5\lib
  160.34 +K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
  160.35 +LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
  160.36 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  160.37 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  160.38 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  160.39 +
  160.40 +mailutil: $(CCLIENTLIB) mailutil.obj
  160.41 +	LINK /NOLOGO mailutil.obj $(LIBS)
  160.42 +
  160.43 +mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
  160.44 +
  160.45 +$(CCLIENTLIB):
  160.46 +	@echo Make c-client first
  160.47 +	false
  160.48 +
  160.49 +clean:
  160.50 +	del *.obj *.exe *.lib *.exp || rem
  160.51 +
  160.52 +# A monument to a hack of long ago and far away...
  160.53 +love:
  160.54 +	@echo not war?
   161.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   161.2 +++ b/src/mailutil/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
   161.3 @@ -0,0 +1,49 @@
   161.4 +# ========================================================================
   161.5 +# Copyright 1988-2006 University of Washington
   161.6 +#
   161.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   161.8 +# you may not use this file except in compliance with the License.
   161.9 +# You may obtain a copy of the License at
  161.10 +#
  161.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  161.12 +#
  161.13 +# 
  161.14 +# ========================================================================
  161.15 +
  161.16 +
  161.17 +# Program:	MAILUTIL Makefile for Windows 2000/XP
  161.18 +#
  161.19 +# Author:	Mark Crispin
  161.20 +#		Networks and Distributed Computing
  161.21 +#		Computing & Communications
  161.22 +#		University of Washington
  161.23 +#		Administration Building, AG-44
  161.24 +#		Seattle, WA  98195
  161.25 +#		Internet: MRC@CAC.Washington.EDU
  161.26 +#
  161.27 +# Date:		25 February 1996
  161.28 +# Last Edited:	30 August 2006
  161.29 +
  161.30 +
  161.31 +C = ..\c-client
  161.32 +CCLIENTLIB = $C\cclient.lib
  161.33 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
  161.34 +OSCOMPAT = /DWIN32
  161.35 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  161.36 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  161.37 +
  161.38 +mailutil: $(CCLIENTLIB) mailutil.obj
  161.39 +	LINK /NOLOGO mailutil.obj $(LIBS)
  161.40 +
  161.41 +mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
  161.42 +
  161.43 +$(CCLIENTLIB):
  161.44 +	@echo Make c-client first
  161.45 +	false
  161.46 +
  161.47 +clean:
  161.48 +	del *.obj *.exe *.lib *.exp || rem
  161.49 +
  161.50 +# A monument to a hack of long ago and far away...
  161.51 +love:
  161.52 +	@echo not war?
   162.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   162.2 +++ b/src/mlock/Makefile	Mon Sep 14 15:17:45 2009 +0900
   162.3 @@ -0,0 +1,51 @@
   162.4 +# ========================================================================
   162.5 +# Copyright 1988-2006 University of Washington
   162.6 +#
   162.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   162.8 +# you may not use this file except in compliance with the License.
   162.9 +# You may obtain a copy of the License at
  162.10 +#
  162.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  162.12 +#
  162.13 +# 
  162.14 +# ========================================================================
  162.15 +
  162.16 +
  162.17 +# Program:	MLOCK Makefile
  162.18 +#
  162.19 +# Author:	Mark Crispin
  162.20 +#		Networks and Distributed Computing
  162.21 +#		Computing & Communications
  162.22 +#		University of Washington
  162.23 +#		Administration Building, AG-44
  162.24 +#		Seattle, WA  98195
  162.25 +#		Internet: MRC@CAC.Washington.EDU
  162.26 +#
  162.27 +# Date:		8 February 1999
  162.28 +# Last Edited:	30 August 2006
  162.29 +
  162.30 +
  162.31 +C = ../c-client
  162.32 +SHELL = /bin/sh
  162.33 +
  162.34 +# Get local definitions from c-client directory
  162.35 +
  162.36 +CC = `cat $C/CCTYPE`
  162.37 +CFLAGS = `cat $C/CFLAGS`
  162.38 +
  162.39 +all:	mlock
  162.40 +
  162.41 +mlock:	mlock.o
  162.42 +	$(CC) $(CFLAGS) -o mlock mlock.o
  162.43 +
  162.44 +install: mlock
  162.45 +	chgrp mail mlock
  162.46 +	chmod 3711 mlock
  162.47 +	cp -p mlock /etc/mlock
  162.48 +
  162.49 +clean:
  162.50 +	rm -f *.o mlock || true
  162.51 +
  162.52 +# A monument to a hack of long ago and far away...
  162.53 +love:
  162.54 +	@echo 'not war?'
   163.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   163.2 +++ b/src/mlock/mlock.c	Mon Sep 14 15:17:45 2009 +0900
   163.3 @@ -0,0 +1,175 @@
   163.4 +/* ========================================================================
   163.5 + * Copyright 1988-2008 University of Washington
   163.6 + *
   163.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   163.8 + * you may not use this file except in compliance with the License.
   163.9 + * You may obtain a copy of the License at
  163.10 + *
  163.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  163.12 + *
  163.13 + * 
  163.14 + * ========================================================================
  163.15 + */
  163.16 +
  163.17 +/*
  163.18 + * Program:	Standalone Mailbox Lock program
  163.19 + *
  163.20 + * Author:	Mark Crispin
  163.21 + *		Networks and Distributed Computing
  163.22 + *		Computing & Communications
  163.23 + *		University of Washington
  163.24 + *		Administration Building, AG-44
  163.25 + *		Seattle, WA  98195
  163.26 + *		Internet: MRC@CAC.Washington.EDU
  163.27 + *
  163.28 + * Date:	8 February 1999
  163.29 + * Last Edited:	3 March 2008
  163.30 + */
  163.31 +
  163.32 +#include <errno.h>
  163.33 +#include <fcntl.h>
  163.34 +#include <stdio.h>
  163.35 +#include <sysexits.h>
  163.36 +#include <syslog.h>
  163.37 +#include <grp.h>
  163.38 +#include <sys/types.h>
  163.39 +#include <sys/file.h>
  163.40 +#include <sys/stat.h>
  163.41 +#include <sys/param.h>
  163.42 +#include <stdlib.h>
  163.43 +#include <netdb.h>
  163.44 +#include <ctype.h>
  163.45 +#include <string.h>
  163.46 +
  163.47 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
  163.48 +#define LOCKPROTECTION 0664
  163.49 +
  163.50 +#ifndef MAXHOSTNAMELEN		/* Solaris still sucks */
  163.51 +#define MAXHOSTNAMELEN 256
  163.52 +#endif
  163.53 +
  163.54 +/* Fatal error
  163.55 + * Accepts: Message string
  163.56 + *	    exit code
  163.57 + * Returns: code
  163.58 + */
  163.59 +
  163.60 +int die (char *msg,int code)
  163.61 +{
  163.62 +  syslog (LOG_NOTICE,"(%u) %s",code,msg);
  163.63 +  write (1,"?",1);		/* indicate "impossible" failure */
  163.64 +  return code;
  163.65 +}
  163.66 +
  163.67 +
  163.68 +int main (int argc,char *argv[])
  163.69 +{
  163.70 +  int ld,i;
  163.71 +  int tries = LOCKTIMEOUT * 60 - 1;
  163.72 +  char *s,*dir,*file,*lock,*hitch,tmp[1024];
  163.73 +  size_t dlen,len;
  163.74 +  struct stat sb,fsb;
  163.75 +  struct group *grp = getgrnam ("mail");
  163.76 +				/* get syslog */
  163.77 +  openlog (argv[0],LOG_PID,LOG_MAIL);
  163.78 +  if (!grp || (grp->gr_gid != getegid ()))
  163.79 +    return die ("not setgid mail",EX_USAGE);
  163.80 +  if (argc != 3) return die ("invalid arguments",EX_USAGE);
  163.81 +  for (s = argv[1]; *s; s++)
  163.82 +    if (!isdigit (*s)) return die ("invalid fd",EX_USAGE);
  163.83 +				/* find directory */
  163.84 +  if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1])
  163.85 +    return die ("invalid path",EX_USAGE);
  163.86 +				/* calculate lengths of directory and file */
  163.87 +  if (!(dlen = file - argv[2])) dlen = 1;
  163.88 +  len = strlen (++file);
  163.89 +				/* make buffers */
  163.90 +  dir = (char *) malloc (dlen + 1);
  163.91 +  lock = (char *) malloc (len + 6);
  163.92 +  hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN);
  163.93 +  if (!dir || !lock || !hitch) return die ("malloc failure",errno);
  163.94 +  strncpy (dir,argv[2],dlen);	/* connect to desired directory */
  163.95 +  dir[dlen] = '\0';
  163.96 +  printf ("dir=%s, file=%s\n",dir,file);
  163.97 +  chdir (dir);
  163.98 +				/* get device/inode of file descriptor */
  163.99 +  if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno);
 163.100 +				/* better be a regular file */
 163.101 +  if ((fsb.st_mode & S_IFMT) != S_IFREG)
 163.102 +    return die ("fd not regular file",EX_USAGE);
 163.103 +				/* now get device/inode of file */
 163.104 +  if (lstat (file,&sb)) return die ("lstat failure",errno);
 163.105 +				/* does it match? */
 163.106 +  if ((sb.st_mode & S_IFMT) != S_IFREG)
 163.107 +    return die ("name not regular file",EX_USAGE);
 163.108 +  if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino))
 163.109 +    return die ("fd and name different",EX_USAGE);
 163.110 +				/* build lock filename */
 163.111 +  sprintf (lock,"%s.lock",file);
 163.112 +  if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG))
 163.113 +    return die ("existing lock not regular file",EX_NOPERM);
 163.114 +
 163.115 +  do {				/* until OK or out of tries */
 163.116 +    if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60)))
 163.117 +      unlink (lock);		/* time out lock if enough time has passed */
 163.118 +    /* SUN-OS had an NFS
 163.119 +     * As kludgy as an albatross;
 163.120 +     * And everywhere that it was installed,
 163.121 +     * It was a total loss.
 163.122 +     * -- MRC 9/25/91
 163.123 +     */
 163.124 +				/* build hitching post file name */
 163.125 +    sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0),
 163.126 +	     (unsigned long) getpid ());
 163.127 +    len = strlen (hitch);	/* append local host name */
 163.128 +    gethostname (hitch + len,MAXHOSTNAMELEN);
 163.129 +				/* try to get hitching-post file */
 163.130 +    if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
 163.131 +				/* make sure others can break the lock */
 163.132 +      chmod (hitch,LOCKPROTECTION);
 163.133 +				/* get device/inode of hitch file */
 163.134 +      if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno);
 163.135 +      close (ld);		/* close the hitching-post */
 163.136 +      /* Note: link() may return an error even if it actually succeeded.  So we
 163.137 +       * always check for success via the link count, and ignore the error if
 163.138 +       * the link count is right.
 163.139 +       */
 163.140 +				/* tie hitching-post to lock */
 163.141 +      i = link (hitch,lock) ? errno : 0;
 163.142 +				/* success if link count now 2 */
 163.143 +      if (stat (hitch,&sb) || (sb.st_nlink != 2) ||
 163.144 +	  (fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) {
 163.145 +	ld = -1;		/* failed to hitch */
 163.146 +	if (i == EPERM) {	/* was it because links not allowed? */
 163.147 +	  /* Probably a FAT filesystem on Linux.  It can't be NFS, so try
 163.148 +	   * creating the lock file directly.
 163.149 +	   */
 163.150 +	  if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
 163.151 +	    /* get device/inode of lock file */
 163.152 +	    if (fstat (ld,&fsb)) return die ("lock fstat failure",errno);
 163.153 +	    close (ld);		/* close the file */
 163.154 +	  }
 163.155 +				/* give up immediately if protection failure */
 163.156 +	  else if (errno != EEXIST) tries = 0;
 163.157 +	}
 163.158 +      }
 163.159 +      unlink (hitch);		/* flush hitching post */
 163.160 +    }
 163.161 +				/* give up immediately if protection failure */
 163.162 +    else if (errno == EACCES) tries = 0;
 163.163 +    if (ld < 0) {		/* lock failed */
 163.164 +      if (tries--) sleep (1);	/* sleep 1 second and try again */
 163.165 +      else {
 163.166 +	write (1,"-",1);	/* hard failure */
 163.167 +	return EX_CANTCREAT;
 163.168 +      }
 163.169 +    }
 163.170 +  } while (ld < 0);
 163.171 +  write (1,"+",1);		/* indicate that all is well */
 163.172 +  read (0,tmp,1);		/* read continue signal from parent */
 163.173 +				/* flush the lock file */
 163.174 +  if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) &&
 163.175 +      (fsb.st_ino == sb.st_ino)) unlink (lock);
 163.176 +  else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock);
 163.177 +  return EX_OK;
 163.178 +}
   164.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   164.2 +++ b/src/mtest/Makefile	Mon Sep 14 15:17:45 2009 +0900
   164.3 @@ -0,0 +1,53 @@
   164.4 +# ========================================================================
   164.5 +# Copyright 1988-2006 University of Washington
   164.6 +#
   164.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   164.8 +# you may not use this file except in compliance with the License.
   164.9 +# You may obtain a copy of the License at
  164.10 +#
  164.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  164.12 +#
  164.13 +# 
  164.14 +# ========================================================================
  164.15 +
  164.16 +
  164.17 +# Program:	MTEST Makefile
  164.18 +#
  164.19 +# Author:	Mark Crispin
  164.20 +#		Networks and Distributed Computing
  164.21 +#		Computing & Communications
  164.22 +#		University of Washington
  164.23 +#		Administration Building, AG-44
  164.24 +#		Seattle, WA  98195
  164.25 +#		Internet: MRC@CAC.Washington.EDU
  164.26 +#
  164.27 +# Date:		25 February 1996
  164.28 +# Last Edited:	30 August 2006
  164.29 +
  164.30 +
  164.31 +C = ../c-client
  164.32 +CCLIENTLIB = $C/c-client.a
  164.33 +SHELL = /bin/sh
  164.34 +
  164.35 +# Get local definitions from c-client directory
  164.36 +
  164.37 +CC = `cat $C/CCTYPE`
  164.38 +CFLAGS = -I$C `cat $C/CFLAGS`
  164.39 +LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
  164.40 +
  164.41 +all:	mtest
  164.42 +
  164.43 +mtest: $(CCLIENTLIB) mtest.o
  164.44 +	$(CC) $(CFLAGS) -o mtest mtest.o $(LDFLAGS)
  164.45 +
  164.46 +mtest.o: $C/mail.h $C/misc.h $C/osdep.h $C/rfc822.h $C/smtp.h $C/nntp.h
  164.47 +
  164.48 +$(CCLIENTLIB):
  164.49 +	cd $C;make
  164.50 +
  164.51 +clean:
  164.52 +	rm -f *.o mtest || true
  164.53 +
  164.54 +# A monument to a hack of long ago and far away...
  164.55 +love:
  164.56 +	@echo 'not war?'
   165.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   165.2 +++ b/src/mtest/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
   165.3 @@ -0,0 +1,49 @@
   165.4 +# ========================================================================
   165.5 +# Copyright 1988-2006 University of Washington
   165.6 +#
   165.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   165.8 +# you may not use this file except in compliance with the License.
   165.9 +# You may obtain a copy of the License at
  165.10 +#
  165.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  165.12 +#
  165.13 +# 
  165.14 +# ========================================================================
  165.15 +
  165.16 +
  165.17 +# Program:	MTEST Makefile for Windows 9x and Windows NT
  165.18 +#
  165.19 +# Author:	Mark Crispin
  165.20 +#		Networks and Distributed Computing
  165.21 +#		Computing & Communications
  165.22 +#		University of Washington
  165.23 +#		Administration Building, AG-44
  165.24 +#		Seattle, WA  98195
  165.25 +#		Internet: MRC@CAC.Washington.EDU
  165.26 +#
  165.27 +# Date:		25 February 1996
  165.28 +# Last Edited:	30 August 2006
  165.29 +
  165.30 +
  165.31 +C = ..\c-client
  165.32 +CCLIENTLIB = $C\cclient.lib
  165.33 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
  165.34 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  165.35 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  165.36 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  165.37 +
  165.38 +mtest: $(CCLIENTLIB) mtest.obj
  165.39 +	LINK /NOLOGO mtest.obj $(LIBS)
  165.40 +
  165.41 +mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
  165.42 +
  165.43 +$(CCLIENTLIB):
  165.44 +	@echo Make c-client first
  165.45 +	false
  165.46 +
  165.47 +clean:
  165.48 +	del *.obj *.exe *.lib *.exp || rem
  165.49 +
  165.50 +# A monument to a hack of long ago and far away...
  165.51 +love:
  165.52 +	@echo not war?
   166.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   166.2 +++ b/src/mtest/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
   166.3 @@ -0,0 +1,51 @@
   166.4 +# ========================================================================
   166.5 +# Copyright 1988-2006 University of Washington
   166.6 +#
   166.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   166.8 +# you may not use this file except in compliance with the License.
   166.9 +# You may obtain a copy of the License at
  166.10 +#
  166.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  166.12 +#
  166.13 +# 
  166.14 +# ========================================================================
  166.15 +
  166.16 +
  166.17 +# Program:	MTEST Makefile for Windows 9x and Windows NT + Kerberos
  166.18 +#
  166.19 +# Author:	Mark Crispin
  166.20 +#		Networks and Distributed Computing
  166.21 +#		Computing & Communications
  166.22 +#		University of Washington
  166.23 +#		Administration Building, AG-44
  166.24 +#		Seattle, WA  98195
  166.25 +#		Internet: MRC@CAC.Washington.EDU
  166.26 +#
  166.27 +# Date:		25 February 1996
  166.28 +# Last Edited:	30 August 2006
  166.29 +
  166.30 +
  166.31 +C = ..\c-client
  166.32 +CCLIENTLIB = $C\cclient.lib
  166.33 +K5 = \k5\lib
  166.34 +K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
  166.35 +LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
  166.36 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  166.37 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  166.38 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  166.39 +
  166.40 +mtest: $(CCLIENTLIB) mtest.obj
  166.41 +	LINK /NOLOGO mtest.obj $(LIBS)
  166.42 +
  166.43 +mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
  166.44 +
  166.45 +$(CCLIENTLIB):
  166.46 +	@echo Make c-client first
  166.47 +	false
  166.48 +
  166.49 +clean:
  166.50 +	del *.obj *.exe *.lib *.exp || rem
  166.51 +
  166.52 +# A monument to a hack of long ago and far away...
  166.53 +love:
  166.54 +	@echo not war?
   167.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   167.2 +++ b/src/mtest/makefile.os2	Mon Sep 14 15:17:45 2009 +0900
   167.3 @@ -0,0 +1,53 @@
   167.4 +# ========================================================================
   167.5 +# Copyright 1988-2006 University of Washington
   167.6 +#
   167.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   167.8 +# you may not use this file except in compliance with the License.
   167.9 +# You may obtain a copy of the License at
  167.10 +#
  167.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  167.12 +#
  167.13 +# 
  167.14 +# ========================================================================
  167.15 +
  167.16 +
  167.17 +# Program:	MTEST Makefile
  167.18 +#
  167.19 +# Author:	Mark Crispin
  167.20 +#		Networks and Distributed Computing
  167.21 +#		Computing & Communications
  167.22 +#		University of Washington
  167.23 +#		Administration Building, AG-44
  167.24 +#		Seattle, WA  98195
  167.25 +#		Internet: MRC@CAC.Washington.EDU
  167.26 +#
  167.27 +# Date:		25 February 1996
  167.28 +# Last Edited:	30 August 2006
  167.29 +
  167.30 +# Thanks to Nicholas Paul Sheppard who contributed the original version
  167.31 +
  167.32 +CC = gcc
  167.33 +CFLAGS = -O2 -Zomf
  167.34 +LD = gcc
  167.35 +LDFLAGS = -s -Zomf -Zcrtdll
  167.36 +
  167.37 +C = ..\c-client
  167.38 +CCLIENTLIB = $C\\c-client.lib
  167.39 +LIBS = $(CCLIENTLIB) -l socket
  167.40 +
  167.41 +mtest.exe: $(CCLIENTLIB) mtest.obj
  167.42 +	$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
  167.43 +
  167.44 +$(CCLIENTLIB):
  167.45 +	@echo Make c-client first
  167.46 +	false
  167.47 +
  167.48 +mtest.obj: mtest.c $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h
  167.49 +	$(CC) $(CFLAGS) -I$C -o $@ -c $<
  167.50 +
  167.51 +clean:
  167.52 +	if exist *.obj del *.obj
  167.53 +
  167.54 +# A monument to a hack of long ago and far away...
  167.55 +love:
  167.56 +	@echo not war?
   168.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   168.2 +++ b/src/mtest/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
   168.3 @@ -0,0 +1,49 @@
   168.4 +# ========================================================================
   168.5 +# Copyright 1988-2006 University of Washington
   168.6 +#
   168.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   168.8 +# you may not use this file except in compliance with the License.
   168.9 +# You may obtain a copy of the License at
  168.10 +#
  168.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  168.12 +#
  168.13 +# 
  168.14 +# ========================================================================
  168.15 +
  168.16 +
  168.17 +# Program:	MTEST Makefile for Windows 2000/XP
  168.18 +#
  168.19 +# Author:	Mark Crispin
  168.20 +#		Networks and Distributed Computing
  168.21 +#		Computing & Communications
  168.22 +#		University of Washington
  168.23 +#		Administration Building, AG-44
  168.24 +#		Seattle, WA  98195
  168.25 +#		Internet: MRC@CAC.Washington.EDU
  168.26 +#
  168.27 +# Date:		25 February 1996
  168.28 +# Last Edited:	30 August 2006
  168.29 +
  168.30 +
  168.31 +C = ..\c-client
  168.32 +CCLIENTLIB = $C\cclient.lib
  168.33 +LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
  168.34 +OSCOMPAT = /DWIN32
  168.35 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  168.36 +CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
  168.37 +
  168.38 +mtest: $(CCLIENTLIB) mtest.obj
  168.39 +	LINK /NOLOGO mtest.obj $(LIBS)
  168.40 +
  168.41 +mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
  168.42 +
  168.43 +$(CCLIENTLIB):
  168.44 +	@echo Make c-client first
  168.45 +	false
  168.46 +
  168.47 +clean:
  168.48 +	del *.obj *.exe *.lib *.exp || rem
  168.49 +
  168.50 +# A monument to a hack of long ago and far away...
  168.51 +love:
  168.52 +	@echo not war?
   169.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   169.2 +++ b/src/mtest/mtest.c	Mon Sep 14 15:17:45 2009 +0900
   169.3 @@ -0,0 +1,813 @@
   169.4 +/* ========================================================================
   169.5 + * Copyright 1988-2007 University of Washington
   169.6 + *
   169.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   169.8 + * you may not use this file except in compliance with the License.
   169.9 + * You may obtain a copy of the License at
  169.10 + *
  169.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  169.12 + *
  169.13 + * 
  169.14 + * ========================================================================
  169.15 + */
  169.16 +
  169.17 +/*
  169.18 + * Program:	Mail library test program
  169.19 + *
  169.20 + * Author:	Mark Crispin
  169.21 + *		Networks and Distributed Computing
  169.22 + *		Computing & Communications
  169.23 + *		University of Washington
  169.24 + *		Administration Building, AG-44
  169.25 + *		Seattle, WA  98195
  169.26 + *		Internet: MRC@CAC.Washington.EDU
  169.27 + *
  169.28 + * Date:	8 July 1988
  169.29 + * Last Edited:	5 November 2007
  169.30 + *
  169.31 + * This original version of this file is
  169.32 + * Copyright 1988 Stanford University
  169.33 + * and was developed in the Symbolic Systems Resources Group of the Knowledge
  169.34 + * Systems Laboratory at Stanford University in 1987-88, and was funded by the
  169.35 + * Biomedical Research Technology Program of the NationalInstitutes of Health
  169.36 + * under grant number RR-00785.
  169.37 + */
  169.38 +
  169.39 +#include <stdio.h>
  169.40 +#include <ctype.h>
  169.41 +#include <signal.h>
  169.42 +#include "c-client.h"
  169.43 +#include "imap4r1.h"
  169.44 +
  169.45 +/* Excellent reasons to hate ifdefs, and why my real code never uses them */
  169.46 +
  169.47 +#ifndef unix
  169.48 +# define unix 0
  169.49 +#endif
  169.50 +
  169.51 +#if unix
  169.52 +# define UNIXLIKE 1
  169.53 +# define MACOS 0
  169.54 +# include <pwd.h>
  169.55 +#else
  169.56 +# define UNIXLIKE 0
  169.57 +# ifdef noErr
  169.58 +#  define MACOS 1
  169.59 +#  include <Memory.h>
  169.60 +# else
  169.61 +#  define MACOS 0
  169.62 +# endif
  169.63 +#endif
  169.64 +
  169.65 +char *curhst = NIL;		/* currently connected host */
  169.66 +char *curusr = NIL;		/* current login user */
  169.67 +char personalname[MAILTMPLEN];	/* user's personal name */
  169.68 +
  169.69 +static char *hostlist[] = {	/* SMTP server host list */
  169.70 +  "mailhost",
  169.71 +  "localhost",
  169.72 +  NIL
  169.73 +};
  169.74 +
  169.75 +static char *newslist[] = {	/* Netnews server host list */
  169.76 +  "news",
  169.77 +  NIL
  169.78 +};
  169.79 +
  169.80 +int main (void);
  169.81 +void mm (MAILSTREAM *stream,long debug);
  169.82 +void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
  169.83 +		      unsigned long msgno);
  169.84 +void header (MAILSTREAM *stream,long msgno);
  169.85 +void display_body (BODY *body,char *pfx,long i);
  169.86 +void status (MAILSTREAM *stream);
  169.87 +void prompt (char *msg,char *txt);
  169.88 +void smtptest (long debug);
  169.89 +
  169.90 +/* Main program - initialization */
  169.91 +
  169.92 +int main ()
  169.93 +{
  169.94 +  MAILSTREAM *stream = NIL;
  169.95 +  void *sdb = NIL;
  169.96 +  char *s,tmp[MAILTMPLEN];
  169.97 +  long debug;
  169.98 +#include "linkage.c"
  169.99 +#if MACOS
 169.100 +  {
 169.101 +    size_t *base = (size_t *) 0x000908;
 169.102 +				/* increase stack size on a Mac */
 169.103 +    SetApplLimit ((Ptr) (*base - (size_t) 65535L));
 169.104 +  }
 169.105 +#endif
 169.106 +  curusr = cpystr (((s = myusername ()) && *s) ? s : "somebody");
 169.107 +#if UNIXLIKE
 169.108 +  {
 169.109 +    char *suffix;
 169.110 +    struct passwd *pwd = getpwnam (curusr);
 169.111 +    if (pwd) {
 169.112 +      strcpy (tmp,pwd->pw_gecos);
 169.113 +				/* dyke out the office and phone poop */
 169.114 +      if (suffix = strchr (tmp,',')) suffix[0] = '\0';
 169.115 +      strcpy (personalname,tmp);/* make a permanent copy of it */
 169.116 +    }
 169.117 +    else personalname[0] = '\0';
 169.118 +  }
 169.119 +#else
 169.120 +  personalname[0] = '\0';
 169.121 +#endif
 169.122 +  curhst = cpystr (mylocalhost ());
 169.123 +  puts ("MTest -- C client test program");
 169.124 +  if (!*personalname) prompt ("Personal name: ",personalname);
 169.125 +				/* user wants protocol telemetry? */
 169.126 +  prompt ("Debug protocol (y/n)?",tmp);
 169.127 +  ucase (tmp);
 169.128 +  debug = (tmp[0] == 'Y') ? T : NIL;
 169.129 +  do {
 169.130 +    prompt ("Mailbox ('?' for help): ",tmp);
 169.131 +    if (!strcmp (tmp,"?")) {
 169.132 +      puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox");
 169.133 +      puts ("Known local mailboxes:");
 169.134 +      mail_list (NIL,NIL,"%");
 169.135 +      if (s = sm_read (&sdb)) {
 169.136 +	puts ("Local subscribed mailboxes:");
 169.137 +	do (mm_lsub (NIL,NIL,s,NIL));
 169.138 +	while (s = sm_read (&sdb));
 169.139 +      }
 169.140 +      puts ("or just hit return to quit");
 169.141 +    }
 169.142 +    else if (tmp[0]) stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
 169.143 +  } while (!stream && tmp[0]);
 169.144 +  mm (stream,debug);		/* run user interface if opened */
 169.145 +#if MACOS
 169.146 +				/* clean up resolver */
 169.147 +  if (resolveropen) CloseResolver ();
 169.148 +#endif
 169.149 +  return NIL;
 169.150 +}
 169.151 +
 169.152 +/* MM command loop
 169.153 + * Accepts: MAIL stream
 169.154 + */
 169.155 +
 169.156 +void mm (MAILSTREAM *stream,long debug)
 169.157 +{
 169.158 +  void *sdb = NIL;
 169.159 +  char cmd[MAILTMPLEN];
 169.160 +  char *s,*arg;
 169.161 +  unsigned long i;
 169.162 +  unsigned long last = 0;
 169.163 +  BODY *body;
 169.164 +  status (stream);		/* first report message status */
 169.165 +  while (stream) {
 169.166 +    prompt ("MTest>",cmd);	/* prompt user, get command */
 169.167 +				/* get argument */
 169.168 +    if (arg = strchr (cmd,' ')) *arg++ = '\0';
 169.169 +    switch (*ucase (cmd)) {	/* dispatch based on command */
 169.170 +    case 'B':			/* Body command */
 169.171 +      if (arg) last = atoi (arg);
 169.172 +      else if (!last) {
 169.173 +	puts ("?Missing message number");
 169.174 +	break;
 169.175 +      }
 169.176 +      if (last && (last <= stream->nmsgs)) {
 169.177 +	mail_fetchstructure (stream,last,&body);
 169.178 +	if (body) display_body (body,NIL,(long) 0);
 169.179 +	else puts ("%No body information available");
 169.180 +      }
 169.181 +      else puts ("?Bad message number");
 169.182 +      break;
 169.183 +    case 'C':			/* Check command */
 169.184 +      mail_check (stream);
 169.185 +      status (stream);
 169.186 +      break;
 169.187 +    case 'D':			/* Delete command */
 169.188 +      if (arg) last = atoi (arg);
 169.189 +      else {
 169.190 +	if (last == 0) {
 169.191 +	  puts ("?Missing message number");
 169.192 +	  break;
 169.193 +	}
 169.194 +	arg = cmd;
 169.195 +	sprintf (arg,"%lu",last);
 169.196 +      }
 169.197 +      if (last && (last <= stream->nmsgs))
 169.198 +	mail_setflag (stream,arg,"\\DELETED");
 169.199 +      else puts ("?Bad message number");
 169.200 +      break;
 169.201 +    case 'E':			/* Expunge command */
 169.202 +      mail_expunge (stream);
 169.203 +      last = 0;
 169.204 +      break;
 169.205 +    case 'F':			/* Find command */
 169.206 +      if (!arg) {
 169.207 +	arg = "%";
 169.208 +	if (s = sm_read (&sdb)) {
 169.209 +	  puts ("Local network subscribed mailboxes:");
 169.210 +	  do if (*s == '{') (mm_lsub (NIL,NIL,s,NIL));
 169.211 +	  while (s = sm_read (&sdb));
 169.212 +	}
 169.213 +      }
 169.214 +      puts ("Subscribed mailboxes:");
 169.215 +      mail_lsub (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
 169.216 +		 NIL,arg);
 169.217 +      puts ("Known mailboxes:");
 169.218 +      mail_list (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
 169.219 +		 NIL,arg);
 169.220 +      break;
 169.221 +    case 'G':
 169.222 +      mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT);
 169.223 +      break;
 169.224 +    case 'H':			/* Headers command */
 169.225 +      if (arg) {
 169.226 +	if (!(last = atoi (arg))) {
 169.227 +	  mail_search (stream,arg);
 169.228 +	  for (i = 1; i <= stream->nmsgs; ++i)
 169.229 +	    if (mail_elt (stream,i)->searched) header (stream,i);
 169.230 +	  break;
 169.231 +	}
 169.232 +      }
 169.233 +      else if (last == 0) {
 169.234 +	puts ("?Missing message number");
 169.235 +	break;
 169.236 +      }
 169.237 +      if (last && (last <= stream->nmsgs)) header (stream,last);
 169.238 +      else puts ("?Bad message number");
 169.239 +      break;
 169.240 +    case 'L':			/* Literal command */
 169.241 +      if (arg) last = atoi (arg);
 169.242 +      else if (!last) {
 169.243 +	puts ("?Missing message number");
 169.244 +	break;
 169.245 +      }
 169.246 +      if (last && (last <= stream->nmsgs))
 169.247 +	puts (mail_fetch_message (stream,last,NIL,NIL));
 169.248 +      else puts ("?Bad message number");
 169.249 +      break;
 169.250 +    case 'M':
 169.251 +      mail_status (NIL,arg ? arg : stream->mailbox,
 169.252 +		   SA_MESSAGES|SA_RECENT|SA_UNSEEN|SA_UIDNEXT|SA_UIDVALIDITY);
 169.253 +      break;
 169.254 +    case 'N':			/* New mailbox command */
 169.255 +      if (!arg) {
 169.256 +	puts ("?Missing mailbox");
 169.257 +	break;
 169.258 +      }
 169.259 +				/* get the new mailbox */
 169.260 +      while (!(stream = mail_open (stream,arg,debug))) {
 169.261 +	prompt ("Mailbox: ",arg);
 169.262 +	if (!arg[0]) break;
 169.263 +      }
 169.264 +      last = 0;
 169.265 +      status (stream);
 169.266 +      break;
 169.267 +    case 'O':			/* Overview command */
 169.268 +      if (!arg) {
 169.269 +	puts ("?Missing UID");
 169.270 +	break;
 169.271 +      }
 169.272 +      mail_fetch_overview (stream,arg,overview_header);
 169.273 +      break;
 169.274 +    case 'P':			/* Ping command */
 169.275 +      mail_ping (stream);
 169.276 +      status (stream);
 169.277 +      break;
 169.278 +    case 'Q':			/* Quit command */
 169.279 +      mail_close (stream);
 169.280 +      stream = NIL;
 169.281 +      break;
 169.282 +    case 'S':			/* Send command */
 169.283 +      smtptest (debug);
 169.284 +      break;
 169.285 +    case '\0':			/* null command (type next message) */
 169.286 +      if (!last || (last++ >= stream->nmsgs)) {
 169.287 +	puts ("%No next message");
 169.288 +	break;
 169.289 +      }
 169.290 +    case 'T':			/* Type command */
 169.291 +      if (arg) last = atoi (arg);
 169.292 +      else if (!last) {
 169.293 +	puts ("?Missing message number");
 169.294 +	break;
 169.295 +      }
 169.296 +      if (last && (last <= stream->nmsgs)) {
 169.297 +	STRINGLIST *lines = mail_newstringlist ();
 169.298 +	STRINGLIST *cur = lines;
 169.299 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.300 +					   cpystr ("Date")));
 169.301 +	cur = cur->next = mail_newstringlist ();
 169.302 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.303 +					   cpystr ("From")));
 169.304 +	cur = cur->next = mail_newstringlist ();
 169.305 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.306 +					   cpystr (">From")));
 169.307 +	cur = cur->next = mail_newstringlist ();
 169.308 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.309 +					   cpystr ("Subject")));
 169.310 +	cur = cur->next = mail_newstringlist ();
 169.311 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.312 +					   cpystr ("To")));
 169.313 +	cur = cur->next = mail_newstringlist ();
 169.314 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.315 +					   cpystr ("cc")));
 169.316 +	cur = cur->next = mail_newstringlist ();
 169.317 +	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
 169.318 +					   cpystr ("Newsgroups")));
 169.319 +	printf ("%s",mail_fetchheader_full (stream,last,lines,NIL,NIL));
 169.320 +	puts (mail_fetchtext (stream,last));
 169.321 +	mail_free_stringlist (&lines);
 169.322 +      }
 169.323 +      else puts ("?Bad message number");
 169.324 +      break;
 169.325 +    case 'U':			/* Undelete command */
 169.326 +      if (arg) last = atoi (arg);
 169.327 +      else {
 169.328 +	if (!last) {
 169.329 +	  puts ("?Missing message number");
 169.330 +	  break;
 169.331 +	}
 169.332 +	arg = cmd;
 169.333 +	sprintf (arg,"%lu",last);
 169.334 +      }
 169.335 +      if (last > 0 && last <= stream->nmsgs)
 169.336 +	mail_clearflag (stream,arg,"\\DELETED");
 169.337 +      else puts ("?Bad message number");
 169.338 +      break;
 169.339 +    case 'X':			/* Xit command */
 169.340 +      mail_expunge (stream);
 169.341 +      mail_close (stream);
 169.342 +      stream = NIL;
 169.343 +      break;
 169.344 +    case '+':
 169.345 +      mail_debug (stream); debug = T;
 169.346 +      break;
 169.347 +    case '-':
 169.348 +      mail_nodebug (stream); debug = NIL;
 169.349 +      break;
 169.350 +    case '?':			/* ? command */
 169.351 +      puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Literal,");
 169.352 +      puts (" MailboxStatus, New Mailbox, Overview, Ping, Quit, Send, Type,");
 169.353 +      puts ("Undelete, Xit, +, -, or <RETURN> for next message");
 169.354 +      break;
 169.355 +    default:			/* bogus command */
 169.356 +      printf ("?Unrecognized command: %s\n",cmd);
 169.357 +      break;
 169.358 +    }
 169.359 +  }
 169.360 +}
 169.361 +
 169.362 +/* MM display header
 169.363 + * Accepts: IMAP2 stream
 169.364 + *	    message number
 169.365 + */
 169.366 +
 169.367 +void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
 169.368 +		      unsigned long msgno)
 169.369 +{
 169.370 +  if (ov) {
 169.371 +    unsigned long i;
 169.372 +    char *t,tmp[MAILTMPLEN];
 169.373 +    ADDRESS *adr;
 169.374 +    MESSAGECACHE *elt = mail_elt (stream,msgno);
 169.375 +    MESSAGECACHE selt;
 169.376 +    tmp[0] = elt->recent ? (elt->seen ? 'R': 'N') : ' ';
 169.377 +    tmp[1] = (elt->recent | elt->seen) ? ' ' : 'U';
 169.378 +    tmp[2] = elt->flagged ? 'F' : ' ';
 169.379 +    tmp[3] = elt->answered ? 'A' : ' ';
 169.380 +    tmp[4] = elt->deleted ? 'D' : ' ';
 169.381 +    mail_parse_date (&selt,ov->date);
 169.382 +    sprintf (tmp+5,"%4lu) ",elt->msgno);
 169.383 +    mail_date (tmp+11,&selt);
 169.384 +    tmp[17] = ' ';
 169.385 +    tmp[18] = '\0';
 169.386 +    memset (tmp+18,' ',(size_t) 20);
 169.387 +    tmp[38] = '\0';		/* tie off with null */
 169.388 +				/* get first from address from envelope */
 169.389 +    for (adr = ov->from; adr && !adr->host; adr = adr->next);
 169.390 +    if (adr) {			/* if a personal name exists use it */
 169.391 +      if (!(t = adr->personal))
 169.392 +	sprintf (t = tmp+400,"%s@%s",adr->mailbox,adr->host);
 169.393 +      memcpy (tmp+18,t,(size_t) min (20,(long) strlen (t)));
 169.394 +    }
 169.395 +    strcat (tmp," ");
 169.396 +    if (i = elt->user_flags) {
 169.397 +      strcat (tmp,"{");
 169.398 +      while (i) {
 169.399 +	strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
 169.400 +	if (i) strcat (tmp," ");
 169.401 +      }
 169.402 +      strcat (tmp,"} ");
 169.403 +    }
 169.404 +    sprintf (tmp + strlen (tmp),"%.25s (%lu chars)",
 169.405 +	     ov->subject ? ov->subject : " ",ov->optional.octets);
 169.406 +    puts (tmp);
 169.407 +  }
 169.408 +  else printf ("%%No overview for UID %lu\n",uid);
 169.409 +}
 169.410 +
 169.411 +/* MM display header
 169.412 + * Accepts: IMAP2 stream
 169.413 + *	    message number
 169.414 + */
 169.415 +
 169.416 +void header (MAILSTREAM *stream,long msgno)
 169.417 +{
 169.418 +  unsigned long i;
 169.419 +  char tmp[MAILTMPLEN];
 169.420 +  char *t;
 169.421 +  MESSAGECACHE *cache = mail_elt (stream,msgno);
 169.422 +  mail_fetchstructure (stream,msgno,NIL);
 169.423 +  tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
 169.424 +  tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
 169.425 +  tmp[2] = cache->flagged ? 'F' : ' ';
 169.426 +  tmp[3] = cache->answered ? 'A' : ' ';
 169.427 +  tmp[4] = cache->deleted ? 'D' : ' ';
 169.428 +  sprintf (tmp+5,"%4lu) ",cache->msgno);
 169.429 +  mail_date (tmp+11,cache);
 169.430 +  tmp[17] = ' ';
 169.431 +  tmp[18] = '\0';
 169.432 +  mail_fetchfrom (tmp+18,stream,msgno,(long) 20);
 169.433 +  strcat (tmp," ");
 169.434 +  if (i = cache->user_flags) {
 169.435 +    strcat (tmp,"{");
 169.436 +    while (i) {
 169.437 +      strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
 169.438 +      if (i) strcat (tmp," ");
 169.439 +    }
 169.440 +    strcat (tmp,"} ");
 169.441 +  }
 169.442 +  mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25);
 169.443 +  sprintf (t += strlen (t)," (%lu chars)",cache->rfc822_size);
 169.444 +  puts (tmp);
 169.445 +}
 169.446 +
 169.447 +/* MM display body
 169.448 + * Accepts: BODY structure pointer
 169.449 + *	    prefix string
 169.450 + *	    index
 169.451 + */
 169.452 +
 169.453 +void display_body (BODY *body,char *pfx,long i)
 169.454 +{
 169.455 +  char tmp[MAILTMPLEN];
 169.456 +  char *s = tmp;
 169.457 +  PARAMETER *par;
 169.458 +  PART *part;			/* multipart doesn't have a row to itself */
 169.459 +  if (body->type == TYPEMULTIPART) {
 169.460 +				/* if not first time, extend prefix */
 169.461 +    if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
 169.462 +    else tmp[0] = '\0';
 169.463 +    for (i = 0,part = body->nested.part; part; part = part->next)
 169.464 +      display_body (&part->body,tmp,i++);
 169.465 +  }
 169.466 +  else {			/* non-multipart, output oneline descriptor */
 169.467 +    if (!pfx) pfx = "";		/* dummy prefix if top level */
 169.468 +    sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
 169.469 +    if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype);
 169.470 +    if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
 169.471 +    if (par = body->parameter) do
 169.472 +      sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
 169.473 +    while (par = par->next);
 169.474 +    if (body->id) sprintf (s += strlen (s),", id = %s",body->id);
 169.475 +    switch (body->type) {	/* bytes or lines depending upon body type */
 169.476 +    case TYPEMESSAGE:		/* encapsulated message */
 169.477 +    case TYPETEXT:		/* plain text */
 169.478 +      sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
 169.479 +      break;
 169.480 +    default:
 169.481 +      sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
 169.482 +      break;
 169.483 +    }
 169.484 +    puts (tmp);			/* output this line */
 169.485 +				/* encapsulated message? */
 169.486 +    if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822") &&
 169.487 +	(body = body->nested.msg->body)) {
 169.488 +      if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1);
 169.489 +      else {			/* build encapsulation prefix */
 169.490 +	sprintf (tmp,"%s%ld.",pfx,i);
 169.491 +	display_body (body,tmp,(long) 0);
 169.492 +      }
 169.493 +    }
 169.494 +  }
 169.495 +}
 169.496 +
 169.497 +/* MM status report
 169.498 + * Accepts: MAIL stream
 169.499 + */
 169.500 +
 169.501 +void status (MAILSTREAM *stream)
 169.502 +{
 169.503 +  unsigned long i;
 169.504 +  char *s,date[MAILTMPLEN];
 169.505 +  THREADER *thr;
 169.506 +  AUTHENTICATOR *auth;
 169.507 +  rfc822_date (date);
 169.508 +  puts (date);
 169.509 +  if (stream) {
 169.510 +    if (stream->mailbox)
 169.511 +      printf (" %s mailbox: %s, %lu messages, %lu recent\n",
 169.512 +	      stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
 169.513 +    else puts ("%No mailbox is open on this stream");
 169.514 +    if (stream->user_flags[0]) {
 169.515 +      printf ("Keywords: %s",stream->user_flags[0]);
 169.516 +      for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
 169.517 +	printf (", %s",stream->user_flags[i]);
 169.518 +      puts ("");
 169.519 +    }
 169.520 +    if (!strcmp (stream->dtb->name,"imap")) {
 169.521 +      if (LEVELIMAP4rev1 (stream)) s = "IMAP4rev1 (RFC 3501)";
 169.522 +      else if (LEVEL1730 (stream)) s = "IMAP4 (RFC 1730)";
 169.523 +      else if (LEVELIMAP2bis (stream)) s = "IMAP2bis";
 169.524 +      else if (LEVEL1176 (stream)) s = "IMAP2 (RFC 1176)";
 169.525 +      else s = "IMAP2 (RFC 1064)";
 169.526 +      printf ("%s server %s\n",s,imap_host (stream));
 169.527 +      if (LEVELIMAP4 (stream)) {
 169.528 +	if (i = imap_cap (stream)->auth) {
 169.529 +	  s = "";
 169.530 +	  printf ("Mutually-supported SASL mechanisms:");
 169.531 +	  while (auth = mail_lookup_auth (find_rightmost_bit (&i) + 1)) {
 169.532 +	    printf (" %s",auth->name);
 169.533 +	    if (!strcmp (auth->name,"PLAIN"))
 169.534 +	      s = "\n  [LOGIN will not be listed here if PLAIN is supported]";
 169.535 +	  }
 169.536 +	  puts (s);
 169.537 +	}
 169.538 +	printf ("Supported standard extensions:\n");
 169.539 +	if (LEVELACL (stream)) puts (" Access Control lists (RFC 2086)");
 169.540 +	if (LEVELQUOTA (stream)) puts (" Quotas (RFC 2087)");
 169.541 +	if (LEVELLITERALPLUS (stream))
 169.542 +	  puts (" Non-synchronizing literals (RFC 2088)");
 169.543 +	if (LEVELIDLE (stream)) puts (" IDLE unsolicited update (RFC 2177)");
 169.544 +	if (LEVELMBX_REF (stream)) puts (" Mailbox referrals (RFC 2193)");
 169.545 +	if (LEVELLOG_REF (stream)) puts (" Login referrals (RFC 2221)");
 169.546 +	if (LEVELANONYMOUS (stream)) puts (" Anonymous access (RFC 2245)");
 169.547 +	if (LEVELNAMESPACE (stream)) puts (" Multiple namespaces (RFC 2342)");
 169.548 +	if (LEVELUIDPLUS (stream)) puts (" Extended UID behavior (RFC 2359)");
 169.549 +	if (LEVELSTARTTLS (stream))
 169.550 +	  puts (" Transport Layer Security (RFC 2595)");
 169.551 +	if (LEVELLOGINDISABLED (stream))
 169.552 +	  puts (" LOGIN command disabled (RFC 2595)");
 169.553 +	if (LEVELID (stream))
 169.554 +	  puts (" Implementation identity negotiation (RFC 2971)");
 169.555 +	if (LEVELCHILDREN (stream))
 169.556 +	  puts (" LIST children announcement (RFC 3348)");
 169.557 +	if (LEVELMULTIAPPEND (stream))
 169.558 +	  puts (" Atomic multiple APPEND (RFC 3502)");
 169.559 +	if (LEVELBINARY (stream))
 169.560 +	  puts (" Binary body content (RFC 3516)");
 169.561 +	if (LEVELUNSELECT (stream)) puts (" Mailbox unselect (RFC 3691)");
 169.562 +	if (LEVELURLAUTH (stream))
 169.563 +	  puts (" URL authenticated fetch (RFC 4467)");
 169.564 +	if (LEVELCATENATE (stream)) puts (" Catenation (RFC 4469)");
 169.565 +	if (LEVELCONDSTORE (stream)) puts (" Conditional STORE (RFC 4551)");
 169.566 +	if (LEVELESEARCH (stream)) puts (" Extended SEARCH (RFC 4731)");
 169.567 +	puts ("Supported draft extensions:");
 169.568 +	if (LEVELSASLIR (stream)) puts (" SASL initial client response");
 169.569 +	if (LEVELSORT (stream)) puts (" Server-based sorting");
 169.570 +	if (LEVELTHREAD (stream)) {
 169.571 +	  printf (" Server-based threading:");
 169.572 +	  for (thr = imap_cap (stream)->threader; thr; thr = thr->next)
 169.573 +	    printf (" %s",thr->name);
 169.574 +	  putchar ('\n');
 169.575 +	}
 169.576 +	if (LEVELSCAN (stream)) puts (" Mailbox text scan");
 169.577 +	if (i = imap_cap (stream)->extlevel) {
 169.578 +	  printf ("Supported BODYSTRUCTURE extensions:");
 169.579 +	  switch (i) {
 169.580 +	  case BODYEXTLOC: printf (" location");
 169.581 +	  case BODYEXTLANG: printf (" language");
 169.582 +	  case BODYEXTDSP: printf (" disposition");
 169.583 +	  case BODYEXTMD5: printf (" MD5\n");
 169.584 +	  }
 169.585 +	}
 169.586 +      }
 169.587 +      else putchar ('\n');
 169.588 +    }
 169.589 +  }
 169.590 +}
 169.591 +
 169.592 +
 169.593 +/* Prompt user for input
 169.594 + * Accepts: pointer to prompt message
 169.595 + *          pointer to input buffer
 169.596 + */
 169.597 +
 169.598 +void prompt (char *msg,char *txt)
 169.599 +{
 169.600 +  printf ("%s",msg);
 169.601 +  gets (txt);
 169.602 +}
 169.603 +
 169.604 +/* Interfaces to C-client */
 169.605 +
 169.606 +
 169.607 +void mm_searched (MAILSTREAM *stream,unsigned long number)
 169.608 +{
 169.609 +}
 169.610 +
 169.611 +
 169.612 +void mm_exists (MAILSTREAM *stream,unsigned long number)
 169.613 +{
 169.614 +}
 169.615 +
 169.616 +
 169.617 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
 169.618 +{
 169.619 +}
 169.620 +
 169.621 +
 169.622 +void mm_flags (MAILSTREAM *stream,unsigned long number)
 169.623 +{
 169.624 +}
 169.625 +
 169.626 +
 169.627 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
 169.628 +{
 169.629 +  mm_log (string,errflg);
 169.630 +}
 169.631 +
 169.632 +
 169.633 +void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
 169.634 +{
 169.635 +  putchar (' ');
 169.636 +  if (delimiter) putchar (delimiter);
 169.637 +  else fputs ("NIL",stdout);
 169.638 +  putchar (' ');
 169.639 +  fputs (mailbox,stdout);
 169.640 +  if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
 169.641 +  if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
 169.642 +  if (attributes & LATT_MARKED) fputs (", marked",stdout);
 169.643 +  if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
 169.644 +  putchar ('\n');
 169.645 +}
 169.646 +
 169.647 +
 169.648 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
 169.649 +{
 169.650 +  putchar (' ');
 169.651 +  if (delimiter) putchar (delimiter);
 169.652 +  else fputs ("NIL",stdout);
 169.653 +  putchar (' ');
 169.654 +  fputs (mailbox,stdout);
 169.655 +  if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
 169.656 +  if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
 169.657 +  if (attributes & LATT_MARKED) fputs (", marked",stdout);
 169.658 +  if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
 169.659 +  putchar ('\n');
 169.660 +}
 169.661 +
 169.662 +
 169.663 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 169.664 +{
 169.665 +  printf (" Mailbox %s",mailbox);
 169.666 +  if (status->flags & SA_MESSAGES) printf (", %lu messages",status->messages);
 169.667 +  if (status->flags & SA_RECENT) printf (", %lu recent",status->recent);
 169.668 +  if (status->flags & SA_UNSEEN) printf (", %lu unseen",status->unseen);
 169.669 +  if (status->flags & SA_UIDVALIDITY) printf (", %lu UID validity",
 169.670 +					      status->uidvalidity);
 169.671 +  if (status->flags & SA_UIDNEXT) printf (", %lu next UID",status->uidnext);
 169.672 +  printf ("\n");
 169.673 +}
 169.674 +
 169.675 +
 169.676 +void mm_log (char *string,long errflg)
 169.677 +{
 169.678 +  switch ((short) errflg) {
 169.679 +  case NIL:
 169.680 +    printf ("[%s]\n",string);
 169.681 +    break;
 169.682 +  case PARSE:
 169.683 +  case WARN:
 169.684 +    printf ("%%%s\n",string);
 169.685 +    break;
 169.686 +  case ERROR:
 169.687 +    printf ("?%s\n",string);
 169.688 +    break;
 169.689 +  }
 169.690 +}
 169.691 +
 169.692 +
 169.693 +void mm_dlog (char *string)
 169.694 +{
 169.695 +  puts (string);
 169.696 +}
 169.697 +
 169.698 +
 169.699 +void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
 169.700 +{
 169.701 +  char *s,tmp[MAILTMPLEN];
 169.702 +  if (curhst) fs_give ((void **) &curhst);
 169.703 +  curhst = (char *) fs_get (1+strlen (mb->host));
 169.704 +  strcpy (curhst,mb->host);
 169.705 +  sprintf (s = tmp,"{%s/%s",mb->host,mb->service);
 169.706 +  if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",strcpy (user,mb->user));
 169.707 +  if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser);
 169.708 +  if (*mb->user) strcat (s = tmp,"} password:");
 169.709 +  else {
 169.710 +    printf ("%s} username: ",tmp);
 169.711 +    fgets (user,NETMAXUSER-1,stdin);
 169.712 +    user[NETMAXUSER-1] = '\0';
 169.713 +    if (s = strchr (user,'\n')) *s = '\0';
 169.714 +    s = "password: ";
 169.715 +  }
 169.716 +  if (curusr) fs_give ((void **) &curusr);
 169.717 +  curusr = cpystr (user);
 169.718 +  strcpy (pwd,getpass (s));
 169.719 +}
 169.720 +
 169.721 +
 169.722 +void mm_critical (MAILSTREAM *stream)
 169.723 +{
 169.724 +}
 169.725 +
 169.726 +
 169.727 +void mm_nocritical (MAILSTREAM *stream)
 169.728 +{
 169.729 +}
 169.730 +
 169.731 +
 169.732 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
 169.733 +{
 169.734 +#if UNIXLIKE
 169.735 +  kill (getpid (),SIGSTOP);
 169.736 +#else
 169.737 +  abort ();
 169.738 +#endif
 169.739 +  return NIL;
 169.740 +}
 169.741 +
 169.742 +
 169.743 +void mm_fatal (char *string)
 169.744 +{
 169.745 +  printf ("?%s\n",string);
 169.746 +}
 169.747 +
 169.748 +/* SMTP tester */
 169.749 +
 169.750 +void smtptest (long debug)
 169.751 +{
 169.752 +  SENDSTREAM *stream = NIL;
 169.753 +  char line[MAILTMPLEN];
 169.754 +  char *text = (char *) fs_get (8*MAILTMPLEN);
 169.755 +  ENVELOPE *msg = mail_newenvelope ();
 169.756 +  BODY *body = mail_newbody ();
 169.757 +  msg->from = mail_newaddr ();
 169.758 +  msg->from->personal = cpystr (personalname);
 169.759 +  msg->from->mailbox = cpystr (curusr);
 169.760 +  msg->from->host = cpystr (curhst);
 169.761 +  msg->return_path = mail_newaddr ();
 169.762 +  msg->return_path->mailbox = cpystr (curusr);
 169.763 +  msg->return_path->host = cpystr (curhst);
 169.764 +  prompt ("To: ",line);
 169.765 +  rfc822_parse_adrlist (&msg->to,line,curhst);
 169.766 +  if (msg->to) {
 169.767 +    prompt ("cc: ",line);
 169.768 +    rfc822_parse_adrlist (&msg->cc,line,curhst);
 169.769 +  }
 169.770 +  else {
 169.771 +    prompt ("Newsgroups: ",line);
 169.772 +    if (*line) msg->newsgroups = cpystr (line);
 169.773 +    else {
 169.774 +      mail_free_body (&body);
 169.775 +      mail_free_envelope (&msg);
 169.776 +      fs_give ((void **) &text);
 169.777 +      return;
 169.778 +    }
 169.779 +  }
 169.780 +  prompt ("Subject: ",line);
 169.781 +  msg->subject = cpystr (line);
 169.782 +  puts (" Msg (end with a line with only a '.'):");
 169.783 +  body->type = TYPETEXT;
 169.784 +  *text = '\0';
 169.785 +  while (gets (line)) {
 169.786 +    if (line[0] == '.') {
 169.787 +      if (line[1] == '\0') break;
 169.788 +      else strcat (text,".");
 169.789 +    }
 169.790 +    strcat (text,line);
 169.791 +    strcat (text,"\015\012");
 169.792 +  }
 169.793 +  body->contents.text.data = (unsigned char *) text;
 169.794 +  body->contents.text.size = strlen (text);
 169.795 +  rfc822_date (line);
 169.796 +  msg->date = (char *) fs_get (1+strlen (line));
 169.797 +  strcpy (msg->date,line);
 169.798 +  if (msg->to) {
 169.799 +    puts ("Sending...");
 169.800 +    if (stream = smtp_open (hostlist,debug)) {
 169.801 +      if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]");
 169.802 +      else printf ("[Failed - %s]\n",stream->reply);
 169.803 +    }
 169.804 +  }
 169.805 +  else {
 169.806 +    puts ("Posting...");
 169.807 +    if (stream = nntp_open (newslist,debug)) {
 169.808 +      if (nntp_mail (stream,msg,body)) puts ("[Ok]");
 169.809 +      else printf ("[Failed - %s]\n",stream->reply);
 169.810 +    }
 169.811 +  }
 169.812 +  if (stream) smtp_close (stream);
 169.813 +  else puts ("[Can't open connection to any server]");
 169.814 +  mail_free_envelope (&msg);
 169.815 +  mail_free_body (&body);
 169.816 +}
   170.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   170.2 +++ b/src/osdep/amiga/Makefile	Mon Sep 14 15:17:45 2009 +0900
   170.3 @@ -0,0 +1,231 @@
   170.4 +# ========================================================================
   170.5 +# Copyright 1988-2006 University of Washington
   170.6 +#
   170.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   170.8 +# you may not use this file except in compliance with the License.
   170.9 +# You may obtain a copy of the License at
  170.10 +#
  170.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  170.12 +#
  170.13 +# 
  170.14 +# ========================================================================
  170.15 +
  170.16 +
  170.17 +# Program:	C client makefile for Amiga
  170.18 +#
  170.19 +# Author:	Mark Crispin
  170.20 +#		Networks and Distributed Computing
  170.21 +#		Computing & Communications
  170.22 +#		University of Washington
  170.23 +#		Administration Building, AG-44
  170.24 +#		Seattle, WA  98195
  170.25 +#		Internet: MRC@CAC.Washington.EDU
  170.26 +#
  170.27 +# Date:		11 May 1989
  170.28 +# Last Edited:	5 November 2006
  170.29 +
  170.30 +
  170.31 +# Command line build parameters
  170.32 +
  170.33 +EXTRAAUTHENTICATORS=
  170.34 +EXTRADRIVERS=mbox
  170.35 +PASSWDTYPE=std
  170.36 +
  170.37 +
  170.38 +# Build parameters normally set by the individual port
  170.39 +
  170.40 +AMICFLAGS=-O -DNO_INLINE_STDARG -Dunix
  170.41 +AMILDFLAGS=/pine/libc.a -lamiga -lauto
  170.42 +CHECKPW=std
  170.43 +LOGINPW=std
  170.44 +ACTIVEFILE=/UULib/News/Active
  170.45 +SPOOLDIR=/usr/spool
  170.46 +MAILSPOOL=/AmiTCP/Mail
  170.47 +NEWSSPOOL=/UUNews
  170.48 +MD5PWD="/etc/cram-md5.pwd"
  170.49 +
  170.50 +
  170.51 +# Default formats for creating new mailboxes and for empty mailboxes in the
  170.52 +# default namespace; must be set to the associated driver's prototype.
  170.53 +#
  170.54 +# The CREATEPROTO is the default format for new mailbox creation.
  170.55 +# The EMPTYPROTO is the default format for handling zero-byte files.
  170.56 +#
  170.57 +# Normally, this is set by the individual port.
  170.58 +#
  170.59 +# NOTE: namespace formats (e.g. mh and news) can not be set as a default format
  170.60 +# since they do not exist in the default namespace.  Also, it is meaningless to
  170.61 +# set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since
  170.62 +# these formats can never be empty files.
  170.63 +
  170.64 +CREATEPROTO=unixproto
  170.65 +EMPTYPROTO=unixproto
  170.66 +
  170.67 +
  170.68 +# Commands possibly overriden by the individual port
  170.69 +
  170.70 +ARRC=ar rc
  170.71 +CC=cc
  170.72 +LN=cp
  170.73 +RANLIB=ranlib
  170.74 +RM=rm -f
  170.75 +
  170.76 +
  170.77 +# Standard distribution build parameters
  170.78 +
  170.79 +DEFAULTAUTHENTICATORS=ext md5 pla log
  170.80 +DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
  170.81 +CHUNKSIZE=65536
  170.82 +
  170.83 +
  170.84 +# Normally no need to change any of these
  170.85 +
  170.86 +ARCHIVE=c-client.a
  170.87 +BINARIES=mail.o misc.o newsrc.o smanager.o osdep.o utf8.o utf8aux.o \
  170.88 + dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
  170.89 + rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
  170.90 + unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
  170.91 +CFLAGS=$(BASECFLAGS) $(EXTRACFLAGS)
  170.92 +MAKE=make
  170.93 +MV=mv
  170.94 +SHELL=/bin/sh
  170.95 +
  170.96 +
  170.97 +# Primary build command
  170.98 +
  170.99 +BUILDOPTIONS= EXTRACFLAGS=$(EXTRACFLAGS) EXTRALDFLAGS=$(EXTRALDFLAGS)\
 170.100 + EXTRADRIVERS=$(EXTRADRIVERS) EXTRAAUTHENTICATORS=$(EXTRAAUTHENTICATORS)\
 170.101 + PASSWDTYPE=$(PASSWDTYPE)
 170.102 +BUILD=$(MAKE) build $(BUILDOPTIONS) $(SPECIALS)
 170.103 +
 170.104 +
 170.105 +# Here if no make argument established
 170.106 +
 170.107 +missing: osdep.h
 170.108 +	$(MAKE) $(ARCHIVE) CC=`cat CCTYPE` CFLAGS="`cat CFLAGS`"
 170.109 +
 170.110 +osdep.h:
 170.111 +	@echo You must specify what type of system
 170.112 +	@false
 170.113 +
 170.114 +
 170.115 +# Current ports
 170.116 +
 170.117 +ami:	# AmigaDOS
 170.118 +	$(BUILD) OS=$@ \
 170.119 +	 BASECFLAGS="-DOLD $(AMICFLAGS)" \
 170.120 +	 BASELDFLAGS="$(AMILDFLAGS) -lamitcp000" \
 170.121 +	 CC=gcc
 170.122 +
 170.123 +am2:	# AmigaDOS with a 68020+
 170.124 +	$(BUILD) OS=ami \
 170.125 +	 BASECFLAGS="-DOLD -m68020 $(AMICFLAGS)" \
 170.126 +	 BASELDFLAGS="$(AMILDFLAGS) -lamitcp" \
 170.127 +	 CC=gcc
 170.128 +
 170.129 +amn:	# AmigaDOS with a 680x0 using "new" socket library
 170.130 +	$(BUILD) OS=ami \
 170.131 +	 BASELDFLAGS="$(AMILDFLAGS) -lnewamitcp000" \
 170.132 +	 CC=gcc
 170.133 +
 170.134 +ama:	# AmigaDOS using AS225R2
 170.135 +	$(BUILD) OS=ami \
 170.136 +	 MAILSPOOL=/INet/Mail \
 170.137 +	 BASECFLAGS="-m68020 $(AMICFLAGS)" \
 170.138 +	 BASELDFLAGS="$(AMILDFLAGS) -las225r2" \
 170.139 +	 CC=gcc
 170.140 +
 170.141 +# Build it!
 170.142 +
 170.143 +build:	clean once ckp$(PASSWDTYPE) $(EXTRAAUTHENTICATORS) $(ARCHIVE)
 170.144 +
 170.145 +$(ARCHIVE): $(BINARIES)
 170.146 +	$(RM) $(ARCHIVE) || true
 170.147 +	$(ARRC) $(ARCHIVE) $(BINARIES)
 170.148 +	$(RANLIB) $(ARCHIVE)
 170.149 +
 170.150 +# Cleanup
 170.151 +
 170.152 +clean:
 170.153 +	$(RM) *.o linkage.[ch] auths.c $(ARCHIVE) osdep.* *TYPE *FLAGS || true
 170.154 +
 170.155 +
 170.156 +# Dependencies
 170.157 +
 170.158 +dummy.o: mail.h misc.h osdep.h dummy.h
 170.159 +fdstring.o: mail.h misc.h osdep.h fdstring.h
 170.160 +flstring.o: mail.h misc.h osdep.h flstring.h
 170.161 +imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h
 170.162 +mail.o: mail.h misc.h osdep.h rfc822.h linkage.h
 170.163 +mbx.o: mail.h misc.h osdep.h dummy.h
 170.164 +mh.o: mail.h misc.h osdep.h mh.h dummy.h
 170.165 +mix.o: mail.h misc.h osdep.h dummy.h
 170.166 +mx.o: mail.h misc.h osdep.h mx.h dummy.h
 170.167 +misc.o: mail.h misc.h osdep.h
 170.168 +mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h
 170.169 +mtx.o: mail.h misc.h osdep.h dummy.h
 170.170 +netmsg.o: mail.h misc.h osdep.h netmsg.h
 170.171 +news.o: mail.h misc.h osdep.h
 170.172 +newsrc.o: mail.h misc.h osdep.h newsrc.h
 170.173 +nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h
 170.174 +phile.o: mail.h misc.h osdep.h rfc822.h dummy.h
 170.175 +pseudo.o: pseudo.h
 170.176 +pop3.o: mail.h misc.h osdep.h pop3.h rfc822.h
 170.177 +smanager.o: mail.h misc.h osdep.h
 170.178 +smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h
 170.179 +rfc822.o: mail.h misc.h osdep.h rfc822.h
 170.180 +tenex.o: mail.h misc.h osdep.h dummy.h
 170.181 +unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
 170.182 +utf8.o: mail.h misc.h osdep.h utf8.h
 170.183 +utf8aux.o: mail.h misc.h osdep.h utf8.h
 170.184 +
 170.185 +
 170.186 +# OS-dependent
 170.187 +
 170.188 +osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \
 170.189 +	osdep.h env_ami.h tcp_ami.h \
 170.190 +	osdep.c env_ami.c fs_ami.c ftl_ami.c nl_ami.c tcp_ami.c \
 170.191 +	auths.c gethstid.c \
 170.192 +	gr_waitp.c \
 170.193 +	auth_log.c auth_md5.c auth_pla.c \
 170.194 +	pmatch.c scandir.c \
 170.195 +	tz_bsd.c \
 170.196 +	write.c \
 170.197 +	strerror.c strpbrk.c strstr.c strtok.c strtoul.c \
 170.198 +	OSCFLAGS
 170.199 +	$(CC) $(CFLAGS) `cat OSCFLAGS` -c osdep.c
 170.200 +
 170.201 +osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c
 170.202 +	$(RM) osdep.c || true
 170.203 +	cat osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c
 170.204 +
 170.205 +
 170.206 +# Once-only environment setup
 170.207 +
 170.208 +once:
 170.209 +	@echo Once-only environment setup...
 170.210 +	./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy
 170.211 +	./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
 170.212 +	echo $(CC) > CCTYPE
 170.213 +	echo $(CFLAGS) -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS
 170.214 +	echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \
 170.215 +	 -DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \
 170.216 +	 -DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \
 170.217 +	 -DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" > OSCFLAGS
 170.218 +	echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS
 170.219 +	$(LN) os_$(OS).h osdep.h
 170.220 +	$(LN) os_$(OS).c osdepbas.c
 170.221 +	$(LN) log_$(LOGINPW).c osdeplog.c
 170.222 +	$(LN) ssl_none.c osdepssl.c
 170.223 +
 170.224 +
 170.225 +# Password checkers
 170.226 +
 170.227 +ckpstd:	# Port standard
 170.228 +	$(LN) ckp_$(CHECKPW).c osdepckp.c
 170.229 +
 170.230 +
 170.231 +# A monument to a hack of long ago and far away...
 170.232 +
 170.233 +love:
 170.234 +	@echo not war?
   171.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   171.2 +++ b/src/osdep/amiga/ckp_std.c	Mon Sep 14 15:17:45 2009 +0900
   171.3 @@ -0,0 +1,42 @@
   171.4 +/* ========================================================================
   171.5 + * Copyright 1988-2006 University of Washington
   171.6 + *
   171.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   171.8 + * you may not use this file except in compliance with the License.
   171.9 + * You may obtain a copy of the License at
  171.10 + *
  171.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  171.12 + *
  171.13 + * 
  171.14 + * ========================================================================
  171.15 + */
  171.16 +
  171.17 +/*
  171.18 + * Program:	Standard check password
  171.19 + *
  171.20 + * Author:	Mark Crispin
  171.21 + *		Networks and Distributed Computing
  171.22 + *		Computing & Communications
  171.23 + *		University of Washington
  171.24 + *		Administration Building, AG-44
  171.25 + *		Seattle, WA  98195
  171.26 + *		Internet: MRC@CAC.Washington.EDU
  171.27 + *
  171.28 + * Date:	1 August 1988
  171.29 + * Last Edited:	30 August 2006
  171.30 + */
  171.31 +
  171.32 +/* Check password
  171.33 + * Accepts: login passwd struct
  171.34 + *	    password string
  171.35 + *	    argument count
  171.36 + *	    argument vector
  171.37 + * Returns: passwd struct if password validated, NIL otherwise
  171.38 + */
  171.39 +
  171.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  171.41 +{
  171.42 +  return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  171.43 +	  !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ?
  171.44 +	    pw : NIL;
  171.45 +}
   172.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   172.2 +++ b/src/osdep/amiga/drivers	Mon Sep 14 15:17:45 2009 +0900
   172.3 @@ -0,0 +1,36 @@
   172.4 +#!/bin/sh
   172.5 +# ========================================================================
   172.6 +# Copyright 1988-2006 University of Washington
   172.7 +#
   172.8 +# Licensed under the Apache License, Version 2.0 (the "License");
   172.9 +# you may not use this file except in compliance with the License.
  172.10 +# You may obtain a copy of the License at
  172.11 +#
  172.12 +#     http://www.apache.org/licenses/LICENSE-2.0
  172.13 +#
  172.14 +# 
  172.15 +# ========================================================================
  172.16 +
  172.17 +# Program:	Driver Linkage Generator
  172.18 +#
  172.19 +# Author:	Mark Crispin
  172.20 +#		Networks and Distributed Computing
  172.21 +#		Computing & Communications
  172.22 +#		University of Washington
  172.23 +#		Administration Building, AG-44
  172.24 +#		Seattle, WA  98195
  172.25 +#		Internet: MRC@CAC.Washington.EDU
  172.26 +#
  172.27 +# Date:		11 October 1989
  172.28 +# Last Edited:	30 August 2006
  172.29 +
  172.30 +
  172.31 +# Erase old driver linkage
  172.32 +rm -f linkage.[ch]
  172.33 +
  172.34 +# Now define the new list
  172.35 +for driver
  172.36 + do
  172.37 +  echo "extern DRIVER "$driver"driver;" >> linkage.h
  172.38 +  echo "  mail_link (&"$driver"driver);		/* link in the $driver driver */" | cat >> linkage.c
  172.39 +done
   173.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   173.2 +++ b/src/osdep/amiga/dummy.c	Mon Sep 14 15:17:45 2009 +0900
   173.3 @@ -0,0 +1,809 @@
   173.4 +/* ========================================================================
   173.5 + * Copyright 1988-2007 University of Washington
   173.6 + *
   173.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   173.8 + * you may not use this file except in compliance with the License.
   173.9 + * You may obtain a copy of the License at
  173.10 + *
  173.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  173.12 + *
  173.13 + * 
  173.14 + * ========================================================================
  173.15 + */
  173.16 +
  173.17 +/*
  173.18 + * Program:	Dummy routines
  173.19 + *
  173.20 + * Author:	Mark Crispin
  173.21 + *		Networks and Distributed Computing
  173.22 + *		Computing & Communications
  173.23 + *		University of Washington
  173.24 + *		Administration Building, AG-44
  173.25 + *		Seattle, WA  98195
  173.26 + *		Internet: MRC@CAC.Washington.EDU
  173.27 + *
  173.28 + * Date:	9 May 1991
  173.29 + * Last Edited:	1 June 2007
  173.30 + */
  173.31 +
  173.32 +
  173.33 +#include <stdio.h>
  173.34 +#include <ctype.h>
  173.35 +#include <errno.h>
  173.36 +extern int errno;		/* just in case */
  173.37 +#include "mail.h"
  173.38 +#include "osdep.h"
  173.39 +#include <pwd.h>
  173.40 +#include <sys/stat.h>
  173.41 +#include "dummy.h"
  173.42 +#include "misc.h"
  173.43 +
  173.44 +/* Function prototypes */
  173.45 +
  173.46 +DRIVER *dummy_valid (char *name);
  173.47 +void *dummy_parameters (long function,void *value);
  173.48 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
  173.49 +		      long level);
  173.50 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
  173.51 +		   long attributes,char *contents);
  173.52 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
  173.53 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  173.54 +void dummy_close (MAILSTREAM *stream,long options);
  173.55 +long dummy_ping (MAILSTREAM *stream);
  173.56 +void dummy_check (MAILSTREAM *stream);
  173.57 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  173.58 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  173.59 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  173.60 +
  173.61 +/* Dummy routines */
  173.62 +
  173.63 +
  173.64 +/* Driver dispatch used by MAIL */
  173.65 +
  173.66 +DRIVER dummydriver = {
  173.67 +  "dummy",			/* driver name */
  173.68 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  173.69 +  (DRIVER *) NIL,		/* next driver */
  173.70 +  dummy_valid,			/* mailbox is valid for us */
  173.71 +  dummy_parameters,		/* manipulate parameters */
  173.72 +  dummy_scan,			/* scan mailboxes */
  173.73 +  dummy_list,			/* list mailboxes */
  173.74 +  dummy_lsub,			/* list subscribed mailboxes */
  173.75 +  dummy_subscribe,		/* subscribe to mailbox */
  173.76 +  NIL,				/* unsubscribe from mailbox */
  173.77 +  dummy_create,			/* create mailbox */
  173.78 +  dummy_delete,			/* delete mailbox */
  173.79 +  dummy_rename,			/* rename mailbox */
  173.80 +  mail_status_default,		/* status of mailbox */
  173.81 +  dummy_open,			/* open mailbox */
  173.82 +  dummy_close,			/* close mailbox */
  173.83 +  NIL,				/* fetch message "fast" attributes */
  173.84 +  NIL,				/* fetch message flags */
  173.85 +  NIL,				/* fetch overview */
  173.86 +  NIL,				/* fetch message structure */
  173.87 +  NIL,				/* fetch header */
  173.88 +  NIL,				/* fetch text */
  173.89 +  NIL,				/* fetch message data */
  173.90 +  NIL,				/* unique identifier */
  173.91 +  NIL,				/* message number from UID */
  173.92 +  NIL,				/* modify flags */
  173.93 +  NIL,				/* per-message modify flags */
  173.94 +  NIL,				/* search for message based on criteria */
  173.95 +  NIL,				/* sort messages */
  173.96 +  NIL,				/* thread messages */
  173.97 +  dummy_ping,			/* ping mailbox to see if still alive */
  173.98 +  dummy_check,			/* check for new messages */
  173.99 +  dummy_expunge,		/* expunge deleted messages */
 173.100 +  dummy_copy,			/* copy messages to another mailbox */
 173.101 +  dummy_append,			/* append string message to mailbox */
 173.102 +  NIL				/* garbage collect stream */
 173.103 +};
 173.104 +
 173.105 +				/* prototype stream */
 173.106 +MAILSTREAM dummyproto = {&dummydriver};
 173.107 +
 173.108 +/* Dummy validate mailbox
 173.109 + * Accepts: mailbox name
 173.110 + * Returns: our driver if name is valid, NIL otherwise
 173.111 + */
 173.112 +
 173.113 +DRIVER *dummy_valid (char *name)
 173.114 +{
 173.115 +  char *s,tmp[MAILTMPLEN];
 173.116 +  struct stat sbuf;
 173.117 +				/* must be valid local mailbox */
 173.118 +  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
 173.119 +				/* indeterminate clearbox INBOX */
 173.120 +    if (!*s) return &dummydriver;
 173.121 +    else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
 173.122 +    case S_IFREG:
 173.123 +    case S_IFDIR:
 173.124 +      return &dummydriver;
 173.125 +    }
 173.126 +				/* blackbox INBOX does not exist yet */
 173.127 +    else if (!compare_cstring (name,"INBOX")) return &dummydriver;
 173.128 +  }
 173.129 +  return NIL;
 173.130 +}
 173.131 +
 173.132 +
 173.133 +/* Dummy manipulate driver parameters
 173.134 + * Accepts: function code
 173.135 + *	    function-dependent value
 173.136 + * Returns: function-dependent return value
 173.137 + */
 173.138 +
 173.139 +void *dummy_parameters (long function,void *value)
 173.140 +{
 173.141 +  void *ret = NIL;
 173.142 +  switch ((int) function) {
 173.143 +  case GET_INBOXPATH:
 173.144 +    if (value) ret = dummy_file ((char *) value,"INBOX");
 173.145 +    break;
 173.146 +  }
 173.147 +  return ret;
 173.148 +}
 173.149 +
 173.150 +/* Dummy scan mailboxes
 173.151 + * Accepts: mail stream
 173.152 + *	    reference
 173.153 + *	    pattern to search
 173.154 + *	    string to scan
 173.155 + */
 173.156 +
 173.157 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 173.158 +{
 173.159 +  DRIVER *drivers;
 173.160 +  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
 173.161 +  long i;
 173.162 +  if (!pat || !*pat) {		/* empty pattern? */
 173.163 +    if (dummy_canonicalize (test,ref,"*")) {
 173.164 +				/* tie off name at root */
 173.165 +      if (s = strchr (test,'/')) *++s = '\0';
 173.166 +      else test[0] = '\0';
 173.167 +      dummy_listed (stream,'/',test,LATT_NOSELECT,NIL);
 173.168 +    }
 173.169 +  }
 173.170 +				/* get canonical form of name */
 173.171 +  else if (dummy_canonicalize (test,ref,pat)) {
 173.172 +				/* found any wildcards? */
 173.173 +    if (s = strpbrk (test,"%*")) {
 173.174 +				/* yes, copy name up to that point */
 173.175 +      strncpy (file,test,i = s - test);
 173.176 +      file[i] = '\0';		/* tie off */
 173.177 +    }
 173.178 +    else strcpy (file,test);	/* use just that name then */
 173.179 +    if (s = strrchr (file,'/')){/* find directory name */
 173.180 +      *++s = '\0';		/* found, tie off at that point */
 173.181 +      s = file;
 173.182 +    }
 173.183 +				/* silly case */
 173.184 +    else if ((file[0] == '~') || (file[0] == '#')) s = file;
 173.185 +				/* do the work */
 173.186 +    dummy_list_work (stream,s,test,contents,0);
 173.187 +				/* always an INBOX */
 173.188 +    if (pmatch ("INBOX",ucase (test))) {
 173.189 +				/* done if have a dirfmt INBOX */
 173.190 +      for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
 173.191 +	   drivers && !(!(drivers->flags & DR_DISABLE) &&
 173.192 +			(drivers->flags & DR_DIRFMT) &&
 173.193 +			(*drivers->valid) ("INBOX")); drivers = drivers->next);
 173.194 +				/* list INBOX appropriately */
 173.195 +      dummy_listed (stream,drivers ? '/' : NIL,"INBOX",
 173.196 +		    drivers ? NIL : LATT_NOINFERIORS,contents);
 173.197 +    }
 173.198 +  }
 173.199 +}
 173.200 +
 173.201 +
 173.202 +/* Dummy list mailboxes
 173.203 + * Accepts: mail stream
 173.204 + *	    reference
 173.205 + *	    pattern to search
 173.206 + */
 173.207 +
 173.208 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 173.209 +{
 173.210 +  dummy_scan (stream,ref,pat,NIL);
 173.211 +}
 173.212 +
 173.213 +/* Dummy list subscribed mailboxes
 173.214 + * Accepts: mail stream
 173.215 + *	    reference
 173.216 + *	    pattern to search
 173.217 + */
 173.218 +
 173.219 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 173.220 +{
 173.221 +  void *sdb = NIL;
 173.222 +  char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN];
 173.223 +  int showuppers = pat[strlen (pat) - 1] == '%';
 173.224 +				/* get canonical form of name */
 173.225 +  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
 173.226 +    if (*s != '{') {
 173.227 +      if (!compare_cstring (s,"INBOX") &&
 173.228 +	  pmatch ("INBOX",ucase (strcpy (tmp,test))))
 173.229 +	mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
 173.230 +      else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
 173.231 +      else while (showuppers && (t = strrchr (s,'/'))) {
 173.232 +	*t = '\0';		/* tie off the name */
 173.233 +	if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT);
 173.234 +      }
 173.235 +    }
 173.236 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 173.237 +}
 173.238 +
 173.239 +
 173.240 +/* Dummy subscribe to mailbox
 173.241 + * Accepts: mail stream
 173.242 + *	    mailbox to add to subscription list
 173.243 + * Returns: T on success, NIL on failure
 173.244 + */
 173.245 +
 173.246 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
 173.247 +{
 173.248 +  char *s,tmp[MAILTMPLEN];
 173.249 +  struct stat sbuf;
 173.250 +				/* must be valid local mailbox */
 173.251 +  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf))
 173.252 +    switch (sbuf.st_mode & S_IFMT) {
 173.253 +    case S_IFDIR:		/* allow but snarl */
 173.254 +      sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s",
 173.255 +	       mailbox);
 173.256 +      MM_NOTIFY (stream,tmp,WARN);
 173.257 +    case S_IFREG:
 173.258 +      return sm_subscribe (mailbox);
 173.259 +    }
 173.260 +  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
 173.261 +  MM_LOG (tmp,ERROR);
 173.262 +  return NIL;
 173.263 +}
 173.264 +
 173.265 +/* Dummy list mailboxes worker routine
 173.266 + * Accepts: mail stream
 173.267 + *	    directory name to search
 173.268 + *	    search pattern
 173.269 + *	    string to scan
 173.270 + *	    search level
 173.271 + */
 173.272 +
 173.273 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
 173.274 +		      long level)
 173.275 +{
 173.276 +  DRIVER *drivers;
 173.277 +  dirfmttest_t dt;
 173.278 +  DIR *dp;
 173.279 +  struct direct *d;
 173.280 +  struct stat sbuf;
 173.281 +  char tmp[MAILTMPLEN],path[MAILTMPLEN];
 173.282 +  size_t len = 0;
 173.283 +				/* punt if bogus name */
 173.284 +  if (!mailboxdir (tmp,dir,NIL)) return;
 173.285 +  if (dp = opendir (tmp)) {	/* do nothing if can't open directory */
 173.286 +				/* see if a non-namespace directory format */
 173.287 +    for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
 173.288 +	 dir && !dt && drivers; drivers = drivers->next)
 173.289 +      if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) &&
 173.290 +	  (*drivers->valid) (dir))
 173.291 +	dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL);
 173.292 +				/* list it if at top-level */
 173.293 +    if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX"))
 173.294 +      dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents);
 173.295 +
 173.296 +				/* scan directory, ignore . and .. */
 173.297 +    if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp))
 173.298 +      if ((!(dt && (*dt) (d->d_name))) &&
 173.299 +	  ((d->d_name[0] != '.') ||
 173.300 +	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
 173.301 +	    (d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) &&
 173.302 +	  ((len + strlen (d->d_name)) <= NETMAXMBX)) {
 173.303 +				/* see if name is useful */
 173.304 +	if (dir) sprintf (tmp,"%s%s",dir,d->d_name);
 173.305 +	else strcpy (tmp,d->d_name);
 173.306 +				/* make sure useful and can get info */
 173.307 +	if ((pmatch_full (strcpy (path,tmp),pat,'/') ||
 173.308 +	     pmatch_full (strcat (path,"/"),pat,'/') ||
 173.309 +	     dmatch (path,pat,'/')) &&
 173.310 +	    mailboxdir (path,dir,"x") && (len = strlen (path)) &&
 173.311 +	    strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) {
 173.312 +				/* only interested in file type */
 173.313 +	  switch (sbuf.st_mode & S_IFMT) {
 173.314 +	  case S_IFDIR:		/* directory? */
 173.315 +				/* form with trailing / */
 173.316 +	    sprintf (path,"%s/",tmp);
 173.317 +				/* skip listing if INBOX */
 173.318 +	    if (!pmatch (tmp,"INBOX")) {
 173.319 +	      if (pmatch_full (tmp,pat,'/')) {
 173.320 +		if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents))
 173.321 +		  break;
 173.322 +	      }
 173.323 +				/* try again with trailing / */
 173.324 +	      else if (pmatch_full (path,pat,'/') &&
 173.325 +		       !dummy_listed (stream,'/',path,LATT_NOSELECT,contents))
 173.326 +		break;
 173.327 +	    }
 173.328 +	    if (dmatch (path,pat,'/') &&
 173.329 +		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 173.330 +	      dummy_list_work (stream,path,pat,contents,level+1);
 173.331 +	    break;
 173.332 +	  case S_IFREG:		/* ordinary name */
 173.333 +	    /* Must use ctime for systems that don't update mtime properly */
 173.334 +	    if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX"))
 173.335 +	      dummy_listed (stream,'/',tmp,LATT_NOINFERIORS +
 173.336 +			    ((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))?
 173.337 +			     LATT_MARKED : LATT_UNMARKED),contents);
 173.338 +	    break;
 173.339 +	  }
 173.340 +	}
 173.341 +      }
 173.342 +    closedir (dp);		/* all done, flush directory */
 173.343 +  }
 173.344 +}
 173.345 +
 173.346 +/* Scan file for contents
 173.347 + * Accepts: driver to use
 173.348 + *	    file name
 173.349 + *	    desired contents
 173.350 + *	    length of contents
 173.351 + *	    size of file
 173.352 + * Returns: NIL if contents not found, T if found
 173.353 + */
 173.354 +
 173.355 +long scan_contents (DRIVER *dtb,char *name,char *contents,
 173.356 +		    unsigned long csiz,unsigned long fsiz)
 173.357 +{
 173.358 +  scancontents_t sc = dtb ?
 173.359 +    (scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL;
 173.360 +  return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz);
 173.361 +}
 173.362 +
 173.363 +
 173.364 +/* Scan file for contents
 173.365 + * Accepts: file name
 173.366 + *	    desired contents
 173.367 + *	    length of contents
 173.368 + *	    size of file
 173.369 + * Returns: NIL if contents not found, T if found
 173.370 + */
 173.371 +
 173.372 +#define BUFSIZE 4*MAILTMPLEN
 173.373 +
 173.374 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
 173.375 +			  unsigned long fsiz)
 173.376 +{
 173.377 +  int fd;
 173.378 +  unsigned long ssiz,bsiz;
 173.379 +  char *buf;
 173.380 +				/* forget it if can't select or open */
 173.381 +  if ((fd = open (name,O_RDONLY,NIL)) >= 0) {
 173.382 +				/* get buffer including slop */    
 173.383 +    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
 173.384 +    memset (buf,'\0',ssiz);	/* no slop area the first time */
 173.385 +    while (fsiz) {		/* until end of file */
 173.386 +      read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE));
 173.387 +      if (search ((unsigned char *) buf,bsiz+ssiz,
 173.388 +		  (unsigned char *) contents,csiz)) break;
 173.389 +      memcpy (buf,buf+BUFSIZE,ssiz);
 173.390 +      fsiz -= bsiz;		/* note that we read that much */
 173.391 +    }
 173.392 +    fs_give ((void **) &buf);	/* flush buffer */
 173.393 +    close (fd);			/* finished with file */
 173.394 +    if (fsiz) return T;		/* found */
 173.395 +  }
 173.396 +  return NIL;			/* not found */
 173.397 +}
 173.398 +
 173.399 +/* Mailbox found
 173.400 + * Accepts: MAIL stream
 173.401 + *	    hierarchy delimiter
 173.402 + *	    mailbox name
 173.403 + *	    attributes
 173.404 + *	    contents to search before calling mm_list()
 173.405 + * Returns: NIL if should abort hierarchy search, else T (currently always)
 173.406 + */
 173.407 +
 173.408 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
 173.409 +		   long attributes,char *contents)
 173.410 +{
 173.411 +  DRIVER *d;
 173.412 +  DIR *dp;
 173.413 +  struct direct *dr;
 173.414 +  dirfmttest_t dt;
 173.415 +  unsigned long csiz;
 173.416 +  struct stat sbuf;
 173.417 +  int nochild;
 173.418 +  char *s,tmp[MAILTMPLEN];
 173.419 +  if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
 173.420 +      (dp = opendir (tmp))) {	/* if not \NoInferiors */
 173.421 +				/* locate dirfmttest if any */
 173.422 +    for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
 173.423 +	 !dt && d; d = d->next)
 173.424 +      if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) &&
 173.425 +	  (*d->valid) (name))
 173.426 +	dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL);
 173.427 +				/* scan directory for children */
 173.428 +    for (nochild = T; nochild && (dr = readdir (dp)); )
 173.429 +      if ((!(dt && (*dt) (dr->d_name))) &&
 173.430 +	  ((dr->d_name[0] != '.') ||
 173.431 +	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
 173.432 +	    (dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2])))))
 173.433 +	nochild = NIL;
 173.434 +    attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
 173.435 +    closedir (dp);		/* all done, flush directory */
 173.436 +  }
 173.437 +  d = NIL;			/* don't \NoSelect dir if it has a driver */
 173.438 +  if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
 173.439 +      (d != &dummydriver)) attributes &= ~LATT_NOSELECT;
 173.440 +  if (!contents ||		/* notify main program */
 173.441 +      (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
 173.442 +       (s = mailboxfile (tmp,name)) &&
 173.443 +       (*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) &&
 173.444 +       !stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) &&
 173.445 +       SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size)))
 173.446 +    mm_list (stream,delimiter,name,attributes);
 173.447 +  return T;
 173.448 +}
 173.449 +
 173.450 +/* Dummy create mailbox
 173.451 + * Accepts: mail stream
 173.452 + *	    mailbox name to create
 173.453 + * Returns: T on success, NIL on failure
 173.454 + */
 173.455 +
 173.456 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 173.457 +{
 173.458 +  char *s,tmp[MAILTMPLEN];
 173.459 +  long ret = NIL;
 173.460 +				/* validate name */
 173.461 +  if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
 173.462 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 173.463 +    MM_LOG (tmp,ERROR);
 173.464 +  }
 173.465 +				/* create the name, done if made directory */
 173.466 +  else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&&
 173.467 +	   (s = strrchr (s,'/')) && !s[1]) return T;
 173.468 +  return ret ? set_mbx_protections (mailbox,tmp) : NIL;
 173.469 +}
 173.470 +
 173.471 +/* Dummy create path
 173.472 + * Accepts: mail stream
 173.473 + *	    path name to create
 173.474 + *	    directory mode
 173.475 + * Returns: T on success, NIL on failure
 173.476 + */
 173.477 +
 173.478 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
 173.479 +{
 173.480 +  struct stat sbuf;
 173.481 +  char c,*s,tmp[MAILTMPLEN];
 173.482 +  int fd;
 173.483 +  long ret = NIL;
 173.484 +  char *t = strrchr (path,'/');
 173.485 +  int wantdir = t && !t[1];
 173.486 +  int mask = umask (0);
 173.487 +  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
 173.488 +  if (s = strrchr (path,'/')) {	/* found superior to this name? */
 173.489 +    c = *++s;			/* remember first character of inferior */
 173.490 +    *s = '\0';			/* tie off to get just superior */
 173.491 +				/* name doesn't exist, create it */
 173.492 +    if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 173.493 +	!dummy_create_path (stream,path,dirmode)) {
 173.494 +      umask (mask);		/* restore mask */
 173.495 +      return NIL;
 173.496 +    }
 173.497 +    *s = c;			/* restore full name */
 173.498 +  }
 173.499 +  if (wantdir) {		/* want to create directory? */
 173.500 +    ret = !mkdir (path,(int) dirmode);
 173.501 +    *t = '/';			/* restore directory delimiter */
 173.502 +  }
 173.503 +				/* create file */
 173.504 +  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,
 173.505 +		       (long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0)
 173.506 +    ret = !close (fd);
 173.507 +  if (!ret) {			/* error? */
 173.508 +    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno));
 173.509 +    MM_LOG (tmp,ERROR);
 173.510 +  }
 173.511 +  umask (mask);			/* restore mask */
 173.512 +  return ret;			/* return status */
 173.513 +}
 173.514 +
 173.515 +/* Dummy delete mailbox
 173.516 + * Accepts: mail stream
 173.517 + *	    mailbox name to delete
 173.518 + * Returns: T on success, NIL on failure
 173.519 + */
 173.520 +
 173.521 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 173.522 +{
 173.523 +  struct stat sbuf;
 173.524 +  char *s,tmp[MAILTMPLEN];
 173.525 +  if (!(s = dummy_file (tmp,mailbox))) {
 173.526 +    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
 173.527 +    MM_LOG (tmp,ERROR);
 173.528 +  }
 173.529 +				/* no trailing / (workaround BSD kernel bug) */
 173.530 +  if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0';
 173.531 +  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
 173.532 +      rmdir (tmp) : unlink (tmp)) {
 173.533 +    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
 173.534 +    MM_LOG (tmp,ERROR);
 173.535 +    return NIL;
 173.536 +  }
 173.537 +  return T;			/* return success */
 173.538 +}
 173.539 +
 173.540 +/* Mail rename mailbox
 173.541 + * Accepts: mail stream
 173.542 + *	    old mailbox name
 173.543 + *	    new mailbox name
 173.544 + * Returns: T on success, NIL on failure
 173.545 + */
 173.546 +
 173.547 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 173.548 +{
 173.549 +  struct stat sbuf;
 173.550 +  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
 173.551 +				/* no trailing / allowed */
 173.552 +  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
 173.553 +      stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
 173.554 +			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
 173.555 +    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
 173.556 +    MM_LOG (mbx,ERROR);
 173.557 +    return NIL;
 173.558 +  }
 173.559 +  if (s) {			/* found a directory delimiter? */
 173.560 +    if (!s[1]) *s = '\0';	/* ignore trailing delimiter */
 173.561 +    else {			/* found superior to destination name? */
 173.562 +      c = *++s;			/* remember first character of inferior */
 173.563 +      *s = '\0';		/* tie off to get just superior */
 173.564 +				/* name doesn't exist, create it */
 173.565 +      if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 173.566 +	  !dummy_create (stream,mbx)) return NIL;
 173.567 +      *s = c;			/* restore full name */
 173.568 +    }
 173.569 +  }
 173.570 +				/* rename of non-ex INBOX creates dest */
 173.571 +  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
 173.572 +    return dummy_create (NIL,mbx);
 173.573 +  if (rename (oldname,mbx)) {
 173.574 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
 173.575 +	     strerror (errno));
 173.576 +    MM_LOG (tmp,ERROR);
 173.577 +    return NIL;
 173.578 +  }
 173.579 +  return T;			/* return success */
 173.580 +}
 173.581 +
 173.582 +/* Dummy open
 173.583 + * Accepts: stream to open
 173.584 + * Returns: stream on success, NIL on failure
 173.585 + */
 173.586 +
 173.587 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 173.588 +{
 173.589 +  int fd;
 173.590 +  char err[MAILTMPLEN],tmp[MAILTMPLEN];
 173.591 +  struct stat sbuf;
 173.592 +				/* OP_PROTOTYPE call */
 173.593 +  if (!stream) return &dummyproto;
 173.594 +  err[0] = '\0';		/* no error message yet */
 173.595 +				/* can we open the file? */
 173.596 +  if (!dummy_file (tmp,stream->mailbox))
 173.597 +    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
 173.598 +  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 173.599 +				/* no, error unless INBOX */
 173.600 +    if (compare_cstring (stream->mailbox,"INBOX"))
 173.601 +      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
 173.602 +  }
 173.603 +  else {			/* file had better be empty then */
 173.604 +    fstat (fd,&sbuf);		/* sniff at its size */
 173.605 +    close (fd);
 173.606 +    if ((sbuf.st_mode & S_IFMT) != S_IFREG)
 173.607 +      sprintf (err,"Can't open %.80s: not a selectable mailbox",
 173.608 +	       stream->mailbox);
 173.609 +    else if (sbuf.st_size)	/* bogus format if non-empty */
 173.610 +      sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format",
 173.611 +	       stream->mailbox,tmp);
 173.612 +  }
 173.613 +  if (err[0]) {			/* if an error happened */
 173.614 +    MM_LOG (err,stream->silent ? WARN : ERROR);
 173.615 +    return NIL;
 173.616 +  }
 173.617 +  else if (!stream->silent) {	/* only if silence not requested */
 173.618 +    mail_exists (stream,0);	/* say there are 0 messages */
 173.619 +    mail_recent (stream,0);	/* and certainly no recent ones! */
 173.620 +    stream->uid_validity = time (0);
 173.621 +  }
 173.622 +  stream->inbox = T;		/* note that it's an INBOX */
 173.623 +  return stream;		/* return success */
 173.624 +}
 173.625 +
 173.626 +
 173.627 +/* Dummy close
 173.628 + * Accepts: MAIL stream
 173.629 + *	    options
 173.630 + */
 173.631 +
 173.632 +void dummy_close (MAILSTREAM *stream,long options)
 173.633 +{
 173.634 +				/* return silently */
 173.635 +}
 173.636 +
 173.637 +/* Dummy ping mailbox
 173.638 + * Accepts: MAIL stream
 173.639 + * Returns: T if stream alive, else NIL
 173.640 + */
 173.641 +
 173.642 +long dummy_ping (MAILSTREAM *stream)
 173.643 +{
 173.644 +  MAILSTREAM *test;
 173.645 +  if (time (0) >=		/* time to do another test? */
 173.646 +      ((time_t) (stream->gensym +
 173.647 +		 (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
 173.648 +				/* has mailbox format changed? */
 173.649 +    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
 173.650 +	(test->dtb != stream->dtb) &&
 173.651 +	(test = mail_open (NIL,stream->mailbox,NIL))) {
 173.652 +				/* preserve some resources */
 173.653 +      test->original_mailbox = stream->original_mailbox;
 173.654 +      stream->original_mailbox = NIL;
 173.655 +      test->sparep = stream->sparep;
 173.656 +      stream->sparep = NIL;
 173.657 +      test->sequence = stream->sequence;
 173.658 +      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
 173.659 +		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
 173.660 +			  sizeof (MAILSTREAM)));
 173.661 +				/* swap the streams */
 173.662 +      memcpy (stream,test,sizeof (MAILSTREAM));
 173.663 +      fs_give ((void **) &test);/* flush test now that copied */
 173.664 +				/* make sure application knows */
 173.665 +      mail_exists (stream,stream->recent = stream->nmsgs);
 173.666 +    }
 173.667 +				/* still hasn't changed */
 173.668 +    else stream->gensym = time (0);
 173.669 +  }
 173.670 +  return T;
 173.671 +}
 173.672 +
 173.673 +
 173.674 +/* Dummy check mailbox
 173.675 + * Accepts: MAIL stream
 173.676 + * No-op for readonly files, since read/writer can expunge it from under us!
 173.677 + */
 173.678 +
 173.679 +void dummy_check (MAILSTREAM *stream)
 173.680 +{
 173.681 +  dummy_ping (stream);		/* invoke ping */
 173.682 +}
 173.683 +
 173.684 +
 173.685 +/* Dummy expunge mailbox
 173.686 + * Accepts: MAIL stream
 173.687 + *	    sequence to expunge if non-NIL
 173.688 + *	    expunge options
 173.689 + * Returns: T, always
 173.690 + */
 173.691 +
 173.692 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 173.693 +{
 173.694 +  return LONGT;
 173.695 +}
 173.696 +
 173.697 +/* Dummy copy message(s)
 173.698 + * Accepts: MAIL stream
 173.699 + *	    sequence
 173.700 + *	    destination mailbox
 173.701 + *	    options
 173.702 + * Returns: T if copy successful, else NIL
 173.703 + */
 173.704 +
 173.705 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 173.706 +{
 173.707 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 173.708 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 173.709 +  return NIL;
 173.710 +}
 173.711 +
 173.712 +
 173.713 +/* Dummy append message string
 173.714 + * Accepts: mail stream
 173.715 + *	    destination mailbox
 173.716 + *	    append callback function
 173.717 + *	    data for callback
 173.718 + * Returns: T on success, NIL on failure
 173.719 + */
 173.720 +
 173.721 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 173.722 +{
 173.723 +  struct stat sbuf;
 173.724 +  int fd = -1;
 173.725 +  int e;
 173.726 +  char tmp[MAILTMPLEN];
 173.727 +  MAILSTREAM *ts = default_proto (T);
 173.728 +				/* append to INBOX? */
 173.729 +  if (!compare_cstring (mailbox,"INBOX")) {
 173.730 +				/* yes, if no empty proto try creating */
 173.731 +    if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX"))
 173.732 +      ts = NIL;
 173.733 +  }
 173.734 +  else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
 173.735 +    if ((e = errno) == ENOENT) /* failed, was it no such file? */
 173.736 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 173.737 +    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
 173.738 +    MM_LOG (tmp,ERROR);		/* pass up error */
 173.739 +    return NIL;			/* always fails */
 173.740 +  }
 173.741 +  else if (fd >= 0) {		/* found file? */
 173.742 +    fstat (fd,&sbuf);		/* get its size */
 173.743 +    close (fd);			/* toss out the fd */
 173.744 +    if (sbuf.st_size) ts = NIL; /* non-empty file? */
 173.745 +  }
 173.746 +  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
 173.747 +  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
 173.748 +  MM_LOG (tmp,ERROR);
 173.749 +  return NIL;
 173.750 +}
 173.751 +
 173.752 +/* Dummy mail generate file string
 173.753 + * Accepts: temporary buffer to write into
 173.754 + *	    mailbox name string
 173.755 + * Returns: local file string or NIL if failure
 173.756 + */
 173.757 +
 173.758 +char *dummy_file (char *dst,char *name)
 173.759 +{
 173.760 +  char *s = mailboxfile (dst,name);
 173.761 +				/* return our standard inbox */
 173.762 +  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
 173.763 +}
 173.764 +
 173.765 +
 173.766 +/* Dummy canonicalize name
 173.767 + * Accepts: buffer to write name
 173.768 + *	    reference
 173.769 + *	    pattern
 173.770 + * Returns: T if success, NIL if failure
 173.771 + */
 173.772 +
 173.773 +long dummy_canonicalize (char *tmp,char *ref,char *pat)
 173.774 +{
 173.775 +  unsigned long i;
 173.776 +  char *s;
 173.777 +  if (ref) {			/* preliminary reference check */
 173.778 +    if (*ref == '{') return NIL;/* remote reference not allowed */
 173.779 +    else if (!*ref) ref = NIL;	/* treat empty reference as no reference */
 173.780 +  }
 173.781 +  switch (*pat) {
 173.782 +  case '#':			/* namespace name */
 173.783 +    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
 173.784 +    else return NIL;		/* unknown namespace */
 173.785 +    break;
 173.786 +  case '{':			/* remote names not allowed */
 173.787 +    return NIL;
 173.788 +  case '/':			/* rooted name */
 173.789 +  case '~':			/* home directory name */
 173.790 +    if (!ref || (*ref != '#')) {/* non-namespace reference? */
 173.791 +      strcpy (tmp,pat);		/* yes, ignore */
 173.792 +      break;
 173.793 +    }
 173.794 +				/* fall through */
 173.795 +  default:			/* apply reference for all other names */
 173.796 +    if (!ref) strcpy (tmp,pat);	/* just copy if no namespace */
 173.797 +    else if ((*ref != '#') || mailboxfile (tmp,ref)) {
 173.798 +				/* wants root of name? */
 173.799 +      if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat);
 173.800 +				/* otherwise just append */
 173.801 +      else sprintf (tmp,"%s%s",ref,pat);
 173.802 +    }
 173.803 +    else return NIL;		/* unknown namespace */
 173.804 +  }
 173.805 +				/* count wildcards */
 173.806 +  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 173.807 +  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
 173.808 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 173.809 +    return NIL;
 173.810 +  }
 173.811 +  return T;
 173.812 +}
   174.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   174.2 +++ b/src/osdep/amiga/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   174.3 @@ -0,0 +1,43 @@
   174.4 +/* ========================================================================
   174.5 + * Copyright 1988-2006 University of Washington
   174.6 + *
   174.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   174.8 + * you may not use this file except in compliance with the License.
   174.9 + * You may obtain a copy of the License at
  174.10 + *
  174.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  174.12 + *
  174.13 + * 
  174.14 + * ========================================================================
  174.15 + */
  174.16 +
  174.17 +/*
  174.18 + * Program:	Dummy routines
  174.19 + *
  174.20 + * Author:	Mark Crispin
  174.21 + *		Networks and Distributed Computing
  174.22 + *		Computing & Communications
  174.23 + *		University of Washington
  174.24 + *		Administration Building, AG-44
  174.25 + *		Seattle, WA  98195
  174.26 + *		Internet: MRC@CAC.Washington.EDU
  174.27 + *
  174.28 + * Date:	9 May 1991
  174.29 + * Last Edited:	30 August 2006
  174.30 + */
  174.31 +
  174.32 +/* Exported function prototypes */
  174.33 +
  174.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  174.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  174.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  174.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  174.38 +		    unsigned long csiz,unsigned long fsiz);
  174.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  174.40 +			  unsigned long fsiz);
  174.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  174.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  174.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  174.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  174.45 +char *dummy_file (char *dst,char *name);
  174.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   175.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   175.2 +++ b/src/osdep/amiga/env_ami.c	Mon Sep 14 15:17:45 2009 +0900
   175.3 @@ -0,0 +1,1282 @@
   175.4 +/* ========================================================================
   175.5 + * Copyright 1988-2008 University of Washington
   175.6 + *
   175.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   175.8 + * you may not use this file except in compliance with the License.
   175.9 + * You may obtain a copy of the License at
  175.10 + *
  175.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  175.12 + *
  175.13 + * 
  175.14 + * ========================================================================
  175.15 + */
  175.16 +
  175.17 +/*
  175.18 + * Program:	Amiga environment routines
  175.19 + *
  175.20 + * Author:	Mark Crispin
  175.21 + *		UW Technology
  175.22 + *		Seattle, WA  98195
  175.23 + *		Internet: MRC@Washington.EDU
  175.24 + *
  175.25 + * Date:	1 August 1988
  175.26 + * Last Edited:	15 May 2008
  175.27 + */
  175.28 +
  175.29 +#include <grp.h>
  175.30 +#include <signal.h>
  175.31 +#include <sys/wait.h>
  175.32 +
  175.33 +/* c-client environment parameters */
  175.34 +
  175.35 +static char *myUserName = NIL;	/* user name */
  175.36 +static char *myHomeDir = NIL;	/* home directory name */
  175.37 +static char *myMailboxDir = NIL;/* mailbox directory name */
  175.38 +static char *myLocalHost = NIL;	/* local host name */
  175.39 +static char *myNewsrc = NIL;	/* newsrc file name */
  175.40 +static char *mailsubdir = NIL;	/* mail subdirectory name */
  175.41 +static char *sysInbox = NIL;	/* system inbox name */
  175.42 +static char *newsActive = NIL;	/* news active file */
  175.43 +static char *newsSpool = NIL;	/* news spool */
  175.44 +				/* anonymous home directory */
  175.45 +static char *anonymousHome = NIL;
  175.46 +static char *ftpHome = NIL;	/* ftp export home directory */
  175.47 +static char *publicHome = NIL;	/* public home directory */
  175.48 +static char *sharedHome = NIL;	/* shared home directory */
  175.49 +static short anonymous = NIL;	/* is anonymous */
  175.50 +static short restrictBox = NIL;	/* is a restricted box */
  175.51 +static short has_no_life = NIL;	/* is a cretin with no life */
  175.52 +				/* block environment init */
  175.53 +static short block_env_init = NIL;
  175.54 +static short hideDotFiles = NIL;/* hide files whose names start with . */
  175.55 +				/* advertise filesystem root */
  175.56 +static short advertisetheworld = NIL;
  175.57 +				/* disable automatic shared namespaces */
  175.58 +static short noautomaticsharedns = NIL;
  175.59 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  175.60 +static short netfsstatbug = NIL;/* compensate for broken stat() on network
  175.61 +				 * filesystems (AFS and old NFS).  Don't do
  175.62 +				 * this unless you really have to!
  175.63 +				 */
  175.64 +				/* 1 = disable plaintext, 2 = if not SSL */
  175.65 +static long disablePlaintext = NIL;
  175.66 +static long list_max_level = 20;/* maximum level of list recursion */
  175.67 +				/* default file protection */
  175.68 +static long mbx_protection = 0600;
  175.69 +				/* default directory protection */
  175.70 +static long dir_protection = 0700;
  175.71 +				/* default lock file protection */
  175.72 +static long lock_protection = MANDATORYLOCKPROT;
  175.73 +				/* default ftp file protection */
  175.74 +static long ftp_protection = 0644;
  175.75 +static long ftp_dir_protection = 0755;
  175.76 +				/* default public file protection */
  175.77 +static long public_protection = 0666;
  175.78 +static long public_dir_protection = 0777;
  175.79 +				/* default shared file protection */
  175.80 +static long shared_protection = 0660;
  175.81 +static long shared_dir_protection = 0770;
  175.82 +static long locktimeout = 5;	/* default lock timeout */
  175.83 +				/* default prototypes */
  175.84 +static MAILSTREAM *createProto = NIL;
  175.85 +static MAILSTREAM *appendProto = NIL;
  175.86 +				/* default user flags */
  175.87 +static char *userFlags[NUSERFLAGS] = {NIL};
  175.88 +static NAMESPACE *nslist[3];	/* namespace list */
  175.89 +static int logtry = 3;		/* number of server login tries */
  175.90 +				/* block notification */
  175.91 +static blocknotify_t mailblocknotify = mm_blocknotify;
  175.92 +
  175.93 +/* Amiga namespaces */
  175.94 +
  175.95 +				/* personal mh namespace */
  175.96 +static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
  175.97 +static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
  175.98 +				/* home namespace */
  175.99 +static NAMESPACE nshome = {"",'/',NIL,&nsmh};
 175.100 +				/* Amiga other user namespace */
 175.101 +static NAMESPACE nsamigaother = {"~",'/',NIL,NIL};
 175.102 +				/* public (anonymous OK) namespace */
 175.103 +static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
 175.104 +				/* netnews namespace */
 175.105 +static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
 175.106 +				/* FTP export namespace */
 175.107 +static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
 175.108 +				/* shared (no anonymous) namespace */
 175.109 +static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
 175.110 +				/* world namespace */
 175.111 +static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
 175.112 +
 175.113 +#include "write.c"		/* include safe writing routines */
 175.114 +#include "pmatch.c"		/* include wildcard pattern matcher */
 175.115 +
 175.116 +/* Get all authenticators */
 175.117 +
 175.118 +#include "auths.c"
 175.119 +
 175.120 +/* Environment manipulate parameters
 175.121 + * Accepts: function code
 175.122 + *	    function-dependent value
 175.123 + * Returns: function-dependent return value
 175.124 + */
 175.125 +
 175.126 +void *env_parameters (long function,void *value)
 175.127 +{
 175.128 +  void *ret = NIL;
 175.129 +  switch ((int) function) {
 175.130 +  case GET_NAMESPACE:
 175.131 +    ret = (void *) nslist;
 175.132 +    break;
 175.133 +  case SET_USERNAME:
 175.134 +    if (myUserName) fs_give ((void **) &myUserName);
 175.135 +    myUserName = cpystr ((char *) value);
 175.136 +  case GET_USERNAME:
 175.137 +    ret = (void *) myUserName;
 175.138 +    break;
 175.139 +  case SET_HOMEDIR:
 175.140 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
 175.141 +    myHomeDir = cpystr ((char *) value);
 175.142 +  case GET_HOMEDIR:
 175.143 +    ret = (void *) myHomeDir;
 175.144 +    break;
 175.145 +  case SET_LOCALHOST:
 175.146 +    if (myLocalHost) fs_give ((void **) &myLocalHost);
 175.147 +    myLocalHost = cpystr ((char *) value);
 175.148 +  case GET_LOCALHOST:
 175.149 +    ret = (void *) myLocalHost;
 175.150 +    break;
 175.151 +  case SET_NEWSRC:
 175.152 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
 175.153 +    myNewsrc = cpystr ((char *) value);
 175.154 +  case GET_NEWSRC:
 175.155 +    ret = (void *) myNewsrc;
 175.156 +    break;
 175.157 +  case SET_NEWSACTIVE:
 175.158 +    if (newsActive) fs_give ((void **) &newsActive);
 175.159 +    newsActive = cpystr ((char *) value);
 175.160 +  case GET_NEWSACTIVE:
 175.161 +    ret = (void *) newsActive;
 175.162 +    break;
 175.163 +  case SET_NEWSSPOOL:
 175.164 +    if (newsSpool) fs_give ((void **) &newsSpool);
 175.165 +    newsSpool = cpystr ((char *) value);
 175.166 +  case GET_NEWSSPOOL:
 175.167 +    ret = (void *) newsSpool;
 175.168 +    break;
 175.169 +
 175.170 +  case SET_ANONYMOUSHOME:
 175.171 +    if (anonymousHome) fs_give ((void **) &anonymousHome);
 175.172 +    anonymousHome = cpystr ((char *) value);
 175.173 +  case GET_ANONYMOUSHOME:
 175.174 +    if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
 175.175 +    ret = (void *) anonymousHome;
 175.176 +    break;
 175.177 +  case SET_FTPHOME:
 175.178 +    if (ftpHome) fs_give ((void **) &ftpHome);
 175.179 +    ftpHome = cpystr ((char *) value);
 175.180 +  case GET_FTPHOME:
 175.181 +    ret = (void *) ftpHome;
 175.182 +    break;
 175.183 +  case SET_PUBLICHOME:
 175.184 +    if (publicHome) fs_give ((void **) &publicHome);
 175.185 +    publicHome = cpystr ((char *) value);
 175.186 +  case GET_PUBLICHOME:
 175.187 +    ret = (void *) publicHome;
 175.188 +    break;
 175.189 +  case SET_SHAREDHOME:
 175.190 +    if (sharedHome) fs_give ((void **) &sharedHome);
 175.191 +    sharedHome = cpystr ((char *) value);
 175.192 +  case GET_SHAREDHOME:
 175.193 +    ret = (void *) sharedHome;
 175.194 +    break;
 175.195 +  case SET_SYSINBOX:
 175.196 +    if (sysInbox) fs_give ((void **) &sysInbox);
 175.197 +    sysInbox = cpystr ((char *) value);
 175.198 +  case GET_SYSINBOX:
 175.199 +    ret = (void *) sysInbox;
 175.200 +    break;
 175.201 +  case SET_LISTMAXLEVEL:
 175.202 +    list_max_level = (long) value;
 175.203 +  case GET_LISTMAXLEVEL:
 175.204 +    ret = (void *) list_max_level;
 175.205 +    break;
 175.206 +
 175.207 +  case SET_MBXPROTECTION:
 175.208 +    mbx_protection = (long) value;
 175.209 +  case GET_MBXPROTECTION:
 175.210 +    ret = (void *) mbx_protection;
 175.211 +    break;
 175.212 +  case SET_DIRPROTECTION:
 175.213 +    dir_protection = (long) value;
 175.214 +  case GET_DIRPROTECTION:
 175.215 +    ret = (void *) dir_protection;
 175.216 +    break;
 175.217 +  case SET_LOCKPROTECTION:
 175.218 +    lock_protection = (long) value;
 175.219 +  case GET_LOCKPROTECTION:
 175.220 +    ret = (void *) lock_protection;
 175.221 +    break;
 175.222 +  case SET_FTPPROTECTION:
 175.223 +    ftp_protection = (long) value;
 175.224 +  case GET_FTPPROTECTION:
 175.225 +    ret = (void *) ftp_protection;
 175.226 +    break;
 175.227 +  case SET_PUBLICPROTECTION:
 175.228 +    public_protection = (long) value;
 175.229 +  case GET_PUBLICPROTECTION:
 175.230 +    ret = (void *) public_protection;
 175.231 +    break;
 175.232 +  case SET_SHAREDPROTECTION:
 175.233 +    shared_protection = (long) value;
 175.234 +  case GET_SHAREDPROTECTION:
 175.235 +    ret = (void *) shared_protection;
 175.236 +    break;
 175.237 +  case SET_FTPDIRPROTECTION:
 175.238 +    ftp_dir_protection = (long) value;
 175.239 +  case GET_FTPDIRPROTECTION:
 175.240 +    ret = (void *) ftp_dir_protection;
 175.241 +    break;
 175.242 +  case SET_PUBLICDIRPROTECTION:
 175.243 +    public_dir_protection = (long) value;
 175.244 +  case GET_PUBLICDIRPROTECTION:
 175.245 +    ret = (void *) public_dir_protection;
 175.246 +    break;
 175.247 +  case SET_SHAREDDIRPROTECTION:
 175.248 +    shared_dir_protection = (long) value;
 175.249 +  case GET_SHAREDDIRPROTECTION:
 175.250 +    ret = (void *) shared_dir_protection;
 175.251 +    break;
 175.252 +
 175.253 +  case SET_LOCKTIMEOUT:
 175.254 +    locktimeout = (long) value;
 175.255 +  case GET_LOCKTIMEOUT:
 175.256 +    ret = (void *) locktimeout;
 175.257 +    break;
 175.258 +  case SET_HIDEDOTFILES:
 175.259 +    hideDotFiles = value ? T : NIL;
 175.260 +  case GET_HIDEDOTFILES:
 175.261 +    ret = (void *) (hideDotFiles ? VOIDT : NIL);
 175.262 +    break;
 175.263 +  case SET_DISABLEPLAINTEXT:
 175.264 +    disablePlaintext = (long) value;
 175.265 +  case GET_DISABLEPLAINTEXT:
 175.266 +    ret = (void *) disablePlaintext;
 175.267 +    break;
 175.268 +  case SET_ADVERTISETHEWORLD:
 175.269 +    advertisetheworld = value ? T : NIL;
 175.270 +  case GET_ADVERTISETHEWORLD:
 175.271 +    ret = (void *) (advertisetheworld ? VOIDT : NIL);
 175.272 +    break;
 175.273 +  case SET_DISABLEAUTOSHAREDNS:
 175.274 +    noautomaticsharedns = value ? T : NIL;
 175.275 +  case GET_DISABLEAUTOSHAREDNS:
 175.276 +    ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
 175.277 +    break;
 175.278 +  case SET_DISABLE822TZTEXT:
 175.279 +    no822tztext = value ? T : NIL;
 175.280 +  case GET_DISABLE822TZTEXT:
 175.281 +    ret = (void *) (no822tztext ? VOIDT : NIL);
 175.282 +    break;
 175.283 +  case SET_USERHASNOLIFE:
 175.284 +    has_no_life = value ? T : NIL;
 175.285 +  case GET_USERHASNOLIFE:
 175.286 +    ret = (void *) (has_no_life ? VOIDT : NIL);
 175.287 +    break;
 175.288 +  case SET_NETFSSTATBUG:
 175.289 +    netfsstatbug = value ? T : NIL;
 175.290 +  case GET_NETFSSTATBUG:
 175.291 +    ret = (void *) (netfsstatbug ? VOIDT : NIL);
 175.292 +    break;
 175.293 +  case SET_BLOCKENVINIT:
 175.294 +    block_env_init = value ? T : NIL;
 175.295 +  case GET_BLOCKENVINIT:
 175.296 +    ret = (void *) (block_env_init ? VOIDT : NIL);
 175.297 +    break;
 175.298 +  case SET_BLOCKNOTIFY:
 175.299 +    mailblocknotify = (blocknotify_t) value;
 175.300 +  case GET_BLOCKNOTIFY:
 175.301 +    ret = (void *) mailblocknotify;
 175.302 +    break;
 175.303 +  }
 175.304 +  return ret;
 175.305 +}
 175.306 +
 175.307 +/* Write current time
 175.308 + * Accepts: destination string
 175.309 + *	    optional format of day-of-week prefix
 175.310 + *	    format of date and time
 175.311 + *	    flag whether to append symbolic timezone
 175.312 + */
 175.313 +
 175.314 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
 175.315 +{
 175.316 +  time_t tn = time (0);
 175.317 +  struct tm *t = gmtime (&tn);
 175.318 +  int zone = t->tm_hour * 60 + t->tm_min;
 175.319 +  int julian = t->tm_yday;
 175.320 +  t = localtime (&tn);		/* get local time now */
 175.321 +				/* minus UTC minutes since midnight */
 175.322 +  zone = t->tm_hour * 60 + t->tm_min - zone;
 175.323 +  /* julian can be one of:
 175.324 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
 175.325 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
 175.326 +   *    0  local time is same day as UTC, no offset
 175.327 +   *   -1  local time is 1 day behind UTC, offset -24 hours
 175.328 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
 175.329 +   */
 175.330 +  if (julian = t->tm_yday -julian)
 175.331 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
 175.332 +  if (prefix) {			/* want day of week? */
 175.333 +    sprintf (date,prefix,days[t->tm_wday]);
 175.334 +    date += strlen (date);	/* make next sprintf append */
 175.335 +  }
 175.336 +				/* output the date */
 175.337 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 175.338 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
 175.339 +				/* append timezone suffix if desired */
 175.340 +  if (suffix) rfc822_timezone (date,(void *) t);
 175.341 +}
 175.342 +
 175.343 +/* Write current time in RFC 822 format
 175.344 + * Accepts: destination string
 175.345 + */
 175.346 +
 175.347 +void rfc822_date (char *date)
 175.348 +{
 175.349 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
 175.350 +	   no822tztext ? NIL : T);
 175.351 +}
 175.352 +
 175.353 +
 175.354 +/* Write current time in fixed-width RFC 822 format
 175.355 + * Accepts: destination string
 175.356 + */
 175.357 +
 175.358 +void rfc822_fixed_date (char *date)
 175.359 +{
 175.360 +  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
 175.361 +}
 175.362 +
 175.363 +
 175.364 +/* Write current time in internal format
 175.365 + * Accepts: destination string
 175.366 + */
 175.367 +
 175.368 +void internal_date (char *date)
 175.369 +{
 175.370 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
 175.371 +}
 175.372 +
 175.373 +/* Initialize server
 175.374 + * Accepts: server name for syslog or NIL
 175.375 + *	    /etc/services service name or NIL
 175.376 + *	    alternate /etc/services service name or NIL
 175.377 + *	    clock interrupt handler
 175.378 + *	    kiss-of-death interrupt handler
 175.379 + *	    hangup interrupt handler
 175.380 + *	    termination interrupt handler
 175.381 + */
 175.382 +
 175.383 +void server_init (char *server,char *service,char *sslservice,
 175.384 +		  void *clkint,void *kodint,void *hupint,void *trmint,
 175.385 +		  void *staint)
 175.386 +{
 175.387 +  int onceonly = server && service && sslservice;
 175.388 +  if (onceonly) {		/* set server name in syslog */
 175.389 +    int mask;
 175.390 +    openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
 175.391 +    fclose (stderr);		/* possibly save a process ID */
 175.392 +
 175.393 +    switch (mask = umask (022)){/* check old umask */
 175.394 +    case 0:			/* definitely unreasonable */
 175.395 +    case 022:			/* don't need to change it */
 175.396 +      break;
 175.397 +    default:			/* already was a reasonable value */
 175.398 +      umask (mask);		/* so change it back */
 175.399 +    }
 175.400 +  }
 175.401 +  arm_signal (SIGALRM,clkint);	/* prepare for clock interrupt */
 175.402 +  arm_signal (SIGUSR2,kodint);	/* prepare for Kiss Of Death */
 175.403 +  arm_signal (SIGHUP,hupint);	/* prepare for hangup */
 175.404 +  arm_signal (SIGPIPE,hupint);	/* alternative hangup */
 175.405 +  arm_signal (SIGTERM,trmint);	/* prepare for termination */
 175.406 +				/* status dump */
 175.407 +  if (staint) arm_signal (SIGUSR1,staint);
 175.408 +  if (onceonly) {		/* set up network and maybe SSL */
 175.409 +    long port;
 175.410 +    struct servent *sv;
 175.411 +    /* Use SSL if SSL service, or if server starts with "s" and not service */
 175.412 +    if (((port = tcp_serverport ()) >= 0)) {
 175.413 +      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
 175.414 +	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
 175.415 +      else if ((sv = getservbyname (sslservice,"tcp")) &&
 175.416 +	       (port == ntohs (sv->s_port))) {
 175.417 +	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
 175.418 +		tcp_clientaddr ());
 175.419 +	ssl_server_init (server);
 175.420 +      }
 175.421 +      else {			/* not service or SSL service port */
 175.422 +	syslog (LOG_DEBUG,"port %ld service init from %s",port,
 175.423 +		tcp_clientaddr ());
 175.424 +	if (*server == 's') ssl_server_init (server);
 175.425 +      }
 175.426 +    }
 175.427 +  }
 175.428 +}
 175.429 +
 175.430 +/* Wait for stdin input
 175.431 + * Accepts: timeout in seconds
 175.432 + * Returns: T if have input on stdin, else NIL
 175.433 + */
 175.434 +
 175.435 +long server_input_wait (long seconds)
 175.436 +{
 175.437 +  fd_set rfd,efd;
 175.438 +  struct timeval tmo;
 175.439 +  FD_ZERO (&rfd);
 175.440 +  FD_ZERO (&efd);
 175.441 +  FD_SET (0,&rfd);
 175.442 +  FD_SET (0,&efd);
 175.443 +  tmo.tv_sec = seconds; tmo.tv_usec = 0;
 175.444 +  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
 175.445 +}
 175.446 +
 175.447 +/* Return Amiga password entry for user name
 175.448 + * Accepts: user name string
 175.449 + * Returns: password entry
 175.450 + *
 175.451 + * Tries all-lowercase form of user name if given user name fails
 175.452 + */
 175.453 +
 175.454 +static struct passwd *pwuser (unsigned char *user)
 175.455 +{
 175.456 +  unsigned char *s;
 175.457 +  struct passwd *pw = getpwnam (user);
 175.458 +  if (!pw) {			/* failed, see if any uppercase characters */
 175.459 +    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
 175.460 +    if (*s) {			/* yes, try all lowercase form */
 175.461 +      pw = getpwnam (s = lcase (cpystr (user)));
 175.462 +      fs_give ((void **) &s);
 175.463 +    }
 175.464 +  }
 175.465 +  return pw;
 175.466 +}
 175.467 +
 175.468 +
 175.469 +/* Validate password for user name
 175.470 + * Accepts: user name string
 175.471 + *	    password string
 175.472 + *	    argument count
 175.473 + *	    argument vector
 175.474 + * Returns: password entry if validated
 175.475 + *
 175.476 + * Tries password+1 if password fails and starts with space
 175.477 + */
 175.478 +
 175.479 +static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
 175.480 +{
 175.481 +  char *s;
 175.482 +  struct passwd *pw;
 175.483 +  struct passwd *ret = NIL;
 175.484 +  if (auth_md5.server) {	/* using CRAM-MD5 authentication? */
 175.485 +    if (s = auth_md5_pwd (user)) {
 175.486 +      if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
 175.487 +	ret = pwuser (user);	/* validated, get passwd entry for user */
 175.488 +      memset (s,0,strlen (s));	/* erase sensitive information */
 175.489 +      fs_give ((void **) &s);
 175.490 +    }
 175.491 +  }
 175.492 +  else if (pw = pwuser (user)) {/* can get user? */
 175.493 +    s = cpystr (pw->pw_name);	/* copy returned name in case we need it */
 175.494 +    if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
 175.495 +	(*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
 175.496 +      ret = checkpw (pw,pwd+1,argc,argv);
 175.497 +    fs_give ((void **) &s);	/* don't need copy of name any more */
 175.498 +  }
 175.499 +  return ret;
 175.500 +}
 175.501 +
 175.502 +/* Server log in
 175.503 + * Accepts: user name string
 175.504 + *	    password string
 175.505 + *	    authenticating user name string
 175.506 + *	    argument count
 175.507 + *	    argument vector
 175.508 + * Returns: T if password validated, NIL otherwise
 175.509 + */
 175.510 +
 175.511 +long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
 175.512 +{
 175.513 +  struct passwd *pw = NIL;
 175.514 +  int level = LOG_NOTICE;
 175.515 +  char *err = "failed";
 175.516 +				/* cretins still haven't given up */
 175.517 +  if ((strlen (user) >= NETMAXUSER) ||
 175.518 +      (authuser && (strlen (authuser) >= NETMAXUSER))) {
 175.519 +    level = LOG_ALERT;		/* escalate this alert */
 175.520 +    err = "SYSTEM BREAK-IN ATTEMPT";
 175.521 +    logtry = 0;			/* render this session useless */
 175.522 +  }
 175.523 +  else if (logtry-- <= 0) err = "excessive login failures";
 175.524 +  else if (disablePlaintext) err = "disabled";
 175.525 +  else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
 175.526 +  else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
 175.527 +  if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
 175.528 +  syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
 175.529 +	  user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
 175.530 +  sleep (3);			/* slow down possible cracker */
 175.531 +  return NIL;
 175.532 +}
 175.533 +
 175.534 +/* Authenticated server log in
 175.535 + * Accepts: user name string
 175.536 + *	    authenticating user name string
 175.537 + *	    argument count
 175.538 + *	    argument vector
 175.539 + * Returns: T if password validated, NIL otherwise
 175.540 + */
 175.541 +
 175.542 +long authserver_login (char *user,char *authuser,int argc,char *argv[])
 175.543 +{
 175.544 +  return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
 175.545 +}
 175.546 +
 175.547 +
 175.548 +/* Log in as anonymous daemon
 175.549 + * Accepts: argument count
 175.550 + *	    argument vector
 175.551 + * Returns: T if successful, NIL if error
 175.552 + */
 175.553 +
 175.554 +long anonymous_login (int argc,char *argv[])
 175.555 +{
 175.556 +				/* log in Mr. A. N. Onymous */
 175.557 +  return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
 175.558 +		   (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
 175.559 +		   argc,argv);
 175.560 +}
 175.561 +
 175.562 +/* Finish log in and environment initialization
 175.563 + * Accepts: passwd struct for loginpw()
 175.564 + *	    optional authentication user name
 175.565 + *	    user name (NIL for anonymous)
 175.566 + *	    home directory (NIL to use directory from passwd struct)
 175.567 + *	    argument count
 175.568 + *	    argument vector
 175.569 + * Returns: T if successful, NIL if error
 175.570 + */
 175.571 +
 175.572 +long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
 175.573 +	       char *argv[])
 175.574 +{
 175.575 +  struct group *gr;
 175.576 +  char **t;
 175.577 +  long ret = NIL;
 175.578 +  if (pw && pw->pw_uid) {	/* must have passwd struct for non-UID 0 */
 175.579 +				/* make safe copies of user and home */
 175.580 +    if (user) user = cpystr (pw->pw_name);
 175.581 +    home = cpystr (home ? home : pw->pw_dir);
 175.582 +				/* authorization ID .NE. authentication ID? */
 175.583 +    if (user && auser && *auser && compare_cstring (auser,user)) {
 175.584 +				/* scan list of mail administrators */
 175.585 +      if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
 175.586 +	if (!compare_cstring (auser,*t++))
 175.587 +	  ret = pw_login (pw,NIL,user,home,argc,argv);
 175.588 +      syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
 175.589 +	      ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
 175.590 +    }
 175.591 +				/* normal login */
 175.592 +    else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
 175.593 +	     (ret = env_init (user,home))) chdir (myhomedir ());
 175.594 +    fs_give ((void **) &home);	/* clean up */
 175.595 +    if (user) fs_give ((void **) &user);
 175.596 +  }
 175.597 +  return ret;			/* return status */
 175.598 +}
 175.599 +
 175.600 +/* Initialize environment
 175.601 + * Accepts: user name (NIL for anonymous)
 175.602 + *	    home directory name
 175.603 + * Returns: T, always
 175.604 + */
 175.605 +
 175.606 +long env_init (char *user,char *home)
 175.607 +{
 175.608 +  extern MAILSTREAM CREATEPROTO;
 175.609 +  extern MAILSTREAM EMPTYPROTO;
 175.610 +  struct passwd *pw;
 175.611 +  struct stat sbuf;
 175.612 +  char tmp[MAILTMPLEN];
 175.613 +				/* don't init if blocked */
 175.614 +  if (block_env_init) return LONGT;
 175.615 +  if (myUserName) fatal ("env_init called twice!");
 175.616 +				/* set up user name */
 175.617 +  myUserName = cpystr (user ? user : ANONYMOUSUSER);
 175.618 +  if (user) {			/* remember user name and home directory */
 175.619 +    nslist[0] = &nshome;	/* home namespace */
 175.620 +    nslist[1] = &nsamigaother;
 175.621 +    nslist[2] = advertisetheworld ? &nsworld : &nsshared;
 175.622 +  }
 175.623 +  else {			/* anonymous user */
 175.624 +    nslist[0] = nslist[1] = NIL,nslist[2] = &nsftp;
 175.625 +    sprintf (tmp,"%s/INBOX",
 175.626 +	     home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
 175.627 +    sysInbox = cpystr (tmp);	/* make system INBOX */
 175.628 +    anonymous = T;		/* flag as anonymous */
 175.629 +  }
 175.630 +  myHomeDir = cpystr (home);	/* set home directory */
 175.631 +  if (!noautomaticsharedns) {
 175.632 +				/* #ftp namespace */
 175.633 +    if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
 175.634 +				/* #public namespace */
 175.635 +    if (!publicHome && (pw = getpwnam ("imappublic")))
 175.636 +      publicHome = cpystr (pw->pw_dir);
 175.637 +				/* #shared namespace */
 175.638 +    if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
 175.639 +      sharedHome = cpystr (pw->pw_dir);
 175.640 +  }
 175.641 +  if (!myLocalHost) mylocalhost ();
 175.642 +  if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
 175.643 +  if (!newsActive) newsActive = cpystr (ACTIVEFILE);
 175.644 +  if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
 175.645 +				/* force default prototype to be set */
 175.646 +  if (!createProto) createProto = &CREATEPROTO;
 175.647 +  if (!appendProto) appendProto = &EMPTYPROTO;
 175.648 +				/* re-do open action to get flags */
 175.649 +  (*createProto->dtb->open) (NIL);
 175.650 +  endpwent ();			/* close pw database */
 175.651 +  return T;
 175.652 +}
 175.653 + 
 175.654 +/* Return my user name
 175.655 + * Accepts: pointer to optional flags
 175.656 + * Returns: my user name
 175.657 + */
 175.658 +
 175.659 +char *myusername_full (unsigned long *flags)
 175.660 +{
 175.661 +  struct passwd *pw;
 175.662 +  struct stat sbuf;
 175.663 +  char *s;
 175.664 +  unsigned long euid;
 175.665 +  char *ret = UNLOGGEDUSER;
 175.666 +				/* no user name yet and not root? */
 175.667 +  if (!myUserName && (euid = geteuid ())) {
 175.668 +				/* yes, look up getlogin() user name or EUID */
 175.669 +    if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
 175.670 +	 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
 175.671 +	(pw = getpwuid (euid))) {
 175.672 +      if (block_env_init) {	/* don't env_init if blocked */
 175.673 +	if (flags) *flags = MU_LOGGEDIN;
 175.674 +	return pw->pw_name;
 175.675 +      }
 175.676 +      env_init (pw->pw_name,
 175.677 +		((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
 175.678 +		 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
 175.679 +		s : pw->pw_dir);
 175.680 +    }
 175.681 +    else fatal ("Unable to look up user name");
 175.682 +  }
 175.683 +  if (myUserName) {		/* logged in? */
 175.684 +    if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
 175.685 +    ret = myUserName;		/* return user name */
 175.686 +  }
 175.687 +  else if (flags) *flags = MU_NOTLOGGEDIN;
 175.688 +  return ret;
 175.689 +}
 175.690 +/* Return my local host name
 175.691 + * Returns: my local host name
 175.692 + */
 175.693 +
 175.694 +char *mylocalhost ()
 175.695 +{
 175.696 +  char tmp[MAILTMPLEN];
 175.697 +  struct hostent *host_name;
 175.698 +  if (!myLocalHost) myLocalHost = cpystr (gethostname (tmp,MAILTMPLEN-1) ?
 175.699 +					  "random-pc" : tcp_canonical (tmp));
 175.700 +  return myLocalHost;
 175.701 +}
 175.702 +
 175.703 +/* Return my home directory name
 175.704 + * Returns: my home directory name
 175.705 + */
 175.706 +
 175.707 +char *myhomedir ()
 175.708 +{
 175.709 +  if (!myHomeDir) myusername ();/* initialize if first time */
 175.710 +  return myHomeDir ? myHomeDir : "";
 175.711 +}
 175.712 +
 175.713 +
 175.714 +/* Return my home mailbox name
 175.715 + * Returns: my home directory name
 175.716 + */
 175.717 +
 175.718 +static char *mymailboxdir ()
 175.719 +{
 175.720 +  char *home = myhomedir ();
 175.721 +  if (!myMailboxDir && home) {	/* initialize if first time */
 175.722 +    if (mailsubdir) {
 175.723 +      char tmp[MAILTMPLEN];
 175.724 +      sprintf (tmp,"%s/%s",home,mailsubdir);
 175.725 +      myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
 175.726 +    }
 175.727 +    else myMailboxDir = cpystr (home);
 175.728 +  }
 175.729 +  return myMailboxDir ? myMailboxDir : "";
 175.730 +}
 175.731 +
 175.732 +
 175.733 +/* Return system standard INBOX
 175.734 + * Accepts: buffer string
 175.735 + */
 175.736 +
 175.737 +char *sysinbox ()
 175.738 +{
 175.739 +  char tmp[MAILTMPLEN];
 175.740 +  if (!sysInbox) {		/* initialize if first time */
 175.741 +    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
 175.742 +    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
 175.743 +  }
 175.744 +  return sysInbox;
 175.745 +}
 175.746 +
 175.747 +/* Return mailbox directory name
 175.748 + * Accepts: destination buffer
 175.749 + *	    directory prefix
 175.750 + *	    name in directory
 175.751 + * Returns: file name or NIL if error
 175.752 + */
 175.753 +
 175.754 +char *mailboxdir (char *dst,char *dir,char *name)
 175.755 +{
 175.756 +  char tmp[MAILTMPLEN];
 175.757 +  if (dir || name) {		/* if either argument provided */
 175.758 +    if (dir) {
 175.759 +      if (strlen (dir) > NETMAXMBX) return NIL;
 175.760 +      strcpy (tmp,dir);		/* write directory prefix */
 175.761 +    }
 175.762 +    else tmp[0] = '\0';		/* otherwise null string */
 175.763 +    if (name) {
 175.764 +      if (strlen (name) > NETMAXMBX) return NIL;
 175.765 +      strcat (tmp,name);	/* write name in directory */
 175.766 +    }
 175.767 +				/* validate name, return its name */
 175.768 +    if (!mailboxfile (dst,tmp)) return NIL;
 175.769 +  }
 175.770 +				/* no arguments, wants mailbox directory */
 175.771 +  else strcpy (dst,mymailboxdir ());
 175.772 +  return dst;			/* return the name */
 175.773 +}
 175.774 +
 175.775 +/* Return mailbox file name
 175.776 + * Accepts: destination buffer
 175.777 + *	    mailbox name
 175.778 + * Returns: file name or empty string for driver-selected INBOX or NIL if error
 175.779 + */
 175.780 +
 175.781 +char *mailboxfile (char *dst,char *name)
 175.782 +{
 175.783 +  struct passwd *pw;
 175.784 +  char *s;
 175.785 +  if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
 175.786 +      ((anonymous || restrictBox || (*name == '#')) &&
 175.787 +       (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
 175.788 +    dst = NIL;			/* invalid name */
 175.789 +  else switch (*name) {		/* determine mailbox type based upon name */
 175.790 +  case '#':			/* namespace name */
 175.791 +				/* #ftp/ namespace */
 175.792 +    if (((name[1] == 'f') || (name[1] == 'F')) &&
 175.793 +	((name[2] == 't') || (name[2] == 'T')) &&
 175.794 +	((name[3] == 'p') || (name[3] == 'P')) &&
 175.795 +	(name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
 175.796 +				/* #public/ and #shared/ namespaces */
 175.797 +    else if ((((name[1] == 'p') || (name[1] == 'P')) &&
 175.798 +	      ((name[2] == 'u') || (name[2] == 'U')) &&
 175.799 +	      ((name[3] == 'b') || (name[3] == 'B')) &&
 175.800 +	      ((name[4] == 'l') || (name[4] == 'L')) &&
 175.801 +	      ((name[5] == 'i') || (name[5] == 'I')) &&
 175.802 +	      ((name[6] == 'c') || (name[6] == 'C')) &&
 175.803 +	      (name[7] == '/') && (s = publicHome)) ||
 175.804 +	     (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
 175.805 +	      ((name[2] == 'h') || (name[2] == 'H')) &&
 175.806 +	      ((name[3] == 'a') || (name[3] == 'A')) &&
 175.807 +	      ((name[4] == 'r') || (name[4] == 'R')) &&
 175.808 +	      ((name[5] == 'e') || (name[5] == 'E')) &&
 175.809 +	      ((name[6] == 'd') || (name[6] == 'D')) &&
 175.810 +	      (name[7] == '/') && (s = sharedHome)))
 175.811 +      sprintf (dst,"%s/%s",s,compare_cstring (name,"INBOX") ? name : "INBOX");
 175.812 +    else dst = NIL;		/* unknown namespace */
 175.813 +    break;
 175.814 +
 175.815 +  case '/':			/* root access */
 175.816 +    if (anonymous) dst = NIL;	/* anonymous forbidden to do this */
 175.817 +    else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
 175.818 +      dst = NIL;		/* restricted and not access to sysinbox */
 175.819 +    else strcpy (dst,name);	/* unrestricted, copy root name */
 175.820 +    break;
 175.821 +  case '~':			/* other user access */
 175.822 +				/* bad syntax or anonymous can't win */
 175.823 +    if (!*++name || anonymous) dst = NIL;
 175.824 +				/* ~/ equivalent to ordinary name */
 175.825 +    else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
 175.826 +				/* other user forbidden if restricted */
 175.827 +    else if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
 175.828 +    else {			/* clear box other user */
 175.829 +				/* copy user name */
 175.830 +      for (s = dst; *name && (*name != '/'); *s++ = *name++);
 175.831 +      *s++ = '\0';		/* tie off user name, look up in passwd file */
 175.832 +      if ((pw = getpwnam (dst)) && pw->pw_dir) {
 175.833 +	if (*name) name++;	/* skip past the slash */
 175.834 +				/* canonicalize case of INBOX */
 175.835 +	if (!compare_cstring (name,"INBOX")) name = "INBOX";
 175.836 +				/* remove trailing / from directory */
 175.837 +	if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
 175.838 +				/* don't allow ~root/ if restricted root */
 175.839 +	if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
 175.840 +				/* build final name w/ subdir if needed */
 175.841 +	else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
 175.842 +	else sprintf (dst,"%s/%s",pw->pw_dir,name);
 175.843 +      }
 175.844 +      else dst = NIL;		/* no such user */
 175.845 +    }
 175.846 +    break;
 175.847 +  case 'I': case 'i':		/* possible INBOX */
 175.848 +    if (!compare_cstring (name+1,"NBOX")) {
 175.849 +				/* if anonymous, use INBOX in mailbox dir */
 175.850 +      if (anonymous) sprintf (dst,"%s/INBOX",mymailboxdir ());
 175.851 +      else *dst = '\0';		/* otherwise driver selects the name */
 175.852 +      break;
 175.853 +    }
 175.854 +				/* drop into to ordinary name case */
 175.855 +  default:			/* ordinary name is easy */
 175.856 +    sprintf (dst,"%s/%s",mymailboxdir (),name);
 175.857 +    break;
 175.858 +  }
 175.859 +  return dst;			/* return final name */
 175.860 +}
 175.861 +
 175.862 +/* Dot-lock file locker
 175.863 + * Accepts: file name to lock
 175.864 + *	    destination buffer for lock file name
 175.865 + *	    open file description on file name to lock
 175.866 + * Returns: T if success, NIL if failure
 175.867 + */
 175.868 +
 175.869 +long dotlock_lock (char *file,DOTLOCK *base,int fd)
 175.870 +{
 175.871 +  int i = locktimeout * 60;
 175.872 +  int j,mask,retry,pi[2],po[2];
 175.873 +  char *s,tmp[MAILTMPLEN];
 175.874 +  struct stat sb;
 175.875 +				/* flush absurd file name */
 175.876 +  if (strlen (file) > 512) return NIL;
 175.877 +				/* build lock filename */
 175.878 +  sprintf (base->lock,"%s.lock",file);
 175.879 +				/* assume no pipe */
 175.880 +  base->pipei = base->pipeo = -1;
 175.881 +  do {				/* make sure not symlink */
 175.882 +    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
 175.883 +				/* time out if file older than 5 minutes */
 175.884 +    if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
 175.885 +				/* try to create the lock */
 175.886 +    if ((j = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) lock_protection)) >= 0) {
 175.887 +      close (i);		/* make the file, now close it */
 175.888 +      chmod (base->lock,(int) lock_protection);
 175.889 +      return LONGT;
 175.890 +    }
 175.891 +    if (errno == EEXIST) {	/* already locked? */
 175.892 +      retry = -1;		/* can try again */
 175.893 +      if (!(i%15)) {		/* time to notify? */
 175.894 +	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
 175.895 +		 file,i);
 175.896 +	mm_log (tmp,WARN);
 175.897 +      }
 175.898 +      sleep (1);		/* wait 1 second before next try */
 175.899 +    }
 175.900 +    else retry = i = 0;		/* hard failure, no more retries */
 175.901 +  } while (i--);		/* until out of retries */
 175.902 +  if (retry < 0) {		/* still returning retry after locktimeout? */
 175.903 +    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
 175.904 +    if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
 175.905 +      sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
 175.906 +	       (long) (time (0) - sb.st_ctime));
 175.907 +      mm_log (tmp,WARN);
 175.908 +    }
 175.909 +    mask = umask (0);
 175.910 +    unlink (base->lock);	/* try to remove the old file */
 175.911 +				/* seize the lock */
 175.912 +    if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) lock_protection)) >= 0) {
 175.913 +      close (i);		/* don't need descriptor any more */
 175.914 +      sprintf (tmp,"Mailbox %.80s lock overridden",file);
 175.915 +      mm_log (tmp,NIL);
 175.916 +      chmod (base->lock,(int) lock_protection);
 175.917 +      umask (mask)		/* restore old umask */
 175.918 +      return LONGT;
 175.919 +    }
 175.920 +    umask (mask)		/* restore old umask */
 175.921 +  }
 175.922 +
 175.923 +  if (fd >= 0) switch (errno) {
 175.924 +  case EACCES:			/* protection failure? */
 175.925 +				/* make command pipes */
 175.926 +    if (!stat (LOCKPGM,&sb) && (pipe (pi) >= 0)) {
 175.927 +				/* if input pipes usable create output pipes */
 175.928 +      if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
 175.929 +				/* make sure output pipes are usable */
 175.930 +	if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
 175.931 +				/* all is good, make inferior process */
 175.932 +	else if (!(j = fork ())) {
 175.933 +	  if (!fork ()) {	/* make grandchild so it's inherited by init */
 175.934 +	    long cf;		/* don't change caller vars in case vfork() */
 175.935 +	    char *argv[4],arg[20];
 175.936 +				/* prepare argument vector */
 175.937 +	    sprintf (arg,"%d",fd);
 175.938 +	    argv[0] = LOCKPGM; argv[1] = arg;
 175.939 +	    argv[2] = file; argv[3] = NIL;
 175.940 +				/* set parent's I/O to my O/I */
 175.941 +	    dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
 175.942 +				/* close all unnecessary descriptors */
 175.943 +	    for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
 175.944 +		 cf >= 3; --cf) if (cf != fd) close (cf);
 175.945 +				/* be our own process group */
 175.946 +	    setpgrp (0,getpid ());
 175.947 +				/* now run it */
 175.948 +	    _exit (execv (argv[0],argv));
 175.949 +	  }
 175.950 +	  _exit (1);		/* child is done */
 175.951 +	}
 175.952 +	else if (j > 0) {	/* parent process */
 175.953 +	  fd_set rfd;
 175.954 +	  struct timeval tmo;
 175.955 +	  FD_ZERO (&rfd);
 175.956 +	  FD_SET (pi[0],&rfd);
 175.957 +	  tmo.tv_sec = locktimeout * 60;
 175.958 +	  grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
 175.959 +				/* read response from locking program */
 175.960 +	  if (select (pi[0]+1,&rfd,0,0,&tmo) &&
 175.961 +	      (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
 175.962 +				/* success, record pipes */
 175.963 +	    base->pipei = pi[0]; base->pipeo = po[1];
 175.964 +				/* close child's side of the pipes */
 175.965 +	    close (pi[1]); close (po[0]);
 175.966 +	    return LONGT;
 175.967 +	  }
 175.968 +	}
 175.969 +	close (po[0]); close (po[1]);
 175.970 +      }
 175.971 +      close (pi[0]); close (pi[1]);
 175.972 +    }
 175.973 +				/* find directory/file delimiter */
 175.974 +    if (s = strrchr (base->lock,'/')) {
 175.975 +      *s = '\0';		/* tie off at directory */
 175.976 +      sprintf(tmp,		/* generate default message */
 175.977 +	      "Mailbox vulnerable - directory %.80s must have 1777 protection",
 175.978 +	      base->lock);
 175.979 +				/* definitely not 1777 if can't stat */
 175.980 +      mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
 175.981 +      *s = '/';			/* restore lock name */
 175.982 +      if (mask != 1777) {	/* default warning if not 1777 */
 175.983 +	MM_LOG (tmp,WARN);
 175.984 +	break;
 175.985 +      }
 175.986 +    }
 175.987 +  default:
 175.988 +    sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
 175.989 +	     base->lock,strerror (errno));
 175.990 +    mm_log (tmp,WARN);		/* this is probably not good */
 175.991 +    break;
 175.992 +  }
 175.993 +  base->lock[0] = '\0';		/* don't use lock files */
 175.994 +  return NIL;
 175.995 +}
 175.996 +
 175.997 +/* Dot-lock file unlocker
 175.998 + * Accepts: lock file name
 175.999 + * Returns: T if success, NIL if failure
175.1000 + */
175.1001 +
175.1002 +long dotlock_unlock (DOTLOCK *base)
175.1003 +{
175.1004 +  long ret = LONGT;
175.1005 +  if (base && base->lock[0]) {
175.1006 +    if (base->pipei >= 0) {	/* if running through a pipe unlocker */
175.1007 +      ret = (write (base->pipeo,"+",1) == 1);
175.1008 +				/* nuke the pipes */
175.1009 +      close (base->pipei); close (base->pipeo);
175.1010 +    }
175.1011 +    else ret = !unlink (base->lock);
175.1012 +  }
175.1013 +  return ret;
175.1014 +}
175.1015 +
175.1016 +/* Lock file name
175.1017 + * Accepts: scratch buffer
175.1018 + *	    file name
175.1019 + *	    type of locking operation (LOCK_SH or LOCK_EX)
175.1020 + *	    pointer to return PID of locker
175.1021 + * Returns: file descriptor of lock or negative if error
175.1022 + */
175.1023 +
175.1024 +int lockname (char *lock,char *fname,int op,long *pid)
175.1025 +{
175.1026 +  struct stat sbuf;
175.1027 +  *pid = 0;			/* no locker PID */
175.1028 +  return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
175.1029 +}
175.1030 +
175.1031 +
175.1032 +/* Lock file descriptor
175.1033 + * Accepts: file descriptor
175.1034 + *	    lock file name buffer
175.1035 + *	    type of locking operation (LOCK_SH or LOCK_EX)
175.1036 + * Returns: file descriptor of lock or negative if error
175.1037 + */
175.1038 +
175.1039 +int lockfd (int fd,char *lock,int op)
175.1040 +{
175.1041 +  struct stat sbuf;
175.1042 +  return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
175.1043 +}
175.1044 +
175.1045 +/* Lock file name worker
175.1046 + * Accepts: lock file name
175.1047 + *	    pointer to stat() buffer
175.1048 + *	    type of locking operation (LOCK_SH or LOCK_EX)
175.1049 + *	    pointer to return PID of locker
175.1050 + * Returns: file descriptor of lock or negative if error
175.1051 + */
175.1052 +
175.1053 +int lock_work (char *lock,void *sb,int op,long *pid)
175.1054 +{
175.1055 +  struct stat lsb,fsb;
175.1056 +  struct stat *sbuf = (struct stat *) sb;
175.1057 +  char tmp[MAILTMPLEN];
175.1058 +  long i;
175.1059 +  int fd;
175.1060 +  int mask = umask (0);
175.1061 +  if (pid) *pid = 0;		/* initialize return PID */
175.1062 +				/* make temporary lock file name */
175.1063 +  sprintf (lock,"%s/.%lx.%lx","/tmp",
175.1064 +	   (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
175.1065 +  while (T) {			/* until get a good lock */
175.1066 +    do switch ((int) chk_notsymlink (lock,&lsb)) {
175.1067 +    case 1:			/* exists just once */
175.1068 +      if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) ||
175.1069 +	  (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
175.1070 +    case -1:			/* name doesn't exist */
175.1071 +      fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection);
175.1072 +      break;
175.1073 +    default:			/* multiple hard links */
175.1074 +      mm_log ("hard link to lock name",ERROR);
175.1075 +      syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
175.1076 +    case 0:			/* symlink (already did syslog) */
175.1077 +      umask (mask);		/* restore old mask */
175.1078 +      return -1;		/* fail: no lock file */
175.1079 +    } while ((fd < 0) && (errno == EEXIST));
175.1080 +    if (fd < 0) {		/* failed to get file descriptor */
175.1081 +      syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
175.1082 +	      strerror (errno));
175.1083 +      if (stat ("/tmp",&lsb))
175.1084 +	syslog (LOG_CRIT,"SYSTEM ERROR: no /tmp: %s",strerror (errno));
175.1085 +      else if ((lsb.st_mode & 01777) != 01777)
175.1086 +	mm_log ("Can't lock for write: /tmp must have 1777 protection",WARN);
175.1087 +      umask (mask);		/* restore old mask */
175.1088 +      return -1;		/* fail: can't open lock file */
175.1089 +    }
175.1090 +
175.1091 +				/* non-blocking form */
175.1092 +    if (op & LOCK_NB) i = flock (fd,op);
175.1093 +    else {			/* blocking form */
175.1094 +      (*mailblocknotify) (BLOCK_FILELOCK,NIL);
175.1095 +      i = flock (fd,op);
175.1096 +      (*mailblocknotify) (BLOCK_NONE,NIL);
175.1097 +    }
175.1098 +    if (i) {			/* failed, get other process' PID */
175.1099 +      if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
175.1100 +	  (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
175.1101 +	*pid = i;
175.1102 +      close (fd);		/* failed, give up on lock */
175.1103 +      umask (mask);		/* restore old mask */
175.1104 +      return -1;		/* fail: can't lock */
175.1105 +    }
175.1106 +				/* make sure this lock is good for us */
175.1107 +    if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
175.1108 +	!fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
175.1109 +	(lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
175.1110 +    close (fd);			/* lock not right, drop fd and try again */
175.1111 +  }
175.1112 +				/* make sure mode OK (don't use fchmod()) */
175.1113 +  chmod (lock,(int) lock_protection);
175.1114 +  umask (mask);			/* restore old mask */
175.1115 +  return fd;			/* success */
175.1116 +}
175.1117 +
175.1118 +/* Check to make sure not a symlink
175.1119 + * Accepts: file name
175.1120 + *	    stat buffer
175.1121 + * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
175.1122 + */
175.1123 +
175.1124 +long chk_notsymlink (char *name,void *sb)
175.1125 +{
175.1126 +  struct stat *sbuf = (struct stat *) sb;
175.1127 +				/* name exists? */
175.1128 +  if (lstat (name,sbuf)) return -1;
175.1129 +				/* forbid symbolic link */
175.1130 +  if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
175.1131 +    mm_log ("symbolic link on lock name",ERROR);
175.1132 +    syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
175.1133 +	    name);
175.1134 +    return NIL;
175.1135 +  }
175.1136 +  return (long) sbuf->st_nlink;	/* return number of hard links */
175.1137 +}
175.1138 +
175.1139 +
175.1140 +/* Unlock file descriptor
175.1141 + * Accepts: file descriptor
175.1142 + *	    lock file name from lockfd()
175.1143 + */
175.1144 +
175.1145 +void unlockfd (int fd,char *lock)
175.1146 +{
175.1147 +				/* delete the file if no sharers */
175.1148 +  if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
175.1149 +  flock (fd,LOCK_UN);		/* unlock it */
175.1150 +  close (fd);			/* close it */
175.1151 +}
175.1152 +
175.1153 +/* Set proper file protection for mailbox
175.1154 + * Accepts: mailbox name
175.1155 + *	    actual file path name
175.1156 + * Returns: T, always
175.1157 + */
175.1158 +
175.1159 +long set_mbx_protections (char *mailbox,char *path)
175.1160 +{
175.1161 +  struct stat sbuf;
175.1162 +  int mode = (int) mbx_protection;
175.1163 +  if (*mailbox == '#') {	/* possible namespace? */
175.1164 +      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
175.1165 +	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
175.1166 +	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
175.1167 +	  (mailbox[4] == '/')) mode = (int) ftp_protection;
175.1168 +      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
175.1169 +	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
175.1170 +	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
175.1171 +	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
175.1172 +	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
175.1173 +	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
175.1174 +	       (mailbox[7] == '/')) mode = (int) public_protection;
175.1175 +      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
175.1176 +	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
175.1177 +	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
175.1178 +	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
175.1179 +	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
175.1180 +	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
175.1181 +	       (mailbox[7] == '/')) mode = (int) shared_protection;
175.1182 +  }
175.1183 +				/* if a directory */
175.1184 +  if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
175.1185 +				/* set owner search if allow read or write */
175.1186 +    if (mode & 0600) mode |= 0100;
175.1187 +    if (mode & 060) mode |= 010;/* set group search if allow read or write */
175.1188 +    if (mode & 06) mode |= 01;	/* set world search if allow read or write */
175.1189 +				/* preserve directory SGID bit */
175.1190 +    if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
175.1191 +  }
175.1192 +  chmod (path,mode);		/* set the new protection, ignore failure */
175.1193 +  return LONGT;
175.1194 +}
175.1195 +
175.1196 +/* Get proper directory protection
175.1197 + * Accepts: mailbox name
175.1198 + * Returns: directory mode, always
175.1199 + */
175.1200 +
175.1201 +long get_dir_protection (char *mailbox)
175.1202 +{
175.1203 +  if (*mailbox == '#') {	/* possible namespace? */
175.1204 +      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
175.1205 +	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
175.1206 +	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
175.1207 +	  (mailbox[4] == '/')) return ftp_dir_protection;
175.1208 +      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
175.1209 +	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
175.1210 +	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
175.1211 +	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
175.1212 +	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
175.1213 +	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
175.1214 +	       (mailbox[7] == '/')) return public_dir_protection;
175.1215 +      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
175.1216 +	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
175.1217 +	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
175.1218 +	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
175.1219 +	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
175.1220 +	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
175.1221 +	       (mailbox[7] == '/')) return shared_dir_protection;
175.1222 +  }
175.1223 +  return dir_protection;
175.1224 +}
175.1225 +
175.1226 +/* Determine default prototype stream to user
175.1227 + * Accepts: type (NIL for create, T for append)
175.1228 + * Returns: default prototype stream
175.1229 + */
175.1230 +
175.1231 +MAILSTREAM *default_proto (long type)
175.1232 +{
175.1233 +  myusername ();		/* make sure initialized */
175.1234 +				/* return default driver's prototype */
175.1235 +  return type ? appendProto : createProto;
175.1236 +}
175.1237 +
175.1238 +
175.1239 +/* Set up user flags for stream
175.1240 + * Accepts: MAIL stream
175.1241 + * Returns: MAIL stream with user flags set up
175.1242 + */
175.1243 +
175.1244 +MAILSTREAM *user_flags (MAILSTREAM *stream)
175.1245 +{
175.1246 +  int i;
175.1247 +  myusername ();		/* make sure initialized */
175.1248 +  for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
175.1249 +    if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
175.1250 +  return stream;
175.1251 +}
175.1252 +
175.1253 +
175.1254 +/* Return nth user flag
175.1255 + * Accepts: user flag number
175.1256 + * Returns: flag
175.1257 + */
175.1258 +
175.1259 +char *default_user_flag (unsigned long i)
175.1260 +{
175.1261 +  myusername ();		/* make sure initialized */
175.1262 +  return userFlags[i];
175.1263 +}
175.1264 +
175.1265 +/* Default block notify routine
175.1266 + * Accepts: reason for calling
175.1267 + *	    data
175.1268 + * Returns: data
175.1269 + */
175.1270 +
175.1271 +void *mm_blocknotify (int reason,void *data)
175.1272 +{
175.1273 +  void *ret = data;
175.1274 +  switch (reason) {
175.1275 +  case BLOCK_SENSITIVE:		/* entering sensitive code */
175.1276 +    ret = (void *) alarm (0);
175.1277 +    break;
175.1278 +  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
175.1279 +    if ((unsigned int) data) alarm ((unsigned int) data);
175.1280 +    break;
175.1281 +  default:			/* ignore all other reasons */
175.1282 +    break;
175.1283 +  }
175.1284 +  return ret;
175.1285 +}
   176.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   176.2 +++ b/src/osdep/amiga/env_ami.h	Mon Sep 14 15:17:45 2009 +0900
   176.3 @@ -0,0 +1,95 @@
   176.4 +/* ========================================================================
   176.5 + * Copyright 1988-2006 University of Washington
   176.6 + *
   176.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   176.8 + * you may not use this file except in compliance with the License.
   176.9 + * You may obtain a copy of the License at
  176.10 + *
  176.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  176.12 + *
  176.13 + * 
  176.14 + * ========================================================================
  176.15 + */
  176.16 +
  176.17 +/*
  176.18 + * Program:	UNIX environment routines
  176.19 + *
  176.20 + * Author:	Mark Crispin
  176.21 + *		Networks and Distributed Computing
  176.22 + *		Computing & Communications
  176.23 + *		University of Washington
  176.24 + *		Administration Building, AG-44
  176.25 + *		Seattle, WA  98195
  176.26 + *		Internet: MRC@CAC.Washington.EDU
  176.27 + *
  176.28 + * Date:	1 August 1988
  176.29 + * Last Edited:	30 August 2006
  176.30 + */
  176.31 +
  176.32 +
  176.33 +typedef struct dotlock_base {
  176.34 +  char lock[MAILTMPLEN];
  176.35 +  int pipei;
  176.36 +  int pipeo;
  176.37 +} DOTLOCK;
  176.38 +
  176.39 +
  176.40 +/* Bits that can be set in restrictBox */
  176.41 +
  176.42 +#define RESTRICTROOT 0x1	/* restricted box doesn't allow root */
  176.43 +#define RESTRICTOTHERUSER 0x2	/* restricted box doesn't allow other user */
  176.44 +
  176.45 +/* Subscription definitions for UNIX */
  176.46 +
  176.47 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ())
  176.48 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ())
  176.49 +
  176.50 +
  176.51 +/* dorc() options */
  176.52 +
  176.53 +#define SYSCONFIG "/etc/c-client.cf"
  176.54 +
  176.55 +
  176.56 +/* Special users */
  176.57 +
  176.58 +#define ANONYMOUSUSER "nobody"	/* anonymous user */
  176.59 +#define UNLOGGEDUSER "root"	/* unlogged-in user */
  176.60 +#define ADMINGROUP "mailadm"	/* mail administrator group */
  176.61 +
  176.62 +/* Function prototypes */
  176.63 +
  176.64 +#include "env.h"
  176.65 +
  176.66 +void rfc822_fixed_date (char *date);
  176.67 +long env_init (char *user,char *home);
  176.68 +char *myusername_full (unsigned long *flags);
  176.69 +#define MU_LOGGEDIN 0
  176.70 +#define MU_NOTLOGGEDIN 1
  176.71 +#define MU_ANONYMOUS 2
  176.72 +#define myusername() \
  176.73 +  myusername_full (NIL)
  176.74 +char *sysinbox ();
  176.75 +char *mailboxdir (char *dst,char *dir,char *name);
  176.76 +long dotlock_lock (char *file,DOTLOCK *base,int fd);
  176.77 +long dotlock_unlock (DOTLOCK *base);
  176.78 +int lockname (char *lock,char *fname,int op,long *pid);
  176.79 +int lockfd (int fd,char *lock,int op);
  176.80 +int lock_work (char *lock,void *sbuf,int op,long *pid);
  176.81 +long chk_notsymlink (char *name,void *sbuf);
  176.82 +void unlockfd (int fd,char *lock);
  176.83 +long set_mbx_protections (char *mailbox,char *path);
  176.84 +long get_dir_protection (char *mailbox);
  176.85 +MAILSTREAM *user_flags (MAILSTREAM *stream);
  176.86 +char *default_user_flag (unsigned long i);
  176.87 +void dorc (char *file,long flag);
  176.88 +long path_create (MAILSTREAM *stream,char *mailbox);
  176.89 +void grim_pid_reap_status (int pid,int killreq,void *status);
  176.90 +#define grim_pid_reap(pid,killreq) \
  176.91 +  grim_pid_reap_status (pid,killreq,NIL)
  176.92 +long safe_write (int fd,char *buf,long nbytes);
  176.93 +void *arm_signal (int sig,void *action);
  176.94 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]);
  176.95 +long loginpw (struct passwd *pw,int argc,char *argv[]);
  176.96 +long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
  176.97 +	       char *argv[]);
  176.98 +void *mm_blocknotify (int reason,void *data);
   177.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   177.2 +++ b/src/osdep/amiga/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
   177.3 @@ -0,0 +1,99 @@
   177.4 +/* ========================================================================
   177.5 + * Copyright 1988-2007 University of Washington
   177.6 + *
   177.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   177.8 + * you may not use this file except in compliance with the License.
   177.9 + * You may obtain a copy of the License at
  177.10 + *
  177.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  177.12 + *
  177.13 + * 
  177.14 + * ========================================================================
  177.15 + */
  177.16 +
  177.17 +/*
  177.18 + * Program:	File descriptor string routines
  177.19 + *
  177.20 + * Author:	Mark Crispin
  177.21 + *		Networks and Distributed Computing
  177.22 + *		Computing & Communications
  177.23 + *		University of Washington
  177.24 + *		Administration Building, AG-44
  177.25 + *		Seattle, WA  98195
  177.26 + *		Internet: MRC@CAC.Washington.EDU
  177.27 + *
  177.28 + * Date:	15 April 1997
  177.29 + * Last Edited:	4 April 2007
  177.30 + */
  177.31 +
  177.32 +#include "mail.h"
  177.33 +#include "osdep.h"
  177.34 +#include "misc.h"
  177.35 +#include "fdstring.h"
  177.36 +
  177.37 +/* String driver for fd stringstructs */
  177.38 +
  177.39 +static void fd_string_init (STRING *s,void *data,unsigned long size);
  177.40 +static char fd_string_next (STRING *s);
  177.41 +static void fd_string_setpos (STRING *s,unsigned long i);
  177.42 +
  177.43 +STRINGDRIVER fd_string = {
  177.44 +  fd_string_init,		/* initialize string structure */
  177.45 +  fd_string_next,		/* get next byte in string structure */
  177.46 +  fd_string_setpos		/* set position in string structure */
  177.47 +};
  177.48 +
  177.49 +
  177.50 +/* Initialize string structure for fd stringstruct
  177.51 + * Accepts: string structure
  177.52 + *	    pointer to string
  177.53 + *	    size of string
  177.54 + */
  177.55 +
  177.56 +static void fd_string_init (STRING *s,void *data,unsigned long size)
  177.57 +{
  177.58 +  FDDATA *d = (FDDATA *) data;
  177.59 +				/* note fd */
  177.60 +  s->data = (void *) (unsigned long) d->fd;
  177.61 +  s->data1 = d->pos;		/* note file offset */
  177.62 +  s->size = size;		/* note size */
  177.63 +  s->curpos = s->chunk = d->chunk;
  177.64 +  s->chunksize = (unsigned long) d->chunksize;
  177.65 +  s->offset = 0;		/* initial position */
  177.66 +				/* and size of data */
  177.67 +  s->cursize = min (s->chunksize,size);
  177.68 +				/* move to that position in the file */
  177.69 +  lseek (d->fd,d->pos,L_SET);
  177.70 +  read (d->fd,s->chunk,(size_t) s->cursize);
  177.71 +}
  177.72 +
  177.73 +/* Get next character from fd stringstruct
  177.74 + * Accepts: string structure
  177.75 + * Returns: character, string structure chunk refreshed
  177.76 + */
  177.77 +
  177.78 +static char fd_string_next (STRING *s)
  177.79 +{
  177.80 +  char c = *s->curpos++;	/* get next byte */
  177.81 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
  177.82 +  return c;			/* return the byte */
  177.83 +}
  177.84 +
  177.85 +
  177.86 +/* Set string pointer position for fd stringstruct
  177.87 + * Accepts: string structure
  177.88 + *	    new position
  177.89 + */
  177.90 +
  177.91 +static void fd_string_setpos (STRING *s,unsigned long i)
  177.92 +{
  177.93 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
  177.94 +  s->offset = i;		/* set new offset */
  177.95 +  s->curpos = s->chunk;		/* reset position */
  177.96 +				/* set size of data */
  177.97 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
  177.98 +				/* move to that position in the file */
  177.99 +    lseek ((long) s->data,s->data1 + s->offset,L_SET);
 177.100 +    read ((long) s->data,s->curpos,(size_t) s->cursize);
 177.101 +  }
 177.102 +}
   178.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   178.2 +++ b/src/osdep/amiga/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
   178.3 @@ -0,0 +1,39 @@
   178.4 +/* ========================================================================
   178.5 + * Copyright 1988-2006 University of Washington
   178.6 + *
   178.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   178.8 + * you may not use this file except in compliance with the License.
   178.9 + * You may obtain a copy of the License at
  178.10 + *
  178.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  178.12 + *
  178.13 + * 
  178.14 + * ========================================================================
  178.15 + */
  178.16 +
  178.17 +/*
  178.18 + * Program:	File descriptor string routines
  178.19 + *
  178.20 + * Author:	Mark Crispin
  178.21 + *		Networks and Distributed Computing
  178.22 + *		Computing & Communications
  178.23 + *		University of Washington
  178.24 + *		Administration Building, AG-44
  178.25 + *		Seattle, WA  98195
  178.26 + *		Internet: MRC@CAC.Washington.EDU
  178.27 + *
  178.28 + * Date:	15 April 1997
  178.29 + * Last Edited:	30 August 2006
  178.30 + */
  178.31 +
  178.32 +/* Driver-dependent data passed to init method */
  178.33 +
  178.34 +typedef struct fd_data {
  178.35 +  int fd;			/* file descriptor */
  178.36 +  unsigned long pos;		/* initial position */
  178.37 +  char *chunk;			/* I/O buffer chunk */
  178.38 +  unsigned long chunksize;	/* I/O buffer chunk length */
  178.39 +} FDDATA;
  178.40 +
  178.41 +
  178.42 +extern STRINGDRIVER fd_string;
   179.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   179.2 +++ b/src/osdep/amiga/fs_ami.c	Mon Sep 14 15:17:45 2009 +0900
   179.3 @@ -0,0 +1,71 @@
   179.4 +/* ========================================================================
   179.5 + * Copyright 1988-2006 University of Washington
   179.6 + *
   179.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   179.8 + * you may not use this file except in compliance with the License.
   179.9 + * You may obtain a copy of the License at
  179.10 + *
  179.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  179.12 + *
  179.13 + * 
  179.14 + * ========================================================================
  179.15 + */
  179.16 +
  179.17 +/*
  179.18 + * Program:	Free storage management routines
  179.19 + *
  179.20 + * Author:	Mark Crispin
  179.21 + *		Networks and Distributed Computing
  179.22 + *		Computing & Communications
  179.23 + *		University of Washington
  179.24 + *		Administration Building, AG-44
  179.25 + *		Seattle, WA  98195
  179.26 + *		Internet: MRC@CAC.Washington.EDU
  179.27 + *
  179.28 + * Date:	1 August 1988
  179.29 + * Last Edited:	30 August 2006
  179.30 + */
  179.31 +
  179.32 +/* Get a block of free storage
  179.33 + * Accepts: size of desired block
  179.34 + * Returns: free storage block
  179.35 + */
  179.36 +
  179.37 +void *fs_get (size_t size)
  179.38 +{
  179.39 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  179.40 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
  179.41 +  void *block = malloc (size ? size : (size_t) 1);
  179.42 +  if (!block) fatal ("Out of memory");
  179.43 +  (*bn) (BLOCK_NONSENSITIVE,data);
  179.44 +  return (block);
  179.45 +}
  179.46 +
  179.47 +
  179.48 +/* Resize a block of free storage
  179.49 + * Accepts: ** pointer to current block
  179.50 + *	    new size
  179.51 + */
  179.52 +
  179.53 +void fs_resize (void **block,size_t size)
  179.54 +{
  179.55 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  179.56 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
  179.57 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  179.58 +    fatal ("Can't resize memory");
  179.59 +  (*bn) (BLOCK_NONSENSITIVE,data);
  179.60 +}
  179.61 +
  179.62 +
  179.63 +/* Return a block of free storage
  179.64 + * Accepts: ** pointer to free storage block
  179.65 + */
  179.66 +
  179.67 +void fs_give (void **block)
  179.68 +{
  179.69 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  179.70 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
  179.71 +  free (*block);
  179.72 +  *block = NIL;
  179.73 +  (*bn) (BLOCK_NONSENSITIVE,data);
  179.74 +}
   180.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   180.2 +++ b/src/osdep/amiga/ftl_ami.c	Mon Sep 14 15:17:45 2009 +0900
   180.3 @@ -0,0 +1,38 @@
   180.4 +/* ========================================================================
   180.5 + * Copyright 1988-2006 University of Washington
   180.6 + *
   180.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   180.8 + * you may not use this file except in compliance with the License.
   180.9 + * You may obtain a copy of the License at
  180.10 + *
  180.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  180.12 + *
  180.13 + * 
  180.14 + * ========================================================================
  180.15 + */
  180.16 +
  180.17 +/*
  180.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  180.19 + *
  180.20 + * Author:	Mark Crispin
  180.21 + *		Networks and Distributed Computing
  180.22 + *		Computing & Communications
  180.23 + *		University of Washington
  180.24 + *		Administration Building, AG-44
  180.25 + *		Seattle, WA  98195
  180.26 + *		Internet: MRC@CAC.Washington.EDU
  180.27 + *
  180.28 + * Date:	1 August 1988
  180.29 + * Last Edited:	30 August 2006
  180.30 + */
  180.31 +
  180.32 +
  180.33 +/* Report a fatal error
  180.34 + * Accepts: string to output
  180.35 + */
  180.36 +
  180.37 +void fatal (char *string)
  180.38 +{
  180.39 +  mm_fatal (string);		/* pass up the string */
  180.40 +  abort ();			/* die horribly */
  180.41 +}
   181.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   181.2 +++ b/src/osdep/amiga/gethstid.c	Mon Sep 14 15:17:45 2009 +0900
   181.3 @@ -0,0 +1,38 @@
   181.4 +/* ========================================================================
   181.5 + * Copyright 1988-2006 University of Washington
   181.6 + *
   181.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   181.8 + * you may not use this file except in compliance with the License.
   181.9 + * You may obtain a copy of the License at
  181.10 + *
  181.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  181.12 + *
  181.13 + * 
  181.14 + * ========================================================================
  181.15 + */
  181.16 +
  181.17 +/*
  181.18 + * Program:	Get host ID emulator
  181.19 + *
  181.20 + * Author:	Mark Crispin
  181.21 + *		Networks and Distributed Computing
  181.22 + *		Computing & Communications
  181.23 + *		University of Washington
  181.24 + *		Administration Building, AG-44
  181.25 + *		Seattle, WA  98195
  181.26 + *		Internet: MRC@CAC.Washington.EDU
  181.27 + *
  181.28 + * Date:	3 May 1995
  181.29 + * Last Edited:	30 August 2006
  181.30 + */
  181.31 +
  181.32 +
  181.33 +/* Emulator for BSD gethostid() call
  181.34 + * Returns: unique identifier for this machine
  181.35 + */
  181.36 +
  181.37 +long gethostid (void)
  181.38 +{
  181.39 +  /* No gethostid() here, so just fake it and hope things turn out okay. */
  181.40 +  return 0xdeadface;
  181.41 +}
   182.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   182.2 +++ b/src/osdep/amiga/gr_waitp.c	Mon Sep 14 15:17:45 2009 +0900
   182.3 @@ -0,0 +1,39 @@
   182.4 +/* ========================================================================
   182.5 + * Copyright 1988-2006 University of Washington
   182.6 + *
   182.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   182.8 + * you may not use this file except in compliance with the License.
   182.9 + * You may obtain a copy of the License at
  182.10 + *
  182.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  182.12 + *
  182.13 + * 
  182.14 + * ========================================================================
  182.15 + */
  182.16 +
  182.17 +/*
  182.18 + * Program:	UNIX Grim PID Reaper -- waitpid() version
  182.19 + *
  182.20 + * Author:	Mark Crispin
  182.21 + *		Networks and Distributed Computing
  182.22 + *		Computing & Communications
  182.23 + *		University of Washington
  182.24 + *		Administration Building, AG-44
  182.25 + *		Seattle, WA  98195
  182.26 + *		Internet: MRC@CAC.Washington.EDU
  182.27 + *
  182.28 + * Date:	30 November 1993
  182.29 + * Last Edited:	30 August 2006
  182.30 + */
  182.31 + 
  182.32 +/* Grim PID reaper
  182.33 + * Accepts: process ID
  182.34 + *	    kill request flag
  182.35 + *	    status return value
  182.36 + */
  182.37 +
  182.38 +void grim_pid_reap_status (int pid,int killreq,void *status)
  182.39 +{
  182.40 +  if (killreq) kill(pid,SIGHUP);/* kill if not already dead */
  182.41 +  while ((waitpid (pid,status,NIL) < 0) && (errno != ECHILD));
  182.42 +}
   183.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   183.2 +++ b/src/osdep/amiga/log_std.c	Mon Sep 14 15:17:45 2009 +0900
   183.3 @@ -0,0 +1,44 @@
   183.4 +/* ========================================================================
   183.5 + * Copyright 1988-2006 University of Washington
   183.6 + *
   183.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   183.8 + * you may not use this file except in compliance with the License.
   183.9 + * You may obtain a copy of the License at
  183.10 + *
  183.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  183.12 + *
  183.13 + * 
  183.14 + * ========================================================================
  183.15 + */
  183.16 +
  183.17 +/*
  183.18 + * Program:	Standard login
  183.19 + *
  183.20 + * Author:	Mark Crispin
  183.21 + *		Networks and Distributed Computing
  183.22 + *		Computing & Communications
  183.23 + *		University of Washington
  183.24 + *		Administration Building, AG-44
  183.25 + *		Seattle, WA  98195
  183.26 + *		Internet: MRC@CAC.Washington.EDU
  183.27 + *
  183.28 + * Date:	1 August 1988
  183.29 + * Last Edited:	30 August 2006
  183.30 + */
  183.31 +
  183.32 +/* Log in
  183.33 + * Accepts: login passwd struct
  183.34 + *	    argument count
  183.35 + *	    argument vector
  183.36 + * Returns: T if success, NIL otherwise
  183.37 + */
  183.38 +
  183.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  183.40 +{
  183.41 +  uid_t uid = pw->pw_uid;
  183.42 +  char *name = cpystr (pw->pw_name);
  183.43 +  long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) ||
  183.44 +	       setuid (uid));
  183.45 +  fs_give ((void **) &name);
  183.46 +  return ret;
  183.47 +}
   184.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   184.2 +++ b/src/osdep/amiga/mbx.c	Mon Sep 14 15:17:45 2009 +0900
   184.3 @@ -0,0 +1,1855 @@
   184.4 +/* ========================================================================
   184.5 + * Copyright 1988-2007 University of Washington
   184.6 + *
   184.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   184.8 + * you may not use this file except in compliance with the License.
   184.9 + * You may obtain a copy of the License at
  184.10 + *
  184.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  184.12 + *
  184.13 + * 
  184.14 + * ========================================================================
  184.15 + */
  184.16 +
  184.17 +/*
  184.18 + * Program:	MBX mail routines
  184.19 + *
  184.20 + * Author:	Mark Crispin
  184.21 + *		Networks and Distributed Computing
  184.22 + *		Computing & Communications
  184.23 + *		University of Washington
  184.24 + *		Administration Building, AG-44
  184.25 + *		Seattle, WA  98195
  184.26 + *		Internet: MRC@CAC.Washington.EDU
  184.27 + *
  184.28 + * Date:	3 October 1995
  184.29 + * Last Edited:	11 October 2007
  184.30 + */
  184.31 +
  184.32 +
  184.33 +/*				FILE TIME SEMANTICS
  184.34 + *
  184.35 + * The atime is the last read time of the file.
  184.36 + * The mtime is the last flags update time of the file.
  184.37 + * The ctime is the last write time of the file.
  184.38 + */
  184.39 +
  184.40 +#include <stdio.h>
  184.41 +#include <ctype.h>
  184.42 +#include <errno.h>
  184.43 +extern int errno;		/* just in case */
  184.44 +#include "mail.h"
  184.45 +#include "osdep.h"
  184.46 +#include <pwd.h>
  184.47 +#include <sys/stat.h>
  184.48 +#include <sys/time.h>
  184.49 +#include "misc.h"
  184.50 +#include "dummy.h"
  184.51 +#include "fdstring.h"
  184.52 +
  184.53 +
  184.54 +/* Build parameters */
  184.55 +
  184.56 +#define HDRSIZE 2048
  184.57 +
  184.58 +
  184.59 +/* Kludge to make Cygwin happy */
  184.60 +
  184.61 +#ifndef O_BINARY
  184.62 +#define O_BINARY 0
  184.63 +#endif
  184.64 +
  184.65 +/* MBX I/O stream local data */
  184.66 +	
  184.67 +typedef struct mbx_local {
  184.68 +  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
  184.69 +  unsigned int expok: 1;	/* if expunging OK in ping */
  184.70 +  unsigned int expunged : 1;	/* if one or more expunged messages */
  184.71 +  int fd;			/* file descriptor for I/O */
  184.72 +  int ld;			/* lock file descriptor */
  184.73 +  int ffuserflag;		/* first free user flag */
  184.74 +  off_t filesize;		/* file size parsed */
  184.75 +  time_t filetime;		/* last file time */
  184.76 +  time_t lastsnarf;		/* last snarf time */
  184.77 +  unsigned long lastpid;	/* PID of last writer */
  184.78 +  unsigned char *buf;		/* temporary buffer */
  184.79 +  unsigned long buflen;		/* current size of temporary buffer */
  184.80 +  char lock[MAILTMPLEN];	/* buffer to write lock name */
  184.81 +} MBXLOCAL;
  184.82 +
  184.83 +
  184.84 +/* Convenient access to local data */
  184.85 +
  184.86 +#define LOCAL ((MBXLOCAL *) stream->local)
  184.87 +
  184.88 +/* Function prototypes */
  184.89 +
  184.90 +DRIVER *mbx_valid (char *name);
  184.91 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
  184.92 +		 long flags);
  184.93 +void *mbx_parameters (long function,void *value);
  184.94 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  184.95 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
  184.96 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  184.97 +long mbx_create (MAILSTREAM *stream,char *mailbox);
  184.98 +long mbx_delete (MAILSTREAM *stream,char *mailbox);
  184.99 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
 184.100 +long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
 184.101 +MAILSTREAM *mbx_open (MAILSTREAM *stream);
 184.102 +void mbx_close (MAILSTREAM *stream,long options);
 184.103 +void mbx_abort (MAILSTREAM *stream);
 184.104 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
 184.105 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 184.106 +		  long flags);
 184.107 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 184.108 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 184.109 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 184.110 +long mbx_ping (MAILSTREAM *stream);
 184.111 +void mbx_check (MAILSTREAM *stream);
 184.112 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
 184.113 +void mbx_snarf (MAILSTREAM *stream);
 184.114 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 184.115 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 184.116 +
 184.117 +char *mbx_file (char *dst,char *name);
 184.118 +long mbx_parse (MAILSTREAM *stream);
 184.119 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
 184.120 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 184.121 +void mbx_update_header (MAILSTREAM *stream);
 184.122 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
 184.123 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 184.124 +			  unsigned long *size,char **hdr);
 184.125 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
 184.126 +			   long flags);
 184.127 +long mbx_flaglock (MAILSTREAM *stream);
 184.128 +
 184.129 +/* MBX mail routines */
 184.130 +
 184.131 +
 184.132 +/* Driver dispatch used by MAIL */
 184.133 +
 184.134 +DRIVER mbxdriver = {
 184.135 +  "mbx",			/* driver name */
 184.136 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
 184.137 +				/* driver flags */
 184.138 +  (DRIVER *) NIL,		/* next driver */
 184.139 +  mbx_valid,			/* mailbox is valid for us */
 184.140 +  mbx_parameters,		/* manipulate parameters */
 184.141 +  mbx_scan,			/* scan mailboxes */
 184.142 +  mbx_list,			/* list mailboxes */
 184.143 +  mbx_lsub,			/* list subscribed mailboxes */
 184.144 +  NIL,				/* subscribe to mailbox */
 184.145 +  NIL,				/* unsubscribe from mailbox */
 184.146 +  mbx_create,			/* create mailbox */
 184.147 +  mbx_delete,			/* delete mailbox */
 184.148 +  mbx_rename,			/* rename mailbox */
 184.149 +  mbx_status,			/* status of mailbox */
 184.150 +  mbx_open,			/* open mailbox */
 184.151 +  mbx_close,			/* close mailbox */
 184.152 +  mbx_flags,			/* fetch message "fast" attributes */
 184.153 +  mbx_flags,			/* fetch message flags */
 184.154 +  NIL,				/* fetch overview */
 184.155 +  NIL,				/* fetch message envelopes */
 184.156 +  mbx_header,			/* fetch message header */
 184.157 +  mbx_text,			/* fetch message body */
 184.158 +  NIL,				/* fetch partial message text */
 184.159 +  NIL,				/* unique identifier */
 184.160 +  NIL,				/* message number */
 184.161 +  mbx_flag,			/* modify flags */
 184.162 +  mbx_flagmsg,			/* per-message modify flags */
 184.163 +  NIL,				/* search for message based on criteria */
 184.164 +  NIL,				/* sort messages */
 184.165 +  NIL,				/* thread messages */
 184.166 +  mbx_ping,			/* ping mailbox to see if still alive */
 184.167 +  mbx_check,			/* check for new messages */
 184.168 +  mbx_expunge,			/* expunge deleted messages */
 184.169 +  mbx_copy,			/* copy messages to another mailbox */
 184.170 +  mbx_append,			/* append string message to mailbox */
 184.171 +  NIL				/* garbage collect stream */
 184.172 +};
 184.173 +
 184.174 +				/* prototype stream */
 184.175 +MAILSTREAM mbxproto = {&mbxdriver};
 184.176 +
 184.177 +/* MBX mail validate mailbox
 184.178 + * Accepts: mailbox name
 184.179 + * Returns: our driver if name is valid, NIL otherwise
 184.180 + */
 184.181 +
 184.182 +DRIVER *mbx_valid (char *name)
 184.183 +{
 184.184 +  char tmp[MAILTMPLEN];
 184.185 +  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
 184.186 +  if (fd < 0) return NIL;
 184.187 +  close (fd);			/* don't need the fd now */
 184.188 +  return &mbxdriver;
 184.189 +}
 184.190 +
 184.191 +
 184.192 +/* MBX mail test for valid mailbox
 184.193 + * Accepts: returned stream with valid mailbox keywords
 184.194 + *	    mailbox name
 184.195 + *	    scratch buffer
 184.196 + *	    returned lock fd
 184.197 + *	    returned lock name
 184.198 + *	    RW flags or NIL for readonly
 184.199 + * Returns: file descriptor if valid, NIL otherwise
 184.200 + */
 184.201 +
 184.202 +#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
 184.203 +#define MBXISVALIDUID 0x2	/* RW, do UID action */
 184.204 +
 184.205 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
 184.206 +		 long flags)
 184.207 +{
 184.208 +  int fd,upd;
 184.209 +  int ret = -1;
 184.210 +  unsigned long i;
 184.211 +  long j,k;
 184.212 +  off_t pos;
 184.213 +  char c,*s,*t,hdr[HDRSIZE];
 184.214 +  struct stat sbuf;
 184.215 +  time_t tp[2];
 184.216 +  int error = EINVAL;		/* assume invalid argument */
 184.217 +  if (ld) *ld = -1;		/* initially no lock */
 184.218 +  if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) &&
 184.219 +      ((fd = open (tmp,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
 184.220 +    error = -1;			/* bogus format */
 184.221 +		/* I love cretinous C compilers -- don't you? */
 184.222 +    if (read (fd,hdr,HDRSIZE) == HDRSIZE)
 184.223 +      if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') &&
 184.224 +	  (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') &&
 184.225 +	  (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]))
 184.226 +	if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) &&
 184.227 +	    isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) &&
 184.228 +	    isxdigit (c = hdr[15]) && isxdigit (hdr[16]))
 184.229 +	  if (isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
 184.230 +	      isxdigit (hdr[19]) && isxdigit (hdr[20]) &&
 184.231 +	      isxdigit (hdr[21]) && isxdigit (hdr[22]) &&
 184.232 +	      (hdr[23] == '\015') && (hdr[24] == '\012')) {
 184.233 +	    ret = fd;		/* mbx format */
 184.234 +
 184.235 +	    if (stream) {	/* lock if making mini-stream */
 184.236 +	      if (flock (fd,LOCK_SH) ||
 184.237 +		  (flags && ((*ld = lockfd (fd,lock,LOCK_EX)) < 0))) ret = -1;
 184.238 +				/* reread data now that locked */
 184.239 +	      else if (lseek (fd,0,L_SET) ||
 184.240 +		       (read (fd,hdr,HDRSIZE) != HDRSIZE)) ret = -1;
 184.241 +	      else {
 184.242 +		*stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),
 184.243 +						 0,sizeof (MAILSTREAM));
 184.244 +		hdr[15] = '\0';	/* tie off UIDVALIDITY */
 184.245 +		(*stream)->uid_validity = strtoul (hdr+7,NIL,16);
 184.246 +		hdr[15] = c;	/* now get UIDLAST */
 184.247 +		(*stream)->uid_last = strtoul (hdr+15,NIL,16);
 184.248 +				/* parse user flags */
 184.249 +		for (i = 0, s = hdr + 25;
 184.250 +		     (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
 184.251 +		     i++, s = t + 2) {
 184.252 +		  *t = '\0';	/* tie off flag */
 184.253 +		  if (strlen (s) <= MAXUSERFLAG)
 184.254 +		    (*stream)->user_flags[i] = cpystr (s);
 184.255 +		}
 184.256 +				/* make sure have true UIDLAST */
 184.257 +		if (flags & MBXISVALIDUID) {
 184.258 +		  for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
 184.259 +		       pos += (j + k)) {
 184.260 +				/* read header for this message */
 184.261 +		    lseek (fd,pos,L_SET);
 184.262 +		    if ((j = read (fd,hdr,64)) >= 0) {
 184.263 +		      hdr[j] = '\0';
 184.264 +		      if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
 184.265 +			*s = '\0';
 184.266 +			k = s + 2 - hdr;
 184.267 +			if ((s = strchr (hdr,',')) &&
 184.268 +			    (j = strtol (s+1,&s,10)) && (*s == ';') &&
 184.269 +			    (s = strchr (s+1,'-'))) {
 184.270 +				/* get UID if there is any */
 184.271 +			  i = strtoul (++s,&t,16);
 184.272 +			  if (!*t && (t == (s + 8)) &&
 184.273 +			      (i <= (*stream)->uid_last)) {
 184.274 +			    if (!i) {
 184.275 +			      lseek (fd,pos + s - hdr,L_SET);
 184.276 +			      sprintf (hdr,"%08lx",++(*stream)->uid_last);
 184.277 +			      write (fd,hdr,8);
 184.278 +			      upd = T;
 184.279 +			    }
 184.280 +			    continue;
 184.281 +			  }
 184.282 +			}
 184.283 +		      }
 184.284 +		      ret = -1;	/* error, give up */
 184.285 +		      *stream = mail_close (*stream);
 184.286 +		      pos = sbuf.st_size + 1;
 184.287 +		      j = k = 0;
 184.288 +		    }
 184.289 +		  }
 184.290 +
 184.291 +		  if (upd) {	/* need to update hdr with new UIDLAST? */
 184.292 +		    lseek (fd,15,L_SET);
 184.293 +		    sprintf (hdr,"%08lx",(*stream)->uid_last);
 184.294 +		    write (fd,hdr,8);
 184.295 +		  }
 184.296 +		}
 184.297 +	      }
 184.298 +	    }
 184.299 +	  }
 184.300 +    if (ret != fd) close (fd);	/* close the file */
 184.301 +    else lseek (fd,0,L_SET);	/* else rewind to start */
 184.302 +				/* \Marked status? */
 184.303 +    if (sbuf.st_ctime > sbuf.st_atime) {
 184.304 +      tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 184.305 +      tp[1] = sbuf.st_mtime;
 184.306 +      utime (tmp,tp);		/* set the times */
 184.307 +    }
 184.308 +  }
 184.309 +				/* in case INBOX but not mbx format */
 184.310 +  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
 184.311 +    error = -1;
 184.312 +  if ((ret < 0) && ld && (*ld >= 0)) {
 184.313 +    unlockfd (*ld,lock);
 184.314 +    *ld = -1;
 184.315 +  }
 184.316 +  errno = error;		/* return as last error */
 184.317 +  return ret;			/* return what we should */
 184.318 +}
 184.319 +
 184.320 +/* MBX manipulate driver parameters
 184.321 + * Accepts: function code
 184.322 + *	    function-dependent value
 184.323 + * Returns: function-dependent return value
 184.324 + */
 184.325 +
 184.326 +void *mbx_parameters (long function,void *value)
 184.327 +{
 184.328 +  void *ret = NIL;
 184.329 +  switch ((int) function) {
 184.330 +  case GET_INBOXPATH:
 184.331 +    if (value) ret = mbx_file ((char *) value,"INBOX");
 184.332 +    break;
 184.333 +  case SET_ONETIMEEXPUNGEATPING:
 184.334 +    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
 184.335 +  case GET_ONETIMEEXPUNGEATPING:
 184.336 +    if (value) ret = (void *)
 184.337 +      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
 184.338 +    break;
 184.339 +  }
 184.340 +  return ret;
 184.341 +}
 184.342 +
 184.343 +
 184.344 +/* MBX mail scan mailboxes
 184.345 + * Accepts: mail stream
 184.346 + *	    reference
 184.347 + *	    pattern to search
 184.348 + *	    string to scan
 184.349 + */
 184.350 +
 184.351 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 184.352 +{
 184.353 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 184.354 +}
 184.355 +
 184.356 +
 184.357 +/* MBX mail list mailboxes
 184.358 + * Accepts: mail stream
 184.359 + *	    reference
 184.360 + *	    pattern to search
 184.361 + */
 184.362 +
 184.363 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
 184.364 +{
 184.365 +  if (stream) dummy_list (NIL,ref,pat);
 184.366 +}
 184.367 +
 184.368 +
 184.369 +/* MBX mail list subscribed mailboxes
 184.370 + * Accepts: mail stream
 184.371 + *	    reference
 184.372 + *	    pattern to search
 184.373 + */
 184.374 +
 184.375 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 184.376 +{
 184.377 +  if (stream) dummy_lsub (NIL,ref,pat);
 184.378 +}
 184.379 +
 184.380 +/* MBX mail create mailbox
 184.381 + * Accepts: MAIL stream
 184.382 + *	    mailbox name to create
 184.383 + * Returns: T on success, NIL on failure
 184.384 + */
 184.385 +
 184.386 +long mbx_create (MAILSTREAM *stream,char *mailbox)
 184.387 +{
 184.388 +  char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE];
 184.389 +  long ret = NIL;
 184.390 +  int i,fd;
 184.391 +  if (!(s = mbx_file (mbx,mailbox))) {
 184.392 +    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 184.393 +    MM_LOG (mbx,ERROR);
 184.394 +  }
 184.395 +				/* create underlying file */
 184.396 +  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
 184.397 +				/* done if made directory */
 184.398 +    if ((s = strrchr (s,'/')) && !s[1]) return T;
 184.399 +    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
 184.400 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 184.401 +      MM_LOG (tmp,ERROR);
 184.402 +      unlink (mbx);		/* delete the file */
 184.403 +    }
 184.404 +    else {
 184.405 +      memset (tmp,'\0',HDRSIZE);/* initialize header */
 184.406 +      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
 184.407 +	       (unsigned long) time (0));
 184.408 +      for (i = 0; i < NUSERFLAGS; ++i) {
 184.409 +	t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
 184.410 +	  ((t = default_user_flag (i)) ? t : "");
 184.411 +	sprintf (s += strlen (s),"%s\015\012",t);
 184.412 +      }
 184.413 +      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
 184.414 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
 184.415 +		 mbx,strerror (errno));
 184.416 +	MM_LOG (tmp,ERROR);
 184.417 +	unlink (mbx);		/* delete the file */
 184.418 +      }
 184.419 +      else ret = T;		/* success */
 184.420 +      close (fd);		/* close file */
 184.421 +    }
 184.422 +  }
 184.423 +				/* set proper protections */
 184.424 +  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
 184.425 +}
 184.426 +
 184.427 +
 184.428 +/* MBX mail delete mailbox
 184.429 + * Accepts: MAIL stream
 184.430 + *	    mailbox name to delete
 184.431 + * Returns: T on success, NIL on failure
 184.432 + */
 184.433 +
 184.434 +long mbx_delete (MAILSTREAM *stream,char *mailbox)
 184.435 +{
 184.436 +  return mbx_rename (stream,mailbox,NIL);
 184.437 +}
 184.438 +
 184.439 +/* MBX mail rename mailbox
 184.440 + * Accepts: MAIL stream
 184.441 + *	    old mailbox name
 184.442 + *	    new mailbox name (or NIL for delete)
 184.443 + * Returns: T on success, NIL on failure
 184.444 + */
 184.445 +
 184.446 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
 184.447 +{
 184.448 +  long ret = LONGT;
 184.449 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 184.450 +  int fd,ld;
 184.451 +  struct stat sbuf;
 184.452 +  if (!mbx_file (file,old) ||
 184.453 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 184.454 +		   ((s = strrchr (tmp,'/')) && !s[1])))) {
 184.455 +    sprintf (tmp,newname ?
 184.456 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 184.457 +	     "Can't delete mailbox %.80s: invalid name",
 184.458 +	     old,newname);
 184.459 +    MM_LOG (tmp,ERROR);
 184.460 +    return NIL;
 184.461 +  }
 184.462 +  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
 184.463 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 184.464 +    MM_LOG (tmp,ERROR);
 184.465 +    return NIL;
 184.466 +  }
 184.467 +				/* get parse/append permission */
 184.468 +  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
 184.469 +    MM_LOG ("Unable to lock rename mailbox",ERROR);
 184.470 +    return NIL;
 184.471 +  }
 184.472 +				/* lock out other users */
 184.473 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 184.474 +    close (fd);			/* couldn't lock, give up on it then */
 184.475 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 184.476 +    MM_LOG (tmp,ERROR);
 184.477 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 184.478 +    return NIL;
 184.479 +  }
 184.480 +
 184.481 +  if (newname) {		/* want rename? */
 184.482 +				/* found superior to destination name? */
 184.483 +    if (s = strrchr (tmp,'/')) {
 184.484 +      c = *++s;			/* remember first character of inferior */
 184.485 +      *s = '\0';		/* tie off to get just superior */
 184.486 +				/* superior name doesn't exist, create it */
 184.487 +      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 184.488 +	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
 184.489 +	ret = NIL;
 184.490 +      else *s = c;		/* restore full name */
 184.491 +    }
 184.492 +				/* rename the file */
 184.493 +    if (ret && rename (file,tmp)) {
 184.494 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 184.495 +	       strerror (errno));
 184.496 +      MM_LOG (tmp,ERROR);
 184.497 +      ret = NIL;		/* set failure */
 184.498 +    }
 184.499 +  }
 184.500 +  else if (unlink (file)) {
 184.501 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 184.502 +    MM_LOG (tmp,ERROR);
 184.503 +    ret = NIL;			/* set failure */
 184.504 +  }
 184.505 +  flock (fd,LOCK_UN);		/* release lock on the file */
 184.506 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 184.507 +  close (fd);			/* close the file */
 184.508 +				/* recreate file if renamed INBOX */
 184.509 +  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
 184.510 +  return ret;			/* return success */
 184.511 +}
 184.512 +
 184.513 +/* MBX Mail status
 184.514 + * Accepts: mail stream
 184.515 + *	    mailbox name
 184.516 + *	    status flags
 184.517 + * Returns: T on success, NIL on failure
 184.518 + */
 184.519 +
 184.520 +long mbx_status (MAILSTREAM *stream,char *mbx,long flags)
 184.521 +{
 184.522 +  MAILSTATUS status;
 184.523 +  unsigned long i;
 184.524 +  MAILSTREAM *tstream = NIL;
 184.525 +  MAILSTREAM *systream = NIL;
 184.526 +				/* make temporary stream (unless this mbx) */
 184.527 +  if (!stream && !(stream = tstream =
 184.528 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT)))
 184.529 +    return NIL;
 184.530 +  status.flags = flags;		/* return status values */
 184.531 +  status.messages = stream->nmsgs;
 184.532 +  status.recent = stream->recent;
 184.533 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 184.534 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 184.535 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 184.536 +  status.uidnext = stream->uid_last + 1;
 184.537 +  status.uidvalidity = stream->uid_validity;
 184.538 +				/* calculate post-snarf results */
 184.539 +  if (!status.recent && stream->inbox &&
 184.540 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
 184.541 +    status.messages += systream->nmsgs;
 184.542 +    status.recent += systream->recent;
 184.543 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 184.544 +      for (i = 1; i <= systream->nmsgs; i++)
 184.545 +	if (!mail_elt (systream,i)->seen) status.unseen++;
 184.546 +				/* kludge but probably good enough */
 184.547 +    status.uidnext += systream->nmsgs;
 184.548 +  }
 184.549 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 184.550 +  if (tstream) mail_close (tstream);
 184.551 +  if (systream) mail_close (systream);
 184.552 +  return T;			/* success */
 184.553 +}
 184.554 +
 184.555 +/* MBX mail open
 184.556 + * Accepts: stream to open
 184.557 + * Returns: stream on success, NIL on failure
 184.558 + */
 184.559 +
 184.560 +MAILSTREAM *mbx_open (MAILSTREAM *stream)
 184.561 +{
 184.562 +  int fd,ld;
 184.563 +  short silent;
 184.564 +  char tmp[MAILTMPLEN];
 184.565 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 184.566 +				/* return prototype for OP_PROTOTYPE call */
 184.567 +  if (!stream) return user_flags (&mbxproto);
 184.568 +  if (stream->local) fatal ("mbx recycle stream");
 184.569 +				/* canonicalize the mailbox name */
 184.570 +  if (!mbx_file (tmp,stream->mailbox)) {
 184.571 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 184.572 +    MM_LOG (tmp,ERROR);
 184.573 +  }
 184.574 +  if (stream->rdonly ||
 184.575 +      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
 184.576 +    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
 184.577 +      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 184.578 +      MM_LOG (tmp,ERROR);
 184.579 +      return NIL;
 184.580 +    }
 184.581 +    else if (!stream->rdonly) {	/* got it, but readonly */
 184.582 +      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 184.583 +      stream->rdonly = T;
 184.584 +    }
 184.585 +  }
 184.586 +
 184.587 +  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
 184.588 +  LOCAL->fd = fd;		/* bind the file */
 184.589 +  LOCAL->ld = -1;		/* no flaglock */
 184.590 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 184.591 +  LOCAL->buflen = CHUNKSIZE - 1;
 184.592 +				/* note if an INBOX or not */
 184.593 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 184.594 +  fs_give ((void **) &stream->mailbox);
 184.595 +  stream->mailbox = cpystr (tmp);
 184.596 +				/* get parse/append permission */
 184.597 +  if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) {
 184.598 +    MM_LOG ("Unable to lock open mailbox",ERROR);
 184.599 +    return NIL;
 184.600 +  }
 184.601 +  (*bn) (BLOCK_FILELOCK,NIL);
 184.602 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 184.603 +  (*bn) (BLOCK_NONE,NIL);
 184.604 +  unlockfd (ld,tmp);		/* release shared parse permission */
 184.605 +  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
 184.606 +				/* time not set up yet */
 184.607 +  LOCAL->lastsnarf = LOCAL->filetime = 0;
 184.608 +  LOCAL->expok = LOCAL->flagcheck = NIL;
 184.609 +  stream->sequence++;		/* bump sequence number */
 184.610 +				/* parse mailbox */
 184.611 +  stream->nmsgs = stream->recent = 0;
 184.612 +  silent = stream->silent;	/* defer events */
 184.613 +  stream->silent = T;
 184.614 +  if (mbx_ping (stream) && !stream->nmsgs)
 184.615 +    MM_LOG ("Mailbox is empty",(long) NIL);
 184.616 +  stream->silent = silent;	/* now notify upper level */
 184.617 +  mail_exists (stream,stream->nmsgs);
 184.618 +  mail_recent (stream,stream->recent);
 184.619 +  if (!LOCAL) return NIL;	/* failure if stream died */
 184.620 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 184.621 +    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 184.622 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 184.623 +  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
 184.624 +    NIL : T;			/* can we create new user flags? */
 184.625 +  return stream;		/* return stream to caller */
 184.626 +}
 184.627 +
 184.628 +/* MBX mail close
 184.629 + * Accepts: MAIL stream
 184.630 + *	    close options
 184.631 + */
 184.632 +
 184.633 +void mbx_close (MAILSTREAM *stream,long options)
 184.634 +{
 184.635 +  if (stream && LOCAL) {	/* only if a file is open */
 184.636 +    int silent = stream->silent;
 184.637 +    stream->silent = T;		/* note this stream is dying */
 184.638 +				/* do an expunge if requested */
 184.639 +    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
 184.640 +    else {			/* otherwise do a checkpoint to purge */
 184.641 +      LOCAL->expok = T;		/*  possible expunged messages */
 184.642 +      mbx_ping (stream);
 184.643 +    }
 184.644 +    stream->silent = silent;	/* restore previous status */
 184.645 +    mbx_abort (stream);
 184.646 +  }
 184.647 +}
 184.648 +
 184.649 +
 184.650 +/* MBX mail abort stream
 184.651 + * Accepts: MAIL stream
 184.652 + */
 184.653 +
 184.654 +void mbx_abort (MAILSTREAM *stream)
 184.655 +{
 184.656 +  if (stream && LOCAL) {	/* only if a file is open */
 184.657 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 184.658 +    close (LOCAL->fd);		/* close the local file */
 184.659 +				/* free local text buffer */
 184.660 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 184.661 +				/* nuke the local data */
 184.662 +    fs_give ((void **) &stream->local);
 184.663 +    stream->dtb = NIL;		/* log out the DTB */
 184.664 +  }
 184.665 +}
 184.666 +
 184.667 +
 184.668 +/* MBX mail fetch flags
 184.669 + * Accepts: MAIL stream
 184.670 + *	    sequence
 184.671 + *	    option flags
 184.672 + * Sniffs at file to see if some other process changed the flags
 184.673 + */
 184.674 +
 184.675 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
 184.676 +{
 184.677 +  MESSAGECACHE *elt;
 184.678 +  unsigned long i;
 184.679 +  if (mbx_ping (stream) && 	/* ping mailbox, get new status for messages */
 184.680 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 184.681 +       mail_sequence (stream,sequence)))
 184.682 +    for (i = 1; i <= stream->nmsgs; i++) 
 184.683 +      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
 184.684 +	mbx_elt (stream,i,NIL);
 184.685 +}
 184.686 +
 184.687 +/* MBX mail fetch message header
 184.688 + * Accepts: MAIL stream
 184.689 + *	    message # to fetch
 184.690 + *	    pointer to returned header text length
 184.691 + *	    option flags
 184.692 + * Returns: message header in RFC822 format
 184.693 + */
 184.694 +
 184.695 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 184.696 +		  long flags)
 184.697 +{
 184.698 +  unsigned long i;
 184.699 +  char *s;
 184.700 +  *length = 0;			/* default to empty */
 184.701 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 184.702 +				/* get header position, possibly header */
 184.703 +  i = mbx_hdrpos (stream,msgno,length,&s);
 184.704 +  if (!s) {			/* mbx_hdrpos() returned header? */
 184.705 +    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
 184.706 +				/* is buffer big enough? */
 184.707 +    if (*length > LOCAL->buflen) {
 184.708 +      fs_give ((void **) &LOCAL->buf);
 184.709 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 184.710 +    }
 184.711 +				/* slurp the data */
 184.712 +    read (LOCAL->fd,s = LOCAL->buf,*length);
 184.713 +  }
 184.714 +  s[*length] = '\0';		/* tie off string */
 184.715 +  return s;
 184.716 +}
 184.717 +
 184.718 +/* MBX mail fetch message text (body only)
 184.719 + * Accepts: MAIL stream
 184.720 + *	    message # to fetch
 184.721 + *	    pointer to returned header text length
 184.722 + *	    option flags
 184.723 + * Returns: T on success, NIL on failure
 184.724 + */
 184.725 +
 184.726 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 184.727 +{
 184.728 +  FDDATA d;
 184.729 +  unsigned long i,j;
 184.730 +  MESSAGECACHE *elt;
 184.731 +				/* UID call "impossible" */
 184.732 +  if (flags & FT_UID) return NIL;
 184.733 +				/* get message status */
 184.734 +  elt = mbx_elt (stream,msgno,NIL);
 184.735 +				/* if message not seen */
 184.736 +  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
 184.737 +    elt->seen = T;		/* mark message as seen */
 184.738 +				/* recalculate status */
 184.739 +    mbx_update_status (stream,msgno,NIL);
 184.740 +    MM_FLAGS (stream,msgno);
 184.741 +				/* update flags */
 184.742 +    mbx_flag (stream,NIL,NIL,NIL);
 184.743 +  }
 184.744 +  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
 184.745 +				/* find header position */
 184.746 +  i = mbx_hdrpos (stream,msgno,&j,NIL);
 184.747 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 184.748 +  d.pos = i + j;
 184.749 +  d.chunk = LOCAL->buf;	/* initial buffer chunk */
 184.750 +  d.chunksize = CHUNKSIZE;
 184.751 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 184.752 +  return LONGT;			/* success */
 184.753 +}
 184.754 +
 184.755 +/* MBX mail modify flags
 184.756 + * Accepts: MAIL stream
 184.757 + *	    sequence
 184.758 + *	    flag(s)
 184.759 + *	    option flags
 184.760 + * Unlocks flag lock
 184.761 + */
 184.762 +
 184.763 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 184.764 +{
 184.765 +  time_t tp[2];
 184.766 +  struct stat sbuf;
 184.767 +  unsigned long oldpid = LOCAL->lastpid;
 184.768 +				/* make sure the update takes */
 184.769 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
 184.770 +    fsync (LOCAL->fd);
 184.771 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 184.772 +    tp[1] = LOCAL->filetime = sbuf.st_mtime;
 184.773 +				/* we are the last flag updater */
 184.774 +    LOCAL->lastpid = (unsigned long) getpid ();
 184.775 +				/* update header if needed */
 184.776 +    if (((LOCAL->ffuserflag < NUSERFLAGS) &&
 184.777 +	 stream->user_flags[LOCAL->ffuserflag]) || (oldpid != LOCAL->lastpid))
 184.778 +      mbx_update_header (stream);
 184.779 +    tp[0] = time (0);		/* make sure read comes after all that */
 184.780 +    utime (stream->mailbox,tp);
 184.781 +  }
 184.782 +  if (LOCAL->ld >= 0) {		/* unlock now */
 184.783 +    unlockfd (LOCAL->ld,LOCAL->lock);
 184.784 +    LOCAL->ld = -1;
 184.785 +  }
 184.786 +}
 184.787 +
 184.788 +
 184.789 +/* MBX mail per-message modify flags
 184.790 + * Accepts: MAIL stream
 184.791 + *	    message cache element
 184.792 + */
 184.793 +
 184.794 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 184.795 +{
 184.796 +  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
 184.797 +}
 184.798 +
 184.799 +/* MBX mail ping mailbox
 184.800 + * Accepts: MAIL stream
 184.801 + * Returns: T if stream still alive, NIL if not
 184.802 + */
 184.803 +
 184.804 +long mbx_ping (MAILSTREAM *stream)
 184.805 +{
 184.806 +  unsigned long i,pos;
 184.807 +  long ret = NIL;
 184.808 +  int ld;
 184.809 +  char lock[MAILTMPLEN];
 184.810 +  MESSAGECACHE *elt;
 184.811 +  struct stat sbuf;
 184.812 +  if (stream && LOCAL) {	/* only if stream already open */
 184.813 +    int snarf = stream->inbox && !stream->rdonly;
 184.814 +    ret = LONGT;		/* assume OK */
 184.815 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 184.816 +				/* allow expunge if permitted at ping */
 184.817 +    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
 184.818 +				/* if external modification */
 184.819 +    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
 184.820 +      LOCAL->flagcheck = T;	/* upgrade to flag checking */
 184.821 +				/* new mail or flagcheck handling needed? */
 184.822 +    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
 184.823 +	 !stream->nmsgs || snarf) &&
 184.824 +	((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
 184.825 +				/* reparse header if not flagchecking */
 184.826 +      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
 184.827 +				/* sweep mailbox for changed message status */
 184.828 +      else if (ret = mbx_parse (stream)) {
 184.829 +	unsigned long recent = 0;
 184.830 +	LOCAL->filetime = sbuf.st_mtime;
 184.831 +	for (i = 1; i <= stream->nmsgs; )
 184.832 +	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
 184.833 +	    if (elt->recent) ++recent;
 184.834 +	    ++i;
 184.835 +	  }
 184.836 +	mail_recent (stream,recent);
 184.837 +	LOCAL->flagcheck = NIL;	/* got all the updates */
 184.838 +      }
 184.839 +				/* always reparse header at least */
 184.840 +      if (ret && snarf) {	/* snarf new messages if still OK */
 184.841 +	mbx_snarf (stream);
 184.842 +				/* parse snarfed messages */
 184.843 +	ret = mbx_parse (stream);
 184.844 +      }
 184.845 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 184.846 +    }
 184.847 +    if (ret) {			/* must still be alive */
 184.848 +      if (!LOCAL->expunged)	/* look for holes if none known yet */
 184.849 +	for (i = 1, pos = HDRSIZE;
 184.850 +	     !LOCAL->expunged && (i <= stream->nmsgs);
 184.851 +	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
 184.852 +	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
 184.853 +	    LOCAL->expunged = T;/* found a hole */
 184.854 +				/* burp any holes */
 184.855 +      if (LOCAL->expunged && !stream->rdonly) {
 184.856 +	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
 184.857 +	if (i) {		/* any space reclaimed? */
 184.858 +	  LOCAL->expunged = NIL;/* no more pending expunge */
 184.859 +	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
 184.860 +	  MM_LOG (LOCAL->buf,(long) NIL);
 184.861 +	}
 184.862 +      }
 184.863 +      LOCAL->expok = NIL;	/* no more expok */
 184.864 +    }
 184.865 +  }
 184.866 +  return ret;			/* return result of the parse */
 184.867 +}
 184.868 +
 184.869 +/* MBX mail check mailbox (reparses status too)
 184.870 + * Accepts: MAIL stream
 184.871 + */
 184.872 +
 184.873 +void mbx_check (MAILSTREAM *stream)
 184.874 +{
 184.875 +  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
 184.876 +  if (mbx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 184.877 +}
 184.878 +
 184.879 +
 184.880 +/* MBX mail expunge mailbox
 184.881 + * Accepts: MAIL stream
 184.882 + *	    sequence to expunge if non-NIL
 184.883 + *	    expunge options
 184.884 + * Returns: T if success, NIL if failure
 184.885 + */
 184.886 +
 184.887 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
 184.888 +{
 184.889 +  long ret;
 184.890 +  unsigned long nexp,reclaimed;
 184.891 +  if (ret = sequence ? ((options & EX_UID) ?
 184.892 +			mail_uid_sequence (stream,sequence) :
 184.893 +			mail_sequence (stream,sequence)) : LONGT) {
 184.894 +    if (!mbx_ping (stream));	/* do nothing if stream dead */
 184.895 +    else if (stream->rdonly)	/* won't do on readonly files! */
 184.896 +      MM_LOG ("Expunge ignored on readonly mailbox",WARN);
 184.897 +				/* if expunged any messages */
 184.898 +    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
 184.899 +      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
 184.900 +      MM_LOG (LOCAL->buf,(long) NIL);
 184.901 +    }
 184.902 +    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
 184.903 +      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
 184.904 +      MM_LOG (LOCAL->buf,(long) NIL);
 184.905 +    }
 184.906 +    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 184.907 +  }
 184.908 +  return ret;
 184.909 +}
 184.910 +
 184.911 +/* MBX mail snarf messages from system inbox
 184.912 + * Accepts: MAIL stream, already locked
 184.913 + */
 184.914 +
 184.915 +void mbx_snarf (MAILSTREAM *stream)
 184.916 +{
 184.917 +  unsigned long i = 0;
 184.918 +  unsigned long j,r,hdrlen,txtlen;
 184.919 +  struct stat sbuf;
 184.920 +  char *hdr,*txt,tmp[MAILTMPLEN];
 184.921 +  MESSAGECACHE *elt;
 184.922 +  MAILSTREAM *sysibx = NIL;
 184.923 +				/* give up if can't get exclusive permission */
 184.924 +  if ((time (0) >= (LOCAL->lastsnarf +
 184.925 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
 184.926 +      strcmp (sysinbox (),stream->mailbox)) {
 184.927 +    MM_CRITICAL (stream);	/* go critical */
 184.928 +				/* sizes match and anything in sysinbox? */
 184.929 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 184.930 +	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
 184.931 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 184.932 +	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
 184.933 +				/* yes, go to end of file in our mailbox */
 184.934 +      lseek (LOCAL->fd,sbuf.st_size,L_SET);
 184.935 +				/* for each message in sysibx mailbox */
 184.936 +      while (r && (++i <= sysibx->nmsgs)) {
 184.937 +				/* snarf message from system INBOX */
 184.938 +	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
 184.939 +	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
 184.940 +				/* if have a message */
 184.941 +	if (j = hdrlen + txtlen) {
 184.942 +				/* build header line */
 184.943 +	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
 184.944 +	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
 184.945 +		   ",%lu;00000000%04x-00000000\015\012",j,(unsigned)
 184.946 +		   ((fSEEN * elt->seen) +
 184.947 +		    (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) +
 184.948 +		    (fANSWERED * elt->answered) + (fDRAFT * elt->draft)));
 184.949 +				/* copy message */
 184.950 +	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
 184.951 +	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
 184.952 +	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
 184.953 +	}
 184.954 +	fs_give ((void **) &hdr);
 184.955 +      }
 184.956 +
 184.957 +				/* make sure all the updates take */
 184.958 +      if (fsync (LOCAL->fd)) r = 0;
 184.959 +      if (r) {			/* delete all the messages we copied */
 184.960 +	if (r == 1) strcpy (tmp,"1");
 184.961 +	else sprintf (tmp,"1:%lu",r);
 184.962 +	mail_setflag (sysibx,tmp,"\\Deleted");
 184.963 +	mail_expunge (sysibx);	/* now expunge all those messages */
 184.964 +      }
 184.965 +      else {
 184.966 +	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
 184.967 +	MM_LOG (LOCAL->buf,WARN);
 184.968 +	ftruncate (LOCAL->fd,sbuf.st_size);
 184.969 +      }
 184.970 +      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
 184.971 +      LOCAL->filetime = sbuf.st_mtime;
 184.972 +    }
 184.973 +    if (sysibx) mail_close (sysibx);
 184.974 +    MM_NOCRITICAL (stream);	/* release critical */
 184.975 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 184.976 +  }
 184.977 +}
 184.978 +
 184.979 +/* MBX mail copy message(s)
 184.980 + * Accepts: MAIL stream
 184.981 + *	    sequence
 184.982 + *	    destination mailbox
 184.983 + *	    copy options
 184.984 + * Returns: T if success, NIL if failed
 184.985 + */
 184.986 +
 184.987 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 184.988 +{
 184.989 +  struct stat sbuf;
 184.990 +  time_t tp[2];
 184.991 +  MESSAGECACHE *elt;
 184.992 +  unsigned long i,j,k,m;
 184.993 +  long ret = LONGT;
 184.994 +  int fd,ld;
 184.995 +  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
 184.996 +  mailproxycopy_t pc =
 184.997 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 184.998 +  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 184.999 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
184.1000 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
184.1001 +  MAILSTREAM *dstream = NIL;
184.1002 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
184.1003 +	mail_sequence (stream,sequence))) return NIL;
184.1004 +				/* make sure valid mailbox */
184.1005 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
184.1006 +			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
184.1007 +    switch (errno) {
184.1008 +    case ENOENT:		/* no such file? */
184.1009 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
184.1010 +      return NIL;
184.1011 +    case EACCES:		/* file protected */
184.1012 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
184.1013 +      MM_LOG (LOCAL->buf,ERROR);
184.1014 +      return NIL;
184.1015 +    case EINVAL:
184.1016 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
184.1017 +      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
184.1018 +      MM_LOG (LOCAL->buf,ERROR);
184.1019 +      return NIL;
184.1020 +    default:
184.1021 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
184.1022 +      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
184.1023 +      MM_LOG (LOCAL->buf,ERROR);
184.1024 +      return NIL;
184.1025 +    }
184.1026 +  MM_CRITICAL (stream);		/* go critical */
184.1027 +  fstat (fd,&sbuf);		/* get current file size */
184.1028 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
184.1029 +
184.1030 +				/* for each requested message */
184.1031 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
184.1032 +    if ((elt = mail_elt (stream,i))->sequence) {
184.1033 +      lseek (LOCAL->fd,elt->private.special.offset +
184.1034 +	     elt->private.special.text.size,L_SET);
184.1035 +      mail_date(LOCAL->buf,elt);/* build target header */
184.1036 +				/* get target keyword mask */
184.1037 +      for (j = elt->user_flags, k = 0; j; )
184.1038 +	if (s = stream->user_flags[find_rightmost_bit (&j)])
184.1039 +	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
184.1040 +	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
184.1041 +      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
184.1042 +	       elt->rfc822_size,k,(unsigned)
184.1043 +	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
184.1044 +		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
184.1045 +		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
184.1046 +				/* write target header */
184.1047 +      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
184.1048 +	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
184.1049 +	  read (LOCAL->fd,LOCAL->buf,j);
184.1050 +	  ret = write (fd,LOCAL->buf,j) >= 0;
184.1051 +	}
184.1052 +	if (cu) {		/* need to pass back new UID? */
184.1053 +	  mail_append_set (source,mail_uid (stream,i));
184.1054 +	  mail_append_set (dest,dstream->uid_last);
184.1055 +	}
184.1056 +      }
184.1057 +    }
184.1058 +
184.1059 +				/* make sure all the updates take */
184.1060 +  if (!(ret && (ret = !fsync (fd)))) {
184.1061 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
184.1062 +    MM_LOG (LOCAL->buf,ERROR);
184.1063 +    ftruncate (fd,sbuf.st_size);
184.1064 +  }
184.1065 +  if (cu && ret) {		/* return sets if doing COPYUID */
184.1066 +    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
184.1067 +    lseek (fd,15,L_SET);	/* update UIDLAST */
184.1068 +    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
184.1069 +    write (fd,LOCAL->buf,8);
184.1070 +  }
184.1071 +  else {			/* flush any sets we may have built */
184.1072 +    mail_free_searchset (&source);
184.1073 +    mail_free_searchset (&dest);
184.1074 +  }
184.1075 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
184.1076 +				/* else preserve \Marked status */
184.1077 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
184.1078 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
184.1079 +  utime (file,tp);		/* set the times */
184.1080 +  close (fd);			/* close the file */
184.1081 +  MM_NOCRITICAL (stream);	/* release critical */
184.1082 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
184.1083 +				/* delete all requested messages */
184.1084 +  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
184.1085 +    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
184.1086 +				/* mark message deleted */
184.1087 +      mbx_elt (stream,i,NIL)->deleted = T;
184.1088 +				/* recalculate status */
184.1089 +      mbx_update_status (stream,i,NIL);
184.1090 +    }
184.1091 +				/* update flags */
184.1092 +    mbx_flag (stream,NIL,NIL,NIL);
184.1093 +  }
184.1094 +  if (dstream != stream) mail_close (dstream);
184.1095 +  return ret;
184.1096 +}
184.1097 +
184.1098 +/* MBX mail append message from stringstruct
184.1099 + * Accepts: MAIL stream
184.1100 + *	    destination mailbox
184.1101 + *	    append callback
184.1102 + *	    data for callback
184.1103 + * Returns: T if append successful, else NIL
184.1104 + */
184.1105 +
184.1106 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
184.1107 +{
184.1108 +  struct stat sbuf;
184.1109 +  int fd,ld;
184.1110 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
184.1111 +  time_t tp[2];
184.1112 +  FILE *df;
184.1113 +  MESSAGECACHE elt;
184.1114 +  long f;
184.1115 +  unsigned long i,uf;
184.1116 +  STRING *message;
184.1117 +  long ret = NIL;
184.1118 +  MAILSTREAM *dstream = NIL;
184.1119 +  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
184.1120 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
184.1121 +				/* make sure valid mailbox */
184.1122 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
184.1123 +			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
184.1124 +    switch (errno) {
184.1125 +    case ENOENT:		/* no such file? */
184.1126 +      if (compare_cstring (mailbox,"INBOX")) {
184.1127 +	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
184.1128 +	return NIL;
184.1129 +      }
184.1130 +				/* can create INBOX here */
184.1131 +      mbx_create (dstream = stream ? stream : user_flags (&mbxproto),"INBOX");
184.1132 +      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
184.1133 +			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) >= 0)
184.1134 +	break;
184.1135 +    case EACCES:		/* file protected */
184.1136 +      sprintf (tmp,"Can't access destination: %.80s",mailbox);
184.1137 +      MM_LOG (tmp,ERROR);
184.1138 +      return NIL;
184.1139 +    case EINVAL:
184.1140 +      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
184.1141 +      MM_LOG (tmp,ERROR);
184.1142 +      return NIL;
184.1143 +    default:
184.1144 +      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
184.1145 +      MM_LOG (tmp,ERROR);
184.1146 +      return NIL;
184.1147 +    }
184.1148 +
184.1149 +				/* get first message */
184.1150 +  if (!MM_APPEND (af) (dstream,data,&flags,&date,&message)) close (fd);
184.1151 +  else if (!(df = fdopen (fd,"r+b"))) {
184.1152 +    MM_LOG ("Unable to reopen append mailbox",ERROR);
184.1153 +    close (fd);
184.1154 +  }
184.1155 +  else {
184.1156 +    MM_CRITICAL (dstream);	/* go critical */
184.1157 +    fstat (fd,&sbuf);		/* get current file size */
184.1158 +    fseek (df,sbuf.st_size,SEEK_SET);
184.1159 +    errno = 0;
184.1160 +    for (ret = LONGT; ret && message; ) {
184.1161 +      if (!SIZE (message)) {	/* guard against zero-length */
184.1162 +	MM_LOG ("Append of zero-length message",ERROR);
184.1163 +	ret = NIL;
184.1164 +	break;
184.1165 +      }
184.1166 +      f = mail_parse_flags (dstream,flags,&uf);
184.1167 +      if (date) {		/* parse date if given */
184.1168 +	if (!mail_parse_date (&elt,date)) {
184.1169 +	  sprintf (tmp,"Bad date in append: %.80s",date);
184.1170 +	  MM_LOG (tmp,ERROR);
184.1171 +	  ret = NIL;		/* mark failure */
184.1172 +	  break;
184.1173 +	}
184.1174 +	mail_date (tmp,&elt);	/* write preseved date */
184.1175 +      }
184.1176 +      else internal_date (tmp);	/* get current date in IMAP format */
184.1177 +				/* write header */
184.1178 +      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
184.1179 +		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
184.1180 +	ret = NIL;
184.1181 +      else {			/* write message */
184.1182 +	size_t j;
184.1183 +	if (!message->cursize) SETPOS (message,GETPOS (message));
184.1184 +	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
184.1185 +	  i -= j;
184.1186 +	  SETPOS (message,GETPOS (message) + j);
184.1187 +	}
184.1188 +				/* get next message */
184.1189 +	if (i || !MM_APPEND (af) (dstream,data,&flags,&date,&message))
184.1190 +	  ret = NIL;
184.1191 +	else if (au) mail_append_set (dst,dstream->uid_last);
184.1192 +      }
184.1193 +    }
184.1194 +
184.1195 +				/* if error... */
184.1196 +    if (!ret || (fflush (df) == EOF)) {
184.1197 +				/* revert file */
184.1198 +      ftruncate (fd,sbuf.st_size);
184.1199 +      close (fd);		/* make sure fclose() doesn't corrupt us */
184.1200 +      if (errno) {
184.1201 +	sprintf (tmp,"Message append failed: %s",strerror (errno));
184.1202 +	MM_LOG (tmp,ERROR);
184.1203 +      }
184.1204 +      ret = NIL;
184.1205 +    }
184.1206 +    if (au && ret) {		/* return sets if doing APPENDUID */
184.1207 +      (*au) (mailbox,dstream->uid_validity,dst);
184.1208 +      fseek (df,15,SEEK_SET);	/* update UIDLAST */
184.1209 +      fprintf (df,"%08lx",dstream->uid_last);
184.1210 +    }
184.1211 +    else mail_free_searchset (&dst);
184.1212 +				/* set atime to now-1 if successful copy */
184.1213 +    if (ret) tp[0] = time (0) - 1;
184.1214 +				/* else preserve \Marked status */
184.1215 +    else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
184.1216 +    tp[1] = sbuf.st_mtime;	/* preserve mtime */
184.1217 +    utime (file,tp);		/* set the times */
184.1218 +    fclose (df);		/* close the file */
184.1219 +    MM_NOCRITICAL (dstream);	/* release critical */
184.1220 +  }
184.1221 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
184.1222 +  if (dstream != stream) mail_close (dstream);
184.1223 +  return ret;
184.1224 +}
184.1225 +
184.1226 +/* Internal routines */
184.1227 +
184.1228 +
184.1229 +/* MBX mail generate file string
184.1230 + * Accepts: temporary buffer to write into
184.1231 + *	    mailbox name string
184.1232 + * Returns: local file string or NIL if failure
184.1233 + */
184.1234 +
184.1235 +char *mbx_file (char *dst,char *name)
184.1236 +{
184.1237 +  char *s = mailboxfile (dst,name);
184.1238 +  return (s && !*s) ? mailboxfile (dst,"~/INBOX") : s;
184.1239 +}
184.1240 +
184.1241 +/* MBX mail parse mailbox
184.1242 + * Accepts: MAIL stream
184.1243 + * Returns: T if parse OK
184.1244 + *	    NIL if failure, stream aborted
184.1245 + */
184.1246 +
184.1247 +long mbx_parse (MAILSTREAM *stream)
184.1248 +{
184.1249 +  struct stat sbuf;
184.1250 +  MESSAGECACHE *elt = NIL;
184.1251 +  unsigned char c,*s,*t,*x;
184.1252 +  char tmp[MAILTMPLEN];
184.1253 +  unsigned long i,j,k,m;
184.1254 +  off_t curpos = LOCAL->filesize;
184.1255 +  unsigned long nmsgs = stream->nmsgs;
184.1256 +  unsigned long recent = stream->recent;
184.1257 +  unsigned long lastuid = 0;
184.1258 +  short dirty = NIL;
184.1259 +  short added = NIL;
184.1260 +  short silent = stream->silent;
184.1261 +  short uidwarn = T;
184.1262 +  fstat (LOCAL->fd,&sbuf);	/* get status */
184.1263 +  if (sbuf.st_size < curpos) {	/* sanity check */
184.1264 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
184.1265 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
184.1266 +    MM_LOG (tmp,ERROR);
184.1267 +    mbx_abort (stream);
184.1268 +    return NIL;
184.1269 +  }
184.1270 +  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
184.1271 +				/* read internal header */
184.1272 +  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
184.1273 +  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
184.1274 +  c = LOCAL->buf[15];		/* save first character of last UID */
184.1275 +  LOCAL->buf[15] = '\0';
184.1276 +				/* parse UID validity */
184.1277 +  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
184.1278 +  LOCAL->buf[15] = c;		/* restore first character of last UID */
184.1279 +				/* parse last UID */
184.1280 +  i = strtoul (LOCAL->buf + 15,NIL,16);
184.1281 +  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
184.1282 +				/* parse user flags */
184.1283 +  for (i = 0, s = LOCAL->buf + 25;
184.1284 +       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
184.1285 +       i++, s = t + 2) {
184.1286 +    *t = '\0';			/* tie off flag */
184.1287 +    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
184.1288 +      stream->user_flags[i] = cpystr (s);
184.1289 +  }
184.1290 +  LOCAL->ffuserflag = (int) i;	/* first free user flag */
184.1291 +
184.1292 +				/* get current last flag updater PID */
184.1293 +  i = (isxdigit (LOCAL->buf[HDRSIZE-10]) && isxdigit (LOCAL->buf[HDRSIZE-9]) &&
184.1294 +       isxdigit (LOCAL->buf[HDRSIZE-8]) && isxdigit (LOCAL->buf[HDRSIZE-7]) &&
184.1295 +       isxdigit (LOCAL->buf[HDRSIZE-6]) && isxdigit (LOCAL->buf[HDRSIZE-5]) &&
184.1296 +       isxdigit (LOCAL->buf[HDRSIZE-4]) && isxdigit (LOCAL->buf[HDRSIZE-3]) &&
184.1297 +       (LOCAL->buf[HDRSIZE-2] == '\015') && (LOCAL->buf[HDRSIZE-1] == '\012'))?
184.1298 +    strtoul (LOCAL->buf + HDRSIZE - 8,NIL,16) : 0;
184.1299 +				/* set flagcheck if lastpid changed */
184.1300 +  if (LOCAL->lastpid && (LOCAL->lastpid != i)) LOCAL->flagcheck = T;
184.1301 +  LOCAL->lastpid = i;		/* set as last PID */
184.1302 +  stream->silent = T;		/* don't pass up exists events yet */
184.1303 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
184.1304 +				/* get to that position in the file */
184.1305 +    lseek (LOCAL->fd,curpos,L_SET);
184.1306 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
184.1307 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
184.1308 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
184.1309 +	       i ? strerror (errno) : "no data read");
184.1310 +      MM_LOG (tmp,ERROR);
184.1311 +      mbx_abort (stream);
184.1312 +      return NIL;
184.1313 +    }
184.1314 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
184.1315 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
184.1316 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
184.1317 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
184.1318 +      MM_LOG (tmp,ERROR);
184.1319 +      mbx_abort (stream);
184.1320 +      return NIL;
184.1321 +    }
184.1322 +    *s = '\0';			/* tie off header line */
184.1323 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
184.1324 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
184.1325 +      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
184.1326 +	       (unsigned long) curpos,(char *) LOCAL->buf);
184.1327 +      MM_LOG (tmp,ERROR);
184.1328 +      mbx_abort (stream);
184.1329 +      return NIL;
184.1330 +    }
184.1331 +    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
184.1332 +	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
184.1333 +	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
184.1334 +	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
184.1335 +      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
184.1336 +	       (unsigned long) curpos,(char *) LOCAL->buf);
184.1337 +      MM_LOG (tmp,ERROR);
184.1338 +      mbx_abort (stream);
184.1339 +      return NIL;
184.1340 +    }
184.1341 +    if ((t[13] != '-') || t[22] ||
184.1342 +	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
184.1343 +	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
184.1344 +	  isxdigit (t[20]) && isxdigit (t[21]))) {
184.1345 +      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
184.1346 +	       (unsigned long) curpos,(char *) LOCAL->buf);
184.1347 +      MM_LOG (tmp,ERROR);
184.1348 +      mbx_abort (stream);
184.1349 +      return NIL;
184.1350 +    }
184.1351 +
184.1352 +    *s++ = '\0'; *t++ = '\0';	/* break up fields */
184.1353 +				/* get message size */
184.1354 +    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
184.1355 +      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
184.1356 +	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
184.1357 +	       (char *) t);
184.1358 +      MM_LOG (tmp,ERROR);
184.1359 +      mbx_abort (stream);
184.1360 +      return NIL;
184.1361 +    }
184.1362 +				/* make sure didn't run off end of file */
184.1363 +    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
184.1364 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
184.1365 +	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
184.1366 +	       (unsigned long) sbuf.st_size);
184.1367 +      MM_LOG (tmp,ERROR);
184.1368 +      mbx_abort (stream);
184.1369 +      return NIL;
184.1370 +    }
184.1371 +				/* parse UID */
184.1372 +    if ((m = strtoul (t+13,NIL,16)) &&
184.1373 +	((m <= lastuid) || (m > stream->uid_last))) {
184.1374 +      if (uidwarn) {
184.1375 +	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
184.1376 +		 m,nmsgs+1);
184.1377 +	MM_LOG (tmp,WARN);
184.1378 +	uidwarn = NIL;
184.1379 +				/* restart UID validity */
184.1380 +	stream->uid_validity = time (0);
184.1381 +      }
184.1382 +      m = 0;			/* lose this UID */
184.1383 +      dirty = T;		/* mark dirty, set new lastuid */
184.1384 +      stream->uid_last = lastuid;
184.1385 +    }
184.1386 +
184.1387 +    t[12] = '\0';		/* parse system flags */
184.1388 +    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
184.1389 +      if (m) lastuid = m;	/* expunge message, update last UID seen */
184.1390 +      else {			/* no UID assigned? */
184.1391 +	lastuid = ++stream->uid_last;
184.1392 +	dirty = T;
184.1393 +      }
184.1394 +    }
184.1395 +    else {			/* not expunged, swell the cache */
184.1396 +      added = T;		/* note that a new message was added */
184.1397 +      mail_exists (stream,++nmsgs);
184.1398 +				/* instantiate an elt for this message */
184.1399 +      (elt = mail_elt (stream,nmsgs))->valid = T;
184.1400 +				/* parse the date */
184.1401 +      if (!mail_parse_date (elt,LOCAL->buf)) {
184.1402 +	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
184.1403 +		 (unsigned long) curpos,(char *) LOCAL->buf);
184.1404 +	MM_LOG (tmp,ERROR);
184.1405 +	mbx_abort (stream);
184.1406 +	return NIL;
184.1407 +      }
184.1408 +				/* note file offset of header */
184.1409 +      elt->private.special.offset = curpos;
184.1410 +				/* and internal header size */
184.1411 +      elt->private.special.text.size = i;
184.1412 +				/* header size not known yet */
184.1413 +      elt->private.msg.header.text.size = 0;
184.1414 +      elt->rfc822_size = j;	/* note message size */
184.1415 +				/* calculate system flags */
184.1416 +      if (k & fSEEN) elt->seen = T;
184.1417 +      if (k & fDELETED) elt->deleted = T;
184.1418 +      if (k & fFLAGGED) elt->flagged = T;
184.1419 +      if (k & fANSWERED) elt->answered = T;
184.1420 +      if (k & fDRAFT) elt->draft = T;
184.1421 +      t[8] = '\0';		/* get user flags value */
184.1422 +      elt->user_flags = strtoul (t,NIL,16);
184.1423 +				/* UID already assigned? */
184.1424 +      if (!(elt->private.uid = m) || !(k & fOLD)) {
184.1425 +	elt->recent = T;	/* no, mark as recent */
184.1426 +	++recent;		/* count up a new recent message */
184.1427 +	dirty = T;		/* and must rewrite header */
184.1428 +				/* assign new UID */
184.1429 +	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
184.1430 +	mbx_update_status (stream,elt->msgno,NIL);
184.1431 +      }
184.1432 +				/* update last parsed UID */
184.1433 +      lastuid = elt->private.uid;
184.1434 +    }
184.1435 +    curpos += i + j;		/* update position */
184.1436 +  }
184.1437 +
184.1438 +  if (dirty && !stream->rdonly){/* update header */
184.1439 +    mbx_update_header (stream);
184.1440 +    fsync (LOCAL->fd);		/* make sure all the UID updates take */
184.1441 +  }
184.1442 +				/* update parsed file size and time */
184.1443 +  LOCAL->filesize = sbuf.st_size;
184.1444 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
184.1445 +  LOCAL->filetime = sbuf.st_mtime;
184.1446 +  if (added && !stream->rdonly){/* make sure atime updated */
184.1447 +    time_t tp[2];
184.1448 +    tp[0] = time (0);
184.1449 +    tp[1] = LOCAL->filetime;
184.1450 +    utime (stream->mailbox,tp);
184.1451 +  }
184.1452 +  stream->silent = silent;	/* can pass up events now */
184.1453 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
184.1454 +  mail_recent (stream,recent);	/* and of change in recent messages */
184.1455 +  return LONGT;			/* return the winnage */
184.1456 +}
184.1457 +
184.1458 +/* MBX get cache element with status updating from file
184.1459 + * Accepts: MAIL stream
184.1460 + *	    message number
184.1461 + *	    expunge OK flag
184.1462 + * Returns: cache element
184.1463 + */
184.1464 +
184.1465 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
184.1466 +{
184.1467 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
184.1468 +  struct {			/* old flags */
184.1469 +    unsigned int seen : 1;
184.1470 +    unsigned int deleted : 1;
184.1471 +    unsigned int flagged : 1;
184.1472 +    unsigned int answered : 1;
184.1473 +    unsigned int draft : 1;
184.1474 +    unsigned long user_flags;
184.1475 +  } old;
184.1476 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
184.1477 +  old.answered = elt->answered; old.draft = elt->draft;
184.1478 +  old.user_flags = elt->user_flags;
184.1479 +				/* get new flags */
184.1480 +  if (mbx_read_flags (stream,elt) && expok) {
184.1481 +    mail_expunged (stream,elt->msgno);
184.1482 +    return NIL;			/* return this message was expunged */
184.1483 +  }
184.1484 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
184.1485 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
184.1486 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
184.1487 +    MM_FLAGS (stream,msgno);	/* let top level know */
184.1488 +  return elt;
184.1489 +}
184.1490 +
184.1491 +/* MBX read flags from file
184.1492 + * Accepts: MAIL stream
184.1493 + *	    cache element
184.1494 + * Returns: non-NIL if message expunged
184.1495 + */
184.1496 +
184.1497 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
184.1498 +{
184.1499 +  unsigned long i;
184.1500 +  struct stat sbuf;
184.1501 +  fstat (LOCAL->fd,&sbuf);	/* get status */
184.1502 +				/* make sure file size is good */
184.1503 +  if (sbuf.st_size < LOCAL->filesize) {
184.1504 +    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
184.1505 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
184.1506 +    fatal (LOCAL->buf);
184.1507 +  }
184.1508 +				/* set the seek pointer */
184.1509 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
184.1510 +	 elt->private.special.text.size - 24,L_SET);
184.1511 +				/* read the new flags */
184.1512 +  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
184.1513 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
184.1514 +    fatal (LOCAL->buf);
184.1515 +  }
184.1516 +  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
184.1517 +    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
184.1518 +    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
184.1519 +	     elt->msgno,elt->private.special.offset,
184.1520 +	     elt->private.special.text.size,(char *) LOCAL->buf);
184.1521 +    fatal (LOCAL->buf+50);
184.1522 +  }
184.1523 +  LOCAL->buf[13] = '\0';	/* tie off buffer */
184.1524 +				/* calculate system flags */
184.1525 +  i = strtoul (LOCAL->buf+9,NIL,16);
184.1526 +  elt->seen = i & fSEEN ? T : NIL;
184.1527 +  elt->deleted = i & fDELETED ? T : NIL;
184.1528 +  elt->flagged = i & fFLAGGED ? T : NIL;
184.1529 +  elt->answered = i & fANSWERED ? T : NIL;
184.1530 +  elt->draft = i & fDRAFT ? T : NIL;
184.1531 +  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
184.1532 +  LOCAL->buf[9] = '\0';		/* tie off flags */
184.1533 +				/* get user flags value */
184.1534 +  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
184.1535 +  elt->valid = T;		/* have valid flags now */
184.1536 +  return i & fEXPUNGED;
184.1537 +}
184.1538 +
184.1539 +/* MBX update header
184.1540 + * Accepts: MAIL stream
184.1541 + */
184.1542 +
184.1543 +#ifndef CYGKLUDGEOFFSET
184.1544 +#define CYGKLUDGEOFFSET 0
184.1545 +#endif
184.1546 +
184.1547 +void mbx_update_header (MAILSTREAM *stream)
184.1548 +{
184.1549 +  int i;
184.1550 +  char *s = LOCAL->buf;
184.1551 +  memset (s,'\0',HDRSIZE);	/* initialize header */
184.1552 +  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
184.1553 +	   stream->uid_validity,stream->uid_last);
184.1554 +  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
184.1555 +    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
184.1556 +  LOCAL->ffuserflag = i;	/* first free user flag */
184.1557 +				/* can we create more user flags? */
184.1558 +  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
184.1559 +				/* write reserved lines */
184.1560 +  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
184.1561 +  sprintf (LOCAL->buf + HDRSIZE - 10,"%08lx\015\012",LOCAL->lastpid);
184.1562 +  while (T) {			/* rewind file */
184.1563 +    lseek (LOCAL->fd,CYGKLUDGEOFFSET,L_SET);
184.1564 +				/* write new header */
184.1565 +    if (write (LOCAL->fd,LOCAL->buf + CYGKLUDGEOFFSET,
184.1566 +	       HDRSIZE - CYGKLUDGEOFFSET) > 0) break;
184.1567 +    MM_NOTIFY (stream,strerror (errno),WARN);
184.1568 +    MM_DISKERROR (stream,errno,T);
184.1569 +  }
184.1570 +}
184.1571 +
184.1572 +/* MBX update status string
184.1573 + * Accepts: MAIL stream
184.1574 + *	    message number
184.1575 + *	    flags
184.1576 + */
184.1577 +
184.1578 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
184.1579 +{
184.1580 +  struct stat sbuf;
184.1581 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
184.1582 +				/* readonly */
184.1583 +  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
184.1584 +  else {			/* readwrite */
184.1585 +    fstat (LOCAL->fd,&sbuf);	/* get status */
184.1586 +				/* make sure file size is good */
184.1587 +    if (sbuf.st_size < LOCAL->filesize) {
184.1588 +      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
184.1589 +	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
184.1590 +      fatal (LOCAL->buf);
184.1591 +    }
184.1592 +				/* set the seek pointer */
184.1593 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
184.1594 +	   elt->private.special.text.size - 24,L_SET);
184.1595 +				/* read the new flags */
184.1596 +    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
184.1597 +      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
184.1598 +      fatal (LOCAL->buf);
184.1599 +    }
184.1600 +    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
184.1601 +      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
184.1602 +      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
184.1603 +	       elt->msgno,elt->private.special.offset,
184.1604 +	       elt->private.special.text.size,(char *) LOCAL->buf);
184.1605 +      fatal (LOCAL->buf+50);
184.1606 +    }
184.1607 +				/* print new flag string */
184.1608 +    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
184.1609 +	     (((elt->deleted && flags) ?
184.1610 +	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
184.1611 +	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
184.1612 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
184.1613 +	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
184.1614 +    while (T) {			/* get to that place in the file */
184.1615 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
184.1616 +	     elt->private.special.text.size - 23,L_SET);
184.1617 +				/* write new flags and UID */
184.1618 +      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
184.1619 +      MM_NOTIFY (stream,strerror (errno),WARN);
184.1620 +      MM_DISKERROR (stream,errno,T);
184.1621 +    }
184.1622 +  }
184.1623 +}
184.1624 +
184.1625 +/* MBX locate header for a message
184.1626 + * Accepts: MAIL stream
184.1627 + *	    message number
184.1628 + *	    pointer to returned header size
184.1629 + *	    pointer to possible returned header
184.1630 + * Returns: position of header in file
184.1631 + */
184.1632 +
184.1633 +#define HDRBUFLEN 16384		/* good enough for most headers */
184.1634 +#define SLOP 4			/* CR LF CR LF */
184.1635 +
184.1636 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
184.1637 +			  unsigned long *size,char **hdr)
184.1638 +{
184.1639 +  unsigned long siz,done;
184.1640 +  long i;
184.1641 +  unsigned char *s,*t,*te;
184.1642 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
184.1643 +  unsigned long ret = elt->private.special.offset +
184.1644 +    elt->private.special.text.size;
184.1645 +  if (hdr) *hdr = NIL;		/* assume no header returned */
184.1646 +				/* is header size known? */ 
184.1647 +  if (*size = elt->private.msg.header.text.size) return ret;
184.1648 +				/* paranoia check */
184.1649 +  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
184.1650 +    fatal ("LOCAL->buf smaller than HDRBUFLEN");
184.1651 +  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
184.1652 +				/* read HDRBUFLEN chunks with 4 byte slop */
184.1653 +  for (done = siz = 0, s = LOCAL->buf;
184.1654 +       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
184.1655 +       (read (LOCAL->fd,s,i) == i);
184.1656 +       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
184.1657 +    te = (t = s + i) - 12;	/* calculate end of fast scan */
184.1658 +				/* fast scan for CR */
184.1659 +    for (s = LOCAL->buf; s < te;)
184.1660 +      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
184.1661 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
184.1662 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
184.1663 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
184.1664 +	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
184.1665 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
184.1666 +	if (hdr) *hdr = LOCAL->buf;
184.1667 +	return ret;
184.1668 +      }
184.1669 +    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
184.1670 +      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
184.1671 +	  (*++s == '\012')) {
184.1672 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
184.1673 +	if (hdr) *hdr = LOCAL->buf;
184.1674 +	return ret;
184.1675 +      }
184.1676 +    if (i <= SLOP) break;	/* end of data */
184.1677 +				/* slide over last 4 bytes */
184.1678 +    memmove (LOCAL->buf,t - SLOP,SLOP);
184.1679 +    hdr = NIL;			/* can't return header this way */
184.1680 +  }
184.1681 +				/* not found: header consumes entire message */
184.1682 +  elt->private.msg.header.text.size = *size = elt->rfc822_size;
184.1683 +  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
184.1684 +  return ret;
184.1685 +}
184.1686 +
184.1687 +/* MBX mail rewrite mailbox
184.1688 + * Accepts: MAIL stream
184.1689 + *	    pointer to return reclaimed size
184.1690 + *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
184.1691 + * Returns: number of expunged messages
184.1692 + */
184.1693 +
184.1694 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
184.1695 +			   long flags)
184.1696 +{
184.1697 +  time_t tp[2];
184.1698 +  struct stat sbuf;
184.1699 +  off_t pos,ppos;
184.1700 +  int ld;
184.1701 +  unsigned long i,j,k,m,delta;
184.1702 +  unsigned long n = *reclaimed = 0;
184.1703 +  unsigned long recent = 0;
184.1704 +  char lock[MAILTMPLEN];
184.1705 +  MESSAGECACHE *elt;
184.1706 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
184.1707 +  /* The cretins who designed flock() created a window of vulnerability in
184.1708 +   * upgrading locks from shared to exclusive or downgrading from exclusive
184.1709 +   * to shared.  Rather than maintain the lock at shared status at a minimum,
184.1710 +   * flock() actually *releases* the former lock.  Obviously they never talked
184.1711 +   * to any database guys.  Fortunately, we have the parse/append permission
184.1712 +   * lock.  If we require this lock before going exclusive on the mailbox,
184.1713 +   * another process can not sneak in and steal the exclusive mailbox lock on
184.1714 +   * us, because it will block on trying to get parse/append permission first.
184.1715 +   */
184.1716 +				/* get parse/append permission */
184.1717 +  if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) {
184.1718 +    MM_LOG ("Unable to lock mailbox for rewrite",ERROR);
184.1719 +    return 0;
184.1720 +  }
184.1721 +  fstat (LOCAL->fd,&sbuf);	/* get current write time */
184.1722 +  if (LOCAL->filetime && !LOCAL->flagcheck &&
184.1723 +      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
184.1724 +  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
184.1725 +    unlockfd (ld,lock);		/* failed?? */
184.1726 +    return 0;
184.1727 +  }
184.1728 +  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
184.1729 +    LOCAL->filetime = sbuf.st_mtime;
184.1730 +    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
184.1731 +    LOCAL->flagcheck = NIL;
184.1732 +  }
184.1733 +
184.1734 +				/* get exclusive access */
184.1735 +  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
184.1736 +    MM_CRITICAL (stream);	/* go critical */
184.1737 +    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
184.1738 +				/* note if message not at predicted location */
184.1739 +      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
184.1740 +	ppos = elt->private.special.offset;
184.1741 +	*reclaimed += m;	/* note reclaimed message space */
184.1742 +	delta += m;		/* and as expunge delta  */
184.1743 +      }
184.1744 +				/* number of bytes to smash or preserve */
184.1745 +      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
184.1746 +				/* if need to expunge this message*/
184.1747 +      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
184.1748 +	delta += k;		/* number of bytes to delete */
184.1749 +	mail_expunged(stream,i);/* notify upper levels */
184.1750 +	n++;			/* count up one more expunged message */
184.1751 +      }
184.1752 +      else {			/* preserved message */
184.1753 +	i++;			/* count this message */
184.1754 +	if (elt->recent) ++recent;
184.1755 +	if (delta) {		/* moved, note first byte to preserve */
184.1756 +	  j = elt->private.special.offset;
184.1757 +	  do {			/* read from source position */
184.1758 +	    m = min (k,LOCAL->buflen);
184.1759 +	    lseek (LOCAL->fd,j,L_SET);
184.1760 +	    read (LOCAL->fd,LOCAL->buf,m);
184.1761 +	    pos = j - delta;	/* write to destination position */
184.1762 +	    while (T) {
184.1763 +	      lseek (LOCAL->fd,pos,L_SET);
184.1764 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
184.1765 +	      MM_NOTIFY (stream,strerror (errno),WARN);
184.1766 +	      MM_DISKERROR (stream,errno,T);
184.1767 +	    }
184.1768 +	    pos += m;		/* new position */
184.1769 +	    j += m;		/* next chunk, perhaps */
184.1770 +	  } while (k -= m);	/* until done */
184.1771 +				/* note the new address of this text */
184.1772 +	  elt->private.special.offset -= delta;
184.1773 +	}
184.1774 +				/* preserved but no deleted messages yet */
184.1775 +	else pos = elt->private.special.offset + k;
184.1776 +      }
184.1777 +    }
184.1778 +				/* deltaed file size match position? */
184.1779 +    if (m = (LOCAL->filesize -= delta) - pos) {
184.1780 +      *reclaimed += m;		/* probably an fEXPUNGED msg */
184.1781 +      LOCAL->filesize = pos;	/* set correct size */
184.1782 +    }
184.1783 +				/* truncate file after last message */
184.1784 +    ftruncate (LOCAL->fd,LOCAL->filesize);
184.1785 +    fsync (LOCAL->fd);		/* force disk update */
184.1786 +    MM_NOCRITICAL (stream);	/* release critical */
184.1787 +    (*bn) (BLOCK_FILELOCK,NIL);
184.1788 +    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
184.1789 +    (*bn) (BLOCK_NONE,NIL);
184.1790 +  }
184.1791 +
184.1792 +  else {			/* can't get exclusive */
184.1793 +    (*bn) (BLOCK_FILELOCK,NIL);
184.1794 +    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
184.1795 +    (*bn) (BLOCK_NONE,NIL);
184.1796 +				/* do hide-expunge when shared */
184.1797 +    if (flags) for (i = 1; i <= stream->nmsgs; ) {
184.1798 +      if (elt = mbx_elt (stream,i,T)) {
184.1799 +				/* make the message invisible */
184.1800 +	if (elt->deleted && ((flags > 0) || elt->sequence)) {
184.1801 +	  mbx_update_status (stream,elt->msgno,LONGT);
184.1802 +				/* notify upper levels */
184.1803 +	  mail_expunged (stream,i);
184.1804 +	  n++;			/* count up one more expunged message */
184.1805 +	}
184.1806 +	else {
184.1807 +	  i++;			/* preserved message */
184.1808 +	  if (elt->recent) ++recent;
184.1809 +	}
184.1810 +      }
184.1811 +      else n++;			/* count up one more expunged message */
184.1812 +    }
184.1813 +    fsync (LOCAL->fd);		/* force disk update */
184.1814 +  }
184.1815 +  fstat (LOCAL->fd,&sbuf);	/* get new write time */
184.1816 +  tp[1] = LOCAL->filetime = sbuf.st_mtime;
184.1817 +  tp[0] = time (0);		/* reset atime to now */
184.1818 +  utime (stream->mailbox,tp);
184.1819 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
184.1820 +				/* notify upper level of new mailbox size */
184.1821 +  mail_exists (stream,stream->nmsgs);
184.1822 +  mail_recent (stream,recent);
184.1823 +  return n;			/* return number of expunged messages */
184.1824 +}
184.1825 +
184.1826 +/* MBX mail lock for flag updating
184.1827 + * Accepts: stream
184.1828 + * Returns: T if successful, NIL if failure
184.1829 + */
184.1830 +
184.1831 +long mbx_flaglock (MAILSTREAM *stream)
184.1832 +{
184.1833 +  struct stat sbuf;
184.1834 +  unsigned long i;
184.1835 +  int ld;
184.1836 +  char lock[MAILTMPLEN];
184.1837 +				/* no-op if readonly or already locked */
184.1838 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
184.1839 +				/* lock now */
184.1840 +    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) return NIL;
184.1841 +    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
184.1842 +      if (LOCAL->filetime) {	/* know previous time? */
184.1843 +	fstat (LOCAL->fd,&sbuf);/* get current write time */
184.1844 +	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
184.1845 +	LOCAL->filetime = 0;	/* don't do this test for any other messages */
184.1846 +      }
184.1847 +      if (!mbx_parse (stream)) {/* parse mailbox */
184.1848 +	unlockfd (ld,lock);	/* shouldn't happen */
184.1849 +	return NIL;
184.1850 +      }
184.1851 +      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
184.1852 +	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
184.1853 +    }
184.1854 +    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
184.1855 +    memcpy (LOCAL->lock,lock,MAILTMPLEN);
184.1856 +  }
184.1857 +  return LONGT;
184.1858 +}
   185.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   185.2 +++ b/src/osdep/amiga/mh.c	Mon Sep 14 15:17:45 2009 +0900
   185.3 @@ -0,0 +1,1283 @@
   185.4 +/* ========================================================================
   185.5 + * Copyright 1988-2007 University of Washington
   185.6 + *
   185.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   185.8 + * you may not use this file except in compliance with the License.
   185.9 + * You may obtain a copy of the License at
  185.10 + *
  185.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  185.12 + *
  185.13 + * 
  185.14 + * ========================================================================
  185.15 + */
  185.16 +
  185.17 +/*
  185.18 + * Program:	MH mail routines
  185.19 + *
  185.20 + * Author(s):	Mark Crispin
  185.21 + *		Networks and Distributed Computing
  185.22 + *		Computing & Communications
  185.23 + *		University of Washington
  185.24 + *		Administration Building, AG-44
  185.25 + *		Seattle, WA  98195
  185.26 + *		Internet: MRC@CAC.Washington.EDU
  185.27 + *
  185.28 + * Date:	23 February 1992
  185.29 + * Last Edited:	11 October 2007
  185.30 + */
  185.31 +
  185.32 +
  185.33 +#include <stdio.h>
  185.34 +#include <ctype.h>
  185.35 +#include <errno.h>
  185.36 +extern int errno;		/* just in case */
  185.37 +#include "mail.h"
  185.38 +#include "osdep.h"
  185.39 +#include <pwd.h>
  185.40 +#include <sys/stat.h>
  185.41 +#include <sys/time.h>
  185.42 +#include "misc.h"
  185.43 +#include "dummy.h"
  185.44 +#include "fdstring.h"
  185.45 +
  185.46 +
  185.47 +/* Build parameters */
  185.48 +
  185.49 +#define MHINBOX "#mhinbox"	/* corresponds to namespace in env_unix.c */
  185.50 +#define MHINBOXDIR "inbox"
  185.51 +#define MHPROFILE ".mh_profile"
  185.52 +#define MHCOMMA ','
  185.53 +#define MHSEQUENCE ".mh_sequence"
  185.54 +#define MHSEQUENCES ".mh_sequences"
  185.55 +#define MHPATH "Mail"
  185.56 +
  185.57 +
  185.58 +/* mh_load_message() flags */
  185.59 +
  185.60 +#define MLM_HEADER 0x1		/* load message text */
  185.61 +#define MLM_TEXT 0x2		/* load message text */
  185.62 +
  185.63 +/* MH I/O stream local data */
  185.64 +	
  185.65 +typedef struct mh_local {
  185.66 +  char *dir;			/* spool directory name */
  185.67 +  unsigned char buf[CHUNKSIZE];	/* temporary buffer */
  185.68 +  unsigned long cachedtexts;	/* total size of all cached texts */
  185.69 +  time_t scantime;		/* last time directory scanned */
  185.70 +} MHLOCAL;
  185.71 +
  185.72 +
  185.73 +/* Convenient access to local data */
  185.74 +
  185.75 +#define LOCAL ((MHLOCAL *) stream->local)
  185.76 +
  185.77 +
  185.78 +/* Function prototypes */
  185.79 +
  185.80 +DRIVER *mh_valid (char *name);
  185.81 +int mh_isvalid (char *name,char *tmp,long synonly);
  185.82 +int mh_namevalid (char *name);
  185.83 +char *mh_path (char *tmp);
  185.84 +void *mh_parameters (long function,void *value);
  185.85 +long mh_dirfmttest (char *name);
  185.86 +void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  185.87 +void mh_list (MAILSTREAM *stream,char *ref,char *pat);
  185.88 +void mh_lsub (MAILSTREAM *stream,char *ref,char *pat);
  185.89 +void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level);
  185.90 +long mh_subscribe (MAILSTREAM *stream,char *mailbox);
  185.91 +long mh_unsubscribe (MAILSTREAM *stream,char *mailbox);
  185.92 +long mh_create (MAILSTREAM *stream,char *mailbox);
  185.93 +long mh_delete (MAILSTREAM *stream,char *mailbox);
  185.94 +long mh_rename (MAILSTREAM *stream,char *old,char *newname);
  185.95 +MAILSTREAM *mh_open (MAILSTREAM *stream);
  185.96 +void mh_close (MAILSTREAM *stream,long options);
  185.97 +void mh_fast (MAILSTREAM *stream,char *sequence,long flags);
  185.98 +void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
  185.99 +char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 185.100 +		 long flags);
 185.101 +long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 185.102 +long mh_ping (MAILSTREAM *stream);
 185.103 +void mh_check (MAILSTREAM *stream);
 185.104 +long mh_expunge (MAILSTREAM *stream,char *sequence,long options);
 185.105 +long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
 185.106 +	      long options);
 185.107 +long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 185.108 +
 185.109 +int mh_select (struct direct *name);
 185.110 +int mh_numsort (const void *d1,const void *d2);
 185.111 +char *mh_file (char *dst,char *name);
 185.112 +long mh_canonicalize (char *pattern,char *ref,char *pat);
 185.113 +void mh_setdate (char *file,MESSAGECACHE *elt);
 185.114 +
 185.115 +/* MH mail routines */
 185.116 +
 185.117 +
 185.118 +/* Driver dispatch used by MAIL */
 185.119 +
 185.120 +DRIVER mhdriver = {
 185.121 +  "mh",				/* driver name */
 185.122 +				/* driver flags */
 185.123 +  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY|DR_DIRFMT,
 185.124 +  (DRIVER *) NIL,		/* next driver */
 185.125 +  mh_valid,			/* mailbox is valid for us */
 185.126 +  mh_parameters,		/* manipulate parameters */
 185.127 +  mh_scan,			/* scan mailboxes */
 185.128 +  mh_list,			/* find mailboxes */
 185.129 +  mh_lsub,			/* find subscribed mailboxes */
 185.130 +  mh_subscribe,			/* subscribe to mailbox */
 185.131 +  mh_unsubscribe,		/* unsubscribe from mailbox */
 185.132 +  mh_create,			/* create mailbox */
 185.133 +  mh_delete,			/* delete mailbox */
 185.134 +  mh_rename,			/* rename mailbox */
 185.135 +  mail_status_default,		/* status of mailbox */
 185.136 +  mh_open,			/* open mailbox */
 185.137 +  mh_close,			/* close mailbox */
 185.138 +  mh_fast,			/* fetch message "fast" attributes */
 185.139 +  NIL,				/* fetch message flags */
 185.140 +  NIL,				/* fetch overview */
 185.141 +  NIL,				/* fetch message envelopes */
 185.142 +  mh_header,			/* fetch message header */
 185.143 +  mh_text,			/* fetch message body */
 185.144 +  NIL,				/* fetch partial message text */
 185.145 +  NIL,				/* unique identifier */
 185.146 +  NIL,				/* message number */
 185.147 +  NIL,				/* modify flags */
 185.148 +  NIL,				/* per-message modify flags */
 185.149 +  NIL,				/* search for message based on criteria */
 185.150 +  NIL,				/* sort messages */
 185.151 +  NIL,				/* thread messages */
 185.152 +  mh_ping,			/* ping mailbox to see if still alive */
 185.153 +  mh_check,			/* check for new messages */
 185.154 +  mh_expunge,			/* expunge deleted messages */
 185.155 +  mh_copy,			/* copy messages to another mailbox */
 185.156 +  mh_append,			/* append string message to mailbox */
 185.157 +  NIL				/* garbage collect stream */
 185.158 +};
 185.159 +
 185.160 +				/* prototype stream */
 185.161 +MAILSTREAM mhproto = {&mhdriver};
 185.162 +
 185.163 +
 185.164 +static char *mh_profile = NIL;	/* holds MH profile */
 185.165 +static char *mh_pathname = NIL;	/* holds MH path name */
 185.166 +static long mh_once = 0;	/* already snarled once */
 185.167 +static long mh_allow_inbox =NIL;/* allow INBOX as well as MHINBOX */
 185.168 +
 185.169 +/* MH mail validate mailbox
 185.170 + * Accepts: mailbox name
 185.171 + * Returns: our driver if name is valid, NIL otherwise
 185.172 + */
 185.173 +
 185.174 +DRIVER *mh_valid (char *name)
 185.175 +{
 185.176 +  char tmp[MAILTMPLEN];
 185.177 +  return mh_isvalid (name,tmp,T) ? &mhdriver : NIL;
 185.178 +}
 185.179 +
 185.180 +
 185.181 +/* MH mail test for valid mailbox
 185.182 + * Accepts: mailbox name
 185.183 + *	    temporary buffer to use
 185.184 + *	    syntax only test flag
 185.185 + * Returns: T if valid, NIL otherwise
 185.186 + */
 185.187 +
 185.188 +int mh_isvalid (char *name,char *tmp,long synonly)
 185.189 +{
 185.190 +  struct stat sbuf;
 185.191 +  char *s,*t,altname[MAILTMPLEN];
 185.192 +  unsigned long i;
 185.193 +  int ret = NIL;
 185.194 +  errno = NIL;			/* zap any error condition */
 185.195 +				/* mh name? */
 185.196 +  if ((mh_allow_inbox && !compare_cstring (name,"INBOX")) ||
 185.197 +      !compare_cstring (name,MHINBOX) ||
 185.198 +      ((name[0] == '#') && ((name[1] == 'm') || (name[1] == 'M')) &&
 185.199 +       ((name[2] == 'h') || (name[2] == 'H')) && (name[3] == '/') && name[4])){
 185.200 +    if (mh_path (tmp))		/* validate name if INBOX or not synonly */
 185.201 +      ret = (synonly && compare_cstring (name,"INBOX")) ?
 185.202 +	T : ((stat (mh_file (tmp,name),&sbuf) == 0) &&
 185.203 +	     (sbuf.st_mode & S_IFMT) == S_IFDIR);
 185.204 +    else if (!mh_once++) {	/* only report error once */
 185.205 +      sprintf (tmp,"%.900s not found, mh format names disabled",mh_profile);
 185.206 +      mm_log (tmp,WARN);
 185.207 +    }
 185.208 +  }
 185.209 +				/* see if non-NS name within mh hierarchy */
 185.210 +  else if ((name[0] != '#') && (s = mh_path (tmp)) && (i = strlen (s)) &&
 185.211 +	   (t = mailboxfile (tmp,name)) && !strncmp (t,s,i) &&
 185.212 +	   (tmp[i] == '/') && tmp[i+1]) {
 185.213 +    sprintf (altname,"#mh%.900s",tmp+i);
 185.214 +				/* can't do synonly here! */
 185.215 +    ret = mh_isvalid (altname,tmp,NIL);
 185.216 +  }
 185.217 +  else errno = EINVAL;		/* bogus name */
 185.218 +  return ret;
 185.219 +}
 185.220 +
 185.221 +/* MH mail test for valid mailbox
 185.222 + * Accepts: mailbox name
 185.223 + * Returns: T if valid, NIL otherwise
 185.224 + */
 185.225 +
 185.226 +int mh_namevalid (char *name)
 185.227 +{
 185.228 +  char *s;
 185.229 +  if (name[0] == '#' && (name[1] == 'm' || name[1] == 'M') &&
 185.230 +      (name[2] == 'h' || name[2] == 'H') && name[3] == '/')
 185.231 +    for (s = name; s && *s;) {	/* make sure no all-digit nodes */
 185.232 +      if (isdigit (*s)) s++;	/* digit, check this node further... */
 185.233 +      else if (*s == '/') break;/* all digit node, barf */
 185.234 +				/* non-digit, skip to next node or return */
 185.235 +      else if (!((s = strchr (s+1,'/')) && *++s)) return T;
 185.236 +    }
 185.237 +  return NIL;			/* all numeric or empty node */
 185.238 +}
 185.239 +
 185.240 +/* Return MH path
 185.241 + * Accepts: temporary buffer
 185.242 + * Returns: MH path or NIL if MH disabled
 185.243 + */
 185.244 +
 185.245 +char *mh_path (char *tmp)
 185.246 +{
 185.247 +  char *s,*t,*v,*r;
 185.248 +  int fd;
 185.249 +  struct stat sbuf;
 185.250 +  if (!mh_profile) {		/* build mh_profile and mh_pathname now */
 185.251 +    sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE);
 185.252 +    if ((fd = open (mh_profile = cpystr (tmp),O_RDONLY,NIL)) >= 0) {
 185.253 +      fstat (fd,&sbuf);		/* yes, get size and read file */
 185.254 +      read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size);
 185.255 +      close (fd);		/* don't need the file any more */
 185.256 +      t[sbuf.st_size] = '\0';	/* tie it off */
 185.257 +				/* parse profile file */
 185.258 +      for (s = strtok_r (t,"\r\n",&r); s && *s; s = strtok_r (NIL,"\r\n",&r)) {
 185.259 +				/* found space in line? */
 185.260 +	if (v = strpbrk (s," \t")) {
 185.261 +	  *v++ = '\0';		/* tie off, is keyword "Path:"? */
 185.262 +	  if (!compare_cstring (s,"Path:")) {
 185.263 +				/* skip whitespace */
 185.264 +	    while ((*v == ' ') || (*v == '\t')) ++v;
 185.265 +				/* absolute path? */
 185.266 +	    if (*v == '/') s = v;
 185.267 +	    else sprintf (s = tmp,"%s/%s",myhomedir (),v);
 185.268 +				/* copy name */
 185.269 +	    mh_pathname = cpystr (s);
 185.270 +	    break;		/* don't need to look at rest of file */
 185.271 +	  }
 185.272 +	}
 185.273 +      }
 185.274 +      fs_give ((void **) &t);	/* flush profile text */
 185.275 +      if (!mh_pathname) {	/* default path if not in the profile */
 185.276 +	sprintf (tmp,"%s/%s",myhomedir (),MHPATH);
 185.277 +	mh_pathname = cpystr (tmp);
 185.278 +      }
 185.279 +    }
 185.280 +  }
 185.281 +  return mh_pathname;
 185.282 +}
 185.283 +
 185.284 +/* MH manipulate driver parameters
 185.285 + * Accepts: function code
 185.286 + *	    function-dependent value
 185.287 + * Returns: function-dependent return value
 185.288 + */
 185.289 +
 185.290 +void *mh_parameters (long function,void *value)
 185.291 +{
 185.292 +  void *ret = NIL;
 185.293 +  switch ((int) function) {
 185.294 +  case GET_INBOXPATH:
 185.295 +    if (value) ret = mh_file ((char *) value,"INBOX");
 185.296 +    break;
 185.297 +  case GET_DIRFMTTEST:
 185.298 +    ret = (void *) mh_dirfmttest;
 185.299 +    break;
 185.300 +  case SET_MHPROFILE:
 185.301 +    if (mh_profile) fs_give ((void **) &mh_profile);
 185.302 +    mh_profile = cpystr ((char *) value);
 185.303 +  case GET_MHPROFILE:
 185.304 +    ret = (void *) mh_profile;
 185.305 +    break;
 185.306 +  case SET_MHPATH:
 185.307 +    if (mh_pathname) fs_give ((void **) &mh_pathname);
 185.308 +    mh_pathname = cpystr ((char *) value);
 185.309 +  case GET_MHPATH:
 185.310 +    ret = (void *) mh_pathname;
 185.311 +    break;
 185.312 +  case SET_MHALLOWINBOX:
 185.313 +    mh_allow_inbox = value ? T : NIL;
 185.314 +  case GET_MHALLOWINBOX:
 185.315 +    ret = (void *) (mh_allow_inbox ? VOIDT : NIL);
 185.316 +  }
 185.317 +  return ret;
 185.318 +}
 185.319 +
 185.320 +
 185.321 +/* MH test for directory format internal node
 185.322 + * Accepts: candidate node name
 185.323 + * Returns: T if internal name, NIL otherwise
 185.324 + */
 185.325 +
 185.326 +long mh_dirfmttest (char *s)
 185.327 +{
 185.328 +  int c;
 185.329 +				/* sequence(s) file is an internal name */
 185.330 +  if (strcmp (s,MHSEQUENCE) && strcmp (s,MHSEQUENCES)) {
 185.331 +    if (*s == MHCOMMA) ++s;	/* else comma + all numeric name */
 185.332 +				/* success if all-numeric */
 185.333 +    while (c = *s++) if (!isdigit (c)) return NIL;
 185.334 +  }
 185.335 +  return LONGT;
 185.336 +}
 185.337 +
 185.338 +/* MH scan mailboxes
 185.339 + * Accepts: mail stream
 185.340 + *	    reference
 185.341 + *	    pattern to search
 185.342 + *	    string to scan
 185.343 + */
 185.344 +
 185.345 +void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 185.346 +{
 185.347 +  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
 185.348 +  long i = 0;
 185.349 +  if (!pat || !*pat) {		/* empty pattern? */
 185.350 +    if (mh_canonicalize (test,ref,"*")) {
 185.351 +				/* tie off name at root */
 185.352 +      if (s = strchr (test,'/')) *++s = '\0';
 185.353 +      else test[0] = '\0';
 185.354 +      mm_list (stream,'/',test,LATT_NOSELECT);
 185.355 +    }
 185.356 +  }
 185.357 +				/* get canonical form of name */
 185.358 +  else if (mh_canonicalize (test,ref,pat)) {
 185.359 +    if (contents) {		/* maybe I'll implement this someday */
 185.360 +      mm_log ("Scan not valid for mh mailboxes",ERROR);
 185.361 +      return;
 185.362 +    }
 185.363 +    if (test[3] == '/') {	/* looking down levels? */
 185.364 +				/* yes, found any wildcards? */
 185.365 +      if (s = strpbrk (test,"%*")) {
 185.366 +				/* yes, copy name up to that point */
 185.367 +	strncpy (file,test+4,i = s - (test+4));
 185.368 +	file[i] = '\0';		/* tie off */
 185.369 +      }
 185.370 +      else strcpy (file,test+4);/* use just that name then */
 185.371 +				/* find directory name */
 185.372 +      if (s = strrchr (file,'/')) {
 185.373 +	*s = '\0';		/* found, tie off at that point */
 185.374 +	s = file;
 185.375 +      }
 185.376 +				/* do the work */
 185.377 +      mh_list_work (stream,s,test,0);
 185.378 +    }
 185.379 +				/* always an INBOX */
 185.380 +    if (!compare_cstring (test,MHINBOX))
 185.381 +      mm_list (stream,NIL,MHINBOX,LATT_NOINFERIORS);
 185.382 +  }
 185.383 +}
 185.384 +
 185.385 +/* MH list mailboxes
 185.386 + * Accepts: mail stream
 185.387 + *	    reference
 185.388 + *	    pattern to search
 185.389 + */
 185.390 +
 185.391 +void mh_list (MAILSTREAM *stream,char *ref,char *pat)
 185.392 +{
 185.393 +  mh_scan (stream,ref,pat,NIL);
 185.394 +}
 185.395 +
 185.396 +
 185.397 +/* MH list subscribed mailboxes
 185.398 + * Accepts: mail stream
 185.399 + *	    reference
 185.400 + *	    pattern to search
 185.401 + */
 185.402 +
 185.403 +void mh_lsub (MAILSTREAM *stream,char *ref,char *pat)
 185.404 +{
 185.405 +  void *sdb = NIL;
 185.406 +  char *s,test[MAILTMPLEN];
 185.407 +				/* get canonical form of name */
 185.408 +  if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
 185.409 +    do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
 185.410 +    while (s = sm_read (&sdb)); /* until no more subscriptions */
 185.411 +  }
 185.412 +}
 185.413 +
 185.414 +/* MH list mailboxes worker routine
 185.415 + * Accepts: mail stream
 185.416 + *	    directory name to search
 185.417 + *	    search pattern
 185.418 + *	    search level
 185.419 + */
 185.420 +
 185.421 +void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
 185.422 +{
 185.423 +  DIR *dp;
 185.424 +  struct direct *d;
 185.425 +  struct stat sbuf;
 185.426 +  char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN];
 185.427 +				/* build MH name to search */
 185.428 +  if (dir) sprintf (name,"#mh/%s/",dir);
 185.429 +  else strcpy (name,"#mh/");
 185.430 +				/* make directory name, punt if bogus */
 185.431 +  if (!mh_file (curdir,name)) return;
 185.432 +  cp = curdir + strlen (curdir);/* end of directory name */
 185.433 +  np = name + strlen (name);	/* end of MH name */
 185.434 +  if (dp = opendir (curdir)) {	/* open directory */
 185.435 +    while (d = readdir (dp))	/* scan, ignore . and numeric names */
 185.436 +      if ((d->d_name[0] != '.') && !mh_select (d)) {
 185.437 +	strcpy (cp,d->d_name);	/* make directory name */
 185.438 +	if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
 185.439 +	  strcpy (np,d->d_name);/* make mh name of directory name */
 185.440 +				/* yes, an MH name if full match */
 185.441 +	  if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL);
 185.442 +				/* check if should recurse */
 185.443 +	  if (dmatch (name,pat,'/') &&
 185.444 +	      (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 185.445 +	    mh_list_work (stream,name+4,pat,level+1);
 185.446 +	}
 185.447 +      }
 185.448 +    closedir (dp);		/* all done, flush directory */
 185.449 +  }
 185.450 +}
 185.451 +
 185.452 +/* MH mail subscribe to mailbox
 185.453 + * Accepts: mail stream
 185.454 + *	    mailbox to add to subscription list
 185.455 + * Returns: T on success, NIL on failure
 185.456 + */
 185.457 +
 185.458 +long mh_subscribe (MAILSTREAM *stream,char *mailbox)
 185.459 +{
 185.460 +  return sm_subscribe (mailbox);
 185.461 +}
 185.462 +
 185.463 +
 185.464 +/* MH mail unsubscribe to mailbox
 185.465 + * Accepts: mail stream
 185.466 + *	    mailbox to delete from subscription list
 185.467 + * Returns: T on success, NIL on failure
 185.468 + */
 185.469 +
 185.470 +long mh_unsubscribe (MAILSTREAM *stream,char *mailbox)
 185.471 +{
 185.472 +  return sm_unsubscribe (mailbox);
 185.473 +}
 185.474 +
 185.475 +/* MH mail create mailbox
 185.476 + * Accepts: mail stream
 185.477 + *	    mailbox name to create
 185.478 + * Returns: T on success, NIL on failure
 185.479 + */
 185.480 +
 185.481 +long mh_create (MAILSTREAM *stream,char *mailbox)
 185.482 +{
 185.483 +  char tmp[MAILTMPLEN];
 185.484 +  if (!mh_namevalid (mailbox))	/* validate name */
 185.485 +    sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox);
 185.486 +				/* must not already exist */
 185.487 +  else if (mh_isvalid (mailbox,tmp,NIL))
 185.488 +    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
 185.489 +  else if (!mh_path (tmp)) return NIL;
 185.490 +				/* try to make it */
 185.491 +  else if (!(mh_file (tmp,mailbox) &&
 185.492 +	     dummy_create_path (stream,strcat (tmp,"/"),
 185.493 +				get_dir_protection (mailbox))))
 185.494 +    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
 185.495 +  else return LONGT;		/* success */
 185.496 +  mm_log (tmp,ERROR);
 185.497 +  return NIL;
 185.498 +}
 185.499 +
 185.500 +/* MH mail delete mailbox
 185.501 + *	    mailbox name to delete
 185.502 + * Returns: T on success, NIL on failure
 185.503 + */
 185.504 +
 185.505 +long mh_delete (MAILSTREAM *stream,char *mailbox)
 185.506 +{
 185.507 +  DIR *dirp;
 185.508 +  struct direct *d;
 185.509 +  int i;
 185.510 +  char tmp[MAILTMPLEN];
 185.511 +				/* is mailbox valid? */
 185.512 +  if (!mh_isvalid (mailbox,tmp,NIL)) {
 185.513 +    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
 185.514 +    mm_log (tmp,ERROR);
 185.515 +    return NIL;
 185.516 +  }
 185.517 +				/* get name of directory */
 185.518 +  i = strlen (mh_file (tmp,mailbox));
 185.519 +  if (dirp = opendir (tmp)) {	/* open directory */
 185.520 +    tmp[i++] = '/';		/* now apply trailing delimiter */
 185.521 +				/* massacre all mh owned files */
 185.522 +    while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) {
 185.523 +      strcpy (tmp + i,d->d_name);
 185.524 +      unlink (tmp);		/* sayonara */
 185.525 +    }
 185.526 +    closedir (dirp);		/* flush directory */
 185.527 +  }
 185.528 +				/* try to remove the directory */
 185.529 +  if (rmdir (mh_file (tmp,mailbox))) {
 185.530 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno));
 185.531 +    mm_log (tmp,WARN);
 185.532 +  }
 185.533 +  return T;			/* return success */
 185.534 +}
 185.535 +
 185.536 +/* MH mail rename mailbox
 185.537 + * Accepts: MH mail stream
 185.538 + *	    old mailbox name
 185.539 + *	    new mailbox name
 185.540 + * Returns: T on success, NIL on failure
 185.541 + */
 185.542 +
 185.543 +long mh_rename (MAILSTREAM *stream,char *old,char *newname)
 185.544 +{
 185.545 +  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
 185.546 +  struct stat sbuf;
 185.547 +				/* old mailbox name must be valid */
 185.548 +  if (!mh_isvalid (old,tmp,NIL))
 185.549 +    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
 185.550 +  else if (!mh_namevalid (newname))
 185.551 +    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name",
 185.552 +	     newname);
 185.553 +				/* new mailbox name must not be valid */
 185.554 +  else if (mh_isvalid (newname,tmp,NIL))
 185.555 +    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
 185.556 +	     newname);
 185.557 +				/* success if can rename the directory */
 185.558 +  else {			/* found superior to destination name? */
 185.559 +    if (s = strrchr (mh_file (tmp1,newname),'/')) {
 185.560 +      c = *++s;			/* remember first character of inferior */
 185.561 +      *s = '\0';		/* tie off to get just superior */
 185.562 +				/* name doesn't exist, create it */
 185.563 +      if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 185.564 +	  !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
 185.565 +	return NIL;
 185.566 +      *s = c;			/* restore full name */
 185.567 +    }
 185.568 +    if (!rename (mh_file (tmp,old),tmp1)) return T;
 185.569 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
 185.570 +	     old,newname,strerror (errno));
 185.571 +  }
 185.572 +  mm_log (tmp,ERROR);		/* something failed */
 185.573 +  return NIL;
 185.574 +}
 185.575 +
 185.576 +/* MH mail open
 185.577 + * Accepts: stream to open
 185.578 + * Returns: stream on success, NIL on failure
 185.579 + */
 185.580 +
 185.581 +MAILSTREAM *mh_open (MAILSTREAM *stream)
 185.582 +{
 185.583 +  char tmp[MAILTMPLEN];
 185.584 +  if (!stream) return &mhproto;	/* return prototype for OP_PROTOTYPE call */
 185.585 +  if (stream->local) fatal ("mh recycle stream");
 185.586 +  stream->local = fs_get (sizeof (MHLOCAL));
 185.587 +  /* INBOXness is one of the following:
 185.588 +   * #mhinbox (case-independent)
 185.589 +   * #mh/inbox (mh is case-independent, inbox is case-dependent)
 185.590 +   * INBOX (case-independent
 185.591 +   */		
 185.592 +  stream->inbox =		/* note if an INBOX or not */
 185.593 +    (!compare_cstring (stream->mailbox,MHINBOX) ||
 185.594 +     ((stream->mailbox[0] == '#') &&
 185.595 +      ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) &&
 185.596 +      ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) &&
 185.597 +      (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) ||
 185.598 +     !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL;
 185.599 +  mh_file (tmp,stream->mailbox);/* get directory name */
 185.600 +  LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
 185.601 +  LOCAL->scantime = 0;		/* not scanned yet */
 185.602 +  LOCAL->cachedtexts = 0;	/* no cached texts */
 185.603 +  stream->sequence++;		/* bump sequence number */
 185.604 +				/* parse mailbox */
 185.605 +  stream->nmsgs = stream->recent = 0;
 185.606 +  if (!mh_ping (stream)) return NIL;
 185.607 +  if (!(stream->nmsgs || stream->silent))
 185.608 +    mm_log ("Mailbox is empty",(long) NIL);
 185.609 +  return stream;		/* return stream to caller */
 185.610 +}
 185.611 +
 185.612 +/* MH mail close
 185.613 + * Accepts: MAIL stream
 185.614 + *	    close options
 185.615 + */
 185.616 +
 185.617 +void mh_close (MAILSTREAM *stream,long options)
 185.618 +{
 185.619 +  if (LOCAL) {			/* only if a file is open */
 185.620 +    int silent = stream->silent;
 185.621 +    stream->silent = T;		/* note this stream is dying */
 185.622 +    if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL);
 185.623 +    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
 185.624 +				/* nuke the local data */
 185.625 +    fs_give ((void **) &stream->local);
 185.626 +    stream->dtb = NIL;		/* log out the DTB */
 185.627 +    stream->silent = silent;	/* reset silent state */
 185.628 +  }
 185.629 +}
 185.630 +
 185.631 +
 185.632 +/* MH mail fetch fast information
 185.633 + * Accepts: MAIL stream
 185.634 + *	    sequence
 185.635 + *	    option flags
 185.636 + */
 185.637 +
 185.638 +void mh_fast (MAILSTREAM *stream,char *sequence,long flags)
 185.639 +{
 185.640 +  MESSAGECACHE *elt;
 185.641 +  unsigned long i;
 185.642 +				/* set up metadata for all messages */
 185.643 +  if (stream && LOCAL && ((flags & FT_UID) ?
 185.644 +			  mail_uid_sequence (stream,sequence) :
 185.645 +			  mail_sequence (stream,sequence)))
 185.646 +    for (i = 1; i <= stream->nmsgs; i++)
 185.647 +      if ((elt = mail_elt (stream,i))->sequence &&
 185.648 +	  !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL);
 185.649 +}
 185.650 +
 185.651 +/* MH load message into cache
 185.652 + * Accepts: MAIL stream
 185.653 + *	    message #
 185.654 + *	    option flags
 185.655 + */
 185.656 +
 185.657 +void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
 185.658 +{
 185.659 +  unsigned long i,j,nlseen;
 185.660 +  int fd;
 185.661 +  unsigned char c,*t;
 185.662 +  struct stat sbuf;
 185.663 +  MESSAGECACHE *elt;
 185.664 +  FDDATA d;
 185.665 +  STRING bs;
 185.666 +  elt = mail_elt (stream,msgno);/* get elt */
 185.667 +				/* build message file name */
 185.668 +  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
 185.669 +				/* anything we need not currently cached? */
 185.670 +  if ((!elt->day || !elt->rfc822_size ||
 185.671 +       ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
 185.672 +       ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) &&
 185.673 +      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
 185.674 +    fstat (fd,&sbuf);		/* get file metadata */
 185.675 +    d.fd = fd;			/* set up file descriptor */
 185.676 +    d.pos = 0;			/* start of file */
 185.677 +    d.chunk = LOCAL->buf;
 185.678 +    d.chunksize = CHUNKSIZE;
 185.679 +    INIT (&bs,fd_string,&d,sbuf.st_size);
 185.680 +    if (!elt->day) {		/* set internaldate to file date */
 185.681 +      struct tm *tm = gmtime (&sbuf.st_mtime);
 185.682 +      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
 185.683 +      elt->year = tm->tm_year + 1900 - BASEYEAR;
 185.684 +      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
 185.685 +      elt->seconds = tm->tm_sec;
 185.686 +      elt->zhours = 0; elt->zminutes = 0;
 185.687 +    }
 185.688 +
 185.689 +    if (!elt->rfc822_size) {	/* know message size yet? */
 185.690 +      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
 185.691 +      case '\015':		/* unlikely carriage return */
 185.692 +	if (!j || (CHR (&bs) != '\012')) {
 185.693 +	  i++;			/* ugh, raw CR */
 185.694 +	  nlseen = NIL;
 185.695 +	  break;
 185.696 +	}
 185.697 +	SNX (&bs);		/* eat the line feed, drop in */
 185.698 +	--j;
 185.699 +      case '\012':		/* line feed? */
 185.700 +	i += 2;			/* count a CRLF */
 185.701 +				/* header size known yet? */
 185.702 +	if (!elt->private.msg.header.text.size && nlseen) {
 185.703 +				/* note position in file */
 185.704 +	  elt->private.special.text.size = GETPOS (&bs);
 185.705 +				/* and CRLF-adjusted size */
 185.706 +	  elt->private.msg.header.text.size = i;
 185.707 +	}
 185.708 +	nlseen = T;		/* note newline seen */
 185.709 +	break;
 185.710 +      default:			/* ordinary chararacter */
 185.711 +	i++;
 185.712 +	nlseen = NIL;
 185.713 +	break;
 185.714 +      }
 185.715 +      SETPOS (&bs,0);		/* restore old position */
 185.716 +      elt->rfc822_size = i;	/* note that we have size now */
 185.717 +				/* header is entire message if no delimiter */
 185.718 +      if (!elt->private.msg.header.text.size)
 185.719 +	elt->private.msg.header.text.size = elt->rfc822_size;
 185.720 +				/* text is remainder of message */
 185.721 +      elt->private.msg.text.text.size =
 185.722 +	elt->rfc822_size - elt->private.msg.header.text.size;
 185.723 +    }
 185.724 +				/* need to load cache with message data? */
 185.725 +    if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
 185.726 +	((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) {
 185.727 +				/* purge cache if too big */
 185.728 +      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
 185.729 +				/* just can't keep that much */
 185.730 +	mail_gc (stream,GC_TEXTS);
 185.731 +	LOCAL->cachedtexts = 0;
 185.732 +      }
 185.733 +
 185.734 +      if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) {
 185.735 +	t = elt->private.msg.header.text.data =
 185.736 +	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
 185.737 +	LOCAL->cachedtexts += elt->private.msg.header.text.size;
 185.738 +				/* read in message header */
 185.739 +	for (i = 0; i < elt->private.msg.header.text.size; i++)
 185.740 +	  switch (c = SNX (&bs)) {
 185.741 +	  case '\015':		/* unlikely carriage return */
 185.742 +	    *t++ = c;
 185.743 +	    if ((CHR (&bs) == '\012')) {
 185.744 +	      *t++ = SNX (&bs);
 185.745 +	      i++;
 185.746 +	    }
 185.747 +	    break;
 185.748 +	  case '\012':		/* line feed? */
 185.749 +	    *t++ = '\015';
 185.750 +	    i++;
 185.751 +	  default:
 185.752 +	    *t++ = c;
 185.753 +	    break;
 185.754 +	  }
 185.755 +	*t = '\0';		/* tie off string */
 185.756 +	if ((t - elt->private.msg.header.text.data) !=
 185.757 +	    elt->private.msg.header.text.size) fatal ("mh hdr size mismatch");
 185.758 +      }
 185.759 +      if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) {
 185.760 +	t = elt->private.msg.text.text.data =
 185.761 +	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
 185.762 +	SETPOS (&bs,elt->private.special.text.size);
 185.763 +	LOCAL->cachedtexts += elt->private.msg.text.text.size;
 185.764 +				/* read in message text */
 185.765 +	for (i = 0; i < elt->private.msg.text.text.size; i++)
 185.766 +	  switch (c = SNX (&bs)) {
 185.767 +	  case '\015':		/* unlikely carriage return */
 185.768 +	    *t++ = c;
 185.769 +	    if ((CHR (&bs) == '\012')) {
 185.770 +	      *t++ = SNX (&bs);
 185.771 +	      i++;
 185.772 +	    }
 185.773 +	    break;
 185.774 +	  case '\012':		/* line feed? */
 185.775 +	    *t++ = '\015';
 185.776 +	    i++;
 185.777 +	  default:
 185.778 +	    *t++ = c;
 185.779 +	    break;
 185.780 +	  }
 185.781 +	*t = '\0';		/* tie off string */
 185.782 +	if ((t - elt->private.msg.text.text.data) !=
 185.783 +	    elt->private.msg.text.text.size) fatal ("mh txt size mismatch");
 185.784 +      }
 185.785 +    }
 185.786 +    close (fd);			/* flush message file */
 185.787 +  }
 185.788 +}
 185.789 +
 185.790 +/* MH mail fetch message header
 185.791 + * Accepts: MAIL stream
 185.792 + *	    message # to fetch
 185.793 + *	    pointer to returned header text length
 185.794 + *	    option flags
 185.795 + * Returns: message header in RFC822 format
 185.796 + */
 185.797 +
 185.798 +char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 185.799 +		 long flags)
 185.800 +{
 185.801 +  MESSAGECACHE *elt;
 185.802 +  *length = 0;			/* default to empty */
 185.803 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 185.804 +  elt = mail_elt (stream,msgno);/* get elt */
 185.805 +  if (!elt->private.msg.header.text.data)
 185.806 +    mh_load_message (stream,msgno,MLM_HEADER);
 185.807 +  *length = elt->private.msg.header.text.size;
 185.808 +  return (char *) elt->private.msg.header.text.data;
 185.809 +}
 185.810 +
 185.811 +
 185.812 +/* MH mail fetch message text (body only)
 185.813 + * Accepts: MAIL stream
 185.814 + *	    message # to fetch
 185.815 + *	    pointer to returned stringstruct
 185.816 + *	    option flags
 185.817 + * Returns: T on success, NIL on failure
 185.818 + */
 185.819 +
 185.820 +long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 185.821 +{
 185.822 +  MESSAGECACHE *elt;
 185.823 +				/* UID call "impossible" */
 185.824 +  if (flags & FT_UID) return NIL;
 185.825 +  elt = mail_elt (stream,msgno);/* get elt */
 185.826 +				/* snarf message if don't have it yet */
 185.827 +  if (!elt->private.msg.text.text.data) {
 185.828 +    mh_load_message (stream,msgno,MLM_TEXT);
 185.829 +    if (!elt->private.msg.text.text.data) return NIL;
 185.830 +  }
 185.831 +  if (!(flags & FT_PEEK)) {	/* mark as seen */
 185.832 +    mail_elt (stream,msgno)->seen = T;
 185.833 +    mm_flags (stream,msgno);
 185.834 +  }
 185.835 +  INIT (bs,mail_string,elt->private.msg.text.text.data,
 185.836 +	elt->private.msg.text.text.size);
 185.837 +  return T;
 185.838 +}
 185.839 +
 185.840 +/* MH mail ping mailbox
 185.841 + * Accepts: MAIL stream
 185.842 + * Returns: T if stream alive, else NIL
 185.843 + */
 185.844 +
 185.845 +long mh_ping (MAILSTREAM *stream)
 185.846 +{
 185.847 +  MAILSTREAM *sysibx = NIL;
 185.848 +  MESSAGECACHE *elt,*selt;
 185.849 +  struct stat sbuf;
 185.850 +  char *s,tmp[MAILTMPLEN];
 185.851 +  int fd;
 185.852 +  unsigned long i,j,r;
 185.853 +  unsigned long old = stream->uid_last;
 185.854 +  long nmsgs = stream->nmsgs;
 185.855 +  long recent = stream->recent;
 185.856 +  int silent = stream->silent;
 185.857 +  if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */
 185.858 +    if (stream->inbox &&	/* no, create if INBOX */
 185.859 +	dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"),
 185.860 +			   get_dir_protection ("INBOX"))) return T;
 185.861 +    sprintf (tmp,"Can't open mailbox %.80s: no such mailbox",stream->mailbox);
 185.862 +    mm_log (tmp,ERROR);
 185.863 +    return NIL;
 185.864 +  }
 185.865 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
 185.866 +  if (sbuf.st_ctime != LOCAL->scantime) {
 185.867 +    struct direct **names = NIL;
 185.868 +    long nfiles = scandir (LOCAL->dir,&names,mh_select,mh_numsort);
 185.869 +    if (nfiles < 0) nfiles = 0;	/* in case error */
 185.870 +				/* note scanned now */
 185.871 +    LOCAL->scantime = sbuf.st_ctime;
 185.872 +				/* scan directory */
 185.873 +    for (i = 0; i < nfiles; ++i) {
 185.874 +				/* if newly seen, add to list */
 185.875 +      if ((j = atoi (names[i]->d_name)) > old) {
 185.876 +	mail_exists (stream,++nmsgs);
 185.877 +	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
 185.878 +	elt->valid = T;		/* note valid flags */
 185.879 +	if (old) {		/* other than the first pass? */
 185.880 +	  elt->recent = T;	/* yup, mark as recent */
 185.881 +	  recent++;		/* bump recent count */
 185.882 +	}
 185.883 +	else {			/* see if already read */
 185.884 +	  sprintf (tmp,"%s/%s",LOCAL->dir,names[i]->d_name);
 185.885 +	  if (!stat (tmp,&sbuf) && (sbuf.st_atime > sbuf.st_mtime))
 185.886 +	    elt->seen = T;
 185.887 +	}
 185.888 +      }
 185.889 +      fs_give ((void **) &names[i]);
 185.890 +    }
 185.891 +				/* free directory */
 185.892 +    if (s = (void *) names) fs_give ((void **) &s);
 185.893 +  }
 185.894 +
 185.895 +				/* if INBOX, snarf from system INBOX  */
 185.896 +  if (stream->inbox && strcmp (sysinbox (),stream->mailbox)) {
 185.897 +    old = stream->uid_last;
 185.898 +    mm_critical (stream);	/* go critical */
 185.899 +				/* see if anything in system inbox */
 185.900 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 185.901 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 185.902 +	!sysibx->rdonly && (r = sysibx->nmsgs)) {
 185.903 +      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
 185.904 +				/* build file name we will use */
 185.905 +	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old);
 185.906 +				/* snarf message from Berkeley mailbox */
 185.907 +	selt = mail_elt (sysibx,i);
 185.908 +	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
 185.909 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
 185.910 +	     >= 0) &&
 185.911 +	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_INTERNAL)) &&
 185.912 +	    (write (fd,s,j) == j) &&
 185.913 +	    (s = mail_fetchtext_full (sysibx,i,&j,FT_INTERNAL|FT_PEEK)) &&
 185.914 +	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
 185.915 +				/* swell the cache */
 185.916 +	  mail_exists (stream,++nmsgs);
 185.917 +	  stream->uid_last =	/* create new elt, note its file number */
 185.918 +	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
 185.919 +	  recent++;		/* bump recent count */
 185.920 +				/* set up initial flags and date */
 185.921 +	  elt->valid = elt->recent = T;
 185.922 +	  elt->seen = selt->seen;
 185.923 +	  elt->deleted = selt->deleted;
 185.924 +	  elt->flagged = selt->flagged;
 185.925 +	  elt->answered = selt->answered;
 185.926 +	  elt->draft = selt->draft;
 185.927 +	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
 185.928 +	  elt->hours = selt->hours;elt->minutes = selt->minutes;
 185.929 +	  elt->seconds = selt->seconds;
 185.930 +	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
 185.931 +	  elt->zoccident = selt->zoccident;
 185.932 +	  mh_setdate (LOCAL->buf,elt);
 185.933 +	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
 185.934 +	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 185.935 +	}
 185.936 +
 185.937 +	else {			/* failed to snarf */
 185.938 +	  if (fd) {		/* did it ever get opened? */
 185.939 +	    close (fd);		/* close descriptor */
 185.940 +	    unlink (LOCAL->buf);/* flush this file */
 185.941 +	  }
 185.942 +	  sprintf (tmp,"Message copy to MH mailbox failed: %.80s",
 185.943 +		   s,strerror (errno));
 185.944 +	  mm_log (tmp,ERROR);
 185.945 +	  r = 0;		/* stop the snarf in its tracks */
 185.946 +	}
 185.947 +      }
 185.948 +				/* update scan time */
 185.949 +      if (!stat (LOCAL->dir,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
 185.950 +      mail_expunge (sysibx);	/* now expunge all those messages */
 185.951 +    }
 185.952 +    if (sysibx) mail_close (sysibx);
 185.953 +    mm_nocritical (stream);	/* release critical */
 185.954 +  }
 185.955 +  stream->silent = silent;	/* can pass up events now */
 185.956 +  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
 185.957 +  mail_recent (stream,recent);
 185.958 +  return T;			/* return that we are alive */
 185.959 +}
 185.960 +
 185.961 +/* MH mail check mailbox
 185.962 + * Accepts: MAIL stream
 185.963 + */
 185.964 +
 185.965 +void mh_check (MAILSTREAM *stream)
 185.966 +{
 185.967 +  /* Perhaps in the future this will preserve flags */
 185.968 +  if (mh_ping (stream)) mm_log ("Check completed",(long) NIL);
 185.969 +}
 185.970 +
 185.971 +
 185.972 +/* MH mail expunge mailbox
 185.973 + * Accepts: MAIL stream
 185.974 + *	    sequence to expunge if non-NIL
 185.975 + *	    expunge options
 185.976 + * Returns: T, always
 185.977 + */
 185.978 +
 185.979 +long mh_expunge (MAILSTREAM *stream,char *sequence,long options)
 185.980 +{
 185.981 +  long ret;
 185.982 +  MESSAGECACHE *elt;
 185.983 +  unsigned long i = 1;
 185.984 +  unsigned long n = 0;
 185.985 +  unsigned long recent = stream->recent;
 185.986 +  if (ret = sequence ? ((options & EX_UID) ?
 185.987 +			mail_uid_sequence (stream,sequence) :
 185.988 +			mail_sequence (stream,sequence)) : LONGT) {
 185.989 +    mm_critical (stream);	/* go critical */
 185.990 +    while (i <= stream->nmsgs) {/* for each message */
 185.991 +      elt = mail_elt (stream,i);/* if deleted, need to trash it */
 185.992 +      if (elt->deleted && (sequence ? elt->sequence : T)) {
 185.993 +	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
 185.994 +	if (unlink (LOCAL->buf)) {/* try to delete the message */
 185.995 +	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
 185.996 +		   strerror (errno));
 185.997 +	  mm_log (LOCAL->buf,(long) NIL);
 185.998 +	  break;
 185.999 +	}
185.1000 +				/* note uncached */
185.1001 +	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
185.1002 +				elt->private.msg.header.text.size : 0) +
185.1003 +			       (elt->private.msg.text.text.data ?
185.1004 +				elt->private.msg.text.text.size : 0));
185.1005 +	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
185.1006 +				/* if recent, note one less recent message */
185.1007 +	if (elt->recent) --recent;
185.1008 +				/* notify upper levels */
185.1009 +	mail_expunged (stream,i);
185.1010 +	n++;			/* count up one more expunged message */
185.1011 +      }
185.1012 +      else i++;			/* otherwise try next message */
185.1013 +    }
185.1014 +    if (n) {			/* output the news if any expunged */
185.1015 +      sprintf (LOCAL->buf,"Expunged %lu messages",n);
185.1016 +      mm_log (LOCAL->buf,(long) NIL);
185.1017 +    }
185.1018 +    else mm_log ("No messages deleted, so no update needed",(long) NIL);
185.1019 +    mm_nocritical (stream);	/* release critical */
185.1020 +				/* notify upper level of new mailbox size */
185.1021 +    mail_exists (stream,stream->nmsgs);
185.1022 +    mail_recent (stream,recent);
185.1023 +  }
185.1024 +  return ret;
185.1025 +}
185.1026 +
185.1027 +/* MH mail copy message(s)
185.1028 + * Accepts: MAIL stream
185.1029 + *	    sequence
185.1030 + *	    destination mailbox
185.1031 + *	    copy options
185.1032 + * Returns: T if copy successful, else NIL
185.1033 + */
185.1034 +
185.1035 +long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
185.1036 +{
185.1037 +  FDDATA d;
185.1038 +  STRING st;
185.1039 +  MESSAGECACHE *elt;
185.1040 +  struct stat sbuf;
185.1041 +  int fd;
185.1042 +  unsigned long i;
185.1043 +  char flags[MAILTMPLEN],date[MAILTMPLEN];
185.1044 +  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
185.1045 +  long ret = NIL;
185.1046 +				/* copy the messages */
185.1047 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
185.1048 +      mail_sequence (stream,sequence))
185.1049 +    for (i = 1; i <= stream->nmsgs; i++) 
185.1050 +      if ((elt = mail_elt (stream,i))->sequence) {
185.1051 +	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
185.1052 +	if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL;
185.1053 +	fstat (fd,&sbuf);	/* get size of message */
185.1054 +	if (!elt->day) {	/* set internaldate to file date if needed */
185.1055 +	  struct tm *tm = gmtime (&sbuf.st_mtime);
185.1056 +	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
185.1057 +	  elt->year = tm->tm_year + 1900 - BASEYEAR;
185.1058 +	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
185.1059 +	  elt->seconds = tm->tm_sec;
185.1060 +	  elt->zhours = 0; elt->zminutes = 0;
185.1061 +	}
185.1062 +	d.fd = fd;		/* set up file descriptor */
185.1063 +	d.pos = 0;		/* start of file */
185.1064 +	d.chunk = LOCAL->buf;
185.1065 +	d.chunksize = CHUNKSIZE;
185.1066 +				/* kludge; mh_append would just strip CRs */
185.1067 +	INIT (&st,fd_string,&d,sbuf.st_size);
185.1068 +				/* init flag string */
185.1069 +	flags[0] = flags[1] = '\0';
185.1070 +	if (elt->seen) strcat (flags," \\Seen");
185.1071 +	if (elt->deleted) strcat (flags," \\Deleted");
185.1072 +	if (elt->flagged) strcat (flags," \\Flagged");
185.1073 +	if (elt->answered) strcat (flags," \\Answered");
185.1074 +	if (elt->draft) strcat (flags," \\Draft");
185.1075 +	flags[0] = '(';		/* open list */
185.1076 +	strcat (flags,")");	/* close list */
185.1077 +	mail_date (date,elt);	/* generate internal date */
185.1078 +	if (au) mail_parameters (NIL,SET_APPENDUID,NIL);
185.1079 +	if ((ret = mail_append_full (NIL,mailbox,flags,date,&st)) &&
185.1080 +	    (options & CP_MOVE)) elt->deleted = T;
185.1081 +	if (au) mail_parameters (NIL,SET_APPENDUID,(void *) au);
185.1082 +	close (fd);
185.1083 +      }
185.1084 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
185.1085 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
185.1086 +  return ret;			/* return success */
185.1087 +}
185.1088 +
185.1089 +/* MH mail append message from stringstruct
185.1090 + * Accepts: MAIL stream
185.1091 + *	    destination mailbox
185.1092 + *	    append callback
185.1093 + *	    data for callback
185.1094 + * Returns: T if append successful, else NIL
185.1095 + */
185.1096 +
185.1097 +long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
185.1098 +{
185.1099 +  struct direct **names = NIL;
185.1100 +  int fd;
185.1101 +  char c,*flags,*date,*s,tmp[MAILTMPLEN];
185.1102 +  STRING *message;
185.1103 +  MESSAGECACHE elt;
185.1104 +  FILE *df;
185.1105 +  long i,size,last,nfiles;
185.1106 +  long ret = LONGT;
185.1107 +				/* default stream to prototype */
185.1108 +  if (!stream) stream = &mhproto;
185.1109 +				/* make sure valid mailbox */
185.1110 +  if (!mh_isvalid (mailbox,tmp,NIL)) switch (errno) {
185.1111 +  case ENOENT:			/* no such file? */
185.1112 +    if (!((!compare_cstring (mailbox,MHINBOX) ||
185.1113 +	   !compare_cstring (mailbox,"INBOX")) &&
185.1114 +	  (mh_file (tmp,MHINBOX) &&
185.1115 +	   dummy_create_path (stream,strcat (tmp,"/"),
185.1116 +			      get_dir_protection (mailbox))))) {
185.1117 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
185.1118 +      return NIL;
185.1119 +    }
185.1120 +				/* falls through */
185.1121 +  case 0:			/* merely empty file? */
185.1122 +    break;
185.1123 +  case EINVAL:
185.1124 +    sprintf (tmp,"Invalid MH-format mailbox name: %.80s",mailbox);
185.1125 +    mm_log (tmp,ERROR);
185.1126 +    return NIL;
185.1127 +  default:
185.1128 +    sprintf (tmp,"Not a MH-format mailbox: %.80s",mailbox);
185.1129 +    mm_log (tmp,ERROR);
185.1130 +    return NIL;
185.1131 +  }
185.1132 +				/* get first message */
185.1133 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
185.1134 +  if ((nfiles = scandir (tmp,&names,mh_select,mh_numsort)) > 0) {
185.1135 +				/* largest number */
185.1136 +    last = atoi (names[nfiles-1]->d_name);    
185.1137 +    for (i = 0; i < nfiles; ++i) /* free directory */
185.1138 +      fs_give ((void **) &names[i]);
185.1139 +  }
185.1140 +  else last = 0;		/* no messages here yet */
185.1141 +  if (s = (void *) names) fs_give ((void **) &s);
185.1142 +
185.1143 +  mm_critical (stream);		/* go critical */
185.1144 +  do {
185.1145 +    if (!SIZE (message)) {	/* guard against zero-length */
185.1146 +      mm_log ("Append of zero-length message",ERROR);
185.1147 +      ret = NIL;
185.1148 +      break;
185.1149 +    }
185.1150 +    if (date) {			/* want to preserve date? */
185.1151 +				/* yes, parse date into an elt */
185.1152 +      if (!mail_parse_date (&elt,date)) {
185.1153 +	sprintf (tmp,"Bad date in append: %.80s",date);
185.1154 +	mm_log (tmp,ERROR);
185.1155 +	ret = NIL;
185.1156 +	break;
185.1157 +      }
185.1158 +    }
185.1159 +    mh_file (tmp,mailbox);	/* build file name we will use */
185.1160 +    sprintf (tmp + strlen (tmp),"/%ld",++last);
185.1161 +    if (((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
185.1162 +		     (long)mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0)||
185.1163 +	!(df = fdopen (fd,"ab"))) {
185.1164 +      sprintf (tmp,"Can't open append message: %s",strerror (errno));
185.1165 +      mm_log (tmp,ERROR);
185.1166 +      ret = NIL;
185.1167 +      break;
185.1168 +    }
185.1169 +				/* copy the data w/o CR's */
185.1170 +    for (size = 0,i = SIZE (message); i && ret; --i)
185.1171 +      if (((c = SNX (message)) != '\015') && (putc (c,df) == EOF)) ret = NIL;
185.1172 +				/* close the file */
185.1173 +    if (!ret || fclose (df)) {
185.1174 +      unlink (tmp);		/* delete message */
185.1175 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
185.1176 +      mm_log (tmp,ERROR);
185.1177 +      ret = NIL;
185.1178 +    }
185.1179 +    if (ret) {			/* set the date for this message */
185.1180 +      if (date) mh_setdate (tmp,&elt);
185.1181 +				/* get next message */
185.1182 +      if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
185.1183 +    }
185.1184 +  } while (ret && message);
185.1185 +  mm_nocritical (stream);	/* release critical */
185.1186 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
185.1187 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
185.1188 +	    WARN);
185.1189 +  return ret;
185.1190 +}
185.1191 +
185.1192 +/* Internal routines */
185.1193 +
185.1194 +
185.1195 +/* MH file name selection test
185.1196 + * Accepts: candidate directory entry
185.1197 + * Returns: T to use file name, NIL to skip it
185.1198 + */
185.1199 +
185.1200 +int mh_select (struct direct *name)
185.1201 +{
185.1202 +  char c;
185.1203 +  char *s = name->d_name;
185.1204 +  while (c = *s++) if (!isdigit (c)) return NIL;
185.1205 +  return T;
185.1206 +}
185.1207 +
185.1208 +
185.1209 +/* MH file name comparision
185.1210 + * Accepts: first candidate directory entry
185.1211 + *	    second candidate directory entry
185.1212 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
185.1213 + */
185.1214 +
185.1215 +int mh_numsort (const void *d1,const void *d2)
185.1216 +{
185.1217 +  return atoi ((*(struct direct **) d1)->d_name) -
185.1218 +    atoi ((*(struct direct **) d2)->d_name);
185.1219 +}
185.1220 +
185.1221 +
185.1222 +/* MH mail build file name
185.1223 + * Accepts: destination string
185.1224 + *          source
185.1225 + * Returns: destination
185.1226 + */
185.1227 +
185.1228 +char *mh_file (char *dst,char *name)
185.1229 +{
185.1230 +  char *s;
185.1231 +  char *path = mh_path (dst);
185.1232 +  if (!path) fatal ("No mh path in mh_file()!");
185.1233 +				/* INBOX becomes "inbox" in the MH path */
185.1234 +  if (!compare_cstring (name,MHINBOX) || !compare_cstring (name,"INBOX"))
185.1235 +    sprintf (dst,"%.900s/%.80s",path,MHINBOXDIR);
185.1236 +				/* #mh names skip past prefix */
185.1237 +  else if (*name == '#') sprintf (dst,"%.100s/%.900s",path,name + 4);
185.1238 +  else mailboxfile (dst,name);	/* all other names */
185.1239 +				/* tie off unnecessary trailing / */
185.1240 +  if ((s = strrchr (dst,'/')) && !s[1] && (s[-1] == '/')) *s = '\0';
185.1241 +  return dst;
185.1242 +}
185.1243 +
185.1244 +/* MH canonicalize name
185.1245 + * Accepts: buffer to write name
185.1246 + *	    reference
185.1247 + *	    pattern
185.1248 + * Returns: T if success, NIL if failure
185.1249 + */
185.1250 +
185.1251 +long mh_canonicalize (char *pattern,char *ref,char *pat)
185.1252 +{
185.1253 +  unsigned long i;
185.1254 +  char *s,tmp[MAILTMPLEN];
185.1255 +  if (ref && *ref) {		/* have a reference */
185.1256 +    strcpy (pattern,ref);	/* copy reference to pattern */
185.1257 +				/* # overrides mailbox field in reference */
185.1258 +    if (*pat == '#') strcpy (pattern,pat);
185.1259 +				/* pattern starts, reference ends, with / */
185.1260 +    else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
185.1261 +      strcat (pattern,pat + 1);	/* append, omitting one of the period */
185.1262 +    else strcat (pattern,pat);	/* anything else is just appended */
185.1263 +  }
185.1264 +  else strcpy (pattern,pat);	/* just have basic name */
185.1265 +  if (mh_isvalid (pattern,tmp,T)) {
185.1266 +				/* count wildcards */
185.1267 +    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
185.1268 +				/* success if not too many */
185.1269 +    if (i <= MAXWILDCARDS) return LONGT;
185.1270 +    mm_log ("Excessive wildcards in LIST/LSUB",ERROR);
185.1271 +  }
185.1272 +  return NIL;
185.1273 +}
185.1274 +
185.1275 +/* Set date for message
185.1276 + * Accepts: file name
185.1277 + *	    elt containing date
185.1278 + */
185.1279 +
185.1280 +void mh_setdate (char *file,MESSAGECACHE *elt)
185.1281 +{
185.1282 +  time_t tp[2];
185.1283 +  tp[0] = time (0);		/* atime is now */
185.1284 +  tp[1] = mail_longdate (elt);	/* modification time */
185.1285 +  utime (file,tp);		/* set the times */
185.1286 +}
   186.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   186.2 +++ b/src/osdep/amiga/mix.c	Mon Sep 14 15:17:45 2009 +0900
   186.3 @@ -0,0 +1,2834 @@
   186.4 +/* ========================================================================
   186.5 + * Copyright 1988-2008 University of Washington
   186.6 + *
   186.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   186.8 + * you may not use this file except in compliance with the License.
   186.9 + * You may obtain a copy of the License at
  186.10 + *
  186.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  186.12 + *
  186.13 + * 
  186.14 + * ========================================================================
  186.15 + */
  186.16 +
  186.17 +/*
  186.18 + * Program:	MIX mail routines
  186.19 + *
  186.20 + * Author(s):	Mark Crispin
  186.21 + *		UW Technology
  186.22 + *		University of Washington
  186.23 + *		Seattle, WA  98195
  186.24 + *		Internet: MRC@Washington.EDU
  186.25 + *
  186.26 + * Date:	1 March 2006
  186.27 + * Last Edited:	7 May 2008
  186.28 + */
  186.29 +
  186.30 +
  186.31 +#include <stdio.h>
  186.32 +#include <ctype.h>
  186.33 +#include <errno.h>
  186.34 +extern int errno;		/* just in case */
  186.35 +#include "mail.h"
  186.36 +#include "osdep.h"
  186.37 +#include <pwd.h>
  186.38 +#include <sys/stat.h>
  186.39 +#include <sys/time.h>
  186.40 +#include "misc.h"
  186.41 +#include "dummy.h"
  186.42 +#include "fdstring.h"
  186.43 +
  186.44 +/* MIX definitions */
  186.45 +
  186.46 +#define MEGABYTE (1024*1024)
  186.47 +
  186.48 +#define MIXDATAROLL MEGABYTE	/* size at which we roll to a new file */
  186.49 +
  186.50 +
  186.51 +/* MIX files */
  186.52 +
  186.53 +#define MIXNAME ".mix"		/* prefix for all MIX file names */
  186.54 +#define MIXMETA "meta"		/* suffix for metadata */
  186.55 +#define MIXINDEX "index"	/* suffix for index */
  186.56 +#define MIXSTATUS "status"	/* suffix for status */
  186.57 +#define MIXSORTCACHE "sortcache"/* suffix for sortcache */
  186.58 +#define METAMAX (MEGABYTE-1)	/* maximum metadata file size (sanity check) */
  186.59 +
  186.60 +
  186.61 +/* MIX file formats */
  186.62 +
  186.63 +				/* sequence format (all but msg files) */
  186.64 +#define SEQFMT "S%08lx\015\012"
  186.65 +				/* metadata file format */
  186.66 +#define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012"
  186.67 +				/* index file record format */
  186.68 +#define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012"
  186.69 +				/* status file record format */
  186.70 +#define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012"
  186.71 +				/* message file header format */
  186.72 +#define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012"
  186.73 +#define MSGTOK ":msg:"
  186.74 +#define MSGTSZ (sizeof(MSGTOK)-1)
  186.75 +				/* sortcache file record format */
  186.76 +#define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012"
  186.77 +
  186.78 +/* MIX I/O stream local data */
  186.79 +	
  186.80 +typedef struct mix_local {
  186.81 +  unsigned long curmsg;		/* current message file number */
  186.82 +  unsigned long newmsg;		/* current new message file number */
  186.83 +  time_t lastsnarf;		/* last snarf time */
  186.84 +  int msgfd;			/* file description of current msg file */
  186.85 +  int mfd;			/* file descriptor of open metadata */
  186.86 +  unsigned long metaseq;	/* metadata sequence */
  186.87 +  char *index;			/* mailbox index name */
  186.88 +  unsigned long indexseq;	/* index sequence */
  186.89 +  char *status;			/* mailbox status name */
  186.90 +  unsigned long statusseq;	/* status sequence */
  186.91 +  char *sortcache;		/* mailbox sortcache name */
  186.92 +  unsigned long sortcacheseq;	/* sortcache sequence */
  186.93 +  unsigned char *buf;		/* temporary buffer */
  186.94 +  unsigned long buflen;		/* current size of temporary buffer */
  186.95 +  unsigned int expok : 1;	/* non-zero if expunge reports OK */
  186.96 +  unsigned int internal : 1;	/* internally opened, do not validate */
  186.97 +} MIXLOCAL;
  186.98 +
  186.99 +
 186.100 +#define MIXBURP struct mix_burp
 186.101 +
 186.102 +MIXBURP {
 186.103 +  unsigned long fileno;		/* message file number */
 186.104 +  char *name;			/* message file name */
 186.105 +  SEARCHSET *tail;		/* tail of ranges */
 186.106 +  SEARCHSET set;		/* set of retained ranges */
 186.107 +  MIXBURP *next;		/* next file to burp */
 186.108 +};
 186.109 +
 186.110 +
 186.111 +/* Convenient access to local data */
 186.112 +
 186.113 +#define LOCAL ((MIXLOCAL *) stream->local)
 186.114 +
 186.115 +/* Function prototypes */
 186.116 +
 186.117 +DRIVER *mix_valid (char *name);
 186.118 +long mix_isvalid (char *name,char *meta);
 186.119 +void *mix_parameters (long function,void *value);
 186.120 +long mix_dirfmttest (char *name);
 186.121 +void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 186.122 +long mix_scan_contents (char *name,char *contents,unsigned long csiz,
 186.123 +			unsigned long fsiz);
 186.124 +void mix_list (MAILSTREAM *stream,char *ref,char *pat);
 186.125 +void mix_lsub (MAILSTREAM *stream,char *ref,char *pat);
 186.126 +long mix_subscribe (MAILSTREAM *stream,char *mailbox);
 186.127 +long mix_unsubscribe (MAILSTREAM *stream,char *mailbox);
 186.128 +long mix_create (MAILSTREAM *stream,char *mailbox);
 186.129 +long mix_delete (MAILSTREAM *stream,char *mailbox);
 186.130 +long mix_rename (MAILSTREAM *stream,char *old,char *newname);
 186.131 +int mix_rselect (struct direct *name);
 186.132 +MAILSTREAM *mix_open (MAILSTREAM *stream);
 186.133 +void mix_close (MAILSTREAM *stream,long options);
 186.134 +void mix_abort (MAILSTREAM *stream);
 186.135 +char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 186.136 +		  long flags);
 186.137 +long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 186.138 +void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 186.139 +unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 186.140 +			 SORTPGM *pgm,long flags);
 186.141 +THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
 186.142 +			SEARCHPGM *spg,long flags);
 186.143 +long mix_ping (MAILSTREAM *stream);
 186.144 +void mix_check (MAILSTREAM *stream);
 186.145 +long mix_expunge (MAILSTREAM *stream,char *sequence,long options);
 186.146 +int mix_select (struct direct *name);
 186.147 +int mix_msgfsort (const void *d1,const void *d2);
 186.148 +long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size);
 186.149 +long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed);
 186.150 +long mix_burp_check (SEARCHSET *set,size_t size,char *file);
 186.151 +long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
 186.152 +	       long options);
 186.153 +long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 186.154 +long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
 186.155 +		     STRING *msg,SEARCHSET *set,unsigned long seq);
 186.156 +
 186.157 +FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags);
 186.158 +char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq);
 186.159 +long mix_meta_update (MAILSTREAM *stream);
 186.160 +long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag);
 186.161 +long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag);
 186.162 +FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
 186.163 +		     unsigned long newsize);
 186.164 +FILE *mix_sortcache_open (MAILSTREAM *stream);
 186.165 +long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache);
 186.166 +char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type);
 186.167 +unsigned long mix_read_sequence (FILE *f);
 186.168 +char *mix_dir (char *dst,char *name);
 186.169 +char *mix_file (char *dst,char *dir,char *name);
 186.170 +char *mix_file_data (char *dst,char *dir,unsigned long data);
 186.171 +unsigned long mix_modseq (unsigned long oldseq);
 186.172 +
 186.173 +/* MIX mail routines */
 186.174 +
 186.175 +
 186.176 +/* Driver dispatch used by MAIL */
 186.177 +
 186.178 +DRIVER mixdriver = {
 186.179 +  "mix",			/* driver name */
 186.180 +				/* driver flags */
 186.181 +  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ,
 186.182 +  (DRIVER *) NIL,		/* next driver */
 186.183 +  mix_valid,			/* mailbox is valid for us */
 186.184 +  mix_parameters,		/* manipulate parameters */
 186.185 +  mix_scan,			/* scan mailboxes */
 186.186 +  mix_list,			/* find mailboxes */
 186.187 +  mix_lsub,			/* find subscribed mailboxes */
 186.188 +  mix_subscribe,		/* subscribe to mailbox */
 186.189 +  mix_unsubscribe,		/* unsubscribe from mailbox */
 186.190 +  mix_create,			/* create mailbox */
 186.191 +  mix_delete,			/* delete mailbox */
 186.192 +  mix_rename,			/* rename mailbox */
 186.193 +  mail_status_default,		/* status of mailbox */
 186.194 +  mix_open,			/* open mailbox */
 186.195 +  mix_close,			/* close mailbox */
 186.196 +  NIL,				/* fetch message "fast" attributes */
 186.197 +  NIL,				/* fetch message flags */
 186.198 +  NIL,				/* fetch overview */
 186.199 +  NIL,				/* fetch message envelopes */
 186.200 +  mix_header,			/* fetch message header only */
 186.201 +  mix_text,			/* fetch message body only */
 186.202 +  NIL,				/* fetch partial message test */
 186.203 +  NIL,				/* unique identifier */
 186.204 +  NIL,				/* message number */
 186.205 +  mix_flag,			/* modify flags */
 186.206 +  NIL,				/* per-message modify flags */
 186.207 +  NIL,				/* search for message based on criteria */
 186.208 +  mix_sort,			/* sort messages */
 186.209 +  mix_thread,			/* thread messages */
 186.210 +  mix_ping,			/* ping mailbox to see if still alive */
 186.211 +  mix_check,			/* check for new messages */
 186.212 +  mix_expunge,			/* expunge deleted messages */
 186.213 +  mix_copy,			/* copy messages to another mailbox */
 186.214 +  mix_append,			/* append string message to mailbox */
 186.215 +  NIL				/* garbage collect stream */
 186.216 +};
 186.217 +
 186.218 +				/* prototype stream */
 186.219 +MAILSTREAM mixproto = {&mixdriver};
 186.220 +
 186.221 +/* MIX mail validate mailbox
 186.222 + * Accepts: mailbox name
 186.223 + * Returns: our driver if name is valid, NIL otherwise
 186.224 + */
 186.225 +
 186.226 +DRIVER *mix_valid (char *name)
 186.227 +{
 186.228 +  char tmp[MAILTMPLEN];
 186.229 +  return mix_isvalid (name,tmp) ? &mixdriver : NIL;
 186.230 +}
 186.231 +
 186.232 +
 186.233 +/* MIX mail test for valid mailbox
 186.234 + * Accepts: mailbox name
 186.235 + *	    buffer to return meta name
 186.236 + * Returns: T if valid, NIL otherwise, metadata name written in both cases
 186.237 + */
 186.238 +
 186.239 +long mix_isvalid (char *name,char *meta)
 186.240 +{
 186.241 +  char dir[MAILTMPLEN];
 186.242 +  struct stat sbuf;
 186.243 +				/* validate name as directory */
 186.244 +  if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) &&
 186.245 +      *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) &&
 186.246 +      !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
 186.247 +				/* name is directory; is it mix? */
 186.248 +    if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
 186.249 +      return LONGT;
 186.250 +    else errno = NIL;		/* directory but not mix */
 186.251 +  }
 186.252 +  return NIL;
 186.253 +}
 186.254 +
 186.255 +/* MIX manipulate driver parameters
 186.256 + * Accepts: function code
 186.257 + *	    function-dependent value
 186.258 + * Returns: function-dependent return value
 186.259 + */
 186.260 +
 186.261 +void *mix_parameters (long function,void *value)
 186.262 +{
 186.263 +  void *ret = NIL;
 186.264 +  switch ((int) function) {
 186.265 +  case GET_INBOXPATH:
 186.266 +    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
 186.267 +    break;
 186.268 +  case GET_DIRFMTTEST:
 186.269 +    ret = (void *) mix_dirfmttest;
 186.270 +    break;
 186.271 +  case GET_SCANCONTENTS:
 186.272 +    ret = (void *) mix_scan_contents;
 186.273 +    break;
 186.274 +  case SET_ONETIMEEXPUNGEATPING:
 186.275 +    if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
 186.276 +  case GET_ONETIMEEXPUNGEATPING:
 186.277 +    if (value) ret = (void *)
 186.278 +      (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
 186.279 +    break;
 186.280 +  }
 186.281 +  return ret;
 186.282 +}
 186.283 +
 186.284 +
 186.285 +/* MIX test for directory format internal node
 186.286 + * Accepts: candidate node name
 186.287 + * Returns: T if internal name, NIL otherwise
 186.288 + */
 186.289 +
 186.290 +long mix_dirfmttest (char *name)
 186.291 +{
 186.292 +				/* belongs to MIX if starts with .mix */
 186.293 +  return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT;
 186.294 +}
 186.295 +
 186.296 +/* MIX mail scan mailboxes
 186.297 + * Accepts: mail stream
 186.298 + *	    reference
 186.299 + *	    pattern to search
 186.300 + *	    string to scan
 186.301 + */
 186.302 +
 186.303 +void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 186.304 +{
 186.305 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 186.306 +}
 186.307 +
 186.308 +
 186.309 +/* MIX scan mailbox for contents
 186.310 + * Accepts: mailbox name
 186.311 + *	    desired contents
 186.312 + *	    contents size
 186.313 + *	    file size (ignored)
 186.314 + * Returns: NIL if contents not found, T if found
 186.315 + */
 186.316 +
 186.317 +long mix_scan_contents (char *name,char *contents,unsigned long csiz,
 186.318 +			unsigned long fsiz)
 186.319 +{
 186.320 +  long i,nfiles;
 186.321 +  void *a;
 186.322 +  char *s;
 186.323 +  long ret = NIL;
 186.324 +  size_t namelen = strlen (name);
 186.325 +  struct stat sbuf;
 186.326 +  struct direct **names = NIL;
 186.327 +  if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0)
 186.328 +    for (i = 0; i < nfiles; ++i) {
 186.329 +      if (!ret) {
 186.330 +	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
 186.331 +		 "%s/%s",name,names[i]->d_name);
 186.332 +	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
 186.333 +	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
 186.334 +	fs_give ((void **) &s);
 186.335 +      }
 186.336 +      fs_give ((void **) &names[i]);
 186.337 +    }
 186.338 +				/* free directory list */
 186.339 +  if (a = (void *) names) fs_give ((void **) &a);
 186.340 +  return ret;
 186.341 +}
 186.342 +
 186.343 +/* MIX list mailboxes
 186.344 + * Accepts: mail stream
 186.345 + *	    reference
 186.346 + *	    pattern to search
 186.347 + */
 186.348 +
 186.349 +void mix_list (MAILSTREAM *stream,char *ref,char *pat)
 186.350 +{
 186.351 +  if (stream) dummy_list (NIL,ref,pat);
 186.352 +}
 186.353 +
 186.354 +
 186.355 +/* MIX list subscribed mailboxes
 186.356 + * Accepts: mail stream
 186.357 + *	    reference
 186.358 + *	    pattern to search
 186.359 + */
 186.360 +
 186.361 +void mix_lsub (MAILSTREAM *stream,char *ref,char *pat)
 186.362 +{
 186.363 +  if (stream) dummy_lsub (NIL,ref,pat);
 186.364 +}
 186.365 +
 186.366 +/* MIX mail subscribe to mailbox
 186.367 + * Accepts: mail stream
 186.368 + *	    mailbox to add to subscription list
 186.369 + * Returns: T on success, NIL on failure
 186.370 + */
 186.371 +
 186.372 +long mix_subscribe (MAILSTREAM *stream,char *mailbox)
 186.373 +{
 186.374 +  return sm_subscribe (mailbox);
 186.375 +}
 186.376 +
 186.377 +
 186.378 +/* MIX mail unsubscribe to mailbox
 186.379 + * Accepts: mail stream
 186.380 + *	    mailbox to delete from subscription list
 186.381 + * Returns: T on success, NIL on failure
 186.382 + */
 186.383 +
 186.384 +long mix_unsubscribe (MAILSTREAM *stream,char *mailbox)
 186.385 +{
 186.386 +  return sm_unsubscribe (mailbox);
 186.387 +}
 186.388 +
 186.389 +/* MIX mail create mailbox
 186.390 + * Accepts: mail stream
 186.391 + *	    mailbox name to create
 186.392 + * Returns: T on success, NIL on failure
 186.393 + */
 186.394 +
 186.395 +long mix_create (MAILSTREAM *stream,char *mailbox)
 186.396 +{
 186.397 +  DRIVER *test;
 186.398 +  FILE *f;
 186.399 +  int c,i;
 186.400 +  char *t,tmp[MAILTMPLEN],file[MAILTMPLEN];
 186.401 +  char *s = strrchr (mailbox,'/');
 186.402 +  unsigned long now = time (NIL);
 186.403 +  long ret = NIL;
 186.404 +				/* always create \NoSelect if trailing /  */
 186.405 +  if (s && !s[1]) return dummy_create (stream,mailbox);
 186.406 +				/* validate name */
 186.407 +  if (mix_dirfmttest (s ? s + 1 : mailbox))
 186.408 +    sprintf(tmp,"Can't create mailbox %.80s: invalid MIX-format name",mailbox);
 186.409 +				/* must not already exist */
 186.410 +  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
 186.411 +	   strcmp (test->name,"dummy"))
 186.412 +    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
 186.413 +				/* create directory and metadata */
 186.414 +  else if (!dummy_create_path (stream,
 186.415 +			       mix_file (file,mix_dir (tmp,mailbox),MIXMETA),
 186.416 +			       get_dir_protection (mailbox)))
 186.417 +    sprintf (tmp,"Can't create mailbox %.80s: %.80s",mailbox,strerror (errno));
 186.418 +  else if (!(f = fopen (file,"w")))
 186.419 +    sprintf (tmp,"Can't re-open metadata %.80s: %.80s",mailbox,
 186.420 +	     strerror (errno));
 186.421 +  else {			/* success, write initial metadata */
 186.422 +    fprintf (f,SEQFMT,now);
 186.423 +    fprintf (f,MTAFMT,now,0,now);
 186.424 +    for (i = 0, c = 'K'; (i < NUSERFLAGS) &&
 186.425 +	   (t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
 186.426 +	    default_user_flag (i)) && *t; ++i) {
 186.427 +      putc (c,f);		/* write another keyword */
 186.428 +      fputs (t,f);
 186.429 +      c = ' ';			/* delimiter is now space */
 186.430 +    }
 186.431 +    fclose (f);
 186.432 +    set_mbx_protections (mailbox,file);
 186.433 +				/* point to suffix */
 186.434 +    s = file + strlen (file) - (sizeof (MIXMETA) - 1);
 186.435 +    strcpy (s,MIXINDEX);	/* create index */
 186.436 +    if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
 186.437 +      sprintf (tmp,"Can't create mix mailbox index: %.80s",strerror (errno));
 186.438 +    else {
 186.439 +      set_mbx_protections (mailbox,file);
 186.440 +      strcpy (s,MIXSTATUS);	/* create status */
 186.441 +      if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
 186.442 +	sprintf (tmp,"Can't create mix mailbox status: %.80s",
 186.443 +		 strerror (errno));
 186.444 +      else {
 186.445 +	set_mbx_protections (mailbox,file);
 186.446 +	sprintf (s,"%08lx",now);/* message file */
 186.447 +	if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
 186.448 +	  sprintf (tmp,"Can't create mix mailbox data: %.80s",
 186.449 +		   strerror (errno));
 186.450 +	else {
 186.451 +	  set_mbx_protections (mailbox,file);
 186.452 +	  ret = LONGT;	/* declare success at this point */
 186.453 +	}
 186.454 +      }
 186.455 +    }
 186.456 +  }
 186.457 +  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
 186.458 +  return ret;
 186.459 +}
 186.460 +
 186.461 +/* MIX mail delete mailbox
 186.462 + *	    mailbox name to delete
 186.463 + * Returns: T on success, NIL on failure
 186.464 + */
 186.465 +
 186.466 +long mix_delete (MAILSTREAM *stream,char *mailbox)
 186.467 +{
 186.468 +  DIR *dirp;
 186.469 +  struct direct *d;
 186.470 +  int fd = -1;
 186.471 +  char *s,tmp[MAILTMPLEN];
 186.472 +  if (!mix_isvalid (mailbox,tmp))
 186.473 +    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
 186.474 +  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
 186.475 +    sprintf (tmp,"Can't lock mailbox for delete: %.80s",mailbox);
 186.476 +				/* delete metadata */
 186.477 +  else if (unlink (tmp)) sprintf (tmp,"Can't delete mailbox %.80s index: %80s",
 186.478 +				  mailbox,strerror (errno));
 186.479 +  else {
 186.480 +    close (fd);			/* close descriptor on deleted metadata */
 186.481 +				/* get directory name */
 186.482 +    *(s = strrchr (tmp,'/')) = '\0';
 186.483 +    if (dirp = opendir (tmp)) {	/* open directory */
 186.484 +      *s++ = '/';		/* restore delimiter */
 186.485 +				/* massacre messages */
 186.486 +      while (d = readdir (dirp)) if (mix_dirfmttest (d->d_name)) {
 186.487 +	strcpy (s,d->d_name);	/* make path */
 186.488 +	unlink (tmp);		/* sayonara */
 186.489 +      }
 186.490 +      closedir (dirp);		/* flush directory */
 186.491 +      *(s = strrchr (tmp,'/')) = '\0';
 186.492 +      if (rmdir (tmp)) {	/* try to remove the directory */
 186.493 +	sprintf (tmp,"Can't delete name %.80s: %.80s",
 186.494 +		 mailbox,strerror (errno));
 186.495 +	MM_LOG (tmp,WARN);
 186.496 +      }
 186.497 +    }
 186.498 +    return T;			/* always success */
 186.499 +  }
 186.500 +  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
 186.501 +  MM_LOG (tmp,ERROR);		/* something failed */
 186.502 +  return NIL;
 186.503 +}
 186.504 +
 186.505 +/* MIX mail rename mailbox
 186.506 + * Accepts: MIX mail stream
 186.507 + *	    old mailbox name
 186.508 + *	    new mailbox name
 186.509 + * Returns: T on success, NIL on failure
 186.510 + */
 186.511 +
 186.512 +long mix_rename (MAILSTREAM *stream,char *old,char *newname)
 186.513 +{
 186.514 +  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
 186.515 +  struct stat sbuf;
 186.516 +  int fd = -1;
 186.517 +  if (!mix_isvalid (old,tmp))
 186.518 +    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
 186.519 +  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
 186.520 +    sprintf (tmp,"Can't lock mailbox for rename: %.80s",old);
 186.521 +  else if (mix_dirfmttest ((s = strrchr (newname,'/')) ? s + 1 : newname))
 186.522 +    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MIX-format name",
 186.523 +	     newname);
 186.524 +				/* new mailbox name must not be valid */
 186.525 +  else if (mix_isvalid (newname,tmp))
 186.526 +    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
 186.527 +	     newname);
 186.528 +  else {
 186.529 +    mix_dir (tmp,old);		/* build old directory name */
 186.530 +    mix_dir (tmp1,newname);	/* and new directory name */
 186.531 +				/* easy if not INBOX */
 186.532 +    if (compare_cstring (old,"INBOX")) {
 186.533 +				/* found superior to destination name? */
 186.534 +      if (s = strrchr (tmp1,'/')) {
 186.535 +	c = *++s;		/* remember first character of inferior */
 186.536 +	*s = '\0';		/* tie off to get just superior */
 186.537 +				/* name doesn't exist, create it */
 186.538 +	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 186.539 +	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
 186.540 +	  return NIL;
 186.541 +	*s = c;			/* restore full name */
 186.542 +      }
 186.543 +      if (!rename (tmp,tmp1)) {
 186.544 +	close (fd);		/* close descriptor on metadata */
 186.545 +	return LONGT;
 186.546 +      }
 186.547 +    }
 186.548 +
 186.549 +				/* RFC 3501 requires this */
 186.550 +    else if (dummy_create_path (stream,strcat (tmp1,"/"),
 186.551 +				get_dir_protection (newname))) {
 186.552 +      void *a;
 186.553 +      int i,n,lasterror;
 186.554 +      char *src,*dst;
 186.555 +      struct direct **names = NIL;
 186.556 +      size_t srcl = strlen (tmp);
 186.557 +      size_t dstl = strlen (tmp1);
 186.558 +				/* rename each mix file to new directory */
 186.559 +      for (i = lasterror = 0,n = scandir (tmp,&names,mix_rselect,alphasort);
 186.560 +	   i < n; ++i) {
 186.561 +	size_t len = strlen (names[i]->d_name);
 186.562 +	sprintf (src = (char *) fs_get (srcl + len + 2),"%s/%s",
 186.563 +		 tmp,names[i]->d_name);
 186.564 +	sprintf (dst = (char *) fs_get (dstl + len + 1),"%s%s",
 186.565 +		 tmp1,names[i]->d_name);
 186.566 +	if (rename (src,dst)) lasterror = errno;
 186.567 +	fs_give ((void **) &src);
 186.568 +	fs_give ((void **) &dst);
 186.569 +	fs_give ((void **) &names[i]);
 186.570 +      }
 186.571 +				/* free directory list */
 186.572 +      if (a = (void *) names) fs_give ((void **) &a);
 186.573 +      if (lasterror) errno = lasterror;
 186.574 +      else {
 186.575 +	close (fd);		/* close descriptor on metadata */
 186.576 +	return mix_create (NIL,"INBOX");
 186.577 +      }
 186.578 +    }
 186.579 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",
 186.580 +	     old,newname,strerror (errno));
 186.581 +  }
 186.582 +  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
 186.583 +  MM_LOG (tmp,ERROR);		/* something failed */
 186.584 +  return NIL;
 186.585 +}
 186.586 +
 186.587 +
 186.588 +/* MIX test for mix name
 186.589 + * Accepts: candidate directory name
 186.590 + * Returns: T if mix file name, NIL otherwise
 186.591 + */
 186.592 +
 186.593 +int mix_rselect (struct direct *name)
 186.594 +{
 186.595 +  return mix_dirfmttest (name->d_name);
 186.596 +}
 186.597 +
 186.598 +/* MIX mail open
 186.599 + * Accepts: stream to open
 186.600 + * Returns: stream on success, NIL on failure
 186.601 + */
 186.602 +
 186.603 +MAILSTREAM *mix_open (MAILSTREAM *stream)
 186.604 +{
 186.605 +  short silent;
 186.606 +				/* return prototype for OP_PROTOTYPE call */
 186.607 +  if (!stream) return user_flags (&mixproto);
 186.608 +  if (stream->local) fatal ("mix recycle stream");
 186.609 +  stream->local = memset (fs_get (sizeof (MIXLOCAL)),0,sizeof (MIXLOCAL));
 186.610 +				/* note if an INBOX or not */
 186.611 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 186.612 +				/* make temporary buffer */
 186.613 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 186.614 +  LOCAL->buflen = CHUNKSIZE - 1;
 186.615 +				/* set stream->mailbox to be directory name */
 186.616 +  mix_dir (LOCAL->buf,stream->mailbox);
 186.617 +  fs_give ((void **) &stream->mailbox);
 186.618 +  stream->mailbox = cpystr (LOCAL->buf);
 186.619 +  LOCAL->msgfd = -1;		/* currently no file open */
 186.620 +  if (!(((!stream->rdonly &&	/* open metadata file */
 186.621 +	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
 186.622 +			       O_RDWR,NIL)) >= 0)) ||
 186.623 +	 ((stream->rdonly = T) &&
 186.624 +	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
 186.625 +			       O_RDONLY,NIL)) >= 0))) &&
 186.626 +	!flock (LOCAL->mfd,LOCK_SH))) {
 186.627 +    MM_LOG ("Error opening mix metadata file",ERROR);
 186.628 +    mix_abort (stream);
 186.629 +    stream = NIL;		/* open fails */
 186.630 +  }
 186.631 +  else {			/* metadata open, complete open */
 186.632 +    LOCAL->index = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXINDEX));
 186.633 +    LOCAL->status = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXSTATUS));
 186.634 +    LOCAL->sortcache = cpystr (mix_file (LOCAL->buf,stream->mailbox,
 186.635 +					 MIXSORTCACHE));
 186.636 +    stream->sequence++;		/* bump sequence number */
 186.637 +				/* parse mailbox */
 186.638 +    stream->nmsgs = stream->recent = 0;
 186.639 +    if (silent = stream->silent) LOCAL->internal = T;
 186.640 +    stream->silent = T;
 186.641 +    if (mix_ping (stream)) {	/* do initial ping */
 186.642 +				/* try burping in case we are exclusive */
 186.643 +      if (!stream->rdonly) mix_expunge (stream,"",NIL);
 186.644 +      if (!(stream->nmsgs || stream->silent))
 186.645 +	MM_LOG ("Mailbox is empty",(long) NIL);
 186.646 +      stream->silent = silent;	/* now notify upper level */
 186.647 +      mail_exists (stream,stream->nmsgs);
 186.648 +      stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 186.649 +	stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 186.650 +      stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 186.651 +      stream->kwd_create =	/* can we create new user flags? */
 186.652 +	(stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T;
 186.653 +    }
 186.654 +    else {			/* got murdelyzed in ping */
 186.655 +      mix_abort (stream);
 186.656 +      stream = NIL;
 186.657 +    }
 186.658 +  }
 186.659 +  return stream;		/* return stream to caller */
 186.660 +}
 186.661 +
 186.662 +/* MIX mail close
 186.663 + * Accepts: MAIL stream
 186.664 + *	    close options
 186.665 + */
 186.666 +
 186.667 +void mix_close (MAILSTREAM *stream,long options)
 186.668 +{
 186.669 +  if (LOCAL) {			/* only if a file is open */
 186.670 +    int silent = stream->silent;
 186.671 +    stream->silent = T;		/* note this stream is dying */
 186.672 +				/* burp-only or expunge */
 186.673 +    mix_expunge (stream,(options & CL_EXPUNGE) ? NIL : "",NIL);
 186.674 +    mix_abort (stream);
 186.675 +    stream->silent = silent;	/* reset silent state */
 186.676 +  }
 186.677 +}
 186.678 +
 186.679 +
 186.680 +/* MIX mail abort stream
 186.681 + * Accepts: MAIL stream
 186.682 + */
 186.683 +
 186.684 +void mix_abort (MAILSTREAM *stream)
 186.685 +{
 186.686 +  if (LOCAL) {			/* only if a file is open */
 186.687 +				/* close current message file if open */
 186.688 +    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
 186.689 +				/* close current metadata file if open */
 186.690 +    if (LOCAL->mfd >= 0) close (LOCAL->mfd);
 186.691 +    if (LOCAL->index) fs_give ((void **) &LOCAL->index);
 186.692 +    if (LOCAL->status) fs_give ((void **) &LOCAL->status);
 186.693 +    if (LOCAL->sortcache) fs_give ((void **) &LOCAL->sortcache);
 186.694 +				/* free local scratch buffer */
 186.695 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 186.696 +				/* nuke the local data */
 186.697 +    fs_give ((void **) &stream->local);
 186.698 +    stream->dtb = NIL;		/* log out the DTB */
 186.699 +  }
 186.700 +}
 186.701 +
 186.702 +/* MIX mail fetch message header
 186.703 + * Accepts: MAIL stream
 186.704 + *	    message # to fetch
 186.705 + *	    pointer to returned header text length
 186.706 + *	    option flags
 186.707 + * Returns: message header in RFC822 format
 186.708 + */
 186.709 +
 186.710 +char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 186.711 +		  long flags)
 186.712 +{
 186.713 +  unsigned long i,j,k;
 186.714 +  int fd;
 186.715 +  char *s,tmp[MAILTMPLEN];
 186.716 +  MESSAGECACHE *elt;
 186.717 +  if (length) *length = 0;	/* default return */
 186.718 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 186.719 +  elt = mail_elt (stream,msgno);/* get elt */
 186.720 +				/* is message in current message file? */
 186.721 +  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
 186.722 +    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
 186.723 +    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
 186.724 +					     elt->private.spare.data),
 186.725 +					     O_RDONLY,NIL)) < 0) return "";
 186.726 +				/* got file */
 186.727 +    LOCAL->curmsg = elt->private.spare.data;
 186.728 +  }    
 186.729 +  lseek (LOCAL->msgfd,elt->private.special.offset,L_SET);
 186.730 +				/* size of special data and header */
 186.731 +  j = elt->private.msg.header.offset + elt->private.msg.header.text.size;
 186.732 +  if (j > LOCAL->buflen) {	/* is buffer big enough? */
 186.733 +				/* no, make one that is */
 186.734 +    fs_give ((void **) &LOCAL->buf);
 186.735 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = j) + 1);
 186.736 +  }
 186.737 +  /* Maybe someday validate internaldate too */
 186.738 +				/* slurp special data + header, validate */
 186.739 +  if ((read (LOCAL->msgfd,LOCAL->buf,j) == j) &&
 186.740 +      !strncmp (LOCAL->buf,MSGTOK,MSGTSZ) &&
 186.741 +      (elt->private.uid == strtoul ((char *) LOCAL->buf + MSGTSZ,&s,16)) &&
 186.742 +      (*s++ == ':') && (s = strchr (s,':')) &&
 186.743 +      (k = strtoul (s+1,&s,16)) && (*s++ == ':') &&
 186.744 +      (s < (char *) (LOCAL->buf + elt->private.msg.header.offset))) {
 186.745 +				/* won, set offset and size of message */
 186.746 +    i = elt->private.msg.header.offset;
 186.747 +    *length = elt->private.msg.header.text.size;
 186.748 +    if (k != elt->rfc822_size) {
 186.749 +      sprintf (tmp,"Inconsistency in mix message size, uid=%lx (%lu != %lu)",
 186.750 +	       elt->private.uid,elt->rfc822_size,k);
 186.751 +      MM_LOG (tmp,WARN);
 186.752 +    }
 186.753 +  }
 186.754 +  else {			/* document the problem */
 186.755 +    LOCAL->buf[100] = '\0';	/* tie off buffer at no more than 100 octets */
 186.756 +				/* or at newline, whichever is first */
 186.757 +    if (s = strpbrk (LOCAL->buf,"\015\012")) *s = '\0';
 186.758 +    sprintf (tmp,"Error reading mix message header, uid=%lx, s=%.0lx, h=%s",
 186.759 +	     elt->private.uid,elt->rfc822_size,LOCAL->buf);
 186.760 +    MM_LOG (tmp,ERROR);
 186.761 +    *length = i = j = 0;	/* default to empty */
 186.762 +  }
 186.763 +  LOCAL->buf[j] = '\0';		/* tie off buffer at the end */
 186.764 +  return (char *) LOCAL->buf + i;
 186.765 +}
 186.766 +
 186.767 +/* MIX mail fetch message text (body only)
 186.768 + * Accepts: MAIL stream
 186.769 + *	    message # to fetch
 186.770 + *	    pointer to returned stringstruct
 186.771 + *	    option flags
 186.772 + * Returns: T on success, NIL on failure
 186.773 + */
 186.774 +
 186.775 +long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 186.776 +{
 186.777 +  unsigned long i;
 186.778 +  FDDATA d;
 186.779 +  MESSAGECACHE *elt;
 186.780 +				/* UID call "impossible" */
 186.781 +  if (flags & FT_UID) return NIL;
 186.782 +  elt = mail_elt (stream,msgno);
 186.783 +				/* is message in current message file? */
 186.784 +  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
 186.785 +    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
 186.786 +    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
 186.787 +					     elt->private.spare.data),
 186.788 +					     O_RDONLY,NIL)) < 0) return NIL;
 186.789 +				/* got file */
 186.790 +    LOCAL->curmsg = elt->private.spare.data;
 186.791 +  }    
 186.792 +				/* doing non-peek fetch? */
 186.793 +  if (!(flags & FT_PEEK) && !elt->seen) {
 186.794 +    FILE *idxf;			/* yes, process metadata/index/status */
 186.795 +    FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
 186.796 +    elt->seen = T;		/* mark as seen */
 186.797 +    MM_FLAGS (stream,elt->msgno);
 186.798 +				/* update status file if possible */
 186.799 +    if (statf && !stream->rdonly) {
 186.800 +      elt->private.mod = LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
 186.801 +      mix_status_update (stream,statf,NIL);
 186.802 +    }
 186.803 +    if (idxf) fclose (idxf);	/* release index and status file */
 186.804 +    if (statf) fclose (statf);
 186.805 +  } 
 186.806 +  d.fd = LOCAL->msgfd;		/* set up file descriptor */
 186.807 +				/* offset of message text */
 186.808 +  d.pos = elt->private.special.offset + elt->private.msg.header.offset +
 186.809 +    elt->private.msg.header.text.size;
 186.810 +  d.chunk = LOCAL->buf;		/* initial buffer chunk */
 186.811 +  d.chunksize = CHUNKSIZE;	/* chunk size */
 186.812 +  INIT (bs,fd_string,&d,elt->rfc822_size - elt->private.msg.header.text.size);
 186.813 +  return T;
 186.814 +}
 186.815 +
 186.816 +/* MIX mail modify flags
 186.817 + * Accepts: MAIL stream
 186.818 + *	    sequence
 186.819 + *	    flag(s)
 186.820 + *	    option flags
 186.821 + */
 186.822 +
 186.823 +void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 186.824 +{
 186.825 +  MESSAGECACHE *elt;
 186.826 +  unsigned long i,uf,ffkey;
 186.827 +  long f;
 186.828 +  short nf;
 186.829 +  FILE *idxf;
 186.830 +  FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
 186.831 +  unsigned long seq = mix_modseq (LOCAL->statusseq);
 186.832 +				/* find first free key */
 186.833 +  for (ffkey = 0; (ffkey < NUSERFLAGS) && stream->user_flags[ffkey]; ++ffkey);
 186.834 +				/* parse sequence and flags */
 186.835 +  if (((flags & ST_UID) ? mail_uid_sequence (stream,sequence) :
 186.836 +       mail_sequence (stream,sequence)) &&
 186.837 +      ((f = mail_parse_flags (stream,flag,&uf)) || uf)) {
 186.838 +				/* alter flags */
 186.839 +    for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++)
 186.840 +      if ((elt = mail_elt (stream,i))->sequence) {
 186.841 +	struct {		/* old flags */
 186.842 +	  unsigned int seen : 1;
 186.843 +	  unsigned int deleted : 1;
 186.844 +	  unsigned int flagged : 1;
 186.845 +	  unsigned int answered : 1;
 186.846 +	  unsigned int draft : 1;
 186.847 +	  unsigned long user_flags;
 186.848 +	} old;
 186.849 +	old.seen = elt->seen; old.deleted = elt->deleted;
 186.850 +	old.flagged = elt->flagged; old.answered = elt->answered;
 186.851 +	old.draft = elt->draft; old.user_flags = elt->user_flags;
 186.852 +	if (f&fSEEN) elt->seen = nf;
 186.853 +	if (f&fDELETED) elt->deleted = nf;
 186.854 +	if (f&fFLAGGED) elt->flagged = nf;
 186.855 +	if (f&fANSWERED) elt->answered = nf;
 186.856 +	if (f&fDRAFT) elt->draft = nf;
 186.857 +				/* user flags */
 186.858 +	if (flags & ST_SET) elt->user_flags |= uf;
 186.859 +	else elt->user_flags &= ~uf;
 186.860 +	if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
 186.861 +	    (old.flagged != elt->flagged) ||
 186.862 +	    (old.answered != elt->answered) || (old.draft != elt->draft) ||
 186.863 +	    (old.user_flags != elt->user_flags)) {
 186.864 +	  if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
 186.865 +	  MM_FLAGS (stream,elt->msgno);
 186.866 +	}
 186.867 +      }
 186.868 +				/* update status file after change */
 186.869 +    if (statf && (seq == LOCAL->statusseq))
 186.870 +      mix_status_update (stream,statf,NIL);
 186.871 +				/* update metadata if created a keyword */
 186.872 +    if ((ffkey < NUSERFLAGS) && stream->user_flags[ffkey] &&
 186.873 +	!mix_meta_update (stream))
 186.874 +      MM_LOG ("Error updating mix metadata after keyword creation",ERROR);
 186.875 +  }
 186.876 +  if (statf) fclose (statf);	/* release status file if still open */
 186.877 +  if (idxf) fclose (idxf);	/* release index file */
 186.878 +}
 186.879 +
 186.880 +/* MIX mail sort messages
 186.881 + * Accepts: mail stream
 186.882 + *	    character set
 186.883 + *	    search program
 186.884 + *	    sort program
 186.885 + *	    option flags
 186.886 + * Returns: vector of sorted message sequences or NIL if error
 186.887 + */
 186.888 +
 186.889 +unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 186.890 +			 SORTPGM *pgm,long flags)
 186.891 +{
 186.892 +  unsigned long *ret;
 186.893 +  FILE *sortcache = mix_sortcache_open (stream);
 186.894 +  ret = mail_sort_msgs (stream,charset,spg,pgm,flags);
 186.895 +  mix_sortcache_update (stream,&sortcache);
 186.896 +  return ret;
 186.897 +}
 186.898 +
 186.899 +
 186.900 +/* MIX mail thread messages
 186.901 + * Accepts: mail stream
 186.902 + *	    thread type
 186.903 + *	    character set
 186.904 + *	    search program
 186.905 + *	    option flags
 186.906 + * Returns: thread node tree or NIL if error
 186.907 + */
 186.908 +
 186.909 +THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
 186.910 +			SEARCHPGM *spg,long flags)
 186.911 +{
 186.912 +  THREADNODE *ret;
 186.913 +  FILE *sortcache = mix_sortcache_open (stream);
 186.914 +  ret = mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs);
 186.915 +  mix_sortcache_update (stream,&sortcache);
 186.916 +  return ret;
 186.917 +}
 186.918 +
 186.919 +/* MIX mail ping mailbox
 186.920 + * Accepts: MAIL stream
 186.921 + * Returns: T if stream alive, else NIL
 186.922 + */
 186.923 +
 186.924 +static int snarfing = 0;	/* lock against recursive snarfing */
 186.925 +
 186.926 +long mix_ping (MAILSTREAM *stream)
 186.927 +{
 186.928 +  FILE *idxf,*statf;
 186.929 +  struct stat sbuf;
 186.930 +  STRING msg;
 186.931 +  MESSAGECACHE *elt;
 186.932 +  int mfd,ifd,sfd;
 186.933 +  unsigned long i,msglen;
 186.934 +  char *message,date[MAILTMPLEN],flags[MAILTMPLEN];
 186.935 +  MAILSTREAM *sysibx = NIL;
 186.936 +  long ret = NIL;
 186.937 +  long snarfok = LONGT;
 186.938 +				/* time to snarf? */
 186.939 +  if (stream->inbox && !stream->rdonly && !snarfing &&
 186.940 +      (time (0) >= (LOCAL->lastsnarf +
 186.941 +		    (time_t) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
 186.942 +    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
 186.943 +    copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 186.944 +    MM_CRITICAL (stream);	/* go critical */
 186.945 +    snarfing = T;		/* don't recursively snarf */
 186.946 +				/* disable APPENDUID/COPYUID callbacks */
 186.947 +    mail_parameters (NIL,SET_APPENDUID,NIL);
 186.948 +    mail_parameters (NIL,SET_COPYUID,NIL);
 186.949 +				/* sizes match and anything in sysinbox? */
 186.950 +    if (!stat (sysinbox (),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
 186.951 +	sbuf.st_size &&	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 186.952 +	!sysibx->rdonly && sysibx->nmsgs) {
 186.953 +				/* for each message in sysibx mailbox */
 186.954 +      for (i = 1; snarfok && (i <= sysibx->nmsgs); ++i)
 186.955 +	if (!(elt = mail_elt (sysibx,i))->deleted &&
 186.956 +	    (message = mail_fetch_message (sysibx,i,&msglen,FT_PEEK)) &&
 186.957 +	    msglen) {
 186.958 +	  mail_date (date,elt);	/* make internal date string */
 186.959 +				/* make flag string */
 186.960 +	  flags[0] = flags[1] = '\0';
 186.961 +	  if (elt->seen) strcat (flags," \\Seen");
 186.962 +	  if (elt->flagged) strcat (flags," \\Flagged");
 186.963 +	  if (elt->answered) strcat (flags," \\Answered");
 186.964 +	  if (elt->draft) strcat (flags," \\Draft");
 186.965 +	  flags[0] = '(';
 186.966 +	  strcat (flags,")");
 186.967 +	  INIT (&msg,mail_string,message,msglen);
 186.968 +	  if (snarfok = mail_append_full (stream,"INBOX",flags,date,&msg)) {
 186.969 +	    char sequence[15];
 186.970 +	    sprintf (sequence,"%lu",i);
 186.971 +	    mail_flag (sysibx,sequence,"\\Deleted",ST_SET);
 186.972 +	  }
 186.973 +	}
 186.974 +
 186.975 +				/* now expunge all those messages */
 186.976 +      if (snarfok) mail_expunge (sysibx);
 186.977 +      else {
 186.978 +	sprintf (LOCAL->buf,"Can't copy new mail at message: %lu",i - 1);
 186.979 +	MM_LOG (LOCAL->buf,WARN);
 186.980 +      }
 186.981 +    }
 186.982 +    if (sysibx) mail_close (sysibx);
 186.983 +				/* reenable APPENDUID/COPYUID */
 186.984 +    mail_parameters (NIL,SET_APPENDUID,(void *) au);
 186.985 +    mail_parameters (NIL,SET_COPYUID,(void *) cu);
 186.986 +    snarfing = NIL;		/* no longer snarfing */
 186.987 +    MM_NOCRITICAL (stream);	/* release critical */
 186.988 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 186.989 +  }
 186.990 +				/* expunging OK if global flag set */
 186.991 +  if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
 186.992 +				/* process metadata/index/status */
 186.993 +  if (statf = mix_parse (stream,&idxf,LONGT,
 186.994 +			 (LOCAL->internal ? NIL : LONGT))) {
 186.995 +    fclose (statf);		/* just close the status file */
 186.996 +    ret = LONGT;		/* declare success */
 186.997 +  }
 186.998 +  if (idxf) fclose (idxf);	/* release index file */
 186.999 +  LOCAL->expok = NIL;		/* expunge no longer OK */
186.1000 +  if (!ret) mix_abort (stream);	/* murdelyze stream if ping fails */
186.1001 +  return ret;
186.1002 +}
186.1003 +
186.1004 +
186.1005 +/* MIX mail checkpoint mailbox (burp only)
186.1006 + * Accepts: MAIL stream
186.1007 + */
186.1008 +
186.1009 +void mix_check (MAILSTREAM *stream)
186.1010 +{
186.1011 +  if (stream->rdonly)		/* won't do on readonly files! */
186.1012 +    MM_LOG ("Checkpoint ignored on readonly mailbox",NIL);
186.1013 +				/* do burp-only expunge action */
186.1014 +  if (mix_expunge (stream,"",NIL)) MM_LOG ("Check completed",(long) NIL);
186.1015 +}
186.1016 +
186.1017 +/* MIX mail expunge mailbox
186.1018 + * Accepts: MAIL stream
186.1019 + *	    sequence to expunge if non-NIL, empty string for burp only
186.1020 + *	    expunge options
186.1021 + * Returns: T on success, NIL if failure
186.1022 + */
186.1023 +
186.1024 +long mix_expunge (MAILSTREAM *stream,char *sequence,long options)
186.1025 +{
186.1026 +  FILE *idxf = NIL;
186.1027 +  FILE *statf = NIL;
186.1028 +  MESSAGECACHE *elt;
186.1029 +  int ifd,sfd;
186.1030 +  long ret;
186.1031 +  unsigned long i;
186.1032 +  unsigned long nexp = 0;
186.1033 +  unsigned long reclaimed = 0;
186.1034 +  int burponly = (sequence && !*sequence);
186.1035 +  LOCAL->expok = T;		/* expunge during ping is OK */
186.1036 +  if (!(ret = burponly || !sequence ||
186.1037 +	((options & EX_UID) ?
186.1038 +	 mail_uid_sequence (stream,sequence) :
186.1039 +	 mail_sequence (stream,sequence))) || stream->rdonly);
186.1040 +				/* read index and open status exclusive */
186.1041 +  else if (statf = mix_parse (stream,&idxf,LONGT,
186.1042 +			      LOCAL->internal ? NIL : LONGT)) {
186.1043 +				/* expunge unless just burping */
186.1044 +    if (!burponly) for (i = 1; i <= stream->nmsgs;) {
186.1045 +      elt = mail_elt (stream,i);/* need to expunge this message? */
186.1046 +      if (sequence ? elt->sequence : elt->deleted) {
186.1047 +	++nexp;			/* yes, make it so */
186.1048 +	mail_expunged (stream,i);
186.1049 +      }
186.1050 +      else ++i;		       /* otherwise advance to next message */
186.1051 +    }
186.1052 +
186.1053 +				/* burp if can get exclusive access */
186.1054 +    if (!flock (LOCAL->mfd,LOCK_EX|LOCK_NB)) {
186.1055 +      void *a;
186.1056 +      struct direct **names = NIL;
186.1057 +      long nfiles = scandir (stream->mailbox,&names,mix_select,mix_msgfsort);
186.1058 +      if (nfiles > 0) {		/* if have message files */
186.1059 +	MIXBURP *burp,*cur;
186.1060 +				/* initialize burp list */
186.1061 +	for (i = 0, burp = cur = NIL; i < nfiles; ++i) {
186.1062 +	  MIXBURP *nxt = (MIXBURP *) memset (fs_get (sizeof (MIXBURP)),0,
186.1063 +					     sizeof (MIXBURP));
186.1064 +				/* another file found */
186.1065 +	  if (cur) cur = cur->next = nxt;
186.1066 +	  else cur = burp = nxt;
186.1067 +	  cur->name = names[i]->d_name;
186.1068 +	  cur->fileno = strtoul (cur->name + sizeof (MIXNAME) - 1,NIL,16);
186.1069 +	  cur->tail = &cur->set;
186.1070 +	  fs_give ((void **) &names[i]);
186.1071 +	}
186.1072 +				/* now load ranges */
186.1073 +	for (i = 1, cur = burp; ret && (i <= stream->nmsgs); i++) {
186.1074 +				/* is this message in current set? */
186.1075 +	  elt = mail_elt (stream,i);
186.1076 +	  if (cur && (elt->private.spare.data != cur->fileno)) {
186.1077 +				/* restart if necessary */
186.1078 +	    if (elt->private.spare.data < cur->fileno) cur = burp;
186.1079 +				/* hunt for appropriate mailbox */
186.1080 +	    while (cur && (elt->private.spare.data > cur->fileno))
186.1081 +	      cur = cur->next;
186.1082 +				/* ought to have found it now... */
186.1083 +	    if (cur && (elt->private.spare.data != cur->fileno)) cur = NIL;
186.1084 +	  }
186.1085 +				/* if found, add to set */
186.1086 +	  if (cur) ret = mix_addset (&cur->tail,elt->private.special.offset,
186.1087 +				     elt->private.msg.header.offset +
186.1088 +				     elt->rfc822_size);
186.1089 +	  else {		/* uh-oh */
186.1090 +	    sprintf (LOCAL->buf,"Can't locate mix message file %.08lx",
186.1091 +		     elt->private.spare.data);
186.1092 +	    MM_LOG (LOCAL->buf,ERROR);
186.1093 +	    ret = NIL;
186.1094 +	  }
186.1095 +	}
186.1096 +	if (ret) 		/* if no errors, burp all files */
186.1097 +	  for (cur = burp; ret && cur; cur = cur->next) {
186.1098 +				/* if non-empty, burp it */
186.1099 +	    if (cur->set.last) ret = mix_burp (stream,cur,&reclaimed);
186.1100 +				/* empty, delete it unless new msg file */
186.1101 +	    else if (mix_file_data (LOCAL->buf,stream->mailbox,cur->fileno) &&
186.1102 +		     ((cur->fileno == LOCAL->newmsg) ?
186.1103 +		      truncate (LOCAL->buf,0) : unlink (LOCAL->buf))) {
186.1104 +	      sprintf (LOCAL->buf,
186.1105 +		       "Can't delete empty message file %.80s: %.80s",
186.1106 +		       cur->name,strerror (errno));
186.1107 +	      MM_LOG (LOCAL->buf,WARN);
186.1108 +	    }
186.1109 +	  }
186.1110 +      }
186.1111 +      else MM_LOG ("No mix message files found during expunge",WARN);
186.1112 +				/* free directory list */
186.1113 +      if (a = (void *) names) fs_give ((void **) &a);
186.1114 +    }
186.1115 +
186.1116 +				/* either way, re-acquire shared lock */
186.1117 +    if (flock (LOCAL->mfd,LOCK_SH|LOCK_NB))
186.1118 +      fatal ("Unable to re-acquire metadata shared lock!");
186.1119 +    /* Do this step even if ret is NIL (meaning some burp problem)! */
186.1120 +    if (nexp || reclaimed) {	/* rewrite index and status if changed */
186.1121 +      LOCAL->indexseq = mix_modseq (LOCAL->indexseq);
186.1122 +      if (mix_index_update (stream,idxf,NIL)) {
186.1123 +	LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
186.1124 +				/* set failure if update fails */
186.1125 +	ret = mix_status_update (stream,statf,NIL);
186.1126 +      }
186.1127 +    }
186.1128 +  }
186.1129 +  if (statf) fclose (statf);	/* close status if still open */
186.1130 +  if (idxf) fclose (idxf);	/* close index if still open */
186.1131 +  LOCAL->expok = NIL;		/* cancel expok */
186.1132 +  if (ret) {			/* only if success */
186.1133 +    char *s = NIL;
186.1134 +    if (nexp) sprintf (s = LOCAL->buf,"Expunged %lu messages",nexp);
186.1135 +    else if (reclaimed)
186.1136 +      sprintf (s=LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
186.1137 +    else if (!burponly)
186.1138 +      s = stream->rdonly ? "Expunge ignored on readonly mailbox" :
186.1139 +	   "No messages deleted, so no update needed";
186.1140 +    if (s) MM_LOG (s,(long) NIL);
186.1141 +  }
186.1142 +  return ret;
186.1143 +}
186.1144 +
186.1145 +/* MIX test for message file name
186.1146 + * Accepts: candidate directory name
186.1147 + * Returns: T if message file name, NIL otherwise
186.1148 + *
186.1149 + * ".mix" with no suffix was used by experimental versions
186.1150 + */
186.1151 +
186.1152 +int mix_select (struct direct *name)
186.1153 +{
186.1154 +  char c,*s;
186.1155 +				/* make sure name has prefix */
186.1156 +  if (mix_dirfmttest (name->d_name)) {
186.1157 +    for (c = *(s = name->d_name + sizeof (MIXNAME) - 1); c && isxdigit (c);
186.1158 +	 c = *s++);
186.1159 +    if (!c) return T;		/* all-hex or no suffix */
186.1160 +  }
186.1161 +  return NIL;			/* not suffix or non-hex */
186.1162 +}
186.1163 +
186.1164 +
186.1165 +/* MIX msg file name comparision
186.1166 + * Accepts: first candidate directory entry
186.1167 + *	    second candidate directory entry
186.1168 + * Returns: -1 if d1 < d2, 0 if d1 == d2, 1 d1 > d2
186.1169 + */
186.1170 +
186.1171 +int mix_msgfsort (const void *d1,const void *d2)
186.1172 +{
186.1173 +  char *n1 = (*(struct direct **) d1)->d_name + sizeof (MIXNAME) - 1;
186.1174 +  char *n2 = (*(struct direct **) d2)->d_name + sizeof (MIXNAME) - 1;
186.1175 +  return compare_ulong (*n1 ? strtoul (n1,NIL,16) : 0,
186.1176 +			*n2 ? strtoul (n2,NIL,16) : 0);
186.1177 +}
186.1178 +
186.1179 +
186.1180 +/* MIX add a range to a set
186.1181 + * Accepts: pointer to set to add
186.1182 + *	    start of set
186.1183 + *	    size of set
186.1184 + * Returns: T if success, set updated, NIL otherwise
186.1185 + */
186.1186 +
186.1187 +long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size)
186.1188 +{
186.1189 +  SEARCHSET *s = *set;
186.1190 +  if (start < s->last) {	/* sanity check */
186.1191 +    char tmp[MAILTMPLEN];
186.1192 +    sprintf (tmp,"Backwards-running mix index %lu < %lu",start,s->last);
186.1193 +    MM_LOG (tmp,ERROR);
186.1194 +    return NIL;
186.1195 +  }
186.1196 +				/* range initially empty? */
186.1197 +  if (!s->last) s->first = start;
186.1198 +  else if (start > s->last)	/* no, start new range if can't append */
186.1199 +    (*set = s = s->next = mail_newsearchset ())->first = start;
186.1200 +  s->last = start + size;	/* end of current range */
186.1201 +  return LONGT;
186.1202 +}
186.1203 +
186.1204 +/* MIX burp message file
186.1205 + * Accepts: MAIL stream
186.1206 + *	    current burp block for this message
186.1207 + * Returns: T if successful, NIL if failed
186.1208 + */
186.1209 +
186.1210 +static char *staterr = "Error in stat of mix message file %.80s: %.80s";
186.1211 +static char *truncerr = "Error truncating mix message file %.80s: %.80s";
186.1212 +
186.1213 +long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed)
186.1214 +{
186.1215 +  MESSAGECACHE *elt;
186.1216 +  SEARCHSET *set;
186.1217 +  struct stat sbuf;
186.1218 +  off_t rpos,wpos;
186.1219 +  size_t size,wsize,wpending,written;
186.1220 +  int fd;
186.1221 +  FILE *f;
186.1222 +  void *s;
186.1223 +  unsigned long i;
186.1224 +  long ret = NIL;
186.1225 +				/* build file name */
186.1226 +  mix_file_data (LOCAL->buf,stream->mailbox,burp->fileno);
186.1227 +				/* need to burp at start or multiple ranges? */
186.1228 +  if (!burp->set.first && !burp->set.next) {
186.1229 +				/* easy case, single range at start of file */
186.1230 +    if (stat (LOCAL->buf,&sbuf)) {
186.1231 +      sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
186.1232 +      MM_LOG (LOCAL->buf,ERROR);
186.1233 +    }
186.1234 +				/* is this range sane? */
186.1235 +    else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
186.1236 +				/* if matches range then no burp needed! */
186.1237 +      if (burp->set.last == sbuf.st_size) ret = LONGT;
186.1238 +				/* just need to remove cruft at end */
186.1239 +      else if (ret = !truncate (LOCAL->buf,burp->set.last))
186.1240 +	*reclaimed += sbuf.st_size - burp->set.last;
186.1241 +      else {
186.1242 +	sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
186.1243 +	MM_LOG (LOCAL->buf,ERROR);
186.1244 +      }
186.1245 +    }
186.1246 +  }
186.1247 +				/* have to do more work, get the file */
186.1248 +  else if (((fd = open (LOCAL->buf,O_RDWR,NIL)) < 0) ||
186.1249 +	   !(f = fdopen (fd,"r+b"))) {
186.1250 +    sprintf (LOCAL->buf,"Error opening mix message file %.80s: %.80s",
186.1251 +	     burp->name,strerror (errno));
186.1252 +    MM_LOG (LOCAL->buf,ERROR);
186.1253 +    if (fd >= 0) close (fd);	/* in case fdopen() failure */
186.1254 +  }
186.1255 +  else if (fstat (fd,&sbuf)) {	/* get file size */
186.1256 +    sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
186.1257 +    MM_LOG (LOCAL->buf,ERROR);
186.1258 +    fclose (f);
186.1259 +  }
186.1260 +
186.1261 +				/* only if sane */
186.1262 +  else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
186.1263 +				/* make sure each range starts with token */
186.1264 +    for (set = &burp->set; set; set = set->next)
186.1265 +      if (fseek (f,set->first,SEEK_SET) ||
186.1266 +	  (fread (LOCAL->buf,1,MSGTSZ,f) != MSGTSZ) ||
186.1267 +	  strncmp (LOCAL->buf,MSGTOK,MSGTSZ)) {
186.1268 +	sprintf (LOCAL->buf,"Bad message token in mix message file at %lu",
186.1269 +		 set->first);
186.1270 +	MM_LOG (LOCAL->buf,ERROR);
186.1271 +	fclose (f);
186.1272 +	return NIL;		/* burp fails for this file */
186.1273 +      }
186.1274 +				/* burp out each old message */
186.1275 +    for (set = &burp->set, wpos = 0; set; set = set->next) {
186.1276 +				/* move down this range */
186.1277 +      for (rpos = set->first, size = set->last - set->first;
186.1278 +	   size; size -= wsize) {
186.1279 +	if (rpos != wpos) {	/* data to skip at start? */
186.1280 +				/* no, slide this buffer down */
186.1281 +	  wsize = min (size,LOCAL->buflen);
186.1282 +				/* failure is not an option here */
186.1283 +	  while (fseek (f,rpos,SEEK_SET) ||
186.1284 +		 (fread (LOCAL->buf,1,wsize,f) != wsize)) {
186.1285 +	    MM_NOTIFY (stream,strerror (errno),WARN);
186.1286 +	    MM_DISKERROR (stream,errno,T);
186.1287 +	  }
186.1288 +				/* nor here */
186.1289 +	  while (fseek (f,wpos,SEEK_SET)) {
186.1290 +	    MM_NOTIFY (stream,strerror (errno),WARN);
186.1291 +	    MM_DISKERROR (stream,errno,T);
186.1292 +	  }
186.1293 +				/* and especially not here */
186.1294 +	  for (s = LOCAL->buf, wpending = wsize; wpending; wpending -= written)
186.1295 +	    if (!(written = fwrite (LOCAL->buf,1,wpending,f))) {
186.1296 +	      MM_NOTIFY (stream,strerror (errno),WARN);
186.1297 +	      MM_DISKERROR (stream,errno,T);
186.1298 +	    }
186.1299 +	}
186.1300 +	else wsize = size;	/* nothing to skip, say we wrote it all */
186.1301 +	rpos += wsize; wpos += wsize;
186.1302 +      }
186.1303 +    }
186.1304 +
186.1305 +    while (fflush (f)) {	/* failure also not an option here... */
186.1306 +      MM_NOTIFY (stream,strerror (errno),WARN);
186.1307 +      MM_DISKERROR (stream,errno,T);
186.1308 +    }
186.1309 +    if (ftruncate (fd,wpos)) {	/* flush cruft at end of file */
186.1310 +      sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
186.1311 +      MM_LOG (LOCAL->buf,WARN);
186.1312 +    }
186.1313 +    else *reclaimed += rpos - wpos;
186.1314 +    ret = !fclose (f);		/* close file */
186.1315 +				/* slide down message positions in index */
186.1316 +    for (i = 1,rpos = 0; i <= stream->nmsgs; ++i)
186.1317 +      if ((elt = mail_elt (stream,i))->private.spare.data == burp->fileno) {
186.1318 +	elt->private.special.offset = rpos;
186.1319 +	rpos += elt->private.msg.header.offset + elt->rfc822_size;
186.1320 +      }
186.1321 +				/* debugging */
186.1322 +    if (rpos != wpos) fatal ("burp size consistency check!");
186.1323 +  }
186.1324 +  return ret;
186.1325 +}
186.1326 +
186.1327 +
186.1328 +/* MIX burp sanity check to make sure not burping off end of file
186.1329 + * Accepts: burp set
186.1330 + *	    file size
186.1331 + *	    file name
186.1332 + * Returns: T if sane, NIL if insane
186.1333 + */
186.1334 +
186.1335 +long mix_burp_check (SEARCHSET *set,size_t size,char *file)
186.1336 +{
186.1337 +  do if (set->last > size) {	/* sanity check */
186.1338 +    char tmp[MAILTMPLEN];
186.1339 +    sprintf (tmp,"Unexpected short mix message file %.80s %lu < %lu",
186.1340 +	     file,size,set->last);
186.1341 +    MM_LOG (tmp,ERROR);
186.1342 +    return NIL;			/* don't burp this file at all */
186.1343 +  } while (set = set->next);
186.1344 +  return LONGT;
186.1345 +}
186.1346 +
186.1347 +/* MIX mail copy message(s)
186.1348 + * Accepts: MAIL stream
186.1349 + *	    sequence
186.1350 + *	    destination mailbox
186.1351 + *	    copy options
186.1352 + * Returns: T if copy successful, else NIL
186.1353 + */
186.1354 +
186.1355 +long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
186.1356 +{
186.1357 +  FDDATA d;
186.1358 +  STRING st;
186.1359 +  char tmp[2*MAILTMPLEN];
186.1360 +  long ret = mix_isvalid (mailbox,LOCAL->buf);
186.1361 +  mailproxycopy_t pc =
186.1362 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
186.1363 +  MAILSTREAM *astream = NIL;
186.1364 +  FILE *idxf = NIL;
186.1365 +  FILE *msgf = NIL;
186.1366 +  FILE *statf = NIL;
186.1367 +  if (!ret) switch (errno) {	/* make sure valid mailbox */
186.1368 +  case NIL:			/* no error in stat() */
186.1369 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
186.1370 +    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
186.1371 +    MM_LOG (tmp,ERROR);
186.1372 +    break;
186.1373 +  default:			/* some stat() error */
186.1374 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
186.1375 +    break;
186.1376 +  }
186.1377 +				/* get sequence to copy */
186.1378 +  else if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
186.1379 +		    mail_sequence (stream,sequence))));
186.1380 +				/* acquire stream to append */
186.1381 +  else if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
186.1382 +		  !astream->rdonly &&
186.1383 +		  (((MIXLOCAL *) astream->local)->expok = T) &&
186.1384 +		  (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
186.1385 +	   LONGT : NIL) {
186.1386 +    int fd;
186.1387 +    unsigned long i;
186.1388 +    MESSAGECACHE *elt;
186.1389 +    unsigned long newsize,hdrsize,size;
186.1390 +    MIXLOCAL *local = (MIXLOCAL *) astream->local;
186.1391 +    unsigned long seq = mix_modseq (local->metaseq);
186.1392 +				/* make sure new modseq fits */
186.1393 +    if (local->indexseq > seq) seq = local->indexseq + 1;
186.1394 +    if (local->statusseq > seq) seq = local->statusseq + 1;
186.1395 +				/* calculate size of per-message header */
186.1396 +    sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
186.1397 +    hdrsize = strlen (local->buf);
186.1398 +
186.1399 +    MM_CRITICAL (stream);	/* go critical */
186.1400 +    astream->silent = T;	/* no events here */
186.1401 +				/* calculate size that will be added */
186.1402 +    for (i = 1, newsize = 0; i <= stream->nmsgs; ++i)
186.1403 +      if ((elt = mail_elt (stream,i))->sequence)
186.1404 +	newsize += hdrsize + elt->rfc822_size;
186.1405 +				/* open data file */
186.1406 +    if (msgf = mix_data_open (astream,&fd,&size,newsize)) {
186.1407 +      char *t;
186.1408 +      unsigned long j,uid,uidv;
186.1409 +      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
186.1410 +      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
186.1411 +      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
186.1412 +      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); ++i) 
186.1413 +	if (((elt = mail_elt (stream,i))->sequence) && elt->rfc822_size) {
186.1414 +				/* is message in current message file? */
186.1415 +	  if ((LOCAL->msgfd < 0) ||
186.1416 +	      (elt->private.spare.data != LOCAL->curmsg)) {
186.1417 +	    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
186.1418 +	    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,
186.1419 +						     stream->mailbox,
186.1420 +						     elt->private.spare.data),
186.1421 +				      O_RDONLY,NIL)) >= 0)
186.1422 +	      LOCAL->curmsg = elt->private.spare.data;
186.1423 +	  }
186.1424 +	  if (LOCAL->msgfd < 0) ret = NIL;
186.1425 +	  else {		/* got file */
186.1426 +	    d.fd = LOCAL->msgfd;/* set up file descriptor */
186.1427 +				/* start of message */
186.1428 +	    d.pos = elt->private.special.offset +
186.1429 +	      elt->private.msg.header.offset;
186.1430 +	    d.chunk = LOCAL->buf;
186.1431 +	    d.chunksize = CHUNKSIZE;
186.1432 +	    INIT (&st,fd_string,&d,elt->rfc822_size);
186.1433 +				/* init flag string */
186.1434 +	    tmp[0] = tmp[1] = '\0';
186.1435 +	    if (j = elt->user_flags) do
186.1436 +	      if ((t = stream->user_flags[find_rightmost_bit (&j)]) && *t)
186.1437 +		strcat (strcat (tmp," "),t);
186.1438 +	    while (j);
186.1439 +	    if (elt->seen) strcat (tmp," \\Seen");
186.1440 +	    if (elt->deleted) strcat (tmp," \\Deleted");
186.1441 +	    if (elt->flagged) strcat (tmp," \\Flagged");
186.1442 +	    if (elt->answered) strcat (tmp," \\Answered");
186.1443 +	    if (elt->draft) strcat (tmp," \\Draft");
186.1444 +	    tmp[0] = '(';	/* wrap list */
186.1445 +	    strcat (tmp,")");
186.1446 +				/* if append OK, add to source set */
186.1447 +	    if ((ret = mix_append_msg (astream,msgf,tmp,elt,&st,dest,
186.1448 +				       seq)) &&	source)
186.1449 +	      mail_append_set (source,mail_uid (stream,i));
186.1450 +	  }
186.1451 +	}
186.1452 +
186.1453 +				/* finish write if success */
186.1454 +      if (ret && (ret = !fflush (msgf))) {
186.1455 +	fclose (msgf);		/* all good, close the msg file now */
186.1456 +				/* write new metadata, index, and status */
186.1457 +	local->metaseq = local->indexseq = local->statusseq = seq;
186.1458 +	if (ret = (mix_meta_update (astream) &&
186.1459 +		   mix_index_update (astream,idxf,LONGT))) {
186.1460 +				/* success, delete if doing a move */
186.1461 +	  if (options & CP_MOVE)
186.1462 +	    for (i = 1; i <= stream->nmsgs; i++)
186.1463 +	      if ((elt = mail_elt (stream,i))->sequence) {
186.1464 +		elt->deleted = T;
186.1465 +		if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
186.1466 +		MM_FLAGS (stream,elt->msgno);
186.1467 +	      }
186.1468 +				/* done with status file now */
186.1469 +	  mix_status_update (astream,statf,LONGT);
186.1470 +				/* return sets if doing COPYUID */
186.1471 +	  if (cu) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
186.1472 +	  source = dest = NIL;	/* don't free these sets now */
186.1473 +	}
186.1474 +      }
186.1475 +      else {			/* error */
186.1476 +	if (errno) {		/* output error message if system call error */
186.1477 +	  sprintf (tmp,"Message copy failed: %.80s",strerror (errno));
186.1478 +	  MM_LOG (tmp,ERROR);
186.1479 +	}
186.1480 +	ftruncate (fd,size);	/* revert file */
186.1481 +	close (fd);		/* make sure that fclose doesn't corrupt us */
186.1482 +	fclose (msgf);		/* free the stdio resources */
186.1483 +      }
186.1484 +				/* flush any sets remaining */
186.1485 +      mail_free_searchset (&source);
186.1486 +      mail_free_searchset (&dest);
186.1487 +    }
186.1488 +    else {			/* message file open failed */
186.1489 +      sprintf (tmp,"Error opening copy message file: %.80s",
186.1490 +	       strerror (errno));
186.1491 +      MM_LOG (tmp,ERROR);
186.1492 +      ret = NIL;
186.1493 +    }
186.1494 +    MM_NOCRITICAL (stream);
186.1495 +  }
186.1496 +  else MM_LOG ("Can't open copy mailbox",ERROR);
186.1497 +  if (statf) fclose (statf);	/* close status if still open */
186.1498 +  if (idxf) fclose (idxf);	/* close index if still open */
186.1499 +				/* finished with append stream */
186.1500 +  if (astream) mail_close (astream);
186.1501 +  return ret;			/* return state */
186.1502 +}
186.1503 +
186.1504 +/* MIX mail append message from stringstruct
186.1505 + * Accepts: MAIL stream
186.1506 + *	    destination mailbox
186.1507 + *	    append callback
186.1508 + *	    data for callback
186.1509 + * Returns: T if append successful, else NIL
186.1510 + */
186.1511 +
186.1512 +long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
186.1513 +{
186.1514 +  STRING *message;
186.1515 +  char *flags,*date,tmp[MAILTMPLEN];
186.1516 +				/* N.B.: can't use LOCAL->buf for tmp */
186.1517 +  long ret = mix_isvalid (mailbox,tmp);
186.1518 +				/* default stream to prototype */
186.1519 +  if (!stream) stream = user_flags (&mixproto);
186.1520 +  if (!ret) switch (errno) {	/* if not valid mailbox */
186.1521 +  case ENOENT:			/* no such file? */
186.1522 +    if (ret = compare_cstring (mailbox,"INBOX") ?
186.1523 +	NIL : mix_create (NIL,"INBOX"))
186.1524 +      break;
186.1525 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
186.1526 +    break;
186.1527 +  default:
186.1528 +    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
186.1529 +    MM_LOG (tmp,ERROR);
186.1530 +    break;
186.1531 +  }
186.1532 +
186.1533 +				/* get first message */
186.1534 +  if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) {
186.1535 +    MAILSTREAM *astream;
186.1536 +    FILE *idxf = NIL;
186.1537 +    FILE *msgf = NIL;
186.1538 +    FILE *statf = NIL;
186.1539 +    if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
186.1540 +	       !astream->rdonly &&
186.1541 +	       (((MIXLOCAL *) astream->local)->expok = T) &&
186.1542 +	       (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
186.1543 +	LONGT : NIL) {
186.1544 +      int fd;
186.1545 +      unsigned long size,hdrsize;
186.1546 +      MESSAGECACHE elt;
186.1547 +      MIXLOCAL *local = (MIXLOCAL *) astream->local;
186.1548 +      unsigned long seq = mix_modseq (local->metaseq);
186.1549 +				/* make sure new modseq fits */
186.1550 +      if (local->indexseq > seq) seq = local->indexseq + 1;
186.1551 +      if (local->statusseq > seq) seq = local->statusseq + 1;
186.1552 +				/* calculate size of per-message header */
186.1553 +      sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
186.1554 +      hdrsize = strlen (local->buf);
186.1555 +      MM_CRITICAL (astream);	/* go critical */
186.1556 +      astream->silent = T;	/* no events here */
186.1557 +				/* open data file */
186.1558 +      if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) {
186.1559 +	appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
186.1560 +	SEARCHSET *dst = au ? mail_newsearchset () : NIL;
186.1561 +	while (ret && message) {/* while good to go and have messages */
186.1562 +	  errno = NIL;		/* in case one of these causes failure */
186.1563 +				/* guard against zero-length */
186.1564 +	  if (!(ret = SIZE (message)))
186.1565 +	    MM_LOG ("Append of zero-length message",ERROR);
186.1566 +	  else if (date && !(ret = mail_parse_date (&elt,date))) {
186.1567 +	    sprintf (tmp,"Bad date in append: %.80s",date);
186.1568 +	    MM_LOG (tmp,ERROR);
186.1569 +	  }
186.1570 +	  else {
186.1571 +	    if (!date) {	/* if date not specified, use now */
186.1572 +	      internal_date (tmp);
186.1573 +	      mail_parse_date (&elt,tmp);
186.1574 +	    }
186.1575 +	    ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) &&
186.1576 +	      MM_APPEND (af) (stream,data,&flags,&date,&message);
186.1577 +	  }
186.1578 +	}
186.1579 +
186.1580 +				/* finish write if success */
186.1581 +	if (ret && (ret = !fflush (msgf))) {
186.1582 +	  fclose (msgf);	/* all good, close the msg file now */
186.1583 +				/* write new metadata, index, and status */
186.1584 +	  local->metaseq = local->indexseq = local->statusseq = seq;
186.1585 +	  if ((ret = (mix_meta_update (astream) &&
186.1586 +		      mix_index_update (astream,idxf,LONGT) &&
186.1587 +		      mix_status_update (astream,statf,LONGT))) && au) {
186.1588 +	      (*au) (mailbox,astream->uid_validity,dst);
186.1589 +	      dst = NIL;	/* don't free this set now */
186.1590 +	  }
186.1591 +	}
186.1592 +	else {			/* failure */
186.1593 +	  if (errno) {		/* output error message if system call error */
186.1594 +	    sprintf (tmp,"Message append failed: %.80s",strerror (errno));
186.1595 +	    MM_LOG (tmp,ERROR);
186.1596 +	  }
186.1597 +	  ftruncate (fd,size);	/* revert all writes to file*/
186.1598 +	  close (fd);		/* make sure that fclose doesn't corrupt us */
186.1599 +	  fclose (msgf);	/* free the stdio resources */
186.1600 +	}
186.1601 +				/* flush any set remaining */
186.1602 +	mail_free_searchset (&dst);
186.1603 +      }
186.1604 +      else {			/* message file open failed */
186.1605 +	sprintf (tmp,"Error opening append message file: %.80s",
186.1606 +		 strerror (errno));
186.1607 +	MM_LOG (tmp,ERROR);
186.1608 +	ret = NIL;
186.1609 +      }
186.1610 +      MM_NOCRITICAL (astream);	/* release critical */
186.1611 +    }
186.1612 +    else MM_LOG ("Can't open append mailbox",ERROR);
186.1613 +    if (statf) fclose (statf);	/* close status if still open */
186.1614 +    if (idxf) fclose (idxf);	/* close index if still open */
186.1615 +    if (astream) mail_close (astream);
186.1616 +  }
186.1617 +  return ret;
186.1618 +}
186.1619 +
186.1620 +/* MIX mail append single message
186.1621 + * Accepts: MAIL stream
186.1622 + *	    flags for new message if non-NIL
186.1623 + *	    elt with source date if non-NIL
186.1624 + *	    stringstruct of message text
186.1625 + *	    searchset to place UID
186.1626 + *	    modseq of message
186.1627 + * Returns: T if success, NIL if failure
186.1628 + */
186.1629 +
186.1630 +long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
186.1631 +		     STRING *msg,SEARCHSET *set,unsigned long seq)
186.1632 +{
186.1633 +  MESSAGECACHE *elt;
186.1634 +  int c,cs;
186.1635 +  unsigned long i,j,k,uf,hoff;
186.1636 +  long sf;
186.1637 +  stream->kwd_create = NIL;	/* don't copy unknown keywords */
186.1638 +  sf = mail_parse_flags (stream,flags,&uf);
186.1639 +				/* swell the cache */
186.1640 +  mail_exists (stream,++stream->nmsgs);
186.1641 +				/* assign new UID from metadata */
186.1642 +  (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last;
186.1643 +  elt->private.mod = seq;	/* set requested modseq in status */
186.1644 +  elt->rfc822_size = SIZE (msg);/* copy message size and date to index */
186.1645 +  elt->year = delt->year; elt->month = delt->month; elt->day = delt->day;
186.1646 +  elt->hours = delt->hours; elt->minutes = delt->minutes;
186.1647 +  elt->seconds = delt->seconds; elt->zoccident = delt->zoccident;
186.1648 +  elt->zhours = delt->zhours; elt->zminutes = delt->zminutes;
186.1649 +  /*
186.1650 +   * Do NOT set elt->valid here!  mix_status_update() uses it to determine
186.1651 +   * whether a message should be marked as old.
186.1652 +   */
186.1653 +  if (sf&fSEEN) elt->seen = T;	/* copy flags to status */
186.1654 +  if (sf&fDELETED) elt->deleted = T;
186.1655 +  if (sf&fFLAGGED) elt->flagged = T;
186.1656 +  if (sf&fANSWERED) elt->answered = T;
186.1657 +  if (sf&fDRAFT) elt->draft = T;
186.1658 +  elt->user_flags |= uf;
186.1659 +				/* message is in new message file */
186.1660 +  elt->private.spare.data = LOCAL->newmsg;
186.1661 +
186.1662 +				/* offset to message internal header */
186.1663 +  elt->private.special.offset = ftell (f);
186.1664 +				/* build header for message */
186.1665 +  fprintf (f,MSRFMT,MSGTOK,elt->private.uid,
186.1666 +	   elt->year + BASEYEAR,elt->month,elt->day,
186.1667 +	   elt->hours,elt->minutes,elt->seconds,
186.1668 +	   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
186.1669 +	   elt->rfc822_size);
186.1670 +				/* offset to header from  internal header */
186.1671 +  elt->private.msg.header.offset = ftell (f) - elt->private.special.offset;
186.1672 +  for (cs = 0; SIZE (msg); ) {	/* copy message */
186.1673 +    if (elt->private.msg.header.text.size) {
186.1674 +      if (msg->cursize)		/* blat entire chunk if have it */
186.1675 +	for (j = msg->cursize; j; j -= k)
186.1676 +	  if (!(k = fwrite (msg->curpos,1,j,f))) return NIL;
186.1677 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
186.1678 +    }
186.1679 +    else {			/* still searching for delimiter */
186.1680 +      c = 0xff & SNX (msg);	/* get source character */
186.1681 +      if (putc (c,f) == EOF) return NIL;
186.1682 +      switch (cs) {		/* decide what to do based on state */
186.1683 +      case 0:			/* previous char ordinary */
186.1684 +	if (c == '\015') cs = 1;/* advance if CR */
186.1685 +	break;
186.1686 +      case 1:			/* previous CR, advance if LF */
186.1687 +	cs = (c == '\012') ? 2 : 0;
186.1688 +	break;
186.1689 +      case 2:			/* previous CRLF, advance if CR */
186.1690 +	cs = (c == '\015') ? 3 : 0;
186.1691 +	break;
186.1692 +      case 3:			/* previous CRLFCR, done if LF */
186.1693 +	if (c == '\012') elt->private.msg.header.text.size =
186.1694 +			   elt->rfc822_size - SIZE (msg);
186.1695 +	cs = 0;			/* reset mechanism */
186.1696 +	break;
186.1697 +      }
186.1698 +    }
186.1699 +  }
186.1700 +				/* if no delimiter, header is entire msg */
186.1701 +  if (!elt->private.msg.header.text.size)
186.1702 +    elt->private.msg.header.text.size = elt->rfc822_size;
186.1703 +				/* add this message to set */
186.1704 +  mail_append_set (set,elt->private.uid);
186.1705 +  return LONGT;			/* success */
186.1706 +}
186.1707 +
186.1708 +/* MIX mail read metadata, index, and status
186.1709 + * Accepts: MAIL stream
186.1710 + *	    returned index file
186.1711 + *	    index file flags (non-NIL if want to add/remove messages)
186.1712 + *	    status file flags (non-NIL if want to update elt->valid and old)
186.1713 + * Returns: open status file, or NIL if failure
186.1714 + *
186.1715 + * Note that this routine can return an open index file even if it fails!
186.1716 + */
186.1717 +
186.1718 +static char *shortmsg =
186.1719 +  "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)";
186.1720 +
186.1721 +FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags)
186.1722 +{
186.1723 +  int fd;
186.1724 +  unsigned long i;
186.1725 +  char *s,*t;
186.1726 +  struct stat sbuf;
186.1727 +  FILE *statf = NIL;
186.1728 +  short metarepairneeded = 0;
186.1729 +  short indexrepairneeded = 0;
186.1730 +  short silent = stream->silent;
186.1731 +  *idxf = NIL;			/* in case error */
186.1732 +				/* readonly means no updates */
186.1733 +  if (stream->rdonly) iflags = sflags = NIL;
186.1734 +				/* open index file */
186.1735 +  if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0)
186.1736 +    MM_LOG ("Error opening mix index file",ERROR);
186.1737 +				/* acquire exclusive access and FILE */
186.1738 +  else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) &&
186.1739 +	   !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) {
186.1740 +    MM_LOG ("Error obtaining stream on mix index file",ERROR);
186.1741 +    flock (fd,LOCK_UN);		/* relinquish lock */
186.1742 +    close (fd);
186.1743 +  }
186.1744 +
186.1745 +				/* slurp metadata */
186.1746 +  else if (s = mix_meta_slurp (stream,&i)) {
186.1747 +    unsigned long j = 0;	/* non-zero if UIDVALIDITY/UIDLAST changed */
186.1748 +    if (i != LOCAL->metaseq) {	/* metadata changed? */
186.1749 +      char *t,*k;
186.1750 +      LOCAL->metaseq = i;	/* note new metadata sequence */
186.1751 +      while (s && *s) {		/* parse entire metadata file */
186.1752 +				/* locate end of line */
186.1753 +	if (s = strstr (t = s,"\015\012")) {
186.1754 +	  *s = '\0';		/* tie off line */
186.1755 +	  s += 2;		/* skip past CRLF */
186.1756 +	  switch (*t++) {	/* parse line */
186.1757 +	  case 'V':		/* UIDVALIDITY */
186.1758 +	    if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) {
186.1759 +	      MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR);
186.1760 +	      return NIL;	/* give up */
186.1761 +	    }
186.1762 +	    if (i != stream->uid_validity) j = stream->uid_validity = i;
186.1763 +	    break;
186.1764 +	  case 'L':		/* new UIDLAST */
186.1765 +	    if (!isxdigit (*t)) {
186.1766 +	      MM_LOG ("Error in mix metadata file UIDLAST record",ERROR);
186.1767 +	      return NIL;	/* give up */
186.1768 +	    }
186.1769 +	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
186.1770 +	      j = stream->uid_last = i;
186.1771 +	    break;
186.1772 +	  case 'N':		/* new message file */
186.1773 +	    if (!isxdigit (*t)) {
186.1774 +	      MM_LOG ("Error in mix metadata file new msg record",ERROR);
186.1775 +	      return NIL;	/* give up */
186.1776 +	    }
186.1777 +	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
186.1778 +	      LOCAL->newmsg = i;
186.1779 +	    break;
186.1780 +	  case 'K':		/* new keyword list */
186.1781 +	    for (i = 0; t && *t && (i < NUSERFLAGS); ++i) {
186.1782 +	      if (t = strchr (k = t,' ')) *t++ = '\0';
186.1783 +				/* make sure keyword non-empty */
186.1784 +	      if (*k && (strlen (k) <= MAXUSERFLAG)) {
186.1785 +				/* in case value changes (shouldn't happen) */
186.1786 +		if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){
186.1787 +		  char tmp[MAILTMPLEN];
186.1788 +		  sprintf (tmp,"flag rename old=%.80s new=%.80s",
186.1789 +			   stream->user_flags[i],k);
186.1790 +		  MM_LOG (tmp,WARN);
186.1791 +		  fs_give ((void **) &stream->user_flags[i]);
186.1792 +		}
186.1793 +		if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k);
186.1794 +	      }
186.1795 +	      else break;	/* empty keyword */
186.1796 +	    }
186.1797 +	    if ((i < NUSERFLAGS) && stream->user_flags[i]) {
186.1798 +	      MM_LOG ("Error in mix metadata file keyword record",ERROR);
186.1799 +	      return NIL;	/* give up */
186.1800 +	    }
186.1801 +	    else if (i == NUSERFLAGS) stream->kwd_create = NIL;
186.1802 +	    break;
186.1803 +	  }
186.1804 +	}
186.1805 +	if (t && *t) {		/* junk in line */
186.1806 +	  MM_LOG ("Error in mix metadata record",ERROR);
186.1807 +	  return NIL;		/* give up */
186.1808 +	}
186.1809 +      }
186.1810 +    }
186.1811 +
186.1812 +				/* get sequence */
186.1813 +    if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) {
186.1814 +      MM_LOG ("Error in mix index file sequence record",ERROR);
186.1815 +      return NIL;		/* give up */
186.1816 +    }
186.1817 +				/* sequence changed from last time? */
186.1818 +    else if (j || (i > LOCAL->indexseq)) {
186.1819 +      unsigned long uid,nmsgs,curfile,curfilesize,curpos;
186.1820 +      char *t,*msg,tmp[MAILTMPLEN];
186.1821 +				/* start with no messages */
186.1822 +      curfile = curfilesize = curpos = nmsgs = 0;
186.1823 +				/* update sequence iff expunging OK */
186.1824 +      if (LOCAL->expok) LOCAL->indexseq = i;
186.1825 +				/* get first elt */
186.1826 +      while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) &&
186.1827 +	     *s)
186.1828 +	switch (*s) {
186.1829 +	case ':':		/* message record */
186.1830 +	  if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID";
186.1831 +	  else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) &&
186.1832 +		     isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) &&
186.1833 +		     isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) &&
186.1834 +		     isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) &&
186.1835 +		     isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) &&
186.1836 +		     ((t[14] == '+') || (t[14] == '-')) && 
186.1837 +		     isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) &&
186.1838 +		     isdigit (t[18]))) msg = "internaldate";
186.1839 +	  else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size";
186.1840 +	  else {
186.1841 +	    unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) +
186.1842 +			      ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR;
186.1843 +	    unsigned int m = ((t[4] - '0') * 10) + t[5] - '0';
186.1844 +	    unsigned int d = ((t[6] - '0') * 10) + t[7] - '0';
186.1845 +	    unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0';
186.1846 +	    unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0';
186.1847 +	    unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0';
186.1848 +	    unsigned int z = (t[14] == '-') ? 1 : 0;
186.1849 +	    unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0';
186.1850 +	    unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0';
186.1851 +	    unsigned long size = strtoul (s,&s,16);
186.1852 +	    if ((*s++ == ':') && isxdigit (*s)) {
186.1853 +	      unsigned long file = strtoul (s,&s,16);
186.1854 +	      if ((*s++ == ':') && isxdigit (*s)) {
186.1855 +		unsigned long pos = strtoul (s,&s,16);
186.1856 +		if ((*s++ == ':') && isxdigit (*s)) {
186.1857 +		  unsigned long hpos = strtoul (s,&s,16);
186.1858 +		  if ((*s++ == ':') && isxdigit (*s)) {
186.1859 +		    unsigned long hsiz = strtoul (s,&s,16);
186.1860 +		    if (uid > stream->uid_last) {
186.1861 +		      sprintf (tmp,"mix index invalid UID (%08lx < %08lx)",
186.1862 +			       uid,stream->uid_last);
186.1863 +		      if (stream->rdonly) {
186.1864 +			MM_LOG (tmp,ERROR);
186.1865 +			return NIL;
186.1866 +		      }
186.1867 +		      strcat (tmp,", repaired");
186.1868 +		      MM_LOG (tmp,WARN);
186.1869 +		      stream->uid_last = uid;
186.1870 +		      metarepairneeded = T;
186.1871 +		    }
186.1872 +
186.1873 +				/* ignore expansion values */
186.1874 +		    if (*s++ == ':') {
186.1875 +		      MESSAGECACHE *elt;
186.1876 +		      ++nmsgs;	/* this is another mesage */
186.1877 +				/* within current known range of messages? */
186.1878 +		      while (nmsgs <= stream->nmsgs) {
186.1879 +				/* yes, get corresponding elt */
186.1880 +			elt = mail_elt (stream,nmsgs);
186.1881 +				/* existing message with matching data? */
186.1882 +			if (uid == elt->private.uid) {
186.1883 +				/* beware of Dracula's resurrection */
186.1884 +			  if (elt->private.ghost) {
186.1885 +			    sprintf (tmp,"mix index data unexpunged UID: %lx",
186.1886 +				     uid);
186.1887 +			    MM_LOG (tmp,ERROR);
186.1888 +			    return NIL;
186.1889 +			  }
186.1890 +				/* also of static data changing */
186.1891 +			  if ((size != elt->rfc822_size) ||
186.1892 +			      (file != elt->private.spare.data) ||
186.1893 +			      (pos != elt->private.special.offset) ||
186.1894 +			      (hpos != elt->private.msg.header.offset) ||
186.1895 +			      (hsiz != elt->private.msg.header.text.size) ||
186.1896 +			      (y != elt->year) || (m != elt->month) ||
186.1897 +			      (d != elt->day) || (hh != elt->hours) ||
186.1898 +			      (mm != elt->minutes) || (ss != elt->seconds) ||
186.1899 +			      (z != elt->zoccident) || (zh != elt->zhours) ||
186.1900 +			      (zm != elt->zminutes)) {
186.1901 +			    sprintf (tmp,"mix index data mismatch: %lx",uid);
186.1902 +			    MM_LOG (tmp,ERROR);
186.1903 +			    return NIL;
186.1904 +			  }
186.1905 +			  break;
186.1906 +			}
186.1907 +				/* existing msg with lower UID is expunged */
186.1908 +			else if (uid > elt->private.uid) {
186.1909 +			  if (LOCAL->expok) mail_expunged (stream,nmsgs);
186.1910 +			  else {/* message expunged, but not yet for us */
186.1911 +			    ++nmsgs;
186.1912 +			    elt->private.ghost = T;
186.1913 +			  }
186.1914 +			}
186.1915 +			else {	/* unexpected message record */
186.1916 +			  sprintf (tmp,"mix index UID mismatch (%lx < %lx)",
186.1917 +				   uid,elt->private.uid);
186.1918 +			  MM_LOG (tmp,ERROR);
186.1919 +			  return NIL;
186.1920 +			}
186.1921 +		      }
186.1922 +
186.1923 +				/* time to create a new message? */
186.1924 +		      if (nmsgs > stream->nmsgs) {
186.1925 +				/* defer announcing until later */
186.1926 +			stream->silent = T;
186.1927 +			mail_exists (stream,nmsgs);
186.1928 +			stream->silent = silent;
186.1929 +			(elt = mail_elt (stream,nmsgs))->recent = T;
186.1930 +			elt->private.uid = uid; elt->rfc822_size = size;
186.1931 +			elt->private.spare.data = file;
186.1932 +			elt->private.special.offset = pos;
186.1933 +			elt->private.msg.header.offset = hpos;
186.1934 +			elt->private.msg.header.text.size = hsiz;
186.1935 +			elt->year = y; elt->month = m; elt->day = d;
186.1936 +			elt->hours = hh; elt->minutes = mm;
186.1937 +			elt->seconds = ss; elt->zoccident = z;
186.1938 +			elt->zhours = zh; elt->zminutes = zm;
186.1939 +				/* message in same file? */
186.1940 +			if (curfile == file) {
186.1941 +			  if (pos < curpos) {
186.1942 +			    MESSAGECACHE *plt = mail_elt (stream,elt->msgno-1);
186.1943 +				/* uh-oh, calculate delta? */
186.1944 +			    i = curpos - pos;
186.1945 +			    sprintf (tmp,shortmsg,plt->msgno,plt->private.uid,
186.1946 +				     i,pos,curpos);
186.1947 +				/* possible to fix? */
186.1948 +			    if (!stream->rdonly && LOCAL->expok &&
186.1949 +				(i < plt->rfc822_size)) {
186.1950 +			      plt->rfc822_size -= i;
186.1951 +			      if (plt->rfc822_size <
186.1952 +				  plt->private.msg.header.text.size)
186.1953 +				plt->private.msg.header.text.size =
186.1954 +				  plt->rfc822_size;
186.1955 +			      strcat (tmp,", repaired");
186.1956 +			      indexrepairneeded = T;
186.1957 +			    }
186.1958 +			    MM_LOG (tmp,WARN);
186.1959 +			  }
186.1960 +			}
186.1961 +			else {	/* new file, restart */
186.1962 +			  if (stat (mix_file_data (LOCAL->buf,stream->mailbox,
186.1963 +						   curfile = file),&sbuf)) {
186.1964 +			    sprintf (tmp,"Missing mix data file: %.500s",
186.1965 +				     LOCAL->buf);
186.1966 +			    MM_LOG (tmp,ERROR);
186.1967 +			    return NIL;
186.1968 +			  }
186.1969 +			  curfile = file;
186.1970 +			  curfilesize = sbuf.st_size;
186.1971 +			}
186.1972 +
186.1973 +				/* position of message in file */
186.1974 +			curpos = pos + elt->private.msg.header.offset +
186.1975 +			  elt->rfc822_size;
186.1976 +				/* short file? */
186.1977 +			if (curfilesize < curpos) {
186.1978 +				/* uh-oh, calculate delta? */
186.1979 +			    i = curpos - curfilesize;
186.1980 +			    sprintf (tmp,shortmsg,elt->msgno,elt->private.uid,
186.1981 +				     i,curfilesize,curpos);
186.1982 +				/* possible to fix? */
186.1983 +			    if (!stream->rdonly && LOCAL->expok &&
186.1984 +				(i < elt->rfc822_size)) {
186.1985 +			      elt->rfc822_size -= i;
186.1986 +			      if (elt->rfc822_size <
186.1987 +				  elt->private.msg.header.text.size)
186.1988 +				elt->private.msg.header.text.size =
186.1989 +				  elt->rfc822_size;
186.1990 +			      strcat (tmp,", repaired");
186.1991 +			      indexrepairneeded = T;
186.1992 +			    }
186.1993 +			    MM_LOG (tmp,WARN);
186.1994 +			}
186.1995 +		      }
186.1996 +		      break;
186.1997 +		    }
186.1998 +		    else msg = "expansion";
186.1999 +		  }
186.2000 +		  else msg = "header size";
186.2001 +		}
186.2002 +		else msg = "header position";
186.2003 +	      }
186.2004 +	      else msg = "message position";
186.2005 +	    }
186.2006 +	    else msg = "file#";
186.2007 +	  }
186.2008 +	  sprintf (tmp,"Error in %s in mix index file: %.500s",msg,s);
186.2009 +	  MM_LOG (tmp,ERROR);
186.2010 +	  return NIL;
186.2011 +	default:
186.2012 +	  sprintf (tmp,"Unknown record in mix index file: %.500s",s);
186.2013 +	  MM_LOG (tmp,ERROR);
186.2014 +	  return NIL;
186.2015 +	}
186.2016 +      if (!s) return NIL;	/* barfage from mix_read_record() */
186.2017 +				/* expunge trailing messages not in index */
186.2018 +      if (LOCAL->expok) while (nmsgs < stream->nmsgs)
186.2019 +	mail_expunged (stream,stream->nmsgs);
186.2020 +    }
186.2021 +
186.2022 +				/* repair metadata and index if needed */
186.2023 +    if ((metarepairneeded ? mix_meta_update (stream) : T) &&
186.2024 +	(indexrepairneeded ? mix_index_update (stream,*idxf,NIL) : T)) {
186.2025 +      MESSAGECACHE *elt;
186.2026 +      int fd;
186.2027 +      unsigned long uid,uf,sf,mod;
186.2028 +      char *s;
186.2029 +      int updatep = NIL;
186.2030 +				/* open status file */
186.2031 +      if ((fd = open (LOCAL->status,
186.2032 +		      stream->rdonly ? O_RDONLY : O_RDWR,NIL)) < 0)
186.2033 +	MM_LOG ("Error opening mix status file",ERROR);
186.2034 +				/* acquire exclusive access and FILE */
186.2035 +      else if (!flock (fd,stream->rdonly ? LOCK_SH : LOCK_EX) &&
186.2036 +	       !(statf = fdopen (fd,stream->rdonly ? "rb" : "r+b"))) {
186.2037 +	MM_LOG ("Error obtaining stream on mix status file",ERROR);
186.2038 +	flock (fd,LOCK_UN);	/* relinquish lock */
186.2039 +	close (fd);
186.2040 +      }
186.2041 +				/* get sequence */
186.2042 +      else if (!(i = mix_read_sequence (statf)) ||
186.2043 +	       ((i < LOCAL->statusseq) && stream->nmsgs && (i != 1))) {
186.2044 +	sprintf (LOCAL->buf,
186.2045 +		 "Error in mix status sequence record, i=%lx, seq=%lx",
186.2046 +		 i,LOCAL->statusseq);
186.2047 +	MM_LOG (LOCAL->buf,ERROR);
186.2048 +      }
186.2049 +				/* sequence changed from last time? */
186.2050 +      else if (i != LOCAL->statusseq) {
186.2051 +				/* update sequence, get first elt */
186.2052 +	if (i > LOCAL->statusseq) LOCAL->statusseq = i;
186.2053 +	if (stream->nmsgs) {
186.2054 +	  elt = mail_elt (stream,i = 1);
186.2055 +
186.2056 +				/* read message records */
186.2057 +	  while ((t = s = mix_read_record (statf,LOCAL->buf,LOCAL->buflen,
186.2058 +					   "status")) && *s && (*s++ == ':') &&
186.2059 +		 isxdigit (*s)) {
186.2060 +	    uid = strtoul (s,&s,16);
186.2061 +	    if ((*s++ == ':') && isxdigit (*s)) {
186.2062 +	      uf = strtoul (s,&s,16);
186.2063 +	      if ((*s++ == ':') && isxdigit (*s)) {
186.2064 +		sf = strtoul (s,&s,16);
186.2065 +		if ((*s++ == ':') && isxdigit (*s)) {
186.2066 +		  mod = strtoul (s,&s,16);
186.2067 +				/* ignore expansion values */
186.2068 +		  if (*s++ == ':') {
186.2069 +				/* need to move ahead to next elt? */
186.2070 +		    while ((uid > elt->private.uid) && (i < stream->nmsgs))
186.2071 +		      elt = mail_elt (stream,++i);
186.2072 +				/* update elt if altered */
186.2073 +		    if ((uid == elt->private.uid) &&
186.2074 +			(!elt->valid || (mod != elt->private.mod))) {
186.2075 +		      elt->user_flags = uf;
186.2076 +		      elt->private.mod = mod;
186.2077 +		      elt->seen = (sf & fSEEN) ? T : NIL;
186.2078 +		      elt->deleted = (sf & fDELETED) ? T : NIL;
186.2079 +		      elt->flagged = (sf & fFLAGGED) ? T : NIL;
186.2080 +		      elt->answered = (sf & fANSWERED) ? T : NIL;
186.2081 +		      elt->draft = (sf & fDRAFT) ? T : NIL;
186.2082 +				/* announce if altered existing message */
186.2083 +		      if (elt->valid) MM_FLAGS (stream,elt->msgno);
186.2084 +				/* first time, is old message? */
186.2085 +		      else if (sf & fOLD) {
186.2086 +				/* yes, clear recent and set valid */
186.2087 +			elt->recent = NIL;
186.2088 +			elt->valid = T;
186.2089 +		      }
186.2090 +				/* recent, allowed to update its status? */
186.2091 +		      else if (sflags) {
186.2092 +				/* yes, set valid and check in status */
186.2093 +			elt->valid = T;
186.2094 +			elt->private.mod = mix_modseq (elt->private.mod);
186.2095 +			updatep = T;
186.2096 +		      }
186.2097 +		      /* leave valid unset and recent if sflags not set */
186.2098 +		    }
186.2099 +		    continue;	/* everything looks good */
186.2100 +		  }
186.2101 +		}
186.2102 +	      }
186.2103 +	    }
186.2104 +	    break;		/* error somewhere */
186.2105 +	  }
186.2106 +
186.2107 +	  if (t && *t) {	/* non-null means bogus record */
186.2108 +	    char msg[MAILTMPLEN];
186.2109 +	    sprintf (msg,"Error in mix status file message record%s: %.80s",
186.2110 +		     stream->rdonly ? "" : ", fixing",t);
186.2111 +	    MM_LOG (msg,WARN);
186.2112 +				/* update it if not readonly */
186.2113 +	    if (!stream->rdonly) updatep = T;
186.2114 +	  }
186.2115 +	  if (updatep) {		/* need to update? */
186.2116 +	    LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
186.2117 +	    mix_status_update (stream,statf,LONGT);
186.2118 +	  }
186.2119 +	}
186.2120 +      }
186.2121 +    }
186.2122 +  }
186.2123 +  if (statf) {			/* still happy? */
186.2124 +    unsigned long j;
186.2125 +    stream->silent = silent;	/* now notify upper level */
186.2126 +    mail_exists (stream,stream->nmsgs);
186.2127 +    for (i = 1, j = 0; i <= stream->nmsgs; ++i)
186.2128 +      if (mail_elt (stream,i)->recent) ++j;
186.2129 +    mail_recent (stream,j);
186.2130 +  }
186.2131 +  return statf;
186.2132 +}
186.2133 +
186.2134 +/* MIX metadata file routines */
186.2135 +
186.2136 +/* MIX read metadata
186.2137 + * Accepts: MAIL stream
186.2138 + *	    return pointer for modseq
186.2139 + * Returns: pointer to metadata after modseq or NIL if failure
186.2140 + */
186.2141 +
186.2142 +char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq)
186.2143 +{
186.2144 +  struct stat sbuf;
186.2145 +  char *s;
186.2146 +  char *ret = NIL;
186.2147 +  if (fstat (LOCAL->mfd,&sbuf))
186.2148 +    MM_LOG ("Error obtaining size of mix metatdata file",ERROR);
186.2149 +  if (sbuf.st_size > LOCAL->buflen) {
186.2150 +				/* should be just a few dozen bytes */
186.2151 +    if (sbuf.st_size > METAMAX) fatal ("absurd mix metadata file size");
186.2152 +    fs_give ((void **) &LOCAL->buf);
186.2153 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1);
186.2154 +  }
186.2155 +				/* read current metadata file */
186.2156 +  LOCAL->buf[sbuf.st_size] = '\0';
186.2157 +  if (lseek (LOCAL->mfd,0,L_SET) ||
186.2158 +      (read (LOCAL->mfd,s = LOCAL->buf,sbuf.st_size) != sbuf.st_size))
186.2159 +    MM_LOG ("Error reading mix metadata file",ERROR);
186.2160 +  else if ((*s != 'S') || !isxdigit (s[1]) ||
186.2161 +	   ((*seq = strtoul (s+1,&s,16)) < LOCAL->metaseq) ||
186.2162 +	   (*s++ != '\015') || (*s++ != '\012'))
186.2163 +    MM_LOG ("Error in mix metadata file sequence record",ERROR);
186.2164 +  else ret = s;
186.2165 +  return ret;
186.2166 +}
186.2167 +
186.2168 +/* MIX update metadata
186.2169 + * Accepts: MAIL stream
186.2170 + * Returns: T on success, NIL if error
186.2171 + *
186.2172 + * Index MUST be locked!!
186.2173 + */
186.2174 +
186.2175 +long mix_meta_update (MAILSTREAM *stream)
186.2176 +{
186.2177 +  long ret;
186.2178 +				/* do nothing if stream readonly */
186.2179 +  if (stream->rdonly) ret = LONGT;
186.2180 +  else {
186.2181 +    unsigned char c,*s,*ss,*t;
186.2182 +    unsigned long i;
186.2183 +    /* The worst-case metadata is limited to:
186.2184 +     *    4 * (1 + 8 + 2) + (NUSERFLAGS * (MAXUSERFLAG + 1))
186.2185 +     * which comes out to 1994 octets.  This is much smaller than the normal
186.2186 +     * CHUNKSIZE definition of 64K, and CHUNKSIZE is the smallest size of
186.2187 +     * LOCAL->buf.
186.2188 +     *
186.2189 +     * If more stuff gets added to the metadata, or if you change the value
186.2190 +     * of NUSERFLAGS, MAXUSERFLAG or CHUNKSIZE, be sure to recalculate the
186.2191 +     * above assertation.
186.2192 +     */
186.2193 +    sprintf (LOCAL->buf,SEQFMT,LOCAL->metaseq = mix_modseq (LOCAL->metaseq));
186.2194 +    sprintf (LOCAL->buf + strlen (LOCAL->buf),MTAFMT,
186.2195 +	     stream->uid_validity,stream->uid_last,LOCAL->newmsg);
186.2196 +    for (i = 0, c = 'K', s = ss = LOCAL->buf + strlen (LOCAL->buf);
186.2197 +	 (i < NUSERFLAGS) && (t = stream->user_flags[i]); ++i) {
186.2198 +      if (!*t) fatal ("impossible empty keyword");
186.2199 +      *s++ = c;			/* write delimiter */
186.2200 +      while (*t) *s++ = *t++;	/* write keyword */
186.2201 +      c = ' ';			/* delimiter is now space */
186.2202 +    }
186.2203 +    if (s != ss) {		/* tie off keywords line */
186.2204 +      *s++ = '\015'; *s++ = '\012';
186.2205 +    }
186.2206 +				/* calculate length of metadata */
186.2207 +    if ((i = s - LOCAL->buf) > LOCAL->buflen)
186.2208 +      fatal ("impossible buffer overflow");
186.2209 +    lseek (LOCAL->mfd,0,L_SET);	/* rewind file */
186.2210 +				/* write new metadata */
186.2211 +    ret = (write (LOCAL->mfd,LOCAL->buf,i) == i) ? LONGT : NIL;
186.2212 +    ftruncate (LOCAL->mfd,i);	/* and tie off at that point */
186.2213 +  }
186.2214 +  return ret;
186.2215 +}
186.2216 +
186.2217 +/* MIX index file routines */
186.2218 +
186.2219 +
186.2220 +/* MIX update index
186.2221 + * Accepts: MAIL stream
186.2222 + *	    open FILE
186.2223 + *	    expansion check flag
186.2224 + * Returns: T on success, NIL if error
186.2225 + */
186.2226 +
186.2227 +long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag)
186.2228 +{
186.2229 +  unsigned long i;
186.2230 +  long ret = LONGT;
186.2231 +  if (!stream->rdonly) {	/* do nothing if stream readonly */
186.2232 +    if (flag) {			/* need to do expansion check? */
186.2233 +      char tmp[MAILTMPLEN];
186.2234 +      size_t size;
186.2235 +      struct stat sbuf;
186.2236 +				/* calculate file size we need */
186.2237 +      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
186.2238 +	if (!mail_elt (stream,i)->private.ghost) ++size;
186.2239 +      if (size) {		/* Winston Smith's first dairy entry */
186.2240 +	sprintf (tmp,IXRFMT,0,14,4,4,13,0,0,'+',0,0,0,0,0,0,0);
186.2241 +	size *= strlen (tmp);
186.2242 +      }
186.2243 +				/* calculate file size we need */
186.2244 +      sprintf (tmp,SEQFMT,LOCAL->indexseq);
186.2245 +      size += strlen (tmp);
186.2246 +				/* get current file size */
186.2247 +      if (fstat (fileno (idxf),&sbuf)) {
186.2248 +	MM_LOG ("Error getting size of mix index file",ERROR);
186.2249 +	ret = NIL;
186.2250 +      }
186.2251 +				/* need to write additional space? */
186.2252 +      else if (sbuf.st_size < size) {
186.2253 +	void *buf = fs_get (size -= sbuf.st_size);
186.2254 +	memset (buf,0,size);
186.2255 +	if (fseek (idxf,0,SEEK_END) || (fwrite (buf,1,size,idxf) != size) ||
186.2256 +	    fflush (idxf)) {
186.2257 +	  fseek (idxf,sbuf.st_size,SEEK_SET);
186.2258 +	  ftruncate (fileno (idxf),sbuf.st_size);
186.2259 +	  MM_LOG ("Error extending mix index file",ERROR);
186.2260 +	  ret = NIL;
186.2261 +	}
186.2262 +	fs_give ((void **) &buf);
186.2263 +      }
186.2264 +    }
186.2265 +
186.2266 +    if (ret) {			/* if still good to go */
186.2267 +      rewind (idxf);		/* let's start at the very beginning */
186.2268 +				/* write modseq first */
186.2269 +      fprintf (idxf,SEQFMT,LOCAL->indexseq);
186.2270 +				/* then write all messages */
186.2271 +      for (i = 1; ret && (i <= stream->nmsgs); i++) {
186.2272 +	MESSAGECACHE *elt = mail_elt (stream,i);
186.2273 +	if (!elt->private.ghost)/* only write living messages */
186.2274 +	  fprintf (idxf,IXRFMT,elt->private.uid,
186.2275 +		   elt->year + BASEYEAR,elt->month,elt->day,
186.2276 +		   elt->hours,elt->minutes,elt->seconds,
186.2277 +		   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
186.2278 +		   elt->rfc822_size,elt->private.spare.data,
186.2279 +		   elt->private.special.offset,
186.2280 +		   elt->private.msg.header.offset,
186.2281 +		   elt->private.msg.header.text.size);
186.2282 +	if (ferror (idxf)) {
186.2283 +	  MM_LOG ("Error updating mix index file",ERROR);
186.2284 +	  ret = NIL;
186.2285 +	}
186.2286 +      }
186.2287 +      if (fflush (idxf)) {
186.2288 +	MM_LOG ("Error flushing mix index file",ERROR);
186.2289 +	ret = NIL;
186.2290 +      }
186.2291 +      if (ret) ftruncate (fileno (idxf),ftell (idxf));
186.2292 +    }
186.2293 +  }
186.2294 +  return ret;
186.2295 +}
186.2296 +
186.2297 +/* MIX status file routines */
186.2298 +
186.2299 +
186.2300 +/* MIX update status
186.2301 + * Accepts: MAIL stream
186.2302 + *	    pointer to open FILE
186.2303 + *	    expansion check flag
186.2304 + * Returns: T on success, NIL if error
186.2305 + */
186.2306 +
186.2307 +long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag)
186.2308 +{
186.2309 +  unsigned long i;
186.2310 +  char tmp[MAILTMPLEN];
186.2311 +  long ret = LONGT;
186.2312 +  if (!stream->rdonly) {	/* do nothing if stream readonly */
186.2313 +    if (flag) {			/* need to do expansion check? */
186.2314 +      char tmp[MAILTMPLEN];
186.2315 +      size_t size;
186.2316 +      struct stat sbuf;
186.2317 +				/* calculate file size we need */
186.2318 +      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
186.2319 +	if (!mail_elt (stream,i)->private.ghost) ++size;
186.2320 +      if (size) {		/* number of living messages */
186.2321 +	sprintf (tmp,STRFMT,0,0,0,0);
186.2322 +	size *= strlen (tmp);
186.2323 +      }
186.2324 +      sprintf (tmp,SEQFMT,LOCAL->statusseq);
186.2325 +      size += strlen (tmp);
186.2326 +				/* get current file size */
186.2327 +      if (fstat (fileno (statf),&sbuf)) {
186.2328 +	MM_LOG ("Error getting size of mix status file",ERROR);
186.2329 +	ret = NIL;
186.2330 +      }
186.2331 +				/* need to write additional space? */
186.2332 +      else if (sbuf.st_size < size) {
186.2333 +	void *buf = fs_get (size -= sbuf.st_size);
186.2334 +	memset (buf,0,size);
186.2335 +	if (fseek (statf,0,SEEK_END) || (fwrite (buf,1,size,statf) != size) ||
186.2336 +	    fflush (statf)) {
186.2337 +	  fseek (statf,sbuf.st_size,SEEK_SET);
186.2338 +	  ftruncate (fileno (statf),sbuf.st_size);
186.2339 +	  MM_LOG ("Error extending mix status file",ERROR);
186.2340 +	  ret = NIL;
186.2341 +	}
186.2342 +	fs_give ((void **) &buf);
186.2343 +      }
186.2344 +    }
186.2345 +
186.2346 +    if (ret) {			/* if still good to go */
186.2347 +      rewind (statf);		/* let's start at the very beginning */
186.2348 +				/* write sequence */
186.2349 +      fprintf (statf,SEQFMT,LOCAL->statusseq);
186.2350 +				/* write message status records */
186.2351 +      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
186.2352 +	MESSAGECACHE *elt = mail_elt (stream,i);
186.2353 +				/* make sure all messages have a modseq */
186.2354 +	if (!elt->private.mod) elt->private.mod = LOCAL->statusseq;
186.2355 +	if (!elt->private.ghost)/* only write living messages */
186.2356 +	  fprintf (statf,STRFMT,elt->private.uid,elt->user_flags,
186.2357 +		   (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
186.2358 +		   (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
186.2359 +		   (fDRAFT * elt->draft) + (elt->valid ? fOLD : NIL),
186.2360 +		   elt->private.mod);
186.2361 +	if (ferror (statf)) {
186.2362 +	  sprintf (tmp,"Error updating mix status file: %.80s",
186.2363 +		   strerror (errno));
186.2364 +	  MM_LOG (tmp,ERROR);
186.2365 +	  ret = NIL;
186.2366 +	}
186.2367 +      }
186.2368 +      if (ret && fflush (statf)) {
186.2369 +	MM_LOG ("Error flushing mix status file",ERROR);
186.2370 +	ret = NIL;
186.2371 +      }
186.2372 +      if (ret) ftruncate (fileno (statf),ftell (statf));
186.2373 +    }
186.2374 +  }
186.2375 +  return ret;
186.2376 +}
186.2377 +
186.2378 +/* MIX data file routines */
186.2379 +
186.2380 +
186.2381 +/* MIX open data file
186.2382 + * Accepts: MAIL stream
186.2383 + *	    pointer to returned fd if success
186.2384 + *	    pointer to returned size if success
186.2385 + *	    size of new data to be added
186.2386 + * Returns: open FILE, or NIL if failure
186.2387 + *
186.2388 + * The curend test assumes that the last message of the mailbox is the furthest
186.2389 + * point that the current data file extends, and thus that is all that needs to
186.2390 + * be tested for short file prevention.
186.2391 + */
186.2392 +
186.2393 +FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
186.2394 +		     unsigned long newsize)
186.2395 +{
186.2396 +  FILE *msgf = NIL;
186.2397 +  struct stat sbuf;
186.2398 +  MESSAGECACHE *elt = stream->nmsgs ? mail_elt (stream,stream->nmsgs) : NIL;
186.2399 +  unsigned long curend = (elt && (elt->private.spare.data == LOCAL->newmsg)) ?
186.2400 +    elt->private.special.offset + elt->private.msg.header.offset +
186.2401 +    elt->rfc822_size : 0;
186.2402 +				/* allow create if curend 0 */
186.2403 +  if ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox,LOCAL->newmsg),
186.2404 +		   O_RDWR | (curend ? NIL : O_CREAT),NIL)) >= 0) {
186.2405 +    fstat (*fd,&sbuf);		/* get current file size */
186.2406 +				/* can we use this file? */
186.2407 +    if ((curend <= sbuf.st_size) &&
186.2408 +	(!sbuf.st_size || ((sbuf.st_size + newsize) <= MIXDATAROLL)))
186.2409 +      *size = sbuf.st_size;	/* yes, return current size */
186.2410 +    else {			/* short file or becoming too long */
186.2411 +      if (curend > sbuf.st_size) {
186.2412 +	char tmp[MAILTMPLEN];
186.2413 +	sprintf (tmp,"short mix message file %.08lx (%ld > %ld), rolling",
186.2414 +		 LOCAL->newmsg,curend,sbuf.st_size);
186.2415 +	MM_LOG (tmp,WARN);	/* shouldn't happen */
186.2416 +      }
186.2417 +      close (*fd);		/* roll to a new file */
186.2418 +      while ((*fd = open (mix_file_data
186.2419 +			  (LOCAL->buf,stream->mailbox,
186.2420 +			   LOCAL->newmsg = mix_modseq (LOCAL->newmsg)),
186.2421 +			  O_RDWR | O_CREAT | O_EXCL,sbuf.st_mode)) < 0);
186.2422 +      *size = 0;		/* brand new file */
186.2423 +      fchmod (*fd,sbuf.st_mode);/* with same mode as previous file */
186.2424 +    }
186.2425 +  }
186.2426 +  if (*fd >= 0) {		/* have a data file? */
186.2427 +				/* yes, get stdio and set position */
186.2428 +    if (msgf = fdopen (*fd,"r+b")) fseek (msgf,*size,SEEK_SET);
186.2429 +    else close (*fd);		/* fdopen() failed? */
186.2430 +  }
186.2431 +  return msgf;			/* return results */
186.2432 +}
186.2433 +
186.2434 +/* MIX open sortcache
186.2435 + * Accepts: MAIL stream
186.2436 + * Returns: open FILE, or NIL if failure or could only get readonly sortcache
186.2437 + */
186.2438 +
186.2439 +FILE *mix_sortcache_open (MAILSTREAM *stream)
186.2440 +{
186.2441 +  int fd,refwd;
186.2442 +  unsigned long i,uid,sentdate,fromlen,tolen,cclen,subjlen,msgidlen,reflen;
186.2443 +  char *s,*t,*msg,tmp[MAILTMPLEN];
186.2444 +  MESSAGECACHE *elt;
186.2445 +  SORTCACHE *sc;
186.2446 +  STRINGLIST *sl;
186.2447 +  struct stat sbuf;
186.2448 +  int rdonly = NIL;
186.2449 +  FILE *srtcf = NIL;
186.2450 +  mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
186.2451 +  fstat (LOCAL->mfd,&sbuf);
186.2452 +  if (!stream->nmsgs);		/* do nothing if mailbox empty */
186.2453 +				/* open sortcache file */
186.2454 +  else if (((fd = open (LOCAL->sortcache,O_RDWR|O_CREAT,sbuf.st_mode)) < 0) &&
186.2455 +	   !(rdonly = ((fd = open (LOCAL->sortcache,O_RDONLY,NIL)) >= 0)))
186.2456 +    MM_LOG ("Error opening mix sortcache file",WARN);
186.2457 +				/* acquire lock and FILE */
186.2458 +  else if (!flock (fd,rdonly ? LOCK_SH : LOCK_EX) &&
186.2459 +	   !(srtcf = fdopen (fd,rdonly ? "rb" : "r+b"))) {
186.2460 +    MM_LOG ("Error obtaining stream on mix sortcache file",WARN);
186.2461 +    flock (fd,LOCK_UN);		/* relinquish lock */
186.2462 +    close (fd);
186.2463 +  }
186.2464 +  else if (!(i = mix_read_sequence (srtcf)) || (i < LOCAL->sortcacheseq))
186.2465 +    MM_LOG ("Error in mix sortcache file sequence record",WARN);
186.2466 +				/* sequence changed from last time? */
186.2467 +  else if (i > LOCAL->sortcacheseq) {
186.2468 +    LOCAL->sortcacheseq = i;	/* update sequence */
186.2469 +    while ((s = t = mix_read_record (srtcf,LOCAL->buf,LOCAL->buflen,
186.2470 +				     "sortcache")) && *s &&
186.2471 +	   (msg = "uid") && (*s++ == ':') && isxdigit (*s)) {
186.2472 +      uid = strtoul (s,&s,16);
186.2473 +      if ((*s++ == ':') && isxdigit (*s)) {
186.2474 +	sentdate = strtoul (s,&s,16);
186.2475 +	if ((*s++ == ':') && isxdigit (*s)) {
186.2476 +	  fromlen = strtoul (s,&s,16);
186.2477 +	  if ((*s++ == ':') && isxdigit (*s)) {
186.2478 +	    tolen = strtoul (s,&s,16);
186.2479 +	    if ((*s++ == ':') && isxdigit (*s)) {
186.2480 +	      cclen = strtoul (s,&s,16);
186.2481 +	      if ((*s++ == ':') && ((*s == 'R') || (*s == ' ')) &&
186.2482 +		  isxdigit (s[1])) {
186.2483 +		refwd = (*s++ == 'R') ? T : NIL;
186.2484 +		subjlen = strtoul (s,&s,16);
186.2485 +		if ((*s++ == ':') && isxdigit (*s)) {
186.2486 +		  msgidlen = strtoul (s,&s,16);
186.2487 +		  if ((*s++ == ':') && isxdigit (*s)) {
186.2488 +		    reflen = strtoul (s,&s,16);
186.2489 +				/* ignore expansion values */
186.2490 +		    if (*s++ == ':') {
186.2491 +
186.2492 +		      if (i = mail_msgno (stream,uid)) {
186.2493 +			sc = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
186.2494 +			sc->size = (elt = mail_elt (stream,i))->rfc822_size;
186.2495 +			sc->date = sentdate;
186.2496 +			sc->arrival = elt->day ? mail_longdate (elt) : 1;
186.2497 +			if (refwd) sc->refwd = T;
186.2498 +			if (fromlen) {
186.2499 +			  if (sc->from) fseek (srtcf,fromlen + 2,SEEK_CUR);
186.2500 +			  else if ((getc (srtcf) != 'F') ||
186.2501 +				   (fread (sc->from = (char *) fs_get(fromlen),
186.2502 +					   1,fromlen-1,srtcf) != (fromlen-1))||
186.2503 +				   (sc->from[fromlen-1] = '\0') ||
186.2504 +				   (getc (srtcf) != '\015') ||
186.2505 +				   (getc (srtcf) != '\012')) {
186.2506 +			    msg = "from data";
186.2507 +			    break;
186.2508 +			  }
186.2509 +			}
186.2510 +			if (tolen) {
186.2511 +			  if (sc->to) fseek (srtcf,tolen + 2,SEEK_CUR);
186.2512 +			  else if ((getc (srtcf) != 'T') ||
186.2513 +				   (fread (sc->to = (char *) fs_get (tolen),
186.2514 +					   1,tolen-1,srtcf) != (tolen - 1)) ||
186.2515 +				   (sc->to[tolen-1] = '\0') ||
186.2516 +				   (getc (srtcf) != '\015') ||
186.2517 +				   (getc (srtcf) != '\012')) {
186.2518 +			    msg = "to data";
186.2519 +			    break;
186.2520 +			  }
186.2521 +			}
186.2522 +			if (cclen) {
186.2523 +			  if (sc->cc) fseek (srtcf,cclen + 2,SEEK_CUR);
186.2524 +			  else if ((getc (srtcf) != 'C') ||
186.2525 +				   (fread (sc->cc = (char *) fs_get (cclen),
186.2526 +					   1,cclen-1,srtcf) != (cclen - 1)) ||
186.2527 +				   (sc->cc[cclen-1] = '\0') ||
186.2528 +				   (getc (srtcf) != '\015') ||
186.2529 +				   (getc (srtcf) != '\012')) {
186.2530 +			    msg = "cc data";
186.2531 +			    break;
186.2532 +			  }
186.2533 +			}
186.2534 +			if (subjlen) {
186.2535 +			  if (sc->subject) fseek (srtcf,subjlen + 2,SEEK_CUR);
186.2536 +			  else if ((getc (srtcf) != 'S') ||
186.2537 +				     (fread (sc->subject =
186.2538 +					     (char *) fs_get (subjlen),1,
186.2539 +					     subjlen-1,srtcf) != (subjlen-1))||
186.2540 +				   (sc->subject[subjlen-1] = '\0') ||
186.2541 +				   (getc (srtcf) != '\015') ||
186.2542 +				   (getc (srtcf) != '\012')) {
186.2543 +			    msg = "subject data";
186.2544 +			    break;
186.2545 +			  }
186.2546 +			}
186.2547 +
186.2548 +			if (msgidlen) {
186.2549 +			  if (sc->message_id)
186.2550 +			    fseek (srtcf,msgidlen + 2,SEEK_CUR);
186.2551 +			  else if ((getc (srtcf) != 'M') ||
186.2552 +				   (fread (sc->message_id = 
186.2553 +					   (char *) fs_get (msgidlen),1,
186.2554 +					   msgidlen-1,srtcf) != (msgidlen-1))||
186.2555 +				   (sc->message_id[msgidlen-1] = '\0') ||
186.2556 +				   (getc (srtcf) != '\015') ||
186.2557 +				   (getc (srtcf) != '\012')) {
186.2558 +			    msg = "message-id data";
186.2559 +			    break;
186.2560 +			  }
186.2561 +			}
186.2562 +			if (reflen) {
186.2563 +			  if (sc->references) fseek(srtcf,reflen + 2,SEEK_CUR);
186.2564 +				/* make sure it fits */
186.2565 +			  else {
186.2566 +			    if (reflen >= LOCAL->buflen) {
186.2567 +			      fs_give ((void **) &LOCAL->buf);
186.2568 +			      LOCAL->buf = (char *)
186.2569 +				fs_get ((LOCAL->buflen = reflen) + 1);
186.2570 +			      }
186.2571 +			    if ((getc (srtcf) != 'R') ||
186.2572 +				(fread (LOCAL->buf,1,reflen-1,srtcf) !=
186.2573 +				 (reflen - 1)) ||
186.2574 +				(LOCAL->buf[reflen-1] = '\0') ||
186.2575 +				(getc (srtcf) != '\015') ||
186.2576 +				(getc (srtcf) != '\012')) {
186.2577 +			      msg = "references data";
186.2578 +			      break;
186.2579 +			    }
186.2580 +			    for (s = LOCAL->buf,sl = NIL,
186.2581 +				   sc->references = mail_newstringlist ();
186.2582 +				 s && *s; s += i + 1) {
186.2583 +			      if ((i = strtoul (s,&s,16)) && (*s++ == ':') &&
186.2584 +				  (s[i] == ':')) {
186.2585 +				if (sl) sl = sl->next = mail_newstringlist();
186.2586 +				else sl = sc->references;
186.2587 +				s[i] = '\0';
186.2588 +				sl->text.data = cpystr (s);
186.2589 +				sl->text.size = i;
186.2590 +			      }
186.2591 +			      else s = NIL;
186.2592 +			    }
186.2593 +			    if (!s || *s ||
186.2594 +				(s != ((char *) LOCAL->buf + reflen - 1))) {
186.2595 +			      msg = "references length consistency check";
186.2596 +			      break;
186.2597 +			    }
186.2598 +			  }
186.2599 +			}
186.2600 +		      }
186.2601 +
186.2602 +				/* UID not found, ignore this message */
186.2603 +		      else fseek (srtcf,((fromlen ? fromlen + 2 : 0) +
186.2604 +					 (tolen ? tolen + 2 : 0) +
186.2605 +					 (cclen ? cclen + 2 : 0) +
186.2606 +					 (subjlen ? subjlen + 2 : 0) +
186.2607 +					 (msgidlen ? msgidlen + 2 : 0) +
186.2608 +					 (reflen ? reflen + 2 : 0)),
186.2609 +				  SEEK_CUR);
186.2610 +		      continue;
186.2611 +		    }
186.2612 +		    else msg = "expansion";
186.2613 +		  }
186.2614 +		  else msg = "references";
186.2615 +		}
186.2616 +		else msg = "message-id";
186.2617 +	      }
186.2618 +	      else msg = "subject";
186.2619 +	    }
186.2620 +	    else msg = "cc";
186.2621 +	  }
186.2622 +	  else msg = "to";
186.2623 +	}
186.2624 +	else msg = "from";
186.2625 +      }
186.2626 +      else msg = "sentdate";
186.2627 +      break;			/* error somewhere */
186.2628 +    }
186.2629 +    if (!t || *t) {		/* error detected? */
186.2630 +      if (t) {			/* non-null means bogus record */
186.2631 +	sprintf (tmp,"Error in %s in mix sortcache record: %.500s",msg,t);
186.2632 +	MM_LOG (tmp,WARN);
186.2633 +      }
186.2634 +      fclose (srtcf);		/* either way, must punt */
186.2635 +      srtcf = NIL;
186.2636 +    }
186.2637 +  }
186.2638 +  if (rdonly && srtcf) {	/* can't update if readonly */
186.2639 +    unlink (LOCAL->sortcache);	/* try deleting it */
186.2640 +    fclose (srtcf);		/* so close it and return as if error */
186.2641 +    srtcf = NIL;
186.2642 +  }
186.2643 +  else fchmod (fd,sbuf.st_mode);
186.2644 +  return srtcf;
186.2645 +}
186.2646 +
186.2647 +/* MIX update and close sortcache
186.2648 + * Accepts: MAIL stream
186.2649 + *	    pointer to open FILE (if FILE is NIL, do nothing)
186.2650 + * Returns: T on success, NIL on error
186.2651 + */
186.2652 +
186.2653 +long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache)
186.2654 +{
186.2655 +  FILE *f = *sortcache;
186.2656 +  long ret = LONGT;
186.2657 +  if (f) {			/* ignore if no file */
186.2658 +    unsigned long i,j;
186.2659 +    mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
186.2660 +    for (i = 1; (i <= stream->nmsgs) &&
186.2661 +	   !((SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE))->dirty; ++i);
186.2662 +    if (i <= stream->nmsgs) {	/* only update if some entry is dirty */
186.2663 +      rewind (f);		/* let's start at the very beginning */
186.2664 +				/* write sequence */
186.2665 +      fprintf (f,SEQFMT,LOCAL->sortcacheseq = mix_modseq(LOCAL->sortcacheseq));
186.2666 +      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
186.2667 +	MESSAGECACHE *elt = mail_elt (stream,i);
186.2668 +	SORTCACHE *s = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
186.2669 +	STRINGLIST *sl;
186.2670 +	s->dirty = NIL;		/* no longer dirty */
186.2671 +	if (sl = s->references)	/* count length of references */
186.2672 +	  for (j = 1; sl && sl->text.data; sl = sl->next)
186.2673 +	    j += 10 + sl->text.size;
186.2674 +	else j = 0;		/* no references yet */
186.2675 +	fprintf (f,SCRFMT,elt->private.uid,s->date,
186.2676 +		 s->from ? strlen (s->from) + 1 : 0,
186.2677 +		 s->to ? strlen (s->to) + 1 : 0,s->cc ? strlen (s->cc) + 1 : 0,
186.2678 +		 s->refwd ? 'R' : ' ',s->subject ? strlen (s->subject) + 1: 0,
186.2679 +		 s->message_id ? strlen (s->message_id) + 1 : 0,j);
186.2680 +	if (s->from) fprintf (f,"F%s\015\012",s->from);
186.2681 +	if (s->to) fprintf (f,"T%s\015\012",s->to);
186.2682 +	if (s->cc) fprintf (f,"C%s\015\012",s->cc);
186.2683 +	if (s->subject) fprintf (f,"S%s\015\012",s->subject);
186.2684 +	if (s->message_id) fprintf (f,"M%s\015\012",s->message_id);
186.2685 +	if (j) {		/* any references to write? */
186.2686 +	  fputc ('R',f);	/* yes, do so */
186.2687 +	  for (sl = s->references; sl && sl->text.data; sl = sl->next)
186.2688 +	    fprintf (f,"%08lx:%s:",sl->text.size,sl->text.data);
186.2689 +	  fputs ("\015\012",f);
186.2690 +	}
186.2691 +	if (ferror (f)) {
186.2692 +	  MM_LOG ("Error updating mix sortcache file",WARN);
186.2693 +	  ret = NIL;
186.2694 +	}
186.2695 +      }
186.2696 +      if (ret && fflush (f)) {
186.2697 +	MM_LOG ("Error flushing mix sortcache file",WARN);
186.2698 +	ret = NIL;
186.2699 +      }
186.2700 +      if (ret) ftruncate (fileno (f),ftell (f));
186.2701 +    }
186.2702 +    if (fclose (f)) {
186.2703 +      MM_LOG ("Error closing mix sortcache file",WARN);
186.2704 +      ret = NIL;
186.2705 +    }
186.2706 +  }
186.2707 +  return ret;
186.2708 +}
186.2709 +
186.2710 +/* MIX generic file routines */
186.2711 +
186.2712 +/* MIX read record
186.2713 + * Accepts: open FILE
186.2714 + *	    buffer
186.2715 + *	    buffer length
186.2716 + *	    record type
186.2717 + * Returns: buffer if success, else NIL (zero-length buffer means EOF)
186.2718 + */
186.2719 +
186.2720 +char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type)
186.2721 +{
186.2722 +  char *s,tmp[MAILTMPLEN];
186.2723 +				/* ensure string tied off */
186.2724 +  buf[buflen-2] = buf[buflen-1] = '\0';
186.2725 +  while (fgets (buf,buflen-1,f)) {
186.2726 +    if (s = strchr (buf,'\012')) {
186.2727 +      if ((s != buf) && (s[-1] == '\015')) --s;
186.2728 +      *s = '\0';		/* tie off buffer */
186.2729 +      if (s != buf) return buf;	/* return if non-empty buffer */
186.2730 +      sprintf (tmp,"Empty mix %s record",type);
186.2731 +      MM_LOG (tmp,WARN);
186.2732 +    }
186.2733 +    else if (buf[buflen-2]) {	/* overlong record is bad news */
186.2734 +      sprintf (tmp,"Oversize mix %s record: %.512s",type,buf);
186.2735 +      MM_LOG (tmp,ERROR);
186.2736 +      return NIL;
186.2737 +    }
186.2738 +    else {
186.2739 +      sprintf (tmp,"Truncated mix %s record: %.512s",type,buf);
186.2740 +      MM_LOG (tmp,WARN);
186.2741 +      return buf;		/* pass to caller anyway */
186.2742 +    }
186.2743 +  }
186.2744 +  buf[0] = '\0';		/* return empty buffer on EOF */
186.2745 +  return buf;
186.2746 +}
186.2747 +
186.2748 +/* MIX read sequence record
186.2749 + * Accepts: open FILE
186.2750 + * Returns: sequence value, or NIL if failure
186.2751 + */
186.2752 +
186.2753 +unsigned long mix_read_sequence (FILE *f)
186.2754 +{
186.2755 +  unsigned long ret;
186.2756 +  char *s,tmp[MAILTMPLEN];
186.2757 +  if (!mix_read_record (f,tmp,MAILTMPLEN-1,"sequence")) return NIL;
186.2758 +  switch (tmp[0]) {		/* examine record */
186.2759 +  case '\0':			/* end of file */
186.2760 +    ret = 1;			/* start a new sequence regime */
186.2761 +    break;
186.2762 +  case 'S':			/* sequence record */
186.2763 +    if (isxdigit (tmp[1])) {	/* must be followed by hex value */
186.2764 +      ret = strtoul (tmp+1,&s,16);
186.2765 +      if (!*s) break;		/* and nothing more */
186.2766 +    }
186.2767 +				/* drop into default case */
186.2768 +  default:			/* anything else is an error */
186.2769 +    return NIL;			/* return error */
186.2770 +  }
186.2771 +  return ret;
186.2772 +}
186.2773 +
186.2774 +/* MIX internal routines */
186.2775 +
186.2776 +
186.2777 +/* MIX mail build directory name
186.2778 + * Accepts: destination string
186.2779 + *          source
186.2780 + * Returns: destination or empty string if error
186.2781 + */
186.2782 +
186.2783 +char *mix_dir (char *dst,char *name)
186.2784 +{
186.2785 +  char *s;
186.2786 +				/* empty string if mailboxfile fails */
186.2787 +  if (!mailboxfile (dst,name)) *dst = '\0';
186.2788 +				/* driver-selected INBOX  */
186.2789 +  else if (!*dst) mailboxfile (dst,"~/INBOX");
186.2790 +				/* tie off unnecessary trailing / */
186.2791 +  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
186.2792 +  return dst;
186.2793 +}
186.2794 +
186.2795 +
186.2796 +/* MIX mail build file name
186.2797 + * Accepts: destination string
186.2798 + *	    directory name
186.2799 + *	    file name
186.2800 + * Returns: destination
186.2801 + */
186.2802 +
186.2803 +char *mix_file (char *dst,char *dir,char *name)
186.2804 +{
186.2805 +  sprintf (dst,"%.500s/%.80s%.80s",dir,MIXNAME,name);
186.2806 +  return dst;
186.2807 +}
186.2808 +
186.2809 +
186.2810 +/* MIX mail build file name from data file number
186.2811 + * Accepts: destination string
186.2812 + *	    directory name
186.2813 + *	    data file number
186.2814 + * Returns: destination
186.2815 + */
186.2816 +
186.2817 +char *mix_file_data (char *dst,char *dir,unsigned long data)
186.2818 +{
186.2819 +  char tmp[MAILTMPLEN];
186.2820 +  if (data) sprintf (tmp,"%08lx",data);
186.2821 +  else tmp[0] = '\0';		/* compatibility with experimental version */
186.2822 +  return mix_file (dst,dir,tmp);
186.2823 +}
186.2824 +
186.2825 +/* MIX mail get new modseq
186.2826 + * Accepts: old modseq
186.2827 + * Returns: new modseq value
186.2828 + */
186.2829 +
186.2830 +unsigned long mix_modseq (unsigned long oldseq)
186.2831 +{
186.2832 +				/* normally time now */
186.2833 +  unsigned long ret = (unsigned long) time (NIL);
186.2834 +				/* ensure that modseq doesn't go backwards */
186.2835 +  if (ret <= oldseq) ret = oldseq + 1;
186.2836 +  return ret;
186.2837 +}
   187.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   187.2 +++ b/src/osdep/amiga/mkauths	Mon Sep 14 15:17:45 2009 +0900
   187.3 @@ -0,0 +1,40 @@
   187.4 +#!/bin/sh
   187.5 +# ========================================================================
   187.6 +# Copyright 1988-2006 University of Washington
   187.7 +#
   187.8 +# Licensed under the Apache License, Version 2.0 (the "License");
   187.9 +# you may not use this file except in compliance with the License.
  187.10 +# You may obtain a copy of the License at
  187.11 +#
  187.12 +#     http://www.apache.org/licenses/LICENSE-2.0
  187.13 +#
  187.14 +# 
  187.15 +# ========================================================================
  187.16 +
  187.17 +# Program:	Authenticator Linkage Generator
  187.18 +#
  187.19 +# Author:	Mark Crispin
  187.20 +#		Networks and Distributed Computing
  187.21 +#		Computing & Communications
  187.22 +#		University of Washington
  187.23 +#		Administration Building, AG-44
  187.24 +#		Seattle, WA  98195
  187.25 +#		Internet: MRC@CAC.Washington.EDU
  187.26 +#
  187.27 +# Date:		5 December 1995
  187.28 +# Last Edited:	30 August 2006
  187.29 +
  187.30 +# Erase old authenticators list
  187.31 +rm -f auths.c
  187.32 +touch auths.c
  187.33 +
  187.34 +# Now define the new list
  187.35 +for authenticator
  187.36 + do
  187.37 +  if [ -f Makefile."$authenticator" ]; then
  187.38 +    make -f Makefile."$authenticator" `cat SPECIALS`
  187.39 +  fi
  187.40 +  echo "extern AUTHENTICATOR auth_"$authenticator";" >> linkage.h
  187.41 +  echo "  auth_link (&auth_"$authenticator");		/* link in the $authenticator authenticator */" | cat >> linkage.c
  187.42 +  echo "#include \"auth_"$authenticator".c\"" >> auths.c
  187.43 +done
   188.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   188.2 +++ b/src/osdep/amiga/mmdf.c	Mon Sep 14 15:17:45 2009 +0900
   188.3 @@ -0,0 +1,2549 @@
   188.4 +/* ========================================================================
   188.5 + * Copyright 1988-2008 University of Washington
   188.6 + *
   188.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   188.8 + * you may not use this file except in compliance with the License.
   188.9 + * You may obtain a copy of the License at
  188.10 + *
  188.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  188.12 + *
  188.13 + * 
  188.14 + * ========================================================================
  188.15 + */
  188.16 +
  188.17 +/*
  188.18 + * Program:	MMDF mail routines
  188.19 + *
  188.20 + * Author:	Mark Crispin
  188.21 + *		UW Technology
  188.22 + *		University of Washington
  188.23 + *		Seattle, WA  98195
  188.24 + *		Internet: MRC@Washington.EDU
  188.25 + *
  188.26 + * Date:	20 December 1989
  188.27 + * Last Edited:	27 March 2008
  188.28 + */
  188.29 +
  188.30 +
  188.31 +#include <stdio.h>
  188.32 +#include <ctype.h>
  188.33 +#include <errno.h>
  188.34 +extern int errno;		/* just in case */
  188.35 +#include <signal.h>
  188.36 +#include "mail.h"
  188.37 +#include "osdep.h"
  188.38 +#include <time.h>
  188.39 +#include <sys/stat.h>
  188.40 +#include "pseudo.h"
  188.41 +#include "fdstring.h"
  188.42 +#include "misc.h"
  188.43 +#include "dummy.h"
  188.44 +
  188.45 +/* Supposedly, this page has everything the MMDF driver needs to know about
  188.46 + * the MMDF delimiter.  By changing these macros, the MMDF driver should
  188.47 + * change with it.  Note that if you change the length of MMDFHDRTXT you
  188.48 + * also need to change the ISMMDF and RETIFMMDFWRD macros to reflect the new
  188.49 + * size.
  188.50 + */
  188.51 +
  188.52 +
  188.53 +/* Useful MMDF constants */
  188.54 +
  188.55 +#define MMDFCHR '\01'		/* MMDF character */
  188.56 +#define MMDFCHRS 0x01010101	/* MMDF header character spread in a word */
  188.57 +				/* MMDF header text */
  188.58 +#define MMDFHDRTXT "\01\01\01\01\n"
  188.59 +				/* length of MMDF header text */
  188.60 +#define MMDFHDRLEN (sizeof (MMDFHDRTXT) - 1)
  188.61 +
  188.62 +
  188.63 +/* Validate MMDF header
  188.64 + * Accepts: pointer to candidate string to validate as an MMDF header
  188.65 + * Returns: T if valid; else NIL
  188.66 + */
  188.67 +
  188.68 +#define ISMMDF(s)							\
  188.69 +  ((*(s) == MMDFCHR) && ((s)[1] == MMDFCHR) && ((s)[2] == MMDFCHR) &&	\
  188.70 +   ((s)[3] == MMDFCHR) && ((s)[4] == '\n'))
  188.71 +
  188.72 +
  188.73 +/* Return if a 32-bit word has the start of an MMDF header
  188.74 + * Accepts: pointer to word of four bytes to validate as an MMDF header
  188.75 + * Returns: pointer to MMDF header, else proceeds
  188.76 + */
  188.77 +
  188.78 +#define RETIFMMDFWRD(s) {						\
  188.79 +  if (s[3] == MMDFCHR) {						\
  188.80 +    if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == MMDFCHR) &&	\
  188.81 +	(s[7] == '\n')) return s + 3;					\
  188.82 +    else if (s[2] == MMDFCHR) {						\
  188.83 +      if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == '\n'))	\
  188.84 +	return s + 2;							\
  188.85 +      else if (s[1] == MMDFCHR) {					\
  188.86 +	if ((s[4] == MMDFCHR) && (s[5] == '\n')) return s + 1;		\
  188.87 +	else if ((*s == MMDFCHR) && (s[4] == '\n')) return s;		\
  188.88 +      }									\
  188.89 +    }									\
  188.90 +  }									\
  188.91 +}
  188.92 +
  188.93 +/* Validate line
  188.94 + * Accepts: pointer to candidate string to validate as a From header
  188.95 + *	    return pointer to end of date/time field
  188.96 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  188.97 + *	    return pointer to offset from t of time zone (if non-zero)
  188.98 + * Returns: t,ti,zn set if valid From string, else ti is NIL
  188.99 + */
 188.100 +
 188.101 +#define VALID(s,x,ti,zn) {						\
 188.102 +  ti = 0;								\
 188.103 +  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
 188.104 +      (s[4] == ' ')) {							\
 188.105 +    for (x = s + 5; *x && *x != '\n'; x++);				\
 188.106 +    if (*x) {								\
 188.107 +      if (x - s >= 41) {						\
 188.108 +	for (zn = -1; x[zn] != ' '; zn--);				\
 188.109 +	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
 188.110 +	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
 188.111 +	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
 188.112 +	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
 188.113 +	  x += zn - 12;							\
 188.114 +      }									\
 188.115 +      if (x - s >= 27) {						\
 188.116 +	if (x[-5] == ' ') {						\
 188.117 +	  if (x[-8] == ':') zn = 0,ti = -5;				\
 188.118 +	  else if (x[-9] == ' ') ti = zn = -9;				\
 188.119 +	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
 188.120 +	    ti = zn = -11;						\
 188.121 +	}								\
 188.122 +	else if (x[-4] == ' ') {					\
 188.123 +	  if (x[-9] == ' ') zn = -4,ti = -9;				\
 188.124 +	}								\
 188.125 +	else if (x[-6] == ' ') {					\
 188.126 +	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
 188.127 +	    zn = -6,ti = -11;						\
 188.128 +	}								\
 188.129 +	if (ti && !((x[ti - 3] == ':') &&				\
 188.130 +		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
 188.131 +		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
 188.132 +		    (x[ti - 11] == ' '))) ti = 0;			\
 188.133 +      }									\
 188.134 +    }									\
 188.135 +  }									\
 188.136 +}
 188.137 +
 188.138 +/* You are not expected to understand this macro, but read the next page if
 188.139 + * you are not faint of heart.
 188.140 + *
 188.141 + * Known formats to the VALID macro are:
 188.142 + *		From user Wed Dec  2 05:53 1992
 188.143 + * BSD		From user Wed Dec  2 05:53:22 1992
 188.144 + * SysV		From user Wed Dec  2 05:53 PST 1992
 188.145 + * rn		From user Wed Dec  2 05:53:22 PST 1992
 188.146 + *		From user Wed Dec  2 05:53 -0700 1992
 188.147 + * emacs	From user Wed Dec  2 05:53:22 -0700 1992
 188.148 + *		From user Wed Dec  2 05:53 1992 PST
 188.149 + *		From user Wed Dec  2 05:53:22 1992 PST
 188.150 + *		From user Wed Dec  2 05:53 1992 -0700
 188.151 + * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
 188.152 + *
 188.153 + * Plus all of the above with `` remote from xxx'' after it. Thank you very
 188.154 + * much, smail and Solaris, for making my life considerably more complicated.
 188.155 + */
 188.156 +
 188.157 +/*
 188.158 + * What?  You want to understand the VALID macro anyway?  Alright, since you
 188.159 + * insist.  Actually, it isn't really all that difficult, provided that you
 188.160 + * take it step by step.
 188.161 + *
 188.162 + * Line 1	Initializes the return ti value to failure (0);
 188.163 + * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
 188.164 + * Lines 4-5	Validates that there is an end of line and points x at it.
 188.165 + * Lines 6-13	First checks to see if the line is at least 41 characters long.
 188.166 + *		If so, it scans backwards to find the rightmost space.  From
 188.167 + *		that point, it scans backwards to see if the string matches
 188.168 + *		`` remote from''.  If so, it sets x to point to the space at
 188.169 + *		the start of the string.
 188.170 + * Line 14	Makes sure that there are at least 27 characters in the line.
 188.171 + * Lines 15-20	Checks if the date/time ends with the year (there is a space
 188.172 + *		five characters back).  If there is a colon three characters
 188.173 + *		further back, there is no timezone field, so zn is set to 0
 188.174 + *		and ti is set in front of the year.  Otherwise, there must
 188.175 + *		either to be a space four characters back for a three-letter
 188.176 + *		timezone, or a space six characters back followed by a + or -
 188.177 + *		for a numeric timezone; in either case, zn and ti become the
 188.178 + *		offset of the space immediately before it.
 188.179 + * Lines 21-23	Are the failure case for line 14.  If there is a space four
 188.180 + *		characters back, it is a three-letter timezone; there must be a
 188.181 + *		space for the year nine characters back.  zn is the zone
 188.182 + *		offset; ti is the offset of the space.
 188.183 + * Lines 24-27	Are the failure case for line 20.  If there is a space six
 188.184 + *		characters back, it is a numeric timezone; there must be a
 188.185 + *		space eleven characters back and a + or - five characters back.
 188.186 + *		zn is the zone offset; ti is the offset of the space.
 188.187 + * Line 28-31	If ti is valid, make sure that the string before ti is of the
 188.188 + *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
 188.189 + *		invalidate ti.  There must be a colon three characters back
 188.190 + *		and a space six or nine	characters back (depending upon
 188.191 + *		whether or not the character six characters back is a colon).
 188.192 + *		There must be a space three characters further back (in front
 188.193 + *		of the day), one seven characters back (in front of the month),
 188.194 + *		and one eleven characters back (in front of the day of week).
 188.195 + *		ti is set to be the offset of the space before the time.
 188.196 + *
 188.197 + * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
 188.198 + * newer pipelined machines it is faster being open-coded than it would be if
 188.199 + * subroutines are called.
 188.200 + *
 188.201 + * Why does it scan backwards from the end of the line, instead of doing the
 188.202 + * much easier forward scan?  There is no deterministic way to parse the
 188.203 + * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
 188.204 + * see if unquoted spaces were possible.  They are, and I've encountered enough
 188.205 + * evil mail to be totally unwilling to trust that ``it will never happen''.
 188.206 + */
 188.207 +
 188.208 +/* Build parameters */
 188.209 +
 188.210 +#define KODRETRY 15		/* kiss-of-death retry in seconds */
 188.211 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
 188.212 +
 188.213 +
 188.214 +/* MMDF I/O stream local data */
 188.215 +
 188.216 +typedef struct mmdf_local {
 188.217 +  unsigned int dirty : 1;	/* disk copy needs updating */
 188.218 +  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
 188.219 +  unsigned int pseudo : 1;	/* uses a pseudo message */
 188.220 +  unsigned int appending : 1;	/* don't mark new messages as old */
 188.221 +  int fd;			/* mailbox file descriptor */
 188.222 +  int ld;			/* lock file descriptor */
 188.223 +  char *lname;			/* lock file name */
 188.224 +  off_t filesize;		/* file size parsed */
 188.225 +  time_t filetime;		/* last file time */
 188.226 +  unsigned char *buf;		/* temporary buffer */
 188.227 +  unsigned long buflen;		/* current size of temporary buffer */
 188.228 +  unsigned long uid;		/* current text uid */
 188.229 +  SIZEDTEXT text;		/* current text */
 188.230 +  unsigned long textlen;	/* current text length */
 188.231 +  char *line;			/* returned line */
 188.232 +  char *linebuf;		/* line readin buffer */
 188.233 +  unsigned long linebuflen;	/* current line readin buffer length */
 188.234 +} MMDFLOCAL;
 188.235 +
 188.236 +
 188.237 +/* Convenient access to local data */
 188.238 +
 188.239 +#define LOCAL ((MMDFLOCAL *) stream->local)
 188.240 +
 188.241 +
 188.242 +/* MMDF protected file structure */
 188.243 +
 188.244 +typedef struct mmdf_file {
 188.245 +  MAILSTREAM *stream;		/* current stream */
 188.246 +  off_t curpos;			/* current file position */
 188.247 +  off_t protect;		/* protected position */
 188.248 +  off_t filepos;		/* current last written file position */
 188.249 +  char *buf;			/* overflow buffer */
 188.250 +  size_t buflen;		/* current overflow buffer length */
 188.251 +  char *bufpos;			/* current buffer position */
 188.252 +} MMDFFILE;
 188.253 +
 188.254 +/* Function prototypes */
 188.255 +
 188.256 +DRIVER *mmdf_valid (char *name);
 188.257 +long mmdf_isvalid (char *name,char *tmp);
 188.258 +long mmdf_isvalid_fd (int fd,char *tmp);
 188.259 +void *mmdf_parameters (long function,void *value);
 188.260 +void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 188.261 +void mmdf_list (MAILSTREAM *stream,char *ref,char *pat);
 188.262 +void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat);
 188.263 +long mmdf_create (MAILSTREAM *stream,char *mailbox);
 188.264 +long mmdf_delete (MAILSTREAM *stream,char *mailbox);
 188.265 +long mmdf_rename (MAILSTREAM *stream,char *old,char *newname);
 188.266 +MAILSTREAM *mmdf_open (MAILSTREAM *stream);
 188.267 +void mmdf_close (MAILSTREAM *stream,long options);
 188.268 +char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
 188.269 +		   unsigned long *length,long flags);
 188.270 +long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 188.271 +char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 188.272 +		      unsigned long *length,long flags);
 188.273 +void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 188.274 +long mmdf_ping (MAILSTREAM *stream);
 188.275 +void mmdf_check (MAILSTREAM *stream);
 188.276 +long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options);
 188.277 +long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 188.278 +long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 188.279 +int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 188.280 +		     STRING *msg);
 188.281 +int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
 188.282 +
 188.283 +void mmdf_abort (MAILSTREAM *stream);
 188.284 +char *mmdf_file (char *dst,char *name);
 188.285 +int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
 188.286 +void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
 188.287 +int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
 188.288 +char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
 188.289 +unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr);
 188.290 +unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
 188.291 +			    unsigned long uid,long flag);
 188.292 +long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
 188.293 +		   long flags);
 188.294 +long mmdf_extend (MAILSTREAM *stream,unsigned long size);
 188.295 +void mmdf_write (MMDFFILE *f,char *s,unsigned long i);
 188.296 +void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size);
 188.297 +
 188.298 +/* MMDF mail routines */
 188.299 +
 188.300 +
 188.301 +/* Driver dispatch used by MAIL */
 188.302 +
 188.303 +DRIVER mmdfdriver = {
 188.304 +  "mmdf",			/* driver name */
 188.305 +				/* driver flags */
 188.306 +  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
 188.307 +  (DRIVER *) NIL,		/* next driver */
 188.308 +  mmdf_valid,			/* mailbox is valid for us */
 188.309 +  mmdf_parameters,		/* manipulate parameters */
 188.310 +  mmdf_scan,			/* scan mailboxes */
 188.311 +  mmdf_list,			/* list mailboxes */
 188.312 +  mmdf_lsub,			/* list subscribed mailboxes */
 188.313 +  NIL,				/* subscribe to mailbox */
 188.314 +  NIL,				/* unsubscribe from mailbox */
 188.315 +  mmdf_create,			/* create mailbox */
 188.316 +  mmdf_delete,			/* delete mailbox */
 188.317 +  mmdf_rename,			/* rename mailbox */
 188.318 +  mail_status_default,		/* status of mailbox */
 188.319 +  mmdf_open,			/* open mailbox */
 188.320 +  mmdf_close,			/* close mailbox */
 188.321 +  NIL,				/* fetch message "fast" attributes */
 188.322 +  NIL,				/* fetch message flags */
 188.323 +  NIL,				/* fetch overview */
 188.324 +  NIL,				/* fetch message envelopes */
 188.325 +  mmdf_header,			/* fetch message header */
 188.326 +  mmdf_text,			/* fetch message text */
 188.327 +  NIL,				/* fetch partial message text */
 188.328 +  NIL,				/* unique identifier */
 188.329 +  NIL,				/* message number */
 188.330 +  NIL,				/* modify flags */
 188.331 +  mmdf_flagmsg,			/* per-message modify flags */
 188.332 +  NIL,				/* search for message based on criteria */
 188.333 +  NIL,				/* sort messages */
 188.334 +  NIL,				/* thread messages */
 188.335 +  mmdf_ping,			/* ping mailbox to see if still alive */
 188.336 +  mmdf_check,			/* check for new messages */
 188.337 +  mmdf_expunge,			/* expunge deleted messages */
 188.338 +  mmdf_copy,			/* copy messages to another mailbox */
 188.339 +  mmdf_append,			/* append string message to mailbox */
 188.340 +  NIL				/* garbage collect stream */
 188.341 +};
 188.342 +
 188.343 +				/* prototype stream */
 188.344 +MAILSTREAM mmdfproto = {&mmdfdriver};
 188.345 +
 188.346 +char *mmdfhdr = MMDFHDRTXT;	/* MMDF header */
 188.347 +
 188.348 +/* MMDF mail validate mailbox
 188.349 + * Accepts: mailbox name
 188.350 + * Returns: our driver if name is valid, NIL otherwise
 188.351 + */
 188.352 +
 188.353 +DRIVER *mmdf_valid (char *name)
 188.354 +{
 188.355 +  char tmp[MAILTMPLEN];
 188.356 +  return mmdf_isvalid (name,tmp) ? &mmdfdriver : NIL;
 188.357 +}
 188.358 +
 188.359 +
 188.360 +/* MMDF mail test for valid mailbox name
 188.361 + * Accepts: mailbox name
 188.362 + *	    scratch buffer
 188.363 + * Returns: T if valid, NIL otherwise
 188.364 + */
 188.365 +
 188.366 +long mmdf_isvalid (char *name,char *tmp)
 188.367 +{
 188.368 +  int fd;
 188.369 +  int ret = NIL;
 188.370 +  char *t,file[MAILTMPLEN];
 188.371 +  struct stat sbuf;
 188.372 +  time_t tp[2];
 188.373 +  errno = EINVAL;		/* assume invalid argument */
 188.374 +				/* must be non-empty file */
 188.375 +  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
 188.376 +    if (!sbuf.st_size)errno = 0;/* empty file */
 188.377 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 188.378 +				/* error -1 for invalid format */
 188.379 +      if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1;
 188.380 +      close (fd);		/* close the file */
 188.381 +				/* \Marked status? */
 188.382 +      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
 188.383 +	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 188.384 +	tp[1] = sbuf.st_mtime;
 188.385 +	utime (file,tp);	/* set the times */
 188.386 +      }
 188.387 +    }
 188.388 +  }
 188.389 +  return ret;			/* return what we should */
 188.390 +}
 188.391 +
 188.392 +/* MMDF mail test for valid mailbox
 188.393 + * Accepts: file descriptor
 188.394 + *	    scratch buffer
 188.395 + * Returns: T if valid, NIL otherwise
 188.396 + */
 188.397 +
 188.398 +long mmdf_isvalid_fd (int fd,char *tmp)
 188.399 +{
 188.400 +  int ret = NIL;
 188.401 +  memset (tmp,'\0',MAILTMPLEN);
 188.402 +  if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL;
 188.403 +  return ret;			/* return what we should */
 188.404 +}
 188.405 +
 188.406 +
 188.407 +/* MMDF manipulate driver parameters
 188.408 + * Accepts: function code
 188.409 + *	    function-dependent value
 188.410 + * Returns: function-dependent return value
 188.411 + */
 188.412 +
 188.413 +void *mmdf_parameters (long function,void *value)
 188.414 +{
 188.415 +  void *ret = NIL;
 188.416 +  switch ((int) function) {
 188.417 +  case GET_INBOXPATH:
 188.418 +    if (value) ret = dummy_file ((char *) value,"INBOX");
 188.419 +    break;
 188.420 +  }
 188.421 +  return ret;
 188.422 +}
 188.423 +
 188.424 +/* MMDF mail scan mailboxes
 188.425 + * Accepts: mail stream
 188.426 + *	    reference
 188.427 + *	    pattern to search
 188.428 + *	    string to scan
 188.429 + */
 188.430 +
 188.431 +void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 188.432 +{
 188.433 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 188.434 +}
 188.435 +
 188.436 +
 188.437 +/* MMDF mail list mailboxes
 188.438 + * Accepts: mail stream
 188.439 + *	    reference
 188.440 + *	    pattern to search
 188.441 + */
 188.442 +
 188.443 +void mmdf_list (MAILSTREAM *stream,char *ref,char *pat)
 188.444 +{
 188.445 +  if (stream) dummy_list (NIL,ref,pat);
 188.446 +}
 188.447 +
 188.448 +
 188.449 +/* MMDF mail list subscribed mailboxes
 188.450 + * Accepts: mail stream
 188.451 + *	    reference
 188.452 + *	    pattern to search
 188.453 + */
 188.454 +
 188.455 +void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat)
 188.456 +{
 188.457 +  if (stream) dummy_lsub (NIL,ref,pat);
 188.458 +}
 188.459 +
 188.460 +/* MMDF mail create mailbox
 188.461 + * Accepts: MAIL stream
 188.462 + *	    mailbox name to create
 188.463 + * Returns: T on success, NIL on failure
 188.464 + */
 188.465 +
 188.466 +long mmdf_create (MAILSTREAM *stream,char *mailbox)
 188.467 +{
 188.468 +  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
 188.469 +  long ret = NIL;
 188.470 +  int i,fd;
 188.471 +  time_t ti = time (0);
 188.472 +  if (!(s = dummy_file (mbx,mailbox))) {
 188.473 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 188.474 +    MM_LOG (tmp,ERROR);
 188.475 +  }
 188.476 +				/* create underlying file */
 188.477 +  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
 188.478 +				/* done if dir-only or whiner */
 188.479 +    if (((s = strrchr (s,'/')) && !s[1]) ||
 188.480 +	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
 188.481 +    else if ((fd = open (mbx,O_WRONLY,
 188.482 +		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
 188.483 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 188.484 +      MM_LOG (tmp,ERROR);
 188.485 +      unlink (mbx);		/* delete the file */
 188.486 +    }
 188.487 +    else {			/* initialize header */
 188.488 +      memset (tmp,'\0',MAILTMPLEN);
 188.489 +      sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti));
 188.490 +      rfc822_date (s = tmp + strlen (tmp));
 188.491 +      sprintf (s += strlen (s),	/* write the pseudo-header */
 188.492 +	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
 188.493 +	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
 188.494 +	       (unsigned long) ti);
 188.495 +      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
 188.496 +	sprintf (s += strlen (s)," %s",default_user_flag (i));
 188.497 +      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
 188.498 +      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
 188.499 +      else {
 188.500 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
 188.501 +		 strerror (errno));
 188.502 +	MM_LOG (tmp,ERROR);
 188.503 +	unlink (mbx);		/* delete the file */
 188.504 +      }
 188.505 +      close (fd);		/* close file */
 188.506 +    }
 188.507 +  }
 188.508 +				/* set proper protections */
 188.509 +  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
 188.510 +}
 188.511 +
 188.512 +/* MMDF mail delete mailbox
 188.513 + * Accepts: MAIL stream
 188.514 + *	    mailbox name to delete
 188.515 + * Returns: T on success, NIL on failure
 188.516 + */
 188.517 +
 188.518 +long mmdf_delete (MAILSTREAM *stream,char *mailbox)
 188.519 +{
 188.520 +  return mmdf_rename (stream,mailbox,NIL);
 188.521 +}
 188.522 +
 188.523 +
 188.524 +/* MMDF mail rename mailbox
 188.525 + * Accepts: MAIL stream
 188.526 + *	    old mailbox name
 188.527 + *	    new mailbox name (or NIL for delete)
 188.528 + * Returns: T on success, NIL on failure
 188.529 + */
 188.530 +
 188.531 +long mmdf_rename (MAILSTREAM *stream,char *old,char *newname)
 188.532 +{
 188.533 +  long ret = NIL;
 188.534 +  char c,*s = NIL;
 188.535 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 188.536 +  DOTLOCK lockx;
 188.537 +  int fd,ld;
 188.538 +  long i;
 188.539 +  struct stat sbuf;
 188.540 +  MM_CRITICAL (stream);	/* get the c-client lock */
 188.541 +  if (!dummy_file (file,old) ||
 188.542 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 188.543 +		   ((s = strrchr (tmp,'/')) && !s[1]))))
 188.544 +    sprintf (tmp,newname ?
 188.545 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 188.546 +	     "Can't delete mailbox %.80s: invalid name",
 188.547 +	     old,newname);
 188.548 +				/* lock out other c-clients */
 188.549 +  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
 188.550 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 188.551 +
 188.552 +  else {
 188.553 +    if ((fd = mmdf_lock (file,O_RDWR,
 188.554 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
 188.555 +			 &lockx,LOCK_EX)) < 0)
 188.556 +       sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
 188.557 +    else {
 188.558 +      if (newname) {		/* want rename? */
 188.559 +				/* found superior to destination name? */
 188.560 +	if (s = strrchr (s,'/')) {
 188.561 +	  c = *++s;		/* remember first character of inferior */
 188.562 +	  *s = '\0';		/* tie off to get just superior */
 188.563 +				/* name doesn't exist, create it */
 188.564 +	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 188.565 +	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
 188.566 +	    mmdf_unlock (fd,NIL,&lockx);
 188.567 +	    mmdf_unlock (ld,NIL,NIL);
 188.568 +	    unlink (lock);
 188.569 +	    MM_NOCRITICAL (stream);
 188.570 +	    return ret;		/* return success or failure */
 188.571 +	  }
 188.572 +	  *s = c;		/* restore full name */
 188.573 +	}
 188.574 +	if (rename (file,tmp))
 188.575 +	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 188.576 +		   strerror (errno));
 188.577 +	else ret = T;		/* set success */
 188.578 +      }
 188.579 +      else if (unlink (file))
 188.580 +	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 188.581 +      else ret = T;		/* set success */
 188.582 +      mmdf_unlock (fd,NIL,&lockx);
 188.583 +    }
 188.584 +    mmdf_unlock (ld,NIL,NIL);	/* flush the lock */
 188.585 +    unlink (lock);
 188.586 +  }
 188.587 +  MM_NOCRITICAL (stream);	/* no longer critical */
 188.588 +  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
 188.589 +  return ret;			/* return success or failure */
 188.590 +}
 188.591 +
 188.592 +/* MMDF mail open
 188.593 + * Accepts: Stream to open
 188.594 + * Returns: Stream on success, NIL on failure
 188.595 + */
 188.596 +
 188.597 +MAILSTREAM *mmdf_open (MAILSTREAM *stream)
 188.598 +{
 188.599 +  long i;
 188.600 +  int fd;
 188.601 +  char tmp[MAILTMPLEN];
 188.602 +  DOTLOCK lock;
 188.603 +  long retry;
 188.604 +				/* return prototype for OP_PROTOTYPE call */
 188.605 +  if (!stream) return user_flags (&mmdfproto);
 188.606 +  retry = stream->silent ? 1 : KODRETRY;
 188.607 +  if (stream->local) fatal ("mmdf recycle stream");
 188.608 +  stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL));
 188.609 +				/* note if an INBOX or not */
 188.610 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 188.611 +				/* canonicalize the stream mailbox name */
 188.612 +  if (!dummy_file (tmp,stream->mailbox)) {
 188.613 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 188.614 +    MM_LOG (tmp,ERROR);
 188.615 +    return NIL;
 188.616 +  }
 188.617 +				/* flush old name */
 188.618 +  fs_give ((void **) &stream->mailbox);
 188.619 +				/* save canonical name */
 188.620 +  stream->mailbox = cpystr (tmp);
 188.621 +  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
 188.622 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 188.623 +  LOCAL->buflen = CHUNKSIZE - 1;
 188.624 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 188.625 +  LOCAL->text.size = CHUNKSIZE - 1;
 188.626 +  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
 188.627 +  LOCAL->linebuflen = CHUNKSIZE - 1;
 188.628 +  stream->sequence++;		/* bump sequence number */
 188.629 +
 188.630 +				/* make lock for read/write access */
 188.631 +  if (!stream->rdonly) while (retry) {
 188.632 +				/* try to lock file */
 188.633 +    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
 188.634 +				/* suppressing kiss-of-death? */
 188.635 +      if (stream->nokod) retry = 0;
 188.636 +				/* no, first time through? */
 188.637 +      else if (retry-- == KODRETRY) {
 188.638 +				/* learned other guy's PID and can signal? */
 188.639 +	if (i && !kill ((int) i,SIGUSR2)) {
 188.640 +	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
 188.641 +	  MM_LOG (tmp,WARN);
 188.642 +	}
 188.643 +	else retry = 0;		/* give up */
 188.644 +      }
 188.645 +      if (!stream->silent) {	/* nothing if silent stream */
 188.646 +	if (retry) sleep (1);	/* wait a second before trying again */
 188.647 +	else MM_LOG ("Mailbox is open by another process, access is readonly",
 188.648 +		     WARN);
 188.649 +      }
 188.650 +    }
 188.651 +    else {			/* got the lock, nobody else can alter state */
 188.652 +      LOCAL->ld = fd;		/* note lock's fd and name */
 188.653 +      LOCAL->lname = cpystr (tmp);
 188.654 +				/* make sure mode OK (don't use fchmod()) */
 188.655 +      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
 188.656 +      if (stream->silent) i = 0;/* silent streams won't accept KOD */
 188.657 +      else {			/* note our PID in the lock */
 188.658 +	sprintf (tmp,"%d",getpid ());
 188.659 +	write (fd,tmp,(i = strlen (tmp))+1);
 188.660 +      }
 188.661 +      ftruncate (fd,i);		/* make sure tied off */
 188.662 +      fsync (fd);		/* make sure it's available */
 188.663 +      retry = 0;		/* no more need to try */
 188.664 +    }
 188.665 +  }
 188.666 +
 188.667 +				/* parse mailbox */
 188.668 +  stream->nmsgs = stream->recent = 0;
 188.669 +				/* will we be able to get write access? */
 188.670 +  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
 188.671 +    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 188.672 +    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
 188.673 +    close (LOCAL->ld);		/* close the lock file */
 188.674 +    LOCAL->ld = -1;		/* no more lock fd */
 188.675 +    unlink (LOCAL->lname);	/* delete it */
 188.676 +  }
 188.677 +				/* reset UID validity */
 188.678 +  stream->uid_validity = stream->uid_last = 0;
 188.679 +  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
 188.680 +    mmdf_abort (stream);	/* abort if can't get RW silent stream */
 188.681 +				/* parse mailbox */
 188.682 +  else if (mmdf_parse (stream,&lock,LOCK_SH)) {
 188.683 +    mmdf_unlock (LOCAL->fd,stream,&lock);
 188.684 +    mail_unlock (stream);
 188.685 +    MM_NOCRITICAL (stream);	/* done with critical */
 188.686 +  }
 188.687 +  if (!LOCAL) return NIL;	/* failure if stream died */
 188.688 +				/* make sure upper level knows readonly */
 188.689 +  stream->rdonly = (LOCAL->ld < 0);
 188.690 +				/* notify about empty mailbox */
 188.691 +  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
 188.692 +  if (!stream->rdonly) {	/* flags stick if readwrite */
 188.693 +    stream->perm_seen = stream->perm_deleted =
 188.694 +      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
 188.695 +    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
 188.696 +      stream->perm_user_flags = 0xffffffff;
 188.697 +				/* and maybe can create them too! */
 188.698 +      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
 188.699 +    }
 188.700 +  }
 188.701 +  return stream;		/* return stream alive to caller */
 188.702 +}
 188.703 +
 188.704 +
 188.705 +/* MMDF mail close
 188.706 + * Accepts: MAIL stream
 188.707 + *	    close options
 188.708 + */
 188.709 +
 188.710 +void mmdf_close (MAILSTREAM *stream,long options)
 188.711 +{
 188.712 +  int silent = stream->silent;
 188.713 +  stream->silent = T;		/* go silent */
 188.714 +				/* expunge if requested */
 188.715 +  if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL);
 188.716 +				/* else dump final checkpoint */
 188.717 +  else if (LOCAL->dirty) mmdf_check (stream);
 188.718 +  stream->silent = silent;	/* restore old silence state */
 188.719 +  mmdf_abort (stream);		/* now punt the file and local data */
 188.720 +}
 188.721 +
 188.722 +/* MMDF mail fetch message header
 188.723 + * Accepts: MAIL stream
 188.724 + *	    message # to fetch
 188.725 + *	    pointer to returned header text length
 188.726 + *	    option flags
 188.727 + * Returns: message header in RFC822 format
 188.728 + */
 188.729 +
 188.730 +				/* lines to filter from header */
 188.731 +static STRINGLIST *mmdf_hlines = NIL;
 188.732 +
 188.733 +char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
 188.734 +		   unsigned long *length,long flags)
 188.735 +{
 188.736 +  MESSAGECACHE *elt;
 188.737 +  unsigned char *s,*t,*tl;
 188.738 +  *length = 0;			/* default to empty */
 188.739 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 188.740 +  elt = mail_elt (stream,msgno);/* get cache */
 188.741 +  if (!mmdf_hlines) {		/* once only code */
 188.742 +    STRINGLIST *lines = mmdf_hlines = mail_newstringlist ();
 188.743 +    lines->text.size = strlen ((char *) (lines->text.data =
 188.744 +					 (unsigned char *) "Status"));
 188.745 +    lines = lines->next = mail_newstringlist ();
 188.746 +    lines->text.size = strlen ((char *) (lines->text.data =
 188.747 +					 (unsigned char *) "X-Status"));
 188.748 +    lines = lines->next = mail_newstringlist ();
 188.749 +    lines->text.size = strlen ((char *) (lines->text.data =
 188.750 +					 (unsigned char *) "X-Keywords"));
 188.751 +    lines = lines->next = mail_newstringlist ();
 188.752 +    lines->text.size = strlen ((char *) (lines->text.data =
 188.753 +					 (unsigned char *) "X-UID"));
 188.754 +    lines = lines->next = mail_newstringlist ();
 188.755 +    lines->text.size = strlen ((char *) (lines->text.data =
 188.756 +					 (unsigned char *) "X-IMAP"));
 188.757 +    lines = lines->next = mail_newstringlist ();
 188.758 +    lines->text.size = strlen ((char *) (lines->text.data =
 188.759 +					 (unsigned char *) "X-IMAPbase"));
 188.760 +  }
 188.761 +				/* go to header position */
 188.762 +  lseek (LOCAL->fd,elt->private.special.offset +
 188.763 +	 elt->private.msg.header.offset,L_SET);
 188.764 +
 188.765 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 188.766 +    if (elt->private.msg.header.text.size > LOCAL->buflen) {
 188.767 +      fs_give ((void **) &LOCAL->buf);
 188.768 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 188.769 +				     elt->private.msg.header.text.size) + 1);
 188.770 +    }
 188.771 +				/* read message */
 188.772 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
 188.773 +				/* got text, tie off string */
 188.774 +    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
 188.775 +				/* squeeze out CRs (in case from PC) */
 188.776 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 188.777 +      if (*t != '\r') *s++ = *t;
 188.778 +    *s = '\0';
 188.779 +    *length = s - LOCAL->buf;	/* adjust length */
 188.780 +  }
 188.781 +  else {			/* need to make a CRLF version */
 188.782 +    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
 188.783 +	  elt->private.msg.header.text.size);
 188.784 +				/* tie off string, and convert to CRLF */
 188.785 +    s[elt->private.msg.header.text.size] = '\0';
 188.786 +    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
 188.787 +			  elt->private.msg.header.text.size);
 188.788 +    fs_give ((void **) &s);	/* free readin buffer */
 188.789 +				/* squeeze out spurious CRs */
 188.790 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 188.791 +      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
 188.792 +    *s = '\0';
 188.793 +    *length = s - LOCAL->buf;	/* adjust length */
 188.794 +  }
 188.795 +  *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT);
 188.796 +  return (char *) LOCAL->buf;	/* return processed copy */
 188.797 +}
 188.798 +
 188.799 +/* MMDF mail fetch message text
 188.800 + * Accepts: MAIL stream
 188.801 + *	    message # to fetch
 188.802 + *	    pointer to returned stringstruct
 188.803 + *	    option flags
 188.804 + * Returns: T on success, NIL if failure
 188.805 + */
 188.806 +
 188.807 +long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 188.808 +{
 188.809 +  char *s;
 188.810 +  unsigned long i;
 188.811 +  MESSAGECACHE *elt;
 188.812 +				/* UID call "impossible" */
 188.813 +  if (flags & FT_UID) return NIL;
 188.814 +  elt = mail_elt (stream,msgno);/* get cache element */
 188.815 +				/* if message not seen */
 188.816 +  if (!(flags & FT_PEEK) && !elt->seen) {
 188.817 +				/* mark message seen and dirty */
 188.818 +    elt->seen = elt->private.dirty = LOCAL->dirty = T;
 188.819 +    MM_FLAGS (stream,msgno);
 188.820 +  }
 188.821 +  s = mmdf_text_work (stream,elt,&i,flags);
 188.822 +  INIT (bs,mail_string,s,i);	/* set up stringstruct */
 188.823 +  return T;			/* success */
 188.824 +}
 188.825 +
 188.826 +/* MMDF mail fetch message text worker routine
 188.827 + * Accepts: MAIL stream
 188.828 + *	    message cache element
 188.829 + *	    pointer to returned header text length
 188.830 + *	    option flags
 188.831 + */
 188.832 +
 188.833 +char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 188.834 +		      unsigned long *length,long flags)
 188.835 +{
 188.836 +  FDDATA d;
 188.837 +  STRING bs;
 188.838 +  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
 188.839 +				/* go to text position */
 188.840 +  lseek (LOCAL->fd,elt->private.special.offset +
 188.841 +	 elt->private.msg.text.offset,L_SET);
 188.842 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 188.843 +    if (elt->private.msg.text.text.size > LOCAL->buflen) {
 188.844 +      fs_give ((void **) &LOCAL->buf);
 188.845 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 188.846 +				     elt->private.msg.text.text.size) + 1);
 188.847 +    }
 188.848 +				/* read message */
 188.849 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
 188.850 +				/* got text, tie off string */
 188.851 +    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
 188.852 +				/* squeeze out CRs (in case from PC) */
 188.853 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 188.854 +      if (*t != '\r') *s++ = *t;
 188.855 +    *s = '\0';
 188.856 +    *length = s - LOCAL->buf;	/* adjust length */
 188.857 +    return (char *) LOCAL->buf;
 188.858 +  }
 188.859 +
 188.860 +				/* have it cached already? */
 188.861 +  if (elt->private.uid != LOCAL->uid) {
 188.862 +				/* not cached, cache it now */
 188.863 +    LOCAL->uid = elt->private.uid;
 188.864 +				/* is buffer big enough? */
 188.865 +    if (elt->rfc822_size > LOCAL->text.size) {
 188.866 +      /* excessively conservative, but the right thing is too hard to do */
 188.867 +      fs_give ((void **) &LOCAL->text.data);
 188.868 +      LOCAL->text.data = (unsigned char *)
 188.869 +	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
 188.870 +    }
 188.871 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
 188.872 +    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
 188.873 +    d.chunk = tmp;		/* initial buffer chunk */
 188.874 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
 188.875 +    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
 188.876 +    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
 188.877 +    case '\r':			/* carriage return seen */
 188.878 +      break;
 188.879 +    case '\n':
 188.880 +      *s++ = '\r';		/* insert a CR */
 188.881 +    default:
 188.882 +      *s++ = c;			/* copy characters */
 188.883 +    }
 188.884 +    *s = '\0';			/* tie off buffer */
 188.885 +				/* calculate length of cached data */
 188.886 +    LOCAL->textlen = s - LOCAL->text.data;
 188.887 +  }
 188.888 +  *length = LOCAL->textlen;	/* return from cache */
 188.889 +  return (char *) LOCAL->text.data;
 188.890 +}
 188.891 +
 188.892 +/* MMDF per-message modify flag
 188.893 + * Accepts: MAIL stream
 188.894 + *	    message cache element
 188.895 + */
 188.896 +
 188.897 +void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 188.898 +{
 188.899 +				/* only after finishing */
 188.900 +  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
 188.901 +}
 188.902 +
 188.903 +
 188.904 +/* MMDF mail ping mailbox
 188.905 + * Accepts: MAIL stream
 188.906 + * Returns: T if stream alive, else NIL
 188.907 + */
 188.908 +
 188.909 +long mmdf_ping (MAILSTREAM *stream)
 188.910 +{
 188.911 +  DOTLOCK lock;
 188.912 +  struct stat sbuf;
 188.913 +  long reparse;
 188.914 +				/* big no-op if not readwrite */
 188.915 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
 188.916 +    if (stream->rdonly) {	/* does he want to give up readwrite? */
 188.917 +				/* checkpoint if we changed something */
 188.918 +      if (LOCAL->dirty) mmdf_check (stream);
 188.919 +      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
 188.920 +      close (LOCAL->ld);	/* close the readwrite lock file */
 188.921 +      LOCAL->ld = -1;		/* no more readwrite lock fd */
 188.922 +      unlink (LOCAL->lname);	/* delete the readwrite lock file */
 188.923 +    }
 188.924 +    else {			/* see if need to reparse */
 188.925 +      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
 188.926 +				/* get current mailbox size */
 188.927 +	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
 188.928 +	else if (stat (stream->mailbox,&sbuf)) {
 188.929 +	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
 188.930 +		   strerror (errno));
 188.931 +	  MM_LOG (LOCAL->buf,ERROR);
 188.932 +	  mmdf_abort (stream);
 188.933 +	  return NIL;
 188.934 +	}
 188.935 +	reparse = (sbuf.st_size != LOCAL->filesize);
 188.936 +      }
 188.937 +				/* parse if mailbox changed */
 188.938 +      if ((LOCAL->ddirty || reparse) && mmdf_parse (stream,&lock,LOCK_EX)) {
 188.939 +				/* force checkpoint if double-dirty */
 188.940 +	if (LOCAL->ddirty) mmdf_rewrite (stream,NIL,&lock,NIL);
 188.941 +				/* unlock mailbox */
 188.942 +	else mmdf_unlock (LOCAL->fd,stream,&lock);
 188.943 +	mail_unlock (stream);	/* and stream */
 188.944 +				/* done with critical */
 188.945 +	MM_NOCRITICAL (stream);
 188.946 +      }
 188.947 +    }
 188.948 +  }
 188.949 +  return LOCAL ? LONGT : NIL;	/* return if still alive */
 188.950 +}
 188.951 +
 188.952 +/* MMDF mail check mailbox
 188.953 + * Accepts: MAIL stream
 188.954 + */
 188.955 +
 188.956 +void mmdf_check (MAILSTREAM *stream)
 188.957 +{
 188.958 +  DOTLOCK lock;
 188.959 +				/* parse and lock mailbox */
 188.960 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 188.961 +      mmdf_parse (stream,&lock,LOCK_EX)) {
 188.962 +				/* any unsaved changes? */
 188.963 +    if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock,NIL)) {
 188.964 +      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
 188.965 +    }
 188.966 +				/* no checkpoint needed, just unlock */
 188.967 +    else mmdf_unlock (LOCAL->fd,stream,&lock);
 188.968 +    mail_unlock (stream);	/* unlock the stream */
 188.969 +    MM_NOCRITICAL (stream);	/* done with critical */
 188.970 +  }
 188.971 +}
 188.972 +
 188.973 +
 188.974 +/* MMDF mail expunge mailbox
 188.975 + * Accepts: MAIL stream
 188.976 + *	    sequence to expunge if non-NIL
 188.977 + *	    expunge options
 188.978 + * Returns: T, always
 188.979 + */
 188.980 +
 188.981 +long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options)
 188.982 +{
 188.983 +  long ret;
 188.984 +  unsigned long i;
 188.985 +  DOTLOCK lock;
 188.986 +  char *msg = NIL;
 188.987 +  if (ret = (sequence ? ((options & EX_UID) ?
 188.988 +			 mail_uid_sequence (stream,sequence) :
 188.989 +			 mail_sequence (stream,sequence)) : LONGT) &&
 188.990 +      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 188.991 +      mmdf_parse (stream,&lock,LOCK_EX)) {
 188.992 +				/* check expunged messages if not dirty */
 188.993 +    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
 188.994 +      MESSAGECACHE *elt = mail_elt (stream,i);
 188.995 +      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
 188.996 +    }
 188.997 +    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
 188.998 +      mmdf_unlock (LOCAL->fd,stream,&lock);
 188.999 +      msg = "No messages deleted, so no update needed";
188.1000 +    }
188.1001 +    else if (mmdf_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
188.1002 +      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
188.1003 +      else msg = "Mailbox checkpointed, but no messages expunged";
188.1004 +    }
188.1005 +				/* rewrite failed */
188.1006 +    else mmdf_unlock (LOCAL->fd,stream,&lock);
188.1007 +    mail_unlock (stream);	/* unlock the stream */
188.1008 +    MM_NOCRITICAL (stream);	/* done with critical */
188.1009 +    if (msg && !stream->silent) MM_LOG (msg,NIL);
188.1010 +  }
188.1011 +  else if (!stream->silent)
188.1012 +    MM_LOG ("Expunge ignored on readonly mailbox",WARN);
188.1013 +  return ret;
188.1014 +}
188.1015 +
188.1016 +/* MMDF mail copy message(s)
188.1017 + * Accepts: MAIL stream
188.1018 + *	    sequence
188.1019 + *	    destination mailbox
188.1020 + *	    copy options
188.1021 + * Returns: T if copy successful, else NIL
188.1022 + */
188.1023 +
188.1024 +long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
188.1025 +{
188.1026 +  struct stat sbuf;
188.1027 +  int fd;
188.1028 +  char *s,file[MAILTMPLEN];
188.1029 +  DOTLOCK lock;
188.1030 +  time_t tp[2];
188.1031 +  unsigned long i,j;
188.1032 +  MESSAGECACHE *elt;
188.1033 +  long ret = T;
188.1034 +  mailproxycopy_t pc =
188.1035 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
188.1036 +  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
188.1037 +			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
188.1038 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
188.1039 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
188.1040 +  MAILSTREAM *tstream = NIL;
188.1041 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
188.1042 +	mail_sequence (stream,sequence))) return NIL;
188.1043 +				/* make sure destination is valid */
188.1044 +  if (!(mmdf_valid (mailbox) || !errno))
188.1045 +    switch (errno) {
188.1046 +    case ENOENT:		/* no such file? */
188.1047 +      if (compare_cstring (mailbox,"INBOX")) {
188.1048 +	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
188.1049 +	return NIL;
188.1050 +      }
188.1051 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
188.1052 +      mmdf_create (NIL,"INBOX");/* create empty INBOX */
188.1053 +    case EACCES:		/* file protected */
188.1054 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
188.1055 +      MM_LOG (LOCAL->buf,ERROR);
188.1056 +      return NIL;
188.1057 +    case EINVAL:
188.1058 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
188.1059 +      sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox);
188.1060 +      MM_LOG (LOCAL->buf,ERROR);
188.1061 +      return NIL;
188.1062 +    default:
188.1063 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
188.1064 +      sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox);
188.1065 +      MM_LOG (LOCAL->buf,ERROR);
188.1066 +      return NIL;
188.1067 +    }
188.1068 +
188.1069 +				/* try to open rewrite for UIDPLUS */
188.1070 +  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
188.1071 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
188.1072 +    tstream = mail_close (tstream);
188.1073 +  if (cu && !tstream) {		/* wanted a COPYUID? */
188.1074 +    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
188.1075 +	     mailbox);
188.1076 +    MM_LOG (LOCAL->buf,WARN);
188.1077 +    cu = NIL;			/* don't try to do COPYUID */
188.1078 +  }
188.1079 +  LOCAL->buf[0] = '\0';
188.1080 +  MM_CRITICAL (stream);		/* go critical */
188.1081 +  if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
188.1082 +		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
188.1083 +		       &lock,LOCK_EX)) < 0) {
188.1084 +    MM_NOCRITICAL (stream);	/* done with critical */
188.1085 +    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
188.1086 +    MM_LOG (LOCAL->buf,ERROR);	/* log the error */
188.1087 +    return NIL;			/* failed */
188.1088 +  }
188.1089 +  fstat (fd,&sbuf);		/* get current file size */
188.1090 +				/* write all requested messages to mailbox */
188.1091 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
188.1092 +    if ((elt = mail_elt (stream,i))->sequence) {
188.1093 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
188.1094 +      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
188.1095 +      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
188.1096 +      else {			/* internal header succeeded */
188.1097 +	s = mmdf_header (stream,i,&j,FT_INTERNAL);
188.1098 +				/* header size, sans trailing newline */
188.1099 +	if (j && (s[j - 2] == '\n')) j--;
188.1100 +	if (write (fd,s,j) < 0) ret = NIL;
188.1101 +	else {			/* message header succeeded */
188.1102 +	  j = tstream ?		/* write UIDPLUS data if have readwrite */
188.1103 +	    mmdf_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
188.1104 +	    mmdf_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
188.1105 +	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
188.1106 +	  else {		/* message status succeeded */
188.1107 +	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
188.1108 +	    if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0))
188.1109 +	      ret = NIL;
188.1110 +	    else if (cu) {	/* need to pass back new UID? */
188.1111 +	      mail_append_set (source,mail_uid (stream,i));
188.1112 +	      mail_append_set (dest,tstream->uid_last);
188.1113 +	    }
188.1114 +	  }
188.1115 +	}
188.1116 +      }
188.1117 +    }
188.1118 +
188.1119 +  if (!ret || fsync (fd)) {	/* force out the update */
188.1120 +    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
188.1121 +    ftruncate (fd,sbuf.st_size);
188.1122 +    ret = NIL;
188.1123 +  }
188.1124 +				/* force UIDVALIDITY assignment now */
188.1125 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
188.1126 +				/* return sets if doing COPYUID */
188.1127 +  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
188.1128 +  else {			/* flush any sets we may have built */
188.1129 +    mail_free_searchset (&source);
188.1130 +    mail_free_searchset (&dest);
188.1131 +  }
188.1132 +  tp[1] = time (0);		/* set mtime to now */
188.1133 +  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
188.1134 +  else tp[0] =			/* else preserve \Marked status */
188.1135 +	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
188.1136 +	 sbuf.st_atime : tp[1];
188.1137 +  utime (file,tp);		/* set the times */
188.1138 +  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
188.1139 +  if (tstream) {		/* update last UID if we can */
188.1140 +    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
188.1141 +    local->dirty = T;		/* do a rewrite */
188.1142 +    local->appending = T;	/* but not at the cost of marking as old */
188.1143 +    tstream = mail_close (tstream);
188.1144 +  }
188.1145 +				/* log the error */
188.1146 +  if (!ret) MM_LOG (LOCAL->buf,ERROR);
188.1147 +				/* delete if requested message */
188.1148 +  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
188.1149 +    if ((elt = mail_elt (stream,i))->sequence)
188.1150 +      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
188.1151 +  MM_NOCRITICAL (stream);	/* release critical */
188.1152 +  return ret;
188.1153 +}
188.1154 +
188.1155 +/* MMDF mail append message from stringstruct
188.1156 + * Accepts: MAIL stream
188.1157 + *	    destination mailbox
188.1158 + *	    append callback
188.1159 + *	    data for callback
188.1160 + * Returns: T if append successful, else NIL
188.1161 + */
188.1162 +
188.1163 +#define BUFLEN 8*MAILTMPLEN
188.1164 +
188.1165 +long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
188.1166 +{
188.1167 +  struct stat sbuf;
188.1168 +  int fd;
188.1169 +  unsigned long i;
188.1170 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
188.1171 +  time_t tp[2];
188.1172 +  FILE *sf,*df;
188.1173 +  MESSAGECACHE elt;
188.1174 +  DOTLOCK lock;
188.1175 +  STRING *message;
188.1176 +  unsigned long uidlocation = 0;
188.1177 +  appenduid_t au = (appenduid_t)
188.1178 +    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
188.1179 +     mail_parameters (NIL,GET_APPENDUID,NIL));
188.1180 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
188.1181 +  long ret = LONGT;
188.1182 +  MAILSTREAM *tstream = NIL;
188.1183 +				/* default stream to prototype */
188.1184 +  if (!stream) {		/* stream specified? */
188.1185 +    stream = &mmdfproto;	/* no, default stream to prototype */
188.1186 +    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
188.1187 +      fs_give ((void **) &stream->user_flags[i]);
188.1188 +  }
188.1189 +  if (!mmdf_valid (mailbox)) switch (errno) {
188.1190 +  case ENOENT:			/* no such file? */
188.1191 +    if (compare_cstring (mailbox,"INBOX")) {
188.1192 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
188.1193 +      return NIL;
188.1194 +    }
188.1195 +    mmdf_create (NIL,"INBOX");	/* create empty INBOX */
188.1196 +  case 0:			/* merely empty file? */
188.1197 +    tstream = stream;
188.1198 +    break;
188.1199 +  case EACCES:			/* file protected */
188.1200 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
188.1201 +    MM_LOG (tmp,ERROR);
188.1202 +    return NIL;
188.1203 +  case EINVAL:
188.1204 +    sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox);
188.1205 +    MM_LOG (tmp,ERROR);
188.1206 +    return NIL;
188.1207 +  default:
188.1208 +    sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox);
188.1209 +    MM_LOG (tmp,ERROR);
188.1210 +    return NIL;
188.1211 +  }
188.1212 +				/* get sniffing stream for keywords */
188.1213 +  else if (!(tstream = mail_open (NIL,mailbox,
188.1214 +				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
188.1215 +    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
188.1216 +    MM_LOG (tmp,ERROR);
188.1217 +    return NIL;
188.1218 +  }
188.1219 +
188.1220 +				/* get first message */
188.1221 +  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
188.1222 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
188.1223 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
188.1224 +    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
188.1225 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
188.1226 +      MM_LOG (tmp,ERROR);
188.1227 +      return NIL;
188.1228 +    }
188.1229 +    unlink (tmp);
188.1230 +  }
188.1231 +  do {				/* parse date */
188.1232 +    if (!date) rfc822_date (date = tmp);
188.1233 +    if (!mail_parse_date (&elt,date)) {
188.1234 +      sprintf (tmp,"Bad date in append: %.80s",date);
188.1235 +      MM_LOG (tmp,ERROR);
188.1236 +    }
188.1237 +    else {			/* user wants to suppress time zones? */
188.1238 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
188.1239 +	time_t when = mail_longdate (&elt);
188.1240 +	date = ctime (&when);	/* use traditional date */
188.1241 +      }
188.1242 +				/* use POSIX-style date */
188.1243 +      else date = mail_cdate (tmp,&elt);
188.1244 +      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
188.1245 +      else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) {
188.1246 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
188.1247 +	MM_LOG (tmp,ERROR);
188.1248 +      }
188.1249 +				/* get next message */
188.1250 +      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
188.1251 +    }
188.1252 +    fclose (sf);		/* punt scratch file */
188.1253 +    return NIL;			/* give up */
188.1254 +  } while (message);		/* until no more messages */
188.1255 +  if (fflush (sf)) {
188.1256 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
188.1257 +    MM_LOG (tmp,ERROR);
188.1258 +    fclose (sf);		/* punt scratch file */
188.1259 +    return NIL;			/* give up */
188.1260 +  }
188.1261 +  i = ftell (sf);		/* size of scratch file */
188.1262 +  if (tstream != stream) tstream = mail_close (tstream);
188.1263 +
188.1264 +  MM_CRITICAL (stream);		/* go critical */
188.1265 +				/* try to open readwrite for UIDPLUS */
188.1266 +  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
188.1267 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
188.1268 +    tstream = mail_close (tstream);
188.1269 +  if (au && !tstream) {		/* wanted an APPENDUID? */
188.1270 +    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
188.1271 +    MM_LOG (tmp,WARN);
188.1272 +    au = NIL;
188.1273 +  }
188.1274 +  if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
188.1275 +			(long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
188.1276 +			&lock,LOCK_EX)) < 0) ||
188.1277 +      !(df = fdopen (fd,"ab"))) {
188.1278 +    MM_NOCRITICAL (stream);	/* done with critical */
188.1279 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
188.1280 +    MM_LOG (tmp,ERROR);
188.1281 +    return NIL;
188.1282 +  }
188.1283 +  fstat (fd,&sbuf);		/* get current file size */
188.1284 +  rewind (sf);
188.1285 +  tp[1] = time (0);		/* set mtime to now */
188.1286 +				/* write all messages */
188.1287 +  if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) ||
188.1288 +      (fflush (df) == EOF) || fsync (fd)) {
188.1289 +    sprintf (buf,"Message append failed: %s",strerror (errno));
188.1290 +    MM_LOG (buf,ERROR);
188.1291 +    ftruncate (fd,sbuf.st_size);
188.1292 +    tp[0] =			/* preserve \Marked status */
188.1293 +      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
188.1294 +      sbuf.st_atime : tp[1];
188.1295 +    ret = NIL;			/* return error */
188.1296 +  }
188.1297 +  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
188.1298 +  utime (file,tp);		/* set the times */
188.1299 +  fclose (sf);			/* done with scratch file */
188.1300 +				/* force UIDVALIDITY assignment now */
188.1301 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
188.1302 +				/* return sets if doing APPENDUID */
188.1303 +  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
188.1304 +  else mail_free_searchset (&dst);
188.1305 +  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
188.1306 +  fclose (df);
188.1307 +  if (tstream) {		/* update last UID if we can */
188.1308 +    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
188.1309 +    local->dirty = T;		/* do a rewrite */
188.1310 +    local->appending = T;	/* but not at the cost of marking as old */
188.1311 +    tstream = mail_close (tstream);
188.1312 +  }
188.1313 +  MM_NOCRITICAL (stream);	/* release critical */
188.1314 +  return ret;
188.1315 +}
188.1316 +
188.1317 +/* Collect and write single message to append scratch file
188.1318 + * Accepts: MAIL stream
188.1319 + *	    scratch file
188.1320 + *	    flags
188.1321 + *	    date
188.1322 + *	    message stringstruct
188.1323 + * Returns: NIL if write error, else T
188.1324 + */
188.1325 +
188.1326 +int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
188.1327 +  		     STRING *msg)
188.1328 +{
188.1329 +  unsigned char *s,*t;
188.1330 +  unsigned long uf;
188.1331 +  long f = mail_parse_flags (stream,flags,&uf);
188.1332 +				/* write metadata, note date ends with NL */
188.1333 +  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
188.1334 +  while (uf)			/* write user flags */    
188.1335 +    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
188.1336 +	(fprintf (sf," %s",s) < 0)) return NIL;
188.1337 +  if (putc ('\n',sf) == EOF) return NIL;
188.1338 +  while (SIZE (msg)) {		/* copy text to scratch file */
188.1339 +    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
188.1340 +      if (!*s) *s = 0x80;	/* disallow NUL */
188.1341 +				/* write buffered text */
188.1342 +    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
188.1343 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
188.1344 +    else return NIL;		/* failed */
188.1345 +  }
188.1346 +				/* write trailing newline and return */
188.1347 +  return (putc ('\n',sf) == EOF) ? NIL : T;
188.1348 +}
188.1349 +
188.1350 +/* Append messages from scratch file to mailbox
188.1351 + * Accepts: MAIL stream
188.1352 + *	    source file
188.1353 + *	    destination file
188.1354 + *	    uidset to update if non-NIL
188.1355 + * Returns: T if success, NIL if failure
188.1356 + */
188.1357 +
188.1358 +int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
188.1359 +{
188.1360 +  int c;
188.1361 +  long f;
188.1362 +  unsigned long i,j;
188.1363 +  char *x,tmp[MAILTMPLEN];
188.1364 +  int hdrp = T;
188.1365 +				/* get message metadata line */
188.1366 +  while (fgets (tmp,MAILTMPLEN,sf)) {
188.1367 +    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
188.1368 +    f = strtol (tmp,&x,10);	/* get flags */
188.1369 +    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
188.1370 +    i = strtoul (x,&x,10);	/* get message size */
188.1371 +    if ((*x++ != ' ') ||	/* build initial header */
188.1372 +	(fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(),
188.1373 +		  mylocalhost(),x) < 0) ||
188.1374 +	(f&fSEEN && (putc ('R',df) == EOF)) ||
188.1375 +	(fputs ("\nX-Status: ",df) == EOF) ||
188.1376 +	(f&fDELETED && (putc ('D',df) == EOF)) ||
188.1377 +	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
188.1378 +	(f&fANSWERED && (putc ('A',df) == EOF)) ||
188.1379 +	(f&fDRAFT && (putc ('T',df) == EOF)) ||
188.1380 +	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
188.1381 +				/* copy keywords */
188.1382 +    while ((c = getc (sf)) != '\n') switch (c) {
188.1383 +    case EOF:
188.1384 +      return NIL;
188.1385 +    default:
188.1386 +      if (putc (c,df) == EOF) return NIL;
188.1387 +    }
188.1388 +    if ((putc ('\n',df) == EOF) ||
188.1389 +	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
188.1390 +      return NIL;
188.1391 +
188.1392 +    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
188.1393 +				/* get read line length */
188.1394 +      if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun");
188.1395 +      i -= j;			/* number of bytes left */
188.1396 +				/* squish out ^A and CRs (note copies NUL) */
188.1397 +      for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp));
188.1398 +      if (!j) continue;		/* do nothing if line emptied */
188.1399 +				/* start of line? */
188.1400 +      if ((c == '\n')) switch (tmp[0]) {
188.1401 +      case 'S': case 's':	/* possible "Status:" */
188.1402 +	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
188.1403 +	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
188.1404 +	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
188.1405 +	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
188.1406 +	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
188.1407 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
188.1408 +	break;
188.1409 +      case 'X': case 'x':	/* possible X-??? header */
188.1410 +	if (hdrp && (tmp[1] == '-') &&
188.1411 +				/* possible X-UID: */
188.1412 +	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
188.1413 +	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
188.1414 +	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
188.1415 +				/* possible X-IMAP: */
188.1416 +	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
188.1417 +	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
188.1418 +	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
188.1419 +	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
188.1420 +	      ((tmp[6] == ':') ||
188.1421 +				/* or X-IMAPbase: */
188.1422 +	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
188.1423 +		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
188.1424 +		((tmp[8] == 's') || (tmp[8] == 'S')) &&
188.1425 +		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
188.1426 +				/* possible X-Status: */
188.1427 +	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
188.1428 +	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
188.1429 +	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
188.1430 +	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
188.1431 +	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
188.1432 +	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
188.1433 +				/* possible X-Keywords: */
188.1434 +	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
188.1435 +	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
188.1436 +	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
188.1437 +	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
188.1438 +	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
188.1439 +	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
188.1440 +	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
188.1441 +	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
188.1442 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
188.1443 +	break;
188.1444 +      case '\n':		/* blank line */
188.1445 +	hdrp = NIL;
188.1446 +	break;
188.1447 +      default:			/* nothing to do */
188.1448 +	break;
188.1449 +      }
188.1450 +				/* just write the line */
188.1451 +      if (fwrite (tmp,1,j,df) != j) return NIL;
188.1452 +    }
188.1453 +				/* make sure read entire msg & wrote trailer */
188.1454 +    if (i || (fputs (mmdfhdr,df) == EOF)) return NIL;
188.1455 +				/* update set */
188.1456 +    if (stream) mail_append_set (set,stream->uid_last);
188.1457 +  }
188.1458 +  return T;
188.1459 +}
188.1460 +
188.1461 +/* Internal routines */
188.1462 +
188.1463 +
188.1464 +/* MMDF mail abort stream
188.1465 + * Accepts: MAIL stream
188.1466 + */
188.1467 +
188.1468 +void mmdf_abort (MAILSTREAM *stream)
188.1469 +{
188.1470 +  if (LOCAL) {			/* only if a file is open */
188.1471 +    if (LOCAL->fd >= 0) close (LOCAL->fd);
188.1472 +    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
188.1473 +      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
188.1474 +      close (LOCAL->ld);	/* close the lock file */
188.1475 +      unlink (LOCAL->lname);	/* and delete it */
188.1476 +    }
188.1477 +    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
188.1478 +				/* free local text buffers */
188.1479 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
188.1480 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
188.1481 +    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
188.1482 +    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
188.1483 +				/* nuke the local data */
188.1484 +    fs_give ((void **) &stream->local);
188.1485 +    stream->dtb = NIL;		/* log out the DTB */
188.1486 +  }
188.1487 +}
188.1488 +
188.1489 +/* MMDF open and lock mailbox
188.1490 + * Accepts: file name to open/lock
188.1491 + *	    file open mode
188.1492 + *	    destination buffer for lock file name
188.1493 + *	    type of locking operation (LOCK_SH or LOCK_EX)
188.1494 + */
188.1495 +
188.1496 +int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
188.1497 +{
188.1498 +  int fd;
188.1499 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
188.1500 +  (*bn) (BLOCK_FILELOCK,NIL);
188.1501 +				/* try locking the easy way */
188.1502 +  if (dotlock_lock (file,lock,-1)) {
188.1503 +				/* got dotlock file, easy open */
188.1504 +    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
188.1505 +    else dotlock_unlock (lock);	/* open failed, free the dotlock */
188.1506 +  }
188.1507 +				/* no dot lock file, open file now */
188.1508 +  else if ((fd = open (file,flags,mode)) >= 0) {
188.1509 +				/* try paranoid way to make a dot lock file */
188.1510 +    if (dotlock_lock (file,lock,fd)) {
188.1511 +      close (fd);		/* get fresh fd in case of timing race */
188.1512 +      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
188.1513 +				/* open failed, free the dotlock */
188.1514 +      else dotlock_unlock (lock);
188.1515 +    }
188.1516 +    else flock (fd,op);		/* paranoid way failed, just flock() it */
188.1517 +  }
188.1518 +  (*bn) (BLOCK_NONE,NIL);
188.1519 +  return fd;
188.1520 +}
188.1521 +
188.1522 +/* MMDF unlock and close mailbox
188.1523 + * Accepts: file descriptor
188.1524 + *	    (optional) mailbox stream to check atime/mtime
188.1525 + *	    (optional) lock file name
188.1526 + */
188.1527 +
188.1528 +void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
188.1529 +{
188.1530 +  if (stream) {			/* need to muck with times? */
188.1531 +    struct stat sbuf;
188.1532 +    time_t tp[2];
188.1533 +    time_t now = time (0);
188.1534 +    fstat (fd,&sbuf);		/* get file times */
188.1535 +    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
188.1536 +      tp[0] = now;		/* set atime to now */
188.1537 +				/* set mtime to (now - 1) if necessary */
188.1538 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
188.1539 +    }
188.1540 +    else if (stream->recent) {	/* readonly with recent messages */
188.1541 +      if ((sbuf.st_atime >= sbuf.st_mtime) ||
188.1542 +	  (sbuf.st_atime >= sbuf.st_ctime))
188.1543 +				/* keep past mtime, whack back atime */
188.1544 +	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
188.1545 +      else now = 0;		/* no time change needed */
188.1546 +    }
188.1547 +				/* readonly with no recent messages */
188.1548 +    else if ((sbuf.st_atime < sbuf.st_mtime) ||
188.1549 +	     (sbuf.st_atime < sbuf.st_ctime)) {
188.1550 +      tp[0] = now;		/* set atime to now */
188.1551 +				/* set mtime to (now - 1) if necessary */
188.1552 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
188.1553 +    }
188.1554 +    else now = 0;		/* no time change needed */
188.1555 +				/* set the times, note change */
188.1556 +    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
188.1557 +  }
188.1558 +  flock (fd,LOCK_UN);		/* release flock'ers */
188.1559 +  if (!stream) close (fd);	/* close the file if no stream */
188.1560 +  dotlock_unlock (lock);	/* flush the lock file if any */
188.1561 +}
188.1562 +
188.1563 +/* MMDF mail parse and lock mailbox
188.1564 + * Accepts: MAIL stream
188.1565 + *	    space to write lock file name
188.1566 + *	    type of locking operation
188.1567 + * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
188.1568 + */
188.1569 +
188.1570 +int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
188.1571 +{
188.1572 +  int ti,zn,m;
188.1573 +  unsigned long i,j,k;
188.1574 +  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
188.1575 +  int retain = T;
188.1576 +  unsigned long nmsgs = stream->nmsgs;
188.1577 +  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
188.1578 +  unsigned long recent = stream->recent;
188.1579 +  unsigned long oldnmsgs = stream->nmsgs;
188.1580 +  short silent = stream->silent;
188.1581 +  short pseudoseen = NIL;
188.1582 +  struct stat sbuf;
188.1583 +  STRING bs;
188.1584 +  FDDATA d;
188.1585 +  MESSAGECACHE *elt;
188.1586 +  mail_lock (stream);		/* guard against recursion or pingers */
188.1587 +				/* toss out previous descriptor */
188.1588 +  if (LOCAL->fd >= 0) close (LOCAL->fd);
188.1589 +  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
188.1590 +  if ((LOCAL->fd = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ?
188.1591 +			      O_RDWR : O_RDONLY,
188.1592 +			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
188.1593 +			      lock,op)) < 0) {
188.1594 +    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
188.1595 +    MM_LOG (tmp,ERROR);
188.1596 +    mmdf_abort (stream);
188.1597 +    mail_unlock (stream);
188.1598 +    MM_NOCRITICAL (stream);	/* done with critical */
188.1599 +    return NIL;
188.1600 +  }
188.1601 +  fstat (LOCAL->fd,&sbuf);	/* get status */
188.1602 +				/* validate change in size */
188.1603 +  if (sbuf.st_size < LOCAL->filesize) {
188.1604 +    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
188.1605 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
188.1606 +    MM_LOG (tmp,ERROR);		/* this is pretty bad */
188.1607 +    mmdf_unlock (LOCAL->fd,stream,lock);
188.1608 +    mmdf_abort (stream);
188.1609 +    mail_unlock (stream);
188.1610 +    MM_NOCRITICAL (stream);	/* done with critical */
188.1611 +    return NIL;
188.1612 +  }
188.1613 +
188.1614 +				/* new data? */
188.1615 +  else if (i = sbuf.st_size - LOCAL->filesize) {
188.1616 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
188.1617 +    d.pos = LOCAL->filesize;	/* get to that position in the file */
188.1618 +    d.chunk = LOCAL->buf;	/* initial buffer chunk */
188.1619 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
188.1620 +    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
188.1621 +				/* skip leading whitespace for broken MTAs */
188.1622 +    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
188.1623 +	   (c == ' ') || (c == '\t')) SNX (&bs);
188.1624 +    if (SIZE (&bs)) {		/* read new data */
188.1625 +				/* remember internal header position */
188.1626 +      j = LOCAL->filesize + GETPOS (&bs);
188.1627 +      s = mmdf_mbxline (stream,&bs,&i);
188.1628 +      stream->silent = T;	/* quell main program new message events */
188.1629 +      do {			/* read MMDF header */
188.1630 +	if (!(i && ISMMDF (s))){/* see if valid MMDF header */
188.1631 +	  sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
188.1632 +		   (char *) s);
188.1633 +				/* see if we can back up to a line */
188.1634 +	  if (i && (j > MMDFHDRLEN)) {
188.1635 +	    SETPOS (&bs,j -= MMDFHDRLEN);
188.1636 +				/* read previous line */
188.1637 +	    s = mmdf_mbxline (stream,&bs,&i);
188.1638 +				/* kill the error if it looks good */
188.1639 +	    if (i && ISMMDF (s)) tmp[0] = '\0';
188.1640 +	  }
188.1641 +	  if (tmp[0]) {
188.1642 +	    MM_LOG (tmp,ERROR);
188.1643 +	    mmdf_unlock (LOCAL->fd,stream,lock);
188.1644 +	    mmdf_abort (stream);
188.1645 +	    mail_unlock (stream);
188.1646 +	    MM_NOCRITICAL (stream);
188.1647 +	    return NIL;
188.1648 +	  }
188.1649 +	}
188.1650 +				/* instantiate first new message */
188.1651 +	mail_exists (stream,++nmsgs);
188.1652 +	(elt = mail_elt (stream,nmsgs))->valid = T;
188.1653 +	recent++;		/* assume recent by default */
188.1654 +	elt->recent = T;
188.1655 +				/* note position/size of internal header */
188.1656 +	elt->private.special.offset = j;
188.1657 +	elt->private.special.text.size = i;
188.1658 +
188.1659 +	s = mmdf_mbxline (stream,&bs,&i);
188.1660 +	ti = 0;			/* assume not a valid date */
188.1661 +	zn = 0,t = NIL;
188.1662 +	if (i) VALID (s,t,ti,zn);
188.1663 +	if (ti) {		/* generate plausible IMAPish date string */
188.1664 +				/* this is also part of header */
188.1665 +	  elt->private.special.text.size += i;
188.1666 +	  date[2] = date[6] = date[20] = '-'; date[11] = ' ';
188.1667 +	  date[14] = date[17] = ':';
188.1668 +				/* dd */
188.1669 +	  date[0] = t[ti - 2]; date[1] = t[ti - 1];
188.1670 +				/* mmm */
188.1671 +	  date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
188.1672 +				/* hh */
188.1673 +	  date[12] = t[ti + 1]; date[13] = t[ti + 2];
188.1674 +				/* mm */
188.1675 +	  date[15] = t[ti + 4]; date[16] = t[ti + 5];
188.1676 +	  if (t[ti += 6]==':'){	/* ss */
188.1677 +	    date[18] = t[++ti]; date[19] = t[++ti];
188.1678 +	    ti++;		/* move to space */
188.1679 +	  }
188.1680 +	  else date[18] = date[19] = '0';
188.1681 +				/* yy -- advance over timezone if necessary */
188.1682 +	  if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
188.1683 +	  date[7] = t[ti + 1]; date[8] = t[ti + 2];
188.1684 +	  date[9] = t[ti + 3]; date[10] = t[ti + 4];
188.1685 +				/* zzz */
188.1686 +	  t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
188.1687 +	  date[21] = *t++; date[22] = *t++; date[23] = *t++;
188.1688 +	  if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
188.1689 +	  else {		/* numeric time zone */
188.1690 +	    date[24] = *t++; date[25] = *t++;
188.1691 +	    date[26] = '\0'; date[20] = ' ';
188.1692 +	  }
188.1693 +				/* set internal date */
188.1694 +	  if (!mail_parse_date (elt,date)) {
188.1695 +	    sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
188.1696 +	    MM_LOG (tmp,WARN);
188.1697 +	  }
188.1698 +	}
188.1699 +	else {			/* make date from file date */
188.1700 +	  struct tm *tm = gmtime (&sbuf.st_mtime);
188.1701 +	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
188.1702 +	  elt->year = tm->tm_year + 1900 - BASEYEAR;
188.1703 +	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
188.1704 +	  elt->seconds = tm->tm_sec;
188.1705 +	  elt->zhours = 0; elt->zminutes = 0;
188.1706 +	  t = NIL;		/* suppress line read */
188.1707 +	}
188.1708 +				/* header starts here */
188.1709 +	elt->private.msg.header.offset = elt->private.special.text.size;
188.1710 +
188.1711 +	do {			/* look for message body */
188.1712 +	  j = GETPOS (&bs);	/* note position before line */
188.1713 +	  if (t) s = t = mmdf_mbxline (stream,&bs,&i);
188.1714 +	  else t = s;		/* this line read was suppressed */
188.1715 +	  if (ISMMDF (s)) {	/* found terminator in header? */
188.1716 +	    SETPOS (&bs,j);	/* oops, back up before line */
188.1717 +				/* must insert a newline */
188.1718 +	    elt->private.spare.data++;
188.1719 +	    break;		/* punt */
188.1720 +	  }
188.1721 +				/* this line is part of header */
188.1722 +	  elt->private.msg.header.text.size += i;
188.1723 +	  if (i) switch (*s) {	/* check header lines */
188.1724 +	  case 'X':		/* possible X-???: line */
188.1725 +	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
188.1726 +				/* X-Status: becomes Status: in S case */
188.1727 +	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
188.1728 +		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
188.1729 +				/* possible X-Keywords */
188.1730 +	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
188.1731 +		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
188.1732 +		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
188.1733 +		SIZEDTEXT uf;
188.1734 +		retain = NIL;	/* don't retain continuation */
188.1735 +		s += 11;	/* flush leading whitespace */
188.1736 +		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
188.1737 +		  while (*s == ' ') s++;
188.1738 +				/* find end of keyword */
188.1739 +		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
188.1740 +				/* got a keyword? */
188.1741 +		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
188.1742 +		    uf.data = (unsigned char *) s;
188.1743 +		    uf.size = k;
188.1744 +		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
188.1745 +		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
188.1746 +			elt->user_flags |= ((long) 1) << j;
188.1747 +			break;
188.1748 +		      }
188.1749 +		  }
188.1750 +		  s = u;	/* advance to next keyword */
188.1751 +		}
188.1752 +		break;
188.1753 +	      }
188.1754 +
188.1755 +				/* possible X-IMAP */
188.1756 +	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
188.1757 +		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
188.1758 +					 ((s[6] == 'b') && (s[7] == 'a') &&
188.1759 +					  (s[8] == 's') && (s[9] == 'e') &&
188.1760 +					  (s[10] == ':')))) {
188.1761 +		retain = NIL;	/* don't retain continuation */
188.1762 +		if ((nmsgs == 1) && !stream->uid_validity) {
188.1763 +				/* advance to data */
188.1764 +		  s += m ? 7 : 11;
188.1765 +				/* flush whitespace */
188.1766 +		  while (*s == ' ') s++;
188.1767 +		  j = 0;	/* slurp UID validity */
188.1768 +				/* found a digit? */
188.1769 +		  while (isdigit (*s)) {
188.1770 +		    j *= 10;	/* yes, add it in */
188.1771 +		    j += *s++ - '0';
188.1772 +		  }
188.1773 +				/* flush whitespace */
188.1774 +		  while (*s == ' ') s++;
188.1775 +				/* must have valid UID validity and UID last */
188.1776 +		  if (j && isdigit (*s)) {
188.1777 +				/* pseudo-header seen if X-IMAP */
188.1778 +		    if (m) pseudoseen = LOCAL->pseudo = T;
188.1779 +				/* save UID validity */
188.1780 +		    stream->uid_validity = j;
188.1781 +		    j = 0;	/* slurp UID last */
188.1782 +		    while (isdigit (*s)) {
188.1783 +		      j *= 10;	/* yes, add it in */
188.1784 +		      j += *s++ - '0';
188.1785 +		    }
188.1786 +				/* save UID last */
188.1787 +		    stream->uid_last = j;
188.1788 +				/* process keywords */
188.1789 +		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
188.1790 +			 s = u,j++) {
188.1791 +				/* flush leading whitespace */
188.1792 +		      while (*s == ' ') s++;
188.1793 +		      u = strpbrk (s," \n\r");
188.1794 +				/* got a keyword? */
188.1795 +		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
188.1796 +			  (k <= MAXUSERFLAG)) {
188.1797 +			if (stream->user_flags[j])
188.1798 +			  fs_give ((void **) &stream->user_flags[j]);
188.1799 +			stream->user_flags[j] = (char *) fs_get (k + 1);
188.1800 +			strncpy (stream->user_flags[j],s,k);
188.1801 +			stream->user_flags[j][k] = '\0';
188.1802 +		      }
188.1803 +		    }
188.1804 +		  }
188.1805 +		}
188.1806 +		break;
188.1807 +	      }
188.1808 +
188.1809 +				/* possible X-UID */
188.1810 +	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
188.1811 +		       s[5] == ':') {
188.1812 +		retain = NIL;	/* don't retain continuation */
188.1813 +				/* only believe if have a UID validity */
188.1814 +		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
188.1815 +		  s += 6;	/* advance to UID value */
188.1816 +				/* flush whitespace */
188.1817 +		  while (*s == ' ') s++;
188.1818 +		  j = 0;
188.1819 +				/* found a digit? */
188.1820 +		  while (isdigit (*s)) {
188.1821 +		    j *= 10;	/* yes, add it in */
188.1822 +		    j += *s++ - '0';
188.1823 +		  }
188.1824 +				/* flush remainder of line */
188.1825 +		  while (*s != '\n') s++;
188.1826 +				/* make sure not duplicated */
188.1827 +		  if (elt->private.uid)
188.1828 +		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
188.1829 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
188.1830 +			     j,elt->private.uid);
188.1831 +				/* make sure UID doesn't go backwards */
188.1832 +		  else if (j <= prevuid)
188.1833 +		    sprintf (tmp,"Message %lu UID %lu less than %lu",
188.1834 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
188.1835 +			     j,prevuid + 1);
188.1836 +#if 0	/* this is currently broken by UIDPLUS */
188.1837 +				/* or skip by mailbox's recorded last */
188.1838 +		  else if (j > stream->uid_last)
188.1839 +		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
188.1840 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
188.1841 +			     j,stream->uid_last);
188.1842 +#endif
188.1843 +		  else {	/* normal UID case */
188.1844 +		    prevuid = elt->private.uid = j;
188.1845 +#if 1	/* temporary kludge for UIDPLUS */
188.1846 +		    if (prevuid > stream->uid_last) {
188.1847 +		      stream->uid_last = prevuid;
188.1848 +		      LOCAL->ddirty = LOCAL->dirty = T;
188.1849 +		    }		    
188.1850 +#endif
188.1851 +		    break;	/* exit this cruft */
188.1852 +		  }
188.1853 +		  MM_LOG (tmp,WARN);
188.1854 +				/* invalidate UID validity */
188.1855 +		  stream->uid_validity = 0;
188.1856 +		  elt->private.uid = 0;
188.1857 +		}
188.1858 +		break;
188.1859 +	      }
188.1860 +	    }
188.1861 +				/* otherwise fall into S case */
188.1862 +
188.1863 +	  case 'S':		/* possible Status: line */
188.1864 +	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
188.1865 +		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
188.1866 +	      retain = NIL;	/* don't retain continuation */
188.1867 +	      s += 6;		/* advance to status flags */
188.1868 +	      do switch (*s++) {/* parse flags */
188.1869 +	      case 'R':		/* message read */
188.1870 +		elt->seen = T;
188.1871 +		break;
188.1872 +	      case 'O':		/* message old */
188.1873 +		if (elt->recent) {
188.1874 +		  elt->recent = NIL;
188.1875 +		  recent--;	/* it really wasn't recent */
188.1876 +		}
188.1877 +		break;
188.1878 +	      case 'D':		/* message deleted */
188.1879 +		elt->deleted = T;
188.1880 +		break;
188.1881 +	      case 'F':		/* message flagged */
188.1882 +		elt->flagged = T;
188.1883 +		break;
188.1884 +	      case 'A':		/* message answered */
188.1885 +		elt->answered = T;
188.1886 +		break;
188.1887 +	      case 'T':		/* message is a draft */
188.1888 +		elt->draft = T;
188.1889 +		break;
188.1890 +	      default:		/* some other crap */
188.1891 +		break;
188.1892 +	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
188.1893 +	      break;		/* all done */
188.1894 +	    }
188.1895 +				/* otherwise fall into default case */
188.1896 +
188.1897 +	  default:		/* ordinary header line */
188.1898 +	    if ((*s == 'S') || (*s == 's') ||
188.1899 +		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
188.1900 +	      unsigned char *e,*v;
188.1901 +				/* must match what mail_filter() does */
188.1902 +	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
188.1903 +		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
188.1904 +		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
188.1905 +				  (c != '\r') && (c != '\n')));
188.1906 +		   *v++ = *u++);
188.1907 +	      *v = '\0';	/* tie off */
188.1908 +				/* matches internal header? */
188.1909 +	      if (!compare_cstring (tmp,"STATUS") ||
188.1910 +		  !compare_cstring (tmp,"X-STATUS") ||
188.1911 +		  !compare_cstring (tmp,"X-KEYWORDS") ||
188.1912 +		  !compare_cstring (tmp,"X-UID") ||
188.1913 +		  !compare_cstring (tmp,"X-IMAP") ||
188.1914 +		  !compare_cstring (tmp,"X-IMAPBASE")) {
188.1915 +		char err[MAILTMPLEN];
188.1916 +		sprintf (err,"Discarding bogus %s header in message %lu",
188.1917 +			 (char *) tmp,elt->msgno);
188.1918 +		MM_LOG (err,WARN);
188.1919 +		retain = NIL;	/* don't retain continuation */
188.1920 +		break;		/* different case or something */
188.1921 +	      }
188.1922 +	    }
188.1923 +				/* retain or non-continuation? */
188.1924 +	    if (retain || ((*s != ' ') && (*s != '\t'))) {
188.1925 +	      retain = T;	/* retaining continuation now */
188.1926 +				/* line length in LF format newline */
188.1927 +	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
188.1928 +				/* "internal" header size */
188.1929 +	      elt->private.spare.data += k;
188.1930 +				/* message size */
188.1931 +	      elt->rfc822_size += k + 1;
188.1932 +	    }
188.1933 +	    else {
188.1934 +	      char err[MAILTMPLEN];
188.1935 +	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
188.1936 +		      elt->msgno,(char *) s);
188.1937 +	      if (u = strpbrk (err,"\r\n")) *u = '\0';
188.1938 +	      MM_LOG (err,WARN);
188.1939 +	      break;		/* different case or something */
188.1940 +	    }
188.1941 +	    break;
188.1942 +	  }
188.1943 +	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
188.1944 +				/* "internal" header sans trailing newline */
188.1945 +	if (i) elt->private.spare.data--;
188.1946 +				/* assign a UID if none found */
188.1947 +	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
188.1948 +	  prevuid = elt->private.uid = ++stream->uid_last;
188.1949 +	  elt->private.dirty = T;
188.1950 +	}
188.1951 +	else elt->private.dirty = elt->recent;
188.1952 +
188.1953 +				/* note size of header, location of text */
188.1954 +	elt->private.msg.header.text.size =
188.1955 +	  (elt->private.msg.text.offset =
188.1956 +	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
188.1957 +	     elt->private.special.text.size;
188.1958 +				/* note current position */
188.1959 +	j = LOCAL->filesize + GETPOS (&bs);
188.1960 +	if (i) do {		/* look for next message */
188.1961 +	  s = mmdf_mbxline (stream,&bs,&i);
188.1962 +	  if (i) {		/* got new data? */
188.1963 +	    if (ISMMDF (s)) break;
188.1964 +	    else {		/* not a header line, add it to message */
188.1965 +	      elt->rfc822_size += i;
188.1966 +	      for (j = 0; j < i; ++j) switch (s[j]) {
188.1967 +	      case '\r':	/* squeeze out CRs */
188.1968 +		elt->rfc822_size -= 1;
188.1969 +		break;
188.1970 +	      case '\n':	/* LF becomes CRLF */
188.1971 +		elt->rfc822_size += 1;
188.1972 +		break;
188.1973 +	      default:
188.1974 +		break;
188.1975 +	      }
188.1976 +				/* update current position */
188.1977 +	      j = LOCAL->filesize + GETPOS (&bs);
188.1978 +	    }
188.1979 +	  }
188.1980 +	} while (i);		/* until found a header */
188.1981 +	elt->private.msg.text.text.size = j -
188.1982 +	  (elt->private.special.offset + elt->private.msg.text.offset);
188.1983 +	if (i) {		/* get next header line */
188.1984 +				/* remember first internal header position */
188.1985 +	  j = LOCAL->filesize + GETPOS (&bs);
188.1986 +	  s = mmdf_mbxline (stream,&bs,&i);
188.1987 +	}
188.1988 +				/* until end of buffer */
188.1989 +      } while (!stream->sniff && i);
188.1990 +      if (pseudoseen) {		/* flush pseudo-message if present */
188.1991 +				/* decrement recent count */
188.1992 +	if (mail_elt (stream,1)->recent) recent--;
188.1993 +				/* and the exists count */
188.1994 +	mail_exists (stream,nmsgs--);
188.1995 +	mail_expunged(stream,1);/* fake an expunge of that message */
188.1996 +      }
188.1997 +				/* need to start a new UID validity? */
188.1998 +      if (!stream->uid_validity) {
188.1999 +	stream->uid_validity = time (0);
188.2000 +				/* in case a whiner with no life */
188.2001 +	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
188.2002 +	  stream->uid_nosticky = T;
188.2003 +	else if (nmsgs) {	/* don't bother if empty file */
188.2004 +				/* make dirty to restart UID epoch */
188.2005 +	  LOCAL->ddirty = LOCAL->dirty = T;
188.2006 +				/* need to rewrite msg 1 if not pseudo */
188.2007 +	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
188.2008 +	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
188.2009 +	}
188.2010 +      }
188.2011 +      stream->nmsgs = oldnmsgs;	/* whack it back down */
188.2012 +      stream->silent = silent;	/* restore old silent setting */
188.2013 +				/* notify upper level of new mailbox sizes */
188.2014 +      mail_exists (stream,nmsgs);
188.2015 +      mail_recent (stream,recent);
188.2016 +				/* mark dirty so O flags are set */
188.2017 +      if (recent) LOCAL->dirty = T;
188.2018 +    }
188.2019 +  }
188.2020 +				/* no change, don't babble if never got time */
188.2021 +  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
188.2022 +    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
188.2023 +				/* update parsed file size and time */
188.2024 +  LOCAL->filesize = sbuf.st_size;
188.2025 +  LOCAL->filetime = sbuf.st_mtime;
188.2026 +  return T;			/* return the winnage */
188.2027 +}
188.2028 +
188.2029 +/* MMDF read line from mailbox
188.2030 + * Accepts: mail stream
188.2031 + *	    stringstruct
188.2032 + *	    pointer to line size
188.2033 + * Returns: pointer to input line
188.2034 + */
188.2035 +
188.2036 +char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
188.2037 +{
188.2038 +  unsigned long i,j,k,m;
188.2039 +  char *s,*t,*te;
188.2040 +  char *ret = "";
188.2041 +				/* flush old buffer */
188.2042 +  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
188.2043 +				/* if buffer needs refreshing */
188.2044 +  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
188.2045 +  if (SIZE (bs)) {		/* find newline */
188.2046 +				/* end of fast scan */
188.2047 +    te = (t = (s = bs->curpos) + bs->cursize) - 12;
188.2048 +    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
188.2049 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
188.2050 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
188.2051 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
188.2052 +      --s;			/* back up */
188.2053 +      break;			/* exit loop */
188.2054 +    }
188.2055 +				/* final character-at-a-time scan */
188.2056 +    while ((s < t) && (*s != '\n')) ++s;
188.2057 +				/* difficult case if line spans buffer */
188.2058 +    if ((i = s - bs->curpos) == bs->cursize) {
188.2059 +				/* have space in line buffer? */
188.2060 +      if (i > LOCAL->linebuflen) {
188.2061 +	fs_give ((void **) &LOCAL->linebuf);
188.2062 +	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
188.2063 +      }
188.2064 +				/* remember what we have so far */
188.2065 +      memcpy (LOCAL->linebuf,bs->curpos,i);
188.2066 +				/* load next buffer */
188.2067 +      SETPOS (bs,k = GETPOS (bs) + i);
188.2068 +				/* end of fast scan */
188.2069 +      te = (t = (s = bs->curpos) + bs->cursize) - 12;
188.2070 +				/* fast scan in overlap buffer */
188.2071 +      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
188.2072 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
188.2073 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
188.2074 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
188.2075 +	--s;			/* back up */
188.2076 +	break;			/* exit loop */
188.2077 +      }
188.2078 +
188.2079 +				/* final character-at-a-time scan */
188.2080 +      while ((s < t) && (*s != '\n')) ++s;
188.2081 +				/* huge line? */
188.2082 +      if ((j = s - bs->curpos) == bs->cursize) {
188.2083 +	SETPOS (bs,GETPOS (bs) + j);
188.2084 +				/* look for end of line (s-l-o-w!!) */
188.2085 +	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
188.2086 +	SETPOS (bs,k);		/* go back to where it started */
188.2087 +      }
188.2088 +				/* got size of data, make buffer for return */
188.2089 +      ret = LOCAL->line = (char *) fs_get (i + j + 2);
188.2090 +				/* copy first chunk */
188.2091 +      memcpy (ret,LOCAL->linebuf,i);
188.2092 +      while (j) {		/* copy remainder */
188.2093 +	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
188.2094 +	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
188.2095 +	i += k;			/* account for this much read in */
188.2096 +	j -= k;
188.2097 +	bs->curpos += k;	/* increment new position */
188.2098 +	bs->cursize -= k;	/* eat that many bytes */
188.2099 +      }
188.2100 +				/* read newline at end */
188.2101 +      if (SIZE (bs)) ret[i++] = SNX (bs);
188.2102 +      ret[i] = '\0';		/* makes debugging easier */
188.2103 +    }
188.2104 +    else {			/* this is easy */
188.2105 +      ret = bs->curpos;		/* string it at this position */
188.2106 +      bs->curpos += ++i;	/* increment new position */
188.2107 +      bs->cursize -= i;		/* eat that many bytes */
188.2108 +    }
188.2109 +    *size = i;			/* return that to user */
188.2110 +  }
188.2111 +  else *size = 0;		/* end of data, return empty */
188.2112 +				/* embedded MMDF header at end of line? */
188.2113 +  if ((*size > sizeof (MMDFHDRTXT)) &&
188.2114 +      (s = ret + *size - (i = sizeof (MMDFHDRTXT) - 1)) && ISMMDF (s)) {
188.2115 +    SETPOS (bs,GETPOS (bs) - i);/* back up to start of MMDF header */
188.2116 +    *size -= i;			/* reduce length of line */
188.2117 +    ret[*size - 1] = '\n';	/* force newline at end */
188.2118 +  }
188.2119 +  return ret;
188.2120 +}
188.2121 +
188.2122 +/* MMDF make pseudo-header
188.2123 + * Accepts: MAIL stream
188.2124 + *	    buffer to write pseudo-header
188.2125 + * Returns: length of pseudo-header
188.2126 + */
188.2127 +
188.2128 +unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr)
188.2129 +{
188.2130 +  int i;
188.2131 +  char *s,tmp[MAILTMPLEN];
188.2132 +  time_t now = time (0);
188.2133 +  rfc822_fixed_date (tmp);
188.2134 +  sprintf (hdr,"%sFrom %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
188.2135 +	   mmdfhdr,pseudo_from,ctime (&now),
188.2136 +	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
188.2137 +	   (unsigned long) now,mylocalhost (),stream->uid_validity,
188.2138 +	   stream->uid_last);
188.2139 +  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
188.2140 +    if (stream->user_flags[i])
188.2141 +      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
188.2142 +  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
188.2143 +  return strlen (hdr);
188.2144 +}
188.2145 +
188.2146 +/* MMDF make status string
188.2147 + * Accepts: MAIL stream
188.2148 + *	    destination string to write
188.2149 + *	    message cache entry
188.2150 + *	    UID to write if non-zero (else use elt->private.uid)
188.2151 + *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
188.2152 + * Returns: length of string
188.2153 + */
188.2154 +
188.2155 +unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
188.2156 +			    unsigned long uid,long flag)
188.2157 +{
188.2158 +  char *t,stack[64];
188.2159 +  char *s = status;
188.2160 +  unsigned long n;
188.2161 +  int pad = 50;
188.2162 +  int sticky = uid ? T : !stream->uid_nosticky;
188.2163 +  /* This used to use sprintf(), but thanks to certain cretinous C libraries
188.2164 +     with horribly slow implementations of sprintf() I had to change it to this
188.2165 +     mess.  At least it should be fast. */
188.2166 +  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
188.2167 +    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
188.2168 +    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
188.2169 +    t = stack;
188.2170 +    n = stream->uid_validity;	/* push UID validity digits on the stack */
188.2171 +    do *t++ = (char) (n % 10) + '0';
188.2172 +    while (n /= 10);
188.2173 +				/* pop UID validity digits from stack */
188.2174 +    while (t > stack) *s++ = *--t;
188.2175 +   *s++ = ' ';
188.2176 +    n = stream->uid_last;	/* push UID last digits on the stack */
188.2177 +    do *t++ = (char) (n % 10) + '0';
188.2178 +    while (n /= 10);
188.2179 +				/* pop UID last digits from stack */
188.2180 +    while (t > stack) *s++ = *--t;
188.2181 +    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
188.2182 +      for (*s++ = ' '; *t; *s++ = *t++);
188.2183 +    *s++ = '\n';
188.2184 +    pad += 30;			/* increased padding if have IMAPbase */
188.2185 +  }
188.2186 +  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
188.2187 +  *s++ = ':'; *s++ = ' ';
188.2188 +  if (elt->seen) *s++ = 'R';
188.2189 +				/* only write O if have a UID */
188.2190 +  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
188.2191 +  *s++ = '\n';
188.2192 +  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
188.2193 +  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
188.2194 +  if (elt->deleted) *s++ = 'D';
188.2195 +  if (elt->flagged) *s++ = 'F';
188.2196 +  if (elt->answered) *s++ = 'A';
188.2197 +  if (elt->draft) *s++ = 'T';
188.2198 +    *s++ = '\n';
188.2199 +
188.2200 +  if (sticky) {			/* only do this if UIDs sticky */
188.2201 +    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
188.2202 +    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
188.2203 +    if (n = elt->user_flags) do {
188.2204 +      *s++ = ' ';
188.2205 +      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
188.2206 +    } while (n);
188.2207 +    n = s - status;		/* get size of stuff so far */
188.2208 +				/* pad X-Keywords to make size constant */
188.2209 +    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
188.2210 +    *s++ = '\n';
188.2211 +    if (flag) {			/* want to include UID? */
188.2212 +      t = stack;
188.2213 +				/* push UID digits on the stack */
188.2214 +      n = uid ? uid : elt->private.uid;
188.2215 +      do *t++ = (char) (n % 10) + '0';
188.2216 +      while (n /= 10);
188.2217 +      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
188.2218 +      *s++ = ' ';
188.2219 +				/* pop UID from stack */
188.2220 +      while (t > stack) *s++ = *--t;
188.2221 +      *s++ = '\n';
188.2222 +    }
188.2223 +  }
188.2224 +  *s++ = '\n'; *s = '\0';	/* end of extended message status */
188.2225 +  return s - status;		/* return size of resulting string */
188.2226 +}
188.2227 +
188.2228 +/* Rewrite mailbox file
188.2229 + * Accepts: MAIL stream, must be critical and locked
188.2230 + *	    return pointer to number of expunged messages if want expunge
188.2231 + *	    lock file name
188.2232 + *	    expunge sequence, not deleted flag
188.2233 + * Returns: T if success and mailbox unlocked, NIL if failure
188.2234 + */
188.2235 +
188.2236 +#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
188.2237 +
188.2238 +long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
188.2239 +		   long flags)
188.2240 +{
188.2241 +  MESSAGECACHE *elt;
188.2242 +  MMDFFILE f;
188.2243 +  char *s;
188.2244 +  time_t tp[2];
188.2245 +  long ret,flag;
188.2246 +  unsigned long i,j;
188.2247 +  unsigned long recent = stream->recent;
188.2248 +  unsigned long size = LOCAL->pseudo ? mmdf_pseudo (stream,LOCAL->buf) : 0;
188.2249 +  if (nexp) *nexp = 0;		/* initially nothing expunged */
188.2250 +				/* calculate size of mailbox after rewrite */
188.2251 +  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
188.2252 +    elt = mail_elt (stream,i);	/* get cache */
188.2253 +    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
188.2254 +				/* add RFC822 size of this message */
188.2255 +      size += elt->private.special.text.size + elt->private.spare.data +
188.2256 +	mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
188.2257 +	  elt->private.msg.text.text.size + MMDFHDRLEN;
188.2258 +      flag = 1;			/* only count X-IMAPbase once */
188.2259 +    }
188.2260 +  }
188.2261 +				/* no messages, has a life, and no pseudo */
188.2262 +  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
188.2263 +    LOCAL->pseudo = T;		/* so make a pseudo-message now */
188.2264 +    size = mmdf_pseudo (stream,LOCAL->buf);
188.2265 +  }
188.2266 +				/* extend the file as necessary */
188.2267 +  if (ret = mmdf_extend (stream,size)) {
188.2268 +    /* Set up buffered I/O file structure
188.2269 +     * curpos	current position being written through buffering
188.2270 +     * filepos	current position being written physically to the disk
188.2271 +     * bufpos	current position being written in the buffer
188.2272 +     * protect	current maximum position that can be written to the disk
188.2273 +     *		before buffering is forced
188.2274 +     * The code tries to buffer so that that disk is written in multiples of
188.2275 +     * OVERBLOWBUFLEN bytes.
188.2276 +     */
188.2277 +    f.stream = stream;		/* note mail stream */
188.2278 +    f.curpos = f.filepos = 0;	/* start of file */
188.2279 +    f.protect = stream->nmsgs ?	/* initial protection pointer */
188.2280 +    mail_elt (stream,1)->private.special.offset : 8192;
188.2281 +    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
188.2282 +
188.2283 +    if (LOCAL->pseudo)		/* update pseudo-header */
188.2284 +      mmdf_write (&f,LOCAL->buf,mmdf_pseudo (stream,LOCAL->buf));
188.2285 +				/* loop through all messages */
188.2286 +    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
188.2287 +      elt = mail_elt (stream,i);/* get cache */
188.2288 +				/* expunge this message? */
188.2289 +      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
188.2290 +				/* one less recent message */
188.2291 +	if (elt->recent) --recent;
188.2292 +	mail_expunged(stream,i);/* notify upper levels */
188.2293 +	++*nexp;		/* count up one more expunged message */
188.2294 +      }
188.2295 +      else {			/* preserve this message */
188.2296 +	i++;			/* advance to next message */
188.2297 +	if ((flag < 0) ||	/* need to rewrite message? */
188.2298 +	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
188.2299 +	    (elt->private.msg.header.text.size !=
188.2300 +	     (elt->private.spare.data +
188.2301 +	      mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
188.2302 +	  unsigned long newoffset = f.curpos;
188.2303 +				/* yes, seek to internal header */
188.2304 +	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
188.2305 +	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
188.2306 +				/* see if need to squeeze out a CR */
188.2307 +	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
188.2308 +	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
188.2309 +	    --size;		/* squeezed out a CR from PC */
188.2310 +	  }
188.2311 +				/* protection pointer moves to RFC822 header */
188.2312 +	  f.protect = elt->private.special.offset +
188.2313 +	    elt->private.msg.header.offset;
188.2314 +				/* write internal header */
188.2315 +	  mmdf_write (&f,LOCAL->buf,elt->private.special.text.size);
188.2316 +				/* get RFC822 header */
188.2317 +	  s = mmdf_header (stream,elt->msgno,&j,FT_INTERNAL);
188.2318 +				/* in case this got decremented */
188.2319 +	  elt->private.msg.header.offset = elt->private.special.text.size;
188.2320 +				/* header size, sans trailing newline */
188.2321 +	  if ((j < 2) || (s[j - 2] == '\n')) j--;
188.2322 +				/* this can happen if CRs were squeezed */
188.2323 +	  if (j < elt->private.spare.data) {
188.2324 +				/* so fix up counts */
188.2325 +	    size -= elt->private.spare.data - j;
188.2326 +	    elt->private.spare.data = j;
188.2327 +	  }
188.2328 +	  else if (j != elt->private.spare.data)
188.2329 +	    fatal ("header size inconsistent");
188.2330 +				/* protection pointer moves to RFC822 text */
188.2331 +	  f.protect = elt->private.special.offset +
188.2332 +	    elt->private.msg.text.offset;
188.2333 +	  mmdf_write (&f,s,j);	/* write RFC822 header */
188.2334 +				/* write status and UID */
188.2335 +	  mmdf_write (&f,LOCAL->buf,
188.2336 +		      j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag));
188.2337 +	  flag = 1;		/* only write X-IMAPbase once */
188.2338 +				/* new file header size */
188.2339 +	  elt->private.msg.header.text.size = elt->private.spare.data + j;
188.2340 +
188.2341 +				/* did text move? */
188.2342 +	  if (f.curpos != f.protect) {
188.2343 +				/* get message text */
188.2344 +	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
188.2345 +				/* this can happen if CRs were squeezed */
188.2346 +	    if (j < elt->private.msg.text.text.size) {
188.2347 +				/* so fix up counts */
188.2348 +	      size -= elt->private.msg.text.text.size - j;
188.2349 +	      elt->private.msg.text.text.size = j;
188.2350 +	    }
188.2351 +				/* can't happen it says here */
188.2352 +	    else if (j > elt->private.msg.text.text.size)
188.2353 +	      fatal ("text size inconsistent");
188.2354 +				/* new text offset, status/UID may change it */
188.2355 +	    elt->private.msg.text.offset = f.curpos - newoffset;
188.2356 +				/* protection pointer moves to next message */
188.2357 +	    f.protect = (i <= stream->nmsgs) ?
188.2358 +	      mail_elt (stream,i)->private.special.offset :
188.2359 +		(f.curpos + j + MMDFHDRLEN);
188.2360 +	    mmdf_write (&f,s,j);/* write text */
188.2361 +				/* write trailing newline */
188.2362 +	    mmdf_write (&f,mmdfhdr,MMDFHDRLEN);
188.2363 +	  }
188.2364 +	  else {		/* tie off header and status */
188.2365 +	    mmdf_write (&f,NIL,NIL);
188.2366 +	    f.curpos = f.protect =/* restart everything at end of message */
188.2367 +	      f.filepos += elt->private.msg.text.text.size + MMDFHDRLEN;
188.2368 +	  }
188.2369 +				/* new internal header offset */
188.2370 +	  elt->private.special.offset = newoffset;
188.2371 +	  elt->private.dirty =NIL;/* message is now clean */
188.2372 +	}
188.2373 +	else {			/* no need to rewrite this message */
188.2374 +				/* tie off previous message if needed */
188.2375 +	  mmdf_write (&f,NIL,NIL);
188.2376 +	  f.curpos = f.protect =/* restart everything at end of message */
188.2377 +	    f.filepos += elt->private.special.text.size +
188.2378 +	      elt->private.msg.header.text.size +
188.2379 +		elt->private.msg.text.text.size + MMDFHDRLEN;
188.2380 +	}
188.2381 +      }
188.2382 +    }
188.2383 +
188.2384 +    mmdf_write (&f,NIL,NIL);	/* tie off final message */
188.2385 +    if (size != f.filepos) fatal ("file size inconsistent");
188.2386 +    fs_give ((void **) &f.buf);	/* free buffer */
188.2387 +				/* make sure tied off */
188.2388 +    ftruncate (LOCAL->fd,LOCAL->filesize = size);
188.2389 +    fsync (LOCAL->fd);		/* make sure the updates take */
188.2390 +    if (size && (flag < 0)) fatal ("lost UID base information");
188.2391 +				/* no longer dirty */
188.2392 +    LOCAL->ddirty = LOCAL->dirty = NIL;
188.2393 +  				/* notify upper level of new mailbox sizes */
188.2394 +    mail_exists (stream,stream->nmsgs);
188.2395 +    mail_recent (stream,recent);
188.2396 +				/* set atime to now, mtime a second earlier */
188.2397 +    tp[1] = (tp[0] = time (0)) - 1;
188.2398 +				/* set the times, note change */
188.2399 +    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
188.2400 +    close (LOCAL->fd);		/* close and reopen file */
188.2401 +    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
188.2402 +			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
188.2403 +	< 0) {
188.2404 +      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
188.2405 +      MM_LOG (LOCAL->buf,ERROR);
188.2406 +      mmdf_abort (stream);
188.2407 +    }
188.2408 +    dotlock_unlock (lock);	/* flush the lock file */
188.2409 +  }
188.2410 +  return ret;			/* return state from algorithm */
188.2411 +}
188.2412 +
188.2413 +/* Extend MMDF mailbox file
188.2414 + * Accepts: MAIL stream
188.2415 + *	    new desired size
188.2416 + * Return: T if success, else NIL
188.2417 + */
188.2418 +
188.2419 +long mmdf_extend (MAILSTREAM *stream,unsigned long size)
188.2420 +{
188.2421 +  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
188.2422 +  if (i) {			/* does the mailbox need to grow? */
188.2423 +    if (i > LOCAL->buflen) {	/* make sure have enough space */
188.2424 +				/* this user won the lottery all right */
188.2425 +      fs_give ((void **) &LOCAL->buf);
188.2426 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
188.2427 +    }
188.2428 +    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
188.2429 +    while (T) {			/* until write successful or punt */
188.2430 +      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
188.2431 +      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
188.2432 +      else {
188.2433 +	long e = errno;		/* note error before doing ftruncate */
188.2434 +	ftruncate (LOCAL->fd,LOCAL->filesize);
188.2435 +	if (MM_DISKERROR (stream,e,NIL)) {
188.2436 +	  fsync (LOCAL->fd);	/* user chose to punt */
188.2437 +	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
188.2438 +	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
188.2439 +	  return NIL;
188.2440 +	}
188.2441 +      }
188.2442 +    }
188.2443 +  }
188.2444 +  return LONGT;
188.2445 +}
188.2446 +
188.2447 +/* Write data to buffered file
188.2448 + * Accepts: buffered file pointer
188.2449 + *	    file data or NIL to indicate "flush buffer"
188.2450 + *	    date size (ignored for "flush buffer")
188.2451 + * Does not return until success
188.2452 + */
188.2453 +
188.2454 +void mmdf_write (MMDFFILE *f,char *buf,unsigned long size)
188.2455 +{
188.2456 +  unsigned long i,j,k;
188.2457 +  if (buf) {			/* doing buffered write? */
188.2458 +    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
188.2459 +				/* yes, have space in current buffer chunk? */
188.2460 +    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
188.2461 +				/* yes, fill up buffer as much as we can */
188.2462 +      memcpy (f->bufpos,buf,k = min (j,size));
188.2463 +      f->bufpos += k;		/* new buffer position */
188.2464 +      f->curpos += k;		/* new current position */
188.2465 +      if (j -= k) return;	/* all done if still have buffer free space */
188.2466 +      buf += k;			/* full, get new unwritten data pointer */
188.2467 +      size -= k;		/* new data size */
188.2468 +      i += k;			/* new buffer data size */
188.2469 +    }
188.2470 +    /* This chunk of the buffer is full.  See if can make some space by
188.2471 +     * writing to the disk, if there's enough unprotected space to do so.
188.2472 +     * Try to fill out any unaligned chunk, along with any subsequent full
188.2473 +     * chunks that will fit in unprotected space.
188.2474 +     */
188.2475 +				/* any unprotected space we can write to? */
188.2476 +    if (j = min (i,f->protect - f->filepos)) {
188.2477 +				/* yes, filepos not at chunk boundary? */
188.2478 +      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
188.2479 +	j -= k;			/* yes, and can write out partial chunk */
188.2480 +      else k = 0;		/* no partial chunk to write */
188.2481 +				/* if at least a chunk free, write that too */
188.2482 +      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
188.2483 +      if (k) {			/* write data if there is anything we can */
188.2484 +	mmdf_phys_write (f,f->buf,k);
188.2485 +				/* slide buffer */
188.2486 +	if (i -= k) memmove (f->buf,f->buf + k,i);
188.2487 +	f->bufpos = f->buf + i;	/* new end of buffer */
188.2488 +      }
188.2489 +    }
188.2490 +
188.2491 +    /* Have flushed the buffer as best as possible.  All done if no more
188.2492 +     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
188.2493 +     * data is larger than a chunk AND the unprotected space is also larger
188.2494 +     * than a chunk, then write as many chunks as we can directly from the
188.2495 +     * data.  Buffer the rest, expanding the buffer as needed.
188.2496 +     */
188.2497 +    if (size) {			/* have more data that we need to buffer? */
188.2498 +				/* can write any of it to disk instead? */
188.2499 +      if ((f->bufpos == f->buf) && 
188.2500 +	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
188.2501 +				/* write as much as we can right now */
188.2502 +	mmdf_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
188.2503 +	buf += j;		/* new data pointer */
188.2504 +	size -= j;		/* new data size */
188.2505 +	f->curpos += j;		/* advance current pointer */
188.2506 +      }
188.2507 +      if (size) {		/* still have data that we need to buffer? */
188.2508 +				/* yes, need to expand the buffer? */
188.2509 +	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
188.2510 +				/* note current position in buffer */
188.2511 +	  j = f->bufpos - f->buf;
188.2512 +	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
188.2513 +	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
188.2514 +				/* in case buffer relocated */
188.2515 +	  f->bufpos = f->buf + j;
188.2516 +	}
188.2517 +				/* buffer remaining data */
188.2518 +	memcpy (f->bufpos,buf,size);
188.2519 +	f->bufpos += size;	/* new end of buffer */
188.2520 +	f->curpos += size;	/* advance current pointer */
188.2521 +      }
188.2522 +    }
188.2523 +  }
188.2524 +  else {			/* flush buffer to disk */
188.2525 +    mmdf_phys_write (f,f->buf,i = f->bufpos - f->buf);
188.2526 +    f->bufpos = f->buf;		/* reset buffer */
188.2527 +				/* update positions */
188.2528 +    f->curpos = f->protect = f->filepos;
188.2529 +  }
188.2530 +}
188.2531 +
188.2532 +/* Physical disk write
188.2533 + * Accepts: buffered file pointer
188.2534 + *	    buffer address
188.2535 + *	    buffer size
188.2536 + * Does not return until success
188.2537 + */
188.2538 +
188.2539 +void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size)
188.2540 +{
188.2541 +  MAILSTREAM *stream = f->stream;
188.2542 +				/* write data at desired position */
188.2543 +  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
188.2544 +		  (write (LOCAL->fd,buf,size) < 0))) {
188.2545 +    int e;
188.2546 +    char tmp[MAILTMPLEN];
188.2547 +    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
188.2548 +    MM_LOG (tmp,ERROR);
188.2549 +    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
188.2550 +  }
188.2551 +  f->filepos += size;		/* update file position */
188.2552 +}
   189.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   189.2 +++ b/src/osdep/amiga/mtx.c	Mon Sep 14 15:17:45 2009 +0900
   189.3 @@ -0,0 +1,1371 @@
   189.4 +/* ========================================================================
   189.5 + * Copyright 1988-2007 University of Washington
   189.6 + *
   189.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   189.8 + * you may not use this file except in compliance with the License.
   189.9 + * You may obtain a copy of the License at
  189.10 + *
  189.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  189.12 + *
  189.13 + * 
  189.14 + * ========================================================================
  189.15 + */
  189.16 +
  189.17 +/*
  189.18 + * Program:	MTX mail routines
  189.19 + *
  189.20 + * Author:	Mark Crispin
  189.21 + *		Networks and Distributed Computing
  189.22 + *		Computing & Communications
  189.23 + *		University of Washington
  189.24 + *		Administration Building, AG-44
  189.25 + *		Seattle, WA  98195
  189.26 + *		Internet: MRC@CAC.Washington.EDU
  189.27 + *
  189.28 + * Date:	22 May 1990
  189.29 + * Last Edited:	11 October 2007
  189.30 + */
  189.31 +
  189.32 +
  189.33 +/*				FILE TIME SEMANTICS
  189.34 + *
  189.35 + * The atime is the last read time of the file.
  189.36 + * The mtime is the last flags update time of the file.
  189.37 + * The ctime is the last write time of the file.
  189.38 + */
  189.39 +
  189.40 +#include <stdio.h>
  189.41 +#include <ctype.h>
  189.42 +#include <errno.h>
  189.43 +extern int errno;		/* just in case */
  189.44 +#include "mail.h"
  189.45 +#include "osdep.h"
  189.46 +#include <pwd.h>
  189.47 +#include <sys/stat.h>
  189.48 +#include <sys/time.h>
  189.49 +#include "misc.h"
  189.50 +#include "dummy.h"
  189.51 +#include "fdstring.h"
  189.52 +
  189.53 +/* MTX I/O stream local data */
  189.54 +	
  189.55 +typedef struct mtx_local {
  189.56 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  189.57 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  189.58 +  int fd;			/* file descriptor for I/O */
  189.59 +  off_t filesize;		/* file size parsed */
  189.60 +  time_t filetime;		/* last file time */
  189.61 +  time_t lastsnarf;		/* last snarf time */
  189.62 +  unsigned char *buf;		/* temporary buffer */
  189.63 +  unsigned long buflen;		/* current size of temporary buffer */
  189.64 +} MTXLOCAL;
  189.65 +
  189.66 +
  189.67 +/* Convenient access to local data */
  189.68 +
  189.69 +#define LOCAL ((MTXLOCAL *) stream->local)
  189.70 +
  189.71 +
  189.72 +/* Function prototypes */
  189.73 +
  189.74 +DRIVER *mtx_valid (char *name);
  189.75 +int mtx_isvalid (char *name,char *tmp);
  189.76 +void *mtx_parameters (long function,void *value);
  189.77 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  189.78 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
  189.79 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  189.80 +long mtx_create (MAILSTREAM *stream,char *mailbox);
  189.81 +long mtx_delete (MAILSTREAM *stream,char *mailbox);
  189.82 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
  189.83 +long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
  189.84 +MAILSTREAM *mtx_open (MAILSTREAM *stream);
  189.85 +void mtx_close (MAILSTREAM *stream,long options);
  189.86 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
  189.87 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
  189.88 +		  unsigned long *length,long flags);
  189.89 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  189.90 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  189.91 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  189.92 +long mtx_ping (MAILSTREAM *stream);
  189.93 +void mtx_check (MAILSTREAM *stream);
  189.94 +void mtx_snarf (MAILSTREAM *stream);
  189.95 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
  189.96 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  189.97 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  189.98 +
  189.99 +char *mtx_file (char *dst,char *name);
 189.100 +long mtx_parse (MAILSTREAM *stream);
 189.101 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
 189.102 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 189.103 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
 189.104 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 189.105 +			  unsigned long *size);
 189.106 +
 189.107 +/* MTX mail routines */
 189.108 +
 189.109 +
 189.110 +/* Driver dispatch used by MAIL */
 189.111 +
 189.112 +DRIVER mtxdriver = {
 189.113 +  "mtx",			/* driver name */
 189.114 +				/* driver flags */
 189.115 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY|DR_LOCKING,
 189.116 +  (DRIVER *) NIL,		/* next driver */
 189.117 +  mtx_valid,			/* mailbox is valid for us */
 189.118 +  mtx_parameters,		/* manipulate parameters */
 189.119 +  mtx_scan,			/* scan mailboxes */
 189.120 +  mtx_list,			/* list mailboxes */
 189.121 +  mtx_lsub,			/* list subscribed mailboxes */
 189.122 +  NIL,				/* subscribe to mailbox */
 189.123 +  NIL,				/* unsubscribe from mailbox */
 189.124 +  dummy_create,			/* create mailbox */
 189.125 +  mtx_delete,			/* delete mailbox */
 189.126 +  mtx_rename,			/* rename mailbox */
 189.127 +  mtx_status,			/* status of mailbox */
 189.128 +  mtx_open,			/* open mailbox */
 189.129 +  mtx_close,			/* close mailbox */
 189.130 +  mtx_flags,			/* fetch message "fast" attributes */
 189.131 +  mtx_flags,			/* fetch message flags */
 189.132 +  NIL,				/* fetch overview */
 189.133 +  NIL,				/* fetch message envelopes */
 189.134 +  mtx_header,			/* fetch message header */
 189.135 +  mtx_text,			/* fetch message body */
 189.136 +  NIL,				/* fetch partial message text */
 189.137 +  NIL,				/* unique identifier */
 189.138 +  NIL,				/* message number */
 189.139 +  mtx_flag,			/* modify flags */
 189.140 +  mtx_flagmsg,			/* per-message modify flags */
 189.141 +  NIL,				/* search for message based on criteria */
 189.142 +  NIL,				/* sort messages */
 189.143 +  NIL,				/* thread messages */
 189.144 +  mtx_ping,			/* ping mailbox to see if still alive */
 189.145 +  mtx_check,			/* check for new messages */
 189.146 +  mtx_expunge,			/* expunge deleted messages */
 189.147 +  mtx_copy,			/* copy messages to another mailbox */
 189.148 +  mtx_append,			/* append string message to mailbox */
 189.149 +  NIL				/* garbage collect stream */
 189.150 +};
 189.151 +
 189.152 +				/* prototype stream */
 189.153 +MAILSTREAM mtxproto = {&mtxdriver};
 189.154 +
 189.155 +/* MTX mail validate mailbox
 189.156 + * Accepts: mailbox name
 189.157 + * Returns: our driver if name is valid, NIL otherwise
 189.158 + */
 189.159 +
 189.160 +DRIVER *mtx_valid (char *name)
 189.161 +{
 189.162 +  char tmp[MAILTMPLEN];
 189.163 +  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
 189.164 +}
 189.165 +
 189.166 +
 189.167 +/* MTX mail test for valid mailbox
 189.168 + * Accepts: mailbox name
 189.169 + * Returns: T if valid, NIL otherwise
 189.170 + */
 189.171 +
 189.172 +int mtx_isvalid (char *name,char *tmp)
 189.173 +{
 189.174 +  int fd;
 189.175 +  int ret = NIL;
 189.176 +  char *s,file[MAILTMPLEN];
 189.177 +  struct stat sbuf;
 189.178 +  time_t tp[2];
 189.179 +  errno = EINVAL;		/* assume invalid argument */
 189.180 +				/* if file, get its status */
 189.181 +  if ((s = mtx_file (file,name)) && !stat (s,&sbuf)) {
 189.182 +    if (!sbuf.st_size) {	/* allow empty file if INBOX */
 189.183 +      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
 189.184 +      else errno = 0;		/* empty file */
 189.185 +    }
 189.186 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 189.187 +      memset (tmp,'\0',MAILTMPLEN);
 189.188 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
 189.189 +	  (s[1] == '\012')) {	/* valid format? */
 189.190 +	*s = '\0';		/* tie off header */
 189.191 +				/* must begin with dd-mmm-yy" */
 189.192 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 189.193 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 189.194 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 189.195 +      }
 189.196 +      else errno = -1;		/* bogus format */
 189.197 +      close (fd);		/* close the file */
 189.198 +				/* \Marked status? */
 189.199 +      if (sbuf.st_ctime > sbuf.st_atime) {
 189.200 +	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 189.201 +	tp[1] = sbuf.st_mtime;
 189.202 +	utime (file,tp);	/* set the times */
 189.203 +      }
 189.204 +    }
 189.205 +  }
 189.206 +				/* in case INBOX but not mtx format */
 189.207 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 189.208 +  return ret;			/* return what we should */
 189.209 +}
 189.210 +
 189.211 +/* MTX manipulate driver parameters
 189.212 + * Accepts: function code
 189.213 + *	    function-dependent value
 189.214 + * Returns: function-dependent return value
 189.215 + */
 189.216 +
 189.217 +void *mtx_parameters (long function,void *value)
 189.218 +{
 189.219 +  void *ret = NIL;
 189.220 +  switch ((int) function) {
 189.221 +  case GET_INBOXPATH:
 189.222 +    if (value) ret = mtx_file ((char *) value,"INBOX");
 189.223 +    break;
 189.224 +  }
 189.225 +  return ret;
 189.226 +}
 189.227 +
 189.228 +
 189.229 +/* MTX mail scan mailboxes
 189.230 + * Accepts: mail stream
 189.231 + *	    reference
 189.232 + *	    pattern to search
 189.233 + *	    string to scan
 189.234 + */
 189.235 +
 189.236 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 189.237 +{
 189.238 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 189.239 +}
 189.240 +
 189.241 +
 189.242 +/* MTX mail list mailboxes
 189.243 + * Accepts: mail stream
 189.244 + *	    reference
 189.245 + *	    pattern to search
 189.246 + */
 189.247 +
 189.248 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
 189.249 +{
 189.250 +  if (stream) dummy_list (NIL,ref,pat);
 189.251 +}
 189.252 +
 189.253 +
 189.254 +/* MTX mail list subscribed mailboxes
 189.255 + * Accepts: mail stream
 189.256 + *	    reference
 189.257 + *	    pattern to search
 189.258 + */
 189.259 +
 189.260 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 189.261 +{
 189.262 +  if (stream) dummy_lsub (NIL,ref,pat);
 189.263 +}
 189.264 +
 189.265 +/* MTX mail delete mailbox
 189.266 + * Accepts: MAIL stream
 189.267 + *	    mailbox name to delete
 189.268 + * Returns: T on success, NIL on failure
 189.269 + */
 189.270 +
 189.271 +long mtx_delete (MAILSTREAM *stream,char *mailbox)
 189.272 +{
 189.273 +  return mtx_rename (stream,mailbox,NIL);
 189.274 +}
 189.275 +
 189.276 +
 189.277 +/* MTX mail rename mailbox
 189.278 + * Accepts: MAIL stream
 189.279 + *	    old mailbox name
 189.280 + *	    new mailbox name (or NIL for delete)
 189.281 + * Returns: T on success, NIL on failure
 189.282 + */
 189.283 +
 189.284 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
 189.285 +{
 189.286 +  long ret = T;
 189.287 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 189.288 +  int fd,ld;
 189.289 +  struct stat sbuf;
 189.290 +  if (!mtx_file (file,old) ||
 189.291 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 189.292 +		   ((s = strrchr (tmp,'/')) && !s[1])))) {
 189.293 +    sprintf (tmp,newname ?
 189.294 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 189.295 +	     "Can't delete mailbox %.80s: invalid name",
 189.296 +	     old,newname);
 189.297 +    MM_LOG (tmp,ERROR);
 189.298 +    return NIL;
 189.299 +  }
 189.300 +  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
 189.301 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 189.302 +    MM_LOG (tmp,ERROR);
 189.303 +    return NIL;
 189.304 +  }
 189.305 +				/* get exclusive parse/append permission */
 189.306 +  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
 189.307 +    MM_LOG ("Unable to lock rename mailbox",ERROR);
 189.308 +    return NIL;
 189.309 +  }
 189.310 +				/* lock out other users */
 189.311 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 189.312 +    close (fd);			/* couldn't lock, give up on it then */
 189.313 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 189.314 +    MM_LOG (tmp,ERROR);
 189.315 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 189.316 +    return NIL;
 189.317 +  }
 189.318 +
 189.319 +  if (newname) {		/* want rename? */
 189.320 +    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
 189.321 +      c = *++s;			/* remember first character of inferior */
 189.322 +      *s = '\0';		/* tie off to get just superior */
 189.323 +				/* name doesn't exist, create it */
 189.324 +      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 189.325 +	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
 189.326 +	ret = NIL;
 189.327 +      else *s = c;		/* restore full name */
 189.328 +    }
 189.329 +				/* rename the file */
 189.330 +    if (ret && rename (file,tmp)) {
 189.331 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 189.332 +	       strerror (errno));
 189.333 +      MM_LOG (tmp,ERROR);
 189.334 +      ret = NIL;		/* set failure */
 189.335 +    }
 189.336 +  }
 189.337 +  else if (unlink (file)) {
 189.338 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 189.339 +    MM_LOG (tmp,ERROR);
 189.340 +    ret = NIL;			/* set failure */
 189.341 +  }
 189.342 +  flock (fd,LOCK_UN);		/* release lock on the file */
 189.343 +  close (fd);			/* close the file */
 189.344 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 189.345 +				/* recreate file if renamed INBOX */
 189.346 +  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"INBOX.MTX");
 189.347 +  return ret;			/* return success */
 189.348 +}
 189.349 +
 189.350 +/* Mtx Mail status
 189.351 + * Accepts: mail stream
 189.352 + *	    mailbox name
 189.353 + *	    status flags
 189.354 + * Returns: T on success, NIL on failure
 189.355 + */
 189.356 +
 189.357 +long mtx_status (MAILSTREAM *stream,char *mbx,long flags)
 189.358 +{
 189.359 +  MAILSTATUS status;
 189.360 +  unsigned long i;
 189.361 +  MAILSTREAM *tstream = NIL;
 189.362 +  MAILSTREAM *systream = NIL;
 189.363 +				/* make temporary stream (unless this mbx) */
 189.364 +  if (!stream && !(stream = tstream =
 189.365 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
 189.366 +  status.flags = flags;		/* return status values */
 189.367 +  status.messages = stream->nmsgs;
 189.368 +  status.recent = stream->recent;
 189.369 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 189.370 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 189.371 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 189.372 +  status.uidnext = stream->uid_last + 1;
 189.373 +  status.uidvalidity = stream->uid_validity;
 189.374 +				/* calculate post-snarf results */
 189.375 +  if (!status.recent && stream->inbox &&
 189.376 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
 189.377 +    status.messages += systream->nmsgs;
 189.378 +    status.recent += systream->recent;
 189.379 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 189.380 +      for (i = 1; i <= systream->nmsgs; i++)
 189.381 +	if (!mail_elt (systream,i)->seen) status.unseen++;
 189.382 +				/* kludge but probably good enough */
 189.383 +    status.uidnext += systream->nmsgs;
 189.384 +  }
 189.385 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 189.386 +  if (tstream) mail_close (tstream);
 189.387 +  if (systream) mail_close (systream);
 189.388 +  return T;			/* success */
 189.389 +}
 189.390 +
 189.391 +/* MTX mail open
 189.392 + * Accepts: stream to open
 189.393 + * Returns: stream on success, NIL on failure
 189.394 + */
 189.395 +
 189.396 +MAILSTREAM *mtx_open (MAILSTREAM *stream)
 189.397 +{
 189.398 +  int fd,ld;
 189.399 +  char tmp[MAILTMPLEN];
 189.400 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 189.401 +				/* return prototype for OP_PROTOTYPE call */
 189.402 +  if (!stream) return user_flags (&mtxproto);
 189.403 +  if (stream->local) fatal ("mtx recycle stream");
 189.404 +  user_flags (stream);		/* set up user flags */
 189.405 +				/* canonicalize the mailbox name */
 189.406 +  if (!mtx_file (tmp,stream->mailbox)) {
 189.407 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 189.408 +    MM_LOG (tmp,ERROR);
 189.409 +  }
 189.410 +  if (stream->rdonly ||
 189.411 +      (fd = open (tmp,O_RDWR,NIL)) < 0) {
 189.412 +    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 189.413 +      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
 189.414 +      MM_LOG (tmp,ERROR);
 189.415 +      return NIL;
 189.416 +    }
 189.417 +    else if (!stream->rdonly) {	/* got it, but readonly */
 189.418 +      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 189.419 +      stream->rdonly = T;
 189.420 +    }
 189.421 +  }
 189.422 +  stream->local = fs_get (sizeof (MTXLOCAL));
 189.423 +  LOCAL->fd = fd;		/* bind the file */
 189.424 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 189.425 +  LOCAL->buflen = CHUNKSIZE - 1;
 189.426 +				/* note if an INBOX or not */
 189.427 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 189.428 +  fs_give ((void **) &stream->mailbox);
 189.429 +  stream->mailbox = cpystr (tmp);
 189.430 +				/* get shared parse permission */
 189.431 +  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
 189.432 +    MM_LOG ("Unable to lock open mailbox",ERROR);
 189.433 +    return NIL;
 189.434 +  }
 189.435 +  (*bn) (BLOCK_FILELOCK,NIL);
 189.436 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 189.437 +  (*bn) (BLOCK_NONE,NIL);
 189.438 +  unlockfd (ld,tmp);		/* release shared parse permission */
 189.439 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 189.440 +				/* time not set up yet */
 189.441 +  LOCAL->lastsnarf = LOCAL->filetime = 0;
 189.442 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 189.443 +  stream->sequence++;		/* bump sequence number */
 189.444 +				/* parse mailbox */
 189.445 +  stream->nmsgs = stream->recent = 0;
 189.446 +  if (mtx_ping (stream) && !stream->nmsgs)
 189.447 +    MM_LOG ("Mailbox is empty",(long) NIL);
 189.448 +  if (!LOCAL) return NIL;	/* failure if stream died */
 189.449 +  stream->perm_seen = stream->perm_deleted =
 189.450 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 189.451 +      stream->rdonly ? NIL : T;
 189.452 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 189.453 +  return stream;		/* return stream to caller */
 189.454 +}
 189.455 +
 189.456 +/* MTX mail close
 189.457 + * Accepts: MAIL stream
 189.458 + *	    close options
 189.459 + */
 189.460 +
 189.461 +void mtx_close (MAILSTREAM *stream,long options)
 189.462 +{
 189.463 +  if (stream && LOCAL) {	/* only if a file is open */
 189.464 +    int silent = stream->silent;
 189.465 +    stream->silent = T;		/* note this stream is dying */
 189.466 +    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
 189.467 +    stream->silent = silent;	/* restore previous status */
 189.468 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 189.469 +    close (LOCAL->fd);		/* close the local file */
 189.470 +				/* free local text buffer */
 189.471 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 189.472 +				/* nuke the local data */
 189.473 +    fs_give ((void **) &stream->local);
 189.474 +    stream->dtb = NIL;		/* log out the DTB */
 189.475 +  }
 189.476 +}
 189.477 +
 189.478 +
 189.479 +/* MTX mail fetch flags
 189.480 + * Accepts: MAIL stream
 189.481 + *	    sequence
 189.482 + *	    option flags
 189.483 + * Sniffs at file to see if some other process changed the flags
 189.484 + */
 189.485 +
 189.486 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
 189.487 +{
 189.488 +  unsigned long i;
 189.489 +  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
 189.490 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 189.491 +       mail_sequence (stream,sequence)))
 189.492 +    for (i = 1; i <= stream->nmsgs; i++) 
 189.493 +      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
 189.494 +}
 189.495 +
 189.496 +/* MTX mail fetch message header
 189.497 + * Accepts: MAIL stream
 189.498 + *	    message # to fetch
 189.499 + *	    pointer to returned header text length
 189.500 + *	    option flags
 189.501 + * Returns: message header in RFC822 format
 189.502 + */
 189.503 +
 189.504 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 189.505 +		  long flags)
 189.506 +{
 189.507 +  *length = 0;			/* default to empty */
 189.508 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 189.509 +				/* get to header position */
 189.510 +  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
 189.511 +				/* is buffer big enough? */
 189.512 +  if (*length > LOCAL->buflen) {
 189.513 +    fs_give ((void **) &LOCAL->buf);
 189.514 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 189.515 +  }
 189.516 +  LOCAL->buf[*length] = '\0';	/* tie off string */
 189.517 +				/* slurp the data */
 189.518 +  read (LOCAL->fd,LOCAL->buf,*length);
 189.519 +  return (char *) LOCAL->buf;
 189.520 +}
 189.521 +
 189.522 +/* MTX mail fetch message text (body only)
 189.523 + * Accepts: MAIL stream
 189.524 + *	    message # to fetch
 189.525 + *	    pointer to returned header text length
 189.526 + *	    option flags
 189.527 + * Returns: T, always
 189.528 + */
 189.529 +
 189.530 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 189.531 +{
 189.532 +  FDDATA d;
 189.533 +  unsigned long i,j;
 189.534 +  MESSAGECACHE *elt;
 189.535 +				/* UID call "impossible" */
 189.536 +  if (flags & FT_UID) return NIL;
 189.537 +  elt = mtx_elt (stream,msgno);	/* get message status */
 189.538 +				/* if message not seen */
 189.539 +  if (!(flags & FT_PEEK) && !elt->seen) {
 189.540 +    elt->seen = T;		/* mark message as seen */
 189.541 +				/* recalculate status */
 189.542 +    mtx_update_status (stream,msgno,NIL);
 189.543 +    MM_FLAGS (stream,msgno);
 189.544 +  }
 189.545 +				/* find header position */
 189.546 +  i = mtx_hdrpos (stream,msgno,&j);
 189.547 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 189.548 +  d.pos = i + j;
 189.549 +  d.chunk = LOCAL->buf;		/* initial buffer chunk */
 189.550 +  d.chunksize = CHUNKSIZE;
 189.551 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 189.552 +  return T;			/* success */
 189.553 +}
 189.554 +
 189.555 +/* MTX mail modify flags
 189.556 + * Accepts: MAIL stream
 189.557 + *	    sequence
 189.558 + *	    flag(s)
 189.559 + *	    option flags
 189.560 + */
 189.561 +
 189.562 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 189.563 +{
 189.564 +  time_t tp[2];
 189.565 +  struct stat sbuf;
 189.566 +  if (!stream->rdonly) {	/* make sure the update takes */
 189.567 +    fsync (LOCAL->fd);
 189.568 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 189.569 +    tp[1] = LOCAL->filetime = sbuf.st_mtime;
 189.570 +    tp[0] = time (0);		/* make sure read comes after all that */
 189.571 +    utime (stream->mailbox,tp);
 189.572 +  }
 189.573 +}
 189.574 +
 189.575 +
 189.576 +/* MTX mail per-message modify flags
 189.577 + * Accepts: MAIL stream
 189.578 + *	    message cache element
 189.579 + */
 189.580 +
 189.581 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 189.582 +{
 189.583 +  struct stat sbuf;
 189.584 +				/* maybe need to do a checkpoint? */
 189.585 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 189.586 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 189.587 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 189.588 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 189.589 +  }
 189.590 +				/* recalculate status */
 189.591 +  mtx_update_status (stream,elt->msgno,NIL);
 189.592 +}
 189.593 +
 189.594 +/* MTX mail ping mailbox
 189.595 + * Accepts: MAIL stream
 189.596 + * Returns: T if stream still alive, NIL if not
 189.597 + */
 189.598 +
 189.599 +long mtx_ping (MAILSTREAM *stream)
 189.600 +{
 189.601 +  unsigned long i = 1;
 189.602 +  long r = T;
 189.603 +  int ld;
 189.604 +  char lock[MAILTMPLEN];
 189.605 +  struct stat sbuf;
 189.606 +  if (stream && LOCAL) {	/* only if stream already open */
 189.607 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 189.608 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 189.609 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 189.610 +				/* check for changed message status */
 189.611 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 189.612 +      LOCAL->filetime = sbuf.st_mtime;
 189.613 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 189.614 +	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
 189.615 +      while (i <= stream->nmsgs) mtx_elt (stream,i++);
 189.616 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 189.617 +    }
 189.618 +				/* get shared parse/append permission */
 189.619 +    if ((sbuf.st_size != LOCAL->filesize) &&
 189.620 +	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 189.621 +				/* parse resulting mailbox */
 189.622 +      r = (mtx_parse (stream)) ? T : NIL;
 189.623 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 189.624 +    }
 189.625 +    if (LOCAL) {		/* stream must still be alive */
 189.626 +				/* snarf if this is a read-write inbox */
 189.627 +      if (stream->inbox && !stream->rdonly) {
 189.628 +	mtx_snarf (stream);
 189.629 +	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
 189.630 +	if ((sbuf.st_size != LOCAL->filesize) &&
 189.631 +	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 189.632 +				/* parse resulting mailbox */
 189.633 +	  r = (mtx_parse (stream)) ? T : NIL;
 189.634 +	  unlockfd (ld,lock);	/* release shared parse/append permission */
 189.635 +	}
 189.636 +      }
 189.637 +    }
 189.638 +  }
 189.639 +  return r;			/* return result of the parse */
 189.640 +}
 189.641 +
 189.642 +
 189.643 +/* MTX mail check mailbox (reparses status too)
 189.644 + * Accepts: MAIL stream
 189.645 + */
 189.646 +
 189.647 +void mtx_check (MAILSTREAM *stream)
 189.648 +{
 189.649 +				/* mark that a check is desired */
 189.650 +  if (LOCAL) LOCAL->mustcheck = T;
 189.651 +  if (mtx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 189.652 +}
 189.653 +
 189.654 +/* MTX mail snarf messages from system inbox
 189.655 + * Accepts: MAIL stream
 189.656 + */
 189.657 +
 189.658 +void mtx_snarf (MAILSTREAM *stream)
 189.659 +{
 189.660 +  unsigned long i = 0;
 189.661 +  unsigned long j,r,hdrlen,txtlen;
 189.662 +  struct stat sbuf;
 189.663 +  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
 189.664 +  MESSAGECACHE *elt;
 189.665 +  MAILSTREAM *sysibx = NIL;
 189.666 +  int ld;
 189.667 +				/* give up if can't get exclusive permission */
 189.668 +  if ((time (0) >= (LOCAL->lastsnarf +
 189.669 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
 189.670 +      strcmp (sysinbox (),stream->mailbox) &&
 189.671 +      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
 189.672 +    MM_CRITICAL (stream);	/* go critical */
 189.673 +				/* sizes match and anything in sysinbox? */
 189.674 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 189.675 +	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
 189.676 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 189.677 +	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
 189.678 +				/* yes, go to end of file in our mailbox */
 189.679 +      lseek (LOCAL->fd,sbuf.st_size,L_SET);
 189.680 +				/* for each message in sysibx mailbox */
 189.681 +      while (r && (++i <= sysibx->nmsgs)) {
 189.682 +				/* snarf message from system INBOX */
 189.683 +	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
 189.684 +	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
 189.685 +				/* if have a message */
 189.686 +	if (j = hdrlen + txtlen) {
 189.687 +				/* calculate header line */
 189.688 +	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
 189.689 +	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
 189.690 +		   ",%lu;0000000000%02o\015\012",j,(unsigned)
 189.691 +		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 189.692 +		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 189.693 +		    (fDRAFT * elt->draft)));
 189.694 +				/* copy message */
 189.695 +	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
 189.696 +	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
 189.697 +	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
 189.698 +	}
 189.699 +	fs_give ((void **) &hdr);
 189.700 +      }
 189.701 +
 189.702 +				/* make sure all the updates take */
 189.703 +      if (fsync (LOCAL->fd)) r = 0;
 189.704 +      if (r) {			/* delete all the messages we copied */
 189.705 +	if (r == 1) strcpy (tmp,"1");
 189.706 +	else sprintf (tmp,"1:%lu",r);
 189.707 +	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 189.708 +	mail_expunge (sysibx);	/* now expunge all those messages */
 189.709 +      }
 189.710 +      else {
 189.711 +	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
 189.712 +	MM_LOG (LOCAL->buf,WARN);
 189.713 +	ftruncate (LOCAL->fd,sbuf.st_size);
 189.714 +      }
 189.715 +      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
 189.716 +      LOCAL->filetime = sbuf.st_mtime;
 189.717 +    }
 189.718 +    if (sysibx) mail_close (sysibx);
 189.719 +    MM_NOCRITICAL (stream);	/* release critical */
 189.720 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 189.721 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 189.722 +  }
 189.723 +}
 189.724 +
 189.725 +/* MTX mail expunge mailbox
 189.726 + * Accepts: MAIL stream
 189.727 + *	    sequence to expunge if non-NIL
 189.728 + *	    expunge options
 189.729 + * Returns: T, always
 189.730 + */
 189.731 +
 189.732 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
 189.733 +{
 189.734 +  long ret;
 189.735 +  time_t tp[2];
 189.736 +  struct stat sbuf;
 189.737 +  off_t pos = 0;
 189.738 +  int ld;
 189.739 +  unsigned long i = 1;
 189.740 +  unsigned long j,k,m,recent;
 189.741 +  unsigned long n = 0;
 189.742 +  unsigned long delta = 0;
 189.743 +  char lock[MAILTMPLEN];
 189.744 +  MESSAGECACHE *elt;
 189.745 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 189.746 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 189.747 +			   mail_uid_sequence (stream,sequence) :
 189.748 +			   mail_sequence (stream,sequence)) : LONGT) &&
 189.749 +	mtx_ping (stream)));	/* parse sequence if given, ping stream */
 189.750 +  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
 189.751 +  else {
 189.752 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 189.753 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 189.754 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 189.755 +    }
 189.756 +  /* The cretins who designed flock() created a window of vulnerability in
 189.757 +   * upgrading locks from shared to exclusive or downgrading from exclusive
 189.758 +   * to shared.  Rather than maintain the lock at shared status at a minimum,
 189.759 +   * flock() actually *releases* the former lock.  Obviously they never talked
 189.760 +   * to any database guys.  Fortunately, we have the parse/append permission
 189.761 +   * lock.  If we require this lock before going exclusive on the mailbox,
 189.762 +   * another process can not sneak in and steal the exclusive mailbox lock on
 189.763 +   * us, because it will block on trying to get parse/append permission first.
 189.764 +   */
 189.765 +				/* get exclusive parse/append permission */
 189.766 +    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
 189.767 +      MM_LOG ("Unable to lock expunge mailbox",ERROR);
 189.768 +				/* make sure see any newly-arrived messages */
 189.769 +    else if (!mtx_parse (stream));
 189.770 +				/* get exclusive access */
 189.771 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 189.772 +      (*bn) (BLOCK_FILELOCK,NIL);
 189.773 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 189.774 +      (*bn) (BLOCK_NONE,NIL);
 189.775 +      MM_LOG ("Can't expunge because mailbox is in use by another process",
 189.776 +	      ERROR);
 189.777 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 189.778 +    }
 189.779 +
 189.780 +    else {
 189.781 +      MM_CRITICAL (stream);	/* go critical */
 189.782 +      recent = stream->recent;	/* get recent now that pinged and locked */
 189.783 +				/* for each message */
 189.784 +      while (i <= stream->nmsgs) {
 189.785 +				/* get cache element */
 189.786 +	elt = mtx_elt (stream,i);
 189.787 +				/* number of bytes to smash or preserve */
 189.788 +	k = elt->private.special.text.size + elt->rfc822_size;
 189.789 +				/* if need to expunge this message */
 189.790 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 189.791 +				/* if recent, note one less recent message */
 189.792 +	  if (elt->recent) --recent;
 189.793 +	  delta += k;		/* number of bytes to delete */
 189.794 +				/* notify upper levels */
 189.795 +	  mail_expunged (stream,i);
 189.796 +	  n++;			/* count up one more expunged message */
 189.797 +	}
 189.798 +	else if (i++ && delta) {/* preserved message */
 189.799 +				/* first byte to preserve */
 189.800 +	  j = elt->private.special.offset;
 189.801 +	  do {			/* read from source position */
 189.802 +	    m = min (k,LOCAL->buflen);
 189.803 +	    lseek (LOCAL->fd,j,L_SET);
 189.804 +	    read (LOCAL->fd,LOCAL->buf,m);
 189.805 +	    pos = j - delta;	/* write to destination position */
 189.806 +	    lseek (LOCAL->fd,pos,L_SET);
 189.807 +	    while (T) {
 189.808 +	      lseek (LOCAL->fd,pos,L_SET);
 189.809 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 189.810 +	      MM_NOTIFY (stream,strerror (errno),WARN);
 189.811 +	      MM_DISKERROR (stream,errno,T);
 189.812 +	    }
 189.813 +	    pos += m;		/* new position */
 189.814 +	    j += m;		/* next chunk, perhaps */
 189.815 +	  } while (k -= m);	/* until done */
 189.816 +				/* note the new address of this text */
 189.817 +	  elt->private.special.offset -= delta;
 189.818 +	}
 189.819 +				/* preserved but no deleted messages */
 189.820 +	else pos = elt->private.special.offset + k;
 189.821 +      }
 189.822 +      if (n) {			/* truncate file after last message */
 189.823 +	if (pos != (LOCAL->filesize -= delta)) {
 189.824 +	  sprintf (LOCAL->buf,
 189.825 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 189.826 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 189.827 +	  MM_LOG (LOCAL->buf,WARN);
 189.828 +	  LOCAL->filesize = pos;/* fix it then */
 189.829 +	}
 189.830 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 189.831 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 189.832 +				/* output the news */
 189.833 +	MM_LOG (LOCAL->buf,(long) NIL);
 189.834 +      }
 189.835 +      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 189.836 +      fsync (LOCAL->fd);	/* force disk update */
 189.837 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 189.838 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
 189.839 +      tp[0] = time (0);		/* reset atime to now */
 189.840 +      utime (stream->mailbox,tp);
 189.841 +      MM_NOCRITICAL (stream);	/* release critical */
 189.842 +				/* notify upper level of new mailbox size */
 189.843 +      mail_exists (stream,stream->nmsgs);
 189.844 +      mail_recent (stream,recent);
 189.845 +      (*bn) (BLOCK_FILELOCK,NIL);
 189.846 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 189.847 +      (*bn) (BLOCK_NONE,NIL);
 189.848 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 189.849 +    }
 189.850 +  }
 189.851 +  return ret;
 189.852 +}
 189.853 +
 189.854 +/* MTX mail copy message(s)
 189.855 + * Accepts: MAIL stream
 189.856 + *	    sequence
 189.857 + *	    destination mailbox
 189.858 + *	    copy options
 189.859 + * Returns: T if success, NIL if failed
 189.860 + */
 189.861 +
 189.862 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 189.863 +{
 189.864 +  struct stat sbuf;
 189.865 +  time_t tp[2];
 189.866 +  MESSAGECACHE *elt;
 189.867 +  unsigned long i,j,k;
 189.868 +  long ret = LONGT;
 189.869 +  int fd,ld;
 189.870 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 189.871 +  mailproxycopy_t pc =
 189.872 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 189.873 +				/* make sure valid mailbox */
 189.874 +  if (!mtx_isvalid (mailbox,LOCAL->buf)) switch (errno) {
 189.875 +  case ENOENT:			/* no such file? */
 189.876 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 189.877 +    return NIL;
 189.878 +  case 0:			/* merely empty file? */
 189.879 +    break;
 189.880 +  case EACCES:			/* file protected */
 189.881 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 189.882 +    MM_LOG (LOCAL->buf,ERROR);
 189.883 +    return NIL;
 189.884 +  case EINVAL:
 189.885 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 189.886 +    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
 189.887 +    MM_LOG (LOCAL->buf,ERROR);
 189.888 +    return NIL;
 189.889 +  default:
 189.890 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 189.891 +    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
 189.892 +    MM_LOG (LOCAL->buf,ERROR);
 189.893 +    return NIL;
 189.894 +  }
 189.895 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 189.896 +	mail_sequence (stream,sequence))) return NIL;
 189.897 +				/* got file? */  
 189.898 +  if ((fd = open (mtx_file (file,mailbox),O_RDWR,NIL)) < 0) {
 189.899 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
 189.900 +    MM_LOG (LOCAL->buf,ERROR);
 189.901 +    return NIL;
 189.902 +  }
 189.903 +  MM_CRITICAL (stream);		/* go critical */
 189.904 +				/* get exclusive parse/append permission */
 189.905 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
 189.906 +    MM_LOG ("Unable to lock copy mailbox",ERROR);
 189.907 +    MM_NOCRITICAL (stream);
 189.908 +    return NIL;
 189.909 +  }
 189.910 +  fstat (fd,&sbuf);		/* get current file size */
 189.911 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 189.912 +
 189.913 +				/* for each requested message */
 189.914 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 189.915 +    if ((elt = mail_elt (stream,i))->sequence) {
 189.916 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 189.917 +				/* number of bytes to copy */
 189.918 +      k = elt->private.special.text.size + elt->rfc822_size;
 189.919 +      do {			/* read from source position */
 189.920 +	j = min (k,LOCAL->buflen);
 189.921 +	read (LOCAL->fd,LOCAL->buf,j);
 189.922 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 189.923 +      } while (ret && (k -= j));/* until done */
 189.924 +    }
 189.925 +				/* make sure all the updates take */
 189.926 +  if (!(ret && (ret = !fsync (fd)))) {
 189.927 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 189.928 +    MM_LOG (LOCAL->buf,ERROR);
 189.929 +    ftruncate (fd,sbuf.st_size);
 189.930 +  }
 189.931 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
 189.932 +				/* else preserve \Marked status */
 189.933 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
 189.934 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
 189.935 +  utime (file,tp);		/* set the times */
 189.936 +  close (fd);			/* close the file */
 189.937 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 189.938 +  MM_NOCRITICAL (stream);	/* release critical */
 189.939 +				/* delete all requested messages */
 189.940 +  if (ret && (options & CP_MOVE)) {
 189.941 +    for (i = 1; i <= stream->nmsgs; i++)
 189.942 +      if ((elt = mtx_elt (stream,i))->sequence) {
 189.943 +	elt->deleted = T;	/* mark message deleted */
 189.944 +				/* recalculate status */
 189.945 +	mtx_update_status (stream,i,NIL);
 189.946 +      }
 189.947 +    if (!stream->rdonly) {	/* make sure the update takes */
 189.948 +      fsync (LOCAL->fd);
 189.949 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 189.950 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
 189.951 +      tp[0] = time (0);		/* make sure atime remains greater */
 189.952 +      utime (stream->mailbox,tp);
 189.953 +    }
 189.954 +  }
 189.955 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 189.956 +    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
 189.957 +  return ret;
 189.958 +}
 189.959 +
 189.960 +/* MTX mail append message from stringstruct
 189.961 + * Accepts: MAIL stream
 189.962 + *	    destination mailbox
 189.963 + *	    append callback
 189.964 + *	    data for callback
 189.965 + * Returns: T if append successful, else NIL
 189.966 + */
 189.967 +
 189.968 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 189.969 +{
 189.970 +  struct stat sbuf;
 189.971 +  int fd,ld,c;
 189.972 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 189.973 +  time_t tp[2];
 189.974 +  FILE *df;
 189.975 +  MESSAGECACHE elt;
 189.976 +  long f;
 189.977 +  unsigned long i,uf;
 189.978 +  STRING *message;
 189.979 +  long ret = LONGT;
 189.980 +				/* default stream to prototype */
 189.981 +  if (!stream) stream = user_flags (&mtxproto);
 189.982 +				/* make sure valid mailbox */
 189.983 +  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
 189.984 +  case ENOENT:			/* no such file? */
 189.985 +    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"INBOX.MTX");
 189.986 +    else {
 189.987 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 189.988 +      return NIL;
 189.989 +    }
 189.990 +				/* falls through */
 189.991 +  case 0:			/* merely empty file? */
 189.992 +    break;
 189.993 +  case EACCES:			/* file protected */
 189.994 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 189.995 +    MM_LOG (tmp,ERROR);
 189.996 +    return NIL;
 189.997 +  case EINVAL:
 189.998 +    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
 189.999 +    MM_LOG (tmp,ERROR);
189.1000 +    return NIL;
189.1001 +  default:
189.1002 +    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
189.1003 +    MM_LOG (tmp,ERROR);
189.1004 +    return NIL;
189.1005 +  }
189.1006 +				/* get first message */
189.1007 +  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
189.1008 +
189.1009 +				/* open destination mailbox */
189.1010 +  if (((fd = open (mtx_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
189.1011 +      !(df = fdopen (fd,"ab"))) {
189.1012 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
189.1013 +    MM_LOG (tmp,ERROR);
189.1014 +    return NIL;
189.1015 +  }
189.1016 +				/* get parse/append permission */
189.1017 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
189.1018 +    MM_LOG ("Unable to lock append mailbox",ERROR);
189.1019 +    close (fd);
189.1020 +    return NIL;
189.1021 +  }
189.1022 +  MM_CRITICAL (stream);		/* go critical */
189.1023 +  fstat (fd,&sbuf);		/* get current file size */
189.1024 +  errno = 0;
189.1025 +  do {				/* parse flags */
189.1026 +    if (!SIZE (message)) {	/* guard against zero-length */
189.1027 +      MM_LOG ("Append of zero-length message",ERROR);
189.1028 +      ret = NIL;
189.1029 +      break;
189.1030 +    }
189.1031 +    f = mail_parse_flags (stream,flags,&i);
189.1032 +				/* reverse bits (dontcha wish we had CIRC?) */
189.1033 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
189.1034 +    if (date) {			/* parse date if given */
189.1035 +      if (!mail_parse_date (&elt,date)) {
189.1036 +	sprintf (tmp,"Bad date in append: %.80s",date);
189.1037 +	MM_LOG (tmp,ERROR);
189.1038 +	ret = NIL;		/* mark failure */
189.1039 +	break;
189.1040 +      }
189.1041 +      mail_date (tmp,&elt);	/* write preseved date */
189.1042 +    }
189.1043 +    else internal_date (tmp);	/* get current date in IMAP format */
189.1044 +				/* write header */
189.1045 +    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
189.1046 +		 (unsigned long) f) < 0) ret = NIL;
189.1047 +    else {			/* write message */
189.1048 +      if (i) do c = 0xff & SNX (message);
189.1049 +      while ((putc (c,df) != EOF) && --i);
189.1050 +				/* get next message */
189.1051 +      if (i || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL;
189.1052 +    }
189.1053 +  } while (ret && message);
189.1054 +				/* if error... */
189.1055 +  if (!ret || (fflush (df) == EOF)) {
189.1056 +    ftruncate (fd,sbuf.st_size);/* revert file */
189.1057 +    close (fd);			/* make sure fclose() doesn't corrupt us */
189.1058 +    if (errno) {
189.1059 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
189.1060 +      MM_LOG (tmp,ERROR);
189.1061 +    }
189.1062 +    ret = NIL;
189.1063 +  }
189.1064 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
189.1065 +				/* else preserve \Marked status */
189.1066 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
189.1067 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
189.1068 +  utime (file,tp);		/* set the times */
189.1069 +  fclose (df);			/* close the file */
189.1070 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
189.1071 +  MM_NOCRITICAL (stream);	/* release critical */
189.1072 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
189.1073 +    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
189.1074 +	    WARN);
189.1075 +  return ret;
189.1076 +}
189.1077 +
189.1078 +/* Internal routines */
189.1079 +
189.1080 +
189.1081 +/* MTX mail generate file string
189.1082 + * Accepts: temporary buffer to write into
189.1083 + *	    mailbox name string
189.1084 + * Returns: local file string or NIL if failure
189.1085 + */
189.1086 +
189.1087 +char *mtx_file (char *dst,char *name)
189.1088 +{
189.1089 +  char tmp[MAILTMPLEN];
189.1090 +  char *s = mailboxfile (dst,name);
189.1091 +				/* return our standard inbox */
189.1092 +  return (s && !*s) ? mailboxfile (dst,mtx_isvalid ("~/INBOX",tmp) ?
189.1093 +				   "~/INBOX" : "INBOX.MTX") : s;
189.1094 +}
189.1095 +
189.1096 +/* MTX mail parse mailbox
189.1097 + * Accepts: MAIL stream
189.1098 + * Returns: T if parse OK
189.1099 + *	    NIL if failure, stream aborted
189.1100 + */
189.1101 +
189.1102 +long mtx_parse (MAILSTREAM *stream)
189.1103 +{
189.1104 +  struct stat sbuf;
189.1105 +  MESSAGECACHE *elt = NIL;
189.1106 +  unsigned char c,*s,*t,*x;
189.1107 +  char tmp[MAILTMPLEN];
189.1108 +  unsigned long i,j;
189.1109 +  long curpos = LOCAL->filesize;
189.1110 +  long nmsgs = stream->nmsgs;
189.1111 +  long recent = stream->recent;
189.1112 +  short added = NIL;
189.1113 +  short silent = stream->silent;
189.1114 +  fstat (LOCAL->fd,&sbuf);	/* get status */
189.1115 +  if (sbuf.st_size < curpos) {	/* sanity check */
189.1116 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
189.1117 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
189.1118 +    MM_LOG (tmp,ERROR);
189.1119 +    mtx_close (stream,NIL);
189.1120 +    return NIL;
189.1121 +  }
189.1122 +  stream->silent = T;		/* don't pass up exists events yet */
189.1123 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
189.1124 +				/* get to that position in the file */
189.1125 +    lseek (LOCAL->fd,curpos,L_SET);
189.1126 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
189.1127 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
189.1128 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
189.1129 +	       i ? strerror (errno) : "no data read");
189.1130 +      MM_LOG (tmp,ERROR);
189.1131 +      mtx_close (stream,NIL);
189.1132 +      return NIL;
189.1133 +    }
189.1134 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
189.1135 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
189.1136 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
189.1137 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
189.1138 +      MM_LOG (tmp,ERROR);
189.1139 +      mtx_close (stream,NIL);
189.1140 +      return NIL;
189.1141 +    }
189.1142 +    *s = '\0';			/* tie off header line */
189.1143 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
189.1144 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
189.1145 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
189.1146 +	       (unsigned long) curpos,(char *) LOCAL->buf);
189.1147 +      MM_LOG (tmp,ERROR);
189.1148 +      mtx_close (stream,NIL);
189.1149 +      return NIL;
189.1150 +    }
189.1151 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
189.1152 +
189.1153 +    added = T;			/* note that a new message was added */
189.1154 +				/* swell the cache */
189.1155 +    mail_exists (stream,++nmsgs);
189.1156 +				/* instantiate an elt for this message */
189.1157 +    (elt = mail_elt (stream,nmsgs))->valid = T;
189.1158 +    elt->private.uid = ++stream->uid_last;
189.1159 +				/* note file offset of header */
189.1160 +    elt->private.special.offset = curpos;
189.1161 +				/* in case error */
189.1162 +    elt->private.special.text.size = 0;
189.1163 +				/* header size not known yet */
189.1164 +    elt->private.msg.header.text.size = 0;
189.1165 +    x = s;			/* parse the header components */
189.1166 +    if (mail_parse_date (elt,LOCAL->buf) &&
189.1167 +	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
189.1168 +	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
189.1169 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
189.1170 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
189.1171 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
189.1172 +      elt->private.special.text.size = i;
189.1173 +    else {			/* oops */
189.1174 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
189.1175 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
189.1176 +      MM_LOG (tmp,ERROR);
189.1177 +      mtx_close (stream,NIL);
189.1178 +      return NIL;
189.1179 +    }
189.1180 +				/* make sure didn't run off end of file */
189.1181 +    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
189.1182 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
189.1183 +	       elt->private.special.offset,(unsigned long) curpos,
189.1184 +	       (unsigned long) sbuf.st_size);
189.1185 +      MM_LOG (tmp,ERROR);
189.1186 +      mtx_close (stream,NIL);
189.1187 +      return NIL;
189.1188 +    }
189.1189 +    c = t[10];			/* remember first system flags byte */
189.1190 +    t[10] = '\0';		/* tie off flags */
189.1191 +    j = strtoul (t,NIL,8);	/* get user flags value */
189.1192 +    t[10] = c;			/* restore first system flags byte */
189.1193 +				/* set up all valid user flags (reversed!) */
189.1194 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
189.1195 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
189.1196 +				/* calculate system flags */
189.1197 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
189.1198 +    if (j & fDELETED) elt->deleted = T;
189.1199 +    if (j & fFLAGGED) elt->flagged = T;
189.1200 +    if (j & fANSWERED) elt->answered = T;
189.1201 +    if (j & fDRAFT) elt->draft = T;
189.1202 +    if (!(j & fOLD)) {		/* newly arrived message? */
189.1203 +      elt->recent = T;
189.1204 +      recent++;			/* count up a new recent message */
189.1205 +				/* mark it as old */
189.1206 +      mtx_update_status (stream,nmsgs,NIL);
189.1207 +    }
189.1208 +  }
189.1209 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
189.1210 +				/* update parsed file size and time */
189.1211 +  LOCAL->filesize = sbuf.st_size;
189.1212 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
189.1213 +  LOCAL->filetime = sbuf.st_mtime;
189.1214 +  if (added && !stream->rdonly){/* make sure atime updated */
189.1215 +    time_t tp[2];
189.1216 +    tp[0] = time (0);
189.1217 +    tp[1] = LOCAL->filetime;
189.1218 +    utime (stream->mailbox,tp);
189.1219 +  }
189.1220 +  stream->silent = silent;	/* can pass up events now */
189.1221 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
189.1222 +  mail_recent (stream,recent);	/* and of change in recent messages */
189.1223 +  return LONGT;			/* return the winnage */
189.1224 +}
189.1225 +
189.1226 +/* MTX get cache element with status updating from file
189.1227 + * Accepts: MAIL stream
189.1228 + *	    message number
189.1229 + * Returns: cache element
189.1230 + */
189.1231 +
189.1232 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
189.1233 +{
189.1234 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
189.1235 +  struct {			/* old flags */
189.1236 +    unsigned int seen : 1;
189.1237 +    unsigned int deleted : 1;
189.1238 +    unsigned int flagged : 1;
189.1239 +    unsigned int answered : 1;
189.1240 +    unsigned int draft : 1;
189.1241 +    unsigned long user_flags;
189.1242 +  } old;
189.1243 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
189.1244 +  old.answered = elt->answered; old.draft = elt->draft;
189.1245 +  old.user_flags = elt->user_flags;
189.1246 +  mtx_read_flags (stream,elt);
189.1247 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
189.1248 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
189.1249 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
189.1250 +    MM_FLAGS (stream,msgno);	/* let top level know */
189.1251 +  return elt;
189.1252 +}
189.1253 +
189.1254 +/* MTX read flags from file
189.1255 + * Accepts: MAIL stream
189.1256 + * Returns: cache element
189.1257 + */
189.1258 +
189.1259 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
189.1260 +{
189.1261 +  unsigned long i,j;
189.1262 +				/* noop if readonly and have valid flags */
189.1263 +  if (stream->rdonly && elt->valid) return;
189.1264 +				/* set the seek pointer */
189.1265 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
189.1266 +	 elt->private.special.text.size - 14,L_SET);
189.1267 +				/* read the new flags */
189.1268 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
189.1269 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
189.1270 +    fatal (LOCAL->buf);
189.1271 +  }
189.1272 +				/* calculate system flags */
189.1273 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
189.1274 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
189.1275 +  elt->flagged = i & fFLAGGED ? T : NIL;
189.1276 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
189.1277 +  LOCAL->buf[10] = '\0';	/* tie off flags */
189.1278 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
189.1279 +				/* set up all valid user flags (reversed!) */
189.1280 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
189.1281 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
189.1282 +  elt->valid = T;		/* have valid flags now */
189.1283 +}
189.1284 +
189.1285 +/* MTX update status string
189.1286 + * Accepts: MAIL stream
189.1287 + *	    message number
189.1288 + *	    flag saying whether or not to sync
189.1289 + */
189.1290 +
189.1291 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
189.1292 +{
189.1293 +  time_t tp[2];
189.1294 +  struct stat sbuf;
189.1295 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
189.1296 +  unsigned long j,k = 0;
189.1297 +				/* readonly */
189.1298 +  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
189.1299 +  else {			/* readwrite */
189.1300 +    j = elt->user_flags;	/* get user flags */
189.1301 +				/* reverse bits (dontcha wish we had CIRC?) */
189.1302 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
189.1303 +				/* print new flag string */
189.1304 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
189.1305 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
189.1306 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
189.1307 +	      (fDRAFT * elt->draft)));
189.1308 +				/* get to that place in the file */
189.1309 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
189.1310 +	   elt->private.special.text.size - 14,L_SET);
189.1311 +				/* write new flags */
189.1312 +    write (LOCAL->fd,LOCAL->buf,12);
189.1313 +    if (syncflag) {		/* sync if requested */
189.1314 +      fsync (LOCAL->fd);
189.1315 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
189.1316 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
189.1317 +      tp[0] = time (0);		/* make sure read is later */
189.1318 +      utime (stream->mailbox,tp);
189.1319 +    }
189.1320 +  }
189.1321 +}
189.1322 +
189.1323 +/* MTX locate header for a message
189.1324 + * Accepts: MAIL stream
189.1325 + *	    message number
189.1326 + *	    pointer to returned header size
189.1327 + * Returns: position of header in file
189.1328 + */
189.1329 +
189.1330 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
189.1331 +			  unsigned long *size)
189.1332 +{
189.1333 +  unsigned long siz;
189.1334 +  long i = 0;
189.1335 +  int q = 0;
189.1336 +  char *s,tmp[MAILTMPLEN];
189.1337 +  MESSAGECACHE *elt = mtx_elt (stream,msgno);
189.1338 +  unsigned long ret = elt->private.special.offset +
189.1339 +    elt->private.special.text.size;
189.1340 +				/* is header size known? */
189.1341 +  if (!(*size = elt->private.msg.header.text.size)) {
189.1342 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
189.1343 +				/* search message for CRLF CRLF */
189.1344 +    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
189.1345 +				/* read another buffer as necessary */
189.1346 +      if ((--i <= 0) &&		/* buffer empty? */
189.1347 +	  (read (LOCAL->fd,s = tmp,
189.1348 +		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
189.1349 +	return ret;		/* I/O error? */
189.1350 +      switch (q) {		/* sniff at buffer */
189.1351 +      case 0:			/* first character */
189.1352 +	q = (*s++ == '\015') ? 1 : 0;
189.1353 +	break;
189.1354 +      case 1:			/* second character */
189.1355 +	q = (*s++ == '\012') ? 2 : 0;
189.1356 +	break;
189.1357 +      case 2:			/* third character */
189.1358 +	q = (*s++ == '\015') ? 3 : 0;
189.1359 +	break;
189.1360 +      case 3:			/* fourth character */
189.1361 +	if (*s++ == '\012') {	/* have the sequence? */
189.1362 +				/* yes, note for later */
189.1363 +	  elt->private.msg.header.text.size = *size = siz;
189.1364 +	  return ret;
189.1365 +	}
189.1366 +	q = 0;			/* lost... */
189.1367 +	break;
189.1368 +      }
189.1369 +    }
189.1370 +				/* header consumes entire message */
189.1371 +    elt->private.msg.header.text.size = *size = elt->rfc822_size;
189.1372 +  }
189.1373 +  return ret;
189.1374 +}
   190.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   190.2 +++ b/src/osdep/amiga/mx.c	Mon Sep 14 15:17:45 2009 +0900
   190.3 @@ -0,0 +1,1287 @@
   190.4 +/* ========================================================================
   190.5 + * Copyright 1988-2008 University of Washington
   190.6 + *
   190.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   190.8 + * you may not use this file except in compliance with the License.
   190.9 + * You may obtain a copy of the License at
  190.10 + *
  190.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  190.12 + *
  190.13 + * 
  190.14 + * ========================================================================
  190.15 + */
  190.16 +
  190.17 +/*
  190.18 + * Program:	MX mail routines
  190.19 + *
  190.20 + * Author(s):	Mark Crispin
  190.21 + *		Networks and Distributed Computing
  190.22 + *		Computing & Communications
  190.23 + *		University of Washington
  190.24 + *		Administration Building, AG-44
  190.25 + *		Seattle, WA  98195
  190.26 + *		Internet: MRC@CAC.Washington.EDU
  190.27 + *
  190.28 + * Date:	3 May 1996
  190.29 + * Last Edited:	6 January 2008
  190.30 + */
  190.31 +
  190.32 +
  190.33 +#include <stdio.h>
  190.34 +#include <ctype.h>
  190.35 +#include <errno.h>
  190.36 +extern int errno;		/* just in case */
  190.37 +#include "mail.h"
  190.38 +#include "osdep.h"
  190.39 +#include <pwd.h>
  190.40 +#include <sys/stat.h>
  190.41 +#include <sys/time.h>
  190.42 +#include "misc.h"
  190.43 +#include "dummy.h"
  190.44 +#include "fdstring.h"
  190.45 +
  190.46 +/* Index file */
  190.47 +
  190.48 +#define MXINDEXNAME "/.mxindex"
  190.49 +#define MXINDEX(d,s) strcat (mx_file (d,s),MXINDEXNAME)
  190.50 +
  190.51 +
  190.52 +/* MX I/O stream local data */
  190.53 +	
  190.54 +typedef struct mx_local {
  190.55 +  int fd;			/* file descriptor of open index */
  190.56 +  unsigned char *buf;		/* temporary buffer */
  190.57 +  unsigned long buflen;		/* current size of temporary buffer */
  190.58 +  unsigned long cachedtexts;	/* total size of all cached texts */
  190.59 +  time_t scantime;		/* last time directory scanned */
  190.60 +} MXLOCAL;
  190.61 +
  190.62 +
  190.63 +/* Convenient access to local data */
  190.64 +
  190.65 +#define LOCAL ((MXLOCAL *) stream->local)
  190.66 +
  190.67 +
  190.68 +/* Function prototypes */
  190.69 +
  190.70 +DRIVER *mx_valid (char *name);
  190.71 +int mx_isvalid (char *name,char *tmp);
  190.72 +int mx_namevalid (char *name);
  190.73 +void *mx_parameters (long function,void *value);
  190.74 +long mx_dirfmttest (char *name);
  190.75 +void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  190.76 +long mx_scan_contents (char *name,char *contents,unsigned long csiz,
  190.77 +		       unsigned long fsiz);
  190.78 +void mx_list (MAILSTREAM *stream,char *ref,char *pat);
  190.79 +void mx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  190.80 +long mx_subscribe (MAILSTREAM *stream,char *mailbox);
  190.81 +long mx_unsubscribe (MAILSTREAM *stream,char *mailbox);
  190.82 +long mx_create (MAILSTREAM *stream,char *mailbox);
  190.83 +long mx_delete (MAILSTREAM *stream,char *mailbox);
  190.84 +long mx_rename (MAILSTREAM *stream,char *old,char *newname);
  190.85 +int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name);
  190.86 +MAILSTREAM *mx_open (MAILSTREAM *stream);
  190.87 +void mx_close (MAILSTREAM *stream,long options);
  190.88 +void mx_fast (MAILSTREAM *stream,char *sequence,long flags);
  190.89 +char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt);
  190.90 +char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
  190.91 +		 long flags);
  190.92 +long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  190.93 +void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  190.94 +void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  190.95 +long mx_ping (MAILSTREAM *stream);
  190.96 +void mx_check (MAILSTREAM *stream);
  190.97 +long mx_expunge (MAILSTREAM *stream,char *sequence,long options);
  190.98 +long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
  190.99 +	      long options);
 190.100 +long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 190.101 +long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
 190.102 +		    STRING *st,SEARCHSET *set);
 190.103 +
 190.104 +int mx_select (struct direct *name);
 190.105 +int mx_numsort (const void *d1,const void *d2);
 190.106 +char *mx_file (char *dst,char *name);
 190.107 +long mx_lockindex (MAILSTREAM *stream);
 190.108 +void mx_unlockindex (MAILSTREAM *stream);
 190.109 +void mx_setdate (char *file,MESSAGECACHE *elt);
 190.110 +
 190.111 +
 190.112 +/* MX mail routines */
 190.113 +
 190.114 +
 190.115 +/* Driver dispatch used by MAIL */
 190.116 +
 190.117 +DRIVER mxdriver = {
 190.118 +  "mx",				/* driver name */
 190.119 +				/* driver flags */
 190.120 +  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT,
 190.121 +  (DRIVER *) NIL,		/* next driver */
 190.122 +  mx_valid,			/* mailbox is valid for us */
 190.123 +  mx_parameters,		/* manipulate parameters */
 190.124 +  mx_scan,			/* scan mailboxes */
 190.125 +  mx_list,			/* find mailboxes */
 190.126 +  mx_lsub,			/* find subscribed mailboxes */
 190.127 +  mx_subscribe,			/* subscribe to mailbox */
 190.128 +  mx_unsubscribe,		/* unsubscribe from mailbox */
 190.129 +  mx_create,			/* create mailbox */
 190.130 +  mx_delete,			/* delete mailbox */
 190.131 +  mx_rename,			/* rename mailbox */
 190.132 +  mail_status_default,		/* status of mailbox */
 190.133 +  mx_open,			/* open mailbox */
 190.134 +  mx_close,			/* close mailbox */
 190.135 +  mx_fast,			/* fetch message "fast" attributes */
 190.136 +  NIL,				/* fetch message flags */
 190.137 +  NIL,				/* fetch overview */
 190.138 +  NIL,				/* fetch message envelopes */
 190.139 +  mx_header,			/* fetch message header only */
 190.140 +  mx_text,			/* fetch message body only */
 190.141 +  NIL,				/* fetch partial message test */
 190.142 +  NIL,				/* unique identifier */
 190.143 +  NIL,				/* message number */
 190.144 +  mx_flag,			/* modify flags */
 190.145 +  mx_flagmsg,			/* per-message modify flags */
 190.146 +  NIL,				/* search for message based on criteria */
 190.147 +  NIL,				/* sort messages */
 190.148 +  NIL,				/* thread messages */
 190.149 +  mx_ping,			/* ping mailbox to see if still alive */
 190.150 +  mx_check,			/* check for new messages */
 190.151 +  mx_expunge,			/* expunge deleted messages */
 190.152 +  mx_copy,			/* copy messages to another mailbox */
 190.153 +  mx_append,			/* append string message to mailbox */
 190.154 +  NIL				/* garbage collect stream */
 190.155 +};
 190.156 +
 190.157 +				/* prototype stream */
 190.158 +MAILSTREAM mxproto = {&mxdriver};
 190.159 +
 190.160 +/* MX mail validate mailbox
 190.161 + * Accepts: mailbox name
 190.162 + * Returns: our driver if name is valid, NIL otherwise
 190.163 + */
 190.164 +
 190.165 +DRIVER *mx_valid (char *name)
 190.166 +{
 190.167 +  char tmp[MAILTMPLEN];
 190.168 +  return mx_isvalid (name,tmp) ? &mxdriver : NIL;
 190.169 +}
 190.170 +
 190.171 +
 190.172 +/* MX mail test for valid mailbox
 190.173 + * Accepts: mailbox name
 190.174 + *	    temporary buffer to use
 190.175 + * Returns: T if valid, NIL otherwise with errno holding dir stat error
 190.176 + */
 190.177 +
 190.178 +int mx_isvalid (char *name,char *tmp)
 190.179 +{
 190.180 +  struct stat sbuf;
 190.181 +  errno = NIL;			/* zap error */
 190.182 +  if ((strlen (name) <= NETMAXMBX) && *mx_file (tmp,name) &&
 190.183 +      !stat (tmp,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
 190.184 +				/* name is directory; is it mx? */
 190.185 +    if (!stat (MXINDEX (tmp,name),&sbuf) &&
 190.186 +	((sbuf.st_mode & S_IFMT) == S_IFREG)) return T;
 190.187 +    errno = NIL;		/* directory but not mx */
 190.188 +  }
 190.189 +  else if (!compare_cstring (name,"INBOX")) errno = NIL;
 190.190 +  return NIL;
 190.191 +}
 190.192 +
 190.193 +
 190.194 +/* MX mail test for valid mailbox
 190.195 + * Accepts: mailbox name
 190.196 + * Returns: T if valid, NIL otherwise
 190.197 + */
 190.198 +
 190.199 +int mx_namevalid (char *name)
 190.200 +{
 190.201 +  char *s = (*name == '/') ? name + 1 : name;
 190.202 +  while (s && *s) {		/* make sure valid name */
 190.203 +    if (isdigit (*s)) s++;	/* digit, check this node further... */
 190.204 +    else if (*s == '/') break;	/* all digit node, barf */
 190.205 +				/* non-digit, skip to next node or return */
 190.206 +    else if (!((s = strchr (s+1,'/')) && *++s)) return T;
 190.207 +  }
 190.208 +  return NIL;			/* all numeric or empty node */
 190.209 +}
 190.210 +
 190.211 +/* MX manipulate driver parameters
 190.212 + * Accepts: function code
 190.213 + *	    function-dependent value
 190.214 + * Returns: function-dependent return value
 190.215 + */
 190.216 +
 190.217 +void *mx_parameters (long function,void *value)
 190.218 +{
 190.219 +  void *ret = NIL;
 190.220 +  switch ((int) function) {
 190.221 +  case GET_INBOXPATH:
 190.222 +    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
 190.223 +    break;
 190.224 +  case GET_DIRFMTTEST:
 190.225 +    ret = (void *) mx_dirfmttest;
 190.226 +    break;
 190.227 +  case GET_SCANCONTENTS:
 190.228 +    ret = (void *) mx_scan_contents;
 190.229 +    break;
 190.230 +  }
 190.231 +  return ret;
 190.232 +}
 190.233 +
 190.234 +
 190.235 +/* MX test for directory format internal node
 190.236 + * Accepts: candidate node name
 190.237 + * Returns: T if internal name, NIL otherwise
 190.238 + */
 190.239 +
 190.240 +long mx_dirfmttest (char *name)
 190.241 +{
 190.242 +  int c;
 190.243 +				/* success if index name or all-numberic */
 190.244 +  if (strcmp (name,MXINDEXNAME+1))
 190.245 +    while (c = *name++) if (!isdigit (c)) return NIL;
 190.246 +  return LONGT;
 190.247 +}
 190.248 +
 190.249 +/* MX scan mailboxes
 190.250 + * Accepts: mail stream
 190.251 + *	    reference
 190.252 + *	    pattern to search
 190.253 + *	    string to scan
 190.254 + */
 190.255 +
 190.256 +void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 190.257 +{
 190.258 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 190.259 +}
 190.260 +
 190.261 +
 190.262 +/* MX scan mailbox for contents
 190.263 + * Accepts: mailbox name
 190.264 + *	    desired contents
 190.265 + *	    contents size
 190.266 + *	    file size (ignored)
 190.267 + * Returns: NIL if contents not found, T if found
 190.268 + */
 190.269 +
 190.270 +long mx_scan_contents (char *name,char *contents,unsigned long csiz,
 190.271 +			unsigned long fsiz)
 190.272 +{
 190.273 +  long i,nfiles;
 190.274 +  void *a;
 190.275 +  char *s;
 190.276 +  long ret = NIL;
 190.277 +  size_t namelen = strlen (name);
 190.278 +  struct stat sbuf;
 190.279 +  struct direct **names = NIL;
 190.280 +  if ((nfiles = scandir (name,&names,mx_select,mx_numsort)) > 0)
 190.281 +    for (i = 0; i < nfiles; ++i) {
 190.282 +      if (!ret) {
 190.283 +	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
 190.284 +		 "%s/%s",name,names[i]->d_name);
 190.285 +	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
 190.286 +	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
 190.287 +	fs_give ((void **) &s);
 190.288 +      }
 190.289 +      fs_give ((void **) &names[i]);
 190.290 +    }
 190.291 +				/* free directory list */
 190.292 +  if (a = (void *) names) fs_give ((void **) &a);
 190.293 +  return ret;
 190.294 +}
 190.295 +
 190.296 +/* MX list mailboxes
 190.297 + * Accepts: mail stream
 190.298 + *	    reference
 190.299 + *	    pattern to search
 190.300 + */
 190.301 +
 190.302 +void mx_list (MAILSTREAM *stream,char *ref,char *pat)
 190.303 +{
 190.304 +  if (stream) dummy_list (NIL,ref,pat);
 190.305 +}
 190.306 +
 190.307 +
 190.308 +/* MX list subscribed mailboxes
 190.309 + * Accepts: mail stream
 190.310 + *	    reference
 190.311 + *	    pattern to search
 190.312 + */
 190.313 +
 190.314 +void mx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 190.315 +{
 190.316 +  if (stream) dummy_lsub (NIL,ref,pat);
 190.317 +}
 190.318 +
 190.319 +/* MX mail subscribe to mailbox
 190.320 + * Accepts: mail stream
 190.321 + *	    mailbox to add to subscription list
 190.322 + * Returns: T on success, NIL on failure
 190.323 + */
 190.324 +
 190.325 +long mx_subscribe (MAILSTREAM *stream,char *mailbox)
 190.326 +{
 190.327 +  return sm_subscribe (mailbox);
 190.328 +}
 190.329 +
 190.330 +
 190.331 +/* MX mail unsubscribe to mailbox
 190.332 + * Accepts: mail stream
 190.333 + *	    mailbox to delete from subscription list
 190.334 + * Returns: T on success, NIL on failure
 190.335 + */
 190.336 +
 190.337 +long mx_unsubscribe (MAILSTREAM *stream,char *mailbox)
 190.338 +{
 190.339 +  return sm_unsubscribe (mailbox);
 190.340 +}
 190.341 +
 190.342 +/* MX mail create mailbox
 190.343 + * Accepts: mail stream
 190.344 + *	    mailbox name to create
 190.345 + * Returns: T on success, NIL on failure
 190.346 + */
 190.347 +
 190.348 +long mx_create (MAILSTREAM *stream,char *mailbox)
 190.349 +{
 190.350 +  DRIVER *test;
 190.351 +  int fd;
 190.352 +  char *s,tmp[MAILTMPLEN];
 190.353 +  int mask = umask (0);
 190.354 +  long ret = NIL;
 190.355 +  if (!mx_namevalid (mailbox))	/* validate name */
 190.356 +    sprintf (tmp,"Can't create mailbox %.80s: invalid MX-format name",mailbox);
 190.357 +				/* must not already exist */
 190.358 +  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
 190.359 +	   strcmp (test->name,"dummy"))
 190.360 +    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
 190.361 +				/* create directory */
 190.362 +  else if (!dummy_create_path (stream,MXINDEX (tmp,mailbox),
 190.363 +			       get_dir_protection (mailbox)))
 190.364 +    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
 190.365 +  else {			/* success */
 190.366 +				/* set index protection */
 190.367 +    set_mbx_protections (mailbox,tmp);
 190.368 +				/* tie off directory name */
 190.369 +    *(s = strrchr (tmp,'/') + 1) = '\0';
 190.370 +				/* set directory protection */
 190.371 +    set_mbx_protections (mailbox,tmp);
 190.372 +    ret = LONGT;
 190.373 +  }
 190.374 +  umask (mask);			/* restore mask */
 190.375 +  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
 190.376 +  return ret;
 190.377 +}
 190.378 +
 190.379 +/* MX mail delete mailbox
 190.380 + *	    mailbox name to delete
 190.381 + * Returns: T on success, NIL on failure
 190.382 + */
 190.383 +
 190.384 +long mx_delete (MAILSTREAM *stream,char *mailbox)
 190.385 +{
 190.386 +  DIR *dirp;
 190.387 +  struct direct *d;
 190.388 +  char *s;
 190.389 +  char tmp[MAILTMPLEN];
 190.390 +  if (!mx_isvalid (mailbox,tmp))
 190.391 +    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
 190.392 +				/* delete index */
 190.393 +  else if (unlink (MXINDEX (tmp,mailbox)))
 190.394 +    sprintf (tmp,"Can't delete mailbox %.80s index: %s",
 190.395 +	     mailbox,strerror (errno));
 190.396 +  else {			/* get directory name */
 190.397 +    *(s = strrchr (tmp,'/')) = '\0';
 190.398 +    if (dirp = opendir (tmp)) {	/* open directory */
 190.399 +      *s++ = '/';		/* restore delimiter */
 190.400 +				/* massacre messages */
 190.401 +      while (d = readdir (dirp)) if (mx_select (d)) {
 190.402 +	strcpy (s,d->d_name);	/* make path */
 190.403 +	unlink (tmp);		/* sayonara */
 190.404 +      }
 190.405 +      closedir (dirp);		/* flush directory */
 190.406 +      *(s = strrchr (tmp,'/')) = '\0';
 190.407 +      if (rmdir (tmp)) {	/* try to remove the directory */
 190.408 +	sprintf (tmp,"Can't delete name %.80s: %s",mailbox,strerror (errno));
 190.409 +	MM_LOG (tmp,WARN);
 190.410 +      }
 190.411 +    }
 190.412 +    return T;			/* always success */
 190.413 +  }
 190.414 +  MM_LOG (tmp,ERROR);		/* something failed */
 190.415 +  return NIL;
 190.416 +}
 190.417 +
 190.418 +/* MX mail rename mailbox
 190.419 + * Accepts: MX mail stream
 190.420 + *	    old mailbox name
 190.421 + *	    new mailbox name
 190.422 + * Returns: T on success, NIL on failure
 190.423 + */
 190.424 +
 190.425 +long mx_rename (MAILSTREAM *stream,char *old,char *newname)
 190.426 +{
 190.427 +  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
 190.428 +  struct stat sbuf;
 190.429 +  if (!mx_isvalid (old,tmp))
 190.430 +    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
 190.431 +  else if (!mx_namevalid (newname))
 190.432 +    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MX-format name",
 190.433 +	     newname);
 190.434 +				/* new mailbox name must not be valid */
 190.435 +  else if (mx_isvalid (newname,tmp))
 190.436 +    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
 190.437 +	     newname);
 190.438 +  else {
 190.439 +    mx_file (tmp,old);		/* build old directory name */
 190.440 +    mx_file (tmp1,newname);	/* and new directory name */
 190.441 +				/* easy if not INBOX */
 190.442 +    if (compare_cstring (old,"INBOX")) {
 190.443 +				/* found superior to destination name? */
 190.444 +      if (s = strrchr (mx_file (tmp1,newname),'/')) {
 190.445 +	c = *++s;	    /* remember first character of inferior */
 190.446 +	*s = '\0';		/* tie off to get just superior */
 190.447 +				/* name doesn't exist, create it */
 190.448 +	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 190.449 +	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
 190.450 +	  return NIL;
 190.451 +	*s = c;			/* restore full name */
 190.452 +      }
 190.453 +      if (!rename (tmp,tmp1)) return LONGT;
 190.454 +    }
 190.455 +
 190.456 +				/* RFC 3501 requires this */
 190.457 +    else if (dummy_create_path (stream,strcat (tmp1,"/"),
 190.458 +				get_dir_protection (newname))) {
 190.459 +      void *a;
 190.460 +      int i,n,lasterror;
 190.461 +      struct direct **names = NIL;
 190.462 +      size_t srcl = strlen (tmp);
 190.463 +      size_t dstl = strlen (tmp1);
 190.464 +				/* rename each mx file to new directory */
 190.465 +      for (i = lasterror = 0,n = scandir (tmp,&names,mx_select,mx_numsort);
 190.466 +	   i < n; ++i) {
 190.467 +	if (mx_rename_work (tmp,srcl,tmp1,dstl,names[i]->d_name))
 190.468 +	  lasterror = errno;
 190.469 +	fs_give ((void **) &names[i]);
 190.470 +      }
 190.471 +				/* free directory list */
 190.472 +      if (a = (void *) names) fs_give ((void **) &a);
 190.473 +      if (lasterror || mx_rename_work (tmp,srcl,tmp1,dstl,MXINDEXNAME+1))
 190.474 +	errno = lasterror;
 190.475 +      else return mx_create (NIL,"INBOX");
 190.476 +    }
 190.477 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
 190.478 +	     old,newname,strerror (errno));
 190.479 +  }
 190.480 +  MM_LOG (tmp,ERROR);		/* something failed */
 190.481 +  return NIL;
 190.482 +}
 190.483 +
 190.484 +
 190.485 +/* MX rename worker routine
 190.486 + * Accepts: source directory name
 190.487 + *	    source directory name length
 190.488 + *	    destination directory name
 190.489 + *	    destination directory name length
 190.490 + *	    name of node to move
 190.491 + * Returns: zero if success, non-zero if error
 190.492 + */
 190.493 +
 190.494 +int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name)
 190.495 +{
 190.496 +  int ret;
 190.497 +  size_t len = strlen (name);
 190.498 +  char *s = (char *) fs_get (srcl + len + 2);
 190.499 +  char *d = (char *) fs_get (dstl + len + 1);
 190.500 +  sprintf (s,"%s/%s",src,name);
 190.501 +  sprintf (d,"%s%s",dst,name);
 190.502 +  ret = rename (s,d);
 190.503 +  fs_give ((void **) &s);
 190.504 +  fs_give ((void **) &d);
 190.505 +  return ret;
 190.506 +}
 190.507 +
 190.508 +/* MX mail open
 190.509 + * Accepts: stream to open
 190.510 + * Returns: stream on success, NIL on failure
 190.511 + */
 190.512 +
 190.513 +MAILSTREAM *mx_open (MAILSTREAM *stream)
 190.514 +{
 190.515 +  char tmp[MAILTMPLEN];
 190.516 +				/* return prototype for OP_PROTOTYPE call */
 190.517 +  if (!stream) return user_flags (&mxproto);
 190.518 +  if (stream->local) fatal ("mx recycle stream");
 190.519 +  stream->local = fs_get (sizeof (MXLOCAL));
 190.520 +				/* note if an INBOX or not */
 190.521 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 190.522 +  mx_file (tmp,stream->mailbox);/* get directory name */
 190.523 +				/* canonicalize mailbox name */
 190.524 +  fs_give ((void **) &stream->mailbox);
 190.525 +  stream->mailbox = cpystr (tmp);
 190.526 +				/* make temporary buffer */
 190.527 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 190.528 +  LOCAL->buflen = CHUNKSIZE - 1;
 190.529 +  LOCAL->scantime = 0;		/* not scanned yet */
 190.530 +  LOCAL->fd = -1;		/* no index yet */
 190.531 +  LOCAL->cachedtexts = 0;	/* no cached texts */
 190.532 +  stream->sequence++;		/* bump sequence number */
 190.533 +				/* parse mailbox */
 190.534 +  stream->nmsgs = stream->recent = 0;
 190.535 +  if (mx_ping (stream) && !(stream->nmsgs || stream->silent))
 190.536 +    MM_LOG ("Mailbox is empty",(long) NIL);
 190.537 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 190.538 +    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 190.539 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 190.540 +  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
 190.541 +    NIL : T;			/* can we create new user flags? */
 190.542 +  return stream;		/* return stream to caller */
 190.543 +}
 190.544 +
 190.545 +/* MX mail close
 190.546 + * Accepts: MAIL stream
 190.547 + *	    close options
 190.548 + */
 190.549 +
 190.550 +void mx_close (MAILSTREAM *stream,long options)
 190.551 +{
 190.552 +  if (LOCAL) {			/* only if a file is open */
 190.553 +    int silent = stream->silent;
 190.554 +    stream->silent = T;		/* note this stream is dying */
 190.555 +    if (options & CL_EXPUNGE) mx_expunge (stream,NIL,NIL);
 190.556 +				/* free local scratch buffer */
 190.557 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 190.558 +				/* nuke the local data */
 190.559 +    fs_give ((void **) &stream->local);
 190.560 +    stream->dtb = NIL;		/* log out the DTB */
 190.561 +    stream->silent = silent;	/* reset silent state */
 190.562 +  }
 190.563 +}
 190.564 +
 190.565 +/* MX mail fetch fast information
 190.566 + * Accepts: MAIL stream
 190.567 + *	    sequence
 190.568 + *	    option flags
 190.569 + */
 190.570 +
 190.571 +void mx_fast (MAILSTREAM *stream,char *sequence,long flags)
 190.572 +{
 190.573 +  unsigned long i;
 190.574 +  MESSAGECACHE *elt;
 190.575 +  if (stream && LOCAL &&
 190.576 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 190.577 +       mail_sequence (stream,sequence)))
 190.578 +    for (i = 1; i <= stream->nmsgs; i++)
 190.579 +      if ((elt = mail_elt (stream,i))->sequence) mx_fast_work (stream,elt);
 190.580 +}
 190.581 +
 190.582 +
 190.583 +/* MX mail fetch fast information
 190.584 + * Accepts: MAIL stream
 190.585 + *	    message cache element
 190.586 + * Returns: name of message file
 190.587 + */
 190.588 +
 190.589 +char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt)
 190.590 +{
 190.591 +  struct stat sbuf;
 190.592 +  struct tm *tm;
 190.593 +				/* build message file name */
 190.594 +  sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
 190.595 +				/* have size yet? */
 190.596 +  if (!elt->rfc822_size && !stat (LOCAL->buf,&sbuf)) {
 190.597 +				/* make plausible IMAPish date string */
 190.598 +    tm = gmtime (&sbuf.st_mtime);
 190.599 +    elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
 190.600 +    elt->year = tm->tm_year + 1900 - BASEYEAR;
 190.601 +    elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
 190.602 +    elt->seconds = tm->tm_sec;
 190.603 +    elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0;
 190.604 +    elt->rfc822_size = sbuf.st_size;
 190.605 +  }
 190.606 +  return (char *) LOCAL->buf;	/* return file name */
 190.607 +}
 190.608 +
 190.609 +/* MX mail fetch message header
 190.610 + * Accepts: MAIL stream
 190.611 + *	    message # to fetch
 190.612 + *	    pointer to returned header text length
 190.613 + *	    option flags
 190.614 + * Returns: message header in RFC822 format
 190.615 + */
 190.616 +
 190.617 +char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 190.618 +		 long flags)
 190.619 +{
 190.620 +  unsigned long i;
 190.621 +  int fd;
 190.622 +  MESSAGECACHE *elt;
 190.623 +  *length = 0;			/* default to empty */
 190.624 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 190.625 +  elt = mail_elt (stream,msgno);/* get elt */
 190.626 +  if (!elt->private.msg.header.text.data) {
 190.627 +				/* purge cache if too big */
 190.628 +    if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
 190.629 +      mail_gc (stream,GC_TEXTS);/* just can't keep that much */
 190.630 +      LOCAL->cachedtexts = 0;
 190.631 +    }
 190.632 +    if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return "";
 190.633 +				/* is buffer big enough? */
 190.634 +    if (elt->rfc822_size > LOCAL->buflen) {
 190.635 +      fs_give ((void **) &LOCAL->buf);
 190.636 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
 190.637 +    }
 190.638 +				/* slurp message */
 190.639 +    read (fd,LOCAL->buf,elt->rfc822_size);
 190.640 +				/* tie off file */
 190.641 +    LOCAL->buf[elt->rfc822_size] = '\0';
 190.642 +    close (fd);			/* flush message file */
 190.643 +				/* find end of header */
 190.644 +    if (elt->rfc822_size < 4) i = 0;
 190.645 +    else for (i = 4; (i < elt->rfc822_size) &&
 190.646 +	      !((LOCAL->buf[i - 4] == '\015') &&
 190.647 +		(LOCAL->buf[i - 3] == '\012') &&
 190.648 +		(LOCAL->buf[i - 2] == '\015') &&
 190.649 +		(LOCAL->buf[i - 1] == '\012')); i++);
 190.650 +				/* copy header */
 190.651 +    cpytxt (&elt->private.msg.header.text,LOCAL->buf,i);
 190.652 +    cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i);
 190.653 +				/* add to cached size */
 190.654 +    LOCAL->cachedtexts += elt->rfc822_size;
 190.655 +  }
 190.656 +  *length = elt->private.msg.header.text.size;
 190.657 +  return (char *) elt->private.msg.header.text.data;
 190.658 +}
 190.659 +
 190.660 +/* MX mail fetch message text (body only)
 190.661 + * Accepts: MAIL stream
 190.662 + *	    message # to fetch
 190.663 + *	    pointer to returned stringstruct
 190.664 + *	    option flags
 190.665 + * Returns: T on success, NIL on failure
 190.666 + */
 190.667 +
 190.668 +long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 190.669 +{
 190.670 +  unsigned long i;
 190.671 +  MESSAGECACHE *elt;
 190.672 +				/* UID call "impossible" */
 190.673 +  if (flags & FT_UID) return NIL;
 190.674 +  elt = mail_elt (stream,msgno);
 190.675 +				/* snarf message if don't have it yet */
 190.676 +  if (!elt->private.msg.text.text.data) {
 190.677 +    mx_header (stream,msgno,&i,flags);
 190.678 +    if (!elt->private.msg.text.text.data) return NIL;
 190.679 +  }
 190.680 +				/* mark as seen */
 190.681 +  if (!(flags & FT_PEEK) && mx_lockindex (stream)) {
 190.682 +    elt->seen = T;
 190.683 +    mx_unlockindex (stream);
 190.684 +    MM_FLAGS (stream,msgno);
 190.685 +  }
 190.686 +  INIT (bs,mail_string,elt->private.msg.text.text.data,
 190.687 +	elt->private.msg.text.text.size);
 190.688 +  return T;
 190.689 +}
 190.690 +
 190.691 +/* MX mail modify flags
 190.692 + * Accepts: MAIL stream
 190.693 + *	    sequence
 190.694 + *	    flag(s)
 190.695 + *	    option flags
 190.696 + */
 190.697 +
 190.698 +void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 190.699 +{
 190.700 +  mx_unlockindex (stream);	/* finished with index */
 190.701 +}
 190.702 +
 190.703 +
 190.704 +/* MX per-message modify flags
 190.705 + * Accepts: MAIL stream
 190.706 + *	    message cache element
 190.707 + */
 190.708 +
 190.709 +void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 190.710 +{
 190.711 +  mx_lockindex (stream);	/* lock index if not already locked */
 190.712 +}
 190.713 +
 190.714 +/* MX mail ping mailbox
 190.715 + * Accepts: MAIL stream
 190.716 + * Returns: T if stream alive, else NIL
 190.717 + */
 190.718 +
 190.719 +long mx_ping (MAILSTREAM *stream)
 190.720 +{
 190.721 +  MAILSTREAM *sysibx = NIL;
 190.722 +  MESSAGECACHE *elt,*selt;
 190.723 +  struct stat sbuf;
 190.724 +  char *s,tmp[MAILTMPLEN];
 190.725 +  int fd;
 190.726 +  unsigned long i,j,r,old;
 190.727 +  long nmsgs = stream->nmsgs;
 190.728 +  long recent = stream->recent;
 190.729 +  int silent = stream->silent;
 190.730 +  if (stat (stream->mailbox,&sbuf)) return NIL;
 190.731 +  stream->silent = T;		/* don't pass up exists events yet */
 190.732 +  if (sbuf.st_ctime != LOCAL->scantime) {
 190.733 +    struct direct **names = NIL;
 190.734 +    long nfiles = scandir (stream->mailbox,&names,mx_select,mx_numsort);
 190.735 +    if (nfiles < 0) nfiles = 0;	/* in case error */
 190.736 +    old = stream->uid_last;
 190.737 +				/* note scanned now */
 190.738 +    LOCAL->scantime = sbuf.st_ctime;
 190.739 +				/* scan directory */
 190.740 +    for (i = 0; i < nfiles; ++i) {
 190.741 +				/* if newly seen, add to list */
 190.742 +      if ((j = atoi (names[i]->d_name)) > old) {
 190.743 +				/* swell the cache */
 190.744 +	mail_exists (stream,++nmsgs);
 190.745 +	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
 190.746 +	elt->valid = T;		/* note valid flags */
 190.747 +	if (old) {		/* other than the first pass? */
 190.748 +	  elt->recent = T;	/* yup, mark as recent */
 190.749 +	  recent++;		/* bump recent count */
 190.750 +	}
 190.751 +      }
 190.752 +      fs_give ((void **) &names[i]);
 190.753 +    }
 190.754 +				/* free directory */
 190.755 +    if (s = (void *) names) fs_give ((void **) &s);
 190.756 +  }
 190.757 +  stream->nmsgs = nmsgs;	/* don't upset mail_uid() */
 190.758 +
 190.759 +				/* if INBOX, snarf from system INBOX  */
 190.760 +  if (mx_lockindex (stream) && stream->inbox &&
 190.761 +      !strcmp (sysinbox (),stream->mailbox)) {
 190.762 +    old = stream->uid_last;
 190.763 +    MM_CRITICAL (stream);	/* go critical */
 190.764 +				/* see if anything in system inbox */
 190.765 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 190.766 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 190.767 +	!sysibx->rdonly && (r = sysibx->nmsgs)) {
 190.768 +      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
 190.769 +				/* build file name we will use */
 190.770 +	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,++old);
 190.771 +				/* snarf message from Berkeley mailbox */
 190.772 +	selt = mail_elt (sysibx,i);
 190.773 +	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
 190.774 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
 190.775 +	     >= 0) &&
 190.776 +	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) &&
 190.777 +	    (write (fd,s,j) == j) &&
 190.778 +	    (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) &&
 190.779 +	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
 190.780 +				/* swell the cache */
 190.781 +	  mail_exists (stream,++nmsgs);
 190.782 +	  stream->uid_last =	/* create new elt, note its file number */
 190.783 +	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
 190.784 +	  recent++;		/* bump recent count */
 190.785 +				/* set up initial flags and date */
 190.786 +	  elt->valid = elt->recent = T;
 190.787 +	  elt->seen = selt->seen;
 190.788 +	  elt->deleted = selt->deleted;
 190.789 +	  elt->flagged = selt->flagged;
 190.790 +	  elt->answered = selt->answered;
 190.791 +	  elt->draft = selt->draft;
 190.792 +	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
 190.793 +	  elt->hours = selt->hours;elt->minutes = selt->minutes;
 190.794 +	  elt->seconds = selt->seconds;
 190.795 +	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
 190.796 +	  elt->zoccident = selt->zoccident;
 190.797 +	  mx_setdate (LOCAL->buf,elt);
 190.798 +	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
 190.799 +	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 190.800 +	}
 190.801 +	else {			/* failed to snarf */
 190.802 +	  if (fd) {		/* did it ever get opened? */
 190.803 +	    close (fd);		/* close descriptor */
 190.804 +	    unlink (LOCAL->buf);/* flush this file */
 190.805 +	  }
 190.806 +	  sprintf (tmp,"Message copy to MX mailbox failed: %.80s",
 190.807 +		   s,strerror (errno));
 190.808 +	  MM_LOG (tmp,ERROR);
 190.809 +	  r = 0;		/* stop the snarf in its tracks */
 190.810 +	}
 190.811 +      }
 190.812 +				/* update scan time */
 190.813 +      if (!stat (stream->mailbox,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
 190.814 +      mail_expunge (sysibx);	/* now expunge all those messages */
 190.815 +    }
 190.816 +    if (sysibx) mail_close (sysibx);
 190.817 +    MM_NOCRITICAL (stream);	/* release critical */
 190.818 +  }
 190.819 +  mx_unlockindex (stream);	/* done with index */
 190.820 +  stream->silent = silent;	/* can pass up events now */
 190.821 +  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
 190.822 +  mail_recent (stream,recent);
 190.823 +  return T;			/* return that we are alive */
 190.824 +}
 190.825 +
 190.826 +/* MX mail check mailbox
 190.827 + * Accepts: MAIL stream
 190.828 + */
 190.829 +
 190.830 +void mx_check (MAILSTREAM *stream)
 190.831 +{
 190.832 +  if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 190.833 +}
 190.834 +
 190.835 +
 190.836 +/* MX mail expunge mailbox
 190.837 + * Accepts: MAIL stream
 190.838 + *	    sequence to expunge if non-NIL
 190.839 + *	    expunge options
 190.840 + * Returns: T, always
 190.841 + */
 190.842 +
 190.843 +long mx_expunge (MAILSTREAM *stream,char *sequence,long options)
 190.844 +{
 190.845 +  long ret;
 190.846 +  MESSAGECACHE *elt;
 190.847 +  unsigned long i = 1;
 190.848 +  unsigned long n = 0;
 190.849 +  unsigned long recent = stream->recent;
 190.850 +  if (ret = (sequence ? ((options & EX_UID) ?
 190.851 +			 mail_uid_sequence (stream,sequence) :
 190.852 +			 mail_sequence (stream,sequence)) : LONGT) &&
 190.853 +      mx_lockindex (stream)) {	/* lock the index */
 190.854 +    MM_CRITICAL (stream);	/* go critical */
 190.855 +    while (i <= stream->nmsgs) {/* for each message */
 190.856 +      elt = mail_elt (stream,i);/* if deleted, need to trash it */
 190.857 +      if (elt->deleted && (sequence ? elt->sequence : T)) {
 190.858 +	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
 190.859 +	if (unlink (LOCAL->buf)) {/* try to delete the message */
 190.860 +	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
 190.861 +		   strerror (errno));
 190.862 +	  MM_LOG (LOCAL->buf,(long) NIL);
 190.863 +	  break;
 190.864 +	}
 190.865 +				/* note uncached */
 190.866 +	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
 190.867 +				elt->private.msg.header.text.size : 0) +
 190.868 +			       (elt->private.msg.text.text.data ?
 190.869 +				elt->private.msg.text.text.size : 0));
 190.870 +	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
 190.871 +	if(elt->recent)--recent;/* if recent, note one less recent message */
 190.872 +	mail_expunged(stream,i);/* notify upper levels */
 190.873 +	n++;			/* count up one more expunged message */
 190.874 +      }
 190.875 +      else i++;			/* otherwise try next message */
 190.876 +    }
 190.877 +    if (n) {			/* output the news if any expunged */
 190.878 +      sprintf (LOCAL->buf,"Expunged %lu messages",n);
 190.879 +      MM_LOG (LOCAL->buf,(long) NIL);
 190.880 +    }
 190.881 +    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 190.882 +    MM_NOCRITICAL (stream);	/* release critical */
 190.883 +    mx_unlockindex (stream);	/* finished with index */
 190.884 +				/* notify upper level of new mailbox size */
 190.885 +    mail_exists (stream,stream->nmsgs);
 190.886 +    mail_recent (stream,recent);
 190.887 +  }
 190.888 +  return ret;
 190.889 +}
 190.890 +
 190.891 +/* MX mail copy message(s)
 190.892 + * Accepts: MAIL stream
 190.893 + *	    sequence
 190.894 + *	    destination mailbox
 190.895 + *	    copy options
 190.896 + * Returns: T if copy successful, else NIL
 190.897 + */
 190.898 +
 190.899 +long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 190.900 +{
 190.901 +  FDDATA d;
 190.902 +  STRING st;
 190.903 +  MESSAGECACHE *elt;
 190.904 +  MAILSTREAM *astream;
 190.905 +  struct stat sbuf;
 190.906 +  int fd;
 190.907 +  unsigned long i,j,uid,uidv;
 190.908 +  char *t,tmp[MAILTMPLEN];
 190.909 +  long ret;
 190.910 +  mailproxycopy_t pc =
 190.911 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 190.912 +				/* make sure valid mailbox */
 190.913 +  if (!mx_valid (mailbox)) switch (errno) {
 190.914 +  case NIL:			/* no error in stat() */
 190.915 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 190.916 +    sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox);
 190.917 +    MM_LOG (LOCAL->buf,ERROR);
 190.918 +    return NIL;
 190.919 +  default:			/* some stat() error */
 190.920 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 190.921 +    return NIL;
 190.922 +  }
 190.923 +				/* copy the messages */
 190.924 +  if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 190.925 +	       mail_sequence (stream,sequence))));
 190.926 +				/* acquire stream to append to */
 190.927 +  else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
 190.928 +    MM_LOG ("Can't open copy mailbox",ERROR);
 190.929 +    ret = NIL;
 190.930 +  }
 190.931 +  else {
 190.932 +    MM_CRITICAL (stream);	/* go critical */
 190.933 +    if (!(ret = mx_lockindex (astream)))
 190.934 +      MM_LOG ("Message copy failed: unable to lock index",ERROR);
 190.935 +    else {
 190.936 +
 190.937 +      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 190.938 +      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 190.939 +      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 190.940 +      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) 
 190.941 +      if ((elt = mail_elt (stream,i))->sequence) {
 190.942 +	if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL))
 190.943 +		   >= 0)) {
 190.944 +	  fstat (fd,&sbuf);	/* get size of message */
 190.945 +	  d.fd = fd;		/* set up file descriptor */
 190.946 +	  d.pos = 0;		/* start of file */
 190.947 +	  d.chunk = LOCAL->buf;
 190.948 +	  d.chunksize = CHUNKSIZE;
 190.949 +	  INIT (&st,fd_string,&d,sbuf.st_size);
 190.950 +				/* init flag string */
 190.951 +	  tmp[0] = tmp[1] = '\0';
 190.952 +	  if (j = elt->user_flags) do
 190.953 +	    if (t = stream->user_flags[find_rightmost_bit (&j)])
 190.954 +	      strcat (strcat (tmp," "),t);
 190.955 +	  while (j);
 190.956 +	  if (elt->seen) strcat (tmp," \\Seen");
 190.957 +	  if (elt->deleted) strcat (tmp," \\Deleted");
 190.958 +	  if (elt->flagged) strcat (tmp," \\Flagged");
 190.959 +	  if (elt->answered) strcat (tmp," \\Answered");
 190.960 +	  if (elt->draft) strcat (tmp," \\Draft");
 190.961 +	  tmp[0] = '(';		/* open list */
 190.962 +	  strcat (tmp,")");	/* close list */
 190.963 +	  if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) {
 190.964 +				/* add to source set if needed */
 190.965 +	    if (source) mail_append_set (source,mail_uid (stream,i));
 190.966 +				/* delete if doing a move */
 190.967 +	    if (options & CP_MOVE) elt->deleted = T;
 190.968 +	  }
 190.969 +	}
 190.970 +      }
 190.971 +				/* return sets if doing COPYUID */
 190.972 +      if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
 190.973 +      else {			/* flush any sets we may have built */
 190.974 +	mail_free_searchset (&source);
 190.975 +	mail_free_searchset (&dest);
 190.976 +      }
 190.977 +      mx_unlockindex (astream);	/* unlock index */
 190.978 +    }
 190.979 +    MM_NOCRITICAL (stream);
 190.980 +    mail_close (astream);	/* finished with append stream */
 190.981 +  }
 190.982 +  return ret;			/* return success */
 190.983 +}
 190.984 +
 190.985 +/* MX mail append message from stringstruct
 190.986 + * Accepts: MAIL stream
 190.987 + *	    destination mailbox
 190.988 + *	    append callback
 190.989 + *	    data for callback
 190.990 + * Returns: T if append successful, else NIL
 190.991 + */
 190.992 +
 190.993 +long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 190.994 +{
 190.995 +  MESSAGECACHE elt;
 190.996 +  MAILSTREAM *astream;
 190.997 +  char *flags,*date,tmp[MAILTMPLEN];
 190.998 +  STRING *message;
 190.999 +  long ret = LONGT;
190.1000 +				/* default stream to prototype */
190.1001 +  if (!stream) stream = user_flags (&mxproto);
190.1002 +				/* N.B.: can't use LOCAL->buf for tmp */
190.1003 +				/* make sure valid mailbox */
190.1004 +  if (!mx_isvalid (mailbox,tmp)) switch (errno) {
190.1005 +  case ENOENT:			/* no such file? */
190.1006 +    if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX");
190.1007 +    else {
190.1008 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
190.1009 +      return NIL;
190.1010 +    }
190.1011 +				/* falls through */
190.1012 +  case 0:			/* merely empty file? */
190.1013 +    break;
190.1014 +  case EINVAL:
190.1015 +    sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox);
190.1016 +    MM_LOG (tmp,ERROR);
190.1017 +    return NIL;
190.1018 +  default:
190.1019 +    sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox);
190.1020 +    MM_LOG (tmp,ERROR);
190.1021 +    return NIL;
190.1022 +  }
190.1023 +
190.1024 +				/* get first message */
190.1025 +  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
190.1026 +  if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
190.1027 +    MM_LOG ("Can't open append mailbox",ERROR);
190.1028 +    return NIL;
190.1029 +  }
190.1030 +  MM_CRITICAL (astream);	/* go critical */
190.1031 +				/* lock the index */
190.1032 +  if (!(ret = mx_lockindex (astream)))
190.1033 +    MM_LOG ("Message append failed: unable to lock index",ERROR);
190.1034 +  else {
190.1035 +    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
190.1036 +    SEARCHSET *dst = au ? mail_newsearchset () : NIL;
190.1037 +    do {
190.1038 +				/* guard against zero-length */
190.1039 +      if (!(ret = SIZE (message)))
190.1040 +	MM_LOG ("Append of zero-length message",ERROR);
190.1041 +      else if (date && !(ret = mail_parse_date (&elt,date))) {
190.1042 +	sprintf (tmp,"Bad date in append: %.80s",date);
190.1043 +	MM_LOG (tmp,ERROR);
190.1044 +      }
190.1045 +      else ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&&
190.1046 +	     MM_APPEND (af) (stream,data,&flags,&date,&message);
190.1047 +    } while (ret && message);
190.1048 +				/* return sets if doing APPENDUID */
190.1049 +    if (au && ret) (*au) (mailbox,astream->uid_validity,dst);
190.1050 +    else mail_free_searchset (&dst);
190.1051 +    mx_unlockindex (astream);	/* unlock index */
190.1052 +  }
190.1053 +  MM_NOCRITICAL (astream);	/* release critical */
190.1054 +  mail_close (astream);
190.1055 +  return ret;
190.1056 +}
190.1057 +
190.1058 +/* MX mail append single message
190.1059 + * Accepts: MAIL stream
190.1060 + *	    flags for new message if non-NIL
190.1061 + *	    elt with source date if non-NIL
190.1062 + *	    stringstruct of message text
190.1063 + *	    searchset to place UID
190.1064 + * Returns: T if success, NIL if failure
190.1065 + */
190.1066 +
190.1067 +long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
190.1068 +		    STRING *st,SEARCHSET *set)
190.1069 +{
190.1070 +  char tmp[MAILTMPLEN];
190.1071 +  int fd;
190.1072 +  unsigned long uf;
190.1073 +  long f = mail_parse_flags (stream,flags,&uf);
190.1074 +				/* make message file name */
190.1075 +  sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last);
190.1076 +  if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
190.1077 +		  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
190.1078 +    sprintf (tmp,"Can't create append message: %s",strerror (errno));
190.1079 +    MM_LOG (tmp,ERROR);
190.1080 +    return NIL;
190.1081 +  }
190.1082 +  while (SIZE (st)) {		/* copy the file */
190.1083 +    if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) {
190.1084 +      unlink (tmp);		/* delete file */
190.1085 +      close (fd);		/* close the file */
190.1086 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
190.1087 +      MM_LOG (tmp,ERROR);
190.1088 +      return NIL;
190.1089 +    }
190.1090 +    SETPOS (st,GETPOS (st) + st->cursize);
190.1091 +  }
190.1092 +  close (fd);			/* close the file */
190.1093 +  if (elt) mx_setdate (tmp,elt);/* set file date */
190.1094 +				/* swell the cache */
190.1095 +  mail_exists (stream,++stream->nmsgs);
190.1096 +				/* copy flags */
190.1097 +  mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid =
190.1098 +		   stream->uid_last);
190.1099 +  if (f&fSEEN) elt->seen = T;
190.1100 +  if (f&fDELETED) elt->deleted = T;
190.1101 +  if (f&fFLAGGED) elt->flagged = T;
190.1102 +  if (f&fANSWERED) elt->answered = T;
190.1103 +  if (f&fDRAFT) elt->draft = T;
190.1104 +  elt->user_flags |= uf;
190.1105 +  return LONGT;
190.1106 +}
190.1107 +
190.1108 +/* Internal routines */
190.1109 +
190.1110 +
190.1111 +/* MX file name selection test
190.1112 + * Accepts: candidate directory entry
190.1113 + * Returns: T to use file name, NIL to skip it
190.1114 + */
190.1115 +
190.1116 +int mx_select (struct direct *name)
190.1117 +{
190.1118 +  char c;
190.1119 +  char *s = name->d_name;
190.1120 +  while (c = *s++) if (!isdigit (c)) return NIL;
190.1121 +  return T;
190.1122 +}
190.1123 +
190.1124 +
190.1125 +/* MX file name comparision
190.1126 + * Accepts: first candidate directory entry
190.1127 + *	    second candidate directory entry
190.1128 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
190.1129 + */
190.1130 +
190.1131 +int mx_numsort (const void *d1,const void *d2)
190.1132 +{
190.1133 +  return atoi ((*(struct direct **) d1)->d_name) -
190.1134 +    atoi ((*(struct direct **) d2)->d_name);
190.1135 +}
190.1136 +
190.1137 +
190.1138 +/* MX mail build file name
190.1139 + * Accepts: destination string
190.1140 + *          source
190.1141 + * Returns: destination
190.1142 + */
190.1143 +
190.1144 +char *mx_file (char *dst,char *name)
190.1145 +{
190.1146 +  char *s;
190.1147 +				/* empty string if mailboxfile fails */
190.1148 +  if (!mailboxfile (dst,name)) *dst = '\0';
190.1149 +				/* driver-selected INBOX  */
190.1150 +  else if (!*dst) mailboxfile (dst,"~/INBOX");
190.1151 +				/* tie off unnecessary trailing / */
190.1152 +  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
190.1153 +  return dst;
190.1154 +}
190.1155 +
190.1156 +/* MX read and lock index
190.1157 + * Accepts: MAIL stream
190.1158 + * Returns: T if success, NIL if failure
190.1159 + */
190.1160 +
190.1161 +long mx_lockindex (MAILSTREAM *stream)
190.1162 +{
190.1163 +  unsigned long uf,sf,uid;
190.1164 +  int k = 0;
190.1165 +  unsigned long msgno = 1;
190.1166 +  struct stat sbuf;
190.1167 +  char *s,*t,*idx,tmp[2*MAILTMPLEN];
190.1168 +  MESSAGECACHE *elt;
190.1169 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
190.1170 +  if ((LOCAL->fd < 0) &&	/* get index file, no-op if already have it */
190.1171 +      (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME),
190.1172 +			 O_RDWR|O_CREAT,
190.1173 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
190.1174 +      >= 0) {
190.1175 +    (*bn) (BLOCK_FILELOCK,NIL);
190.1176 +    flock (LOCAL->fd,LOCK_EX);	/* get exclusive lock */
190.1177 +    (*bn) (BLOCK_NONE,NIL);
190.1178 +    fstat (LOCAL->fd,&sbuf);	/* get size of index */
190.1179 +				/* slurp index */
190.1180 +    read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
190.1181 +    idx[sbuf.st_size] = '\0';	/* tie off index */
190.1182 +				/* parse index */
190.1183 +    if (sbuf.st_size) while (s && *s) switch (*s) {
190.1184 +    case 'V':			/* UID validity record */
190.1185 +      stream->uid_validity = strtoul (s+1,&s,16);
190.1186 +      break;
190.1187 +    case 'L':			/* UID last record */
190.1188 +      stream->uid_last = strtoul (s+1,&s,16);
190.1189 +      break;
190.1190 +    case 'K':			/* keyword */
190.1191 +				/* find end of keyword */
190.1192 +      if (s = strchr (t = ++s,'\n')) {
190.1193 +	*s++ = '\0';		/* tie off keyword */
190.1194 +				/* copy keyword */
190.1195 +	if ((k < NUSERFLAGS) && !stream->user_flags[k] &&
190.1196 +	    (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t);
190.1197 +	k++;			/* one more keyword */
190.1198 +      }
190.1199 +      break;
190.1200 +
190.1201 +    case 'M':			/* message status record */
190.1202 +      uid = strtoul (s+1,&s,16);/* get UID for this message */
190.1203 +      if (*s == ';') {		/* get user flags */
190.1204 +	uf = strtoul (s+1,&s,16);
190.1205 +	if (*s == '.') {	/* get system flags */
190.1206 +	  sf = strtoul (s+1,&s,16);
190.1207 +	  while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid))
190.1208 +	    msgno++;		/* find message number for this UID */
190.1209 +	  if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) {
190.1210 +	    (elt = mail_elt (stream,msgno))->valid = T;
190.1211 +	    elt->user_flags=uf; /* set user and system flags in elt */
190.1212 +	    if (sf & fSEEN) elt->seen = T;
190.1213 +	    if (sf & fDELETED) elt->deleted = T;
190.1214 +	    if (sf & fFLAGGED) elt->flagged = T;
190.1215 +	    if (sf & fANSWERED) elt->answered = T;
190.1216 +	    if (sf & fDRAFT) elt->draft = T;
190.1217 +	  }
190.1218 +	  break;
190.1219 +	}
190.1220 +      }
190.1221 +    default:			/* bad news */
190.1222 +      sprintf (tmp,"Error in index: %.80s",s);
190.1223 +      MM_LOG (tmp,ERROR);
190.1224 +      *s = NIL;			/* ignore remainder of index */
190.1225 +    }
190.1226 +    else {			/* new index */
190.1227 +      stream->uid_validity = time (0);
190.1228 +      user_flags (stream);	/* init stream with default user flags */
190.1229 +    }
190.1230 +    fs_give ((void **) &idx);	/* flush index */
190.1231 +  }
190.1232 +  return (LOCAL->fd >= 0) ? T : NIL;
190.1233 +}
190.1234 +
190.1235 +/* MX write and unlock index
190.1236 + * Accepts: MAIL stream
190.1237 + */
190.1238 +
190.1239 +#define MXIXBUFLEN 2048
190.1240 +
190.1241 +void mx_unlockindex (MAILSTREAM *stream)
190.1242 +{
190.1243 +  unsigned long i,j;
190.1244 +  off_t size = 0;
190.1245 +  char *s,tmp[MXIXBUFLEN + 64];
190.1246 +  MESSAGECACHE *elt;
190.1247 +  if (LOCAL->fd >= 0) {
190.1248 +    lseek (LOCAL->fd,0,L_SET);	/* rewind file */
190.1249 +				/* write header */
190.1250 +    sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last);
190.1251 +    for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
190.1252 +      sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]);
190.1253 +				/* write messages */
190.1254 +    for (i = 1; i <= stream->nmsgs; i++) {
190.1255 +				/* filled buffer? */
190.1256 +      if (((s += strlen (s)) - tmp) > MXIXBUFLEN) {
190.1257 +	write (LOCAL->fd,tmp,j = s - tmp);
190.1258 +	size += j;
190.1259 +	*(s = tmp) = '\0';	/* dump out and restart buffer */
190.1260 +      }
190.1261 +      elt = mail_elt (stream,i);
190.1262 +      sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned)
190.1263 +	      ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
190.1264 +	       (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
190.1265 +	       (fDRAFT * elt->draft)));
190.1266 +    }
190.1267 +				/* write tail end of buffer */
190.1268 +    if ((s += strlen (s)) != tmp) {
190.1269 +      write (LOCAL->fd,tmp,j = s - tmp);
190.1270 +      size += j;
190.1271 +    }
190.1272 +    ftruncate (LOCAL->fd,size);
190.1273 +    flock (LOCAL->fd,LOCK_UN);	/* unlock the index */
190.1274 +    close (LOCAL->fd);		/* finished with file */
190.1275 +    LOCAL->fd = -1;		/* no index now */
190.1276 +  }
190.1277 +}
190.1278 +
190.1279 +/* Set date for message
190.1280 + * Accepts: file name
190.1281 + *	    elt containing date
190.1282 + */
190.1283 +
190.1284 +void mx_setdate (char *file,MESSAGECACHE *elt)
190.1285 +{
190.1286 +  time_t tp[2];
190.1287 +  tp[0] = time (0);		/* atime is now */
190.1288 +  tp[1] = mail_longdate (elt);	/* modification time */
190.1289 +  utime (file,tp);		/* set the times */
190.1290 +}
   191.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   191.2 +++ b/src/osdep/amiga/news.c	Mon Sep 14 15:17:45 2009 +0900
   191.3 @@ -0,0 +1,738 @@
   191.4 +/* ========================================================================
   191.5 + * Copyright 1988-2007 University of Washington
   191.6 + *
   191.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   191.8 + * you may not use this file except in compliance with the License.
   191.9 + * You may obtain a copy of the License at
  191.10 + *
  191.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  191.12 + *
  191.13 + * 
  191.14 + * ========================================================================
  191.15 + */
  191.16 +
  191.17 +/*
  191.18 + * Program:	News routines
  191.19 + *
  191.20 + * Author:	Mark Crispin
  191.21 + *		Networks and Distributed Computing
  191.22 + *		Computing & Communications
  191.23 + *		University of Washington
  191.24 + *		Administration Building, AG-44
  191.25 + *		Seattle, WA  98195
  191.26 + *		Internet: MRC@CAC.Washington.EDU
  191.27 + *
  191.28 + * Date:	4 September 1991
  191.29 + * Last Edited:	30 January 2007
  191.30 + */
  191.31 +
  191.32 +
  191.33 +#include <stdio.h>
  191.34 +#include <ctype.h>
  191.35 +#include <errno.h>
  191.36 +extern int errno;		/* just in case */
  191.37 +#include "mail.h"
  191.38 +#include "osdep.h"
  191.39 +#include <sys/stat.h>
  191.40 +#include <sys/time.h>
  191.41 +#include "misc.h"
  191.42 +#include "newsrc.h"
  191.43 +#include "fdstring.h"
  191.44 +
  191.45 +
  191.46 +/* news_load_message() flags */
  191.47 +
  191.48 +#define NLM_HEADER 0x1		/* load message text */
  191.49 +#define NLM_TEXT 0x2		/* load message text */
  191.50 +
  191.51 +/* NEWS I/O stream local data */
  191.52 +	
  191.53 +typedef struct news_local {
  191.54 +  unsigned int dirty : 1;	/* disk copy of .newsrc needs updating */
  191.55 +  char *dir;			/* spool directory name */
  191.56 +  char *name;			/* local mailbox name */
  191.57 +  unsigned char buf[CHUNKSIZE];	/* scratch buffer */
  191.58 +  unsigned long cachedtexts;	/* total size of all cached texts */
  191.59 +} NEWSLOCAL;
  191.60 +
  191.61 +
  191.62 +/* Convenient access to local data */
  191.63 +
  191.64 +#define LOCAL ((NEWSLOCAL *) stream->local)
  191.65 +
  191.66 +
  191.67 +/* Function prototypes */
  191.68 +
  191.69 +DRIVER *news_valid (char *name);
  191.70 +DRIVER *news_isvalid (char *name,char *mbx);
  191.71 +void *news_parameters (long function,void *value);
  191.72 +void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  191.73 +void news_list (MAILSTREAM *stream,char *ref,char *pat);
  191.74 +void news_lsub (MAILSTREAM *stream,char *ref,char *pat);
  191.75 +long news_canonicalize (char *ref,char *pat,char *pattern);
  191.76 +long news_subscribe (MAILSTREAM *stream,char *mailbox);
  191.77 +long news_unsubscribe (MAILSTREAM *stream,char *mailbox);
  191.78 +long news_create (MAILSTREAM *stream,char *mailbox);
  191.79 +long news_delete (MAILSTREAM *stream,char *mailbox);
  191.80 +long news_rename (MAILSTREAM *stream,char *old,char *newname);
  191.81 +MAILSTREAM *news_open (MAILSTREAM *stream);
  191.82 +int news_select (struct direct *name);
  191.83 +int news_numsort (const void *d1,const void *d2);
  191.84 +void news_close (MAILSTREAM *stream,long options);
  191.85 +void news_fast (MAILSTREAM *stream,char *sequence,long flags);
  191.86 +void news_flags (MAILSTREAM *stream,char *sequence,long flags);
  191.87 +void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
  191.88 +char *news_header (MAILSTREAM *stream,unsigned long msgno,
  191.89 +		   unsigned long *length,long flags);
  191.90 +long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  191.91 +void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  191.92 +long news_ping (MAILSTREAM *stream);
  191.93 +void news_check (MAILSTREAM *stream);
  191.94 +long news_expunge (MAILSTREAM *stream,char *sequence,long options);
  191.95 +long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  191.96 +long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  191.97 +
  191.98 +/* News routines */
  191.99 +
 191.100 +
 191.101 +/* Driver dispatch used by MAIL */
 191.102 +
 191.103 +DRIVER newsdriver = {
 191.104 +  "news",			/* driver name */
 191.105 +				/* driver flags */
 191.106 +  DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_NONEWMAIL|DR_DIRFMT,
 191.107 +  (DRIVER *) NIL,		/* next driver */
 191.108 +  news_valid,			/* mailbox is valid for us */
 191.109 +  news_parameters,		/* manipulate parameters */
 191.110 +  news_scan,			/* scan mailboxes */
 191.111 +  news_list,			/* find mailboxes */
 191.112 +  news_lsub,			/* find subscribed mailboxes */
 191.113 +  news_subscribe,		/* subscribe to mailbox */
 191.114 +  news_unsubscribe,		/* unsubscribe from mailbox */
 191.115 +  news_create,			/* create mailbox */
 191.116 +  news_delete,			/* delete mailbox */
 191.117 +  news_rename,			/* rename mailbox */
 191.118 +  mail_status_default,		/* status of mailbox */
 191.119 +  news_open,			/* open mailbox */
 191.120 +  news_close,			/* close mailbox */
 191.121 +  news_fast,			/* fetch message "fast" attributes */
 191.122 +  news_flags,			/* fetch message flags */
 191.123 +  NIL,				/* fetch overview */
 191.124 +  NIL,				/* fetch message envelopes */
 191.125 +  news_header,			/* fetch message header */
 191.126 +  news_text,			/* fetch message body */
 191.127 +  NIL,				/* fetch partial message text */
 191.128 +  NIL,				/* unique identifier */
 191.129 +  NIL,				/* message number */
 191.130 +  NIL,				/* modify flags */
 191.131 +  news_flagmsg,			/* per-message modify flags */
 191.132 +  NIL,				/* search for message based on criteria */
 191.133 +  NIL,				/* sort messages */
 191.134 +  NIL,				/* thread messages */
 191.135 +  news_ping,			/* ping mailbox to see if still alive */
 191.136 +  news_check,			/* check for new messages */
 191.137 +  news_expunge,			/* expunge deleted messages */
 191.138 +  news_copy,			/* copy messages to another mailbox */
 191.139 +  news_append,			/* append string message to mailbox */
 191.140 +  NIL				/* garbage collect stream */
 191.141 +};
 191.142 +
 191.143 +				/* prototype stream */
 191.144 +MAILSTREAM newsproto = {&newsdriver};
 191.145 +
 191.146 +/* News validate mailbox
 191.147 + * Accepts: mailbox name
 191.148 + * Returns: our driver if name is valid, NIL otherwise
 191.149 + */
 191.150 +
 191.151 +DRIVER *news_valid (char *name)
 191.152 +{
 191.153 +  int fd;
 191.154 +  char *s,*t,*u;
 191.155 +  struct stat sbuf;
 191.156 +  if ((name[0] == '#') && (name[1] == 'n') && (name[2] == 'e') &&
 191.157 +      (name[3] == 'w') && (name[4] == 's') && (name[5] == '.') &&
 191.158 +      !strchr (name,'/') &&
 191.159 +      !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
 191.160 +      ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),O_RDONLY,
 191.161 +		   NIL)) >= 0)) {
 191.162 +    fstat (fd,&sbuf);		/* get size of active file */
 191.163 +				/* slurp in active file */
 191.164 +    read (fd,t = s = (char *) fs_get (sbuf.st_size+1),sbuf.st_size);
 191.165 +    s[sbuf.st_size] = '\0';	/* tie off file */
 191.166 +    close (fd);			/* flush file */
 191.167 +    while (*t && (u = strchr (t,' '))) {
 191.168 +      *u++ = '\0';		/* tie off at end of name */
 191.169 +      if (!strcmp (name+6,t)) {
 191.170 +	fs_give ((void **) &s);	/* flush data */
 191.171 +	return &newsdriver;
 191.172 +      }
 191.173 +      t = 1 + strchr (u,'\n');	/* next line */
 191.174 +    }
 191.175 +    fs_give ((void **) &s);	/* flush data */
 191.176 +  }
 191.177 +  return NIL;			/* return status */
 191.178 +}
 191.179 +
 191.180 +/* News manipulate driver parameters
 191.181 + * Accepts: function code
 191.182 + *	    function-dependent value
 191.183 + * Returns: function-dependent return value
 191.184 + */
 191.185 +
 191.186 +void *news_parameters (long function,void *value)
 191.187 +{
 191.188 +  return (function == GET_NEWSRC) ? env_parameters (function,value) : NIL;
 191.189 +}
 191.190 +
 191.191 +
 191.192 +/* News scan mailboxes
 191.193 + * Accepts: mail stream
 191.194 + *	    reference
 191.195 + *	    pattern to search
 191.196 + *	    string to scan
 191.197 + */
 191.198 +
 191.199 +void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 191.200 +{
 191.201 +  char tmp[MAILTMPLEN];
 191.202 +  if (news_canonicalize (ref,pat,tmp))
 191.203 +    mm_log ("Scan not valid for news mailboxes",ERROR);
 191.204 +}
 191.205 +
 191.206 +/* News find list of newsgroups
 191.207 + * Accepts: mail stream
 191.208 + *	    reference
 191.209 + *	    pattern to search
 191.210 + */
 191.211 +
 191.212 +void news_list (MAILSTREAM *stream,char *ref,char *pat)
 191.213 +{
 191.214 +  int fd;
 191.215 +  int i;
 191.216 +  char *s,*t,*u,*r,pattern[MAILTMPLEN],name[MAILTMPLEN];
 191.217 +  struct stat sbuf;
 191.218 +  if (!pat || !*pat) {		/* empty pattern? */
 191.219 +    if (news_canonicalize (ref,"*",pattern)) {
 191.220 +				/* tie off name at root */
 191.221 +      if (s = strchr (pattern,'.')) *++s = '\0';
 191.222 +      else pattern[0] = '\0';
 191.223 +      mm_list (stream,'.',pattern,LATT_NOSELECT);
 191.224 +    }
 191.225 +  }
 191.226 +  else if (news_canonicalize (ref,pat,pattern) &&
 191.227 +	   !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
 191.228 +	   ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),
 191.229 +			O_RDONLY,NIL)) >= 0)) {
 191.230 +    fstat (fd,&sbuf);		/* get file size and read data */
 191.231 +    read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
 191.232 +    close (fd);			/* close file */
 191.233 +    s[sbuf.st_size] = '\0';	/* tie off string */
 191.234 +    strcpy (name,"#news.");	/* write initial prefix */
 191.235 +    i = strlen (pattern);	/* length of pattern */
 191.236 +    if (pattern[--i] != '%') i = 0;
 191.237 +    if (t = strtok_r (s,"\n",&r)) do if (u = strchr (t,' ')) {
 191.238 +      *u = '\0';		/* tie off at end of name */
 191.239 +      strcpy (name + 6,t);	/* make full form of name */
 191.240 +      if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL);
 191.241 +      else if (i && (u = strchr (name + i,'.'))) {
 191.242 +	*u = '\0';		/* tie off at delimiter, see if matches */
 191.243 +	if (pmatch_full (name,pattern,'.'))
 191.244 +	  mm_list (stream,'.',name,LATT_NOSELECT);
 191.245 +      }
 191.246 +    } while (t = strtok_r (NIL,"\n",&r));
 191.247 +    fs_give ((void **) &s);
 191.248 +  }
 191.249 +}
 191.250 +
 191.251 +/* News find list of subscribed newsgroups
 191.252 + * Accepts: mail stream
 191.253 + *	    reference
 191.254 + *	    pattern to search
 191.255 + */
 191.256 +
 191.257 +void news_lsub (MAILSTREAM *stream,char *ref,char *pat)
 191.258 +{
 191.259 +  char pattern[MAILTMPLEN];
 191.260 +				/* return data from newsrc */
 191.261 +  if (news_canonicalize (ref,pat,pattern)) newsrc_lsub (stream,pattern);
 191.262 +}
 191.263 +
 191.264 +
 191.265 +/* News canonicalize newsgroup name
 191.266 + * Accepts: reference
 191.267 + *	    pattern
 191.268 + *	    returned single pattern
 191.269 + * Returns: T on success, NIL on failure
 191.270 + */
 191.271 +
 191.272 +long news_canonicalize (char *ref,char *pat,char *pattern)
 191.273 +{
 191.274 +  unsigned long i;
 191.275 +  char *s;
 191.276 +  if (ref && *ref) {		/* have a reference */
 191.277 +    strcpy (pattern,ref);	/* copy reference to pattern */
 191.278 +				/* # overrides mailbox field in reference */
 191.279 +    if (*pat == '#') strcpy (pattern,pat);
 191.280 +				/* pattern starts, reference ends, with . */
 191.281 +    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
 191.282 +      strcat (pattern,pat + 1);	/* append, omitting one of the period */
 191.283 +    else strcat (pattern,pat);	/* anything else is just appended */
 191.284 +  }
 191.285 +  else strcpy (pattern,pat);	/* just have basic name */
 191.286 +  if ((pattern[0] == '#') && (pattern[1] == 'n') && (pattern[2] == 'e') &&
 191.287 +      (pattern[3] == 'w') && (pattern[4] == 's') && (pattern[5] == '.') &&
 191.288 +      !strchr (pattern,'/')) {	/* count wildcards */
 191.289 +    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 191.290 +				/* success if not too many */
 191.291 +    if (i <= MAXWILDCARDS) return LONGT;
 191.292 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 191.293 +  }
 191.294 +  return NIL;
 191.295 +}
 191.296 +
 191.297 +/* News subscribe to mailbox
 191.298 + * Accepts: mail stream
 191.299 + *	    mailbox to add to subscription list
 191.300 + * Returns: T on success, NIL on failure
 191.301 + */
 191.302 +
 191.303 +long news_subscribe (MAILSTREAM *stream,char *mailbox)
 191.304 +{
 191.305 +  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,':') : NIL;
 191.306 +}
 191.307 +
 191.308 +
 191.309 +/* NEWS unsubscribe to mailbox
 191.310 + * Accepts: mail stream
 191.311 + *	    mailbox to delete from subscription list
 191.312 + * Returns: T on success, NIL on failure
 191.313 + */
 191.314 +
 191.315 +long news_unsubscribe (MAILSTREAM *stream,char *mailbox)
 191.316 +{
 191.317 +  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,'!') : NIL;
 191.318 +}
 191.319 +
 191.320 +/* News create mailbox
 191.321 + * Accepts: mail stream
 191.322 + *	    mailbox name to create
 191.323 + * Returns: T on success, NIL on failure
 191.324 + */
 191.325 +
 191.326 +long news_create (MAILSTREAM *stream,char *mailbox)
 191.327 +{
 191.328 +  return NIL;			/* never valid for News */
 191.329 +}
 191.330 +
 191.331 +
 191.332 +/* News delete mailbox
 191.333 + *	    mailbox name to delete
 191.334 + * Returns: T on success, NIL on failure
 191.335 + */
 191.336 +
 191.337 +long news_delete (MAILSTREAM *stream,char *mailbox)
 191.338 +{
 191.339 +  return NIL;			/* never valid for News */
 191.340 +}
 191.341 +
 191.342 +
 191.343 +/* News rename mailbox
 191.344 + * Accepts: mail stream
 191.345 + *	    old mailbox name
 191.346 + *	    new mailbox name
 191.347 + * Returns: T on success, NIL on failure
 191.348 + */
 191.349 +
 191.350 +long news_rename (MAILSTREAM *stream,char *old,char *newname)
 191.351 +{
 191.352 +  return NIL;			/* never valid for News */
 191.353 +}
 191.354 +
 191.355 +/* News open
 191.356 + * Accepts: stream to open
 191.357 + * Returns: stream on success, NIL on failure
 191.358 + */
 191.359 +
 191.360 +MAILSTREAM *news_open (MAILSTREAM *stream)
 191.361 +{
 191.362 +  long i,nmsgs;
 191.363 +  char *s,tmp[MAILTMPLEN];
 191.364 +  struct direct **names = NIL;
 191.365 +  				/* return prototype for OP_PROTOTYPE call */
 191.366 +  if (!stream) return &newsproto;
 191.367 +  if (stream->local) fatal ("news recycle stream");
 191.368 +				/* build directory name */
 191.369 +  sprintf (s = tmp,"%s/%s",(char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),
 191.370 +	   stream->mailbox + 6);
 191.371 +  while (s = strchr (s,'.')) *s = '/';
 191.372 +				/* scan directory */
 191.373 +  if ((nmsgs = scandir (tmp,&names,news_select,news_numsort)) >= 0) {
 191.374 +    mail_exists (stream,nmsgs);	/* notify upper level that messages exist */
 191.375 +    stream->local = fs_get (sizeof (NEWSLOCAL));
 191.376 +    LOCAL->dirty = NIL;		/* no update to .newsrc needed yet */
 191.377 +    LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
 191.378 +    LOCAL->name = cpystr (stream->mailbox + 6);
 191.379 +    for (i = 0; i < nmsgs; ++i) {
 191.380 +      stream->uid_last = mail_elt (stream,i+1)->private.uid =
 191.381 +	atoi (names[i]->d_name);
 191.382 +      fs_give ((void **) &names[i]);
 191.383 +    }
 191.384 +    s = (void *) names;		/* stupid language */
 191.385 +    fs_give ((void **) &s);	/* free directory */
 191.386 +    LOCAL->cachedtexts = 0;	/* no cached texts */
 191.387 +    stream->sequence++;		/* bump sequence number */
 191.388 +    stream->rdonly = stream->perm_deleted = T;
 191.389 +				/* UIDs are always valid */
 191.390 +    stream->uid_validity = 0xbeefface;
 191.391 +				/* read .newsrc entries */
 191.392 +    mail_recent (stream,newsrc_read (LOCAL->name,stream));
 191.393 +				/* notify if empty newsgroup */
 191.394 +    if (!(stream->nmsgs || stream->silent)) {
 191.395 +      sprintf (tmp,"Newsgroup %s is empty",LOCAL->name);
 191.396 +      mm_log (tmp,WARN);
 191.397 +    }
 191.398 +  }
 191.399 +  else mm_log ("Unable to scan newsgroup spool directory",ERROR);
 191.400 +  return LOCAL ? stream : NIL;	/* if stream is alive, return to caller */
 191.401 +}
 191.402 +
 191.403 +/* News file name selection test
 191.404 + * Accepts: candidate directory entry
 191.405 + * Returns: T to use file name, NIL to skip it
 191.406 + */
 191.407 +
 191.408 +int news_select (struct direct *name)
 191.409 +{
 191.410 +  char c;
 191.411 +  char *s = name->d_name;
 191.412 +  while (c = *s++) if (!isdigit (c)) return NIL;
 191.413 +  return T;
 191.414 +}
 191.415 +
 191.416 +
 191.417 +/* News file name comparision
 191.418 + * Accepts: first candidate directory entry
 191.419 + *	    second candidate directory entry
 191.420 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
 191.421 + */
 191.422 +
 191.423 +int news_numsort (const void *d1,const void *d2)
 191.424 +{
 191.425 +  return atoi ((*(struct direct **) d1)->d_name) -
 191.426 +    atoi ((*(struct direct **) d2)->d_name);
 191.427 +}
 191.428 +
 191.429 +
 191.430 +/* News close
 191.431 + * Accepts: MAIL stream
 191.432 + *	    option flags
 191.433 + */
 191.434 +
 191.435 +void news_close (MAILSTREAM *stream,long options)
 191.436 +{
 191.437 +  if (LOCAL) {			/* only if a file is open */
 191.438 +    news_check (stream);	/* dump final checkpoint */
 191.439 +    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
 191.440 +    if (LOCAL->name) fs_give ((void **) &LOCAL->name);
 191.441 +				/* nuke the local data */
 191.442 +    fs_give ((void **) &stream->local);
 191.443 +    stream->dtb = NIL;		/* log out the DTB */
 191.444 +  }
 191.445 +}
 191.446 +
 191.447 +/* News fetch fast information
 191.448 + * Accepts: MAIL stream
 191.449 + *	    sequence
 191.450 + *	    option flags
 191.451 + */
 191.452 +
 191.453 +void news_fast (MAILSTREAM *stream,char *sequence,long flags)
 191.454 +{
 191.455 +  MESSAGECACHE *elt;
 191.456 +  unsigned long i;
 191.457 +				/* set up metadata for all messages */
 191.458 +  if (stream && LOCAL && ((flags & FT_UID) ?
 191.459 +			  mail_uid_sequence (stream,sequence) :
 191.460 +			  mail_sequence (stream,sequence)))
 191.461 +    for (i = 1; i <= stream->nmsgs; i++)
 191.462 +      if ((elt = mail_elt (stream,i))->sequence &&
 191.463 +	  !(elt->day && elt->rfc822_size)) news_load_message (stream,i,NIL);
 191.464 +}
 191.465 +
 191.466 +
 191.467 +/* News fetch flags
 191.468 + * Accepts: MAIL stream
 191.469 + *	    sequence
 191.470 + *	    option flags
 191.471 + */
 191.472 +
 191.473 +void news_flags (MAILSTREAM *stream,char *sequence,long flags)
 191.474 +{
 191.475 +  unsigned long i;
 191.476 +  if ((flags & FT_UID) ?	/* validate all elts */
 191.477 +      mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))
 191.478 +    for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;
 191.479 +}
 191.480 +
 191.481 +/* News load message into cache
 191.482 + * Accepts: MAIL stream
 191.483 + *	    message #
 191.484 + *	    option flags
 191.485 + */
 191.486 +
 191.487 +void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
 191.488 +{
 191.489 +  unsigned long i,j,nlseen;
 191.490 +  int fd;
 191.491 +  unsigned char c,*t;
 191.492 +  struct stat sbuf;
 191.493 +  MESSAGECACHE *elt;
 191.494 +  FDDATA d;
 191.495 +  STRING bs;
 191.496 +  elt = mail_elt (stream,msgno);/* get elt */
 191.497 +				/* build message file name */
 191.498 +  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
 191.499 +				/* anything we need not currently cached? */
 191.500 +  if ((!elt->day || !elt->rfc822_size ||
 191.501 +       ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
 191.502 +       ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) &&
 191.503 +      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
 191.504 +    fstat (fd,&sbuf);		/* get file metadata */
 191.505 +    d.fd = fd;			/* set up file descriptor */
 191.506 +    d.pos = 0;			/* start of file */
 191.507 +    d.chunk = LOCAL->buf;
 191.508 +    d.chunksize = CHUNKSIZE;
 191.509 +    INIT (&bs,fd_string,&d,sbuf.st_size);
 191.510 +    if (!elt->day) {		/* set internaldate to file date */
 191.511 +      struct tm *tm = gmtime (&sbuf.st_mtime);
 191.512 +      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
 191.513 +      elt->year = tm->tm_year + 1900 - BASEYEAR;
 191.514 +      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
 191.515 +      elt->seconds = tm->tm_sec;
 191.516 +      elt->zhours = 0; elt->zminutes = 0;
 191.517 +    }
 191.518 +
 191.519 +    if (!elt->rfc822_size) {	/* know message size yet? */
 191.520 +      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
 191.521 +      case '\015':		/* unlikely carriage return */
 191.522 +	if (!j || (CHR (&bs) != '\012')) {
 191.523 +	  i++;			/* ugh, raw CR */
 191.524 +	  nlseen = NIL;
 191.525 +	  break;
 191.526 +	}
 191.527 +	SNX (&bs);		/* eat the line feed, drop in */
 191.528 +      case '\012':		/* line feed? */
 191.529 +	i += 2;			/* count a CRLF */
 191.530 +				/* header size known yet? */
 191.531 +	if (!elt->private.msg.header.text.size && nlseen) {
 191.532 +				/* note position in file */
 191.533 +	  elt->private.special.text.size = GETPOS (&bs);
 191.534 +				/* and CRLF-adjusted size */
 191.535 +	  elt->private.msg.header.text.size = i;
 191.536 +	}
 191.537 +	nlseen = T;		/* note newline seen */
 191.538 +	break;
 191.539 +      default:			/* ordinary chararacter */
 191.540 +	i++;
 191.541 +	nlseen = NIL;
 191.542 +	break;
 191.543 +      }
 191.544 +      SETPOS (&bs,0);		/* restore old position */
 191.545 +      elt->rfc822_size = i;	/* note that we have size now */
 191.546 +				/* header is entire message if no delimiter */
 191.547 +      if (!elt->private.msg.header.text.size)
 191.548 +	elt->private.msg.header.text.size = elt->rfc822_size;
 191.549 +				/* text is remainder of message */
 191.550 +      elt->private.msg.text.text.size =
 191.551 +	elt->rfc822_size - elt->private.msg.header.text.size;
 191.552 +    }
 191.553 +
 191.554 +				/* need to load cache with message data? */
 191.555 +    if (((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
 191.556 +	((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) {
 191.557 +				/* purge cache if too big */
 191.558 +      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
 191.559 +				/* just can't keep that much */
 191.560 +	mail_gc (stream,GC_TEXTS);
 191.561 +	LOCAL->cachedtexts = 0;
 191.562 +      }
 191.563 +      if ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) {
 191.564 +	t = elt->private.msg.header.text.data =
 191.565 +	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
 191.566 +	LOCAL->cachedtexts += elt->private.msg.header.text.size;
 191.567 +				/* read in message header */
 191.568 +	for (i = 0; i <= elt->private.msg.header.text.size; i++)
 191.569 +	  switch (c = SNX (&bs)) {
 191.570 +	  case '\015':		/* unlikely carriage return */
 191.571 +	    *t++ = c;
 191.572 +	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
 191.573 +	    break;
 191.574 +	  case '\012':		/* line feed? */
 191.575 +	    *t++ = '\015';
 191.576 +	  default:
 191.577 +	    *t++ = c;
 191.578 +	    break;
 191.579 +	  }
 191.580 +	*t = '\0';		/* tie off string */
 191.581 +      }
 191.582 +      if ((flags & NLM_TEXT) && !elt->private.msg.text.text.data) {
 191.583 +	t = elt->private.msg.text.text.data =
 191.584 +	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
 191.585 +	SETPOS (&bs,elt->private.msg.header.text.size);
 191.586 +	LOCAL->cachedtexts += elt->private.msg.text.text.size;
 191.587 +				/* read in message text */
 191.588 +	for (i = 0; i <= elt->private.msg.text.text.size; i++)
 191.589 +	  switch (c = SNX (&bs)) {
 191.590 +	  case '\015':		/* unlikely carriage return */
 191.591 +	    *t++ = c;
 191.592 +	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
 191.593 +	    break;
 191.594 +	  case '\012':		/* line feed? */
 191.595 +	    *t++ = '\015';
 191.596 +	  default:
 191.597 +	    *t++ = c;
 191.598 +	    break;
 191.599 +	  }
 191.600 +	*t = '\0';		/* tie off string */
 191.601 +      }
 191.602 +    }
 191.603 +    close (fd);			/* flush message file */
 191.604 +  }
 191.605 +}
 191.606 +
 191.607 +/* News fetch message header
 191.608 + * Accepts: MAIL stream
 191.609 + *	    message # to fetch
 191.610 + *	    pointer to returned header text length
 191.611 + *	    option flags
 191.612 + * Returns: message header in RFC822 format
 191.613 + */
 191.614 +
 191.615 +char *news_header (MAILSTREAM *stream,unsigned long msgno,
 191.616 +		   unsigned long *length,long flags)
 191.617 +{
 191.618 +  MESSAGECACHE *elt;
 191.619 +  *length = 0;			/* default to empty */
 191.620 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 191.621 +  elt = mail_elt (stream,msgno);/* get elt */
 191.622 +  if (!elt->private.msg.header.text.data)
 191.623 +    news_load_message (stream,msgno,NLM_HEADER);
 191.624 +  *length = elt->private.msg.header.text.size;
 191.625 +  return (char *) elt->private.msg.header.text.data;
 191.626 +}
 191.627 +
 191.628 +
 191.629 +/* News fetch message text (body only)
 191.630 + * Accepts: MAIL stream
 191.631 + *	    message # to fetch
 191.632 + *	    pointer to returned stringstruct
 191.633 + *	    option flags
 191.634 + * Returns: T on success, NIL on failure
 191.635 + */
 191.636 +
 191.637 +long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 191.638 +{
 191.639 +  MESSAGECACHE *elt;
 191.640 +				/* UID call "impossible" */
 191.641 +  if (flags & FT_UID) return NIL;
 191.642 +  elt = mail_elt (stream,msgno);/* get elt */
 191.643 +				/* snarf message if don't have it yet */
 191.644 +  if (!elt->private.msg.text.text.data) {
 191.645 +    news_load_message (stream,msgno,NLM_TEXT);
 191.646 +    if (!elt->private.msg.text.text.data) return NIL;
 191.647 +  }
 191.648 +  if (!(flags & FT_PEEK)) {	/* mark as seen */
 191.649 +    mail_elt (stream,msgno)->seen = T;
 191.650 +    mm_flags (stream,msgno);
 191.651 +  }
 191.652 +  INIT (bs,mail_string,elt->private.msg.text.text.data,
 191.653 +	elt->private.msg.text.text.size);
 191.654 +  return T;
 191.655 +}
 191.656 +
 191.657 +/* News per-message modify flag
 191.658 + * Accepts: MAIL stream
 191.659 + *	    message cache element
 191.660 + */
 191.661 +
 191.662 +void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 191.663 +{
 191.664 +  if (!LOCAL->dirty) {		/* only bother checking if not dirty yet */
 191.665 +    if (elt->valid) {		/* if done, see if deleted changed */
 191.666 +      if (elt->sequence != elt->deleted) LOCAL->dirty = T;
 191.667 +      elt->sequence = T;	/* leave the sequence set */
 191.668 +    }
 191.669 +				/* note current setting of deleted flag */
 191.670 +    else elt->sequence = elt->deleted;
 191.671 +  }
 191.672 +}
 191.673 +
 191.674 +
 191.675 +/* News ping mailbox
 191.676 + * Accepts: MAIL stream
 191.677 + * Returns: T if stream alive, else NIL
 191.678 + */
 191.679 +
 191.680 +long news_ping (MAILSTREAM *stream)
 191.681 +{
 191.682 +  return T;			/* always alive */
 191.683 +}
 191.684 +
 191.685 +
 191.686 +/* News check mailbox
 191.687 + * Accepts: MAIL stream
 191.688 + */
 191.689 +
 191.690 +void news_check (MAILSTREAM *stream)
 191.691 +{
 191.692 +				/* never do if no updates */
 191.693 +  if (LOCAL->dirty) newsrc_write (LOCAL->name,stream);
 191.694 +  LOCAL->dirty = NIL;
 191.695 +}
 191.696 +
 191.697 +
 191.698 +/* News expunge mailbox
 191.699 + * Accepts: MAIL stream
 191.700 + *	    sequence to expunge if non-NIL
 191.701 + *	    expunge options
 191.702 + * Returns: T if success, NIL if failure
 191.703 + */
 191.704 +
 191.705 +long news_expunge (MAILSTREAM *stream,char *sequence,long options)
 191.706 +{
 191.707 +  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
 191.708 +  return LONGT;
 191.709 +}
 191.710 +
 191.711 +/* News copy message(s)
 191.712 + * Accepts: MAIL stream
 191.713 + *	    sequence
 191.714 + *	    destination mailbox
 191.715 + *	    option flags
 191.716 + * Returns: T if copy successful, else NIL
 191.717 + */
 191.718 +
 191.719 +long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 191.720 +{
 191.721 +  mailproxycopy_t pc =
 191.722 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 191.723 +  if (pc) return (*pc) (stream,sequence,mailbox,options);
 191.724 +  mm_log ("Copy not valid for News",ERROR);
 191.725 +  return NIL;
 191.726 +}
 191.727 +
 191.728 +
 191.729 +/* News append message from stringstruct
 191.730 + * Accepts: MAIL stream
 191.731 + *	    destination mailbox
 191.732 + *	    append callback function
 191.733 + *	    data for callback
 191.734 + * Returns: T if append successful, else NIL
 191.735 + */
 191.736 +
 191.737 +long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 191.738 +{
 191.739 +  mm_log ("Append not valid for news",ERROR);
 191.740 +  return NIL;
 191.741 +}
   192.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   192.2 +++ b/src/osdep/amiga/nl_ami.c	Mon Sep 14 15:17:45 2009 +0900
   192.3 @@ -0,0 +1,92 @@
   192.4 +/* ========================================================================
   192.5 + * Copyright 1988-2006 University of Washington
   192.6 + *
   192.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   192.8 + * you may not use this file except in compliance with the License.
   192.9 + * You may obtain a copy of the License at
  192.10 + *
  192.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  192.12 + *
  192.13 + * 
  192.14 + * ========================================================================
  192.15 + */
  192.16 +
  192.17 +/*
  192.18 + * Program:	UNIX/VMS newline routines
  192.19 + *
  192.20 + * Author:	Mark Crispin
  192.21 + *		Networks and Distributed Computing
  192.22 + *		Computing & Communications
  192.23 + *		University of Washington
  192.24 + *		Administration Building, AG-44
  192.25 + *		Seattle, WA  98195
  192.26 + *		Internet: MRC@CAC.Washington.EDU
  192.27 + *
  192.28 + * Date:	1 August 1988
  192.29 + * Last Edited:	30 August 2006
  192.30 + */
  192.31 +
  192.32 +/* Copy string with CRLF newlines
  192.33 + * Accepts: destination string
  192.34 + *	    pointer to size of destination string buffer
  192.35 + *	    source string
  192.36 + *	    length of source string
  192.37 + * Returns: length of copied string
  192.38 + */
  192.39 +
  192.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  192.41 +			  unsigned char *src,unsigned long srcl)
  192.42 +{
  192.43 +  long i = srcl * 2,j;
  192.44 +  unsigned char c,*d = src;
  192.45 +  if (*dst) {			/* candidate destination provided? */
  192.46 +				/* count NLs if doesn't fit worst-case */
  192.47 +    if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++;
  192.48 +				/* still too small, must reset destination */
  192.49 +    if (i > *dstl) fs_give ((void **) dst);
  192.50 +  }
  192.51 +				/* make a new buffer if needed */
  192.52 +  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
  192.53 +  d = *dst;			/* destination string */
  192.54 +  if (srcl) do {		/* main copy loop */
  192.55 +    if ((c = *src++) < '\016') {
  192.56 +				/* prepend CR to LF */
  192.57 +      if (c == '\012') *d++ = '\015';
  192.58 +				/* unlikely CR */
  192.59 +      else if ((c == '\015') && (srcl > 1) && (*src == '\012')) {
  192.60 +	*d++ = c;		/* copy the CR */
  192.61 +	c = *src++;		/* grab the LF */
  192.62 +	--srcl;			/* adjust the count */
  192.63 +      }
  192.64 +    }
  192.65 +    *d++ = c;			/* copy character */
  192.66 +  } while (--srcl);
  192.67 +  *d = '\0';			/* tie off destination */
  192.68 +  return d - *dst;		/* return length */
  192.69 +}
  192.70 +
  192.71 +/* Length of string after strcrlfcpy applied
  192.72 + * Accepts: source string
  192.73 + * Returns: length of string
  192.74 + */
  192.75 +
  192.76 +unsigned long strcrlflen (STRING *s)
  192.77 +{
  192.78 +  unsigned long pos = GETPOS (s);
  192.79 +  unsigned long i = SIZE (s);
  192.80 +  unsigned long j = i;
  192.81 +  while (j--) switch (SNX (s)) {/* search for newlines */
  192.82 +  case '\015':			/* unlikely carriage return */
  192.83 +    if (j && (CHR (s) == '\012')) {
  192.84 +      SNX (s);			/* eat the line feed */
  192.85 +      j--;
  192.86 +    }
  192.87 +    break;
  192.88 +  case '\012':			/* line feed? */
  192.89 +    i++;
  192.90 +  default:			/* ordinary chararacter */
  192.91 +    break;
  192.92 +  }
  192.93 +  SETPOS (s,pos);		/* restore old position */
  192.94 +  return i;
  192.95 +}
   193.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   193.2 +++ b/src/osdep/amiga/os_ami.c	Mon Sep 14 15:17:45 2009 +0900
   193.3 @@ -0,0 +1,80 @@
   193.4 +/* ========================================================================
   193.5 + * Copyright 1988-2006 University of Washington
   193.6 + *
   193.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   193.8 + * you may not use this file except in compliance with the License.
   193.9 + * You may obtain a copy of the License at
  193.10 + *
  193.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  193.12 + *
  193.13 + * 
  193.14 + * ========================================================================
  193.15 + */
  193.16 +
  193.17 +/*
  193.18 + * Program:	Operating-system dependent routines -- Amiga version
  193.19 + *
  193.20 + * Author:	Mark Crispin
  193.21 + *		Networks and Distributed Computing
  193.22 + *		Computing & Communications
  193.23 + *		University of Washington
  193.24 + *		Administration Building, AG-44
  193.25 + *		Seattle, WA  98195
  193.26 + *		Internet: MRC@CAC.Washington.EDU
  193.27 + *
  193.28 + * Date:	11 May 1989
  193.29 + * Last Edited:	30 August 2006
  193.30 + */
  193.31 +
  193.32 +#define PINE		       /* to get full DIR description in <dirent.h> */
  193.33 +#include "tcp_ami.h"           /* must be before osdep includes tcp.h */
  193.34 +#include "mail.h"
  193.35 +#include "osdep.h"
  193.36 +#include <stdio.h>
  193.37 +#include <sys/stat.h>
  193.38 +#include <sys/time.h>
  193.39 +#include <sys/socket.h>
  193.40 +#include <netinet/in.h>
  193.41 +#include <arpa/inet.h>
  193.42 +#include <netdb.h>
  193.43 +#include <ctype.h>
  193.44 +#include <errno.h>
  193.45 +extern int errno;		/* just in case */
  193.46 +#include <pwd.h>
  193.47 +#include "misc.h"
  193.48 +
  193.49 +extern int sys_nerr;
  193.50 +extern char *sys_errlist[];
  193.51 +
  193.52 +#define DIR_SIZE(d) d->d_reclen /* for scandir.c */
  193.53 +
  193.54 +#include "fs_ami.c"
  193.55 +#include "ftl_ami.c"
  193.56 +#include "nl_ami.c"
  193.57 +#include "env_ami.c"
  193.58 +#include "tcp_ami.c"
  193.59 +#include "log_std.c"
  193.60 +#include "gr_waitp.c"
  193.61 +#include "tz_bsd.c"
  193.62 +#include "scandir.c"
  193.63 +#include "gethstid.c"
  193.64 +
  193.65 +#undef utime
  193.66 +
  193.67 +/* Amiga has its own wierd utime() with an incompatible struct utimbuf that
  193.68 + * does not match with the traditional time_t [2].
  193.69 + */
  193.70 +
  193.71 +/* Portable utime() that takes it args like real Unix systems
  193.72 + * Accepts: file path
  193.73 + *	    traditional utime() argument
  193.74 + * Returns: utime() results
  193.75 + */
  193.76 +
  193.77 +int portable_utime (char *file,time_t timep[2])
  193.78 +{
  193.79 +  struct utimbuf times;
  193.80 +  times.actime = timep[0];	/* copy the portable values */
  193.81 +  times.modtime = timep[1];
  193.82 +  return utime (file,&times);	/* now call Amiga's routine */
  193.83 +}
   194.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   194.2 +++ b/src/osdep/amiga/os_ami.h	Mon Sep 14 15:17:45 2009 +0900
   194.3 @@ -0,0 +1,54 @@
   194.4 +/* ========================================================================
   194.5 + * Copyright 1988-2006 University of Washington
   194.6 + *
   194.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   194.8 + * you may not use this file except in compliance with the License.
   194.9 + * You may obtain a copy of the License at
  194.10 + *
  194.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  194.12 + *
  194.13 + * 
  194.14 + * ========================================================================
  194.15 + */
  194.16 +
  194.17 +/*
  194.18 + * Program:	Operating-system dependent routines -- Amiga version
  194.19 + *
  194.20 + * Author:	Mark Crispin
  194.21 + *		Networks and Distributed Computing
  194.22 + *		Computing & Communications
  194.23 + *		University of Washington
  194.24 + *		Administration Building, AG-44
  194.25 + *		Seattle, WA  98195
  194.26 + *		Internet: MRC@CAC.Washington.EDU
  194.27 + *
  194.28 + * Date:	11 May 1989
  194.29 + * Last Edited:	15 September 2006
  194.30 + */
  194.31 +
  194.32 +#include <proto/socket.h>
  194.33 +#include <sys/types.h>
  194.34 +#include <sys/dir.h>
  194.35 +#include <stdlib.h>
  194.36 +#include <string.h>
  194.37 +#include <syslog.h>
  194.38 +#include <sys/file.h>
  194.39 +
  194.40 +/* Different names, equivalent things in BSD and SysV */
  194.41 +
  194.42 +#define direct dirent
  194.43 +#define utime portable_utime
  194.44 +int portable_utime (char *file,time_t timep[2]);
  194.45 +
  194.46 +#include "env_ami.h"
  194.47 +#include "fs.h"
  194.48 +#include "ftl.h"
  194.49 +#include "nl.h"
  194.50 +#include "tcp.h"
  194.51 +
  194.52 +long gethostid (void);
  194.53 +typedef int (*select_t) (struct direct *name);
  194.54 +typedef int (*compar_t) (void *d1,void *d2);
  194.55 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  194.56 +	     compar_t compar);
  194.57 +int alphasort (void *d1,void *d2);
   195.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   195.2 +++ b/src/osdep/amiga/phile.c	Mon Sep 14 15:17:45 2009 +0900
   195.3 @@ -0,0 +1,553 @@
   195.4 +/* ========================================================================
   195.5 + * Copyright 1988-2006 University of Washington
   195.6 + *
   195.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   195.8 + * you may not use this file except in compliance with the License.
   195.9 + * You may obtain a copy of the License at
  195.10 + *
  195.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  195.12 + *
  195.13 + * 
  195.14 + * ========================================================================
  195.15 + */
  195.16 +
  195.17 +/*
  195.18 + * Program:	File routines
  195.19 + *
  195.20 + * Author:	Mark Crispin
  195.21 + *		Networks and Distributed Computing
  195.22 + *		Computing & Communications
  195.23 + *		University of Washington
  195.24 + *		Administration Building, AG-44
  195.25 + *		Seattle, WA  98195
  195.26 + *		Internet: MRC@CAC.Washington.EDU
  195.27 + *
  195.28 + * Date:	25 August 1993
  195.29 + * Last Edited:	9 May 2006
  195.30 + */
  195.31 +
  195.32 +
  195.33 +#include <stdio.h>
  195.34 +#include <ctype.h>
  195.35 +#include <errno.h>
  195.36 +extern int errno;		/* just in case */
  195.37 +#include <signal.h>
  195.38 +#include "mail.h"
  195.39 +#include "osdep.h"
  195.40 +#include <pwd.h>
  195.41 +#include <sys/stat.h>
  195.42 +#include <sys/time.h>
  195.43 +#include "rfc822.h"
  195.44 +#include "misc.h"
  195.45 +#include "dummy.h"
  195.46 +
  195.47 +/* Types returned from phile_type() */
  195.48 +
  195.49 +#define PTYPEBINARY 0		/* binary data */
  195.50 +#define PTYPETEXT 1		/* textual data */
  195.51 +#define PTYPECRTEXT 2		/* textual data with CR */
  195.52 +#define PTYPE8 4		/* textual 8bit data */
  195.53 +#define PTYPEISO2022JP 8	/* textual Japanese */
  195.54 +#define PTYPEISO2022KR 16	/* textual Korean */
  195.55 +#define PTYPEISO2022CN 32	/* textual Chinese */
  195.56 +
  195.57 +
  195.58 +/* PHILE I/O stream local data */
  195.59 +	
  195.60 +typedef struct phile_local {
  195.61 +  ENVELOPE *env;		/* file envelope */
  195.62 +  BODY *body;			/* file body */
  195.63 +  char tmp[MAILTMPLEN];		/* temporary buffer */
  195.64 +} PHILELOCAL;
  195.65 +
  195.66 +
  195.67 +/* Convenient access to local data */
  195.68 +
  195.69 +#define LOCAL ((PHILELOCAL *) stream->local)
  195.70 +
  195.71 +
  195.72 +/* Function prototypes */
  195.73 +
  195.74 +DRIVER *phile_valid (char *name);
  195.75 +int phile_isvalid (char *name,char *tmp);
  195.76 +void *phile_parameters (long function,void *value);
  195.77 +void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  195.78 +void phile_list (MAILSTREAM *stream,char *ref,char *pat);
  195.79 +void phile_lsub (MAILSTREAM *stream,char *ref,char *pat);
  195.80 +long phile_create (MAILSTREAM *stream,char *mailbox);
  195.81 +long phile_delete (MAILSTREAM *stream,char *mailbox);
  195.82 +long phile_rename (MAILSTREAM *stream,char *old,char *newname);
  195.83 +long phile_status (MAILSTREAM *stream,char *mbx,long flags);
  195.84 +MAILSTREAM *phile_open (MAILSTREAM *stream);
  195.85 +int phile_type (unsigned char *s,unsigned long i,unsigned long *j);
  195.86 +void phile_close (MAILSTREAM *stream,long options);
  195.87 +ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
  195.88 +			   long flags);
  195.89 +char *phile_header (MAILSTREAM *stream,unsigned long msgno,
  195.90 +		    unsigned long *length,long flags);
  195.91 +long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  195.92 +long phile_ping (MAILSTREAM *stream);
  195.93 +void phile_check (MAILSTREAM *stream);
  195.94 +long phile_expunge (MAILSTREAM *stream,char *sequence,long options);
  195.95 +long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  195.96 +long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  195.97 +
  195.98 +/* File routines */
  195.99 +
 195.100 +
 195.101 +/* Driver dispatch used by MAIL */
 195.102 +
 195.103 +DRIVER philedriver = {
 195.104 +  "phile",			/* driver name */
 195.105 +				/* driver flags */
 195.106 +  DR_LOCAL|DR_READONLY|DR_NOSTICKY,
 195.107 +  (DRIVER *) NIL,		/* next driver */
 195.108 +  phile_valid,			/* mailbox is valid for us */
 195.109 +  phile_parameters,		/* manipulate parameters */
 195.110 +  phile_scan,			/* scan mailboxes */
 195.111 +  phile_list,			/* list mailboxes */
 195.112 +  phile_lsub,			/* list subscribed mailboxes */
 195.113 +  NIL,				/* subscribe to mailbox */
 195.114 +  NIL,				/* unsubscribe from mailbox */
 195.115 +  dummy_create,			/* create mailbox */
 195.116 +  dummy_delete,			/* delete mailbox */
 195.117 +  dummy_rename,			/* rename mailbox */
 195.118 +  phile_status,			/* status of mailbox */
 195.119 +  phile_open,			/* open mailbox */
 195.120 +  phile_close,			/* close mailbox */
 195.121 +  NIL,				/* fetch message "fast" attributes */
 195.122 +  NIL,				/* fetch message flags */
 195.123 +  NIL,				/* fetch overview */
 195.124 +  phile_structure,		/* fetch message envelopes */
 195.125 +  phile_header,			/* fetch message header only */
 195.126 +  phile_text,			/* fetch message body only */
 195.127 +  NIL,				/* fetch partial message text */
 195.128 +  NIL,				/* unique identifier */
 195.129 +  NIL,				/* message number */
 195.130 +  NIL,				/* modify flags */
 195.131 +  NIL,				/* per-message modify flags */
 195.132 +  NIL,				/* search for message based on criteria */
 195.133 +  NIL,				/* sort messages */
 195.134 +  NIL,				/* thread messages */
 195.135 +  phile_ping,			/* ping mailbox to see if still alive */
 195.136 +  phile_check,			/* check for new messages */
 195.137 +  phile_expunge,		/* expunge deleted messages */
 195.138 +  phile_copy,			/* copy messages to another mailbox */
 195.139 +  phile_append,			/* append string message to mailbox */
 195.140 +  NIL				/* garbage collect stream */
 195.141 +};
 195.142 +
 195.143 +				/* prototype stream */
 195.144 +MAILSTREAM phileproto = {&philedriver};
 195.145 +
 195.146 +/* File validate mailbox
 195.147 + * Accepts: mailbox name
 195.148 + * Returns: our driver if name is valid, NIL otherwise
 195.149 + */
 195.150 +
 195.151 +DRIVER *phile_valid (char *name)
 195.152 +{
 195.153 +  char tmp[MAILTMPLEN];
 195.154 +  return phile_isvalid (name,tmp) ? &philedriver : NIL;
 195.155 +}
 195.156 +
 195.157 +
 195.158 +/* File test for valid mailbox
 195.159 + * Accepts: mailbox name
 195.160 + * Returns: T if valid, NIL otherwise
 195.161 + */
 195.162 +
 195.163 +int phile_isvalid (char *name,char *tmp)
 195.164 +{
 195.165 +  struct stat sbuf;
 195.166 +  char *s;
 195.167 +				/* INBOX never accepted, any other name is */
 195.168 +  return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) &&
 195.169 +	  !(sbuf.st_mode & S_IFDIR) &&
 195.170 +				/* only allow empty files if no empty proto
 195.171 +				   or if #ftp */
 195.172 +	  (sbuf.st_size || !default_proto (T) ||
 195.173 +	   ((*name == '#') && ((name[1] == 'f') || (name[1] == 'F')) &&
 195.174 +	    ((name[2] == 't') || (name[2] == 'T')) &&
 195.175 +	    ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/'))));
 195.176 +}
 195.177 +
 195.178 +/* File manipulate driver parameters
 195.179 + * Accepts: function code
 195.180 + *	    function-dependent value
 195.181 + * Returns: function-dependent return value
 195.182 + */
 195.183 +
 195.184 +void *phile_parameters (long function,void *value)
 195.185 +{
 195.186 +  return NIL;
 195.187 +}
 195.188 +
 195.189 +/* File mail scan mailboxes
 195.190 + * Accepts: mail stream
 195.191 + *	    reference
 195.192 + *	    pattern to search
 195.193 + *	    string to scan
 195.194 + */
 195.195 +
 195.196 +void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 195.197 +{
 195.198 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 195.199 +}
 195.200 +
 195.201 +
 195.202 +/* File list mailboxes
 195.203 + * Accepts: mail stream
 195.204 + *	    reference
 195.205 + *	    pattern to search
 195.206 + */
 195.207 +
 195.208 +void phile_list (MAILSTREAM *stream,char *ref,char *pat)
 195.209 +{
 195.210 +  if (stream) dummy_list (NIL,ref,pat);
 195.211 +}
 195.212 +
 195.213 +
 195.214 +/* File list subscribed mailboxes
 195.215 + * Accepts: mail stream
 195.216 + *	    reference
 195.217 + *	    pattern to search
 195.218 + */
 195.219 +
 195.220 +void phile_lsub (MAILSTREAM *stream,char *ref,char *pat)
 195.221 +{
 195.222 +  if (stream) dummy_lsub (NIL,ref,pat);
 195.223 +}
 195.224 +
 195.225 +
 195.226 +/* File status
 195.227 + * Accepts: mail stream
 195.228 + *	    mailbox name
 195.229 + *	    status flags
 195.230 + * Returns: T on success, NIL on failure
 195.231 + */
 195.232 +
 195.233 +long phile_status (MAILSTREAM *stream,char *mbx,long flags)
 195.234 +{
 195.235 +  char *s,tmp[MAILTMPLEN];
 195.236 +  MAILSTATUS status;
 195.237 +  struct stat sbuf;
 195.238 +  long ret = NIL;
 195.239 +  if ((s = mailboxfile (tmp,mbx)) && *s && !stat (s,&sbuf)) {
 195.240 +    status.flags = flags;	/* return status values */
 195.241 +    status.unseen = (stream && mail_elt (stream,1)->seen) ? 0 : 1;
 195.242 +    status.messages = status.recent = status.uidnext = 1;
 195.243 +    status.uidvalidity = sbuf.st_mtime;
 195.244 +				/* pass status to main program */
 195.245 +    mm_status (stream,mbx,&status);
 195.246 +    ret = LONGT;		/* success */
 195.247 +  }
 195.248 +  return ret;
 195.249 +}
 195.250 +
 195.251 +/* File open
 195.252 + * Accepts: Stream to open
 195.253 + * Returns: Stream on success, NIL on failure
 195.254 + */
 195.255 +
 195.256 +MAILSTREAM *phile_open (MAILSTREAM *stream)
 195.257 +{
 195.258 +  int i,k,fd;
 195.259 +  unsigned long j,m;
 195.260 +  char *s,tmp[MAILTMPLEN];
 195.261 +  struct passwd *pw;
 195.262 +  struct stat sbuf;
 195.263 +  struct tm *t;
 195.264 +  MESSAGECACHE *elt;
 195.265 +  SIZEDTEXT *buf;
 195.266 +				/* return prototype for OP_PROTOTYPE call */
 195.267 +  if (!stream) return &phileproto;
 195.268 +  if (stream->local) fatal ("phile recycle stream");
 195.269 +				/* open associated file */
 195.270 +  if (!mailboxfile (tmp,stream->mailbox) || !tmp[0] || stat (tmp,&sbuf) ||
 195.271 +      (fd = open (tmp,O_RDONLY,NIL)) < 0) {
 195.272 +    sprintf (tmp,"Unable to open file %s",stream->mailbox);
 195.273 +    mm_log (tmp,ERROR);
 195.274 +    return NIL;
 195.275 +  }
 195.276 +  fs_give ((void **) &stream->mailbox);
 195.277 +  stream->mailbox = cpystr (tmp);
 195.278 +  stream->local = fs_get (sizeof (PHILELOCAL));
 195.279 +  mail_exists (stream,1);	/* make sure upper level knows */
 195.280 +  mail_recent (stream,1);
 195.281 +  elt = mail_elt (stream,1);	/* instantiate cache element */
 195.282 +  elt->valid = elt->recent = T;	/* mark valid flags */
 195.283 +  stream->sequence++;		/* bump sequence number */
 195.284 +  stream->rdonly = T;		/* make sure upper level knows readonly */
 195.285 +				/* instantiate a new envelope and body */
 195.286 +  LOCAL->env = mail_newenvelope ();
 195.287 +  LOCAL->body = mail_newbody ();
 195.288 +
 195.289 +  t = gmtime (&sbuf.st_mtime);	/* get UTC time and Julian day */
 195.290 +  i = t->tm_hour * 60 + t->tm_min;
 195.291 +  k = t->tm_yday;
 195.292 +  t = localtime(&sbuf.st_mtime);/* get local time */
 195.293 +				/* calculate time delta */
 195.294 +  i = t->tm_hour * 60 + t->tm_min - i;
 195.295 +  if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
 195.296 +  k = abs (i);			/* time from UTC either way */
 195.297 +  elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec;
 195.298 +  elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
 195.299 +  elt->year = t->tm_year - (BASEYEAR - 1900);
 195.300 +  elt->zoccident = (k == i) ? 0 : 1;
 195.301 +  elt->zhours = k/60;
 195.302 +  elt->zminutes = k % 60;
 195.303 +  sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d",
 195.304 +	   days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 195.305 +	   t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+',
 195.306 +	   elt->zhours,elt->zminutes);
 195.307 +				/* set up Date field */
 195.308 +  LOCAL->env->date = cpystr (tmp);
 195.309 +
 195.310 +				/* fill in From field from file owner */
 195.311 +  LOCAL->env->from = mail_newaddr ();
 195.312 +  if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name);
 195.313 +  else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid);
 195.314 +  LOCAL->env->from->mailbox = cpystr (tmp);
 195.315 +  LOCAL->env->from->host = cpystr (mylocalhost ());
 195.316 +				/* set subject to be mailbox name */
 195.317 +  LOCAL->env->subject = cpystr (stream->mailbox);
 195.318 +				/* slurp the data */
 195.319 +  (buf = &elt->private.special.text)->size = sbuf.st_size;
 195.320 +  read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size);
 195.321 +  buf->data[buf->size] = '\0';
 195.322 +  close (fd);			/* close the file */
 195.323 +				/* analyze data type */
 195.324 +  if (i = phile_type (buf->data,buf->size,&j)) {
 195.325 +    LOCAL->body->type = TYPETEXT;
 195.326 +    LOCAL->body->subtype = cpystr ("PLAIN");
 195.327 +    if (!(i & PTYPECRTEXT)) {	/* change Internet newline format as needed */
 195.328 +      s = (char *) buf->data;	/* make copy of UNIX-format string */
 195.329 +      buf->data = NIL;		/* zap the buffer */
 195.330 +      buf->size = strcrlfcpy (&buf->data,&m,s,buf->size);
 195.331 +      fs_give ((void **) &s);	/* flush original UNIX-format string */
 195.332 +    }
 195.333 +    LOCAL->body->parameter = mail_newbody_parameter ();
 195.334 +    LOCAL->body->parameter->attribute = cpystr ("charset");
 195.335 +    LOCAL->body->parameter->value =
 195.336 +      cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" :
 195.337 +	      (i & PTYPEISO2022KR) ? "ISO-2022-KR" :
 195.338 +	      (i & PTYPEISO2022CN) ? "ISO-2022-CN" :
 195.339 +	      (i & PTYPE8) ? "X-UNKNOWN" : "US-ASCII");
 195.340 +    LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT;
 195.341 +    LOCAL->body->size.lines = j;
 195.342 +  }
 195.343 +  else {			/* binary data */
 195.344 +    LOCAL->body->type = TYPEAPPLICATION;
 195.345 +    LOCAL->body->subtype = cpystr ("OCTET-STREAM");
 195.346 +    LOCAL->body->parameter = mail_newbody_parameter ();
 195.347 +    LOCAL->body->parameter->attribute = cpystr ("name");
 195.348 +    LOCAL->body->parameter->value =
 195.349 +      cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox);
 195.350 +    LOCAL->body->encoding = ENCBASE64;
 195.351 +    buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size);
 195.352 +    fs_give ((void **) &s);	/* flush originary binary contents */
 195.353 +  }
 195.354 +  phile_header (stream,1,&j,NIL);
 195.355 +  LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size;
 195.356 +  elt->rfc822_size = j + buf->size;
 195.357 +				/* only one message ever... */
 195.358 +  stream->uid_validity = sbuf.st_mtime;
 195.359 +  stream->uid_last = elt->private.uid = 1;
 195.360 +  return stream;		/* return stream alive to caller */
 195.361 +}
 195.362 +
 195.363 +/* File determine data type
 195.364 + * Accepts: data to examine
 195.365 + *	    size of data
 195.366 + *	    pointer to line count return
 195.367 + * Returns: PTYPE mask of data type
 195.368 + */
 195.369 +
 195.370 +int phile_type (unsigned char *s,unsigned long i,unsigned long *j)
 195.371 +{
 195.372 +  int ret = PTYPETEXT;
 195.373 +  char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
 195.374 +  *j = 0;			/* no lines */
 195.375 +				/* check type of every character */
 195.376 +  while (i--) switch (charvec[*s++]) {
 195.377 +  case 'A':
 195.378 +    ret |= PTYPE8;		/* 8bit character */
 195.379 +    break;
 195.380 +  case 'a':
 195.381 +    break;			/* ASCII character */
 195.382 +  case 'b':
 195.383 +    return PTYPEBINARY;		/* binary byte seen, stop immediately */
 195.384 +  case 'c':
 195.385 +    ret |= PTYPECRTEXT;		/* CR indicates Internet text */
 195.386 +    break;
 195.387 +  case 'e':			/* ESC */
 195.388 +    if (*s == '$') {		/* ISO-2022 sequence? */
 195.389 +      switch (s[1]) {
 195.390 +      case 'B': case '@': ret |= PTYPEISO2022JP; break;
 195.391 +      case ')':
 195.392 +	switch (s[2]) {
 195.393 +	case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break;
 195.394 +	case 'C': ret |= PTYPEISO2022KR; break;
 195.395 +	}
 195.396 +      case '*':
 195.397 +	switch (s[2]) {
 195.398 +	case 'H': ret |= PTYPEISO2022CN; break;
 195.399 +	}
 195.400 +      case '+':
 195.401 +	switch (s[2]) {
 195.402 +	case 'I': case 'J': case 'K': case 'L': case 'M':
 195.403 +	  ret |= PTYPEISO2022CN; break;
 195.404 +	}
 195.405 +      }
 195.406 +    }
 195.407 +    break;
 195.408 +  case 'l':			/* newline */
 195.409 +    (*j)++;
 195.410 +    break;
 195.411 +  }
 195.412 +  return ret;			/* return type of data */
 195.413 +}
 195.414 +
 195.415 +/* File close
 195.416 + * Accepts: MAIL stream
 195.417 + *	    close options
 195.418 + */
 195.419 +
 195.420 +void phile_close (MAILSTREAM *stream,long options)
 195.421 +{
 195.422 +  if (LOCAL) {			/* only if a file is open */
 195.423 +    fs_give ((void **) &mail_elt (stream,1)->private.special.text.data);
 195.424 +				/* nuke the local data */
 195.425 +    fs_give ((void **) &stream->local);
 195.426 +    stream->dtb = NIL;		/* log out the DTB */
 195.427 +  }
 195.428 +}
 195.429 +
 195.430 +/* File fetch structure
 195.431 + * Accepts: MAIL stream
 195.432 + *	    message # to fetch
 195.433 + *	    pointer to return body
 195.434 + *	    option flags
 195.435 + * Returns: envelope of this message, body returned in body value
 195.436 + *
 195.437 + * Fetches the "fast" information as well
 195.438 + */
 195.439 +
 195.440 +ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
 195.441 +			   long flags)
 195.442 +{
 195.443 +  if (body) *body = LOCAL->body;
 195.444 +  return LOCAL->env;		/* return the envelope */
 195.445 +}
 195.446 +
 195.447 +
 195.448 +/* File fetch message header
 195.449 + * Accepts: MAIL stream
 195.450 + *	    message # to fetch
 195.451 + *	    pointer to returned header text length
 195.452 + *	    option flags
 195.453 + * Returns: message header in RFC822 format
 195.454 + */
 195.455 +
 195.456 +char *phile_header (MAILSTREAM *stream,unsigned long msgno,
 195.457 +		    unsigned long *length,long flags)
 195.458 +{
 195.459 +  rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body);
 195.460 +  *length = strlen (LOCAL->tmp);
 195.461 +  return LOCAL->tmp;
 195.462 +}
 195.463 +
 195.464 +
 195.465 +/* File fetch message text (body only)
 195.466 + * Accepts: MAIL stream
 195.467 + *	    message # to fetch
 195.468 + *	    pointer to returned stringstruct
 195.469 + *	    option flags
 195.470 + * Returns: T, always
 195.471 + */
 195.472 +
 195.473 +long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 195.474 +{
 195.475 +  SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text;
 195.476 +  if (!(flags &FT_PEEK)) {	/* mark message as seen */
 195.477 +    mail_elt (stream,msgno)->seen = T;
 195.478 +    mm_flags (stream,msgno);
 195.479 +  }
 195.480 +  INIT (bs,mail_string,buf->data,buf->size);
 195.481 +  return T;
 195.482 +}
 195.483 +
 195.484 +/* File ping mailbox
 195.485 + * Accepts: MAIL stream
 195.486 + * Returns: T if stream alive, else NIL
 195.487 + * No-op for readonly files, since read/writer can expunge it from under us!
 195.488 + */
 195.489 +
 195.490 +long phile_ping (MAILSTREAM *stream)
 195.491 +{
 195.492 +  return T;
 195.493 +}
 195.494 +
 195.495 +/* File check mailbox
 195.496 + * Accepts: MAIL stream
 195.497 + * No-op for readonly files, since read/writer can expunge it from under us!
 195.498 + */
 195.499 +
 195.500 +void phile_check (MAILSTREAM *stream)
 195.501 +{
 195.502 +  mm_log ("Check completed",NIL);
 195.503 +}
 195.504 +
 195.505 +/* File expunge mailbox
 195.506 + * Accepts: MAIL stream
 195.507 + *	    sequence to expunge if non-NIL
 195.508 + *	    expunge options
 195.509 + * Returns: T if success, NIL if failure
 195.510 + */
 195.511 +
 195.512 +long phile_expunge (MAILSTREAM *stream,char *sequence,long options)
 195.513 +{
 195.514 +  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
 195.515 +  return LONGT;
 195.516 +}
 195.517 +
 195.518 +/* File copy message(s)
 195.519 + * Accepts: MAIL stream
 195.520 + *	    sequence
 195.521 + *	    destination mailbox
 195.522 + *	    copy options
 195.523 + * Returns: T if copy successful, else NIL
 195.524 + */
 195.525 +
 195.526 +long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 195.527 +{
 195.528 +  char tmp[MAILTMPLEN];
 195.529 +  mailproxycopy_t pc =
 195.530 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 195.531 +  if (pc) return (*pc) (stream,sequence,mailbox,options);
 195.532 +  sprintf (tmp,"Can't copy - file \"%s\" is not in valid mailbox format",
 195.533 +	   stream->mailbox);
 195.534 +  mm_log (tmp,ERROR);
 195.535 +  return NIL;
 195.536 +}
 195.537 +
 195.538 +
 195.539 +/* File append message from stringstruct
 195.540 + * Accepts: MAIL stream
 195.541 + *	    destination mailbox
 195.542 + *	    append callback function
 195.543 + *	    data for callback
 195.544 + * Returns: T if append successful, else NIL
 195.545 + */
 195.546 +
 195.547 +long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 195.548 +{
 195.549 +  char tmp[MAILTMPLEN],file[MAILTMPLEN];
 195.550 +  char *s = mailboxfile (file,mailbox);
 195.551 +  if (s && *s) 
 195.552 +    sprintf (tmp,"Can't append - not in valid mailbox format: %.80s",s);
 195.553 +  else sprintf (tmp,"Can't append - invalid name: %.80s",mailbox);
 195.554 +  mm_log (tmp,ERROR);
 195.555 +  return NIL;
 195.556 +}
   196.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   196.2 +++ b/src/osdep/amiga/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   196.3 @@ -0,0 +1,89 @@
   196.4 +/* ========================================================================
   196.5 + * Copyright 1988-2006 University of Washington
   196.6 + *
   196.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   196.8 + * you may not use this file except in compliance with the License.
   196.9 + * You may obtain a copy of the License at
  196.10 + *
  196.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  196.12 + *
  196.13 + * 
  196.14 + * ========================================================================
  196.15 + */
  196.16 +
  196.17 +/*
  196.18 + * Program:	IMAP Wildcard Matching Routines (case-dependent)
  196.19 + *
  196.20 + * Author:	Mark Crispin
  196.21 + *		Networks and Distributed Computing
  196.22 + *		Computing & Communications
  196.23 + *		University of Washington
  196.24 + *		Administration Building, AG-44
  196.25 + *		Seattle, WA  98195
  196.26 + *		Internet: MRC@CAC.Washington.EDU
  196.27 + *
  196.28 + * Date:	15 June 2000
  196.29 + * Last Edited:	30 August 2006
  196.30 + */
  196.31 +
  196.32 +/* Wildcard pattern match
  196.33 + * Accepts: base string
  196.34 + *	    pattern string
  196.35 + *	    delimiter character
  196.36 + * Returns: T if pattern matches base, else NIL
  196.37 + */
  196.38 +
  196.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  196.40 +{
  196.41 +  switch (*pat) {
  196.42 +  case '%':			/* non-recursive */
  196.43 +				/* % at end, OK if no inferiors */
  196.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  196.45 +                                /* scan remainder of string until delimiter */
  196.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  196.47 +    while ((*s != delim) && *s++);
  196.48 +    break;
  196.49 +  case '*':			/* match 0 or more characters */
  196.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  196.51 +				/* scan remainder of string */
  196.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  196.53 +    while (*s++);
  196.54 +    break;
  196.55 +  case '\0':			/* end of pattern */
  196.56 +    return *s ? NIL : T;	/* success if also end of base */
  196.57 +  default:			/* match this character */
  196.58 +    return (*pat == *s) ? pmatch_full (s+1,pat+1,delim) : NIL;
  196.59 +  }
  196.60 +  return NIL;
  196.61 +}
  196.62 +
  196.63 +/* Directory pattern match
  196.64 + * Accepts: base string
  196.65 + *	    pattern string
  196.66 + *	    delimiter character
  196.67 + * Returns: T if base is a matching directory of pattern, else NIL
  196.68 + */
  196.69 +
  196.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  196.71 +{
  196.72 +  switch (*pat) {
  196.73 +  case '%':			/* non-recursive */
  196.74 +    if (!*s) return T;		/* end of base means have a subset match */
  196.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  196.76 +				/* scan remainder of string until delimiter */
  196.77 +    do if (dmatch (s,pat,delim)) return T;
  196.78 +    while ((*s != delim) && *s++);
  196.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  196.80 +    return dmatch (s,pat,delim);/* do new scan */
  196.81 +  case '*':			/* match 0 or more characters */
  196.82 +    return T;			/* unconditional match */
  196.83 +  case '\0':			/* end of pattern */
  196.84 +    break;
  196.85 +  default:			/* match this character */
  196.86 +    if (*s) return (*pat == *s) ? dmatch (s+1,pat+1,delim) : NIL;
  196.87 +				/* end of base, return if at delimiter */
  196.88 +    else if (*pat == delim) return T;
  196.89 +    break;
  196.90 +  }
  196.91 +  return NIL;
  196.92 +}
   197.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   197.2 +++ b/src/osdep/amiga/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
   197.3 @@ -0,0 +1,36 @@
   197.4 +/* ========================================================================
   197.5 + * Copyright 1988-2006 University of Washington
   197.6 + *
   197.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   197.8 + * you may not use this file except in compliance with the License.
   197.9 + * You may obtain a copy of the License at
  197.10 + *
  197.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  197.12 + *
  197.13 + * 
  197.14 + * ========================================================================
  197.15 + */
  197.16 +
  197.17 +/*
  197.18 + * Program:	Pseudo Header Strings
  197.19 + *
  197.20 + * Author:	Mark Crispin
  197.21 + *		Networks and Distributed Computing
  197.22 + *		Computing & Communications
  197.23 + *		University of Washington
  197.24 + *		Administration Building, AG-44
  197.25 + *		Seattle, WA  98195
  197.26 + *		Internet: MRC@CAC.Washington.EDU
  197.27 + *
  197.28 + * Date:	26 September 1996
  197.29 + * Last Edited:	30 August 2006
  197.30 + */
  197.31 +
  197.32 +/* Local sites may wish to alter this text */
  197.33 +
  197.34 +char *pseudo_from = "MAILER-DAEMON";
  197.35 +char *pseudo_name = "Mail System Internal Data";
  197.36 +char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
  197.37 +char *pseudo_msg =
  197.38 +  "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."
  197.39 +  ;
   198.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   198.2 +++ b/src/osdep/amiga/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
   198.3 @@ -0,0 +1,30 @@
   198.4 +/* ========================================================================
   198.5 + * Copyright 1988-2006 University of Washington
   198.6 + *
   198.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   198.8 + * you may not use this file except in compliance with the License.
   198.9 + * You may obtain a copy of the License at
  198.10 + *
  198.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  198.12 + *
  198.13 + * 
  198.14 + * ========================================================================
  198.15 + */
  198.16 +
  198.17 +/*
  198.18 + * Program:	Pseudo Header Strings
  198.19 + *
  198.20 + * Author:	Mark Crispin
  198.21 + *		Networks and Distributed Computing
  198.22 + *		Computing & Communications
  198.23 + *		University of Washington
  198.24 + *		Administration Building, AG-44
  198.25 + *		Seattle, WA  98195
  198.26 + *		Internet: MRC@CAC.Washington.EDU
  198.27 + *
  198.28 + * Date:	26 September 1996
  198.29 + * Last Edited:	30 August 2006
  198.30 + */
  198.31 +
  198.32 +
  198.33 +extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
   199.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   199.2 +++ b/src/osdep/amiga/scandir.c	Mon Sep 14 15:17:45 2009 +0900
   199.3 @@ -0,0 +1,81 @@
   199.4 +/* ========================================================================
   199.5 + * Copyright 1988-2006 University of Washington
   199.6 + *
   199.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   199.8 + * you may not use this file except in compliance with the License.
   199.9 + * You may obtain a copy of the License at
  199.10 + *
  199.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  199.12 + *
  199.13 + * 
  199.14 + * ========================================================================
  199.15 + */
  199.16 +
  199.17 +/*
  199.18 + * Program:	Scan directories
  199.19 + *
  199.20 + * Author:	Mark Crispin
  199.21 + *		Networks and Distributed Computing
  199.22 + *		Computing & Communications
  199.23 + *		University of Washington
  199.24 + *		Administration Building, AG-44
  199.25 + *		Seattle, WA  98195
  199.26 + *		Internet: MRC@CAC.Washington.EDU
  199.27 + *
  199.28 + * Date:	1 August 1988
  199.29 + * Last Edited:	15 September 2006
  199.30 + */
  199.31 + 
  199.32 +/* Emulator for BSD scandir() call
  199.33 + * Accepts: directory name
  199.34 + *	    destination pointer of names array
  199.35 + *	    selection function
  199.36 + *	    comparison function
  199.37 + * Returns: number of elements in the array or -1 if error
  199.38 + */
  199.39 +
  199.40 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  199.41 +	     compar_t compar)
  199.42 +{
  199.43 +  struct direct *p,*d,**names;
  199.44 +  int nitems;
  199.45 +  struct stat stb;
  199.46 +  long nlmax;
  199.47 +  DIR *dirp = opendir (dirname);/* open directory and get status poop */
  199.48 +  if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
  199.49 +  nlmax = stb.st_size / 24;	/* guesstimate at number of files */
  199.50 +  names = (struct direct **) fs_get (nlmax * sizeof (struct direct *));
  199.51 +  nitems = 0;			/* initially none found */
  199.52 +  while (d = readdir (dirp)) {	/* read directory item */
  199.53 +				/* matches select criterion? */
  199.54 +    if (select && !(*select) (d)) continue;
  199.55 +				/* get size of direct record for this file */
  199.56 +    p = (struct direct *) fs_get (DIR_SIZE (d));
  199.57 +    p->d_ino = d->d_ino;	/* copy the poop */
  199.58 +    strcpy (p->d_name,d->d_name);
  199.59 +    if (++nitems >= nlmax) {	/* if out of space, try bigger guesstimate */
  199.60 +      void *s = (void *) names;	/* stupid language */
  199.61 +      nlmax *= 2;		/* double it */
  199.62 +      fs_resize ((void **) &s,nlmax * sizeof (struct direct *));
  199.63 +      names = (struct direct **) s;
  199.64 +    }
  199.65 +    names[nitems - 1] = p;	/* store this file there */
  199.66 +  }
  199.67 +  closedir (dirp);		/* done with directory */
  199.68 +				/* sort if necessary */
  199.69 +  if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar);
  199.70 +  *namelist = names;		/* return directory */
  199.71 +  return nitems;		/* and size */
  199.72 +}
  199.73 +
  199.74 +/* Alphabetic file name comparision
  199.75 + * Accepts: first candidate directory entry
  199.76 + *	    second candidate directory entry
  199.77 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
  199.78 + */
  199.79 +
  199.80 +int alphasort (void *d1,void *d2)
  199.81 +{
  199.82 +  return strcmp ((*(struct direct **) d1)->d_name,
  199.83 +		 (*(struct direct **) d2)->d_name);
  199.84 +}
   200.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   200.2 +++ b/src/osdep/amiga/ssl_none.c	Mon Sep 14 15:17:45 2009 +0900
   200.3 @@ -0,0 +1,141 @@
   200.4 +/* ========================================================================
   200.5 + * Copyright 1988-2006 University of Washington
   200.6 + *
   200.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   200.8 + * you may not use this file except in compliance with the License.
   200.9 + * You may obtain a copy of the License at
  200.10 + *
  200.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  200.12 + *
  200.13 + * 
  200.14 + * ========================================================================
  200.15 + */
  200.16 +
  200.17 +/*
  200.18 + * Program:	Dummy (no SSL) authentication/encryption module
  200.19 + *
  200.20 + * Author:	Mark Crispin
  200.21 + *		Networks and Distributed Computing
  200.22 + *		Computing & Communications
  200.23 + *		University of Washington
  200.24 + *		Administration Building, AG-44
  200.25 + *		Seattle, WA  98195
  200.26 + *		Internet: MRC@CAC.Washington.EDU
  200.27 + *
  200.28 + * Date:	7 February 2001
  200.29 + * Last Edited:	30 August 2006
  200.30 + */
  200.31 +
  200.32 +/* Init server for SSL
  200.33 + * Accepts: server name
  200.34 + */
  200.35 +
  200.36 +void ssl_server_init (char *server)
  200.37 +{
  200.38 +  syslog (LOG_ERR,"This server does not support SSL");
  200.39 +  exit (1);			/* punt this program too */
  200.40 +}
  200.41 +
  200.42 +
  200.43 +/* Start TLS
  200.44 + * Accepts: /etc/services service name
  200.45 + * Returns: cpystr'd error string if TLS failed, else NIL for success
  200.46 + */
  200.47 +
  200.48 +char *ssl_start_tls (char *server)
  200.49 +{
  200.50 +  return cpystr ("This server does not support TLS");
  200.51 +}
  200.52 +
  200.53 +/* Get character
  200.54 + * Returns: character or EOF
  200.55 + */
  200.56 +
  200.57 +int PBIN (void)
  200.58 +{
  200.59 +  return getchar ();
  200.60 +}
  200.61 +
  200.62 +
  200.63 +/* Get string
  200.64 + * Accepts: destination string pointer
  200.65 + *	    number of bytes available
  200.66 + * Returns: destination string pointer or NIL if EOF
  200.67 + */
  200.68 +
  200.69 +char *PSIN (char *s,int n)
  200.70 +{
  200.71 +  return fgets (s,n,stdin);
  200.72 +}
  200.73 +
  200.74 +
  200.75 +/* Get record
  200.76 + * Accepts: destination string pointer
  200.77 + *	    number of bytes to read
  200.78 + * Returns: T if success, NIL otherwise
  200.79 + */
  200.80 +
  200.81 +long PSINR (char *s,unsigned long n)
  200.82 +{
  200.83 +  unsigned long i;
  200.84 +  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
  200.85 +  return n ? NIL : LONGT;
  200.86 +}
  200.87 +
  200.88 +
  200.89 +/* Wait for input
  200.90 + * Accepts: timeout in seconds
  200.91 + * Returns: T if have input on stdin, else NIL
  200.92 + */
  200.93 +
  200.94 +long INWAIT (long seconds)
  200.95 +{
  200.96 +  return server_input_wait (seconds);
  200.97 +}
  200.98 +
  200.99 +/* Put character
 200.100 + * Accepts: character
 200.101 + * Returns: character written or EOF
 200.102 + */
 200.103 +
 200.104 +int PBOUT (int c)
 200.105 +{
 200.106 +  return putchar (c);
 200.107 +}
 200.108 +
 200.109 +
 200.110 +/* Put string
 200.111 + * Accepts: source string pointer
 200.112 + * Returns: 0 or EOF if error
 200.113 + */
 200.114 +
 200.115 +int PSOUT (char *s)
 200.116 +{
 200.117 +  return fputs (s,stdout);
 200.118 +}
 200.119 +
 200.120 +
 200.121 +/* Put record
 200.122 + * Accepts: source sized text
 200.123 + * Returns: 0 or EOF if error
 200.124 + */
 200.125 +
 200.126 +int PSOUTR (SIZEDTEXT *s)
 200.127 +{
 200.128 +  unsigned char *t;
 200.129 +  unsigned long i,j;
 200.130 +  for (t = s->data,i = s->size;
 200.131 +       (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)));
 200.132 +       t += j,i -= j);
 200.133 +  return i ? EOF : NIL;
 200.134 +}
 200.135 +
 200.136 +
 200.137 +/* Flush output
 200.138 + * Returns: 0 or EOF if error
 200.139 + */
 200.140 +
 200.141 +int PFLUSH (void)
 200.142 +{
 200.143 +  return fflush (stdout);
 200.144 +}
   201.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   201.2 +++ b/src/osdep/amiga/tcp_ami.c	Mon Sep 14 15:17:45 2009 +0900
   201.3 @@ -0,0 +1,797 @@
   201.4 +/* ========================================================================
   201.5 + * Copyright 1988-2008 University of Washington
   201.6 + *
   201.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   201.8 + * you may not use this file except in compliance with the License.
   201.9 + * You may obtain a copy of the License at
  201.10 + *
  201.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  201.12 + *
  201.13 + * 
  201.14 + * ========================================================================
  201.15 + */
  201.16 +
  201.17 +/*
  201.18 + * Program:	Amiga TCP/IP routines
  201.19 + *
  201.20 + * Author:	Mark Crispin
  201.21 + *		Networks and Distributed Computing
  201.22 + *		Computing & Communications
  201.23 + *		University of Washington
  201.24 + *		Administration Building, AG-44
  201.25 + *		Seattle, WA  98195
  201.26 + *		Internet: MRC@CAC.Washington.EDU
  201.27 + *
  201.28 + * Date:	1 August 1988
  201.29 + * Last Edited:	13 January 2008
  201.30 + */
  201.31 +
  201.32 +#undef write			/* don't use redefined write() */
  201.33 + 
  201.34 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  201.35 +static long ttmo_open = 0;	/* TCP timeouts, in seconds */
  201.36 +static long ttmo_read = 0;
  201.37 +static long ttmo_write = 0;
  201.38 +static long allowreversedns = T;/* allow reverse DNS lookup */
  201.39 +static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
  201.40 +
  201.41 +extern long maxposint;		/* get this from write.c */
  201.42 +
  201.43 +/* Local function prototypes */
  201.44 +
  201.45 +int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst,
  201.46 +		     unsigned long port);
  201.47 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  201.48 +			       long *contd);
  201.49 +long tcp_abort (TCPSTREAM *stream);
  201.50 +char *tcp_name (struct sockaddr_in *sin,long flag);
  201.51 +char *tcp_name_valid (char *s);
  201.52 +
  201.53 +/* TCP/IP manipulate parameters
  201.54 + * Accepts: function code
  201.55 + *	    function-dependent value
  201.56 + * Returns: function-dependent return value
  201.57 + */
  201.58 +
  201.59 +void *tcp_parameters (long function,void *value)
  201.60 +{
  201.61 +  void *ret = NIL;
  201.62 +  switch ((int) function) {
  201.63 +  case SET_TIMEOUT:
  201.64 +    tmoh = (tcptimeout_t) value;
  201.65 +  case GET_TIMEOUT:
  201.66 +    ret = (void *) tmoh;
  201.67 +    break;
  201.68 +  case SET_OPENTIMEOUT:
  201.69 +    ttmo_open = (long) value;
  201.70 +  case GET_OPENTIMEOUT:
  201.71 +    ret = (void *) ttmo_open;
  201.72 +    break;
  201.73 +  case SET_READTIMEOUT:
  201.74 +    ttmo_read = (long) value;
  201.75 +  case GET_READTIMEOUT:
  201.76 +    ret = (void *) ttmo_read;
  201.77 +    break;
  201.78 +  case SET_WRITETIMEOUT:
  201.79 +    ttmo_write = (long) value;
  201.80 +  case GET_WRITETIMEOUT:
  201.81 +    ret = (void *) ttmo_write;
  201.82 +    break;
  201.83 +  case SET_ALLOWREVERSEDNS:
  201.84 +    allowreversedns = (long) value;
  201.85 +  case GET_ALLOWREVERSEDNS:
  201.86 +    ret = (void *) allowreversedns;
  201.87 +    break;
  201.88 +  case SET_TCPDEBUG:
  201.89 +    tcpdebug = (long) value;
  201.90 +  case GET_TCPDEBUG:
  201.91 +    ret = (void *) tcpdebug;
  201.92 +    break;
  201.93 +  }
  201.94 +  return ret;
  201.95 +}
  201.96 +
  201.97 +/* TCP/IP open
  201.98 + * Accepts: host name
  201.99 + *	    contact service name
 201.100 + *	    contact port number and optional silent flag
 201.101 + * Returns: TCP/IP stream if success else NIL
 201.102 + */
 201.103 +
 201.104 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
 201.105 +{
 201.106 +  TCPSTREAM *stream = NIL;
 201.107 +  int i;
 201.108 +  int sock = -1;
 201.109 +  int ctr = 0;
 201.110 +  int silent = (port & NET_SILENT) ? T : NIL;
 201.111 +  int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr;
 201.112 +  char *s;
 201.113 +  struct sockaddr_in sin;
 201.114 +  struct hostent *he;
 201.115 +  char hostname[MAILTMPLEN];
 201.116 +  char tmp[MAILTMPLEN];
 201.117 +  struct servent *sv = NIL;
 201.118 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.119 +  void *data;
 201.120 +  port &= 0xffff;		/* erase flags */
 201.121 +				/* lookup service */
 201.122 +  if (service && (sv = getservbyname (service,"tcp")))
 201.123 +    port = ntohs (sin.sin_port = sv->s_port);
 201.124 + 				/* copy port number in network format */
 201.125 +  else sin.sin_port = htons (port);
 201.126 +  /* The domain literal form is used (rather than simply the dotted decimal
 201.127 +     as with other Amiga programs) because it has to be a valid "host name"
 201.128 +     in mailsystem terminology. */
 201.129 +				/* look like domain literal? */
 201.130 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
 201.131 +    strcpy (hostname,host+1);	/* yes, copy number part */
 201.132 +    hostname[(strlen (hostname))-1] = '\0';
 201.133 +    if ((sin.sin_addr.s_addr = inet_addr (hostname)) == -1)
 201.134 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
 201.135 +    else {
 201.136 +      sin.sin_family = AF_INET;	/* family is always Internet */
 201.137 +      strcpy (hostname,host);	/* hostname is user's argument */
 201.138 +      (*bn) (BLOCK_TCPOPEN,NIL);
 201.139 +				/* get an open socket for this system */
 201.140 +      sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port);
 201.141 +      (*bn) (BLOCK_NONE,NIL);
 201.142 +    }
 201.143 +  }
 201.144 +
 201.145 +  else {			/* lookup host name */
 201.146 +    if (tcpdebug) {
 201.147 +      sprintf (tmp,"DNS resolution %.80s",host);
 201.148 +      mm_log (tmp,TCPDEBUG);
 201.149 +    }
 201.150 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 201.151 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
 201.152 +    if (!(he = gethostbyname (lcase (strcpy (hostname,host)))))
 201.153 +      sprintf (tmp,"No such host as %.80s",host);
 201.154 +    (*bn) (BLOCK_NONSENSITIVE,data);
 201.155 +    (*bn) (BLOCK_NONE,NIL);
 201.156 +    if (he) {			/* DNS resolution won? */
 201.157 +      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
 201.158 +				/* copy address type */
 201.159 +      sin.sin_family = he->h_addrtype;
 201.160 +				/* copy host name */
 201.161 +      strcpy (hostname,he->h_name);
 201.162 +#ifdef HOST_NOT_FOUND		/* muliple addresses only on DNS systems */
 201.163 +      for (sock = -1,i = 0; (sock < 0) && (s = he->h_addr_list[i]); i++) {
 201.164 +	if (i && !silent) mm_log (tmp,WARN);
 201.165 +	memcpy (&sin.sin_addr,s,he->h_length);
 201.166 +	(*bn) (BLOCK_TCPOPEN,NIL);
 201.167 +	sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port);
 201.168 +	(*bn) (BLOCK_NONE,NIL);
 201.169 +      }
 201.170 +#else				/* the one true address then */
 201.171 +      memcpy (&sin.sin_addr,he->h_addr,he->h_length);
 201.172 +      (*bn) (BLOCK_TCPOPEN,NIL);
 201.173 +      sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port);
 201.174 +      (*bn) (BLOCK_NONE,NIL);
 201.175 +#endif
 201.176 +    }
 201.177 +  }
 201.178 +  if (sock >= 0)  {		/* won */
 201.179 +    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
 201.180 +				   sizeof (TCPSTREAM));
 201.181 +    stream->port = port;	/* port number */
 201.182 +				/* init sockets */
 201.183 +    stream->tcpsi = stream->tcpso = sock;
 201.184 +				/* stash in the snuck-in byte */
 201.185 +    if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0];
 201.186 +				/* copy official host name */
 201.187 +    stream->host = cpystr (hostname);
 201.188 +    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
 201.189 +  }
 201.190 +  else if (!silent) mm_log (tmp,ERROR);
 201.191 +  return stream;		/* return success */
 201.192 +}
 201.193 +
 201.194 +/* Open a TCP socket
 201.195 + * Accepts: Internet socket address block
 201.196 + *	    scratch buffer
 201.197 + *	    pointer to "first byte read in" storage or NIL
 201.198 + *	    host name for error message
 201.199 + *	    port number for error message
 201.200 + * Returns: socket if success, else -1 with error string in scratch buffer
 201.201 + */
 201.202 +
 201.203 +int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst,
 201.204 +		     unsigned long port)
 201.205 +{
 201.206 +  int i,ti,sock,flgs;
 201.207 +  time_t now;
 201.208 +  struct protoent *pt = getprotobyname ("tcp");
 201.209 +  fd_set fds,efds;
 201.210 +  struct timeval tmo;
 201.211 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.212 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
 201.213 +  sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
 201.214 +  mm_log (tmp,NIL);
 201.215 +				/* make a socket */
 201.216 +  if ((sock = socket (sin->sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
 201.217 +    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
 201.218 +    (*bn) (BLOCK_NONSENSITIVE,data);
 201.219 +    return -1;
 201.220 +  }
 201.221 +  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
 201.222 +    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
 201.223 +	     sock,FD_SETSIZE);
 201.224 +    (*bn) (BLOCK_NONSENSITIVE,data);
 201.225 +    close (sock);
 201.226 +    errno = EMFILE;
 201.227 +    return -1;
 201.228 +  }
 201.229 +  flgs = fcntl (sock,F_GETFL,0);/* get current socket flags */
 201.230 +				/* set non-blocking if want open timeout */
 201.231 +  if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY);
 201.232 +				/* open connection */
 201.233 +  while ((i = connect (sock,(struct sockaddr *) sin,
 201.234 +		       sizeof (struct sockaddr_in))) < 0 && (errno == EINTR));
 201.235 +  (*bn) (BLOCK_NONSENSITIVE,data);
 201.236 +  if (i < 0) switch (errno) {	/* failed? */
 201.237 +  case EAGAIN:			/* DG brain damage */
 201.238 +  case EINPROGRESS:		/* what we expect to happen */
 201.239 +  case EALREADY:		/* or another form of it */
 201.240 +  case EISCONN:			/* restart after interrupt? */
 201.241 +  case EADDRINUSE:		/* restart after interrupt? */
 201.242 +    break;			/* well, not really, it was interrupted */
 201.243 +  default:
 201.244 +    sprintf (tmp,"Can't connect to %.80s,%lu: %s",hst,port,strerror (errno));
 201.245 +    close (sock);		/* flush socket */
 201.246 +    return -1;
 201.247 +  }
 201.248 +
 201.249 +  if (ctr) {			/* want open timeout */
 201.250 +    now = time (0);		/* open timeout */
 201.251 +    ti = ttmo_open ? now + ttmo_open : 0;
 201.252 +    tmo.tv_usec = 0;
 201.253 +    FD_ZERO (&fds);		/* initialize selection vector */
 201.254 +    FD_ZERO (&efds);		/* handle errors too */
 201.255 +    FD_SET (sock,&fds);		/* block for error or readable */
 201.256 +    FD_SET (sock,&efds);
 201.257 +    do {			/* block under timeout */
 201.258 +      tmo.tv_sec = ti ? ti - now : 0;
 201.259 +      i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);
 201.260 +      now = time (0);		/* fake timeout if interrupt & time expired */
 201.261 +      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 201.262 +    } while ((i < 0) && (errno == EINTR));
 201.263 +    if (i > 0) {		/* success, make sure really connected */
 201.264 +      fcntl (sock,F_SETFL,flgs);/* restore blocking status */
 201.265 +      /* This used to be a zero-byte read(), but that crashes Solaris */
 201.266 +				/* get socket status */
 201.267 +      while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR));
 201.268 +    }	
 201.269 +    if (i <= 0) {		/* timeout or error? */
 201.270 +      i = i ? errno : ETIMEDOUT;/* determine error code */
 201.271 +      close (sock);		/* flush socket */
 201.272 +      errno = i;		/* return error code */
 201.273 +      sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst,port,
 201.274 +	       strerror (errno));
 201.275 +      return -1;
 201.276 +    }
 201.277 +  }
 201.278 +  return sock;			/* return the socket */
 201.279 +}
 201.280 +  
 201.281 +/* TCP/IP authenticated open
 201.282 + * Accepts: host name
 201.283 + *	    service name
 201.284 + *	    returned user name buffer
 201.285 + * Returns: TCP/IP stream if success else NIL
 201.286 + */
 201.287 +
 201.288 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 201.289 +{
 201.290 +  return NIL;			/* disabled */
 201.291 +}
 201.292 +
 201.293 +/* TCP receive line
 201.294 + * Accepts: TCP stream
 201.295 + * Returns: text line string or NIL if failure
 201.296 + */
 201.297 +
 201.298 +char *tcp_getline (TCPSTREAM *stream)
 201.299 +{
 201.300 +  unsigned long n,contd;
 201.301 +  char *ret = tcp_getline_work (stream,&n,&contd);
 201.302 +  if (ret && contd) {		/* got a line needing continuation? */
 201.303 +    STRINGLIST *stl = mail_newstringlist ();
 201.304 +    STRINGLIST *stc = stl;
 201.305 +    do {			/* collect additional lines */
 201.306 +      stc->text.data = (unsigned char *) ret;
 201.307 +      stc->text.size = n;
 201.308 +      stc = stc->next = mail_newstringlist ();
 201.309 +      ret = tcp_getline_work (stream,&n,&contd);
 201.310 +    } while (ret && contd);
 201.311 +    if (ret) {			/* stash final part of line on list */
 201.312 +      stc->text.data = (unsigned char *) ret;
 201.313 +      stc->text.size = n;
 201.314 +				/* determine how large a buffer we need */
 201.315 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 201.316 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 201.317 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 201.318 +	memcpy (ret + n,stc->text.data,stc->text.size);
 201.319 +      ret[n] = '\0';
 201.320 +    }
 201.321 +    mail_free_stringlist (&stl);/* either way, done with list */
 201.322 +  }
 201.323 +  return ret;
 201.324 +}
 201.325 +
 201.326 +/* TCP receive line or partial line
 201.327 + * Accepts: TCP stream
 201.328 + *	    pointer to return size
 201.329 + *	    pointer to return continuation flag
 201.330 + * Returns: text line string, size and continuation flag, or NIL if failure
 201.331 + */
 201.332 +
 201.333 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 201.334 +			       long *contd)
 201.335 +{
 201.336 +  unsigned long n;
 201.337 +  char *s,*ret,c,d;
 201.338 +  *contd = NIL;			/* assume no continuation */
 201.339 +				/* make sure have data */
 201.340 +  if (!tcp_getdata (stream)) return NIL;
 201.341 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 201.342 +    d = *stream->iptr++;	/* slurp another character */
 201.343 +    if ((c == '\015') && (d == '\012')) {
 201.344 +      ret = (char *) fs_get (n--);
 201.345 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 201.346 +      ret[n] = '\0';		/* tie off string with null */
 201.347 +      return ret;
 201.348 +    }
 201.349 +  }
 201.350 +				/* copy partial string from buffer */
 201.351 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 201.352 +				/* get more data from the net */
 201.353 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 201.354 +				/* special case of newline broken by buffer */
 201.355 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 201.356 +    stream->iptr++;		/* eat the line feed */
 201.357 +    stream->ictr--;
 201.358 +    ret[*size = --n] = '\0';	/* tie off string with null */
 201.359 +  }
 201.360 +  else *contd = LONGT;		/* continuation needed */
 201.361 +  return ret;
 201.362 +}
 201.363 +
 201.364 +/* TCP/IP receive buffer
 201.365 + * Accepts: TCP/IP stream
 201.366 + *	    size in bytes
 201.367 + *	    buffer to read into
 201.368 + * Returns: T if success, NIL otherwise
 201.369 + */
 201.370 +
 201.371 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
 201.372 +{
 201.373 +  unsigned long n;
 201.374 +				/* make sure socket still alive */
 201.375 +  if (stream->tcpsi < 0) return NIL;
 201.376 +				/* can transfer bytes from buffer? */
 201.377 +  if (n = min (size,stream->ictr)) {
 201.378 +    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
 201.379 +    s += n;			/* update pointer */
 201.380 +    stream->iptr +=n;
 201.381 +    size -= n;			/* update # of bytes to do */
 201.382 +    stream->ictr -=n;
 201.383 +  }
 201.384 +  if (size) {
 201.385 +    int i;
 201.386 +    fd_set fds,efds;
 201.387 +    struct timeval tmo;
 201.388 +    time_t t = time (0);
 201.389 +    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.390 +    (*bn) (BLOCK_TCPREAD,NIL);
 201.391 +    while (size > 0) {		/* until request satisfied */
 201.392 +      time_t tl = time (0);
 201.393 +      time_t now = tl;
 201.394 +      time_t ti = ttmo_read ? now + ttmo_read : 0;
 201.395 +      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
 201.396 +      tmo.tv_usec = 0;
 201.397 +      FD_ZERO (&fds);		/* initialize selection vector */
 201.398 +      FD_ZERO (&efds);		/* handle errors too */
 201.399 +      FD_SET (stream->tcpsi,&fds);
 201.400 +      FD_SET (stream->tcpsi,&efds);
 201.401 +      errno = NIL;		/* block and read */
 201.402 +      do {			/* block under timeout */
 201.403 +	tmo.tv_sec = ti ? ti - now : 0;
 201.404 +	i = select (stream->tcpsi+1,&fds,0,&efds,ti ? &tmo : 0);
 201.405 +	now = time (0);		/* fake timeout if interrupt & time expired */
 201.406 +	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 201.407 +      } while ((i < 0) && (errno == EINTR));
 201.408 +      if (i > 0) {		/* select says there's data to read? */
 201.409 +	while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) &&
 201.410 +	       (errno == EINTR));
 201.411 +	if (i < 1) return tcp_abort (stream);
 201.412 +	s += i;			/* point at new place to write */
 201.413 +	size -= i;		/* reduce byte count */
 201.414 +	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
 201.415 +      }
 201.416 +      else if (i || !tmoh || !(*tmoh) (now - t,now - tl))
 201.417 +	return tcp_abort (stream);
 201.418 +    }
 201.419 +    (*bn) (BLOCK_NONE,NIL);
 201.420 +  }
 201.421 +  *s = '\0';			/* tie off string */
 201.422 +  return T;
 201.423 +}
 201.424 +
 201.425 +/* TCP/IP receive data
 201.426 + * Accepts: TCP/IP stream
 201.427 + * Returns: T if success, NIL otherwise
 201.428 + */
 201.429 +
 201.430 +long tcp_getdata (TCPSTREAM *stream)
 201.431 +{
 201.432 +  int i;
 201.433 +  fd_set fds,efds;
 201.434 +  struct timeval tmo;
 201.435 +  time_t t = time (0);
 201.436 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.437 +  if (stream->tcpsi < 0) return NIL;
 201.438 +  (*bn) (BLOCK_TCPREAD,NIL);
 201.439 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 201.440 +    time_t tl = time (0);	/* start of request */
 201.441 +    time_t now = tl;
 201.442 +    time_t ti = ttmo_read ? now + ttmo_read : 0;
 201.443 +    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
 201.444 +    tmo.tv_usec = 0;
 201.445 +    FD_ZERO (&fds);		/* initialize selection vector */
 201.446 +    FD_ZERO (&efds);		/* handle errors too */
 201.447 +    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
 201.448 +    FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */
 201.449 +    errno = NIL;		/* block and read */
 201.450 +    do {			/* block under timeout */
 201.451 +      tmo.tv_sec = ti ? ti - now : 0;
 201.452 +      i = select (stream->tcpsi+1,&fds,0,&efds,ti ? &tmo : 0);
 201.453 +      now = time (0);		/* fake timeout if interrupt & time expired */
 201.454 +      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 201.455 +    } while ((i < 0) && (errno == EINTR));
 201.456 +    if (i > 0) {		/* got data? */
 201.457 +      while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
 201.458 +	     (errno == EINTR));
 201.459 +      if (i < 1) return tcp_abort (stream);
 201.460 +      stream->iptr = stream->ibuf;/* point at TCP buffer */
 201.461 +      stream->ictr = i;		/* set new byte count */
 201.462 +      if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
 201.463 +    }
 201.464 +    else if (i || !tmoh || !(*tmoh) (now - t,now - tl))
 201.465 +      return tcp_abort (stream);/* error or timeout no-continue */
 201.466 +  }
 201.467 +  (*bn) (BLOCK_NONE,NIL);
 201.468 +  return T;
 201.469 +}
 201.470 +
 201.471 +/* TCP/IP send string as record
 201.472 + * Accepts: TCP/IP stream
 201.473 + *	    string pointer
 201.474 + * Returns: T if success else NIL
 201.475 + */
 201.476 +
 201.477 +long tcp_soutr (TCPSTREAM *stream,char *string)
 201.478 +{
 201.479 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 201.480 +}
 201.481 +
 201.482 +
 201.483 +/* TCP/IP send string
 201.484 + * Accepts: TCP/IP stream
 201.485 + *	    string pointer
 201.486 + *	    byte count
 201.487 + * Returns: T if success else NIL
 201.488 + */
 201.489 +
 201.490 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 201.491 +{
 201.492 +  int i;
 201.493 +  fd_set fds,efds;
 201.494 +  struct timeval tmo;
 201.495 +  time_t t = time (0);
 201.496 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.497 +  if (stream->tcpso < 0) return NIL;
 201.498 +  (*bn) (BLOCK_TCPWRITE,NIL);
 201.499 +  while (size > 0) {		/* until request satisfied */
 201.500 +    time_t tl = time (0);	/* start of request */
 201.501 +    time_t now = tl;
 201.502 +    time_t ti = ttmo_write ? now + ttmo_write : 0;
 201.503 +    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
 201.504 +    tmo.tv_usec = 0;
 201.505 +    FD_ZERO (&fds);		/* initialize selection vector */
 201.506 +    FD_ZERO (&efds);		/* handle errors too */
 201.507 +    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
 201.508 +    FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */
 201.509 +    errno = NIL;		/* block and write */
 201.510 +    do {			/* block under timeout */
 201.511 +      tmo.tv_sec = ti ? ti - now : 0;
 201.512 +      i = select (stream->tcpso+1,0,&fds,&efds,ti ? &tmo : 0);
 201.513 +      now = time (0);		/* fake timeout if interrupt & time expired */
 201.514 +      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 201.515 +    } while ((i < 0) && (errno == EINTR));
 201.516 +    if (i > 0) {		/* OK to send data? */
 201.517 +      while (((i = write (stream->tcpso,string,size)) < 0) &&(errno == EINTR));
 201.518 +      if (i < 0) return tcp_abort (stream);
 201.519 +      size -= i;		/* how much we sent */
 201.520 +      string += i;
 201.521 +      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
 201.522 +    }
 201.523 +    else if (i || !tmoh || !(*tmoh) (now - t,now - tl))
 201.524 +      return tcp_abort (stream);/* error or timeout no-continue */
 201.525 +  }
 201.526 +  (*bn) (BLOCK_NONE,NIL);
 201.527 +  return T;			/* all done */
 201.528 +}
 201.529 +
 201.530 +/* TCP/IP close
 201.531 + * Accepts: TCP/IP stream
 201.532 + */
 201.533 +
 201.534 +void tcp_close (TCPSTREAM *stream)
 201.535 +{
 201.536 +  tcp_abort (stream);		/* nuke the stream */
 201.537 +				/* flush host names */
 201.538 +  if (stream->host) fs_give ((void **) &stream->host);
 201.539 +  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
 201.540 +  if (stream->localhost) fs_give ((void **) &stream->localhost);
 201.541 +  fs_give ((void **) &stream);	/* flush the stream */
 201.542 +}
 201.543 +
 201.544 +
 201.545 +/* TCP/IP abort stream
 201.546 + * Accepts: TCP/IP stream
 201.547 + * Returns: NIL always
 201.548 + */
 201.549 +
 201.550 +long tcp_abort (TCPSTREAM *stream)
 201.551 +{
 201.552 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.553 +  if (stream->tcpsi >= 0) {	/* no-op if no socket */
 201.554 +    (*bn) (BLOCK_TCPCLOSE,NIL);
 201.555 +    close (stream->tcpsi);	/* nuke the socket */
 201.556 +    if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
 201.557 +    stream->tcpsi = stream->tcpso = -1;
 201.558 +  }
 201.559 +  (*bn) (BLOCK_NONE,NIL);
 201.560 +  return NIL;
 201.561 +}
 201.562 +
 201.563 +/* TCP/IP get host name
 201.564 + * Accepts: TCP/IP stream
 201.565 + * Returns: host name for this stream
 201.566 + */
 201.567 +
 201.568 +char *tcp_host (TCPSTREAM *stream)
 201.569 +{
 201.570 +  return stream->host;		/* use tcp_remotehost() if want guarantees */
 201.571 +}
 201.572 +
 201.573 +
 201.574 +/* TCP/IP get remote host name
 201.575 + * Accepts: TCP/IP stream
 201.576 + * Returns: host name for this stream
 201.577 + */
 201.578 +
 201.579 +char *tcp_remotehost (TCPSTREAM *stream)
 201.580 +{
 201.581 +  if (!stream->remotehost) {
 201.582 +    struct sockaddr_in sin;
 201.583 +    int sinlen = sizeof (struct sockaddr_in);
 201.584 +    stream->remotehost =	/* get socket's peer name */
 201.585 +      (getpeername (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) ||
 201.586 +       (sin.sin_family != AF_INET)) ?
 201.587 +	 cpystr (stream->host) : tcp_name (&sin,NIL);
 201.588 +  }
 201.589 +  return stream->remotehost;
 201.590 +}
 201.591 +
 201.592 +
 201.593 +/* TCP/IP return port for this stream
 201.594 + * Accepts: TCP/IP stream
 201.595 + * Returns: port number for this stream
 201.596 + */
 201.597 +
 201.598 +unsigned long tcp_port (TCPSTREAM *stream)
 201.599 +{
 201.600 +  return stream->port;		/* return port number */
 201.601 +}
 201.602 +
 201.603 +
 201.604 +/* TCP/IP get local host name
 201.605 + * Accepts: TCP/IP stream
 201.606 + * Returns: local host name
 201.607 + */
 201.608 +
 201.609 +char *tcp_localhost (TCPSTREAM *stream)
 201.610 +{
 201.611 +  if (!stream->localhost) {
 201.612 +    struct sockaddr_in sin;
 201.613 +    int sinlen = sizeof (struct sockaddr_in);
 201.614 +    stream->localhost =		/* get socket's name */
 201.615 +      ((stream->port & 0xffff000) ||
 201.616 +       getsockname (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) ||
 201.617 +       (sin.sin_family != AF_INET)) ?
 201.618 +	 cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
 201.619 +  }
 201.620 +  return stream->localhost;	/* return local host name */
 201.621 +}
 201.622 +
 201.623 +/* TCP/IP get client host address (server calls only)
 201.624 + * Returns: client host address
 201.625 + */
 201.626 +
 201.627 +static char *myClientAddr = NIL;
 201.628 +
 201.629 +char *tcp_clientaddr ()
 201.630 +{
 201.631 +  if (!myClientAddr) {
 201.632 +    struct sockaddr_in sin;
 201.633 +    int sinlen = sizeof (struct sockaddr_in);
 201.634 +    myClientAddr =		/* get stdin's peer name */
 201.635 +      cpystr (getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
 201.636 +	      "UNKNOWN" : ((sin.sin_family == AF_INET) ?
 201.637 +			   inet_ntoa (sin.sin_addr) : "NON-IPv4"));
 201.638 +  }
 201.639 +  return myClientAddr;
 201.640 +}
 201.641 +
 201.642 +
 201.643 +/* TCP/IP get client host name (server calls only)
 201.644 + * Returns: client host name
 201.645 + */
 201.646 +
 201.647 +static char *myClientHost = NIL;
 201.648 +
 201.649 +char *tcp_clienthost ()
 201.650 +{
 201.651 +  if (!myClientHost) {
 201.652 +    struct sockaddr_in sin;
 201.653 +    int sinlen = sizeof (struct sockaddr_in);
 201.654 +    myClientHost =		/* get stdin's peer name */
 201.655 +      getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
 201.656 +	cpystr ("UNKNOWN") : ((sin.sin_family == AF_INET) ?
 201.657 +			      tcp_name (&sin,T) : cpystr ("NON-IPv4"));
 201.658 +  }
 201.659 +  return myClientHost;
 201.660 +}
 201.661 +
 201.662 +/* TCP/IP get server host address (server calls only)
 201.663 + * Returns: server host address
 201.664 + */
 201.665 +
 201.666 +static char *myServerAddr = NIL;
 201.667 +
 201.668 +char *tcp_serveraddr ()
 201.669 +{
 201.670 +  if (!myServerAddr) {
 201.671 +    struct sockaddr_in sin;
 201.672 +    int sinlen = sizeof (struct sockaddr_in);
 201.673 +    myServerAddr =		/* get stdin's peer name */
 201.674 +      cpystr (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
 201.675 +	      "UNKNOWN" : ((sin.sin_family == AF_INET) ?
 201.676 +			   inet_ntoa (sin.sin_addr) : "NON-IPv4"));
 201.677 +  }
 201.678 +  return myServerAddr;
 201.679 +}
 201.680 +
 201.681 +
 201.682 +/* TCP/IP get server host name (server calls only)
 201.683 + * Returns: server host name
 201.684 + */
 201.685 +
 201.686 +static char *myServerHost = NIL;
 201.687 +static long myServerPort = -1;
 201.688 +
 201.689 +char *tcp_serverhost ()
 201.690 +{
 201.691 +  if (!myServerHost) {
 201.692 +    struct sockaddr_in sin;
 201.693 +    int sinlen = sizeof (struct sockaddr_in);
 201.694 +				/* get stdin's name */
 201.695 +    if (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) ||
 201.696 +	(sin.sin_family != AF_INET)) myServerHost = cpystr (mylocalhost ());
 201.697 +    else {
 201.698 +      myServerHost = tcp_name (&sin,NIL);
 201.699 +      myServerPort = ntohs (sin.sin_port);
 201.700 +    }
 201.701 +  }
 201.702 +  return myServerHost;
 201.703 +}
 201.704 +
 201.705 +
 201.706 +/* TCP/IP get server port number (server calls only)
 201.707 + * Returns: server port number
 201.708 + */
 201.709 +
 201.710 +long tcp_serverport ()
 201.711 +{
 201.712 +  if (!myServerHost) tcp_serverhost ();
 201.713 +  return myServerPort;
 201.714 +}
 201.715 +
 201.716 +/* TCP/IP return canonical form of host name
 201.717 + * Accepts: host name
 201.718 + * Returns: canonical form of host name
 201.719 + */
 201.720 +
 201.721 +char *tcp_canonical (char *name)
 201.722 +{
 201.723 +  char *ret,host[MAILTMPLEN];
 201.724 +  struct hostent *he;
 201.725 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 201.726 +  void *data;
 201.727 +				/* look like domain literal? */
 201.728 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 201.729 +  (*bn) (BLOCK_DNSLOOKUP,NIL);	/* quell alarms */
 201.730 +  data = (*bn) (BLOCK_SENSITIVE,NIL);
 201.731 +  if (tcpdebug) {
 201.732 +    sprintf (host,"DNS canonicalization %.80s",name);
 201.733 +    mm_log (host,TCPDEBUG);
 201.734 +  }
 201.735 +				/* note that Amiga requires lowercase! */
 201.736 +  ret = (he = gethostbyname (lcase (strcpy (host,name)))) ?
 201.737 +    (char *) he->h_name : name;
 201.738 +  (*bn) (BLOCK_NONSENSITIVE,data);
 201.739 +  (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 201.740 +  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
 201.741 +  return ret;
 201.742 +}
 201.743 +
 201.744 +
 201.745 +/* TCP/IP return name from socket
 201.746 + * Accepts: socket
 201.747 + *	    verbose flag
 201.748 + * Returns: cpystr name
 201.749 + */
 201.750 +
 201.751 +char *tcp_name (struct sockaddr_in *sin,long flag)
 201.752 +{
 201.753 +  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
 201.754 +  sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
 201.755 +  if (allowreversedns) {
 201.756 +    struct hostent *he;
 201.757 +    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
 201.758 +    void *data;
 201.759 +    if (tcpdebug) {
 201.760 +      sprintf (tmp,"Reverse DNS resolution %s",adr);
 201.761 +      mm_log (tmp,TCPDEBUG);
 201.762 +    }
 201.763 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 201.764 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
 201.765 +				/* translate address to name */
 201.766 +    if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
 201.767 +						 sizeof (struct in_addr),
 201.768 +						 sin->sin_family)) ?
 201.769 +			    (char *) he->h_name : NIL)) {
 201.770 +				/* produce verbose form if needed */
 201.771 +      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
 201.772 +      else ret = t;
 201.773 +    }
 201.774 +    (*bn) (BLOCK_NONSENSITIVE,data);
 201.775 +    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 201.776 +    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
 201.777 +  }
 201.778 +  return cpystr (ret);
 201.779 +}
 201.780 +
 201.781 +
 201.782 +/* Validate name
 201.783 + * Accepts: domain name
 201.784 + * Returns: T if valid, NIL otherwise
 201.785 + */
 201.786 +
 201.787 +char *tcp_name_valid (char *s)
 201.788 +{
 201.789 +  int c;
 201.790 +  char *ret,*tail;
 201.791 +				/* must be non-empty and not too long */
 201.792 +  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
 201.793 +				/* must be alnum, dot, or hyphen */
 201.794 +    while ((c = *s++) && (s <= tail) &&
 201.795 +	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
 201.796 +	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
 201.797 +    if (c) ret = NIL;
 201.798 +  }
 201.799 +  return ret;
 201.800 +}
   202.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   202.2 +++ b/src/osdep/amiga/tcp_ami.h	Mon Sep 14 15:17:45 2009 +0900
   202.3 @@ -0,0 +1,48 @@
   202.4 +/* ========================================================================
   202.5 + * Copyright 1988-2006 University of Washington
   202.6 + *
   202.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   202.8 + * you may not use this file except in compliance with the License.
   202.9 + * You may obtain a copy of the License at
  202.10 + *
  202.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  202.12 + *
  202.13 + * 
  202.14 + * ========================================================================
  202.15 + */
  202.16 +
  202.17 +/*
  202.18 + * Program:	UNIX TCP/IP routines
  202.19 + *
  202.20 + * Author:	Mark Crispin
  202.21 + *		Networks and Distributed Computing
  202.22 + *		Computing & Communications
  202.23 + *		University of Washington
  202.24 + *		Administration Building, AG-44
  202.25 + *		Seattle, WA  98195
  202.26 + *		Internet: MRC@CAC.Washington.EDU
  202.27 + *
  202.28 + * Date:	1 August 1988
  202.29 + * Last Edited:	30 August 2006
  202.30 + */
  202.31 +
  202.32 +
  202.33 +/* TCP input buffer */
  202.34 +
  202.35 +#define BUFLEN 8192
  202.36 +
  202.37 +
  202.38 +/* TCP I/O stream */
  202.39 +
  202.40 +#define TCPSTREAM struct tcp_stream
  202.41 +TCPSTREAM {
  202.42 +  char *host;			/* host name */
  202.43 +  unsigned long port;		/* port number */
  202.44 +  char *localhost;		/* local host name */
  202.45 +  char *remotehost;		/* remote host name */
  202.46 +  int tcpsi;			/* input socket */
  202.47 +  int tcpso;			/* output socket */
  202.48 +  int ictr;			/* input counter */
  202.49 +  char *iptr;			/* input pointer */
  202.50 +  char ibuf[BUFLEN];		/* input buffer */
  202.51 +};
   203.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   203.2 +++ b/src/osdep/amiga/tenex.c	Mon Sep 14 15:17:45 2009 +0900
   203.3 @@ -0,0 +1,1470 @@
   203.4 +/* ========================================================================
   203.5 + * Copyright 1988-2007 University of Washington
   203.6 + *
   203.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   203.8 + * you may not use this file except in compliance with the License.
   203.9 + * You may obtain a copy of the License at
  203.10 + *
  203.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  203.12 + *
  203.13 + * 
  203.14 + * ========================================================================
  203.15 + */
  203.16 +
  203.17 +/*
  203.18 + * Program:	Tenex mail routines
  203.19 + *
  203.20 + * Author:	Mark Crispin
  203.21 + *		Networks and Distributed Computing
  203.22 + *		Computing & Communications
  203.23 + *		University of Washington
  203.24 + *		Administration Building, AG-44
  203.25 + *		Seattle, WA  98195
  203.26 + *		Internet: MRC@CAC.Washington.EDU
  203.27 + *
  203.28 + * Date:	22 May 1990
  203.29 + * Last Edited:	11 October 2007
  203.30 + */
  203.31 +
  203.32 +
  203.33 +/*				FILE TIME SEMANTICS
  203.34 + *
  203.35 + * The atime is the last read time of the file.
  203.36 + * The mtime is the last flags update time of the file.
  203.37 + * The ctime is the last write time of the file.
  203.38 + *
  203.39 + *				TEXT SIZE SEMANTICS
  203.40 + *
  203.41 + * Most of the text sizes are in internal (LF-only) form, except for the
  203.42 + * msg.text size.  Beware.
  203.43 + */
  203.44 +
  203.45 +#include <stdio.h>
  203.46 +#include <ctype.h>
  203.47 +#include <errno.h>
  203.48 +extern int errno;		/* just in case */
  203.49 +#include "mail.h"
  203.50 +#include "osdep.h"
  203.51 +#include <sys/stat.h>
  203.52 +#include "misc.h"
  203.53 +#include "dummy.h"
  203.54 +
  203.55 +/* TENEX I/O stream local data */
  203.56 +	
  203.57 +typedef struct tenex_local {
  203.58 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  203.59 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  203.60 +  int fd;			/* file descriptor for I/O */
  203.61 +  off_t filesize;		/* file size parsed */
  203.62 +  time_t filetime;		/* last file time */
  203.63 +  time_t lastsnarf;		/* local snarf time */
  203.64 +  unsigned char *buf;		/* temporary buffer */
  203.65 +  unsigned long buflen;		/* current size of temporary buffer */
  203.66 +  unsigned long uid;		/* current text uid */
  203.67 +  SIZEDTEXT text;		/* current text */
  203.68 +} TENEXLOCAL;
  203.69 +
  203.70 +
  203.71 +/* Convenient access to local data */
  203.72 +
  203.73 +#define LOCAL ((TENEXLOCAL *) stream->local)
  203.74 +
  203.75 +
  203.76 +/* Function prototypes */
  203.77 +
  203.78 +DRIVER *tenex_valid (char *name);
  203.79 +int tenex_isvalid (char *name,char *tmp);
  203.80 +void *tenex_parameters (long function,void *value);
  203.81 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  203.82 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
  203.83 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
  203.84 +long tenex_create (MAILSTREAM *stream,char *mailbox);
  203.85 +long tenex_delete (MAILSTREAM *stream,char *mailbox);
  203.86 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
  203.87 +long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
  203.88 +MAILSTREAM *tenex_open (MAILSTREAM *stream);
  203.89 +void tenex_close (MAILSTREAM *stream,long options);
  203.90 +void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
  203.91 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
  203.92 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
  203.93 +		    unsigned long *length,long flags);
  203.94 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  203.95 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  203.96 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  203.97 +long tenex_ping (MAILSTREAM *stream);
  203.98 +void tenex_check (MAILSTREAM *stream);
  203.99 +void tenex_snarf (MAILSTREAM *stream);
 203.100 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
 203.101 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 203.102 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 203.103 +
 203.104 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
 203.105 +char *tenex_file (char *dst,char *name);
 203.106 +long tenex_parse (MAILSTREAM *stream);
 203.107 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
 203.108 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 203.109 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
 203.110 +			  long syncflag);
 203.111 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 203.112 +			    unsigned long *size);
 203.113 +
 203.114 +/* Tenex mail routines */
 203.115 +
 203.116 +
 203.117 +/* Driver dispatch used by MAIL */
 203.118 +
 203.119 +DRIVER tenexdriver = {
 203.120 +  "tenex",			/* driver name */
 203.121 +  DR_LOCAL|DR_MAIL|DR_NOSTICKY|DR_LOCKING,
 203.122 +				/* driver flags */
 203.123 +  (DRIVER *) NIL,		/* next driver */
 203.124 +  tenex_valid,			/* mailbox is valid for us */
 203.125 +  tenex_parameters,		/* manipulate parameters */
 203.126 +  tenex_scan,			/* scan mailboxes */
 203.127 +  tenex_list,			/* list mailboxes */
 203.128 +  tenex_lsub,			/* list subscribed mailboxes */
 203.129 +  NIL,				/* subscribe to mailbox */
 203.130 +  NIL,				/* unsubscribe from mailbox */
 203.131 +  dummy_create,			/* create mailbox */
 203.132 +  tenex_delete,			/* delete mailbox */
 203.133 +  tenex_rename,			/* rename mailbox */
 203.134 +  tenex_status,			/* status of mailbox */
 203.135 +  tenex_open,			/* open mailbox */
 203.136 +  tenex_close,			/* close mailbox */
 203.137 +  tenex_fast,			/* fetch message "fast" attributes */
 203.138 +  tenex_flags,			/* fetch message flags */
 203.139 +  NIL,				/* fetch overview */
 203.140 +  NIL,				/* fetch message envelopes */
 203.141 +  tenex_header,			/* fetch message header */
 203.142 +  tenex_text,			/* fetch message body */
 203.143 +  NIL,				/* fetch partial message text */
 203.144 +  NIL,				/* unique identifier */
 203.145 +  NIL,				/* message number */
 203.146 +  tenex_flag,			/* modify flags */
 203.147 +  tenex_flagmsg,		/* per-message modify flags */
 203.148 +  NIL,				/* search for message based on criteria */
 203.149 +  NIL,				/* sort messages */
 203.150 +  NIL,				/* thread messages */
 203.151 +  tenex_ping,			/* ping mailbox to see if still alive */
 203.152 +  tenex_check,			/* check for new messages */
 203.153 +  tenex_expunge,		/* expunge deleted messages */
 203.154 +  tenex_copy,			/* copy messages to another mailbox */
 203.155 +  tenex_append,			/* append string message to mailbox */
 203.156 +  NIL				/* garbage collect stream */
 203.157 +};
 203.158 +
 203.159 +				/* prototype stream */
 203.160 +MAILSTREAM tenexproto = {&tenexdriver};
 203.161 +
 203.162 +/* Tenex mail validate mailbox
 203.163 + * Accepts: mailbox name
 203.164 + * Returns: our driver if name is valid, NIL otherwise
 203.165 + */
 203.166 +
 203.167 +DRIVER *tenex_valid (char *name)
 203.168 +{
 203.169 +  char tmp[MAILTMPLEN];
 203.170 +  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
 203.171 +}
 203.172 +
 203.173 +
 203.174 +/* Tenex mail test for valid mailbox
 203.175 + * Accepts: mailbox name
 203.176 + * Returns: T if valid, NIL otherwise
 203.177 + */
 203.178 +
 203.179 +int tenex_isvalid (char *name,char *tmp)
 203.180 +{
 203.181 +  int fd;
 203.182 +  int ret = NIL;
 203.183 +  char *s,file[MAILTMPLEN];
 203.184 +  struct stat sbuf;
 203.185 +  time_t tp[2];
 203.186 +  errno = EINVAL;		/* assume invalid argument */
 203.187 +				/* if file, get its status */
 203.188 +  if ((s = tenex_file (file,name)) && !stat (s,&sbuf)) {
 203.189 +    if (!sbuf.st_size) {	/* allow empty file if INBOX */
 203.190 +      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
 203.191 +      else errno = 0;		/* empty file */
 203.192 +    }
 203.193 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 203.194 +      memset (tmp,'\0',MAILTMPLEN);
 203.195 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
 203.196 +	  (s[-1] != '\015')) {	/* valid format? */
 203.197 +	*s = '\0';		/* tie off header */
 203.198 +				/* must begin with dd-mmm-yy" */
 203.199 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 203.200 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 203.201 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 203.202 +      }
 203.203 +      else errno = -1;		/* bogus format */
 203.204 +      close (fd);		/* close the file */
 203.205 +				/* \Marked status? */
 203.206 +      if (sbuf.st_ctime > sbuf.st_atime) {
 203.207 +	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 203.208 +	tp[1] = sbuf.st_mtime;
 203.209 +	utime (file,tp);	/* set the times */
 203.210 +      }
 203.211 +    }
 203.212 +  }
 203.213 +				/* in case INBOX but not tenex format */
 203.214 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 203.215 +  return ret;			/* return what we should */
 203.216 +}
 203.217 +
 203.218 +/* Tenex manipulate driver parameters
 203.219 + * Accepts: function code
 203.220 + *	    function-dependent value
 203.221 + * Returns: function-dependent return value
 203.222 + */
 203.223 +
 203.224 +void *tenex_parameters (long function,void *value)
 203.225 +{
 203.226 +  void *ret = NIL;
 203.227 +  switch ((int) function) {
 203.228 +  case GET_INBOXPATH:
 203.229 +    if (value) ret = tenex_file ((char *) value,"INBOX");
 203.230 +    break;
 203.231 +  }
 203.232 +  return ret;
 203.233 +}
 203.234 +
 203.235 +
 203.236 +/* Tenex mail scan mailboxes
 203.237 + * Accepts: mail stream
 203.238 + *	    reference
 203.239 + *	    pattern to search
 203.240 + *	    string to scan
 203.241 + */
 203.242 +
 203.243 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 203.244 +{
 203.245 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 203.246 +}
 203.247 +
 203.248 +
 203.249 +/* Tenex mail list mailboxes
 203.250 + * Accepts: mail stream
 203.251 + *	    reference
 203.252 + *	    pattern to search
 203.253 + */
 203.254 +
 203.255 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
 203.256 +{
 203.257 +  if (stream) dummy_list (NIL,ref,pat);
 203.258 +}
 203.259 +
 203.260 +
 203.261 +/* Tenex mail list subscribed mailboxes
 203.262 + * Accepts: mail stream
 203.263 + *	    reference
 203.264 + *	    pattern to search
 203.265 + */
 203.266 +
 203.267 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
 203.268 +{
 203.269 +  if (stream) dummy_lsub (NIL,ref,pat);
 203.270 +}
 203.271 +
 203.272 +/* Tenex mail delete mailbox
 203.273 + * Accepts: MAIL stream
 203.274 + *	    mailbox name to delete
 203.275 + * Returns: T on success, NIL on failure
 203.276 + */
 203.277 +
 203.278 +long tenex_delete (MAILSTREAM *stream,char *mailbox)
 203.279 +{
 203.280 +  return tenex_rename (stream,mailbox,NIL);
 203.281 +}
 203.282 +
 203.283 +
 203.284 +/* Tenex mail rename mailbox
 203.285 + * Accepts: MAIL stream
 203.286 + *	    old mailbox name
 203.287 + *	    new mailbox name (or NIL for delete)
 203.288 + * Returns: T on success, NIL on failure
 203.289 + */
 203.290 +
 203.291 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
 203.292 +{
 203.293 +  long ret = T;
 203.294 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 203.295 +  int fd,ld;
 203.296 +  struct stat sbuf;
 203.297 +  if (!tenex_file (file,old) ||
 203.298 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 203.299 +		   ((s = strrchr (tmp,'/')) && !s[1])))) {
 203.300 +    sprintf (tmp,newname ?
 203.301 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 203.302 +	     "Can't delete mailbox %.80s: invalid name",
 203.303 +	     old,newname);
 203.304 +    MM_LOG (tmp,ERROR);
 203.305 +    return NIL;
 203.306 +  }
 203.307 +  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
 203.308 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 203.309 +    MM_LOG (tmp,ERROR);
 203.310 +    return NIL;
 203.311 +  }
 203.312 +				/* get exclusive parse/append permission */
 203.313 +  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
 203.314 +    MM_LOG ("Unable to lock rename mailbox",ERROR);
 203.315 +    return NIL;
 203.316 +  }
 203.317 +				/* lock out other users */
 203.318 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 203.319 +    close (fd);			/* couldn't lock, give up on it then */
 203.320 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 203.321 +    MM_LOG (tmp,ERROR);
 203.322 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 203.323 +    return NIL;
 203.324 +  }
 203.325 +
 203.326 +  if (newname) {		/* want rename? */
 203.327 +    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
 203.328 +      c = *++s;			/* remember first character of inferior */
 203.329 +      *s = '\0';		/* tie off to get just superior */
 203.330 +				/* name doesn't exist, create it */
 203.331 +      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 203.332 +	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
 203.333 +	ret = NIL;
 203.334 +      else *s = c;		/* restore full name */
 203.335 +    }
 203.336 +				/* rename the file */
 203.337 +    if (ret && rename (file,tmp)) {
 203.338 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 203.339 +	       strerror (errno));
 203.340 +      MM_LOG (tmp,ERROR);
 203.341 +      ret = NIL;		/* set failure */
 203.342 +    }
 203.343 +  }
 203.344 +  else if (unlink (file)) {
 203.345 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 203.346 +    MM_LOG (tmp,ERROR);
 203.347 +    ret = NIL;			/* set failure */
 203.348 +  }
 203.349 +  flock (fd,LOCK_UN);		/* release lock on the file */
 203.350 +  close (fd);			/* close the file */
 203.351 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 203.352 +				/* recreate file if renamed INBOX */
 203.353 +  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"mail.txt");
 203.354 +  return ret;			/* return success */
 203.355 +}
 203.356 +
 203.357 +/* Tenex Mail status
 203.358 + * Accepts: mail stream
 203.359 + *	    mailbox name
 203.360 + *	    status flags
 203.361 + * Returns: T on success, NIL on failure
 203.362 + */
 203.363 +
 203.364 +long tenex_status (MAILSTREAM *stream,char *mbx,long flags)
 203.365 +{
 203.366 +  MAILSTATUS status;
 203.367 +  unsigned long i;
 203.368 +  MAILSTREAM *tstream = NIL;
 203.369 +  MAILSTREAM *systream = NIL;
 203.370 +				/* make temporary stream (unless this mbx) */
 203.371 +  if (!stream && !(stream = tstream =
 203.372 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
 203.373 +  status.flags = flags;		/* return status values */
 203.374 +  status.messages = stream->nmsgs;
 203.375 +  status.recent = stream->recent;
 203.376 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 203.377 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 203.378 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 203.379 +  status.uidnext = stream->uid_last + 1;
 203.380 +  status.uidvalidity = stream->uid_validity;
 203.381 +				/* calculate post-snarf results */
 203.382 +  if (!status.recent && stream->inbox &&
 203.383 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
 203.384 +    status.messages += systream->nmsgs;
 203.385 +    status.recent += systream->recent;
 203.386 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 203.387 +      for (i = 1; i <= systream->nmsgs; i++)
 203.388 +	if (!mail_elt (systream,i)->seen) status.unseen++;
 203.389 +				/* kludge but probably good enough */
 203.390 +    status.uidnext += systream->nmsgs;
 203.391 +  }
 203.392 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 203.393 +  if (tstream) mail_close (tstream);
 203.394 +  if (systream) mail_close (systream);
 203.395 +  return T;			/* success */
 203.396 +}
 203.397 +
 203.398 +/* Tenex mail open
 203.399 + * Accepts: stream to open
 203.400 + * Returns: stream on success, NIL on failure
 203.401 + */
 203.402 +
 203.403 +MAILSTREAM *tenex_open (MAILSTREAM *stream)
 203.404 +{
 203.405 +  int fd,ld;
 203.406 +  char tmp[MAILTMPLEN];
 203.407 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 203.408 +				/* return prototype for OP_PROTOTYPE call */
 203.409 +  if (!stream) return user_flags (&tenexproto);
 203.410 +  if (stream->local) fatal ("tenex recycle stream");
 203.411 +  user_flags (stream);		/* set up user flags */
 203.412 +				/* canonicalize the mailbox name */
 203.413 +  if (!tenex_file (tmp,stream->mailbox)) {
 203.414 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 203.415 +    MM_LOG (tmp,ERROR);
 203.416 +  }
 203.417 +  if (stream->rdonly ||
 203.418 +      (fd = open (tmp,O_RDWR,NIL)) < 0) {
 203.419 +    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 203.420 +      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 203.421 +      MM_LOG (tmp,ERROR);
 203.422 +      return NIL;
 203.423 +    }
 203.424 +    else if (!stream->rdonly) {	/* got it, but readonly */
 203.425 +      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 203.426 +      stream->rdonly = T;
 203.427 +    }
 203.428 +  }
 203.429 +  stream->local = fs_get (sizeof (TENEXLOCAL));
 203.430 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 203.431 +  LOCAL->buflen = CHUNKSIZE - 1;
 203.432 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 203.433 +  LOCAL->text.size = CHUNKSIZE - 1;
 203.434 +
 203.435 +				/* note if an INBOX or not */
 203.436 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 203.437 +  LOCAL->fd = fd;		/* bind the file */
 203.438 +				/* flush old name */
 203.439 +  fs_give ((void **) &stream->mailbox);
 203.440 +				/* save canonical name */
 203.441 +  stream->mailbox = cpystr (tmp);
 203.442 +				/* get shared parse permission */
 203.443 +  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
 203.444 +    MM_LOG ("Unable to lock open mailbox",ERROR);
 203.445 +    return NIL;
 203.446 +  }
 203.447 +  (*bn) (BLOCK_FILELOCK,NIL);
 203.448 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 203.449 +  (*bn) (BLOCK_NONE,NIL);
 203.450 +  unlockfd (ld,tmp);		/* release shared parse permission */
 203.451 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 203.452 +				/* time not set up yet */
 203.453 +  LOCAL->lastsnarf = LOCAL->filetime = 0;
 203.454 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 203.455 +  stream->sequence++;		/* bump sequence number */
 203.456 +				/* parse mailbox */
 203.457 +  stream->nmsgs = stream->recent = 0;
 203.458 +  if (tenex_ping (stream) && !stream->nmsgs)
 203.459 +    MM_LOG ("Mailbox is empty",(long) NIL);
 203.460 +  if (!LOCAL) return NIL;	/* failure if stream died */
 203.461 +  stream->perm_seen = stream->perm_deleted =
 203.462 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 203.463 +      stream->rdonly ? NIL : T;
 203.464 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 203.465 +  return stream;		/* return stream to caller */
 203.466 +}
 203.467 +
 203.468 +/* Tenex mail close
 203.469 + * Accepts: MAIL stream
 203.470 + *	    close options
 203.471 + */
 203.472 +
 203.473 +void tenex_close (MAILSTREAM *stream,long options)
 203.474 +{
 203.475 +  if (stream && LOCAL) {	/* only if a file is open */
 203.476 +    int silent = stream->silent;
 203.477 +    stream->silent = T;		/* note this stream is dying */
 203.478 +    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
 203.479 +    stream->silent = silent;	/* restore previous status */
 203.480 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 203.481 +    close (LOCAL->fd);		/* close the local file */
 203.482 +				/* free local text buffer */
 203.483 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 203.484 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
 203.485 +				/* nuke the local data */
 203.486 +    fs_give ((void **) &stream->local);
 203.487 +    stream->dtb = NIL;		/* log out the DTB */
 203.488 +  }
 203.489 +}
 203.490 +
 203.491 +/* Tenex mail fetch fast data
 203.492 + * Accepts: MAIL stream
 203.493 + *	    sequence
 203.494 + *	    option flags
 203.495 + */
 203.496 +
 203.497 +void tenex_fast (MAILSTREAM *stream,char *sequence,long flags)
 203.498 +{
 203.499 +  STRING bs;
 203.500 +  MESSAGECACHE *elt;
 203.501 +  unsigned long i;
 203.502 +  if (stream && LOCAL &&
 203.503 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 203.504 +       mail_sequence (stream,sequence)))
 203.505 +    for (i = 1; i <= stream->nmsgs; i++)
 203.506 +      if ((elt = mail_elt (stream,i))->sequence) {
 203.507 +	if (!elt->rfc822_size) { /* have header size yet? */
 203.508 +	  lseek (LOCAL->fd,elt->private.special.offset +
 203.509 +		 elt->private.special.text.size,L_SET);
 203.510 +				/* resize bigbuf if necessary */
 203.511 +	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
 203.512 +	    fs_give ((void **) &LOCAL->buf);
 203.513 +	    LOCAL->buflen = elt->private.msg.full.text.size;
 203.514 +	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
 203.515 +	  }
 203.516 +				/* tie off string */
 203.517 +	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
 203.518 +				/* read in the message */
 203.519 +	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
 203.520 +	  INIT (&bs,mail_string,(void *) LOCAL->buf,
 203.521 +		elt->private.msg.full.text.size);
 203.522 +				/* calculate its CRLF size */
 203.523 +	  elt->rfc822_size = strcrlflen (&bs);
 203.524 +	}
 203.525 +	tenex_elt (stream,i);	/* get current flags from file */
 203.526 +      }
 203.527 +}
 203.528 +
 203.529 +
 203.530 +/* Tenex mail fetch flags
 203.531 + * Accepts: MAIL stream
 203.532 + *	    sequence
 203.533 + *	    option flags
 203.534 + * Sniffs at file to get flags
 203.535 + */
 203.536 +
 203.537 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
 203.538 +{
 203.539 +  unsigned long i;
 203.540 +  if (stream && LOCAL &&
 203.541 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 203.542 +       mail_sequence (stream,sequence)))
 203.543 +    for (i = 1; i <= stream->nmsgs; i++)
 203.544 +      if (mail_elt (stream,i)->sequence) tenex_elt (stream,i);
 203.545 +}
 203.546 +
 203.547 +/* TENEX mail fetch message header
 203.548 + * Accepts: MAIL stream
 203.549 + *	    message # to fetch
 203.550 + *	    pointer to returned header text length
 203.551 + *	    option flags
 203.552 + * Returns: message header in RFC822 format
 203.553 + */
 203.554 +
 203.555 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
 203.556 +		    unsigned long *length,long flags)
 203.557 +{
 203.558 +  char *s;
 203.559 +  unsigned long i;
 203.560 +  *length = 0;			/* default to empty */
 203.561 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 203.562 +				/* get to header position */
 203.563 +  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
 203.564 +  if (flags & FT_INTERNAL) {
 203.565 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 203.566 +      fs_give ((void **) &LOCAL->buf);
 203.567 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 203.568 +    }
 203.569 +				/* slurp the data */
 203.570 +    read (LOCAL->fd,LOCAL->buf,*length = i);
 203.571 +  }
 203.572 +  else {
 203.573 +    s = (char *) fs_get (i + 1);/* get readin buffer */
 203.574 +    s[i] = '\0';		/* tie off string */
 203.575 +    read (LOCAL->fd,s,i);	/* slurp the data */
 203.576 +				/* make CRLF copy of string */
 203.577 +    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
 203.578 +    fs_give ((void **) &s);	/* free readin buffer */
 203.579 +  }
 203.580 +  return (char *) LOCAL->buf;
 203.581 +}
 203.582 +
 203.583 +/* TENEX mail fetch message text (body only)
 203.584 + * Accepts: MAIL stream
 203.585 + *	    message # to fetch
 203.586 + *	    pointer to returned stringstruct
 203.587 + *	    option flags
 203.588 + * Returns: T, always
 203.589 + */
 203.590 +
 203.591 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 203.592 +{
 203.593 +  char *s;
 203.594 +  unsigned long i,j;
 203.595 +  MESSAGECACHE *elt;
 203.596 +				/* UID call "impossible" */
 203.597 +  if (flags & FT_UID) return NIL;
 203.598 +				/* get message status */
 203.599 +  elt = tenex_elt (stream,msgno);
 203.600 +				/* if message not seen */
 203.601 +  if (!(flags & FT_PEEK) && !elt->seen) {
 203.602 +    elt->seen = T;		/* mark message as seen */
 203.603 +				/* recalculate status */
 203.604 +    tenex_update_status (stream,msgno,T);
 203.605 +    MM_FLAGS (stream,msgno);
 203.606 +  }
 203.607 +  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
 203.608 +				/* find header position */
 203.609 +    i = tenex_hdrpos (stream,msgno,&j);
 203.610 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 203.611 +      fs_give ((void **) &LOCAL->buf);
 203.612 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 203.613 +    }
 203.614 +				/* go to text position */
 203.615 +    lseek (LOCAL->fd,i + j,L_SET);
 203.616 +				/* slurp the data */
 203.617 +    read (LOCAL->fd,LOCAL->buf,i);
 203.618 +				/* set up stringstruct for internal */
 203.619 +    INIT (bs,mail_string,LOCAL->buf,i);
 203.620 +  }
 203.621 +  else {			/* normal form, previous text cached? */
 203.622 +    if (elt->private.uid == LOCAL->uid)
 203.623 +      i = elt->private.msg.text.text.size;
 203.624 +    else {			/* not cached, cache it now */
 203.625 +      LOCAL->uid = elt->private.uid;
 203.626 +				/* find header position */
 203.627 +      i = tenex_hdrpos (stream,msgno,&j);
 203.628 +				/* go to text position */
 203.629 +      lseek (LOCAL->fd,i + j,L_SET);
 203.630 +      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
 203.631 +      s[i] = '\0';		/* tie off string */
 203.632 +      read (LOCAL->fd,s,i);	/* slurp the data */
 203.633 +				/* make CRLF copy of string */
 203.634 +      i = elt->private.msg.text.text.size =
 203.635 +	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
 203.636 +      fs_give ((void **) &s);	/* free readin buffer */
 203.637 +    }
 203.638 +				/* set up stringstruct */
 203.639 +    INIT (bs,mail_string,LOCAL->text.data,i);
 203.640 +  }
 203.641 +  return T;			/* success */
 203.642 +}
 203.643 +
 203.644 +/* Tenex mail modify flags
 203.645 + * Accepts: MAIL stream
 203.646 + *	    sequence
 203.647 + *	    flag(s)
 203.648 + *	    option flags
 203.649 + */
 203.650 +
 203.651 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 203.652 +{
 203.653 +  time_t tp[2];
 203.654 +  struct stat sbuf;
 203.655 +  if (!stream->rdonly) {	/* make sure the update takes */
 203.656 +    fsync (LOCAL->fd);
 203.657 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 203.658 +    tp[1] = LOCAL->filetime = sbuf.st_mtime;
 203.659 +    tp[0] = time (0);		/* make sure read comes after all that */
 203.660 +    utime (stream->mailbox,tp);
 203.661 +  }
 203.662 +}
 203.663 +
 203.664 +
 203.665 +/* Tenex mail per-message modify flags
 203.666 + * Accepts: MAIL stream
 203.667 + *	    message cache element
 203.668 + */
 203.669 +
 203.670 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 203.671 +{
 203.672 +  struct stat sbuf;
 203.673 +				/* maybe need to do a checkpoint? */
 203.674 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 203.675 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 203.676 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 203.677 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 203.678 +  }
 203.679 +				/* recalculate status */
 203.680 +  tenex_update_status (stream,elt->msgno,NIL);
 203.681 +}
 203.682 +
 203.683 +/* Tenex mail ping mailbox
 203.684 + * Accepts: MAIL stream
 203.685 + * Returns: T if stream still alive, NIL if not
 203.686 + */
 203.687 +
 203.688 +long tenex_ping (MAILSTREAM *stream)
 203.689 +{
 203.690 +  unsigned long i = 1;
 203.691 +  long r = T;
 203.692 +  int ld;
 203.693 +  char lock[MAILTMPLEN];
 203.694 +  struct stat sbuf;
 203.695 +  if (stream && LOCAL) {	/* only if stream already open */
 203.696 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 203.697 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 203.698 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 203.699 +				/* check for changed message status */
 203.700 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 203.701 +      LOCAL->filetime = sbuf.st_mtime;
 203.702 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 203.703 +	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
 203.704 +      while (i <= stream->nmsgs) tenex_elt (stream,i++);
 203.705 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 203.706 +    }
 203.707 +				/* get shared parse/append permission */
 203.708 +    if ((sbuf.st_size != LOCAL->filesize) &&
 203.709 +	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 203.710 +				/* parse resulting mailbox */
 203.711 +      r = (tenex_parse (stream)) ? T : NIL;
 203.712 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 203.713 +    }
 203.714 +    if (LOCAL) {		/* stream must still be alive */
 203.715 +				/* snarf if this is a read-write inbox */
 203.716 +      if (stream->inbox && !stream->rdonly) {
 203.717 +	tenex_snarf (stream);
 203.718 +	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
 203.719 +	if ((sbuf.st_size != LOCAL->filesize) &&
 203.720 +	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 203.721 +				/* parse resulting mailbox */
 203.722 +	  r = (tenex_parse (stream)) ? T : NIL;
 203.723 +	  unlockfd (ld,lock);	/* release shared parse/append permission */
 203.724 +	}
 203.725 +      }
 203.726 +    }
 203.727 +  }
 203.728 +  return r;			/* return result of the parse */
 203.729 +}
 203.730 +
 203.731 +
 203.732 +/* Tenex mail check mailbox (reparses status too)
 203.733 + * Accepts: MAIL stream
 203.734 + */
 203.735 +
 203.736 +void tenex_check (MAILSTREAM *stream)
 203.737 +{
 203.738 +				/* mark that a check is desired */
 203.739 +  if (LOCAL) LOCAL->mustcheck = T;
 203.740 +  if (tenex_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 203.741 +}
 203.742 +
 203.743 +/* Tenex mail snarf messages from system inbox
 203.744 + * Accepts: MAIL stream
 203.745 + */
 203.746 +
 203.747 +void tenex_snarf (MAILSTREAM *stream)
 203.748 +{
 203.749 +  unsigned long i = 0;
 203.750 +  unsigned long j,r,hdrlen,txtlen;
 203.751 +  struct stat sbuf;
 203.752 +  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
 203.753 +  MESSAGECACHE *elt;
 203.754 +  MAILSTREAM *sysibx = NIL;
 203.755 +  int ld;
 203.756 +				/* give up if can't get exclusive permission */
 203.757 +  if ((time (0) >= (LOCAL->lastsnarf +
 203.758 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
 203.759 +      strcmp (sysinbox (),stream->mailbox) &&
 203.760 +      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
 203.761 +    MM_CRITICAL (stream);	/* go critical */
 203.762 +				/* sizes match and anything in sysinbox? */
 203.763 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 203.764 +	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
 203.765 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 203.766 +	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
 203.767 +				/* yes, go to end of file in our mailbox */
 203.768 +      lseek (LOCAL->fd,sbuf.st_size,L_SET);
 203.769 +				/* for each message in sysibx mailbox */
 203.770 +      while (r && (++i <= sysibx->nmsgs)) {
 203.771 +				/* snarf message from system INBOX */
 203.772 +	hdr = cpystr (mail_fetchheader_full(sysibx,i,NIL,&hdrlen,FT_INTERNAL));
 203.773 +	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|FT_PEEK);
 203.774 +				/* if have a message */
 203.775 +	if (j = hdrlen + txtlen) {
 203.776 +				/* calculate header line */
 203.777 +	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
 203.778 +	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
 203.779 +		   ",%lu;0000000000%02o\n",j,(unsigned)
 203.780 +		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 203.781 +		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 203.782 +		    (fDRAFT * elt->draft)));
 203.783 +				/* copy message */
 203.784 +	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
 203.785 +	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
 203.786 +	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
 203.787 +	}
 203.788 +	fs_give ((void **) &hdr);
 203.789 +      }
 203.790 +
 203.791 +				/* make sure all the updates take */
 203.792 +      if (fsync (LOCAL->fd)) r = 0;
 203.793 +      if (r) {			/* delete all the messages we copied */
 203.794 +	if (r == 1) strcpy (tmp,"1");
 203.795 +	else sprintf (tmp,"1:%lu",r);
 203.796 +	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 203.797 +	mail_expunge (sysibx);	/* now expunge all those messages */
 203.798 +      }
 203.799 +      else {
 203.800 +	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
 203.801 +	MM_LOG (LOCAL->buf,WARN);
 203.802 +	ftruncate (LOCAL->fd,sbuf.st_size);
 203.803 +      }
 203.804 +      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
 203.805 +      LOCAL->filetime = sbuf.st_mtime;
 203.806 +    }
 203.807 +    if (sysibx) mail_close (sysibx);
 203.808 +    MM_NOCRITICAL (stream);	/* release critical */
 203.809 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 203.810 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 203.811 +  }
 203.812 +}
 203.813 +
 203.814 +/* Tenex mail expunge mailbox
 203.815 + * Accepts: MAIL stream
 203.816 + *	    sequence to expunge if non-NIL
 203.817 + *	    expunge options
 203.818 + * Returns: T, always
 203.819 + */
 203.820 +
 203.821 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
 203.822 +{
 203.823 +  long ret;
 203.824 +  time_t tp[2];
 203.825 +  struct stat sbuf;
 203.826 +  off_t pos = 0;
 203.827 +  int ld;
 203.828 +  unsigned long i = 1;
 203.829 +  unsigned long j,k,m,recent;
 203.830 +  unsigned long n = 0;
 203.831 +  unsigned long delta = 0;
 203.832 +  char lock[MAILTMPLEN];
 203.833 +  MESSAGECACHE *elt;
 203.834 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 203.835 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 203.836 +			   mail_uid_sequence (stream,sequence) :
 203.837 +			   mail_sequence (stream,sequence)) : LONGT) &&
 203.838 +	tenex_ping (stream)));	/* parse sequence if given, ping stream */
 203.839 +  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
 203.840 +  else {
 203.841 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 203.842 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 203.843 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 203.844 +    }
 203.845 +  /* The cretins who designed flock() created a window of vulnerability in
 203.846 +   * upgrading locks from shared to exclusive or downgrading from exclusive
 203.847 +   * to shared.  Rather than maintain the lock at shared status at a minimum,
 203.848 +   * flock() actually *releases* the former lock.  Obviously they never talked
 203.849 +   * to any database guys.  Fortunately, we have the parse/append permission
 203.850 +   * lock.  If we require this lock before going exclusive on the mailbox,
 203.851 +   * another process can not sneak in and steal the exclusive mailbox lock on
 203.852 +   * us, because it will block on trying to get parse/append permission first.
 203.853 +   */
 203.854 +				/* get exclusive parse/append permission */
 203.855 +    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
 203.856 +      MM_LOG ("Unable to lock expunge mailbox",ERROR);
 203.857 +				/* make sure see any newly-arrived messages */
 203.858 +    else if (!tenex_parse (stream));
 203.859 +				/* get exclusive access */
 203.860 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 203.861 +      (*bn) (BLOCK_FILELOCK,NIL);
 203.862 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 203.863 +      (*bn) (BLOCK_NONE,NIL);
 203.864 +      MM_LOG ("Can't expunge because mailbox is in use by another process",
 203.865 +	      ERROR);
 203.866 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 203.867 +    }
 203.868 +
 203.869 +    else {
 203.870 +      MM_CRITICAL (stream);	/* go critical */
 203.871 +      recent = stream->recent;	/* get recent now that pinged and locked */
 203.872 +				/* for each message */
 203.873 +      while (i <= stream->nmsgs) {
 203.874 +				/* get cache element */
 203.875 +	elt = tenex_elt (stream,i);
 203.876 +				/* number of bytes to smash or preserve */
 203.877 +	k = elt->private.special.text.size + tenex_size (stream,i);
 203.878 +				/* if need to expunge this message */
 203.879 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 203.880 +				/* if recent, note one less recent message */
 203.881 +	  if (elt->recent) --recent;
 203.882 +	  delta += k;		/* number of bytes to delete */
 203.883 +				/* notify upper levels */
 203.884 +	  mail_expunged (stream,i);
 203.885 +	  n++;			/* count up one more expunged message */
 203.886 +	}
 203.887 +	else if (i++ && delta) {/* preserved message */
 203.888 +				/* first byte to preserve */
 203.889 +	  j = elt->private.special.offset;
 203.890 +	  do {			/* read from source position */
 203.891 +	    m = min (k,LOCAL->buflen);
 203.892 +	    lseek (LOCAL->fd,j,L_SET);
 203.893 +	    read (LOCAL->fd,LOCAL->buf,m);
 203.894 +	    pos = j - delta;	/* write to destination position */
 203.895 +	    lseek (LOCAL->fd,pos,L_SET);
 203.896 +	    while (T) {
 203.897 +	      lseek (LOCAL->fd,pos,L_SET);
 203.898 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 203.899 +	      MM_NOTIFY (stream,strerror (errno),WARN);
 203.900 +	      MM_DISKERROR (stream,errno,T);
 203.901 +	    }
 203.902 +	    pos += m;		/* new position */
 203.903 +	    j += m;		/* next chunk, perhaps */
 203.904 +	  } while (k -= m);		/* until done */
 203.905 +				/* note the new address of this text */
 203.906 +	  elt->private.special.offset -= delta;
 203.907 +	}
 203.908 +				/* preserved but no deleted messages */
 203.909 +	else pos = elt->private.special.offset + k;
 203.910 +      }
 203.911 +
 203.912 +      if (n) {			/* truncate file after last message */
 203.913 +	if (pos != (LOCAL->filesize -= delta)) {
 203.914 +	  sprintf (LOCAL->buf,
 203.915 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 203.916 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 203.917 +	  MM_LOG (LOCAL->buf,WARN);
 203.918 +	  LOCAL->filesize = pos;/* fix it then */
 203.919 +	}
 203.920 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 203.921 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 203.922 +				/* output the news */
 203.923 +	MM_LOG (LOCAL->buf,(long) NIL);
 203.924 +      }
 203.925 +      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 203.926 +      fsync (LOCAL->fd);		/* force disk update */
 203.927 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 203.928 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
 203.929 +      tp[0] = time (0);		/* reset atime to now */
 203.930 +      utime (stream->mailbox,tp);
 203.931 +      MM_NOCRITICAL (stream);	/* release critical */
 203.932 +				/* notify upper level of new mailbox size */
 203.933 +      mail_exists (stream,stream->nmsgs);
 203.934 +      mail_recent (stream,recent);
 203.935 +      (*bn) (BLOCK_FILELOCK,NIL);
 203.936 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 203.937 +      (*bn) (BLOCK_NONE,NIL);
 203.938 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 203.939 +    }
 203.940 +  }
 203.941 +  return LONGT;
 203.942 +}
 203.943 +
 203.944 +/* Tenex mail copy message(s)
 203.945 + * Accepts: MAIL stream
 203.946 + *	    sequence
 203.947 + *	    destination mailbox
 203.948 + *	    copy options
 203.949 + * Returns: T if success, NIL if failed
 203.950 + */
 203.951 +
 203.952 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 203.953 +{
 203.954 +  struct stat sbuf;
 203.955 +  time_t tp[2];
 203.956 +  MESSAGECACHE *elt;
 203.957 +  unsigned long i,j,k;
 203.958 +  long ret = LONGT;
 203.959 +  int fd,ld;
 203.960 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 203.961 +  mailproxycopy_t pc =
 203.962 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 203.963 +				/* make sure valid mailbox */
 203.964 +  if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) {
 203.965 +  case ENOENT:			/* no such file? */
 203.966 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 203.967 +    return NIL;
 203.968 +  case 0:			/* merely empty file? */
 203.969 +    break;
 203.970 +  case EACCES:			/* file protected */
 203.971 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 203.972 +    MM_LOG (LOCAL->buf,ERROR);
 203.973 +    return NIL;
 203.974 +  case EINVAL:
 203.975 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 203.976 +    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
 203.977 +    MM_LOG (LOCAL->buf,ERROR);
 203.978 +    return NIL;
 203.979 +  default:
 203.980 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 203.981 +    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
 203.982 +    MM_LOG (LOCAL->buf,ERROR);
 203.983 +    return NIL;
 203.984 +  }
 203.985 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 203.986 +	mail_sequence (stream,sequence))) return NIL;
 203.987 +				/* got file? */  
 203.988 +  if ((fd = open (tenex_file(file,mailbox),O_RDWR,NIL)) < 0) {
 203.989 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
 203.990 +    MM_LOG (LOCAL->buf,ERROR);
 203.991 +    return NIL;
 203.992 +  }
 203.993 +  MM_CRITICAL (stream);		/* go critical */
 203.994 +				/* get exclusive parse/append permission */
 203.995 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
 203.996 +    MM_LOG ("Unable to lock copy mailbox",ERROR);
 203.997 +    MM_NOCRITICAL (stream);
 203.998 +    return NIL;
 203.999 +  }
203.1000 +  fstat (fd,&sbuf);		/* get current file size */
203.1001 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
203.1002 +
203.1003 +				/* for each requested message */
203.1004 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
203.1005 +    if ((elt = mail_elt (stream,i))->sequence) {
203.1006 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
203.1007 +				/* number of bytes to copy */
203.1008 +      k = elt->private.special.text.size + tenex_size (stream,i);
203.1009 +      do {			/* read from source position */
203.1010 +	j = min (k,LOCAL->buflen);
203.1011 +	read (LOCAL->fd,LOCAL->buf,j);
203.1012 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
203.1013 +      } while (ret && (k -= j));/* until done */
203.1014 +    }
203.1015 +				/* make sure all the updates take */
203.1016 +  if (!(ret && (ret = !fsync (fd)))) {
203.1017 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
203.1018 +    MM_LOG (LOCAL->buf,ERROR);
203.1019 +    ftruncate (fd,sbuf.st_size);
203.1020 +  }
203.1021 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
203.1022 +				/* else preserve \Marked status */
203.1023 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
203.1024 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
203.1025 +  utime (file,tp);		/* set the times */
203.1026 +  close (fd);			/* close the file */
203.1027 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
203.1028 +  MM_NOCRITICAL (stream);	/* release critical */
203.1029 +				/* delete all requested messages */
203.1030 +  if (ret && (options & CP_MOVE)) {
203.1031 +    for (i = 1; i <= stream->nmsgs; i++)
203.1032 +      if ((elt = tenex_elt (stream,i))->sequence) {
203.1033 +	elt->deleted = T;	/* mark message deleted */
203.1034 +				/* recalculate status */
203.1035 +	tenex_update_status (stream,i,NIL);
203.1036 +      }
203.1037 +    if (!stream->rdonly) {	/* make sure the update takes */
203.1038 +      fsync (LOCAL->fd);
203.1039 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
203.1040 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
203.1041 +      tp[0] = time (0);		/* make sure atime remains greater */
203.1042 +      utime (stream->mailbox,tp);
203.1043 +    }
203.1044 +  }
203.1045 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
203.1046 +    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
203.1047 +  return ret;
203.1048 +}
203.1049 +
203.1050 +/* Tenex mail append message from stringstruct
203.1051 + * Accepts: MAIL stream
203.1052 + *	    destination mailbox
203.1053 + *	    append callback
203.1054 + *	    data for callback
203.1055 + * Returns: T if append successful, else NIL
203.1056 + */
203.1057 +
203.1058 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
203.1059 +{
203.1060 +  struct stat sbuf;
203.1061 +  int fd,ld,c;
203.1062 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
203.1063 +  time_t tp[2];
203.1064 +  FILE *df;
203.1065 +  MESSAGECACHE elt;
203.1066 +  long f;
203.1067 +  unsigned long i,j,uf,size;
203.1068 +  STRING *message;
203.1069 +  long ret = LONGT;
203.1070 +				/* default stream to prototype */
203.1071 +  if (!stream) stream = user_flags (&tenexproto);
203.1072 +				/* make sure valid mailbox */
203.1073 +  if (!tenex_isvalid (mailbox,tmp)) switch (errno) {
203.1074 +  case ENOENT:			/* no such file? */
203.1075 +    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"mail.txt");
203.1076 +    else {
203.1077 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
203.1078 +      return NIL;
203.1079 +    }
203.1080 +				/* falls through */
203.1081 +  case 0:			/* merely empty file? */
203.1082 +    break;
203.1083 +  case EACCES:			/* file protected */
203.1084 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
203.1085 +    MM_LOG (tmp,ERROR);
203.1086 +    return NIL;
203.1087 +  case EINVAL:
203.1088 +    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
203.1089 +    MM_LOG (tmp,ERROR);
203.1090 +    return NIL;
203.1091 +  default:
203.1092 +    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
203.1093 +    MM_LOG (tmp,ERROR);
203.1094 +    return NIL;
203.1095 +  }
203.1096 +				/* get first message */
203.1097 +  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
203.1098 +
203.1099 +				/* open destination mailbox */
203.1100 +  if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
203.1101 +      !(df = fdopen (fd,"ab"))) {
203.1102 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
203.1103 +    MM_LOG (tmp,ERROR);
203.1104 +    return NIL;
203.1105 +  }
203.1106 +				/* get parse/append permission */
203.1107 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
203.1108 +    MM_LOG ("Unable to lock append mailbox",ERROR);
203.1109 +    close (fd);
203.1110 +    return NIL;
203.1111 +  }
203.1112 +  MM_CRITICAL (stream);		/* go critical */
203.1113 +  fstat (fd,&sbuf);		/* get current file size */
203.1114 +  errno = 0;
203.1115 +  do {				/* parse flags */ 
203.1116 +    if (!SIZE (message)) {	/* guard against zero-length */
203.1117 +      MM_LOG ("Append of zero-length message",ERROR);
203.1118 +      ret = NIL;
203.1119 +      break;
203.1120 +    }
203.1121 +    f = mail_parse_flags (stream,flags,&i);
203.1122 +				/* reverse bits (dontcha wish we had CIRC?) */
203.1123 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
203.1124 +    if (date) {			/* parse date if given */
203.1125 +      if (!mail_parse_date (&elt,date)) {
203.1126 +	sprintf (tmp,"Bad date in append: %.80s",date);
203.1127 +	MM_LOG (tmp,ERROR);
203.1128 +	ret = NIL;		/* mark failure */
203.1129 +	break;
203.1130 +      }
203.1131 +      mail_date (tmp,&elt);	/* write preseved date */
203.1132 +    }
203.1133 +    else internal_date (tmp);	/* get current date in IMAP format */
203.1134 +    i = GETPOS (message);	/* remember current position */
203.1135 +    for (j = SIZE (message), size = 0; j; --j)
203.1136 +      if (SNX (message) != '\015') ++size;
203.1137 +    SETPOS (message,i);		/* restore position */
203.1138 +				/* write header */
203.1139 +    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
203.1140 +      ret = NIL;
203.1141 +    else {			/* write message */
203.1142 +      while (size) if ((c = 0xff & SNX (message)) != '\015') {
203.1143 +	if (putc (c,df) != EOF) --size;
203.1144 +	else break;
203.1145 +      }
203.1146 +				/* get next message */
203.1147 +      if (size || !MM_APPEND (af) (stream,data,&flags,&date,&message))
203.1148 +	ret = NIL;
203.1149 +    }
203.1150 +  } while (ret && message);
203.1151 +				/* if error... */
203.1152 +  if (!ret || (fflush (df) == EOF)) {
203.1153 +    ftruncate (fd,sbuf.st_size);/* revert file */
203.1154 +    close (fd);			/* make sure fclose() doesn't corrupt us */
203.1155 +    if (errno) {
203.1156 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
203.1157 +      MM_LOG (tmp,ERROR);
203.1158 +    }
203.1159 +    ret = NIL;
203.1160 +  }
203.1161 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
203.1162 +				/* else preserve \Marked status */
203.1163 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
203.1164 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
203.1165 +  utime (file,tp);		/* set the times */
203.1166 +  fclose (df);			/* close the file */
203.1167 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
203.1168 +  MM_NOCRITICAL (stream);	/* release critical */
203.1169 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
203.1170 +    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
203.1171 +	    WARN);
203.1172 +  return ret;
203.1173 +}
203.1174 +
203.1175 +/* Internal routines */
203.1176 +
203.1177 +
203.1178 +/* Tenex mail return internal message size in bytes
203.1179 + * Accepts: MAIL stream
203.1180 + *	    message #
203.1181 + * Returns: internal size of message
203.1182 + */
203.1183 +
203.1184 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
203.1185 +{
203.1186 +  MESSAGECACHE *elt = mail_elt (stream,m);
203.1187 +  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
203.1188 +	  LOCAL->filesize) -
203.1189 +	    (elt->private.special.offset + elt->private.special.text.size);
203.1190 +}
203.1191 +
203.1192 +
203.1193 +/* Tenex mail generate file string
203.1194 + * Accepts: temporary buffer to write into
203.1195 + *	    mailbox name string
203.1196 + * Returns: local file string or NIL if failure
203.1197 + */
203.1198 +
203.1199 +char *tenex_file (char *dst,char *name)
203.1200 +{
203.1201 +  char tmp[MAILTMPLEN];
203.1202 +  char *s = mailboxfile (dst,name);
203.1203 +				/* return our standard inbox */
203.1204 +  return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ?
203.1205 +				   "~/INBOX" : "mail.txt") : s;
203.1206 +}
203.1207 +
203.1208 +/* Tenex mail parse mailbox
203.1209 + * Accepts: MAIL stream
203.1210 + * Returns: T if parse OK
203.1211 + *	    NIL if failure, stream aborted
203.1212 + */
203.1213 +
203.1214 +long tenex_parse (MAILSTREAM *stream)
203.1215 +{
203.1216 +  struct stat sbuf;
203.1217 +  MESSAGECACHE *elt = NIL;
203.1218 +  unsigned char c,*s,*t,*x;
203.1219 +  char tmp[MAILTMPLEN];
203.1220 +  unsigned long i,j;
203.1221 +  long curpos = LOCAL->filesize;
203.1222 +  long nmsgs = stream->nmsgs;
203.1223 +  long recent = stream->recent;
203.1224 +  short added = NIL;
203.1225 +  short silent = stream->silent;
203.1226 +  fstat (LOCAL->fd,&sbuf);	/* get status */
203.1227 +  if (sbuf.st_size < curpos) {	/* sanity check */
203.1228 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
203.1229 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
203.1230 +    MM_LOG (tmp,ERROR);
203.1231 +    tenex_close (stream,NIL);
203.1232 +    return NIL;
203.1233 +  }
203.1234 +  stream->silent = T;		/* don't pass up exists events yet */
203.1235 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
203.1236 +				/* get to that position in the file */
203.1237 +    lseek (LOCAL->fd,curpos,L_SET);
203.1238 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
203.1239 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
203.1240 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
203.1241 +	       i ? strerror (errno) : "no data read");
203.1242 +      MM_LOG (tmp,ERROR);
203.1243 +      tenex_close (stream,NIL);
203.1244 +      return NIL;
203.1245 +    }
203.1246 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
203.1247 +    if (!(s = strchr (LOCAL->buf,'\012'))) {
203.1248 +      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
203.1249 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
203.1250 +      MM_LOG (tmp,ERROR);
203.1251 +      tenex_close (stream,NIL);
203.1252 +      return NIL;
203.1253 +    }
203.1254 +    *s = '\0';			/* tie off header line */
203.1255 +    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
203.1256 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
203.1257 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
203.1258 +	       (unsigned long) curpos,(char *) LOCAL->buf);
203.1259 +      MM_LOG (tmp,ERROR);
203.1260 +      tenex_close (stream,NIL);
203.1261 +      return NIL;
203.1262 +    }
203.1263 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
203.1264 +
203.1265 +    added = T;			/* note that a new message was added */
203.1266 +				/* swell the cache */
203.1267 +    mail_exists (stream,++nmsgs);
203.1268 +				/* instantiate an elt for this message */
203.1269 +    (elt = mail_elt (stream,nmsgs))->valid = T;
203.1270 +    elt->private.uid = ++stream->uid_last;
203.1271 +				/* note file offset of header */
203.1272 +    elt->private.special.offset = curpos;
203.1273 +				/* in case error */
203.1274 +    elt->private.special.text.size = 0;
203.1275 +				/* header size not known yet */
203.1276 +    elt->private.msg.header.text.size = 0;
203.1277 +    x = s;			/* parse the header components */
203.1278 +    if (mail_parse_date (elt,LOCAL->buf) &&
203.1279 +	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
203.1280 +	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
203.1281 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
203.1282 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
203.1283 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
203.1284 +      elt->private.special.text.size = i;
203.1285 +    else {			/* oops */
203.1286 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
203.1287 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
203.1288 +      MM_LOG (tmp,ERROR);
203.1289 +      tenex_close (stream,NIL);
203.1290 +      return NIL;
203.1291 +    }
203.1292 +				/* make sure didn't run off end of file */
203.1293 +    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
203.1294 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
203.1295 +	       elt->private.special.offset,(unsigned long) curpos,
203.1296 +	       (unsigned long) sbuf.st_size);
203.1297 +      MM_LOG (tmp,ERROR);
203.1298 +      tenex_close (stream,NIL);
203.1299 +      return NIL;
203.1300 +    }
203.1301 +    c = t[10];			/* remember first system flags byte */
203.1302 +    t[10] = '\0';		/* tie off flags */
203.1303 +    j = strtoul (t,NIL,8);	/* get user flags value */
203.1304 +    t[10] = c;			/* restore first system flags byte */
203.1305 +				/* set up all valid user flags (reversed!) */
203.1306 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
203.1307 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
203.1308 +				/* calculate system flags */
203.1309 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
203.1310 +    if (j & fDELETED) elt->deleted = T;
203.1311 +    if (j & fFLAGGED) elt->flagged = T;
203.1312 +    if (j & fANSWERED) elt->answered = T;
203.1313 +    if (j & fDRAFT) elt->draft = T;
203.1314 +    if (!(j & fOLD)) {		/* newly arrived message? */
203.1315 +      elt->recent = T;
203.1316 +      recent++;			/* count up a new recent message */
203.1317 +				/* mark it as old */
203.1318 +      tenex_update_status (stream,nmsgs,NIL);
203.1319 +    }
203.1320 +  }
203.1321 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
203.1322 +				/* update parsed file size and time */
203.1323 +  LOCAL->filesize = sbuf.st_size;
203.1324 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
203.1325 +  LOCAL->filetime = sbuf.st_mtime;
203.1326 +  if (added && !stream->rdonly){/* make sure atime updated */
203.1327 +    time_t tp[2];
203.1328 +    tp[0] = time (0);
203.1329 +    tp[1] = LOCAL->filetime;
203.1330 +    utime (stream->mailbox,tp);
203.1331 +  }
203.1332 +  stream->silent = silent;	/* can pass up events now */
203.1333 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
203.1334 +  mail_recent (stream,recent);	/* and of change in recent messages */
203.1335 +  return LONGT;			/* return the winnage */
203.1336 +}
203.1337 +
203.1338 +/* Tenex get cache element with status updating from file
203.1339 + * Accepts: MAIL stream
203.1340 + *	    message number
203.1341 + * Returns: cache element
203.1342 + */
203.1343 +
203.1344 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
203.1345 +{
203.1346 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
203.1347 +  struct {			/* old flags */
203.1348 +    unsigned int seen : 1;
203.1349 +    unsigned int deleted : 1;
203.1350 +    unsigned int flagged : 1;
203.1351 +    unsigned int answered : 1;
203.1352 +    unsigned int draft : 1;
203.1353 +    unsigned long user_flags;
203.1354 +  } old;
203.1355 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
203.1356 +  old.answered = elt->answered; old.draft = elt->draft;
203.1357 +  old.user_flags = elt->user_flags;
203.1358 +  tenex_read_flags (stream,elt);
203.1359 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
203.1360 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
203.1361 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
203.1362 +    MM_FLAGS (stream,msgno);	/* let top level know */
203.1363 +  return elt;
203.1364 +}
203.1365 +
203.1366 +/* Tenex read flags from file
203.1367 + * Accepts: MAIL stream
203.1368 + * Returns: cache element
203.1369 + */
203.1370 +
203.1371 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
203.1372 +{
203.1373 +  unsigned long i,j;
203.1374 +				/* noop if readonly and have valid flags */
203.1375 +  if (stream->rdonly && elt->valid) return;
203.1376 +				/* set the seek pointer */
203.1377 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
203.1378 +	 elt->private.special.text.size - 13,L_SET);
203.1379 +				/* read the new flags */
203.1380 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
203.1381 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
203.1382 +    fatal (LOCAL->buf);
203.1383 +  }
203.1384 +				/* calculate system flags */
203.1385 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
203.1386 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
203.1387 +  elt->flagged = i & fFLAGGED ? T : NIL;
203.1388 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
203.1389 +  LOCAL->buf[10] = '\0';	/* tie off flags */
203.1390 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
203.1391 +				/* set up all valid user flags (reversed!) */
203.1392 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
203.1393 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
203.1394 +  elt->valid = T;		/* have valid flags now */
203.1395 +}
203.1396 +
203.1397 +/* Tenex update status string
203.1398 + * Accepts: MAIL stream
203.1399 + *	    message number
203.1400 + *	    flag saying whether or not to sync
203.1401 + */
203.1402 +
203.1403 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
203.1404 +{
203.1405 +  time_t tp[2];
203.1406 +  struct stat sbuf;
203.1407 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
203.1408 +  unsigned long j,k = 0;
203.1409 +				/* readonly */
203.1410 +  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
203.1411 +  else {			/* readwrite */
203.1412 +    j = elt->user_flags;	/* get user flags */
203.1413 +				/* reverse bits (dontcha wish we had CIRC?) */
203.1414 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
203.1415 +				/* print new flag string */
203.1416 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
203.1417 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
203.1418 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
203.1419 +	      (fDRAFT * elt->draft)));
203.1420 +				/* get to that place in the file */
203.1421 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
203.1422 +	   elt->private.special.text.size - 13,L_SET);
203.1423 +				/* write new flags */
203.1424 +    write (LOCAL->fd,LOCAL->buf,12);
203.1425 +    if (syncflag) {		/* sync if requested */
203.1426 +      fsync (LOCAL->fd);
203.1427 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
203.1428 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
203.1429 +      tp[0] = time (0);		/* make sure read is later */
203.1430 +      utime (stream->mailbox,tp);
203.1431 +    }
203.1432 +  }
203.1433 +}
203.1434 +
203.1435 +/* Tenex locate header for a message
203.1436 + * Accepts: MAIL stream
203.1437 + *	    message number
203.1438 + *	    pointer to returned header size
203.1439 + * Returns: position of header in file
203.1440 + */
203.1441 +
203.1442 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
203.1443 +			    unsigned long *size)
203.1444 +{
203.1445 +  unsigned long siz;
203.1446 +  long i = 0;
203.1447 +  char c = '\0';
203.1448 +  char *s = NIL;
203.1449 +  MESSAGECACHE *elt = tenex_elt (stream,msgno);
203.1450 +  unsigned long ret = elt->private.special.offset +
203.1451 +    elt->private.special.text.size;
203.1452 +  unsigned long msiz = tenex_size (stream,msgno);
203.1453 +				/* is header size known? */
203.1454 +  if (!(*size = elt->private.msg.header.text.size)) {
203.1455 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
203.1456 +				/* search message for LF LF */
203.1457 +    for (siz = 0; siz < msiz; siz++) {
203.1458 +      if (--i <= 0)		/* read another buffer as necessary */
203.1459 +	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
203.1460 +				/* two newline sequence? */
203.1461 +      if ((c == '\012') && (*s == '\012')) {
203.1462 +				/* yes, note for later */
203.1463 +	elt->private.msg.header.text.size = (*size = siz + 1);
203.1464 +		
203.1465 +	return ret;		/* return to caller */
203.1466 +      }
203.1467 +      else c = *s++;		/* next character */
203.1468 +    }
203.1469 +				/* header consumes entire message */
203.1470 +    elt->private.msg.header.text.size = *size = msiz;
203.1471 +  }
203.1472 +  return ret;
203.1473 +}
   204.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   204.2 +++ b/src/osdep/amiga/tz_bsd.c	Mon Sep 14 15:17:45 2009 +0900
   204.3 @@ -0,0 +1,38 @@
   204.4 +/* ========================================================================
   204.5 + * Copyright 1988-2006 University of Washington
   204.6 + *
   204.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   204.8 + * you may not use this file except in compliance with the License.
   204.9 + * You may obtain a copy of the License at
  204.10 + *
  204.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  204.12 + *
  204.13 + * 
  204.14 + * ========================================================================
  204.15 + */
  204.16 +
  204.17 +/*
  204.18 + * Program:	BSD-style Time Zone String
  204.19 + *
  204.20 + * Author:	Mark Crispin
  204.21 + *		Networks and Distributed Computing
  204.22 + *		Computing & Communications
  204.23 + *		University of Washington
  204.24 + *		Administration Building, AG-44
  204.25 + *		Seattle, WA  98195
  204.26 + *		Internet: MRC@CAC.Washington.EDU
  204.27 + *
  204.28 + * Date:	30 August 1994
  204.29 + * Last Edited:	30 August 2006
  204.30 + */
  204.31 +
  204.32 +
  204.33 +/* Append local timezone name
  204.34 + * Accepts: destination string
  204.35 + */
  204.36 +
  204.37 +void rfc822_timezone (char *s,void *t)
  204.38 +{
  204.39 +				/* append timezone from tm struct */
  204.40 +  sprintf (s + strlen (s)," (%.50s)",((struct tm *) t)->tm_zone);
  204.41 +}
   205.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   205.2 +++ b/src/osdep/amiga/unix.c	Mon Sep 14 15:17:45 2009 +0900
   205.3 @@ -0,0 +1,2708 @@
   205.4 +/* ========================================================================
   205.5 + * Copyright 1988-2008 University of Washington
   205.6 + *
   205.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   205.8 + * you may not use this file except in compliance with the License.
   205.9 + * You may obtain a copy of the License at
  205.10 + *
  205.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  205.12 + *
  205.13 + * 
  205.14 + * ========================================================================
  205.15 + */
  205.16 +
  205.17 +/*
  205.18 + * Program:	UNIX mail routines
  205.19 + *
  205.20 + * Author:	Mark Crispin
  205.21 + *		UW Technology
  205.22 + *		University of Washington
  205.23 + *		Seattle, WA  98195
  205.24 + *		Internet: MRC@Washington.EDU
  205.25 + *
  205.26 + * Date:	20 December 1989
  205.27 + * Last Edited:	27 March 2008
  205.28 + */
  205.29 +
  205.30 +
  205.31 +/*				DEDICATION
  205.32 + *
  205.33 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  205.34 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  205.35 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  205.36 + * a two-month bout with cirrhosis of the liver.
  205.37 + *
  205.38 + *  He was a dear friend, and I miss him terribly.
  205.39 + *
  205.40 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  205.41 + */
  205.42 +
  205.43 +#include <stdio.h>
  205.44 +#include <ctype.h>
  205.45 +#include <errno.h>
  205.46 +extern int errno;		/* just in case */
  205.47 +#include <signal.h>
  205.48 +#include "mail.h"
  205.49 +#include "osdep.h"
  205.50 +#include <time.h>
  205.51 +#include <sys/stat.h>
  205.52 +#include "unix.h"
  205.53 +#include "pseudo.h"
  205.54 +#include "fdstring.h"
  205.55 +#include "misc.h"
  205.56 +#include "dummy.h"
  205.57 +
  205.58 +/* UNIX I/O stream local data */
  205.59 +
  205.60 +typedef struct unix_local {
  205.61 +  unsigned int dirty : 1;	/* disk copy needs updating */
  205.62 +  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
  205.63 +  unsigned int pseudo : 1;	/* uses a pseudo message */
  205.64 +  unsigned int appending : 1;	/* don't mark new messages as old */
  205.65 +  int fd;			/* mailbox file descriptor */
  205.66 +  int ld;			/* lock file descriptor */
  205.67 +  char *lname;			/* lock file name */
  205.68 +  off_t filesize;		/* file size parsed */
  205.69 +  time_t filetime;		/* last file time */
  205.70 +  time_t lastsnarf;		/* last snarf time (for mbox driver) */
  205.71 +  unsigned char *buf;		/* temporary buffer */
  205.72 +  unsigned long buflen;		/* current size of temporary buffer */
  205.73 +  unsigned long uid;		/* current text uid */
  205.74 +  SIZEDTEXT text;		/* current text */
  205.75 +  unsigned long textlen;	/* current text length */
  205.76 +  char *line;			/* returned line */
  205.77 +  char *linebuf;		/* line readin buffer */
  205.78 +  unsigned long linebuflen;	/* current line readin buffer length */
  205.79 +} UNIXLOCAL;
  205.80 +
  205.81 +
  205.82 +/* Convenient access to local data */
  205.83 +
  205.84 +#define LOCAL ((UNIXLOCAL *) stream->local)
  205.85 +
  205.86 +
  205.87 +/* UNIX protected file structure */
  205.88 +
  205.89 +typedef struct unix_file {
  205.90 +  MAILSTREAM *stream;		/* current stream */
  205.91 +  off_t curpos;			/* current file position */
  205.92 +  off_t protect;		/* protected position */
  205.93 +  off_t filepos;		/* current last written file position */
  205.94 +  char *buf;			/* overflow buffer */
  205.95 +  size_t buflen;		/* current overflow buffer length */
  205.96 +  char *bufpos;			/* current buffer position */
  205.97 +} UNIXFILE;
  205.98 +
  205.99 +/* Function prototypes */
 205.100 +
 205.101 +DRIVER *unix_valid (char *name);
 205.102 +long unix_isvalid_fd (int fd);
 205.103 +void *unix_parameters (long function,void *value);
 205.104 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 205.105 +void unix_list (MAILSTREAM *stream,char *ref,char *pat);
 205.106 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
 205.107 +long unix_create (MAILSTREAM *stream,char *mailbox);
 205.108 +long unix_delete (MAILSTREAM *stream,char *mailbox);
 205.109 +long unix_rename (MAILSTREAM *stream,char *old,char *newname);
 205.110 +MAILSTREAM *unix_open (MAILSTREAM *stream);
 205.111 +void unix_close (MAILSTREAM *stream,long options);
 205.112 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 205.113 +		   unsigned long *length,long flags);
 205.114 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 205.115 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 205.116 +		      unsigned long *length,long flags);
 205.117 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 205.118 +long unix_ping (MAILSTREAM *stream);
 205.119 +void unix_check (MAILSTREAM *stream);
 205.120 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
 205.121 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 205.122 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 205.123 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 205.124 +		     STRING *msg);
 205.125 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
 205.126 +
 205.127 +void unix_abort (MAILSTREAM *stream);
 205.128 +char *unix_file (char *dst,char *name);
 205.129 +int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
 205.130 +void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
 205.131 +int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
 205.132 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
 205.133 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
 205.134 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
 205.135 +			    unsigned long uid,long flag);
 205.136 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
 205.137 +		   long flags);
 205.138 +long unix_extend (MAILSTREAM *stream,unsigned long size);
 205.139 +void unix_write (UNIXFILE *f,char *s,unsigned long i);
 205.140 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
 205.141 +
 205.142 +/* mbox mail routines */
 205.143 +
 205.144 +/* Function prototypes */
 205.145 +
 205.146 +DRIVER *mbox_valid (char *name);
 205.147 +long mbox_create (MAILSTREAM *stream,char *mailbox);
 205.148 +long mbox_delete (MAILSTREAM *stream,char *mailbox);
 205.149 +long mbox_rename (MAILSTREAM *stream,char *old,char *newname);
 205.150 +long mbox_status (MAILSTREAM *stream,char *mbx,long flags);
 205.151 +MAILSTREAM *mbox_open (MAILSTREAM *stream);
 205.152 +long mbox_ping (MAILSTREAM *stream);
 205.153 +void mbox_check (MAILSTREAM *stream);
 205.154 +long mbox_expunge (MAILSTREAM *stream,char *sequence,long options);
 205.155 +long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 205.156 +
 205.157 +
 205.158 +/* UNIX mail routines */
 205.159 +
 205.160 +
 205.161 +/* Driver dispatch used by MAIL */
 205.162 +
 205.163 +DRIVER unixdriver = {
 205.164 +  "unix",			/* driver name */
 205.165 +				/* driver flags */
 205.166 +  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
 205.167 +  (DRIVER *) NIL,		/* next driver */
 205.168 +  unix_valid,			/* mailbox is valid for us */
 205.169 +  unix_parameters,		/* manipulate parameters */
 205.170 +  unix_scan,			/* scan mailboxes */
 205.171 +  unix_list,			/* list mailboxes */
 205.172 +  unix_lsub,			/* list subscribed mailboxes */
 205.173 +  NIL,				/* subscribe to mailbox */
 205.174 +  NIL,				/* unsubscribe from mailbox */
 205.175 +  unix_create,			/* create mailbox */
 205.176 +  unix_delete,			/* delete mailbox */
 205.177 +  unix_rename,			/* rename mailbox */
 205.178 +  mail_status_default,		/* status of mailbox */
 205.179 +  unix_open,			/* open mailbox */
 205.180 +  unix_close,			/* close mailbox */
 205.181 +  NIL,				/* fetch message "fast" attributes */
 205.182 +  NIL,				/* fetch message flags */
 205.183 +  NIL,				/* fetch overview */
 205.184 +  NIL,				/* fetch message envelopes */
 205.185 +  unix_header,			/* fetch message header */
 205.186 +  unix_text,			/* fetch message text */
 205.187 +  NIL,				/* fetch partial message text */
 205.188 +  NIL,				/* unique identifier */
 205.189 +  NIL,				/* message number */
 205.190 +  NIL,				/* modify flags */
 205.191 +  unix_flagmsg,			/* per-message modify flags */
 205.192 +  NIL,				/* search for message based on criteria */
 205.193 +  NIL,				/* sort messages */
 205.194 +  NIL,				/* thread messages */
 205.195 +  unix_ping,			/* ping mailbox to see if still alive */
 205.196 +  unix_check,			/* check for new messages */
 205.197 +  unix_expunge,			/* expunge deleted messages */
 205.198 +  unix_copy,			/* copy messages to another mailbox */
 205.199 +  unix_append,			/* append string message to mailbox */
 205.200 +  NIL				/* garbage collect stream */
 205.201 +};
 205.202 +
 205.203 +				/* prototype stream */
 205.204 +MAILSTREAM unixproto = {&unixdriver};
 205.205 +
 205.206 +				/* driver parameters */
 205.207 +static long unix_fromwidget = T;
 205.208 +
 205.209 +/* UNIX mail validate mailbox
 205.210 + * Accepts: mailbox name
 205.211 + * Returns: our driver if name is valid, NIL otherwise
 205.212 + */
 205.213 +
 205.214 +DRIVER *unix_valid (char *name)
 205.215 +{
 205.216 +  int fd;
 205.217 +  DRIVER *ret = NIL;
 205.218 +  char *t,file[MAILTMPLEN];
 205.219 +  struct stat sbuf;
 205.220 +  time_t tp[2];
 205.221 +  errno = EINVAL;		/* assume invalid argument */
 205.222 +				/* must be non-empty file */
 205.223 +  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
 205.224 +    if (!sbuf.st_size)errno = 0;/* empty file */
 205.225 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 205.226 +				/* OK if mailbox format good */
 205.227 +      if (unix_isvalid_fd (fd)) ret = &unixdriver;
 205.228 +      else errno = -1;		/* invalid format */
 205.229 +      close (fd);		/* close the file */
 205.230 +				/* \Marked status? */
 205.231 +      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
 205.232 +	tp[0] = sbuf.st_atime;	/* yes, preserve atime and mtime */
 205.233 +	tp[1] = sbuf.st_mtime;
 205.234 +	utime (file,tp);	/* set the times */
 205.235 +      }
 205.236 +    }
 205.237 +  }
 205.238 +  return ret;			/* return what we should */
 205.239 +}
 205.240 +
 205.241 +/* UNIX mail test for valid mailbox
 205.242 + * Accepts: file descriptor
 205.243 + *	    scratch buffer
 205.244 + * Returns: T if valid, NIL otherwise
 205.245 + */
 205.246 +
 205.247 +long unix_isvalid_fd (int fd)
 205.248 +{
 205.249 +  int zn;
 205.250 +  int ret = NIL;
 205.251 +  char tmp[MAILTMPLEN],*s,*t,c = '\n';
 205.252 +  memset (tmp,'\0',MAILTMPLEN);
 205.253 +  if (read (fd,tmp,MAILTMPLEN-1) >= 0) {
 205.254 +    for (s = tmp; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');)
 205.255 +      c = *s++;
 205.256 +    if (c == '\n') VALID (s,t,ret,zn);
 205.257 +  }
 205.258 +  return ret;			/* return what we should */
 205.259 +}
 205.260 +
 205.261 +
 205.262 +/* UNIX manipulate driver parameters
 205.263 + * Accepts: function code
 205.264 + *	    function-dependent value
 205.265 + * Returns: function-dependent return value
 205.266 + */
 205.267 +
 205.268 +void *unix_parameters (long function,void *value)
 205.269 +{
 205.270 +  void *ret = NIL;
 205.271 +  switch ((int) function) {
 205.272 +  case GET_INBOXPATH:
 205.273 +    if (value) ret = dummy_file ((char *) value,"INBOX");
 205.274 +    break;
 205.275 +  case SET_FROMWIDGET:
 205.276 +    unix_fromwidget = (long) value;
 205.277 +  case GET_FROMWIDGET:
 205.278 +    ret = (void *) unix_fromwidget;
 205.279 +    break;
 205.280 +  }
 205.281 +  return ret;
 205.282 +}
 205.283 +
 205.284 +/* UNIX mail scan mailboxes
 205.285 + * Accepts: mail stream
 205.286 + *	    reference
 205.287 + *	    pattern to search
 205.288 + *	    string to scan
 205.289 + */
 205.290 +
 205.291 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 205.292 +{
 205.293 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 205.294 +}
 205.295 +
 205.296 +
 205.297 +/* UNIX mail list mailboxes
 205.298 + * Accepts: mail stream
 205.299 + *	    reference
 205.300 + *	    pattern to search
 205.301 + */
 205.302 +
 205.303 +void unix_list (MAILSTREAM *stream,char *ref,char *pat)
 205.304 +{
 205.305 +  if (stream) dummy_list (NIL,ref,pat);
 205.306 +}
 205.307 +
 205.308 +
 205.309 +/* UNIX mail list subscribed mailboxes
 205.310 + * Accepts: mail stream
 205.311 + *	    reference
 205.312 + *	    pattern to search
 205.313 + */
 205.314 +
 205.315 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
 205.316 +{
 205.317 +  if (stream) dummy_lsub (NIL,ref,pat);
 205.318 +}
 205.319 +
 205.320 +/* UNIX mail create mailbox
 205.321 + * Accepts: MAIL stream
 205.322 + *	    mailbox name to create
 205.323 + * Returns: T on success, NIL on failure
 205.324 + */
 205.325 +
 205.326 +long unix_create (MAILSTREAM *stream,char *mailbox)
 205.327 +{
 205.328 +  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
 205.329 +  long ret = NIL;
 205.330 +  int i,fd;
 205.331 +  time_t ti = time (0);
 205.332 +  if (!(s = dummy_file (mbx,mailbox))) {
 205.333 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 205.334 +    MM_LOG (tmp,ERROR);
 205.335 +  }
 205.336 +				/* create underlying file */
 205.337 +  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
 205.338 +				/* done if dir-only or whiner */
 205.339 +    if (((s = strrchr (s,'/')) && !s[1]) ||
 205.340 +	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
 205.341 +    else if ((fd = open (mbx,O_WRONLY,
 205.342 +		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
 205.343 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 205.344 +      MM_LOG (tmp,ERROR);
 205.345 +      unlink (mbx);		/* delete the file */
 205.346 +    }
 205.347 +    else {			/* initialize header */
 205.348 +      memset (tmp,'\0',MAILTMPLEN);
 205.349 +      sprintf (tmp,"From %s %sDate: ",pseudo_from,ctime (&ti));
 205.350 +      rfc822_fixed_date (s = tmp + strlen (tmp));
 205.351 +				/* write the pseudo-header */
 205.352 +      sprintf (s += strlen (s),
 205.353 +	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
 205.354 +	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
 205.355 +	       (unsigned long) ti);
 205.356 +      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
 205.357 +	sprintf (s += strlen (s)," %s",default_user_flag (i));
 205.358 +      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
 205.359 +      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
 205.360 +      else {
 205.361 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
 205.362 +		 strerror (errno));
 205.363 +	MM_LOG (tmp,ERROR);
 205.364 +	unlink (mbx);		/* delete the file */
 205.365 +      }
 205.366 +      close (fd);		/* close file */
 205.367 +    }
 205.368 +  }
 205.369 +				/* set proper protections */
 205.370 +  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
 205.371 +}
 205.372 +
 205.373 +/* UNIX mail delete mailbox
 205.374 + * Accepts: MAIL stream
 205.375 + *	    mailbox name to delete
 205.376 + * Returns: T on success, NIL on failure
 205.377 + */
 205.378 +
 205.379 +long unix_delete (MAILSTREAM *stream,char *mailbox)
 205.380 +{
 205.381 +  return unix_rename (stream,mailbox,NIL);
 205.382 +}
 205.383 +
 205.384 +
 205.385 +/* UNIX mail rename mailbox
 205.386 + * Accepts: MAIL stream
 205.387 + *	    old mailbox name
 205.388 + *	    new mailbox name (or NIL for delete)
 205.389 + * Returns: T on success, NIL on failure
 205.390 + */
 205.391 +
 205.392 +long unix_rename (MAILSTREAM *stream,char *old,char *newname)
 205.393 +{
 205.394 +  long ret = NIL;
 205.395 +  char c,*s = NIL;
 205.396 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 205.397 +  DOTLOCK lockx;
 205.398 +  int fd,ld;
 205.399 +  long i;
 205.400 +  struct stat sbuf;
 205.401 +  MM_CRITICAL (stream);		/* get the c-client lock */
 205.402 +  if (!dummy_file (file,old) ||
 205.403 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 205.404 +		   ((s = strrchr (tmp,'/')) && !s[1]))))
 205.405 +    sprintf (tmp,newname ?
 205.406 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 205.407 +	     "Can't delete mailbox %.80s: invalid name",
 205.408 +	     old,newname);
 205.409 +				/* lock out other c-clients */
 205.410 +  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
 205.411 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 205.412 +
 205.413 +  else {
 205.414 +    if ((fd = unix_lock (file,O_RDWR,
 205.415 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
 205.416 +			 &lockx,LOCK_EX)) < 0)
 205.417 +      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
 205.418 +    else {
 205.419 +      if (newname) {		/* want rename? */
 205.420 +				/* found superior to destination name? */
 205.421 +	if (s = strrchr (s,'/')) {
 205.422 +	  c = *++s;		/* remember first character of inferior */
 205.423 +	  *s = '\0';		/* tie off to get just superior */
 205.424 +				/* name doesn't exist, create it */
 205.425 +	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 205.426 +	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
 205.427 +	    unix_unlock (fd,NIL,&lockx);
 205.428 +	    unix_unlock (ld,NIL,NIL);
 205.429 +	    unlink (lock);
 205.430 +	    MM_NOCRITICAL (stream);
 205.431 +	    return ret;		/* return success or failure */
 205.432 +	  }
 205.433 +	  *s = c;		/* restore full name */
 205.434 +	}
 205.435 +	if (rename (file,tmp))
 205.436 +	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 205.437 +		   strerror (errno));
 205.438 +	else ret = T;		/* set success */
 205.439 +      }
 205.440 +      else if (unlink (file))
 205.441 +	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 205.442 +      else ret = T;		/* set success */
 205.443 +      unix_unlock (fd,NIL,&lockx);
 205.444 +    }
 205.445 +    unix_unlock (ld,NIL,NIL);	/* flush the lock */
 205.446 +    unlink (lock);
 205.447 +  }
 205.448 +  MM_NOCRITICAL (stream);	/* no longer critical */
 205.449 +  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
 205.450 +  return ret;			/* return success or failure */
 205.451 +}
 205.452 +
 205.453 +/* UNIX mail open
 205.454 + * Accepts: Stream to open
 205.455 + * Returns: Stream on success, NIL on failure
 205.456 + */
 205.457 +
 205.458 +MAILSTREAM *unix_open (MAILSTREAM *stream)
 205.459 +{
 205.460 +  long i;
 205.461 +  int fd;
 205.462 +  char tmp[MAILTMPLEN];
 205.463 +  DOTLOCK lock;
 205.464 +  long retry;
 205.465 +				/* return prototype for OP_PROTOTYPE call */
 205.466 +  if (!stream) return user_flags (&unixproto);
 205.467 +  retry = stream->silent ? 1 : KODRETRY;
 205.468 +  if (stream->local) fatal ("unix recycle stream");
 205.469 +  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
 205.470 +				/* note if an INBOX or not */
 205.471 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 205.472 +				/* canonicalize the stream mailbox name */
 205.473 +  if (!dummy_file (tmp,stream->mailbox)) {
 205.474 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 205.475 +    MM_LOG (tmp,ERROR);
 205.476 +    return NIL;
 205.477 +  }
 205.478 +				/* flush old name */
 205.479 +  fs_give ((void **) &stream->mailbox);
 205.480 +				/* save canonical name */
 205.481 +  stream->mailbox = cpystr (tmp);
 205.482 +  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
 205.483 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 205.484 +  LOCAL->buflen = CHUNKSIZE - 1;
 205.485 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 205.486 +  LOCAL->text.size = CHUNKSIZE - 1;
 205.487 +  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
 205.488 +  LOCAL->linebuflen = CHUNKSIZE - 1;
 205.489 +  stream->sequence++;		/* bump sequence number */
 205.490 +
 205.491 +				/* make lock for read/write access */
 205.492 +  if (!stream->rdonly) while (retry) {
 205.493 +				/* try to lock file */
 205.494 +    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
 205.495 +				/* suppressing kiss-of-death? */
 205.496 +      if (stream->nokod) retry = 0;
 205.497 +				/* no, first time through? */
 205.498 +      else if (retry-- == KODRETRY) {
 205.499 +				/* learned other guy's PID and can signal? */
 205.500 +	if (i && !kill ((int) i,SIGUSR2)) {
 205.501 +	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
 205.502 +	  MM_LOG (tmp,WARN);
 205.503 +	}
 205.504 +	else retry = 0;		/* give up */
 205.505 +      }
 205.506 +      if (!stream->silent) {	/* nothing if silent stream */
 205.507 +	if (retry) sleep (1);	/* wait a second before trying again */
 205.508 +	else MM_LOG ("Mailbox is open by another process, access is readonly",
 205.509 +		     WARN);
 205.510 +      }
 205.511 +    }
 205.512 +    else {			/* got the lock, nobody else can alter state */
 205.513 +      LOCAL->ld = fd;		/* note lock's fd and name */
 205.514 +      LOCAL->lname = cpystr (tmp);
 205.515 +				/* make sure mode OK (don't use fchmod()) */
 205.516 +      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
 205.517 +      if (stream->silent) i = 0;/* silent streams won't accept KOD */
 205.518 +      else {			/* note our PID in the lock */
 205.519 +	sprintf (tmp,"%d",getpid ());
 205.520 +	write (fd,tmp,(i = strlen (tmp))+1);
 205.521 +      }
 205.522 +      ftruncate (fd,i);		/* make sure tied off */
 205.523 +      fsync (fd);		/* make sure it's available */
 205.524 +      retry = 0;		/* no more need to try */
 205.525 +    }
 205.526 +  }
 205.527 +
 205.528 +				/* parse mailbox */
 205.529 +  stream->nmsgs = stream->recent = 0;
 205.530 +				/* will we be able to get write access? */
 205.531 +  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
 205.532 +    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 205.533 +    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
 205.534 +    close (LOCAL->ld);		/* close the lock file */
 205.535 +    LOCAL->ld = -1;		/* no more lock fd */
 205.536 +    unlink (LOCAL->lname);	/* delete it */
 205.537 +  }
 205.538 +				/* reset UID validity */
 205.539 +  stream->uid_validity = stream->uid_last = 0;
 205.540 +  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
 205.541 +    unix_abort (stream);	/* abort if can't get RW silent stream */
 205.542 +				/* parse mailbox */
 205.543 +  else if (unix_parse (stream,&lock,LOCK_SH)) {
 205.544 +    unix_unlock (LOCAL->fd,stream,&lock);
 205.545 +    mail_unlock (stream);
 205.546 +    MM_NOCRITICAL (stream);	/* done with critical */
 205.547 +  }
 205.548 +  if (!LOCAL) return NIL;	/* failure if stream died */
 205.549 +				/* make sure upper level knows readonly */
 205.550 +  stream->rdonly = (LOCAL->ld < 0);
 205.551 +				/* notify about empty mailbox */
 205.552 +  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
 205.553 +  if (!stream->rdonly) {	/* flags stick if readwrite */
 205.554 +    stream->perm_seen = stream->perm_deleted =
 205.555 +      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
 205.556 +    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
 205.557 +      stream->perm_user_flags = 0xffffffff;
 205.558 +				/* and maybe can create them too! */
 205.559 +      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
 205.560 +    }
 205.561 +  }
 205.562 +  return stream;		/* return stream alive to caller */
 205.563 +}
 205.564 +
 205.565 +
 205.566 +/* UNIX mail close
 205.567 + * Accepts: MAIL stream
 205.568 + *	    close options
 205.569 + */
 205.570 +
 205.571 +void unix_close (MAILSTREAM *stream,long options)
 205.572 +{
 205.573 +  int silent = stream->silent;
 205.574 +  stream->silent = T;		/* go silent */
 205.575 +				/* expunge if requested */
 205.576 +  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
 205.577 +				/* else dump final checkpoint */
 205.578 +  else if (LOCAL->dirty) unix_check (stream);
 205.579 +  stream->silent = silent;	/* restore old silence state */
 205.580 +  unix_abort (stream);		/* now punt the file and local data */
 205.581 +}
 205.582 +
 205.583 +/* UNIX mail fetch message header
 205.584 + * Accepts: MAIL stream
 205.585 + *	    message # to fetch
 205.586 + *	    pointer to returned header text length
 205.587 + *	    option flags
 205.588 + * Returns: message header in RFC822 format
 205.589 + */
 205.590 +
 205.591 +				/* lines to filter from header */
 205.592 +static STRINGLIST *unix_hlines = NIL;
 205.593 +
 205.594 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 205.595 +		   unsigned long *length,long flags)
 205.596 +{
 205.597 +  MESSAGECACHE *elt;
 205.598 +  unsigned char *s,*t,*tl;
 205.599 +  *length = 0;			/* default to empty */
 205.600 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 205.601 +  elt = mail_elt (stream,msgno);/* get cache */
 205.602 +  if (!unix_hlines) {		/* once only code */
 205.603 +    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
 205.604 +    lines->text.size = strlen ((char *) (lines->text.data =
 205.605 +					 (unsigned char *) "Status"));
 205.606 +    lines = lines->next = mail_newstringlist ();
 205.607 +    lines->text.size = strlen ((char *) (lines->text.data =
 205.608 +					 (unsigned char *) "X-Status"));
 205.609 +    lines = lines->next = mail_newstringlist ();
 205.610 +    lines->text.size = strlen ((char *) (lines->text.data =
 205.611 +					 (unsigned char *) "X-Keywords"));
 205.612 +    lines = lines->next = mail_newstringlist ();
 205.613 +    lines->text.size = strlen ((char *) (lines->text.data =
 205.614 +					 (unsigned char *) "X-UID"));
 205.615 +    lines = lines->next = mail_newstringlist ();
 205.616 +    lines->text.size = strlen ((char *) (lines->text.data =
 205.617 +					 (unsigned char *) "X-IMAP"));
 205.618 +    lines = lines->next = mail_newstringlist ();
 205.619 +    lines->text.size = strlen ((char *) (lines->text.data =
 205.620 +					 (unsigned char *) "X-IMAPbase"));
 205.621 +  }
 205.622 +				/* go to header position */
 205.623 +  lseek (LOCAL->fd,elt->private.special.offset +
 205.624 +	 elt->private.msg.header.offset,L_SET);
 205.625 +
 205.626 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 205.627 +    if (elt->private.msg.header.text.size > LOCAL->buflen) {
 205.628 +      fs_give ((void **) &LOCAL->buf);
 205.629 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 205.630 +				     elt->private.msg.header.text.size) + 1);
 205.631 +    }
 205.632 +				/* read message */
 205.633 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
 205.634 +				/* got text, tie off string */
 205.635 +    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
 205.636 +				/* squeeze out CRs (in case from PC) */
 205.637 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 205.638 +      if (*t != '\r') *s++ = *t;
 205.639 +    *s = '\0';
 205.640 +    *length = s - LOCAL->buf;	/* adjust length */
 205.641 +  }
 205.642 +  else {			/* need to make a CRLF version */
 205.643 +    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
 205.644 +	  elt->private.msg.header.text.size);
 205.645 +				/* tie off string, and convert to CRLF */
 205.646 +    s[elt->private.msg.header.text.size] = '\0';
 205.647 +    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
 205.648 +			  elt->private.msg.header.text.size);
 205.649 +    fs_give ((void **) &s);	/* free readin buffer */
 205.650 +				/* squeeze out spurious CRs */
 205.651 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 205.652 +      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
 205.653 +    *s = '\0';
 205.654 +    *length = s - LOCAL->buf;	/* adjust length */
 205.655 +  }
 205.656 +  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
 205.657 +  return (char *) LOCAL->buf;	/* return processed copy */
 205.658 +}
 205.659 +
 205.660 +/* UNIX mail fetch message text
 205.661 + * Accepts: MAIL stream
 205.662 + *	    message # to fetch
 205.663 + *	    pointer to returned stringstruct
 205.664 + *	    option flags
 205.665 + * Returns: T on success, NIL if failure
 205.666 + */
 205.667 +
 205.668 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 205.669 +{
 205.670 +  char *s;
 205.671 +  unsigned long i;
 205.672 +  MESSAGECACHE *elt;
 205.673 +				/* UID call "impossible" */
 205.674 +  if (flags & FT_UID) return NIL;
 205.675 +  elt = mail_elt (stream,msgno);/* get cache element */
 205.676 +				/* if message not seen */
 205.677 +  if (!(flags & FT_PEEK) && !elt->seen) {
 205.678 +				/* mark message seen and dirty */
 205.679 +    elt->seen = elt->private.dirty = LOCAL->dirty = T;
 205.680 +    MM_FLAGS (stream,msgno);
 205.681 +  }
 205.682 +  s = unix_text_work (stream,elt,&i,flags);
 205.683 +  INIT (bs,mail_string,s,i);	/* set up stringstruct */
 205.684 +  return T;			/* success */
 205.685 +}
 205.686 +
 205.687 +/* UNIX mail fetch message text worker routine
 205.688 + * Accepts: MAIL stream
 205.689 + *	    message cache element
 205.690 + *	    pointer to returned header text length
 205.691 + *	    option flags
 205.692 + */
 205.693 +
 205.694 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 205.695 +		      unsigned long *length,long flags)
 205.696 +{
 205.697 +  FDDATA d;
 205.698 +  STRING bs;
 205.699 +  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
 205.700 +				/* go to text position */
 205.701 +  lseek (LOCAL->fd,elt->private.special.offset +
 205.702 +	 elt->private.msg.text.offset,L_SET);
 205.703 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 205.704 +    if (elt->private.msg.text.text.size > LOCAL->buflen) {
 205.705 +      fs_give ((void **) &LOCAL->buf);
 205.706 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 205.707 +				     elt->private.msg.text.text.size) + 1);
 205.708 +    }
 205.709 +				/* read message */
 205.710 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
 205.711 +				/* got text, tie off string */
 205.712 +    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
 205.713 +				/* squeeze out CRs (in case from PC) */
 205.714 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 205.715 +      if (*t != '\r') *s++ = *t;
 205.716 +    *s = '\0';
 205.717 +    *length = s - LOCAL->buf;	/* adjust length */
 205.718 +    return (char *) LOCAL->buf;
 205.719 +  }
 205.720 +
 205.721 +				/* have it cached already? */
 205.722 +  if (elt->private.uid != LOCAL->uid) {
 205.723 +				/* not cached, cache it now */
 205.724 +    LOCAL->uid = elt->private.uid;
 205.725 +				/* is buffer big enough? */
 205.726 +    if (elt->rfc822_size > LOCAL->text.size) {
 205.727 +      /* excessively conservative, but the right thing is too hard to do */
 205.728 +      fs_give ((void **) &LOCAL->text.data);
 205.729 +      LOCAL->text.data = (unsigned char *)
 205.730 +	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
 205.731 +    }
 205.732 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
 205.733 +    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
 205.734 +    d.chunk = tmp;		/* initial buffer chunk */
 205.735 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
 205.736 +    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
 205.737 +    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
 205.738 +    case '\r':			/* carriage return seen */
 205.739 +      break;
 205.740 +    case '\n':
 205.741 +      *s++ = '\r';		/* insert a CR */
 205.742 +    default:
 205.743 +      *s++ = c;			/* copy characters */
 205.744 +    }
 205.745 +    *s = '\0';			/* tie off buffer */
 205.746 +				/* calculate length of cached data */
 205.747 +    LOCAL->textlen = s - LOCAL->text.data;
 205.748 +  }
 205.749 +  *length = LOCAL->textlen;	/* return from cache */
 205.750 +  return (char *) LOCAL->text.data;
 205.751 +}
 205.752 +
 205.753 +/* UNIX per-message modify flag
 205.754 + * Accepts: MAIL stream
 205.755 + *	    message cache element
 205.756 + */
 205.757 +
 205.758 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 205.759 +{
 205.760 +				/* only after finishing */
 205.761 +  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
 205.762 +}
 205.763 +
 205.764 +
 205.765 +/* UNIX mail ping mailbox
 205.766 + * Accepts: MAIL stream
 205.767 + * Returns: T if stream alive, else NIL
 205.768 + */
 205.769 +
 205.770 +long unix_ping (MAILSTREAM *stream)
 205.771 +{
 205.772 +  DOTLOCK lock;
 205.773 +  struct stat sbuf;
 205.774 +  long reparse;
 205.775 +				/* big no-op if not readwrite */
 205.776 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
 205.777 +    if (stream->rdonly) {	/* does he want to give up readwrite? */
 205.778 +				/* checkpoint if we changed something */
 205.779 +      if (LOCAL->dirty) unix_check (stream);
 205.780 +      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
 205.781 +      close (LOCAL->ld);	/* close the readwrite lock file */
 205.782 +      LOCAL->ld = -1;		/* no more readwrite lock fd */
 205.783 +      unlink (LOCAL->lname);	/* delete the readwrite lock file */
 205.784 +    }
 205.785 +    else {			/* see if need to reparse */
 205.786 +      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
 205.787 +				/* get current mailbox size */
 205.788 +	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
 205.789 +	else if (stat (stream->mailbox,&sbuf)) {
 205.790 +	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
 205.791 +		   strerror (errno));
 205.792 +	  MM_LOG (LOCAL->buf,ERROR);
 205.793 +	  unix_abort (stream);
 205.794 +	  return NIL;
 205.795 +	}
 205.796 +	reparse = (sbuf.st_size != LOCAL->filesize);
 205.797 +      }
 205.798 +				/* parse if mailbox changed */
 205.799 +      if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) {
 205.800 +				/* force checkpoint if double-dirty */
 205.801 +	if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL);
 205.802 +				/* unlock mailbox */
 205.803 +	else unix_unlock (LOCAL->fd,stream,&lock);
 205.804 +	mail_unlock (stream);	/* and stream */
 205.805 +	MM_NOCRITICAL (stream);	/* done with critical */
 205.806 +      }
 205.807 +    }
 205.808 +  }
 205.809 +  return LOCAL ? LONGT : NIL;	/* return if still alive */
 205.810 +}
 205.811 +
 205.812 +/* UNIX mail check mailbox
 205.813 + * Accepts: MAIL stream
 205.814 + */
 205.815 +
 205.816 +void unix_check (MAILSTREAM *stream)
 205.817 +{
 205.818 +  DOTLOCK lock;
 205.819 +				/* parse and lock mailbox */
 205.820 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 205.821 +      unix_parse (stream,&lock,LOCK_EX)) {
 205.822 +				/* any unsaved changes? */
 205.823 +    if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) {
 205.824 +      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
 205.825 +    }
 205.826 +				/* no checkpoint needed, just unlock */
 205.827 +    else unix_unlock (LOCAL->fd,stream,&lock);
 205.828 +    mail_unlock (stream);	/* unlock the stream */
 205.829 +    MM_NOCRITICAL (stream);	/* done with critical */
 205.830 +  }
 205.831 +}
 205.832 +
 205.833 +
 205.834 +/* UNIX mail expunge mailbox
 205.835 + * Accepts: MAIL stream
 205.836 + *	    sequence to expunge if non-NIL
 205.837 + *	    expunge options
 205.838 + * Returns: T, always
 205.839 + */
 205.840 +
 205.841 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
 205.842 +{
 205.843 +  long ret;
 205.844 +  unsigned long i;
 205.845 +  DOTLOCK lock;
 205.846 +  char *msg = NIL;
 205.847 +				/* parse and lock mailbox */
 205.848 +  if (ret = (sequence ? ((options & EX_UID) ?
 205.849 +			 mail_uid_sequence (stream,sequence) :
 205.850 +			 mail_sequence (stream,sequence)) : LONGT) &&
 205.851 +      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 205.852 +      unix_parse (stream,&lock,LOCK_EX)) {
 205.853 +				/* check expunged messages if not dirty */
 205.854 +    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
 205.855 +      MESSAGECACHE *elt = mail_elt (stream,i);
 205.856 +      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
 205.857 +    }
 205.858 +    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
 205.859 +      unix_unlock (LOCAL->fd,stream,&lock);
 205.860 +      msg = "No messages deleted, so no update needed";
 205.861 +    }
 205.862 +    else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
 205.863 +      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
 205.864 +      else msg = "Mailbox checkpointed, but no messages expunged";
 205.865 +    }
 205.866 +				/* rewrite failed */
 205.867 +    else unix_unlock (LOCAL->fd,stream,&lock);
 205.868 +    mail_unlock (stream);	/* unlock the stream */
 205.869 +    MM_NOCRITICAL (stream);	/* done with critical */
 205.870 +    if (msg && !stream->silent) MM_LOG (msg,NIL);
 205.871 +  }
 205.872 +  else if (!stream->silent) MM_LOG("Expunge ignored on readonly mailbox",WARN);
 205.873 +  return ret;
 205.874 +}
 205.875 +
 205.876 +/* UNIX mail copy message(s)
 205.877 + * Accepts: MAIL stream
 205.878 + *	    sequence
 205.879 + *	    destination mailbox
 205.880 + *	    copy options
 205.881 + * Returns: T if copy successful, else NIL
 205.882 + */
 205.883 +
 205.884 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 205.885 +{
 205.886 +  struct stat sbuf;
 205.887 +  int fd;
 205.888 +  char *s,file[MAILTMPLEN];
 205.889 +  DOTLOCK lock;
 205.890 +  time_t tp[2];
 205.891 +  unsigned long i,j;
 205.892 +  MESSAGECACHE *elt;
 205.893 +  long ret = T;
 205.894 +  mailproxycopy_t pc =
 205.895 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 205.896 +  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
 205.897 +			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
 205.898 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 205.899 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 205.900 +  MAILSTREAM *tstream = NIL;
 205.901 +  DRIVER *d;
 205.902 +  for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
 205.903 +       (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE));
 205.904 +       d = d->next);		/* see if mbox driver active */
 205.905 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 205.906 +	mail_sequence (stream,sequence))) return NIL;
 205.907 +				/* make sure destination is valid */
 205.908 +  if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) ||
 205.909 +	unix_valid (mailbox) || !errno))
 205.910 +    switch (errno) {
 205.911 +    case ENOENT:		/* no such file? */
 205.912 +      if (compare_cstring (mailbox,"INBOX")) {
 205.913 +	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 205.914 +	return NIL;
 205.915 +      }
 205.916 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 205.917 +      unix_create (NIL,"INBOX");/* create empty INBOX */
 205.918 +    case EACCES:		/* file protected */
 205.919 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 205.920 +      MM_LOG (LOCAL->buf,ERROR);
 205.921 +      return NIL;
 205.922 +    case EINVAL:
 205.923 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 205.924 +      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
 205.925 +      MM_LOG (LOCAL->buf,ERROR);
 205.926 +      return NIL;
 205.927 +    default:
 205.928 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 205.929 +      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
 205.930 +      MM_LOG (LOCAL->buf,ERROR);
 205.931 +      return NIL;
 205.932 +    }
 205.933 +
 205.934 +				/* try to open rewrite for UIDPLUS */
 205.935 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
 205.936 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
 205.937 +    tstream = mail_close (tstream);
 205.938 +  if (cu && !tstream) {		/* wanted a COPYUID? */
 205.939 +    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
 205.940 +	     mailbox);
 205.941 +    MM_LOG (LOCAL->buf,WARN);
 205.942 +    cu = NIL;			/* don't try to do COPYUID */
 205.943 +  }
 205.944 +  LOCAL->buf[0] = '\0';
 205.945 +  MM_CRITICAL (stream);		/* go critical */
 205.946 +  if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
 205.947 +		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
 205.948 +		       &lock,LOCK_EX)) < 0) {
 205.949 +    MM_NOCRITICAL (stream);	/* done with critical */
 205.950 +    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
 205.951 +    MM_LOG (LOCAL->buf,ERROR);/* log the error */
 205.952 +    return NIL;			/* failed */
 205.953 +  }
 205.954 +  fstat (fd,&sbuf);		/* get current file size */
 205.955 +				/* write all requested messages to mailbox */
 205.956 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
 205.957 +    if ((elt = mail_elt (stream,i))->sequence) {
 205.958 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 205.959 +      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
 205.960 +      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
 205.961 +      else {			/* internal header succeeded */
 205.962 +	s = unix_header (stream,i,&j,FT_INTERNAL);
 205.963 +				/* header size, sans trailing newline */
 205.964 +	if (j && (s[j - 2] == '\n')) j--;
 205.965 +	if (write (fd,s,j) < 0) ret = NIL;
 205.966 +	else {			/* message header succeeded */
 205.967 +	  j = tstream ?		/* write UIDPLUS data if have readwrite */
 205.968 +	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
 205.969 +	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
 205.970 +	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 205.971 +	  else {		/* message status succeeded */
 205.972 +	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
 205.973 +	    if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL;
 205.974 +	    else if (cu) {	/* need to pass back new UID? */
 205.975 +	      mail_append_set (source,mail_uid (stream,i));
 205.976 +	      mail_append_set (dest,tstream->uid_last);
 205.977 +	    }
 205.978 +	  }
 205.979 +	}
 205.980 +      }
 205.981 +    }
 205.982 +
 205.983 +  if (!ret || fsync (fd)) {	/* force out the update */
 205.984 +    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
 205.985 +    ftruncate (fd,sbuf.st_size);
 205.986 +    ret = NIL;
 205.987 +  }
 205.988 +				/* force UIDVALIDITY assignment now */
 205.989 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
 205.990 +				/* return sets if doing COPYUID */
 205.991 +  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
 205.992 +  else {			/* flush any sets we may have built */
 205.993 +    mail_free_searchset (&source);
 205.994 +    mail_free_searchset (&dest);
 205.995 +  }
 205.996 +  tp[1] = time (0);		/* set mtime to now */
 205.997 +  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
 205.998 +  else tp[0] =			/* else preserve \Marked status */
 205.999 +	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
205.1000 +	 sbuf.st_atime : tp[1];
205.1001 +  utime (file,tp);		/* set the times */
205.1002 +  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
205.1003 +  if (tstream) {		/* update last UID if we can */
205.1004 +    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
205.1005 +    local->dirty = T;		/* do a rewrite */
205.1006 +    local->appending = T;	/* but not at the cost of marking as old */
205.1007 +    tstream = mail_close (tstream);
205.1008 +  }
205.1009 +				/* log the error */
205.1010 +  if (!ret) MM_LOG (LOCAL->buf,ERROR);
205.1011 +				/* delete if requested message */
205.1012 +  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
205.1013 +    if ((elt = mail_elt (stream,i))->sequence)
205.1014 +      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
205.1015 +  MM_NOCRITICAL (stream);	/* release critical */
205.1016 +  return ret;
205.1017 +}
205.1018 +
205.1019 +/* UNIX mail append message from stringstruct
205.1020 + * Accepts: MAIL stream
205.1021 + *	    destination mailbox
205.1022 + *	    append callback
205.1023 + *	    data for callback
205.1024 + * Returns: T if append successful, else NIL
205.1025 + */
205.1026 +
205.1027 +#define BUFLEN 8*MAILTMPLEN
205.1028 +
205.1029 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
205.1030 +{
205.1031 +  struct stat sbuf;
205.1032 +  int fd;
205.1033 +  unsigned long i;
205.1034 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
205.1035 +  time_t tp[2];
205.1036 +  FILE *sf,*df;
205.1037 +  MESSAGECACHE elt;
205.1038 +  DOTLOCK lock;
205.1039 +  STRING *message;
205.1040 +  unsigned long uidlocation = 0;
205.1041 +  appenduid_t au = (appenduid_t)
205.1042 +    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
205.1043 +     mail_parameters (NIL,GET_APPENDUID,NIL));
205.1044 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
205.1045 +  long ret = LONGT;
205.1046 +  MAILSTREAM *tstream = NIL;
205.1047 +  if (!stream) {		/* stream specified? */
205.1048 +    stream = &unixproto;	/* no, default stream to prototype */
205.1049 +    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
205.1050 +      fs_give ((void **) &stream->user_flags[i]);
205.1051 +  }
205.1052 +  if (!unix_valid (mailbox)) switch (errno) {
205.1053 +  case ENOENT:			/* no such file? */
205.1054 +    if (compare_cstring (mailbox,"INBOX")) {
205.1055 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
205.1056 +      return NIL;
205.1057 +    }
205.1058 +    unix_create (NIL,"INBOX");	/* create empty INBOX */
205.1059 +  case 0:			/* merely empty file? */
205.1060 +    tstream = stream;
205.1061 +    break;
205.1062 +  case EACCES:			/* file protected */
205.1063 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
205.1064 +    MM_LOG (tmp,ERROR);
205.1065 +    return NIL;
205.1066 +  case EINVAL:
205.1067 +    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
205.1068 +    MM_LOG (tmp,ERROR);
205.1069 +    return NIL;
205.1070 +  default:
205.1071 +    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
205.1072 +    MM_LOG (tmp,ERROR);
205.1073 +    return NIL;
205.1074 +  }
205.1075 +				/* get sniffing stream for keywords */
205.1076 +  else if (!(tstream = mail_open (NIL,mailbox,
205.1077 +				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
205.1078 +    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
205.1079 +    MM_LOG (tmp,ERROR);
205.1080 +    return NIL;
205.1081 +  }
205.1082 +
205.1083 +				/* get first message */
205.1084 +  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
205.1085 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
205.1086 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
205.1087 +    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
205.1088 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
205.1089 +      MM_LOG (tmp,ERROR);
205.1090 +      return NIL;
205.1091 +    }
205.1092 +    unlink (tmp);
205.1093 +  }
205.1094 +  do {				/* parse date */
205.1095 +    if (!date) rfc822_date (date = tmp);
205.1096 +    if (!mail_parse_date (&elt,date)) {
205.1097 +      sprintf (tmp,"Bad date in append: %.80s",date);
205.1098 +      MM_LOG (tmp,ERROR);
205.1099 +    }
205.1100 +    else {			/* user wants to suppress time zones? */
205.1101 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
205.1102 +	time_t when = mail_longdate (&elt);
205.1103 +	date = ctime (&when);	/* use traditional date */
205.1104 +      }
205.1105 +				/* use POSIX-style date */
205.1106 +      else date = mail_cdate (tmp,&elt);
205.1107 +      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
205.1108 +      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
205.1109 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
205.1110 +	MM_LOG (tmp,ERROR);
205.1111 +      }
205.1112 +				/* get next message */
205.1113 +      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
205.1114 +    }
205.1115 +    fclose (sf);		/* punt scratch file */
205.1116 +    return NIL;			/* give up */
205.1117 +  } while (message);		/* until no more messages */
205.1118 +  if (fflush (sf)) {
205.1119 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
205.1120 +    MM_LOG (tmp,ERROR);
205.1121 +    fclose (sf);		/* punt scratch file */
205.1122 +    return NIL;			/* give up */
205.1123 +  }
205.1124 +  i = ftell (sf);		/* size of scratch file */
205.1125 +				/* close sniffing stream */
205.1126 +  if (tstream != stream) tstream = mail_close (tstream);
205.1127 +
205.1128 +  MM_CRITICAL (stream);		/* go critical */
205.1129 +				/* try to open readwrite for UIDPLUS */
205.1130 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
205.1131 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
205.1132 +    tstream = mail_close (tstream);
205.1133 +  if (au && !tstream) {		/* wanted an APPENDUID? */
205.1134 +    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
205.1135 +    MM_LOG (tmp,WARN);
205.1136 +    au = NIL;
205.1137 +  }
205.1138 +  if (((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
205.1139 +		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
205.1140 +			&lock,LOCK_EX)) < 0) ||
205.1141 +      !(df = fdopen (fd,"ab"))) {
205.1142 +    MM_NOCRITICAL (stream);	/* done with critical */
205.1143 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
205.1144 +    MM_LOG (tmp,ERROR);
205.1145 +    return NIL;
205.1146 +  }
205.1147 +  fstat (fd,&sbuf);		/* get current file size */
205.1148 +  rewind (sf);
205.1149 +  tp[1] = time (0);		/* set mtime to now */
205.1150 +				/* write all messages */
205.1151 +  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
205.1152 +      (fflush (df) == EOF) || fsync (fd)) {
205.1153 +    sprintf (buf,"Message append failed: %s",strerror (errno));
205.1154 +    MM_LOG (buf,ERROR);
205.1155 +    ftruncate (fd,sbuf.st_size);
205.1156 +    tp[0] =			/* preserve \Marked status */
205.1157 +      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
205.1158 +      sbuf.st_atime : tp[1];
205.1159 +    ret = NIL;			/* return error */
205.1160 +  }
205.1161 +  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
205.1162 +  utime (file,tp);		/* set the times */
205.1163 +  fclose (sf);			/* done with scratch file */
205.1164 +				/* force UIDVALIDITY assignment now */
205.1165 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
205.1166 +				/* return sets if doing APPENDUID */
205.1167 +  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
205.1168 +  else mail_free_searchset (&dst);
205.1169 +  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
205.1170 +  fclose (df);			/* note that unix_unlock() released the fd */
205.1171 +  if (tstream) {		/* update last UID if we can */
205.1172 +    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
205.1173 +    local->dirty = T;		/* do a rewrite */
205.1174 +    local->appending = T;	/* but not at the cost of marking as old */
205.1175 +    tstream = mail_close (tstream);
205.1176 +  }
205.1177 +  MM_NOCRITICAL (stream);	/* release critical */
205.1178 +  return ret;
205.1179 +}
205.1180 +
205.1181 +/* Collect and write single message to append scratch file
205.1182 + * Accepts: MAIL stream
205.1183 + *	    scratch file
205.1184 + *	    flags
205.1185 + *	    date
205.1186 + *	    message stringstruct
205.1187 + * Returns: NIL if write error, else T
205.1188 + */
205.1189 +
205.1190 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
205.1191 +		     STRING *msg)
205.1192 +{
205.1193 +  unsigned char *s,*t;
205.1194 +  unsigned long uf;
205.1195 +  long f = mail_parse_flags (stream,flags,&uf);
205.1196 +				/* write metadata, note date ends with NL */
205.1197 +  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
205.1198 +  while (uf)			/* write user flags */    
205.1199 +    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
205.1200 +	(fprintf (sf," %s",s) < 0)) return NIL;
205.1201 +  if (putc ('\n',sf) == EOF) return NIL;
205.1202 +  while (SIZE (msg)) {		/* copy text to scratch file */
205.1203 +    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
205.1204 +      if (!*s) *s = 0x80;	/* disallow NUL */
205.1205 +				/* write buffered text */
205.1206 +    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
205.1207 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
205.1208 +    else return NIL;		/* failed */
205.1209 +  }
205.1210 +				/* write trailing newline and return */
205.1211 +  return (putc ('\n',sf) == EOF) ? NIL : T;
205.1212 +}
205.1213 +
205.1214 +/* Append messages from scratch file to mailbox
205.1215 + * Accepts: MAIL stream
205.1216 + *	    source file
205.1217 + *	    destination file
205.1218 + *	    uidset to update if non-NIL
205.1219 + * Returns: T if success, NIL if failure
205.1220 + */
205.1221 +
205.1222 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
205.1223 +{
205.1224 +  int ti,zn,c;
205.1225 +  long f;
205.1226 +  unsigned long i,j;
205.1227 +  char *x,tmp[MAILTMPLEN];
205.1228 +  int hdrp = T;
205.1229 +				/* get message metadata line */
205.1230 +  while (fgets (tmp,MAILTMPLEN,sf)) {
205.1231 +    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
205.1232 +    f = strtol (tmp,&x,10);	/* get flags */
205.1233 +    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
205.1234 +    i = strtoul (x,&x,10);	/* get message size */
205.1235 +    if ((*x++ != ' ') ||	/* build initial header */
205.1236 +	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
205.1237 +	(f&fSEEN && (putc ('R',df) == EOF)) ||
205.1238 +	(fputs ("\nX-Status: ",df) == EOF) ||
205.1239 +	(f&fDELETED && (putc ('D',df) == EOF)) ||
205.1240 +	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
205.1241 +	(f&fANSWERED && (putc ('A',df) == EOF)) ||
205.1242 +	(f&fDRAFT && (putc ('T',df) == EOF)) ||
205.1243 +	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
205.1244 +				/* copy keywords */
205.1245 +    while ((c = getc (sf)) != '\n') switch (c) {
205.1246 +    case EOF:
205.1247 +      return NIL;
205.1248 +    default:
205.1249 +      if (putc (c,df) == EOF) return NIL;
205.1250 +    }
205.1251 +    if ((putc ('\n',df) == EOF) ||
205.1252 +	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
205.1253 +      return NIL;
205.1254 +
205.1255 +    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
205.1256 +				/* get read line length */
205.1257 +      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
205.1258 +      i -= j;			/* number of bytes left */
205.1259 +				/* squish out CRs (note also copies NUL) */
205.1260 +      for (x = tmp; x = strchr (x,'\r'); --j) memmove (x,x+1,j-(x-tmp));
205.1261 +      if (!j) continue;		/* do nothing if line emptied */
205.1262 +				/* start of line? */
205.1263 +      if ((c == '\n')) switch (tmp[0]) {
205.1264 +      case 'F':			/* possible "From " (case counts here) */
205.1265 +	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
205.1266 +	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
205.1267 +	  if (!unix_fromwidget) {
205.1268 +	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
205.1269 +	    if (!ti) break;	/*  it looks like a valid header */
205.1270 +	  }			/* write the widget */
205.1271 +	  if (putc ('>',df) == EOF) return NIL;
205.1272 +	}
205.1273 +	break;
205.1274 +      case 'S': case 's':	/* possible "Status:" */
205.1275 +	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
205.1276 +	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
205.1277 +	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
205.1278 +	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
205.1279 +	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
205.1280 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
205.1281 +	break;
205.1282 +      case 'X': case 'x':	/* possible X-??? header */
205.1283 +	if (hdrp && (tmp[1] == '-') &&
205.1284 +				/* possible X-UID: */
205.1285 +	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
205.1286 +	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
205.1287 +	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
205.1288 +				/* possible X-IMAP: */
205.1289 +	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
205.1290 +	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
205.1291 +	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
205.1292 +	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
205.1293 +	      ((tmp[6] == ':') ||
205.1294 +				/* or X-IMAPbase: */
205.1295 +	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
205.1296 +		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
205.1297 +		((tmp[8] == 's') || (tmp[8] == 'S')) &&
205.1298 +		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
205.1299 +				/* possible X-Status: */
205.1300 +	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
205.1301 +	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
205.1302 +	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
205.1303 +	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
205.1304 +	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
205.1305 +	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
205.1306 +				/* possible X-Keywords: */
205.1307 +	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
205.1308 +	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
205.1309 +	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
205.1310 +	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
205.1311 +	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
205.1312 +	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
205.1313 +	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
205.1314 +	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
205.1315 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
205.1316 +      case '\n':		/* blank line */
205.1317 +	hdrp = NIL;
205.1318 +	break;
205.1319 +      default:			/* nothing to do */
205.1320 +	break;
205.1321 +      }
205.1322 +				/* just write the line */
205.1323 +      if (fwrite (tmp,1,j,df) != j) return NIL;
205.1324 +    }
205.1325 +    if (i) return NIL;		/* didn't read entire message */
205.1326 +				/* update set */
205.1327 +    if (stream) mail_append_set (set,stream->uid_last);
205.1328 +  }
205.1329 +  return T;
205.1330 +}
205.1331 +
205.1332 +/* Internal routines */
205.1333 +
205.1334 +
205.1335 +/* UNIX mail abort stream
205.1336 + * Accepts: MAIL stream
205.1337 + */
205.1338 +
205.1339 +void unix_abort (MAILSTREAM *stream)
205.1340 +{
205.1341 +  if (LOCAL) {			/* only if a file is open */
205.1342 +    if (LOCAL->fd >= 0) close (LOCAL->fd);
205.1343 +    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
205.1344 +      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
205.1345 +      close (LOCAL->ld);	/* close the lock file */
205.1346 +      unlink (LOCAL->lname);	/* and delete it */
205.1347 +    }
205.1348 +    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
205.1349 +				/* free local text buffers */
205.1350 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
205.1351 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
205.1352 +    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
205.1353 +    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
205.1354 +				/* nuke the local data */
205.1355 +    fs_give ((void **) &stream->local);
205.1356 +    stream->dtb = NIL;		/* log out the DTB */
205.1357 +  }
205.1358 +}
205.1359 +
205.1360 +/* UNIX open and lock mailbox
205.1361 + * Accepts: file name to open/lock
205.1362 + *	    file open mode
205.1363 + *	    destination buffer for lock file name
205.1364 + *	    type of locking operation (LOCK_SH or LOCK_EX)
205.1365 + */
205.1366 +
205.1367 +int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
205.1368 +{
205.1369 +  int fd;
205.1370 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
205.1371 +  (*bn) (BLOCK_FILELOCK,NIL);
205.1372 +				/* try locking the easy way */
205.1373 +  if (dotlock_lock (file,lock,-1)) {
205.1374 +				/* got dotlock file, easy open */
205.1375 +    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
205.1376 +    else dotlock_unlock (lock);	/* open failed, free the dotlock */
205.1377 +  }
205.1378 +				/* no dot lock file, open file now */
205.1379 +  else if ((fd = open (file,flags,mode)) >= 0) {
205.1380 +				/* try paranoid way to make a dot lock file */
205.1381 +    if (dotlock_lock (file,lock,fd)) {
205.1382 +      close (fd);		/* get fresh fd in case of timing race */
205.1383 +      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
205.1384 +				/* open failed, free the dotlock */
205.1385 +      else dotlock_unlock (lock);
205.1386 +    }
205.1387 +    else flock (fd,op);		/* paranoid way failed, just flock() it */
205.1388 +  }
205.1389 +  (*bn) (BLOCK_NONE,NIL);
205.1390 +  return fd;
205.1391 +}
205.1392 +
205.1393 +/* UNIX unlock and close mailbox
205.1394 + * Accepts: file descriptor
205.1395 + *	    (optional) mailbox stream to check atime/mtime
205.1396 + *	    (optional) lock file name
205.1397 + */
205.1398 +
205.1399 +void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
205.1400 +{
205.1401 +  if (stream) {			/* need to muck with times? */
205.1402 +    struct stat sbuf;
205.1403 +    time_t tp[2];
205.1404 +    time_t now = time (0);
205.1405 +    fstat (fd,&sbuf);		/* get file times */
205.1406 +    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
205.1407 +      tp[0] = now;		/* set atime to now */
205.1408 +				/* set mtime to (now - 1) if necessary */
205.1409 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
205.1410 +    }
205.1411 +    else if (stream->recent) {	/* readonly with recent messages */
205.1412 +      if ((sbuf.st_atime >= sbuf.st_mtime) ||
205.1413 +	  (sbuf.st_atime >= sbuf.st_ctime))
205.1414 +				/* keep past mtime, whack back atime */
205.1415 +	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
205.1416 +      else now = 0;		/* no time change needed */
205.1417 +    }
205.1418 +				/* readonly with no recent messages */
205.1419 +    else if ((sbuf.st_atime < sbuf.st_mtime) ||
205.1420 +	     (sbuf.st_atime < sbuf.st_ctime)) {
205.1421 +      tp[0] = now;		/* set atime to now */
205.1422 +				/* set mtime to (now - 1) if necessary */
205.1423 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
205.1424 +    }
205.1425 +    else now = 0;		/* no time change needed */
205.1426 +				/* set the times, note change */
205.1427 +    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
205.1428 +  }
205.1429 +  flock (fd,LOCK_UN);		/* release flock'ers */
205.1430 +  if (!stream) close (fd);	/* close the file if no stream */
205.1431 +  dotlock_unlock (lock);	/* flush the lock file if any */
205.1432 +}
205.1433 +
205.1434 +/* UNIX mail parse and lock mailbox
205.1435 + * Accepts: MAIL stream
205.1436 + *	    space to write lock file name
205.1437 + *	    type of locking operation
205.1438 + * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
205.1439 + */
205.1440 +
205.1441 +int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
205.1442 +{
205.1443 +  int zn;
205.1444 +  unsigned long i,j,k,m;
205.1445 +  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
205.1446 +  int ti = 0,retain = T;
205.1447 +  unsigned long nmsgs = stream->nmsgs;
205.1448 +  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
205.1449 +  unsigned long recent = stream->recent;
205.1450 +  unsigned long oldnmsgs = stream->nmsgs;
205.1451 +  short silent = stream->silent;
205.1452 +  short pseudoseen = NIL;
205.1453 +  struct stat sbuf;
205.1454 +  STRING bs;
205.1455 +  FDDATA d;
205.1456 +  MESSAGECACHE *elt;
205.1457 +  mail_lock (stream);		/* guard against recursion or pingers */
205.1458 +				/* toss out previous descriptor */
205.1459 +  if (LOCAL->fd >= 0) close (LOCAL->fd);
205.1460 +  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
205.1461 +  if ((LOCAL->fd = unix_lock (stream->mailbox,(LOCAL->ld >= 0) ?
205.1462 +			      O_RDWR : O_RDONLY,
205.1463 +			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
205.1464 +			      lock,op)) < 0) {
205.1465 +    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
205.1466 +    MM_LOG (tmp,ERROR);
205.1467 +    unix_abort (stream);
205.1468 +    mail_unlock (stream);
205.1469 +    MM_NOCRITICAL (stream);	/* done with critical */
205.1470 +    return NIL;
205.1471 +  }
205.1472 +  fstat (LOCAL->fd,&sbuf);	/* get status */
205.1473 +				/* validate change in size */
205.1474 +  if (sbuf.st_size < LOCAL->filesize) {
205.1475 +    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
205.1476 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
205.1477 +    MM_LOG (tmp,ERROR);		/* this is pretty bad */
205.1478 +    unix_unlock (LOCAL->fd,stream,lock);
205.1479 +    unix_abort (stream);
205.1480 +    mail_unlock (stream);
205.1481 +    MM_NOCRITICAL (stream);	/* done with critical */
205.1482 +    return NIL;
205.1483 +  }
205.1484 +
205.1485 +				/* new data? */
205.1486 +  else if (i = sbuf.st_size - LOCAL->filesize) {
205.1487 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
205.1488 +    d.pos = LOCAL->filesize;	/* get to that position in the file */
205.1489 +    d.chunk = LOCAL->buf;	/* initial buffer chunk */
205.1490 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
205.1491 +    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
205.1492 +				/* skip leading whitespace for broken MTAs */
205.1493 +    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
205.1494 +	   (c == ' ') || (c == '\t')) SNX (&bs);
205.1495 +    if (SIZE (&bs)) {		/* read new data */
205.1496 +				/* remember internal header position */
205.1497 +      j = LOCAL->filesize + GETPOS (&bs);
205.1498 +      s = unix_mbxline (stream,&bs,&i);
205.1499 +      t = NIL,zn = 0;
205.1500 +      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
205.1501 +      if (!ti) {		/* someone pulled the rug from under us */
205.1502 +	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
205.1503 +		 (char *) s);
205.1504 +	MM_LOG (tmp,ERROR);
205.1505 +	unix_unlock (LOCAL->fd,stream,lock);
205.1506 +	unix_abort (stream);
205.1507 +	mail_unlock (stream);
205.1508 +				/* done with critical */
205.1509 +	MM_NOCRITICAL (stream);
205.1510 +	return NIL;
205.1511 +      }
205.1512 +      stream->silent = T;	/* quell main program new message events */
205.1513 +      do {			/* found a message */
205.1514 +				/* instantiate first new message */
205.1515 +	mail_exists (stream,++nmsgs);
205.1516 +	(elt = mail_elt (stream,nmsgs))->valid = T;
205.1517 +	recent++;		/* assume recent by default */
205.1518 +	elt->recent = T;
205.1519 +				/* note position/size of internal header */
205.1520 +	elt->private.special.offset = j;
205.1521 +	elt->private.msg.header.offset = elt->private.special.text.size = i;
205.1522 +
205.1523 +				/* generate plausible IMAPish date string */
205.1524 +	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
205.1525 +	date[14] = date[17] = ':';
205.1526 +				/* dd */
205.1527 +	date[0] = t[ti - 2]; date[1] = t[ti - 1];
205.1528 +				/* mmm */
205.1529 +	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
205.1530 +				/* hh */
205.1531 +	date[12] = t[ti + 1]; date[13] = t[ti + 2];
205.1532 +				/* mm */
205.1533 +	date[15] = t[ti + 4]; date[16] = t[ti + 5];
205.1534 +	if (t[ti += 6] == ':') {/* ss */
205.1535 +	  date[18] = t[++ti]; date[19] = t[++ti];
205.1536 +	  ti++;			/* move to space */
205.1537 +	}
205.1538 +	else date[18] = date[19] = '0';
205.1539 +				/* yy -- advance over timezone if necessary */
205.1540 +	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
205.1541 +	date[7] = t[ti + 1]; date[8] = t[ti + 2];
205.1542 +	date[9] = t[ti + 3]; date[10] = t[ti + 4];
205.1543 +				/* zzz */
205.1544 +	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
205.1545 +	date[21] = *t++; date[22] = *t++; date[23] = *t++;
205.1546 +	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
205.1547 +	else {			/* numeric time zone */
205.1548 +	  date[24] = *t++; date[25] = *t++;
205.1549 +	  date[26] = '\0'; date[20] = ' ';
205.1550 +	}
205.1551 +				/* set internal date */
205.1552 +	if (!mail_parse_date (elt,date)) {
205.1553 +	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
205.1554 +	  MM_LOG (tmp,WARN);
205.1555 +	}
205.1556 +
205.1557 +	do {			/* look for message body */
205.1558 +	  s = t = unix_mbxline (stream,&bs,&i);
205.1559 +	  if (i) switch (*s) {	/* check header lines */
205.1560 +	  case 'X':		/* possible X-???: line */
205.1561 +	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
205.1562 +				/* X-Status: becomes Status: in S case */
205.1563 +	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
205.1564 +		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
205.1565 +				/* possible X-Keywords */
205.1566 +	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
205.1567 +		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
205.1568 +		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
205.1569 +		SIZEDTEXT uf;
205.1570 +		retain = NIL;	/* don't retain continuation */
205.1571 +		s += 11;	/* flush leading whitespace */
205.1572 +		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
205.1573 +		  while (*s == ' ') s++;
205.1574 +				/* find end of keyword */
205.1575 +		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
205.1576 +				/* got a keyword? */
205.1577 +		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
205.1578 +		    uf.data = (unsigned char *) s;
205.1579 +		    uf.size = k;
205.1580 +		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
205.1581 +		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
205.1582 +			elt->user_flags |= ((long) 1) << j;
205.1583 +			break;
205.1584 +		      }
205.1585 + 		  }
205.1586 +		  s = u;	/* advance to next keyword */
205.1587 +		}
205.1588 +		break;
205.1589 +	      }
205.1590 +
205.1591 +				/* possible X-IMAP */
205.1592 +	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
205.1593 +		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
205.1594 +					 ((s[6] == 'b') && (s[7] == 'a') &&
205.1595 +					  (s[8] == 's') && (s[9] == 'e') &&
205.1596 +					  (s[10] == ':')))) {
205.1597 +		retain = NIL;	/* don't retain continuation */
205.1598 +		if ((nmsgs == 1) && !stream->uid_validity) {
205.1599 +				/* advance to data */
205.1600 +		  s += m ? 7 : 11;
205.1601 +				/* flush whitespace */
205.1602 +		  while (*s == ' ') s++;
205.1603 +		  j = 0;	/* slurp UID validity */
205.1604 +				/* found a digit? */
205.1605 +		  while (isdigit (*s)) {
205.1606 +		    j *= 10;	/* yes, add it in */
205.1607 +		    j += *s++ - '0';
205.1608 +		  }
205.1609 +				/* flush whitespace */
205.1610 +		  while (*s == ' ') s++;
205.1611 +				/* must have valid UID validity and UID last */
205.1612 +		  if (j && isdigit (*s)) {
205.1613 +				/* pseudo-header seen if X-IMAP */
205.1614 +		    if (m) pseudoseen = LOCAL->pseudo = T;
205.1615 +				/* save UID validity */
205.1616 +		    stream->uid_validity = j;
205.1617 +		    j = 0;	/* slurp UID last */
205.1618 +		    while (isdigit (*s)) {
205.1619 +		      j *= 10;	/* yes, add it in */
205.1620 +		      j += *s++ - '0';
205.1621 +		    }
205.1622 +				/* save UID last */
205.1623 +		    stream->uid_last = j;
205.1624 +				/* process keywords */
205.1625 +		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
205.1626 +			 s = u,j++) {
205.1627 +				/* flush leading whitespace */
205.1628 +		      while (*s == ' ') s++;
205.1629 +		      u = strpbrk (s," \n\r");
205.1630 +				/* got a keyword? */
205.1631 +		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
205.1632 +			  (k <= MAXUSERFLAG)) {
205.1633 +			if (stream->user_flags[j])
205.1634 +			  fs_give ((void **) &stream->user_flags[j]);
205.1635 +			stream->user_flags[j] = (char *) fs_get (k + 1);
205.1636 +			strncpy (stream->user_flags[j],s,k);
205.1637 +			stream->user_flags[j][k] = '\0';
205.1638 +		      }
205.1639 +		    }
205.1640 +		  }
205.1641 +		}
205.1642 +		break;
205.1643 +	      }
205.1644 +
205.1645 +				/* possible X-UID */
205.1646 +	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
205.1647 +		       s[5] == ':') {
205.1648 +		retain = NIL;	/* don't retain continuation */
205.1649 +				/* only believe if have a UID validity */
205.1650 +		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
205.1651 +		  s += 6;	/* advance to UID value */
205.1652 +				/* flush whitespace */
205.1653 +		  while (*s == ' ') s++;
205.1654 +		  j = 0;
205.1655 +				/* found a digit? */
205.1656 +		  while (isdigit (*s)) {
205.1657 +		    j *= 10;	/* yes, add it in */
205.1658 +		    j += *s++ - '0';
205.1659 +		  }
205.1660 +				/* flush remainder of line */
205.1661 +		  while (*s != '\n') s++;
205.1662 +				/* make sure not duplicated */
205.1663 +		  if (elt->private.uid)
205.1664 +		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
205.1665 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
205.1666 +			     j,elt->private.uid);
205.1667 +				/* make sure UID doesn't go backwards */
205.1668 +		  else if (j <= prevuid)
205.1669 +		    sprintf (tmp,"Message %lu UID %lu less than %lu",
205.1670 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
205.1671 +			     j,prevuid + 1);
205.1672 +#if 0	/* this is currently broken by UIDPLUS */
205.1673 +				/* or skip by mailbox's recorded last */
205.1674 +		  else if (j > stream->uid_last)
205.1675 +		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
205.1676 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
205.1677 +			     j,stream->uid_last);
205.1678 +#endif
205.1679 +		  else {	/* normal UID case */
205.1680 +		    prevuid = elt->private.uid = j;
205.1681 +#if 1	/* temporary kludge for UIDPLUS */
205.1682 +		    if (prevuid > stream->uid_last) {
205.1683 +		      stream->uid_last = prevuid;
205.1684 +		      LOCAL->ddirty = LOCAL->dirty = T;
205.1685 +		    }		    
205.1686 +#endif
205.1687 +		    break;	/* exit this cruft */
205.1688 +		  }
205.1689 +		  MM_LOG (tmp,WARN);
205.1690 +				/* invalidate UID validity */
205.1691 +		  stream->uid_validity = 0;
205.1692 +		  elt->private.uid = 0;
205.1693 +		}
205.1694 +		break;
205.1695 +	      }
205.1696 +	    }
205.1697 +				/* otherwise fall into S case */
205.1698 +
205.1699 +	  case 'S':		/* possible Status: line */
205.1700 +	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
205.1701 +		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
205.1702 +	      retain = NIL;	/* don't retain continuation */
205.1703 +	      s += 6;		/* advance to status flags */
205.1704 +	      do switch (*s++) {/* parse flags */
205.1705 +	      case 'R':		/* message read */
205.1706 +		elt->seen = T;
205.1707 +		break;
205.1708 +	      case 'O':		/* message old */
205.1709 +		if (elt->recent) {
205.1710 +		  elt->recent = NIL;
205.1711 +		  recent--;	/* it really wasn't recent */
205.1712 +		}
205.1713 +		break;
205.1714 +	      case 'D':		/* message deleted */
205.1715 +		elt->deleted = T;
205.1716 +		break;
205.1717 +	      case 'F':		/* message flagged */
205.1718 +		elt->flagged = T;
205.1719 +		break;
205.1720 +	      case 'A':		/* message answered */
205.1721 +		elt->answered = T;
205.1722 +		break;
205.1723 +	      case 'T':		/* message is a draft */
205.1724 +		elt->draft = T;
205.1725 +		break;
205.1726 +	      default:		/* some other crap */
205.1727 +		break;
205.1728 +	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
205.1729 +	      break;		/* all done */
205.1730 +	    }
205.1731 +				/* otherwise fall into default case */
205.1732 +
205.1733 +	  default:		/* ordinary header line */
205.1734 +	    if ((*s == 'S') || (*s == 's') ||
205.1735 +		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
205.1736 +	      unsigned char *e,*v;
205.1737 +				/* must match what mail_filter() does */
205.1738 +	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
205.1739 +		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
205.1740 +		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
205.1741 +				  (c != '\r') && (c != '\n')));
205.1742 +		   *v++ = *u++);
205.1743 +	      *v = '\0';	/* tie off */
205.1744 +				/* matches internal header? */
205.1745 +	      if (!compare_cstring (tmp,"STATUS") ||
205.1746 +		  !compare_cstring (tmp,"X-STATUS") ||
205.1747 +		  !compare_cstring (tmp,"X-KEYWORDS") ||
205.1748 +		  !compare_cstring (tmp,"X-UID") ||
205.1749 +		  !compare_cstring (tmp,"X-IMAP") ||
205.1750 +		  !compare_cstring (tmp,"X-IMAPBASE")) {
205.1751 +		char err[MAILTMPLEN];
205.1752 +		sprintf (err,"Discarding bogus %s header in message %lu",
205.1753 +			 (char *) tmp,elt->msgno);
205.1754 +		MM_LOG (err,WARN);
205.1755 +		retain = NIL;	/* don't retain continuation */
205.1756 +		break;		/* different case or something */
205.1757 +	      }
205.1758 +	    }
205.1759 +				/* retain or non-continuation? */
205.1760 +	    if (retain || ((*s != ' ') && (*s != '\t'))) {
205.1761 +	      retain = T;	/* retaining continuation now */
205.1762 +				/* line length in LF format newline */
205.1763 +	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
205.1764 +				/* "internal" header size */
205.1765 +	      elt->private.spare.data += k;
205.1766 +				/* message size */
205.1767 +	      elt->rfc822_size += k + 1;
205.1768 +	    }
205.1769 +	    else {
205.1770 +	      char err[MAILTMPLEN];
205.1771 +	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
205.1772 +		      elt->msgno,(char *) s);
205.1773 +	      if (u = strpbrk (err,"\r\n")) *u = '\0';
205.1774 +	      MM_LOG (err,WARN);
205.1775 +	      break;		/* different case or something */
205.1776 +	    }
205.1777 +	    break;
205.1778 +	  }
205.1779 +	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
205.1780 +				/* "internal" header sans trailing newline */
205.1781 +	if (i) elt->private.spare.data--;
205.1782 +				/* assign a UID if none found */
205.1783 +	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
205.1784 +	  prevuid = elt->private.uid = ++stream->uid_last;
205.1785 +	  elt->private.dirty = T;
205.1786 +	  LOCAL->ddirty = T;	/* force update */
205.1787 +	}
205.1788 +	else elt->private.dirty = elt->recent;
205.1789 +
205.1790 +				/* note size of header, location of text */
205.1791 +	elt->private.msg.header.text.size = 
205.1792 +	  (elt->private.msg.text.offset =
205.1793 +	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
205.1794 +	     elt->private.special.text.size;
205.1795 +	k = m = 0;		/* no previous line size yet */
205.1796 +				/* note current position */
205.1797 +	j = LOCAL->filesize + GETPOS (&bs);
205.1798 +	if (i) do {		/* look for next message */
205.1799 +	  s = unix_mbxline (stream,&bs,&i);
205.1800 +	  if (i) {		/* got new data? */
205.1801 +	    VALID (s,t,ti,zn);	/* yes, parse line */
205.1802 +	    if (!ti) {		/* not a header line, add it to message */
205.1803 +	      elt->rfc822_size += i;
205.1804 +	      for (j = 0; j < i; ++j) switch (s[j]) {
205.1805 +	      case '\r':	/* squeeze out CRs */
205.1806 +		elt->rfc822_size -= 1;
205.1807 +		break;
205.1808 +	      case '\n':	/* LF becomes CRLF */
205.1809 +		elt->rfc822_size += 1;
205.1810 +		break;
205.1811 +	      default:
205.1812 +		break;
205.1813 +	      }
205.1814 +	      if ((i == 1) && (*s == '\n')) {
205.1815 +		k = 2;
205.1816 +		m = 1;
205.1817 +	      }
205.1818 +	      else if ((i == 2) && (*s == '\r') && (s[1] == '\n'))
205.1819 +		k = m = 2;
205.1820 +	      else k = m = 0;	/* file does not end with newline! */
205.1821 +				/* update current position */
205.1822 +	      j = LOCAL->filesize + GETPOS (&bs);
205.1823 +	    }
205.1824 +	  }
205.1825 +	} while (i && !ti);	/* until found a header */
205.1826 +	elt->private.msg.text.text.size = j -
205.1827 +	  (elt->private.special.offset + elt->private.msg.text.offset);
205.1828 +				/* flush ending blank line */
205.1829 +	elt->private.msg.text.text.size -= m;
205.1830 +	elt->rfc822_size -= k;
205.1831 +				/* until end of buffer */
205.1832 +      } while (!stream->sniff && i);
205.1833 +      if (pseudoseen) {		/* flush pseudo-message if present */
205.1834 +				/* decrement recent count */
205.1835 +	if (mail_elt (stream,1)->recent) recent--;
205.1836 +				/* and the exists count */
205.1837 +	mail_exists (stream,nmsgs--);
205.1838 +	mail_expunged(stream,1);/* fake an expunge of that message */
205.1839 +      }
205.1840 +				/* need to start a new UID validity? */
205.1841 +      if (!stream->uid_validity) {
205.1842 +	stream->uid_validity = time (0);
205.1843 +				/* in case a whiner with no life */
205.1844 +	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
205.1845 +	  stream->uid_nosticky = T;
205.1846 +	else if (nmsgs) {	/* don't bother if empty file */
205.1847 +				/* make dirty to restart UID epoch */
205.1848 +	  LOCAL->ddirty = LOCAL->dirty = T;
205.1849 +				/* need to rewrite msg 1 if not pseudo */
205.1850 +	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
205.1851 +	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
205.1852 +	}
205.1853 +      }
205.1854 +      stream->nmsgs = oldnmsgs;	/* whack it back down */
205.1855 +      stream->silent = silent;	/* restore old silent setting */
205.1856 +				/* notify upper level of new mailbox sizes */
205.1857 +      mail_exists (stream,nmsgs);
205.1858 +      mail_recent (stream,recent);
205.1859 +				/* mark dirty so O flags are set */
205.1860 +      if (recent) LOCAL->dirty = T;
205.1861 +    }
205.1862 +  }
205.1863 +				/* no change, don't babble if never got time */
205.1864 +  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
205.1865 +    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
205.1866 +				/* update parsed file size and time */
205.1867 +  LOCAL->filesize = sbuf.st_size;
205.1868 +  LOCAL->filetime = sbuf.st_mtime;
205.1869 +  return T;			/* return the winnage */
205.1870 +}
205.1871 +
205.1872 +/* UNIX read line from mailbox
205.1873 + * Accepts: mail stream
205.1874 + *	    stringstruct
205.1875 + *	    pointer to line size
205.1876 + * Returns: pointer to input line
205.1877 + */
205.1878 +
205.1879 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
205.1880 +{
205.1881 +  unsigned long i,j,k,m;
205.1882 +  char *s,*t,*te;
205.1883 +  char *ret = "";
205.1884 +				/* flush old buffer */
205.1885 +  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
205.1886 +				/* if buffer needs refreshing */
205.1887 +  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
205.1888 +  if (SIZE (bs)) {		/* find newline */
205.1889 +				/* end of fast scan */
205.1890 +    te = (t = (s = bs->curpos) + bs->cursize) - 12;
205.1891 +    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
205.1892 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
205.1893 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
205.1894 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
205.1895 +      --s;			/* back up */
205.1896 +      break;			/* exit loop */
205.1897 +    }
205.1898 +				/* final character-at-a-time scan */
205.1899 +    while ((s < t) && (*s != '\n')) ++s;
205.1900 +				/* difficult case if line spans buffer */
205.1901 +    if ((i = s - bs->curpos) == bs->cursize) {
205.1902 +				/* have space in line buffer? */
205.1903 +      if (i > LOCAL->linebuflen) {
205.1904 +	fs_give ((void **) &LOCAL->linebuf);
205.1905 +	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
205.1906 +      }
205.1907 +				/* remember what we have so far */
205.1908 +      memcpy (LOCAL->linebuf,bs->curpos,i);
205.1909 +				/* load next buffer */
205.1910 +      SETPOS (bs,k = GETPOS (bs) + i);
205.1911 +				/* end of fast scan */
205.1912 +      te = (t = (s = bs->curpos) + bs->cursize) - 12;
205.1913 +				/* fast scan in overlap buffer */
205.1914 +      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
205.1915 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
205.1916 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
205.1917 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
205.1918 +	--s;			/* back up */
205.1919 +	break;			/* exit loop */
205.1920 +      }
205.1921 +
205.1922 +				/* final character-at-a-time scan */
205.1923 +      while ((s < t) && (*s != '\n')) ++s;
205.1924 +				/* huge line? */
205.1925 +      if ((j = s - bs->curpos) == bs->cursize) {
205.1926 +	SETPOS (bs,GETPOS (bs) + j);
205.1927 +				/* look for end of line (s-l-o-w!!) */
205.1928 +	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
205.1929 +	SETPOS (bs,k);		/* go back to where it started */
205.1930 +      }
205.1931 +				/* got size of data, make buffer for return */
205.1932 +      ret = LOCAL->line = (char *) fs_get (i + j + 2);
205.1933 +				/* copy first chunk */
205.1934 +      memcpy (ret,LOCAL->linebuf,i);
205.1935 +      while (j) {		/* copy remainder */
205.1936 +	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
205.1937 +	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
205.1938 +	i += k;			/* account for this much read in */
205.1939 +	j -= k;
205.1940 +	bs->curpos += k;	/* increment new position */
205.1941 +	bs->cursize -= k;	/* eat that many bytes */
205.1942 +      }
205.1943 +      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
205.1944 +				/* read newline at end */
205.1945 +      if (SIZE (bs)) ret[i++] = SNX (bs);
205.1946 +      ret[i] = '\0';		/* makes debugging easier */
205.1947 +    }
205.1948 +    else {			/* this is easy */
205.1949 +      ret = bs->curpos;		/* string it at this position */
205.1950 +      bs->curpos += ++i;	/* increment new position */
205.1951 +      bs->cursize -= i;		/* eat that many bytes */
205.1952 +    }
205.1953 +    *size = i;			/* return that to user */
205.1954 +  }
205.1955 +  else *size = 0;		/* end of data, return empty */
205.1956 +  return ret;
205.1957 +}
205.1958 +
205.1959 +/* UNIX make pseudo-header
205.1960 + * Accepts: MAIL stream
205.1961 + *	    buffer to write pseudo-header
205.1962 + * Returns: length of pseudo-header
205.1963 + */
205.1964 +
205.1965 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
205.1966 +{
205.1967 +  int i;
205.1968 +  char *s,tmp[MAILTMPLEN];
205.1969 +  time_t now = time (0);
205.1970 +  rfc822_fixed_date (tmp);
205.1971 +  sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
205.1972 +	   pseudo_from,ctime (&now),
205.1973 +	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
205.1974 +	   (unsigned long) now,mylocalhost (),stream->uid_validity,
205.1975 +	   stream->uid_last);
205.1976 +  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
205.1977 +    if (stream->user_flags[i])
205.1978 +      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
205.1979 +  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
205.1980 +  return strlen (hdr);		/* return header length */
205.1981 +}
205.1982 +
205.1983 +/* UNIX make status string
205.1984 + * Accepts: MAIL stream
205.1985 + *	    destination string to write
205.1986 + *	    message cache entry
205.1987 + *	    UID to write if non-zero (else use elt->private.uid)
205.1988 + *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
205.1989 + * Returns: length of string
205.1990 + */
205.1991 +
205.1992 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
205.1993 +			    unsigned long uid,long flag)
205.1994 +{
205.1995 +  char *t,stack[64];
205.1996 +  char *s = status;
205.1997 +  unsigned long n;
205.1998 +  int pad = 50;
205.1999 +  int sticky = uid ? T : !stream->uid_nosticky;
205.2000 +  /* This used to use sprintf(), but thanks to certain cretinous C libraries
205.2001 +     with horribly slow implementations of sprintf() I had to change it to this
205.2002 +     mess.  At least it should be fast. */
205.2003 +  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
205.2004 +    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
205.2005 +    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
205.2006 +    t = stack;
205.2007 +    n = stream->uid_validity;	/* push UID validity digits on the stack */
205.2008 +    do *t++ = (char) (n % 10) + '0';
205.2009 +    while (n /= 10);
205.2010 +				/* pop UID validity digits from stack */
205.2011 +    while (t > stack) *s++ = *--t;
205.2012 +    *s++ = ' ';
205.2013 +    n = stream->uid_last;	/* push UID last digits on the stack */
205.2014 +    do *t++ = (char) (n % 10) + '0';
205.2015 +    while (n /= 10);
205.2016 +				/* pop UID last digits from stack */
205.2017 +    while (t > stack) *s++ = *--t;
205.2018 +    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
205.2019 +      for (*s++ = ' '; *t; *s++ = *t++);
205.2020 +    *s++ = '\n';
205.2021 +    pad += 30;			/* increased padding if have IMAPbase */
205.2022 +  }
205.2023 +  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
205.2024 +  *s++ = ':'; *s++ = ' ';
205.2025 +  if (elt->seen) *s++ = 'R';
205.2026 +				/* only write O if have a UID */
205.2027 +  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
205.2028 +  *s++ = '\n';
205.2029 +  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
205.2030 +  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
205.2031 +  if (elt->deleted) *s++ = 'D';
205.2032 +  if (elt->flagged) *s++ = 'F';
205.2033 +  if (elt->answered) *s++ = 'A';
205.2034 +  if (elt->draft) *s++ = 'T';
205.2035 +  *s++ = '\n';
205.2036 +
205.2037 +  if (sticky) {			/* only do this if UIDs sticky */
205.2038 +    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
205.2039 +    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
205.2040 +    if (n = elt->user_flags) do {
205.2041 +      *s++ = ' ';
205.2042 +      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
205.2043 +    } while (n);
205.2044 +    n = s - status;		/* get size of stuff so far */
205.2045 +				/* pad X-Keywords to make size constant */
205.2046 +    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
205.2047 +    *s++ = '\n';
205.2048 +    if (flag) {			/* want to include UID? */
205.2049 +      t = stack;
205.2050 +				/* push UID digits on the stack */
205.2051 +      n = uid ? uid : elt->private.uid;
205.2052 +      do *t++ = (char) (n % 10) + '0';
205.2053 +      while (n /= 10);
205.2054 +      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
205.2055 +      *s++ = ' ';
205.2056 +				/* pop UID from stack */
205.2057 +      while (t > stack) *s++ = *--t;
205.2058 +      *s++ = '\n';
205.2059 +    }
205.2060 +  }
205.2061 +  *s++ = '\n'; *s = '\0';	/* end of extended message status */
205.2062 +  return s - status;		/* return size of resulting string */
205.2063 +}
205.2064 +
205.2065 +/* Rewrite mailbox file
205.2066 + * Accepts: MAIL stream, must be critical and locked
205.2067 + *	    return pointer to number of expunged messages if want expunge
205.2068 + *	    lock file name
205.2069 + *	    expunge sequence, not deleted flag
205.2070 + * Returns: T if success and mailbox unlocked, NIL if failure
205.2071 + */
205.2072 +
205.2073 +#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
205.2074 +
205.2075 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
205.2076 +		   long flags)
205.2077 +{
205.2078 +  MESSAGECACHE *elt;
205.2079 +  UNIXFILE f;
205.2080 +  char *s;
205.2081 +  time_t tp[2];
205.2082 +  long ret,flag;
205.2083 +  unsigned long i,j;
205.2084 +  unsigned long recent = stream->recent;
205.2085 +  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
205.2086 +  if (nexp) *nexp = 0;		/* initially nothing expunged */
205.2087 +				/* calculate size of mailbox after rewrite */
205.2088 +  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
205.2089 +    elt = mail_elt (stream,i);	/* get cache */
205.2090 +    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
205.2091 +				/* add RFC822 size of this message */
205.2092 +      size += elt->private.special.text.size + elt->private.spare.data +
205.2093 +	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
205.2094 +	  elt->private.msg.text.text.size + 1;
205.2095 +      flag = 1;			/* only count X-IMAPbase once */
205.2096 +    }
205.2097 +  }
205.2098 +				/* no messages, has a life, and no pseudo */
205.2099 +  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
205.2100 +    LOCAL->pseudo = T;		/* so make a pseudo-message now */
205.2101 +    size = unix_pseudo (stream,LOCAL->buf);
205.2102 +  }
205.2103 +				/* extend the file as necessary */
205.2104 +  if (ret = unix_extend (stream,size)) {
205.2105 +    /* Set up buffered I/O file structure
205.2106 +     * curpos	current position being written through buffering
205.2107 +     * filepos	current position being written physically to the disk
205.2108 +     * bufpos	current position being written in the buffer
205.2109 +     * protect	current maximum position that can be written to the disk
205.2110 +     *		before buffering is forced
205.2111 +     * The code tries to buffer so that that disk is written in multiples of
205.2112 +     * OVERBLOWBUFLEN bytes.
205.2113 +     */
205.2114 +    f.stream = stream;		/* note mail stream */
205.2115 +    f.curpos = f.filepos = 0;	/* start of file */
205.2116 +    f.protect = stream->nmsgs ?	/* initial protection pointer */
205.2117 +    mail_elt (stream,1)->private.special.offset : 8192;
205.2118 +    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
205.2119 +
205.2120 +    if (LOCAL->pseudo)		/* update pseudo-header */
205.2121 +      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
205.2122 +				/* loop through all messages */
205.2123 +    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
205.2124 +      elt = mail_elt (stream,i);/* get cache */
205.2125 +				/* expunge this message? */
205.2126 +      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
205.2127 +				/* one less recent message */
205.2128 +	if (elt->recent) --recent;
205.2129 +	mail_expunged(stream,i);/* notify upper levels */
205.2130 +	++*nexp;		/* count up one more expunged message */
205.2131 +      }
205.2132 +      else {			/* preserve this message */
205.2133 +	i++;			/* advance to next message */
205.2134 +	if ((flag < 0) ||	/* need to rewrite message? */
205.2135 +	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
205.2136 +	    (elt->private.msg.header.text.size !=
205.2137 +	     (elt->private.spare.data +
205.2138 +	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
205.2139 +	  unsigned long newoffset = f.curpos;
205.2140 +				/* yes, seek to internal header */
205.2141 +	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
205.2142 +	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
205.2143 +				/* see if need to squeeze out a CR */
205.2144 +	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
205.2145 +	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
205.2146 +	    --size;		/* squeezed out a CR from PC */
205.2147 +	  }
205.2148 +				/* protection pointer moves to RFC822 header */
205.2149 +	  f.protect = elt->private.special.offset +
205.2150 +	    elt->private.msg.header.offset;
205.2151 +				/* write internal header */
205.2152 +	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
205.2153 +				/* get RFC822 header */
205.2154 +	  s = unix_header (stream,elt->msgno,&j,FT_INTERNAL);
205.2155 +				/* in case this got decremented */
205.2156 +	  elt->private.msg.header.offset = elt->private.special.text.size;
205.2157 +				/* header size, sans trailing newline */
205.2158 +	  if ((j < 2) || (s[j - 2] == '\n')) j--;
205.2159 +				/* this can happen if CRs were squeezed */
205.2160 +	  if (j < elt->private.spare.data) {
205.2161 +				/* so fix up counts */
205.2162 +	    size -= elt->private.spare.data - j;
205.2163 +	    elt->private.spare.data = j;
205.2164 +	  }
205.2165 +	  else if (j != elt->private.spare.data)
205.2166 +	    fatal ("header size inconsistent");
205.2167 +				/* protection pointer moves to RFC822 text */
205.2168 +	  f.protect = elt->private.special.offset +
205.2169 +	    elt->private.msg.text.offset;
205.2170 +	  unix_write (&f,s,j);	/* write RFC822 header */
205.2171 +				/* write status and UID */
205.2172 +	  unix_write (&f,LOCAL->buf,
205.2173 +		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
205.2174 +	  flag = 1;		/* only write X-IMAPbase once */
205.2175 +				/* new file header size */
205.2176 +	  elt->private.msg.header.text.size = elt->private.spare.data + j;
205.2177 +
205.2178 +				/* did text move? */
205.2179 +	  if (f.curpos != f.protect) {
205.2180 +				/* get message text */
205.2181 +	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
205.2182 +				/* this can happen if CRs were squeezed */
205.2183 +	    if (j < elt->private.msg.text.text.size) {
205.2184 +				/* so fix up counts */
205.2185 +	      size -= elt->private.msg.text.text.size - j;
205.2186 +	      elt->private.msg.text.text.size = j;
205.2187 +	    }
205.2188 +				/* can't happen it says here */
205.2189 +	    else if (j > elt->private.msg.text.text.size)
205.2190 +	      fatal ("text size inconsistent");
205.2191 +				/* new text offset, status/UID may change it */
205.2192 +	    elt->private.msg.text.offset = f.curpos - newoffset;
205.2193 +				/* protection pointer moves to next message */
205.2194 +	    f.protect = (i <= stream->nmsgs) ?
205.2195 +	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1);
205.2196 +	    unix_write (&f,s,j);/* write text */
205.2197 +				/* write trailing newline */
205.2198 +	    unix_write (&f,"\n",1);
205.2199 +	  }
205.2200 +	  else {		/* tie off header and status */
205.2201 +	    unix_write (&f,NIL,NIL);
205.2202 +				/* protection pointer moves to next message */
205.2203 +	    f.protect = (i <= stream->nmsgs) ?
205.2204 +	      mail_elt (stream,i)->private.special.offset : size;
205.2205 +				/* locate end of message text */
205.2206 +	    j = f.filepos + elt->private.msg.text.text.size;
205.2207 +				/* trailing newline already there? */
205.2208 +	    if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
205.2209 +	    else {		/* trailing newline missing, write it */
205.2210 +	      f.curpos = f.filepos = j;
205.2211 +	      unix_write (&f,"\n",1);
205.2212 +	    }
205.2213 +	  }
205.2214 +				/* new internal header offset */
205.2215 +	  elt->private.special.offset = newoffset;
205.2216 +	  elt->private.dirty =NIL;/* message is now clean */
205.2217 +	}
205.2218 +	else {			/* no need to rewrite this message */
205.2219 +				/* tie off previous message if needed */
205.2220 +	  unix_write (&f,NIL,NIL);
205.2221 +				/* protection pointer moves to next message */
205.2222 +	  f.protect = (i <= stream->nmsgs) ?
205.2223 +	    mail_elt (stream,i)->private.special.offset : size;
205.2224 +				/* locate end of message text */
205.2225 +	  j = f.filepos + elt->private.special.text.size +
205.2226 +	    elt->private.msg.header.text.size +
205.2227 +	      elt->private.msg.text.text.size;
205.2228 +				/* trailing newline already there? */
205.2229 +	  if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
205.2230 +	  else {		/* trailing newline missing, write it */
205.2231 +	    f.curpos = f.filepos = j;
205.2232 +	    unix_write (&f,"\n",1);
205.2233 +	  }
205.2234 +	}
205.2235 +      }
205.2236 +    }
205.2237 +
205.2238 +    unix_write (&f,NIL,NIL);	/* tie off final message */
205.2239 +    if (size != f.filepos) fatal ("file size inconsistent");
205.2240 +    fs_give ((void **) &f.buf);	/* free buffer */
205.2241 +				/* make sure tied off */
205.2242 +    ftruncate (LOCAL->fd,LOCAL->filesize = size);
205.2243 +    fsync (LOCAL->fd);		/* make sure the updates take */
205.2244 +    if (size && (flag < 0)) fatal ("lost UID base information");
205.2245 +				/* no longer dirty */
205.2246 +    LOCAL->ddirty = LOCAL->dirty = NIL;
205.2247 +  				/* notify upper level of new mailbox sizes */
205.2248 +    mail_exists (stream,stream->nmsgs);
205.2249 +    mail_recent (stream,recent);
205.2250 +				/* set atime to now, mtime a second earlier */
205.2251 +    tp[1] = (tp[0] = time (0)) - 1;
205.2252 +				/* set the times, note change */
205.2253 +    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
205.2254 +    close (LOCAL->fd);		/* close and reopen file */
205.2255 +    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
205.2256 +			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
205.2257 +	< 0) {
205.2258 +      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
205.2259 +      MM_LOG (LOCAL->buf,ERROR);
205.2260 +      unix_abort (stream);
205.2261 +    }
205.2262 +    dotlock_unlock (lock);	/* flush the lock file */
205.2263 +  }
205.2264 +  return ret;			/* return state from algorithm */
205.2265 +}
205.2266 +
205.2267 +/* Extend UNIX mailbox file
205.2268 + * Accepts: MAIL stream
205.2269 + *	    new desired size
205.2270 + * Return: T if success, else NIL
205.2271 + */
205.2272 +
205.2273 +long unix_extend (MAILSTREAM *stream,unsigned long size)
205.2274 +{
205.2275 +  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
205.2276 +  if (i) {			/* does the mailbox need to grow? */
205.2277 +    if (i > LOCAL->buflen) {	/* make sure have enough space */
205.2278 +				/* this user won the lottery all right */
205.2279 +      fs_give ((void **) &LOCAL->buf);
205.2280 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
205.2281 +    }
205.2282 +    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
205.2283 +    while (T) {			/* until write successful or punt */
205.2284 +      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
205.2285 +      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
205.2286 +      else {
205.2287 +	long e = errno;		/* note error before doing ftruncate */
205.2288 +	ftruncate (LOCAL->fd,LOCAL->filesize);
205.2289 +	if (MM_DISKERROR (stream,e,NIL)) {
205.2290 +	  fsync (LOCAL->fd);	/* user chose to punt */
205.2291 +	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
205.2292 +	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
205.2293 +	  return NIL;
205.2294 +	}
205.2295 +      }
205.2296 +    }
205.2297 +  }
205.2298 +  return LONGT;
205.2299 +}
205.2300 +
205.2301 +/* Write data to buffered file
205.2302 + * Accepts: buffered file pointer
205.2303 + *	    file data or NIL to indicate "flush buffer"
205.2304 + *	    date size (ignored for "flush buffer")
205.2305 + * Does not return until success
205.2306 + */
205.2307 +
205.2308 +void unix_write (UNIXFILE *f,char *buf,unsigned long size)
205.2309 +{
205.2310 +  unsigned long i,j,k;
205.2311 +  if (buf) {			/* doing buffered write? */
205.2312 +    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
205.2313 +				/* yes, have space in current buffer chunk? */
205.2314 +    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
205.2315 +				/* yes, fill up buffer as much as we can */
205.2316 +      memcpy (f->bufpos,buf,k = min (j,size));
205.2317 +      f->bufpos += k;		/* new buffer position */
205.2318 +      f->curpos += k;		/* new current position */
205.2319 +      if (j -= k) return;	/* all done if still have buffer free space */
205.2320 +      buf += k;			/* full, get new unwritten data pointer */
205.2321 +      size -= k;		/* new data size */
205.2322 +      i += k;			/* new buffer data size */
205.2323 +    }
205.2324 +    /* This chunk of the buffer is full.  See if can make some space by
205.2325 +     * writing to the disk, if there's enough unprotected space to do so.
205.2326 +     * Try to fill out any unaligned chunk, along with any subsequent full
205.2327 +     * chunks that will fit in unprotected space.
205.2328 +     */
205.2329 +				/* any unprotected space we can write to? */
205.2330 +    if (j = min (i,f->protect - f->filepos)) {
205.2331 +				/* yes, filepos not at chunk boundary? */
205.2332 +      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
205.2333 +	j -= k;			/* yes, and can write out partial chunk */
205.2334 +      else k = 0;		/* no partial chunk to write */
205.2335 +				/* if at least a chunk free, write that too */
205.2336 +      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
205.2337 +      if (k) {			/* write data if there is anything we can */
205.2338 +	unix_phys_write (f,f->buf,k);
205.2339 +				/* slide buffer */
205.2340 +	if (i -= k) memmove (f->buf,f->buf + k,i);
205.2341 +	f->bufpos = f->buf + i;	/* new end of buffer */
205.2342 +      }
205.2343 +    }
205.2344 +
205.2345 +    /* Have flushed the buffer as best as possible.  All done if no more
205.2346 +     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
205.2347 +     * data is larger than a chunk AND the unprotected space is also larger
205.2348 +     * than a chunk, then write as many chunks as we can directly from the
205.2349 +     * data.  Buffer the rest, expanding the buffer as needed.
205.2350 +     */
205.2351 +    if (size) {			/* have more data that we need to buffer? */
205.2352 +				/* can write any of it to disk instead? */
205.2353 +      if ((f->bufpos == f->buf) && 
205.2354 +	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
205.2355 +				/* write as much as we can right now */
205.2356 +	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
205.2357 +	buf += j;		/* new data pointer */
205.2358 +	size -= j;		/* new data size */
205.2359 +	f->curpos += j;		/* advance current pointer */
205.2360 +      }
205.2361 +      if (size) {		/* still have data that we need to buffer? */
205.2362 +				/* yes, need to expand the buffer? */
205.2363 +	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
205.2364 +				/* note current position in buffer */
205.2365 +	  j = f->bufpos - f->buf;
205.2366 +	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
205.2367 +	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
205.2368 +				/* in case buffer relocated */
205.2369 +	  f->bufpos = f->buf + j;
205.2370 +	}
205.2371 +				/* buffer remaining data */
205.2372 +	memcpy (f->bufpos,buf,size);
205.2373 +	f->bufpos += size;	/* new end of buffer */
205.2374 +	f->curpos += size;	/* advance current pointer */
205.2375 +      }
205.2376 +    }
205.2377 +  }
205.2378 +  else {			/* flush buffer to disk */
205.2379 +    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
205.2380 +    f->bufpos = f->buf;		/* reset buffer */
205.2381 +				/* update positions */
205.2382 +    f->curpos = f->protect = f->filepos;
205.2383 +  }
205.2384 +}
205.2385 +
205.2386 +/* Physical disk write
205.2387 + * Accepts: buffered file pointer
205.2388 + *	    buffer address
205.2389 + *	    buffer size
205.2390 + * Does not return until success
205.2391 + */
205.2392 +
205.2393 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
205.2394 +{
205.2395 +  MAILSTREAM *stream = f->stream;
205.2396 +				/* write data at desired position */
205.2397 +  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
205.2398 +		  (write (LOCAL->fd,buf,size) < 0))) {
205.2399 +    int e;
205.2400 +    char tmp[MAILTMPLEN];
205.2401 +    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
205.2402 +    MM_LOG (tmp,ERROR);
205.2403 +    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
205.2404 +  }
205.2405 +  f->filepos += size;		/* update file position */
205.2406 +}
205.2407 +
205.2408 +/* MBOX mail routines */
205.2409 +
205.2410 +
205.2411 +/* Driver dispatch used by MAIL */
205.2412 +
205.2413 +DRIVER mboxdriver = {
205.2414 +  "mbox",			/* driver name */
205.2415 +				/* driver flags */
205.2416 +  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY,
205.2417 +  (DRIVER *) NIL,		/* next driver */
205.2418 +  mbox_valid,			/* mailbox is valid for us */
205.2419 +  unix_parameters,		/* manipulate parameters */
205.2420 +  unix_scan,			/* scan mailboxes */
205.2421 +  unix_list,			/* find mailboxes */
205.2422 +  unix_lsub,			/* find subscribed mailboxes */
205.2423 +  NIL,				/* subscribe to mailbox */
205.2424 +  NIL,				/* unsubscribe from mailbox */
205.2425 +  mbox_create,			/* create mailbox */
205.2426 +  mbox_delete,			/* delete mailbox */
205.2427 +  mbox_rename,			/* rename mailbox */
205.2428 +  mbox_status,			/* status of mailbox */
205.2429 +  mbox_open,			/* open mailbox */
205.2430 +  unix_close,			/* close mailbox */
205.2431 +  NIL,				/* fetch message "fast" attributes */
205.2432 +  NIL,				/* fetch message flags */
205.2433 +  NIL,				/* fetch overview */
205.2434 +  NIL,				/* fetch message structure */
205.2435 +  unix_header,			/* fetch message header */
205.2436 +  unix_text,			/* fetch message body */
205.2437 +  NIL,				/* fetch partial message text */
205.2438 +  NIL,				/* unique identifier */
205.2439 +  NIL,				/* message number */
205.2440 +  NIL,				/* modify flags */
205.2441 +  unix_flagmsg,			/* per-message modify flags */
205.2442 +  NIL,				/* search for message based on criteria */
205.2443 +  NIL,				/* sort messages */
205.2444 +  NIL,				/* thread messages */
205.2445 +  mbox_ping,			/* ping mailbox to see if still alive */
205.2446 +  mbox_check,			/* check for new messages */
205.2447 +  mbox_expunge,			/* expunge deleted messages */
205.2448 +  unix_copy,			/* copy messages to another mailbox */
205.2449 +  mbox_append,			/* append string message to mailbox */
205.2450 +  NIL				/* garbage collect stream */
205.2451 +};
205.2452 +
205.2453 +				/* prototype stream */
205.2454 +MAILSTREAM mboxproto = {&mboxdriver};
205.2455 +
205.2456 +/* MBOX mail validate mailbox
205.2457 + * Accepts: mailbox name
205.2458 + * Returns: our driver if name is valid, NIL otherwise
205.2459 + */
205.2460 +
205.2461 +DRIVER *mbox_valid (char *name)
205.2462 +{
205.2463 +				/* only INBOX, mbox must exist */
205.2464 +  if (!compare_cstring (name,"INBOX") && (unix_valid ("mbox") || !errno) &&
205.2465 +      (unix_valid (sysinbox()) || !errno || (errno == ENOENT)))
205.2466 +    return &mboxdriver;
205.2467 +  return NIL;			/* can't win (yet, anyway) */
205.2468 +}
205.2469 +
205.2470 +/* MBOX mail create mailbox
205.2471 + * Accepts: MAIL stream
205.2472 + *	    mailbox name to create
205.2473 + * Returns: T on success, NIL on failure
205.2474 + */
205.2475 +
205.2476 +long mbox_create (MAILSTREAM *stream,char *mailbox)
205.2477 +{
205.2478 +  char tmp[MAILTMPLEN];
205.2479 +  if (!compare_cstring (mailbox,"INBOX")) return unix_create (NIL,"mbox");
205.2480 +  sprintf (tmp,"Can't create non-INBOX name as mbox: %.80s",mailbox);
205.2481 +  MM_LOG (tmp,ERROR);
205.2482 +  return NIL;
205.2483 +}
205.2484 +
205.2485 +
205.2486 +/* MBOX mail delete mailbox
205.2487 + * Accepts: MAIL stream
205.2488 + *	    mailbox name to delete
205.2489 + * Returns: T on success, NIL on failure
205.2490 + */
205.2491 +
205.2492 +long mbox_delete (MAILSTREAM *stream,char *mailbox)
205.2493 +{
205.2494 +  return mbox_rename (stream,mailbox,NIL);
205.2495 +}
205.2496 +
205.2497 +
205.2498 +/* MBOX mail rename mailbox
205.2499 + * Accepts: MAIL stream
205.2500 + *	    old mailbox name
205.2501 + *	    new mailbox name (or NIL for delete)
205.2502 + * Returns: T on success, NIL on failure
205.2503 + */
205.2504 +
205.2505 +long mbox_rename (MAILSTREAM *stream,char *old,char *newname)
205.2506 +{
205.2507 +  char tmp[MAILTMPLEN];
205.2508 +  long ret = unix_rename (stream,"~/mbox",newname);
205.2509 +				/* recreate file if renamed INBOX */
205.2510 +  if (ret) unix_create (NIL,"mbox");
205.2511 +  else MM_LOG (tmp,ERROR);	/* log error */
205.2512 +  return ret;			/* return success */
205.2513 +}
205.2514 +
205.2515 +/* MBOX Mail status
205.2516 + * Accepts: mail stream
205.2517 + *	    mailbox name
205.2518 + *	    status flags
205.2519 + * Returns: T on success, NIL on failure
205.2520 + */
205.2521 +
205.2522 +long mbox_status (MAILSTREAM *stream,char *mbx,long flags)
205.2523 +{
205.2524 +  MAILSTATUS status;
205.2525 +  unsigned long i;
205.2526 +  MAILSTREAM *tstream = NIL;
205.2527 +  MAILSTREAM *systream = NIL;
205.2528 +				/* make temporary stream (unless this mbx) */
205.2529 +  if (!stream && !(stream = tstream =
205.2530 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
205.2531 +  status.flags = flags;		/* return status values */
205.2532 +  status.messages = stream->nmsgs;
205.2533 +  status.recent = stream->recent;
205.2534 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
205.2535 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
205.2536 +      if (!mail_elt (stream,i)->seen) status.unseen++;
205.2537 +  status.uidnext = stream->uid_last + 1;
205.2538 +  status.uidvalidity = stream->uid_validity;
205.2539 +  if (!status.recent &&		/* calculate post-snarf results */
205.2540 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
205.2541 +    status.messages += systream->nmsgs;
205.2542 +    status.recent += systream->recent;
205.2543 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
205.2544 +      for (i = 1; i <= systream->nmsgs; i++)
205.2545 +	if (!mail_elt (systream,i)->seen) status.unseen++;
205.2546 +				/* kludge but probably good enough */
205.2547 +    status.uidnext += systream->nmsgs;
205.2548 +  }
205.2549 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
205.2550 +  if (tstream) mail_close (tstream);
205.2551 +  if (systream) mail_close (systream);
205.2552 +  return T;			/* success */
205.2553 +}
205.2554 +
205.2555 +/* MBOX mail open
205.2556 + * Accepts: stream to open
205.2557 + * Returns: stream on success, NIL on failure
205.2558 + */
205.2559 +
205.2560 +MAILSTREAM *mbox_open (MAILSTREAM *stream)
205.2561 +{
205.2562 +  unsigned long i = 1;
205.2563 +  unsigned long recent = 0;
205.2564 +				/* return prototype for OP_PROTOTYPE call */
205.2565 +  if (!stream) return &mboxproto;
205.2566 +				/* change mailbox file name */
205.2567 +  fs_give ((void **) &stream->mailbox);
205.2568 +  stream->mailbox = cpystr ("mbox");
205.2569 +				/* open mailbox, snarf new mail */
205.2570 +  if (!(unix_open (stream) && mbox_ping (stream))) return NIL;
205.2571 +  stream->inbox = T;		/* mark that this is an INBOX */
205.2572 +				/* notify upper level of mailbox sizes */
205.2573 +  mail_exists (stream,stream->nmsgs);
205.2574 +  while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent;
205.2575 +  mail_recent (stream,recent);	/* including recent messages */
205.2576 +  return stream;
205.2577 +}
205.2578 +
205.2579 +/* MBOX mail ping mailbox
205.2580 + * Accepts: MAIL stream
205.2581 + * Returns: T if stream alive, else NIL
205.2582 + * No-op for readonly files, since read/writer can expunge it from under us!
205.2583 + */
205.2584 +
205.2585 +static int snarfed = 0;		/* number of snarfs */
205.2586 +
205.2587 +long mbox_ping (MAILSTREAM *stream)
205.2588 +{
205.2589 +  int sfd;
205.2590 +  unsigned long size;
205.2591 +  struct stat sbuf;
205.2592 +  char *s;
205.2593 +  DOTLOCK lock,lockx;
205.2594 +				/* time to try snarf and sysinbox non-empty? */
205.2595 +  if (LOCAL && !stream->rdonly && !stream->lock &&
205.2596 +      (time (0) >= (LOCAL->lastsnarf +
205.2597 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
205.2598 +      !stat (sysinbox (),&sbuf) && sbuf.st_size) {
205.2599 +    MM_CRITICAL (stream);	/* yes, go critical */
205.2600 +				/* open and lock sysinbox */
205.2601 +    if ((sfd = unix_lock (sysinbox (),O_RDWR,
205.2602 +			  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
205.2603 +			  &lockx,LOCK_EX)) >= 0) {
205.2604 +				/* locked sysinbox in good format? */
205.2605 +      if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) ||
205.2606 +	  !unix_isvalid_fd (sfd)) {
205.2607 +	sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format",
205.2608 +		 sysinbox ());
205.2609 +	MM_LOG (LOCAL->buf,ERROR);
205.2610 +      }
205.2611 +				/* sysinbox good, parse and excl-lock mbox */
205.2612 +      else if (unix_parse (stream,&lock,LOCK_EX)) {
205.2613 +	lseek (sfd,0,L_SET);	/* read entire sysinbox into memory */
205.2614 +	read (sfd,s = (char *) fs_get (size + 1),size);
205.2615 +	s[size] = '\0';		/* tie it off */
205.2616 +				/* append to end of mbox */
205.2617 +	lseek (LOCAL->fd,LOCAL->filesize,L_SET);
205.2618 +
205.2619 +				/* copy to mbox */
205.2620 +	if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) {
205.2621 +	  sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno));
205.2622 +	  MM_LOG (LOCAL->buf,WARN);
205.2623 +				/* revert mbox to previous size */
205.2624 +	  ftruncate (LOCAL->fd,LOCAL->filesize);
205.2625 +	}
205.2626 +				/* sysinbox better not have changed */
205.2627 +	else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) {
205.2628 +	  sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu",
205.2629 +		   sysinbox (),size,(unsigned long) sbuf.st_size);
205.2630 +	  MM_LOG (LOCAL->buf,ERROR);
205.2631 +				/* revert mbox to previous size */
205.2632 +	  ftruncate (LOCAL->fd,LOCAL->filesize);
205.2633 +	  /* Believe it or not, a Singaporean government system actually had
205.2634 +	   * symlinks from /var/mail/user to ~user/mbox.  To compound this
205.2635 +	   * error, they used an SVR4 system; BSD and OSF locks would have
205.2636 +	   * prevented it but not SVR4 locks.
205.2637 +	   */
205.2638 +	  if (!fstat (sfd,&sbuf) && (size == sbuf.st_size))
205.2639 +	    syslog (LOG_ALERT,"File %s and %s are the same file!",
205.2640 +		    sysinbox (),stream->mailbox);
205.2641 +	}
205.2642 +	else {			/* data copied OK */
205.2643 +	  ftruncate (sfd,0);	/* truncate sysinbox to zero bytes */
205.2644 +	  if (!snarfed++) {	/* have we snarfed before? */
205.2645 +				/* syslog if server, else user log */
205.2646 +	    sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s",
205.2647 +		     size,stream->mailbox,sysinbox ());
205.2648 +	    if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
205.2649 +			"unknown"))
205.2650 +	      syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ());
205.2651 +	    else MM_LOG (LOCAL->buf,WARN);
205.2652 +	  }
205.2653 +	}
205.2654 +				/* done with sysinbox text */
205.2655 +	fs_give ((void **) &s);
205.2656 +				/* all done with mbox */
205.2657 +	unix_unlock (LOCAL->fd,stream,&lock);
205.2658 +	mail_unlock (stream);	/* unlock the stream */
205.2659 +	MM_NOCRITICAL (stream);	/* done with critical */
205.2660 +      }
205.2661 +				/* all done with sysinbox */
205.2662 +      unix_unlock (sfd,NIL,&lockx);
205.2663 +    }
205.2664 +    MM_NOCRITICAL (stream);	/* done with critical */
205.2665 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
205.2666 +  }
205.2667 +  return unix_ping (stream);	/* do the unix routine now */
205.2668 +}
205.2669 +
205.2670 +/* MBOX mail check mailbox
205.2671 + * Accepts: MAIL stream
205.2672 + */
205.2673 +
205.2674 +void mbox_check (MAILSTREAM *stream)
205.2675 +{
205.2676 +				/* do local ping, then do unix routine */
205.2677 +  if (mbox_ping (stream)) unix_check (stream);
205.2678 +}
205.2679 +
205.2680 +
205.2681 +/* MBOX mail expunge mailbox
205.2682 + * Accepts: MAIL stream
205.2683 + *	    sequence to expunge if non-NIL
205.2684 + *	    expunge options
205.2685 + * Returns: T, always
205.2686 + */
205.2687 +
205.2688 +long mbox_expunge (MAILSTREAM *stream,char *sequence,long options)
205.2689 +{
205.2690 +  long ret = unix_expunge (stream,sequence,options);
205.2691 +  mbox_ping (stream);		/* do local ping */
205.2692 +  return ret;
205.2693 +}
205.2694 +
205.2695 +
205.2696 +/* MBOX mail append message from stringstruct
205.2697 + * Accepts: MAIL stream
205.2698 + *	    destination mailbox
205.2699 + *	    append callback
205.2700 + *	    data for callback
205.2701 + * Returns: T if append successful, else NIL
205.2702 + */
205.2703 +
205.2704 +long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
205.2705 +{
205.2706 +  char tmp[MAILTMPLEN];
205.2707 +  if (mbox_valid (mailbox)) return unix_append (stream,"mbox",af,data);
205.2708 +  sprintf (tmp,"Can't append to that name: %.80s",mailbox);
205.2709 +  MM_LOG (tmp,ERROR);
205.2710 +  return NIL;
205.2711 +}
   206.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   206.2 +++ b/src/osdep/amiga/unix.h	Mon Sep 14 15:17:45 2009 +0900
   206.3 @@ -0,0 +1,219 @@
   206.4 +/* ========================================================================
   206.5 + * Copyright 1988-2006 University of Washington
   206.6 + *
   206.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   206.8 + * you may not use this file except in compliance with the License.
   206.9 + * You may obtain a copy of the License at
  206.10 + *
  206.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  206.12 + *
  206.13 + * 
  206.14 + * ========================================================================
  206.15 + */
  206.16 +
  206.17 +/*
  206.18 + * Program:	UNIX mail routines, Amiga version
  206.19 + *
  206.20 + * Author:	Mark Crispin
  206.21 + *		Networks and Distributed Computing
  206.22 + *		Computing & Communications
  206.23 + *		University of Washington
  206.24 + *		Administration Building, AG-44
  206.25 + *		Seattle, WA  98195
  206.26 + *		Internet: MRC@CAC.Washington.EDU
  206.27 + *
  206.28 + * Date:	20 December 1989
  206.29 + * Last Edited:	30 August 2006
  206.30 + */
  206.31 +
  206.32 +
  206.33 +/*				DEDICATION
  206.34 + *
  206.35 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  206.36 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  206.37 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  206.38 + * a two-month bout with cirrhosis of the liver.
  206.39 + *
  206.40 + *  He was a dear friend, and I miss him terribly.
  206.41 + *
  206.42 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  206.43 + */
  206.44 +
  206.45 +/* Validate line
  206.46 + * Accepts: pointer to candidate string to validate as a From header
  206.47 + *	    return pointer to end of date/time field
  206.48 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  206.49 + *	    return pointer to offset from t of time zone (if non-zero)
  206.50 + * Returns: t,ti,zn set if valid From string, else ti is NIL
  206.51 + */
  206.52 +
  206.53 +#define VALID(s,x,ti,zn) {						\
  206.54 +  int remote = 0;							\
  206.55 +  ti = 0;								\
  206.56 +  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
  206.57 +      (s[4] == ' ')) {							\
  206.58 +    for (x = s + 5; *x && *x != '\012'; x++);				\
  206.59 +    if (*x) {								\
  206.60 +      if (x[-1] == '\015') --x;						\
  206.61 +      if (x - s >= 41) {						\
  206.62 +	for (zn = -1; x[zn] != ' '; zn--);				\
  206.63 +	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
  206.64 +	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
  206.65 +	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
  206.66 +	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
  206.67 +	  {								\
  206.68 +	    while (x[zn-13] == ' ') zn--;				\
  206.69 +	    x += zn - 12;						\
  206.70 +	    remote = 1;							\
  206.71 +	  }								\
  206.72 +      }									\
  206.73 +      if (x - s >= 27) {						\
  206.74 +	if (x[-5] == ' ') {						\
  206.75 +	  if (x[-8] == ':') zn = 0,ti = -5;				\
  206.76 +	  else if (x[-9] == ' ') ti = zn = -9;				\
  206.77 +	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
  206.78 +	    ti = zn = -11;						\
  206.79 +	}								\
  206.80 +	else if (x[-4] == ' ') {					\
  206.81 +	  if (x[-9] == ' ') zn = -4,ti = -9;				\
  206.82 +	  else if ( (x[-13] == ' ') && (x[-16] == ' ')			\
  206.83 +		&& (x[-20] ==' ') &&					\
  206.84 +		( ((x[-22] == ' ') && (x[-23] == ',')) ||		\
  206.85 +		  ((x[-23] == ' ') && (x[-24] == ',')) ) ) {		\
  206.86 +	    char weekday[4]={0,}, month[4]={0,}, time[11]={0,};		\
  206.87 +	    char tzone[4]={0,}; 					\
  206.88 +	    char realtime[80];						\
  206.89 +	    int day,year,start=-26;					\
  206.90 +	    if (x[-23] == ' ') x--;					\
  206.91 +	      sscanf(&x[start],"%3c, %d %s %d %s %s",			\
  206.92 +		weekday,&day,month,&year,time,tzone);			\
  206.93 +	      sprintf(realtime,"%s %s %2d %s %d %s",			\
  206.94 +		weekday,month,day,time, 				\
  206.95 +		( (year < 100) ? year+1900 : year),tzone);		\
  206.96 +	      if (remote)						\
  206.97 +		strcat(realtime," remote from ");			\
  206.98 +	      else							\
  206.99 +		strcat(realtime,"\n");					\
 206.100 +	      strncpy(&x[start],realtime,strlen(realtime));		\
 206.101 +	      zn = -2;							\
 206.102 +	      ti = -7;							\
 206.103 +	  }								\
 206.104 +	}								\
 206.105 +	else if (x[-6] == ' ') {					\
 206.106 +	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
 206.107 +	    zn = -6,ti = -11;						\
 206.108 +	}								\
 206.109 +	else if (x[-9] == ' ') {					\
 206.110 +	    if ( ( (x[-12] == ' ') && (x[-16] == ' ') &&		\
 206.111 +		  ( ((x[-18] == ' ') && (x[-19] == ',') )  ||		\
 206.112 +		    ((x[-19] == ' ') && (x[-20] == ',')) )		\
 206.113 +		||							\
 206.114 +		((x[-14] == ' ') && (x[-18] == ' ') &&			\
 206.115 +		  ( ((x[-20] == ' ') && (x[-21] == ',') )  ||		\
 206.116 +		    ((x[-21] == ' ') && (x[-22] == ',')) ) ) ) ) {	\
 206.117 +	      char weekday[4]={0,}, month[4]={0,},time[11]={0,};	\
 206.118 +	      int day,year,start=-24;					\
 206.119 +	      char realtime[80];					\
 206.120 +	      if (x[-12] == ' ') x++;					\
 206.121 +	      if (x[-19] == ' ') x++;					\
 206.122 +	      sscanf(&x[start],"%3c, %d %3c %d %s",weekday,		\
 206.123 +		     &day,month,&year,time);				\
 206.124 +	      sprintf(realtime,"%s %s %2d %s %d",weekday,month,day,time,\
 206.125 +		 ( (year < 100) ? year+1900 : year));			\
 206.126 +	      if (remote)						\
 206.127 +		strcat(realtime," remote from ");			\
 206.128 +	      else							\
 206.129 +		strcat(realtime,"\n");					\
 206.130 +	      strncpy(&x[start],realtime,strlen(realtime));		\
 206.131 +	      ti=-5;							\
 206.132 +	      zn=0;							\
 206.133 +	    }								\
 206.134 +	}								\
 206.135 +	if (ti && !((x[ti - 3] == ':') &&				\
 206.136 +		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
 206.137 +		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
 206.138 +		    (x[ti - 11] == ' '))) ti = 0;			\
 206.139 +      }									\
 206.140 +    }									\
 206.141 +  }									\
 206.142 +}
 206.143 +
 206.144 +/* You are not expected to understand this macro, but read the next page if
 206.145 + * you are not faint of heart.
 206.146 + *
 206.147 + * Known formats to the VALID macro are:
 206.148 + *		From user Wed Dec  2 05:53 1992
 206.149 + * BSD		From user Wed Dec  2 05:53:22 1992
 206.150 + * SysV		From user Wed Dec  2 05:53 PST 1992
 206.151 + * rn		From user Wed Dec  2 05:53:22 PST 1992
 206.152 + *		From user Wed Dec  2 05:53 -0700 1992
 206.153 + * emacs	From user Wed Dec  2 05:53:22 -0700 1992
 206.154 + *		From user Wed Dec  2 05:53 1992 PST
 206.155 + *		From user Wed Dec  2 05:53:22 1992 PST
 206.156 + *		From user Wed Dec  2 05:53 1992 -0700
 206.157 + * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
 206.158 + *
 206.159 + * Amiga	From user Wed, 6 Dec 92 05:53:22 who did this !!!
 206.160 + *		CHANGED in place to
 206.161 + *		From user Wed Dec  2 05:53:22 1992
 206.162 + *
 206.163 + * Plus all of the above with `` remote from xxx'' after it. Thank you very
 206.164 + * much, smail and Solaris, for making my life considerably more complicated.
 206.165 + */
 206.166 +
 206.167 +/*
 206.168 + * What?  You want to understand the VALID macro anyway?  Alright, since you
 206.169 + * insist.  Actually, it isn't really all that difficult, provided that you
 206.170 + * take it step by step.
 206.171 + *
 206.172 + * Line 1	Initializes the return ti value to failure (0);
 206.173 + * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
 206.174 + * Lines 4-6	Validates that there is an end of line and points x at it.
 206.175 + * Lines 7-14	First checks to see if the line is at least 41 characters long.
 206.176 + *		If so, it scans backwards to find the rightmost space.  From
 206.177 + *		that point, it scans backwards to see if the string matches
 206.178 + *		`` remote from''.  If so, it sets x to point to the space at
 206.179 + *		the start of the string.
 206.180 + * Line 15	Makes sure that there are at least 27 characters in the line.
 206.181 + * Lines 16-21	Checks if the date/time ends with the year (there is a space
 206.182 + *		five characters back).  If there is a colon three characters
 206.183 + *		further back, there is no timezone field, so zn is set to 0
 206.184 + *		and ti is set in front of the year.  Otherwise, there must
 206.185 + *		either to be a space four characters back for a three-letter
 206.186 + *		timezone, or a space six characters back followed by a + or -
 206.187 + *		for a numeric timezone; in either case, zn and ti become the
 206.188 + *		offset of the space immediately before it.
 206.189 + * Lines 22-24	Are the failure case for line 14.  If there is a space four
 206.190 + *		characters back, it is a three-letter timezone; there must be a
 206.191 + *		space for the year nine characters back.  zn is the zone
 206.192 + *		offset; ti is the offset of the space.
 206.193 + * Lines 25-28	Are the failure case for line 20.  If there is a space six
 206.194 + *		characters back, it is a numeric timezone; there must be a
 206.195 + *		space eleven characters back and a + or - five characters back.
 206.196 + *		zn is the zone offset; ti is the offset of the space.
 206.197 + * Line 29-32	If ti is valid, make sure that the string before ti is of the
 206.198 + *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
 206.199 + *		invalidate ti.  There must be a colon three characters back
 206.200 + *		and a space six or nine	characters back (depending upon
 206.201 + *		whether or not the character six characters back is a colon).
 206.202 + *		There must be a space three characters further back (in front
 206.203 + *		of the day), one seven characters back (in front of the month),
 206.204 + *		and one eleven characters back (in front of the day of week).
 206.205 + *		ti is set to be the offset of the space before the time.
 206.206 + *
 206.207 + * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
 206.208 + * newer pipelined machines it is faster being open-coded than it would be if
 206.209 + * subroutines are called.
 206.210 + *
 206.211 + * Why does it scan backwards from the end of the line, instead of doing the
 206.212 + * much easier forward scan?  There is no deterministic way to parse the
 206.213 + * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
 206.214 + * see if unquoted spaces were possible.  They are, and I've encountered enough
 206.215 + * evil mail to be totally unwilling to trust that ``it will never happen''.
 206.216 + */
 206.217 +
 206.218 +/* Build parameters */
 206.219 +
 206.220 +#define KODRETRY 15		/* kiss-of-death retry in seconds */
 206.221 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
 206.222 +#define CHUNK 16384		/* read-in chunk size */
   207.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   207.2 +++ b/src/osdep/amiga/write.c	Mon Sep 14 15:17:45 2009 +0900
   207.3 @@ -0,0 +1,59 @@
   207.4 +/* ========================================================================
   207.5 + * Copyright 1988-2006 University of Washington
   207.6 + *
   207.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   207.8 + * you may not use this file except in compliance with the License.
   207.9 + * You may obtain a copy of the License at
  207.10 + *
  207.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  207.12 + *
  207.13 + * 
  207.14 + * ========================================================================
  207.15 + */
  207.16 +
  207.17 +/*
  207.18 + * Program:	Write data, treating partial writes as an error
  207.19 + *
  207.20 + * Author:	Mark Crispin
  207.21 + *		Networks and Distributed Computing
  207.22 + *		Computing & Communications
  207.23 + *		University of Washington
  207.24 + *		Administration Building, AG-44
  207.25 + *		Seattle, WA  98195
  207.26 + *		Internet: MRC@CAC.Washington.EDU
  207.27 + *
  207.28 + * Date:	26 May 1995
  207.29 + * Last Edited:	30 August 2006
  207.30 + */
  207.31 +
  207.32 +/*  The whole purpose of this unfortunate routine is to deal with DOS and
  207.33 + * certain cretinous versions of UNIX which decided that the "bytes actually
  207.34 + * written" return value from write() gave them license to use that for things
  207.35 + * that are really errors, such as disk quota exceeded, maximum file size
  207.36 + * exceeded, disk full, etc.
  207.37 + * 
  207.38 + *  BSD won't screw us this way on the local filesystem, but who knows what
  207.39 + * some NFS-mounted filesystem will do.
  207.40 + */
  207.41 +
  207.42 +#undef write
  207.43 +
  207.44 +/* Write data to file
  207.45 + * Accepts: file descriptor
  207.46 + *	    I/O vector structure
  207.47 + *	    number of vectors in structure
  207.48 + * Returns: number of bytes written if successful, -1 if failure
  207.49 + */
  207.50 +
  207.51 +long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
  207.52 +
  207.53 +long safe_write (int fd,char *buf,long nbytes)
  207.54 +{
  207.55 +  long i,j;
  207.56 +  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
  207.57 +    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
  207.58 +	   (errno == EINTR));
  207.59 +    if (j < 0) return j;
  207.60 +  }
  207.61 +  return nbytes;
  207.62 +}
   208.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   208.2 +++ b/src/osdep/dos/bezrkdos.c	Mon Sep 14 15:17:45 2009 +0900
   208.3 @@ -0,0 +1,901 @@
   208.4 +/* ========================================================================
   208.5 + * Copyright 1988-2006 University of Washington
   208.6 + *
   208.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   208.8 + * you may not use this file except in compliance with the License.
   208.9 + * You may obtain a copy of the License at
  208.10 + *
  208.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  208.12 + *
  208.13 + * 
  208.14 + * ========================================================================
  208.15 + */
  208.16 +
  208.17 +/*
  208.18 + * Program:	Berkeley mail routines
  208.19 + *
  208.20 + * Author:	Mark Crispin
  208.21 + *		Networks and Distributed Computing
  208.22 + *		Computing & Communications
  208.23 + *		University of Washington
  208.24 + *		Administration Building, AG-44
  208.25 + *		Seattle, WA  98195
  208.26 + *		Internet: MRC@CAC.Washington.EDU
  208.27 + *
  208.28 + * Date:	24 June 1992
  208.29 + * Last Edited:	30 August 2006
  208.30 + */
  208.31 +
  208.32 +
  208.33 +/* Dedication:
  208.34 + *  This file is dedicated with affection to those Merry Marvels of Musical
  208.35 + * Madness . . .
  208.36 + *  ->  The Incomparable Leland Stanford Junior University Marching Band  <-
  208.37 + * who entertain, awaken, and outrage Stanford fans in the fact of repeated
  208.38 + * losing seasons and shattered Rose Bowl dreams [Cardinal just don't have
  208.39 + * HUSKY FEVER!!!].
  208.40 + *
  208.41 + */
  208.42 +
  208.43 +#include <ctype.h>
  208.44 +#include <errno.h>
  208.45 +#include <fcntl.h>
  208.46 +#include "mail.h"
  208.47 +#include "osdep.h"
  208.48 +#include <time.h>
  208.49 +#include <sys\stat.h>
  208.50 +#include <dos.h>
  208.51 +#include "rfc822.h"
  208.52 +#include "dummy.h"
  208.53 +#include "misc.h"
  208.54 +#include "fdstring.h"
  208.55 +
  208.56 +/* Berkeley I/O stream local data */
  208.57 +	
  208.58 +typedef struct bezerk_local {
  208.59 +  int fd;			/* file descriptor for I/O */
  208.60 +  off_t filesize;		/* file size parsed */
  208.61 +  char *buf;			/* temporary buffer */
  208.62 +} BEZERKLOCAL;
  208.63 +
  208.64 +
  208.65 +/* Convenient access to local data */
  208.66 +
  208.67 +#define LOCAL ((BEZERKLOCAL *) stream->local)
  208.68 +
  208.69 +/* Function prototypes */
  208.70 +
  208.71 +DRIVER *bezerk_valid (char *name);
  208.72 +long bezerk_isvalid (char *name,char *tmp);
  208.73 +int bezerk_valid_line (char *s,char **rx,int *rzn);
  208.74 +void *bezerk_parameters (long function,void *value);
  208.75 +void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  208.76 +void bezerk_list (MAILSTREAM *stream,char *ref,char *pat);
  208.77 +void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat);
  208.78 +long bezerk_create (MAILSTREAM *stream,char *mailbox);
  208.79 +long bezerk_delete (MAILSTREAM *stream,char *mailbox);
  208.80 +long bezerk_rename (MAILSTREAM *stream,char *old,char *newname);
  208.81 +MAILSTREAM *bezerk_open (MAILSTREAM *stream);
  208.82 +void bezerk_close (MAILSTREAM *stream,long options);
  208.83 +char *bezerk_header (MAILSTREAM *stream,unsigned long msgno,
  208.84 +		     unsigned long *length,long flags);
  208.85 +long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,
  208.86 +		  long flags);
  208.87 +long bezerk_ping (MAILSTREAM *stream);
  208.88 +void bezerk_check (MAILSTREAM *stream);
  208.89 +long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options);
  208.90 +long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
  208.91 +		  long options);
  208.92 +long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  208.93 +int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
  208.94 +		     STRING *msg);
  208.95 +void bezerk_gc (MAILSTREAM *stream,long gcflags);
  208.96 +char *bezerk_file (char *dst,char *name);
  208.97 +long bezerk_badname (char *tmp,char *s);
  208.98 +long bezerk_parse (MAILSTREAM *stream);
  208.99 +unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 208.100 +			     unsigned long *size);
 208.101 +
 208.102 +/* Berkeley mail routines */
 208.103 +
 208.104 +
 208.105 +/* Driver dispatch used by MAIL */
 208.106 +
 208.107 +DRIVER bezerkdriver = {
 208.108 +  "bezerk",			/* driver name */
 208.109 +				/* driver flags */
 208.110 +  DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY,
 208.111 +  (DRIVER *) NIL,		/* next driver */
 208.112 +  bezerk_valid,			/* mailbox is valid for us */
 208.113 +  bezerk_parameters,		/* manipulate parameters */
 208.114 +  bezerk_scan,			/* scan mailboxes */
 208.115 +  bezerk_list,			/* list mailboxes */
 208.116 +  bezerk_lsub,			/* list subscribed mailboxes */
 208.117 +  NIL,				/* subscribe to mailbox */
 208.118 +  NIL,				/* unsubscribe from mailbox */
 208.119 +  bezerk_create,		/* create mailbox */
 208.120 +  bezerk_delete,		/* delete mailbox */
 208.121 +  bezerk_rename,		/* rename mailbox */
 208.122 +  mail_status_default,		/* status of mailbox */
 208.123 +  bezerk_open,			/* open mailbox */
 208.124 +  bezerk_close,			/* close mailbox */
 208.125 +  NIL,				/* fetch message "fast" attributes */
 208.126 +  NIL,				/* fetch message flags */
 208.127 +  NIL,				/* fetch overview */
 208.128 +  NIL,				/* fetch message envelopes */
 208.129 +  bezerk_header,		/* fetch message header */
 208.130 +  bezerk_text,			/* fetch message text */
 208.131 +  NIL,				/* fetch partial message text */
 208.132 +  NIL,				/* unique identifier */
 208.133 +  NIL,				/* message number */
 208.134 +  NIL,				/* modify flags */
 208.135 +  NIL,				/* per-message modify flags */
 208.136 +  NIL,				/* search for message based on criteria */
 208.137 +  NIL,				/* sort messages */
 208.138 +  NIL,				/* thread messages */
 208.139 +  bezerk_ping,			/* ping mailbox to see if still alive */
 208.140 +  bezerk_check,			/* check for new messages */
 208.141 +  bezerk_expunge,		/* expunge deleted messages */
 208.142 +  bezerk_copy,			/* copy messages to another mailbox */
 208.143 +  bezerk_append,		/* append string message to mailbox */
 208.144 +  NIL				/* garbage collect stream */
 208.145 +};
 208.146 +
 208.147 +				/* prototype stream */
 208.148 +MAILSTREAM bezerkproto = {&bezerkdriver};
 208.149 +
 208.150 +/* Berkeley mail validate mailbox
 208.151 + * Accepts: mailbox name
 208.152 + * Returns: our driver if name is valid, NIL otherwise
 208.153 + */
 208.154 +
 208.155 +DRIVER *bezerk_valid (char *name)
 208.156 +{
 208.157 +  char tmp[MAILTMPLEN];
 208.158 +  return bezerk_isvalid (name,tmp) ? &bezerkdriver : (DRIVER *) NIL;
 208.159 +}
 208.160 +
 208.161 +
 208.162 +/* Berkeley mail test for valid mailbox
 208.163 + * Accepts: mailbox name
 208.164 + * Returns: T if valid, NIL otherwise
 208.165 + */
 208.166 +
 208.167 +long bezerk_isvalid (char *name,char *tmp)
 208.168 +{
 208.169 +  int fd;
 208.170 +  long ret = NIL;
 208.171 +  struct stat sbuf;
 208.172 +  errno = EINVAL;		/* assume invalid argument */
 208.173 +				/* if file, get its status */
 208.174 +  if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) {
 208.175 +    if (!sbuf.st_size)errno = 0;/* empty file */
 208.176 +    else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) {
 208.177 +      memset (tmp,'\0',MAILTMPLEN);
 208.178 +      errno = -1;		/* in case bezerk_valid_line fails */
 208.179 +      if (read (fd,tmp,MAILTMPLEN-1) >= 0)
 208.180 +	ret = bezerk_valid_line (tmp,NIL,NIL);
 208.181 +      close (fd);		/* close the file */
 208.182 +    }
 208.183 +  }
 208.184 +				/* in case INBOX but not bezerk format */
 208.185 +  else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) &&
 208.186 +	   ((name[1] == 'N') || (name[1] == 'n')) &&
 208.187 +	   ((name[2] == 'B') || (name[2] == 'b')) &&
 208.188 +	   ((name[3] == 'O') || (name[3] == 'o')) &&
 208.189 +	   ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1;
 208.190 +  return ret;			/* return what we should */
 208.191 +}
 208.192 +
 208.193 +/* Validate line
 208.194 + * Accepts: pointer to candidate string to validate as a From header
 208.195 + *	    return pointer to end of date/time field
 208.196 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
 208.197 + *	    return pointer to offset from t of time zone (if non-zero)
 208.198 + * Returns: t,ti,zn set if valid From string, else ti is NIL
 208.199 + */
 208.200 +
 208.201 +int bezerk_valid_line (char *s,char **rx,int *rzn)
 208.202 +{
 208.203 +  char *x;
 208.204 +  int zn;
 208.205 +  int ti = 0;
 208.206 +				/* line must begin with "From " */
 208.207 +  if ((*s != 'F') || (s[1] != 'r') || (s[2] != 'o') || (s[3] != 'm') ||
 208.208 +	(s[4] != ' ')) return NIL;
 208.209 +				/* find end of line */
 208.210 +  for (x = s + 5; *x && *x != '\012'; x++);
 208.211 +  if (!x) return NIL;		/* end of line not found */
 208.212 +  if (x[-1] == '\015') x--;	/* ignore CR */
 208.213 +  if ((x - s < 27)) return NIL;	/* line too short */
 208.214 +  if (x - s >= 41) {		/* possible search for " remote from " */
 208.215 +    for (zn = -1; x[zn] != ' '; zn--);
 208.216 +    if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&
 208.217 +	(x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&
 208.218 +	(x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&
 208.219 +	(x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))
 208.220 +      x += zn - 12;
 208.221 +  }
 208.222 +  if (x[-5] == ' ') {		/* ends with year? */
 208.223 +				/* no timezone? */
 208.224 +    if (x[-8] == ':') zn = 0,ti = -5;
 208.225 +				/* three letter timezone? */
 208.226 +    else if (x[-9] == ' ') ti = zn = -9;
 208.227 +				/* numeric timezone? */
 208.228 +    else if ((x[-11]==' ') && ((x[-10]=='+') || (x[-10]=='-'))) ti = zn = -11;
 208.229 +  }
 208.230 +  else if (x[-4] == ' ') {	/* no year and three leter timezone? */
 208.231 +    if (x[-9] == ' ') zn = -4,ti = -9;
 208.232 +  }
 208.233 +  else if (x[-6] == ' ') {	/* no year and numeric timezone? */
 208.234 +    if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))
 208.235 +      zn = -6,ti = -11;
 208.236 +  }
 208.237 +				/* time must be www mmm dd hh:mm[:ss] */
 208.238 +  if (ti && !((x[ti - 3] == ':') &&
 208.239 +	      (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&
 208.240 +	      (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&
 208.241 +	      (x[ti - 11] == ' '))) return NIL;
 208.242 +  if (rx) *rx = x;		/* set return values */
 208.243 +  if (rzn) *rzn = zn;
 208.244 +  return ti;
 208.245 +}
 208.246 +
 208.247 +/* Berkeley manipulate driver parameters
 208.248 + * Accepts: function code
 208.249 + *	    function-dependent value
 208.250 + * Returns: function-dependent return value
 208.251 + */
 208.252 +
 208.253 +void *bezerk_parameters (long function,void *value)
 208.254 +{
 208.255 +  return NIL;
 208.256 +}
 208.257 +
 208.258 +
 208.259 +/* Berkeley mail scan mailboxes
 208.260 + * Accepts: mail stream
 208.261 + *	    reference
 208.262 + *	    pattern to search
 208.263 + *	    string to scan
 208.264 + */
 208.265 +
 208.266 +void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 208.267 +{
 208.268 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 208.269 +}
 208.270 +
 208.271 +
 208.272 +/* Berkeley mail list mailboxes
 208.273 + * Accepts: mail stream
 208.274 + *	    reference
 208.275 + *	    pattern to search
 208.276 + */
 208.277 +
 208.278 +void bezerk_list (MAILSTREAM *stream,char *ref,char *pat)
 208.279 +{
 208.280 +  if (stream) dummy_list (stream,ref,pat);
 208.281 +}
 208.282 +
 208.283 +
 208.284 +/* Berkeley mail list subscribed mailboxes
 208.285 + * Accepts: mail stream
 208.286 + *	    reference
 208.287 + *	    pattern to search
 208.288 + */
 208.289 +
 208.290 +void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat)
 208.291 +{
 208.292 +  if (stream) dummy_lsub (stream,ref,pat);
 208.293 +}
 208.294 +
 208.295 +/* Berkeley mail create mailbox
 208.296 + * Accepts: MAIL stream
 208.297 + *	    mailbox name to create
 208.298 + * Returns: T on success, NIL on failure
 208.299 + */
 208.300 +
 208.301 +long bezerk_create (MAILSTREAM *stream,char *mailbox)
 208.302 +{
 208.303 +  return dummy_create (stream,mailbox);
 208.304 +}
 208.305 +
 208.306 +
 208.307 +/* Berkeley mail delete mailbox
 208.308 + * Accepts: MAIL stream
 208.309 + *	    mailbox name to delete
 208.310 + * Returns: T on success, NIL on failure
 208.311 + */
 208.312 +
 208.313 +long bezerk_delete (MAILSTREAM *stream,char *mailbox)
 208.314 +{
 208.315 +  return dummy_delete (stream,mailbox);
 208.316 +}
 208.317 +
 208.318 +
 208.319 +/* Berkeley mail rename mailbox
 208.320 + * Accepts: MAIL stream
 208.321 + *	    old mailbox name
 208.322 + *	    new mailbox name (or NIL for delete)
 208.323 + * Returns: T on success, NIL on failure
 208.324 + */
 208.325 +
 208.326 +long bezerk_rename (MAILSTREAM *stream,char *old,char *newname)
 208.327 +{
 208.328 +  return dummy_rename (stream,old,newname);
 208.329 +}
 208.330 +
 208.331 +/* Berkeley mail open
 208.332 + * Accepts: stream to open
 208.333 + * Returns: stream on success, NIL on failure
 208.334 + */
 208.335 +
 208.336 +MAILSTREAM *bezerk_open (MAILSTREAM *stream)
 208.337 +{
 208.338 +  long i;
 208.339 +  int fd;
 208.340 +  char *s;
 208.341 +  char tmp[MAILTMPLEN];
 208.342 +				/* return prototype for OP_PROTOTYPE call */
 208.343 +  if (!stream) return &bezerkproto;
 208.344 +  if (stream->local) fatal ("bezerk recycle stream");
 208.345 +  if (!mailboxfile (tmp,stream->mailbox))
 208.346 +    return (MAILSTREAM *) bezerk_badname (tmp,stream->mailbox);
 208.347 +  if (((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0)) {
 208.348 +    sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 208.349 +    mm_log (tmp,ERROR);
 208.350 +    return NIL;
 208.351 +  }
 208.352 +  stream->rdonly = T;		/* this driver is readonly */
 208.353 +  stream->local = fs_get (sizeof (BEZERKLOCAL));
 208.354 +				/* canonicalize the stream mailbox name */
 208.355 +  fs_give ((void **) &stream->mailbox);
 208.356 +  if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0';
 208.357 +  stream->mailbox = cpystr (tmp);
 208.358 +  LOCAL->fd = fd;		/* note the file */
 208.359 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 208.360 +  LOCAL->buf = NIL;		/* initially no local buffer */
 208.361 +  stream->sequence++;		/* bump sequence number */
 208.362 +  stream->uid_validity = time (0);
 208.363 +				/* parse mailbox */
 208.364 +  stream->nmsgs = stream->recent = 0;
 208.365 +  if (!bezerk_ping (stream)) return NIL;
 208.366 +  if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL);
 208.367 +  stream->perm_seen = stream->perm_deleted =
 208.368 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft = NIL;
 208.369 +  stream->perm_user_flags = NIL;
 208.370 +  return stream;		/* return stream to caller */
 208.371 +}
 208.372 +
 208.373 +/* Berkeley mail close
 208.374 + * Accepts: MAIL stream
 208.375 + *	    close options
 208.376 + */
 208.377 +
 208.378 +void bezerk_close (MAILSTREAM *stream,long options)
 208.379 +{
 208.380 +  if (stream && LOCAL) {	/* only if a file is open */
 208.381 +    int silent = stream->silent;
 208.382 +    stream->silent = T;
 208.383 +    if (options & CL_EXPUNGE) bezerk_expunge (stream,NIL,NIL);
 208.384 +    close (LOCAL->fd);		/* close the local file */
 208.385 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 208.386 +				/* nuke the local data */
 208.387 +    fs_give ((void **) &stream->local);
 208.388 +    stream->dtb = NIL;		/* log out the DTB */
 208.389 +  }
 208.390 +}
 208.391 +
 208.392 +/* Berkeley mail fetch message header
 208.393 + * Accepts: MAIL stream
 208.394 + *	    message # to fetch
 208.395 + *	    pointer to returned header text length
 208.396 + *	    option flags
 208.397 + * Returns: message header in RFC822 format
 208.398 + */
 208.399 +
 208.400 +char *bezerk_header (MAILSTREAM *stream,unsigned long msgno,
 208.401 +		     unsigned long *length,long flags)
 208.402 +{
 208.403 +  char tmp[MAILTMPLEN];
 208.404 +  *length = 0;			/* default to empty */
 208.405 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 208.406 +				/* get to header position */
 208.407 +  lseek (LOCAL->fd,bezerk_hdrpos (stream,msgno,length),L_SET);
 208.408 +				/* is buffer big enough? */
 208.409 +  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 208.410 +  LOCAL->buf = (char *) fs_get ((size_t) *length + 1);
 208.411 +  LOCAL->buf[*length] = '\0';	/* tie off string */
 208.412 +				/* slurp the data */
 208.413 +  read (LOCAL->fd,LOCAL->buf,(size_t) *length);
 208.414 +  return LOCAL->buf;
 208.415 +}
 208.416 +
 208.417 +
 208.418 +/* Berkeley mail fetch message text (body only)
 208.419 + * Accepts: MAIL stream
 208.420 + *	    message # to fetch
 208.421 + *	    pointer to returned header text length
 208.422 + *	    option flags
 208.423 + * Returns: T, always
 208.424 + */
 208.425 +
 208.426 +long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 208.427 +{
 208.428 +  MESSAGECACHE *elt;
 208.429 +  FDDATA d;
 208.430 +  unsigned long hdrsize,hdrpos;
 208.431 +				/* UID call "impossible" */
 208.432 +  if (flags & FT_UID) return NIL;
 208.433 +  elt = mail_elt (stream,msgno);/* if message not seen */
 208.434 +				/* mark message as seen */
 208.435 +  if (elt->seen && !(flags & FT_PEEK)) {
 208.436 +    elt->seen = T;
 208.437 +    mm_flags (stream,msgno);
 208.438 +  }
 208.439 +				/* get location of text data */
 208.440 +  hdrpos = bezerk_hdrpos (stream,msgno,&hdrsize);
 208.441 +  d.fd = LOCAL->fd;		/* set initial stringstruct */
 208.442 +  d.pos = hdrpos + hdrsize;
 208.443 +				/* flush old buffer */
 208.444 +  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 208.445 +  d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE);
 208.446 +  INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize);
 208.447 +  return T;			/* success */
 208.448 +}
 208.449 +
 208.450 +/* Berkeley mail ping mailbox
 208.451 + * Accepts: MAIL stream
 208.452 + * Returns: T if stream still alive, NIL if not
 208.453 + */
 208.454 +
 208.455 +long bezerk_ping (MAILSTREAM *stream)
 208.456 +{
 208.457 +				/* punt if stream no longer alive */
 208.458 +  if (!(stream && LOCAL)) return NIL;
 208.459 +				/* parse mailbox, punt if parse dies */
 208.460 +  return (bezerk_parse (stream)) ? T : NIL;
 208.461 +}
 208.462 +
 208.463 +
 208.464 +/* Berkeley mail check mailbox (reparses status too)
 208.465 + * Accepts: MAIL stream
 208.466 + */
 208.467 +
 208.468 +void bezerk_check (MAILSTREAM *stream)
 208.469 +{
 208.470 +  unsigned long i = 1;
 208.471 +  if (bezerk_ping (stream)) {	/* ping mailbox */
 208.472 +				/* get new message status */
 208.473 +    while (i <= stream->nmsgs) mail_elt (stream,i++);
 208.474 +    mm_log ("Check completed",(long) NIL);
 208.475 +  }
 208.476 +}
 208.477 +
 208.478 +/* Berkeley mail expunge mailbox
 208.479 + * Accepts: MAIL stream
 208.480 + *	    sequence to expunge if non-NIL
 208.481 + *	    expunge options
 208.482 + * Returns: T, always
 208.483 + */
 208.484 +
 208.485 +long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options)
 208.486 +{
 208.487 +  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",WARN);
 208.488 +  return LONGT;
 208.489 +}
 208.490 +
 208.491 +/* Berkeley mail copy message(s)
 208.492 + * Accepts: MAIL stream
 208.493 + *	    sequence
 208.494 + *	    destination mailbox
 208.495 + *	    copy options
 208.496 + * Returns: T if success, NIL if failed
 208.497 + */
 208.498 +
 208.499 +long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 208.500 +{
 208.501 +  char tmp[MAILTMPLEN];
 208.502 +  struct stat sbuf;
 208.503 +  MESSAGECACHE *elt;
 208.504 +  unsigned long i,j,k;
 208.505 +  int fd;
 208.506 +  mailproxycopy_t pc =
 208.507 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 208.508 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 208.509 +	mail_sequence (stream,sequence))) return NIL;
 208.510 +				/* make sure valid mailbox */
 208.511 +  if (!bezerk_isvalid (mailbox,tmp) && errno) {
 208.512 +    if (errno == ENOENT)
 208.513 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
 208.514 +		 (long) NIL);
 208.515 +    else if (pc) return (*pc) (stream,sequence,mailbox,options);
 208.516 +    else if (mailboxfile (tmp,mailbox)) {
 208.517 +      sprintf (tmp,"Not a Bezerk-format mailbox: %s",mailbox);
 208.518 +      mm_log (tmp,ERROR);
 208.519 +    }
 208.520 +    else bezerk_badname (tmp,mailbox);
 208.521 +    return NIL;
 208.522 +  }
 208.523 +				/* open the destination */
 208.524 +  if (!mailboxfile (tmp,mailbox) ||
 208.525 +      (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
 208.526 +		  S_IREAD|S_IWRITE)) < 0) {
 208.527 +    sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno));
 208.528 +    mm_log (tmp,ERROR);
 208.529 +    return NIL;
 208.530 +  }
 208.531 +
 208.532 +  mm_critical (stream);		/* go critical */
 208.533 +  fstat (fd,&sbuf);		/* get current file size */
 208.534 +				/* for each requested message */
 208.535 +  for (i = 1; i <= stream->nmsgs; i++)
 208.536 +    if ((elt = mail_elt (stream,i))->sequence) {
 208.537 +      lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET);
 208.538 +				/* number of bytes to copy */
 208.539 +      j = elt->private.msg.full.offset + elt->rfc822_size;
 208.540 +      do {			/* read from source position */
 208.541 +	k = min (j,(unsigned long) MAILTMPLEN);
 208.542 +	read (LOCAL->fd,tmp,(unsigned int) k);
 208.543 +	if (write (fd,tmp,(unsigned int) k) < 0) {
 208.544 +	  sprintf (tmp,"Unable to write message: %s",strerror (errno));
 208.545 +	  mm_log (tmp,ERROR);
 208.546 +	  chsize (fd,sbuf.st_size);
 208.547 +	  close (fd);		/* punt */
 208.548 +	  mm_nocritical (stream);
 208.549 +	  return NIL;
 208.550 +	}
 208.551 +      } while (j -= k);		/* until done */
 208.552 +    }
 208.553 +  close (fd);			/* close the file */
 208.554 +  mm_nocritical (stream);	/* release critical */
 208.555 +				/* delete all requested messages */
 208.556 +  if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
 208.557 +    if ((elt = mail_elt (stream,i))->sequence) elt->deleted = T;
 208.558 +  if (mail_parameters (NIL,GET_COPYUID,NIL))
 208.559 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
 208.560 +  return T;
 208.561 +}
 208.562 +
 208.563 +/* Berkeley mail append message from stringstruct
 208.564 + * Accepts: MAIL stream
 208.565 + *	    destination mailbox
 208.566 + *	    append callback
 208.567 + *	    data for callback
 208.568 + * Returns: T if append successful, else NIL
 208.569 + */
 208.570 +
 208.571 +#define BUFLEN MAILTMPLEN
 208.572 +
 208.573 +long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 208.574 +{
 208.575 +  struct stat sbuf;
 208.576 +  int fd;
 208.577 +  unsigned long i,j;
 208.578 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
 208.579 +  FILE *sf,*df;
 208.580 +  MESSAGECACHE elt;
 208.581 +  STRING *message;
 208.582 +  long ret = LONGT;
 208.583 +				/* default stream to prototype */
 208.584 +  if (!stream) stream = &bezerkproto;
 208.585 +				/* make sure valid mailbox */
 208.586 +  if (!bezerk_isvalid (mailbox,tmp) && errno) {
 208.587 +    if (errno == ENOENT) {
 208.588 +      if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
 208.589 +	  ((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
 208.590 +	  ((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
 208.591 +	  ((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
 208.592 +	  ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5])
 208.593 +	bezerk_create (NIL,"INBOX");
 208.594 +      else {
 208.595 +	mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 208.596 +	return NIL;
 208.597 +      }
 208.598 +    }
 208.599 +    else if (mailboxfile (tmp,mailbox)) {
 208.600 +      sprintf (tmp,"Not a Bezerk-format mailbox: %.80ss",mailbox);
 208.601 +      mm_log (tmp,ERROR);
 208.602 +    }
 208.603 +    else bezerk_badname (tmp,mailbox);
 208.604 +    return NIL;
 208.605 +  }
 208.606 +  tzset ();			/* initialize timezone stuff */
 208.607 +				/* get first message */
 208.608 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
 208.609 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
 208.610 +    sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
 208.611 +    mm_log (tmp,ERROR);
 208.612 +  }
 208.613 +
 208.614 +  do {				/* parse date */
 208.615 +    if (!date) rfc822_date (date = tmp);
 208.616 +    if (!mail_parse_date (&elt,date)) {
 208.617 +      sprintf (tmp,"Bad date in append: %.80s",date);
 208.618 +      mm_log (tmp,ERROR);
 208.619 +    }
 208.620 +    else {			/* user wants to suppress time zones? */
 208.621 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
 208.622 +	time_t when = mail_longdate (&elt);
 208.623 +	date = ctime (&when);	/* use traditional date */
 208.624 +      }
 208.625 +				/* use POSIX-style date */
 208.626 +      else date = mail_cdate (tmp,&elt);
 208.627 +      if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
 208.628 +      else if (!bezerk_append_msg (stream,sf,flags,date,message)) {
 208.629 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
 208.630 +	mm_log (tmp,ERROR);
 208.631 +      }
 208.632 +				/* get next message */
 208.633 +      else if ((*af) (stream,data,&flags,&date,&message)) continue;
 208.634 +    }
 208.635 +    fclose (sf);		/* punt scratch file */
 208.636 +    return NIL;			/* give up */
 208.637 +  } while (message);		/* until no more messages */
 208.638 +  if (fflush (sf) || fstat (fileno (sf),&sbuf)) {
 208.639 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
 208.640 +    mm_log (tmp,ERROR);
 208.641 +    fclose (sf);		/* punt scratch file */
 208.642 +    return NIL;			/* give up */
 208.643 +  }
 208.644 +  i = sbuf.st_size;		/* size of scratch file */
 208.645 +
 208.646 +  mm_critical (stream);		/* go critical */
 208.647 +				/* open the destination */
 208.648 +  if (!mailboxfile (tmp,mailbox) || 
 208.649 +      ((fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
 208.650 +		   S_IREAD|S_IWRITE)) < 0) ||
 208.651 +      !(df = fdopen (fd,"ab"))) {
 208.652 +    mm_nocritical (stream);	/* done with critical */
 208.653 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
 208.654 +    mm_log (tmp,ERROR);
 208.655 +    return NIL;
 208.656 +  }
 208.657 +  fstat (fd,&sbuf);		/* get current file size */
 208.658 +  while (i)			/* until written all bytes */
 208.659 +    if ((j = fread (buf,1,min ((long) BUFLEN,i),sf)) &&
 208.660 +	(fwrite (buf,1,j,df) == j)) i -= j;
 208.661 +  fclose (sf);			/* done with scratch file */
 208.662 +				/* make sure append wins */
 208.663 +  if (i || (fflush (df) == EOF)) {
 208.664 +    chsize (fd,sbuf.st_size);	/* revert file */
 208.665 +    close (fd);			/* make sure fclose() doesn't corrupt us */
 208.666 +    sprintf (buf,"Message append failed: %s",strerror (errno));
 208.667 +    mm_log (buf,ERROR);
 208.668 +    ret = NIL;			/* return error */
 208.669 +  }
 208.670 +  fclose (df);
 208.671 +  mm_nocritical (stream);	/* release critical */
 208.672 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
 208.673 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
 208.674 +	    WARN);
 208.675 +  return ret;
 208.676 +}
 208.677 +
 208.678 +/* Write single message to append scratch file
 208.679 + * Accepts: MAIL stream
 208.680 + *	    scratch file
 208.681 + *	    flags
 208.682 + *	    message stringstruct
 208.683 + * Returns: NIL if write error, else T
 208.684 + */
 208.685 +
 208.686 +int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 208.687 +		     STRING *msg)
 208.688 +{
 208.689 +  int c;
 208.690 +  unsigned long i,uf;
 208.691 +  char tmp[MAILTMPLEN];
 208.692 +  long f = mail_parse_flags (stream,flags,&uf);
 208.693 +				/* build initial header */
 208.694 +  if ((fprintf (sf,"From %s@%s %sStatus: ",
 208.695 +		myusername (),mylocalhost (),date) < 0) ||
 208.696 +      (f&fSEEN && (putc ('R',sf) == EOF)) ||
 208.697 +      (fputs ("\nX-Status: ",sf) == EOF) ||
 208.698 +      (f&fDELETED && (putc ('D',sf) == EOF)) ||
 208.699 +      (f&fFLAGGED && (putc ('F',sf) == EOF)) ||
 208.700 +      (f&fANSWERED && (putc ('A',sf) == EOF)) ||
 208.701 +      (f&fDRAFT && (putc ('T',sf) == EOF)) ||
 208.702 +      (fputs ("\nX-Keywords:",sf) == EOF)) return NIL;
 208.703 +  while (uf)			/* write user flags */
 208.704 +    if (fprintf (sf," %s",stream->user_flags[find_rightmost_bit (&uf)]) < 0)
 208.705 +      return NIL;
 208.706 +				/* tie off flags */
 208.707 +  if (putc ('\n',sf) == EOF) return NIL;
 208.708 +  while (SIZE (msg)) {		/* copy text to scratch file */
 208.709 +				/* possible delimiter if line starts with F */
 208.710 +    if ((c = 0xff & SNX (msg)) == 'F') {
 208.711 +				/* copy line to buffer */
 208.712 +      for (i = 1,tmp[0] = c; SIZE (msg) && (c != '\n') && (i < MAILTMPLEN);)
 208.713 +	if (((c = 0xff & SNX (msg)) != '\r') || !(SIZE (msg)) ||
 208.714 +	    (CHR (msg) != '\n')) tmp[i++] = c;
 208.715 +      if ((i > 4) && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') &&
 208.716 +	  (tmp[4] == ' ')) {	/* possible "From " line? */
 208.717 +				/* yes, see if need to write a widget */
 208.718 +	if (((c != '\n') || bezerk_valid_line (tmp,NIL,NIL)) &&
 208.719 +	    (putc ('>',sf) == EOF)) return NIL;
 208.720 +      }
 208.721 +				/* write buffered text */
 208.722 +      if (fwrite (tmp,1,i,sf) != i) return NIL;
 208.723 +      if (c == '\n') continue;	/* all done if got a complete line */
 208.724 +    }
 208.725 +				/* copy line, toss out CR from CRLF */
 208.726 +    do if (((c == '\r') && SIZE (msg) && ((c = 0xff & SNX (msg)) != '\n') &&
 208.727 +	    (putc ('\r',sf) == EOF)) || (putc (c,sf) == EOF)) return NIL;
 208.728 +    while ((c != '\n') && SIZE (msg) && ((c = 0xff & SNX (msg)) ? c : T));
 208.729 +  }
 208.730 +				/* write trailing newline and return */
 208.731 +  return (putc ('\n',sf) == EOF) ? NIL : T;
 208.732 +}
 208.733 +
 208.734 +
 208.735 +/* Return bad file name error message
 208.736 + * Accepts: temporary buffer
 208.737 + *	    file name
 208.738 + * Returns: long NIL always
 208.739 + */
 208.740 +
 208.741 +long bezerk_badname (char *tmp,char *s)
 208.742 +{
 208.743 +  sprintf (tmp,"Invalid mailbox name: %s",s);
 208.744 +  mm_log (tmp,ERROR);
 208.745 +  return (long) NIL;
 208.746 +}
 208.747 +
 208.748 +/* Parse mailbox
 208.749 + * Accepts: MAIL stream
 208.750 + * Returns: T if parse OK
 208.751 + *	    NIL if failure, stream aborted
 208.752 + */
 208.753 +
 208.754 +long bezerk_parse (MAILSTREAM *stream)
 208.755 +{
 208.756 +  struct stat sbuf;
 208.757 +  MESSAGECACHE *elt;
 208.758 +  char *s,*t,tmp[MAILTMPLEN + 1],*db,datemsg[100];
 208.759 +  long i;
 208.760 +  int j,ti,zn;
 208.761 +  long curpos = LOCAL->filesize;
 208.762 +  long nmsgs = stream->nmsgs;
 208.763 +  long recent = stream->recent;
 208.764 +  short silent = stream->silent;
 208.765 +  fstat (LOCAL->fd,&sbuf);	/* get status */
 208.766 +  if (sbuf.st_size < curpos) {	/* sanity check */
 208.767 +    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
 208.768 +    mm_log (tmp,ERROR);
 208.769 +    bezerk_close (stream,NIL);
 208.770 +    return NIL;
 208.771 +  }
 208.772 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
 208.773 +  db = datemsg + strlen (strcpy (datemsg,"Unparsable date: "));
 208.774 +				/* while there is data to read */
 208.775 +  while (i = sbuf.st_size - curpos){
 208.776 +				/* get to that position in the file */
 208.777 +    lseek (LOCAL->fd,curpos,SEEK_SET);
 208.778 +				/* read first buffer's worth */
 208.779 +    read (LOCAL->fd,tmp,j = (int) min (i,(long) MAILTMPLEN));
 208.780 +    tmp[j] = '\0';		/* tie off buffer */
 208.781 +    if (!(ti = bezerk_valid_line (tmp,&t,&zn))) {
 208.782 +      mm_log ("Mailbox format invalidated (consult an expert), aborted",ERROR);
 208.783 +      bezerk_close (stream,NIL);
 208.784 +      return NIL;
 208.785 +    }
 208.786 +
 208.787 +				/* swell the cache */
 208.788 +    mail_exists (stream,++nmsgs);
 208.789 +				/* instantiate an elt for this message */
 208.790 +    (elt = mail_elt (stream,nmsgs))->valid = T;
 208.791 +    elt->private.uid = ++stream->uid_last;
 208.792 +				/* note file offset of header */
 208.793 +    elt->private.special.offset = curpos;
 208.794 +				/* note offset of message */
 208.795 +    elt->private.msg.full.offset =
 208.796 +      (s = ((*t == '\015') ? (t + 2) : (t + 1))) - tmp;
 208.797 +				/* generate plausable IMAPish date string */
 208.798 +    db[2] = db[6] = db[20] = '-'; db[11] = ' '; db[14] = db[17] = ':';
 208.799 +				/* dd */
 208.800 +    db[0] = t[ti - 2]; db[1] = t[ti - 1];
 208.801 +				/* mmm */
 208.802 +    db[3] = t[ti - 6]; db[4] = t[ti - 5]; db[5] = t[ti - 4];
 208.803 +				/* hh */
 208.804 +    db[12] = t[ti + 1]; db[13] = t[ti + 2];
 208.805 +				/* mm */
 208.806 +    db[15] = t[ti + 4]; db[16] = t[ti + 5];
 208.807 +    if (t[ti += 6] == ':') {	/* ss if present */
 208.808 +      db[18] = t[++ti]; db[19] = t[++ti];
 208.809 +      ti++;			/* move to space */
 208.810 +    }
 208.811 +    else db[18] = db[19] = '0';	/* assume 0 seconds */
 208.812 +				/* yy -- advance over timezone if necessary */
 208.813 +    if (++zn == ++ti) ti += (((t[zn] == '+') || (t[zn] == '-')) ? 6 : 4);
 208.814 +    db[7] = t[ti]; db[8] = t[ti + 1]; db[9] = t[ti + 2]; db[10] = t[ti + 3];
 208.815 +    t = zn ? (t + zn) : "LCL";	/* zzz */
 208.816 +    db[21] = *t++; db[22] = *t++; db[23] = *t++;
 208.817 +    if ((db[21] != '+') && (db[21] != '-')) db[24] = '\0';
 208.818 +    else {			/* numeric time zone */
 208.819 +      db[20] = ' '; db[24] = *t++; db[25] = *t++; db[26] = '\0';
 208.820 +    }
 208.821 +				/* set internal date */
 208.822 +    if (!mail_parse_date (elt,db)) mm_log (datemsg,WARN);
 208.823 +
 208.824 +    curpos += s - tmp;		/* advance position after header */
 208.825 +    t = strchr (s,'\012');	/* start of next line */
 208.826 +				/* find start of next message */
 208.827 +    while (!(bezerk_valid_line (s,NIL,NIL))) {
 208.828 +      if (t) {			/* have next line? */
 208.829 +	t++;			/* advance to new line */
 208.830 +	curpos += t - s;	/* update position and size */
 208.831 +	elt->rfc822_size += ((t - s) + ((t[-2] == '\015') ? 0 : 1));
 208.832 +	s = t;			/* move to next line */
 208.833 +	t = strchr (s,'\012');
 208.834 +      }
 208.835 +      else {			/* try next buffer */
 208.836 +	j = strlen (s);		/* length of unread data in buffer */
 208.837 +	if ((i = sbuf.st_size - curpos) && (i != j)) {
 208.838 +				/* get to that position in the file */
 208.839 +	  lseek (LOCAL->fd,curpos,SEEK_SET);
 208.840 +				/* read another buffer's worth */
 208.841 +	  read (LOCAL->fd,s = tmp,j = (int) min (i,(long) MAILTMPLEN));
 208.842 +	  tmp[j] = '\0';	/* tie off buffer */
 208.843 +	  if (!(t = strchr (s,'\012'))) fatal ("Line too long in mailbox");
 208.844 +	}
 208.845 +	else {
 208.846 +	  curpos += j;		/* last bit of data */
 208.847 +	  elt->rfc822_size += j;
 208.848 +	  break;
 208.849 +	}
 208.850 +      }
 208.851 +    }
 208.852 +  }
 208.853 +				/* update parsed file size */
 208.854 +  LOCAL->filesize = sbuf.st_size;
 208.855 +  stream->silent = silent;	/* can pass up events now */
 208.856 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
 208.857 +  mail_recent (stream,recent);	/* and of change in recent messages */
 208.858 +  return T;			/* return the winnage */
 208.859 +}
 208.860 +
 208.861 +/* Berkeley locate header for a message
 208.862 + * Accepts: MAIL stream
 208.863 + *	    message number
 208.864 + *	    pointer to returned header size
 208.865 + * Returns: position of header in file
 208.866 + */
 208.867 +
 208.868 +unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 208.869 +			     unsigned long *size)
 208.870 +{
 208.871 +  long siz;
 208.872 +  size_t i = 0;
 208.873 +  char c = '\0';
 208.874 +  char *s;
 208.875 +  char tmp[MAILTMPLEN];
 208.876 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
 208.877 +  long pos = elt->private.special.offset + elt->private.msg.full.offset;
 208.878 +				/* is size known? */
 208.879 +  if (!(*size = elt->private.msg.header.text.size)) {
 208.880 +				/* get to header position */
 208.881 +    lseek (LOCAL->fd,pos,SEEK_SET);
 208.882 +				/* search message for CRLF CRLF */
 208.883 +    for (siz = 1; siz <= elt->rfc822_size; siz++) {
 208.884 +      if (!i &&			/* buffer empty? */
 208.885 +	  (read (LOCAL->fd,s = tmp,
 208.886 +		 i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0))
 208.887 +	return pos;
 208.888 +      else i--;
 208.889 +				/* two newline sequence? */
 208.890 +      if ((c == '\012') && (*s == '\012')) {
 208.891 +				/* yes, note for later */
 208.892 +	elt->private.msg.header.text.size = (*size = siz);
 208.893 +	return pos;		/* return to caller */
 208.894 +      }
 208.895 +      else if ((c == '\012') && (*s == '\015')) {
 208.896 +				/* yes, note for later */
 208.897 +	elt->private.msg.header.text.size = (*size = siz + 1);
 208.898 +	return pos;		/* return to caller */
 208.899 +      }
 208.900 +      else c = *s++;		/* next character */
 208.901 +    }
 208.902 +  }
 208.903 +  return pos;			/* have position */
 208.904 +}
   209.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   209.2 +++ b/src/osdep/dos/drivers.bat	Mon Sep 14 15:17:45 2009 +0900
   209.3 @@ -0,0 +1,33 @@
   209.4 +@ECHO OFF
   209.5 +REM ========================================================================
   209.6 +REM Copyright 1988-2006 University of Washington
   209.7 +REM
   209.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   209.9 +REM you may not use this file except in compliance with the License.
  209.10 +REM You may obtain a copy of the License at
  209.11 +REM
  209.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  209.13 +REM
  209.14 +REM 
  209.15 +REM ========================================================================
  209.16 +
  209.17 +REM Program:	Driver Linkage Generator for DOS/NT
  209.18 +REM
  209.19 +REM Author:	Mark Crispin
  209.20 +REM		Networks and Distributed Computing
  209.21 +REM		Computing & Communications
  209.22 +REM		University of Washington
  209.23 +REM		Administration Building, AG-44
  209.24 +REM		Seattle, WA  98195
  209.25 +REM		Internet: MRC@CAC.Washington.EDU
  209.26 +REM
  209.27 +REM Date:	11 October 1989
  209.28 +REM Last Edited:30 August 2006
  209.29 +
  209.30 +REM Erase old driver linkage
  209.31 +IF EXIST LINKAGE.* DEL LINKAGE.*
  209.32 +
  209.33 +REM Now define the new list
  209.34 +FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
  209.35 +
  209.36 +EXIT 0
   210.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   210.2 +++ b/src/osdep/dos/drivraux.bat	Mon Sep 14 15:17:45 2009 +0900
   210.3 @@ -0,0 +1,28 @@
   210.4 +@ECHO OFF
   210.5 +REM ========================================================================
   210.6 +REM Copyright 1988-2006 University of Washington
   210.7 +REM
   210.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   210.9 +REM you may not use this file except in compliance with the License.
  210.10 +REM You may obtain a copy of the License at
  210.11 +REM
  210.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  210.13 +REM
  210.14 +REM 
  210.15 +REM ========================================================================
  210.16 +
  210.17 +REM Program:	Driver Linkage Generator auxillary for DOS
  210.18 +REM
  210.19 +REM Author:	Mark Crispin
  210.20 +REM		Networks and Distributed Computing
  210.21 +REM		Computing & Communications
  210.22 +REM		University of Washington
  210.23 +REM		Administration Building, AG-44
  210.24 +REM		Seattle, WA  98195
  210.25 +REM		Internet: MRC@CAC.Washington.EDU
  210.26 +REM
  210.27 +REM Date:	11 October 1989
  210.28 +REM Last Edited:30 August 2006
  210.29 +
  210.30 +ECHO extern DRIVER %1driver; >> LINKAGE.H
  210.31 +ECHO   mail_link (&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
   211.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   211.2 +++ b/src/osdep/dos/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   211.3 @@ -0,0 +1,43 @@
   211.4 +/* ========================================================================
   211.5 + * Copyright 1988-2006 University of Washington
   211.6 + *
   211.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   211.8 + * you may not use this file except in compliance with the License.
   211.9 + * You may obtain a copy of the License at
  211.10 + *
  211.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  211.12 + *
  211.13 + * 
  211.14 + * ========================================================================
  211.15 + */
  211.16 +
  211.17 +/*
  211.18 + * Program:	Dummy routines
  211.19 + *
  211.20 + * Author:	Mark Crispin
  211.21 + *		Networks and Distributed Computing
  211.22 + *		Computing & Communications
  211.23 + *		University of Washington
  211.24 + *		Administration Building, AG-44
  211.25 + *		Seattle, WA  98195
  211.26 + *		Internet: MRC@CAC.Washington.EDU
  211.27 + *
  211.28 + * Date:	9 May 1991
  211.29 + * Last Edited:	30 August 2006
  211.30 + */
  211.31 +
  211.32 +/* Exported function prototypes */
  211.33 +
  211.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  211.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  211.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  211.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  211.38 +		    unsigned long csiz,unsigned long fsiz);
  211.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  211.40 +			  unsigned long fsiz);
  211.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  211.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  211.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  211.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  211.45 +char *dummy_file (char *dst,char *name);
  211.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   212.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   212.2 +++ b/src/osdep/dos/dummydos.c	Mon Sep 14 15:17:45 2009 +0900
   212.3 @@ -0,0 +1,689 @@
   212.4 +/* ========================================================================
   212.5 + * Copyright 1988-2006 University of Washington
   212.6 + *
   212.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   212.8 + * you may not use this file except in compliance with the License.
   212.9 + * You may obtain a copy of the License at
  212.10 + *
  212.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  212.12 + *
  212.13 + * 
  212.14 + * ========================================================================
  212.15 + */
  212.16 +
  212.17 +/*
  212.18 + * Program:	Dummy routines for DOS
  212.19 + *
  212.20 + * Author:	Mark Crispin
  212.21 + *		Networks and Distributed Computing
  212.22 + *		Computing & Communications
  212.23 + *		University of Washington
  212.24 + *		Administration Building, AG-44
  212.25 + *		Seattle, WA  98195
  212.26 + *		Internet: MRC@CAC.Washington.EDU
  212.27 + *
  212.28 + * Date:	24 May 1993
  212.29 + * Last Edited:	30 August 2006
  212.30 + */
  212.31 +
  212.32 +
  212.33 +#include <ctype.h>
  212.34 +#include <errno.h>
  212.35 +#include <fcntl.h>
  212.36 +#include "mail.h"
  212.37 +#include "osdep.h"
  212.38 +#include <sys\stat.h>
  212.39 +#include <dos.h>
  212.40 +#include "dummy.h"
  212.41 +#include "misc.h"
  212.42 +
  212.43 +/* Function prototypes */
  212.44 +
  212.45 +DRIVER *dummy_valid (char *name);
  212.46 +void *dummy_parameters (long function,void *value);
  212.47 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
  212.48 +		      long level);
  212.49 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
  212.50 +		   long attributes,char *contents);
  212.51 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
  212.52 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  212.53 +void dummy_close (MAILSTREAM *stream,long options);
  212.54 +long dummy_ping (MAILSTREAM *stream);
  212.55 +void dummy_check (MAILSTREAM *stream);
  212.56 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  212.57 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  212.58 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  212.59 +long dummy_badname (char *tmp,char *s);
  212.60 +
  212.61 +/* Dummy routines */
  212.62 +
  212.63 +
  212.64 +/* Driver dispatch used by MAIL */
  212.65 +
  212.66 +DRIVER dummydriver = {
  212.67 +  "dummy",			/* driver name */
  212.68 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  212.69 +  (DRIVER *) NIL,		/* next driver */
  212.70 +  dummy_valid,			/* mailbox is valid for us */
  212.71 +  dummy_parameters,		/* manipulate parameters */
  212.72 +  dummy_scan,			/* scan mailboxes */
  212.73 +  dummy_list,			/* list mailboxes */
  212.74 +  dummy_lsub,			/* list subscribed mailboxes */
  212.75 +  dummy_subscribe,		/* subscribe to mailbox */
  212.76 +  NIL,				/* unsubscribe from mailbox */
  212.77 +  dummy_create,			/* create mailbox */
  212.78 +  dummy_delete,			/* delete mailbox */
  212.79 +  dummy_rename,			/* rename mailbox */
  212.80 +  mail_status_default,		/* status of mailbox */
  212.81 +  dummy_open,			/* open mailbox */
  212.82 +  dummy_close,			/* close mailbox */
  212.83 +  NIL,				/* fetch message "fast" attributes */
  212.84 +  NIL,				/* fetch message flags */
  212.85 +  NIL,				/* fetch overview */
  212.86 +  NIL,				/* fetch message structure */
  212.87 +  NIL,				/* fetch header */
  212.88 +  NIL,				/* fetch text */
  212.89 +  NIL,				/* fetch message data */
  212.90 +  NIL,				/* unique identifier */
  212.91 +  NIL,				/* message number from UID */
  212.92 +  NIL,				/* modify flags */
  212.93 +  NIL,				/* per-message modify flags */
  212.94 +  NIL,				/* search for message based on criteria */
  212.95 +  NIL,				/* sort messages */
  212.96 +  NIL,				/* thread messages */
  212.97 +  dummy_ping,			/* ping mailbox to see if still alive */
  212.98 +  dummy_check,			/* check for new messages */
  212.99 +  dummy_expunge,		/* expunge deleted messages */
 212.100 +  dummy_copy,			/* copy messages to another mailbox */
 212.101 +  dummy_append,			/* append string message to mailbox */
 212.102 +  NIL				/* garbage collect stream */
 212.103 +};
 212.104 +
 212.105 +
 212.106 +				/* prototype stream */
 212.107 +MAILSTREAM dummyproto = {&dummydriver};
 212.108 +
 212.109 +				/* driver parameters */
 212.110 +static char *file_extension = NIL;
 212.111 +
 212.112 +/* Dummy validate mailbox
 212.113 + * Accepts: mailbox name
 212.114 + * Returns: our driver if name is valid, NIL otherwise
 212.115 + */
 212.116 +
 212.117 +DRIVER *dummy_valid (char *name)
 212.118 +{
 212.119 +  char *s,tmp[MAILTMPLEN];
 212.120 +  struct stat sbuf;
 212.121 +				/* must be valid local mailbox */
 212.122 +  return (name && *name && (*name != '{') &&
 212.123 +	  (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ?
 212.124 +	    &dummydriver : NIL;
 212.125 +}
 212.126 +
 212.127 +
 212.128 +/* Dummy manipulate driver parameters
 212.129 + * Accepts: function code
 212.130 + *	    function-dependent value
 212.131 + * Returns: function-dependent return value
 212.132 + */
 212.133 +
 212.134 +void *dummy_parameters (long function,void *value)
 212.135 +{
 212.136 +  void *ret = NIL;
 212.137 +  switch ((int) function) {
 212.138 +  case SET_EXTENSION:
 212.139 +    if (file_extension) fs_give ((void **) &file_extension);
 212.140 +    if (*(char *) value) file_extension = cpystr ((char *) value);
 212.141 +  case GET_EXTENSION:
 212.142 +    ret = (void *) file_extension;
 212.143 +  }
 212.144 +  return ret;
 212.145 +}
 212.146 +
 212.147 +/* Dummy scan mailboxes
 212.148 + * Accepts: mail stream
 212.149 + *	    reference
 212.150 + *	    pattern to search
 212.151 + *	    string to scan
 212.152 + */
 212.153 +
 212.154 +#define LISTTMPLEN 128
 212.155 +
 212.156 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 212.157 +{
 212.158 +  char *s,test[LISTTMPLEN],file[LISTTMPLEN];
 212.159 +  long i = 0;
 212.160 +  if (!pat || !*pat) {		/* empty pattern? */
 212.161 +    if (dummy_canonicalize (test,ref,"*")) {
 212.162 +				/* tie off name at root */
 212.163 +      if (s = strchr (test,'\\')) *++s = '\0';
 212.164 +      else test[0] = '\0';
 212.165 +      dummy_listed (stream,'\\',test,LATT_NOINFERIORS,NIL);
 212.166 +    }
 212.167 +  }
 212.168 +				/* get canonical form of name */
 212.169 +  else if (dummy_canonicalize (test,ref,pat)) {
 212.170 +				/* found any wildcards? */
 212.171 +    if (s = strpbrk (test,"%*")) {
 212.172 +				/* yes, copy name up to that point */
 212.173 +      strncpy (file,test,(size_t) (i = s - test));
 212.174 +      file[i] = '\0';		/* tie off */
 212.175 +    }
 212.176 +    else strcpy (file,test);	/* use just that name then */
 212.177 +				/* find directory name */
 212.178 +    if (s = strrchr (file,'\\')) {
 212.179 +      *++s = '\0';		/* found, tie off at that point */
 212.180 +      s = file;
 212.181 +    }
 212.182 +				/* silly case */
 212.183 +    else if (file[0] == '#') s = file;
 212.184 +				/* do the work */
 212.185 +    dummy_list_work (stream,s,test,contents,0);
 212.186 +    if (pmatch ("INBOX",test))	/* always an INBOX */
 212.187 +      dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
 212.188 +  }
 212.189 +}
 212.190 +
 212.191 +/* Dummy list mailboxes
 212.192 + * Accepts: mail stream
 212.193 + *	    reference
 212.194 + *	    pattern to search
 212.195 + */
 212.196 +
 212.197 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 212.198 +{
 212.199 +  dummy_scan (stream,ref,pat,NIL);
 212.200 +}
 212.201 +
 212.202 +
 212.203 +/* Dummy list subscribed mailboxes
 212.204 + * Accepts: mail stream
 212.205 + *	    pattern to search
 212.206 + */
 212.207 +
 212.208 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 212.209 +{
 212.210 +  void *sdb = NIL;
 212.211 +  char *s,*t,test[MAILTMPLEN];
 212.212 +  int showuppers = pat[strlen (pat) - 1] == '%';
 212.213 +				/* get canonical form of name */
 212.214 +  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
 212.215 +    if (*s != '{') {
 212.216 +      if (pmatch_full (s,test,'\\')) {
 212.217 +	if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
 212.218 +	else mm_lsub (stream,'\\',s,NIL);
 212.219 +      }
 212.220 +      else while (showuppers && (t = strrchr (s,'\\'))) {
 212.221 +	*t = '\0';		/* tie off the name */
 212.222 +	if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
 212.223 +      }
 212.224 +    }
 212.225 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 212.226 +}
 212.227 +
 212.228 +
 212.229 +/* Dummy subscribe to mailbox
 212.230 + * Accepts: mail stream
 212.231 + *	    mailbox to add to subscription list
 212.232 + * Returns: T on success, NIL on failure
 212.233 + */
 212.234 +
 212.235 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
 212.236 +{
 212.237 +  char *s,tmp[MAILTMPLEN];
 212.238 +  struct stat sbuf;
 212.239 +				/* must be valid local mailbox */
 212.240 +  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
 212.241 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
 212.242 +  sprintf (tmp,"Can't subscribe %s: not a mailbox",mailbox);
 212.243 +  mm_log (tmp,ERROR);
 212.244 +  return NIL;
 212.245 +}
 212.246 +
 212.247 +/* Dummy list mailboxes worker routine
 212.248 + * Accepts: mail stream
 212.249 + *	    directory name to search
 212.250 + *	    search pattern
 212.251 + *	    string to scan
 212.252 + *	    search level
 212.253 + */
 212.254 +
 212.255 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
 212.256 +		      long level)
 212.257 +{
 212.258 +  struct find_t f;
 212.259 +  struct stat sbuf;
 212.260 +  char *s,tmp[LISTTMPLEN],tmpx[LISTTMPLEN];
 212.261 +  char *base = (dir && (dir[0] == '\\')) ? NIL : myhomedir ();
 212.262 +				/* build name */
 212.263 +  if (base) sprintf (tmpx,"%s\\",base);
 212.264 +  else tmpx[0] = '\0';
 212.265 +  if (dir) strcat (tmpx,dir);
 212.266 +				/* punt if bogus name */
 212.267 +  if (!mailboxfile (tmp,tmpx)) return;
 212.268 +				/* make directory wildcard */
 212.269 +  strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*." : "\\*.");
 212.270 +  strcat (tmp,file_extension ? file_extension : "*");
 212.271 +				/* do nothing if can't open directory */
 212.272 +  if (!_dos_findfirst (tmp,_A_NORMAL|_A_SUBDIR,&f)) {
 212.273 +				/* list it if at top-level */
 212.274 +    if (!level && dir && pmatch_full (dir,pat,'\\'))
 212.275 +      dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
 212.276 +				/* scan directory */
 212.277 +    if (tmpx[strlen (tmpx) - 1] == '\\') do if (*f.name != '.') {
 212.278 +      if (base) sprintf (tmpx,"%s\\",base);
 212.279 +      else tmpx[0] = '\0';
 212.280 +      if (dir) sprintf (tmpx + strlen (tmpx),"%s%s",dir,f.name);
 212.281 +      else strcat (tmpx,f.name);
 212.282 +      if (mailboxfile (tmp,tmpx) && !stat (tmp,&sbuf)) {
 212.283 +				/* suppress extension */
 212.284 +	if (file_extension && (s = strchr (f.name,'.'))) *s = '\0';
 212.285 +				/* now make name we'd return */
 212.286 +	if (dir) sprintf (tmp,"%s%s",dir,f.name);
 212.287 +	else strcpy (tmp,f.name);
 212.288 +				/* only interested in file type */
 212.289 +	switch (sbuf.st_mode & S_IFMT) {
 212.290 +	case S_IFDIR:		/* directory? */
 212.291 +	  if (pmatch_full (tmp,pat,'\\')) {
 212.292 +	    dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents);
 212.293 +	    strcat (tmp,"\\");	/* set up for dmatch call */
 212.294 +	  }
 212.295 +				/* try again with trailing / */
 212.296 +	  else if (pmatch_full (strcat (tmp,"\\"),pat,'\\'))
 212.297 +	    dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents);
 212.298 +	  if (dmatch (tmp,pat,'\\') &&
 212.299 +	      (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 212.300 +	    dummy_list_work (stream,tmp,pat,contents,level+1);
 212.301 +	  break;
 212.302 +	case S_IFREG:		/* ordinary name */
 212.303 +	  if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
 212.304 +	    dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
 212.305 +	  break;
 212.306 +	}
 212.307 +      }
 212.308 +    }
 212.309 +    while (!_dos_findnext (&f));
 212.310 +  }
 212.311 +}
 212.312 +
 212.313 +/* Mailbox found
 212.314 + * Accepts: hierarchy delimiter
 212.315 + *	    mailbox name
 212.316 + *	    attributes
 212.317 + *	    contents to search before calling mm_list()
 212.318 + * Returns: T, always
 212.319 + */
 212.320 +
 212.321 +#define BUFSIZE MAILTMPLEN
 212.322 +
 212.323 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
 212.324 +		   long attributes,char *contents)
 212.325 +{
 212.326 +  struct stat sbuf;
 212.327 +  int fd;
 212.328 +  size_t csiz,ssiz,bsiz;
 212.329 +  char *buf,tmp[MAILTMPLEN];
 212.330 +  if (contents) {		/* want to search contents? */
 212.331 +				/* forget it if can't select or open */
 212.332 +    if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
 212.333 +	!mailboxfile (tmp,name) || stat (tmp,&sbuf) || (csiz > sbuf.st_size) ||
 212.334 +	((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T;
 212.335 +				/* get buffer including slop */    
 212.336 +    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
 212.337 +    memset (buf,'\0',ssiz);	/* no slop area the first time */
 212.338 +    while (sbuf.st_size) {	/* until end of file */
 212.339 +      read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
 212.340 +      if (search ((unsigned char *) buf,bsiz+ssiz,
 212.341 +		  (unsigned char *) contents,csiz)) break;
 212.342 +      memcpy (buf,buf+BUFSIZE,ssiz);
 212.343 +      sbuf.st_size -= bsiz;	/* note that we read that much */
 212.344 +    }
 212.345 +    fs_give ((void **) &buf);	/* flush buffer */
 212.346 +    close (fd);			/* finished with file */
 212.347 +    if (!sbuf.st_size) return T;/* not found */
 212.348 +  }
 212.349 +				/* notify main program */
 212.350 +  mm_list (stream,delimiter,name,attributes);
 212.351 +  return T;
 212.352 +}
 212.353 +
 212.354 +/* Dummy create mailbox
 212.355 + * Accepts: mail stream
 212.356 + *	    mailbox name to create
 212.357 + * Returns: T on success, NIL on failure
 212.358 + */
 212.359 +
 212.360 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 212.361 +{
 212.362 +  char tmp[MAILTMPLEN];
 212.363 +  return (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox)) ?
 212.364 +    dummy_create_path (stream,tmp,NIL) : dummy_badname (tmp,mailbox);
 212.365 +}
 212.366 +
 212.367 +
 212.368 +/* Dummy create path
 212.369 + * Accepts: mail stream
 212.370 + *	    path name to create
 212.371 + *	    directory mode
 212.372 + * Returns: T on success, NIL on failure
 212.373 + */
 212.374 +
 212.375 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
 212.376 +{
 212.377 +  struct stat sbuf;
 212.378 +  char c,*s,tmp[MAILTMPLEN];
 212.379 +  int fd;
 212.380 +  long ret = NIL;
 212.381 +  char *t = strrchr (path,'\\');
 212.382 +  char *pt = (path[1] == ':') ? path + 2 : path;
 212.383 +  int wantdir = t && !t[1];
 212.384 +  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
 212.385 +				/* found superior to this name? */
 212.386 +  if ((s = strrchr (pt,'\\')) && (s != pt)) {
 212.387 +    strncpy (tmp,path,(size_t) (s - path));
 212.388 +    tmp[s - path] = '\0';	/* make directory name for stat */
 212.389 +    c = *++s;			/* tie off in case need to recurse */
 212.390 +    *s = '\0';
 212.391 +				/* name doesn't exist, create it */
 212.392 +    if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 212.393 +	!dummy_create_path (stream,path,dirmode)) return NIL;
 212.394 +    *s = c;			/* restore full name */
 212.395 +  }
 212.396 +  if (wantdir) {		/* want to create directory? */
 212.397 +    ret = !mkdir (path);
 212.398 +    *t = '\\';			/* restore directory delimiter */
 212.399 +  }
 212.400 +				/* create file */
 212.401 +  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
 212.402 +    ret = !close (fd);		/* close file */
 212.403 +  if (!ret) {			/* error? */
 212.404 +    sprintf (tmp,"Can't create mailbox node %s: %s",path,strerror (errno));
 212.405 +    mm_log (tmp,ERROR);
 212.406 +  }
 212.407 +  return ret;			/* return status */
 212.408 +}
 212.409 +
 212.410 +/* Dummy delete mailbox
 212.411 + * Accepts: mail stream
 212.412 + *	    mailbox name to delete
 212.413 + * Returns: T on success, NIL on failure
 212.414 + */
 212.415 +
 212.416 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 212.417 +{
 212.418 +  struct stat sbuf;
 212.419 +  char *s,tmp[MAILTMPLEN];
 212.420 +  if (!mailboxfile (tmp,mailbox)) return dummy_badname (tmp,mailbox);
 212.421 +				/* no trailing \ */
 212.422 +  if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
 212.423 +  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
 212.424 +      rmdir (tmp) : unlink (tmp)) {
 212.425 +    sprintf (tmp,"Can't delete mailbox %s: %s",mailbox,strerror (errno));
 212.426 +    mm_log (tmp,ERROR);
 212.427 +    return NIL;
 212.428 +  }
 212.429 +  return T;			/* return success */
 212.430 +}
 212.431 +
 212.432 +
 212.433 +/* Mail rename mailbox
 212.434 + * Accepts: mail stream
 212.435 + *	    old mailbox name
 212.436 + *	    new mailbox name
 212.437 + * Returns: T on success, NIL on failure
 212.438 + */
 212.439 +
 212.440 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 212.441 +{
 212.442 +  struct stat sbuf;
 212.443 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN];
 212.444 +				/* make file name */
 212.445 +  if (!mailboxfile (file,old)) return dummy_badname (tmp,old);
 212.446 +				/* no trailing \ allowed */
 212.447 +  if (!(s = mailboxfile (tmp,newname)) || ((s = strrchr (s,'\\')) && !s[1]))
 212.448 +    return dummy_badname (tmp,newname);
 212.449 +  if (s) {			/* found superior to destination name? */
 212.450 +    c = *++s;			/* remember first character of inferior */
 212.451 +    *s = '\0';			/* tie off to get just superior */
 212.452 +				/* name doesn't exist, create it */
 212.453 +    if ((stat (file,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 212.454 +	!dummy_create (stream,file)) return NIL;
 212.455 +    *s = c;			/* restore full name */
 212.456 +  }
 212.457 +  if (rename (file,tmp)) {
 212.458 +    sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,newname,
 212.459 +	     strerror (errno));
 212.460 +    mm_log (tmp,ERROR);
 212.461 +    return NIL;
 212.462 +  }
 212.463 +  return LONGT;			/* return success */
 212.464 +}
 212.465 +
 212.466 +/* Dummy open
 212.467 + * Accepts: stream to open
 212.468 + * Returns: stream on success, NIL on failure
 212.469 + */
 212.470 +
 212.471 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 212.472 +{
 212.473 +  char tmp[MAILTMPLEN];
 212.474 +  struct stat sbuf;
 212.475 +  int fd = -1;
 212.476 +				/* OP_PROTOTYPE call or silence */
 212.477 +  if (!stream || stream->silent) return NIL;
 212.478 +  if (!mailboxfile (tmp,stream->mailbox))
 212.479 +    sprintf (tmp,"Can't open this name: %.80s",stream->mailbox);
 212.480 +  else if (compare_cstring (stream->mailbox,"INBOX") &&
 212.481 +      ((fd = open (tmp,O_RDONLY,NIL)) < 0))
 212.482 +    sprintf (tmp,"%s: %s",strerror (errno),stream->mailbox);
 212.483 +  else {
 212.484 +    if (fd >= 0) {		/* if got a file */
 212.485 +      fstat (fd,&sbuf);		/* sniff at its size */
 212.486 +      close (fd);
 212.487 +      if (sbuf.st_size) sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
 212.488 +      else fd = -1;		/* a-OK */
 212.489 +    }
 212.490 +    if (fd < 0) {		/* no file, right? */
 212.491 +      if (!stream->silent) {	/* only if silence not requested */
 212.492 +				/* say there are 0 messages */
 212.493 +	mail_exists (stream,(long) 0);
 212.494 +	mail_recent (stream,(long) 0);
 212.495 +	stream->uid_validity = time (0);
 212.496 +      }
 212.497 +      stream->inbox = T;	/* note that it's an INBOX */
 212.498 +      return stream;		/* return success */
 212.499 +    }
 212.500 +  }
 212.501 +  mm_log (tmp,stream->silent ? WARN: ERROR);
 212.502 +  return NIL;			/* always fails */
 212.503 +}
 212.504 +
 212.505 +
 212.506 +/* Dummy close
 212.507 + * Accepts: MAIL stream
 212.508 + *	    options
 212.509 + */
 212.510 +
 212.511 +void dummy_close (MAILSTREAM *stream,long options)
 212.512 +{
 212.513 +				/* return silently */
 212.514 +}
 212.515 +
 212.516 +/* Dummy ping mailbox
 212.517 + * Accepts: MAIL stream
 212.518 + * Returns: T if stream alive, else NIL
 212.519 + * No-op for readonly files, since read/writer can expunge it from under us!
 212.520 + */
 212.521 +
 212.522 +long dummy_ping (MAILSTREAM *stream)
 212.523 +{
 212.524 +  MAILSTREAM *test;
 212.525 +				/* time to do another test? */
 212.526 +  if (time (0) >= ((time_t) (stream->gensym + 30))) {
 212.527 +				/* has mailbox format changed? */
 212.528 +    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
 212.529 +	(test->dtb != stream->dtb) &&
 212.530 +	(test = mail_open (NIL,stream->mailbox,NIL))) {
 212.531 +				/* preserve some resources */
 212.532 +      test->original_mailbox = stream->original_mailbox;
 212.533 +      stream->original_mailbox = NIL;
 212.534 +      test->sparep = stream->sparep;
 212.535 +      stream->sparep = NIL;
 212.536 +      test->sequence = stream->sequence;
 212.537 +      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
 212.538 +		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
 212.539 +			  sizeof (MAILSTREAM)));
 212.540 +				/* swap the streams */
 212.541 +      memcpy (stream,test,sizeof (MAILSTREAM));
 212.542 +      fs_give ((void **) &test);/* flush test now that copied */
 212.543 +				/* make sure application knows */
 212.544 +      mail_exists (stream,stream->recent = stream->nmsgs);
 212.545 +    }
 212.546 +				/* still hasn't changed */
 212.547 +    else stream->gensym = time (0);
 212.548 +  }
 212.549 +  return T;
 212.550 +}
 212.551 +
 212.552 +
 212.553 +/* Dummy check mailbox
 212.554 + * Accepts: MAIL stream
 212.555 + * No-op for readonly files, since read/writer can expunge it from under us!
 212.556 + */
 212.557 +
 212.558 +void dummy_check (MAILSTREAM *stream)
 212.559 +{
 212.560 +  dummy_ping (stream);		/* invoke ping */
 212.561 +}
 212.562 +
 212.563 +
 212.564 +/* Dummy expunge mailbox
 212.565 + * Accepts: MAIL stream
 212.566 + *	    sequence to expunge if non-NIL
 212.567 + *	    expunge options
 212.568 + * Returns: T, always
 212.569 + */
 212.570 +
 212.571 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 212.572 +{
 212.573 +  return LONGT;
 212.574 +}
 212.575 +
 212.576 +/* Dummy copy message(s)
 212.577 + * Accepts: MAIL stream
 212.578 + *	    sequence
 212.579 + *	    destination mailbox
 212.580 + *	    options
 212.581 + * Returns: T if copy successful, else NIL
 212.582 + */
 212.583 +
 212.584 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 212.585 +{
 212.586 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 212.587 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 212.588 +  return NIL;
 212.589 +}
 212.590 +
 212.591 +
 212.592 +/* Dummy append message string
 212.593 + * Accepts: mail stream
 212.594 + *	    destination mailbox
 212.595 + *	    append callback function
 212.596 + *	    data for callback
 212.597 + * Returns: T on success, NIL on failure
 212.598 + */
 212.599 +
 212.600 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 212.601 +{
 212.602 +  struct stat sbuf;
 212.603 +  int fd = -1;
 212.604 +  int e;
 212.605 +  char tmp[MAILTMPLEN];
 212.606 +  MAILSTREAM *ts = default_proto (T);
 212.607 +  if (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox) &&
 212.608 +      ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
 212.609 +    if ((e = errno) == ENOENT)	/* failed, was it no such file? */
 212.610 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
 212.611 +		 (long) NIL);
 212.612 +    sprintf (tmp,"%s: %s",strerror (e),mailbox);
 212.613 +    mm_log (tmp,ERROR);		/* pass up error */
 212.614 +    return NIL;			/* always fails */
 212.615 +  }
 212.616 +  if (fd >= 0) {		/* found file? */
 212.617 +    fstat (fd,&sbuf);		/* get its size */
 212.618 +    close (fd);			/* toss out the fd */
 212.619 +    if (sbuf.st_size) ts = NIL;	/* non-empty file? */
 212.620 +  }
 212.621 +  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
 212.622 +  sprintf (tmp,"Indeterminate mailbox format: %s",mailbox);
 212.623 +  mm_log (tmp,ERROR);
 212.624 +  return NIL;
 212.625 +}
 212.626 +
 212.627 +/* Return bad file name error message
 212.628 + * Accepts: temporary buffer
 212.629 + *	    file name
 212.630 + * Returns: long NIL always
 212.631 + */
 212.632 +
 212.633 +long dummy_badname (char *tmp,char *s)
 212.634 +{
 212.635 +  sprintf (tmp,"Invalid mailbox name: %s",s);
 212.636 +  mm_log (tmp,ERROR);
 212.637 +  return (long) NIL;
 212.638 +}
 212.639 +
 212.640 +
 212.641 +/* Dummy canonicalize name
 212.642 + * Accepts: buffer to write name
 212.643 + *	    reference
 212.644 + *	    pattern
 212.645 + * Returns: T if success, NIL if failure
 212.646 + */
 212.647 +
 212.648 +long dummy_canonicalize (char *tmp,char *ref,char *pat)
 212.649 +{
 212.650 +  unsigned long i;
 212.651 +  char *s,dev[4];
 212.652 +				/* initially no device */
 212.653 +  dev[0] = dev[1] = dev[2] = dev[3] = '\0';
 212.654 +  if (ref) switch (*ref) {	/* preliminary reference check */
 212.655 +  case '{':			/* remote names not allowed */
 212.656 +    return NIL;			/* disallowed */
 212.657 +  case '\0':			/* empty reference string */
 212.658 +    break;
 212.659 +  default:			/* all other names */
 212.660 +    if (ref[1] == ':') {	/* start with device name? */
 212.661 +      dev[0] = *ref++; dev[1] = *ref++;
 212.662 +    }
 212.663 +    break;
 212.664 +  }
 212.665 +  if (pat[1] == ':') {		/* device name in pattern? */
 212.666 +    dev[0] = *pat++; dev[1] = *pat++;
 212.667 +    ref = NIL;			/* ignore reference */
 212.668 +  }
 212.669 +  switch (*pat) {
 212.670 +  case '#':			/* namespace names */
 212.671 +    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
 212.672 +    else return NIL;		/* unknown namespace */
 212.673 +    break;
 212.674 +  case '{':			/* remote names not allowed */
 212.675 +    return NIL;
 212.676 +  case '\\':			/* rooted name */
 212.677 +    ref = NIL;			/* ignore reference */
 212.678 +    break;
 212.679 +  }
 212.680 +				/* make sure device names are rooted */
 212.681 +  if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
 212.682 +				/* build name */
 212.683 +  sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
 212.684 +  ucase (tmp);			/* force upper case */
 212.685 +				/* count wildcards */
 212.686 +  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 212.687 +  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
 212.688 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 212.689 +    return NIL;
 212.690 +  }
 212.691 +  return T;
 212.692 +}
   213.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   213.2 +++ b/src/osdep/dos/env_dos.c	Mon Sep 14 15:17:45 2009 +0900
   213.3 @@ -0,0 +1,300 @@
   213.4 +/* ========================================================================
   213.5 + * Copyright 1988-2006 University of Washington
   213.6 + *
   213.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   213.8 + * you may not use this file except in compliance with the License.
   213.9 + * You may obtain a copy of the License at
  213.10 + *
  213.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  213.12 + *
  213.13 + * 
  213.14 + * ========================================================================
  213.15 + */
  213.16 +
  213.17 +/*
  213.18 + * Program:	DOS environment routines
  213.19 + *
  213.20 + * Author:	Mark Crispin
  213.21 + *		Networks and Distributed Computing
  213.22 + *		Computing & Communications
  213.23 + *		University of Washington
  213.24 + *		Administration Building, AG-44
  213.25 + *		Seattle, WA  98195
  213.26 + *		Internet: MRC@CAC.Washington.EDU
  213.27 + *
  213.28 + * Date:	1 August 1988
  213.29 + * Last Edited:	30 August 2006
  213.30 + */
  213.31 +
  213.32 +
  213.33 +static char *myLocalHost = NIL;	/* local host name */
  213.34 +static char *myClientAddr = NIL;/* client host address */
  213.35 +static char *myClientHost = NIL;/* client host name */
  213.36 +static char *myServerAddr = NIL;/* server host address */
  213.37 +static char *myServerHost = NIL;/* server host name */
  213.38 +static char *myHomeDir = NIL;	/* home directory name */
  213.39 +static char *myNewsrc = NIL;	/* newsrc file name */
  213.40 +static long list_max_level = 5;	/* maximum level of list recursion */
  213.41 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  213.42 +				/* home namespace */
  213.43 +static NAMESPACE nshome = {"",'\\',NIL,NIL};
  213.44 +				/* namespace list */
  213.45 +static NAMESPACE *nslist[3] = {&nshome,NIL,NIL};
  213.46 +
  213.47 +#include "write.c"		/* include safe writing routines */
  213.48 +#include "pmatch.c"		/* include wildcard pattern matcher */
  213.49 +
  213.50 +
  213.51 +/* Dummy definitions to prevent errors */
  213.52 +
  213.53 +#define server_login(user,pass,authuser,argc,argv) NIL
  213.54 +#define authserver_login(user,authuser,argc,argv) NIL
  213.55 +#define myusername() ""
  213.56 +#define MD5ENABLE "\\.nosuch.."
  213.57 +
  213.58 +
  213.59 +/* Get all authenticators */
  213.60 +
  213.61 +#include "auths.c"
  213.62 +
  213.63 +/* Environment manipulate parameters
  213.64 + * Accepts: function code
  213.65 + *	    function-dependent value
  213.66 + * Returns: function-dependent return value
  213.67 + */
  213.68 +
  213.69 +void *env_parameters (long function,void *value)
  213.70 +{
  213.71 +  void *ret = NIL;
  213.72 +  switch ((int) function) {
  213.73 +  case GET_NAMESPACE:
  213.74 +    ret = (void *) nslist;
  213.75 +    break;
  213.76 +  case SET_HOMEDIR:
  213.77 +    myHomeDir = cpystr ((char *) value);
  213.78 +  case GET_HOMEDIR:
  213.79 +    ret = (void *) myHomeDir;
  213.80 +    break;
  213.81 +  case SET_LOCALHOST:
  213.82 +    myLocalHost = cpystr ((char *) value);
  213.83 +  case GET_LOCALHOST:
  213.84 +    ret = (void *) myLocalHost;
  213.85 +    break;
  213.86 +  case SET_NEWSRC:
  213.87 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  213.88 +    myNewsrc = cpystr ((char *) value);
  213.89 +  case GET_NEWSRC:
  213.90 +    if (!myNewsrc) {		/* set news file name if not defined */
  213.91 +      char tmp[MAILTMPLEN];
  213.92 +      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
  213.93 +      myNewsrc = cpystr (tmp);
  213.94 +    }
  213.95 +    ret = (void *) myNewsrc;
  213.96 +    break;
  213.97 +  case SET_LISTMAXLEVEL:
  213.98 +    list_max_level = (long) value;
  213.99 +  case GET_LISTMAXLEVEL:
 213.100 +    ret = (void *) list_max_level;
 213.101 +    break;
 213.102 +  case SET_DISABLE822TZTEXT:
 213.103 +    no822tztext = value ? T : NIL;
 213.104 +  case GET_DISABLE822TZTEXT:
 213.105 +    ret = (void *) (no822tztext ? VOIDT : NIL);
 213.106 +    break;
 213.107 +  }
 213.108 +  return ret;
 213.109 +}
 213.110 +
 213.111 +/* Write current time
 213.112 + * Accepts: destination string
 213.113 + *	    optional format of day-of-week prefix
 213.114 + *	    format of date and time
 213.115 + *	    flag whether to append symbolic timezone
 213.116 + */
 213.117 +
 213.118 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
 213.119 +{
 213.120 +  time_t tn = time (0);
 213.121 +  struct tm *t = gmtime (&tn);
 213.122 +  int zone = t->tm_hour * 60 + t->tm_min;
 213.123 +  int julian = t->tm_yday;
 213.124 +  t = localtime (&tn);		/* get local time now */
 213.125 +				/* minus UTC minutes since midnight */
 213.126 +  zone = t->tm_hour * 60 + t->tm_min - zone;
 213.127 +  /* julian can be one of:
 213.128 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
 213.129 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
 213.130 +   *    0  local time is same day as UTC, no offset
 213.131 +   *   -1  local time is 1 day behind UTC, offset -24 hours
 213.132 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
 213.133 +   */
 213.134 +  if (julian = t->tm_yday -julian)
 213.135 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
 213.136 +  if (prefix) {			/* want day of week? */
 213.137 +    sprintf (date,prefix,days[t->tm_wday]);
 213.138 +    date += strlen (date);	/* make next sprintf append */
 213.139 +  }
 213.140 +				/* output the date */
 213.141 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 213.142 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
 213.143 +  if (suffix) {			/* append timezone suffix if desired */
 213.144 +    tzset ();			/* get timezone from TZ environment stuff */
 213.145 +    sprintf (date + strlen (date)," (%.50s)",
 213.146 +	     tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]);
 213.147 +  }
 213.148 +}
 213.149 +
 213.150 +
 213.151 +/* Write current time in RFC 822 format
 213.152 + * Accepts: destination string
 213.153 + */
 213.154 +
 213.155 +void rfc822_date (char *date)
 213.156 +{
 213.157 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
 213.158 +	   no822tztext ? NIL : T);
 213.159 +}
 213.160 +
 213.161 +
 213.162 +/* Write current time in internal format
 213.163 + * Accepts: destination string
 213.164 + */
 213.165 +
 213.166 +void internal_date (char *date)
 213.167 +{
 213.168 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
 213.169 +}
 213.170 +
 213.171 +/* Return my home directory name
 213.172 + * Returns: my home directory name
 213.173 + */
 213.174 +
 213.175 +char *myhomedir ()
 213.176 +{
 213.177 +  int i;
 213.178 +  char *s;
 213.179 +  if (!myHomeDir) {		/* get home directory name if not yet known */
 213.180 +    i = strlen (myHomeDir = cpystr ((s = getenv ("HOME")) ? s : ""));
 213.181 +    if (i && ((myHomeDir[i-1] == '\\') || (myHomeDir[i-1]=='/')))
 213.182 +      myHomeDir[i-1] = '\0';	/* tie off trailing directory delimiter */
 213.183 +  }
 213.184 +  return myHomeDir;
 213.185 +}
 213.186 +
 213.187 +
 213.188 +/* Return mailbox file name
 213.189 + * Accepts: destination buffer
 213.190 + *	    mailbox name
 213.191 + * Returns: file name
 213.192 + */
 213.193 +
 213.194 +char *mailboxfile (char *dst,char *name)
 213.195 +{
 213.196 +  char *s;
 213.197 +  char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL);
 213.198 +				/* forbid extraneous extensions */
 213.199 +  if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) &&
 213.200 +      ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) ||
 213.201 +       strchr (s+1,'.'))) return NIL;
 213.202 +				/* absolute path name? */
 213.203 +  if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name);
 213.204 +  else sprintf (dst,"%s\\%s",myhomedir (),name);
 213.205 +  if (ext) sprintf (dst + strlen (dst),".%s",ext);
 213.206 +  return ucase (dst);
 213.207 +}
 213.208 +
 213.209 +
 213.210 +/* Determine default prototype stream to user
 213.211 + * Accepts: type (NIL for create, T for append)
 213.212 + * Returns: default prototype stream
 213.213 + */
 213.214 +
 213.215 +MAILSTREAM *default_proto (long type)
 213.216 +{
 213.217 +  extern MAILSTREAM DEFAULTPROTO;
 213.218 +  return &DEFAULTPROTO;		/* return default driver's prototype */
 213.219 +}
 213.220 +
 213.221 +/* Global data */
 213.222 +
 213.223 +static unsigned rndm = 0;	/* initial `random' number */
 213.224 +
 213.225 +
 213.226 +/* Return random number
 213.227 + */
 213.228 +
 213.229 +long random ()
 213.230 +{
 213.231 +  if (!rndm) srand (rndm = (unsigned) time (0L));
 213.232 +  return (long) rand ();
 213.233 +}
 213.234 +
 213.235 +/* Default mailgets routine on DOS
 213.236 + * Accepts: readin function pointer
 213.237 + *	    stream to use
 213.238 + *	    number of bytes
 213.239 + *	    identifier data
 213.240 + * Returns: string read in, truncated if necessary
 213.241 + *
 213.242 + * This is a sample mailgets routine.  It simply truncates any data larger
 213.243 + * than 63K.  On most systems, you generally don't use a mailgets
 213.244 + * routine at all, but on DOS it's required to prevent the application from
 213.245 + * crashing.
 213.246 + */
 213.247 +
 213.248 +static char *dos_gets_buf = NIL;
 213.249 +
 213.250 +char *dos_default_gets (readfn_t f,void *stream,unsigned long size,
 213.251 +			GETS_DATA *md)
 213.252 +{
 213.253 +  readprogress_t *rp = mail_parameters (NIL,GET_READPROGRESS,NIL);
 213.254 +  char *ret,tmp[MAILTMPLEN+1];
 213.255 +  unsigned long i,j,dsc,rdi = 0;
 213.256 +  unsigned long dos_max = 63 * 1024;
 213.257 +  if (!dos_gets_buf)		/* one-time initialization */
 213.258 +    dos_gets_buf = (char *) fs_get ((size_t) dos_max + 1);
 213.259 +  ret = (md->flags & MG_COPY) ?
 213.260 +    ((char *) fs_get ((size_t) size + 1)) : dos_gets_buf;
 213.261 +  if (size > dos_max) {
 213.262 +    sprintf (tmp,"Mailbox %s, %s %lu[%.80s], %lu octets truncated to %ld",
 213.263 +	     md->stream->mailbox,(md->flags & MG_UID) ? "UID" : "#",
 213.264 +	     md->msgno,md->what,size,(long) dos_max);
 213.265 +    mm_log (tmp,WARN);		/* warn user */
 213.266 +    dsc = size - dos_max;	/* number of bytes to discard */
 213.267 +    size = dos_max;		/* maximum length string we can read */
 213.268 +  }
 213.269 +  else dsc = 0;			/* nothing to discard */
 213.270 +  dos_gets_buf[size] = '\0';	/* tie off string */
 213.271 +  if (rp) for (i = size; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
 213.272 +    (*f) (stream,j,ret + rdi);
 213.273 +    (*rp) (md,rdi += j);
 213.274 +  }
 213.275 +  else (*f) (stream,size,dos_gets_buf);
 213.276 +				/* toss out everything after that */
 213.277 +  for (i = dsc; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
 213.278 +    (*f) (stream,j,tmp);
 213.279 +    if (rp) (*rp) (md,rdi += j);
 213.280 +  }
 213.281 +  return ret;
 213.282 +}
 213.283 +
 213.284 +/* Emulator for BSD syslog() routine
 213.285 + * Accepts: priority
 213.286 + *	    message
 213.287 + *	    parameters
 213.288 + */
 213.289 +
 213.290 +void syslog (int priority,const char *message,...)
 213.291 +{
 213.292 +}
 213.293 +
 213.294 +
 213.295 +/* Emulator for BSD openlog() routine
 213.296 + * Accepts: identity
 213.297 + *	    options
 213.298 + *	    facility
 213.299 + */
 213.300 +
 213.301 +void openlog (const char *ident,int logopt,int facility)
 213.302 +{
 213.303 +}
   214.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   214.2 +++ b/src/osdep/dos/env_dos.h	Mon Sep 14 15:17:45 2009 +0900
   214.3 @@ -0,0 +1,68 @@
   214.4 +/* ========================================================================
   214.5 + * Copyright 1988-2006 University of Washington
   214.6 + *
   214.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   214.8 + * you may not use this file except in compliance with the License.
   214.9 + * You may obtain a copy of the License at
  214.10 + *
  214.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  214.12 + *
  214.13 + * 
  214.14 + * ========================================================================
  214.15 + */
  214.16 +
  214.17 +/*
  214.18 + * Program:	DOS environment routines
  214.19 + *
  214.20 + * Author:	Mark Crispin
  214.21 + *		Networks and Distributed Computing
  214.22 + *		Computing & Communications
  214.23 + *		University of Washington
  214.24 + *		Administration Building, AG-44
  214.25 + *		Seattle, WA  98195
  214.26 + *		Internet: MRC@CAC.Washington.EDU
  214.27 + *
  214.28 + * Date:	1 August 1988
  214.29 + * Last Edited:	30 August 2006
  214.30 + */
  214.31 +
  214.32 +
  214.33 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/MAILBOX.LST",myhomedir ())
  214.34 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/MAILBOX.TMP",myhomedir ())
  214.35 +
  214.36 +#define L_SET SEEK_SET
  214.37 +
  214.38 +/* Function prototypes */
  214.39 +
  214.40 +#include "env.h"
  214.41 +
  214.42 +char *dos_default_gets (readfn_t f,void *stream,unsigned long size,
  214.43 +			GETS_DATA *md);
  214.44 +long safe_write (int fd,char *buf,long nbytes);
  214.45 +long random ();
  214.46 +#if _MSC_VER < 700
  214.47 +#define getpid random
  214.48 +#endif
  214.49 +
  214.50 +
  214.51 +/* syslog() emulation */
  214.52 +
  214.53 +#define LOG_MAIL	(2<<3)	/* mail system */
  214.54 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  214.55 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  214.56 +#define LOG_EMERG	0	/* system is unusable */
  214.57 +#define LOG_ALERT	1	/* action must be taken immediately */
  214.58 +#define LOG_CRIT	2	/* critical conditions */
  214.59 +#define LOG_ERR		3	/* error conditions */
  214.60 +#define LOG_WARNING	4	/* warning conditions */
  214.61 +#define LOG_NOTICE	5	/* normal but signification condition */
  214.62 +#define LOG_INFO	6	/* informational */
  214.63 +#define LOG_DEBUG	7	/* debug-level messages */
  214.64 +#define LOG_PID		0x01	/* log the pid with each message */
  214.65 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  214.66 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  214.67 +#define LOG_NDELAY	0x08	/* don't delay open */
  214.68 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  214.69 +
  214.70 +void openlog (const char *ident,int logopt,int facility);
  214.71 +void syslog (int priority,const char *message,...);
   215.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   215.2 +++ b/src/osdep/dos/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
   215.3 @@ -0,0 +1,99 @@
   215.4 +/* ========================================================================
   215.5 + * Copyright 1988-2007 University of Washington
   215.6 + *
   215.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   215.8 + * you may not use this file except in compliance with the License.
   215.9 + * You may obtain a copy of the License at
  215.10 + *
  215.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  215.12 + *
  215.13 + * 
  215.14 + * ========================================================================
  215.15 + */
  215.16 +
  215.17 +/*
  215.18 + * Program:	File descriptor string routines
  215.19 + *
  215.20 + * Author:	Mark Crispin
  215.21 + *		Networks and Distributed Computing
  215.22 + *		Computing & Communications
  215.23 + *		University of Washington
  215.24 + *		Administration Building, AG-44
  215.25 + *		Seattle, WA  98195
  215.26 + *		Internet: MRC@CAC.Washington.EDU
  215.27 + *
  215.28 + * Date:	15 April 1997
  215.29 + * Last Edited:	4 April 2007
  215.30 + */
  215.31 +
  215.32 +#include "mail.h"
  215.33 +#include "osdep.h"
  215.34 +#include "misc.h"
  215.35 +#include "fdstring.h"
  215.36 +
  215.37 +/* String driver for fd stringstructs */
  215.38 +
  215.39 +static void fd_string_init (STRING *s,void *data,unsigned long size);
  215.40 +static char fd_string_next (STRING *s);
  215.41 +static void fd_string_setpos (STRING *s,unsigned long i);
  215.42 +
  215.43 +STRINGDRIVER fd_string = {
  215.44 +  fd_string_init,		/* initialize string structure */
  215.45 +  fd_string_next,		/* get next byte in string structure */
  215.46 +  fd_string_setpos		/* set position in string structure */
  215.47 +};
  215.48 +
  215.49 +
  215.50 +/* Initialize string structure for fd stringstruct
  215.51 + * Accepts: string structure
  215.52 + *	    pointer to string
  215.53 + *	    size of string
  215.54 + */
  215.55 +
  215.56 +static void fd_string_init (STRING *s,void *data,unsigned long size)
  215.57 +{
  215.58 +  FDDATA *d = (FDDATA *) data;
  215.59 +				/* note fd */
  215.60 +  s->data = (void *) (unsigned long) d->fd;
  215.61 +  s->data1 = d->pos;		/* note file offset */
  215.62 +  s->size = size;		/* note size */
  215.63 +  s->curpos = s->chunk = d->chunk;
  215.64 +  s->chunksize = (unsigned long) d->chunksize;
  215.65 +  s->offset = 0;		/* initial position */
  215.66 +				/* and size of data */
  215.67 +  s->cursize = min (s->chunksize,size);
  215.68 +				/* move to that position in the file */
  215.69 +  lseek (d->fd,d->pos,L_SET);
  215.70 +  read (d->fd,s->chunk,(size_t) s->cursize);
  215.71 +}
  215.72 +
  215.73 +/* Get next character from fd stringstruct
  215.74 + * Accepts: string structure
  215.75 + * Returns: character, string structure chunk refreshed
  215.76 + */
  215.77 +
  215.78 +static char fd_string_next (STRING *s)
  215.79 +{
  215.80 +  char c = *s->curpos++;	/* get next byte */
  215.81 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
  215.82 +  return c;			/* return the byte */
  215.83 +}
  215.84 +
  215.85 +
  215.86 +/* Set string pointer position for fd stringstruct
  215.87 + * Accepts: string structure
  215.88 + *	    new position
  215.89 + */
  215.90 +
  215.91 +static void fd_string_setpos (STRING *s,unsigned long i)
  215.92 +{
  215.93 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
  215.94 +  s->offset = i;		/* set new offset */
  215.95 +  s->curpos = s->chunk;		/* reset position */
  215.96 +				/* set size of data */
  215.97 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
  215.98 +				/* move to that position in the file */
  215.99 +    lseek ((long) s->data,s->data1 + s->offset,L_SET);
 215.100 +    read ((long) s->data,s->curpos,(size_t) s->cursize);
 215.101 +  }
 215.102 +}
   216.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   216.2 +++ b/src/osdep/dos/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
   216.3 @@ -0,0 +1,39 @@
   216.4 +/* ========================================================================
   216.5 + * Copyright 1988-2006 University of Washington
   216.6 + *
   216.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   216.8 + * you may not use this file except in compliance with the License.
   216.9 + * You may obtain a copy of the License at
  216.10 + *
  216.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  216.12 + *
  216.13 + * 
  216.14 + * ========================================================================
  216.15 + */
  216.16 +
  216.17 +/*
  216.18 + * Program:	File descriptor string routines
  216.19 + *
  216.20 + * Author:	Mark Crispin
  216.21 + *		Networks and Distributed Computing
  216.22 + *		Computing & Communications
  216.23 + *		University of Washington
  216.24 + *		Administration Building, AG-44
  216.25 + *		Seattle, WA  98195
  216.26 + *		Internet: MRC@CAC.Washington.EDU
  216.27 + *
  216.28 + * Date:	15 April 1997
  216.29 + * Last Edited:	30 August 2006
  216.30 + */
  216.31 +
  216.32 +/* Driver-dependent data passed to init method */
  216.33 +
  216.34 +typedef struct fd_data {
  216.35 +  int fd;			/* file descriptor */
  216.36 +  unsigned long pos;		/* initial position */
  216.37 +  char *chunk;			/* I/O buffer chunk */
  216.38 +  unsigned long chunksize;	/* I/O buffer chunk length */
  216.39 +} FDDATA;
  216.40 +
  216.41 +
  216.42 +extern STRINGDRIVER fd_string;
   217.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   217.2 +++ b/src/osdep/dos/fs_dos.c	Mon Sep 14 15:17:45 2009 +0900
   217.3 @@ -0,0 +1,62 @@
   217.4 +/* ========================================================================
   217.5 + * Copyright 1988-2006 University of Washington
   217.6 + *
   217.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   217.8 + * you may not use this file except in compliance with the License.
   217.9 + * You may obtain a copy of the License at
  217.10 + *
  217.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  217.12 + *
  217.13 + * 
  217.14 + * ========================================================================
  217.15 + */
  217.16 +
  217.17 +/*
  217.18 + * Program:	Free storage management routines
  217.19 + *
  217.20 + * Author:	Mark Crispin
  217.21 + *		Networks and Distributed Computing
  217.22 + *		Computing & Communications
  217.23 + *		University of Washington
  217.24 + *		Administration Building, AG-44
  217.25 + *		Seattle, WA  98195
  217.26 + *		Internet: MRC@CAC.Washington.EDU
  217.27 + *
  217.28 + * Date:	1 August 1988
  217.29 + * Last Edited:	30 August 2006
  217.30 + */
  217.31 +
  217.32 +/* Get a block of free storage
  217.33 + * Accepts: size of desired block
  217.34 + * Returns: free storage block
  217.35 + */
  217.36 +
  217.37 +void *fs_get (size_t size)
  217.38 +{
  217.39 +  void *block = malloc (size ? size : (size_t) 1);
  217.40 +  if (!block) fatal ("Out of memory");
  217.41 +  return (block);
  217.42 +}
  217.43 +
  217.44 +
  217.45 +/* Resize a block of free storage
  217.46 + * Accepts: ** pointer to current block
  217.47 + *	    new size
  217.48 + */
  217.49 +
  217.50 +void fs_resize (void **block,size_t size)
  217.51 +{
  217.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  217.53 +    fatal ("Can't resize memory");
  217.54 +}
  217.55 +
  217.56 +
  217.57 +/* Return a block of free storage
  217.58 + * Accepts: ** pointer to free storage block
  217.59 + */
  217.60 +
  217.61 +void fs_give (void **block)
  217.62 +{
  217.63 +  free (*block);
  217.64 +  *block = NIL;
  217.65 +}
   218.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   218.2 +++ b/src/osdep/dos/ftl_dos.c	Mon Sep 14 15:17:45 2009 +0900
   218.3 @@ -0,0 +1,38 @@
   218.4 +/* ========================================================================
   218.5 + * Copyright 1988-2006 University of Washington
   218.6 + *
   218.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   218.8 + * you may not use this file except in compliance with the License.
   218.9 + * You may obtain a copy of the License at
  218.10 + *
  218.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  218.12 + *
  218.13 + * 
  218.14 + * ========================================================================
  218.15 + */
  218.16 +
  218.17 +/*
  218.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  218.19 + *
  218.20 + * Author:	Mark Crispin
  218.21 + *		Networks and Distributed Computing
  218.22 + *		Computing & Communications
  218.23 + *		University of Washington
  218.24 + *		Administration Building, AG-44
  218.25 + *		Seattle, WA  98195
  218.26 + *		Internet: MRC@CAC.Washington.EDU
  218.27 + *
  218.28 + * Date:	1 August 1988
  218.29 + * Last Edited:	30 August 2006
  218.30 + */
  218.31 +
  218.32 +
  218.33 +/* Report a fatal error
  218.34 + * Accepts: string to output
  218.35 + */
  218.36 +
  218.37 +void fatal (char *string)
  218.38 +{
  218.39 +  mm_fatal (string);		/* pass up the string */
  218.40 +  abort ();			/* die horribly */
  218.41 +}
   219.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   219.2 +++ b/src/osdep/dos/makefile	Mon Sep 14 15:17:45 2009 +0900
   219.3 @@ -0,0 +1,98 @@
   219.4 +# ========================================================================
   219.5 +# Copyright 1988-2007 University of Washington
   219.6 +#
   219.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   219.8 +# you may not use this file except in compliance with the License.
   219.9 +# You may obtain a copy of the License at
  219.10 +#
  219.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  219.12 +#
  219.13 +# 
  219.14 +# ========================================================================
  219.15 +
  219.16 +
  219.17 +# Program:	Portable C client makefile -- MS-DOS version
  219.18 +#
  219.19 +# Author:	Mark Crispin
  219.20 +#		Networks and Distributed Computing
  219.21 +#		Computing & Communications
  219.22 +#		University of Washington
  219.23 +#		Administration Building, AG-44
  219.24 +#		Seattle, WA  98195
  219.25 +#		Internet: MRC@CAC.Washington.EDU
  219.26 +#
  219.27 +# Date:		11 May 1989
  219.28 +# Last Edited:	23 May 2007
  219.29 +
  219.30 +
  219.31 +OS = wsk
  219.32 +EXTRAAUTHENTICATORS=
  219.33 +DEFAULTAUTHENTICATORS= ext md5 pla log
  219.34 +EXTRADRIVERS = 
  219.35 +DRIVERS = imap nntp pop3 mtx bezerk
  219.36 +DEFAULTDRIVER = mtx
  219.37 +CFLAGS= -AL /DCHUNKSIZE=4096 -nologo $(EXTRACFLAGS)
  219.38 +CC = cl
  219.39 +
  219.40 +all:	mtest.exe
  219.41 +
  219.42 +.c.obj:
  219.43 +	$(CC) -c $(CFLAGS) $*.c
  219.44 +
  219.45 +osdep.h: os_$(OS).h
  219.46 +	copy os_$(OS).h osdep.h
  219.47 +	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
  219.48 +	mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
  219.49 +	ECHO #define DEFAULTPROTO $(DEFAULTDRIVER)proto >> LINKAGE.H
  219.50 +	ECHO   if (!mail_parameters (NIL,GET_GETS)) >> LINKAGE.C
  219.51 +	ECHO     mail_parameters (NIL,SET_GETS,(void *) dos_default_gets); >> LINKAGE.C
  219.52 +	ECHO mail_versioncheck (CCLIENTVERSION); >> LINKAGE.C
  219.53 +
  219.54 +mtest.obj: mail.h smtp.h misc.h osdep.h mtest.c
  219.55 +
  219.56 +mail.obj: mail.h misc.h osdep.h mail.c
  219.57 +
  219.58 +misc.obj: mail.h misc.h misc.c
  219.59 +
  219.60 +fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
  219.61 +
  219.62 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  219.63 +
  219.64 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  219.65 +
  219.66 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  219.67 +
  219.68 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  219.69 +
  219.70 +smanager.obj: mail.h misc.h smanager.c
  219.71 +
  219.72 +utf8.obj: mail.h misc.h osdep.h utf8.h
  219.73 +
  219.74 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  219.75 +
  219.76 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  219.77 +
  219.78 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  219.79 +
  219.80 +pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
  219.81 +
  219.82 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  219.83 +
  219.84 +os_$(OS).obj: mail.h osdep.h env_dos.h fs.h ftl.h nl.h tcp.h \
  219.85 +	os_$(OS).c fs_dos.c ftl_dos.c nl_dos.c env_dos.c pmatch.c write.c
  219.86 +
  219.87 +mtxdos.obj: mail.h misc.h osdep.h mtxdos.c
  219.88 +
  219.89 +bezrkdos.obj: mail.h misc.h osdep.h bezrkdos.c
  219.90 +
  219.91 +dummydos.obj: mail.h dummy.h misc.h osdep.h dummydos.c
  219.92 +
  219.93 +cclient.lib: mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
  219.94 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
  219.95 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_$(OS).obj \
  219.96 +	mtxdos.obj bezrkdos.obj dummydos.obj
  219.97 +	erase cclient.lib
  219.98 +	lib cclient +mail+misc+fdstring+flstring+netmsg+newsrc+rfc822+smanager+utf8+utf8aux+imap4r1+nntp+pop3+smtp+os_$(OS)+mtxdos+bezrkdos+dummydos;
  219.99 +
 219.100 +mtest.exe: cclient.lib mtest.obj
 219.101 +	mtest$(OS)
   220.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   220.2 +++ b/src/osdep/dos/mkautaux.bat	Mon Sep 14 15:17:45 2009 +0900
   220.3 @@ -0,0 +1,29 @@
   220.4 +@ECHO OFF
   220.5 +REM ========================================================================
   220.6 +REM Copyright 1988-2006 University of Washington
   220.7 +REM
   220.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   220.9 +REM you may not use this file except in compliance with the License.
  220.10 +REM You may obtain a copy of the License at
  220.11 +REM
  220.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  220.13 +REM
  220.14 +REM 
  220.15 +REM ========================================================================
  220.16 +
  220.17 +REM Program:	Authenticator Linkage Generator auxillary for DOS
  220.18 +REM
  220.19 +REM Author:	Mark Crispin
  220.20 +REM		Networks and Distributed Computing
  220.21 +REM		Computing & Communications
  220.22 +REM		University of Washington
  220.23 +REM		Administration Building, AG-44
  220.24 +REM		Seattle, WA  98195
  220.25 +REM		Internet: MRC@CAC.Washington.EDU
  220.26 +REM
  220.27 +REM Date:	7 December 1995
  220.28 +REM Last Edited:30 August 2006
  220.29 +
  220.30 +ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
  220.31 +ECHO   auth_link (&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
  220.32 +ECHO #include "auth_%1.c" >> AUTHS.C
   221.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   221.2 +++ b/src/osdep/dos/mkauths.bat	Mon Sep 14 15:17:45 2009 +0900
   221.3 @@ -0,0 +1,33 @@
   221.4 +@ECHO OFF
   221.5 +REM ========================================================================
   221.6 +REM Copyright 1988-2006 University of Washington
   221.7 +REM
   221.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   221.9 +REM you may not use this file except in compliance with the License.
  221.10 +REM You may obtain a copy of the License at
  221.11 +REM
  221.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  221.13 +REM
  221.14 +REM 
  221.15 +REM ========================================================================
  221.16 +
  221.17 +REM Program:	Authenticator Linkage Generator for DOS and Windows
  221.18 +REM
  221.19 +REM Author:	Mark Crispin
  221.20 +REM		Networks and Distributed Computing
  221.21 +REM		Computing & Communications
  221.22 +REM		University of Washington
  221.23 +REM		Administration Building, AG-44
  221.24 +REM		Seattle, WA  98195
  221.25 +REM		Internet: MRC@CAC.Washington.EDU
  221.26 +REM
  221.27 +REM Date:	6 December 1995
  221.28 +REM Last Edited:30 August 2006
  221.29 +
  221.30 +REM Erase old authenticators list
  221.31 +IF EXIST AUTHS.C DEL AUTHS.C
  221.32 +
  221.33 +REM Now define the new list
  221.34 +FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
  221.35 +
  221.36 +EXIT 0
   222.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   222.2 +++ b/src/osdep/dos/mtestdbw.bat	Mon Sep 14 15:17:45 2009 +0900
   222.3 @@ -0,0 +1,27 @@
   222.4 +@ECHO OFF
   222.5 +REM ========================================================================
   222.6 +REM Copyright 1988-2006 University of Washington
   222.7 +REM
   222.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   222.9 +REM you may not use this file except in compliance with the License.
  222.10 +REM You may obtain a copy of the License at
  222.11 +REM
  222.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  222.13 +REM
  222.14 +REM 
  222.15 +REM ========================================================================
  222.16 +
  222.17 +REM Program:	Portable C client makefile -- MS-DOS B&W link
  222.18 +REM
  222.19 +REM Author:	Mark Crispin
  222.20 +REM		Networks and Distributed Computing
  222.21 +REM		Computing & Communications
  222.22 +REM		University of Washington
  222.23 +REM		Administration Building, AG-44
  222.24 +REM		Seattle, WA  98195
  222.25 +REM		Internet: MRC@CAC.Washington.EDU
  222.26 +REM
  222.27 +REM Date:	26 June 1994
  222.28 +REM Last Edited:30 August 2006
  222.29 +
  222.30 +link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llbwtcp.lib llibce.lib
   223.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   223.2 +++ b/src/osdep/dos/mtestdnf.bat	Mon Sep 14 15:17:45 2009 +0900
   223.3 @@ -0,0 +1,27 @@
   223.4 +@ECHO OFF
   223.5 +REM ========================================================================
   223.6 +REM Copyright 1988-2006 University of Washington
   223.7 +REM
   223.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   223.9 +REM you may not use this file except in compliance with the License.
  223.10 +REM You may obtain a copy of the License at
  223.11 +REM
  223.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  223.13 +REM
  223.14 +REM 
  223.15 +REM ========================================================================
  223.16 +
  223.17 +REM Program:	Portable C client makefile -- MS-DOS PC-NFS link
  223.18 +REM
  223.19 +REM Author:	Mark Crispin
  223.20 +REM		Networks and Distributed Computing
  223.21 +REM		Computing & Communications
  223.22 +REM		University of Washington
  223.23 +REM		Administration Building, AG-44
  223.24 +REM		Seattle, WA  98195
  223.25 +REM		Internet: MRC@CAC.Washington.EDU
  223.26 +REM
  223.27 +REM Date:	26 June 1994
  223.28 +REM Last Edited:30 August 2006
  223.29 +
  223.30 +link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib ltklib.lib
   224.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   224.2 +++ b/src/osdep/dos/mtestdnv.bat	Mon Sep 14 15:17:45 2009 +0900
   224.3 @@ -0,0 +1,27 @@
   224.4 +@ECHO OFF
   224.5 +REM ========================================================================
   224.6 +REM Copyright 1988-2006 University of Washington
   224.7 +REM
   224.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   224.9 +REM you may not use this file except in compliance with the License.
  224.10 +REM You may obtain a copy of the License at
  224.11 +REM
  224.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  224.13 +REM
  224.14 +REM 
  224.15 +REM ========================================================================
  224.16 +
  224.17 +REM Program:	Portable C client makefile -- MS-DOS Novell link
  224.18 +REM
  224.19 +REM Author:	Mark Crispin
  224.20 +REM		Networks and Distributed Computing
  224.21 +REM		Computing & Communications
  224.22 +REM		University of Washington
  224.23 +REM		Administration Building, AG-44
  224.24 +REM		Seattle, WA  98195
  224.25 +REM		Internet: MRC@CAC.Washington.EDU
  224.26 +REM
  224.27 +REM Date:	26 June 1994
  224.28 +REM Last Edited:30 August 2006
  224.29 +
  224.30 +link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llibsock.lib
   225.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   225.2 +++ b/src/osdep/dos/mtestdpc.bat	Mon Sep 14 15:17:45 2009 +0900
   225.3 @@ -0,0 +1,27 @@
   225.4 +@ECHO OFF
   225.5 +REM ========================================================================
   225.6 +REM Copyright 1988-2006 University of Washington
   225.7 +REM
   225.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   225.9 +REM you may not use this file except in compliance with the License.
  225.10 +REM You may obtain a copy of the License at
  225.11 +REM
  225.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  225.13 +REM
  225.14 +REM 
  225.15 +REM ========================================================================
  225.16 +
  225.17 +REM Program:	Portable C client makefile -- MS-DOS PC/TCP link
  225.18 +REM
  225.19 +REM Author:	Mark Crispin
  225.20 +REM		Networks and Distributed Computing
  225.21 +REM		Computing & Communications
  225.22 +REM		University of Washington
  225.23 +REM		Administration Building, AG-44
  225.24 +REM		Seattle, WA  98195
  225.25 +REM		Internet: MRC@CAC.Washington.EDU
  225.26 +REM
  225.27 +REM Date:	26 June 1994
  225.28 +REM Last Edited:30 August 2006
  225.29 +
  225.30 +link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib lsocket.lib lnetlib.lib lpc.lib lconfig.lib llibce.lib;
   226.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   226.2 +++ b/src/osdep/dos/mtestdwa.bat	Mon Sep 14 15:17:45 2009 +0900
   226.3 @@ -0,0 +1,27 @@
   226.4 +@ECHO OFF
   226.5 +REM ========================================================================
   226.6 +REM Copyright 1988-2006 University of Washington
   226.7 +REM
   226.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   226.9 +REM you may not use this file except in compliance with the License.
  226.10 +REM You may obtain a copy of the License at
  226.11 +REM
  226.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  226.13 +REM
  226.14 +REM 
  226.15 +REM ========================================================================
  226.16 +
  226.17 +REM Program:	Portable C client makefile -- MS-DOS Waterloo link
  226.18 +REM
  226.19 +REM Author:	Mark Crispin
  226.20 +REM		Networks and Distributed Computing
  226.21 +REM		Computing & Communications
  226.22 +REM		University of Washington
  226.23 +REM		Administration Building, AG-44
  226.24 +REM		Seattle, WA  98195
  226.25 +REM		Internet: MRC@CAC.Washington.EDU
  226.26 +REM
  226.27 +REM Date:	26 June 1994
  226.28 +REM Last Edited:30 August 2006
  226.29 +
  226.30 +link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib wattcplg.lib
   227.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   227.2 +++ b/src/osdep/dos/mtestwsk.bat	Mon Sep 14 15:17:45 2009 +0900
   227.3 @@ -0,0 +1,27 @@
   227.4 +@ECHO OFF
   227.5 +REM ========================================================================
   227.6 +REM Copyright 1988-2006 University of Washington
   227.7 +REM
   227.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   227.9 +REM you may not use this file except in compliance with the License.
  227.10 +REM You may obtain a copy of the License at
  227.11 +REM
  227.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  227.13 +REM
  227.14 +REM 
  227.15 +REM ========================================================================
  227.16 +
  227.17 +REM Program:	Portable C client makefile -- MS-DOS Winsock link
  227.18 +REM
  227.19 +REM Author:	Mark Crispin
  227.20 +REM		Networks and Distributed Computing
  227.21 +REM		Computing & Communications
  227.22 +REM		University of Washington
  227.23 +REM		Administration Building, AG-44
  227.24 +REM		Seattle, WA  98195
  227.25 +REM		Internet: MRC@CAC.Washington.EDU
  227.26 +REM
  227.27 +REM Date:	26 June 1994
  227.28 +REM Last Edited:30 August 2006
  227.29 +
  227.30 +link /NOD:llibce mtest.obj,mtest.exe,,cclient.lib winsock.lib llibcewq.lib libw.lib, mtest
   228.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   228.2 +++ b/src/osdep/dos/mtxdos.c	Mon Sep 14 15:17:45 2009 +0900
   228.3 @@ -0,0 +1,875 @@
   228.4 +/* ========================================================================
   228.5 + * Copyright 1988-2006 University of Washington
   228.6 + *
   228.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   228.8 + * you may not use this file except in compliance with the License.
   228.9 + * You may obtain a copy of the License at
  228.10 + *
  228.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  228.12 + *
  228.13 + * 
  228.14 + * ========================================================================
  228.15 + */
  228.16 +
  228.17 +/*
  228.18 + * Program:	MTX mail routines
  228.19 + *
  228.20 + * Author:	Mark Crispin
  228.21 + *		Networks and Distributed Computing
  228.22 + *		Computing & Communications
  228.23 + *		University of Washington
  228.24 + *		Administration Building, AG-44
  228.25 + *		Seattle, WA  98195
  228.26 + *		Internet: MRC@CAC.Washington.EDU
  228.27 + *
  228.28 + * Date:	24 June 1992
  228.29 + * Last Edited:	30 August 2006
  228.30 + */
  228.31 +
  228.32 +
  228.33 +#include <ctype.h>
  228.34 +#include <errno.h>
  228.35 +#include <fcntl.h>
  228.36 +#include "mail.h"
  228.37 +#include "osdep.h"
  228.38 +#include <time.h>
  228.39 +#include <sys\stat.h>
  228.40 +#include <dos.h>
  228.41 +#include "rfc822.h"
  228.42 +#include "dummy.h"
  228.43 +#include "misc.h"
  228.44 +#include "fdstring.h"
  228.45 +
  228.46 +/* MTX I/O stream local data */
  228.47 +	
  228.48 +typedef struct mtx_local {
  228.49 +  int fd;			/* file descriptor for I/O */
  228.50 +  off_t filesize;		/* file size parsed */
  228.51 +  unsigned char *buf;		/* temporary buffer */
  228.52 +} MTXLOCAL;
  228.53 +
  228.54 +
  228.55 +/* Drive-dependent data passed to init method */
  228.56 +
  228.57 +typedef struct mtx_data {
  228.58 +  int fd;			/* file data */
  228.59 +  unsigned long pos;		/* initial position */
  228.60 +} MTXDATA;
  228.61 +
  228.62 +
  228.63 +/* Convenient access to local data */
  228.64 +
  228.65 +#define LOCAL ((MTXLOCAL *) stream->local)
  228.66 +
  228.67 +
  228.68 +/* Function prototypes */
  228.69 +
  228.70 +DRIVER *mtx_valid (char *name);
  228.71 +long mtx_isvalid (char *name,char *tmp);
  228.72 +void *mtx_parameters (long function,void *value);
  228.73 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  228.74 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
  228.75 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  228.76 +long mtx_create (MAILSTREAM *stream,char *mailbox);
  228.77 +long mtx_delete (MAILSTREAM *stream,char *mailbox);
  228.78 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
  228.79 +MAILSTREAM *mtx_open (MAILSTREAM *stream);
  228.80 +void mtx_close (MAILSTREAM *stream,long options);
  228.81 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
  228.82 +		  unsigned long *length,long flags);
  228.83 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  228.84 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  228.85 +long mtx_ping (MAILSTREAM *stream);
  228.86 +void mtx_check (MAILSTREAM *stream);
  228.87 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
  228.88 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  228.89 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  228.90 +
  228.91 +char *mtx_file (char *dst,char *name);
  228.92 +long mtx_badname (char *tmp,char *s);
  228.93 +long mtx_parse (MAILSTREAM *stream);
  228.94 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno);
  228.95 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
  228.96 +			  unsigned long *size);
  228.97 +
  228.98 +/* MTX mail routines */
  228.99 +
 228.100 +
 228.101 +/* Driver dispatch used by MAIL */
 228.102 +
 228.103 +DRIVER mtxdriver = {
 228.104 +  "mtx",			/* driver name */
 228.105 +				/* driver flags */
 228.106 +  DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY,
 228.107 +  (DRIVER *) NIL,		/* next driver */
 228.108 +  mtx_valid,			/* mailbox is valid for us */
 228.109 +  mtx_parameters,		/* manipulate parameters */
 228.110 +  mtx_scan,			/* scan mailboxes */
 228.111 +  mtx_list,			/* list mailboxes */
 228.112 +  mtx_lsub,			/* list subscribed mailboxes */
 228.113 +  NIL,				/* subscribe to mailbox */
 228.114 +  NIL,				/* unsubscribe from mailbox */
 228.115 +  mtx_create,			/* create mailbox */
 228.116 +  mtx_delete,			/* delete mailbox */
 228.117 +  mtx_rename,			/* rename mailbox */
 228.118 +  mail_status_default,		/* status of mailbox */
 228.119 +  mtx_open,			/* open mailbox */
 228.120 +  mtx_close,			/* close mailbox */
 228.121 +  NIL,				/* fetch message "fast" attributes */
 228.122 +  NIL,				/* fetch message flags */
 228.123 +  NIL,				/* fetch overview */
 228.124 +  NIL,				/* fetch message envelopes */
 228.125 +  mtx_header,			/* fetch message header */
 228.126 +  mtx_text,			/* fetch message body */
 228.127 +  NIL,				/* fetch partial message text */
 228.128 +  NIL,				/* unique identifier */
 228.129 +  NIL,				/* message number */
 228.130 +  NIL,				/* modify flags */
 228.131 +  mtx_flagmsg,			/* per-message modify flags */
 228.132 +  NIL,				/* search for message based on criteria */
 228.133 +  NIL,				/* sort messages */
 228.134 +  NIL,				/* thread messages */
 228.135 +  mtx_ping,			/* ping mailbox to see if still alive */
 228.136 +  mtx_check,			/* check for new messages */
 228.137 +  mtx_expunge,			/* expunge deleted messages */
 228.138 +  mtx_copy,			/* copy messages to another mailbox */
 228.139 +  mtx_append,			/* append string message to mailbox */
 228.140 +  NIL				/* garbage collect stream */
 228.141 +};
 228.142 +
 228.143 +				/* prototype stream */
 228.144 +MAILSTREAM mtxproto = {&mtxdriver};
 228.145 +
 228.146 +/* MTX mail validate mailbox
 228.147 + * Accepts: mailbox name
 228.148 + * Returns: our driver if name is valid, NIL otherwise
 228.149 + */
 228.150 +
 228.151 +DRIVER *mtx_valid (char *name)
 228.152 +{
 228.153 +  char tmp[MAILTMPLEN];
 228.154 +  return mtx_isvalid (name,tmp) ? &mtxdriver : (DRIVER *) NIL;
 228.155 +}
 228.156 +
 228.157 +
 228.158 +/* MTX mail test for valid mailbox
 228.159 + * Accepts: mailbox name
 228.160 + * Returns: T if valid, NIL otherwise
 228.161 + */
 228.162 +
 228.163 +long mtx_isvalid (char *name,char *tmp)
 228.164 +{
 228.165 +  int fd;
 228.166 +  long ret = NIL;
 228.167 +  char *s;
 228.168 +  struct stat sbuf;
 228.169 +  errno = EINVAL;		/* assume invalid argument */
 228.170 +				/* if file, get its status */
 228.171 +  if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) {
 228.172 +    if (!sbuf.st_size)errno = 0;/* empty file */
 228.173 +    else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) {
 228.174 +      memset (tmp,'\0',MAILTMPLEN);
 228.175 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
 228.176 +	  (s[1] == '\012')) {	/* valid format? */
 228.177 +	*s = '\0';		/* tie off header */
 228.178 +				/* must begin with dd-mmm-yy" */
 228.179 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 228.180 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 228.181 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 228.182 +      }
 228.183 +      else errno = -1;		/* bogus format */
 228.184 +      close (fd);		/* close the file */
 228.185 +    }
 228.186 +  }
 228.187 +				/* in case INBOX but not mtx format */
 228.188 +  else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) &&
 228.189 +	   ((name[1] == 'N') || (name[1] == 'n')) &&
 228.190 +	   ((name[2] == 'B') || (name[2] == 'b')) &&
 228.191 +	   ((name[3] == 'O') || (name[3] == 'o')) &&
 228.192 +	   ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1;
 228.193 +  return ret;			/* return what we should */
 228.194 +}
 228.195 +
 228.196 +
 228.197 +/* MTX manipulate driver parameters
 228.198 + * Accepts: function code
 228.199 + *	    function-dependent value
 228.200 + * Returns: function-dependent return value
 228.201 + */
 228.202 +
 228.203 +void *mtx_parameters (long function,void *value)
 228.204 +{
 228.205 +  return NIL;
 228.206 +}
 228.207 +
 228.208 +/* MTX mail scan mailboxes
 228.209 + * Accepts: mail stream
 228.210 + *	    reference
 228.211 + *	    pattern to search
 228.212 + *	    string to scan
 228.213 + */
 228.214 +
 228.215 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 228.216 +{
 228.217 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 228.218 +}
 228.219 +
 228.220 +
 228.221 +/* MTX mail list mailboxes
 228.222 + * Accepts: mail stream
 228.223 + *	    reference
 228.224 + *	    pattern to search
 228.225 + */
 228.226 +
 228.227 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
 228.228 +{
 228.229 +  if (stream) dummy_list (stream,ref,pat);
 228.230 +}
 228.231 +
 228.232 +
 228.233 +/* MTX mail list subscribed mailboxes
 228.234 + * Accepts: mail stream
 228.235 + *	    reference
 228.236 + *	    pattern to search
 228.237 + */
 228.238 +
 228.239 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 228.240 +{
 228.241 +  if (stream) dummy_lsub (stream,ref,pat);
 228.242 +}
 228.243 +
 228.244 +/* MTX mail create mailbox
 228.245 + * Accepts: MAIL stream
 228.246 + *	    mailbox name to create
 228.247 + * Returns: T on success, NIL on failure
 228.248 + */
 228.249 +
 228.250 +long mtx_create (MAILSTREAM *stream,char *mailbox)
 228.251 +{
 228.252 +  return dummy_create (stream,mailbox);
 228.253 +}
 228.254 +
 228.255 +
 228.256 +/* MTX mail delete mailbox
 228.257 + * Accepts: MAIL stream
 228.258 + *	    mailbox name to delete
 228.259 + * Returns: T on success, NIL on failure
 228.260 + */
 228.261 +
 228.262 +long mtx_delete (MAILSTREAM *stream,char *mailbox)
 228.263 +{
 228.264 +  return dummy_delete (stream,mailbox);
 228.265 +}
 228.266 +
 228.267 +
 228.268 +/* MTX mail rename mailbox
 228.269 + * Accepts: MAIL stream
 228.270 + *	    old mailbox name
 228.271 + *	    new mailbox name (or NIL for delete)
 228.272 + * Returns: T on success, NIL on failure
 228.273 + */
 228.274 +
 228.275 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
 228.276 +{
 228.277 +  return dummy_rename (stream,old,newname);
 228.278 +}
 228.279 +
 228.280 +/* MTX mail open
 228.281 + * Accepts: stream to open
 228.282 + * Returns: stream on success, NIL on failure
 228.283 + */
 228.284 +
 228.285 +MAILSTREAM *mtx_open (MAILSTREAM *stream)
 228.286 +{
 228.287 +  long i;
 228.288 +  int fd;
 228.289 +  char *s;
 228.290 +  char tmp[MAILTMPLEN];
 228.291 +				/* return prototype for OP_PROTOTYPE call */
 228.292 +  if (!stream) return &mtxproto;
 228.293 +  if (stream->local) fatal ("mtx recycle stream");
 228.294 +  if (!mailboxfile (tmp,stream->mailbox))
 228.295 +    return (MAILSTREAM *) mtx_badname (tmp,stream->mailbox);
 228.296 +				/* open, possibly creating INBOX */
 228.297 +  if (((fd = open (tmp,O_BINARY|(stream->rdonly ? O_RDONLY:O_RDWR),NIL)) < 0)&&
 228.298 +      (compare_cstring (stream->mailbox,"INBOX") ||
 228.299 +       ((fd = open (tmp,O_BINARY|O_RDWR|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))<0))){
 228.300 +    sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 228.301 +    mm_log (tmp,ERROR);
 228.302 +    return NIL;
 228.303 +  }
 228.304 +  stream->local = fs_get (sizeof (MTXLOCAL));
 228.305 +				/* canonicalize the stream mailbox name */
 228.306 +  fs_give ((void **) &stream->mailbox);
 228.307 +  if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0';
 228.308 +  stream->mailbox = cpystr (tmp);
 228.309 +  LOCAL->fd = fd;		/* note the file */
 228.310 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 228.311 +  LOCAL->buf = NIL;		/* initially no local buffer */
 228.312 +  stream->sequence++;		/* bump sequence number */
 228.313 +  stream->uid_validity = time (0);
 228.314 +				/* parse mailbox */
 228.315 +  stream->nmsgs = stream->recent = 0;
 228.316 +  if (!mtx_ping (stream)) return NIL;
 228.317 +  if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL);
 228.318 +  stream->perm_seen = stream->perm_deleted =
 228.319 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 228.320 +      stream->rdonly ? NIL : T;
 228.321 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 228.322 +  return stream;		/* return stream to caller */
 228.323 +}
 228.324 +
 228.325 +/* MTX mail close
 228.326 + * Accepts: MAIL stream
 228.327 + *	    close options
 228.328 + */
 228.329 +
 228.330 +void mtx_close (MAILSTREAM *stream,long options)
 228.331 +{
 228.332 +  if (stream && LOCAL) {	/* only if a file is open */
 228.333 +    int silent = stream->silent;
 228.334 +    stream->silent = T;
 228.335 +    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
 228.336 +    close (LOCAL->fd);		/* close the local file */
 228.337 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 228.338 +				/* nuke the local data */
 228.339 +    fs_give ((void **) &stream->local);
 228.340 +    stream->dtb = NIL;		/* log out the DTB */
 228.341 +  }
 228.342 +}
 228.343 +
 228.344 +/* MTX mail fetch message header
 228.345 + * Accepts: MAIL stream
 228.346 + *	    message # to fetch
 228.347 + *	    pointer to returned header text length
 228.348 + *	    option flags
 228.349 + * Returns: message header in RFC822 format
 228.350 + */
 228.351 +
 228.352 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 228.353 +		  long flags)
 228.354 +{
 228.355 +  *length = 0;			/* default to empty */
 228.356 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 228.357 +				/* get to header position */
 228.358 +  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
 228.359 +				/* is buffer big enough? */
 228.360 +  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 228.361 +  LOCAL->buf = (char *) fs_get ((size_t) *length + 1);
 228.362 +  LOCAL->buf[*length] = '\0';	/* tie off string */
 228.363 +				/* slurp the data */
 228.364 +  read (LOCAL->fd,LOCAL->buf,(size_t) *length);
 228.365 +  return LOCAL->buf;
 228.366 +}
 228.367 +
 228.368 +
 228.369 +/* MTX mail fetch message text (body only)
 228.370 + * Accepts: MAIL stream
 228.371 + *	    message # to fetch
 228.372 + *	    pointer to returned header text length
 228.373 + *	    option flags
 228.374 + * Returns: T, always
 228.375 + */
 228.376 +
 228.377 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 228.378 +{
 228.379 +  MESSAGECACHE *elt;
 228.380 +  FDDATA d;
 228.381 +  unsigned long hdrsize,hdrpos;
 228.382 +				/* UID call "impossible" */
 228.383 +  if (flags & FT_UID) return NIL;
 228.384 +  elt = mail_elt (stream,msgno);/* if message not seen */
 228.385 +  if (elt->seen && !(flags & FT_PEEK)) {
 228.386 +    elt->seen = T;		/* mark message as seen */
 228.387 +				/* recalculate status */
 228.388 +    mtx_update_status (stream,msgno);
 228.389 +    mm_flags (stream,msgno);
 228.390 +  }
 228.391 +				/* get location of text data */
 228.392 +  hdrpos = mtx_hdrpos (stream,msgno,&hdrsize);
 228.393 +  d.fd = LOCAL->fd;		/* set initial stringstruct */
 228.394 +  d.pos = hdrpos + hdrsize;
 228.395 +				/* flush old buffer */
 228.396 +  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 228.397 +  d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE);
 228.398 +  INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize);
 228.399 +  return T;			/* success */
 228.400 +}
 228.401 +
 228.402 +/* MTX mail per-message modify flags
 228.403 + * Accepts: MAIL stream
 228.404 + *	    message cache element
 228.405 + */
 228.406 +
 228.407 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 228.408 +{
 228.409 +				/* recalculate status */
 228.410 +  mtx_update_status (stream,elt->msgno);
 228.411 +}
 228.412 +
 228.413 +
 228.414 +/* MTX mail ping mailbox
 228.415 + * Accepts: MAIL stream
 228.416 + * Returns: T if stream still alive, NIL if not
 228.417 + */
 228.418 +
 228.419 +long mtx_ping (MAILSTREAM *stream)
 228.420 +{
 228.421 +				/* punt if stream no longer alive */
 228.422 +  if (!(stream && LOCAL)) return NIL;
 228.423 +				/* parse mailbox, punt if parse dies */
 228.424 +  return (mtx_parse (stream)) ? T : NIL;
 228.425 +}
 228.426 +
 228.427 +
 228.428 +/* MTX mail check mailbox (reparses status too)
 228.429 + * Accepts: MAIL stream
 228.430 + */
 228.431 +
 228.432 +void mtx_check (MAILSTREAM *stream)
 228.433 +{
 228.434 +  unsigned long i = 1;
 228.435 +  if (mtx_ping (stream)) {	/* ping mailbox */
 228.436 +				/* get new message status */
 228.437 +    while (i <= stream->nmsgs) mail_elt (stream,i++);
 228.438 +    mm_log ("Check completed",(long) NIL);
 228.439 +  }
 228.440 +}
 228.441 +
 228.442 +/* MTX mail expunge mailbox
 228.443 + * Accepts: MAIL stream
 228.444 + *	    sequence to expunge if non-NIL
 228.445 + *	    expunge options
 228.446 + * Returns: T, always
 228.447 + */
 228.448 +
 228.449 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
 228.450 +{
 228.451 +  long ret;
 228.452 +  unsigned long i = 1;
 228.453 +  unsigned long j,k,m,recent;
 228.454 +  unsigned long n = 0;
 228.455 +  unsigned long delta = 0;
 228.456 +  MESSAGECACHE *elt;
 228.457 +  char tmp[MAILTMPLEN];
 228.458 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 228.459 +			   mail_uid_sequence (stream,sequence) :
 228.460 +			   mail_sequence (stream,sequence)) : LONGT) &&
 228.461 +	mtx_ping (stream)));	/* parse sequence if given, ping stream */
 228.462 +  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
 228.463 +  else {
 228.464 +    mm_critical (stream);	/* go critical */
 228.465 +    recent = stream->recent;	/* get recent now that pinged */ 
 228.466 +    while (i <= stream->nmsgs) {/* for each message */
 228.467 +      elt = mail_elt (stream,i);/* get cache element */
 228.468 +				/* number of bytes to smash or preserve */
 228.469 +      k = elt->private.special.text.size + elt->rfc822_size;
 228.470 +				/* if need to expunge this message */
 228.471 +      if (elt->deleted && (sequence ? elt->sequence : T)) {
 228.472 +				/* if recent, note one less recent message */
 228.473 +	if (elt->recent) --recent;
 228.474 +	delta += k;		/* number of bytes to delete */
 228.475 +				/* notify upper levels */
 228.476 +	mail_expunged (stream,i);
 228.477 +	n++;			/* count up one more deleted message */
 228.478 +      }
 228.479 +      else if (i++ && delta) {	/* preserved message */
 228.480 +				/* first byte to preserve */
 228.481 +	j = elt->private.special.offset;
 228.482 +	do {			/* read from source position */
 228.483 +	  m = min (k,(unsigned long) MAILTMPLEN);
 228.484 +	  lseek (LOCAL->fd,j,SEEK_SET);
 228.485 +	  read (LOCAL->fd,tmp,(size_t) m);
 228.486 +				/* write to destination position */
 228.487 +	  lseek (LOCAL->fd,j - delta,SEEK_SET);
 228.488 +	  write (LOCAL->fd,tmp,(size_t) m);
 228.489 +	  j += m;		/* next chunk, perhaps */
 228.490 +	} while (k -= m);	/* until done */
 228.491 +	elt->private.special.offset -= delta;
 228.492 +      }
 228.493 +    }
 228.494 +    if (n) {			/* truncate file after last message */
 228.495 +      chsize (LOCAL->fd,LOCAL->filesize -= delta);
 228.496 +      sprintf (tmp,"Expunged %ld messages",n);
 228.497 +      mm_log (tmp,(long) NIL);	/* output the news */
 228.498 +    }
 228.499 +    else mm_log ("No messages deleted, so no update needed",(long) NIL);
 228.500 +    mm_nocritical (stream);	/* release critical */
 228.501 +				/* notify upper level of new mailbox size */
 228.502 +    mail_exists (stream,stream->nmsgs);
 228.503 +    mail_recent (stream,recent);
 228.504 +  }
 228.505 +  return ret;
 228.506 +}
 228.507 +
 228.508 +/* MTX mail copy message(s)
 228.509 + * Accepts: MAIL stream
 228.510 + *	    sequence
 228.511 + *	    destination mailbox
 228.512 + *	    copy options
 228.513 + * Returns: T if success, NIL if failed
 228.514 + */
 228.515 +
 228.516 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 228.517 +{
 228.518 +  char tmp[MAILTMPLEN];
 228.519 +  struct stat sbuf;
 228.520 +  MESSAGECACHE *elt;
 228.521 +  unsigned long i,j,k;
 228.522 +  long ret = LONGT;
 228.523 +  int fd;
 228.524 +  mailproxycopy_t pc =
 228.525 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 228.526 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 228.527 +	mail_sequence (stream,sequence))) return NIL;
 228.528 +  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
 228.529 +  case ENOENT:			/* no such file? */
 228.530 +    mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
 228.531 +	       (long) NIL);
 228.532 +    return NIL;
 228.533 +  case 0:			/* merely empty file? */
 228.534 +    break;
 228.535 +  case EINVAL:			/* name is bogus */
 228.536 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 228.537 +    return mtx_badname (tmp,mailbox);
 228.538 +  default:			/* file exists, but not valid format */
 228.539 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 228.540 +    sprintf (tmp,"Not a MTX-format mailbox: %s",mailbox);
 228.541 +    mm_log (tmp,ERROR);
 228.542 +    return NIL;
 228.543 +  }
 228.544 +				/* open the destination */
 228.545 +  if (!mailboxfile (tmp,mailbox) ||
 228.546 +      (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
 228.547 +		  S_IREAD|S_IWRITE)) < 0) {
 228.548 +    sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno));
 228.549 +    mm_log (tmp,ERROR);
 228.550 +    return NIL;
 228.551 +  }
 228.552 +
 228.553 +  mm_critical (stream);		/* go critical */
 228.554 +  fstat (fd,&sbuf);		/* get current file size */
 228.555 +				/* for each requested message */
 228.556 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
 228.557 +    if ((elt = mail_elt (stream,i))->sequence) {
 228.558 +      lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET);
 228.559 +				/* number of bytes to copy */
 228.560 +      k = elt->private.special.text.size + elt->rfc822_size;
 228.561 +      do {			/* read from source position */
 228.562 +	j = min (k,(long) MAILTMPLEN);
 228.563 +	read (LOCAL->fd,tmp,(size_t) j);
 228.564 +	if (write (fd,tmp,(size_t) j) < 0) {
 228.565 +	  sprintf (tmp,"Unable to write message: %s",strerror (errno));
 228.566 +	  mm_log (tmp,ERROR);
 228.567 +	  chsize (fd,sbuf.st_size);
 228.568 +	  j = k;
 228.569 +	  ret = NIL;		/* note error */
 228.570 +	  break;
 228.571 +	}
 228.572 +      } while (k -= j);		/* until done */
 228.573 +    }
 228.574 +  close (fd);			/* close the file */
 228.575 +  mm_nocritical (stream);	/* release critical */
 228.576 +				/* delete all requested messages */
 228.577 +  if (ret && (options & CP_MOVE)) for (i = 1; i <= stream->nmsgs; i++)
 228.578 +    if ((elt = mail_elt (stream,i))->sequence) {
 228.579 +      elt->deleted = T;		/* mark message deleted */
 228.580 +				/* recalculate status */
 228.581 +      mtx_update_status (stream,i);
 228.582 +    }
 228.583 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 228.584 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
 228.585 +  return ret;
 228.586 +}
 228.587 +
 228.588 +/* MTX mail append message from stringstruct
 228.589 + * Accepts: MAIL stream
 228.590 + *	    destination mailbox
 228.591 + *	    append callback
 228.592 + *	    data for callback
 228.593 + * Returns: T if append successful, else NIL
 228.594 + */
 228.595 +
 228.596 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 228.597 +{
 228.598 +  struct stat sbuf;
 228.599 +  int fd,ld,c;
 228.600 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN];
 228.601 +  FILE *df;
 228.602 +  MESSAGECACHE elt;
 228.603 +  long f;
 228.604 +  unsigned long i,uf;
 228.605 +  STRING *message;
 228.606 +  long ret = LONGT;
 228.607 +				/* default stream to prototype */
 228.608 +  if (!stream) stream = &mtxproto;
 228.609 +				/* make sure valid mailbox */
 228.610 +  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
 228.611 +  case ENOENT:			/* no such file? */
 228.612 +    if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
 228.613 +	((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
 228.614 +	((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
 228.615 +	((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
 228.616 +	((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5])
 228.617 +      dummy_create (NIL,"INBOX.MTX");
 228.618 +    else {
 228.619 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 228.620 +      return NIL;
 228.621 +    }
 228.622 +				/* falls through */
 228.623 +  case 0:			/* merely empty file? */
 228.624 +    break;
 228.625 +  case EINVAL:
 228.626 +    return mtx_badname (tmp,mailbox);
 228.627 +  default:
 228.628 +    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
 228.629 +    mm_log (tmp,ERROR);
 228.630 +    return NIL;
 228.631 +  }
 228.632 +				/* get first message */
 228.633 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
 228.634 +				/* open destination mailbox */
 228.635 +  if (!mailboxfile (file,mailbox) ||
 228.636 +      ((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
 228.637 +		   S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) {
 228.638 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
 228.639 +    mm_log (tmp,ERROR);
 228.640 +    return NIL;
 228.641 +  }
 228.642 +  mm_critical (stream);		/* go critical */
 228.643 +  fstat (fd,&sbuf);		/* get current file size */
 228.644 +
 228.645 +  errno = 0;
 228.646 +  do {				/* parse flags */
 228.647 +    if (!SIZE (message)) {	/* guard against zero-length */
 228.648 +      mm_log ("Append of zero-length message",ERROR);
 228.649 +      ret = NIL;
 228.650 +      break;
 228.651 +    }
 228.652 +    f = mail_parse_flags (stream,flags,&i);
 228.653 +				/* reverse bits (dontcha wish we had CIRC?) */
 228.654 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
 228.655 +    if (date) {			/* parse date if given */
 228.656 +      if (!mail_parse_date (&elt,date)) {
 228.657 +	sprintf (tmp,"Bad date in append: %.80s",date);
 228.658 +	mm_log (tmp,ERROR);
 228.659 +	ret = NIL;		/* mark failure */
 228.660 +	break;
 228.661 +      }
 228.662 +      mail_date (tmp,&elt);	/* write preseved date */
 228.663 +    }
 228.664 +    else internal_date (tmp);	/* get current date in IMAP format */
 228.665 +				/* write header */
 228.666 +    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
 228.667 +		 (unsigned long) f) < 0) ret = NIL;
 228.668 +    else {			/* write message */
 228.669 +      if (i) do c = 0xff & SNX (message);
 228.670 +      while ((putc (c,df) != EOF) && --i);
 228.671 +				/* get next message */
 228.672 +      if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
 228.673 +    }
 228.674 +  } while (ret && message);
 228.675 +				/* revert file if failure */
 228.676 +  if (!ret || (fflush (df) == EOF)) {
 228.677 +    chsize (fd,sbuf.st_size);	/* revert file */
 228.678 +    close (fd);			/* make sure fclose() doesn't corrupt us */
 228.679 +    if (errno) {
 228.680 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
 228.681 +      mm_log (tmp,ERROR);
 228.682 +    }
 228.683 +    ret = NIL;
 228.684 +  }
 228.685 +  fclose (df);			/* close the file */ 
 228.686 +  mm_nocritical (stream);	/* release critical */
 228.687 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
 228.688 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
 228.689 +	    WARN);
 228.690 +  return ret;
 228.691 +}
 228.692 +
 228.693 +
 228.694 +/* Return bad file name error message
 228.695 + * Accepts: temporary buffer
 228.696 + *	    file name
 228.697 + * Returns: long NIL always
 228.698 + */
 228.699 +
 228.700 +long mtx_badname (char *tmp,char *s)
 228.701 +{
 228.702 +  sprintf (tmp,"Invalid mailbox name: %s",s);
 228.703 +  mm_log (tmp,ERROR);
 228.704 +  return (long) NIL;
 228.705 +}
 228.706 +
 228.707 +/* Parse mailbox
 228.708 + * Accepts: MAIL stream
 228.709 + * Returns: T if parse OK
 228.710 + *	    NIL if failure, stream aborted
 228.711 + */
 228.712 +
 228.713 +long mtx_parse (MAILSTREAM *stream)
 228.714 +{
 228.715 +  struct stat sbuf;
 228.716 +  MESSAGECACHE *elt = NIL;
 228.717 +  unsigned char *s,*t,*x,lbuf[65];
 228.718 +  char tmp[MAILTMPLEN];
 228.719 +  long i;
 228.720 +  long curpos = LOCAL->filesize;
 228.721 +  long nmsgs = stream->nmsgs;
 228.722 +  long recent = stream->recent;
 228.723 +  fstat (LOCAL->fd,&sbuf);	/* get status */
 228.724 +  if (sbuf.st_size < curpos) {	/* sanity check */
 228.725 +    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
 228.726 +    mm_log (tmp,ERROR);
 228.727 +    mtx_close (stream,NIL);
 228.728 +    return NIL;
 228.729 +  }
 228.730 +				/* while there is stuff to parse */
 228.731 +  while (i = sbuf.st_size - curpos) {
 228.732 +				/* get to that position in the file */
 228.733 +    lseek (LOCAL->fd,curpos,SEEK_SET);
 228.734 +    if ((i = read (LOCAL->fd,lbuf,64)) <= 0) {
 228.735 +      sprintf (tmp,"Unable to read internal header at %ld, size = %ld: %s",
 228.736 +	       curpos,sbuf.st_size,i ? strerror (errno) : "no data read");
 228.737 +      mm_log (tmp,ERROR);
 228.738 +      mtx_close (stream,NIL);
 228.739 +      return NIL;
 228.740 +    }
 228.741 +    lbuf[i] = '\0';		/* tie off buffer just in case */
 228.742 +    if (!((s = strchr (lbuf,'\015')) && (s[1] == '\012'))) {
 228.743 +      sprintf (tmp,"Unable to find end of line at %ld in %ld bytes, text: %s",
 228.744 +	       curpos,i,(char *) lbuf);
 228.745 +      mm_log (tmp,ERROR);
 228.746 +      mtx_close (stream,NIL);
 228.747 +      return NIL;
 228.748 +    }
 228.749 +    *s = '\0';			/* tie off header line */
 228.750 +    i = (s + 2) - lbuf;		/* note start of text offset */
 228.751 +    if (!((s = strchr (lbuf,',')) && (t = strchr (s+1,';')))) {
 228.752 +      sprintf (tmp,"Unable to parse internal header at %ld: %s",curpos,
 228.753 +	       (char *) lbuf);
 228.754 +      mm_log (tmp,ERROR);
 228.755 +      mtx_close (stream,NIL);
 228.756 +      return NIL;
 228.757 +    }
 228.758 +
 228.759 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
 228.760 +				/* intantiate an elt for this message */
 228.761 +    (elt = mail_elt (stream,++nmsgs))->valid = T;
 228.762 +    elt->private.uid = ++stream->uid_last;
 228.763 +				/* note file offset of header */
 228.764 +    elt->private.special.offset = curpos;
 228.765 +				/* as well as offset from header of message */
 228.766 +    elt->private.special.text.size = i;
 228.767 +				/* header size not known yet */
 228.768 +    elt->private.msg.header.text.size = 0;
 228.769 +				/* parse the header components */
 228.770 +    if (!(mail_parse_date (elt,lbuf) &&
 228.771 +	  (elt->rfc822_size = strtol (x = s,(char **) &s,10)) && (!(s && *s))&&
 228.772 +	  isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
 228.773 +	  isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
 228.774 +	  isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
 228.775 +	  isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])) {
 228.776 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
 228.777 +	       curpos,(char *) lbuf,(char *) x,(char *) t);
 228.778 +      mtx_close (stream,NIL);
 228.779 +      return NIL;
 228.780 +    }
 228.781 +				/* update current position to next header */
 228.782 +    curpos += i + elt->rfc822_size;
 228.783 +				/* calculate system flags */
 228.784 +    if ((i = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
 228.785 +    if (i & fDELETED) elt->deleted = T;
 228.786 +    if (i & fFLAGGED) elt->flagged = T;
 228.787 +    if (i & fANSWERED) elt->answered = T;
 228.788 +    if (i & fDRAFT) elt->draft = T;
 228.789 +    if (curpos > sbuf.st_size) {
 228.790 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
 228.791 +	       elt->private.special.offset,curpos,sbuf.st_size);
 228.792 +      mm_log (tmp,ERROR);
 228.793 +      mtx_close (stream,NIL);
 228.794 +      return NIL;
 228.795 +    }
 228.796 +  }
 228.797 +				/* update parsed file size */
 228.798 +  LOCAL->filesize = sbuf.st_size;
 228.799 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
 228.800 +  mail_recent (stream,recent);	/* and of change in recent messages */
 228.801 +  return T;			/* return the winnage */
 228.802 +}
 228.803 +
 228.804 +/* Update status string
 228.805 + * Accepts: MAIL stream
 228.806 + *	    message number
 228.807 + */
 228.808 +
 228.809 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno)
 228.810 +{
 228.811 +  char tmp[MAILTMPLEN];
 228.812 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
 228.813 +  unsigned long j,k = 0;
 228.814 +				/* not if readonly you don't */
 228.815 +  if (stream->rdonly || !elt->valid) return;
 228.816 +  j = elt->user_flags;		/* get user flags */
 228.817 +				/* reverse bits (dontcha wish we had CIRC?) */
 228.818 +  while (j) k |= 1 << 29 - find_rightmost_bit (&j);
 228.819 +  sprintf (tmp,"%010lo%02o",k,	/* print new flag string */
 228.820 +	   fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 228.821 +	   (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 228.822 +	   (fDRAFT * elt->draft));
 228.823 +				/* get to that place in the file */
 228.824 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
 228.825 +	 elt->private.special.text.size - 14,SEEK_SET);
 228.826 +  write (LOCAL->fd,tmp,12);	/* write new flags */
 228.827 +}
 228.828 +
 228.829 +/* MTX locate header for a message
 228.830 + * Accepts: MAIL stream
 228.831 + *	    message number
 228.832 + *	    pointer to returned header size
 228.833 + * Returns: position of header in file
 228.834 + */
 228.835 +
 228.836 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 228.837 +			  unsigned long *size)
 228.838 +{
 228.839 +  unsigned long siz;
 228.840 +  size_t i = 0;
 228.841 +  int q = 0;
 228.842 +  char *s,tmp[MAILTMPLEN];
 228.843 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
 228.844 +  long pos = elt->private.special.offset + elt->private.special.text.size;
 228.845 +				/* is header size known? */
 228.846 +  if (!(*size = elt->private.msg.header.text.size)) {
 228.847 +				/* get to header position */
 228.848 +    lseek (LOCAL->fd,pos,SEEK_SET);
 228.849 +				/* search message for CRLF CRLF */
 228.850 +    for (siz = 1; siz <= elt->rfc822_size; siz++) {
 228.851 +      if (!i &&			/* buffer empty? */
 228.852 +	  (read (LOCAL->fd,s = tmp,
 228.853 +		 i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0))
 228.854 +	return pos;
 228.855 +      else i--;
 228.856 +      switch (q) {		/* sniff at buffer */
 228.857 +      case 0:			/* first character */
 228.858 +	q = (*s++ == '\015') ? 1 : 0;
 228.859 +	break;
 228.860 +      case 1:			/* second character */
 228.861 +	q = (*s++ == '\012') ? 2 : 0;
 228.862 +	break;
 228.863 +      case 2:			/* third character */
 228.864 +	q = (*s++ == '\015') ? 3 : 0;
 228.865 +	break;
 228.866 +      case 3:			/* fourth character */
 228.867 +	if (*s++ == '\012') {	/* have the sequence? */
 228.868 +				/* yes, note for later */
 228.869 +	  elt->private.msg.header.text.size = (*size = siz);
 228.870 +	  return pos;		/* return to caller */
 228.871 +	}
 228.872 +	q = 0;			/* lost... */
 228.873 +	break;
 228.874 +      }
 228.875 +    }
 228.876 +  }
 228.877 +  return pos;			/* have position */
 228.878 +}
   229.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   229.2 +++ b/src/osdep/dos/nl_dos.c	Mon Sep 14 15:17:45 2009 +0900
   229.3 @@ -0,0 +1,61 @@
   229.4 +/* ========================================================================
   229.5 + * Copyright 1988-2006 University of Washington
   229.6 + *
   229.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   229.8 + * you may not use this file except in compliance with the License.
   229.9 + * You may obtain a copy of the License at
  229.10 + *
  229.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  229.12 + *
  229.13 + * 
  229.14 + * ========================================================================
  229.15 + */
  229.16 +
  229.17 +/*
  229.18 + * Program:	Windows/TOPS-20 newline routines
  229.19 + *
  229.20 + * Author:	Mark Crispin
  229.21 + *		Networks and Distributed Computing
  229.22 + *		Computing & Communications
  229.23 + *		University of Washington
  229.24 + *		Administration Building, AG-44
  229.25 + *		Seattle, WA  98195
  229.26 + *		Internet: MRC@CAC.Washington.EDU
  229.27 + *
  229.28 + * Date:	1 August 1988
  229.29 + * Last Edited:	30 August 2006
  229.30 + */
  229.31 +
  229.32 +/* Copy string with CRLF newlines
  229.33 + * Accepts: destination string
  229.34 + *	    pointer to size of destination string buffer
  229.35 + *	    source string
  229.36 + *	    length of source string
  229.37 + * Returns: length of copied string
  229.38 + */
  229.39 +
  229.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  229.41 +			  unsigned char *src,unsigned long srcl)
  229.42 +{
  229.43 +				/* flush destination buffer if too small */
  229.44 +  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
  229.45 +  if (!*dst) {			/* make a new buffer if needed */
  229.46 +    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
  229.47 +    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
  229.48 +  }
  229.49 +				/* copy strings */
  229.50 +  if (srcl) memcpy (*dst,src,(size_t) srcl);
  229.51 +  *(*dst + srcl) = '\0';	/* tie off destination */
  229.52 +  return srcl;			/* return length */
  229.53 +}
  229.54 +
  229.55 +
  229.56 +/* Length of string after strcrlfcpy applied
  229.57 + * Accepts: source string
  229.58 + * Returns: length of string
  229.59 + */
  229.60 +
  229.61 +unsigned long strcrlflen (STRING *s)
  229.62 +{
  229.63 +  return SIZE (s);		/* no-brainer on DOS! */
  229.64 +}
   230.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   230.2 +++ b/src/osdep/dos/os_dbw.c	Mon Sep 14 15:17:45 2009 +0900
   230.3 @@ -0,0 +1,91 @@
   230.4 +/* ========================================================================
   230.5 + * Copyright 1988-2006 University of Washington
   230.6 + *
   230.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   230.8 + * you may not use this file except in compliance with the License.
   230.9 + * You may obtain a copy of the License at
  230.10 + *
  230.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  230.12 + *
  230.13 + * 
  230.14 + * ========================================================================
  230.15 + */
  230.16 +
  230.17 +/*
  230.18 + * Program:	Operating-system dependent routines -- MS-DOS (B&W) version
  230.19 + *
  230.20 + * Author:	Mark Crispin
  230.21 + *		Networks and Distributed Computing
  230.22 + *		Computing & Communications
  230.23 + *		University of Washington
  230.24 + *		Administration Building, AG-44
  230.25 + *		Seattle, WA  98195
  230.26 + *		Internet: MRC@CAC.Washington.EDU
  230.27 + *
  230.28 + * Date:	11 April 1989
  230.29 + * Last Edited:	30 August 2006
  230.30 + */
  230.31 +
  230.32 +/* Private function prototypes */
  230.33 +
  230.34 +#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
  230.35 +#include "mail.h"
  230.36 +#include "osdep.h"
  230.37 +#include <time.h>
  230.38 +#include <errno.h>
  230.39 +#include <fcntl.h>
  230.40 +#include <sys\stat.h>
  230.41 +#include <sys\timeb.h>
  230.42 +#include "misc.h"
  230.43 +#include "stdlib.h"
  230.44 +#include "bwtcp.h"
  230.45 +
  230.46 +
  230.47 +#include "fs_dos.c"
  230.48 +#include "ftl_dos.c"
  230.49 +#include "nl_dos.c"
  230.50 +#include "env_dos.c"
  230.51 +#undef write
  230.52 +#define read soread
  230.53 +#define write sowrite
  230.54 +#define close soclose 
  230.55 +#include "tcp_dos.c"
  230.56 +
  230.57 +
  230.58 +/* Return my local host name
  230.59 + * Returns: my local host name
  230.60 + */
  230.61 +
  230.62 +char *mylocalhost (void)
  230.63 +{
  230.64 +  char *s;
  230.65 +  if (!myLocalHost) {		/* known yet? */
  230.66 +				/* get local host name from DISPLAY env var */
  230.67 +    if (!((s = getenv ("DISPLAY")) || (s = getenv ("display")))) {
  230.68 +      mm_log ("Environment variable 'DISPLAY' is not set", ERROR);
  230.69 +      s = "random-pc";
  230.70 +    }
  230.71 +    myLocalHost = cpystr (s);
  230.72 +  }
  230.73 +  return myLocalHost;
  230.74 +}
  230.75 +
  230.76 +
  230.77 +/* Look up host address
  230.78 + * Accepts: pointer to pointer to host name
  230.79 + *	    socket address block
  230.80 + * Returns: non-zero with host address in socket, official host name in host;
  230.81 + *	    else NIL
  230.82 + */
  230.83 +
  230.84 +long lookuphost (char **host,struct sockaddr_in *sin)
  230.85 +{
  230.86 +  char *s = *host;		/* in case of error */
  230.87 +  sin->sin_addr.s_addr = rhost (host);
  230.88 +  if (sin->sin_addr.s_addr == -1) {
  230.89 +    *host = s;			/* error, restore old host name */
  230.90 +    return NIL;
  230.91 +  }
  230.92 +  *host = cpystr (*host);	/* make permanent copy of name */
  230.93 +  return T;			/* success */
  230.94 +}
   231.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   231.2 +++ b/src/osdep/dos/os_dbw.h	Mon Sep 14 15:17:45 2009 +0900
   231.3 @@ -0,0 +1,43 @@
   231.4 +/* ========================================================================
   231.5 + * Copyright 1988-2006 University of Washington
   231.6 + *
   231.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   231.8 + * you may not use this file except in compliance with the License.
   231.9 + * You may obtain a copy of the License at
  231.10 + *
  231.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  231.12 + *
  231.13 + * 
  231.14 + * ========================================================================
  231.15 + */
  231.16 +
  231.17 +/*
  231.18 + * Program:	Operating-system dependent routines -- DOS (B&W/Novell) version
  231.19 + *
  231.20 + * Author:	Mark Crispin
  231.21 + *		Networks and Distributed Computing
  231.22 + *		Computing & Communications
  231.23 + *		University of Washington
  231.24 + *		Administration Building, AG-44
  231.25 + *		Seattle, WA  98195
  231.26 + *		Internet: MRC@CAC.Washington.EDU
  231.27 + *
  231.28 + * Date:	11 May 1989
  231.29 + * Last Edited:	30 August 2006
  231.30 + */
  231.31 +
  231.32 +#define INADEQUATE_MEMORY
  231.33 +
  231.34 +#include <stdlib.h>
  231.35 +#include <stdio.h>
  231.36 +#include <string.h>
  231.37 +#include <sys\types.h>
  231.38 +#include <io.h>
  231.39 +
  231.40 +#define gethostid clock
  231.41 +
  231.42 +#include "env_dos.h"
  231.43 +#include "fs.h"
  231.44 +#include "ftl.h"
  231.45 +#include "nl.h"
  231.46 +#include "tcp.h"
   232.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   232.2 +++ b/src/osdep/dos/os_dnf.c	Mon Sep 14 15:17:45 2009 +0900
   232.3 @@ -0,0 +1,95 @@
   232.4 +/* ========================================================================
   232.5 + * Copyright 1988-2006 University of Washington
   232.6 + *
   232.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   232.8 + * you may not use this file except in compliance with the License.
   232.9 + * You may obtain a copy of the License at
  232.10 + *
  232.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  232.12 + *
  232.13 + * 
  232.14 + * ========================================================================
  232.15 + */
  232.16 +
  232.17 +/*
  232.18 + * Program:	Operating-system dependent routines -- MS-DOS (PC-NFS) version
  232.19 + *
  232.20 + * Author:	Mark Crispin
  232.21 + *		Networks and Distributed Computing
  232.22 + *		Computing & Communications
  232.23 + *		University of Washington
  232.24 + *		Administration Building, AG-44
  232.25 + *		Seattle, WA  98195
  232.26 + *		Internet: MRC@CAC.Washington.EDU
  232.27 + *
  232.28 + * Date:	11 April 1989
  232.29 + * Last Edited:	30 August 2006
  232.30 + */
  232.31 +
  232.32 +/* Private function prototypes */
  232.33 +
  232.34 +#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
  232.35 +#include "mail.h"
  232.36 +#include "osdep.h"
  232.37 +#include <time.h>
  232.38 +#include <errno.h>
  232.39 +#include <fcntl.h>
  232.40 +#include <sys\stat.h>
  232.41 +#include <sys\timeb.h>
  232.42 +#include <sys\nfs_time.h>
  232.43 +#include <sys\tk_types.h>
  232.44 +#include <sys\socket.h>
  232.45 +#include <netinet\in.h>
  232.46 +#include <tk_errno.h>
  232.47 +#include <sys\uio.h>
  232.48 +#include <netdb.h>
  232.49 +#include "misc.h"
  232.50 +
  232.51 +
  232.52 +#include "fs_dos.c"
  232.53 +#include "ftl_dos.c"
  232.54 +#include "nl_dos.c"
  232.55 +#include "env_dos.c"
  232.56 +#undef write
  232.57 +#include "tcp_dos.c"
  232.58 +
  232.59 +
  232.60 +/* Return my local host name
  232.61 + * Returns: my local host name
  232.62 + */
  232.63 +
  232.64 +char *mylocalhost (void)
  232.65 +{
  232.66 +  if (!myLocalHost) {		/* known yet? */
  232.67 +    char *s,tmp[MAILTMPLEN];
  232.68 +    unsigned long myip;
  232.69 +				/* see if known host name */
  232.70 +    if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp;
  232.71 +				/* no, try host address */
  232.72 +    else if (get_myipaddr ((char *) &myip))
  232.73 +      sprintf (s = tmp,"[%s]",inet_ntoa (myip));
  232.74 +    else s = "random-pc";	/* say what? */
  232.75 +    myLocalHost = cpystr (s);	/* record for subsequent use */
  232.76 +  }
  232.77 +  return myLocalHost;
  232.78 +}
  232.79 +
  232.80 +
  232.81 +/* Look up host address
  232.82 + * Accepts: pointer to pointer to host name
  232.83 + *	    socket address block
  232.84 + * Returns: non-zero with host address in socket, official host name in host;
  232.85 + *	    else NIL
  232.86 + */
  232.87 +
  232.88 +long lookuphost (char **host,struct sockaddr_in *sin)
  232.89 +{
  232.90 +  long ret = -1;
  232.91 +  char tmp[MAILTMPLEN];
  232.92 +  struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
  232.93 +  if (!hn) return NIL;		/* got a host name? */
  232.94 +  *host = cpystr (hn->h_name);	/* set official name */
  232.95 +				/* copy host addresses */
  232.96 +  memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
  232.97 +  return T;
  232.98 +}
   233.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   233.2 +++ b/src/osdep/dos/os_dnf.h	Mon Sep 14 15:17:45 2009 +0900
   233.3 @@ -0,0 +1,44 @@
   233.4 +/* ========================================================================
   233.5 + * Copyright 1988-2006 University of Washington
   233.6 + *
   233.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   233.8 + * you may not use this file except in compliance with the License.
   233.9 + * You may obtain a copy of the License at
  233.10 + *
  233.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  233.12 + *
  233.13 + * 
  233.14 + * ========================================================================
  233.15 + */
  233.16 +
  233.17 +/*
  233.18 + * Program:	Operating-system dependent routines -- DOS (PC-NFS) version
  233.19 + *
  233.20 + * Author:	Mike Seibel from Novell version by Mark Crispin
  233.21 + *		Networks and Distributed Computing
  233.22 + *		Computing & Communications
  233.23 + *		University of Washington
  233.24 + *		Administration Building, AG-44
  233.25 + *		Seattle, WA  98195
  233.26 + *		Internet: MikeS@CAC.Washington.EDU
  233.27 + *
  233.28 + * Date:	11 May 1989
  233.29 + * Last Edited:	30 August 2006
  233.30 + */
  233.31 +
  233.32 +#define INADEQUATE_MEMORY
  233.33 +
  233.34 +#include <tklib.h>
  233.35 +#include <stdlib.h>
  233.36 +#include <stdio.h>
  233.37 +#include <string.h>
  233.38 +#include <sys\types.h>
  233.39 +#include <io.h>
  233.40 +
  233.41 +#define gethostid clock
  233.42 +
  233.43 +#include "env_dos.h"
  233.44 +#include "fs.h"
  233.45 +#include "ftl.h"
  233.46 +#include "nl.h"
  233.47 +#include "tcp.h"
   234.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   234.2 +++ b/src/osdep/dos/os_dnv.c	Mon Sep 14 15:17:45 2009 +0900
   234.3 @@ -0,0 +1,95 @@
   234.4 +/* ========================================================================
   234.5 + * Copyright 1988-2006 University of Washington
   234.6 + *
   234.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   234.8 + * you may not use this file except in compliance with the License.
   234.9 + * You may obtain a copy of the License at
  234.10 + *
  234.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  234.12 + *
  234.13 + * 
  234.14 + * ========================================================================
  234.15 + */
  234.16 +
  234.17 +/*
  234.18 + * Program:	Operating-system dependent routines -- MS-DOS (Novell) version
  234.19 + *
  234.20 + * Author:	Mark Crispin
  234.21 + *		Networks and Distributed Computing
  234.22 + *		Computing & Communications
  234.23 + *		University of Washington
  234.24 + *		Administration Building, AG-44
  234.25 + *		Seattle, WA  98195
  234.26 + *		Internet: MRC@CAC.Washington.EDU
  234.27 + *
  234.28 + * Date:	11 April 1989
  234.29 + * Last Edited:	30 August 2006
  234.30 + */
  234.31 +
  234.32 +/* Private function prototypes */
  234.33 +
  234.34 +#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
  234.35 +#include "mail.h"
  234.36 +#include "osdep.h"
  234.37 +#include <time.h>
  234.38 +#include <errno.h>
  234.39 +#include <fcntl.h>
  234.40 +#include <sys\stat.h>
  234.41 +#include <sys\timeb.h>
  234.42 +#include <sys\socket.h>
  234.43 +#include <netinet\in.h>
  234.44 +#include <netdb.h>
  234.45 +#include "misc.h"
  234.46 +
  234.47 +
  234.48 +#include "fs_dos.c"
  234.49 +#include "ftl_dos.c"
  234.50 +#include "nl_dos.c"
  234.51 +#include "env_dos.c"
  234.52 +#undef write
  234.53 +#define read soread
  234.54 +#define write sowrite
  234.55 +#define close soclose 
  234.56 +#include "tcp_dos.c"
  234.57 +
  234.58 +
  234.59 +/* Return my local host name
  234.60 + * Returns: my local host name
  234.61 + */
  234.62 +
  234.63 +char *mylocalhost (void)
  234.64 +{
  234.65 +  if (!myLocalHost) {		/* known yet? */
  234.66 +    char *s,tmp[MAILTMPLEN];
  234.67 +    struct hostent *he;
  234.68 +    struct in_addr in;
  234.69 +				/* could we get local id? */
  234.70 +    if ((in.s_addr = getmyipaddr ()) != -1) {
  234.71 +      if (he = gethostbyaddr ((char *) &in.s_addr,4,PF_INET)) s = he->h_name;
  234.72 +      else sprintf (s = tmp,"[%s]",inet_ntoa (in));
  234.73 +    }
  234.74 +    else s = "random-pc";	/* say what? */
  234.75 +    myLocalHost = cpystr (s);	/* record for subsequent use */
  234.76 +  }
  234.77 +  return myLocalHost;
  234.78 +}
  234.79 +
  234.80 +
  234.81 +/* Look up host address
  234.82 + * Accepts: pointer to pointer to host name
  234.83 + *	    socket address block
  234.84 + * Returns: non-zero with host address in socket, official host name in host;
  234.85 + *	    else NIL
  234.86 + */
  234.87 +
  234.88 +long lookuphost (char **host,struct sockaddr_in *sin)
  234.89 +{
  234.90 +  char *s = *host;		/* in case of error */
  234.91 +  sin->sin_addr.s_addr = rhost (host);
  234.92 +  if (sin->sin_addr.s_addr == -1) {
  234.93 +    *host = s;			/* error, restore old host name */
  234.94 +    return NIL;
  234.95 +  }
  234.96 +  *host = cpystr (*host);	/* make permanent copy of name */
  234.97 +  return T;			/* success */
  234.98 +}
   235.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   235.2 +++ b/src/osdep/dos/os_dnv.h	Mon Sep 14 15:17:45 2009 +0900
   235.3 @@ -0,0 +1,43 @@
   235.4 +/* ========================================================================
   235.5 + * Copyright 1988-2006 University of Washington
   235.6 + *
   235.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   235.8 + * you may not use this file except in compliance with the License.
   235.9 + * You may obtain a copy of the License at
  235.10 + *
  235.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  235.12 + *
  235.13 + * 
  235.14 + * ========================================================================
  235.15 + */
  235.16 +
  235.17 +/*
  235.18 + * Program:	Operating-system dependent routines -- DOS (B&W/Novell) version
  235.19 + *
  235.20 + * Author:	Mark Crispin
  235.21 + *		Networks and Distributed Computing
  235.22 + *		Computing & Communications
  235.23 + *		University of Washington
  235.24 + *		Administration Building, AG-44
  235.25 + *		Seattle, WA  98195
  235.26 + *		Internet: MRC@CAC.Washington.EDU
  235.27 + *
  235.28 + * Date:	11 May 1989
  235.29 + * Last Edited:	30 August 2006
  235.30 + */
  235.31 +
  235.32 +#define INADEQUATE_MEMORY
  235.33 +
  235.34 +#include <stdlib.h>
  235.35 +#include <stdio.h>
  235.36 +#include <string.h>
  235.37 +#include <sys\types.h>
  235.38 +#include <io.h>
  235.39 +
  235.40 +#define gethostid clock
  235.41 +
  235.42 +#include "env_dos.h"
  235.43 +#include "fs.h"
  235.44 +#include "ftl.h"
  235.45 +#include "nl.h"
  235.46 +#include "tcp.h"
   236.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   236.2 +++ b/src/osdep/dos/os_dpc.c	Mon Sep 14 15:17:45 2009 +0900
   236.3 @@ -0,0 +1,102 @@
   236.4 +/* ========================================================================
   236.5 + * Copyright 1988-2006 University of Washington
   236.6 + *
   236.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   236.8 + * you may not use this file except in compliance with the License.
   236.9 + * You may obtain a copy of the License at
  236.10 + *
  236.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  236.12 + *
  236.13 + * 
  236.14 + * ========================================================================
  236.15 + */
  236.16 +
  236.17 +/*
  236.18 + * Program:	Operating-system dependent routines -- MS-DOS (PC/TCP) version
  236.19 + *
  236.20 + * Author:	Mark Crispin
  236.21 + *		Networks and Distributed Computing
  236.22 + *		Computing & Communications
  236.23 + *		University of Washington
  236.24 + *		Administration Building, AG-44
  236.25 + *		Seattle, WA  98195
  236.26 + *		Internet: MRC@CAC.Washington.EDU
  236.27 + *
  236.28 + * Date:	11 April 1989
  236.29 + * Last Edited:	30 August 2006
  236.30 + */
  236.31 +
  236.32 +/* Private function prototypes */
  236.33 +
  236.34 +#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
  236.35 +#include "mail.h"
  236.36 +#include "osdep.h"
  236.37 +#include <time.h>
  236.38 +#include <errno.h>
  236.39 +#include <fcntl.h>
  236.40 +#include <sys\stat.h>
  236.41 +#include <sys\timeb.h>
  236.42 +#include <4bsddefs.h>
  236.43 +#include <sys\socket.h>
  236.44 +#include <errno.h>
  236.45 +#include <arpa\inet.h>
  236.46 +#include <netinet\in.h>
  236.47 +#include <netdb.h>
  236.48 +#include "misc.h"
  236.49 +
  236.50 +
  236.51 +#include "fs_dos.c"
  236.52 +#include "ftl_dos.c"
  236.53 +#include "nl_dos.c"
  236.54 +#include "env_dos.c"
  236.55 +#undef write
  236.56 +#include "tcp_dos.c"
  236.57 +
  236.58 +
  236.59 +/* Return my local host name
  236.60 + * Returns: my local host name
  236.61 + */
  236.62 +
  236.63 +char *mylocalhost (void)
  236.64 +{
  236.65 +  if (!myLocalHost) {		/* known yet */
  236.66 +    char *s,tmp[MAILTMPLEN];
  236.67 +    long myip;
  236.68 +				/* see if known host name */
  236.69 +    if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp;
  236.70 +				/* no, try IP address */
  236.71 +    else if (myip = gethostid ()) {
  236.72 +      struct in_addr in;
  236.73 +      in.s_addr = myip;
  236.74 +      sprintf (s = tmp,"[%s]",inet_ntoa (in));
  236.75 +    }
  236.76 +				/* older kernel, look harder. */
  236.77 +    else if (getconf ("ifcust","ip-address",tmp+1,MAILTMPLEN-2)) {
  236.78 +      *(s = tmp) = '[';		/* wrap the brackets around it */
  236.79 +      strcat (tmp,"]");
  236.80 +    }
  236.81 +    else s = "random-pc";	/* say what? */
  236.82 +    myLocalHost = cpystr (s);	/* record for subsequent use */
  236.83 +  }
  236.84 +  return myLocalHost;
  236.85 +}
  236.86 +
  236.87 +
  236.88 +/* Look up host address
  236.89 + * Accepts: pointer to pointer to host name
  236.90 + *	    socket address block
  236.91 + * Returns: non-zero with host address in socket, official host name in host;
  236.92 + *	    else NIL
  236.93 + */
  236.94 +
  236.95 +long lookuphost (char **host,struct sockaddr_in *sin)
  236.96 +{
  236.97 +  long ret = -1;
  236.98 +  char tmp[MAILTMPLEN];
  236.99 +  struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
 236.100 +  if (!hn) return NIL;		/* got a host name? */
 236.101 +  *host = cpystr (hn->h_name);	/* set official name */
 236.102 +				/* copy host addresses */
 236.103 +  memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
 236.104 +  return T;
 236.105 +}
   237.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   237.2 +++ b/src/osdep/dos/os_dpc.h	Mon Sep 14 15:17:45 2009 +0900
   237.3 @@ -0,0 +1,41 @@
   237.4 +/* ========================================================================
   237.5 + * Copyright 1988-2006 University of Washington
   237.6 + *
   237.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   237.8 + * you may not use this file except in compliance with the License.
   237.9 + * You may obtain a copy of the License at
  237.10 + *
  237.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  237.12 + *
  237.13 + * 
  237.14 + * ========================================================================
  237.15 + */
  237.16 +
  237.17 +/*
  237.18 + * Program:	Operating-system dependent routines -- DOS (PC/TCP) version
  237.19 + *
  237.20 + * Author:	Mark Crispin
  237.21 + *		Networks and Distributed Computing
  237.22 + *		Computing & Communications
  237.23 + *		University of Washington
  237.24 + *		Administration Building, AG-44
  237.25 + *		Seattle, WA  98195
  237.26 + *		Internet: MRC@CAC.Washington.EDU
  237.27 + *
  237.28 + * Date:	11 May 1989
  237.29 + * Last Edited:	30 August 2006
  237.30 + */
  237.31 +
  237.32 +#define INADEQUATE_MEMORY
  237.33 +
  237.34 +#include <stdlib.h>
  237.35 +#include <stdio.h>
  237.36 +#include <string.h>
  237.37 +#include <sys\types.h>
  237.38 +#include <io.h>
  237.39 +
  237.40 +#include "env_dos.h"
  237.41 +#include "fs.h"
  237.42 +#include "ftl.h"
  237.43 +#include "nl.h"
  237.44 +#include "tcp.h"
   238.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   238.2 +++ b/src/osdep/dos/os_dwa.c	Mon Sep 14 15:17:45 2009 +0900
   238.3 @@ -0,0 +1,72 @@
   238.4 +/* ========================================================================
   238.5 + * Copyright 1988-2006 University of Washington
   238.6 + *
   238.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   238.8 + * you may not use this file except in compliance with the License.
   238.9 + * You may obtain a copy of the License at
  238.10 + *
  238.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  238.12 + *
  238.13 + * 
  238.14 + * ========================================================================
  238.15 + */
  238.16 +
  238.17 +/*
  238.18 + * Program:	Operating-system dependent routines -- DOS (Waterloo) version
  238.19 + *
  238.20 + * Author:	Mark Crispin
  238.21 + *		Networks and Distributed Computing
  238.22 + *		Computing & Communications
  238.23 + *		University of Washington
  238.24 + *		Administration Building, AG-44
  238.25 + *		Seattle, WA  98195
  238.26 + *		Internet: MRC@CAC.Washington.EDU
  238.27 + *
  238.28 + * Date:	11 April 1989
  238.29 + * Last Edited:	30 August 2006
  238.30 + */
  238.31 +
  238.32 +#include <tcp.h>		/* must be before TCPSTREAM definition */
  238.33 +#include "tcp_dwa.h"		/* must be before osdep include our tcp.h */
  238.34 +#include "mail.h"
  238.35 +#include "osdep.h"
  238.36 +#include <time.h>
  238.37 +#include <errno.h>
  238.38 +#include <fcntl.h>
  238.39 +#include <sys\stat.h>
  238.40 +#include <sys\timeb.h>
  238.41 +#include "misc.h"
  238.42 +
  238.43 +/* Undo compatibility definition */
  238.44 +
  238.45 +#undef tcp_open
  238.46 +
  238.47 +#include "fs_dos.c"
  238.48 +#include "ftl_dos.c"
  238.49 +#include "nl_dos.c"
  238.50 +#include "env_dos.c"
  238.51 +#include "tcp_dwa.c"
  238.52 +
  238.53 +
  238.54 +/* Return my local host name
  238.55 + * Returns: my local host name
  238.56 + */
  238.57 +
  238.58 +char *mylocalhost (void)
  238.59 +{
  238.60 +  if (!myLocalHost) {
  238.61 +    char *s,hname[32],tmp[MAILTMPLEN];
  238.62 +    long myip;
  238.63 +
  238.64 +    if (!sock_initted++) sock_init();
  238.65 +    tcp_cbrk (0x01);		/* turn off ctrl-break catching */
  238.66 +    /*
  238.67 +     * haven't discovered a way to find out the local host's 
  238.68 +     * name with wattcp yet.
  238.69 +     */
  238.70 +    if (myip = gethostid ()) sprintf (s = tmp,"[%s]",inet_ntoa (hname,myip));
  238.71 +    else s = "random-pc";
  238.72 +    myLocalHost = cpystr (s);
  238.73 +  }
  238.74 +  return myLocalHost;
  238.75 +}
   239.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   239.2 +++ b/src/osdep/dos/os_dwa.h	Mon Sep 14 15:17:45 2009 +0900
   239.3 @@ -0,0 +1,43 @@
   239.4 +/* ========================================================================
   239.5 + * Copyright 1988-2006 University of Washington
   239.6 + *
   239.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   239.8 + * you may not use this file except in compliance with the License.
   239.9 + * You may obtain a copy of the License at
  239.10 + *
  239.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  239.12 + *
  239.13 + * 
  239.14 + * ========================================================================
  239.15 + */
  239.16 +
  239.17 +/*
  239.18 + * Program:	Operating-system dependent routines -- DOS (Waterloo) version
  239.19 + *
  239.20 + * Author:	Mark Crispin
  239.21 + *		Networks and Distributed Computing
  239.22 + *		Computing & Communications
  239.23 + *		University of Washington
  239.24 + *		Administration Building, AG-44
  239.25 + *		Seattle, WA  98195
  239.26 + *		Internet: MRC@CAC.Washington.EDU
  239.27 + *
  239.28 + * Date:	11 May 1989
  239.29 + * Last Edited:	30 August 2006
  239.30 + */
  239.31 +
  239.32 +#define INADEQUATE_MEMORY
  239.33 +
  239.34 +#include <stdlib.h>
  239.35 +#include <stdio.h>
  239.36 +#include <string.h>
  239.37 +#include <sys\types.h>
  239.38 +#include <io.h>
  239.39 +
  239.40 +#define tcp_open TCP_open
  239.41 +
  239.42 +#include "env_dos.h"
  239.43 +#include "fs.h"
  239.44 +#include "ftl.h"
  239.45 +#include "nl.h"
  239.46 +#include "tcp.h"
   240.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   240.2 +++ b/src/osdep/dos/os_wsk.c	Mon Sep 14 15:17:45 2009 +0900
   240.3 @@ -0,0 +1,45 @@
   240.4 +/* ========================================================================
   240.5 + * Copyright 1988-2006 University of Washington
   240.6 + *
   240.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   240.8 + * you may not use this file except in compliance with the License.
   240.9 + * You may obtain a copy of the License at
  240.10 + *
  240.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  240.12 + *
  240.13 + * 
  240.14 + * ========================================================================
  240.15 + */
  240.16 +
  240.17 +/*
  240.18 + * Program:	Operating-system dependent routines -- Winsock version
  240.19 + *
  240.20 + * Author:	Mike Seibel from Unix version by Mark Crispin
  240.21 + *		Networks and Distributed Computing
  240.22 + *		Computing & Communications
  240.23 + *		University of Washington
  240.24 + *		Administration Building, AG-44
  240.25 + *		Seattle, WA  98195
  240.26 + *		Internet: MikeS@CAC.Washington.EDU
  240.27 + *
  240.28 + * Date:	11 April 1989
  240.29 + * Last Edited:	30 August 2006
  240.30 + */
  240.31 +
  240.32 +#include "tcp_wsk.h"		/* must be before osdep includes tcp.h */
  240.33 +#undef	ERROR			/* quell conflicting def warning */
  240.34 +#include "mail.h"
  240.35 +#include "osdep.h"
  240.36 +#include <time.h>
  240.37 +#include <errno.h>
  240.38 +#include <fcntl.h>
  240.39 +#include <sys\stat.h>
  240.40 +#include <sys\timeb.h>
  240.41 +#include "misc.h"
  240.42 +
  240.43 +
  240.44 +#include "fs_dos.c"
  240.45 +#include "ftl_dos.c"
  240.46 +#include "nl_dos.c"
  240.47 +#include "env_dos.c"
  240.48 +#include "tcp_wsk.c"
   241.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   241.2 +++ b/src/osdep/dos/os_wsk.h	Mon Sep 14 15:17:45 2009 +0900
   241.3 @@ -0,0 +1,48 @@
   241.4 +/* ========================================================================
   241.5 + * Copyright 1988-2006 University of Washington
   241.6 + *
   241.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   241.8 + * you may not use this file except in compliance with the License.
   241.9 + * You may obtain a copy of the License at
  241.10 + *
  241.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  241.12 + *
  241.13 + * 
  241.14 + * ========================================================================
  241.15 + */
  241.16 +
  241.17 +/*
  241.18 + * Program:	Operating-system dependent routines -- 16-bit Winsock version
  241.19 + *
  241.20 + * Author:	Mike Seibel from Novell version by Mark Crispin
  241.21 + *		Networks and Distributed Computing
  241.22 + *		Computing & Communications
  241.23 + *		University of Washington
  241.24 + *		Administration Building, AG-44
  241.25 + *		Seattle, WA  98195
  241.26 + *		Internet: MikeS@CAC.Washington.EDU
  241.27 + *
  241.28 + * Date:	11 May 1989
  241.29 + * Last Edited:	30 August 2006
  241.30 + */
  241.31 +
  241.32 +#define INADEQUATE_MEMORY
  241.33 +
  241.34 +#include <stdlib.h>
  241.35 +#include <stdio.h>
  241.36 +#include <string.h>
  241.37 +#include <sys\types.h>
  241.38 +#include <io.h>
  241.39 +
  241.40 +#define gethostid clock
  241.41 +#define	WSA_VERSION	((1 << 8) | 1)
  241.42 +
  241.43 +#include "env_dos.h"
  241.44 +#include "fs.h"
  241.45 +#include "ftl.h"
  241.46 +#include "nl.h"
  241.47 +#include "tcp.h"
  241.48 +
  241.49 +
  241.50 +#undef noErr
  241.51 +#undef MAC
   242.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   242.2 +++ b/src/osdep/dos/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   242.3 @@ -0,0 +1,89 @@
   242.4 +/* ========================================================================
   242.5 + * Copyright 1988-2006 University of Washington
   242.6 + *
   242.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   242.8 + * you may not use this file except in compliance with the License.
   242.9 + * You may obtain a copy of the License at
  242.10 + *
  242.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  242.12 + *
  242.13 + * 
  242.14 + * ========================================================================
  242.15 + */
  242.16 +
  242.17 +/*
  242.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  242.19 + *
  242.20 + * Author:	Mark Crispin
  242.21 + *		Networks and Distributed Computing
  242.22 + *		Computing & Communications
  242.23 + *		University of Washington
  242.24 + *		Administration Building, AG-44
  242.25 + *		Seattle, WA  98195
  242.26 + *		Internet: MRC@CAC.Washington.EDU
  242.27 + *
  242.28 + * Date:	15 June 2000
  242.29 + * Last Edited:	30 August 2006
  242.30 + */
  242.31 +
  242.32 +/* Wildcard pattern match
  242.33 + * Accepts: base string
  242.34 + *	    pattern string
  242.35 + *	    delimiter character
  242.36 + * Returns: T if pattern matches base, else NIL
  242.37 + */
  242.38 +
  242.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  242.40 +{
  242.41 +  switch (*pat) {
  242.42 +  case '%':			/* non-recursive */
  242.43 +				/* % at end, OK if no inferiors */
  242.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  242.45 +                                /* scan remainder of string until delimiter */
  242.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  242.47 +    while ((*s != delim) && *s++);
  242.48 +    break;
  242.49 +  case '*':			/* match 0 or more characters */
  242.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  242.51 +				/* scan remainder of string */
  242.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  242.53 +    while (*s++);
  242.54 +    break;
  242.55 +  case '\0':			/* end of pattern */
  242.56 +    return *s ? NIL : T;	/* success if also end of base */
  242.57 +  default:			/* match this character */
  242.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  242.59 +  }
  242.60 +  return NIL;
  242.61 +}
  242.62 +
  242.63 +/* Directory pattern match
  242.64 + * Accepts: base string
  242.65 + *	    pattern string
  242.66 + *	    delimiter character
  242.67 + * Returns: T if base is a matching directory of pattern, else NIL
  242.68 + */
  242.69 +
  242.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  242.71 +{
  242.72 +  switch (*pat) {
  242.73 +  case '%':			/* non-recursive */
  242.74 +    if (!*s) return T;		/* end of base means have a subset match */
  242.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  242.76 +				/* scan remainder of string until delimiter */
  242.77 +    do if (dmatch (s,pat,delim)) return T;
  242.78 +    while ((*s != delim) && *s++);
  242.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  242.80 +    return dmatch (s,pat,delim);/* do new scan */
  242.81 +  case '*':			/* match 0 or more characters */
  242.82 +    return T;			/* unconditional match */
  242.83 +  case '\0':			/* end of pattern */
  242.84 +    break;
  242.85 +  default:			/* match this character */
  242.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  242.87 +				/* end of base, return if at delimiter */
  242.88 +    else if (*pat == delim) return T;
  242.89 +    break;
  242.90 +  }
  242.91 +  return NIL;
  242.92 +}
   243.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   243.2 +++ b/src/osdep/dos/tcp_dos.c	Mon Sep 14 15:17:45 2009 +0900
   243.3 @@ -0,0 +1,434 @@
   243.4 +/* ========================================================================
   243.5 + * Copyright 1988-2008 University of Washington
   243.6 + *
   243.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   243.8 + * you may not use this file except in compliance with the License.
   243.9 + * You may obtain a copy of the License at
  243.10 + *
  243.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  243.12 + *
  243.13 + * 
  243.14 + * ========================================================================
  243.15 + */
  243.16 +
  243.17 +/*
  243.18 + * Program:	MS-DOS TCP/IP routines
  243.19 + *
  243.20 + * Author:	Mark Crispin
  243.21 + *		Networks and Distributed Computing
  243.22 + *		Computing & Communications
  243.23 + *		University of Washington
  243.24 + *		Administration Building, AG-44
  243.25 + *		Seattle, WA  98195
  243.26 + *		Internet: MRC@CAC.Washington.EDU
  243.27 + *
  243.28 + * Date:	11 April 1989
  243.29 + * Last Edited:	13 January 2008
  243.30 + */
  243.31 +
  243.32 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  243.33 +static long ttmo_read = 0;	/* TCP timeouts, in seconds */
  243.34 +static long ttmo_write = 0;
  243.35 +
  243.36 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  243.37 +			       long *contd);
  243.38 +
  243.39 +/* TCP/IP manipulate parameters
  243.40 + * Accepts: function code
  243.41 + *	    function-dependent value
  243.42 + * Returns: function-dependent return value
  243.43 + */
  243.44 +
  243.45 +void *tcp_parameters (long function,void *value)
  243.46 +{
  243.47 +  void *ret = NIL;
  243.48 +  switch ((int) function) {
  243.49 +  case SET_TIMEOUT:
  243.50 +    tmoh = (tcptimeout_t) value;
  243.51 +  case GET_TIMEOUT:
  243.52 +    ret = (void *) tmoh;
  243.53 +    break;
  243.54 +  case SET_READTIMEOUT:
  243.55 +    ttmo_read = (long) value;
  243.56 +  case GET_READTIMEOUT:
  243.57 +    ret = (void *) ttmo_read;
  243.58 +    break;
  243.59 +  case SET_WRITETIMEOUT:
  243.60 +    ttmo_write = (long) value;
  243.61 +  case GET_WRITETIMEOUT:
  243.62 +    ret = (void *) ttmo_write;
  243.63 +    break;
  243.64 +  }
  243.65 +  return ret;
  243.66 +}
  243.67 +
  243.68 +/* TCP/IP open
  243.69 + * Accepts: host name
  243.70 + *	    contact service name
  243.71 + *	    contact port number
  243.72 + * Returns: TCP/IP stream if success else NIL
  243.73 + */
  243.74 +
  243.75 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  243.76 +{
  243.77 +  TCPSTREAM *stream = NIL;
  243.78 +  struct sockaddr_in sin;
  243.79 +  int sock;
  243.80 +  char *s,tmp[MAILTMPLEN];
  243.81 +  port &= 0xffff;		/* erase flags */
  243.82 +  /* The domain literal form is used (rather than simply the dotted decimal
  243.83 +     as with other Unix programs) because it has to be a valid "host name"
  243.84 +     in mailsystem terminology. */
  243.85 +  sin.sin_family = AF_INET;	/* family is always Internet */
  243.86 +				/* look like domain literal? */
  243.87 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  243.88 +    strcpy (tmp,host+1);	/* yes, copy number part */
  243.89 +    tmp[strlen (tmp)-1] = '\0';
  243.90 +    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
  243.91 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
  243.92 +      mm_log (tmp,ERROR);
  243.93 +      return NIL;
  243.94 +    }
  243.95 +  }
  243.96 +				/* look up host name */
  243.97 +  else if (!lookuphost (&host,&sin)) {
  243.98 +    sprintf (tmp,"Host not found: %s",host);
  243.99 +    mm_log (tmp,ERROR);
 243.100 +    return NIL;
 243.101 +  }
 243.102 +
 243.103 +				/* copy port number in network format */
 243.104 +  if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
 243.105 +				/* get a TCP stream */
 243.106 +  if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
 243.107 +    sprintf (tmp,"Unable to create TCP socket (%d)",errno);
 243.108 +    mm_log (tmp,ERROR);
 243.109 +    fs_give ((void **) &host);
 243.110 +    return NIL;
 243.111 +  }
 243.112 +#if 0
 243.113 +  /* needed? */
 243.114 +  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
 243.115 +    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
 243.116 +	     sock,FD_SETSIZE);
 243.117 +    close (sock);
 243.118 +    errno = ENOBUFS;		/* just in case */
 243.119 +    return NIL;
 243.120 +  }
 243.121 +#endif
 243.122 +				/* open connection */
 243.123 +  if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
 243.124 +    switch (errno) {		/* analyze error */
 243.125 +    case ECONNREFUSED:
 243.126 +      s = "Refused";
 243.127 +      break;
 243.128 +    case ENOBUFS:
 243.129 +      s = "Insufficient system resources";
 243.130 +      break;
 243.131 +    case ETIMEDOUT:
 243.132 +      s = "Timed out";
 243.133 +      break;
 243.134 +    default:
 243.135 +      s = "Unknown error";
 243.136 +      break;
 243.137 +    }
 243.138 +    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
 243.139 +    mm_log (tmp,ERROR);
 243.140 +    close (sock);
 243.141 +    fs_give ((void **) &host);
 243.142 +    return NIL;
 243.143 +  }
 243.144 +				/* create TCP/IP stream */
 243.145 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
 243.146 +  stream->host = host;		/* official host name */
 243.147 +  stream->localhost = cpystr (mylocalhost ());
 243.148 +  stream->port = port;		/* port number */
 243.149 +  stream->tcps = sock;		/* init socket */
 243.150 +  stream->ictr = 0;		/* init input counter */
 243.151 +  return stream;		/* return success */
 243.152 +}
 243.153 +  
 243.154 +/* TCP/IP authenticated open
 243.155 + * Accepts: NETMBX specifier
 243.156 + *	    service name
 243.157 + *	    returned user name buffer
 243.158 + * Returns: TCP/IP stream if success else NIL
 243.159 + */
 243.160 +
 243.161 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 243.162 +{
 243.163 +  return NIL;			/* always NIL on DOS */
 243.164 +}
 243.165 +
 243.166 +/* TCP receive line
 243.167 + * Accepts: TCP stream
 243.168 + * Returns: text line string or NIL if failure
 243.169 + */
 243.170 +
 243.171 +char *tcp_getline (TCPSTREAM *stream)
 243.172 +{
 243.173 +  unsigned long n,contd;
 243.174 +  char *ret = tcp_getline_work (stream,&n,&contd);
 243.175 +  if (ret && contd) {		/* got a line needing continuation? */
 243.176 +    STRINGLIST *stl = mail_newstringlist ();
 243.177 +    STRINGLIST *stc = stl;
 243.178 +    do {			/* collect additional lines */
 243.179 +      stc->text.data = (unsigned char *) ret;
 243.180 +      stc->text.size = n;
 243.181 +      stc = stc->next = mail_newstringlist ();
 243.182 +      ret = tcp_getline_work (stream,&n,&contd);
 243.183 +    } while (ret && contd);
 243.184 +    if (ret) {			/* stash final part of line on list */
 243.185 +      stc->text.data = (unsigned char *) ret;
 243.186 +      stc->text.size = n;
 243.187 +				/* determine how large a buffer we need */
 243.188 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 243.189 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 243.190 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 243.191 +	memcpy (ret + n,stc->text.data,stc->text.size);
 243.192 +      ret[n] = '\0';
 243.193 +    }
 243.194 +    mail_free_stringlist (&stl);/* either way, done with list */
 243.195 +  }
 243.196 +  return ret;
 243.197 +}
 243.198 +
 243.199 +/* TCP receive line or partial line
 243.200 + * Accepts: TCP stream
 243.201 + *	    pointer to return size
 243.202 + *	    pointer to return continuation flag
 243.203 + * Returns: text line string, size and continuation flag, or NIL if failure
 243.204 + */
 243.205 +
 243.206 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 243.207 +			       long *contd)
 243.208 +{
 243.209 +  unsigned long n;
 243.210 +  char *s,*ret,c,d;
 243.211 +  *contd = NIL;			/* assume no continuation */
 243.212 +				/* make sure have data */
 243.213 +  if (!tcp_getdata (stream)) return NIL;
 243.214 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 243.215 +    d = *stream->iptr++;	/* slurp another character */
 243.216 +    if ((c == '\015') && (d == '\012')) {
 243.217 +      ret = (char *) fs_get (n--);
 243.218 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 243.219 +      ret[n] = '\0';		/* tie off string with null */
 243.220 +      return ret;
 243.221 +    }
 243.222 +  }
 243.223 +				/* copy partial string from buffer */
 243.224 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 243.225 +				/* get more data from the net */
 243.226 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 243.227 +				/* special case of newline broken by buffer */
 243.228 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 243.229 +    stream->iptr++;		/* eat the line feed */
 243.230 +    stream->ictr--;
 243.231 +    ret[*size = --n] = '\0';	/* tie off string with null */
 243.232 +  }
 243.233 +  else *contd = LONGT;		/* continuation needed */
 243.234 +  return ret;
 243.235 +}
 243.236 +
 243.237 +/* TCP/IP receive buffer
 243.238 + * Accepts: TCP/IP stream
 243.239 + *	    size in bytes
 243.240 + *	    buffer to read into
 243.241 + * Returns: T if success, NIL otherwise
 243.242 + */
 243.243 +
 243.244 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 243.245 +{
 243.246 +  unsigned long n;
 243.247 +  char *bufptr = buffer;
 243.248 +  while (size > 0) {		/* until request satisfied */
 243.249 +    if (!tcp_getdata (stream)) return NIL;
 243.250 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 243.251 +				/* do the copy */
 243.252 +    memcpy (bufptr,stream->iptr,n);
 243.253 +    bufptr += n;		/* update pointer */
 243.254 +    stream->iptr +=n;
 243.255 +    size -= n;			/* update # of bytes to do */
 243.256 +    stream->ictr -=n;
 243.257 +  }
 243.258 +  bufptr[0] = '\0';		/* tie off string */
 243.259 +  return T;
 243.260 +}
 243.261 +
 243.262 +/* TCP/IP receive data
 243.263 + * Accepts: TCP/IP stream
 243.264 + * Returns: T if success, NIL otherwise
 243.265 + */
 243.266 +
 243.267 +long tcp_getdata (TCPSTREAM *stream)
 243.268 +{
 243.269 +  int i;
 243.270 +  fd_set fds,efds;
 243.271 +  struct timeval tmo;
 243.272 +  time_t t = time (0);
 243.273 +  if (stream->tcps < 0) return NIL;
 243.274 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 243.275 +    time_t tl = time (0);	/* start of request */
 243.276 +    tmo.tv_sec = ttmo_read;	/* read timeout */
 243.277 +    tmo.tv_usec = 0;
 243.278 +    FD_ZERO (&fds);		/* initialize selection vector */
 243.279 +    FD_ZERO (&efds);		/* handle errors too */
 243.280 +    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
 243.281 +    FD_SET(stream->tcps,&efds);/* set bit in error selection vector */
 243.282 +    errno = NIL;		/* block and read */
 243.283 +    while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0)
 243.284 +	   && (errno == EINTR));
 243.285 +    if (!i) {			/* timeout? */
 243.286 +      time_t tc = time (0);
 243.287 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
 243.288 +      else return tcp_abort (stream);
 243.289 +    }
 243.290 +    else if (i < 0) return tcp_abort (stream);
 243.291 +    while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
 243.292 +	   (errno == EINTR));
 243.293 +    if (i < 1) return tcp_abort (stream);
 243.294 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 243.295 +    stream->ictr = i;		/* set new byte count */
 243.296 +  }
 243.297 +  return T;
 243.298 +}
 243.299 +
 243.300 +/* TCP/IP send string as record
 243.301 + * Accepts: TCP/IP stream
 243.302 + *	    string pointer
 243.303 + * Returns: T if success else NIL
 243.304 + */
 243.305 +
 243.306 +long tcp_soutr (TCPSTREAM *stream,char *string)
 243.307 +{
 243.308 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 243.309 +}
 243.310 +
 243.311 +
 243.312 +/* TCP/IP send string
 243.313 + * Accepts: TCP/IP stream
 243.314 + *	    string pointer
 243.315 + *	    byte count
 243.316 + * Returns: T if success else NIL
 243.317 + */
 243.318 +
 243.319 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 243.320 +{
 243.321 +  int i;
 243.322 +  fd_set fds;
 243.323 +  struct timeval tmo;
 243.324 +  time_t t = time (0);
 243.325 +  if (stream->tcps < 0) return NIL;
 243.326 +  while (size > 0) {		/* until request satisfied */
 243.327 +    time_t tl = time (0);	/* start of request */
 243.328 +    tmo.tv_sec = ttmo_write;	/* write timeout */
 243.329 +    tmo.tv_usec = 0;
 243.330 +    FD_ZERO (&fds);		/* initialize selection vector */
 243.331 +    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
 243.332 +    errno = NIL;		/* block and write */
 243.333 +    while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
 243.334 +	   && (errno == EINTR));
 243.335 +    if (!i) {			/* timeout? */
 243.336 +      time_t tc = time (0);
 243.337 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
 243.338 +      else return tcp_abort (stream);
 243.339 +    }
 243.340 +    else if (i < 0) return tcp_abort (stream);
 243.341 +    while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR));
 243.342 +    if (i < 0) return tcp_abort (stream);
 243.343 +    size -= i;			/* how much we sent */
 243.344 +    string += i;
 243.345 +  }
 243.346 +  return T;			/* all done */
 243.347 +}
 243.348 +
 243.349 +/* TCP/IP close
 243.350 + * Accepts: TCP/IP stream
 243.351 + */
 243.352 +
 243.353 +void tcp_close (TCPSTREAM *stream)
 243.354 +{
 243.355 +  tcp_abort (stream);		/* nuke the socket */
 243.356 +				/* flush host names */
 243.357 +  fs_give ((void **) &stream->host);
 243.358 +  fs_give ((void **) &stream->localhost);
 243.359 +  fs_give ((void **) &stream);	/* flush the stream */
 243.360 +}
 243.361 +
 243.362 +
 243.363 +/* TCP/IP abort stream
 243.364 + * Accepts: TCP/IP stream
 243.365 + * Returns: NIL always
 243.366 + */
 243.367 +
 243.368 +long tcp_abort (TCPSTREAM *stream)
 243.369 +{
 243.370 +  if (stream->tcps >= 0) close (stream->tcps);
 243.371 +  stream->tcps = -1;
 243.372 +  return NIL;
 243.373 +}
 243.374 +
 243.375 +/* TCP/IP get host name
 243.376 + * Accepts: TCP/IP stream
 243.377 + * Returns: host name for this stream
 243.378 + */
 243.379 +
 243.380 +char *tcp_host (TCPSTREAM *stream)
 243.381 +{
 243.382 +  return stream->host;		/* return host name */
 243.383 +}
 243.384 +
 243.385 +
 243.386 +/* TCP/IP get remote host name
 243.387 + * Accepts: TCP/IP stream
 243.388 + * Returns: host name for this stream
 243.389 + */
 243.390 +
 243.391 +char *tcp_remotehost (TCPSTREAM *stream)
 243.392 +{
 243.393 +  return stream->host;		/* all we can do for now */
 243.394 +}
 243.395 +
 243.396 +
 243.397 +/* TCP/IP return port for this stream
 243.398 + * Accepts: TCP/IP stream
 243.399 + * Returns: port number for this stream
 243.400 + */
 243.401 +
 243.402 +unsigned long tcp_port (TCPSTREAM *stream)
 243.403 +{
 243.404 +  return stream->port;		/* return port number */
 243.405 +}
 243.406 +
 243.407 +
 243.408 +/* TCP/IP get local host name
 243.409 + * Accepts: TCP/IP stream
 243.410 + * Returns: local host name
 243.411 + */
 243.412 +
 243.413 +char *tcp_localhost (TCPSTREAM *stream)
 243.414 +{
 243.415 +  return stream->localhost;	/* return local host name */
 243.416 +}
 243.417 +
 243.418 +
 243.419 +/* TCP/IP return canonical form of host name
 243.420 + * Accepts: host name
 243.421 + * Returns: canonical form of host name
 243.422 + */
 243.423 +
 243.424 +char *tcp_canonical (char *name)
 243.425 +{
 243.426 +  return name;
 243.427 +}
 243.428 +
 243.429 +
 243.430 +/* TCP/IP get client host name (server calls only)
 243.431 + * Returns: client host name
 243.432 + */
 243.433 +
 243.434 +char *tcp_clienthost ()
 243.435 +{
 243.436 +  return "UNKNOWN";
 243.437 +}
   244.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   244.2 +++ b/src/osdep/dos/tcp_dos.h	Mon Sep 14 15:17:45 2009 +0900
   244.3 @@ -0,0 +1,51 @@
   244.4 +/* ========================================================================
   244.5 + * Copyright 1988-2006 University of Washington
   244.6 + *
   244.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   244.8 + * you may not use this file except in compliance with the License.
   244.9 + * You may obtain a copy of the License at
  244.10 + *
  244.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  244.12 + *
  244.13 + * 
  244.14 + * ========================================================================
  244.15 + */
  244.16 +
  244.17 +/*
  244.18 + * Program:	OS2 routines
  244.19 + *
  244.20 + * Author:	Mark Crispin
  244.21 + *		Networks and Distributed Computing
  244.22 + *		Computing & Communications
  244.23 + *		University of Washington
  244.24 + *		Administration Building, AG-44
  244.25 + *		Seattle, WA  98195
  244.26 + *		Internet: MRC@CAC.Washington.EDU
  244.27 + *
  244.28 + * Date:	11 April 1989
  244.29 + * Last Edited:	30 August 2006
  244.30 + */
  244.31 +
  244.32 +/* TCP input buffer -- must be large enough to prevent overflow */
  244.33 +
  244.34 +#define BUFLEN 8192
  244.35 +
  244.36 +
  244.37 +/* TCP I/O stream (must be before osdep.h is included) */
  244.38 +
  244.39 +#define TCPSTREAM struct tcp_stream
  244.40 +TCPSTREAM {
  244.41 +  char *host;			/* host name */
  244.42 +  unsigned long port;		/* port number */
  244.43 +  char *localhost;		/* local host name */
  244.44 +  int tcps;			/* tcp socket */
  244.45 +  long ictr;			/* input counter */
  244.46 +  char *iptr;			/* input pointer */
  244.47 +  char ibuf[BUFLEN];		/* input buffer */
  244.48 +};
  244.49 +
  244.50 +
  244.51 +/* Local function prototypes */
  244.52 +
  244.53 +long lookuphost (char **host,struct sockaddr_in *sin);
  244.54 +long tcp_abort (TCPSTREAM *stream);
   245.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   245.2 +++ b/src/osdep/dos/tcp_dwa.c	Mon Sep 14 15:17:45 2009 +0900
   245.3 @@ -0,0 +1,344 @@
   245.4 +/* ========================================================================
   245.5 + * Copyright 1988-2008 University of Washington
   245.6 + *
   245.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   245.8 + * you may not use this file except in compliance with the License.
   245.9 + * You may obtain a copy of the License at
  245.10 + *
  245.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  245.12 + *
  245.13 + * 
  245.14 + * ========================================================================
  245.15 + */
  245.16 +
  245.17 +/*
  245.18 + * Program:	Waterloo DOS TCP/IP routines
  245.19 + *
  245.20 + * Author:	Mark Crispin
  245.21 + *		Networks and Distributed Computing
  245.22 + *		Computing & Communications
  245.23 + *		University of Washington
  245.24 + *		Administration Building, AG-44
  245.25 + *		Seattle, WA  98195
  245.26 + *		Internet: MRC@CAC.Washington.EDU
  245.27 + *
  245.28 + * Date:	11 April 1989
  245.29 + * Last Edited:	13 January 2008
  245.30 + */
  245.31 +
  245.32 +
  245.33 +/* Global data */
  245.34 +
  245.35 +short sock_initted = 0;		/* global so others using net can see it */
  245.36 +
  245.37 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  245.38 +			       long *contd);
  245.39 +
  245.40 +/* TCP/IP manipulate parameters
  245.41 + * Accepts: function code
  245.42 + *	    function-dependent value
  245.43 + * Returns: function-dependent return value
  245.44 + */
  245.45 +
  245.46 +void *tcp_parameters (long function,void *value)
  245.47 +{
  245.48 +  return NIL;
  245.49 +}
  245.50 +
  245.51 +/* TCP/IP open
  245.52 + * Accepts: host name
  245.53 + *	    contact service name
  245.54 + *	    contact port number
  245.55 + * Returns: TCP/IP stream if success else NIL
  245.56 + */
  245.57 +
  245.58 +TCPSTREAM *TCP_open (char *host,char *service,unsigned long port)
  245.59 +{
  245.60 +  TCPSTREAM *stream = NIL;
  245.61 +  tcp_Socket *sock;
  245.62 +  char *s,tmp[MAILTMPLEN];
  245.63 +  unsigned long adr,i,j,k,l;
  245.64 +  port &= 0xffff;		/* erase flags */
  245.65 +				/* initialize if first time here */
  245.66 +  if (!sock_initted++) sock_init();
  245.67 +  /* The domain literal form is used (rather than simply the dotted decimal
  245.68 +     as with other Unix programs) because it has to be a valid "host name"
  245.69 +     in mailsystem terminology. */
  245.70 +				/* look like domain literal? */
  245.71 +  if (host[0] == '[' && host[strlen (host)-1] == ']') {
  245.72 +    if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
  245.73 +	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
  245.74 +	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
  245.75 +	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s)
  245.76 +      adr = (i << 24) + (j << 16) + (k << 8) + l;
  245.77 +    else {
  245.78 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
  245.79 +      mm_log (tmp,ERROR);
  245.80 +      return NIL;
  245.81 +    }
  245.82 +  }
  245.83 +  else {			/* lookup host name */
  245.84 +    if (!(adr = resolve (host))) {
  245.85 +      sprintf (tmp,"Host not found: %s",host);
  245.86 +      mm_log (tmp,ERROR);
  245.87 +      return NIL;
  245.88 +    }
  245.89 +  }
  245.90 +
  245.91 +				/* OK to instantiate socket now */
  245.92 +  sock = (tcp_Socket *) fs_get (sizeof (tcp_Socket));
  245.93 +				/* open connection */
  245.94 +  if (!tcp_open (sock,(word) 0,adr,(word) port,NULL)) {
  245.95 +    sprintf (tmp,"Can't connect to %.80s,%ld",host,port);
  245.96 +    mm_log (tmp,ERROR);
  245.97 +    fs_give ((void **) &sock);
  245.98 +    return NIL;
  245.99 +  }
 245.100 +				/* create TCP/IP stream */
 245.101 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
 245.102 +  stream->host = cpystr (host);	/* official host name */
 245.103 +  stream->localhost = cpystr (mylocalhost ());
 245.104 +  stream->port = port;		/* port number */
 245.105 +  stream->tcps = sock;		/* init socket */
 245.106 +  stream->ictr = 0;		/* init input counter */
 245.107 +  return stream;		/* return success */
 245.108 +}
 245.109 +  
 245.110 +/* TCP/IP authenticated open
 245.111 + * Accepts: NETMBX specifier
 245.112 + *	    service name
 245.113 + *	    returned user name buffer
 245.114 + * Returns: TCP/IP stream if success else NIL
 245.115 + */
 245.116 +
 245.117 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 245.118 +{
 245.119 +  return NIL;			/* always NIL on DOS */
 245.120 +}
 245.121 +
 245.122 +/* TCP receive line
 245.123 + * Accepts: TCP stream
 245.124 + * Returns: text line string or NIL if failure
 245.125 + */
 245.126 +
 245.127 +char *tcp_getline (TCPSTREAM *stream)
 245.128 +{
 245.129 +  unsigned long n,contd;
 245.130 +  char *ret = tcp_getline_work (stream,&n,&contd);
 245.131 +  if (ret && contd) {		/* got a line needing continuation? */
 245.132 +    STRINGLIST *stl = mail_newstringlist ();
 245.133 +    STRINGLIST *stc = stl;
 245.134 +    do {			/* collect additional lines */
 245.135 +      stc->text.data = (unsigned char *) ret;
 245.136 +      stc->text.size = n;
 245.137 +      stc = stc->next = mail_newstringlist ();
 245.138 +      ret = tcp_getline_work (stream,&n,&contd);
 245.139 +    } while (ret && contd);
 245.140 +    if (ret) {			/* stash final part of line on list */
 245.141 +      stc->text.data = (unsigned char *) ret;
 245.142 +      stc->text.size = n;
 245.143 +				/* determine how large a buffer we need */
 245.144 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 245.145 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 245.146 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 245.147 +	memcpy (ret + n,stc->text.data,stc->text.size);
 245.148 +      ret[n] = '\0';
 245.149 +    }
 245.150 +    mail_free_stringlist (&stl);/* either way, done with list */
 245.151 +  }
 245.152 +  return ret;
 245.153 +}
 245.154 +
 245.155 +/* TCP receive line or partial line
 245.156 + * Accepts: TCP stream
 245.157 + *	    pointer to return size
 245.158 + *	    pointer to return continuation flag
 245.159 + * Returns: text line string, size and continuation flag, or NIL if failure
 245.160 + */
 245.161 +
 245.162 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 245.163 +			       long *contd)
 245.164 +{
 245.165 +  unsigned long n;
 245.166 +  char *s,*ret,c,d;
 245.167 +  *contd = NIL;			/* assume no continuation */
 245.168 +				/* make sure have data */
 245.169 +  if (!tcp_getdata (stream)) return NIL;
 245.170 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 245.171 +    d = *stream->iptr++;	/* slurp another character */
 245.172 +    if ((c == '\015') && (d == '\012')) {
 245.173 +      ret = (char *) fs_get (n--);
 245.174 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 245.175 +      ret[n] = '\0';		/* tie off string with null */
 245.176 +      return ret;
 245.177 +    }
 245.178 +  }
 245.179 +				/* copy partial string from buffer */
 245.180 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 245.181 +				/* get more data from the net */
 245.182 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 245.183 +				/* special case of newline broken by buffer */
 245.184 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 245.185 +    stream->iptr++;		/* eat the line feed */
 245.186 +    stream->ictr--;
 245.187 +    ret[*size = --n] = '\0';	/* tie off string with null */
 245.188 +  }
 245.189 +  else *contd = LONGT;		/* continuation needed */
 245.190 +  return ret;
 245.191 +}
 245.192 +
 245.193 +/* TCP/IP receive buffer
 245.194 + * Accepts: TCP/IP stream
 245.195 + *	    size in bytes
 245.196 + *	    buffer to read into
 245.197 + * Returns: T if success, NIL otherwise
 245.198 + */
 245.199 +
 245.200 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 245.201 +{
 245.202 +  unsigned long n;
 245.203 +  char *bufptr = buffer;
 245.204 +  while (size > 0) {		/* until request satisfied */
 245.205 +    if (!tcp_getdata (stream)) return NIL;
 245.206 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 245.207 +				/* do the copy */
 245.208 +    memcpy (bufptr,stream->iptr,(size_t) n);
 245.209 +    bufptr += n;		/* update pointer */
 245.210 +    stream->iptr +=n;
 245.211 +    size -= n;			/* update # of bytes to do */
 245.212 +    stream->ictr -=n;
 245.213 +  }
 245.214 +  bufptr[0] = '\0';		/* tie off string */
 245.215 +  return T;
 245.216 +}
 245.217 +
 245.218 +
 245.219 +/* TCP/IP receive data
 245.220 + * Accepts: TCP/IP stream
 245.221 + * Returns: T if success, NIL otherwise
 245.222 + */
 245.223 +
 245.224 +long tcp_getdata (TCPSTREAM *stream)
 245.225 +{
 245.226 +  int status;
 245.227 +  if (!stream->tcps) return NIL;/* no-no nuked socket */
 245.228 +  while (stream->ictr < 1) {	/* if buffer empty, block for input and read */
 245.229 +    if (!_ip_delay1 (stream->tcps,600,NULL,&status))
 245.230 +      stream->ictr = sock_fastread (stream->tcps,
 245.231 +				    stream->iptr = stream->ibuf,BUFLEN);
 245.232 +    else if (status == 1) {	/* nuke the socket if closed */
 245.233 +      sock_close (stream->tcps);
 245.234 +      fs_give ((void **) &stream->tcps);
 245.235 +      return NIL;
 245.236 +    }
 245.237 +  }
 245.238 +  return T;
 245.239 +}
 245.240 +
 245.241 +/* TCP/IP send string as record
 245.242 + * Accepts: TCP/IP stream
 245.243 + * Returns: T if success else NIL
 245.244 + */
 245.245 +
 245.246 +long tcp_soutr (TCPSTREAM *stream,char *string)
 245.247 +{
 245.248 +				/* output the cruft */
 245.249 +  sock_puts (stream->tcps,string);
 245.250 +  return T;			/* all done */
 245.251 +}
 245.252 +
 245.253 +
 245.254 +/* TCP/IP send string
 245.255 + * Accepts: TCP/IP stream
 245.256 + *	    string pointer
 245.257 + *	    byte count
 245.258 + * Returns: T if success else NIL
 245.259 + */
 245.260 +
 245.261 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 245.262 +{
 245.263 +  sock_write (stream->tcps,string,(int) size);
 245.264 +  return T;
 245.265 +}
 245.266 +
 245.267 +
 245.268 +/* TCP/IP close
 245.269 + * Accepts: TCP/IP stream
 245.270 + */
 245.271 +
 245.272 +void tcp_close (TCPSTREAM *stream)
 245.273 +{
 245.274 +  if (stream->tcps){ 		/* nuke the socket */
 245.275 +    sock_close (stream->tcps);
 245.276 +    _ip_delay2 (stream->tcps,0,NULL,NULL);
 245.277 +  }
 245.278 +  fs_give ((void **) &stream->tcps);
 245.279 +				/* flush host names */
 245.280 +  fs_give ((void **) &stream->host);
 245.281 +  fs_give ((void **) &stream->localhost);
 245.282 +  fs_give ((void **) &stream);	/* flush the stream */
 245.283 +}
 245.284 +
 245.285 +/* TCP/IP get host name
 245.286 + * Accepts: TCP/IP stream
 245.287 + * Returns: host name for this stream
 245.288 + */
 245.289 +
 245.290 +char *tcp_host (TCPSTREAM *stream)
 245.291 +{
 245.292 +  return stream->host;		/* return host name */
 245.293 +}
 245.294 +
 245.295 +
 245.296 +/* TCP/IP get remote host name
 245.297 + * Accepts: TCP/IP stream
 245.298 + * Returns: host name for this stream
 245.299 + */
 245.300 +
 245.301 +char *tcp_remotehost (TCPSTREAM *stream)
 245.302 +{
 245.303 +  return stream->host;		/* return host name */
 245.304 +}
 245.305 +
 245.306 +
 245.307 +/* TCP/IP return port for this stream
 245.308 + * Accepts: TCP/IP stream
 245.309 + * Returns: port number for this stream
 245.310 + */
 245.311 +
 245.312 +unsigned long tcp_port (TCPSTREAM *stream)
 245.313 +{
 245.314 +  return stream->port;		/* return port number */
 245.315 +}
 245.316 +
 245.317 +
 245.318 +/* TCP/IP get local host name
 245.319 + * Accepts: TCP/IP stream
 245.320 + * Returns: local host name
 245.321 + */
 245.322 +
 245.323 +char *tcp_localhost (TCPSTREAM *stream)
 245.324 +{
 245.325 +  return stream->localhost;	/* return local host name */
 245.326 +}
 245.327 +
 245.328 +
 245.329 +/* TCP/IP return canonical form of host name
 245.330 + * Accepts: host name
 245.331 + * Returns: canonical form of host name
 245.332 + */
 245.333 +
 245.334 +char *tcp_canonical (char *name)
 245.335 +{
 245.336 +  return name;
 245.337 +}
 245.338 +
 245.339 +
 245.340 +/* TCP/IP get client host name (server calls only)
 245.341 + * Returns: client host name
 245.342 + */
 245.343 +
 245.344 +char *tcp_clienthost ()
 245.345 +{
 245.346 +  return "UNKNOWN";
 245.347 +}
   246.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   246.2 +++ b/src/osdep/dos/tcp_dwa.h	Mon Sep 14 15:17:45 2009 +0900
   246.3 @@ -0,0 +1,45 @@
   246.4 +/* ========================================================================
   246.5 + * Copyright 1988-2006 University of Washington
   246.6 + *
   246.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   246.8 + * you may not use this file except in compliance with the License.
   246.9 + * You may obtain a copy of the License at
  246.10 + *
  246.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  246.12 + *
  246.13 + * 
  246.14 + * ========================================================================
  246.15 + */
  246.16 +
  246.17 +/*
  246.18 + * Program:	Waterloo DOS TCP/IP routines
  246.19 + *
  246.20 + * Author:	Mark Crispin
  246.21 + *		Networks and Distributed Computing
  246.22 + *		Computing & Communications
  246.23 + *		University of Washington
  246.24 + *		Administration Building, AG-44
  246.25 + *		Seattle, WA  98195
  246.26 + *		Internet: MRC@CAC.Washington.EDU
  246.27 + *
  246.28 + * Date:	11 April 1989
  246.29 + * Last Edited:	30 August 2006
  246.30 + */
  246.31 +
  246.32 +/* TCP input buffer -- must be large enough to prevent overflow */
  246.33 +
  246.34 +#define BUFLEN 8192
  246.35 +
  246.36 +
  246.37 +/* TCP I/O stream (must be before osdep.h is included) */
  246.38 +
  246.39 +#define TCPSTREAM struct tcp_stream
  246.40 +TCPSTREAM {
  246.41 +  char *host;			/* host name */
  246.42 +  unsigned long port;		/* port number */
  246.43 +  char *localhost;		/* local host name */
  246.44 +  tcp_Socket *tcps;		/* tcp socket */
  246.45 +  long ictr;			/* input counter */
  246.46 +  char *iptr;			/* input pointer */
  246.47 +  char ibuf[BUFLEN];		/* input buffer */
  246.48 +};
   247.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   247.2 +++ b/src/osdep/dos/tcp_wsk.c	Mon Sep 14 15:17:45 2009 +0900
   247.3 @@ -0,0 +1,818 @@
   247.4 +/* ========================================================================
   247.5 + * Copyright 1988-2008 University of Washington
   247.6 + *
   247.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   247.8 + * you may not use this file except in compliance with the License.
   247.9 + * You may obtain a copy of the License at
  247.10 + *
  247.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  247.12 + *
  247.13 + * 
  247.14 + * ========================================================================
  247.15 + */
  247.16 +
  247.17 +/*
  247.18 + * Program:	Winsock TCP/IP routines
  247.19 + *
  247.20 + * Author:	Mark Crispin from Mike Seibel's Winsock code
  247.21 + *		Networks and Distributed Computing
  247.22 + *		Computing & Communications
  247.23 + *		University of Washington
  247.24 + *		Administration Building, AG-44
  247.25 + *		Seattle, WA  98195
  247.26 + *		Internet: MRC@CAC.Washington.EDU
  247.27 + *
  247.28 + * Date:	11 April 1989
  247.29 + * Last Edited:	13 January 2008
  247.30 + */
  247.31 +
  247.32 +
  247.33 +#define TCPMAXSEND 32768
  247.34 +
  247.35 +/* Private functions */
  247.36 +
  247.37 +int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
  247.38 +		     unsigned long port);
  247.39 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  247.40 +			       long *contd);
  247.41 +long tcp_abort (TCPSTREAM *stream);
  247.42 +long tcp_close_socket (SOCKET *sock);
  247.43 +char *tcp_name (struct sockaddr_in *sin,long flag);
  247.44 +char *tcp_name_valid (char *s);
  247.45 +
  247.46 +
  247.47 +/* Private data */
  247.48 +
  247.49 +int wsa_initted = 0;		/* init ? */
  247.50 +static int wsa_sock_open = 0;	/* keep track of open sockets */
  247.51 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  247.52 +static long ttmo_read = 0;	/* TCP timeouts, in seconds */
  247.53 +static long ttmo_write = 0;
  247.54 +static long allowreversedns = T;/* allow reverse DNS lookup */
  247.55 +static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
  247.56 +
  247.57 +/* TCP/IP manipulate parameters
  247.58 + * Accepts: function code
  247.59 + *	    function-dependent value
  247.60 + * Returns: function-dependent return value
  247.61 + */
  247.62 +
  247.63 +void *tcp_parameters (long function,void *value)
  247.64 +{
  247.65 +  void *ret = NIL;
  247.66 +  switch ((int) function) {
  247.67 +  case SET_TIMEOUT:
  247.68 +    tmoh = (tcptimeout_t) value;
  247.69 +  case GET_TIMEOUT:
  247.70 +    ret = (void *) tmoh;
  247.71 +    break;
  247.72 +  case SET_READTIMEOUT:
  247.73 +    ttmo_read = (long) value;
  247.74 +  case GET_READTIMEOUT:
  247.75 +    ret = (void *) ttmo_read;
  247.76 +    break;
  247.77 +  case SET_WRITETIMEOUT:
  247.78 +    ttmo_write = (long) value;
  247.79 +  case GET_WRITETIMEOUT:
  247.80 +    ret = (void *) ttmo_write;
  247.81 +    break;
  247.82 +  case SET_ALLOWREVERSEDNS:
  247.83 +    allowreversedns = (long) value;
  247.84 +  case GET_ALLOWREVERSEDNS:
  247.85 +    ret = (void *) allowreversedns;
  247.86 +    break;
  247.87 +  case SET_TCPDEBUG:
  247.88 +    tcpdebug = (long) value;
  247.89 +  case GET_TCPDEBUG:
  247.90 +    ret = (void *) tcpdebug;
  247.91 +    break;
  247.92 +  }
  247.93 +  return ret;
  247.94 +}
  247.95 +
  247.96 +/* TCP/IP open
  247.97 + * Accepts: host name
  247.98 + *	    contact service name
  247.99 + *	    contact port number and optional silent flag
 247.100 + * Returns: TCP/IP stream if success else NIL
 247.101 + */
 247.102 +
 247.103 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
 247.104 +{
 247.105 +  TCPSTREAM *stream = NIL;
 247.106 +  int i;
 247.107 +  SOCKET sock = INVALID_SOCKET;
 247.108 +  int silent = (port & NET_SILENT) ? T : NIL;
 247.109 +  char *s;
 247.110 +  struct sockaddr_in sin;
 247.111 +  struct hostent *he;
 247.112 +  char hostname[MAILTMPLEN];
 247.113 +  char tmp[MAILTMPLEN];
 247.114 +  struct servent *sv = NIL;
 247.115 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 247.116 +  if (!wsa_initted++) {		/* init Windows Sockets */
 247.117 +    WSADATA wsock;
 247.118 +    if (i = (int) WSAStartup (WSA_VERSION,&wsock)) {
 247.119 +      wsa_initted = 0;		/* in case we try again */
 247.120 +      sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
 247.121 +      mm_log (tmp,ERROR);
 247.122 +      return NIL;
 247.123 +    }
 247.124 +  }
 247.125 +  port &= 0xffff;		/* erase flags */
 247.126 +				/* lookup service */
 247.127 +  if (service && (sv = getservbyname (service,"tcp")))
 247.128 +    port = ntohs (sin.sin_port = sv->s_port);
 247.129 + 				/* copy port number in network format */
 247.130 +  else sin.sin_port = htons ((u_short) port);
 247.131 +  /* The domain literal form is used (rather than simply the dotted decimal
 247.132 +     as with other Windows programs) because it has to be a valid "host name"
 247.133 +     in mailsystem terminology. */
 247.134 +  sin.sin_family = AF_INET;	/* family is always Internet */
 247.135 +				/* look like domain literal? */
 247.136 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
 247.137 +    strcpy (tmp,host+1);	/* yes, copy number part */
 247.138 +    tmp[strlen (tmp)-1] = '\0';
 247.139 +    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
 247.140 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
 247.141 +      mm_log (tmp,ERROR);
 247.142 +      return NIL;
 247.143 +    }
 247.144 +    else {
 247.145 +      sin.sin_family = AF_INET;	/* family is always Internet */
 247.146 +      strcpy (hostname,host);
 247.147 +      (*bn) (BLOCK_TCPOPEN,NIL);
 247.148 +      sock = tcp_socket_open (&sin,tmp,hostname,port);
 247.149 +      (*bn) (BLOCK_NONE,NIL);
 247.150 +    }
 247.151 +  }
 247.152 +
 247.153 +  else {			/* lookup host name */
 247.154 +    if (tcpdebug) {
 247.155 +      sprintf (tmp,"DNS resolution %.80s",host);
 247.156 +      mm_log (tmp,TCPDEBUG);
 247.157 +    }
 247.158 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
 247.159 +    if (!(he = gethostbyname (lcase (strcpy (tmp,host)))))
 247.160 +      sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
 247.161 +    (*bn) (BLOCK_NONE,NIL);
 247.162 +    if (he) {			/* DNS resolution won? */
 247.163 +      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
 247.164 +				/* copy address type */
 247.165 +      sin.sin_family = he->h_addrtype;
 247.166 +				/* copy host name */
 247.167 +      strcpy (hostname,he->h_name);
 247.168 +      wsa_sock_open++;		/* prevent tcp_close_socket() from freeing in
 247.169 +				   loop */
 247.170 +      for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) {
 247.171 +	if (i && !silent) mm_log (tmp,WARN);
 247.172 +	memcpy (&sin.sin_addr,s,he->h_length);
 247.173 +	(*bn) (BLOCK_TCPOPEN,NIL);
 247.174 +	sock = tcp_socket_open (&sin,tmp,hostname,port);
 247.175 +	(*bn) (BLOCK_NONE,NIL);
 247.176 +      }
 247.177 +      wsa_sock_open--;		/* undo protection */
 247.178 +    }
 247.179 +  }
 247.180 +  if (sock == INVALID_SOCKET) {	/* error? */
 247.181 +    if (!silent) mm_log (tmp,ERROR);
 247.182 +    tcp_close_socket (&sock);	/* do possible cleanup action */
 247.183 +  }
 247.184 +  else {			/* got a socket, create TCP/IP stream */
 247.185 +    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
 247.186 +				   sizeof (TCPSTREAM));
 247.187 +    stream->port = port;	/* port number */
 247.188 +				/* init socket */
 247.189 +    stream->tcpsi = stream->tcpso = sock;
 247.190 +    stream->ictr = 0;		/* init input counter */
 247.191 +				/* copy official host name */
 247.192 +    stream->host = cpystr (hostname);
 247.193 +    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
 247.194 +  }
 247.195 +  return stream;		/* return success */
 247.196 +}
 247.197 +
 247.198 +/* Open a TCP socket
 247.199 + * Accepts: Internet socket address block
 247.200 + *	    scratch buffer
 247.201 + *	    host name for error message
 247.202 + *	    port number for error message
 247.203 + * Returns: socket if success, else -1 with error string in scratch buffer
 247.204 + */
 247.205 +
 247.206 +int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
 247.207 +		     unsigned long port)
 247.208 +{
 247.209 +  int sock;
 247.210 +  char *s;
 247.211 +  sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
 247.212 +  mm_log (tmp,NIL);
 247.213 +				/* get a TCP stream */
 247.214 +  if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
 247.215 +    sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
 247.216 +    return -1;
 247.217 +  }
 247.218 +  wsa_sock_open++;		/* count this socket as open */
 247.219 +				/* open connection */
 247.220 +  if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) ==
 247.221 +      SOCKET_ERROR) {
 247.222 +    switch (WSAGetLastError ()){/* analyze error */
 247.223 +    case WSAECONNREFUSED:
 247.224 +      s = "Refused";
 247.225 +      break;
 247.226 +    case WSAENOBUFS:
 247.227 +      s = "Insufficient system resources";
 247.228 +      break;
 247.229 +    case WSAETIMEDOUT:
 247.230 +      s = "Timed out";
 247.231 +      break;
 247.232 +    case WSAEHOSTUNREACH:
 247.233 +      s = "Host unreachable";
 247.234 +      break;
 247.235 +    default:
 247.236 +      s = "Unknown error";
 247.237 +      break;
 247.238 +    }
 247.239 +    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s,
 247.240 +	     WSAGetLastError ());
 247.241 +    tcp_close_socket (&sock);	/* flush socket */
 247.242 +    sock = INVALID_SOCKET;
 247.243 +  }
 247.244 +  return sock;			/* return the socket */
 247.245 +}
 247.246 +  
 247.247 +/* TCP/IP authenticated open
 247.248 + * Accepts: NETMBX specifier
 247.249 + *	    service name
 247.250 + *	    returned user name buffer
 247.251 + * Returns: TCP/IP stream if success else NIL
 247.252 + */
 247.253 +
 247.254 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 247.255 +{
 247.256 +  return NIL;			/* always NIL on Windows */
 247.257 +}
 247.258 +
 247.259 +/* TCP receive line
 247.260 + * Accepts: TCP stream
 247.261 + * Returns: text line string or NIL if failure
 247.262 + */
 247.263 +
 247.264 +char *tcp_getline (TCPSTREAM *stream)
 247.265 +{
 247.266 +  unsigned long n,contd;
 247.267 +  char *ret = tcp_getline_work (stream,&n,&contd);
 247.268 +  if (ret && contd) {		/* got a line needing continuation? */
 247.269 +    STRINGLIST *stl = mail_newstringlist ();
 247.270 +    STRINGLIST *stc = stl;
 247.271 +    do {			/* collect additional lines */
 247.272 +      stc->text.data = (unsigned char *) ret;
 247.273 +      stc->text.size = n;
 247.274 +      stc = stc->next = mail_newstringlist ();
 247.275 +      ret = tcp_getline_work (stream,&n,&contd);
 247.276 +    } while (ret && contd);
 247.277 +    if (ret) {			/* stash final part of line on list */
 247.278 +      stc->text.data = (unsigned char *) ret;
 247.279 +      stc->text.size = n;
 247.280 +				/* determine how large a buffer we need */
 247.281 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 247.282 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 247.283 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 247.284 +	memcpy (ret + n,stc->text.data,stc->text.size);
 247.285 +      ret[n] = '\0';
 247.286 +    }
 247.287 +    mail_free_stringlist (&stl);/* either way, done with list */
 247.288 +  }
 247.289 +  return ret;
 247.290 +}
 247.291 +
 247.292 +/* TCP receive line or partial line
 247.293 + * Accepts: TCP stream
 247.294 + *	    pointer to return size
 247.295 + *	    pointer to return continuation flag
 247.296 + * Returns: text line string, size and continuation flag, or NIL if failure
 247.297 + */
 247.298 +
 247.299 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 247.300 +			       long *contd)
 247.301 +{
 247.302 +  unsigned long n;
 247.303 +  char *s,*ret,c,d;
 247.304 +  *contd = NIL;			/* assume no continuation */
 247.305 +				/* make sure have data */
 247.306 +  if (!tcp_getdata (stream)) return NIL;
 247.307 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 247.308 +    d = *stream->iptr++;	/* slurp another character */
 247.309 +    if ((c == '\015') && (d == '\012')) {
 247.310 +      ret = (char *) fs_get (n--);
 247.311 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 247.312 +      ret[n] = '\0';		/* tie off string with null */
 247.313 +      return ret;
 247.314 +    }
 247.315 +  }
 247.316 +				/* copy partial string from buffer */
 247.317 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 247.318 +				/* get more data from the net */
 247.319 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 247.320 +				/* special case of newline broken by buffer */
 247.321 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 247.322 +    stream->iptr++;		/* eat the line feed */
 247.323 +    stream->ictr--;
 247.324 +    ret[*size = --n] = '\0';	/* tie off string with null */
 247.325 +  }
 247.326 +  else *contd = LONGT;		/* continuation needed */
 247.327 +  return ret;
 247.328 +}
 247.329 +
 247.330 +/* TCP/IP receive buffer
 247.331 + * Accepts: TCP/IP stream
 247.332 + *	    size in bytes
 247.333 + *	    buffer to read into
 247.334 + * Returns: T if success, NIL otherwise
 247.335 + */
 247.336 +
 247.337 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
 247.338 +{
 247.339 +  unsigned long n;
 247.340 +				/* make sure socket still alive */
 247.341 +  if (stream->tcpsi == INVALID_SOCKET) return NIL;
 247.342 +				/* can transfer bytes from buffer? */
 247.343 +  if (n = min (size,stream->ictr)) {
 247.344 +    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
 247.345 +    s += n;			/* update pointer */
 247.346 +    stream->iptr +=n;
 247.347 +    size -= n;			/* update # of bytes to do */
 247.348 +    stream->ictr -=n;
 247.349 +  }
 247.350 +  if (size) {
 247.351 +    int i;
 247.352 +    fd_set fds;
 247.353 +    struct timeval tmo;
 247.354 +    time_t tc,t = time (0);
 247.355 +    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 247.356 +    (*bn) (BLOCK_TCPREAD,NIL);
 247.357 +    while (size > 0) {		/* until request satisfied */
 247.358 +      time_t tl = time (0);
 247.359 +      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
 247.360 +      FD_ZERO (&fds);		/* initialize selection vector */
 247.361 +      FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
 247.362 +      tmo.tv_sec = ttmo_read;
 247.363 +      tmo.tv_usec = 0;
 247.364 +				/* block and read */
 247.365 +      switch ((stream->tcpsi == stream->tcpso) ?
 247.366 +	      select (stream->tcpsi+1,&fds,0,0,
 247.367 +		      ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
 247.368 +      case SOCKET_ERROR:		/* error */
 247.369 +	if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
 247.370 +	break;
 247.371 +      case 0:			/* timeout */
 247.372 +	tc = time (0);
 247.373 +	if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
 247.374 +	return tcp_abort (stream);
 247.375 +      default:
 247.376 +	if (stream->tcpsi == stream->tcpso)
 247.377 +	  while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) ==
 247.378 +		  SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
 247.379 +	else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) <
 247.380 +		     0) && (errno == EINTR));
 247.381 +	switch (i) {
 247.382 +	case SOCKET_ERROR:	/* error */
 247.383 +	case 0:			/* no data read */
 247.384 +	  return tcp_abort (stream);
 247.385 +	default:
 247.386 +	  s += i;		/* point at new place to write */
 247.387 +	  size -= i;		/* reduce byte count */
 247.388 +	  if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
 247.389 +	}
 247.390 +      }
 247.391 +    }
 247.392 +    (*bn) (BLOCK_NONE,NIL);
 247.393 +  }
 247.394 +  *s = '\0';			/* tie off string */
 247.395 +  return T;
 247.396 +}
 247.397 +
 247.398 +/* TCP/IP receive data
 247.399 + * Accepts: TCP/IP stream
 247.400 + * Returns: T if success, NIL otherwise
 247.401 + */
 247.402 +
 247.403 +long tcp_getdata (TCPSTREAM *stream)
 247.404 +{
 247.405 +  struct timeval tmo;
 247.406 +  int i;
 247.407 +  fd_set fds;
 247.408 +  time_t tc,t = time (0);
 247.409 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 247.410 +  FD_ZERO (&fds);		/* initialize selection vector */
 247.411 +  if (stream->tcpsi == INVALID_SOCKET) return NIL;
 247.412 +  (*bn) (BLOCK_TCPREAD,NIL);
 247.413 +  tmo.tv_sec = ttmo_read;
 247.414 +  tmo.tv_usec = 0;
 247.415 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 247.416 +    time_t tl = time (0);
 247.417 +    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
 247.418 +    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
 247.419 +				/* block and read */
 247.420 +    switch ((stream->tcpsi == stream->tcpso) ?
 247.421 +	    select (stream->tcpsi+1,&fds,0,0,
 247.422 +		    ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
 247.423 +    case SOCKET_ERROR:		/* error */
 247.424 +      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
 247.425 +      break;
 247.426 +    case 0:			/* timeout */
 247.427 +      tc = time (0);
 247.428 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
 247.429 +      return tcp_abort (stream);
 247.430 +    default:
 247.431 +      if (stream->tcpsi == stream->tcpso)
 247.432 +	while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
 247.433 +		SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
 247.434 +      else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
 247.435 +		  (errno == EINTR));
 247.436 +      switch (i) {
 247.437 +      case SOCKET_ERROR:	/* error */
 247.438 +      case 0:			/* no data read */
 247.439 +	return tcp_abort (stream);
 247.440 +      default:
 247.441 +	stream->ictr = i;	/* set new byte count */
 247.442 +				/* point at TCP buffer */
 247.443 +	stream->iptr = stream->ibuf;
 247.444 +	if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
 247.445 +      }
 247.446 +    }
 247.447 +  }
 247.448 +  (*bn) (BLOCK_NONE,NIL);
 247.449 +  return T;
 247.450 +}
 247.451 +
 247.452 +/* TCP/IP send string as record
 247.453 + * Accepts: TCP/IP stream
 247.454 + *	    string pointer
 247.455 + * Returns: T if success else NIL
 247.456 + */
 247.457 +
 247.458 +long tcp_soutr (TCPSTREAM *stream,char *string)
 247.459 +{
 247.460 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 247.461 +}
 247.462 +
 247.463 +
 247.464 +/* TCP/IP send string
 247.465 + * Accepts: TCP/IP stream
 247.466 + *	    string pointer
 247.467 + *	    byte count
 247.468 + * Returns: T if success else NIL
 247.469 + */
 247.470 +
 247.471 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 247.472 +{
 247.473 +  int i;
 247.474 +  struct timeval tmo;
 247.475 +  fd_set fds;
 247.476 +  time_t tc,t = time (0);
 247.477 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 247.478 +  tmo.tv_sec = ttmo_write;
 247.479 +  tmo.tv_usec = 0;
 247.480 +  FD_ZERO (&fds);		/* initialize selection vector */
 247.481 +  if (stream->tcpso == INVALID_SOCKET) return NIL;
 247.482 +  (*bn) (BLOCK_TCPWRITE,NIL);
 247.483 +  while (size > 0) {		/* until request satisfied */
 247.484 +    time_t tl = time (0);
 247.485 +    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
 247.486 +    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
 247.487 +				/* block and write */
 247.488 +    switch ((stream->tcpsi == stream->tcpso) ?
 247.489 +	    select (stream->tcpso+1,NULL,&fds,NULL,
 247.490 +		    tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) {
 247.491 +    case SOCKET_ERROR:		/* error */
 247.492 +      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
 247.493 +      break;
 247.494 +    case 0:			/* timeout */
 247.495 +      tc = time (0);
 247.496 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
 247.497 +      return tcp_abort (stream);
 247.498 +    default:
 247.499 +      if (stream->tcpsi == stream->tcpso)
 247.500 +	while (((i = send (stream->tcpso,string,
 247.501 +			   (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) &&
 247.502 +	       (WSAGetLastError () == WSAEINTR));
 247.503 +      else while (((i = write (stream->tcpso,string,
 247.504 +			       min (size,TCPMAXSEND))) < 0) &&
 247.505 +		  (errno == EINTR));
 247.506 +      if (i == SOCKET_ERROR) return tcp_abort (stream);
 247.507 +      size -= i;		/* count this size */
 247.508 +      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
 247.509 +      string += i;
 247.510 +    }
 247.511 +  }
 247.512 +  (*bn) (BLOCK_NONE,NIL);
 247.513 +  return T;			/* all done */
 247.514 +}
 247.515 +
 247.516 +
 247.517 +/* TCP/IP close
 247.518 + * Accepts: TCP/IP stream
 247.519 + */
 247.520 +
 247.521 +void tcp_close (TCPSTREAM *stream)
 247.522 +{
 247.523 +  tcp_abort (stream);		/* nuke the sockets */
 247.524 +				/* flush host names */
 247.525 +  if (stream->host) fs_give ((void **) &stream->host);
 247.526 +  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
 247.527 +  if (stream->localhost) fs_give ((void **) &stream->localhost);
 247.528 +  fs_give ((void **) &stream);	/* flush the stream */
 247.529 +}
 247.530 +
 247.531 +
 247.532 +/* TCP/IP abort sockets
 247.533 + * Accepts: TCP/IP stream
 247.534 + * Returns: NIL, always
 247.535 + */
 247.536 +
 247.537 +long tcp_abort (TCPSTREAM *stream)
 247.538 +{
 247.539 +  if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
 247.540 +  else stream->tcpso = INVALID_SOCKET;
 247.541 +  return tcp_close_socket (&stream->tcpsi);
 247.542 +}
 247.543 +
 247.544 +
 247.545 +/* TCP/IP abort stream
 247.546 + * Accepts: WinSock socket
 247.547 + * Returns: NIL, always
 247.548 + */
 247.549 +
 247.550 +long tcp_close_socket (SOCKET *sock)
 247.551 +{
 247.552 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 247.553 +				/* something to close? */
 247.554 +  if (sock && (*sock != INVALID_SOCKET)) {
 247.555 +    (*bn) (BLOCK_TCPCLOSE,NIL);
 247.556 +    closesocket (*sock);	/* WinSock socket close */
 247.557 +    *sock = INVALID_SOCKET;
 247.558 +    (*bn) (BLOCK_NONE,NIL);
 247.559 +    wsa_sock_open--;		/* drop this socket */
 247.560 +  }
 247.561 +				/* no more open streams? */
 247.562 +  if (wsa_initted && !wsa_sock_open) {
 247.563 +    mm_log ("Winsock cleanup",NIL);
 247.564 +    wsa_initted = 0;		/* no more sockets, so... */
 247.565 +    WSACleanup ();		/* free up resources until needed */
 247.566 +  }
 247.567 +  return NIL;
 247.568 +}
 247.569 +
 247.570 +/* TCP/IP get host name
 247.571 + * Accepts: TCP/IP stream
 247.572 + * Returns: host name for this stream
 247.573 + */
 247.574 +
 247.575 +char *tcp_host (TCPSTREAM *stream)
 247.576 +{
 247.577 +  return stream->host;		/* use tcp_remotehost() if want guarantees */
 247.578 +}
 247.579 +
 247.580 +
 247.581 +/* TCP/IP get remote host name
 247.582 + * Accepts: TCP/IP stream
 247.583 + * Returns: host name for this stream
 247.584 + */
 247.585 +
 247.586 +char *tcp_remotehost (TCPSTREAM *stream)
 247.587 +{
 247.588 +  if (!stream->remotehost) {
 247.589 +    struct sockaddr_in sin;
 247.590 +    int sinlen = sizeof (struct sockaddr_in);
 247.591 +    stream->remotehost =	/* get socket's peer name */
 247.592 +      ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
 247.593 +	SOCKET_ERROR) || (sinlen <= 0)) ?
 247.594 +	  cpystr (stream->host) : tcp_name (&sin,NIL);
 247.595 +  }
 247.596 +  return stream->remotehost;
 247.597 +}
 247.598 +
 247.599 +
 247.600 +/* TCP/IP return port for this stream
 247.601 + * Accepts: TCP/IP stream
 247.602 + * Returns: port number for this stream
 247.603 + */
 247.604 +
 247.605 +unsigned long tcp_port (TCPSTREAM *stream)
 247.606 +{
 247.607 +  return stream->port;		/* return port number */
 247.608 +}
 247.609 +
 247.610 +
 247.611 +/* TCP/IP get local host name
 247.612 + * Accepts: TCP/IP stream
 247.613 + * Returns: local host name
 247.614 + */
 247.615 +
 247.616 +char *tcp_localhost (TCPSTREAM *stream)
 247.617 +{
 247.618 +  if (!stream->localhost) {
 247.619 +    struct sockaddr_in sin;
 247.620 +    int sinlen = sizeof (struct sockaddr_in);
 247.621 +    stream->localhost =		/* get socket's name */
 247.622 +      ((stream->port & 0xffff000) ||
 247.623 +       ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
 247.624 +	 SOCKET_ERROR) || (sinlen <= 0))) ?
 247.625 +	   cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
 247.626 +  }
 247.627 +  return stream->localhost;	/* return local host name */
 247.628 +}
 247.629 +
 247.630 +/* TCP/IP get client host address (server calls only)
 247.631 + * Returns: client host address
 247.632 + */
 247.633 +
 247.634 +char *tcp_clientaddr ()
 247.635 +{
 247.636 +  if (!myClientAddr) {
 247.637 +    struct sockaddr_in sin;
 247.638 +    int sinlen = sizeof (struct sockaddr_in);
 247.639 +    myClientAddr =		/* get stdin's peer name */
 247.640 +      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 247.641 +       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
 247.642 +  }
 247.643 +  return myClientAddr;
 247.644 +}
 247.645 +
 247.646 +
 247.647 +/* TCP/IP get client host name (server calls only)
 247.648 + * Returns: client host name
 247.649 + */
 247.650 +
 247.651 +char *tcp_clienthost ()
 247.652 +{
 247.653 +  if (!myClientHost) {
 247.654 +    struct sockaddr_in sin;
 247.655 +    int sinlen = sizeof (struct sockaddr_in);
 247.656 +    myClientHost =		/* get stdin's peer name */
 247.657 +      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 247.658 +       (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T);
 247.659 +  }
 247.660 +  return myClientHost;
 247.661 +}
 247.662 +
 247.663 +/* TCP/IP get server host address (server calls only)
 247.664 + * Returns: server host address
 247.665 + */
 247.666 +
 247.667 +char *tcp_serveraddr ()
 247.668 +{
 247.669 +  if (!myServerAddr) {
 247.670 +    struct sockaddr_in sin;
 247.671 +    int sinlen = sizeof (struct sockaddr_in);
 247.672 +    myServerAddr =		/* get stdin's peer name */
 247.673 +      ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 247.674 +       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
 247.675 +  }
 247.676 +  return myServerAddr;
 247.677 +}
 247.678 +
 247.679 +
 247.680 +/* TCP/IP get server host name (server calls only)
 247.681 + * Returns: server host name
 247.682 + */
 247.683 +
 247.684 +static long myServerPort = -1;
 247.685 +
 247.686 +char *tcp_serverhost ()
 247.687 +{
 247.688 +  if (!myServerHost) {
 247.689 +    struct sockaddr_in sin;
 247.690 +    int sinlen = sizeof (struct sockaddr_in);
 247.691 +    if (!wsa_initted++) {	/* init Windows Sockets */
 247.692 +      WSADATA wsock;
 247.693 +      if (WSAStartup (WSA_VERSION,&wsock)) {
 247.694 +	wsa_initted = 0;
 247.695 +	return "random-pc";	/* try again later? */
 247.696 +      }
 247.697 +    }
 247.698 +				/* get stdin's name */
 247.699 +    if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 247.700 +	(sinlen <= 0)) myServerHost = cpystr (mylocalhost ());
 247.701 +    else {
 247.702 +      myServerHost = tcp_name (&sin,NIL);
 247.703 +      myServerPort = ntohs (sin.sin_port);
 247.704 +    }
 247.705 +  }
 247.706 +  return myServerHost;
 247.707 +}
 247.708 +
 247.709 +
 247.710 +/* TCP/IP get server port number (server calls only)
 247.711 + * Returns: server port number
 247.712 + */
 247.713 +
 247.714 +long tcp_serverport ()
 247.715 +{
 247.716 +  if (!myServerHost) tcp_serverhost ();
 247.717 +  return myServerPort;
 247.718 +}
 247.719 +
 247.720 +/* TCP/IP return canonical form of host name
 247.721 + * Accepts: host name
 247.722 + * Returns: canonical form of host name
 247.723 + */
 247.724 +
 247.725 +char *tcp_canonical (char *name)
 247.726 +{
 247.727 +  char *ret,host[MAILTMPLEN];
 247.728 +  struct hostent *he;
 247.729 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 247.730 +				/* look like domain literal? */
 247.731 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 247.732 +  (*bn) (BLOCK_DNSLOOKUP,NIL);
 247.733 +  if (tcpdebug) {
 247.734 +    sprintf (host,"DNS canonicalization %.80s",name);
 247.735 +    mm_log (host,TCPDEBUG);
 247.736 +  }
 247.737 +				/* note that NT requires lowercase! */
 247.738 +  ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name;
 247.739 +  (*bn) (BLOCK_NONE,NIL);
 247.740 +  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
 247.741 +  return ret;
 247.742 +}
 247.743 +
 247.744 +
 247.745 +/* TCP/IP return name from socket
 247.746 + * Accepts: socket
 247.747 + *	    verbose flag
 247.748 + * Returns: cpystr name
 247.749 + */
 247.750 +
 247.751 +char *tcp_name (struct sockaddr_in *sin,long flag)
 247.752 +{
 247.753 +  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
 247.754 +  sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
 247.755 +  if (allowreversedns) {
 247.756 +    struct hostent *he;
 247.757 +    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
 247.758 +    void *data;
 247.759 +    if (tcpdebug) {
 247.760 +      sprintf (tmp,"Reverse DNS resolution %s",adr);
 247.761 +      mm_log (tmp,TCPDEBUG);
 247.762 +    }
 247.763 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 247.764 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
 247.765 +				/* translate address to name */
 247.766 +    if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
 247.767 +						 sizeof (struct in_addr),
 247.768 +						 sin->sin_family)) ?
 247.769 +			    (char *) he->h_name : NIL)) {
 247.770 +				/* produce verbose form if needed */
 247.771 +      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
 247.772 +      else ret = t;
 247.773 +    }
 247.774 +    (*bn) (BLOCK_NONSENSITIVE,data);
 247.775 +    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 247.776 +    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
 247.777 +  }
 247.778 +  return cpystr (ret);
 247.779 +}
 247.780 +
 247.781 +/* Return my local host name
 247.782 + * Returns: my local host name
 247.783 + */
 247.784 +
 247.785 +char *mylocalhost (void)
 247.786 +{
 247.787 +  if (!myLocalHost) {
 247.788 +    char tmp[MAILTMPLEN];
 247.789 +    if (!wsa_initted++) {	/* init Windows Sockets */
 247.790 +      WSADATA wsock;
 247.791 +      if (WSAStartup (WSA_VERSION,&wsock)) {
 247.792 +	wsa_initted = 0;
 247.793 +	return "random-pc";	/* try again later? */
 247.794 +      }
 247.795 +    }
 247.796 +    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
 247.797 +			  "random-pc" : tcp_canonical (tmp));
 247.798 +  }
 247.799 +  return myLocalHost;
 247.800 +}
 247.801 +
 247.802 +
 247.803 +/* Validate name
 247.804 + * Accepts: domain name
 247.805 + * Returns: T if valid, NIL otherwise
 247.806 + */
 247.807 +
 247.808 +char *tcp_name_valid (char *s)
 247.809 +{
 247.810 +  int c;
 247.811 +  char *ret,*tail;
 247.812 +				/* must be non-empty and not too long */
 247.813 +  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
 247.814 +				/* must be alnum, dot, or hyphen */
 247.815 +    while ((c = *s++) && (s <= tail) &&
 247.816 +	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
 247.817 +	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
 247.818 +    if (c) ret = NIL;
 247.819 +  }
 247.820 +  return ret;
 247.821 +}
   248.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   248.2 +++ b/src/osdep/dos/tcp_wsk.h	Mon Sep 14 15:17:45 2009 +0900
   248.3 @@ -0,0 +1,50 @@
   248.4 +/* ========================================================================
   248.5 + * Copyright 1988-2006 University of Washington
   248.6 + *
   248.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   248.8 + * you may not use this file except in compliance with the License.
   248.9 + * You may obtain a copy of the License at
  248.10 + *
  248.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  248.12 + *
  248.13 + * 
  248.14 + * ========================================================================
  248.15 + */
  248.16 +
  248.17 +/*
  248.18 + * Program:	Winsock TCP/IP routines
  248.19 + *
  248.20 + * Author:	Mike Seibel from Unix version by Mark Crispin
  248.21 + *		Computing & Communications
  248.22 + *		University of Washington
  248.23 + *		Administration Building, AG-44
  248.24 + *		Seattle, WA  98195
  248.25 + *		Internet: MRC@CAC.Washington.EDU
  248.26 + *
  248.27 + * Date:	11 April 1989
  248.28 + * Last Edited:	30 August 2006
  248.29 + */
  248.30 +
  248.31 +/* TCP input buffer -- must be large enough to prevent overflow */
  248.32 +
  248.33 +#define BUFLEN 16384		/* 32768 causes stdin read() to barf */
  248.34 +
  248.35 +#include <windows.h>
  248.36 +#define _INC_WINDOWS
  248.37 +#include <winsock.h>
  248.38 +
  248.39 +
  248.40 +/* TCP I/O stream (must be before osdep.h is included) */
  248.41 +
  248.42 +#define TCPSTREAM struct tcp_stream
  248.43 +TCPSTREAM {
  248.44 +  char *host;			/* host name */
  248.45 +  char *remotehost;		/* remote host name */
  248.46 +  unsigned long port;		/* port number */
  248.47 +  char *localhost;		/* local host name */
  248.48 +  SOCKET tcpsi;			/* tcp socket */
  248.49 +  SOCKET tcpso;			/* tcp socket */
  248.50 +  long ictr;			/* input counter */
  248.51 +  char *iptr;			/* input pointer */
  248.52 +  char ibuf[BUFLEN];		/* input buffer */
  248.53 +};
   249.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   249.2 +++ b/src/osdep/dos/write.c	Mon Sep 14 15:17:45 2009 +0900
   249.3 @@ -0,0 +1,59 @@
   249.4 +/* ========================================================================
   249.5 + * Copyright 1988-2006 University of Washington
   249.6 + *
   249.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   249.8 + * you may not use this file except in compliance with the License.
   249.9 + * You may obtain a copy of the License at
  249.10 + *
  249.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  249.12 + *
  249.13 + * 
  249.14 + * ========================================================================
  249.15 + */
  249.16 +
  249.17 +/*
  249.18 + * Program:	Write data, treating partial writes as an error
  249.19 + *
  249.20 + * Author:	Mark Crispin
  249.21 + *		Networks and Distributed Computing
  249.22 + *		Computing & Communications
  249.23 + *		University of Washington
  249.24 + *		Administration Building, AG-44
  249.25 + *		Seattle, WA  98195
  249.26 + *		Internet: MRC@CAC.Washington.EDU
  249.27 + *
  249.28 + * Date:	26 May 1995
  249.29 + * Last Edited:	30 August 2006
  249.30 + */
  249.31 +
  249.32 +/*  The whole purpose of this unfortunate routine is to deal with DOS and
  249.33 + * certain cretinous versions of UNIX which decided that the "bytes actually
  249.34 + * written" return value from write() gave them license to use that for things
  249.35 + * that are really errors, such as disk quota exceeded, maximum file size
  249.36 + * exceeded, disk full, etc.
  249.37 + * 
  249.38 + *  BSD won't screw us this way on the local filesystem, but who knows what
  249.39 + * some NFS-mounted filesystem will do.
  249.40 + */
  249.41 +
  249.42 +#undef write
  249.43 +
  249.44 +/* Write data to file
  249.45 + * Accepts: file descriptor
  249.46 + *	    I/O vector structure
  249.47 + *	    number of vectors in structure
  249.48 + * Returns: number of bytes written if successful, -1 if failure
  249.49 + */
  249.50 +
  249.51 +long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
  249.52 +
  249.53 +long safe_write (int fd,char *buf,long nbytes)
  249.54 +{
  249.55 +  long i,j;
  249.56 +  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
  249.57 +    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
  249.58 +	   (errno == EINTR));
  249.59 +    if (j < 0) return j;
  249.60 +  }
  249.61 +  return nbytes;
  249.62 +}
   250.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   250.2 +++ b/src/osdep/mac/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   250.3 @@ -0,0 +1,43 @@
   250.4 +/* ========================================================================
   250.5 + * Copyright 1988-2006 University of Washington
   250.6 + *
   250.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   250.8 + * you may not use this file except in compliance with the License.
   250.9 + * You may obtain a copy of the License at
  250.10 + *
  250.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  250.12 + *
  250.13 + * 
  250.14 + * ========================================================================
  250.15 + */
  250.16 +
  250.17 +/*
  250.18 + * Program:	Dummy routines
  250.19 + *
  250.20 + * Author:	Mark Crispin
  250.21 + *		Networks and Distributed Computing
  250.22 + *		Computing & Communications
  250.23 + *		University of Washington
  250.24 + *		Administration Building, AG-44
  250.25 + *		Seattle, WA  98195
  250.26 + *		Internet: MRC@CAC.Washington.EDU
  250.27 + *
  250.28 + * Date:	9 May 1991
  250.29 + * Last Edited:	30 August 2006
  250.30 + */
  250.31 +
  250.32 +/* Exported function prototypes */
  250.33 +
  250.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  250.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  250.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  250.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  250.38 +		    unsigned long csiz,unsigned long fsiz);
  250.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  250.40 +			  unsigned long fsiz);
  250.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  250.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  250.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  250.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  250.45 +char *dummy_file (char *dst,char *name);
  250.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   251.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   251.2 +++ b/src/osdep/mac/dummymac.c	Mon Sep 14 15:17:45 2009 +0900
   251.3 @@ -0,0 +1,295 @@
   251.4 +/* ========================================================================
   251.5 + * Copyright 1988-2006 University of Washington
   251.6 + *
   251.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   251.8 + * you may not use this file except in compliance with the License.
   251.9 + * You may obtain a copy of the License at
  251.10 + *
  251.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  251.12 + *
  251.13 + * 
  251.14 + * ========================================================================
  251.15 + */
  251.16 +
  251.17 +/*
  251.18 + * Program:	Dummy routines for Mac
  251.19 + *
  251.20 + * Author:	Mark Crispin
  251.21 + *		Networks and Distributed Computing
  251.22 + *		Computing & Communications
  251.23 + *		University of Washington
  251.24 + *		Administration Building, AG-44
  251.25 + *		Seattle, WA  98195
  251.26 + *		Internet: MRC@CAC.Washington.EDU
  251.27 + *
  251.28 + * Date:	24 May 1993
  251.29 + * Last Edited:	30 August 2006
  251.30 + */
  251.31 +
  251.32 +
  251.33 +#include <ctype.h>
  251.34 +#include <stdio.h>
  251.35 +#include "mail.h"
  251.36 +#include "osdep.h"
  251.37 +#include "dummy.h"
  251.38 +#include "misc.h"
  251.39 +
  251.40 +/* Function prototypes */
  251.41 +
  251.42 +DRIVER *dummy_valid (char *name);
  251.43 +void *dummy_parameters (long function,void *value);
  251.44 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  251.45 +void dummy_close (MAILSTREAM *stream,long options);
  251.46 +long dummy_ping (MAILSTREAM *stream);
  251.47 +void dummy_check (MAILSTREAM *stream);
  251.48 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  251.49 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  251.50 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  251.51 +
  251.52 +/* Dummy routines */
  251.53 +
  251.54 +
  251.55 +/* Driver dispatch used by MAIL */
  251.56 +
  251.57 +DRIVER dummydriver = {
  251.58 +  "dummy",			/* driver name */
  251.59 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  251.60 +  (DRIVER *) NIL,		/* next driver */
  251.61 +  dummy_valid,			/* mailbox is valid for us */
  251.62 +  dummy_parameters,		/* manipulate parameters */
  251.63 +  dummy_scan,			/* scan mailboxes */
  251.64 +  dummy_list,			/* list mailboxes */
  251.65 +  dummy_lsub,			/* list subscribed mailboxes */
  251.66 +  NIL,				/* subscribe to mailbox */
  251.67 +  NIL,				/* unsubscribe from mailbox */
  251.68 +  dummy_create,			/* create mailbox */
  251.69 +  dummy_delete,			/* delete mailbox */
  251.70 +  dummy_rename,			/* rename mailbox */
  251.71 +  mail_status_default,		/* status of mailbox */
  251.72 +  dummy_open,			/* open mailbox */
  251.73 +  dummy_close,			/* close mailbox */
  251.74 +  NIL,				/* fetch message "fast" attributes */
  251.75 +  NIL,				/* fetch message flags */
  251.76 +  NIL,				/* fetch overview */
  251.77 +  NIL,				/* fetch message structure */
  251.78 +  NIL,				/* fetch header */
  251.79 +  NIL,				/* fetch text */
  251.80 +  NIL,				/* fetch message data */
  251.81 +  NIL,				/* unique identifier */
  251.82 +  NIL,				/* message number from UID */
  251.83 +  NIL,				/* modify flags */
  251.84 +  NIL,				/* per-message modify flags */
  251.85 +  NIL,				/* search for message based on criteria */
  251.86 +  NIL,				/* sort messages */
  251.87 +  NIL,				/* thread messages */
  251.88 +  dummy_ping,			/* ping mailbox to see if still alive */
  251.89 +  dummy_check,			/* check for new messages */
  251.90 +  dummy_expunge,		/* expunge deleted messages */
  251.91 +  dummy_copy,			/* copy messages to another mailbox */
  251.92 +  dummy_append,			/* append string message to mailbox */
  251.93 +  NIL				/* garbage collect stream */
  251.94 +};
  251.95 +
  251.96 +
  251.97 +				/* prototype stream */
  251.98 +MAILSTREAM dummyproto = {&dummydriver};
  251.99 +
 251.100 +/* Dummy validate mailbox
 251.101 + * Accepts: mailbox name
 251.102 + * Returns: our driver if name is valid, NIL otherwise
 251.103 + */
 251.104 +
 251.105 +DRIVER *dummy_valid (char *name)
 251.106 +{
 251.107 +  char tmp[MAILTMPLEN];
 251.108 +				/* must be valid local mailbox */
 251.109 +  return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ?
 251.110 +    &dummydriver : NIL;
 251.111 +}
 251.112 +
 251.113 +
 251.114 +/* Dummy manipulate driver parameters
 251.115 + * Accepts: function code
 251.116 + *	    function-dependent value
 251.117 + * Returns: function-dependent return value
 251.118 + */
 251.119 +
 251.120 +void *dummy_parameters (long function,void *value)
 251.121 +{
 251.122 +  return NIL;
 251.123 +}
 251.124 +
 251.125 +/* Dummy scan mailboxes
 251.126 + * Accepts: mail stream
 251.127 + *	    reference
 251.128 + *	    pattern to search
 251.129 + *	    string to scan
 251.130 + */
 251.131 +
 251.132 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 251.133 +{
 251.134 +				/* return silently */
 251.135 +}
 251.136 +
 251.137 +
 251.138 +/* Dummy list mailboxes
 251.139 + * Accepts: mail stream
 251.140 + *	    reference
 251.141 + *	    pattern to search
 251.142 + */
 251.143 +
 251.144 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 251.145 +{
 251.146 +				/* return silently */
 251.147 +}
 251.148 +
 251.149 +
 251.150 +/* Dummy list subscribed mailboxes
 251.151 + * Accepts: mail stream
 251.152 + *	    reference
 251.153 + *	    pattern to search
 251.154 + */
 251.155 +
 251.156 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 251.157 +{
 251.158 +				/* return silently */
 251.159 +}
 251.160 +
 251.161 +/* Dummy create mailbox
 251.162 + * Accepts: mail stream
 251.163 + *	    mailbox name to create
 251.164 + *	    driver type to use
 251.165 + * Returns: T on success, NIL on failure
 251.166 + */
 251.167 +
 251.168 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 251.169 +{
 251.170 +  return NIL;			/* always fails */
 251.171 +}
 251.172 +
 251.173 +
 251.174 +/* Dummy delete mailbox
 251.175 + * Accepts: mail stream
 251.176 + *	    mailbox name to delete
 251.177 + * Returns: T on success, NIL on failure
 251.178 + */
 251.179 +
 251.180 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 251.181 +{
 251.182 +  return NIL;			/* always fails */
 251.183 +}
 251.184 +
 251.185 +
 251.186 +/* Mail rename mailbox
 251.187 + * Accepts: mail stream
 251.188 + *	    old mailbox name
 251.189 + *	    new mailbox name
 251.190 + * Returns: T on success, NIL on failure
 251.191 + */
 251.192 +
 251.193 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 251.194 +{
 251.195 +  return NIL;			/* always fails */
 251.196 +}
 251.197 +
 251.198 +/* Dummy open
 251.199 + * Accepts: stream to open
 251.200 + * Returns: stream on success, NIL on failure
 251.201 + */
 251.202 +
 251.203 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 251.204 +{
 251.205 +  char tmp[MAILTMPLEN];
 251.206 +				/* OP_PROTOTYPE call or silence */
 251.207 +  if (!stream || stream->silent) return NIL;
 251.208 +  if (compare_cstring (stream->mailbox,"INBOX")) {
 251.209 +    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
 251.210 +    mm_log (tmp,ERROR);
 251.211 +    return NIL;			/* always fails */
 251.212 +  }
 251.213 +  if (!stream->silent) {	/* only if silence not requested */
 251.214 +    mail_exists (stream,0);	/* say there are 0 messages */
 251.215 +    mail_recent (stream,0);
 251.216 +    stream->uid_validity = time (0);
 251.217 +  }
 251.218 +  stream->inbox = T;		/* note that it's an INBOX */
 251.219 +  return stream;		/* return success */
 251.220 +}
 251.221 +
 251.222 +
 251.223 +/* Dummy close
 251.224 + * Accepts: MAIL stream
 251.225 + *	    options
 251.226 + */
 251.227 +
 251.228 +void dummy_close (MAILSTREAM *stream,long options)
 251.229 +{
 251.230 +				/* return silently */
 251.231 +}
 251.232 +
 251.233 +/* Dummy ping mailbox
 251.234 + * Accepts: MAIL stream
 251.235 + * Returns: T if stream alive, else NIL
 251.236 + * No-op for readonly files, since read/writer can expunge it from under us!
 251.237 + */
 251.238 +
 251.239 +long dummy_ping (MAILSTREAM *stream)
 251.240 +{
 251.241 +  return T;
 251.242 +}
 251.243 +
 251.244 +
 251.245 +/* Dummy check mailbox
 251.246 + * Accepts: MAIL stream
 251.247 + * No-op for readonly files, since read/writer can expunge it from under us!
 251.248 + */
 251.249 +
 251.250 +void dummy_check (MAILSTREAM *stream)
 251.251 +{
 251.252 +  dummy_ping (stream);		/* invoke ping */
 251.253 +}
 251.254 +
 251.255 +
 251.256 +/* Dummy expunge mailbox
 251.257 + * Accepts: MAIL stream
 251.258 + *	    sequence to expunge if non-NIL
 251.259 + *	    expunge options
 251.260 + * Returns: T, always
 251.261 + */
 251.262 +
 251.263 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 251.264 +{
 251.265 +  return LONGT;
 251.266 +}
 251.267 +
 251.268 +/* Dummy copy message(s)
 251.269 + * Accepts: MAIL stream
 251.270 + *	    sequence
 251.271 + *	    destination mailbox
 251.272 + *	    options
 251.273 + * Returns: T if copy successful, else NIL
 251.274 + */
 251.275 +
 251.276 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 251.277 +{
 251.278 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 251.279 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 251.280 +  return NIL;
 251.281 +}
 251.282 +
 251.283 +
 251.284 +/* Dummy append message string
 251.285 + * Accepts: mail stream
 251.286 + *	    destination mailbox
 251.287 + *	    append callback function
 251.288 + *	    data for callback
 251.289 + * Returns: T on success, NIL on failure
 251.290 + */
 251.291 +
 251.292 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 251.293 +{
 251.294 +  char tmp[MAILTMPLEN];
 251.295 +  sprintf (tmp,"Can't append to %s",mailbox);
 251.296 +  mm_log (tmp,ERROR);		/* pass up error */
 251.297 +  return NIL;			/* always fails */
 251.298 +}
   252.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   252.2 +++ b/src/osdep/mac/env_mac.c	Mon Sep 14 15:17:45 2009 +0900
   252.3 @@ -0,0 +1,236 @@
   252.4 +/* ========================================================================
   252.5 + * Copyright 1988-2006 University of Washington
   252.6 + *
   252.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   252.8 + * you may not use this file except in compliance with the License.
   252.9 + * You may obtain a copy of the License at
  252.10 + *
  252.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  252.12 + *
  252.13 + * 
  252.14 + * ========================================================================
  252.15 + */
  252.16 +
  252.17 +/*
  252.18 + * Program:	Mac environment routines
  252.19 + *
  252.20 + * Author:	Mark Crispin
  252.21 + *		Networks and Distributed Computing
  252.22 + *		Computing & Communications
  252.23 + *		University of Washington
  252.24 + *		Administration Building, AG-44
  252.25 + *		Seattle, WA  98195
  252.26 + *		Internet: MRC@CAC.Washington.EDU
  252.27 + *
  252.28 + * Date:	26 January 1992
  252.29 + * Last Edited:	30 August 2006
  252.30 + */
  252.31 +
  252.32 +
  252.33 +static char *myHomeDir = NIL;	/* home directory name */
  252.34 +static char *myLocalHost = NIL;	/* local host name */
  252.35 +static char *myNewsrc = NIL;	/* newsrc file name */
  252.36 +
  252.37 +#include "pmatch.c"		/* include wildcard pattern matcher */
  252.38 +
  252.39 +/* Environment manipulate parameters
  252.40 + * Accepts: function code
  252.41 + *	    function-dependent value
  252.42 + * Returns: function-dependent return value
  252.43 + */
  252.44 +
  252.45 +void *env_parameters (long function,void *value)
  252.46 +{
  252.47 +  void *ret = NIL;
  252.48 +  char tmp[MAILTMPLEN];
  252.49 +  switch ((int) function) {
  252.50 +  case SET_HOMEDIR:
  252.51 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
  252.52 +    myHomeDir = cpystr ((char *) value);
  252.53 +  case GET_HOMEDIR:
  252.54 +				/* set home directory if not defined */
  252.55 +    if (!myHomeDir) myHomeDir = cpystr ("");
  252.56 +    ret = (void *) myHomeDir;
  252.57 +    break;
  252.58 +  case SET_LOCALHOST:
  252.59 +    myLocalHost = cpystr ((char *) value);
  252.60 +  case GET_LOCALHOST:
  252.61 +    ret = (void *) myLocalHost ? myLocalHost : "random-mac";
  252.62 +    break;
  252.63 +  case SET_NEWSRC:
  252.64 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  252.65 +    myNewsrc = cpystr ((char *) value);
  252.66 +  case GET_NEWSRC:
  252.67 +    if (!myNewsrc) {		/* set news file name if not defined */
  252.68 +      sprintf (tmp,"%s:News State",myhomedir ());
  252.69 +      myNewsrc = cpystr (tmp);
  252.70 +    }
  252.71 +    ret = (void *) myNewsrc;
  252.72 +    break;
  252.73 +  }
  252.74 +  return ret;
  252.75 +}
  252.76 +
  252.77 +/* Write current time
  252.78 + * Accepts: destination string
  252.79 + *	    format of date and time
  252.80 + *
  252.81 + * This depends upon the ReadLocation() call in System 7 and the
  252.82 + * user properly setting his location/timezone in the Map control
  252.83 + * panel.
  252.84 + * Nothing is done about the gmtFlags.dlsDelta byte yet, since I
  252.85 + * don't know how it's supposed to work.
  252.86 + */
  252.87 +
  252.88 +static void do_date (char *date,char *fmt)
  252.89 +{
  252.90 +  long tz,tzm;
  252.91 +  time_t ti = time (0);
  252.92 +  struct tm *t = localtime (&ti);
  252.93 +  MachineLocation loc;
  252.94 +  ReadLocation (&loc);		/* get location/timezone poop */
  252.95 +				/* get sign-extended time zone */
  252.96 +  tz = (loc.gmtFlags.gmtDelta & 0x00ffffff) |
  252.97 +    ((loc.gmtFlags.gmtDelta & 0x00800000) ? 0xff000000 : 0);
  252.98 +  tz /= 60;			/* get timezone in minutes */
  252.99 +  tzm = tz % 60;		/* get minutes from the hour */
 252.100 +				/* output time */
 252.101 +  strftime (date,MAILTMPLEN,fmt,t);
 252.102 +				/* now output time zone */
 252.103 +  sprintf (date += strlen (date),"%+03ld%02ld",tz/60,tzm >= 0 ? tzm : -tzm);
 252.104 +}
 252.105 +
 252.106 +
 252.107 +/* Write current time in RFC 822 format
 252.108 + * Accepts: destination string
 252.109 + */
 252.110 +
 252.111 +void rfc822_date (char *date)
 252.112 +{
 252.113 +  do_date (date,"%a, %d %b %Y %H:%M:%S ");
 252.114 +}
 252.115 +
 252.116 +
 252.117 +/* Write current time in internal format
 252.118 + * Accepts: destination string
 252.119 + */
 252.120 +
 252.121 +void internal_date (char *date)
 252.122 +{
 252.123 +  do_date (date,"%2d-%b-%Y %H:%M:%S ");
 252.124 +}
 252.125 +
 252.126 +/* Return my local host name
 252.127 + * Returns: my local host name
 252.128 + */
 252.129 +
 252.130 +char *mylocalhost (void)
 252.131 +{
 252.132 +  return (char *) mail_parameters (NIL,GET_LOCALHOST,NIL);
 252.133 +}
 252.134 +
 252.135 +
 252.136 +/* Return my home directory name
 252.137 + * Returns: my home directory name
 252.138 + */
 252.139 +
 252.140 +char *myhomedir ()
 252.141 +{
 252.142 +  return (char *) mail_parameters (NIL,GET_HOMEDIR,NIL);
 252.143 +}
 252.144 +
 252.145 +
 252.146 +/* Determine default prototype stream to user
 252.147 + * Accepts: type (NIL for create, T for append)
 252.148 + * Returns: default prototype stream
 252.149 + */
 252.150 +
 252.151 +MAILSTREAM *default_proto (long type)
 252.152 +{
 252.153 +  extern MAILSTREAM dummyproto;
 252.154 +  return &dummyproto;		/* return default driver's prototype */
 252.155 +}
 252.156 +
 252.157 +/* Block until event satisfied
 252.158 + * Called as: while (wait_condition && wait ());
 252.159 + * Returns T if OK, NIL if user wants to abort
 252.160 + *
 252.161 + * Allows user to run a desk accessory, select a different window, or go
 252.162 + * to another application while waiting for the event to finish.  COMMAND/.
 252.163 + * will abort the wait.
 252.164 + * Assumes the Apple menu has the apple character as its first character,
 252.165 + * and that the main program has disabled all other menus.
 252.166 + */
 252.167 +
 252.168 +long wait ()
 252.169 +{
 252.170 +  EventRecord event;
 252.171 +  WindowPtr window;
 252.172 +  MenuInfo **m;
 252.173 +  long r;
 252.174 +  Str255 tmp;
 252.175 +				/* wait for an event */
 252.176 +  WaitNextEvent (everyEvent,&event,(long) 6,NIL);
 252.177 +  switch (event.what) {		/* got one -- what is it? */
 252.178 +  case mouseDown:		/* mouse clicked */
 252.179 +    switch (FindWindow (event.where,&window)) {
 252.180 +    case inMenuBar:		/* menu bar item? */
 252.181 +				/* yes, interesting event? */	
 252.182 +      if (r = MenuSelect (event.where)) {
 252.183 +				/* round-about test for Apple menu */
 252.184 +	  if ((*(m = GetMHandle (HiWord (r))))->menuData[1] == appleMark) {
 252.185 +				/* get desk accessory name */ 
 252.186 +	  GetItem (m,LoWord (r),tmp);
 252.187 +	  OpenDeskAcc (tmp);	/* fire it up */
 252.188 +	  SetPort (window);	/* put us back at our window */
 252.189 +	}
 252.190 +	else SysBeep (60);	/* the fool forgot to disable it! */
 252.191 +      }
 252.192 +      HiliteMenu (0);		/* unhighlight it */
 252.193 +      break;
 252.194 +    case inContent:		/* some window was selected */
 252.195 +      if (window != FrontWindow ()) SelectWindow (window);
 252.196 +      break;
 252.197 +    default:			/* ignore all others */
 252.198 +      break;
 252.199 +    }
 252.200 +    break;
 252.201 +  case keyDown:			/* key hit - if COMMAND/. then punt */
 252.202 +    if ((event.modifiers & cmdKey) && (event.message & charCodeMask) == '.')
 252.203 +      return NIL;
 252.204 +    break;
 252.205 +  default:			/* ignore all others */
 252.206 +    break;
 252.207 +  }
 252.208 +  return T;			/* try wait test again */
 252.209 +}
 252.210 +
 252.211 +/* Return random number
 252.212 + */
 252.213 +
 252.214 +long random ()
 252.215 +{
 252.216 +  return (long) rand () << 16 + rand ();
 252.217 +}
 252.218 +
 252.219 +
 252.220 +/* Emulator for BSD syslog() routine
 252.221 + * Accepts: priority
 252.222 + *	    message
 252.223 + *	    parameters
 252.224 + */
 252.225 +
 252.226 +void syslog (int priority,const char *message,...)
 252.227 +{
 252.228 +}
 252.229 +
 252.230 +
 252.231 +/* Emulator for BSD openlog() routine
 252.232 + * Accepts: identity
 252.233 + *	    options
 252.234 + *	    facility
 252.235 + */
 252.236 +
 252.237 +void openlog (const char *ident,int logopt,int facility)
 252.238 +{
 252.239 +}
   253.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   253.2 +++ b/src/osdep/mac/env_mac.h	Mon Sep 14 15:17:45 2009 +0900
   253.3 @@ -0,0 +1,58 @@
   253.4 +/* ========================================================================
   253.5 + * Copyright 1988-2006 University of Washington
   253.6 + *
   253.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   253.8 + * you may not use this file except in compliance with the License.
   253.9 + * You may obtain a copy of the License at
  253.10 + *
  253.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  253.12 + *
  253.13 + * 
  253.14 + * ========================================================================
  253.15 + */
  253.16 +
  253.17 +/*
  253.18 + * Program:	Macintosh environment routines
  253.19 + *
  253.20 + * Author:	Mark Crispin
  253.21 + *		Networks and Distributed Computing
  253.22 + *		Computing & Communications
  253.23 + *		University of Washington
  253.24 + *		Administration Building, AG-44
  253.25 + *		Seattle, WA  98195
  253.26 + *		Internet: MRC@CAC.Washington.EDU
  253.27 + *
  253.28 + * Date:	25 May 1995
  253.29 + * Last Edited:	30 August 2006
  253.30 + */
  253.31 +
  253.32 +
  253.33 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s:Mailbox List",myhomedir ())
  253.34 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s:Mailbox List Temp",myhomedir ())
  253.35 +
  253.36 +/* Function prototypes */
  253.37 +
  253.38 +#include "env.h"
  253.39 +
  253.40 +
  253.41 +/* syslog() emulation */
  253.42 +
  253.43 +#define LOG_MAIL	(2<<3)	/* mail system */
  253.44 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  253.45 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  253.46 +#define LOG_EMERG	0	/* system is unusable */
  253.47 +#define LOG_ALERT	1	/* action must be taken immediately */
  253.48 +#define LOG_CRIT	2	/* critical conditions */
  253.49 +#define LOG_ERR		3	/* error conditions */
  253.50 +#define LOG_WARNING	4	/* warning conditions */
  253.51 +#define LOG_NOTICE	5	/* normal but signification condition */
  253.52 +#define LOG_INFO	6	/* informational */
  253.53 +#define LOG_DEBUG	7	/* debug-level messages */
  253.54 +#define LOG_PID		0x01	/* log the pid with each message */
  253.55 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  253.56 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  253.57 +#define LOG_NDELAY	0x08	/* don't delay open */
  253.58 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  253.59 +
  253.60 +void openlog (const char *ident,int logopt,int facility);
  253.61 +void syslog (int priority,const char *message,...);
   254.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   254.2 +++ b/src/osdep/mac/fs_mac.c	Mon Sep 14 15:17:45 2009 +0900
   254.3 @@ -0,0 +1,62 @@
   254.4 +/* ========================================================================
   254.5 + * Copyright 1988-2006 University of Washington
   254.6 + *
   254.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   254.8 + * you may not use this file except in compliance with the License.
   254.9 + * You may obtain a copy of the License at
  254.10 + *
  254.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  254.12 + *
  254.13 + * 
  254.14 + * ========================================================================
  254.15 + */
  254.16 +
  254.17 +/*
  254.18 + * Program:	Free storage management routines
  254.19 + *
  254.20 + * Author:	Mark Crispin
  254.21 + *		Networks and Distributed Computing
  254.22 + *		Computing & Communications
  254.23 + *		University of Washington
  254.24 + *		Administration Building, AG-44
  254.25 + *		Seattle, WA  98195
  254.26 + *		Internet: MRC@CAC.Washington.EDU
  254.27 + *
  254.28 + * Date:	1 August 1988
  254.29 + * Last Edited:	30 August 2006
  254.30 + */
  254.31 +
  254.32 +/* Get a block of free storage
  254.33 + * Accepts: size of desired block
  254.34 + * Returns: free storage block
  254.35 + */
  254.36 +
  254.37 +void *fs_get (size_t size)
  254.38 +{
  254.39 +  void *block = malloc (size ? size : (size_t) 1);
  254.40 +  if (!block) fatal ("Out of memory");
  254.41 +  return (block);
  254.42 +}
  254.43 +
  254.44 +
  254.45 +/* Resize a block of free storage
  254.46 + * Accepts: ** pointer to current block
  254.47 + *	    new size
  254.48 + */
  254.49 +
  254.50 +void fs_resize (void **block,size_t size)
  254.51 +{
  254.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  254.53 +    fatal ("Can't resize memory");
  254.54 +}
  254.55 +
  254.56 +
  254.57 +/* Return a block of free storage
  254.58 + * Accepts: ** pointer to free storage block
  254.59 + */
  254.60 +
  254.61 +void fs_give (void **block)
  254.62 +{
  254.63 +  free (*block);
  254.64 +  *block = NIL;
  254.65 +}
   255.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   255.2 +++ b/src/osdep/mac/ftl_mac.c	Mon Sep 14 15:17:45 2009 +0900
   255.3 @@ -0,0 +1,39 @@
   255.4 +/* ========================================================================
   255.5 + * Copyright 1988-2006 University of Washington
   255.6 + *
   255.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   255.8 + * you may not use this file except in compliance with the License.
   255.9 + * You may obtain a copy of the License at
  255.10 + *
  255.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  255.12 + *
  255.13 + * 
  255.14 + * ========================================================================
  255.15 + */
  255.16 +
  255.17 +/*
  255.18 + * Program:	Mac crash management routines
  255.19 + *
  255.20 + * Author:	Mark Crispin
  255.21 + *		Networks and Distributed Computing
  255.22 + *		Computing & Communications
  255.23 + *		University of Washington
  255.24 + *		Administration Building, AG-44
  255.25 + *		Seattle, WA  98195
  255.26 + *		Internet: MRC@CAC.Washington.EDU
  255.27 + *
  255.28 + * Date:	26 January 1992
  255.29 + * Last Edited:	30 August 2006
  255.30 + */
  255.31 +
  255.32 +/* Report a fatal error
  255.33 + * Accepts: string to output
  255.34 + */
  255.35 +
  255.36 +void fatal (char *string)
  255.37 +{
  255.38 +  mm_fatal (string);		/* pass up the string */
  255.39 +				/* nuke the resolver */
  255.40 +  if (resolveropen) CloseResolver ();
  255.41 +  abort ();			/* die horribly */
  255.42 +}
   256.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   256.2 +++ b/src/osdep/mac/linkage.c	Mon Sep 14 15:17:45 2009 +0900
   256.3 @@ -0,0 +1,37 @@
   256.4 +/* ========================================================================
   256.5 + * Copyright 1988-2007 University of Washington
   256.6 + *
   256.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   256.8 + * you may not use this file except in compliance with the License.
   256.9 + * You may obtain a copy of the License at
  256.10 + *
  256.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  256.12 + *
  256.13 + * 
  256.14 + * ========================================================================
  256.15 + */
  256.16 +
  256.17 +/*
  256.18 + * Program:	Default driver linkage
  256.19 + *
  256.20 + * Author:	Mark Crispin
  256.21 + *		Networks and Distributed Computing
  256.22 + *		Computing & Communications
  256.23 + *		University of Washington
  256.24 + *		Administration Building, AG-44
  256.25 + *		Seattle, WA  98195
  256.26 + *		Internet: MRC@CAC.Washington.EDU
  256.27 + *
  256.28 + * Date:	13 June 1995
  256.29 + * Last Edited:	23 May 2007
  256.30 + */
  256.31 +
  256.32 +  mail_link (&imapdriver);		/* link in the imap driver */
  256.33 +  mail_link (&nntpdriver);		/* link in the nntp driver */
  256.34 +  mail_link (&pop3driver);		/* link in the pop3 driver */
  256.35 +  mail_link (&dummydriver);		/* link in the dummy driver */
  256.36 +  auth_link (&auth_ext);		/* link in the ext authenticator */
  256.37 +  auth_link (&auth_md5);		/* link in the md5 authenticator */
  256.38 +  auth_link (&auth_pla);		/* link in the plain authenticator */
  256.39 +  auth_link (&auth_log);		/* link in the log authenticator */
  256.40 +  mail_versioncheck (CCLIENTVERSION);	/* validate version */
   257.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   257.2 +++ b/src/osdep/mac/linkage.h	Mon Sep 14 15:17:45 2009 +0900
   257.3 @@ -0,0 +1,36 @@
   257.4 +/* ========================================================================
   257.5 + * Copyright 1988-2006 University of Washington
   257.6 + *
   257.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   257.8 + * you may not use this file except in compliance with the License.
   257.9 + * You may obtain a copy of the License at
  257.10 + *
  257.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  257.12 + *
  257.13 + * 
  257.14 + * ========================================================================
  257.15 + */
  257.16 +
  257.17 +/*
  257.18 + * Program:	Default driver linkage
  257.19 + *
  257.20 + * Author:	Mark Crispin
  257.21 + *		Networks and Distributed Computing
  257.22 + *		Computing & Communications
  257.23 + *		University of Washington
  257.24 + *		Administration Building, AG-44
  257.25 + *		Seattle, WA  98195
  257.26 + *		Internet: MRC@CAC.Washington.EDU
  257.27 + *
  257.28 + * Date:	13 June 1995
  257.29 + * Last Edited:	30 August 2006
  257.30 + */
  257.31 +
  257.32 +extern DRIVER imapdriver;
  257.33 +extern DRIVER nntpdriver;
  257.34 +extern DRIVER pop3driver;
  257.35 +extern DRIVER dummydriver;
  257.36 +extern AUTHENTICATOR auth_ext;
  257.37 +extern AUTHENTICATOR auth_log;
  257.38 +extern AUTHENTICATOR auth_md5;
  257.39 +extern AUTHENTICATOR auth_pla;
   258.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   258.2 +++ b/src/osdep/mac/mtest.sit.hqx	Mon Sep 14 15:17:45 2009 +0900
   258.3 @@ -0,0 +1,171 @@
   258.4 +(This file must be converted with BinHex 4.0)
   258.5 +:#@edCA0d,R0TG!"6594%8dP8)3#3""l`!!!"4[4p8dP8)3!#!!!Hm(*-BA8#bJ#
   258.6 +3!aB"#Jd!$'edCA0d,VNZFR0bB`#3%j@,!*!8"h-!N!6rN!4bFh*M8P0&4!%!TFk
   258.7 +UMDPEIVJ!!"f3!!#3"JEY!*!%`hJ!N!KIY3c!q+l(4rK4`['9YjP(D"GY*FH1(-X
   258.8 +cXLBR0(,Fbb2([#i[,dqCK"rKGS3@iEFb3JQeji4&VeZ[1Tp``PGTPS4GCi46F[`
   258.9 +)*dr*J*-T2h+-c2N46VMfC-$*Vi46-Z(N'*P4`L5F(#G2#5GiGT&MK"*'9LD!erG
  258.10 +CjLAcHUq9(@&*RN@fj0Ne))``F[c)XC9`B,`kD)!("P!!B+%+X!"Ij9MdF'6TDbk
  258.11 +eDS@rkBHYZjA")jZhqKjc,5mCd(FTrHqIGj@qeG-@lI&rjBp%)kdK&fVILa2,2T2
  258.12 +)Nrd4Q1G"rm8Y@pe%8-SkIQSGk2H@qIe3dIJcJrAH1R9c&i2J#HpTbZ[82H$e3hN
  258.13 +Gr+r1$kAiHS*IpmchqmF6`GH$qi)l!%)YfjZ9XS-II05ZY0Hd[$N205VQN@SCP1m
  258.14 +)Y64Y8k#VBqraRH@Q)09I"'0XA!G`I`Z`"YrDNrJL[SBi1UackpVJ'9h60qKDB,'
  258.15 +ZI9HZ+l((G5@JIUk!US1Z-MDXaLiE+K4V$)T"`eF&6AH$4eI`"F3!(Y2Kj)ABCH6
  258.16 +#b6&ffHN-mSr[[a($&e6dMmla&Iiep%rHVrQhHi#(0JaJe+#i-PJ&%!J"P1Cl!ep
  258.17 +YQ2T$jSEJi2Z0c+hDh!RbcmB"'fT`%@-'kLB+!r6'c4USMFh0fb68Y(llUk)VPLr
  258.18 +Ed,hR3+5c[D2(piA[kG@V9rTHlZTmZbd5lH`ji1X1qelC&HhSl'V[kHkL2X*kMAQ
  258.19 +aAlcJMXYmY&+R(%SV"d9HaYKaMM2'05VCQ-Q6Z-8I6HNNK$jrP@'C#fhdRG$`*Iq
  258.20 +%&@Cib6p[RSd[23pm09LaTDQaQHE,TKFhEZ)8(AZN&j&$@cB%&dm`1'D23KiA`i4
  258.21 +k2MCcJkB$!`hclN6Fi$P,$&'1lZ1NTbALF5'11FV9NaR+!fJ,m`$QQX5KhSi!*8i
  258.22 +0H"P%&KpL"M!d&Sm2'A1eSI*J(ND+Nh2H4CbM[(`bCJHJ,N8-+K58K!`YM1)PBC(
  258.23 +MF0C+`KM%5qDK'9kBG#fF$!KI)Lr"'SQFp+A[c%U3!1a*+dC(4bhbb%J@6`TE[35
  258.24 +MM(Nm(X4XR"M-a)90**KqZ"l(V4#iN!!lHpDXM)NM`EB,Cr%6K!Nq4h*KmA)pB*I
  258.25 +)`FD3!b4&J$+3!2'`Cjcj!bJL9'E`T&l56UjPreMAX3FQ,GJZd#hK9K%451'Ll4J
  258.26 +[Q!K6EaUrTfIlcI)Grdj,Q,L8F($6rf6,&2hjQq2Ql%alc$FQUj8Y-F8G'4R*miZ
  258.27 +6r#N"Nhme6(qhkM0Gm4bIGkdBkR++CrL5,4D&DElPi!UIMbP,)&-ICUi63Q#+l`6
  258.28 +Mr0435I-cJc8P-0hc+6l8CL,C!fPlFU@j0YHYP5HlVH6iFMqck@,jbDiKPVai*iE
  258.29 +U$Ik%rBbr0$p6)-ka&c4LTeHf'r90kr2kc1PIL8)!1m$[-EHZbBe6E*MC$6#jJ*S
  258.30 +D5ADDE#fUXfa6S4$,$R1GEqqVFra(qSj!BB$kcE6AAIeme%lY-+NSX$"!#a3%h`&
  258.31 +Q*k"SP1XGG*8[q[)kriiqr[N`q606mMGrMr6Ym@A(IIpC!`re#`28larr"3,URqc
  258.32 +[!JVpml$rlr*6*KrShqr[f3f'4hk$ZAhbP(CPb2rrCL3-m3pHa&&p!ZrP1,mSX("
  258.33 +(RI3Qr550fhJiM2F2G!"KiYhmHX("5F#`F3Cii$"NqG''q!Q&BH'NM`)*!fm-NMJ
  258.34 +G#iK#50`+6KKLT8)))B%,06GHI$PV%q'LL"-iAR[``!-0+5$5!(j#))h,X24N"1M
  258.35 +Z3b$mh!-#ETlA5jqQAj-I-'p$,*iGIjfpb3C00LpePpdq'U&fJp!9LaP)F'!L&(#
  258.36 +B-5QFhja-i,Ii3Z#f[f4jF[adr42@M*(aS%(r(cJ$V%XHH6)M*j%XNB0M090iPKm
  258.37 +LA!c@+El%Er(aKNG'k+Uq'6Iie,4jIhRpArhcH[pGRlRkjh#kDmVcVp8l0@+3!*-
  258.38 +C-3dda3h982@pIFIkIZcpjA`I1q0HjqjcpETeZPLFAMG*`Fd9K!Ihi0Vp`bA5LG*
  258.39 +hUZq8VJ`VcUpGcBK0cMcR"h&$E,bKHRr0IYFEPf+ABZGi0Kklp*kV`G9iZ[%FBMH
  258.40 +rb60J'$JdYQJ98C5$i*'hHLqX$cj("j*GmUV[S,cU1p,C'LAqPjfYZeGLrMhLP&p
  258.41 +!I"@iP2Q)8riXB-@A8,d'p(lS*8`T3Z`S(+*+ZVBKKRHdK,Ph`N#[r#[[UN(HZi,
  258.42 +RmL$f+@NM9SlBFD(YENEXX0#SAS2B+U&4(82X+D&4I3Da#U&48BGBJp#BAipB3'K
  258.43 +82B2B3PQ$$a&l6QJ8DBJY%4T&Rb$Q&4UHaBLY&4UP5a&E)65mYBK9#BhL5X4@#Sf
  258.44 +5"BMjK)Dk#,(5*lDrdp8@m8ADSYhl)UeYr`%0!!GYG'9cG#kj3)#D#J&2H#J!&c6
  258.45 ++!*!$J!#3"!&EEhJT,!#3%4B!N!MrN!438Np+5d&)6!%!UKPEcE$CcD)!!(*+!*!
  258.46 +'&`d!N!3HUJ#3#1[c$J#9qCRFXlGVCEICCSIR+lY0&eVRAMZqXX[00PXS2r@Df1A
  258.47 +KkHA*"VNBTjER*iZH[pFm&Z8ZE"qcfblm[',l@,%Y@BlrBZI+'dRENNhB`TG6`U+
  258.48 +%rm+qcS9IXHh##19fLpl##EGFH-DfXHfjAGJq`Xl0#&Z"UN(Pee&qXHelQ@6(IQ(
  258.49 +lb#E,Nrd4YNmb@CI$RfG![9r(Q-!B#jFc&X+DS8F3ArE,60Kl5)j0,',#3EXF'lA
  258.50 +Ff"lcGF6XpqJ3VDZ[VCVRG&G6"[,RPeil*ApGbRl6q$rjPKb*9Y(1D'@k1jk56ib
  258.51 +Eb(5E,A,-M0L$VA*XbY0-Yr-@1CBlLqRfhkE85@)CT[d855D6KeK',QTi*XDBC34
  258.52 +L5e$cI81&5RrqMB2Q!HmIb'5XY(jK24d42+cfld3SK%*fYiD6QclP6#EAG(r)aeP
  258.53 +A9eeCik`c3H*Pl-%"%f1(rd'SBd9bYr%[Ke#EaC*,Y$c-`"ZCB(aPl&BS5Mh,BLD
  258.54 +N0[#0c'FQ[EfTSphSF9G+mm35REeC$@ABQb1@KQ[EQd)a(q9fL4i("NpNfN2KQ-m
  258.55 +SrQ-S(2)pT,1(,a$YBE%N(&VZLmCm8CdpQL8R8qpEN@Q2GN5E4pEl1X,aD,-2+*'
  258.56 +J,iSDk,LB&@mhVGUh%i%T`9"c@lc&*aE90$@hqTTDI0'15bkj3XE)'FC`$f"%"*l
  258.57 +1P"DI2aMbLE&Sh#I+hk8AU)Im6@dGbUP#l9$8Yd)"kNG#BZUa&")[D50+5NM)&9b
  258.58 +(+Q,e$K1L)[VIr25C($[MAIaX"HGhq)+1&j!!e[2jJj+Bi9hm,'b0jr&KUjKP@[a
  258.59 +prP3lUX&jI')FUX(jqP([8`qIabF--RE1iir'PSMXGrLk$$B+fa(Rm6-0[2G([SX
  258.60 +r"YZFmrJ'bKlZfl[ie([83qIV4le(06c22e6lh(IaUAI([SY2[8XIeB'afAb9Ir$
  258.61 +Df*FU$RcS#1"L*RJ,Ea'm-fRG)RJrZ&A`AVj,m,SFJVIm#X%lcb9ikpb#ep-PH+p
  258.62 +#E1P2"'r!,RL[ALpi`bm+hXK8V%Z`hSce%F(lBEhJM4F*hQXl"Hp(eQ,G*(MAbRj
  258.63 +Q$[XD'T2@ZpNUa&HaZ`@Ri-$UI+HX[rmZrkFkaRE&f&5@+e`QI%6A4AYGekUNX",
  258.64 +a$f$r%H%$&&q992!JbRG&K)XDRZXL%808*$F5I@jPT8B8j'B8aRlIb[FAeAq55dH
  258.65 +1L1MQrZMBlqI#N6heG3RbIm0h"PIj6mS9SQrVVEIZf)'ii2IIHL[fZKNcr(lX)9e
  258.66 +Qc0LaJqPIj*p+"@Tqh$jQE2+q8I`V51f,88$DMjNaBmC[idIcNIFrX['[3-eISDr
  258.67 +,(liA2GB#PGG%M!Y$j0I99(,S4!lH0"+9j69jk$RX1"[J-k&q&K)M!KJPmk2bp!&
  258.68 +6A(i)A$f%aJ9#mk**M)h2!k&-a+NY%$!d(f"'9ic!cqF$K"F86-V-6b31L6b5G`0
  258.69 +1M&'($4C$r*(IEi'!bf%jZAp2)MJRAj%!m+V!I53X6@!NNPIi-M$VJ*EN'9#9N!"
  258.70 +a&YKjY(!C*kkY+8YVm&1V[[Q*Em&G4"8%*T5f,[#88kD'H-`rfpl-l%cSlTfdA9f
  258.71 +"JHN(J%eSm*4@)PpM4k`P',DM)A3i[eTGJ6&"`DPF8NCpe"&Fi@Z-%4"P0#'KVZJ
  258.72 +[*D-5cj9JHF(B(,XfiL-JBI-6ph@T+dUX9+M'@9P0&@T[#VEaI(3iraee4Fp0i$M
  258.73 +,UZ%S8Bqf"80A0`@dM*j99r5IR0'bfSC5UT%ah0(LLr"D$Z!BeBaU'aTVU*EKMXE
  258.74 +fTQDHHdChlq40kSUZ9+[Z+8@0""1kSbfiP#2TZlpQQDfZk&!&D9'*Qh46eMA0V8e
  258.75 +4Z8%STi[9&If[j942(BHFSX&33-Rq5%lCFLGG'%BMSCk#N4UTJi!'FlG!4h'FNPU
  258.76 +T&$KMB#kf"'2"F+LT$GjI0$b-H3($G!YKeP3ZTYbbDi+G[TDDF![[Um`"V"&D(HU
  258.77 +G[+-pdDB)cfQ`AL29cPmJ9B,h"%-m&1`FlT@F&1Fi2G6j(E%QQ8Nbd5%AUL[i8-(
  258.78 +a90C32aYL`ACH(TD"2Rj'AF'05MqA53XEUIGmSH9U3qZ"%&GA'!MMC-i"%Nd8C3+
  258.79 +*ea'RPkXVE!)&TEc"6VT5lqI&(N)CUk&iURNZrKLR,d,jQ,S#3d'4UZ9F3M,(%FV
  258.80 +(eC9GU+*i5ZTi,V&QcP[%Ek[9&GfJ-QCP3`PRc'!(&4QFM[2Ve*@09rUKYEkmK,M
  258.81 +I&28hchBiC+i'`RTe"FjV+U%9HSK`lP&ApKk`"H%%+aYUUF2-`Bj`iqcCPhd3LN,
  258.82 +1kAje"C+FIA"HE5A2rZT`F(CM&%M03dM[I4dTVL&p3ehC*"A*8pR!1c`@l'LFj5M
  258.83 +NkEqTJp$a'"p6ZV5kJEM'l'p6q*CA,Zf!&T,VPY)iT)9HdcLY3aT(IdlMC*l91)C
  258.84 +c'SI8d"Q0SkQK8aT(8d1R0)ljV-E*rSh'XIa+iea`9Z-S@ZL8aY'dd%Q0SfQKNaT
  258.85 +Re$Q0-rUdaY'8d!Q0Ne*#ac@1TS41D"a0#Ch31"HHd$LTbPMIi(A9bcQQ#EB&8Yl
  258.86 +)!#XVHU$IbG$d`+Y1aS"Zd*h9$4RRG-22[C'MZL&GXcGbh(&BhDmZMP6LeqTL3!Z
  258.87 +3!,Vi$jq8e-8C,D#ULhHdJ+BZ6QN"FK[He!*(0&$+EAM94dkhicBF8D$pEJ-T8*C
  258.88 +5S1Q2e-9E@Z!"ZL1#F*R4@q-TDk#qP#q[J"K)kc#&J8b@U#Yh(T@-+R"h"VJc'!$
  258.89 +*DASST808jr%G6d*c(NrT%10C(8*+i)`1k9F#*cd*c@NiT5kbckN,bePeFF&[e-@
  258.90 +)AkN,43fF8KHD'MMT5@KUi+4U'(e@0B`jTaSd2A"#0D6d`((9S1Q"%kT"d`-R9)2
  258.91 +e,GA`5krK4R90H3d004jd,$UX28B*bA-BIkkZQ-03F#4*aJQ&9*b"MU8C$*NYbQT
  258.92 +ULE0UI1hKk,9DjLPPmpjMbNE12-AUkJ6'+kcqpJ6'YQ$+$aQS@ATZYc@P3c3rC%L
  258.93 +(r,IEQY)KQJ*kABHNU[JH051TE"%j+UD3!1mDA*QLCE4'AE8j0#"j1,H'I,(f$TR
  258.94 +G"QG*hRYLPQ63&Cjdc"@QUC)hAH(GfKcDXY)&0930FdZm[4fha2bA-j`f@JNpVDk
  258.95 +D%P*jhFKjr98(HI`aII2fr1Uc#2q-&rQ-E(I[HlDS+e!8$X09@*c$fS,Y`4Ke#8I
  258.96 +Ulf&00mJp,+Jp$*ErT@iB8#+N'hkQ4)5[k"mS9eIS"Xk+eVdecK+`M$!'9)Mf+JQ
  258.97 +hYiG$(T9*G32-C$M0T,SlD`pZ89GYbZ3(5TiQ18m!03haSqNSRfY91+SPIXR0U5Q
  258.98 +6YlNj@mf*lLqMR*b45*[2dp4fp@Yk3R(dDKX@8%@cX)m&fhK@`PHZkhT%AD%LE(+
  258.99 +218Y,FEHFN!$ME'Q*qMSk&VFe8G2)+KhG1%eGY5Q6[@J4Z9lBZf5pqEU[A&V@!08
 258.100 +R'%Tp(Ea83afESpCerS*+F*f3!$dr(QbqZLADG-fV26#+L30B)c8XMkq6#j!!`6i
 258.101 +BVH*95KlUQC'9S9LEHPrD-(Z3!0I-mFS@P[(jKV,P[K"RaHK3GA09T0+bKF4K@D@
 258.102 +qjF(AFaUVpN&jC6ARM2*JQi`c@0YaDNB0C498Uk`'Ak!kh06bDNBADVPA1MP5DE#
 258.103 +T,4`BcXQU)LfUj'bBY5JBDJPI-maBip8Z"'m5BjM"Ql&SQ&1'EiLab(e4r'*T!9@
 258.104 +daKH+$fG2p`$)c&DfQ1G%69S'0ZBj(I1JbqVVZ3GG&Sf'Sj688EHD2'LjRq4+'FY
 258.105 +4+CRC"R$)JjElU84@k3h0d@#%FMqDd@5Y6V@eR&NpiA#EaTH$[5F1e65EDRS-kb+
 258.106 +e!Z@9Lk('K+cbB'G08ka9eA[2U5Xi@0&Yi&,jaS,QL+Tr"cfA+FFm&rZ3!1FbpCc
 258.107 +RmVkcRN[H1FrPMmjj,[RR2*GTjcbALpr`A!Ca,MRVG8ar`qXBp$$HIml$X*rf-!T
 258.108 +1HaL&Tcf-5dpl')l6dfdc6Xc1lPCA0[2Rr8$cE!1GFjQ+9+i`Lepe,BiLcG+3!$c
 258.109 +92#G8qdK1+IllJ)SN9FXjK63JM[4[kSUEPBjaVj*6bVhjS-U8cJ8HkL*M8cc@fN%
 258.110 +ia*3TR$QUHk[JQ!QR%3VYpI'A)`l1pDRjPlVDZKR8AC&`C)CfadP+"j!!krZD$QJ
 258.111 +HdJ%d!hK'"kLhMlbM!l6E4dlT!2*pcmcjTLD#hjRce5D#6bQ'IZIhT',)1Z[5QRr
 258.112 +MdQUZc5qFS04%i0Y1N!!b$haUcPHE"cijjjY@jrD4JFN,ZRhNcCRmkp8e0Imb`1R
 258.113 +UY%JkJ[QAe&4,rrc,bDQ@LHG[5,P[VHBk(kfEiMUREjK9'H!ZcA0qaF91KcHhR&j
 258.114 +P9L@P4XJl2U0'IMkYm[EG*cHQ[)k"1HDd$kSK6Hq%@qTZ!XhV',UE)$h"V1raQ`6
 258.115 +)D98bT,FH8-F&fjXL-k1A+[HTT'R3&cbMY,bZa!Te6EN54eRpIqj6qBA#+(a$B@b
 258.116 +kmKXdUc'1pqCiTp4!rVUHliGR2&681hq`KVK@4[e"U962kp`5LYV[HFYMj6a!DSC
 258.117 +ij9rP'9A'Ce5*@SlRqcTbPSVXk,m8rjAkMQrm6UUq-NFa2A%8CQ+2ZcSI5qQZS6X
 258.118 +AdR2l1[pjBfBUCdee$GqiFP`hV$QL'`CQ9G)6h,apG+SfrI$0fkN*0-f[16@"4MF
 258.119 +3r1m%fMVY[L5icNlFfm$-(AK4$hLChK'3!+EJh[idd'qB`$I%#2,M6%akN!"U#)p
 258.120 +,qVqSJrqI(QlqArf8"brKC8[r3[T,rV)Hf6b-Jjj%IZ`a#hm3'K2Um0BX["Z+ap$
 258.121 +2Zr*CM(8*&HaQi4RX+i@2#jm4RXC,X&B,EKjG,r`9R4"fim`DS3+ReJZI%'l$UGh
 258.122 +#-cLcFIM-TiHaEdlPTV`c5hk9dfmr[*XU$F&(6`f,+$&b4N3QcX9E+,[hCEiSl`d
 258.123 +kC6p1f6Z8IDZbAk[X0bRlEmVlV&*j6hbLj(GfRl83'pkeaclq0#PATlRUVaq4HPJ
 258.124 +VeXlT4ELUF,(8Bj3UqT)2jUh(lZYjeq&NPp56FEI8Bc)JpM,@ql(QZ3,ZcQ65(@C
 258.125 +kpb*h*a0XFj+ET*l-Uk5[@CRBcYUNQlVhimaY!401ZHQ8&*pr`(a9K%NpqJF$KUU
 258.126 +E!VT%T43ACjXlr51Q&bfTPFUN(N1[D2%DmSV&5jL)r0ejA9*mHP'Tdq2%fE[&DPY
 258.127 +RPNR8*qbSdM+F,mblERS4&(8$6Yq#q-5mp8#V,kY'I+eB,HS$&UP(pe8pNCl&[er
 258.128 +U-mk8&LDIG"l)bV(94X5%25,X(,9N91p@CamE(FP-f"GX3%9ehAmTA5A&q4[r@%@
 258.129 +Im5Gj@m`Va8jcjprbPfi'6$McI0iGE&c"E(1AAlGiJa4I[-(p[H5"+`VBE+Uaehc
 258.130 +PKJ*6paI&bBRL3L1kjr&!@dAIiH[ceSSjJHGXa9@ImYX6da+9diY+H+dbR`j8%lC
 258.131 +D-IDN9V%H`aT8F+@iiV!l%F56bSaqID)P-3eRRVH&fF`rA9G3b@C9ljkFp'bSQLf
 258.132 +m2k$V6NVab-MZKaG[%0'EPMVTS(p%SBJDe!If*#i'ETIpXe)FrB-B'd&p`k-6dBP
 258.133 +cM$Pi)*G$l04p+@,CHG2Q,ET0IK[U[MIa2V(1jVCC[@ER(QD+#GGCGfkIrh"brde
 258.134 +VGklckk5iM5AXK#-+LDQfZYUANP[&@YFGE25P3I$4Z-4BejIG3@B4DlYIGPK4J4H
 258.135 +R,RjXfdbVc4Uk)Q#VG`C'BmeEk-69h&p&K$&8a*'I41eeKakYef)lqQ1pMfj+(UD
 258.136 +kk6BkTM&,94!c+k,(Y5bRhZA[M$4h2icp!F)$`Xfph@b%%VZ6BKCAmP"JDAXV-24
 258.137 +dVZ6(9Yhpmrdl,%ecLr`2iT6"[)aGQ$cXZ'LadlELd-lH6ffXkXqpYIF6F[C+I+B
 258.138 +D4bbImP2MkPl*Ear2l`ANPT%mj,MS3j4EV2G6[F$B@(@C-hPijVh5Kj%91N4iTZc
 258.139 +(9[EBYfGD!`jdbG6!L(UR2eI19pMMY5U4(Zm)*E,G#fi@RNA''p'0P-(M9$&aa8m
 258.140 +2Lh0qHVMU$V"@[L1Ij3GX8r1Cp8TAb3pCcU0lQ2ka+af(jKDjaSrH`bjh(1VH0pr
 258.141 +ThiXH,qEm8qarN!$Rd)-FHU,*'10j6,JrRehZcjf&E0`2"#bl2REA(8c[dp[biF+
 258.142 +QN!"h!IF[a,T)cXDZjpF9ER[q4ZEUBSAEN8pGP$QXK9CGmDVNppDK0m5CSlbMEG1
 258.143 +BIZ0DacDUKQ-lVm4$bEhH@@*1BS&BI"64%T31-Ph!1K1Sk)&4lNJ1)e6TS'dhF2H
 258.144 +*FjKC,2EVQJ`5[E#4&4BPl[YmZFe8@(6(ClpFIYIDJ!&m2pdV`R[3#`8qLYUmSa(
 258.145 +9+9'V9irGT*+qj(EE@LQHZ%q+lcq!$Pr"G+DY,%2k-`E@!mFAPG5@PXePh3QaX3k
 258.146 +m,jUNH2k+[SffkNr[qZlU*lBpZS[(9f`ra)TY-ke@a0EdhXc2q*8cTSdpIF[i#Bp
 258.147 +b)UHhTmr$6lL8%hS$[9BQKaJQq6Q0lp$ab5eH2AD2%qZJXaSGeTR@cBXA2CcXUh)
 258.148 +&$N[la%2+Q9[kcr3TCe`Kmdh1GX21BZFqTL[-SE13!+i&6&rJC(TE!6-90%,EIDm
 258.149 +)0Q1Hi(CprB&mGV(J,R[S'lY+h5kADqZfR@ZUGl-Lff4NrJVUT9"jl$-i[rkYmbY
 258.150 +&i56#p*2R,DN-UVU@6DaD[Fa5fP@k'LG&l1+P8+jX($m4aeNc2fR!UEJG,mj-*Zr
 258.151 +UDMEB)0fPq1BEPPUkYVQ,(Fa9l#k@iRIGX(5#RFISP,[L#ZDZq15f3U1l`Q'8iY3
 258.152 +4ckjpGKe3$R4YfhU$)f2l9RZ'Zq+4VHk+hKYmTSeVPZSTjiCLlh-ICD3)`4@'Z8E
 258.153 +`a'451AR&L'GhIc&[XTLGRe&Im9*&IF8FShIF!-VDqJV$GAMQhq%&'`TBpjF+*d2
 258.154 +pCIUI)Tljjl,E+[`6aBa%-E,iR$J'D%X3fCMI)-j,6)X)k"IplC0%%mkjmYdDaLa
 258.155 +aRTMKY3jNDDZ[%)Y&G-1U``8QU,cU*lBQl0fIRrqYj*1hIMf[QZFbVkS-UR-+H""
 258.156 +pjLMUhPI5Gc!(RE3CXCF4ZaHa,b$f)m4Z41`@a2iGX5rdDqBF-Cq0#jLaQaM)PIT
 258.157 +B$$J4i1`(6Jca&X5p5Mb+Z!I9#+2A-4H!Phl1BFZK6)X'P1Pd)2UT'YLl+([Xje"
 258.158 +&X(G3"E#rQ$,#hLBf5[&#iIEbUHk)jIC*K8+LS[#3!(52q$"f"m9[bQGYVFb8Q&`
 258.159 +SL*@*#SPH*-BrdXA*r3'p@1bk+AAU$prJ+hU&X5pX[UJ04bEU2XP'ZCd0j"eZ*#m
 258.160 +%qlqCaqq1CTX@9GH5ZhFh`M30XVe"RY0mK03(jKUH*(m%QFdK*`6lFR*!X+p[Z,+
 258.161 +'iPH95189,&0B*NpR#(H9ZJKIZ,r848kam%eb)A$qm9,A!Z$S*TAMdQVBIhjH,+V
 258.162 +Cf"I`*%GkTjmP&c&i6"6,f)mBhYe(XFaka1!98Xc`AF4!9K6,rL&HEiKhr9'XaBT
 258.163 +c5)ZK9LdVF@iPjNB`#p&b(@+GF!U3!(2,HX3LQ2j!R9YZ4Lb'qBkPL(d'X6E8'Vh
 258.164 +5mJA%FKKHG*M,@Zj%E)HFAmL!'0L'amb)i9Q$2$B#X30+E$4Lqr*I3PE--!@a2EB
 258.165 +rTZG''UC4RA1R`,YMKKUFHkCM*Hi9CKB"XDFQ2B@EFTRK`iKpQePi[Dp(,5Nb&l&
 258.166 +1a(*B&krhpi'a5ijPASAB6UEMHBp$V"$+Rf)6%)0DjV&*r!@-Q6aQ3mc%$$b@KaM
 258.167 +F(Kkl'$',NSGG',YRVj+(!qHQ+RR-3LaAb@-1BK192+j!6&6bF!(lN!"F'`YHeEK
 258.168 +RIfEle8fYEB2[A-fZ#erMLpD9d*0B"pl(UMkP0I8+9U()@"I&&&Md@Mh0K'A94F1
 258.169 +aF$0Z,XqLDlNaF1$Vb#S4Ui0,Si#Ji5H4$`Vm2`!5FJ!!!3#3!`%8!*!$&!#3!c)
 258.170 +U9*!(+LVX!!!U+P53#Z`!!#T8N!-*EA4PFh3ZFfPd!J#3!e0*9%46593K!3!!T!)
 258.171 +-!*!$!3!!8dP84&0*9#%"!!#N!J`!N"+`fEpN!!!Hm!!!!8C892q3"953!q`!N!4
 258.172 +8N!Er9*!&l!!!+P53"Iq3!e53!q`!N!-U9*!+l1`!N!-Ul&53"qcX!*!&l!$X9*!
 258.173 +$l*!$!*!+l*!$!*!,!3#3!rq3#J#3#"!!+!!@!48#!3#3"J-!N!-"!*!$!43!N!-
 258.174 +8!*!$-J&20H`KbJ#3!a`!-J!!8f9dC`#3!`S!!2rr!*!%!8pi(2'-:
   259.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   259.2 +++ b/src/osdep/mac/nl_mac.c	Mon Sep 14 15:17:45 2009 +0900
   259.3 @@ -0,0 +1,74 @@
   259.4 +/* ========================================================================
   259.5 + * Copyright 1988-2006 University of Washington
   259.6 + *
   259.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   259.8 + * you may not use this file except in compliance with the License.
   259.9 + * You may obtain a copy of the License at
  259.10 + *
  259.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  259.12 + *
  259.13 + * 
  259.14 + * ========================================================================
  259.15 + */
  259.16 +
  259.17 +/*
  259.18 + * Program:	Mac newline routines
  259.19 + *
  259.20 + * Author:	Mark Crispin
  259.21 + *		Networks and Distributed Computing
  259.22 + *		Computing & Communications
  259.23 + *		University of Washington
  259.24 + *		Administration Building, AG-44
  259.25 + *		Seattle, WA  98195
  259.26 + *		Internet: MRC@CAC.Washington.EDU
  259.27 + *
  259.28 + * Date:	26 January 1992
  259.29 + * Last Edited:	30 August 2006
  259.30 + */
  259.31 +
  259.32 +/* Copy string with CRLF newlines
  259.33 + * Accepts: destination string
  259.34 + *	    pointer to size of destination string buffer
  259.35 + *	    source string
  259.36 + *	    length of source string
  259.37 + * Returns: length of copied string
  259.38 + */
  259.39 +
  259.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  259.41 +			  unsigned char *src,unsigned long srcl)
  259.42 +{
  259.43 +  long i,j;
  259.44 +  unsigned char c,*d = src;
  259.45 +  if (*dst) {			/* destination provided? */
  259.46 +    if ((i = srcl * 2) > *dstl)	/* calculate worst-case situation */
  259.47 +      for (i = j = srcl; j; --j) if (*d++ == '\015') i++;
  259.48 +				/* flush destination buffer if too small */
  259.49 +    if (i > *dstl) fs_give ((void **) dst);
  259.50 +  }
  259.51 +				/* make a new buffer if needed */
  259.52 +  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
  259.53 +  d = *dst;			/* destination string */
  259.54 +  if (srcl) do {		/* copy string */
  259.55 +    c = *d++ = *src++;		/* copy character */
  259.56 +				/* append line feed to bare CR */
  259.57 +    if ((c == '\015') && (*src != '\012')) *d++ = '\012';
  259.58 +  } while (--srcl);
  259.59 +  *d = '\0';			/* tie off destination */
  259.60 +  return d - *dst;		/* return length */
  259.61 +}
  259.62 +
  259.63 +
  259.64 +/* Length of string after strcrlfcpy applied
  259.65 + * Accepts: source string
  259.66 + * Returns: length of string
  259.67 + */
  259.68 +
  259.69 +unsigned long strcrlflen (STRING *s)
  259.70 +{
  259.71 +  unsigned long pos = GETPOS (s);
  259.72 +  unsigned long i = SIZE (s);
  259.73 +  unsigned long j = i;
  259.74 +  while (j--) if ((SNX (s) == '\015') && ((CHR (s) != '\012') || !j)) i++;
  259.75 +  SETPOS (s,pos);		/* restore old position */
  259.76 +  return i;
  259.77 +}
   260.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   260.2 +++ b/src/osdep/mac/os_mac.c	Mon Sep 14 15:17:45 2009 +0900
   260.3 @@ -0,0 +1,82 @@
   260.4 +/* ========================================================================
   260.5 + * Copyright 1988-2006 University of Washington
   260.6 + *
   260.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   260.8 + * you may not use this file except in compliance with the License.
   260.9 + * You may obtain a copy of the License at
  260.10 + *
  260.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  260.12 + *
  260.13 + * 
  260.14 + * ========================================================================
  260.15 + */
  260.16 +
  260.17 +/*
  260.18 + * Program:	Operating-system dependent routines -- Macintosh version
  260.19 + *
  260.20 + * Author:	Mark Crispin
  260.21 + *		Networks and Distributed Computing
  260.22 + *		Computing & Communications
  260.23 + *		University of Washington
  260.24 + *		Administration Building, AG-44
  260.25 + *		Seattle, WA  98195
  260.26 + *		Internet: MRC@CAC.Washington.EDU
  260.27 + *
  260.28 + * Date:	26 January 1992
  260.29 + * Last Edited:	30 August 2006
  260.30 + */
  260.31 +
  260.32 +
  260.33 +/*  This is a totally new operating-system dependent module for the Macintosh,
  260.34 + * written using THINK C on my Mac PowerBook-100 in my free time.
  260.35 + * Unlike earlier efforts, this version requires no external TCP library.  It
  260.36 + * also takes advantage of the Map panel in System 7 for the timezone.
  260.37 + */
  260.38 +
  260.39 +/* PPC cretins broke the MachineLocation struct */
  260.40 +
  260.41 +#define gmtFlags u
  260.42 +
  260.43 +#include <limits.h>
  260.44 +#include <time.h>
  260.45 +#include <stdio.h>
  260.46 +#include <fcntl.h>
  260.47 +#define tcp_port MacTCP_port
  260.48 +#include <MacTCPCommonTypes.h>
  260.49 +#include <AddressXlation.h>
  260.50 +#include <TCPPB.h>
  260.51 +#include <Desk.h>
  260.52 +#include <Devices.h>
  260.53 +#include <Errors.h>
  260.54 +#include <Files.h>
  260.55 +#include <Fonts.h>
  260.56 +#include <Menus.h>
  260.57 +#include <Script.h>
  260.58 +#include <ToolUtils.h>
  260.59 +#include <Windows.h>
  260.60 +#undef tcp_port
  260.61 +
  260.62 +#include "tcp_mac.h"		/* must be before osdep.h */
  260.63 +#include "mail.h"
  260.64 +#include "osdep.h"
  260.65 +#include "misc.h"
  260.66 +
  260.67 +static short TCPdriver = 0;	/* MacTCP's reference number */
  260.68 +short resolveropen = 0;		/* TCP's resolver open */
  260.69 +
  260.70 +
  260.71 +#include "env_mac.c"
  260.72 +#include "fs_mac.c"
  260.73 +#include "ftl_mac.c"
  260.74 +#include "nl_mac.c"
  260.75 +#include "tcp_mac.c"
  260.76 +
  260.77 +#define open(a,b,c) open (a,b)
  260.78 +#define server_login(user,pass,authuser,argc,argv) NIL
  260.79 +#define authserver_login(user,authuser,argc,argv) NIL
  260.80 +#define myusername() ""		/* dummy definition to prevent build errors */
  260.81 +#define MD5ENABLE ""
  260.82 +
  260.83 +#include "auth_md5.c"
  260.84 +#include "auth_pla.c"
  260.85 +#include "auth_log.c"
   261.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   261.2 +++ b/src/osdep/mac/os_mac.h	Mon Sep 14 15:17:45 2009 +0900
   261.3 @@ -0,0 +1,69 @@
   261.4 +/* ========================================================================
   261.5 + * Copyright 1988-2006 University of Washington
   261.6 + *
   261.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   261.8 + * you may not use this file except in compliance with the License.
   261.9 + * You may obtain a copy of the License at
  261.10 + *
  261.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  261.12 + *
  261.13 + * 
  261.14 + * ========================================================================
  261.15 + */
  261.16 +
  261.17 +/*
  261.18 + * Program:	Operating-system dependent routines -- Macintosh version
  261.19 + *
  261.20 + * Author:	Mark Crispin
  261.21 + *		Networks and Distributed Computing
  261.22 + *		Computing & Communications
  261.23 + *		University of Washington
  261.24 + *		Administration Building, AG-44
  261.25 + *		Seattle, WA  98195
  261.26 + *		Internet: MRC@CAC.Washington.EDU
  261.27 + *
  261.28 + * Date:	26 January 1992
  261.29 + * Last Edited:	30 August 2006
  261.30 + */
  261.31 +
  261.32 +
  261.33 +/*  This is a totally new operating-system dependent module for the Macintosh,
  261.34 + * written using THINK C on my Mac PowerBook-100 in my free time.
  261.35 + * Unlike earlier efforts, this version requires no external TCP library.  It
  261.36 + * also takes advantage of the Map panel in System 7 for the timezone.
  261.37 + */
  261.38 +
  261.39 +#include <stdlib.h>
  261.40 +#include <string.h>
  261.41 +#include <types.h>
  261.42 +#include <unix.h>
  261.43 +#ifndef noErr
  261.44 +#include <Desk.h>
  261.45 +#include <Devices.h>
  261.46 +#include <Errors.h>
  261.47 +#include <Events.h>
  261.48 +#include <Fonts.h>
  261.49 +#include <Memory.h>
  261.50 +#include <Menus.h>
  261.51 +#include <ToolUtils.h>
  261.52 +#include <Windows.h>
  261.53 +#endif
  261.54 +
  261.55 +#define L_SET SEEK_SET
  261.56 +#define L_INCR SEEK_CUR
  261.57 +#define L_XTND SEEK_END
  261.58 +
  261.59 +extern short resolveropen;	/* make this global so caller can sniff */
  261.60 +
  261.61 +#include "env_mac.h"
  261.62 +#include "fs.h"
  261.63 +#include "ftl.h"
  261.64 +#include "nl.h"
  261.65 +#include "tcp.h"
  261.66 +
  261.67 +#define TCPDRIVER "\p.IPP"
  261.68 +
  261.69 +#define gethostid clock
  261.70 +
  261.71 +long wait (void);
  261.72 +long random (void);
   262.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   262.2 +++ b/src/osdep/mac/osdep.h	Mon Sep 14 15:17:45 2009 +0900
   262.3 @@ -0,0 +1,29 @@
   262.4 +/* ========================================================================
   262.5 + * Copyright 1988-2006 University of Washington
   262.6 + *
   262.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   262.8 + * you may not use this file except in compliance with the License.
   262.9 + * You may obtain a copy of the License at
  262.10 + *
  262.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  262.12 + *
  262.13 + * 
  262.14 + * ========================================================================
  262.15 + */
  262.16 +
  262.17 +/*
  262.18 + * Program:	Operating-system dependent routines -- Macintosh version
  262.19 + *
  262.20 + * Author:	Mark Crispin
  262.21 + *		Networks and Distributed Computing
  262.22 + *		Computing & Communications
  262.23 + *		University of Washington
  262.24 + *		Administration Building, AG-44
  262.25 + *		Seattle, WA  98195
  262.26 + *		Internet: MRC@CAC.Washington.EDU
  262.27 + *
  262.28 + * Date:	13 June 1995
  262.29 + * Last Edited:	30 August 2006
  262.30 + */
  262.31 +
  262.32 +#include "os_mac.h"
   263.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   263.2 +++ b/src/osdep/mac/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   263.3 @@ -0,0 +1,89 @@
   263.4 +/* ========================================================================
   263.5 + * Copyright 1988-2006 University of Washington
   263.6 + *
   263.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   263.8 + * you may not use this file except in compliance with the License.
   263.9 + * You may obtain a copy of the License at
  263.10 + *
  263.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  263.12 + *
  263.13 + * 
  263.14 + * ========================================================================
  263.15 + */
  263.16 +
  263.17 +/*
  263.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  263.19 + *
  263.20 + * Author:	Mark Crispin
  263.21 + *		Networks and Distributed Computing
  263.22 + *		Computing & Communications
  263.23 + *		University of Washington
  263.24 + *		Administration Building, AG-44
  263.25 + *		Seattle, WA  98195
  263.26 + *		Internet: MRC@CAC.Washington.EDU
  263.27 + *
  263.28 + * Date:	15 June 2000
  263.29 + * Last Edited:	30 August 2006
  263.30 + */
  263.31 +
  263.32 +/* Wildcard pattern match
  263.33 + * Accepts: base string
  263.34 + *	    pattern string
  263.35 + *	    delimiter character
  263.36 + * Returns: T if pattern matches base, else NIL
  263.37 + */
  263.38 +
  263.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  263.40 +{
  263.41 +  switch (*pat) {
  263.42 +  case '%':			/* non-recursive */
  263.43 +				/* % at end, OK if no inferiors */
  263.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  263.45 +                                /* scan remainder of string until delimiter */
  263.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  263.47 +    while ((*s != delim) && *s++);
  263.48 +    break;
  263.49 +  case '*':			/* match 0 or more characters */
  263.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  263.51 +				/* scan remainder of string */
  263.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  263.53 +    while (*s++);
  263.54 +    break;
  263.55 +  case '\0':			/* end of pattern */
  263.56 +    return *s ? NIL : T;	/* success if also end of base */
  263.57 +  default:			/* match this character */
  263.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  263.59 +  }
  263.60 +  return NIL;
  263.61 +}
  263.62 +
  263.63 +/* Directory pattern match
  263.64 + * Accepts: base string
  263.65 + *	    pattern string
  263.66 + *	    delimiter character
  263.67 + * Returns: T if base is a matching directory of pattern, else NIL
  263.68 + */
  263.69 +
  263.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  263.71 +{
  263.72 +  switch (*pat) {
  263.73 +  case '%':			/* non-recursive */
  263.74 +    if (!*s) return T;		/* end of base means have a subset match */
  263.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  263.76 +				/* scan remainder of string until delimiter */
  263.77 +    do if (dmatch (s,pat,delim)) return T;
  263.78 +    while ((*s != delim) && *s++);
  263.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  263.80 +    return dmatch (s,pat,delim);/* do new scan */
  263.81 +  case '*':			/* match 0 or more characters */
  263.82 +    return T;			/* unconditional match */
  263.83 +  case '\0':			/* end of pattern */
  263.84 +    break;
  263.85 +  default:			/* match this character */
  263.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  263.87 +				/* end of base, return if at delimiter */
  263.88 +    else if (*pat == delim) return T;
  263.89 +    break;
  263.90 +  }
  263.91 +  return NIL;
  263.92 +}
   264.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   264.2 +++ b/src/osdep/mac/tcp_mac.c	Mon Sep 14 15:17:45 2009 +0900
   264.3 @@ -0,0 +1,557 @@
   264.4 +/* ========================================================================
   264.5 + * Copyright 1988-2008 University of Washington
   264.6 + *
   264.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   264.8 + * you may not use this file except in compliance with the License.
   264.9 + * You may obtain a copy of the License at
  264.10 + *
  264.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  264.12 + *
  264.13 + * 
  264.14 + * ========================================================================
  264.15 + */
  264.16 +
  264.17 +/*
  264.18 + * Program:	Macintosh TCP/IP routines
  264.19 + *
  264.20 + * Author:	Mark Crispin
  264.21 + *		Networks and Distributed Computing
  264.22 + *		Computing & Communications
  264.23 + *		University of Washington
  264.24 + *		Administration Building, AG-44
  264.25 + *		Seattle, WA  98195
  264.26 + *		Internet: MRC@CAC.Washington.EDU
  264.27 + *
  264.28 + * Date:	26 January 1992
  264.29 + * Last Edited:	13 January 2008
  264.30 + */
  264.31 +
  264.32 +
  264.33 +/*  This is a totally new operating-system dependent module for the Macintosh,
  264.34 + * written using THINK C on my Mac PowerBook-100 in my free time.
  264.35 + * Unlike earlier efforts, this version requires no external TCP library.  It
  264.36 + * also takes advantage of the Map panel in System 7 for the timezone.
  264.37 + */
  264.38 +
  264.39 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  264.40 +static long ttmo_open = 75;	/* TCP timeouts, in seconds */
  264.41 +static long ttmo_read = 0;
  264.42 +static long ttmo_write = 0;
  264.43 +static long ttmo_close = 0;
  264.44 +
  264.45 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  264.46 +			       long *contd);
  264.47 +
  264.48 +/* TCP/IP manipulate parameters
  264.49 + * Accepts: function code
  264.50 + *	    function-dependent value
  264.51 + * Returns: function-dependent return value
  264.52 + */
  264.53 +
  264.54 +void *tcp_parameters (long function,void *value)
  264.55 +{
  264.56 +  void *ret = NIL;
  264.57 +  switch ((int) function) {
  264.58 +  case SET_TIMEOUT:
  264.59 +    tmoh = (tcptimeout_t) value;
  264.60 +  case GET_TIMEOUT:
  264.61 +    ret = (void *) tmoh;
  264.62 +    break;
  264.63 +  case SET_OPENTIMEOUT:
  264.64 +    ttmo_open = (long) value;
  264.65 +  case GET_OPENTIMEOUT:
  264.66 +    ret = (void *) ttmo_open;
  264.67 +    break;
  264.68 +  case SET_READTIMEOUT:
  264.69 +    ttmo_read = (long) value;
  264.70 +  case GET_READTIMEOUT:
  264.71 +    ret = (void *) ttmo_read;
  264.72 +    break;
  264.73 +  case SET_WRITETIMEOUT:
  264.74 +    ttmo_write = (long) value;
  264.75 +  case GET_WRITETIMEOUT:
  264.76 +    ret = (void *) ttmo_write;
  264.77 +    break;
  264.78 +  case SET_CLOSETIMEOUT:
  264.79 +    ttmo_close = (long) value;
  264.80 +  case GET_CLOSETIMEOUT:
  264.81 +    ret = (void *) ttmo_close;
  264.82 +    break;
  264.83 +  }
  264.84 +  return ret;
  264.85 +}
  264.86 +
  264.87 +/* TCP/IP open
  264.88 + * Accepts: host name
  264.89 + *	    contact service name
  264.90 + *	    contact port number
  264.91 + * Returns: TCP stream if success else NIL
  264.92 + */
  264.93 +
  264.94 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  264.95 +{
  264.96 +  TCPSTREAM *stream;
  264.97 +  struct hostInfo hst;
  264.98 +  struct TCPCreatePB *createpb;
  264.99 +  struct TCPOpenPB *openpb;
 264.100 +  char *s;
 264.101 +  unsigned long i,j,k,l;
 264.102 +  char tmp[MAILTMPLEN];
 264.103 +  port &= 0xffff;		/* erase flags */
 264.104 +				/* init MacTCP */
 264.105 +  if (!TCPdriver && OpenDriver (TCPDRIVER,&TCPdriver)) {
 264.106 +    mm_log ("Can't init MacTCP",ERROR);
 264.107 +    return NIL;
 264.108 +  }
 264.109 +  if (!resolveropen && OpenResolver (NIL)) {
 264.110 +    mm_log ("Can't init domain resolver",ERROR);
 264.111 +    return NIL;
 264.112 +  }
 264.113 +  resolveropen = T;		/* note resolver open now */
 264.114 +				/* domain literal? */
 264.115 +  if (host[0] == '[' && host[strlen (host)-1] == ']') {
 264.116 +    if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
 264.117 +	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
 264.118 +	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
 264.119 +	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
 264.120 +      hst.addr[0] = (i << 24) + (j << 16) + (k << 8) + l;
 264.121 +      hst.addr[1] = 0;		/* only one address to try! */
 264.122 +      sprintf (hst.cname,"[%ld.%ld.%ld.%ld]",i,j,k,l);
 264.123 +    }
 264.124 +    else {
 264.125 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
 264.126 +      mm_log (tmp,ERROR);
 264.127 +      return NIL;
 264.128 +    }
 264.129 +  }
 264.130 +
 264.131 +  else {			/* look up host name */
 264.132 +    if (!tcp_dns_upp) tcp_dns_upp = NewResultProc (tcp_dns_result);
 264.133 +    if (StrToAddr (host,&hst,tcp_dns_upp,NIL)) {
 264.134 +      while (hst.rtnCode == cacheFault && wait ());
 264.135 +				/* kludge around MacTCP bug */
 264.136 +      if (hst.rtnCode == outOfMemory) {
 264.137 +	mm_log ("Re-initializing domain resolver",WARN);
 264.138 +	CloseResolver ();	/* bop it on the head and try again */
 264.139 +	OpenResolver (NIL);	/* note this will leak 12K */
 264.140 +	StrToAddr (host,&hst,tcp_dns_upp,NIL);
 264.141 +	while (hst.rtnCode == cacheFault && wait ());
 264.142 +      }
 264.143 +      if (hst.rtnCode) {	/* still have error status? */
 264.144 +	switch (hst.rtnCode) {	/* analyze return */
 264.145 +	case nameSyntaxErr:
 264.146 +	  s = "Syntax error in name";
 264.147 +	  break;
 264.148 +	case noResultProc:
 264.149 +	  s = "No result procedure";
 264.150 +	  break;
 264.151 +	case noNameServer:
 264.152 +	  s = "No name server found";
 264.153 +	  break;
 264.154 +	case authNameErr:
 264.155 +	  s = "Host does not exist";
 264.156 +	  break;
 264.157 +	case noAnsErr:
 264.158 +	  s = "No name servers responding";
 264.159 +	  break;
 264.160 +	case dnrErr:
 264.161 +	  s = "Name server returned an error";
 264.162 +	  break;
 264.163 +	case outOfMemory:
 264.164 +	  s = "Not enough memory to resolve name";
 264.165 +	  break;
 264.166 +	case notOpenErr:
 264.167 +	  s = "Driver not open";
 264.168 +	  break;
 264.169 +	default:
 264.170 +	  s = NIL;
 264.171 +	  break;
 264.172 +	}
 264.173 +	if (s) sprintf (tmp,"%s: %.80s",s,host);
 264.174 +	else sprintf (tmp,"Unknown resolver error (%ld): %.80s",
 264.175 +		      hst.rtnCode,host);
 264.176 +	mm_log (tmp,ERROR);
 264.177 +	return NIL;
 264.178 +      }
 264.179 +    }
 264.180 +  }
 264.181 +
 264.182 +				/* create local TCP/IP stream */
 264.183 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
 264.184 +  stream->ictr = 0;		/* initialize input */
 264.185 +  stream->pb.ioCRefNum = TCPdriver;
 264.186 +  createpb = &stream->pb.csParam.create;
 264.187 +  openpb = &stream->pb.csParam.open;
 264.188 +  stream->pb.csCode = TCPCreate;/* create a TCP stream */
 264.189 +				/* set up buffer for TCP */
 264.190 +  createpb->rcvBuffLen = 4*BUFLEN;
 264.191 +  createpb->rcvBuff = fs_get (createpb->rcvBuffLen);
 264.192 +  createpb->notifyProc = NIL;	/* no special notify procedure */
 264.193 +  createpb->userDataPtr = NIL;
 264.194 +  if (PBControlSync ((ParmBlkPtr) &stream->pb))
 264.195 +    fatal ("Can't create TCP stream");
 264.196 +  				/* open TCP connection */
 264.197 +  stream->pb.csCode = TCPActiveOpen;
 264.198 +  openpb->ulpTimeoutValue = (int) ttmo_open;
 264.199 +  openpb->ulpTimeoutAction = T;
 264.200 +  openpb->validityFlags = timeoutValue|timeoutAction;
 264.201 +				/* remote host (should try all) */
 264.202 +  openpb->remoteHost = hst.addr[0];
 264.203 +  openpb->remotePort = port;	/* caller specified remote port */
 264.204 +  openpb->localPort = 0;	/* generate a local port */
 264.205 +  openpb->tosFlags = 0;		/* no special TOS */
 264.206 +  openpb->precedence = 0;	/* no special precedence */
 264.207 +  openpb->dontFrag = 0;		/* allow fragmentation */
 264.208 +  openpb->timeToLive = 255;	/* standards say 60, UNIX uses 255 */
 264.209 +  openpb->security = 0;		/* no special security */
 264.210 +  openpb->optionCnt = 0;	/* no IP options */
 264.211 +  openpb->options[0] = 0;
 264.212 +  openpb->userDataPtr = NIL;	/* no special data pointer */
 264.213 +  PBControlAsync ((ParmBlkPtr) &stream->pb);
 264.214 +  while (stream->pb.ioResult == inProgress && wait ());
 264.215 +  if (stream->pb.ioResult) {	/* got back error status? */
 264.216 +    sprintf (tmp,"Can't connect to %.80s,%ld",hst.cname,port);
 264.217 +    mm_log (tmp,ERROR);
 264.218 +				/* nuke the buffer */
 264.219 +    stream->pb.csCode = TCPRelease;
 264.220 +    createpb->userDataPtr = NIL;
 264.221 +    if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
 264.222 +				/* free its buffer */
 264.223 +    fs_give ((void **) &createpb->rcvBuff);
 264.224 +    fs_give ((void **) &stream);/* and the local stream */
 264.225 +    return NIL;
 264.226 +  }
 264.227 +
 264.228 +				/* copy host names for later use */
 264.229 +  stream->host = cpystr (hst.cname);
 264.230 +				/* tie off trailing dot */
 264.231 +  stream->host[strlen (stream->host) - 1] = '\0';
 264.232 +				/* the open gave us our address */
 264.233 +  i = (openpb->localHost >> 24) & 0xff;
 264.234 +  j = (openpb->localHost >> 16) & 0xff;
 264.235 +  k = (openpb->localHost >> 8) & 0xff;
 264.236 +  l = openpb->localHost & 0xff;
 264.237 +  sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l);
 264.238 +  stream->localhost = cpystr (tmp);
 264.239 +  if (!myLocalHost) myLocalHost = cpystr (tmp);
 264.240 +  stream->port = port;		/* copy port number */
 264.241 +  return stream;
 264.242 +}
 264.243 +
 264.244 +
 264.245 +/* Called when have return from DNS
 264.246 + * Accepts: host info pointer
 264.247 + *	    user data pointer
 264.248 + */
 264.249 +
 264.250 +ResultUPP tcp_dns_upp = NIL;
 264.251 +
 264.252 +pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr)
 264.253 +{
 264.254 +  /* dummy routine */
 264.255 +}
 264.256 +
 264.257 +/* TCP/IP authenticated open
 264.258 + * Accepts: NETMBX specifier
 264.259 + *	    service name
 264.260 + *	    returned user name buffer
 264.261 + * Returns: TCP/IP stream if success else NIL
 264.262 + */
 264.263 +
 264.264 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 264.265 +{
 264.266 +  return NIL;			/* no authenticated opens on Mac */
 264.267 +}
 264.268 +
 264.269 +/* TCP receive line
 264.270 + * Accepts: TCP stream
 264.271 + * Returns: text line string or NIL if failure
 264.272 + */
 264.273 +
 264.274 +char *tcp_getline (TCPSTREAM *stream)
 264.275 +{
 264.276 +  unsigned long n,contd;
 264.277 +  char *ret = tcp_getline_work (stream,&n,&contd);
 264.278 +  if (ret && contd) {		/* got a line needing continuation? */
 264.279 +    STRINGLIST *stl = mail_newstringlist ();
 264.280 +    STRINGLIST *stc = stl;
 264.281 +    do {			/* collect additional lines */
 264.282 +      stc->text.data = (unsigned char *) ret;
 264.283 +      stc->text.size = n;
 264.284 +      stc = stc->next = mail_newstringlist ();
 264.285 +      ret = tcp_getline_work (stream,&n,&contd);
 264.286 +    } while (ret && contd);
 264.287 +    if (ret) {			/* stash final part of line on list */
 264.288 +      stc->text.data = (unsigned char *) ret;
 264.289 +      stc->text.size = n;
 264.290 +				/* determine how large a buffer we need */
 264.291 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 264.292 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 264.293 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 264.294 +	memcpy (ret + n,stc->text.data,stc->text.size);
 264.295 +      ret[n] = '\0';
 264.296 +    }
 264.297 +    mail_free_stringlist (&stl);/* either way, done with list */
 264.298 +  }
 264.299 +  return ret;
 264.300 +}
 264.301 +
 264.302 +/* TCP receive line or partial line
 264.303 + * Accepts: TCP stream
 264.304 + *	    pointer to return size
 264.305 + *	    pointer to return continuation flag
 264.306 + * Returns: text line string, size and continuation flag, or NIL if failure
 264.307 + */
 264.308 +
 264.309 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 264.310 +			       long *contd)
 264.311 +{
 264.312 +  unsigned long n;
 264.313 +  char *s,*ret,c,d;
 264.314 +  *contd = NIL;			/* assume no continuation */
 264.315 +				/* make sure have data */
 264.316 +  if (!tcp_getdata (stream)) return NIL;
 264.317 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 264.318 +    d = *stream->iptr++;	/* slurp another character */
 264.319 +    if ((c == '\015') && (d == '\012')) {
 264.320 +      ret = (char *) fs_get (n--);
 264.321 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 264.322 +      ret[n] = '\0';		/* tie off string with null */
 264.323 +      return ret;
 264.324 +    }
 264.325 +  }
 264.326 +				/* copy partial string from buffer */
 264.327 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 264.328 +				/* get more data from the net */
 264.329 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 264.330 +				/* special case of newline broken by buffer */
 264.331 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 264.332 +    stream->iptr++;		/* eat the line feed */
 264.333 +    stream->ictr--;
 264.334 +    ret[*size = --n] = '\0';	/* tie off string with null */
 264.335 +  }
 264.336 +  else *contd = LONGT;		/* continuation needed */
 264.337 +  return ret;
 264.338 +}
 264.339 +
 264.340 +/* TCP/IP receive buffer
 264.341 + * Accepts: TCP/IP stream
 264.342 + *	    size in bytes
 264.343 + *	    buffer to read into
 264.344 + * Returns: T if success, NIL otherwise
 264.345 + */
 264.346 +
 264.347 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 264.348 +{
 264.349 +  unsigned long n;
 264.350 +  char *bufptr = buffer;
 264.351 +  while (size > 0) {		/* until request satisfied */
 264.352 +    if (!tcp_getdata (stream)) return NIL;
 264.353 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 264.354 +				/* do the copy */
 264.355 +    memcpy (bufptr,stream->iptr,n);
 264.356 +    bufptr += n;		/* update pointer */
 264.357 +    stream->iptr +=n;
 264.358 +    size -= n;			/* update # of bytes to do */
 264.359 +    stream->ictr -=n;
 264.360 +  }
 264.361 +  bufptr[0] = '\0';		/* tie off string */
 264.362 +  return T;
 264.363 +}
 264.364 +
 264.365 +
 264.366 +/* TCP/IP receive data
 264.367 + * Accepts: TCP/IP stream
 264.368 + * Returns: T if success, NIL otherwise
 264.369 + */
 264.370 +
 264.371 +long tcp_getdata (TCPSTREAM *stream)
 264.372 +{
 264.373 +  time_t t = time (0);
 264.374 +  struct TCPReceivePB *receivepb = &stream->pb.csParam.receive;
 264.375 +  struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
 264.376 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 264.377 +    time_t tl = time (0);
 264.378 +    stream->pb.csCode = TCPRcv;	/* receive TCP data */
 264.379 +    receivepb->commandTimeoutValue = (int) ttmo_read;
 264.380 +    receivepb->rcvBuff = stream->ibuf;
 264.381 +    receivepb->rcvBuffLen = BUFLEN;
 264.382 +    receivepb->secondTimeStamp = 0;
 264.383 +    receivepb->userDataPtr = NIL;
 264.384 +    PBControlAsync ((ParmBlkPtr) &stream->pb);
 264.385 +    while (stream->pb.ioResult == inProgress && wait ());
 264.386 +    if (stream->pb.ioResult) {	/* punt if got an error */
 264.387 +      time_t tc = time (0);
 264.388 +      if ((stream->pb.ioResult == commandTimeout) && tmoh &&
 264.389 +	  ((*tmoh) (tc - t,tc - tl))) continue;
 264.390 +    				/* nuke connection */
 264.391 +      stream->pb.csCode = TCPAbort;
 264.392 +      abortpb->userDataPtr = NIL;
 264.393 +      PBControlSync ((ParmBlkPtr) &stream->pb);
 264.394 +      return NIL;
 264.395 +    }
 264.396 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 264.397 +    stream->ictr = receivepb->rcvBuffLen;
 264.398 +  }
 264.399 +  return T;
 264.400 +}
 264.401 +
 264.402 +/* TCP/IP send string as record
 264.403 + * Accepts: TCP/IP stream
 264.404 + *	    string pointer
 264.405 + * Returns: T if success else NIL
 264.406 + */
 264.407 +
 264.408 +long tcp_soutr (TCPSTREAM *stream,char *string)
 264.409 +{
 264.410 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 264.411 +}
 264.412 +
 264.413 +
 264.414 +/* TCP/IP send string
 264.415 + * Accepts: TCP/IP stream
 264.416 + *	    string pointer
 264.417 + *	    byte count
 264.418 + * Returns: T if success else NIL
 264.419 + */
 264.420 +
 264.421 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 264.422 +{
 264.423 +  struct TCPSendPB *sendpb = &stream->pb.csParam.send;
 264.424 +  struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
 264.425 +  struct {
 264.426 +    unsigned short length;
 264.427 +    Ptr buffer;
 264.428 +    unsigned short trailer;
 264.429 +  } wds;
 264.430 +  while (wds.length = (size > (unsigned long) 32768) ? 32768 : size) {
 264.431 +    wds.buffer = string;	/* buffer */
 264.432 +    wds.trailer = 0;		/* tie off buffer */
 264.433 +    size -= wds.length;		/* this many words will be output */
 264.434 +    string += wds.length;
 264.435 +    stream->pb.csCode = TCPSend;/* send TCP data */
 264.436 +    sendpb->ulpTimeoutValue = (int) ttmo_write;
 264.437 +    sendpb->ulpTimeoutAction = 0;
 264.438 +    sendpb->validityFlags = timeoutValue|timeoutAction;
 264.439 +    sendpb->pushFlag = T;	/* send the data now */
 264.440 +    sendpb->urgentFlag = NIL;	/* non-urgent data */
 264.441 +    sendpb->wdsPtr = (Ptr) &wds;
 264.442 +    sendpb->userDataPtr = NIL;
 264.443 +    PBControlAsync ((ParmBlkPtr) &stream->pb);
 264.444 +    while (stream->pb.ioResult == inProgress && wait ());
 264.445 +    if (stream->pb.ioResult) {	/* punt if got an error */
 264.446 +				/* nuke connection */
 264.447 +      stream->pb.csCode =TCPAbort;
 264.448 +      abortpb->userDataPtr = NIL;
 264.449 +      PBControlSync ((ParmBlkPtr) &stream->pb);
 264.450 +      return NIL;
 264.451 +    }
 264.452 +  }
 264.453 +  return T;			/* success */
 264.454 +}
 264.455 +
 264.456 +/* TCP/IP close
 264.457 + * Accepts: TCP/IP stream
 264.458 + */
 264.459 +
 264.460 +void tcp_close (TCPSTREAM *stream)
 264.461 +{
 264.462 +  struct TCPClosePB *closepb = &stream->pb.csParam.close;
 264.463 +  struct TCPCreatePB *createpb = &stream->pb.csParam.create;
 264.464 +  stream->pb.csCode = TCPClose;	/* close TCP stream */
 264.465 +  closepb->ulpTimeoutValue = (int) ttmo_close;
 264.466 +  closepb->ulpTimeoutAction = 0;
 264.467 +  closepb->validityFlags = timeoutValue|timeoutAction;
 264.468 +  closepb->userDataPtr = NIL;
 264.469 +  PBControlAsync ((ParmBlkPtr) &stream->pb);
 264.470 +  while (stream->pb.ioResult == inProgress && wait ());
 264.471 +  stream->pb.csCode =TCPRelease;/* flush the buffers */
 264.472 +  createpb->userDataPtr = NIL;
 264.473 +  if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
 264.474 +				/* free its buffer */
 264.475 +  fs_give ((void **) &createpb->rcvBuff);
 264.476 +				/* flush host names */
 264.477 +  fs_give ((void **) &stream->host);
 264.478 +  fs_give ((void **) &stream->localhost);
 264.479 +  fs_give ((void **) &stream);	/* flush the stream */
 264.480 +}
 264.481 +
 264.482 +/* TCP/IP return host for this stream
 264.483 + * Accepts: TCP/IP stream
 264.484 + * Returns: host name for this stream
 264.485 + */
 264.486 +
 264.487 +char *tcp_host (TCPSTREAM *stream)
 264.488 +{
 264.489 +  return stream->host;		/* return host name */
 264.490 +}
 264.491 +
 264.492 +
 264.493 +/* TCP/IP return remote host for this stream
 264.494 + * Accepts: TCP/IP stream
 264.495 + * Returns: host name for this stream
 264.496 + */
 264.497 +
 264.498 +char *tcp_remotehost (TCPSTREAM *stream)
 264.499 +{
 264.500 +  return stream->host;		/* return host name */
 264.501 +}
 264.502 +
 264.503 +
 264.504 +/* TCP/IP return port for this stream
 264.505 + * Accepts: TCP/IP stream
 264.506 + * Returns: port number for this stream
 264.507 + */
 264.508 +
 264.509 +unsigned long tcp_port (TCPSTREAM *stream)
 264.510 +{
 264.511 +  return stream->port;		/* return port number */
 264.512 +}
 264.513 +
 264.514 +
 264.515 +/* TCP/IP return local host for this stream
 264.516 + * Accepts: TCP/IP stream
 264.517 + * Returns: local host name for this stream
 264.518 + */
 264.519 +
 264.520 +char *tcp_localhost (TCPSTREAM *stream)
 264.521 +{
 264.522 +  return stream->localhost;	/* return local host name */
 264.523 +}
 264.524 +
 264.525 +/* TCP/IP return canonical form of host name
 264.526 + * Accepts: host name
 264.527 + * Returns: canonical form of host name
 264.528 + */
 264.529 +
 264.530 +char *tcp_canonical (char *name)
 264.531 +{
 264.532 +  int i;
 264.533 +  struct hostInfo hst;
 264.534 +				/* look like domain literal? */
 264.535 +  if (name[0] == '[' && name[i = (strlen (name))-1] == ']') return name;
 264.536 +  if (StrToAddr (name,&hst,tcp_dns_upp,NIL)) {
 264.537 +    while (hst.rtnCode == cacheFault && wait ());
 264.538 +				/* kludge around MacTCP bug */
 264.539 +    if (hst.rtnCode == outOfMemory) {
 264.540 +      mm_log ("Re-initializing domain resolver",WARN);
 264.541 +      CloseResolver ();		/* bop it on the head and try again */
 264.542 +      OpenResolver (NIL);	/* note this will leak 12K */
 264.543 +      StrToAddr (name,&hst,tcp_dns_upp,NIL);
 264.544 +      while (hst.rtnCode == cacheFault && wait ());
 264.545 +    }
 264.546 +				/* still have error status? */
 264.547 +    if (hst.rtnCode) return name;
 264.548 +  }
 264.549 +  return hst.cname;		/* success */
 264.550 +}
 264.551 +
 264.552 +
 264.553 +/* TCP/IP get client host name (server calls only)
 264.554 + * Returns: client host name
 264.555 + */
 264.556 +
 264.557 +char *tcp_clienthost ()
 264.558 +{
 264.559 +  return "UNKNOWN";
 264.560 +}
   265.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   265.2 +++ b/src/osdep/mac/tcp_mac.h	Mon Sep 14 15:17:45 2009 +0900
   265.3 @@ -0,0 +1,49 @@
   265.4 +/* ========================================================================
   265.5 + * Copyright 1988-2006 University of Washington
   265.6 + *
   265.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   265.8 + * you may not use this file except in compliance with the License.
   265.9 + * You may obtain a copy of the License at
  265.10 + *
  265.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  265.12 + *
  265.13 + * 
  265.14 + * ========================================================================
  265.15 + */
  265.16 +
  265.17 +/*
  265.18 + * Program:	Macintosh TCP/IP routines
  265.19 + *
  265.20 + * Author:	Mark Crispin
  265.21 + *		Networks and Distributed Computing
  265.22 + *		Computing & Communications
  265.23 + *		University of Washington
  265.24 + *		Administration Building, AG-44
  265.25 + *		Seattle, WA  98195
  265.26 + *		Internet: MRC@CAC.Washington.EDU
  265.27 + *
  265.28 + * Date:	26 January 1992
  265.29 + * Last Edited:	30 August 2006
  265.30 + */
  265.31 +
  265.32 +
  265.33 +/* TCP input buffer */
  265.34 +
  265.35 +#define BUFLEN (size_t) 8192	/* TCP input buffer */
  265.36 +
  265.37 +
  265.38 +/* TCP I/O stream */
  265.39 +
  265.40 +#define TCPSTREAM struct tcp_stream
  265.41 +TCPSTREAM {
  265.42 +  char *host;			/* host name */
  265.43 +  unsigned long port;		/* port number */
  265.44 +  char *localhost;		/* local host name */
  265.45 +  struct TCPiopb pb;		/* MacTCP parameter block */
  265.46 +  long ictr;			/* input counter */
  265.47 +  char *iptr;			/* input pointer */
  265.48 +  char ibuf[BUFLEN];		/* input buffer */
  265.49 +};
  265.50 +
  265.51 +extern ResultUPP tcp_dns_upp;
  265.52 +pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr);
   266.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   266.2 +++ b/src/osdep/nt/drivers.bat	Mon Sep 14 15:17:45 2009 +0900
   266.3 @@ -0,0 +1,33 @@
   266.4 +@ECHO OFF
   266.5 +REM ========================================================================
   266.6 +REM Copyright 1988-2006 University of Washington
   266.7 +REM
   266.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   266.9 +REM you may not use this file except in compliance with the License.
  266.10 +REM You may obtain a copy of the License at
  266.11 +REM
  266.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  266.13 +REM
  266.14 +REM 
  266.15 +REM ========================================================================
  266.16 +
  266.17 +REM Program:	Driver Linkage Generator for DOS/NT
  266.18 +REM
  266.19 +REM Author:	Mark Crispin
  266.20 +REM		Networks and Distributed Computing
  266.21 +REM		Computing & Communications
  266.22 +REM		University of Washington
  266.23 +REM		Administration Building, AG-44
  266.24 +REM		Seattle, WA  98195
  266.25 +REM		Internet: MRC@CAC.Washington.EDU
  266.26 +REM
  266.27 +REM Date:	11 October 1989
  266.28 +REM Last Edited:30 August 2006
  266.29 +
  266.30 +REM Erase old driver linkage
  266.31 +IF EXIST LINKAGE.* DEL LINKAGE.*
  266.32 +
  266.33 +REM Now define the new list
  266.34 +FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
  266.35 +
  266.36 +EXIT 0
   267.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   267.2 +++ b/src/osdep/nt/drivraux.bat	Mon Sep 14 15:17:45 2009 +0900
   267.3 @@ -0,0 +1,30 @@
   267.4 +@ECHO OFF
   267.5 +REM ========================================================================
   267.6 +REM Copyright 1988-2006 University of Washington
   267.7 +REM
   267.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   267.9 +REM you may not use this file except in compliance with the License.
  267.10 +REM You may obtain a copy of the License at
  267.11 +REM
  267.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  267.13 +REM
  267.14 +REM 
  267.15 +REM ========================================================================
  267.16 +
  267.17 +REM Program:	Driver Linkage Generator auxillary for NT/Win9x
  267.18 +REM
  267.19 +REM Author:	Mark Crispin
  267.20 +REM		Networks and Distributed Computing
  267.21 +REM		Computing & Communications
  267.22 +REM		University of Washington
  267.23 +REM		Administration Building, AG-44
  267.24 +REM		Seattle, WA  98195
  267.25 +REM		Internet: MRC@CAC.Washington.EDU
  267.26 +REM
  267.27 +REM Date:	11 October 1989
  267.28 +REM Last Edited:30 August 2006
  267.29 +
  267.30 +ECHO extern DRIVER %1driver; >> LINKAGE.H
  267.31 +REM Note the introduction of the caret to quote the ampersand in NT
  267.32 +if "%OS%" == "Windows_NT" ECHO   mail_link (^&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
  267.33 +if "%OS%" == "" ECHO   mail_link (&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
   268.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   268.2 +++ b/src/osdep/nt/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   268.3 @@ -0,0 +1,43 @@
   268.4 +/* ========================================================================
   268.5 + * Copyright 1988-2006 University of Washington
   268.6 + *
   268.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   268.8 + * you may not use this file except in compliance with the License.
   268.9 + * You may obtain a copy of the License at
  268.10 + *
  268.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  268.12 + *
  268.13 + * 
  268.14 + * ========================================================================
  268.15 + */
  268.16 +
  268.17 +/*
  268.18 + * Program:	Dummy routines
  268.19 + *
  268.20 + * Author:	Mark Crispin
  268.21 + *		Networks and Distributed Computing
  268.22 + *		Computing & Communications
  268.23 + *		University of Washington
  268.24 + *		Administration Building, AG-44
  268.25 + *		Seattle, WA  98195
  268.26 + *		Internet: MRC@CAC.Washington.EDU
  268.27 + *
  268.28 + * Date:	9 May 1991
  268.29 + * Last Edited:	30 August 2006
  268.30 + */
  268.31 +
  268.32 +/* Exported function prototypes */
  268.33 +
  268.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  268.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  268.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  268.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  268.38 +		    unsigned long csiz,unsigned long fsiz);
  268.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  268.40 +			  unsigned long fsiz);
  268.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  268.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  268.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  268.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  268.45 +char *dummy_file (char *dst,char *name);
  268.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   269.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   269.2 +++ b/src/osdep/nt/dummynt.c	Mon Sep 14 15:17:45 2009 +0900
   269.3 @@ -0,0 +1,724 @@
   269.4 +/* ========================================================================
   269.5 + * Copyright 1988-2007 University of Washington
   269.6 + *
   269.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   269.8 + * you may not use this file except in compliance with the License.
   269.9 + * You may obtain a copy of the License at
  269.10 + *
  269.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  269.12 + *
  269.13 + * 
  269.14 + * ========================================================================
  269.15 + */
  269.16 +
  269.17 +/*
  269.18 + * Program:	Dummy routines for NT
  269.19 + *
  269.20 + * Author:	Mark Crispin
  269.21 + *		Networks and Distributed Computing
  269.22 + *		Computing & Communications
  269.23 + *		University of Washington
  269.24 + *		Administration Building, AG-44
  269.25 + *		Seattle, WA  98195
  269.26 + *		Internet: MRC@CAC.Washington.EDU
  269.27 + *
  269.28 + * Date:	24 May 1993
  269.29 + * Last Edited:	1 June 2007
  269.30 + */
  269.31 +
  269.32 +
  269.33 +#include <ctype.h>
  269.34 +#include <stdio.h>
  269.35 +#include <errno.h>
  269.36 +#include <fcntl.h>
  269.37 +#include <direct.h>
  269.38 +#include "mail.h"
  269.39 +#include "osdep.h"
  269.40 +#include <sys\stat.h>
  269.41 +#include <dos.h>
  269.42 +#include "dummy.h"
  269.43 +#include "misc.h"
  269.44 +
  269.45 +/* Function prototypes */
  269.46 +
  269.47 +DRIVER *dummy_valid (char *name);
  269.48 +void *dummy_parameters (long function,void *value);
  269.49 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
  269.50 +		      long level);
  269.51 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
  269.52 +		   long attributes,char *contents);
  269.53 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
  269.54 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  269.55 +void dummy_close (MAILSTREAM *stream,long options);
  269.56 +long dummy_ping (MAILSTREAM *stream);
  269.57 +void dummy_check (MAILSTREAM *stream);
  269.58 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  269.59 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  269.60 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  269.61 +
  269.62 +/* Dummy routines */
  269.63 +
  269.64 +
  269.65 +/* Driver dispatch used by MAIL */
  269.66 +
  269.67 +DRIVER dummydriver = {
  269.68 +  "dummy",			/* driver name */
  269.69 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  269.70 +  (DRIVER *) NIL,		/* next driver */
  269.71 +  dummy_valid,			/* mailbox is valid for us */
  269.72 +  dummy_parameters,		/* manipulate parameters */
  269.73 +  dummy_scan,			/* scan mailboxes */
  269.74 +  dummy_list,			/* list mailboxes */
  269.75 +  dummy_lsub,			/* list subscribed mailboxes */
  269.76 +  dummy_subscribe,		/* subscribe to mailbox */
  269.77 +  NIL,				/* unsubscribe from mailbox */
  269.78 +  dummy_create,			/* create mailbox */
  269.79 +  dummy_delete,			/* delete mailbox */
  269.80 +  dummy_rename,			/* rename mailbox */
  269.81 +  mail_status_default,		/* status of mailbox */
  269.82 +  dummy_open,			/* open mailbox */
  269.83 +  dummy_close,			/* close mailbox */
  269.84 +  NIL,				/* fetch message "fast" attributes */
  269.85 +  NIL,				/* fetch message flags */
  269.86 +  NIL,				/* fetch overview */
  269.87 +  NIL,				/* fetch message structure */
  269.88 +  NIL,				/* fetch header */
  269.89 +  NIL,				/* fetch text */
  269.90 +  NIL,				/* fetch message data */
  269.91 +  NIL,				/* unique identifier */
  269.92 +  NIL,				/* message number from UID */
  269.93 +  NIL,				/* modify flags */
  269.94 +  NIL,				/* per-message modify flags */
  269.95 +  NIL,				/* search for message based on criteria */
  269.96 +  NIL,				/* sort messages */
  269.97 +  NIL,				/* thread messages */
  269.98 +  dummy_ping,			/* ping mailbox to see if still alive */
  269.99 +  dummy_check,			/* check for new messages */
 269.100 +  dummy_expunge,		/* expunge deleted messages */
 269.101 +  dummy_copy,			/* copy messages to another mailbox */
 269.102 +  dummy_append,			/* append string message to mailbox */
 269.103 +  NIL				/* garbage collect stream */
 269.104 +};
 269.105 +
 269.106 +
 269.107 +				/* prototype stream */
 269.108 +MAILSTREAM dummyproto = {&dummydriver};
 269.109 +
 269.110 +/* Dummy validate mailbox
 269.111 + * Accepts: mailbox name
 269.112 + * Returns: our driver if name is valid, NIL otherwise
 269.113 + */
 269.114 +
 269.115 +DRIVER *dummy_valid (char *name)
 269.116 +{
 269.117 +  char *s,*t,tmp[MAILTMPLEN];
 269.118 +  struct stat sbuf;
 269.119 +				/* must be valid local mailbox */
 269.120 +  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
 269.121 +				/* indeterminate INBOX */
 269.122 +    if (!*s) return &dummydriver;
 269.123 +				/* remove trailing \ */
 269.124 +    if ((t = strrchr (s,'\\')) && !t[1]) *t = '\0';
 269.125 +    if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
 269.126 +    case S_IFREG:		/* file */
 269.127 +    case S_IFDIR:		/* future use */
 269.128 +      return &dummydriver;
 269.129 +    }
 269.130 +  }
 269.131 +  return NIL;
 269.132 +}
 269.133 +
 269.134 +
 269.135 +/* Dummy manipulate driver parameters
 269.136 + * Accepts: function code
 269.137 + *	    function-dependent value
 269.138 + * Returns: function-dependent return value
 269.139 + */
 269.140 +
 269.141 +void *dummy_parameters (long function,void *value)
 269.142 +{
 269.143 +  return NIL;
 269.144 +}
 269.145 +
 269.146 +/* Dummy scan mailboxes
 269.147 + * Accepts: mail stream
 269.148 + *	    reference
 269.149 + *	    pattern to search
 269.150 + *	    string to scan
 269.151 + */
 269.152 +
 269.153 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 269.154 +{
 269.155 +  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
 269.156 +  long i = 0;
 269.157 +  if (!pat || !*pat) {		/* empty pattern? */
 269.158 +    if (dummy_canonicalize (test,ref,"*")) {
 269.159 +				/* tie off name at root */
 269.160 +      if (s = strchr (test,'\\')) *++s = '\0';
 269.161 +      else test[0] = '\0';
 269.162 +      dummy_listed (stream,'\\',test,LATT_NOSELECT,NIL);
 269.163 +    }
 269.164 +  }
 269.165 +				/* get canonical form of name */
 269.166 +  else if (dummy_canonicalize (test,ref,pat)) {
 269.167 +				/* found any wildcards? */
 269.168 +    if (s = strpbrk (test,"%*")) {
 269.169 +				/* yes, copy name up to that point */
 269.170 +      strncpy (file,test,(size_t) (i = s - test));
 269.171 +      file[i] = '\0';		/* tie off */
 269.172 +    }
 269.173 +    else strcpy (file,test);	/* use just that name then */
 269.174 +				/* find directory name */
 269.175 +    if (s = strrchr (file,'\\')) {
 269.176 +      *++s = '\0';		/* found, tie off at that point */
 269.177 +      s = file;
 269.178 +    }
 269.179 +				/* silly case */
 269.180 +    else if (file[0] == '#') s = file;
 269.181 +				/* do the work */
 269.182 +    dummy_list_work (stream,s,test,contents,0);
 269.183 +    if (pmatch ("INBOX",test))	/* always an INBOX */
 269.184 +      dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
 269.185 +  }
 269.186 +}
 269.187 +
 269.188 +/* Dummy list mailboxes
 269.189 + * Accepts: mail stream
 269.190 + *	    reference
 269.191 + *	    pattern to search
 269.192 + */
 269.193 +
 269.194 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 269.195 +{
 269.196 +  dummy_scan (stream,ref,pat,NIL);
 269.197 +}
 269.198 +
 269.199 +
 269.200 +/* Dummy list subscribed mailboxes
 269.201 + * Accepts: mail stream
 269.202 + *	    reference
 269.203 + *	    pattern to search
 269.204 + */
 269.205 +
 269.206 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 269.207 +{
 269.208 +  void *sdb = NIL;
 269.209 +  char *s,*t,test[MAILTMPLEN];
 269.210 +  int showuppers = pat[strlen (pat) - 1] == '%';
 269.211 +				/* get canonical form of name */
 269.212 +  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
 269.213 +    if (*s != '{') {
 269.214 +      if (pmatch_full (s,test,'\\')) {
 269.215 +	if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
 269.216 +	else mm_lsub (stream,'\\',s,NIL);
 269.217 +      }
 269.218 +      else while (showuppers && (t = strrchr (s,'\\'))) {
 269.219 +	*t = '\0';		/* tie off the name */
 269.220 +	if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
 269.221 +      }
 269.222 +    }
 269.223 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 269.224 +}
 269.225 +
 269.226 +
 269.227 +/* Dummy subscribe to mailbox
 269.228 + * Accepts: mail stream
 269.229 + *	    mailbox to add to subscription list
 269.230 + * Returns: T on success, NIL on failure
 269.231 + */
 269.232 +
 269.233 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
 269.234 +{
 269.235 +  char *s,tmp[MAILTMPLEN];
 269.236 +  struct stat sbuf;
 269.237 +				/* must be valid local mailbox */
 269.238 +  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
 269.239 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
 269.240 +  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
 269.241 +  mm_log (tmp,ERROR);
 269.242 +  return NIL;
 269.243 +}
 269.244 +
 269.245 +/* Dummy list mailboxes worker routine
 269.246 + * Accepts: mail stream
 269.247 + *	    directory name to search
 269.248 + *	    search pattern
 269.249 + *	    string to scan
 269.250 + *	    search level
 269.251 + */
 269.252 +
 269.253 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
 269.254 +		      long level)
 269.255 +{
 269.256 +  struct _finddata_t f;
 269.257 +  struct stat sbuf;
 269.258 +  long fhandle;
 269.259 +  char tmp[MAILTMPLEN];
 269.260 +  size_t len = 0;
 269.261 +				/* punt if bogus name */
 269.262 +  if (!mailboxdir (tmp,dir,NIL)) return;
 269.263 +				/* make directory wildcard */
 269.264 +  strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*");
 269.265 +				/* do nothing if can't open directory */
 269.266 +  if ((fhandle = _findfirst (tmp,&f)) >= 0) {  
 269.267 +				/* list it if at top-level */
 269.268 +    if (!level && dir && pmatch_full (dir,pat,'\\'))
 269.269 +      dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
 269.270 +				/* scan directory */
 269.271 +    if (!dir || dir[(len = strlen (dir)) - 1] == '\\') do
 269.272 +      if (((f.name[0] != '.') ||
 269.273 +	   (f.name[1] && ((f.name[1] != '.') || f.name[2]))) &&
 269.274 +	  ((len + strlen (f.name)) <= NETMAXMBX)) {
 269.275 +				/* see if name is useful */
 269.276 +	if (dir) sprintf (tmp,"%s%s",dir,f.name);
 269.277 +	else strcpy (tmp,f.name);
 269.278 +				/* make sure useful and can get info */
 269.279 +	if ((pmatch_full (tmp,pat,'\\') ||
 269.280 +	     pmatch_full (strcat (tmp,"\\"),pat,'\\') ||
 269.281 +	     dmatch (tmp,pat,'\\')) &&
 269.282 +	    mailboxdir (tmp,dir,f.name) && tmp[0] && !stat (tmp,&sbuf)) {
 269.283 +				/* now make name we'd return */
 269.284 +	  if (dir) sprintf (tmp,"%s%s",dir,f.name);
 269.285 +	  else strcpy (tmp,f.name);
 269.286 +				/* only interested in file type */
 269.287 +	  switch (sbuf.st_mode & S_IFMT) {
 269.288 +	  case S_IFDIR:		/* directory? */
 269.289 +	    if (pmatch_full (tmp,pat,'\\')) {
 269.290 +	      if (!dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))break;
 269.291 +	      strcat (tmp,"\\");/* set up for dmatch call */
 269.292 +	    }
 269.293 +				/* try again with trailing \ */
 269.294 +	    else if (pmatch_full (strcat (tmp,"\\"),pat,'\\') &&
 269.295 +		     !dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))
 269.296 +	      break;
 269.297 +	    if (dmatch (tmp,pat,'\\') &&
 269.298 +		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 269.299 +	      dummy_list_work (stream,tmp,pat,contents,level+1);
 269.300 +	    break;
 269.301 +	  case S_IFREG:		/* ordinary name */
 269.302 +	    if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
 269.303 +	      dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
 269.304 +	    break;
 269.305 +	  }
 269.306 +	}
 269.307 +      }
 269.308 +    while (!_findnext (fhandle,&f));
 269.309 +    _findclose(fhandle);
 269.310 +  }
 269.311 +}
 269.312 +
 269.313 +/* Mailbox found
 269.314 + * Accepts: hierarchy delimiter
 269.315 + *	    mailbox name
 269.316 + *	    attributes
 269.317 + *	    contents to search before calling mm_list()
 269.318 + * Returns: T, always
 269.319 + */
 269.320 +
 269.321 +#define BUFSIZE 4*MAILTMPLEN
 269.322 +
 269.323 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
 269.324 +		   long attributes,char *contents)
 269.325 +{
 269.326 +  struct stat sbuf;
 269.327 +  struct _finddata_t f;
 269.328 +  int fd,nochild;
 269.329 +  long fhandle,csiz,ssiz,bsiz;
 269.330 +  char *s,*buf,tmp[MAILTMPLEN];
 269.331 +				/* if not \NoInferiors */
 269.332 +  if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
 269.333 +      strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*") &&
 269.334 +      ((fhandle = _findfirst (tmp,&f)) >= 0)) {
 269.335 +    nochild = T;
 269.336 +    do if ((f.name[0] != '.') || (f.name[1] && ((f.name[1] != '.') ||
 269.337 +						f.name[2]))) nochild = NIL;
 269.338 +    while (nochild && !_findnext (fhandle,&f));
 269.339 +    attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
 269.340 +    _findclose (fhandle);	/* all done, flush directory */
 269.341 +  }
 269.342 +  if (contents) {		/* want to search contents? */
 269.343 +				/* forget it if can't select or open */
 269.344 +    if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
 269.345 +	!(s = dummy_file (tmp,name)) || stat (s,&sbuf) ||
 269.346 +	(csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0))
 269.347 +      return T;
 269.348 +				/* get buffer including slop */    
 269.349 +    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
 269.350 +    memset (buf,'\0',ssiz);	/* no slop area the first time */
 269.351 +    while (sbuf.st_size) {	/* until end of file */
 269.352 +      read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
 269.353 +      if (search ((unsigned char *) buf,bsiz+ssiz,
 269.354 +		  (unsigned char *) contents,csiz)) break;
 269.355 +      memcpy (buf,buf+BUFSIZE,ssiz);
 269.356 +      sbuf.st_size -= bsiz;	/* note that we read that much */
 269.357 +    }
 269.358 +    fs_give ((void **) &buf);	/* flush buffer */
 269.359 +    close (fd);			/* finished with file */
 269.360 +    if (!sbuf.st_size) return T;/* not found */
 269.361 +  }
 269.362 +				/* notify main program */
 269.363 +  mm_list (stream,delimiter,name,attributes);
 269.364 +  return T;
 269.365 +}
 269.366 +
 269.367 +/* Dummy create mailbox
 269.368 + * Accepts: mail stream
 269.369 + *	    mailbox name to create
 269.370 + * Returns: T on success, NIL on failure
 269.371 + */
 269.372 +
 269.373 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 269.374 +{
 269.375 +  char tmp[MAILTMPLEN];
 269.376 +  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox))
 269.377 +    return dummy_create_path (stream,tmp,NIL);
 269.378 +  sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 269.379 +  mm_log (tmp,ERROR);
 269.380 +  return NIL;
 269.381 +}
 269.382 +
 269.383 +
 269.384 +/* Dummy create path
 269.385 + * Accepts: mail stream
 269.386 + *	    path name to create
 269.387 + *	    directory mode
 269.388 + * Returns: T on success, NIL on failure
 269.389 + */
 269.390 +
 269.391 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
 269.392 +{
 269.393 +  struct stat sbuf;
 269.394 +  char c,*s,tmp[MAILTMPLEN];
 269.395 +  int fd;
 269.396 +  long ret = NIL;
 269.397 +  char *t = strrchr (path,'\\');
 269.398 +  char *pt = (path[1] == ':') ? path + 2 : path;
 269.399 +  int wantdir = t && !t[1];
 269.400 +  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
 269.401 +				/* found superior to this name? */
 269.402 +  if ((s = strrchr (pt,'\\')) && (s != pt)) {
 269.403 +    strncpy (tmp,path,(size_t) (s - path));
 269.404 +    tmp[s - path] = '\0';	/* make directory name for stat */
 269.405 +    c = *++s;			/* tie off in case need to recurse */
 269.406 +    *s = '\0';
 269.407 +				/* name doesn't exist, create it */
 269.408 +    if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 269.409 +	!dummy_create_path (stream,path,dirmode)) return NIL;
 269.410 +    *s = c;			/* restore full name */
 269.411 +  }
 269.412 +  if (wantdir) {		/* want to create directory? */
 269.413 +    ret = !mkdir (path);
 269.414 +    *t = '\\';			/* restore directory delimiter */
 269.415 +  }
 269.416 +				/* create file */
 269.417 +  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
 269.418 +    ret = !close (fd);		/* close file */
 269.419 +  if (!ret) {			/* error? */
 269.420 +    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,
 269.421 +	     strerror (errno));
 269.422 +    mm_log (tmp,ERROR);
 269.423 +  }
 269.424 +  return ret;			/* return status */
 269.425 +}
 269.426 +
 269.427 +/* Dummy delete mailbox
 269.428 + * Accepts: mail stream
 269.429 + *	    mailbox name to delete
 269.430 + * Returns: T on success, NIL on failure
 269.431 + */
 269.432 +
 269.433 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 269.434 +{
 269.435 +  struct stat sbuf;
 269.436 +  char *s,tmp[MAILTMPLEN];
 269.437 +  if (!(s = dummy_file (tmp,mailbox))) {
 269.438 +    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
 269.439 +    mm_log (tmp,ERROR);
 269.440 +  }
 269.441 +				/* no trailing \ */
 269.442 +  if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
 269.443 +  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
 269.444 +      rmdir (tmp) : unlink (tmp)) {
 269.445 +    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
 269.446 +    mm_log (tmp,ERROR);
 269.447 +    return NIL;
 269.448 +  }
 269.449 +  return T;			/* return success */
 269.450 +}
 269.451 +
 269.452 +
 269.453 +/* Mail rename mailbox
 269.454 + * Accepts: mail stream
 269.455 + *	    old mailbox name
 269.456 + *	    new mailbox name
 269.457 + * Returns: T on success, NIL on failure
 269.458 + */
 269.459 +
 269.460 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 269.461 +{
 269.462 +  struct stat sbuf;
 269.463 +  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
 269.464 +  long ret = NIL;
 269.465 +				/* no trailing \ allowed */
 269.466 +  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
 269.467 +      stat (oldname,&sbuf) || ((s = strrchr (s,'\\')) && !s[1] &&
 269.468 +			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
 269.469 +    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
 269.470 +    mm_log (mbx,ERROR);
 269.471 +    return NIL;
 269.472 +  }
 269.473 +  if (s) {			/* found a directory delimiter? */
 269.474 +    if (!s[1]) *s = '\0';	/* ignore trailing delimiter */
 269.475 +				/* found superior to destination name? */
 269.476 +    else if ((s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) {
 269.477 +      c = s[1];			/* remember character after delimiter */
 269.478 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 269.479 +				/* name doesn't exist, create it */
 269.480 +      if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 269.481 +	*s = '\\';		/* restore delimiter */
 269.482 +	if (!dummy_create (stream,mbx)) return NIL;
 269.483 +      }
 269.484 +      else *s = '\\';		/* restore delimiter */
 269.485 +      s[1] = c;			/* restore character after delimiter */
 269.486 +    }
 269.487 +  }
 269.488 +				/* rename of non-ex INBOX creates dest */
 269.489 +  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
 269.490 +    return dummy_create (NIL,mbx);
 269.491 +  if (rename (oldname,mbx)) {
 269.492 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
 269.493 +	     strerror (errno));
 269.494 +    mm_log (tmp,ERROR);
 269.495 +    return NIL;
 269.496 +  }
 269.497 +  return LONGT;			/* return success */
 269.498 +}
 269.499 +
 269.500 +/* Dummy open
 269.501 + * Accepts: stream to open
 269.502 + * Returns: stream on success, NIL on failure
 269.503 + */
 269.504 +
 269.505 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 269.506 +{
 269.507 +  int fd;
 269.508 +  char err[MAILTMPLEN],tmp[MAILTMPLEN];
 269.509 +  struct stat sbuf;
 269.510 +				/* OP_PROTOTYPE call */
 269.511 +  if (!stream) return &dummyproto;
 269.512 +  err[0] = '\0';		/* no error message yet */
 269.513 +				/* can we open the file? */
 269.514 +  if (!dummy_file (tmp,stream->mailbox))
 269.515 +    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
 269.516 +  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 269.517 +				/* no, error unless INBOX */
 269.518 +    if (compare_cstring (stream->mailbox,"INBOX"))
 269.519 +      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
 269.520 +  }
 269.521 +  else {			/* file had better be empty then */
 269.522 +    fstat (fd,&sbuf);		/* sniff at its size */
 269.523 +    close (fd);
 269.524 +    if (sbuf.st_size)		/* bogus format if non-empty */
 269.525 +      sprintf (err,"%.80s (file %.80s) is not in valid mailbox format",
 269.526 +	       stream->mailbox,tmp);
 269.527 +  }
 269.528 +  if (err[0]) {			/* if an error happened */
 269.529 +    mm_log (err,stream->silent ? WARN : ERROR);
 269.530 +    return NIL;
 269.531 +  }
 269.532 +  else if (!stream->silent) {	/* only if silence not requested */
 269.533 +    mail_exists (stream,0);	/* say there are 0 messages */
 269.534 +    mail_recent (stream,0);	/* and certainly no recent ones! */
 269.535 +    stream->uid_validity = (unsigned long) time (0);
 269.536 +  }
 269.537 +  stream->inbox = T;		/* note that it's an INBOX */
 269.538 +  return stream;		/* return success */
 269.539 +}
 269.540 +
 269.541 +
 269.542 +/* Dummy close
 269.543 + * Accepts: MAIL stream
 269.544 + *	    options
 269.545 + */
 269.546 +
 269.547 +void dummy_close (MAILSTREAM *stream,long options)
 269.548 +{
 269.549 +				/* return silently */
 269.550 +}
 269.551 +
 269.552 +/* Dummy ping mailbox
 269.553 + * Accepts: MAIL stream
 269.554 + * Returns: T if stream alive, else NIL
 269.555 + */
 269.556 +
 269.557 +long dummy_ping (MAILSTREAM *stream)
 269.558 +{
 269.559 +  MAILSTREAM *test;
 269.560 +				/* time to do another test? */
 269.561 +  if (time (0) >= ((time_t) (stream->gensym + 30))) {
 269.562 +				/* has mailbox format changed? */
 269.563 +    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
 269.564 +	(test->dtb != stream->dtb) &&
 269.565 +	(test = mail_open (NIL,stream->mailbox,NIL))) {
 269.566 +				/* preserve some resources */
 269.567 +      test->original_mailbox = stream->original_mailbox;
 269.568 +      stream->original_mailbox = NIL;
 269.569 +      test->sparep = stream->sparep;
 269.570 +      stream->sparep = NIL;
 269.571 +      test->sequence = stream->sequence;
 269.572 +      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
 269.573 +		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
 269.574 +			  sizeof (MAILSTREAM)));
 269.575 +				/* swap the streams */
 269.576 +      memcpy (stream,test,sizeof (MAILSTREAM));
 269.577 +      fs_give ((void **) &test);/* flush test now that copied */
 269.578 +				/* make sure application knows */
 269.579 +      mail_exists (stream,stream->recent = stream->nmsgs);
 269.580 +    }
 269.581 +				/* still hasn't changed */
 269.582 +    else stream->gensym = (unsigned long) time (0);
 269.583 +  }
 269.584 +  return T;
 269.585 +}
 269.586 +
 269.587 +
 269.588 +/* Dummy check mailbox
 269.589 + * Accepts: MAIL stream
 269.590 + * No-op for readonly files, since read/writer can expunge it from under us!
 269.591 + */
 269.592 +
 269.593 +void dummy_check (MAILSTREAM *stream)
 269.594 +{
 269.595 +  dummy_ping (stream);		/* invoke ping */
 269.596 +}
 269.597 +
 269.598 +
 269.599 +/* Dummy expunge mailbox
 269.600 + * Accepts: MAIL stream
 269.601 + *	    sequence to expunge if non-NIL
 269.602 + *	    expunge options
 269.603 + * Returns: T, always
 269.604 + */
 269.605 +
 269.606 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 269.607 +{
 269.608 +  return LONGT;
 269.609 +}
 269.610 +
 269.611 +/* Dummy copy message(s)
 269.612 + * Accepts: MAIL stream
 269.613 + *	    sequence
 269.614 + *	    destination mailbox
 269.615 + *	    options
 269.616 + * Returns: T if copy successful, else NIL
 269.617 + */
 269.618 +
 269.619 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 269.620 +{
 269.621 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 269.622 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 269.623 +  return NIL;
 269.624 +}
 269.625 +
 269.626 +
 269.627 +/* Dummy append message string
 269.628 + * Accepts: mail stream
 269.629 + *	    destination mailbox
 269.630 + *	    append callback function
 269.631 + *	    data for callback
 269.632 + * Returns: T on success, NIL on failure
 269.633 + */
 269.634 +
 269.635 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 269.636 +{
 269.637 +  struct stat sbuf;
 269.638 +  int fd = -1;
 269.639 +  int e;
 269.640 +  char tmp[MAILTMPLEN];
 269.641 +  MAILSTREAM *ts = default_proto (T);
 269.642 +  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox) &&
 269.643 +      ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
 269.644 +    if ((e = errno) == ENOENT)	/* failed, was it no such file? */
 269.645 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
 269.646 +		 (long) NIL);
 269.647 +    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
 269.648 +    mm_log (tmp,ERROR);		/* pass up error */
 269.649 +    return NIL;			/* always fails */
 269.650 +  }
 269.651 +  if (fd >= 0) {		/* found file? */
 269.652 +    fstat (fd,&sbuf);		/* get its size */
 269.653 +    close (fd);			/* toss out the fd */
 269.654 +    if (sbuf.st_size) ts = NIL;	/* non-empty file? */
 269.655 +  }
 269.656 +  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
 269.657 +  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
 269.658 +  mm_log (tmp,ERROR);
 269.659 +  return NIL;
 269.660 +}
 269.661 +
 269.662 +/* Dummy mail generate file string
 269.663 + * Accepts: temporary buffer to write into
 269.664 + *	    mailbox name string
 269.665 + * Returns: local file string or NIL if failure
 269.666 + */
 269.667 +
 269.668 +char *dummy_file (char *dst,char *name)
 269.669 +{
 269.670 +  char *s = mailboxfile (dst,name);
 269.671 +				/* return our standard inbox */
 269.672 +  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
 269.673 +}
 269.674 +
 269.675 +
 269.676 +/* Dummy canonicalize name
 269.677 + * Accepts: buffer to write name
 269.678 + *	    reference
 269.679 + *	    pattern
 269.680 + * Returns: T if success, NIL if failure
 269.681 + */
 269.682 +
 269.683 +long dummy_canonicalize (char *tmp,char *ref,char *pat)
 269.684 +{
 269.685 +  unsigned long i;
 269.686 +  char *s,dev[4];
 269.687 +				/* initially no device */
 269.688 +  dev[0] = dev[1] = dev[2] = dev[3] = '\0';
 269.689 +  if (ref) switch (*ref) {	/* preliminary reference check */
 269.690 +  case '{':			/* remote names not allowed */
 269.691 +    return NIL;			/* disallowed */
 269.692 +  case '\0':			/* empty reference string */
 269.693 +    break;
 269.694 +  default:			/* all other names */
 269.695 +    if (ref[1] == ':') {	/* start with device name? */
 269.696 +      dev[0] = *ref++; dev[1] = *ref++;
 269.697 +    }
 269.698 +    break;
 269.699 +  }
 269.700 +  if (pat[1] == ':') {		/* device name in pattern? */
 269.701 +    dev[0] = *pat++; dev[1] = *pat++;
 269.702 +    ref = NIL;			/* ignore reference */
 269.703 +  }
 269.704 +  switch (*pat) {
 269.705 +  case '#':			/* namespace names */
 269.706 +    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
 269.707 +    else return NIL;		/* unknown namespace */
 269.708 +    break;
 269.709 +  case '{':			/* remote names not allowed */
 269.710 +    return NIL;
 269.711 +  case '\\':			/* rooted name */
 269.712 +    ref = NIL;			/* ignore reference */
 269.713 +    break;
 269.714 +  }
 269.715 +				/* make sure device names are rooted */
 269.716 +  if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
 269.717 +				/* build name */
 269.718 +  sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
 269.719 +  ucase (tmp);			/* force upper case */
 269.720 +				/* count wildcards */
 269.721 +  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 269.722 +  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
 269.723 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 269.724 +    return NIL;
 269.725 +  }
 269.726 +  return T;
 269.727 +}
   270.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   270.2 +++ b/src/osdep/nt/env_nt.c	Mon Sep 14 15:17:45 2009 +0900
   270.3 @@ -0,0 +1,774 @@
   270.4 +/* ========================================================================
   270.5 + * Copyright 1988-2008 University of Washington
   270.6 + *
   270.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   270.8 + * you may not use this file except in compliance with the License.
   270.9 + * You may obtain a copy of the License at
  270.10 + *
  270.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  270.12 + *
  270.13 + * 
  270.14 + * ========================================================================
  270.15 + */
  270.16 +
  270.17 +/*
  270.18 + * Program:	NT environment routines
  270.19 + *
  270.20 + * Author:	Mark Crispin
  270.21 + *		UW Technology
  270.22 + *		University of Washington
  270.23 + *		Seattle, WA  98195
  270.24 + *		Internet: MRC@Washington.EDU
  270.25 + *
  270.26 + * Date:	1 August 1988
  270.27 + * Last Edited:	15 February 2008
  270.28 + */
  270.29 +
  270.30 +static char *myUserName = NIL;	/* user name */
  270.31 +static char *myLocalHost = NIL;	/* local host name */
  270.32 +static char *myHomeDir = NIL;	/* home directory name */
  270.33 +static char *myNewsrc = NIL;	/* newsrc file name */
  270.34 +static char *sysInbox = NIL;	/* system inbox name */
  270.35 +static long list_max_level = 5;	/* maximum level of list recursion */
  270.36 +				/* block environment init */
  270.37 +static short block_env_init = NIL;
  270.38 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  270.39 +				/* home namespace */
  270.40 +static NAMESPACE nshome = {"",'\\',NIL,NIL};
  270.41 +				/* UNIX other user namespace */
  270.42 +static NAMESPACE nsother = {"#user.",'\\',NIL,NIL};
  270.43 +				/* namespace list */
  270.44 +static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL};
  270.45 +static long alarm_countdown = 0;/* alarm count down */
  270.46 +static void (*alarm_rang) ();	/* alarm interrupt function */
  270.47 +static unsigned int rndm = 0;	/* initial `random' number */
  270.48 +static int server_nli = 0;	/* server and not logged in */
  270.49 +static int logtry = 3;		/* number of login tries */
  270.50 +				/* block notification */
  270.51 +static blocknotify_t mailblocknotify = mm_blocknotify;
  270.52 +				/* callback to get username */
  270.53 +static userprompt_t mailusername = NIL;
  270.54 +static long is_nt = -1;		/* T if NT, NIL if not NT, -1 unknown */
  270.55 +static HINSTANCE netapi = NIL;
  270.56 +typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *);
  270.57 +static GETINFO getinfo = NIL;
  270.58 +
  270.59 +#include "write.c"		/* include safe writing routines */
  270.60 +#include "pmatch.c"		/* include wildcard pattern matcher */
  270.61 +
  270.62 +
  270.63 +/* Get all authenticators */
  270.64 +
  270.65 +#include "auths.c"
  270.66 +
  270.67 +/* Environment manipulate parameters
  270.68 + * Accepts: function code
  270.69 + *	    function-dependent value
  270.70 + * Returns: function-dependent return value
  270.71 + */
  270.72 +
  270.73 +void *env_parameters (long function,void *value)
  270.74 +{
  270.75 +  void *ret = NIL;
  270.76 +  switch ((int) function) {
  270.77 +  case GET_NAMESPACE:
  270.78 +    ret = (void *) nslist;
  270.79 +    break;
  270.80 +  case SET_USERPROMPT :
  270.81 +    mailusername = (userprompt_t) value;
  270.82 +  case GET_USERPROMPT :
  270.83 +    ret = (void *) mailusername;
  270.84 +    break;
  270.85 +  case SET_HOMEDIR:
  270.86 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
  270.87 +    myHomeDir = cpystr ((char *) value);
  270.88 +  case GET_HOMEDIR:
  270.89 +    ret = (void *) myHomeDir;
  270.90 +    break;
  270.91 +  case SET_LOCALHOST:
  270.92 +    myLocalHost = cpystr ((char *) value);
  270.93 +  case GET_LOCALHOST:
  270.94 +    if (myLocalHost) fs_give ((void **) &myLocalHost);
  270.95 +    ret = (void *) myLocalHost;
  270.96 +    break;
  270.97 +  case SET_NEWSRC:
  270.98 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  270.99 +    myNewsrc = cpystr ((char *) value);
 270.100 +  case GET_NEWSRC:
 270.101 +    if (!myNewsrc) {		/* set news file name if not defined */
 270.102 +      char tmp[MAILTMPLEN];
 270.103 +      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
 270.104 +      myNewsrc = cpystr (tmp);
 270.105 +    }
 270.106 +    ret = (void *) myNewsrc;
 270.107 +    break;
 270.108 +  case SET_SYSINBOX:
 270.109 +    if (sysInbox) fs_give ((void **) &sysInbox);
 270.110 +    sysInbox = cpystr ((char *) value);
 270.111 +  case GET_SYSINBOX:
 270.112 +    ret = (void *) sysInbox;
 270.113 +    break;
 270.114 +  case SET_LISTMAXLEVEL:
 270.115 +    list_max_level = (long) value;
 270.116 +  case GET_LISTMAXLEVEL:
 270.117 +    ret = (void *) list_max_level;
 270.118 +    break;
 270.119 +  case SET_DISABLE822TZTEXT:
 270.120 +    no822tztext = value ? T : NIL;
 270.121 +  case GET_DISABLE822TZTEXT:
 270.122 +    ret = (void *) (no822tztext ? VOIDT : NIL);
 270.123 +    break;
 270.124 +  case SET_BLOCKENVINIT:
 270.125 +    block_env_init = value ? T : NIL;
 270.126 +  case GET_BLOCKENVINIT:
 270.127 +    ret = (void *) (block_env_init ? VOIDT : NIL);
 270.128 +    break;
 270.129 +  case SET_BLOCKNOTIFY:
 270.130 +    mailblocknotify = (blocknotify_t) value;
 270.131 +  case GET_BLOCKNOTIFY:
 270.132 +    ret = (void *) mailblocknotify;
 270.133 +    break;
 270.134 +  }
 270.135 +  return ret;
 270.136 +}
 270.137 +
 270.138 +/* Write current time
 270.139 + * Accepts: destination string
 270.140 + *	    optional format of day-of-week prefix
 270.141 + *	    format of date and time
 270.142 + *	    flag whether to append symbolic timezone
 270.143 + */
 270.144 +
 270.145 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
 270.146 +{
 270.147 +  time_t tn = time (0);
 270.148 +  struct tm *t = gmtime (&tn);
 270.149 +  int zone = t->tm_hour * 60 + t->tm_min;
 270.150 +  int julian = t->tm_yday;
 270.151 +  t = localtime (&tn);		/* get local time now */
 270.152 +				/* minus UTC minutes since midnight */
 270.153 +  zone = t->tm_hour * 60 + t->tm_min - zone;
 270.154 +  /* julian can be one of:
 270.155 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
 270.156 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
 270.157 +   *    0  local time is same day as UTC, no offset
 270.158 +   *   -1  local time is 1 day behind UTC, offset -24 hours
 270.159 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
 270.160 +   */
 270.161 +  if (julian = t->tm_yday -julian)
 270.162 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
 270.163 +  if (prefix) {			/* want day of week? */
 270.164 +    sprintf (date,prefix,days[t->tm_wday]);
 270.165 +    date += strlen (date);	/* make next sprintf append */
 270.166 +  }
 270.167 +				/* output the date */
 270.168 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 270.169 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
 270.170 +  if (suffix) {			/* append timezone suffix if desired */
 270.171 +    char *tz;
 270.172 +    tzset ();			/* get timezone from TZ environment stuff */
 270.173 +    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
 270.174 +    if (tz && tz[0]) {
 270.175 +      char *s;
 270.176 +      for (s = tz; *s; s++) if (*s & 0x80) return;
 270.177 +      sprintf (date + strlen (date)," (%.50s)",tz);
 270.178 +    }
 270.179 +  }
 270.180 +}
 270.181 +
 270.182 +
 270.183 +/* Write current time in RFC 822 format
 270.184 + * Accepts: destination string
 270.185 + */
 270.186 +
 270.187 +void rfc822_date (char *date)
 270.188 +{
 270.189 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
 270.190 +	   no822tztext ? NIL : T);
 270.191 +}
 270.192 +
 270.193 +
 270.194 +/* Write current time in fixed-width RFC 822 format
 270.195 + * Accepts: destination string
 270.196 + */
 270.197 +
 270.198 +void rfc822_fixed_date (char *date)
 270.199 +{
 270.200 +  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
 270.201 +}
 270.202 +
 270.203 +
 270.204 +/* Write current time in internal format
 270.205 + * Accepts: destination string
 270.206 + */
 270.207 +
 270.208 +void internal_date (char *date)
 270.209 +{
 270.210 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
 270.211 +}
 270.212 +
 270.213 +/* Return random number
 270.214 + */
 270.215 +
 270.216 +long random (void)
 270.217 +{
 270.218 +  if (!rndm) srand (rndm = (unsigned) time (0L));
 270.219 +  return (long) rand ();
 270.220 +}
 270.221 +
 270.222 +
 270.223 +/* Set alarm timer
 270.224 + * Accepts: new value
 270.225 + * Returns: old alarm value
 270.226 + */
 270.227 +
 270.228 +long alarm (long seconds)
 270.229 +{
 270.230 +  long ret = alarm_countdown;
 270.231 +  alarm_countdown = seconds;
 270.232 +  return ret;
 270.233 +}
 270.234 +
 270.235 +
 270.236 +/* The clock ticked
 270.237 + */
 270.238 +
 270.239 +void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
 270.240 +			    DWORD dwReserved1,DWORD dwReserved2)
 270.241 +{
 270.242 +  if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
 270.243 +}
 270.244 +
 270.245 +/* Initialize server
 270.246 + * Accepts: server name for syslog or NIL
 270.247 + *	    /etc/services service name or NIL
 270.248 + *	    alternate /etc/services service name or NIL
 270.249 + *	    clock interrupt handler
 270.250 + *	    kiss-of-death interrupt handler
 270.251 + *	    hangup interrupt handler
 270.252 + *	    termination interrupt handler
 270.253 + */
 270.254 +
 270.255 +void server_init (char *server,char *service,char *sslservice,
 270.256 +		  void *clkint,void *kodint,void *hupint,void *trmint,
 270.257 +		  void *staint)
 270.258 +{
 270.259 +  if (!check_nt ()) {
 270.260 +    if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database");
 270.261 +    server_nli = T;		/* Windows server not logged in */
 270.262 +  }
 270.263 +				/* only do this if for init call */
 270.264 +  if (server && service && sslservice) {
 270.265 +    long port;
 270.266 +    struct servent *sv;
 270.267 +				/* set server name in syslog */
 270.268 +    openlog (server,LOG_PID,LOG_MAIL);
 270.269 +    fclose (stderr);		/* possibly save a process ID */
 270.270 +    /* Use SSL if SSL service, or if server starts with "s" and not service */
 270.271 +    if (((port = tcp_serverport ()) >= 0)) {
 270.272 +      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
 270.273 +	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
 270.274 +      else if ((sv = getservbyname (sslservice,"tcp")) &&
 270.275 +	       (port == ntohs (sv->s_port))) {
 270.276 +	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
 270.277 +		tcp_clientaddr ());
 270.278 +	ssl_server_init (server);
 270.279 +      }
 270.280 +      else {			/* not service or SSL service port */
 270.281 +	syslog (LOG_DEBUG,"port %ld service init from %s",port,
 270.282 +		tcp_clientaddr ());
 270.283 +	if (*server == 's') ssl_server_init (server);
 270.284 +      }
 270.285 +    }
 270.286 +				/* make sure stdout does binary */
 270.287 +    setmode (fileno (stdin),O_BINARY);
 270.288 +    setmode (fileno (stdout),O_BINARY);
 270.289 +  }
 270.290 +  alarm_rang = clkint;		/* note the clock interrupt */
 270.291 +  timeBeginPeriod (1000);	/* set the timer interval */
 270.292 +  timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
 270.293 +}
 270.294 +
 270.295 +
 270.296 +/* Wait for stdin input
 270.297 + * Accepts: timeout in seconds
 270.298 + * Returns: T if have input on stdin, else NIL
 270.299 + */
 270.300 +
 270.301 +long server_input_wait (long seconds)
 270.302 +{
 270.303 +  fd_set rfd,efd;
 270.304 +  struct timeval tmo;
 270.305 +  FD_ZERO (&rfd);
 270.306 +  FD_ZERO (&efd);
 270.307 +  FD_SET (0,&rfd);
 270.308 +  FD_SET (0,&efd);
 270.309 +  tmo.tv_sec = seconds; tmo.tv_usec = 0;
 270.310 +  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
 270.311 +}
 270.312 +
 270.313 +/* Server log in
 270.314 + * Accepts: user name string
 270.315 + *	    password string
 270.316 + *	    authenticating user name string
 270.317 + *	    argument count
 270.318 + *	    argument vector
 270.319 + * Returns: T if password validated, NIL otherwise
 270.320 + */
 270.321 +
 270.322 +static int gotprivs = NIL;	/* once-only flag to grab privileges */
 270.323 +
 270.324 +long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
 270.325 +{
 270.326 +  HANDLE hdl;
 270.327 +  LUID tcbpriv;
 270.328 +  TOKEN_PRIVILEGES tkp;
 270.329 +  char *s;
 270.330 +				/* need to get privileges? */
 270.331 +  if (!gotprivs++ && check_nt ()) {
 270.332 +				/* hack for inetlisn */
 270.333 +    if (argc >= 2) myClientHost = argv[1];
 270.334 +				/* get process token and TCB priv value */
 270.335 +    if (!(OpenProcessToken (GetCurrentProcess (),
 270.336 +			    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
 270.337 +	  LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
 270.338 +      return NIL;
 270.339 +    tkp.PrivilegeCount = 1;	/* want to enable this privilege */
 270.340 +    tkp.Privileges[0].Luid = tcbpriv;
 270.341 +    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 270.342 +				/* enable it */
 270.343 +    AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
 270.344 +			   (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
 270.345 +				/* make sure it won */
 270.346 +    if (GetLastError() != ERROR_SUCCESS) return NIL;
 270.347 +  }
 270.348 +
 270.349 +				/* cretins still haven't given up */
 270.350 +  if ((strlen (user) >= MAILTMPLEN) ||
 270.351 +      (authuser && (strlen (authuser) >= MAILTMPLEN)))
 270.352 +    syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ());
 270.353 +  else if (logtry > 0) {	/* still have available logins? */
 270.354 +				/* authentication user not supported */
 270.355 +    if (authuser && *authuser && compare_cstring (authuser,user))
 270.356 +      mm_log ("Authentication id must match authorization id",ERROR);
 270.357 +    if (check_nt ()) {		/* NT: authserver_login() call not supported */
 270.358 +      if (!pass) mm_log ("Unsupported authentication mechanism",ERROR);
 270.359 +      else if ((		/* try to login and impersonate the guy */
 270.360 +#ifdef LOGIN32_LOGON_NETWORK
 270.361 +		LogonUser (user,".",pass,LOGON32_LOGON_NETWORK,
 270.362 +			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
 270.363 +#endif
 270.364 +		LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
 270.365 +			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
 270.366 +		LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
 270.367 +			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
 270.368 +		LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
 270.369 +			   LOGON32_PROVIDER_DEFAULT,&hdl)) &&
 270.370 +	       ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL);
 270.371 +    }
 270.372 +    else {			/* Win9x: done if from authserver_login() */
 270.373 +      if (!pass) server_nli = NIL;
 270.374 +				/* otherwise check MD5 database */
 270.375 +      else if (s = auth_md5_pwd (user)) {
 270.376 +				/* change NLI state based on pwd match */
 270.377 +	server_nli = strcmp (s,pass);
 270.378 +	memset (s,0,strlen (s));/* erase sensitive information */
 270.379 +	fs_give ((void **) &s);	/* flush erased password */
 270.380 +      }
 270.381 +				/* success if no longer NLI */
 270.382 +      if (!server_nli) return env_init (user,NIL);
 270.383 +    }
 270.384 +  }
 270.385 +  s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
 270.386 +				/* note the failure in the syslog */
 270.387 +  syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
 270.388 +  sleep (3);			/* slow down possible cracker */
 270.389 +  return NIL;
 270.390 +}
 270.391 +
 270.392 +/* Authenticated server log in
 270.393 + * Accepts: user name string
 270.394 + *	    authentication user name string
 270.395 + *	    argument count
 270.396 + *	    argument vector
 270.397 + * Returns: T if password validated, NIL otherwise
 270.398 + */
 270.399 +
 270.400 +long authserver_login (char *user,char *authuser,int argc,char *argv[])
 270.401 +{
 270.402 +  return server_login (user,NIL,authuser,argc,argv);
 270.403 +}
 270.404 +
 270.405 +
 270.406 +/* Log in as anonymous daemon
 270.407 + * Accepts: argument count
 270.408 + *	    argument vector
 270.409 + * Returns: T if successful, NIL if error
 270.410 + */
 270.411 +
 270.412 +long anonymous_login (int argc,char *argv[])
 270.413 +{
 270.414 +  return server_login ("Guest",NIL,NIL,argc,argv);
 270.415 +}
 270.416 +
 270.417 +
 270.418 +/* Initialize environment
 270.419 + * Accepts: user name
 270.420 + *          home directory, or NIL to use default
 270.421 + * Returns: T, always
 270.422 + */
 270.423 +
 270.424 +long env_init (char *user,char *home)
 270.425 +{
 270.426 +				/* don't init if blocked */
 270.427 +  if (block_env_init) return LONGT;
 270.428 +  if (myUserName) fatal ("env_init called twice!");
 270.429 +  myUserName = cpystr (user);	/* remember user name */
 270.430 +  if (!myHomeDir)		/* only if home directory not set up yet */
 270.431 +    myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user);
 270.432 +  return T;
 270.433 +}
 270.434 +
 270.435 +/* Check if NT
 270.436 + * Returns: T if NT, NIL if Win9x
 270.437 + */
 270.438 +
 270.439 +int check_nt (void)
 270.440 +{
 270.441 +  if (is_nt < 0) {		/* not yet set up? */
 270.442 +    OSVERSIONINFO ver;
 270.443 +    ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
 270.444 +    GetVersionEx (&ver);
 270.445 +    is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
 270.446 +  }
 270.447 +  return is_nt;
 270.448 +}
 270.449 +
 270.450 +
 270.451 +/* Return Windows home directory
 270.452 + * Accepts: user name
 270.453 + * Returns: home directory
 270.454 + */
 270.455 +
 270.456 +char *win_homedir (char *user)
 270.457 +{
 270.458 +  char *s,*t,tmp[MAILTMPLEN];
 270.459 +  PUSER_INFO_1 ui;
 270.460 +				/* Win9x default */
 270.461 +  if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ());
 270.462 +				/* get from user info on NT */
 270.463 +  else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) &&
 270.464 +	   (getinfo ||
 270.465 +	    (getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) &&
 270.466 +	   MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
 270.467 +				(WCHAR *) tmp,MAILTMPLEN) &&
 270.468 +	   !(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
 270.469 +	   WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
 270.470 +				tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) {
 270.471 +				/* make sure doesn't end with delimiter */
 270.472 +    if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0';
 270.473 +  }
 270.474 +				/* no home dir, found Win2K user profile? */
 270.475 +  else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) {      
 270.476 +    strncpy (tmp,s,t-s);	/* copy up to user name */
 270.477 +    sprintf (tmp+(t-s),"\\%.100s\\My Documents",user);
 270.478 +  }
 270.479 +				/* last resort NT default */
 270.480 +  else sprintf (tmp,"%s\\users\\default",defaultDrive ());
 270.481 +  return cpystr (tmp);
 270.482 +}
 270.483 +
 270.484 +
 270.485 +/* Return default drive
 270.486 + * Returns: default drive
 270.487 + */
 270.488 +
 270.489 +static char *defaultDrive (void)
 270.490 +{
 270.491 +  char *s = getenv ("SystemDrive");
 270.492 +  return (s && *s) ? s : "C:";
 270.493 +}
 270.494 +
 270.495 +/* Return my user name
 270.496 + * Accepts: pointer to optional flags
 270.497 + * Returns: my user name
 270.498 + */
 270.499 +
 270.500 +char *myusername_full (unsigned long *flags)
 270.501 +{
 270.502 +  UCHAR usr[MAILTMPLEN];
 270.503 +  DWORD len = MAILTMPLEN;
 270.504 +  char *user,*path,*d,*p,pth[MAILTMPLEN];
 270.505 +  char *ret = "SYSTEM";
 270.506 +				/* get user name if don't have it yet */
 270.507 +  if (!myUserName && !server_nli &&
 270.508 +				/* use callback, else logon name */
 270.509 +      ((mailusername && (user = (char *) (*mailusername) ())) ||
 270.510 +       (GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) {
 270.511 +    if (block_env_init) {	/* don't env_init if blocked */
 270.512 +      if (flags) *flags = MU_LOGGEDIN;
 270.513 +      return user;
 270.514 +    }
 270.515 +				/* try HOMEPATH, then HOME */
 270.516 +    if (p = getenv ("HOMEPATH"))
 270.517 +      sprintf (path = pth,"%s%s",
 270.518 +	       (d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p);
 270.519 +    else if (!(path = getenv ("HOME")))
 270.520 +      sprintf (path = pth,"%s\\My Documents",defaultDrive ());
 270.521 +				/* make sure doesn't end with delimiter */
 270.522 +    if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0';
 270.523 +    env_init (user,path);	/* initialize environment */
 270.524 +  }
 270.525 +  if (myUserName) {		/* logged in? */
 270.526 +    if (flags)			/* Guest is an anonymous user */
 270.527 +      *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
 270.528 +    ret = myUserName;		/* return user name */
 270.529 +  }
 270.530 +  else if (flags) *flags = MU_NOTLOGGEDIN;
 270.531 +  return ret;
 270.532 +}
 270.533 +
 270.534 +/* Return my local host name
 270.535 + * Returns: my local host name
 270.536 + */
 270.537 +
 270.538 +char *mylocalhost (void)
 270.539 +{
 270.540 +  if (!myLocalHost) {
 270.541 +    char tmp[MAILTMPLEN];
 270.542 +    if (!wsa_initted++) {	/* init Windows Sockets */
 270.543 +      WSADATA wsock;
 270.544 +      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
 270.545 +	wsa_initted = 0;
 270.546 +	return "random-pc";	/* try again later? */
 270.547 +      }
 270.548 +    }
 270.549 +    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
 270.550 +			  "random-pc" : tcp_canonical (tmp));
 270.551 +  }
 270.552 +  return myLocalHost;
 270.553 +}
 270.554 +
 270.555 +/* Return my home directory name
 270.556 + * Returns: my home directory name
 270.557 + */
 270.558 +
 270.559 +char *myhomedir ()
 270.560 +{
 270.561 +  if (!myHomeDir) myusername ();/* initialize if first time */
 270.562 +  return myHomeDir ? myHomeDir : "";
 270.563 +}
 270.564 +
 270.565 +
 270.566 +/* Return system standard INBOX
 270.567 + * Accepts: buffer string
 270.568 + */
 270.569 +
 270.570 +char *sysinbox ()
 270.571 +{
 270.572 +  char tmp[MAILTMPLEN];
 270.573 +  if (!sysInbox) {		/* initialize if first time */
 270.574 +    if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
 270.575 +    else sprintf (tmp,"%s\\INBOX",myhomedir ());
 270.576 +    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
 270.577 +  }
 270.578 +  return sysInbox;
 270.579 +}
 270.580 +
 270.581 +
 270.582 +/* Return mailbox directory name
 270.583 + * Accepts: destination buffer
 270.584 + *	    directory prefix
 270.585 + *	    name in directory
 270.586 + * Returns: file name or NIL if error
 270.587 + */
 270.588 +
 270.589 +char *mailboxdir (char *dst,char *dir,char *name)
 270.590 +{
 270.591 +  char tmp[MAILTMPLEN];
 270.592 +  if (dir || name) {		/* if either argument provided */
 270.593 +    if (dir) {
 270.594 +      if (strlen (dir) > NETMAXMBX) return NIL;
 270.595 +      strcpy (tmp,dir);		/* write directory prefix */
 270.596 +    }
 270.597 +    else tmp[0] = '\0';		/* otherwise null string */
 270.598 +    if (name) {
 270.599 +      if (strlen (name) > NETMAXMBX) return NIL;
 270.600 +      strcat (tmp,name);	/* write name in directory */
 270.601 +    }
 270.602 +				/* validate name, return its name */
 270.603 +    if (!mailboxfile (dst,tmp)) return NIL;
 270.604 +  }
 270.605 +  else strcpy (dst,myhomedir());/* no arguments, wants home directory */
 270.606 +  return dst;			/* return the name */
 270.607 +}
 270.608 +
 270.609 +/* Return mailbox file name
 270.610 + * Accepts: destination buffer
 270.611 + *	    mailbox name
 270.612 + * Returns: file name or empty string for driver-selected INBOX or NIL if error
 270.613 + */
 270.614 +
 270.615 +char *mailboxfile (char *dst,char *name)
 270.616 +{
 270.617 +  char homedev[3];
 270.618 +  char *dir = myhomedir ();
 270.619 +  if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) {
 270.620 +    homedev[0] = dir[0];	/* copy home device */
 270.621 +    homedev[1] = dir[1];
 270.622 +    homedev[2] = '\0';
 270.623 +  }
 270.624 +  else homedev[0] = '\0';	/* ??no home device?? */
 270.625 +  *dst = '\0';			/* default to empty string */
 270.626 +				/* check for INBOX */
 270.627 +  if (!compare_cstring (name,"INBOX"));
 270.628 +				/* reject names with / */
 270.629 +  else if (strchr (name,'/')) dst = NIL;
 270.630 +  else switch (*name) {
 270.631 +  case '#':			/* namespace names */
 270.632 +    if (((name[1] == 'u') || (name[1] == 'U')) &&
 270.633 +	((name[2] == 's') || (name[2] == 'S')) &&
 270.634 +	((name[3] == 'e') || (name[3] == 'E')) &&
 270.635 +	((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) {
 270.636 +				/* copy user name to destination buffer */
 270.637 +      for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++);
 270.638 +      *dir++ = '\0';		/* tie off user name */
 270.639 +				/* look up homedir for user name */
 270.640 +      if (dir = win_homedir (dst)) {
 270.641 +				/* build resulting name */
 270.642 +	sprintf (dst,"%s\\%s",dir,name);
 270.643 +	fs_give ((void **) &dir);
 270.644 +      }
 270.645 +      else dst = NIL;
 270.646 +    }
 270.647 +    else dst = NIL;		/* unknown namespace name */
 270.648 +    break;
 270.649 +  case '\\':			/* absolute path on default drive? */
 270.650 +    sprintf (dst,"%s%s",homedev,name);
 270.651 +    break;
 270.652 +  default:			/* any other name */
 270.653 +    if (name[1] == ':') {	/* some other drive? */
 270.654 +      if (name[2] == '\\') strcpy (dst,name);
 270.655 +      else sprintf (dst,"%c:\\%s",name[0],name+2);
 270.656 +    }
 270.657 +				/* build home-directory relative name */
 270.658 +    else sprintf (dst,"%s\\%s",dir,name);
 270.659 +  }
 270.660 +  return dst;			/* return it */
 270.661 +}
 270.662 +
 270.663 +/* Lock file name
 270.664 + * Accepts: return buffer for file name
 270.665 + *	    file name
 270.666 + *	    locking to be placed on file if non-NIL
 270.667 + * Returns: file descriptor of lock or -1 if error
 270.668 + */
 270.669 +
 270.670 +int lockname (char *lock,char *fname,int op)
 270.671 +{
 270.672 +  int ld;
 270.673 +  char c,*s;
 270.674 +				/* Win2K and Win98 have TEMP under windir */
 270.675 +  if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) ||
 270.676 +				/* NT4, NT3.x and Win95 use one of these */
 270.677 +	(s = lockdir (lock,getenv ("TEMP"),NIL)) ||
 270.678 +	(s = lockdir (lock,getenv ("TMP"),NIL)) ||
 270.679 +	(s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
 270.680 +				/* try one of these */
 270.681 +	(s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) ||
 270.682 +	(s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) ||
 270.683 +				/* C:\TEMP is last resort */
 270.684 +	(s = lockdir (lock,defaultDrive (),"TEMP")))) {
 270.685 +    mm_log ("Unable to find temporary directory",ERROR);
 270.686 +    return -1;
 270.687 +  }
 270.688 +				/* generate file name */
 270.689 +  while (c = *fname++) switch (c) {
 270.690 +  case '/': case '\\': case ':':
 270.691 +    *s++ = '!';			/* convert bad chars to ! */
 270.692 +    break;
 270.693 +  default:
 270.694 +    *s++ = c;
 270.695 +    break;
 270.696 +  }
 270.697 +  *s++ = c;			/* tie off name */
 270.698 +				/* get the lock */
 270.699 +  if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
 270.700 +    flock (ld,op);		/* apply locking function */
 270.701 +  return ld;			/* return locking file descriptor */
 270.702 +}
 270.703 +
 270.704 +/* Build lock directory, check to see if it exists
 270.705 + * Accepts: return buffer for lock directory
 270.706 + *	    first part of possible name
 270.707 + *	    optional second part
 270.708 + * Returns: pointer to end of buffer if buffer has a good name, else NIL
 270.709 + */
 270.710 +
 270.711 +char *lockdir (char *lock,char *first,char *last)
 270.712 +{
 270.713 +  struct stat sbuf;
 270.714 +  char c,*s;
 270.715 +  if (first && *first) {	/* first part must be non-NIL */
 270.716 +				/* copy first part */
 270.717 +    for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c);
 270.718 +    if (last && *last) {	/* copy last part if specified */
 270.719 +				/* write trailing \ in case not in first */
 270.720 +      if (s[-1] != '\\') *s++ = '\\';
 270.721 +      while (c = *last++) *s++ = (c == '/') ? '\\' : c;
 270.722 +    }
 270.723 +    if (s[-1] == '\\') --s;	/* delete trailing \ if any */
 270.724 +    *s = s[1] = '\0';		/* tie off name at this point */
 270.725 +    if (!stat (lock,&sbuf)) {	/* does the name exist? */
 270.726 +      *s++ = '\\';		/* yes, reinstall trailing \ */
 270.727 +      return s;			/* return the name */
 270.728 +    }
 270.729 +  }
 270.730 +  return NIL;			/* failed */
 270.731 +}
 270.732 +
 270.733 +
 270.734 +/* Unlock file descriptor
 270.735 + * Accepts: file descriptor
 270.736 + *	    lock file name from lockfd()
 270.737 + */
 270.738 +
 270.739 +void unlockfd (int fd,char *lock)
 270.740 +{
 270.741 +  flock (fd,LOCK_UN);		/* unlock it */
 270.742 +  close (fd);			/* close it */
 270.743 +}
 270.744 +
 270.745 +
 270.746 +/* Determine default prototype stream to user
 270.747 + * Accepts: type (NIL for create, T for append)
 270.748 + * Returns: default prototype stream
 270.749 + */
 270.750 +
 270.751 +MAILSTREAM *default_proto (long type)
 270.752 +{
 270.753 +  extern MAILSTREAM CREATEPROTO,APPENDPROTO;
 270.754 +  return type ? &APPENDPROTO : &CREATEPROTO;
 270.755 +}
 270.756 +
 270.757 +/* Default block notify routine
 270.758 + * Accepts: reason for calling
 270.759 + *	    data
 270.760 + * Returns: data
 270.761 + */
 270.762 +
 270.763 +void *mm_blocknotify (int reason,void *data)
 270.764 +{
 270.765 +  void *ret = data;
 270.766 +  switch (reason) {
 270.767 +  case BLOCK_SENSITIVE:		/* entering sensitive code */
 270.768 +    ret = (void *) alarm (0);
 270.769 +    break;
 270.770 +  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
 270.771 +    if ((unsigned int) data) alarm ((unsigned int) data);
 270.772 +    break;
 270.773 +  default:			/* ignore all other reasons */
 270.774 +    break;
 270.775 +  }
 270.776 +  return ret;
 270.777 +}
   271.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   271.2 +++ b/src/osdep/nt/env_nt.h	Mon Sep 14 15:17:45 2009 +0900
   271.3 @@ -0,0 +1,68 @@
   271.4 +/* ========================================================================
   271.5 + * Copyright 1988-2006 University of Washington
   271.6 + *
   271.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   271.8 + * you may not use this file except in compliance with the License.
   271.9 + * You may obtain a copy of the License at
  271.10 + *
  271.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  271.12 + *
  271.13 + * 
  271.14 + * ========================================================================
  271.15 + */
  271.16 +
  271.17 +/*
  271.18 + * Program:	NT environment routines
  271.19 + *
  271.20 + * Author:	Mark Crispin
  271.21 + *		Networks and Distributed Computing
  271.22 + *		Computing & Communications
  271.23 + *		University of Washington
  271.24 + *		Administration Building, AG-44
  271.25 + *		Seattle, WA  98195
  271.26 + *		Internet: MRC@CAC.Washington.EDU
  271.27 + *
  271.28 + * Date:	1 August 1988
  271.29 + * Last Edited:	30 August 2006
  271.30 + */
  271.31 +
  271.32 +
  271.33 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\MAILBOX.LST",myhomedir ())
  271.34 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\MAILBOX.TMP",myhomedir ())
  271.35 +
  271.36 +/* Note: the \CRAM-MD5.PWD file only works on DOS-based Windows (Win9x/Me)
  271.37 + * and not on NT-based Windows (WinNT/2K/XP).  If installed on NT-based
  271.38 + * Windows, servers will advertise CRAM-MD5 authentication but it will
  271.39 + * never succeed.
  271.40 + */
  271.41 +
  271.42 +#define MD5ENABLE "\\cram-md5.pwd"
  271.43 +
  271.44 +#define L_SET SEEK_SET
  271.45 +
  271.46 +/* Function prototypes */
  271.47 +
  271.48 +#include "env.h"
  271.49 +
  271.50 +void rfc822_fixed_date (char *date);
  271.51 +long env_init (char *user,char *home);
  271.52 +int check_nt (void);
  271.53 +char *win_homedir (char *user);
  271.54 +static char *defaultDrive (void);
  271.55 +char *myusername_full (unsigned long *flags);
  271.56 +#define MU_LOGGEDIN 0
  271.57 +#define MU_NOTLOGGEDIN 1
  271.58 +#define MU_ANONYMOUS 2
  271.59 +#define myusername() \
  271.60 +  myusername_full (NIL)
  271.61 +char *sysinbox ();
  271.62 +char *mailboxdir (char *dst,char *dir,char *name);
  271.63 +int lockname (char *lock,char *fname,int op);
  271.64 +char *lockdir (char *lock,char *first,char *last);
  271.65 +void unlockfd (int fd,char *lock);
  271.66 +long safe_write (int fd,char *buf,long nbytes);
  271.67 +void *mm_blocknotify (int reason,void *data);
  271.68 +long random ();
  271.69 +#if _MSC_VER < 700
  271.70 +#define getpid random
  271.71 +#endif
   272.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   272.2 +++ b/src/osdep/nt/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
   272.3 @@ -0,0 +1,99 @@
   272.4 +/* ========================================================================
   272.5 + * Copyright 1988-2007 University of Washington
   272.6 + *
   272.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   272.8 + * you may not use this file except in compliance with the License.
   272.9 + * You may obtain a copy of the License at
  272.10 + *
  272.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  272.12 + *
  272.13 + * 
  272.14 + * ========================================================================
  272.15 + */
  272.16 +
  272.17 +/*
  272.18 + * Program:	File descriptor string routines
  272.19 + *
  272.20 + * Author:	Mark Crispin
  272.21 + *		Networks and Distributed Computing
  272.22 + *		Computing & Communications
  272.23 + *		University of Washington
  272.24 + *		Administration Building, AG-44
  272.25 + *		Seattle, WA  98195
  272.26 + *		Internet: MRC@CAC.Washington.EDU
  272.27 + *
  272.28 + * Date:	15 April 1997
  272.29 + * Last Edited:	4 April 2007
  272.30 + */
  272.31 +
  272.32 +#include "mail.h"
  272.33 +#include "osdep.h"
  272.34 +#include "misc.h"
  272.35 +#include "fdstring.h"
  272.36 +
  272.37 +/* String driver for fd stringstructs */
  272.38 +
  272.39 +static void fd_string_init (STRING *s,void *data,unsigned long size);
  272.40 +static char fd_string_next (STRING *s);
  272.41 +static void fd_string_setpos (STRING *s,unsigned long i);
  272.42 +
  272.43 +STRINGDRIVER fd_string = {
  272.44 +  fd_string_init,		/* initialize string structure */
  272.45 +  fd_string_next,		/* get next byte in string structure */
  272.46 +  fd_string_setpos		/* set position in string structure */
  272.47 +};
  272.48 +
  272.49 +
  272.50 +/* Initialize string structure for fd stringstruct
  272.51 + * Accepts: string structure
  272.52 + *	    pointer to string
  272.53 + *	    size of string
  272.54 + */
  272.55 +
  272.56 +static void fd_string_init (STRING *s,void *data,unsigned long size)
  272.57 +{
  272.58 +  FDDATA *d = (FDDATA *) data;
  272.59 +				/* note fd */
  272.60 +  s->data = (void *) (unsigned long) d->fd;
  272.61 +  s->data1 = d->pos;		/* note file offset */
  272.62 +  s->size = size;		/* note size */
  272.63 +  s->curpos = s->chunk = d->chunk;
  272.64 +  s->chunksize = (unsigned long) d->chunksize;
  272.65 +  s->offset = 0;		/* initial position */
  272.66 +				/* and size of data */
  272.67 +  s->cursize = min (s->chunksize,size);
  272.68 +				/* move to that position in the file */
  272.69 +  lseek (d->fd,d->pos,L_SET);
  272.70 +  read (d->fd,s->chunk,(size_t) s->cursize);
  272.71 +}
  272.72 +
  272.73 +/* Get next character from fd stringstruct
  272.74 + * Accepts: string structure
  272.75 + * Returns: character, string structure chunk refreshed
  272.76 + */
  272.77 +
  272.78 +static char fd_string_next (STRING *s)
  272.79 +{
  272.80 +  char c = *s->curpos++;	/* get next byte */
  272.81 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
  272.82 +  return c;			/* return the byte */
  272.83 +}
  272.84 +
  272.85 +
  272.86 +/* Set string pointer position for fd stringstruct
  272.87 + * Accepts: string structure
  272.88 + *	    new position
  272.89 + */
  272.90 +
  272.91 +static void fd_string_setpos (STRING *s,unsigned long i)
  272.92 +{
  272.93 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
  272.94 +  s->offset = i;		/* set new offset */
  272.95 +  s->curpos = s->chunk;		/* reset position */
  272.96 +				/* set size of data */
  272.97 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
  272.98 +				/* move to that position in the file */
  272.99 +    lseek ((long) s->data,s->data1 + s->offset,L_SET);
 272.100 +    read ((long) s->data,s->curpos,(size_t) s->cursize);
 272.101 +  }
 272.102 +}
   273.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   273.2 +++ b/src/osdep/nt/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
   273.3 @@ -0,0 +1,39 @@
   273.4 +/* ========================================================================
   273.5 + * Copyright 1988-2006 University of Washington
   273.6 + *
   273.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   273.8 + * you may not use this file except in compliance with the License.
   273.9 + * You may obtain a copy of the License at
  273.10 + *
  273.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  273.12 + *
  273.13 + * 
  273.14 + * ========================================================================
  273.15 + */
  273.16 +
  273.17 +/*
  273.18 + * Program:	File descriptor string routines
  273.19 + *
  273.20 + * Author:	Mark Crispin
  273.21 + *		Networks and Distributed Computing
  273.22 + *		Computing & Communications
  273.23 + *		University of Washington
  273.24 + *		Administration Building, AG-44
  273.25 + *		Seattle, WA  98195
  273.26 + *		Internet: MRC@CAC.Washington.EDU
  273.27 + *
  273.28 + * Date:	15 April 1997
  273.29 + * Last Edited:	30 August 2006
  273.30 + */
  273.31 +
  273.32 +/* Driver-dependent data passed to init method */
  273.33 +
  273.34 +typedef struct fd_data {
  273.35 +  int fd;			/* file descriptor */
  273.36 +  unsigned long pos;		/* initial position */
  273.37 +  char *chunk;			/* I/O buffer chunk */
  273.38 +  unsigned long chunksize;	/* I/O buffer chunk length */
  273.39 +} FDDATA;
  273.40 +
  273.41 +
  273.42 +extern STRINGDRIVER fd_string;
   274.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   274.2 +++ b/src/osdep/nt/fs_nt.c	Mon Sep 14 15:17:45 2009 +0900
   274.3 @@ -0,0 +1,62 @@
   274.4 +/* ========================================================================
   274.5 + * Copyright 1988-2006 University of Washington
   274.6 + *
   274.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   274.8 + * you may not use this file except in compliance with the License.
   274.9 + * You may obtain a copy of the License at
  274.10 + *
  274.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  274.12 + *
  274.13 + * 
  274.14 + * ========================================================================
  274.15 + */
  274.16 +
  274.17 +/*
  274.18 + * Program:	Free storage management routines
  274.19 + *
  274.20 + * Author:	Mark Crispin
  274.21 + *		Networks and Distributed Computing
  274.22 + *		Computing & Communications
  274.23 + *		University of Washington
  274.24 + *		Administration Building, AG-44
  274.25 + *		Seattle, WA  98195
  274.26 + *		Internet: MRC@CAC.Washington.EDU
  274.27 + *
  274.28 + * Date:	1 August 1988
  274.29 + * Last Edited:	30 August 2006
  274.30 + */
  274.31 +
  274.32 +/* Get a block of free storage
  274.33 + * Accepts: size of desired block
  274.34 + * Returns: free storage block
  274.35 + */
  274.36 +
  274.37 +void *fs_get (size_t size)
  274.38 +{
  274.39 +  void *block = malloc (size ? size : (size_t) 1);
  274.40 +  if (!block) fatal ("Out of memory");
  274.41 +  return (block);
  274.42 +}
  274.43 +
  274.44 +
  274.45 +/* Resize a block of free storage
  274.46 + * Accepts: ** pointer to current block
  274.47 + *	    new size
  274.48 + */
  274.49 +
  274.50 +void fs_resize (void **block,size_t size)
  274.51 +{
  274.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  274.53 +    fatal ("Can't resize memory");
  274.54 +}
  274.55 +
  274.56 +
  274.57 +/* Return a block of free storage
  274.58 + * Accepts: ** pointer to free storage block
  274.59 + */
  274.60 +
  274.61 +void fs_give (void **block)
  274.62 +{
  274.63 +  free (*block);
  274.64 +  *block = NIL;
  274.65 +}
   275.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   275.2 +++ b/src/osdep/nt/ftl_nt.c	Mon Sep 14 15:17:45 2009 +0900
   275.3 @@ -0,0 +1,38 @@
   275.4 +/* ========================================================================
   275.5 + * Copyright 1988-2006 University of Washington
   275.6 + *
   275.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   275.8 + * you may not use this file except in compliance with the License.
   275.9 + * You may obtain a copy of the License at
  275.10 + *
  275.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  275.12 + *
  275.13 + * 
  275.14 + * ========================================================================
  275.15 + */
  275.16 +
  275.17 +/*
  275.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  275.19 + *
  275.20 + * Author:	Mark Crispin
  275.21 + *		Networks and Distributed Computing
  275.22 + *		Computing & Communications
  275.23 + *		University of Washington
  275.24 + *		Administration Building, AG-44
  275.25 + *		Seattle, WA  98195
  275.26 + *		Internet: MRC@CAC.Washington.EDU
  275.27 + *
  275.28 + * Date:	1 August 1988
  275.29 + * Last Edited:	30 August 2006
  275.30 + */
  275.31 +
  275.32 +
  275.33 +/* Report a fatal error
  275.34 + * Accepts: string to output
  275.35 + */
  275.36 +
  275.37 +void fatal (char *string)
  275.38 +{
  275.39 +  mm_fatal (string);		/* pass up the string */
  275.40 +  abort ();			/* die horribly */
  275.41 +}
   276.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   276.2 +++ b/src/osdep/nt/ip4_nt.c	Mon Sep 14 15:17:45 2009 +0900
   276.3 @@ -0,0 +1,184 @@
   276.4 +/* ========================================================================
   276.5 + * Copyright 1988-2006 University of Washington
   276.6 + *
   276.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   276.8 + * you may not use this file except in compliance with the License.
   276.9 + * You may obtain a copy of the License at
  276.10 + *
  276.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  276.12 + *
  276.13 + * 
  276.14 + * ========================================================================
  276.15 + */
  276.16 +
  276.17 +/*
  276.18 + * Program:	UNIX IPv4 routines
  276.19 + *
  276.20 + * Author:	Mark Crispin
  276.21 + *		Networks and Distributed Computing
  276.22 + *		Computing & Communications
  276.23 + *		University of Washington
  276.24 + *		Administration Building, AG-44
  276.25 + *		Seattle, WA  98195
  276.26 + *		Internet: MRC@CAC.Washington.EDU
  276.27 + *
  276.28 + * Date:	18 December 2003
  276.29 + * Last Edited:	30 August 2006
  276.30 + */
  276.31 +
  276.32 +#define SADRLEN sizeof (struct sockaddr)
  276.33 +
  276.34 +#define SADR4(sadr) ((struct sockaddr_in *) sadr)
  276.35 +#define SADR4LEN sizeof (struct sockaddr_in)
  276.36 +#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
  276.37 +#define ADR4LEN sizeof (struct in_addr)
  276.38 +#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
  276.39 +
  276.40 +
  276.41 +/* IP abstraction layer */
  276.42 +
  276.43 +char *ip_sockaddrtostring (struct sockaddr *sadr);
  276.44 +long ip_sockaddrtoport (struct sockaddr *sadr);
  276.45 +void *ip_stringtoaddr (char *text,size_t *len,int *family);
  276.46 +struct sockaddr *ip_newsockaddr (size_t *len);
  276.47 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
  276.48 +			      unsigned short port,size_t *len);
  276.49 +char *ip_sockaddrtoname (struct sockaddr *sadr);
  276.50 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
  276.51 +		     void **next);
  276.52 +
  276.53 +/* Return IP address string from socket address
  276.54 + * Accepts: socket address
  276.55 + * Returns: IP address as name string
  276.56 + */
  276.57 +
  276.58 +char *ip_sockaddrtostring (struct sockaddr *sadr)
  276.59 +{
  276.60 +  return (sadr->sa_family == PF_INET) ?
  276.61 +    inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4";
  276.62 +}
  276.63 +
  276.64 +
  276.65 +/* Return port from socket address
  276.66 + * Accepts: socket address
  276.67 + * Returns: port number or -1 if can't determine it
  276.68 + */
  276.69 +
  276.70 +long ip_sockaddrtoport (struct sockaddr *sadr)
  276.71 +{
  276.72 +  return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1;
  276.73 +}
  276.74 +
  276.75 +
  276.76 +/* Return IP address from string
  276.77 + * Accepts: name string
  276.78 + *	    pointer to returned length
  276.79 + *	    pointer to returned address family
  276.80 + * Returns: address if valid, length and family updated, or NIL
  276.81 + */
  276.82 +
  276.83 +void *ip_stringtoaddr (char *text,size_t *len,int *family)
  276.84 +{
  276.85 +  unsigned long adr;
  276.86 +  struct in_addr *ret;
  276.87 +				/* get address */
  276.88 +  if ((adr = inet_addr (text)) == -1) ret = NIL;
  276.89 +  else {			/* make in_addr */
  276.90 +    ret = (struct in_addr *) fs_get (*len = ADR4LEN);
  276.91 +    *family = AF_INET;		/* IPv4 */
  276.92 +    ret->s_addr = adr;		/* set address */
  276.93 +  }
  276.94 +  return (void *) ret;
  276.95 +}
  276.96 +
  276.97 +/* Create a maximum-size socket address
  276.98 + * Accepts: pointer to return maximum socket address length
  276.99 + * Returns: new, empty socket address of maximum size
 276.100 + */
 276.101 +
 276.102 +struct sockaddr *ip_newsockaddr (size_t *len)
 276.103 +{
 276.104 +  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
 276.105 +}
 276.106 +
 276.107 +
 276.108 +/* Stuff a socket address
 276.109 + * Accepts: address family
 276.110 + *	    IPv4 address
 276.111 + *	    length of address (always 4 in IPv4)
 276.112 + *	    port number
 276.113 + *	    pointer to return socket address length
 276.114 + * Returns: socket address or NIL if error
 276.115 + */
 276.116 +
 276.117 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
 276.118 +			      unsigned short port,size_t *len)
 276.119 +{
 276.120 +  struct sockaddr *sadr = ip_newsockaddr (len);
 276.121 +  switch (family) {		/* build socket address based upon family */
 276.122 +  case AF_INET:			/* IPv4 */
 276.123 +    sadr->sa_family = PF_INET;
 276.124 +				/* copy host address */
 276.125 +    memcpy (&SADR4ADR (sadr),adr,adrlen);
 276.126 +				/* copy port number in network format */
 276.127 +    SADR4PORT (sadr) = htons (port);
 276.128 +    *len = SADR4LEN;
 276.129 +    break;
 276.130 +  default:			/* non-IP?? */
 276.131 +    sadr->sa_family = PF_UNSPEC;
 276.132 +    break;
 276.133 +  }
 276.134 +  return sadr;
 276.135 +}
 276.136 +
 276.137 +/* Return name from socket address
 276.138 + * Accepts: socket address
 276.139 + * Returns: canonical name for that address or NIL if none
 276.140 + */
 276.141 +
 276.142 +char *ip_sockaddrtoname (struct sockaddr *sadr)
 276.143 +{
 276.144 +  struct hostent *he;
 276.145 +  return ((sadr->sa_family == PF_INET) &&
 276.146 +	  (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ?
 276.147 +    (char *) he->h_name : NIL;
 276.148 +}
 276.149 +
 276.150 +
 276.151 +/* Return address from name
 276.152 + * Accepts: name or NIL to return next address
 276.153 + *	    pointer to previous/returned length
 276.154 + *	    pointer to previous/returned address family
 276.155 + *	    pointer to previous/returned canonical name
 276.156 + *	    pointer to previous/return state for next-address calls
 276.157 + * Returns: address with length/family/canonical updated if needed, or NIL
 276.158 + */
 276.159 +
 276.160 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
 276.161 +		     void **next)
 276.162 +{
 276.163 +  char **adl,tmp[MAILTMPLEN];
 276.164 +  struct hostent *he;
 276.165 +  if (name) {			/* first lookup? */
 276.166 +				/* yes, do case-independent lookup */
 276.167 +    if ((strlen (name) < MAILTMPLEN) &&
 276.168 +	(he = gethostbyname (lcase (strcpy (tmp,name))))) {
 276.169 +      adl = he->h_addr_list;
 276.170 +      if (len) *len = he->h_length;
 276.171 +      if (family) *family = he->h_addrtype;
 276.172 +      if (canonical) *canonical = (char *) he->h_name;
 276.173 +      if (next) *next = (void *) adl;
 276.174 +    }
 276.175 +    else {			/* error */
 276.176 +      adl = NIL;
 276.177 +      if (len) *len = 0;
 276.178 +      if (family) *family = 0;
 276.179 +      if (canonical) *canonical = NIL;
 276.180 +      if (next) *next = NIL;
 276.181 +    }
 276.182 +  }
 276.183 +				/* return next in series */
 276.184 +  else if (next && (adl = (char **) *next)) *next = ++adl;
 276.185 +  else adl = NIL;		/* failure */
 276.186 +  return adl ? (void *) *adl : NIL;
 276.187 +}
   277.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   277.2 +++ b/src/osdep/nt/ip6_nt.c	Mon Sep 14 15:17:45 2009 +0900
   277.3 @@ -0,0 +1,288 @@
   277.4 +/* ========================================================================
   277.5 + * Copyright 1988-2006 University of Washington
   277.6 + *
   277.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   277.8 + * you may not use this file except in compliance with the License.
   277.9 + * You may obtain a copy of the License at
  277.10 + *
  277.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  277.12 + *
  277.13 + * 
  277.14 + * ========================================================================
  277.15 + */
  277.16 +
  277.17 +/*
  277.18 + * Program:	UNIX IPv6 routines
  277.19 + *
  277.20 + * Author:	Mark Crispin
  277.21 + *		Networks and Distributed Computing
  277.22 + *		Computing & Communications
  277.23 + *		University of Washington
  277.24 + *		Administration Building, AG-44
  277.25 + *		Seattle, WA  98195
  277.26 + *		Internet: MRC@CAC.Washington.EDU
  277.27 + *
  277.28 + * Date:	18 December 2003
  277.29 + * Last Edited:	30 August 2006
  277.30 + */
  277.31 +
  277.32 +
  277.33 +/*
  277.34 + * There is some amazingly bad design in IPv6 sockets.
  277.35 + *
  277.36 + * Supposedly, the new getnameinfo() and getaddrinfo() functions create an
  277.37 + * abstraction that is not dependent upon IPv4 or IPv6.  However, the
  277.38 + * definition of getnameinfo() requires that the caller pass the length of
  277.39 + * the sockaddr instead of deriving it from sa_family.  The man page says
  277.40 + * that there's an sa_len member in the sockaddr, but actually there isn't.
  277.41 + * This means that any caller to getnameinfo() and getaddrinfo() has to know
  277.42 + * the size for the protocol family used by that sockaddr.
  277.43 + *
  277.44 + * The new sockaddr_in6 is bigger than the generic sockaddr (which is what
  277.45 + * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect).
  277.46 + * Rather than increase the size of sockaddr, there's a new sockaddr_storage
  277.47 + * which is only usable for allocating space.
  277.48 + */
  277.49 +
  277.50 +#define SADRLEN sizeof (struct sockaddr_storage)
  277.51 +
  277.52 +#define SADR4(sadr) ((struct sockaddr_in *) sadr)
  277.53 +#define SADR4LEN sizeof (struct sockaddr_in)
  277.54 +#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
  277.55 +#define ADR4LEN sizeof (struct in_addr)
  277.56 +#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
  277.57 +
  277.58 +#define SADR6(sadr) ((struct sockaddr_in6 *) sadr)
  277.59 +#define SADR6LEN sizeof (struct sockaddr_in6)
  277.60 +#define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr
  277.61 +#define ADR6LEN sizeof (struct in6_addr)
  277.62 +#define SADR6PORT(sadr) SADR6 (sadr)->sin6_port
  277.63 +
  277.64 +
  277.65 +/* IP abstraction layer */
  277.66 +
  277.67 +char *ip_sockaddrtostring (struct sockaddr *sadr);
  277.68 +long ip_sockaddrtoport (struct sockaddr *sadr);
  277.69 +void *ip_stringtoaddr (char *text,size_t *len,int *family);
  277.70 +struct sockaddr *ip_newsockaddr (size_t *len);
  277.71 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
  277.72 +			      unsigned short port,size_t *len);
  277.73 +char *ip_sockaddrtoname (struct sockaddr *sadr);
  277.74 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
  277.75 +		     void **next);
  277.76 +
  277.77 +/* Return IP address string from socket address
  277.78 + * Accepts: socket address
  277.79 + * Returns: IP address as name string
  277.80 + */
  277.81 +
  277.82 +char *ip_sockaddrtostring (struct sockaddr *sadr)
  277.83 +{
  277.84 +  static char tmp[NI_MAXHOST];
  277.85 +  switch (sadr->sa_family) {
  277.86 +  case PF_INET:			/* IPv4 */
  277.87 +    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
  277.88 +      return tmp;
  277.89 +    break;
  277.90 +  case PF_INET6:		/* IPv6 */
  277.91 +    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
  277.92 +      return tmp;
  277.93 +    break;
  277.94 +  }
  277.95 +  return "NON-IP";
  277.96 +}
  277.97 +
  277.98 +
  277.99 +/* Return port from socket address
 277.100 + * Accepts: socket address
 277.101 + * Returns: port number or -1 if can't determine it
 277.102 + */
 277.103 +
 277.104 +long ip_sockaddrtoport (struct sockaddr *sadr)
 277.105 +{
 277.106 +  switch (sadr->sa_family) {
 277.107 +  case PF_INET:
 277.108 +    return ntohs (SADR4PORT (sadr));
 277.109 +  case PF_INET6:
 277.110 +    return ntohs (SADR6PORT (sadr));
 277.111 +  }
 277.112 +  return -1;
 277.113 +}
 277.114 +
 277.115 +/* Return IP address from string
 277.116 + * Accepts: name string
 277.117 + *	    pointer to returned length
 277.118 + *	    pointer to returned address family
 277.119 + * Returns: address if valid, length and family updated, or NIL
 277.120 + */
 277.121 +
 277.122 +void *ip_stringtoaddr (char *text,size_t *len,int *family)
 277.123 +
 277.124 +{
 277.125 +  char tmp[MAILTMPLEN];
 277.126 +  static struct addrinfo *hints;
 277.127 +  struct addrinfo *ai;
 277.128 +  void *adr = NIL;
 277.129 +  if (!hints) {			/* hints set up yet? */
 277.130 +    hints = (struct addrinfo *) /* one-time setup */
 277.131 +      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
 277.132 +    hints->ai_family = AF_UNSPEC;/* allow any address family */
 277.133 +    hints->ai_socktype = SOCK_STREAM;
 277.134 +				/* numeric name only */
 277.135 +    hints->ai_flags = AI_NUMERICHOST;
 277.136 +  }
 277.137 +				/* case-independent lookup */
 277.138 +  if (text && (strlen (text) < MAILTMPLEN) &&
 277.139 +      (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) {
 277.140 +    switch (*family = ai->ai_family) {
 277.141 +    case AF_INET:		/* IPv4 */
 277.142 +      adr = fs_get (*len = ADR4LEN);
 277.143 +      memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len);
 277.144 +      break;
 277.145 +    case AF_INET6:		/* IPv6 */
 277.146 +      adr = fs_get (*len = ADR6LEN);
 277.147 +      memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len);
 277.148 +      break;
 277.149 +    }
 277.150 +    freeaddrinfo (ai);		/* free addrinfo */
 277.151 +  }
 277.152 +  return adr;
 277.153 +}
 277.154 +
 277.155 +/* Create a maximum-size socket address
 277.156 + * Accepts: pointer to return maximum socket address length
 277.157 + * Returns: new, empty socket address of maximum size
 277.158 + */
 277.159 +
 277.160 +struct sockaddr *ip_newsockaddr (size_t *len)
 277.161 +{
 277.162 +  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
 277.163 +}
 277.164 +
 277.165 +
 277.166 +/* Stuff a socket address
 277.167 + * Accepts: address family
 277.168 + *	    IPv4 address
 277.169 + *	    length of address
 277.170 + *	    port number
 277.171 + *	    pointer to return socket address length
 277.172 + * Returns: socket address
 277.173 + */
 277.174 +
 277.175 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
 277.176 +			      unsigned short port,size_t *len)
 277.177 +{
 277.178 +  struct sockaddr *sadr = ip_newsockaddr (len);
 277.179 +  switch (family) {		/* build socket address based upon family */
 277.180 +  case AF_INET:			/* IPv4 */
 277.181 +    sadr->sa_family = PF_INET;
 277.182 +				/* copy host address */
 277.183 +    memcpy (&SADR4ADR (sadr),adr,adrlen);
 277.184 +				/* copy port number in network format */
 277.185 +    SADR4PORT (sadr) = htons (port);
 277.186 +    *len = SADR4LEN;
 277.187 +    break;
 277.188 +  case AF_INET6:		/* IPv6 */
 277.189 +    sadr->sa_family = PF_INET6;
 277.190 +				/* copy host address */
 277.191 +    memcpy (&SADR6ADR (sadr),adr,adrlen);
 277.192 +				/* copy port number in network format */
 277.193 +    SADR6PORT (sadr) = htons (port);
 277.194 +    *len = SADR6LEN;
 277.195 +    break;
 277.196 +  default:			/* non-IP?? */
 277.197 +    sadr->sa_family = PF_UNSPEC;
 277.198 +    break;
 277.199 +  }
 277.200 +  return sadr;
 277.201 +}
 277.202 +
 277.203 +/* Return name from socket address
 277.204 + * Accepts: socket address
 277.205 + * Returns: canonical name for that address or NIL if none
 277.206 + */
 277.207 +
 277.208 +char *ip_sockaddrtoname (struct sockaddr *sadr)
 277.209 +{
 277.210 +  static char tmp[NI_MAXHOST];
 277.211 +  switch (sadr->sa_family) {
 277.212 +  case PF_INET:			/* IPv4 */
 277.213 +    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
 277.214 +      return tmp;
 277.215 +    break;
 277.216 +  case PF_INET6:		/* IPv6 */
 277.217 +    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
 277.218 +      return tmp;
 277.219 +    break;
 277.220 +  }
 277.221 +  return NIL;
 277.222 +}
 277.223 +
 277.224 +/* Return address from name
 277.225 + * Accepts: name or NIL to return next address
 277.226 + *	    pointer to previous/returned length
 277.227 + *	    pointer to previous/returned address family
 277.228 + *	    pointer to previous/returned canonical name
 277.229 + *	    pointer to previous/return state for next-address calls
 277.230 + * Returns: address with length/family/canonical updated if needed, or NIL
 277.231 + */
 277.232 +
 277.233 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
 277.234 +		     void **next)
 277.235 +{
 277.236 +  struct addrinfo *cur = NIL;
 277.237 +  static struct addrinfo *hints;
 277.238 +  static struct addrinfo *ai = NIL;
 277.239 +  static char lcname[MAILTMPLEN];
 277.240 +  if (!hints) {			/* hints set up yet? */
 277.241 +    hints = (struct addrinfo *) /* one-time setup */
 277.242 +      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
 277.243 +				/* allow any address family */
 277.244 +    hints->ai_family = AF_UNSPEC;
 277.245 +    hints->ai_socktype = SOCK_STREAM;
 277.246 +				/* need canonical name */
 277.247 +    hints->ai_flags = AI_CANONNAME;
 277.248 +  }
 277.249 +  if (name) {			/* name supplied? */
 277.250 +    if (ai) {
 277.251 +      freeaddrinfo (ai);	/* free old addrinfo */
 277.252 +      ai = NIL;
 277.253 +    }
 277.254 +				/* case-independent lookup */
 277.255 +    if ((strlen (name) < MAILTMPLEN) &&
 277.256 +	(!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) {
 277.257 +      cur = ai;			/* current block */
 277.258 +      if (canonical)		/* set canonical name */
 277.259 +	*canonical = cur->ai_canonname ? cur->ai_canonname : lcname;
 277.260 +				/* remember as next block */
 277.261 +      if (next) *next = (void *) ai;
 277.262 +    }
 277.263 +    else {			/* error */
 277.264 +      cur = NIL;
 277.265 +      if (len) *len = 0;
 277.266 +      if (family) *family = 0;
 277.267 +      if (canonical) *canonical = NIL;
 277.268 +      if (next) *next = NIL;
 277.269 +    }
 277.270 +  }
 277.271 +				/* return next in series */
 277.272 +  else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) {
 277.273 +    *next = cur;		/* set as last address */
 277.274 +				/* set canonical in case changed */
 277.275 +    if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname;
 277.276 +  }
 277.277 +
 277.278 +  if (cur) {			/* got data? */
 277.279 +    if (family) *family = cur->ai_family;
 277.280 +    switch (cur->ai_family) {
 277.281 +    case AF_INET:
 277.282 +      if (len) *len = ADR4LEN;
 277.283 +      return (void *) &SADR4ADR (cur->ai_addr);
 277.284 +    case AF_INET6:
 277.285 +      if (len) *len = ADR6LEN;
 277.286 +      return (void *) &SADR6ADR (cur->ai_addr);
 277.287 +    }
 277.288 +  }
 277.289 +  if (len) *len = 0;		/* error return */
 277.290 +  return NIL;
 277.291 +}
   278.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   278.2 +++ b/src/osdep/nt/kerb_mit.c	Mon Sep 14 15:17:45 2009 +0900
   278.3 @@ -0,0 +1,74 @@
   278.4 +/* ========================================================================
   278.5 + * Copyright 1988-2006 University of Washington
   278.6 + *
   278.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   278.8 + * you may not use this file except in compliance with the License.
   278.9 + * You may obtain a copy of the License at
  278.10 + *
  278.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  278.12 + *
  278.13 + * 
  278.14 + * ========================================================================
  278.15 + */
  278.16 +
  278.17 +/*
  278.18 + * Program:	MIT Kerberos routines
  278.19 + *
  278.20 + * Author:	Mark Crispin
  278.21 + *		Networks and Distributed Computing
  278.22 + *		Computing & Communications
  278.23 + *		University of Washington
  278.24 + *		Administration Building, AG-44
  278.25 + *		Seattle, WA  98195
  278.26 + *		Internet: MRC@CAC.Washington.EDU
  278.27 + *
  278.28 + * Date:	4 March 2003
  278.29 + * Last Edited:	30 August 2006
  278.30 + */
  278.31 +
  278.32 +#define PROTOTYPE(x) x
  278.33 +#include <gssapi/gssapi_generic.h>
  278.34 +#include <gssapi/gssapi_krb5.h>
  278.35 +
  278.36 +
  278.37 +long kerberos_server_valid (void);
  278.38 +long kerberos_try_kinit (OM_uint32 error);
  278.39 +char *kerberos_login (char *user,char *authuser,int argc,char *argv[]);
  278.40 +
  278.41 +/* Kerberos server valid check
  278.42 + * Returns: T if have keytab, NIL otherwise
  278.43 + */
  278.44 +
  278.45 +long kerberos_server_valid ()
  278.46 +{
  278.47 +  return NIL;
  278.48 +}
  278.49 +
  278.50 +
  278.51 +/* Kerberos check for missing or expired credentials
  278.52 + * Returns: T if should suggest running kinit, NIL otherwise
  278.53 + */
  278.54 +
  278.55 +long kerberos_try_kinit (OM_uint32 error)
  278.56 +{
  278.57 +  switch (error) {
  278.58 +  case KRB5KRB_AP_ERR_TKT_EXPIRED:
  278.59 +  case KRB5_FCC_NOFILE:		/* MIT */
  278.60 +  case KRB5_CC_NOTFOUND:	/* Heimdal */
  278.61 +    return LONGT;
  278.62 +  }
  278.63 +  return NIL;
  278.64 +}
  278.65 +
  278.66 +/* Kerberos server log in
  278.67 + * Accepts: authorization ID as user name
  278.68 + *	    authentication ID as Kerberos principal
  278.69 + *	    argument count
  278.70 + *	    argument vector
  278.71 + * Returns: logged in user name if logged in, NIL otherwise
  278.72 + */
  278.73 +
  278.74 +char *kerberos_login (char *user,char *authuser,int argc,char *argv[])
  278.75 +{
  278.76 +  return NIL;
  278.77 +}
   279.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   279.2 +++ b/src/osdep/nt/kerb_w2k.c	Mon Sep 14 15:17:45 2009 +0900
   279.3 @@ -0,0 +1,699 @@
   279.4 +/* ========================================================================
   279.5 + * Copyright 1988-2006 University of Washington
   279.6 + *
   279.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   279.8 + * you may not use this file except in compliance with the License.
   279.9 + * You may obtain a copy of the License at
  279.10 + *
  279.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  279.12 + *
  279.13 + * 
  279.14 + * ========================================================================
  279.15 + */
  279.16 +
  279.17 +/*
  279.18 + * Program:	GSSAPI Kerberos Shim 5 for Windows 2000/XP IMAP Toolkit
  279.19 + *
  279.20 + * Author:	Mark Crispin
  279.21 + *		Networks and Distributed Computing
  279.22 + *		Computing & Communications
  279.23 + *		University of Washington
  279.24 + *		Administration Building, AG-44
  279.25 + *		Seattle, WA  98195
  279.26 + *		Internet: MRC@CAC.Washington.EDU
  279.27 + *
  279.28 + * Date:	6 March 2000
  279.29 + * Last Edited:	30 August 2006
  279.30 + */
  279.31 +
  279.32 +/*  The purpose of this module is to be a shim, so that the auth_gss.c module
  279.33 + * (written for MIT Kerberos) will compile, link, and run with SSPI Kerberos
  279.34 + * on Windows 2000 systems.
  279.35 + *  There is no attempt whatsoever to make this be a complete implementation
  279.36 + * of GSSAPI.  A number of shortcuts were taken that a real GSSAPI
  279.37 + * implementation for SSPI can't do.
  279.38 + *  Nor is there any attempt to make the types identical with MIT Kerberos;
  279.39 + * you can't link this library with object files compiled with the MIT
  279.40 + * Kerberos .h files.
  279.41 + */
  279.42 +
  279.43 +
  279.44 +/* GSSAPI generic definitions */
  279.45 +
  279.46 +
  279.47 +#define SECURITY_WIN32
  279.48 +#include <security.h>
  279.49 +
  279.50 +
  279.51 +/* GSSAPI types for which we use SSPI equivalent types */
  279.52 +
  279.53 +typedef ULONG OM_uint32;
  279.54 +typedef PCredHandle gss_cred_id_t;
  279.55 +typedef ULONG gss_cred_usage_t;
  279.56 +typedef PCtxtHandle gss_ctx_id_t;
  279.57 +typedef SEC_CHAR * gss_name_t;
  279.58 +typedef ULONG gss_qop_t;
  279.59 +
  279.60 +
  279.61 +/* Major status codes */
  279.62 +
  279.63 +#define GSS_S_COMPLETE SEC_E_OK
  279.64 +#define GSS_S_BAD_MECH SEC_E_SECPKG_NOT_FOUND
  279.65 +#define GSS_S_CONTINUE_NEEDED SEC_I_CONTINUE_NEEDED
  279.66 +#define GSS_S_CREDENTIALS_EXPIRED SEC_E_CERT_EXPIRED
  279.67 +#define GSS_S_FAILURE SEC_E_INTERNAL_ERROR
  279.68 +#define GSS_S_NO_CRED SEC_E_NO_CREDENTIALS
  279.69 +#define GSS_S_NO_CONTEXT SEC_E_INVALID_HANDLE
  279.70 +
  279.71 +
  279.72 +/* Flag bits for context-level services */
  279.73 +
  279.74 +#define GSS_C_DELEG_FLAG ISC_REQ_DELEGATE
  279.75 +#define GSS_C_MUTUAL_FLAG ISC_REQ_MUTUAL_AUTH
  279.76 +#define GSS_C_REPLAY_FLAG ISC_REQ_REPLAY_DETECT
  279.77 +#define GSS_C_SEQUENCE_FLAG ISC_REQ_SEQUENCE_DETECT
  279.78 +#define GSS_C_CONF_FLAG ISC_REQ_CONFIDENTIALITY
  279.79 +#define GSS_C_INTEG_FLAG ISC_REQ_INTEGRITY
  279.80 +
  279.81 +
  279.82 +/* Credential usage options */
  279.83 +
  279.84 +#define GSS_C_BOTH SECPKG_CRED_BOTH
  279.85 +#define GSS_C_INITIATE SECPKG_CRED_OUTBOUND
  279.86 +#define GSS_C_ACCEPT SECPKG_CRED_INBOUND
  279.87 +
  279.88 +
  279.89 +/* Major status codes defined by shim */
  279.90 +
  279.91 +#define GSS_S_BAD_BINDINGS 100
  279.92 +#define GSS_S_BAD_NAME 101
  279.93 +#define GSS_S_BAD_NAMETYPE 102
  279.94 +#define GSS_S_BAD_STATUS 103
  279.95 +
  279.96 +/* GSSAPI types as used in GSSAPI */
  279.97 +
  279.98 +
  279.99 +/* Buffer */
 279.100 +
 279.101 +typedef struct gss_buffer_desc_struct {
 279.102 +  size_t length;
 279.103 +  void *value;
 279.104 +} gss_buffer_desc,*gss_buffer_t;
 279.105 +
 279.106 +
 279.107 +/* Object identifier */
 279.108 +
 279.109 +typedef struct gss_OID_desc_struct {
 279.110 +  OM_uint32 length;
 279.111 +  void *elements;
 279.112 +} gss_OID_desc,*gss_OID;
 279.113 +
 279.114 +typedef struct gss_OID_set_desc_struct {
 279.115 +  size_t count;
 279.116 +  gss_OID elements;
 279.117 +} gss_OID_set_desc,*gss_OID_set;
 279.118 +
 279.119 +
 279.120 +/* Unused, but needed in prototypes */
 279.121 +
 279.122 +typedef void * gss_channel_bindings_t;
 279.123 +
 279.124 +
 279.125 +/* Default constants */
 279.126 +
 279.127 +#define GSS_C_EMPTY_BUFFER {0,NIL}
 279.128 +#define GSS_C_NO_BUFFER ((gss_buffer_t) NIL)
 279.129 +#define GSS_C_NO_OID ((gss_OID) NIL)
 279.130 +#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) NIL)
 279.131 +#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) NIL)
 279.132 +#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) NIL)
 279.133 +#define GSS_C_QOP_DEFAULT NIL
 279.134 +
 279.135 +
 279.136 +/* Status code types for gss_display_status */
 279.137 +
 279.138 +#define GSS_C_GSS_CODE 1
 279.139 +#define GSS_C_MECH_CODE 2
 279.140 +
 279.141 +
 279.142 +/* GSSAPI constants */
 279.143 +
 279.144 +const gss_OID gss_nt_service_name;
 279.145 +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
 279.146 +const gss_OID gss_mech_krb5;
 279.147 +const gss_OID_set gss_mech_set_krb5;
 279.148 +
 279.149 +/* GSSAPI prototypes */
 279.150 +
 279.151 +
 279.152 +OM_uint32 gss_accept_sec_context (OM_uint32 *minor_status,
 279.153 +				  gss_ctx_id_t *context_handle,
 279.154 +				  gss_cred_id_t acceptor_cred_handle,
 279.155 +				  gss_buffer_t input_token_buffer,
 279.156 +				  gss_channel_bindings_t input_chan_bindings,
 279.157 +				  gss_name_t *src_name,gss_OID *mech_type,
 279.158 +				  gss_buffer_t output_token,
 279.159 +				  OM_uint32 *ret_flags,OM_uint32 *time_rec,
 279.160 +				  gss_cred_id_t *delegated_cred_handle);
 279.161 +OM_uint32 gss_acquire_cred (OM_uint32 *minor_status,gss_name_t desired_name,
 279.162 +			    OM_uint32 time_req,gss_OID_set desired_mechs,
 279.163 +			    gss_cred_usage_t cred_usage,
 279.164 +			    gss_cred_id_t *output_cred_handle,
 279.165 +			    gss_OID_set *actual_mechs,OM_uint32 *time_rec);
 279.166 +OM_uint32 gss_delete_sec_context (OM_uint32 *minor_status,
 279.167 +				  gss_ctx_id_t *context_handle,
 279.168 +				  gss_buffer_t output_token);
 279.169 +OM_uint32 gss_display_name (OM_uint32 *minor_status,gss_name_t input_name,
 279.170 +			    gss_buffer_t output_name_buffer,
 279.171 +			    gss_OID *output_name_type);
 279.172 +OM_uint32 gss_display_status (OM_uint32 *minor_status,OM_uint32 status_value,
 279.173 +			      int status_type,gss_OID mech_type,
 279.174 +			      OM_uint32 *message_context,
 279.175 +			      gss_buffer_t status_string);
 279.176 +OM_uint32 gss_import_name (OM_uint32 *minor_status,
 279.177 +			   gss_buffer_t input_name_buffer,
 279.178 +			   gss_OID input_name_type,gss_name_t *output_name);
 279.179 +OM_uint32 gss_init_sec_context (OM_uint32 *minor_status,
 279.180 +				gss_cred_id_t claimant_cred_handle,
 279.181 +				gss_ctx_id_t *context_handle,
 279.182 +				gss_name_t target_name,gss_OID mech_type,
 279.183 +				OM_uint32 req_flags,OM_uint32 time_req,
 279.184 +				gss_channel_bindings_t input_chan_bindings,
 279.185 +				gss_buffer_t input_token,
 279.186 +				gss_OID *actual_mech_type,
 279.187 +				gss_buffer_t output_token,OM_uint32 *ret_flags,
 279.188 +				OM_uint32 *time_rec);
 279.189 +OM_uint32 gss_release_buffer (OM_uint32 *minor_status,gss_buffer_t buffer);
 279.190 +OM_uint32 gss_release_cred (OM_uint32 *minor_status,gss_cred_id_t *cred_handle);
 279.191 +OM_uint32 gss_release_name (OM_uint32 *minor_status,gss_name_t *input_name);
 279.192 +OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
 279.193 +		    int conf_req_flag,gss_qop_t qop_req,
 279.194 +		    gss_buffer_t input_message_buffer,int *conf_state,
 279.195 +		    gss_buffer_t output_message_buffer);
 279.196 +OM_uint32 gss_unwrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
 279.197 +		      gss_buffer_t input_message_buffer,
 279.198 +		      gss_buffer_t output_message_buffer,int *conf_state,
 279.199 +		      gss_qop_t *qop_state);
 279.200 +
 279.201 +/* Kerberos definitions */
 279.202 +
 279.203 +long kerberos_server_valid (void);
 279.204 +long kerberos_try_kinit (OM_uint32 error);
 279.205 +char *kerberos_login (char *user,char *authuser,int argc,char *argv[]);
 279.206 +
 279.207 +
 279.208 +#define STRING WINSTRING	/* conflict with mail.h */
 279.209 +#include <NTSecAPI.h>
 279.210 +
 279.211 +/* GSSAPI build-in object identifiers */
 279.212 +
 279.213 +static gss_OID_desc oids[] = {	/* stupid C language makes this necessary */
 279.214 +  {10,"\052\206\110\206\367\022\001\002\001\004"},
 279.215 +  {9,"\052\206\110\206\367\022\001\002\002"}
 279.216 +};
 279.217 +
 279.218 +				/* stupid C language ditto */
 279.219 +static gss_OID_set_desc oidsets[] = {
 279.220 +  {1,(gss_OID) oids+1}
 279.221 +};
 279.222 +
 279.223 +				/* these are the real OIDs */
 279.224 +const gss_OID gss_nt_service_name = oids+0;
 279.225 +const gss_OID gss_mech_krb5 = oids+1;
 279.226 +const gss_OID_set gss_mech_set_krb5 = oidsets+0;
 279.227 +
 279.228 +
 279.229 +/* Other globals */
 279.230 +
 279.231 +				/* substitute for GSS_C_NO_CREDENTIAL */
 279.232 +static gss_cred_id_t gss_default_cred = NIL;
 279.233 +
 279.234 +/* GSSAPI import name (convert to full service principal name)
 279.235 + * Accepts: pointer to return minor status
 279.236 + *	    buffer containining input name
 279.237 + *	    type of input name
 279.238 + *	    pointer to return output internal name
 279.239 + * Returns: major status, always
 279.240 + */
 279.241 +
 279.242 +OM_uint32 gss_import_name (OM_uint32 *minor_status,
 279.243 +			   gss_buffer_t input_name_buffer,
 279.244 +			   gss_OID input_name_type,gss_name_t *output_name)
 279.245 +{
 279.246 +  OM_uint32 major_status = GSS_S_COMPLETE;
 279.247 +  TimeStamp expiry;
 279.248 +  static CredHandle gss_cred;
 279.249 +  char *s,tmp[MAILTMPLEN];
 279.250 +  *minor_status = 0;		/* never any minor status */
 279.251 +  if (!gss_default_cred) {	/* default credentials set up yet? */
 279.252 +    if (AcquireCredentialsHandle/* no, acquire them now */
 279.253 +	(NIL,MICROSOFT_KERBEROS_NAME_A,SECPKG_CRED_OUTBOUND,NIL,NIL,NIL,NIL,
 279.254 +	 &gss_cred,&expiry) != SEC_E_OK) return GSS_S_FAILURE;
 279.255 +				/* have default credentials now */
 279.256 +    gss_default_cred = &gss_cred;
 279.257 +  }
 279.258 +				/* must be the gss_nt_service_name format */
 279.259 +  if (input_name_type != gss_nt_service_name)
 279.260 +    major_status = GSS_S_BAD_NAMETYPE;
 279.261 +				/* name must be of sane length */
 279.262 +  else if (input_name_buffer->length > (MAILTMPLEN/2))
 279.263 +    major_status = GSS_S_BAD_NAME;
 279.264 +  else {			/* copy name */
 279.265 +    memcpy (tmp,input_name_buffer->value,input_name_buffer->length);
 279.266 +    tmp[input_name_buffer->length] = '\0';
 279.267 +    if (s = strchr (tmp,'@')) {	/* find service/host/delimiter */
 279.268 +      *s = '/';			/* convert to full service principal name */
 279.269 +      *output_name = cpystr (tmp);
 279.270 +    }
 279.271 +    else major_status = GSS_S_BAD_NAME;
 279.272 +  }
 279.273 +  return major_status;
 279.274 +}
 279.275 +
 279.276 +/* GSSAPI Initialize security context
 279.277 + * Accepts: pointer to return minor status
 279.278 + *	    claimant credential handle
 279.279 + *	    context (NIL means "none assigned yet")
 279.280 + *	    desired principal
 279.281 + *	    desired mechanisms
 279.282 + *	    required context attributes
 279.283 + *	    desired lifetime
 279.284 + *	    input channel bindings
 279.285 + *	    input token buffer
 279.286 + *	    pointer to return mechanism type
 279.287 + *	    buffer to return output token
 279.288 + *	    pointer to return flags
 279.289 + *	    pointer to return context lifetime
 279.290 + * Returns: major status, always
 279.291 + */
 279.292 +
 279.293 +OM_uint32 gss_init_sec_context (OM_uint32 *minor_status,
 279.294 +				gss_cred_id_t claimant_cred_handle,
 279.295 +				gss_ctx_id_t *context_handle,
 279.296 +				gss_name_t target_name,gss_OID mech_type,
 279.297 +				OM_uint32 req_flags,OM_uint32 time_req,
 279.298 +				gss_channel_bindings_t input_chan_bindings,
 279.299 +				gss_buffer_t input_token,
 279.300 +				gss_OID *actual_mech_type,
 279.301 +				gss_buffer_t output_token,OM_uint32 *ret_flags,
 279.302 +				OM_uint32 *time_rec)
 279.303 +{
 279.304 +  OM_uint32 i;
 279.305 +  OM_uint32 major_status;
 279.306 +  TimeStamp expiry;
 279.307 +  SecBuffer ibuf[1],obuf[1];
 279.308 +  SecBufferDesc ibufs,obufs;
 279.309 +  *minor_status = 0;		/* never any minor status */
 279.310 +				/* error if non-default time requested */
 279.311 +  if (time_req) return GSS_S_FAILURE;
 279.312 +  if (mech_type && memcmp (mech_type,gss_mech_krb5,sizeof (gss_OID)))
 279.313 +    return GSS_S_BAD_MECH;
 279.314 +				/* ditto if any channel bindings */
 279.315 +  if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS)
 279.316 +    return GSS_S_BAD_BINDINGS;
 279.317 +
 279.318 +				/* apply default credential if necessary */
 279.319 +  if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
 279.320 +    claimant_cred_handle = gss_default_cred;
 279.321 +				/* create output buffer storage as needed */
 279.322 +  req_flags |= ISC_REQ_ALLOCATE_MEMORY;
 279.323 +				/* make output buffer */
 279.324 +  obuf[0].BufferType = SECBUFFER_TOKEN;
 279.325 +  obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
 279.326 +				/* output buffer descriptor */
 279.327 +  obufs.ulVersion = SECBUFFER_VERSION;
 279.328 +  obufs.cBuffers = 1;
 279.329 +  obufs.pBuffers = obuf;
 279.330 +				/* first time caller? */
 279.331 +  if (*context_handle == GSS_C_NO_CONTEXT) {
 279.332 +				/* yes, set up output context handle */
 279.333 +    PCtxtHandle ctx = (PCtxtHandle) fs_get (sizeof (CtxtHandle));
 279.334 +    major_status = InitializeSecurityContext (claimant_cred_handle,NIL,
 279.335 +					      target_name,req_flags,0,
 279.336 +					      SECURITY_NETWORK_DREP,NIL,0,ctx,
 279.337 +					      &obufs,
 279.338 +					      ret_flags ? ret_flags : &i,
 279.339 +					      &expiry);
 279.340 +    *context_handle = ctx;	/* return updated context */
 279.341 +  }
 279.342 +  else {			/* no, make SSPI buffer from GSSAPI buffer */
 279.343 +    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
 279.344 +    ibuf[0].cbBuffer = input_token->length;
 279.345 +    ibuf[0].pvBuffer = input_token->value;
 279.346 +				/* input buffer descriptor */
 279.347 +    ibufs.ulVersion = SECBUFFER_VERSION;
 279.348 +    ibufs.cBuffers = 1;
 279.349 +    ibufs.pBuffers = ibuf;
 279.350 +    major_status = InitializeSecurityContext (claimant_cred_handle,
 279.351 +					      *context_handle,target_name,
 279.352 +					      req_flags,0,
 279.353 +					      SECURITY_NETWORK_DREP,&ibufs,0,
 279.354 +					      *context_handle,&obufs,
 279.355 +					      ret_flags ? ret_flags : &i,
 279.356 +					      &expiry);
 279.357 +  }
 279.358 +				/* return output */
 279.359 +  output_token->value = obuf[0].pvBuffer;
 279.360 +  output_token->length = obuf[0].cbBuffer;
 279.361 +				/* in case client wanted lifetime returned */
 279.362 +  if (time_rec) *time_rec = expiry.LowPart;
 279.363 +  return major_status;
 279.364 +}
 279.365 +
 279.366 +/* GSSAPI display status text
 279.367 + * Accepts: pointer to return minor status
 279.368 + *	    status to display
 279.369 + *	    status type
 279.370 + *	    message context for continuation
 279.371 + *	    buffer to write status string
 279.372 + * Returns: major status, always
 279.373 + */
 279.374 +
 279.375 +OM_uint32 gss_display_status (OM_uint32 *minor_status,OM_uint32 status_value,
 279.376 +			      int status_type,gss_OID mech_type,
 279.377 +			      OM_uint32 *message_context,
 279.378 +			      gss_buffer_t status_string)
 279.379 +{
 279.380 +  char *s,tmp[MAILTMPLEN];
 279.381 +  *minor_status = 0;		/* never any minor status */
 279.382 +  if (*message_context) return GSS_S_FAILURE;
 279.383 +  switch (status_type) {	/* what type of status code? */
 279.384 +  case GSS_C_GSS_CODE:		/* major_status */
 279.385 +    switch (status_value) {	/* analyze status value */
 279.386 +    case GSS_S_FAILURE:
 279.387 +      s = "Unspecified failure"; break;
 279.388 +    case GSS_S_CREDENTIALS_EXPIRED:
 279.389 +      s = "Credentials expired"; break;
 279.390 +    case GSS_S_BAD_BINDINGS:
 279.391 +      s = "Bad bindings"; break;
 279.392 +    case GSS_S_BAD_MECH:
 279.393 +      s = "Bad mechanism type"; break;
 279.394 +    case GSS_S_BAD_NAME:
 279.395 +      s = "Bad name"; break;
 279.396 +    case GSS_S_BAD_NAMETYPE:
 279.397 +      s = "Bad name type"; break;
 279.398 +    case GSS_S_BAD_STATUS:
 279.399 +      s = "Bad status"; break;
 279.400 +    case GSS_S_NO_CONTEXT:
 279.401 +      s = "Invalid context handle"; break;
 279.402 +    case GSS_S_NO_CRED:
 279.403 +      s = "Unable to authenticate to Kerberos service";
 279.404 +      mail_parameters (NIL,DISABLE_AUTHENTICATOR,"GSSAPI");
 279.405 +      break;
 279.406 +    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
 279.407 +      s = "No authenticating authority"; break;
 279.408 +    case SEC_E_TARGET_UNKNOWN:
 279.409 +      s = "Destination server unknown to Kerberos service"; break;
 279.410 +    default:
 279.411 +      sprintf (s = tmp,"SSPI code %lx",status_value);
 279.412 +    }
 279.413 +    break;
 279.414 +  case GSS_C_MECH_CODE:		/* minor status - drop into default */
 279.415 +  default:
 279.416 +    return GSS_S_BAD_STATUS;	/* bad status type */
 279.417 +  }
 279.418 +				/* return status string */
 279.419 +  status_string->length = strlen (status_string->value = cpystr (s));
 279.420 +  return GSS_S_COMPLETE;
 279.421 +}
 279.422 +
 279.423 +/* GSSAPI delete security context
 279.424 + * Accepts: pointer to return minor status
 279.425 + *	    context to delete
 279.426 + *	    output context token
 279.427 + * Returns: major status, always
 279.428 + */
 279.429 +
 279.430 +OM_uint32 gss_delete_sec_context (OM_uint32 *minor_status,
 279.431 +				  gss_ctx_id_t *context_handle,
 279.432 +				  gss_buffer_t output_token)
 279.433 +{
 279.434 +  OM_uint32 major_status;
 279.435 +  *minor_status = 0;		/* never any minor status */
 279.436 +				/* output token not supported */
 279.437 +  major_status = output_token ? GSS_S_FAILURE :
 279.438 +    DeleteSecurityContext (*context_handle);
 279.439 +  fs_give ((void **) context_handle);
 279.440 +  return major_status;
 279.441 +}
 279.442 +
 279.443 +
 279.444 +/* GSSAPI release buffer
 279.445 + * Accepts: pointer to return minor status
 279.446 + *	    buffer to release
 279.447 + * Returns: GSS_S_COMPLETE, always
 279.448 + */
 279.449 +
 279.450 +OM_uint32 gss_release_buffer (OM_uint32 *minor_status,gss_buffer_t buffer)
 279.451 +{
 279.452 +  *minor_status = 0;		/* never any minor status */
 279.453 +  fs_give (&buffer->value);
 279.454 +  return GSS_S_COMPLETE;
 279.455 +}
 279.456 +
 279.457 +
 279.458 +/* GSSAPI release name
 279.459 + * Accepts: pointer to return minor status
 279.460 + *	    pointer to name to release
 279.461 + * Returns: GSS_S_COMPLETE, always
 279.462 + */
 279.463 +
 279.464 +OM_uint32 gss_release_name (OM_uint32 *minor_status,gss_name_t *input_name)
 279.465 +{
 279.466 +  *minor_status = 0;		/* never any minor status */
 279.467 +  fs_give (input_name);
 279.468 +  return GSS_S_COMPLETE;
 279.469 +}
 279.470 +
 279.471 +/* GSSAPI wrap data
 279.472 + * Accepts: pointer to return minor status
 279.473 + *	    context handle
 279.474 + *	    requested confidentiality
 279.475 + *	    requested quality of protection
 279.476 + *	    input message buffer
 279.477 + *	    pointer to return confidentiality state
 279.478 + *	    output message buffer
 279.479 + * Returns: major status, always
 279.480 + */
 279.481 +
 279.482 +OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
 279.483 +		    int conf_req_flag,gss_qop_t qop_req,
 279.484 +		    gss_buffer_t input_message_buffer,int *conf_state,
 279.485 +		    gss_buffer_t output_message_buffer)
 279.486 +{
 279.487 +  OM_uint32 major_status;
 279.488 +  SecBuffer buf[3];
 279.489 +  SecBufferDesc bufs;
 279.490 +  SecPkgContext_Sizes sizes;
 279.491 +  *minor_status = NIL;		/* never any minor status */
 279.492 +  *conf_state = conf_req_flag;	/* same as requested */
 279.493 +  if ((major_status =		/* get trailer and padding sizes */
 279.494 +       QueryContextAttributes (context_handle,SECPKG_ATTR_SIZES,&sizes)) ==
 279.495 +      SEC_E_OK) {
 279.496 +				/* create big enough output buffer */
 279.497 +    output_message_buffer->value =
 279.498 +      fs_get (sizes.cbSecurityTrailer + input_message_buffer->length +
 279.499 +	      sizes.cbBlockSize);
 279.500 +    /* MSDN claims that for EncryptMessage() in Kerberos, you need an
 279.501 +     * uninitialized SECBUFFER_STREAM_HEADER; a SECBUFFER_DATA that "contains
 279.502 +     * the message to be encrypted.  The message is encrypted in place,
 279.503 +     * overwriting the original contents of its buffer"; an uninitialized
 279.504 +     * SECBUFFER_STREAM_TRAILER, and an uninitialized SECBUFFER_EMPTY.  I've
 279.505 +     * never been able to get it to work that way.
 279.506 +     */
 279.507 +    bufs.cBuffers = 3;		/* set up buffer descriptor */
 279.508 +    bufs.pBuffers = buf;
 279.509 +    bufs.ulVersion = SECBUFFER_VERSION;
 279.510 +    buf[0].BufferType = SECBUFFER_TOKEN;
 279.511 +    buf[0].pvBuffer = output_message_buffer->value;
 279.512 +    buf[0].cbBuffer = sizes.cbSecurityTrailer;
 279.513 +				/* I/O buffer */
 279.514 +    buf[1].BufferType = SECBUFFER_DATA;
 279.515 +    buf[1].pvBuffer = ((char *) buf[0].pvBuffer) + buf[0].cbBuffer;
 279.516 +    buf[1].cbBuffer = input_message_buffer->length;
 279.517 +    memcpy (buf[1].pvBuffer,input_message_buffer->value,buf[1].cbBuffer);
 279.518 +    buf[2].BufferType = SECBUFFER_PADDING;
 279.519 +    buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer;
 279.520 +    buf[2].cbBuffer = sizes.cbBlockSize;
 279.521 +    if ((major_status = EncryptMessage (context_handle,qop_req,&bufs,0)) ==
 279.522 +	GSS_S_COMPLETE) {
 279.523 +				/* slide data as necessary (how annoying!) */
 279.524 +      unsigned long i = sizes.cbSecurityTrailer - buf[0].cbBuffer;
 279.525 +      if (i) buf[1].pvBuffer =
 279.526 +	       memmove (((char *) buf[0].pvBuffer) + buf[0].cbBuffer,
 279.527 +			buf[1].pvBuffer,buf[1].cbBuffer);
 279.528 +      if (i += (input_message_buffer->length - buf[1].cbBuffer))
 279.529 +	buf[1].pvBuffer = memmove (((char *)buf[1].pvBuffer) + buf[1].cbBuffer,
 279.530 +		   buf[2].pvBuffer,buf[2].cbBuffer);
 279.531 +      output_message_buffer->length = buf[0].cbBuffer + buf[1].cbBuffer +
 279.532 +	buf[2].cbBuffer;
 279.533 +    }
 279.534 +    else fs_give (&output_message_buffer->value);
 279.535 +  }
 279.536 +  return major_status;		/* return status */
 279.537 +}
 279.538 +
 279.539 +/* GSSAPI unwrap data
 279.540 + * Accepts: pointer to return minor status
 279.541 + *	    context handle
 279.542 + *	    input message buffer
 279.543 + *	    output message buffer
 279.544 + *	    pointer to return confidentiality state
 279.545 + *	    pointer to return quality of protection
 279.546 + * Returns: major status, always
 279.547 + */
 279.548 +
 279.549 +OM_uint32 gss_unwrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
 279.550 +		      gss_buffer_t input_message_buffer,
 279.551 +		      gss_buffer_t output_message_buffer,int *conf_state,
 279.552 +		      gss_qop_t *qop_state)
 279.553 +{
 279.554 +  OM_uint32 major_status;
 279.555 +  SecBuffer buf[2];
 279.556 +  SecBufferDesc bufs;
 279.557 +  *minor_status = NIL;		/* never any minor status */
 279.558 +  *conf_state = NIL;		/* or confidentiality state */
 279.559 +  /* MSDN implies that all that is needed for DecryptMessage() in Kerberos
 279.560 +   * is a single SECBUFFER_DATA which "contains the encrypted message.  The
 279.561 +   * encrypted message is decrypted in place, overwriting the original
 279.562 +   * contents of its buffer."  I've never been able to get it to work without
 279.563 +   * using a SECBUFFER_STREAM for input and an uninitialized SECBUFFER_DATA
 279.564 +   * for output.
 279.565 +   * It *does* overwrite the input buffer, but not at the same point; e.g.
 279.566 +   * with an input pointer of 0xa140a8 and size of 53, the output ends up
 279.567 +   * at 0xa140d5 and size of 4.
 279.568 +   */
 279.569 +  bufs.cBuffers = 2;		/* set up buffer descriptor */
 279.570 +  bufs.pBuffers = buf;
 279.571 +  bufs.ulVersion = SECBUFFER_VERSION;
 279.572 +				/* input buffer */
 279.573 +  buf[0].BufferType = SECBUFFER_STREAM;
 279.574 +  buf[0].pvBuffer = input_message_buffer->value;
 279.575 +  buf[0].cbBuffer = input_message_buffer->length;
 279.576 +				/* output buffer */
 279.577 +  buf[1].BufferType = SECBUFFER_DATA;
 279.578 +  buf[1].pvBuffer = NIL;
 279.579 +  buf[1].cbBuffer = 0;
 279.580 +				/* decrypt and copy to output buffer */
 279.581 +  if ((major_status = DecryptMessage (context_handle,&bufs,0,qop_state)) ==
 279.582 +      SEC_E_OK)
 279.583 +   memcpy (output_message_buffer->value = fs_get (buf[1].cbBuffer),
 279.584 +	   buf[1].pvBuffer,output_message_buffer->length = buf[1].cbBuffer);
 279.585 +  return major_status;		/* return status */
 279.586 +}
 279.587 +
 279.588 +/* From here on are server-only functions, currently unused */
 279.589 +
 279.590 +
 279.591 +/* GSSAPI acquire credentials
 279.592 + * Accepts: pointer to return minor status
 279.593 + *	    desired principal
 279.594 + *	    desired lifetime
 279.595 + *	    desired mechanisms
 279.596 + *	    credentials usage
 279.597 + *	    pointer to return credentials handle
 279.598 + *	    pointer to return mechanisms
 279.599 + *	    pointer to return lifetime
 279.600 + * Returns: GSS_S_FAILURE, always
 279.601 + */
 279.602 +
 279.603 +OM_uint32 gss_acquire_cred (OM_uint32 *minor_status,gss_name_t desired_name,
 279.604 +			    OM_uint32 time_req,gss_OID_set desired_mechs,
 279.605 +			    gss_cred_usage_t cred_usage,
 279.606 +			    gss_cred_id_t *output_cred_handle,
 279.607 +			    gss_OID_set *actual_mechs,OM_uint32 *time_rec)
 279.608 +{
 279.609 +  *minor_status = 0;		/* never any minor status */
 279.610 +  return GSS_S_FAILURE;		/* server only */
 279.611 +}
 279.612 +
 279.613 +
 279.614 +/* GSSAPI release credentials
 279.615 + * Accepts: pointer to return minor status
 279.616 + *	    credentials handle to free
 279.617 + * Returns: GSS_S_COMPLETE, always
 279.618 + */
 279.619 +
 279.620 +OM_uint32 gss_release_cred (OM_uint32 *minor_status,gss_cred_id_t *cred_handle)
 279.621 +{
 279.622 +  *minor_status = 0;		/* never any minor status */
 279.623 +  return GSS_S_FAILURE;		/* server only */
 279.624 +}
 279.625 +
 279.626 +/* GSSAPI Accept security context
 279.627 + * Accepts: pointer to return minor status
 279.628 + *	    context
 279.629 + *	    acceptor credentials
 279.630 + *	    input token buffer
 279.631 + *	    input channel bindings
 279.632 + *	    pointer to return source name
 279.633 + *	    pointer to return mechanism type
 279.634 + *	    buffer to return output token
 279.635 + *	    pointer to return flags
 279.636 + *	    pointer to return context lifetime
 279.637 + *	    pointer to return delegated credentials
 279.638 + * Returns: GSS_S_FAILURE, always
 279.639 + */
 279.640 +
 279.641 +OM_uint32 gss_accept_sec_context (OM_uint32 *minor_status,
 279.642 +				  gss_ctx_id_t *context_handle,
 279.643 +				  gss_cred_id_t acceptor_cred_handle,
 279.644 +				  gss_buffer_t input_token_buffer,
 279.645 +				  gss_channel_bindings_t input_chan_bindings,
 279.646 +				  gss_name_t *src_name,gss_OID *mech_type,
 279.647 +				  gss_buffer_t output_token,
 279.648 +				  OM_uint32 *ret_flags,OM_uint32 *time_rec,
 279.649 +				  gss_cred_id_t *delegated_cred_handle)
 279.650 +{
 279.651 +  *minor_status = 0;		/* never any minor status */
 279.652 +  return GSS_S_FAILURE;		/* server only */
 279.653 +}
 279.654 +
 279.655 +
 279.656 +/* GSSAPI return printable name
 279.657 + * Accepts: pointer to return minor status
 279.658 + *	    internal name
 279.659 + *	    buffer to return output name
 279.660 + *	    output name type
 279.661 + * Returns: GSS_S_FAILURE, always
 279.662 + */
 279.663 +
 279.664 +OM_uint32 gss_display_name (OM_uint32 *minor_status,gss_name_t input_name,
 279.665 +			    gss_buffer_t output_name_buffer,
 279.666 +			    gss_OID *output_name_type)
 279.667 +{
 279.668 +  *minor_status = 0;		/* never any minor status */
 279.669 +  return GSS_S_FAILURE;		/* server only */
 279.670 +}
 279.671 +
 279.672 +/* Kerberos server valid check
 279.673 + * Returns: T if have keytab, NIL otherwise
 279.674 + */
 279.675 +
 279.676 +long kerberos_server_valid ()
 279.677 +{
 279.678 +  return NIL;
 279.679 +}
 279.680 +
 279.681 +
 279.682 +/* Kerberos check for missing or expired credentials
 279.683 + * Returns: T if should suggest running kinit, NIL otherwise
 279.684 + */
 279.685 +
 279.686 +long kerberos_try_kinit (OM_uint32 error)
 279.687 +{
 279.688 +  return NIL;
 279.689 +}
 279.690 +
 279.691 +/* Kerberos server log in
 279.692 + * Accepts: authorization ID as user name
 279.693 + *	    authentication ID as Kerberos principal
 279.694 + *	    argument count
 279.695 + *	    argument vector
 279.696 + * Returns: logged in user name if logged in, NIL otherwise
 279.697 + */
 279.698 +
 279.699 +char *kerberos_login (char *user,char *authuser,int argc,char *argv[])
 279.700 +{
 279.701 +  return NIL;
 279.702 +}
   280.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   280.2 +++ b/src/osdep/nt/mailfile.h	Mon Sep 14 15:17:45 2009 +0900
   280.3 @@ -0,0 +1,29 @@
   280.4 +/* ========================================================================
   280.5 + * Copyright 1988-2006 University of Washington
   280.6 + *
   280.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   280.8 + * you may not use this file except in compliance with the License.
   280.9 + * You may obtain a copy of the License at
  280.10 + *
  280.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  280.12 + *
  280.13 + * 
  280.14 + * ========================================================================
  280.15 + */
  280.16 +
  280.17 +/*
  280.18 + * Program:	Mail Spool file name
  280.19 + *
  280.20 + * Author:	Mark Crispin
  280.21 + *		Networks and Distributed Computing
  280.22 + *		Computing & Communications
  280.23 + *		University of Washington
  280.24 + *		Administration Building, AG-44
  280.25 + *		Seattle, WA  98195
  280.26 + *		Internet: MRC@CAC.Washington.EDU
  280.27 + *
  280.28 + * Date:	8 February 1996
  280.29 + * Last Edited:	30 August 2006
  280.30 + */
  280.31 +
  280.32 +#define MAILFILE "C:\\WINSMTP\\%s.MBX"
   281.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   281.2 +++ b/src/osdep/nt/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
   281.3 @@ -0,0 +1,118 @@
   281.4 +# ========================================================================
   281.5 +# Copyright 1988-2007 University of Washington
   281.6 +#
   281.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   281.8 +# you may not use this file except in compliance with the License.
   281.9 +# You may obtain a copy of the License at
  281.10 +#
  281.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  281.12 +#
  281.13 +# 
  281.14 +# ========================================================================
  281.15 +
  281.16 +# Program:	Portable C client makefile -- NT version
  281.17 +#
  281.18 +# Author:	Mark Crispin
  281.19 +#		Networks and Distributed Computing
  281.20 +#		Computing & Communications
  281.21 +#		University of Washington
  281.22 +#		Administration Building, AG-44
  281.23 +#		Seattle, WA  98195
  281.24 +#		Internet: MRC@CAC.Washington.EDU
  281.25 +#
  281.26 +# Date:		11 May 1989
  281.27 +# Last Edited:	23 May 2007
  281.28 +
  281.29 +
  281.30 +EXTRAAUTHENTICATORS =
  281.31 +EXTRADRIVERS = 
  281.32 +EXTRACFLAGS =
  281.33 +AUTHENTICATORS = ext md5 pla log
  281.34 +DRIVERS = imap nntp pop3 mbx mtx tenex unix
  281.35 +CREATEDRIVER = mbx
  281.36 +APPENDDRIVER = unix
  281.37 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  281.38 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  281.39 +CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
  281.40 +CC = cl
  281.41 +CCLIENTLIB = cclient.lib
  281.42 +
  281.43 +all:	$(CCLIENTLIB)
  281.44 +
  281.45 +.c.obj:
  281.46 +	$(CC) -c $(CFLAGS) $*.c
  281.47 +
  281.48 +osdep.h: os_nt.h
  281.49 +	copy os_nt.h osdep.h
  281.50 +	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
  281.51 +	setproto $(CREATEDRIVER) $(APPENDDRIVER)
  281.52 +	echo ssl_onceonlyinit (); >> linkage.c
  281.53 +	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
  281.54 +	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
  281.55 +
  281.56 +ip_nt.c: ip4_nt.c
  281.57 +	copy ip4_nt.c ip_nt.c
  281.58 +
  281.59 +mail.obj: mail.h misc.h osdep.h mail.c
  281.60 +
  281.61 +misc.obj: mail.h misc.h misc.c
  281.62 +
  281.63 +fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
  281.64 +
  281.65 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  281.66 +
  281.67 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  281.68 +
  281.69 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  281.70 +
  281.71 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  281.72 +
  281.73 +smanager.obj: mail.h misc.h smanager.c
  281.74 +
  281.75 +utf8.obj: mail.h misc.h osdep.h utf8.h
  281.76 +
  281.77 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  281.78 +
  281.79 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  281.80 +
  281.81 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  281.82 +
  281.83 +pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
  281.84 +
  281.85 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  281.86 +
  281.87 +os_nt.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
  281.88 +	os_nt.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \
  281.89 +	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
  281.90 +	mailfile.h auth_md5.c auth_pla.c auth_log.c
  281.91 +
  281.92 +mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
  281.93 +
  281.94 +mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
  281.95 +
  281.96 +tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
  281.97 +
  281.98 +unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
  281.99 +
 281.100 +dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
 281.101 +
 281.102 +pseudo.obj: pseudo.h
 281.103 +
 281.104 +$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 281.105 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 281.106 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_nt.obj \
 281.107 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 281.108 +	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
 281.109 +	LIB /NOLOGO /OUT:cclient.lib \
 281.110 +	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 281.111 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 281.112 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_nt.obj \
 281.113 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 281.114 +
 281.115 +clean:
 281.116 +	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
 281.117 +
 281.118 +# A monument to a hack of long ago and far away...
 281.119 +
 281.120 +love:
 281.121 +	@echo not war?
   282.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   282.2 +++ b/src/osdep/nt/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
   282.3 @@ -0,0 +1,118 @@
   282.4 +# ========================================================================
   282.5 +# Copyright 1988-2007 University of Washington
   282.6 +#
   282.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   282.8 +# you may not use this file except in compliance with the License.
   282.9 +# You may obtain a copy of the License at
  282.10 +#
  282.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  282.12 +#
  282.13 +# 
  282.14 +# ========================================================================
  282.15 +
  282.16 +# Program:	Portable C client makefile -- NT version + Kerberos
  282.17 +#
  282.18 +# Author:	Mark Crispin
  282.19 +#		Networks and Distributed Computing
  282.20 +#		Computing & Communications
  282.21 +#		University of Washington
  282.22 +#		Administration Building, AG-44
  282.23 +#		Seattle, WA  98195
  282.24 +#		Internet: MRC@CAC.Washington.EDU
  282.25 +#
  282.26 +# Date:		11 May 1989
  282.27 +# Last Edited:	23 May 2007
  282.28 +
  282.29 +
  282.30 +EXTRAAUTHENTICATORS =
  282.31 +EXTRADRIVERS = 
  282.32 +EXTRACFLAGS =
  282.33 +AUTHENTICATORS = ext gss md5 pla log
  282.34 +DRIVERS = imap nntp pop3 mbx mtx tenex unix
  282.35 +CREATEDRIVER = mbx
  282.36 +APPENDDRIVER = unix
  282.37 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 /I\k5\include
  282.38 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  282.39 +CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
  282.40 +CC = cl
  282.41 +CCLIENTLIB = cclient.lib
  282.42 +
  282.43 +all:	$(CCLIENTLIB)
  282.44 +
  282.45 +.c.obj:
  282.46 +	$(CC) -c $(CFLAGS) $*.c
  282.47 +
  282.48 +osdep.h: os_nt.h
  282.49 +	copy os_nt.h osdep.h
  282.50 +	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
  282.51 +	setproto $(CREATEDRIVER) $(APPENDDRIVER)
  282.52 +	echo ssl_onceonlyinit (); >> linkage.c
  282.53 +	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
  282.54 +	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
  282.55 +
  282.56 +ip_nt.c: ip4_nt.c
  282.57 +	copy ip4_nt.c ip_nt.c
  282.58 +
  282.59 +mail.obj: mail.h misc.h osdep.h mail.c
  282.60 +
  282.61 +misc.obj: mail.h misc.h misc.c
  282.62 +
  282.63 +fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
  282.64 +
  282.65 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  282.66 +
  282.67 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  282.68 +
  282.69 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  282.70 +
  282.71 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  282.72 +
  282.73 +smanager.obj: mail.h misc.h smanager.c
  282.74 +
  282.75 +utf8.obj: mail.h misc.h osdep.h utf8.h
  282.76 +
  282.77 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  282.78 +
  282.79 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  282.80 +
  282.81 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  282.82 +
  282.83 +pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
  282.84 +
  282.85 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  282.86 +
  282.87 +os_ntk.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
  282.88 +	os_ntk.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \
  282.89 +	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
  282.90 +	mailfile.h auth_gss.c auth_md5.c auth_pla.c auth_log.c kerb_mit.c
  282.91 +
  282.92 +mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
  282.93 +
  282.94 +mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
  282.95 +
  282.96 +tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
  282.97 +
  282.98 +unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
  282.99 +
 282.100 +dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
 282.101 +
 282.102 +pseudo.obj: pseudo.h
 282.103 +
 282.104 +$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 282.105 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 282.106 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_ntk.obj \
 282.107 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 282.108 +	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
 282.109 +	LIB /NOLOGO /OUT:cclient.lib \
 282.110 +	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 282.111 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 282.112 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_ntk.obj \
 282.113 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 282.114 +
 282.115 +clean:
 282.116 +	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
 282.117 +
 282.118 +# A monument to a hack of long ago and far away...
 282.119 +
 282.120 +love:
 282.121 +	@echo not war?
   283.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   283.2 +++ b/src/osdep/nt/makefile.old	Mon Sep 14 15:17:45 2009 +0900
   283.3 @@ -0,0 +1,118 @@
   283.4 +# ========================================================================
   283.5 +# Copyright 1988-2007 University of Washington
   283.6 +#
   283.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   283.8 +# you may not use this file except in compliance with the License.
   283.9 +# You may obtain a copy of the License at
  283.10 +#
  283.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  283.12 +#
  283.13 +# 
  283.14 +# ========================================================================
  283.15 +
  283.16 +# Program:	Portable C client makefile -- old NT version
  283.17 +#
  283.18 +# Author:	Mark Crispin
  283.19 +#		Networks and Distributed Computing
  283.20 +#		Computing & Communications
  283.21 +#		University of Washington
  283.22 +#		Administration Building, AG-44
  283.23 +#		Seattle, WA  98195
  283.24 +#		Internet: MRC@CAC.Washington.EDU
  283.25 +#
  283.26 +# Date:		11 May 1989
  283.27 +# Last Edited:	23 May 2007
  283.28 +
  283.29 +
  283.30 +EXTRAAUTHENTICATORS =
  283.31 +EXTRADRIVERS = 
  283.32 +EXTRACFLAGS =
  283.33 +AUTHENTICATORS = ext md5 pla log
  283.34 +DRIVERS = imap nntp pop3 mbx mtx tenex unix
  283.35 +CREATEDRIVER = mbx
  283.36 +APPENDDRIVER = unix
  283.37 +OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
  283.38 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  283.39 +CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
  283.40 +CC = cl
  283.41 +CCLIENTLIB = cclient.lib
  283.42 +
  283.43 +all:	$(CCLIENTLIB)
  283.44 +
  283.45 +.c.obj:
  283.46 +	$(CC) -c $(CFLAGS) $*.c
  283.47 +
  283.48 +osdep.h: os_nt.h
  283.49 +	copy os_nt.h osdep.h
  283.50 +	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
  283.51 +	setproto $(CREATEDRIVER) $(APPENDDRIVER)
  283.52 +	echo ssl_onceonlyinit (); >> linkage.c
  283.53 +	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
  283.54 +	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
  283.55 +
  283.56 +ip_nt.c: ip4_nt.c
  283.57 +	copy ip4_nt.c ip_nt.c
  283.58 +
  283.59 +mail.obj: mail.h misc.h osdep.h mail.c
  283.60 +
  283.61 +misc.obj: mail.h misc.h misc.c
  283.62 +
  283.63 +fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
  283.64 +
  283.65 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  283.66 +
  283.67 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  283.68 +
  283.69 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  283.70 +
  283.71 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  283.72 +
  283.73 +smanager.obj: mail.h misc.h smanager.c
  283.74 +
  283.75 +utf8.obj: mail.h misc.h osdep.h utf8.h
  283.76 +
  283.77 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  283.78 +
  283.79 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  283.80 +
  283.81 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  283.82 +
  283.83 +pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
  283.84 +
  283.85 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  283.86 +
  283.87 +os_old.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
  283.88 +	os_old.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \
  283.89 +	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
  283.90 +	mailfile.h auth_md5.c auth_pla.c auth_log.c
  283.91 +
  283.92 +mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
  283.93 +
  283.94 +mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
  283.95 +
  283.96 +tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
  283.97 +
  283.98 +unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
  283.99 +
 283.100 +dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
 283.101 +
 283.102 +pseudo.obj: pseudo.h
 283.103 +
 283.104 +$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 283.105 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 283.106 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_old.obj \
 283.107 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 283.108 +	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
 283.109 +	LIB /NOLOGO /OUT:cclient.lib \
 283.110 +	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 283.111 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 283.112 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_old.obj \
 283.113 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 283.114 +
 283.115 +clean:
 283.116 +	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
 283.117 +
 283.118 +# A monument to a hack of long ago and far away...
 283.119 +
 283.120 +love:
 283.121 +	@echo not war?
   284.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   284.2 +++ b/src/osdep/nt/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
   284.3 @@ -0,0 +1,119 @@
   284.4 +# ========================================================================
   284.5 +# Copyright 1988-2007 University of Washington
   284.6 +#
   284.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   284.8 +# you may not use this file except in compliance with the License.
   284.9 +# You may obtain a copy of the License at
  284.10 +#
  284.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  284.12 +#
  284.13 +# 
  284.14 +# ========================================================================
  284.15 +
  284.16 +# Program:	Portable C client makefile -- Windows 2000/XP version
  284.17 +#
  284.18 +# Author:	Mark Crispin
  284.19 +#		Networks and Distributed Computing
  284.20 +#		Computing & Communications
  284.21 +#		University of Washington
  284.22 +#		Administration Building, AG-44
  284.23 +#		Seattle, WA  98195
  284.24 +#		Internet: MRC@CAC.Washington.EDU
  284.25 +#
  284.26 +# Date:		11 May 1989
  284.27 +# Last Edited:	23 May 2007
  284.28 +
  284.29 +
  284.30 +IP=6
  284.31 +EXTRAAUTHENTICATORS =
  284.32 +EXTRADRIVERS = 
  284.33 +EXTRACFLAGS =
  284.34 +AUTHENTICATORS = ext gss md5 pla log
  284.35 +DRIVERS = imap nntp pop3 mbx mtx tenex unix
  284.36 +CREATEDRIVER = mbx
  284.37 +APPENDDRIVER = unix
  284.38 +OSCOMPAT = /DWIN32
  284.39 +VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
  284.40 +CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
  284.41 +CC = cl
  284.42 +CCLIENTLIB = cclient.lib
  284.43 +
  284.44 +all:	$(CCLIENTLIB)
  284.45 +
  284.46 +.c.obj:
  284.47 +	$(CC) -c $(CFLAGS) $*.c
  284.48 +
  284.49 +osdep.h: os_nt.h
  284.50 +	copy os_nt.h osdep.h
  284.51 +	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
  284.52 +	setproto $(CREATEDRIVER) $(APPENDDRIVER)
  284.53 +	echo ssl_onceonlyinit (); >> linkage.c
  284.54 +	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
  284.55 +	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
  284.56 +
  284.57 +ip_nt.c: ip$(IP)_nt.c
  284.58 +	copy ip$(IP)_nt.c ip_nt.c
  284.59 +
  284.60 +mail.obj: mail.h misc.h osdep.h mail.c
  284.61 +
  284.62 +misc.obj: mail.h misc.h misc.c
  284.63 +
  284.64 +fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
  284.65 +
  284.66 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  284.67 +
  284.68 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  284.69 +
  284.70 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  284.71 +
  284.72 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  284.73 +
  284.74 +smanager.obj: mail.h misc.h smanager.c
  284.75 +
  284.76 +utf8.obj: mail.h misc.h osdep.h utf8.h
  284.77 +
  284.78 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  284.79 +
  284.80 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  284.81 +
  284.82 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  284.83 +
  284.84 +pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
  284.85 +
  284.86 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  284.87 +
  284.88 +os_w2k.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
  284.89 +	os_w2k.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_w2k.c ssl_none.c \
  284.90 +	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
  284.91 +	mailfile.h auth_gss.c auth_md5.c auth_pla.c auth_log.c kerb_w2k.c
  284.92 +
  284.93 +mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
  284.94 +
  284.95 +mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
  284.96 +
  284.97 +tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
  284.98 +
  284.99 +unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
 284.100 +
 284.101 +dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
 284.102 +
 284.103 +pseudo.obj: pseudo.h
 284.104 +
 284.105 +$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 284.106 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 284.107 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_w2k.obj \
 284.108 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 284.109 +	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
 284.110 +	LIB /NOLOGO /OUT:cclient.lib \
 284.111 +	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 284.112 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 284.113 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_w2k.obj \
 284.114 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 284.115 +
 284.116 +clean:
 284.117 +	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
 284.118 +
 284.119 +# A monument to a hack of long ago and far away...
 284.120 +
 284.121 +love:
 284.122 +	@echo not war?
   285.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   285.2 +++ b/src/osdep/nt/mbxnt.c	Mon Sep 14 15:17:45 2009 +0900
   285.3 @@ -0,0 +1,1694 @@
   285.4 +/* ========================================================================
   285.5 + * Copyright 1988-2007 University of Washington
   285.6 + *
   285.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   285.8 + * you may not use this file except in compliance with the License.
   285.9 + * You may obtain a copy of the License at
  285.10 + *
  285.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  285.12 + *
  285.13 + * 
  285.14 + * ========================================================================
  285.15 + */
  285.16 +
  285.17 +/*
  285.18 + * Program:	MBX mail routines
  285.19 + *
  285.20 + * Author:	Mark Crispin
  285.21 + *		Networks and Distributed Computing
  285.22 + *		Computing & Communications
  285.23 + *		University of Washington
  285.24 + *		Administration Building, AG-44
  285.25 + *		Seattle, WA  98195
  285.26 + *		Internet: MRC@CAC.Washington.EDU
  285.27 + *
  285.28 + * Date:	3 October 1995
  285.29 + * Last Edited:	28 September 2007
  285.30 + */
  285.31 +
  285.32 +
  285.33 +/*				FILE TIME SEMANTICS
  285.34 + *
  285.35 + * The atime is the last read time of the file.
  285.36 + * The mtime is the last flags update time of the file.
  285.37 + * The ctime is the last write time of the file.
  285.38 + */
  285.39 +
  285.40 +#include <stdio.h>
  285.41 +#include <ctype.h>
  285.42 +#include <errno.h>
  285.43 +extern int errno;		/* just in case */
  285.44 +#include "mail.h"
  285.45 +#include "osdep.h"
  285.46 +#include <fcntl.h>
  285.47 +#include <time.h>
  285.48 +#include <sys/stat.h>
  285.49 +#include <sys/utime.h>
  285.50 +#include "misc.h"
  285.51 +#include "dummy.h"
  285.52 +#include "fdstring.h"
  285.53 +
  285.54 +
  285.55 +/* Build parameters */
  285.56 +
  285.57 +#define HDRSIZE 2048
  285.58 +
  285.59 +/* MBX I/O stream local data */
  285.60 +	
  285.61 +typedef struct mbx_local {
  285.62 +  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
  285.63 +  unsigned int expok: 1;	/* if expunging OK in ping */
  285.64 +  unsigned int expunged : 1;	/* if one or more expunged messages */
  285.65 +  int fd;			/* file descriptor for I/O */
  285.66 +  int ld;			/* lock file descriptor */
  285.67 +  int ffuserflag;		/* first free user flag */
  285.68 +  off_t filesize;		/* file size parsed */
  285.69 +  time_t filetime;		/* last file time */
  285.70 +  time_t lastsnarf;		/* last snarf time */
  285.71 +  unsigned char *buf;		/* temporary buffer */
  285.72 +  unsigned long buflen;		/* current size of temporary buffer */
  285.73 +  char lock[MAILTMPLEN];	/* buffer to write lock name */
  285.74 +} MBXLOCAL;
  285.75 +
  285.76 +
  285.77 +/* Convenient access to local data */
  285.78 +
  285.79 +#define LOCAL ((MBXLOCAL *) stream->local)
  285.80 +
  285.81 +/* Function prototypes */
  285.82 +
  285.83 +DRIVER *mbx_valid (char *name);
  285.84 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
  285.85 +		 long flags);
  285.86 +void *mbx_parameters (long function,void *value);
  285.87 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  285.88 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
  285.89 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  285.90 +long mbx_create (MAILSTREAM *stream,char *mailbox);
  285.91 +long mbx_delete (MAILSTREAM *stream,char *mailbox);
  285.92 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
  285.93 +long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
  285.94 +MAILSTREAM *mbx_open (MAILSTREAM *stream);
  285.95 +void mbx_close (MAILSTREAM *stream,long options);
  285.96 +void mbx_abort (MAILSTREAM *stream);
  285.97 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
  285.98 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
  285.99 +		  long flags);
 285.100 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 285.101 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 285.102 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 285.103 +long mbx_ping (MAILSTREAM *stream);
 285.104 +void mbx_check (MAILSTREAM *stream);
 285.105 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
 285.106 +void mbx_snarf (MAILSTREAM *stream);
 285.107 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 285.108 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 285.109 +
 285.110 +long mbx_parse (MAILSTREAM *stream);
 285.111 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
 285.112 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 285.113 +void mbx_update_header (MAILSTREAM *stream);
 285.114 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
 285.115 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 285.116 +			  unsigned long *size,char **hdr);
 285.117 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
 285.118 +			   long flags);
 285.119 +long mbx_flaglock (MAILSTREAM *stream);
 285.120 +
 285.121 +/* MBX mail routines */
 285.122 +
 285.123 +
 285.124 +/* Driver dispatch used by MAIL */
 285.125 +
 285.126 +DRIVER mbxdriver = {
 285.127 +  "mbx",			/* driver name */
 285.128 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
 285.129 +				/* driver flags */
 285.130 +  (DRIVER *) NIL,		/* next driver */
 285.131 +  mbx_valid,			/* mailbox is valid for us */
 285.132 +  mbx_parameters,		/* manipulate parameters */
 285.133 +  mbx_scan,			/* scan mailboxes */
 285.134 +  mbx_list,			/* list mailboxes */
 285.135 +  mbx_lsub,			/* list subscribed mailboxes */
 285.136 +  NIL,				/* subscribe to mailbox */
 285.137 +  NIL,				/* unsubscribe from mailbox */
 285.138 +  mbx_create,			/* create mailbox */
 285.139 +  mbx_delete,			/* delete mailbox */
 285.140 +  mbx_rename,			/* rename mailbox */
 285.141 +  mail_status_default,		/* status of mailbox */
 285.142 +  mbx_open,			/* open mailbox */
 285.143 +  mbx_close,			/* close mailbox */
 285.144 +  mbx_flags,			/* fetch message "fast" attributes */
 285.145 +  mbx_flags,			/* fetch message flags */
 285.146 +  NIL,				/* fetch overview */
 285.147 +  NIL,				/* fetch message envelopes */
 285.148 +  mbx_header,			/* fetch message header */
 285.149 +  mbx_text,			/* fetch message body */
 285.150 +  NIL,				/* fetch partial message text */
 285.151 +  NIL,				/* unique identifier */
 285.152 +  NIL,				/* message number */
 285.153 +  mbx_flag,			/* modify flags */
 285.154 +  mbx_flagmsg,			/* per-message modify flags */
 285.155 +  NIL,				/* search for message based on criteria */
 285.156 +  NIL,				/* sort messages */
 285.157 +  NIL,				/* thread messages */
 285.158 +  mbx_ping,			/* ping mailbox to see if still alive */
 285.159 +  mbx_check,			/* check for new messages */
 285.160 +  mbx_expunge,			/* expunge deleted messages */
 285.161 +  mbx_copy,			/* copy messages to another mailbox */
 285.162 +  mbx_append,			/* append string message to mailbox */
 285.163 +  NIL				/* garbage collect stream */
 285.164 +};
 285.165 +
 285.166 +				/* prototype stream */
 285.167 +MAILSTREAM mbxproto = {&mbxdriver};
 285.168 +
 285.169 +/* MBX mail validate mailbox
 285.170 + * Accepts: mailbox name
 285.171 + * Returns: our driver if name is valid, NIL otherwise
 285.172 + */
 285.173 +
 285.174 +DRIVER *mbx_valid (char *name)
 285.175 +{
 285.176 +  char tmp[MAILTMPLEN];
 285.177 +  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
 285.178 +  if (fd < 0) return NIL;
 285.179 +  close (fd);			/* don't need the fd now */
 285.180 +  return &mbxdriver;
 285.181 +}
 285.182 +
 285.183 +
 285.184 +/* MBX mail test for valid mailbox
 285.185 + * Accepts: returned stream with valid mailbox keywords
 285.186 + *	    mailbox name
 285.187 + *	    buffer to write file name
 285.188 + *	    returned lock fd
 285.189 + *	    returned lock name
 285.190 + *	    RW flags or NIL for readonly
 285.191 + * Returns: file descriptor if valid, NIL otherwise
 285.192 + */
 285.193 +
 285.194 +#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
 285.195 +#define MBXISVALIDUID 0x2	/* RW, do UID action */
 285.196 +
 285.197 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
 285.198 +		 long flags)
 285.199 +{
 285.200 +  int fd,upd;
 285.201 +  int ret = -1;
 285.202 +  unsigned long i;
 285.203 +  long j,k;
 285.204 +  off_t pos;
 285.205 +  char c,*s,*t,hdr[HDRSIZE];
 285.206 +  struct stat sbuf;
 285.207 +  struct utimbuf times;
 285.208 +  int error = EINVAL;		/* assume invalid argument */
 285.209 +  if (ld) *ld = -1;		/* initially no lock */
 285.210 +				/* if file, get its status */
 285.211 +  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
 285.212 +      ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
 285.213 +      ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
 285.214 +    error = -1;			/* assume bogus format */
 285.215 +    if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) ||
 285.216 +				/* locked, set byte 0 to "*", read rest */
 285.217 +	 ((j < 0) && (lseek (fd,1,L_SET) == 1) &&
 285.218 +	  (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (hdr[0] = '*'))) &&
 285.219 +	(hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') &&
 285.220 +	(hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') &&
 285.221 +	isxdigit (hdr[7]) && isxdigit (hdr[8]) && isxdigit (hdr[9]) &&
 285.222 +	isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) &&
 285.223 +	isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) &&
 285.224 +	isxdigit (hdr[16]) && isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
 285.225 +	isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) &&
 285.226 +	isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) {
 285.227 +      ret = fd;			/* mbx format */
 285.228 +
 285.229 +      if (stream) {		/* lock if making a mini-stream */
 285.230 +	if (flock (fd,LOCK_SH) ||
 285.231 +	    (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1;
 285.232 +				/* reread data now that locked */
 285.233 +	else if (lseek (fd,0,L_SET) ||
 285.234 +		 (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1;
 285.235 +	else {
 285.236 +	  *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0,
 285.237 +					   sizeof (MAILSTREAM));
 285.238 +	  hdr[15] = '\0';	/* tie off UIDVALIDITY */
 285.239 +	  (*stream)->uid_validity = strtoul (hdr+7,NIL,16);
 285.240 +	  hdr[15] = c;		/* now get UIDLAST */
 285.241 +	  (*stream)->uid_last = strtoul (hdr+15,NIL,16);
 285.242 +				/* parse user flags */
 285.243 +	  for (i = 0, s = hdr + 25;
 285.244 +	       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
 285.245 +	       i++, s = t + 2) {
 285.246 +	    *t = '\0';		/* tie off flag */
 285.247 +	    if (strlen (s) <= MAXUSERFLAG)
 285.248 +	      (*stream)->user_flags[i] = cpystr (s);
 285.249 +	  }
 285.250 +				/* make sure have true UIDLAST */
 285.251 +	  if (flags & MBXISVALIDUID) {
 285.252 +	    for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
 285.253 +		 pos += (j + k)) {
 285.254 +				/* read header for this message */
 285.255 +	      lseek (fd,pos,L_SET);
 285.256 +	      if ((j = read (fd,hdr,64)) >= 0) {
 285.257 +		hdr[j] = '\0';
 285.258 +		if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
 285.259 +		  *s = '\0';
 285.260 +		  k = s + 2 - hdr;
 285.261 +		  if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) &&
 285.262 +		      (*s == ';') && (s = strchr (s+1,'-'))) {
 285.263 +				/* get UID if there is any */
 285.264 +		    i = strtoul (++s,&t,16);
 285.265 +		    if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) {
 285.266 +		      if (!i) {
 285.267 +			lseek (fd,pos + s - hdr,L_SET);
 285.268 +			sprintf (hdr,"%08lx",++(*stream)->uid_last);
 285.269 +			write (fd,hdr,8);
 285.270 +			upd = T;
 285.271 +		      }
 285.272 +		      continue;
 285.273 +		    }
 285.274 +		  }
 285.275 +		}
 285.276 +		ret = -1;	/* error, give up */
 285.277 +		*stream = mail_close (*stream);
 285.278 +		pos = sbuf.st_size + 1;
 285.279 +		j = k = 0;
 285.280 +	      }
 285.281 +	    }
 285.282 +
 285.283 +	    if (upd) {	    /* need to update hdr with new UIDLAST? */
 285.284 +	      lseek (fd,15,L_SET);
 285.285 +	      sprintf (hdr,"%08lx",(*stream)->uid_last);
 285.286 +	      write (fd,hdr,8);
 285.287 +	    }
 285.288 +	  }
 285.289 +	}
 285.290 +      }
 285.291 +    }
 285.292 +    if (ret != fd) close (fd);	/* close the file */
 285.293 +    else lseek (fd,0,L_SET);	/* else rewind to start */
 285.294 +				/* \Marked status? */
 285.295 +    if (sbuf.st_ctime > sbuf.st_atime) {
 285.296 +				/* preserve atime and mtime */
 285.297 +      times.actime = sbuf.st_atime;
 285.298 +      times.modtime = sbuf.st_mtime;
 285.299 +      utime (file,&times);	/* set the times */
 285.300 +    }
 285.301 +  }
 285.302 +				/* in case INBOX but not mbx format */
 285.303 +  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
 285.304 +    error = -1;
 285.305 +  if ((ret < 0) && ld && (*ld >= 0)) {
 285.306 +    unlockfd (*ld,lock);
 285.307 +    *ld = -1;
 285.308 +  }
 285.309 +  errno = error;		/* return as last error */
 285.310 +  return ret;			/* return what we should */
 285.311 +}
 285.312 +
 285.313 +/* MBX manipulate driver parameters
 285.314 + * Accepts: function code
 285.315 + *	    function-dependent value
 285.316 + * Returns: function-dependent return value
 285.317 + */
 285.318 +
 285.319 +void *mbx_parameters (long function,void *value)
 285.320 +{
 285.321 +  void *ret = NIL;
 285.322 +  switch ((int) function) {
 285.323 +  case SET_ONETIMEEXPUNGEATPING:
 285.324 +    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
 285.325 +  case GET_ONETIMEEXPUNGEATPING:
 285.326 +    if (value) ret = (void *)
 285.327 +      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
 285.328 +    break;
 285.329 +  }
 285.330 +  return ret;
 285.331 +}
 285.332 +
 285.333 +
 285.334 +/* MBX mail scan mailboxes
 285.335 + * Accepts: mail stream
 285.336 + *	    reference
 285.337 + *	    pattern to search
 285.338 + *	    string to scan
 285.339 + */
 285.340 +
 285.341 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 285.342 +{
 285.343 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 285.344 +}
 285.345 +
 285.346 +
 285.347 +/* MBX mail list mailboxes
 285.348 + * Accepts: mail stream
 285.349 + *	    reference
 285.350 + *	    pattern to search
 285.351 + */
 285.352 +
 285.353 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
 285.354 +{
 285.355 +  if (stream) dummy_list (NIL,ref,pat);
 285.356 +}
 285.357 +
 285.358 +
 285.359 +/* MBX mail list subscribed mailboxes
 285.360 + * Accepts: mail stream
 285.361 + *	    reference
 285.362 + *	    pattern to search
 285.363 + */
 285.364 +
 285.365 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 285.366 +{
 285.367 +  if (stream) dummy_lsub (NIL,ref,pat);
 285.368 +}
 285.369 +
 285.370 +/* MBX mail create mailbox
 285.371 + * Accepts: MAIL stream
 285.372 + *	    mailbox name to create
 285.373 + * Returns: T on success, NIL on failure
 285.374 + */
 285.375 +
 285.376 +long mbx_create (MAILSTREAM *stream,char *mailbox)
 285.377 +{
 285.378 +  char *s,mbx[MAILTMPLEN],tmp[HDRSIZE];
 285.379 +  long ret = NIL;
 285.380 +  int i,fd;
 285.381 +  if (!(s = dummy_file (mbx,mailbox))) {
 285.382 +    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 285.383 +    mm_log (mbx,ERROR);
 285.384 +  }
 285.385 +				/* create underlying file */
 285.386 +  else if (dummy_create (stream,s)) {
 285.387 +				/* done if made directory */
 285.388 +    if ((s = strrchr (s,'\\')) && !s[1]) return T;
 285.389 +    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
 285.390 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 285.391 +      mm_log (tmp,ERROR);
 285.392 +      unlink (mbx);		/* delete the file */
 285.393 +    }
 285.394 +    else {
 285.395 +      memset (tmp,'\0',HDRSIZE);/* initialize header */
 285.396 +      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
 285.397 +	       (unsigned long) time (0));
 285.398 +      for (i = 0; i < NUSERFLAGS; ++i)
 285.399 +	sprintf (s += strlen (s),"%s\015\012",
 285.400 +		 (stream && stream->user_flags[i]) ? stream->user_flags[i] :
 285.401 +		 "");
 285.402 +      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
 285.403 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
 285.404 +		 mbx,strerror (errno));
 285.405 +	mm_log (tmp,ERROR);
 285.406 +	unlink (mbx);		/* delete the file */
 285.407 +      }
 285.408 +      else ret = T;		/* success */
 285.409 +      close (fd);		/* close file */
 285.410 +    }
 285.411 +  }
 285.412 +  return ret;
 285.413 +}
 285.414 +
 285.415 +
 285.416 +/* MBX mail delete mailbox
 285.417 + * Accepts: MAIL stream
 285.418 + *	    mailbox name to delete
 285.419 + * Returns: T on success, NIL on failure
 285.420 + */
 285.421 +
 285.422 +long mbx_delete (MAILSTREAM *stream,char *mailbox)
 285.423 +{
 285.424 +  return mbx_rename (stream,mailbox,NIL);
 285.425 +}
 285.426 +
 285.427 +/* MBX mail rename mailbox
 285.428 + * Accepts: MAIL stream
 285.429 + *	    old mailbox name
 285.430 + *	    new mailbox name (or NIL for delete)
 285.431 + * Returns: T on success, NIL on failure
 285.432 + */
 285.433 +
 285.434 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
 285.435 +{
 285.436 +  long ret = LONGT;
 285.437 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 285.438 +  int fd,ld;
 285.439 +  struct stat sbuf;
 285.440 +  if (!dummy_file (file,old) ||
 285.441 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 285.442 +		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
 285.443 +    sprintf (tmp,newname ?
 285.444 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 285.445 +	     "Can't delete mailbox %.80s: invalid name",
 285.446 +	     old,newname);
 285.447 +    mm_log (tmp,ERROR);
 285.448 +    return NIL;
 285.449 +  }
 285.450 +  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
 285.451 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 285.452 +    mm_log (tmp,ERROR);
 285.453 +    return NIL;
 285.454 +  }
 285.455 +				/* get parse/append permission */
 285.456 +  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
 285.457 +    mm_log ("Unable to lock rename mailbox",ERROR);
 285.458 +    return NIL;
 285.459 +  }
 285.460 +				/* lock out other users */
 285.461 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 285.462 +    close (fd);			/* couldn't lock, give up on it then */
 285.463 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 285.464 +    mm_log (tmp,ERROR);
 285.465 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 285.466 +    return NIL;
 285.467 +  }
 285.468 +
 285.469 +  if (newname) {		/* want rename? */
 285.470 +				/* found superior to destination name? */
 285.471 +    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 285.472 +	((tmp[1] != ':') || (s != tmp + 2))) {
 285.473 +      c = s[1];			/* remember character after delimiter */
 285.474 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 285.475 +				/* name doesn't exist, create it */
 285.476 +      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 285.477 +	*s = '\\';		/* restore delimiter */
 285.478 +	if (!dummy_create (stream,tmp)) ret = NIL;
 285.479 +      }
 285.480 +      else *s = '\\';		/* restore delimiter */
 285.481 +      s[1] = c;			/* restore character after delimiter */
 285.482 +    }
 285.483 +    flock (fd,LOCK_UN);		/* release lock on the file */
 285.484 +    close (fd);			/* pacify NTFS */
 285.485 +				/* rename the file */
 285.486 +    if (ret && rename (file,tmp)) {
 285.487 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 285.488 +	       strerror (errno));
 285.489 +      mm_log (tmp,ERROR);
 285.490 +      ret = NIL;		/* set failure */
 285.491 +    }
 285.492 +  }
 285.493 +  else {
 285.494 +    flock (fd,LOCK_UN);		/* release lock on the file */
 285.495 +    close (fd);			/* pacify NTFS */
 285.496 +    if (unlink (file)) {
 285.497 +      sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 285.498 +      mm_log (tmp,ERROR);
 285.499 +      ret = NIL;		/* set failure */
 285.500 +    }
 285.501 +  }
 285.502 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 285.503 +				/* recreate file if renamed INBOX */
 285.504 +  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
 285.505 +  return ret;			/* return success */
 285.506 +}
 285.507 +
 285.508 +/* MBX mail open
 285.509 + * Accepts: stream to open
 285.510 + * Returns: stream on success, NIL on failure
 285.511 + */
 285.512 +
 285.513 +MAILSTREAM *mbx_open (MAILSTREAM *stream)
 285.514 +{
 285.515 +  int fd,ld;
 285.516 +  short silent;
 285.517 +  char tmp[MAILTMPLEN];
 285.518 +  if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */
 285.519 +  if (stream->local) fatal ("mbx recycle stream");
 285.520 +				/* canonicalize the mailbox name */
 285.521 +  if (!dummy_file (tmp,stream->mailbox)) {
 285.522 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 285.523 +    mm_log (tmp,ERROR);
 285.524 +  }
 285.525 +  if (stream->rdonly ||
 285.526 +      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
 285.527 +    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
 285.528 +      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 285.529 +      mm_log (tmp,ERROR);
 285.530 +      return NIL;
 285.531 +    }
 285.532 +    else if (!stream->rdonly) {	/* got it, but readonly */
 285.533 +      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 285.534 +      stream->rdonly = T;
 285.535 +    }
 285.536 +  }
 285.537 +
 285.538 +  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
 285.539 +  LOCAL->fd = fd;		/* bind the file */
 285.540 +  LOCAL->ld = -1;		/* no flaglock */
 285.541 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 285.542 +  LOCAL->buflen = CHUNKSIZE - 1;
 285.543 +				/* note if an INBOX or not */
 285.544 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 285.545 +  fs_give ((void **) &stream->mailbox);
 285.546 +  stream->mailbox = cpystr (tmp);
 285.547 +				/* get parse/append permission */
 285.548 +  if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) {
 285.549 +    mm_log ("Unable to lock open mailbox",ERROR);
 285.550 +    return NIL;
 285.551 +  }
 285.552 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 285.553 +  unlockfd (ld,tmp);		/* release shared parse permission */
 285.554 +  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
 285.555 +  LOCAL->filetime = 0;		/* time not set up yet */
 285.556 +  LOCAL->expok = LOCAL->flagcheck = NIL;
 285.557 +  stream->sequence++;		/* bump sequence number */
 285.558 +				/* parse mailbox */
 285.559 +  stream->nmsgs = stream->recent = 0;
 285.560 +  silent = stream->silent;	/* defer events */
 285.561 +  stream->silent = T;
 285.562 +  if (mbx_ping (stream) && !stream->nmsgs)
 285.563 +    mm_log ("Mailbox is empty",(long) NIL);
 285.564 +  stream->silent = silent;	/* now notify upper level */
 285.565 +  mail_exists (stream,stream->nmsgs);
 285.566 +  mail_recent (stream,stream->recent);
 285.567 +  if (!LOCAL) return NIL;	/* failure if stream died */
 285.568 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 285.569 +    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 285.570 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 285.571 +  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
 285.572 +    NIL : T;			/* can we create new user flags? */
 285.573 +  return stream;		/* return stream to caller */
 285.574 +}
 285.575 +
 285.576 +/* MBX mail close
 285.577 + * Accepts: MAIL stream
 285.578 + *	    close options
 285.579 + */
 285.580 +
 285.581 +void mbx_close (MAILSTREAM *stream,long options)
 285.582 +{
 285.583 +  if (stream && LOCAL) {	/* only if a file is open */
 285.584 +    int silent = stream->silent;
 285.585 +    stream->silent = T;		/* note this stream is dying */
 285.586 +				/* do an expunge if requested */
 285.587 +    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
 285.588 +    else {			/* otherwise do a checkpoint to purge */
 285.589 +      LOCAL->expok = T;		/*  possible expunged messages */
 285.590 +      mbx_ping (stream);
 285.591 +    }
 285.592 +    stream->silent = silent;	/* restore previous status */
 285.593 +    mbx_abort (stream);
 285.594 +  }
 285.595 +}
 285.596 +
 285.597 +
 285.598 +/* MBX mail abort stream
 285.599 + * Accepts: MAIL stream
 285.600 + */
 285.601 +
 285.602 +void mbx_abort (MAILSTREAM *stream)
 285.603 +{
 285.604 +  if (stream && LOCAL) {	/* only if a file is open */
 285.605 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 285.606 +    close (LOCAL->fd);		/* close the local file */
 285.607 +				/* free local text buffer */
 285.608 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 285.609 +				/* nuke the local data */
 285.610 +    fs_give ((void **) &stream->local);
 285.611 +    stream->dtb = NIL;		/* log out the DTB */
 285.612 +  }
 285.613 +}
 285.614 +
 285.615 +
 285.616 +/* MBX mail fetch flags
 285.617 + * Accepts: MAIL stream
 285.618 + *	    sequence
 285.619 + *	    option flags
 285.620 + * Sniffs at file to see if some other process changed the flags
 285.621 + */
 285.622 +
 285.623 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
 285.624 +{
 285.625 +  MESSAGECACHE *elt;
 285.626 +  unsigned long i;
 285.627 +  if (mbx_ping (stream) &&	/* ping mailbox, get new status for messages */
 285.628 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 285.629 +       mail_sequence (stream,sequence)))
 285.630 +    for (i = 1; i <= stream->nmsgs; i++) 
 285.631 +      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
 285.632 +	mbx_elt (stream,i,NIL);
 285.633 +}
 285.634 +
 285.635 +/* MBX mail fetch message header
 285.636 + * Accepts: MAIL stream
 285.637 + *	    message # to fetch
 285.638 + *	    pointer to returned header text length
 285.639 + *	    option flags
 285.640 + * Returns: message header in RFC822 format
 285.641 + */
 285.642 +
 285.643 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 285.644 +		  long flags)
 285.645 +{
 285.646 +  unsigned long i;
 285.647 +  char *s;
 285.648 +  *length = 0;			/* default to empty */
 285.649 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 285.650 +				/* get header position, possibly header */
 285.651 +  i = mbx_hdrpos (stream,msgno,length,&s);
 285.652 +  if (!s) {			/* mbx_hdrpos() returned header? */
 285.653 +    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
 285.654 +				/* is buffer big enough? */
 285.655 +    if (*length > LOCAL->buflen) {
 285.656 +      fs_give ((void **) &LOCAL->buf);
 285.657 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 285.658 +    }
 285.659 +				/* slurp the data */
 285.660 +    read (LOCAL->fd,s = LOCAL->buf,*length);
 285.661 +  }
 285.662 +  s[*length] = '\0';		/* tie off string */
 285.663 +  return s;
 285.664 +}
 285.665 +
 285.666 +/* MBX mail fetch message text (body only)
 285.667 + * Accepts: MAIL stream
 285.668 + *	    message # to fetch
 285.669 + *	    pointer to returned header text length
 285.670 + *	    option flags
 285.671 + * Returns: T on success, NIL on failure
 285.672 + */
 285.673 +
 285.674 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 285.675 +{
 285.676 +  FDDATA d;
 285.677 +  unsigned long i,j;
 285.678 +  MESSAGECACHE *elt;
 285.679 +				/* UID call "impossible" */
 285.680 +  if (flags & FT_UID) return NIL;
 285.681 +				/* get message status */
 285.682 +  elt = mbx_elt (stream,msgno,NIL);
 285.683 +				/* if message not seen */
 285.684 +  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
 285.685 +    elt->seen = T;		/* mark message as seen */
 285.686 +				/* recalculate status */
 285.687 +    mbx_update_status (stream,msgno,NIL);
 285.688 +    mm_flags (stream,msgno);
 285.689 +				/* update flags */
 285.690 +    mbx_flag (stream,NIL,NIL,NIL);
 285.691 +  }
 285.692 +  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
 285.693 +				/* find header position */
 285.694 +  i = mbx_hdrpos (stream,msgno,&j,NIL);
 285.695 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 285.696 +  d.pos = i + j;
 285.697 +  d.chunk = LOCAL->buf;	/* initial buffer chunk */
 285.698 +  d.chunksize = CHUNKSIZE;
 285.699 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 285.700 +  return LONGT;			/* success */
 285.701 +}
 285.702 +
 285.703 +/* MBX mail modify flags
 285.704 + * Accepts: MAIL stream
 285.705 + *	    sequence
 285.706 + *	    flag(s)
 285.707 + *	    option flags
 285.708 + * Unlocks flag lock
 285.709 + */
 285.710 +
 285.711 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 285.712 +{
 285.713 +  struct utimbuf times;
 285.714 +  struct stat sbuf;
 285.715 +				/* make sure the update takes */
 285.716 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
 285.717 +    fsync (LOCAL->fd);
 285.718 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 285.719 +    times.modtime = LOCAL->filetime = sbuf.st_mtime;
 285.720 +				/* update header */
 285.721 +    if ((LOCAL->ffuserflag < NUSERFLAGS) &&
 285.722 +	stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream);
 285.723 +    times.actime = time (0);	/* make sure read comes after all that */
 285.724 +    utime (stream->mailbox,&times);
 285.725 +  }
 285.726 +  if (LOCAL->ld >= 0) {		/* unlock now */
 285.727 +    unlockfd (LOCAL->ld,LOCAL->lock);
 285.728 +    LOCAL->ld = -1;
 285.729 +  }
 285.730 +}
 285.731 +
 285.732 +
 285.733 +/* MBX mail per-message modify flags
 285.734 + * Accepts: MAIL stream
 285.735 + *	    message cache element
 285.736 + */
 285.737 +
 285.738 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 285.739 +{
 285.740 +  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
 285.741 +}
 285.742 +
 285.743 +/* MBX mail ping mailbox
 285.744 + * Accepts: MAIL stream
 285.745 + * Returns: T if stream still alive, NIL if not
 285.746 + */
 285.747 +
 285.748 +long mbx_ping (MAILSTREAM *stream)
 285.749 +{
 285.750 +  unsigned long i,pos;
 285.751 +  long ret = NIL;
 285.752 +  int ld;
 285.753 +  char lock[MAILTMPLEN];
 285.754 +  MESSAGECACHE *elt;
 285.755 +  struct stat sbuf;
 285.756 +  if (stream && LOCAL) {	/* only if stream already open */
 285.757 +    ret = LONGT;		/* assume OK */
 285.758 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 285.759 +				/* allow expunge if permitted at ping */
 285.760 +    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
 285.761 +				/* if external modification */
 285.762 +    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
 285.763 +      LOCAL->flagcheck = T;	/* upgrade to flag checking */
 285.764 +				/* new mail or flagcheck handling needed? */
 285.765 +    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
 285.766 +	 !stream->nmsgs) &&
 285.767 +	((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) {
 285.768 +      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
 285.769 +				/* sweep mailbox for changed message status */
 285.770 +      else if (ret = mbx_parse (stream)) {
 285.771 +	unsigned long recent = 0;
 285.772 +	LOCAL->filetime = sbuf.st_mtime;
 285.773 +	for (i = 1; i <= stream->nmsgs; )
 285.774 +	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
 285.775 +	    if (elt->recent) ++recent;
 285.776 +	    ++i;
 285.777 +	  }
 285.778 +	mail_recent (stream,recent);
 285.779 +	LOCAL->flagcheck = NIL;	/* got all the updates */
 285.780 +      }
 285.781 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 285.782 +    }
 285.783 +    if (ret) {			/* must still be alive */
 285.784 +      if (!LOCAL->expunged)	/* look for holes if none known yet */
 285.785 +	for (i = 1, pos = HDRSIZE;
 285.786 +	     !LOCAL->expunged && (i <= stream->nmsgs);
 285.787 +	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
 285.788 +	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
 285.789 +	    LOCAL->expunged = T;/* found a hole */
 285.790 +				/* burp any holes */
 285.791 +      if (LOCAL->expunged && !stream->rdonly) {
 285.792 +	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
 285.793 +	if (i) {		/* any space reclaimed? */
 285.794 +	  LOCAL->expunged = NIL;/* no more pending expunge */
 285.795 +	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
 285.796 +	  mm_log (LOCAL->buf,(long) NIL);
 285.797 +	}
 285.798 +      }
 285.799 +      LOCAL->expok = NIL;	/* no more expok */
 285.800 +    }
 285.801 +  }
 285.802 +  return ret;			/* return result of the parse */
 285.803 +}
 285.804 +
 285.805 +/* MBX mail check mailbox (reparses status too)
 285.806 + * Accepts: MAIL stream
 285.807 + */
 285.808 +
 285.809 +void mbx_check (MAILSTREAM *stream)
 285.810 +{
 285.811 +  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
 285.812 +  if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL);
 285.813 +}
 285.814 +
 285.815 +
 285.816 +/* MBX mail expunge mailbox
 285.817 + * Accepts: MAIL stream
 285.818 + *	    sequence to expunge if non-NIL
 285.819 + *	    expunge options
 285.820 + * Returns: T if success, NIL if failure
 285.821 + */
 285.822 +
 285.823 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
 285.824 +{
 285.825 +  long ret;
 285.826 +  unsigned long nexp,reclaimed;
 285.827 +  if (ret = sequence ? ((options & EX_UID) ?
 285.828 +			mail_uid_sequence (stream,sequence) :
 285.829 +			mail_sequence (stream,sequence)) : LONGT) {
 285.830 +    if (!mbx_ping (stream));	/* do nothing if stream dead */
 285.831 +    else if (stream->rdonly)	/* won't do on readonly files! */
 285.832 +      mm_log ("Expunge ignored on readonly mailbox",WARN);
 285.833 +				/* if expunged any messages */
 285.834 +    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
 285.835 +      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
 285.836 +      mm_log (LOCAL->buf,(long) NIL);
 285.837 +    }
 285.838 +    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
 285.839 +      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
 285.840 +      mm_log (LOCAL->buf,(long) NIL);
 285.841 +    }
 285.842 +    else mm_log ("No messages deleted, so no update needed",(long) NIL);
 285.843 +  }
 285.844 +  return ret;
 285.845 +}
 285.846 +
 285.847 +/* MBX mail copy message(s)
 285.848 + * Accepts: MAIL stream
 285.849 + *	    sequence
 285.850 + *	    destination mailbox
 285.851 + *	    copy options
 285.852 + * Returns: T if success, NIL if failed
 285.853 + */
 285.854 +
 285.855 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 285.856 +{
 285.857 +  struct stat sbuf;
 285.858 +  struct utimbuf times;
 285.859 +  MESSAGECACHE *elt;
 285.860 +  unsigned long i,j,k,m;
 285.861 +  long ret = LONGT;
 285.862 +  int fd,ld;
 285.863 +  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
 285.864 +  mailproxycopy_t pc =
 285.865 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 285.866 +  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 285.867 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 285.868 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 285.869 +  MAILSTREAM *dstream = NIL;
 285.870 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 285.871 +	mail_sequence (stream,sequence))) return NIL;
 285.872 +				/* make sure valid mailbox */
 285.873 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
 285.874 +			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
 285.875 +    switch (errno) {
 285.876 +    case ENOENT:		/* no such file? */
 285.877 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 285.878 +      return NIL;
 285.879 +    case EACCES:		/* file protected */
 285.880 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 285.881 +      MM_LOG (LOCAL->buf,ERROR);
 285.882 +      return NIL;
 285.883 +    case EINVAL:
 285.884 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 285.885 +      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
 285.886 +      mm_log (LOCAL->buf,ERROR);
 285.887 +      return NIL;
 285.888 +    default:
 285.889 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 285.890 +      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
 285.891 +      mm_log (LOCAL->buf,ERROR);
 285.892 +      return NIL;
 285.893 +    }
 285.894 +				/* got file? */  
 285.895 +  if ((fd = open (dummy_file (file,mailbox),O_RDWR|O_CREAT|O_BINARY,
 285.896 +		  S_IREAD|S_IWRITE)) < 0) {
 285.897 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
 285.898 +    mm_log (LOCAL->buf,ERROR);
 285.899 +    return NIL;
 285.900 +  }
 285.901 +  mm_critical (stream);		/* go critical */
 285.902 +  fstat (fd,&sbuf);		/* get current file size */
 285.903 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 285.904 +
 285.905 +				/* for each requested message */
 285.906 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 285.907 +    if ((elt = mail_elt (stream,i))->sequence) {
 285.908 +      lseek (LOCAL->fd,elt->private.special.offset +
 285.909 +	     elt->private.special.text.size,L_SET);
 285.910 +      mail_date(LOCAL->buf,elt);/* build target header */
 285.911 +				/* get target keyword mask */
 285.912 +      for (j = elt->user_flags, k = 0; j; )
 285.913 +	if (s = stream->user_flags[find_rightmost_bit (&j)])
 285.914 +	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
 285.915 +	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
 285.916 +      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
 285.917 +	       elt->rfc822_size,k,(unsigned)
 285.918 +	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 285.919 +		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 285.920 +		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
 285.921 +				/* write target header */
 285.922 +      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
 285.923 +	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
 285.924 +	  read (LOCAL->fd,LOCAL->buf,j);
 285.925 +	  ret = write (fd,LOCAL->buf,j) >= 0;
 285.926 +	}
 285.927 +	if (cu) {		/* need to pass back new UID? */
 285.928 +	  mail_append_set (source,mail_uid (stream,i));
 285.929 +	  mail_append_set (dest,dstream->uid_last);
 285.930 +	}
 285.931 +      }
 285.932 +    }
 285.933 +
 285.934 +				/* make sure all the updates take */
 285.935 +  if (!(ret && (ret = !fsync (fd)))) {
 285.936 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 285.937 +    mm_log (LOCAL->buf,ERROR);
 285.938 +    ftruncate (fd,sbuf.st_size);
 285.939 +  }
 285.940 +  if (cu && ret) {		/* return sets if doing COPYUID */
 285.941 +    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
 285.942 +    lseek (fd,15,L_SET);	/* update UIDLAST */
 285.943 +    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
 285.944 +    write (fd,LOCAL->buf,8);
 285.945 +  }
 285.946 +  else {			/* flush any sets we may have built */
 285.947 +    mail_free_searchset (&source);
 285.948 +    mail_free_searchset (&dest);
 285.949 +  }
 285.950 +				/* set atime to now-1 if successful copy */
 285.951 +  if (ret) times.actime = time (0) - 1;
 285.952 +				/* else preserved \Marked status */
 285.953 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 285.954 +	 sbuf.st_atime : time (0);
 285.955 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 285.956 +  utime (file,&times);		/* set the times */
 285.957 +  close (fd);			/* close the file */
 285.958 +  mm_nocritical (stream);	/* release critical */
 285.959 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 285.960 +				/* delete all requested messages */
 285.961 +  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
 285.962 +    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
 285.963 +				/* mark message deleted */
 285.964 +      mbx_elt (stream,i,NIL)->deleted = T;
 285.965 +				/* recalculate status */
 285.966 +      mbx_update_status (stream,i,NIL);
 285.967 +    }
 285.968 +				/* update flags */
 285.969 +    mbx_flag (stream,NIL,NIL,NIL);
 285.970 +  }
 285.971 +  if (dstream != stream) mail_close (dstream);
 285.972 +  return ret;
 285.973 +}
 285.974 +
 285.975 +/* MBX mail append message from stringstruct
 285.976 + * Accepts: MAIL stream
 285.977 + *	    destination mailbox
 285.978 + *	    append callback
 285.979 + *	    data for callback
 285.980 + * Returns: T if append successful, else NIL
 285.981 + */
 285.982 +
 285.983 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 285.984 +{
 285.985 +  struct stat sbuf;
 285.986 +  int fd,ld;
 285.987 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 285.988 +  struct utimbuf times;
 285.989 +  FILE *df;
 285.990 +  MESSAGECACHE elt;
 285.991 +  long f;
 285.992 +  unsigned long i,uf;
 285.993 +  STRING *message;
 285.994 +  long ret = NIL;
 285.995 +  MAILSTREAM *dstream = NIL;
 285.996 +  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
 285.997 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
 285.998 +				/* make sure valid mailbox */
 285.999 +				/* make sure valid mailbox */
285.1000 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
285.1001 +			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
285.1002 +    switch (errno) {
285.1003 +    case ENOENT:		/* no such file? */
285.1004 +      if (compare_cstring (mailbox,"INBOX")) {
285.1005 +	mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
285.1006 +	return NIL;
285.1007 +      }
285.1008 +				/* can create INBOX here */
285.1009 +      mbx_create (dstream = stream ? stream : &mbxproto,"INBOX");
285.1010 +      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
285.1011 +			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
285.1012 +	break;
285.1013 +    case EACCES:		/* file protected */
285.1014 +      sprintf (tmp,"Can't access destination: %.80s",mailbox);
285.1015 +      MM_LOG (tmp,ERROR);
285.1016 +      return NIL;
285.1017 +    case EINVAL:
285.1018 +      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
285.1019 +      mm_log (tmp,ERROR);
285.1020 +      return NIL;
285.1021 +    default:
285.1022 +      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
285.1023 +      mm_log (tmp,ERROR);
285.1024 +      return NIL;
285.1025 +    }
285.1026 +
285.1027 +				/* get first message */
285.1028 +  if (!(*af) (dstream,data,&flags,&date,&message)) close (fd);
285.1029 +  else if (!(df = fdopen (fd,"r+b"))) {
285.1030 +    MM_LOG ("Unable to reopen append mailbox",ERROR);
285.1031 +    close (fd);
285.1032 +  }
285.1033 +  else {
285.1034 +    mm_critical (dstream);	/* go critical */
285.1035 +    fstat (fd,&sbuf);		/* get current file size */
285.1036 +    fseek (df,sbuf.st_size,SEEK_SET);
285.1037 +    errno = 0;
285.1038 +    for (ret = LONGT; ret && message; ) {
285.1039 +      if (!SIZE (message)) {	/* guard against zero-length */
285.1040 +	mm_log ("Append of zero-length message",ERROR);
285.1041 +	ret = NIL;
285.1042 +	break;
285.1043 +      }
285.1044 +      f = mail_parse_flags (dstream,flags,&uf);
285.1045 +      if (date) {		/* parse date if given */
285.1046 +	if (!mail_parse_date (&elt,date)) {
285.1047 +	  sprintf (tmp,"Bad date in append: %.80s",date);
285.1048 +	  mm_log (tmp,ERROR);
285.1049 +	  ret = NIL;		/* mark failure */
285.1050 +	  break;
285.1051 +	}
285.1052 +	mail_date (tmp,&elt);	/* write preseved date */
285.1053 +      }
285.1054 +      else internal_date (tmp);	/* get current date in IMAP format */
285.1055 +				/* write header */
285.1056 +      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
285.1057 +		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
285.1058 +	ret = NIL;
285.1059 +      else {			/* write message */
285.1060 +	size_t j;
285.1061 +	if (!message->cursize) SETPOS (message,GETPOS (message));
285.1062 +	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
285.1063 +	  i -= j;
285.1064 +	  SETPOS (message,GETPOS (message) + j);
285.1065 +	}
285.1066 +				/* get next message */
285.1067 +	if (i || !(*af) (dstream,data,&flags,&date,&message)) ret = NIL;
285.1068 +	else if (au) mail_append_set (dst,dstream->uid_last);
285.1069 +      }
285.1070 +    }
285.1071 +
285.1072 +				/* if error... */
285.1073 +    if (!ret || (fflush (df) == EOF)) {
285.1074 +				/* revert file */
285.1075 +      ftruncate (fd,sbuf.st_size);
285.1076 +      close (fd);		/* make sure fclose() doesn't corrupt us */
285.1077 +      if (errno) {
285.1078 +	sprintf (tmp,"Message append failed: %s",strerror (errno));
285.1079 +	mm_log (tmp,ERROR);
285.1080 +      }
285.1081 +      ret = NIL;
285.1082 +    }
285.1083 +    if (au && ret) {		/* return sets if doing APPENDUID */
285.1084 +      (*au) (mailbox,dstream->uid_validity,dst);
285.1085 +      fseek (df,15,SEEK_SET);	/* update UIDLAST */
285.1086 +      fprintf (df,"%08lx",dstream->uid_last);
285.1087 +    }
285.1088 +    else mail_free_searchset (&dst);
285.1089 +    if (ret) times.actime = time (0) - 1;
285.1090 +				/* else preserve \Marked status */
285.1091 +    else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
285.1092 +	   sbuf.st_atime : time (0);
285.1093 +				/* preserve mtime */
285.1094 +    times.modtime = sbuf.st_mtime;
285.1095 +    utime (file,&times);	/* set the times */
285.1096 +    fclose (df);		/* close the file */
285.1097 +    mm_nocritical (dstream);	/* release critical */
285.1098 +  }
285.1099 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
285.1100 +  if (dstream != stream) mail_close (dstream);
285.1101 +  return ret;
285.1102 +}
285.1103 +
285.1104 +/* Internal routines */
285.1105 +
285.1106 +
285.1107 +/* MBX mail parse mailbox
285.1108 + * Accepts: MAIL stream
285.1109 + * Returns: T if parse OK
285.1110 + *	    NIL if failure, stream aborted
285.1111 + */
285.1112 +
285.1113 +long mbx_parse (MAILSTREAM *stream)
285.1114 +{
285.1115 +  struct stat sbuf;
285.1116 +  MESSAGECACHE *elt = NIL;
285.1117 +  unsigned char c,*s,*t,*x;
285.1118 +  char tmp[MAILTMPLEN];
285.1119 +  unsigned long i,j,k,m;
285.1120 +  off_t curpos = LOCAL->filesize;
285.1121 +  unsigned long nmsgs = stream->nmsgs;
285.1122 +  unsigned long recent = stream->recent;
285.1123 +  unsigned long lastuid = 0;
285.1124 +  short dirty = NIL;
285.1125 +  short added = NIL;
285.1126 +  short silent = stream->silent;
285.1127 +  short uidwarn = T;
285.1128 +  fstat (LOCAL->fd,&sbuf);	/* get status */
285.1129 +  if (sbuf.st_size < curpos) {	/* sanity check */
285.1130 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
285.1131 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
285.1132 +    mm_log (tmp,ERROR);
285.1133 +    mbx_abort (stream);
285.1134 +    return NIL;
285.1135 +  }
285.1136 +  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
285.1137 +				/* read internal header */
285.1138 +  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
285.1139 +  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
285.1140 +  c = LOCAL->buf[15];		/* save first character of last UID */
285.1141 +  LOCAL->buf[15] = '\0';
285.1142 +				/* parse UID validity */
285.1143 +  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
285.1144 +  LOCAL->buf[15] = c;		/* restore first character of last UID */
285.1145 +				/* parse last UID */
285.1146 +  i = strtoul (LOCAL->buf + 15,NIL,16);
285.1147 +  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
285.1148 +				/* parse user flags */
285.1149 +  for (i = 0, s = LOCAL->buf + 25;
285.1150 +       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
285.1151 +       i++, s = t + 2) {
285.1152 +    *t = '\0';			/* tie off flag */
285.1153 +    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
285.1154 +      stream->user_flags[i] = cpystr (s);
285.1155 +  }
285.1156 +  LOCAL->ffuserflag = (int) i;	/* first free user flag */
285.1157 +
285.1158 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
285.1159 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
285.1160 +				/* get to that position in the file */
285.1161 +    lseek (LOCAL->fd,curpos,L_SET);
285.1162 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
285.1163 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
285.1164 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
285.1165 +	       i ? strerror (errno) : "no data read");
285.1166 +      mm_log (tmp,ERROR);
285.1167 +      mbx_abort (stream);
285.1168 +      return NIL;
285.1169 +    }
285.1170 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
285.1171 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
285.1172 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
285.1173 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
285.1174 +      mm_log (tmp,ERROR);
285.1175 +      mbx_abort (stream);
285.1176 +      return NIL;
285.1177 +    }
285.1178 +    *s = '\0';			/* tie off header line */
285.1179 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
285.1180 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
285.1181 +      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
285.1182 +	       (unsigned long) curpos,(char *) LOCAL->buf);
285.1183 +      mm_log (tmp,ERROR);
285.1184 +      mbx_abort (stream);
285.1185 +      return NIL;
285.1186 +    }
285.1187 +    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
285.1188 +	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
285.1189 +	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
285.1190 +	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
285.1191 +      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
285.1192 +	       (unsigned long) curpos,(char *) LOCAL->buf);
285.1193 +      mm_log (tmp,ERROR);
285.1194 +      mbx_abort (stream);
285.1195 +      return NIL;
285.1196 +    }
285.1197 +    if ((t[13] != '-') || t[22] ||
285.1198 +	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
285.1199 +	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
285.1200 +	  isxdigit (t[20]) && isxdigit (t[21]))) {
285.1201 +      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
285.1202 +	       (unsigned long) curpos,(char *) LOCAL->buf);
285.1203 +      mm_log (tmp,ERROR);
285.1204 +      mbx_abort (stream);
285.1205 +      return NIL;
285.1206 +    }
285.1207 +
285.1208 +    *s++ = '\0'; *t++ = '\0';	/* break up fields */
285.1209 +				/* get message size */
285.1210 +    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
285.1211 +      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
285.1212 +	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
285.1213 +	       (char *) t);
285.1214 +      mm_log (tmp,ERROR);
285.1215 +      mbx_abort (stream);
285.1216 +      return NIL;
285.1217 +    }
285.1218 +				/* make sure didn't run off end of file */
285.1219 +    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
285.1220 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
285.1221 +	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
285.1222 +	       (unsigned long) sbuf.st_size);
285.1223 +      mm_log (tmp,ERROR);
285.1224 +      mbx_abort (stream);
285.1225 +      return NIL;
285.1226 +    }
285.1227 +				/* parse UID */
285.1228 +    if ((m = strtoul (t+13,NIL,16)) &&
285.1229 +	((m <= lastuid) || (m > stream->uid_last))) {
285.1230 +      if (uidwarn) {
285.1231 +	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
285.1232 +		 m,nmsgs+1);
285.1233 +	mm_log (tmp,WARN);
285.1234 +	uidwarn = NIL;
285.1235 +				/* restart UID validity */
285.1236 +	stream->uid_validity = (unsigned long) time (0);
285.1237 +      }
285.1238 +      m = 0;			/* lose this UID */
285.1239 +      dirty = T;		/* mark dirty, set new lastuid */
285.1240 +      stream->uid_last = lastuid;
285.1241 +    }
285.1242 +
285.1243 +    t[12] = '\0';		/* parse system flags */
285.1244 +    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
285.1245 +      if (m) lastuid = m;	/* expunge message, update last UID seen */
285.1246 +      else {			/* no UID assigned? */
285.1247 +	lastuid = ++stream->uid_last;
285.1248 +	dirty = T;
285.1249 +      }
285.1250 +    }
285.1251 +    else {			/* not expunged, swell the cache */
285.1252 +      added = T;		/* note that a new message was added */
285.1253 +      mail_exists (stream,++nmsgs);
285.1254 +				/* instantiate an elt for this message */
285.1255 +      (elt = mail_elt (stream,nmsgs))->valid = T;
285.1256 +				/* parse the date */
285.1257 +      if (!mail_parse_date (elt,LOCAL->buf)) {
285.1258 +	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
285.1259 +		 (unsigned long) curpos,(char *) LOCAL->buf);
285.1260 +	mm_log (tmp,ERROR);
285.1261 +	mbx_abort (stream);
285.1262 +	return NIL;
285.1263 +      }
285.1264 +				/* note file offset of header */
285.1265 +      elt->private.special.offset = curpos;
285.1266 +				/* and internal header size */
285.1267 +      elt->private.special.text.size = i;
285.1268 +				/* header size not known yet */
285.1269 +      elt->private.msg.header.text.size = 0;
285.1270 +      elt->rfc822_size = j;	/* note message size */
285.1271 +				/* calculate system flags */
285.1272 +      if (k & fSEEN) elt->seen = T;
285.1273 +      if (k & fDELETED) elt->deleted = T;
285.1274 +      if (k & fFLAGGED) elt->flagged = T;
285.1275 +      if (k & fANSWERED) elt->answered = T;
285.1276 +      if (k & fDRAFT) elt->draft = T;
285.1277 +      t[8] = '\0';		/* get user flags value */
285.1278 +      elt->user_flags = strtoul (t,NIL,16);
285.1279 +				/* UID already assigned? */
285.1280 +      if (!(elt->private.uid = m) || !(k & fOLD)) {
285.1281 +	elt->recent = T;	/* no, mark as recent */
285.1282 +	++recent;		/* count up a new recent message */
285.1283 +	dirty = T;		/* and must rewrite header */
285.1284 +				/* assign new UID */
285.1285 +	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
285.1286 +	mbx_update_status (stream,elt->msgno,NIL);
285.1287 +      }
285.1288 +				/* update last parsed UID */
285.1289 +      lastuid = elt->private.uid;
285.1290 +    }
285.1291 +    curpos += i + j;		/* update position */
285.1292 +  }
285.1293 +
285.1294 +  if (dirty && !stream->rdonly){/* update header */
285.1295 +    mbx_update_header (stream);
285.1296 +    fsync (LOCAL->fd);		/* make sure all the UID updates take */
285.1297 +  }
285.1298 +				/* update parsed file size and time */
285.1299 +  LOCAL->filesize = sbuf.st_size;
285.1300 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
285.1301 +  LOCAL->filetime = sbuf.st_mtime;
285.1302 +  if (added && !stream->rdonly){/* make sure atime updated */
285.1303 +    struct utimbuf times;
285.1304 +    times.actime = time (0);
285.1305 +    times.modtime = LOCAL->filetime;
285.1306 +    utime (stream->mailbox,&times);
285.1307 +  }
285.1308 +  stream->silent = silent;	/* can pass up events now */
285.1309 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
285.1310 +  mail_recent (stream,recent);	/* and of change in recent messages */
285.1311 +  return LONGT;			/* return the winnage */
285.1312 +}
285.1313 +
285.1314 +/* MBX get cache element with status updating from file
285.1315 + * Accepts: MAIL stream
285.1316 + *	    message number
285.1317 + *	    expunge OK flag
285.1318 + * Returns: cache element
285.1319 + */
285.1320 +
285.1321 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
285.1322 +{
285.1323 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
285.1324 +  struct {			/* old flags */
285.1325 +    unsigned int seen : 1;
285.1326 +    unsigned int deleted : 1;
285.1327 +    unsigned int flagged : 1;
285.1328 +    unsigned int answered : 1;
285.1329 +    unsigned int draft : 1;
285.1330 +    unsigned long user_flags;
285.1331 +  } old;
285.1332 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
285.1333 +  old.answered = elt->answered; old.draft = elt->draft;
285.1334 +  old.user_flags = elt->user_flags;
285.1335 +				/* get new flags */
285.1336 +  if (mbx_read_flags (stream,elt) && expok) {
285.1337 +    mail_expunged (stream,elt->msgno);
285.1338 +    return NIL;			/* return this message was expunged */
285.1339 +  }
285.1340 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
285.1341 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
285.1342 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
285.1343 +    mm_flags (stream,msgno);	/* let top level know */
285.1344 +  return elt;
285.1345 +}
285.1346 +
285.1347 +/* MBX read flags from file
285.1348 + * Accepts: MAIL stream
285.1349 + *	    cache element
285.1350 + * Returns: non-NIL if message expunged
285.1351 + */
285.1352 +
285.1353 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
285.1354 +{
285.1355 +  unsigned long i;
285.1356 +  struct stat sbuf;
285.1357 +  fstat (LOCAL->fd,&sbuf);	/* get status */
285.1358 +				/* make sure file size is good */
285.1359 +  if (sbuf.st_size < LOCAL->filesize) {
285.1360 +    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
285.1361 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
285.1362 +    fatal (LOCAL->buf);
285.1363 +  }
285.1364 +				/* set the seek pointer */
285.1365 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
285.1366 +	 elt->private.special.text.size - 24,L_SET);
285.1367 +				/* read the new flags */
285.1368 +  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
285.1369 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
285.1370 +    fatal (LOCAL->buf);
285.1371 +  }
285.1372 +  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
285.1373 +    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
285.1374 +    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
285.1375 +	     elt->msgno,elt->private.special.offset,
285.1376 +	     elt->private.special.text.size,(char *) LOCAL->buf);
285.1377 +    fatal (LOCAL->buf+50);
285.1378 +  }
285.1379 +  LOCAL->buf[13] = '\0';	/* tie off buffer */
285.1380 +				/* calculate system flags */
285.1381 +  i = strtoul (LOCAL->buf+9,NIL,16);
285.1382 +  elt->seen = i & fSEEN ? T : NIL;
285.1383 +  elt->deleted = i & fDELETED ? T : NIL;
285.1384 +  elt->flagged = i & fFLAGGED ? T : NIL;
285.1385 +  elt->answered = i & fANSWERED ? T : NIL;
285.1386 +  elt->draft = i & fDRAFT ? T : NIL;
285.1387 +  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
285.1388 +  LOCAL->buf[9] = '\0';		/* tie off flags */
285.1389 +				/* get user flags value */
285.1390 +  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
285.1391 +  elt->valid = T;		/* have valid flags now */
285.1392 +  return i & fEXPUNGED;
285.1393 +}
285.1394 +
285.1395 +/* MBX update header
285.1396 + * Accepts: MAIL stream
285.1397 + */
285.1398 +
285.1399 +#define NTKLUDGEOFFSET 7
285.1400 +
285.1401 +void mbx_update_header (MAILSTREAM *stream)
285.1402 +{
285.1403 +  int i;
285.1404 +  char *s = LOCAL->buf;
285.1405 +  memset (s,'\0',HDRSIZE);	/* initialize header */
285.1406 +  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
285.1407 +	   stream->uid_validity,stream->uid_last);
285.1408 +  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
285.1409 +    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
285.1410 +  LOCAL->ffuserflag = i;	/* first free user flag */
285.1411 +				/* can we create more user flags? */
285.1412 +  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
285.1413 +				/* write reserved lines */
285.1414 +  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
285.1415 +  while (T) {			/* rewind file */
285.1416 +    lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET);
285.1417 +				/* write new header */
285.1418 +    if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET,
285.1419 +	       HDRSIZE - NTKLUDGEOFFSET) > 0) break;
285.1420 +    mm_notify (stream,strerror (errno),WARN);
285.1421 +    mm_diskerror (stream,errno,T);
285.1422 +  }
285.1423 +}
285.1424 +
285.1425 +/* MBX update status string
285.1426 + * Accepts: MAIL stream
285.1427 + *	    message number
285.1428 + *	    flags
285.1429 + */
285.1430 +
285.1431 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
285.1432 +{
285.1433 +  struct stat sbuf;
285.1434 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
285.1435 +				/* readonly */
285.1436 +  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
285.1437 +  else {			/* readwrite */
285.1438 +    fstat (LOCAL->fd,&sbuf);	/* get status */
285.1439 +				/* make sure file size is good */
285.1440 +    if (sbuf.st_size < LOCAL->filesize) {
285.1441 +      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
285.1442 +	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
285.1443 +      fatal (LOCAL->buf);
285.1444 +    }
285.1445 +				/* set the seek pointer */
285.1446 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
285.1447 +	   elt->private.special.text.size - 24,L_SET);
285.1448 +				/* read the new flags */
285.1449 +    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
285.1450 +      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
285.1451 +      fatal (LOCAL->buf);
285.1452 +    }
285.1453 +    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
285.1454 +      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
285.1455 +      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
285.1456 +	       elt->msgno,elt->private.special.offset,
285.1457 +	       elt->private.special.text.size,(char *) LOCAL->buf);
285.1458 +      fatal (LOCAL->buf+50);
285.1459 +    }
285.1460 +				/* print new flag string */
285.1461 +    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
285.1462 +	     (((elt->deleted && flags) ?
285.1463 +	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
285.1464 +	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
285.1465 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
285.1466 +	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
285.1467 +    while (T) {			/* get to that place in the file */
285.1468 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
285.1469 +	     elt->private.special.text.size - 23,L_SET);
285.1470 +				/* write new flags and UID */
285.1471 +      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
285.1472 +      mm_notify (stream,strerror (errno),WARN);
285.1473 +      mm_diskerror (stream,errno,T);
285.1474 +    }
285.1475 +  }
285.1476 +}
285.1477 +
285.1478 +/* MBX locate header for a message
285.1479 + * Accepts: MAIL stream
285.1480 + *	    message number
285.1481 + *	    pointer to returned header size
285.1482 + *	    pointer to possible returned header
285.1483 + * Returns: position of header in file
285.1484 + */
285.1485 +
285.1486 +#define HDRBUFLEN 16384		/* good enough for most headers */
285.1487 +#define SLOP 4			/* CR LF CR LF */
285.1488 +
285.1489 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
285.1490 +			  unsigned long *size,char **hdr)
285.1491 +{
285.1492 +  unsigned long siz,done;
285.1493 +  long i;
285.1494 +  unsigned char *s,*t,*te;
285.1495 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
285.1496 +  unsigned long ret = elt->private.special.offset +
285.1497 +    elt->private.special.text.size;
285.1498 +  if (hdr) *hdr = NIL;		/* assume no header returned */
285.1499 +				/* is header size known? */ 
285.1500 +  if (*size = elt->private.msg.header.text.size) return ret;
285.1501 +				/* paranoia check */
285.1502 +  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
285.1503 +    fatal ("LOCAL->buf smaller than HDRBUFLEN");
285.1504 +  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
285.1505 +				/* read HDRBUFLEN chunks with 4 byte slop */
285.1506 +  for (done = siz = 0, s = LOCAL->buf;
285.1507 +       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
285.1508 +       (read (LOCAL->fd,s,i) == i);
285.1509 +       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
285.1510 +    te = (t = s + i) - 12;	/* calculate end of fast scan */
285.1511 +				/* fast scan for CR */
285.1512 +    for (s = LOCAL->buf; s < te;)
285.1513 +      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
285.1514 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
285.1515 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
285.1516 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
285.1517 +	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
285.1518 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
285.1519 +	if (hdr) *hdr = LOCAL->buf;
285.1520 +	return ret;
285.1521 +      }
285.1522 +    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
285.1523 +      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
285.1524 +	  (*++s == '\012')) {
285.1525 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
285.1526 +	if (hdr) *hdr = LOCAL->buf;
285.1527 +	return ret;
285.1528 +      }
285.1529 +    if (i <= SLOP) break;	/* end of data */
285.1530 +				/* slide over last 4 bytes */
285.1531 +    memmove (LOCAL->buf,t - SLOP,SLOP);
285.1532 +    hdr = NIL;			/* can't return header this way */
285.1533 +  }
285.1534 +				/* not found: header consumes entire message */
285.1535 +  elt->private.msg.header.text.size = *size = elt->rfc822_size;
285.1536 +  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
285.1537 +  return ret;
285.1538 +}
285.1539 +
285.1540 +/* MBX mail rewrite mailbox
285.1541 + * Accepts: MAIL stream
285.1542 + *	    pointer to return reclaimed size
285.1543 + *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
285.1544 + * Returns: number of expunged messages
285.1545 + */
285.1546 +
285.1547 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
285.1548 +			   long flags)
285.1549 +{
285.1550 +  struct utimbuf times;
285.1551 +  struct stat sbuf;
285.1552 +  off_t pos,ppos;
285.1553 +  int ld;
285.1554 +  unsigned long i,j,k,m,delta;
285.1555 +  unsigned long n = *reclaimed = 0;
285.1556 +  unsigned long recent = 0;
285.1557 +  char lock[MAILTMPLEN];
285.1558 +  MESSAGECACHE *elt;
285.1559 +				/* get parse/append permission */
285.1560 +  if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) {
285.1561 +    mm_log ("Unable to lock expunge mailbox",ERROR);
285.1562 +    return 0;
285.1563 +  }
285.1564 +  fstat (LOCAL->fd,&sbuf);	/* get current write time */
285.1565 +  if (LOCAL->filetime && !LOCAL->flagcheck &&
285.1566 +      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
285.1567 +  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
285.1568 +    unlockfd (ld,lock);		/* failed?? */
285.1569 +    return 0;
285.1570 +  }
285.1571 +  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
285.1572 +    LOCAL->filetime = sbuf.st_mtime;
285.1573 +    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
285.1574 +    LOCAL->flagcheck = NIL;
285.1575 +  }
285.1576 +
285.1577 +				/* get exclusive access */
285.1578 +  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
285.1579 +    mm_critical (stream);	/* go critical */
285.1580 +    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
285.1581 +				/* note if message not at predicted location */
285.1582 +      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
285.1583 +	ppos = elt->private.special.offset;
285.1584 +	*reclaimed += m;	/* note reclaimed message space */
285.1585 +	delta += m;		/* and as expunge delta  */
285.1586 +      }
285.1587 +				/* number of bytes to smash or preserve */
285.1588 +      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
285.1589 +				/* if need to expunge this message*/
285.1590 +      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
285.1591 +	delta += k;		/* number of bytes to delete */
285.1592 +	mail_expunged(stream,i);/* notify upper levels */
285.1593 +	n++;			/* count up one more expunged message */
285.1594 +      }
285.1595 +      else {			/* preserved message */
285.1596 +	i++;			/* count this message */
285.1597 +	if (elt->recent) ++recent;
285.1598 +	if (delta) {		/* moved, note first byte to preserve */
285.1599 +	  j = elt->private.special.offset;
285.1600 +	  do {			/* read from source position */
285.1601 +	    m = min (k,LOCAL->buflen);
285.1602 +	    lseek (LOCAL->fd,j,L_SET);
285.1603 +	    read (LOCAL->fd,LOCAL->buf,m);
285.1604 +	    pos = j - delta;	/* write to destination position */
285.1605 +	    while (T) {
285.1606 +	      lseek (LOCAL->fd,pos,L_SET);
285.1607 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
285.1608 +	      mm_notify (stream,strerror (errno),WARN);
285.1609 +	      mm_diskerror (stream,errno,T);
285.1610 +	    }
285.1611 +	    pos += m;		/* new position */
285.1612 +	    j += m;		/* next chunk, perhaps */
285.1613 +	  } while (k -= m);	/* until done */
285.1614 +				/* note the new address of this text */
285.1615 +	  elt->private.special.offset -= delta;
285.1616 +	}
285.1617 +				/* preserved but no deleted messages yet */
285.1618 +	else pos = elt->private.special.offset + k;
285.1619 +      }
285.1620 +    }
285.1621 +				/* deltaed file size match position? */
285.1622 +    if (m = (LOCAL->filesize -= delta) - pos) {
285.1623 +      *reclaimed += m;		/* probably an fEXPUNGED msg */
285.1624 +      LOCAL->filesize = pos;	/* set correct size */
285.1625 +    }
285.1626 +				/* truncate file after last message */
285.1627 +    ftruncate (LOCAL->fd,LOCAL->filesize);
285.1628 +    fsync (LOCAL->fd);		/* force disk update */
285.1629 +    mm_nocritical (stream);	/* release critical */
285.1630 +    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
285.1631 +  }
285.1632 +
285.1633 +  else {			/* can't get exclusive */
285.1634 +    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
285.1635 +				/* do hide-expunge when shared */
285.1636 +    if (flags) for (i = 1; i <= stream->nmsgs; ) {
285.1637 +      if (elt = mbx_elt (stream,i,T)) {
285.1638 +				/* make the message invisible */
285.1639 +	if (elt->deleted && ((flags > 0) || elt->sequence)) {
285.1640 +	  mbx_update_status (stream,elt->msgno,LONGT);
285.1641 +				/* notify upper levels */
285.1642 +	  mail_expunged (stream,i);
285.1643 +	  n++;			/* count up one more expunged message */
285.1644 +	}
285.1645 +	else {
285.1646 +	  i++;			/* preserved message */
285.1647 +	  if (elt->recent) ++recent;
285.1648 +	}
285.1649 +      }
285.1650 +      else n++;			/* count up one more expunged message */
285.1651 +    }
285.1652 +    fsync (LOCAL->fd);		/* force disk update */
285.1653 +  }
285.1654 +  fstat (LOCAL->fd,&sbuf);	/* get new write time */
285.1655 +  times.modtime = LOCAL->filetime = sbuf.st_mtime;
285.1656 +  times.actime = time (0);	/* reset atime to now */
285.1657 +  utime (stream->mailbox,&times);
285.1658 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
285.1659 +				/* notify upper level of new mailbox size */
285.1660 +  mail_exists (stream,stream->nmsgs);
285.1661 +  mail_recent (stream,recent);
285.1662 +  return n;			/* return number of expunged messages */
285.1663 +}
285.1664 +
285.1665 +/* MBX mail lock for flag updating
285.1666 + * Accepts: stream
285.1667 + * Returns: T if successful, NIL if failure
285.1668 + */
285.1669 +
285.1670 +long mbx_flaglock (MAILSTREAM *stream)
285.1671 +{
285.1672 +  struct stat sbuf;
285.1673 +  unsigned long i;
285.1674 +  int ld;
285.1675 +  char lock[MAILTMPLEN];
285.1676 +				/* no-op if readonly or already locked */
285.1677 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
285.1678 +				/* lock now */
285.1679 +    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL;
285.1680 +    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
285.1681 +      if (LOCAL->filetime) {	/* know previous time? */
285.1682 +	fstat (LOCAL->fd,&sbuf);/* get current write time */
285.1683 +	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
285.1684 +	LOCAL->filetime = 0;	/* don't do this test for any other messages */
285.1685 +      }
285.1686 +      if (!mbx_parse (stream)) {/* parse mailbox */
285.1687 +	unlockfd (ld,lock);	/* shouldn't happen */
285.1688 +	return NIL;
285.1689 +      }
285.1690 +      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
285.1691 +	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
285.1692 +    }
285.1693 +    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
285.1694 +    memcpy (LOCAL->lock,lock,MAILTMPLEN);
285.1695 +  }
285.1696 +  return LONGT;
285.1697 +}
   286.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   286.2 +++ b/src/osdep/nt/mkautaux.bat	Mon Sep 14 15:17:45 2009 +0900
   286.3 @@ -0,0 +1,31 @@
   286.4 +@ECHO OFF
   286.5 +REM ========================================================================
   286.6 +REM Copyright 1988-2006 University of Washington
   286.7 +REM
   286.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   286.9 +REM you may not use this file except in compliance with the License.
  286.10 +REM You may obtain a copy of the License at
  286.11 +REM
  286.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  286.13 +REM
  286.14 +REM 
  286.15 +REM ========================================================================
  286.16 +
  286.17 +REM Program:	Authenticator Linkage Generator auxillary for NT/Win9x
  286.18 +REM
  286.19 +REM Author:	Mark Crispin
  286.20 +REM		Networks and Distributed Computing
  286.21 +REM		Computing & Communications
  286.22 +REM		University of Washington
  286.23 +REM		Administration Building, AG-44
  286.24 +REM		Seattle, WA  98195
  286.25 +REM		Internet: MRC@CAC.Washington.EDU
  286.26 +REM
  286.27 +REM Date:	6 December 1995
  286.28 +REM Last Edited:30 August 2006
  286.29 +
  286.30 +ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
  286.31 +REM Note the introduction of the caret to quote the ampersand in NT
  286.32 +if "%OS%" == "Windows_NT" ECHO   auth_link (^&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
  286.33 +if "%OS%" == "" ECHO   auth_link (&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
  286.34 +ECHO #include "auth_%1.c" >> AUTHS.C
   287.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   287.2 +++ b/src/osdep/nt/mkauths.bat	Mon Sep 14 15:17:45 2009 +0900
   287.3 @@ -0,0 +1,33 @@
   287.4 +@ECHO OFF
   287.5 +REM ========================================================================
   287.6 +REM Copyright 1988-2006 University of Washington
   287.7 +REM
   287.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   287.9 +REM you may not use this file except in compliance with the License.
  287.10 +REM You may obtain a copy of the License at
  287.11 +REM
  287.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  287.13 +REM
  287.14 +REM 
  287.15 +REM ========================================================================
  287.16 +
  287.17 +REM Program:	Authenticator Linkage Generator for DOS and Windows
  287.18 +REM
  287.19 +REM Author:	Mark Crispin
  287.20 +REM		Networks and Distributed Computing
  287.21 +REM		Computing & Communications
  287.22 +REM		University of Washington
  287.23 +REM		Administration Building, AG-44
  287.24 +REM		Seattle, WA  98195
  287.25 +REM		Internet: MRC@CAC.Washington.EDU
  287.26 +REM
  287.27 +REM Date:	6 December 1995
  287.28 +REM Last Edited:30 August 2006
  287.29 +
  287.30 +REM Erase old authenticators list
  287.31 +IF EXIST AUTHS.C DEL AUTHS.C
  287.32 +
  287.33 +REM Now define the new list
  287.34 +FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
  287.35 +
  287.36 +EXIT 0
   288.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   288.2 +++ b/src/osdep/nt/mtxnt.c	Mon Sep 14 15:17:45 2009 +0900
   288.3 @@ -0,0 +1,1232 @@
   288.4 +/* ========================================================================
   288.5 + * Copyright 1988-2007 University of Washington
   288.6 + *
   288.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   288.8 + * you may not use this file except in compliance with the License.
   288.9 + * You may obtain a copy of the License at
  288.10 + *
  288.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  288.12 + *
  288.13 + * 
  288.14 + * ========================================================================
  288.15 + */
  288.16 +
  288.17 +/*
  288.18 + * Program:	MTX mail routines
  288.19 + *
  288.20 + * Author:	Mark Crispin
  288.21 + *		Networks and Distributed Computing
  288.22 + *		Computing & Communications
  288.23 + *		University of Washington
  288.24 + *		Administration Building, AG-44
  288.25 + *		Seattle, WA  98195
  288.26 + *		Internet: MRC@CAC.Washington.EDU
  288.27 + *
  288.28 + * Date:	22 May 1990
  288.29 + * Last Edited:	15 June 2007
  288.30 + */
  288.31 +
  288.32 +
  288.33 +/*				FILE TIME SEMANTICS
  288.34 + *
  288.35 + * The atime is the last read time of the file.
  288.36 + * The mtime is the last flags update time of the file.
  288.37 + * The ctime is the last write time of the file.
  288.38 + */
  288.39 +
  288.40 +#include <stdio.h>
  288.41 +#include <ctype.h>
  288.42 +#include <errno.h>
  288.43 +extern int errno;		/* just in case */
  288.44 +#include "mail.h"
  288.45 +#include "osdep.h"
  288.46 +#include <fcntl.h>
  288.47 +#include <time.h>
  288.48 +#include <sys/stat.h>
  288.49 +#include <sys/utime.h>
  288.50 +#include "misc.h"
  288.51 +#include "dummy.h"
  288.52 +#include "fdstring.h"
  288.53 +
  288.54 +/* MTX I/O stream local data */
  288.55 +	
  288.56 +typedef struct mtx_local {
  288.57 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  288.58 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  288.59 +  int fd;			/* file descriptor for I/O */
  288.60 +  off_t filesize;		/* file size parsed */
  288.61 +  time_t filetime;		/* last file time */
  288.62 +  time_t lastsnarf;		/* last snarf time */
  288.63 +  unsigned char *buf;		/* temporary buffer */
  288.64 +  unsigned long buflen;		/* current size of temporary buffer */
  288.65 +} MTXLOCAL;
  288.66 +
  288.67 +
  288.68 +/* Convenient access to local data */
  288.69 +
  288.70 +#define LOCAL ((MTXLOCAL *) stream->local)
  288.71 +
  288.72 +
  288.73 +/* Function prototypes */
  288.74 +
  288.75 +DRIVER *mtx_valid (char *name);
  288.76 +int mtx_isvalid (char *name,char *file);
  288.77 +void *mtx_parameters (long function,void *value);
  288.78 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  288.79 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
  288.80 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  288.81 +long mtx_create (MAILSTREAM *stream,char *mailbox);
  288.82 +long mtx_delete (MAILSTREAM *stream,char *mailbox);
  288.83 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
  288.84 +long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
  288.85 +MAILSTREAM *mtx_open (MAILSTREAM *stream);
  288.86 +void mtx_close (MAILSTREAM *stream,long options);
  288.87 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
  288.88 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
  288.89 +		  unsigned long *length,long flags);
  288.90 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  288.91 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  288.92 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  288.93 +long mtx_ping (MAILSTREAM *stream);
  288.94 +void mtx_check (MAILSTREAM *stream);
  288.95 +void mtx_snarf (MAILSTREAM *stream);
  288.96 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
  288.97 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  288.98 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  288.99 +
 288.100 +long mtx_parse (MAILSTREAM *stream);
 288.101 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
 288.102 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 288.103 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
 288.104 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 288.105 +			  unsigned long *size);
 288.106 +
 288.107 +
 288.108 +/* MTX mail routines */
 288.109 +
 288.110 +
 288.111 +/* Driver dispatch used by MAIL */
 288.112 +
 288.113 +DRIVER mtxdriver = {
 288.114 +  "mtx",			/* driver name */
 288.115 +				/* driver flags */
 288.116 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY,
 288.117 +  (DRIVER *) NIL,		/* next driver */
 288.118 +  mtx_valid,			/* mailbox is valid for us */
 288.119 +  mtx_parameters,		/* manipulate parameters */
 288.120 +  mtx_scan,			/* scan mailboxes */
 288.121 +  mtx_list,			/* list mailboxes */
 288.122 +  mtx_lsub,			/* list subscribed mailboxes */
 288.123 +  NIL,				/* subscribe to mailbox */
 288.124 +  NIL,				/* unsubscribe from mailbox */
 288.125 +  mtx_create,			/* create mailbox */
 288.126 +  mtx_delete,			/* delete mailbox */
 288.127 +  mtx_rename,			/* rename mailbox */
 288.128 +  mail_status_default,		/* status of mailbox */
 288.129 +  mtx_open,			/* open mailbox */
 288.130 +  mtx_close,			/* close mailbox */
 288.131 +  mtx_flags,			/* fetch message "fast" attributes */
 288.132 +  mtx_flags,			/* fetch message flags */
 288.133 +  NIL,				/* fetch overview */
 288.134 +  NIL,				/* fetch message envelopes */
 288.135 +  mtx_header,			/* fetch message header */
 288.136 +  mtx_text,			/* fetch message body */
 288.137 +  NIL,				/* fetch partial message text */
 288.138 +  NIL,				/* unique identifier */
 288.139 +  NIL,				/* message number */
 288.140 +  mtx_flag,			/* modify flags */
 288.141 +  mtx_flagmsg,			/* per-message modify flags */
 288.142 +  NIL,				/* search for message based on criteria */
 288.143 +  NIL,				/* sort messages */
 288.144 +  NIL,				/* thread messages */
 288.145 +  mtx_ping,			/* ping mailbox to see if still alive */
 288.146 +  mtx_check,			/* check for new messages */
 288.147 +  mtx_expunge,			/* expunge deleted messages */
 288.148 +  mtx_copy,			/* copy messages to another mailbox */
 288.149 +  mtx_append,			/* append string message to mailbox */
 288.150 +  NIL				/* garbage collect stream */
 288.151 +};
 288.152 +
 288.153 +				/* prototype stream */
 288.154 +MAILSTREAM mtxproto = {&mtxdriver};
 288.155 +
 288.156 +/* MTX mail validate mailbox
 288.157 + * Accepts: mailbox name
 288.158 + * Returns: our driver if name is valid, NIL otherwise
 288.159 + */
 288.160 +
 288.161 +DRIVER *mtx_valid (char *name)
 288.162 +{
 288.163 +  char tmp[MAILTMPLEN];
 288.164 +  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
 288.165 +}
 288.166 +
 288.167 +
 288.168 +/* MTX mail test for valid mailbox
 288.169 + * Accepts: mailbox name
 288.170 + *	    buffer to return file name
 288.171 + * Returns: T if valid, NIL otherwise
 288.172 + */
 288.173 +
 288.174 +int mtx_isvalid (char *name,char *file)
 288.175 +{
 288.176 +  int fd;
 288.177 +  int ret = NIL;
 288.178 +  char *s,tmp[MAILTMPLEN];
 288.179 +  struct stat sbuf;
 288.180 +  struct utimbuf times;
 288.181 +  errno = EINVAL;		/* assume invalid argument */
 288.182 +				/* if file, get its status */
 288.183 +  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
 288.184 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
 288.185 +    if (!sbuf.st_size)errno = 0;/* empty file */
 288.186 +    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
 288.187 +      memset (tmp,'\0',MAILTMPLEN);
 288.188 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
 288.189 +	  (s[1] == '\012')) {	/* valid format? */
 288.190 +	*s = '\0';		/* tie off header */
 288.191 +				/* must begin with dd-mmm-yy" */
 288.192 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 288.193 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 288.194 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 288.195 +      }
 288.196 +      else errno = -1;		/* bogus format */
 288.197 +      close (fd);		/* close the file */
 288.198 +				/* \Marked status? */
 288.199 +      if (sbuf.st_ctime > sbuf.st_atime) {
 288.200 +				/* preserve atime and mtime */
 288.201 +	times.actime = sbuf.st_atime;
 288.202 +	times.modtime = sbuf.st_mtime;
 288.203 +	utime (file,&times);	/* set the times */
 288.204 +      }
 288.205 +    }
 288.206 +  }
 288.207 +				/* in case INBOX but not mtx format */
 288.208 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 288.209 +  return ret;			/* return what we should */
 288.210 +}
 288.211 +
 288.212 +
 288.213 +/* MTX manipulate driver parameters
 288.214 + * Accepts: function code
 288.215 + *	    function-dependent value
 288.216 + * Returns: function-dependent return value
 288.217 + */
 288.218 +
 288.219 +void *mtx_parameters (long function,void *value)
 288.220 +{
 288.221 +  return NIL;
 288.222 +}
 288.223 +
 288.224 +/* MTX mail scan mailboxes
 288.225 + * Accepts: mail stream
 288.226 + *	    reference
 288.227 + *	    pattern to search
 288.228 + *	    string to scan
 288.229 + */
 288.230 +
 288.231 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 288.232 +{
 288.233 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 288.234 +}
 288.235 +
 288.236 +
 288.237 +/* MTX mail list mailboxes
 288.238 + * Accepts: mail stream
 288.239 + *	    reference
 288.240 + *	    pattern to search
 288.241 + */
 288.242 +
 288.243 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
 288.244 +{
 288.245 +  if (stream) dummy_list (NIL,ref,pat);
 288.246 +}
 288.247 +
 288.248 +
 288.249 +/* MTX mail list subscribed mailboxes
 288.250 + * Accepts: mail stream
 288.251 + *	    reference
 288.252 + *	    pattern to search
 288.253 + */
 288.254 +
 288.255 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 288.256 +{
 288.257 +  if (stream) dummy_lsub (NIL,ref,pat);
 288.258 +}
 288.259 +
 288.260 +/* MTX mail create mailbox
 288.261 + * Accepts: MAIL stream
 288.262 + *	    mailbox name to create
 288.263 + * Returns: T on success, NIL on failure
 288.264 + */
 288.265 +
 288.266 +long mtx_create (MAILSTREAM *stream,char *mailbox)
 288.267 +{
 288.268 +  char *s,mbx[MAILTMPLEN];
 288.269 +  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
 288.270 +  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 288.271 +  mm_log (mbx,ERROR);
 288.272 +  return NIL;
 288.273 +}
 288.274 +
 288.275 +
 288.276 +/* MTX mail delete mailbox
 288.277 + * Accepts: MAIL stream
 288.278 + *	    mailbox name to delete
 288.279 + * Returns: T on success, NIL on failure
 288.280 + */
 288.281 +
 288.282 +long mtx_delete (MAILSTREAM *stream,char *mailbox)
 288.283 +{
 288.284 +  return mtx_rename (stream,mailbox,NIL);
 288.285 +}
 288.286 +
 288.287 +/* MTX mail rename mailbox
 288.288 + * Accepts: MAIL stream
 288.289 + *	    old mailbox name
 288.290 + *	    new mailbox name (or NIL for delete)
 288.291 + * Returns: T on success, NIL on failure
 288.292 + */
 288.293 +
 288.294 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
 288.295 +{
 288.296 +  long ret = LONGT;
 288.297 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 288.298 +  int fd,ld;
 288.299 +  struct stat sbuf;
 288.300 +  if (!dummy_file (file,old) ||
 288.301 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 288.302 +		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
 288.303 +    sprintf (tmp,newname ?
 288.304 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 288.305 +	     "Can't delete mailbox %.80s: invalid name",
 288.306 +	     old,newname);
 288.307 +    mm_log (tmp,ERROR);
 288.308 +    return NIL;
 288.309 +  }
 288.310 +  if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
 288.311 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 288.312 +    mm_log (tmp,ERROR);
 288.313 +    return NIL;
 288.314 +  }
 288.315 +				/* get exclusive parse/append permission */
 288.316 +  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
 288.317 +    mm_log ("Unable to lock rename mailbox",ERROR);
 288.318 +    return NIL;
 288.319 +  }
 288.320 +				/* lock out other users */
 288.321 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 288.322 +    close (fd);			/* couldn't lock, give up on it then */
 288.323 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 288.324 +    mm_log (tmp,ERROR);
 288.325 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 288.326 +    return NIL;
 288.327 +  }
 288.328 +
 288.329 +  if (newname) {		/* want rename? */
 288.330 +				/* found superior to destination name? */
 288.331 +    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 288.332 +	((tmp[1] != ':') || (s != tmp + 2))) {
 288.333 +      c = s[1];			/* remember character after delimiter */
 288.334 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 288.335 +				/* name doesn't exist, create it */
 288.336 +      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 288.337 +	*s = '\\';		/* restore delimiter */
 288.338 +	if (!dummy_create (stream,tmp)) ret = NIL;
 288.339 +      }
 288.340 +      else *s = '\\';		/* restore delimiter */
 288.341 +      s[1] = c;			/* restore character after delimiter */
 288.342 +    }
 288.343 +    flock (fd,LOCK_UN);		/* release lock on the file */
 288.344 +    close (fd);			/* pacify NTFS */
 288.345 +				/* rename the file */
 288.346 +    if (ret && rename (file,tmp)) {
 288.347 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 288.348 +	       strerror (errno));
 288.349 +      mm_log (tmp,ERROR);
 288.350 +      ret = NIL;		/* set failure */
 288.351 +    }
 288.352 +  }
 288.353 +  else {
 288.354 +    flock (fd,LOCK_UN);		/* release lock on the file */
 288.355 +    close (fd);			/* pacify NTFS */
 288.356 +    if (unlink (file)) {
 288.357 +      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
 288.358 +      mm_log (tmp,ERROR);
 288.359 +      ret = NIL;		/* set failure */
 288.360 +    }
 288.361 +  }
 288.362 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 288.363 +  return ret;			/* return success */
 288.364 +}
 288.365 +
 288.366 +/* MTX mail open
 288.367 + * Accepts: stream to open
 288.368 + * Returns: stream on success, NIL on failure
 288.369 + */
 288.370 +
 288.371 +MAILSTREAM *mtx_open (MAILSTREAM *stream)
 288.372 +{
 288.373 +  int fd,ld;
 288.374 +  char tmp[MAILTMPLEN];
 288.375 +				/* return prototype for OP_PROTOTYPE call */
 288.376 +  if (!stream) return &mtxproto;
 288.377 +  if (stream->local) fatal ("mtx recycle stream");
 288.378 +				/* canonicalize the mailbox name */
 288.379 +  if (!dummy_file (tmp,stream->mailbox)) {
 288.380 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 288.381 +    mm_log (tmp,ERROR);
 288.382 +  }
 288.383 +  if (stream->rdonly ||
 288.384 +      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
 288.385 +    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
 288.386 +      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
 288.387 +      mm_log (tmp,ERROR);
 288.388 +      return NIL;
 288.389 +    }
 288.390 +    else if (!stream->rdonly) {	/* got it, but readonly */
 288.391 +      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 288.392 +      stream->rdonly = T;
 288.393 +    }
 288.394 +  }
 288.395 +  stream->local = fs_get (sizeof (MTXLOCAL));
 288.396 +  LOCAL->fd = fd;		/* bind the file */
 288.397 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 288.398 +  LOCAL->buflen = CHUNKSIZE - 1;
 288.399 +				/* note if an INBOX or not */
 288.400 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 288.401 +  fs_give ((void **) &stream->mailbox);
 288.402 +  stream->mailbox = cpystr (tmp);
 288.403 +				/* get shared parse permission */
 288.404 +  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
 288.405 +    mm_log ("Unable to lock open mailbox",ERROR);
 288.406 +    return NIL;
 288.407 +  }
 288.408 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 288.409 +  unlockfd (ld,tmp);		/* release shared parse permission */
 288.410 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 288.411 +  LOCAL->filetime = 0;		/* time not set up yet */
 288.412 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 288.413 +  stream->sequence++;		/* bump sequence number */
 288.414 +  stream->uid_validity = (unsigned long) time (0);
 288.415 +				/* parse mailbox */
 288.416 +  stream->nmsgs = stream->recent = 0;
 288.417 +  if (mtx_ping (stream) && !stream->nmsgs)
 288.418 +    mm_log ("Mailbox is empty",(long) NIL);
 288.419 +  if (!LOCAL) return NIL;	/* failure if stream died */
 288.420 +  stream->perm_seen = stream->perm_deleted =
 288.421 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 288.422 +      stream->rdonly ? NIL : T;
 288.423 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 288.424 +  return stream;		/* return stream to caller */
 288.425 +}
 288.426 +
 288.427 +/* MTX mail close
 288.428 + * Accepts: MAIL stream
 288.429 + *	    close options
 288.430 + */
 288.431 +
 288.432 +void mtx_close (MAILSTREAM *stream,long options)
 288.433 +{
 288.434 +  if (stream && LOCAL) {	/* only if a file is open */
 288.435 +    int silent = stream->silent;
 288.436 +    stream->silent = T;		/* note this stream is dying */
 288.437 +    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
 288.438 +    stream->silent = silent;	/* restore previous status */
 288.439 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 288.440 +    close (LOCAL->fd);		/* close the local file */
 288.441 +				/* free local text buffer */
 288.442 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 288.443 +				/* nuke the local data */
 288.444 +    fs_give ((void **) &stream->local);
 288.445 +    stream->dtb = NIL;		/* log out the DTB */
 288.446 +  }
 288.447 +}
 288.448 +
 288.449 +
 288.450 +/* MTX mail fetch flags
 288.451 + * Accepts: MAIL stream
 288.452 + *	    sequence
 288.453 + *	    option flags
 288.454 + * Sniffs at file to see if some other process changed the flags
 288.455 + */
 288.456 +
 288.457 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
 288.458 +{
 288.459 +  unsigned long i;
 288.460 +  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
 288.461 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 288.462 +       mail_sequence (stream,sequence)))
 288.463 +    for (i = 1; i <= stream->nmsgs; i++) 
 288.464 +      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
 288.465 +}
 288.466 +
 288.467 +/* MTX mail fetch message header
 288.468 + * Accepts: MAIL stream
 288.469 + *	    message # to fetch
 288.470 + *	    pointer to returned header text length
 288.471 + *	    option flags
 288.472 + * Returns: message header in RFC822 format
 288.473 + */
 288.474 +
 288.475 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 288.476 +		  long flags)
 288.477 +{
 288.478 +  *length = 0;			/* default to empty */
 288.479 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 288.480 +				/* get to header position */
 288.481 +  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
 288.482 +				/* is buffer big enough? */
 288.483 +  if (*length > LOCAL->buflen) {
 288.484 +    fs_give ((void **) &LOCAL->buf);
 288.485 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 288.486 +  }
 288.487 +  LOCAL->buf[*length] = '\0';	/* tie off string */
 288.488 +				/* slurp the data */
 288.489 +  read (LOCAL->fd,LOCAL->buf,*length);
 288.490 +  return LOCAL->buf;
 288.491 +}
 288.492 +
 288.493 +/* MTX mail fetch message text (body only)
 288.494 + * Accepts: MAIL stream
 288.495 + *	    message # to fetch
 288.496 + *	    pointer to returned header text length
 288.497 + *	    option flags
 288.498 + * Returns: T, always
 288.499 + */
 288.500 +
 288.501 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 288.502 +{
 288.503 +  FDDATA d;
 288.504 +  unsigned long i,j;
 288.505 +  MESSAGECACHE *elt;
 288.506 +				/* UID call "impossible" */
 288.507 +  if (flags & FT_UID) return NIL;
 288.508 +  elt = mtx_elt (stream,msgno);	/* get message status */
 288.509 +				/* if message not seen */
 288.510 +  if (!(flags & FT_PEEK) && !elt->seen) {
 288.511 +    elt->seen = T;		/* mark message as seen */
 288.512 +				/* recalculate status */
 288.513 +    mtx_update_status (stream,msgno,NIL);
 288.514 +    mm_flags (stream,msgno);
 288.515 +  }
 288.516 +				/* find header position */
 288.517 +  i = mtx_hdrpos (stream,msgno,&j);
 288.518 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 288.519 +  d.pos = i + j;
 288.520 +  d.chunk = LOCAL->buf;	/* initial buffer chunk */
 288.521 +  d.chunksize = CHUNKSIZE;
 288.522 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 288.523 +  return T;			/* success */
 288.524 +}
 288.525 +
 288.526 +/* MTX mail modify flags
 288.527 + * Accepts: MAIL stream
 288.528 + *	    sequence
 288.529 + *	    flag(s)
 288.530 + *	    option flags
 288.531 + */
 288.532 +
 288.533 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 288.534 +{
 288.535 +  struct utimbuf times;
 288.536 +  struct stat sbuf;
 288.537 +  if (!stream->rdonly) {	/* make sure the update takes */
 288.538 +    fsync (LOCAL->fd);
 288.539 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 288.540 +    times.modtime = LOCAL->filetime = sbuf.st_mtime;
 288.541 +    times.actime = time (0);	/* make sure read comes after all that */
 288.542 +    utime (stream->mailbox,&times);
 288.543 +  }
 288.544 +}
 288.545 +
 288.546 +
 288.547 +/* MTX mail per-message modify flags
 288.548 + * Accepts: MAIL stream
 288.549 + *	    message cache element
 288.550 + */
 288.551 +
 288.552 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 288.553 +{
 288.554 +  struct stat sbuf;
 288.555 +				/* maybe need to do a checkpoint? */
 288.556 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 288.557 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 288.558 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 288.559 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 288.560 +  }
 288.561 +				/* recalculate status */
 288.562 +  mtx_update_status (stream,elt->msgno,NIL);
 288.563 +}
 288.564 +
 288.565 +/* MTX mail ping mailbox
 288.566 + * Accepts: MAIL stream
 288.567 + * Returns: T if stream still alive, NIL if not
 288.568 + */
 288.569 +
 288.570 +long mtx_ping (MAILSTREAM *stream)
 288.571 +{
 288.572 +  unsigned long i = 1;
 288.573 +  long r = T;
 288.574 +  int ld;
 288.575 +  char lock[MAILTMPLEN];
 288.576 +  struct stat sbuf;
 288.577 +  if (stream && LOCAL) {	/* only if stream already open */
 288.578 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 288.579 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 288.580 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 288.581 +				/* check for changed message status */
 288.582 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 288.583 +      LOCAL->filetime = sbuf.st_mtime;
 288.584 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 288.585 +	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
 288.586 +      while (i <= stream->nmsgs) mtx_elt (stream,i++);
 288.587 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 288.588 +    }
 288.589 +				/* get shared parse/append permission */
 288.590 +    if ((sbuf.st_size != LOCAL->filesize) &&
 288.591 +	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
 288.592 +				/* parse resulting mailbox */
 288.593 +      r = (mtx_parse (stream)) ? T : NIL;
 288.594 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 288.595 +    }
 288.596 +  }
 288.597 +  return r;			/* return result of the parse */
 288.598 +}
 288.599 +
 288.600 +
 288.601 +/* MTX mail check mailbox (reparses status too)
 288.602 + * Accepts: MAIL stream
 288.603 + */
 288.604 +
 288.605 +void mtx_check (MAILSTREAM *stream)
 288.606 +{
 288.607 +				/* mark that a check is desired */
 288.608 +  if (LOCAL) LOCAL->mustcheck = T;
 288.609 +  if (mtx_ping (stream)) mm_log ("Check completed",(long) NIL);
 288.610 +}
 288.611 +
 288.612 +/* MTX mail expunge mailbox
 288.613 + *	    sequence to expunge if non-NIL
 288.614 + *	    expunge options
 288.615 + * Returns: T, always
 288.616 + */
 288.617 +
 288.618 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
 288.619 +{
 288.620 +  long ret;
 288.621 +  struct utimbuf times;
 288.622 +  struct stat sbuf;
 288.623 +  off_t pos = 0;
 288.624 +  int ld;
 288.625 +  unsigned long i = 1;
 288.626 +  unsigned long j,k,m,recent;
 288.627 +  unsigned long n = 0;
 288.628 +  unsigned long delta = 0;
 288.629 +  char lock[MAILTMPLEN];
 288.630 +  MESSAGECACHE *elt;
 288.631 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 288.632 +			   mail_uid_sequence (stream,sequence) :
 288.633 +			   mail_sequence (stream,sequence)) : LONGT) &&
 288.634 +	mtx_ping (stream)));	/* parse sequence if given, ping stream */
 288.635 +  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
 288.636 +  else {
 288.637 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 288.638 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 288.639 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 288.640 +    }
 288.641 +				/* get exclusive parse/append permission */
 288.642 +    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
 288.643 +      mm_log ("Unable to lock expunge mailbox",ERROR);
 288.644 +				/* make sure see any newly-arrived messages */
 288.645 +    else if (!mtx_parse (stream));
 288.646 +				/* get exclusive access */
 288.647 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 288.648 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 288.649 +      mm_log ("Can't expunge because mailbox is in use by another process",
 288.650 +	      ERROR);
 288.651 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 288.652 +    }
 288.653 +
 288.654 +    else {
 288.655 +      mm_critical (stream);	/* go critical */
 288.656 +      recent = stream->recent;	/* get recent now that pinged and locked */
 288.657 +				/* for each message */
 288.658 +      while (i <= stream->nmsgs) {
 288.659 +				/* get cache element */
 288.660 +	elt = mtx_elt (stream,i);
 288.661 +				/* number of bytes to smash or preserve */
 288.662 +	k = elt->private.special.text.size + elt->rfc822_size;
 288.663 +				/* if need to expunge this message */
 288.664 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 288.665 +				/* if recent, note one less recent message */
 288.666 +	  if (elt->recent) --recent;
 288.667 +	  delta += k;		/* number of bytes to delete */
 288.668 +				/* notify upper levels */
 288.669 +	  mail_expunged (stream,i);
 288.670 +	  n++;			/* count up one more expunged message */
 288.671 +	}
 288.672 +	else if (i++ && delta) {/* preserved message */
 288.673 +				/* first byte to preserve */
 288.674 +	  j = elt->private.special.offset;
 288.675 +	  do {			/* read from source position */
 288.676 +	    m = min (k,LOCAL->buflen);
 288.677 +	    lseek (LOCAL->fd,j,L_SET);
 288.678 +	    read (LOCAL->fd,LOCAL->buf,m);
 288.679 +	    pos = j - delta;	/* write to destination position */
 288.680 +	    while (T) {
 288.681 +	      lseek (LOCAL->fd,pos,L_SET);
 288.682 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 288.683 +	      mm_notify (stream,strerror (errno),WARN);
 288.684 +	      mm_diskerror (stream,errno,T);
 288.685 +	    }
 288.686 +	    pos += m;		/* new position */
 288.687 +	    j += m;		/* next chunk, perhaps */
 288.688 +	  } while (k -= m);	/* until done */
 288.689 +				/* note the new address of this text */
 288.690 +	  elt->private.special.offset -= delta;
 288.691 +	}
 288.692 +				/* preserved but no deleted messages */
 288.693 +	else pos = elt->private.special.offset + k;
 288.694 +      }
 288.695 +      if (n) {			/* truncate file after last message */
 288.696 +	if (pos != (LOCAL->filesize -= delta)) {
 288.697 +	  sprintf (LOCAL->buf,
 288.698 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 288.699 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 288.700 +	  mm_log (LOCAL->buf,WARN);
 288.701 +	  LOCAL->filesize = pos;/* fix it then */
 288.702 +	}
 288.703 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 288.704 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 288.705 +				/* output the news */
 288.706 +	mm_log (LOCAL->buf,(long) NIL);
 288.707 +      }
 288.708 +      else mm_log ("No messages deleted, so no update needed",(long) NIL);
 288.709 +      fsync (LOCAL->fd);	/* force disk update */
 288.710 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 288.711 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 288.712 +      times.actime = time (0);	/* reset atime to now */
 288.713 +      utime (stream->mailbox,&times);
 288.714 +      mm_nocritical (stream);	/* release critical */
 288.715 +				/* notify upper level of new mailbox size */
 288.716 +      mail_exists (stream,stream->nmsgs);
 288.717 +      mail_recent (stream,recent);
 288.718 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 288.719 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 288.720 +    }
 288.721 +  }
 288.722 +  return ret;
 288.723 +}
 288.724 +
 288.725 +/* MTX mail copy message(s)
 288.726 + * Accepts: MAIL stream
 288.727 + *	    sequence
 288.728 + *	    destination mailbox
 288.729 + *	    copy options
 288.730 + * Returns: T if success, NIL if failed
 288.731 + */
 288.732 +
 288.733 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 288.734 +{
 288.735 +  struct stat sbuf;
 288.736 +  struct utimbuf times;
 288.737 +  MESSAGECACHE *elt;
 288.738 +  unsigned long i,j,k;
 288.739 +  long ret = LONGT;
 288.740 +  int fd,ld;
 288.741 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 288.742 +  mailproxycopy_t pc =
 288.743 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 288.744 +				/* make sure valid mailbox */
 288.745 +  if (!mtx_isvalid (mailbox,file)) switch (errno) {
 288.746 +  case ENOENT:			/* no such file? */
 288.747 +    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 288.748 +    return NIL;
 288.749 +  case 0:			/* merely empty file? */
 288.750 +    break;
 288.751 +  case EACCES:			/* file protected */
 288.752 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 288.753 +    MM_LOG (LOCAL->buf,ERROR);
 288.754 +    return NIL;
 288.755 +  case EINVAL:
 288.756 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 288.757 +    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
 288.758 +    mm_log (LOCAL->buf,ERROR);
 288.759 +    return NIL;
 288.760 +  default:
 288.761 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 288.762 +    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
 288.763 +    mm_log (LOCAL->buf,ERROR);
 288.764 +    return NIL;
 288.765 +  }
 288.766 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 288.767 +	mail_sequence (stream,sequence))) return NIL;
 288.768 +				/* got file? */
 288.769 +  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
 288.770 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
 288.771 +    mm_log (LOCAL->buf,ERROR);
 288.772 +    return NIL;
 288.773 +  }
 288.774 +  mm_critical (stream);		/* go critical */
 288.775 +				/* get exclusive parse/append permission */
 288.776 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 288.777 +    mm_log ("Unable to lock copy mailbox",ERROR);
 288.778 +    mm_nocritical (stream);
 288.779 +    return NIL;
 288.780 +  }
 288.781 +  fstat (fd,&sbuf);		/* get current file size */
 288.782 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 288.783 +
 288.784 +				/* for each requested message */
 288.785 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 288.786 +    if ((elt = mail_elt (stream,i))->sequence) {
 288.787 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 288.788 +				/* number of bytes to copy */
 288.789 +      k = elt->private.special.text.size + elt->rfc822_size;
 288.790 +      do {			/* read from source position */
 288.791 +	j = min (k,LOCAL->buflen);
 288.792 +	read (LOCAL->fd,LOCAL->buf,j);
 288.793 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 288.794 +      } while (ret && (k -= j));/* until done */
 288.795 +    }
 288.796 +				/* make sure all the updates take */
 288.797 +  if (!(ret && (ret = !fsync (fd)))) {
 288.798 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 288.799 +    mm_log (LOCAL->buf,ERROR);
 288.800 +    ftruncate (fd,sbuf.st_size);
 288.801 +  }
 288.802 +				/* set atime to now-1 if successful copy */
 288.803 +  if (ret) times.actime = time (0) - 1;
 288.804 +				/* else preserved \Marked status */
 288.805 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 288.806 +	 sbuf.st_atime : time (0);
 288.807 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 288.808 +  utime (file,&times);		/* set the times */
 288.809 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 288.810 +  close (fd);			/* close the file */
 288.811 +  mm_nocritical (stream);	/* release critical */
 288.812 +				/* delete all requested messages */
 288.813 +  if (ret && (options & CP_MOVE)) {
 288.814 +    for (i = 1; i <= stream->nmsgs; i++)
 288.815 +      if ((elt = mtx_elt (stream,i))->sequence) {
 288.816 +	elt->deleted = T;	/* mark message deleted */
 288.817 +				/* recalculate status */
 288.818 +	mtx_update_status (stream,i,NIL);
 288.819 +      }
 288.820 +    if (!stream->rdonly) {	/* make sure the update takes */
 288.821 +      fsync (LOCAL->fd);
 288.822 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 288.823 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 288.824 +      times.actime = time (0);	/* make sure atime remains greater */
 288.825 +      utime (stream->mailbox,&times);
 288.826 +    }
 288.827 +  }
 288.828 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 288.829 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
 288.830 +  return ret;
 288.831 +}
 288.832 +
 288.833 +/* MTX mail append message from stringstruct
 288.834 + * Accepts: MAIL stream
 288.835 + *	    destination mailbox
 288.836 + *	    append callback
 288.837 + *	    data for callback
 288.838 + * Returns: T if append successful, else NIL
 288.839 + */
 288.840 +
 288.841 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 288.842 +{
 288.843 +  struct stat sbuf;
 288.844 +  int fd,ld,c;
 288.845 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 288.846 +  struct utimbuf times;
 288.847 +  FILE *df;
 288.848 +  MESSAGECACHE elt;
 288.849 +  long f;
 288.850 +  unsigned long i,uf;
 288.851 +  STRING *message;
 288.852 +  long ret = LONGT;
 288.853 +				/* default stream to prototype */
 288.854 +  if (!stream) stream = &mtxproto;
 288.855 +				/* make sure valid mailbox */
 288.856 +  if (!mtx_isvalid (mailbox,file)) switch (errno) {
 288.857 +  case ENOENT:			/* no such file? */
 288.858 +    if (!compare_cstring (mailbox,"INBOX")) mtx_create (NIL,"INBOX");
 288.859 +    else {
 288.860 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 288.861 +      return NIL;
 288.862 +    }
 288.863 +				/* falls through */
 288.864 +  case 0:			/* merely empty file? */
 288.865 +    break;
 288.866 +  case EACCES:			/* file protected */
 288.867 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 288.868 +    MM_LOG (tmp,ERROR);
 288.869 +    return NIL;
 288.870 +  case EINVAL:
 288.871 +    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
 288.872 +    mm_log (tmp,ERROR);
 288.873 +    return NIL;
 288.874 +  default:
 288.875 +    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
 288.876 +    mm_log (tmp,ERROR);
 288.877 +    return NIL;
 288.878 +  }
 288.879 +				/* get first message */
 288.880 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
 288.881 +
 288.882 +				/* open destination mailbox */
 288.883 +  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
 288.884 +       < 0) || !(df = fdopen (fd,"ab"))) {
 288.885 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
 288.886 +    mm_log (tmp,ERROR);
 288.887 +    return NIL;
 288.888 +  }
 288.889 +				/* get parse/append permission */
 288.890 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 288.891 +    mm_log ("Unable to lock append mailbox",ERROR);
 288.892 +    close (fd);
 288.893 +    return NIL;
 288.894 +  }
 288.895 +  mm_critical (stream);		/* go critical */
 288.896 +  fstat (fd,&sbuf);		/* get current file size */
 288.897 +  errno = 0;
 288.898 +  do {				/* parse flags */
 288.899 +    if (!SIZE (message)) {	/* guard against zero-length */
 288.900 +      mm_log ("Append of zero-length message",ERROR);
 288.901 +      ret = NIL;
 288.902 +      break;
 288.903 +    }
 288.904 +    f = mail_parse_flags (stream,flags,&i);
 288.905 +				/* reverse bits (dontcha wish we had CIRC?) */
 288.906 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
 288.907 +    if (date) {			/* parse date if given */
 288.908 +      if (!mail_parse_date (&elt,date)) {
 288.909 +	sprintf (tmp,"Bad date in append: %.80s",date);
 288.910 +	mm_log (tmp,ERROR);
 288.911 +	ret = NIL;		/* mark failure */
 288.912 +	break;
 288.913 +      }
 288.914 +      mail_date (tmp,&elt);	/* write preseved date */
 288.915 +    }
 288.916 +    else internal_date (tmp);	/* get current date in IMAP format */
 288.917 +				/* write header */
 288.918 +    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
 288.919 +		 (unsigned long) f) < 0) ret = NIL;
 288.920 +    else {			/* write message */
 288.921 +      if (i) do c = 0xff & SNX (message);
 288.922 +      while ((putc (c,df) != EOF) && --i);
 288.923 +				/* get next message */
 288.924 +      if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
 288.925 +    }
 288.926 +  } while (ret && message);
 288.927 +				/* if error... */
 288.928 +  if (!ret || (fflush (df) == EOF)) {
 288.929 +    ftruncate (fd,sbuf.st_size);/* revert file */
 288.930 +    close (fd);			/* make sure fclose() doesn't corrupt us */
 288.931 +    if (errno) {
 288.932 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
 288.933 +      mm_log (tmp,ERROR);
 288.934 +    }
 288.935 +    ret = NIL;
 288.936 +  }
 288.937 +  if (ret) times.actime = time (0) - 1;
 288.938 +				/* else preserved \Marked status */
 288.939 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 288.940 +	 sbuf.st_atime : time (0);
 288.941 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 288.942 +  utime (file,&times);		/* set the times */
 288.943 +  fclose (df);			/* close the file */
 288.944 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 288.945 +  mm_nocritical (stream);	/* release critical */
 288.946 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
 288.947 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
 288.948 +	    WARN);
 288.949 +  return ret;
 288.950 +}
 288.951 +
 288.952 +/* Internal routines */
 288.953 +
 288.954 +
 288.955 +/* MTX mail parse mailbox
 288.956 + * Accepts: MAIL stream
 288.957 + * Returns: T if parse OK
 288.958 + *	    NIL if failure, stream aborted
 288.959 + */
 288.960 +
 288.961 +long mtx_parse (MAILSTREAM *stream)
 288.962 +{
 288.963 +  struct stat sbuf;
 288.964 +  MESSAGECACHE *elt = NIL;
 288.965 +  unsigned char c,*s,*t,*x;
 288.966 +  char tmp[MAILTMPLEN];
 288.967 +  unsigned long i,j;
 288.968 +  long curpos = LOCAL->filesize;
 288.969 +  long nmsgs = stream->nmsgs;
 288.970 +  long recent = stream->recent;
 288.971 +  short added = NIL;
 288.972 +  short silent = stream->silent;
 288.973 +  fstat (LOCAL->fd,&sbuf);	/* get status */
 288.974 +  if (sbuf.st_size < curpos) {	/* sanity check */
 288.975 +    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
 288.976 +    mm_log (tmp,ERROR);
 288.977 +    mtx_close (stream,NIL);
 288.978 +    return NIL;
 288.979 +  }
 288.980 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
 288.981 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
 288.982 +				/* get to that position in the file */
 288.983 +    lseek (LOCAL->fd,curpos,L_SET);
 288.984 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
 288.985 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
 288.986 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
 288.987 +	       i ? strerror (errno) : "no data read");
 288.988 +      mm_log (tmp,ERROR);
 288.989 +      mtx_close (stream,NIL);
 288.990 +      return NIL;
 288.991 +    }
 288.992 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
 288.993 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
 288.994 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
 288.995 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
 288.996 +      mm_log (tmp,ERROR);
 288.997 +      mtx_close (stream,NIL);
 288.998 +      return NIL;
 288.999 +    }
288.1000 +    *s = '\0';			/* tie off header line */
288.1001 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
288.1002 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
288.1003 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
288.1004 +	       (unsigned long) curpos,(char *) LOCAL->buf);
288.1005 +      mm_log (tmp,ERROR);
288.1006 +      mtx_close (stream,NIL);
288.1007 +      return NIL;
288.1008 +    }
288.1009 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
288.1010 +
288.1011 +    added = T;			/* note that a new message was added */
288.1012 +				/* swell the cache */
288.1013 +    mail_exists (stream,++nmsgs);
288.1014 +				/* instantiate an elt for this message */
288.1015 +    (elt = mail_elt (stream,nmsgs))->valid = T;
288.1016 +    elt->private.uid = ++stream->uid_last;
288.1017 +				/* note file offset of header */
288.1018 +    elt->private.special.offset = curpos;
288.1019 +				/* in case error */
288.1020 +    elt->private.special.text.size = 0;
288.1021 +				/* header size not known yet */
288.1022 +    elt->private.msg.header.text.size = 0;
288.1023 +    x = s;			/* parse the header components */
288.1024 +    if (mail_parse_date (elt,LOCAL->buf) &&
288.1025 +	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
288.1026 +	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
288.1027 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
288.1028 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
288.1029 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
288.1030 +      elt->private.special.text.size = i;
288.1031 +    else {			/* oops */
288.1032 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
288.1033 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
288.1034 +      mm_log (tmp,ERROR);
288.1035 +      mtx_close (stream,NIL);
288.1036 +      return NIL;
288.1037 +    }
288.1038 +				/* make sure didn't run off end of file */
288.1039 +    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
288.1040 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
288.1041 +	       elt->private.special.offset,(unsigned long) curpos,
288.1042 +	       (unsigned long) sbuf.st_size);
288.1043 +      mm_log (tmp,ERROR);
288.1044 +      mtx_close (stream,NIL);
288.1045 +      return NIL;
288.1046 +    }
288.1047 +    c = t[10];			/* remember first system flags byte */
288.1048 +    t[10] = '\0';		/* tie off flags */
288.1049 +    j = strtoul (t,NIL,8);	/* get user flags value */
288.1050 +    t[10] = c;			/* restore first system flags byte */
288.1051 +				/* set up all valid user flags (reversed!) */
288.1052 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
288.1053 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
288.1054 +				/* calculate system flags */
288.1055 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
288.1056 +    if (j & fDELETED) elt->deleted = T;
288.1057 +    if (j & fFLAGGED) elt->flagged = T;
288.1058 +    if (j & fANSWERED) elt->answered = T;
288.1059 +    if (j & fDRAFT) elt->draft = T;
288.1060 +    if (!(j & fOLD)) {		/* newly arrived message? */
288.1061 +      elt->recent = T;
288.1062 +      recent++;			/* count up a new recent message */
288.1063 +				/* mark it as old */
288.1064 +      mtx_update_status (stream,nmsgs,NIL);
288.1065 +    }
288.1066 +  }
288.1067 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
288.1068 +				/* update parsed file size and time */
288.1069 +  LOCAL->filesize = sbuf.st_size;
288.1070 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
288.1071 +  LOCAL->filetime = sbuf.st_mtime;
288.1072 +  if (added && !stream->rdonly){/* make sure atime updated */
288.1073 +    struct utimbuf times;
288.1074 +    times.actime = time (0);
288.1075 +    times.modtime = LOCAL->filetime;
288.1076 +    utime (stream->mailbox,&times);
288.1077 +  }
288.1078 +  stream->silent = silent;	/* can pass up events now */
288.1079 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
288.1080 +  mail_recent (stream,recent);	/* and of change in recent messages */
288.1081 +  return LONGT;			/* return the winnage */
288.1082 +}
288.1083 +
288.1084 +/* MTX get cache element with status updating from file
288.1085 + * Accepts: MAIL stream
288.1086 + *	    message number
288.1087 + * Returns: cache element
288.1088 + */
288.1089 +
288.1090 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
288.1091 +{
288.1092 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
288.1093 +  struct {			/* old flags */
288.1094 +    unsigned int seen : 1;
288.1095 +    unsigned int deleted : 1;
288.1096 +    unsigned int flagged : 1;
288.1097 +    unsigned int answered : 1;
288.1098 +    unsigned int draft : 1;
288.1099 +    unsigned long user_flags;
288.1100 +  } old;
288.1101 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
288.1102 +  old.answered = elt->answered; old.draft = elt->draft;
288.1103 +  old.user_flags = elt->user_flags;
288.1104 +  mtx_read_flags (stream,elt);
288.1105 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
288.1106 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
288.1107 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
288.1108 +    mm_flags (stream,msgno);	/* let top level know */
288.1109 +  return elt;
288.1110 +}
288.1111 +
288.1112 +/* MTX read flags from file
288.1113 + * Accepts: MAIL stream
288.1114 + * Returns: cache element
288.1115 + */
288.1116 +
288.1117 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
288.1118 +{
288.1119 +  unsigned long i,j;
288.1120 +				/* noop if readonly and have valid flags */
288.1121 +  if (stream->rdonly && elt->valid) return;
288.1122 +				/* set the seek pointer */
288.1123 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
288.1124 +	 elt->private.special.text.size - 14,L_SET);
288.1125 +				/* read the new flags */
288.1126 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
288.1127 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
288.1128 +    fatal (LOCAL->buf);
288.1129 +  }
288.1130 +				/* calculate system flags */
288.1131 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
288.1132 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
288.1133 +  elt->flagged = i & fFLAGGED ? T : NIL;
288.1134 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
288.1135 +  LOCAL->buf[10] = '\0';	/* tie off flags */
288.1136 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
288.1137 +				/* set up all valid user flags (reversed!) */
288.1138 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
288.1139 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
288.1140 +  elt->valid = T;		/* have valid flags now */
288.1141 +}
288.1142 +
288.1143 +/* MTX update status string
288.1144 + * Accepts: MAIL stream
288.1145 + *	    message number
288.1146 + *	    flag saying whether or not to sync
288.1147 + */
288.1148 +
288.1149 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
288.1150 +{
288.1151 +  struct utimbuf times;
288.1152 +  struct stat sbuf;
288.1153 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
288.1154 +  unsigned long j,k = 0;
288.1155 +				/* readonly */
288.1156 +  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
288.1157 +  else {			/* readwrite */
288.1158 +    j = elt->user_flags;	/* get user flags */
288.1159 +				/* reverse bits (dontcha wish we had CIRC?) */
288.1160 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
288.1161 +				/* print new flag string */
288.1162 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
288.1163 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
288.1164 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
288.1165 +	      (fDRAFT * elt->draft)));
288.1166 +    while (T) {			/* get to that place in the file */
288.1167 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
288.1168 +	     elt->private.special.text.size - 14,L_SET);
288.1169 +				/* write new flags */
288.1170 +      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
288.1171 +      mm_notify (stream,strerror (errno),WARN);
288.1172 +      mm_diskerror (stream,errno,T);
288.1173 +    }
288.1174 +    if (syncflag) {		/* sync if requested */
288.1175 +      fsync (LOCAL->fd);
288.1176 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
288.1177 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
288.1178 +      times.actime = time (0);	/* make sure read is later */
288.1179 +      utime (stream->mailbox,&times);
288.1180 +    }
288.1181 +  }
288.1182 +}
288.1183 +
288.1184 +/* MTX locate header for a message
288.1185 + * Accepts: MAIL stream
288.1186 + *	    message number
288.1187 + *	    pointer to returned header size
288.1188 + * Returns: position of header in file
288.1189 + */
288.1190 +
288.1191 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
288.1192 +			  unsigned long *size)
288.1193 +{
288.1194 +  unsigned long siz;
288.1195 +  long i = 0;
288.1196 +  int q = 0;
288.1197 +  char *s,tmp[MAILTMPLEN];
288.1198 +  MESSAGECACHE *elt = mtx_elt (stream,msgno);
288.1199 +  unsigned long ret = elt->private.special.offset +
288.1200 +    elt->private.special.text.size;
288.1201 +				/* is header size known? */
288.1202 +  if (!(*size = elt->private.msg.header.text.size)) {
288.1203 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
288.1204 +				/* search message for CRLF CRLF */
288.1205 +    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
288.1206 +				/* read another buffer as necessary */
288.1207 +      if ((--i <= 0) &&		/* buffer empty? */
288.1208 +	  (read (LOCAL->fd,s = tmp,
288.1209 +		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
288.1210 +	return ret;		/* I/O error? */
288.1211 +      switch (q) {		/* sniff at buffer */
288.1212 +      case 0:			/* first character */
288.1213 +	q = (*s++ == '\015') ? 1 : 0;
288.1214 +	break;
288.1215 +      case 1:			/* second character */
288.1216 +	q = (*s++ == '\012') ? 2 : 0;
288.1217 +	break;
288.1218 +      case 2:			/* third character */
288.1219 +	q = (*s++ == '\015') ? 3 : 0;
288.1220 +	break;
288.1221 +      case 3:			/* fourth character */
288.1222 +	if (*s++ == '\012') {	/* have the sequence? */
288.1223 +				/* yes, note for later */
288.1224 +	  elt->private.msg.header.text.size = *size = siz;
288.1225 +	  return ret;
288.1226 +	}
288.1227 +	q = 0;			/* lost... */
288.1228 +	break;
288.1229 +      }
288.1230 +    }
288.1231 +				/* header consumes entire message */
288.1232 +    elt->private.msg.header.text.size = *size = elt->rfc822_size;
288.1233 +  }
288.1234 +  return ret;
288.1235 +}
   289.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   289.2 +++ b/src/osdep/nt/nl_nt.c	Mon Sep 14 15:17:45 2009 +0900
   289.3 @@ -0,0 +1,61 @@
   289.4 +/* ========================================================================
   289.5 + * Copyright 1988-2006 University of Washington
   289.6 + *
   289.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   289.8 + * you may not use this file except in compliance with the License.
   289.9 + * You may obtain a copy of the License at
  289.10 + *
  289.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  289.12 + *
  289.13 + * 
  289.14 + * ========================================================================
  289.15 + */
  289.16 +
  289.17 +/*
  289.18 + * Program:	Windows/TOPS-20 newline routines
  289.19 + *
  289.20 + * Author:	Mark Crispin
  289.21 + *		Networks and Distributed Computing
  289.22 + *		Computing & Communications
  289.23 + *		University of Washington
  289.24 + *		Administration Building, AG-44
  289.25 + *		Seattle, WA  98195
  289.26 + *		Internet: MRC@CAC.Washington.EDU
  289.27 + *
  289.28 + * Date:	1 August 1988
  289.29 + * Last Edited:	30 August 2006
  289.30 + */
  289.31 +
  289.32 +/* Copy string with CRLF newlines
  289.33 + * Accepts: destination string
  289.34 + *	    pointer to size of destination string buffer
  289.35 + *	    source string
  289.36 + *	    length of source string
  289.37 + * Returns: length of copied string
  289.38 + */
  289.39 +
  289.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  289.41 +			  unsigned char *src,unsigned long srcl)
  289.42 +{
  289.43 +				/* flush destination buffer if too small */
  289.44 +  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
  289.45 +  if (!*dst) {			/* make a new buffer if needed */
  289.46 +    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
  289.47 +    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
  289.48 +  }
  289.49 +				/* copy strings */
  289.50 +  if (srcl) memcpy (*dst,src,(size_t) srcl);
  289.51 +  *(*dst + srcl) = '\0';	/* tie off destination */
  289.52 +  return srcl;			/* return length */
  289.53 +}
  289.54 +
  289.55 +
  289.56 +/* Length of string after strcrlfcpy applied
  289.57 + * Accepts: source string
  289.58 + * Returns: length of string
  289.59 + */
  289.60 +
  289.61 +unsigned long strcrlflen (STRING *s)
  289.62 +{
  289.63 +  return SIZE (s);		/* no-brainer on DOS! */
  289.64 +}
   290.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   290.2 +++ b/src/osdep/nt/os_nt.c	Mon Sep 14 15:17:45 2009 +0900
   290.3 @@ -0,0 +1,48 @@
   290.4 +/* ========================================================================
   290.5 + * Copyright 1988-2006 University of Washington
   290.6 + *
   290.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   290.8 + * you may not use this file except in compliance with the License.
   290.9 + * You may obtain a copy of the License at
  290.10 + *
  290.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  290.12 + *
  290.13 + * 
  290.14 + * ========================================================================
  290.15 + */
  290.16 +
  290.17 +/*
  290.18 + * Program:	Operating-system dependent routines -- NT version
  290.19 + *
  290.20 + * Author:	Mark Crispin
  290.21 + *		Networks and Distributed Computing
  290.22 + *		Computing & Communications
  290.23 + *		University of Washington
  290.24 + *		Administration Building, AG-44
  290.25 + *		Seattle, WA  98195
  290.26 + *		Internet: MRC@CAC.Washington.EDU
  290.27 + *
  290.28 + * Date:	11 April 1989
  290.29 + * Last Edited:	30 August 2006
  290.30 + */
  290.31 +
  290.32 +#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
  290.33 +#undef	ERROR			/* quell conflicting def warning */
  290.34 +#include "mail.h"
  290.35 +#include "osdep.h"
  290.36 +#include <stdio.h>
  290.37 +#include <time.h>
  290.38 +#include <errno.h>
  290.39 +#include <sys\timeb.h>
  290.40 +#include <fcntl.h>
  290.41 +#include <sys\stat.h>
  290.42 +#include "misc.h"
  290.43 +#include "mailfile.h"
  290.44 +
  290.45 +#include "fs_nt.c"
  290.46 +#include "ftl_nt.c"
  290.47 +#include "nl_nt.c"
  290.48 +#include "yunchan.c"
  290.49 +#include "tcp_nt.c"		/* must be before env_nt.c */
  290.50 +#include "env_nt.c"
  290.51 +#include "ssl_nt.c"
   291.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   291.2 +++ b/src/osdep/nt/os_nt.h	Mon Sep 14 15:17:45 2009 +0900
   291.3 @@ -0,0 +1,60 @@
   291.4 +/* ========================================================================
   291.5 + * Copyright 1988-2007 University of Washington
   291.6 + *
   291.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   291.8 + * you may not use this file except in compliance with the License.
   291.9 + * You may obtain a copy of the License at
  291.10 + *
  291.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  291.12 + *
  291.13 + * 
  291.14 + * ========================================================================
  291.15 + */
  291.16 +
  291.17 +/*
  291.18 + * Program:	Operating-system dependent routines -- NT version
  291.19 + *
  291.20 + * Author:	Mark Crispin
  291.21 + *		Networks and Distributed Computing
  291.22 + *		Computing & Communications
  291.23 + *		University of Washington
  291.24 + *		Administration Building, AG-44
  291.25 + *		Seattle, WA  98195
  291.26 + *		Internet: MRC@CAC.Washington.EDU
  291.27 + *
  291.28 + * Date:	11 May 1989
  291.29 + * Last Edited:	27 April 2007
  291.30 + */
  291.31 +
  291.32 +#include <stdlib.h>
  291.33 +#include <string.h>
  291.34 +#include <stdio.h>
  291.35 +#include <sys\types.h>
  291.36 +#include <time.h>
  291.37 +#include <io.h>
  291.38 +#include <conio.h>
  291.39 +#include <process.h>
  291.40 +#undef ERROR			/* quell conflicting defintion warning */
  291.41 +#include <windows.h>
  291.42 +#include <lm.h>
  291.43 +#undef ERROR
  291.44 +#define ERROR (long) 2		/* must match mail.h */
  291.45 +
  291.46 +#if _MSC_VER >= 1400
  291.47 +#define strtok_r strtok_s	/* for some reason they called it this */
  291.48 +#else
  291.49 +/* strtok() is actually MT-safe in MSVC.  Why is it that Microsoft can do
  291.50 + * their CRT right, but GNU, Sun, etc. can't?
  291.51 + */
  291.52 +#define strtok_r(a,b,c) strtok(*(c) = a,b)
  291.53 +#endif
  291.54 +
  291.55 +#include "env_nt.h"
  291.56 +#include "fs.h"
  291.57 +#include "ftl.h"
  291.58 +#include "nl.h"
  291.59 +#include "tcp.h"
  291.60 +#include "yunchan.h"
  291.61 +
  291.62 +#undef noErr
  291.63 +#undef MAC
   292.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   292.2 +++ b/src/osdep/nt/os_ntk.c	Mon Sep 14 15:17:45 2009 +0900
   292.3 @@ -0,0 +1,51 @@
   292.4 +/* ========================================================================
   292.5 + * Copyright 1988-2006 University of Washington
   292.6 + *
   292.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   292.8 + * you may not use this file except in compliance with the License.
   292.9 + * You may obtain a copy of the License at
  292.10 + *
  292.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  292.12 + *
  292.13 + * 
  292.14 + * ========================================================================
  292.15 + */
  292.16 +
  292.17 +/*
  292.18 + * Program:	Operating-system dependent routines -- NT version + Kerberos
  292.19 + *
  292.20 + * Author:	Mark Crispin
  292.21 + *		Networks and Distributed Computing
  292.22 + *		Computing & Communications
  292.23 + *		University of Washington
  292.24 + *		Administration Building, AG-44
  292.25 + *		Seattle, WA  98195
  292.26 + *		Internet: MRC@CAC.Washington.EDU
  292.27 + *
  292.28 + * Date:	11 April 1989
  292.29 + * Last Edited:	30 August 2006
  292.30 + */
  292.31 +
  292.32 +#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
  292.33 +#undef	ERROR			/* quell conflicting def warning */
  292.34 +#include "mail.h"
  292.35 +#include "osdep.h"
  292.36 +#include <stdio.h>
  292.37 +#include <time.h>
  292.38 +#include <errno.h>
  292.39 +#include <sys\timeb.h>
  292.40 +#include <fcntl.h>
  292.41 +#include <sys\stat.h>
  292.42 +#include "misc.h"
  292.43 +#include "mailfile.h"
  292.44 +
  292.45 +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
  292.46 +
  292.47 +#include "fs_nt.c"
  292.48 +#include "ftl_nt.c"
  292.49 +#include "nl_nt.c"
  292.50 +#include "yunchan.c"
  292.51 +#include "kerb_mit.c"
  292.52 +#include "tcp_nt.c"		/* must be before env_nt.c */
  292.53 +#include "env_nt.c"
  292.54 +#include "ssl_nt.c"
   293.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   293.2 +++ b/src/osdep/nt/os_old.c	Mon Sep 14 15:17:45 2009 +0900
   293.3 @@ -0,0 +1,48 @@
   293.4 +/* ========================================================================
   293.5 + * Copyright 1988-2006 University of Washington
   293.6 + *
   293.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   293.8 + * you may not use this file except in compliance with the License.
   293.9 + * You may obtain a copy of the License at
  293.10 + *
  293.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  293.12 + *
  293.13 + * 
  293.14 + * ========================================================================
  293.15 + */
  293.16 +
  293.17 +/*
  293.18 + * Program:	Operating-system dependent routines -- NT version
  293.19 + *
  293.20 + * Author:	Mark Crispin
  293.21 + *		Networks and Distributed Computing
  293.22 + *		Computing & Communications
  293.23 + *		University of Washington
  293.24 + *		Administration Building, AG-44
  293.25 + *		Seattle, WA  98195
  293.26 + *		Internet: MRC@CAC.Washington.EDU
  293.27 + *
  293.28 + * Date:	11 April 1989
  293.29 + * Last Edited:	21 December 2007
  293.30 + */
  293.31 +
  293.32 +#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
  293.33 +#undef	ERROR			/* quell conflicting def warning */
  293.34 +#include "mail.h"
  293.35 +#include "osdep.h"
  293.36 +#include <stdio.h>
  293.37 +#include <time.h>
  293.38 +#include <errno.h>
  293.39 +#include <sys\timeb.h>
  293.40 +#include <fcntl.h>
  293.41 +#include <sys\stat.h>
  293.42 +#include "misc.h"
  293.43 +#include "mailfile.h"
  293.44 +
  293.45 +#include "fs_nt.c"
  293.46 +#include "ftl_nt.c"
  293.47 +#include "nl_nt.c"
  293.48 +#include "yunchan.c"
  293.49 +#include "tcp_nt.c"		/* must be before env_nt.c */
  293.50 +#include "env_nt.c"
  293.51 +#include "ssl_old.c"
   294.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   294.2 +++ b/src/osdep/nt/os_w2k.c	Mon Sep 14 15:17:45 2009 +0900
   294.3 @@ -0,0 +1,49 @@
   294.4 +/* ========================================================================
   294.5 + * Copyright 1988-2006 University of Washington
   294.6 + *
   294.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   294.8 + * you may not use this file except in compliance with the License.
   294.9 + * You may obtain a copy of the License at
  294.10 + *
  294.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  294.12 + *
  294.13 + * 
  294.14 + * ========================================================================
  294.15 + */
  294.16 +
  294.17 +/*
  294.18 + * Program:	Operating-system dependent routines -- Windows 2000 version
  294.19 + *
  294.20 + * Author:	Mark Crispin
  294.21 + *		Networks and Distributed Computing
  294.22 + *		Computing & Communications
  294.23 + *		University of Washington
  294.24 + *		Administration Building, AG-44
  294.25 + *		Seattle, WA  98195
  294.26 + *		Internet: MRC@CAC.Washington.EDU
  294.27 + *
  294.28 + * Date:	11 April 1989
  294.29 + * Last Edited:	30 August 2006
  294.30 + */
  294.31 +
  294.32 +#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
  294.33 +#undef	ERROR			/* quell conflicting def warning */
  294.34 +#include "mail.h"
  294.35 +#include "osdep.h"
  294.36 +#include <stdio.h>
  294.37 +#include <time.h>
  294.38 +#include <errno.h>
  294.39 +#include <sys\timeb.h>
  294.40 +#include <fcntl.h>
  294.41 +#include <sys\stat.h>
  294.42 +#include "misc.h"
  294.43 +#include "mailfile.h"
  294.44 +
  294.45 +#include "fs_nt.c"
  294.46 +#include "ftl_nt.c"
  294.47 +#include "nl_nt.c"
  294.48 +#include "yunchan.c"
  294.49 +#include "kerb_w2k.c"
  294.50 +#include "tcp_nt.c"		/* must be before env_nt.c */
  294.51 +#include "env_nt.c"
  294.52 +#include "ssl_w2k.c"
   295.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   295.2 +++ b/src/osdep/nt/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   295.3 @@ -0,0 +1,89 @@
   295.4 +/* ========================================================================
   295.5 + * Copyright 1988-2006 University of Washington
   295.6 + *
   295.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   295.8 + * you may not use this file except in compliance with the License.
   295.9 + * You may obtain a copy of the License at
  295.10 + *
  295.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  295.12 + *
  295.13 + * 
  295.14 + * ========================================================================
  295.15 + */
  295.16 +
  295.17 +/*
  295.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  295.19 + *
  295.20 + * Author:	Mark Crispin
  295.21 + *		Networks and Distributed Computing
  295.22 + *		Computing & Communications
  295.23 + *		University of Washington
  295.24 + *		Administration Building, AG-44
  295.25 + *		Seattle, WA  98195
  295.26 + *		Internet: MRC@CAC.Washington.EDU
  295.27 + *
  295.28 + * Date:	15 June 2000
  295.29 + * Last Edited:	30 August 2006
  295.30 + */
  295.31 +
  295.32 +/* Wildcard pattern match
  295.33 + * Accepts: base string
  295.34 + *	    pattern string
  295.35 + *	    delimiter character
  295.36 + * Returns: T if pattern matches base, else NIL
  295.37 + */
  295.38 +
  295.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  295.40 +{
  295.41 +  switch (*pat) {
  295.42 +  case '%':			/* non-recursive */
  295.43 +				/* % at end, OK if no inferiors */
  295.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  295.45 +                                /* scan remainder of string until delimiter */
  295.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  295.47 +    while ((*s != delim) && *s++);
  295.48 +    break;
  295.49 +  case '*':			/* match 0 or more characters */
  295.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  295.51 +				/* scan remainder of string */
  295.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  295.53 +    while (*s++);
  295.54 +    break;
  295.55 +  case '\0':			/* end of pattern */
  295.56 +    return *s ? NIL : T;	/* success if also end of base */
  295.57 +  default:			/* match this character */
  295.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  295.59 +  }
  295.60 +  return NIL;
  295.61 +}
  295.62 +
  295.63 +/* Directory pattern match
  295.64 + * Accepts: base string
  295.65 + *	    pattern string
  295.66 + *	    delimiter character
  295.67 + * Returns: T if base is a matching directory of pattern, else NIL
  295.68 + */
  295.69 +
  295.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  295.71 +{
  295.72 +  switch (*pat) {
  295.73 +  case '%':			/* non-recursive */
  295.74 +    if (!*s) return T;		/* end of base means have a subset match */
  295.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  295.76 +				/* scan remainder of string until delimiter */
  295.77 +    do if (dmatch (s,pat,delim)) return T;
  295.78 +    while ((*s != delim) && *s++);
  295.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  295.80 +    return dmatch (s,pat,delim);/* do new scan */
  295.81 +  case '*':			/* match 0 or more characters */
  295.82 +    return T;			/* unconditional match */
  295.83 +  case '\0':			/* end of pattern */
  295.84 +    break;
  295.85 +  default:			/* match this character */
  295.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  295.87 +				/* end of base, return if at delimiter */
  295.88 +    else if (*pat == delim) return T;
  295.89 +    break;
  295.90 +  }
  295.91 +  return NIL;
  295.92 +}
   296.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   296.2 +++ b/src/osdep/nt/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
   296.3 @@ -0,0 +1,36 @@
   296.4 +/* ========================================================================
   296.5 + * Copyright 1988-2006 University of Washington
   296.6 + *
   296.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   296.8 + * you may not use this file except in compliance with the License.
   296.9 + * You may obtain a copy of the License at
  296.10 + *
  296.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  296.12 + *
  296.13 + * 
  296.14 + * ========================================================================
  296.15 + */
  296.16 +
  296.17 +/*
  296.18 + * Program:	Pseudo Header Strings
  296.19 + *
  296.20 + * Author:	Mark Crispin
  296.21 + *		Networks and Distributed Computing
  296.22 + *		Computing & Communications
  296.23 + *		University of Washington
  296.24 + *		Administration Building, AG-44
  296.25 + *		Seattle, WA  98195
  296.26 + *		Internet: MRC@CAC.Washington.EDU
  296.27 + *
  296.28 + * Date:	26 September 1996
  296.29 + * Last Edited:	30 August 2006
  296.30 + */
  296.31 +
  296.32 +/* Local sites may wish to alter this text */
  296.33 +
  296.34 +char *pseudo_from = "MAILER-DAEMON";
  296.35 +char *pseudo_name = "Mail System Internal Data";
  296.36 +char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
  296.37 +char *pseudo_msg =
  296.38 +  "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."
  296.39 +  ;
   297.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   297.2 +++ b/src/osdep/nt/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
   297.3 @@ -0,0 +1,30 @@
   297.4 +/* ========================================================================
   297.5 + * Copyright 1988-2006 University of Washington
   297.6 + *
   297.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   297.8 + * you may not use this file except in compliance with the License.
   297.9 + * You may obtain a copy of the License at
  297.10 + *
  297.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  297.12 + *
  297.13 + * 
  297.14 + * ========================================================================
  297.15 + */
  297.16 +
  297.17 +/*
  297.18 + * Program:	Pseudo Header Strings
  297.19 + *
  297.20 + * Author:	Mark Crispin
  297.21 + *		Networks and Distributed Computing
  297.22 + *		Computing & Communications
  297.23 + *		University of Washington
  297.24 + *		Administration Building, AG-44
  297.25 + *		Seattle, WA  98195
  297.26 + *		Internet: MRC@CAC.Washington.EDU
  297.27 + *
  297.28 + * Date:	26 September 1996
  297.29 + * Last Edited:	30 August 2006
  297.30 + */
  297.31 +
  297.32 +
  297.33 +extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
   298.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   298.2 +++ b/src/osdep/nt/setproto.bat	Mon Sep 14 15:17:45 2009 +0900
   298.3 @@ -0,0 +1,29 @@
   298.4 +@ECHO OFF
   298.5 +REM ========================================================================
   298.6 +REM Copyright 1988-2006 University of Washington
   298.7 +REM
   298.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   298.9 +REM you may not use this file except in compliance with the License.
  298.10 +REM You may obtain a copy of the License at
  298.11 +REM
  298.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  298.13 +REM
  298.14 +REM 
  298.15 +REM ========================================================================
  298.16 +
  298.17 +REM Program:	Set default prototype for DOS/NT
  298.18 +REM
  298.19 +REM Author:	Mark Crispin
  298.20 +REM		Networks and Distributed Computing
  298.21 +REM		Computing & Communications
  298.22 +REM		University of Washington
  298.23 +REM		Administration Building, AG-44
  298.24 +REM		Seattle, WA  98195
  298.25 +REM		Internet: MRC@CAC.Washington.EDU
  298.26 +REM
  298.27 +REM Date:	 9 October 1995
  298.28 +REM Last Edited: 30 August 2006
  298.29 +
  298.30 +REM Set the default drivers
  298.31 +ECHO #define CREATEPROTO %1proto >> LINKAGE.H
  298.32 +ECHO #define APPENDPROTO %2proto >> LINKAGE.H
   299.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   299.2 +++ b/src/osdep/nt/ssl_none.c	Mon Sep 14 15:17:45 2009 +0900
   299.3 @@ -0,0 +1,141 @@
   299.4 +/* ========================================================================
   299.5 + * Copyright 1988-2006 University of Washington
   299.6 + *
   299.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   299.8 + * you may not use this file except in compliance with the License.
   299.9 + * You may obtain a copy of the License at
  299.10 + *
  299.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  299.12 + *
  299.13 + * 
  299.14 + * ========================================================================
  299.15 + */
  299.16 +
  299.17 +/*
  299.18 + * Program:	Dummy (no SSL) authentication/encryption module
  299.19 + *
  299.20 + * Author:	Mark Crispin
  299.21 + *		Networks and Distributed Computing
  299.22 + *		Computing & Communications
  299.23 + *		University of Washington
  299.24 + *		Administration Building, AG-44
  299.25 + *		Seattle, WA  98195
  299.26 + *		Internet: MRC@CAC.Washington.EDU
  299.27 + *
  299.28 + * Date:	7 February 2001
  299.29 + * Last Edited:	30 August 2006
  299.30 + */
  299.31 +
  299.32 +/* Init server for SSL
  299.33 + * Accepts: server name
  299.34 + */
  299.35 +
  299.36 +void ssl_server_init (char *server)
  299.37 +{
  299.38 +  syslog (LOG_ERR,"This server does not support SSL");
  299.39 +  exit (1);			/* punt this program too */
  299.40 +}
  299.41 +
  299.42 +
  299.43 +/* Start TLS
  299.44 + * Accepts: /etc/services service name
  299.45 + * Returns: cpystr'd error string if TLS failed, else NIL for success
  299.46 + */
  299.47 +
  299.48 +char *ssl_start_tls (char *server)
  299.49 +{
  299.50 +  return cpystr ("This server does not support TLS");
  299.51 +}
  299.52 +
  299.53 +/* Get character
  299.54 + * Returns: character or EOF
  299.55 + */
  299.56 +
  299.57 +int PBIN (void)
  299.58 +{
  299.59 +  return getchar ();
  299.60 +}
  299.61 +
  299.62 +
  299.63 +/* Get string
  299.64 + * Accepts: destination string pointer
  299.65 + *	    number of bytes available
  299.66 + * Returns: destination string pointer or NIL if EOF
  299.67 + */
  299.68 +
  299.69 +char *PSIN (char *s,int n)
  299.70 +{
  299.71 +  return fgets (s,n,stdin);
  299.72 +}
  299.73 +
  299.74 +
  299.75 +/* Get record
  299.76 + * Accepts: destination string pointer
  299.77 + *	    number of bytes to read
  299.78 + * Returns: T if success, NIL otherwise
  299.79 + */
  299.80 +
  299.81 +long PSINR (char *s,unsigned long n)
  299.82 +{
  299.83 +  unsigned long i;
  299.84 +  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
  299.85 +  return n ? NIL : LONGT;
  299.86 +}
  299.87 +
  299.88 +
  299.89 +/* Wait for input
  299.90 + * Accepts: timeout in seconds
  299.91 + * Returns: T if have input on stdin, else NIL
  299.92 + */
  299.93 +
  299.94 +long INWAIT (long seconds)
  299.95 +{
  299.96 +  return server_input_wait (seconds);
  299.97 +}
  299.98 +
  299.99 +/* Put character
 299.100 + * Accepts: character
 299.101 + * Returns: character written or EOF
 299.102 + */
 299.103 +
 299.104 +int PBOUT (int c)
 299.105 +{
 299.106 +  return putchar (c);
 299.107 +}
 299.108 +
 299.109 +
 299.110 +/* Put string
 299.111 + * Accepts: source string pointer
 299.112 + * Returns: 0 or EOF if error
 299.113 + */
 299.114 +
 299.115 +int PSOUT (char *s)
 299.116 +{
 299.117 +  return fputs (s,stdout);
 299.118 +}
 299.119 +
 299.120 +
 299.121 +/* Put record
 299.122 + * Accepts: source sized text
 299.123 + * Returns: 0 or EOF if error
 299.124 + */
 299.125 +
 299.126 +int PSOUTR (SIZEDTEXT *s)
 299.127 +{
 299.128 +  unsigned char *t;
 299.129 +  unsigned long i,j;
 299.130 +  for (t = s->data,i = s->size;
 299.131 +       (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)));
 299.132 +       t += j,i -= j);
 299.133 +  return i ? EOF : NIL;
 299.134 +}
 299.135 +
 299.136 +
 299.137 +/* Flush output
 299.138 + * Returns: 0 or EOF if error
 299.139 + */
 299.140 +
 299.141 +int PFLUSH (void)
 299.142 +{
 299.143 +  return fflush (stdout);
 299.144 +}
   300.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   300.2 +++ b/src/osdep/nt/ssl_nt.c	Mon Sep 14 15:17:45 2009 +0900
   300.3 @@ -0,0 +1,721 @@
   300.4 +/* ========================================================================
   300.5 + * Copyright 1988-2008 University of Washington
   300.6 + *
   300.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   300.8 + * you may not use this file except in compliance with the License.
   300.9 + * You may obtain a copy of the License at
  300.10 + *
  300.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  300.12 + *
  300.13 + * 
  300.14 + * ========================================================================
  300.15 + */
  300.16 +
  300.17 +/*
  300.18 + * Program:	SSL authentication/encryption module for Windows 9x and NT
  300.19 + *
  300.20 + * Author:	Mark Crispin
  300.21 + *		Networks and Distributed Computing
  300.22 + *		Computing & Communications
  300.23 + *		University of Washington
  300.24 + *		Administration Building, AG-44
  300.25 + *		Seattle, WA  98195
  300.26 + *		Internet: MRC@CAC.Washington.EDU
  300.27 + *
  300.28 + * Date:	22 September 1998
  300.29 + * Last Edited:	13 January 2008
  300.30 + */
  300.31 +
  300.32 +#define SECURITY_WIN32
  300.33 +#include <sspi.h>
  300.34 +#include <schannel.h>
  300.35 +
  300.36 +
  300.37 +#define SSLBUFLEN 8192
  300.38 +
  300.39 +
  300.40 +/* SSL I/O stream */
  300.41 +
  300.42 +typedef struct ssl_stream {
  300.43 +  TCPSTREAM *tcpstream;		/* TCP stream */
  300.44 +  CredHandle cred;		/* SSL credentials */
  300.45 +  CtxtHandle context;		/* SSL context */
  300.46 +				/* stream encryption sizes */
  300.47 +  SecPkgContext_StreamSizes sizes;
  300.48 +  size_t bufsize;
  300.49 +  int ictr;			/* input counter */
  300.50 +  char *iptr;			/* input pointer */
  300.51 +  int iextractr;		/* extra input counter */
  300.52 +  char *iextraptr;		/* extra input pointer */
  300.53 +  char *ibuf;			/* input buffer */
  300.54 +  char *obuf;			/* output buffer */
  300.55 +} SSLSTREAM;
  300.56 +
  300.57 +#include "sslio.h"
  300.58 +
  300.59 +
  300.60 +/* Function prototypes */
  300.61 +
  300.62 +static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
  300.63 +static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
  300.64 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
  300.65 +			       long *contd);
  300.66 +static long ssl_abort (SSLSTREAM *stream);
  300.67 +
  300.68 +/* Secure Sockets Layer network driver dispatch */
  300.69 +
  300.70 +static struct ssl_driver ssldriver = {
  300.71 +  ssl_open,			/* open connection */
  300.72 +  ssl_aopen,			/* open preauthenticated connection */
  300.73 +  ssl_getline,			/* get a line */
  300.74 +  ssl_getbuffer,		/* get a buffer */
  300.75 +  ssl_soutr,			/* output pushed data */
  300.76 +  ssl_sout,			/* output string */
  300.77 +  ssl_close,			/* close connection */
  300.78 +  ssl_host,			/* return host name */
  300.79 +  ssl_remotehost,		/* return remote host name */
  300.80 +  ssl_port,			/* return port number */
  300.81 +  ssl_localhost			/* return local host name */
  300.82 +};
  300.83 +
  300.84 +				/* security function table */
  300.85 +static SecurityFunctionTable *sft = NIL;
  300.86 +static unsigned long ssltsz = 0;/* SSL maximum token length */
  300.87 +
  300.88 +
  300.89 +/* Define crypt32.dll stuff here in case a pre-IE5 Win9x system */
  300.90 +
  300.91 +typedef DWORD (CALLBACK *CNTS) (DWORD,PCERT_NAME_BLOB,DWORD,LPSTR,DWORD);
  300.92 +typedef BOOL (CALLBACK *CGCC) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,
  300.93 +			       HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,
  300.94 +			       PCCERT_CHAIN_CONTEXT *);
  300.95 +typedef BOOL (CALLBACK *CVCCP) (LPCSTR,PCCERT_CHAIN_CONTEXT,
  300.96 +				PCERT_CHAIN_POLICY_PARA,
  300.97 +				PCERT_CHAIN_POLICY_STATUS);
  300.98 +typedef VOID (CALLBACK *CFCC) (PCCERT_CHAIN_CONTEXT);
  300.99 +typedef BOOL (CALLBACK *CFCCX) (PCCERT_CONTEXT);
 300.100 +
 300.101 +static CNTS certNameToStr = NIL;
 300.102 +static CGCC certGetCertificateChain = NIL;
 300.103 +static CVCCP certVerifyCertificateChainPolicy = NIL;
 300.104 +static CFCC certFreeCertificateChain = NIL;
 300.105 +static CFCCX certFreeCertificateContext = NIL;
 300.106 +
 300.107 +/* One-time SSL initialization */
 300.108 +
 300.109 +static int sslonceonly = 0;
 300.110 +
 300.111 +void ssl_onceonlyinit (void)
 300.112 +{
 300.113 +  if (!sslonceonly++) {		/* only need to call it once */
 300.114 +    HINSTANCE lib;
 300.115 +    FARPROC pi;
 300.116 +    ULONG np;
 300.117 +    SecPkgInfo *pp;
 300.118 +    int i;
 300.119 +				/* get security library */
 300.120 +    if (((lib = LoadLibrary ("schannel.dll")) ||
 300.121 +	 (lib = LoadLibrary ("security.dll"))) &&
 300.122 +	(pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) &&
 300.123 +	(sft = (SecurityFunctionTable *) pi ()) &&
 300.124 +	!(sft->EnumerateSecurityPackages (&np,&pp))) {
 300.125 +				/* look for an SSL package */
 300.126 +      for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
 300.127 +				/* note maximum token size and name */
 300.128 +	ssltsz = pp[i].cbMaxToken;
 300.129 +				/* apply runtime linkage */
 300.130 +	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
 300.131 +	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
 300.132 +	if ((lib = LoadLibrary ("crypt32.dll")) &&
 300.133 +	    (certGetCertificateChain = (CGCC)
 300.134 +	     GetProcAddress (lib,"CertGetCertificateChain")) &&
 300.135 +	    (certVerifyCertificateChainPolicy = (CVCCP)
 300.136 +	     GetProcAddress (lib,"CertVerifyCertificateChainPolicy")) &&
 300.137 +	    (certFreeCertificateChain = (CFCC)
 300.138 +	     GetProcAddress (lib,"CertFreeCertificateChain")) &&
 300.139 +	    (certFreeCertificateContext = (CFCCX)
 300.140 +	     GetProcAddress (lib,"CertFreeCertificateContext")))
 300.141 +	  certNameToStr = (CNTS) GetProcAddress (lib,"CertNameToStrA");
 300.142 +	return;			/* all done */
 300.143 +      }
 300.144 +    }
 300.145 +  }
 300.146 +}
 300.147 +
 300.148 +/* SSL open
 300.149 + * Accepts: host name
 300.150 + *	    contact service name
 300.151 + *	    contact port number
 300.152 + * Returns: SSL stream if success else NIL
 300.153 + */
 300.154 +
 300.155 +SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
 300.156 +{
 300.157 +  TCPSTREAM *stream = tcp_open (host,service,port);
 300.158 +  return stream ? ssl_start (stream,host,port) : NIL;
 300.159 +}
 300.160 +
 300.161 +  
 300.162 +/* SSL authenticated open
 300.163 + * Accepts: host name
 300.164 + *	    service name
 300.165 + *	    returned user name buffer
 300.166 + * Returns: SSL stream if success else NIL
 300.167 + */
 300.168 +
 300.169 +SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
 300.170 +{
 300.171 +  return NIL;			/* don't use this mechanism with SSL */
 300.172 +}
 300.173 +
 300.174 +/* Start SSL/TLS negotiations
 300.175 + * Accepts: open TCP stream of session
 300.176 + *	    user's host name
 300.177 + *	    flags
 300.178 + * Returns: SSL stream if success else NIL
 300.179 + */
 300.180 +
 300.181 +static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
 300.182 +{
 300.183 +  SECURITY_STATUS e;
 300.184 +  ULONG a;
 300.185 +  TimeStamp t;
 300.186 +  SecBuffer ibuf[2],obuf[1];
 300.187 +  SecBufferDesc ibufs,obufs;
 300.188 +  SCHANNEL_CRED tlscred;
 300.189 +  CERT_CONTEXT *cert = NIL;
 300.190 +  CERT_CHAIN_PARA chparam;
 300.191 +  CERT_CHAIN_CONTEXT *chain;
 300.192 +  SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy;
 300.193 +  CERT_CHAIN_POLICY_PARA polparam;
 300.194 +  CERT_CHAIN_POLICY_STATUS status;
 300.195 +  char tmp[MAILTMPLEN],certname[256];
 300.196 +  char *reason = NIL;
 300.197 +  ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
 300.198 +    ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
 300.199 +      ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
 300.200 +	ISC_REQ_MANUAL_CRED_VALIDATION;
 300.201 +  LPSTR usage[] = {
 300.202 +    szOID_PKIX_KP_SERVER_AUTH,
 300.203 +    szOID_SERVER_GATED_CRYPTO,
 300.204 +    szOID_SGC_NETSCAPE
 300.205 +  };
 300.206 +  PWSTR whost = NIL;
 300.207 +  char *buf = (char *) fs_get (ssltsz);
 300.208 +  unsigned long size = 0;
 300.209 +  sslcertificatequery_t scq =
 300.210 +    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
 300.211 +  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
 300.212 +  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 300.213 +					    sizeof (SSLSTREAM));
 300.214 +  stream->tcpstream = tstream;	/* bind TCP stream */
 300.215 +				/* initialize TLS credential */
 300.216 +  memset (&tlscred,0,sizeof (SCHANNEL_CRED));
 300.217 +  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
 300.218 +  tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
 300.219 +
 300.220 +				/* acquire credentials */
 300.221 +  if (sft->AcquireCredentialsHandle
 300.222 +      (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
 300.223 +       &tlscred : NIL,NIL,NIL,&stream->cred,&t)
 300.224 +      != SEC_E_OK) reason = "Acquire credentials handle failed";
 300.225 +  else while (!reason) {	/* negotiate security context */
 300.226 +				/* initialize buffers */
 300.227 +    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
 300.228 +    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
 300.229 +    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
 300.230 +    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
 300.231 +    ibuf[1].BufferType = SECBUFFER_EMPTY;
 300.232 +				/* initialize buffer descriptors */
 300.233 +    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
 300.234 +    ibufs.cBuffers = 2; obufs.cBuffers = 1;
 300.235 +    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
 300.236 +				/* negotiate security */
 300.237 +    e = sft->InitializeSecurityContext
 300.238 +      (&stream->cred,size ? &stream->context : NIL,host,req,0,
 300.239 +       SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
 300.240 +				/* have an output buffer we need to send? */
 300.241 +    if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
 300.242 +      if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
 300.243 +	reason = "Unexpected TCP output disconnect";
 300.244 +				/* free the buffer */
 300.245 +      sft->FreeContextBuffer (obuf[0].pvBuffer);
 300.246 +    }
 300.247 +    if (!reason) switch (e) {	/* negotiation state */
 300.248 +    case SEC_I_INCOMPLETE_CREDENTIALS:
 300.249 +      break;			/* server wants client auth */
 300.250 +    case SEC_I_CONTINUE_NEEDED:
 300.251 +      if (size) {		/* continue, read any data? */
 300.252 +				/* yes, anything regurgiated back to us? */
 300.253 +	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
 300.254 +				/* yes, set this as the new data */
 300.255 +	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
 300.256 +	  size = ibuf[1].cbBuffer;
 300.257 +	  break;
 300.258 +	}
 300.259 +	size = 0;		/* otherwise, read more stuff from server */
 300.260 +      }
 300.261 +    case SEC_E_INCOMPLETE_MESSAGE:
 300.262 +				/* need to read more data from server */
 300.263 +      if (!tcp_getdata (stream->tcpstream))
 300.264 +	reason = "Unexpected TCP input disconnect";
 300.265 +      else {
 300.266 +	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
 300.267 +	size += stream->tcpstream->ictr;
 300.268 +				/* empty it from TCP's buffers */
 300.269 +	stream->tcpstream->iptr += stream->tcpstream->ictr;
 300.270 +	stream->tcpstream->ictr = 0;
 300.271 +      }
 300.272 +      break;
 300.273 +
 300.274 +    case SEC_E_OK:		/* success, any data to be regurgitated? */
 300.275 +      if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
 300.276 +				/* yes, set this as the new data */
 300.277 +	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
 300.278 +		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
 300.279 +	stream->tcpstream->ictr = ibuf[1].cbBuffer;
 300.280 +      }
 300.281 +      if (certNameToStr && !(flags & NET_NOVALIDATECERT)) {
 300.282 +				/* need validation, make wchar of host */
 300.283 +	if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) &&
 300.284 +	      (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) &&
 300.285 +	      MultiByteToWideChar (CP_ACP,0,host,-1,whost,size)))
 300.286 +	  fatal ("Can't make wchar of host name!");
 300.287 +				/* get certificate */
 300.288 +	if ((sft->QueryContextAttributes
 300.289 +	     (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) !=
 300.290 +	     SEC_E_OK) || !cert) {
 300.291 +	  reason = "*Unable to get certificate";
 300.292 +	  strcpy (certname,"<no certificate>");
 300.293 +	}
 300.294 +	else {			/* get certificate subject name */
 300.295 +	  (*certNameToStr) (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
 300.296 +			    &cert->pCertInfo->Subject,CERT_X500_NAME_STR,
 300.297 +			    certname,255);
 300.298 +				/* build certificate chain */
 300.299 +	  memset (&chparam,0,sizeof (chparam));
 300.300 +	  chparam.cbSize = sizeof (chparam);
 300.301 +	  chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
 300.302 +	  chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage;
 300.303 +	  chparam.RequestedUsage.Usage.cUsageIdentifier =
 300.304 +	    sizeof (usage) / sizeof (LPSTR);
 300.305 +	  if (!(*certGetCertificateChain)
 300.306 +	      (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain))
 300.307 +	    reason = ssl_analyze_status (GetLastError (),tmp);
 300.308 +	  else {		/* validate certificate chain */
 300.309 +	    memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
 300.310 +	    policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
 300.311 +	    policy.dwAuthType = AUTHTYPE_SERVER;
 300.312 +	    policy.fdwChecks = NIL;
 300.313 +	    policy.pwszServerName = whost;
 300.314 +	    memset (&polparam,0,sizeof (polparam));
 300.315 +	    polparam.cbSize = sizeof (polparam);
 300.316 +	    polparam.pvExtraPolicyPara = &policy;
 300.317 +	    memset (&status,0,sizeof (status));
 300.318 +	    status.cbSize = sizeof (status);
 300.319 +	    if (!(*certVerifyCertificateChainPolicy)
 300.320 +		(CERT_CHAIN_POLICY_SSL,chain,&polparam,&status))
 300.321 +	      reason = ssl_analyze_status (GetLastError (),tmp);
 300.322 +	    else if (status.dwError)
 300.323 +	      reason = ssl_analyze_status (status.dwError,tmp);
 300.324 +	    (*certFreeCertificateChain) (chain);
 300.325 +	  }
 300.326 +	  (*certFreeCertificateContext) (cert);
 300.327 +	}
 300.328 +	if (whost) fs_give ((void **) &whost);
 300.329 +
 300.330 +	if (reason) {		/* got an error? */
 300.331 +				/* application callback */
 300.332 +	  if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason,
 300.333 +				    host,certname) ? NIL : "";
 300.334 +	  else if (*certname) {	/* error message to return via mm_log() */
 300.335 +	    sprintf (buf,"*%.128s: %.255s",
 300.336 +		     (*reason == '*') ? reason + 1 : reason,certname);
 300.337 +	    reason = buf;
 300.338 +	  }
 300.339 +	}
 300.340 +      }
 300.341 +      if (reason ||
 300.342 +	  (reason = ssl_analyze_status
 300.343 +	   (sft->QueryContextAttributes
 300.344 +	    (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)))
 300.345 +	break;			/* error in certificate or getting sizes */
 300.346 +      fs_give ((void **) &buf);	/* flush temporary buffer */
 300.347 +				/* make maximum-sized buffers */
 300.348 +      stream->bufsize = stream->sizes.cbHeader +
 300.349 +	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
 300.350 +      if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
 300.351 +	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
 300.352 +      else if (stream->sizes.cbMaximumMessage < 16384) {
 300.353 +	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
 300.354 +		 (long) stream->sizes.cbMaximumMessage);
 300.355 +	mm_log (tmp,NIL);
 300.356 +      }
 300.357 +      stream->ibuf = (char *) fs_get (stream->bufsize);
 300.358 +      stream->obuf = (char *) fs_get (stream->bufsize);
 300.359 +      return stream;
 300.360 +    default:
 300.361 +      reason = ssl_analyze_status (e,buf);
 300.362 +    }
 300.363 +  }
 300.364 +  ssl_close (stream);		/* failed to do SSL */
 300.365 +  stream = NIL;			/* no stream returned */
 300.366 +  switch (*reason) {		/* analyze reason */
 300.367 +  case '*':			/* certificate failure */
 300.368 +    ++reason;			/* skip over certificate failure indication */
 300.369 +				/* pass to error callback */
 300.370 +    if (sf) (*sf) (host,reason,flags);
 300.371 +    else {			/* no error callback, build error message */
 300.372 +      sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
 300.373 +      mm_log (tmp,ERROR);
 300.374 +    }
 300.375 +  case '\0':			/* user answered no to certificate callback */
 300.376 +    if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
 300.377 +      stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 300.378 +				     sizeof (SSLSTREAM));
 300.379 +    break;
 300.380 +  default:			/* non-certificate failure */
 300.381 +    if (flags & NET_TRYSSL);	/* no error output if tryssl */
 300.382 +				/* pass to error callback */
 300.383 +    else if (sf) (*sf) (host,reason,flags);
 300.384 +    else {			/* no error callback, build error message */
 300.385 +      sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
 300.386 +      mm_log (tmp,ERROR);
 300.387 +    }
 300.388 +    break;
 300.389 +  }
 300.390 +  fs_give ((void **) &buf);	/* flush temporary buffer */
 300.391 +  return stream;
 300.392 +}
 300.393 +
 300.394 +/* Generate error text from SSL error code
 300.395 + * Accepts: SSL status
 300.396 + *	    scratch buffer
 300.397 + * Returns: text if error status, else NIL
 300.398 + */
 300.399 +
 300.400 +static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
 300.401 +{
 300.402 +  switch (err) {
 300.403 +  case SEC_E_OK:		/* no error */
 300.404 +  case SEC_I_CONTINUE_NEEDED:
 300.405 +  case SEC_I_INCOMPLETE_CREDENTIALS:
 300.406 +  case SEC_E_INCOMPLETE_MESSAGE:
 300.407 +    return NIL;
 300.408 +  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
 300.409 +    mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL);
 300.410 +    return "*No authority could be contacted for authentication";
 300.411 +  case SEC_E_WRONG_PRINCIPAL:
 300.412 +    mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL);
 300.413 +  case CERT_E_CN_NO_MATCH:
 300.414 +    return "*Server name does not match certificate";
 300.415 +  case SEC_E_UNTRUSTED_ROOT:
 300.416 +    mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL);
 300.417 +  case CERT_E_UNTRUSTEDROOT:
 300.418 +    return "*Self-signed certificate or untrusted authority";
 300.419 +  case SEC_E_CERT_EXPIRED:
 300.420 +    mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL);
 300.421 +  case CERT_E_EXPIRED:
 300.422 +    return "*Certificate has expired";
 300.423 +  case CERT_E_REVOKED:
 300.424 +    return "*Certificate revoked";
 300.425 +  case SEC_E_INVALID_TOKEN:
 300.426 +    return "Invalid token, probably not an SSL server";
 300.427 +  case SEC_E_UNSUPPORTED_FUNCTION:
 300.428 +    return "SSL not supported on this machine - upgrade your system software";
 300.429 +  }
 300.430 +  sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err);
 300.431 +  return buf;
 300.432 +}
 300.433 +
 300.434 +/* SSL receive line
 300.435 + * Accepts: SSL stream
 300.436 + * Returns: text line string or NIL if failure
 300.437 + */
 300.438 +
 300.439 +char *ssl_getline (SSLSTREAM *stream)
 300.440 +{
 300.441 +  unsigned long n,contd;
 300.442 +  char *ret = ssl_getline_work (stream,&n,&contd);
 300.443 +  if (ret && contd) {		/* got a line needing continuation? */
 300.444 +    STRINGLIST *stl = mail_newstringlist ();
 300.445 +    STRINGLIST *stc = stl;
 300.446 +    do {			/* collect additional lines */
 300.447 +      stc->text.data = (unsigned char *) ret;
 300.448 +      stc->text.size = n;
 300.449 +      stc = stc->next = mail_newstringlist ();
 300.450 +      ret = ssl_getline_work (stream,&n,&contd);
 300.451 +    } while (ret && contd);
 300.452 +    if (ret) {			/* stash final part of line on list */
 300.453 +      stc->text.data = (unsigned char *) ret;
 300.454 +      stc->text.size = n;
 300.455 +				/* determine how large a buffer we need */
 300.456 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 300.457 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 300.458 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 300.459 +	memcpy (ret + n,stc->text.data,stc->text.size);
 300.460 +      ret[n] = '\0';
 300.461 +    }
 300.462 +    mail_free_stringlist (&stl);/* either way, done with list */
 300.463 +  }
 300.464 +  return ret;
 300.465 +}
 300.466 +
 300.467 +/* SSL receive line or partial line
 300.468 + * Accepts: SSL stream
 300.469 + *	    pointer to return size
 300.470 + *	    pointer to return continuation flag
 300.471 + * Returns: text line string, size and continuation flag, or NIL if failure
 300.472 + */
 300.473 +
 300.474 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
 300.475 +			       long *contd)
 300.476 +{
 300.477 +  unsigned long n;
 300.478 +  char *s,*ret,c,d;
 300.479 +  *contd = NIL;			/* assume no continuation */
 300.480 +				/* make sure have data */
 300.481 +  if (!ssl_getdata (stream)) return NIL;
 300.482 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 300.483 +    d = *stream->iptr++;	/* slurp another character */
 300.484 +    if ((c == '\015') && (d == '\012')) {
 300.485 +      ret = (char *) fs_get (n--);
 300.486 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 300.487 +      ret[n] = '\0';		/* tie off string with null */
 300.488 +      return ret;
 300.489 +    }
 300.490 +  }
 300.491 +				/* copy partial string from buffer */
 300.492 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 300.493 +				/* get more data from the net */
 300.494 +  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
 300.495 +				/* special case of newline broken by buffer */
 300.496 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 300.497 +    stream->iptr++;		/* eat the line feed */
 300.498 +    stream->ictr--;
 300.499 +    ret[*size = --n] = '\0';	/* tie off string with null */
 300.500 +  }
 300.501 +  else *contd = LONGT;		/* continuation needed */
 300.502 +  return ret;
 300.503 +}
 300.504 +
 300.505 +/* SSL receive buffer
 300.506 + * Accepts: SSL stream
 300.507 + *	    size in bytes
 300.508 + *	    buffer to read into
 300.509 + * Returns: T if success, NIL otherwise
 300.510 + */
 300.511 +
 300.512 +long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
 300.513 +{
 300.514 +  unsigned long n;
 300.515 +  while (size > 0) {		/* until request satisfied */
 300.516 +    if (!ssl_getdata (stream)) return NIL;
 300.517 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 300.518 +				/* do the copy */
 300.519 +    memcpy (buffer,stream->iptr,n);
 300.520 +    buffer += n;		/* update pointer */
 300.521 +    stream->iptr += n;
 300.522 +    size -= n;			/* update # of bytes to do */
 300.523 +    stream->ictr -= n;
 300.524 +  }
 300.525 +  buffer[0] = '\0';		/* tie off string */
 300.526 +  return T;
 300.527 +}
 300.528 +
 300.529 +/* SSL receive data
 300.530 + * Accepts: TCP/IP stream
 300.531 + * Returns: T if success, NIL otherwise
 300.532 + */
 300.533 +
 300.534 +long ssl_getdata (SSLSTREAM *stream)
 300.535 +{
 300.536 +  while (stream->ictr < 1) {	/* decrypted buffer empty? */
 300.537 +    SECURITY_STATUS status;
 300.538 +    SecBuffer buf[4];
 300.539 +    SecBufferDesc msg;
 300.540 +    size_t i;
 300.541 +    size_t n = 0;		/* initially no bytes to decrypt */
 300.542 +    do {			/* yes, make sure have data from TCP */
 300.543 +      if (stream->iextractr) {	/* have previous unread data? */
 300.544 +	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
 300.545 +	n += stream->iextractr;	/* update number of bytes read */
 300.546 +	stream->iextractr = 0;	/* no more extra data */
 300.547 +      }
 300.548 +      else {			/* read from TCP */
 300.549 +	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
 300.550 +				/* maximum amount of data to copy */
 300.551 +	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
 300.552 +	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
 300.553 +				/* do the copy */
 300.554 +	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
 300.555 +	stream->tcpstream->iptr += i;
 300.556 +	stream->tcpstream->ictr -= i;
 300.557 +	n += i;			/* update number of bytes to decrypt */
 300.558 +      }
 300.559 +      buf[0].cbBuffer = n;	/* first SecBuffer gets data */
 300.560 +      buf[0].pvBuffer = stream->ibuf;
 300.561 +      buf[0].BufferType = SECBUFFER_DATA;
 300.562 +				/* subsequent ones are for spares */
 300.563 +      buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
 300.564 +	SECBUFFER_EMPTY;
 300.565 +      msg.ulVersion = SECBUFFER_VERSION;
 300.566 +      msg.cBuffers = 4;		/* number of SecBuffers */
 300.567 +      msg.pBuffers = buf;	/* first SecBuffer */
 300.568 +
 300.569 +    } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4)
 300.570 +	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
 300.571 +    switch (status) {
 300.572 +    case SEC_E_OK:		/* won */
 300.573 +    case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
 300.574 +				/* hunt for a buffer */
 300.575 +      for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
 300.576 +      if (i < 4) {		/* found a buffer? */
 300.577 +				/* yes, set up pointer and counter */
 300.578 +	stream->iptr = buf[i].pvBuffer;
 300.579 +	stream->ictr = buf[i].cbBuffer;
 300.580 +				/* any unprocessed data? */
 300.581 +	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
 300.582 +				/* yes, note for next time around */
 300.583 +	  stream->iextraptr = buf[i].pvBuffer;
 300.584 +	  stream->iextractr = buf[i].cbBuffer;
 300.585 +	}
 300.586 +      }
 300.587 +      break;
 300.588 +    default:			/* anything else means we've lost */
 300.589 +      return ssl_abort (stream);
 300.590 +    }
 300.591 +  }
 300.592 +  return LONGT;
 300.593 +}
 300.594 +
 300.595 +/* SSL send string as record
 300.596 + * Accepts: SSL stream
 300.597 + *	    string pointer
 300.598 + * Returns: T if success else NIL
 300.599 + */
 300.600 +
 300.601 +long ssl_soutr (SSLSTREAM *stream,char *string)
 300.602 +{
 300.603 +  return ssl_sout (stream,string,(unsigned long) strlen (string));
 300.604 +}
 300.605 +
 300.606 +
 300.607 +/* SSL send string
 300.608 + * Accepts: SSL stream
 300.609 + *	    string pointer
 300.610 + *	    byte count
 300.611 + * Returns: T if success else NIL
 300.612 + */
 300.613 +
 300.614 +long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
 300.615 +{
 300.616 +  SecBuffer buf[4];
 300.617 +  SecBufferDesc msg;
 300.618 +  char *s;
 300.619 +  size_t n;
 300.620 +  if (!stream->tcpstream) return NIL;
 300.621 +				/* until request satisfied */
 300.622 +  for (s = stream->ibuf,n = 0; size;) {
 300.623 +				/* header */
 300.624 +    buf[0].BufferType = SECBUFFER_STREAM_HEADER;
 300.625 +    memset (buf[0].pvBuffer = stream->obuf,0,
 300.626 +	    buf[0].cbBuffer = stream->sizes.cbHeader);
 300.627 +				/* message (up to maximum size) */
 300.628 +    buf[1].BufferType = SECBUFFER_DATA;
 300.629 +    memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
 300.630 +	    buf[1].cbBuffer = min (size,SSLBUFLEN));
 300.631 +				/* trailer */
 300.632 +    buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
 300.633 +    memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
 300.634 +	    buf[2].cbBuffer = stream->sizes.cbTrailer);
 300.635 +				/* spare */
 300.636 +    buf[3].BufferType = SECBUFFER_EMPTY;
 300.637 +    msg.ulVersion = SECBUFFER_VERSION;
 300.638 +    msg.cBuffers = 4;		/* number of SecBuffers */
 300.639 +    msg.pBuffers = buf;		/* first SecBuffer */
 300.640 +    string += buf[1].cbBuffer;
 300.641 +    size -= buf[1].cbBuffer;	/* this many bytes processed */
 300.642 +				/* encrypt and send message */
 300.643 +    if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3)
 300.644 +	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
 300.645 +	!tcp_sout (stream->tcpstream,stream->obuf,
 300.646 +		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
 300.647 +      return ssl_abort (stream);/* encryption or sending failed */
 300.648 +  }
 300.649 +  return LONGT;
 300.650 +}
 300.651 +
 300.652 +/* SSL close
 300.653 + * Accepts: SSL stream
 300.654 + */
 300.655 +
 300.656 +void ssl_close (SSLSTREAM *stream)
 300.657 +{
 300.658 +  ssl_abort (stream);		/* nuke the stream */
 300.659 +  fs_give ((void **) &stream);	/* flush the stream */
 300.660 +}
 300.661 +
 300.662 +
 300.663 +/* SSL abort stream
 300.664 + * Accepts: SSL stream
 300.665 + * Returns: NIL always
 300.666 + */
 300.667 +
 300.668 +static long ssl_abort (SSLSTREAM *stream)
 300.669 +{
 300.670 +  if (stream->tcpstream) {	/* close TCP stream */
 300.671 +    sft->DeleteSecurityContext (&stream->context);
 300.672 +    sft->FreeCredentialHandle (&stream->cred);
 300.673 +    tcp_close (stream->tcpstream);
 300.674 +    stream->tcpstream = NIL;
 300.675 +  }
 300.676 +  if (stream->ibuf) fs_give ((void **) &stream->ibuf);
 300.677 +  if (stream->obuf) fs_give ((void **) &stream->obuf);
 300.678 +  return NIL;
 300.679 +}
 300.680 +
 300.681 +/* SSL get host name
 300.682 + * Accepts: SSL stream
 300.683 + * Returns: host name for this stream
 300.684 + */
 300.685 +
 300.686 +char *ssl_host (SSLSTREAM *stream)
 300.687 +{
 300.688 +  return tcp_host (stream->tcpstream);
 300.689 +}
 300.690 +
 300.691 +
 300.692 +/* SSL get remote host name
 300.693 + * Accepts: SSL stream
 300.694 + * Returns: host name for this stream
 300.695 + */
 300.696 +
 300.697 +char *ssl_remotehost (SSLSTREAM *stream)
 300.698 +{
 300.699 +  return tcp_remotehost (stream->tcpstream);
 300.700 +}
 300.701 +
 300.702 +
 300.703 +/* SSL return port for this stream
 300.704 + * Accepts: SSL stream
 300.705 + * Returns: port number for this stream
 300.706 + */
 300.707 +
 300.708 +unsigned long ssl_port (SSLSTREAM *stream)
 300.709 +{
 300.710 +  return tcp_port (stream->tcpstream);
 300.711 +}
 300.712 +
 300.713 +
 300.714 +/* SSL get local host name
 300.715 + * Accepts: SSL stream
 300.716 + * Returns: local host name
 300.717 + */
 300.718 +
 300.719 +char *ssl_localhost (SSLSTREAM *stream)
 300.720 +{
 300.721 +  return tcp_localhost (stream->tcpstream);
 300.722 +}
 300.723 +
 300.724 +#include "ssl_none.c"		/* currently no server support */
   301.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   301.2 +++ b/src/osdep/nt/ssl_old.c	Mon Sep 14 15:17:45 2009 +0900
   301.3 @@ -0,0 +1,625 @@
   301.4 +/* ========================================================================
   301.5 + * Copyright 1988-2008 University of Washington
   301.6 + *
   301.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   301.8 + * you may not use this file except in compliance with the License.
   301.9 + * You may obtain a copy of the License at
  301.10 + *
  301.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  301.12 + *
  301.13 + * 
  301.14 + * ========================================================================
  301.15 + */
  301.16 +
  301.17 +/*
  301.18 + * Program:	SSL authentication/encryption module for Windows 9x and NT
  301.19 + *
  301.20 + * Author:	Mark Crispin
  301.21 + *		Networks and Distributed Computing
  301.22 + *		Computing & Communications
  301.23 + *		University of Washington
  301.24 + *		Administration Building, AG-44
  301.25 + *		Seattle, WA  98195
  301.26 + *		Internet: MRC@CAC.Washington.EDU
  301.27 + *
  301.28 + * Date:	22 September 1998
  301.29 + * Last Edited:	13 January 2008
  301.30 + */
  301.31 +
  301.32 +#define SECURITY_WIN32
  301.33 +#include <sspi.h>
  301.34 +#if(_WIN32_WINNT < 0x0400)
  301.35 +typedef unsigned int ALG_ID;
  301.36 +#else
  301.37 +#include <wincrypt.h>
  301.38 +ALGIDDEF
  301.39 +#endif
  301.40 +#include <schnlsp.h>
  301.41 +#include <issperr.h>
  301.42 +
  301.43 +				/* in case a binary runs on Windows 2000 */
  301.44 +#ifndef ISC_REQ_MANUAL_CRED_VALIDATION
  301.45 +#define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000
  301.46 +#endif
  301.47 +#ifndef SEC_E_UNTRUSTED_ROOT
  301.48 +#define SEC_E_UNTRUSTED_ROOT ((HRESULT) 0x80090325L)
  301.49 +#endif
  301.50 +#ifndef SEC_E_CERT_EXPIRED
  301.51 +#define SEC_E_CERT_EXPIRED ((HRESULT) 0x80090328L)
  301.52 +#endif
  301.53 +
  301.54 +
  301.55 +#define SSLBUFLEN 8192
  301.56 +
  301.57 +
  301.58 +/* SSL I/O stream */
  301.59 +
  301.60 +typedef struct ssl_stream {
  301.61 +  TCPSTREAM *tcpstream;		/* TCP stream */
  301.62 +  CredHandle cred;		/* SSL credentials */
  301.63 +  CtxtHandle context;		/* SSL context */
  301.64 +				/* stream encryption sizes */
  301.65 +  SecPkgContext_StreamSizes sizes;
  301.66 +  size_t bufsize;
  301.67 +  int ictr;			/* input counter */
  301.68 +  char *iptr;			/* input pointer */
  301.69 +  int iextractr;		/* extra input counter */
  301.70 +  char *iextraptr;		/* extra input pointer */
  301.71 +  char *ibuf;			/* input buffer */
  301.72 +  char *obuf;			/* output buffer */
  301.73 +} SSLSTREAM;
  301.74 +
  301.75 +#include "sslio.h"
  301.76 +
  301.77 +
  301.78 +/* Function prototypes */
  301.79 +
  301.80 +static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
  301.81 +static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
  301.82 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
  301.83 +			       long *contd);
  301.84 +static long ssl_abort (SSLSTREAM *stream);
  301.85 +
  301.86 +/* Secure Sockets Layer network driver dispatch */
  301.87 +
  301.88 +static struct ssl_driver ssldriver = {
  301.89 +  ssl_open,			/* open connection */
  301.90 +  ssl_aopen,			/* open preauthenticated connection */
  301.91 +  ssl_getline,			/* get a line */
  301.92 +  ssl_getbuffer,		/* get a buffer */
  301.93 +  ssl_soutr,			/* output pushed data */
  301.94 +  ssl_sout,			/* output string */
  301.95 +  ssl_close,			/* close connection */
  301.96 +  ssl_host,			/* return host name */
  301.97 +  ssl_remotehost,		/* return remote host name */
  301.98 +  ssl_port,			/* return port number */
  301.99 +  ssl_localhost			/* return local host name */
 301.100 +};
 301.101 +
 301.102 +				/* security function table */
 301.103 +static SecurityFunctionTable *sft = NIL;
 301.104 +static unsigned long ssltsz = 0;/* SSL maximum token length */
 301.105 +
 301.106 +/* One-time SSL initialization */
 301.107 +
 301.108 +static int sslonceonly = 0;
 301.109 +
 301.110 +void ssl_onceonlyinit (void)
 301.111 +{
 301.112 +  if (!sslonceonly++) {		/* only need to call it once */
 301.113 +    HINSTANCE lib;
 301.114 +    FARPROC pi;
 301.115 +    ULONG np;
 301.116 +    SecPkgInfo *pp;
 301.117 +    int i;
 301.118 +				/* get security library */
 301.119 +    if (((lib = LoadLibrary ("schannel.dll")) ||
 301.120 +	 (lib = LoadLibrary ("security.dll"))) &&
 301.121 +	(pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) &&
 301.122 +	(sft = (SecurityFunctionTable *) pi ()) &&
 301.123 +	!(sft->EnumerateSecurityPackages (&np,&pp))) {
 301.124 +				/* look for an SSL package */
 301.125 +      for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
 301.126 +				/* note maximum token size and name */
 301.127 +	ssltsz = pp[i].cbMaxToken;
 301.128 +				/* apply runtime linkage */
 301.129 +	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
 301.130 +	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
 301.131 +	return;			/* all done */
 301.132 +      }
 301.133 +    }
 301.134 +  }
 301.135 +}
 301.136 +
 301.137 +/* SSL open
 301.138 + * Accepts: host name
 301.139 + *	    contact service name
 301.140 + *	    contact port number
 301.141 + * Returns: SSL stream if success else NIL
 301.142 + */
 301.143 +
 301.144 +SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
 301.145 +{
 301.146 +  TCPSTREAM *stream = tcp_open (host,service,port);
 301.147 +  return stream ? ssl_start (stream,host,port) : NIL;
 301.148 +}
 301.149 +
 301.150 +  
 301.151 +/* SSL authenticated open
 301.152 + * Accepts: host name
 301.153 + *	    service name
 301.154 + *	    returned user name buffer
 301.155 + * Returns: SSL stream if success else NIL
 301.156 + */
 301.157 +
 301.158 +SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
 301.159 +{
 301.160 +  return NIL;			/* don't use this mechanism with SSL */
 301.161 +}
 301.162 +
 301.163 +/* Start SSL/TLS negotiations
 301.164 + * Accepts: open TCP stream of session
 301.165 + *	    user's host name
 301.166 + *	    flags
 301.167 + * Returns: SSL stream if success else NIL
 301.168 + */
 301.169 +
 301.170 +static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
 301.171 +{
 301.172 +  SECURITY_STATUS e;
 301.173 +  ULONG a;
 301.174 +  TimeStamp t;
 301.175 +  SecBuffer ibuf[2],obuf[1];
 301.176 +  SecBufferDesc ibufs,obufs;
 301.177 +  char tmp[MAILTMPLEN];
 301.178 +  char *reason = NIL;
 301.179 +  ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
 301.180 +    ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
 301.181 +      ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR +
 301.182 +	((flags & NET_NOVALIDATECERT) ? ISC_REQ_MANUAL_CRED_VALIDATION :
 301.183 +	 ISC_REQ_MUTUAL_AUTH);
 301.184 +  SCHANNEL_CRED tlscred;
 301.185 +  char *buf = (char *) fs_get (ssltsz);
 301.186 +  unsigned long size = 0;
 301.187 +  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
 301.188 +  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 301.189 +					    sizeof (SSLSTREAM));
 301.190 +  stream->tcpstream = tstream;	/* bind TCP stream */
 301.191 +				/* initialize TLS credential */
 301.192 +  memset (&tlscred,0,sizeof (SCHANNEL_CRED));
 301.193 +  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
 301.194 +  tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
 301.195 +
 301.196 +				/* acquire credentials */
 301.197 +  if (sft->AcquireCredentialsHandle
 301.198 +      (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
 301.199 +       &tlscred : NIL,NIL,NIL,&stream->cred,&t)
 301.200 +      != SEC_E_OK) reason = "Acquire credentials handle failed";
 301.201 +  else while (!reason) {	/* negotiate security context */
 301.202 +				/* initialize buffers */
 301.203 +    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
 301.204 +    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
 301.205 +    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
 301.206 +    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
 301.207 +    ibuf[1].BufferType = SECBUFFER_EMPTY;
 301.208 +				/* initialize buffer descriptors */
 301.209 +    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
 301.210 +    ibufs.cBuffers = 2; obufs.cBuffers = 1;
 301.211 +    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
 301.212 +				/* negotiate security */
 301.213 +    e = sft->InitializeSecurityContext
 301.214 +      (&stream->cred,size ? &stream->context : NIL,host,req,0,
 301.215 +       SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
 301.216 +				/* have an output buffer we need to send? */
 301.217 +    if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
 301.218 +      if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
 301.219 +	reason = "Unexpected TCP output disconnect";
 301.220 +				/* free the buffer */
 301.221 +      sft->FreeContextBuffer (obuf[0].pvBuffer);
 301.222 +    }
 301.223 +    if (!reason) switch (e) {	/* negotiation state */
 301.224 +    case SEC_I_INCOMPLETE_CREDENTIALS:
 301.225 +      break;			/* server wants client auth */
 301.226 +    case SEC_I_CONTINUE_NEEDED:
 301.227 +      if (size) {		/* continue, read any data? */
 301.228 +				/* yes, anything regurgiated back to us? */
 301.229 +	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
 301.230 +				/* yes, set this as the new data */
 301.231 +	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
 301.232 +	  size = ibuf[1].cbBuffer;
 301.233 +	  break;
 301.234 +	}
 301.235 +	size = 0;		/* otherwise, read more stuff from server */
 301.236 +      }
 301.237 +    case SEC_E_INCOMPLETE_MESSAGE:
 301.238 +				/* need to read more data from server */
 301.239 +      if (!tcp_getdata (stream->tcpstream))
 301.240 +	reason = "Unexpected TCP input disconnect";
 301.241 +      else {
 301.242 +	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
 301.243 +	size += stream->tcpstream->ictr;
 301.244 +				/* empty it from TCP's buffers */
 301.245 +	stream->tcpstream->iptr += stream->tcpstream->ictr;
 301.246 +	stream->tcpstream->ictr = 0;
 301.247 +      }
 301.248 +      break;
 301.249 +
 301.250 +    case SEC_E_OK:		/* success, any data to be regurgitated? */
 301.251 +      if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
 301.252 +				/* yes, set this as the new data */
 301.253 +	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
 301.254 +		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
 301.255 +	stream->tcpstream->ictr = ibuf[1].cbBuffer;
 301.256 +      }
 301.257 +      if (reason = ssl_analyze_status
 301.258 +	  (sft->QueryContextAttributes
 301.259 +	   (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))
 301.260 +	break;			/* error getting sizes */
 301.261 +      fs_give ((void **) &buf);	/* flush temporary buffer */
 301.262 +				/* make maximum-sized buffers */
 301.263 +      stream->bufsize = stream->sizes.cbHeader +
 301.264 +	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
 301.265 +      if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
 301.266 +	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
 301.267 +      else if (stream->sizes.cbMaximumMessage < 16384) {
 301.268 +	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
 301.269 +		 (long) stream->sizes.cbMaximumMessage);
 301.270 +	mm_log (tmp,NIL);
 301.271 +      }
 301.272 +      stream->ibuf = (char *) fs_get (stream->bufsize);
 301.273 +      stream->obuf = (char *) fs_get (stream->bufsize);
 301.274 +      return stream;
 301.275 +    default:
 301.276 +      reason = ssl_analyze_status (e,buf);
 301.277 +    }
 301.278 +  }
 301.279 +  ssl_close (stream);		/* failed to do SSL */
 301.280 +  stream = NIL;			/* no stream returned */
 301.281 +  fs_give ((void **) &buf);	/* flush temporary buffer */
 301.282 +  switch (*reason) {		/* analyze reason */
 301.283 +  case '*':			/* certificate failure */
 301.284 +    ++reason;			/* skip over certificate failure indication */
 301.285 +				/* pass to error callback */
 301.286 +    if (sf) (*sf) (host,reason,flags);
 301.287 +    else {			/* no error callback, build error message */
 301.288 +      sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
 301.289 +      mm_log (tmp,ERROR);
 301.290 +    }
 301.291 +  case '\0':			/* user answered no to certificate callback */
 301.292 +    if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
 301.293 +      stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 301.294 +				     sizeof (SSLSTREAM));
 301.295 +    break;
 301.296 +  default:			/* non-certificate failure */
 301.297 +    if (flags & NET_TRYSSL);	/* no error output if tryssl */
 301.298 +				/* pass to error callback */
 301.299 +    else if (sf) (*sf) (host,reason,flags);
 301.300 +    else {			/* no error callback, build error message */
 301.301 +      sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
 301.302 +      mm_log (tmp,ERROR);
 301.303 +    }
 301.304 +    break;
 301.305 +  }
 301.306 +  return stream;
 301.307 +}
 301.308 +
 301.309 +/* Generate error text from SSL error code
 301.310 + * Accepts: SSL status
 301.311 + *	    scratch buffer
 301.312 + * Returns: text if error status, else NIL
 301.313 + */
 301.314 +
 301.315 +static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
 301.316 +{
 301.317 +  switch (err) {
 301.318 +  case SEC_E_OK:		/* no error */
 301.319 +  case SEC_I_CONTINUE_NEEDED:
 301.320 +  case SEC_I_INCOMPLETE_CREDENTIALS:
 301.321 +  case SEC_E_INCOMPLETE_MESSAGE:
 301.322 +    return NIL;
 301.323 +  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
 301.324 +    return "*No authority could be contacted for authentication";
 301.325 +  case SEC_E_WRONG_PRINCIPAL:
 301.326 +    return "*Server name does not match certificate";
 301.327 +  case SEC_E_UNTRUSTED_ROOT:
 301.328 +    return "*Self-signed certificate or untrusted authority";
 301.329 +  case SEC_E_CERT_EXPIRED:
 301.330 +    return "*Certificate has expired";
 301.331 +  case SEC_E_INVALID_TOKEN:
 301.332 +    return "Invalid token, probably not an SSL server";
 301.333 +  case SEC_E_UNSUPPORTED_FUNCTION:
 301.334 +    return "SSL not supported on this machine - upgrade your system software";
 301.335 +  }
 301.336 +  sprintf (buf,"Unexpected SChannel error %lx - report this",err);
 301.337 +  return buf;
 301.338 +}
 301.339 +
 301.340 +/* SSL receive line
 301.341 + * Accepts: SSL stream
 301.342 + * Returns: text line string or NIL if failure
 301.343 + */
 301.344 +
 301.345 +char *ssl_getline (SSLSTREAM *stream)
 301.346 +{
 301.347 +  unsigned long n,contd;
 301.348 +  char *ret = ssl_getline_work (stream,&n,&contd);
 301.349 +  if (ret && contd) {		/* got a line needing continuation? */
 301.350 +    STRINGLIST *stl = mail_newstringlist ();
 301.351 +    STRINGLIST *stc = stl;
 301.352 +    do {			/* collect additional lines */
 301.353 +      stc->text.data = (unsigned char *) ret;
 301.354 +      stc->text.size = n;
 301.355 +      stc = stc->next = mail_newstringlist ();
 301.356 +      ret = ssl_getline_work (stream,&n,&contd);
 301.357 +    } while (ret && contd);
 301.358 +    if (ret) {			/* stash final part of line on list */
 301.359 +      stc->text.data = (unsigned char *) ret;
 301.360 +      stc->text.size = n;
 301.361 +				/* determine how large a buffer we need */
 301.362 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 301.363 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 301.364 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 301.365 +	memcpy (ret + n,stc->text.data,stc->text.size);
 301.366 +      ret[n] = '\0';
 301.367 +    }
 301.368 +    mail_free_stringlist (&stl);/* either way, done with list */
 301.369 +  }
 301.370 +  return ret;
 301.371 +}
 301.372 +
 301.373 +/* SSL receive line or partial line
 301.374 + * Accepts: SSL stream
 301.375 + *	    pointer to return size
 301.376 + *	    pointer to return continuation flag
 301.377 + * Returns: text line string, size and continuation flag, or NIL if failure
 301.378 + */
 301.379 +
 301.380 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
 301.381 +			       long *contd)
 301.382 +{
 301.383 +  unsigned long n;
 301.384 +  char *s,*ret,c,d;
 301.385 +  *contd = NIL;			/* assume no continuation */
 301.386 +				/* make sure have data */
 301.387 +  if (!ssl_getdata (stream)) return NIL;
 301.388 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 301.389 +    d = *stream->iptr++;	/* slurp another character */
 301.390 +    if ((c == '\015') && (d == '\012')) {
 301.391 +      ret = (char *) fs_get (n--);
 301.392 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 301.393 +      ret[n] = '\0';		/* tie off string with null */
 301.394 +      return ret;
 301.395 +    }
 301.396 +  }
 301.397 +				/* copy partial string from buffer */
 301.398 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 301.399 +				/* get more data from the net */
 301.400 +  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
 301.401 +				/* special case of newline broken by buffer */
 301.402 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 301.403 +    stream->iptr++;		/* eat the line feed */
 301.404 +    stream->ictr--;
 301.405 +    ret[*size = --n] = '\0';	/* tie off string with null */
 301.406 +  }
 301.407 +  else *contd = LONGT;		/* continuation needed */
 301.408 +  return ret;
 301.409 +}
 301.410 +
 301.411 +/* SSL receive buffer
 301.412 + * Accepts: SSL stream
 301.413 + *	    size in bytes
 301.414 + *	    buffer to read into
 301.415 + * Returns: T if success, NIL otherwise
 301.416 + */
 301.417 +
 301.418 +long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
 301.419 +{
 301.420 +  unsigned long n;
 301.421 +  while (size > 0) {		/* until request satisfied */
 301.422 +    if (!ssl_getdata (stream)) return NIL;
 301.423 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 301.424 +				/* do the copy */
 301.425 +    memcpy (buffer,stream->iptr,n);
 301.426 +    buffer += n;		/* update pointer */
 301.427 +    stream->iptr += n;
 301.428 +    size -= n;			/* update # of bytes to do */
 301.429 +    stream->ictr -= n;
 301.430 +  }
 301.431 +  buffer[0] = '\0';		/* tie off string */
 301.432 +  return T;
 301.433 +}
 301.434 +
 301.435 +/* SSL receive data
 301.436 + * Accepts: TCP/IP stream
 301.437 + * Returns: T if success, NIL otherwise
 301.438 + */
 301.439 +
 301.440 +long ssl_getdata (SSLSTREAM *stream)
 301.441 +{
 301.442 +  while (stream->ictr < 1) {	/* decrypted buffer empty? */
 301.443 +    SECURITY_STATUS status;
 301.444 +    SecBuffer buf[4];
 301.445 +    SecBufferDesc msg;
 301.446 +    size_t i;
 301.447 +    size_t n = 0;		/* initially no bytes to decrypt */
 301.448 +    do {			/* yes, make sure have data from TCP */
 301.449 +      if (stream->iextractr) {	/* have previous unread data? */
 301.450 +	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
 301.451 +	n += stream->iextractr;	/* update number of bytes read */
 301.452 +	stream->iextractr = 0;	/* no more extra data */
 301.453 +      }
 301.454 +      else {			/* read from TCP */
 301.455 +	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
 301.456 +				/* maximum amount of data to copy */
 301.457 +	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
 301.458 +	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
 301.459 +				/* do the copy */
 301.460 +	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
 301.461 +	stream->tcpstream->iptr += i;
 301.462 +	stream->tcpstream->ictr -= i;
 301.463 +	n += i;			/* update number of bytes to decrypt */
 301.464 +      }
 301.465 +      buf[0].cbBuffer = n;	/* first SecBuffer gets data */
 301.466 +      buf[0].pvBuffer = stream->ibuf;
 301.467 +      buf[0].BufferType = SECBUFFER_DATA;
 301.468 +				/* subsequent ones are for spares */
 301.469 +      buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
 301.470 +	SECBUFFER_EMPTY;
 301.471 +      msg.ulVersion = SECBUFFER_VERSION;
 301.472 +      msg.cBuffers = 4;		/* number of SecBuffers */
 301.473 +      msg.pBuffers = buf;	/* first SecBuffer */
 301.474 +
 301.475 +    } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4)
 301.476 +	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
 301.477 +    switch (status) {
 301.478 +    case SEC_E_OK:		/* won */
 301.479 +    case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
 301.480 +				/* hunt for a buffer */
 301.481 +      for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
 301.482 +      if (i < 4) {		/* found a buffer? */
 301.483 +				/* yes, set up pointer and counter */
 301.484 +	stream->iptr = buf[i].pvBuffer;
 301.485 +	stream->ictr = buf[i].cbBuffer;
 301.486 +				/* any unprocessed data? */
 301.487 +	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
 301.488 +				/* yes, note for next time around */
 301.489 +	  stream->iextraptr = buf[i].pvBuffer;
 301.490 +	  stream->iextractr = buf[i].cbBuffer;
 301.491 +	}
 301.492 +      }
 301.493 +      break;
 301.494 +    default:			/* anything else means we've lost */
 301.495 +      return ssl_abort (stream);
 301.496 +    }
 301.497 +  }
 301.498 +  return LONGT;
 301.499 +}
 301.500 +
 301.501 +/* SSL send string as record
 301.502 + * Accepts: SSL stream
 301.503 + *	    string pointer
 301.504 + * Returns: T if success else NIL
 301.505 + */
 301.506 +
 301.507 +long ssl_soutr (SSLSTREAM *stream,char *string)
 301.508 +{
 301.509 +  return ssl_sout (stream,string,(unsigned long) strlen (string));
 301.510 +}
 301.511 +
 301.512 +
 301.513 +/* SSL send string
 301.514 + * Accepts: SSL stream
 301.515 + *	    string pointer
 301.516 + *	    byte count
 301.517 + * Returns: T if success else NIL
 301.518 + */
 301.519 +
 301.520 +long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
 301.521 +{
 301.522 +  SecBuffer buf[4];
 301.523 +  SecBufferDesc msg;
 301.524 +  char *s = stream->ibuf;
 301.525 +  size_t n = 0;
 301.526 +  while (size) {		/* until satisfied request */
 301.527 +				/* header */
 301.528 +    buf[0].BufferType = SECBUFFER_STREAM_HEADER;
 301.529 +    memset (buf[0].pvBuffer = stream->obuf,0,
 301.530 +	    buf[0].cbBuffer = stream->sizes.cbHeader);
 301.531 +				/* message (up to maximum size) */
 301.532 +    buf[1].BufferType = SECBUFFER_DATA;
 301.533 +    memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
 301.534 +	    buf[1].cbBuffer = min (size,SSLBUFLEN));
 301.535 +				/* trailer */
 301.536 +    buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
 301.537 +    memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
 301.538 +	    buf[2].cbBuffer = stream->sizes.cbTrailer);
 301.539 +				/* spare */
 301.540 +    buf[3].BufferType = SECBUFFER_EMPTY;
 301.541 +    msg.ulVersion = SECBUFFER_VERSION;
 301.542 +    msg.cBuffers = 4;		/* number of SecBuffers */
 301.543 +    msg.pBuffers = buf;		/* first SecBuffer */
 301.544 +    string += buf[1].cbBuffer;
 301.545 +    size -= buf[1].cbBuffer;	/* this many bytes processed */
 301.546 +				/* encrypt and send message */
 301.547 +    if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3)
 301.548 +	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
 301.549 +	!tcp_sout (stream->tcpstream,stream->obuf,
 301.550 +		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
 301.551 +      return ssl_abort (stream);/* encryption or sending failed */
 301.552 +  }
 301.553 +  return LONGT;
 301.554 +}
 301.555 +
 301.556 +/* SSL close
 301.557 + * Accepts: SSL stream
 301.558 + */
 301.559 +
 301.560 +void ssl_close (SSLSTREAM *stream)
 301.561 +{
 301.562 +  ssl_abort (stream);		/* nuke the stream */
 301.563 +  fs_give ((void **) &stream);	/* flush the stream */
 301.564 +}
 301.565 +
 301.566 +
 301.567 +/* SSL abort stream
 301.568 + * Accepts: SSL stream
 301.569 + * Returns: NIL always
 301.570 + */
 301.571 +
 301.572 +static long ssl_abort (SSLSTREAM *stream)
 301.573 +{
 301.574 +  if (stream->tcpstream) {	/* close TCP stream */
 301.575 +    sft->DeleteSecurityContext (&stream->context);
 301.576 +    sft->FreeCredentialHandle (&stream->cred);
 301.577 +    tcp_close (stream->tcpstream);
 301.578 +    stream->tcpstream = NIL;
 301.579 +  }
 301.580 +  if (stream->ibuf) fs_give ((void **) &stream->ibuf);
 301.581 +  if (stream->obuf) fs_give ((void **) &stream->obuf);
 301.582 +  return NIL;
 301.583 +}
 301.584 +
 301.585 +/* SSL get host name
 301.586 + * Accepts: SSL stream
 301.587 + * Returns: host name for this stream
 301.588 + */
 301.589 +
 301.590 +char *ssl_host (SSLSTREAM *stream)
 301.591 +{
 301.592 +  return tcp_host (stream->tcpstream);
 301.593 +}
 301.594 +
 301.595 +
 301.596 +/* SSL get remote host name
 301.597 + * Accepts: SSL stream
 301.598 + * Returns: host name for this stream
 301.599 + */
 301.600 +
 301.601 +char *ssl_remotehost (SSLSTREAM *stream)
 301.602 +{
 301.603 +  return tcp_remotehost (stream->tcpstream);
 301.604 +}
 301.605 +
 301.606 +
 301.607 +/* SSL return port for this stream
 301.608 + * Accepts: SSL stream
 301.609 + * Returns: port number for this stream
 301.610 + */
 301.611 +
 301.612 +unsigned long ssl_port (SSLSTREAM *stream)
 301.613 +{
 301.614 +  return tcp_port (stream->tcpstream);
 301.615 +}
 301.616 +
 301.617 +
 301.618 +/* SSL get local host name
 301.619 + * Accepts: SSL stream
 301.620 + * Returns: local host name
 301.621 + */
 301.622 +
 301.623 +char *ssl_localhost (SSLSTREAM *stream)
 301.624 +{
 301.625 +  return tcp_localhost (stream->tcpstream);
 301.626 +}
 301.627 +
 301.628 +#include "ssl_none.c"		/* currently no server support */
   302.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   302.2 +++ b/src/osdep/nt/ssl_w2k.c	Mon Sep 14 15:17:45 2009 +0900
   302.3 @@ -0,0 +1,683 @@
   302.4 +/* ========================================================================
   302.5 + * Copyright 1988-2008 University of Washington
   302.6 + *
   302.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   302.8 + * you may not use this file except in compliance with the License.
   302.9 + * You may obtain a copy of the License at
  302.10 + *
  302.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  302.12 + *
  302.13 + * 
  302.14 + * ========================================================================
  302.15 + */
  302.16 +
  302.17 +/*
  302.18 + * Program:	SSL authentication/encryption module for Windows 2000
  302.19 + *
  302.20 + * Author:	Mark Crispin
  302.21 + *		Networks and Distributed Computing
  302.22 + *		Computing & Communications
  302.23 + *		University of Washington
  302.24 + *		Administration Building, AG-44
  302.25 + *		Seattle, WA  98195
  302.26 + *		Internet: MRC@CAC.Washington.EDU
  302.27 + *
  302.28 + * Date:	22 September 1998
  302.29 + * Last Edited:	13 January 2008
  302.30 + */
  302.31 +
  302.32 +#define SECURITY_WIN32
  302.33 +#include <sspi.h>
  302.34 +#include <schannel.h>
  302.35 +
  302.36 +
  302.37 +#define SSLBUFLEN 8192
  302.38 +
  302.39 +
  302.40 +/* SSL I/O stream */
  302.41 +
  302.42 +typedef struct ssl_stream {
  302.43 +  TCPSTREAM *tcpstream;		/* TCP stream */
  302.44 +  CredHandle cred;		/* SSL credentials */
  302.45 +  CtxtHandle context;		/* SSL context */
  302.46 +				/* stream encryption sizes */
  302.47 +  SecPkgContext_StreamSizes sizes;
  302.48 +  size_t bufsize;
  302.49 +  int ictr;			/* input counter */
  302.50 +  char *iptr;			/* input pointer */
  302.51 +  int iextractr;		/* extra input counter */
  302.52 +  char *iextraptr;		/* extra input pointer */
  302.53 +  char *ibuf;			/* input buffer */
  302.54 +  char *obuf;			/* output buffer */
  302.55 +} SSLSTREAM;
  302.56 +
  302.57 +#include "sslio.h"
  302.58 +
  302.59 +
  302.60 +/* Function prototypes */
  302.61 +
  302.62 +static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
  302.63 +static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
  302.64 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
  302.65 +			       long *contd);
  302.66 +static long ssl_abort (SSLSTREAM *stream);
  302.67 +
  302.68 +/* Secure Sockets Layer network driver dispatch */
  302.69 +
  302.70 +static struct ssl_driver ssldriver = {
  302.71 +  ssl_open,			/* open connection */
  302.72 +  ssl_aopen,			/* open preauthenticated connection */
  302.73 +  ssl_getline,			/* get a line */
  302.74 +  ssl_getbuffer,		/* get a buffer */
  302.75 +  ssl_soutr,			/* output pushed data */
  302.76 +  ssl_sout,			/* output string */
  302.77 +  ssl_close,			/* close connection */
  302.78 +  ssl_host,			/* return host name */
  302.79 +  ssl_remotehost,		/* return remote host name */
  302.80 +  ssl_port,			/* return port number */
  302.81 +  ssl_localhost			/* return local host name */
  302.82 +};
  302.83 +
  302.84 +static unsigned long ssltsz = 0;/* SSL maximum token length */
  302.85 +
  302.86 +/* One-time SSL initialization */
  302.87 +
  302.88 +static int sslonceonly = 0;
  302.89 +
  302.90 +void ssl_onceonlyinit (void)
  302.91 +{
  302.92 +  if (!sslonceonly++) {		/* only need to call it once */
  302.93 +    ULONG np;
  302.94 +    SecPkgInfo *pp;
  302.95 +    int i;
  302.96 +				/* get security library */
  302.97 +    if (!EnumerateSecurityPackages (&np,&pp)) {
  302.98 +				/* look for an SSL package */
  302.99 +      for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
 302.100 +				/* note maximum token size and name */
 302.101 +	ssltsz = pp[i].cbMaxToken;
 302.102 +				/* apply runtime linkage */
 302.103 +	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
 302.104 +	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
 302.105 +	return;			/* all done */
 302.106 +      }
 302.107 +    }
 302.108 +  }
 302.109 +}
 302.110 +
 302.111 +/* SSL open
 302.112 + * Accepts: host name
 302.113 + *	    contact service name
 302.114 + *	    contact port number
 302.115 + * Returns: SSL stream if success else NIL
 302.116 + */
 302.117 +
 302.118 +SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
 302.119 +{
 302.120 +  TCPSTREAM *stream = tcp_open (host,service,port);
 302.121 +  return stream ? ssl_start (stream,host,port) : NIL;
 302.122 +}
 302.123 +
 302.124 +  
 302.125 +/* SSL authenticated open
 302.126 + * Accepts: host name
 302.127 + *	    service name
 302.128 + *	    returned user name buffer
 302.129 + * Returns: SSL stream if success else NIL
 302.130 + */
 302.131 +
 302.132 +SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
 302.133 +{
 302.134 +  return NIL;			/* don't use this mechanism with SSL */
 302.135 +}
 302.136 +
 302.137 +/* Start SSL/TLS negotiations
 302.138 + * Accepts: open TCP stream of session
 302.139 + *	    user's host name
 302.140 + *	    flags
 302.141 + * Returns: SSL stream if success else NIL
 302.142 + */
 302.143 +
 302.144 +static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
 302.145 +{
 302.146 +  SECURITY_STATUS e;
 302.147 +  ULONG a;
 302.148 +  TimeStamp t;
 302.149 +  SecBuffer ibuf[2],obuf[1];
 302.150 +  SecBufferDesc ibufs,obufs;
 302.151 +  SCHANNEL_CRED tlscred;
 302.152 +  CERT_CONTEXT *cert = NIL;
 302.153 +  CERT_CHAIN_PARA chparam;
 302.154 +  CERT_CHAIN_CONTEXT *chain;
 302.155 +  SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy;
 302.156 +  CERT_CHAIN_POLICY_PARA polparam;
 302.157 +  CERT_CHAIN_POLICY_STATUS status;
 302.158 +  char tmp[MAILTMPLEN],certname[256];
 302.159 +  char *reason = NIL;
 302.160 +  ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
 302.161 +    ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
 302.162 +      ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
 302.163 +	ISC_REQ_MANUAL_CRED_VALIDATION;
 302.164 +  LPSTR usage[] = {
 302.165 +    szOID_PKIX_KP_SERVER_AUTH,
 302.166 +    szOID_SERVER_GATED_CRYPTO,
 302.167 +    szOID_SGC_NETSCAPE
 302.168 +  };
 302.169 +  PWSTR whost = NIL;
 302.170 +  char *buf = (char *) fs_get (ssltsz);
 302.171 +  unsigned long size = 0;
 302.172 +  sslcertificatequery_t scq =
 302.173 +    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
 302.174 +  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
 302.175 +  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 302.176 +					    sizeof (SSLSTREAM));
 302.177 +  stream->tcpstream = tstream;	/* bind TCP stream */
 302.178 +				/* initialize TLS credential */
 302.179 +  memset (&tlscred,0,sizeof (SCHANNEL_CRED));
 302.180 +  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
 302.181 +  tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
 302.182 +
 302.183 +				/* acquire credentials */
 302.184 +  if (AcquireCredentialsHandle
 302.185 +      (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
 302.186 +       &tlscred : NIL,NIL,NIL,&stream->cred,&t)
 302.187 +      != SEC_E_OK) reason = "Acquire credentials handle failed";
 302.188 +  else while (!reason) {	/* negotiate security context */
 302.189 +				/* initialize buffers */
 302.190 +    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
 302.191 +    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
 302.192 +    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
 302.193 +    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
 302.194 +    ibuf[1].BufferType = SECBUFFER_EMPTY;
 302.195 +				/* initialize buffer descriptors */
 302.196 +    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
 302.197 +    ibufs.cBuffers = 2; obufs.cBuffers = 1;
 302.198 +    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
 302.199 +				/* negotiate security */
 302.200 +    e = InitializeSecurityContext
 302.201 +      (&stream->cred,size ? &stream->context : NIL,host,req,0,
 302.202 +       SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
 302.203 +				/* have an output buffer we need to send? */
 302.204 +    if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
 302.205 +      if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
 302.206 +	reason = "Unexpected TCP output disconnect";
 302.207 +				/* free the buffer */
 302.208 +      FreeContextBuffer (obuf[0].pvBuffer);
 302.209 +    }
 302.210 +    if (!reason) switch (e) {	/* negotiation state */
 302.211 +    case SEC_I_INCOMPLETE_CREDENTIALS:
 302.212 +      break;			/* server wants client auth */
 302.213 +    case SEC_I_CONTINUE_NEEDED:
 302.214 +      if (size) {		/* continue, read any data? */
 302.215 +				/* yes, anything regurgiated back to us? */
 302.216 +	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
 302.217 +				/* yes, set this as the new data */
 302.218 +	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
 302.219 +	  size = ibuf[1].cbBuffer;
 302.220 +	  break;
 302.221 +	}
 302.222 +	size = 0;		/* otherwise, read more stuff from server */
 302.223 +      }
 302.224 +    case SEC_E_INCOMPLETE_MESSAGE:
 302.225 +				/* need to read more data from server */
 302.226 +      if (!tcp_getdata (stream->tcpstream))
 302.227 +	reason = "Unexpected TCP input disconnect";
 302.228 +      else {
 302.229 +	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
 302.230 +	size += stream->tcpstream->ictr;
 302.231 +				/* empty it from TCP's buffers */
 302.232 +	stream->tcpstream->iptr += stream->tcpstream->ictr;
 302.233 +	stream->tcpstream->ictr = 0;
 302.234 +      }
 302.235 +      break;
 302.236 +
 302.237 +    case SEC_E_OK:		/* success, any data to be regurgitated? */
 302.238 +      if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
 302.239 +				/* yes, set this as the new data */
 302.240 +	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
 302.241 +		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
 302.242 +	stream->tcpstream->ictr = ibuf[1].cbBuffer;
 302.243 +      }
 302.244 +      if (!(flags & NET_NOVALIDATECERT)) {
 302.245 +				/* need validation, make wchar of host */
 302.246 +	if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) &&
 302.247 +	      (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) &&
 302.248 +	      MultiByteToWideChar (CP_ACP,0,host,-1,whost,size)))
 302.249 +	  fatal ("Can't make wchar of host name!");
 302.250 +				/* get certificate */
 302.251 +	if ((QueryContextAttributes
 302.252 +	     (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) !=
 302.253 +	     SEC_E_OK) || !cert) {
 302.254 +	  reason = "*Unable to get certificate";
 302.255 +	  strcpy (certname,"<no certificate>");
 302.256 +	}
 302.257 +	else {			/* get certificate subject name */
 302.258 +	  CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
 302.259 +			 &cert->pCertInfo->Subject,CERT_X500_NAME_STR,
 302.260 +			 certname,255);
 302.261 +				/* build certificate chain */
 302.262 +	  memset (&chparam,0,sizeof (chparam));
 302.263 +	  chparam.cbSize = sizeof (chparam);
 302.264 +	  chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
 302.265 +	  chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage;
 302.266 +	  chparam.RequestedUsage.Usage.cUsageIdentifier =
 302.267 +	    sizeof (usage) / sizeof (LPSTR);
 302.268 +	  if (!CertGetCertificateChain
 302.269 +	      (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain))
 302.270 +	    reason = ssl_analyze_status (GetLastError (),tmp);
 302.271 +	  else {		/* validate certificate chain */
 302.272 +	    memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
 302.273 +	    policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
 302.274 +	    policy.dwAuthType = AUTHTYPE_SERVER;
 302.275 +	    policy.fdwChecks = NIL;
 302.276 +	    policy.pwszServerName = whost;
 302.277 +	    memset (&polparam,0,sizeof (polparam));
 302.278 +	    polparam.cbSize = sizeof (polparam);
 302.279 +	    polparam.pvExtraPolicyPara = &policy;
 302.280 +	    memset (&status,0,sizeof (status));
 302.281 +	    status.cbSize = sizeof (status);
 302.282 +	    if (!CertVerifyCertificateChainPolicy
 302.283 +		(CERT_CHAIN_POLICY_SSL,chain,&polparam,&status))
 302.284 +	      reason = ssl_analyze_status (GetLastError (),tmp);
 302.285 +	    else if (status.dwError)
 302.286 +	      reason = ssl_analyze_status (status.dwError,tmp);
 302.287 +	    CertFreeCertificateChain (chain);
 302.288 +	  }
 302.289 +	  CertFreeCertificateContext (cert);
 302.290 +	}
 302.291 +	if (whost) fs_give ((void **) &whost);
 302.292 +
 302.293 +	if (reason) {		/* got an error? */
 302.294 +				/* application callback */
 302.295 +	  if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason,
 302.296 +				    host,certname) ? NIL : "";
 302.297 +	  else if (*certname) {	/* error message to return via mm_log() */
 302.298 +	    sprintf (buf,"*%.128s: %.255s",
 302.299 +		     (*reason == '*') ? reason + 1 : reason,certname);
 302.300 +	    reason = buf;
 302.301 +	  }
 302.302 +	}
 302.303 +      }
 302.304 +      if (reason ||
 302.305 +	  (reason = ssl_analyze_status
 302.306 +	   (QueryContextAttributes
 302.307 +	    (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)))
 302.308 +	break;			/* error in certificate or getting sizes */
 302.309 +      fs_give ((void **) &buf);	/* flush temporary buffer */
 302.310 +				/* make maximum-sized buffers */
 302.311 +      stream->bufsize = stream->sizes.cbHeader +
 302.312 +	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
 302.313 +      if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
 302.314 +	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
 302.315 +      else if (stream->sizes.cbMaximumMessage < 16384) {
 302.316 +	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
 302.317 +		 (long) stream->sizes.cbMaximumMessage);
 302.318 +	mm_log (tmp,NIL);
 302.319 +      }
 302.320 +      stream->ibuf = (char *) fs_get (stream->bufsize);
 302.321 +      stream->obuf = (char *) fs_get (stream->bufsize);
 302.322 +      return stream;
 302.323 +    default:
 302.324 +      reason = ssl_analyze_status (e,buf);
 302.325 +    }
 302.326 +  }
 302.327 +  ssl_close (stream);		/* failed to do SSL */
 302.328 +  stream = NIL;			/* no stream returned */
 302.329 +  switch (*reason) {		/* analyze reason */
 302.330 +  case '*':			/* certificate failure */
 302.331 +    ++reason;			/* skip over certificate failure indication */
 302.332 +				/* pass to error callback */
 302.333 +    if (sf) (*sf) (host,reason,flags);
 302.334 +    else {			/* no error callback, build error message */
 302.335 +      sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
 302.336 +      mm_log (tmp,ERROR);
 302.337 +    }
 302.338 +  case '\0':			/* user answered no to certificate callback */
 302.339 +    if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
 302.340 +      stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 302.341 +				     sizeof (SSLSTREAM));
 302.342 +    break;
 302.343 +  default:			/* non-certificate failure */
 302.344 +    if (flags & NET_TRYSSL);	/* no error output if tryssl */
 302.345 +				/* pass to error callback */
 302.346 +    else if (sf) (*sf) (host,reason,flags);
 302.347 +    else {			/* no error callback, build error message */
 302.348 +      sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
 302.349 +      mm_log (tmp,ERROR);
 302.350 +    }
 302.351 +    break;
 302.352 +  }
 302.353 +  fs_give ((void **) &buf);	/* flush temporary buffer */
 302.354 +  return stream;
 302.355 +}
 302.356 +
 302.357 +/* Generate error text from SSL error code
 302.358 + * Accepts: SSL status
 302.359 + *	    scratch buffer
 302.360 + * Returns: text if error status, else NIL
 302.361 + */
 302.362 +
 302.363 +static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
 302.364 +{
 302.365 +  switch (err) {
 302.366 +  case SEC_E_OK:		/* no error */
 302.367 +  case SEC_I_CONTINUE_NEEDED:
 302.368 +  case SEC_I_INCOMPLETE_CREDENTIALS:
 302.369 +  case SEC_E_INCOMPLETE_MESSAGE:
 302.370 +    return NIL;
 302.371 +  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
 302.372 +    mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL);
 302.373 +    return "*No authority could be contacted for authentication";
 302.374 +  case SEC_E_WRONG_PRINCIPAL:
 302.375 +    mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL);
 302.376 +  case CERT_E_CN_NO_MATCH:
 302.377 +    return "*Server name does not match certificate";
 302.378 +  case SEC_E_UNTRUSTED_ROOT:
 302.379 +    mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL);
 302.380 +  case CERT_E_UNTRUSTEDROOT:
 302.381 +    return "*Self-signed certificate or untrusted authority";
 302.382 +  case SEC_E_CERT_EXPIRED:
 302.383 +    mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL);
 302.384 +  case CERT_E_EXPIRED:
 302.385 +    return "*Certificate has expired";
 302.386 +  case CERT_E_REVOKED:
 302.387 +    return "*Certificate revoked";
 302.388 +  case SEC_E_INVALID_TOKEN:
 302.389 +    return "Invalid token, probably not an SSL server";
 302.390 +  case SEC_E_UNSUPPORTED_FUNCTION:
 302.391 +    return "SSL not supported on this machine - upgrade your system software";
 302.392 +  }
 302.393 +  sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err);
 302.394 +  return buf;
 302.395 +}
 302.396 +
 302.397 +/* SSL receive line
 302.398 + * Accepts: SSL stream
 302.399 + * Returns: text line string or NIL if failure
 302.400 + */
 302.401 +
 302.402 +char *ssl_getline (SSLSTREAM *stream)
 302.403 +{
 302.404 +  unsigned long n,contd;
 302.405 +  char *ret = ssl_getline_work (stream,&n,&contd);
 302.406 +  if (ret && contd) {		/* got a line needing continuation? */
 302.407 +    STRINGLIST *stl = mail_newstringlist ();
 302.408 +    STRINGLIST *stc = stl;
 302.409 +    do {			/* collect additional lines */
 302.410 +      stc->text.data = (unsigned char *) ret;
 302.411 +      stc->text.size = n;
 302.412 +      stc = stc->next = mail_newstringlist ();
 302.413 +      ret = ssl_getline_work (stream,&n,&contd);
 302.414 +    } while (ret && contd);
 302.415 +    if (ret) {			/* stash final part of line on list */
 302.416 +      stc->text.data = (unsigned char *) ret;
 302.417 +      stc->text.size = n;
 302.418 +				/* determine how large a buffer we need */
 302.419 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 302.420 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 302.421 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 302.422 +	memcpy (ret + n,stc->text.data,stc->text.size);
 302.423 +      ret[n] = '\0';
 302.424 +    }
 302.425 +    mail_free_stringlist (&stl);/* either way, done with list */
 302.426 +  }
 302.427 +  return ret;
 302.428 +}
 302.429 +
 302.430 +/* SSL receive line or partial line
 302.431 + * Accepts: SSL stream
 302.432 + *	    pointer to return size
 302.433 + *	    pointer to return continuation flag
 302.434 + * Returns: text line string, size and continuation flag, or NIL if failure
 302.435 + */
 302.436 +
 302.437 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
 302.438 +			       long *contd)
 302.439 +{
 302.440 +  unsigned long n;
 302.441 +  char *s,*ret,c,d;
 302.442 +  *contd = NIL;			/* assume no continuation */
 302.443 +				/* make sure have data */
 302.444 +  if (!ssl_getdata (stream)) return NIL;
 302.445 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 302.446 +    d = *stream->iptr++;	/* slurp another character */
 302.447 +    if ((c == '\015') && (d == '\012')) {
 302.448 +      ret = (char *) fs_get (n--);
 302.449 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 302.450 +      ret[n] = '\0';		/* tie off string with null */
 302.451 +      return ret;
 302.452 +    }
 302.453 +  }
 302.454 +				/* copy partial string from buffer */
 302.455 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 302.456 +				/* get more data from the net */
 302.457 +  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
 302.458 +				/* special case of newline broken by buffer */
 302.459 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 302.460 +    stream->iptr++;		/* eat the line feed */
 302.461 +    stream->ictr--;
 302.462 +    ret[*size = --n] = '\0';	/* tie off string with null */
 302.463 +  }
 302.464 +  else *contd = LONGT;		/* continuation needed */
 302.465 +  return ret;
 302.466 +}
 302.467 +
 302.468 +/* SSL receive buffer
 302.469 + * Accepts: SSL stream
 302.470 + *	    size in bytes
 302.471 + *	    buffer to read into
 302.472 + * Returns: T if success, NIL otherwise
 302.473 + */
 302.474 +
 302.475 +long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
 302.476 +{
 302.477 +  unsigned long n;
 302.478 +  while (size > 0) {		/* until request satisfied */
 302.479 +    if (!ssl_getdata (stream)) return NIL;
 302.480 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 302.481 +				/* do the copy */
 302.482 +    memcpy (buffer,stream->iptr,n);
 302.483 +    buffer += n;		/* update pointer */
 302.484 +    stream->iptr += n;
 302.485 +    size -= n;			/* update # of bytes to do */
 302.486 +    stream->ictr -= n;
 302.487 +  }
 302.488 +  buffer[0] = '\0';		/* tie off string */
 302.489 +  return T;
 302.490 +}
 302.491 +
 302.492 +/* SSL receive data
 302.493 + * Accepts: TCP/IP stream
 302.494 + * Returns: T if success, NIL otherwise
 302.495 + */
 302.496 +
 302.497 +long ssl_getdata (SSLSTREAM *stream)
 302.498 +{
 302.499 +  while (stream->ictr < 1) {	/* decrypted buffer empty? */
 302.500 +    SECURITY_STATUS status;
 302.501 +    SecBuffer buf[4];
 302.502 +    SecBufferDesc msg;
 302.503 +    size_t i;
 302.504 +    size_t n = 0;		/* initially no bytes to decrypt */
 302.505 +    do {			/* yes, make sure have data from TCP */
 302.506 +      if (stream->iextractr) {	/* have previous unread data? */
 302.507 +	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
 302.508 +	n += stream->iextractr;	/* update number of bytes read */
 302.509 +	stream->iextractr = 0;	/* no more extra data */
 302.510 +      }
 302.511 +      else {			/* read from TCP */
 302.512 +	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
 302.513 +				/* maximum amount of data to copy */
 302.514 +	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
 302.515 +	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
 302.516 +				/* do the copy */
 302.517 +	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
 302.518 +	stream->tcpstream->iptr += i;
 302.519 +	stream->tcpstream->ictr -= i;
 302.520 +	n += i;			/* update number of bytes to decrypt */
 302.521 +      }
 302.522 +      buf[0].cbBuffer = n;	/* first SecBuffer gets data */
 302.523 +      buf[0].pvBuffer = stream->ibuf;
 302.524 +      buf[0].BufferType = SECBUFFER_DATA;
 302.525 +				/* subsequent ones are for spares */
 302.526 +      buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
 302.527 +	SECBUFFER_EMPTY;
 302.528 +      msg.ulVersion = SECBUFFER_VERSION;
 302.529 +      msg.cBuffers = 4;		/* number of SecBuffers */
 302.530 +      msg.pBuffers = buf;	/* first SecBuffer */
 302.531 +    } while ((status = DecryptMessage
 302.532 +	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
 302.533 +    switch (status) {
 302.534 +    case SEC_E_OK:		/* won */
 302.535 +    case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
 302.536 +				/* hunt for a buffer */
 302.537 +      for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
 302.538 +      if (i < 4) {		/* found a buffer? */
 302.539 +				/* yes, set up pointer and counter */
 302.540 +	stream->iptr = buf[i].pvBuffer;
 302.541 +	stream->ictr = buf[i].cbBuffer;
 302.542 +				/* any unprocessed data? */
 302.543 +	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
 302.544 +				/* yes, note for next time around */
 302.545 +	  stream->iextraptr = buf[i].pvBuffer;
 302.546 +	  stream->iextractr = buf[i].cbBuffer;
 302.547 +	}
 302.548 +      }
 302.549 +      break;
 302.550 +    default:			/* anything else means we've lost */
 302.551 +      return ssl_abort (stream);
 302.552 +    }
 302.553 +  }
 302.554 +  return LONGT;
 302.555 +}
 302.556 +
 302.557 +/* SSL send string as record
 302.558 + * Accepts: SSL stream
 302.559 + *	    string pointer
 302.560 + * Returns: T if success else NIL
 302.561 + */
 302.562 +
 302.563 +long ssl_soutr (SSLSTREAM *stream,char *string)
 302.564 +{
 302.565 +  return ssl_sout (stream,string,(unsigned long) strlen (string));
 302.566 +}
 302.567 +
 302.568 +
 302.569 +/* SSL send string
 302.570 + * Accepts: SSL stream
 302.571 + *	    string pointer
 302.572 + *	    byte count
 302.573 + * Returns: T if success else NIL
 302.574 + */
 302.575 +
 302.576 +long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
 302.577 +{
 302.578 +  SecBuffer buf[4];
 302.579 +  SecBufferDesc msg;
 302.580 +  char *s;
 302.581 +  size_t n;
 302.582 +  if (!stream->tcpstream) return NIL;
 302.583 +				/* until request satisfied */
 302.584 +  for (s = stream->ibuf,n = 0; size;) {
 302.585 +				/* header */
 302.586 +    buf[0].BufferType = SECBUFFER_STREAM_HEADER;
 302.587 +    memset (buf[0].pvBuffer = stream->obuf,0,
 302.588 +	    buf[0].cbBuffer = stream->sizes.cbHeader);
 302.589 +				/* message (up to maximum size) */
 302.590 +    buf[1].BufferType = SECBUFFER_DATA;
 302.591 +    memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
 302.592 +	    buf[1].cbBuffer = min (size,SSLBUFLEN));
 302.593 +				/* trailer */
 302.594 +    buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
 302.595 +    memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
 302.596 +	    buf[2].cbBuffer = stream->sizes.cbTrailer);
 302.597 +				/* spare */
 302.598 +    buf[3].BufferType = SECBUFFER_EMPTY;
 302.599 +    msg.ulVersion = SECBUFFER_VERSION;
 302.600 +    msg.cBuffers = 4;		/* number of SecBuffers */
 302.601 +    msg.pBuffers = buf;		/* first SecBuffer */
 302.602 +    string += buf[1].cbBuffer;
 302.603 +    size -= buf[1].cbBuffer;	/* this many bytes processed */
 302.604 +				/* encrypt and send message */
 302.605 +    if ((EncryptMessage
 302.606 +	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
 302.607 +	!tcp_sout (stream->tcpstream,stream->obuf,
 302.608 +		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
 302.609 +      return ssl_abort (stream);/* encryption or sending failed */
 302.610 +  }
 302.611 +  return LONGT;
 302.612 +}
 302.613 +
 302.614 +/* SSL close
 302.615 + * Accepts: SSL stream
 302.616 + */
 302.617 +
 302.618 +void ssl_close (SSLSTREAM *stream)
 302.619 +{
 302.620 +  ssl_abort (stream);		/* nuke the stream */
 302.621 +  fs_give ((void **) &stream);	/* flush the stream */
 302.622 +}
 302.623 +
 302.624 +
 302.625 +/* SSL abort stream
 302.626 + * Accepts: SSL stream
 302.627 + * Returns: NIL always
 302.628 + */
 302.629 +
 302.630 +static long ssl_abort (SSLSTREAM *stream)
 302.631 +{
 302.632 +  if (stream->tcpstream) {	/* close TCP stream */
 302.633 +    DeleteSecurityContext (&stream->context);
 302.634 +    FreeCredentialHandle (&stream->cred);
 302.635 +    tcp_close (stream->tcpstream);
 302.636 +    stream->tcpstream = NIL;
 302.637 +  }
 302.638 +  if (stream->ibuf) fs_give ((void **) &stream->ibuf);
 302.639 +  if (stream->obuf) fs_give ((void **) &stream->obuf);
 302.640 +  return NIL;
 302.641 +}
 302.642 +
 302.643 +/* SSL get host name
 302.644 + * Accepts: SSL stream
 302.645 + * Returns: host name for this stream
 302.646 + */
 302.647 +
 302.648 +char *ssl_host (SSLSTREAM *stream)
 302.649 +{
 302.650 +  return tcp_host (stream->tcpstream);
 302.651 +}
 302.652 +
 302.653 +
 302.654 +/* SSL get remote host name
 302.655 + * Accepts: SSL stream
 302.656 + * Returns: host name for this stream
 302.657 + */
 302.658 +
 302.659 +char *ssl_remotehost (SSLSTREAM *stream)
 302.660 +{
 302.661 +  return tcp_remotehost (stream->tcpstream);
 302.662 +}
 302.663 +
 302.664 +
 302.665 +/* SSL return port for this stream
 302.666 + * Accepts: SSL stream
 302.667 + * Returns: port number for this stream
 302.668 + */
 302.669 +
 302.670 +unsigned long ssl_port (SSLSTREAM *stream)
 302.671 +{
 302.672 +  return tcp_port (stream->tcpstream);
 302.673 +}
 302.674 +
 302.675 +
 302.676 +/* SSL get local host name
 302.677 + * Accepts: SSL stream
 302.678 + * Returns: local host name
 302.679 + */
 302.680 +
 302.681 +char *ssl_localhost (SSLSTREAM *stream)
 302.682 +{
 302.683 +  return tcp_localhost (stream->tcpstream);
 302.684 +}
 302.685 +
 302.686 +#include "ssl_none.c"		/* currently no server support */
   303.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   303.2 +++ b/src/osdep/nt/tcp_nt.c	Mon Sep 14 15:17:45 2009 +0900
   303.3 @@ -0,0 +1,912 @@
   303.4 +/* ========================================================================
   303.5 + * Copyright 1988-2007 University of Washington
   303.6 + *
   303.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   303.8 + * you may not use this file except in compliance with the License.
   303.9 + * You may obtain a copy of the License at
  303.10 + *
  303.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  303.12 + *
  303.13 + * 
  303.14 + * ========================================================================
  303.15 + */
  303.16 +
  303.17 +/*
  303.18 + * Program:	Winsock TCP/IP routines
  303.19 + *
  303.20 + * Author:	Mark Crispin from Mike Seibel's Winsock code
  303.21 + *		Networks and Distributed Computing
  303.22 + *		Computing & Communications
  303.23 + *		University of Washington
  303.24 + *		Administration Building, AG-44
  303.25 + *		Seattle, WA  98195
  303.26 + *		Internet: MRC@CAC.Washington.EDU
  303.27 + *
  303.28 + * Date:	11 April 1989
  303.29 + * Last Edited: 13 January 2007
  303.30 + */
  303.31 +
  303.32 +#include "ip_nt.c"
  303.33 +
  303.34 +
  303.35 +#define TCPMAXSEND 32768
  303.36 +
  303.37 +/* Private functions */
  303.38 +
  303.39 +int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
  303.40 +		     char *tmp,char *hst);
  303.41 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  303.42 +			       long *contd);
  303.43 +long tcp_abort (TCPSTREAM *stream);
  303.44 +long tcp_close_socket (SOCKET *sock);
  303.45 +char *tcp_name (struct sockaddr *sadr,long flag);
  303.46 +char *tcp_name_valid (char *s);
  303.47 +
  303.48 +
  303.49 +/* Private data */
  303.50 +
  303.51 +int wsa_initted = 0;		/* init ? */
  303.52 +static int wsa_sock_open = 0;	/* keep track of open sockets */
  303.53 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  303.54 +static long ttmo_open = 0;	/* TCP timeouts, in seconds */
  303.55 +static long ttmo_read = 0;
  303.56 +static long ttmo_write = 0;
  303.57 +static long allowreversedns = T;/* allow reverse DNS lookup */
  303.58 +static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
  303.59 +static char *myClientAddr = NIL;/* client host address */
  303.60 +static char *myClientHost = NIL;/* client host name */
  303.61 +static long myClientPort = -1;	/* client port */
  303.62 +static char *myServerAddr = NIL;/* server host address */
  303.63 +static char *myServerHost = NIL;/* server host name */
  303.64 +static long myServerPort = -1;	/* server port */
  303.65 +
  303.66 +extern long maxposint;		/* get this from write.c */
  303.67 +
  303.68 +/* TCP/IP manipulate parameters
  303.69 + * Accepts: function code
  303.70 + *	    function-dependent value
  303.71 + * Returns: function-dependent return value
  303.72 + */
  303.73 +
  303.74 +void *tcp_parameters (long function,void *value)
  303.75 +{
  303.76 +  void *ret = NIL;
  303.77 +  switch ((int) function) {
  303.78 +  case SET_TIMEOUT:
  303.79 +    tmoh = (tcptimeout_t) value;
  303.80 +  case GET_TIMEOUT:
  303.81 +    ret = (void *) tmoh;
  303.82 +    break;
  303.83 +  case SET_OPENTIMEOUT:
  303.84 +    ttmo_open = (long) value ? (long) value : (long) WSA_INFINITE;
  303.85 +  case GET_OPENTIMEOUT:
  303.86 +    ret = (void *) ttmo_open;
  303.87 +    break;
  303.88 +  case SET_READTIMEOUT:
  303.89 +    ttmo_read = (long) value;
  303.90 +  case GET_READTIMEOUT:
  303.91 +    ret = (void *) ttmo_read;
  303.92 +    break;
  303.93 +  case SET_WRITETIMEOUT:
  303.94 +    ttmo_write = (long) value;
  303.95 +  case GET_WRITETIMEOUT:
  303.96 +    ret = (void *) ttmo_write;
  303.97 +    break;
  303.98 +  case SET_ALLOWREVERSEDNS:
  303.99 +    allowreversedns = (long) value;
 303.100 +  case GET_ALLOWREVERSEDNS:
 303.101 +    ret = (void *) allowreversedns;
 303.102 +    break;
 303.103 +  case SET_TCPDEBUG:
 303.104 +    tcpdebug = (long) value;
 303.105 +  case GET_TCPDEBUG:
 303.106 +    ret = (void *) tcpdebug;
 303.107 +    break;
 303.108 +  }
 303.109 +  return ret;
 303.110 +}
 303.111 +
 303.112 +/* TCP/IP open
 303.113 + * Accepts: host name
 303.114 + *	    contact service name
 303.115 + *	    contact port number and optional silent flag
 303.116 + * Returns: TCP/IP stream if success else NIL
 303.117 + */
 303.118 +
 303.119 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
 303.120 +{
 303.121 +  TCPSTREAM *stream = NIL;
 303.122 +  int i,family;
 303.123 +  SOCKET sock = INVALID_SOCKET;
 303.124 +  int silent = (port & NET_SILENT) ? T : NIL;
 303.125 +  char *s,*hostname,tmp[MAILTMPLEN];
 303.126 +  void *adr,*next;
 303.127 +  size_t adrlen;
 303.128 +  struct servent *sv = NIL;
 303.129 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 303.130 +  if (!wsa_initted++) {		/* init Windows Sockets */
 303.131 +    WSADATA wsock;
 303.132 +    if (i = (int) WSAStartup (WINSOCK_VERSION,&wsock)) {
 303.133 +      wsa_initted = 0;		/* in case we try again */
 303.134 +      sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
 303.135 +      mm_log (tmp,ERROR);
 303.136 +      return NIL;
 303.137 +    }
 303.138 +  }
 303.139 +  port &= 0xffff;		/* erase flags */
 303.140 +				/* lookup service */
 303.141 +  if (service && (sv = getservbyname (service,"tcp")))
 303.142 +    port = ntohs (sv->s_port);
 303.143 +  /* The domain literal form is used (rather than simply the dotted decimal
 303.144 +     as with other Windows programs) because it has to be a valid "host name"
 303.145 +     in mailsystem terminology. */
 303.146 +				/* look like domain literal? */
 303.147 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
 303.148 +    strcpy (tmp,host+1);	/* yes, copy number part */
 303.149 +    tmp[strlen (tmp)-1] = '\0';
 303.150 +    if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) {
 303.151 +      (*bn) (BLOCK_TCPOPEN,NIL);
 303.152 +      sock = tcp_socket_open (family,adr,adrlen,(unsigned short) port,tmp,
 303.153 +			      hostname = host);
 303.154 +      (*bn) (BLOCK_NONE,NIL);
 303.155 +      fs_give ((void **) &adr);
 303.156 +    }
 303.157 +    else sprintf (tmp,"Bad format domain-literal: %.80s",host);
 303.158 +  }
 303.159 +
 303.160 +  else {			/* lookup host name */
 303.161 +    if (tcpdebug) {
 303.162 +      sprintf (tmp,"DNS resolution %.80s",host);
 303.163 +      mm_log (tmp,TCPDEBUG);
 303.164 +    }
 303.165 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
 303.166 +    if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next)))
 303.167 +      sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError (),host);
 303.168 +    (*bn) (BLOCK_NONE,NIL);
 303.169 +    if (s) {			/* DNS resolution won? */
 303.170 +      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
 303.171 +      wsa_sock_open++;		/* prevent tcp_close_socket() from freeing in
 303.172 +				   loop */
 303.173 +      do {
 303.174 +	(*bn) (BLOCK_TCPOPEN,NIL);
 303.175 +	if (((sock = tcp_socket_open (family,s,adrlen,(unsigned short) port,
 303.176 +				      tmp,hostname)) == INVALID_SOCKET) &&
 303.177 +	    (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) &&
 303.178 +	    !silent) mm_log (tmp,WARN);
 303.179 +	(*bn) (BLOCK_NONE,NIL);
 303.180 +      } while ((sock == INVALID_SOCKET) && s);
 303.181 +      wsa_sock_open--;		/* undo protection */
 303.182 +    }
 303.183 +  }
 303.184 +  if (sock == INVALID_SOCKET) {	/* do possible cleanup action */
 303.185 +    if (!silent) mm_log (tmp,ERROR);
 303.186 +    tcp_close_socket (&sock);	
 303.187 +  }
 303.188 +  else {			/* got a socket, create TCP/IP stream */
 303.189 +    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
 303.190 +				   sizeof (TCPSTREAM));
 303.191 +    stream->port = port;	/* port number */
 303.192 +				/* init socket */
 303.193 +    stream->tcpsi = stream->tcpso = sock;
 303.194 +    stream->ictr = 0;		/* init input counter */
 303.195 +				/* copy official host name */
 303.196 +    stream->host = cpystr (hostname);
 303.197 +    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
 303.198 +  }
 303.199 +  return stream;		/* return success */
 303.200 +}
 303.201 +
 303.202 +/* Open a TCP socket
 303.203 + * Accepts: protocol family
 303.204 + *	    address to connect to
 303.205 + *	    address length
 303.206 + *	    port
 303.207 + *	    scratch buffer
 303.208 + *	    host name
 303.209 + * Returns: socket if success, else SOCKET_ERROR with error string in scratch
 303.210 + */
 303.211 +
 303.212 +int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
 303.213 +		     char *tmp,char *hst)
 303.214 +{
 303.215 +  int sock,err;
 303.216 +  char *s,errmsg[100];
 303.217 +  size_t len;
 303.218 +  DWORD eo;
 303.219 +  WSAEVENT event;
 303.220 +  WSANETWORKEVENTS events;
 303.221 +  unsigned long cmd = 0;
 303.222 +  struct protoent *pt = getprotobyname ("tcp");
 303.223 +  struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len);
 303.224 +  sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr));
 303.225 +  mm_log (tmp,NIL);
 303.226 +				/* get a TCP stream */
 303.227 +  if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) ==
 303.228 +      INVALID_SOCKET)
 303.229 +    sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError ());
 303.230 +  else {
 303.231 +    /* On Windows, FD_SETSIZE is the number of descriptors which can be
 303.232 +     * held in an fd_set, as opposed to the maximum descriptor value on UNIX.
 303.233 +     * Similarly, an fd_set in Windows is a vector of descriptor values, as
 303.234 +     * opposed to a bitmask of set fds on UNIX.  Thus, an fd_set can hold up
 303.235 +     * to FD_SETSIZE values which can be larger than FD_SETSIZE, and the test
 303.236 +     * that is used on UNIX is unnecessary here.
 303.237 +     */
 303.238 +    wsa_sock_open++;		/* count this socket as open */
 303.239 +				/* set socket nonblocking */
 303.240 +    if (ttmo_open) WSAEventSelect (sock,event = WSACreateEvent (),FD_CONNECT);
 303.241 +    else event = 0;		/* no event */
 303.242 +				/* open connection */
 303.243 +    err = (connect (sock,sadr,len) == SOCKET_ERROR) ? WSAGetLastError () : NIL;
 303.244 +				/* if timer in effect, wait for event */
 303.245 +    if (event) while (err == WSAEWOULDBLOCK)
 303.246 +      switch (eo = WSAWaitForMultipleEvents (1,&event,T,ttmo_open*1000,NIL)) {
 303.247 +      case WSA_WAIT_EVENT_0:	/* got an event? */
 303.248 +	err = (WSAEnumNetworkEvents (sock,event,&events) == SOCKET_ERROR) ?
 303.249 +	  WSAGetLastError () : events.iErrorCode[FD_CONNECT_BIT];
 303.250 +	break;
 303.251 +      case WSA_WAIT_IO_COMPLETION:
 303.252 +	break;			/* fAlertable is NIL so shouldn't happen */
 303.253 +      default:			/* all other conditions */
 303.254 +	err = eo;		/* error from WSAWaitForMultipleEvents() */
 303.255 +	break;
 303.256 +      }
 303.257 +
 303.258 +    switch (err) {		/* analyze result from connect and wait */
 303.259 +    case 0:			/* got a connection */
 303.260 +      s = NIL;
 303.261 +      if (event) {		/* unset blocking mode */
 303.262 +	WSAEventSelect (sock,event,NIL);
 303.263 +	if (ioctlsocket (sock,FIONBIO,&cmd) == SOCKET_ERROR)
 303.264 +	  sprintf (s = errmsg,"Can't set blocking mode (%d)",
 303.265 +		   WSAGetLastError ());
 303.266 +      }
 303.267 +      break;
 303.268 +    case WSAECONNREFUSED:
 303.269 +      s = "Refused";
 303.270 +      break;
 303.271 +    case WSAENOBUFS:
 303.272 +      s = "Insufficient system resources";
 303.273 +      break;
 303.274 +    case WSA_WAIT_TIMEOUT: case WSAETIMEDOUT:
 303.275 +      s = "Timed out";
 303.276 +      break;
 303.277 +    case WSAEHOSTUNREACH:
 303.278 +      s = "Host unreachable";
 303.279 +      break;
 303.280 +    default:			/* horrible error 69 */
 303.281 +      sprintf (s = errmsg,"Unknown error (%d)",err);
 303.282 +      break;
 303.283 +    }
 303.284 +				/* flush event */
 303.285 +    if (event) WSACloseEvent (event);
 303.286 +    if (s) {			/* got an error? */
 303.287 +      sprintf (tmp,"Can't connect to %.80s,%ld: %.80s",hst,port,s);
 303.288 +      tcp_close_socket (&sock);	/* flush socket */
 303.289 +      sock = INVALID_SOCKET;
 303.290 +    }
 303.291 +  }
 303.292 +  fs_give ((void **) &sadr);	/* and socket address */
 303.293 +  return sock;			/* return the socket */
 303.294 +}
 303.295 +  
 303.296 +/* TCP/IP authenticated open
 303.297 + * Accepts: NETMBX specifier
 303.298 + *	    service name
 303.299 + *	    returned user name buffer
 303.300 + * Returns: TCP/IP stream if success else NIL
 303.301 + */
 303.302 +
 303.303 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 303.304 +{
 303.305 +  return NIL;			/* always NIL on Windows */
 303.306 +}
 303.307 +
 303.308 +/* TCP receive line
 303.309 + * Accepts: TCP stream
 303.310 + * Returns: text line string or NIL if failure
 303.311 + */
 303.312 +
 303.313 +char *tcp_getline (TCPSTREAM *stream)
 303.314 +{
 303.315 +  unsigned long n,contd;
 303.316 +  char *ret = tcp_getline_work (stream,&n,&contd);
 303.317 +  if (ret && contd) {		/* got a line needing continuation? */
 303.318 +    STRINGLIST *stl = mail_newstringlist ();
 303.319 +    STRINGLIST *stc = stl;
 303.320 +    do {			/* collect additional lines */
 303.321 +      stc->text.data = (unsigned char *) ret;
 303.322 +      stc->text.size = n;
 303.323 +      stc = stc->next = mail_newstringlist ();
 303.324 +      ret = tcp_getline_work (stream,&n,&contd);
 303.325 +    } while (ret && contd);
 303.326 +    if (ret) {			/* stash final part of line on list */
 303.327 +      stc->text.data = (unsigned char *) ret;
 303.328 +      stc->text.size = n;
 303.329 +				/* determine how large a buffer we need */
 303.330 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 303.331 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 303.332 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 303.333 +	memcpy (ret + n,stc->text.data,stc->text.size);
 303.334 +      ret[n] = '\0';
 303.335 +    }
 303.336 +    mail_free_stringlist (&stl);/* either way, done with list */
 303.337 +  }
 303.338 +  return ret;
 303.339 +}
 303.340 +
 303.341 +/* TCP receive line or partial line
 303.342 + * Accepts: TCP stream
 303.343 + *	    pointer to return size
 303.344 + *	    pointer to return continuation flag
 303.345 + * Returns: text line string, size and continuation flag, or NIL if failure
 303.346 + */
 303.347 +
 303.348 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 303.349 +			       long *contd)
 303.350 +{
 303.351 +  unsigned long n;
 303.352 +  char *s,*ret,c,d;
 303.353 +  *contd = NIL;			/* assume no continuation */
 303.354 +				/* make sure have data */
 303.355 +  if (!tcp_getdata (stream)) return NIL;
 303.356 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 303.357 +    d = *stream->iptr++;	/* slurp another character */
 303.358 +    if ((c == '\015') && (d == '\012')) {
 303.359 +      ret = (char *) fs_get (n--);
 303.360 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 303.361 +      ret[n] = '\0';		/* tie off string with null */
 303.362 +      return ret;
 303.363 +    }
 303.364 +  }
 303.365 +				/* copy partial string from buffer */
 303.366 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 303.367 +				/* get more data from the net */
 303.368 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 303.369 +				/* special case of newline broken by buffer */
 303.370 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 303.371 +    stream->iptr++;		/* eat the line feed */
 303.372 +    stream->ictr--;
 303.373 +    ret[*size = --n] = '\0';	/* tie off string with null */
 303.374 +  }
 303.375 +  else *contd = LONGT;		/* continuation needed */
 303.376 +  return ret;
 303.377 +}
 303.378 +
 303.379 +/* TCP/IP receive buffer
 303.380 + * Accepts: TCP/IP stream
 303.381 + *	    size in bytes
 303.382 + *	    buffer to read into
 303.383 + * Returns: T if success, NIL otherwise
 303.384 + */
 303.385 +
 303.386 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
 303.387 +{
 303.388 +  unsigned long n;
 303.389 +				/* make sure socket still alive */
 303.390 +  if (stream->tcpsi == INVALID_SOCKET) return NIL;
 303.391 +				/* can transfer bytes from buffer? */
 303.392 +  if (n = min (size,stream->ictr)) {
 303.393 +    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
 303.394 +    s += n;			/* update pointer */
 303.395 +    stream->iptr +=n;
 303.396 +    size -= n;			/* update # of bytes to do */
 303.397 +    stream->ictr -=n;
 303.398 +  }
 303.399 +  if (size) {
 303.400 +    int i;
 303.401 +    fd_set fds,efds;
 303.402 +    struct timeval tmo;
 303.403 +    time_t t = time (0);
 303.404 +    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 303.405 +    (*bn) (BLOCK_TCPREAD,NIL);
 303.406 +    while (size > 0) {		/* until request satisfied */
 303.407 +      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
 303.408 +				/* simple case if not a socket */
 303.409 +      if (stream->tcpsi != stream->tcpso)
 303.410 +	while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) &&
 303.411 +	       (errno == EINTR));
 303.412 +      else {			/* socket case */
 303.413 +	time_t tl = time (0);
 303.414 +	time_t now = tl;
 303.415 +	time_t ti = ttmo_read ? now + ttmo_read : 0;
 303.416 +	tmo.tv_usec = 0;
 303.417 +	FD_ZERO (&fds);		/* initialize selection vector */
 303.418 +	FD_ZERO (&efds);	/* handle errors too */
 303.419 +				/* set bit in selection vectors */
 303.420 +	FD_SET (stream->tcpsi,&fds);
 303.421 +	FD_SET (stream->tcpsi,&efds);
 303.422 +	errno = NIL;		/* initially no error */
 303.423 +	do {			/* block under timeout */
 303.424 +	  tmo.tv_sec = (long) (ti ? ti - now : 0);
 303.425 +	  i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
 303.426 +	  now = time (0);	/* fake timeout if interrupt & time expired */
 303.427 +	  if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti &&
 303.428 +	      (ti <= now)) i = 0;
 303.429 +	} while ((i < 0) && (errno == WSAEINTR));
 303.430 +				/* success from select, read what we can */
 303.431 +	if (i > 0) while (((i = recv (stream->tcpsi,s,
 303.432 +				      (int) min (maxposint,size),0)) ==
 303.433 +			   SOCKET_ERROR) &&
 303.434 +			  ((errno = WSAGetLastError ()) == WSAEINTR));
 303.435 +	else if (!i) {		/* timeout, ignore if told to resume */
 303.436 +	  if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
 303.437 +				/* otherwise punt */
 303.438 +	  if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
 303.439 +	  return tcp_abort (stream);
 303.440 +	}
 303.441 +      }
 303.442 +      if (i <= 0) {		/* error seen? */
 303.443 +	if (tcpdebug) {
 303.444 +	  char tmp[MAILTMPLEN];
 303.445 +	  if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno);
 303.446 +	  else s = "TCP buffer read end of file";
 303.447 +	  mm_log (s,TCPDEBUG);
 303.448 +	}
 303.449 +	return tcp_abort (stream);
 303.450 +      }
 303.451 +      s += i;			/* point at new place to write */
 303.452 +      size -= i;		/* reduce byte count */
 303.453 +      if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
 303.454 +    }
 303.455 +    (*bn) (BLOCK_NONE,NIL);
 303.456 +  }
 303.457 +  *s = '\0';			/* tie off string */
 303.458 +  return LONGT;
 303.459 +}
 303.460 +
 303.461 +/* TCP/IP receive data
 303.462 + * Accepts: TCP/IP stream
 303.463 + * Returns: T if success, NIL otherwise
 303.464 + */
 303.465 +
 303.466 +long tcp_getdata (TCPSTREAM *stream)
 303.467 +{
 303.468 +  int i;
 303.469 +  fd_set fds,efds;
 303.470 +  struct timeval tmo;
 303.471 +  time_t t = time (0);
 303.472 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 303.473 +  if (stream->tcpsi == INVALID_SOCKET) return NIL;
 303.474 +  (*bn) (BLOCK_TCPREAD,NIL);
 303.475 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 303.476 +    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
 303.477 +				/* simple case if not a socket */
 303.478 +    if (stream->tcpsi != stream->tcpso)
 303.479 +      while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
 303.480 +	     (errno == EINTR));
 303.481 +    else {
 303.482 +      time_t tl = time (0);
 303.483 +      time_t now = tl;
 303.484 +      time_t ti = ttmo_read ? now + ttmo_read : 0;
 303.485 +      tmo.tv_usec = 0;
 303.486 +      FD_ZERO (&fds);		/* initialize selection vector */
 303.487 +      FD_ZERO (&efds);		/* handle errors too */
 303.488 +				/* set bit in selection vectors */
 303.489 +      FD_SET (stream->tcpsi,&fds);
 303.490 +      FD_SET (stream->tcpsi,&efds);
 303.491 +      errno = NIL;		/* initially no error */
 303.492 +      do {			/* block under timeout */
 303.493 +	tmo.tv_sec = (long) (ti ? ti - now : 0);
 303.494 +	i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
 303.495 +	now = time (0);		/* fake timeout if interrupt & time expired */
 303.496 +	if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti &&
 303.497 +	    (ti <= now)) i = 0;
 303.498 +      } while ((i < 0) && (errno == WSAEINTR));
 303.499 +				/* success from select, read what we can */
 303.500 +      if (i > 0) while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
 303.501 +			 SOCKET_ERROR) &&
 303.502 +			((errno = WSAGetLastError ()) == WSAEINTR));
 303.503 +      else if (!i) {		/* timeout, ignore if told to resume */
 303.504 +	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
 303.505 +				/* otherwise punt */
 303.506 +	if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
 303.507 +	return tcp_abort (stream);
 303.508 +      }
 303.509 +    }
 303.510 +    if (i <= 0) {		/* error seen? */
 303.511 +      if (tcpdebug) {
 303.512 +	char *s,tmp[MAILTMPLEN];
 303.513 +	if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno);
 303.514 +	else s = "TCP data read end of file";
 303.515 +	mm_log (tmp,TCPDEBUG);
 303.516 +      }
 303.517 +      return tcp_abort (stream);
 303.518 +    }
 303.519 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 303.520 +    stream->ictr = i;		/* set new byte count */
 303.521 +    if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
 303.522 +  }
 303.523 +  (*bn) (BLOCK_NONE,NIL);
 303.524 +  return T;
 303.525 +}
 303.526 +
 303.527 +/* TCP/IP send string as record
 303.528 + * Accepts: TCP/IP stream
 303.529 + *	    string pointer
 303.530 + * Returns: T if success else NIL
 303.531 + */
 303.532 +
 303.533 +long tcp_soutr (TCPSTREAM *stream,char *string)
 303.534 +{
 303.535 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 303.536 +}
 303.537 +
 303.538 +
 303.539 +/* TCP/IP send string
 303.540 + * Accepts: TCP/IP stream
 303.541 + *	    string pointer
 303.542 + *	    byte count
 303.543 + * Returns: T if success else NIL
 303.544 + */
 303.545 +
 303.546 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 303.547 +{
 303.548 +  int i;
 303.549 +  struct timeval tmo;
 303.550 +  fd_set fds,efds;
 303.551 +  time_t t = time (0);
 303.552 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 303.553 +  tmo.tv_sec = ttmo_write;
 303.554 +  tmo.tv_usec = 0;
 303.555 +  FD_ZERO (&fds);		/* initialize selection vector */
 303.556 +  if (stream->tcpso == INVALID_SOCKET) return NIL;
 303.557 +  (*bn) (BLOCK_TCPWRITE,NIL);
 303.558 +  while (size > 0) {		/* until request satisfied */
 303.559 +    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
 303.560 +				/* simple case if not a socket */
 303.561 +    if (stream->tcpsi != stream->tcpso)
 303.562 +      while (((i = write (stream->tcpso,string,min (size,TCPMAXSEND))) < 0) &&
 303.563 +	     (errno == EINTR));
 303.564 +    else {
 303.565 +      time_t tl = time (0);	/* start of request */
 303.566 +      time_t now = tl;
 303.567 +      time_t ti = ttmo_write ? now + ttmo_write : 0;
 303.568 +      tmo.tv_usec = 0;
 303.569 +      FD_ZERO (&fds);		/* initialize selection vector */
 303.570 +      FD_ZERO (&efds);		/* handle errors too */
 303.571 +				/* set bit in selection vectors */
 303.572 +      FD_SET (stream->tcpso,&fds);
 303.573 +      FD_SET(stream->tcpso,&efds);
 303.574 +      errno = NIL;		/* block and write */
 303.575 +      do {			/* block under timeout */
 303.576 +	tmo.tv_sec = (long) (ti ? ti - now : 0);
 303.577 +	i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL);
 303.578 +	now = time (0);		/* fake timeout if interrupt & time expired */
 303.579 +	if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti &&
 303.580 +	    (ti <= now)) i = 0;
 303.581 +      } while ((i < 0) && (errno == WSAEINTR));
 303.582 +				/* OK to send data? */
 303.583 +      if (i > 0) while (((i = send (stream->tcpso,string,
 303.584 +				    (int) min (size,TCPMAXSEND),0)) ==
 303.585 +			 SOCKET_ERROR) &&
 303.586 +			((errno = WSAGetLastError ()) == WSAEINTR));
 303.587 +      else if (!i) {		/* timeout, ignore if told to resume */
 303.588 +	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
 303.589 +				/* otherwise punt */
 303.590 +	if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
 303.591 +	return tcp_abort (stream);
 303.592 +      }
 303.593 +    }
 303.594 +    if (i <= 0) {		/* error seen? */
 303.595 +      if (tcpdebug) {
 303.596 +	char tmp[MAILTMPLEN];
 303.597 +	sprintf (tmp,"TCP write I/O error %d",errno);
 303.598 +	mm_log (tmp,TCPDEBUG);
 303.599 +      }
 303.600 +      return tcp_abort (stream);
 303.601 +    }
 303.602 +    string += i;		/* how much we sent */
 303.603 +    size -= i;			/* count this size */
 303.604 +    if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
 303.605 +  }
 303.606 +  (*bn) (BLOCK_NONE,NIL);
 303.607 +  return T;			/* all done */
 303.608 +}
 303.609 +
 303.610 +/* TCP/IP close
 303.611 + * Accepts: TCP/IP stream
 303.612 + */
 303.613 +
 303.614 +void tcp_close (TCPSTREAM *stream)
 303.615 +{
 303.616 +  tcp_abort (stream);		/* nuke the sockets */
 303.617 +				/* flush host names */
 303.618 +  if (stream->host) fs_give ((void **) &stream->host);
 303.619 +  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
 303.620 +  if (stream->localhost) fs_give ((void **) &stream->localhost);
 303.621 +  fs_give ((void **) &stream);	/* flush the stream */
 303.622 +}
 303.623 +
 303.624 +
 303.625 +/* TCP/IP abort sockets
 303.626 + * Accepts: TCP/IP stream
 303.627 + * Returns: NIL, always
 303.628 + */
 303.629 +
 303.630 +long tcp_abort (TCPSTREAM *stream)
 303.631 +{
 303.632 +  if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
 303.633 +  else stream->tcpso = INVALID_SOCKET;
 303.634 +  return tcp_close_socket (&stream->tcpsi);
 303.635 +}
 303.636 +
 303.637 +
 303.638 +/* TCP/IP abort stream
 303.639 + * Accepts: WinSock socket
 303.640 + * Returns: NIL, always
 303.641 + */
 303.642 +
 303.643 +long tcp_close_socket (SOCKET *sock)
 303.644 +{
 303.645 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 303.646 +				/* something to close? */
 303.647 +  if (sock && (*sock != INVALID_SOCKET)) {
 303.648 +    (*bn) (BLOCK_TCPCLOSE,NIL);
 303.649 +    closesocket (*sock);	/* WinSock socket close */
 303.650 +    *sock = INVALID_SOCKET;
 303.651 +    (*bn) (BLOCK_NONE,NIL);
 303.652 +    wsa_sock_open--;		/* drop this socket */
 303.653 +  }
 303.654 +				/* no more open streams? */
 303.655 +  if (wsa_initted && !wsa_sock_open) {
 303.656 +    mm_log ("Winsock cleanup",NIL);
 303.657 +    wsa_initted = 0;		/* no more sockets, so... */
 303.658 +    WSACleanup ();		/* free up resources until needed */
 303.659 +  }
 303.660 +  return NIL;
 303.661 +}
 303.662 +
 303.663 +/* TCP/IP get host name
 303.664 + * Accepts: TCP/IP stream
 303.665 + * Returns: host name for this stream
 303.666 + */
 303.667 +
 303.668 +char *tcp_host (TCPSTREAM *stream)
 303.669 +{
 303.670 +  return stream->host;		/* use tcp_remotehost() if want guarantees */
 303.671 +}
 303.672 +
 303.673 +
 303.674 +/* TCP/IP get remote host name
 303.675 + * Accepts: TCP/IP stream
 303.676 + * Returns: host name for this stream
 303.677 + */
 303.678 +
 303.679 +char *tcp_remotehost (TCPSTREAM *stream)
 303.680 +{
 303.681 +  if (!stream->remotehost) {
 303.682 +    size_t sadrlen;
 303.683 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 303.684 +    stream->remotehost =	/* get socket's peer name */
 303.685 +      ((getpeername (stream->tcpsi,sadr,&sadrlen) == SOCKET_ERROR) ||
 303.686 +       (sadrlen <= 0)) ? cpystr (stream->host) : tcp_name (sadr,NIL);
 303.687 +    fs_give ((void **) &sadr);
 303.688 +  }
 303.689 +  return stream->remotehost;
 303.690 +}
 303.691 +
 303.692 +
 303.693 +/* TCP/IP return port for this stream
 303.694 + * Accepts: TCP/IP stream
 303.695 + * Returns: port number for this stream
 303.696 + */
 303.697 +
 303.698 +unsigned long tcp_port (TCPSTREAM *stream)
 303.699 +{
 303.700 +  return stream->port;		/* return port number */
 303.701 +}
 303.702 +
 303.703 +
 303.704 +/* TCP/IP get local host name
 303.705 + * Accepts: TCP/IP stream
 303.706 + * Returns: local host name
 303.707 + */
 303.708 +
 303.709 +char *tcp_localhost (TCPSTREAM *stream)
 303.710 +{
 303.711 +  if (!stream->localhost) {
 303.712 +    size_t sadrlen;
 303.713 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 303.714 +    stream->localhost =		/* get socket's name */
 303.715 +      ((stream->port & 0xffff000) ||
 303.716 +       ((getsockname (stream->tcpsi,sadr,&sadrlen) == SOCKET_ERROR) ||
 303.717 +	(sadrlen <= 0))) ? cpystr (mylocalhost ()) : tcp_name (sadr,NIL);
 303.718 +    fs_give ((void **) &sadr);
 303.719 +  }
 303.720 +  return stream->localhost;	/* return local host name */
 303.721 +}
 303.722 +
 303.723 +/* TCP/IP get client host address (server calls only)
 303.724 + * Returns: client host address
 303.725 + */
 303.726 +
 303.727 +char *tcp_clientaddr ()
 303.728 +{
 303.729 +  if (!myClientAddr) {
 303.730 +    size_t sadrlen;
 303.731 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 303.732 +    if ((getpeername (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
 303.733 +	(sadrlen <= 0)) myClientAddr = cpystr ("UNKNOWN");
 303.734 +    else {			/* get stdin's peer name */
 303.735 +      myClientAddr = cpystr (ip_sockaddrtostring (sadr));
 303.736 +      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
 303.737 +    }
 303.738 +    fs_give ((void **) &sadr);
 303.739 +  }
 303.740 +  return myClientAddr;
 303.741 +}
 303.742 +
 303.743 +
 303.744 +/* TCP/IP get client host name (server calls only)
 303.745 + * Returns: client host name
 303.746 + */
 303.747 +
 303.748 +char *tcp_clienthost ()
 303.749 +{
 303.750 +  if (!myClientHost) {
 303.751 +    size_t sadrlen;
 303.752 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 303.753 +    if ((getpeername (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
 303.754 +	(sadrlen <= 0)) myClientHost = cpystr ("UNKNOWN");
 303.755 +    else {			/* get stdin's peer name */
 303.756 +      myClientHost = tcp_name (sadr,T);
 303.757 +      if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr));
 303.758 +      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
 303.759 +    }
 303.760 +    fs_give ((void **) &sadr);
 303.761 +  }
 303.762 +  return myClientHost;
 303.763 +}
 303.764 +
 303.765 +
 303.766 +/* TCP/IP get client port number (server calls only)
 303.767 + * Returns: client port number
 303.768 + */
 303.769 +
 303.770 +long tcp_clientport ()
 303.771 +{
 303.772 +  if (!myClientHost && !myClientAddr) tcp_clientaddr ();
 303.773 +  return myClientPort;
 303.774 +}
 303.775 +
 303.776 +/* TCP/IP get server host address (server calls only)
 303.777 + * Returns: server host address
 303.778 + */
 303.779 +
 303.780 +char *tcp_serveraddr ()
 303.781 +{
 303.782 +  if (!myServerAddr) {
 303.783 +    size_t sadrlen;
 303.784 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 303.785 +    if (!wsa_initted++) {	/* init Windows Sockets */
 303.786 +      WSADATA wsock;
 303.787 +      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
 303.788 +	wsa_initted = 0;
 303.789 +	return "random-pc";	/* try again later? */
 303.790 +      }
 303.791 +    }
 303.792 +    if ((getsockname (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
 303.793 +	(sadrlen <= 0)) myServerAddr = cpystr ("UNKNOWN");
 303.794 +    else {			/* get stdin's name */
 303.795 +      myServerAddr = cpystr (ip_sockaddrtostring (sadr));
 303.796 +      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
 303.797 +    }
 303.798 +    fs_give ((void **) &sadr);
 303.799 +  }
 303.800 +  return myServerAddr;
 303.801 +}
 303.802 +
 303.803 +
 303.804 +/* TCP/IP get server host name (server calls only)
 303.805 + * Returns: server host name
 303.806 + */
 303.807 +
 303.808 +char *tcp_serverhost ()
 303.809 +{
 303.810 +  if (!myServerHost) {		/* once-only */
 303.811 +    size_t sadrlen;
 303.812 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 303.813 +    if (!wsa_initted++) {	/* init Windows Sockets */
 303.814 +      WSADATA wsock;
 303.815 +      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
 303.816 +	wsa_initted = 0;
 303.817 +	return "random-pc";	/* try again later? */
 303.818 +      }
 303.819 +    }
 303.820 +				/* get stdin's name */
 303.821 +    if ((getsockname (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
 303.822 +	(sadrlen <= 0)) myServerHost = cpystr (mylocalhost ());
 303.823 +    else {			/* get stdin's name */
 303.824 +      myServerHost = tcp_name (sadr,NIL);
 303.825 +      if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr));
 303.826 +      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
 303.827 +    }
 303.828 +    fs_give ((void **) &sadr);
 303.829 +  }
 303.830 +  return myServerHost;
 303.831 +}
 303.832 +
 303.833 +
 303.834 +/* TCP/IP get server port number (server calls only)
 303.835 + * Returns: server port number
 303.836 + */
 303.837 +
 303.838 +long tcp_serverport ()
 303.839 +{
 303.840 +  if (!myServerHost && !myServerAddr) tcp_serveraddr ();
 303.841 +  return myServerPort;
 303.842 +}
 303.843 +
 303.844 +/* TCP/IP return canonical form of host name
 303.845 + * Accepts: host name
 303.846 + * Returns: canonical form of host name
 303.847 + */
 303.848 +
 303.849 +char *tcp_canonical (char *name)
 303.850 +{
 303.851 +  char *ret,host[MAILTMPLEN];
 303.852 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 303.853 +				/* look like domain literal? */
 303.854 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 303.855 +  (*bn) (BLOCK_DNSLOOKUP,NIL);
 303.856 +  if (tcpdebug) {
 303.857 +    sprintf (host,"DNS canonicalization %.80s",name);
 303.858 +    mm_log (host,TCPDEBUG);
 303.859 +  }
 303.860 +				/* get canonical name */
 303.861 +  if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name;
 303.862 +  (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 303.863 +  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
 303.864 +  return ret;
 303.865 +}
 303.866 +
 303.867 +
 303.868 +/* TCP/IP return name from socket
 303.869 + * Accepts: socket
 303.870 + *	    verbose flag
 303.871 + * Returns: cpystr name
 303.872 + */
 303.873 +
 303.874 +char *tcp_name (struct sockaddr *sadr,long flag)
 303.875 +{
 303.876 +  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
 303.877 +  sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr));
 303.878 +  if (allowreversedns) {
 303.879 +    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
 303.880 +    if (tcpdebug) {
 303.881 +      sprintf (tmp,"Reverse DNS resolution %s",adr);
 303.882 +      mm_log (tmp,TCPDEBUG);
 303.883 +    }
 303.884 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 303.885 +				/* translate address to name */
 303.886 +    if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) {
 303.887 +				/* produce verbose form if needed */
 303.888 +      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
 303.889 +      else ret = t;
 303.890 +    }
 303.891 +    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 303.892 +    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
 303.893 +  }
 303.894 +  return cpystr (ret);
 303.895 +}
 303.896 +
 303.897 +/* Validate name
 303.898 + * Accepts: domain name
 303.899 + * Returns: T if valid, NIL otherwise
 303.900 + */
 303.901 +
 303.902 +char *tcp_name_valid (char *s)
 303.903 +{
 303.904 +  int c;
 303.905 +  char *ret,*tail;
 303.906 +				/* must be non-empty and not too long */
 303.907 +  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
 303.908 +				/* must be alnum, dot, or hyphen */
 303.909 +    while ((c = *s++) && (s <= tail) &&
 303.910 +	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
 303.911 +	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
 303.912 +    if (c) ret = NIL;
 303.913 +  }
 303.914 +  return ret;
 303.915 +}
   304.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   304.2 +++ b/src/osdep/nt/tcp_nt.h	Mon Sep 14 15:17:45 2009 +0900
   304.3 @@ -0,0 +1,51 @@
   304.4 +/* ========================================================================
   304.5 + * Copyright 1988-2006 University of Washington
   304.6 + *
   304.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   304.8 + * you may not use this file except in compliance with the License.
   304.9 + * You may obtain a copy of the License at
  304.10 + *
  304.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  304.12 + *
  304.13 + * 
  304.14 + * ========================================================================
  304.15 + */
  304.16 +
  304.17 +/*
  304.18 + * Program:	Winsock TCP/IP routines
  304.19 + *
  304.20 + * Author:	Mark Crispin
  304.21 + *	        Networks and Distributed Computing
  304.22 + *		Computing & Communications
  304.23 + *		University of Washington
  304.24 + *		Administration Building, AG-44
  304.25 + *		Seattle, WA  98195
  304.26 + *		Internet: MRC@CAC.Washington.EDU
  304.27 + *
  304.28 + * Date:	11 April 1989
  304.29 + * Last Edited:	30 August 2006
  304.30 + */
  304.31 +
  304.32 +/* TCP input buffer -- must be large enough to prevent overflow */
  304.33 +
  304.34 +#define BUFLEN 16384		/* 32768 causes stdin read() to barf */
  304.35 +
  304.36 +#include <winsock2.h>
  304.37 +#include <ws2tcpip.h>
  304.38 +#undef ERROR			/* quell conflicting definition diagnostic */
  304.39 +
  304.40 +
  304.41 +/* TCP I/O stream (must be before osdep.h is included) */
  304.42 +
  304.43 +#define TCPSTREAM struct tcp_stream
  304.44 +TCPSTREAM {
  304.45 +  char *host;			/* host name */
  304.46 +  char *remotehost;		/* remote host name */
  304.47 +  unsigned long port;		/* port number */
  304.48 +  char *localhost;		/* local host name */
  304.49 +  SOCKET tcpsi;			/* tcp socket */
  304.50 +  SOCKET tcpso;			/* tcp socket */
  304.51 +  long ictr;			/* input counter */
  304.52 +  char *iptr;			/* input pointer */
  304.53 +  char ibuf[BUFLEN];		/* input buffer */
  304.54 +};
   305.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   305.2 +++ b/src/osdep/nt/tenexnt.c	Mon Sep 14 15:17:45 2009 +0900
   305.3 @@ -0,0 +1,1310 @@
   305.4 +/* ========================================================================
   305.5 + * Copyright 1988-2007 University of Washington
   305.6 + *
   305.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   305.8 + * you may not use this file except in compliance with the License.
   305.9 + * You may obtain a copy of the License at
  305.10 + *
  305.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  305.12 + *
  305.13 + * 
  305.14 + * ========================================================================
  305.15 + */
  305.16 +
  305.17 +/*
  305.18 + * Program:	Tenex mail routines
  305.19 + *
  305.20 + * Author:	Mark Crispin
  305.21 + *		Networks and Distributed Computing
  305.22 + *		Computing & Communications
  305.23 + *		University of Washington
  305.24 + *		Administration Building, AG-44
  305.25 + *		Seattle, WA  98195
  305.26 + *		Internet: MRC@CAC.Washington.EDU
  305.27 + *
  305.28 + * Date:	22 May 1990
  305.29 + * Last Edited:	18 June 2007
  305.30 + */
  305.31 +
  305.32 +
  305.33 +/*				FILE TIME SEMANTICS
  305.34 + *
  305.35 + * The atime is the last read time of the file.
  305.36 + * The mtime is the last flags update time of the file.
  305.37 + * The ctime is the last write time of the file.
  305.38 + *
  305.39 + *				TEXT SIZE SEMANTICS
  305.40 + *
  305.41 + * Most of the text sizes are in internal (LF-only) form, except for the
  305.42 + * msg.text size.  Beware.
  305.43 + */
  305.44 +
  305.45 +#include <stdio.h>
  305.46 +#include <ctype.h>
  305.47 +#include <errno.h>
  305.48 +extern int errno;		/* just in case */
  305.49 +#include "mail.h"
  305.50 +#include "osdep.h"
  305.51 +#include <fcntl.h>
  305.52 +#include <time.h>
  305.53 +#include <sys/stat.h>
  305.54 +#include <sys/utime.h>
  305.55 +#include "misc.h"
  305.56 +#include "dummy.h"
  305.57 +
  305.58 +/* TENEX I/O stream local data */
  305.59 +	
  305.60 +typedef struct tenex_local {
  305.61 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  305.62 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  305.63 +  int fd;			/* file descriptor for I/O */
  305.64 +  off_t filesize;		/* file size parsed */
  305.65 +  time_t filetime;		/* last file time */
  305.66 +  time_t lastsnarf;		/* local snarf time */
  305.67 +  unsigned char *buf;		/* temporary buffer */
  305.68 +  unsigned long buflen;		/* current size of temporary buffer */
  305.69 +  unsigned long uid;		/* current text uid */
  305.70 +  SIZEDTEXT text;		/* current text */
  305.71 +} TENEXLOCAL;
  305.72 +
  305.73 +
  305.74 +/* Convenient access to local data */
  305.75 +
  305.76 +#define LOCAL ((TENEXLOCAL *) stream->local)
  305.77 +
  305.78 +
  305.79 +/* Function prototypes */
  305.80 +
  305.81 +DRIVER *tenex_valid (char *name);
  305.82 +int tenex_isvalid (char *name,char *file);
  305.83 +void *tenex_parameters (long function,void *value);
  305.84 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  305.85 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
  305.86 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
  305.87 +long tenex_create (MAILSTREAM *stream,char *mailbox);
  305.88 +long tenex_delete (MAILSTREAM *stream,char *mailbox);
  305.89 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
  305.90 +long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
  305.91 +MAILSTREAM *tenex_open (MAILSTREAM *stream);
  305.92 +void tenex_close (MAILSTREAM *stream,long options);
  305.93 +void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
  305.94 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
  305.95 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
  305.96 +		    unsigned long *length,long flags);
  305.97 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  305.98 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  305.99 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 305.100 +long tenex_ping (MAILSTREAM *stream);
 305.101 +void tenex_check (MAILSTREAM *stream);
 305.102 +void tenex_snarf (MAILSTREAM *stream);
 305.103 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
 305.104 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 305.105 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 305.106 +
 305.107 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
 305.108 +long tenex_parse (MAILSTREAM *stream);
 305.109 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
 305.110 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 305.111 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
 305.112 +			  long syncflag);
 305.113 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 305.114 +			    unsigned long *size);
 305.115 +
 305.116 +
 305.117 +/* Tenex mail routines */
 305.118 +
 305.119 +
 305.120 +/* Driver dispatch used by MAIL */
 305.121 +
 305.122 +DRIVER tenexdriver = {
 305.123 +  "tenex",			/* driver name */
 305.124 +  DR_LOCAL|DR_MAIL,		/* driver flags */
 305.125 +  (DRIVER *) NIL,		/* next driver */
 305.126 +  tenex_valid,			/* mailbox is valid for us */
 305.127 +  tenex_parameters,		/* manipulate parameters */
 305.128 +  tenex_scan,			/* scan mailboxes */
 305.129 +  tenex_list,			/* list mailboxes */
 305.130 +  tenex_lsub,			/* list subscribed mailboxes */
 305.131 +  NIL,				/* subscribe to mailbox */
 305.132 +  NIL,				/* unsubscribe from mailbox */
 305.133 +  tenex_create,			/* create mailbox */
 305.134 +  tenex_delete,			/* delete mailbox */
 305.135 +  tenex_rename,			/* rename mailbox */
 305.136 +  mail_status_default,		/* status of mailbox */
 305.137 +  tenex_open,			/* open mailbox */
 305.138 +  tenex_close,			/* close mailbox */
 305.139 +  tenex_flags,			/* fetch message "fast" attributes */
 305.140 +  tenex_flags,			/* fetch message flags */
 305.141 +  NIL,				/* fetch overview */
 305.142 +  NIL,				/* fetch message envelopes */
 305.143 +  tenex_header,			/* fetch message header */
 305.144 +  tenex_text,			/* fetch message body */
 305.145 +  NIL,				/* fetch partial message text */
 305.146 +  NIL,				/* unique identifier */
 305.147 +  NIL,				/* message number */
 305.148 +  tenex_flag,			/* modify flags */
 305.149 +  tenex_flagmsg,		/* per-message modify flags */
 305.150 +  NIL,				/* search for message based on criteria */
 305.151 +  NIL,				/* sort messages */
 305.152 +  NIL,				/* thread messages */
 305.153 +  tenex_ping,			/* ping mailbox to see if still alive */
 305.154 +  tenex_check,			/* check for new messages */
 305.155 +  tenex_expunge,		/* expunge deleted messages */
 305.156 +  tenex_copy,			/* copy messages to another mailbox */
 305.157 +  tenex_append,			/* append string message to mailbox */
 305.158 +  NIL				/* garbage collect stream */
 305.159 +};
 305.160 +
 305.161 +				/* prototype stream */
 305.162 +MAILSTREAM tenexproto = {&tenexdriver};
 305.163 +
 305.164 +/* Tenex mail validate mailbox
 305.165 + * Accepts: mailbox name
 305.166 + * Returns: our driver if name is valid, NIL otherwise
 305.167 + */
 305.168 +
 305.169 +DRIVER *tenex_valid (char *name)
 305.170 +{
 305.171 +  char tmp[MAILTMPLEN];
 305.172 +  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
 305.173 +}
 305.174 +
 305.175 +
 305.176 +/* Tenex mail test for valid mailbox
 305.177 + * Accepts: mailbox name
 305.178 + *	    buffer to return file name
 305.179 + * Returns: T if valid, NIL otherwise
 305.180 + */
 305.181 +
 305.182 +int tenex_isvalid (char *name,char *file)
 305.183 +{
 305.184 +  int fd;
 305.185 +  int ret = NIL;
 305.186 +  char *s,tmp[MAILTMPLEN];
 305.187 +  struct stat sbuf;
 305.188 +  struct utimbuf times;
 305.189 +  errno = EINVAL;		/* assume invalid argument */
 305.190 +				/* if file, get its status */
 305.191 +  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
 305.192 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
 305.193 +    if (!sbuf.st_size)errno = 0;/* empty file */
 305.194 +    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
 305.195 +      memset (tmp,'\0',MAILTMPLEN);
 305.196 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
 305.197 +	  (s[-1] != '\015')) {	/* valid format? */
 305.198 +	*s = '\0';		/* tie off header */
 305.199 +				/* must begin with dd-mmm-yy" */
 305.200 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 305.201 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 305.202 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 305.203 +      }
 305.204 +      else errno = -1;		/* bogus format */
 305.205 +      close (fd);		/* close the file */
 305.206 +				/* \Marked status? */
 305.207 +      if (sbuf.st_ctime > sbuf.st_atime) {
 305.208 +				/* preserve atime and mtime */
 305.209 +	times.actime = sbuf.st_atime;
 305.210 +	times.modtime = sbuf.st_mtime;
 305.211 +	utime (file,&times);	/* set the times */
 305.212 +      }
 305.213 +    }
 305.214 +  }
 305.215 +				/* in case INBOX but not tenex format */
 305.216 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 305.217 +  return ret;			/* return what we should */
 305.218 +}
 305.219 +
 305.220 +
 305.221 +/* Tenex manipulate driver parameters
 305.222 + * Accepts: function code
 305.223 + *	    function-dependent value
 305.224 + * Returns: function-dependent return value
 305.225 + */
 305.226 +
 305.227 +void *tenex_parameters (long function,void *value)
 305.228 +{
 305.229 +  return NIL;
 305.230 +}
 305.231 +
 305.232 +/* Tenex mail scan mailboxes
 305.233 + * Accepts: mail stream
 305.234 + *	    reference
 305.235 + *	    pattern to search
 305.236 + *	    string to scan
 305.237 + */
 305.238 +
 305.239 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 305.240 +{
 305.241 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 305.242 +}
 305.243 +
 305.244 +
 305.245 +/* Tenex mail list mailboxes
 305.246 + * Accepts: mail stream
 305.247 + *	    reference
 305.248 + *	    pattern to search
 305.249 + */
 305.250 +
 305.251 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
 305.252 +{
 305.253 +  if (stream) dummy_list (NIL,ref,pat);
 305.254 +}
 305.255 +
 305.256 +
 305.257 +/* Tenex mail list subscribed mailboxes
 305.258 + * Accepts: mail stream
 305.259 + *	    reference
 305.260 + *	    pattern to search
 305.261 + */
 305.262 +
 305.263 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
 305.264 +{
 305.265 +  if (stream) dummy_lsub (NIL,ref,pat);
 305.266 +}
 305.267 +
 305.268 +/* Tenex mail create mailbox
 305.269 + * Accepts: MAIL stream
 305.270 + *	    mailbox name to create
 305.271 + * Returns: T on success, NIL on failure
 305.272 + */
 305.273 +
 305.274 +long tenex_create (MAILSTREAM *stream,char *mailbox)
 305.275 +{
 305.276 +  char *s,mbx[MAILTMPLEN];
 305.277 +  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
 305.278 +  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 305.279 +  mm_log (mbx,ERROR);
 305.280 +  return NIL;
 305.281 +}
 305.282 +
 305.283 +
 305.284 +/* Tenex mail delete mailbox
 305.285 + * Accepts: MAIL stream
 305.286 + *	    mailbox name to delete
 305.287 + * Returns: T on success, NIL on failure
 305.288 + */
 305.289 +
 305.290 +long tenex_delete (MAILSTREAM *stream,char *mailbox)
 305.291 +{
 305.292 +  return tenex_rename (stream,mailbox,NIL);
 305.293 +}
 305.294 +
 305.295 +/* Tenex mail rename mailbox
 305.296 + * Accepts: MAIL stream
 305.297 + *	    old mailbox name
 305.298 + *	    new mailbox name (or NIL for delete)
 305.299 + * Returns: T on success, NIL on failure
 305.300 + */
 305.301 +
 305.302 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
 305.303 +{
 305.304 +  long ret = LONGT;
 305.305 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 305.306 +  int fd,ld;
 305.307 +  struct stat sbuf;
 305.308 +  if (!dummy_file (file,old) ||
 305.309 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 305.310 +		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
 305.311 +    sprintf (tmp,newname ?
 305.312 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 305.313 +	     "Can't delete mailbox %.80s: invalid name",
 305.314 +	     old,newname);
 305.315 +    mm_log (tmp,ERROR);
 305.316 +    return NIL;
 305.317 +  }
 305.318 +  else if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
 305.319 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 305.320 +    mm_log (tmp,ERROR);
 305.321 +    return NIL;
 305.322 +  }
 305.323 +				/* get exclusive parse/append permission */
 305.324 +  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
 305.325 +    mm_log ("Unable to lock rename mailbox",ERROR);
 305.326 +    return NIL;
 305.327 +  }
 305.328 +				/* lock out other users */
 305.329 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 305.330 +    close (fd);			/* couldn't lock, give up on it then */
 305.331 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 305.332 +    mm_log (tmp,ERROR);
 305.333 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 305.334 +    return NIL;
 305.335 +  }
 305.336 +
 305.337 +  if (newname) {		/* want rename? */
 305.338 +				/* found superior to destination name? */
 305.339 +    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 305.340 +	((tmp[1] != ':') || (s != tmp + 2))) {
 305.341 +      c = s[1];			/* remember character after delimiter */
 305.342 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 305.343 +				/* name doesn't exist, create it */
 305.344 +      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 305.345 +	*s = '\\';		/* restore delimiter */
 305.346 +	if (!dummy_create (stream,tmp)) ret = NIL;
 305.347 +      }
 305.348 +      else *s = '\\';		/* restore delimiter */
 305.349 +      s[1] = c;			/* restore character after delimiter */
 305.350 +    }
 305.351 +    flock (fd,LOCK_UN);		/* release lock on the file */
 305.352 +    close (fd);			/* pacify NTFS */
 305.353 +				/* rename the file */
 305.354 +    if (ret && rename (file,tmp)) {
 305.355 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 305.356 +	       strerror (errno));
 305.357 +      mm_log (tmp,ERROR);
 305.358 +      ret = NIL;		/* set failure */
 305.359 +    }
 305.360 +  }
 305.361 +  else {
 305.362 +    flock (fd,LOCK_UN);		/* release lock on the file */
 305.363 +    close (fd);			/* pacify NTFS */
 305.364 +    if (unlink (file)) {
 305.365 +      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
 305.366 +      mm_log (tmp,ERROR);
 305.367 +      ret = NIL;		/* set failure */
 305.368 +    }
 305.369 +  }
 305.370 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 305.371 +  return ret;			/* return success */
 305.372 +}
 305.373 +
 305.374 +/* Tenex mail open
 305.375 + * Accepts: stream to open
 305.376 + * Returns: stream on success, NIL on failure
 305.377 + */
 305.378 +
 305.379 +MAILSTREAM *tenex_open (MAILSTREAM *stream)
 305.380 +{
 305.381 +  int fd,ld;
 305.382 +  char tmp[MAILTMPLEN];
 305.383 +				/* return prototype for OP_PROTOTYPE call */
 305.384 +  if (!stream) return &tenexproto;
 305.385 +  if (stream->local) fatal ("tenex recycle stream");
 305.386 +				/* canonicalize the mailbox name */
 305.387 +  if (!dummy_file (tmp,stream->mailbox)) {
 305.388 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 305.389 +    mm_log (tmp,ERROR);
 305.390 +  }
 305.391 +  if (stream->rdonly ||
 305.392 +      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
 305.393 +    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
 305.394 +      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
 305.395 +      mm_log (tmp,ERROR);
 305.396 +      return NIL;
 305.397 +    }
 305.398 +    else if (!stream->rdonly) {	/* got it, but readonly */
 305.399 +      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 305.400 +      stream->rdonly = T;
 305.401 +    }
 305.402 +  }
 305.403 +  stream->local = fs_get (sizeof (TENEXLOCAL));
 305.404 +  LOCAL->fd = fd;		/* bind the file */
 305.405 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 305.406 +  LOCAL->buflen = CHUNKSIZE - 1;
 305.407 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 305.408 +  LOCAL->text.size = CHUNKSIZE - 1;
 305.409 +				/* note if an INBOX or not */
 305.410 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 305.411 +  fs_give ((void **) &stream->mailbox);
 305.412 +  stream->mailbox = cpystr (tmp);
 305.413 +				/* get shared parse permission */
 305.414 +  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
 305.415 +    mm_log ("Unable to lock open mailbox",ERROR);
 305.416 +    return NIL;
 305.417 +  }
 305.418 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 305.419 +  unlockfd (ld,tmp);		/* release shared parse permission */
 305.420 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 305.421 +  LOCAL->filetime = 0;		/* time not set up yet */
 305.422 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 305.423 +  stream->sequence++;		/* bump sequence number */
 305.424 +  stream->uid_validity = (unsigned long) time (0);
 305.425 +				/* parse mailbox */
 305.426 +  stream->nmsgs = stream->recent = 0;
 305.427 +  if (tenex_ping (stream) && !stream->nmsgs)
 305.428 +    mm_log ("Mailbox is empty",(long) NIL);
 305.429 +  if (!LOCAL) return NIL;	/* failure if stream died */
 305.430 +  stream->perm_seen = stream->perm_deleted =
 305.431 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 305.432 +      stream->rdonly ? NIL : T;
 305.433 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 305.434 +  return stream;		/* return stream to caller */
 305.435 +}
 305.436 +
 305.437 +/* Tenex mail close
 305.438 + * Accepts: MAIL stream
 305.439 + *	    close options
 305.440 + */
 305.441 +
 305.442 +void tenex_close (MAILSTREAM *stream,long options)
 305.443 +{
 305.444 +  if (stream && LOCAL) {	/* only if a file is open */
 305.445 +    int silent = stream->silent;
 305.446 +    stream->silent = T;		/* note this stream is dying */
 305.447 +    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
 305.448 +    stream->silent = silent;	/* restore previous status */
 305.449 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 305.450 +    close (LOCAL->fd);		/* close the local file */
 305.451 +				/* free local text buffer */
 305.452 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 305.453 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
 305.454 +				/* nuke the local data */
 305.455 +    fs_give ((void **) &stream->local);
 305.456 +    stream->dtb = NIL;		/* log out the DTB */
 305.457 +  }
 305.458 +}
 305.459 +
 305.460 +/* Tenex mail fetch flags
 305.461 + * Accepts: MAIL stream
 305.462 + *	    sequence
 305.463 + *	    option flags
 305.464 + * Sniffs at file to get flags
 305.465 + */
 305.466 +
 305.467 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
 305.468 +{
 305.469 +  STRING bs;
 305.470 +  MESSAGECACHE *elt;
 305.471 +  unsigned long i;
 305.472 +  if (stream && LOCAL &&
 305.473 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 305.474 +       mail_sequence (stream,sequence)))
 305.475 +    for (i = 1; i <= stream->nmsgs; i++)
 305.476 +      if ((elt = mail_elt (stream,i))->sequence) {
 305.477 +	if (!elt->rfc822_size) { /* have header size yet? */
 305.478 +	  lseek (LOCAL->fd,elt->private.special.offset +
 305.479 +		 elt->private.special.text.size,L_SET);
 305.480 +				/* resize bigbuf if necessary */
 305.481 +	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
 305.482 +	    fs_give ((void **) &LOCAL->buf);
 305.483 +	    LOCAL->buflen = elt->private.msg.full.text.size;
 305.484 +	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
 305.485 +	  }
 305.486 +				/* tie off string */
 305.487 +	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
 305.488 +				/* read in the message */
 305.489 +	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
 305.490 +	  INIT (&bs,mail_string,(void *) LOCAL->buf,
 305.491 +		elt->private.msg.full.text.size);
 305.492 +				/* calculate its CRLF size */
 305.493 +	  elt->rfc822_size = unix_crlflen (&bs);
 305.494 +	}
 305.495 +	tenex_elt (stream,i);	/* get current flags from file */
 305.496 +      }
 305.497 +}
 305.498 +
 305.499 +/* TENEX mail fetch message header
 305.500 + * Accepts: MAIL stream
 305.501 + *	    message # to fetch
 305.502 + *	    pointer to returned header text length
 305.503 + *	    option flags
 305.504 + * Returns: message header in RFC822 format
 305.505 + */
 305.506 +
 305.507 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
 305.508 +		    unsigned long *length,long flags)
 305.509 +{
 305.510 +  char *s;
 305.511 +  unsigned long i;
 305.512 +  *length = 0;			/* default to empty */
 305.513 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 305.514 +				/* get to header position */
 305.515 +  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
 305.516 +  if (flags & FT_INTERNAL) {
 305.517 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 305.518 +      fs_give ((void **) &LOCAL->buf);
 305.519 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 305.520 +    }
 305.521 +				/* slurp the data */
 305.522 +    read (LOCAL->fd,LOCAL->buf,*length = i);
 305.523 +  }
 305.524 +  else {
 305.525 +    s = (char *) fs_get (i + 1);/* get readin buffer */
 305.526 +    s[i] = '\0';		/* tie off string */
 305.527 +    read (LOCAL->fd,s,i);	/* slurp the data */
 305.528 +				/* make CRLF copy of string */
 305.529 +    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
 305.530 +    fs_give ((void **) &s);	/* free readin buffer */
 305.531 +  }
 305.532 +  return LOCAL->buf;
 305.533 +}
 305.534 +
 305.535 +/* TENEX mail fetch message text (body only)
 305.536 + * Accepts: MAIL stream
 305.537 + *	    message # to fetch
 305.538 + *	    pointer to returned stringstruct
 305.539 + *	    option flags
 305.540 + * Returns: T, always
 305.541 + */
 305.542 +
 305.543 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 305.544 +{
 305.545 +  char *s;
 305.546 +  unsigned long i,j;
 305.547 +  MESSAGECACHE *elt;
 305.548 +				/* UID call "impossible" */
 305.549 +  if (flags & FT_UID) return NIL;
 305.550 +				/* get message status */
 305.551 +  elt = tenex_elt (stream,msgno);
 305.552 +				/* if message not seen */
 305.553 +  if (!(flags & FT_PEEK) && !elt->seen) {
 305.554 +    elt->seen = T;		/* mark message as seen */
 305.555 +				/* recalculate status */
 305.556 +    tenex_update_status (stream,msgno,T);
 305.557 +    mm_flags (stream,msgno);
 305.558 +  }
 305.559 +  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
 305.560 +				/* find header position */
 305.561 +    i = tenex_hdrpos (stream,msgno,&j);
 305.562 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 305.563 +      fs_give ((void **) &LOCAL->buf);
 305.564 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 305.565 +    }
 305.566 +				/* go to text position */
 305.567 +    lseek (LOCAL->fd,i + j,L_SET);
 305.568 +				/* slurp the data */
 305.569 +    if (read (LOCAL->fd,LOCAL->buf,i) != (long) i) return NIL;
 305.570 +				/* set up stringstruct for internal */
 305.571 +    INIT (bs,mail_string,LOCAL->buf,i);
 305.572 +  }
 305.573 +  else {			/* normal form, previous text cached? */
 305.574 +    if (elt->private.uid == LOCAL->uid)
 305.575 +      i = elt->private.msg.text.text.size;
 305.576 +    else {			/* not cached, cache it now */
 305.577 +      LOCAL->uid = elt->private.uid;
 305.578 +				/* find header position */
 305.579 +      i = tenex_hdrpos (stream,msgno,&j);
 305.580 +				/* go to text position */
 305.581 +      lseek (LOCAL->fd,i + j,L_SET);
 305.582 +      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
 305.583 +      s[i] = '\0';		/* tie off string */
 305.584 +      read (LOCAL->fd,s,i);	/* slurp the data */
 305.585 +				/* make CRLF copy of string */
 305.586 +      i = elt->private.msg.text.text.size =
 305.587 +	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
 305.588 +      fs_give ((void **) &s);	/* free readin buffer */
 305.589 +    }
 305.590 +				/* set up stringstruct */
 305.591 +    INIT (bs,mail_string,LOCAL->text.data,i);
 305.592 +  }
 305.593 +  return T;			/* success */
 305.594 +}
 305.595 +
 305.596 +/* Tenex mail modify flags
 305.597 + * Accepts: MAIL stream
 305.598 + *	    sequence
 305.599 + *	    flag(s)
 305.600 + *	    option flags
 305.601 + */
 305.602 +
 305.603 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 305.604 +{
 305.605 +  struct utimbuf times;
 305.606 +  struct stat sbuf;
 305.607 +  if (!stream->rdonly) {	/* make sure the update takes */
 305.608 +    fsync (LOCAL->fd);
 305.609 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 305.610 +    times.modtime = LOCAL->filetime = sbuf.st_mtime;
 305.611 +    times.actime = time (0);	/* make sure read comes after all that */
 305.612 +    utime (stream->mailbox,&times);
 305.613 +  }
 305.614 +}
 305.615 +
 305.616 +
 305.617 +/* Tenex mail per-message modify flags
 305.618 + * Accepts: MAIL stream
 305.619 + *	    message cache element
 305.620 + */
 305.621 +
 305.622 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 305.623 +{
 305.624 +  struct stat sbuf;
 305.625 +				/* maybe need to do a checkpoint? */
 305.626 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 305.627 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 305.628 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 305.629 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 305.630 +  }
 305.631 +				/* recalculate status */
 305.632 +  tenex_update_status (stream,elt->msgno,NIL);
 305.633 +}
 305.634 +
 305.635 +/* Tenex mail ping mailbox
 305.636 + * Accepts: MAIL stream
 305.637 + * Returns: T if stream still alive, NIL if not
 305.638 + */
 305.639 +
 305.640 +long tenex_ping (MAILSTREAM *stream)
 305.641 +{
 305.642 +  unsigned long i = 1;
 305.643 +  long r = T;
 305.644 +  int ld;
 305.645 +  char lock[MAILTMPLEN];
 305.646 +  struct stat sbuf;
 305.647 +  if (stream && LOCAL) {	/* only if stream already open */
 305.648 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 305.649 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 305.650 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 305.651 +				/* check for changed message status */
 305.652 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 305.653 +      LOCAL->filetime = sbuf.st_mtime;
 305.654 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 305.655 +	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
 305.656 +      while (i <= stream->nmsgs) tenex_elt (stream,i++);
 305.657 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 305.658 +    }
 305.659 +				/* get shared parse/append permission */
 305.660 +    if ((sbuf.st_size != LOCAL->filesize) &&
 305.661 +	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
 305.662 +				/* parse resulting mailbox */
 305.663 +      r = (tenex_parse (stream)) ? T : NIL;
 305.664 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 305.665 +    }
 305.666 +  }
 305.667 +  return r;			/* return result of the parse */
 305.668 +}
 305.669 +
 305.670 +
 305.671 +/* Tenex mail check mailbox (reparses status too)
 305.672 + * Accepts: MAIL stream
 305.673 + */
 305.674 +
 305.675 +void tenex_check (MAILSTREAM *stream)
 305.676 +{
 305.677 +				/* mark that a check is desired */
 305.678 +  if (LOCAL) LOCAL->mustcheck = T;
 305.679 +  if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL);
 305.680 +}
 305.681 +
 305.682 +/* Tenex mail expunge mailbox
 305.683 + *	    sequence to expunge if non-NIL
 305.684 + *	    expunge options
 305.685 + * Returns: T, always
 305.686 + */
 305.687 +
 305.688 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
 305.689 +{
 305.690 +  long ret;
 305.691 +  struct utimbuf times;
 305.692 +  struct stat sbuf;
 305.693 +  off_t pos = 0;
 305.694 +  int ld;
 305.695 +  unsigned long i = 1;
 305.696 +  unsigned long j,k,m,recent;
 305.697 +  unsigned long n = 0;
 305.698 +  unsigned long delta = 0;
 305.699 +  char lock[MAILTMPLEN];
 305.700 +  MESSAGECACHE *elt;
 305.701 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 305.702 +			   mail_uid_sequence (stream,sequence) :
 305.703 +			   mail_sequence (stream,sequence)) : LONGT) &&
 305.704 +	tenex_ping (stream)));	/* parse sequence if given, ping stream */
 305.705 +  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
 305.706 +  else {
 305.707 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 305.708 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 305.709 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 305.710 +    }
 305.711 +				/* get exclusive access */
 305.712 +    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
 305.713 +      mm_log ("Unable to lock expunge mailbox",ERROR);
 305.714 +				/* make sure see any newly-arrived messages */
 305.715 +    else if (!tenex_parse (stream));
 305.716 +				/* get exclusive access */
 305.717 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 305.718 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 305.719 +      mm_log ("Can't expunge because mailbox is in use by another process",
 305.720 +	      ERROR);
 305.721 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 305.722 +    }
 305.723 +
 305.724 +    else {
 305.725 +      mm_critical (stream);	/* go critical */
 305.726 +      recent = stream->recent;	/* get recent now that pinged and locked */
 305.727 +				/* for each message */
 305.728 +      while (i <= stream->nmsgs) {
 305.729 +				/* get cache element */
 305.730 +	elt = tenex_elt (stream,i);
 305.731 +				/* number of bytes to smash or preserve */
 305.732 +	k = elt->private.special.text.size + tenex_size (stream,i);
 305.733 +				/* if need to expunge this message */
 305.734 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 305.735 +				/* if recent, note one less recent message */
 305.736 +	  if (elt->recent) --recent;
 305.737 +	  delta += k;		/* number of bytes to delete */
 305.738 +				/* notify upper levels */
 305.739 +	  mail_expunged (stream,i);
 305.740 +	  n++;			/* count up one more expunged message */
 305.741 +	}
 305.742 +	else if (i++ && delta) {/* preserved message */
 305.743 +				/* first byte to preserve */
 305.744 +	  j = elt->private.special.offset;
 305.745 +	  do {			/* read from source position */
 305.746 +	    m = min (k,LOCAL->buflen);
 305.747 +	    lseek (LOCAL->fd,j,L_SET);
 305.748 +	    read (LOCAL->fd,LOCAL->buf,m);
 305.749 +	    pos = j - delta;	/* write to destination position */
 305.750 +	    while (T) {
 305.751 +	      lseek (LOCAL->fd,pos,L_SET);
 305.752 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 305.753 +	      mm_notify (stream,strerror (errno),WARN);
 305.754 +	      mm_diskerror (stream,errno,T);
 305.755 +	    }
 305.756 +	    pos += m;		/* new position */
 305.757 +	    j += m;		/* next chunk, perhaps */
 305.758 +	  } while (k -= m);	/* until done */
 305.759 +				/* note the new address of this text */
 305.760 +	  elt->private.special.offset -= delta;
 305.761 +	}
 305.762 +				/* preserved but no deleted messages */
 305.763 +	else pos = elt->private.special.offset + k;
 305.764 +      }
 305.765 +
 305.766 +      if (n) {			/* truncate file after last message */
 305.767 +	if (pos != (LOCAL->filesize -= delta)) {
 305.768 +	  sprintf (LOCAL->buf,
 305.769 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 305.770 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 305.771 +	  mm_log (LOCAL->buf,WARN);
 305.772 +	  LOCAL->filesize = pos;/* fix it then */
 305.773 +	}
 305.774 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 305.775 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 305.776 +				/* output the news */
 305.777 +	mm_log (LOCAL->buf,(long) NIL);
 305.778 +      }
 305.779 +      else mm_log ("No messages deleted, so no update needed",(long) NIL);
 305.780 +      fsync (LOCAL->fd);	/* force disk update */
 305.781 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 305.782 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 305.783 +      times.actime = time (0);	/* reset atime to now */
 305.784 +      utime (stream->mailbox,&times);
 305.785 +      mm_nocritical (stream);	/* release critical */
 305.786 +				/* notify upper level of new mailbox size */
 305.787 +      mail_exists (stream,stream->nmsgs);
 305.788 +      mail_recent (stream,recent);
 305.789 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 305.790 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 305.791 +    }
 305.792 +  }
 305.793 +  return ret;
 305.794 +}
 305.795 +
 305.796 +/* Tenex mail copy message(s)
 305.797 + * Accepts: MAIL stream
 305.798 + *	    sequence
 305.799 + *	    destination mailbox
 305.800 + *	    copy options
 305.801 + * Returns: T if success, NIL if failed
 305.802 + */
 305.803 +
 305.804 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 305.805 +{
 305.806 +  struct stat sbuf;
 305.807 +  struct utimbuf times;
 305.808 +  MESSAGECACHE *elt;
 305.809 +  unsigned long i,j,k;
 305.810 +  long ret = LONGT;
 305.811 +  int fd,ld;
 305.812 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 305.813 +  mailproxycopy_t pc =
 305.814 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 305.815 +				/* make sure valid mailbox */
 305.816 +  if (!tenex_isvalid (mailbox,file)) switch (errno) {
 305.817 +  case ENOENT:			/* no such file? */
 305.818 +    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 305.819 +    return NIL;
 305.820 +  case 0:			/* merely empty file? */
 305.821 +    break;
 305.822 +  case EACCES:			/* file protected */
 305.823 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 305.824 +    MM_LOG (LOCAL->buf,ERROR);
 305.825 +    return NIL;
 305.826 +  case EINVAL:
 305.827 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 305.828 +    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
 305.829 +    mm_log (LOCAL->buf,ERROR);
 305.830 +    return NIL;
 305.831 +  default:
 305.832 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 305.833 +    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
 305.834 +    mm_log (LOCAL->buf,ERROR);
 305.835 +    return NIL;
 305.836 +  }
 305.837 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 305.838 +	mail_sequence (stream,sequence))) return NIL;
 305.839 +				/* got file? */  
 305.840 +  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
 305.841 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
 305.842 +    mm_log (LOCAL->buf,ERROR);
 305.843 +    return NIL;
 305.844 +  }
 305.845 +  mm_critical (stream);		/* go critical */
 305.846 +				/* get exclusive parse/append permission */
 305.847 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 305.848 +    mm_log ("Unable to lock copy mailbox",ERROR);
 305.849 +    mm_nocritical (stream);
 305.850 +    return NIL;
 305.851 +  }
 305.852 +  fstat (fd,&sbuf);		/* get current file size */
 305.853 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 305.854 +
 305.855 +				/* for each requested message */
 305.856 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 305.857 +    if ((elt = mail_elt (stream,i))->sequence) {
 305.858 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 305.859 +				/* number of bytes to copy */
 305.860 +      k = elt->private.special.text.size + tenex_size (stream,i);
 305.861 +      do {			/* read from source position */
 305.862 +	j = min (k,LOCAL->buflen);
 305.863 +	read (LOCAL->fd,LOCAL->buf,j);
 305.864 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 305.865 +      } while (ret && (k -= j));/* until done */
 305.866 +    }
 305.867 +				/* delete all requested messages */
 305.868 +  if (ret && (options & CP_MOVE)) {
 305.869 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 305.870 +    mm_log (LOCAL->buf,ERROR);
 305.871 +    ftruncate (fd,sbuf.st_size);
 305.872 +  }
 305.873 +				/* set atime to now-1 if successful copy */
 305.874 +  if (ret) times.actime = time (0) - 1;
 305.875 +				/* else preserved \Marked status */
 305.876 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 305.877 +	 sbuf.st_atime : time (0);
 305.878 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 305.879 +  utime (file,&times);		/* set the times */
 305.880 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 305.881 +  close (fd);			/* close the file */
 305.882 +  mm_nocritical (stream);	/* release critical */
 305.883 +				/* delete all requested messages */
 305.884 +  if (ret && (options & CP_MOVE)) {
 305.885 +    for (i = 1; i <= stream->nmsgs; i++)
 305.886 +      if ((elt = tenex_elt (stream,i))->sequence) {
 305.887 +	elt->deleted = T;	/* mark message deleted */
 305.888 +				/* recalculate status */
 305.889 +	tenex_update_status (stream,i,NIL);
 305.890 +      }
 305.891 +    if (!stream->rdonly) {	/* make sure the update takes */
 305.892 +      fsync (LOCAL->fd);
 305.893 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 305.894 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 305.895 +      times.actime = time (0);	/* make sure atime remains greater */
 305.896 +      utime (stream->mailbox,&times);
 305.897 +    }
 305.898 +  }
 305.899 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 305.900 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
 305.901 +  return ret;
 305.902 +}
 305.903 +
 305.904 +/* Tenex mail append message from stringstruct
 305.905 + * Accepts: MAIL stream
 305.906 + *	    destination mailbox
 305.907 + *	    append callback
 305.908 + *	    data for callback
 305.909 + * Returns: T if append successful, else NIL
 305.910 + */
 305.911 +
 305.912 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 305.913 +{
 305.914 +  struct stat sbuf;
 305.915 +  int fd,ld,c;
 305.916 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 305.917 +  struct utimbuf times;
 305.918 +  FILE *df;
 305.919 +  MESSAGECACHE elt;
 305.920 +  long f;
 305.921 +  unsigned long i,j,uf,size;
 305.922 +  STRING *message;
 305.923 +  long ret = LONGT;
 305.924 +				/* default stream to prototype */
 305.925 +  if (!stream) stream = &tenexproto;
 305.926 +				/* make sure valid mailbox */
 305.927 +  if (!tenex_isvalid (mailbox,file)) switch (errno) {
 305.928 +  case ENOENT:			/* no such file? */
 305.929 +    if (!compare_cstring (mailbox,"INBOX")) tenex_create (NIL,"INBOX");
 305.930 +    else {
 305.931 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 305.932 +      return NIL;
 305.933 +    }
 305.934 +				/* falls through */
 305.935 +  case 0:			/* merely empty file? */
 305.936 +    break;
 305.937 +  case EACCES:			/* file protected */
 305.938 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 305.939 +    MM_LOG (tmp,ERROR);
 305.940 +    return NIL;
 305.941 +  case EINVAL:
 305.942 +    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
 305.943 +    mm_log (tmp,ERROR);
 305.944 +    return NIL;
 305.945 +  default:
 305.946 +    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
 305.947 +    mm_log (tmp,ERROR);
 305.948 +    return NIL;
 305.949 +  }
 305.950 +				/* get first message */
 305.951 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
 305.952 +
 305.953 +				/* open destination mailbox */
 305.954 +  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
 305.955 +       < 0) || !(df = fdopen (fd,"ab"))) {
 305.956 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
 305.957 +    mm_log (tmp,ERROR);
 305.958 +    return NIL;
 305.959 +  }
 305.960 +				/* get parse/append permission */
 305.961 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 305.962 +    mm_log ("Unable to lock append mailbox",ERROR);
 305.963 +    close (fd);
 305.964 +    return NIL;
 305.965 +  }
 305.966 +  mm_critical (stream);		/* go critical */
 305.967 +  fstat (fd,&sbuf);		/* get current file size */
 305.968 +  errno = 0;
 305.969 +  do {				/* parse flags */
 305.970 +    if (!SIZE (message)) {	/* guard against zero-length */
 305.971 +      mm_log ("Append of zero-length message",ERROR);
 305.972 +      ret = NIL;
 305.973 +      break;
 305.974 +    }
 305.975 +    f = mail_parse_flags (stream,flags,&i);
 305.976 +				/* reverse bits (dontcha wish we had CIRC?) */
 305.977 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
 305.978 +    if (date) {			/* parse date if given */
 305.979 +      if (!mail_parse_date (&elt,date)) {
 305.980 +	sprintf (tmp,"Bad date in append: %.80s",date);
 305.981 +	mm_log (tmp,ERROR);
 305.982 +	ret = NIL;		/* mark failure */
 305.983 +	break;
 305.984 +      }
 305.985 +      mail_date (tmp,&elt);	/* write preseved date */
 305.986 +    }
 305.987 +    else internal_date (tmp);	/* get current date in IMAP format */
 305.988 +    i = GETPOS (message);	/* remember current position */
 305.989 +    for (j = SIZE (message), size = 0; j; --j)
 305.990 +      if (SNX (message) != '\015') ++size;
 305.991 +    SETPOS (message,i);		/* restore position */
 305.992 +				/* write header */
 305.993 +    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
 305.994 +      ret = NIL;
 305.995 +    else {			/* write message */
 305.996 +      while (size) if ((c = 0xff & SNX (message)) != '\015') {
 305.997 +	if (putc (c,df) != EOF) --size;
 305.998 +	else break;
 305.999 +      }
305.1000 +				/* get next message */
305.1001 +      if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
305.1002 +    }
305.1003 +  } while (ret && message);
305.1004 +				/* if error... */
305.1005 +  if (!ret || (fflush (df) == EOF)) {
305.1006 +    ftruncate (fd,sbuf.st_size);/* revert file */
305.1007 +    close (fd);			/* make sure fclose() doesn't corrupt us */
305.1008 +    if (errno) {
305.1009 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
305.1010 +      mm_log (tmp,ERROR);
305.1011 +    }
305.1012 +    ret = NIL;
305.1013 +  }
305.1014 +  if (ret) times.actime = time (0) - 1;
305.1015 +				/* else preserved \Marked status */
305.1016 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
305.1017 +	 sbuf.st_atime : time (0);
305.1018 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
305.1019 +  utime (file,&times);		/* set the times */
305.1020 +  fclose (df);			/* close the file */
305.1021 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
305.1022 +  mm_nocritical (stream);	/* release critical */
305.1023 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
305.1024 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
305.1025 +	    WARN);
305.1026 +  return ret;
305.1027 +}
305.1028 +
305.1029 +/* Internal routines */
305.1030 +
305.1031 +
305.1032 +/* Tenex mail return internal message size in bytes
305.1033 + * Accepts: MAIL stream
305.1034 + *	    message #
305.1035 + * Returns: internal size of message
305.1036 + */
305.1037 +
305.1038 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
305.1039 +{
305.1040 +  MESSAGECACHE *elt = mail_elt (stream,m);
305.1041 +  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
305.1042 +	  LOCAL->filesize) -
305.1043 +	    (elt->private.special.offset + elt->private.special.text.size);
305.1044 +}
305.1045 +
305.1046 +/* Tenex mail parse mailbox
305.1047 + * Accepts: MAIL stream
305.1048 + * Returns: T if parse OK
305.1049 + *	    NIL if failure, stream aborted
305.1050 + */
305.1051 +
305.1052 +long tenex_parse (MAILSTREAM *stream)
305.1053 +{
305.1054 +  struct stat sbuf;
305.1055 +  MESSAGECACHE *elt = NIL;
305.1056 +  unsigned char c,*s,*t,*x;
305.1057 +  char tmp[MAILTMPLEN];
305.1058 +  unsigned long i,j;
305.1059 +  long curpos = LOCAL->filesize;
305.1060 +  long nmsgs = stream->nmsgs;
305.1061 +  long recent = stream->recent;
305.1062 +  short added = NIL;
305.1063 +  short silent = stream->silent;
305.1064 +  fstat (LOCAL->fd,&sbuf);	/* get status */
305.1065 +  if (sbuf.st_size < curpos) {	/* sanity check */
305.1066 +    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
305.1067 +    mm_log (tmp,ERROR);
305.1068 +    tenex_close (stream,NIL);
305.1069 +    return NIL;
305.1070 +  }
305.1071 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
305.1072 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
305.1073 +				/* get to that position in the file */
305.1074 +    lseek (LOCAL->fd,curpos,L_SET);
305.1075 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
305.1076 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
305.1077 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
305.1078 +	       i ? strerror (errno) : "no data read");
305.1079 +      mm_log (tmp,ERROR);
305.1080 +      tenex_close (stream,NIL);
305.1081 +      return NIL;
305.1082 +    }
305.1083 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
305.1084 +    if (!(s = strchr (LOCAL->buf,'\012'))) {
305.1085 +      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
305.1086 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
305.1087 +      mm_log (tmp,ERROR);
305.1088 +      tenex_close (stream,NIL);
305.1089 +      return NIL;
305.1090 +    }
305.1091 +    *s = '\0';			/* tie off header line */
305.1092 +    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
305.1093 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
305.1094 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
305.1095 +	       (unsigned long) curpos,(char *) LOCAL->buf);
305.1096 +      mm_log (tmp,ERROR);
305.1097 +      tenex_close (stream,NIL);
305.1098 +      return NIL;
305.1099 +    }
305.1100 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
305.1101 +
305.1102 +    added = T;			/* note that a new message was added */
305.1103 +				/* swell the cache */
305.1104 +    mail_exists (stream,++nmsgs);
305.1105 +				/* instantiate an elt for this message */
305.1106 +    (elt = mail_elt (stream,nmsgs))->valid = T;
305.1107 +    elt->private.uid = ++stream->uid_last;
305.1108 +				/* note file offset of header */
305.1109 +    elt->private.special.offset = curpos;
305.1110 +				/* in case error */
305.1111 +    elt->private.special.text.size = 0;
305.1112 +				/* header size not known yet */
305.1113 +    elt->private.msg.header.text.size = 0;
305.1114 +    x = s;			/* parse the header components */
305.1115 +    if (mail_parse_date (elt,LOCAL->buf) &&
305.1116 +	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
305.1117 +	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
305.1118 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
305.1119 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
305.1120 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
305.1121 +      elt->private.special.text.size = i;
305.1122 +    else {			/* oops */
305.1123 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
305.1124 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
305.1125 +      mm_log (tmp,ERROR);
305.1126 +      tenex_close (stream,NIL);
305.1127 +      return NIL;
305.1128 +    }
305.1129 +				/* make sure didn't run off end of file */
305.1130 +    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
305.1131 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
305.1132 +	       elt->private.special.offset,(unsigned long) curpos,
305.1133 +	       (unsigned long) sbuf.st_size);
305.1134 +      mm_log (tmp,ERROR);
305.1135 +      tenex_close (stream,NIL);
305.1136 +      return NIL;
305.1137 +    }
305.1138 +    c = t[10];			/* remember first system flags byte */
305.1139 +    t[10] = '\0';		/* tie off flags */
305.1140 +    j = strtoul (t,NIL,8);	/* get user flags value */
305.1141 +    t[10] = c;			/* restore first system flags byte */
305.1142 +				/* set up all valid user flags (reversed!) */
305.1143 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
305.1144 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
305.1145 +				/* calculate system flags */
305.1146 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
305.1147 +    if (j & fDELETED) elt->deleted = T;
305.1148 +    if (j & fFLAGGED) elt->flagged = T;
305.1149 +    if (j & fANSWERED) elt->answered = T;
305.1150 +    if (j & fDRAFT) elt->draft = T;
305.1151 +    if (!(j & fOLD)) {		/* newly arrived message? */
305.1152 +      elt->recent = T;
305.1153 +      recent++;			/* count up a new recent message */
305.1154 +				/* mark it as old */
305.1155 +      tenex_update_status (stream,nmsgs,NIL);
305.1156 +    }
305.1157 +  }
305.1158 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
305.1159 +				/* update parsed file size and time */
305.1160 +  LOCAL->filesize = sbuf.st_size;
305.1161 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
305.1162 +  LOCAL->filetime = sbuf.st_mtime;
305.1163 +  if (added && !stream->rdonly){/* make sure atime updated */
305.1164 +    struct utimbuf times;
305.1165 +    times.actime = time (0);
305.1166 +    times.modtime = LOCAL->filetime;
305.1167 +    utime (stream->mailbox,&times);
305.1168 +  }
305.1169 +  stream->silent = silent;	/* can pass up events now */
305.1170 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
305.1171 +  mail_recent (stream,recent);	/* and of change in recent messages */
305.1172 +  return LONGT;			/* return the winnage */
305.1173 +}
305.1174 +
305.1175 +/* Tenex get cache element with status updating from file
305.1176 + * Accepts: MAIL stream
305.1177 + *	    message number
305.1178 + * Returns: cache element
305.1179 + */
305.1180 +
305.1181 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
305.1182 +{
305.1183 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
305.1184 +  struct {			/* old flags */
305.1185 +    unsigned int seen : 1;
305.1186 +    unsigned int deleted : 1;
305.1187 +    unsigned int flagged : 1;
305.1188 +    unsigned int answered : 1;
305.1189 +    unsigned int draft : 1;
305.1190 +    unsigned long user_flags;
305.1191 +  } old;
305.1192 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
305.1193 +  old.answered = elt->answered; old.draft = elt->draft;
305.1194 +  old.user_flags = elt->user_flags;
305.1195 +  tenex_read_flags (stream,elt);
305.1196 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
305.1197 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
305.1198 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
305.1199 +    mm_flags (stream,msgno);	/* let top level know */
305.1200 +  return elt;
305.1201 +}
305.1202 +
305.1203 +
305.1204 +/* Tenex read flags from file
305.1205 + * Accepts: MAIL stream
305.1206 + * Returns: cache element
305.1207 + */
305.1208 +
305.1209 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
305.1210 +{
305.1211 +  unsigned long i,j;
305.1212 +				/* noop if readonly and have valid flags */
305.1213 +  if (stream->rdonly && elt->valid) return;
305.1214 +				/* set the seek pointer */
305.1215 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
305.1216 +	 elt->private.special.text.size - 13,L_SET);
305.1217 +				/* read the new flags */
305.1218 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
305.1219 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
305.1220 +    fatal (LOCAL->buf);
305.1221 +  }
305.1222 +				/* calculate system flags */
305.1223 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
305.1224 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
305.1225 +  elt->flagged = i & fFLAGGED ? T : NIL;
305.1226 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
305.1227 +  LOCAL->buf[10] = '\0';	/* tie off flags */
305.1228 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
305.1229 +				/* set up all valid user flags (reversed!) */
305.1230 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
305.1231 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
305.1232 +  elt->valid = T;		/* have valid flags now */
305.1233 +}
305.1234 +
305.1235 +/* Tenex update status string
305.1236 + * Accepts: MAIL stream
305.1237 + *	    message number
305.1238 + *	    flag saying whether or not to sync
305.1239 + */
305.1240 +
305.1241 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
305.1242 +{
305.1243 +  struct utimbuf times;
305.1244 +  struct stat sbuf;
305.1245 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
305.1246 +  unsigned long j,k = 0;
305.1247 +				/* readonly */
305.1248 +  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
305.1249 +  else {			/* readwrite */
305.1250 +    j = elt->user_flags;	/* get user flags */
305.1251 +				/* reverse bits (dontcha wish we had CIRC?) */
305.1252 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
305.1253 +				/* print new flag string */
305.1254 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
305.1255 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
305.1256 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
305.1257 +	      (fDRAFT * elt->draft)));
305.1258 +    while (T) {			/* get to that place in the file */
305.1259 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
305.1260 +	     elt->private.special.text.size - 13,L_SET);
305.1261 +				/* write new flags */
305.1262 +      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
305.1263 +      mm_notify (stream,strerror (errno),WARN);
305.1264 +      mm_diskerror (stream,errno,T);
305.1265 +    }
305.1266 +    if (syncflag) {		/* sync if requested */
305.1267 +      fsync (LOCAL->fd);
305.1268 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
305.1269 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
305.1270 +      times.actime = time (0);	/* make sure read is later */
305.1271 +      utime (stream->mailbox,&times);
305.1272 +    }
305.1273 +  }
305.1274 +}
305.1275 +
305.1276 +/* Tenex locate header for a message
305.1277 + * Accepts: MAIL stream
305.1278 + *	    message number
305.1279 + *	    pointer to returned header size
305.1280 + * Returns: position of header in file
305.1281 + */
305.1282 +
305.1283 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
305.1284 +			    unsigned long *size)
305.1285 +{
305.1286 +  unsigned long siz;
305.1287 +  long i = 0;
305.1288 +  char c = '\0';
305.1289 +  char *s = NIL;
305.1290 +  MESSAGECACHE *elt = tenex_elt (stream,msgno);
305.1291 +  unsigned long ret = elt->private.special.offset +
305.1292 +    elt->private.special.text.size;
305.1293 +  unsigned long msiz = tenex_size (stream,msgno);
305.1294 +				/* is header size known? */
305.1295 +  if (!(*size = elt->private.msg.header.text.size)) {
305.1296 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
305.1297 +				/* search message for LF LF */
305.1298 +    for (siz = 0; siz < msiz; siz++) {
305.1299 +      if (--i <= 0)		/* read another buffer as necessary */
305.1300 +	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
305.1301 +				/* two newline sequence? */
305.1302 +      if ((c == '\012') && (*s == '\012')) {
305.1303 +				/* yes, note for later */
305.1304 +	elt->private.msg.header.text.size = (*size = siz + 1);
305.1305 +	return ret;		/* return to caller */
305.1306 +      }
305.1307 +      else c = *s++;		/* next character */
305.1308 +    }
305.1309 +				/* header consumes entire message */
305.1310 +    elt->private.msg.header.text.size = *size = msiz;
305.1311 +  }
305.1312 +  return ret;
305.1313 +}
   306.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   306.2 +++ b/src/osdep/nt/unixnt.c	Mon Sep 14 15:17:45 2009 +0900
   306.3 @@ -0,0 +1,2297 @@
   306.4 +/* ========================================================================
   306.5 + * Copyright 1988-2008 University of Washington
   306.6 + *
   306.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   306.8 + * you may not use this file except in compliance with the License.
   306.9 + * You may obtain a copy of the License at
  306.10 + *
  306.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  306.12 + *
  306.13 + * 
  306.14 + * ========================================================================
  306.15 + */
  306.16 +
  306.17 +/*
  306.18 + * Program:	UNIX mail routines
  306.19 + *
  306.20 + * Author:	Mark Crispin
  306.21 + *		UW Technology
  306.22 + *		University of Washington
  306.23 + *		Seattle, WA  98195
  306.24 + *		Internet: MRC@CAC.Washington.EDU
  306.25 + *
  306.26 + * Date:	20 December 1989
  306.27 + * Last Edited:	27 March 2008
  306.28 + */
  306.29 +
  306.30 +
  306.31 +/*				DEDICATION
  306.32 + *
  306.33 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  306.34 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  306.35 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  306.36 + * a two-month bout with cirrhosis of the liver.
  306.37 + *
  306.38 + *  He was a dear friend, and I miss him terribly.
  306.39 + *
  306.40 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  306.41 + */
  306.42 +
  306.43 +#include <stdio.h>
  306.44 +#include <ctype.h>
  306.45 +#include <errno.h>
  306.46 +extern int errno;		/* just in case */
  306.47 +#include "mail.h"
  306.48 +#include "osdep.h"
  306.49 +#include <time.h>
  306.50 +#include <fcntl.h>
  306.51 +#include <sys/stat.h>
  306.52 +#include <sys/utime.h>
  306.53 +#include "unixnt.h"
  306.54 +#include "pseudo.h"
  306.55 +#include "fdstring.h"
  306.56 +#include "misc.h"
  306.57 +#include "dummy.h"
  306.58 +
  306.59 +/* UNIX I/O stream local data */
  306.60 +
  306.61 +typedef struct unix_local {
  306.62 +  unsigned int dirty : 1;	/* disk copy needs updating */
  306.63 +  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
  306.64 +  unsigned int pseudo : 1;	/* uses a pseudo message */
  306.65 +  unsigned int appending : 1;	/* don't mark new messages as old */
  306.66 +  int fd;			/* mailbox file descriptor */
  306.67 +  int ld;			/* lock file descriptor */
  306.68 +  char *lname;			/* lock file name */
  306.69 +  off_t filesize;		/* file size parsed */
  306.70 +  time_t filetime;		/* last file time */
  306.71 +  unsigned char *buf;		/* temporary buffer */
  306.72 +  unsigned long buflen;		/* current size of temporary buffer */
  306.73 +  unsigned long uid;		/* current text uid */
  306.74 +  SIZEDTEXT text;		/* current text */
  306.75 +  unsigned long textlen;	/* current text length */
  306.76 +  char *line;			/* returned line */
  306.77 +  char *linebuf;		/* line readin buffer */
  306.78 +  unsigned long linebuflen;	/* current line readin buffer length */
  306.79 +} UNIXLOCAL;
  306.80 +
  306.81 +
  306.82 +/* Convenient access to local data */
  306.83 +
  306.84 +#define LOCAL ((UNIXLOCAL *) stream->local)
  306.85 +
  306.86 +
  306.87 +/* UNIX protected file structure */
  306.88 +
  306.89 +typedef struct unix_file {
  306.90 +  MAILSTREAM *stream;		/* current stream */
  306.91 +  off_t curpos;			/* current file position */
  306.92 +  off_t protect;		/* protected position */
  306.93 +  off_t filepos;		/* current last written file position */
  306.94 +  char *buf;			/* overflow buffer */
  306.95 +  size_t buflen;		/* current overflow buffer length */
  306.96 +  char *bufpos;			/* current buffer position */
  306.97 +} UNIXFILE;
  306.98 +
  306.99 +/* Function prototypes */
 306.100 +
 306.101 +DRIVER *unix_valid (char *name);
 306.102 +void *unix_parameters (long function,void *value);
 306.103 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 306.104 +void unix_list (MAILSTREAM *stream,char *ref,char *pat);
 306.105 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
 306.106 +long unix_create (MAILSTREAM *stream,char *mailbox);
 306.107 +long unix_delete (MAILSTREAM *stream,char *mailbox);
 306.108 +long unix_rename (MAILSTREAM *stream,char *old,char *newname);
 306.109 +MAILSTREAM *unix_open (MAILSTREAM *stream);
 306.110 +void unix_close (MAILSTREAM *stream,long options);
 306.111 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 306.112 +		   unsigned long *length,long flags);
 306.113 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 306.114 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 306.115 +		      unsigned long *length,long flags);
 306.116 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 306.117 +long unix_ping (MAILSTREAM *stream);
 306.118 +void unix_check (MAILSTREAM *stream);
 306.119 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
 306.120 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 306.121 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 306.122 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 306.123 +		     STRING *msg);
 306.124 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
 306.125 +
 306.126 +void unix_abort (MAILSTREAM *stream);
 306.127 +char *unix_file (char *dst,char *name);
 306.128 +int unix_lock (char *file,int flags,int mode,char *lock,int op);
 306.129 +void unix_unlock (int fd,MAILSTREAM *stream,char *lock);
 306.130 +int unix_parse (MAILSTREAM *stream,char *lock,int op);
 306.131 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
 306.132 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
 306.133 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
 306.134 +			    unsigned long uid,long flag);
 306.135 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
 306.136 +		   long flags);
 306.137 +long unix_extend (MAILSTREAM *stream,unsigned long size);
 306.138 +void unix_write (UNIXFILE *f,char *s,unsigned long i);
 306.139 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
 306.140 +
 306.141 +/* UNIX mail routines */
 306.142 +
 306.143 +
 306.144 +/* Driver dispatch used by MAIL */
 306.145 +
 306.146 +DRIVER unixdriver = {
 306.147 +  "unix",			/* driver name */
 306.148 +				/* driver flags */
 306.149 +  DR_LOCAL|DR_MAIL|DR_NONEWMAILRONLY|DR_XPOINT,
 306.150 +  (DRIVER *) NIL,		/* next driver */
 306.151 +  unix_valid,			/* mailbox is valid for us */
 306.152 +  unix_parameters,		/* manipulate parameters */
 306.153 +  unix_scan,			/* scan mailboxes */
 306.154 +  unix_list,			/* list mailboxes */
 306.155 +  unix_lsub,			/* list subscribed mailboxes */
 306.156 +  NIL,				/* subscribe to mailbox */
 306.157 +  NIL,				/* unsubscribe from mailbox */
 306.158 +  unix_create,			/* create mailbox */
 306.159 +  unix_delete,			/* delete mailbox */
 306.160 +  unix_rename,			/* rename mailbox */
 306.161 +  mail_status_default,		/* status of mailbox */
 306.162 +  unix_open,			/* open mailbox */
 306.163 +  unix_close,			/* close mailbox */
 306.164 +  NIL,				/* fetch message "fast" attributes */
 306.165 +  NIL,				/* fetch message flags */
 306.166 +  NIL,				/* fetch overview */
 306.167 +  NIL,				/* fetch message envelopes */
 306.168 +  unix_header,			/* fetch message header */
 306.169 +  unix_text,			/* fetch message text */
 306.170 +  NIL,				/* fetch partial message text */
 306.171 +  NIL,				/* unique identifier */
 306.172 +  NIL,				/* message number */
 306.173 +  NIL,				/* modify flags */
 306.174 +  unix_flagmsg,			/* per-message modify flags */
 306.175 +  NIL,				/* search for message based on criteria */
 306.176 +  NIL,				/* sort messages */
 306.177 +  NIL,				/* thread messages */
 306.178 +  unix_ping,			/* ping mailbox to see if still alive */
 306.179 +  unix_check,			/* check for new messages */
 306.180 +  unix_expunge,			/* expunge deleted messages */
 306.181 +  unix_copy,			/* copy messages to another mailbox */
 306.182 +  unix_append,			/* append string message to mailbox */
 306.183 +  NIL				/* garbage collect stream */
 306.184 +};
 306.185 +
 306.186 +				/* prototype stream */
 306.187 +MAILSTREAM unixproto = {&unixdriver};
 306.188 +
 306.189 +				/* driver parameters */
 306.190 +static long unix_fromwidget = T;
 306.191 +
 306.192 +/* UNIX mail validate mailbox
 306.193 + * Accepts: mailbox name
 306.194 + * Returns: our driver if name is valid, NIL otherwise
 306.195 + */
 306.196 +
 306.197 +DRIVER *unix_valid (char *name)
 306.198 +{
 306.199 +  int fd;
 306.200 +  DRIVER *ret = NIL;
 306.201 +  int c,r;
 306.202 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],*s,*t;
 306.203 +  struct stat sbuf;
 306.204 +  struct utimbuf times;
 306.205 +  errno = EINVAL;		/* assume invalid argument */
 306.206 +				/* must be non-empty file */
 306.207 +  if ((t = dummy_file (file,name)) && !stat (t,&sbuf) &&
 306.208 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
 306.209 +    if (!sbuf.st_size)errno = 0;/* empty file */
 306.210 +    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
 306.211 +      memset (tmp,'\0',MAILTMPLEN);
 306.212 +      if (read (fd,tmp,MAILTMPLEN-1) <= 0) errno = -1;
 306.213 +      else {			/* ignore leading whitespace */
 306.214 +	for (s = tmp,c = '\n';
 306.215 +	     (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');
 306.216 +	     c = *s++);
 306.217 +	if (c == '\n') {	/* at start of a line? */
 306.218 +	  VALID (s,t,r,c);	/* yes, validate format */
 306.219 +	  if (r) ret = &unixdriver;
 306.220 +	  else errno = -1;	/* invalid format */
 306.221 +	}
 306.222 +      }
 306.223 +      close (fd);		/* close the file */
 306.224 +				/* \Marked status? */
 306.225 +      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
 306.226 +				/* yes, preserve atime and mtime */
 306.227 +	times.actime = sbuf.st_atime;
 306.228 +	times.modtime = sbuf.st_mtime;
 306.229 +	utime (file,&times);	/* set the times */
 306.230 +      }
 306.231 +    }
 306.232 +  }
 306.233 +  return ret;			/* return what we should */
 306.234 +}
 306.235 +/* UNIX manipulate driver parameters
 306.236 + * Accepts: function code
 306.237 + *	    function-dependent value
 306.238 + * Returns: function-dependent return value
 306.239 + */
 306.240 +
 306.241 +void *unix_parameters (long function,void *value)
 306.242 +{
 306.243 +  void *ret = NIL;
 306.244 +  switch ((int) function) {
 306.245 +  case SET_FROMWIDGET:
 306.246 +    unix_fromwidget = (long) value;
 306.247 +  case GET_FROMWIDGET:
 306.248 +    ret = (void *) unix_fromwidget;
 306.249 +    break;
 306.250 +  }
 306.251 +  return ret;
 306.252 +}
 306.253 +
 306.254 +/* UNIX mail scan mailboxes
 306.255 + * Accepts: mail stream
 306.256 + *	    reference
 306.257 + *	    pattern to search
 306.258 + *	    string to scan
 306.259 + */
 306.260 +
 306.261 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 306.262 +{
 306.263 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 306.264 +}
 306.265 +
 306.266 +
 306.267 +/* UNIX mail list mailboxes
 306.268 + * Accepts: mail stream
 306.269 + *	    reference
 306.270 + *	    pattern to search
 306.271 + */
 306.272 +
 306.273 +void unix_list (MAILSTREAM *stream,char *ref,char *pat)
 306.274 +{
 306.275 +  if (stream) dummy_list (NIL,ref,pat);
 306.276 +}
 306.277 +
 306.278 +
 306.279 +/* UNIX mail list subscribed mailboxes
 306.280 + * Accepts: mail stream
 306.281 + *	    reference
 306.282 + *	    pattern to search
 306.283 + */
 306.284 +
 306.285 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
 306.286 +{
 306.287 +  if (stream) dummy_lsub (NIL,ref,pat);
 306.288 +}
 306.289 +
 306.290 +/* UNIX mail create mailbox
 306.291 + * Accepts: MAIL stream
 306.292 + *	    mailbox name to create
 306.293 + * Returns: T on success, NIL on failure
 306.294 + */
 306.295 +
 306.296 +long unix_create (MAILSTREAM *stream,char *mailbox)
 306.297 +{
 306.298 +  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
 306.299 +  long ret = NIL;
 306.300 +  int fd;
 306.301 +  time_t ti = time (0);
 306.302 +  if (!(s = dummy_file (mbx,mailbox))) {
 306.303 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 306.304 +    mm_log (tmp,ERROR);
 306.305 +  }
 306.306 +				/* create underlying file */
 306.307 +  else if (dummy_create_path (stream,s,NIL)) {
 306.308 +    if ((s = strrchr (s,'\\')) && !s[1]) ret = T;
 306.309 +    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
 306.310 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 306.311 +      mm_log (tmp,ERROR);
 306.312 +      unlink (mbx);		/* delete the file */
 306.313 +    }
 306.314 +    else {			/* initialize header */
 306.315 +      memset (tmp,'\0',MAILTMPLEN);
 306.316 +      sprintf (tmp,"From %s %s",pseudo_from,ctime (&ti));
 306.317 +      if (s = strpbrk (tmp,"\r\n")) *s = '\0';
 306.318 +      strcat (tmp,"\r\nDate: ");
 306.319 +      rfc822_fixed_date (s = tmp + strlen (tmp));
 306.320 +      sprintf (s += strlen (s),	/* write the pseudo-header */
 306.321 +	       "\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",
 306.322 +	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
 306.323 +	       (unsigned long) ti,pseudo_msg);
 306.324 +      if (write (fd,tmp,strlen (tmp)) > 0) {
 306.325 +	close (fd);		/* close file */
 306.326 +	ret = T;
 306.327 +      }
 306.328 +      else {
 306.329 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
 306.330 +		 strerror (errno));
 306.331 +	mm_log (tmp,ERROR);
 306.332 +	close (fd);		/* close file before unlinking */
 306.333 +	unlink (mbx);		/* delete the file */
 306.334 +      }
 306.335 +    }
 306.336 +  }
 306.337 +  return ret;
 306.338 +}
 306.339 +
 306.340 +/* UNIX mail delete mailbox
 306.341 + * Accepts: MAIL stream
 306.342 + *	    mailbox name to delete
 306.343 + * Returns: T on success, NIL on failure
 306.344 + */
 306.345 +
 306.346 +long unix_delete (MAILSTREAM *stream,char *mailbox)
 306.347 +{
 306.348 +  return unix_rename (stream,mailbox,NIL);
 306.349 +}
 306.350 +
 306.351 +
 306.352 +/* UNIX mail rename mailbox
 306.353 + * Accepts: MAIL stream
 306.354 + *	    old mailbox name
 306.355 + *	    new mailbox name (or NIL for delete)
 306.356 + * Returns: T on success, NIL on failure
 306.357 + */
 306.358 +
 306.359 +long unix_rename (MAILSTREAM *stream,char *old,char *newname)
 306.360 +{
 306.361 +  long ret = NIL;
 306.362 +  char c,*s = NIL;
 306.363 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN];
 306.364 +  int fd,ld;
 306.365 +  struct stat sbuf;
 306.366 +  mm_critical (stream);		/* get the c-client lock */
 306.367 +  if (!dummy_file (file,old) ||
 306.368 +      (newname && (!(s = dummy_file (tmp,newname)) ||
 306.369 +		   ((s = strrchr (s,'\\')) && !s[1]))))
 306.370 +    sprintf (tmp,newname ?
 306.371 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 306.372 +	     "Can't delete mailbox %.80s: invalid name",
 306.373 +	     old,newname);
 306.374 +  else if ((ld = lockname (lock,file,NIL)) < 0)
 306.375 +    sprintf (tmp,"Can't get lock for mailbox %.80s",old);
 306.376 +
 306.377 +  else {			/* lock out other c-clients */
 306.378 +    if (flock (ld,LOCK_EX|LOCK_NB)) {
 306.379 +      close (ld);		/* couldn't lock, give up on it then */
 306.380 +      sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 306.381 +    }
 306.382 +				/* lock out non c-client applications */
 306.383 +    else if ((fd = unix_lock (file,O_BINARY|O_RDWR,S_IREAD|S_IWRITE,lockx,
 306.384 +			      LOCK_EX)) < 0)
 306.385 +      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
 306.386 +    else {
 306.387 +      unix_unlock(fd,NIL,lockx);/* pacify evil NTFS */
 306.388 +      if (newname) {		/* want rename? */
 306.389 +				/* found superior to destination name? */
 306.390 +	if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 306.391 +	    ((tmp[1] != ':') || (s != tmp + 2))) {
 306.392 +	  c = s[1];		/* remember character after delimiter */
 306.393 +	  *s = s[1] = '\0';	/* tie off name at delimiter */
 306.394 +				/* name doesn't exist, create it */
 306.395 +	  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 306.396 +	    *s = '\\';		/* restore delimiter */
 306.397 +	    if (!dummy_create (stream,newname)) {
 306.398 +	      flock (ld,LOCK_UN);
 306.399 +	      close (ld);	/* close c-client lock */
 306.400 +	      unlink (lock);	/* and delete it */
 306.401 +	      mm_nocritical (stream);
 306.402 +	      return NIL;	/* couldn't create superior */
 306.403 +	    }
 306.404 +	  }
 306.405 +	  else *s = '\\';	/* restore delimiter */
 306.406 +	  s[1] = c;		/* restore character after delimiter */
 306.407 +	}
 306.408 +	if (rename (file,tmp))
 306.409 +	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 306.410 +		   strerror (errno));
 306.411 +	else ret = T;		/* set success */
 306.412 +      }
 306.413 +      else if (unlink (file))	/* want delete */
 306.414 +	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 306.415 +      else ret = T;		/* set success */
 306.416 +      flock (ld,LOCK_UN);	/* release c-client lock */
 306.417 +      close (ld);		/* close c-client lock */
 306.418 +      unlink (lock);		/* and delete it */
 306.419 +    }
 306.420 +  }
 306.421 +  mm_nocritical (stream);	/* no longer critical */
 306.422 +  if (!ret) mm_log (tmp,ERROR);	/* log error */
 306.423 +  return ret;			/* return success or failure */
 306.424 +}
 306.425 +
 306.426 +/* UNIX mail open
 306.427 + * Accepts: Stream to open
 306.428 + * Returns: Stream on success, NIL on failure
 306.429 + */
 306.430 +
 306.431 +MAILSTREAM *unix_open (MAILSTREAM *stream)
 306.432 +{
 306.433 +  int fd;
 306.434 +  char tmp[MAILTMPLEN];
 306.435 +				/* return prototype for OP_PROTOTYPE call */
 306.436 +  if (!stream) return &unixproto;
 306.437 +  if (stream->local) fatal ("unix recycle stream");
 306.438 +  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
 306.439 +				/* note if an INBOX or not */
 306.440 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 306.441 +				/* canonicalize the stream mailbox name */
 306.442 +  if (!dummy_file (tmp,stream->mailbox)) {
 306.443 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 306.444 +    mm_log (tmp,ERROR);
 306.445 +    return NIL;
 306.446 +  }
 306.447 +				/* flush old name */
 306.448 +  fs_give ((void **) &stream->mailbox);
 306.449 +				/* save canonical name */
 306.450 +  stream->mailbox = cpystr (tmp);
 306.451 +  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
 306.452 +  LOCAL->buf = (char *) fs_get ((LOCAL->buflen = CHUNKSIZE) + 1);
 306.453 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 306.454 +  LOCAL->text.size = CHUNKSIZE - 1;
 306.455 +  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
 306.456 +  LOCAL->linebuflen = CHUNKSIZE - 1;
 306.457 +  stream->sequence++;		/* bump sequence number */
 306.458 +  if (!stream->rdonly) {	/* make lock for read/write access */
 306.459 +    if ((fd = lockname (tmp,stream->mailbox,NIL)) < 0)
 306.460 +      mm_log ("Can't open mailbox lock, access is readonly",WARN);
 306.461 +				/* can get the lock? */
 306.462 +    else if (flock (fd,LOCK_EX|LOCK_NB)) {
 306.463 +      if (!stream->silent)
 306.464 +	mm_log ("Mailbox is open by another process, access is readonly",WARN);
 306.465 +      close (fd);
 306.466 +    }
 306.467 +    else {			/* got the lock, nobody else can alter state */
 306.468 +      LOCAL->ld = fd;		/* note lock's fd and name */
 306.469 +      LOCAL->lname = cpystr (tmp);
 306.470 +    }
 306.471 +  }
 306.472 +
 306.473 +				/* parse mailbox */
 306.474 +  stream->nmsgs = stream->recent = 0;
 306.475 +				/* will we be able to get write access? */
 306.476 +  if ((LOCAL->ld >= 0) && access (stream->mailbox,02) && (errno == EACCES)) {
 306.477 +    mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 306.478 +    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
 306.479 +    close (LOCAL->ld);		/* close the lock file */
 306.480 +    LOCAL->ld = -1;		/* no more lock fd */
 306.481 +    unlink (LOCAL->lname);	/* delete it */
 306.482 +  }
 306.483 +				/* reset UID validity */
 306.484 +  stream->uid_validity = stream->uid_last = 0;
 306.485 +  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
 306.486 +    unix_abort (stream);	/* abort if can't get RW silent stream */
 306.487 +				/* parse mailbox */
 306.488 +  else if (unix_parse (stream,tmp,LOCK_SH)) {
 306.489 +    unix_unlock (LOCAL->fd,stream,tmp);
 306.490 +    mail_unlock (stream);
 306.491 +    mm_nocritical (stream);	/* done with critical */
 306.492 +  }
 306.493 +  if (!LOCAL) return NIL;	/* failure if stream died */
 306.494 +				/* make sure upper level knows readonly */
 306.495 +  stream->rdonly = (LOCAL->ld < 0);
 306.496 +				/* notify about empty mailbox */
 306.497 +  if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",NIL);
 306.498 +  if (!stream->rdonly) {	/* flags stick if readwrite */
 306.499 +    stream->perm_seen = stream->perm_deleted =
 306.500 +      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
 306.501 +				/* have permanent keywords */
 306.502 +    stream->perm_user_flags = 0xffffffff;
 306.503 +				/* and maybe can create them too */
 306.504 +    stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
 306.505 +  }
 306.506 +  return stream;		/* return stream alive to caller */
 306.507 +}
 306.508 +
 306.509 +
 306.510 +/* UNIX mail close
 306.511 + * Accepts: MAIL stream
 306.512 + *	    close options
 306.513 + */
 306.514 +
 306.515 +void unix_close (MAILSTREAM *stream,long options)
 306.516 +{
 306.517 +  int silent = stream->silent;
 306.518 +  stream->silent = T;		/* go silent */
 306.519 +				/* expunge if requested */
 306.520 +  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
 306.521 +				/* else dump final checkpoint */
 306.522 +  else if (LOCAL->dirty) unix_check (stream);
 306.523 +  stream->silent = silent;	/* restore old silence state */
 306.524 +  unix_abort (stream);		/* now punt the file and local data */
 306.525 +}
 306.526 +
 306.527 +/* UNIX mail fetch message header
 306.528 + * Accepts: MAIL stream
 306.529 + *	    message # to fetch
 306.530 + *	    pointer to returned header text length
 306.531 + *	    option flags
 306.532 + * Returns: message header in RFC822 format
 306.533 + */
 306.534 +
 306.535 +				/* lines to filter from header */
 306.536 +static STRINGLIST *unix_hlines = NIL;
 306.537 +
 306.538 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 306.539 +		   unsigned long *length,long flags)
 306.540 +{
 306.541 +  MESSAGECACHE *elt;
 306.542 +  unsigned char *s;
 306.543 +  *length = 0;			/* default to empty */
 306.544 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 306.545 +  elt = mail_elt (stream,msgno);/* get cache */
 306.546 +  if (!unix_hlines) {		/* once only code */
 306.547 +    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
 306.548 +    lines->text.size = strlen ((char *) (lines->text.data =
 306.549 +					 (unsigned char *) "Status"));
 306.550 +    lines = lines->next = mail_newstringlist ();
 306.551 +    lines->text.size = strlen ((char *) (lines->text.data =
 306.552 +					 (unsigned char *) "X-Status"));
 306.553 +    lines = lines->next = mail_newstringlist ();
 306.554 +    lines->text.size = strlen ((char *) (lines->text.data =
 306.555 +					 (unsigned char *) "X-Keywords"));
 306.556 +    lines = lines->next = mail_newstringlist ();
 306.557 +    lines->text.size = strlen ((char *) (lines->text.data =
 306.558 +					 (unsigned char *) "X-UID"));
 306.559 +    lines = lines->next = mail_newstringlist ();
 306.560 +    lines->text.size = strlen ((char *) (lines->text.data =
 306.561 +					 (unsigned char *) "X-IMAP"));
 306.562 +    lines = lines->next = mail_newstringlist ();
 306.563 +    lines->text.size = strlen ((char *) (lines->text.data =
 306.564 +					 (unsigned char *) "X-IMAPbase"));
 306.565 +  }
 306.566 +				/* go to header position */
 306.567 +  lseek (LOCAL->fd,elt->private.special.offset +
 306.568 +	 elt->private.msg.header.offset,L_SET);
 306.569 +
 306.570 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 306.571 +    if (elt->private.msg.header.text.size > LOCAL->buflen) {
 306.572 +      fs_give ((void **) &LOCAL->buf);
 306.573 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 306.574 +				     elt->private.msg.header.text.size) + 1);
 306.575 +    }
 306.576 +				/* read message */
 306.577 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
 306.578 +				/* got text, tie off string */
 306.579 +    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
 306.580 +  }
 306.581 +  else {			/* need to make a CRLF version */
 306.582 +    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
 306.583 +	  elt->private.msg.header.text.size);
 306.584 +				/* tie off string, and convert to CRLF */
 306.585 +    s[elt->private.msg.header.text.size] = '\0';
 306.586 +    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
 306.587 +			    elt->private.msg.header.text.size);
 306.588 +    fs_give ((void **) &s);	/* free readin buffer */
 306.589 +  }
 306.590 +  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
 306.591 +  return LOCAL->buf;		/* return processed copy */
 306.592 +}
 306.593 +
 306.594 +/* UNIX mail fetch message text
 306.595 + * Accepts: MAIL stream
 306.596 + *	    message # to fetch
 306.597 + *	    pointer to returned stringstruct
 306.598 + *	    option flags
 306.599 + * Returns: T on success, NIL if failure
 306.600 + */
 306.601 +
 306.602 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 306.603 +{
 306.604 +  char *s;
 306.605 +  unsigned long i;
 306.606 +  MESSAGECACHE *elt;
 306.607 +				/* UID call "impossible" */
 306.608 +  if (flags & FT_UID) return NIL;
 306.609 +  elt = mail_elt (stream,msgno);/* get cache element */
 306.610 +				/* if message not seen */
 306.611 +  if (!(flags & FT_PEEK) && !elt->seen) {
 306.612 +				/* mark message seen and dirty */
 306.613 +    elt->seen = elt->private.dirty = LOCAL->dirty = T;
 306.614 +    mm_flags (stream,msgno);
 306.615 +  }
 306.616 +  s = unix_text_work (stream,elt,&i,flags);
 306.617 +  INIT (bs,mail_string,s,i);	/* set up stringstruct */
 306.618 +  return T;			/* success */
 306.619 +}
 306.620 +
 306.621 +/* UNIX mail fetch message text worker routine
 306.622 + * Accepts: MAIL stream
 306.623 + *	    message cache element
 306.624 + *	    pointer to returned header text length
 306.625 + *	    option flags
 306.626 + */
 306.627 +
 306.628 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 306.629 +		      unsigned long *length,long flags)
 306.630 +{
 306.631 +  FDDATA d;
 306.632 +  STRING bs;
 306.633 +  unsigned char c,*s,tmp[CHUNKSIZE];
 306.634 +				/* go to text position */
 306.635 +  lseek (LOCAL->fd,elt->private.special.offset +
 306.636 +	 elt->private.msg.text.offset,L_SET);
 306.637 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 306.638 +    if (elt->private.msg.text.text.size > LOCAL->buflen) {
 306.639 +      fs_give ((void **) &LOCAL->buf);
 306.640 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 306.641 +				     elt->private.msg.text.text.size) + 1);
 306.642 +    }
 306.643 +				/* read message */
 306.644 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
 306.645 +				/* got text, tie off string */
 306.646 +    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
 306.647 +    return LOCAL->buf;
 306.648 +  }
 306.649 +				/* have it cached already? */
 306.650 +  if (elt->private.uid != LOCAL->uid) {
 306.651 +				/* not cached, cache it now */
 306.652 +    LOCAL->uid = elt->private.uid;
 306.653 +				/* is buffer big enough? */
 306.654 +    if (elt->rfc822_size > LOCAL->text.size) {
 306.655 +      /* excessively conservative, but the right thing is too hard to do */
 306.656 +      fs_give ((void **) &LOCAL->text.data);
 306.657 +      LOCAL->text.data = (unsigned char *)
 306.658 +	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
 306.659 +    }
 306.660 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
 306.661 +    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
 306.662 +    d.chunk = tmp;		/* initial buffer chunk */
 306.663 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
 306.664 +    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
 306.665 +    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
 306.666 +    case '\r':			/* carriage return seen */
 306.667 +      *s++ = c;			/* copy it and any succeeding LF */
 306.668 +      if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
 306.669 +      break;
 306.670 +    case '\n':
 306.671 +      *s++ = '\r';		/* insert a CR */
 306.672 +    default:
 306.673 +      *s++ = c;			/* copy characters */
 306.674 +    }
 306.675 +    *s = '\0';			/* tie off buffer */
 306.676 +				/* calculate length of cached data */
 306.677 +    LOCAL->textlen = s - LOCAL->text.data;
 306.678 +  }
 306.679 +  *length = LOCAL->textlen;	/* return from cache */
 306.680 +  return (char *) LOCAL->text.data;
 306.681 +}
 306.682 +
 306.683 +/* UNIX per-message modify flag
 306.684 + * Accepts: MAIL stream
 306.685 + *	    message cache element
 306.686 + */
 306.687 +
 306.688 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 306.689 +{
 306.690 +				/* only after finishing */
 306.691 +  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
 306.692 +}
 306.693 +
 306.694 +
 306.695 +/* UNIX mail ping mailbox
 306.696 + * Accepts: MAIL stream
 306.697 + * Returns: T if stream alive, else NIL
 306.698 + */
 306.699 +
 306.700 +long unix_ping (MAILSTREAM *stream)
 306.701 +{
 306.702 +  char lock[MAILTMPLEN];
 306.703 +  struct stat sbuf;
 306.704 +				/* big no-op if not readwrite */
 306.705 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
 306.706 +    if (stream->rdonly) {	/* does he want to give up readwrite? */
 306.707 +				/* checkpoint if we changed something */
 306.708 +      if (LOCAL->dirty) unix_check (stream);
 306.709 +      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
 306.710 +      close (LOCAL->ld);	/* close the readwrite lock file */
 306.711 +      LOCAL->ld = -1;		/* no more readwrite lock fd */
 306.712 +      unlink (LOCAL->lname);	/* delete the readwrite lock file */
 306.713 +    }
 306.714 +    else {			/* get current mailbox size */
 306.715 +      if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
 306.716 +      else if (stat (stream->mailbox,&sbuf)) {
 306.717 +	sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
 306.718 +		 strerror (errno));
 306.719 +	MM_LOG (LOCAL->buf,ERROR);
 306.720 +	unix_abort (stream);
 306.721 +	return NIL;
 306.722 +      }
 306.723 +				/* parse if mailbox changed */
 306.724 +      if ((LOCAL->ddirty || (sbuf.st_size != LOCAL->filesize)) &&
 306.725 +	  unix_parse (stream,lock,LOCK_EX)) {
 306.726 +				/* force checkpoint if double-dirty */
 306.727 +	if (LOCAL->ddirty) unix_rewrite (stream,NIL,lock,NIL);
 306.728 +				/* unlock mailbox */
 306.729 +	else unix_unlock (LOCAL->fd,stream,lock);
 306.730 +	mail_unlock (stream);	/* and stream */
 306.731 +	mm_nocritical (stream);	/* done with critical */
 306.732 +      }
 306.733 +    }
 306.734 +  }
 306.735 +  return LOCAL ? LONGT : NIL;	/* return if still alive */
 306.736 +}
 306.737 +
 306.738 +/* UNIX mail check mailbox
 306.739 + * Accepts: MAIL stream
 306.740 + */
 306.741 +
 306.742 +void unix_check (MAILSTREAM *stream)
 306.743 +{
 306.744 +  char lock[MAILTMPLEN];
 306.745 +				/* parse and lock mailbox */
 306.746 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 306.747 +      unix_parse (stream,lock,LOCK_EX)) {
 306.748 +				/* any unsaved changes? */
 306.749 +    if (LOCAL->dirty && unix_rewrite (stream,NIL,lock,NIL)) {
 306.750 +      if (!stream->silent) mm_log ("Checkpoint completed",NIL);
 306.751 +    }
 306.752 +				/* no checkpoint needed, just unlock */
 306.753 +    else unix_unlock (LOCAL->fd,stream,lock);
 306.754 +    mail_unlock (stream);	/* unlock the stream */
 306.755 +    mm_nocritical (stream);	/* done with critical */
 306.756 +  }
 306.757 +}
 306.758 +
 306.759 +
 306.760 +/* UNIX mail expunge mailbox
 306.761 + * Accepts: MAIL stream
 306.762 + *	    sequence to expunge if non-NIL
 306.763 + *	    expunge options
 306.764 + * Returns: T, always
 306.765 + */
 306.766 +
 306.767 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
 306.768 +{
 306.769 +  long ret;
 306.770 +  unsigned long i;
 306.771 +  char lock[MAILTMPLEN];
 306.772 +  char *msg = NIL;
 306.773 +				/* parse and lock mailbox */
 306.774 +  if (ret = (sequence ? ((options & EX_UID) ?
 306.775 +			 mail_uid_sequence (stream,sequence) :
 306.776 +			 mail_sequence (stream,sequence)) : LONGT) &&
 306.777 +      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 306.778 +      unix_parse (stream,lock,LOCK_EX)) {
 306.779 +				/* check expunged messages if not dirty */
 306.780 +    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
 306.781 +      MESSAGECACHE *elt = mail_elt (stream,i);
 306.782 +      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
 306.783 +    }
 306.784 +    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
 306.785 +      unix_unlock (LOCAL->fd,stream,lock);
 306.786 +      msg = "No messages deleted, so no update needed";
 306.787 +    }
 306.788 +    else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) {
 306.789 +      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
 306.790 +      else msg = "Mailbox checkpointed, but no messages expunged";
 306.791 +    }
 306.792 +				/* rewrite failed */
 306.793 +    else unix_unlock (LOCAL->fd,stream,lock);
 306.794 +    mail_unlock (stream);	/* unlock the stream */
 306.795 +    mm_nocritical (stream);	/* done with critical */
 306.796 +    if (msg && !stream->silent) mm_log (msg,NIL);
 306.797 +  }
 306.798 +  else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN);
 306.799 +  return ret;
 306.800 +}
 306.801 +
 306.802 +/* UNIX mail copy message(s)
 306.803 + * Accepts: MAIL stream
 306.804 + *	    sequence
 306.805 + *	    destination mailbox
 306.806 + *	    copy options
 306.807 + * Returns: T if copy successful, else NIL
 306.808 + */
 306.809 +
 306.810 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 306.811 +{
 306.812 +  struct stat sbuf;
 306.813 +  int fd;
 306.814 +  char *s,file[MAILTMPLEN],lock[MAILTMPLEN];
 306.815 +  struct utimbuf times;
 306.816 +  unsigned long i,j;
 306.817 +  MESSAGECACHE *elt;
 306.818 +  long ret = T;
 306.819 +  mailproxycopy_t pc =
 306.820 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 306.821 +  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
 306.822 +			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
 306.823 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 306.824 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 306.825 +  MAILSTREAM *tstream = NIL;
 306.826 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 306.827 +	mail_sequence (stream,sequence))) return NIL;
 306.828 +				/* make sure destination is valid */
 306.829 +  if (!(unix_valid (mailbox) || !errno))
 306.830 +    switch (errno) {
 306.831 +    case ENOENT:			/* no such file? */
 306.832 +      if (compare_cstring (mailbox,"INBOX")) {
 306.833 +	mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 306.834 +	return NIL;
 306.835 +      }
 306.836 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 306.837 +      unix_create (NIL,"INBOX");/* create empty INBOX */
 306.838 +    case EACCES:		/* file protected */
 306.839 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 306.840 +      MM_LOG (LOCAL->buf,ERROR);
 306.841 +      return NIL;
 306.842 +    case EINVAL:
 306.843 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 306.844 +      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
 306.845 +      mm_log (LOCAL->buf,ERROR);
 306.846 +      return NIL;
 306.847 +    default:
 306.848 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 306.849 +      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
 306.850 +      mm_log (LOCAL->buf,ERROR);
 306.851 +      return NIL;
 306.852 +    }
 306.853 +
 306.854 +				/* try to open rewrite for UIDPLUS */
 306.855 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
 306.856 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
 306.857 +    tstream = mail_close (tstream);
 306.858 +  if (cu && !tstream) {		/* wanted a COPYUID? */
 306.859 +    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
 306.860 +	     mailbox);
 306.861 +    MM_LOG (LOCAL->buf,WARN);
 306.862 +    cu = NIL;			/* don't try to do COPYUID */
 306.863 +  }
 306.864 +  LOCAL->buf[0] = '\0';
 306.865 +  mm_critical (stream);		/* go critical */
 306.866 +  if ((fd = unix_lock (dummy_file (file,mailbox),
 306.867 +		       O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
 306.868 +		       lock,LOCK_EX)) < 0) {
 306.869 +    mm_nocritical (stream);	/* done with critical */
 306.870 +    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
 306.871 +    mm_log (LOCAL->buf,ERROR);	/* log the error */
 306.872 +    return NIL;			/* failed */
 306.873 +  }
 306.874 +  fstat (fd,&sbuf);		/* get current file size */
 306.875 +				/* write all requested messages to mailbox */
 306.876 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
 306.877 +    if ((elt = mail_elt (stream,i))->sequence) {
 306.878 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 306.879 +      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
 306.880 +      if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') {
 306.881 +	LOCAL->buf[j - 1] = '\r';
 306.882 +	LOCAL->buf[j++] = '\n';
 306.883 +      }
 306.884 +      if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 306.885 +      else {			/* internal header succeeded */
 306.886 +	s = unix_header (stream,i,&j,NIL);
 306.887 +				/* header size, sans trailing newline */
 306.888 +	if (j && (s[j - 4] == '\r')) j -= 2;
 306.889 +	if (write (fd,s,j) < 0) ret = NIL;
 306.890 +	else {			/* message header succeeded */
 306.891 +	  j = tstream ?		/* write UIDPLUS data if have readwrite */
 306.892 +	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
 306.893 +	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
 306.894 +	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 306.895 +	  else {		/* message status succeeded */
 306.896 +	    s = unix_text_work (stream,elt,&j,NIL);
 306.897 +	    if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0))
 306.898 +	      ret = NIL;
 306.899 +	    else if (cu) {	/* need to pass back new UID? */
 306.900 +	      mail_append_set (source,mail_uid (stream,i));
 306.901 +	      mail_append_set (dest,tstream->uid_last);
 306.902 +	    }
 306.903 +	  }
 306.904 +	}
 306.905 +      }
 306.906 +    }
 306.907 +
 306.908 +  if (!ret || fsync (fd)) {	/* force out the update */
 306.909 +    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
 306.910 +    ftruncate (fd,sbuf.st_size);
 306.911 +    ret = NIL;
 306.912 +  }
 306.913 +				/* force UIDVALIDITY assignment now */
 306.914 +  if (tstream && !tstream->uid_validity)
 306.915 +    tstream->uid_validity = (unsigned long) time (0);
 306.916 +				/* return sets if doing COPYUID */
 306.917 +  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
 306.918 +  else {			/* flush any sets we may have built */
 306.919 +    mail_free_searchset (&source);
 306.920 +    mail_free_searchset (&dest);
 306.921 +  }
 306.922 +  times.modtime = time (0);	/* set mtime to now */
 306.923 +				/* set atime to now-1 if successful copy */
 306.924 +  if (ret) times.actime = times.modtime - 1;
 306.925 +		
 306.926 +  else times.actime =		/* else preserve \Marked status */
 306.927 +	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
 306.928 +	 sbuf.st_atime : times.modtime;
 306.929 +  utime (file,&times);		/* set the times */
 306.930 +  unix_unlock (fd,NIL,lock);	/* unlock and close mailbox */
 306.931 +  if (tstream) {		/* update last UID if we can */
 306.932 +    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
 306.933 +    local->dirty = T;		/* do a rewrite */
 306.934 +    local->appending = T;	/* but not at the cost of marking as old */
 306.935 +    tstream = mail_close (tstream);
 306.936 +  }
 306.937 +				/* log the error */
 306.938 +  if (!ret) mm_log (LOCAL->buf,ERROR);
 306.939 +				/* delete if requested message */
 306.940 +  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
 306.941 +    if ((elt = mail_elt (stream,i))->sequence)
 306.942 +      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
 306.943 +  mm_nocritical (stream);	/* release critical */
 306.944 +  return ret;
 306.945 +}
 306.946 +
 306.947 +/* UNIX mail append message from stringstruct
 306.948 + * Accepts: MAIL stream
 306.949 + *	    destination mailbox
 306.950 + *	    append callback
 306.951 + *	    data for callback
 306.952 + * Returns: T if append successful, else NIL
 306.953 + */
 306.954 +
 306.955 +#define BUFLEN 8*MAILTMPLEN
 306.956 +
 306.957 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 306.958 +{
 306.959 +  struct stat sbuf;
 306.960 +  int fd;
 306.961 +  unsigned long i;
 306.962 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN],
 306.963 +    lock[MAILTMPLEN];
 306.964 +  struct utimbuf times;
 306.965 +  FILE *sf,*df;
 306.966 +  MESSAGECACHE elt;
 306.967 +  STRING *message;
 306.968 +  unsigned long uidlocation = 0;
 306.969 +  appenduid_t au = (appenduid_t)
 306.970 +    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
 306.971 +     mail_parameters (NIL,GET_APPENDUID,NIL));
 306.972 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
 306.973 +  long ret = LONGT;
 306.974 +  MAILSTREAM *tstream = NIL;
 306.975 +  if (!stream) {		/* stream specified? */
 306.976 +    stream = &unixproto;	/* no, default stream to prototype */
 306.977 +    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
 306.978 +      fs_give ((void **) &stream->user_flags[i]);
 306.979 +  }
 306.980 +  if (!unix_valid (mailbox)) switch (errno) {
 306.981 +  case ENOENT:			/* no such file? */
 306.982 +    if (!compare_cstring (mailbox,"INBOX")) {
 306.983 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 306.984 +      return NIL;
 306.985 +    }
 306.986 +    unix_create (NIL,"INBOX");	/* create empty INBOX */
 306.987 +  case 0:			/* merely empty file? */
 306.988 +    tstream = stream;
 306.989 +    break;
 306.990 +  case EACCES:			/* file protected */
 306.991 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 306.992 +    MM_LOG (tmp,ERROR);
 306.993 +    return NIL;
 306.994 +  case EINVAL:
 306.995 +    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
 306.996 +    mm_log (tmp,ERROR);
 306.997 +    return NIL;
 306.998 +  default:
 306.999 +    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
306.1000 +    mm_log (tmp,ERROR);
306.1001 +    return NIL;
306.1002 +  }
306.1003 +				/* get sniffing stream for keywords */
306.1004 +  else if (!(tstream = mail_open (NIL,mailbox,
306.1005 +				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
306.1006 +    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
306.1007 +    MM_LOG (tmp,ERROR);
306.1008 +    return NIL;
306.1009 +  }
306.1010 +
306.1011 +				/* get first message */
306.1012 +  if (!(*af) (tstream,data,&flags,&date,&message)) return NIL;
306.1013 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
306.1014 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
306.1015 +    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
306.1016 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
306.1017 +      mm_log (tmp,ERROR);
306.1018 +      return NIL;
306.1019 +    }
306.1020 +    unlink (tmp);
306.1021 +  }
306.1022 +  do {				/* parse date */
306.1023 +    if (!date) rfc822_date (date = tmp);
306.1024 +    if (!mail_parse_date (&elt,date)) {
306.1025 +      sprintf (tmp,"Bad date in append: %.80s",date);
306.1026 +      mm_log (tmp,ERROR);
306.1027 +    }
306.1028 +    else {			/* user wants to suppress time zones? */
306.1029 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
306.1030 +	time_t when = mail_longdate (&elt);
306.1031 +	date = ctime (&when);	/* use traditional date */
306.1032 +      }
306.1033 +				/* use POSIX-style date */
306.1034 +      else date = mail_cdate (tmp,&elt);
306.1035 +      if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
306.1036 +      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
306.1037 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
306.1038 +	mm_log (tmp,ERROR);
306.1039 +      }
306.1040 +				/* get next message */
306.1041 +      else if ((*af) (tstream,data,&flags,&date,&message)) continue;
306.1042 +    }
306.1043 +    fclose (sf);		/* punt scratch file */
306.1044 +    return NIL;			/* give up */
306.1045 +  } while (message);		/* until no more messages */
306.1046 +  if (fflush (sf)) {
306.1047 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
306.1048 +    mm_log (tmp,ERROR);
306.1049 +    fclose (sf);		/* punt scratch file */
306.1050 +    return NIL;			/* give up */
306.1051 +  }
306.1052 +  i = ftell (sf);		/* size of scratch file */
306.1053 +
306.1054 +				/* close sniffing stream */
306.1055 +  if (tstream != stream) tstream = mail_close (tstream);
306.1056 +  mm_critical (stream);		/* go critical */
306.1057 +				/* try to open readwrite for UIDPLUS */
306.1058 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
306.1059 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
306.1060 +    tstream = mail_close (tstream);
306.1061 +  if (au && !tstream) {		/* wanted an APPENDUID? */
306.1062 +    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
306.1063 +    MM_LOG (tmp,WARN);
306.1064 +    au = NIL;
306.1065 +  }
306.1066 +  if (((fd = unix_lock (dummy_file (file,mailbox),
306.1067 +			O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
306.1068 +			lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) {
306.1069 +    mm_nocritical (stream);	/* done with critical */
306.1070 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
306.1071 +    mm_log (tmp,ERROR);
306.1072 +    return NIL;
306.1073 +  }
306.1074 +  fstat (fd,&sbuf);		/* get current file size */
306.1075 +  rewind (sf);
306.1076 +  times.modtime = time (0);	/* set mtime to now */
306.1077 +				/* write all messages */
306.1078 +  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
306.1079 +      (fflush (df) == EOF) || fsync (fd)) {
306.1080 +    sprintf (buf,"Message append failed: %s",strerror (errno));
306.1081 +    mm_log (buf,ERROR);
306.1082 +    ftruncate (fd,sbuf.st_size);/* revert file */
306.1083 +    times.actime =		/* preserve \Marked status */
306.1084 +      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
306.1085 +      sbuf.st_atime : times.modtime;
306.1086 +    ret = NIL;			/* return error */
306.1087 +  }
306.1088 +				/* set atime to now-1 if successful copy */
306.1089 +  else times.actime = times.modtime - 1;
306.1090 +  utime (file,&times);		/* set the times */
306.1091 +  fclose (sf);			/* done with scratch file */
306.1092 +				/* force UIDVALIDITY assignment now */
306.1093 +  if (tstream && !tstream->uid_validity)
306.1094 +    tstream->uid_validity = (unsigned long) time (0);
306.1095 +				/* return sets if doing APPENDUID */
306.1096 +  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
306.1097 +  else mail_free_searchset (&dst);
306.1098 +  flock (fd,LOCK_UN);		/* unlock mailbox (can't use unix_unlock() */
306.1099 +  if (lock && *lock) unlink (lock);
306.1100 +  fclose (df);			/* close mailbox */
306.1101 +  if (tstream) {		/* update last UID if we can */
306.1102 +    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
306.1103 +    local->dirty = T;		/* do a rewrite */
306.1104 +    local->appending = T;	/* but not at the cost of marking as old */
306.1105 +    tstream = mail_close (tstream);
306.1106 +  }
306.1107 +  mm_nocritical (stream);	/* release critical */
306.1108 +  return ret;
306.1109 +}
306.1110 +
306.1111 +/* Collect and write single message to append scratch file
306.1112 + * Accepts: MAIL stream
306.1113 + *	    scratch file
306.1114 + *	    flags
306.1115 + *	    date
306.1116 + *	    message stringstruct
306.1117 + * Returns: NIL if write error, else T
306.1118 + */
306.1119 +
306.1120 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
306.1121 +		     STRING *msg)
306.1122 +{
306.1123 +  unsigned char *s,*t;
306.1124 +  unsigned long uf;
306.1125 +  long f = mail_parse_flags (stream,flags,&uf);
306.1126 +				/* write metadata */
306.1127 +  if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL;
306.1128 +  for (s = date; *s; *s++) switch (*s) {
306.1129 +  default:
306.1130 +    if (putc (*s,sf) == EOF) return NIL;
306.1131 +  case '\r': case '\n':
306.1132 +    break;
306.1133 +  }
306.1134 +  if (fputs ("\r\n",sf) == EOF) return NIL;
306.1135 +  while (uf)			/* write user flags */    
306.1136 +    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
306.1137 +	(fprintf (sf," %s",s) < 0)) return NIL;
306.1138 +  if (fputs ("\r\n",sf) == EOF) return NIL;
306.1139 +  while (SIZE (msg)) {		/* copy text to scratch file */
306.1140 +    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
306.1141 +      if (!*s) *s = 0x80;	/* disallow NUL */
306.1142 +				/* write buffered text */
306.1143 +    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
306.1144 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
306.1145 +    else return NIL;		/* failed */
306.1146 +  }
306.1147 +				/* write trailing CRLF and return */
306.1148 +  return (fputs ("\r\n",sf) == EOF) ? NIL : T;
306.1149 +}
306.1150 +
306.1151 +/* Append messages from scratch file to mailbox
306.1152 + * Accepts: MAIL stream
306.1153 + *	    source file
306.1154 + *	    destination file
306.1155 + *	    uidset to update if non-NIL
306.1156 + * Returns: T if success, NIL if failure
306.1157 + */
306.1158 +
306.1159 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
306.1160 +{
306.1161 +  int ti,zn,c;
306.1162 +  long f;
306.1163 +  unsigned long i,j;
306.1164 +  char *x,tmp[MAILTMPLEN];
306.1165 +  int hdrp = T;
306.1166 +				/* get message metadata line */
306.1167 +  while (fgets (tmp,MAILTMPLEN,sf)) {
306.1168 +    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
306.1169 +    f = strtol (tmp,&x,10);	/* get flags */
306.1170 +    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
306.1171 +    i = strtoul (x,&x,10);	/* get message size */
306.1172 +    if ((*x++ != ' ') ||	/* build initial header */
306.1173 +	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
306.1174 +	(f&fSEEN && (putc ('R',df) == EOF)) ||
306.1175 +	(fputs ("\r\nX-Status: ",df) == EOF) ||
306.1176 +	(f&fDELETED && (putc ('D',df) == EOF)) ||
306.1177 +	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
306.1178 +	(f&fANSWERED && (putc ('A',df) == EOF)) ||
306.1179 +	(f&fDRAFT && (putc ('T',df) == EOF)) ||
306.1180 +	(fputs ("\r\nX-Keywords:",df) == EOF)) return NIL;
306.1181 +				/* copy keywords */
306.1182 +    while ((c = getc (sf)) != '\n') switch (c) {
306.1183 +    case EOF:
306.1184 +      return NIL;
306.1185 +    default:
306.1186 +      if (putc (c,df) == EOF) return NIL;
306.1187 +    }
306.1188 +    if ((putc ('\n',df) == EOF) ||
306.1189 +	(set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0)))
306.1190 +      return NIL;
306.1191 +
306.1192 +    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
306.1193 +				/* get read line length */
306.1194 +      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
306.1195 +      i -= j;			/* number of bytes left */
306.1196 +      if (!j) continue;		/* do nothing if line emptied */
306.1197 +				/* complete line? */
306.1198 +      if ((c == '\n')) switch (tmp[0]) {
306.1199 +      case 'F':			/* possible "From " (case counts here) */
306.1200 +	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
306.1201 +	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
306.1202 +	  if (!unix_fromwidget) {
306.1203 +	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
306.1204 +	    if (!ti) break;	/*  it looks like a valid header */
306.1205 +	  }			/* write the widget */
306.1206 +	  if (putc ('>',df) == EOF) return NIL;
306.1207 +	}
306.1208 +	break;
306.1209 +      case 'S': case 's':	/* possible "Status:" */
306.1210 +	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
306.1211 +	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
306.1212 +	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
306.1213 +	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
306.1214 +	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
306.1215 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
306.1216 +	break;
306.1217 +      case 'X': case 'x':	/* possible X-??? header */
306.1218 +	if (hdrp && (tmp[1] == '-') &&
306.1219 +				/* possible X-UID: */
306.1220 +	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
306.1221 +	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
306.1222 +	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
306.1223 +				/* possible X-IMAP: */
306.1224 +	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
306.1225 +	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
306.1226 +	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
306.1227 +	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
306.1228 +	      ((tmp[6] == ':') ||
306.1229 +				/* or X-IMAPbase: */
306.1230 +	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
306.1231 +		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
306.1232 +		((tmp[8] == 's') || (tmp[8] == 'S')) &&
306.1233 +		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
306.1234 +				/* possible X-Status: */
306.1235 +	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
306.1236 +	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
306.1237 +	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
306.1238 +	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
306.1239 +	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
306.1240 +	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
306.1241 +				/* possible X-Keywords: */
306.1242 +	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
306.1243 +	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
306.1244 +	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
306.1245 +	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
306.1246 +	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
306.1247 +	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
306.1248 +	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
306.1249 +	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
306.1250 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
306.1251 +	break;
306.1252 +      case '\n':		/* blank line */
306.1253 +	hdrp = NIL;
306.1254 +	break;
306.1255 +      default:			/* nothing to do */
306.1256 +	break;
306.1257 +      }
306.1258 +				/* just write the line */
306.1259 +      if (fwrite (tmp,1,j,df) != j) return NIL;
306.1260 +    }
306.1261 +    if (i) return NIL;		/* didn't read entire message */
306.1262 +				/* update set */
306.1263 +    if (stream) mail_append_set (set,stream->uid_last);
306.1264 +  }
306.1265 +  return T;
306.1266 +}
306.1267 +
306.1268 +/* Internal routines */
306.1269 +
306.1270 +
306.1271 +/* UNIX mail abort stream
306.1272 + * Accepts: MAIL stream
306.1273 + */
306.1274 +
306.1275 +void unix_abort (MAILSTREAM *stream)
306.1276 +{
306.1277 +  if (LOCAL) {			/* only if a file is open */
306.1278 +    if (LOCAL->fd >= 0) close (LOCAL->fd);
306.1279 +    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
306.1280 +      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
306.1281 +      close (LOCAL->ld);	/* close the lock file */
306.1282 +      unlink (LOCAL->lname);	/* and delete it */
306.1283 +    }
306.1284 +    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
306.1285 +				/* free local text buffers */
306.1286 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
306.1287 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
306.1288 +    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
306.1289 +    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
306.1290 +				/* nuke the local data */
306.1291 +    fs_give ((void **) &stream->local);
306.1292 +    stream->dtb = NIL;		/* log out the DTB */
306.1293 +  }
306.1294 +}
306.1295 +
306.1296 +/* UNIX open and lock mailbox
306.1297 + * Accepts: file name to open/lock
306.1298 + *	    file open mode
306.1299 + *	    destination buffer for lock file name
306.1300 + *	    type of locking operation (LOCK_SH or LOCK_EX)
306.1301 + */
306.1302 +
306.1303 +int unix_lock (char *file,int flags,int mode,char *lock,int op)
306.1304 +{
306.1305 +  int fd,ld,j;
306.1306 +  int i = LOCKTIMEOUT * 60 - 1;
306.1307 +  char tmp[MAILTMPLEN];
306.1308 +  time_t t;
306.1309 +  struct stat sb;
306.1310 +  sprintf (lock,"%s.lock",file);/* build lock filename */
306.1311 +  do {				/* until OK or out of tries */
306.1312 +    t = time (0);		/* get the time now */
306.1313 +				/* try to get the lock */
306.1314 +    if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0)
306.1315 +      close (ld);		/* got it, close the lock file! */
306.1316 +    else if (errno != EEXIST) {	/* miscellaneous error */
306.1317 +      sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno));
306.1318 +      if (!(i%15)) mm_log (tmp,WARN);
306.1319 +    }
306.1320 +				/* lock exists, still active? */
306.1321 +    else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) &&
306.1322 +	     ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0))
306.1323 +      close (ld);		/* got timed-out lock file */
306.1324 +    else {			/* active lock, try again */
306.1325 +      if (!(i%15)) {
306.1326 +	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
306.1327 +		 file,i);
306.1328 +	mm_log (tmp,WARN);
306.1329 +      }
306.1330 +      sleep (1);		/* wait a second before next retry */
306.1331 +    }
306.1332 +  } while (*lock && ld < 0 && i--);
306.1333 +				/* open file */
306.1334 +  if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
306.1335 +  else {			/* open failed */
306.1336 +    j = errno;			/* preserve error code */
306.1337 +    if (*lock) unlink (lock);	/* flush the lock file if any */
306.1338 +    errno = j;			/* restore error code */
306.1339 +  }
306.1340 +  return fd;
306.1341 +}
306.1342 +
306.1343 +/* UNIX unlock and close mailbox
306.1344 + * Accepts: file descriptor
306.1345 + *	    (optional) mailbox stream to check atime/mtime
306.1346 + *	    (optional) lock file name
306.1347 + */
306.1348 +
306.1349 +void unix_unlock (int fd,MAILSTREAM *stream,char *lock)
306.1350 +{
306.1351 +  if (stream) {			/* need to muck with times? */
306.1352 +    struct stat sbuf;
306.1353 +    struct utimbuf times;
306.1354 +    time_t now = time (0);
306.1355 +    fstat (fd,&sbuf);		/* get file times */
306.1356 +    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
306.1357 +      times.actime = now;	/* set atime to now */
306.1358 +				/* set mtime to (now - 1) if necessary */
306.1359 +      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
306.1360 +    }
306.1361 +    else if (stream->recent) {	/* readonly with recent messages */
306.1362 +      if ((sbuf.st_atime >= sbuf.st_mtime) ||
306.1363 +	  (sbuf.st_atime >= sbuf.st_ctime))
306.1364 +				/* keep past mtime, whack back atime */
306.1365 +	times.actime = (times.modtime = (sbuf.st_mtime < now) ?
306.1366 +			sbuf.st_mtime : now) - 1;
306.1367 +      else now = 0;		/* no time change needed */
306.1368 +    }
306.1369 +				/* readonly with no recent messages */
306.1370 +    else if ((sbuf.st_atime < sbuf.st_mtime) ||
306.1371 +	     (sbuf.st_atime < sbuf.st_ctime)) {
306.1372 +      times.actime = now;	/* set atime to now */
306.1373 +				/* set mtime to (now - 1) if necessary */
306.1374 +      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
306.1375 +    }
306.1376 +    else now = 0;		/* no time change needed */
306.1377 +				/* set the times, note change */
306.1378 +    if (now && !utime (stream->mailbox,&times))
306.1379 +      LOCAL->filetime = times.modtime;
306.1380 +  }
306.1381 +  flock (fd,LOCK_UN);		/* release flock'ers */
306.1382 +  if (!stream) close (fd);	/* close the file if no stream */
306.1383 +				/* flush the lock file if any */
306.1384 +  if (lock && *lock) unlink (lock);
306.1385 +}
306.1386 +
306.1387 +/* UNIX mail parse and lock mailbox
306.1388 + * Accepts: MAIL stream
306.1389 + *	    space to write lock file name
306.1390 + *	    type of locking operation
306.1391 + * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
306.1392 + */
306.1393 +
306.1394 +int unix_parse (MAILSTREAM *stream,char *lock,int op)
306.1395 +{
306.1396 +  int zn;
306.1397 +  unsigned long i,j,k,m;
306.1398 +  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
306.1399 +  int ti = 0,retain = T;
306.1400 +  unsigned long nmsgs = stream->nmsgs;
306.1401 +  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
306.1402 +  unsigned long recent = stream->recent;
306.1403 +  unsigned long oldnmsgs = stream->nmsgs;
306.1404 +  short silent = stream->silent;
306.1405 +  short pseudoseen = NIL;
306.1406 +  struct stat sbuf;
306.1407 +  STRING bs;
306.1408 +  FDDATA d;
306.1409 +  MESSAGECACHE *elt;
306.1410 +  mail_lock (stream);		/* guard against recursion or pingers */
306.1411 +				/* toss out previous descriptor */
306.1412 +  if (LOCAL->fd >= 0) close (LOCAL->fd);
306.1413 +  mm_critical (stream);		/* open and lock mailbox (shared OK) */
306.1414 +  if ((LOCAL->fd = unix_lock (stream->mailbox,
306.1415 +			      O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY),
306.1416 +			      NIL,lock,op)) < 0) {
306.1417 +    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
306.1418 +    mm_log (tmp,ERROR);
306.1419 +    unix_abort (stream);
306.1420 +    mail_unlock (stream);
306.1421 +    mm_nocritical (stream);	/* done with critical */
306.1422 +    return NIL;
306.1423 +  }
306.1424 +  fstat (LOCAL->fd,&sbuf);	/* get status */
306.1425 +				/* validate change in size */
306.1426 +  if (sbuf.st_size < LOCAL->filesize) {
306.1427 +    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
306.1428 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
306.1429 +    mm_log (tmp,ERROR);		/* this is pretty bad */
306.1430 +    unix_unlock (LOCAL->fd,stream,lock);
306.1431 +    unix_abort (stream);
306.1432 +    mail_unlock (stream);
306.1433 +    mm_nocritical (stream);	/* done with critical */
306.1434 +    return NIL;
306.1435 +  }
306.1436 +
306.1437 +				/* new data? */
306.1438 +  else if (i = sbuf.st_size - LOCAL->filesize) {
306.1439 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
306.1440 +    d.pos = LOCAL->filesize;	/* get to that position in the file */
306.1441 +    d.chunk = LOCAL->buf;	/* initial buffer chunk */
306.1442 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
306.1443 +    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
306.1444 +				/* skip leading whitespace for broken MTAs */
306.1445 +    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
306.1446 +	   (c == ' ') || (c == '\t')) SNX (&bs);
306.1447 +    if (SIZE (&bs)) {		/* read new data */
306.1448 +				/* remember internal header position */
306.1449 +      j = LOCAL->filesize + GETPOS (&bs);
306.1450 +      s = unix_mbxline (stream,&bs,&i);
306.1451 +      t = NIL,zn = 0;
306.1452 +      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
306.1453 +      if (!ti) {		/* someone pulled the rug from under us */
306.1454 +	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
306.1455 +		 (char *) s);
306.1456 +	mm_log (tmp,ERROR);
306.1457 +	unix_unlock (LOCAL->fd,stream,lock);
306.1458 +	unix_abort (stream);
306.1459 +	mail_unlock (stream);
306.1460 +	mm_nocritical (stream);	/* done with critical */
306.1461 +	return NIL;
306.1462 +      }
306.1463 +      stream->silent = T;	/* quell main program new message events */
306.1464 +      do {			/* found a message */
306.1465 +				/* instantiate first new message */
306.1466 +	mail_exists (stream,++nmsgs);
306.1467 +	(elt = mail_elt (stream,nmsgs))->valid = T;
306.1468 +	recent++;		/* assume recent by default */
306.1469 +	elt->recent = T;
306.1470 +				/* note position/size of internal header */
306.1471 +	elt->private.special.offset = j;
306.1472 +	elt->private.msg.header.offset = elt->private.special.text.size = i;
306.1473 +
306.1474 +				/* generate plausible IMAPish date string */
306.1475 +	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
306.1476 +	date[14] = date[17] = ':';
306.1477 +				/* dd */
306.1478 +	date[0] = t[ti - 2]; date[1] = t[ti - 1];
306.1479 +				/* mmm */
306.1480 +	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
306.1481 +				/* hh */
306.1482 +	date[12] = t[ti + 1]; date[13] = t[ti + 2];
306.1483 +				/* mm */
306.1484 +	date[15] = t[ti + 4]; date[16] = t[ti + 5];
306.1485 +	if (t[ti += 6] == ':') {/* ss */
306.1486 +	  date[18] = t[++ti]; date[19] = t[++ti];
306.1487 +	  ti++;			/* move to space */
306.1488 +	}
306.1489 +	else date[18] = date[19] = '0';
306.1490 +				/* yy -- advance over timezone if necessary */
306.1491 +	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
306.1492 +	date[7] = t[ti + 1]; date[8] = t[ti + 2];
306.1493 +	date[9] = t[ti + 3]; date[10] = t[ti + 4];
306.1494 +				/* zzz */
306.1495 +	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
306.1496 +	date[21] = *t++; date[22] = *t++; date[23] = *t++;
306.1497 +	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
306.1498 +	else {			/* numeric time zone */
306.1499 +	  date[24] = *t++; date[25] = *t++;
306.1500 +	  date[26] = '\0'; date[20] = ' ';
306.1501 +	}
306.1502 +				/* set internal date */
306.1503 +	if (!mail_parse_date (elt,date)) {
306.1504 +	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
306.1505 +	  mm_log (tmp,WARN);
306.1506 +	}
306.1507 +
306.1508 +	do {			/* look for message body */
306.1509 +	  s = t = unix_mbxline (stream,&bs,&i);
306.1510 +	  if (i) switch (*s) {	/* check header lines */
306.1511 +	  case 'X':		/* possible X-???: line */
306.1512 +	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
306.1513 +				/* X-Status: becomes Status: in S case */
306.1514 +	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
306.1515 +		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
306.1516 +				/* possible X-Keywords */
306.1517 +	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
306.1518 +		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
306.1519 +		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
306.1520 +		SIZEDTEXT uf;
306.1521 +		retain = NIL;	/* don't retain continuation */
306.1522 +		s += 11;	/* flush leading whitespace */
306.1523 +		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
306.1524 +		  while (*s == ' ') s++;
306.1525 +				/* find end of keyword */
306.1526 +		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
306.1527 +				/* got a keyword? */
306.1528 +		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
306.1529 +		    uf.data = (unsigned char *) s;
306.1530 +		    uf.size = k;
306.1531 +		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
306.1532 +		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
306.1533 +			elt->user_flags |= ((long) 1) << j;
306.1534 +			break;
306.1535 +		      }
306.1536 +		  }
306.1537 +		  s = u;	/* advance to next keyword */
306.1538 +		}
306.1539 +		break;
306.1540 +	      }
306.1541 +
306.1542 +				/* possible X-IMAP */
306.1543 +	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
306.1544 +		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
306.1545 +					 ((s[6] == 'b') && (s[7] == 'a') &&
306.1546 +					  (s[8] == 's') && (s[9] == 'e') &&
306.1547 +					  (s[10] == ':')))) {
306.1548 +		retain = NIL;	/* don't retain continuation */
306.1549 +		if ((nmsgs == 1) && !stream->uid_validity) {
306.1550 +				/* advance to data */
306.1551 +		  s += m ? 7 : 11;
306.1552 +				/* flush whitespace */
306.1553 +		  while (*s == ' ') s++;
306.1554 +		  j = 0;	/* slurp UID validity */
306.1555 +				/* found a digit? */
306.1556 +		  while (isdigit (*s)) {
306.1557 +		    j *= 10;	/* yes, add it in */
306.1558 +		    j += *s++ - '0';
306.1559 +		  }
306.1560 +				/* flush whitespace */
306.1561 +		  while (*s == ' ') s++;
306.1562 +				/* must have valid UID validity and UID last */
306.1563 +		  if (j && isdigit (*s)) {
306.1564 +				/* pseudo-header seen if X-IMAP */
306.1565 +		    if (m) pseudoseen = LOCAL->pseudo = T;
306.1566 +				/* save UID validity */
306.1567 +		    stream->uid_validity = j;
306.1568 +		    j = 0;	/* slurp UID last */
306.1569 +		    while (isdigit (*s)) {
306.1570 +		      j *= 10;	/* yes, add it in */
306.1571 +		      j += *s++ - '0';
306.1572 +		    }
306.1573 +				/* save UID last */
306.1574 +		    stream->uid_last = j;
306.1575 +				/* process keywords */
306.1576 +		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
306.1577 +			 s = u,j++) {
306.1578 +				/* flush leading whitespace */
306.1579 +		      while (*s == ' ') s++;
306.1580 +		      u = strpbrk (s," \n\r");
306.1581 +				/* got a keyword? */
306.1582 +		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
306.1583 +			  (k <= MAXUSERFLAG)) {
306.1584 +			if (stream->user_flags[j])
306.1585 +			  fs_give ((void **) &stream->user_flags[j]);
306.1586 +			stream->user_flags[j] = (char *) fs_get (k + 1);
306.1587 +			strncpy (stream->user_flags[j],s,k);
306.1588 +			stream->user_flags[j][k] = '\0';
306.1589 +		      }
306.1590 +		    }
306.1591 +		  }
306.1592 +		}
306.1593 +		break;
306.1594 +	      }
306.1595 +
306.1596 +				/* possible X-UID */
306.1597 +	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
306.1598 +		       s[5] == ':') {
306.1599 +		retain = NIL;	/* don't retain continuation */
306.1600 +				/* only believe if have a UID validity */
306.1601 +		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
306.1602 +		  s += 6;	/* advance to UID value */
306.1603 +				/* flush whitespace */
306.1604 +		  while (*s == ' ') s++;
306.1605 +		  j = 0;
306.1606 +				/* found a digit? */
306.1607 +		  while (isdigit (*s)) {
306.1608 +		    j *= 10;	/* yes, add it in */
306.1609 +		    j += *s++ - '0';
306.1610 +		  }
306.1611 +				/* flush remainder of line */
306.1612 +		  while (*s != '\n') s++;
306.1613 +				/* make sure not duplicated */
306.1614 +		  if (elt->private.uid)
306.1615 +		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
306.1616 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
306.1617 +			     j,elt->private.uid);
306.1618 +				/* make sure UID doesn't go backwards */
306.1619 +		  else if (j <= prevuid)
306.1620 +		    sprintf (tmp,"Message %lu UID %lu less than %lu",
306.1621 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
306.1622 +			     j,prevuid + 1);
306.1623 +#if 0	/* this is currently broken by UIDPLUS */
306.1624 +				/* or skip by mailbox's recorded last */
306.1625 +		  else if (j > stream->uid_last)
306.1626 +		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
306.1627 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
306.1628 +			     j,stream->uid_last);
306.1629 +#endif
306.1630 +		  else {	/* normal UID case */
306.1631 +		    prevuid = elt->private.uid = j;
306.1632 +#if 1	/* temporary kludge for UIDPLUS */
306.1633 +		    if (prevuid > stream->uid_last) {
306.1634 +		      stream->uid_last = prevuid;
306.1635 +		      LOCAL->ddirty = LOCAL->dirty = T;
306.1636 +		    }		    
306.1637 +#endif
306.1638 +		    break;	/* exit this cruft */
306.1639 +		  }
306.1640 +		  mm_log (tmp,WARN);
306.1641 +				/* invalidate UID validity */
306.1642 +		  stream->uid_validity = 0;
306.1643 +		  elt->private.uid = 0;
306.1644 +		}
306.1645 +		break;
306.1646 +	      }
306.1647 +	    }
306.1648 +				/* otherwise fall into S case */
306.1649 +
306.1650 +	  case 'S':		/* possible Status: line */
306.1651 +	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
306.1652 +		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
306.1653 +	      retain = NIL;	/* don't retain continuation */
306.1654 +	      s += 6;		/* advance to status flags */
306.1655 +	      do switch (*s++) {/* parse flags */
306.1656 +	      case 'R':		/* message read */
306.1657 +		elt->seen = T;
306.1658 +		break;
306.1659 +	      case 'O':		/* message old */
306.1660 +		if (elt->recent) {
306.1661 +		  elt->recent = NIL;
306.1662 +		  recent--;	/* it really wasn't recent */
306.1663 +		}
306.1664 +		break;
306.1665 +	      case 'D':		/* message deleted */
306.1666 +		elt->deleted = T;
306.1667 +		break;
306.1668 +	      case 'F':		/* message flagged */
306.1669 +		elt->flagged = T;
306.1670 +		break;
306.1671 +	      case 'A':		/* message answered */
306.1672 +		elt->answered = T;
306.1673 +		break;
306.1674 +	      case 'T':		/* message is a draft */
306.1675 +		elt->draft = T;
306.1676 +		break;
306.1677 +	      default:		/* some other crap */
306.1678 +		break;
306.1679 +	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
306.1680 +	      break;		/* all done */
306.1681 +	    }
306.1682 +				/* otherwise fall into default case */
306.1683 +
306.1684 +	  default:		/* ordinary header line */
306.1685 +	    if ((*s == 'S') || (*s == 's') ||
306.1686 +		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
306.1687 +	      unsigned char *e,*v;
306.1688 +				/* must match what mail_filter() does */
306.1689 +	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
306.1690 +		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
306.1691 +		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
306.1692 +				  (c != '\r') && (c != '\n')));
306.1693 +		   *v++ = *u++);
306.1694 +	      *v = '\0';	/* tie off */
306.1695 +				/* matches internal header? */
306.1696 +	      if (!compare_cstring (tmp,"STATUS") ||
306.1697 +		  !compare_cstring (tmp,"X-STATUS") ||
306.1698 +		  !compare_cstring (tmp,"X-KEYWORDS") ||
306.1699 +		  !compare_cstring (tmp,"X-UID") ||
306.1700 +		  !compare_cstring (tmp,"X-IMAP") ||
306.1701 +		  !compare_cstring (tmp,"X-IMAPBASE")) {
306.1702 +		char err[MAILTMPLEN];
306.1703 +		sprintf (err,"Discarding bogus %s header in message %lu",
306.1704 +			 (char *) tmp,elt->msgno);
306.1705 +		mm_log (err,WARN);
306.1706 +		retain = NIL;	/* don't retain continuation */
306.1707 +		break;		/* different case or something */
306.1708 +	      }
306.1709 +	    }
306.1710 +				/* retain or non-continuation? */
306.1711 +	    if (retain || ((*s != ' ') && (*s != '\t'))) {
306.1712 +	      retain = T;	/* retaining continuation now */
306.1713 +				/* line length in CRLF format newline */
306.1714 +	      k = i + (((i < 2) || (s[i - 2] != '\r')) ? 1 : 0);
306.1715 +				/* header size */
306.1716 +	      elt->rfc822_size = elt->private.spare.data += k;
306.1717 +	    }
306.1718 +	    else {
306.1719 +	      char err[MAILTMPLEN];
306.1720 +	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
306.1721 +		      elt->msgno,(char *) s);
306.1722 +	      if (u = strpbrk (err,"\r\n")) *u = '\0';
306.1723 +	      mm_log (err,WARN);
306.1724 +	      break;		/* different case or something */
306.1725 +	    }
306.1726 +	    break;
306.1727 +	  }
306.1728 +	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
306.1729 +				/* "internal" header sans trailing newline */
306.1730 +	if (i) elt->private.spare.data -= 2;
306.1731 +				/* assign a UID if none found */
306.1732 +	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
306.1733 +	  prevuid = elt->private.uid = ++stream->uid_last;
306.1734 +	  elt->private.dirty = T;
306.1735 +	  LOCAL->ddirty = T;	/* force update */
306.1736 +	}
306.1737 +	else elt->private.dirty = elt->recent;
306.1738 +
306.1739 +				/* note size of header, location of text */
306.1740 +	elt->private.msg.header.text.size = 
306.1741 +	  (elt->private.msg.text.offset =
306.1742 +	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
306.1743 +	     elt->private.special.text.size;
306.1744 +	k = m = 0;		/* no previous line size yet */
306.1745 +				/* note current position */
306.1746 +	j = LOCAL->filesize + GETPOS (&bs);
306.1747 +	if (i) do {		/* look for next message */
306.1748 +	  s = unix_mbxline (stream,&bs,&i);
306.1749 +	  if (i) {		/* got new data? */
306.1750 +	    VALID (s,t,ti,zn);	/* yes, parse line */
306.1751 +	    if (!ti) {		/* not a header line, add it to message */
306.1752 +	      if (s[i - 1] == '\n')
306.1753 +		elt->rfc822_size += 
306.1754 +		  k = i + (m = (((i < 2) || s[i - 2] != '\r') ? 1 : 0));
306.1755 +	      else {		/* file does not end with newline! */
306.1756 +		elt->rfc822_size += i;
306.1757 +		k = m = 0;
306.1758 +	      }
306.1759 +				/* update current position */
306.1760 +	      j = LOCAL->filesize + GETPOS (&bs);
306.1761 +	    }
306.1762 +	  }
306.1763 +	} while (i && !ti);	/* until found a header */
306.1764 +	elt->private.msg.text.text.size = j -
306.1765 +	  (elt->private.special.offset + elt->private.msg.text.offset);
306.1766 +	if (k == 2) {		/* last line was blank? */
306.1767 +	  elt->private.msg.text.text.size -= (m ? 1 : 2);
306.1768 +	  elt->rfc822_size -= 2;
306.1769 +	}
306.1770 +				/* until end of buffer */
306.1771 +      } while (!stream->sniff && i);
306.1772 +      if (pseudoseen) {		/* flush pseudo-message if present */
306.1773 +				/* decrement recent count */
306.1774 +	if (mail_elt (stream,1)->recent) recent--;
306.1775 +				/* and the exists count */
306.1776 +	mail_exists (stream,nmsgs--);
306.1777 +	mail_expunged(stream,1);/* fake an expunge of that message */
306.1778 +      }
306.1779 +				/* need to start a new UID validity? */
306.1780 +      if (!stream->uid_validity) {
306.1781 +	stream->uid_validity = (unsigned long) time (0);
306.1782 +	if (nmsgs) {		/* don't bother if empty file */
306.1783 +				/* make dirty to restart UID epoch */
306.1784 +	  LOCAL->ddirty = LOCAL->dirty = T;
306.1785 +				/* need to rewrite msg 1 if not pseudo */
306.1786 +	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
306.1787 +	  mm_log ("Assigning new unique identifiers to all messages",NIL);
306.1788 +	}
306.1789 +      }
306.1790 +      stream->nmsgs = oldnmsgs;	/* whack it back down */
306.1791 +      stream->silent = silent;	/* restore old silent setting */
306.1792 +				/* notify upper level of new mailbox sizes */
306.1793 +      mail_exists (stream,nmsgs);
306.1794 +      mail_recent (stream,recent);
306.1795 +				/* mark dirty so O flags are set */
306.1796 +      if (recent) LOCAL->dirty = T;
306.1797 +    }
306.1798 +  }
306.1799 +				/* no change, don't babble if never got time */
306.1800 +  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
306.1801 +    mm_log ("New mailbox modification time but apparently no changes",WARN);
306.1802 +				/* update parsed file size and time */
306.1803 +  LOCAL->filesize = sbuf.st_size;
306.1804 +  LOCAL->filetime = sbuf.st_mtime;
306.1805 +  return T;			/* return the winnage */
306.1806 +}
306.1807 +
306.1808 +/* UNIX read line from mailbox
306.1809 + * Accepts: mail stream
306.1810 + *	    stringstruct
306.1811 + *	    pointer to line size
306.1812 + * Returns: pointer to input line
306.1813 + */
306.1814 +
306.1815 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
306.1816 +{
306.1817 +  unsigned long i,j,k,m;
306.1818 +  char *s,*t,*te;
306.1819 +  char *ret = "";
306.1820 +				/* flush old buffer */
306.1821 +  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
306.1822 +				/* if buffer needs refreshing */
306.1823 +  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
306.1824 +  if (SIZE (bs)) {		/* find newline */
306.1825 +				/* end of fast scan */
306.1826 +    te = (t = (s = bs->curpos) + bs->cursize) - 12;
306.1827 +    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
306.1828 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
306.1829 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
306.1830 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
306.1831 +      --s;			/* back up */
306.1832 +      break;			/* exit loop */
306.1833 +    }
306.1834 +				/* final character-at-a-time scan */
306.1835 +    while ((s < t) && (*s != '\n')) ++s;
306.1836 +				/* difficult case if line spans buffer */
306.1837 +    if ((i = s - bs->curpos) == bs->cursize) {
306.1838 +				/* have space in line buffer? */
306.1839 +      if (i > LOCAL->linebuflen) {
306.1840 +	fs_give ((void **) &LOCAL->linebuf);
306.1841 +	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
306.1842 +      }
306.1843 +				/* remember what we have so far */
306.1844 +      memcpy (LOCAL->linebuf,bs->curpos,i);
306.1845 +				/* load next buffer */
306.1846 +      SETPOS (bs,k = GETPOS (bs) + i);
306.1847 +				/* end of fast scan */
306.1848 +      te = (t = (s = bs->curpos) + bs->cursize) - 12;
306.1849 +				/* fast scan in overlap buffer */
306.1850 +      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
306.1851 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
306.1852 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
306.1853 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
306.1854 +	--s;			/* back up */
306.1855 +	break;			/* exit loop */
306.1856 +      }
306.1857 +
306.1858 +				/* final character-at-a-time scan */
306.1859 +      while ((s < t) && (*s != '\n')) ++s;
306.1860 +				/* huge line? */
306.1861 +      if ((j = s - bs->curpos) == bs->cursize) {
306.1862 +	SETPOS (bs,GETPOS (bs) + j);
306.1863 +				/* look for end of line (s-l-o-w!!) */
306.1864 +	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
306.1865 +	SETPOS (bs,k);		/* go back to where it started */
306.1866 +      }
306.1867 +				/* got size of data, make buffer for return */
306.1868 +      ret = LOCAL->line = (char *) fs_get (i + j + 2);
306.1869 +				/* copy first chunk */
306.1870 +      memcpy (ret,LOCAL->linebuf,i);
306.1871 +      while (j) {		/* copy remainder */
306.1872 +	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
306.1873 +	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
306.1874 +	i += k;			/* account for this much read in */
306.1875 +	j -= k;
306.1876 +	bs->curpos += k;	/* increment new position */
306.1877 +	bs->cursize -= k;	/* eat that many bytes */
306.1878 +      }
306.1879 +      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
306.1880 +				/* read newline at end */
306.1881 +      if (SIZE (bs)) ret[i++] = SNX (bs);
306.1882 +      ret[i] = '\0';		/* makes debugging easier */
306.1883 +    }
306.1884 +    else {			/* this is easy */
306.1885 +      ret = bs->curpos;		/* string it at this position */
306.1886 +      bs->curpos += ++i;	/* increment new position */
306.1887 +      bs->cursize -= i;		/* eat that many bytes */
306.1888 +    }
306.1889 +    *size = i;			/* return that to user */
306.1890 +  }
306.1891 +  else *size = 0;		/* end of data, return empty */
306.1892 +  return ret;
306.1893 +}
306.1894 +
306.1895 +/* UNIX make pseudo-header
306.1896 + * Accepts: MAIL stream
306.1897 + *	    buffer to write pseudo-header
306.1898 + * Returns: length of pseudo-header
306.1899 + */
306.1900 +
306.1901 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
306.1902 +{
306.1903 +  int i;
306.1904 +  char *s,*t,tmp[MAILTMPLEN];
306.1905 +  time_t now = time(0);
306.1906 +  rfc822_fixed_date (tmp);
306.1907 +  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",
306.1908 +	   pseudo_from,ctime (&now),
306.1909 +	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
306.1910 +	   (unsigned long) now,mylocalhost (),stream->uid_validity,
306.1911 +	   stream->uid_last);
306.1912 +  for (t = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
306.1913 +    if (stream->user_flags[i])
306.1914 +      sprintf (t += strlen (t)," %s",stream->user_flags[i]);
306.1915 +  strcpy (t += strlen (t),"\r\nStatus: RO\r\n\r\n");
306.1916 +  for (s = pseudo_msg,t += strlen (t); *s; *t++ = *s++)
306.1917 +    if (*s == '\n') *t++ = '\r';
306.1918 +  *t++ = '\r'; *t++ = '\n'; *t++ = '\r'; *t++ = '\n';
306.1919 +  *t = '\0';			/* tie off pseudo header */
306.1920 +  return t - hdr;		/* return length of pseudo header */
306.1921 +}
306.1922 +
306.1923 +/* UNIX make status string
306.1924 + * Accepts: MAIL stream
306.1925 + *	    destination string to write
306.1926 + *	    message cache entry
306.1927 + *	    UID to write if non-zero (else use elt->private.uid)
306.1928 + *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
306.1929 + * Returns: length of string
306.1930 + */
306.1931 +
306.1932 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
306.1933 +			    unsigned long uid,long flag)
306.1934 +{
306.1935 +  char *t,stack[64];
306.1936 +  char *s = status;
306.1937 +  unsigned long n;
306.1938 +  unsigned long pad = 50;
306.1939 +  /* This used to use sprintf(), but thanks to certain cretinous C libraries
306.1940 +     with horribly slow implementations of sprintf() I had to change it to this
306.1941 +     mess.  At least it should be fast. */
306.1942 +  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
306.1943 +  *s++ = ':'; *s++ = ' ';
306.1944 +  if (elt->seen) *s++ = 'R';
306.1945 +				/* only write O if have a UID */
306.1946 +  if (flag && (!elt->recent || LOCAL->appending)) *s++ = 'O';
306.1947 +  *s++ = '\r'; *s++ = '\n';
306.1948 +  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
306.1949 +  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
306.1950 +  if (elt->deleted) *s++ = 'D';
306.1951 +  if (elt->flagged) *s++ = 'F';
306.1952 +  if (elt->answered) *s++ = 'A';
306.1953 +  if (elt->draft) *s++ = 'T';
306.1954 +  *s++ = '\r'; *s++ = '\n';
306.1955 +
306.1956 +  *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
306.1957 +  *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
306.1958 +  if (n = elt->user_flags) do {
306.1959 +    *s++ = ' ';
306.1960 +    for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
306.1961 +  } while (n);
306.1962 +  n = s - status;		/* get size of stuff so far */
306.1963 +				/* pad X-Keywords to make size constant */
306.1964 +  if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
306.1965 +  *s++ = '\r'; *s++ = '\n';
306.1966 +  if (flag) {			/* want to include UID? */
306.1967 +    t = stack;
306.1968 +				/* push UID digits on the stack */
306.1969 +    n = uid ? uid : elt->private.uid;
306.1970 +    do *t++ = (char) (n % 10) + '0';
306.1971 +    while (n /= 10);
306.1972 +    *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
306.1973 +    *s++ = ' ';
306.1974 +				/* pop UID from stack */
306.1975 +    while (t > stack) *s++ = *--t;
306.1976 +    *s++ = '\r'; *s++ = '\n';
306.1977 +  }
306.1978 +				/* end of extended message status */
306.1979 +  *s++ = '\r'; *s++ = '\n'; *s = '\0';
306.1980 +  return s - status;		/* return size of resulting string */
306.1981 +}
306.1982 +
306.1983 +/* Rewrite mailbox file
306.1984 + * Accepts: MAIL stream, must be critical and locked
306.1985 + *	    return pointer to number of expunged messages if want expunge
306.1986 + *	    lock file name
306.1987 + *	    expunge sequence, not deleted flag
306.1988 + * Returns: T if success and mailbox unlocked, NIL if failure
306.1989 + */
306.1990 +
306.1991 +#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
306.1992 +
306.1993 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
306.1994 +		   long flags)
306.1995 +{
306.1996 +  MESSAGECACHE *elt;
306.1997 +  UNIXFILE f;
306.1998 +  char *s;
306.1999 +  struct utimbuf times;
306.2000 +  long ret,flag;
306.2001 +  unsigned long i,j;
306.2002 +  unsigned long recent = stream->recent;
306.2003 +  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
306.2004 +  if (nexp) *nexp = 0;		/* initially nothing expunged */
306.2005 +				/* calculate size of mailbox after rewrite */
306.2006 +  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
306.2007 +    elt = mail_elt (stream,i);	/* get cache */
306.2008 +    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
306.2009 +				/* add RFC822 size of this message */
306.2010 +      size += elt->private.special.text.size + elt->private.spare.data +
306.2011 +	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
306.2012 +	  elt->private.msg.text.text.size + 2;
306.2013 +      flag = 1;			/* only count X-IMAPbase once */
306.2014 +    }
306.2015 +  }
306.2016 +  if (!size) {			/* no messages and no pseudo, make one now */
306.2017 +    size = unix_pseudo (stream,LOCAL->buf);
306.2018 +    LOCAL->pseudo = T;
306.2019 +  }
306.2020 +				/* extend the file as necessary */
306.2021 +  if (ret = unix_extend (stream,size)) {
306.2022 +    /* Set up buffered I/O file structure
306.2023 +     * curpos	current position being written through buffering
306.2024 +     * filepos	current position being written physically to the disk
306.2025 +     * bufpos	current position being written in the buffer
306.2026 +     * protect	current maximum position that can be written to the disk
306.2027 +     *		before buffering is forced
306.2028 +     * The code tries to buffer so that that disk is written in multiples of
306.2029 +     * OVERBLOWBUFLEN bytes.
306.2030 +     */
306.2031 +    f.stream = stream;		/* note mail stream */
306.2032 +    f.curpos = f.filepos = 0;	/* start of file */
306.2033 +    f.protect = stream->nmsgs ?	/* initial protection pointer */
306.2034 +    mail_elt (stream,1)->private.special.offset : 8192;
306.2035 +    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
306.2036 +
306.2037 +    if (LOCAL->pseudo)		/* update pseudo-header */
306.2038 +      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
306.2039 +				/* loop through all messages */
306.2040 +    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
306.2041 +      elt = mail_elt (stream,i);/* get cache */
306.2042 +				/* expunge this message? */
306.2043 +      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
306.2044 +				/* one less recent message */
306.2045 +	if (elt->recent) --recent;
306.2046 +	mail_expunged(stream,i);/* notify upper levels */
306.2047 +	++*nexp;		/* count up one more expunged message */
306.2048 +      }
306.2049 +      else {			/* preserve this message */
306.2050 +	i++;			/* advance to next message */
306.2051 +	if ((flag < 0) ||	/* need to rewrite message? */
306.2052 +	    elt->private.dirty ||
306.2053 +	    (((unsigned long) f.curpos) != elt->private.special.offset) ||
306.2054 +	    (elt->private.msg.header.text.size !=
306.2055 +	     (elt->private.spare.data +
306.2056 +	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
306.2057 +	  unsigned long newoffset = f.curpos;
306.2058 +				/* yes, seek to internal header */
306.2059 +	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
306.2060 +	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
306.2061 +				/* protection pointer moves to RFC822 header */
306.2062 +	  f.protect = elt->private.special.offset +
306.2063 +	    elt->private.msg.header.offset;
306.2064 +				/* write internal header */
306.2065 +	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
306.2066 +				/* get RFC822 header */
306.2067 +	  s = unix_header (stream,elt->msgno,&j,NIL);
306.2068 +				/* in case this got decremented */
306.2069 +	  elt->private.msg.header.offset = elt->private.special.text.size;
306.2070 +				/* header size, sans trailing newline */
306.2071 +	  if ((j < 4) || (s[j - 4] == '\r')) j -= 2;
306.2072 +	  if (j != elt->private.spare.data) fatal ("header size inconsistent");
306.2073 +				/* protection pointer moves to RFC822 text */
306.2074 +	  f.protect = elt->private.special.offset +
306.2075 +	    elt->private.msg.text.offset;
306.2076 +	  unix_write (&f,s,j);	/* write RFC822 header */
306.2077 +				/* write status and UID */
306.2078 +	  unix_write (&f,LOCAL->buf,
306.2079 +		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
306.2080 +	  flag = 1;		/* only write X-IMAPbase once */
306.2081 +				/* new file header size */
306.2082 +	  elt->private.msg.header.text.size = elt->private.spare.data + j;
306.2083 +
306.2084 +				/* did text move? */
306.2085 +	  if (f.curpos != f.protect) {
306.2086 +				/* get message text */
306.2087 +	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
306.2088 +				/* can't happen it says here */
306.2089 +	    if (j > elt->private.msg.text.text.size)
306.2090 +	      fatal ("text size inconsistent");
306.2091 +				/* new text offset, status/UID may change it */
306.2092 +	    elt->private.msg.text.offset = f.curpos - newoffset;
306.2093 +				/* protection pointer moves to next message */
306.2094 +	    f.protect = (i <= stream->nmsgs) ?
306.2095 +	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 2);
306.2096 +	    unix_write (&f,s,j);/* write text */
306.2097 +				/* write trailing newline */
306.2098 +	    unix_write (&f,"\r\n",2);
306.2099 +	  }
306.2100 +	  else {		/* tie off header and status */
306.2101 +	    unix_write (&f,NIL,NIL);
306.2102 +				/* protection pointer moves to next message */
306.2103 +	    f.protect = (i <= stream->nmsgs) ?
306.2104 +	      mail_elt (stream,i)->private.special.offset : size;
306.2105 +				/* locate end of message text */
306.2106 +	    j = f.filepos + elt->private.msg.text.text.size;
306.2107 +				/* trailing newline already there? */
306.2108 +	    if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
306.2109 +	    else {		/* trailing newline missing, write it */
306.2110 +	      f.curpos = f.filepos = j;
306.2111 +	      unix_write (&f,"\r\n",2);
306.2112 +	    }
306.2113 +	  }
306.2114 +				/* new internal header offset */
306.2115 +	  elt->private.special.offset = newoffset;
306.2116 +	  elt->private.dirty =NIL;/* message is now clean */
306.2117 +	}
306.2118 +	else {			/* no need to rewrite this message */
306.2119 +				/* tie off previous message if needed */
306.2120 +	  unix_write (&f,NIL,NIL);
306.2121 +				/* protection pointer moves to next message */
306.2122 +	  f.protect = (i <= stream->nmsgs) ?
306.2123 +	    mail_elt (stream,i)->private.special.offset : size;
306.2124 +				/* locate end of message text */
306.2125 +	  j = f.filepos + elt->private.special.text.size +
306.2126 +	    elt->private.msg.header.text.size +
306.2127 +	      elt->private.msg.text.text.size;
306.2128 +				/* trailing newline already there? */
306.2129 +	  if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
306.2130 +	  else {		/* trailing newline missing, write it */
306.2131 +	    f.curpos = f.filepos = j;
306.2132 +	    unix_write (&f,"\r\n",2);
306.2133 +	  }
306.2134 +	}
306.2135 +      }
306.2136 +    }
306.2137 +
306.2138 +    unix_write (&f,NIL,NIL);	/* tie off final message */
306.2139 +    if (size != ((unsigned long) f.filepos)) fatal ("file size inconsistent");
306.2140 +    fs_give ((void **) &f.buf);	/* free buffer */
306.2141 +				/* make sure tied off */
306.2142 +    ftruncate (LOCAL->fd,LOCAL->filesize = size);
306.2143 +    fsync (LOCAL->fd);		/* make sure the updates take */
306.2144 +    if (size && (flag < 0)) fatal ("lost UID base information");
306.2145 +				/* no longer dirty */
306.2146 +    LOCAL->ddirty = LOCAL->dirty = NIL;
306.2147 +  				/* notify upper level of new mailbox sizes */
306.2148 +    mail_exists (stream,stream->nmsgs);
306.2149 +    mail_recent (stream,recent);
306.2150 +				/* set atime to now, mtime a second earlier */
306.2151 +    times.modtime = (times.actime = time (0)) -1;
306.2152 +				/* set the times, note change */
306.2153 +    if (!utime (stream->mailbox,&times)) LOCAL->filetime = times.modtime;
306.2154 +				/* flush the lock file */
306.2155 +    unix_unlock (LOCAL->fd,stream,lock);
306.2156 +  }
306.2157 +  return ret;			/* return state from algorithm */
306.2158 +}
306.2159 +
306.2160 +/* Extend UNIX mailbox file
306.2161 + * Accepts: MAIL stream
306.2162 + *	    new desired size
306.2163 + * Return: T if success, else NIL
306.2164 + */
306.2165 +
306.2166 +long unix_extend (MAILSTREAM *stream,unsigned long size)
306.2167 +{
306.2168 +  unsigned long i = (size > ((unsigned long) LOCAL->filesize)) ?
306.2169 +    size - ((unsigned long) LOCAL->filesize) : 0;
306.2170 +  if (i) {			/* does the mailbox need to grow? */
306.2171 +    if (i > LOCAL->buflen) {	/* make sure have enough space */
306.2172 +				/* this user won the lottery all right */
306.2173 +      fs_give ((void **) &LOCAL->buf);
306.2174 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
306.2175 +    }
306.2176 +    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
306.2177 +    while (T) {			/* until write successful or punt */
306.2178 +      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
306.2179 +      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
306.2180 +      else {
306.2181 +	long e = errno;		/* note error before doing ftruncate */
306.2182 +	ftruncate (LOCAL->fd,LOCAL->filesize);
306.2183 +	if (mm_diskerror (stream,e,NIL)) {
306.2184 +	  fsync (LOCAL->fd);	/* user chose to punt */
306.2185 +	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
306.2186 +	  if (!stream->silent) mm_log (LOCAL->buf,ERROR);
306.2187 +	  return NIL;
306.2188 +	}
306.2189 +      }
306.2190 +    }
306.2191 +  }
306.2192 +  return LONGT;
306.2193 +}
306.2194 +
306.2195 +/* Write data to buffered file
306.2196 + * Accepts: buffered file pointer
306.2197 + *	    file data or NIL to indicate "flush buffer"
306.2198 + *	    date size (ignored for "flush buffer")
306.2199 + * Does not return until success
306.2200 + */
306.2201 +
306.2202 +void unix_write (UNIXFILE *f,char *buf,unsigned long size)
306.2203 +{
306.2204 +  unsigned long i,j,k;
306.2205 +  if (buf) {			/* doing buffered write? */
306.2206 +    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
306.2207 +				/* yes, have space in current buffer chunk? */
306.2208 +    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
306.2209 +				/* yes, fill up buffer as much as we can */
306.2210 +      memcpy (f->bufpos,buf,k = min (j,size));
306.2211 +      f->bufpos += k;		/* new buffer position */
306.2212 +      f->curpos += k;		/* new current position */
306.2213 +      if (j -= k) return;	/* all done if still have buffer free space */
306.2214 +      buf += k;			/* full, get new unwritten data pointer */
306.2215 +      size -= k;		/* new data size */
306.2216 +      i += k;			/* new buffer data size */
306.2217 +    }
306.2218 +    /* This chunk of the buffer is full.  See if can make some space by
306.2219 +     * writing to the disk, if there's enough unprotected space to do so.
306.2220 +     * Try to fill out any unaligned chunk, along with any subsequent full
306.2221 +     * chunks that will fit in unprotected space.
306.2222 +     */
306.2223 +				/* any unprotected space we can write to? */
306.2224 +    if (j = min (i,f->protect - f->filepos)) {
306.2225 +				/* yes, filepos not at chunk boundary? */
306.2226 +      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
306.2227 +	j -= k;			/* yes, and can write out partial chunk */
306.2228 +      else k = 0;		/* no partial chunk to write */
306.2229 +				/* if at least a chunk free, write that too */
306.2230 +      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
306.2231 +      if (k) {			/* write data if there is anything we can */
306.2232 +	unix_phys_write (f,f->buf,k);
306.2233 +				/* slide buffer */
306.2234 +	if (i -= k) memmove (f->buf,f->buf + k,i);
306.2235 +	f->bufpos = f->buf + i;	/* new end of buffer */
306.2236 +      }
306.2237 +    }
306.2238 +
306.2239 +    /* Have flushed the buffer as best as possible.  All done if no more
306.2240 +     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
306.2241 +     * data is larger than a chunk AND the unprotected space is also larger
306.2242 +     * than a chunk, then write as many chunks as we can directly from the
306.2243 +     * data.  Buffer the rest, expanding the buffer as needed.
306.2244 +     */
306.2245 +    if (size) {			/* have more data that we need to buffer? */
306.2246 +				/* can write any of it to disk instead? */
306.2247 +      if ((f->bufpos == f->buf) && 
306.2248 +	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
306.2249 +				/* write as much as we can right now */
306.2250 +	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
306.2251 +	buf += j;		/* new data pointer */
306.2252 +	size -= j;		/* new data size */
306.2253 +	f->curpos += j;		/* advance current pointer */
306.2254 +      }
306.2255 +      if (size) {		/* still have data that we need to buffer? */
306.2256 +				/* yes, need to expand the buffer? */
306.2257 +	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
306.2258 +				/* note current position in buffer */
306.2259 +	  j = f->bufpos - f->buf;
306.2260 +	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
306.2261 +	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
306.2262 +				/* in case buffer relocated */
306.2263 +	  f->bufpos = f->buf + j;
306.2264 +	}
306.2265 +				/* buffer remaining data */
306.2266 +	memcpy (f->bufpos,buf,size);
306.2267 +	f->bufpos += size;	/* new end of buffer */
306.2268 +	f->curpos += size;	/* advance current pointer */
306.2269 +      }
306.2270 +    }
306.2271 +  }
306.2272 +  else {			/* flush buffer to disk */
306.2273 +    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
306.2274 +    f->bufpos = f->buf;		/* reset buffer */
306.2275 +				/* update positions */
306.2276 +    f->curpos = f->protect = f->filepos;
306.2277 +  }
306.2278 +}
306.2279 +
306.2280 +/* Physical disk write
306.2281 + * Accepts: buffered file pointer
306.2282 + *	    buffer address
306.2283 + *	    buffer size
306.2284 + * Does not return until success
306.2285 + */
306.2286 +
306.2287 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
306.2288 +{
306.2289 +  MAILSTREAM *stream = f->stream;
306.2290 +				/* write data at desired position */
306.2291 +  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
306.2292 +		  (write (LOCAL->fd,buf,size) < 0))) {
306.2293 +    int e;
306.2294 +    char tmp[MAILTMPLEN];
306.2295 +    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
306.2296 +    mm_log (tmp,ERROR);
306.2297 +    mm_diskerror (NIL,e,T);	/* serious problem, must retry */
306.2298 +  }
306.2299 +  f->filepos += size;		/* update file position */
306.2300 +}
   307.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   307.2 +++ b/src/osdep/nt/unixnt.h	Mon Sep 14 15:17:45 2009 +0900
   307.3 @@ -0,0 +1,161 @@
   307.4 +/* ========================================================================
   307.5 + * Copyright 1988-2006 University of Washington
   307.6 + *
   307.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   307.8 + * you may not use this file except in compliance with the License.
   307.9 + * You may obtain a copy of the License at
  307.10 + *
  307.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  307.12 + *
  307.13 + * 
  307.14 + * ========================================================================
  307.15 + */
  307.16 +
  307.17 +/*
  307.18 + * Program:	UNIX mail routines
  307.19 + *
  307.20 + * Author:	Mark Crispin
  307.21 + *		Networks and Distributed Computing
  307.22 + *		Computing & Communications
  307.23 + *		University of Washington
  307.24 + *		Administration Building, AG-44
  307.25 + *		Seattle, WA  98195
  307.26 + *		Internet: MRC@CAC.Washington.EDU
  307.27 + *
  307.28 + * Date:	20 December 1989
  307.29 + * Last Edited:	30 August 2006
  307.30 + */
  307.31 +
  307.32 +
  307.33 +/*				DEDICATION
  307.34 + *
  307.35 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  307.36 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  307.37 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  307.38 + * a two-month bout with cirrhosis of the liver.
  307.39 + *
  307.40 + *  He was a dear friend, and I miss him terribly.
  307.41 + *
  307.42 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  307.43 + */
  307.44 +
  307.45 +/* Validate line
  307.46 + * Accepts: pointer to candidate string to validate as a From header
  307.47 + *	    return pointer to end of date/time field
  307.48 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  307.49 + *	    return pointer to offset from t of time zone (if non-zero)
  307.50 + * Returns: t,ti,zn set if valid From string, else ti is NIL
  307.51 + */
  307.52 +
  307.53 +#define VALID(s,x,ti,zn) {						\
  307.54 +  ti = 0;								\
  307.55 +  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
  307.56 +      (s[4] == ' ')) {							\
  307.57 +    for (x = s + 5; *x && *x != '\012'; x++);				\
  307.58 +    if (*x) {								\
  307.59 +      if (x[-1] == '\015') --x;						\
  307.60 +      if (x - s >= 41) {						\
  307.61 +	for (zn = -1; x[zn] != ' '; zn--);				\
  307.62 +	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
  307.63 +	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
  307.64 +	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
  307.65 +	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
  307.66 +	  x += zn - 12;							\
  307.67 +      }									\
  307.68 +      if (x - s >= 27) {						\
  307.69 +	if (x[-5] == ' ') {						\
  307.70 +	  if (x[-8] == ':') zn = 0,ti = -5;				\
  307.71 +	  else if (x[-9] == ' ') ti = zn = -9;				\
  307.72 +	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
  307.73 +	    ti = zn = -11;						\
  307.74 +	}								\
  307.75 +	else if (x[-4] == ' ') {					\
  307.76 +	  if (x[-9] == ' ') zn = -4,ti = -9;				\
  307.77 +	}								\
  307.78 +	else if (x[-6] == ' ') {					\
  307.79 +	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
  307.80 +	    zn = -6,ti = -11;						\
  307.81 +	}								\
  307.82 +	if (ti && !((x[ti - 3] == ':') &&				\
  307.83 +		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
  307.84 +		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
  307.85 +		    (x[ti - 11] == ' '))) ti = 0;			\
  307.86 +      }									\
  307.87 +    }									\
  307.88 +  }									\
  307.89 +}
  307.90 +
  307.91 +/* You are not expected to understand this macro, but read the next page if
  307.92 + * you are not faint of heart.
  307.93 + *
  307.94 + * Known formats to the VALID macro are:
  307.95 + *		From user Wed Dec  2 05:53 1992
  307.96 + * BSD		From user Wed Dec  2 05:53:22 1992
  307.97 + * SysV		From user Wed Dec  2 05:53 PST 1992
  307.98 + * rn		From user Wed Dec  2 05:53:22 PST 1992
  307.99 + *		From user Wed Dec  2 05:53 -0700 1992
 307.100 + * emacs	From user Wed Dec  2 05:53:22 -0700 1992
 307.101 + *		From user Wed Dec  2 05:53 1992 PST
 307.102 + *		From user Wed Dec  2 05:53:22 1992 PST
 307.103 + *		From user Wed Dec  2 05:53 1992 -0700
 307.104 + * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
 307.105 + *
 307.106 + * Plus all of the above with `` remote from xxx'' after it. Thank you very
 307.107 + * much, smail and Solaris, for making my life considerably more complicated.
 307.108 + */
 307.109 +
 307.110 +/*
 307.111 + * What?  You want to understand the VALID macro anyway?  Alright, since you
 307.112 + * insist.  Actually, it isn't really all that difficult, provided that you
 307.113 + * take it step by step.
 307.114 + *
 307.115 + * Line 1	Initializes the return ti value to failure (0);
 307.116 + * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
 307.117 + * Lines 4-6	Validates that there is an end of line and points x at it.
 307.118 + * Lines 7-14	First checks to see if the line is at least 41 characters long.
 307.119 + *		If so, it scans backwards to find the rightmost space.  From
 307.120 + *		that point, it scans backwards to see if the string matches
 307.121 + *		`` remote from''.  If so, it sets x to point to the space at
 307.122 + *		the start of the string.
 307.123 + * Line 15	Makes sure that there are at least 27 characters in the line.
 307.124 + * Lines 16-21	Checks if the date/time ends with the year (there is a space
 307.125 + *		five characters back).  If there is a colon three characters
 307.126 + *		further back, there is no timezone field, so zn is set to 0
 307.127 + *		and ti is set in front of the year.  Otherwise, there must
 307.128 + *		either to be a space four characters back for a three-letter
 307.129 + *		timezone, or a space six characters back followed by a + or -
 307.130 + *		for a numeric timezone; in either case, zn and ti become the
 307.131 + *		offset of the space immediately before it.
 307.132 + * Lines 22-24	Are the failure case for line 14.  If there is a space four
 307.133 + *		characters back, it is a three-letter timezone; there must be a
 307.134 + *		space for the year nine characters back.  zn is the zone
 307.135 + *		offset; ti is the offset of the space.
 307.136 + * Lines 25-28	Are the failure case for line 20.  If there is a space six
 307.137 + *		characters back, it is a numeric timezone; there must be a
 307.138 + *		space eleven characters back and a + or - five characters back.
 307.139 + *		zn is the zone offset; ti is the offset of the space.
 307.140 + * Line 29-32	If ti is valid, make sure that the string before ti is of the
 307.141 + *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
 307.142 + *		invalidate ti.  There must be a colon three characters back
 307.143 + *		and a space six or nine	characters back (depending upon
 307.144 + *		whether or not the character six characters back is a colon).
 307.145 + *		There must be a space three characters further back (in front
 307.146 + *		of the day), one seven characters back (in front of the month),
 307.147 + *		and one eleven characters back (in front of the day of week).
 307.148 + *		ti is set to be the offset of the space before the time.
 307.149 + *
 307.150 + * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
 307.151 + * newer pipelined machines it is faster being open-coded than it would be if
 307.152 + * subroutines are called.
 307.153 + *
 307.154 + * Why does it scan backwards from the end of the line, instead of doing the
 307.155 + * much easier forward scan?  There is no deterministic way to parse the
 307.156 + * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
 307.157 + * see if unquoted spaces were possible.  They are, and I've encountered enough
 307.158 + * evil mail to be totally unwilling to trust that ``it will never happen''.
 307.159 + */
 307.160 +
 307.161 +/* Build parameters */
 307.162 +
 307.163 +#define KODRETRY 15		/* kiss-of-death retry in seconds */
 307.164 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
   308.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   308.2 +++ b/src/osdep/nt/write.c	Mon Sep 14 15:17:45 2009 +0900
   308.3 @@ -0,0 +1,59 @@
   308.4 +/* ========================================================================
   308.5 + * Copyright 1988-2006 University of Washington
   308.6 + *
   308.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   308.8 + * you may not use this file except in compliance with the License.
   308.9 + * You may obtain a copy of the License at
  308.10 + *
  308.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  308.12 + *
  308.13 + * 
  308.14 + * ========================================================================
  308.15 + */
  308.16 +
  308.17 +/*
  308.18 + * Program:	Write data, treating partial writes as an error
  308.19 + *
  308.20 + * Author:	Mark Crispin
  308.21 + *		Networks and Distributed Computing
  308.22 + *		Computing & Communications
  308.23 + *		University of Washington
  308.24 + *		Administration Building, AG-44
  308.25 + *		Seattle, WA  98195
  308.26 + *		Internet: MRC@CAC.Washington.EDU
  308.27 + *
  308.28 + * Date:	26 May 1995
  308.29 + * Last Edited:	30 August 2006
  308.30 + */
  308.31 +
  308.32 +/*  The whole purpose of this unfortunate routine is to deal with DOS and
  308.33 + * certain cretinous versions of UNIX which decided that the "bytes actually
  308.34 + * written" return value from write() gave them license to use that for things
  308.35 + * that are really errors, such as disk quota exceeded, maximum file size
  308.36 + * exceeded, disk full, etc.
  308.37 + * 
  308.38 + *  BSD won't screw us this way on the local filesystem, but who knows what
  308.39 + * some NFS-mounted filesystem will do.
  308.40 + */
  308.41 +
  308.42 +#undef write
  308.43 +
  308.44 +/* Write data to file
  308.45 + * Accepts: file descriptor
  308.46 + *	    I/O vector structure
  308.47 + *	    number of vectors in structure
  308.48 + * Returns: number of bytes written if successful, -1 if failure
  308.49 + */
  308.50 +
  308.51 +long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
  308.52 +
  308.53 +long safe_write (int fd,char *buf,long nbytes)
  308.54 +{
  308.55 +  long i,j;
  308.56 +  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
  308.57 +    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
  308.58 +	   (errno == EINTR));
  308.59 +    if (j < 0) return j;
  308.60 +  }
  308.61 +  return nbytes;
  308.62 +}
   309.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   309.2 +++ b/src/osdep/nt/yunchan.c	Mon Sep 14 15:17:45 2009 +0900
   309.3 @@ -0,0 +1,286 @@
   309.4 +/* ========================================================================
   309.5 + * Copyright 1988-2006 University of Washington
   309.6 + *
   309.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   309.8 + * you may not use this file except in compliance with the License.
   309.9 + * You may obtain a copy of the License at
  309.10 + *
  309.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  309.12 + *
  309.13 + * 
  309.14 + * ========================================================================
  309.15 + */
  309.16 +
  309.17 +/*
  309.18 + * Program:	Unix compatibility routines
  309.19 + *
  309.20 + * Author:	Mark Crispin
  309.21 + *		Networks and Distributed Computing
  309.22 + *		Computing & Communications
  309.23 + *		University of Washington
  309.24 + *		Administration Building, AG-44
  309.25 + *		Seattle, WA  98195
  309.26 + *		Internet: MRC@CAC.Washington.EDU
  309.27 + *
  309.28 + * Date:	14 September 1996
  309.29 + * Last Edited:	30 August 2006
  309.30 + */
  309.31 +
  309.32 +
  309.33 +/*				DEDICATION
  309.34 + *
  309.35 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  309.36 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  309.37 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  309.38 + * a two-month bout with cirrhosis of the liver.
  309.39 + *
  309.40 + *  He was a dear friend, and I miss him terribly.
  309.41 + *
  309.42 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  309.43 + */
  309.44 + 
  309.45 +/* Emulator for BSD flock() call
  309.46 + * Accepts: file descriptor
  309.47 + *	    operation bitmask
  309.48 + * Returns: 0 if successful, -1 if failure
  309.49 + */
  309.50 +
  309.51 +/*  Our friends in Redmond have decided that you can not write to any segment
  309.52 + * which has a shared lock.  This screws up the shared-write mailbox drivers
  309.53 + * (mbx, mtx, and tenex).  As a workaround, we'll only lock the first byte of
  309.54 + * the file, meaning that you can't write that byte shared.
  309.55 + *  This behavior seems to be new as of NT 4.0.
  309.56 + */
  309.57 +
  309.58 +int flock (int fd,int op)
  309.59 +{
  309.60 +  HANDLE hdl = (HANDLE) _get_osfhandle (fd);
  309.61 +  DWORD flags = (op & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
  309.62 +  OVERLAPPED offset = {NIL,NIL,0,0,NIL};
  309.63 +  int ret = -1;
  309.64 +  blocknotify_t bn = (blocknotify_t) 
  309.65 +    ((op & LOCK_NB) ? NIL : mail_parameters (NIL,GET_BLOCKNOTIFY,NIL));
  309.66 +  if (hdl < 0) errno = EBADF;	/* error in file descriptor */
  309.67 +  else switch (op & ~LOCK_NB) {	/* translate to LockFileEx() op */
  309.68 +  case LOCK_EX:			/* exclusive */
  309.69 +    flags |= LOCKFILE_EXCLUSIVE_LOCK;
  309.70 +  case LOCK_SH:			/* shared */
  309.71 +    if (!check_nt ()) return 0;	/* always succeeds if not NT */
  309.72 +    if (bn) (*bn) (BLOCK_FILELOCK,NIL);
  309.73 +				/* bug for bug compatible with Unix */
  309.74 +    UnlockFileEx (hdl,NIL,1,0,&offset);
  309.75 +				/* lock the file as requested */
  309.76 +    if (LockFileEx (hdl,flags,NIL,1,0,&offset)) ret = 0;
  309.77 +    if (bn) (*bn) (BLOCK_NONE,NIL);
  309.78 +				/* if failed */
  309.79 +    if (ret) errno = (op & LOCK_NB) ? EAGAIN : EBADF;
  309.80 +    break;
  309.81 +  case LOCK_UN:			/* unlock */
  309.82 +    if (check_nt ()) UnlockFileEx (hdl,NIL,1,0,&offset);
  309.83 +    ret = 0;			/* always succeeds */
  309.84 +  default:			/* default */
  309.85 +    errno = EINVAL;		/* bad call */
  309.86 +    break;
  309.87 +  }
  309.88 +  return ret;
  309.89 +}
  309.90 +
  309.91 +/* Local storage */
  309.92 +
  309.93 +static char *loghdr;		/* log file header string */
  309.94 +static HANDLE loghdl = NIL;	/* handle of event source */
  309.95 +
  309.96 +/* Emulator for BSD syslog() routine
  309.97 + * Accepts: priority
  309.98 + *	    message
  309.99 + *	    parameters
 309.100 + */
 309.101 +
 309.102 +void syslog (int priority,const char *message,...)
 309.103 +{
 309.104 +  va_list args;
 309.105 +  LPTSTR strs[2];
 309.106 +  char tmp[MAILTMPLEN];		/* callers must be careful not to pop this */
 309.107 +  unsigned short etype;
 309.108 +  if (!check_nt ()) return;	/* no-op on non-NT system */
 309.109 +				/* default event source */
 309.110 +  if (!loghdl) openlog ("c-client",LOG_PID,LOG_MAIL);
 309.111 +  switch (priority) {		/* translate UNIX type into NT type */
 309.112 +  case LOG_ALERT:
 309.113 +    etype = EVENTLOG_ERROR_TYPE;
 309.114 +    break;
 309.115 +  case LOG_INFO:
 309.116 +    etype = EVENTLOG_INFORMATION_TYPE;
 309.117 +    break;
 309.118 +  default:
 309.119 +    etype = EVENTLOG_WARNING_TYPE;
 309.120 +  }
 309.121 +  va_start (args,message);	/* initialize vararg mechanism */
 309.122 +  vsprintf (tmp,message,args);	/* build message */
 309.123 +  strs[0] = loghdr;		/* write header */
 309.124 +  strs[1] = tmp;		/* then the message */
 309.125 +				/* report the event */
 309.126 +  ReportEvent (loghdl,etype,(unsigned short) priority,2000,NIL,2,0,strs,NIL);
 309.127 +  va_end (args);
 309.128 +}
 309.129 +
 309.130 +
 309.131 +/* Emulator for BSD openlog() routine
 309.132 + * Accepts: identity
 309.133 + *	    options
 309.134 + *	    facility
 309.135 + */
 309.136 +
 309.137 +void openlog (const char *ident,int logopt,int facility)
 309.138 +{
 309.139 +  char tmp[MAILTMPLEN];
 309.140 +  if (!check_nt ()) return;	/* no-op on non-NT system */
 309.141 +  if (loghdl) fatal ("Duplicate openlog()!");
 309.142 +  loghdl = RegisterEventSource (NIL,ident);
 309.143 +  sprintf (tmp,(logopt & LOG_PID) ? "%s[%d]" : "%s",ident,getpid ());
 309.144 +  loghdr = cpystr (tmp);	/* save header for later */
 309.145 +}
 309.146 +
 309.147 +/* Copy Unix string with CRLF newlines
 309.148 + * Accepts: destination string
 309.149 + *	    pointer to size of destination string buffer
 309.150 + *	    source string
 309.151 + *	    length of source string
 309.152 + * Returns: length of copied string
 309.153 + */
 309.154 +
 309.155 +unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
 309.156 +			    unsigned long srcl)
 309.157 +{
 309.158 +  unsigned long i,j;
 309.159 +  char *d = src;
 309.160 +				/* count number of LF's in source string(s) */
 309.161 +  for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
 309.162 +				/* flush destination buffer if too small */
 309.163 +  if (*dst && (i > *dstl)) fs_give ((void **) dst);
 309.164 +  if (!*dst) {			/* make a new buffer if needed */
 309.165 +    *dst = (char *) fs_get ((*dstl = i) + 1);
 309.166 +    if (dstl) *dstl = i;	/* return new buffer length to main program */
 309.167 +  }
 309.168 +  d = *dst;			/* destination string */
 309.169 +				/* copy strings, inserting CR's before LF's */
 309.170 +  while (srcl--) switch (*src) {
 309.171 +  case '\015':			/* unlikely carriage return */
 309.172 +    *d++ = *src++;		/* copy it and any succeeding linefeed */
 309.173 +    if (srcl && *src == '\012') {
 309.174 +      *d++ = *src++;
 309.175 +      srcl--;
 309.176 +    }
 309.177 +    break;
 309.178 +  case '\012':			/* line feed? */
 309.179 +    *d++ ='\015';		/* yes, prepend a CR, drop into default case */
 309.180 +  default:			/* ordinary chararacter */
 309.181 +    *d++ = *src++;		/* just copy character */
 309.182 +    break;
 309.183 +  }
 309.184 +  *d = '\0';			/* tie off destination */
 309.185 +  return d - *dst;		/* return length */
 309.186 +}
 309.187 +
 309.188 +/* Length of Unix string after unix_crlfcpy applied
 309.189 + * Accepts: source string
 309.190 + * Returns: length of string
 309.191 + */
 309.192 +
 309.193 +unsigned long unix_crlflen (STRING *s)
 309.194 +{
 309.195 +  unsigned long pos = GETPOS (s);
 309.196 +  unsigned long i = SIZE (s);
 309.197 +  unsigned long j = i;
 309.198 +  while (j--) switch (SNX (s)) {/* search for newlines */
 309.199 +  case '\015':			/* unlikely carriage return */
 309.200 +    if (j && (CHR (s) == '\012')) {
 309.201 +      SNX (s);			/* eat the line feed */
 309.202 +      j--;
 309.203 +    }
 309.204 +    break;
 309.205 +  case '\012':			/* line feed? */
 309.206 +    i++;
 309.207 +  default:			/* ordinary chararacter */
 309.208 +    break;
 309.209 +  }
 309.210 +  SETPOS (s,pos);		/* restore old position */
 309.211 +  return i;
 309.212 +}
 309.213 +
 309.214 +/* Undoubtably, I'm going to regret these two routines in the future.  I
 309.215 + * regret them now.  Their purpose is to work around two problems in the
 309.216 + * VC++ 6.0 C library:
 309.217 + *  (1) tmpfile() creates the file in the current directory instead of a
 309.218 + *	temporary directory
 309.219 + *  (2) tmpfile() and fclose() think that on NT systems, it works to unlink
 309.220 + *	the file while it's still open, so there's no need for the _tmpfname
 309.221 + *	hook at fclose().  Unfortunately, that doesn't work in Win2K.
 309.222 + * I would be delighted to have a better alternative.
 309.223 + */
 309.224 +
 309.225 +#undef fclose			/* use the real fclose() in close_file() */
 309.226 +
 309.227 +/* Substitute for Microsoft's tmpfile() that uses the real temporary directory
 309.228 + * Returns: FILE structure if success, NIL if failure
 309.229 + */
 309.230 +
 309.231 +FILE *create_tempfile (void)
 309.232 +{
 309.233 +  FILE *ret = NIL;
 309.234 +  char *s = _tempnam (getenv ("TEMP"),"msg");
 309.235 +  if (s) {			/* if got temporary name... */
 309.236 +				/* open file, and stash name on _tmpfname */
 309.237 +    if (ret = fopen (s,"w+b")) ret->_tmpfname = s;
 309.238 +    else fs_give ((void **) &s);/* flush temporary string */
 309.239 +  }
 309.240 +  return ret;
 309.241 +}
 309.242 +
 309.243 +
 309.244 +/* Substitute for Microsoft's fclose() that always flushes _tmpfname
 309.245 + * Returns: FILE structure if success, NIL if failure
 309.246 + */
 309.247 +
 309.248 +int close_file (FILE *stream)
 309.249 +{
 309.250 +  int ret;
 309.251 +  char *s = stream->_tmpfname;
 309.252 +  stream->_tmpfname = NIL;	/* just in case fclose() tries to delete it */
 309.253 +  ret = fclose (stream);	/* close the file */
 309.254 +  if (s) {			/* was there a _tmpfname? */
 309.255 +    unlink (s);			/* yup, delete it */
 309.256 +    fs_give ((void **) &s);	/* and flush the name */
 309.257 +  }
 309.258 +  return ret;
 309.259 +}
 309.260 +
 309.261 +/* Get password from console
 309.262 + * Accepts: prompt
 309.263 + * Returns: password
 309.264 + */
 309.265 +
 309.266 +#define PWDLEN 128		/* used by Linux */
 309.267 +
 309.268 +char *getpass (const char *prompt)
 309.269 +{
 309.270 +  static char pwd[PWDLEN];
 309.271 +  int ch,i,done;
 309.272 +  fputs (prompt,stderr);	/* output prompt */
 309.273 +  for (i = done = 0; !done; ) switch (ch = _getch()) {
 309.274 +  case 0x03:			/* CTRL/C stops program */
 309.275 +    _exit (1);
 309.276 +  case '\b':			/* BACKSPACE erase previous character */
 309.277 +    if (i) pwd[--i] = '\0';
 309.278 +    break;
 309.279 +  case '\n': case '\r':		/* CR or LF terminates string */
 309.280 +    done = 1;
 309.281 +    break;
 309.282 +  default:			/* any other character is a pwd char */
 309.283 +    if (i < (PWDLEN - 1)) pwd[i++] = ch;
 309.284 +    break;
 309.285 +  }
 309.286 +  pwd[i] = '\0';		/* tie off string with null */
 309.287 +  putchar ('\n');		/* echo newline */
 309.288 +  return pwd;
 309.289 +}
   310.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   310.2 +++ b/src/osdep/nt/yunchan.h	Mon Sep 14 15:17:45 2009 +0900
   310.3 @@ -0,0 +1,86 @@
   310.4 +/* ========================================================================
   310.5 + * Copyright 1988-2006 University of Washington
   310.6 + *
   310.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   310.8 + * you may not use this file except in compliance with the License.
   310.9 + * You may obtain a copy of the License at
  310.10 + *
  310.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  310.12 + *
  310.13 + * 
  310.14 + * ========================================================================
  310.15 + */
  310.16 +
  310.17 +/*
  310.18 + * Program:	Unix compatibility routines
  310.19 + *
  310.20 + * Author:	Mark Crispin
  310.21 + *		Networks and Distributed Computing
  310.22 + *		Computing & Communications
  310.23 + *		University of Washington
  310.24 + *		Administration Building, AG-44
  310.25 + *		Seattle, WA  98195
  310.26 + *		Internet: MRC@CAC.Washington.EDU
  310.27 + *
  310.28 + * Date:	14 September 1996
  310.29 + * Last Edited:	30 August 2006
  310.30 + */
  310.31 +
  310.32 +
  310.33 +/*				DEDICATION
  310.34 + *
  310.35 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  310.36 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  310.37 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  310.38 + * a two-month bout with cirrhosis of the liver.
  310.39 + *
  310.40 + *  He was a dear friend, and I miss him terribly.
  310.41 + *
  310.42 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  310.43 + */
  310.44 +
  310.45 +/* For flock() emulation */
  310.46 +
  310.47 +#define LOCK_SH 1
  310.48 +#define LOCK_EX 2
  310.49 +#define LOCK_NB 4
  310.50 +#define LOCK_UN 8
  310.51 +
  310.52 +
  310.53 +/* syslog() emulation */
  310.54 +
  310.55 +#define LOG_MAIL	(2<<3)	/* mail system */
  310.56 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  310.57 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  310.58 +#define LOG_EMERG	0	/* system is unusable */
  310.59 +#define LOG_ALERT	1	/* action must be taken immediately */
  310.60 +#define LOG_CRIT	2	/* critical conditions */
  310.61 +#define LOG_ERR		3	/* error conditions */
  310.62 +#define LOG_WARNING	4	/* warning conditions */
  310.63 +#define LOG_NOTICE	5	/* normal but signification condition */
  310.64 +#define LOG_INFO	6	/* informational */
  310.65 +#define LOG_DEBUG	7	/* debug-level messages */
  310.66 +#define LOG_PID		0x01	/* log the pid with each message */
  310.67 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  310.68 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  310.69 +#define LOG_NDELAY	0x08	/* don't delay open */
  310.70 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  310.71 +
  310.72 +#define tmpfile create_tempfile
  310.73 +#define fclose close_file
  310.74 +#define fsync _commit
  310.75 +#define ftruncate chsize
  310.76 +#define gethostid clock
  310.77 +#define sleep(x) Sleep (1000 * x)
  310.78 +
  310.79 +
  310.80 +long alarm (long seconds);
  310.81 +int flock (int fd,int op);
  310.82 +void openlog (const char *ident,int logopt,int facility);
  310.83 +void syslog (int priority,const char *message,...);
  310.84 +unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
  310.85 +			    unsigned long srcl);
  310.86 +unsigned long unix_crlflen (STRING *s);
  310.87 +FILE *create_tempfile (void);
  310.88 +int close_file (FILE *stream);
  310.89 +char *getpass (const char *prompt);
   311.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   311.2 +++ b/src/osdep/os2/auths.cmd	Mon Sep 14 15:17:45 2009 +0900
   311.3 @@ -0,0 +1,48 @@
   311.4 +/* rexx */
   311.5 +/* ========================================================================
   311.6 + * Copyright 1988-2006 University of Washington
   311.7 + *
   311.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   311.9 + * you may not use this file except in compliance with the License.
  311.10 + * You may obtain a copy of the License at
  311.11 + *
  311.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  311.13 + *
  311.14 + * 
  311.15 + * ========================================================================
  311.16 + */
  311.17 +/*
  311.18 + * Program:	Authenticator Linkage Generator for OS/2
  311.19 + *
  311.20 + * Author:	Mark Crispin
  311.21 + *		Networks and Distributed Computing
  311.22 + *		Computing & Communications
  311.23 + *		University of Washington
  311.24 + *		Administration Building, AG-44
  311.25 + *		Seattle, WA  98195
  311.26 + *		Internet: MRC@CAC.Washington.EDU
  311.27 + *
  311.28 + * Date:	10 June 1999
  311.29 + * Last Edited:	30 August 2006
  311.30 + */
  311.31 +'@echo off'
  311.32 +/* Erase old authenticators list */
  311.33 +'if exist auths.c del auths.c'
  311.34 +parse arg args
  311.35 +n=words(args)
  311.36 +a_file='auths.c'
  311.37 +c_file='linkage.c'
  311.38 +h_file='linkage.h'
  311.39 +call stream a_file, 'C', 'open write'
  311.40 +call stream c_file, 'C', 'open write'
  311.41 +call stream h_file, 'C', 'open write'
  311.42 +do i=1 to n
  311.43 +  arg=word(args,i)
  311.44 +  call lineout a_file, '#include "auth_'arg'.c"'
  311.45 +  call lineout h_file, 'extern AUTHENTICATOR auth_'arg';'
  311.46 +  call lineout c_file, '  auth_link (&auth_'arg');	/* link in the 'arg' authenticator */'
  311.47 +  end
  311.48 +call stream h_file, 'C', 'close'
  311.49 +call stream c_file, 'C', 'close'
  311.50 +call stream a_file, 'C', 'close'
  311.51 +exit 0
   312.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   312.2 +++ b/src/osdep/os2/drivers.cmd	Mon Sep 14 15:17:45 2009 +0900
   312.3 @@ -0,0 +1,45 @@
   312.4 +/* rexx */
   312.5 +/* ========================================================================
   312.6 + * Copyright 1988-2006 University of Washington
   312.7 + *
   312.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   312.9 + * you may not use this file except in compliance with the License.
  312.10 + * You may obtain a copy of the License at
  312.11 + *
  312.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  312.13 + *
  312.14 + * 
  312.15 + * ========================================================================
  312.16 + */
  312.17 +/*
  312.18 + * Program:	Authenticator Linkage Generator for OS/2
  312.19 + *
  312.20 + * Author:	Mark Crispin
  312.21 + *		Networks and Distributed Computing
  312.22 + *		Computing & Communications
  312.23 + *		University of Washington
  312.24 + *		Administration Building, AG-44
  312.25 + *		Seattle, WA  98195
  312.26 + *		Internet: MRC@CAC.Washington.EDU
  312.27 + *
  312.28 + * Date:	10 June 1999
  312.29 + * Last Edited:	30 August 2006
  312.30 + */
  312.31 +'@echo off'
  312.32 +/* Erase old authenticators list */
  312.33 +'if exist linkage.h del linkage.h'
  312.34 +'if exist linkage.c del linkage.c'
  312.35 +parse arg args
  312.36 +n=words(args)
  312.37 +c_file='linkage.c'
  312.38 +h_file='linkage.h'
  312.39 +call stream c_file, 'C', 'open write'
  312.40 +call stream h_file, 'C', 'open write'
  312.41 +do i=1 to n
  312.42 +  arg=word(args,i)
  312.43 +  call lineout h_file, 'extern DRIVER 'arg'driver;'
  312.44 +  call lineout c_file, '  mail_link (&'arg'driver);	/* link in the 'arg' driver */'
  312.45 +  end
  312.46 +call stream h_file, 'C', 'close'
  312.47 +call stream c_file, 'C', 'close'
  312.48 +exit 0
   313.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   313.2 +++ b/src/osdep/os2/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   313.3 @@ -0,0 +1,43 @@
   313.4 +/* ========================================================================
   313.5 + * Copyright 1988-2006 University of Washington
   313.6 + *
   313.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   313.8 + * you may not use this file except in compliance with the License.
   313.9 + * You may obtain a copy of the License at
  313.10 + *
  313.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  313.12 + *
  313.13 + * 
  313.14 + * ========================================================================
  313.15 + */
  313.16 +
  313.17 +/*
  313.18 + * Program:	Dummy routines
  313.19 + *
  313.20 + * Author:	Mark Crispin
  313.21 + *		Networks and Distributed Computing
  313.22 + *		Computing & Communications
  313.23 + *		University of Washington
  313.24 + *		Administration Building, AG-44
  313.25 + *		Seattle, WA  98195
  313.26 + *		Internet: MRC@CAC.Washington.EDU
  313.27 + *
  313.28 + * Date:	9 May 1991
  313.29 + * Last Edited:	30 August 2006
  313.30 + */
  313.31 +
  313.32 +/* Exported function prototypes */
  313.33 +
  313.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  313.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  313.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  313.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  313.38 +		    unsigned long csiz,unsigned long fsiz);
  313.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  313.40 +			  unsigned long fsiz);
  313.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  313.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  313.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  313.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  313.45 +char *dummy_file (char *dst,char *name);
  313.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   314.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   314.2 +++ b/src/osdep/os2/dummyos2.c	Mon Sep 14 15:17:45 2009 +0900
   314.3 @@ -0,0 +1,714 @@
   314.4 +/* ========================================================================
   314.5 + * Copyright 1988-2006 University of Washington
   314.6 + *
   314.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   314.8 + * you may not use this file except in compliance with the License.
   314.9 + * You may obtain a copy of the License at
  314.10 + *
  314.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  314.12 + *
  314.13 + * 
  314.14 + * ========================================================================
  314.15 + */
  314.16 +
  314.17 +/*
  314.18 + * Program:	Dummy routines for OS2
  314.19 + *
  314.20 + * Author:	Mark Crispin
  314.21 + *		Networks and Distributed Computing
  314.22 + *		Computing & Communications
  314.23 + *		University of Washington
  314.24 + *		Administration Building, AG-44
  314.25 + *		Seattle, WA  98195
  314.26 + *		Internet: MRC@CAC.Washington.EDU
  314.27 + *
  314.28 + * Date:	24 May 1993
  314.29 + * Last Edited:	30 August 2006
  314.30 + */
  314.31 +
  314.32 +/* Thanks to Nicholas Sheppard for the original version */
  314.33 +
  314.34 +
  314.35 +#include <ctype.h>
  314.36 +#include <stdio.h>
  314.37 +#include <errno.h>
  314.38 +#include <sys/types.h>
  314.39 +#include <dirent.h>
  314.40 +#include <pwd.h>
  314.41 +#include <sys/stat.h>
  314.42 +#include <io.h>
  314.43 +#include <fcntl.h>
  314.44 +#include <os2.h>
  314.45 +#undef ADDRESS
  314.46 +#include "mail.h"
  314.47 +#include "osdep.h"
  314.48 +#include "misc.h"
  314.49 +#include "dummy.h"
  314.50 +
  314.51 +/* Function prototypes */
  314.52 +
  314.53 +DRIVER *dummy_valid (char *name);
  314.54 +void *dummy_parameters (long function,void *value);
  314.55 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
  314.56 +		      long level);
  314.57 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
  314.58 +		   long attributes,char *contents);
  314.59 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
  314.60 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  314.61 +void dummy_close (MAILSTREAM *stream,long options);
  314.62 +long dummy_ping (MAILSTREAM *stream);
  314.63 +void dummy_check (MAILSTREAM *stream);
  314.64 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  314.65 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  314.66 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  314.67 +
  314.68 +/* Dummy routines */
  314.69 +
  314.70 +
  314.71 +/* Driver dispatch used by MAIL */
  314.72 +
  314.73 +DRIVER dummydriver = {
  314.74 +  "dummy",			/* driver name */
  314.75 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  314.76 +  (DRIVER *) NIL,		/* next driver */
  314.77 +  dummy_valid,			/* mailbox is valid for us */
  314.78 +  dummy_parameters,		/* manipulate parameters */
  314.79 +  dummy_scan,			/* scan mailboxes */
  314.80 +  dummy_list,			/* list mailboxes */
  314.81 +  dummy_lsub,			/* list subscribed mailboxes */
  314.82 +  dummy_subscribe,		/* subscribe to mailbox */
  314.83 +  NIL,				/* unsubscribe from mailbox */
  314.84 +  dummy_create,			/* create mailbox */
  314.85 +  dummy_delete,			/* delete mailbox */
  314.86 +  dummy_rename,			/* rename mailbox */
  314.87 +  mail_status_default,		/* status of mailbox */
  314.88 +  dummy_open,			/* open mailbox */
  314.89 +  dummy_close,			/* close mailbox */
  314.90 +  NIL,				/* fetch message "fast" attributes */
  314.91 +  NIL,				/* fetch message flags */
  314.92 +  NIL,				/* fetch overview */
  314.93 +  NIL,				/* fetch message structure */
  314.94 +  NIL,				/* fetch header */
  314.95 +  NIL,				/* fetch text */
  314.96 +  NIL,				/* fetch message data */
  314.97 +  NIL,				/* unique identifier */
  314.98 +  NIL,				/* message number from UID */
  314.99 +  NIL,				/* modify flags */
 314.100 +  NIL,				/* per-message modify flags */
 314.101 +  NIL,				/* search for message based on criteria */
 314.102 +  NIL,				/* sort messages */
 314.103 +  NIL,				/* thread messages */
 314.104 +  dummy_ping,			/* ping mailbox to see if still alive */
 314.105 +  dummy_check,			/* check for new messages */
 314.106 +  dummy_expunge,		/* expunge deleted messages */
 314.107 +  dummy_copy,			/* copy messages to another mailbox */
 314.108 +  dummy_append,			/* append string message to mailbox */
 314.109 +  NIL				/* garbage collect stream */
 314.110 +};
 314.111 +
 314.112 +
 314.113 +				/* prototype stream */
 314.114 +MAILSTREAM dummyproto = {&dummydriver};
 314.115 +
 314.116 +/* Dummy validate mailbox
 314.117 + * Accepts: mailbox name
 314.118 + * Returns: our driver if name is valid, NIL otherwise
 314.119 + */
 314.120 +
 314.121 +DRIVER *dummy_valid (char *name)
 314.122 +{
 314.123 +  char *s,*t,tmp[MAILTMPLEN];
 314.124 +  struct stat sbuf;
 314.125 +				/* must be valid local mailbox */
 314.126 +  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
 314.127 +				/* indeterminate INBOX */
 314.128 +    if (!*s) return &dummydriver;
 314.129 +				/* remove trailing \ */
 314.130 +    if ((t = strrchr (s,'\\')) && !t[1]) *t = '\0';
 314.131 +    if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
 314.132 +    case S_IFREG:		/* file */
 314.133 +    case S_IFDIR:		/* future use */
 314.134 +      return &dummydriver;
 314.135 +    }
 314.136 +  }
 314.137 +  return NIL;
 314.138 +}
 314.139 +
 314.140 +
 314.141 +/* Dummy manipulate driver parameters
 314.142 + * Accepts: function code
 314.143 + *	    function-dependent value
 314.144 + * Returns: function-dependent return value
 314.145 + */
 314.146 +
 314.147 +void *dummy_parameters (long function,void *value)
 314.148 +{
 314.149 +  return NIL;
 314.150 +}
 314.151 +
 314.152 +/* Dummy scan mailboxes
 314.153 + * Accepts: mail stream
 314.154 + *	    reference
 314.155 + *	    pattern to search
 314.156 + *	    string to scan
 314.157 + */
 314.158 +
 314.159 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 314.160 +{
 314.161 +  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
 314.162 +  long i = 0;
 314.163 +  if (!pat || !*pat) {		/* empty pattern? */
 314.164 +    if (dummy_canonicalize (test,ref,"*")) {
 314.165 +				/* tie off name at root */
 314.166 +      if (s = strchr (test,'\\')) *++s = '\0';
 314.167 +      else test[0] = '\0';
 314.168 +      dummy_listed (stream,'\\',test,LATT_NOSELECT,NIL);
 314.169 +    }
 314.170 +  }
 314.171 +				/* get canonical form of name */
 314.172 +  else if (dummy_canonicalize (test,ref,pat)) {
 314.173 +				/* found any wildcards? */
 314.174 +    if (s = strpbrk (test,"%*")) {
 314.175 +				/* yes, copy name up to that point */
 314.176 +      strncpy (file,test,(size_t) (i = s - test));
 314.177 +      file[i] = '\0';		/* tie off */
 314.178 +    }
 314.179 +    else strcpy (file,test);	/* use just that name then */
 314.180 +				/* find directory name */
 314.181 +    if (s = strrchr (file,'\\')) {
 314.182 +      *++s = '\0';		/* found, tie off at that point */
 314.183 +      s = file;
 314.184 +    }
 314.185 +				/* silly case */
 314.186 +    else if (file[0] == '#') s = file;
 314.187 +				/* do the work */
 314.188 +    dummy_list_work (stream,s,test,contents,0);
 314.189 +    if (pmatch ("INBOX",test))	/* always an INBOX */
 314.190 +      dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
 314.191 +  }
 314.192 +}
 314.193 +
 314.194 +/* Dummy list mailboxes
 314.195 + * Accepts: mail stream
 314.196 + *	    reference
 314.197 + *	    pattern to search
 314.198 + */
 314.199 +
 314.200 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 314.201 +{
 314.202 +  dummy_scan (stream,ref,pat,NIL);
 314.203 +}
 314.204 +
 314.205 +
 314.206 +/* Dummy list subscribed mailboxes
 314.207 + * Accepts: mail stream
 314.208 + *	    reference
 314.209 + *	    pattern to search
 314.210 + */
 314.211 +
 314.212 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 314.213 +{
 314.214 +  void *sdb = NIL;
 314.215 +  char *s,*t,test[MAILTMPLEN];
 314.216 +  int showuppers = pat[strlen (pat) - 1] == '%';
 314.217 +				/* get canonical form of name */
 314.218 +  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
 314.219 +    if (*s != '{') {
 314.220 +      if (pmatch_full (s,test,'\\')) {
 314.221 +	if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
 314.222 +	else mm_lsub (stream,'\\',s,NIL);
 314.223 +      }
 314.224 +      else while (showuppers && (t = strrchr (s,'\\'))) {
 314.225 +	*t = '\0';		/* tie off the name */
 314.226 +	if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
 314.227 +      }
 314.228 +    }
 314.229 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 314.230 +}
 314.231 +
 314.232 +
 314.233 +/* Dummy subscribe to mailbox
 314.234 + * Accepts: mail stream
 314.235 + *	    mailbox to add to subscription list
 314.236 + * Returns: T on success, NIL on failure
 314.237 + */
 314.238 +
 314.239 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
 314.240 +{
 314.241 +  char *s,tmp[MAILTMPLEN];
 314.242 +  struct stat sbuf;
 314.243 +				/* must be valid local mailbox */
 314.244 +  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
 314.245 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
 314.246 +  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
 314.247 +  mm_log (tmp,ERROR);
 314.248 +  return NIL;
 314.249 +}
 314.250 +
 314.251 +/* Dummy list mailboxes worker routine
 314.252 + * Accepts: mail stream
 314.253 + *	    directory name to search
 314.254 + *	    search pattern
 314.255 + *	    string to scan
 314.256 + *	    search level
 314.257 + */
 314.258 +
 314.259 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
 314.260 +		      long level)
 314.261 +{
 314.262 +  unsigned long i = 1;
 314.263 +  FILEFINDBUF3 f;
 314.264 +  HDIR hd = HDIR_CREATE;
 314.265 +  struct stat sbuf;
 314.266 +  char tmp[MAILTMPLEN];
 314.267 +				/* punt if bogus name */
 314.268 +  if (!mailboxdir (tmp,dir,NIL)) return;
 314.269 +				/* make directory wildcard */
 314.270 +  strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*");
 314.271 +				/* do nothing if can't open directory */
 314.272 +  if (!DosFindFirst (tmp,&hd,FILE_NORMAL,&f,sizeof (f),&i,FIL_STANDARD)) {
 314.273 +				/* list it if not at top-level */
 314.274 +    if (!level && dir && pmatch_full (dir,pat,'\\'))
 314.275 +      dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
 314.276 +				/* scan directory */
 314.277 +    if (!dir || dir[strlen (dir) -1] == '\\') do {
 314.278 +      if (((f.name[0] != '.') ||
 314.279 +	   (f.name[1] && ((f.name[1] != '.') || f.name[2]))) &&
 314.280 +	  (strlen (f.name) <= NETMAXMBX)) {
 314.281 +				/* see if name is useful */
 314.282 +	if (dir) sprintf (tmp,"%s%s",dir,f.name);
 314.283 +	else strcpy (tmp,f.name);
 314.284 +				/* make sure useful and can get info */
 314.285 +	if ((pmatch_full (tmp,pat,'\\') ||
 314.286 +	     pmatch_full (strcat (tmp,"\\"),pat,'\\') ||
 314.287 +	     dmatch (tmp,pat,'\\')) &&
 314.288 +	    mailboxdir (tmp,dir,f.name) && tmp[0] && !stat (tmp,&sbuf)) {
 314.289 +				/* now make name we'd return */
 314.290 +	  if (dir) sprintf (tmp,"%s%s",dir,f.name);
 314.291 +	  else strcpy (tmp,f.name);
 314.292 +				/* only interested in file type */
 314.293 +	  switch (sbuf.st_mode & S_IFMT) {
 314.294 +	  case S_IFDIR:		/* directory? */
 314.295 +	    if (pmatch_full (tmp,pat,'\\')) {
 314.296 +	      if (!dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))break;
 314.297 +	      strcat (tmp,"\\");/* set up for dmatch call */
 314.298 +	    }
 314.299 +				/* try again with trailing \ */
 314.300 +	    else if (pmatch_full (strcat (tmp,"\\"),pat,'\\') &&
 314.301 +		     !dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))
 314.302 +	      break;
 314.303 +	    if (dmatch (tmp,pat,'\\') &&
 314.304 +		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 314.305 +	      dummy_list_work (stream,tmp,pat,contents,level+1);
 314.306 +	    break;
 314.307 +	  case S_IFREG:		/* ordinary name */
 314.308 +	    if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
 314.309 +	      dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
 314.310 +	    break;
 314.311 +	  }
 314.312 +	}
 314.313 +      }
 314.314 +      i = 1;
 314.315 +    } while (!DosFindNext (h,&f,sizeof (f),&i));
 314.316 +  }
 314.317 +}
 314.318 +
 314.319 +/* Mailbox found
 314.320 + * Accepts: hierarchy delimiter
 314.321 + *	    mailbox name
 314.322 + *	    attributes
 314.323 + *	    contents to search before calling mm_list()
 314.324 + * Returns: T, always
 314.325 + */
 314.326 +
 314.327 +#define BUFSIZE 4*MAILTMPLEN
 314.328 +
 314.329 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
 314.330 +		   long attributes,char *contents)
 314.331 +{
 314.332 +  struct stat sbuf;
 314.333 +  int fd;
 314.334 +  long csiz,ssiz,bsiz;
 314.335 +  char *s,*buf,tmp[MAILTMPLEN];
 314.336 +  if (contents) {		/* want to search contents? */
 314.337 +				/* forget it if can't select or open */
 314.338 +    if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
 314.339 +	!(s = dummy_file (tmp,name)) || stat (s,&sbuf) ||
 314.340 +	(csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0))
 314.341 +      return T;
 314.342 +				/* get buffer including slop */    
 314.343 +    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
 314.344 +    memset (buf,'\0',ssiz);	/* no slop area the first time */
 314.345 +    while (sbuf.st_size) {	/* until end of file */
 314.346 +      read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
 314.347 +      if (search ((unsigned char *) buf,bsiz+ssiz,
 314.348 +		  (unsigned char *) contents,csiz)) break;
 314.349 +      memcpy (buf,buf+BUFSIZE,ssiz);
 314.350 +      sbuf.st_size -= bsiz;	/* note that we read that much */
 314.351 +    }
 314.352 +    fs_give ((void **) &buf);	/* flush buffer */
 314.353 +    close (fd);			/* finished with file */
 314.354 +    if (!sbuf.st_size) return T;/* not found */
 314.355 +  }
 314.356 +				/* notify main program */
 314.357 +  mm_list (stream,delimiter,name,attributes);
 314.358 +  return T;
 314.359 +}
 314.360 +
 314.361 +/* Dummy create mailbox
 314.362 + * Accepts: mail stream
 314.363 + *	    mailbox name to create
 314.364 + * Returns: T on success, NIL on failure
 314.365 + */
 314.366 +
 314.367 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 314.368 +{
 314.369 +  char tmp[MAILTMPLEN];
 314.370 +  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox))
 314.371 +    return dummy_create_path (stream,tmp,NIL);
 314.372 +  sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 314.373 +  mm_log (tmp,ERROR);
 314.374 +  return NIL;
 314.375 +}
 314.376 +
 314.377 +
 314.378 +/* Dummy create path
 314.379 + * Accepts: mail stream
 314.380 + *	    path name to create
 314.381 + *	    directory mode
 314.382 + * Returns: T on success, NIL on failure
 314.383 + */
 314.384 +
 314.385 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
 314.386 +{
 314.387 +  struct stat sbuf;
 314.388 +  char c,*s,tmp[MAILTMPLEN];
 314.389 +  int fd;
 314.390 +  long ret = NIL;
 314.391 +  char *t = strrchr (path,'\\');
 314.392 +  char *pt = (path[1] == ':') ? path + 2 : path;
 314.393 +  int wantdir = t && !t[1];
 314.394 +  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
 314.395 +				/* found superior to this name? */
 314.396 +  if ((s = strrchr (pt,'\\')) && (s != pt)) {
 314.397 +    strncpy (tmp,path,(size_t) (s - path));
 314.398 +    tmp[s - path] = '\0';	/* make directory name for stat */
 314.399 +    c = *++s;			/* tie off in case need to recurse */
 314.400 +    *s = '\0';
 314.401 +				/* name doesn't exist, create it */
 314.402 +    if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 314.403 +	!dummy_create_path (stream,path,dirmode)) return NIL;
 314.404 +    *s = c;			/* restore full name */
 314.405 +  }
 314.406 +  if (wantdir) {		/* want to create directory? */
 314.407 +    ret = !mkdir (path);
 314.408 +    *t = '\\';			/* restore directory delimiter */
 314.409 +  }
 314.410 +				/* create file */
 314.411 +  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
 314.412 +    ret = !close (fd);		/* close file */
 314.413 +  if (!ret) {			/* error? */
 314.414 +    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,
 314.415 +	     strerror (errno));
 314.416 +    mm_log (tmp,ERROR);
 314.417 +  }
 314.418 +  return ret;			/* return status */
 314.419 +}
 314.420 +
 314.421 +/* Dummy delete mailbox
 314.422 + * Accepts: mail stream
 314.423 + *	    mailbox name to delete
 314.424 + * Returns: T on success, NIL on failure
 314.425 + */
 314.426 +
 314.427 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 314.428 +{
 314.429 +  struct stat sbuf;
 314.430 +  char *s,tmp[MAILTMPLEN];
 314.431 +  if (!(s = dummy_file (tmp,mailbox))) {
 314.432 +    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
 314.433 +    mm_log (tmp,ERROR);
 314.434 +  }
 314.435 +				/* no trailing \ */
 314.436 +  if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
 314.437 +  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
 314.438 +      rmdir (tmp) : unlink (tmp)) {
 314.439 +    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
 314.440 +    mm_log (tmp,ERROR);
 314.441 +    return NIL;
 314.442 +  }
 314.443 +  return T;			/* return success */
 314.444 +}
 314.445 +
 314.446 +
 314.447 +/* Mail rename mailbox
 314.448 + * Accepts: mail stream
 314.449 + *	    old mailbox name
 314.450 + *	    new mailbox name
 314.451 + * Returns: T on success, NIL on failure
 314.452 + */
 314.453 +
 314.454 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 314.455 +{
 314.456 +  struct stat sbuf;
 314.457 +  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
 314.458 +  long ret = NIL;
 314.459 +				/* no trailing \ allowed */
 314.460 +  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
 314.461 +      ((s = strrchr (s,'\\')) && !s[1])) {
 314.462 +    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
 314.463 +    mm_log (mbx,ERROR);
 314.464 +    return NIL;
 314.465 +  }
 314.466 +				/* found superior to destination name? */
 314.467 +  if (s && (s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) {
 314.468 +    c = s[1];			/* remember character after delimiter */
 314.469 +    *s = s[1] = '\0';		/* tie off name at delimiter */
 314.470 +				/* name doesn't exist, create it */
 314.471 +    if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 314.472 +      *s = '\\';		/* restore delimiter */
 314.473 +      if (!dummy_create (stream,mbx)) return NIL;
 314.474 +    }
 314.475 +    else *s = '\\';		/* restore delimiter */
 314.476 +    s[1] = c;			/* restore character after delimiter */
 314.477 +  }
 314.478 +				/* rename of non-ex INBOX creates dest */
 314.479 +  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
 314.480 +    return dummy_create (NIL,mbx);
 314.481 +  if (rename (oldname,mbx)) {
 314.482 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
 314.483 +	     strerror (errno));
 314.484 +    mm_log (tmp,ERROR);
 314.485 +    return NIL;
 314.486 +  }
 314.487 +  return LONGT;			/* return success */
 314.488 +}
 314.489 +
 314.490 +/* Dummy open
 314.491 + * Accepts: stream to open
 314.492 + * Returns: stream on success, NIL on failure
 314.493 + */
 314.494 +
 314.495 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 314.496 +{
 314.497 +  int fd;
 314.498 +  char err[MAILTMPLEN],tmp[MAILTMPLEN];
 314.499 +  struct stat sbuf;
 314.500 +				/* OP_PROTOTYPE call */
 314.501 +  if (!stream) return &dummyproto;
 314.502 +  err[0] = '\0';		/* no error message yet */
 314.503 +				/* can we open the file? */
 314.504 +  if (!dummy_file (tmp,stream->mailbox))
 314.505 +    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
 314.506 +  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 314.507 +				/* no, error unless INBOX */
 314.508 +    if (compare_cstring (stream->mailbox,"INBOX"))
 314.509 +      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
 314.510 +  }
 314.511 +  else {			/* file had better be empty then */
 314.512 +    fstat (fd,&sbuf);		/* sniff at its size */
 314.513 +    close (fd);
 314.514 +    if (sbuf.st_size)		/* bogus format if non-empty */
 314.515 +      sprintf (err,"%.80s (file %.80s) is not in valid mailbox format",
 314.516 +	       stream->mailbox,tmp);
 314.517 +  }
 314.518 +  if (err[0]) {			/* if an error happened */
 314.519 +    mm_log (err,stream->silent ? WARN : ERROR);
 314.520 +    return NIL;
 314.521 +  }
 314.522 +  else if (!stream->silent) {	/* only if silence not requested */
 314.523 +    mail_exists (stream,0);	/* say there are 0 messages */
 314.524 +    mail_recent (stream,0);	/* and certainly no recent ones! */
 314.525 +    stream->uid_validity = time (0);
 314.526 +  }
 314.527 +  stream->inbox = T;		/* note that it's an INBOX */
 314.528 +  return stream;		/* return success */
 314.529 +}
 314.530 +
 314.531 +
 314.532 +/* Dummy close
 314.533 + * Accepts: MAIL stream
 314.534 + *	    options
 314.535 + */
 314.536 +
 314.537 +void dummy_close (MAILSTREAM *stream,long options)
 314.538 +{
 314.539 +				/* return silently */
 314.540 +}
 314.541 +
 314.542 +/* Dummy ping mailbox
 314.543 + * Accepts: MAIL stream
 314.544 + * Returns: T if stream alive, else NIL
 314.545 + */
 314.546 +
 314.547 +long dummy_ping (MAILSTREAM *stream)
 314.548 +{
 314.549 +  MAILSTREAM *test;
 314.550 +				/* time to do another test? */
 314.551 +  if (time (0) >= ((time_t) (stream->gensym + 30))) {
 314.552 +				/* has mailbox format changed? */
 314.553 +    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
 314.554 +	(test->dtb != stream->dtb) &&
 314.555 +	(test = mail_open (NIL,stream->mailbox,NIL))) {
 314.556 +				/* preserve some resources */
 314.557 +      test->original_mailbox = stream->original_mailbox;
 314.558 +      stream->original_mailbox = NIL;
 314.559 +      test->sparep = stream->sparep;
 314.560 +      stream->sparep = NIL;
 314.561 +      test->sequence = stream->sequence;
 314.562 +      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
 314.563 +		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
 314.564 +			  sizeof (MAILSTREAM)));
 314.565 +				/* swap the streams */
 314.566 +      memcpy (stream,test,sizeof (MAILSTREAM));
 314.567 +      fs_give ((void **) &test);/* flush test now that copied */
 314.568 +				/* make sure application knows */
 314.569 +      mail_exists (stream,stream->recent = stream->nmsgs);
 314.570 +    }
 314.571 +				/* still hasn't changed */
 314.572 +    else stream->gensym = time (0);
 314.573 +  }
 314.574 +  return T;
 314.575 +}
 314.576 +
 314.577 +
 314.578 +/* Dummy check mailbox
 314.579 + * Accepts: MAIL stream
 314.580 + * No-op for readonly files, since read/writer can expunge it from under us!
 314.581 + */
 314.582 +
 314.583 +void dummy_check (MAILSTREAM *stream)
 314.584 +{
 314.585 +  dummy_ping (stream);		/* invoke ping */
 314.586 +}
 314.587 +
 314.588 +
 314.589 +/* Dummy expunge mailbox
 314.590 + * Accepts: MAIL stream
 314.591 + *	    sequence to expunge if non-NIL
 314.592 + *	    expunge options
 314.593 + * Returns: T, always
 314.594 + */
 314.595 +
 314.596 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 314.597 +{
 314.598 +  return LONGT;
 314.599 +}
 314.600 +
 314.601 +/* Dummy copy message(s)
 314.602 + * Accepts: MAIL stream
 314.603 + *	    sequence
 314.604 + *	    destination mailbox
 314.605 + *	    options
 314.606 + * Returns: T if copy successful, else NIL
 314.607 + */
 314.608 +
 314.609 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 314.610 +{
 314.611 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 314.612 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 314.613 +  return NIL;
 314.614 +}
 314.615 +
 314.616 +
 314.617 +/* Dummy append message string
 314.618 + * Accepts: mail stream
 314.619 + *	    destination mailbox
 314.620 + *	    append callback function
 314.621 + *	    data for callback
 314.622 + * Returns: T on success, NIL on failure
 314.623 + */
 314.624 +
 314.625 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 314.626 +{
 314.627 +  struct stat sbuf;
 314.628 +  int fd = -1;
 314.629 +  int e;
 314.630 +  char tmp[MAILTMPLEN];
 314.631 +  MAILSTREAM *ts = default_proto (T);
 314.632 +  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox) &&
 314.633 +      ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
 314.634 +    if ((e = errno) == ENOENT)	/* failed, was it no such file? */
 314.635 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
 314.636 +		 (long) NIL);
 314.637 +    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
 314.638 +    mm_log (tmp,ERROR);		/* pass up error */
 314.639 +    return NIL;			/* always fails */
 314.640 +  }
 314.641 +  if (fd >= 0) {		/* found file? */
 314.642 +    fstat (fd,&sbuf);		/* get its size */
 314.643 +    close (fd);			/* toss out the fd */
 314.644 +    if (sbuf.st_size) ts = NIL;	/* non-empty file? */
 314.645 +  }
 314.646 +  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
 314.647 +  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
 314.648 +  mm_log (tmp,ERROR);
 314.649 +  return NIL;
 314.650 +}
 314.651 +
 314.652 +/* Dummy mail generate file string
 314.653 + * Accepts: temporary buffer to write into
 314.654 + *	    mailbox name string
 314.655 + * Returns: local file string or NIL if failure
 314.656 + */
 314.657 +
 314.658 +char *dummy_file (char *dst,char *name)
 314.659 +{
 314.660 +  char *s = mailboxfile (dst,name);
 314.661 +				/* return our standard inbox */
 314.662 +  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
 314.663 +}
 314.664 +
 314.665 +
 314.666 +/* Dummy canonicalize name
 314.667 + * Accepts: buffer to write name
 314.668 + *	    reference
 314.669 + *	    pattern
 314.670 + * Returns: T if success, NIL if failure
 314.671 + */
 314.672 +
 314.673 +long dummy_canonicalize (char *tmp,char *ref,char *pat)
 314.674 +{
 314.675 +  unsigned long i;
 314.676 +  char *s,dev[4];
 314.677 +				/* initially no device */
 314.678 +  dev[0] = dev[1] = dev[2] = dev[3] = '\0';
 314.679 +  if (ref) switch (*ref) {	/* preliminary reference check */
 314.680 +  case '{':			/* remote names not allowed */
 314.681 +    return NIL;			/* disallowed */
 314.682 +  case '\0':			/* empty reference string */
 314.683 +    break;
 314.684 +  default:			/* all other names */
 314.685 +    if (ref[1] == ':') {	/* start with device name? */
 314.686 +      dev[0] = *ref++; dev[1] = *ref++;
 314.687 +    }
 314.688 +    break;
 314.689 +  }
 314.690 +  if (pat[1] == ':') {		/* device name in pattern? */
 314.691 +    dev[0] = *pat++; dev[1] = *pat++;
 314.692 +    ref = NIL;			/* ignore reference */
 314.693 +  }
 314.694 +  switch (*pat) {
 314.695 +  case '#':			/* namespace names */
 314.696 +    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
 314.697 +    else return NIL;		/* unknown namespace */
 314.698 +    break;
 314.699 +  case '{':			/* remote names not allowed */
 314.700 +    return NIL;
 314.701 +  case '\\':			/* rooted name */
 314.702 +    ref = NIL;			/* ignore reference */
 314.703 +    break;
 314.704 +  }
 314.705 +				/* make sure device names are rooted */
 314.706 +  if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
 314.707 +				/* build name */
 314.708 +  sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
 314.709 +  ucase (tmp);			/* force upper case */
 314.710 +				/* count wildcards */
 314.711 +  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 314.712 +  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
 314.713 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 314.714 +    return NIL;
 314.715 +  }
 314.716 +  return T;
 314.717 +}
   315.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   315.2 +++ b/src/osdep/os2/env_os2.c	Mon Sep 14 15:17:45 2009 +0900
   315.3 @@ -0,0 +1,318 @@
   315.4 +/* ========================================================================
   315.5 + * Copyright 1988-2006 University of Washington
   315.6 + *
   315.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   315.8 + * you may not use this file except in compliance with the License.
   315.9 + * You may obtain a copy of the License at
  315.10 + *
  315.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  315.12 + *
  315.13 + * 
  315.14 + * ========================================================================
  315.15 + */
  315.16 +
  315.17 +/*
  315.18 + * Program:	OS/2 environment routines
  315.19 + *
  315.20 + * Author:	Mark Crispin
  315.21 + *		Networks and Distributed Computing
  315.22 + *		Computing & Communications
  315.23 + *		University of Washington
  315.24 + *		Administration Building, AG-44
  315.25 + *		Seattle, WA  98195
  315.26 + *		Internet: MRC@CAC.Washington.EDU
  315.27 + *
  315.28 + * Date:	1 August 1988
  315.29 + * Last Edited:	30 August 2006
  315.30 + */
  315.31 +
  315.32 +
  315.33 +static char *myLocalHost = NIL;	/* local host name */
  315.34 +static char *myHomeDir = NIL;	/* home directory name */
  315.35 +static char *myNewsrc = NIL;	/* newsrc file name */
  315.36 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  315.37 +
  315.38 +#include "write.c"		/* include safe writing routines */
  315.39 +#include "pmatch.c"		/* include wildcard pattern matcher */
  315.40 +
  315.41 +
  315.42 +/* Get all authenticators */
  315.43 +
  315.44 +#include "auths.c"
  315.45 +
  315.46 +/* Environment manipulate parameters
  315.47 + * Accepts: function code
  315.48 + *	    function-dependent value
  315.49 + * Returns: function-dependent return value
  315.50 + */
  315.51 +
  315.52 +void *env_parameters (long function,void *value)
  315.53 +{
  315.54 +  void *ret = NIL;
  315.55 +  switch ((int) function) {
  315.56 +  case SET_HOMEDIR:
  315.57 +    myHomeDir = cpystr ((char *) value);
  315.58 +  case GET_HOMEDIR:
  315.59 +    ret = (void *) myHomeDir;
  315.60 +    break;
  315.61 +  case SET_LOCALHOST:
  315.62 +    myLocalHost = cpystr ((char *) value);
  315.63 +  case GET_LOCALHOST:
  315.64 +    ret = (void *) myLocalHost;
  315.65 +    break;
  315.66 +  case SET_NEWSRC:
  315.67 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  315.68 +    myNewsrc = cpystr ((char *) value);
  315.69 +  case GET_NEWSRC:
  315.70 +    if (!myNewsrc) {		/* set news file name if not defined */
  315.71 +      char tmp[MAILTMPLEN];
  315.72 +      sprintf (tmp,"%s\\newsrc",myhomedir ());
  315.73 +      myNewsrc = cpystr (tmp);
  315.74 +    }
  315.75 +    ret = (void *) myNewsrc;
  315.76 +    break;
  315.77 +  case SET_DISABLE822TZTEXT:
  315.78 +    no822tztext = value ? T : NIL;
  315.79 +  case GET_DISABLE822TZTEXT:
  315.80 +    ret = (void *) (no822tztext ? VOIDT : NIL);
  315.81 +    break;
  315.82 +  }
  315.83 +  return ret;
  315.84 +}
  315.85 +
  315.86 +/* Write current time
  315.87 + * Accepts: destination string
  315.88 + *	    optional format of day-of-week prefix
  315.89 + *	    format of date and time
  315.90 + *	    flag whether to append symbolic timezone
  315.91 + */
  315.92 +
  315.93 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
  315.94 +{
  315.95 +  time_t tn = time (0);
  315.96 +  struct tm *t = gmtime (&tn);
  315.97 +  int zone = t->tm_hour * 60 + t->tm_min;
  315.98 +  int julian = t->tm_yday;
  315.99 +  t = localtime (&tn);		/* get local time now */
 315.100 +				/* minus UTC minutes since midnight */
 315.101 +  zone = t->tm_hour * 60 + t->tm_min - zone;
 315.102 +  /* julian can be one of:
 315.103 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
 315.104 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
 315.105 +   *    0  local time is same day as UTC, no offset
 315.106 +   *   -1  local time is 1 day behind UTC, offset -24 hours
 315.107 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
 315.108 +   */
 315.109 +  if (julian = t->tm_yday -julian)
 315.110 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
 315.111 +  if (prefix) {			/* want day of week? */
 315.112 +    sprintf (date,prefix,days[t->tm_wday]);
 315.113 +    date += strlen (date);	/* make next sprintf append */
 315.114 +  }
 315.115 +				/* output the date */
 315.116 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 315.117 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
 315.118 +  if (suffix) {			/* append timezone suffix if desired */
 315.119 +    char *tz;
 315.120 +    tzset ();			/* get timezone from TZ environment stuff */
 315.121 +    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
 315.122 +    if (tz && tz[0]) {
 315.123 +      char *s;
 315.124 +      for (s = tz; *s; s++) if (*s & 0x80) return;
 315.125 +      sprintf (date + strlen (date)," (%.50s)",tz);
 315.126 +    }
 315.127 +  }
 315.128 +}
 315.129 +
 315.130 +
 315.131 +/* Write current time in RFC 822 format
 315.132 + * Accepts: destination string
 315.133 + */
 315.134 +
 315.135 +void rfc822_date (char *date)
 315.136 +{
 315.137 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
 315.138 +	   no822tztext ? NIL : T);
 315.139 +}
 315.140 +
 315.141 +
 315.142 +/* Write current time in fixed-width RFC 822 format
 315.143 + * Accepts: destination string
 315.144 + */
 315.145 +
 315.146 +void rfc822_fixed_date (char *date)
 315.147 +{
 315.148 +  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
 315.149 +}
 315.150 +
 315.151 +
 315.152 +/* Write current time in internal format
 315.153 + * Accepts: destination string
 315.154 + */
 315.155 +
 315.156 +void internal_date (char *date)
 315.157 +{
 315.158 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
 315.159 +}
 315.160 +
 315.161 +/* Return my home directory name
 315.162 + * Returns: my home directory name
 315.163 + */
 315.164 +
 315.165 +char *myhomedir ()
 315.166 +{
 315.167 +  if (!myHomeDir) {		/* get home directory name if not yet known */
 315.168 +    char *s;
 315.169 +    if ((s = getenv ("PINEHOME")) || (s = getenv ("HOME")) ||
 315.170 +	(s = getenv ("ETC"))) {
 315.171 +      myHomeDir = cpystr (s);
 315.172 +      while (s = strchr (myHomeDir,'/')) *s = '\\';
 315.173 +      if ((s = strrchr (myHomeDir,'\\')) && !s[1]) *s = '\0';
 315.174 +    }
 315.175 +    else myHomeDir = cpystr ("");
 315.176 +  }
 315.177 +  return myHomeDir;
 315.178 +}
 315.179 +
 315.180 +
 315.181 +/* Return mailbox file name
 315.182 + * Accepts: destination buffer
 315.183 + *	    mailbox name
 315.184 + * Returns: file name
 315.185 + */
 315.186 +
 315.187 +char *mailboxfile (char *dst,char *name)
 315.188 +{
 315.189 +  char *s;
 315.190 +  char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL);
 315.191 +				/* forbid extraneous extensions */
 315.192 +  if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) &&
 315.193 +      ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) ||
 315.194 +       strchr (s+1,'.'))) return NIL;
 315.195 +				/* absolute path name? */
 315.196 +  if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name);
 315.197 +  else sprintf (dst,"%s\\%s",myhomedir (),name);
 315.198 +  if (ext) sprintf (dst + strlen (dst),".%s",ext);
 315.199 +  return dst;
 315.200 +}
 315.201 +
 315.202 +/* Lock file name
 315.203 + * Accepts: return buffer for file name
 315.204 + *	    file name
 315.205 + *	    locking to be placed on file if non-NIL
 315.206 + * Returns: file descriptor of lock or -1 if error
 315.207 + */
 315.208 +
 315.209 +int lockname (char *lock,char *fname,int op)
 315.210 +{
 315.211 +  int ld;
 315.212 +  char c,*s;
 315.213 +  if (!((s = lockdir (lock,getenv ("TEMP"),NIL)) ||
 315.214 +	(s = lockdir (lock,getenv ("TMP"),NIL)) ||
 315.215 +	(s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
 315.216 +				/* C:\TEMP is last resort */
 315.217 +	(s = lockdir (lock,defaultDrive (),"TEMP")))) {
 315.218 +    mm_log ("Unable to find temporary directory",ERROR);
 315.219 +    return -1;
 315.220 +  }
 315.221 +				/* generate file name */
 315.222 +  while (c = *fname++) switch (c) {
 315.223 +  case '/': case '\\': case ':':
 315.224 +    *s++ = '!';			/* convert bad chars to ! */
 315.225 +    break;
 315.226 +  default:
 315.227 +    *s++ = c;
 315.228 +    break;
 315.229 +  }
 315.230 +  *s++ = c;			/* tie off name */
 315.231 +				/* get the lock */
 315.232 +  if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
 315.233 +    flock (ld,op);		/* apply locking function */
 315.234 +  return ld;			/* return locking file descriptor */
 315.235 +}
 315.236 +
 315.237 +/* Build lock directory, check to see if it exists
 315.238 + * Accepts: return buffer for lock directory
 315.239 + *	    first part of possible name
 315.240 + *	    optional second part
 315.241 + * Returns: pointer to end of buffer if buffer has a good name, else NIL
 315.242 + */
 315.243 +
 315.244 +char *lockdir (char *lock,char *first,char *last)
 315.245 +{
 315.246 +  struct stat sbuf;
 315.247 +  char c,*s;
 315.248 +  if (first && *first) {	/* first part must be non-NIL */
 315.249 +				/* copy first part */
 315.250 +    for (s = lock; *first; c = *s++ = *first++);
 315.251 +    if (last && *last) {	/* copy last part if specified */
 315.252 +				/* write trailing \ in case not in first */
 315.253 +      if (c != '\\') *s++ = '\\';
 315.254 +      while (*last) c = *s++ = *last++;
 315.255 +    }
 315.256 +    if (c == '\\') --s;		/* delete trailing \ if any */
 315.257 +    *s = '\0';			/* tie off name at this point */
 315.258 +    return stat (lock,&sbuf) ? NIL : s;
 315.259 +  }
 315.260 +  return NIL;			/* failed */
 315.261 +}
 315.262 +
 315.263 +
 315.264 +/* Unlock file descriptor
 315.265 + * Accepts: file descriptor
 315.266 + *	    lock file name from lockfd()
 315.267 + */
 315.268 +
 315.269 +void unlockfd (int fd,char *lock)
 315.270 +{
 315.271 +  flock (fd,LOCK_UN);		/* unlock it */
 315.272 +  close (fd);			/* close it */
 315.273 +}
 315.274 +
 315.275 +
 315.276 +/* Determine default prototype stream to user
 315.277 + * Accepts: type (NIL for create, T for append)
 315.278 + * Returns: default prototype stream
 315.279 + */
 315.280 +
 315.281 +MAILSTREAM *default_proto (long type)
 315.282 +{
 315.283 +  extern MAILSTREAM DEFAULTPROTO;
 315.284 +  return &DEFAULTPROTO;		/* return default driver's prototype */
 315.285 +}
 315.286 +
 315.287 +/* Global data */
 315.288 +
 315.289 +static unsigned rndm = 0;	/* initial `random' number */
 315.290 +
 315.291 +
 315.292 +/* Return random number
 315.293 + */
 315.294 +
 315.295 +long random ()
 315.296 +{
 315.297 +  if (!rndm) srand (rndm = (unsigned) time (0L));
 315.298 +  return (long) rand ();
 315.299 +}
 315.300 +
 315.301 +
 315.302 +/* Emulator for BSD syslog() routine
 315.303 + * Accepts: priority
 315.304 + *	    message
 315.305 + *	    parameters
 315.306 + */
 315.307 +
 315.308 +void syslog (int priority,const char *message,...)
 315.309 +{
 315.310 +}
 315.311 +
 315.312 +
 315.313 +/* Emulator for BSD openlog() routine
 315.314 + * Accepts: identity
 315.315 + *	    options
 315.316 + *	    facility
 315.317 + */
 315.318 +
 315.319 +void openlog (const char *ident,int logopt,int facility)
 315.320 +{
 315.321 +}
   316.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   316.2 +++ b/src/osdep/os2/env_os2.h	Mon Sep 14 15:17:45 2009 +0900
   316.3 @@ -0,0 +1,62 @@
   316.4 +/* ========================================================================
   316.5 + * Copyright 1988-2006 University of Washington
   316.6 + *
   316.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   316.8 + * you may not use this file except in compliance with the License.
   316.9 + * You may obtain a copy of the License at
  316.10 + *
  316.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  316.12 + *
  316.13 + * 
  316.14 + * ========================================================================
  316.15 + */
  316.16 +
  316.17 +/*
  316.18 + * Program:	OS/2 environment routines
  316.19 + *
  316.20 + * Author:	Mark Crispin
  316.21 + *		Networks and Distributed Computing
  316.22 + *		Computing & Communications
  316.23 + *		University of Washington
  316.24 + *		Administration Building, AG-44
  316.25 + *		Seattle, WA  98195
  316.26 + *		Internet: MRC@CAC.Washington.EDU
  316.27 + *
  316.28 + * Date:	14 March 1996
  316.29 + * Last Edited:	30 August 2006
  316.30 + */
  316.31 +
  316.32 +
  316.33 +/* Function prototypes */
  316.34 +
  316.35 +#include "env.h"
  316.36 +
  316.37 +long random (void);
  316.38 +
  316.39 +
  316.40 +/* syslog() emulation */
  316.41 +
  316.42 +#define LOG_MAIL	(2<<3)	/* mail system */
  316.43 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  316.44 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  316.45 +#define LOG_EMERG	0	/* system is unusable */
  316.46 +#define LOG_ALERT	1	/* action must be taken immediately */
  316.47 +#define LOG_CRIT	2	/* critical conditions */
  316.48 +#define LOG_ERR		3	/* error conditions */
  316.49 +#define LOG_WARNING	4	/* warning conditions */
  316.50 +#define LOG_NOTICE	5	/* normal but signification condition */
  316.51 +#define LOG_INFO	6	/* informational */
  316.52 +#define LOG_DEBUG	7	/* debug-level messages */
  316.53 +#define LOG_PID		0x01	/* log the pid with each message */
  316.54 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  316.55 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  316.56 +#define LOG_NDELAY	0x08	/* don't delay open */
  316.57 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  316.58 +
  316.59 +void openlog (const char *ident,int logopt,int facility);
  316.60 +void syslog (int priority,const char *message,...);
  316.61 +
  316.62 +void rfc822_fixed_date (char *date);
  316.63 +int lockname (char *lock,char *fname,int op);
  316.64 +char *lockdir (char *lock,char *first,char *last);
  316.65 +void unlockfd (int fd,char *lock);
   317.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   317.2 +++ b/src/osdep/os2/fs_os2.c	Mon Sep 14 15:17:45 2009 +0900
   317.3 @@ -0,0 +1,62 @@
   317.4 +/* ========================================================================
   317.5 + * Copyright 1988-2006 University of Washington
   317.6 + *
   317.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   317.8 + * you may not use this file except in compliance with the License.
   317.9 + * You may obtain a copy of the License at
  317.10 + *
  317.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  317.12 + *
  317.13 + * 
  317.14 + * ========================================================================
  317.15 + */
  317.16 +
  317.17 +/*
  317.18 + * Program:	Free storage management routines
  317.19 + *
  317.20 + * Author:	Mark Crispin
  317.21 + *		Networks and Distributed Computing
  317.22 + *		Computing & Communications
  317.23 + *		University of Washington
  317.24 + *		Administration Building, AG-44
  317.25 + *		Seattle, WA  98195
  317.26 + *		Internet: MRC@CAC.Washington.EDU
  317.27 + *
  317.28 + * Date:	1 August 1988
  317.29 + * Last Edited:	30 August 2006
  317.30 + */
  317.31 +
  317.32 +/* Get a block of free storage
  317.33 + * Accepts: size of desired block
  317.34 + * Returns: free storage block
  317.35 + */
  317.36 +
  317.37 +void *fs_get (size_t size)
  317.38 +{
  317.39 +  void *block = malloc (size ? size : (size_t) 1);
  317.40 +  if (!block) fatal ("Out of memory");
  317.41 +  return (block);
  317.42 +}
  317.43 +
  317.44 +
  317.45 +/* Resize a block of free storage
  317.46 + * Accepts: ** pointer to current block
  317.47 + *	    new size
  317.48 + */
  317.49 +
  317.50 +void fs_resize (void **block,size_t size)
  317.51 +{
  317.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  317.53 +    fatal ("Can't resize memory");
  317.54 +}
  317.55 +
  317.56 +
  317.57 +/* Return a block of free storage
  317.58 + * Accepts: ** pointer to free storage block
  317.59 + */
  317.60 +
  317.61 +void fs_give (void **block)
  317.62 +{
  317.63 +  free (*block);
  317.64 +  *block = NIL;
  317.65 +}
   318.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   318.2 +++ b/src/osdep/os2/ftl_os2.c	Mon Sep 14 15:17:45 2009 +0900
   318.3 @@ -0,0 +1,38 @@
   318.4 +/* ========================================================================
   318.5 + * Copyright 1988-2006 University of Washington
   318.6 + *
   318.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   318.8 + * you may not use this file except in compliance with the License.
   318.9 + * You may obtain a copy of the License at
  318.10 + *
  318.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  318.12 + *
  318.13 + * 
  318.14 + * ========================================================================
  318.15 + */
  318.16 +
  318.17 +/*
  318.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  318.19 + *
  318.20 + * Author:	Mark Crispin
  318.21 + *		Networks and Distributed Computing
  318.22 + *		Computing & Communications
  318.23 + *		University of Washington
  318.24 + *		Administration Building, AG-44
  318.25 + *		Seattle, WA  98195
  318.26 + *		Internet: MRC@CAC.Washington.EDU
  318.27 + *
  318.28 + * Date:	1 August 1988
  318.29 + * Last Edited:	30 August 2006
  318.30 + */
  318.31 +
  318.32 +
  318.33 +/* Report a fatal error
  318.34 + * Accepts: string to output
  318.35 + */
  318.36 +
  318.37 +void fatal (char *string)
  318.38 +{
  318.39 +  mm_fatal (string);		/* pass up the string */
  318.40 +  abort ();			/* die horribly */
  318.41 +}
   319.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   319.2 +++ b/src/osdep/os2/makefile.os2	Mon Sep 14 15:17:45 2009 +0900
   319.3 @@ -0,0 +1,109 @@
   319.4 +# ========================================================================
   319.5 +# Copyright 1988-2006 University of Washington
   319.6 +#
   319.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   319.8 +# you may not use this file except in compliance with the License.
   319.9 +# You may obtain a copy of the License at
  319.10 +#
  319.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  319.12 +#
  319.13 +# 
  319.14 +# ========================================================================
  319.15 +
  319.16 +# Program:	Portable C client makefile -- OS/2 version
  319.17 +#
  319.18 +# Author:	Mark Crispin
  319.19 +#		Networks and Distributed Computing
  319.20 +#		Computing & Communications
  319.21 +#		University of Washington
  319.22 +#		Administration Building, AG-44
  319.23 +#		Seattle, WA  98195
  319.24 +#		Internet: MRC@CAC.Washington.EDU
  319.25 +#
  319.26 +# Date:		11 May 1989
  319.27 +# Last Edited:	30 August 2006
  319.28 +
  319.29 +
  319.30 +EXTRAAUTHENTICATORS =
  319.31 +EXTRADRIVERS =
  319.32 +EXTRACFLAGS =
  319.33 +DEFAULTAUTHENTICATORS = ext md5 pla log
  319.34 +DRIVERS = imap nntp pop3 mbx mtx tenex unix
  319.35 +DEFAULTDRIVER =	mbx
  319.36 +CFLAGS = -DOMF -DCHUNKSIZE=65536 -O2 -Zomf $(EXTRACFLAGS)
  319.37 +CC = gcc
  319.38 +CCLIENTLIB = cclient.lib
  319.39 +
  319.40 +all:	$(CCLIENTLIB)
  319.41 +
  319.42 +.c.obj:
  319.43 +	$(CC) $(CFLAGS) -o $@ -c $*.c
  319.44 +
  319.45 +osdep.h: os_os2.h
  319.46 +	copy os_os2.h osdep.h
  319.47 +	drivers.cmd $(EXTRADRIVERS) $(DRIVERS) dummy
  319.48 +	auths.cmd $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
  319.49 +	setproto.cmd $(DEFAULTDRIVER)
  319.50 +
  319.51 +mail.obj: mail.h misc.h osdep.h mail.c
  319.52 +
  319.53 +misc.obj: mail.h misc.h misc.c
  319.54 +
  319.55 +fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
  319.56 +
  319.57 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  319.58 +
  319.59 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  319.60 +
  319.61 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  319.62 +
  319.63 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  319.64 +
  319.65 +smanager.obj: mail.h misc.h smanager.c
  319.66 +
  319.67 +utf8.obj: mail.h misc.h osdep.h utf8.h
  319.68 +
  319.69 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  319.70 +
  319.71 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  319.72 +
  319.73 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  319.74 +
  319.75 +pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
  319.76 +
  319.77 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  319.78 +
  319.79 +os_os2.obj: mail.h osdep.h env_os2.h fs.h ftl.h nl.h tcp.h tcp_os2.h \
  319.80 +	os_os2.c fs_os2.c ftl_os2.c nl_os2.c env_os2.c tcp_os2.c \
  319.81 +	mailfile.h auth_md5.c auth_log.c pmatch.c write.c
  319.82 +
  319.83 +mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
  319.84 +
  319.85 +mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
  319.86 +
  319.87 +tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
  319.88 +
  319.89 +unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
  319.90 +
  319.91 +dummyos2.obj: mail.h dummy.h misc.h osdep.h dummyos2.c
  319.92 +
  319.93 +pseudo.obj: pseudo.h
  319.94 +
  319.95 +$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
  319.96 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
  319.97 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_os2.obj \
  319.98 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
  319.99 +	del $(CCLIENTLIB)
 319.100 +	LIB /NOLOGO /OUT:$(CCLIENTLIB) \
 319.101 +	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
 319.102 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
 319.103 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_os2.obj \
 319.104 +	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
 319.105 +
 319.106 +clean:
 319.107 +	del *.lib *.obj linkage.* osdep.* auths.c *.exe *.exp
 319.108 +
 319.109 +# A monument to a hack of long ago and far away...
 319.110 +
 319.111 +love:
 319.112 +	@echo not war?
   320.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   320.2 +++ b/src/osdep/os2/mbxnt.c	Mon Sep 14 15:17:45 2009 +0900
   320.3 @@ -0,0 +1,1694 @@
   320.4 +/* ========================================================================
   320.5 + * Copyright 1988-2007 University of Washington
   320.6 + *
   320.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   320.8 + * you may not use this file except in compliance with the License.
   320.9 + * You may obtain a copy of the License at
  320.10 + *
  320.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  320.12 + *
  320.13 + * 
  320.14 + * ========================================================================
  320.15 + */
  320.16 +
  320.17 +/*
  320.18 + * Program:	MBX mail routines
  320.19 + *
  320.20 + * Author:	Mark Crispin
  320.21 + *		Networks and Distributed Computing
  320.22 + *		Computing & Communications
  320.23 + *		University of Washington
  320.24 + *		Administration Building, AG-44
  320.25 + *		Seattle, WA  98195
  320.26 + *		Internet: MRC@CAC.Washington.EDU
  320.27 + *
  320.28 + * Date:	3 October 1995
  320.29 + * Last Edited:	28 September 2007
  320.30 + */
  320.31 +
  320.32 +
  320.33 +/*				FILE TIME SEMANTICS
  320.34 + *
  320.35 + * The atime is the last read time of the file.
  320.36 + * The mtime is the last flags update time of the file.
  320.37 + * The ctime is the last write time of the file.
  320.38 + */
  320.39 +
  320.40 +#include <stdio.h>
  320.41 +#include <ctype.h>
  320.42 +#include <errno.h>
  320.43 +extern int errno;		/* just in case */
  320.44 +#include "mail.h"
  320.45 +#include "osdep.h"
  320.46 +#include <fcntl.h>
  320.47 +#include <time.h>
  320.48 +#include <sys/stat.h>
  320.49 +#include <sys/utime.h>
  320.50 +#include "misc.h"
  320.51 +#include "dummy.h"
  320.52 +#include "fdstring.h"
  320.53 +
  320.54 +
  320.55 +/* Build parameters */
  320.56 +
  320.57 +#define HDRSIZE 2048
  320.58 +
  320.59 +/* MBX I/O stream local data */
  320.60 +	
  320.61 +typedef struct mbx_local {
  320.62 +  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
  320.63 +  unsigned int expok: 1;	/* if expunging OK in ping */
  320.64 +  unsigned int expunged : 1;	/* if one or more expunged messages */
  320.65 +  int fd;			/* file descriptor for I/O */
  320.66 +  int ld;			/* lock file descriptor */
  320.67 +  int ffuserflag;		/* first free user flag */
  320.68 +  off_t filesize;		/* file size parsed */
  320.69 +  time_t filetime;		/* last file time */
  320.70 +  time_t lastsnarf;		/* last snarf time */
  320.71 +  unsigned char *buf;		/* temporary buffer */
  320.72 +  unsigned long buflen;		/* current size of temporary buffer */
  320.73 +  char lock[MAILTMPLEN];	/* buffer to write lock name */
  320.74 +} MBXLOCAL;
  320.75 +
  320.76 +
  320.77 +/* Convenient access to local data */
  320.78 +
  320.79 +#define LOCAL ((MBXLOCAL *) stream->local)
  320.80 +
  320.81 +/* Function prototypes */
  320.82 +
  320.83 +DRIVER *mbx_valid (char *name);
  320.84 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
  320.85 +		 long flags);
  320.86 +void *mbx_parameters (long function,void *value);
  320.87 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  320.88 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
  320.89 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  320.90 +long mbx_create (MAILSTREAM *stream,char *mailbox);
  320.91 +long mbx_delete (MAILSTREAM *stream,char *mailbox);
  320.92 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
  320.93 +long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
  320.94 +MAILSTREAM *mbx_open (MAILSTREAM *stream);
  320.95 +void mbx_close (MAILSTREAM *stream,long options);
  320.96 +void mbx_abort (MAILSTREAM *stream);
  320.97 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
  320.98 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
  320.99 +		  long flags);
 320.100 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 320.101 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 320.102 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 320.103 +long mbx_ping (MAILSTREAM *stream);
 320.104 +void mbx_check (MAILSTREAM *stream);
 320.105 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
 320.106 +void mbx_snarf (MAILSTREAM *stream);
 320.107 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 320.108 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 320.109 +
 320.110 +long mbx_parse (MAILSTREAM *stream);
 320.111 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
 320.112 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 320.113 +void mbx_update_header (MAILSTREAM *stream);
 320.114 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
 320.115 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 320.116 +			  unsigned long *size,char **hdr);
 320.117 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
 320.118 +			   long flags);
 320.119 +long mbx_flaglock (MAILSTREAM *stream);
 320.120 +
 320.121 +/* MBX mail routines */
 320.122 +
 320.123 +
 320.124 +/* Driver dispatch used by MAIL */
 320.125 +
 320.126 +DRIVER mbxdriver = {
 320.127 +  "mbx",			/* driver name */
 320.128 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
 320.129 +				/* driver flags */
 320.130 +  (DRIVER *) NIL,		/* next driver */
 320.131 +  mbx_valid,			/* mailbox is valid for us */
 320.132 +  mbx_parameters,		/* manipulate parameters */
 320.133 +  mbx_scan,			/* scan mailboxes */
 320.134 +  mbx_list,			/* list mailboxes */
 320.135 +  mbx_lsub,			/* list subscribed mailboxes */
 320.136 +  NIL,				/* subscribe to mailbox */
 320.137 +  NIL,				/* unsubscribe from mailbox */
 320.138 +  mbx_create,			/* create mailbox */
 320.139 +  mbx_delete,			/* delete mailbox */
 320.140 +  mbx_rename,			/* rename mailbox */
 320.141 +  mail_status_default,		/* status of mailbox */
 320.142 +  mbx_open,			/* open mailbox */
 320.143 +  mbx_close,			/* close mailbox */
 320.144 +  mbx_flags,			/* fetch message "fast" attributes */
 320.145 +  mbx_flags,			/* fetch message flags */
 320.146 +  NIL,				/* fetch overview */
 320.147 +  NIL,				/* fetch message envelopes */
 320.148 +  mbx_header,			/* fetch message header */
 320.149 +  mbx_text,			/* fetch message body */
 320.150 +  NIL,				/* fetch partial message text */
 320.151 +  NIL,				/* unique identifier */
 320.152 +  NIL,				/* message number */
 320.153 +  mbx_flag,			/* modify flags */
 320.154 +  mbx_flagmsg,			/* per-message modify flags */
 320.155 +  NIL,				/* search for message based on criteria */
 320.156 +  NIL,				/* sort messages */
 320.157 +  NIL,				/* thread messages */
 320.158 +  mbx_ping,			/* ping mailbox to see if still alive */
 320.159 +  mbx_check,			/* check for new messages */
 320.160 +  mbx_expunge,			/* expunge deleted messages */
 320.161 +  mbx_copy,			/* copy messages to another mailbox */
 320.162 +  mbx_append,			/* append string message to mailbox */
 320.163 +  NIL				/* garbage collect stream */
 320.164 +};
 320.165 +
 320.166 +				/* prototype stream */
 320.167 +MAILSTREAM mbxproto = {&mbxdriver};
 320.168 +
 320.169 +/* MBX mail validate mailbox
 320.170 + * Accepts: mailbox name
 320.171 + * Returns: our driver if name is valid, NIL otherwise
 320.172 + */
 320.173 +
 320.174 +DRIVER *mbx_valid (char *name)
 320.175 +{
 320.176 +  char tmp[MAILTMPLEN];
 320.177 +  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
 320.178 +  if (fd < 0) return NIL;
 320.179 +  close (fd);			/* don't need the fd now */
 320.180 +  return &mbxdriver;
 320.181 +}
 320.182 +
 320.183 +
 320.184 +/* MBX mail test for valid mailbox
 320.185 + * Accepts: returned stream with valid mailbox keywords
 320.186 + *	    mailbox name
 320.187 + *	    buffer to write file name
 320.188 + *	    returned lock fd
 320.189 + *	    returned lock name
 320.190 + *	    RW flags or NIL for readonly
 320.191 + * Returns: file descriptor if valid, NIL otherwise
 320.192 + */
 320.193 +
 320.194 +#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
 320.195 +#define MBXISVALIDUID 0x2	/* RW, do UID action */
 320.196 +
 320.197 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
 320.198 +		 long flags)
 320.199 +{
 320.200 +  int fd,upd;
 320.201 +  int ret = -1;
 320.202 +  unsigned long i;
 320.203 +  long j,k;
 320.204 +  off_t pos;
 320.205 +  char c,*s,*t,hdr[HDRSIZE];
 320.206 +  struct stat sbuf;
 320.207 +  struct utimbuf times;
 320.208 +  int error = EINVAL;		/* assume invalid argument */
 320.209 +  if (ld) *ld = -1;		/* initially no lock */
 320.210 +				/* if file, get its status */
 320.211 +  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
 320.212 +      ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
 320.213 +      ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
 320.214 +    error = -1;			/* assume bogus format */
 320.215 +    if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) ||
 320.216 +				/* locked, set byte 0 to "*", read rest */
 320.217 +	 ((j < 0) && (lseek (fd,1,L_SET) == 1) &&
 320.218 +	  (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (hdr[0] = '*'))) &&
 320.219 +	(hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') &&
 320.220 +	(hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') &&
 320.221 +	isxdigit (hdr[7]) && isxdigit (hdr[8]) && isxdigit (hdr[9]) &&
 320.222 +	isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) &&
 320.223 +	isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) &&
 320.224 +	isxdigit (hdr[16]) && isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
 320.225 +	isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) &&
 320.226 +	isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) {
 320.227 +      ret = fd;			/* mbx format */
 320.228 +
 320.229 +      if (stream) {		/* lock if making a mini-stream */
 320.230 +	if (flock (fd,LOCK_SH) ||
 320.231 +	    (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1;
 320.232 +				/* reread data now that locked */
 320.233 +	else if (lseek (fd,0,L_SET) ||
 320.234 +		 (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1;
 320.235 +	else {
 320.236 +	  *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0,
 320.237 +					   sizeof (MAILSTREAM));
 320.238 +	  hdr[15] = '\0';	/* tie off UIDVALIDITY */
 320.239 +	  (*stream)->uid_validity = strtoul (hdr+7,NIL,16);
 320.240 +	  hdr[15] = c;		/* now get UIDLAST */
 320.241 +	  (*stream)->uid_last = strtoul (hdr+15,NIL,16);
 320.242 +				/* parse user flags */
 320.243 +	  for (i = 0, s = hdr + 25;
 320.244 +	       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
 320.245 +	       i++, s = t + 2) {
 320.246 +	    *t = '\0';		/* tie off flag */
 320.247 +	    if (strlen (s) <= MAXUSERFLAG)
 320.248 +	      (*stream)->user_flags[i] = cpystr (s);
 320.249 +	  }
 320.250 +				/* make sure have true UIDLAST */
 320.251 +	  if (flags & MBXISVALIDUID) {
 320.252 +	    for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
 320.253 +		 pos += (j + k)) {
 320.254 +				/* read header for this message */
 320.255 +	      lseek (fd,pos,L_SET);
 320.256 +	      if ((j = read (fd,hdr,64)) >= 0) {
 320.257 +		hdr[j] = '\0';
 320.258 +		if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
 320.259 +		  *s = '\0';
 320.260 +		  k = s + 2 - hdr;
 320.261 +		  if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) &&
 320.262 +		      (*s == ';') && (s = strchr (s+1,'-'))) {
 320.263 +				/* get UID if there is any */
 320.264 +		    i = strtoul (++s,&t,16);
 320.265 +		    if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) {
 320.266 +		      if (!i) {
 320.267 +			lseek (fd,pos + s - hdr,L_SET);
 320.268 +			sprintf (hdr,"%08lx",++(*stream)->uid_last);
 320.269 +			write (fd,hdr,8);
 320.270 +			upd = T;
 320.271 +		      }
 320.272 +		      continue;
 320.273 +		    }
 320.274 +		  }
 320.275 +		}
 320.276 +		ret = -1;	/* error, give up */
 320.277 +		*stream = mail_close (*stream);
 320.278 +		pos = sbuf.st_size + 1;
 320.279 +		j = k = 0;
 320.280 +	      }
 320.281 +	    }
 320.282 +
 320.283 +	    if (upd) {	    /* need to update hdr with new UIDLAST? */
 320.284 +	      lseek (fd,15,L_SET);
 320.285 +	      sprintf (hdr,"%08lx",(*stream)->uid_last);
 320.286 +	      write (fd,hdr,8);
 320.287 +	    }
 320.288 +	  }
 320.289 +	}
 320.290 +      }
 320.291 +    }
 320.292 +    if (ret != fd) close (fd);	/* close the file */
 320.293 +    else lseek (fd,0,L_SET);	/* else rewind to start */
 320.294 +				/* \Marked status? */
 320.295 +    if (sbuf.st_ctime > sbuf.st_atime) {
 320.296 +				/* preserve atime and mtime */
 320.297 +      times.actime = sbuf.st_atime;
 320.298 +      times.modtime = sbuf.st_mtime;
 320.299 +      utime (file,&times);	/* set the times */
 320.300 +    }
 320.301 +  }
 320.302 +				/* in case INBOX but not mbx format */
 320.303 +  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
 320.304 +    error = -1;
 320.305 +  if ((ret < 0) && ld && (*ld >= 0)) {
 320.306 +    unlockfd (*ld,lock);
 320.307 +    *ld = -1;
 320.308 +  }
 320.309 +  errno = error;		/* return as last error */
 320.310 +  return ret;			/* return what we should */
 320.311 +}
 320.312 +
 320.313 +/* MBX manipulate driver parameters
 320.314 + * Accepts: function code
 320.315 + *	    function-dependent value
 320.316 + * Returns: function-dependent return value
 320.317 + */
 320.318 +
 320.319 +void *mbx_parameters (long function,void *value)
 320.320 +{
 320.321 +  void *ret = NIL;
 320.322 +  switch ((int) function) {
 320.323 +  case SET_ONETIMEEXPUNGEATPING:
 320.324 +    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
 320.325 +  case GET_ONETIMEEXPUNGEATPING:
 320.326 +    if (value) ret = (void *)
 320.327 +      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
 320.328 +    break;
 320.329 +  }
 320.330 +  return ret;
 320.331 +}
 320.332 +
 320.333 +
 320.334 +/* MBX mail scan mailboxes
 320.335 + * Accepts: mail stream
 320.336 + *	    reference
 320.337 + *	    pattern to search
 320.338 + *	    string to scan
 320.339 + */
 320.340 +
 320.341 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 320.342 +{
 320.343 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 320.344 +}
 320.345 +
 320.346 +
 320.347 +/* MBX mail list mailboxes
 320.348 + * Accepts: mail stream
 320.349 + *	    reference
 320.350 + *	    pattern to search
 320.351 + */
 320.352 +
 320.353 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
 320.354 +{
 320.355 +  if (stream) dummy_list (NIL,ref,pat);
 320.356 +}
 320.357 +
 320.358 +
 320.359 +/* MBX mail list subscribed mailboxes
 320.360 + * Accepts: mail stream
 320.361 + *	    reference
 320.362 + *	    pattern to search
 320.363 + */
 320.364 +
 320.365 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 320.366 +{
 320.367 +  if (stream) dummy_lsub (NIL,ref,pat);
 320.368 +}
 320.369 +
 320.370 +/* MBX mail create mailbox
 320.371 + * Accepts: MAIL stream
 320.372 + *	    mailbox name to create
 320.373 + * Returns: T on success, NIL on failure
 320.374 + */
 320.375 +
 320.376 +long mbx_create (MAILSTREAM *stream,char *mailbox)
 320.377 +{
 320.378 +  char *s,mbx[MAILTMPLEN],tmp[HDRSIZE];
 320.379 +  long ret = NIL;
 320.380 +  int i,fd;
 320.381 +  if (!(s = dummy_file (mbx,mailbox))) {
 320.382 +    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 320.383 +    mm_log (mbx,ERROR);
 320.384 +  }
 320.385 +				/* create underlying file */
 320.386 +  else if (dummy_create (stream,s)) {
 320.387 +				/* done if made directory */
 320.388 +    if ((s = strrchr (s,'\\')) && !s[1]) return T;
 320.389 +    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
 320.390 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 320.391 +      mm_log (tmp,ERROR);
 320.392 +      unlink (mbx);		/* delete the file */
 320.393 +    }
 320.394 +    else {
 320.395 +      memset (tmp,'\0',HDRSIZE);/* initialize header */
 320.396 +      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
 320.397 +	       (unsigned long) time (0));
 320.398 +      for (i = 0; i < NUSERFLAGS; ++i)
 320.399 +	sprintf (s += strlen (s),"%s\015\012",
 320.400 +		 (stream && stream->user_flags[i]) ? stream->user_flags[i] :
 320.401 +		 "");
 320.402 +      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
 320.403 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
 320.404 +		 mbx,strerror (errno));
 320.405 +	mm_log (tmp,ERROR);
 320.406 +	unlink (mbx);		/* delete the file */
 320.407 +      }
 320.408 +      else ret = T;		/* success */
 320.409 +      close (fd);		/* close file */
 320.410 +    }
 320.411 +  }
 320.412 +  return ret;
 320.413 +}
 320.414 +
 320.415 +
 320.416 +/* MBX mail delete mailbox
 320.417 + * Accepts: MAIL stream
 320.418 + *	    mailbox name to delete
 320.419 + * Returns: T on success, NIL on failure
 320.420 + */
 320.421 +
 320.422 +long mbx_delete (MAILSTREAM *stream,char *mailbox)
 320.423 +{
 320.424 +  return mbx_rename (stream,mailbox,NIL);
 320.425 +}
 320.426 +
 320.427 +/* MBX mail rename mailbox
 320.428 + * Accepts: MAIL stream
 320.429 + *	    old mailbox name
 320.430 + *	    new mailbox name (or NIL for delete)
 320.431 + * Returns: T on success, NIL on failure
 320.432 + */
 320.433 +
 320.434 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
 320.435 +{
 320.436 +  long ret = LONGT;
 320.437 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 320.438 +  int fd,ld;
 320.439 +  struct stat sbuf;
 320.440 +  if (!dummy_file (file,old) ||
 320.441 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 320.442 +		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
 320.443 +    sprintf (tmp,newname ?
 320.444 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 320.445 +	     "Can't delete mailbox %.80s: invalid name",
 320.446 +	     old,newname);
 320.447 +    mm_log (tmp,ERROR);
 320.448 +    return NIL;
 320.449 +  }
 320.450 +  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
 320.451 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 320.452 +    mm_log (tmp,ERROR);
 320.453 +    return NIL;
 320.454 +  }
 320.455 +				/* get parse/append permission */
 320.456 +  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
 320.457 +    mm_log ("Unable to lock rename mailbox",ERROR);
 320.458 +    return NIL;
 320.459 +  }
 320.460 +				/* lock out other users */
 320.461 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 320.462 +    close (fd);			/* couldn't lock, give up on it then */
 320.463 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 320.464 +    mm_log (tmp,ERROR);
 320.465 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 320.466 +    return NIL;
 320.467 +  }
 320.468 +
 320.469 +  if (newname) {		/* want rename? */
 320.470 +				/* found superior to destination name? */
 320.471 +    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 320.472 +	((tmp[1] != ':') || (s != tmp + 2))) {
 320.473 +      c = s[1];			/* remember character after delimiter */
 320.474 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 320.475 +				/* name doesn't exist, create it */
 320.476 +      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 320.477 +	*s = '\\';		/* restore delimiter */
 320.478 +	if (!dummy_create (stream,tmp)) ret = NIL;
 320.479 +      }
 320.480 +      else *s = '\\';		/* restore delimiter */
 320.481 +      s[1] = c;			/* restore character after delimiter */
 320.482 +    }
 320.483 +    flock (fd,LOCK_UN);		/* release lock on the file */
 320.484 +    close (fd);			/* pacify NTFS */
 320.485 +				/* rename the file */
 320.486 +    if (ret && rename (file,tmp)) {
 320.487 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 320.488 +	       strerror (errno));
 320.489 +      mm_log (tmp,ERROR);
 320.490 +      ret = NIL;		/* set failure */
 320.491 +    }
 320.492 +  }
 320.493 +  else {
 320.494 +    flock (fd,LOCK_UN);		/* release lock on the file */
 320.495 +    close (fd);			/* pacify NTFS */
 320.496 +    if (unlink (file)) {
 320.497 +      sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 320.498 +      mm_log (tmp,ERROR);
 320.499 +      ret = NIL;		/* set failure */
 320.500 +    }
 320.501 +  }
 320.502 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 320.503 +				/* recreate file if renamed INBOX */
 320.504 +  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
 320.505 +  return ret;			/* return success */
 320.506 +}
 320.507 +
 320.508 +/* MBX mail open
 320.509 + * Accepts: stream to open
 320.510 + * Returns: stream on success, NIL on failure
 320.511 + */
 320.512 +
 320.513 +MAILSTREAM *mbx_open (MAILSTREAM *stream)
 320.514 +{
 320.515 +  int fd,ld;
 320.516 +  short silent;
 320.517 +  char tmp[MAILTMPLEN];
 320.518 +  if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */
 320.519 +  if (stream->local) fatal ("mbx recycle stream");
 320.520 +				/* canonicalize the mailbox name */
 320.521 +  if (!dummy_file (tmp,stream->mailbox)) {
 320.522 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 320.523 +    mm_log (tmp,ERROR);
 320.524 +  }
 320.525 +  if (stream->rdonly ||
 320.526 +      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
 320.527 +    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
 320.528 +      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 320.529 +      mm_log (tmp,ERROR);
 320.530 +      return NIL;
 320.531 +    }
 320.532 +    else if (!stream->rdonly) {	/* got it, but readonly */
 320.533 +      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 320.534 +      stream->rdonly = T;
 320.535 +    }
 320.536 +  }
 320.537 +
 320.538 +  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
 320.539 +  LOCAL->fd = fd;		/* bind the file */
 320.540 +  LOCAL->ld = -1;		/* no flaglock */
 320.541 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 320.542 +  LOCAL->buflen = CHUNKSIZE - 1;
 320.543 +				/* note if an INBOX or not */
 320.544 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 320.545 +  fs_give ((void **) &stream->mailbox);
 320.546 +  stream->mailbox = cpystr (tmp);
 320.547 +				/* get parse/append permission */
 320.548 +  if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) {
 320.549 +    mm_log ("Unable to lock open mailbox",ERROR);
 320.550 +    return NIL;
 320.551 +  }
 320.552 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 320.553 +  unlockfd (ld,tmp);		/* release shared parse permission */
 320.554 +  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
 320.555 +  LOCAL->filetime = 0;		/* time not set up yet */
 320.556 +  LOCAL->expok = LOCAL->flagcheck = NIL;
 320.557 +  stream->sequence++;		/* bump sequence number */
 320.558 +				/* parse mailbox */
 320.559 +  stream->nmsgs = stream->recent = 0;
 320.560 +  silent = stream->silent;	/* defer events */
 320.561 +  stream->silent = T;
 320.562 +  if (mbx_ping (stream) && !stream->nmsgs)
 320.563 +    mm_log ("Mailbox is empty",(long) NIL);
 320.564 +  stream->silent = silent;	/* now notify upper level */
 320.565 +  mail_exists (stream,stream->nmsgs);
 320.566 +  mail_recent (stream,stream->recent);
 320.567 +  if (!LOCAL) return NIL;	/* failure if stream died */
 320.568 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 320.569 +    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 320.570 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 320.571 +  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
 320.572 +    NIL : T;			/* can we create new user flags? */
 320.573 +  return stream;		/* return stream to caller */
 320.574 +}
 320.575 +
 320.576 +/* MBX mail close
 320.577 + * Accepts: MAIL stream
 320.578 + *	    close options
 320.579 + */
 320.580 +
 320.581 +void mbx_close (MAILSTREAM *stream,long options)
 320.582 +{
 320.583 +  if (stream && LOCAL) {	/* only if a file is open */
 320.584 +    int silent = stream->silent;
 320.585 +    stream->silent = T;		/* note this stream is dying */
 320.586 +				/* do an expunge if requested */
 320.587 +    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
 320.588 +    else {			/* otherwise do a checkpoint to purge */
 320.589 +      LOCAL->expok = T;		/*  possible expunged messages */
 320.590 +      mbx_ping (stream);
 320.591 +    }
 320.592 +    stream->silent = silent;	/* restore previous status */
 320.593 +    mbx_abort (stream);
 320.594 +  }
 320.595 +}
 320.596 +
 320.597 +
 320.598 +/* MBX mail abort stream
 320.599 + * Accepts: MAIL stream
 320.600 + */
 320.601 +
 320.602 +void mbx_abort (MAILSTREAM *stream)
 320.603 +{
 320.604 +  if (stream && LOCAL) {	/* only if a file is open */
 320.605 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 320.606 +    close (LOCAL->fd);		/* close the local file */
 320.607 +				/* free local text buffer */
 320.608 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 320.609 +				/* nuke the local data */
 320.610 +    fs_give ((void **) &stream->local);
 320.611 +    stream->dtb = NIL;		/* log out the DTB */
 320.612 +  }
 320.613 +}
 320.614 +
 320.615 +
 320.616 +/* MBX mail fetch flags
 320.617 + * Accepts: MAIL stream
 320.618 + *	    sequence
 320.619 + *	    option flags
 320.620 + * Sniffs at file to see if some other process changed the flags
 320.621 + */
 320.622 +
 320.623 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
 320.624 +{
 320.625 +  MESSAGECACHE *elt;
 320.626 +  unsigned long i;
 320.627 +  if (mbx_ping (stream) &&	/* ping mailbox, get new status for messages */
 320.628 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 320.629 +       mail_sequence (stream,sequence)))
 320.630 +    for (i = 1; i <= stream->nmsgs; i++) 
 320.631 +      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
 320.632 +	mbx_elt (stream,i,NIL);
 320.633 +}
 320.634 +
 320.635 +/* MBX mail fetch message header
 320.636 + * Accepts: MAIL stream
 320.637 + *	    message # to fetch
 320.638 + *	    pointer to returned header text length
 320.639 + *	    option flags
 320.640 + * Returns: message header in RFC822 format
 320.641 + */
 320.642 +
 320.643 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 320.644 +		  long flags)
 320.645 +{
 320.646 +  unsigned long i;
 320.647 +  char *s;
 320.648 +  *length = 0;			/* default to empty */
 320.649 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 320.650 +				/* get header position, possibly header */
 320.651 +  i = mbx_hdrpos (stream,msgno,length,&s);
 320.652 +  if (!s) {			/* mbx_hdrpos() returned header? */
 320.653 +    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
 320.654 +				/* is buffer big enough? */
 320.655 +    if (*length > LOCAL->buflen) {
 320.656 +      fs_give ((void **) &LOCAL->buf);
 320.657 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 320.658 +    }
 320.659 +				/* slurp the data */
 320.660 +    read (LOCAL->fd,s = LOCAL->buf,*length);
 320.661 +  }
 320.662 +  s[*length] = '\0';		/* tie off string */
 320.663 +  return s;
 320.664 +}
 320.665 +
 320.666 +/* MBX mail fetch message text (body only)
 320.667 + * Accepts: MAIL stream
 320.668 + *	    message # to fetch
 320.669 + *	    pointer to returned header text length
 320.670 + *	    option flags
 320.671 + * Returns: T on success, NIL on failure
 320.672 + */
 320.673 +
 320.674 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 320.675 +{
 320.676 +  FDDATA d;
 320.677 +  unsigned long i,j;
 320.678 +  MESSAGECACHE *elt;
 320.679 +				/* UID call "impossible" */
 320.680 +  if (flags & FT_UID) return NIL;
 320.681 +				/* get message status */
 320.682 +  elt = mbx_elt (stream,msgno,NIL);
 320.683 +				/* if message not seen */
 320.684 +  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
 320.685 +    elt->seen = T;		/* mark message as seen */
 320.686 +				/* recalculate status */
 320.687 +    mbx_update_status (stream,msgno,NIL);
 320.688 +    mm_flags (stream,msgno);
 320.689 +				/* update flags */
 320.690 +    mbx_flag (stream,NIL,NIL,NIL);
 320.691 +  }
 320.692 +  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
 320.693 +				/* find header position */
 320.694 +  i = mbx_hdrpos (stream,msgno,&j,NIL);
 320.695 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 320.696 +  d.pos = i + j;
 320.697 +  d.chunk = LOCAL->buf;	/* initial buffer chunk */
 320.698 +  d.chunksize = CHUNKSIZE;
 320.699 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 320.700 +  return LONGT;			/* success */
 320.701 +}
 320.702 +
 320.703 +/* MBX mail modify flags
 320.704 + * Accepts: MAIL stream
 320.705 + *	    sequence
 320.706 + *	    flag(s)
 320.707 + *	    option flags
 320.708 + * Unlocks flag lock
 320.709 + */
 320.710 +
 320.711 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 320.712 +{
 320.713 +  struct utimbuf times;
 320.714 +  struct stat sbuf;
 320.715 +				/* make sure the update takes */
 320.716 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
 320.717 +    fsync (LOCAL->fd);
 320.718 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 320.719 +    times.modtime = LOCAL->filetime = sbuf.st_mtime;
 320.720 +				/* update header */
 320.721 +    if ((LOCAL->ffuserflag < NUSERFLAGS) &&
 320.722 +	stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream);
 320.723 +    times.actime = time (0);	/* make sure read comes after all that */
 320.724 +    utime (stream->mailbox,&times);
 320.725 +  }
 320.726 +  if (LOCAL->ld >= 0) {		/* unlock now */
 320.727 +    unlockfd (LOCAL->ld,LOCAL->lock);
 320.728 +    LOCAL->ld = -1;
 320.729 +  }
 320.730 +}
 320.731 +
 320.732 +
 320.733 +/* MBX mail per-message modify flags
 320.734 + * Accepts: MAIL stream
 320.735 + *	    message cache element
 320.736 + */
 320.737 +
 320.738 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 320.739 +{
 320.740 +  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
 320.741 +}
 320.742 +
 320.743 +/* MBX mail ping mailbox
 320.744 + * Accepts: MAIL stream
 320.745 + * Returns: T if stream still alive, NIL if not
 320.746 + */
 320.747 +
 320.748 +long mbx_ping (MAILSTREAM *stream)
 320.749 +{
 320.750 +  unsigned long i,pos;
 320.751 +  long ret = NIL;
 320.752 +  int ld;
 320.753 +  char lock[MAILTMPLEN];
 320.754 +  MESSAGECACHE *elt;
 320.755 +  struct stat sbuf;
 320.756 +  if (stream && LOCAL) {	/* only if stream already open */
 320.757 +    ret = LONGT;		/* assume OK */
 320.758 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 320.759 +				/* allow expunge if permitted at ping */
 320.760 +    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
 320.761 +				/* if external modification */
 320.762 +    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
 320.763 +      LOCAL->flagcheck = T;	/* upgrade to flag checking */
 320.764 +				/* new mail or flagcheck handling needed? */
 320.765 +    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
 320.766 +	 !stream->nmsgs) &&
 320.767 +	((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) {
 320.768 +      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
 320.769 +				/* sweep mailbox for changed message status */
 320.770 +      else if (ret = mbx_parse (stream)) {
 320.771 +	unsigned long recent = 0;
 320.772 +	LOCAL->filetime = sbuf.st_mtime;
 320.773 +	for (i = 1; i <= stream->nmsgs; )
 320.774 +	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
 320.775 +	    if (elt->recent) ++recent;
 320.776 +	    ++i;
 320.777 +	  }
 320.778 +	mail_recent (stream,recent);
 320.779 +	LOCAL->flagcheck = NIL;	/* got all the updates */
 320.780 +      }
 320.781 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 320.782 +    }
 320.783 +    if (ret) {			/* must still be alive */
 320.784 +      if (!LOCAL->expunged)	/* look for holes if none known yet */
 320.785 +	for (i = 1, pos = HDRSIZE;
 320.786 +	     !LOCAL->expunged && (i <= stream->nmsgs);
 320.787 +	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
 320.788 +	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
 320.789 +	    LOCAL->expunged = T;/* found a hole */
 320.790 +				/* burp any holes */
 320.791 +      if (LOCAL->expunged && !stream->rdonly) {
 320.792 +	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
 320.793 +	if (i) {		/* any space reclaimed? */
 320.794 +	  LOCAL->expunged = NIL;/* no more pending expunge */
 320.795 +	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
 320.796 +	  mm_log (LOCAL->buf,(long) NIL);
 320.797 +	}
 320.798 +      }
 320.799 +      LOCAL->expok = NIL;	/* no more expok */
 320.800 +    }
 320.801 +  }
 320.802 +  return ret;			/* return result of the parse */
 320.803 +}
 320.804 +
 320.805 +/* MBX mail check mailbox (reparses status too)
 320.806 + * Accepts: MAIL stream
 320.807 + */
 320.808 +
 320.809 +void mbx_check (MAILSTREAM *stream)
 320.810 +{
 320.811 +  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
 320.812 +  if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL);
 320.813 +}
 320.814 +
 320.815 +
 320.816 +/* MBX mail expunge mailbox
 320.817 + * Accepts: MAIL stream
 320.818 + *	    sequence to expunge if non-NIL
 320.819 + *	    expunge options
 320.820 + * Returns: T if success, NIL if failure
 320.821 + */
 320.822 +
 320.823 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
 320.824 +{
 320.825 +  long ret;
 320.826 +  unsigned long nexp,reclaimed;
 320.827 +  if (ret = sequence ? ((options & EX_UID) ?
 320.828 +			mail_uid_sequence (stream,sequence) :
 320.829 +			mail_sequence (stream,sequence)) : LONGT) {
 320.830 +    if (!mbx_ping (stream));	/* do nothing if stream dead */
 320.831 +    else if (stream->rdonly)	/* won't do on readonly files! */
 320.832 +      mm_log ("Expunge ignored on readonly mailbox",WARN);
 320.833 +				/* if expunged any messages */
 320.834 +    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
 320.835 +      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
 320.836 +      mm_log (LOCAL->buf,(long) NIL);
 320.837 +    }
 320.838 +    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
 320.839 +      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
 320.840 +      mm_log (LOCAL->buf,(long) NIL);
 320.841 +    }
 320.842 +    else mm_log ("No messages deleted, so no update needed",(long) NIL);
 320.843 +  }
 320.844 +  return ret;
 320.845 +}
 320.846 +
 320.847 +/* MBX mail copy message(s)
 320.848 + * Accepts: MAIL stream
 320.849 + *	    sequence
 320.850 + *	    destination mailbox
 320.851 + *	    copy options
 320.852 + * Returns: T if success, NIL if failed
 320.853 + */
 320.854 +
 320.855 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 320.856 +{
 320.857 +  struct stat sbuf;
 320.858 +  struct utimbuf times;
 320.859 +  MESSAGECACHE *elt;
 320.860 +  unsigned long i,j,k,m;
 320.861 +  long ret = LONGT;
 320.862 +  int fd,ld;
 320.863 +  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
 320.864 +  mailproxycopy_t pc =
 320.865 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 320.866 +  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 320.867 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 320.868 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 320.869 +  MAILSTREAM *dstream = NIL;
 320.870 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 320.871 +	mail_sequence (stream,sequence))) return NIL;
 320.872 +				/* make sure valid mailbox */
 320.873 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
 320.874 +			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
 320.875 +    switch (errno) {
 320.876 +    case ENOENT:		/* no such file? */
 320.877 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 320.878 +      return NIL;
 320.879 +    case EACCES:		/* file protected */
 320.880 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 320.881 +      MM_LOG (LOCAL->buf,ERROR);
 320.882 +      return NIL;
 320.883 +    case EINVAL:
 320.884 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 320.885 +      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
 320.886 +      mm_log (LOCAL->buf,ERROR);
 320.887 +      return NIL;
 320.888 +    default:
 320.889 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 320.890 +      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
 320.891 +      mm_log (LOCAL->buf,ERROR);
 320.892 +      return NIL;
 320.893 +    }
 320.894 +				/* got file? */  
 320.895 +  if ((fd = open (dummy_file (file,mailbox),O_RDWR|O_CREAT|O_BINARY,
 320.896 +		  S_IREAD|S_IWRITE)) < 0) {
 320.897 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
 320.898 +    mm_log (LOCAL->buf,ERROR);
 320.899 +    return NIL;
 320.900 +  }
 320.901 +  mm_critical (stream);		/* go critical */
 320.902 +  fstat (fd,&sbuf);		/* get current file size */
 320.903 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 320.904 +
 320.905 +				/* for each requested message */
 320.906 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 320.907 +    if ((elt = mail_elt (stream,i))->sequence) {
 320.908 +      lseek (LOCAL->fd,elt->private.special.offset +
 320.909 +	     elt->private.special.text.size,L_SET);
 320.910 +      mail_date(LOCAL->buf,elt);/* build target header */
 320.911 +				/* get target keyword mask */
 320.912 +      for (j = elt->user_flags, k = 0; j; )
 320.913 +	if (s = stream->user_flags[find_rightmost_bit (&j)])
 320.914 +	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
 320.915 +	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
 320.916 +      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
 320.917 +	       elt->rfc822_size,k,(unsigned)
 320.918 +	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 320.919 +		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 320.920 +		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
 320.921 +				/* write target header */
 320.922 +      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
 320.923 +	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
 320.924 +	  read (LOCAL->fd,LOCAL->buf,j);
 320.925 +	  ret = write (fd,LOCAL->buf,j) >= 0;
 320.926 +	}
 320.927 +	if (cu) {		/* need to pass back new UID? */
 320.928 +	  mail_append_set (source,mail_uid (stream,i));
 320.929 +	  mail_append_set (dest,dstream->uid_last);
 320.930 +	}
 320.931 +      }
 320.932 +    }
 320.933 +
 320.934 +				/* make sure all the updates take */
 320.935 +  if (!(ret && (ret = !fsync (fd)))) {
 320.936 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 320.937 +    mm_log (LOCAL->buf,ERROR);
 320.938 +    ftruncate (fd,sbuf.st_size);
 320.939 +  }
 320.940 +  if (cu && ret) {		/* return sets if doing COPYUID */
 320.941 +    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
 320.942 +    lseek (fd,15,L_SET);	/* update UIDLAST */
 320.943 +    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
 320.944 +    write (fd,LOCAL->buf,8);
 320.945 +  }
 320.946 +  else {			/* flush any sets we may have built */
 320.947 +    mail_free_searchset (&source);
 320.948 +    mail_free_searchset (&dest);
 320.949 +  }
 320.950 +				/* set atime to now-1 if successful copy */
 320.951 +  if (ret) times.actime = time (0) - 1;
 320.952 +				/* else preserved \Marked status */
 320.953 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 320.954 +	 sbuf.st_atime : time (0);
 320.955 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 320.956 +  utime (file,&times);		/* set the times */
 320.957 +  close (fd);			/* close the file */
 320.958 +  mm_nocritical (stream);	/* release critical */
 320.959 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 320.960 +				/* delete all requested messages */
 320.961 +  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
 320.962 +    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
 320.963 +				/* mark message deleted */
 320.964 +      mbx_elt (stream,i,NIL)->deleted = T;
 320.965 +				/* recalculate status */
 320.966 +      mbx_update_status (stream,i,NIL);
 320.967 +    }
 320.968 +				/* update flags */
 320.969 +    mbx_flag (stream,NIL,NIL,NIL);
 320.970 +  }
 320.971 +  if (dstream != stream) mail_close (dstream);
 320.972 +  return ret;
 320.973 +}
 320.974 +
 320.975 +/* MBX mail append message from stringstruct
 320.976 + * Accepts: MAIL stream
 320.977 + *	    destination mailbox
 320.978 + *	    append callback
 320.979 + *	    data for callback
 320.980 + * Returns: T if append successful, else NIL
 320.981 + */
 320.982 +
 320.983 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 320.984 +{
 320.985 +  struct stat sbuf;
 320.986 +  int fd,ld;
 320.987 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 320.988 +  struct utimbuf times;
 320.989 +  FILE *df;
 320.990 +  MESSAGECACHE elt;
 320.991 +  long f;
 320.992 +  unsigned long i,uf;
 320.993 +  STRING *message;
 320.994 +  long ret = NIL;
 320.995 +  MAILSTREAM *dstream = NIL;
 320.996 +  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
 320.997 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
 320.998 +				/* make sure valid mailbox */
 320.999 +				/* make sure valid mailbox */
320.1000 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
320.1001 +			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
320.1002 +    switch (errno) {
320.1003 +    case ENOENT:		/* no such file? */
320.1004 +      if (compare_cstring (mailbox,"INBOX")) {
320.1005 +	mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
320.1006 +	return NIL;
320.1007 +      }
320.1008 +				/* can create INBOX here */
320.1009 +      mbx_create (dstream = stream ? stream : &mbxproto,"INBOX");
320.1010 +      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
320.1011 +			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
320.1012 +	break;
320.1013 +    case EACCES:		/* file protected */
320.1014 +      sprintf (tmp,"Can't access destination: %.80s",mailbox);
320.1015 +      MM_LOG (tmp,ERROR);
320.1016 +      return NIL;
320.1017 +    case EINVAL:
320.1018 +      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
320.1019 +      mm_log (tmp,ERROR);
320.1020 +      return NIL;
320.1021 +    default:
320.1022 +      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
320.1023 +      mm_log (tmp,ERROR);
320.1024 +      return NIL;
320.1025 +    }
320.1026 +
320.1027 +				/* get first message */
320.1028 +  if (!(*af) (dstream,data,&flags,&date,&message)) close (fd);
320.1029 +  else if (!(df = fdopen (fd,"r+b"))) {
320.1030 +    MM_LOG ("Unable to reopen append mailbox",ERROR);
320.1031 +    close (fd);
320.1032 +  }
320.1033 +  else {
320.1034 +    mm_critical (dstream);	/* go critical */
320.1035 +    fstat (fd,&sbuf);		/* get current file size */
320.1036 +    fseek (df,sbuf.st_size,SEEK_SET);
320.1037 +    errno = 0;
320.1038 +    for (ret = LONGT; ret && message; ) {
320.1039 +      if (!SIZE (message)) {	/* guard against zero-length */
320.1040 +	mm_log ("Append of zero-length message",ERROR);
320.1041 +	ret = NIL;
320.1042 +	break;
320.1043 +      }
320.1044 +      f = mail_parse_flags (dstream,flags,&uf);
320.1045 +      if (date) {		/* parse date if given */
320.1046 +	if (!mail_parse_date (&elt,date)) {
320.1047 +	  sprintf (tmp,"Bad date in append: %.80s",date);
320.1048 +	  mm_log (tmp,ERROR);
320.1049 +	  ret = NIL;		/* mark failure */
320.1050 +	  break;
320.1051 +	}
320.1052 +	mail_date (tmp,&elt);	/* write preseved date */
320.1053 +      }
320.1054 +      else internal_date (tmp);	/* get current date in IMAP format */
320.1055 +				/* write header */
320.1056 +      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
320.1057 +		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
320.1058 +	ret = NIL;
320.1059 +      else {			/* write message */
320.1060 +	size_t j;
320.1061 +	if (!message->cursize) SETPOS (message,GETPOS (message));
320.1062 +	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
320.1063 +	  i -= j;
320.1064 +	  SETPOS (message,GETPOS (message) + j);
320.1065 +	}
320.1066 +				/* get next message */
320.1067 +	if (i || !(*af) (dstream,data,&flags,&date,&message)) ret = NIL;
320.1068 +	else if (au) mail_append_set (dst,dstream->uid_last);
320.1069 +      }
320.1070 +    }
320.1071 +
320.1072 +				/* if error... */
320.1073 +    if (!ret || (fflush (df) == EOF)) {
320.1074 +				/* revert file */
320.1075 +      ftruncate (fd,sbuf.st_size);
320.1076 +      close (fd);		/* make sure fclose() doesn't corrupt us */
320.1077 +      if (errno) {
320.1078 +	sprintf (tmp,"Message append failed: %s",strerror (errno));
320.1079 +	mm_log (tmp,ERROR);
320.1080 +      }
320.1081 +      ret = NIL;
320.1082 +    }
320.1083 +    if (au && ret) {		/* return sets if doing APPENDUID */
320.1084 +      (*au) (mailbox,dstream->uid_validity,dst);
320.1085 +      fseek (df,15,SEEK_SET);	/* update UIDLAST */
320.1086 +      fprintf (df,"%08lx",dstream->uid_last);
320.1087 +    }
320.1088 +    else mail_free_searchset (&dst);
320.1089 +    if (ret) times.actime = time (0) - 1;
320.1090 +				/* else preserve \Marked status */
320.1091 +    else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
320.1092 +	   sbuf.st_atime : time (0);
320.1093 +				/* preserve mtime */
320.1094 +    times.modtime = sbuf.st_mtime;
320.1095 +    utime (file,&times);	/* set the times */
320.1096 +    fclose (df);		/* close the file */
320.1097 +    mm_nocritical (dstream);	/* release critical */
320.1098 +  }
320.1099 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
320.1100 +  if (dstream != stream) mail_close (dstream);
320.1101 +  return ret;
320.1102 +}
320.1103 +
320.1104 +/* Internal routines */
320.1105 +
320.1106 +
320.1107 +/* MBX mail parse mailbox
320.1108 + * Accepts: MAIL stream
320.1109 + * Returns: T if parse OK
320.1110 + *	    NIL if failure, stream aborted
320.1111 + */
320.1112 +
320.1113 +long mbx_parse (MAILSTREAM *stream)
320.1114 +{
320.1115 +  struct stat sbuf;
320.1116 +  MESSAGECACHE *elt = NIL;
320.1117 +  unsigned char c,*s,*t,*x;
320.1118 +  char tmp[MAILTMPLEN];
320.1119 +  unsigned long i,j,k,m;
320.1120 +  off_t curpos = LOCAL->filesize;
320.1121 +  unsigned long nmsgs = stream->nmsgs;
320.1122 +  unsigned long recent = stream->recent;
320.1123 +  unsigned long lastuid = 0;
320.1124 +  short dirty = NIL;
320.1125 +  short added = NIL;
320.1126 +  short silent = stream->silent;
320.1127 +  short uidwarn = T;
320.1128 +  fstat (LOCAL->fd,&sbuf);	/* get status */
320.1129 +  if (sbuf.st_size < curpos) {	/* sanity check */
320.1130 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
320.1131 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
320.1132 +    mm_log (tmp,ERROR);
320.1133 +    mbx_abort (stream);
320.1134 +    return NIL;
320.1135 +  }
320.1136 +  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
320.1137 +				/* read internal header */
320.1138 +  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
320.1139 +  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
320.1140 +  c = LOCAL->buf[15];		/* save first character of last UID */
320.1141 +  LOCAL->buf[15] = '\0';
320.1142 +				/* parse UID validity */
320.1143 +  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
320.1144 +  LOCAL->buf[15] = c;		/* restore first character of last UID */
320.1145 +				/* parse last UID */
320.1146 +  i = strtoul (LOCAL->buf + 15,NIL,16);
320.1147 +  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
320.1148 +				/* parse user flags */
320.1149 +  for (i = 0, s = LOCAL->buf + 25;
320.1150 +       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
320.1151 +       i++, s = t + 2) {
320.1152 +    *t = '\0';			/* tie off flag */
320.1153 +    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
320.1154 +      stream->user_flags[i] = cpystr (s);
320.1155 +  }
320.1156 +  LOCAL->ffuserflag = (int) i;	/* first free user flag */
320.1157 +
320.1158 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
320.1159 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
320.1160 +				/* get to that position in the file */
320.1161 +    lseek (LOCAL->fd,curpos,L_SET);
320.1162 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
320.1163 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
320.1164 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
320.1165 +	       i ? strerror (errno) : "no data read");
320.1166 +      mm_log (tmp,ERROR);
320.1167 +      mbx_abort (stream);
320.1168 +      return NIL;
320.1169 +    }
320.1170 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
320.1171 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
320.1172 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
320.1173 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
320.1174 +      mm_log (tmp,ERROR);
320.1175 +      mbx_abort (stream);
320.1176 +      return NIL;
320.1177 +    }
320.1178 +    *s = '\0';			/* tie off header line */
320.1179 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
320.1180 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
320.1181 +      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
320.1182 +	       (unsigned long) curpos,(char *) LOCAL->buf);
320.1183 +      mm_log (tmp,ERROR);
320.1184 +      mbx_abort (stream);
320.1185 +      return NIL;
320.1186 +    }
320.1187 +    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
320.1188 +	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
320.1189 +	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
320.1190 +	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
320.1191 +      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
320.1192 +	       (unsigned long) curpos,(char *) LOCAL->buf);
320.1193 +      mm_log (tmp,ERROR);
320.1194 +      mbx_abort (stream);
320.1195 +      return NIL;
320.1196 +    }
320.1197 +    if ((t[13] != '-') || t[22] ||
320.1198 +	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
320.1199 +	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
320.1200 +	  isxdigit (t[20]) && isxdigit (t[21]))) {
320.1201 +      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
320.1202 +	       (unsigned long) curpos,(char *) LOCAL->buf);
320.1203 +      mm_log (tmp,ERROR);
320.1204 +      mbx_abort (stream);
320.1205 +      return NIL;
320.1206 +    }
320.1207 +
320.1208 +    *s++ = '\0'; *t++ = '\0';	/* break up fields */
320.1209 +				/* get message size */
320.1210 +    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
320.1211 +      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
320.1212 +	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
320.1213 +	       (char *) t);
320.1214 +      mm_log (tmp,ERROR);
320.1215 +      mbx_abort (stream);
320.1216 +      return NIL;
320.1217 +    }
320.1218 +				/* make sure didn't run off end of file */
320.1219 +    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
320.1220 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
320.1221 +	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
320.1222 +	       (unsigned long) sbuf.st_size);
320.1223 +      mm_log (tmp,ERROR);
320.1224 +      mbx_abort (stream);
320.1225 +      return NIL;
320.1226 +    }
320.1227 +				/* parse UID */
320.1228 +    if ((m = strtoul (t+13,NIL,16)) &&
320.1229 +	((m <= lastuid) || (m > stream->uid_last))) {
320.1230 +      if (uidwarn) {
320.1231 +	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
320.1232 +		 m,nmsgs+1);
320.1233 +	mm_log (tmp,WARN);
320.1234 +	uidwarn = NIL;
320.1235 +				/* restart UID validity */
320.1236 +	stream->uid_validity = (unsigned long) time (0);
320.1237 +      }
320.1238 +      m = 0;			/* lose this UID */
320.1239 +      dirty = T;		/* mark dirty, set new lastuid */
320.1240 +      stream->uid_last = lastuid;
320.1241 +    }
320.1242 +
320.1243 +    t[12] = '\0';		/* parse system flags */
320.1244 +    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
320.1245 +      if (m) lastuid = m;	/* expunge message, update last UID seen */
320.1246 +      else {			/* no UID assigned? */
320.1247 +	lastuid = ++stream->uid_last;
320.1248 +	dirty = T;
320.1249 +      }
320.1250 +    }
320.1251 +    else {			/* not expunged, swell the cache */
320.1252 +      added = T;		/* note that a new message was added */
320.1253 +      mail_exists (stream,++nmsgs);
320.1254 +				/* instantiate an elt for this message */
320.1255 +      (elt = mail_elt (stream,nmsgs))->valid = T;
320.1256 +				/* parse the date */
320.1257 +      if (!mail_parse_date (elt,LOCAL->buf)) {
320.1258 +	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
320.1259 +		 (unsigned long) curpos,(char *) LOCAL->buf);
320.1260 +	mm_log (tmp,ERROR);
320.1261 +	mbx_abort (stream);
320.1262 +	return NIL;
320.1263 +      }
320.1264 +				/* note file offset of header */
320.1265 +      elt->private.special.offset = curpos;
320.1266 +				/* and internal header size */
320.1267 +      elt->private.special.text.size = i;
320.1268 +				/* header size not known yet */
320.1269 +      elt->private.msg.header.text.size = 0;
320.1270 +      elt->rfc822_size = j;	/* note message size */
320.1271 +				/* calculate system flags */
320.1272 +      if (k & fSEEN) elt->seen = T;
320.1273 +      if (k & fDELETED) elt->deleted = T;
320.1274 +      if (k & fFLAGGED) elt->flagged = T;
320.1275 +      if (k & fANSWERED) elt->answered = T;
320.1276 +      if (k & fDRAFT) elt->draft = T;
320.1277 +      t[8] = '\0';		/* get user flags value */
320.1278 +      elt->user_flags = strtoul (t,NIL,16);
320.1279 +				/* UID already assigned? */
320.1280 +      if (!(elt->private.uid = m) || !(k & fOLD)) {
320.1281 +	elt->recent = T;	/* no, mark as recent */
320.1282 +	++recent;		/* count up a new recent message */
320.1283 +	dirty = T;		/* and must rewrite header */
320.1284 +				/* assign new UID */
320.1285 +	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
320.1286 +	mbx_update_status (stream,elt->msgno,NIL);
320.1287 +      }
320.1288 +				/* update last parsed UID */
320.1289 +      lastuid = elt->private.uid;
320.1290 +    }
320.1291 +    curpos += i + j;		/* update position */
320.1292 +  }
320.1293 +
320.1294 +  if (dirty && !stream->rdonly){/* update header */
320.1295 +    mbx_update_header (stream);
320.1296 +    fsync (LOCAL->fd);		/* make sure all the UID updates take */
320.1297 +  }
320.1298 +				/* update parsed file size and time */
320.1299 +  LOCAL->filesize = sbuf.st_size;
320.1300 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
320.1301 +  LOCAL->filetime = sbuf.st_mtime;
320.1302 +  if (added && !stream->rdonly){/* make sure atime updated */
320.1303 +    struct utimbuf times;
320.1304 +    times.actime = time (0);
320.1305 +    times.modtime = LOCAL->filetime;
320.1306 +    utime (stream->mailbox,&times);
320.1307 +  }
320.1308 +  stream->silent = silent;	/* can pass up events now */
320.1309 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
320.1310 +  mail_recent (stream,recent);	/* and of change in recent messages */
320.1311 +  return LONGT;			/* return the winnage */
320.1312 +}
320.1313 +
320.1314 +/* MBX get cache element with status updating from file
320.1315 + * Accepts: MAIL stream
320.1316 + *	    message number
320.1317 + *	    expunge OK flag
320.1318 + * Returns: cache element
320.1319 + */
320.1320 +
320.1321 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
320.1322 +{
320.1323 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
320.1324 +  struct {			/* old flags */
320.1325 +    unsigned int seen : 1;
320.1326 +    unsigned int deleted : 1;
320.1327 +    unsigned int flagged : 1;
320.1328 +    unsigned int answered : 1;
320.1329 +    unsigned int draft : 1;
320.1330 +    unsigned long user_flags;
320.1331 +  } old;
320.1332 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
320.1333 +  old.answered = elt->answered; old.draft = elt->draft;
320.1334 +  old.user_flags = elt->user_flags;
320.1335 +				/* get new flags */
320.1336 +  if (mbx_read_flags (stream,elt) && expok) {
320.1337 +    mail_expunged (stream,elt->msgno);
320.1338 +    return NIL;			/* return this message was expunged */
320.1339 +  }
320.1340 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
320.1341 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
320.1342 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
320.1343 +    mm_flags (stream,msgno);	/* let top level know */
320.1344 +  return elt;
320.1345 +}
320.1346 +
320.1347 +/* MBX read flags from file
320.1348 + * Accepts: MAIL stream
320.1349 + *	    cache element
320.1350 + * Returns: non-NIL if message expunged
320.1351 + */
320.1352 +
320.1353 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
320.1354 +{
320.1355 +  unsigned long i;
320.1356 +  struct stat sbuf;
320.1357 +  fstat (LOCAL->fd,&sbuf);	/* get status */
320.1358 +				/* make sure file size is good */
320.1359 +  if (sbuf.st_size < LOCAL->filesize) {
320.1360 +    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
320.1361 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
320.1362 +    fatal (LOCAL->buf);
320.1363 +  }
320.1364 +				/* set the seek pointer */
320.1365 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
320.1366 +	 elt->private.special.text.size - 24,L_SET);
320.1367 +				/* read the new flags */
320.1368 +  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
320.1369 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
320.1370 +    fatal (LOCAL->buf);
320.1371 +  }
320.1372 +  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
320.1373 +    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
320.1374 +    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
320.1375 +	     elt->msgno,elt->private.special.offset,
320.1376 +	     elt->private.special.text.size,(char *) LOCAL->buf);
320.1377 +    fatal (LOCAL->buf+50);
320.1378 +  }
320.1379 +  LOCAL->buf[13] = '\0';	/* tie off buffer */
320.1380 +				/* calculate system flags */
320.1381 +  i = strtoul (LOCAL->buf+9,NIL,16);
320.1382 +  elt->seen = i & fSEEN ? T : NIL;
320.1383 +  elt->deleted = i & fDELETED ? T : NIL;
320.1384 +  elt->flagged = i & fFLAGGED ? T : NIL;
320.1385 +  elt->answered = i & fANSWERED ? T : NIL;
320.1386 +  elt->draft = i & fDRAFT ? T : NIL;
320.1387 +  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
320.1388 +  LOCAL->buf[9] = '\0';		/* tie off flags */
320.1389 +				/* get user flags value */
320.1390 +  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
320.1391 +  elt->valid = T;		/* have valid flags now */
320.1392 +  return i & fEXPUNGED;
320.1393 +}
320.1394 +
320.1395 +/* MBX update header
320.1396 + * Accepts: MAIL stream
320.1397 + */
320.1398 +
320.1399 +#define NTKLUDGEOFFSET 7
320.1400 +
320.1401 +void mbx_update_header (MAILSTREAM *stream)
320.1402 +{
320.1403 +  int i;
320.1404 +  char *s = LOCAL->buf;
320.1405 +  memset (s,'\0',HDRSIZE);	/* initialize header */
320.1406 +  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
320.1407 +	   stream->uid_validity,stream->uid_last);
320.1408 +  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
320.1409 +    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
320.1410 +  LOCAL->ffuserflag = i;	/* first free user flag */
320.1411 +				/* can we create more user flags? */
320.1412 +  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
320.1413 +				/* write reserved lines */
320.1414 +  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
320.1415 +  while (T) {			/* rewind file */
320.1416 +    lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET);
320.1417 +				/* write new header */
320.1418 +    if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET,
320.1419 +	       HDRSIZE - NTKLUDGEOFFSET) > 0) break;
320.1420 +    mm_notify (stream,strerror (errno),WARN);
320.1421 +    mm_diskerror (stream,errno,T);
320.1422 +  }
320.1423 +}
320.1424 +
320.1425 +/* MBX update status string
320.1426 + * Accepts: MAIL stream
320.1427 + *	    message number
320.1428 + *	    flags
320.1429 + */
320.1430 +
320.1431 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
320.1432 +{
320.1433 +  struct stat sbuf;
320.1434 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
320.1435 +				/* readonly */
320.1436 +  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
320.1437 +  else {			/* readwrite */
320.1438 +    fstat (LOCAL->fd,&sbuf);	/* get status */
320.1439 +				/* make sure file size is good */
320.1440 +    if (sbuf.st_size < LOCAL->filesize) {
320.1441 +      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
320.1442 +	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
320.1443 +      fatal (LOCAL->buf);
320.1444 +    }
320.1445 +				/* set the seek pointer */
320.1446 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
320.1447 +	   elt->private.special.text.size - 24,L_SET);
320.1448 +				/* read the new flags */
320.1449 +    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
320.1450 +      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
320.1451 +      fatal (LOCAL->buf);
320.1452 +    }
320.1453 +    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
320.1454 +      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
320.1455 +      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
320.1456 +	       elt->msgno,elt->private.special.offset,
320.1457 +	       elt->private.special.text.size,(char *) LOCAL->buf);
320.1458 +      fatal (LOCAL->buf+50);
320.1459 +    }
320.1460 +				/* print new flag string */
320.1461 +    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
320.1462 +	     (((elt->deleted && flags) ?
320.1463 +	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
320.1464 +	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
320.1465 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
320.1466 +	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
320.1467 +    while (T) {			/* get to that place in the file */
320.1468 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
320.1469 +	     elt->private.special.text.size - 23,L_SET);
320.1470 +				/* write new flags and UID */
320.1471 +      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
320.1472 +      mm_notify (stream,strerror (errno),WARN);
320.1473 +      mm_diskerror (stream,errno,T);
320.1474 +    }
320.1475 +  }
320.1476 +}
320.1477 +
320.1478 +/* MBX locate header for a message
320.1479 + * Accepts: MAIL stream
320.1480 + *	    message number
320.1481 + *	    pointer to returned header size
320.1482 + *	    pointer to possible returned header
320.1483 + * Returns: position of header in file
320.1484 + */
320.1485 +
320.1486 +#define HDRBUFLEN 16384		/* good enough for most headers */
320.1487 +#define SLOP 4			/* CR LF CR LF */
320.1488 +
320.1489 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
320.1490 +			  unsigned long *size,char **hdr)
320.1491 +{
320.1492 +  unsigned long siz,done;
320.1493 +  long i;
320.1494 +  unsigned char *s,*t,*te;
320.1495 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
320.1496 +  unsigned long ret = elt->private.special.offset +
320.1497 +    elt->private.special.text.size;
320.1498 +  if (hdr) *hdr = NIL;		/* assume no header returned */
320.1499 +				/* is header size known? */ 
320.1500 +  if (*size = elt->private.msg.header.text.size) return ret;
320.1501 +				/* paranoia check */
320.1502 +  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
320.1503 +    fatal ("LOCAL->buf smaller than HDRBUFLEN");
320.1504 +  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
320.1505 +				/* read HDRBUFLEN chunks with 4 byte slop */
320.1506 +  for (done = siz = 0, s = LOCAL->buf;
320.1507 +       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
320.1508 +       (read (LOCAL->fd,s,i) == i);
320.1509 +       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
320.1510 +    te = (t = s + i) - 12;	/* calculate end of fast scan */
320.1511 +				/* fast scan for CR */
320.1512 +    for (s = LOCAL->buf; s < te;)
320.1513 +      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
320.1514 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
320.1515 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
320.1516 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
320.1517 +	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
320.1518 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
320.1519 +	if (hdr) *hdr = LOCAL->buf;
320.1520 +	return ret;
320.1521 +      }
320.1522 +    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
320.1523 +      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
320.1524 +	  (*++s == '\012')) {
320.1525 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
320.1526 +	if (hdr) *hdr = LOCAL->buf;
320.1527 +	return ret;
320.1528 +      }
320.1529 +    if (i <= SLOP) break;	/* end of data */
320.1530 +				/* slide over last 4 bytes */
320.1531 +    memmove (LOCAL->buf,t - SLOP,SLOP);
320.1532 +    hdr = NIL;			/* can't return header this way */
320.1533 +  }
320.1534 +				/* not found: header consumes entire message */
320.1535 +  elt->private.msg.header.text.size = *size = elt->rfc822_size;
320.1536 +  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
320.1537 +  return ret;
320.1538 +}
320.1539 +
320.1540 +/* MBX mail rewrite mailbox
320.1541 + * Accepts: MAIL stream
320.1542 + *	    pointer to return reclaimed size
320.1543 + *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
320.1544 + * Returns: number of expunged messages
320.1545 + */
320.1546 +
320.1547 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
320.1548 +			   long flags)
320.1549 +{
320.1550 +  struct utimbuf times;
320.1551 +  struct stat sbuf;
320.1552 +  off_t pos,ppos;
320.1553 +  int ld;
320.1554 +  unsigned long i,j,k,m,delta;
320.1555 +  unsigned long n = *reclaimed = 0;
320.1556 +  unsigned long recent = 0;
320.1557 +  char lock[MAILTMPLEN];
320.1558 +  MESSAGECACHE *elt;
320.1559 +				/* get parse/append permission */
320.1560 +  if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) {
320.1561 +    mm_log ("Unable to lock expunge mailbox",ERROR);
320.1562 +    return 0;
320.1563 +  }
320.1564 +  fstat (LOCAL->fd,&sbuf);	/* get current write time */
320.1565 +  if (LOCAL->filetime && !LOCAL->flagcheck &&
320.1566 +      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
320.1567 +  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
320.1568 +    unlockfd (ld,lock);		/* failed?? */
320.1569 +    return 0;
320.1570 +  }
320.1571 +  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
320.1572 +    LOCAL->filetime = sbuf.st_mtime;
320.1573 +    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
320.1574 +    LOCAL->flagcheck = NIL;
320.1575 +  }
320.1576 +
320.1577 +				/* get exclusive access */
320.1578 +  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
320.1579 +    mm_critical (stream);	/* go critical */
320.1580 +    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
320.1581 +				/* note if message not at predicted location */
320.1582 +      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
320.1583 +	ppos = elt->private.special.offset;
320.1584 +	*reclaimed += m;	/* note reclaimed message space */
320.1585 +	delta += m;		/* and as expunge delta  */
320.1586 +      }
320.1587 +				/* number of bytes to smash or preserve */
320.1588 +      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
320.1589 +				/* if need to expunge this message*/
320.1590 +      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
320.1591 +	delta += k;		/* number of bytes to delete */
320.1592 +	mail_expunged(stream,i);/* notify upper levels */
320.1593 +	n++;			/* count up one more expunged message */
320.1594 +      }
320.1595 +      else {			/* preserved message */
320.1596 +	i++;			/* count this message */
320.1597 +	if (elt->recent) ++recent;
320.1598 +	if (delta) {		/* moved, note first byte to preserve */
320.1599 +	  j = elt->private.special.offset;
320.1600 +	  do {			/* read from source position */
320.1601 +	    m = min (k,LOCAL->buflen);
320.1602 +	    lseek (LOCAL->fd,j,L_SET);
320.1603 +	    read (LOCAL->fd,LOCAL->buf,m);
320.1604 +	    pos = j - delta;	/* write to destination position */
320.1605 +	    while (T) {
320.1606 +	      lseek (LOCAL->fd,pos,L_SET);
320.1607 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
320.1608 +	      mm_notify (stream,strerror (errno),WARN);
320.1609 +	      mm_diskerror (stream,errno,T);
320.1610 +	    }
320.1611 +	    pos += m;		/* new position */
320.1612 +	    j += m;		/* next chunk, perhaps */
320.1613 +	  } while (k -= m);	/* until done */
320.1614 +				/* note the new address of this text */
320.1615 +	  elt->private.special.offset -= delta;
320.1616 +	}
320.1617 +				/* preserved but no deleted messages yet */
320.1618 +	else pos = elt->private.special.offset + k;
320.1619 +      }
320.1620 +    }
320.1621 +				/* deltaed file size match position? */
320.1622 +    if (m = (LOCAL->filesize -= delta) - pos) {
320.1623 +      *reclaimed += m;		/* probably an fEXPUNGED msg */
320.1624 +      LOCAL->filesize = pos;	/* set correct size */
320.1625 +    }
320.1626 +				/* truncate file after last message */
320.1627 +    ftruncate (LOCAL->fd,LOCAL->filesize);
320.1628 +    fsync (LOCAL->fd);		/* force disk update */
320.1629 +    mm_nocritical (stream);	/* release critical */
320.1630 +    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
320.1631 +  }
320.1632 +
320.1633 +  else {			/* can't get exclusive */
320.1634 +    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
320.1635 +				/* do hide-expunge when shared */
320.1636 +    if (flags) for (i = 1; i <= stream->nmsgs; ) {
320.1637 +      if (elt = mbx_elt (stream,i,T)) {
320.1638 +				/* make the message invisible */
320.1639 +	if (elt->deleted && ((flags > 0) || elt->sequence)) {
320.1640 +	  mbx_update_status (stream,elt->msgno,LONGT);
320.1641 +				/* notify upper levels */
320.1642 +	  mail_expunged (stream,i);
320.1643 +	  n++;			/* count up one more expunged message */
320.1644 +	}
320.1645 +	else {
320.1646 +	  i++;			/* preserved message */
320.1647 +	  if (elt->recent) ++recent;
320.1648 +	}
320.1649 +      }
320.1650 +      else n++;			/* count up one more expunged message */
320.1651 +    }
320.1652 +    fsync (LOCAL->fd);		/* force disk update */
320.1653 +  }
320.1654 +  fstat (LOCAL->fd,&sbuf);	/* get new write time */
320.1655 +  times.modtime = LOCAL->filetime = sbuf.st_mtime;
320.1656 +  times.actime = time (0);	/* reset atime to now */
320.1657 +  utime (stream->mailbox,&times);
320.1658 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
320.1659 +				/* notify upper level of new mailbox size */
320.1660 +  mail_exists (stream,stream->nmsgs);
320.1661 +  mail_recent (stream,recent);
320.1662 +  return n;			/* return number of expunged messages */
320.1663 +}
320.1664 +
320.1665 +/* MBX mail lock for flag updating
320.1666 + * Accepts: stream
320.1667 + * Returns: T if successful, NIL if failure
320.1668 + */
320.1669 +
320.1670 +long mbx_flaglock (MAILSTREAM *stream)
320.1671 +{
320.1672 +  struct stat sbuf;
320.1673 +  unsigned long i;
320.1674 +  int ld;
320.1675 +  char lock[MAILTMPLEN];
320.1676 +				/* no-op if readonly or already locked */
320.1677 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
320.1678 +				/* lock now */
320.1679 +    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL;
320.1680 +    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
320.1681 +      if (LOCAL->filetime) {	/* know previous time? */
320.1682 +	fstat (LOCAL->fd,&sbuf);/* get current write time */
320.1683 +	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
320.1684 +	LOCAL->filetime = 0;	/* don't do this test for any other messages */
320.1685 +      }
320.1686 +      if (!mbx_parse (stream)) {/* parse mailbox */
320.1687 +	unlockfd (ld,lock);	/* shouldn't happen */
320.1688 +	return NIL;
320.1689 +      }
320.1690 +      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
320.1691 +	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
320.1692 +    }
320.1693 +    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
320.1694 +    memcpy (LOCAL->lock,lock,MAILTMPLEN);
320.1695 +  }
320.1696 +  return LONGT;
320.1697 +}
   321.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   321.2 +++ b/src/osdep/os2/mtxnt.c	Mon Sep 14 15:17:45 2009 +0900
   321.3 @@ -0,0 +1,1232 @@
   321.4 +/* ========================================================================
   321.5 + * Copyright 1988-2007 University of Washington
   321.6 + *
   321.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   321.8 + * you may not use this file except in compliance with the License.
   321.9 + * You may obtain a copy of the License at
  321.10 + *
  321.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  321.12 + *
  321.13 + * 
  321.14 + * ========================================================================
  321.15 + */
  321.16 +
  321.17 +/*
  321.18 + * Program:	MTX mail routines
  321.19 + *
  321.20 + * Author:	Mark Crispin
  321.21 + *		Networks and Distributed Computing
  321.22 + *		Computing & Communications
  321.23 + *		University of Washington
  321.24 + *		Administration Building, AG-44
  321.25 + *		Seattle, WA  98195
  321.26 + *		Internet: MRC@CAC.Washington.EDU
  321.27 + *
  321.28 + * Date:	22 May 1990
  321.29 + * Last Edited:	15 June 2007
  321.30 + */
  321.31 +
  321.32 +
  321.33 +/*				FILE TIME SEMANTICS
  321.34 + *
  321.35 + * The atime is the last read time of the file.
  321.36 + * The mtime is the last flags update time of the file.
  321.37 + * The ctime is the last write time of the file.
  321.38 + */
  321.39 +
  321.40 +#include <stdio.h>
  321.41 +#include <ctype.h>
  321.42 +#include <errno.h>
  321.43 +extern int errno;		/* just in case */
  321.44 +#include "mail.h"
  321.45 +#include "osdep.h"
  321.46 +#include <fcntl.h>
  321.47 +#include <time.h>
  321.48 +#include <sys/stat.h>
  321.49 +#include <sys/utime.h>
  321.50 +#include "misc.h"
  321.51 +#include "dummy.h"
  321.52 +#include "fdstring.h"
  321.53 +
  321.54 +/* MTX I/O stream local data */
  321.55 +	
  321.56 +typedef struct mtx_local {
  321.57 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  321.58 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  321.59 +  int fd;			/* file descriptor for I/O */
  321.60 +  off_t filesize;		/* file size parsed */
  321.61 +  time_t filetime;		/* last file time */
  321.62 +  time_t lastsnarf;		/* last snarf time */
  321.63 +  unsigned char *buf;		/* temporary buffer */
  321.64 +  unsigned long buflen;		/* current size of temporary buffer */
  321.65 +} MTXLOCAL;
  321.66 +
  321.67 +
  321.68 +/* Convenient access to local data */
  321.69 +
  321.70 +#define LOCAL ((MTXLOCAL *) stream->local)
  321.71 +
  321.72 +
  321.73 +/* Function prototypes */
  321.74 +
  321.75 +DRIVER *mtx_valid (char *name);
  321.76 +int mtx_isvalid (char *name,char *file);
  321.77 +void *mtx_parameters (long function,void *value);
  321.78 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  321.79 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
  321.80 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  321.81 +long mtx_create (MAILSTREAM *stream,char *mailbox);
  321.82 +long mtx_delete (MAILSTREAM *stream,char *mailbox);
  321.83 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
  321.84 +long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
  321.85 +MAILSTREAM *mtx_open (MAILSTREAM *stream);
  321.86 +void mtx_close (MAILSTREAM *stream,long options);
  321.87 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
  321.88 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
  321.89 +		  unsigned long *length,long flags);
  321.90 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  321.91 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  321.92 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  321.93 +long mtx_ping (MAILSTREAM *stream);
  321.94 +void mtx_check (MAILSTREAM *stream);
  321.95 +void mtx_snarf (MAILSTREAM *stream);
  321.96 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
  321.97 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  321.98 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  321.99 +
 321.100 +long mtx_parse (MAILSTREAM *stream);
 321.101 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
 321.102 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 321.103 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
 321.104 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 321.105 +			  unsigned long *size);
 321.106 +
 321.107 +
 321.108 +/* MTX mail routines */
 321.109 +
 321.110 +
 321.111 +/* Driver dispatch used by MAIL */
 321.112 +
 321.113 +DRIVER mtxdriver = {
 321.114 +  "mtx",			/* driver name */
 321.115 +				/* driver flags */
 321.116 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY,
 321.117 +  (DRIVER *) NIL,		/* next driver */
 321.118 +  mtx_valid,			/* mailbox is valid for us */
 321.119 +  mtx_parameters,		/* manipulate parameters */
 321.120 +  mtx_scan,			/* scan mailboxes */
 321.121 +  mtx_list,			/* list mailboxes */
 321.122 +  mtx_lsub,			/* list subscribed mailboxes */
 321.123 +  NIL,				/* subscribe to mailbox */
 321.124 +  NIL,				/* unsubscribe from mailbox */
 321.125 +  mtx_create,			/* create mailbox */
 321.126 +  mtx_delete,			/* delete mailbox */
 321.127 +  mtx_rename,			/* rename mailbox */
 321.128 +  mail_status_default,		/* status of mailbox */
 321.129 +  mtx_open,			/* open mailbox */
 321.130 +  mtx_close,			/* close mailbox */
 321.131 +  mtx_flags,			/* fetch message "fast" attributes */
 321.132 +  mtx_flags,			/* fetch message flags */
 321.133 +  NIL,				/* fetch overview */
 321.134 +  NIL,				/* fetch message envelopes */
 321.135 +  mtx_header,			/* fetch message header */
 321.136 +  mtx_text,			/* fetch message body */
 321.137 +  NIL,				/* fetch partial message text */
 321.138 +  NIL,				/* unique identifier */
 321.139 +  NIL,				/* message number */
 321.140 +  mtx_flag,			/* modify flags */
 321.141 +  mtx_flagmsg,			/* per-message modify flags */
 321.142 +  NIL,				/* search for message based on criteria */
 321.143 +  NIL,				/* sort messages */
 321.144 +  NIL,				/* thread messages */
 321.145 +  mtx_ping,			/* ping mailbox to see if still alive */
 321.146 +  mtx_check,			/* check for new messages */
 321.147 +  mtx_expunge,			/* expunge deleted messages */
 321.148 +  mtx_copy,			/* copy messages to another mailbox */
 321.149 +  mtx_append,			/* append string message to mailbox */
 321.150 +  NIL				/* garbage collect stream */
 321.151 +};
 321.152 +
 321.153 +				/* prototype stream */
 321.154 +MAILSTREAM mtxproto = {&mtxdriver};
 321.155 +
 321.156 +/* MTX mail validate mailbox
 321.157 + * Accepts: mailbox name
 321.158 + * Returns: our driver if name is valid, NIL otherwise
 321.159 + */
 321.160 +
 321.161 +DRIVER *mtx_valid (char *name)
 321.162 +{
 321.163 +  char tmp[MAILTMPLEN];
 321.164 +  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
 321.165 +}
 321.166 +
 321.167 +
 321.168 +/* MTX mail test for valid mailbox
 321.169 + * Accepts: mailbox name
 321.170 + *	    buffer to return file name
 321.171 + * Returns: T if valid, NIL otherwise
 321.172 + */
 321.173 +
 321.174 +int mtx_isvalid (char *name,char *file)
 321.175 +{
 321.176 +  int fd;
 321.177 +  int ret = NIL;
 321.178 +  char *s,tmp[MAILTMPLEN];
 321.179 +  struct stat sbuf;
 321.180 +  struct utimbuf times;
 321.181 +  errno = EINVAL;		/* assume invalid argument */
 321.182 +				/* if file, get its status */
 321.183 +  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
 321.184 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
 321.185 +    if (!sbuf.st_size)errno = 0;/* empty file */
 321.186 +    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
 321.187 +      memset (tmp,'\0',MAILTMPLEN);
 321.188 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
 321.189 +	  (s[1] == '\012')) {	/* valid format? */
 321.190 +	*s = '\0';		/* tie off header */
 321.191 +				/* must begin with dd-mmm-yy" */
 321.192 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 321.193 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 321.194 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 321.195 +      }
 321.196 +      else errno = -1;		/* bogus format */
 321.197 +      close (fd);		/* close the file */
 321.198 +				/* \Marked status? */
 321.199 +      if (sbuf.st_ctime > sbuf.st_atime) {
 321.200 +				/* preserve atime and mtime */
 321.201 +	times.actime = sbuf.st_atime;
 321.202 +	times.modtime = sbuf.st_mtime;
 321.203 +	utime (file,&times);	/* set the times */
 321.204 +      }
 321.205 +    }
 321.206 +  }
 321.207 +				/* in case INBOX but not mtx format */
 321.208 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 321.209 +  return ret;			/* return what we should */
 321.210 +}
 321.211 +
 321.212 +
 321.213 +/* MTX manipulate driver parameters
 321.214 + * Accepts: function code
 321.215 + *	    function-dependent value
 321.216 + * Returns: function-dependent return value
 321.217 + */
 321.218 +
 321.219 +void *mtx_parameters (long function,void *value)
 321.220 +{
 321.221 +  return NIL;
 321.222 +}
 321.223 +
 321.224 +/* MTX mail scan mailboxes
 321.225 + * Accepts: mail stream
 321.226 + *	    reference
 321.227 + *	    pattern to search
 321.228 + *	    string to scan
 321.229 + */
 321.230 +
 321.231 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 321.232 +{
 321.233 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 321.234 +}
 321.235 +
 321.236 +
 321.237 +/* MTX mail list mailboxes
 321.238 + * Accepts: mail stream
 321.239 + *	    reference
 321.240 + *	    pattern to search
 321.241 + */
 321.242 +
 321.243 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
 321.244 +{
 321.245 +  if (stream) dummy_list (NIL,ref,pat);
 321.246 +}
 321.247 +
 321.248 +
 321.249 +/* MTX mail list subscribed mailboxes
 321.250 + * Accepts: mail stream
 321.251 + *	    reference
 321.252 + *	    pattern to search
 321.253 + */
 321.254 +
 321.255 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 321.256 +{
 321.257 +  if (stream) dummy_lsub (NIL,ref,pat);
 321.258 +}
 321.259 +
 321.260 +/* MTX mail create mailbox
 321.261 + * Accepts: MAIL stream
 321.262 + *	    mailbox name to create
 321.263 + * Returns: T on success, NIL on failure
 321.264 + */
 321.265 +
 321.266 +long mtx_create (MAILSTREAM *stream,char *mailbox)
 321.267 +{
 321.268 +  char *s,mbx[MAILTMPLEN];
 321.269 +  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
 321.270 +  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 321.271 +  mm_log (mbx,ERROR);
 321.272 +  return NIL;
 321.273 +}
 321.274 +
 321.275 +
 321.276 +/* MTX mail delete mailbox
 321.277 + * Accepts: MAIL stream
 321.278 + *	    mailbox name to delete
 321.279 + * Returns: T on success, NIL on failure
 321.280 + */
 321.281 +
 321.282 +long mtx_delete (MAILSTREAM *stream,char *mailbox)
 321.283 +{
 321.284 +  return mtx_rename (stream,mailbox,NIL);
 321.285 +}
 321.286 +
 321.287 +/* MTX mail rename mailbox
 321.288 + * Accepts: MAIL stream
 321.289 + *	    old mailbox name
 321.290 + *	    new mailbox name (or NIL for delete)
 321.291 + * Returns: T on success, NIL on failure
 321.292 + */
 321.293 +
 321.294 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
 321.295 +{
 321.296 +  long ret = LONGT;
 321.297 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 321.298 +  int fd,ld;
 321.299 +  struct stat sbuf;
 321.300 +  if (!dummy_file (file,old) ||
 321.301 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 321.302 +		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
 321.303 +    sprintf (tmp,newname ?
 321.304 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 321.305 +	     "Can't delete mailbox %.80s: invalid name",
 321.306 +	     old,newname);
 321.307 +    mm_log (tmp,ERROR);
 321.308 +    return NIL;
 321.309 +  }
 321.310 +  if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
 321.311 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 321.312 +    mm_log (tmp,ERROR);
 321.313 +    return NIL;
 321.314 +  }
 321.315 +				/* get exclusive parse/append permission */
 321.316 +  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
 321.317 +    mm_log ("Unable to lock rename mailbox",ERROR);
 321.318 +    return NIL;
 321.319 +  }
 321.320 +				/* lock out other users */
 321.321 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 321.322 +    close (fd);			/* couldn't lock, give up on it then */
 321.323 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 321.324 +    mm_log (tmp,ERROR);
 321.325 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 321.326 +    return NIL;
 321.327 +  }
 321.328 +
 321.329 +  if (newname) {		/* want rename? */
 321.330 +				/* found superior to destination name? */
 321.331 +    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 321.332 +	((tmp[1] != ':') || (s != tmp + 2))) {
 321.333 +      c = s[1];			/* remember character after delimiter */
 321.334 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 321.335 +				/* name doesn't exist, create it */
 321.336 +      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 321.337 +	*s = '\\';		/* restore delimiter */
 321.338 +	if (!dummy_create (stream,tmp)) ret = NIL;
 321.339 +      }
 321.340 +      else *s = '\\';		/* restore delimiter */
 321.341 +      s[1] = c;			/* restore character after delimiter */
 321.342 +    }
 321.343 +    flock (fd,LOCK_UN);		/* release lock on the file */
 321.344 +    close (fd);			/* pacify NTFS */
 321.345 +				/* rename the file */
 321.346 +    if (ret && rename (file,tmp)) {
 321.347 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 321.348 +	       strerror (errno));
 321.349 +      mm_log (tmp,ERROR);
 321.350 +      ret = NIL;		/* set failure */
 321.351 +    }
 321.352 +  }
 321.353 +  else {
 321.354 +    flock (fd,LOCK_UN);		/* release lock on the file */
 321.355 +    close (fd);			/* pacify NTFS */
 321.356 +    if (unlink (file)) {
 321.357 +      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
 321.358 +      mm_log (tmp,ERROR);
 321.359 +      ret = NIL;		/* set failure */
 321.360 +    }
 321.361 +  }
 321.362 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 321.363 +  return ret;			/* return success */
 321.364 +}
 321.365 +
 321.366 +/* MTX mail open
 321.367 + * Accepts: stream to open
 321.368 + * Returns: stream on success, NIL on failure
 321.369 + */
 321.370 +
 321.371 +MAILSTREAM *mtx_open (MAILSTREAM *stream)
 321.372 +{
 321.373 +  int fd,ld;
 321.374 +  char tmp[MAILTMPLEN];
 321.375 +				/* return prototype for OP_PROTOTYPE call */
 321.376 +  if (!stream) return &mtxproto;
 321.377 +  if (stream->local) fatal ("mtx recycle stream");
 321.378 +				/* canonicalize the mailbox name */
 321.379 +  if (!dummy_file (tmp,stream->mailbox)) {
 321.380 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 321.381 +    mm_log (tmp,ERROR);
 321.382 +  }
 321.383 +  if (stream->rdonly ||
 321.384 +      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
 321.385 +    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
 321.386 +      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
 321.387 +      mm_log (tmp,ERROR);
 321.388 +      return NIL;
 321.389 +    }
 321.390 +    else if (!stream->rdonly) {	/* got it, but readonly */
 321.391 +      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 321.392 +      stream->rdonly = T;
 321.393 +    }
 321.394 +  }
 321.395 +  stream->local = fs_get (sizeof (MTXLOCAL));
 321.396 +  LOCAL->fd = fd;		/* bind the file */
 321.397 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 321.398 +  LOCAL->buflen = CHUNKSIZE - 1;
 321.399 +				/* note if an INBOX or not */
 321.400 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 321.401 +  fs_give ((void **) &stream->mailbox);
 321.402 +  stream->mailbox = cpystr (tmp);
 321.403 +				/* get shared parse permission */
 321.404 +  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
 321.405 +    mm_log ("Unable to lock open mailbox",ERROR);
 321.406 +    return NIL;
 321.407 +  }
 321.408 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 321.409 +  unlockfd (ld,tmp);		/* release shared parse permission */
 321.410 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 321.411 +  LOCAL->filetime = 0;		/* time not set up yet */
 321.412 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 321.413 +  stream->sequence++;		/* bump sequence number */
 321.414 +  stream->uid_validity = (unsigned long) time (0);
 321.415 +				/* parse mailbox */
 321.416 +  stream->nmsgs = stream->recent = 0;
 321.417 +  if (mtx_ping (stream) && !stream->nmsgs)
 321.418 +    mm_log ("Mailbox is empty",(long) NIL);
 321.419 +  if (!LOCAL) return NIL;	/* failure if stream died */
 321.420 +  stream->perm_seen = stream->perm_deleted =
 321.421 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 321.422 +      stream->rdonly ? NIL : T;
 321.423 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 321.424 +  return stream;		/* return stream to caller */
 321.425 +}
 321.426 +
 321.427 +/* MTX mail close
 321.428 + * Accepts: MAIL stream
 321.429 + *	    close options
 321.430 + */
 321.431 +
 321.432 +void mtx_close (MAILSTREAM *stream,long options)
 321.433 +{
 321.434 +  if (stream && LOCAL) {	/* only if a file is open */
 321.435 +    int silent = stream->silent;
 321.436 +    stream->silent = T;		/* note this stream is dying */
 321.437 +    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
 321.438 +    stream->silent = silent;	/* restore previous status */
 321.439 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 321.440 +    close (LOCAL->fd);		/* close the local file */
 321.441 +				/* free local text buffer */
 321.442 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 321.443 +				/* nuke the local data */
 321.444 +    fs_give ((void **) &stream->local);
 321.445 +    stream->dtb = NIL;		/* log out the DTB */
 321.446 +  }
 321.447 +}
 321.448 +
 321.449 +
 321.450 +/* MTX mail fetch flags
 321.451 + * Accepts: MAIL stream
 321.452 + *	    sequence
 321.453 + *	    option flags
 321.454 + * Sniffs at file to see if some other process changed the flags
 321.455 + */
 321.456 +
 321.457 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
 321.458 +{
 321.459 +  unsigned long i;
 321.460 +  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
 321.461 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 321.462 +       mail_sequence (stream,sequence)))
 321.463 +    for (i = 1; i <= stream->nmsgs; i++) 
 321.464 +      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
 321.465 +}
 321.466 +
 321.467 +/* MTX mail fetch message header
 321.468 + * Accepts: MAIL stream
 321.469 + *	    message # to fetch
 321.470 + *	    pointer to returned header text length
 321.471 + *	    option flags
 321.472 + * Returns: message header in RFC822 format
 321.473 + */
 321.474 +
 321.475 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 321.476 +		  long flags)
 321.477 +{
 321.478 +  *length = 0;			/* default to empty */
 321.479 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 321.480 +				/* get to header position */
 321.481 +  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
 321.482 +				/* is buffer big enough? */
 321.483 +  if (*length > LOCAL->buflen) {
 321.484 +    fs_give ((void **) &LOCAL->buf);
 321.485 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 321.486 +  }
 321.487 +  LOCAL->buf[*length] = '\0';	/* tie off string */
 321.488 +				/* slurp the data */
 321.489 +  read (LOCAL->fd,LOCAL->buf,*length);
 321.490 +  return LOCAL->buf;
 321.491 +}
 321.492 +
 321.493 +/* MTX mail fetch message text (body only)
 321.494 + * Accepts: MAIL stream
 321.495 + *	    message # to fetch
 321.496 + *	    pointer to returned header text length
 321.497 + *	    option flags
 321.498 + * Returns: T, always
 321.499 + */
 321.500 +
 321.501 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 321.502 +{
 321.503 +  FDDATA d;
 321.504 +  unsigned long i,j;
 321.505 +  MESSAGECACHE *elt;
 321.506 +				/* UID call "impossible" */
 321.507 +  if (flags & FT_UID) return NIL;
 321.508 +  elt = mtx_elt (stream,msgno);	/* get message status */
 321.509 +				/* if message not seen */
 321.510 +  if (!(flags & FT_PEEK) && !elt->seen) {
 321.511 +    elt->seen = T;		/* mark message as seen */
 321.512 +				/* recalculate status */
 321.513 +    mtx_update_status (stream,msgno,NIL);
 321.514 +    mm_flags (stream,msgno);
 321.515 +  }
 321.516 +				/* find header position */
 321.517 +  i = mtx_hdrpos (stream,msgno,&j);
 321.518 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 321.519 +  d.pos = i + j;
 321.520 +  d.chunk = LOCAL->buf;	/* initial buffer chunk */
 321.521 +  d.chunksize = CHUNKSIZE;
 321.522 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 321.523 +  return T;			/* success */
 321.524 +}
 321.525 +
 321.526 +/* MTX mail modify flags
 321.527 + * Accepts: MAIL stream
 321.528 + *	    sequence
 321.529 + *	    flag(s)
 321.530 + *	    option flags
 321.531 + */
 321.532 +
 321.533 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 321.534 +{
 321.535 +  struct utimbuf times;
 321.536 +  struct stat sbuf;
 321.537 +  if (!stream->rdonly) {	/* make sure the update takes */
 321.538 +    fsync (LOCAL->fd);
 321.539 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 321.540 +    times.modtime = LOCAL->filetime = sbuf.st_mtime;
 321.541 +    times.actime = time (0);	/* make sure read comes after all that */
 321.542 +    utime (stream->mailbox,&times);
 321.543 +  }
 321.544 +}
 321.545 +
 321.546 +
 321.547 +/* MTX mail per-message modify flags
 321.548 + * Accepts: MAIL stream
 321.549 + *	    message cache element
 321.550 + */
 321.551 +
 321.552 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 321.553 +{
 321.554 +  struct stat sbuf;
 321.555 +				/* maybe need to do a checkpoint? */
 321.556 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 321.557 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 321.558 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 321.559 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 321.560 +  }
 321.561 +				/* recalculate status */
 321.562 +  mtx_update_status (stream,elt->msgno,NIL);
 321.563 +}
 321.564 +
 321.565 +/* MTX mail ping mailbox
 321.566 + * Accepts: MAIL stream
 321.567 + * Returns: T if stream still alive, NIL if not
 321.568 + */
 321.569 +
 321.570 +long mtx_ping (MAILSTREAM *stream)
 321.571 +{
 321.572 +  unsigned long i = 1;
 321.573 +  long r = T;
 321.574 +  int ld;
 321.575 +  char lock[MAILTMPLEN];
 321.576 +  struct stat sbuf;
 321.577 +  if (stream && LOCAL) {	/* only if stream already open */
 321.578 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 321.579 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 321.580 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 321.581 +				/* check for changed message status */
 321.582 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 321.583 +      LOCAL->filetime = sbuf.st_mtime;
 321.584 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 321.585 +	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
 321.586 +      while (i <= stream->nmsgs) mtx_elt (stream,i++);
 321.587 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 321.588 +    }
 321.589 +				/* get shared parse/append permission */
 321.590 +    if ((sbuf.st_size != LOCAL->filesize) &&
 321.591 +	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
 321.592 +				/* parse resulting mailbox */
 321.593 +      r = (mtx_parse (stream)) ? T : NIL;
 321.594 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 321.595 +    }
 321.596 +  }
 321.597 +  return r;			/* return result of the parse */
 321.598 +}
 321.599 +
 321.600 +
 321.601 +/* MTX mail check mailbox (reparses status too)
 321.602 + * Accepts: MAIL stream
 321.603 + */
 321.604 +
 321.605 +void mtx_check (MAILSTREAM *stream)
 321.606 +{
 321.607 +				/* mark that a check is desired */
 321.608 +  if (LOCAL) LOCAL->mustcheck = T;
 321.609 +  if (mtx_ping (stream)) mm_log ("Check completed",(long) NIL);
 321.610 +}
 321.611 +
 321.612 +/* MTX mail expunge mailbox
 321.613 + *	    sequence to expunge if non-NIL
 321.614 + *	    expunge options
 321.615 + * Returns: T, always
 321.616 + */
 321.617 +
 321.618 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
 321.619 +{
 321.620 +  long ret;
 321.621 +  struct utimbuf times;
 321.622 +  struct stat sbuf;
 321.623 +  off_t pos = 0;
 321.624 +  int ld;
 321.625 +  unsigned long i = 1;
 321.626 +  unsigned long j,k,m,recent;
 321.627 +  unsigned long n = 0;
 321.628 +  unsigned long delta = 0;
 321.629 +  char lock[MAILTMPLEN];
 321.630 +  MESSAGECACHE *elt;
 321.631 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 321.632 +			   mail_uid_sequence (stream,sequence) :
 321.633 +			   mail_sequence (stream,sequence)) : LONGT) &&
 321.634 +	mtx_ping (stream)));	/* parse sequence if given, ping stream */
 321.635 +  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
 321.636 +  else {
 321.637 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 321.638 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 321.639 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 321.640 +    }
 321.641 +				/* get exclusive parse/append permission */
 321.642 +    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
 321.643 +      mm_log ("Unable to lock expunge mailbox",ERROR);
 321.644 +				/* make sure see any newly-arrived messages */
 321.645 +    else if (!mtx_parse (stream));
 321.646 +				/* get exclusive access */
 321.647 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 321.648 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 321.649 +      mm_log ("Can't expunge because mailbox is in use by another process",
 321.650 +	      ERROR);
 321.651 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 321.652 +    }
 321.653 +
 321.654 +    else {
 321.655 +      mm_critical (stream);	/* go critical */
 321.656 +      recent = stream->recent;	/* get recent now that pinged and locked */
 321.657 +				/* for each message */
 321.658 +      while (i <= stream->nmsgs) {
 321.659 +				/* get cache element */
 321.660 +	elt = mtx_elt (stream,i);
 321.661 +				/* number of bytes to smash or preserve */
 321.662 +	k = elt->private.special.text.size + elt->rfc822_size;
 321.663 +				/* if need to expunge this message */
 321.664 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 321.665 +				/* if recent, note one less recent message */
 321.666 +	  if (elt->recent) --recent;
 321.667 +	  delta += k;		/* number of bytes to delete */
 321.668 +				/* notify upper levels */
 321.669 +	  mail_expunged (stream,i);
 321.670 +	  n++;			/* count up one more expunged message */
 321.671 +	}
 321.672 +	else if (i++ && delta) {/* preserved message */
 321.673 +				/* first byte to preserve */
 321.674 +	  j = elt->private.special.offset;
 321.675 +	  do {			/* read from source position */
 321.676 +	    m = min (k,LOCAL->buflen);
 321.677 +	    lseek (LOCAL->fd,j,L_SET);
 321.678 +	    read (LOCAL->fd,LOCAL->buf,m);
 321.679 +	    pos = j - delta;	/* write to destination position */
 321.680 +	    while (T) {
 321.681 +	      lseek (LOCAL->fd,pos,L_SET);
 321.682 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 321.683 +	      mm_notify (stream,strerror (errno),WARN);
 321.684 +	      mm_diskerror (stream,errno,T);
 321.685 +	    }
 321.686 +	    pos += m;		/* new position */
 321.687 +	    j += m;		/* next chunk, perhaps */
 321.688 +	  } while (k -= m);	/* until done */
 321.689 +				/* note the new address of this text */
 321.690 +	  elt->private.special.offset -= delta;
 321.691 +	}
 321.692 +				/* preserved but no deleted messages */
 321.693 +	else pos = elt->private.special.offset + k;
 321.694 +      }
 321.695 +      if (n) {			/* truncate file after last message */
 321.696 +	if (pos != (LOCAL->filesize -= delta)) {
 321.697 +	  sprintf (LOCAL->buf,
 321.698 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 321.699 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 321.700 +	  mm_log (LOCAL->buf,WARN);
 321.701 +	  LOCAL->filesize = pos;/* fix it then */
 321.702 +	}
 321.703 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 321.704 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 321.705 +				/* output the news */
 321.706 +	mm_log (LOCAL->buf,(long) NIL);
 321.707 +      }
 321.708 +      else mm_log ("No messages deleted, so no update needed",(long) NIL);
 321.709 +      fsync (LOCAL->fd);	/* force disk update */
 321.710 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 321.711 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 321.712 +      times.actime = time (0);	/* reset atime to now */
 321.713 +      utime (stream->mailbox,&times);
 321.714 +      mm_nocritical (stream);	/* release critical */
 321.715 +				/* notify upper level of new mailbox size */
 321.716 +      mail_exists (stream,stream->nmsgs);
 321.717 +      mail_recent (stream,recent);
 321.718 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 321.719 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 321.720 +    }
 321.721 +  }
 321.722 +  return ret;
 321.723 +}
 321.724 +
 321.725 +/* MTX mail copy message(s)
 321.726 + * Accepts: MAIL stream
 321.727 + *	    sequence
 321.728 + *	    destination mailbox
 321.729 + *	    copy options
 321.730 + * Returns: T if success, NIL if failed
 321.731 + */
 321.732 +
 321.733 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 321.734 +{
 321.735 +  struct stat sbuf;
 321.736 +  struct utimbuf times;
 321.737 +  MESSAGECACHE *elt;
 321.738 +  unsigned long i,j,k;
 321.739 +  long ret = LONGT;
 321.740 +  int fd,ld;
 321.741 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 321.742 +  mailproxycopy_t pc =
 321.743 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 321.744 +				/* make sure valid mailbox */
 321.745 +  if (!mtx_isvalid (mailbox,file)) switch (errno) {
 321.746 +  case ENOENT:			/* no such file? */
 321.747 +    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 321.748 +    return NIL;
 321.749 +  case 0:			/* merely empty file? */
 321.750 +    break;
 321.751 +  case EACCES:			/* file protected */
 321.752 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 321.753 +    MM_LOG (LOCAL->buf,ERROR);
 321.754 +    return NIL;
 321.755 +  case EINVAL:
 321.756 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 321.757 +    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
 321.758 +    mm_log (LOCAL->buf,ERROR);
 321.759 +    return NIL;
 321.760 +  default:
 321.761 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 321.762 +    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
 321.763 +    mm_log (LOCAL->buf,ERROR);
 321.764 +    return NIL;
 321.765 +  }
 321.766 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 321.767 +	mail_sequence (stream,sequence))) return NIL;
 321.768 +				/* got file? */
 321.769 +  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
 321.770 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
 321.771 +    mm_log (LOCAL->buf,ERROR);
 321.772 +    return NIL;
 321.773 +  }
 321.774 +  mm_critical (stream);		/* go critical */
 321.775 +				/* get exclusive parse/append permission */
 321.776 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 321.777 +    mm_log ("Unable to lock copy mailbox",ERROR);
 321.778 +    mm_nocritical (stream);
 321.779 +    return NIL;
 321.780 +  }
 321.781 +  fstat (fd,&sbuf);		/* get current file size */
 321.782 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 321.783 +
 321.784 +				/* for each requested message */
 321.785 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 321.786 +    if ((elt = mail_elt (stream,i))->sequence) {
 321.787 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 321.788 +				/* number of bytes to copy */
 321.789 +      k = elt->private.special.text.size + elt->rfc822_size;
 321.790 +      do {			/* read from source position */
 321.791 +	j = min (k,LOCAL->buflen);
 321.792 +	read (LOCAL->fd,LOCAL->buf,j);
 321.793 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 321.794 +      } while (ret && (k -= j));/* until done */
 321.795 +    }
 321.796 +				/* make sure all the updates take */
 321.797 +  if (!(ret && (ret = !fsync (fd)))) {
 321.798 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 321.799 +    mm_log (LOCAL->buf,ERROR);
 321.800 +    ftruncate (fd,sbuf.st_size);
 321.801 +  }
 321.802 +				/* set atime to now-1 if successful copy */
 321.803 +  if (ret) times.actime = time (0) - 1;
 321.804 +				/* else preserved \Marked status */
 321.805 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 321.806 +	 sbuf.st_atime : time (0);
 321.807 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 321.808 +  utime (file,&times);		/* set the times */
 321.809 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 321.810 +  close (fd);			/* close the file */
 321.811 +  mm_nocritical (stream);	/* release critical */
 321.812 +				/* delete all requested messages */
 321.813 +  if (ret && (options & CP_MOVE)) {
 321.814 +    for (i = 1; i <= stream->nmsgs; i++)
 321.815 +      if ((elt = mtx_elt (stream,i))->sequence) {
 321.816 +	elt->deleted = T;	/* mark message deleted */
 321.817 +				/* recalculate status */
 321.818 +	mtx_update_status (stream,i,NIL);
 321.819 +      }
 321.820 +    if (!stream->rdonly) {	/* make sure the update takes */
 321.821 +      fsync (LOCAL->fd);
 321.822 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 321.823 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 321.824 +      times.actime = time (0);	/* make sure atime remains greater */
 321.825 +      utime (stream->mailbox,&times);
 321.826 +    }
 321.827 +  }
 321.828 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 321.829 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
 321.830 +  return ret;
 321.831 +}
 321.832 +
 321.833 +/* MTX mail append message from stringstruct
 321.834 + * Accepts: MAIL stream
 321.835 + *	    destination mailbox
 321.836 + *	    append callback
 321.837 + *	    data for callback
 321.838 + * Returns: T if append successful, else NIL
 321.839 + */
 321.840 +
 321.841 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 321.842 +{
 321.843 +  struct stat sbuf;
 321.844 +  int fd,ld,c;
 321.845 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 321.846 +  struct utimbuf times;
 321.847 +  FILE *df;
 321.848 +  MESSAGECACHE elt;
 321.849 +  long f;
 321.850 +  unsigned long i,uf;
 321.851 +  STRING *message;
 321.852 +  long ret = LONGT;
 321.853 +				/* default stream to prototype */
 321.854 +  if (!stream) stream = &mtxproto;
 321.855 +				/* make sure valid mailbox */
 321.856 +  if (!mtx_isvalid (mailbox,file)) switch (errno) {
 321.857 +  case ENOENT:			/* no such file? */
 321.858 +    if (!compare_cstring (mailbox,"INBOX")) mtx_create (NIL,"INBOX");
 321.859 +    else {
 321.860 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 321.861 +      return NIL;
 321.862 +    }
 321.863 +				/* falls through */
 321.864 +  case 0:			/* merely empty file? */
 321.865 +    break;
 321.866 +  case EACCES:			/* file protected */
 321.867 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 321.868 +    MM_LOG (tmp,ERROR);
 321.869 +    return NIL;
 321.870 +  case EINVAL:
 321.871 +    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
 321.872 +    mm_log (tmp,ERROR);
 321.873 +    return NIL;
 321.874 +  default:
 321.875 +    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
 321.876 +    mm_log (tmp,ERROR);
 321.877 +    return NIL;
 321.878 +  }
 321.879 +				/* get first message */
 321.880 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
 321.881 +
 321.882 +				/* open destination mailbox */
 321.883 +  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
 321.884 +       < 0) || !(df = fdopen (fd,"ab"))) {
 321.885 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
 321.886 +    mm_log (tmp,ERROR);
 321.887 +    return NIL;
 321.888 +  }
 321.889 +				/* get parse/append permission */
 321.890 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 321.891 +    mm_log ("Unable to lock append mailbox",ERROR);
 321.892 +    close (fd);
 321.893 +    return NIL;
 321.894 +  }
 321.895 +  mm_critical (stream);		/* go critical */
 321.896 +  fstat (fd,&sbuf);		/* get current file size */
 321.897 +  errno = 0;
 321.898 +  do {				/* parse flags */
 321.899 +    if (!SIZE (message)) {	/* guard against zero-length */
 321.900 +      mm_log ("Append of zero-length message",ERROR);
 321.901 +      ret = NIL;
 321.902 +      break;
 321.903 +    }
 321.904 +    f = mail_parse_flags (stream,flags,&i);
 321.905 +				/* reverse bits (dontcha wish we had CIRC?) */
 321.906 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
 321.907 +    if (date) {			/* parse date if given */
 321.908 +      if (!mail_parse_date (&elt,date)) {
 321.909 +	sprintf (tmp,"Bad date in append: %.80s",date);
 321.910 +	mm_log (tmp,ERROR);
 321.911 +	ret = NIL;		/* mark failure */
 321.912 +	break;
 321.913 +      }
 321.914 +      mail_date (tmp,&elt);	/* write preseved date */
 321.915 +    }
 321.916 +    else internal_date (tmp);	/* get current date in IMAP format */
 321.917 +				/* write header */
 321.918 +    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
 321.919 +		 (unsigned long) f) < 0) ret = NIL;
 321.920 +    else {			/* write message */
 321.921 +      if (i) do c = 0xff & SNX (message);
 321.922 +      while ((putc (c,df) != EOF) && --i);
 321.923 +				/* get next message */
 321.924 +      if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
 321.925 +    }
 321.926 +  } while (ret && message);
 321.927 +				/* if error... */
 321.928 +  if (!ret || (fflush (df) == EOF)) {
 321.929 +    ftruncate (fd,sbuf.st_size);/* revert file */
 321.930 +    close (fd);			/* make sure fclose() doesn't corrupt us */
 321.931 +    if (errno) {
 321.932 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
 321.933 +      mm_log (tmp,ERROR);
 321.934 +    }
 321.935 +    ret = NIL;
 321.936 +  }
 321.937 +  if (ret) times.actime = time (0) - 1;
 321.938 +				/* else preserved \Marked status */
 321.939 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 321.940 +	 sbuf.st_atime : time (0);
 321.941 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 321.942 +  utime (file,&times);		/* set the times */
 321.943 +  fclose (df);			/* close the file */
 321.944 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 321.945 +  mm_nocritical (stream);	/* release critical */
 321.946 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
 321.947 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
 321.948 +	    WARN);
 321.949 +  return ret;
 321.950 +}
 321.951 +
 321.952 +/* Internal routines */
 321.953 +
 321.954 +
 321.955 +/* MTX mail parse mailbox
 321.956 + * Accepts: MAIL stream
 321.957 + * Returns: T if parse OK
 321.958 + *	    NIL if failure, stream aborted
 321.959 + */
 321.960 +
 321.961 +long mtx_parse (MAILSTREAM *stream)
 321.962 +{
 321.963 +  struct stat sbuf;
 321.964 +  MESSAGECACHE *elt = NIL;
 321.965 +  unsigned char c,*s,*t,*x;
 321.966 +  char tmp[MAILTMPLEN];
 321.967 +  unsigned long i,j;
 321.968 +  long curpos = LOCAL->filesize;
 321.969 +  long nmsgs = stream->nmsgs;
 321.970 +  long recent = stream->recent;
 321.971 +  short added = NIL;
 321.972 +  short silent = stream->silent;
 321.973 +  fstat (LOCAL->fd,&sbuf);	/* get status */
 321.974 +  if (sbuf.st_size < curpos) {	/* sanity check */
 321.975 +    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
 321.976 +    mm_log (tmp,ERROR);
 321.977 +    mtx_close (stream,NIL);
 321.978 +    return NIL;
 321.979 +  }
 321.980 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
 321.981 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
 321.982 +				/* get to that position in the file */
 321.983 +    lseek (LOCAL->fd,curpos,L_SET);
 321.984 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
 321.985 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
 321.986 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
 321.987 +	       i ? strerror (errno) : "no data read");
 321.988 +      mm_log (tmp,ERROR);
 321.989 +      mtx_close (stream,NIL);
 321.990 +      return NIL;
 321.991 +    }
 321.992 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
 321.993 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
 321.994 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
 321.995 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
 321.996 +      mm_log (tmp,ERROR);
 321.997 +      mtx_close (stream,NIL);
 321.998 +      return NIL;
 321.999 +    }
321.1000 +    *s = '\0';			/* tie off header line */
321.1001 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
321.1002 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
321.1003 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
321.1004 +	       (unsigned long) curpos,(char *) LOCAL->buf);
321.1005 +      mm_log (tmp,ERROR);
321.1006 +      mtx_close (stream,NIL);
321.1007 +      return NIL;
321.1008 +    }
321.1009 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
321.1010 +
321.1011 +    added = T;			/* note that a new message was added */
321.1012 +				/* swell the cache */
321.1013 +    mail_exists (stream,++nmsgs);
321.1014 +				/* instantiate an elt for this message */
321.1015 +    (elt = mail_elt (stream,nmsgs))->valid = T;
321.1016 +    elt->private.uid = ++stream->uid_last;
321.1017 +				/* note file offset of header */
321.1018 +    elt->private.special.offset = curpos;
321.1019 +				/* in case error */
321.1020 +    elt->private.special.text.size = 0;
321.1021 +				/* header size not known yet */
321.1022 +    elt->private.msg.header.text.size = 0;
321.1023 +    x = s;			/* parse the header components */
321.1024 +    if (mail_parse_date (elt,LOCAL->buf) &&
321.1025 +	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
321.1026 +	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
321.1027 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
321.1028 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
321.1029 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
321.1030 +      elt->private.special.text.size = i;
321.1031 +    else {			/* oops */
321.1032 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
321.1033 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
321.1034 +      mm_log (tmp,ERROR);
321.1035 +      mtx_close (stream,NIL);
321.1036 +      return NIL;
321.1037 +    }
321.1038 +				/* make sure didn't run off end of file */
321.1039 +    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
321.1040 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
321.1041 +	       elt->private.special.offset,(unsigned long) curpos,
321.1042 +	       (unsigned long) sbuf.st_size);
321.1043 +      mm_log (tmp,ERROR);
321.1044 +      mtx_close (stream,NIL);
321.1045 +      return NIL;
321.1046 +    }
321.1047 +    c = t[10];			/* remember first system flags byte */
321.1048 +    t[10] = '\0';		/* tie off flags */
321.1049 +    j = strtoul (t,NIL,8);	/* get user flags value */
321.1050 +    t[10] = c;			/* restore first system flags byte */
321.1051 +				/* set up all valid user flags (reversed!) */
321.1052 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
321.1053 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
321.1054 +				/* calculate system flags */
321.1055 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
321.1056 +    if (j & fDELETED) elt->deleted = T;
321.1057 +    if (j & fFLAGGED) elt->flagged = T;
321.1058 +    if (j & fANSWERED) elt->answered = T;
321.1059 +    if (j & fDRAFT) elt->draft = T;
321.1060 +    if (!(j & fOLD)) {		/* newly arrived message? */
321.1061 +      elt->recent = T;
321.1062 +      recent++;			/* count up a new recent message */
321.1063 +				/* mark it as old */
321.1064 +      mtx_update_status (stream,nmsgs,NIL);
321.1065 +    }
321.1066 +  }
321.1067 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
321.1068 +				/* update parsed file size and time */
321.1069 +  LOCAL->filesize = sbuf.st_size;
321.1070 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
321.1071 +  LOCAL->filetime = sbuf.st_mtime;
321.1072 +  if (added && !stream->rdonly){/* make sure atime updated */
321.1073 +    struct utimbuf times;
321.1074 +    times.actime = time (0);
321.1075 +    times.modtime = LOCAL->filetime;
321.1076 +    utime (stream->mailbox,&times);
321.1077 +  }
321.1078 +  stream->silent = silent;	/* can pass up events now */
321.1079 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
321.1080 +  mail_recent (stream,recent);	/* and of change in recent messages */
321.1081 +  return LONGT;			/* return the winnage */
321.1082 +}
321.1083 +
321.1084 +/* MTX get cache element with status updating from file
321.1085 + * Accepts: MAIL stream
321.1086 + *	    message number
321.1087 + * Returns: cache element
321.1088 + */
321.1089 +
321.1090 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
321.1091 +{
321.1092 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
321.1093 +  struct {			/* old flags */
321.1094 +    unsigned int seen : 1;
321.1095 +    unsigned int deleted : 1;
321.1096 +    unsigned int flagged : 1;
321.1097 +    unsigned int answered : 1;
321.1098 +    unsigned int draft : 1;
321.1099 +    unsigned long user_flags;
321.1100 +  } old;
321.1101 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
321.1102 +  old.answered = elt->answered; old.draft = elt->draft;
321.1103 +  old.user_flags = elt->user_flags;
321.1104 +  mtx_read_flags (stream,elt);
321.1105 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
321.1106 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
321.1107 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
321.1108 +    mm_flags (stream,msgno);	/* let top level know */
321.1109 +  return elt;
321.1110 +}
321.1111 +
321.1112 +/* MTX read flags from file
321.1113 + * Accepts: MAIL stream
321.1114 + * Returns: cache element
321.1115 + */
321.1116 +
321.1117 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
321.1118 +{
321.1119 +  unsigned long i,j;
321.1120 +				/* noop if readonly and have valid flags */
321.1121 +  if (stream->rdonly && elt->valid) return;
321.1122 +				/* set the seek pointer */
321.1123 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
321.1124 +	 elt->private.special.text.size - 14,L_SET);
321.1125 +				/* read the new flags */
321.1126 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
321.1127 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
321.1128 +    fatal (LOCAL->buf);
321.1129 +  }
321.1130 +				/* calculate system flags */
321.1131 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
321.1132 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
321.1133 +  elt->flagged = i & fFLAGGED ? T : NIL;
321.1134 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
321.1135 +  LOCAL->buf[10] = '\0';	/* tie off flags */
321.1136 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
321.1137 +				/* set up all valid user flags (reversed!) */
321.1138 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
321.1139 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
321.1140 +  elt->valid = T;		/* have valid flags now */
321.1141 +}
321.1142 +
321.1143 +/* MTX update status string
321.1144 + * Accepts: MAIL stream
321.1145 + *	    message number
321.1146 + *	    flag saying whether or not to sync
321.1147 + */
321.1148 +
321.1149 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
321.1150 +{
321.1151 +  struct utimbuf times;
321.1152 +  struct stat sbuf;
321.1153 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
321.1154 +  unsigned long j,k = 0;
321.1155 +				/* readonly */
321.1156 +  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
321.1157 +  else {			/* readwrite */
321.1158 +    j = elt->user_flags;	/* get user flags */
321.1159 +				/* reverse bits (dontcha wish we had CIRC?) */
321.1160 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
321.1161 +				/* print new flag string */
321.1162 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
321.1163 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
321.1164 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
321.1165 +	      (fDRAFT * elt->draft)));
321.1166 +    while (T) {			/* get to that place in the file */
321.1167 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
321.1168 +	     elt->private.special.text.size - 14,L_SET);
321.1169 +				/* write new flags */
321.1170 +      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
321.1171 +      mm_notify (stream,strerror (errno),WARN);
321.1172 +      mm_diskerror (stream,errno,T);
321.1173 +    }
321.1174 +    if (syncflag) {		/* sync if requested */
321.1175 +      fsync (LOCAL->fd);
321.1176 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
321.1177 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
321.1178 +      times.actime = time (0);	/* make sure read is later */
321.1179 +      utime (stream->mailbox,&times);
321.1180 +    }
321.1181 +  }
321.1182 +}
321.1183 +
321.1184 +/* MTX locate header for a message
321.1185 + * Accepts: MAIL stream
321.1186 + *	    message number
321.1187 + *	    pointer to returned header size
321.1188 + * Returns: position of header in file
321.1189 + */
321.1190 +
321.1191 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
321.1192 +			  unsigned long *size)
321.1193 +{
321.1194 +  unsigned long siz;
321.1195 +  long i = 0;
321.1196 +  int q = 0;
321.1197 +  char *s,tmp[MAILTMPLEN];
321.1198 +  MESSAGECACHE *elt = mtx_elt (stream,msgno);
321.1199 +  unsigned long ret = elt->private.special.offset +
321.1200 +    elt->private.special.text.size;
321.1201 +				/* is header size known? */
321.1202 +  if (!(*size = elt->private.msg.header.text.size)) {
321.1203 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
321.1204 +				/* search message for CRLF CRLF */
321.1205 +    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
321.1206 +				/* read another buffer as necessary */
321.1207 +      if ((--i <= 0) &&		/* buffer empty? */
321.1208 +	  (read (LOCAL->fd,s = tmp,
321.1209 +		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
321.1210 +	return ret;		/* I/O error? */
321.1211 +      switch (q) {		/* sniff at buffer */
321.1212 +      case 0:			/* first character */
321.1213 +	q = (*s++ == '\015') ? 1 : 0;
321.1214 +	break;
321.1215 +      case 1:			/* second character */
321.1216 +	q = (*s++ == '\012') ? 2 : 0;
321.1217 +	break;
321.1218 +      case 2:			/* third character */
321.1219 +	q = (*s++ == '\015') ? 3 : 0;
321.1220 +	break;
321.1221 +      case 3:			/* fourth character */
321.1222 +	if (*s++ == '\012') {	/* have the sequence? */
321.1223 +				/* yes, note for later */
321.1224 +	  elt->private.msg.header.text.size = *size = siz;
321.1225 +	  return ret;
321.1226 +	}
321.1227 +	q = 0;			/* lost... */
321.1228 +	break;
321.1229 +      }
321.1230 +    }
321.1231 +				/* header consumes entire message */
321.1232 +    elt->private.msg.header.text.size = *size = elt->rfc822_size;
321.1233 +  }
321.1234 +  return ret;
321.1235 +}
   322.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   322.2 +++ b/src/osdep/os2/nl_os2.c	Mon Sep 14 15:17:45 2009 +0900
   322.3 @@ -0,0 +1,61 @@
   322.4 +/* ========================================================================
   322.5 + * Copyright 1988-2006 University of Washington
   322.6 + *
   322.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   322.8 + * you may not use this file except in compliance with the License.
   322.9 + * You may obtain a copy of the License at
  322.10 + *
  322.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  322.12 + *
  322.13 + * 
  322.14 + * ========================================================================
  322.15 + */
  322.16 +
  322.17 +/*
  322.18 + * Program:	Windows/TOPS-20 newline routines
  322.19 + *
  322.20 + * Author:	Mark Crispin
  322.21 + *		Networks and Distributed Computing
  322.22 + *		Computing & Communications
  322.23 + *		University of Washington
  322.24 + *		Administration Building, AG-44
  322.25 + *		Seattle, WA  98195
  322.26 + *		Internet: MRC@CAC.Washington.EDU
  322.27 + *
  322.28 + * Date:	1 August 1988
  322.29 + * Last Edited:	30 August 2006
  322.30 + */
  322.31 +
  322.32 +/* Copy string with CRLF newlines
  322.33 + * Accepts: destination string
  322.34 + *	    pointer to size of destination string buffer
  322.35 + *	    source string
  322.36 + *	    length of source string
  322.37 + * Returns: length of copied string
  322.38 + */
  322.39 +
  322.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  322.41 +			  unsigned char *src,unsigned long srcl)
  322.42 +{
  322.43 +				/* flush destination buffer if too small */
  322.44 +  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
  322.45 +  if (!*dst) {			/* make a new buffer if needed */
  322.46 +    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
  322.47 +    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
  322.48 +  }
  322.49 +				/* copy strings */
  322.50 +  if (srcl) memcpy (*dst,src,(size_t) srcl);
  322.51 +  *(*dst + srcl) = '\0';	/* tie off destination */
  322.52 +  return srcl;			/* return length */
  322.53 +}
  322.54 +
  322.55 +
  322.56 +/* Length of string after strcrlfcpy applied
  322.57 + * Accepts: source string
  322.58 + * Returns: length of string
  322.59 + */
  322.60 +
  322.61 +unsigned long strcrlflen (STRING *s)
  322.62 +{
  322.63 +  return SIZE (s);		/* no-brainer on DOS! */
  322.64 +}
   323.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   323.2 +++ b/src/osdep/os2/os_os2.c	Mon Sep 14 15:17:45 2009 +0900
   323.3 @@ -0,0 +1,100 @@
   323.4 +/* ========================================================================
   323.5 + * Copyright 1988-2006 University of Washington
   323.6 + *
   323.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   323.8 + * you may not use this file except in compliance with the License.
   323.9 + * You may obtain a copy of the License at
  323.10 + *
  323.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  323.12 + *
  323.13 + * 
  323.14 + * ========================================================================
  323.15 + */
  323.16 +
  323.17 +/*
  323.18 + * Program:	Operating-system dependent routines -- OS/2 emx version
  323.19 + *
  323.20 + * Author:	Mark Crispin
  323.21 + *		Networks and Distributed Computing
  323.22 + *		Computing & Communications
  323.23 + *		University of Washington
  323.24 + *		Administration Building, AG-44
  323.25 + *		Seattle, WA  98195
  323.26 + *		Internet: MRC@CAC.Washington.EDU
  323.27 + *
  323.28 + * Date:	14 March 1996
  323.29 + * Last Edited:	30 August 2006
  323.30 + */
  323.31 +
  323.32 +#include <stdio.h>
  323.33 +#include <time.h>
  323.34 +#include <sys/time.h>
  323.35 +#include <sys/types.h>
  323.36 +#include <sys/stat.h>
  323.37 +#include <sys/socket.h>
  323.38 +#include <netinet/in.h>
  323.39 +#include <arpa/inet.h>
  323.40 +#include <netdb.h>
  323.41 +#include <ctype.h>
  323.42 +#include <errno.h>
  323.43 +extern int errno;		/* just in case */
  323.44 +#include "tcp_os2.h"		/* must be before osdep includes tcp.h */
  323.45 +#include "mail.h"
  323.46 +#include "osdep.h"
  323.47 +#include "misc.h"
  323.48 +#include "fs_os2.c"
  323.49 +#include "ftl_os2.c"
  323.50 +#include "nl_os2.c"
  323.51 +#include "env_os2.c"
  323.52 +#include "tcp_os2.c"
  323.53 +
  323.54 +/* Return my local host name
  323.55 + * Returns: my local host name
  323.56 + */
  323.57 +
  323.58 +char *mylocalhost (void)
  323.59 +{
  323.60 +  if (!myLocalHost) {		/* known yet? */
  323.61 +    char *s,tmp[MAILTMPLEN];
  323.62 +    struct hostent *he;
  323.63 +				/* could we get local id? */
  323.64 +    gethostname (tmp,MAILTMPLEN-1);
  323.65 +    if (he = gethostbyname (lcase (tmp))) {
  323.66 +      if (he->h_name) s = he->h_name;
  323.67 +      else sprintf (s = tmp,"[%i.%i.%i.%i]",he->h_addr[0],he->h_addr[1],
  323.68 +		    he->h_addr[2],he->h_addr[3]);
  323.69 +    }
  323.70 +    else s = "random-pc";
  323.71 +    myLocalHost = cpystr (s);	/* record for subsequent use */
  323.72 +  }
  323.73 +  return myLocalHost;
  323.74 +}
  323.75 +
  323.76 +
  323.77 +/* Look up host address
  323.78 + * Accepts: pointer to pointer to host name
  323.79 + *	    socket address block
  323.80 + * Returns: non-zero with host address in socket, official host name in host;
  323.81 + *	    else NIL
  323.82 + */
  323.83 +
  323.84 +long lookuphost (char **host,struct sockaddr_in *sin)
  323.85 +{
  323.86 +  long ret = -1;
  323.87 +  char tmp[MAILTMPLEN];
  323.88 +  struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
  323.89 +  if (!hn) return NIL;		/* got a host name? */
  323.90 +  *host = cpystr (hn->h_name);	/* set official name */
  323.91 +				/* copy host addresses */
  323.92 +  memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
  323.93 +  return T;
  323.94 +}
  323.95 +
  323.96 +
  323.97 +/*
  323.98 + * Emulator for BSD syslog() routine.
  323.99 + */
 323.100 +
 323.101 +void syslog (int priority,const char *message,...)
 323.102 +{
 323.103 +}
   324.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   324.2 +++ b/src/osdep/os2/os_os2.h	Mon Sep 14 15:17:45 2009 +0900
   324.3 @@ -0,0 +1,38 @@
   324.4 +/* ========================================================================
   324.5 + * Copyright 1988-2006 University of Washington
   324.6 + *
   324.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   324.8 + * you may not use this file except in compliance with the License.
   324.9 + * You may obtain a copy of the License at
  324.10 + *
  324.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  324.12 + *
  324.13 + * 
  324.14 + * ========================================================================
  324.15 + */
  324.16 +
  324.17 +/*
  324.18 + * Program:	Operating-system dependent routines -- OS/2 emx version
  324.19 + *
  324.20 + * Author:	Mark Crispin
  324.21 + *		Networks and Distributed Computing
  324.22 + *		Computing & Communications
  324.23 + *		University of Washington
  324.24 + *		Administration Building, AG-44
  324.25 + *		Seattle, WA  98195
  324.26 + *		Internet: MRC@CAC.Washington.EDU
  324.27 + *
  324.28 + * Date:	14 March 1996
  324.29 + * Last Edited:	30 August 2006
  324.30 + */
  324.31 +
  324.32 +
  324.33 +#include <stdlib.h>
  324.34 +#include <string.h>
  324.35 +#include <unistd.h>
  324.36 +#include <sys/types.h>
  324.37 +#include "env_os2.h"
  324.38 +#include "fs.h"
  324.39 +#include "ftl.h"
  324.40 +#include "nl.h"
  324.41 +#include "tcp.h"
   325.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   325.2 +++ b/src/osdep/os2/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   325.3 @@ -0,0 +1,89 @@
   325.4 +/* ========================================================================
   325.5 + * Copyright 1988-2006 University of Washington
   325.6 + *
   325.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   325.8 + * you may not use this file except in compliance with the License.
   325.9 + * You may obtain a copy of the License at
  325.10 + *
  325.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  325.12 + *
  325.13 + * 
  325.14 + * ========================================================================
  325.15 + */
  325.16 +
  325.17 +/*
  325.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  325.19 + *
  325.20 + * Author:	Mark Crispin
  325.21 + *		Networks and Distributed Computing
  325.22 + *		Computing & Communications
  325.23 + *		University of Washington
  325.24 + *		Administration Building, AG-44
  325.25 + *		Seattle, WA  98195
  325.26 + *		Internet: MRC@CAC.Washington.EDU
  325.27 + *
  325.28 + * Date:	15 June 2000
  325.29 + * Last Edited:	30 August 2006
  325.30 + */
  325.31 +
  325.32 +/* Wildcard pattern match
  325.33 + * Accepts: base string
  325.34 + *	    pattern string
  325.35 + *	    delimiter character
  325.36 + * Returns: T if pattern matches base, else NIL
  325.37 + */
  325.38 +
  325.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  325.40 +{
  325.41 +  switch (*pat) {
  325.42 +  case '%':			/* non-recursive */
  325.43 +				/* % at end, OK if no inferiors */
  325.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  325.45 +                                /* scan remainder of string until delimiter */
  325.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  325.47 +    while ((*s != delim) && *s++);
  325.48 +    break;
  325.49 +  case '*':			/* match 0 or more characters */
  325.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  325.51 +				/* scan remainder of string */
  325.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  325.53 +    while (*s++);
  325.54 +    break;
  325.55 +  case '\0':			/* end of pattern */
  325.56 +    return *s ? NIL : T;	/* success if also end of base */
  325.57 +  default:			/* match this character */
  325.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  325.59 +  }
  325.60 +  return NIL;
  325.61 +}
  325.62 +
  325.63 +/* Directory pattern match
  325.64 + * Accepts: base string
  325.65 + *	    pattern string
  325.66 + *	    delimiter character
  325.67 + * Returns: T if base is a matching directory of pattern, else NIL
  325.68 + */
  325.69 +
  325.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  325.71 +{
  325.72 +  switch (*pat) {
  325.73 +  case '%':			/* non-recursive */
  325.74 +    if (!*s) return T;		/* end of base means have a subset match */
  325.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  325.76 +				/* scan remainder of string until delimiter */
  325.77 +    do if (dmatch (s,pat,delim)) return T;
  325.78 +    while ((*s != delim) && *s++);
  325.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  325.80 +    return dmatch (s,pat,delim);/* do new scan */
  325.81 +  case '*':			/* match 0 or more characters */
  325.82 +    return T;			/* unconditional match */
  325.83 +  case '\0':			/* end of pattern */
  325.84 +    break;
  325.85 +  default:			/* match this character */
  325.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  325.87 +				/* end of base, return if at delimiter */
  325.88 +    else if (*pat == delim) return T;
  325.89 +    break;
  325.90 +  }
  325.91 +  return NIL;
  325.92 +}
   326.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   326.2 +++ b/src/osdep/os2/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
   326.3 @@ -0,0 +1,36 @@
   326.4 +/* ========================================================================
   326.5 + * Copyright 1988-2006 University of Washington
   326.6 + *
   326.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   326.8 + * you may not use this file except in compliance with the License.
   326.9 + * You may obtain a copy of the License at
  326.10 + *
  326.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  326.12 + *
  326.13 + * 
  326.14 + * ========================================================================
  326.15 + */
  326.16 +
  326.17 +/*
  326.18 + * Program:	Pseudo Header Strings
  326.19 + *
  326.20 + * Author:	Mark Crispin
  326.21 + *		Networks and Distributed Computing
  326.22 + *		Computing & Communications
  326.23 + *		University of Washington
  326.24 + *		Administration Building, AG-44
  326.25 + *		Seattle, WA  98195
  326.26 + *		Internet: MRC@CAC.Washington.EDU
  326.27 + *
  326.28 + * Date:	26 September 1996
  326.29 + * Last Edited:	30 August 2006
  326.30 + */
  326.31 +
  326.32 +/* Local sites may wish to alter this text */
  326.33 +
  326.34 +char *pseudo_from = "MAILER-DAEMON";
  326.35 +char *pseudo_name = "Mail System Internal Data";
  326.36 +char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
  326.37 +char *pseudo_msg =
  326.38 +  "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."
  326.39 +  ;
   327.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   327.2 +++ b/src/osdep/os2/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
   327.3 @@ -0,0 +1,30 @@
   327.4 +/* ========================================================================
   327.5 + * Copyright 1988-2006 University of Washington
   327.6 + *
   327.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   327.8 + * you may not use this file except in compliance with the License.
   327.9 + * You may obtain a copy of the License at
  327.10 + *
  327.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  327.12 + *
  327.13 + * 
  327.14 + * ========================================================================
  327.15 + */
  327.16 +
  327.17 +/*
  327.18 + * Program:	Pseudo Header Strings
  327.19 + *
  327.20 + * Author:	Mark Crispin
  327.21 + *		Networks and Distributed Computing
  327.22 + *		Computing & Communications
  327.23 + *		University of Washington
  327.24 + *		Administration Building, AG-44
  327.25 + *		Seattle, WA  98195
  327.26 + *		Internet: MRC@CAC.Washington.EDU
  327.27 + *
  327.28 + * Date:	26 September 1996
  327.29 + * Last Edited:	30 August 2006
  327.30 + */
  327.31 +
  327.32 +
  327.33 +extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
   328.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   328.2 +++ b/src/osdep/os2/setproto.cmd	Mon Sep 14 15:17:45 2009 +0900
   328.3 @@ -0,0 +1,34 @@
   328.4 +/* rexx */
   328.5 +/* ========================================================================
   328.6 + * Copyright 1988-2006 University of Washington
   328.7 + *
   328.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   328.9 + * you may not use this file except in compliance with the License.
  328.10 + * You may obtain a copy of the License at
  328.11 + *
  328.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  328.13 + *
  328.14 + * 
  328.15 + * ========================================================================
  328.16 + */
  328.17 +/*
  328.18 + * Program:	Set default prototype for OS/2
  328.19 + *
  328.20 + * Author:	Mark Crispin
  328.21 + *		Networks and Distributed Computing
  328.22 + *		Computing & Communications
  328.23 + *		University of Washington
  328.24 + *		Administration Building, AG-44
  328.25 + *		Seattle, WA  98195
  328.26 + *		Internet: MRC@CAC.Washington.EDU
  328.27 + *
  328.28 + * Date:	10 June 1999
  328.29 + * Last Edited:	30 August 2006
  328.30 + */
  328.31 +'@echo off'
  328.32 +parse arg default args
  328.33 +h_file='linkage.h'
  328.34 +call stream h_file, 'C', 'open write'
  328.35 +call lineout h_file, '#define DEFAULTPROTO' default'proto'
  328.36 +call stream h_file, 'C', 'close'
  328.37 +exit 0
   329.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   329.2 +++ b/src/osdep/os2/tcp_os2.c	Mon Sep 14 15:17:45 2009 +0900
   329.3 @@ -0,0 +1,434 @@
   329.4 +/* ========================================================================
   329.5 + * Copyright 1988-2008 University of Washington
   329.6 + *
   329.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   329.8 + * you may not use this file except in compliance with the License.
   329.9 + * You may obtain a copy of the License at
  329.10 + *
  329.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  329.12 + *
  329.13 + * 
  329.14 + * ========================================================================
  329.15 + */
  329.16 +
  329.17 +/*
  329.18 + * Program:	MS-DOS TCP/IP routines
  329.19 + *
  329.20 + * Author:	Mark Crispin
  329.21 + *		Networks and Distributed Computing
  329.22 + *		Computing & Communications
  329.23 + *		University of Washington
  329.24 + *		Administration Building, AG-44
  329.25 + *		Seattle, WA  98195
  329.26 + *		Internet: MRC@CAC.Washington.EDU
  329.27 + *
  329.28 + * Date:	11 April 1989
  329.29 + * Last Edited:	13 January 2008
  329.30 + */
  329.31 +
  329.32 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  329.33 +static long ttmo_read = 0;	/* TCP timeouts, in seconds */
  329.34 +static long ttmo_write = 0;
  329.35 +
  329.36 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  329.37 +			       long *contd);
  329.38 +
  329.39 +/* TCP/IP manipulate parameters
  329.40 + * Accepts: function code
  329.41 + *	    function-dependent value
  329.42 + * Returns: function-dependent return value
  329.43 + */
  329.44 +
  329.45 +void *tcp_parameters (long function,void *value)
  329.46 +{
  329.47 +  void *ret = NIL;
  329.48 +  switch ((int) function) {
  329.49 +  case SET_TIMEOUT:
  329.50 +    tmoh = (tcptimeout_t) value;
  329.51 +  case GET_TIMEOUT:
  329.52 +    ret = (void *) tmoh;
  329.53 +    break;
  329.54 +  case SET_READTIMEOUT:
  329.55 +    ttmo_read = (long) value;
  329.56 +  case GET_READTIMEOUT:
  329.57 +    ret = (void *) ttmo_read;
  329.58 +    break;
  329.59 +  case SET_WRITETIMEOUT:
  329.60 +    ttmo_write = (long) value;
  329.61 +  case GET_WRITETIMEOUT:
  329.62 +    ret = (void *) ttmo_write;
  329.63 +    break;
  329.64 +  }
  329.65 +  return ret;
  329.66 +}
  329.67 +
  329.68 +/* TCP/IP open
  329.69 + * Accepts: host name
  329.70 + *	    contact service name
  329.71 + *	    contact port number
  329.72 + * Returns: TCP/IP stream if success else NIL
  329.73 + */
  329.74 +
  329.75 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  329.76 +{
  329.77 +  TCPSTREAM *stream = NIL;
  329.78 +  struct sockaddr_in sin;
  329.79 +  int sock;
  329.80 +  char *s,tmp[MAILTMPLEN];
  329.81 +  port &= 0xffff;		/* erase flags */
  329.82 +  /* The domain literal form is used (rather than simply the dotted decimal
  329.83 +     as with other Unix programs) because it has to be a valid "host name"
  329.84 +     in mailsystem terminology. */
  329.85 +  sin.sin_family = AF_INET;	/* family is always Internet */
  329.86 +				/* look like domain literal? */
  329.87 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  329.88 +    strcpy (tmp,host+1);	/* yes, copy number part */
  329.89 +    tmp[strlen (tmp)-1] = '\0';
  329.90 +    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
  329.91 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
  329.92 +      mm_log (tmp,ERROR);
  329.93 +      return NIL;
  329.94 +    }
  329.95 +  }
  329.96 +				/* look up host name */
  329.97 +  else if (!lookuphost (&host,&sin)) {
  329.98 +    sprintf (tmp,"Host not found: %s",host);
  329.99 +    mm_log (tmp,ERROR);
 329.100 +    return NIL;
 329.101 +  }
 329.102 +
 329.103 +				/* copy port number in network format */
 329.104 +  if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
 329.105 +				/* get a TCP stream */
 329.106 +  if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
 329.107 +    sprintf (tmp,"Unable to create TCP socket (%d)",errno);
 329.108 +    mm_log (tmp,ERROR);
 329.109 +    fs_give ((void **) &host);
 329.110 +    return NIL;
 329.111 +  }
 329.112 +#if 0
 329.113 +  /* needed? */
 329.114 +  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
 329.115 +    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
 329.116 +	     sock,FD_SETSIZE);
 329.117 +    close (sock);
 329.118 +    errno = ENOBUFS;		/* just in case */
 329.119 +    return NIL;
 329.120 +  }
 329.121 +#endif
 329.122 +				/* open connection */
 329.123 +  if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
 329.124 +    switch (errno) {		/* analyze error */
 329.125 +    case ECONNREFUSED:
 329.126 +      s = "Refused";
 329.127 +      break;
 329.128 +    case ENOBUFS:
 329.129 +      s = "Insufficient system resources";
 329.130 +      break;
 329.131 +    case ETIMEDOUT:
 329.132 +      s = "Timed out";
 329.133 +      break;
 329.134 +    default:
 329.135 +      s = "Unknown error";
 329.136 +      break;
 329.137 +    }
 329.138 +    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
 329.139 +    mm_log (tmp,ERROR);
 329.140 +    close (sock);
 329.141 +    fs_give ((void **) &host);
 329.142 +    return NIL;
 329.143 +  }
 329.144 +				/* create TCP/IP stream */
 329.145 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
 329.146 +  stream->host = host;		/* official host name */
 329.147 +  stream->localhost = cpystr (mylocalhost ());
 329.148 +  stream->port = port;		/* port number */
 329.149 +  stream->tcps = sock;		/* init socket */
 329.150 +  stream->ictr = 0;		/* init input counter */
 329.151 +  return stream;		/* return success */
 329.152 +}
 329.153 +  
 329.154 +/* TCP/IP authenticated open
 329.155 + * Accepts: NETMBX specifier
 329.156 + *	    service name
 329.157 + *	    returned user name buffer
 329.158 + * Returns: TCP/IP stream if success else NIL
 329.159 + */
 329.160 +
 329.161 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 329.162 +{
 329.163 +  return NIL;			/* always NIL on DOS */
 329.164 +}
 329.165 +
 329.166 +/* TCP receive line
 329.167 + * Accepts: TCP stream
 329.168 + * Returns: text line string or NIL if failure
 329.169 + */
 329.170 +
 329.171 +char *tcp_getline (TCPSTREAM *stream)
 329.172 +{
 329.173 +  unsigned long n,contd;
 329.174 +  char *ret = tcp_getline_work (stream,&n,&contd);
 329.175 +  if (ret && contd) {		/* got a line needing continuation? */
 329.176 +    STRINGLIST *stl = mail_newstringlist ();
 329.177 +    STRINGLIST *stc = stl;
 329.178 +    do {			/* collect additional lines */
 329.179 +      stc->text.data = (unsigned char *) ret;
 329.180 +      stc->text.size = n;
 329.181 +      stc = stc->next = mail_newstringlist ();
 329.182 +      ret = tcp_getline_work (stream,&n,&contd);
 329.183 +    } while (ret && contd);
 329.184 +    if (ret) {			/* stash final part of line on list */
 329.185 +      stc->text.data = (unsigned char *) ret;
 329.186 +      stc->text.size = n;
 329.187 +				/* determine how large a buffer we need */
 329.188 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 329.189 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 329.190 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 329.191 +	memcpy (ret + n,stc->text.data,stc->text.size);
 329.192 +      ret[n] = '\0';
 329.193 +    }
 329.194 +    mail_free_stringlist (&stl);/* either way, done with list */
 329.195 +  }
 329.196 +  return ret;
 329.197 +}
 329.198 +
 329.199 +/* TCP receive line or partial line
 329.200 + * Accepts: TCP stream
 329.201 + *	    pointer to return size
 329.202 + *	    pointer to return continuation flag
 329.203 + * Returns: text line string, size and continuation flag, or NIL if failure
 329.204 + */
 329.205 +
 329.206 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 329.207 +			       long *contd)
 329.208 +{
 329.209 +  unsigned long n;
 329.210 +  char *s,*ret,c,d;
 329.211 +  *contd = NIL;			/* assume no continuation */
 329.212 +				/* make sure have data */
 329.213 +  if (!tcp_getdata (stream)) return NIL;
 329.214 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 329.215 +    d = *stream->iptr++;	/* slurp another character */
 329.216 +    if ((c == '\015') && (d == '\012')) {
 329.217 +      ret = (char *) fs_get (n--);
 329.218 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 329.219 +      ret[n] = '\0';		/* tie off string with null */
 329.220 +      return ret;
 329.221 +    }
 329.222 +  }
 329.223 +				/* copy partial string from buffer */
 329.224 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 329.225 +				/* get more data from the net */
 329.226 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 329.227 +				/* special case of newline broken by buffer */
 329.228 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 329.229 +    stream->iptr++;		/* eat the line feed */
 329.230 +    stream->ictr--;
 329.231 +    ret[*size = --n] = '\0';	/* tie off string with null */
 329.232 +  }
 329.233 +  else *contd = LONGT;		/* continuation needed */
 329.234 +  return ret;
 329.235 +}
 329.236 +
 329.237 +/* TCP/IP receive buffer
 329.238 + * Accepts: TCP/IP stream
 329.239 + *	    size in bytes
 329.240 + *	    buffer to read into
 329.241 + * Returns: T if success, NIL otherwise
 329.242 + */
 329.243 +
 329.244 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 329.245 +{
 329.246 +  unsigned long n;
 329.247 +  char *bufptr = buffer;
 329.248 +  while (size > 0) {		/* until request satisfied */
 329.249 +    if (!tcp_getdata (stream)) return NIL;
 329.250 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 329.251 +				/* do the copy */
 329.252 +    memcpy (bufptr,stream->iptr,n);
 329.253 +    bufptr += n;		/* update pointer */
 329.254 +    stream->iptr +=n;
 329.255 +    size -= n;			/* update # of bytes to do */
 329.256 +    stream->ictr -=n;
 329.257 +  }
 329.258 +  bufptr[0] = '\0';		/* tie off string */
 329.259 +  return T;
 329.260 +}
 329.261 +
 329.262 +/* TCP/IP receive data
 329.263 + * Accepts: TCP/IP stream
 329.264 + * Returns: T if success, NIL otherwise
 329.265 + */
 329.266 +
 329.267 +long tcp_getdata (TCPSTREAM *stream)
 329.268 +{
 329.269 +  int i;
 329.270 +  fd_set fds,efds;
 329.271 +  struct timeval tmo;
 329.272 +  time_t t = time (0);
 329.273 +  if (stream->tcps < 0) return NIL;
 329.274 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 329.275 +    time_t tl = time (0);	/* start of request */
 329.276 +    tmo.tv_sec = ttmo_read;	/* read timeout */
 329.277 +    tmo.tv_usec = 0;
 329.278 +    FD_ZERO (&fds);		/* initialize selection vector */
 329.279 +    FD_ZERO (&efds);		/* handle errors too */
 329.280 +    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
 329.281 +    FD_SET(stream->tcps,&efds);/* set bit in error selection vector */
 329.282 +    errno = NIL;		/* block and read */
 329.283 +    while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0)
 329.284 +	   && (errno == EINTR));
 329.285 +    if (!i) {			/* timeout? */
 329.286 +      time_t tc = time (0);
 329.287 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
 329.288 +      else return tcp_abort (stream);
 329.289 +    }
 329.290 +    else if (i < 0) return tcp_abort (stream);
 329.291 +    while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
 329.292 +	   (errno == EINTR));
 329.293 +    if (i < 1) return tcp_abort (stream);
 329.294 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 329.295 +    stream->ictr = i;		/* set new byte count */
 329.296 +  }
 329.297 +  return T;
 329.298 +}
 329.299 +
 329.300 +/* TCP/IP send string as record
 329.301 + * Accepts: TCP/IP stream
 329.302 + *	    string pointer
 329.303 + * Returns: T if success else NIL
 329.304 + */
 329.305 +
 329.306 +long tcp_soutr (TCPSTREAM *stream,char *string)
 329.307 +{
 329.308 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 329.309 +}
 329.310 +
 329.311 +
 329.312 +/* TCP/IP send string
 329.313 + * Accepts: TCP/IP stream
 329.314 + *	    string pointer
 329.315 + *	    byte count
 329.316 + * Returns: T if success else NIL
 329.317 + */
 329.318 +
 329.319 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 329.320 +{
 329.321 +  int i;
 329.322 +  fd_set fds;
 329.323 +  struct timeval tmo;
 329.324 +  time_t t = time (0);
 329.325 +  if (stream->tcps < 0) return NIL;
 329.326 +  while (size > 0) {		/* until request satisfied */
 329.327 +    time_t tl = time (0);	/* start of request */
 329.328 +    tmo.tv_sec = ttmo_write;	/* write timeout */
 329.329 +    tmo.tv_usec = 0;
 329.330 +    FD_ZERO (&fds);		/* initialize selection vector */
 329.331 +    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
 329.332 +    errno = NIL;		/* block and write */
 329.333 +    while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
 329.334 +	   && (errno == EINTR));
 329.335 +    if (!i) {			/* timeout? */
 329.336 +      time_t tc = time (0);
 329.337 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
 329.338 +      else return tcp_abort (stream);
 329.339 +    }
 329.340 +    else if (i < 0) return tcp_abort (stream);
 329.341 +    while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR));
 329.342 +    if (i < 0) return tcp_abort (stream);
 329.343 +    size -= i;			/* how much we sent */
 329.344 +    string += i;
 329.345 +  }
 329.346 +  return T;			/* all done */
 329.347 +}
 329.348 +
 329.349 +/* TCP/IP close
 329.350 + * Accepts: TCP/IP stream
 329.351 + */
 329.352 +
 329.353 +void tcp_close (TCPSTREAM *stream)
 329.354 +{
 329.355 +  tcp_abort (stream);		/* nuke the socket */
 329.356 +				/* flush host names */
 329.357 +  fs_give ((void **) &stream->host);
 329.358 +  fs_give ((void **) &stream->localhost);
 329.359 +  fs_give ((void **) &stream);	/* flush the stream */
 329.360 +}
 329.361 +
 329.362 +
 329.363 +/* TCP/IP abort stream
 329.364 + * Accepts: TCP/IP stream
 329.365 + * Returns: NIL always
 329.366 + */
 329.367 +
 329.368 +long tcp_abort (TCPSTREAM *stream)
 329.369 +{
 329.370 +  if (stream->tcps >= 0) close (stream->tcps);
 329.371 +  stream->tcps = -1;
 329.372 +  return NIL;
 329.373 +}
 329.374 +
 329.375 +/* TCP/IP get host name
 329.376 + * Accepts: TCP/IP stream
 329.377 + * Returns: host name for this stream
 329.378 + */
 329.379 +
 329.380 +char *tcp_host (TCPSTREAM *stream)
 329.381 +{
 329.382 +  return stream->host;		/* return host name */
 329.383 +}
 329.384 +
 329.385 +
 329.386 +/* TCP/IP get remote host name
 329.387 + * Accepts: TCP/IP stream
 329.388 + * Returns: host name for this stream
 329.389 + */
 329.390 +
 329.391 +char *tcp_remotehost (TCPSTREAM *stream)
 329.392 +{
 329.393 +  return stream->host;		/* all we can do for now */
 329.394 +}
 329.395 +
 329.396 +
 329.397 +/* TCP/IP return port for this stream
 329.398 + * Accepts: TCP/IP stream
 329.399 + * Returns: port number for this stream
 329.400 + */
 329.401 +
 329.402 +unsigned long tcp_port (TCPSTREAM *stream)
 329.403 +{
 329.404 +  return stream->port;		/* return port number */
 329.405 +}
 329.406 +
 329.407 +
 329.408 +/* TCP/IP get local host name
 329.409 + * Accepts: TCP/IP stream
 329.410 + * Returns: local host name
 329.411 + */
 329.412 +
 329.413 +char *tcp_localhost (TCPSTREAM *stream)
 329.414 +{
 329.415 +  return stream->localhost;	/* return local host name */
 329.416 +}
 329.417 +
 329.418 +
 329.419 +/* TCP/IP return canonical form of host name
 329.420 + * Accepts: host name
 329.421 + * Returns: canonical form of host name
 329.422 + */
 329.423 +
 329.424 +char *tcp_canonical (char *name)
 329.425 +{
 329.426 +  return name;
 329.427 +}
 329.428 +
 329.429 +
 329.430 +/* TCP/IP get client host name (server calls only)
 329.431 + * Returns: client host name
 329.432 + */
 329.433 +
 329.434 +char *tcp_clienthost ()
 329.435 +{
 329.436 +  return "UNKNOWN";
 329.437 +}
   330.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   330.2 +++ b/src/osdep/os2/tcp_os2.h	Mon Sep 14 15:17:45 2009 +0900
   330.3 @@ -0,0 +1,51 @@
   330.4 +/* ========================================================================
   330.5 + * Copyright 1988-2006 University of Washington
   330.6 + *
   330.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   330.8 + * you may not use this file except in compliance with the License.
   330.9 + * You may obtain a copy of the License at
  330.10 + *
  330.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  330.12 + *
  330.13 + * 
  330.14 + * ========================================================================
  330.15 + */
  330.16 +
  330.17 +/*
  330.18 + * Program:	OS2 routines
  330.19 + *
  330.20 + * Author:	Mark Crispin
  330.21 + *		Networks and Distributed Computing
  330.22 + *		Computing & Communications
  330.23 + *		University of Washington
  330.24 + *		Administration Building, AG-44
  330.25 + *		Seattle, WA  98195
  330.26 + *		Internet: MRC@CAC.Washington.EDU
  330.27 + *
  330.28 + * Date:	11 April 1989
  330.29 + * Last Edited:	30 August 2006
  330.30 + */
  330.31 +
  330.32 +/* TCP input buffer -- must be large enough to prevent overflow */
  330.33 +
  330.34 +#define BUFLEN 8192
  330.35 +
  330.36 +
  330.37 +/* TCP I/O stream (must be before osdep.h is included) */
  330.38 +
  330.39 +#define TCPSTREAM struct tcp_stream
  330.40 +TCPSTREAM {
  330.41 +  char *host;			/* host name */
  330.42 +  unsigned long port;		/* port number */
  330.43 +  char *localhost;		/* local host name */
  330.44 +  int tcps;			/* tcp socket */
  330.45 +  long ictr;			/* input counter */
  330.46 +  char *iptr;			/* input pointer */
  330.47 +  char ibuf[BUFLEN];		/* input buffer */
  330.48 +};
  330.49 +
  330.50 +
  330.51 +/* Local function prototypes */
  330.52 +
  330.53 +long lookuphost (char **host,struct sockaddr_in *sin);
  330.54 +long tcp_abort (TCPSTREAM *stream);
   331.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   331.2 +++ b/src/osdep/os2/tenexnt.c	Mon Sep 14 15:17:45 2009 +0900
   331.3 @@ -0,0 +1,1310 @@
   331.4 +/* ========================================================================
   331.5 + * Copyright 1988-2007 University of Washington
   331.6 + *
   331.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   331.8 + * you may not use this file except in compliance with the License.
   331.9 + * You may obtain a copy of the License at
  331.10 + *
  331.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  331.12 + *
  331.13 + * 
  331.14 + * ========================================================================
  331.15 + */
  331.16 +
  331.17 +/*
  331.18 + * Program:	Tenex mail routines
  331.19 + *
  331.20 + * Author:	Mark Crispin
  331.21 + *		Networks and Distributed Computing
  331.22 + *		Computing & Communications
  331.23 + *		University of Washington
  331.24 + *		Administration Building, AG-44
  331.25 + *		Seattle, WA  98195
  331.26 + *		Internet: MRC@CAC.Washington.EDU
  331.27 + *
  331.28 + * Date:	22 May 1990
  331.29 + * Last Edited:	18 June 2007
  331.30 + */
  331.31 +
  331.32 +
  331.33 +/*				FILE TIME SEMANTICS
  331.34 + *
  331.35 + * The atime is the last read time of the file.
  331.36 + * The mtime is the last flags update time of the file.
  331.37 + * The ctime is the last write time of the file.
  331.38 + *
  331.39 + *				TEXT SIZE SEMANTICS
  331.40 + *
  331.41 + * Most of the text sizes are in internal (LF-only) form, except for the
  331.42 + * msg.text size.  Beware.
  331.43 + */
  331.44 +
  331.45 +#include <stdio.h>
  331.46 +#include <ctype.h>
  331.47 +#include <errno.h>
  331.48 +extern int errno;		/* just in case */
  331.49 +#include "mail.h"
  331.50 +#include "osdep.h"
  331.51 +#include <fcntl.h>
  331.52 +#include <time.h>
  331.53 +#include <sys/stat.h>
  331.54 +#include <sys/utime.h>
  331.55 +#include "misc.h"
  331.56 +#include "dummy.h"
  331.57 +
  331.58 +/* TENEX I/O stream local data */
  331.59 +	
  331.60 +typedef struct tenex_local {
  331.61 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  331.62 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  331.63 +  int fd;			/* file descriptor for I/O */
  331.64 +  off_t filesize;		/* file size parsed */
  331.65 +  time_t filetime;		/* last file time */
  331.66 +  time_t lastsnarf;		/* local snarf time */
  331.67 +  unsigned char *buf;		/* temporary buffer */
  331.68 +  unsigned long buflen;		/* current size of temporary buffer */
  331.69 +  unsigned long uid;		/* current text uid */
  331.70 +  SIZEDTEXT text;		/* current text */
  331.71 +} TENEXLOCAL;
  331.72 +
  331.73 +
  331.74 +/* Convenient access to local data */
  331.75 +
  331.76 +#define LOCAL ((TENEXLOCAL *) stream->local)
  331.77 +
  331.78 +
  331.79 +/* Function prototypes */
  331.80 +
  331.81 +DRIVER *tenex_valid (char *name);
  331.82 +int tenex_isvalid (char *name,char *file);
  331.83 +void *tenex_parameters (long function,void *value);
  331.84 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  331.85 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
  331.86 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
  331.87 +long tenex_create (MAILSTREAM *stream,char *mailbox);
  331.88 +long tenex_delete (MAILSTREAM *stream,char *mailbox);
  331.89 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
  331.90 +long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
  331.91 +MAILSTREAM *tenex_open (MAILSTREAM *stream);
  331.92 +void tenex_close (MAILSTREAM *stream,long options);
  331.93 +void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
  331.94 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
  331.95 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
  331.96 +		    unsigned long *length,long flags);
  331.97 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  331.98 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  331.99 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 331.100 +long tenex_ping (MAILSTREAM *stream);
 331.101 +void tenex_check (MAILSTREAM *stream);
 331.102 +void tenex_snarf (MAILSTREAM *stream);
 331.103 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
 331.104 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 331.105 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 331.106 +
 331.107 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
 331.108 +long tenex_parse (MAILSTREAM *stream);
 331.109 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
 331.110 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 331.111 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
 331.112 +			  long syncflag);
 331.113 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 331.114 +			    unsigned long *size);
 331.115 +
 331.116 +
 331.117 +/* Tenex mail routines */
 331.118 +
 331.119 +
 331.120 +/* Driver dispatch used by MAIL */
 331.121 +
 331.122 +DRIVER tenexdriver = {
 331.123 +  "tenex",			/* driver name */
 331.124 +  DR_LOCAL|DR_MAIL,		/* driver flags */
 331.125 +  (DRIVER *) NIL,		/* next driver */
 331.126 +  tenex_valid,			/* mailbox is valid for us */
 331.127 +  tenex_parameters,		/* manipulate parameters */
 331.128 +  tenex_scan,			/* scan mailboxes */
 331.129 +  tenex_list,			/* list mailboxes */
 331.130 +  tenex_lsub,			/* list subscribed mailboxes */
 331.131 +  NIL,				/* subscribe to mailbox */
 331.132 +  NIL,				/* unsubscribe from mailbox */
 331.133 +  tenex_create,			/* create mailbox */
 331.134 +  tenex_delete,			/* delete mailbox */
 331.135 +  tenex_rename,			/* rename mailbox */
 331.136 +  mail_status_default,		/* status of mailbox */
 331.137 +  tenex_open,			/* open mailbox */
 331.138 +  tenex_close,			/* close mailbox */
 331.139 +  tenex_flags,			/* fetch message "fast" attributes */
 331.140 +  tenex_flags,			/* fetch message flags */
 331.141 +  NIL,				/* fetch overview */
 331.142 +  NIL,				/* fetch message envelopes */
 331.143 +  tenex_header,			/* fetch message header */
 331.144 +  tenex_text,			/* fetch message body */
 331.145 +  NIL,				/* fetch partial message text */
 331.146 +  NIL,				/* unique identifier */
 331.147 +  NIL,				/* message number */
 331.148 +  tenex_flag,			/* modify flags */
 331.149 +  tenex_flagmsg,		/* per-message modify flags */
 331.150 +  NIL,				/* search for message based on criteria */
 331.151 +  NIL,				/* sort messages */
 331.152 +  NIL,				/* thread messages */
 331.153 +  tenex_ping,			/* ping mailbox to see if still alive */
 331.154 +  tenex_check,			/* check for new messages */
 331.155 +  tenex_expunge,		/* expunge deleted messages */
 331.156 +  tenex_copy,			/* copy messages to another mailbox */
 331.157 +  tenex_append,			/* append string message to mailbox */
 331.158 +  NIL				/* garbage collect stream */
 331.159 +};
 331.160 +
 331.161 +				/* prototype stream */
 331.162 +MAILSTREAM tenexproto = {&tenexdriver};
 331.163 +
 331.164 +/* Tenex mail validate mailbox
 331.165 + * Accepts: mailbox name
 331.166 + * Returns: our driver if name is valid, NIL otherwise
 331.167 + */
 331.168 +
 331.169 +DRIVER *tenex_valid (char *name)
 331.170 +{
 331.171 +  char tmp[MAILTMPLEN];
 331.172 +  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
 331.173 +}
 331.174 +
 331.175 +
 331.176 +/* Tenex mail test for valid mailbox
 331.177 + * Accepts: mailbox name
 331.178 + *	    buffer to return file name
 331.179 + * Returns: T if valid, NIL otherwise
 331.180 + */
 331.181 +
 331.182 +int tenex_isvalid (char *name,char *file)
 331.183 +{
 331.184 +  int fd;
 331.185 +  int ret = NIL;
 331.186 +  char *s,tmp[MAILTMPLEN];
 331.187 +  struct stat sbuf;
 331.188 +  struct utimbuf times;
 331.189 +  errno = EINVAL;		/* assume invalid argument */
 331.190 +				/* if file, get its status */
 331.191 +  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
 331.192 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
 331.193 +    if (!sbuf.st_size)errno = 0;/* empty file */
 331.194 +    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
 331.195 +      memset (tmp,'\0',MAILTMPLEN);
 331.196 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
 331.197 +	  (s[-1] != '\015')) {	/* valid format? */
 331.198 +	*s = '\0';		/* tie off header */
 331.199 +				/* must begin with dd-mmm-yy" */
 331.200 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 331.201 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 331.202 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 331.203 +      }
 331.204 +      else errno = -1;		/* bogus format */
 331.205 +      close (fd);		/* close the file */
 331.206 +				/* \Marked status? */
 331.207 +      if (sbuf.st_ctime > sbuf.st_atime) {
 331.208 +				/* preserve atime and mtime */
 331.209 +	times.actime = sbuf.st_atime;
 331.210 +	times.modtime = sbuf.st_mtime;
 331.211 +	utime (file,&times);	/* set the times */
 331.212 +      }
 331.213 +    }
 331.214 +  }
 331.215 +				/* in case INBOX but not tenex format */
 331.216 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 331.217 +  return ret;			/* return what we should */
 331.218 +}
 331.219 +
 331.220 +
 331.221 +/* Tenex manipulate driver parameters
 331.222 + * Accepts: function code
 331.223 + *	    function-dependent value
 331.224 + * Returns: function-dependent return value
 331.225 + */
 331.226 +
 331.227 +void *tenex_parameters (long function,void *value)
 331.228 +{
 331.229 +  return NIL;
 331.230 +}
 331.231 +
 331.232 +/* Tenex mail scan mailboxes
 331.233 + * Accepts: mail stream
 331.234 + *	    reference
 331.235 + *	    pattern to search
 331.236 + *	    string to scan
 331.237 + */
 331.238 +
 331.239 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 331.240 +{
 331.241 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 331.242 +}
 331.243 +
 331.244 +
 331.245 +/* Tenex mail list mailboxes
 331.246 + * Accepts: mail stream
 331.247 + *	    reference
 331.248 + *	    pattern to search
 331.249 + */
 331.250 +
 331.251 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
 331.252 +{
 331.253 +  if (stream) dummy_list (NIL,ref,pat);
 331.254 +}
 331.255 +
 331.256 +
 331.257 +/* Tenex mail list subscribed mailboxes
 331.258 + * Accepts: mail stream
 331.259 + *	    reference
 331.260 + *	    pattern to search
 331.261 + */
 331.262 +
 331.263 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
 331.264 +{
 331.265 +  if (stream) dummy_lsub (NIL,ref,pat);
 331.266 +}
 331.267 +
 331.268 +/* Tenex mail create mailbox
 331.269 + * Accepts: MAIL stream
 331.270 + *	    mailbox name to create
 331.271 + * Returns: T on success, NIL on failure
 331.272 + */
 331.273 +
 331.274 +long tenex_create (MAILSTREAM *stream,char *mailbox)
 331.275 +{
 331.276 +  char *s,mbx[MAILTMPLEN];
 331.277 +  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
 331.278 +  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 331.279 +  mm_log (mbx,ERROR);
 331.280 +  return NIL;
 331.281 +}
 331.282 +
 331.283 +
 331.284 +/* Tenex mail delete mailbox
 331.285 + * Accepts: MAIL stream
 331.286 + *	    mailbox name to delete
 331.287 + * Returns: T on success, NIL on failure
 331.288 + */
 331.289 +
 331.290 +long tenex_delete (MAILSTREAM *stream,char *mailbox)
 331.291 +{
 331.292 +  return tenex_rename (stream,mailbox,NIL);
 331.293 +}
 331.294 +
 331.295 +/* Tenex mail rename mailbox
 331.296 + * Accepts: MAIL stream
 331.297 + *	    old mailbox name
 331.298 + *	    new mailbox name (or NIL for delete)
 331.299 + * Returns: T on success, NIL on failure
 331.300 + */
 331.301 +
 331.302 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
 331.303 +{
 331.304 +  long ret = LONGT;
 331.305 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 331.306 +  int fd,ld;
 331.307 +  struct stat sbuf;
 331.308 +  if (!dummy_file (file,old) ||
 331.309 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 331.310 +		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
 331.311 +    sprintf (tmp,newname ?
 331.312 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 331.313 +	     "Can't delete mailbox %.80s: invalid name",
 331.314 +	     old,newname);
 331.315 +    mm_log (tmp,ERROR);
 331.316 +    return NIL;
 331.317 +  }
 331.318 +  else if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
 331.319 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 331.320 +    mm_log (tmp,ERROR);
 331.321 +    return NIL;
 331.322 +  }
 331.323 +				/* get exclusive parse/append permission */
 331.324 +  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
 331.325 +    mm_log ("Unable to lock rename mailbox",ERROR);
 331.326 +    return NIL;
 331.327 +  }
 331.328 +				/* lock out other users */
 331.329 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 331.330 +    close (fd);			/* couldn't lock, give up on it then */
 331.331 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 331.332 +    mm_log (tmp,ERROR);
 331.333 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 331.334 +    return NIL;
 331.335 +  }
 331.336 +
 331.337 +  if (newname) {		/* want rename? */
 331.338 +				/* found superior to destination name? */
 331.339 +    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 331.340 +	((tmp[1] != ':') || (s != tmp + 2))) {
 331.341 +      c = s[1];			/* remember character after delimiter */
 331.342 +      *s = s[1] = '\0';		/* tie off name at delimiter */
 331.343 +				/* name doesn't exist, create it */
 331.344 +      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 331.345 +	*s = '\\';		/* restore delimiter */
 331.346 +	if (!dummy_create (stream,tmp)) ret = NIL;
 331.347 +      }
 331.348 +      else *s = '\\';		/* restore delimiter */
 331.349 +      s[1] = c;			/* restore character after delimiter */
 331.350 +    }
 331.351 +    flock (fd,LOCK_UN);		/* release lock on the file */
 331.352 +    close (fd);			/* pacify NTFS */
 331.353 +				/* rename the file */
 331.354 +    if (ret && rename (file,tmp)) {
 331.355 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 331.356 +	       strerror (errno));
 331.357 +      mm_log (tmp,ERROR);
 331.358 +      ret = NIL;		/* set failure */
 331.359 +    }
 331.360 +  }
 331.361 +  else {
 331.362 +    flock (fd,LOCK_UN);		/* release lock on the file */
 331.363 +    close (fd);			/* pacify NTFS */
 331.364 +    if (unlink (file)) {
 331.365 +      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
 331.366 +      mm_log (tmp,ERROR);
 331.367 +      ret = NIL;		/* set failure */
 331.368 +    }
 331.369 +  }
 331.370 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 331.371 +  return ret;			/* return success */
 331.372 +}
 331.373 +
 331.374 +/* Tenex mail open
 331.375 + * Accepts: stream to open
 331.376 + * Returns: stream on success, NIL on failure
 331.377 + */
 331.378 +
 331.379 +MAILSTREAM *tenex_open (MAILSTREAM *stream)
 331.380 +{
 331.381 +  int fd,ld;
 331.382 +  char tmp[MAILTMPLEN];
 331.383 +				/* return prototype for OP_PROTOTYPE call */
 331.384 +  if (!stream) return &tenexproto;
 331.385 +  if (stream->local) fatal ("tenex recycle stream");
 331.386 +				/* canonicalize the mailbox name */
 331.387 +  if (!dummy_file (tmp,stream->mailbox)) {
 331.388 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 331.389 +    mm_log (tmp,ERROR);
 331.390 +  }
 331.391 +  if (stream->rdonly ||
 331.392 +      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
 331.393 +    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
 331.394 +      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
 331.395 +      mm_log (tmp,ERROR);
 331.396 +      return NIL;
 331.397 +    }
 331.398 +    else if (!stream->rdonly) {	/* got it, but readonly */
 331.399 +      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 331.400 +      stream->rdonly = T;
 331.401 +    }
 331.402 +  }
 331.403 +  stream->local = fs_get (sizeof (TENEXLOCAL));
 331.404 +  LOCAL->fd = fd;		/* bind the file */
 331.405 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 331.406 +  LOCAL->buflen = CHUNKSIZE - 1;
 331.407 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 331.408 +  LOCAL->text.size = CHUNKSIZE - 1;
 331.409 +				/* note if an INBOX or not */
 331.410 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 331.411 +  fs_give ((void **) &stream->mailbox);
 331.412 +  stream->mailbox = cpystr (tmp);
 331.413 +				/* get shared parse permission */
 331.414 +  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
 331.415 +    mm_log ("Unable to lock open mailbox",ERROR);
 331.416 +    return NIL;
 331.417 +  }
 331.418 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 331.419 +  unlockfd (ld,tmp);		/* release shared parse permission */
 331.420 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 331.421 +  LOCAL->filetime = 0;		/* time not set up yet */
 331.422 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 331.423 +  stream->sequence++;		/* bump sequence number */
 331.424 +  stream->uid_validity = (unsigned long) time (0);
 331.425 +				/* parse mailbox */
 331.426 +  stream->nmsgs = stream->recent = 0;
 331.427 +  if (tenex_ping (stream) && !stream->nmsgs)
 331.428 +    mm_log ("Mailbox is empty",(long) NIL);
 331.429 +  if (!LOCAL) return NIL;	/* failure if stream died */
 331.430 +  stream->perm_seen = stream->perm_deleted =
 331.431 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 331.432 +      stream->rdonly ? NIL : T;
 331.433 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 331.434 +  return stream;		/* return stream to caller */
 331.435 +}
 331.436 +
 331.437 +/* Tenex mail close
 331.438 + * Accepts: MAIL stream
 331.439 + *	    close options
 331.440 + */
 331.441 +
 331.442 +void tenex_close (MAILSTREAM *stream,long options)
 331.443 +{
 331.444 +  if (stream && LOCAL) {	/* only if a file is open */
 331.445 +    int silent = stream->silent;
 331.446 +    stream->silent = T;		/* note this stream is dying */
 331.447 +    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
 331.448 +    stream->silent = silent;	/* restore previous status */
 331.449 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 331.450 +    close (LOCAL->fd);		/* close the local file */
 331.451 +				/* free local text buffer */
 331.452 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 331.453 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
 331.454 +				/* nuke the local data */
 331.455 +    fs_give ((void **) &stream->local);
 331.456 +    stream->dtb = NIL;		/* log out the DTB */
 331.457 +  }
 331.458 +}
 331.459 +
 331.460 +/* Tenex mail fetch flags
 331.461 + * Accepts: MAIL stream
 331.462 + *	    sequence
 331.463 + *	    option flags
 331.464 + * Sniffs at file to get flags
 331.465 + */
 331.466 +
 331.467 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
 331.468 +{
 331.469 +  STRING bs;
 331.470 +  MESSAGECACHE *elt;
 331.471 +  unsigned long i;
 331.472 +  if (stream && LOCAL &&
 331.473 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 331.474 +       mail_sequence (stream,sequence)))
 331.475 +    for (i = 1; i <= stream->nmsgs; i++)
 331.476 +      if ((elt = mail_elt (stream,i))->sequence) {
 331.477 +	if (!elt->rfc822_size) { /* have header size yet? */
 331.478 +	  lseek (LOCAL->fd,elt->private.special.offset +
 331.479 +		 elt->private.special.text.size,L_SET);
 331.480 +				/* resize bigbuf if necessary */
 331.481 +	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
 331.482 +	    fs_give ((void **) &LOCAL->buf);
 331.483 +	    LOCAL->buflen = elt->private.msg.full.text.size;
 331.484 +	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
 331.485 +	  }
 331.486 +				/* tie off string */
 331.487 +	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
 331.488 +				/* read in the message */
 331.489 +	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
 331.490 +	  INIT (&bs,mail_string,(void *) LOCAL->buf,
 331.491 +		elt->private.msg.full.text.size);
 331.492 +				/* calculate its CRLF size */
 331.493 +	  elt->rfc822_size = unix_crlflen (&bs);
 331.494 +	}
 331.495 +	tenex_elt (stream,i);	/* get current flags from file */
 331.496 +      }
 331.497 +}
 331.498 +
 331.499 +/* TENEX mail fetch message header
 331.500 + * Accepts: MAIL stream
 331.501 + *	    message # to fetch
 331.502 + *	    pointer to returned header text length
 331.503 + *	    option flags
 331.504 + * Returns: message header in RFC822 format
 331.505 + */
 331.506 +
 331.507 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
 331.508 +		    unsigned long *length,long flags)
 331.509 +{
 331.510 +  char *s;
 331.511 +  unsigned long i;
 331.512 +  *length = 0;			/* default to empty */
 331.513 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 331.514 +				/* get to header position */
 331.515 +  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
 331.516 +  if (flags & FT_INTERNAL) {
 331.517 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 331.518 +      fs_give ((void **) &LOCAL->buf);
 331.519 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 331.520 +    }
 331.521 +				/* slurp the data */
 331.522 +    read (LOCAL->fd,LOCAL->buf,*length = i);
 331.523 +  }
 331.524 +  else {
 331.525 +    s = (char *) fs_get (i + 1);/* get readin buffer */
 331.526 +    s[i] = '\0';		/* tie off string */
 331.527 +    read (LOCAL->fd,s,i);	/* slurp the data */
 331.528 +				/* make CRLF copy of string */
 331.529 +    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
 331.530 +    fs_give ((void **) &s);	/* free readin buffer */
 331.531 +  }
 331.532 +  return LOCAL->buf;
 331.533 +}
 331.534 +
 331.535 +/* TENEX mail fetch message text (body only)
 331.536 + * Accepts: MAIL stream
 331.537 + *	    message # to fetch
 331.538 + *	    pointer to returned stringstruct
 331.539 + *	    option flags
 331.540 + * Returns: T, always
 331.541 + */
 331.542 +
 331.543 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 331.544 +{
 331.545 +  char *s;
 331.546 +  unsigned long i,j;
 331.547 +  MESSAGECACHE *elt;
 331.548 +				/* UID call "impossible" */
 331.549 +  if (flags & FT_UID) return NIL;
 331.550 +				/* get message status */
 331.551 +  elt = tenex_elt (stream,msgno);
 331.552 +				/* if message not seen */
 331.553 +  if (!(flags & FT_PEEK) && !elt->seen) {
 331.554 +    elt->seen = T;		/* mark message as seen */
 331.555 +				/* recalculate status */
 331.556 +    tenex_update_status (stream,msgno,T);
 331.557 +    mm_flags (stream,msgno);
 331.558 +  }
 331.559 +  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
 331.560 +				/* find header position */
 331.561 +    i = tenex_hdrpos (stream,msgno,&j);
 331.562 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 331.563 +      fs_give ((void **) &LOCAL->buf);
 331.564 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 331.565 +    }
 331.566 +				/* go to text position */
 331.567 +    lseek (LOCAL->fd,i + j,L_SET);
 331.568 +				/* slurp the data */
 331.569 +    if (read (LOCAL->fd,LOCAL->buf,i) != (long) i) return NIL;
 331.570 +				/* set up stringstruct for internal */
 331.571 +    INIT (bs,mail_string,LOCAL->buf,i);
 331.572 +  }
 331.573 +  else {			/* normal form, previous text cached? */
 331.574 +    if (elt->private.uid == LOCAL->uid)
 331.575 +      i = elt->private.msg.text.text.size;
 331.576 +    else {			/* not cached, cache it now */
 331.577 +      LOCAL->uid = elt->private.uid;
 331.578 +				/* find header position */
 331.579 +      i = tenex_hdrpos (stream,msgno,&j);
 331.580 +				/* go to text position */
 331.581 +      lseek (LOCAL->fd,i + j,L_SET);
 331.582 +      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
 331.583 +      s[i] = '\0';		/* tie off string */
 331.584 +      read (LOCAL->fd,s,i);	/* slurp the data */
 331.585 +				/* make CRLF copy of string */
 331.586 +      i = elt->private.msg.text.text.size =
 331.587 +	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
 331.588 +      fs_give ((void **) &s);	/* free readin buffer */
 331.589 +    }
 331.590 +				/* set up stringstruct */
 331.591 +    INIT (bs,mail_string,LOCAL->text.data,i);
 331.592 +  }
 331.593 +  return T;			/* success */
 331.594 +}
 331.595 +
 331.596 +/* Tenex mail modify flags
 331.597 + * Accepts: MAIL stream
 331.598 + *	    sequence
 331.599 + *	    flag(s)
 331.600 + *	    option flags
 331.601 + */
 331.602 +
 331.603 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 331.604 +{
 331.605 +  struct utimbuf times;
 331.606 +  struct stat sbuf;
 331.607 +  if (!stream->rdonly) {	/* make sure the update takes */
 331.608 +    fsync (LOCAL->fd);
 331.609 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 331.610 +    times.modtime = LOCAL->filetime = sbuf.st_mtime;
 331.611 +    times.actime = time (0);	/* make sure read comes after all that */
 331.612 +    utime (stream->mailbox,&times);
 331.613 +  }
 331.614 +}
 331.615 +
 331.616 +
 331.617 +/* Tenex mail per-message modify flags
 331.618 + * Accepts: MAIL stream
 331.619 + *	    message cache element
 331.620 + */
 331.621 +
 331.622 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 331.623 +{
 331.624 +  struct stat sbuf;
 331.625 +				/* maybe need to do a checkpoint? */
 331.626 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 331.627 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 331.628 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 331.629 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 331.630 +  }
 331.631 +				/* recalculate status */
 331.632 +  tenex_update_status (stream,elt->msgno,NIL);
 331.633 +}
 331.634 +
 331.635 +/* Tenex mail ping mailbox
 331.636 + * Accepts: MAIL stream
 331.637 + * Returns: T if stream still alive, NIL if not
 331.638 + */
 331.639 +
 331.640 +long tenex_ping (MAILSTREAM *stream)
 331.641 +{
 331.642 +  unsigned long i = 1;
 331.643 +  long r = T;
 331.644 +  int ld;
 331.645 +  char lock[MAILTMPLEN];
 331.646 +  struct stat sbuf;
 331.647 +  if (stream && LOCAL) {	/* only if stream already open */
 331.648 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 331.649 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 331.650 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 331.651 +				/* check for changed message status */
 331.652 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 331.653 +      LOCAL->filetime = sbuf.st_mtime;
 331.654 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 331.655 +	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
 331.656 +      while (i <= stream->nmsgs) tenex_elt (stream,i++);
 331.657 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 331.658 +    }
 331.659 +				/* get shared parse/append permission */
 331.660 +    if ((sbuf.st_size != LOCAL->filesize) &&
 331.661 +	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
 331.662 +				/* parse resulting mailbox */
 331.663 +      r = (tenex_parse (stream)) ? T : NIL;
 331.664 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 331.665 +    }
 331.666 +  }
 331.667 +  return r;			/* return result of the parse */
 331.668 +}
 331.669 +
 331.670 +
 331.671 +/* Tenex mail check mailbox (reparses status too)
 331.672 + * Accepts: MAIL stream
 331.673 + */
 331.674 +
 331.675 +void tenex_check (MAILSTREAM *stream)
 331.676 +{
 331.677 +				/* mark that a check is desired */
 331.678 +  if (LOCAL) LOCAL->mustcheck = T;
 331.679 +  if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL);
 331.680 +}
 331.681 +
 331.682 +/* Tenex mail expunge mailbox
 331.683 + *	    sequence to expunge if non-NIL
 331.684 + *	    expunge options
 331.685 + * Returns: T, always
 331.686 + */
 331.687 +
 331.688 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
 331.689 +{
 331.690 +  long ret;
 331.691 +  struct utimbuf times;
 331.692 +  struct stat sbuf;
 331.693 +  off_t pos = 0;
 331.694 +  int ld;
 331.695 +  unsigned long i = 1;
 331.696 +  unsigned long j,k,m,recent;
 331.697 +  unsigned long n = 0;
 331.698 +  unsigned long delta = 0;
 331.699 +  char lock[MAILTMPLEN];
 331.700 +  MESSAGECACHE *elt;
 331.701 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 331.702 +			   mail_uid_sequence (stream,sequence) :
 331.703 +			   mail_sequence (stream,sequence)) : LONGT) &&
 331.704 +	tenex_ping (stream)));	/* parse sequence if given, ping stream */
 331.705 +  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
 331.706 +  else {
 331.707 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 331.708 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 331.709 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 331.710 +    }
 331.711 +				/* get exclusive access */
 331.712 +    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
 331.713 +      mm_log ("Unable to lock expunge mailbox",ERROR);
 331.714 +				/* make sure see any newly-arrived messages */
 331.715 +    else if (!tenex_parse (stream));
 331.716 +				/* get exclusive access */
 331.717 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 331.718 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 331.719 +      mm_log ("Can't expunge because mailbox is in use by another process",
 331.720 +	      ERROR);
 331.721 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 331.722 +    }
 331.723 +
 331.724 +    else {
 331.725 +      mm_critical (stream);	/* go critical */
 331.726 +      recent = stream->recent;	/* get recent now that pinged and locked */
 331.727 +				/* for each message */
 331.728 +      while (i <= stream->nmsgs) {
 331.729 +				/* get cache element */
 331.730 +	elt = tenex_elt (stream,i);
 331.731 +				/* number of bytes to smash or preserve */
 331.732 +	k = elt->private.special.text.size + tenex_size (stream,i);
 331.733 +				/* if need to expunge this message */
 331.734 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 331.735 +				/* if recent, note one less recent message */
 331.736 +	  if (elt->recent) --recent;
 331.737 +	  delta += k;		/* number of bytes to delete */
 331.738 +				/* notify upper levels */
 331.739 +	  mail_expunged (stream,i);
 331.740 +	  n++;			/* count up one more expunged message */
 331.741 +	}
 331.742 +	else if (i++ && delta) {/* preserved message */
 331.743 +				/* first byte to preserve */
 331.744 +	  j = elt->private.special.offset;
 331.745 +	  do {			/* read from source position */
 331.746 +	    m = min (k,LOCAL->buflen);
 331.747 +	    lseek (LOCAL->fd,j,L_SET);
 331.748 +	    read (LOCAL->fd,LOCAL->buf,m);
 331.749 +	    pos = j - delta;	/* write to destination position */
 331.750 +	    while (T) {
 331.751 +	      lseek (LOCAL->fd,pos,L_SET);
 331.752 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 331.753 +	      mm_notify (stream,strerror (errno),WARN);
 331.754 +	      mm_diskerror (stream,errno,T);
 331.755 +	    }
 331.756 +	    pos += m;		/* new position */
 331.757 +	    j += m;		/* next chunk, perhaps */
 331.758 +	  } while (k -= m);	/* until done */
 331.759 +				/* note the new address of this text */
 331.760 +	  elt->private.special.offset -= delta;
 331.761 +	}
 331.762 +				/* preserved but no deleted messages */
 331.763 +	else pos = elt->private.special.offset + k;
 331.764 +      }
 331.765 +
 331.766 +      if (n) {			/* truncate file after last message */
 331.767 +	if (pos != (LOCAL->filesize -= delta)) {
 331.768 +	  sprintf (LOCAL->buf,
 331.769 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 331.770 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 331.771 +	  mm_log (LOCAL->buf,WARN);
 331.772 +	  LOCAL->filesize = pos;/* fix it then */
 331.773 +	}
 331.774 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 331.775 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 331.776 +				/* output the news */
 331.777 +	mm_log (LOCAL->buf,(long) NIL);
 331.778 +      }
 331.779 +      else mm_log ("No messages deleted, so no update needed",(long) NIL);
 331.780 +      fsync (LOCAL->fd);	/* force disk update */
 331.781 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 331.782 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 331.783 +      times.actime = time (0);	/* reset atime to now */
 331.784 +      utime (stream->mailbox,&times);
 331.785 +      mm_nocritical (stream);	/* release critical */
 331.786 +				/* notify upper level of new mailbox size */
 331.787 +      mail_exists (stream,stream->nmsgs);
 331.788 +      mail_recent (stream,recent);
 331.789 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 331.790 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 331.791 +    }
 331.792 +  }
 331.793 +  return ret;
 331.794 +}
 331.795 +
 331.796 +/* Tenex mail copy message(s)
 331.797 + * Accepts: MAIL stream
 331.798 + *	    sequence
 331.799 + *	    destination mailbox
 331.800 + *	    copy options
 331.801 + * Returns: T if success, NIL if failed
 331.802 + */
 331.803 +
 331.804 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 331.805 +{
 331.806 +  struct stat sbuf;
 331.807 +  struct utimbuf times;
 331.808 +  MESSAGECACHE *elt;
 331.809 +  unsigned long i,j,k;
 331.810 +  long ret = LONGT;
 331.811 +  int fd,ld;
 331.812 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 331.813 +  mailproxycopy_t pc =
 331.814 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 331.815 +				/* make sure valid mailbox */
 331.816 +  if (!tenex_isvalid (mailbox,file)) switch (errno) {
 331.817 +  case ENOENT:			/* no such file? */
 331.818 +    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 331.819 +    return NIL;
 331.820 +  case 0:			/* merely empty file? */
 331.821 +    break;
 331.822 +  case EACCES:			/* file protected */
 331.823 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 331.824 +    MM_LOG (LOCAL->buf,ERROR);
 331.825 +    return NIL;
 331.826 +  case EINVAL:
 331.827 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 331.828 +    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
 331.829 +    mm_log (LOCAL->buf,ERROR);
 331.830 +    return NIL;
 331.831 +  default:
 331.832 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 331.833 +    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
 331.834 +    mm_log (LOCAL->buf,ERROR);
 331.835 +    return NIL;
 331.836 +  }
 331.837 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 331.838 +	mail_sequence (stream,sequence))) return NIL;
 331.839 +				/* got file? */  
 331.840 +  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
 331.841 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
 331.842 +    mm_log (LOCAL->buf,ERROR);
 331.843 +    return NIL;
 331.844 +  }
 331.845 +  mm_critical (stream);		/* go critical */
 331.846 +				/* get exclusive parse/append permission */
 331.847 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 331.848 +    mm_log ("Unable to lock copy mailbox",ERROR);
 331.849 +    mm_nocritical (stream);
 331.850 +    return NIL;
 331.851 +  }
 331.852 +  fstat (fd,&sbuf);		/* get current file size */
 331.853 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 331.854 +
 331.855 +				/* for each requested message */
 331.856 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 331.857 +    if ((elt = mail_elt (stream,i))->sequence) {
 331.858 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 331.859 +				/* number of bytes to copy */
 331.860 +      k = elt->private.special.text.size + tenex_size (stream,i);
 331.861 +      do {			/* read from source position */
 331.862 +	j = min (k,LOCAL->buflen);
 331.863 +	read (LOCAL->fd,LOCAL->buf,j);
 331.864 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 331.865 +      } while (ret && (k -= j));/* until done */
 331.866 +    }
 331.867 +				/* delete all requested messages */
 331.868 +  if (ret && (options & CP_MOVE)) {
 331.869 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 331.870 +    mm_log (LOCAL->buf,ERROR);
 331.871 +    ftruncate (fd,sbuf.st_size);
 331.872 +  }
 331.873 +				/* set atime to now-1 if successful copy */
 331.874 +  if (ret) times.actime = time (0) - 1;
 331.875 +				/* else preserved \Marked status */
 331.876 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
 331.877 +	 sbuf.st_atime : time (0);
 331.878 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
 331.879 +  utime (file,&times);		/* set the times */
 331.880 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 331.881 +  close (fd);			/* close the file */
 331.882 +  mm_nocritical (stream);	/* release critical */
 331.883 +				/* delete all requested messages */
 331.884 +  if (ret && (options & CP_MOVE)) {
 331.885 +    for (i = 1; i <= stream->nmsgs; i++)
 331.886 +      if ((elt = tenex_elt (stream,i))->sequence) {
 331.887 +	elt->deleted = T;	/* mark message deleted */
 331.888 +				/* recalculate status */
 331.889 +	tenex_update_status (stream,i,NIL);
 331.890 +      }
 331.891 +    if (!stream->rdonly) {	/* make sure the update takes */
 331.892 +      fsync (LOCAL->fd);
 331.893 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 331.894 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
 331.895 +      times.actime = time (0);	/* make sure atime remains greater */
 331.896 +      utime (stream->mailbox,&times);
 331.897 +    }
 331.898 +  }
 331.899 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 331.900 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
 331.901 +  return ret;
 331.902 +}
 331.903 +
 331.904 +/* Tenex mail append message from stringstruct
 331.905 + * Accepts: MAIL stream
 331.906 + *	    destination mailbox
 331.907 + *	    append callback
 331.908 + *	    data for callback
 331.909 + * Returns: T if append successful, else NIL
 331.910 + */
 331.911 +
 331.912 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 331.913 +{
 331.914 +  struct stat sbuf;
 331.915 +  int fd,ld,c;
 331.916 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 331.917 +  struct utimbuf times;
 331.918 +  FILE *df;
 331.919 +  MESSAGECACHE elt;
 331.920 +  long f;
 331.921 +  unsigned long i,j,uf,size;
 331.922 +  STRING *message;
 331.923 +  long ret = LONGT;
 331.924 +				/* default stream to prototype */
 331.925 +  if (!stream) stream = &tenexproto;
 331.926 +				/* make sure valid mailbox */
 331.927 +  if (!tenex_isvalid (mailbox,file)) switch (errno) {
 331.928 +  case ENOENT:			/* no such file? */
 331.929 +    if (!compare_cstring (mailbox,"INBOX")) tenex_create (NIL,"INBOX");
 331.930 +    else {
 331.931 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 331.932 +      return NIL;
 331.933 +    }
 331.934 +				/* falls through */
 331.935 +  case 0:			/* merely empty file? */
 331.936 +    break;
 331.937 +  case EACCES:			/* file protected */
 331.938 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 331.939 +    MM_LOG (tmp,ERROR);
 331.940 +    return NIL;
 331.941 +  case EINVAL:
 331.942 +    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
 331.943 +    mm_log (tmp,ERROR);
 331.944 +    return NIL;
 331.945 +  default:
 331.946 +    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
 331.947 +    mm_log (tmp,ERROR);
 331.948 +    return NIL;
 331.949 +  }
 331.950 +				/* get first message */
 331.951 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
 331.952 +
 331.953 +				/* open destination mailbox */
 331.954 +  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
 331.955 +       < 0) || !(df = fdopen (fd,"ab"))) {
 331.956 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
 331.957 +    mm_log (tmp,ERROR);
 331.958 +    return NIL;
 331.959 +  }
 331.960 +				/* get parse/append permission */
 331.961 +  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
 331.962 +    mm_log ("Unable to lock append mailbox",ERROR);
 331.963 +    close (fd);
 331.964 +    return NIL;
 331.965 +  }
 331.966 +  mm_critical (stream);		/* go critical */
 331.967 +  fstat (fd,&sbuf);		/* get current file size */
 331.968 +  errno = 0;
 331.969 +  do {				/* parse flags */
 331.970 +    if (!SIZE (message)) {	/* guard against zero-length */
 331.971 +      mm_log ("Append of zero-length message",ERROR);
 331.972 +      ret = NIL;
 331.973 +      break;
 331.974 +    }
 331.975 +    f = mail_parse_flags (stream,flags,&i);
 331.976 +				/* reverse bits (dontcha wish we had CIRC?) */
 331.977 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
 331.978 +    if (date) {			/* parse date if given */
 331.979 +      if (!mail_parse_date (&elt,date)) {
 331.980 +	sprintf (tmp,"Bad date in append: %.80s",date);
 331.981 +	mm_log (tmp,ERROR);
 331.982 +	ret = NIL;		/* mark failure */
 331.983 +	break;
 331.984 +      }
 331.985 +      mail_date (tmp,&elt);	/* write preseved date */
 331.986 +    }
 331.987 +    else internal_date (tmp);	/* get current date in IMAP format */
 331.988 +    i = GETPOS (message);	/* remember current position */
 331.989 +    for (j = SIZE (message), size = 0; j; --j)
 331.990 +      if (SNX (message) != '\015') ++size;
 331.991 +    SETPOS (message,i);		/* restore position */
 331.992 +				/* write header */
 331.993 +    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
 331.994 +      ret = NIL;
 331.995 +    else {			/* write message */
 331.996 +      while (size) if ((c = 0xff & SNX (message)) != '\015') {
 331.997 +	if (putc (c,df) != EOF) --size;
 331.998 +	else break;
 331.999 +      }
331.1000 +				/* get next message */
331.1001 +      if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
331.1002 +    }
331.1003 +  } while (ret && message);
331.1004 +				/* if error... */
331.1005 +  if (!ret || (fflush (df) == EOF)) {
331.1006 +    ftruncate (fd,sbuf.st_size);/* revert file */
331.1007 +    close (fd);			/* make sure fclose() doesn't corrupt us */
331.1008 +    if (errno) {
331.1009 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
331.1010 +      mm_log (tmp,ERROR);
331.1011 +    }
331.1012 +    ret = NIL;
331.1013 +  }
331.1014 +  if (ret) times.actime = time (0) - 1;
331.1015 +				/* else preserved \Marked status */
331.1016 +  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
331.1017 +	 sbuf.st_atime : time (0);
331.1018 +  times.modtime = sbuf.st_mtime;/* preserve mtime */
331.1019 +  utime (file,&times);		/* set the times */
331.1020 +  fclose (df);			/* close the file */
331.1021 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
331.1022 +  mm_nocritical (stream);	/* release critical */
331.1023 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
331.1024 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
331.1025 +	    WARN);
331.1026 +  return ret;
331.1027 +}
331.1028 +
331.1029 +/* Internal routines */
331.1030 +
331.1031 +
331.1032 +/* Tenex mail return internal message size in bytes
331.1033 + * Accepts: MAIL stream
331.1034 + *	    message #
331.1035 + * Returns: internal size of message
331.1036 + */
331.1037 +
331.1038 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
331.1039 +{
331.1040 +  MESSAGECACHE *elt = mail_elt (stream,m);
331.1041 +  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
331.1042 +	  LOCAL->filesize) -
331.1043 +	    (elt->private.special.offset + elt->private.special.text.size);
331.1044 +}
331.1045 +
331.1046 +/* Tenex mail parse mailbox
331.1047 + * Accepts: MAIL stream
331.1048 + * Returns: T if parse OK
331.1049 + *	    NIL if failure, stream aborted
331.1050 + */
331.1051 +
331.1052 +long tenex_parse (MAILSTREAM *stream)
331.1053 +{
331.1054 +  struct stat sbuf;
331.1055 +  MESSAGECACHE *elt = NIL;
331.1056 +  unsigned char c,*s,*t,*x;
331.1057 +  char tmp[MAILTMPLEN];
331.1058 +  unsigned long i,j;
331.1059 +  long curpos = LOCAL->filesize;
331.1060 +  long nmsgs = stream->nmsgs;
331.1061 +  long recent = stream->recent;
331.1062 +  short added = NIL;
331.1063 +  short silent = stream->silent;
331.1064 +  fstat (LOCAL->fd,&sbuf);	/* get status */
331.1065 +  if (sbuf.st_size < curpos) {	/* sanity check */
331.1066 +    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
331.1067 +    mm_log (tmp,ERROR);
331.1068 +    tenex_close (stream,NIL);
331.1069 +    return NIL;
331.1070 +  }
331.1071 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
331.1072 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
331.1073 +				/* get to that position in the file */
331.1074 +    lseek (LOCAL->fd,curpos,L_SET);
331.1075 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
331.1076 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
331.1077 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
331.1078 +	       i ? strerror (errno) : "no data read");
331.1079 +      mm_log (tmp,ERROR);
331.1080 +      tenex_close (stream,NIL);
331.1081 +      return NIL;
331.1082 +    }
331.1083 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
331.1084 +    if (!(s = strchr (LOCAL->buf,'\012'))) {
331.1085 +      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
331.1086 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
331.1087 +      mm_log (tmp,ERROR);
331.1088 +      tenex_close (stream,NIL);
331.1089 +      return NIL;
331.1090 +    }
331.1091 +    *s = '\0';			/* tie off header line */
331.1092 +    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
331.1093 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
331.1094 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
331.1095 +	       (unsigned long) curpos,(char *) LOCAL->buf);
331.1096 +      mm_log (tmp,ERROR);
331.1097 +      tenex_close (stream,NIL);
331.1098 +      return NIL;
331.1099 +    }
331.1100 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
331.1101 +
331.1102 +    added = T;			/* note that a new message was added */
331.1103 +				/* swell the cache */
331.1104 +    mail_exists (stream,++nmsgs);
331.1105 +				/* instantiate an elt for this message */
331.1106 +    (elt = mail_elt (stream,nmsgs))->valid = T;
331.1107 +    elt->private.uid = ++stream->uid_last;
331.1108 +				/* note file offset of header */
331.1109 +    elt->private.special.offset = curpos;
331.1110 +				/* in case error */
331.1111 +    elt->private.special.text.size = 0;
331.1112 +				/* header size not known yet */
331.1113 +    elt->private.msg.header.text.size = 0;
331.1114 +    x = s;			/* parse the header components */
331.1115 +    if (mail_parse_date (elt,LOCAL->buf) &&
331.1116 +	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
331.1117 +	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
331.1118 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
331.1119 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
331.1120 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
331.1121 +      elt->private.special.text.size = i;
331.1122 +    else {			/* oops */
331.1123 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
331.1124 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
331.1125 +      mm_log (tmp,ERROR);
331.1126 +      tenex_close (stream,NIL);
331.1127 +      return NIL;
331.1128 +    }
331.1129 +				/* make sure didn't run off end of file */
331.1130 +    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
331.1131 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
331.1132 +	       elt->private.special.offset,(unsigned long) curpos,
331.1133 +	       (unsigned long) sbuf.st_size);
331.1134 +      mm_log (tmp,ERROR);
331.1135 +      tenex_close (stream,NIL);
331.1136 +      return NIL;
331.1137 +    }
331.1138 +    c = t[10];			/* remember first system flags byte */
331.1139 +    t[10] = '\0';		/* tie off flags */
331.1140 +    j = strtoul (t,NIL,8);	/* get user flags value */
331.1141 +    t[10] = c;			/* restore first system flags byte */
331.1142 +				/* set up all valid user flags (reversed!) */
331.1143 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
331.1144 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
331.1145 +				/* calculate system flags */
331.1146 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
331.1147 +    if (j & fDELETED) elt->deleted = T;
331.1148 +    if (j & fFLAGGED) elt->flagged = T;
331.1149 +    if (j & fANSWERED) elt->answered = T;
331.1150 +    if (j & fDRAFT) elt->draft = T;
331.1151 +    if (!(j & fOLD)) {		/* newly arrived message? */
331.1152 +      elt->recent = T;
331.1153 +      recent++;			/* count up a new recent message */
331.1154 +				/* mark it as old */
331.1155 +      tenex_update_status (stream,nmsgs,NIL);
331.1156 +    }
331.1157 +  }
331.1158 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
331.1159 +				/* update parsed file size and time */
331.1160 +  LOCAL->filesize = sbuf.st_size;
331.1161 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
331.1162 +  LOCAL->filetime = sbuf.st_mtime;
331.1163 +  if (added && !stream->rdonly){/* make sure atime updated */
331.1164 +    struct utimbuf times;
331.1165 +    times.actime = time (0);
331.1166 +    times.modtime = LOCAL->filetime;
331.1167 +    utime (stream->mailbox,&times);
331.1168 +  }
331.1169 +  stream->silent = silent;	/* can pass up events now */
331.1170 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
331.1171 +  mail_recent (stream,recent);	/* and of change in recent messages */
331.1172 +  return LONGT;			/* return the winnage */
331.1173 +}
331.1174 +
331.1175 +/* Tenex get cache element with status updating from file
331.1176 + * Accepts: MAIL stream
331.1177 + *	    message number
331.1178 + * Returns: cache element
331.1179 + */
331.1180 +
331.1181 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
331.1182 +{
331.1183 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
331.1184 +  struct {			/* old flags */
331.1185 +    unsigned int seen : 1;
331.1186 +    unsigned int deleted : 1;
331.1187 +    unsigned int flagged : 1;
331.1188 +    unsigned int answered : 1;
331.1189 +    unsigned int draft : 1;
331.1190 +    unsigned long user_flags;
331.1191 +  } old;
331.1192 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
331.1193 +  old.answered = elt->answered; old.draft = elt->draft;
331.1194 +  old.user_flags = elt->user_flags;
331.1195 +  tenex_read_flags (stream,elt);
331.1196 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
331.1197 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
331.1198 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
331.1199 +    mm_flags (stream,msgno);	/* let top level know */
331.1200 +  return elt;
331.1201 +}
331.1202 +
331.1203 +
331.1204 +/* Tenex read flags from file
331.1205 + * Accepts: MAIL stream
331.1206 + * Returns: cache element
331.1207 + */
331.1208 +
331.1209 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
331.1210 +{
331.1211 +  unsigned long i,j;
331.1212 +				/* noop if readonly and have valid flags */
331.1213 +  if (stream->rdonly && elt->valid) return;
331.1214 +				/* set the seek pointer */
331.1215 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
331.1216 +	 elt->private.special.text.size - 13,L_SET);
331.1217 +				/* read the new flags */
331.1218 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
331.1219 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
331.1220 +    fatal (LOCAL->buf);
331.1221 +  }
331.1222 +				/* calculate system flags */
331.1223 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
331.1224 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
331.1225 +  elt->flagged = i & fFLAGGED ? T : NIL;
331.1226 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
331.1227 +  LOCAL->buf[10] = '\0';	/* tie off flags */
331.1228 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
331.1229 +				/* set up all valid user flags (reversed!) */
331.1230 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
331.1231 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
331.1232 +  elt->valid = T;		/* have valid flags now */
331.1233 +}
331.1234 +
331.1235 +/* Tenex update status string
331.1236 + * Accepts: MAIL stream
331.1237 + *	    message number
331.1238 + *	    flag saying whether or not to sync
331.1239 + */
331.1240 +
331.1241 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
331.1242 +{
331.1243 +  struct utimbuf times;
331.1244 +  struct stat sbuf;
331.1245 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
331.1246 +  unsigned long j,k = 0;
331.1247 +				/* readonly */
331.1248 +  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
331.1249 +  else {			/* readwrite */
331.1250 +    j = elt->user_flags;	/* get user flags */
331.1251 +				/* reverse bits (dontcha wish we had CIRC?) */
331.1252 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
331.1253 +				/* print new flag string */
331.1254 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
331.1255 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
331.1256 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
331.1257 +	      (fDRAFT * elt->draft)));
331.1258 +    while (T) {			/* get to that place in the file */
331.1259 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
331.1260 +	     elt->private.special.text.size - 13,L_SET);
331.1261 +				/* write new flags */
331.1262 +      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
331.1263 +      mm_notify (stream,strerror (errno),WARN);
331.1264 +      mm_diskerror (stream,errno,T);
331.1265 +    }
331.1266 +    if (syncflag) {		/* sync if requested */
331.1267 +      fsync (LOCAL->fd);
331.1268 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
331.1269 +      times.modtime = LOCAL->filetime = sbuf.st_mtime;
331.1270 +      times.actime = time (0);	/* make sure read is later */
331.1271 +      utime (stream->mailbox,&times);
331.1272 +    }
331.1273 +  }
331.1274 +}
331.1275 +
331.1276 +/* Tenex locate header for a message
331.1277 + * Accepts: MAIL stream
331.1278 + *	    message number
331.1279 + *	    pointer to returned header size
331.1280 + * Returns: position of header in file
331.1281 + */
331.1282 +
331.1283 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
331.1284 +			    unsigned long *size)
331.1285 +{
331.1286 +  unsigned long siz;
331.1287 +  long i = 0;
331.1288 +  char c = '\0';
331.1289 +  char *s = NIL;
331.1290 +  MESSAGECACHE *elt = tenex_elt (stream,msgno);
331.1291 +  unsigned long ret = elt->private.special.offset +
331.1292 +    elt->private.special.text.size;
331.1293 +  unsigned long msiz = tenex_size (stream,msgno);
331.1294 +				/* is header size known? */
331.1295 +  if (!(*size = elt->private.msg.header.text.size)) {
331.1296 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
331.1297 +				/* search message for LF LF */
331.1298 +    for (siz = 0; siz < msiz; siz++) {
331.1299 +      if (--i <= 0)		/* read another buffer as necessary */
331.1300 +	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
331.1301 +				/* two newline sequence? */
331.1302 +      if ((c == '\012') && (*s == '\012')) {
331.1303 +				/* yes, note for later */
331.1304 +	elt->private.msg.header.text.size = (*size = siz + 1);
331.1305 +	return ret;		/* return to caller */
331.1306 +      }
331.1307 +      else c = *s++;		/* next character */
331.1308 +    }
331.1309 +				/* header consumes entire message */
331.1310 +    elt->private.msg.header.text.size = *size = msiz;
331.1311 +  }
331.1312 +  return ret;
331.1313 +}
   332.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   332.2 +++ b/src/osdep/os2/unixnt.c	Mon Sep 14 15:17:45 2009 +0900
   332.3 @@ -0,0 +1,2297 @@
   332.4 +/* ========================================================================
   332.5 + * Copyright 1988-2008 University of Washington
   332.6 + *
   332.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   332.8 + * you may not use this file except in compliance with the License.
   332.9 + * You may obtain a copy of the License at
  332.10 + *
  332.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  332.12 + *
  332.13 + * 
  332.14 + * ========================================================================
  332.15 + */
  332.16 +
  332.17 +/*
  332.18 + * Program:	UNIX mail routines
  332.19 + *
  332.20 + * Author:	Mark Crispin
  332.21 + *		UW Technology
  332.22 + *		University of Washington
  332.23 + *		Seattle, WA  98195
  332.24 + *		Internet: MRC@CAC.Washington.EDU
  332.25 + *
  332.26 + * Date:	20 December 1989
  332.27 + * Last Edited:	27 March 2008
  332.28 + */
  332.29 +
  332.30 +
  332.31 +/*				DEDICATION
  332.32 + *
  332.33 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  332.34 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  332.35 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  332.36 + * a two-month bout with cirrhosis of the liver.
  332.37 + *
  332.38 + *  He was a dear friend, and I miss him terribly.
  332.39 + *
  332.40 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  332.41 + */
  332.42 +
  332.43 +#include <stdio.h>
  332.44 +#include <ctype.h>
  332.45 +#include <errno.h>
  332.46 +extern int errno;		/* just in case */
  332.47 +#include "mail.h"
  332.48 +#include "osdep.h"
  332.49 +#include <time.h>
  332.50 +#include <fcntl.h>
  332.51 +#include <sys/stat.h>
  332.52 +#include <sys/utime.h>
  332.53 +#include "unixnt.h"
  332.54 +#include "pseudo.h"
  332.55 +#include "fdstring.h"
  332.56 +#include "misc.h"
  332.57 +#include "dummy.h"
  332.58 +
  332.59 +/* UNIX I/O stream local data */
  332.60 +
  332.61 +typedef struct unix_local {
  332.62 +  unsigned int dirty : 1;	/* disk copy needs updating */
  332.63 +  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
  332.64 +  unsigned int pseudo : 1;	/* uses a pseudo message */
  332.65 +  unsigned int appending : 1;	/* don't mark new messages as old */
  332.66 +  int fd;			/* mailbox file descriptor */
  332.67 +  int ld;			/* lock file descriptor */
  332.68 +  char *lname;			/* lock file name */
  332.69 +  off_t filesize;		/* file size parsed */
  332.70 +  time_t filetime;		/* last file time */
  332.71 +  unsigned char *buf;		/* temporary buffer */
  332.72 +  unsigned long buflen;		/* current size of temporary buffer */
  332.73 +  unsigned long uid;		/* current text uid */
  332.74 +  SIZEDTEXT text;		/* current text */
  332.75 +  unsigned long textlen;	/* current text length */
  332.76 +  char *line;			/* returned line */
  332.77 +  char *linebuf;		/* line readin buffer */
  332.78 +  unsigned long linebuflen;	/* current line readin buffer length */
  332.79 +} UNIXLOCAL;
  332.80 +
  332.81 +
  332.82 +/* Convenient access to local data */
  332.83 +
  332.84 +#define LOCAL ((UNIXLOCAL *) stream->local)
  332.85 +
  332.86 +
  332.87 +/* UNIX protected file structure */
  332.88 +
  332.89 +typedef struct unix_file {
  332.90 +  MAILSTREAM *stream;		/* current stream */
  332.91 +  off_t curpos;			/* current file position */
  332.92 +  off_t protect;		/* protected position */
  332.93 +  off_t filepos;		/* current last written file position */
  332.94 +  char *buf;			/* overflow buffer */
  332.95 +  size_t buflen;		/* current overflow buffer length */
  332.96 +  char *bufpos;			/* current buffer position */
  332.97 +} UNIXFILE;
  332.98 +
  332.99 +/* Function prototypes */
 332.100 +
 332.101 +DRIVER *unix_valid (char *name);
 332.102 +void *unix_parameters (long function,void *value);
 332.103 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 332.104 +void unix_list (MAILSTREAM *stream,char *ref,char *pat);
 332.105 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
 332.106 +long unix_create (MAILSTREAM *stream,char *mailbox);
 332.107 +long unix_delete (MAILSTREAM *stream,char *mailbox);
 332.108 +long unix_rename (MAILSTREAM *stream,char *old,char *newname);
 332.109 +MAILSTREAM *unix_open (MAILSTREAM *stream);
 332.110 +void unix_close (MAILSTREAM *stream,long options);
 332.111 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 332.112 +		   unsigned long *length,long flags);
 332.113 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 332.114 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 332.115 +		      unsigned long *length,long flags);
 332.116 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 332.117 +long unix_ping (MAILSTREAM *stream);
 332.118 +void unix_check (MAILSTREAM *stream);
 332.119 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
 332.120 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 332.121 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 332.122 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 332.123 +		     STRING *msg);
 332.124 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
 332.125 +
 332.126 +void unix_abort (MAILSTREAM *stream);
 332.127 +char *unix_file (char *dst,char *name);
 332.128 +int unix_lock (char *file,int flags,int mode,char *lock,int op);
 332.129 +void unix_unlock (int fd,MAILSTREAM *stream,char *lock);
 332.130 +int unix_parse (MAILSTREAM *stream,char *lock,int op);
 332.131 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
 332.132 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
 332.133 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
 332.134 +			    unsigned long uid,long flag);
 332.135 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
 332.136 +		   long flags);
 332.137 +long unix_extend (MAILSTREAM *stream,unsigned long size);
 332.138 +void unix_write (UNIXFILE *f,char *s,unsigned long i);
 332.139 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
 332.140 +
 332.141 +/* UNIX mail routines */
 332.142 +
 332.143 +
 332.144 +/* Driver dispatch used by MAIL */
 332.145 +
 332.146 +DRIVER unixdriver = {
 332.147 +  "unix",			/* driver name */
 332.148 +				/* driver flags */
 332.149 +  DR_LOCAL|DR_MAIL|DR_NONEWMAILRONLY|DR_XPOINT,
 332.150 +  (DRIVER *) NIL,		/* next driver */
 332.151 +  unix_valid,			/* mailbox is valid for us */
 332.152 +  unix_parameters,		/* manipulate parameters */
 332.153 +  unix_scan,			/* scan mailboxes */
 332.154 +  unix_list,			/* list mailboxes */
 332.155 +  unix_lsub,			/* list subscribed mailboxes */
 332.156 +  NIL,				/* subscribe to mailbox */
 332.157 +  NIL,				/* unsubscribe from mailbox */
 332.158 +  unix_create,			/* create mailbox */
 332.159 +  unix_delete,			/* delete mailbox */
 332.160 +  unix_rename,			/* rename mailbox */
 332.161 +  mail_status_default,		/* status of mailbox */
 332.162 +  unix_open,			/* open mailbox */
 332.163 +  unix_close,			/* close mailbox */
 332.164 +  NIL,				/* fetch message "fast" attributes */
 332.165 +  NIL,				/* fetch message flags */
 332.166 +  NIL,				/* fetch overview */
 332.167 +  NIL,				/* fetch message envelopes */
 332.168 +  unix_header,			/* fetch message header */
 332.169 +  unix_text,			/* fetch message text */
 332.170 +  NIL,				/* fetch partial message text */
 332.171 +  NIL,				/* unique identifier */
 332.172 +  NIL,				/* message number */
 332.173 +  NIL,				/* modify flags */
 332.174 +  unix_flagmsg,			/* per-message modify flags */
 332.175 +  NIL,				/* search for message based on criteria */
 332.176 +  NIL,				/* sort messages */
 332.177 +  NIL,				/* thread messages */
 332.178 +  unix_ping,			/* ping mailbox to see if still alive */
 332.179 +  unix_check,			/* check for new messages */
 332.180 +  unix_expunge,			/* expunge deleted messages */
 332.181 +  unix_copy,			/* copy messages to another mailbox */
 332.182 +  unix_append,			/* append string message to mailbox */
 332.183 +  NIL				/* garbage collect stream */
 332.184 +};
 332.185 +
 332.186 +				/* prototype stream */
 332.187 +MAILSTREAM unixproto = {&unixdriver};
 332.188 +
 332.189 +				/* driver parameters */
 332.190 +static long unix_fromwidget = T;
 332.191 +
 332.192 +/* UNIX mail validate mailbox
 332.193 + * Accepts: mailbox name
 332.194 + * Returns: our driver if name is valid, NIL otherwise
 332.195 + */
 332.196 +
 332.197 +DRIVER *unix_valid (char *name)
 332.198 +{
 332.199 +  int fd;
 332.200 +  DRIVER *ret = NIL;
 332.201 +  int c,r;
 332.202 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],*s,*t;
 332.203 +  struct stat sbuf;
 332.204 +  struct utimbuf times;
 332.205 +  errno = EINVAL;		/* assume invalid argument */
 332.206 +				/* must be non-empty file */
 332.207 +  if ((t = dummy_file (file,name)) && !stat (t,&sbuf) &&
 332.208 +      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
 332.209 +    if (!sbuf.st_size)errno = 0;/* empty file */
 332.210 +    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
 332.211 +      memset (tmp,'\0',MAILTMPLEN);
 332.212 +      if (read (fd,tmp,MAILTMPLEN-1) <= 0) errno = -1;
 332.213 +      else {			/* ignore leading whitespace */
 332.214 +	for (s = tmp,c = '\n';
 332.215 +	     (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');
 332.216 +	     c = *s++);
 332.217 +	if (c == '\n') {	/* at start of a line? */
 332.218 +	  VALID (s,t,r,c);	/* yes, validate format */
 332.219 +	  if (r) ret = &unixdriver;
 332.220 +	  else errno = -1;	/* invalid format */
 332.221 +	}
 332.222 +      }
 332.223 +      close (fd);		/* close the file */
 332.224 +				/* \Marked status? */
 332.225 +      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
 332.226 +				/* yes, preserve atime and mtime */
 332.227 +	times.actime = sbuf.st_atime;
 332.228 +	times.modtime = sbuf.st_mtime;
 332.229 +	utime (file,&times);	/* set the times */
 332.230 +      }
 332.231 +    }
 332.232 +  }
 332.233 +  return ret;			/* return what we should */
 332.234 +}
 332.235 +/* UNIX manipulate driver parameters
 332.236 + * Accepts: function code
 332.237 + *	    function-dependent value
 332.238 + * Returns: function-dependent return value
 332.239 + */
 332.240 +
 332.241 +void *unix_parameters (long function,void *value)
 332.242 +{
 332.243 +  void *ret = NIL;
 332.244 +  switch ((int) function) {
 332.245 +  case SET_FROMWIDGET:
 332.246 +    unix_fromwidget = (long) value;
 332.247 +  case GET_FROMWIDGET:
 332.248 +    ret = (void *) unix_fromwidget;
 332.249 +    break;
 332.250 +  }
 332.251 +  return ret;
 332.252 +}
 332.253 +
 332.254 +/* UNIX mail scan mailboxes
 332.255 + * Accepts: mail stream
 332.256 + *	    reference
 332.257 + *	    pattern to search
 332.258 + *	    string to scan
 332.259 + */
 332.260 +
 332.261 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 332.262 +{
 332.263 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 332.264 +}
 332.265 +
 332.266 +
 332.267 +/* UNIX mail list mailboxes
 332.268 + * Accepts: mail stream
 332.269 + *	    reference
 332.270 + *	    pattern to search
 332.271 + */
 332.272 +
 332.273 +void unix_list (MAILSTREAM *stream,char *ref,char *pat)
 332.274 +{
 332.275 +  if (stream) dummy_list (NIL,ref,pat);
 332.276 +}
 332.277 +
 332.278 +
 332.279 +/* UNIX mail list subscribed mailboxes
 332.280 + * Accepts: mail stream
 332.281 + *	    reference
 332.282 + *	    pattern to search
 332.283 + */
 332.284 +
 332.285 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
 332.286 +{
 332.287 +  if (stream) dummy_lsub (NIL,ref,pat);
 332.288 +}
 332.289 +
 332.290 +/* UNIX mail create mailbox
 332.291 + * Accepts: MAIL stream
 332.292 + *	    mailbox name to create
 332.293 + * Returns: T on success, NIL on failure
 332.294 + */
 332.295 +
 332.296 +long unix_create (MAILSTREAM *stream,char *mailbox)
 332.297 +{
 332.298 +  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
 332.299 +  long ret = NIL;
 332.300 +  int fd;
 332.301 +  time_t ti = time (0);
 332.302 +  if (!(s = dummy_file (mbx,mailbox))) {
 332.303 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 332.304 +    mm_log (tmp,ERROR);
 332.305 +  }
 332.306 +				/* create underlying file */
 332.307 +  else if (dummy_create_path (stream,s,NIL)) {
 332.308 +    if ((s = strrchr (s,'\\')) && !s[1]) ret = T;
 332.309 +    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
 332.310 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 332.311 +      mm_log (tmp,ERROR);
 332.312 +      unlink (mbx);		/* delete the file */
 332.313 +    }
 332.314 +    else {			/* initialize header */
 332.315 +      memset (tmp,'\0',MAILTMPLEN);
 332.316 +      sprintf (tmp,"From %s %s",pseudo_from,ctime (&ti));
 332.317 +      if (s = strpbrk (tmp,"\r\n")) *s = '\0';
 332.318 +      strcat (tmp,"\r\nDate: ");
 332.319 +      rfc822_fixed_date (s = tmp + strlen (tmp));
 332.320 +      sprintf (s += strlen (s),	/* write the pseudo-header */
 332.321 +	       "\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",
 332.322 +	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
 332.323 +	       (unsigned long) ti,pseudo_msg);
 332.324 +      if (write (fd,tmp,strlen (tmp)) > 0) {
 332.325 +	close (fd);		/* close file */
 332.326 +	ret = T;
 332.327 +      }
 332.328 +      else {
 332.329 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
 332.330 +		 strerror (errno));
 332.331 +	mm_log (tmp,ERROR);
 332.332 +	close (fd);		/* close file before unlinking */
 332.333 +	unlink (mbx);		/* delete the file */
 332.334 +      }
 332.335 +    }
 332.336 +  }
 332.337 +  return ret;
 332.338 +}
 332.339 +
 332.340 +/* UNIX mail delete mailbox
 332.341 + * Accepts: MAIL stream
 332.342 + *	    mailbox name to delete
 332.343 + * Returns: T on success, NIL on failure
 332.344 + */
 332.345 +
 332.346 +long unix_delete (MAILSTREAM *stream,char *mailbox)
 332.347 +{
 332.348 +  return unix_rename (stream,mailbox,NIL);
 332.349 +}
 332.350 +
 332.351 +
 332.352 +/* UNIX mail rename mailbox
 332.353 + * Accepts: MAIL stream
 332.354 + *	    old mailbox name
 332.355 + *	    new mailbox name (or NIL for delete)
 332.356 + * Returns: T on success, NIL on failure
 332.357 + */
 332.358 +
 332.359 +long unix_rename (MAILSTREAM *stream,char *old,char *newname)
 332.360 +{
 332.361 +  long ret = NIL;
 332.362 +  char c,*s = NIL;
 332.363 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN];
 332.364 +  int fd,ld;
 332.365 +  struct stat sbuf;
 332.366 +  mm_critical (stream);		/* get the c-client lock */
 332.367 +  if (!dummy_file (file,old) ||
 332.368 +      (newname && (!(s = dummy_file (tmp,newname)) ||
 332.369 +		   ((s = strrchr (s,'\\')) && !s[1]))))
 332.370 +    sprintf (tmp,newname ?
 332.371 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 332.372 +	     "Can't delete mailbox %.80s: invalid name",
 332.373 +	     old,newname);
 332.374 +  else if ((ld = lockname (lock,file,NIL)) < 0)
 332.375 +    sprintf (tmp,"Can't get lock for mailbox %.80s",old);
 332.376 +
 332.377 +  else {			/* lock out other c-clients */
 332.378 +    if (flock (ld,LOCK_EX|LOCK_NB)) {
 332.379 +      close (ld);		/* couldn't lock, give up on it then */
 332.380 +      sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 332.381 +    }
 332.382 +				/* lock out non c-client applications */
 332.383 +    else if ((fd = unix_lock (file,O_BINARY|O_RDWR,S_IREAD|S_IWRITE,lockx,
 332.384 +			      LOCK_EX)) < 0)
 332.385 +      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
 332.386 +    else {
 332.387 +      unix_unlock(fd,NIL,lockx);/* pacify evil NTFS */
 332.388 +      if (newname) {		/* want rename? */
 332.389 +				/* found superior to destination name? */
 332.390 +	if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
 332.391 +	    ((tmp[1] != ':') || (s != tmp + 2))) {
 332.392 +	  c = s[1];		/* remember character after delimiter */
 332.393 +	  *s = s[1] = '\0';	/* tie off name at delimiter */
 332.394 +				/* name doesn't exist, create it */
 332.395 +	  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
 332.396 +	    *s = '\\';		/* restore delimiter */
 332.397 +	    if (!dummy_create (stream,newname)) {
 332.398 +	      flock (ld,LOCK_UN);
 332.399 +	      close (ld);	/* close c-client lock */
 332.400 +	      unlink (lock);	/* and delete it */
 332.401 +	      mm_nocritical (stream);
 332.402 +	      return NIL;	/* couldn't create superior */
 332.403 +	    }
 332.404 +	  }
 332.405 +	  else *s = '\\';	/* restore delimiter */
 332.406 +	  s[1] = c;		/* restore character after delimiter */
 332.407 +	}
 332.408 +	if (rename (file,tmp))
 332.409 +	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 332.410 +		   strerror (errno));
 332.411 +	else ret = T;		/* set success */
 332.412 +      }
 332.413 +      else if (unlink (file))	/* want delete */
 332.414 +	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 332.415 +      else ret = T;		/* set success */
 332.416 +      flock (ld,LOCK_UN);	/* release c-client lock */
 332.417 +      close (ld);		/* close c-client lock */
 332.418 +      unlink (lock);		/* and delete it */
 332.419 +    }
 332.420 +  }
 332.421 +  mm_nocritical (stream);	/* no longer critical */
 332.422 +  if (!ret) mm_log (tmp,ERROR);	/* log error */
 332.423 +  return ret;			/* return success or failure */
 332.424 +}
 332.425 +
 332.426 +/* UNIX mail open
 332.427 + * Accepts: Stream to open
 332.428 + * Returns: Stream on success, NIL on failure
 332.429 + */
 332.430 +
 332.431 +MAILSTREAM *unix_open (MAILSTREAM *stream)
 332.432 +{
 332.433 +  int fd;
 332.434 +  char tmp[MAILTMPLEN];
 332.435 +				/* return prototype for OP_PROTOTYPE call */
 332.436 +  if (!stream) return &unixproto;
 332.437 +  if (stream->local) fatal ("unix recycle stream");
 332.438 +  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
 332.439 +				/* note if an INBOX or not */
 332.440 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 332.441 +				/* canonicalize the stream mailbox name */
 332.442 +  if (!dummy_file (tmp,stream->mailbox)) {
 332.443 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 332.444 +    mm_log (tmp,ERROR);
 332.445 +    return NIL;
 332.446 +  }
 332.447 +				/* flush old name */
 332.448 +  fs_give ((void **) &stream->mailbox);
 332.449 +				/* save canonical name */
 332.450 +  stream->mailbox = cpystr (tmp);
 332.451 +  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
 332.452 +  LOCAL->buf = (char *) fs_get ((LOCAL->buflen = CHUNKSIZE) + 1);
 332.453 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 332.454 +  LOCAL->text.size = CHUNKSIZE - 1;
 332.455 +  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
 332.456 +  LOCAL->linebuflen = CHUNKSIZE - 1;
 332.457 +  stream->sequence++;		/* bump sequence number */
 332.458 +  if (!stream->rdonly) {	/* make lock for read/write access */
 332.459 +    if ((fd = lockname (tmp,stream->mailbox,NIL)) < 0)
 332.460 +      mm_log ("Can't open mailbox lock, access is readonly",WARN);
 332.461 +				/* can get the lock? */
 332.462 +    else if (flock (fd,LOCK_EX|LOCK_NB)) {
 332.463 +      if (!stream->silent)
 332.464 +	mm_log ("Mailbox is open by another process, access is readonly",WARN);
 332.465 +      close (fd);
 332.466 +    }
 332.467 +    else {			/* got the lock, nobody else can alter state */
 332.468 +      LOCAL->ld = fd;		/* note lock's fd and name */
 332.469 +      LOCAL->lname = cpystr (tmp);
 332.470 +    }
 332.471 +  }
 332.472 +
 332.473 +				/* parse mailbox */
 332.474 +  stream->nmsgs = stream->recent = 0;
 332.475 +				/* will we be able to get write access? */
 332.476 +  if ((LOCAL->ld >= 0) && access (stream->mailbox,02) && (errno == EACCES)) {
 332.477 +    mm_log ("Can't get write access to mailbox, access is readonly",WARN);
 332.478 +    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
 332.479 +    close (LOCAL->ld);		/* close the lock file */
 332.480 +    LOCAL->ld = -1;		/* no more lock fd */
 332.481 +    unlink (LOCAL->lname);	/* delete it */
 332.482 +  }
 332.483 +				/* reset UID validity */
 332.484 +  stream->uid_validity = stream->uid_last = 0;
 332.485 +  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
 332.486 +    unix_abort (stream);	/* abort if can't get RW silent stream */
 332.487 +				/* parse mailbox */
 332.488 +  else if (unix_parse (stream,tmp,LOCK_SH)) {
 332.489 +    unix_unlock (LOCAL->fd,stream,tmp);
 332.490 +    mail_unlock (stream);
 332.491 +    mm_nocritical (stream);	/* done with critical */
 332.492 +  }
 332.493 +  if (!LOCAL) return NIL;	/* failure if stream died */
 332.494 +				/* make sure upper level knows readonly */
 332.495 +  stream->rdonly = (LOCAL->ld < 0);
 332.496 +				/* notify about empty mailbox */
 332.497 +  if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",NIL);
 332.498 +  if (!stream->rdonly) {	/* flags stick if readwrite */
 332.499 +    stream->perm_seen = stream->perm_deleted =
 332.500 +      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
 332.501 +				/* have permanent keywords */
 332.502 +    stream->perm_user_flags = 0xffffffff;
 332.503 +				/* and maybe can create them too */
 332.504 +    stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
 332.505 +  }
 332.506 +  return stream;		/* return stream alive to caller */
 332.507 +}
 332.508 +
 332.509 +
 332.510 +/* UNIX mail close
 332.511 + * Accepts: MAIL stream
 332.512 + *	    close options
 332.513 + */
 332.514 +
 332.515 +void unix_close (MAILSTREAM *stream,long options)
 332.516 +{
 332.517 +  int silent = stream->silent;
 332.518 +  stream->silent = T;		/* go silent */
 332.519 +				/* expunge if requested */
 332.520 +  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
 332.521 +				/* else dump final checkpoint */
 332.522 +  else if (LOCAL->dirty) unix_check (stream);
 332.523 +  stream->silent = silent;	/* restore old silence state */
 332.524 +  unix_abort (stream);		/* now punt the file and local data */
 332.525 +}
 332.526 +
 332.527 +/* UNIX mail fetch message header
 332.528 + * Accepts: MAIL stream
 332.529 + *	    message # to fetch
 332.530 + *	    pointer to returned header text length
 332.531 + *	    option flags
 332.532 + * Returns: message header in RFC822 format
 332.533 + */
 332.534 +
 332.535 +				/* lines to filter from header */
 332.536 +static STRINGLIST *unix_hlines = NIL;
 332.537 +
 332.538 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 332.539 +		   unsigned long *length,long flags)
 332.540 +{
 332.541 +  MESSAGECACHE *elt;
 332.542 +  unsigned char *s;
 332.543 +  *length = 0;			/* default to empty */
 332.544 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 332.545 +  elt = mail_elt (stream,msgno);/* get cache */
 332.546 +  if (!unix_hlines) {		/* once only code */
 332.547 +    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
 332.548 +    lines->text.size = strlen ((char *) (lines->text.data =
 332.549 +					 (unsigned char *) "Status"));
 332.550 +    lines = lines->next = mail_newstringlist ();
 332.551 +    lines->text.size = strlen ((char *) (lines->text.data =
 332.552 +					 (unsigned char *) "X-Status"));
 332.553 +    lines = lines->next = mail_newstringlist ();
 332.554 +    lines->text.size = strlen ((char *) (lines->text.data =
 332.555 +					 (unsigned char *) "X-Keywords"));
 332.556 +    lines = lines->next = mail_newstringlist ();
 332.557 +    lines->text.size = strlen ((char *) (lines->text.data =
 332.558 +					 (unsigned char *) "X-UID"));
 332.559 +    lines = lines->next = mail_newstringlist ();
 332.560 +    lines->text.size = strlen ((char *) (lines->text.data =
 332.561 +					 (unsigned char *) "X-IMAP"));
 332.562 +    lines = lines->next = mail_newstringlist ();
 332.563 +    lines->text.size = strlen ((char *) (lines->text.data =
 332.564 +					 (unsigned char *) "X-IMAPbase"));
 332.565 +  }
 332.566 +				/* go to header position */
 332.567 +  lseek (LOCAL->fd,elt->private.special.offset +
 332.568 +	 elt->private.msg.header.offset,L_SET);
 332.569 +
 332.570 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 332.571 +    if (elt->private.msg.header.text.size > LOCAL->buflen) {
 332.572 +      fs_give ((void **) &LOCAL->buf);
 332.573 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 332.574 +				     elt->private.msg.header.text.size) + 1);
 332.575 +    }
 332.576 +				/* read message */
 332.577 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
 332.578 +				/* got text, tie off string */
 332.579 +    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
 332.580 +  }
 332.581 +  else {			/* need to make a CRLF version */
 332.582 +    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
 332.583 +	  elt->private.msg.header.text.size);
 332.584 +				/* tie off string, and convert to CRLF */
 332.585 +    s[elt->private.msg.header.text.size] = '\0';
 332.586 +    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
 332.587 +			    elt->private.msg.header.text.size);
 332.588 +    fs_give ((void **) &s);	/* free readin buffer */
 332.589 +  }
 332.590 +  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
 332.591 +  return LOCAL->buf;		/* return processed copy */
 332.592 +}
 332.593 +
 332.594 +/* UNIX mail fetch message text
 332.595 + * Accepts: MAIL stream
 332.596 + *	    message # to fetch
 332.597 + *	    pointer to returned stringstruct
 332.598 + *	    option flags
 332.599 + * Returns: T on success, NIL if failure
 332.600 + */
 332.601 +
 332.602 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 332.603 +{
 332.604 +  char *s;
 332.605 +  unsigned long i;
 332.606 +  MESSAGECACHE *elt;
 332.607 +				/* UID call "impossible" */
 332.608 +  if (flags & FT_UID) return NIL;
 332.609 +  elt = mail_elt (stream,msgno);/* get cache element */
 332.610 +				/* if message not seen */
 332.611 +  if (!(flags & FT_PEEK) && !elt->seen) {
 332.612 +				/* mark message seen and dirty */
 332.613 +    elt->seen = elt->private.dirty = LOCAL->dirty = T;
 332.614 +    mm_flags (stream,msgno);
 332.615 +  }
 332.616 +  s = unix_text_work (stream,elt,&i,flags);
 332.617 +  INIT (bs,mail_string,s,i);	/* set up stringstruct */
 332.618 +  return T;			/* success */
 332.619 +}
 332.620 +
 332.621 +/* UNIX mail fetch message text worker routine
 332.622 + * Accepts: MAIL stream
 332.623 + *	    message cache element
 332.624 + *	    pointer to returned header text length
 332.625 + *	    option flags
 332.626 + */
 332.627 +
 332.628 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 332.629 +		      unsigned long *length,long flags)
 332.630 +{
 332.631 +  FDDATA d;
 332.632 +  STRING bs;
 332.633 +  unsigned char c,*s,tmp[CHUNKSIZE];
 332.634 +				/* go to text position */
 332.635 +  lseek (LOCAL->fd,elt->private.special.offset +
 332.636 +	 elt->private.msg.text.offset,L_SET);
 332.637 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 332.638 +    if (elt->private.msg.text.text.size > LOCAL->buflen) {
 332.639 +      fs_give ((void **) &LOCAL->buf);
 332.640 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 332.641 +				     elt->private.msg.text.text.size) + 1);
 332.642 +    }
 332.643 +				/* read message */
 332.644 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
 332.645 +				/* got text, tie off string */
 332.646 +    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
 332.647 +    return LOCAL->buf;
 332.648 +  }
 332.649 +				/* have it cached already? */
 332.650 +  if (elt->private.uid != LOCAL->uid) {
 332.651 +				/* not cached, cache it now */
 332.652 +    LOCAL->uid = elt->private.uid;
 332.653 +				/* is buffer big enough? */
 332.654 +    if (elt->rfc822_size > LOCAL->text.size) {
 332.655 +      /* excessively conservative, but the right thing is too hard to do */
 332.656 +      fs_give ((void **) &LOCAL->text.data);
 332.657 +      LOCAL->text.data = (unsigned char *)
 332.658 +	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
 332.659 +    }
 332.660 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
 332.661 +    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
 332.662 +    d.chunk = tmp;		/* initial buffer chunk */
 332.663 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
 332.664 +    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
 332.665 +    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
 332.666 +    case '\r':			/* carriage return seen */
 332.667 +      *s++ = c;			/* copy it and any succeeding LF */
 332.668 +      if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
 332.669 +      break;
 332.670 +    case '\n':
 332.671 +      *s++ = '\r';		/* insert a CR */
 332.672 +    default:
 332.673 +      *s++ = c;			/* copy characters */
 332.674 +    }
 332.675 +    *s = '\0';			/* tie off buffer */
 332.676 +				/* calculate length of cached data */
 332.677 +    LOCAL->textlen = s - LOCAL->text.data;
 332.678 +  }
 332.679 +  *length = LOCAL->textlen;	/* return from cache */
 332.680 +  return (char *) LOCAL->text.data;
 332.681 +}
 332.682 +
 332.683 +/* UNIX per-message modify flag
 332.684 + * Accepts: MAIL stream
 332.685 + *	    message cache element
 332.686 + */
 332.687 +
 332.688 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 332.689 +{
 332.690 +				/* only after finishing */
 332.691 +  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
 332.692 +}
 332.693 +
 332.694 +
 332.695 +/* UNIX mail ping mailbox
 332.696 + * Accepts: MAIL stream
 332.697 + * Returns: T if stream alive, else NIL
 332.698 + */
 332.699 +
 332.700 +long unix_ping (MAILSTREAM *stream)
 332.701 +{
 332.702 +  char lock[MAILTMPLEN];
 332.703 +  struct stat sbuf;
 332.704 +				/* big no-op if not readwrite */
 332.705 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
 332.706 +    if (stream->rdonly) {	/* does he want to give up readwrite? */
 332.707 +				/* checkpoint if we changed something */
 332.708 +      if (LOCAL->dirty) unix_check (stream);
 332.709 +      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
 332.710 +      close (LOCAL->ld);	/* close the readwrite lock file */
 332.711 +      LOCAL->ld = -1;		/* no more readwrite lock fd */
 332.712 +      unlink (LOCAL->lname);	/* delete the readwrite lock file */
 332.713 +    }
 332.714 +    else {			/* get current mailbox size */
 332.715 +      if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
 332.716 +      else if (stat (stream->mailbox,&sbuf)) {
 332.717 +	sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
 332.718 +		 strerror (errno));
 332.719 +	MM_LOG (LOCAL->buf,ERROR);
 332.720 +	unix_abort (stream);
 332.721 +	return NIL;
 332.722 +      }
 332.723 +				/* parse if mailbox changed */
 332.724 +      if ((LOCAL->ddirty || (sbuf.st_size != LOCAL->filesize)) &&
 332.725 +	  unix_parse (stream,lock,LOCK_EX)) {
 332.726 +				/* force checkpoint if double-dirty */
 332.727 +	if (LOCAL->ddirty) unix_rewrite (stream,NIL,lock,NIL);
 332.728 +				/* unlock mailbox */
 332.729 +	else unix_unlock (LOCAL->fd,stream,lock);
 332.730 +	mail_unlock (stream);	/* and stream */
 332.731 +	mm_nocritical (stream);	/* done with critical */
 332.732 +      }
 332.733 +    }
 332.734 +  }
 332.735 +  return LOCAL ? LONGT : NIL;	/* return if still alive */
 332.736 +}
 332.737 +
 332.738 +/* UNIX mail check mailbox
 332.739 + * Accepts: MAIL stream
 332.740 + */
 332.741 +
 332.742 +void unix_check (MAILSTREAM *stream)
 332.743 +{
 332.744 +  char lock[MAILTMPLEN];
 332.745 +				/* parse and lock mailbox */
 332.746 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 332.747 +      unix_parse (stream,lock,LOCK_EX)) {
 332.748 +				/* any unsaved changes? */
 332.749 +    if (LOCAL->dirty && unix_rewrite (stream,NIL,lock,NIL)) {
 332.750 +      if (!stream->silent) mm_log ("Checkpoint completed",NIL);
 332.751 +    }
 332.752 +				/* no checkpoint needed, just unlock */
 332.753 +    else unix_unlock (LOCAL->fd,stream,lock);
 332.754 +    mail_unlock (stream);	/* unlock the stream */
 332.755 +    mm_nocritical (stream);	/* done with critical */
 332.756 +  }
 332.757 +}
 332.758 +
 332.759 +
 332.760 +/* UNIX mail expunge mailbox
 332.761 + * Accepts: MAIL stream
 332.762 + *	    sequence to expunge if non-NIL
 332.763 + *	    expunge options
 332.764 + * Returns: T, always
 332.765 + */
 332.766 +
 332.767 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
 332.768 +{
 332.769 +  long ret;
 332.770 +  unsigned long i;
 332.771 +  char lock[MAILTMPLEN];
 332.772 +  char *msg = NIL;
 332.773 +				/* parse and lock mailbox */
 332.774 +  if (ret = (sequence ? ((options & EX_UID) ?
 332.775 +			 mail_uid_sequence (stream,sequence) :
 332.776 +			 mail_sequence (stream,sequence)) : LONGT) &&
 332.777 +      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 332.778 +      unix_parse (stream,lock,LOCK_EX)) {
 332.779 +				/* check expunged messages if not dirty */
 332.780 +    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
 332.781 +      MESSAGECACHE *elt = mail_elt (stream,i);
 332.782 +      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
 332.783 +    }
 332.784 +    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
 332.785 +      unix_unlock (LOCAL->fd,stream,lock);
 332.786 +      msg = "No messages deleted, so no update needed";
 332.787 +    }
 332.788 +    else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) {
 332.789 +      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
 332.790 +      else msg = "Mailbox checkpointed, but no messages expunged";
 332.791 +    }
 332.792 +				/* rewrite failed */
 332.793 +    else unix_unlock (LOCAL->fd,stream,lock);
 332.794 +    mail_unlock (stream);	/* unlock the stream */
 332.795 +    mm_nocritical (stream);	/* done with critical */
 332.796 +    if (msg && !stream->silent) mm_log (msg,NIL);
 332.797 +  }
 332.798 +  else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN);
 332.799 +  return ret;
 332.800 +}
 332.801 +
 332.802 +/* UNIX mail copy message(s)
 332.803 + * Accepts: MAIL stream
 332.804 + *	    sequence
 332.805 + *	    destination mailbox
 332.806 + *	    copy options
 332.807 + * Returns: T if copy successful, else NIL
 332.808 + */
 332.809 +
 332.810 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 332.811 +{
 332.812 +  struct stat sbuf;
 332.813 +  int fd;
 332.814 +  char *s,file[MAILTMPLEN],lock[MAILTMPLEN];
 332.815 +  struct utimbuf times;
 332.816 +  unsigned long i,j;
 332.817 +  MESSAGECACHE *elt;
 332.818 +  long ret = T;
 332.819 +  mailproxycopy_t pc =
 332.820 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 332.821 +  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
 332.822 +			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
 332.823 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 332.824 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 332.825 +  MAILSTREAM *tstream = NIL;
 332.826 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 332.827 +	mail_sequence (stream,sequence))) return NIL;
 332.828 +				/* make sure destination is valid */
 332.829 +  if (!(unix_valid (mailbox) || !errno))
 332.830 +    switch (errno) {
 332.831 +    case ENOENT:			/* no such file? */
 332.832 +      if (compare_cstring (mailbox,"INBOX")) {
 332.833 +	mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 332.834 +	return NIL;
 332.835 +      }
 332.836 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 332.837 +      unix_create (NIL,"INBOX");/* create empty INBOX */
 332.838 +    case EACCES:		/* file protected */
 332.839 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 332.840 +      MM_LOG (LOCAL->buf,ERROR);
 332.841 +      return NIL;
 332.842 +    case EINVAL:
 332.843 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 332.844 +      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
 332.845 +      mm_log (LOCAL->buf,ERROR);
 332.846 +      return NIL;
 332.847 +    default:
 332.848 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 332.849 +      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
 332.850 +      mm_log (LOCAL->buf,ERROR);
 332.851 +      return NIL;
 332.852 +    }
 332.853 +
 332.854 +				/* try to open rewrite for UIDPLUS */
 332.855 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
 332.856 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
 332.857 +    tstream = mail_close (tstream);
 332.858 +  if (cu && !tstream) {		/* wanted a COPYUID? */
 332.859 +    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
 332.860 +	     mailbox);
 332.861 +    MM_LOG (LOCAL->buf,WARN);
 332.862 +    cu = NIL;			/* don't try to do COPYUID */
 332.863 +  }
 332.864 +  LOCAL->buf[0] = '\0';
 332.865 +  mm_critical (stream);		/* go critical */
 332.866 +  if ((fd = unix_lock (dummy_file (file,mailbox),
 332.867 +		       O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
 332.868 +		       lock,LOCK_EX)) < 0) {
 332.869 +    mm_nocritical (stream);	/* done with critical */
 332.870 +    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
 332.871 +    mm_log (LOCAL->buf,ERROR);	/* log the error */
 332.872 +    return NIL;			/* failed */
 332.873 +  }
 332.874 +  fstat (fd,&sbuf);		/* get current file size */
 332.875 +				/* write all requested messages to mailbox */
 332.876 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
 332.877 +    if ((elt = mail_elt (stream,i))->sequence) {
 332.878 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 332.879 +      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
 332.880 +      if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') {
 332.881 +	LOCAL->buf[j - 1] = '\r';
 332.882 +	LOCAL->buf[j++] = '\n';
 332.883 +      }
 332.884 +      if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 332.885 +      else {			/* internal header succeeded */
 332.886 +	s = unix_header (stream,i,&j,NIL);
 332.887 +				/* header size, sans trailing newline */
 332.888 +	if (j && (s[j - 4] == '\r')) j -= 2;
 332.889 +	if (write (fd,s,j) < 0) ret = NIL;
 332.890 +	else {			/* message header succeeded */
 332.891 +	  j = tstream ?		/* write UIDPLUS data if have readwrite */
 332.892 +	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
 332.893 +	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
 332.894 +	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 332.895 +	  else {		/* message status succeeded */
 332.896 +	    s = unix_text_work (stream,elt,&j,NIL);
 332.897 +	    if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0))
 332.898 +	      ret = NIL;
 332.899 +	    else if (cu) {	/* need to pass back new UID? */
 332.900 +	      mail_append_set (source,mail_uid (stream,i));
 332.901 +	      mail_append_set (dest,tstream->uid_last);
 332.902 +	    }
 332.903 +	  }
 332.904 +	}
 332.905 +      }
 332.906 +    }
 332.907 +
 332.908 +  if (!ret || fsync (fd)) {	/* force out the update */
 332.909 +    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
 332.910 +    ftruncate (fd,sbuf.st_size);
 332.911 +    ret = NIL;
 332.912 +  }
 332.913 +				/* force UIDVALIDITY assignment now */
 332.914 +  if (tstream && !tstream->uid_validity)
 332.915 +    tstream->uid_validity = (unsigned long) time (0);
 332.916 +				/* return sets if doing COPYUID */
 332.917 +  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
 332.918 +  else {			/* flush any sets we may have built */
 332.919 +    mail_free_searchset (&source);
 332.920 +    mail_free_searchset (&dest);
 332.921 +  }
 332.922 +  times.modtime = time (0);	/* set mtime to now */
 332.923 +				/* set atime to now-1 if successful copy */
 332.924 +  if (ret) times.actime = times.modtime - 1;
 332.925 +		
 332.926 +  else times.actime =		/* else preserve \Marked status */
 332.927 +	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
 332.928 +	 sbuf.st_atime : times.modtime;
 332.929 +  utime (file,&times);		/* set the times */
 332.930 +  unix_unlock (fd,NIL,lock);	/* unlock and close mailbox */
 332.931 +  if (tstream) {		/* update last UID if we can */
 332.932 +    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
 332.933 +    local->dirty = T;		/* do a rewrite */
 332.934 +    local->appending = T;	/* but not at the cost of marking as old */
 332.935 +    tstream = mail_close (tstream);
 332.936 +  }
 332.937 +				/* log the error */
 332.938 +  if (!ret) mm_log (LOCAL->buf,ERROR);
 332.939 +				/* delete if requested message */
 332.940 +  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
 332.941 +    if ((elt = mail_elt (stream,i))->sequence)
 332.942 +      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
 332.943 +  mm_nocritical (stream);	/* release critical */
 332.944 +  return ret;
 332.945 +}
 332.946 +
 332.947 +/* UNIX mail append message from stringstruct
 332.948 + * Accepts: MAIL stream
 332.949 + *	    destination mailbox
 332.950 + *	    append callback
 332.951 + *	    data for callback
 332.952 + * Returns: T if append successful, else NIL
 332.953 + */
 332.954 +
 332.955 +#define BUFLEN 8*MAILTMPLEN
 332.956 +
 332.957 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 332.958 +{
 332.959 +  struct stat sbuf;
 332.960 +  int fd;
 332.961 +  unsigned long i;
 332.962 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN],
 332.963 +    lock[MAILTMPLEN];
 332.964 +  struct utimbuf times;
 332.965 +  FILE *sf,*df;
 332.966 +  MESSAGECACHE elt;
 332.967 +  STRING *message;
 332.968 +  unsigned long uidlocation = 0;
 332.969 +  appenduid_t au = (appenduid_t)
 332.970 +    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
 332.971 +     mail_parameters (NIL,GET_APPENDUID,NIL));
 332.972 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
 332.973 +  long ret = LONGT;
 332.974 +  MAILSTREAM *tstream = NIL;
 332.975 +  if (!stream) {		/* stream specified? */
 332.976 +    stream = &unixproto;	/* no, default stream to prototype */
 332.977 +    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
 332.978 +      fs_give ((void **) &stream->user_flags[i]);
 332.979 +  }
 332.980 +  if (!unix_valid (mailbox)) switch (errno) {
 332.981 +  case ENOENT:			/* no such file? */
 332.982 +    if (!compare_cstring (mailbox,"INBOX")) {
 332.983 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 332.984 +      return NIL;
 332.985 +    }
 332.986 +    unix_create (NIL,"INBOX");	/* create empty INBOX */
 332.987 +  case 0:			/* merely empty file? */
 332.988 +    tstream = stream;
 332.989 +    break;
 332.990 +  case EACCES:			/* file protected */
 332.991 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 332.992 +    MM_LOG (tmp,ERROR);
 332.993 +    return NIL;
 332.994 +  case EINVAL:
 332.995 +    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
 332.996 +    mm_log (tmp,ERROR);
 332.997 +    return NIL;
 332.998 +  default:
 332.999 +    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
332.1000 +    mm_log (tmp,ERROR);
332.1001 +    return NIL;
332.1002 +  }
332.1003 +				/* get sniffing stream for keywords */
332.1004 +  else if (!(tstream = mail_open (NIL,mailbox,
332.1005 +				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
332.1006 +    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
332.1007 +    MM_LOG (tmp,ERROR);
332.1008 +    return NIL;
332.1009 +  }
332.1010 +
332.1011 +				/* get first message */
332.1012 +  if (!(*af) (tstream,data,&flags,&date,&message)) return NIL;
332.1013 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
332.1014 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
332.1015 +    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
332.1016 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
332.1017 +      mm_log (tmp,ERROR);
332.1018 +      return NIL;
332.1019 +    }
332.1020 +    unlink (tmp);
332.1021 +  }
332.1022 +  do {				/* parse date */
332.1023 +    if (!date) rfc822_date (date = tmp);
332.1024 +    if (!mail_parse_date (&elt,date)) {
332.1025 +      sprintf (tmp,"Bad date in append: %.80s",date);
332.1026 +      mm_log (tmp,ERROR);
332.1027 +    }
332.1028 +    else {			/* user wants to suppress time zones? */
332.1029 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
332.1030 +	time_t when = mail_longdate (&elt);
332.1031 +	date = ctime (&when);	/* use traditional date */
332.1032 +      }
332.1033 +				/* use POSIX-style date */
332.1034 +      else date = mail_cdate (tmp,&elt);
332.1035 +      if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
332.1036 +      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
332.1037 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
332.1038 +	mm_log (tmp,ERROR);
332.1039 +      }
332.1040 +				/* get next message */
332.1041 +      else if ((*af) (tstream,data,&flags,&date,&message)) continue;
332.1042 +    }
332.1043 +    fclose (sf);		/* punt scratch file */
332.1044 +    return NIL;			/* give up */
332.1045 +  } while (message);		/* until no more messages */
332.1046 +  if (fflush (sf)) {
332.1047 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
332.1048 +    mm_log (tmp,ERROR);
332.1049 +    fclose (sf);		/* punt scratch file */
332.1050 +    return NIL;			/* give up */
332.1051 +  }
332.1052 +  i = ftell (sf);		/* size of scratch file */
332.1053 +
332.1054 +				/* close sniffing stream */
332.1055 +  if (tstream != stream) tstream = mail_close (tstream);
332.1056 +  mm_critical (stream);		/* go critical */
332.1057 +				/* try to open readwrite for UIDPLUS */
332.1058 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
332.1059 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
332.1060 +    tstream = mail_close (tstream);
332.1061 +  if (au && !tstream) {		/* wanted an APPENDUID? */
332.1062 +    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
332.1063 +    MM_LOG (tmp,WARN);
332.1064 +    au = NIL;
332.1065 +  }
332.1066 +  if (((fd = unix_lock (dummy_file (file,mailbox),
332.1067 +			O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
332.1068 +			lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) {
332.1069 +    mm_nocritical (stream);	/* done with critical */
332.1070 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
332.1071 +    mm_log (tmp,ERROR);
332.1072 +    return NIL;
332.1073 +  }
332.1074 +  fstat (fd,&sbuf);		/* get current file size */
332.1075 +  rewind (sf);
332.1076 +  times.modtime = time (0);	/* set mtime to now */
332.1077 +				/* write all messages */
332.1078 +  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
332.1079 +      (fflush (df) == EOF) || fsync (fd)) {
332.1080 +    sprintf (buf,"Message append failed: %s",strerror (errno));
332.1081 +    mm_log (buf,ERROR);
332.1082 +    ftruncate (fd,sbuf.st_size);/* revert file */
332.1083 +    times.actime =		/* preserve \Marked status */
332.1084 +      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
332.1085 +      sbuf.st_atime : times.modtime;
332.1086 +    ret = NIL;			/* return error */
332.1087 +  }
332.1088 +				/* set atime to now-1 if successful copy */
332.1089 +  else times.actime = times.modtime - 1;
332.1090 +  utime (file,&times);		/* set the times */
332.1091 +  fclose (sf);			/* done with scratch file */
332.1092 +				/* force UIDVALIDITY assignment now */
332.1093 +  if (tstream && !tstream->uid_validity)
332.1094 +    tstream->uid_validity = (unsigned long) time (0);
332.1095 +				/* return sets if doing APPENDUID */
332.1096 +  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
332.1097 +  else mail_free_searchset (&dst);
332.1098 +  flock (fd,LOCK_UN);		/* unlock mailbox (can't use unix_unlock() */
332.1099 +  if (lock && *lock) unlink (lock);
332.1100 +  fclose (df);			/* close mailbox */
332.1101 +  if (tstream) {		/* update last UID if we can */
332.1102 +    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
332.1103 +    local->dirty = T;		/* do a rewrite */
332.1104 +    local->appending = T;	/* but not at the cost of marking as old */
332.1105 +    tstream = mail_close (tstream);
332.1106 +  }
332.1107 +  mm_nocritical (stream);	/* release critical */
332.1108 +  return ret;
332.1109 +}
332.1110 +
332.1111 +/* Collect and write single message to append scratch file
332.1112 + * Accepts: MAIL stream
332.1113 + *	    scratch file
332.1114 + *	    flags
332.1115 + *	    date
332.1116 + *	    message stringstruct
332.1117 + * Returns: NIL if write error, else T
332.1118 + */
332.1119 +
332.1120 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
332.1121 +		     STRING *msg)
332.1122 +{
332.1123 +  unsigned char *s,*t;
332.1124 +  unsigned long uf;
332.1125 +  long f = mail_parse_flags (stream,flags,&uf);
332.1126 +				/* write metadata */
332.1127 +  if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL;
332.1128 +  for (s = date; *s; *s++) switch (*s) {
332.1129 +  default:
332.1130 +    if (putc (*s,sf) == EOF) return NIL;
332.1131 +  case '\r': case '\n':
332.1132 +    break;
332.1133 +  }
332.1134 +  if (fputs ("\r\n",sf) == EOF) return NIL;
332.1135 +  while (uf)			/* write user flags */    
332.1136 +    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
332.1137 +	(fprintf (sf," %s",s) < 0)) return NIL;
332.1138 +  if (fputs ("\r\n",sf) == EOF) return NIL;
332.1139 +  while (SIZE (msg)) {		/* copy text to scratch file */
332.1140 +    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
332.1141 +      if (!*s) *s = 0x80;	/* disallow NUL */
332.1142 +				/* write buffered text */
332.1143 +    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
332.1144 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
332.1145 +    else return NIL;		/* failed */
332.1146 +  }
332.1147 +				/* write trailing CRLF and return */
332.1148 +  return (fputs ("\r\n",sf) == EOF) ? NIL : T;
332.1149 +}
332.1150 +
332.1151 +/* Append messages from scratch file to mailbox
332.1152 + * Accepts: MAIL stream
332.1153 + *	    source file
332.1154 + *	    destination file
332.1155 + *	    uidset to update if non-NIL
332.1156 + * Returns: T if success, NIL if failure
332.1157 + */
332.1158 +
332.1159 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
332.1160 +{
332.1161 +  int ti,zn,c;
332.1162 +  long f;
332.1163 +  unsigned long i,j;
332.1164 +  char *x,tmp[MAILTMPLEN];
332.1165 +  int hdrp = T;
332.1166 +				/* get message metadata line */
332.1167 +  while (fgets (tmp,MAILTMPLEN,sf)) {
332.1168 +    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
332.1169 +    f = strtol (tmp,&x,10);	/* get flags */
332.1170 +    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
332.1171 +    i = strtoul (x,&x,10);	/* get message size */
332.1172 +    if ((*x++ != ' ') ||	/* build initial header */
332.1173 +	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
332.1174 +	(f&fSEEN && (putc ('R',df) == EOF)) ||
332.1175 +	(fputs ("\r\nX-Status: ",df) == EOF) ||
332.1176 +	(f&fDELETED && (putc ('D',df) == EOF)) ||
332.1177 +	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
332.1178 +	(f&fANSWERED && (putc ('A',df) == EOF)) ||
332.1179 +	(f&fDRAFT && (putc ('T',df) == EOF)) ||
332.1180 +	(fputs ("\r\nX-Keywords:",df) == EOF)) return NIL;
332.1181 +				/* copy keywords */
332.1182 +    while ((c = getc (sf)) != '\n') switch (c) {
332.1183 +    case EOF:
332.1184 +      return NIL;
332.1185 +    default:
332.1186 +      if (putc (c,df) == EOF) return NIL;
332.1187 +    }
332.1188 +    if ((putc ('\n',df) == EOF) ||
332.1189 +	(set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0)))
332.1190 +      return NIL;
332.1191 +
332.1192 +    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
332.1193 +				/* get read line length */
332.1194 +      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
332.1195 +      i -= j;			/* number of bytes left */
332.1196 +      if (!j) continue;		/* do nothing if line emptied */
332.1197 +				/* complete line? */
332.1198 +      if ((c == '\n')) switch (tmp[0]) {
332.1199 +      case 'F':			/* possible "From " (case counts here) */
332.1200 +	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
332.1201 +	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
332.1202 +	  if (!unix_fromwidget) {
332.1203 +	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
332.1204 +	    if (!ti) break;	/*  it looks like a valid header */
332.1205 +	  }			/* write the widget */
332.1206 +	  if (putc ('>',df) == EOF) return NIL;
332.1207 +	}
332.1208 +	break;
332.1209 +      case 'S': case 's':	/* possible "Status:" */
332.1210 +	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
332.1211 +	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
332.1212 +	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
332.1213 +	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
332.1214 +	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
332.1215 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
332.1216 +	break;
332.1217 +      case 'X': case 'x':	/* possible X-??? header */
332.1218 +	if (hdrp && (tmp[1] == '-') &&
332.1219 +				/* possible X-UID: */
332.1220 +	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
332.1221 +	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
332.1222 +	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
332.1223 +				/* possible X-IMAP: */
332.1224 +	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
332.1225 +	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
332.1226 +	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
332.1227 +	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
332.1228 +	      ((tmp[6] == ':') ||
332.1229 +				/* or X-IMAPbase: */
332.1230 +	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
332.1231 +		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
332.1232 +		((tmp[8] == 's') || (tmp[8] == 'S')) &&
332.1233 +		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
332.1234 +				/* possible X-Status: */
332.1235 +	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
332.1236 +	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
332.1237 +	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
332.1238 +	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
332.1239 +	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
332.1240 +	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
332.1241 +				/* possible X-Keywords: */
332.1242 +	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
332.1243 +	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
332.1244 +	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
332.1245 +	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
332.1246 +	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
332.1247 +	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
332.1248 +	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
332.1249 +	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
332.1250 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
332.1251 +	break;
332.1252 +      case '\n':		/* blank line */
332.1253 +	hdrp = NIL;
332.1254 +	break;
332.1255 +      default:			/* nothing to do */
332.1256 +	break;
332.1257 +      }
332.1258 +				/* just write the line */
332.1259 +      if (fwrite (tmp,1,j,df) != j) return NIL;
332.1260 +    }
332.1261 +    if (i) return NIL;		/* didn't read entire message */
332.1262 +				/* update set */
332.1263 +    if (stream) mail_append_set (set,stream->uid_last);
332.1264 +  }
332.1265 +  return T;
332.1266 +}
332.1267 +
332.1268 +/* Internal routines */
332.1269 +
332.1270 +
332.1271 +/* UNIX mail abort stream
332.1272 + * Accepts: MAIL stream
332.1273 + */
332.1274 +
332.1275 +void unix_abort (MAILSTREAM *stream)
332.1276 +{
332.1277 +  if (LOCAL) {			/* only if a file is open */
332.1278 +    if (LOCAL->fd >= 0) close (LOCAL->fd);
332.1279 +    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
332.1280 +      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
332.1281 +      close (LOCAL->ld);	/* close the lock file */
332.1282 +      unlink (LOCAL->lname);	/* and delete it */
332.1283 +    }
332.1284 +    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
332.1285 +				/* free local text buffers */
332.1286 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
332.1287 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
332.1288 +    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
332.1289 +    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
332.1290 +				/* nuke the local data */
332.1291 +    fs_give ((void **) &stream->local);
332.1292 +    stream->dtb = NIL;		/* log out the DTB */
332.1293 +  }
332.1294 +}
332.1295 +
332.1296 +/* UNIX open and lock mailbox
332.1297 + * Accepts: file name to open/lock
332.1298 + *	    file open mode
332.1299 + *	    destination buffer for lock file name
332.1300 + *	    type of locking operation (LOCK_SH or LOCK_EX)
332.1301 + */
332.1302 +
332.1303 +int unix_lock (char *file,int flags,int mode,char *lock,int op)
332.1304 +{
332.1305 +  int fd,ld,j;
332.1306 +  int i = LOCKTIMEOUT * 60 - 1;
332.1307 +  char tmp[MAILTMPLEN];
332.1308 +  time_t t;
332.1309 +  struct stat sb;
332.1310 +  sprintf (lock,"%s.lock",file);/* build lock filename */
332.1311 +  do {				/* until OK or out of tries */
332.1312 +    t = time (0);		/* get the time now */
332.1313 +				/* try to get the lock */
332.1314 +    if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0)
332.1315 +      close (ld);		/* got it, close the lock file! */
332.1316 +    else if (errno != EEXIST) {	/* miscellaneous error */
332.1317 +      sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno));
332.1318 +      if (!(i%15)) mm_log (tmp,WARN);
332.1319 +    }
332.1320 +				/* lock exists, still active? */
332.1321 +    else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) &&
332.1322 +	     ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0))
332.1323 +      close (ld);		/* got timed-out lock file */
332.1324 +    else {			/* active lock, try again */
332.1325 +      if (!(i%15)) {
332.1326 +	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
332.1327 +		 file,i);
332.1328 +	mm_log (tmp,WARN);
332.1329 +      }
332.1330 +      sleep (1);		/* wait a second before next retry */
332.1331 +    }
332.1332 +  } while (*lock && ld < 0 && i--);
332.1333 +				/* open file */
332.1334 +  if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
332.1335 +  else {			/* open failed */
332.1336 +    j = errno;			/* preserve error code */
332.1337 +    if (*lock) unlink (lock);	/* flush the lock file if any */
332.1338 +    errno = j;			/* restore error code */
332.1339 +  }
332.1340 +  return fd;
332.1341 +}
332.1342 +
332.1343 +/* UNIX unlock and close mailbox
332.1344 + * Accepts: file descriptor
332.1345 + *	    (optional) mailbox stream to check atime/mtime
332.1346 + *	    (optional) lock file name
332.1347 + */
332.1348 +
332.1349 +void unix_unlock (int fd,MAILSTREAM *stream,char *lock)
332.1350 +{
332.1351 +  if (stream) {			/* need to muck with times? */
332.1352 +    struct stat sbuf;
332.1353 +    struct utimbuf times;
332.1354 +    time_t now = time (0);
332.1355 +    fstat (fd,&sbuf);		/* get file times */
332.1356 +    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
332.1357 +      times.actime = now;	/* set atime to now */
332.1358 +				/* set mtime to (now - 1) if necessary */
332.1359 +      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
332.1360 +    }
332.1361 +    else if (stream->recent) {	/* readonly with recent messages */
332.1362 +      if ((sbuf.st_atime >= sbuf.st_mtime) ||
332.1363 +	  (sbuf.st_atime >= sbuf.st_ctime))
332.1364 +				/* keep past mtime, whack back atime */
332.1365 +	times.actime = (times.modtime = (sbuf.st_mtime < now) ?
332.1366 +			sbuf.st_mtime : now) - 1;
332.1367 +      else now = 0;		/* no time change needed */
332.1368 +    }
332.1369 +				/* readonly with no recent messages */
332.1370 +    else if ((sbuf.st_atime < sbuf.st_mtime) ||
332.1371 +	     (sbuf.st_atime < sbuf.st_ctime)) {
332.1372 +      times.actime = now;	/* set atime to now */
332.1373 +				/* set mtime to (now - 1) if necessary */
332.1374 +      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
332.1375 +    }
332.1376 +    else now = 0;		/* no time change needed */
332.1377 +				/* set the times, note change */
332.1378 +    if (now && !utime (stream->mailbox,&times))
332.1379 +      LOCAL->filetime = times.modtime;
332.1380 +  }
332.1381 +  flock (fd,LOCK_UN);		/* release flock'ers */
332.1382 +  if (!stream) close (fd);	/* close the file if no stream */
332.1383 +				/* flush the lock file if any */
332.1384 +  if (lock && *lock) unlink (lock);
332.1385 +}
332.1386 +
332.1387 +/* UNIX mail parse and lock mailbox
332.1388 + * Accepts: MAIL stream
332.1389 + *	    space to write lock file name
332.1390 + *	    type of locking operation
332.1391 + * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
332.1392 + */
332.1393 +
332.1394 +int unix_parse (MAILSTREAM *stream,char *lock,int op)
332.1395 +{
332.1396 +  int zn;
332.1397 +  unsigned long i,j,k,m;
332.1398 +  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
332.1399 +  int ti = 0,retain = T;
332.1400 +  unsigned long nmsgs = stream->nmsgs;
332.1401 +  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
332.1402 +  unsigned long recent = stream->recent;
332.1403 +  unsigned long oldnmsgs = stream->nmsgs;
332.1404 +  short silent = stream->silent;
332.1405 +  short pseudoseen = NIL;
332.1406 +  struct stat sbuf;
332.1407 +  STRING bs;
332.1408 +  FDDATA d;
332.1409 +  MESSAGECACHE *elt;
332.1410 +  mail_lock (stream);		/* guard against recursion or pingers */
332.1411 +				/* toss out previous descriptor */
332.1412 +  if (LOCAL->fd >= 0) close (LOCAL->fd);
332.1413 +  mm_critical (stream);		/* open and lock mailbox (shared OK) */
332.1414 +  if ((LOCAL->fd = unix_lock (stream->mailbox,
332.1415 +			      O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY),
332.1416 +			      NIL,lock,op)) < 0) {
332.1417 +    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
332.1418 +    mm_log (tmp,ERROR);
332.1419 +    unix_abort (stream);
332.1420 +    mail_unlock (stream);
332.1421 +    mm_nocritical (stream);	/* done with critical */
332.1422 +    return NIL;
332.1423 +  }
332.1424 +  fstat (LOCAL->fd,&sbuf);	/* get status */
332.1425 +				/* validate change in size */
332.1426 +  if (sbuf.st_size < LOCAL->filesize) {
332.1427 +    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
332.1428 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
332.1429 +    mm_log (tmp,ERROR);		/* this is pretty bad */
332.1430 +    unix_unlock (LOCAL->fd,stream,lock);
332.1431 +    unix_abort (stream);
332.1432 +    mail_unlock (stream);
332.1433 +    mm_nocritical (stream);	/* done with critical */
332.1434 +    return NIL;
332.1435 +  }
332.1436 +
332.1437 +				/* new data? */
332.1438 +  else if (i = sbuf.st_size - LOCAL->filesize) {
332.1439 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
332.1440 +    d.pos = LOCAL->filesize;	/* get to that position in the file */
332.1441 +    d.chunk = LOCAL->buf;	/* initial buffer chunk */
332.1442 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
332.1443 +    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
332.1444 +				/* skip leading whitespace for broken MTAs */
332.1445 +    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
332.1446 +	   (c == ' ') || (c == '\t')) SNX (&bs);
332.1447 +    if (SIZE (&bs)) {		/* read new data */
332.1448 +				/* remember internal header position */
332.1449 +      j = LOCAL->filesize + GETPOS (&bs);
332.1450 +      s = unix_mbxline (stream,&bs,&i);
332.1451 +      t = NIL,zn = 0;
332.1452 +      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
332.1453 +      if (!ti) {		/* someone pulled the rug from under us */
332.1454 +	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
332.1455 +		 (char *) s);
332.1456 +	mm_log (tmp,ERROR);
332.1457 +	unix_unlock (LOCAL->fd,stream,lock);
332.1458 +	unix_abort (stream);
332.1459 +	mail_unlock (stream);
332.1460 +	mm_nocritical (stream);	/* done with critical */
332.1461 +	return NIL;
332.1462 +      }
332.1463 +      stream->silent = T;	/* quell main program new message events */
332.1464 +      do {			/* found a message */
332.1465 +				/* instantiate first new message */
332.1466 +	mail_exists (stream,++nmsgs);
332.1467 +	(elt = mail_elt (stream,nmsgs))->valid = T;
332.1468 +	recent++;		/* assume recent by default */
332.1469 +	elt->recent = T;
332.1470 +				/* note position/size of internal header */
332.1471 +	elt->private.special.offset = j;
332.1472 +	elt->private.msg.header.offset = elt->private.special.text.size = i;
332.1473 +
332.1474 +				/* generate plausible IMAPish date string */
332.1475 +	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
332.1476 +	date[14] = date[17] = ':';
332.1477 +				/* dd */
332.1478 +	date[0] = t[ti - 2]; date[1] = t[ti - 1];
332.1479 +				/* mmm */
332.1480 +	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
332.1481 +				/* hh */
332.1482 +	date[12] = t[ti + 1]; date[13] = t[ti + 2];
332.1483 +				/* mm */
332.1484 +	date[15] = t[ti + 4]; date[16] = t[ti + 5];
332.1485 +	if (t[ti += 6] == ':') {/* ss */
332.1486 +	  date[18] = t[++ti]; date[19] = t[++ti];
332.1487 +	  ti++;			/* move to space */
332.1488 +	}
332.1489 +	else date[18] = date[19] = '0';
332.1490 +				/* yy -- advance over timezone if necessary */
332.1491 +	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
332.1492 +	date[7] = t[ti + 1]; date[8] = t[ti + 2];
332.1493 +	date[9] = t[ti + 3]; date[10] = t[ti + 4];
332.1494 +				/* zzz */
332.1495 +	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
332.1496 +	date[21] = *t++; date[22] = *t++; date[23] = *t++;
332.1497 +	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
332.1498 +	else {			/* numeric time zone */
332.1499 +	  date[24] = *t++; date[25] = *t++;
332.1500 +	  date[26] = '\0'; date[20] = ' ';
332.1501 +	}
332.1502 +				/* set internal date */
332.1503 +	if (!mail_parse_date (elt,date)) {
332.1504 +	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
332.1505 +	  mm_log (tmp,WARN);
332.1506 +	}
332.1507 +
332.1508 +	do {			/* look for message body */
332.1509 +	  s = t = unix_mbxline (stream,&bs,&i);
332.1510 +	  if (i) switch (*s) {	/* check header lines */
332.1511 +	  case 'X':		/* possible X-???: line */
332.1512 +	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
332.1513 +				/* X-Status: becomes Status: in S case */
332.1514 +	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
332.1515 +		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
332.1516 +				/* possible X-Keywords */
332.1517 +	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
332.1518 +		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
332.1519 +		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
332.1520 +		SIZEDTEXT uf;
332.1521 +		retain = NIL;	/* don't retain continuation */
332.1522 +		s += 11;	/* flush leading whitespace */
332.1523 +		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
332.1524 +		  while (*s == ' ') s++;
332.1525 +				/* find end of keyword */
332.1526 +		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
332.1527 +				/* got a keyword? */
332.1528 +		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
332.1529 +		    uf.data = (unsigned char *) s;
332.1530 +		    uf.size = k;
332.1531 +		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
332.1532 +		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
332.1533 +			elt->user_flags |= ((long) 1) << j;
332.1534 +			break;
332.1535 +		      }
332.1536 +		  }
332.1537 +		  s = u;	/* advance to next keyword */
332.1538 +		}
332.1539 +		break;
332.1540 +	      }
332.1541 +
332.1542 +				/* possible X-IMAP */
332.1543 +	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
332.1544 +		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
332.1545 +					 ((s[6] == 'b') && (s[7] == 'a') &&
332.1546 +					  (s[8] == 's') && (s[9] == 'e') &&
332.1547 +					  (s[10] == ':')))) {
332.1548 +		retain = NIL;	/* don't retain continuation */
332.1549 +		if ((nmsgs == 1) && !stream->uid_validity) {
332.1550 +				/* advance to data */
332.1551 +		  s += m ? 7 : 11;
332.1552 +				/* flush whitespace */
332.1553 +		  while (*s == ' ') s++;
332.1554 +		  j = 0;	/* slurp UID validity */
332.1555 +				/* found a digit? */
332.1556 +		  while (isdigit (*s)) {
332.1557 +		    j *= 10;	/* yes, add it in */
332.1558 +		    j += *s++ - '0';
332.1559 +		  }
332.1560 +				/* flush whitespace */
332.1561 +		  while (*s == ' ') s++;
332.1562 +				/* must have valid UID validity and UID last */
332.1563 +		  if (j && isdigit (*s)) {
332.1564 +				/* pseudo-header seen if X-IMAP */
332.1565 +		    if (m) pseudoseen = LOCAL->pseudo = T;
332.1566 +				/* save UID validity */
332.1567 +		    stream->uid_validity = j;
332.1568 +		    j = 0;	/* slurp UID last */
332.1569 +		    while (isdigit (*s)) {
332.1570 +		      j *= 10;	/* yes, add it in */
332.1571 +		      j += *s++ - '0';
332.1572 +		    }
332.1573 +				/* save UID last */
332.1574 +		    stream->uid_last = j;
332.1575 +				/* process keywords */
332.1576 +		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
332.1577 +			 s = u,j++) {
332.1578 +				/* flush leading whitespace */
332.1579 +		      while (*s == ' ') s++;
332.1580 +		      u = strpbrk (s," \n\r");
332.1581 +				/* got a keyword? */
332.1582 +		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
332.1583 +			  (k <= MAXUSERFLAG)) {
332.1584 +			if (stream->user_flags[j])
332.1585 +			  fs_give ((void **) &stream->user_flags[j]);
332.1586 +			stream->user_flags[j] = (char *) fs_get (k + 1);
332.1587 +			strncpy (stream->user_flags[j],s,k);
332.1588 +			stream->user_flags[j][k] = '\0';
332.1589 +		      }
332.1590 +		    }
332.1591 +		  }
332.1592 +		}
332.1593 +		break;
332.1594 +	      }
332.1595 +
332.1596 +				/* possible X-UID */
332.1597 +	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
332.1598 +		       s[5] == ':') {
332.1599 +		retain = NIL;	/* don't retain continuation */
332.1600 +				/* only believe if have a UID validity */
332.1601 +		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
332.1602 +		  s += 6;	/* advance to UID value */
332.1603 +				/* flush whitespace */
332.1604 +		  while (*s == ' ') s++;
332.1605 +		  j = 0;
332.1606 +				/* found a digit? */
332.1607 +		  while (isdigit (*s)) {
332.1608 +		    j *= 10;	/* yes, add it in */
332.1609 +		    j += *s++ - '0';
332.1610 +		  }
332.1611 +				/* flush remainder of line */
332.1612 +		  while (*s != '\n') s++;
332.1613 +				/* make sure not duplicated */
332.1614 +		  if (elt->private.uid)
332.1615 +		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
332.1616 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
332.1617 +			     j,elt->private.uid);
332.1618 +				/* make sure UID doesn't go backwards */
332.1619 +		  else if (j <= prevuid)
332.1620 +		    sprintf (tmp,"Message %lu UID %lu less than %lu",
332.1621 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
332.1622 +			     j,prevuid + 1);
332.1623 +#if 0	/* this is currently broken by UIDPLUS */
332.1624 +				/* or skip by mailbox's recorded last */
332.1625 +		  else if (j > stream->uid_last)
332.1626 +		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
332.1627 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
332.1628 +			     j,stream->uid_last);
332.1629 +#endif
332.1630 +		  else {	/* normal UID case */
332.1631 +		    prevuid = elt->private.uid = j;
332.1632 +#if 1	/* temporary kludge for UIDPLUS */
332.1633 +		    if (prevuid > stream->uid_last) {
332.1634 +		      stream->uid_last = prevuid;
332.1635 +		      LOCAL->ddirty = LOCAL->dirty = T;
332.1636 +		    }		    
332.1637 +#endif
332.1638 +		    break;	/* exit this cruft */
332.1639 +		  }
332.1640 +		  mm_log (tmp,WARN);
332.1641 +				/* invalidate UID validity */
332.1642 +		  stream->uid_validity = 0;
332.1643 +		  elt->private.uid = 0;
332.1644 +		}
332.1645 +		break;
332.1646 +	      }
332.1647 +	    }
332.1648 +				/* otherwise fall into S case */
332.1649 +
332.1650 +	  case 'S':		/* possible Status: line */
332.1651 +	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
332.1652 +		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
332.1653 +	      retain = NIL;	/* don't retain continuation */
332.1654 +	      s += 6;		/* advance to status flags */
332.1655 +	      do switch (*s++) {/* parse flags */
332.1656 +	      case 'R':		/* message read */
332.1657 +		elt->seen = T;
332.1658 +		break;
332.1659 +	      case 'O':		/* message old */
332.1660 +		if (elt->recent) {
332.1661 +		  elt->recent = NIL;
332.1662 +		  recent--;	/* it really wasn't recent */
332.1663 +		}
332.1664 +		break;
332.1665 +	      case 'D':		/* message deleted */
332.1666 +		elt->deleted = T;
332.1667 +		break;
332.1668 +	      case 'F':		/* message flagged */
332.1669 +		elt->flagged = T;
332.1670 +		break;
332.1671 +	      case 'A':		/* message answered */
332.1672 +		elt->answered = T;
332.1673 +		break;
332.1674 +	      case 'T':		/* message is a draft */
332.1675 +		elt->draft = T;
332.1676 +		break;
332.1677 +	      default:		/* some other crap */
332.1678 +		break;
332.1679 +	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
332.1680 +	      break;		/* all done */
332.1681 +	    }
332.1682 +				/* otherwise fall into default case */
332.1683 +
332.1684 +	  default:		/* ordinary header line */
332.1685 +	    if ((*s == 'S') || (*s == 's') ||
332.1686 +		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
332.1687 +	      unsigned char *e,*v;
332.1688 +				/* must match what mail_filter() does */
332.1689 +	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
332.1690 +		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
332.1691 +		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
332.1692 +				  (c != '\r') && (c != '\n')));
332.1693 +		   *v++ = *u++);
332.1694 +	      *v = '\0';	/* tie off */
332.1695 +				/* matches internal header? */
332.1696 +	      if (!compare_cstring (tmp,"STATUS") ||
332.1697 +		  !compare_cstring (tmp,"X-STATUS") ||
332.1698 +		  !compare_cstring (tmp,"X-KEYWORDS") ||
332.1699 +		  !compare_cstring (tmp,"X-UID") ||
332.1700 +		  !compare_cstring (tmp,"X-IMAP") ||
332.1701 +		  !compare_cstring (tmp,"X-IMAPBASE")) {
332.1702 +		char err[MAILTMPLEN];
332.1703 +		sprintf (err,"Discarding bogus %s header in message %lu",
332.1704 +			 (char *) tmp,elt->msgno);
332.1705 +		mm_log (err,WARN);
332.1706 +		retain = NIL;	/* don't retain continuation */
332.1707 +		break;		/* different case or something */
332.1708 +	      }
332.1709 +	    }
332.1710 +				/* retain or non-continuation? */
332.1711 +	    if (retain || ((*s != ' ') && (*s != '\t'))) {
332.1712 +	      retain = T;	/* retaining continuation now */
332.1713 +				/* line length in CRLF format newline */
332.1714 +	      k = i + (((i < 2) || (s[i - 2] != '\r')) ? 1 : 0);
332.1715 +				/* header size */
332.1716 +	      elt->rfc822_size = elt->private.spare.data += k;
332.1717 +	    }
332.1718 +	    else {
332.1719 +	      char err[MAILTMPLEN];
332.1720 +	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
332.1721 +		      elt->msgno,(char *) s);
332.1722 +	      if (u = strpbrk (err,"\r\n")) *u = '\0';
332.1723 +	      mm_log (err,WARN);
332.1724 +	      break;		/* different case or something */
332.1725 +	    }
332.1726 +	    break;
332.1727 +	  }
332.1728 +	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
332.1729 +				/* "internal" header sans trailing newline */
332.1730 +	if (i) elt->private.spare.data -= 2;
332.1731 +				/* assign a UID if none found */
332.1732 +	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
332.1733 +	  prevuid = elt->private.uid = ++stream->uid_last;
332.1734 +	  elt->private.dirty = T;
332.1735 +	  LOCAL->ddirty = T;	/* force update */
332.1736 +	}
332.1737 +	else elt->private.dirty = elt->recent;
332.1738 +
332.1739 +				/* note size of header, location of text */
332.1740 +	elt->private.msg.header.text.size = 
332.1741 +	  (elt->private.msg.text.offset =
332.1742 +	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
332.1743 +	     elt->private.special.text.size;
332.1744 +	k = m = 0;		/* no previous line size yet */
332.1745 +				/* note current position */
332.1746 +	j = LOCAL->filesize + GETPOS (&bs);
332.1747 +	if (i) do {		/* look for next message */
332.1748 +	  s = unix_mbxline (stream,&bs,&i);
332.1749 +	  if (i) {		/* got new data? */
332.1750 +	    VALID (s,t,ti,zn);	/* yes, parse line */
332.1751 +	    if (!ti) {		/* not a header line, add it to message */
332.1752 +	      if (s[i - 1] == '\n')
332.1753 +		elt->rfc822_size += 
332.1754 +		  k = i + (m = (((i < 2) || s[i - 2] != '\r') ? 1 : 0));
332.1755 +	      else {		/* file does not end with newline! */
332.1756 +		elt->rfc822_size += i;
332.1757 +		k = m = 0;
332.1758 +	      }
332.1759 +				/* update current position */
332.1760 +	      j = LOCAL->filesize + GETPOS (&bs);
332.1761 +	    }
332.1762 +	  }
332.1763 +	} while (i && !ti);	/* until found a header */
332.1764 +	elt->private.msg.text.text.size = j -
332.1765 +	  (elt->private.special.offset + elt->private.msg.text.offset);
332.1766 +	if (k == 2) {		/* last line was blank? */
332.1767 +	  elt->private.msg.text.text.size -= (m ? 1 : 2);
332.1768 +	  elt->rfc822_size -= 2;
332.1769 +	}
332.1770 +				/* until end of buffer */
332.1771 +      } while (!stream->sniff && i);
332.1772 +      if (pseudoseen) {		/* flush pseudo-message if present */
332.1773 +				/* decrement recent count */
332.1774 +	if (mail_elt (stream,1)->recent) recent--;
332.1775 +				/* and the exists count */
332.1776 +	mail_exists (stream,nmsgs--);
332.1777 +	mail_expunged(stream,1);/* fake an expunge of that message */
332.1778 +      }
332.1779 +				/* need to start a new UID validity? */
332.1780 +      if (!stream->uid_validity) {
332.1781 +	stream->uid_validity = (unsigned long) time (0);
332.1782 +	if (nmsgs) {		/* don't bother if empty file */
332.1783 +				/* make dirty to restart UID epoch */
332.1784 +	  LOCAL->ddirty = LOCAL->dirty = T;
332.1785 +				/* need to rewrite msg 1 if not pseudo */
332.1786 +	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
332.1787 +	  mm_log ("Assigning new unique identifiers to all messages",NIL);
332.1788 +	}
332.1789 +      }
332.1790 +      stream->nmsgs = oldnmsgs;	/* whack it back down */
332.1791 +      stream->silent = silent;	/* restore old silent setting */
332.1792 +				/* notify upper level of new mailbox sizes */
332.1793 +      mail_exists (stream,nmsgs);
332.1794 +      mail_recent (stream,recent);
332.1795 +				/* mark dirty so O flags are set */
332.1796 +      if (recent) LOCAL->dirty = T;
332.1797 +    }
332.1798 +  }
332.1799 +				/* no change, don't babble if never got time */
332.1800 +  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
332.1801 +    mm_log ("New mailbox modification time but apparently no changes",WARN);
332.1802 +				/* update parsed file size and time */
332.1803 +  LOCAL->filesize = sbuf.st_size;
332.1804 +  LOCAL->filetime = sbuf.st_mtime;
332.1805 +  return T;			/* return the winnage */
332.1806 +}
332.1807 +
332.1808 +/* UNIX read line from mailbox
332.1809 + * Accepts: mail stream
332.1810 + *	    stringstruct
332.1811 + *	    pointer to line size
332.1812 + * Returns: pointer to input line
332.1813 + */
332.1814 +
332.1815 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
332.1816 +{
332.1817 +  unsigned long i,j,k,m;
332.1818 +  char *s,*t,*te;
332.1819 +  char *ret = "";
332.1820 +				/* flush old buffer */
332.1821 +  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
332.1822 +				/* if buffer needs refreshing */
332.1823 +  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
332.1824 +  if (SIZE (bs)) {		/* find newline */
332.1825 +				/* end of fast scan */
332.1826 +    te = (t = (s = bs->curpos) + bs->cursize) - 12;
332.1827 +    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
332.1828 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
332.1829 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
332.1830 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
332.1831 +      --s;			/* back up */
332.1832 +      break;			/* exit loop */
332.1833 +    }
332.1834 +				/* final character-at-a-time scan */
332.1835 +    while ((s < t) && (*s != '\n')) ++s;
332.1836 +				/* difficult case if line spans buffer */
332.1837 +    if ((i = s - bs->curpos) == bs->cursize) {
332.1838 +				/* have space in line buffer? */
332.1839 +      if (i > LOCAL->linebuflen) {
332.1840 +	fs_give ((void **) &LOCAL->linebuf);
332.1841 +	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
332.1842 +      }
332.1843 +				/* remember what we have so far */
332.1844 +      memcpy (LOCAL->linebuf,bs->curpos,i);
332.1845 +				/* load next buffer */
332.1846 +      SETPOS (bs,k = GETPOS (bs) + i);
332.1847 +				/* end of fast scan */
332.1848 +      te = (t = (s = bs->curpos) + bs->cursize) - 12;
332.1849 +				/* fast scan in overlap buffer */
332.1850 +      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
332.1851 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
332.1852 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
332.1853 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
332.1854 +	--s;			/* back up */
332.1855 +	break;			/* exit loop */
332.1856 +      }
332.1857 +
332.1858 +				/* final character-at-a-time scan */
332.1859 +      while ((s < t) && (*s != '\n')) ++s;
332.1860 +				/* huge line? */
332.1861 +      if ((j = s - bs->curpos) == bs->cursize) {
332.1862 +	SETPOS (bs,GETPOS (bs) + j);
332.1863 +				/* look for end of line (s-l-o-w!!) */
332.1864 +	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
332.1865 +	SETPOS (bs,k);		/* go back to where it started */
332.1866 +      }
332.1867 +				/* got size of data, make buffer for return */
332.1868 +      ret = LOCAL->line = (char *) fs_get (i + j + 2);
332.1869 +				/* copy first chunk */
332.1870 +      memcpy (ret,LOCAL->linebuf,i);
332.1871 +      while (j) {		/* copy remainder */
332.1872 +	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
332.1873 +	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
332.1874 +	i += k;			/* account for this much read in */
332.1875 +	j -= k;
332.1876 +	bs->curpos += k;	/* increment new position */
332.1877 +	bs->cursize -= k;	/* eat that many bytes */
332.1878 +      }
332.1879 +      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
332.1880 +				/* read newline at end */
332.1881 +      if (SIZE (bs)) ret[i++] = SNX (bs);
332.1882 +      ret[i] = '\0';		/* makes debugging easier */
332.1883 +    }
332.1884 +    else {			/* this is easy */
332.1885 +      ret = bs->curpos;		/* string it at this position */
332.1886 +      bs->curpos += ++i;	/* increment new position */
332.1887 +      bs->cursize -= i;		/* eat that many bytes */
332.1888 +    }
332.1889 +    *size = i;			/* return that to user */
332.1890 +  }
332.1891 +  else *size = 0;		/* end of data, return empty */
332.1892 +  return ret;
332.1893 +}
332.1894 +
332.1895 +/* UNIX make pseudo-header
332.1896 + * Accepts: MAIL stream
332.1897 + *	    buffer to write pseudo-header
332.1898 + * Returns: length of pseudo-header
332.1899 + */
332.1900 +
332.1901 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
332.1902 +{
332.1903 +  int i;
332.1904 +  char *s,*t,tmp[MAILTMPLEN];
332.1905 +  time_t now = time(0);
332.1906 +  rfc822_fixed_date (tmp);
332.1907 +  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",
332.1908 +	   pseudo_from,ctime (&now),
332.1909 +	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
332.1910 +	   (unsigned long) now,mylocalhost (),stream->uid_validity,
332.1911 +	   stream->uid_last);
332.1912 +  for (t = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
332.1913 +    if (stream->user_flags[i])
332.1914 +      sprintf (t += strlen (t)," %s",stream->user_flags[i]);
332.1915 +  strcpy (t += strlen (t),"\r\nStatus: RO\r\n\r\n");
332.1916 +  for (s = pseudo_msg,t += strlen (t); *s; *t++ = *s++)
332.1917 +    if (*s == '\n') *t++ = '\r';
332.1918 +  *t++ = '\r'; *t++ = '\n'; *t++ = '\r'; *t++ = '\n';
332.1919 +  *t = '\0';			/* tie off pseudo header */
332.1920 +  return t - hdr;		/* return length of pseudo header */
332.1921 +}
332.1922 +
332.1923 +/* UNIX make status string
332.1924 + * Accepts: MAIL stream
332.1925 + *	    destination string to write
332.1926 + *	    message cache entry
332.1927 + *	    UID to write if non-zero (else use elt->private.uid)
332.1928 + *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
332.1929 + * Returns: length of string
332.1930 + */
332.1931 +
332.1932 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
332.1933 +			    unsigned long uid,long flag)
332.1934 +{
332.1935 +  char *t,stack[64];
332.1936 +  char *s = status;
332.1937 +  unsigned long n;
332.1938 +  unsigned long pad = 50;
332.1939 +  /* This used to use sprintf(), but thanks to certain cretinous C libraries
332.1940 +     with horribly slow implementations of sprintf() I had to change it to this
332.1941 +     mess.  At least it should be fast. */
332.1942 +  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
332.1943 +  *s++ = ':'; *s++ = ' ';
332.1944 +  if (elt->seen) *s++ = 'R';
332.1945 +				/* only write O if have a UID */
332.1946 +  if (flag && (!elt->recent || LOCAL->appending)) *s++ = 'O';
332.1947 +  *s++ = '\r'; *s++ = '\n';
332.1948 +  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
332.1949 +  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
332.1950 +  if (elt->deleted) *s++ = 'D';
332.1951 +  if (elt->flagged) *s++ = 'F';
332.1952 +  if (elt->answered) *s++ = 'A';
332.1953 +  if (elt->draft) *s++ = 'T';
332.1954 +  *s++ = '\r'; *s++ = '\n';
332.1955 +
332.1956 +  *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
332.1957 +  *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
332.1958 +  if (n = elt->user_flags) do {
332.1959 +    *s++ = ' ';
332.1960 +    for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
332.1961 +  } while (n);
332.1962 +  n = s - status;		/* get size of stuff so far */
332.1963 +				/* pad X-Keywords to make size constant */
332.1964 +  if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
332.1965 +  *s++ = '\r'; *s++ = '\n';
332.1966 +  if (flag) {			/* want to include UID? */
332.1967 +    t = stack;
332.1968 +				/* push UID digits on the stack */
332.1969 +    n = uid ? uid : elt->private.uid;
332.1970 +    do *t++ = (char) (n % 10) + '0';
332.1971 +    while (n /= 10);
332.1972 +    *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
332.1973 +    *s++ = ' ';
332.1974 +				/* pop UID from stack */
332.1975 +    while (t > stack) *s++ = *--t;
332.1976 +    *s++ = '\r'; *s++ = '\n';
332.1977 +  }
332.1978 +				/* end of extended message status */
332.1979 +  *s++ = '\r'; *s++ = '\n'; *s = '\0';
332.1980 +  return s - status;		/* return size of resulting string */
332.1981 +}
332.1982 +
332.1983 +/* Rewrite mailbox file
332.1984 + * Accepts: MAIL stream, must be critical and locked
332.1985 + *	    return pointer to number of expunged messages if want expunge
332.1986 + *	    lock file name
332.1987 + *	    expunge sequence, not deleted flag
332.1988 + * Returns: T if success and mailbox unlocked, NIL if failure
332.1989 + */
332.1990 +
332.1991 +#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
332.1992 +
332.1993 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
332.1994 +		   long flags)
332.1995 +{
332.1996 +  MESSAGECACHE *elt;
332.1997 +  UNIXFILE f;
332.1998 +  char *s;
332.1999 +  struct utimbuf times;
332.2000 +  long ret,flag;
332.2001 +  unsigned long i,j;
332.2002 +  unsigned long recent = stream->recent;
332.2003 +  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
332.2004 +  if (nexp) *nexp = 0;		/* initially nothing expunged */
332.2005 +				/* calculate size of mailbox after rewrite */
332.2006 +  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
332.2007 +    elt = mail_elt (stream,i);	/* get cache */
332.2008 +    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
332.2009 +				/* add RFC822 size of this message */
332.2010 +      size += elt->private.special.text.size + elt->private.spare.data +
332.2011 +	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
332.2012 +	  elt->private.msg.text.text.size + 2;
332.2013 +      flag = 1;			/* only count X-IMAPbase once */
332.2014 +    }
332.2015 +  }
332.2016 +  if (!size) {			/* no messages and no pseudo, make one now */
332.2017 +    size = unix_pseudo (stream,LOCAL->buf);
332.2018 +    LOCAL->pseudo = T;
332.2019 +  }
332.2020 +				/* extend the file as necessary */
332.2021 +  if (ret = unix_extend (stream,size)) {
332.2022 +    /* Set up buffered I/O file structure
332.2023 +     * curpos	current position being written through buffering
332.2024 +     * filepos	current position being written physically to the disk
332.2025 +     * bufpos	current position being written in the buffer
332.2026 +     * protect	current maximum position that can be written to the disk
332.2027 +     *		before buffering is forced
332.2028 +     * The code tries to buffer so that that disk is written in multiples of
332.2029 +     * OVERBLOWBUFLEN bytes.
332.2030 +     */
332.2031 +    f.stream = stream;		/* note mail stream */
332.2032 +    f.curpos = f.filepos = 0;	/* start of file */
332.2033 +    f.protect = stream->nmsgs ?	/* initial protection pointer */
332.2034 +    mail_elt (stream,1)->private.special.offset : 8192;
332.2035 +    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
332.2036 +
332.2037 +    if (LOCAL->pseudo)		/* update pseudo-header */
332.2038 +      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
332.2039 +				/* loop through all messages */
332.2040 +    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
332.2041 +      elt = mail_elt (stream,i);/* get cache */
332.2042 +				/* expunge this message? */
332.2043 +      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
332.2044 +				/* one less recent message */
332.2045 +	if (elt->recent) --recent;
332.2046 +	mail_expunged(stream,i);/* notify upper levels */
332.2047 +	++*nexp;		/* count up one more expunged message */
332.2048 +      }
332.2049 +      else {			/* preserve this message */
332.2050 +	i++;			/* advance to next message */
332.2051 +	if ((flag < 0) ||	/* need to rewrite message? */
332.2052 +	    elt->private.dirty ||
332.2053 +	    (((unsigned long) f.curpos) != elt->private.special.offset) ||
332.2054 +	    (elt->private.msg.header.text.size !=
332.2055 +	     (elt->private.spare.data +
332.2056 +	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
332.2057 +	  unsigned long newoffset = f.curpos;
332.2058 +				/* yes, seek to internal header */
332.2059 +	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
332.2060 +	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
332.2061 +				/* protection pointer moves to RFC822 header */
332.2062 +	  f.protect = elt->private.special.offset +
332.2063 +	    elt->private.msg.header.offset;
332.2064 +				/* write internal header */
332.2065 +	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
332.2066 +				/* get RFC822 header */
332.2067 +	  s = unix_header (stream,elt->msgno,&j,NIL);
332.2068 +				/* in case this got decremented */
332.2069 +	  elt->private.msg.header.offset = elt->private.special.text.size;
332.2070 +				/* header size, sans trailing newline */
332.2071 +	  if ((j < 4) || (s[j - 4] == '\r')) j -= 2;
332.2072 +	  if (j != elt->private.spare.data) fatal ("header size inconsistent");
332.2073 +				/* protection pointer moves to RFC822 text */
332.2074 +	  f.protect = elt->private.special.offset +
332.2075 +	    elt->private.msg.text.offset;
332.2076 +	  unix_write (&f,s,j);	/* write RFC822 header */
332.2077 +				/* write status and UID */
332.2078 +	  unix_write (&f,LOCAL->buf,
332.2079 +		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
332.2080 +	  flag = 1;		/* only write X-IMAPbase once */
332.2081 +				/* new file header size */
332.2082 +	  elt->private.msg.header.text.size = elt->private.spare.data + j;
332.2083 +
332.2084 +				/* did text move? */
332.2085 +	  if (f.curpos != f.protect) {
332.2086 +				/* get message text */
332.2087 +	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
332.2088 +				/* can't happen it says here */
332.2089 +	    if (j > elt->private.msg.text.text.size)
332.2090 +	      fatal ("text size inconsistent");
332.2091 +				/* new text offset, status/UID may change it */
332.2092 +	    elt->private.msg.text.offset = f.curpos - newoffset;
332.2093 +				/* protection pointer moves to next message */
332.2094 +	    f.protect = (i <= stream->nmsgs) ?
332.2095 +	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 2);
332.2096 +	    unix_write (&f,s,j);/* write text */
332.2097 +				/* write trailing newline */
332.2098 +	    unix_write (&f,"\r\n",2);
332.2099 +	  }
332.2100 +	  else {		/* tie off header and status */
332.2101 +	    unix_write (&f,NIL,NIL);
332.2102 +				/* protection pointer moves to next message */
332.2103 +	    f.protect = (i <= stream->nmsgs) ?
332.2104 +	      mail_elt (stream,i)->private.special.offset : size;
332.2105 +				/* locate end of message text */
332.2106 +	    j = f.filepos + elt->private.msg.text.text.size;
332.2107 +				/* trailing newline already there? */
332.2108 +	    if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
332.2109 +	    else {		/* trailing newline missing, write it */
332.2110 +	      f.curpos = f.filepos = j;
332.2111 +	      unix_write (&f,"\r\n",2);
332.2112 +	    }
332.2113 +	  }
332.2114 +				/* new internal header offset */
332.2115 +	  elt->private.special.offset = newoffset;
332.2116 +	  elt->private.dirty =NIL;/* message is now clean */
332.2117 +	}
332.2118 +	else {			/* no need to rewrite this message */
332.2119 +				/* tie off previous message if needed */
332.2120 +	  unix_write (&f,NIL,NIL);
332.2121 +				/* protection pointer moves to next message */
332.2122 +	  f.protect = (i <= stream->nmsgs) ?
332.2123 +	    mail_elt (stream,i)->private.special.offset : size;
332.2124 +				/* locate end of message text */
332.2125 +	  j = f.filepos + elt->private.special.text.size +
332.2126 +	    elt->private.msg.header.text.size +
332.2127 +	      elt->private.msg.text.text.size;
332.2128 +				/* trailing newline already there? */
332.2129 +	  if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
332.2130 +	  else {		/* trailing newline missing, write it */
332.2131 +	    f.curpos = f.filepos = j;
332.2132 +	    unix_write (&f,"\r\n",2);
332.2133 +	  }
332.2134 +	}
332.2135 +      }
332.2136 +    }
332.2137 +
332.2138 +    unix_write (&f,NIL,NIL);	/* tie off final message */
332.2139 +    if (size != ((unsigned long) f.filepos)) fatal ("file size inconsistent");
332.2140 +    fs_give ((void **) &f.buf);	/* free buffer */
332.2141 +				/* make sure tied off */
332.2142 +    ftruncate (LOCAL->fd,LOCAL->filesize = size);
332.2143 +    fsync (LOCAL->fd);		/* make sure the updates take */
332.2144 +    if (size && (flag < 0)) fatal ("lost UID base information");
332.2145 +				/* no longer dirty */
332.2146 +    LOCAL->ddirty = LOCAL->dirty = NIL;
332.2147 +  				/* notify upper level of new mailbox sizes */
332.2148 +    mail_exists (stream,stream->nmsgs);
332.2149 +    mail_recent (stream,recent);
332.2150 +				/* set atime to now, mtime a second earlier */
332.2151 +    times.modtime = (times.actime = time (0)) -1;
332.2152 +				/* set the times, note change */
332.2153 +    if (!utime (stream->mailbox,&times)) LOCAL->filetime = times.modtime;
332.2154 +				/* flush the lock file */
332.2155 +    unix_unlock (LOCAL->fd,stream,lock);
332.2156 +  }
332.2157 +  return ret;			/* return state from algorithm */
332.2158 +}
332.2159 +
332.2160 +/* Extend UNIX mailbox file
332.2161 + * Accepts: MAIL stream
332.2162 + *	    new desired size
332.2163 + * Return: T if success, else NIL
332.2164 + */
332.2165 +
332.2166 +long unix_extend (MAILSTREAM *stream,unsigned long size)
332.2167 +{
332.2168 +  unsigned long i = (size > ((unsigned long) LOCAL->filesize)) ?
332.2169 +    size - ((unsigned long) LOCAL->filesize) : 0;
332.2170 +  if (i) {			/* does the mailbox need to grow? */
332.2171 +    if (i > LOCAL->buflen) {	/* make sure have enough space */
332.2172 +				/* this user won the lottery all right */
332.2173 +      fs_give ((void **) &LOCAL->buf);
332.2174 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
332.2175 +    }
332.2176 +    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
332.2177 +    while (T) {			/* until write successful or punt */
332.2178 +      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
332.2179 +      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
332.2180 +      else {
332.2181 +	long e = errno;		/* note error before doing ftruncate */
332.2182 +	ftruncate (LOCAL->fd,LOCAL->filesize);
332.2183 +	if (mm_diskerror (stream,e,NIL)) {
332.2184 +	  fsync (LOCAL->fd);	/* user chose to punt */
332.2185 +	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
332.2186 +	  if (!stream->silent) mm_log (LOCAL->buf,ERROR);
332.2187 +	  return NIL;
332.2188 +	}
332.2189 +      }
332.2190 +    }
332.2191 +  }
332.2192 +  return LONGT;
332.2193 +}
332.2194 +
332.2195 +/* Write data to buffered file
332.2196 + * Accepts: buffered file pointer
332.2197 + *	    file data or NIL to indicate "flush buffer"
332.2198 + *	    date size (ignored for "flush buffer")
332.2199 + * Does not return until success
332.2200 + */
332.2201 +
332.2202 +void unix_write (UNIXFILE *f,char *buf,unsigned long size)
332.2203 +{
332.2204 +  unsigned long i,j,k;
332.2205 +  if (buf) {			/* doing buffered write? */
332.2206 +    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
332.2207 +				/* yes, have space in current buffer chunk? */
332.2208 +    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
332.2209 +				/* yes, fill up buffer as much as we can */
332.2210 +      memcpy (f->bufpos,buf,k = min (j,size));
332.2211 +      f->bufpos += k;		/* new buffer position */
332.2212 +      f->curpos += k;		/* new current position */
332.2213 +      if (j -= k) return;	/* all done if still have buffer free space */
332.2214 +      buf += k;			/* full, get new unwritten data pointer */
332.2215 +      size -= k;		/* new data size */
332.2216 +      i += k;			/* new buffer data size */
332.2217 +    }
332.2218 +    /* This chunk of the buffer is full.  See if can make some space by
332.2219 +     * writing to the disk, if there's enough unprotected space to do so.
332.2220 +     * Try to fill out any unaligned chunk, along with any subsequent full
332.2221 +     * chunks that will fit in unprotected space.
332.2222 +     */
332.2223 +				/* any unprotected space we can write to? */
332.2224 +    if (j = min (i,f->protect - f->filepos)) {
332.2225 +				/* yes, filepos not at chunk boundary? */
332.2226 +      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
332.2227 +	j -= k;			/* yes, and can write out partial chunk */
332.2228 +      else k = 0;		/* no partial chunk to write */
332.2229 +				/* if at least a chunk free, write that too */
332.2230 +      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
332.2231 +      if (k) {			/* write data if there is anything we can */
332.2232 +	unix_phys_write (f,f->buf,k);
332.2233 +				/* slide buffer */
332.2234 +	if (i -= k) memmove (f->buf,f->buf + k,i);
332.2235 +	f->bufpos = f->buf + i;	/* new end of buffer */
332.2236 +      }
332.2237 +    }
332.2238 +
332.2239 +    /* Have flushed the buffer as best as possible.  All done if no more
332.2240 +     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
332.2241 +     * data is larger than a chunk AND the unprotected space is also larger
332.2242 +     * than a chunk, then write as many chunks as we can directly from the
332.2243 +     * data.  Buffer the rest, expanding the buffer as needed.
332.2244 +     */
332.2245 +    if (size) {			/* have more data that we need to buffer? */
332.2246 +				/* can write any of it to disk instead? */
332.2247 +      if ((f->bufpos == f->buf) && 
332.2248 +	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
332.2249 +				/* write as much as we can right now */
332.2250 +	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
332.2251 +	buf += j;		/* new data pointer */
332.2252 +	size -= j;		/* new data size */
332.2253 +	f->curpos += j;		/* advance current pointer */
332.2254 +      }
332.2255 +      if (size) {		/* still have data that we need to buffer? */
332.2256 +				/* yes, need to expand the buffer? */
332.2257 +	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
332.2258 +				/* note current position in buffer */
332.2259 +	  j = f->bufpos - f->buf;
332.2260 +	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
332.2261 +	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
332.2262 +				/* in case buffer relocated */
332.2263 +	  f->bufpos = f->buf + j;
332.2264 +	}
332.2265 +				/* buffer remaining data */
332.2266 +	memcpy (f->bufpos,buf,size);
332.2267 +	f->bufpos += size;	/* new end of buffer */
332.2268 +	f->curpos += size;	/* advance current pointer */
332.2269 +      }
332.2270 +    }
332.2271 +  }
332.2272 +  else {			/* flush buffer to disk */
332.2273 +    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
332.2274 +    f->bufpos = f->buf;		/* reset buffer */
332.2275 +				/* update positions */
332.2276 +    f->curpos = f->protect = f->filepos;
332.2277 +  }
332.2278 +}
332.2279 +
332.2280 +/* Physical disk write
332.2281 + * Accepts: buffered file pointer
332.2282 + *	    buffer address
332.2283 + *	    buffer size
332.2284 + * Does not return until success
332.2285 + */
332.2286 +
332.2287 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
332.2288 +{
332.2289 +  MAILSTREAM *stream = f->stream;
332.2290 +				/* write data at desired position */
332.2291 +  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
332.2292 +		  (write (LOCAL->fd,buf,size) < 0))) {
332.2293 +    int e;
332.2294 +    char tmp[MAILTMPLEN];
332.2295 +    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
332.2296 +    mm_log (tmp,ERROR);
332.2297 +    mm_diskerror (NIL,e,T);	/* serious problem, must retry */
332.2298 +  }
332.2299 +  f->filepos += size;		/* update file position */
332.2300 +}
   333.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   333.2 +++ b/src/osdep/os2/unixnt.h	Mon Sep 14 15:17:45 2009 +0900
   333.3 @@ -0,0 +1,161 @@
   333.4 +/* ========================================================================
   333.5 + * Copyright 1988-2006 University of Washington
   333.6 + *
   333.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   333.8 + * you may not use this file except in compliance with the License.
   333.9 + * You may obtain a copy of the License at
  333.10 + *
  333.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  333.12 + *
  333.13 + * 
  333.14 + * ========================================================================
  333.15 + */
  333.16 +
  333.17 +/*
  333.18 + * Program:	UNIX mail routines
  333.19 + *
  333.20 + * Author:	Mark Crispin
  333.21 + *		Networks and Distributed Computing
  333.22 + *		Computing & Communications
  333.23 + *		University of Washington
  333.24 + *		Administration Building, AG-44
  333.25 + *		Seattle, WA  98195
  333.26 + *		Internet: MRC@CAC.Washington.EDU
  333.27 + *
  333.28 + * Date:	20 December 1989
  333.29 + * Last Edited:	30 August 2006
  333.30 + */
  333.31 +
  333.32 +
  333.33 +/*				DEDICATION
  333.34 + *
  333.35 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  333.36 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  333.37 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  333.38 + * a two-month bout with cirrhosis of the liver.
  333.39 + *
  333.40 + *  He was a dear friend, and I miss him terribly.
  333.41 + *
  333.42 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  333.43 + */
  333.44 +
  333.45 +/* Validate line
  333.46 + * Accepts: pointer to candidate string to validate as a From header
  333.47 + *	    return pointer to end of date/time field
  333.48 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  333.49 + *	    return pointer to offset from t of time zone (if non-zero)
  333.50 + * Returns: t,ti,zn set if valid From string, else ti is NIL
  333.51 + */
  333.52 +
  333.53 +#define VALID(s,x,ti,zn) {						\
  333.54 +  ti = 0;								\
  333.55 +  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
  333.56 +      (s[4] == ' ')) {							\
  333.57 +    for (x = s + 5; *x && *x != '\012'; x++);				\
  333.58 +    if (*x) {								\
  333.59 +      if (x[-1] == '\015') --x;						\
  333.60 +      if (x - s >= 41) {						\
  333.61 +	for (zn = -1; x[zn] != ' '; zn--);				\
  333.62 +	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
  333.63 +	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
  333.64 +	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
  333.65 +	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
  333.66 +	  x += zn - 12;							\
  333.67 +      }									\
  333.68 +      if (x - s >= 27) {						\
  333.69 +	if (x[-5] == ' ') {						\
  333.70 +	  if (x[-8] == ':') zn = 0,ti = -5;				\
  333.71 +	  else if (x[-9] == ' ') ti = zn = -9;				\
  333.72 +	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
  333.73 +	    ti = zn = -11;						\
  333.74 +	}								\
  333.75 +	else if (x[-4] == ' ') {					\
  333.76 +	  if (x[-9] == ' ') zn = -4,ti = -9;				\
  333.77 +	}								\
  333.78 +	else if (x[-6] == ' ') {					\
  333.79 +	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
  333.80 +	    zn = -6,ti = -11;						\
  333.81 +	}								\
  333.82 +	if (ti && !((x[ti - 3] == ':') &&				\
  333.83 +		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
  333.84 +		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
  333.85 +		    (x[ti - 11] == ' '))) ti = 0;			\
  333.86 +      }									\
  333.87 +    }									\
  333.88 +  }									\
  333.89 +}
  333.90 +
  333.91 +/* You are not expected to understand this macro, but read the next page if
  333.92 + * you are not faint of heart.
  333.93 + *
  333.94 + * Known formats to the VALID macro are:
  333.95 + *		From user Wed Dec  2 05:53 1992
  333.96 + * BSD		From user Wed Dec  2 05:53:22 1992
  333.97 + * SysV		From user Wed Dec  2 05:53 PST 1992
  333.98 + * rn		From user Wed Dec  2 05:53:22 PST 1992
  333.99 + *		From user Wed Dec  2 05:53 -0700 1992
 333.100 + * emacs	From user Wed Dec  2 05:53:22 -0700 1992
 333.101 + *		From user Wed Dec  2 05:53 1992 PST
 333.102 + *		From user Wed Dec  2 05:53:22 1992 PST
 333.103 + *		From user Wed Dec  2 05:53 1992 -0700
 333.104 + * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
 333.105 + *
 333.106 + * Plus all of the above with `` remote from xxx'' after it. Thank you very
 333.107 + * much, smail and Solaris, for making my life considerably more complicated.
 333.108 + */
 333.109 +
 333.110 +/*
 333.111 + * What?  You want to understand the VALID macro anyway?  Alright, since you
 333.112 + * insist.  Actually, it isn't really all that difficult, provided that you
 333.113 + * take it step by step.
 333.114 + *
 333.115 + * Line 1	Initializes the return ti value to failure (0);
 333.116 + * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
 333.117 + * Lines 4-6	Validates that there is an end of line and points x at it.
 333.118 + * Lines 7-14	First checks to see if the line is at least 41 characters long.
 333.119 + *		If so, it scans backwards to find the rightmost space.  From
 333.120 + *		that point, it scans backwards to see if the string matches
 333.121 + *		`` remote from''.  If so, it sets x to point to the space at
 333.122 + *		the start of the string.
 333.123 + * Line 15	Makes sure that there are at least 27 characters in the line.
 333.124 + * Lines 16-21	Checks if the date/time ends with the year (there is a space
 333.125 + *		five characters back).  If there is a colon three characters
 333.126 + *		further back, there is no timezone field, so zn is set to 0
 333.127 + *		and ti is set in front of the year.  Otherwise, there must
 333.128 + *		either to be a space four characters back for a three-letter
 333.129 + *		timezone, or a space six characters back followed by a + or -
 333.130 + *		for a numeric timezone; in either case, zn and ti become the
 333.131 + *		offset of the space immediately before it.
 333.132 + * Lines 22-24	Are the failure case for line 14.  If there is a space four
 333.133 + *		characters back, it is a three-letter timezone; there must be a
 333.134 + *		space for the year nine characters back.  zn is the zone
 333.135 + *		offset; ti is the offset of the space.
 333.136 + * Lines 25-28	Are the failure case for line 20.  If there is a space six
 333.137 + *		characters back, it is a numeric timezone; there must be a
 333.138 + *		space eleven characters back and a + or - five characters back.
 333.139 + *		zn is the zone offset; ti is the offset of the space.
 333.140 + * Line 29-32	If ti is valid, make sure that the string before ti is of the
 333.141 + *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
 333.142 + *		invalidate ti.  There must be a colon three characters back
 333.143 + *		and a space six or nine	characters back (depending upon
 333.144 + *		whether or not the character six characters back is a colon).
 333.145 + *		There must be a space three characters further back (in front
 333.146 + *		of the day), one seven characters back (in front of the month),
 333.147 + *		and one eleven characters back (in front of the day of week).
 333.148 + *		ti is set to be the offset of the space before the time.
 333.149 + *
 333.150 + * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
 333.151 + * newer pipelined machines it is faster being open-coded than it would be if
 333.152 + * subroutines are called.
 333.153 + *
 333.154 + * Why does it scan backwards from the end of the line, instead of doing the
 333.155 + * much easier forward scan?  There is no deterministic way to parse the
 333.156 + * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
 333.157 + * see if unquoted spaces were possible.  They are, and I've encountered enough
 333.158 + * evil mail to be totally unwilling to trust that ``it will never happen''.
 333.159 + */
 333.160 +
 333.161 +/* Build parameters */
 333.162 +
 333.163 +#define KODRETRY 15		/* kiss-of-death retry in seconds */
 333.164 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
   334.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   334.2 +++ b/src/osdep/os2/write.c	Mon Sep 14 15:17:45 2009 +0900
   334.3 @@ -0,0 +1,59 @@
   334.4 +/* ========================================================================
   334.5 + * Copyright 1988-2006 University of Washington
   334.6 + *
   334.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   334.8 + * you may not use this file except in compliance with the License.
   334.9 + * You may obtain a copy of the License at
  334.10 + *
  334.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  334.12 + *
  334.13 + * 
  334.14 + * ========================================================================
  334.15 + */
  334.16 +
  334.17 +/*
  334.18 + * Program:	Write data, treating partial writes as an error
  334.19 + *
  334.20 + * Author:	Mark Crispin
  334.21 + *		Networks and Distributed Computing
  334.22 + *		Computing & Communications
  334.23 + *		University of Washington
  334.24 + *		Administration Building, AG-44
  334.25 + *		Seattle, WA  98195
  334.26 + *		Internet: MRC@CAC.Washington.EDU
  334.27 + *
  334.28 + * Date:	26 May 1995
  334.29 + * Last Edited:	30 August 2006
  334.30 + */
  334.31 +
  334.32 +/*  The whole purpose of this unfortunate routine is to deal with DOS and
  334.33 + * certain cretinous versions of UNIX which decided that the "bytes actually
  334.34 + * written" return value from write() gave them license to use that for things
  334.35 + * that are really errors, such as disk quota exceeded, maximum file size
  334.36 + * exceeded, disk full, etc.
  334.37 + * 
  334.38 + *  BSD won't screw us this way on the local filesystem, but who knows what
  334.39 + * some NFS-mounted filesystem will do.
  334.40 + */
  334.41 +
  334.42 +#undef write
  334.43 +
  334.44 +/* Write data to file
  334.45 + * Accepts: file descriptor
  334.46 + *	    I/O vector structure
  334.47 + *	    number of vectors in structure
  334.48 + * Returns: number of bytes written if successful, -1 if failure
  334.49 + */
  334.50 +
  334.51 +long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
  334.52 +
  334.53 +long safe_write (int fd,char *buf,long nbytes)
  334.54 +{
  334.55 +  long i,j;
  334.56 +  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
  334.57 +    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
  334.58 +	   (errno == EINTR));
  334.59 +    if (j < 0) return j;
  334.60 +  }
  334.61 +  return nbytes;
  334.62 +}
   335.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   335.2 +++ b/src/osdep/tops-20/build.ctl	Mon Sep 14 15:17:45 2009 +0900
   335.3 @@ -0,0 +1,63 @@
   335.4 +! ========================================================================
   335.5 +! Copyright 1988-2006 University of Washington
   335.6 +!
   335.7 +! Licensed under the Apache License, Version 2.0 (the "License");
   335.8 +! you may not use this file except in compliance with the License.
   335.9 +! You may obtain a copy of the License at
  335.10 +!
  335.11 +!     http://www.apache.org/licenses/LICENSE-2.0
  335.12 +!
  335.13 +! 
  335.14 +! ========================================================================
  335.15 +
  335.16 +! Program:	Portable C client build for TOPS-20
  335.17 +!
  335.18 +! Author:	Mark Crispin
  335.19 +!		Networks and Distributed Computing
  335.20 +!		Computing & Communications
  335.21 +!		University of Washington
  335.22 +!		Administration Building, AG-44
  335.23 +!		Seattle, WA  98195
  335.24 +!		Internet: MRC@CAC.Washington.EDU
  335.25 +!
  335.26 +! Date:		11 May 1989
  335.27 +! Last Edited:	30 August 2006
  335.28 +
  335.29 +!
  335.30 +! Set environment
  335.31 +@DEFINE SYS: PS:<KCC-6>,SYS:
  335.32 +!
  335.33 +! Build c-client library
  335.34 +!
  335.35 +@COPY OS_T20.* OSDEP.*
  335.36 +@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
  335.37 +!
  335.38 +! Build c-client library file.  Should use MAKLIB, but MAKLIB barfs on MAIL.REL
  335.39 +!
  335.40 +@DELETE CCLINT.REL
  335.41 +@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
  335.42 +!
  335.43 +! Build MTEST library test program
  335.44 +!
  335.45 +@CCX -c -m -w=note MTEST.C
  335.46 +@LINK
  335.47 +*/SET:.HIGH.:200000
  335.48 +*C:LIBCKX.REL
  335.49 +*MTEST.REL
  335.50 +*CCLINT.REL
  335.51 +*MTEST/SAVE
  335.52 +*/GO
  335.53 +!
  335.54 +! Build MAILUTIL
  335.55 +!
  335.56 +@CCX -c -m -w=note MAILUTIL.C
  335.57 +@RENAME MAILUTIL.REL MUTIL.REL
  335.58 +@LINK
  335.59 +*/SET:.HIGH.:200000
  335.60 +*C:LIBCKX.REL
  335.61 +*MUTIL.REL
  335.62 +*CCLINT.REL
  335.63 +*MUTIL/SAVE
  335.64 +*/GO
  335.65 +@RESET
  335.66 +@RENAME MUTIL.EXE MAILUTIL.EXE
   336.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   336.2 +++ b/src/osdep/tops-20/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   336.3 @@ -0,0 +1,43 @@
   336.4 +/* ========================================================================
   336.5 + * Copyright 1988-2006 University of Washington
   336.6 + *
   336.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   336.8 + * you may not use this file except in compliance with the License.
   336.9 + * You may obtain a copy of the License at
  336.10 + *
  336.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  336.12 + *
  336.13 + * 
  336.14 + * ========================================================================
  336.15 + */
  336.16 +
  336.17 +/*
  336.18 + * Program:	Dummy routines
  336.19 + *
  336.20 + * Author:	Mark Crispin
  336.21 + *		Networks and Distributed Computing
  336.22 + *		Computing & Communications
  336.23 + *		University of Washington
  336.24 + *		Administration Building, AG-44
  336.25 + *		Seattle, WA  98195
  336.26 + *		Internet: MRC@CAC.Washington.EDU
  336.27 + *
  336.28 + * Date:	9 May 1991
  336.29 + * Last Edited:	30 August 2006
  336.30 + */
  336.31 +
  336.32 +/* Exported function prototypes */
  336.33 +
  336.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  336.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  336.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  336.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  336.38 +		    unsigned long csiz,unsigned long fsiz);
  336.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  336.40 +			  unsigned long fsiz);
  336.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  336.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  336.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  336.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  336.45 +char *dummy_file (char *dst,char *name);
  336.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   337.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   337.2 +++ b/src/osdep/tops-20/dummyt20.c	Mon Sep 14 15:17:45 2009 +0900
   337.3 @@ -0,0 +1,294 @@
   337.4 +/* ========================================================================
   337.5 + * Copyright 1988-2006 University of Washington
   337.6 + *
   337.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   337.8 + * you may not use this file except in compliance with the License.
   337.9 + * You may obtain a copy of the License at
  337.10 + *
  337.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  337.12 + *
  337.13 + * 
  337.14 + * ========================================================================
  337.15 + */
  337.16 +
  337.17 +/*
  337.18 + * Program:	Dummy routines for TOPS-20
  337.19 + *
  337.20 + * Author:	Mark Crispin
  337.21 + *		Networks and Distributed Computing
  337.22 + *		Computing & Communications
  337.23 + *		University of Washington
  337.24 + *		Administration Building, AG-44
  337.25 + *		Seattle, WA  98195
  337.26 + *		Internet: MRC@CAC.Washington.EDU
  337.27 + *
  337.28 + * Date:	13 June 1995
  337.29 + * Last Edited:	30 August 2006
  337.30 + */
  337.31 +
  337.32 +
  337.33 +#include <ctype.h>
  337.34 +#include <stdio.h>
  337.35 +#include "mail.h"
  337.36 +#include "osdep.h"
  337.37 +#include "dummy.h"
  337.38 +#include "misc.h"
  337.39 +
  337.40 +/* Function prototypes */
  337.41 +
  337.42 +DRIVER *dummy_valid (char *name);
  337.43 +void *dummy_parameters (long function,void *value);
  337.44 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  337.45 +void dummy_close (MAILSTREAM *stream,long options);
  337.46 +long dummy_ping (MAILSTREAM *stream);
  337.47 +void dummy_check (MAILSTREAM *stream);
  337.48 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  337.49 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  337.50 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  337.51 +
  337.52 +/* Dummy routines */
  337.53 +
  337.54 +
  337.55 +/* Driver dispatch used by MAIL */
  337.56 +
  337.57 +DRIVER dummydriver = {
  337.58 +  "dummy",			/* driver name */
  337.59 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  337.60 +  (DRIVER *) NIL,		/* next driver */
  337.61 +  dummy_valid,			/* mailbox is valid for us */
  337.62 +  dummy_parameters,		/* manipulate parameters */
  337.63 +  dummy_scan,			/* scan mailboxes */
  337.64 +  dummy_list,			/* list mailboxes */
  337.65 +  dummy_lsub,			/* list subscribed mailboxes */
  337.66 +  NIL,				/* subscribe to mailbox */
  337.67 +  NIL,				/* unsubscribe from mailbox */
  337.68 +  dummy_create,			/* create mailbox */
  337.69 +  dummy_delete,			/* delete mailbox */
  337.70 +  dummy_rename,			/* rename mailbox */
  337.71 +  mail_status_default,		/* status of mailbox */
  337.72 +  dummy_open,			/* open mailbox */
  337.73 +  dummy_close,			/* close mailbox */
  337.74 +  NIL,				/* fetch message "fast" attributes */
  337.75 +  NIL,				/* fetch message flags */
  337.76 +  NIL,				/* fetch overview */
  337.77 +  NIL,				/* fetch message structure */
  337.78 +  NIL,				/* fetch header */
  337.79 +  NIL,				/* fetch text */
  337.80 +  NIL,				/* fetch message data */
  337.81 +  NIL,				/* unique identifier */
  337.82 +  NIL,				/* message number from UID */
  337.83 +  NIL,				/* modify flags */
  337.84 +  NIL,				/* per-message modify flags */
  337.85 +  NIL,				/* search for message based on criteria */
  337.86 +  NIL,				/* sort messages */
  337.87 +  NIL,				/* thread messages */
  337.88 +  dummy_ping,			/* ping mailbox to see if still alive */
  337.89 +  dummy_check,			/* check for new messages */
  337.90 +  dummy_expunge,		/* expunge deleted messages */
  337.91 +  dummy_copy,			/* copy messages to another mailbox */
  337.92 +  dummy_append,			/* append string message to mailbox */
  337.93 +  NIL				/* garbage collect stream */
  337.94 +};
  337.95 +
  337.96 +
  337.97 +				/* prototype stream */
  337.98 +MAILSTREAM dummyproto = {&dummydriver};
  337.99 +
 337.100 +/* Dummy validate mailbox
 337.101 + * Accepts: mailbox name
 337.102 + * Returns: our driver if name is valid, NIL otherwise
 337.103 + */
 337.104 +
 337.105 +DRIVER *dummy_valid (char *name)
 337.106 +{
 337.107 +				/* must be valid local mailbox */
 337.108 +  return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ?
 337.109 +    &dummydriver : NIL;
 337.110 +}
 337.111 +
 337.112 +
 337.113 +/* Dummy manipulate driver parameters
 337.114 + * Accepts: function code
 337.115 + *	    function-dependent value
 337.116 + * Returns: function-dependent return value
 337.117 + */
 337.118 +
 337.119 +void *dummy_parameters (long function,void *value)
 337.120 +{
 337.121 +  return NIL;
 337.122 +}
 337.123 +
 337.124 +/* Dummy scan mailboxes
 337.125 + * Accepts: mail stream
 337.126 + *	    reference
 337.127 + *	    pattern to search
 337.128 + *	    string to scan
 337.129 + */
 337.130 +
 337.131 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 337.132 +{
 337.133 +				/* return silently */
 337.134 +}
 337.135 +
 337.136 +
 337.137 +/* Dummy list mailboxes
 337.138 + * Accepts: mail stream
 337.139 + *	    reference
 337.140 + *	    pattern to search
 337.141 + */
 337.142 +
 337.143 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 337.144 +{
 337.145 +				/* return silently */
 337.146 +}
 337.147 +
 337.148 +
 337.149 +/* Dummy list subscribed mailboxes
 337.150 + * Accepts: mail stream
 337.151 + *	    reference
 337.152 + *	    pattern to search
 337.153 + */
 337.154 +
 337.155 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 337.156 +{
 337.157 +				/* return silently */
 337.158 +}
 337.159 +
 337.160 +/* Dummy create mailbox
 337.161 + * Accepts: mail stream
 337.162 + *	    mailbox name to create
 337.163 + *	    driver type to use
 337.164 + * Returns: T on success, NIL on failure
 337.165 + */
 337.166 +
 337.167 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 337.168 +{
 337.169 +  return NIL;			/* always fails */
 337.170 +}
 337.171 +
 337.172 +
 337.173 +/* Dummy delete mailbox
 337.174 + * Accepts: mail stream
 337.175 + *	    mailbox name to delete
 337.176 + * Returns: T on success, NIL on failure
 337.177 + */
 337.178 +
 337.179 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 337.180 +{
 337.181 +  return NIL;			/* always fails */
 337.182 +}
 337.183 +
 337.184 +
 337.185 +/* Mail rename mailbox
 337.186 + * Accepts: mail stream
 337.187 + *	    old mailbox name
 337.188 + *	    new mailbox name
 337.189 + * Returns: T on success, NIL on failure
 337.190 + */
 337.191 +
 337.192 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 337.193 +{
 337.194 +  return NIL;			/* always fails */
 337.195 +}
 337.196 +
 337.197 +/* Dummy open
 337.198 + * Accepts: stream to open
 337.199 + * Returns: stream on success, NIL on failure
 337.200 + */
 337.201 +
 337.202 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 337.203 +{
 337.204 +  char tmp[MAILTMPLEN];
 337.205 +				/* OP_PROTOTYPE call or silence */
 337.206 +  if (!stream || stream->silent) return NIL;
 337.207 +  if (compare_cstring (stream->mailbox,"INBOX")) {
 337.208 +    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
 337.209 +    mm_log (tmp,ERROR);
 337.210 +    return NIL;			/* always fails */
 337.211 +  }
 337.212 +  if (!stream->silent) {	/* only if silence not requested */
 337.213 +    mail_exists (stream,0);	/* say there are 0 messages */
 337.214 +    mail_recent (stream,0);
 337.215 +    stream->uid_validity = time (0);
 337.216 +  }
 337.217 +  stream->inbox = T;		/* note that it's an INBOX */
 337.218 +  return stream;		/* return success */
 337.219 +}
 337.220 +
 337.221 +
 337.222 +/* Dummy close
 337.223 + * Accepts: MAIL stream
 337.224 + *	    options
 337.225 + */
 337.226 +
 337.227 +void dummy_close (MAILSTREAM *stream,long options)
 337.228 +{
 337.229 +				/* return silently */
 337.230 +}
 337.231 +
 337.232 +/* Dummy ping mailbox
 337.233 + * Accepts: MAIL stream
 337.234 + * Returns: T if stream alive, else NIL
 337.235 + * No-op for readonly files, since read/writer can expunge it from under us!
 337.236 + */
 337.237 +
 337.238 +long dummy_ping (MAILSTREAM *stream)
 337.239 +{
 337.240 +  return T;
 337.241 +}
 337.242 +
 337.243 +
 337.244 +/* Dummy check mailbox
 337.245 + * Accepts: MAIL stream
 337.246 + * No-op for readonly files, since read/writer can expunge it from under us!
 337.247 + */
 337.248 +
 337.249 +void dummy_check (MAILSTREAM *stream)
 337.250 +{
 337.251 +  dummy_ping (stream);		/* invoke ping */
 337.252 +}
 337.253 +
 337.254 +
 337.255 +/* Dummy expunge mailbox
 337.256 + * Accepts: MAIL stream
 337.257 + *	    sequence to expunge if non-NIL
 337.258 + *	    expunge options
 337.259 + * Returns: T, always
 337.260 + */
 337.261 +
 337.262 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 337.263 +{
 337.264 +  return LONGT;
 337.265 +}
 337.266 +
 337.267 +/* Dummy copy message(s)
 337.268 + * Accepts: MAIL stream
 337.269 + *	    sequence
 337.270 + *	    destination mailbox
 337.271 + *	    options
 337.272 + * Returns: T if copy successful, else NIL
 337.273 + */
 337.274 +
 337.275 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 337.276 +{
 337.277 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 337.278 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 337.279 +  return NIL;
 337.280 +}
 337.281 +
 337.282 +
 337.283 +/* Dummy append message string
 337.284 + * Accepts: mail stream
 337.285 + *	    destination mailbox
 337.286 + *	    append callback function
 337.287 + *	    data for callback
 337.288 + * Returns: T on success, NIL on failure
 337.289 + */
 337.290 +
 337.291 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 337.292 +{
 337.293 +  char tmp[MAILTMPLEN];
 337.294 +  sprintf (tmp,"Can't append to %s",mailbox);
 337.295 +  mm_log (tmp,ERROR);		/* pass up error */
 337.296 +  return NIL;			/* always fails */
 337.297 +}
   338.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   338.2 +++ b/src/osdep/tops-20/env_t20.c	Mon Sep 14 15:17:45 2009 +0900
   338.3 @@ -0,0 +1,226 @@
   338.4 +/* ========================================================================
   338.5 + * Copyright 1988-2006 University of Washington
   338.6 + *
   338.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   338.8 + * you may not use this file except in compliance with the License.
   338.9 + * You may obtain a copy of the License at
  338.10 + *
  338.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  338.12 + *
  338.13 + * 
  338.14 + * ========================================================================
  338.15 + */
  338.16 +
  338.17 +/*
  338.18 + * Program:	Environment routines -- TOPS-20 version
  338.19 + *
  338.20 + * Author:	Mark Crispin
  338.21 + *		Networks and Distributed Computing
  338.22 + *		Computing & Communications
  338.23 + *		University of Washington
  338.24 + *		Administration Building, AG-44
  338.25 + *		Seattle, WA  98195
  338.26 + *		Internet: MRC@CAC.Washington.EDU
  338.27 + *
  338.28 + * Date:	1 August 1988
  338.29 + * Last Edited:	30 August 2006
  338.30 + */
  338.31 +
  338.32 +
  338.33 +/* Dedication:
  338.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  338.35 + * set standards for user and programmer friendliness that have still not been
  338.36 + * equaled by more `modern' operating systems.
  338.37 + * Wasureru mon ka!!!!
  338.38 + */
  338.39 +
  338.40 +/* c-client environment parameters */
  338.41 +
  338.42 +static char *myUserName = NIL;	/* user name */
  338.43 +static char *myHomeDir = NIL;	/* home directory name */
  338.44 +static char *myLocalHost = NIL;	/* local host name */
  338.45 +static char *myNewsrc = NIL;	/* newsrc file name */
  338.46 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  338.47 +
  338.48 +
  338.49 +#include "pmatch.c"		/* include wildcard pattern matcher */
  338.50 +
  338.51 +/* Environment manipulate parameters
  338.52 + * Accepts: function code
  338.53 + *	    function-dependent value
  338.54 + * Returns: function-dependent return value
  338.55 + */
  338.56 +
  338.57 +void *env_parameters (long function,void *value)
  338.58 +{
  338.59 +  void *ret = NIL;
  338.60 +  switch ((int) function) {
  338.61 +  case SET_USERNAME:
  338.62 +    if (myUserName) fs_give ((void **) &myUserName);
  338.63 +    myUserName = cpystr ((char *) value);
  338.64 +  case GET_USERNAME:
  338.65 +    ret = (void *) myUserName;
  338.66 +    break;
  338.67 +  case SET_HOMEDIR:
  338.68 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
  338.69 +    myHomeDir = cpystr ((char *) value);
  338.70 +  case GET_HOMEDIR:
  338.71 +    ret = (void *) myHomeDir;
  338.72 +    break;
  338.73 +  case SET_LOCALHOST:
  338.74 +    if (myLocalHost) fs_give ((void **) &myLocalHost);
  338.75 +    myLocalHost = cpystr ((char *) value);
  338.76 +  case GET_LOCALHOST:
  338.77 +    ret = (void *) myLocalHost;
  338.78 +    break;
  338.79 +  case SET_NEWSRC:
  338.80 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  338.81 +    myNewsrc = cpystr ((char *) value);
  338.82 +  case GET_NEWSRC:
  338.83 +    ret = (void *) myNewsrc;
  338.84 +    break;
  338.85 +  case SET_DISABLE822TZTEXT:
  338.86 +    no822tztext = value ? T : NIL;
  338.87 +  case GET_DISABLE822TZTEXT:
  338.88 +    ret = (void *) (no822tztext ? VOIDT : NIL);
  338.89 +    break;
  338.90 +  }
  338.91 +  return ret;
  338.92 +}
  338.93 +
  338.94 +/* Write current time in RFC 822 format
  338.95 + * Accepts: destination string
  338.96 + */
  338.97 +
  338.98 +void rfc822_date (char *date)
  338.99 +{
 338.100 +  char *s;
 338.101 +  int argblk[4];
 338.102 +  argblk[1] = (int) (date-1);
 338.103 +  argblk[2] = -1;		/* time now */
 338.104 +  argblk[3] = OT_822;		/* want RFC [2]822 format */
 338.105 +  jsys (ODTIM,argblk);
 338.106 +				/* suppress time zone text if desired */
 338.107 +  if (no822tztext && (s = strstr (date," ("))) *s = NIL;
 338.108 +}
 338.109 +
 338.110 +
 338.111 +/* Write current time in internal format
 338.112 + * Accepts: destination string
 338.113 + */
 338.114 +
 338.115 +void internal_date (char *date)
 338.116 +{
 338.117 +  int argblk[5];
 338.118 +  argblk[1] = (int) (date-1);
 338.119 +  argblk[2] = -1;		/* time now */
 338.120 +  argblk[3] = OT_4YR;		/* output in 4-digit year format */
 338.121 +  jsys (ODTIM,argblk);
 338.122 +  argblk[2] = ' ';		/* delimit with space */
 338.123 +  jsys (BOUT,argblk);
 338.124 +  argblk[2] = -1;		/* time now */
 338.125 +  argblk[4] = 0;		/* no flags */
 338.126 +  jsys (ODCNV,argblk);		/* get time zone */
 338.127 +  argblk[2] = ((argblk[4] & 077000000) >> 18) * -100;
 338.128 +				/* add an hour if summer time */
 338.129 +  if (argblk[4] & IC_ADS) argblk[2] += 100;
 338.130 +  argblk[3] = 0340005000012;
 338.131 +  jsys (NOUT,argblk);
 338.132 +}
 338.133 +
 338.134 +/* Return my user name
 338.135 + * Accepts: pointer to optional flags
 338.136 + * Returns: my user name
 338.137 + */
 338.138 +
 338.139 +char *myusername_full (unsigned long *flags)
 338.140 +{
 338.141 +  if (!myUserName) {		/* get user name if don't have it yet */
 338.142 +    char tmp[MAILTMPLEN];
 338.143 +    int argblk[5],i;
 338.144 +    jsys (GJINF,argblk);	/* get job poop */
 338.145 +    if (!(i = argblk[1])) {	/* remember user number */
 338.146 +      if (flags) *flags = MU_NOTLOGGEDIN;
 338.147 +      return "SYSTEM";		/* not logged in */
 338.148 +    }
 338.149 +    argblk[1] = (int) (tmp-1);	/* destination */
 338.150 +    argblk[2] = i;		/* user number */
 338.151 +    jsys (DIRST,argblk);	/* get user name string */
 338.152 +    myUserName = cpystr (tmp);	/* copy user name */
 338.153 +    argblk[1] = 0;		/* no flags */
 338.154 +    argblk[2] = i;		/* user number */
 338.155 +    argblk[3] = 0;		/* no stepping */
 338.156 +    jsys (RCDIR,argblk);	/* get home directory */
 338.157 +    argblk[1] = (int) (tmp-1);	/* destination */
 338.158 +    argblk[2] = argblk[3];	/* home directory number */
 338.159 +    jsys (DIRST,argblk);	/* get home directory string */
 338.160 +    myHomeDir = cpystr (tmp);	/* copy home directory */
 338.161 +    if (!myNewsrc) {		/* set news file name if not defined */
 338.162 +      sprintf (tmp,"%sNEWSRC",myhomedir ());
 338.163 +      myNewsrc = cpystr (tmp);
 338.164 +    }
 338.165 +    if (flags) *flags = MU_LOGGEDIN;
 338.166 +  }
 338.167 +  return myUserName;
 338.168 +}
 338.169 +
 338.170 +/* Return my local host name
 338.171 + * Returns: my local host name
 338.172 + */
 338.173 +
 338.174 +char *mylocalhost ()
 338.175 +{
 338.176 +  if (!myLocalHost) {		/* initialize if first time */
 338.177 +    char tmp[MAILTMPLEN];
 338.178 +    int argblk[5];
 338.179 +    argblk[1] = _GTHNS;		/* convert number to string */
 338.180 +    argblk[2] = (int) (tmp-1);
 338.181 +    argblk[3] = -1;		/* want local host */
 338.182 +    if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL");
 338.183 +    myLocalHost = cpystr (tmp);
 338.184 +  }
 338.185 +  return myLocalHost;
 338.186 +}
 338.187 +
 338.188 +
 338.189 +/* Return my home directory name
 338.190 + * Returns: my home directory name
 338.191 + */
 338.192 +
 338.193 +char *myhomedir ()
 338.194 +{
 338.195 +  if (!myHomeDir) myusername ();/* initialize if first time */
 338.196 +  return myHomeDir ? myHomeDir : "";
 338.197 +}
 338.198 +
 338.199 +
 338.200 +/* Determine default prototype stream to user
 338.201 + * Accepts: type (NIL for create, T for append)
 338.202 + * Returns: default prototype stream
 338.203 + */
 338.204 +
 338.205 +MAILSTREAM *default_proto (long type)
 338.206 +{
 338.207 +  return NIL;			/* no default prototype */
 338.208 +}
 338.209 +
 338.210 +/* Emulator for BSD syslog() routine
 338.211 + * Accepts: priority
 338.212 + *	    message
 338.213 + *	    parameters
 338.214 + */
 338.215 +
 338.216 +void syslog (int priority,const char *message,...)
 338.217 +{
 338.218 +}
 338.219 +
 338.220 +
 338.221 +/* Emulator for BSD openlog() routine
 338.222 + * Accepts: identity
 338.223 + *	    options
 338.224 + *	    facility
 338.225 + */
 338.226 +
 338.227 +void openlog (const char *ident,int logopt,int facility)
 338.228 +{
 338.229 +}
   339.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   339.2 +++ b/src/osdep/tops-20/env_t20.h	Mon Sep 14 15:17:45 2009 +0900
   339.3 @@ -0,0 +1,73 @@
   339.4 +/* ========================================================================
   339.5 + * Copyright 1988-2006 University of Washington
   339.6 + *
   339.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   339.8 + * you may not use this file except in compliance with the License.
   339.9 + * You may obtain a copy of the License at
  339.10 + *
  339.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  339.12 + *
  339.13 + * 
  339.14 + * ========================================================================
  339.15 + */
  339.16 +
  339.17 +/*
  339.18 + * Program:	TOPS-20 environment routines
  339.19 + *
  339.20 + * Author:	Mark Crispin
  339.21 + *		Networks and Distributed Computing
  339.22 + *		Computing & Communications
  339.23 + *		University of Washington
  339.24 + *		Administration Building, AG-44
  339.25 + *		Seattle, WA  98195
  339.26 + *		Internet: MRC@CAC.Washington.EDU
  339.27 + *
  339.28 + * Date:	25 May 1995
  339.29 + * Last Edited:	30 August 2006
  339.30 + */
  339.31 +
  339.32 +
  339.33 +/* Dedication:
  339.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  339.35 + * set standards for user and programmer friendliness that have still not been
  339.36 + * equaled by more `modern' operating systems.
  339.37 + * Wasureru mon ka!!!!
  339.38 + */
  339.39 +
  339.40 +
  339.41 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\SUBSCRIPTIONS.TXT",myhomedir ())
  339.42 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\SUBSCRIPTIONS.TMP",myhomedir ())
  339.43 +
  339.44 +/* Function prototypes */
  339.45 +
  339.46 +#include "env.h"
  339.47 +
  339.48 +char *myusername_full (unsigned long *flags);
  339.49 +#define MU_LOGGEDIN 0
  339.50 +#define MU_NOTLOGGEDIN 1
  339.51 +#define MU_ANONYMOUS 2
  339.52 +#define myusername() \
  339.53 +  myusername_full (NIL)
  339.54 +
  339.55 +
  339.56 +/* syslog() emulation */
  339.57 +
  339.58 +#define LOG_MAIL	(2<<3)	/* mail system */
  339.59 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  339.60 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  339.61 +#define LOG_EMERG	0	/* system is unusable */
  339.62 +#define LOG_ALERT	1	/* action must be taken immediately */
  339.63 +#define LOG_CRIT	2	/* critical conditions */
  339.64 +#define LOG_ERR		3	/* error conditions */
  339.65 +#define LOG_WARNING	4	/* warning conditions */
  339.66 +#define LOG_NOTICE	5	/* normal but signification condition */
  339.67 +#define LOG_INFO	6	/* informational */
  339.68 +#define LOG_DEBUG	7	/* debug-level messages */
  339.69 +#define LOG_PID		0x01	/* log the pid with each message */
  339.70 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  339.71 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  339.72 +#define LOG_NDELAY	0x08	/* don't delay open */
  339.73 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  339.74 +
  339.75 +void openlog (const char *ident,int logopt,int facility);
  339.76 +void syslog (int priority,const char *message,...);
   340.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   340.2 +++ b/src/osdep/tops-20/fs_t20.c	Mon Sep 14 15:17:45 2009 +0900
   340.3 @@ -0,0 +1,62 @@
   340.4 +/* ========================================================================
   340.5 + * Copyright 1988-2006 University of Washington
   340.6 + *
   340.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   340.8 + * you may not use this file except in compliance with the License.
   340.9 + * You may obtain a copy of the License at
  340.10 + *
  340.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  340.12 + *
  340.13 + * 
  340.14 + * ========================================================================
  340.15 + */
  340.16 +
  340.17 +/*
  340.18 + * Program:	Free storage management routines
  340.19 + *
  340.20 + * Author:	Mark Crispin
  340.21 + *		Networks and Distributed Computing
  340.22 + *		Computing & Communications
  340.23 + *		University of Washington
  340.24 + *		Administration Building, AG-44
  340.25 + *		Seattle, WA  98195
  340.26 + *		Internet: MRC@CAC.Washington.EDU
  340.27 + *
  340.28 + * Date:	1 August 1988
  340.29 + * Last Edited:	30 August 2006
  340.30 + */
  340.31 +
  340.32 +/* Get a block of free storage
  340.33 + * Accepts: size of desired block
  340.34 + * Returns: free storage block
  340.35 + */
  340.36 +
  340.37 +void *fs_get (size_t size)
  340.38 +{
  340.39 +  void *block = malloc (size ? size : (size_t) 1);
  340.40 +  if (!block) fatal ("Out of memory");
  340.41 +  return (block);
  340.42 +}
  340.43 +
  340.44 +
  340.45 +/* Resize a block of free storage
  340.46 + * Accepts: ** pointer to current block
  340.47 + *	    new size
  340.48 + */
  340.49 +
  340.50 +void fs_resize (void **block,size_t size)
  340.51 +{
  340.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  340.53 +    fatal ("Can't resize memory");
  340.54 +}
  340.55 +
  340.56 +
  340.57 +/* Return a block of free storage
  340.58 + * Accepts: ** pointer to free storage block
  340.59 + */
  340.60 +
  340.61 +void fs_give (void **block)
  340.62 +{
  340.63 +  free (*block);
  340.64 +  *block = NIL;
  340.65 +}
   341.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   341.2 +++ b/src/osdep/tops-20/ftl_t20.c	Mon Sep 14 15:17:45 2009 +0900
   341.3 @@ -0,0 +1,38 @@
   341.4 +/* ========================================================================
   341.5 + * Copyright 1988-2006 University of Washington
   341.6 + *
   341.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   341.8 + * you may not use this file except in compliance with the License.
   341.9 + * You may obtain a copy of the License at
  341.10 + *
  341.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  341.12 + *
  341.13 + * 
  341.14 + * ========================================================================
  341.15 + */
  341.16 +
  341.17 +/*
  341.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  341.19 + *
  341.20 + * Author:	Mark Crispin
  341.21 + *		Networks and Distributed Computing
  341.22 + *		Computing & Communications
  341.23 + *		University of Washington
  341.24 + *		Administration Building, AG-44
  341.25 + *		Seattle, WA  98195
  341.26 + *		Internet: MRC@CAC.Washington.EDU
  341.27 + *
  341.28 + * Date:	1 August 1988
  341.29 + * Last Edited:	30 August 2006
  341.30 + */
  341.31 +
  341.32 +
  341.33 +/* Report a fatal error
  341.34 + * Accepts: string to output
  341.35 + */
  341.36 +
  341.37 +void fatal (char *string)
  341.38 +{
  341.39 +  mm_fatal (string);		/* pass up the string */
  341.40 +  abort ();			/* die horribly */
  341.41 +}
   342.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   342.2 +++ b/src/osdep/tops-20/linkage.c	Mon Sep 14 15:17:45 2009 +0900
   342.3 @@ -0,0 +1,37 @@
   342.4 +/* ========================================================================
   342.5 + * Copyright 1988-2007 University of Washington
   342.6 + *
   342.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   342.8 + * you may not use this file except in compliance with the License.
   342.9 + * You may obtain a copy of the License at
  342.10 + *
  342.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  342.12 + *
  342.13 + * 
  342.14 + * ========================================================================
  342.15 + */
  342.16 +
  342.17 +/*
  342.18 + * Program:	Default driver linkage
  342.19 + *
  342.20 + * Author:	Mark Crispin
  342.21 + *		Networks and Distributed Computing
  342.22 + *		Computing & Communications
  342.23 + *		University of Washington
  342.24 + *		Administration Building, AG-44
  342.25 + *		Seattle, WA  98195
  342.26 + *		Internet: MRC@CAC.Washington.EDU
  342.27 + *
  342.28 + * Date:	13 June 1995
  342.29 + * Last Edited:	23 May 2007
  342.30 + */
  342.31 +
  342.32 +  mail_link (&imapdriver);		/* link in the imap driver */
  342.33 +  mail_link (&nntpdriver);		/* link in the nntp driver */
  342.34 +  mail_link (&pop3driver);		/* link in the pop3 driver */
  342.35 +  mail_link (&dummydriver);		/* link in the dummy driver */
  342.36 +  auth_link (&auth_ext);		/* link in the ext authenticator */
  342.37 +  auth_link (&auth_md5);		/* link in the md5 authenticator */
  342.38 +  auth_link (&auth_pla);		/* link in the plain authenticator */
  342.39 +  auth_link (&auth_log);		/* link in the log authenticator */
  342.40 +  mail_versioncheck (CCLIENTVERSION);	/* validate version */
   343.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   343.2 +++ b/src/osdep/tops-20/linkage.h	Mon Sep 14 15:17:45 2009 +0900
   343.3 @@ -0,0 +1,36 @@
   343.4 +/* ========================================================================
   343.5 + * Copyright 1988-2006 University of Washington
   343.6 + *
   343.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   343.8 + * you may not use this file except in compliance with the License.
   343.9 + * You may obtain a copy of the License at
  343.10 + *
  343.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  343.12 + *
  343.13 + * 
  343.14 + * ========================================================================
  343.15 + */
  343.16 +
  343.17 +/*
  343.18 + * Program:	Default driver linkage
  343.19 + *
  343.20 + * Author:	Mark Crispin
  343.21 + *		Networks and Distributed Computing
  343.22 + *		Computing & Communications
  343.23 + *		University of Washington
  343.24 + *		Administration Building, AG-44
  343.25 + *		Seattle, WA  98195
  343.26 + *		Internet: MRC@CAC.Washington.EDU
  343.27 + *
  343.28 + * Date:	13 June 1995
  343.29 + * Last Edited:	30 August 2006
  343.30 + */
  343.31 +
  343.32 +extern DRIVER imapdriver;
  343.33 +extern DRIVER nntpdriver;
  343.34 +extern DRIVER pop3driver;
  343.35 +extern DRIVER dummydriver;
  343.36 +extern AUTHENTICATOR auth_ext;
  343.37 +extern AUTHENTICATOR auth_log;
  343.38 +extern AUTHENTICATOR auth_md5;
  343.39 +extern AUTHENTICATOR auth_pla;
   344.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   344.2 +++ b/src/osdep/tops-20/log_t20.c	Mon Sep 14 15:17:45 2009 +0900
   344.3 @@ -0,0 +1,80 @@
   344.4 +/* ========================================================================
   344.5 + * Copyright 1988-2006 University of Washington
   344.6 + *
   344.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   344.8 + * you may not use this file except in compliance with the License.
   344.9 + * You may obtain a copy of the License at
  344.10 + *
  344.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  344.12 + *
  344.13 + * 
  344.14 + * ========================================================================
  344.15 + */
  344.16 +
  344.17 +/*
  344.18 + * Program:	TOPS-20 server login
  344.19 + *
  344.20 + * Author:	Mark Crispin
  344.21 + *		Networks and Distributed Computing
  344.22 + *		Computing & Communications
  344.23 + *		University of Washington
  344.24 + *		Administration Building, AG-44
  344.25 + *		Seattle, WA  98195
  344.26 + *		Internet: MRC@CAC.Washington.EDU
  344.27 + *
  344.28 + * Date:	1 August 1988
  344.29 + * Last Edited:	30 August 2006
  344.30 + */
  344.31 +
  344.32 +
  344.33 +/* Dedication:
  344.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  344.35 + * set standards for user and programmer friendliness that have still not been
  344.36 + * equaled by more `modern' operating systems.
  344.37 + * Wasureru mon ka!!!!
  344.38 + */
  344.39 +
  344.40 +/* Server log in
  344.41 + * Accepts: user name string
  344.42 + *	    password string
  344.43 + *	    authenticating user name string
  344.44 + *	    argument count
  344.45 + *	    argument vector
  344.46 + * Returns: T if password validated, NIL otherwise
  344.47 + */
  344.48 +
  344.49 +long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
  344.50 +{
  344.51 +  int uid;
  344.52 +  int argblk[5];
  344.53 +  if (authuser && *authuser) {	/* not available */
  344.54 +    syslog (LOG_NOTICE|LOG_AUTH,
  344.55 +	    "Login %s failed: invalid authentication ID %s host=%.80s",
  344.56 +	    user,authuser,tcp_clienthost ());
  344.57 +    sleep (3);
  344.58 +    return NIL;
  344.59 +  }
  344.60 +  argblk[1] = RC_EMO;		/* require exact match */
  344.61 +  argblk[2] = (int) (user-1);	/* user name */
  344.62 +  argblk[3] = 0;		/* no stepping */
  344.63 +  if (!jsys (RCUSR,argblk)) return NIL;
  344.64 +  uid = argblk[1] = argblk[3];	/* user number */
  344.65 +  argblk[2] = (int) (pass-1);	/* password */
  344.66 +  argblk[3] = 0;		/* no special account */
  344.67 +  if (!jsys (LOGIN,argblk)) return NIL;
  344.68 +  return T;
  344.69 +}
  344.70 +
  344.71 +
  344.72 +/* Authenticated server log in
  344.73 + * Accepts: user name string
  344.74 + *	    authenticating user name string
  344.75 + *	    argument count
  344.76 + *	    argument vector
  344.77 + * Returns: T if password validated, NIL otherwise
  344.78 + */
  344.79 +
  344.80 +long authserver_login (char *user,char *authuser,int argc,char *argv[])
  344.81 +{
  344.82 +  return NIL;			/* how to implement this on TOPS-20??? */
  344.83 +}
   345.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   345.2 +++ b/src/osdep/tops-20/nl_t20.c	Mon Sep 14 15:17:45 2009 +0900
   345.3 @@ -0,0 +1,61 @@
   345.4 +/* ========================================================================
   345.5 + * Copyright 1988-2006 University of Washington
   345.6 + *
   345.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   345.8 + * you may not use this file except in compliance with the License.
   345.9 + * You may obtain a copy of the License at
  345.10 + *
  345.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  345.12 + *
  345.13 + * 
  345.14 + * ========================================================================
  345.15 + */
  345.16 +
  345.17 +/*
  345.18 + * Program:	Windows/TOPS-20 newline routines
  345.19 + *
  345.20 + * Author:	Mark Crispin
  345.21 + *		Networks and Distributed Computing
  345.22 + *		Computing & Communications
  345.23 + *		University of Washington
  345.24 + *		Administration Building, AG-44
  345.25 + *		Seattle, WA  98195
  345.26 + *		Internet: MRC@CAC.Washington.EDU
  345.27 + *
  345.28 + * Date:	1 August 1988
  345.29 + * Last Edited:	30 August 2006
  345.30 + */
  345.31 +
  345.32 +/* Copy string with CRLF newlines
  345.33 + * Accepts: destination string
  345.34 + *	    pointer to size of destination string buffer
  345.35 + *	    source string
  345.36 + *	    length of source string
  345.37 + * Returns: length of copied string
  345.38 + */
  345.39 +
  345.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  345.41 +			  unsigned char *src,unsigned long srcl)
  345.42 +{
  345.43 +				/* flush destination buffer if too small */
  345.44 +  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
  345.45 +  if (!*dst) {			/* make a new buffer if needed */
  345.46 +    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
  345.47 +    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
  345.48 +  }
  345.49 +				/* copy strings */
  345.50 +  if (srcl) memcpy (*dst,src,(size_t) srcl);
  345.51 +  *(*dst + srcl) = '\0';	/* tie off destination */
  345.52 +  return srcl;			/* return length */
  345.53 +}
  345.54 +
  345.55 +
  345.56 +/* Length of string after strcrlfcpy applied
  345.57 + * Accepts: source string
  345.58 + * Returns: length of string
  345.59 + */
  345.60 +
  345.61 +unsigned long strcrlflen (STRING *s)
  345.62 +{
  345.63 +  return SIZE (s);		/* no-brainer on DOS! */
  345.64 +}
   346.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   346.2 +++ b/src/osdep/tops-20/os_t20.c	Mon Sep 14 15:17:45 2009 +0900
   346.3 @@ -0,0 +1,106 @@
   346.4 +/* ========================================================================
   346.5 + * Copyright 1988-2006 University of Washington
   346.6 + *
   346.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   346.8 + * you may not use this file except in compliance with the License.
   346.9 + * You may obtain a copy of the License at
  346.10 + *
  346.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  346.12 + *
  346.13 + * 
  346.14 + * ========================================================================
  346.15 + */
  346.16 +
  346.17 +/*
  346.18 + * Program:	Operating-system dependent routines -- TOPS-20 version
  346.19 + *
  346.20 + * Author:	Mark Crispin
  346.21 + *		Networks and Distributed Computing
  346.22 + *		Computing & Communications
  346.23 + *		University of Washington
  346.24 + *		Administration Building, AG-44
  346.25 + *		Seattle, WA  98195
  346.26 + *		Internet: MRC@CAC.Washington.EDU
  346.27 + *
  346.28 + * Date:	1 August 1988
  346.29 + * Last Edited:	30 August 2006
  346.30 + */
  346.31 +
  346.32 +
  346.33 +/* Dedication:
  346.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  346.35 + * set standards for user and programmer friendliness that have still not been
  346.36 + * equaled by more `modern' operating systems.
  346.37 + * Wasureru mon ka!!!!
  346.38 + */
  346.39 +
  346.40 +#include "mail.h"
  346.41 +#include <jsys.h>		/* must be before tcp_t20.h */
  346.42 +#include "tcp_t20.h"		/* must be before osdep include tcp.h */
  346.43 +#include <time.h>
  346.44 +#include "osdep.h"
  346.45 +#include <sys/time.h>
  346.46 +#include "misc.h"
  346.47 +#include <stdio.h>
  346.48 +#include <fcntl.h>
  346.49 +#include <sys/stat.h>
  346.50 +#include <ctype.h>
  346.51 +
  346.52 +#include "fs_t20.c"
  346.53 +#include "ftl_t20.c"
  346.54 +#include "nl_t20.c"
  346.55 +#include "env_t20.c"
  346.56 +#include "tcp_t20.c"
  346.57 +#include "log_t20.c"
  346.58 +
  346.59 +#define MD5ENABLE "PS:<SYSTEM>CRAM-MD5.PWD"
  346.60 +#include "auth_md5.c"
  346.61 +#include "auth_ext.c"
  346.62 +#include "auth_pla.c"
  346.63 +#include "auth_log.c"
  346.64 +
  346.65 +/* Emulator for UNIX gethostid() call
  346.66 + * Returns: host id
  346.67 + */
  346.68 +
  346.69 +long gethostid ()
  346.70 +{
  346.71 +  int argblk[5];
  346.72 +#ifndef _APRID
  346.73 +#define _APRID 28
  346.74 +#endif
  346.75 +  argblk[1] = _APRID;
  346.76 +  jsys (GETAB,argblk);
  346.77 +  return (long) argblk[1];
  346.78 +}
  346.79 +
  346.80 +
  346.81 +/* Emulator for UNIX getpass() call
  346.82 + * Accepts: prompt
  346.83 + * Returns: password
  346.84 + */
  346.85 +
  346.86 +#define PWDLEN 128		/* used by Linux */
  346.87 +
  346.88 +char *getpass (const char *prompt)
  346.89 +{
  346.90 +  char *s;
  346.91 +  static char pwd[PWDLEN];
  346.92 +  int argblk[5],mode;
  346.93 +  argblk[1] = (int) (prompt-1);	/* prompt user */
  346.94 +  jsys (PSOUT,argblk);
  346.95 +  argblk[1] = _PRIIN;		/* get current TTY mode */
  346.96 +  jsys (RFMOD,argblk);
  346.97 +  mode = argblk[2];		/* save for later */
  346.98 +  argblk[2] &= ~06000;
  346.99 +  jsys (SFMOD,argblk);
 346.100 +  jsys (STPAR,argblk);
 346.101 +  fgets (pwd,PWDLEN-1,stdin);
 346.102 +  pwd[PWDLEN-1] = '\0';
 346.103 +  if (s = strchr (pwd,'\n')) *s = '\0';
 346.104 +  putchar ('\n');
 346.105 +  argblk[2] = mode;
 346.106 +  jsys (SFMOD,argblk);
 346.107 +  jsys (STPAR,argblk);
 346.108 +  return pwd;
 346.109 +}
   347.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   347.2 +++ b/src/osdep/tops-20/os_t20.h	Mon Sep 14 15:17:45 2009 +0900
   347.3 @@ -0,0 +1,52 @@
   347.4 +/* ========================================================================
   347.5 + * Copyright 1988-2007 University of Washington
   347.6 + *
   347.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   347.8 + * you may not use this file except in compliance with the License.
   347.9 + * You may obtain a copy of the License at
  347.10 + *
  347.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  347.12 + *
  347.13 + * 
  347.14 + * ========================================================================
  347.15 + */
  347.16 +
  347.17 +/*
  347.18 + * Program:	Operating-system dependent routines -- TOPS-20 version
  347.19 + *
  347.20 + * Author:	Mark Crispin
  347.21 + *		Networks and Distributed Computing
  347.22 + *		Computing & Communications
  347.23 + *		University of Washington
  347.24 + *		Administration Building, AG-44
  347.25 + *		Seattle, WA  98195
  347.26 + *		Internet: MRC@CAC.Washington.EDU
  347.27 + *
  347.28 + * Date:	1 August 1988
  347.29 + * Last Edited:	30 January 2007
  347.30 + */
  347.31 +
  347.32 +
  347.33 +/* Dedication:
  347.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  347.35 + * set standards for user and programmer friendliness that have still not been
  347.36 + * equaled by more `modern' operating systems.
  347.37 + * Wasureru mon ka!!!!
  347.38 + */
  347.39 +
  347.40 +#include <stdlib.h>
  347.41 +#include <string.h>
  347.42 +#include <sys/types.h>
  347.43 +#include <sys/file.h>
  347.44 +#include <unistd.h>
  347.45 +
  347.46 +#include "env_t20.h"
  347.47 +#include "fs.h"
  347.48 +#include "ftl.h"
  347.49 +#include "nl.h"
  347.50 +#include "tcp.h"
  347.51 +
  347.52 +long gethostid (void);
  347.53 +char *getpass (const char *prompt);
  347.54 +
  347.55 +#define strtok_r(a,b,c) strtok(a,b)
   348.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   348.2 +++ b/src/osdep/tops-20/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   348.3 @@ -0,0 +1,89 @@
   348.4 +/* ========================================================================
   348.5 + * Copyright 1988-2006 University of Washington
   348.6 + *
   348.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   348.8 + * you may not use this file except in compliance with the License.
   348.9 + * You may obtain a copy of the License at
  348.10 + *
  348.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  348.12 + *
  348.13 + * 
  348.14 + * ========================================================================
  348.15 + */
  348.16 +
  348.17 +/*
  348.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  348.19 + *
  348.20 + * Author:	Mark Crispin
  348.21 + *		Networks and Distributed Computing
  348.22 + *		Computing & Communications
  348.23 + *		University of Washington
  348.24 + *		Administration Building, AG-44
  348.25 + *		Seattle, WA  98195
  348.26 + *		Internet: MRC@CAC.Washington.EDU
  348.27 + *
  348.28 + * Date:	15 June 2000
  348.29 + * Last Edited:	30 August 2006
  348.30 + */
  348.31 +
  348.32 +/* Wildcard pattern match
  348.33 + * Accepts: base string
  348.34 + *	    pattern string
  348.35 + *	    delimiter character
  348.36 + * Returns: T if pattern matches base, else NIL
  348.37 + */
  348.38 +
  348.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  348.40 +{
  348.41 +  switch (*pat) {
  348.42 +  case '%':			/* non-recursive */
  348.43 +				/* % at end, OK if no inferiors */
  348.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  348.45 +                                /* scan remainder of string until delimiter */
  348.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  348.47 +    while ((*s != delim) && *s++);
  348.48 +    break;
  348.49 +  case '*':			/* match 0 or more characters */
  348.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  348.51 +				/* scan remainder of string */
  348.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  348.53 +    while (*s++);
  348.54 +    break;
  348.55 +  case '\0':			/* end of pattern */
  348.56 +    return *s ? NIL : T;	/* success if also end of base */
  348.57 +  default:			/* match this character */
  348.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  348.59 +  }
  348.60 +  return NIL;
  348.61 +}
  348.62 +
  348.63 +/* Directory pattern match
  348.64 + * Accepts: base string
  348.65 + *	    pattern string
  348.66 + *	    delimiter character
  348.67 + * Returns: T if base is a matching directory of pattern, else NIL
  348.68 + */
  348.69 +
  348.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  348.71 +{
  348.72 +  switch (*pat) {
  348.73 +  case '%':			/* non-recursive */
  348.74 +    if (!*s) return T;		/* end of base means have a subset match */
  348.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  348.76 +				/* scan remainder of string until delimiter */
  348.77 +    do if (dmatch (s,pat,delim)) return T;
  348.78 +    while ((*s != delim) && *s++);
  348.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  348.80 +    return dmatch (s,pat,delim);/* do new scan */
  348.81 +  case '*':			/* match 0 or more characters */
  348.82 +    return T;			/* unconditional match */
  348.83 +  case '\0':			/* end of pattern */
  348.84 +    break;
  348.85 +  default:			/* match this character */
  348.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  348.87 +				/* end of base, return if at delimiter */
  348.88 +    else if (*pat == delim) return T;
  348.89 +    break;
  348.90 +  }
  348.91 +  return NIL;
  348.92 +}
   349.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   349.2 +++ b/src/osdep/tops-20/shortsym.h	Mon Sep 14 15:17:45 2009 +0900
   349.3 @@ -0,0 +1,608 @@
   349.4 +/* ========================================================================
   349.5 + * Copyright 1988-2008 University of Washington
   349.6 + *
   349.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   349.8 + * you may not use this file except in compliance with the License.
   349.9 + * You may obtain a copy of the License at
  349.10 + *
  349.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  349.12 + *
  349.13 + * 
  349.14 + * ========================================================================
  349.15 + */
  349.16 +
  349.17 +/*
  349.18 + * Program:	Definitions for compilers with 6-letter symbol limits
  349.19 + *
  349.20 + * Author:	Mark Crispin
  349.21 + *		Networks and Distributed Computing
  349.22 + *		Computing & Communications
  349.23 + *		University of Washington
  349.24 + *		Administration Building, AG-44
  349.25 + *		Seattle, WA  98195
  349.26 + *		Internet: MRC@CAC.Washington.EDU
  349.27 + *
  349.28 + * Date:	24 May 1995
  349.29 + * Last Edited:	1 January 2008
  349.30 + */
  349.31 +
  349.32 +#define auth_link a_link
  349.33 +#define auth_log a_log
  349.34 +#define auth_login_client al_cli
  349.35 +#define auth_login_server al_ser
  349.36 +#define auth_ext a_ext
  349.37 +#define auth_external_client ae_cli
  349.38 +#define auth_external_server ae_ser
  349.39 +#define auth_md5 a_md5
  349.40 +#define auth_md5_valid a5_val
  349.41 +#define auth_md5_client a5_cli
  349.42 +#define auth_md5_server a5_ser
  349.43 +#define auth_pla a_pla
  349.44 +#define auth_plain_client ap_cli
  349.45 +#define auth_plain_server ap_ser
  349.46 +#define authenticate a_auth
  349.47 +#define authserver_login a_serv
  349.48 +#define body_encodings bencds
  349.49 +#define body_types btypes
  349.50 +#define compare_csizedtext cm_szt
  349.51 +#define compare_cstring cm_str
  349.52 +#define compare_uchar cm_uch
  349.53 +#define compare_ulong cm_uln
  349.54 +#define default_proto d_prot
  349.55 +#define dummy_append d_appn
  349.56 +#define dummy_canonicalize d_cano
  349.57 +#define dummy_check d_chck
  349.58 +#define dummy_close d_clos
  349.59 +#define dummy_copy d_copy
  349.60 +#define dummy_create d_crea
  349.61 +#define dummy_create_path d_crep
  349.62 +#define dummy_delete d_del
  349.63 +#define dummy_expunge d_exp
  349.64 +#define dummy_file d_fil
  349.65 +#define dummy_list d_list
  349.66 +#define dummy_list_work d_lstw
  349.67 +#define dummy_listed d_lstd
  349.68 +#define dummy_lsub d_lsub
  349.69 +#define dummy_open d_open
  349.70 +#define dummy_parameters d_parm
  349.71 +#define dummy_ping d_ping
  349.72 +#define dummy_rename d_ren
  349.73 +#define dummy_scan d_scan
  349.74 +#define dummy_search d_srch
  349.75 +#define dummy_subscribe d_subs
  349.76 +#define dummy_valid d_val
  349.77 +#define env_parameters e_parm
  349.78 +#define fatal fatal
  349.79 +#define file_string fl_str
  349.80 +#define file_string_init fl_ini
  349.81 +#define file_string_next fl_nxt
  349.82 +#define file_string_setpos fl_sps
  349.83 +#define fs_get f_get
  349.84 +#define fs_give f_give
  349.85 +#define fs_resize f_rsiz
  349.86 +#define hash_create h_crea
  349.87 +#define hash_destory h_dest
  349.88 +#define hash_index h_indx
  349.89 +#define hash_lookup h_lkup
  349.90 +#define hash_add h_add
  349.91 +#define hash_lookup_and_add h_lad
  349.92 +#define imap_OK i_OK
  349.93 +#define imap_acl_work i_aclw
  349.94 +#define imap_append i_appn
  349.95 +#define imap_append_single i_apps
  349.96 +#define imap_anon i_anon
  349.97 +#define imap_auth i_auth
  349.98 +#define imap_cache i_cach
  349.99 +#define imap_cap i_cap
 349.100 +#define imap_capability i_capa
 349.101 +#define imap_challenge i_chln
 349.102 +#define imap_check i_chck
 349.103 +#define imap_close i_clos
 349.104 +#define imap_copy i_copy
 349.105 +#define imap_create i_crea
 349.106 +#define imap_delete i_del
 349.107 +#define imap_deleteacl i_dacl
 349.108 +#define imap_expunge i_expn
 349.109 +#define imap_fake i_fake
 349.110 +#define imap_fast i_fast
 349.111 +#define imap_fetch i_fetc
 349.112 +#define imap_flag i_flag
 349.113 +#define imap_flags i_flgs
 349.114 +#define imap_gc i_gc
 349.115 +#define imap_gc_body ig_bdy
 349.116 +#define imap_getacl i_gacl
 349.117 +#define imap_getquota i_gqot
 349.118 +#define imap_getquotaroot i_gqtr
 349.119 +#define imap_host i_host
 349.120 +#define imap_list i_list
 349.121 +#define imap_listrights i_lrgh
 349.122 +#define imap_list_work il_wrk
 349.123 +#define imap_login i_logn
 349.124 +#define imap_lsub i_lsub
 349.125 +#define imap_manage i_man
 349.126 +#define imap_msgdata i_msgd
 349.127 +#define imap_msgno i_msgn
 349.128 +#define imap_myrights i_mrgh
 349.129 +#define imap_open i_open
 349.130 +#define imap_parameters i_parm
 349.131 +#define imap_parse_address ip_adr
 349.132 +#define imap_parse_adrlist ip_adl
 349.133 +#define imap_parse_astring ip_ast
 349.134 +#define imap_parse_body ip_bdy
 349.135 +#define imap_parse_body_parameter ipb_pa
 349.136 +#define imap_parse_body_structure ipb_st
 349.137 +#define imap_parse_capabilities ip_cap
 349.138 +#define imap_parse_disposition ip_dsp
 349.139 +#define imap_parse_envelope ip_env
 349.140 +#define imap_parse_extension ip_ext
 349.141 +#define imap_parse_flags ip_flg
 349.142 +#define imap_parse_header ip_hdr
 349.143 +#define imap_parse_language ip_lng
 349.144 +#define imap_parse_namespace ip_nam
 349.145 +#define imap_parse_reply ip_rep
 349.146 +#define imap_parse_response ip_rsp
 349.147 +#define imap_parse_string ip_str
 349.148 +#define imap_parse_stringlist ip_stl
 349.149 +#define imap_parse_thread ip_thr
 349.150 +#define imap_parse_unsolicited ip_uns
 349.151 +#define imap_parse_user_flag ipu_fl
 349.152 +#define imap_ping i_ping
 349.153 +#define imap_reform_sequence i_rfrs
 349.154 +#define imap_rename i_ren
 349.155 +#define imap_reply i_rep
 349.156 +#define imap_response i_rspn
 349.157 +#define imap_scan i_scan
 349.158 +#define imap_search i_srch
 349.159 +#define imap_send i_send
 349.160 +#define imap_send_astring is_ast
 349.161 +#define imap_send_literal is_lit
 349.162 +#define imap_send_sdate iss_da
 349.163 +#define imap_send_slist iss_sl
 349.164 +#define imap_send_spgm iss_pg
 349.165 +#define imap_send_spgm_trim iss_pt
 349.166 +#define imap_send_sset iss_st
 349.167 +#define imap_send_sset_work iss_sw
 349.168 +#define imap_setacl i_sacl
 349.169 +#define imap_setquota i_sqot
 349.170 +#define imap_sort i_sort
 349.171 +#define imap_sout i_sout
 349.172 +#define imap_soutr i_sotr
 349.173 +#define imap_status i_stat
 349.174 +#define imap_structure i_stru
 349.175 +#define imap_subscribe i_sub
 349.176 +#define imap_thread i_thrd
 349.177 +#define imap_thread_work i_thrw
 349.178 +#define imap_uid i_uid
 349.179 +#define imap_unsubscribe i_uns
 349.180 +#define imap_valid i_val
 349.181 +#define internal_date in_dat
 349.182 +#define mail_append_full m_appn
 349.183 +#define mail_append_multiple m_appm
 349.184 +#define mail_append_set m_apps
 349.185 +#define mail_auth m_auth
 349.186 +#define mail_body m_body
 349.187 +#define mail_cdate m_cdat
 349.188 +#define mail_check m_chck
 349.189 +#define mail_close_full m_clos
 349.190 +#define mail_copy_full m_copy
 349.191 +#define mail_create m_crea
 349.192 +#define mail_criteria m_crit
 349.193 +#define mail_criteria_date mc_dat
 349.194 +#define mail_criteria_string mc_str
 349.195 +#define mail_date m_date
 349.196 +#define mail_debug m_dbug
 349.197 +#define mail_delete m_del
 349.198 +#define mail_dlog m_dlog
 349.199 +#define mail_elt m_elt
 349.200 +#define mail_exists m_exst
 349.201 +#define mail_expunge_full m_expn
 349.202 +#define mail_expunged m_expd
 349.203 +#define mail_fetch_body fs_bdy
 349.204 +#define mail_fetch_fast mf_fst
 349.205 +#define mail_fetch_flags mf_flg
 349.206 +#define mail_fetch_header mf_hdr
 349.207 +#define mail_fetch_message mf_msg
 349.208 +#define mail_fetch_mime mf_mim
 349.209 +#define mail_fetch_overview mf_ovr
 349.210 +#define mail_fetch_overview_sequence mf_ovs
 349.211 +#define mail_fetch_overview_default mf_ovd
 349.212 +#define mail_fetch_structure mf_str
 349.213 +#define mail_fetch_text mf_txt
 349.214 +#define mail_fetch_text_return mf_txr
 349.215 +#define mail_fetch_string_return mf_tsr
 349.216 +#define mail_fetchfrom mf_frm
 349.217 +#define mail_fetchsubject mf_sub
 349.218 +#define mail_filter m_filt
 349.219 +#define mail_flag m_flag
 349.220 +#define mail_free_acl mr_acl
 349.221 +#define mail_free_address mr_add
 349.222 +#define mail_free_body mr_bdy
 349.223 +#define mail_free_body_data mrb_da
 349.224 +#define mail_free_body_parameter mrb_pr
 349.225 +#define mail_free_body_part mrb_pt
 349.226 +#define mail_free_cache mr_cac
 349.227 +#define mail_free_elt mr_elt
 349.228 +#define mail_free_envelope mr_env
 349.229 +#define mail_free_handle mr_han
 349.230 +#define mail_free_namespace mr_nsp
 349.231 +#define mail_free_quotalist mr_qtl
 349.232 +#define mail_free_searchheader mrs_hd
 349.233 +#define mail_free_searchor mrs_or
 349.234 +#define mail_free_searchpgm mrs_pg
 349.235 +#define mail_free_searchpgmlist mrs_pl
 349.236 +#define mail_free_searchset mrs_st
 349.237 +#define mail_free_sortpgm mr_spg
 349.238 +#define mail_free_stringlist mr_sls
 349.239 +#define mail_free_threadnode mr_thn
 349.240 +#define mail_gc m_gc
 349.241 +#define mail_gc_msg m_gcm
 349.242 +#define mail_gc_body m_gcb
 349.243 +#define mail_initbody m_ibdy
 349.244 +#define mail_link m_link
 349.245 +#define mail_list m_list
 349.246 +#define mail_lock m_lock
 349.247 +#define mail_longdate ml_lda
 349.248 +#define mail_lookup_auth m_laut
 349.249 +#define mail_lookup_auth_name m_latn
 349.250 +#define mail_lsub m_lsub
 349.251 +#define mail_makehandle m_mhdl
 349.252 +#define mail_match_lines m_mlns
 349.253 +#define mail_msgno m_msgn
 349.254 +#define mail_newacl mn_acl
 349.255 +#define mail_newaddr mn_add
 349.256 +#define mail_newbody mn_bdy
 349.257 +#define mail_newbody_parameter mnb_pr
 349.258 +#define mail_newbody_part mnb_pt
 349.259 +#define mail_newbody_message_part mnb_mp
 349.260 +#define mail_new_cache_elt mn_elt
 349.261 +#define mail_newenvelope mn_env
 349.262 +#define mail_newmsg mn_msg
 349.263 +#define mail_newquotalist mn_qtl
 349.264 +#define mail_newsearchheader mns_hd
 349.265 +#define mail_newsearchor mns_or
 349.266 +#define mail_newsearchpgm mns_pg
 349.267 +#define mail_newsearchpgmlist mns_pl
 349.268 +#define mail_newsearchset mns_st
 349.269 +#define mail_newsortpgm mn_spg
 349.270 +#define mail_newstringlist mn_sls
 349.271 +#define mail_newthreadnode mn_thr
 349.272 +#define mail_nodebug m_ndbg
 349.273 +#define mail_open m_open
 349.274 +#define mail_parameters m_parm
 349.275 +#define mail_parse_date mp_dat
 349.276 +#define mail_parse_flags mp_flg
 349.277 +#define mail_parse_set mp_set
 349.278 +#define mail_partial_body mpt_bd
 349.279 +#define mail_partial_text mpt_tx
 349.280 +#define mail_ping m_ping
 349.281 +#define mail_read m_read
 349.282 +#define mail_recent m_rcent
 349.283 +#define mail_rename m_ren
 349.284 +#define mail_scan m_scan
 349.285 +#define mail_search_addr ms_adr
 349.286 +#define mail_search_body ms_bdy
 349.287 +#define mail_search_default ms_def
 349.288 +#define mail_search_full m_srch
 349.289 +#define mail_search_gets ms_gts
 349.290 +#define mail_search_header ms_hdr
 349.291 +#define mail_search_header_text ms_hdt
 349.292 +#define mail_search_keyword ms_key
 349.293 +#define mail_search_msg ms_msg
 349.294 +#define mail_search_string ms_str
 349.295 +#define mail_search_string_work ms_stw
 349.296 +#define mail_search_text ms_txt
 349.297 +#define mail_sequence m_seq
 349.298 +#define mail_shortdate m_shtd
 349.299 +#define mail_skip_fwd msk_fw
 349.300 +#define mail_skip_re msk_re
 349.301 +#define mail_sort ml_srt
 349.302 +#define mail_sort_cache ms_csh
 349.303 +#define mail_sort_compare ms_cmp
 349.304 +#define mail_sort_loadcache ms_lcs
 349.305 +#define mail_sort_msgs ms_mgs
 349.306 +#define mail_status m_stat
 349.307 +#define mail_status_default m_stad
 349.308 +#define mail_stream m_strm
 349.309 +#define mail_string m_strg
 349.310 +#define mail_string_init mt_ini
 349.311 +#define mail_string_next mt_nxt
 349.312 +#define mail_string_setpos mt_sps
 349.313 +#define mail_strip_subject mst_sb
 349.314 +#define mail_strip_subject_wsp mst_ws
 349.315 +#define mail_strip_subject_blob mst_bl
 349.316 +#define mail_subscribe m_sub
 349.317 +#define mail_thread m_thr
 349.318 +#define mail_threadlist mt_lst
 349.319 +#define mail_thread_c2node mt_c2n
 349.320 +#define mail_thread_check_child mt_ckc
 349.321 +#define mail_thread_compare_date mtc_da
 349.322 +#define mail_thread_loadcache mt_ldc
 349.323 +#define mail_thread_msgs mt_mgs
 349.324 +#define mail_thread_orderedsubject mt_osb
 349.325 +#define mail_thread_parse_msgid mtp_mi
 349.326 +#define mail_thread_parse_references mtp_rf
 349.327 +#define mail_thread_prune_dummy mt_prd
 349.328 +#define mail_thread_references mt_ref
 349.329 +#define mail_thread_sort mt_srt
 349.330 +#define mail_uid m_uid
 349.331 +#define mail_uid_sequence mu_seq
 349.332 +#define mail_unlock m_unl
 349.333 +#define mail_unsubscribe m_uns
 349.334 +#define mail_usable_network_stream m_usns
 349.335 +#define mail_utf7_valid m_ut7v
 349.336 +#define mail_valid m_val
 349.337 +#define mail_valid_net mv_net
 349.338 +#define mail_valid_net_parse mvn_pr
 349.339 +#define mail_valid_net_parse_work mvn_pw
 349.340 +#define mail_versioncheck m_vers
 349.341 +#define mailboxfile mbxfil
 349.342 +#define md5_init m5_ini
 349.343 +#define md5_update m5_upd
 349.344 +#define md5_final m5_fin
 349.345 +#define mime2_decode m2_dec
 349.346 +#define mime2_text m2_txt
 349.347 +#define mime2_token m2_tok
 349.348 +#define mm_cache mm_cac
 349.349 +#define mm_critical mm_crt
 349.350 +#define mm_diskerror mm_dse
 349.351 +#define mm_dlog mm_dlg
 349.352 +#define mm_exists mm_exs
 349.353 +#define mm_expunged mm_exp
 349.354 +#define mm_fatal mm_ftl
 349.355 +#define mm_flags mm_flg
 349.356 +#define mm_list mm_lst
 349.357 +#define mm_log mm_log
 349.358 +#define mm_login mm_lgi
 349.359 +#define mm_lsub mm_lsb
 349.360 +#define mm_mailbox mm_mbx
 349.361 +#define mm_nocritical mm_ncr
 349.362 +#define mm_notify mm_not
 349.363 +#define mm_searched mm_src
 349.364 +#define myhomedir myhome
 349.365 +#define mylocalhost myhost
 349.366 +#define myusername_full myuser
 349.367 +#define net_aopen nt_aop
 349.368 +#define net_close nt_cls
 349.369 +#define net_getbuffer nt_gtb
 349.370 +#define net_getdata nt_gtd
 349.371 +#define net_getline nt_gtl
 349.372 +#define net_host nt_hst
 349.373 +#define net_localhost nt_lhs
 349.374 +#define net_open nt_opn
 349.375 +#define net_port nt_prt
 349.376 +#define net_sout nt_sot
 349.377 +#define net_soutr nt_str
 349.378 +#define netmsg_read nm_rea
 349.379 +#define netmsg_slurp nm_slr
 349.380 +#define netmsg_slurp_text nm_slt
 349.381 +#define newsrc_check_uid nsc_ui
 349.382 +#define newsrc_create ns_crea
 349.383 +#define newsrc_error ns_err
 349.384 +#define newsrc_lsub ns_lsub
 349.385 +#define newsrc_newmessages ns_nms
 349.386 +#define newsrc_newstate ns_nst
 349.387 +#define newsrc_read ns_rea
 349.388 +#define newsrc_status ns_sta
 349.389 +#define newsrc_update ns_upd
 349.390 +#define newsrc_write ns_wri
 349.391 +#define newsrc_write_error ns_wer
 349.392 +#define nntp_append n_appn
 349.393 +#define nntp_canonicalize n_cano
 349.394 +#define nntp_check n_chck
 349.395 +#define nntp_close n_clos
 349.396 +#define nntp_copy n_copy
 349.397 +#define nntp_create n_crea
 349.398 +#define nntp_delete n_del
 349.399 +#define nntp_expunge n_expn
 349.400 +#define nntp_fake n_fake
 349.401 +#define nntp_fetchfast nf_fst
 349.402 +#define nntp_fetchflags nf_flg
 349.403 +#define nntp_fetchmessage nf_msg
 349.404 +#define nntp_flagmsg n_fmsg
 349.405 +#define nntp_gc n_gc
 349.406 +#define nntp_getmap n_gmap
 349.407 +#define nntp_header n_head
 349.408 +#define nntp_isvalid n_isvl
 349.409 +#define nntp_list n_list
 349.410 +#define nntp_lsub n_lsub
 349.411 +#define nntp_mail n_mail
 349.412 +#define nntp_mclose n_mcls
 349.413 +#define nntp_mopen n_mopn
 349.414 +#define nntp_open_full n_open
 349.415 +#define nntp_over n_ovr
 349.416 +#define nntp_overview n_over
 349.417 +#define nntp_parameters n_parm
 349.418 +#define nntp_parsestructure n_pars
 349.419 +#define nntp_parse_overview n_povr
 349.420 +#define nntp_ping n_ping
 349.421 +#define nntp_rename n_ren
 349.422 +#define nntp_reply n_repl
 349.423 +#define nntp_scan n_scan
 349.424 +#define nntp_search n_srch
 349.425 +#define nntp_search_msg ns_msg
 349.426 +#define nntp_send n_send
 349.427 +#define nntp_send_auth ns_aut
 349.428 +#define nntp_send_auth_work ns_atw
 349.429 +#define nntp_send_work n_sndw
 349.430 +#define nntp_sort n_sort
 349.431 +#define nntp_sort_loadcache ns_lcs
 349.432 +#define nntp_soutr n_sout
 349.433 +#define nntp_status n_stat
 349.434 +#define nntp_subscribe n_sub
 349.435 +#define nntp_text n_text
 349.436 +#define nntp_text_slurp nt_slp
 349.437 +#define nntp_thread n_thrd
 349.438 +#define nntp_unsubscribe n_uns
 349.439 +#define nntp_valid n_val
 349.440 +#define pop3_append p_appn
 349.441 +#define pop3_auth p_auth
 349.442 +#define pop3_cache p_cach
 349.443 +#define pop3_challenge p_chal
 349.444 +#define pop3_check p_chck
 349.445 +#define pop3_close p_clos
 349.446 +#define pop3_copy p_copy
 349.447 +#define pop3_create p_crea
 349.448 +#define pop3_delete p_del
 349.449 +#define pop3_expunge p_exp
 349.450 +#define pop3_fake p_fake
 349.451 +#define pop3_fetchfast pf_fst
 349.452 +#define pop3_fetchflags pf_flg
 349.453 +#define pop3_fetchmessage pf_msg
 349.454 +#define pop3_gc p_gc
 349.455 +#define pop3_list p_list
 349.456 +#define pop3_lsub p_lsub
 349.457 +#define pop3_open p_open
 349.458 +#define pop3_parameters p_parm
 349.459 +#define pop3_parsestructure p_pars
 349.460 +#define pop3_ping p_ping
 349.461 +#define pop3_rename p_ren
 349.462 +#define pop3_reply p_rep
 349.463 +#define pop3_response p_resp
 349.464 +#define pop3_scan p_scan
 349.465 +#define pop3_send p_send
 349.466 +#define pop3_send_num ps_num
 349.467 +#define pop3_status p_stat
 349.468 +#define pop3_subscribe p_sub
 349.469 +#define pop3_unsubscribe p_uns
 349.470 +#define pop3_valid p_val
 349.471 +#define rfc822_8bit r
 349.472 +#define rfc822_address r_addr
 349.473 +#define rfc822_address_line ra_lin
 349.474 +#define rfc822_base64 r_b64
 349.475 +#define rfc822_binary r_bin
 349.476 +#define rfc822_cat r_cat
 349.477 +#define rfc822_contents r_cont
 349.478 +#define rfc822_cpy r_cpy
 349.479 +#define rfc822_cpy_adr rc_adr
 349.480 +#define rfc822_date r_date
 349.481 +#define rfc822_default_subtype rd_sub
 349.482 +#define rfc822_encode_body_7bit reb_7b
 349.483 +#define rfc822_encode_body_8bit reb_8b
 349.484 +#define rfc822_header r_head
 349.485 +#define rfc822_header_line rh_lin
 349.486 +#define rfc822_output r_out
 349.487 +#define rfc822_output_address ro_adr
 349.488 +#define rfc822_output_address_line roa_ln
 349.489 +#define rfc822_output_address_list roa_li
 349.490 +#define rfc822_output_body ro_bdy
 349.491 +#define rfc822_output_body_header rob_hd
 349.492 +#define rfc822_output_full ro_ful
 349.493 +#define rfc822_output_flush ro_flu
 349.494 +#define rfc822_output_header ro_hdr
 349.495 +#define rfc822_output_header_line roh_ln
 349.496 +#define rfc822_output_cat ro_cat
 349.497 +#define rfc822_output_parameter ro_par
 349.498 +#define rfc822_output_stringlist ro_stl
 349.499 +#define rfc822_output_text ro_txt
 349.500 +#define rfc822_parse_address rp_adr
 349.501 +#define rfc822_parse_addrspec rp_ads
 349.502 +#define rfc822_parse_adrlist rp_adl
 349.503 +#define rfc822_parse_content rp_cnt
 349.504 +#define rfc822_parse_content_header rpc_hd
 349.505 +#define rfc822_parse_group rp_grp
 349.506 +#define rfc822_parse_mailbox rp_mbx
 349.507 +#define rfc822_parse_msg_full rp_msg
 349.508 +#define rfc822_parse_parameter rp_par
 349.509 +#define rfc822_parse_phrase rp_phr
 349.510 +#define rfc822_parse_routeaddr rp_rte
 349.511 +#define rfc822_parse_word rp_wrd
 349.512 +#define rfc822_phraseonly r_poly
 349.513 +#define rfc822_qprint r_qpnt
 349.514 +#define rfc822_quote r_quot
 349.515 +#define rfc822_skip_comment rs_cmt
 349.516 +#define rfc822_skipws rs_ws
 349.517 +#define rfc822_timezone r_tz
 349.518 +#define rfc822_write_address_full rw_adr
 349.519 +#define rfc822_write_body_header rwbh_8
 349.520 +#define server_input_wait s_iwat
 349.521 +#define server_login s_log
 349.522 +#define server_init s_init
 349.523 +#define sm_read sm_rd
 349.524 +#define sm_subscribe sm_sub
 349.525 +#define sm_unsubscribe sm_uns
 349.526 +#define smtp_auth s_auth
 349.527 +#define smtp_challenge s_chal
 349.528 +#define smtp_close s_clos
 349.529 +#define smtp_ehlo s_ehlo
 349.530 +#define smtp_fake s_fake
 349.531 +#define smtp_mail s_mail
 349.532 +#define smtp_open_full s_open
 349.533 +#define smtp_rcpt s_rcpt
 349.534 +#define smtp_reply s_repl
 349.535 +#define smtp_response s_resp
 349.536 +#define smtp_send s_send
 349.537 +#define smtp_send_auth ss_aut
 349.538 +#define smtp_send_auth_work ss_atw
 349.539 +#define smtp_send_work ss_wrk
 349.540 +#define smtp_soutr s_str
 349.541 +#define strcrlfcpy sc_cpy
 349.542 +#define strcrlflen sc_len
 349.543 +#define tcp_aopen t_aopn
 349.544 +#define tcp_canonical t_cnon
 349.545 +#define tcp_clientaddr t_cadr
 349.546 +#define tcp_clienthost t_chst
 349.547 +#define tcp_clientport t_cprt
 349.548 +#define tcp_close t_clos
 349.549 +#define tcp_getbuffer tg_buf
 349.550 +#define tcp_getdata tg_dat
 349.551 +#define tcp_getline tg_lin
 349.552 +#define tcp_host t_host
 349.553 +#define tcp_localhost t_lhst
 349.554 +#define tcp_open t_open
 349.555 +#define tcp_parameters t_parameters
 349.556 +#define tcp_port t_port
 349.557 +#define tcp_remotehost t_rhst
 349.558 +#define tcp_serveraddr t_sadr
 349.559 +#define tcp_serverhost t_shst
 349.560 +#define tcp_serverport t_sprt
 349.561 +#define tcp_sout t_sout
 349.562 +#define tcp_soutr t_str
 349.563 +#define textcpy txcopy
 349.564 +#define textcpystring txcpst
 349.565 +#define textcpyoffstring txcpos
 349.566 +#define ucs4_cs_get u4_csg
 349.567 +#define ucs4_decompose u4_dcm
 349.568 +#define ucs4_decompose_recursive u4_dcr
 349.569 +#define ucs4_rmapbuf u4r_bf
 349.570 +#define ucs4_rmaplen u4r_ln
 349.571 +#define ucs4_rmaptext u4r_tx
 349.572 +#define ucs4_titlecase u4_tcs
 349.573 +#define ucs4_width u4_wid
 349.574 +#define utf8_badcharset u8_bcs
 349.575 +#define utf8_charset u8_chs
 349.576 +#define utf8_cstext u8_cst
 349.577 +#define utf8_cstocstext u8_cct
 349.578 +#define utf8_from_mutf7 u8fmu7
 349.579 +#define utf8_get u8_get
 349.580 +#define utf8_get_raw u8_gtr
 349.581 +#define utf8_iso2022text u8_i22
 349.582 +#define utf8_mime2text u8_mi2
 349.583 +#define utf8_put u8_put
 349.584 +#define utf8_rmap u8_rmp
 349.585 +#define utf8_rmap_cs u8r_cs
 349.586 +#define utf8_rmap_gen u8r_gn
 349.587 +#define utf8_rmapsize u8r_sz
 349.588 +#define utf8_rmaptext u8r_tx
 349.589 +#define utf8_script u8_scr
 349.590 +#define utf8_searchpgm u8_spg
 349.591 +#define utf8_size u8_siz
 349.592 +#define utf8_stringlist u8_lst
 349.593 +#define utf8_text u8_txt
 349.594 +#define utf8_text_2022 u8t_22
 349.595 +#define utf8_text_8859_1 u8t_we
 349.596 +#define utf8_text_1byte0 u8t_10
 349.597 +#define utf8_text_1byte u8t_1b
 349.598 +#define utf8_text_1byte8 u8t_18
 349.599 +#define utf8_text_cs ut8_cs
 349.600 +#define utf8_text_euc u8t_eu
 349.601 +#define utf8_text_dbyte u8t_db
 349.602 +#define utf8_text_dbyte2 u8t_d2
 349.603 +#define utf8_text_sjis u8t_sj
 349.604 +#define utf8_text_ucs2 u8t_u2
 349.605 +#define utf8_text_ucs4 ut8_u4
 349.606 +#define utf8_text_utf7 ut8_u7
 349.607 +#define utf8_text_utf8 ut8_u8
 349.608 +#define utf8_text_utf16 ut8_16
 349.609 +#define utf8_to_mutf7 u8tmu7
 349.610 +#define utf8_validate u8_val
 349.611 +#define utf8_textwidth u8_twd
   350.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   350.2 +++ b/src/osdep/tops-20/tcp_t20.c	Mon Sep 14 15:17:45 2009 +0900
   350.3 @@ -0,0 +1,365 @@
   350.4 +/* ========================================================================
   350.5 + * Copyright 1988-2008 University of Washington
   350.6 + *
   350.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   350.8 + * you may not use this file except in compliance with the License.
   350.9 + * You may obtain a copy of the License at
  350.10 + *
  350.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  350.12 + *
  350.13 + * 
  350.14 + * ========================================================================
  350.15 + */
  350.16 +
  350.17 +/*
  350.18 + * Program:	TOPS-20 TCP/IP routines
  350.19 + *
  350.20 + * Author:	Mark Crispin
  350.21 + *		Networks and Distributed Computing
  350.22 + *		Computing & Communications
  350.23 + *		University of Washington
  350.24 + *		Administration Building, AG-44
  350.25 + *		Seattle, WA  98195
  350.26 + *		Internet: MRC@CAC.Washington.EDU
  350.27 + *
  350.28 + * Date:	1 August 1988
  350.29 + * Last Edited:	13 January 2008
  350.30 + */
  350.31 +
  350.32 +
  350.33 +/* Dedication:
  350.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  350.35 + * set standards for user and programmer friendliness that have still not been
  350.36 + * equaled by more `modern' operating systems.
  350.37 + * Wasureru mon ka!!!!
  350.38 + */
  350.39 +
  350.40 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  350.41 +			       long *contd);
  350.42 +
  350.43 +/* TCP/IP manipulate parameters
  350.44 + * Accepts: function code
  350.45 + *	    function-dependent value
  350.46 + * Returns: function-dependent return value
  350.47 + */
  350.48 +
  350.49 +void *tcp_parameters (long function,void *value)
  350.50 +{
  350.51 +  return NIL;
  350.52 +}
  350.53 +
  350.54 +/* TCP/IP open
  350.55 + * Accepts: host name
  350.56 + *	    contact service name
  350.57 + *	    contact port number
  350.58 + * Returns: TCP stream if success else NIL
  350.59 + */
  350.60 +
  350.61 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  350.62 +{
  350.63 +  char *s,tmp[MAILTMPLEN];
  350.64 +  TCPSTREAM *stream = NIL;
  350.65 +  int argblk[5],jfn;
  350.66 +  unsigned long i,j,k,l;
  350.67 +  char file[MAILTMPLEN];
  350.68 +  port &= 0xffff;		/* erase flags */
  350.69 +				/* domain literal? */
  350.70 +  if (host[0] == '[' && host[strlen (host)-1] == ']') {
  350.71 +    if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
  350.72 +	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
  350.73 +	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
  350.74 +	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
  350.75 +      argblk[3] = (i << 24) + (j << 16) + (k << 8) + l;
  350.76 +      sprintf (tmp,"[%lu.%lu.%lu.%lu]",i,j,k,l);
  350.77 +    }
  350.78 +    else {
  350.79 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
  350.80 +      mm_log (tmp,ERROR);
  350.81 +      return NIL;
  350.82 +    }
  350.83 +  }
  350.84 +  else {			/* host name */
  350.85 +    argblk[1] = _GTHPN;		/* get IP address and primary name */
  350.86 +    argblk[2] = (int) (host-1);	/* pointer to host */
  350.87 +    argblk[4] = (int) (tmp-1);
  350.88 +    if (!jsys (GTHST,argblk)) {	/* first try DEC's domain way */
  350.89 +      argblk[1] = _GTHPN;	/* get IP address and primary name */
  350.90 +      argblk[2] = (int) (host-1);
  350.91 +      argblk[4] = (int) (tmp-1);
  350.92 +      if (!jsys (GTDOM,argblk)){/* try the CHIVES domain way */
  350.93 +	argblk[1] = _GTHSN;	/* failed, do the host table then */
  350.94 +	if (!jsys (GTHST,argblk)) {
  350.95 +	  sprintf (tmp,"No such host as %s",host);
  350.96 +	  mm_log (tmp,ERROR);
  350.97 +	  return NIL;
  350.98 +	}
  350.99 +	argblk[1] = _GTHNS;	/* convert number to string */
 350.100 +	argblk[2] = (int) (tmp-1);
 350.101 +				/* get the official name */
 350.102 +	if (!jsys (GTHST,argblk)) strcpy (tmp,host);
 350.103 +      }
 350.104 +    }
 350.105 +  }
 350.106 +
 350.107 +  sprintf (file,"TCP:.%o-%d;PERSIST:30;CONNECTION:ACTIVE",argblk[3],port);
 350.108 +  argblk[1] = GJ_SHT;		/* short form GTJFN% */
 350.109 +  argblk[2] = (int) (file-1);	/* pointer to file name */
 350.110 +				/* get JFN for TCP: file */
 350.111 +  if (!jsys (GTJFN,argblk)) fatal ("Unable to create TCP JFN");
 350.112 +  jfn = argblk[1];		/* note JFN for later */
 350.113 +				/* want 8-bit bidirectional I/O */
 350.114 +  argblk[2] = OF_RD|OF_WR|(FLD (8,monsym("OF%BSZ")));
 350.115 +  if (!jsys (OPENF,argblk)) {
 350.116 +    sprintf (file,"Can't connect to %s,%d server",tmp,port);
 350.117 +    mm_log (file,ERROR);
 350.118 +    return NIL;
 350.119 +  }
 350.120 +				/* create TCP/IP stream */
 350.121 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
 350.122 +  stream->host = cpystr (tmp);	/* copy official host name */
 350.123 +  argblk[1] = _GTHNS;		/* convert number to string */
 350.124 +  argblk[2] = (int) (tmp-1);
 350.125 +  argblk[3] = -1;		/* want local host */
 350.126 +  if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL");
 350.127 +  stream->localhost = cpystr (tmp);
 350.128 +  stream->port = port;		/* save port number */
 350.129 +  stream->jfn = jfn;		/* init JFN */
 350.130 +  return stream;
 350.131 +}
 350.132 +
 350.133 +/* TCP/IP authenticated open
 350.134 + * Accepts: NETMBX specifier
 350.135 + *	    service name
 350.136 + *	    returned user name buffer
 350.137 + * Returns: TCP/IP stream if success else NIL
 350.138 + */
 350.139 +
 350.140 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 350.141 +{
 350.142 +  return NIL;
 350.143 +}
 350.144 +
 350.145 +/* TCP receive line
 350.146 + * Accepts: TCP stream
 350.147 + * Returns: text line string or NIL if failure
 350.148 + */
 350.149 +
 350.150 +char *tcp_getline (TCPSTREAM *stream)
 350.151 +{
 350.152 +  unsigned long n,contd;
 350.153 +  char *ret = tcp_getline_work (stream,&n,&contd);
 350.154 +  if (ret && contd) {		/* got a line needing continuation? */
 350.155 +    STRINGLIST *stl = mail_newstringlist ();
 350.156 +    STRINGLIST *stc = stl;
 350.157 +    do {			/* collect additional lines */
 350.158 +      stc->text.data = (unsigned char *) ret;
 350.159 +      stc->text.size = n;
 350.160 +      stc = stc->next = mail_newstringlist ();
 350.161 +      ret = tcp_getline_work (stream,&n,&contd);
 350.162 +    } while (ret && contd);
 350.163 +    if (ret) {			/* stash final part of line on list */
 350.164 +      stc->text.data = (unsigned char *) ret;
 350.165 +      stc->text.size = n;
 350.166 +				/* determine how large a buffer we need */
 350.167 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 350.168 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 350.169 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 350.170 +	memcpy (ret + n,stc->text.data,stc->text.size);
 350.171 +      ret[n] = '\0';
 350.172 +    }
 350.173 +    mail_free_stringlist (&stl);/* either way, done with list */
 350.174 +  }
 350.175 +  return ret;
 350.176 +}
 350.177 +
 350.178 +/* TCP receive line or partial line
 350.179 + * Accepts: TCP stream
 350.180 + *	    pointer to return size
 350.181 + *	    pointer to return continuation flag
 350.182 + * Returns: text line string, size and continuation flag, or NIL if failure
 350.183 + */
 350.184 +
 350.185 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 350.186 +			       long *contd)
 350.187 +{
 350.188 +  int argblk[5];
 350.189 +  unsigned long n,m;
 350.190 +  char *ret,*stp,*st;
 350.191 +  *contd = NIL;			/* assume no continuation */
 350.192 +  argblk[1] = stream->jfn;	/* read from TCP */
 350.193 +				/* pointer to buffer */
 350.194 +  argblk[2] = (int) (stream->ibuf - 1);
 350.195 +  argblk[3] = BUFLEN;		/* max number of bytes to read */
 350.196 +  argblk[4] = '\012';		/* terminate on LF */
 350.197 +  if (!jsys (SIN,argblk)) return NIL;
 350.198 +  n = BUFLEN - argblk[3];	/* number of bytes read */
 350.199 +				/* got a complete line? */
 350.200 +  if ((stream->ibuf[n - 2] == '\015') && (stream->ibuf[n - 1] == '\012')) {
 350.201 +    memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n - 2);
 350.202 +    ret[n - 2] = '\0';		/* tie off string with null */
 350.203 +    return ret;
 350.204 +  }
 350.205 +				/* copy partial string */
 350.206 +  memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n);
 350.207 +				/* special case of newline broken by buffer */
 350.208 +  if ((stream->ibuf[n - 1] == '\015') && jsys (BIN,argblk) &&
 350.209 +      (argblk[2] == '\012')) {	/* was it? */
 350.210 +    ret[n - 1] = '\0';		/* tie off string with null */
 350.211 +  }
 350.212 +				/* otherwise back up */
 350.213 +  else if (!jsys (BKJFN,argblk)) fs_give ((void **) &ret);
 350.214 +  else *contd = LONGT;		/* continuation needed */
 350.215 +  return ret;
 350.216 +}
 350.217 +
 350.218 +/* TCP/IP receive buffer
 350.219 + * Accepts: TCP/IP stream
 350.220 + *	    size in bytes
 350.221 + *	    buffer to read into
 350.222 + * Returns: T if success, NIL otherwise
 350.223 + */
 350.224 +
 350.225 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 350.226 +{
 350.227 +  int argblk[5];
 350.228 +  argblk[1] = stream->jfn;	/* read from TCP */
 350.229 +  argblk[2] = (int) (buffer-1);	/* pointer to buffer */
 350.230 +  argblk[3] = -size;		/* number of bytes to read */
 350.231 +  if (!jsys (SIN,argblk)) return NIL;
 350.232 +  buffer[size] = '\0';		/* tie off text */
 350.233 +  return T;
 350.234 +}
 350.235 +
 350.236 +
 350.237 +/* TCP/IP send string as record
 350.238 + * Accepts: TCP/IP stream
 350.239 + *	    string pointer
 350.240 + * Returns: T if success else NIL
 350.241 + */
 350.242 +
 350.243 +long tcp_soutr (TCPSTREAM *stream,char *string)
 350.244 +{
 350.245 +  int argblk[5];
 350.246 +  argblk[1] = stream->jfn;	/* write to TCP */
 350.247 +  argblk[2] = (int) (string-1);	/* pointer to buffer */
 350.248 +  argblk[3] = 0;		/* write until NUL */
 350.249 +  if (!jsys (SOUTR,argblk)) return NIL;
 350.250 +  return T;
 350.251 +}
 350.252 +
 350.253 +
 350.254 +/* TCP/IP send string
 350.255 + * Accepts: TCP/IP stream
 350.256 + *	    string pointer
 350.257 + *	    byte count
 350.258 + * Returns: T if success else NIL
 350.259 + */
 350.260 +
 350.261 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 350.262 +{
 350.263 +  int argblk[5];
 350.264 +  argblk[1] = stream->jfn;	/* write to TCP */
 350.265 +  argblk[2] = (int) (string-1);	/* pointer to buffer */
 350.266 +  argblk[3] = -size;		/* write this many bytes */
 350.267 +  if (!jsys (SOUTR,argblk)) return NIL;
 350.268 +  return T;
 350.269 +}
 350.270 +
 350.271 +/* TCP/IP close
 350.272 + * Accepts: TCP/IP stream
 350.273 + */
 350.274 +
 350.275 +void tcp_close (TCPSTREAM *stream)
 350.276 +{
 350.277 +  int argblk[5];
 350.278 +  argblk[1] = stream->jfn;	/* close TCP */
 350.279 +  jsys (CLOSF,argblk);
 350.280 +				/* flush host names */
 350.281 +  fs_give ((void **) &stream->host);
 350.282 +  fs_give ((void **) &stream->localhost);
 350.283 +  fs_give ((void **) &stream);	/* flush the stream */
 350.284 +}
 350.285 +
 350.286 +
 350.287 +/* TCP/IP return host for this stream
 350.288 + * Accepts: TCP/IP stream
 350.289 + * Returns: host name for this stream
 350.290 + */
 350.291 +
 350.292 +char *tcp_host (TCPSTREAM *stream)
 350.293 +{
 350.294 +  return stream->host;		/* return host name */
 350.295 +}
 350.296 +
 350.297 +
 350.298 +/* TCP/IP return remote host for this stream
 350.299 + * Accepts: TCP/IP stream
 350.300 + * Returns: host name for this stream
 350.301 + */
 350.302 +
 350.303 +char *tcp_remotehost (TCPSTREAM *stream)
 350.304 +{
 350.305 +  return stream->host;		/* return host name */
 350.306 +}
 350.307 +
 350.308 +
 350.309 +/* TCP/IP return port for this stream
 350.310 + * Accepts: TCP/IP stream
 350.311 + * Returns: port number for this stream
 350.312 + */
 350.313 +
 350.314 +unsigned long tcp_port (TCPSTREAM *stream)
 350.315 +{
 350.316 +  return stream->port;		/* return port number */
 350.317 +}
 350.318 +
 350.319 +
 350.320 +/* TCP/IP return local host for this stream
 350.321 + * Accepts: TCP/IP stream
 350.322 + * Returns: local host name for this stream
 350.323 + */
 350.324 +
 350.325 +char *tcp_localhost (TCPSTREAM *stream)
 350.326 +{
 350.327 +  return stream->localhost;	/* return local host name */
 350.328 +}
 350.329 +
 350.330 +/* TCP/IP return canonical form of host name
 350.331 + * Accepts: host name
 350.332 + * Returns: canonical form of host name
 350.333 + */
 350.334 +
 350.335 +char *tcp_canonical (char *name)
 350.336 +{
 350.337 +  int argblk[5];
 350.338 +  static char tmp[MAILTMPLEN];
 350.339 +				/* look like domain literal? */
 350.340 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 350.341 +  argblk[1] = _GTHPN;		/* get IP address and primary name */
 350.342 +  argblk[2] = (int) (name-1);	/* pointer to host */
 350.343 +  argblk[4] = (int) (tmp-1);	/* pointer to return destination */
 350.344 +  if (!jsys (GTHST,argblk)) {	/* first try DEC's domain way */
 350.345 +    argblk[1] = _GTHPN;		/* get IP address and primary name */
 350.346 +    argblk[2] = (int) (name-1);
 350.347 +    argblk[4] = (int) (tmp-1);
 350.348 +    if (!jsys (GTDOM,argblk)) {	/* try the CHIVES domain way */
 350.349 +      argblk[1] = _GTHSN;	/* failed, do the host table then */
 350.350 +      if (!jsys (GTHST,argblk)) return name;
 350.351 +      argblk[1] = _GTHNS;	/* convert number to string */
 350.352 +      argblk[2] = (int) (tmp-1);
 350.353 +				/* get the official name */
 350.354 +      if (!jsys (GTHST,argblk)) return name;
 350.355 +    }
 350.356 +  }
 350.357 +  return tmp;
 350.358 +}
 350.359 +
 350.360 +
 350.361 +/* TCP/IP get client host name (server calls only)
 350.362 + * Returns: client host name
 350.363 + */
 350.364 +
 350.365 +char *tcp_clienthost ()
 350.366 +{
 350.367 +  return "UNKNOWN";
 350.368 +}
   351.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   351.2 +++ b/src/osdep/tops-20/tcp_t20.h	Mon Sep 14 15:17:45 2009 +0900
   351.3 @@ -0,0 +1,65 @@
   351.4 +/* ========================================================================
   351.5 + * Copyright 1988-2006 University of Washington
   351.6 + *
   351.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   351.8 + * you may not use this file except in compliance with the License.
   351.9 + * You may obtain a copy of the License at
  351.10 + *
  351.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  351.12 + *
  351.13 + * 
  351.14 + * ========================================================================
  351.15 + */
  351.16 +
  351.17 +/*
  351.18 + * Program:	TOPS-20 TCP/IP routines
  351.19 + *
  351.20 + * Author:	Mark Crispin
  351.21 + *		Networks and Distributed Computing
  351.22 + *		Computing & Communications
  351.23 + *		University of Washington
  351.24 + *		Administration Building, AG-44
  351.25 + *		Seattle, WA  98195
  351.26 + *		Internet: MRC@CAC.Washington.EDU
  351.27 + *
  351.28 + * Date:	1 August 1988
  351.29 + * Last Edited:	30 August 2006
  351.30 + */
  351.31 +
  351.32 +
  351.33 +/* Dedication:
  351.34 + * This file is dedicated with affection to the TOPS-20 operating system, which
  351.35 + * set standards for user and programmer friendliness that have still not been
  351.36 + * equaled by more `modern' operating systems.
  351.37 + * Wasureru mon ka!!!!
  351.38 + */
  351.39 +
  351.40 +/* TCP input buffer */
  351.41 +
  351.42 +#define BUFLEN 8192
  351.43 +
  351.44 +/* TCP I/O stream (must be before osdep.h is included) */
  351.45 +
  351.46 +#define TCPSTREAM struct tcp_stream
  351.47 +TCPSTREAM {
  351.48 +  char *host;			/* host name */
  351.49 +  unsigned long port;		/* port number */
  351.50 +  char *localhost;		/* local host name */
  351.51 +  int jfn;			/* jfn for connection */
  351.52 +  char ibuf[BUFLEN];		/* input buffer */
  351.53 +};
  351.54 +
  351.55 +
  351.56 +/* All of these should be in JSYS.H, but just in case... */
  351.57 +
  351.58 +#ifndef _GTHPN
  351.59 +#define _GTHPN 12
  351.60 +#endif
  351.61 +
  351.62 +#ifndef _GTDPN
  351.63 +#define _GTDPN 12
  351.64 +#endif
  351.65 +
  351.66 +#ifndef GTDOM
  351.67 +#define GTDOM (FLD (1,JSYS_CLASS) | 501
  351.68 +#endif
   352.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   352.2 +++ b/src/osdep/unix/Makefile	Mon Sep 14 15:17:45 2009 +0900
   352.3 @@ -0,0 +1,1070 @@
   352.4 +# ========================================================================
   352.5 +# Copyright 1988-2007 University of Washington
   352.6 +#
   352.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   352.8 +# you may not use this file except in compliance with the License.
   352.9 +# You may obtain a copy of the License at
  352.10 +#
  352.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  352.12 +#
  352.13 +# 
  352.14 +# ========================================================================
  352.15 +
  352.16 +# Program:	C client makefile
  352.17 +#
  352.18 +# Author:	Mark Crispin
  352.19 +#		Networks and Distributed Computing
  352.20 +#		Computing & Communications
  352.21 +#		University of Washington
  352.22 +#		Administration Building, AG-44
  352.23 +#		Seattle, WA  98195
  352.24 +#		Internet: MRC@CAC.Washington.EDU
  352.25 +#
  352.26 +# Date:		11 May 1989
  352.27 +# Last Edited:	17 December 2007
  352.28 +
  352.29 +
  352.30 +# Command line build parameters
  352.31 +
  352.32 +EXTRAAUTHENTICATORS=
  352.33 +EXTRADRIVERS=mbox
  352.34 +PASSWDTYPE=std
  352.35 +SSLTYPE=nopwd
  352.36 +IP=4
  352.37 +
  352.38 +
  352.39 +# The optimization level here for GCC ports is set here for a reason.  It's
  352.40 +# to get you to read this text.
  352.41 +# The general concensus seems to be that -O2 is the one to use.
  352.42 +# Over the years, I've been told to use many different settings, including -O6.
  352.43 +# In recent versions of GCC [as of 2/2005], -O6 generates bad code that, among
  352.44 +# other ill effects, causes infinite loops.
  352.45 +# -O3 seems to be safe, but empirical observation from our local expert
  352.46 +# indicates that in some (many?) cases -O3 code runs slower than -O2.
  352.47 +
  352.48 +GCCOPTLEVEL= -O2
  352.49 +
  352.50 +
  352.51 +# Try to have some consistency in GCC builds.  We want optimization, but we
  352.52 +# also want to be able to debug.
  352.53 +
  352.54 +GCCCFLAGS= -g $(GCCOPTLEVEL) -pipe -fno-omit-frame-pointer
  352.55 +GCC4CFLAGS= $(GCCCFLAGS) -Wno-pointer-sign
  352.56 +
  352.57 +
  352.58 +# Extended flags needed for SSL.  You may need to modify.
  352.59 +
  352.60 +SSLDIR=/usr/local/ssl
  352.61 +SSLCERTS=$(SSLDIR)/certs
  352.62 +SSLKEYS=$(SSLCERTS)
  352.63 +SSLINCLUDE=$(SSLDIR)/include
  352.64 +SSLLIB=$(SSLDIR)/lib
  352.65 +
  352.66 +SSLCRYPTO=-lcrypto
  352.67 +
  352.68 +# Older versions of MIT Kerberos also have a libcrypto.  If so, you may need
  352.69 +# to use this instead
  352.70 +#SSLCRYPTO=$(SSLLIB)/libcrypto.a
  352.71 +
  352.72 +# RSA Security Inc. released the RSA public key encryption algorithm into
  352.73 +# the public domain on September 6, 2000.  There is no longer any need to
  352.74 +# use RSAREF.
  352.75 +SSLRSA= # -lRSAglue -lrsaref
  352.76 +
  352.77 +SSLCFLAGS= -I$(SSLINCLUDE) -I$(SSLINCLUDE)/openssl\
  352.78 + -DSSL_CERT_DIRECTORY=\"$(SSLCERTS)\" -DSSL_KEY_DIRECTORY=\"$(SSLKEYS)\"
  352.79 +SSLLDFLAGS= -L$(SSLLIB) -lssl $(SSLCRYPTO) $(SSLRSA)
  352.80 +
  352.81 +
  352.82 +# Extended flags needed for non-standard passwd types.  You may need to modify.
  352.83 +
  352.84 +AFSDIR=/usr/afsws
  352.85 +AFSCFLAGS=-I$(AFSDIR)/include
  352.86 +AFSLIB=$(AFSDIR)/lib
  352.87 +AFSLDFLAGS=-L$(AFSLIB)/afs -L$(AFSLIB) -L$(AFSDIR)/domestic/lib\
  352.88 + -lkauth -lprot -lubik -lauth -lrxkad -lrx -llwp -ldes -lcom_err\
  352.89 + $(AFSLIB)/afs/util.a -laudit -lsys
  352.90 +# AFSLDFLAGS may also need -L/usr/ucblib -lucb
  352.91 +DCECFLAGS= -DDCE_MINIMAL -DPASSWD_OVERRIDE=\"/opt/pop3/passwd/passwd\"
  352.92 +DCELDFLAGS= -ldce
  352.93 +PAMLDFLAGS= -lpam -ldl
  352.94 +
  352.95 +
  352.96 +# Build parameters normally set by the individual port
  352.97 +
  352.98 +CHECKPW=std
  352.99 +LOGINPW=std
 352.100 +SIGTYPE=bsd
 352.101 +CRXTYPE=std
 352.102 +ACTIVEFILE=/usr/lib/news/active
 352.103 +SPOOLDIR=/usr/spool
 352.104 +MAILSPOOL=$(SPOOLDIR)/mail
 352.105 +NEWSSPOOL=$(SPOOLDIR)/news
 352.106 +RSHPATH=/usr/ucb/rsh
 352.107 +MD5PWD=/etc/cram-md5.pwd
 352.108 +# Tries one of the test alternatives below if not specified.
 352.109 +LOCKPGM=
 352.110 +# Test alternatives if LOCKPGM not specified
 352.111 +LOCKPGM1=/usr/libexec/mlock
 352.112 +LOCKPGM2=/usr/sbin/mlock
 352.113 +LOCKPGM3=/etc/mlock
 352.114 +
 352.115 +
 352.116 +# Default formats for creating new mailboxes and for empty mailboxes in the
 352.117 +# default namespace; must be set to the associated driver's prototype.
 352.118 +#
 352.119 +# The CREATEPROTO is the default format for new mailbox creation.
 352.120 +# The EMPTYPROTO is the default format for handling zero-byte files.
 352.121 +#
 352.122 +# Normally, this is set by the individual port.
 352.123 +#
 352.124 +# NOTE: namespace formats (e.g. mh and news) can not be set as a default format
 352.125 +# since they do not exist in the default namespace.  Also, it is meaningless to
 352.126 +# set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since
 352.127 +# these formats can never be empty files.
 352.128 +
 352.129 +CREATEPROTO=unixproto
 352.130 +EMPTYPROTO=unixproto
 352.131 +
 352.132 +
 352.133 +# Commands possibly overriden by the individual port
 352.134 +
 352.135 +ARRC=ar rc
 352.136 +CC=cc
 352.137 +LN=ln -s
 352.138 +RANLIB=ranlib
 352.139 +
 352.140 +
 352.141 +# Standard distribution build parameters
 352.142 +
 352.143 +DEFAULTAUTHENTICATORS=ext md5 pla log
 352.144 +#
 352.145 +# mh needs to be after any other directory format drivers (such as mx or mix)
 352.146 +# since otherwise mh will seize any directory that is under the mh path.
 352.147 +# However, mh needs to be before any sysinbox formats (such as mmdf or unix)
 352.148 +# since otherwise INBOX won't work correctly when mh_allow_inbox is set.
 352.149 +#
 352.150 +DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
 352.151 +CHUNKSIZE=65536
 352.152 +
 352.153 +# Normally no need to change any of these
 352.154 +
 352.155 +ARCHIVE=c-client.a
 352.156 +BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
 352.157 + dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
 352.158 + rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
 352.159 + unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
 352.160 +CFLAGS=-g
 352.161 +
 352.162 +CAT=cat
 352.163 +MAKE=make
 352.164 +MV=mv
 352.165 +RM=rm -rf
 352.166 +SH=sh
 352.167 +
 352.168 +
 352.169 +# Primary build command
 352.170 +
 352.171 +BUILD=$(MAKE) build EXTRACFLAGS='$(EXTRACFLAGS)'\
 352.172 + EXTRALDFLAGS='$(EXTRALDFLAGS)'\
 352.173 + EXTRADRIVERS='$(EXTRADRIVERS)' EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\
 352.174 + PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP)
 352.175 +
 352.176 +
 352.177 +# Here if no make argument established
 352.178 +
 352.179 +missing: osdep.h
 352.180 +	$(MAKE) all `$(CAT) SPECIALS`
 352.181 +
 352.182 +osdep.h:
 352.183 +	@echo You must specify what type of system
 352.184 +	@false
 352.185 +
 352.186 +
 352.187 +# Current ports
 352.188 +
 352.189 +a32:	# AIX 3.2 for RS/6000
 352.190 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.191 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.192 +	 SPOOLDIR=/var/spool \
 352.193 +	 RSHPATH=/usr/bin/rsh \
 352.194 +	 BASECFLAGS="-g -Dunix=1 -D_BSD" \
 352.195 +	 BASELDFLAGS="-lbsd"
 352.196 +
 352.197 +a41:	# AIX 4.1 for RS/6000
 352.198 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.199 +	 SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \
 352.200 +	 SPOOLDIR=/var/spool \
 352.201 +	 RSHPATH=/usr/bin/rsh \
 352.202 +	 BASECFLAGS="-g -Dunix=1 -D_BSD -qro -qroconst" \
 352.203 +	 BASELDFLAGS="-ls"
 352.204 +
 352.205 +aix:	# AIX/370
 352.206 +	@echo You are building for AIX on an S/370 class machine
 352.207 +	@echo If you want AIX on an RS/6000 you need to use a32 or a41 instead!
 352.208 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.209 +	 CRXTYPE=nfs \
 352.210 +	 BASECFLAGS="-g" \
 352.211 +	 BASELDFLAGS="-lbsd"
 352.212 +
 352.213 +aos:	# AOS for RT
 352.214 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.215 +	 CRXTYPE=nfs \
 352.216 +	 BASECFLAGS="-g -Dconst="
 352.217 +
 352.218 +art:	# AIX 2.2.1 for RT
 352.219 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.220 +	 SIGTYPE=sv4 \
 352.221 +	 SPOOLDIR=/var \
 352.222 +	 ACTIVEFILE=/usr/local/news/control/active \
 352.223 +	 RSHPATH=/bin/rsh \
 352.224 +	 BASECFLAGS="-g -Dconst= -Dvoid=char" \
 352.225 +	 RANLIB=true 
 352.226 +
 352.227 +asv:	# Altos SVR4
 352.228 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.229 +	 SIGTYPE=sv4 LOGINPW=old \
 352.230 +	 ACTIVEFILE=/usr/spool/news/active \
 352.231 +	 RSHPATH=/usr/bin/rcmd \
 352.232 +	 BASECFLAGS="-Dconst= -DSIGSTOP=SIGKILL" \
 352.233 +	 BASELDFLAGS="-lsocket -lrpc -lgen -lcrypt -lxenix" \
 352.234 +	 RANLIB=true
 352.235 +
 352.236 +aux:	# A/UX
 352.237 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.238 +	 CRXTYPE=nfs \
 352.239 +	 MAILSPOOL=/usr/mail \
 352.240 +	 BASECFLAGS="-g -B/usr/lib/big/ -Dvoid=char -Dconst=" \
 352.241 +	 RANLIB=true ARRC="ar -rc"
 352.242 +
 352.243 +bs3:	# BSD/i386 3.0 or higher
 352.244 +	$(BUILD) `$(CAT) SPECIALS` OS=bsi \
 352.245 +	 CHECKPW=bsi LOGINPW=bsi CRXTYPE=nfs \
 352.246 +	 SPOOLDIR=/var NEWSSPOOL=/var/news/spool \
 352.247 +	 ACTIVEFILE=/var/news/etc/active \
 352.248 +	 RSHPATH=/usr/bin/rsh \
 352.249 +	 BASECFLAGS="$(GCCCFLAGS)" CC=shlicc
 352.250 +
 352.251 +bsd:	# BSD UNIX
 352.252 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.253 +	 CRXTYPE=nfs \
 352.254 +	 BASECFLAGS="-g -Dconst="
 352.255 +
 352.256 +bsf:	# FreeBSD
 352.257 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.258 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.259 +	 SPOOLDIR=/var \
 352.260 +	 ACTIVEFILE=/usr/local/news/lib/active \
 352.261 +	 RSHPATH=/usr/bin/rsh \
 352.262 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.263 +	 BASELDFLAGS="-lcrypt"
 352.264 +
 352.265 +bsi:	# BSD/i386
 352.266 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.267 +	 CRXTYPE=nfs \
 352.268 +	 SPOOLDIR=/var NEWSSPOOL=/var/news/spool \
 352.269 +	 ACTIVEFILE=/var/news/etc/active \
 352.270 +	 RSHPATH=/usr/bin/rsh \
 352.271 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.272 +
 352.273 +bso:	# OpenBSD
 352.274 +	$(BUILD) `$(CAT) SPECIALS` OS=bsi \
 352.275 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.276 +	 SPOOLDIR=/var \
 352.277 +	 ACTIVEFILE=/usr/local/news/lib/active \
 352.278 +	 RSHPATH=/usr/bin/rsh \
 352.279 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.280 +
 352.281 +cvx:	# Convex
 352.282 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.283 +	 CRXTYPE=nfs \
 352.284 +	 BASECFLAGS="-O -ext -Dconst="
 352.285 +
 352.286 +cyg:	# Cygwin - note that most local file drivers don't work!!
 352.287 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.288 +	DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \
 352.289 +	SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
 352.290 +	SPOOLDIR=/var \
 352.291 +	ACTIVEFILE=/usr/local/news/lib/active \
 352.292 +	RSHPATH=/usr/bin/rsh \
 352.293 +	BASECFLAGS="$(GCCCFLAGS)" \
 352.294 +	BASELDFLAGS="-lcrypt" \
 352.295 +	CC=gcc
 352.296 +
 352.297 +d-g:	# Data General DG/UX
 352.298 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.299 +	 SIGTYPE=sv4 CRXTYPE=nfs \
 352.300 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.301 +	 ACTIVEFILE=/local/news/active \
 352.302 +	 RSHPATH=/usr/bin/remsh \
 352.303 +	 BASECFLAGS="-g -Dconst=" \
 352.304 +	 BASELDFLAGS="-lnsl -lsocket" \
 352.305 +	 RANLIB=true
 352.306 +
 352.307 +d54:	# Data General DG/UX 5.4
 352.308 +	$(BUILD) `$(CAT) SPECIALS` OS=d-g \
 352.309 +	 SIGTYPE=sv4 CRXTYPE=nfs \
 352.310 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.311 +	 ACTIVEFILE=/local/news/active \
 352.312 +	 RSHPATH=/usr/bin/remsh \
 352.313 +	 BASECFLAGS="-g -Dconst=" \
 352.314 +	 BASELDFLAGS="-lnsl -lsocket" \
 352.315 +	 RANLIB=true
 352.316 +
 352.317 +dpx:	# Bull DPX/2
 352.318 +	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
 352.319 +	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
 352.320 +	 RSHPATH=/usr/bin/remsh \
 352.321 +	 BASECFLAGS="-Dconst= -DSYSTEM5 -DSHORT_IDENT" \
 352.322 +	 BASELDFLAGS="-linet" \
 352.323 +	 RANLIB=true LN=ln
 352.324 +
 352.325 +drs:	# ICL DRS/NX
 352.326 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.327 +	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 CRXTYPE=nfs \
 352.328 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.329 +	 ACTIVEFILE=/var/lib/news/active \
 352.330 +	 RSHPATH=/usr/bin/rsh \
 352.331 +	 BASECFLAGS="-O" \
 352.332 +	 BASELDFLAGS="-lsocket -lgen" \
 352.333 +	 RANLIB=true
 352.334 +
 352.335 +do4:	# Apollo Domain/OS sr10.4
 352.336 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.337 +	 CRXTYPE=nfs \
 352.338 +	 BASECFLAGS="-A systype,bsd4.3 -D_APOLLO_SOURCE" \
 352.339 +	 RANLIB=true
 352.340 +
 352.341 +dyn:	# Dynix
 352.342 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.343 +	 CRXTYPE=nfs \
 352.344 +	 BASECFLAGS="-g -Dconst="
 352.345 +
 352.346 +epx:	# EP/IX
 352.347 +	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
 352.348 +	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
 352.349 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.350 +	 ACTIVEFILE=/usr/share/news/active \
 352.351 +	 RSHPATH=/usr/net/rsh \
 352.352 +	 BASECFLAGS="-g -systype svr4" \
 352.353 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.354 +	 RANLIB=true
 352.355 +
 352.356 +ga4:	# GCC AIX 4.1 for RS/6000
 352.357 +	$(BUILD) `$(CAT) SPECIALS` OS=a41 \
 352.358 +	 SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \
 352.359 +	 SPOOLDIR=/var/spool \
 352.360 +	 RSHPATH=/usr/bin/rsh \
 352.361 +	 BASECFLAGS="-g -Dunix=1 -D_BSD" \
 352.362 +	 BASELDFLAGS="-ls"
 352.363 +
 352.364 +gas:	# GCC Altos SVR4
 352.365 +	$(BUILD) `$(CAT) SPECIALS` OS=asv \
 352.366 +	 SIGTYPE=sv4 LOGINPW=old \
 352.367 +	 ACTIVEFILE=/usr/spool/news/active \
 352.368 +	 RSHPATH=/usr/bin/rcmd \
 352.369 +	 BASECFLAGS="-g -O -DALTOS_SYSTEM_V -DSIGSTOP=SIGKILL" \
 352.370 +	 BASELDFLAGS="-lsocket -lrpc -lgen -lcrypt -lxenix" \
 352.371 +	 RANLIB=true CC=gcc
 352.372 +
 352.373 +gh9:	# GCC HP-UX 9.x
 352.374 +	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
 352.375 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.376 +	 MAILSPOOL=/usr/mail \
 352.377 +	 RSHPATH=/usr/bin/remsh \
 352.378 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.379 +	 RANLIB=true CC=gcc
 352.380 +
 352.381 +ghp:	# GCC HP-UX 10.x
 352.382 +	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
 352.383 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.384 +	 SPOOLDIR=/var \
 352.385 +	 ACTIVEFILE=/var/news/active \
 352.386 +	 RSHPATH=/usr/bin/remsh \
 352.387 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.388 +	 RANLIB=true CC=gcc
 352.389 +
 352.390 +ghs:	# GCC HP-UX with Trusted Computer Base
 352.391 +	$(BUILD) `$(CAT) SPECIALS` OS=shp \
 352.392 +	 SIGTYPE=psx CHECKPW=sec CRXTYPE=nfs \
 352.393 +	 SPOOLDIR=/var \
 352.394 +	 ACTIVEFILE=/var/news/active \
 352.395 +	 RSHPATH=/usr/bin/remsh \
 352.396 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.397 +	 BASELDFLAGS="-lnet -lV3 -lsec" \
 352.398 +	 RANLIB=true CC=gcc
 352.399 +
 352.400 +go5:	# GCC 2.7.1 (95q4) SCO Open Server 5.0.x
 352.401 +	$(BUILD) `$(CAT) SPECIALS` OS=sc5 \
 352.402 +	 SIGTYPE=psx CHECKPW=sec LOGINPW=sec \
 352.403 +	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
 352.404 +	 SPOOLDIR=/var/spool \
 352.405 +	 ACTIVEFILE=/var/lib/news/active \
 352.406 +	 RSHPATH=/usr/bin/rcmd \
 352.407 +	 BASECFLAGS="$(GCCCFLAGS) -I/usr/include -L/lib" \
 352.408 +	 BASELDFLAGS="-lsocket -lprot -lx -ltinfo -lm" \
 352.409 +	 RANLIB=true CC=gcc
 352.410 +
 352.411 +gsc:	# Santa Cruz Operation
 352.412 +	$(BUILD) `$(CAT) SPECIALS` OS=sco \
 352.413 +	 SIGTYPE=sv4 CHECKPW=sec LOGINPW=sec \
 352.414 +	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
 352.415 +	 RSHPATH=/usr/bin/rcmd \
 352.416 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.417 +	 BASELDFLAGS="-lsocket -lprot -lcrypt_i -lx -los" \
 352.418 +	 RANLIB=true LN=ln CC=gcc
 352.419 +
 352.420 +gsg:	# GCC Silicon Graphics
 352.421 +	$(BUILD) `$(CAT) SPECIALS` OS=sgi \
 352.422 +	 SIGTYPE=sv4 CRXTYPE=nfs \
 352.423 +	 MAILSPOOL=/usr/mail \
 352.424 +	 RSHPATH=/usr/bsd/rsh \
 352.425 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.426 +	 RANLIB=true CC=gcc
 352.427 +
 352.428 +gso:	os_sol.h	# GCC Solaris
 352.429 +	$(BUILD) `$(CAT) SPECIALS` OS=sol \
 352.430 +	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
 352.431 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.432 +	 ACTIVEFILE=/usr/share/news/active \
 352.433 +	 RSHPATH=/usr/bin/rsh \
 352.434 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.435 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.436 +	 RANLIB=true CC=gcc
 352.437 +
 352.438 +gsu:	# GCC SUN-OS
 352.439 +	$(BUILD) `$(CAT) SPECIALS` OS=sun \
 352.440 +	 CRXTYPE=nfs \
 352.441 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.442 +	 BASELDFLAGS="-ldl" \
 352.443 +	 CC=gcc
 352.444 +
 352.445 +gul:	# GCC Ultrix
 352.446 +	$(BUILD) `$(CAT) SPECIALS` OS=ult \
 352.447 +	 SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \
 352.448 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.449 +	 BASELDFLAGS="-lauth -lc" \
 352.450 +	 CC=gcc
 352.451 +
 352.452 +h11:	# HP-UX 11i
 352.453 +	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
 352.454 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.455 +	 SPOOLDIR=/var \
 352.456 +	 ACTIVEFILE=/var/news/active \
 352.457 +	 RSHPATH=/usr/bin/remsh \
 352.458 +	 BASECFLAGS="-g -Ae" \
 352.459 +	 RANLIB=true
 352.460 +
 352.461 +hpp:	# HP-UX 9.x
 352.462 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.463 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.464 +	 MAILSPOOL=/usr/mail \
 352.465 +	 RSHPATH=/usr/bin/remsh \
 352.466 +	 BASECFLAGS="-g -Aa -D_HPUX_SOURCE" \
 352.467 +	 BASELDFLAGS="-lnet -lV3" \
 352.468 +	 RANLIB=true
 352.469 +
 352.470 +hpx:	# HP-UX 10.x
 352.471 +	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
 352.472 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.473 +	 SPOOLDIR=/var \
 352.474 +	 ACTIVEFILE=/var/news/active \
 352.475 +	 RSHPATH=/usr/bin/remsh \
 352.476 +	 BASECFLAGS="-g -Ae" \
 352.477 +	 BASELDFLAGS="-lnet -lV3" \
 352.478 +	 RANLIB=true
 352.479 +
 352.480 +isc:	# Interactive
 352.481 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.482 +	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
 352.483 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.484 +	 ACTIVEFILE=/var/spool/news/active \
 352.485 +	 BASECFLAGS="-Xp -D_SYSV3" \
 352.486 +	 BASELDFLAGS="-linet -lnsl_s -lgen -lx -lsec -liberty" \
 352.487 +	 RANLIB=true
 352.488 +
 352.489 +lnp:	# Linux Pluggable Authentication modules
 352.490 +	$(BUILD) `$(CAT) SPECIALS` OS=slx \
 352.491 +	 SIGTYPE=psx CHECKPW=pam CRXTYPE=nfs \
 352.492 +	 SPOOLDIR=/var/spool \
 352.493 +	 ACTIVEFILE=/var/lib/news/active \
 352.494 +	 RSHPATH=/usr/bin/rsh \
 352.495 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.496 +	 BASELDFLAGS="$(PAMLDFLAGS)"
 352.497 +
 352.498 +lnx:	# Linux non-shadow passwords
 352.499 +	@echo You are building for traditional Linux *without* shadow
 352.500 +	@echo passwords and with the crypt function in the C library.
 352.501 +	@echo If your system has shadow passwords, or if crypt is not
 352.502 +	@echo in the C library, you must use slx, sl4, or sl5 instead!
 352.503 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.504 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.505 +	 SPOOLDIR=/var/spool \
 352.506 +	 ACTIVEFILE=/var/lib/news/active \
 352.507 +	 RSHPATH=/usr/bin/rsh \
 352.508 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.509 +
 352.510 +lyn:	# LynxOS
 352.511 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.512 +	 CRXTYPE=nfs \
 352.513 +	 RSHPATH=/bin/rsh \
 352.514 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.515 +	 BASELDFLAGS=-lbsd \
 352.516 +	 CC=gcc
 352.517 +
 352.518 +mct:	# MachTen - CRXTYPE=nfs doesn't work (at least not on 2.2)
 352.519 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.520 +	 SPOOLDIR=/var/spool \
 352.521 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.522 +
 352.523 +mnt:	# Mint
 352.524 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.525 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.526 +	 SPOOLDIR=/var/spool \
 352.527 +	 ACTIVEFILE=/var/lib/news/active \
 352.528 +	 RSHPATH=/usr/bin/rsh \
 352.529 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.530 +
 352.531 +neb:	# NetBSD
 352.532 +	$(BUILD) `$(CAT) SPECIALS` OS=bsi \
 352.533 +	 CRXTYPE=nfs \
 352.534 +	 SPOOLDIR=/var \
 352.535 +	 ACTIVEFILE=/var/db/news/active \
 352.536 +	 RSHPATH=/usr/bin/rsh \
 352.537 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.538 +	 BASELDFLAGS="-lcrypt"
 352.539 +
 352.540 +nec:	# NEC UX
 352.541 +	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
 352.542 +	 SIGTYPE=sv4 CHECKPW=sv4 \
 352.543 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.544 +	 ACTIVEFILE=/var/news/lib/active \
 352.545 +	 RSHPATH=/usr/bin/rsh \
 352.546 +	 BASECFLAGS="-g -Kopt=2 -KOlimit=2000" \
 352.547 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.548 +	 RANLIB=true CC=/usr/abiccs/bin/cc
 352.549 +
 352.550 +nto:	# QNX Neutrino RTP
 352.551 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.552 +	 CRXTYPE=nfs \
 352.553 +	 SPOOLDIR=/var/spool \
 352.554 +	 ACTIVEFILE=/var/lib/news/active \
 352.555 +	 RSHPATH=/usr/bin/rsh \
 352.556 +	 BASECFLAGS="-g -O"
 352.557 +
 352.558 +nxt:	# NEXTSTEP
 352.559 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.560 +	 CRXTYPE=nfs \
 352.561 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.562 +
 352.563 +nx3:	# NEXTSTEP 3.0 single threaded
 352.564 +	$(BUILD) `$(CAT) SPECIALS` OS=nxt \
 352.565 +	 CRXTYPE=nfs \
 352.566 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.567 +	echo "void malloc_singlethreaded (void);" >> linkage.h
 352.568 +	echo "  malloc_singlethreaded ();" >> linkage.c
 352.569 +
 352.570 +osf:	# OSF/1
 352.571 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.572 +	 SIGTYPE=psx CRXTYPE=nfs \
 352.573 +	 SPOOLDIR=/var/spool \
 352.574 +	 BASECFLAGS="-g3 -w -O2 -Olimit 1500"
 352.575 +
 352.576 +# Note: sia_become_user() used by LOGINPW=os4 doesn't seem to work right.  The
 352.577 +# user doesn't get proper file access, and the process can't be killed.
 352.578 +
 352.579 +os4:	# OSF/1 (Digital UNIX) 4
 352.580 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.581 +	 SIGTYPE=psx CHECKPW=os4 LOGINPW=os4 CRXTYPE=nfs \
 352.582 +	 SPOOLDIR=/var/spool \
 352.583 +	 BASECFLAGS="-g3 -w -std0 -O2"
 352.584 +
 352.585 +osx:	# Mac OS X
 352.586 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.587 +	 CRXTYPE=nfs \
 352.588 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.589 +	 RSHPATH=/usr/bin/rsh \
 352.590 +	 BASECFLAGS="$(GCC4CFLAGS)"
 352.591 +
 352.592 +ptx:	# PTX
 352.593 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.594 +	 SIGTYPE=psx CHECKPW=svo LOGINPW=sv4 CRXTYPE=nfs \
 352.595 +	 MAILSPOOL=/usr/mail \
 352.596 +	 RSHPATH=/usr/bin/resh \
 352.597 +	 BASECFLAGS="-Wc,-O3 -Wc,-seq -Dprivate=PRIVATE" \
 352.598 +	 BASELDFLAGS="-lseq -lsec -lsocket -linet -lnsl -lgen" \
 352.599 +	 RANLIB=true
 352.600 +
 352.601 +pyr:	# Pyramid
 352.602 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.603 +	 CRXTYPE=nfs \
 352.604 +	 BASECFLAGS="-g -Dconst="
 352.605 +
 352.606 +qnx:	# QNX
 352.607 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.608 +	 CHECKPW=psx LOGINPW=old \
 352.609 +	 RSHPATH=/usr/ucb/rsh \
 352.610 +	 BASECFLAGS="-Otax -g -Dunix=1 -D_POSIX_SOURCE" \
 352.611 +	 BASELDFLAGS="-g -N128k -llogin -lsocket -lunix"
 352.612 +
 352.613 +s40:	# SUN-OS 4.0
 352.614 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.615 +	 CRXTYPE=nfs \
 352.616 +	 BASECFLAGS="-g -Dconst="
 352.617 +
 352.618 +sc5:	# SCO Open Server 5.0
 352.619 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.620 +	 SIGTYPE=psx CHECKPW=sec LOGINPW=sec \
 352.621 +	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
 352.622 +	 SPOOLDIR=/var/spool \
 352.623 +	 ACTIVEFILE=/var/lib/news/active \
 352.624 +	 RSHPATH=/usr/bin/rcmd \
 352.625 +	 BASECFLAGS="-O3 -s -belf" \
 352.626 +	 BASELDFLAGS="-lsocket -lprot -lx -ltinfo -lm" \
 352.627 +	 RANLIB=true
 352.628 +
 352.629 +sco:	# Santa Cruz Operation
 352.630 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.631 +	 SIGTYPE=sv4 CHECKPW=sec LOGINPW=sec \
 352.632 +	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
 352.633 +	 RSHPATH=/usr/bin/rcmd \
 352.634 +	 BASECFLAGS="-O3" \
 352.635 +	 BASELDFLAGS="-lsocket -lprot -lcrypt_i -lx -los" \
 352.636 +	 RANLIB=true LN=ln
 352.637 +
 352.638 +# Note: setting _POSIX_SOURCE doesn't seem to build it as of SGI IRIX 5.3
 352.639 +
 352.640 +sgi:	# Silicon Graphics
 352.641 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.642 +	 SIGTYPE=sv4 CRXTYPE=nfs \
 352.643 +	 MAILSPOOL=/usr/mail \
 352.644 +	 RSHPATH=/usr/bsd/rsh \
 352.645 +	 BASECFLAGS="-g3 -O2 -Olimit 8192" \
 352.646 +	 RANLIB=true
 352.647 +
 352.648 +sg6:	# Silicon Graphics, IRIX 6.5
 352.649 +	MAKEFLAGS= $(BUILD) `$(CAT) SPECIALS` OS=sgi \
 352.650 +	 SIGTYPE=sv4 CRXTYPE=nfs \
 352.651 +	 MAILSPOOL=/usr/mail \
 352.652 +	 RSHPATH=/usr/bsd/rsh \
 352.653 +	 BASECFLAGS="-g3 -O2 -OPT:Olimit=0 -woff 1110,1116" \
 352.654 +	 RANLIB=true
 352.655 +
 352.656 +# Note: Mark Kaesling says that setluid() isn't in HP-UX with SecureWare.
 352.657 +
 352.658 +shp:	# HP-UX with Trusted Computer Base
 352.659 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.660 +	 SIGTYPE=psx CHECKPW=sec CRXTYPE=nfs \
 352.661 +	 SPOOLDIR=/var \
 352.662 +	 ACTIVEFILE=/var/news/active \
 352.663 +	 RSHPATH=/usr/bin/remsh \
 352.664 +	 BASECFLAGS="-g -Ae" \
 352.665 +	 BASELDFLAGS="-lnet -lV3 -lsec" \
 352.666 +	 RANLIB=true
 352.667 +
 352.668 +slx:	# Secure Linux
 352.669 +	@echo You are building for libc6/glibc versions of Secure Linux
 352.670 +	@echo If you want libc5 versions you must use sl5 instead!
 352.671 +	@echo If you want libc4 versions you must use sl4 instead!
 352.672 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.673 +	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
 352.674 +	 SPOOLDIR=/var/spool \
 352.675 +	 ACTIVEFILE=/var/lib/news/active \
 352.676 +	 RSHPATH=/usr/bin/rsh \
 352.677 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.678 +	 BASELDFLAGS="-lcrypt"
 352.679 +
 352.680 +sl4:	# Secure Linux using libc4
 352.681 +	@echo You are building for libc4 versions of Secure Linux
 352.682 +	@echo If you want libc6/glibc versions you must use slx instead!
 352.683 +	@echo If you want libc5 versions you must use sl5 instead!
 352.684 +	$(BUILD) `$(CAT) SPECIALS` OS=slx \
 352.685 +	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
 352.686 +	 SPOOLDIR=/var/spool \
 352.687 +	 ACTIVEFILE=/var/lib/news/active \
 352.688 +	 RSHPATH=/usr/bin/rsh \
 352.689 +	 BASECFLAGS="$(GCCCFLAGS)" \
 352.690 +	 BASELDFLAGS="-lshadow"
 352.691 +
 352.692 +sl5:	# Secure Linux using libc5
 352.693 +	@echo You are building for libc5 versions of Secure Linux
 352.694 +	@echo If you want libc6/glibc versions you must use slx instead!
 352.695 +	@echo If you want libc4 versions you must use sl4 instead!
 352.696 +	$(BUILD) `$(CAT) SPECIALS` OS=slx \
 352.697 +	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
 352.698 +	 SPOOLDIR=/var/spool \
 352.699 +	 ACTIVEFILE=/var/lib/news/active \
 352.700 +	 RSHPATH=/usr/bin/rsh \
 352.701 +	 BASECFLAGS="$(GCCCFLAGS)"
 352.702 +
 352.703 +snx:	# Siemens Nixdorf SINIX and Reliant UNIX
 352.704 +	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
 352.705 +	 SIGTYPE=psx CHECKPW=sv4 \
 352.706 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.707 +	 ACTIVEFILE=/usr/share/news/active \
 352.708 +	 RSHPATH=/usr/bin/rsh \
 352.709 +	 BASECFLAGS="-g -D_SYS_CLOCK_H -Dconst=" \
 352.710 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.711 +	 RANLIB=true
 352.712 +
 352.713 +# Sorry about the -w, but the cretinous SUN Workshop Pro C compiler barfs on
 352.714 +# implicit casts between char and unsigned char.
 352.715 +
 352.716 +soc:	os_sol.h	# Solaris with cc
 352.717 +	$(BUILD) `$(CAT) SPECIALS` OS=sol \
 352.718 +	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
 352.719 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.720 +	 ACTIVEFILE=/usr/share/news/active \
 352.721 +	 RSHPATH=/usr/bin/rsh \
 352.722 +	 BASECFLAGS="-g -O -w" \
 352.723 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.724 +	 RANLIB=true CC=/opt/SUNWspro/bin/cc
 352.725 +
 352.726 +
 352.727 +# Note: It is a long and disgusting story about why cc is set to ucbcc.  You
 352.728 +# need to invoke the C compiler so that it links with the SVR4 libraries and
 352.729 +# not the BSD libraries, otherwise readdir() will return the wrong information.
 352.730 +# Of all the names in the most common path, ucbcc is the only name to be found
 352.731 +# (on /usr/ccs/bin) that points to a suitable compiler.  cc is likely to be
 352.732 +# /usr/ucb/cc which is absolutely not the compiler that you want.  The real
 352.733 +# SVR4 cc is probably something like /opt/SUNWspro/bin/cc which is rarely in
 352.734 +# anyone's path.
 352.735 +#
 352.736 +# ucbcc is probably a link to acc, e.g. /opt/SUNWspro/SC4.0/bin/acc, and is
 352.737 +# the UCB C compiler using the SVR4 libraries.
 352.738 +#
 352.739 +# If ucbcc isn't on your system, then punt on the SUN C compiler and use gcc
 352.740 +# instead (the gso port instead of the sol port).
 352.741 +# 
 352.742 +# If, in spite of all the above warnings, you choose to use the "soc" port
 352.743 +# instead of the "sol" port, be sure to check the behavior of the LIST command
 352.744 +# in imapd.  Also, note that the "soc" port uses -O.  If you want to use the
 352.745 +# real SVR4 compiler, you must use -O.  If it works to compile with -O2, then
 352.746 +# cc is probably using the UCB compiler with BSD libraries, and will not build
 352.747 +# a good binary
 352.748 +#
 352.749 +# To recap:
 352.750 +# 1) The sol port is designed to be built using the UCB compiler using the
 352.751 +#    SVR4 libraries.  This compiler is "ucbcc", which is lunk to acc.  You
 352.752 +#    use -O2 as one of the CFLAGS.
 352.753 +# 2) If you build the sol port with the UCB compiler using the BSD libraries,
 352.754 +#    you will get no error messages but you will get bad binaries (the most
 352.755 +#    obvious symptom is dropping the first two characters return filenames
 352.756 +#    from the imapd LIST command.  This compiler also uses -O2, and is very
 352.757 +#    often what the user gets from "cc".  BEWARE!!!
 352.758 +# 3) If you build the sol port with the real SVR4 compiler, which is often
 352.759 +#    hidden away or unavailable on many systems, then you will get errors
 352.760 +#    from -O2 and you need to change that to -O.  But you will get a good
 352.761 +#    binary.  However, you should try it with -O2 first, to make sure that
 352.762 +#    you got this compiler and not the UCB compiler using BSD libraries.
 352.763 +
 352.764 +sol:	os_sol.h	# Solaris
 352.765 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.766 +	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
 352.767 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.768 +	 ACTIVEFILE=/usr/share/news/active \
 352.769 +	 RSHPATH=/usr/bin/rsh \
 352.770 +	 BASECFLAGS="-g -O2" \
 352.771 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.772 +	 RANLIB=true CC=ucbcc
 352.773 +
 352.774 +sos:	# Secure OSF/1
 352.775 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.776 +	 SIGTYPE=psx CHECKPW=sce LOGINPW=sec CRXTYPE=nfs \
 352.777 +	 BASECFLAGS="-g3 -w -O2 -Olimit 1500" \
 352.778 +	 BASELDFLAGS="-lsecurity -laud"
 352.779 +
 352.780 +ssn:	# Secure SUN-OS
 352.781 +	$(BUILD) `$(CAT) SPECIALS` OS=sun \
 352.782 +	 CHECKPW=ssn CRXTYPE=nfs \
 352.783 +	 BASECFLAGS="-g -Dconst=" \
 352.784 +	 BASELDFLAGS="-ldl"
 352.785 +
 352.786 +sua:	# Windows Vista Subsystem for UNIX Applications
 352.787 +	$(BUILD) `$(CAT) SPECIALS` OS=sua \
 352.788 +	 SIGTYPE=psx CRXTYPE=nfs LOGINPW=old \
 352.789 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.790 +	 ACTIVEFILE=/var/lib/news/active \
 352.791 +	 RSHPATH=/usr/bin/rsh \
 352.792 +	 BASECFLAGS="-g -O2" \
 352.793 +	 BASELDFLAGS="-lcrypt"
 352.794 +
 352.795 +sun:	# SUN-OS
 352.796 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.797 +	 CRXTYPE=nfs \
 352.798 +	 BASECFLAGS="-g -Dconst=" \
 352.799 +	 BASELDFLAGS="-ldl"
 352.800 +
 352.801 +sv2:	# SVR2
 352.802 +	@echo You are being *very* optimistic!
 352.803 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.804 +	 SIGTYPE=sv4 LOGINPW=old \
 352.805 +	 MAILSPOOL=/usr/mail \
 352.806 +	 RSHPATH=/usr/bin/remsh \
 352.807 +	 BASECFLAGS="-Dconst= -DSYSTEM5 -DSHORT_IDENT -I/usr/ethernet/include" \
 352.808 +	 BASELDFLAGS="-lnet" \
 352.809 +	 RANLIB=true LN=ln
 352.810 +
 352.811 +sv4:	# SVR4
 352.812 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.813 +	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
 352.814 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.815 +	 ACTIVEFILE=/usr/share/news/active \
 352.816 +	 RSHPATH=/usr/bin/resh \
 352.817 +	 BASECFLAGS="-g -Dconst=" \
 352.818 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.819 +	 RANLIB=true
 352.820 +
 352.821 +ult:	# Ultrix
 352.822 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.823 +	 SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \
 352.824 +	 BASECFLAGS="-g3 -O2 -Olimit 1500 -Dconst=" \
 352.825 +	 BASELDFLAGS="-lauth -lc"
 352.826 +
 352.827 +uw2:	# UnixWare SVR4.2
 352.828 +	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
 352.829 +	 SIGTYPE=sv4 CHECKPW=sv4 \
 352.830 +	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
 352.831 +	 ACTIVEFILE=/var/news/lib/active \
 352.832 +	 RSHPATH=/usr/bin/rsh \
 352.833 +	 BASECFLAGS="-g" \
 352.834 +	 BASELDFLAGS="-lsocket -lnsl -lgen" \
 352.835 +	 RANLIB=true
 352.836 +
 352.837 +vul:	# VAX Ultrix
 352.838 +	$(BUILD) `$(CAT) SPECIALS` OS=ult \
 352.839 +	 SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \
 352.840 +	 BASECFLAGS="-O2 -Dconst=" \
 352.841 +	 BASELDFLAGS="-lauth -lc"
 352.842 +
 352.843 +vu2:	# VAX Ultrix 2.3, etc.
 352.844 +	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
 352.845 +	 CRXTYPE=nfs \
 352.846 +	 BASECFLAGS="-O2 -Dconst= -Dvoid=char"
 352.847 +
 352.848 +
 352.849 +# Build it!
 352.850 +
 352.851 +build:	clean once $(ARCHIVE)
 352.852 +
 352.853 +all:	$(ARCHIVE)
 352.854 +
 352.855 +$(ARCHIVE): $(BINARIES)
 352.856 +	sh -c '$(RM) $(ARCHIVE) || true'
 352.857 +	@$(CAT) ARCHIVE
 352.858 +	@$(SH) ARCHIVE
 352.859 +
 352.860 +.c.o:
 352.861 +	`$(CAT) CCTYPE` -c `$(CAT) CFLAGS` $*.c
 352.862 +
 352.863 +
 352.864 +# Cleanup
 352.865 +
 352.866 +clean:
 352.867 +	sh -c '$(RM) auths.c crexcl.c ip_unix.c linkage.[ch] siglocal.c osdep*.[ch] *.o ARCHIVE *FLAGS *TYPE $(ARCHIVE) || true'
 352.868 +
 352.869 +
 352.870 +# Dependencies
 352.871 +
 352.872 +dummy.o: mail.h misc.h osdep.h dummy.h
 352.873 +fdstring.o: mail.h misc.h osdep.h fdstring.h
 352.874 +flstring.o: mail.h misc.h osdep.h flstring.h
 352.875 +imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h
 352.876 +mail.o: mail.h misc.h osdep.h rfc822.h linkage.h
 352.877 +mbx.o: mail.h misc.h osdep.h dummy.h
 352.878 +mh.o: mail.h misc.h osdep.h dummy.h
 352.879 +mix.o: mail.h misc.h osdep.h dummy.h
 352.880 +mx.o: mail.h misc.h osdep.h dummy.h
 352.881 +misc.o: mail.h misc.h osdep.h
 352.882 +mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h
 352.883 +mtx.o: mail.h misc.h osdep.h dummy.h
 352.884 +netmsg.o: mail.h misc.h osdep.h netmsg.h
 352.885 +news.o: mail.h misc.h osdep.h
 352.886 +newsrc.o: mail.h misc.h osdep.h newsrc.h
 352.887 +nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h
 352.888 +phile.o: mail.h misc.h osdep.h rfc822.h dummy.h
 352.889 +pseudo.o: pseudo.h
 352.890 +pop3.o: mail.h misc.h osdep.h rfc822.h
 352.891 +smanager.o: mail.h misc.h osdep.h
 352.892 +smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h
 352.893 +rfc822.o: mail.h misc.h osdep.h rfc822.h
 352.894 +tenex.o: mail.h misc.h osdep.h dummy.h
 352.895 +unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
 352.896 +utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c
 352.897 +utf8aux.o: mail.h misc.h osdep.h utf8.h
 352.898 +
 352.899 +
 352.900 +# OS-dependent
 352.901 +
 352.902 +osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \
 352.903 +	osdep.h env_unix.h tcp_unix.h \
 352.904 +	osdep.c env_unix.c fs_unix.c ftl_unix.c nl_unix.c tcp_unix.c ip_unix.c\
 352.905 +	auths.c crexcl.c flockcyg.c flocklnx.c flocksim.c fsync.c \
 352.906 +	gethstid.c getspnam.c \
 352.907 +	gr_wait.c gr_wait4.c gr_waitp.c \
 352.908 +	kerb_mit.c \
 352.909 +	auth_ext.c auth_gss.c auth_log.c auth_md5.c auth_pla.c \
 352.910 +	pmatch.c scandir.c setpgrp.c strerror.c truncate.c write.c \
 352.911 +	memmove.c memmove2.c memset.c \
 352.912 +	tz_bsd.c tz_nul.c tz_sv4.c \
 352.913 +	write.c sslstdio.c \
 352.914 +	strerror.c strpbrk.c strstr.c strtok.c strtoul.c \
 352.915 +	OSCFLAGS
 352.916 +	@echo Building OS-dependent module
 352.917 +	@echo If you get No such file error messages for files x509.h, ssl.h,
 352.918 +	@echo pem.h, buffer.h, bio.h, and crypto.h, that means that OpenSSL
 352.919 +	@echo is not installed on your system.  Either install OpenSSL first
 352.920 +	@echo or build with command: make `$(CAT) OSTYPE` SSLTYPE=none
 352.921 +	`$(CAT) CCTYPE` -c `$(CAT) CFLAGS` `$(CAT) OSCFLAGS` -c osdep.c
 352.922 +
 352.923 +osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c
 352.924 +	$(CAT) osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c
 352.925 +
 352.926 +osdepbas.c:
 352.927 +	@echo osdepbas.c not found...try make clean and new make
 352.928 +	@false
 352.929 +
 352.930 +osdepckp.c:
 352.931 +	@echo osdepckp.c not found...try make clean and new make
 352.932 +	@false
 352.933 +
 352.934 +osdeplog.c:
 352.935 +	@echo osdeplog.c not found...try make clean and new make
 352.936 +	@false
 352.937 +
 352.938 +osdepssl.c:
 352.939 +	@echo osdepssl.c not found...try make clean and new make
 352.940 +	@false
 352.941 +
 352.942 +siglocal.c:
 352.943 +	@echo siglocal.c not found...try make clean and new make
 352.944 +	@false
 352.945 +
 352.946 +crexcl.c:
 352.947 +	@echo crexcl.c not found...do make clean and new make
 352.948 +	@false
 352.949 +
 352.950 +ip_unix.c:
 352.951 +	@echo ip_unix.c not found...do make clean and new make
 352.952 +	@false
 352.953 +
 352.954 +os_sol.h:
 352.955 +	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'
 352.956 +
 352.957 +
 352.958 +# Once-only environment setup
 352.959 +
 352.960 +once:	onceenv ckp$(PASSWDTYPE) ssl$(SSLTYPE) osdep.c
 352.961 +
 352.962 +onceenv:
 352.963 +	@echo Once-only environment setup...
 352.964 +	echo $(CC) > CCTYPE
 352.965 +	echo $(BASECFLAGS) '$(EXTRACFLAGS)' -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS
 352.966 +	echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \
 352.967 +	 -DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \
 352.968 +	 -DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" \
 352.969 +	 -DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \
 352.970 +	 -DRSHPATH=\"$(RSHPATH)\" -DLOCKPGM=\"$(LOCKPGM)\" \
 352.971 +	 -DLOCKPGM1=\"$(LOCKPGM1)\" -DLOCKPGM2=\"$(LOCKPGM2)\" \
 352.972 +	 -DLOCKPGM3=\"$(LOCKPGM3)\" > OSCFLAGS
 352.973 +	echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS
 352.974 +	echo "$(ARRC) $(ARCHIVE) $(BINARIES);$(RANLIB) $(ARCHIVE)" > ARCHIVE
 352.975 +	echo $(OS) > OSTYPE
 352.976 +	./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy
 352.977 +	./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
 352.978 +	echo "  mail_versioncheck (CCLIENTVERSION);" >> linkage.c
 352.979 +	$(LN) os_$(OS).h osdep.h
 352.980 +	$(LN) os_$(OS).c osdepbas.c
 352.981 +	$(LN) log_$(LOGINPW).c osdeplog.c
 352.982 +	$(LN) sig_$(SIGTYPE).c siglocal.c
 352.983 +	$(LN) crx_$(CRXTYPE).c crexcl.c
 352.984 +	$(LN) ip$(IP)_unix.c ip_unix.c
 352.985 +	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'
 352.986 +
 352.987 +
 352.988 +# Password checkers
 352.989 +
 352.990 +ckpafs:	# AFS
 352.991 +	@echo AFS password authentication
 352.992 +	echo $(AFSCFLAGS) >> OSCFLAGS
 352.993 +#	echo $(AFSLDFLAGS) >> LDFLAGS
 352.994 +# Note: Steve Roseman says that AFS libraries have to be lunk before SSL
 352.995 +	echo $(AFSLDFLAGS) `$(CAT) LDFLAGS` > LDFLAGS.tmp
 352.996 +	mv LDFLAGS.tmp LDFLAGS
 352.997 +	$(LN) ckp_afs.c osdepckp.c
 352.998 +
 352.999 +ckpdce:	# DCE
352.1000 +	@echo DCE password authentication
352.1001 +	echo $(DCECFLAGS) >> OSCFLAGS
352.1002 +	echo $(DCELDFLAGS) >> LDFLAGS
352.1003 +	$(LN) ckp_dce.c osdepckp.c
352.1004 +
352.1005 +ckpgss:	# Kerberos V (must have gss EXTRAAUTHENTICATOR as well)
352.1006 +	@echo Kerberos V password authentication
352.1007 +	$(LN) ckp_gss.c osdepckp.c
352.1008 +
352.1009 +ckpnul:	# NUL authenticator (disables all plaintext authentication)
352.1010 +	@echo Plaintext authentication prohibited
352.1011 +	echo "  mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 1);" >> linkage.c
352.1012 +	$(LN) ckp_nul.c osdepckp.c
352.1013 +
352.1014 +ckppam:	# Pluggable Authentication Modules authenticator
352.1015 +	@echo PAM password authentication
352.1016 +	echo $(PAMLDFLAGS) >> LDFLAGS
352.1017 +	$(LN) ckp_pam.c osdepckp.c
352.1018 +
352.1019 +ckppmb:	# Broken (e.g. SUN) Pluggable Authentication Modules authenticator
352.1020 +	@echo Broken PAM password authentication
352.1021 +	echo $(PAMLDFLAGS) >> LDFLAGS
352.1022 +	$(LN) ckp_pmb.c osdepckp.c
352.1023 +
352.1024 +ckpstd:	# Port standard
352.1025 +	@echo Standard password authentication
352.1026 +	$(LN) ckp_$(CHECKPW).c osdepckp.c
352.1027 +
352.1028 +ckptwo:	# Something plus standard
352.1029 +	@echo $(CHECKPWALT) password authentication first, then standard
352.1030 +	$(CAT) ckp_1st.c ckp_$(CHECKPWALT).c ckp_2nd.c ckp_$(CHECKPW).c \
352.1031 +	 ckp_3rd.c > osdepckp.c
352.1032 +
352.1033 +
352.1034 +# SSL support
352.1035 +
352.1036 +sslnone:# No SSL
352.1037 +	@echo Building without SSL support
352.1038 +	$(LN) ssl_none.c osdepssl.c
352.1039 +
352.1040 +sslnopwd: sslunix snopwd
352.1041 +
352.1042 +sslunix.nopwd: sslnopwd
352.1043 +
352.1044 +sslsco.nopwd: sslsco snopwd
352.1045 +
352.1046 +sslunix: sbasic sldunix
352.1047 +
352.1048 +sslsco:	sbasic sldsco
352.1049 +
352.1050 +sbasic:	# UNIX OpenSSL
352.1051 +	@echo Building with SSL
352.1052 +	$(LN) ssl_unix.c osdepssl.c
352.1053 +	echo $(SSLCFLAGS) >> OSCFLAGS
352.1054 +	echo "  ssl_onceonlyinit ();" >> linkage.c
352.1055 +
352.1056 +snopwd:	# Plaintext disable
352.1057 +	@echo Building with SSL and plaintext passwords disabled unless SSL/TLS
352.1058 +	echo "  mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 2);" >> linkage.c
352.1059 +
352.1060 +sldunix:# Normal UNIX SSL load flags
352.1061 +	echo $(SSLLDFLAGS) >> LDFLAGS
352.1062 +
352.1063 +
352.1064 +sldsco:	# SCO SSL load flags
352.1065 +# Note: Tim Rice says that SSL has to be lunk before other libraries on SCO.
352.1066 +	echo $(SSLLDFLAGS) `cat LDFLAGS` > LDFLAGS.tmp
352.1067 +	mv LDFLAGS.tmp LDFLAGS
352.1068 +
352.1069 +
352.1070 +# A monument to a hack of long ago and far away...
352.1071 +
352.1072 +love:
352.1073 +	@echo not war?
   353.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   353.2 +++ b/src/osdep/unix/Makefile.gss	Mon Sep 14 15:17:45 2009 +0900
   353.3 @@ -0,0 +1,39 @@
   353.4 +# ========================================================================
   353.5 +# Copyright 1988-2007 University of Washington
   353.6 +#
   353.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   353.8 +# you may not use this file except in compliance with the License.
   353.9 +# You may obtain a copy of the License at
  353.10 +#
  353.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  353.12 +#
  353.13 +# 
  353.14 +# ========================================================================
  353.15 +
  353.16 +# Program:	GSSAPI makefile
  353.17 +#
  353.18 +# Author:	Mark Crispin
  353.19 +#		Networks and Distributed Computing
  353.20 +#		Computing & Communications
  353.21 +#		University of Washington
  353.22 +#		Administration Building, AG-44
  353.23 +#		Seattle, WA  98195
  353.24 +#		Internet: MRC@CAC.Washington.EDU
  353.25 +#
  353.26 +# Date:		11 May 1989
  353.27 +# Last Edited:	4 April 2007
  353.28 +
  353.29 +
  353.30 +# Extended flags needed for additional authenticators.  You may need to modify.
  353.31 +
  353.32 +GSSDIR=/usr/local
  353.33 +GSSINCLUDE=$(GSSDIR)/include
  353.34 +GSSLIB=$(GSSDIR)/lib
  353.35 +GSSCFLAGS= -I$(GSSINCLUDE) -DGSS_C_NT_HOSTBASED_SERVICE=gss_nt_service_name -DKRB5_DEPRECATED=1
  353.36 +GSSOLDLDFLAGS= -L$(GSSLIB) -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err
  353.37 +GSSNEWLDFLAGS= -L$(GSSLIB) -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err
  353.38 +
  353.39 +gss:	# GSSAPI Kerberos V flags
  353.40 +	echo $(GSSCFLAGS) >> OSCFLAGS
  353.41 +	sh -c '(test -f $(GSSLIB)/libk5crypto.a) && echo $(GSSNEWLDFLAGS) || echo $(GSSOLDLDFLAGS)' >> LDFLAGS
  353.42 +	echo "#include \"kerb_mit.c\"" >> auths.c
   354.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   354.2 +++ b/src/osdep/unix/ckp_1st.c	Mon Sep 14 15:17:45 2009 +0900
   354.3 @@ -0,0 +1,53 @@
   354.4 +/* ========================================================================
   354.5 + * Copyright 1988-2006 University of Washington
   354.6 + *
   354.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   354.8 + * you may not use this file except in compliance with the License.
   354.9 + * You may obtain a copy of the License at
  354.10 + *
  354.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  354.12 + *
  354.13 + * 
  354.14 + * ========================================================================
  354.15 + */
  354.16 +
  354.17 +/*
  354.18 + * Program:	Dual check password part 1
  354.19 + *
  354.20 + * Author:	Mark Crispin
  354.21 + *		Networks and Distributed Computing
  354.22 + *		Computing & Communications
  354.23 + *		University of Washington
  354.24 + *		Administration Building, AG-44
  354.25 + *		Seattle, WA  98195
  354.26 + *		Internet: MRC@CAC.Washington.EDU
  354.27 + *
  354.28 + * Date:	1 August 1988
  354.29 + * Last Edited:	30 August 2006
  354.30 + */
  354.31 +
  354.32 +struct passwd *checkpw_alt(struct passwd *pw,char *pass,int argc,char *argv[]);
  354.33 +struct passwd *checkpw_std(struct passwd *pw,char *pass,int argc,char *argv[]);
  354.34 +
  354.35 +/* Check password
  354.36 + * Accepts: login passwd struct
  354.37 + *	    password string
  354.38 + *	    argument count
  354.39 + *	    argument vector
  354.40 + * Returns: passwd struct if password validated, NIL otherwise
  354.41 + */
  354.42 +
  354.43 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  354.44 +{
  354.45 +  struct passwd *ret;
  354.46 +				/* in case first checker smashes it */
  354.47 +  char *user = cpystr (pw->pw_name);
  354.48 +  if (!(ret = checkpw_alt (pw,pass,argc,argv)))
  354.49 +    ret = checkpw_std (getpwnam (user),pass,argc,argv);
  354.50 +  fs_give ((void **) &user);
  354.51 +  return ret;
  354.52 +}
  354.53 +
  354.54 +/* Redefine alt checker's routine name */
  354.55 +
  354.56 +#define checkpw checkpw_alt
   355.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   355.2 +++ b/src/osdep/unix/ckp_2nd.c	Mon Sep 14 15:17:45 2009 +0900
   355.3 @@ -0,0 +1,36 @@
   355.4 +/* ========================================================================
   355.5 + * Copyright 1988-2006 University of Washington
   355.6 + *
   355.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   355.8 + * you may not use this file except in compliance with the License.
   355.9 + * You may obtain a copy of the License at
  355.10 + *
  355.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  355.12 + *
  355.13 + * 
  355.14 + * ========================================================================
  355.15 + */
  355.16 +
  355.17 +/*
  355.18 + * Program:	Dual check password part 2
  355.19 + *
  355.20 + * Author:	Mark Crispin
  355.21 + *		Networks and Distributed Computing
  355.22 + *		Computing & Communications
  355.23 + *		University of Washington
  355.24 + *		Administration Building, AG-44
  355.25 + *		Seattle, WA  98195
  355.26 + *		Internet: MRC@CAC.Washington.EDU
  355.27 + *
  355.28 + * Date:	1 August 1988
  355.29 + * Last Edited:	30 August 2006
  355.30 + */
  355.31 +
  355.32 +
  355.33 +/* Undefine routine name */
  355.34 +
  355.35 +#undef checkpw
  355.36 +
  355.37 +/* Redefine std checker's routine name */
  355.38 +
  355.39 +#define checkpw checkpw_std
   356.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   356.2 +++ b/src/osdep/unix/ckp_3rd.c	Mon Sep 14 15:17:45 2009 +0900
   356.3 @@ -0,0 +1,32 @@
   356.4 +/* ========================================================================
   356.5 + * Copyright 1988-2006 University of Washington
   356.6 + *
   356.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   356.8 + * you may not use this file except in compliance with the License.
   356.9 + * You may obtain a copy of the License at
  356.10 + *
  356.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  356.12 + *
  356.13 + * 
  356.14 + * ========================================================================
  356.15 + */
  356.16 +
  356.17 +/*
  356.18 + * Program:	Dual check password part 3
  356.19 + *
  356.20 + * Author:	Mark Crispin
  356.21 + *		Networks and Distributed Computing
  356.22 + *		Computing & Communications
  356.23 + *		University of Washington
  356.24 + *		Administration Building, AG-44
  356.25 + *		Seattle, WA  98195
  356.26 + *		Internet: MRC@CAC.Washington.EDU
  356.27 + *
  356.28 + * Date:	1 August 1988
  356.29 + * Last Edited:	30 August 2006
  356.30 + */
  356.31 +
  356.32 +
  356.33 +/* Undefine routine name */
  356.34 +
  356.35 +#undef checkpw
   357.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   357.2 +++ b/src/osdep/unix/ckp_a41.c	Mon Sep 14 15:17:45 2009 +0900
   357.3 @@ -0,0 +1,52 @@
   357.4 +/* ========================================================================
   357.5 + * Copyright 1988-2006 University of Washington
   357.6 + *
   357.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   357.8 + * you may not use this file except in compliance with the License.
   357.9 + * You may obtain a copy of the License at
  357.10 + *
  357.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  357.12 + *
  357.13 + * 
  357.14 + * ========================================================================
  357.15 + */
  357.16 +
  357.17 +/*
  357.18 + * Program:	AIX 4.1 check password
  357.19 + *
  357.20 + * Author:	Mark Crispin
  357.21 + *		Networks and Distributed Computing
  357.22 + *		Computing & Communications
  357.23 + *		University of Washington
  357.24 + *		Administration Building, AG-44
  357.25 + *		Seattle, WA  98195
  357.26 + *		Internet: MRC@CAC.Washington.EDU
  357.27 + *
  357.28 + * Date:	1 August 1988	
  357.29 + * Last Edited:	30 August 2006
  357.30 + */
  357.31 + 
  357.32 +#include <login.h>
  357.33 +
  357.34 +/* Check password
  357.35 + * Accepts: login passwd struct
  357.36 + *	    password string
  357.37 + *	    argument count
  357.38 + *	    argument vector
  357.39 + * Returns: passwd struct if password validated, NIL otherwise
  357.40 + */
  357.41 +
  357.42 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  357.43 +{
  357.44 +  int reenter = 0;
  357.45 +  char *msg = NIL;
  357.46 +  char *user = cpystr (pw->pw_name);
  357.47 +				/* validate password */
  357.48 +  struct passwd *ret = (pw && !loginrestrictions (user,S_RLOGIN,NIL,&msg) &&
  357.49 +			!authenticate (user,pass,&reenter,&msg)) ?
  357.50 +			  getpwnam (user) : NIL;
  357.51 +				/* clean up any message returned */
  357.52 +  if (msg) fs_give ((void **) &msg);
  357.53 +  if (user) fs_give ((void **) &user);
  357.54 +  return ret;
  357.55 +}
   358.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   358.2 +++ b/src/osdep/unix/ckp_afs.c	Mon Sep 14 15:17:45 2009 +0900
   358.3 @@ -0,0 +1,71 @@
   358.4 +/* ========================================================================
   358.5 + * Copyright 1988-2006 University of Washington
   358.6 + *
   358.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   358.8 + * you may not use this file except in compliance with the License.
   358.9 + * You may obtain a copy of the License at
  358.10 + *
  358.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  358.12 + *
  358.13 + * 
  358.14 + * ========================================================================
  358.15 + */
  358.16 +
  358.17 +/*
  358.18 + * Program:	AFS check password
  358.19 + *
  358.20 + * Author:	Mark Crispin
  358.21 + *		Networks and Distributed Computing
  358.22 + *		Computing & Communications
  358.23 + *		University of Washington
  358.24 + *		Administration Building, AG-44
  358.25 + *		Seattle, WA  98195
  358.26 + *		Internet: MRC@CAC.Washington.EDU
  358.27 + *
  358.28 + * Date:	1 August 1988
  358.29 + * Last Edited:	30 August 2006
  358.30 + */
  358.31 +
  358.32 +/* AFS cleanup
  358.33 + * Accepts: data
  358.34 + */
  358.35 +
  358.36 +void checkpw_cleanup (void *data)
  358.37 +{
  358.38 +  ktc_ForgetAllTokens ();
  358.39 +}
  358.40 +
  358.41 +
  358.42 +/* Check password
  358.43 + * Accepts: login passwd struct
  358.44 + *	    password string
  358.45 + *	    argument count
  358.46 + *	    argument vector
  358.47 + * Returns: passwd struct if password validated, NIL otherwise
  358.48 + */
  358.49 +
  358.50 +#undef INIT
  358.51 +#define min AFS_MIN
  358.52 +#define max AFS_MAX
  358.53 +#include <afs/param.h>
  358.54 +#include <afs/kautils.h>
  358.55 +
  358.56 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  358.57 +{
  358.58 +  char *reason;
  358.59 +				/* faster validation for POP servers */
  358.60 +  if (!strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),"pop")) {
  358.61 +    struct ktc_encryptionKey key;
  358.62 +    struct ktc_token token;
  358.63 +				/* just check the password */
  358.64 +    ka_StringToKey (pass,NIL,&key);
  358.65 +    if (ka_GetAdminToken (pw->pw_name,"","",&key,600,&token,1)) return NIL;
  358.66 +  }
  358.67 +				/* check password and get AFS token */
  358.68 +  else if (ka_UserAuthenticateGeneral
  358.69 +	   (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,pw->pw_name,NIL,NIL,
  358.70 +	    pass,0,0,0,&reason)) return NIL;
  358.71 +				/* arm hook to delete credentials */
  358.72 +  mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
  358.73 +  return pw;
  358.74 +}
   359.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   359.2 +++ b/src/osdep/unix/ckp_bsi.c	Mon Sep 14 15:17:45 2009 +0900
   359.3 @@ -0,0 +1,50 @@
   359.4 +/* ========================================================================
   359.5 + * Copyright 1988-2006 University of Washington
   359.6 + *
   359.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   359.8 + * you may not use this file except in compliance with the License.
   359.9 + * You may obtain a copy of the License at
  359.10 + *
  359.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  359.12 + *
  359.13 + * 
  359.14 + * ========================================================================
  359.15 + */
  359.16 +
  359.17 +/*
  359.18 + * Program:	BSI check password
  359.19 + *
  359.20 + * Author:	Mark Crispin
  359.21 + *		Networks and Distributed Computing
  359.22 + *		Computing & Communications
  359.23 + *		University of Washington
  359.24 + *		Administration Building, AG-44
  359.25 + *		Seattle, WA  98195
  359.26 + *		Internet: MRC@CAC.Washington.EDU
  359.27 + *
  359.28 + * Date:	1 August 1988
  359.29 + * Last Edited:	30 August 2006
  359.30 + */
  359.31 +
  359.32 +/* Check password
  359.33 + * Accepts: login passwd struct
  359.34 + *	    password string
  359.35 + *	    argument count
  359.36 + *	    argument vector
  359.37 + * Returns: passwd struct if password validated, NIL otherwise
  359.38 + */
  359.39 +
  359.40 +#include <login_cap.h>
  359.41 +
  359.42 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  359.43 +{
  359.44 +  char *s,tmp[MAILTMPLEN];
  359.45 +  login_cap_t *lc;
  359.46 +				/* make service name */
  359.47 +  sprintf (tmp,"auth-%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL));
  359.48 +				/* validate password */
  359.49 +  return ((lc = login_getclass (pw->pw_class)) &&
  359.50 +	  (s = login_getstyle (lc,NIL,tmp)) &&
  359.51 +	  (auth_response (pw->pw_name,lc->lc_class,s,"response",NIL,"",pass)
  359.52 +	   > 0)) ? pw : NIL;
  359.53 +}
   360.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   360.2 +++ b/src/osdep/unix/ckp_cyg.c	Mon Sep 14 15:17:45 2009 +0900
   360.3 @@ -0,0 +1,63 @@
   360.4 +/* ========================================================================
   360.5 + * Copyright 1988-2006 University of Washington
   360.6 + *
   360.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   360.8 + * you may not use this file except in compliance with the License.
   360.9 + * You may obtain a copy of the License at
  360.10 + *
  360.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  360.12 + *
  360.13 + * 
  360.14 + * ========================================================================
  360.15 + */
  360.16 +
  360.17 +/*
  360.18 + * Program:	Cygwin check password
  360.19 + *
  360.20 + * Author:	Mark Crispin
  360.21 + *		Networks and Distributed Computing
  360.22 + *		Computing & Communications
  360.23 + *		University of Washington
  360.24 + *		Administration Building, AG-44
  360.25 + *		Seattle, WA  98195
  360.26 + *		Internet: MRC@CAC.Washington.EDU
  360.27 + *
  360.28 + * Date:	1 August 1988
  360.29 + * Last Edited:	30 August 2006
  360.30 + */
  360.31 +
  360.32 +/* This module is against my better judgement.  If you want to run an imapd
  360.33 + * or ipop[23]d you should use the native NT or W2K ports intead of this
  360.34 + * Cygwin port.  There is no surety that this module works right or will work
  360.35 + * right in the future.
  360.36 + */
  360.37 +
  360.38 +#undef ERROR
  360.39 +#include <windows.h>
  360.40 +#include <sys/cygwin.h>
  360.41 +
  360.42 +
  360.43 +/* Check password
  360.44 + * Accepts: login passwd struct
  360.45 + *	    password string
  360.46 + *	    argument count
  360.47 + *	    argument vector
  360.48 + * Returns: passwd struct if password validated, NIL otherwise
  360.49 + */
  360.50 +
  360.51 +static char *cyg_user = NIL;
  360.52 +static HANDLE cyg_hdl = NIL;
  360.53 +
  360.54 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  360.55 +{
  360.56 +				/* flush last pw-checked user */
  360.57 +  if (cyg_user) fs_give ((void **) &cyg_user);
  360.58 +				/* forbid if UID 0 or SYSTEM uid */
  360.59 +  if (!pw->pw_uid || (pw->pw_uid == SYSTEMUID) ||
  360.60 +      ((cyg_hdl = cygwin_logon_user (pw,pass)) == INVALID_HANDLE_VALUE))
  360.61 +    return NIL;			/* bad UID or password */
  360.62 +				/* remember user for this handle */
  360.63 +  cyg_user = cpystr (pw->pw_name);
  360.64 +  return pw;
  360.65 +}
  360.66 +
   361.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   361.2 +++ b/src/osdep/unix/ckp_dce.c	Mon Sep 14 15:17:45 2009 +0900
   361.3 @@ -0,0 +1,83 @@
   361.4 +/* ========================================================================
   361.5 + * Copyright 1988-2006 University of Washington
   361.6 + *
   361.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   361.8 + * you may not use this file except in compliance with the License.
   361.9 + * You may obtain a copy of the License at
  361.10 + *
  361.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  361.12 + *
  361.13 + * 
  361.14 + * ========================================================================
  361.15 + */
  361.16 +
  361.17 +/*
  361.18 + * Program:	DCE check password
  361.19 + *
  361.20 + * Author:	Mark Crispin
  361.21 + *		Networks and Distributed Computing
  361.22 + *		Computing & Communications
  361.23 + *		University of Washington
  361.24 + *		Administration Building, AG-44
  361.25 + *		Seattle, WA  98195
  361.26 + *		Internet: MRC@CAC.Washington.EDU
  361.27 + *
  361.28 + * Date:	1 August 1988
  361.29 + * Last Edited:	30 August 2006
  361.30 + */
  361.31 +
  361.32 +/* Check password
  361.33 + * Accepts: login passwd struct
  361.34 + *	    password string
  361.35 + *	    argument count
  361.36 + *	    argument vector
  361.37 + * Returns: passwd struct if password validated, NIL otherwise
  361.38 + */
  361.39 +
  361.40 +#include <dce/rpc.h>
  361.41 +#include <dce/sec_login.h>
  361.42 +
  361.43 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  361.44 +{
  361.45 +  sec_passwd_rec_t pwr;
  361.46 +  sec_login_handle_t lhdl;
  361.47 +  boolean32 rstpwd;
  361.48 +  sec_login_auth_src_t asrc;
  361.49 +  error_status_t status;
  361.50 +  FILE *fd;
  361.51 +				/* easy case */
  361.52 +  if (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  361.53 +      !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) return pw;
  361.54 +				/* try DCE password cache file */
  361.55 +  if (fd = fopen (PASSWD_OVERRIDE,"r")) {
  361.56 +    char *usr = cpystr (pw->pw_name);
  361.57 +    while ((pw = fgetpwent (fd)) && strcmp (usr,pw->pw_name));
  361.58 +    fclose (fd);		/* finished with cache file */
  361.59 +				/* validate cached password */
  361.60 +    if (pw && pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  361.61 +	!strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
  361.62 +      fs_give ((void **) &usr);
  361.63 +      return pw;
  361.64 +    }
  361.65 +    if (!pw) pw = getpwnam (usr);
  361.66 +    fs_give ((void **) &usr);
  361.67 +  }
  361.68 +  if (pw) {			/* try S-L-O-W DCE... */
  361.69 +    sec_login_setup_identity ((unsigned_char_p_t) pw->pw_name,
  361.70 +			      sec_login_no_flags,&lhdl,&status);
  361.71 +    if (status == error_status_ok) {
  361.72 +      pwr.key.tagged_union.plain = (idl_char *) pass;
  361.73 +      pwr.key.key_type = sec_passwd_plain;
  361.74 +      pwr.pepper = NIL;
  361.75 +      pwr.version_number = sec_passwd_c_version_none;
  361.76 +				/* validate password with login context */
  361.77 +      sec_login_validate_identity (lhdl,&pwr,&rstpwd,&asrc,&status);
  361.78 +      if (!rstpwd && (asrc == sec_login_auth_src_network) &&
  361.79 +	  (status == error_status_ok)) {
  361.80 +	sec_login_purge_context (&lhdl,&status);
  361.81 +	if (status == error_status_ok) return pw;
  361.82 +      }
  361.83 +    }
  361.84 +  }
  361.85 +  return NIL;			/* password validation failed */
  361.86 +}
   362.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   362.2 +++ b/src/osdep/unix/ckp_gss.c	Mon Sep 14 15:17:45 2009 +0900
   362.3 @@ -0,0 +1,90 @@
   362.4 +/* ========================================================================
   362.5 + * Copyright 1988-2007 University of Washington
   362.6 + *
   362.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   362.8 + * you may not use this file except in compliance with the License.
   362.9 + * You may obtain a copy of the License at
  362.10 + *
  362.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  362.12 + *
  362.13 + * 
  362.14 + * ========================================================================
  362.15 + */
  362.16 +
  362.17 +/*
  362.18 + * Program:	Kerberos 5 check password
  362.19 + *
  362.20 + * Author:	Mark Crispin
  362.21 + *		Networks and Distributed Computing
  362.22 + *		Computing & Communications
  362.23 + *		University of Washington
  362.24 + *		Administration Building, AG-44
  362.25 + *		Seattle, WA  98195
  362.26 + *		Internet: MRC@CAC.Washington.EDU
  362.27 + *
  362.28 + * Date:	1 August 1988
  362.29 + * Last Edited:	11 October 2007
  362.30 + */
  362.31 +
  362.32 +/* Check password
  362.33 + * Accepts: login passwd struct
  362.34 + *	    password string
  362.35 + *	    argument count
  362.36 + *	    argument vector
  362.37 + * Returns: passwd struct if password validated, NIL otherwise
  362.38 + */
  362.39 +
  362.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  362.41 +{
  362.42 +  char svrnam[MAILTMPLEN],cltnam[MAILTMPLEN];
  362.43 +  krb5_context ctx;
  362.44 +  krb5_timestamp now;
  362.45 +  krb5_principal service;
  362.46 +  krb5_ccache ccache;
  362.47 +  krb5_error_code code;
  362.48 +  krb5_creds *crd = (krb5_creds *) memset (fs_get (sizeof (krb5_creds)),0,
  362.49 +						   sizeof (krb5_creds));
  362.50 +  struct passwd *ret = NIL;
  362.51 +  if (*pass) {			/* only if password non-empty */
  362.52 +				/* make service name */
  362.53 +    sprintf (svrnam,"%.80s@%.512s",
  362.54 +	     (char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
  362.55 +	     tcp_serverhost ());
  362.56 +				/* make client name with principal */
  362.57 +    sprintf (cltnam,"%.80s/%.80s",pw->pw_name,
  362.58 +	     (char *) mail_parameters (NIL,GET_SERVICENAME,NIL));
  362.59 +				/* get a context */
  362.60 +    if (!krb5_init_context (&ctx)) {
  362.61 +				/* get time, client and server principals */
  362.62 +      if (!krb5_timeofday (ctx,&now) &&
  362.63 +	/* Normally, kerb_cp_svr_name (defined/set in env_unix.c) is NIL, so
  362.64 +	 * only the user name is used as a client principal.  A few sites want
  362.65 +	 * to have separate client principals for different services, but many
  362.66 +	 * other sites vehemently object...
  362.67 +	 */
  362.68 +	  !krb5_parse_name (ctx,kerb_cp_svr_name ? cltnam : pw->pw_name,
  362.69 +			    &crd->client) &&
  362.70 +	  !krb5_parse_name (ctx,svrnam,&service) &&
  362.71 +	  !krb5_build_principal_ext(ctx,&crd->server,
  362.72 +				    krb5_princ_realm (ctx,crd->client)->length,
  362.73 +				    krb5_princ_realm (ctx,crd->client)->data,
  362.74 +				    KRB5_TGS_NAME_SIZE,KRB5_TGS_NAME,
  362.75 +				    krb5_princ_realm (ctx,crd->client)->length,
  362.76 +				    krb5_princ_realm (ctx,crd->client)->data,
  362.77 +				    0)) {
  362.78 +				/* expire in 3 minutes */
  362.79 +	crd->times.endtime = now + (3 * 60);
  362.80 +	if (krb5_cc_resolve (ctx,"MEMORY:pwk",&ccache) ||
  362.81 +	    krb5_cc_initialize (ctx,ccache,crd->client)) ccache = 0;
  362.82 +	if (!krb5_get_in_tkt_with_password (ctx,NIL,NIL,NIL,NIL,pass,ccache,
  362.83 +					    crd,0) &&
  362.84 +	    !krb5_verify_init_creds (ctx,crd,service,0,ccache ? &ccache : 0,0))
  362.85 +	  ret = pw;
  362.86 +	krb5_free_creds (ctx,crd);/* flush creds and service principal */
  362.87 +	krb5_free_principal (ctx,service);
  362.88 +      }
  362.89 +      krb5_free_context (ctx);	/* don't need context any more */
  362.90 +    }
  362.91 +  }
  362.92 +  return ret;
  362.93 +}
   363.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   363.2 +++ b/src/osdep/unix/ckp_nul.c	Mon Sep 14 15:17:45 2009 +0900
   363.3 @@ -0,0 +1,40 @@
   363.4 +/* ========================================================================
   363.5 + * Copyright 1988-2006 University of Washington
   363.6 + *
   363.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   363.8 + * you may not use this file except in compliance with the License.
   363.9 + * You may obtain a copy of the License at
  363.10 + *
  363.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  363.12 + *
  363.13 + * 
  363.14 + * ========================================================================
  363.15 + */
  363.16 +
  363.17 +/*
  363.18 + * Program:	Null check password
  363.19 + *
  363.20 + * Author:	Mark Crispin
  363.21 + *		Networks and Distributed Computing
  363.22 + *		Computing & Communications
  363.23 + *		University of Washington
  363.24 + *		Administration Building, AG-44
  363.25 + *		Seattle, WA  98195
  363.26 + *		Internet: MRC@CAC.Washington.EDU
  363.27 + *
  363.28 + * Date:	23 July 1998
  363.29 + * Last Edited:	30 August 2006
  363.30 + */
  363.31 +
  363.32 +/* Check password
  363.33 + * Accepts: login passwd struct
  363.34 + *	    password string
  363.35 + *	    argument count
  363.36 + *	    argument vector
  363.37 + * Returns: passwd struct if password validated, NIL otherwise
  363.38 + */
  363.39 +
  363.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  363.41 +{
  363.42 +  return NIL;			/* always fails */
  363.43 +}
   364.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   364.2 +++ b/src/osdep/unix/ckp_os4.c	Mon Sep 14 15:17:45 2009 +0900
   364.3 @@ -0,0 +1,78 @@
   364.4 +/* ========================================================================
   364.5 + * Copyright 1988-2006 University of Washington
   364.6 + *
   364.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   364.8 + * you may not use this file except in compliance with the License.
   364.9 + * You may obtain a copy of the License at
  364.10 + *
  364.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  364.12 + *
  364.13 + * 
  364.14 + * ========================================================================
  364.15 + */
  364.16 +
  364.17 +/*
  364.18 + * Program:	OSF/1 (Digital UNIX) 4 check password
  364.19 + *
  364.20 + * Author:	Mark Crispin
  364.21 + *		Networks and Distributed Computing
  364.22 + *		Computing & Communications
  364.23 + *		University of Washington
  364.24 + *		Administration Building, AG-44
  364.25 + *		Seattle, WA  98195
  364.26 + *		Internet: MRC@CAC.Washington.EDU
  364.27 + *
  364.28 + * Date:	1 August 1988
  364.29 + * Last Edited:	30 August 2006
  364.30 + */
  364.31 +
  364.32 +/* Dummy collection routine
  364.33 + * Accepts: how long to wait for user
  364.34 + *	    how to run parameter collection
  364.35 + *	    title
  364.36 + *	    number of prompts
  364.37 + *	    prompts
  364.38 + * Returns: collection status
  364.39 + *
  364.40 + * Because Spider Boardman, who wrote SIA, says that it's needed for buggy SIA
  364.41 + * mechanisms, that's why.
  364.42 + */
  364.43 +
  364.44 +static int checkpw_collect (int timeout,int rendition,uchar_t *title,
  364.45 +			    int nprompts,prompt_t *prompts)
  364.46 +{
  364.47 +  switch (rendition) {
  364.48 +  case SIAONELINER: case SIAINFO: case SIAWARNING: return SIACOLSUCCESS;
  364.49 +  }
  364.50 +  return SIACOLABORT;		/* another else is bogus */
  364.51 +}
  364.52 +
  364.53 +
  364.54 +/* Check password
  364.55 + * Accepts: login passwd struct
  364.56 + *	    password string
  364.57 + *	    argument count
  364.58 + *	    argument vector
  364.59 + * Returns: passwd struct if password validated, NIL otherwise
  364.60 + */
  364.61 +
  364.62 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  364.63 +{
  364.64 +  int i;
  364.65 +  char *s;
  364.66 +  char *name = cpystr (pw->pw_name);
  364.67 +  char *host = cpystr (tcp_clienthost ());
  364.68 +  struct passwd *ret = NIL;
  364.69 +				/* tie off address */
  364.70 +  if (s = strchr (host,' ')) *s = '\0';
  364.71 +  if (*host == '[') {		/* convert [a.b.c.d] to a.b.c.d */
  364.72 +    memmove (host,host+1,i = strlen (host + 2));
  364.73 +    host[i] = '\0';
  364.74 +  }
  364.75 +				/* validate password */
  364.76 +  if (sia_validate_user (checkpw_collect,argc,argv,host,name,NIL,NIL,NIL,pass)
  364.77 +      == SIASUCCESS) ret = getpwnam (name);
  364.78 +  fs_give ((void **) &name);
  364.79 +  fs_give ((void **) &host);
  364.80 +  return ret;
  364.81 +}
   365.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   365.2 +++ b/src/osdep/unix/ckp_pam.c	Mon Sep 14 15:17:45 2009 +0900
   365.3 @@ -0,0 +1,136 @@
   365.4 +/* ========================================================================
   365.5 + * Copyright 1988-2006 University of Washington
   365.6 + *
   365.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   365.8 + * you may not use this file except in compliance with the License.
   365.9 + * You may obtain a copy of the License at
  365.10 + *
  365.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  365.12 + *
  365.13 + * 
  365.14 + * ========================================================================
  365.15 + */
  365.16 +
  365.17 +/*
  365.18 + * Program:	Pluggable Authentication Modules login services
  365.19 + *
  365.20 + * Author:	Mark Crispin
  365.21 + *		Networks and Distributed Computing
  365.22 + *		Computing & Communications
  365.23 + *		University of Washington
  365.24 + *		Administration Building, AG-44
  365.25 + *		Seattle, WA  98195
  365.26 + *		Internet: MRC@CAC.Washington.EDU
  365.27 + *
  365.28 + * Date:	1 August 1988
  365.29 + * Last Edited:	31 August 2006
  365.30 + */
  365.31 +
  365.32 +
  365.33 +#ifdef MAC_OSX_KLUDGE		/* why can't Apple be compatible? */
  365.34 +#include <pam/pam_appl.h>
  365.35 +#else
  365.36 +#include <security/pam_appl.h>
  365.37 +#endif
  365.38 +
  365.39 +struct checkpw_cred {
  365.40 +  char *uname;			/* user name */
  365.41 +  char *pass;			/* password */
  365.42 +};
  365.43 +
  365.44 +/* PAM conversation function
  365.45 + * Accepts: number of messages
  365.46 + *	    vector of messages
  365.47 + *	    pointer to response return
  365.48 + *	    application data
  365.49 + * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR
  365.50 + */
  365.51 +
  365.52 +static int checkpw_conv (int num_msg,const struct pam_message **msg,
  365.53 +			 struct pam_response **resp,void *appdata_ptr)
  365.54 +{
  365.55 +  int i;
  365.56 +  struct checkpw_cred *cred = (struct checkpw_cred *) appdata_ptr;
  365.57 +  struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg);
  365.58 +  for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) {
  365.59 +  case PAM_PROMPT_ECHO_ON:	/* assume want user name */
  365.60 +    reply[i].resp_retcode = PAM_SUCCESS;
  365.61 +    reply[i].resp = cpystr (cred->uname);
  365.62 +    break;
  365.63 +  case PAM_PROMPT_ECHO_OFF:	/* assume want password */
  365.64 +    reply[i].resp_retcode = PAM_SUCCESS;
  365.65 +    reply[i].resp = cpystr (cred->pass);
  365.66 +    break;
  365.67 +  case PAM_TEXT_INFO:
  365.68 +  case PAM_ERROR_MSG:
  365.69 +    reply[i].resp_retcode = PAM_SUCCESS;
  365.70 +    reply[i].resp = NULL;
  365.71 +    break;
  365.72 +  default:			/* unknown message style */
  365.73 +    fs_give ((void **) &reply);
  365.74 +    return PAM_CONV_ERR;
  365.75 +  }
  365.76 +  *resp = reply;
  365.77 +  return PAM_SUCCESS;
  365.78 +}
  365.79 +
  365.80 +
  365.81 +/* PAM cleanup
  365.82 + * Accepts: handle
  365.83 + */
  365.84 +
  365.85 +static void checkpw_cleanup (pam_handle_t *hdl)
  365.86 +{
  365.87 +#if 0	/* see checkpw() for why this is #if 0 */
  365.88 +  pam_close_session (hdl,NIL);	/* close session [uw]tmp */
  365.89 +#endif
  365.90 +  pam_setcred (hdl,PAM_DELETE_CRED);
  365.91 +  pam_end (hdl,PAM_SUCCESS);
  365.92 +}
  365.93 +
  365.94 +/* Server log in
  365.95 + * Accepts: user name string
  365.96 + *	    password string
  365.97 + * Returns: T if password validated, NIL otherwise
  365.98 + */
  365.99 +
 365.100 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
 365.101 +{
 365.102 +  pam_handle_t *hdl;
 365.103 +  struct pam_conv conv;
 365.104 +  struct checkpw_cred cred;
 365.105 +  char *name = cpystr (pw->pw_name);
 365.106 +  conv.conv = &checkpw_conv;
 365.107 +  conv.appdata_ptr = &cred;
 365.108 +  cred.uname = name;
 365.109 +  cred.pass = pass;
 365.110 +  if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
 365.111 +			pw->pw_name,&conv,&hdl) == PAM_SUCCESS) &&
 365.112 +	    (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) &&
 365.113 +	    (pam_authenticate (hdl,NIL) == PAM_SUCCESS) &&
 365.114 +	    (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) &&
 365.115 +	    (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ?
 365.116 +      getpwnam (name) : NIL) {
 365.117 +#if 0
 365.118 +    /*
 365.119 +     * Some people have reported that this causes a SEGV in strncpy() from
 365.120 +     * pam_unix.so.1
 365.121 +     */
 365.122 +    /*
 365.123 +     * This pam_open_session() call is inconsistant with how we handle other
 365.124 +     * platforms, where we don't write [uw]tmp records.  However, unlike our
 365.125 +     * code on other platforms, pam_acct_mgmt() will check those records for
 365.126 +     * inactivity and deny the authentication.
 365.127 +     */
 365.128 +    pam_open_session (hdl,NIL);	/* make sure account doesn't go inactive */
 365.129 +#endif
 365.130 +				/* arm hook to delete credentials */
 365.131 +    mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
 365.132 +    mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl);
 365.133 +  }
 365.134 +  else checkpw_cleanup (hdl);	/* clean up */
 365.135 +  fs_give ((void **) &name);
 365.136 +				/* reset log facility in case PAM broke it */
 365.137 +  if (myServerName) openlog (myServerName,LOG_PID,syslog_facility);
 365.138 +  return pw;
 365.139 +}
   366.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   366.2 +++ b/src/osdep/unix/ckp_pmb.c	Mon Sep 14 15:17:45 2009 +0900
   366.3 @@ -0,0 +1,128 @@
   366.4 +/* ========================================================================
   366.5 + * Copyright 1988-2006 University of Washington
   366.6 + *
   366.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   366.8 + * you may not use this file except in compliance with the License.
   366.9 + * You may obtain a copy of the License at
  366.10 + *
  366.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  366.12 + *
  366.13 + * 
  366.14 + * ========================================================================
  366.15 + */
  366.16 +
  366.17 +/*
  366.18 + * Program:	Pluggable Authentication Modules login services, buggy systems
  366.19 + *		(use this instead of ckp_pam.c on Solaris)
  366.20 + *
  366.21 + * Author:	Mark Crispin
  366.22 + *		Networks and Distributed Computing
  366.23 + *		Computing & Communications
  366.24 + *		University of Washington
  366.25 + *		Administration Building, AG-44
  366.26 + *		Seattle, WA  98195
  366.27 + *		Internet: MRC@CAC.Washington.EDU
  366.28 + *
  366.29 + * Date:	1 August 1988
  366.30 + * Last Edited:	31 August 2006
  366.31 + */
  366.32 +
  366.33 +
  366.34 +#include <security/pam_appl.h>
  366.35 +
  366.36 +static char *pam_uname;		/* user name */
  366.37 +static char *pam_pass;		/* password */
  366.38 +
  366.39 +/* PAM conversation function
  366.40 + * Accepts: number of messages
  366.41 + *	    vector of messages
  366.42 + *	    pointer to response return
  366.43 + *	    application data
  366.44 + * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR
  366.45 + */
  366.46 +
  366.47 +static int checkpw_conv (int num_msg,const struct pam_message **msg,
  366.48 +			 struct pam_response **resp,void *appdata_ptr)
  366.49 +{
  366.50 +  int i;
  366.51 +  struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg);
  366.52 +  for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) {
  366.53 +  case PAM_PROMPT_ECHO_ON:	/* assume want user name */
  366.54 +    reply[i].resp_retcode = PAM_SUCCESS;
  366.55 +    reply[i].resp = cpystr (pam_uname);
  366.56 +    break;
  366.57 +  case PAM_PROMPT_ECHO_OFF:	/* assume want password */
  366.58 +    reply[i].resp_retcode = PAM_SUCCESS;
  366.59 +    reply[i].resp = cpystr (pam_pass);
  366.60 +    break;
  366.61 +  case PAM_TEXT_INFO:
  366.62 +  case PAM_ERROR_MSG:
  366.63 +    reply[i].resp_retcode = PAM_SUCCESS;
  366.64 +    reply[i].resp = NULL;
  366.65 +    break;
  366.66 +  default:			/* unknown message style */
  366.67 +    fs_give ((void **) &reply);
  366.68 +    return PAM_CONV_ERR;
  366.69 +  }
  366.70 +  *resp = reply;
  366.71 +  return PAM_SUCCESS;
  366.72 +}
  366.73 +
  366.74 +
  366.75 +/* PAM cleanup
  366.76 + * Accepts: handle
  366.77 + */
  366.78 +
  366.79 +static void checkpw_cleanup (pam_handle_t *hdl)
  366.80 +{
  366.81 +#if 0	/* see checkpw() for why this is #if 0 */
  366.82 +  pam_close_session (hdl,NIL);	/* close session [uw]tmp */
  366.83 +#endif
  366.84 +  pam_setcred (hdl,PAM_DELETE_CRED);
  366.85 +  pam_end (hdl,PAM_SUCCESS);
  366.86 +}
  366.87 +
  366.88 +/* Server log in
  366.89 + * Accepts: user name string
  366.90 + *	    password string
  366.91 + * Returns: T if password validated, NIL otherwise
  366.92 + */
  366.93 +
  366.94 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  366.95 +{
  366.96 +  pam_handle_t *hdl;
  366.97 +  struct pam_conv conv;
  366.98 +  char *name = cpystr (pw->pw_name);
  366.99 +  conv.conv = &checkpw_conv;
 366.100 +  pam_uname = pw->pw_name;
 366.101 +  pam_pass = pass;
 366.102 +  if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
 366.103 +			pw->pw_name,&conv,&hdl) == PAM_SUCCESS) &&
 366.104 +	    (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) &&
 366.105 +	    (pam_authenticate (hdl,NIL) == PAM_SUCCESS) &&
 366.106 +	    (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) &&
 366.107 +	    (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ?
 366.108 +      getpwnam (name) : NIL) {
 366.109 +#if 0
 366.110 +    /*
 366.111 +     * Some people have reported that this causes a SEGV in strncpy() from
 366.112 +     * pam_unix.so.1
 366.113 +     */
 366.114 +    /*
 366.115 +     * This pam_open_session() call is inconsistant with how we handle other
 366.116 +     * platforms, where we don't write [uw]tmp records.  However, unlike our
 366.117 +     * code on other platforms, pam_acct_mgmt() will check those records for
 366.118 +     * inactivity and deny the authentication.
 366.119 +     */
 366.120 +    pam_open_session (hdl,NIL);	/* make sure account doesn't go inactive */
 366.121 +#endif
 366.122 +				/* arm hook to delete credentials */
 366.123 +    mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
 366.124 +    mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl);
 366.125 +  }
 366.126 +  else checkpw_cleanup (hdl);	/* clean up */
 366.127 +  fs_give ((void **) &name);
 366.128 +				/* reset log facility in case PAM broke it */
 366.129 +  if (myServerName) openlog (myServerName,LOG_PID,syslog_facility);
 366.130 +  return pw;
 366.131 +}
   367.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   367.2 +++ b/src/osdep/unix/ckp_psx.c	Mon Sep 14 15:17:45 2009 +0900
   367.3 @@ -0,0 +1,101 @@
   367.4 +/* ========================================================================
   367.5 + * Copyright 1988-2006 University of Washington
   367.6 + *
   367.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   367.8 + * you may not use this file except in compliance with the License.
   367.9 + * You may obtain a copy of the License at
  367.10 + *
  367.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  367.12 + *
  367.13 + * 
  367.14 + * ========================================================================
  367.15 + */
  367.16 +
  367.17 +/*
  367.18 + * Program:	POSIX check password
  367.19 + *
  367.20 + * Author:	Mark Crispin
  367.21 + *		Networks and Distributed Computing
  367.22 + *		Computing & Communications
  367.23 + *		University of Washington
  367.24 + *		Administration Building, AG-44
  367.25 + *		Seattle, WA  98195
  367.26 + *		Internet: MRC@CAC.Washington.EDU
  367.27 + *
  367.28 + * Date:	1 August 1988
  367.29 + * Last Edited:	30 August 2006
  367.30 + */
  367.31 +
  367.32 +/* Check password
  367.33 + * Accepts: login passwd struct
  367.34 + *	    password string
  367.35 + *	    argument count
  367.36 + *	    argument vector
  367.37 + * Returns: passwd struct if password validated, NIL otherwise
  367.38 + */
  367.39 +
  367.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  367.41 +{
  367.42 +  char tmp[MAILTMPLEN];
  367.43 +  struct spwd *sp = NIL;
  367.44 +  time_t left;
  367.45 +  time_t now = time (0);
  367.46 +  struct tm *t = gmtime (&now);
  367.47 +  int zone = t->tm_hour * 60 + t->tm_min;
  367.48 +  int julian = t->tm_yday;
  367.49 +  t = localtime (&now);		/* get local time now */
  367.50 +				/* minus UTC minutes since midnight */
  367.51 +  zone = t->tm_hour * 60 + t->tm_min - zone;
  367.52 +  /* julian can be one of:
  367.53 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
  367.54 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
  367.55 +   *    0  local time is same day as UTC, no offset
  367.56 +   *   -1  local time is 1 day behind UTC, offset -24 hours
  367.57 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
  367.58 +   */
  367.59 +  if (julian = t->tm_yday -julian)
  367.60 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
  367.61 +				/* days since 1/1/1970 local time */
  367.62 +  now = ((now /60) + zone) / (60*24);
  367.63 +				/* non-shadow authentication */
  367.64 +  if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] ||
  367.65 +      strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
  367.66 +    /* As far as I've been able to determine, here is how the expiration
  367.67 +     * fields in the shadow authentication data work:
  367.68 +     *  lstchg	last password change date if non-negative.  If zero, the
  367.69 +     *		user can not log in without changing password.
  367.70 +     *  max	number of days a password is valid if positive
  367.71 +     *  warn	number of days of password expiration warning
  367.72 +     *  expire	date account expires if positive
  367.73 +     *  inact	number of days an accout can be inactive (not checked!)
  367.74 +     * The expiration day is the *last* day that the password or account
  367.75 +     * is valid.
  367.76 +     */
  367.77 +				/* shadow authentication */
  367.78 +    if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg &&
  367.79 +	((sp->sp_lstchg < 0) || (sp->sp_max <= 0) ||
  367.80 +	 ((sp->sp_lstchg + sp->sp_max) >= now)) &&
  367.81 +	((sp->sp_expire <= 0) || (sp->sp_expire >= now)) &&
  367.82 +	sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] &&
  367.83 +	!strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) {
  367.84 +      if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
  367.85 +	  ((left = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)) {
  367.86 +	if (left) {
  367.87 +	  sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left);
  367.88 +	  mm_notify (NIL,tmp,NIL);
  367.89 +	}
  367.90 +	else mm_notify (NIL,"[ALERT] Password expires today!",WARN);
  367.91 +      }
  367.92 +      if ((sp->sp_expire > 0) && ((left = sp->sp_expire - now) < 28)) {
  367.93 +	if (left) {
  367.94 +	  sprintf (tmp,"[ALERT] Account expires in %ld day(s)",(long) left);
  367.95 +	  mm_notify (NIL,tmp,NIL);
  367.96 +	}
  367.97 +	else mm_notify (NIL,"[ALERT] Account expires today!",WARN);
  367.98 +      }
  367.99 +      endspent ();		/* don't need shadow password data any more */
 367.100 +    }
 367.101 +    else pw = NIL;		/* password failed */
 367.102 +  }
 367.103 +  return pw;
 367.104 +}
   368.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   368.2 +++ b/src/osdep/unix/ckp_sce.c	Mon Sep 14 15:17:45 2009 +0900
   368.3 @@ -0,0 +1,51 @@
   368.4 +/* ========================================================================
   368.5 + * Copyright 1988-2006 University of Washington
   368.6 + *
   368.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   368.8 + * you may not use this file except in compliance with the License.
   368.9 + * You may obtain a copy of the License at
  368.10 + *
  368.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  368.12 + *
  368.13 + * 
  368.14 + * ========================================================================
  368.15 + */
  368.16 +
  368.17 +/*
  368.18 + * Program:	SecureWare check password
  368.19 + *
  368.20 + * Author:	Mark Crispin
  368.21 + *		Networks and Distributed Computing
  368.22 + *		Computing & Communications
  368.23 + *		University of Washington
  368.24 + *		Administration Building, AG-44
  368.25 + *		Seattle, WA  98195
  368.26 + *		Internet: MRC@CAC.Washington.EDU
  368.27 + *
  368.28 + * Date:	1 August 1988
  368.29 + * Last Edited:	30 August 2006
  368.30 + */
  368.31 +
  368.32 +/* Check password
  368.33 + * Accepts: login passwd struct
  368.34 + *	    password string
  368.35 + *	    argument count
  368.36 + *	    argument vector
  368.37 + * Returns: passwd struct if password validated, NIL otherwise
  368.38 + */
  368.39 +
  368.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  368.41 +{
  368.42 +  struct es_passwd *pp;
  368.43 +  set_auth_parameters (argc,argv);
  368.44 +  if ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  368.45 +       !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ||
  368.46 +      ((pp = getespwnam (pw->pw_name)) && !pp->ufld->fd_lock &&
  368.47 +       !pp->ufld->fd_psw_chg_reqd &&
  368.48 +       pp->ufld->fd_encrypt && pp->ufld->fd_encrypt[0] &&
  368.49 +       pp->ufld->fd_encrypt[1] &&
  368.50 +       !strcmp (pp->ufld->fd_encrypt,bigcrypt (pass,pp->ufld->fd_encrypt))))
  368.51 +    endprpwent ();		/* don't need shadow password data any more */
  368.52 +  else pw = NIL;		/* password failed */
  368.53 +  return pw;
  368.54 +}
   369.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   369.2 +++ b/src/osdep/unix/ckp_sec.c	Mon Sep 14 15:17:45 2009 +0900
   369.3 @@ -0,0 +1,50 @@
   369.4 +/* ========================================================================
   369.5 + * Copyright 1988-2006 University of Washington
   369.6 + *
   369.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   369.8 + * you may not use this file except in compliance with the License.
   369.9 + * You may obtain a copy of the License at
  369.10 + *
  369.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  369.12 + *
  369.13 + * 
  369.14 + * ========================================================================
  369.15 + */
  369.16 +
  369.17 +/*
  369.18 + * Program:	SecureWare check password
  369.19 + *
  369.20 + * Author:	Mark Crispin
  369.21 + *		Networks and Distributed Computing
  369.22 + *		Computing & Communications
  369.23 + *		University of Washington
  369.24 + *		Administration Building, AG-44
  369.25 + *		Seattle, WA  98195
  369.26 + *		Internet: MRC@CAC.Washington.EDU
  369.27 + *
  369.28 + * Date:	1 August 1988
  369.29 + * Last Edited:	30 August 2006
  369.30 + */
  369.31 +
  369.32 +/* Check password
  369.33 + * Accepts: login passwd struct
  369.34 + *	    password string
  369.35 + *	    argument count
  369.36 + *	    argument vector
  369.37 + * Returns: passwd struct if password validated, NIL otherwise
  369.38 + */
  369.39 +
  369.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  369.41 +{
  369.42 +  struct pr_passwd *pp;
  369.43 +  set_auth_parameters (argc,argv);
  369.44 +  if ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  369.45 +       !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ||
  369.46 +      ((pp = getprpwnam (pw->pw_name)) && !pp->ufld.fd_lock &&
  369.47 +       pp->ufld.fd_encrypt && pp->ufld.fd_encrypt[0] &&
  369.48 +       pp->ufld.fd_encrypt[1] &&
  369.49 +       !strcmp (pp->ufld.fd_encrypt,bigcrypt (pass,pp->ufld.fd_encrypt))))
  369.50 +    endprpwent ();		/* don't need shadow password data any more */
  369.51 +  else pw = NIL;		/* password failed */
  369.52 +  return pw;
  369.53 +}
   370.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   370.2 +++ b/src/osdep/unix/ckp_ssn.c	Mon Sep 14 15:17:45 2009 +0900
   370.3 @@ -0,0 +1,56 @@
   370.4 +/* ========================================================================
   370.5 + * Copyright 1988-2006 University of Washington
   370.6 + *
   370.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   370.8 + * you may not use this file except in compliance with the License.
   370.9 + * You may obtain a copy of the License at
  370.10 + *
  370.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  370.12 + *
  370.13 + * 
  370.14 + * ========================================================================
  370.15 + */
  370.16 +
  370.17 +/*
  370.18 + * Program:	Secure SUN-OS check password
  370.19 + *
  370.20 + * Author:	Mark Crispin
  370.21 + *		Networks and Distributed Computing
  370.22 + *		Computing & Communications
  370.23 + *		University of Washington
  370.24 + *		Administration Building, AG-44
  370.25 + *		Seattle, WA  98195
  370.26 + *		Internet: MRC@CAC.Washington.EDU
  370.27 + *
  370.28 + * Date:	1 August 1988
  370.29 + * Last Edited:	30 August 2006
  370.30 + */
  370.31 +
  370.32 +#include <sys/label.h>
  370.33 +#include <sys/audit.h>
  370.34 +#include <pwdadj.h>
  370.35 +
  370.36 +
  370.37 +/* Check password
  370.38 + * Accepts: login passwd struct
  370.39 + *	    password string
  370.40 + *	    argument count
  370.41 + *	    argument vector
  370.42 + * Returns: passwd struct if password validated, NIL otherwise
  370.43 + */
  370.44 +
  370.45 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  370.46 +{
  370.47 +  struct passwd_adjunct *pa;
  370.48 +  char *user = cpystr (pw->pw_name);
  370.49 +				/* validate user and password */
  370.50 +  struct passwd *ret =
  370.51 +    ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  370.52 +      !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ||
  370.53 +     ((pa = getpwanam (pw->pw_name)) &&
  370.54 +      pa->pwa_passwd && pa->pwa_passwd[0] && pa->pwa_passwd[1] &&
  370.55 +      !strcmp (pa->pwa_passwd,(char *) crypt (pass,pa->pwa_passwd)))) ?
  370.56 +	getpwnam (user) : NIL;
  370.57 +  if (user) fs_give ((void **) &user);
  370.58 +  return ret;
  370.59 +}
   371.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   371.2 +++ b/src/osdep/unix/ckp_std.c	Mon Sep 14 15:17:45 2009 +0900
   371.3 @@ -0,0 +1,42 @@
   371.4 +/* ========================================================================
   371.5 + * Copyright 1988-2006 University of Washington
   371.6 + *
   371.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   371.8 + * you may not use this file except in compliance with the License.
   371.9 + * You may obtain a copy of the License at
  371.10 + *
  371.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  371.12 + *
  371.13 + * 
  371.14 + * ========================================================================
  371.15 + */
  371.16 +
  371.17 +/*
  371.18 + * Program:	Standard check password
  371.19 + *
  371.20 + * Author:	Mark Crispin
  371.21 + *		Networks and Distributed Computing
  371.22 + *		Computing & Communications
  371.23 + *		University of Washington
  371.24 + *		Administration Building, AG-44
  371.25 + *		Seattle, WA  98195
  371.26 + *		Internet: MRC@CAC.Washington.EDU
  371.27 + *
  371.28 + * Date:	1 August 1988
  371.29 + * Last Edited:	30 August 2006
  371.30 + */
  371.31 +
  371.32 +/* Check password
  371.33 + * Accepts: login passwd struct
  371.34 + *	    password string
  371.35 + *	    argument count
  371.36 + *	    argument vector
  371.37 + * Returns: passwd struct if password validated, NIL otherwise
  371.38 + */
  371.39 +
  371.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  371.41 +{
  371.42 +  return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
  371.43 +	  !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ?
  371.44 +	    pw : NIL;
  371.45 +}
   372.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   372.2 +++ b/src/osdep/unix/ckp_sv4.c	Mon Sep 14 15:17:45 2009 +0900
   372.3 @@ -0,0 +1,90 @@
   372.4 +/* ========================================================================
   372.5 + * Copyright 1988-2006 University of Washington
   372.6 + *
   372.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   372.8 + * you may not use this file except in compliance with the License.
   372.9 + * You may obtain a copy of the License at
  372.10 + *
  372.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  372.12 + *
  372.13 + * 
  372.14 + * ========================================================================
  372.15 + */
  372.16 +
  372.17 +/*
  372.18 + * Program:	SVR4 check password
  372.19 + *
  372.20 + * Author:	Mark Crispin
  372.21 + *		Networks and Distributed Computing
  372.22 + *		Computing & Communications
  372.23 + *		University of Washington
  372.24 + *		Administration Building, AG-44
  372.25 + *		Seattle, WA  98195
  372.26 + *		Internet: MRC@CAC.Washington.EDU
  372.27 + *
  372.28 + * Date:	1 August 1988
  372.29 + * Last Edited:	30 August 2006
  372.30 + */
  372.31 +
  372.32 +/* Check password
  372.33 + * Accepts: login passwd struct
  372.34 + *	    password string
  372.35 + *	    argument count
  372.36 + *	    argument vector
  372.37 + * Returns: passwd struct if password validated, NIL otherwise
  372.38 + */
  372.39 +
  372.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  372.41 +{
  372.42 +  char tmp[MAILTMPLEN];
  372.43 +  struct spwd *sp = NIL;
  372.44 +  time_t left;
  372.45 +  time_t now = time (0);
  372.46 +  struct tm *t = gmtime (&now);
  372.47 +  int zone = t->tm_hour * 60 + t->tm_min;
  372.48 +  int julian = t->tm_yday;
  372.49 +  t = localtime (&now);		/* get local time now */
  372.50 +				/* minus UTC minutes since midnight */
  372.51 +  zone = t->tm_hour * 60 + t->tm_min - zone;
  372.52 +  /* julian can be one of:
  372.53 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
  372.54 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
  372.55 +   *    0  local time is same day as UTC, no offset
  372.56 +   *   -1  local time is 1 day behind UTC, offset -24 hours
  372.57 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
  372.58 +   */
  372.59 +  if (julian = t->tm_yday -julian)
  372.60 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
  372.61 +				/* days since 1/1/1970 local time */
  372.62 +  now = ((now /60) + zone) / (60*24);
  372.63 +				/* non-shadow authentication */
  372.64 +  if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] ||
  372.65 +      strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
  372.66 +    /* As far as I've been able to determine, here is how the expiration
  372.67 +     * fields in the shadow authentication data work:
  372.68 +     *  lstchg	last password change date if non-negative.  If zero, the
  372.69 +     *		user can not log in without changing password.
  372.70 +     *  max	number of days a password is valid if positive
  372.71 +     *  warn	number of days of password expiration warning
  372.72 +     * The expiration day is the *last* day that the password is valid.
  372.73 +     */
  372.74 +				/* shadow authentication */
  372.75 +    if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg &&
  372.76 +	((sp->sp_lstchg < 0) || (sp->sp_max <= 0) ||
  372.77 +	 ((sp->sp_lstchg + sp->sp_max) >= now)) &&
  372.78 +	sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] &&
  372.79 +	!strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) {
  372.80 +      if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
  372.81 +	  ((left = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)) {
  372.82 +	if (left) {
  372.83 +	  sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left);
  372.84 +	  mm_notify (NIL,tmp,NIL);
  372.85 +	}
  372.86 +	else mm_notify (NIL,"[ALERT] Password expires today!",WARN);
  372.87 +      }
  372.88 +      endspent ();		/* don't need shadow password data any more */
  372.89 +    }
  372.90 +    else pw = NIL;		/* password failed */
  372.91 +  }
  372.92 +  return pw;
  372.93 +}
   373.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   373.2 +++ b/src/osdep/unix/ckp_svo.c	Mon Sep 14 15:17:45 2009 +0900
   373.3 @@ -0,0 +1,89 @@
   373.4 +/* ========================================================================
   373.5 + * Copyright 1988-2006 University of Washington
   373.6 + *
   373.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   373.8 + * you may not use this file except in compliance with the License.
   373.9 + * You may obtain a copy of the License at
  373.10 + *
  373.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  373.12 + *
  373.13 + * 
  373.14 + * ========================================================================
  373.15 + */
  373.16 +
  373.17 +/*
  373.18 + * Program:	Old SVR4 check password
  373.19 + *
  373.20 + * Author:	Mark Crispin
  373.21 + *		Networks and Distributed Computing
  373.22 + *		Computing & Communications
  373.23 + *		University of Washington
  373.24 + *		Administration Building, AG-44
  373.25 + *		Seattle, WA  98195
  373.26 + *		Internet: MRC@CAC.Washington.EDU
  373.27 + *
  373.28 + * Date:	1 August 1988
  373.29 + * Last Edited:	30 August 2006
  373.30 + */
  373.31 +
  373.32 +/* Check password
  373.33 + * Accepts: login passwd struct
  373.34 + *	    password string
  373.35 + *	    argument count
  373.36 + *	    argument vector
  373.37 + * Returns: passwd struct if password validated, NIL otherwise
  373.38 + */
  373.39 +
  373.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  373.41 +{
  373.42 +  char tmp[MAILTMPLEN];
  373.43 +  struct spwd *sp = NIL;
  373.44 +  time_t left;
  373.45 +  time_t now = time (0);
  373.46 +  struct tm *t = gmtime (&now);
  373.47 +  int zone = t->tm_hour * 60 + t->tm_min;
  373.48 +  int julian = t->tm_yday;
  373.49 +  t = localtime (&now);		/* get local time now */
  373.50 +				/* minus UTC minutes since midnight */
  373.51 +  zone = t->tm_hour * 60 + t->tm_min - zone;
  373.52 +  /* julian can be one of:
  373.53 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
  373.54 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
  373.55 +   *    0  local time is same day as UTC, no offset
  373.56 +   *   -1  local time is 1 day behind UTC, offset -24 hours
  373.57 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
  373.58 +   */
  373.59 +  if (julian = t->tm_yday -julian)
  373.60 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
  373.61 +				/* days since 1/1/1970 local time */
  373.62 +  now = ((now /60) + zone) / (60*24);
  373.63 +				/* non-shadow authentication */
  373.64 +  if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] ||
  373.65 +      strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
  373.66 +    /* As far as I've been able to determine, here is how the expiration
  373.67 +     * fields in the shadow authentication data work:
  373.68 +     *  lstchg	last password change date if non-negative.  If zero, the
  373.69 +     *		user can not log in without changing password.
  373.70 +     *  max	number of days a password is valid if positive
  373.71 +     * The expiration day is the *last* day that the password is valid.
  373.72 +     */
  373.73 +				/* shadow authentication */
  373.74 +    if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg &&
  373.75 +	((sp->sp_lstchg < 0) || (sp->sp_max <= 0) ||
  373.76 +	 ((sp->sp_lstchg + sp->sp_max) >= now)) &&
  373.77 +	sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] &&
  373.78 +	!strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) {
  373.79 +      if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
  373.80 +	  ((left = (sp->sp_lstchg + sp->sp_max) - now) <= 28)) {
  373.81 +	if (left) {
  373.82 +	  sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left);
  373.83 +	  mm_notify (NIL,tmp,NIL);
  373.84 +	}
  373.85 +	else mm_notify (NIL,"[ALERT] Password expires today!",WARN);
  373.86 +      }
  373.87 +      endspent ();		/* don't need shadow password data any more */
  373.88 +    }
  373.89 +    else pw = NIL;		/* password failed */
  373.90 +  }
  373.91 +  return pw;
  373.92 +}
   374.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   374.2 +++ b/src/osdep/unix/ckp_ult.c	Mon Sep 14 15:17:45 2009 +0900
   374.3 @@ -0,0 +1,40 @@
   374.4 +/* ========================================================================
   374.5 + * Copyright 1988-2006 University of Washington
   374.6 + *
   374.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   374.8 + * you may not use this file except in compliance with the License.
   374.9 + * You may obtain a copy of the License at
  374.10 + *
  374.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  374.12 + *
  374.13 + * 
  374.14 + * ========================================================================
  374.15 + */
  374.16 +
  374.17 +/*
  374.18 + * Program:	ULTRIX check password
  374.19 + *
  374.20 + * Author:	Mark Crispin
  374.21 + *		Networks and Distributed Computing
  374.22 + *		Computing & Communications
  374.23 + *		University of Washington
  374.24 + *		Administration Building, AG-44
  374.25 + *		Seattle, WA  98195
  374.26 + *		Internet: MRC@CAC.Washington.EDU
  374.27 + *
  374.28 + * Date:	1 August 1988
  374.29 + * Last Edited:	30 August 2006
  374.30 + */
  374.31 +
  374.32 +/* Check password
  374.33 + * Accepts: login passwd struct
  374.34 + *	    password string
  374.35 + *	    argument count
  374.36 + *	    argument vector
  374.37 + * Returns: passwd struct if password validated, NIL otherwise
  374.38 + */
  374.39 +
  374.40 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
  374.41 +{
  374.42 +  return (authenticate_user (pw,pass,NIL) >= 0) ? pw : NIL;
  374.43 +}
   375.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   375.2 +++ b/src/osdep/unix/crx_nfs.c	Mon Sep 14 15:17:45 2009 +0900
   375.3 @@ -0,0 +1,79 @@
   375.4 +/* ========================================================================
   375.5 + * Copyright 1988-2006 University of Washington
   375.6 + *
   375.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   375.8 + * you may not use this file except in compliance with the License.
   375.9 + * You may obtain a copy of the License at
  375.10 + *
  375.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  375.12 + *
  375.13 + * 
  375.14 + * ========================================================================
  375.15 + */
  375.16 +
  375.17 +/*
  375.18 + * Program:	Exclusive create of a file, NFS kludge version
  375.19 + *
  375.20 + * Author:	Mark Crispin
  375.21 + *		Networks and Distributed Computing
  375.22 + *		Computing & Communications
  375.23 + *		University of Washington
  375.24 + *		Administration Building, AG-44
  375.25 + *		Seattle, WA  98195
  375.26 + *		Internet: MRC@CAC.Washington.EDU
  375.27 + *
  375.28 + * Date:	17 December 1999
  375.29 + * Last Edited:	30 August 2006
  375.30 + */
  375.31 +
  375.32 +
  375.33 +/* SUN-OS had an NFS, As kludgy as an albatross;
  375.34 + * And everywhere that it was installed, It was a total loss.
  375.35 + *  -- MRC 9/25/91
  375.36 + */
  375.37 +
  375.38 +/* Exclusive create of a file
  375.39 + * Accepts: file name
  375.40 + * Return: T if success, NIL if failed, -1 if retry
  375.41 + */
  375.42 +
  375.43 +long crexcl (char *name)
  375.44 +{
  375.45 +  long ret = -1;
  375.46 +  int i;
  375.47 +  char hitch[MAILTMPLEN];
  375.48 +  struct stat sb;
  375.49 +  int mask = umask (0);
  375.50 +				/* build hitching post file name */
  375.51 +  sprintf (hitch,"%s.%lu.%d.",name,(unsigned long) time (0),getpid ());
  375.52 +  i = strlen (hitch);		/* append local host name */
  375.53 +  gethostname (hitch + i,(MAILTMPLEN - i) - 1);
  375.54 +				/* try to get hitching-post file */
  375.55 +  if ((i = open (hitch,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) >= 0) {
  375.56 +    close (i);			/* close the hitching-post */
  375.57 +    /* Note: link() may return an error even if it actually succeeded.  So we
  375.58 +     * always check for success via the link count, and ignore the error if
  375.59 +     * the link count is right.
  375.60 +     */
  375.61 +				/* tie hitching-post to lock */
  375.62 +    i = link (hitch,name) ? errno : 0;
  375.63 +				/* success if link count now 2 */
  375.64 +    if (!stat (hitch,&sb) && (sb.st_nlink == 2)) ret = LONGT;
  375.65 +    else if (i == EPERM) {	/* links not allowed? */
  375.66 +      /* Probably a FAT filesystem on Linux.  It can't be NFS, so try creating
  375.67 +       * the lock file directly.
  375.68 +       */
  375.69 +      if ((i = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) >= 0){
  375.70 +	close (i);		/* close the file */
  375.71 +	ret = LONGT;		/* success */
  375.72 +      }
  375.73 +				/* fail unless error is EEXIST */
  375.74 +      else if (errno != EEXIST) ret = NIL;
  375.75 +    }
  375.76 +    unlink (hitch);		/* flush hitching post */
  375.77 +  }
  375.78 +				/* fail unless error is EEXIST */
  375.79 +  else if (errno != EEXIST) ret = NIL;
  375.80 +  umask (mask);			/* restore previous mask */
  375.81 +  return ret;
  375.82 +}
   376.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   376.2 +++ b/src/osdep/unix/crx_std.c	Mon Sep 14 15:17:45 2009 +0900
   376.3 @@ -0,0 +1,45 @@
   376.4 +/* ========================================================================
   376.5 + * Copyright 1988-2006 University of Washington
   376.6 + *
   376.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   376.8 + * you may not use this file except in compliance with the License.
   376.9 + * You may obtain a copy of the License at
  376.10 + *
  376.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  376.12 + *
  376.13 + * 
  376.14 + * ========================================================================
  376.15 + */
  376.16 +
  376.17 +/*
  376.18 + * Program:	Exclusive create of a file
  376.19 + *
  376.20 + * Author:	Mark Crispin
  376.21 + *		Networks and Distributed Computing
  376.22 + *		Computing & Communications
  376.23 + *		University of Washington
  376.24 + *		Administration Building, AG-44
  376.25 + *		Seattle, WA  98195
  376.26 + *		Internet: MRC@CAC.Washington.EDU
  376.27 + *
  376.28 + * Date:	17 December 1999
  376.29 + * Last Edited:	30 August 2006
  376.30 + */
  376.31 +
  376.32 +/* Exclusive create of a file
  376.33 + * Accepts: file name
  376.34 + * Return: T if success, NIL if failed, -1 if retry
  376.35 + */
  376.36 +
  376.37 +long crexcl (char *name)
  376.38 +{
  376.39 +  int i;
  376.40 +  int mask = umask (0);
  376.41 +  long ret = LONGT;
  376.42 +				/* try to get the lock */
  376.43 +  if ((i = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) < 0)
  376.44 +    ret = (errno == EEXIST) ? -1 : NIL;
  376.45 +  else close (i);		/* made the file, now close it */
  376.46 +  umask (mask);			/* restore previous mask */
  376.47 +  return LONGT;			/* success */
  376.48 +}
   377.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   377.2 +++ b/src/osdep/unix/drivers	Mon Sep 14 15:17:45 2009 +0900
   377.3 @@ -0,0 +1,36 @@
   377.4 +#!/bin/sh
   377.5 +# ========================================================================
   377.6 +# Copyright 1988-2006 University of Washington
   377.7 +#
   377.8 +# Licensed under the Apache License, Version 2.0 (the "License");
   377.9 +# you may not use this file except in compliance with the License.
  377.10 +# You may obtain a copy of the License at
  377.11 +#
  377.12 +#     http://www.apache.org/licenses/LICENSE-2.0
  377.13 +#
  377.14 +# 
  377.15 +# ========================================================================
  377.16 +
  377.17 +# Program:	Driver Linkage Generator
  377.18 +#
  377.19 +# Author:	Mark Crispin
  377.20 +#		Networks and Distributed Computing
  377.21 +#		Computing & Communications
  377.22 +#		University of Washington
  377.23 +#		Administration Building, AG-44
  377.24 +#		Seattle, WA  98195
  377.25 +#		Internet: MRC@CAC.Washington.EDU
  377.26 +#
  377.27 +# Date:		11 October 1989
  377.28 +# Last Edited:	30 August 2006
  377.29 +
  377.30 +
  377.31 +# Erase old driver linkage
  377.32 +rm -f linkage.[ch]
  377.33 +
  377.34 +# Now define the new list
  377.35 +for driver
  377.36 + do
  377.37 +  echo "extern DRIVER "$driver"driver;" >> linkage.h
  377.38 +  echo "  mail_link (&"$driver"driver);		/* link in the $driver driver */" | cat >> linkage.c
  377.39 +done
   378.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   378.2 +++ b/src/osdep/unix/dummy.c	Mon Sep 14 15:17:45 2009 +0900
   378.3 @@ -0,0 +1,809 @@
   378.4 +/* ========================================================================
   378.5 + * Copyright 1988-2007 University of Washington
   378.6 + *
   378.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   378.8 + * you may not use this file except in compliance with the License.
   378.9 + * You may obtain a copy of the License at
  378.10 + *
  378.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  378.12 + *
  378.13 + * 
  378.14 + * ========================================================================
  378.15 + */
  378.16 +
  378.17 +/*
  378.18 + * Program:	Dummy routines
  378.19 + *
  378.20 + * Author:	Mark Crispin
  378.21 + *		Networks and Distributed Computing
  378.22 + *		Computing & Communications
  378.23 + *		University of Washington
  378.24 + *		Administration Building, AG-44
  378.25 + *		Seattle, WA  98195
  378.26 + *		Internet: MRC@CAC.Washington.EDU
  378.27 + *
  378.28 + * Date:	9 May 1991
  378.29 + * Last Edited:	1 June 2007
  378.30 + */
  378.31 +
  378.32 +
  378.33 +#include <stdio.h>
  378.34 +#include <ctype.h>
  378.35 +#include <errno.h>
  378.36 +extern int errno;		/* just in case */
  378.37 +#include "mail.h"
  378.38 +#include "osdep.h"
  378.39 +#include <pwd.h>
  378.40 +#include <sys/stat.h>
  378.41 +#include "dummy.h"
  378.42 +#include "misc.h"
  378.43 +
  378.44 +/* Function prototypes */
  378.45 +
  378.46 +DRIVER *dummy_valid (char *name);
  378.47 +void *dummy_parameters (long function,void *value);
  378.48 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
  378.49 +		      long level);
  378.50 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
  378.51 +		   long attributes,char *contents);
  378.52 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
  378.53 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  378.54 +void dummy_close (MAILSTREAM *stream,long options);
  378.55 +long dummy_ping (MAILSTREAM *stream);
  378.56 +void dummy_check (MAILSTREAM *stream);
  378.57 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  378.58 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  378.59 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  378.60 +
  378.61 +/* Dummy routines */
  378.62 +
  378.63 +
  378.64 +/* Driver dispatch used by MAIL */
  378.65 +
  378.66 +DRIVER dummydriver = {
  378.67 +  "dummy",			/* driver name */
  378.68 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  378.69 +  (DRIVER *) NIL,		/* next driver */
  378.70 +  dummy_valid,			/* mailbox is valid for us */
  378.71 +  dummy_parameters,		/* manipulate parameters */
  378.72 +  dummy_scan,			/* scan mailboxes */
  378.73 +  dummy_list,			/* list mailboxes */
  378.74 +  dummy_lsub,			/* list subscribed mailboxes */
  378.75 +  dummy_subscribe,		/* subscribe to mailbox */
  378.76 +  NIL,				/* unsubscribe from mailbox */
  378.77 +  dummy_create,			/* create mailbox */
  378.78 +  dummy_delete,			/* delete mailbox */
  378.79 +  dummy_rename,			/* rename mailbox */
  378.80 +  mail_status_default,		/* status of mailbox */
  378.81 +  dummy_open,			/* open mailbox */
  378.82 +  dummy_close,			/* close mailbox */
  378.83 +  NIL,				/* fetch message "fast" attributes */
  378.84 +  NIL,				/* fetch message flags */
  378.85 +  NIL,				/* fetch overview */
  378.86 +  NIL,				/* fetch message structure */
  378.87 +  NIL,				/* fetch header */
  378.88 +  NIL,				/* fetch text */
  378.89 +  NIL,				/* fetch message data */
  378.90 +  NIL,				/* unique identifier */
  378.91 +  NIL,				/* message number from UID */
  378.92 +  NIL,				/* modify flags */
  378.93 +  NIL,				/* per-message modify flags */
  378.94 +  NIL,				/* search for message based on criteria */
  378.95 +  NIL,				/* sort messages */
  378.96 +  NIL,				/* thread messages */
  378.97 +  dummy_ping,			/* ping mailbox to see if still alive */
  378.98 +  dummy_check,			/* check for new messages */
  378.99 +  dummy_expunge,		/* expunge deleted messages */
 378.100 +  dummy_copy,			/* copy messages to another mailbox */
 378.101 +  dummy_append,			/* append string message to mailbox */
 378.102 +  NIL				/* garbage collect stream */
 378.103 +};
 378.104 +
 378.105 +				/* prototype stream */
 378.106 +MAILSTREAM dummyproto = {&dummydriver};
 378.107 +
 378.108 +/* Dummy validate mailbox
 378.109 + * Accepts: mailbox name
 378.110 + * Returns: our driver if name is valid, NIL otherwise
 378.111 + */
 378.112 +
 378.113 +DRIVER *dummy_valid (char *name)
 378.114 +{
 378.115 +  char *s,tmp[MAILTMPLEN];
 378.116 +  struct stat sbuf;
 378.117 +				/* must be valid local mailbox */
 378.118 +  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
 378.119 +				/* indeterminate clearbox INBOX */
 378.120 +    if (!*s) return &dummydriver;
 378.121 +    else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
 378.122 +    case S_IFREG:
 378.123 +    case S_IFDIR:
 378.124 +      return &dummydriver;
 378.125 +    }
 378.126 +				/* blackbox INBOX does not exist yet */
 378.127 +    else if (!compare_cstring (name,"INBOX")) return &dummydriver;
 378.128 +  }
 378.129 +  return NIL;
 378.130 +}
 378.131 +
 378.132 +
 378.133 +/* Dummy manipulate driver parameters
 378.134 + * Accepts: function code
 378.135 + *	    function-dependent value
 378.136 + * Returns: function-dependent return value
 378.137 + */
 378.138 +
 378.139 +void *dummy_parameters (long function,void *value)
 378.140 +{
 378.141 +  void *ret = NIL;
 378.142 +  switch ((int) function) {
 378.143 +  case GET_INBOXPATH:
 378.144 +    if (value) ret = dummy_file ((char *) value,"INBOX");
 378.145 +    break;
 378.146 +  }
 378.147 +  return ret;
 378.148 +}
 378.149 +
 378.150 +/* Dummy scan mailboxes
 378.151 + * Accepts: mail stream
 378.152 + *	    reference
 378.153 + *	    pattern to search
 378.154 + *	    string to scan
 378.155 + */
 378.156 +
 378.157 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 378.158 +{
 378.159 +  DRIVER *drivers;
 378.160 +  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
 378.161 +  long i;
 378.162 +  if (!pat || !*pat) {		/* empty pattern? */
 378.163 +    if (dummy_canonicalize (test,ref,"*")) {
 378.164 +				/* tie off name at root */
 378.165 +      if (s = strchr (test,'/')) *++s = '\0';
 378.166 +      else test[0] = '\0';
 378.167 +      dummy_listed (stream,'/',test,LATT_NOSELECT,NIL);
 378.168 +    }
 378.169 +  }
 378.170 +				/* get canonical form of name */
 378.171 +  else if (dummy_canonicalize (test,ref,pat)) {
 378.172 +				/* found any wildcards? */
 378.173 +    if (s = strpbrk (test,"%*")) {
 378.174 +				/* yes, copy name up to that point */
 378.175 +      strncpy (file,test,i = s - test);
 378.176 +      file[i] = '\0';		/* tie off */
 378.177 +    }
 378.178 +    else strcpy (file,test);	/* use just that name then */
 378.179 +    if (s = strrchr (file,'/')){/* find directory name */
 378.180 +      *++s = '\0';		/* found, tie off at that point */
 378.181 +      s = file;
 378.182 +    }
 378.183 +				/* silly case */
 378.184 +    else if ((file[0] == '~') || (file[0] == '#')) s = file;
 378.185 +				/* do the work */
 378.186 +    dummy_list_work (stream,s,test,contents,0);
 378.187 +				/* always an INBOX */
 378.188 +    if (pmatch ("INBOX",ucase (test))) {
 378.189 +				/* done if have a dirfmt INBOX */
 378.190 +      for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
 378.191 +	   drivers && !(!(drivers->flags & DR_DISABLE) &&
 378.192 +			(drivers->flags & DR_DIRFMT) &&
 378.193 +			(*drivers->valid) ("INBOX")); drivers = drivers->next);
 378.194 +				/* list INBOX appropriately */
 378.195 +      dummy_listed (stream,drivers ? '/' : NIL,"INBOX",
 378.196 +		    drivers ? NIL : LATT_NOINFERIORS,contents);
 378.197 +    }
 378.198 +  }
 378.199 +}
 378.200 +
 378.201 +
 378.202 +/* Dummy list mailboxes
 378.203 + * Accepts: mail stream
 378.204 + *	    reference
 378.205 + *	    pattern to search
 378.206 + */
 378.207 +
 378.208 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 378.209 +{
 378.210 +  dummy_scan (stream,ref,pat,NIL);
 378.211 +}
 378.212 +
 378.213 +/* Dummy list subscribed mailboxes
 378.214 + * Accepts: mail stream
 378.215 + *	    reference
 378.216 + *	    pattern to search
 378.217 + */
 378.218 +
 378.219 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 378.220 +{
 378.221 +  void *sdb = NIL;
 378.222 +  char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN];
 378.223 +  int showuppers = pat[strlen (pat) - 1] == '%';
 378.224 +				/* get canonical form of name */
 378.225 +  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
 378.226 +    if (*s != '{') {
 378.227 +      if (!compare_cstring (s,"INBOX") &&
 378.228 +	  pmatch ("INBOX",ucase (strcpy (tmp,test))))
 378.229 +	mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
 378.230 +      else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
 378.231 +      else while (showuppers && (t = strrchr (s,'/'))) {
 378.232 +	*t = '\0';		/* tie off the name */
 378.233 +	if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT);
 378.234 +      }
 378.235 +    }
 378.236 +  while (s = sm_read (&sdb));	/* until no more subscriptions */
 378.237 +}
 378.238 +
 378.239 +
 378.240 +/* Dummy subscribe to mailbox
 378.241 + * Accepts: mail stream
 378.242 + *	    mailbox to add to subscription list
 378.243 + * Returns: T on success, NIL on failure
 378.244 + */
 378.245 +
 378.246 +long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
 378.247 +{
 378.248 +  char *s,tmp[MAILTMPLEN];
 378.249 +  struct stat sbuf;
 378.250 +				/* must be valid local mailbox */
 378.251 +  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf))
 378.252 +    switch (sbuf.st_mode & S_IFMT) {
 378.253 +    case S_IFDIR:		/* allow but snarl */
 378.254 +      sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s",
 378.255 +	       mailbox);
 378.256 +      MM_NOTIFY (stream,tmp,WARN);
 378.257 +    case S_IFREG:
 378.258 +      return sm_subscribe (mailbox);
 378.259 +    }
 378.260 +  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
 378.261 +  MM_LOG (tmp,ERROR);
 378.262 +  return NIL;
 378.263 +}
 378.264 +
 378.265 +/* Dummy list mailboxes worker routine
 378.266 + * Accepts: mail stream
 378.267 + *	    directory name to search
 378.268 + *	    search pattern
 378.269 + *	    string to scan
 378.270 + *	    search level
 378.271 + */
 378.272 +
 378.273 +void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
 378.274 +		      long level)
 378.275 +{
 378.276 +  DRIVER *drivers;
 378.277 +  dirfmttest_t dt;
 378.278 +  DIR *dp;
 378.279 +  struct direct *d;
 378.280 +  struct stat sbuf;
 378.281 +  char tmp[MAILTMPLEN],path[MAILTMPLEN];
 378.282 +  size_t len = 0;
 378.283 +				/* punt if bogus name */
 378.284 +  if (!mailboxdir (tmp,dir,NIL)) return;
 378.285 +  if (dp = opendir (tmp)) {	/* do nothing if can't open directory */
 378.286 +				/* see if a non-namespace directory format */
 378.287 +    for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
 378.288 +	 dir && !dt && drivers; drivers = drivers->next)
 378.289 +      if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) &&
 378.290 +	  (*drivers->valid) (dir))
 378.291 +	dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL);
 378.292 +				/* list it if at top-level */
 378.293 +    if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX"))
 378.294 +      dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents);
 378.295 +
 378.296 +				/* scan directory, ignore . and .. */
 378.297 +    if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp))
 378.298 +      if ((!(dt && (*dt) (d->d_name))) &&
 378.299 +	  ((d->d_name[0] != '.') ||
 378.300 +	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
 378.301 +	    (d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) &&
 378.302 +	  ((len + strlen (d->d_name)) <= NETMAXMBX)) {
 378.303 +				/* see if name is useful */
 378.304 +	if (dir) sprintf (tmp,"%s%s",dir,d->d_name);
 378.305 +	else strcpy (tmp,d->d_name);
 378.306 +				/* make sure useful and can get info */
 378.307 +	if ((pmatch_full (strcpy (path,tmp),pat,'/') ||
 378.308 +	     pmatch_full (strcat (path,"/"),pat,'/') ||
 378.309 +	     dmatch (path,pat,'/')) &&
 378.310 +	    mailboxdir (path,dir,"x") && (len = strlen (path)) &&
 378.311 +	    strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) {
 378.312 +				/* only interested in file type */
 378.313 +	  switch (sbuf.st_mode & S_IFMT) {
 378.314 +	  case S_IFDIR:		/* directory? */
 378.315 +				/* form with trailing / */
 378.316 +	    sprintf (path,"%s/",tmp);
 378.317 +				/* skip listing if INBOX */
 378.318 +	    if (!pmatch (tmp,"INBOX")) {
 378.319 +	      if (pmatch_full (tmp,pat,'/')) {
 378.320 +		if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents))
 378.321 +		  break;
 378.322 +	      }
 378.323 +				/* try again with trailing / */
 378.324 +	      else if (pmatch_full (path,pat,'/') &&
 378.325 +		       !dummy_listed (stream,'/',path,LATT_NOSELECT,contents))
 378.326 +		break;
 378.327 +	    }
 378.328 +	    if (dmatch (path,pat,'/') &&
 378.329 +		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 378.330 +	      dummy_list_work (stream,path,pat,contents,level+1);
 378.331 +	    break;
 378.332 +	  case S_IFREG:		/* ordinary name */
 378.333 +	    /* Must use ctime for systems that don't update mtime properly */
 378.334 +	    if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX"))
 378.335 +	      dummy_listed (stream,'/',tmp,LATT_NOINFERIORS +
 378.336 +			    ((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))?
 378.337 +			     LATT_MARKED : LATT_UNMARKED),contents);
 378.338 +	    break;
 378.339 +	  }
 378.340 +	}
 378.341 +      }
 378.342 +    closedir (dp);		/* all done, flush directory */
 378.343 +  }
 378.344 +}
 378.345 +
 378.346 +/* Scan file for contents
 378.347 + * Accepts: driver to use
 378.348 + *	    file name
 378.349 + *	    desired contents
 378.350 + *	    length of contents
 378.351 + *	    size of file
 378.352 + * Returns: NIL if contents not found, T if found
 378.353 + */
 378.354 +
 378.355 +long scan_contents (DRIVER *dtb,char *name,char *contents,
 378.356 +		    unsigned long csiz,unsigned long fsiz)
 378.357 +{
 378.358 +  scancontents_t sc = dtb ?
 378.359 +    (scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL;
 378.360 +  return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz);
 378.361 +}
 378.362 +
 378.363 +
 378.364 +/* Scan file for contents
 378.365 + * Accepts: file name
 378.366 + *	    desired contents
 378.367 + *	    length of contents
 378.368 + *	    size of file
 378.369 + * Returns: NIL if contents not found, T if found
 378.370 + */
 378.371 +
 378.372 +#define BUFSIZE 4*MAILTMPLEN
 378.373 +
 378.374 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
 378.375 +			  unsigned long fsiz)
 378.376 +{
 378.377 +  int fd;
 378.378 +  unsigned long ssiz,bsiz;
 378.379 +  char *buf;
 378.380 +				/* forget it if can't select or open */
 378.381 +  if ((fd = open (name,O_RDONLY,NIL)) >= 0) {
 378.382 +				/* get buffer including slop */    
 378.383 +    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
 378.384 +    memset (buf,'\0',ssiz);	/* no slop area the first time */
 378.385 +    while (fsiz) {		/* until end of file */
 378.386 +      read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE));
 378.387 +      if (search ((unsigned char *) buf,bsiz+ssiz,
 378.388 +		  (unsigned char *) contents,csiz)) break;
 378.389 +      memcpy (buf,buf+BUFSIZE,ssiz);
 378.390 +      fsiz -= bsiz;		/* note that we read that much */
 378.391 +    }
 378.392 +    fs_give ((void **) &buf);	/* flush buffer */
 378.393 +    close (fd);			/* finished with file */
 378.394 +    if (fsiz) return T;		/* found */
 378.395 +  }
 378.396 +  return NIL;			/* not found */
 378.397 +}
 378.398 +
 378.399 +/* Mailbox found
 378.400 + * Accepts: MAIL stream
 378.401 + *	    hierarchy delimiter
 378.402 + *	    mailbox name
 378.403 + *	    attributes
 378.404 + *	    contents to search before calling mm_list()
 378.405 + * Returns: NIL if should abort hierarchy search, else T (currently always)
 378.406 + */
 378.407 +
 378.408 +long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
 378.409 +		   long attributes,char *contents)
 378.410 +{
 378.411 +  DRIVER *d;
 378.412 +  DIR *dp;
 378.413 +  struct direct *dr;
 378.414 +  dirfmttest_t dt;
 378.415 +  unsigned long csiz;
 378.416 +  struct stat sbuf;
 378.417 +  int nochild;
 378.418 +  char *s,tmp[MAILTMPLEN];
 378.419 +  if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
 378.420 +      (dp = opendir (tmp))) {	/* if not \NoInferiors */
 378.421 +				/* locate dirfmttest if any */
 378.422 +    for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
 378.423 +	 !dt && d; d = d->next)
 378.424 +      if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) &&
 378.425 +	  (*d->valid) (name))
 378.426 +	dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL);
 378.427 +				/* scan directory for children */
 378.428 +    for (nochild = T; nochild && (dr = readdir (dp)); )
 378.429 +      if ((!(dt && (*dt) (dr->d_name))) &&
 378.430 +	  ((dr->d_name[0] != '.') ||
 378.431 +	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
 378.432 +	    (dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2])))))
 378.433 +	nochild = NIL;
 378.434 +    attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
 378.435 +    closedir (dp);		/* all done, flush directory */
 378.436 +  }
 378.437 +  d = NIL;			/* don't \NoSelect dir if it has a driver */
 378.438 +  if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
 378.439 +      (d != &dummydriver)) attributes &= ~LATT_NOSELECT;
 378.440 +  if (!contents ||		/* notify main program */
 378.441 +      (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
 378.442 +       (s = mailboxfile (tmp,name)) &&
 378.443 +       (*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) &&
 378.444 +       !stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) &&
 378.445 +       SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size)))
 378.446 +    mm_list (stream,delimiter,name,attributes);
 378.447 +  return T;
 378.448 +}
 378.449 +
 378.450 +/* Dummy create mailbox
 378.451 + * Accepts: mail stream
 378.452 + *	    mailbox name to create
 378.453 + * Returns: T on success, NIL on failure
 378.454 + */
 378.455 +
 378.456 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 378.457 +{
 378.458 +  char *s,tmp[MAILTMPLEN];
 378.459 +  long ret = NIL;
 378.460 +				/* validate name */
 378.461 +  if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
 378.462 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 378.463 +    MM_LOG (tmp,ERROR);
 378.464 +  }
 378.465 +				/* create the name, done if made directory */
 378.466 +  else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&&
 378.467 +	   (s = strrchr (s,'/')) && !s[1]) return T;
 378.468 +  return ret ? set_mbx_protections (mailbox,tmp) : NIL;
 378.469 +}
 378.470 +
 378.471 +/* Dummy create path
 378.472 + * Accepts: mail stream
 378.473 + *	    path name to create
 378.474 + *	    directory mode
 378.475 + * Returns: T on success, NIL on failure
 378.476 + */
 378.477 +
 378.478 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
 378.479 +{
 378.480 +  struct stat sbuf;
 378.481 +  char c,*s,tmp[MAILTMPLEN];
 378.482 +  int fd;
 378.483 +  long ret = NIL;
 378.484 +  char *t = strrchr (path,'/');
 378.485 +  int wantdir = t && !t[1];
 378.486 +  int mask = umask (0);
 378.487 +  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
 378.488 +  if (s = strrchr (path,'/')) {	/* found superior to this name? */
 378.489 +    c = *++s;			/* remember first character of inferior */
 378.490 +    *s = '\0';			/* tie off to get just superior */
 378.491 +				/* name doesn't exist, create it */
 378.492 +    if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 378.493 +	!dummy_create_path (stream,path,dirmode)) {
 378.494 +      umask (mask);		/* restore mask */
 378.495 +      return NIL;
 378.496 +    }
 378.497 +    *s = c;			/* restore full name */
 378.498 +  }
 378.499 +  if (wantdir) {		/* want to create directory? */
 378.500 +    ret = !mkdir (path,(int) dirmode);
 378.501 +    *t = '/';			/* restore directory delimiter */
 378.502 +  }
 378.503 +				/* create file */
 378.504 +  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,
 378.505 +		       (long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0)
 378.506 +    ret = !close (fd);
 378.507 +  if (!ret) {			/* error? */
 378.508 +    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno));
 378.509 +    MM_LOG (tmp,ERROR);
 378.510 +  }
 378.511 +  umask (mask);			/* restore mask */
 378.512 +  return ret;			/* return status */
 378.513 +}
 378.514 +
 378.515 +/* Dummy delete mailbox
 378.516 + * Accepts: mail stream
 378.517 + *	    mailbox name to delete
 378.518 + * Returns: T on success, NIL on failure
 378.519 + */
 378.520 +
 378.521 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 378.522 +{
 378.523 +  struct stat sbuf;
 378.524 +  char *s,tmp[MAILTMPLEN];
 378.525 +  if (!(s = dummy_file (tmp,mailbox))) {
 378.526 +    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
 378.527 +    MM_LOG (tmp,ERROR);
 378.528 +  }
 378.529 +				/* no trailing / (workaround BSD kernel bug) */
 378.530 +  if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0';
 378.531 +  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
 378.532 +      rmdir (tmp) : unlink (tmp)) {
 378.533 +    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
 378.534 +    MM_LOG (tmp,ERROR);
 378.535 +    return NIL;
 378.536 +  }
 378.537 +  return T;			/* return success */
 378.538 +}
 378.539 +
 378.540 +/* Mail rename mailbox
 378.541 + * Accepts: mail stream
 378.542 + *	    old mailbox name
 378.543 + *	    new mailbox name
 378.544 + * Returns: T on success, NIL on failure
 378.545 + */
 378.546 +
 378.547 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 378.548 +{
 378.549 +  struct stat sbuf;
 378.550 +  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
 378.551 +				/* no trailing / allowed */
 378.552 +  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
 378.553 +      stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
 378.554 +			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
 378.555 +    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
 378.556 +    MM_LOG (mbx,ERROR);
 378.557 +    return NIL;
 378.558 +  }
 378.559 +  if (s) {			/* found a directory delimiter? */
 378.560 +    if (!s[1]) *s = '\0';	/* ignore trailing delimiter */
 378.561 +    else {			/* found superior to destination name? */
 378.562 +      c = *++s;			/* remember first character of inferior */
 378.563 +      *s = '\0';		/* tie off to get just superior */
 378.564 +				/* name doesn't exist, create it */
 378.565 +      if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 378.566 +	  !dummy_create (stream,mbx)) return NIL;
 378.567 +      *s = c;			/* restore full name */
 378.568 +    }
 378.569 +  }
 378.570 +				/* rename of non-ex INBOX creates dest */
 378.571 +  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
 378.572 +    return dummy_create (NIL,mbx);
 378.573 +  if (rename (oldname,mbx)) {
 378.574 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
 378.575 +	     strerror (errno));
 378.576 +    MM_LOG (tmp,ERROR);
 378.577 +    return NIL;
 378.578 +  }
 378.579 +  return T;			/* return success */
 378.580 +}
 378.581 +
 378.582 +/* Dummy open
 378.583 + * Accepts: stream to open
 378.584 + * Returns: stream on success, NIL on failure
 378.585 + */
 378.586 +
 378.587 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 378.588 +{
 378.589 +  int fd;
 378.590 +  char err[MAILTMPLEN],tmp[MAILTMPLEN];
 378.591 +  struct stat sbuf;
 378.592 +				/* OP_PROTOTYPE call */
 378.593 +  if (!stream) return &dummyproto;
 378.594 +  err[0] = '\0';		/* no error message yet */
 378.595 +				/* can we open the file? */
 378.596 +  if (!dummy_file (tmp,stream->mailbox))
 378.597 +    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
 378.598 +  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 378.599 +				/* no, error unless INBOX */
 378.600 +    if (compare_cstring (stream->mailbox,"INBOX"))
 378.601 +      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
 378.602 +  }
 378.603 +  else {			/* file had better be empty then */
 378.604 +    fstat (fd,&sbuf);		/* sniff at its size */
 378.605 +    close (fd);
 378.606 +    if ((sbuf.st_mode & S_IFMT) != S_IFREG)
 378.607 +      sprintf (err,"Can't open %.80s: not a selectable mailbox",
 378.608 +	       stream->mailbox);
 378.609 +    else if (sbuf.st_size)	/* bogus format if non-empty */
 378.610 +      sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format",
 378.611 +	       stream->mailbox,tmp);
 378.612 +  }
 378.613 +  if (err[0]) {			/* if an error happened */
 378.614 +    MM_LOG (err,stream->silent ? WARN : ERROR);
 378.615 +    return NIL;
 378.616 +  }
 378.617 +  else if (!stream->silent) {	/* only if silence not requested */
 378.618 +    mail_exists (stream,0);	/* say there are 0 messages */
 378.619 +    mail_recent (stream,0);	/* and certainly no recent ones! */
 378.620 +    stream->uid_validity = time (0);
 378.621 +  }
 378.622 +  stream->inbox = T;		/* note that it's an INBOX */
 378.623 +  return stream;		/* return success */
 378.624 +}
 378.625 +
 378.626 +
 378.627 +/* Dummy close
 378.628 + * Accepts: MAIL stream
 378.629 + *	    options
 378.630 + */
 378.631 +
 378.632 +void dummy_close (MAILSTREAM *stream,long options)
 378.633 +{
 378.634 +				/* return silently */
 378.635 +}
 378.636 +
 378.637 +/* Dummy ping mailbox
 378.638 + * Accepts: MAIL stream
 378.639 + * Returns: T if stream alive, else NIL
 378.640 + */
 378.641 +
 378.642 +long dummy_ping (MAILSTREAM *stream)
 378.643 +{
 378.644 +  MAILSTREAM *test;
 378.645 +  if (time (0) >=		/* time to do another test? */
 378.646 +      ((time_t) (stream->gensym +
 378.647 +		 (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
 378.648 +				/* has mailbox format changed? */
 378.649 +    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
 378.650 +	(test->dtb != stream->dtb) &&
 378.651 +	(test = mail_open (NIL,stream->mailbox,NIL))) {
 378.652 +				/* preserve some resources */
 378.653 +      test->original_mailbox = stream->original_mailbox;
 378.654 +      stream->original_mailbox = NIL;
 378.655 +      test->sparep = stream->sparep;
 378.656 +      stream->sparep = NIL;
 378.657 +      test->sequence = stream->sequence;
 378.658 +      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
 378.659 +		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
 378.660 +			  sizeof (MAILSTREAM)));
 378.661 +				/* swap the streams */
 378.662 +      memcpy (stream,test,sizeof (MAILSTREAM));
 378.663 +      fs_give ((void **) &test);/* flush test now that copied */
 378.664 +				/* make sure application knows */
 378.665 +      mail_exists (stream,stream->recent = stream->nmsgs);
 378.666 +    }
 378.667 +				/* still hasn't changed */
 378.668 +    else stream->gensym = time (0);
 378.669 +  }
 378.670 +  return T;
 378.671 +}
 378.672 +
 378.673 +
 378.674 +/* Dummy check mailbox
 378.675 + * Accepts: MAIL stream
 378.676 + * No-op for readonly files, since read/writer can expunge it from under us!
 378.677 + */
 378.678 +
 378.679 +void dummy_check (MAILSTREAM *stream)
 378.680 +{
 378.681 +  dummy_ping (stream);		/* invoke ping */
 378.682 +}
 378.683 +
 378.684 +
 378.685 +/* Dummy expunge mailbox
 378.686 + * Accepts: MAIL stream
 378.687 + *	    sequence to expunge if non-NIL
 378.688 + *	    expunge options
 378.689 + * Returns: T, always
 378.690 + */
 378.691 +
 378.692 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 378.693 +{
 378.694 +  return LONGT;
 378.695 +}
 378.696 +
 378.697 +/* Dummy copy message(s)
 378.698 + * Accepts: MAIL stream
 378.699 + *	    sequence
 378.700 + *	    destination mailbox
 378.701 + *	    options
 378.702 + * Returns: T if copy successful, else NIL
 378.703 + */
 378.704 +
 378.705 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 378.706 +{
 378.707 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 378.708 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 378.709 +  return NIL;
 378.710 +}
 378.711 +
 378.712 +
 378.713 +/* Dummy append message string
 378.714 + * Accepts: mail stream
 378.715 + *	    destination mailbox
 378.716 + *	    append callback function
 378.717 + *	    data for callback
 378.718 + * Returns: T on success, NIL on failure
 378.719 + */
 378.720 +
 378.721 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 378.722 +{
 378.723 +  struct stat sbuf;
 378.724 +  int fd = -1;
 378.725 +  int e;
 378.726 +  char tmp[MAILTMPLEN];
 378.727 +  MAILSTREAM *ts = default_proto (T);
 378.728 +				/* append to INBOX? */
 378.729 +  if (!compare_cstring (mailbox,"INBOX")) {
 378.730 +				/* yes, if no empty proto try creating */
 378.731 +    if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX"))
 378.732 +      ts = NIL;
 378.733 +  }
 378.734 +  else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
 378.735 +    if ((e = errno) == ENOENT) /* failed, was it no such file? */
 378.736 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 378.737 +    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
 378.738 +    MM_LOG (tmp,ERROR);		/* pass up error */
 378.739 +    return NIL;			/* always fails */
 378.740 +  }
 378.741 +  else if (fd >= 0) {		/* found file? */
 378.742 +    fstat (fd,&sbuf);		/* get its size */
 378.743 +    close (fd);			/* toss out the fd */
 378.744 +    if (sbuf.st_size) ts = NIL; /* non-empty file? */
 378.745 +  }
 378.746 +  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
 378.747 +  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
 378.748 +  MM_LOG (tmp,ERROR);
 378.749 +  return NIL;
 378.750 +}
 378.751 +
 378.752 +/* Dummy mail generate file string
 378.753 + * Accepts: temporary buffer to write into
 378.754 + *	    mailbox name string
 378.755 + * Returns: local file string or NIL if failure
 378.756 + */
 378.757 +
 378.758 +char *dummy_file (char *dst,char *name)
 378.759 +{
 378.760 +  char *s = mailboxfile (dst,name);
 378.761 +				/* return our standard inbox */
 378.762 +  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
 378.763 +}
 378.764 +
 378.765 +
 378.766 +/* Dummy canonicalize name
 378.767 + * Accepts: buffer to write name
 378.768 + *	    reference
 378.769 + *	    pattern
 378.770 + * Returns: T if success, NIL if failure
 378.771 + */
 378.772 +
 378.773 +long dummy_canonicalize (char *tmp,char *ref,char *pat)
 378.774 +{
 378.775 +  unsigned long i;
 378.776 +  char *s;
 378.777 +  if (ref) {			/* preliminary reference check */
 378.778 +    if (*ref == '{') return NIL;/* remote reference not allowed */
 378.779 +    else if (!*ref) ref = NIL;	/* treat empty reference as no reference */
 378.780 +  }
 378.781 +  switch (*pat) {
 378.782 +  case '#':			/* namespace name */
 378.783 +    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
 378.784 +    else return NIL;		/* unknown namespace */
 378.785 +    break;
 378.786 +  case '{':			/* remote names not allowed */
 378.787 +    return NIL;
 378.788 +  case '/':			/* rooted name */
 378.789 +  case '~':			/* home directory name */
 378.790 +    if (!ref || (*ref != '#')) {/* non-namespace reference? */
 378.791 +      strcpy (tmp,pat);		/* yes, ignore */
 378.792 +      break;
 378.793 +    }
 378.794 +				/* fall through */
 378.795 +  default:			/* apply reference for all other names */
 378.796 +    if (!ref) strcpy (tmp,pat);	/* just copy if no namespace */
 378.797 +    else if ((*ref != '#') || mailboxfile (tmp,ref)) {
 378.798 +				/* wants root of name? */
 378.799 +      if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat);
 378.800 +				/* otherwise just append */
 378.801 +      else sprintf (tmp,"%s%s",ref,pat);
 378.802 +    }
 378.803 +    else return NIL;		/* unknown namespace */
 378.804 +  }
 378.805 +				/* count wildcards */
 378.806 +  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 378.807 +  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
 378.808 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 378.809 +    return NIL;
 378.810 +  }
 378.811 +  return T;
 378.812 +}
   379.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   379.2 +++ b/src/osdep/unix/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   379.3 @@ -0,0 +1,43 @@
   379.4 +/* ========================================================================
   379.5 + * Copyright 1988-2006 University of Washington
   379.6 + *
   379.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   379.8 + * you may not use this file except in compliance with the License.
   379.9 + * You may obtain a copy of the License at
  379.10 + *
  379.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  379.12 + *
  379.13 + * 
  379.14 + * ========================================================================
  379.15 + */
  379.16 +
  379.17 +/*
  379.18 + * Program:	Dummy routines
  379.19 + *
  379.20 + * Author:	Mark Crispin
  379.21 + *		Networks and Distributed Computing
  379.22 + *		Computing & Communications
  379.23 + *		University of Washington
  379.24 + *		Administration Building, AG-44
  379.25 + *		Seattle, WA  98195
  379.26 + *		Internet: MRC@CAC.Washington.EDU
  379.27 + *
  379.28 + * Date:	9 May 1991
  379.29 + * Last Edited:	30 August 2006
  379.30 + */
  379.31 +
  379.32 +/* Exported function prototypes */
  379.33 +
  379.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  379.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  379.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  379.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  379.38 +		    unsigned long csiz,unsigned long fsiz);
  379.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  379.40 +			  unsigned long fsiz);
  379.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  379.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  379.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  379.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  379.45 +char *dummy_file (char *dst,char *name);
  379.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   380.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   380.2 +++ b/src/osdep/unix/env_unix.c	Mon Sep 14 15:17:45 2009 +0900
   380.3 @@ -0,0 +1,1847 @@
   380.4 +/* ========================================================================
   380.5 + * Copyright 1988-2008 University of Washington
   380.6 + *
   380.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   380.8 + * you may not use this file except in compliance with the License.
   380.9 + * You may obtain a copy of the License at
  380.10 + *
  380.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  380.12 + *
  380.13 + * 
  380.14 + * ========================================================================
  380.15 + */
  380.16 +
  380.17 +/*
  380.18 + * Program:	UNIX environment routines
  380.19 + *
  380.20 + * Author:	Mark Crispin
  380.21 + *		UW Technology
  380.22 + *		University of Washington
  380.23 + *		Seattle, WA  98195
  380.24 + *		Internet: MRC@Washington.EDU
  380.25 + *
  380.26 + * Date:	1 August 1988
  380.27 + * Last Edited:	15 May 2008
  380.28 + */
  380.29 +
  380.30 +#include <grp.h>
  380.31 +#include <signal.h>
  380.32 +#include <sys/wait.h>
  380.33 +
  380.34 +
  380.35 +/* in case stat.h is ancient */
  380.36 +
  380.37 +#ifndef S_IRUSR
  380.38 +#define S_IRUSR S_IREAD
  380.39 +#endif
  380.40 +#ifndef S_IWUSR
  380.41 +#define S_IWUSR S_IWRITE
  380.42 +#endif
  380.43 +#ifndef S_IXUSR
  380.44 +#define S_IXUSR S_IEXEC
  380.45 +#endif
  380.46 +#ifndef S_IRGRP
  380.47 +#define S_IRGRP (S_IREAD >> 3)
  380.48 +#endif
  380.49 +#ifndef S_IWGRP
  380.50 +#define S_IWGRP (S_IWRITE >> 3)
  380.51 +#endif
  380.52 +#ifndef S_IXGRP
  380.53 +#define S_IXGRP (S_IEXEC >> 3)
  380.54 +#endif
  380.55 +#ifndef S_IROTH
  380.56 +#define S_IROTH (S_IREAD >> 6)
  380.57 +#endif
  380.58 +#ifndef S_IWOTH
  380.59 +#define S_IWOTH (S_IWRITE >> 6)
  380.60 +#endif
  380.61 +#ifndef S_IXOTH
  380.62 +#define S_IXOTH (S_IEXEC >> 6)
  380.63 +#endif
  380.64 +
  380.65 +/* c-client environment parameters */
  380.66 +
  380.67 +static char *myUserName = NIL;	/* user name */
  380.68 +static char *myHomeDir = NIL;	/* home directory name */
  380.69 +static char *myServerName = NIL;/* server name */
  380.70 +static char *myLocalHost = NIL;	/* local host name */
  380.71 +static char *myNewsrc = NIL;	/* newsrc file name */
  380.72 +static char *mailsubdir = NIL;	/* mailbox subdirectory name */
  380.73 +static char *sysInbox = NIL;	/* system inbox name */
  380.74 +static char *newsActive = NIL;	/* news active file */
  380.75 +static char *newsSpool = NIL;	/* news spool */
  380.76 +static char *blackBoxDir = NIL;	/* black box directory name */
  380.77 +				/* black box default home directory */
  380.78 +static char *blackBoxDefaultHome = NIL;
  380.79 +static char *sslCApath = NIL;	/* non-standard CA path */
  380.80 +static short anonymous = NIL;	/* is anonymous */
  380.81 +static short blackBox = NIL;	/* is a black box */
  380.82 +static short closedBox = NIL;	/* is a closed box (uses chroot() jail) */
  380.83 +static short restrictBox = NIL;	/* is a restricted box */
  380.84 +static short has_no_life = NIL;	/* is a cretin with no life */
  380.85 +				/* block environment init */
  380.86 +static short block_env_init = NIL;
  380.87 +static short hideDotFiles = NIL;/* hide files whose names start with . */
  380.88 +				/* advertise filesystem root */
  380.89 +static short advertisetheworld = NIL;
  380.90 +				/* only advertise own mailboxes and #shared */
  380.91 +static short limitedadvertise = NIL;
  380.92 +				/* disable automatic shared namespaces */
  380.93 +static short noautomaticsharedns = NIL;
  380.94 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  380.95 +				/* client principals include service name */
  380.96 +static short kerb_cp_svr_name = NIL;
  380.97 +static long locktimeout = 5;	/* default lock timeout in minutes */
  380.98 +				/* default prototypes */
  380.99 +static MAILSTREAM *createProto = NIL;
 380.100 +static MAILSTREAM *appendProto = NIL;
 380.101 +				/* default user flags */
 380.102 +static char *userFlags[NUSERFLAGS] = {NIL};
 380.103 +static NAMESPACE *nslist[3];	/* namespace list */
 380.104 +static int logtry = 3;		/* number of server login tries */
 380.105 +				/* block notification */
 380.106 +static blocknotify_t mailblocknotify = mm_blocknotify;
 380.107 +				/* logout function */
 380.108 +static logouthook_t maillogouthook = NIL;
 380.109 +				/* logout data */
 380.110 +static void *maillogoutdata = NIL;
 380.111 +				/* allow user config files */
 380.112 +static short allowuserconfig = NIL;
 380.113 +				/* 1 = disable plaintext, 2 = if not SSL */
 380.114 +static long disablePlaintext = NIL;
 380.115 +static long list_max_level = 20;/* maximum level of list recursion */
 380.116 +				/* facility for syslog */
 380.117 +static int syslog_facility = LOG_MAIL;
 380.118 +
 380.119 +/* Path of the privileged system lock program (mlock).  Normally set by
 380.120 + * logic test.
 380.121 + */
 380.122 +
 380.123 +static char *lockpgm = LOCKPGM;
 380.124 +
 380.125 +/* Directory used for shared locks.  MUST be the same for all users of the
 380.126 + * system, and MUST be protected 1777.  /var/tmp may be preferable on some
 380.127 + * systems.
 380.128 + */
 380.129 +
 380.130 +static const char *tmpdir = "/tmp";
 380.131 +
 380.132 +/* Do not change shlock_mode.  Doing so can cause mailbox corruption and
 380.133 + * denial of service.  It also defeats the entire purpose of the shared
 380.134 + * lock mechanism.  The right way to avoid shared locks is to set up a
 380.135 + * closed box (see the closedBox setting).
 380.136 + */
 380.137 +
 380.138 +				/* shared lock mode */
 380.139 +static const int shlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
 380.140 +
 380.141 +
 380.142 +/* It is STRONGLY recommended that you do not change dotlock_mode.  Doing so
 380.143 + * can cause denial of service with old dot-lock files left lying around.
 380.144 + * However, since dot-locks are only used with traditional UNIX and MMDF
 380.145 + * formats which are not normally shared, it is much less harmful to tamper
 380.146 + * with this than with shlock_mode.
 380.147 + */
 380.148 +
 380.149 +				/* dot-lock mode */
 380.150 +static long dotlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
 380.151 +
 380.152 +/* File/directory access and protection policies */
 380.153 +
 380.154 +/* Unlike shlock_mode, the ????_protection modes are intended to be fully
 380.155 + * customizable according to site policy.  The values here are recommended
 380.156 + * settings, based upon the documented purposes of the namespaces.
 380.157 + */
 380.158 +
 380.159 +	/* user space - only owner can read/write */
 380.160 +static char *myMailboxDir = NIL;/* user space directory name */
 380.161 +				/* default file protection */
 380.162 +static long mbx_protection = S_IRUSR|S_IWUSR;
 380.163 +				/* default directory protection */
 380.164 +static long dir_protection = S_IRUSR|S_IWUSR|S_IXUSR;
 380.165 +
 380.166 +	/* user space for user "anonymous" */
 380.167 +				/* anonymous home directory */
 380.168 +static char *anonymousHome = NIL;
 380.169 +
 380.170 +	/* #ftp - everybody can read, only owner can write */
 380.171 +static char *ftpHome = NIL;	/* ftp export home directory */
 380.172 +				/* default ftp file protection */
 380.173 +static long ftp_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
 380.174 +static long ftp_dir_protection =/* default ftp directory protection */
 380.175 +  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
 380.176 +
 380.177 +	/* #public - everybody can read/write */
 380.178 +static char *publicHome = NIL;	/* public home directory */
 380.179 +static long public_protection =	/* default public file protection */
 380.180 +  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
 380.181 +				/* default public directory protection */
 380.182 +static long public_dir_protection =
 380.183 +  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
 380.184 +
 380.185 +	/* #shared/ - owner and group members can read/write */
 380.186 +static char *sharedHome = NIL;	/* shared home directory */
 380.187 +				/* default shared file protection */
 380.188 +static long shared_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
 380.189 +				/* default shared directory protection */
 380.190 +static long shared_dir_protection =
 380.191 +  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP;
 380.192 +
 380.193 +/* OS bug workarounds - should be avoided at all cost */
 380.194 +
 380.195 +
 380.196 +/* Don't set fcntlhangbug unless you really have to, since it risks mailbox
 380.197 + * corruption.  The flocksim.c mechanism is designed to detect NFS access
 380.198 + * and no-op in that cases only, so this flag should be unnecessary.
 380.199 + */
 380.200 +
 380.201 +static short fcntlhangbug = NIL;/* flock() emulator using fcntl() is a no-op */
 380.202 +
 380.203 +
 380.204 +/* Don't set netfsstatbug unless you really have to, since it dramatically
 380.205 + * slows down traditional UNIX and MMDF mailbox performance.
 380.206 + */
 380.207 +
 380.208 +static short netfsstatbug = NIL;/* compensate for broken stat() on network
 380.209 +				 * filesystems (AFS and old NFS)
 380.210 +				 */
 380.211 +
 380.212 +
 380.213 +/* Note: setting disableLockWarning means that you assert that the
 380.214 + * so-modified copy of this software will NEVER be used:
 380.215 + *  1) in conjunction with any software which expects .lock files
 380.216 + *  2) to access NFS-mounted files and directories
 380.217 + *
 380.218 + * Unless both of these conditions apply, then do not set this flag.
 380.219 + * Instead, read the FAQ (item 7.10) and either use 1777 protection
 380.220 + * on the mail spool, or install mlock.
 380.221 + *
 380.222 + * In addition, by setting this flag you also agree that you are fully
 380.223 + * legally and morally responsible when (not if) mail files are damaged
 380.224 + * as the result of your choice.
 380.225 + *
 380.226 + * The mlock tool exists for a reason.  Use it.
 380.227 + */
 380.228 +				/* disable warning if can't make .lock file */
 380.229 +static short disableLockWarning = NIL;
 380.230 +
 380.231 +/* UNIX Namespaces */
 380.232 +
 380.233 +				/* personal mh namespace */
 380.234 +static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
 380.235 +static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
 380.236 +				/* home namespace */
 380.237 +static NAMESPACE nshome = {"",'/',NIL,&nsmh};
 380.238 +				/* UNIX other user namespace */
 380.239 +static NAMESPACE nsunixother = {"~",'/',NIL,NIL};
 380.240 +				/* black box other user namespace */
 380.241 +static NAMESPACE nsblackother = {"/",'/',NIL,NIL};
 380.242 +				/* public (anonymous OK) namespace */
 380.243 +static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
 380.244 +				/* netnews namespace */
 380.245 +static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
 380.246 +				/* FTP export namespace */
 380.247 +static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
 380.248 +				/* shared (no anonymous) namespace */
 380.249 +static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
 380.250 +				/* world namespace */
 380.251 +static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
 380.252 +				/* only shared and public namespaces */
 380.253 +static NAMESPACE nslimited = {"#shared/",'/',NIL,&nspublic};
 380.254 +
 380.255 +
 380.256 +
 380.257 +#include "write.c"		/* include safe writing routines */
 380.258 +#include "crexcl.c"		/* include exclusive create */
 380.259 +#include "pmatch.c"		/* include wildcard pattern matcher */
 380.260 +
 380.261 +/* Get all authenticators */
 380.262 +
 380.263 +#include "auths.c"
 380.264 +
 380.265 +/* Environment manipulate parameters
 380.266 + * Accepts: function code
 380.267 + *	    function-dependent value
 380.268 + * Returns: function-dependent return value
 380.269 + */
 380.270 +
 380.271 +void *env_parameters (long function,void *value)
 380.272 +{
 380.273 +  void *ret = NIL;
 380.274 +  switch ((int) function) {
 380.275 +  case GET_NAMESPACE:
 380.276 +    ret = (void *) nslist;
 380.277 +    break;
 380.278 +  case SET_USERNAME:
 380.279 +    if (myUserName) fs_give ((void **) &myUserName);
 380.280 +    myUserName = cpystr ((char *) value);
 380.281 +  case GET_USERNAME:
 380.282 +    ret = (void *) myUserName;
 380.283 +    break;
 380.284 +  case SET_HOMEDIR:
 380.285 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
 380.286 +    myHomeDir = cpystr ((char *) value);
 380.287 +  case GET_HOMEDIR:
 380.288 +    ret = (void *) myHomeDir;
 380.289 +    break;
 380.290 +  case SET_LOCALHOST:
 380.291 +    if (myLocalHost) fs_give ((void **) &myLocalHost);
 380.292 +    myLocalHost = cpystr ((char *) value);
 380.293 +  case GET_LOCALHOST:
 380.294 +    ret = (void *) myLocalHost;
 380.295 +    break;
 380.296 +  case SET_NEWSRC:
 380.297 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
 380.298 +    myNewsrc = cpystr ((char *) value);
 380.299 +  case GET_NEWSRC:
 380.300 +    ret = (void *) myNewsrc;
 380.301 +    break;
 380.302 +  case SET_NEWSACTIVE:
 380.303 +    if (newsActive) fs_give ((void **) &newsActive);
 380.304 +    newsActive = cpystr ((char *) value);
 380.305 +  case GET_NEWSACTIVE:
 380.306 +    ret = (void *) newsActive;
 380.307 +    break;
 380.308 +  case SET_NEWSSPOOL:
 380.309 +    if (newsSpool) fs_give ((void **) &newsSpool);
 380.310 +    newsSpool = cpystr ((char *) value);
 380.311 +  case GET_NEWSSPOOL:
 380.312 +    ret = (void *) newsSpool;
 380.313 +    break;
 380.314 +
 380.315 +  case SET_ANONYMOUSHOME:
 380.316 +    if (anonymousHome) fs_give ((void **) &anonymousHome);
 380.317 +    anonymousHome = cpystr ((char *) value);
 380.318 +  case GET_ANONYMOUSHOME:
 380.319 +    if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
 380.320 +    ret = (void *) anonymousHome;
 380.321 +    break;
 380.322 +  case SET_FTPHOME:
 380.323 +    if (ftpHome) fs_give ((void **) &ftpHome);
 380.324 +    ftpHome = cpystr ((char *) value);
 380.325 +  case GET_FTPHOME:
 380.326 +    ret = (void *) ftpHome;
 380.327 +    break;
 380.328 +  case SET_PUBLICHOME:
 380.329 +    if (publicHome) fs_give ((void **) &publicHome);
 380.330 +    publicHome = cpystr ((char *) value);
 380.331 +  case GET_PUBLICHOME:
 380.332 +    ret = (void *) publicHome;
 380.333 +    break;
 380.334 +  case SET_SHAREDHOME:
 380.335 +    if (sharedHome) fs_give ((void **) &sharedHome);
 380.336 +    sharedHome = cpystr ((char *) value);
 380.337 +  case GET_SHAREDHOME:
 380.338 +    ret = (void *) sharedHome;
 380.339 +    break;
 380.340 +  case SET_SYSINBOX:
 380.341 +    if (sysInbox) fs_give ((void **) &sysInbox);
 380.342 +    sysInbox = cpystr ((char *) value);
 380.343 +  case GET_SYSINBOX:
 380.344 +    ret = (void *) sysInbox;
 380.345 +    break;
 380.346 +  case SET_SSLCAPATH:		/* this can be set null */
 380.347 +    if (sslCApath) fs_give ((void **) &sslCApath);
 380.348 +    sslCApath = value ? cpystr ((char *) value) : value;
 380.349 +    break;
 380.350 +  case GET_SSLCAPATH:
 380.351 +    ret = (void *) sslCApath;
 380.352 +    break;
 380.353 +  case SET_LISTMAXLEVEL:
 380.354 +    list_max_level = (long) value;
 380.355 +  case GET_LISTMAXLEVEL:
 380.356 +    ret = (void *) list_max_level;
 380.357 +    break;
 380.358 +
 380.359 +  case SET_MBXPROTECTION:
 380.360 +    mbx_protection = (long) value;
 380.361 +  case GET_MBXPROTECTION:
 380.362 +    ret = (void *) mbx_protection;
 380.363 +    break;
 380.364 +  case SET_DIRPROTECTION:
 380.365 +    dir_protection = (long) value;
 380.366 +  case GET_DIRPROTECTION:
 380.367 +    ret = (void *) dir_protection;
 380.368 +    break;
 380.369 +  case SET_LOCKPROTECTION:
 380.370 +    dotlock_mode = (long) value;
 380.371 +  case GET_LOCKPROTECTION:
 380.372 +    ret = (void *) dotlock_mode;
 380.373 +    break;
 380.374 +  case SET_FTPPROTECTION:
 380.375 +    ftp_protection = (long) value;
 380.376 +  case GET_FTPPROTECTION:
 380.377 +    ret = (void *) ftp_protection;
 380.378 +    break;
 380.379 +  case SET_PUBLICPROTECTION:
 380.380 +    public_protection = (long) value;
 380.381 +  case GET_PUBLICPROTECTION:
 380.382 +    ret = (void *) public_protection;
 380.383 +    break;
 380.384 +  case SET_SHAREDPROTECTION:
 380.385 +    shared_protection = (long) value;
 380.386 +  case GET_SHAREDPROTECTION:
 380.387 +    ret = (void *) shared_protection;
 380.388 +    break;
 380.389 +  case SET_FTPDIRPROTECTION:
 380.390 +    ftp_dir_protection = (long) value;
 380.391 +  case GET_FTPDIRPROTECTION:
 380.392 +    ret = (void *) ftp_dir_protection;
 380.393 +    break;
 380.394 +  case SET_PUBLICDIRPROTECTION:
 380.395 +    public_dir_protection = (long) value;
 380.396 +  case GET_PUBLICDIRPROTECTION:
 380.397 +    ret = (void *) public_dir_protection;
 380.398 +    break;
 380.399 +  case SET_SHAREDDIRPROTECTION:
 380.400 +    shared_dir_protection = (long) value;
 380.401 +  case GET_SHAREDDIRPROTECTION:
 380.402 +    ret = (void *) shared_dir_protection;
 380.403 +    break;
 380.404 +
 380.405 +  case SET_LOCKTIMEOUT:
 380.406 +    locktimeout = (long) value;
 380.407 +  case GET_LOCKTIMEOUT:
 380.408 +    ret = (void *) locktimeout;
 380.409 +    break;
 380.410 +  case SET_DISABLEFCNTLLOCK:
 380.411 +    fcntlhangbug = value ? T : NIL;
 380.412 +  case GET_DISABLEFCNTLLOCK:
 380.413 +    ret = (void *) (fcntlhangbug ? VOIDT : NIL);
 380.414 +    break;
 380.415 +  case SET_LOCKEACCESERROR:
 380.416 +    disableLockWarning = value ? NIL : T;
 380.417 +  case GET_LOCKEACCESERROR:
 380.418 +    ret = (void *) (disableLockWarning ? NIL : VOIDT);
 380.419 +    break;
 380.420 +  case SET_HIDEDOTFILES:
 380.421 +    hideDotFiles = value ? T : NIL;
 380.422 +  case GET_HIDEDOTFILES:
 380.423 +    ret = (void *) (hideDotFiles ? VOIDT : NIL);
 380.424 +    break;
 380.425 +  case SET_DISABLEPLAINTEXT:
 380.426 +    disablePlaintext = (long) value;
 380.427 +  case GET_DISABLEPLAINTEXT:
 380.428 +    ret = (void *) disablePlaintext;
 380.429 +    break;
 380.430 +  case SET_CHROOTSERVER:
 380.431 +    closedBox = value ? T : NIL;
 380.432 +  case GET_CHROOTSERVER:
 380.433 +    ret = (void *) (closedBox ? VOIDT : NIL);
 380.434 +    break;
 380.435 +  case SET_ADVERTISETHEWORLD:
 380.436 +    advertisetheworld = value ? T : NIL;
 380.437 +  case GET_ADVERTISETHEWORLD:
 380.438 +    ret = (void *) (advertisetheworld ? VOIDT : NIL);
 380.439 +    break;
 380.440 +  case SET_LIMITEDADVERTISE:
 380.441 +    limitedadvertise = value ? T : NIL;
 380.442 +  case GET_LIMITEDADVERTISE:
 380.443 +    ret = (void *) (limitedadvertise ? VOIDT : NIL);
 380.444 +    break;
 380.445 +  case SET_DISABLEAUTOSHAREDNS:
 380.446 +    noautomaticsharedns = value ? T : NIL;
 380.447 +  case GET_DISABLEAUTOSHAREDNS:
 380.448 +    ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
 380.449 +    break;
 380.450 +  case SET_DISABLE822TZTEXT:
 380.451 +    no822tztext = value ? T : NIL;
 380.452 +  case GET_DISABLE822TZTEXT:
 380.453 +    ret = (void *) (no822tztext ? VOIDT : NIL);
 380.454 +    break;
 380.455 +
 380.456 +  case SET_USERHASNOLIFE:
 380.457 +    has_no_life = value ? T : NIL;
 380.458 +  case GET_USERHASNOLIFE:
 380.459 +    ret = (void *) (has_no_life ? VOIDT : NIL);
 380.460 +    break;
 380.461 +  case SET_KERBEROS_CP_SVR_NAME:
 380.462 +    kerb_cp_svr_name = value ? T : NIL;
 380.463 +  case GET_KERBEROS_CP_SVR_NAME:
 380.464 +    ret = (void *) (kerb_cp_svr_name ? VOIDT : NIL);
 380.465 +    break;
 380.466 +  case SET_NETFSSTATBUG:
 380.467 +    netfsstatbug = value ? T : NIL;
 380.468 +  case GET_NETFSSTATBUG:
 380.469 +    ret = (void *) (netfsstatbug ? VOIDT : NIL);
 380.470 +    break;
 380.471 +  case SET_BLOCKENVINIT:
 380.472 +    block_env_init = value ? T : NIL;
 380.473 +  case GET_BLOCKENVINIT:
 380.474 +    ret = (void *) (block_env_init ? VOIDT : NIL);
 380.475 +    break;
 380.476 +  case SET_BLOCKNOTIFY:
 380.477 +    mailblocknotify = (blocknotify_t) value;
 380.478 +  case GET_BLOCKNOTIFY:
 380.479 +    ret = (void *) mailblocknotify;
 380.480 +    break;
 380.481 +  case SET_LOGOUTHOOK:
 380.482 +    maillogouthook = (logouthook_t) value;
 380.483 +  case GET_LOGOUTHOOK:
 380.484 +    ret = maillogouthook;
 380.485 +    break;
 380.486 +  case SET_LOGOUTDATA:
 380.487 +    maillogoutdata = (void *) value;
 380.488 +  case GET_LOGOUTDATA:
 380.489 +    ret = maillogoutdata;
 380.490 +  }
 380.491 +  return ret;
 380.492 +}
 380.493 +
 380.494 +/* Write current time
 380.495 + * Accepts: destination string
 380.496 + *	    optional format of day-of-week prefix
 380.497 + *	    format of date and time
 380.498 + *	    flag whether to append symbolic timezone
 380.499 + */
 380.500 +
 380.501 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
 380.502 +{
 380.503 +  time_t tn = time (0);
 380.504 +  struct tm *t = gmtime (&tn);
 380.505 +  int zone = t->tm_hour * 60 + t->tm_min;
 380.506 +  int julian = t->tm_yday;
 380.507 +  t = localtime (&tn);		/* get local time now */
 380.508 +				/* minus UTC minutes since midnight */
 380.509 +  zone = t->tm_hour * 60 + t->tm_min - zone;
 380.510 +  /* julian can be one of:
 380.511 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
 380.512 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
 380.513 +   *    0  local time is same day as UTC, no offset
 380.514 +   *   -1  local time is 1 day behind UTC, offset -24 hours
 380.515 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
 380.516 +   */
 380.517 +  if (julian = t->tm_yday -julian)
 380.518 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
 380.519 +  if (prefix) {			/* want day of week? */
 380.520 +    sprintf (date,prefix,days[t->tm_wday]);
 380.521 +    date += strlen (date);	/* make next sprintf append */
 380.522 +  }
 380.523 +				/* output the date */
 380.524 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 380.525 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
 380.526 +				/* append timezone suffix if desired */
 380.527 +  if (suffix) rfc822_timezone (date,(void *) t);
 380.528 +}
 380.529 +
 380.530 +/* Write current time in RFC 822 format
 380.531 + * Accepts: destination string
 380.532 + */
 380.533 +
 380.534 +void rfc822_date (char *date)
 380.535 +{
 380.536 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
 380.537 +	   no822tztext ? NIL : T);
 380.538 +}
 380.539 +
 380.540 +
 380.541 +/* Write current time in fixed-width RFC 822 format
 380.542 + * Accepts: destination string
 380.543 + */
 380.544 +
 380.545 +void rfc822_fixed_date (char *date)
 380.546 +{
 380.547 +  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
 380.548 +}
 380.549 +
 380.550 +
 380.551 +/* Write current time in internal format
 380.552 + * Accepts: destination string
 380.553 + */
 380.554 +
 380.555 +void internal_date (char *date)
 380.556 +{
 380.557 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
 380.558 +}
 380.559 +
 380.560 +/* Initialize server
 380.561 + * Accepts: server name for syslog or NIL
 380.562 + *	    /etc/services service name or NIL
 380.563 + *	    alternate /etc/services service name or NIL
 380.564 + *	    clock interrupt handler
 380.565 + *	    kiss-of-death interrupt handler
 380.566 + *	    hangup interrupt handler
 380.567 + *	    termination interrupt handler
 380.568 + */
 380.569 +
 380.570 +void server_init (char *server,char *service,char *sslservice,
 380.571 +		  void *clkint,void *kodint,void *hupint,void *trmint,
 380.572 +		  void *staint)
 380.573 +{
 380.574 +  int onceonly = server && service && sslservice;
 380.575 +  if (onceonly) {		/* set server name in syslog */
 380.576 +    int mask;
 380.577 +    openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
 380.578 +    fclose (stderr);		/* possibly save a process ID */
 380.579 +    dorc (NIL,NIL);		/* do systemwide configuration */
 380.580 +    switch (mask = umask (022)){/* check old umask */
 380.581 +    case 0:			/* definitely unreasonable */
 380.582 +    case 022:			/* don't need to change it */
 380.583 +      break;
 380.584 +    default:			/* already was a reasonable value */
 380.585 +      umask (mask);		/* so change it back */
 380.586 +    }
 380.587 +  }
 380.588 +  arm_signal (SIGALRM,clkint);	/* prepare for clock interrupt */
 380.589 +  arm_signal (SIGUSR2,kodint);	/* prepare for Kiss Of Death */
 380.590 +  arm_signal (SIGHUP,hupint);	/* prepare for hangup */
 380.591 +  arm_signal (SIGPIPE,hupint);	/* alternative hangup */
 380.592 +  arm_signal (SIGTERM,trmint);	/* prepare for termination */
 380.593 +				/* status dump */
 380.594 +  if (staint) arm_signal (SIGUSR1,staint);
 380.595 +  if (onceonly) {		/* set up network and maybe SSL */
 380.596 +    long port;
 380.597 +    struct servent *sv;
 380.598 +    /* Use SSL if SSL service, or if server starts with "s" and not service */
 380.599 +    if (((port = tcp_serverport ()) >= 0)) {
 380.600 +      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
 380.601 +	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
 380.602 +      else if ((sv = getservbyname (sslservice,"tcp")) &&
 380.603 +	       (port == ntohs (sv->s_port))) {
 380.604 +	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
 380.605 +		tcp_clientaddr ());
 380.606 +	ssl_server_init (server);
 380.607 +      }
 380.608 +      else {			/* not service or SSL service port */
 380.609 +	syslog (LOG_DEBUG,"port %ld service init from %s",port,
 380.610 +		tcp_clientaddr ());
 380.611 +	if (*server == 's') ssl_server_init (server);
 380.612 +      }
 380.613 +    }
 380.614 +  }
 380.615 +}
 380.616 +
 380.617 +/* Wait for stdin input
 380.618 + * Accepts: timeout in seconds
 380.619 + * Returns: T if have input on stdin, else NIL
 380.620 + */
 380.621 +
 380.622 +long server_input_wait (long seconds)
 380.623 +{
 380.624 +  fd_set rfd,efd;
 380.625 +  struct timeval tmo;
 380.626 +  FD_ZERO (&rfd);
 380.627 +  FD_ZERO (&efd);
 380.628 +  FD_SET (0,&rfd);
 380.629 +  FD_SET (0,&efd);
 380.630 +  tmo.tv_sec = seconds; tmo.tv_usec = 0;
 380.631 +  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
 380.632 +}
 380.633 +
 380.634 +/* Return UNIX password entry for user name
 380.635 + * Accepts: user name string
 380.636 + * Returns: password entry
 380.637 + *
 380.638 + * Tries all-lowercase form of user name if given user name fails
 380.639 + */
 380.640 +
 380.641 +static struct passwd *pwuser (unsigned char *user)
 380.642 +{
 380.643 +  unsigned char *s;
 380.644 +  struct passwd *pw = getpwnam (user);
 380.645 +  if (!pw) {			/* failed, see if any uppercase characters */
 380.646 +    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
 380.647 +    if (*s) {			/* yes, try all lowercase form */
 380.648 +      pw = getpwnam (s = lcase (cpystr (user)));
 380.649 +      fs_give ((void **) &s);
 380.650 +    }
 380.651 +  }
 380.652 +  return pw;
 380.653 +}
 380.654 +
 380.655 +
 380.656 +/* Validate password for user name
 380.657 + * Accepts: user name string
 380.658 + *	    password string
 380.659 + *	    argument count
 380.660 + *	    argument vector
 380.661 + * Returns: password entry if validated
 380.662 + *
 380.663 + * Tries password+1 if password fails and starts with space
 380.664 + */
 380.665 +
 380.666 +static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
 380.667 +{
 380.668 +  char *s;
 380.669 +  struct passwd *pw;
 380.670 +  struct passwd *ret = NIL;
 380.671 +  if (auth_md5.server) {	/* using CRAM-MD5 authentication? */
 380.672 +    if (s = auth_md5_pwd (user)) {
 380.673 +      if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
 380.674 +	ret = pwuser (user);	/* validated, get passwd entry for user */
 380.675 +      memset (s,0,strlen (s));	/* erase sensitive information */
 380.676 +      fs_give ((void **) &s);
 380.677 +    }
 380.678 +  }
 380.679 +  else if (pw = pwuser (user)) {/* can get user? */
 380.680 +    s = cpystr (pw->pw_name);	/* copy returned name in case we need it */
 380.681 +    if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
 380.682 +	(*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
 380.683 +      ret = checkpw (pw,pwd+1,argc,argv);
 380.684 +    fs_give ((void **) &s);	/* don't need copy of name any more */
 380.685 +  }
 380.686 +  return ret;
 380.687 +}
 380.688 +
 380.689 +/* Server log in
 380.690 + * Accepts: user name string
 380.691 + *	    password string
 380.692 + *	    authenticating user name string
 380.693 + *	    argument count
 380.694 + *	    argument vector
 380.695 + * Returns: T if password validated, NIL otherwise
 380.696 + */
 380.697 +
 380.698 +long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
 380.699 +{
 380.700 +  struct passwd *pw = NIL;
 380.701 +  int level = LOG_NOTICE;
 380.702 +  char *err = "failed";
 380.703 +				/* cretins still haven't given up */
 380.704 +  if ((strlen (user) >= NETMAXUSER) ||
 380.705 +      (authuser && (strlen (authuser) >= NETMAXUSER))) {
 380.706 +    level = LOG_ALERT;		/* escalate this alert */
 380.707 +    err = "SYSTEM BREAK-IN ATTEMPT";
 380.708 +    logtry = 0;			/* render this session useless */
 380.709 +  }
 380.710 +  else if (logtry-- <= 0) err = "excessive login failures";
 380.711 +  else if (disablePlaintext) err = "disabled";
 380.712 +  else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
 380.713 +  else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
 380.714 +  if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
 380.715 +  syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
 380.716 +	  user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
 380.717 +  sleep (3);			/* slow down possible cracker */
 380.718 +  return NIL;
 380.719 +}
 380.720 +
 380.721 +/* Authenticated server log in
 380.722 + * Accepts: user name string
 380.723 + *	    authenticating user name string
 380.724 + *	    argument count
 380.725 + *	    argument vector
 380.726 + * Returns: T if password validated, NIL otherwise
 380.727 + */
 380.728 +
 380.729 +long authserver_login (char *user,char *authuser,int argc,char *argv[])
 380.730 +{
 380.731 +  return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
 380.732 +}
 380.733 +
 380.734 +
 380.735 +/* Log in as anonymous daemon
 380.736 + * Accepts: argument count
 380.737 + *	    argument vector
 380.738 + * Returns: T if successful, NIL if error
 380.739 + */
 380.740 +
 380.741 +long anonymous_login (int argc,char *argv[])
 380.742 +{
 380.743 +				/* log in Mr. A. N. Onymous */
 380.744 +  return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
 380.745 +		   (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
 380.746 +		   argc,argv);
 380.747 +}
 380.748 +
 380.749 +/* Finish log in and environment initialization
 380.750 + * Accepts: passwd struct for loginpw()
 380.751 + *	    optional authentication user name
 380.752 + *	    user name (NIL for anonymous)
 380.753 + *	    home directory (NIL to use directory from passwd struct)
 380.754 + *	    argument count
 380.755 + *	    argument vector
 380.756 + * Returns: T if successful, NIL if error
 380.757 + */
 380.758 +
 380.759 +long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
 380.760 +	       char *argv[])
 380.761 +{
 380.762 +  struct group *gr;
 380.763 +  char **t;
 380.764 +  long ret = NIL;
 380.765 +  if (pw && pw->pw_uid) {	/* must have passwd struct for non-UID 0 */
 380.766 +				/* make safe copies of user and home */
 380.767 +    if (user) user = cpystr (pw->pw_name);
 380.768 +    home = cpystr (home ? home : pw->pw_dir);
 380.769 +				/* authorization ID .NE. authentication ID? */
 380.770 +    if (user && auser && *auser && compare_cstring (auser,user)) {
 380.771 +				/* scan list of mail administrators */
 380.772 +      if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
 380.773 +	if (!compare_cstring (auser,*t++))
 380.774 +	  ret = pw_login (pw,NIL,user,home,argc,argv);
 380.775 +      syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
 380.776 +	      ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
 380.777 +    }
 380.778 +    else if (closedBox) {	/* paranoid site, lock out other directories */
 380.779 +      if (chdir (home) || chroot (home))
 380.780 +	syslog (LOG_NOTICE|LOG_AUTH,
 380.781 +		"Login %s failed: unable to set chroot=%.80s host=%.80s",
 380.782 +		pw->pw_name,home,tcp_clienthost ());
 380.783 +      else if (loginpw (pw,argc,argv)) ret = env_init (user,NIL);
 380.784 +      else fatal ("Login failed after chroot");
 380.785 +    }
 380.786 +				/* normal login */
 380.787 +    else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
 380.788 +	     (ret = env_init (user,home))) chdir (myhomedir ());
 380.789 +    fs_give ((void **) &home);	/* clean up */
 380.790 +    if (user) fs_give ((void **) &user);
 380.791 +  }
 380.792 +  endpwent ();			/* in case shadow passwords in pw data */
 380.793 +  return ret;			/* return status */
 380.794 +}
 380.795 +
 380.796 +/* Initialize environment
 380.797 + * Accepts: user name (NIL for anonymous)
 380.798 + *	    home directory name
 380.799 + * Returns: T, always
 380.800 + */
 380.801 +
 380.802 +long env_init (char *user,char *home)
 380.803 +{
 380.804 +  extern MAILSTREAM CREATEPROTO;
 380.805 +  extern MAILSTREAM EMPTYPROTO;
 380.806 +  struct passwd *pw;
 380.807 +  struct stat sbuf;
 380.808 +  char tmp[MAILTMPLEN];
 380.809 +				/* don't init if blocked */
 380.810 +  if (block_env_init) return LONGT;
 380.811 +  if (myUserName) fatal ("env_init called twice!");
 380.812 +				/* initially nothing in namespace list */
 380.813 +  nslist[0] = nslist[1] = nslist[2] = NIL;
 380.814 +				/* myUserName must be set before dorc() call */
 380.815 +  myUserName = cpystr (user ? user : ANONYMOUSUSER);
 380.816 +				/* force default prototypes to be set */
 380.817 +  if (!createProto) createProto = &CREATEPROTO;
 380.818 +  if (!appendProto) appendProto = &EMPTYPROTO;
 380.819 +  dorc (NIL,NIL);		/* do systemwide configuration */
 380.820 +  if (!home) {			/* closed box server */
 380.821 +				/* standard user can only reference home */
 380.822 +    if (user) nslist[0] = &nshome;
 380.823 +    else {			/* anonymous user */
 380.824 +      nslist[0] = &nsblackother; /* set root */
 380.825 +      anonymous = T;		/* flag as anonymous */
 380.826 +    }
 380.827 +    myHomeDir = cpystr ("");	/* home directory is root */
 380.828 +    sysInbox = cpystr ("INBOX");/* make system INBOX */
 380.829 +  }
 380.830 +  else {			/* open or black box */
 380.831 +    closedBox = NIL;		/* definitely not a closed box */
 380.832 +    if (user) {			/* remember user name and home directory */
 380.833 +      if (blackBoxDir) {	/* build black box directory name */
 380.834 +	sprintf (tmp,"%s/%s",blackBoxDir,myUserName);
 380.835 +				/* must exist */
 380.836 +	if (!((!stat (home = tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ||
 380.837 +	      (blackBoxDefaultHome &&
 380.838 +	       !stat (home = blackBoxDefaultHome,&sbuf) &&
 380.839 +	       (sbuf.st_mode & S_IFDIR)))) fatal ("no home");
 380.840 +	sysInbox = (char *) fs_get (strlen (home) + 7);
 380.841 +				/* set system INBOX */
 380.842 +	sprintf (sysInbox,"%s/INBOX",home);
 380.843 +	blackBox = T;		/* mark that it's a black box */
 380.844 +				/* mbox meaningless if black box */
 380.845 +	mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox");
 380.846 +      }
 380.847 +      nslist[0] = &nshome;	/* home namespace */
 380.848 +				/* limited advertise namespaces */
 380.849 +      if (limitedadvertise) nslist[2] = &nslimited;
 380.850 +      else if (blackBox) {	/* black box namespaces */
 380.851 +	nslist[1] = &nsblackother;
 380.852 +	nslist[2] = &nsshared;
 380.853 +      }
 380.854 +      else {			/* open box namespaces */
 380.855 +	nslist[1] = &nsunixother;
 380.856 +	nslist[2] = advertisetheworld ? &nsworld : &nsshared;
 380.857 +      }
 380.858 +    }
 380.859 +    else {
 380.860 +      nslist[2] = &nsftp;	/* anonymous user */
 380.861 +      sprintf (tmp,"%s/INBOX",
 380.862 +	       home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
 380.863 +      sysInbox = cpystr (tmp);	/* make system INBOX */
 380.864 +      anonymous = T;		/* flag as anonymous */
 380.865 +    }
 380.866 +    myHomeDir = cpystr (home);	/* set home directory */
 380.867 +  }
 380.868 +
 380.869 +  if (allowuserconfig) {	/* allow user config files */
 380.870 +    dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T);
 380.871 +    dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL);
 380.872 +  }
 380.873 +  if (!closedBox && !noautomaticsharedns) {
 380.874 +				/* #ftp namespace */
 380.875 +    if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
 380.876 +				/* #public namespace */
 380.877 +    if (!publicHome && (pw = getpwnam ("imappublic")))
 380.878 +      publicHome = cpystr (pw->pw_dir);
 380.879 +				/* #shared namespace */
 380.880 +    if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
 380.881 +      sharedHome = cpystr (pw->pw_dir);
 380.882 +  }
 380.883 +  if (!myLocalHost) mylocalhost ();
 380.884 +  if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
 380.885 +  if (!newsActive) newsActive = cpystr (ACTIVEFILE);
 380.886 +  if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
 380.887 +				/* re-do open action to get flags */
 380.888 +  (*createProto->dtb->open) (NIL);
 380.889 +  endpwent ();			/* close pw database */
 380.890 +  return T;
 380.891 +}
 380.892 + 
 380.893 +/* Return my user name
 380.894 + * Accepts: pointer to optional flags
 380.895 + * Returns: my user name
 380.896 + */
 380.897 +
 380.898 +char *myusername_full (unsigned long *flags)
 380.899 +{
 380.900 +  struct passwd *pw;
 380.901 +  struct stat sbuf;
 380.902 +  char *s;
 380.903 +  unsigned long euid;
 380.904 +  char *ret = UNLOGGEDUSER;
 380.905 +				/* no user name yet and not root? */
 380.906 +  if (!myUserName && (euid = geteuid ())) {
 380.907 +				/* yes, look up getlogin() user name or EUID */
 380.908 +    if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
 380.909 +	 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
 380.910 +	(pw = getpwuid (euid))) {
 380.911 +      if (block_env_init) {	/* don't env_init if blocked */
 380.912 +	if (flags) *flags = MU_LOGGEDIN;
 380.913 +	return pw->pw_name;
 380.914 +      }
 380.915 +      env_init (pw->pw_name,
 380.916 +		((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
 380.917 +		 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
 380.918 +		s : pw->pw_dir);
 380.919 +    }
 380.920 +    else fatal ("Unable to look up user name");
 380.921 +  }
 380.922 +  if (myUserName) {		/* logged in? */
 380.923 +    if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
 380.924 +    ret = myUserName;		/* return user name */
 380.925 +  }
 380.926 +  else if (flags) *flags = MU_NOTLOGGEDIN;
 380.927 +  return ret;
 380.928 +}
 380.929 +
 380.930 +
 380.931 +/* Return my local host name
 380.932 + * Returns: my local host name
 380.933 + */
 380.934 +
 380.935 +char *mylocalhost ()
 380.936 +{
 380.937 +  if (!myLocalHost) {
 380.938 +    char *s,tmp[MAILTMPLEN];
 380.939 +    char *t = "unknown";
 380.940 +    tmp[0] = tmp[MAILTMPLEN-1] = '\0';
 380.941 +    if (!gethostname (tmp,MAILTMPLEN-1) && tmp[0]) {
 380.942 +				/* sanity check of name */
 380.943 +      for (s = tmp; (*s > 0x20) && (*s < 0x7f); ++s);
 380.944 +      if (!*s) t = tcp_canonical (tmp);
 380.945 +    }
 380.946 +    myLocalHost = cpystr (t);
 380.947 +  }
 380.948 +  return myLocalHost;
 380.949 +}
 380.950 +
 380.951 +/* Return my home directory name
 380.952 + * Returns: my home directory name
 380.953 + */
 380.954 +
 380.955 +char *myhomedir ()
 380.956 +{
 380.957 +  if (!myHomeDir) myusername ();/* initialize if first time */
 380.958 +  return myHomeDir ? myHomeDir : "";
 380.959 +}
 380.960 +
 380.961 +
 380.962 +/* Return my home mailbox name
 380.963 + * Returns: my home directory name
 380.964 + */
 380.965 +
 380.966 +static char *mymailboxdir ()
 380.967 +{
 380.968 +  char *home = myhomedir ();
 380.969 +				/* initialize if first time */
 380.970 +  if (!myMailboxDir && myHomeDir) {
 380.971 +    if (mailsubdir) {
 380.972 +      char tmp[MAILTMPLEN];
 380.973 +      sprintf (tmp,"%s/%s",home,mailsubdir);
 380.974 +      myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
 380.975 +    }
 380.976 +    else myMailboxDir = cpystr (home);
 380.977 +  }
 380.978 +  return myMailboxDir ? myMailboxDir : "";
 380.979 +}
 380.980 +
 380.981 +
 380.982 +/* Return system standard INBOX
 380.983 + * Accepts: buffer string
 380.984 + */
 380.985 +
 380.986 +char *sysinbox ()
 380.987 +{
 380.988 +  char tmp[MAILTMPLEN];
 380.989 +  if (!sysInbox) {		/* initialize if first time */
 380.990 +    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
 380.991 +    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
 380.992 +  }
 380.993 +  return sysInbox;
 380.994 +}
 380.995 +
 380.996 +/* Return mailbox directory name
 380.997 + * Accepts: destination buffer
 380.998 + *	    directory prefix
 380.999 + *	    name in directory
380.1000 + * Returns: file name or NIL if error
380.1001 + */
380.1002 +
380.1003 +char *mailboxdir (char *dst,char *dir,char *name)
380.1004 +{
380.1005 +  char tmp[MAILTMPLEN];
380.1006 +  if (dir || name) {		/* if either argument provided */
380.1007 +    if (dir) {
380.1008 +      if (strlen (dir) > NETMAXMBX) return NIL;
380.1009 +      strcpy (tmp,dir);		/* write directory prefix */
380.1010 +    }
380.1011 +    else tmp[0] = '\0';		/* otherwise null string */
380.1012 +    if (name) {
380.1013 +      if (strlen (name) > NETMAXMBX) return NIL;
380.1014 +      strcat (tmp,name);	/* write name in directory */
380.1015 +    }
380.1016 +				/* validate name, return its name */
380.1017 +    if (!mailboxfile (dst,tmp)) return NIL;
380.1018 +  }
380.1019 +				/* no arguments, wants mailbox directory */
380.1020 +  else strcpy (dst,mymailboxdir ());
380.1021 +  return dst;			/* return the name */
380.1022 +}
380.1023 +
380.1024 +/* Return mailbox file name
380.1025 + * Accepts: destination buffer
380.1026 + *	    mailbox name
380.1027 + * Returns: file name or empty string for driver-selected INBOX or NIL if error
380.1028 + */
380.1029 +
380.1030 +char *mailboxfile (char *dst,char *name)
380.1031 +{
380.1032 +  struct passwd *pw;
380.1033 +  char *s;
380.1034 +  if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
380.1035 +      ((anonymous || blackBox || restrictBox || (*name == '#')) &&
380.1036 +       (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
380.1037 +    dst = NIL;			/* invalid name */
380.1038 +  else switch (*name) {		/* determine mailbox type based upon name */
380.1039 +  case '#':			/* namespace name */
380.1040 +				/* #ftp/ namespace */
380.1041 +    if (((name[1] == 'f') || (name[1] == 'F')) &&
380.1042 +	((name[2] == 't') || (name[2] == 'T')) &&
380.1043 +	((name[3] == 'p') || (name[3] == 'P')) &&
380.1044 +	(name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
380.1045 +				/* #public/ and #shared/ namespaces */
380.1046 +    else if ((((name[1] == 'p') || (name[1] == 'P')) &&
380.1047 +	      ((name[2] == 'u') || (name[2] == 'U')) &&
380.1048 +	      ((name[3] == 'b') || (name[3] == 'B')) &&
380.1049 +	      ((name[4] == 'l') || (name[4] == 'L')) &&
380.1050 +	      ((name[5] == 'i') || (name[5] == 'I')) &&
380.1051 +	      ((name[6] == 'c') || (name[6] == 'C')) &&
380.1052 +	      (name[7] == '/') && (s = publicHome)) ||
380.1053 +	     (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
380.1054 +	      ((name[2] == 'h') || (name[2] == 'H')) &&
380.1055 +	      ((name[3] == 'a') || (name[3] == 'A')) &&
380.1056 +	      ((name[4] == 'r') || (name[4] == 'R')) &&
380.1057 +	      ((name[5] == 'e') || (name[5] == 'E')) &&
380.1058 +	      ((name[6] == 'd') || (name[6] == 'D')) &&
380.1059 +	      (name[7] == '/') && (s = sharedHome)))
380.1060 +      sprintf (dst,"%s/%s",s,compare_cstring (name+8,"INBOX") ?
380.1061 +	       name+8 : "INBOX");
380.1062 +    else dst = NIL;		/* unknown namespace */
380.1063 +    break;
380.1064 +
380.1065 +  case '/':			/* root access */
380.1066 +    if (anonymous) dst = NIL;	/* anonymous forbidden to do this */
380.1067 +    else if (blackBox) {	/* other user access if blackbox */
380.1068 +      if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
380.1069 +				/* see if other user INBOX */
380.1070 +      else if ((s = strchr (name+1,'/')) && !compare_cstring (s+1,"INBOX")) {
380.1071 +	*s = '\0';		/* temporarily tie off string */
380.1072 +	sprintf (dst,"%s/%s/INBOX",blackBoxDir,name+1);
380.1073 +	*s = '/';		/* in case caller cares */
380.1074 +      }
380.1075 +      else sprintf (dst,"%s/%s",blackBoxDir,name+1);
380.1076 +    }
380.1077 +    else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
380.1078 +      dst = NIL;		/* restricted and not access to sysinbox */
380.1079 +    else strcpy (dst,name);	/* unrestricted, copy root name */
380.1080 +    break;
380.1081 +  case '~':			/* other user access */
380.1082 +				/* bad syntax or anonymous can't win */
380.1083 +    if (!*++name || anonymous) dst = NIL;
380.1084 +				/* ~/ equivalent to ordinary name */
380.1085 +    else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
380.1086 +				/* other user forbidden if closed/restricted */
380.1087 +    else if (closedBox || (restrictBox & RESTRICTOTHERUSER)) dst = NIL;
380.1088 +    else if (blackBox) {	/* black box form of other user */
380.1089 +				/* see if other user INBOX */
380.1090 +      if ((s = strchr (name,'/')) && compare_cstring (s+1,"INBOX")) {
380.1091 +	*s = '\0';		/* temporarily tie off string */
380.1092 +	sprintf (dst,"%s/%s/INBOX",blackBoxDir,name);
380.1093 +	*s = '/';		/* in case caller cares */
380.1094 +      }
380.1095 +      else sprintf (dst,"%s/%s",blackBoxDir,name);
380.1096 +    }
380.1097 +    else {			/* clear box other user */
380.1098 +				/* copy user name */
380.1099 +      for (s = dst; *name && (*name != '/'); *s++ = *name++);
380.1100 +      *s++ = '\0';		/* tie off user name, look up in passwd file */
380.1101 +      if ((pw = getpwnam (dst)) && pw->pw_dir) {
380.1102 +	if (*name) name++;	/* skip past the slash */
380.1103 +				/* canonicalize case of INBOX */
380.1104 +	if (!compare_cstring (name,"INBOX")) name = "INBOX";
380.1105 +				/* remove trailing / from directory */
380.1106 +	if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
380.1107 +				/* don't allow ~root/ if restricted root */
380.1108 +	if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
380.1109 +				/* build final name w/ subdir if needed */
380.1110 +	else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
380.1111 +	else sprintf (dst,"%s/%s",pw->pw_dir,name);
380.1112 +      }
380.1113 +      else dst = NIL;		/* no such user */
380.1114 +    }
380.1115 +    break;
380.1116 +
380.1117 +  case 'I': case 'i':		/* possible INBOX */
380.1118 +    if (!compare_cstring (name+1,"NBOX")) {
380.1119 +				/* if restricted, use INBOX in mailbox dir */
380.1120 +      if (anonymous || blackBox || closedBox)
380.1121 +	sprintf (dst,"%s/INBOX",mymailboxdir ());
380.1122 +      else *dst = '\0';		/* otherwise driver selects the name */
380.1123 +      break;
380.1124 +    }
380.1125 +				/* drop into to ordinary name case */
380.1126 +  default:			/* ordinary name is easy */
380.1127 +    sprintf (dst,"%s/%s",mymailboxdir (),name);
380.1128 +    break;
380.1129 +  }
380.1130 +  return dst;			/* return final name */
380.1131 +}
380.1132 +
380.1133 +/* Dot-lock file locker
380.1134 + * Accepts: file name to lock
380.1135 + *	    destination buffer for lock file name
380.1136 + *	    open file description on file name to lock
380.1137 + * Returns: T if success, NIL if failure
380.1138 + */
380.1139 +
380.1140 +long dotlock_lock (char *file,DOTLOCK *base,int fd)
380.1141 +{
380.1142 +  int i = locktimeout * 60;
380.1143 +  int j,mask,retry,pi[2],po[2];
380.1144 +  char *s,tmp[MAILTMPLEN];
380.1145 +  struct stat sb;
380.1146 +				/* flush absurd file name */
380.1147 +  if (strlen (file) > 512) return NIL;
380.1148 +				/* build lock filename */
380.1149 +  sprintf (base->lock,"%s.lock",file);
380.1150 +				/* assume no pipe */
380.1151 +  base->pipei = base->pipeo = -1;
380.1152 +  do {				/* make sure not symlink */
380.1153 +    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
380.1154 +				/* time out if file older than 5 minutes */
380.1155 +    if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
380.1156 +				/* try to create the lock */
380.1157 +    switch (retry = crexcl (base->lock)) {
380.1158 +    case -1:			/* OK to retry */
380.1159 +      if (!(i%15)) {		/* time to notify? */
380.1160 +	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
380.1161 +		 file,i);
380.1162 +	MM_LOG (tmp,WARN);
380.1163 +      }
380.1164 +      sleep (1);		/* wait 1 second before next try */
380.1165 +      break;
380.1166 +    case NIL:			/* failure, can't retry */
380.1167 +      i = 0;
380.1168 +      break;
380.1169 +    case T:			/* success, make sure others can break lock */
380.1170 +      chmod (base->lock,(int) dotlock_mode);
380.1171 +      return LONGT;
380.1172 +    }
380.1173 +  } while (i--);		/* until out of retries */
380.1174 +  if (retry < 0) {		/* still returning retry after locktimeout? */
380.1175 +    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
380.1176 +    if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
380.1177 +      sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
380.1178 +	       (long) (time (0) - sb.st_ctime));
380.1179 +      MM_LOG (tmp,WARN);
380.1180 +    }
380.1181 +    mask = umask (0);		/* want our lock protection */
380.1182 +    unlink (base->lock);	/* try to remove the old file */
380.1183 +				/* seize the lock */
380.1184 +    if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) dotlock_mode)) >= 0) {
380.1185 +      close (i);		/* don't need descriptor any more */
380.1186 +      sprintf (tmp,"Mailbox %.80s lock overridden",file);
380.1187 +      MM_LOG (tmp,NIL);
380.1188 +      chmod (base->lock,(int) dotlock_mode);
380.1189 +      umask (mask);		/* restore old umask */
380.1190 +      return LONGT;
380.1191 +    }
380.1192 +    umask (mask);		/* restore old umask */
380.1193 +  }
380.1194 +
380.1195 +  if (fd >= 0) switch (errno) {
380.1196 +  case EACCES:			/* protection failure? */
380.1197 +    MM_CRITICAL (NIL);		/* go critical */
380.1198 +    if (closedBox || !lockpgm);	/* can't do on closed box or disabled */
380.1199 +    else if ((*lockpgm && stat (lockpgm,&sb)) ||
380.1200 +	     (!*lockpgm && stat (lockpgm = LOCKPGM1,&sb) &&
380.1201 +	      stat (lockpgm = LOCKPGM2,&sb) && stat (lockpgm = LOCKPGM3,&sb)))
380.1202 +      lockpgm = NIL;		/* disable if can't find lockpgm */
380.1203 +    else if (pipe (pi) >= 0) {	/* make command pipes */
380.1204 +      long cf;
380.1205 +      char *argv[4],arg[20];
380.1206 +				/* if input pipes usable create output pipes */
380.1207 +      if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
380.1208 +				/* make sure output pipes are usable */
380.1209 +	if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
380.1210 +				/* all is good, make inferior process */
380.1211 +	else if (!(j = fork ())) {
380.1212 +	  if (!fork ()) {	/* make grandchild so it's inherited by init */
380.1213 +				/* prepare argument vector */
380.1214 +	    sprintf (arg,"%d",fd);
380.1215 +	    argv[0] = lockpgm; argv[1] = arg;
380.1216 +	    argv[2] = file; argv[3] = NIL;
380.1217 +				/* set parent's I/O to my O/I */
380.1218 +	    dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
380.1219 +				/* close all unnecessary descriptors */
380.1220 +	    for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
380.1221 +		 cf >= 3; --cf) if (cf != fd) close (cf);
380.1222 +				/* be our own process group */
380.1223 +	    setpgrp (0,getpid ());
380.1224 +				/* now run it */
380.1225 +	    _exit (execv (argv[0],argv));
380.1226 +	  }
380.1227 +	  _exit (1);		/* child is done */
380.1228 +	}
380.1229 +	else if (j > 0) {	/* parent process */
380.1230 +	  fd_set rfd;
380.1231 +	  struct timeval tmo;
380.1232 +	  FD_ZERO (&rfd);
380.1233 +	  FD_SET (pi[0],&rfd);
380.1234 +	  tmo.tv_sec = locktimeout * 60;
380.1235 +	  grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
380.1236 +				/* read response from locking program */
380.1237 +	  if (select (pi[0]+1,&rfd,0,0,&tmo) &&
380.1238 +	      (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
380.1239 +				/* success, record pipes */
380.1240 +	    base->pipei = pi[0]; base->pipeo = po[1];
380.1241 +				/* close child's side of the pipes */
380.1242 +	    close (pi[1]); close (po[0]);
380.1243 +	    MM_NOCRITICAL (NIL);/* no longer critical */
380.1244 +	    return LONGT;
380.1245 +	  }
380.1246 +	}
380.1247 +	close (po[0]); close (po[1]);
380.1248 +      }
380.1249 +      close (pi[0]); close (pi[1]);
380.1250 +    }
380.1251 +
380.1252 +    MM_NOCRITICAL (NIL);	/* no longer critical */
380.1253 +				/* find directory/file delimiter */
380.1254 +    if (s = strrchr (base->lock,'/')) {
380.1255 +      *s = '\0';		/* tie off at directory */
380.1256 +      sprintf(tmp,		/* generate default message */
380.1257 +	      "Mailbox vulnerable - directory %.80s must have 1777 protection",
380.1258 +	      base->lock);
380.1259 +				/* definitely not 1777 if can't stat */
380.1260 +      mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
380.1261 +      *s = '/';			/* restore lock name */
380.1262 +      if (mask != 1777) {	/* default warning if not 1777 */
380.1263 +	if (!disableLockWarning) MM_LOG (tmp,WARN);
380.1264 +	break;
380.1265 +      }
380.1266 +    }
380.1267 +  default:
380.1268 +    sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
380.1269 +	     base->lock,strerror (errno));
380.1270 +    if (!disableLockWarning) MM_LOG (tmp,WARN);
380.1271 +    break;
380.1272 +  }
380.1273 +  base->lock[0] = '\0';		/* don't use lock files */
380.1274 +  return NIL;
380.1275 +}
380.1276 +
380.1277 +/* Dot-lock file unlocker
380.1278 + * Accepts: lock file name
380.1279 + * Returns: T if success, NIL if failure
380.1280 + */
380.1281 +
380.1282 +long dotlock_unlock (DOTLOCK *base)
380.1283 +{
380.1284 +  long ret = LONGT;
380.1285 +  if (base && base->lock[0]) {
380.1286 +    if (base->pipei >= 0) {	/* if running through a pipe unlocker */
380.1287 +      ret = (write (base->pipeo,"+",1) == 1);
380.1288 +				/* nuke the pipes */
380.1289 +      close (base->pipei); close (base->pipeo);
380.1290 +    }
380.1291 +    else ret = !unlink (base->lock);
380.1292 +  }
380.1293 +  return ret;
380.1294 +}
380.1295 +
380.1296 +/* Lock file name
380.1297 + * Accepts: scratch buffer
380.1298 + *	    file name
380.1299 + *	    type of locking operation (LOCK_SH or LOCK_EX)
380.1300 + *	    pointer to return PID of locker
380.1301 + * Returns: file descriptor of lock or negative if error
380.1302 + */
380.1303 +
380.1304 +int lockname (char *lock,char *fname,int op,long *pid)
380.1305 +{
380.1306 +  struct stat sbuf;
380.1307 +  *pid = 0;			/* no locker PID */
380.1308 +  return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
380.1309 +}
380.1310 +
380.1311 +
380.1312 +/* Lock file descriptor
380.1313 + * Accepts: file descriptor
380.1314 + *	    lock file name buffer
380.1315 + *	    type of locking operation (LOCK_SH or LOCK_EX)
380.1316 + * Returns: file descriptor of lock or negative if error
380.1317 + */
380.1318 +
380.1319 +int lockfd (int fd,char *lock,int op)
380.1320 +{
380.1321 +  struct stat sbuf;
380.1322 +  return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
380.1323 +}
380.1324 +
380.1325 +/* Lock file name worker
380.1326 + * Accepts: lock file name
380.1327 + *	    pointer to stat() buffer
380.1328 + *	    type of locking operation (LOCK_SH or LOCK_EX)
380.1329 + *	    pointer to return PID of locker
380.1330 + * Returns: file descriptor of lock or negative if error
380.1331 + */
380.1332 +
380.1333 +int lock_work (char *lock,void *sb,int op,long *pid)
380.1334 +{
380.1335 +  struct stat lsb,fsb;
380.1336 +  struct stat *sbuf = (struct stat *) sb;
380.1337 +  char tmp[MAILTMPLEN];
380.1338 +  long i;
380.1339 +  int fd;
380.1340 +  int mask = umask (0);
380.1341 +  if (pid) *pid = 0;		/* initialize return PID */
380.1342 +				/* make temporary lock file name */
380.1343 +  sprintf (lock,"%s/.%lx.%lx",closedBox ? "" : tmpdir,
380.1344 +	   (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
380.1345 +  while (T) {			/* until get a good lock */
380.1346 +    do switch ((int) chk_notsymlink (lock,&lsb)) {
380.1347 +    case 1:			/* exists just once */
380.1348 +      if (((fd = open (lock,O_RDWR,shlock_mode)) >= 0) ||
380.1349 +	  (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
380.1350 +    case -1:			/* name doesn't exist */
380.1351 +      fd = open (lock,O_RDWR|O_CREAT|O_EXCL,shlock_mode);
380.1352 +      break;
380.1353 +    default:			/* multiple hard links */
380.1354 +      MM_LOG ("hard link to lock name",ERROR);
380.1355 +      syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
380.1356 +    case 0:			/* symlink (already did syslog) */
380.1357 +      umask (mask);		/* restore old mask */
380.1358 +      return -1;		/* fail: no lock file */
380.1359 +    } while ((fd < 0) && (errno == EEXIST));
380.1360 +    if (fd < 0) {		/* failed to get file descriptor */
380.1361 +      syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
380.1362 +	      strerror (errno));
380.1363 +      if (!closedBox) {		/* more explicit snarl for bad configuration */
380.1364 +	if (stat (tmpdir,&lsb))
380.1365 +	  syslog (LOG_CRIT,"SYSTEM ERROR: no %s: %s",tmpdir,strerror (errno));
380.1366 +	else if ((lsb.st_mode & 01777) != 01777) {
380.1367 +	  sprintf (tmp,"Can't lock for write: %.80s must have 1777 protection",
380.1368 +		   tmpdir);
380.1369 +	  MM_LOG (tmp,WARN);
380.1370 +	}
380.1371 +      }
380.1372 +      umask (mask);		/* restore old mask */
380.1373 +      return -1;		/* fail: can't open lock file */
380.1374 +    }
380.1375 +
380.1376 +				/* non-blocking form */
380.1377 +    if (op & LOCK_NB) i = flock (fd,op);
380.1378 +    else {			/* blocking form */
380.1379 +      (*mailblocknotify) (BLOCK_FILELOCK,NIL);
380.1380 +      i = flock (fd,op);
380.1381 +      (*mailblocknotify) (BLOCK_NONE,NIL);
380.1382 +    }
380.1383 +    if (i) {			/* failed, get other process' PID */
380.1384 +      if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
380.1385 +	  (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
380.1386 +	*pid = i;
380.1387 +      close (fd);		/* failed, give up on lock */
380.1388 +      umask (mask);		/* restore old mask */
380.1389 +      return -1;		/* fail: can't lock */
380.1390 +    }
380.1391 +				/* make sure this lock is good for us */
380.1392 +    if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
380.1393 +	!fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
380.1394 +	(lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
380.1395 +    close (fd);			/* lock not right, drop fd and try again */
380.1396 +  }
380.1397 +  chmod (lock,shlock_mode);	/* make sure mode OK (don't use fchmod()) */
380.1398 +  umask (mask);			/* restore old mask */
380.1399 +  return fd;			/* success */
380.1400 +}
380.1401 +
380.1402 +/* Check to make sure not a symlink
380.1403 + * Accepts: file name
380.1404 + *	    stat buffer
380.1405 + * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
380.1406 + */
380.1407 +
380.1408 +long chk_notsymlink (char *name,void *sb)
380.1409 +{
380.1410 +  struct stat *sbuf = (struct stat *) sb;
380.1411 +				/* name exists? */
380.1412 +  if (lstat (name,sbuf)) return -1;
380.1413 +				/* forbid symbolic link */
380.1414 +  if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
380.1415 +    MM_LOG ("symbolic link on lock name",ERROR);
380.1416 +    syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
380.1417 +	    name);
380.1418 +    return NIL;
380.1419 +  }
380.1420 +  return (long) sbuf->st_nlink;	/* return number of hard links */
380.1421 +}
380.1422 +
380.1423 +
380.1424 +/* Unlock file descriptor
380.1425 + * Accepts: file descriptor
380.1426 + *	    lock file name from lockfd()
380.1427 + */
380.1428 +
380.1429 +void unlockfd (int fd,char *lock)
380.1430 +{
380.1431 +				/* delete the file if no sharers */
380.1432 +  if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
380.1433 +  flock (fd,LOCK_UN);		/* unlock it */
380.1434 +  close (fd);			/* close it */
380.1435 +}
380.1436 +
380.1437 +/* Set proper file protection for mailbox
380.1438 + * Accepts: mailbox name
380.1439 + *	    actual file path name
380.1440 + * Returns: T, always
380.1441 + */
380.1442 +
380.1443 +long set_mbx_protections (char *mailbox,char *path)
380.1444 +{
380.1445 +  struct stat sbuf;
380.1446 +  int mode = (int) mbx_protection;
380.1447 +  if (*mailbox == '#') {	/* possible namespace? */
380.1448 +      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
380.1449 +	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
380.1450 +	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
380.1451 +	  (mailbox[4] == '/')) mode = (int) ftp_protection;
380.1452 +      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
380.1453 +	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
380.1454 +	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
380.1455 +	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
380.1456 +	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
380.1457 +	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
380.1458 +	       (mailbox[7] == '/')) mode = (int) public_protection;
380.1459 +      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
380.1460 +	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
380.1461 +	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
380.1462 +	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
380.1463 +	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
380.1464 +	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
380.1465 +	       (mailbox[7] == '/')) mode = (int) shared_protection;
380.1466 +  }
380.1467 +				/* if a directory */
380.1468 +  if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
380.1469 +				/* set owner search if allow read or write */
380.1470 +    if (mode & 0600) mode |= 0100;
380.1471 +    if (mode & 060) mode |= 010;/* set group search if allow read or write */
380.1472 +    if (mode & 06) mode |= 01;	/* set world search if allow read or write */
380.1473 +				/* preserve directory SGID bit */
380.1474 +    if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
380.1475 +  }
380.1476 +  chmod (path,mode);		/* set the new protection, ignore failure */
380.1477 +  return LONGT;
380.1478 +}
380.1479 +
380.1480 +/* Get proper directory protection
380.1481 + * Accepts: mailbox name
380.1482 + * Returns: directory mode, always
380.1483 + */
380.1484 +
380.1485 +long get_dir_protection (char *mailbox)
380.1486 +{
380.1487 +  if (*mailbox == '#') {	/* possible namespace? */
380.1488 +      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
380.1489 +	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
380.1490 +	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
380.1491 +	  (mailbox[4] == '/')) return ftp_dir_protection;
380.1492 +      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
380.1493 +	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
380.1494 +	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
380.1495 +	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
380.1496 +	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
380.1497 +	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
380.1498 +	       (mailbox[7] == '/')) return public_dir_protection;
380.1499 +      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
380.1500 +	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
380.1501 +	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
380.1502 +	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
380.1503 +	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
380.1504 +	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
380.1505 +	       (mailbox[7] == '/')) return shared_dir_protection;
380.1506 +  }
380.1507 +  return dir_protection;
380.1508 +}
380.1509 +
380.1510 +/* Determine default prototype stream to user
380.1511 + * Accepts: type (NIL for create, T for append)
380.1512 + * Returns: default prototype stream
380.1513 + */
380.1514 +
380.1515 +MAILSTREAM *default_proto (long type)
380.1516 +{
380.1517 +  myusername ();		/* make sure initialized */
380.1518 +				/* return default driver's prototype */
380.1519 +  return type ? appendProto : createProto;
380.1520 +}
380.1521 +
380.1522 +
380.1523 +/* Set up user flags for stream
380.1524 + * Accepts: MAIL stream
380.1525 + * Returns: MAIL stream with user flags set up
380.1526 + */
380.1527 +
380.1528 +MAILSTREAM *user_flags (MAILSTREAM *stream)
380.1529 +{
380.1530 +  int i;
380.1531 +  myusername ();		/* make sure initialized */
380.1532 +  for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
380.1533 +    if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
380.1534 +  return stream;
380.1535 +}
380.1536 +
380.1537 +
380.1538 +/* Return nth user flag
380.1539 + * Accepts: user flag number
380.1540 + * Returns: flag
380.1541 + */
380.1542 +
380.1543 +char *default_user_flag (unsigned long i)
380.1544 +{
380.1545 +  myusername ();		/* make sure initialized */
380.1546 +  return userFlags[i];
380.1547 +}
380.1548 +
380.1549 +/* Process rc file
380.1550 + * Accepts: file name
380.1551 + *	    .mminit flag
380.1552 + * Don't use this feature.
380.1553 + */
380.1554 +
380.1555 +void dorc (char *file,long flag)
380.1556 +{
380.1557 +  int i;
380.1558 +  char *s,*t,*k,*r,tmp[MAILTMPLEN],tmpx[MAILTMPLEN];
380.1559 +  extern MAILSTREAM CREATEPROTO;
380.1560 +  extern MAILSTREAM EMPTYPROTO;
380.1561 +  DRIVER *d;
380.1562 +  FILE *f;
380.1563 +  if ((f = fopen (file ? file : SYSCONFIG,"r")) &&
380.1564 +      (s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) do {
380.1565 +    *t++ = '\0';		/* tie off line, find second space */
380.1566 +    if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) {
380.1567 +      *k++ = '\0';		/* tie off two words */
380.1568 +      if (!compare_cstring (s,"set keywords") && !userFlags[0]) {
380.1569 +				/* yes, get first keyword */
380.1570 +	k = strtok_r (k,", ",&r);
380.1571 +				/* copy keyword list */
380.1572 +	for (i = 0; k && i < NUSERFLAGS; ++i) if (strlen (k) <= MAXUSERFLAG) {
380.1573 +	  if (userFlags[i]) fs_give ((void **) &userFlags[i]);
380.1574 +	  userFlags[i] = cpystr (k);
380.1575 +	  k = strtok_r (NIL,", ",&r);
380.1576 +	}
380.1577 +	if (flag) break;	/* found "set keywords" in .mminit */
380.1578 +      }
380.1579 +
380.1580 +      else if (!flag) {		/* none of these valid in .mminit */
380.1581 +	if (myUserName) {	/* only valid if logged in */
380.1582 +	  if (!compare_cstring (s,"set new-mailbox-format") ||
380.1583 +	      !compare_cstring (s,"set new-folder-format")) {
380.1584 +	    if (!compare_cstring (k,"same-as-inbox")) {
380.1585 +	      if (d = mail_valid (NIL,"INBOX",NIL)) {
380.1586 +		if (!compare_cstring (d->name,"mbox"))
380.1587 +		  d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,
380.1588 +						  (void *) "unix");
380.1589 +		else if (!compare_cstring (d->name,"dummy")) d = NIL;
380.1590 +	      }
380.1591 +	      createProto = d ? ((*d->open) (NIL)) : &CREATEPROTO;
380.1592 +	    }
380.1593 +	    else if (!compare_cstring (k,"system-standard"))
380.1594 +	      createProto = &CREATEPROTO;
380.1595 +	    else {		/* canonicalize mbox to unix */
380.1596 +	      if (!compare_cstring (k,"mbox")) k = "unix";
380.1597 +				/* see if a driver name */
380.1598 +	      if (d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,(void *) k))
380.1599 +		createProto = (*d->open) (NIL);
380.1600 +	      else {		/* duh... */
380.1601 +		sprintf (tmpx,"Unknown new mailbox format in %s: %s",
380.1602 +			 file ? file : SYSCONFIG,k);
380.1603 +		MM_LOG (tmpx,WARN);
380.1604 +	      }
380.1605 +	    }
380.1606 +	  }
380.1607 +	  if (!compare_cstring (s,"set empty-mailbox-format") ||
380.1608 +	      !compare_cstring (s,"set empty-folder-format")) {
380.1609 +	    if (!compare_cstring (k,"invalid")) appendProto = NIL;
380.1610 +	    else if (!compare_cstring (k,"same-as-inbox"))
380.1611 +	      appendProto = ((d = mail_valid (NIL,"INBOX",NIL)) &&
380.1612 +			     compare_cstring (d->name,"dummy")) ?
380.1613 +			       ((*d->open) (NIL)) : &EMPTYPROTO;
380.1614 +	    else if (!compare_cstring (k,"system-standard"))
380.1615 +	      appendProto = &EMPTYPROTO;
380.1616 +	    else {		/* see if a driver name */
380.1617 +	      for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
380.1618 +		   d && compare_cstring (d->name,k); d = d->next);
380.1619 +	      if (d) appendProto = (*d->open) (NIL);
380.1620 +	      else {		/* duh... */
380.1621 +		sprintf (tmpx,"Unknown empty mailbox format in %s: %s",
380.1622 +			 file ? file : SYSCONFIG,k);
380.1623 +		MM_LOG (tmpx,WARN);
380.1624 +	      }
380.1625 +	    }
380.1626 +	  }
380.1627 +	}
380.1628 +
380.1629 +	if (!compare_cstring (s,"set local-host")) {
380.1630 +	  fs_give ((void **) &myLocalHost);
380.1631 +	  myLocalHost = cpystr (k);
380.1632 +	}
380.1633 +	else if (!compare_cstring (s,"set news-active-file")) {
380.1634 +	  fs_give ((void **) &newsActive);
380.1635 +	  newsActive = cpystr (k);
380.1636 +	}
380.1637 +	else if (!compare_cstring (s,"set news-spool-directory")) {
380.1638 +	  fs_give ((void **) &newsSpool);
380.1639 +	  newsSpool = cpystr (k);
380.1640 +	}
380.1641 +	else if (!compare_cstring (s,"set mh-path"))
380.1642 +	  mail_parameters (NIL,SET_MHPATH,(void *) k);
380.1643 +	else if (!compare_cstring (s,"set mh-allow-inbox"))
380.1644 +	  mail_parameters (NIL,SET_MHALLOWINBOX,(void *) atol (k));
380.1645 +	else if (!compare_cstring (s,"set news-state-file")) {
380.1646 +	  fs_give ((void **) &myNewsrc);
380.1647 +	  myNewsrc = cpystr (k);
380.1648 +	}
380.1649 +	else if (!compare_cstring (s,"set ftp-export-directory")) {
380.1650 +	  fs_give ((void **) &ftpHome);
380.1651 +	  ftpHome = cpystr (k);
380.1652 +	}
380.1653 +	else if (!compare_cstring (s,"set public-home-directory")) {
380.1654 +	  fs_give ((void **) &publicHome);
380.1655 +	  publicHome = cpystr (k);
380.1656 +	}
380.1657 +	else if (!compare_cstring (s,"set shared-home-directory")) {
380.1658 +	  fs_give ((void **) &sharedHome);
380.1659 +	  sharedHome = cpystr (k);
380.1660 +	}
380.1661 +	else if (!compare_cstring (s,"set system-inbox")) {
380.1662 +	  fs_give ((void **) &sysInbox);
380.1663 +	  sysInbox = cpystr (k);
380.1664 +	}
380.1665 +	else if (!compare_cstring (s,"set mail-subdirectory")) {
380.1666 +	  fs_give ((void **) &mailsubdir);
380.1667 +	  mailsubdir = cpystr (k);
380.1668 +	}
380.1669 +	else if (!compare_cstring (s,"set from-widget"))
380.1670 +	  mail_parameters (NIL,SET_FROMWIDGET,
380.1671 +			   compare_cstring (k,"header-only") ?
380.1672 +			   VOIDT : NIL);
380.1673 +
380.1674 +	else if (!compare_cstring (s,"set rsh-command"))
380.1675 +	  mail_parameters (NIL,SET_RSHCOMMAND,(void *) k);
380.1676 +	else if (!compare_cstring (s,"set rsh-path"))
380.1677 +	  mail_parameters (NIL,SET_RSHPATH,(void *) k);
380.1678 +	else if (!compare_cstring (s,"set ssh-command"))
380.1679 +	  mail_parameters (NIL,SET_SSHCOMMAND,(void *) k);
380.1680 +	else if (!compare_cstring (s,"set ssh-path"))
380.1681 +	  mail_parameters (NIL,SET_SSHPATH,(void *) k);
380.1682 +	else if (!compare_cstring (s,"set tcp-open-timeout"))
380.1683 +	  mail_parameters (NIL,SET_OPENTIMEOUT,(void *) atol (k));
380.1684 +	else if (!compare_cstring (s,"set tcp-read-timeout"))
380.1685 +	  mail_parameters (NIL,SET_READTIMEOUT,(void *) atol (k));
380.1686 +	else if (!compare_cstring (s,"set tcp-write-timeout"))
380.1687 +	  mail_parameters (NIL,SET_WRITETIMEOUT,(void *) atol (k));
380.1688 +	else if (!compare_cstring (s,"set rsh-timeout"))
380.1689 +	  mail_parameters (NIL,SET_RSHTIMEOUT,(void *) atol (k));
380.1690 +	else if (!compare_cstring (s,"set ssh-timeout"))
380.1691 +	  mail_parameters (NIL,SET_SSHTIMEOUT,(void *) atol (k));
380.1692 +	else if (!compare_cstring (s,"set maximum-login-trials"))
380.1693 +	  mail_parameters (NIL,SET_MAXLOGINTRIALS,(void *) atol (k));
380.1694 +	else if (!compare_cstring (s,"set lookahead"))
380.1695 +	  mail_parameters (NIL,SET_LOOKAHEAD,(void *) atol (k));
380.1696 +	else if (!compare_cstring (s,"set prefetch"))
380.1697 +	  mail_parameters (NIL,SET_PREFETCH,(void *) atol (k));
380.1698 +	else if (!compare_cstring (s,"set close-on-error"))
380.1699 +	  mail_parameters (NIL,SET_CLOSEONERROR,(void *) atol (k));
380.1700 +	else if (!compare_cstring (s,"set imap-port"))
380.1701 +	  mail_parameters (NIL,SET_IMAPPORT,(void *) atol (k));
380.1702 +	else if (!compare_cstring (s,"set pop3-port"))
380.1703 +	  mail_parameters (NIL,SET_POP3PORT,(void *) atol (k));
380.1704 +	else if (!compare_cstring (s,"set uid-lookahead"))
380.1705 +	  mail_parameters (NIL,SET_UIDLOOKAHEAD,(void *) atol (k));
380.1706 +	else if (!compare_cstring (s,"set try-ssl-first"))
380.1707 +	  mail_parameters (NIL,SET_TRYSSLFIRST,(void *) atol (k));
380.1708 +
380.1709 +	else if (!compare_cstring (s,"set mailbox-protection"))
380.1710 +	  mbx_protection = atol (k);
380.1711 +	else if (!compare_cstring (s,"set directory-protection"))
380.1712 +	  dir_protection = atol (k);
380.1713 +	else if (!compare_cstring (s,"set lock-protection"))
380.1714 +	  dotlock_mode = atol (k);
380.1715 +	else if (!compare_cstring (s,"set ftp-protection"))
380.1716 +	  ftp_protection = atol (k);
380.1717 +	else if (!compare_cstring (s,"set public-protection"))
380.1718 +	  public_protection = atol (k);
380.1719 +	else if (!compare_cstring (s,"set shared-protection"))
380.1720 +	  shared_protection = atol (k);
380.1721 +	else if (!compare_cstring (s,"set ftp-directory-protection"))
380.1722 +	  ftp_dir_protection = atol (k);
380.1723 +	else if (!compare_cstring (s,"set public-directory-protection"))
380.1724 +	  public_dir_protection = atol (k);
380.1725 +	else if (!compare_cstring (s,"set shared-directory-protection"))
380.1726 +	  shared_dir_protection = atol (k);
380.1727 +	else if (!compare_cstring (s,"set dot-lock-file-timeout"))
380.1728 +	  locktimeout = atoi (k);
380.1729 +	else if (!compare_cstring (s,"set disable-fcntl-locking"))
380.1730 +	  fcntlhangbug = atoi (k);
380.1731 +	else if (!compare_cstring (s,"set disable-lock-warning"))
380.1732 +	  disableLockWarning = atoi (k);
380.1733 +	else if (!compare_cstring (s,"set disable-unix-UIDs-and-keywords"))
380.1734 +	  has_no_life = atoi (k);
380.1735 +	else if (!compare_cstring (s,"set hide-dot-files"))
380.1736 +	  hideDotFiles = atoi (k);
380.1737 +	else if (!compare_cstring (s,"set list-maximum-level"))
380.1738 +	  list_max_level = atol (k);
380.1739 +	else if (!compare_cstring (s,"set trust-dns"))
380.1740 +	  mail_parameters (NIL,SET_TRUSTDNS,(void *) atol (k));
380.1741 +	else if (!compare_cstring (s,"set sasl-uses-ptr-name"))
380.1742 +	  mail_parameters (NIL,SET_SASLUSESPTRNAME,(void *) atol (k));
380.1743 +	else if (!compare_cstring (s,"set network-filesystem-stat-bug"))
380.1744 +	  netfsstatbug = atoi (k);
380.1745 +	else if (!compare_cstring (s,"set nntp-range"))
380.1746 +	  mail_parameters (NIL,SET_NNTPRANGE,(void *) atol (k));
380.1747 +
380.1748 +	else if (!file) {	/* only allowed in system init */
380.1749 +	  if (!compare_cstring (s,"set black-box-directory") &&
380.1750 +	      !blackBoxDir) blackBoxDir = cpystr (k);
380.1751 +	  else if (!compare_cstring(s,"set black-box-default-home-directory")&&
380.1752 +		   blackBoxDir && !blackBoxDefaultHome)
380.1753 +	    blackBoxDefaultHome = cpystr (k);
380.1754 +	  else if (!compare_cstring (s,"set anonymous-home-directory") &&
380.1755 +		   !anonymousHome) anonymousHome = cpystr (k);
380.1756 +				/* It's tempting to allow setting the CA path
380.1757 +				 * in a user init.  However, that opens up a
380.1758 +				 * vector of attack big enough to drive a
380.1759 +				 * truck through...  Resist the temptation.
380.1760 +				 */
380.1761 +	  else if (!compare_cstring (s,"set CA-certificate-path"))
380.1762 +	    sslCApath = cpystr (k);
380.1763 +	  else if (!compare_cstring (s,"set disable-plaintext"))
380.1764 +	    disablePlaintext = atoi (k);
380.1765 +	  else if (!compare_cstring (s,"set allowed-login-attempts"))
380.1766 +	    logtry = atoi (k);
380.1767 +	  else if (!compare_cstring (s,"set chroot-server"))
380.1768 +	    closedBox = atoi (k);
380.1769 +	  else if (!compare_cstring (s,"set restrict-mailbox-access"))
380.1770 +	    for (k = strtok_r (k,", ",&r); k; k = strtok_r (NIL,", ",&r)) {
380.1771 +	      if (!compare_cstring (k,"root")) restrictBox |= RESTRICTROOT;
380.1772 +	      else if (!compare_cstring (k,"otherusers"))
380.1773 +		restrictBox |= RESTRICTOTHERUSER;
380.1774 +	      else if (!compare_cstring (k,"all")) restrictBox = -1;
380.1775 +	    }
380.1776 +	  else if (!compare_cstring (s,"set advertise-the-world"))
380.1777 +	    advertisetheworld = atoi (k);
380.1778 +	  else if (!compare_cstring (s,"set limited-advertise"))
380.1779 +	    limitedadvertise = atoi (k);
380.1780 +	  else if (!compare_cstring
380.1781 +		   (s,"set disable-automatic-shared-namespaces"))
380.1782 +	    noautomaticsharedns = atoi (k);
380.1783 +	  else if (!compare_cstring (s,"set allow-user-config"))
380.1784 +	    allowuserconfig = atoi (k);
380.1785 +	  else if (!compare_cstring (s,"set allow-reverse-dns"))
380.1786 +	    mail_parameters (NIL,SET_ALLOWREVERSEDNS,(void *) atol (k));
380.1787 +	  else if (!compare_cstring (s,"set k5-cp-uses-service-name"))
380.1788 +	    kerb_cp_svr_name = atoi (k);
380.1789 +				/* must appear in file after any
380.1790 +				 * "set disable-plaintext" command! */
380.1791 +	  else if (!compare_cstring (s,"set plaintext-allowed-clients")) {
380.1792 +	    for (k = strtok_r (k,", ",&r); k && !tcp_isclienthost (k);
380.1793 +		 k = strtok_r (NIL,", ",&r));
380.1794 +	    if (k) disablePlaintext = 0;
380.1795 +	  }
380.1796 +	}
380.1797 +      }
380.1798 +    }
380.1799 +  } while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n')));
380.1800 +  if (f) fclose (f);		/* flush the file */
380.1801 +}
380.1802 +
380.1803 +/* INBOX create function for tmail/dmail use only
380.1804 + * Accepts: mail stream
380.1805 + *	    path name buffer, preloaded with driver-dependent path
380.1806 + * Returns: T on success, NIL on failure
380.1807 + *
380.1808 + * This routine is evil and a truly incredible kludge.  It is private for
380.1809 + * tmail/dmail and is not supported for any other application.
380.1810 + */
380.1811 +
380.1812 +long path_create (MAILSTREAM *stream,char *path)
380.1813 +{
380.1814 +  long ret;
380.1815 +  short rsave = restrictBox;
380.1816 +  restrictBox = NIL;		/* can't restrict */
380.1817 +  if (blackBox) {		/* if black box */
380.1818 +				/* toss out driver dependent names */
380.1819 +    printf (path,"%s/INBOX",mymailboxdir ());
380.1820 +    blackBox = NIL;		/* well that's evil - evil is going on */
380.1821 +    ret = mail_create (stream,path);
380.1822 +    blackBox = T;		/* restore the box */
380.1823 +  }
380.1824 +				/* easy thing otherwise */
380.1825 +  else ret = mail_create (stream,path);
380.1826 +  restrictBox = rsave;		/* restore restrictions */
380.1827 +  return ret;
380.1828 +}
380.1829 +
380.1830 +/* Default block notify routine
380.1831 + * Accepts: reason for calling
380.1832 + *	    data
380.1833 + * Returns: data
380.1834 + */
380.1835 +
380.1836 +void *mm_blocknotify (int reason,void *data)
380.1837 +{
380.1838 +  void *ret = data;
380.1839 +  switch (reason) {
380.1840 +  case BLOCK_SENSITIVE:		/* entering sensitive code */
380.1841 +    ret = (void *) (unsigned long) alarm (0);
380.1842 +    break;
380.1843 +  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
380.1844 +    if ((unsigned long) data) alarm ((unsigned long) data);
380.1845 +    break;
380.1846 +  default:			/* ignore all other reasons */
380.1847 +    break;
380.1848 +  }
380.1849 +  return ret;
380.1850 +}
   381.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   381.2 +++ b/src/osdep/unix/env_unix.h	Mon Sep 14 15:17:45 2009 +0900
   381.3 @@ -0,0 +1,95 @@
   381.4 +/* ========================================================================
   381.5 + * Copyright 1988-2006 University of Washington
   381.6 + *
   381.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   381.8 + * you may not use this file except in compliance with the License.
   381.9 + * You may obtain a copy of the License at
  381.10 + *
  381.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  381.12 + *
  381.13 + * 
  381.14 + * ========================================================================
  381.15 + */
  381.16 +
  381.17 +/*
  381.18 + * Program:	UNIX environment routines
  381.19 + *
  381.20 + * Author:	Mark Crispin
  381.21 + *		Networks and Distributed Computing
  381.22 + *		Computing & Communications
  381.23 + *		University of Washington
  381.24 + *		Administration Building, AG-44
  381.25 + *		Seattle, WA  98195
  381.26 + *		Internet: MRC@CAC.Washington.EDU
  381.27 + *
  381.28 + * Date:	1 August 1988
  381.29 + * Last Edited:	30 August 2006
  381.30 + */
  381.31 +
  381.32 +
  381.33 +typedef struct dotlock_base {
  381.34 +  char lock[MAILTMPLEN];
  381.35 +  int pipei;
  381.36 +  int pipeo;
  381.37 +} DOTLOCK;
  381.38 +
  381.39 +
  381.40 +/* Bits that can be set in restrictBox */
  381.41 +
  381.42 +#define RESTRICTROOT 0x1	/* restricted box doesn't allow root */
  381.43 +#define RESTRICTOTHERUSER 0x2	/* restricted box doesn't allow other user */
  381.44 +
  381.45 +/* Subscription definitions for UNIX */
  381.46 +
  381.47 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ())
  381.48 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ())
  381.49 +
  381.50 +
  381.51 +/* dorc() options */
  381.52 +
  381.53 +#define SYSCONFIG "/etc/c-client.cf"
  381.54 +
  381.55 +
  381.56 +/* Special users */
  381.57 +
  381.58 +#define ANONYMOUSUSER "nobody"	/* anonymous user */
  381.59 +#define UNLOGGEDUSER "root"	/* unlogged-in user */
  381.60 +#define ADMINGROUP "mailadm"	/* mail administrator group */
  381.61 +
  381.62 +/* Function prototypes */
  381.63 +
  381.64 +#include "env.h"
  381.65 +
  381.66 +void rfc822_fixed_date (char *date);
  381.67 +long env_init (char *user,char *home);
  381.68 +char *myusername_full (unsigned long *flags);
  381.69 +#define MU_LOGGEDIN 0
  381.70 +#define MU_NOTLOGGEDIN 1
  381.71 +#define MU_ANONYMOUS 2
  381.72 +#define myusername() \
  381.73 +  myusername_full (NIL)
  381.74 +char *sysinbox ();
  381.75 +char *mailboxdir (char *dst,char *dir,char *name);
  381.76 +long dotlock_lock (char *file,DOTLOCK *base,int fd);
  381.77 +long dotlock_unlock (DOTLOCK *base);
  381.78 +int lockname (char *lock,char *fname,int op,long *pid);
  381.79 +int lockfd (int fd,char *lock,int op);
  381.80 +int lock_work (char *lock,void *sbuf,int op,long *pid);
  381.81 +long chk_notsymlink (char *name,void *sbuf);
  381.82 +void unlockfd (int fd,char *lock);
  381.83 +long set_mbx_protections (char *mailbox,char *path);
  381.84 +long get_dir_protection (char *mailbox);
  381.85 +MAILSTREAM *user_flags (MAILSTREAM *stream);
  381.86 +char *default_user_flag (unsigned long i);
  381.87 +void dorc (char *file,long flag);
  381.88 +long path_create (MAILSTREAM *stream,char *mailbox);
  381.89 +void grim_pid_reap_status (int pid,int killreq,void *status);
  381.90 +#define grim_pid_reap(pid,killreq) \
  381.91 +  grim_pid_reap_status (pid,killreq,NIL)
  381.92 +long safe_write (int fd,char *buf,long nbytes);
  381.93 +void *arm_signal (int sig,void *action);
  381.94 +struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]);
  381.95 +long loginpw (struct passwd *pw,int argc,char *argv[]);
  381.96 +long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
  381.97 +	       char *argv[]);
  381.98 +void *mm_blocknotify (int reason,void *data);
   382.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   382.2 +++ b/src/osdep/unix/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
   382.3 @@ -0,0 +1,99 @@
   382.4 +/* ========================================================================
   382.5 + * Copyright 1988-2007 University of Washington
   382.6 + *
   382.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   382.8 + * you may not use this file except in compliance with the License.
   382.9 + * You may obtain a copy of the License at
  382.10 + *
  382.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  382.12 + *
  382.13 + * 
  382.14 + * ========================================================================
  382.15 + */
  382.16 +
  382.17 +/*
  382.18 + * Program:	File descriptor string routines
  382.19 + *
  382.20 + * Author:	Mark Crispin
  382.21 + *		Networks and Distributed Computing
  382.22 + *		Computing & Communications
  382.23 + *		University of Washington
  382.24 + *		Administration Building, AG-44
  382.25 + *		Seattle, WA  98195
  382.26 + *		Internet: MRC@CAC.Washington.EDU
  382.27 + *
  382.28 + * Date:	15 April 1997
  382.29 + * Last Edited:	4 April 2007
  382.30 + */
  382.31 +
  382.32 +#include "mail.h"
  382.33 +#include "osdep.h"
  382.34 +#include "misc.h"
  382.35 +#include "fdstring.h"
  382.36 +
  382.37 +/* String driver for fd stringstructs */
  382.38 +
  382.39 +static void fd_string_init (STRING *s,void *data,unsigned long size);
  382.40 +static char fd_string_next (STRING *s);
  382.41 +static void fd_string_setpos (STRING *s,unsigned long i);
  382.42 +
  382.43 +STRINGDRIVER fd_string = {
  382.44 +  fd_string_init,		/* initialize string structure */
  382.45 +  fd_string_next,		/* get next byte in string structure */
  382.46 +  fd_string_setpos		/* set position in string structure */
  382.47 +};
  382.48 +
  382.49 +
  382.50 +/* Initialize string structure for fd stringstruct
  382.51 + * Accepts: string structure
  382.52 + *	    pointer to string
  382.53 + *	    size of string
  382.54 + */
  382.55 +
  382.56 +static void fd_string_init (STRING *s,void *data,unsigned long size)
  382.57 +{
  382.58 +  FDDATA *d = (FDDATA *) data;
  382.59 +				/* note fd */
  382.60 +  s->data = (void *) (unsigned long) d->fd;
  382.61 +  s->data1 = d->pos;		/* note file offset */
  382.62 +  s->size = size;		/* note size */
  382.63 +  s->curpos = s->chunk = d->chunk;
  382.64 +  s->chunksize = (unsigned long) d->chunksize;
  382.65 +  s->offset = 0;		/* initial position */
  382.66 +				/* and size of data */
  382.67 +  s->cursize = min (s->chunksize,size);
  382.68 +				/* move to that position in the file */
  382.69 +  lseek (d->fd,d->pos,L_SET);
  382.70 +  read (d->fd,s->chunk,(size_t) s->cursize);
  382.71 +}
  382.72 +
  382.73 +/* Get next character from fd stringstruct
  382.74 + * Accepts: string structure
  382.75 + * Returns: character, string structure chunk refreshed
  382.76 + */
  382.77 +
  382.78 +static char fd_string_next (STRING *s)
  382.79 +{
  382.80 +  char c = *s->curpos++;	/* get next byte */
  382.81 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
  382.82 +  return c;			/* return the byte */
  382.83 +}
  382.84 +
  382.85 +
  382.86 +/* Set string pointer position for fd stringstruct
  382.87 + * Accepts: string structure
  382.88 + *	    new position
  382.89 + */
  382.90 +
  382.91 +static void fd_string_setpos (STRING *s,unsigned long i)
  382.92 +{
  382.93 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
  382.94 +  s->offset = i;		/* set new offset */
  382.95 +  s->curpos = s->chunk;		/* reset position */
  382.96 +				/* set size of data */
  382.97 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
  382.98 +				/* move to that position in the file */
  382.99 +    lseek ((long) s->data,s->data1 + s->offset,L_SET);
 382.100 +    read ((long) s->data,s->curpos,(size_t) s->cursize);
 382.101 +  }
 382.102 +}
   383.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   383.2 +++ b/src/osdep/unix/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
   383.3 @@ -0,0 +1,39 @@
   383.4 +/* ========================================================================
   383.5 + * Copyright 1988-2006 University of Washington
   383.6 + *
   383.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   383.8 + * you may not use this file except in compliance with the License.
   383.9 + * You may obtain a copy of the License at
  383.10 + *
  383.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  383.12 + *
  383.13 + * 
  383.14 + * ========================================================================
  383.15 + */
  383.16 +
  383.17 +/*
  383.18 + * Program:	File descriptor string routines
  383.19 + *
  383.20 + * Author:	Mark Crispin
  383.21 + *		Networks and Distributed Computing
  383.22 + *		Computing & Communications
  383.23 + *		University of Washington
  383.24 + *		Administration Building, AG-44
  383.25 + *		Seattle, WA  98195
  383.26 + *		Internet: MRC@CAC.Washington.EDU
  383.27 + *
  383.28 + * Date:	15 April 1997
  383.29 + * Last Edited:	30 August 2006
  383.30 + */
  383.31 +
  383.32 +/* Driver-dependent data passed to init method */
  383.33 +
  383.34 +typedef struct fd_data {
  383.35 +  int fd;			/* file descriptor */
  383.36 +  unsigned long pos;		/* initial position */
  383.37 +  char *chunk;			/* I/O buffer chunk */
  383.38 +  unsigned long chunksize;	/* I/O buffer chunk length */
  383.39 +} FDDATA;
  383.40 +
  383.41 +
  383.42 +extern STRINGDRIVER fd_string;
   384.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   384.2 +++ b/src/osdep/unix/flockcyg.c	Mon Sep 14 15:17:45 2009 +0900
   384.3 @@ -0,0 +1,92 @@
   384.4 +/* ========================================================================
   384.5 + * Copyright 1988-2006 University of Washington
   384.6 + *
   384.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   384.8 + * you may not use this file except in compliance with the License.
   384.9 + * You may obtain a copy of the License at
  384.10 + *
  384.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  384.12 + *
  384.13 + * 
  384.14 + * ========================================================================
  384.15 + */
  384.16 +
  384.17 +/*
  384.18 + * Program:	flock emulation via fcntl() locking
  384.19 + *
  384.20 + * Author:	Mark Crispin
  384.21 + *		Networks and Distributed Computing
  384.22 + *		Computing & Communications
  384.23 + *		University of Washington
  384.24 + *		Administration Building, AG-44
  384.25 + *		Seattle, WA  98195
  384.26 + *		Internet: MRC@CAC.Washington.EDU
  384.27 + *
  384.28 + * Date:	10 April 2001
  384.29 + * Last Edited:	30 August 2006
  384.30 + */
  384.31 +
  384.32 +
  384.33 +/* Cygwin does not seem to have the design flaw in fcntl() locking that
  384.34 + * most other systems do (see flocksim.c for details).  If some cretin
  384.35 + * decides to implement that design flaw, then Cygwin will have to use
  384.36 + * flocksim.  Also, we don't test NFS either.
  384.37 + *
  384.38 + * However, Cygwin does have the Windows misfeature (introduced in NT 4.0)
  384.39 + * that you can not write to any segment which has a shared lock, and you
  384.40 + * can't lock a zero-byte segment either.  This screws up the shared-write
  384.41 + * mailbox drivers (mbx, mtx, mx, and tenex).  As a workaround, we'll only
  384.42 + * lock the first byte of the file, meaning that you can't write that byte
  384.43 + * shared.  It's been suggested to lock the maximum off_t type, but that
  384.44 + * risks having a future version of Windows (or Cygwin) deciding that this
  384.45 + * also means "no lock".
  384.46 + */
  384.47 +
  384.48 +#undef flock			/* name is used as a struct for fcntl */
  384.49 +
  384.50 +/* Emulator for flock() call
  384.51 + * Accepts: file descriptor
  384.52 + *	    operation bitmask
  384.53 + * Returns: 0 if successful, -1 if failure under BSD conditions
  384.54 + */
  384.55 +
  384.56 +int flocksim (int fd,int op)
  384.57 +{
  384.58 +  char tmp[MAILTMPLEN];
  384.59 +  int logged = 0;
  384.60 +  struct flock fl;
  384.61 +				/* lock one bytes at byte 0 */
  384.62 +  fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1;
  384.63 +  fl.l_pid = getpid ();		/* shouldn't be necessary */
  384.64 +  switch (op & ~LOCK_NB) {	/* translate to fcntl() operation */
  384.65 +  case LOCK_EX:			/* exclusive */
  384.66 +    fl.l_type = F_WRLCK;
  384.67 +    break;
  384.68 +  case LOCK_SH:			/* shared */
  384.69 +    fl.l_type = F_RDLCK;
  384.70 +    break;
  384.71 +  case LOCK_UN:			/* unlock */
  384.72 +    fl.l_type = F_UNLCK;
  384.73 +    break;
  384.74 +  default:			/* default */
  384.75 +    errno = EINVAL;
  384.76 +    return -1;
  384.77 +  }
  384.78 +  while (fcntl (fd,(op & LOCK_NB) ? F_SETLK : F_SETLKW,&fl))
  384.79 +    if (errno != EINTR) {
  384.80 +      /* Can't use switch here because these error codes may resolve to the
  384.81 +       * same value on some systems.
  384.82 +       */
  384.83 +      if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EACCES)) {
  384.84 +	sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno));
  384.85 +				/* give the user a warning of what happened */
  384.86 +	MM_NOTIFY (NIL,tmp,WARN);
  384.87 +	if (!logged++) syslog (LOG_ERR,"%s",tmp);
  384.88 +	if (op & LOCK_NB) return -1;
  384.89 +	sleep (5);		/* slow things down for loops */
  384.90 +      }
  384.91 +				/* return failure for non-blocking lock */
  384.92 +      else if (op & LOCK_NB) return -1;
  384.93 +    }
  384.94 +  return 0;			/* success */
  384.95 +}
   385.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   385.2 +++ b/src/osdep/unix/flockcyg.h	Mon Sep 14 15:17:45 2009 +0900
   385.3 @@ -0,0 +1,50 @@
   385.4 +/* ========================================================================
   385.5 + * Copyright 1988-2006 University of Washington
   385.6 + *
   385.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   385.8 + * you may not use this file except in compliance with the License.
   385.9 + * You may obtain a copy of the License at
  385.10 + *
  385.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  385.12 + *
  385.13 + * 
  385.14 + * ========================================================================
  385.15 + */
  385.16 +
  385.17 +/*
  385.18 + * Program:	flock() emulation via fcntl() locking
  385.19 + *
  385.20 + * Author:	Mark Crispin
  385.21 + *		Networks and Distributed Computing
  385.22 + *		Computing & Communications
  385.23 + *		University of Washington
  385.24 + *		Administration Building, AG-44
  385.25 + *		Seattle, WA  98195
  385.26 + *		Internet: MRC@CAC.Washington.EDU
  385.27 + *
  385.28 + * Date:	10 April 2001
  385.29 + * Last Edited:	30 August 2006
  385.30 + */
  385.31 +
  385.32 +/* Cygwin does not seem to have the design flaw in fcntl() locking that
  385.33 + * most other systems do (see flocksim.c for details).  If some cretin
  385.34 + * decides to implement that design flaw, then Cygwin will have to use
  385.35 + * flocksim.  Also, we don't test NFS either
  385.36 + */
  385.37 +
  385.38 +
  385.39 +#define flock flocksim		/* use ours instead of theirs */
  385.40 +
  385.41 +#undef LOCK_SH
  385.42 +#define LOCK_SH 1		/* shared lock */
  385.43 +#undef LOCK_EX
  385.44 +#define LOCK_EX 2		/* exclusive lock */
  385.45 +#undef LOCK_NB
  385.46 +#define LOCK_NB 4		/* no blocking */
  385.47 +#undef LOCK_UN
  385.48 +#define LOCK_UN 8		/* unlock */
  385.49 +
  385.50 +
  385.51 +/* Function prototypes */
  385.52 +
  385.53 +int flocksim (int fd,int operation);
   386.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   386.2 +++ b/src/osdep/unix/flocklnx.c	Mon Sep 14 15:17:45 2009 +0900
   386.3 @@ -0,0 +1,76 @@
   386.4 +/* ========================================================================
   386.5 + * Copyright 1988-2006 University of Washington
   386.6 + *
   386.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   386.8 + * you may not use this file except in compliance with the License.
   386.9 + * You may obtain a copy of the License at
  386.10 + *
  386.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  386.12 + *
  386.13 + * 
  386.14 + * ========================================================================
  386.15 + */
  386.16 +
  386.17 +/*
  386.18 + * Program:	Safe File Lock for Linux
  386.19 + *
  386.20 + * Author:	Mark Crispin
  386.21 + *		Networks and Distributed Computing
  386.22 + *		Computing & Communications
  386.23 + *		University of Washington
  386.24 + *		Administration Building, AG-44
  386.25 + *		Seattle, WA  98195
  386.26 + *		Internet: MRC@CAC.Washington.EDU
  386.27 + *
  386.28 + * Date:	20 April 2005
  386.29 + * Last Edited:	30 August 2006
  386.30 + */
  386.31 + 
  386.32 +#undef flock
  386.33 +
  386.34 +#include <sys/vfs.h>
  386.35 +#ifndef NFS_SUPER_MAGIC
  386.36 +#define NFS_SUPER_MAGIC 0x6969
  386.37 +#endif
  386.38 +
  386.39 +int safe_flock (int fd,int op)
  386.40 +{
  386.41 +  struct statfs sfbuf;
  386.42 +  char tmp[MAILTMPLEN];
  386.43 +  int e;
  386.44 +  int logged = 0;
  386.45 +  /* Check for NFS because Linux 2.6 broke flock() on NFS.  Instead of being
  386.46 +   * a no-op, flock() on NFS now returns ENOLCK.  Read
  386.47 +   *   https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415
  386.48 +   * for the gruesome details.
  386.49 +   */
  386.50 +				/* check filesystem type */
  386.51 +  while ((e = fstatfs (fd,&sfbuf)) && (errno == EINTR));
  386.52 +  if (!e) switch (sfbuf.f_type) {
  386.53 +  case NFS_SUPER_MAGIC:		/* always a fast no-op on NFS */
  386.54 +    break;
  386.55 +  default:			/* allow on other filesystem types */
  386.56 +				/* do the lock */
  386.57 +    while (flock (fd,op)) switch (errno) {
  386.58 +    case EINTR:			/* interrupt */
  386.59 +      break;
  386.60 +    case ENOLCK:		/* lock table is full */
  386.61 +      sprintf (tmp,"File locking failure: %s",strerror (errno));
  386.62 +      mm_log (tmp,WARN);	/* give the user a warning of what happened */
  386.63 +      if (!logged++) syslog (LOG_ERR,tmp);
  386.64 +				/* return failure if non-blocking lock */
  386.65 +      if (op & LOCK_NB) return -1;
  386.66 +      sleep (5);		/* slow down in case it loops */
  386.67 +      break;
  386.68 +    case EWOULDBLOCK:		/* file is locked, LOCK_NB should be set */
  386.69 +      if (op & LOCK_NB) return -1;
  386.70 +    case EBADF:			/* not valid open file descriptor */
  386.71 +    case EINVAL:		/* invalid operator */
  386.72 +    default:			/* other error code? */
  386.73 +      sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno));
  386.74 +      fatal (tmp);
  386.75 +    }
  386.76 +    break;
  386.77 +  }
  386.78 +  return 0;			/* success */
  386.79 +}
   387.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   387.2 +++ b/src/osdep/unix/flocksim.c	Mon Sep 14 15:17:45 2009 +0900
   387.3 @@ -0,0 +1,920 @@
   387.4 +/* ========================================================================
   387.5 + * Copyright 1988-2007 University of Washington
   387.6 + *
   387.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   387.8 + * you may not use this file except in compliance with the License.
   387.9 + * You may obtain a copy of the License at
  387.10 + *
  387.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  387.12 + *
  387.13 + * 
  387.14 + * ========================================================================
  387.15 + */
  387.16 +
  387.17 +/*
  387.18 + * Program:	flock emulation via fcntl() locking
  387.19 + *
  387.20 + * Author:	Mark Crispin
  387.21 + *		Networks and Distributed Computing
  387.22 + *		Computing & Communications
  387.23 + *		University of Washington
  387.24 + *		Administration Building, AG-44
  387.25 + *		Seattle, WA  98195
  387.26 + *		Internet: MRC@CAC.Washington.EDU
  387.27 + *
  387.28 + * Date:	10 April 2001
  387.29 + * Last Edited:	11 October 2007
  387.30 + */
  387.31 + 
  387.32 +#undef flock			/* name is used as a struct for fcntl */
  387.33 +
  387.34 +#ifndef NOFSTATVFS		/* thank you, SUN.  NOT! */
  387.35 +# ifndef NOFSTATVFS64
  387.36 +#  ifndef _LARGEFILE64_SOURCE
  387.37 +#   define _LARGEFILE64_SOURCE
  387.38 +#  endif	/* _LARGEFILE64_SOURCE */
  387.39 +# endif		/* NOFSTATVFFS64 */
  387.40 +#include <sys/statvfs.h>
  387.41 +#endif		/* NOFSTATVFS */
  387.42 +
  387.43 +#ifndef NSIG			/* don't know if this can happen */
  387.44 +#define NSIG 32			/* a common maximum */
  387.45 +#endif
  387.46 +
  387.47 +/* Emulator for flock() call
  387.48 + * Accepts: file descriptor
  387.49 + *	    operation bitmask
  387.50 + * Returns: 0 if successful, -1 if failure under BSD conditions
  387.51 + */
  387.52 +
  387.53 +int flocksim (int fd,int op)
  387.54 +{
  387.55 +  char tmp[MAILTMPLEN];
  387.56 +  int logged = 0;
  387.57 +  struct stat sbuf;
  387.58 +  struct ustat usbuf;
  387.59 +  struct flock fl;
  387.60 +				/* lock zero bytes at byte 0 */
  387.61 +  fl.l_whence = SEEK_SET; fl.l_start = fl.l_len = 0;
  387.62 +  fl.l_pid = getpid ();		/* shouldn't be necessary */
  387.63 +  switch (op & ~LOCK_NB) {	/* translate to fcntl() operation */
  387.64 +  case LOCK_EX:			/* exclusive */
  387.65 +    fl.l_type = F_WRLCK;
  387.66 +    break;
  387.67 +  case LOCK_SH:			/* shared */
  387.68 +    fl.l_type = F_RDLCK;
  387.69 +    break;
  387.70 +  case LOCK_UN:			/* unlock */
  387.71 +    fl.l_type = F_UNLCK;
  387.72 +    break;
  387.73 +  default:			/* default */
  387.74 +    errno = EINVAL;
  387.75 +    return -1;
  387.76 +  }
  387.77 +				/* always return success if disabled */
  387.78 +  if (mail_parameters (NIL,GET_DISABLEFCNTLLOCK,NIL)) return 0;
  387.79 +
  387.80 +  /*  Make fcntl() locking of NFS files be a no-op the way it is with flock()
  387.81 +   * on BSD.  This is because the rpc.statd/rpc.lockd daemons don't work very
  387.82 +   * well and cause cluster-wide hangs if you exercise them at all.  The
  387.83 +   * result of this is that you lose the ability to detect shared mail_open()
  387.84 +   * on NFS-mounted files.  If you are wise, you'll use IMAP instead of NFS
  387.85 +   * for mail files.
  387.86 +   *
  387.87 +   *  Sun alleges that it doesn't matter, and that they have fixed all the
  387.88 +   * rpc.statd/rpc.lockd bugs.  As of October 2006, that is still false.
  387.89 +   *
  387.90 +   *  We need three tests for three major historical variants in SVR4:
  387.91 +   *  1) In NFSv2, ustat() would return -1 in f_tinode for NFS.
  387.92 +   *  2) When fstatvfs() was introduced with NFSv3, ustat() was "fixed".
  387.93 +   *  3) When 64-bit filesystems were introduced, fstatvfs() would return
  387.94 +   *	 EOVERFLOW; you have to use fstatvfs64() even though you don't care
  387.95 +   *	 about any of the affected values.
  387.96 +   *
  387.97 +   * We can't use fstatfs() because fstatfs():
  387.98 +   * . is documented as being deprecated in SVR4.
  387.99 +   * . has inconsistent calling conventions (there are two additional int
 387.100 +   *   arguments on Solaris and I don't know what they do).
 387.101 +   * . returns inconsistent statfs structs.  On Solaris, the file system type
 387.102 +   *   is a short called f_fstyp.  On AIX, it's an int called f_type that is
 387.103 +   *   documented as always being 0!
 387.104 +   *
 387.105 +   * For what it's worth, here's the scoop on fstatfs() elsewhere:
 387.106 +   *
 387.107 +   *  On Linux, the file system type is a long called f_type that has a file
 387.108 +   * system type code.  A different module (flocklnx.c) uses this because
 387.109 +   * some knothead "improved" flock() to return ENOLCK on NFS files instead
 387.110 +   * of being a successful no-op.  This "improvement" apparently has been
 387.111 +   * reverted, but not before it got to many systems in the field.
 387.112 +   *
 387.113 +   *  On BSD, it's a short called either f_otype or f_type that is documented
 387.114 +   * as always being zero.  Fortunately, BSD has flock() the way it's supposed
 387.115 +   * to be, and none of this nonsense is necessary.
 387.116 +   */
 387.117 +  if (!fstat (fd,&sbuf))	{ /* no hope of working if can't fstat()! */
 387.118 +    /* Any base type that begins with "nfs" or "afs" is considered to be a
 387.119 +     * network filesystem.
 387.120 +     */
 387.121 +#ifndef NOFSTATVFS
 387.122 +    struct statvfs vsbuf;
 387.123 +#ifndef NOFSTATVFS64
 387.124 +    struct statvfs64 vsbuf64;
 387.125 +    if (!fstatvfs64 (fd,&vsbuf64) && (vsbuf64.f_basetype[1] == 'f') &&
 387.126 +	(vsbuf64.f_basetype[2] == 's') &&
 387.127 +	((vsbuf64.f_basetype[0] == 'n') || (vsbuf64.f_basetype[0] == 'a')))
 387.128 +      return 0;
 387.129 +#endif		/* NOFSTATVFS64 */
 387.130 +    if (!fstatvfs (fd,&vsbuf) && (vsbuf.f_basetype[1] == 'f') &&
 387.131 +	(vsbuf.f_basetype[2] == 's') &&
 387.132 +	((vsbuf.f_basetype[0] == 'n') || (vsbuf.f_basetype[0] == 'a')))
 387.133 +      return 0;
 387.134 +#endif		/* NOFSTATVFS */
 387.135 +    if (!ustat (sbuf.st_dev,&usbuf) && !++usbuf.f_tinode) return 0;
 387.136 +  }
 387.137 +
 387.138 +				/* do the lock */
 387.139 +  while (fcntl (fd,(op & LOCK_NB) ? F_SETLK : F_SETLKW,&fl))
 387.140 +    if (errno != EINTR) {
 387.141 +      /* Can't use switch here because these error codes may resolve to the
 387.142 +       * same value on some systems.
 387.143 +       */
 387.144 +      if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EACCES)) {
 387.145 +	sprintf (tmp,"Unexpected file locking failure: %.100s",
 387.146 +		 strerror (errno));
 387.147 +				/* give the user a warning of what happened */
 387.148 +	MM_NOTIFY (NIL,tmp,WARN);
 387.149 +	if (!logged++) syslog (LOG_ERR,"%s",tmp);
 387.150 +	if (op & LOCK_NB) return -1;
 387.151 +	sleep (5);		/* slow things down for loops */
 387.152 +      }
 387.153 +				/* return failure for non-blocking lock */
 387.154 +      else if (op & LOCK_NB) return -1;
 387.155 +    }
 387.156 +  return 0;			/* success */
 387.157 +}
 387.158 +
 387.159 +/* Master/slave procedures for safe fcntl() locking.
 387.160 + *
 387.161 + *  The purpose of this nonsense is to work around a bad bug in fcntl()
 387.162 + * locking.  The cretins who designed it decided that a close() should
 387.163 + * release any locks made by that process on the file opened on that
 387.164 + * file descriptor.  Never mind that the lock wasn't made on that file
 387.165 + * descriptor, but rather on some other file descriptor.
 387.166 + *
 387.167 + *  This bug is on every implementation of fcntl() locking that I have
 387.168 + * tested.  Fortunately, on BSD systems, OSF/1, and Linux, we can use the
 387.169 + * flock() system call which doesn't have this bug.
 387.170 + *
 387.171 + *  Note that OSF/1, Linux, and some BSD systems have both broken fcntl()
 387.172 + * locking and the working flock() locking.
 387.173 + *
 387.174 + *  The program below can be used to demonstrate this problem.  Be sure to
 387.175 + * let it run long enough for all the sleep() calls to finish.
 387.176 + */
 387.177 +
 387.178 +#if 0
 387.179 +#include <stdio.h>
 387.180 +#include <unistd.h>
 387.181 +#include <fcntl.h>
 387.182 +#include <errno.h>
 387.183 +#include <string.h>
 387.184 +#include <sys/file.h>
 387.185 +
 387.186 +main ()
 387.187 +{
 387.188 +  struct flock fl;
 387.189 +  int fd,fd2;
 387.190 +  char *file = "a.a";
 387.191 +  if ((fd = creat (file,0666)) < 0)
 387.192 +    perror ("TEST FAILED: can't create test file"),_exit (errno);
 387.193 +  close (fd);
 387.194 +  if (fork ()) {		/* parent */
 387.195 +    if ((fd = open (file,O_RDWR,0)) < 0) abort();
 387.196 +				/* lock applies to entire file */
 387.197 +    fl.l_whence = fl.l_start = fl.l_len = 0;
 387.198 +    fl.l_pid = getpid ();	/* shouldn't be necessary */
 387.199 +    fl.l_type = F_RDLCK;
 387.200 +    if (fcntl (fd,F_SETLKW,&fl) == -1) abort ();
 387.201 +    sleep (5);
 387.202 +    if ((fd2 = open (file,O_RDWR,0)) < 0) abort ();
 387.203 +    sleep (1);
 387.204 +    puts ("parent test ready -- will hang here if locking works correctly");
 387.205 +    close (fd2);
 387.206 +    wait (0);
 387.207 +    puts ("OS BUG: child terminated");
 387.208 +    _exit (0);
 387.209 +  }
 387.210 +  else {			/* child */
 387.211 +    sleep (2);
 387.212 +    if ((fd = open (file,O_RDWR,0666)) < 0) abort ();
 387.213 +    puts ("child test ready -- child will hang if no bug");
 387.214 +				/* lock applies to entire file */
 387.215 +    fl.l_whence = fl.l_start = fl.l_len = 0;
 387.216 +    fl.l_pid = getpid ();	/* shouldn't be necessary */
 387.217 +    fl.l_type = F_WRLCK;
 387.218 +    if (fcntl (fd,F_SETLKW,&fl) == -1) abort ();
 387.219 +    puts ("OS BUG: child got lock");
 387.220 +  }
 387.221 +}
 387.222 +#endif
 387.223 +
 387.224 +/*  Beware of systems such as AIX which offer flock() as a compatibility
 387.225 + * function that is just a jacket into fcntl() locking.  The program below
 387.226 + * is a variant of the program above, only using flock().  It can be used
 387.227 + * to test to see if your system has real flock() or just a jacket into
 387.228 + * fcntl().
 387.229 + *
 387.230 + *  Be sure to let it run long enough for all the sleep() calls to finish.
 387.231 + * If the program hangs, then flock() works and you can dispense with the
 387.232 + * use of this module (you lucky person!).
 387.233 + */
 387.234 +
 387.235 +#if 0
 387.236 +#include <stdio.h>
 387.237 +#include <errno.h>
 387.238 +#include <string.h>
 387.239 +#include <sys/file.h>
 387.240 +
 387.241 +main ()
 387.242 +{
 387.243 +  int fd,fd2;
 387.244 +  char *file = "a.a";
 387.245 +  if ((fd = creat (file,0666)) < 0)
 387.246 +    perror ("TEST FAILED: can't create test file"),_exit (errno);
 387.247 +  close (fd);
 387.248 +  if (fork ()) {		/* parent */
 387.249 +    if ((fd = open (file,O_RDWR,0)) < 0) abort();
 387.250 +    if (flock (fd,LOCK_SH) == -1) abort ();
 387.251 +    sleep (5);
 387.252 +    if ((fd2 = open (file,O_RDWR,0)) < 0) abort ();
 387.253 +    sleep (1);
 387.254 +    puts ("parent test ready -- will hang here if flock() works correctly");
 387.255 +    close (fd2);
 387.256 +    wait (0);
 387.257 +    puts ("OS BUG: child terminated");
 387.258 +    _exit (0);
 387.259 +  }
 387.260 +  else {			/* child */
 387.261 +    sleep (2);
 387.262 +    if ((fd = open (file,O_RDWR,0666)) < 0) abort ();
 387.263 +    puts ("child test ready -- child will hang if no bug");
 387.264 +    if (flock (fd,LOCK_EX) == -1) abort ();
 387.265 +    puts ("OS BUG: child got lock");
 387.266 +  }
 387.267 +}
 387.268 +#endif
 387.269 +
 387.270 +/* Master/slave details
 387.271 + *
 387.272 + *  On broken systems, we invoke an inferior fork to execute any driver
 387.273 + * dispatches which are likely to tickle this bug; specifically, any
 387.274 + * dispatch which may fiddle with a mailbox that is already selected.  As
 387.275 + * of this writing, these are: delete, rename, status, scan, copy, and append.
 387.276 + *
 387.277 + *  Delete and rename are pretty marginal, yet there are certain clients
 387.278 + * (e.g. Outlook Express) that really want to delete or rename the selected
 387.279 + * mailbox.  The same is true of status, but there are people (such as the
 387.280 + * authors of Entourage) who don't understand why status of the selected
 387.281 + * mailbox is bad news.
 387.282 + *
 387.283 + *  However, in copy and append it is reasonable to do this to a selected
 387.284 + * mailbox.  Although scanning the selected mailbox isn't particularly
 387.285 + * sensible, it's hard to avoid due to wildcards.
 387.286 + *
 387.287 + *  It is still possible for an application to trigger the bug by doing
 387.288 + * mail_open() on the same mailbox twice.  Don't do it.
 387.289 + *
 387.290 + *  Once the slave is invoked, the master only has to read events from the
 387.291 + * slave's output (see below for these events) and translate these events
 387.292 + * to the appropriate c-client callback.  When end of file occurs on the pipe,
 387.293 + * the master reads the slave's exit status and uses that as the function
 387.294 + * return.  The append master is slightly more complicated because it has to
 387.295 + * send data back to the slave (see below).
 387.296 + *
 387.297 + *  The slave takes callback events from the driver which otherwise would
 387.298 + * pass to the main program.  Only those events which a slave can actually
 387.299 + * encounter are covered here; for example mm_searched() and mm_list() are
 387.300 + * not covered since a slave never does the operations that trigger these.
 387.301 + * Certain other events (mm_exists(), mm_expunged(), mm_flags()) are discarded
 387.302 + * by the slave since the master will generate these events for itself.
 387.303 + *
 387.304 + *  The other events cause the slave to write a newline-terminated string to
 387.305 + * its output.  The first character of string indicates the event: S for
 387.306 + * mm_status(), N for mm_notify(), L for mm_log(), C for mm_critical(), X for
 387.307 + * mm_nocritical(), D for mm_diskerror(), F for mm_fatal(), and "A" for append
 387.308 + * argument callback.  Most of these events also carry data, which carried as
 387.309 + * text space-delimited in the string.
 387.310 + *
 387.311 + *  Append argument callback requires the master to provide the slave with
 387.312 + * data in the slave's input.  The first thing that the master provides is
 387.313 + * either a "+" (master has data for the slave) or a "-" (master has no data).
 387.314 + * If the master has data, it will then send the flags, internal date, and
 387.315 + * message text, each as <text octet count><SPACE><text>.
 387.316 + */
 387.317 +
 387.318 +/*  It should be alright for lockslavep to be a global, since it will always
 387.319 + * be zero in the master (which is where threads would be).  The slave won't
 387.320 + * ever thread, since any driver which threads in its methods probably can't
 387.321 + * use fcntl() locking so won't have DR_LOCKING in its driver flags 
 387.322 + *
 387.323 + *  lockslavep can not be a static, since it's used by the dispatch macros.
 387.324 + */
 387.325 +
 387.326 +int lockslavep = 0;		/* non-zero means slave process for locking */
 387.327 +static int lockproxycopy = 0;	/* non-zero means redo copy as proxy */
 387.328 +FILE *slavein = NIL;		/* slave input */
 387.329 +FILE *slaveout = NIL;		/* slave output */
 387.330 +
 387.331 +
 387.332 +/* Common master
 387.333 + * Accepts: permitted stream
 387.334 + *	    append callback (append calls only, else NIL)
 387.335 + *	    data for callback (append calls only, else NIL)
 387.336 + * Returns: (master) T if slave succeeded, NIL if slave failed
 387.337 + *	    (slave) NIL always, with lockslavep non-NIL
 387.338 + */
 387.339 +
 387.340 +static long master (MAILSTREAM *stream,append_t af,void *data)
 387.341 +{
 387.342 +  MAILSTREAM *st;
 387.343 +  MAILSTATUS status;
 387.344 +  STRING *message;
 387.345 +  FILE *pi,*po;
 387.346 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 387.347 +  long ret = NIL;
 387.348 +  unsigned long i,j;
 387.349 +  int c,pid,pipei[2],pipeo[2];
 387.350 +  char *s,*t,event[MAILTMPLEN],tmp[MAILTMPLEN];
 387.351 +  lockproxycopy = NIL;		/* not doing a lock proxycopy */
 387.352 +				/* make pipe from slave */
 387.353 +  if (pipe (pipei) < 0) mm_log ("Can't create input pipe",ERROR);
 387.354 +  else if (pipe (pipeo) < 0) {
 387.355 +    mm_log ("Can't create output pipe",ERROR);
 387.356 +    close (pipei[0]); close (pipei[1]);
 387.357 +  }
 387.358 +  else if ((pid = fork ()) < 0) {/* make slave */
 387.359 +    mm_log ("Can't create execution process",ERROR);
 387.360 +    close (pipei[0]); close (pipei[1]);
 387.361 +    close (pipeo[0]); close (pipeo[1]);
 387.362 +  }
 387.363 +  else if (lockslavep = !pid) {	/* are we slave or master? */
 387.364 +    alarm (0);			/* slave doesn't have alarms or signals */
 387.365 +    for (c = 0; c < NSIG; c++) signal (c,SIG_DFL);
 387.366 +    if (!(slavein = fdopen (pipeo[0],"r")) ||
 387.367 +	!(slaveout = fdopen (pipei[1],"w")))
 387.368 +      fatal ("Can't do slave pipe buffered I/O");
 387.369 +    close (pipei[0]);		/* close parent's side of the pipes */
 387.370 +    close (pipeo[1]);
 387.371 +  }
 387.372 +
 387.373 +  else {			/* master process */
 387.374 +    void *blockdata = (*bn) (BLOCK_SENSITIVE,NIL);
 387.375 +    close (pipei[1]);		/* close slave's side of the pipes */
 387.376 +    close (pipeo[0]);
 387.377 +    if (!(pi = fdopen (pipei[0],"r")) || !(po = fdopen (pipeo[1],"w")))
 387.378 +      fatal ("Can't do master pipe buffered I/O");
 387.379 +				/* do slave events until EOF */
 387.380 +				/* read event */
 387.381 +    while (fgets (event,MAILTMPLEN-1,pi)) {
 387.382 +      if (!(s = strchr (event,'\n'))) {
 387.383 +	sprintf (tmp,"Execution process event string too long: %.500s",event);
 387.384 +	fatal (tmp);
 387.385 +      }
 387.386 +      *s = '\0';		/* tie off event at end of line */
 387.387 +      switch (event[0]) {	/* analyze event */
 387.388 +      case 'A':			/* append callback */
 387.389 +	if ((*af) (NIL,data,&s,&t,&message)) {
 387.390 +	  if (i = message ? SIZE (message) : 0) {
 387.391 +	    if (!s) s = "";	/* default values */
 387.392 +	    if (!t) t = "";
 387.393 +	  }
 387.394 +	  else s = t = "";	/* no flags or date if no message */
 387.395 +	  errno = NIL;		/* reset last error */
 387.396 +				/* build response */
 387.397 +	  if (fprintf (po,"+%lu %s%lu %s%lu ",strlen (s),s,strlen (t),t,i) < 0)
 387.398 +	    fatal ("Failed to pipe append command");
 387.399 +				/* write message text */
 387.400 +	  if (i) do if (putc (c = 0xff & SNX (message),po) == EOF) {
 387.401 +	    sprintf (tmp,"Failed to pipe %lu bytes (of %lu), last=%u: %.100s",
 387.402 +		     i,message->size,c,strerror (errno));
 387.403 +	    fatal (tmp);
 387.404 +	  } while (--i);
 387.405 +	}
 387.406 +	else putc ('-',po);	/* append error */
 387.407 +	fflush (po);
 387.408 +	break;
 387.409 +      case '&':			/* slave wants a proxycopy? */
 387.410 +	lockproxycopy = T;
 387.411 +	break;
 387.412 +
 387.413 +      case 'L':			/* mm_log() */
 387.414 +	i = strtoul (event+1,&s,10);
 387.415 +	if (!s || (*s++ != ' ')) {
 387.416 +	  sprintf (tmp,"Invalid log event arguments: %.500s",event);
 387.417 +	  fatal (tmp);
 387.418 +	}
 387.419 +	mm_log (s,i);
 387.420 +	break;
 387.421 +      case 'N':			/* mm_notify() */
 387.422 +	st = (MAILSTREAM *) strtoul (event+1,&s,16);
 387.423 +	if (s && (*s++ == ' ')) {
 387.424 +	  i = strtoul (s,&s,10);/* get severity */
 387.425 +	  if (s && (*s++ == ' ')) {
 387.426 +	    mm_notify ((st == stream) ? stream : NIL,s,i);
 387.427 +	    break;
 387.428 +	  }
 387.429 +	}
 387.430 +	sprintf (tmp,"Invalid notify event arguments: %.500s",event);
 387.431 +	fatal (tmp);
 387.432 +
 387.433 +      case 'S':			/* mm_status() */
 387.434 +	st = (MAILSTREAM *) strtoul (event+1,&s,16);
 387.435 +	if (s && (*s++ == ' ')) {
 387.436 +	  status.flags = strtoul (s,&s,10);
 387.437 +	  if (s && (*s++ == ' ')) {
 387.438 +	    status.messages = strtoul (s,&s,10);
 387.439 +	    if (s && (*s++ == ' ')) {
 387.440 +	      status.recent = strtoul (s,&s,10);
 387.441 +	      if (s && (*s++ == ' ')) {
 387.442 +		status.unseen = strtoul (s,&s,10);
 387.443 +		if (s && (*s++ == ' ')) {
 387.444 +		  status.uidnext = strtoul (s,&s,10);
 387.445 +		  if (s && (*s++ == ' ')) {
 387.446 +		    status.uidvalidity = strtoul (s,&s,10);
 387.447 +		    if (s && (*s++ == ' ')) {
 387.448 +		      mm_status ((st == stream) ? stream : NIL,s,&status);
 387.449 +		      break;
 387.450 +		    }
 387.451 +		  }
 387.452 +		}
 387.453 +	      }
 387.454 +	    }
 387.455 +	  }
 387.456 +	}
 387.457 +	sprintf (tmp,"Invalid status event arguments: %.500s",event);
 387.458 +	fatal (tmp);
 387.459 +      case 'C':			/* mm_critical() */
 387.460 +	st = (MAILSTREAM *) strtoul (event+1,&s,16);
 387.461 +	mm_critical ((st == stream) ? stream : NIL);
 387.462 +	break;
 387.463 +      case 'X':			/* mm_nocritical() */
 387.464 +	st = (MAILSTREAM *) strtoul (event+1,&s,16);
 387.465 +	mm_nocritical ((st == stream) ? stream : NIL);
 387.466 +	break;
 387.467 +
 387.468 +      case 'D':			/* mm_diskerror() */
 387.469 +	st = (MAILSTREAM *) strtoul (event+1,&s,16);
 387.470 +	if (s && (*s++ == ' ')) {
 387.471 +	  i = strtoul (s,&s,10);
 387.472 +	  if (s && (*s++ == ' ')) {
 387.473 +	    j = (long) strtoul (s,NIL,10);
 387.474 +	    if (st == stream)	/* let's hope it's on usable stream */
 387.475 +	      putc (mm_diskerror (stream,(long) i,j) ? '+' : '-',po);
 387.476 +	    else if (j) {	/* serious diskerror on slave-created stream */
 387.477 +	      mm_log ("Retrying disk write to avoid mailbox corruption!",WARN);
 387.478 +	      sleep (5);	/* give some time for it to clear up */
 387.479 +	      putc ('-',po);	/* don't abort */
 387.480 +	    }
 387.481 +	    else {		/* recoverable on slave-created stream */
 387.482 +	      mm_log ("Error on disk write",ERROR);
 387.483 +	      putc ('+',po);	/* so abort it */
 387.484 +	    }
 387.485 +	    fflush (po);	/* force it out either way */
 387.486 +	    break;
 387.487 +	  }
 387.488 +	}
 387.489 +	sprintf (tmp,"Invalid diskerror event arguments: %.500s",event);
 387.490 +	fatal (tmp);
 387.491 +      case 'F':			/* mm_fatal() */
 387.492 +	mm_fatal (event+1);
 387.493 +	break;
 387.494 +      default:			/* random lossage */
 387.495 +	sprintf (tmp,"Unknown event from execution process: %.500s",event);
 387.496 +	fatal (tmp);
 387.497 +      }
 387.498 +    }
 387.499 +    fclose (pi); fclose (po);	/* done with the pipes */
 387.500 +				/* get slave status */
 387.501 +    grim_pid_reap_status (pid,NIL,&ret);
 387.502 +    if (ret & 0177) {		/* signal or stopped */
 387.503 +      sprintf (tmp,"Execution process terminated abnormally (%lx)",ret);
 387.504 +      mm_log (tmp,ERROR);
 387.505 +      ret = NIL;
 387.506 +    }
 387.507 +    else ret >>= 8;		/* return exit code */
 387.508 +    (*bn) (BLOCK_NONSENSITIVE,blockdata);
 387.509 +  }
 387.510 +  return ret;			/* return status */
 387.511 +}
 387.512 +
 387.513 +/* Safe driver calls */
 387.514 +
 387.515 +
 387.516 +/* Safely delete mailbox
 387.517 + * Accepts: driver to call under slave
 387.518 + *	    MAIL stream
 387.519 + *	    mailbox name to delete
 387.520 + * Returns: T on success, NIL on failure
 387.521 + */
 387.522 +
 387.523 +long safe_delete (DRIVER *dtb,MAILSTREAM *stream,char *mbx)
 387.524 +{
 387.525 +  long ret = master (stream,NIL,NIL);
 387.526 +  if (lockslavep) exit ((*dtb->mbxdel) (stream,mbx));
 387.527 +  return ret;
 387.528 +}
 387.529 +
 387.530 +
 387.531 +/* Safely rename mailbox
 387.532 + * Accepts: driver to call under slave
 387.533 + *	    MAIL stream
 387.534 + *	    old mailbox name
 387.535 + *	    new mailbox name (or NIL for delete)
 387.536 + * Returns: T on success, NIL on failure
 387.537 + */
 387.538 +
 387.539 +long safe_rename (DRIVER *dtb,MAILSTREAM *stream,char *old,char *newname)
 387.540 +{
 387.541 +  long ret = master (stream,NIL,NIL);
 387.542 +  if (lockslavep) exit ((*dtb->mbxren) (stream,old,newname));
 387.543 +  return ret;
 387.544 +}
 387.545 +
 387.546 +
 387.547 +/* Safely get status of mailbox
 387.548 + * Accepts: driver to call under slave
 387.549 + *	    MAIL stream
 387.550 + *	    mailbox name
 387.551 + *	    status flags
 387.552 + * Returns: T on success, NIL on failure
 387.553 + */
 387.554 +
 387.555 +long safe_status (DRIVER *dtb,MAILSTREAM *stream,char *mbx,long flags)
 387.556 +{
 387.557 +  long ret = master (stream,NIL,NIL);
 387.558 +  if (lockslavep) exit ((*dtb->status) (stream,mbx,flags));
 387.559 +  return ret;
 387.560 +}
 387.561 +
 387.562 +
 387.563 +/* Scan file for contents
 387.564 + * Accepts: driver to call under slave
 387.565 + *	    file name
 387.566 + *	    desired contents
 387.567 + *	    length of contents
 387.568 + *	    length of file
 387.569 + * Returns: NIL if contents not found, T if found
 387.570 + */
 387.571 +
 387.572 +long safe_scan_contents (DRIVER *dtb,char *name,char *contents,
 387.573 +			 unsigned long csiz,unsigned long fsiz)
 387.574 +{
 387.575 +  long ret = master (NIL,NIL,NIL);
 387.576 +  if (lockslavep) exit (scan_contents (dtb,name,contents,csiz,fsiz));
 387.577 +  return ret;
 387.578 +}
 387.579 +
 387.580 +/* Safely copy message to mailbox
 387.581 + * Accepts: driver to call under slave
 387.582 + *	    MAIL stream
 387.583 + *	    sequence
 387.584 + *	    destination mailbox
 387.585 + *	    copy options
 387.586 + * Returns: T if success, NIL if failed
 387.587 + */
 387.588 +
 387.589 +long safe_copy (DRIVER *dtb,MAILSTREAM *stream,char *seq,char *mbx,long flags)
 387.590 +{
 387.591 +  mailproxycopy_t pc =
 387.592 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 387.593 +  long ret = master (stream,NIL,NIL);
 387.594 +  if (lockslavep) {
 387.595 +				/* don't do proxycopy in slave */
 387.596 +    if (pc) mail_parameters (stream,SET_MAILPROXYCOPY,(void *) slaveproxycopy);
 387.597 +    exit ((*dtb->copy) (stream,seq,mbx,flags));
 387.598 +  }
 387.599 +				/* do any proxycopy in master */
 387.600 +  if (lockproxycopy && pc) return (*pc) (stream,seq,mbx,flags);
 387.601 +  return ret;
 387.602 +}
 387.603 +
 387.604 +
 387.605 +/* Append package for slave */
 387.606 +
 387.607 +typedef struct append_data {
 387.608 +  int first;			/* flag indicating first message */
 387.609 +  char *flags;			/* message flags */
 387.610 +  char *date;			/* message date */
 387.611 +  char *msg;			/* message text */
 387.612 +  STRING message;		/* message stringstruct */
 387.613 +} APPENDDATA;
 387.614 +
 387.615 +
 387.616 +/* Safely append message to mailbox
 387.617 + * Accepts: driver to call under slave
 387.618 + *	    MAIL stream
 387.619 + *	    destination mailbox
 387.620 + *	    append callback
 387.621 + *	    data for callback
 387.622 + * Returns: T if append successful, else NIL
 387.623 + */
 387.624 +
 387.625 +long safe_append (DRIVER *dtb,MAILSTREAM *stream,char *mbx,append_t af,
 387.626 +		  void *data)
 387.627 +{
 387.628 +  long ret = master (stream,af,data);
 387.629 +  if (lockslavep) {
 387.630 +    APPENDDATA ad;
 387.631 +    ad.first = T;		/* initialize initial append package */
 387.632 +    ad.flags = ad.date = ad.msg = NIL;
 387.633 +    exit ((*dtb->append) (stream,mbx,slave_append,&ad));
 387.634 +  }
 387.635 +  return ret;
 387.636 +}
 387.637 +
 387.638 +/* Slave callbacks */
 387.639 +
 387.640 +
 387.641 +/* Message exists (i.e. there are that many messages in the mailbox)
 387.642 + * Accepts: MAIL stream
 387.643 + *	    message number
 387.644 + */
 387.645 +
 387.646 +void slave_exists (MAILSTREAM *stream,unsigned long number)
 387.647 +{
 387.648 +  /* this event never passed by slaves */
 387.649 +}
 387.650 +
 387.651 +
 387.652 +/* Message expunged
 387.653 + * Accepts: MAIL stream
 387.654 + *	    message number
 387.655 + */
 387.656 +
 387.657 +void slave_expunged (MAILSTREAM *stream,unsigned long number)
 387.658 +{
 387.659 +  /* this event never passed by slaves */
 387.660 +}
 387.661 +
 387.662 +
 387.663 +/* Message status changed
 387.664 + * Accepts: MAIL stream
 387.665 + *	    message number
 387.666 + */
 387.667 +
 387.668 +void slave_flags (MAILSTREAM *stream,unsigned long number)
 387.669 +{
 387.670 +  /* this event never passed by slaves */
 387.671 +}
 387.672 +
 387.673 +/* Mailbox status
 387.674 + * Accepts: MAIL stream
 387.675 + *	    mailbox name
 387.676 + *	    mailbox status
 387.677 + */
 387.678 +
 387.679 +void slave_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 387.680 +{
 387.681 +  int i,c;
 387.682 +  fprintf (slaveout,"S%lx %lu %lu %lu %lu %lu %lu ",
 387.683 +	  (unsigned long) stream,status->flags,status->messages,status->recent,
 387.684 +	  status->unseen,status->uidnext,status->uidvalidity,mailbox);
 387.685 +				/* yow!  are we paranoid enough yet? */
 387.686 +  for (i = 0; (i < 500) && (c = *mailbox++); ++i) switch (c) {
 387.687 +  case '\r': case '\n':		/* newline in a mailbox name? */
 387.688 +    c = ' ';
 387.689 +  default:
 387.690 +    putc (c,slaveout);
 387.691 +  }
 387.692 +  putc ('\n',slaveout);
 387.693 +  fflush (slaveout);
 387.694 +}
 387.695 +
 387.696 +/* Notification event
 387.697 + * Accepts: MAIL stream
 387.698 + *	    string to log
 387.699 + *	    error flag
 387.700 + */
 387.701 +
 387.702 +void slave_notify (MAILSTREAM *stream,char *string,long errflg)
 387.703 +{
 387.704 +  int i,c;
 387.705 +  fprintf (slaveout,"N%lx %lu ",(unsigned long) stream,errflg);
 387.706 +				/* prevent more than 500 bytes */
 387.707 +  for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) {
 387.708 +  case '\r': case '\n':		/* or embedded newline */
 387.709 +    c = ' ';
 387.710 +  default:
 387.711 +    putc (c,slaveout);
 387.712 +  }
 387.713 +  putc ('\n',slaveout);
 387.714 +  fflush (slaveout);
 387.715 +}
 387.716 +
 387.717 +
 387.718 +/* Log an event for the user to see
 387.719 + * Accepts: string to log
 387.720 + *	    error flag
 387.721 + */
 387.722 +
 387.723 +void slave_log (char *string,long errflg)
 387.724 +{
 387.725 +  int i,c;
 387.726 +  fprintf (slaveout,"L%lu ",errflg);
 387.727 +				/* prevent more than 500 bytes */
 387.728 +  for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) {
 387.729 +  case '\r': case '\n':		/* or embedded newline */
 387.730 +    c = ' ';
 387.731 +  default:
 387.732 +    putc (c,slaveout);
 387.733 +  }
 387.734 +  putc ('\n',slaveout);
 387.735 +  fflush (slaveout);
 387.736 +}
 387.737 +
 387.738 +/* About to enter critical code
 387.739 + * Accepts: stream
 387.740 + */
 387.741 +
 387.742 +void slave_critical (MAILSTREAM *stream)
 387.743 +{
 387.744 +  fprintf (slaveout,"C%lx\n",(unsigned long) stream);
 387.745 +  fflush (slaveout);
 387.746 +}
 387.747 +
 387.748 +
 387.749 +/* About to exit critical code
 387.750 + * Accepts: stream
 387.751 + */
 387.752 +
 387.753 +void slave_nocritical (MAILSTREAM *stream)
 387.754 +{
 387.755 +  fprintf (slaveout,"X%lx\n",(unsigned long) stream);
 387.756 +  fflush (slaveout);
 387.757 +}
 387.758 +
 387.759 +/* Disk error found
 387.760 + * Accepts: stream
 387.761 + *	    system error code
 387.762 + *	    flag indicating that mailbox may be clobbered
 387.763 + * Returns: abort flag
 387.764 + */
 387.765 +
 387.766 +long slave_diskerror (MAILSTREAM *stream,long errcode,long serious)
 387.767 +{
 387.768 +  char tmp[MAILTMPLEN];
 387.769 +  int c;
 387.770 +  long ret = NIL;
 387.771 +  fprintf (slaveout,"D%lx %lu %lu\n",(unsigned long) stream,errcode,serious);
 387.772 +  fflush (slaveout);
 387.773 +  switch (c = getc (slavein)) {
 387.774 +  case EOF:			/* pipe broken */
 387.775 +    slave_fatal ("Pipe broken reading diskerror response");
 387.776 +  case '+':			/* user wants to abort */
 387.777 +    ret = LONGT;
 387.778 +  case '-':			/* no abort */
 387.779 +    break;
 387.780 +  default:
 387.781 +    sprintf (tmp,"Unknown master response for diskerror: %c",c);
 387.782 +    slave_fatal (tmp);
 387.783 +  }
 387.784 +  return ret;
 387.785 +}
 387.786 +
 387.787 +
 387.788 +/* Log a fatal error event
 387.789 + * Accepts: string to log
 387.790 + * Does not return
 387.791 + */
 387.792 +
 387.793 +void slave_fatal (char *string)
 387.794 +{
 387.795 +  int i,c;
 387.796 +  syslog (LOG_ALERT,"IMAP toolkit slave process crash: %.500s",string);
 387.797 +  putc ('F',slaveout);
 387.798 +				/* prevent more than 500 bytes */
 387.799 +  for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) {
 387.800 +  case '\r': case '\n':		/* newline in a mailbox name? */
 387.801 +    c = ' ';
 387.802 +  default:
 387.803 +    putc (c,slaveout);
 387.804 +  }
 387.805 +  putc ('\n',slaveout);
 387.806 +  fflush (slaveout);
 387.807 +  abort ();			/* die */
 387.808 +}
 387.809 +
 387.810 +/* Append read buffer
 387.811 + * Accepts: number of bytes to read
 387.812 + *	    error message if fails
 387.813 + * Returns: read-in string
 387.814 + */
 387.815 +
 387.816 +static char *slave_append_read (unsigned long n,char *error)
 387.817 +{
 387.818 +#if 0
 387.819 +  unsigned long i;
 387.820 +#endif
 387.821 +  int c;
 387.822 +  char *t,tmp[MAILTMPLEN];
 387.823 +  char *s = (char *) fs_get (n + 1);
 387.824 +  s[n] = '\0';
 387.825 +#if 0
 387.826 +  /* This doesn't work on Solaris with GCC.  I think that it's a C library
 387.827 +   * bug, since the problem only shows up if the application does fread()
 387.828 +   * on some other file
 387.829 +   */
 387.830 +  for (t = s; n && ((i = fread (t,1,n,slavein)); t += i,n -= i);
 387.831 +#else
 387.832 +  for (t = s; n && ((c = getc (slavein)) != EOF); *t++ = c,--n);
 387.833 +#endif
 387.834 +  if (n) {
 387.835 +    sprintf(tmp,"Pipe broken reading %.100s with %lu bytes remaining",error,n);
 387.836 +    slave_fatal (tmp);
 387.837 +  }
 387.838 +  return s;
 387.839 +}
 387.840 +
 387.841 +/* Append message callback
 387.842 + * Accepts: MAIL stream
 387.843 + *	    append data package
 387.844 + *	    pointer to return initial flags
 387.845 + *	    pointer to return message internal date
 387.846 + *	    pointer to return stringstruct of message or NIL to stop
 387.847 + * Returns: T if success (have message or stop), NIL if error
 387.848 + */
 387.849 +
 387.850 +long slave_append (MAILSTREAM *stream,void *data,char **flags,char **date,
 387.851 +		   STRING **message)
 387.852 +{
 387.853 +  char tmp[MAILTMPLEN];
 387.854 +  unsigned long n;
 387.855 +  int c;
 387.856 +  APPENDDATA *ad = (APPENDDATA *) data;
 387.857 +				/* flush text of previous message */
 387.858 +  if (ad->flags) fs_give ((void **) &ad->flags);
 387.859 +  if (ad->date) fs_give ((void **) &ad->date);
 387.860 +  if (ad->msg) fs_give ((void **) &ad->msg);
 387.861 +  *flags = *date = NIL;		/* assume no flags or date */
 387.862 +  fputs ("A\n",slaveout);	/* tell master we're doing append callback */
 387.863 +  fflush (slaveout);
 387.864 +  switch (c = getc (slavein)) {	/* what did master say? */
 387.865 +  case '+':			/* have message, get size of flags */
 387.866 +    for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0'));
 387.867 +    if (c != ' ') {
 387.868 +      if (c == EOF) sprintf (tmp,"Pipe broken after flag size %lu",n);
 387.869 +      sprintf (tmp,"Missing delimiter after flag size %lu: %c",n,c);
 387.870 +      slave_fatal (tmp);
 387.871 +    }
 387.872 +    if (n) *flags = ad->flags = slave_append_read (n,"flags");
 387.873 +				/* get size of date */
 387.874 +    for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0'));
 387.875 +    if (c != ' ') {
 387.876 +      if (c == EOF) sprintf (tmp,"Pipe broken after date size %lu",n);
 387.877 +      else sprintf (tmp,"Missing delimiter after date size %lu: %c",n,c);
 387.878 +      slave_fatal (tmp);
 387.879 +    }
 387.880 +    if (n) *date = ad->date = slave_append_read (n,"date");
 387.881 +				/* get size of message */
 387.882 +    for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0'));
 387.883 +    if (c != ' ') {
 387.884 +      if (c == EOF) sprintf (tmp,"Pipe broken after message size %lu",n);
 387.885 +      sprintf (tmp,"Missing delimiter after message size %lu: %c",n,c);
 387.886 +      slave_fatal (tmp);
 387.887 +    }
 387.888 +    if (n) {			/* make buffer for message */
 387.889 +      ad->msg = slave_append_read (n,"message");
 387.890 +				/* initialize stringstruct */
 387.891 +      INIT (&ad->message,mail_string,(void *) ad->msg,n);
 387.892 +      ad->first = NIL;		/* no longer first message */
 387.893 +      *message = &ad->message;	/* return message */
 387.894 +    }
 387.895 +    else *message = NIL;	/* empty message */
 387.896 +    return LONGT;
 387.897 +  case '-':			/* error */
 387.898 +    *message = NIL;		/* set stop */
 387.899 +    break;
 387.900 +  case EOF:			/* end of file */
 387.901 +    slave_fatal ("Pipe broken reading append response");
 387.902 +  default:			/* unknown event */
 387.903 +    sprintf (tmp,"Unknown master response for append: %c",c);
 387.904 +    slave_fatal (tmp);
 387.905 +  }
 387.906 +  return NIL;			/* return failure */
 387.907 +}
 387.908 +
 387.909 +/* Proxy copy across mailbox formats
 387.910 + * Accepts: mail stream
 387.911 + *	    sequence to copy on this stream
 387.912 + *	    destination mailbox
 387.913 + *	    option flags
 387.914 + * Returns: T if success, else NIL
 387.915 + */
 387.916 +
 387.917 +long slaveproxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,
 387.918 +		     long options)
 387.919 +{
 387.920 +  fputs ("&\n",slaveout);	/* redo copy as append */
 387.921 +  fflush (slaveout);
 387.922 +  return NIL;			/* failure for now */
 387.923 +}
   388.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   388.2 +++ b/src/osdep/unix/flocksim.h	Mon Sep 14 15:17:45 2009 +0900
   388.3 @@ -0,0 +1,117 @@
   388.4 +/* ========================================================================
   388.5 + * Copyright 1988-2006 University of Washington
   388.6 + *
   388.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   388.8 + * you may not use this file except in compliance with the License.
   388.9 + * You may obtain a copy of the License at
  388.10 + *
  388.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  388.12 + *
  388.13 + * 
  388.14 + * ========================================================================
  388.15 + */
  388.16 +
  388.17 +/*
  388.18 + * Program:	flock() emulation via fcntl() locking
  388.19 + *
  388.20 + * Author:	Mark Crispin
  388.21 + *		Networks and Distributed Computing
  388.22 + *		Computing & Communications
  388.23 + *		University of Washington
  388.24 + *		Administration Building, AG-44
  388.25 + *		Seattle, WA  98195
  388.26 + *		Internet: MRC@CAC.Washington.EDU
  388.27 + *
  388.28 + * Date:	10 April 2001
  388.29 + * Last Edited:	20 December 2006
  388.30 + */
  388.31 +
  388.32 +
  388.33 +#include "dummy.h"		/* get scan_contents() prototype */
  388.34 +
  388.35 +#define flock flocksim		/* use ours instead of theirs */
  388.36 +
  388.37 +#undef LOCK_SH
  388.38 +#define LOCK_SH 1		/* shared lock */
  388.39 +#undef LOCK_EX
  388.40 +#define LOCK_EX 2		/* exclusive lock */
  388.41 +#undef LOCK_NB
  388.42 +#define LOCK_NB 4		/* no blocking */
  388.43 +#undef LOCK_UN
  388.44 +#define LOCK_UN 8		/* unlock */
  388.45 +
  388.46 +/* Safe locking definitions */
  388.47 +
  388.48 +extern int lockslavep;		/* non-zero means slave process */
  388.49 +
  388.50 +#undef SAFE_DELETE
  388.51 +#define SAFE_DELETE(dtb,stream,mbx) (dtb->flags & DR_LOCKING) ? \
  388.52 +  safe_delete (dtb,stream,mbx) : (*dtb->mbxdel) (stream,mbx)
  388.53 +#undef SAFE_RENAME
  388.54 +#define SAFE_RENAME(dtb,stream,old,newname) (dtb->flags & DR_LOCKING) ? \
  388.55 +  safe_rename (dtb,stream,old,newname) : (*dtb->mbxren) (stream,old,newname)
  388.56 +#undef SAFE_STATUS
  388.57 +#define SAFE_STATUS(dtb,stream,mbx,bits) (dtb->flags & DR_LOCKING) ? \
  388.58 +  safe_status (dtb,stream,mbx,bits) : (*dtb->status) (stream,mbx,bits)
  388.59 +#undef SAFE_SCAN_CONTENTS
  388.60 +#define SAFE_SCAN_CONTENTS(dtb,name,contents,csiz,fsiz) \
  388.61 +  (!dtb || (dtb->flags & DR_LOCKING)) ? \
  388.62 +   safe_scan_contents (dtb,name,contents,csiz,fsiz) : \
  388.63 +   scan_contents (dtb,name,contents,csiz,fsiz)
  388.64 +#undef SAFE_COPY
  388.65 +#define SAFE_COPY(dtb,stream,seq,mbx,bits) (dtb->flags & DR_LOCKING) ? \
  388.66 +  safe_copy (dtb,stream,seq,mbx,bits) : (*dtb->copy) (stream,seq,mbx,bits)
  388.67 +#undef SAFE_APPEND
  388.68 +#define SAFE_APPEND(dtb,stream,mbx,af,data) (dtb->flags & DR_LOCKING) ? \
  388.69 +  safe_append (dtb,stream,mbx,af,data) : (*dtb->append) (stream,mbx,af,data)
  388.70 +
  388.71 +#undef MM_EXISTS
  388.72 +#define MM_EXISTS (lockslavep ? slave_exists : mm_exists)
  388.73 +#undef MM_EXPUNGED
  388.74 +#define MM_EXPUNGED (lockslavep ? slave_expunged : mm_expunged)
  388.75 +#undef MM_FLAGS
  388.76 +#define MM_FLAGS (lockslavep ? slave_flags : mm_flags)
  388.77 +#undef MM_NOTIFY
  388.78 +#define MM_NOTIFY (lockslavep ? slave_notify : mm_notify)
  388.79 +#undef MM_STATUS
  388.80 +#define MM_STATUS (lockslavep ? slave_status : mm_status)
  388.81 +#undef MM_LOG
  388.82 +#define MM_LOG (lockslavep ? slave_log : mm_log)
  388.83 +#undef MM_CRITICAL
  388.84 +#define MM_CRITICAL (lockslavep ? slave_critical : mm_critical)
  388.85 +#undef MM_NOCRITICAL
  388.86 +#define MM_NOCRITICAL (lockslavep ? slave_nocritical : mm_nocritical)
  388.87 +#undef MM_DISKERROR
  388.88 +#define MM_DISKERROR (lockslavep ? slave_diskerror : mm_diskerror)
  388.89 +#undef MM_FATAL
  388.90 +#define MM_FATAL (lockslavep ? slave_fatal : mm_fatal)
  388.91 +#undef MM_APPEND
  388.92 +#define MM_APPEND(af) (lockslavep ? slave_append : (*af))
  388.93 +
  388.94 +/* Function prototypes */
  388.95 +
  388.96 +int flocksim (int fd,int operation);
  388.97 +
  388.98 +long safe_delete (DRIVER *dtb,MAILSTREAM *stream,char *mbx);
  388.99 +long safe_rename (DRIVER *dtb,MAILSTREAM *stream,char *old,char *newname);
 388.100 +long safe_status (DRIVER *dtb,MAILSTREAM *stream,char *mbx,long flags);
 388.101 +long safe_scan_contents (DRIVER *dtb,char *name,char *contents,
 388.102 +			 unsigned long csiz,unsigned long fsiz);
 388.103 +long safe_copy (DRIVER *dtb,MAILSTREAM *stream,char *seq,char *mbx,long flags);
 388.104 +long safe_append (DRIVER *dtb,MAILSTREAM *stream,char *mbx,append_t af,
 388.105 +		  void *data);
 388.106 +
 388.107 +void slave_exists (MAILSTREAM *stream,unsigned long number);
 388.108 +void slave_expunged (MAILSTREAM *stream,unsigned long number);
 388.109 +void slave_flags (MAILSTREAM *stream,unsigned long number);
 388.110 +void slave_notify (MAILSTREAM *stream,char *string,long errflg);
 388.111 +void slave_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
 388.112 +void slave_log (char *string,long errflg);
 388.113 +void slave_critical (MAILSTREAM *stream);
 388.114 +void slave_nocritical (MAILSTREAM *stream);
 388.115 +long slave_diskerror (MAILSTREAM *stream,long errcode,long serious);
 388.116 +void slave_fatal (char *string);
 388.117 +long slave_append (MAILSTREAM *stream,void *data,char **flags,char **date,
 388.118 +		   STRING **message);
 388.119 +long slaveproxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,
 388.120 +		     long options);
   389.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   389.2 +++ b/src/osdep/unix/fs_unix.c	Mon Sep 14 15:17:45 2009 +0900
   389.3 @@ -0,0 +1,71 @@
   389.4 +/* ========================================================================
   389.5 + * Copyright 1988-2006 University of Washington
   389.6 + *
   389.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   389.8 + * you may not use this file except in compliance with the License.
   389.9 + * You may obtain a copy of the License at
  389.10 + *
  389.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  389.12 + *
  389.13 + * 
  389.14 + * ========================================================================
  389.15 + */
  389.16 +
  389.17 +/*
  389.18 + * Program:	Free storage management routines
  389.19 + *
  389.20 + * Author:	Mark Crispin
  389.21 + *		Networks and Distributed Computing
  389.22 + *		Computing & Communications
  389.23 + *		University of Washington
  389.24 + *		Administration Building, AG-44
  389.25 + *		Seattle, WA  98195
  389.26 + *		Internet: MRC@CAC.Washington.EDU
  389.27 + *
  389.28 + * Date:	1 August 1988
  389.29 + * Last Edited:	30 August 2006
  389.30 + */
  389.31 +
  389.32 +/* Get a block of free storage
  389.33 + * Accepts: size of desired block
  389.34 + * Returns: free storage block
  389.35 + */
  389.36 +
  389.37 +void *fs_get (size_t size)
  389.38 +{
  389.39 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  389.40 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
  389.41 +  void *block = malloc (size ? size : (size_t) 1);
  389.42 +  if (!block) fatal ("Out of memory");
  389.43 +  (*bn) (BLOCK_NONSENSITIVE,data);
  389.44 +  return (block);
  389.45 +}
  389.46 +
  389.47 +
  389.48 +/* Resize a block of free storage
  389.49 + * Accepts: ** pointer to current block
  389.50 + *	    new size
  389.51 + */
  389.52 +
  389.53 +void fs_resize (void **block,size_t size)
  389.54 +{
  389.55 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  389.56 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
  389.57 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  389.58 +    fatal ("Can't resize memory");
  389.59 +  (*bn) (BLOCK_NONSENSITIVE,data);
  389.60 +}
  389.61 +
  389.62 +
  389.63 +/* Return a block of free storage
  389.64 + * Accepts: ** pointer to free storage block
  389.65 + */
  389.66 +
  389.67 +void fs_give (void **block)
  389.68 +{
  389.69 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  389.70 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
  389.71 +  free (*block);
  389.72 +  *block = NIL;
  389.73 +  (*bn) (BLOCK_NONSENSITIVE,data);
  389.74 +}
   390.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   390.2 +++ b/src/osdep/unix/fsync.c	Mon Sep 14 15:17:45 2009 +0900
   390.3 @@ -0,0 +1,39 @@
   390.4 +/* ========================================================================
   390.5 + * Copyright 1988-2006 University of Washington
   390.6 + *
   390.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   390.8 + * you may not use this file except in compliance with the License.
   390.9 + * You may obtain a copy of the License at
  390.10 + *
  390.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  390.12 + *
  390.13 + * 
  390.14 + * ========================================================================
  390.15 + */
  390.16 +
  390.17 +/*
  390.18 + * Program:	File sync emulator
  390.19 + *
  390.20 + * Author:	Mark Crispin
  390.21 + *		Networks and Distributed Computing
  390.22 + *		Computing & Communications
  390.23 + *		University of Washington
  390.24 + *		Administration Building, AG-44
  390.25 + *		Seattle, WA  98195
  390.26 + *		Internet: MRC@CAC.Washington.EDU
  390.27 + *
  390.28 + * Date:	3 May 1995
  390.29 + * Last Edited:	30 August 2006
  390.30 + */
  390.31 +
  390.32 +
  390.33 +/* Emulator for BSD fsync() call
  390.34 + * Accepts: file name
  390.35 + * Returns: 0 if successful, -1 if failure
  390.36 + */
  390.37 +
  390.38 +int fsync (int fd)
  390.39 +{
  390.40 +  sync ();
  390.41 +  return 0;
  390.42 +}
   391.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   391.2 +++ b/src/osdep/unix/ftl_unix.c	Mon Sep 14 15:17:45 2009 +0900
   391.3 @@ -0,0 +1,39 @@
   391.4 +/* ========================================================================
   391.5 + * Copyright 1988-2006 University of Washington
   391.6 + *
   391.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   391.8 + * you may not use this file except in compliance with the License.
   391.9 + * You may obtain a copy of the License at
  391.10 + *
  391.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  391.12 + *
  391.13 + * 
  391.14 + * ========================================================================
  391.15 + */
  391.16 +
  391.17 +/*
  391.18 + * Program:	UNIX crash management routines
  391.19 + *
  391.20 + * Author:	Mark Crispin
  391.21 + *		Networks and Distributed Computing
  391.22 + *		Computing & Communications
  391.23 + *		University of Washington
  391.24 + *		Administration Building, AG-44
  391.25 + *		Seattle, WA  98195
  391.26 + *		Internet: MRC@CAC.Washington.EDU
  391.27 + *
  391.28 + * Date:	1 August 1988
  391.29 + * Last Edited:	30 August 2006
  391.30 + */
  391.31 +
  391.32 +
  391.33 +/* Report a fatal error
  391.34 + * Accepts: string to output
  391.35 + */
  391.36 +
  391.37 +void fatal (char *string)
  391.38 +{
  391.39 +  MM_FATAL (string);		/* pass up the string */
  391.40 +  syslog (LOG_ALERT,"IMAP toolkit crash: %.100s",string);
  391.41 +  abort ();			/* die horribly */
  391.42 +}
   392.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   392.2 +++ b/src/osdep/unix/gethstid.c	Mon Sep 14 15:17:45 2009 +0900
   392.3 @@ -0,0 +1,38 @@
   392.4 +/* ========================================================================
   392.5 + * Copyright 1988-2006 University of Washington
   392.6 + *
   392.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   392.8 + * you may not use this file except in compliance with the License.
   392.9 + * You may obtain a copy of the License at
  392.10 + *
  392.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  392.12 + *
  392.13 + * 
  392.14 + * ========================================================================
  392.15 + */
  392.16 +
  392.17 +/*
  392.18 + * Program:	Get host ID emulator
  392.19 + *
  392.20 + * Author:	Mark Crispin
  392.21 + *		Networks and Distributed Computing
  392.22 + *		Computing & Communications
  392.23 + *		University of Washington
  392.24 + *		Administration Building, AG-44
  392.25 + *		Seattle, WA  98195
  392.26 + *		Internet: MRC@CAC.Washington.EDU
  392.27 + *
  392.28 + * Date:	3 May 1995
  392.29 + * Last Edited:	30 August 2006
  392.30 + */
  392.31 +
  392.32 +
  392.33 +/* Emulator for BSD gethostid() call
  392.34 + * Returns: unique identifier for this machine
  392.35 + */
  392.36 +
  392.37 +long gethostid (void)
  392.38 +{
  392.39 +  /* No gethostid() here, so just fake it and hope things turn out okay. */
  392.40 +  return 0xdeadface;
  392.41 +}
   393.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   393.2 +++ b/src/osdep/unix/getspnam.c	Mon Sep 14 15:17:45 2009 +0900
   393.3 @@ -0,0 +1,65 @@
   393.4 +/* ========================================================================
   393.5 + * Copyright 1988-2006 University of Washington
   393.6 + *
   393.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   393.8 + * you may not use this file except in compliance with the License.
   393.9 + * You may obtain a copy of the License at
  393.10 + *
  393.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  393.12 + *
  393.13 + * 
  393.14 + * ========================================================================
  393.15 + */
  393.16 +
  393.17 +/*
  393.18 + * Program:	64-bit getsockname()/getpeername() emulator
  393.19 + *
  393.20 + * Author:	Mark Crispin from code contributed by Chris Ross
  393.21 + *		Networks and Distributed Computing
  393.22 + *		Computing & Communications
  393.23 + *		University of Washington
  393.24 + *		Administration Building, AG-44
  393.25 + *		Seattle, WA  98195
  393.26 + *		Internet: MRC@CAC.Washington.EDU
  393.27 + *
  393.28 + * Date:	5 November 2004
  393.29 + * Last Edited:	30 August 2006
  393.30 + */
  393.31 +
  393.32 +
  393.33 +/* Jacket into getpeername()
  393.34 + * Accepts: socket
  393.35 + *	    pointer to socket address
  393.36 + *	    void pointer to len
  393.37 + * Returns: 0 if success, -1 if error
  393.38 + */
  393.39 +
  393.40 +int Getpeername (int s,struct sockaddr *name,size_t *namelen)
  393.41 +{
  393.42 +  int ret;
  393.43 +  socklen_t len = (socklen_t) *namelen;
  393.44 +  ret = getpeername (s,name,&len);
  393.45 +  *namelen = (size_t) len;
  393.46 +  return ret;
  393.47 +}
  393.48 +
  393.49 +
  393.50 +/* Jacket into getsockname()
  393.51 + * Accepts: socket
  393.52 + *	    pointer to socket address
  393.53 + *	    void pointer to len
  393.54 + * Returns: 0 if success, -1 if error
  393.55 + */
  393.56 +
  393.57 +int Getsockname (int s,struct sockaddr *name,size_t *namelen)
  393.58 +{
  393.59 +  int ret;
  393.60 +  socklen_t len = (socklen_t) *namelen;
  393.61 +  ret = getsockname (s,name,&len);
  393.62 +  *namelen = (size_t) len;
  393.63 +  return ret;
  393.64 +}
  393.65 +
  393.66 +
  393.67 +#define getpeername Getpeername
  393.68 +#define getsockname Getsockname
   394.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   394.2 +++ b/src/osdep/unix/gr_wait.c	Mon Sep 14 15:17:45 2009 +0900
   394.3 @@ -0,0 +1,46 @@
   394.4 +/* ========================================================================
   394.5 + * Copyright 1988-2006 University of Washington
   394.6 + *
   394.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   394.8 + * you may not use this file except in compliance with the License.
   394.9 + * You may obtain a copy of the License at
  394.10 + *
  394.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  394.12 + *
  394.13 + * 
  394.14 + * ========================================================================
  394.15 + */
  394.16 +
  394.17 +/*
  394.18 + * Program:	UNIX Grim PID Reaper -- wait() version
  394.19 + *
  394.20 + * Author:	Mark Crispin
  394.21 + *		Networks and Distributed Computing
  394.22 + *		Computing & Communications
  394.23 + *		University of Washington
  394.24 + *		Administration Building, AG-44
  394.25 + *		Seattle, WA  98195
  394.26 + *		Internet: MRC@CAC.Washington.EDU
  394.27 + *
  394.28 + * Date:	30 November 1993
  394.29 + * Last Edited:	30 August 2006
  394.30 + */
  394.31 + 
  394.32 +/* Grim PID reaper
  394.33 + * Accepts: process ID
  394.34 + *	    kill request flag
  394.35 + *	    status return value
  394.36 + */
  394.37 +
  394.38 +void grim_pid_reap_status (int pid,int killreq,void *status)
  394.39 +{
  394.40 +  int r;
  394.41 +  if (killreq) {
  394.42 +    kill (pid,SIGHUP);		/* kill if not already dead */
  394.43 +    alarm (10);			/* in case we get hosed */
  394.44 +    while (((r = wait (NIL)) != pid) &&
  394.45 +	   ((r > 0) || ((errno != ECHILD) && (errno != EINTR))));
  394.46 +    alarm (0);			/* cancel the alarm */
  394.47 +  }
  394.48 +  else while (((r = wait (status)) != pid) && ((r > 0) || (errno != ECHILD)));
  394.49 +}
   395.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   395.2 +++ b/src/osdep/unix/gr_wait4.c	Mon Sep 14 15:17:45 2009 +0900
   395.3 @@ -0,0 +1,39 @@
   395.4 +/* ========================================================================
   395.5 + * Copyright 1988-2006 University of Washington
   395.6 + *
   395.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   395.8 + * you may not use this file except in compliance with the License.
   395.9 + * You may obtain a copy of the License at
  395.10 + *
  395.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  395.12 + *
  395.13 + * 
  395.14 + * ========================================================================
  395.15 + */
  395.16 +
  395.17 +/*
  395.18 + * Program:	UNIX Grim PID Reaper -- wait4() version
  395.19 + *
  395.20 + * Author:	Mark Crispin
  395.21 + *		Networks and Distributed Computing
  395.22 + *		Computing & Communications
  395.23 + *		University of Washington
  395.24 + *		Administration Building, AG-44
  395.25 + *		Seattle, WA  98195
  395.26 + *		Internet: MRC@CAC.Washington.EDU
  395.27 + *
  395.28 + * Date:	30 November 1993
  395.29 + * Last Edited:	30 August 2006
  395.30 + */
  395.31 + 
  395.32 +/* Grim PID reaper
  395.33 + * Accepts: process ID
  395.34 + *	    kill request flag
  395.35 + *	    status return value
  395.36 + */
  395.37 +
  395.38 +void grim_pid_reap_status (int pid,int killreq,void *status)
  395.39 +{
  395.40 +  if (killreq) kill(pid,SIGHUP);/* kill if not already dead */
  395.41 +  while ((wait4 (pid,status,NIL,NIL) < 0) && (errno != ECHILD));
  395.42 +}
   396.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   396.2 +++ b/src/osdep/unix/gr_waitp.c	Mon Sep 14 15:17:45 2009 +0900
   396.3 @@ -0,0 +1,39 @@
   396.4 +/* ========================================================================
   396.5 + * Copyright 1988-2006 University of Washington
   396.6 + *
   396.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   396.8 + * you may not use this file except in compliance with the License.
   396.9 + * You may obtain a copy of the License at
  396.10 + *
  396.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  396.12 + *
  396.13 + * 
  396.14 + * ========================================================================
  396.15 + */
  396.16 +
  396.17 +/*
  396.18 + * Program:	UNIX Grim PID Reaper -- waitpid() version
  396.19 + *
  396.20 + * Author:	Mark Crispin
  396.21 + *		Networks and Distributed Computing
  396.22 + *		Computing & Communications
  396.23 + *		University of Washington
  396.24 + *		Administration Building, AG-44
  396.25 + *		Seattle, WA  98195
  396.26 + *		Internet: MRC@CAC.Washington.EDU
  396.27 + *
  396.28 + * Date:	30 November 1993
  396.29 + * Last Edited:	30 August 2006
  396.30 + */
  396.31 + 
  396.32 +/* Grim PID reaper
  396.33 + * Accepts: process ID
  396.34 + *	    kill request flag
  396.35 + *	    status return value
  396.36 + */
  396.37 +
  396.38 +void grim_pid_reap_status (int pid,int killreq,void *status)
  396.39 +{
  396.40 +  if (killreq) kill(pid,SIGHUP);/* kill if not already dead */
  396.41 +  while ((waitpid (pid,status,NIL) < 0) && (errno != ECHILD));
  396.42 +}
   397.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   397.2 +++ b/src/osdep/unix/ip4_unix.c	Mon Sep 14 15:17:45 2009 +0900
   397.3 @@ -0,0 +1,184 @@
   397.4 +/* ========================================================================
   397.5 + * Copyright 1988-2006 University of Washington
   397.6 + *
   397.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   397.8 + * you may not use this file except in compliance with the License.
   397.9 + * You may obtain a copy of the License at
  397.10 + *
  397.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  397.12 + *
  397.13 + * 
  397.14 + * ========================================================================
  397.15 + */
  397.16 +
  397.17 +/*
  397.18 + * Program:	UNIX IPv4 routines
  397.19 + *
  397.20 + * Author:	Mark Crispin
  397.21 + *		Networks and Distributed Computing
  397.22 + *		Computing & Communications
  397.23 + *		University of Washington
  397.24 + *		Administration Building, AG-44
  397.25 + *		Seattle, WA  98195
  397.26 + *		Internet: MRC@CAC.Washington.EDU
  397.27 + *
  397.28 + * Date:	18 December 2003
  397.29 + * Last Edited:	30 August 2006
  397.30 + */
  397.31 +
  397.32 +#define SADRLEN sizeof (struct sockaddr)
  397.33 +
  397.34 +#define SADR4(sadr) ((struct sockaddr_in *) sadr)
  397.35 +#define SADR4LEN sizeof (struct sockaddr_in)
  397.36 +#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
  397.37 +#define ADR4LEN sizeof (struct in_addr)
  397.38 +#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
  397.39 +
  397.40 +
  397.41 +/* IP abstraction layer */
  397.42 +
  397.43 +char *ip_sockaddrtostring (struct sockaddr *sadr);
  397.44 +long ip_sockaddrtoport (struct sockaddr *sadr);
  397.45 +void *ip_stringtoaddr (char *text,size_t *len,int *family);
  397.46 +struct sockaddr *ip_newsockaddr (size_t *len);
  397.47 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
  397.48 +			      unsigned short port,size_t *len);
  397.49 +char *ip_sockaddrtoname (struct sockaddr *sadr);
  397.50 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
  397.51 +		     void **next);
  397.52 +
  397.53 +/* Return IP address string from socket address
  397.54 + * Accepts: socket address
  397.55 + * Returns: IP address as name string
  397.56 + */
  397.57 +
  397.58 +char *ip_sockaddrtostring (struct sockaddr *sadr)
  397.59 +{
  397.60 +  return (sadr->sa_family == PF_INET) ?
  397.61 +    inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4";
  397.62 +}
  397.63 +
  397.64 +
  397.65 +/* Return port from socket address
  397.66 + * Accepts: socket address
  397.67 + * Returns: port number or -1 if can't determine it
  397.68 + */
  397.69 +
  397.70 +long ip_sockaddrtoport (struct sockaddr *sadr)
  397.71 +{
  397.72 +  return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1;
  397.73 +}
  397.74 +
  397.75 +
  397.76 +/* Return IP address from string
  397.77 + * Accepts: name string
  397.78 + *	    pointer to returned length
  397.79 + *	    pointer to returned address family
  397.80 + * Returns: address if valid, length and family updated, or NIL
  397.81 + */
  397.82 +
  397.83 +void *ip_stringtoaddr (char *text,size_t *len,int *family)
  397.84 +{
  397.85 +  unsigned long adr;
  397.86 +  struct in_addr *ret;
  397.87 +				/* get address */
  397.88 +  if ((adr = inet_addr (text)) == -1) ret = NIL;
  397.89 +  else {			/* make in_addr */
  397.90 +    ret = (struct in_addr *) fs_get (*len = ADR4LEN);
  397.91 +    *family = AF_INET;		/* IPv4 */
  397.92 +    ret->s_addr = adr;		/* set address */
  397.93 +  }
  397.94 +  return (void *) ret;
  397.95 +}
  397.96 +
  397.97 +/* Create a maximum-size socket address
  397.98 + * Accepts: pointer to return maximum socket address length
  397.99 + * Returns: new, empty socket address of maximum size
 397.100 + */
 397.101 +
 397.102 +struct sockaddr *ip_newsockaddr (size_t *len)
 397.103 +{
 397.104 +  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
 397.105 +}
 397.106 +
 397.107 +
 397.108 +/* Stuff a socket address
 397.109 + * Accepts: address family
 397.110 + *	    IPv4 address
 397.111 + *	    length of address (always 4 in IPv4)
 397.112 + *	    port number
 397.113 + *	    pointer to return socket address length
 397.114 + * Returns: socket address or NIL if error
 397.115 + */
 397.116 +
 397.117 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
 397.118 +			      unsigned short port,size_t *len)
 397.119 +{
 397.120 +  struct sockaddr *sadr = ip_newsockaddr (len);
 397.121 +  switch (family) {		/* build socket address based upon family */
 397.122 +  case AF_INET:			/* IPv4 */
 397.123 +    sadr->sa_family = PF_INET;
 397.124 +				/* copy host address */
 397.125 +    memcpy (&SADR4ADR (sadr),adr,adrlen);
 397.126 +				/* copy port number in network format */
 397.127 +    SADR4PORT (sadr) = htons (port);
 397.128 +    *len = SADR4LEN;
 397.129 +    break;
 397.130 +  default:			/* non-IP?? */
 397.131 +    sadr->sa_family = PF_UNSPEC;
 397.132 +    break;
 397.133 +  }
 397.134 +  return sadr;
 397.135 +}
 397.136 +
 397.137 +/* Return name from socket address
 397.138 + * Accepts: socket address
 397.139 + * Returns: canonical name for that address or NIL if none
 397.140 + */
 397.141 +
 397.142 +char *ip_sockaddrtoname (struct sockaddr *sadr)
 397.143 +{
 397.144 +  struct hostent *he;
 397.145 +  return ((sadr->sa_family == PF_INET) &&
 397.146 +	  (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ?
 397.147 +    (char *) he->h_name : NIL;
 397.148 +}
 397.149 +
 397.150 +
 397.151 +/* Return address from name
 397.152 + * Accepts: name or NIL to return next address
 397.153 + *	    pointer to previous/returned length
 397.154 + *	    pointer to previous/returned address family
 397.155 + *	    pointer to previous/returned canonical name
 397.156 + *	    pointer to previous/return state for next-address calls
 397.157 + * Returns: address with length/family/canonical updated if needed, or NIL
 397.158 + */
 397.159 +
 397.160 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
 397.161 +		     void **next)
 397.162 +{
 397.163 +  char **adl,tmp[MAILTMPLEN];
 397.164 +  struct hostent *he;
 397.165 +  if (name) {			/* first lookup? */
 397.166 +				/* yes, do case-independent lookup */
 397.167 +    if ((strlen (name) < MAILTMPLEN) &&
 397.168 +	(he = gethostbyname (lcase (strcpy (tmp,name))))) {
 397.169 +      adl = he->h_addr_list;
 397.170 +      if (len) *len = he->h_length;
 397.171 +      if (family) *family = he->h_addrtype;
 397.172 +      if (canonical) *canonical = (char *) he->h_name;
 397.173 +      if (next) *next = (void *) adl;
 397.174 +    }
 397.175 +    else {			/* error */
 397.176 +      adl = NIL;
 397.177 +      if (len) *len = 0;
 397.178 +      if (family) *family = 0;
 397.179 +      if (canonical) *canonical = NIL;
 397.180 +      if (next) *next = NIL;
 397.181 +    }
 397.182 +  }
 397.183 +				/* return next in series */
 397.184 +  else if (next && (adl = (char **) *next)) *next = ++adl;
 397.185 +  else adl = NIL;		/* failure */
 397.186 +  return adl ? (void *) *adl : NIL;
 397.187 +}
   398.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   398.2 +++ b/src/osdep/unix/ip6_unix.c	Mon Sep 14 15:17:45 2009 +0900
   398.3 @@ -0,0 +1,288 @@
   398.4 +/* ========================================================================
   398.5 + * Copyright 1988-2006 University of Washington
   398.6 + *
   398.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   398.8 + * you may not use this file except in compliance with the License.
   398.9 + * You may obtain a copy of the License at
  398.10 + *
  398.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  398.12 + *
  398.13 + * 
  398.14 + * ========================================================================
  398.15 + */
  398.16 +
  398.17 +/*
  398.18 + * Program:	UNIX IPv6 routines
  398.19 + *
  398.20 + * Author:	Mark Crispin
  398.21 + *		Networks and Distributed Computing
  398.22 + *		Computing & Communications
  398.23 + *		University of Washington
  398.24 + *		Administration Building, AG-44
  398.25 + *		Seattle, WA  98195
  398.26 + *		Internet: MRC@CAC.Washington.EDU
  398.27 + *
  398.28 + * Date:	18 December 2003
  398.29 + * Last Edited:	30 August 2006
  398.30 + */
  398.31 +
  398.32 +
  398.33 +/*
  398.34 + * There is some amazingly bad design in IPv6 sockets.
  398.35 + *
  398.36 + * Supposedly, the new getnameinfo() and getaddrinfo() functions create an
  398.37 + * abstraction that is not dependent upon IPv4 or IPv6.  However, the
  398.38 + * definition of getnameinfo() requires that the caller pass the length of
  398.39 + * the sockaddr instead of deriving it from sa_family.  The man page says
  398.40 + * that there's an sa_len member in the sockaddr, but actually there isn't.
  398.41 + * This means that any caller to getnameinfo() and getaddrinfo() has to know
  398.42 + * the size for the protocol family used by that sockaddr.
  398.43 + *
  398.44 + * The new sockaddr_in6 is bigger than the generic sockaddr (which is what
  398.45 + * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect).
  398.46 + * Rather than increase the size of sockaddr, there's a new sockaddr_storage
  398.47 + * which is only usable for allocating space.
  398.48 + */
  398.49 +
  398.50 +#define SADRLEN sizeof (struct sockaddr_storage)
  398.51 +
  398.52 +#define SADR4(sadr) ((struct sockaddr_in *) sadr)
  398.53 +#define SADR4LEN sizeof (struct sockaddr_in)
  398.54 +#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
  398.55 +#define ADR4LEN sizeof (struct in_addr)
  398.56 +#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
  398.57 +
  398.58 +#define SADR6(sadr) ((struct sockaddr_in6 *) sadr)
  398.59 +#define SADR6LEN sizeof (struct sockaddr_in6)
  398.60 +#define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr
  398.61 +#define ADR6LEN sizeof (struct in6_addr)
  398.62 +#define SADR6PORT(sadr) SADR6 (sadr)->sin6_port
  398.63 +
  398.64 +
  398.65 +/* IP abstraction layer */
  398.66 +
  398.67 +char *ip_sockaddrtostring (struct sockaddr *sadr);
  398.68 +long ip_sockaddrtoport (struct sockaddr *sadr);
  398.69 +void *ip_stringtoaddr (char *text,size_t *len,int *family);
  398.70 +struct sockaddr *ip_newsockaddr (size_t *len);
  398.71 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
  398.72 +			      unsigned short port,size_t *len);
  398.73 +char *ip_sockaddrtoname (struct sockaddr *sadr);
  398.74 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
  398.75 +		     void **next);
  398.76 +
  398.77 +/* Return IP address string from socket address
  398.78 + * Accepts: socket address
  398.79 + * Returns: IP address as name string
  398.80 + */
  398.81 +
  398.82 +char *ip_sockaddrtostring (struct sockaddr *sadr)
  398.83 +{
  398.84 +  static char tmp[NI_MAXHOST];
  398.85 +  switch (sadr->sa_family) {
  398.86 +  case PF_INET:			/* IPv4 */
  398.87 +    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
  398.88 +      return tmp;
  398.89 +    break;
  398.90 +  case PF_INET6:		/* IPv6 */
  398.91 +    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
  398.92 +      return tmp;
  398.93 +    break;
  398.94 +  }
  398.95 +  return "NON-IP";
  398.96 +}
  398.97 +
  398.98 +
  398.99 +/* Return port from socket address
 398.100 + * Accepts: socket address
 398.101 + * Returns: port number or -1 if can't determine it
 398.102 + */
 398.103 +
 398.104 +long ip_sockaddrtoport (struct sockaddr *sadr)
 398.105 +{
 398.106 +  switch (sadr->sa_family) {
 398.107 +  case PF_INET:
 398.108 +    return ntohs (SADR4PORT (sadr));
 398.109 +  case PF_INET6:
 398.110 +    return ntohs (SADR6PORT (sadr));
 398.111 +  }
 398.112 +  return -1;
 398.113 +}
 398.114 +
 398.115 +/* Return IP address from string
 398.116 + * Accepts: name string
 398.117 + *	    pointer to returned length
 398.118 + *	    pointer to returned address family
 398.119 + * Returns: address if valid, length and family updated, or NIL
 398.120 + */
 398.121 +
 398.122 +void *ip_stringtoaddr (char *text,size_t *len,int *family)
 398.123 +
 398.124 +{
 398.125 +  char tmp[MAILTMPLEN];
 398.126 +  static struct addrinfo *hints;
 398.127 +  struct addrinfo *ai;
 398.128 +  void *adr = NIL;
 398.129 +  if (!hints) {			/* hints set up yet? */
 398.130 +    hints = (struct addrinfo *) /* one-time setup */
 398.131 +      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
 398.132 +    hints->ai_family = AF_UNSPEC;/* allow any address family */
 398.133 +    hints->ai_socktype = SOCK_STREAM;
 398.134 +				/* numeric name only */
 398.135 +    hints->ai_flags = AI_NUMERICHOST;
 398.136 +  }
 398.137 +				/* case-independent lookup */
 398.138 +  if (text && (strlen (text) < MAILTMPLEN) &&
 398.139 +      (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) {
 398.140 +    switch (*family = ai->ai_family) {
 398.141 +    case AF_INET:		/* IPv4 */
 398.142 +      adr = fs_get (*len = ADR4LEN);
 398.143 +      memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len);
 398.144 +      break;
 398.145 +    case AF_INET6:		/* IPv6 */
 398.146 +      adr = fs_get (*len = ADR6LEN);
 398.147 +      memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len);
 398.148 +      break;
 398.149 +    }
 398.150 +    freeaddrinfo (ai);		/* free addrinfo */
 398.151 +  }
 398.152 +  return adr;
 398.153 +}
 398.154 +
 398.155 +/* Create a maximum-size socket address
 398.156 + * Accepts: pointer to return maximum socket address length
 398.157 + * Returns: new, empty socket address of maximum size
 398.158 + */
 398.159 +
 398.160 +struct sockaddr *ip_newsockaddr (size_t *len)
 398.161 +{
 398.162 +  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
 398.163 +}
 398.164 +
 398.165 +
 398.166 +/* Stuff a socket address
 398.167 + * Accepts: address family
 398.168 + *	    IPv4 address
 398.169 + *	    length of address
 398.170 + *	    port number
 398.171 + *	    pointer to return socket address length
 398.172 + * Returns: socket address
 398.173 + */
 398.174 +
 398.175 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
 398.176 +			      unsigned short port,size_t *len)
 398.177 +{
 398.178 +  struct sockaddr *sadr = ip_newsockaddr (len);
 398.179 +  switch (family) {		/* build socket address based upon family */
 398.180 +  case AF_INET:			/* IPv4 */
 398.181 +    sadr->sa_family = PF_INET;
 398.182 +				/* copy host address */
 398.183 +    memcpy (&SADR4ADR (sadr),adr,adrlen);
 398.184 +				/* copy port number in network format */
 398.185 +    SADR4PORT (sadr) = htons (port);
 398.186 +    *len = SADR4LEN;
 398.187 +    break;
 398.188 +  case AF_INET6:		/* IPv6 */
 398.189 +    sadr->sa_family = PF_INET6;
 398.190 +				/* copy host address */
 398.191 +    memcpy (&SADR6ADR (sadr),adr,adrlen);
 398.192 +				/* copy port number in network format */
 398.193 +    SADR6PORT (sadr) = htons (port);
 398.194 +    *len = SADR6LEN;
 398.195 +    break;
 398.196 +  default:			/* non-IP?? */
 398.197 +    sadr->sa_family = PF_UNSPEC;
 398.198 +    break;
 398.199 +  }
 398.200 +  return sadr;
 398.201 +}
 398.202 +
 398.203 +/* Return name from socket address
 398.204 + * Accepts: socket address
 398.205 + * Returns: canonical name for that address or NIL if none
 398.206 + */
 398.207 +
 398.208 +char *ip_sockaddrtoname (struct sockaddr *sadr)
 398.209 +{
 398.210 +  static char tmp[NI_MAXHOST];
 398.211 +  switch (sadr->sa_family) {
 398.212 +  case PF_INET:			/* IPv4 */
 398.213 +    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
 398.214 +      return tmp;
 398.215 +    break;
 398.216 +  case PF_INET6:		/* IPv6 */
 398.217 +    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
 398.218 +      return tmp;
 398.219 +    break;
 398.220 +  }
 398.221 +  return NIL;
 398.222 +}
 398.223 +
 398.224 +/* Return address from name
 398.225 + * Accepts: name or NIL to return next address
 398.226 + *	    pointer to previous/returned length
 398.227 + *	    pointer to previous/returned address family
 398.228 + *	    pointer to previous/returned canonical name
 398.229 + *	    pointer to previous/return state for next-address calls
 398.230 + * Returns: address with length/family/canonical updated if needed, or NIL
 398.231 + */
 398.232 +
 398.233 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
 398.234 +		     void **next)
 398.235 +{
 398.236 +  struct addrinfo *cur = NIL;
 398.237 +  static struct addrinfo *hints;
 398.238 +  static struct addrinfo *ai = NIL;
 398.239 +  static char lcname[MAILTMPLEN];
 398.240 +  if (!hints) {			/* hints set up yet? */
 398.241 +    hints = (struct addrinfo *) /* one-time setup */
 398.242 +      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
 398.243 +				/* allow any address family */
 398.244 +    hints->ai_family = AF_UNSPEC;
 398.245 +    hints->ai_socktype = SOCK_STREAM;
 398.246 +				/* need canonical name */
 398.247 +    hints->ai_flags = AI_CANONNAME;
 398.248 +  }
 398.249 +  if (name) {			/* name supplied? */
 398.250 +    if (ai) {
 398.251 +      freeaddrinfo (ai);	/* free old addrinfo */
 398.252 +      ai = NIL;
 398.253 +    }
 398.254 +				/* case-independent lookup */
 398.255 +    if ((strlen (name) < MAILTMPLEN) &&
 398.256 +	(!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) {
 398.257 +      cur = ai;			/* current block */
 398.258 +      if (canonical)		/* set canonical name */
 398.259 +	*canonical = cur->ai_canonname ? cur->ai_canonname : lcname;
 398.260 +				/* remember as next block */
 398.261 +      if (next) *next = (void *) ai;
 398.262 +    }
 398.263 +    else {			/* error */
 398.264 +      cur = NIL;
 398.265 +      if (len) *len = 0;
 398.266 +      if (family) *family = 0;
 398.267 +      if (canonical) *canonical = NIL;
 398.268 +      if (next) *next = NIL;
 398.269 +    }
 398.270 +  }
 398.271 +				/* return next in series */
 398.272 +  else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) {
 398.273 +    *next = cur;		/* set as last address */
 398.274 +				/* set canonical in case changed */
 398.275 +    if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname;
 398.276 +  }
 398.277 +
 398.278 +  if (cur) {			/* got data? */
 398.279 +    if (family) *family = cur->ai_family;
 398.280 +    switch (cur->ai_family) {
 398.281 +    case AF_INET:
 398.282 +      if (len) *len = ADR4LEN;
 398.283 +      return (void *) &SADR4ADR (cur->ai_addr);
 398.284 +    case AF_INET6:
 398.285 +      if (len) *len = ADR6LEN;
 398.286 +      return (void *) &SADR6ADR (cur->ai_addr);
 398.287 +    }
 398.288 +  }
 398.289 +  if (len) *len = 0;		/* error return */
 398.290 +  return NIL;
 398.291 +}
   399.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   399.2 +++ b/src/osdep/unix/ipo_unix.c	Mon Sep 14 15:17:45 2009 +0900
   399.3 @@ -0,0 +1,181 @@
   399.4 +/* ========================================================================
   399.5 + * Copyright 1988-2006 University of Washington
   399.6 + *
   399.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   399.8 + * you may not use this file except in compliance with the License.
   399.9 + * You may obtain a copy of the License at
  399.10 + *
  399.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  399.12 + *
  399.13 + * 
  399.14 + * ========================================================================
  399.15 + */
  399.16 +
  399.17 +/*
  399.18 + * Program:	UNIX IPv4 old routines
  399.19 + *
  399.20 + * Author:	Mark Crispin
  399.21 + *		Networks and Distributed Computing
  399.22 + *		Computing & Communications
  399.23 + *		University of Washington
  399.24 + *		Administration Building, AG-44
  399.25 + *		Seattle, WA  98195
  399.26 + *		Internet: MRC@CAC.Washington.EDU
  399.27 + *
  399.28 + * Date:	18 December 2003
  399.29 + * Last Edited:	30 August 2006
  399.30 + */
  399.31 +
  399.32 +#define SADRLEN sizeof (struct sockaddr)
  399.33 +
  399.34 +#define SADR4(sadr) ((struct sockaddr_in *) sadr)
  399.35 +#define SADR4LEN sizeof (struct sockaddr_in)
  399.36 +#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
  399.37 +#define ADR4LEN sizeof (struct in_addr)
  399.38 +#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
  399.39 +
  399.40 +
  399.41 +/* IP abstraction layer */
  399.42 +
  399.43 +char *ip_sockaddrtostring (struct sockaddr *sadr);
  399.44 +long ip_sockaddrtoport (struct sockaddr *sadr);
  399.45 +void *ip_stringtoaddr (char *text,size_t *len,int *family);
  399.46 +struct sockaddr *ip_newsockaddr (size_t *len);
  399.47 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
  399.48 +			      unsigned short port,size_t *len);
  399.49 +char *ip_sockaddrtoname (struct sockaddr *sadr);
  399.50 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
  399.51 +		     void **next);
  399.52 +
  399.53 +/* Return IP address string from socket address
  399.54 + * Accepts: socket address
  399.55 + * Returns: IP address as name string
  399.56 + */
  399.57 +
  399.58 +char *ip_sockaddrtostring (struct sockaddr *sadr)
  399.59 +{
  399.60 +  return (sadr->sa_family == PF_INET) ?
  399.61 +    inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4";
  399.62 +}
  399.63 +
  399.64 +
  399.65 +/* Return port from socket address
  399.66 + * Accepts: socket address
  399.67 + * Returns: port number or -1 if can't determine it
  399.68 + */
  399.69 +
  399.70 +long ip_sockaddrtoport (struct sockaddr *sadr)
  399.71 +{
  399.72 +  return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1;
  399.73 +}
  399.74 +
  399.75 +
  399.76 +/* Return IP address from string
  399.77 + * Accepts: name string
  399.78 + *	    pointer to returned length
  399.79 + *	    pointer to returned address family
  399.80 + * Returns: address if valid, length and family updated, or NIL
  399.81 + */
  399.82 +
  399.83 +void *ip_stringtoaddr (char *text,size_t *len,int *family)
  399.84 +{
  399.85 +  unsigned long adr;
  399.86 +  struct in_addr *ret;
  399.87 +				/* get address */
  399.88 +  if ((adr = inet_addr (text)) == -1) ret = NIL;
  399.89 +  else {			/* make in_addr */
  399.90 +    ret = (struct in_addr *) fs_get (*len = ADR4LEN);
  399.91 +    *family = AF_INET;		/* IPv4 */
  399.92 +    ret->s_addr = adr;		/* set address */
  399.93 +  }
  399.94 +  return (void *) ret;
  399.95 +}
  399.96 +
  399.97 +/* Create a maximum-size socket address
  399.98 + * Accepts: pointer to return maximum socket address length
  399.99 + * Returns: new, empty socket address of maximum size
 399.100 + */
 399.101 +
 399.102 +struct sockaddr *ip_newsockaddr (size_t *len)
 399.103 +{
 399.104 +  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
 399.105 +}
 399.106 +
 399.107 +
 399.108 +/* Stuff a socket address
 399.109 + * Accepts: address family
 399.110 + *	    IPv4 address
 399.111 + *	    length of address (always 4 in IPv4)
 399.112 + *	    port number
 399.113 + *	    pointer to return socket address length
 399.114 + * Returns: socket address or NIL if error
 399.115 + */
 399.116 +
 399.117 +struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
 399.118 +			      unsigned short port,size_t *len)
 399.119 +{
 399.120 +  struct sockaddr *sadr = ip_newsockaddr (len);
 399.121 +  switch (family) {		/* build socket address based upon family */
 399.122 +  case AF_INET:			/* IPv4 */
 399.123 +    sadr->sa_family = PF_INET;
 399.124 +				/* copy host address */
 399.125 +    memcpy (&SADR4ADR (sadr),adr,adrlen);
 399.126 +				/* copy port number in network format */
 399.127 +    SADR4PORT (sadr) = htons (port);
 399.128 +    *len = SADR4LEN;
 399.129 +    break;
 399.130 +  default:			/* non-IP?? */
 399.131 +    sadr->sa_family = PF_UNSPEC;
 399.132 +    break;
 399.133 +  }
 399.134 +  return sadr;
 399.135 +}
 399.136 +
 399.137 +/* Return name from socket address
 399.138 + * Accepts: socket address
 399.139 + * Returns: canonical name for that address or NIL if none
 399.140 + */
 399.141 +
 399.142 +char *ip_sockaddrtoname (struct sockaddr *sadr)
 399.143 +{
 399.144 +  struct hostent *he;
 399.145 +  return ((sadr->sa_family == PF_INET) &&
 399.146 +	  (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ?
 399.147 +    (char *) he->h_name : NIL;
 399.148 +}
 399.149 +
 399.150 +
 399.151 +/* Return address from name
 399.152 + * Accepts: name or NIL to return next address
 399.153 + *	    pointer to previous/returned length
 399.154 + *	    pointer to previous/returned address family
 399.155 + *	    pointer to previous/returned canonical name
 399.156 + *	    pointer to previous/return state for next-address calls
 399.157 + * Returns: address with length/family/canonical updated if needed, or NIL
 399.158 + */
 399.159 +
 399.160 +void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
 399.161 +		     void **next)
 399.162 +{
 399.163 +  char tmp[MAILTMPLEN];
 399.164 +  struct hostent *he;
 399.165 +  void *ret = NIL;
 399.166 +  if (name) {			/* first lookup? */
 399.167 +				/* yes, do case-independent lookup */
 399.168 +    if ((strlen (name) < MAILTMPLEN) &&
 399.169 +	(he = gethostbyname (lcase (strcpy (tmp,name))))) {
 399.170 +      if (len) *len = he->h_length;
 399.171 +      if (family) *family = he->h_addrtype;
 399.172 +      if (canonical) *canonical = (char *) he->h_name;
 399.173 +      if (next) *next = 0;
 399.174 +      ret = he->h_addr;		/* set result to this one and only block */
 399.175 +    }
 399.176 +    else {			/* error */
 399.177 +      if (len) *len = 0;
 399.178 +      if (family) *family = 0;
 399.179 +      if (canonical) *canonical = NIL;
 399.180 +      if (next) *next = NIL;
 399.181 +    }
 399.182 +  }
 399.183 +  return ret;			/* return result */
 399.184 +}
   400.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   400.2 +++ b/src/osdep/unix/kerb_mit.c	Mon Sep 14 15:17:45 2009 +0900
   400.3 @@ -0,0 +1,111 @@
   400.4 +/* ========================================================================
   400.5 + * Copyright 1988-2006 University of Washington
   400.6 + *
   400.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   400.8 + * you may not use this file except in compliance with the License.
   400.9 + * You may obtain a copy of the License at
  400.10 + *
  400.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  400.12 + *
  400.13 + * 
  400.14 + * ========================================================================
  400.15 + */
  400.16 +
  400.17 +/*
  400.18 + * Program:	MIT Kerberos routines
  400.19 + *
  400.20 + * Author:	Mark Crispin
  400.21 + *		Networks and Distributed Computing
  400.22 + *		Computing & Communications
  400.23 + *		University of Washington
  400.24 + *		Administration Building, AG-44
  400.25 + *		Seattle, WA  98195
  400.26 + *		Internet: MRC@CAC.Washington.EDU
  400.27 + *
  400.28 + * Date:	4 March 2003
  400.29 + * Last Edited:	30 August 2006
  400.30 + */
  400.31 +
  400.32 +#define PROTOTYPE(x) x
  400.33 +#include <gssapi/gssapi_generic.h>
  400.34 +#include <gssapi/gssapi_krb5.h>
  400.35 +
  400.36 +
  400.37 +long kerberos_server_valid (void);
  400.38 +long kerberos_try_kinit (OM_uint32 error);
  400.39 +char *kerberos_login (char *user,char *authuser,int argc,char *argv[]);
  400.40 +
  400.41 +/* Kerberos server valid check
  400.42 + * Returns: T if have keytab, NIL otherwise
  400.43 + *
  400.44 + * Note that this routine will probably return T only if the process is root.
  400.45 + * This is alright since the server is probably still root at this point.
  400.46 + */
  400.47 +
  400.48 +long kerberos_server_valid ()
  400.49 +{
  400.50 +  krb5_context ctx;
  400.51 +  krb5_keytab kt;
  400.52 +  krb5_kt_cursor csr;
  400.53 +  long ret = NIL;
  400.54 +				/* make a context */
  400.55 +  if (!krb5_init_context (&ctx)) {
  400.56 +				/* get default keytab */
  400.57 +    if (!krb5_kt_default (ctx,&kt)) {
  400.58 +				/* can do server if have good keytab */
  400.59 +      if (!krb5_kt_start_seq_get (ctx,kt,&csr) &&
  400.60 +	  !krb5_kt_end_seq_get (ctx,kt,&csr)) ret = LONGT;
  400.61 +      krb5_kt_close (ctx,kt);	/* finished with keytab */
  400.62 +    }
  400.63 +    krb5_free_context (ctx);	/* finished with context */
  400.64 +  }
  400.65 +  return ret;
  400.66 +}
  400.67 +
  400.68 +
  400.69 +/* Kerberos check for missing or expired credentials
  400.70 + * Returns: T if should suggest running kinit, NIL otherwise
  400.71 + */
  400.72 +
  400.73 +long kerberos_try_kinit (OM_uint32 error)
  400.74 +{
  400.75 +  switch (error) {
  400.76 +  case KRB5KRB_AP_ERR_TKT_EXPIRED:
  400.77 +  case KRB5_FCC_NOFILE:		/* MIT */
  400.78 +  case KRB5_CC_NOTFOUND:	/* Heimdal */
  400.79 +    return LONGT;
  400.80 +  }
  400.81 +  return NIL;
  400.82 +}
  400.83 +
  400.84 +/* Kerberos server log in
  400.85 + * Accepts: authorization ID as user name
  400.86 + *	    authentication ID as Kerberos principal
  400.87 + *	    argument count
  400.88 + *	    argument vector
  400.89 + * Returns: logged in user name if logged in, NIL otherwise
  400.90 + */
  400.91 +
  400.92 +char *kerberos_login (char *user,char *authuser,int argc,char *argv[])
  400.93 +{
  400.94 +  krb5_context ctx;
  400.95 +  krb5_principal prnc;
  400.96 +  char kuser[NETMAXUSER];
  400.97 +  char *ret = NIL;
  400.98 +				/* make a context */
  400.99 +  if (!krb5_init_context (&ctx)) {
 400.100 +				/* build principal */
 400.101 +    if (!krb5_parse_name (ctx,authuser,&prnc)) {
 400.102 +				/* can get local name for this principal? */
 400.103 +      if (!krb5_aname_to_localname (ctx,prnc,NETMAXUSER-1,kuser)) {
 400.104 +				/* yes, local name permitted login as user?  */
 400.105 +	if (authserver_login (user,kuser,argc,argv) ||
 400.106 +	    authserver_login (lcase (user),kuser,argc,argv))
 400.107 +	  ret = myusername ();	/* yes, return user name */
 400.108 +      }
 400.109 +      krb5_free_principal (ctx,prnc);
 400.110 +    }
 400.111 +    krb5_free_context (ctx);	/* finished with context */
 400.112 +  }
 400.113 +  return ret;
 400.114 +}
   401.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   401.2 +++ b/src/osdep/unix/log_bsi.c	Mon Sep 14 15:17:45 2009 +0900
   401.3 @@ -0,0 +1,55 @@
   401.4 +/* ========================================================================
   401.5 + * Copyright 1988-2006 University of Washington
   401.6 + *
   401.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   401.8 + * you may not use this file except in compliance with the License.
   401.9 + * You may obtain a copy of the License at
  401.10 + *
  401.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  401.12 + *
  401.13 + * 
  401.14 + * ========================================================================
  401.15 + */
  401.16 +
  401.17 +/*
  401.18 + * Program:	BSI login
  401.19 + *
  401.20 + * Author:	Mark Crispin
  401.21 + *		Networks and Distributed Computing
  401.22 + *		Computing & Communications
  401.23 + *		University of Washington
  401.24 + *		Administration Building, AG-44
  401.25 + *		Seattle, WA  98195
  401.26 + *		Internet: MRC@CAC.Washington.EDU
  401.27 + *
  401.28 + * Date:	1 August 1988
  401.29 + * Last Edited:	30 August 2006
  401.30 + */
  401.31 +
  401.32 +/* Log in
  401.33 + * Accepts: login passwd struct
  401.34 + *	    argument count
  401.35 + *	    argument vector
  401.36 + * Returns: T if success, NIL otherwise
  401.37 + */
  401.38 +
  401.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  401.40 +{
  401.41 +  long ret = NIL;
  401.42 +  uid_t euid = geteuid ();
  401.43 +  login_cap_t *lc = login_getclass (pw->pw_class);
  401.44 +				/* have class and can become user? */
  401.45 +  if (lc && !seteuid (pw->pw_uid)) {
  401.46 +				/* ask for approval */
  401.47 +    if (auth_approve (lc,pw->pw_name,
  401.48 +		      (char *) mail_parameters (NIL,GET_SERVICENAME,NIL)) <= 0)
  401.49 +      seteuid (euid);		/* not approved, restore root euid */
  401.50 +    else {			/* approved */
  401.51 +      seteuid (euid);		/* restore former root euid first */
  401.52 +      setsid ();		/* ensure we are session leader */
  401.53 +				/* log the guy in */
  401.54 +      ret = !setusercontext (lc,pw,pw->pw_uid,LOGIN_SETALL&~LOGIN_SETPATH);
  401.55 +    }
  401.56 +  }
  401.57 +  return ret;
  401.58 +}
   402.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   402.2 +++ b/src/osdep/unix/log_cyg.c	Mon Sep 14 15:17:45 2009 +0900
   402.3 @@ -0,0 +1,46 @@
   402.4 +/* ========================================================================
   402.5 + * Copyright 1988-2006 University of Washington
   402.6 + *
   402.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   402.8 + * you may not use this file except in compliance with the License.
   402.9 + * You may obtain a copy of the License at
  402.10 + *
  402.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  402.12 + *
  402.13 + * 
  402.14 + * ========================================================================
  402.15 + */
  402.16 +
  402.17 +/*
  402.18 + * Program:	Cygwin login
  402.19 + *
  402.20 + * Author:	Mark Crispin
  402.21 + *		Networks and Distributed Computing
  402.22 + *		Computing & Communications
  402.23 + *		University of Washington
  402.24 + *		Administration Building, AG-44
  402.25 + *		Seattle, WA  98195
  402.26 + *		Internet: MRC@CAC.Washington.EDU
  402.27 + *
  402.28 + * Date:	1 August 1988
  402.29 + * Last Edited:	30 August 2006
  402.30 + */
  402.31 +
  402.32 +/* Log in
  402.33 + * Accepts: login passwd struct
  402.34 + *	    argument count
  402.35 + *	    argument vector
  402.36 + * Returns: T if success, NIL otherwise
  402.37 + */
  402.38 +
  402.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  402.40 +{
  402.41 +  uid_t uid = pw->pw_uid;
  402.42 +				/* must be same user name as last checkpw() */
  402.43 +  if (!(cyg_user && !strcmp (pw->pw_name,cyg_user))) return NIL;
  402.44 +				/* do the ImpersonateLoggedOnUser() */
  402.45 +  cygwin_set_impersonation_token (cyg_hdl);
  402.46 +
  402.47 +  return !(setgid (pw->pw_gid) || initgroups (cyg_user,pw->pw_gid) ||
  402.48 +	   setuid (uid));
  402.49 +}
   403.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   403.2 +++ b/src/osdep/unix/log_old.c	Mon Sep 14 15:17:45 2009 +0900
   403.3 @@ -0,0 +1,39 @@
   403.4 +/* ========================================================================
   403.5 + * Copyright 1988-2006 University of Washington
   403.6 + *
   403.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   403.8 + * you may not use this file except in compliance with the License.
   403.9 + * You may obtain a copy of the License at
  403.10 + *
  403.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  403.12 + *
  403.13 + * 
  403.14 + * ========================================================================
  403.15 + */
  403.16 +
  403.17 +/*
  403.18 + * Program:	Standard login for very old UNIX systems
  403.19 + *
  403.20 + * Author:	Mark Crispin
  403.21 + *		Networks and Distributed Computing
  403.22 + *		Computing & Communications
  403.23 + *		University of Washington
  403.24 + *		Administration Building, AG-44
  403.25 + *		Seattle, WA  98195
  403.26 + *		Internet: MRC@CAC.Washington.EDU
  403.27 + *
  403.28 + * Date:	1 August 1988
  403.29 + * Last Edited:	30 August 2006
  403.30 + */
  403.31 +
  403.32 +/* Log in
  403.33 + * Accepts: login passwd struct
  403.34 + *	    argument count
  403.35 + *	    argument vector
  403.36 + * Returns: T if success, NIL otherwise
  403.37 + */
  403.38 +
  403.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  403.40 +{
  403.41 +  return !(setgid (pw->pw_gid) || setuid (pw->pw_uid));
  403.42 +}
   404.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   404.2 +++ b/src/osdep/unix/log_os4.c	Mon Sep 14 15:17:45 2009 +0900
   404.3 @@ -0,0 +1,58 @@
   404.4 +/* ========================================================================
   404.5 + * Copyright 1988-2006 University of Washington
   404.6 + *
   404.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   404.8 + * you may not use this file except in compliance with the License.
   404.9 + * You may obtain a copy of the License at
  404.10 + *
  404.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  404.12 + *
  404.13 + * 
  404.14 + * ========================================================================
  404.15 + */
  404.16 +
  404.17 +/*
  404.18 + * Program:	OSF/1 (Digital UNIX) 4 login
  404.19 + *
  404.20 + * Author:	Mark Crispin
  404.21 + *		Networks and Distributed Computing
  404.22 + *		Computing & Communications
  404.23 + *		University of Washington
  404.24 + *		Administration Building, AG-44
  404.25 + *		Seattle, WA  98195
  404.26 + *		Internet: MRC@CAC.Washington.EDU
  404.27 + *
  404.28 + * Date:	1 August 1988
  404.29 + * Last Edited:	30 August 2006
  404.30 + */
  404.31 +
  404.32 +/* Log in
  404.33 + * Accepts: login passwd struct
  404.34 + *	    argument count
  404.35 + *	    argument vector
  404.36 + * Returns: T if success, NIL otherwise
  404.37 + */
  404.38 +
  404.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  404.40 +{
  404.41 +  int i;
  404.42 +  char *s;
  404.43 +  char *name = cpystr (pw->pw_name);
  404.44 +  char *host = cpystr (tcp_clienthost ());
  404.45 +  uid_t uid = pw->pw_uid;
  404.46 +  long ret = NIL;
  404.47 +				/* tie off address */
  404.48 +  if (s = strchr (host,' ')) *s = '\0';
  404.49 +  if (*host == '[') {		/* convert [a.b.c.d] to a.b.c.d */
  404.50 +    memmove (host,host+1,i = strlen (host + 2));
  404.51 +    host[i] = '\0';
  404.52 +  }
  404.53 +  if (sia_become_user (checkpw_collect,argc,argv,host,name,NIL,NIL,NIL,NIL,
  404.54 +		       SIA_BEU_REALLOGIN|SIA_BEU_OKROOTDIR) != SIASUCCESS)
  404.55 +    setreuid (0,0);		/* make sure have root again */
  404.56 +				/* probable success, complete login */
  404.57 +  else ret = (!setreuid (0,0) && !setuid (uid));
  404.58 +  fs_give ((void **) &name);
  404.59 +  fs_give ((void **) &host);
  404.60 +  return ret;
  404.61 +}
   405.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   405.2 +++ b/src/osdep/unix/log_sec.c	Mon Sep 14 15:17:45 2009 +0900
   405.3 @@ -0,0 +1,44 @@
   405.4 +/* ========================================================================
   405.5 + * Copyright 1988-2006 University of Washington
   405.6 + *
   405.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   405.8 + * you may not use this file except in compliance with the License.
   405.9 + * You may obtain a copy of the License at
  405.10 + *
  405.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  405.12 + *
  405.13 + * 
  405.14 + * ========================================================================
  405.15 + */
  405.16 +
  405.17 +/*
  405.18 + * Program:	SecureWare login
  405.19 + *
  405.20 + * Author:	Mark Crispin
  405.21 + *		Networks and Distributed Computing
  405.22 + *		Computing & Communications
  405.23 + *		University of Washington
  405.24 + *		Administration Building, AG-44
  405.25 + *		Seattle, WA  98195
  405.26 + *		Internet: MRC@CAC.Washington.EDU
  405.27 + *
  405.28 + * Date:	1 August 1988
  405.29 + * Last Edited:	30 August 2006
  405.30 + */
  405.31 +
  405.32 +/* Log in
  405.33 + * Accepts: login passwd struct
  405.34 + *	    argument count
  405.35 + *	    argument vector
  405.36 + * Returns: T if success, NIL otherwise
  405.37 + */
  405.38 +
  405.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  405.40 +{
  405.41 +  uid_t uid = pw->pw_uid;
  405.42 +  char *name = cpystr (pw->pw_name);
  405.43 +  long ret = !(setluid (uid) || setgid (pw->pw_gid) ||
  405.44 +	       initgroups (name,pw->pw_gid) || setuid (uid));
  405.45 +  fs_give ((void **) &name);
  405.46 +  return ret;
  405.47 +}
   406.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   406.2 +++ b/src/osdep/unix/log_std.c	Mon Sep 14 15:17:45 2009 +0900
   406.3 @@ -0,0 +1,44 @@
   406.4 +/* ========================================================================
   406.5 + * Copyright 1988-2006 University of Washington
   406.6 + *
   406.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   406.8 + * you may not use this file except in compliance with the License.
   406.9 + * You may obtain a copy of the License at
  406.10 + *
  406.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  406.12 + *
  406.13 + * 
  406.14 + * ========================================================================
  406.15 + */
  406.16 +
  406.17 +/*
  406.18 + * Program:	Standard login
  406.19 + *
  406.20 + * Author:	Mark Crispin
  406.21 + *		Networks and Distributed Computing
  406.22 + *		Computing & Communications
  406.23 + *		University of Washington
  406.24 + *		Administration Building, AG-44
  406.25 + *		Seattle, WA  98195
  406.26 + *		Internet: MRC@CAC.Washington.EDU
  406.27 + *
  406.28 + * Date:	1 August 1988
  406.29 + * Last Edited:	30 August 2006
  406.30 + */
  406.31 +
  406.32 +/* Log in
  406.33 + * Accepts: login passwd struct
  406.34 + *	    argument count
  406.35 + *	    argument vector
  406.36 + * Returns: T if success, NIL otherwise
  406.37 + */
  406.38 +
  406.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  406.40 +{
  406.41 +  uid_t uid = pw->pw_uid;
  406.42 +  char *name = cpystr (pw->pw_name);
  406.43 +  long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) ||
  406.44 +	       setuid (uid));
  406.45 +  fs_give ((void **) &name);
  406.46 +  return ret;
  406.47 +}
   407.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   407.2 +++ b/src/osdep/unix/log_sv4.c	Mon Sep 14 15:17:45 2009 +0900
   407.3 @@ -0,0 +1,43 @@
   407.4 +/* ========================================================================
   407.5 + * Copyright 1988-2006 University of Washington
   407.6 + *
   407.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   407.8 + * you may not use this file except in compliance with the License.
   407.9 + * You may obtain a copy of the License at
  407.10 + *
  407.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  407.12 + *
  407.13 + * 
  407.14 + * ========================================================================
  407.15 + */
  407.16 +
  407.17 +/*
  407.18 + * Program:	SVR4 login
  407.19 + *
  407.20 + * Author:	Mark Crispin
  407.21 + *		Networks and Distributed Computing
  407.22 + *		Computing & Communications
  407.23 + *		University of Washington
  407.24 + *		Administration Building, AG-44
  407.25 + *		Seattle, WA  98195
  407.26 + *		Internet: MRC@CAC.Washington.EDU
  407.27 + *
  407.28 + * Date:	1 August 1988
  407.29 + * Last Edited:	30 August 2006
  407.30 + */
  407.31 +
  407.32 +/* Log in
  407.33 + * Accepts: login passwd struct
  407.34 + *	    argument count
  407.35 + *	    argument vector
  407.36 + * Returns: T if success, NIL otherwise
  407.37 + */
  407.38 +
  407.39 +long loginpw (struct passwd *pw,int argc,char *argv[])
  407.40 +{
  407.41 +  uid_t uid = pw->pw_uid;
  407.42 +  char *name = cpystr (pw->pw_name);
  407.43 +  long ret = !(setgid (pw->pw_gid) || initgroups (name) || setuid (uid));
  407.44 +  fs_give ((void **) &name);
  407.45 +  return ret;
  407.46 +}
   408.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   408.2 +++ b/src/osdep/unix/mbx.c	Mon Sep 14 15:17:45 2009 +0900
   408.3 @@ -0,0 +1,1855 @@
   408.4 +/* ========================================================================
   408.5 + * Copyright 1988-2007 University of Washington
   408.6 + *
   408.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   408.8 + * you may not use this file except in compliance with the License.
   408.9 + * You may obtain a copy of the License at
  408.10 + *
  408.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  408.12 + *
  408.13 + * 
  408.14 + * ========================================================================
  408.15 + */
  408.16 +
  408.17 +/*
  408.18 + * Program:	MBX mail routines
  408.19 + *
  408.20 + * Author:	Mark Crispin
  408.21 + *		Networks and Distributed Computing
  408.22 + *		Computing & Communications
  408.23 + *		University of Washington
  408.24 + *		Administration Building, AG-44
  408.25 + *		Seattle, WA  98195
  408.26 + *		Internet: MRC@CAC.Washington.EDU
  408.27 + *
  408.28 + * Date:	3 October 1995
  408.29 + * Last Edited:	11 October 2007
  408.30 + */
  408.31 +
  408.32 +
  408.33 +/*				FILE TIME SEMANTICS
  408.34 + *
  408.35 + * The atime is the last read time of the file.
  408.36 + * The mtime is the last flags update time of the file.
  408.37 + * The ctime is the last write time of the file.
  408.38 + */
  408.39 +
  408.40 +#include <stdio.h>
  408.41 +#include <ctype.h>
  408.42 +#include <errno.h>
  408.43 +extern int errno;		/* just in case */
  408.44 +#include "mail.h"
  408.45 +#include "osdep.h"
  408.46 +#include <pwd.h>
  408.47 +#include <sys/stat.h>
  408.48 +#include <sys/time.h>
  408.49 +#include "misc.h"
  408.50 +#include "dummy.h"
  408.51 +#include "fdstring.h"
  408.52 +
  408.53 +
  408.54 +/* Build parameters */
  408.55 +
  408.56 +#define HDRSIZE 2048
  408.57 +
  408.58 +
  408.59 +/* Kludge to make Cygwin happy */
  408.60 +
  408.61 +#ifndef O_BINARY
  408.62 +#define O_BINARY 0
  408.63 +#endif
  408.64 +
  408.65 +/* MBX I/O stream local data */
  408.66 +	
  408.67 +typedef struct mbx_local {
  408.68 +  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
  408.69 +  unsigned int expok: 1;	/* if expunging OK in ping */
  408.70 +  unsigned int expunged : 1;	/* if one or more expunged messages */
  408.71 +  int fd;			/* file descriptor for I/O */
  408.72 +  int ld;			/* lock file descriptor */
  408.73 +  int ffuserflag;		/* first free user flag */
  408.74 +  off_t filesize;		/* file size parsed */
  408.75 +  time_t filetime;		/* last file time */
  408.76 +  time_t lastsnarf;		/* last snarf time */
  408.77 +  unsigned long lastpid;	/* PID of last writer */
  408.78 +  unsigned char *buf;		/* temporary buffer */
  408.79 +  unsigned long buflen;		/* current size of temporary buffer */
  408.80 +  char lock[MAILTMPLEN];	/* buffer to write lock name */
  408.81 +} MBXLOCAL;
  408.82 +
  408.83 +
  408.84 +/* Convenient access to local data */
  408.85 +
  408.86 +#define LOCAL ((MBXLOCAL *) stream->local)
  408.87 +
  408.88 +/* Function prototypes */
  408.89 +
  408.90 +DRIVER *mbx_valid (char *name);
  408.91 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
  408.92 +		 long flags);
  408.93 +void *mbx_parameters (long function,void *value);
  408.94 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  408.95 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
  408.96 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  408.97 +long mbx_create (MAILSTREAM *stream,char *mailbox);
  408.98 +long mbx_delete (MAILSTREAM *stream,char *mailbox);
  408.99 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
 408.100 +long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
 408.101 +MAILSTREAM *mbx_open (MAILSTREAM *stream);
 408.102 +void mbx_close (MAILSTREAM *stream,long options);
 408.103 +void mbx_abort (MAILSTREAM *stream);
 408.104 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
 408.105 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 408.106 +		  long flags);
 408.107 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 408.108 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 408.109 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 408.110 +long mbx_ping (MAILSTREAM *stream);
 408.111 +void mbx_check (MAILSTREAM *stream);
 408.112 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
 408.113 +void mbx_snarf (MAILSTREAM *stream);
 408.114 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 408.115 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 408.116 +
 408.117 +char *mbx_file (char *dst,char *name);
 408.118 +long mbx_parse (MAILSTREAM *stream);
 408.119 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
 408.120 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 408.121 +void mbx_update_header (MAILSTREAM *stream);
 408.122 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
 408.123 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 408.124 +			  unsigned long *size,char **hdr);
 408.125 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
 408.126 +			   long flags);
 408.127 +long mbx_flaglock (MAILSTREAM *stream);
 408.128 +
 408.129 +/* MBX mail routines */
 408.130 +
 408.131 +
 408.132 +/* Driver dispatch used by MAIL */
 408.133 +
 408.134 +DRIVER mbxdriver = {
 408.135 +  "mbx",			/* driver name */
 408.136 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
 408.137 +				/* driver flags */
 408.138 +  (DRIVER *) NIL,		/* next driver */
 408.139 +  mbx_valid,			/* mailbox is valid for us */
 408.140 +  mbx_parameters,		/* manipulate parameters */
 408.141 +  mbx_scan,			/* scan mailboxes */
 408.142 +  mbx_list,			/* list mailboxes */
 408.143 +  mbx_lsub,			/* list subscribed mailboxes */
 408.144 +  NIL,				/* subscribe to mailbox */
 408.145 +  NIL,				/* unsubscribe from mailbox */
 408.146 +  mbx_create,			/* create mailbox */
 408.147 +  mbx_delete,			/* delete mailbox */
 408.148 +  mbx_rename,			/* rename mailbox */
 408.149 +  mbx_status,			/* status of mailbox */
 408.150 +  mbx_open,			/* open mailbox */
 408.151 +  mbx_close,			/* close mailbox */
 408.152 +  mbx_flags,			/* fetch message "fast" attributes */
 408.153 +  mbx_flags,			/* fetch message flags */
 408.154 +  NIL,				/* fetch overview */
 408.155 +  NIL,				/* fetch message envelopes */
 408.156 +  mbx_header,			/* fetch message header */
 408.157 +  mbx_text,			/* fetch message body */
 408.158 +  NIL,				/* fetch partial message text */
 408.159 +  NIL,				/* unique identifier */
 408.160 +  NIL,				/* message number */
 408.161 +  mbx_flag,			/* modify flags */
 408.162 +  mbx_flagmsg,			/* per-message modify flags */
 408.163 +  NIL,				/* search for message based on criteria */
 408.164 +  NIL,				/* sort messages */
 408.165 +  NIL,				/* thread messages */
 408.166 +  mbx_ping,			/* ping mailbox to see if still alive */
 408.167 +  mbx_check,			/* check for new messages */
 408.168 +  mbx_expunge,			/* expunge deleted messages */
 408.169 +  mbx_copy,			/* copy messages to another mailbox */
 408.170 +  mbx_append,			/* append string message to mailbox */
 408.171 +  NIL				/* garbage collect stream */
 408.172 +};
 408.173 +
 408.174 +				/* prototype stream */
 408.175 +MAILSTREAM mbxproto = {&mbxdriver};
 408.176 +
 408.177 +/* MBX mail validate mailbox
 408.178 + * Accepts: mailbox name
 408.179 + * Returns: our driver if name is valid, NIL otherwise
 408.180 + */
 408.181 +
 408.182 +DRIVER *mbx_valid (char *name)
 408.183 +{
 408.184 +  char tmp[MAILTMPLEN];
 408.185 +  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
 408.186 +  if (fd < 0) return NIL;
 408.187 +  close (fd);			/* don't need the fd now */
 408.188 +  return &mbxdriver;
 408.189 +}
 408.190 +
 408.191 +
 408.192 +/* MBX mail test for valid mailbox
 408.193 + * Accepts: returned stream with valid mailbox keywords
 408.194 + *	    mailbox name
 408.195 + *	    scratch buffer
 408.196 + *	    returned lock fd
 408.197 + *	    returned lock name
 408.198 + *	    RW flags or NIL for readonly
 408.199 + * Returns: file descriptor if valid, NIL otherwise
 408.200 + */
 408.201 +
 408.202 +#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
 408.203 +#define MBXISVALIDUID 0x2	/* RW, do UID action */
 408.204 +
 408.205 +int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
 408.206 +		 long flags)
 408.207 +{
 408.208 +  int fd,upd;
 408.209 +  int ret = -1;
 408.210 +  unsigned long i;
 408.211 +  long j,k;
 408.212 +  off_t pos;
 408.213 +  char c,*s,*t,hdr[HDRSIZE];
 408.214 +  struct stat sbuf;
 408.215 +  time_t tp[2];
 408.216 +  int error = EINVAL;		/* assume invalid argument */
 408.217 +  if (ld) *ld = -1;		/* initially no lock */
 408.218 +  if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) &&
 408.219 +      ((fd = open (tmp,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
 408.220 +    error = -1;			/* bogus format */
 408.221 +		/* I love cretinous C compilers -- don't you? */
 408.222 +    if (read (fd,hdr,HDRSIZE) == HDRSIZE)
 408.223 +      if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') &&
 408.224 +	  (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') &&
 408.225 +	  (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]))
 408.226 +	if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) &&
 408.227 +	    isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) &&
 408.228 +	    isxdigit (c = hdr[15]) && isxdigit (hdr[16]))
 408.229 +	  if (isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
 408.230 +	      isxdigit (hdr[19]) && isxdigit (hdr[20]) &&
 408.231 +	      isxdigit (hdr[21]) && isxdigit (hdr[22]) &&
 408.232 +	      (hdr[23] == '\015') && (hdr[24] == '\012')) {
 408.233 +	    ret = fd;		/* mbx format */
 408.234 +
 408.235 +	    if (stream) {	/* lock if making mini-stream */
 408.236 +	      if (flock (fd,LOCK_SH) ||
 408.237 +		  (flags && ((*ld = lockfd (fd,lock,LOCK_EX)) < 0))) ret = -1;
 408.238 +				/* reread data now that locked */
 408.239 +	      else if (lseek (fd,0,L_SET) ||
 408.240 +		       (read (fd,hdr,HDRSIZE) != HDRSIZE)) ret = -1;
 408.241 +	      else {
 408.242 +		*stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),
 408.243 +						 0,sizeof (MAILSTREAM));
 408.244 +		hdr[15] = '\0';	/* tie off UIDVALIDITY */
 408.245 +		(*stream)->uid_validity = strtoul (hdr+7,NIL,16);
 408.246 +		hdr[15] = c;	/* now get UIDLAST */
 408.247 +		(*stream)->uid_last = strtoul (hdr+15,NIL,16);
 408.248 +				/* parse user flags */
 408.249 +		for (i = 0, s = hdr + 25;
 408.250 +		     (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
 408.251 +		     i++, s = t + 2) {
 408.252 +		  *t = '\0';	/* tie off flag */
 408.253 +		  if (strlen (s) <= MAXUSERFLAG)
 408.254 +		    (*stream)->user_flags[i] = cpystr (s);
 408.255 +		}
 408.256 +				/* make sure have true UIDLAST */
 408.257 +		if (flags & MBXISVALIDUID) {
 408.258 +		  for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
 408.259 +		       pos += (j + k)) {
 408.260 +				/* read header for this message */
 408.261 +		    lseek (fd,pos,L_SET);
 408.262 +		    if ((j = read (fd,hdr,64)) >= 0) {
 408.263 +		      hdr[j] = '\0';
 408.264 +		      if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
 408.265 +			*s = '\0';
 408.266 +			k = s + 2 - hdr;
 408.267 +			if ((s = strchr (hdr,',')) &&
 408.268 +			    (j = strtol (s+1,&s,10)) && (*s == ';') &&
 408.269 +			    (s = strchr (s+1,'-'))) {
 408.270 +				/* get UID if there is any */
 408.271 +			  i = strtoul (++s,&t,16);
 408.272 +			  if (!*t && (t == (s + 8)) &&
 408.273 +			      (i <= (*stream)->uid_last)) {
 408.274 +			    if (!i) {
 408.275 +			      lseek (fd,pos + s - hdr,L_SET);
 408.276 +			      sprintf (hdr,"%08lx",++(*stream)->uid_last);
 408.277 +			      write (fd,hdr,8);
 408.278 +			      upd = T;
 408.279 +			    }
 408.280 +			    continue;
 408.281 +			  }
 408.282 +			}
 408.283 +		      }
 408.284 +		      ret = -1;	/* error, give up */
 408.285 +		      *stream = mail_close (*stream);
 408.286 +		      pos = sbuf.st_size + 1;
 408.287 +		      j = k = 0;
 408.288 +		    }
 408.289 +		  }
 408.290 +
 408.291 +		  if (upd) {	/* need to update hdr with new UIDLAST? */
 408.292 +		    lseek (fd,15,L_SET);
 408.293 +		    sprintf (hdr,"%08lx",(*stream)->uid_last);
 408.294 +		    write (fd,hdr,8);
 408.295 +		  }
 408.296 +		}
 408.297 +	      }
 408.298 +	    }
 408.299 +	  }
 408.300 +    if (ret != fd) close (fd);	/* close the file */
 408.301 +    else lseek (fd,0,L_SET);	/* else rewind to start */
 408.302 +				/* \Marked status? */
 408.303 +    if (sbuf.st_ctime > sbuf.st_atime) {
 408.304 +      tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 408.305 +      tp[1] = sbuf.st_mtime;
 408.306 +      utime (tmp,tp);		/* set the times */
 408.307 +    }
 408.308 +  }
 408.309 +				/* in case INBOX but not mbx format */
 408.310 +  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
 408.311 +    error = -1;
 408.312 +  if ((ret < 0) && ld && (*ld >= 0)) {
 408.313 +    unlockfd (*ld,lock);
 408.314 +    *ld = -1;
 408.315 +  }
 408.316 +  errno = error;		/* return as last error */
 408.317 +  return ret;			/* return what we should */
 408.318 +}
 408.319 +
 408.320 +/* MBX manipulate driver parameters
 408.321 + * Accepts: function code
 408.322 + *	    function-dependent value
 408.323 + * Returns: function-dependent return value
 408.324 + */
 408.325 +
 408.326 +void *mbx_parameters (long function,void *value)
 408.327 +{
 408.328 +  void *ret = NIL;
 408.329 +  switch ((int) function) {
 408.330 +  case GET_INBOXPATH:
 408.331 +    if (value) ret = mbx_file ((char *) value,"INBOX");
 408.332 +    break;
 408.333 +  case SET_ONETIMEEXPUNGEATPING:
 408.334 +    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
 408.335 +  case GET_ONETIMEEXPUNGEATPING:
 408.336 +    if (value) ret = (void *)
 408.337 +      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
 408.338 +    break;
 408.339 +  }
 408.340 +  return ret;
 408.341 +}
 408.342 +
 408.343 +
 408.344 +/* MBX mail scan mailboxes
 408.345 + * Accepts: mail stream
 408.346 + *	    reference
 408.347 + *	    pattern to search
 408.348 + *	    string to scan
 408.349 + */
 408.350 +
 408.351 +void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 408.352 +{
 408.353 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 408.354 +}
 408.355 +
 408.356 +
 408.357 +/* MBX mail list mailboxes
 408.358 + * Accepts: mail stream
 408.359 + *	    reference
 408.360 + *	    pattern to search
 408.361 + */
 408.362 +
 408.363 +void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
 408.364 +{
 408.365 +  if (stream) dummy_list (NIL,ref,pat);
 408.366 +}
 408.367 +
 408.368 +
 408.369 +/* MBX mail list subscribed mailboxes
 408.370 + * Accepts: mail stream
 408.371 + *	    reference
 408.372 + *	    pattern to search
 408.373 + */
 408.374 +
 408.375 +void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 408.376 +{
 408.377 +  if (stream) dummy_lsub (NIL,ref,pat);
 408.378 +}
 408.379 +
 408.380 +/* MBX mail create mailbox
 408.381 + * Accepts: MAIL stream
 408.382 + *	    mailbox name to create
 408.383 + * Returns: T on success, NIL on failure
 408.384 + */
 408.385 +
 408.386 +long mbx_create (MAILSTREAM *stream,char *mailbox)
 408.387 +{
 408.388 +  char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE];
 408.389 +  long ret = NIL;
 408.390 +  int i,fd;
 408.391 +  if (!(s = mbx_file (mbx,mailbox))) {
 408.392 +    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
 408.393 +    MM_LOG (mbx,ERROR);
 408.394 +  }
 408.395 +				/* create underlying file */
 408.396 +  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
 408.397 +				/* done if made directory */
 408.398 +    if ((s = strrchr (s,'/')) && !s[1]) return T;
 408.399 +    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
 408.400 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 408.401 +      MM_LOG (tmp,ERROR);
 408.402 +      unlink (mbx);		/* delete the file */
 408.403 +    }
 408.404 +    else {
 408.405 +      memset (tmp,'\0',HDRSIZE);/* initialize header */
 408.406 +      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
 408.407 +	       (unsigned long) time (0));
 408.408 +      for (i = 0; i < NUSERFLAGS; ++i) {
 408.409 +	t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
 408.410 +	  ((t = default_user_flag (i)) ? t : "");
 408.411 +	sprintf (s += strlen (s),"%s\015\012",t);
 408.412 +      }
 408.413 +      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
 408.414 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
 408.415 +		 mbx,strerror (errno));
 408.416 +	MM_LOG (tmp,ERROR);
 408.417 +	unlink (mbx);		/* delete the file */
 408.418 +      }
 408.419 +      else ret = T;		/* success */
 408.420 +      close (fd);		/* close file */
 408.421 +    }
 408.422 +  }
 408.423 +				/* set proper protections */
 408.424 +  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
 408.425 +}
 408.426 +
 408.427 +
 408.428 +/* MBX mail delete mailbox
 408.429 + * Accepts: MAIL stream
 408.430 + *	    mailbox name to delete
 408.431 + * Returns: T on success, NIL on failure
 408.432 + */
 408.433 +
 408.434 +long mbx_delete (MAILSTREAM *stream,char *mailbox)
 408.435 +{
 408.436 +  return mbx_rename (stream,mailbox,NIL);
 408.437 +}
 408.438 +
 408.439 +/* MBX mail rename mailbox
 408.440 + * Accepts: MAIL stream
 408.441 + *	    old mailbox name
 408.442 + *	    new mailbox name (or NIL for delete)
 408.443 + * Returns: T on success, NIL on failure
 408.444 + */
 408.445 +
 408.446 +long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
 408.447 +{
 408.448 +  long ret = LONGT;
 408.449 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 408.450 +  int fd,ld;
 408.451 +  struct stat sbuf;
 408.452 +  if (!mbx_file (file,old) ||
 408.453 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 408.454 +		   ((s = strrchr (tmp,'/')) && !s[1])))) {
 408.455 +    sprintf (tmp,newname ?
 408.456 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 408.457 +	     "Can't delete mailbox %.80s: invalid name",
 408.458 +	     old,newname);
 408.459 +    MM_LOG (tmp,ERROR);
 408.460 +    return NIL;
 408.461 +  }
 408.462 +  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
 408.463 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 408.464 +    MM_LOG (tmp,ERROR);
 408.465 +    return NIL;
 408.466 +  }
 408.467 +				/* get parse/append permission */
 408.468 +  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
 408.469 +    MM_LOG ("Unable to lock rename mailbox",ERROR);
 408.470 +    return NIL;
 408.471 +  }
 408.472 +				/* lock out other users */
 408.473 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 408.474 +    close (fd);			/* couldn't lock, give up on it then */
 408.475 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 408.476 +    MM_LOG (tmp,ERROR);
 408.477 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 408.478 +    return NIL;
 408.479 +  }
 408.480 +
 408.481 +  if (newname) {		/* want rename? */
 408.482 +				/* found superior to destination name? */
 408.483 +    if (s = strrchr (tmp,'/')) {
 408.484 +      c = *++s;			/* remember first character of inferior */
 408.485 +      *s = '\0';		/* tie off to get just superior */
 408.486 +				/* superior name doesn't exist, create it */
 408.487 +      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 408.488 +	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
 408.489 +	ret = NIL;
 408.490 +      else *s = c;		/* restore full name */
 408.491 +    }
 408.492 +				/* rename the file */
 408.493 +    if (ret && rename (file,tmp)) {
 408.494 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 408.495 +	       strerror (errno));
 408.496 +      MM_LOG (tmp,ERROR);
 408.497 +      ret = NIL;		/* set failure */
 408.498 +    }
 408.499 +  }
 408.500 +  else if (unlink (file)) {
 408.501 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 408.502 +    MM_LOG (tmp,ERROR);
 408.503 +    ret = NIL;			/* set failure */
 408.504 +  }
 408.505 +  flock (fd,LOCK_UN);		/* release lock on the file */
 408.506 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 408.507 +  close (fd);			/* close the file */
 408.508 +				/* recreate file if renamed INBOX */
 408.509 +  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
 408.510 +  return ret;			/* return success */
 408.511 +}
 408.512 +
 408.513 +/* MBX Mail status
 408.514 + * Accepts: mail stream
 408.515 + *	    mailbox name
 408.516 + *	    status flags
 408.517 + * Returns: T on success, NIL on failure
 408.518 + */
 408.519 +
 408.520 +long mbx_status (MAILSTREAM *stream,char *mbx,long flags)
 408.521 +{
 408.522 +  MAILSTATUS status;
 408.523 +  unsigned long i;
 408.524 +  MAILSTREAM *tstream = NIL;
 408.525 +  MAILSTREAM *systream = NIL;
 408.526 +				/* make temporary stream (unless this mbx) */
 408.527 +  if (!stream && !(stream = tstream =
 408.528 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT)))
 408.529 +    return NIL;
 408.530 +  status.flags = flags;		/* return status values */
 408.531 +  status.messages = stream->nmsgs;
 408.532 +  status.recent = stream->recent;
 408.533 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 408.534 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 408.535 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 408.536 +  status.uidnext = stream->uid_last + 1;
 408.537 +  status.uidvalidity = stream->uid_validity;
 408.538 +				/* calculate post-snarf results */
 408.539 +  if (!status.recent && stream->inbox &&
 408.540 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
 408.541 +    status.messages += systream->nmsgs;
 408.542 +    status.recent += systream->recent;
 408.543 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 408.544 +      for (i = 1; i <= systream->nmsgs; i++)
 408.545 +	if (!mail_elt (systream,i)->seen) status.unseen++;
 408.546 +				/* kludge but probably good enough */
 408.547 +    status.uidnext += systream->nmsgs;
 408.548 +  }
 408.549 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 408.550 +  if (tstream) mail_close (tstream);
 408.551 +  if (systream) mail_close (systream);
 408.552 +  return T;			/* success */
 408.553 +}
 408.554 +
 408.555 +/* MBX mail open
 408.556 + * Accepts: stream to open
 408.557 + * Returns: stream on success, NIL on failure
 408.558 + */
 408.559 +
 408.560 +MAILSTREAM *mbx_open (MAILSTREAM *stream)
 408.561 +{
 408.562 +  int fd,ld;
 408.563 +  short silent;
 408.564 +  char tmp[MAILTMPLEN];
 408.565 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 408.566 +				/* return prototype for OP_PROTOTYPE call */
 408.567 +  if (!stream) return user_flags (&mbxproto);
 408.568 +  if (stream->local) fatal ("mbx recycle stream");
 408.569 +				/* canonicalize the mailbox name */
 408.570 +  if (!mbx_file (tmp,stream->mailbox)) {
 408.571 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 408.572 +    MM_LOG (tmp,ERROR);
 408.573 +  }
 408.574 +  if (stream->rdonly ||
 408.575 +      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
 408.576 +    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
 408.577 +      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 408.578 +      MM_LOG (tmp,ERROR);
 408.579 +      return NIL;
 408.580 +    }
 408.581 +    else if (!stream->rdonly) {	/* got it, but readonly */
 408.582 +      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 408.583 +      stream->rdonly = T;
 408.584 +    }
 408.585 +  }
 408.586 +
 408.587 +  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
 408.588 +  LOCAL->fd = fd;		/* bind the file */
 408.589 +  LOCAL->ld = -1;		/* no flaglock */
 408.590 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 408.591 +  LOCAL->buflen = CHUNKSIZE - 1;
 408.592 +				/* note if an INBOX or not */
 408.593 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 408.594 +  fs_give ((void **) &stream->mailbox);
 408.595 +  stream->mailbox = cpystr (tmp);
 408.596 +				/* get parse/append permission */
 408.597 +  if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) {
 408.598 +    MM_LOG ("Unable to lock open mailbox",ERROR);
 408.599 +    return NIL;
 408.600 +  }
 408.601 +  (*bn) (BLOCK_FILELOCK,NIL);
 408.602 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 408.603 +  (*bn) (BLOCK_NONE,NIL);
 408.604 +  unlockfd (ld,tmp);		/* release shared parse permission */
 408.605 +  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
 408.606 +				/* time not set up yet */
 408.607 +  LOCAL->lastsnarf = LOCAL->filetime = 0;
 408.608 +  LOCAL->expok = LOCAL->flagcheck = NIL;
 408.609 +  stream->sequence++;		/* bump sequence number */
 408.610 +				/* parse mailbox */
 408.611 +  stream->nmsgs = stream->recent = 0;
 408.612 +  silent = stream->silent;	/* defer events */
 408.613 +  stream->silent = T;
 408.614 +  if (mbx_ping (stream) && !stream->nmsgs)
 408.615 +    MM_LOG ("Mailbox is empty",(long) NIL);
 408.616 +  stream->silent = silent;	/* now notify upper level */
 408.617 +  mail_exists (stream,stream->nmsgs);
 408.618 +  mail_recent (stream,stream->recent);
 408.619 +  if (!LOCAL) return NIL;	/* failure if stream died */
 408.620 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 408.621 +    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 408.622 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 408.623 +  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
 408.624 +    NIL : T;			/* can we create new user flags? */
 408.625 +  return stream;		/* return stream to caller */
 408.626 +}
 408.627 +
 408.628 +/* MBX mail close
 408.629 + * Accepts: MAIL stream
 408.630 + *	    close options
 408.631 + */
 408.632 +
 408.633 +void mbx_close (MAILSTREAM *stream,long options)
 408.634 +{
 408.635 +  if (stream && LOCAL) {	/* only if a file is open */
 408.636 +    int silent = stream->silent;
 408.637 +    stream->silent = T;		/* note this stream is dying */
 408.638 +				/* do an expunge if requested */
 408.639 +    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
 408.640 +    else {			/* otherwise do a checkpoint to purge */
 408.641 +      LOCAL->expok = T;		/*  possible expunged messages */
 408.642 +      mbx_ping (stream);
 408.643 +    }
 408.644 +    stream->silent = silent;	/* restore previous status */
 408.645 +    mbx_abort (stream);
 408.646 +  }
 408.647 +}
 408.648 +
 408.649 +
 408.650 +/* MBX mail abort stream
 408.651 + * Accepts: MAIL stream
 408.652 + */
 408.653 +
 408.654 +void mbx_abort (MAILSTREAM *stream)
 408.655 +{
 408.656 +  if (stream && LOCAL) {	/* only if a file is open */
 408.657 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 408.658 +    close (LOCAL->fd);		/* close the local file */
 408.659 +				/* free local text buffer */
 408.660 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 408.661 +				/* nuke the local data */
 408.662 +    fs_give ((void **) &stream->local);
 408.663 +    stream->dtb = NIL;		/* log out the DTB */
 408.664 +  }
 408.665 +}
 408.666 +
 408.667 +
 408.668 +/* MBX mail fetch flags
 408.669 + * Accepts: MAIL stream
 408.670 + *	    sequence
 408.671 + *	    option flags
 408.672 + * Sniffs at file to see if some other process changed the flags
 408.673 + */
 408.674 +
 408.675 +void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
 408.676 +{
 408.677 +  MESSAGECACHE *elt;
 408.678 +  unsigned long i;
 408.679 +  if (mbx_ping (stream) && 	/* ping mailbox, get new status for messages */
 408.680 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 408.681 +       mail_sequence (stream,sequence)))
 408.682 +    for (i = 1; i <= stream->nmsgs; i++) 
 408.683 +      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
 408.684 +	mbx_elt (stream,i,NIL);
 408.685 +}
 408.686 +
 408.687 +/* MBX mail fetch message header
 408.688 + * Accepts: MAIL stream
 408.689 + *	    message # to fetch
 408.690 + *	    pointer to returned header text length
 408.691 + *	    option flags
 408.692 + * Returns: message header in RFC822 format
 408.693 + */
 408.694 +
 408.695 +char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 408.696 +		  long flags)
 408.697 +{
 408.698 +  unsigned long i;
 408.699 +  char *s;
 408.700 +  *length = 0;			/* default to empty */
 408.701 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 408.702 +				/* get header position, possibly header */
 408.703 +  i = mbx_hdrpos (stream,msgno,length,&s);
 408.704 +  if (!s) {			/* mbx_hdrpos() returned header? */
 408.705 +    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
 408.706 +				/* is buffer big enough? */
 408.707 +    if (*length > LOCAL->buflen) {
 408.708 +      fs_give ((void **) &LOCAL->buf);
 408.709 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 408.710 +    }
 408.711 +				/* slurp the data */
 408.712 +    read (LOCAL->fd,s = LOCAL->buf,*length);
 408.713 +  }
 408.714 +  s[*length] = '\0';		/* tie off string */
 408.715 +  return s;
 408.716 +}
 408.717 +
 408.718 +/* MBX mail fetch message text (body only)
 408.719 + * Accepts: MAIL stream
 408.720 + *	    message # to fetch
 408.721 + *	    pointer to returned header text length
 408.722 + *	    option flags
 408.723 + * Returns: T on success, NIL on failure
 408.724 + */
 408.725 +
 408.726 +long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 408.727 +{
 408.728 +  FDDATA d;
 408.729 +  unsigned long i,j;
 408.730 +  MESSAGECACHE *elt;
 408.731 +				/* UID call "impossible" */
 408.732 +  if (flags & FT_UID) return NIL;
 408.733 +				/* get message status */
 408.734 +  elt = mbx_elt (stream,msgno,NIL);
 408.735 +				/* if message not seen */
 408.736 +  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
 408.737 +    elt->seen = T;		/* mark message as seen */
 408.738 +				/* recalculate status */
 408.739 +    mbx_update_status (stream,msgno,NIL);
 408.740 +    MM_FLAGS (stream,msgno);
 408.741 +				/* update flags */
 408.742 +    mbx_flag (stream,NIL,NIL,NIL);
 408.743 +  }
 408.744 +  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
 408.745 +				/* find header position */
 408.746 +  i = mbx_hdrpos (stream,msgno,&j,NIL);
 408.747 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 408.748 +  d.pos = i + j;
 408.749 +  d.chunk = LOCAL->buf;	/* initial buffer chunk */
 408.750 +  d.chunksize = CHUNKSIZE;
 408.751 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 408.752 +  return LONGT;			/* success */
 408.753 +}
 408.754 +
 408.755 +/* MBX mail modify flags
 408.756 + * Accepts: MAIL stream
 408.757 + *	    sequence
 408.758 + *	    flag(s)
 408.759 + *	    option flags
 408.760 + * Unlocks flag lock
 408.761 + */
 408.762 +
 408.763 +void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 408.764 +{
 408.765 +  time_t tp[2];
 408.766 +  struct stat sbuf;
 408.767 +  unsigned long oldpid = LOCAL->lastpid;
 408.768 +				/* make sure the update takes */
 408.769 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
 408.770 +    fsync (LOCAL->fd);
 408.771 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 408.772 +    tp[1] = LOCAL->filetime = sbuf.st_mtime;
 408.773 +				/* we are the last flag updater */
 408.774 +    LOCAL->lastpid = (unsigned long) getpid ();
 408.775 +				/* update header if needed */
 408.776 +    if (((LOCAL->ffuserflag < NUSERFLAGS) &&
 408.777 +	 stream->user_flags[LOCAL->ffuserflag]) || (oldpid != LOCAL->lastpid))
 408.778 +      mbx_update_header (stream);
 408.779 +    tp[0] = time (0);		/* make sure read comes after all that */
 408.780 +    utime (stream->mailbox,tp);
 408.781 +  }
 408.782 +  if (LOCAL->ld >= 0) {		/* unlock now */
 408.783 +    unlockfd (LOCAL->ld,LOCAL->lock);
 408.784 +    LOCAL->ld = -1;
 408.785 +  }
 408.786 +}
 408.787 +
 408.788 +
 408.789 +/* MBX mail per-message modify flags
 408.790 + * Accepts: MAIL stream
 408.791 + *	    message cache element
 408.792 + */
 408.793 +
 408.794 +void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 408.795 +{
 408.796 +  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
 408.797 +}
 408.798 +
 408.799 +/* MBX mail ping mailbox
 408.800 + * Accepts: MAIL stream
 408.801 + * Returns: T if stream still alive, NIL if not
 408.802 + */
 408.803 +
 408.804 +long mbx_ping (MAILSTREAM *stream)
 408.805 +{
 408.806 +  unsigned long i,pos;
 408.807 +  long ret = NIL;
 408.808 +  int ld;
 408.809 +  char lock[MAILTMPLEN];
 408.810 +  MESSAGECACHE *elt;
 408.811 +  struct stat sbuf;
 408.812 +  if (stream && LOCAL) {	/* only if stream already open */
 408.813 +    int snarf = stream->inbox && !stream->rdonly;
 408.814 +    ret = LONGT;		/* assume OK */
 408.815 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 408.816 +				/* allow expunge if permitted at ping */
 408.817 +    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
 408.818 +				/* if external modification */
 408.819 +    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
 408.820 +      LOCAL->flagcheck = T;	/* upgrade to flag checking */
 408.821 +				/* new mail or flagcheck handling needed? */
 408.822 +    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
 408.823 +	 !stream->nmsgs || snarf) &&
 408.824 +	((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
 408.825 +				/* reparse header if not flagchecking */
 408.826 +      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
 408.827 +				/* sweep mailbox for changed message status */
 408.828 +      else if (ret = mbx_parse (stream)) {
 408.829 +	unsigned long recent = 0;
 408.830 +	LOCAL->filetime = sbuf.st_mtime;
 408.831 +	for (i = 1; i <= stream->nmsgs; )
 408.832 +	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
 408.833 +	    if (elt->recent) ++recent;
 408.834 +	    ++i;
 408.835 +	  }
 408.836 +	mail_recent (stream,recent);
 408.837 +	LOCAL->flagcheck = NIL;	/* got all the updates */
 408.838 +      }
 408.839 +				/* always reparse header at least */
 408.840 +      if (ret && snarf) {	/* snarf new messages if still OK */
 408.841 +	mbx_snarf (stream);
 408.842 +				/* parse snarfed messages */
 408.843 +	ret = mbx_parse (stream);
 408.844 +      }
 408.845 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 408.846 +    }
 408.847 +    if (ret) {			/* must still be alive */
 408.848 +      if (!LOCAL->expunged)	/* look for holes if none known yet */
 408.849 +	for (i = 1, pos = HDRSIZE;
 408.850 +	     !LOCAL->expunged && (i <= stream->nmsgs);
 408.851 +	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
 408.852 +	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
 408.853 +	    LOCAL->expunged = T;/* found a hole */
 408.854 +				/* burp any holes */
 408.855 +      if (LOCAL->expunged && !stream->rdonly) {
 408.856 +	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
 408.857 +	if (i) {		/* any space reclaimed? */
 408.858 +	  LOCAL->expunged = NIL;/* no more pending expunge */
 408.859 +	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
 408.860 +	  MM_LOG (LOCAL->buf,(long) NIL);
 408.861 +	}
 408.862 +      }
 408.863 +      LOCAL->expok = NIL;	/* no more expok */
 408.864 +    }
 408.865 +  }
 408.866 +  return ret;			/* return result of the parse */
 408.867 +}
 408.868 +
 408.869 +/* MBX mail check mailbox (reparses status too)
 408.870 + * Accepts: MAIL stream
 408.871 + */
 408.872 +
 408.873 +void mbx_check (MAILSTREAM *stream)
 408.874 +{
 408.875 +  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
 408.876 +  if (mbx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 408.877 +}
 408.878 +
 408.879 +
 408.880 +/* MBX mail expunge mailbox
 408.881 + * Accepts: MAIL stream
 408.882 + *	    sequence to expunge if non-NIL
 408.883 + *	    expunge options
 408.884 + * Returns: T if success, NIL if failure
 408.885 + */
 408.886 +
 408.887 +long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
 408.888 +{
 408.889 +  long ret;
 408.890 +  unsigned long nexp,reclaimed;
 408.891 +  if (ret = sequence ? ((options & EX_UID) ?
 408.892 +			mail_uid_sequence (stream,sequence) :
 408.893 +			mail_sequence (stream,sequence)) : LONGT) {
 408.894 +    if (!mbx_ping (stream));	/* do nothing if stream dead */
 408.895 +    else if (stream->rdonly)	/* won't do on readonly files! */
 408.896 +      MM_LOG ("Expunge ignored on readonly mailbox",WARN);
 408.897 +				/* if expunged any messages */
 408.898 +    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
 408.899 +      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
 408.900 +      MM_LOG (LOCAL->buf,(long) NIL);
 408.901 +    }
 408.902 +    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
 408.903 +      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
 408.904 +      MM_LOG (LOCAL->buf,(long) NIL);
 408.905 +    }
 408.906 +    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 408.907 +  }
 408.908 +  return ret;
 408.909 +}
 408.910 +
 408.911 +/* MBX mail snarf messages from system inbox
 408.912 + * Accepts: MAIL stream, already locked
 408.913 + */
 408.914 +
 408.915 +void mbx_snarf (MAILSTREAM *stream)
 408.916 +{
 408.917 +  unsigned long i = 0;
 408.918 +  unsigned long j,r,hdrlen,txtlen;
 408.919 +  struct stat sbuf;
 408.920 +  char *hdr,*txt,tmp[MAILTMPLEN];
 408.921 +  MESSAGECACHE *elt;
 408.922 +  MAILSTREAM *sysibx = NIL;
 408.923 +				/* give up if can't get exclusive permission */
 408.924 +  if ((time (0) >= (LOCAL->lastsnarf +
 408.925 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
 408.926 +      strcmp (sysinbox (),stream->mailbox)) {
 408.927 +    MM_CRITICAL (stream);	/* go critical */
 408.928 +				/* sizes match and anything in sysinbox? */
 408.929 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 408.930 +	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
 408.931 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 408.932 +	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
 408.933 +				/* yes, go to end of file in our mailbox */
 408.934 +      lseek (LOCAL->fd,sbuf.st_size,L_SET);
 408.935 +				/* for each message in sysibx mailbox */
 408.936 +      while (r && (++i <= sysibx->nmsgs)) {
 408.937 +				/* snarf message from system INBOX */
 408.938 +	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
 408.939 +	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
 408.940 +				/* if have a message */
 408.941 +	if (j = hdrlen + txtlen) {
 408.942 +				/* build header line */
 408.943 +	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
 408.944 +	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
 408.945 +		   ",%lu;00000000%04x-00000000\015\012",j,(unsigned)
 408.946 +		   ((fSEEN * elt->seen) +
 408.947 +		    (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) +
 408.948 +		    (fANSWERED * elt->answered) + (fDRAFT * elt->draft)));
 408.949 +				/* copy message */
 408.950 +	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
 408.951 +	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
 408.952 +	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
 408.953 +	}
 408.954 +	fs_give ((void **) &hdr);
 408.955 +      }
 408.956 +
 408.957 +				/* make sure all the updates take */
 408.958 +      if (fsync (LOCAL->fd)) r = 0;
 408.959 +      if (r) {			/* delete all the messages we copied */
 408.960 +	if (r == 1) strcpy (tmp,"1");
 408.961 +	else sprintf (tmp,"1:%lu",r);
 408.962 +	mail_setflag (sysibx,tmp,"\\Deleted");
 408.963 +	mail_expunge (sysibx);	/* now expunge all those messages */
 408.964 +      }
 408.965 +      else {
 408.966 +	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
 408.967 +	MM_LOG (LOCAL->buf,WARN);
 408.968 +	ftruncate (LOCAL->fd,sbuf.st_size);
 408.969 +      }
 408.970 +      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
 408.971 +      LOCAL->filetime = sbuf.st_mtime;
 408.972 +    }
 408.973 +    if (sysibx) mail_close (sysibx);
 408.974 +    MM_NOCRITICAL (stream);	/* release critical */
 408.975 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 408.976 +  }
 408.977 +}
 408.978 +
 408.979 +/* MBX mail copy message(s)
 408.980 + * Accepts: MAIL stream
 408.981 + *	    sequence
 408.982 + *	    destination mailbox
 408.983 + *	    copy options
 408.984 + * Returns: T if success, NIL if failed
 408.985 + */
 408.986 +
 408.987 +long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 408.988 +{
 408.989 +  struct stat sbuf;
 408.990 +  time_t tp[2];
 408.991 +  MESSAGECACHE *elt;
 408.992 +  unsigned long i,j,k,m;
 408.993 +  long ret = LONGT;
 408.994 +  int fd,ld;
 408.995 +  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
 408.996 +  mailproxycopy_t pc =
 408.997 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 408.998 +  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 408.999 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
408.1000 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
408.1001 +  MAILSTREAM *dstream = NIL;
408.1002 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
408.1003 +	mail_sequence (stream,sequence))) return NIL;
408.1004 +				/* make sure valid mailbox */
408.1005 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
408.1006 +			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
408.1007 +    switch (errno) {
408.1008 +    case ENOENT:		/* no such file? */
408.1009 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
408.1010 +      return NIL;
408.1011 +    case EACCES:		/* file protected */
408.1012 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
408.1013 +      MM_LOG (LOCAL->buf,ERROR);
408.1014 +      return NIL;
408.1015 +    case EINVAL:
408.1016 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
408.1017 +      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
408.1018 +      MM_LOG (LOCAL->buf,ERROR);
408.1019 +      return NIL;
408.1020 +    default:
408.1021 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
408.1022 +      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
408.1023 +      MM_LOG (LOCAL->buf,ERROR);
408.1024 +      return NIL;
408.1025 +    }
408.1026 +  MM_CRITICAL (stream);		/* go critical */
408.1027 +  fstat (fd,&sbuf);		/* get current file size */
408.1028 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
408.1029 +
408.1030 +				/* for each requested message */
408.1031 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
408.1032 +    if ((elt = mail_elt (stream,i))->sequence) {
408.1033 +      lseek (LOCAL->fd,elt->private.special.offset +
408.1034 +	     elt->private.special.text.size,L_SET);
408.1035 +      mail_date(LOCAL->buf,elt);/* build target header */
408.1036 +				/* get target keyword mask */
408.1037 +      for (j = elt->user_flags, k = 0; j; )
408.1038 +	if (s = stream->user_flags[find_rightmost_bit (&j)])
408.1039 +	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
408.1040 +	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
408.1041 +      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
408.1042 +	       elt->rfc822_size,k,(unsigned)
408.1043 +	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
408.1044 +		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
408.1045 +		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
408.1046 +				/* write target header */
408.1047 +      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
408.1048 +	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
408.1049 +	  read (LOCAL->fd,LOCAL->buf,j);
408.1050 +	  ret = write (fd,LOCAL->buf,j) >= 0;
408.1051 +	}
408.1052 +	if (cu) {		/* need to pass back new UID? */
408.1053 +	  mail_append_set (source,mail_uid (stream,i));
408.1054 +	  mail_append_set (dest,dstream->uid_last);
408.1055 +	}
408.1056 +      }
408.1057 +    }
408.1058 +
408.1059 +				/* make sure all the updates take */
408.1060 +  if (!(ret && (ret = !fsync (fd)))) {
408.1061 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
408.1062 +    MM_LOG (LOCAL->buf,ERROR);
408.1063 +    ftruncate (fd,sbuf.st_size);
408.1064 +  }
408.1065 +  if (cu && ret) {		/* return sets if doing COPYUID */
408.1066 +    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
408.1067 +    lseek (fd,15,L_SET);	/* update UIDLAST */
408.1068 +    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
408.1069 +    write (fd,LOCAL->buf,8);
408.1070 +  }
408.1071 +  else {			/* flush any sets we may have built */
408.1072 +    mail_free_searchset (&source);
408.1073 +    mail_free_searchset (&dest);
408.1074 +  }
408.1075 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
408.1076 +				/* else preserve \Marked status */
408.1077 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
408.1078 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
408.1079 +  utime (file,tp);		/* set the times */
408.1080 +  close (fd);			/* close the file */
408.1081 +  MM_NOCRITICAL (stream);	/* release critical */
408.1082 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
408.1083 +				/* delete all requested messages */
408.1084 +  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
408.1085 +    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
408.1086 +				/* mark message deleted */
408.1087 +      mbx_elt (stream,i,NIL)->deleted = T;
408.1088 +				/* recalculate status */
408.1089 +      mbx_update_status (stream,i,NIL);
408.1090 +    }
408.1091 +				/* update flags */
408.1092 +    mbx_flag (stream,NIL,NIL,NIL);
408.1093 +  }
408.1094 +  if (dstream != stream) mail_close (dstream);
408.1095 +  return ret;
408.1096 +}
408.1097 +
408.1098 +/* MBX mail append message from stringstruct
408.1099 + * Accepts: MAIL stream
408.1100 + *	    destination mailbox
408.1101 + *	    append callback
408.1102 + *	    data for callback
408.1103 + * Returns: T if append successful, else NIL
408.1104 + */
408.1105 +
408.1106 +long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
408.1107 +{
408.1108 +  struct stat sbuf;
408.1109 +  int fd,ld;
408.1110 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
408.1111 +  time_t tp[2];
408.1112 +  FILE *df;
408.1113 +  MESSAGECACHE elt;
408.1114 +  long f;
408.1115 +  unsigned long i,uf;
408.1116 +  STRING *message;
408.1117 +  long ret = NIL;
408.1118 +  MAILSTREAM *dstream = NIL;
408.1119 +  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
408.1120 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
408.1121 +				/* make sure valid mailbox */
408.1122 +  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
408.1123 +			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
408.1124 +    switch (errno) {
408.1125 +    case ENOENT:		/* no such file? */
408.1126 +      if (compare_cstring (mailbox,"INBOX")) {
408.1127 +	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
408.1128 +	return NIL;
408.1129 +      }
408.1130 +				/* can create INBOX here */
408.1131 +      mbx_create (dstream = stream ? stream : user_flags (&mbxproto),"INBOX");
408.1132 +      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
408.1133 +			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) >= 0)
408.1134 +	break;
408.1135 +    case EACCES:		/* file protected */
408.1136 +      sprintf (tmp,"Can't access destination: %.80s",mailbox);
408.1137 +      MM_LOG (tmp,ERROR);
408.1138 +      return NIL;
408.1139 +    case EINVAL:
408.1140 +      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
408.1141 +      MM_LOG (tmp,ERROR);
408.1142 +      return NIL;
408.1143 +    default:
408.1144 +      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
408.1145 +      MM_LOG (tmp,ERROR);
408.1146 +      return NIL;
408.1147 +    }
408.1148 +
408.1149 +				/* get first message */
408.1150 +  if (!MM_APPEND (af) (dstream,data,&flags,&date,&message)) close (fd);
408.1151 +  else if (!(df = fdopen (fd,"r+b"))) {
408.1152 +    MM_LOG ("Unable to reopen append mailbox",ERROR);
408.1153 +    close (fd);
408.1154 +  }
408.1155 +  else {
408.1156 +    MM_CRITICAL (dstream);	/* go critical */
408.1157 +    fstat (fd,&sbuf);		/* get current file size */
408.1158 +    fseek (df,sbuf.st_size,SEEK_SET);
408.1159 +    errno = 0;
408.1160 +    for (ret = LONGT; ret && message; ) {
408.1161 +      if (!SIZE (message)) {	/* guard against zero-length */
408.1162 +	MM_LOG ("Append of zero-length message",ERROR);
408.1163 +	ret = NIL;
408.1164 +	break;
408.1165 +      }
408.1166 +      f = mail_parse_flags (dstream,flags,&uf);
408.1167 +      if (date) {		/* parse date if given */
408.1168 +	if (!mail_parse_date (&elt,date)) {
408.1169 +	  sprintf (tmp,"Bad date in append: %.80s",date);
408.1170 +	  MM_LOG (tmp,ERROR);
408.1171 +	  ret = NIL;		/* mark failure */
408.1172 +	  break;
408.1173 +	}
408.1174 +	mail_date (tmp,&elt);	/* write preseved date */
408.1175 +      }
408.1176 +      else internal_date (tmp);	/* get current date in IMAP format */
408.1177 +				/* write header */
408.1178 +      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
408.1179 +		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
408.1180 +	ret = NIL;
408.1181 +      else {			/* write message */
408.1182 +	size_t j;
408.1183 +	if (!message->cursize) SETPOS (message,GETPOS (message));
408.1184 +	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
408.1185 +	  i -= j;
408.1186 +	  SETPOS (message,GETPOS (message) + j);
408.1187 +	}
408.1188 +				/* get next message */
408.1189 +	if (i || !MM_APPEND (af) (dstream,data,&flags,&date,&message))
408.1190 +	  ret = NIL;
408.1191 +	else if (au) mail_append_set (dst,dstream->uid_last);
408.1192 +      }
408.1193 +    }
408.1194 +
408.1195 +				/* if error... */
408.1196 +    if (!ret || (fflush (df) == EOF)) {
408.1197 +				/* revert file */
408.1198 +      ftruncate (fd,sbuf.st_size);
408.1199 +      close (fd);		/* make sure fclose() doesn't corrupt us */
408.1200 +      if (errno) {
408.1201 +	sprintf (tmp,"Message append failed: %s",strerror (errno));
408.1202 +	MM_LOG (tmp,ERROR);
408.1203 +      }
408.1204 +      ret = NIL;
408.1205 +    }
408.1206 +    if (au && ret) {		/* return sets if doing APPENDUID */
408.1207 +      (*au) (mailbox,dstream->uid_validity,dst);
408.1208 +      fseek (df,15,SEEK_SET);	/* update UIDLAST */
408.1209 +      fprintf (df,"%08lx",dstream->uid_last);
408.1210 +    }
408.1211 +    else mail_free_searchset (&dst);
408.1212 +				/* set atime to now-1 if successful copy */
408.1213 +    if (ret) tp[0] = time (0) - 1;
408.1214 +				/* else preserve \Marked status */
408.1215 +    else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
408.1216 +    tp[1] = sbuf.st_mtime;	/* preserve mtime */
408.1217 +    utime (file,tp);		/* set the times */
408.1218 +    fclose (df);		/* close the file */
408.1219 +    MM_NOCRITICAL (dstream);	/* release critical */
408.1220 +  }
408.1221 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
408.1222 +  if (dstream != stream) mail_close (dstream);
408.1223 +  return ret;
408.1224 +}
408.1225 +
408.1226 +/* Internal routines */
408.1227 +
408.1228 +
408.1229 +/* MBX mail generate file string
408.1230 + * Accepts: temporary buffer to write into
408.1231 + *	    mailbox name string
408.1232 + * Returns: local file string or NIL if failure
408.1233 + */
408.1234 +
408.1235 +char *mbx_file (char *dst,char *name)
408.1236 +{
408.1237 +  char *s = mailboxfile (dst,name);
408.1238 +  return (s && !*s) ? mailboxfile (dst,"~/INBOX") : s;
408.1239 +}
408.1240 +
408.1241 +/* MBX mail parse mailbox
408.1242 + * Accepts: MAIL stream
408.1243 + * Returns: T if parse OK
408.1244 + *	    NIL if failure, stream aborted
408.1245 + */
408.1246 +
408.1247 +long mbx_parse (MAILSTREAM *stream)
408.1248 +{
408.1249 +  struct stat sbuf;
408.1250 +  MESSAGECACHE *elt = NIL;
408.1251 +  unsigned char c,*s,*t,*x;
408.1252 +  char tmp[MAILTMPLEN];
408.1253 +  unsigned long i,j,k,m;
408.1254 +  off_t curpos = LOCAL->filesize;
408.1255 +  unsigned long nmsgs = stream->nmsgs;
408.1256 +  unsigned long recent = stream->recent;
408.1257 +  unsigned long lastuid = 0;
408.1258 +  short dirty = NIL;
408.1259 +  short added = NIL;
408.1260 +  short silent = stream->silent;
408.1261 +  short uidwarn = T;
408.1262 +  fstat (LOCAL->fd,&sbuf);	/* get status */
408.1263 +  if (sbuf.st_size < curpos) {	/* sanity check */
408.1264 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
408.1265 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
408.1266 +    MM_LOG (tmp,ERROR);
408.1267 +    mbx_abort (stream);
408.1268 +    return NIL;
408.1269 +  }
408.1270 +  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
408.1271 +				/* read internal header */
408.1272 +  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
408.1273 +  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
408.1274 +  c = LOCAL->buf[15];		/* save first character of last UID */
408.1275 +  LOCAL->buf[15] = '\0';
408.1276 +				/* parse UID validity */
408.1277 +  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
408.1278 +  LOCAL->buf[15] = c;		/* restore first character of last UID */
408.1279 +				/* parse last UID */
408.1280 +  i = strtoul (LOCAL->buf + 15,NIL,16);
408.1281 +  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
408.1282 +				/* parse user flags */
408.1283 +  for (i = 0, s = LOCAL->buf + 25;
408.1284 +       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
408.1285 +       i++, s = t + 2) {
408.1286 +    *t = '\0';			/* tie off flag */
408.1287 +    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
408.1288 +      stream->user_flags[i] = cpystr (s);
408.1289 +  }
408.1290 +  LOCAL->ffuserflag = (int) i;	/* first free user flag */
408.1291 +
408.1292 +				/* get current last flag updater PID */
408.1293 +  i = (isxdigit (LOCAL->buf[HDRSIZE-10]) && isxdigit (LOCAL->buf[HDRSIZE-9]) &&
408.1294 +       isxdigit (LOCAL->buf[HDRSIZE-8]) && isxdigit (LOCAL->buf[HDRSIZE-7]) &&
408.1295 +       isxdigit (LOCAL->buf[HDRSIZE-6]) && isxdigit (LOCAL->buf[HDRSIZE-5]) &&
408.1296 +       isxdigit (LOCAL->buf[HDRSIZE-4]) && isxdigit (LOCAL->buf[HDRSIZE-3]) &&
408.1297 +       (LOCAL->buf[HDRSIZE-2] == '\015') && (LOCAL->buf[HDRSIZE-1] == '\012'))?
408.1298 +    strtoul (LOCAL->buf + HDRSIZE - 8,NIL,16) : 0;
408.1299 +				/* set flagcheck if lastpid changed */
408.1300 +  if (LOCAL->lastpid && (LOCAL->lastpid != i)) LOCAL->flagcheck = T;
408.1301 +  LOCAL->lastpid = i;		/* set as last PID */
408.1302 +  stream->silent = T;		/* don't pass up exists events yet */
408.1303 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
408.1304 +				/* get to that position in the file */
408.1305 +    lseek (LOCAL->fd,curpos,L_SET);
408.1306 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
408.1307 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
408.1308 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
408.1309 +	       i ? strerror (errno) : "no data read");
408.1310 +      MM_LOG (tmp,ERROR);
408.1311 +      mbx_abort (stream);
408.1312 +      return NIL;
408.1313 +    }
408.1314 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
408.1315 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
408.1316 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
408.1317 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
408.1318 +      MM_LOG (tmp,ERROR);
408.1319 +      mbx_abort (stream);
408.1320 +      return NIL;
408.1321 +    }
408.1322 +    *s = '\0';			/* tie off header line */
408.1323 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
408.1324 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
408.1325 +      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
408.1326 +	       (unsigned long) curpos,(char *) LOCAL->buf);
408.1327 +      MM_LOG (tmp,ERROR);
408.1328 +      mbx_abort (stream);
408.1329 +      return NIL;
408.1330 +    }
408.1331 +    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
408.1332 +	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
408.1333 +	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
408.1334 +	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
408.1335 +      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
408.1336 +	       (unsigned long) curpos,(char *) LOCAL->buf);
408.1337 +      MM_LOG (tmp,ERROR);
408.1338 +      mbx_abort (stream);
408.1339 +      return NIL;
408.1340 +    }
408.1341 +    if ((t[13] != '-') || t[22] ||
408.1342 +	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
408.1343 +	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
408.1344 +	  isxdigit (t[20]) && isxdigit (t[21]))) {
408.1345 +      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
408.1346 +	       (unsigned long) curpos,(char *) LOCAL->buf);
408.1347 +      MM_LOG (tmp,ERROR);
408.1348 +      mbx_abort (stream);
408.1349 +      return NIL;
408.1350 +    }
408.1351 +
408.1352 +    *s++ = '\0'; *t++ = '\0';	/* break up fields */
408.1353 +				/* get message size */
408.1354 +    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
408.1355 +      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
408.1356 +	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
408.1357 +	       (char *) t);
408.1358 +      MM_LOG (tmp,ERROR);
408.1359 +      mbx_abort (stream);
408.1360 +      return NIL;
408.1361 +    }
408.1362 +				/* make sure didn't run off end of file */
408.1363 +    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
408.1364 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
408.1365 +	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
408.1366 +	       (unsigned long) sbuf.st_size);
408.1367 +      MM_LOG (tmp,ERROR);
408.1368 +      mbx_abort (stream);
408.1369 +      return NIL;
408.1370 +    }
408.1371 +				/* parse UID */
408.1372 +    if ((m = strtoul (t+13,NIL,16)) &&
408.1373 +	((m <= lastuid) || (m > stream->uid_last))) {
408.1374 +      if (uidwarn) {
408.1375 +	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
408.1376 +		 m,nmsgs+1);
408.1377 +	MM_LOG (tmp,WARN);
408.1378 +	uidwarn = NIL;
408.1379 +				/* restart UID validity */
408.1380 +	stream->uid_validity = time (0);
408.1381 +      }
408.1382 +      m = 0;			/* lose this UID */
408.1383 +      dirty = T;		/* mark dirty, set new lastuid */
408.1384 +      stream->uid_last = lastuid;
408.1385 +    }
408.1386 +
408.1387 +    t[12] = '\0';		/* parse system flags */
408.1388 +    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
408.1389 +      if (m) lastuid = m;	/* expunge message, update last UID seen */
408.1390 +      else {			/* no UID assigned? */
408.1391 +	lastuid = ++stream->uid_last;
408.1392 +	dirty = T;
408.1393 +      }
408.1394 +    }
408.1395 +    else {			/* not expunged, swell the cache */
408.1396 +      added = T;		/* note that a new message was added */
408.1397 +      mail_exists (stream,++nmsgs);
408.1398 +				/* instantiate an elt for this message */
408.1399 +      (elt = mail_elt (stream,nmsgs))->valid = T;
408.1400 +				/* parse the date */
408.1401 +      if (!mail_parse_date (elt,LOCAL->buf)) {
408.1402 +	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
408.1403 +		 (unsigned long) curpos,(char *) LOCAL->buf);
408.1404 +	MM_LOG (tmp,ERROR);
408.1405 +	mbx_abort (stream);
408.1406 +	return NIL;
408.1407 +      }
408.1408 +				/* note file offset of header */
408.1409 +      elt->private.special.offset = curpos;
408.1410 +				/* and internal header size */
408.1411 +      elt->private.special.text.size = i;
408.1412 +				/* header size not known yet */
408.1413 +      elt->private.msg.header.text.size = 0;
408.1414 +      elt->rfc822_size = j;	/* note message size */
408.1415 +				/* calculate system flags */
408.1416 +      if (k & fSEEN) elt->seen = T;
408.1417 +      if (k & fDELETED) elt->deleted = T;
408.1418 +      if (k & fFLAGGED) elt->flagged = T;
408.1419 +      if (k & fANSWERED) elt->answered = T;
408.1420 +      if (k & fDRAFT) elt->draft = T;
408.1421 +      t[8] = '\0';		/* get user flags value */
408.1422 +      elt->user_flags = strtoul (t,NIL,16);
408.1423 +				/* UID already assigned? */
408.1424 +      if (!(elt->private.uid = m) || !(k & fOLD)) {
408.1425 +	elt->recent = T;	/* no, mark as recent */
408.1426 +	++recent;		/* count up a new recent message */
408.1427 +	dirty = T;		/* and must rewrite header */
408.1428 +				/* assign new UID */
408.1429 +	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
408.1430 +	mbx_update_status (stream,elt->msgno,NIL);
408.1431 +      }
408.1432 +				/* update last parsed UID */
408.1433 +      lastuid = elt->private.uid;
408.1434 +    }
408.1435 +    curpos += i + j;		/* update position */
408.1436 +  }
408.1437 +
408.1438 +  if (dirty && !stream->rdonly){/* update header */
408.1439 +    mbx_update_header (stream);
408.1440 +    fsync (LOCAL->fd);		/* make sure all the UID updates take */
408.1441 +  }
408.1442 +				/* update parsed file size and time */
408.1443 +  LOCAL->filesize = sbuf.st_size;
408.1444 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
408.1445 +  LOCAL->filetime = sbuf.st_mtime;
408.1446 +  if (added && !stream->rdonly){/* make sure atime updated */
408.1447 +    time_t tp[2];
408.1448 +    tp[0] = time (0);
408.1449 +    tp[1] = LOCAL->filetime;
408.1450 +    utime (stream->mailbox,tp);
408.1451 +  }
408.1452 +  stream->silent = silent;	/* can pass up events now */
408.1453 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
408.1454 +  mail_recent (stream,recent);	/* and of change in recent messages */
408.1455 +  return LONGT;			/* return the winnage */
408.1456 +}
408.1457 +
408.1458 +/* MBX get cache element with status updating from file
408.1459 + * Accepts: MAIL stream
408.1460 + *	    message number
408.1461 + *	    expunge OK flag
408.1462 + * Returns: cache element
408.1463 + */
408.1464 +
408.1465 +MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
408.1466 +{
408.1467 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
408.1468 +  struct {			/* old flags */
408.1469 +    unsigned int seen : 1;
408.1470 +    unsigned int deleted : 1;
408.1471 +    unsigned int flagged : 1;
408.1472 +    unsigned int answered : 1;
408.1473 +    unsigned int draft : 1;
408.1474 +    unsigned long user_flags;
408.1475 +  } old;
408.1476 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
408.1477 +  old.answered = elt->answered; old.draft = elt->draft;
408.1478 +  old.user_flags = elt->user_flags;
408.1479 +				/* get new flags */
408.1480 +  if (mbx_read_flags (stream,elt) && expok) {
408.1481 +    mail_expunged (stream,elt->msgno);
408.1482 +    return NIL;			/* return this message was expunged */
408.1483 +  }
408.1484 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
408.1485 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
408.1486 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
408.1487 +    MM_FLAGS (stream,msgno);	/* let top level know */
408.1488 +  return elt;
408.1489 +}
408.1490 +
408.1491 +/* MBX read flags from file
408.1492 + * Accepts: MAIL stream
408.1493 + *	    cache element
408.1494 + * Returns: non-NIL if message expunged
408.1495 + */
408.1496 +
408.1497 +unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
408.1498 +{
408.1499 +  unsigned long i;
408.1500 +  struct stat sbuf;
408.1501 +  fstat (LOCAL->fd,&sbuf);	/* get status */
408.1502 +				/* make sure file size is good */
408.1503 +  if (sbuf.st_size < LOCAL->filesize) {
408.1504 +    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
408.1505 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
408.1506 +    fatal (LOCAL->buf);
408.1507 +  }
408.1508 +				/* set the seek pointer */
408.1509 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
408.1510 +	 elt->private.special.text.size - 24,L_SET);
408.1511 +				/* read the new flags */
408.1512 +  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
408.1513 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
408.1514 +    fatal (LOCAL->buf);
408.1515 +  }
408.1516 +  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
408.1517 +    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
408.1518 +    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
408.1519 +	     elt->msgno,elt->private.special.offset,
408.1520 +	     elt->private.special.text.size,(char *) LOCAL->buf);
408.1521 +    fatal (LOCAL->buf+50);
408.1522 +  }
408.1523 +  LOCAL->buf[13] = '\0';	/* tie off buffer */
408.1524 +				/* calculate system flags */
408.1525 +  i = strtoul (LOCAL->buf+9,NIL,16);
408.1526 +  elt->seen = i & fSEEN ? T : NIL;
408.1527 +  elt->deleted = i & fDELETED ? T : NIL;
408.1528 +  elt->flagged = i & fFLAGGED ? T : NIL;
408.1529 +  elt->answered = i & fANSWERED ? T : NIL;
408.1530 +  elt->draft = i & fDRAFT ? T : NIL;
408.1531 +  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
408.1532 +  LOCAL->buf[9] = '\0';		/* tie off flags */
408.1533 +				/* get user flags value */
408.1534 +  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
408.1535 +  elt->valid = T;		/* have valid flags now */
408.1536 +  return i & fEXPUNGED;
408.1537 +}
408.1538 +
408.1539 +/* MBX update header
408.1540 + * Accepts: MAIL stream
408.1541 + */
408.1542 +
408.1543 +#ifndef CYGKLUDGEOFFSET
408.1544 +#define CYGKLUDGEOFFSET 0
408.1545 +#endif
408.1546 +
408.1547 +void mbx_update_header (MAILSTREAM *stream)
408.1548 +{
408.1549 +  int i;
408.1550 +  char *s = LOCAL->buf;
408.1551 +  memset (s,'\0',HDRSIZE);	/* initialize header */
408.1552 +  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
408.1553 +	   stream->uid_validity,stream->uid_last);
408.1554 +  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
408.1555 +    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
408.1556 +  LOCAL->ffuserflag = i;	/* first free user flag */
408.1557 +				/* can we create more user flags? */
408.1558 +  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
408.1559 +				/* write reserved lines */
408.1560 +  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
408.1561 +  sprintf (LOCAL->buf + HDRSIZE - 10,"%08lx\015\012",LOCAL->lastpid);
408.1562 +  while (T) {			/* rewind file */
408.1563 +    lseek (LOCAL->fd,CYGKLUDGEOFFSET,L_SET);
408.1564 +				/* write new header */
408.1565 +    if (write (LOCAL->fd,LOCAL->buf + CYGKLUDGEOFFSET,
408.1566 +	       HDRSIZE - CYGKLUDGEOFFSET) > 0) break;
408.1567 +    MM_NOTIFY (stream,strerror (errno),WARN);
408.1568 +    MM_DISKERROR (stream,errno,T);
408.1569 +  }
408.1570 +}
408.1571 +
408.1572 +/* MBX update status string
408.1573 + * Accepts: MAIL stream
408.1574 + *	    message number
408.1575 + *	    flags
408.1576 + */
408.1577 +
408.1578 +void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
408.1579 +{
408.1580 +  struct stat sbuf;
408.1581 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
408.1582 +				/* readonly */
408.1583 +  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
408.1584 +  else {			/* readwrite */
408.1585 +    fstat (LOCAL->fd,&sbuf);	/* get status */
408.1586 +				/* make sure file size is good */
408.1587 +    if (sbuf.st_size < LOCAL->filesize) {
408.1588 +      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
408.1589 +	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
408.1590 +      fatal (LOCAL->buf);
408.1591 +    }
408.1592 +				/* set the seek pointer */
408.1593 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
408.1594 +	   elt->private.special.text.size - 24,L_SET);
408.1595 +				/* read the new flags */
408.1596 +    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
408.1597 +      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
408.1598 +      fatal (LOCAL->buf);
408.1599 +    }
408.1600 +    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
408.1601 +      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
408.1602 +      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
408.1603 +	       elt->msgno,elt->private.special.offset,
408.1604 +	       elt->private.special.text.size,(char *) LOCAL->buf);
408.1605 +      fatal (LOCAL->buf+50);
408.1606 +    }
408.1607 +				/* print new flag string */
408.1608 +    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
408.1609 +	     (((elt->deleted && flags) ?
408.1610 +	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
408.1611 +	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
408.1612 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
408.1613 +	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
408.1614 +    while (T) {			/* get to that place in the file */
408.1615 +      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
408.1616 +	     elt->private.special.text.size - 23,L_SET);
408.1617 +				/* write new flags and UID */
408.1618 +      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
408.1619 +      MM_NOTIFY (stream,strerror (errno),WARN);
408.1620 +      MM_DISKERROR (stream,errno,T);
408.1621 +    }
408.1622 +  }
408.1623 +}
408.1624 +
408.1625 +/* MBX locate header for a message
408.1626 + * Accepts: MAIL stream
408.1627 + *	    message number
408.1628 + *	    pointer to returned header size
408.1629 + *	    pointer to possible returned header
408.1630 + * Returns: position of header in file
408.1631 + */
408.1632 +
408.1633 +#define HDRBUFLEN 16384		/* good enough for most headers */
408.1634 +#define SLOP 4			/* CR LF CR LF */
408.1635 +
408.1636 +unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
408.1637 +			  unsigned long *size,char **hdr)
408.1638 +{
408.1639 +  unsigned long siz,done;
408.1640 +  long i;
408.1641 +  unsigned char *s,*t,*te;
408.1642 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
408.1643 +  unsigned long ret = elt->private.special.offset +
408.1644 +    elt->private.special.text.size;
408.1645 +  if (hdr) *hdr = NIL;		/* assume no header returned */
408.1646 +				/* is header size known? */ 
408.1647 +  if (*size = elt->private.msg.header.text.size) return ret;
408.1648 +				/* paranoia check */
408.1649 +  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
408.1650 +    fatal ("LOCAL->buf smaller than HDRBUFLEN");
408.1651 +  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
408.1652 +				/* read HDRBUFLEN chunks with 4 byte slop */
408.1653 +  for (done = siz = 0, s = LOCAL->buf;
408.1654 +       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
408.1655 +       (read (LOCAL->fd,s,i) == i);
408.1656 +       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
408.1657 +    te = (t = s + i) - 12;	/* calculate end of fast scan */
408.1658 +				/* fast scan for CR */
408.1659 +    for (s = LOCAL->buf; s < te;)
408.1660 +      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
408.1661 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
408.1662 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
408.1663 +	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
408.1664 +	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
408.1665 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
408.1666 +	if (hdr) *hdr = LOCAL->buf;
408.1667 +	return ret;
408.1668 +      }
408.1669 +    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
408.1670 +      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
408.1671 +	  (*++s == '\012')) {
408.1672 +	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
408.1673 +	if (hdr) *hdr = LOCAL->buf;
408.1674 +	return ret;
408.1675 +      }
408.1676 +    if (i <= SLOP) break;	/* end of data */
408.1677 +				/* slide over last 4 bytes */
408.1678 +    memmove (LOCAL->buf,t - SLOP,SLOP);
408.1679 +    hdr = NIL;			/* can't return header this way */
408.1680 +  }
408.1681 +				/* not found: header consumes entire message */
408.1682 +  elt->private.msg.header.text.size = *size = elt->rfc822_size;
408.1683 +  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
408.1684 +  return ret;
408.1685 +}
408.1686 +
408.1687 +/* MBX mail rewrite mailbox
408.1688 + * Accepts: MAIL stream
408.1689 + *	    pointer to return reclaimed size
408.1690 + *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
408.1691 + * Returns: number of expunged messages
408.1692 + */
408.1693 +
408.1694 +unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
408.1695 +			   long flags)
408.1696 +{
408.1697 +  time_t tp[2];
408.1698 +  struct stat sbuf;
408.1699 +  off_t pos,ppos;
408.1700 +  int ld;
408.1701 +  unsigned long i,j,k,m,delta;
408.1702 +  unsigned long n = *reclaimed = 0;
408.1703 +  unsigned long recent = 0;
408.1704 +  char lock[MAILTMPLEN];
408.1705 +  MESSAGECACHE *elt;
408.1706 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
408.1707 +  /* The cretins who designed flock() created a window of vulnerability in
408.1708 +   * upgrading locks from shared to exclusive or downgrading from exclusive
408.1709 +   * to shared.  Rather than maintain the lock at shared status at a minimum,
408.1710 +   * flock() actually *releases* the former lock.  Obviously they never talked
408.1711 +   * to any database guys.  Fortunately, we have the parse/append permission
408.1712 +   * lock.  If we require this lock before going exclusive on the mailbox,
408.1713 +   * another process can not sneak in and steal the exclusive mailbox lock on
408.1714 +   * us, because it will block on trying to get parse/append permission first.
408.1715 +   */
408.1716 +				/* get parse/append permission */
408.1717 +  if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) {
408.1718 +    MM_LOG ("Unable to lock mailbox for rewrite",ERROR);
408.1719 +    return 0;
408.1720 +  }
408.1721 +  fstat (LOCAL->fd,&sbuf);	/* get current write time */
408.1722 +  if (LOCAL->filetime && !LOCAL->flagcheck &&
408.1723 +      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
408.1724 +  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
408.1725 +    unlockfd (ld,lock);		/* failed?? */
408.1726 +    return 0;
408.1727 +  }
408.1728 +  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
408.1729 +    LOCAL->filetime = sbuf.st_mtime;
408.1730 +    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
408.1731 +    LOCAL->flagcheck = NIL;
408.1732 +  }
408.1733 +
408.1734 +				/* get exclusive access */
408.1735 +  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
408.1736 +    MM_CRITICAL (stream);	/* go critical */
408.1737 +    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
408.1738 +				/* note if message not at predicted location */
408.1739 +      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
408.1740 +	ppos = elt->private.special.offset;
408.1741 +	*reclaimed += m;	/* note reclaimed message space */
408.1742 +	delta += m;		/* and as expunge delta  */
408.1743 +      }
408.1744 +				/* number of bytes to smash or preserve */
408.1745 +      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
408.1746 +				/* if need to expunge this message*/
408.1747 +      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
408.1748 +	delta += k;		/* number of bytes to delete */
408.1749 +	mail_expunged(stream,i);/* notify upper levels */
408.1750 +	n++;			/* count up one more expunged message */
408.1751 +      }
408.1752 +      else {			/* preserved message */
408.1753 +	i++;			/* count this message */
408.1754 +	if (elt->recent) ++recent;
408.1755 +	if (delta) {		/* moved, note first byte to preserve */
408.1756 +	  j = elt->private.special.offset;
408.1757 +	  do {			/* read from source position */
408.1758 +	    m = min (k,LOCAL->buflen);
408.1759 +	    lseek (LOCAL->fd,j,L_SET);
408.1760 +	    read (LOCAL->fd,LOCAL->buf,m);
408.1761 +	    pos = j - delta;	/* write to destination position */
408.1762 +	    while (T) {
408.1763 +	      lseek (LOCAL->fd,pos,L_SET);
408.1764 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
408.1765 +	      MM_NOTIFY (stream,strerror (errno),WARN);
408.1766 +	      MM_DISKERROR (stream,errno,T);
408.1767 +	    }
408.1768 +	    pos += m;		/* new position */
408.1769 +	    j += m;		/* next chunk, perhaps */
408.1770 +	  } while (k -= m);	/* until done */
408.1771 +				/* note the new address of this text */
408.1772 +	  elt->private.special.offset -= delta;
408.1773 +	}
408.1774 +				/* preserved but no deleted messages yet */
408.1775 +	else pos = elt->private.special.offset + k;
408.1776 +      }
408.1777 +    }
408.1778 +				/* deltaed file size match position? */
408.1779 +    if (m = (LOCAL->filesize -= delta) - pos) {
408.1780 +      *reclaimed += m;		/* probably an fEXPUNGED msg */
408.1781 +      LOCAL->filesize = pos;	/* set correct size */
408.1782 +    }
408.1783 +				/* truncate file after last message */
408.1784 +    ftruncate (LOCAL->fd,LOCAL->filesize);
408.1785 +    fsync (LOCAL->fd);		/* force disk update */
408.1786 +    MM_NOCRITICAL (stream);	/* release critical */
408.1787 +    (*bn) (BLOCK_FILELOCK,NIL);
408.1788 +    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
408.1789 +    (*bn) (BLOCK_NONE,NIL);
408.1790 +  }
408.1791 +
408.1792 +  else {			/* can't get exclusive */
408.1793 +    (*bn) (BLOCK_FILELOCK,NIL);
408.1794 +    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
408.1795 +    (*bn) (BLOCK_NONE,NIL);
408.1796 +				/* do hide-expunge when shared */
408.1797 +    if (flags) for (i = 1; i <= stream->nmsgs; ) {
408.1798 +      if (elt = mbx_elt (stream,i,T)) {
408.1799 +				/* make the message invisible */
408.1800 +	if (elt->deleted && ((flags > 0) || elt->sequence)) {
408.1801 +	  mbx_update_status (stream,elt->msgno,LONGT);
408.1802 +				/* notify upper levels */
408.1803 +	  mail_expunged (stream,i);
408.1804 +	  n++;			/* count up one more expunged message */
408.1805 +	}
408.1806 +	else {
408.1807 +	  i++;			/* preserved message */
408.1808 +	  if (elt->recent) ++recent;
408.1809 +	}
408.1810 +      }
408.1811 +      else n++;			/* count up one more expunged message */
408.1812 +    }
408.1813 +    fsync (LOCAL->fd);		/* force disk update */
408.1814 +  }
408.1815 +  fstat (LOCAL->fd,&sbuf);	/* get new write time */
408.1816 +  tp[1] = LOCAL->filetime = sbuf.st_mtime;
408.1817 +  tp[0] = time (0);		/* reset atime to now */
408.1818 +  utime (stream->mailbox,tp);
408.1819 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
408.1820 +				/* notify upper level of new mailbox size */
408.1821 +  mail_exists (stream,stream->nmsgs);
408.1822 +  mail_recent (stream,recent);
408.1823 +  return n;			/* return number of expunged messages */
408.1824 +}
408.1825 +
408.1826 +/* MBX mail lock for flag updating
408.1827 + * Accepts: stream
408.1828 + * Returns: T if successful, NIL if failure
408.1829 + */
408.1830 +
408.1831 +long mbx_flaglock (MAILSTREAM *stream)
408.1832 +{
408.1833 +  struct stat sbuf;
408.1834 +  unsigned long i;
408.1835 +  int ld;
408.1836 +  char lock[MAILTMPLEN];
408.1837 +				/* no-op if readonly or already locked */
408.1838 +  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
408.1839 +				/* lock now */
408.1840 +    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) return NIL;
408.1841 +    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
408.1842 +      if (LOCAL->filetime) {	/* know previous time? */
408.1843 +	fstat (LOCAL->fd,&sbuf);/* get current write time */
408.1844 +	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
408.1845 +	LOCAL->filetime = 0;	/* don't do this test for any other messages */
408.1846 +      }
408.1847 +      if (!mbx_parse (stream)) {/* parse mailbox */
408.1848 +	unlockfd (ld,lock);	/* shouldn't happen */
408.1849 +	return NIL;
408.1850 +      }
408.1851 +      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
408.1852 +	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
408.1853 +    }
408.1854 +    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
408.1855 +    memcpy (LOCAL->lock,lock,MAILTMPLEN);
408.1856 +  }
408.1857 +  return LONGT;
408.1858 +}
   409.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   409.2 +++ b/src/osdep/unix/mh.c	Mon Sep 14 15:17:45 2009 +0900
   409.3 @@ -0,0 +1,1283 @@
   409.4 +/* ========================================================================
   409.5 + * Copyright 1988-2007 University of Washington
   409.6 + *
   409.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   409.8 + * you may not use this file except in compliance with the License.
   409.9 + * You may obtain a copy of the License at
  409.10 + *
  409.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  409.12 + *
  409.13 + * 
  409.14 + * ========================================================================
  409.15 + */
  409.16 +
  409.17 +/*
  409.18 + * Program:	MH mail routines
  409.19 + *
  409.20 + * Author(s):	Mark Crispin
  409.21 + *		Networks and Distributed Computing
  409.22 + *		Computing & Communications
  409.23 + *		University of Washington
  409.24 + *		Administration Building, AG-44
  409.25 + *		Seattle, WA  98195
  409.26 + *		Internet: MRC@CAC.Washington.EDU
  409.27 + *
  409.28 + * Date:	23 February 1992
  409.29 + * Last Edited:	11 October 2007
  409.30 + */
  409.31 +
  409.32 +
  409.33 +#include <stdio.h>
  409.34 +#include <ctype.h>
  409.35 +#include <errno.h>
  409.36 +extern int errno;		/* just in case */
  409.37 +#include "mail.h"
  409.38 +#include "osdep.h"
  409.39 +#include <pwd.h>
  409.40 +#include <sys/stat.h>
  409.41 +#include <sys/time.h>
  409.42 +#include "misc.h"
  409.43 +#include "dummy.h"
  409.44 +#include "fdstring.h"
  409.45 +
  409.46 +
  409.47 +/* Build parameters */
  409.48 +
  409.49 +#define MHINBOX "#mhinbox"	/* corresponds to namespace in env_unix.c */
  409.50 +#define MHINBOXDIR "inbox"
  409.51 +#define MHPROFILE ".mh_profile"
  409.52 +#define MHCOMMA ','
  409.53 +#define MHSEQUENCE ".mh_sequence"
  409.54 +#define MHSEQUENCES ".mh_sequences"
  409.55 +#define MHPATH "Mail"
  409.56 +
  409.57 +
  409.58 +/* mh_load_message() flags */
  409.59 +
  409.60 +#define MLM_HEADER 0x1		/* load message text */
  409.61 +#define MLM_TEXT 0x2		/* load message text */
  409.62 +
  409.63 +/* MH I/O stream local data */
  409.64 +	
  409.65 +typedef struct mh_local {
  409.66 +  char *dir;			/* spool directory name */
  409.67 +  unsigned char buf[CHUNKSIZE];	/* temporary buffer */
  409.68 +  unsigned long cachedtexts;	/* total size of all cached texts */
  409.69 +  time_t scantime;		/* last time directory scanned */
  409.70 +} MHLOCAL;
  409.71 +
  409.72 +
  409.73 +/* Convenient access to local data */
  409.74 +
  409.75 +#define LOCAL ((MHLOCAL *) stream->local)
  409.76 +
  409.77 +
  409.78 +/* Function prototypes */
  409.79 +
  409.80 +DRIVER *mh_valid (char *name);
  409.81 +int mh_isvalid (char *name,char *tmp,long synonly);
  409.82 +int mh_namevalid (char *name);
  409.83 +char *mh_path (char *tmp);
  409.84 +void *mh_parameters (long function,void *value);
  409.85 +long mh_dirfmttest (char *name);
  409.86 +void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  409.87 +void mh_list (MAILSTREAM *stream,char *ref,char *pat);
  409.88 +void mh_lsub (MAILSTREAM *stream,char *ref,char *pat);
  409.89 +void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level);
  409.90 +long mh_subscribe (MAILSTREAM *stream,char *mailbox);
  409.91 +long mh_unsubscribe (MAILSTREAM *stream,char *mailbox);
  409.92 +long mh_create (MAILSTREAM *stream,char *mailbox);
  409.93 +long mh_delete (MAILSTREAM *stream,char *mailbox);
  409.94 +long mh_rename (MAILSTREAM *stream,char *old,char *newname);
  409.95 +MAILSTREAM *mh_open (MAILSTREAM *stream);
  409.96 +void mh_close (MAILSTREAM *stream,long options);
  409.97 +void mh_fast (MAILSTREAM *stream,char *sequence,long flags);
  409.98 +void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
  409.99 +char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 409.100 +		 long flags);
 409.101 +long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 409.102 +long mh_ping (MAILSTREAM *stream);
 409.103 +void mh_check (MAILSTREAM *stream);
 409.104 +long mh_expunge (MAILSTREAM *stream,char *sequence,long options);
 409.105 +long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
 409.106 +	      long options);
 409.107 +long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 409.108 +
 409.109 +int mh_select (struct direct *name);
 409.110 +int mh_numsort (const void *d1,const void *d2);
 409.111 +char *mh_file (char *dst,char *name);
 409.112 +long mh_canonicalize (char *pattern,char *ref,char *pat);
 409.113 +void mh_setdate (char *file,MESSAGECACHE *elt);
 409.114 +
 409.115 +/* MH mail routines */
 409.116 +
 409.117 +
 409.118 +/* Driver dispatch used by MAIL */
 409.119 +
 409.120 +DRIVER mhdriver = {
 409.121 +  "mh",				/* driver name */
 409.122 +				/* driver flags */
 409.123 +  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY|DR_DIRFMT,
 409.124 +  (DRIVER *) NIL,		/* next driver */
 409.125 +  mh_valid,			/* mailbox is valid for us */
 409.126 +  mh_parameters,		/* manipulate parameters */
 409.127 +  mh_scan,			/* scan mailboxes */
 409.128 +  mh_list,			/* find mailboxes */
 409.129 +  mh_lsub,			/* find subscribed mailboxes */
 409.130 +  mh_subscribe,			/* subscribe to mailbox */
 409.131 +  mh_unsubscribe,		/* unsubscribe from mailbox */
 409.132 +  mh_create,			/* create mailbox */
 409.133 +  mh_delete,			/* delete mailbox */
 409.134 +  mh_rename,			/* rename mailbox */
 409.135 +  mail_status_default,		/* status of mailbox */
 409.136 +  mh_open,			/* open mailbox */
 409.137 +  mh_close,			/* close mailbox */
 409.138 +  mh_fast,			/* fetch message "fast" attributes */
 409.139 +  NIL,				/* fetch message flags */
 409.140 +  NIL,				/* fetch overview */
 409.141 +  NIL,				/* fetch message envelopes */
 409.142 +  mh_header,			/* fetch message header */
 409.143 +  mh_text,			/* fetch message body */
 409.144 +  NIL,				/* fetch partial message text */
 409.145 +  NIL,				/* unique identifier */
 409.146 +  NIL,				/* message number */
 409.147 +  NIL,				/* modify flags */
 409.148 +  NIL,				/* per-message modify flags */
 409.149 +  NIL,				/* search for message based on criteria */
 409.150 +  NIL,				/* sort messages */
 409.151 +  NIL,				/* thread messages */
 409.152 +  mh_ping,			/* ping mailbox to see if still alive */
 409.153 +  mh_check,			/* check for new messages */
 409.154 +  mh_expunge,			/* expunge deleted messages */
 409.155 +  mh_copy,			/* copy messages to another mailbox */
 409.156 +  mh_append,			/* append string message to mailbox */
 409.157 +  NIL				/* garbage collect stream */
 409.158 +};
 409.159 +
 409.160 +				/* prototype stream */
 409.161 +MAILSTREAM mhproto = {&mhdriver};
 409.162 +
 409.163 +
 409.164 +static char *mh_profile = NIL;	/* holds MH profile */
 409.165 +static char *mh_pathname = NIL;	/* holds MH path name */
 409.166 +static long mh_once = 0;	/* already snarled once */
 409.167 +static long mh_allow_inbox =NIL;/* allow INBOX as well as MHINBOX */
 409.168 +
 409.169 +/* MH mail validate mailbox
 409.170 + * Accepts: mailbox name
 409.171 + * Returns: our driver if name is valid, NIL otherwise
 409.172 + */
 409.173 +
 409.174 +DRIVER *mh_valid (char *name)
 409.175 +{
 409.176 +  char tmp[MAILTMPLEN];
 409.177 +  return mh_isvalid (name,tmp,T) ? &mhdriver : NIL;
 409.178 +}
 409.179 +
 409.180 +
 409.181 +/* MH mail test for valid mailbox
 409.182 + * Accepts: mailbox name
 409.183 + *	    temporary buffer to use
 409.184 + *	    syntax only test flag
 409.185 + * Returns: T if valid, NIL otherwise
 409.186 + */
 409.187 +
 409.188 +int mh_isvalid (char *name,char *tmp,long synonly)
 409.189 +{
 409.190 +  struct stat sbuf;
 409.191 +  char *s,*t,altname[MAILTMPLEN];
 409.192 +  unsigned long i;
 409.193 +  int ret = NIL;
 409.194 +  errno = NIL;			/* zap any error condition */
 409.195 +				/* mh name? */
 409.196 +  if ((mh_allow_inbox && !compare_cstring (name,"INBOX")) ||
 409.197 +      !compare_cstring (name,MHINBOX) ||
 409.198 +      ((name[0] == '#') && ((name[1] == 'm') || (name[1] == 'M')) &&
 409.199 +       ((name[2] == 'h') || (name[2] == 'H')) && (name[3] == '/') && name[4])){
 409.200 +    if (mh_path (tmp))		/* validate name if INBOX or not synonly */
 409.201 +      ret = (synonly && compare_cstring (name,"INBOX")) ?
 409.202 +	T : ((stat (mh_file (tmp,name),&sbuf) == 0) &&
 409.203 +	     (sbuf.st_mode & S_IFMT) == S_IFDIR);
 409.204 +    else if (!mh_once++) {	/* only report error once */
 409.205 +      sprintf (tmp,"%.900s not found, mh format names disabled",mh_profile);
 409.206 +      mm_log (tmp,WARN);
 409.207 +    }
 409.208 +  }
 409.209 +				/* see if non-NS name within mh hierarchy */
 409.210 +  else if ((name[0] != '#') && (s = mh_path (tmp)) && (i = strlen (s)) &&
 409.211 +	   (t = mailboxfile (tmp,name)) && !strncmp (t,s,i) &&
 409.212 +	   (tmp[i] == '/') && tmp[i+1]) {
 409.213 +    sprintf (altname,"#mh%.900s",tmp+i);
 409.214 +				/* can't do synonly here! */
 409.215 +    ret = mh_isvalid (altname,tmp,NIL);
 409.216 +  }
 409.217 +  else errno = EINVAL;		/* bogus name */
 409.218 +  return ret;
 409.219 +}
 409.220 +
 409.221 +/* MH mail test for valid mailbox
 409.222 + * Accepts: mailbox name
 409.223 + * Returns: T if valid, NIL otherwise
 409.224 + */
 409.225 +
 409.226 +int mh_namevalid (char *name)
 409.227 +{
 409.228 +  char *s;
 409.229 +  if (name[0] == '#' && (name[1] == 'm' || name[1] == 'M') &&
 409.230 +      (name[2] == 'h' || name[2] == 'H') && name[3] == '/')
 409.231 +    for (s = name; s && *s;) {	/* make sure no all-digit nodes */
 409.232 +      if (isdigit (*s)) s++;	/* digit, check this node further... */
 409.233 +      else if (*s == '/') break;/* all digit node, barf */
 409.234 +				/* non-digit, skip to next node or return */
 409.235 +      else if (!((s = strchr (s+1,'/')) && *++s)) return T;
 409.236 +    }
 409.237 +  return NIL;			/* all numeric or empty node */
 409.238 +}
 409.239 +
 409.240 +/* Return MH path
 409.241 + * Accepts: temporary buffer
 409.242 + * Returns: MH path or NIL if MH disabled
 409.243 + */
 409.244 +
 409.245 +char *mh_path (char *tmp)
 409.246 +{
 409.247 +  char *s,*t,*v,*r;
 409.248 +  int fd;
 409.249 +  struct stat sbuf;
 409.250 +  if (!mh_profile) {		/* build mh_profile and mh_pathname now */
 409.251 +    sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE);
 409.252 +    if ((fd = open (mh_profile = cpystr (tmp),O_RDONLY,NIL)) >= 0) {
 409.253 +      fstat (fd,&sbuf);		/* yes, get size and read file */
 409.254 +      read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size);
 409.255 +      close (fd);		/* don't need the file any more */
 409.256 +      t[sbuf.st_size] = '\0';	/* tie it off */
 409.257 +				/* parse profile file */
 409.258 +      for (s = strtok_r (t,"\r\n",&r); s && *s; s = strtok_r (NIL,"\r\n",&r)) {
 409.259 +				/* found space in line? */
 409.260 +	if (v = strpbrk (s," \t")) {
 409.261 +	  *v++ = '\0';		/* tie off, is keyword "Path:"? */
 409.262 +	  if (!compare_cstring (s,"Path:")) {
 409.263 +				/* skip whitespace */
 409.264 +	    while ((*v == ' ') || (*v == '\t')) ++v;
 409.265 +				/* absolute path? */
 409.266 +	    if (*v == '/') s = v;
 409.267 +	    else sprintf (s = tmp,"%s/%s",myhomedir (),v);
 409.268 +				/* copy name */
 409.269 +	    mh_pathname = cpystr (s);
 409.270 +	    break;		/* don't need to look at rest of file */
 409.271 +	  }
 409.272 +	}
 409.273 +      }
 409.274 +      fs_give ((void **) &t);	/* flush profile text */
 409.275 +      if (!mh_pathname) {	/* default path if not in the profile */
 409.276 +	sprintf (tmp,"%s/%s",myhomedir (),MHPATH);
 409.277 +	mh_pathname = cpystr (tmp);
 409.278 +      }
 409.279 +    }
 409.280 +  }
 409.281 +  return mh_pathname;
 409.282 +}
 409.283 +
 409.284 +/* MH manipulate driver parameters
 409.285 + * Accepts: function code
 409.286 + *	    function-dependent value
 409.287 + * Returns: function-dependent return value
 409.288 + */
 409.289 +
 409.290 +void *mh_parameters (long function,void *value)
 409.291 +{
 409.292 +  void *ret = NIL;
 409.293 +  switch ((int) function) {
 409.294 +  case GET_INBOXPATH:
 409.295 +    if (value) ret = mh_file ((char *) value,"INBOX");
 409.296 +    break;
 409.297 +  case GET_DIRFMTTEST:
 409.298 +    ret = (void *) mh_dirfmttest;
 409.299 +    break;
 409.300 +  case SET_MHPROFILE:
 409.301 +    if (mh_profile) fs_give ((void **) &mh_profile);
 409.302 +    mh_profile = cpystr ((char *) value);
 409.303 +  case GET_MHPROFILE:
 409.304 +    ret = (void *) mh_profile;
 409.305 +    break;
 409.306 +  case SET_MHPATH:
 409.307 +    if (mh_pathname) fs_give ((void **) &mh_pathname);
 409.308 +    mh_pathname = cpystr ((char *) value);
 409.309 +  case GET_MHPATH:
 409.310 +    ret = (void *) mh_pathname;
 409.311 +    break;
 409.312 +  case SET_MHALLOWINBOX:
 409.313 +    mh_allow_inbox = value ? T : NIL;
 409.314 +  case GET_MHALLOWINBOX:
 409.315 +    ret = (void *) (mh_allow_inbox ? VOIDT : NIL);
 409.316 +  }
 409.317 +  return ret;
 409.318 +}
 409.319 +
 409.320 +
 409.321 +/* MH test for directory format internal node
 409.322 + * Accepts: candidate node name
 409.323 + * Returns: T if internal name, NIL otherwise
 409.324 + */
 409.325 +
 409.326 +long mh_dirfmttest (char *s)
 409.327 +{
 409.328 +  int c;
 409.329 +				/* sequence(s) file is an internal name */
 409.330 +  if (strcmp (s,MHSEQUENCE) && strcmp (s,MHSEQUENCES)) {
 409.331 +    if (*s == MHCOMMA) ++s;	/* else comma + all numeric name */
 409.332 +				/* success if all-numeric */
 409.333 +    while (c = *s++) if (!isdigit (c)) return NIL;
 409.334 +  }
 409.335 +  return LONGT;
 409.336 +}
 409.337 +
 409.338 +/* MH scan mailboxes
 409.339 + * Accepts: mail stream
 409.340 + *	    reference
 409.341 + *	    pattern to search
 409.342 + *	    string to scan
 409.343 + */
 409.344 +
 409.345 +void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 409.346 +{
 409.347 +  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
 409.348 +  long i = 0;
 409.349 +  if (!pat || !*pat) {		/* empty pattern? */
 409.350 +    if (mh_canonicalize (test,ref,"*")) {
 409.351 +				/* tie off name at root */
 409.352 +      if (s = strchr (test,'/')) *++s = '\0';
 409.353 +      else test[0] = '\0';
 409.354 +      mm_list (stream,'/',test,LATT_NOSELECT);
 409.355 +    }
 409.356 +  }
 409.357 +				/* get canonical form of name */
 409.358 +  else if (mh_canonicalize (test,ref,pat)) {
 409.359 +    if (contents) {		/* maybe I'll implement this someday */
 409.360 +      mm_log ("Scan not valid for mh mailboxes",ERROR);
 409.361 +      return;
 409.362 +    }
 409.363 +    if (test[3] == '/') {	/* looking down levels? */
 409.364 +				/* yes, found any wildcards? */
 409.365 +      if (s = strpbrk (test,"%*")) {
 409.366 +				/* yes, copy name up to that point */
 409.367 +	strncpy (file,test+4,i = s - (test+4));
 409.368 +	file[i] = '\0';		/* tie off */
 409.369 +      }
 409.370 +      else strcpy (file,test+4);/* use just that name then */
 409.371 +				/* find directory name */
 409.372 +      if (s = strrchr (file,'/')) {
 409.373 +	*s = '\0';		/* found, tie off at that point */
 409.374 +	s = file;
 409.375 +      }
 409.376 +				/* do the work */
 409.377 +      mh_list_work (stream,s,test,0);
 409.378 +    }
 409.379 +				/* always an INBOX */
 409.380 +    if (!compare_cstring (test,MHINBOX))
 409.381 +      mm_list (stream,NIL,MHINBOX,LATT_NOINFERIORS);
 409.382 +  }
 409.383 +}
 409.384 +
 409.385 +/* MH list mailboxes
 409.386 + * Accepts: mail stream
 409.387 + *	    reference
 409.388 + *	    pattern to search
 409.389 + */
 409.390 +
 409.391 +void mh_list (MAILSTREAM *stream,char *ref,char *pat)
 409.392 +{
 409.393 +  mh_scan (stream,ref,pat,NIL);
 409.394 +}
 409.395 +
 409.396 +
 409.397 +/* MH list subscribed mailboxes
 409.398 + * Accepts: mail stream
 409.399 + *	    reference
 409.400 + *	    pattern to search
 409.401 + */
 409.402 +
 409.403 +void mh_lsub (MAILSTREAM *stream,char *ref,char *pat)
 409.404 +{
 409.405 +  void *sdb = NIL;
 409.406 +  char *s,test[MAILTMPLEN];
 409.407 +				/* get canonical form of name */
 409.408 +  if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
 409.409 +    do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
 409.410 +    while (s = sm_read (&sdb)); /* until no more subscriptions */
 409.411 +  }
 409.412 +}
 409.413 +
 409.414 +/* MH list mailboxes worker routine
 409.415 + * Accepts: mail stream
 409.416 + *	    directory name to search
 409.417 + *	    search pattern
 409.418 + *	    search level
 409.419 + */
 409.420 +
 409.421 +void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
 409.422 +{
 409.423 +  DIR *dp;
 409.424 +  struct direct *d;
 409.425 +  struct stat sbuf;
 409.426 +  char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN];
 409.427 +				/* build MH name to search */
 409.428 +  if (dir) sprintf (name,"#mh/%s/",dir);
 409.429 +  else strcpy (name,"#mh/");
 409.430 +				/* make directory name, punt if bogus */
 409.431 +  if (!mh_file (curdir,name)) return;
 409.432 +  cp = curdir + strlen (curdir);/* end of directory name */
 409.433 +  np = name + strlen (name);	/* end of MH name */
 409.434 +  if (dp = opendir (curdir)) {	/* open directory */
 409.435 +    while (d = readdir (dp))	/* scan, ignore . and numeric names */
 409.436 +      if ((d->d_name[0] != '.') && !mh_select (d)) {
 409.437 +	strcpy (cp,d->d_name);	/* make directory name */
 409.438 +	if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
 409.439 +	  strcpy (np,d->d_name);/* make mh name of directory name */
 409.440 +				/* yes, an MH name if full match */
 409.441 +	  if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL);
 409.442 +				/* check if should recurse */
 409.443 +	  if (dmatch (name,pat,'/') &&
 409.444 +	      (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
 409.445 +	    mh_list_work (stream,name+4,pat,level+1);
 409.446 +	}
 409.447 +      }
 409.448 +    closedir (dp);		/* all done, flush directory */
 409.449 +  }
 409.450 +}
 409.451 +
 409.452 +/* MH mail subscribe to mailbox
 409.453 + * Accepts: mail stream
 409.454 + *	    mailbox to add to subscription list
 409.455 + * Returns: T on success, NIL on failure
 409.456 + */
 409.457 +
 409.458 +long mh_subscribe (MAILSTREAM *stream,char *mailbox)
 409.459 +{
 409.460 +  return sm_subscribe (mailbox);
 409.461 +}
 409.462 +
 409.463 +
 409.464 +/* MH mail unsubscribe to mailbox
 409.465 + * Accepts: mail stream
 409.466 + *	    mailbox to delete from subscription list
 409.467 + * Returns: T on success, NIL on failure
 409.468 + */
 409.469 +
 409.470 +long mh_unsubscribe (MAILSTREAM *stream,char *mailbox)
 409.471 +{
 409.472 +  return sm_unsubscribe (mailbox);
 409.473 +}
 409.474 +
 409.475 +/* MH mail create mailbox
 409.476 + * Accepts: mail stream
 409.477 + *	    mailbox name to create
 409.478 + * Returns: T on success, NIL on failure
 409.479 + */
 409.480 +
 409.481 +long mh_create (MAILSTREAM *stream,char *mailbox)
 409.482 +{
 409.483 +  char tmp[MAILTMPLEN];
 409.484 +  if (!mh_namevalid (mailbox))	/* validate name */
 409.485 +    sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox);
 409.486 +				/* must not already exist */
 409.487 +  else if (mh_isvalid (mailbox,tmp,NIL))
 409.488 +    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
 409.489 +  else if (!mh_path (tmp)) return NIL;
 409.490 +				/* try to make it */
 409.491 +  else if (!(mh_file (tmp,mailbox) &&
 409.492 +	     dummy_create_path (stream,strcat (tmp,"/"),
 409.493 +				get_dir_protection (mailbox))))
 409.494 +    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
 409.495 +  else return LONGT;		/* success */
 409.496 +  mm_log (tmp,ERROR);
 409.497 +  return NIL;
 409.498 +}
 409.499 +
 409.500 +/* MH mail delete mailbox
 409.501 + *	    mailbox name to delete
 409.502 + * Returns: T on success, NIL on failure
 409.503 + */
 409.504 +
 409.505 +long mh_delete (MAILSTREAM *stream,char *mailbox)
 409.506 +{
 409.507 +  DIR *dirp;
 409.508 +  struct direct *d;
 409.509 +  int i;
 409.510 +  char tmp[MAILTMPLEN];
 409.511 +				/* is mailbox valid? */
 409.512 +  if (!mh_isvalid (mailbox,tmp,NIL)) {
 409.513 +    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
 409.514 +    mm_log (tmp,ERROR);
 409.515 +    return NIL;
 409.516 +  }
 409.517 +				/* get name of directory */
 409.518 +  i = strlen (mh_file (tmp,mailbox));
 409.519 +  if (dirp = opendir (tmp)) {	/* open directory */
 409.520 +    tmp[i++] = '/';		/* now apply trailing delimiter */
 409.521 +				/* massacre all mh owned files */
 409.522 +    while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) {
 409.523 +      strcpy (tmp + i,d->d_name);
 409.524 +      unlink (tmp);		/* sayonara */
 409.525 +    }
 409.526 +    closedir (dirp);		/* flush directory */
 409.527 +  }
 409.528 +				/* try to remove the directory */
 409.529 +  if (rmdir (mh_file (tmp,mailbox))) {
 409.530 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno));
 409.531 +    mm_log (tmp,WARN);
 409.532 +  }
 409.533 +  return T;			/* return success */
 409.534 +}
 409.535 +
 409.536 +/* MH mail rename mailbox
 409.537 + * Accepts: MH mail stream
 409.538 + *	    old mailbox name
 409.539 + *	    new mailbox name
 409.540 + * Returns: T on success, NIL on failure
 409.541 + */
 409.542 +
 409.543 +long mh_rename (MAILSTREAM *stream,char *old,char *newname)
 409.544 +{
 409.545 +  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
 409.546 +  struct stat sbuf;
 409.547 +				/* old mailbox name must be valid */
 409.548 +  if (!mh_isvalid (old,tmp,NIL))
 409.549 +    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
 409.550 +  else if (!mh_namevalid (newname))
 409.551 +    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name",
 409.552 +	     newname);
 409.553 +				/* new mailbox name must not be valid */
 409.554 +  else if (mh_isvalid (newname,tmp,NIL))
 409.555 +    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
 409.556 +	     newname);
 409.557 +				/* success if can rename the directory */
 409.558 +  else {			/* found superior to destination name? */
 409.559 +    if (s = strrchr (mh_file (tmp1,newname),'/')) {
 409.560 +      c = *++s;			/* remember first character of inferior */
 409.561 +      *s = '\0';		/* tie off to get just superior */
 409.562 +				/* name doesn't exist, create it */
 409.563 +      if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 409.564 +	  !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
 409.565 +	return NIL;
 409.566 +      *s = c;			/* restore full name */
 409.567 +    }
 409.568 +    if (!rename (mh_file (tmp,old),tmp1)) return T;
 409.569 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
 409.570 +	     old,newname,strerror (errno));
 409.571 +  }
 409.572 +  mm_log (tmp,ERROR);		/* something failed */
 409.573 +  return NIL;
 409.574 +}
 409.575 +
 409.576 +/* MH mail open
 409.577 + * Accepts: stream to open
 409.578 + * Returns: stream on success, NIL on failure
 409.579 + */
 409.580 +
 409.581 +MAILSTREAM *mh_open (MAILSTREAM *stream)
 409.582 +{
 409.583 +  char tmp[MAILTMPLEN];
 409.584 +  if (!stream) return &mhproto;	/* return prototype for OP_PROTOTYPE call */
 409.585 +  if (stream->local) fatal ("mh recycle stream");
 409.586 +  stream->local = fs_get (sizeof (MHLOCAL));
 409.587 +  /* INBOXness is one of the following:
 409.588 +   * #mhinbox (case-independent)
 409.589 +   * #mh/inbox (mh is case-independent, inbox is case-dependent)
 409.590 +   * INBOX (case-independent
 409.591 +   */		
 409.592 +  stream->inbox =		/* note if an INBOX or not */
 409.593 +    (!compare_cstring (stream->mailbox,MHINBOX) ||
 409.594 +     ((stream->mailbox[0] == '#') &&
 409.595 +      ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) &&
 409.596 +      ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) &&
 409.597 +      (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) ||
 409.598 +     !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL;
 409.599 +  mh_file (tmp,stream->mailbox);/* get directory name */
 409.600 +  LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
 409.601 +  LOCAL->scantime = 0;		/* not scanned yet */
 409.602 +  LOCAL->cachedtexts = 0;	/* no cached texts */
 409.603 +  stream->sequence++;		/* bump sequence number */
 409.604 +				/* parse mailbox */
 409.605 +  stream->nmsgs = stream->recent = 0;
 409.606 +  if (!mh_ping (stream)) return NIL;
 409.607 +  if (!(stream->nmsgs || stream->silent))
 409.608 +    mm_log ("Mailbox is empty",(long) NIL);
 409.609 +  return stream;		/* return stream to caller */
 409.610 +}
 409.611 +
 409.612 +/* MH mail close
 409.613 + * Accepts: MAIL stream
 409.614 + *	    close options
 409.615 + */
 409.616 +
 409.617 +void mh_close (MAILSTREAM *stream,long options)
 409.618 +{
 409.619 +  if (LOCAL) {			/* only if a file is open */
 409.620 +    int silent = stream->silent;
 409.621 +    stream->silent = T;		/* note this stream is dying */
 409.622 +    if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL);
 409.623 +    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
 409.624 +				/* nuke the local data */
 409.625 +    fs_give ((void **) &stream->local);
 409.626 +    stream->dtb = NIL;		/* log out the DTB */
 409.627 +    stream->silent = silent;	/* reset silent state */
 409.628 +  }
 409.629 +}
 409.630 +
 409.631 +
 409.632 +/* MH mail fetch fast information
 409.633 + * Accepts: MAIL stream
 409.634 + *	    sequence
 409.635 + *	    option flags
 409.636 + */
 409.637 +
 409.638 +void mh_fast (MAILSTREAM *stream,char *sequence,long flags)
 409.639 +{
 409.640 +  MESSAGECACHE *elt;
 409.641 +  unsigned long i;
 409.642 +				/* set up metadata for all messages */
 409.643 +  if (stream && LOCAL && ((flags & FT_UID) ?
 409.644 +			  mail_uid_sequence (stream,sequence) :
 409.645 +			  mail_sequence (stream,sequence)))
 409.646 +    for (i = 1; i <= stream->nmsgs; i++)
 409.647 +      if ((elt = mail_elt (stream,i))->sequence &&
 409.648 +	  !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL);
 409.649 +}
 409.650 +
 409.651 +/* MH load message into cache
 409.652 + * Accepts: MAIL stream
 409.653 + *	    message #
 409.654 + *	    option flags
 409.655 + */
 409.656 +
 409.657 +void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
 409.658 +{
 409.659 +  unsigned long i,j,nlseen;
 409.660 +  int fd;
 409.661 +  unsigned char c,*t;
 409.662 +  struct stat sbuf;
 409.663 +  MESSAGECACHE *elt;
 409.664 +  FDDATA d;
 409.665 +  STRING bs;
 409.666 +  elt = mail_elt (stream,msgno);/* get elt */
 409.667 +				/* build message file name */
 409.668 +  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
 409.669 +				/* anything we need not currently cached? */
 409.670 +  if ((!elt->day || !elt->rfc822_size ||
 409.671 +       ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
 409.672 +       ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) &&
 409.673 +      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
 409.674 +    fstat (fd,&sbuf);		/* get file metadata */
 409.675 +    d.fd = fd;			/* set up file descriptor */
 409.676 +    d.pos = 0;			/* start of file */
 409.677 +    d.chunk = LOCAL->buf;
 409.678 +    d.chunksize = CHUNKSIZE;
 409.679 +    INIT (&bs,fd_string,&d,sbuf.st_size);
 409.680 +    if (!elt->day) {		/* set internaldate to file date */
 409.681 +      struct tm *tm = gmtime (&sbuf.st_mtime);
 409.682 +      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
 409.683 +      elt->year = tm->tm_year + 1900 - BASEYEAR;
 409.684 +      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
 409.685 +      elt->seconds = tm->tm_sec;
 409.686 +      elt->zhours = 0; elt->zminutes = 0;
 409.687 +    }
 409.688 +
 409.689 +    if (!elt->rfc822_size) {	/* know message size yet? */
 409.690 +      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
 409.691 +      case '\015':		/* unlikely carriage return */
 409.692 +	if (!j || (CHR (&bs) != '\012')) {
 409.693 +	  i++;			/* ugh, raw CR */
 409.694 +	  nlseen = NIL;
 409.695 +	  break;
 409.696 +	}
 409.697 +	SNX (&bs);		/* eat the line feed, drop in */
 409.698 +	--j;
 409.699 +      case '\012':		/* line feed? */
 409.700 +	i += 2;			/* count a CRLF */
 409.701 +				/* header size known yet? */
 409.702 +	if (!elt->private.msg.header.text.size && nlseen) {
 409.703 +				/* note position in file */
 409.704 +	  elt->private.special.text.size = GETPOS (&bs);
 409.705 +				/* and CRLF-adjusted size */
 409.706 +	  elt->private.msg.header.text.size = i;
 409.707 +	}
 409.708 +	nlseen = T;		/* note newline seen */
 409.709 +	break;
 409.710 +      default:			/* ordinary chararacter */
 409.711 +	i++;
 409.712 +	nlseen = NIL;
 409.713 +	break;
 409.714 +      }
 409.715 +      SETPOS (&bs,0);		/* restore old position */
 409.716 +      elt->rfc822_size = i;	/* note that we have size now */
 409.717 +				/* header is entire message if no delimiter */
 409.718 +      if (!elt->private.msg.header.text.size)
 409.719 +	elt->private.msg.header.text.size = elt->rfc822_size;
 409.720 +				/* text is remainder of message */
 409.721 +      elt->private.msg.text.text.size =
 409.722 +	elt->rfc822_size - elt->private.msg.header.text.size;
 409.723 +    }
 409.724 +				/* need to load cache with message data? */
 409.725 +    if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
 409.726 +	((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) {
 409.727 +				/* purge cache if too big */
 409.728 +      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
 409.729 +				/* just can't keep that much */
 409.730 +	mail_gc (stream,GC_TEXTS);
 409.731 +	LOCAL->cachedtexts = 0;
 409.732 +      }
 409.733 +
 409.734 +      if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) {
 409.735 +	t = elt->private.msg.header.text.data =
 409.736 +	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
 409.737 +	LOCAL->cachedtexts += elt->private.msg.header.text.size;
 409.738 +				/* read in message header */
 409.739 +	for (i = 0; i < elt->private.msg.header.text.size; i++)
 409.740 +	  switch (c = SNX (&bs)) {
 409.741 +	  case '\015':		/* unlikely carriage return */
 409.742 +	    *t++ = c;
 409.743 +	    if ((CHR (&bs) == '\012')) {
 409.744 +	      *t++ = SNX (&bs);
 409.745 +	      i++;
 409.746 +	    }
 409.747 +	    break;
 409.748 +	  case '\012':		/* line feed? */
 409.749 +	    *t++ = '\015';
 409.750 +	    i++;
 409.751 +	  default:
 409.752 +	    *t++ = c;
 409.753 +	    break;
 409.754 +	  }
 409.755 +	*t = '\0';		/* tie off string */
 409.756 +	if ((t - elt->private.msg.header.text.data) !=
 409.757 +	    elt->private.msg.header.text.size) fatal ("mh hdr size mismatch");
 409.758 +      }
 409.759 +      if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) {
 409.760 +	t = elt->private.msg.text.text.data =
 409.761 +	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
 409.762 +	SETPOS (&bs,elt->private.special.text.size);
 409.763 +	LOCAL->cachedtexts += elt->private.msg.text.text.size;
 409.764 +				/* read in message text */
 409.765 +	for (i = 0; i < elt->private.msg.text.text.size; i++)
 409.766 +	  switch (c = SNX (&bs)) {
 409.767 +	  case '\015':		/* unlikely carriage return */
 409.768 +	    *t++ = c;
 409.769 +	    if ((CHR (&bs) == '\012')) {
 409.770 +	      *t++ = SNX (&bs);
 409.771 +	      i++;
 409.772 +	    }
 409.773 +	    break;
 409.774 +	  case '\012':		/* line feed? */
 409.775 +	    *t++ = '\015';
 409.776 +	    i++;
 409.777 +	  default:
 409.778 +	    *t++ = c;
 409.779 +	    break;
 409.780 +	  }
 409.781 +	*t = '\0';		/* tie off string */
 409.782 +	if ((t - elt->private.msg.text.text.data) !=
 409.783 +	    elt->private.msg.text.text.size) fatal ("mh txt size mismatch");
 409.784 +      }
 409.785 +    }
 409.786 +    close (fd);			/* flush message file */
 409.787 +  }
 409.788 +}
 409.789 +
 409.790 +/* MH mail fetch message header
 409.791 + * Accepts: MAIL stream
 409.792 + *	    message # to fetch
 409.793 + *	    pointer to returned header text length
 409.794 + *	    option flags
 409.795 + * Returns: message header in RFC822 format
 409.796 + */
 409.797 +
 409.798 +char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 409.799 +		 long flags)
 409.800 +{
 409.801 +  MESSAGECACHE *elt;
 409.802 +  *length = 0;			/* default to empty */
 409.803 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 409.804 +  elt = mail_elt (stream,msgno);/* get elt */
 409.805 +  if (!elt->private.msg.header.text.data)
 409.806 +    mh_load_message (stream,msgno,MLM_HEADER);
 409.807 +  *length = elt->private.msg.header.text.size;
 409.808 +  return (char *) elt->private.msg.header.text.data;
 409.809 +}
 409.810 +
 409.811 +
 409.812 +/* MH mail fetch message text (body only)
 409.813 + * Accepts: MAIL stream
 409.814 + *	    message # to fetch
 409.815 + *	    pointer to returned stringstruct
 409.816 + *	    option flags
 409.817 + * Returns: T on success, NIL on failure
 409.818 + */
 409.819 +
 409.820 +long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 409.821 +{
 409.822 +  MESSAGECACHE *elt;
 409.823 +				/* UID call "impossible" */
 409.824 +  if (flags & FT_UID) return NIL;
 409.825 +  elt = mail_elt (stream,msgno);/* get elt */
 409.826 +				/* snarf message if don't have it yet */
 409.827 +  if (!elt->private.msg.text.text.data) {
 409.828 +    mh_load_message (stream,msgno,MLM_TEXT);
 409.829 +    if (!elt->private.msg.text.text.data) return NIL;
 409.830 +  }
 409.831 +  if (!(flags & FT_PEEK)) {	/* mark as seen */
 409.832 +    mail_elt (stream,msgno)->seen = T;
 409.833 +    mm_flags (stream,msgno);
 409.834 +  }
 409.835 +  INIT (bs,mail_string,elt->private.msg.text.text.data,
 409.836 +	elt->private.msg.text.text.size);
 409.837 +  return T;
 409.838 +}
 409.839 +
 409.840 +/* MH mail ping mailbox
 409.841 + * Accepts: MAIL stream
 409.842 + * Returns: T if stream alive, else NIL
 409.843 + */
 409.844 +
 409.845 +long mh_ping (MAILSTREAM *stream)
 409.846 +{
 409.847 +  MAILSTREAM *sysibx = NIL;
 409.848 +  MESSAGECACHE *elt,*selt;
 409.849 +  struct stat sbuf;
 409.850 +  char *s,tmp[MAILTMPLEN];
 409.851 +  int fd;
 409.852 +  unsigned long i,j,r;
 409.853 +  unsigned long old = stream->uid_last;
 409.854 +  long nmsgs = stream->nmsgs;
 409.855 +  long recent = stream->recent;
 409.856 +  int silent = stream->silent;
 409.857 +  if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */
 409.858 +    if (stream->inbox &&	/* no, create if INBOX */
 409.859 +	dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"),
 409.860 +			   get_dir_protection ("INBOX"))) return T;
 409.861 +    sprintf (tmp,"Can't open mailbox %.80s: no such mailbox",stream->mailbox);
 409.862 +    mm_log (tmp,ERROR);
 409.863 +    return NIL;
 409.864 +  }
 409.865 +  stream->silent = T;		/* don't pass up mm_exists() events yet */
 409.866 +  if (sbuf.st_ctime != LOCAL->scantime) {
 409.867 +    struct direct **names = NIL;
 409.868 +    long nfiles = scandir (LOCAL->dir,&names,mh_select,mh_numsort);
 409.869 +    if (nfiles < 0) nfiles = 0;	/* in case error */
 409.870 +				/* note scanned now */
 409.871 +    LOCAL->scantime = sbuf.st_ctime;
 409.872 +				/* scan directory */
 409.873 +    for (i = 0; i < nfiles; ++i) {
 409.874 +				/* if newly seen, add to list */
 409.875 +      if ((j = atoi (names[i]->d_name)) > old) {
 409.876 +	mail_exists (stream,++nmsgs);
 409.877 +	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
 409.878 +	elt->valid = T;		/* note valid flags */
 409.879 +	if (old) {		/* other than the first pass? */
 409.880 +	  elt->recent = T;	/* yup, mark as recent */
 409.881 +	  recent++;		/* bump recent count */
 409.882 +	}
 409.883 +	else {			/* see if already read */
 409.884 +	  sprintf (tmp,"%s/%s",LOCAL->dir,names[i]->d_name);
 409.885 +	  if (!stat (tmp,&sbuf) && (sbuf.st_atime > sbuf.st_mtime))
 409.886 +	    elt->seen = T;
 409.887 +	}
 409.888 +      }
 409.889 +      fs_give ((void **) &names[i]);
 409.890 +    }
 409.891 +				/* free directory */
 409.892 +    if (s = (void *) names) fs_give ((void **) &s);
 409.893 +  }
 409.894 +
 409.895 +				/* if INBOX, snarf from system INBOX  */
 409.896 +  if (stream->inbox && strcmp (sysinbox (),stream->mailbox)) {
 409.897 +    old = stream->uid_last;
 409.898 +    mm_critical (stream);	/* go critical */
 409.899 +				/* see if anything in system inbox */
 409.900 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 409.901 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 409.902 +	!sysibx->rdonly && (r = sysibx->nmsgs)) {
 409.903 +      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
 409.904 +				/* build file name we will use */
 409.905 +	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old);
 409.906 +				/* snarf message from Berkeley mailbox */
 409.907 +	selt = mail_elt (sysibx,i);
 409.908 +	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
 409.909 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
 409.910 +	     >= 0) &&
 409.911 +	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_INTERNAL)) &&
 409.912 +	    (write (fd,s,j) == j) &&
 409.913 +	    (s = mail_fetchtext_full (sysibx,i,&j,FT_INTERNAL|FT_PEEK)) &&
 409.914 +	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
 409.915 +				/* swell the cache */
 409.916 +	  mail_exists (stream,++nmsgs);
 409.917 +	  stream->uid_last =	/* create new elt, note its file number */
 409.918 +	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
 409.919 +	  recent++;		/* bump recent count */
 409.920 +				/* set up initial flags and date */
 409.921 +	  elt->valid = elt->recent = T;
 409.922 +	  elt->seen = selt->seen;
 409.923 +	  elt->deleted = selt->deleted;
 409.924 +	  elt->flagged = selt->flagged;
 409.925 +	  elt->answered = selt->answered;
 409.926 +	  elt->draft = selt->draft;
 409.927 +	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
 409.928 +	  elt->hours = selt->hours;elt->minutes = selt->minutes;
 409.929 +	  elt->seconds = selt->seconds;
 409.930 +	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
 409.931 +	  elt->zoccident = selt->zoccident;
 409.932 +	  mh_setdate (LOCAL->buf,elt);
 409.933 +	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
 409.934 +	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 409.935 +	}
 409.936 +
 409.937 +	else {			/* failed to snarf */
 409.938 +	  if (fd) {		/* did it ever get opened? */
 409.939 +	    close (fd);		/* close descriptor */
 409.940 +	    unlink (LOCAL->buf);/* flush this file */
 409.941 +	  }
 409.942 +	  sprintf (tmp,"Message copy to MH mailbox failed: %.80s",
 409.943 +		   s,strerror (errno));
 409.944 +	  mm_log (tmp,ERROR);
 409.945 +	  r = 0;		/* stop the snarf in its tracks */
 409.946 +	}
 409.947 +      }
 409.948 +				/* update scan time */
 409.949 +      if (!stat (LOCAL->dir,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
 409.950 +      mail_expunge (sysibx);	/* now expunge all those messages */
 409.951 +    }
 409.952 +    if (sysibx) mail_close (sysibx);
 409.953 +    mm_nocritical (stream);	/* release critical */
 409.954 +  }
 409.955 +  stream->silent = silent;	/* can pass up events now */
 409.956 +  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
 409.957 +  mail_recent (stream,recent);
 409.958 +  return T;			/* return that we are alive */
 409.959 +}
 409.960 +
 409.961 +/* MH mail check mailbox
 409.962 + * Accepts: MAIL stream
 409.963 + */
 409.964 +
 409.965 +void mh_check (MAILSTREAM *stream)
 409.966 +{
 409.967 +  /* Perhaps in the future this will preserve flags */
 409.968 +  if (mh_ping (stream)) mm_log ("Check completed",(long) NIL);
 409.969 +}
 409.970 +
 409.971 +
 409.972 +/* MH mail expunge mailbox
 409.973 + * Accepts: MAIL stream
 409.974 + *	    sequence to expunge if non-NIL
 409.975 + *	    expunge options
 409.976 + * Returns: T, always
 409.977 + */
 409.978 +
 409.979 +long mh_expunge (MAILSTREAM *stream,char *sequence,long options)
 409.980 +{
 409.981 +  long ret;
 409.982 +  MESSAGECACHE *elt;
 409.983 +  unsigned long i = 1;
 409.984 +  unsigned long n = 0;
 409.985 +  unsigned long recent = stream->recent;
 409.986 +  if (ret = sequence ? ((options & EX_UID) ?
 409.987 +			mail_uid_sequence (stream,sequence) :
 409.988 +			mail_sequence (stream,sequence)) : LONGT) {
 409.989 +    mm_critical (stream);	/* go critical */
 409.990 +    while (i <= stream->nmsgs) {/* for each message */
 409.991 +      elt = mail_elt (stream,i);/* if deleted, need to trash it */
 409.992 +      if (elt->deleted && (sequence ? elt->sequence : T)) {
 409.993 +	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
 409.994 +	if (unlink (LOCAL->buf)) {/* try to delete the message */
 409.995 +	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
 409.996 +		   strerror (errno));
 409.997 +	  mm_log (LOCAL->buf,(long) NIL);
 409.998 +	  break;
 409.999 +	}
409.1000 +				/* note uncached */
409.1001 +	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
409.1002 +				elt->private.msg.header.text.size : 0) +
409.1003 +			       (elt->private.msg.text.text.data ?
409.1004 +				elt->private.msg.text.text.size : 0));
409.1005 +	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
409.1006 +				/* if recent, note one less recent message */
409.1007 +	if (elt->recent) --recent;
409.1008 +				/* notify upper levels */
409.1009 +	mail_expunged (stream,i);
409.1010 +	n++;			/* count up one more expunged message */
409.1011 +      }
409.1012 +      else i++;			/* otherwise try next message */
409.1013 +    }
409.1014 +    if (n) {			/* output the news if any expunged */
409.1015 +      sprintf (LOCAL->buf,"Expunged %lu messages",n);
409.1016 +      mm_log (LOCAL->buf,(long) NIL);
409.1017 +    }
409.1018 +    else mm_log ("No messages deleted, so no update needed",(long) NIL);
409.1019 +    mm_nocritical (stream);	/* release critical */
409.1020 +				/* notify upper level of new mailbox size */
409.1021 +    mail_exists (stream,stream->nmsgs);
409.1022 +    mail_recent (stream,recent);
409.1023 +  }
409.1024 +  return ret;
409.1025 +}
409.1026 +
409.1027 +/* MH mail copy message(s)
409.1028 + * Accepts: MAIL stream
409.1029 + *	    sequence
409.1030 + *	    destination mailbox
409.1031 + *	    copy options
409.1032 + * Returns: T if copy successful, else NIL
409.1033 + */
409.1034 +
409.1035 +long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
409.1036 +{
409.1037 +  FDDATA d;
409.1038 +  STRING st;
409.1039 +  MESSAGECACHE *elt;
409.1040 +  struct stat sbuf;
409.1041 +  int fd;
409.1042 +  unsigned long i;
409.1043 +  char flags[MAILTMPLEN],date[MAILTMPLEN];
409.1044 +  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
409.1045 +  long ret = NIL;
409.1046 +				/* copy the messages */
409.1047 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
409.1048 +      mail_sequence (stream,sequence))
409.1049 +    for (i = 1; i <= stream->nmsgs; i++) 
409.1050 +      if ((elt = mail_elt (stream,i))->sequence) {
409.1051 +	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
409.1052 +	if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL;
409.1053 +	fstat (fd,&sbuf);	/* get size of message */
409.1054 +	if (!elt->day) {	/* set internaldate to file date if needed */
409.1055 +	  struct tm *tm = gmtime (&sbuf.st_mtime);
409.1056 +	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
409.1057 +	  elt->year = tm->tm_year + 1900 - BASEYEAR;
409.1058 +	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
409.1059 +	  elt->seconds = tm->tm_sec;
409.1060 +	  elt->zhours = 0; elt->zminutes = 0;
409.1061 +	}
409.1062 +	d.fd = fd;		/* set up file descriptor */
409.1063 +	d.pos = 0;		/* start of file */
409.1064 +	d.chunk = LOCAL->buf;
409.1065 +	d.chunksize = CHUNKSIZE;
409.1066 +				/* kludge; mh_append would just strip CRs */
409.1067 +	INIT (&st,fd_string,&d,sbuf.st_size);
409.1068 +				/* init flag string */
409.1069 +	flags[0] = flags[1] = '\0';
409.1070 +	if (elt->seen) strcat (flags," \\Seen");
409.1071 +	if (elt->deleted) strcat (flags," \\Deleted");
409.1072 +	if (elt->flagged) strcat (flags," \\Flagged");
409.1073 +	if (elt->answered) strcat (flags," \\Answered");
409.1074 +	if (elt->draft) strcat (flags," \\Draft");
409.1075 +	flags[0] = '(';		/* open list */
409.1076 +	strcat (flags,")");	/* close list */
409.1077 +	mail_date (date,elt);	/* generate internal date */
409.1078 +	if (au) mail_parameters (NIL,SET_APPENDUID,NIL);
409.1079 +	if ((ret = mail_append_full (NIL,mailbox,flags,date,&st)) &&
409.1080 +	    (options & CP_MOVE)) elt->deleted = T;
409.1081 +	if (au) mail_parameters (NIL,SET_APPENDUID,(void *) au);
409.1082 +	close (fd);
409.1083 +      }
409.1084 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
409.1085 +    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
409.1086 +  return ret;			/* return success */
409.1087 +}
409.1088 +
409.1089 +/* MH mail append message from stringstruct
409.1090 + * Accepts: MAIL stream
409.1091 + *	    destination mailbox
409.1092 + *	    append callback
409.1093 + *	    data for callback
409.1094 + * Returns: T if append successful, else NIL
409.1095 + */
409.1096 +
409.1097 +long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
409.1098 +{
409.1099 +  struct direct **names = NIL;
409.1100 +  int fd;
409.1101 +  char c,*flags,*date,*s,tmp[MAILTMPLEN];
409.1102 +  STRING *message;
409.1103 +  MESSAGECACHE elt;
409.1104 +  FILE *df;
409.1105 +  long i,size,last,nfiles;
409.1106 +  long ret = LONGT;
409.1107 +				/* default stream to prototype */
409.1108 +  if (!stream) stream = &mhproto;
409.1109 +				/* make sure valid mailbox */
409.1110 +  if (!mh_isvalid (mailbox,tmp,NIL)) switch (errno) {
409.1111 +  case ENOENT:			/* no such file? */
409.1112 +    if (!((!compare_cstring (mailbox,MHINBOX) ||
409.1113 +	   !compare_cstring (mailbox,"INBOX")) &&
409.1114 +	  (mh_file (tmp,MHINBOX) &&
409.1115 +	   dummy_create_path (stream,strcat (tmp,"/"),
409.1116 +			      get_dir_protection (mailbox))))) {
409.1117 +      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
409.1118 +      return NIL;
409.1119 +    }
409.1120 +				/* falls through */
409.1121 +  case 0:			/* merely empty file? */
409.1122 +    break;
409.1123 +  case EINVAL:
409.1124 +    sprintf (tmp,"Invalid MH-format mailbox name: %.80s",mailbox);
409.1125 +    mm_log (tmp,ERROR);
409.1126 +    return NIL;
409.1127 +  default:
409.1128 +    sprintf (tmp,"Not a MH-format mailbox: %.80s",mailbox);
409.1129 +    mm_log (tmp,ERROR);
409.1130 +    return NIL;
409.1131 +  }
409.1132 +				/* get first message */
409.1133 +  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
409.1134 +  if ((nfiles = scandir (tmp,&names,mh_select,mh_numsort)) > 0) {
409.1135 +				/* largest number */
409.1136 +    last = atoi (names[nfiles-1]->d_name);    
409.1137 +    for (i = 0; i < nfiles; ++i) /* free directory */
409.1138 +      fs_give ((void **) &names[i]);
409.1139 +  }
409.1140 +  else last = 0;		/* no messages here yet */
409.1141 +  if (s = (void *) names) fs_give ((void **) &s);
409.1142 +
409.1143 +  mm_critical (stream);		/* go critical */
409.1144 +  do {
409.1145 +    if (!SIZE (message)) {	/* guard against zero-length */
409.1146 +      mm_log ("Append of zero-length message",ERROR);
409.1147 +      ret = NIL;
409.1148 +      break;
409.1149 +    }
409.1150 +    if (date) {			/* want to preserve date? */
409.1151 +				/* yes, parse date into an elt */
409.1152 +      if (!mail_parse_date (&elt,date)) {
409.1153 +	sprintf (tmp,"Bad date in append: %.80s",date);
409.1154 +	mm_log (tmp,ERROR);
409.1155 +	ret = NIL;
409.1156 +	break;
409.1157 +      }
409.1158 +    }
409.1159 +    mh_file (tmp,mailbox);	/* build file name we will use */
409.1160 +    sprintf (tmp + strlen (tmp),"/%ld",++last);
409.1161 +    if (((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
409.1162 +		     (long)mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0)||
409.1163 +	!(df = fdopen (fd,"ab"))) {
409.1164 +      sprintf (tmp,"Can't open append message: %s",strerror (errno));
409.1165 +      mm_log (tmp,ERROR);
409.1166 +      ret = NIL;
409.1167 +      break;
409.1168 +    }
409.1169 +				/* copy the data w/o CR's */
409.1170 +    for (size = 0,i = SIZE (message); i && ret; --i)
409.1171 +      if (((c = SNX (message)) != '\015') && (putc (c,df) == EOF)) ret = NIL;
409.1172 +				/* close the file */
409.1173 +    if (!ret || fclose (df)) {
409.1174 +      unlink (tmp);		/* delete message */
409.1175 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
409.1176 +      mm_log (tmp,ERROR);
409.1177 +      ret = NIL;
409.1178 +    }
409.1179 +    if (ret) {			/* set the date for this message */
409.1180 +      if (date) mh_setdate (tmp,&elt);
409.1181 +				/* get next message */
409.1182 +      if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
409.1183 +    }
409.1184 +  } while (ret && message);
409.1185 +  mm_nocritical (stream);	/* release critical */
409.1186 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
409.1187 +    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
409.1188 +	    WARN);
409.1189 +  return ret;
409.1190 +}
409.1191 +
409.1192 +/* Internal routines */
409.1193 +
409.1194 +
409.1195 +/* MH file name selection test
409.1196 + * Accepts: candidate directory entry
409.1197 + * Returns: T to use file name, NIL to skip it
409.1198 + */
409.1199 +
409.1200 +int mh_select (struct direct *name)
409.1201 +{
409.1202 +  char c;
409.1203 +  char *s = name->d_name;
409.1204 +  while (c = *s++) if (!isdigit (c)) return NIL;
409.1205 +  return T;
409.1206 +}
409.1207 +
409.1208 +
409.1209 +/* MH file name comparision
409.1210 + * Accepts: first candidate directory entry
409.1211 + *	    second candidate directory entry
409.1212 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
409.1213 + */
409.1214 +
409.1215 +int mh_numsort (const void *d1,const void *d2)
409.1216 +{
409.1217 +  return atoi ((*(struct direct **) d1)->d_name) -
409.1218 +    atoi ((*(struct direct **) d2)->d_name);
409.1219 +}
409.1220 +
409.1221 +
409.1222 +/* MH mail build file name
409.1223 + * Accepts: destination string
409.1224 + *          source
409.1225 + * Returns: destination
409.1226 + */
409.1227 +
409.1228 +char *mh_file (char *dst,char *name)
409.1229 +{
409.1230 +  char *s;
409.1231 +  char *path = mh_path (dst);
409.1232 +  if (!path) fatal ("No mh path in mh_file()!");
409.1233 +				/* INBOX becomes "inbox" in the MH path */
409.1234 +  if (!compare_cstring (name,MHINBOX) || !compare_cstring (name,"INBOX"))
409.1235 +    sprintf (dst,"%.900s/%.80s",path,MHINBOXDIR);
409.1236 +				/* #mh names skip past prefix */
409.1237 +  else if (*name == '#') sprintf (dst,"%.100s/%.900s",path,name + 4);
409.1238 +  else mailboxfile (dst,name);	/* all other names */
409.1239 +				/* tie off unnecessary trailing / */
409.1240 +  if ((s = strrchr (dst,'/')) && !s[1] && (s[-1] == '/')) *s = '\0';
409.1241 +  return dst;
409.1242 +}
409.1243 +
409.1244 +/* MH canonicalize name
409.1245 + * Accepts: buffer to write name
409.1246 + *	    reference
409.1247 + *	    pattern
409.1248 + * Returns: T if success, NIL if failure
409.1249 + */
409.1250 +
409.1251 +long mh_canonicalize (char *pattern,char *ref,char *pat)
409.1252 +{
409.1253 +  unsigned long i;
409.1254 +  char *s,tmp[MAILTMPLEN];
409.1255 +  if (ref && *ref) {		/* have a reference */
409.1256 +    strcpy (pattern,ref);	/* copy reference to pattern */
409.1257 +				/* # overrides mailbox field in reference */
409.1258 +    if (*pat == '#') strcpy (pattern,pat);
409.1259 +				/* pattern starts, reference ends, with / */
409.1260 +    else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
409.1261 +      strcat (pattern,pat + 1);	/* append, omitting one of the period */
409.1262 +    else strcat (pattern,pat);	/* anything else is just appended */
409.1263 +  }
409.1264 +  else strcpy (pattern,pat);	/* just have basic name */
409.1265 +  if (mh_isvalid (pattern,tmp,T)) {
409.1266 +				/* count wildcards */
409.1267 +    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
409.1268 +				/* success if not too many */
409.1269 +    if (i <= MAXWILDCARDS) return LONGT;
409.1270 +    mm_log ("Excessive wildcards in LIST/LSUB",ERROR);
409.1271 +  }
409.1272 +  return NIL;
409.1273 +}
409.1274 +
409.1275 +/* Set date for message
409.1276 + * Accepts: file name
409.1277 + *	    elt containing date
409.1278 + */
409.1279 +
409.1280 +void mh_setdate (char *file,MESSAGECACHE *elt)
409.1281 +{
409.1282 +  time_t tp[2];
409.1283 +  tp[0] = time (0);		/* atime is now */
409.1284 +  tp[1] = mail_longdate (elt);	/* modification time */
409.1285 +  utime (file,tp);		/* set the times */
409.1286 +}
   410.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   410.2 +++ b/src/osdep/unix/mix.c	Mon Sep 14 15:17:45 2009 +0900
   410.3 @@ -0,0 +1,2834 @@
   410.4 +/* ========================================================================
   410.5 + * Copyright 1988-2008 University of Washington
   410.6 + *
   410.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   410.8 + * you may not use this file except in compliance with the License.
   410.9 + * You may obtain a copy of the License at
  410.10 + *
  410.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  410.12 + *
  410.13 + * 
  410.14 + * ========================================================================
  410.15 + */
  410.16 +
  410.17 +/*
  410.18 + * Program:	MIX mail routines
  410.19 + *
  410.20 + * Author(s):	Mark Crispin
  410.21 + *		UW Technology
  410.22 + *		University of Washington
  410.23 + *		Seattle, WA  98195
  410.24 + *		Internet: MRC@Washington.EDU
  410.25 + *
  410.26 + * Date:	1 March 2006
  410.27 + * Last Edited:	7 May 2008
  410.28 + */
  410.29 +
  410.30 +
  410.31 +#include <stdio.h>
  410.32 +#include <ctype.h>
  410.33 +#include <errno.h>
  410.34 +extern int errno;		/* just in case */
  410.35 +#include "mail.h"
  410.36 +#include "osdep.h"
  410.37 +#include <pwd.h>
  410.38 +#include <sys/stat.h>
  410.39 +#include <sys/time.h>
  410.40 +#include "misc.h"
  410.41 +#include "dummy.h"
  410.42 +#include "fdstring.h"
  410.43 +
  410.44 +/* MIX definitions */
  410.45 +
  410.46 +#define MEGABYTE (1024*1024)
  410.47 +
  410.48 +#define MIXDATAROLL MEGABYTE	/* size at which we roll to a new file */
  410.49 +
  410.50 +
  410.51 +/* MIX files */
  410.52 +
  410.53 +#define MIXNAME ".mix"		/* prefix for all MIX file names */
  410.54 +#define MIXMETA "meta"		/* suffix for metadata */
  410.55 +#define MIXINDEX "index"	/* suffix for index */
  410.56 +#define MIXSTATUS "status"	/* suffix for status */
  410.57 +#define MIXSORTCACHE "sortcache"/* suffix for sortcache */
  410.58 +#define METAMAX (MEGABYTE-1)	/* maximum metadata file size (sanity check) */
  410.59 +
  410.60 +
  410.61 +/* MIX file formats */
  410.62 +
  410.63 +				/* sequence format (all but msg files) */
  410.64 +#define SEQFMT "S%08lx\015\012"
  410.65 +				/* metadata file format */
  410.66 +#define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012"
  410.67 +				/* index file record format */
  410.68 +#define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012"
  410.69 +				/* status file record format */
  410.70 +#define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012"
  410.71 +				/* message file header format */
  410.72 +#define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012"
  410.73 +#define MSGTOK ":msg:"
  410.74 +#define MSGTSZ (sizeof(MSGTOK)-1)
  410.75 +				/* sortcache file record format */
  410.76 +#define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012"
  410.77 +
  410.78 +/* MIX I/O stream local data */
  410.79 +	
  410.80 +typedef struct mix_local {
  410.81 +  unsigned long curmsg;		/* current message file number */
  410.82 +  unsigned long newmsg;		/* current new message file number */
  410.83 +  time_t lastsnarf;		/* last snarf time */
  410.84 +  int msgfd;			/* file description of current msg file */
  410.85 +  int mfd;			/* file descriptor of open metadata */
  410.86 +  unsigned long metaseq;	/* metadata sequence */
  410.87 +  char *index;			/* mailbox index name */
  410.88 +  unsigned long indexseq;	/* index sequence */
  410.89 +  char *status;			/* mailbox status name */
  410.90 +  unsigned long statusseq;	/* status sequence */
  410.91 +  char *sortcache;		/* mailbox sortcache name */
  410.92 +  unsigned long sortcacheseq;	/* sortcache sequence */
  410.93 +  unsigned char *buf;		/* temporary buffer */
  410.94 +  unsigned long buflen;		/* current size of temporary buffer */
  410.95 +  unsigned int expok : 1;	/* non-zero if expunge reports OK */
  410.96 +  unsigned int internal : 1;	/* internally opened, do not validate */
  410.97 +} MIXLOCAL;
  410.98 +
  410.99 +
 410.100 +#define MIXBURP struct mix_burp
 410.101 +
 410.102 +MIXBURP {
 410.103 +  unsigned long fileno;		/* message file number */
 410.104 +  char *name;			/* message file name */
 410.105 +  SEARCHSET *tail;		/* tail of ranges */
 410.106 +  SEARCHSET set;		/* set of retained ranges */
 410.107 +  MIXBURP *next;		/* next file to burp */
 410.108 +};
 410.109 +
 410.110 +
 410.111 +/* Convenient access to local data */
 410.112 +
 410.113 +#define LOCAL ((MIXLOCAL *) stream->local)
 410.114 +
 410.115 +/* Function prototypes */
 410.116 +
 410.117 +DRIVER *mix_valid (char *name);
 410.118 +long mix_isvalid (char *name,char *meta);
 410.119 +void *mix_parameters (long function,void *value);
 410.120 +long mix_dirfmttest (char *name);
 410.121 +void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 410.122 +long mix_scan_contents (char *name,char *contents,unsigned long csiz,
 410.123 +			unsigned long fsiz);
 410.124 +void mix_list (MAILSTREAM *stream,char *ref,char *pat);
 410.125 +void mix_lsub (MAILSTREAM *stream,char *ref,char *pat);
 410.126 +long mix_subscribe (MAILSTREAM *stream,char *mailbox);
 410.127 +long mix_unsubscribe (MAILSTREAM *stream,char *mailbox);
 410.128 +long mix_create (MAILSTREAM *stream,char *mailbox);
 410.129 +long mix_delete (MAILSTREAM *stream,char *mailbox);
 410.130 +long mix_rename (MAILSTREAM *stream,char *old,char *newname);
 410.131 +int mix_rselect (struct direct *name);
 410.132 +MAILSTREAM *mix_open (MAILSTREAM *stream);
 410.133 +void mix_close (MAILSTREAM *stream,long options);
 410.134 +void mix_abort (MAILSTREAM *stream);
 410.135 +char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 410.136 +		  long flags);
 410.137 +long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 410.138 +void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
 410.139 +unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 410.140 +			 SORTPGM *pgm,long flags);
 410.141 +THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
 410.142 +			SEARCHPGM *spg,long flags);
 410.143 +long mix_ping (MAILSTREAM *stream);
 410.144 +void mix_check (MAILSTREAM *stream);
 410.145 +long mix_expunge (MAILSTREAM *stream,char *sequence,long options);
 410.146 +int mix_select (struct direct *name);
 410.147 +int mix_msgfsort (const void *d1,const void *d2);
 410.148 +long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size);
 410.149 +long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed);
 410.150 +long mix_burp_check (SEARCHSET *set,size_t size,char *file);
 410.151 +long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
 410.152 +	       long options);
 410.153 +long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 410.154 +long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
 410.155 +		     STRING *msg,SEARCHSET *set,unsigned long seq);
 410.156 +
 410.157 +FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags);
 410.158 +char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq);
 410.159 +long mix_meta_update (MAILSTREAM *stream);
 410.160 +long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag);
 410.161 +long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag);
 410.162 +FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
 410.163 +		     unsigned long newsize);
 410.164 +FILE *mix_sortcache_open (MAILSTREAM *stream);
 410.165 +long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache);
 410.166 +char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type);
 410.167 +unsigned long mix_read_sequence (FILE *f);
 410.168 +char *mix_dir (char *dst,char *name);
 410.169 +char *mix_file (char *dst,char *dir,char *name);
 410.170 +char *mix_file_data (char *dst,char *dir,unsigned long data);
 410.171 +unsigned long mix_modseq (unsigned long oldseq);
 410.172 +
 410.173 +/* MIX mail routines */
 410.174 +
 410.175 +
 410.176 +/* Driver dispatch used by MAIL */
 410.177 +
 410.178 +DRIVER mixdriver = {
 410.179 +  "mix",			/* driver name */
 410.180 +				/* driver flags */
 410.181 +  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ,
 410.182 +  (DRIVER *) NIL,		/* next driver */
 410.183 +  mix_valid,			/* mailbox is valid for us */
 410.184 +  mix_parameters,		/* manipulate parameters */
 410.185 +  mix_scan,			/* scan mailboxes */
 410.186 +  mix_list,			/* find mailboxes */
 410.187 +  mix_lsub,			/* find subscribed mailboxes */
 410.188 +  mix_subscribe,		/* subscribe to mailbox */
 410.189 +  mix_unsubscribe,		/* unsubscribe from mailbox */
 410.190 +  mix_create,			/* create mailbox */
 410.191 +  mix_delete,			/* delete mailbox */
 410.192 +  mix_rename,			/* rename mailbox */
 410.193 +  mail_status_default,		/* status of mailbox */
 410.194 +  mix_open,			/* open mailbox */
 410.195 +  mix_close,			/* close mailbox */
 410.196 +  NIL,				/* fetch message "fast" attributes */
 410.197 +  NIL,				/* fetch message flags */
 410.198 +  NIL,				/* fetch overview */
 410.199 +  NIL,				/* fetch message envelopes */
 410.200 +  mix_header,			/* fetch message header only */
 410.201 +  mix_text,			/* fetch message body only */
 410.202 +  NIL,				/* fetch partial message test */
 410.203 +  NIL,				/* unique identifier */
 410.204 +  NIL,				/* message number */
 410.205 +  mix_flag,			/* modify flags */
 410.206 +  NIL,				/* per-message modify flags */
 410.207 +  NIL,				/* search for message based on criteria */
 410.208 +  mix_sort,			/* sort messages */
 410.209 +  mix_thread,			/* thread messages */
 410.210 +  mix_ping,			/* ping mailbox to see if still alive */
 410.211 +  mix_check,			/* check for new messages */
 410.212 +  mix_expunge,			/* expunge deleted messages */
 410.213 +  mix_copy,			/* copy messages to another mailbox */
 410.214 +  mix_append,			/* append string message to mailbox */
 410.215 +  NIL				/* garbage collect stream */
 410.216 +};
 410.217 +
 410.218 +				/* prototype stream */
 410.219 +MAILSTREAM mixproto = {&mixdriver};
 410.220 +
 410.221 +/* MIX mail validate mailbox
 410.222 + * Accepts: mailbox name
 410.223 + * Returns: our driver if name is valid, NIL otherwise
 410.224 + */
 410.225 +
 410.226 +DRIVER *mix_valid (char *name)
 410.227 +{
 410.228 +  char tmp[MAILTMPLEN];
 410.229 +  return mix_isvalid (name,tmp) ? &mixdriver : NIL;
 410.230 +}
 410.231 +
 410.232 +
 410.233 +/* MIX mail test for valid mailbox
 410.234 + * Accepts: mailbox name
 410.235 + *	    buffer to return meta name
 410.236 + * Returns: T if valid, NIL otherwise, metadata name written in both cases
 410.237 + */
 410.238 +
 410.239 +long mix_isvalid (char *name,char *meta)
 410.240 +{
 410.241 +  char dir[MAILTMPLEN];
 410.242 +  struct stat sbuf;
 410.243 +				/* validate name as directory */
 410.244 +  if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) &&
 410.245 +      *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) &&
 410.246 +      !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
 410.247 +				/* name is directory; is it mix? */
 410.248 +    if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
 410.249 +      return LONGT;
 410.250 +    else errno = NIL;		/* directory but not mix */
 410.251 +  }
 410.252 +  return NIL;
 410.253 +}
 410.254 +
 410.255 +/* MIX manipulate driver parameters
 410.256 + * Accepts: function code
 410.257 + *	    function-dependent value
 410.258 + * Returns: function-dependent return value
 410.259 + */
 410.260 +
 410.261 +void *mix_parameters (long function,void *value)
 410.262 +{
 410.263 +  void *ret = NIL;
 410.264 +  switch ((int) function) {
 410.265 +  case GET_INBOXPATH:
 410.266 +    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
 410.267 +    break;
 410.268 +  case GET_DIRFMTTEST:
 410.269 +    ret = (void *) mix_dirfmttest;
 410.270 +    break;
 410.271 +  case GET_SCANCONTENTS:
 410.272 +    ret = (void *) mix_scan_contents;
 410.273 +    break;
 410.274 +  case SET_ONETIMEEXPUNGEATPING:
 410.275 +    if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
 410.276 +  case GET_ONETIMEEXPUNGEATPING:
 410.277 +    if (value) ret = (void *)
 410.278 +      (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
 410.279 +    break;
 410.280 +  }
 410.281 +  return ret;
 410.282 +}
 410.283 +
 410.284 +
 410.285 +/* MIX test for directory format internal node
 410.286 + * Accepts: candidate node name
 410.287 + * Returns: T if internal name, NIL otherwise
 410.288 + */
 410.289 +
 410.290 +long mix_dirfmttest (char *name)
 410.291 +{
 410.292 +				/* belongs to MIX if starts with .mix */
 410.293 +  return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT;
 410.294 +}
 410.295 +
 410.296 +/* MIX mail scan mailboxes
 410.297 + * Accepts: mail stream
 410.298 + *	    reference
 410.299 + *	    pattern to search
 410.300 + *	    string to scan
 410.301 + */
 410.302 +
 410.303 +void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 410.304 +{
 410.305 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 410.306 +}
 410.307 +
 410.308 +
 410.309 +/* MIX scan mailbox for contents
 410.310 + * Accepts: mailbox name
 410.311 + *	    desired contents
 410.312 + *	    contents size
 410.313 + *	    file size (ignored)
 410.314 + * Returns: NIL if contents not found, T if found
 410.315 + */
 410.316 +
 410.317 +long mix_scan_contents (char *name,char *contents,unsigned long csiz,
 410.318 +			unsigned long fsiz)
 410.319 +{
 410.320 +  long i,nfiles;
 410.321 +  void *a;
 410.322 +  char *s;
 410.323 +  long ret = NIL;
 410.324 +  size_t namelen = strlen (name);
 410.325 +  struct stat sbuf;
 410.326 +  struct direct **names = NIL;
 410.327 +  if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0)
 410.328 +    for (i = 0; i < nfiles; ++i) {
 410.329 +      if (!ret) {
 410.330 +	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
 410.331 +		 "%s/%s",name,names[i]->d_name);
 410.332 +	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
 410.333 +	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
 410.334 +	fs_give ((void **) &s);
 410.335 +      }
 410.336 +      fs_give ((void **) &names[i]);
 410.337 +    }
 410.338 +				/* free directory list */
 410.339 +  if (a = (void *) names) fs_give ((void **) &a);
 410.340 +  return ret;
 410.341 +}
 410.342 +
 410.343 +/* MIX list mailboxes
 410.344 + * Accepts: mail stream
 410.345 + *	    reference
 410.346 + *	    pattern to search
 410.347 + */
 410.348 +
 410.349 +void mix_list (MAILSTREAM *stream,char *ref,char *pat)
 410.350 +{
 410.351 +  if (stream) dummy_list (NIL,ref,pat);
 410.352 +}
 410.353 +
 410.354 +
 410.355 +/* MIX list subscribed mailboxes
 410.356 + * Accepts: mail stream
 410.357 + *	    reference
 410.358 + *	    pattern to search
 410.359 + */
 410.360 +
 410.361 +void mix_lsub (MAILSTREAM *stream,char *ref,char *pat)
 410.362 +{
 410.363 +  if (stream) dummy_lsub (NIL,ref,pat);
 410.364 +}
 410.365 +
 410.366 +/* MIX mail subscribe to mailbox
 410.367 + * Accepts: mail stream
 410.368 + *	    mailbox to add to subscription list
 410.369 + * Returns: T on success, NIL on failure
 410.370 + */
 410.371 +
 410.372 +long mix_subscribe (MAILSTREAM *stream,char *mailbox)
 410.373 +{
 410.374 +  return sm_subscribe (mailbox);
 410.375 +}
 410.376 +
 410.377 +
 410.378 +/* MIX mail unsubscribe to mailbox
 410.379 + * Accepts: mail stream
 410.380 + *	    mailbox to delete from subscription list
 410.381 + * Returns: T on success, NIL on failure
 410.382 + */
 410.383 +
 410.384 +long mix_unsubscribe (MAILSTREAM *stream,char *mailbox)
 410.385 +{
 410.386 +  return sm_unsubscribe (mailbox);
 410.387 +}
 410.388 +
 410.389 +/* MIX mail create mailbox
 410.390 + * Accepts: mail stream
 410.391 + *	    mailbox name to create
 410.392 + * Returns: T on success, NIL on failure
 410.393 + */
 410.394 +
 410.395 +long mix_create (MAILSTREAM *stream,char *mailbox)
 410.396 +{
 410.397 +  DRIVER *test;
 410.398 +  FILE *f;
 410.399 +  int c,i;
 410.400 +  char *t,tmp[MAILTMPLEN],file[MAILTMPLEN];
 410.401 +  char *s = strrchr (mailbox,'/');
 410.402 +  unsigned long now = time (NIL);
 410.403 +  long ret = NIL;
 410.404 +				/* always create \NoSelect if trailing /  */
 410.405 +  if (s && !s[1]) return dummy_create (stream,mailbox);
 410.406 +				/* validate name */
 410.407 +  if (mix_dirfmttest (s ? s + 1 : mailbox))
 410.408 +    sprintf(tmp,"Can't create mailbox %.80s: invalid MIX-format name",mailbox);
 410.409 +				/* must not already exist */
 410.410 +  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
 410.411 +	   strcmp (test->name,"dummy"))
 410.412 +    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
 410.413 +				/* create directory and metadata */
 410.414 +  else if (!dummy_create_path (stream,
 410.415 +			       mix_file (file,mix_dir (tmp,mailbox),MIXMETA),
 410.416 +			       get_dir_protection (mailbox)))
 410.417 +    sprintf (tmp,"Can't create mailbox %.80s: %.80s",mailbox,strerror (errno));
 410.418 +  else if (!(f = fopen (file,"w")))
 410.419 +    sprintf (tmp,"Can't re-open metadata %.80s: %.80s",mailbox,
 410.420 +	     strerror (errno));
 410.421 +  else {			/* success, write initial metadata */
 410.422 +    fprintf (f,SEQFMT,now);
 410.423 +    fprintf (f,MTAFMT,now,0,now);
 410.424 +    for (i = 0, c = 'K'; (i < NUSERFLAGS) &&
 410.425 +	   (t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
 410.426 +	    default_user_flag (i)) && *t; ++i) {
 410.427 +      putc (c,f);		/* write another keyword */
 410.428 +      fputs (t,f);
 410.429 +      c = ' ';			/* delimiter is now space */
 410.430 +    }
 410.431 +    fclose (f);
 410.432 +    set_mbx_protections (mailbox,file);
 410.433 +				/* point to suffix */
 410.434 +    s = file + strlen (file) - (sizeof (MIXMETA) - 1);
 410.435 +    strcpy (s,MIXINDEX);	/* create index */
 410.436 +    if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
 410.437 +      sprintf (tmp,"Can't create mix mailbox index: %.80s",strerror (errno));
 410.438 +    else {
 410.439 +      set_mbx_protections (mailbox,file);
 410.440 +      strcpy (s,MIXSTATUS);	/* create status */
 410.441 +      if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
 410.442 +	sprintf (tmp,"Can't create mix mailbox status: %.80s",
 410.443 +		 strerror (errno));
 410.444 +      else {
 410.445 +	set_mbx_protections (mailbox,file);
 410.446 +	sprintf (s,"%08lx",now);/* message file */
 410.447 +	if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
 410.448 +	  sprintf (tmp,"Can't create mix mailbox data: %.80s",
 410.449 +		   strerror (errno));
 410.450 +	else {
 410.451 +	  set_mbx_protections (mailbox,file);
 410.452 +	  ret = LONGT;	/* declare success at this point */
 410.453 +	}
 410.454 +      }
 410.455 +    }
 410.456 +  }
 410.457 +  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
 410.458 +  return ret;
 410.459 +}
 410.460 +
 410.461 +/* MIX mail delete mailbox
 410.462 + *	    mailbox name to delete
 410.463 + * Returns: T on success, NIL on failure
 410.464 + */
 410.465 +
 410.466 +long mix_delete (MAILSTREAM *stream,char *mailbox)
 410.467 +{
 410.468 +  DIR *dirp;
 410.469 +  struct direct *d;
 410.470 +  int fd = -1;
 410.471 +  char *s,tmp[MAILTMPLEN];
 410.472 +  if (!mix_isvalid (mailbox,tmp))
 410.473 +    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
 410.474 +  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
 410.475 +    sprintf (tmp,"Can't lock mailbox for delete: %.80s",mailbox);
 410.476 +				/* delete metadata */
 410.477 +  else if (unlink (tmp)) sprintf (tmp,"Can't delete mailbox %.80s index: %80s",
 410.478 +				  mailbox,strerror (errno));
 410.479 +  else {
 410.480 +    close (fd);			/* close descriptor on deleted metadata */
 410.481 +				/* get directory name */
 410.482 +    *(s = strrchr (tmp,'/')) = '\0';
 410.483 +    if (dirp = opendir (tmp)) {	/* open directory */
 410.484 +      *s++ = '/';		/* restore delimiter */
 410.485 +				/* massacre messages */
 410.486 +      while (d = readdir (dirp)) if (mix_dirfmttest (d->d_name)) {
 410.487 +	strcpy (s,d->d_name);	/* make path */
 410.488 +	unlink (tmp);		/* sayonara */
 410.489 +      }
 410.490 +      closedir (dirp);		/* flush directory */
 410.491 +      *(s = strrchr (tmp,'/')) = '\0';
 410.492 +      if (rmdir (tmp)) {	/* try to remove the directory */
 410.493 +	sprintf (tmp,"Can't delete name %.80s: %.80s",
 410.494 +		 mailbox,strerror (errno));
 410.495 +	MM_LOG (tmp,WARN);
 410.496 +      }
 410.497 +    }
 410.498 +    return T;			/* always success */
 410.499 +  }
 410.500 +  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
 410.501 +  MM_LOG (tmp,ERROR);		/* something failed */
 410.502 +  return NIL;
 410.503 +}
 410.504 +
 410.505 +/* MIX mail rename mailbox
 410.506 + * Accepts: MIX mail stream
 410.507 + *	    old mailbox name
 410.508 + *	    new mailbox name
 410.509 + * Returns: T on success, NIL on failure
 410.510 + */
 410.511 +
 410.512 +long mix_rename (MAILSTREAM *stream,char *old,char *newname)
 410.513 +{
 410.514 +  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
 410.515 +  struct stat sbuf;
 410.516 +  int fd = -1;
 410.517 +  if (!mix_isvalid (old,tmp))
 410.518 +    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
 410.519 +  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
 410.520 +    sprintf (tmp,"Can't lock mailbox for rename: %.80s",old);
 410.521 +  else if (mix_dirfmttest ((s = strrchr (newname,'/')) ? s + 1 : newname))
 410.522 +    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MIX-format name",
 410.523 +	     newname);
 410.524 +				/* new mailbox name must not be valid */
 410.525 +  else if (mix_isvalid (newname,tmp))
 410.526 +    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
 410.527 +	     newname);
 410.528 +  else {
 410.529 +    mix_dir (tmp,old);		/* build old directory name */
 410.530 +    mix_dir (tmp1,newname);	/* and new directory name */
 410.531 +				/* easy if not INBOX */
 410.532 +    if (compare_cstring (old,"INBOX")) {
 410.533 +				/* found superior to destination name? */
 410.534 +      if (s = strrchr (tmp1,'/')) {
 410.535 +	c = *++s;		/* remember first character of inferior */
 410.536 +	*s = '\0';		/* tie off to get just superior */
 410.537 +				/* name doesn't exist, create it */
 410.538 +	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 410.539 +	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
 410.540 +	  return NIL;
 410.541 +	*s = c;			/* restore full name */
 410.542 +      }
 410.543 +      if (!rename (tmp,tmp1)) {
 410.544 +	close (fd);		/* close descriptor on metadata */
 410.545 +	return LONGT;
 410.546 +      }
 410.547 +    }
 410.548 +
 410.549 +				/* RFC 3501 requires this */
 410.550 +    else if (dummy_create_path (stream,strcat (tmp1,"/"),
 410.551 +				get_dir_protection (newname))) {
 410.552 +      void *a;
 410.553 +      int i,n,lasterror;
 410.554 +      char *src,*dst;
 410.555 +      struct direct **names = NIL;
 410.556 +      size_t srcl = strlen (tmp);
 410.557 +      size_t dstl = strlen (tmp1);
 410.558 +				/* rename each mix file to new directory */
 410.559 +      for (i = lasterror = 0,n = scandir (tmp,&names,mix_rselect,alphasort);
 410.560 +	   i < n; ++i) {
 410.561 +	size_t len = strlen (names[i]->d_name);
 410.562 +	sprintf (src = (char *) fs_get (srcl + len + 2),"%s/%s",
 410.563 +		 tmp,names[i]->d_name);
 410.564 +	sprintf (dst = (char *) fs_get (dstl + len + 1),"%s%s",
 410.565 +		 tmp1,names[i]->d_name);
 410.566 +	if (rename (src,dst)) lasterror = errno;
 410.567 +	fs_give ((void **) &src);
 410.568 +	fs_give ((void **) &dst);
 410.569 +	fs_give ((void **) &names[i]);
 410.570 +      }
 410.571 +				/* free directory list */
 410.572 +      if (a = (void *) names) fs_give ((void **) &a);
 410.573 +      if (lasterror) errno = lasterror;
 410.574 +      else {
 410.575 +	close (fd);		/* close descriptor on metadata */
 410.576 +	return mix_create (NIL,"INBOX");
 410.577 +      }
 410.578 +    }
 410.579 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",
 410.580 +	     old,newname,strerror (errno));
 410.581 +  }
 410.582 +  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
 410.583 +  MM_LOG (tmp,ERROR);		/* something failed */
 410.584 +  return NIL;
 410.585 +}
 410.586 +
 410.587 +
 410.588 +/* MIX test for mix name
 410.589 + * Accepts: candidate directory name
 410.590 + * Returns: T if mix file name, NIL otherwise
 410.591 + */
 410.592 +
 410.593 +int mix_rselect (struct direct *name)
 410.594 +{
 410.595 +  return mix_dirfmttest (name->d_name);
 410.596 +}
 410.597 +
 410.598 +/* MIX mail open
 410.599 + * Accepts: stream to open
 410.600 + * Returns: stream on success, NIL on failure
 410.601 + */
 410.602 +
 410.603 +MAILSTREAM *mix_open (MAILSTREAM *stream)
 410.604 +{
 410.605 +  short silent;
 410.606 +				/* return prototype for OP_PROTOTYPE call */
 410.607 +  if (!stream) return user_flags (&mixproto);
 410.608 +  if (stream->local) fatal ("mix recycle stream");
 410.609 +  stream->local = memset (fs_get (sizeof (MIXLOCAL)),0,sizeof (MIXLOCAL));
 410.610 +				/* note if an INBOX or not */
 410.611 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 410.612 +				/* make temporary buffer */
 410.613 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 410.614 +  LOCAL->buflen = CHUNKSIZE - 1;
 410.615 +				/* set stream->mailbox to be directory name */
 410.616 +  mix_dir (LOCAL->buf,stream->mailbox);
 410.617 +  fs_give ((void **) &stream->mailbox);
 410.618 +  stream->mailbox = cpystr (LOCAL->buf);
 410.619 +  LOCAL->msgfd = -1;		/* currently no file open */
 410.620 +  if (!(((!stream->rdonly &&	/* open metadata file */
 410.621 +	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
 410.622 +			       O_RDWR,NIL)) >= 0)) ||
 410.623 +	 ((stream->rdonly = T) &&
 410.624 +	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
 410.625 +			       O_RDONLY,NIL)) >= 0))) &&
 410.626 +	!flock (LOCAL->mfd,LOCK_SH))) {
 410.627 +    MM_LOG ("Error opening mix metadata file",ERROR);
 410.628 +    mix_abort (stream);
 410.629 +    stream = NIL;		/* open fails */
 410.630 +  }
 410.631 +  else {			/* metadata open, complete open */
 410.632 +    LOCAL->index = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXINDEX));
 410.633 +    LOCAL->status = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXSTATUS));
 410.634 +    LOCAL->sortcache = cpystr (mix_file (LOCAL->buf,stream->mailbox,
 410.635 +					 MIXSORTCACHE));
 410.636 +    stream->sequence++;		/* bump sequence number */
 410.637 +				/* parse mailbox */
 410.638 +    stream->nmsgs = stream->recent = 0;
 410.639 +    if (silent = stream->silent) LOCAL->internal = T;
 410.640 +    stream->silent = T;
 410.641 +    if (mix_ping (stream)) {	/* do initial ping */
 410.642 +				/* try burping in case we are exclusive */
 410.643 +      if (!stream->rdonly) mix_expunge (stream,"",NIL);
 410.644 +      if (!(stream->nmsgs || stream->silent))
 410.645 +	MM_LOG ("Mailbox is empty",(long) NIL);
 410.646 +      stream->silent = silent;	/* now notify upper level */
 410.647 +      mail_exists (stream,stream->nmsgs);
 410.648 +      stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 410.649 +	stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 410.650 +      stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 410.651 +      stream->kwd_create =	/* can we create new user flags? */
 410.652 +	(stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T;
 410.653 +    }
 410.654 +    else {			/* got murdelyzed in ping */
 410.655 +      mix_abort (stream);
 410.656 +      stream = NIL;
 410.657 +    }
 410.658 +  }
 410.659 +  return stream;		/* return stream to caller */
 410.660 +}
 410.661 +
 410.662 +/* MIX mail close
 410.663 + * Accepts: MAIL stream
 410.664 + *	    close options
 410.665 + */
 410.666 +
 410.667 +void mix_close (MAILSTREAM *stream,long options)
 410.668 +{
 410.669 +  if (LOCAL) {			/* only if a file is open */
 410.670 +    int silent = stream->silent;
 410.671 +    stream->silent = T;		/* note this stream is dying */
 410.672 +				/* burp-only or expunge */
 410.673 +    mix_expunge (stream,(options & CL_EXPUNGE) ? NIL : "",NIL);
 410.674 +    mix_abort (stream);
 410.675 +    stream->silent = silent;	/* reset silent state */
 410.676 +  }
 410.677 +}
 410.678 +
 410.679 +
 410.680 +/* MIX mail abort stream
 410.681 + * Accepts: MAIL stream
 410.682 + */
 410.683 +
 410.684 +void mix_abort (MAILSTREAM *stream)
 410.685 +{
 410.686 +  if (LOCAL) {			/* only if a file is open */
 410.687 +				/* close current message file if open */
 410.688 +    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
 410.689 +				/* close current metadata file if open */
 410.690 +    if (LOCAL->mfd >= 0) close (LOCAL->mfd);
 410.691 +    if (LOCAL->index) fs_give ((void **) &LOCAL->index);
 410.692 +    if (LOCAL->status) fs_give ((void **) &LOCAL->status);
 410.693 +    if (LOCAL->sortcache) fs_give ((void **) &LOCAL->sortcache);
 410.694 +				/* free local scratch buffer */
 410.695 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 410.696 +				/* nuke the local data */
 410.697 +    fs_give ((void **) &stream->local);
 410.698 +    stream->dtb = NIL;		/* log out the DTB */
 410.699 +  }
 410.700 +}
 410.701 +
 410.702 +/* MIX mail fetch message header
 410.703 + * Accepts: MAIL stream
 410.704 + *	    message # to fetch
 410.705 + *	    pointer to returned header text length
 410.706 + *	    option flags
 410.707 + * Returns: message header in RFC822 format
 410.708 + */
 410.709 +
 410.710 +char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 410.711 +		  long flags)
 410.712 +{
 410.713 +  unsigned long i,j,k;
 410.714 +  int fd;
 410.715 +  char *s,tmp[MAILTMPLEN];
 410.716 +  MESSAGECACHE *elt;
 410.717 +  if (length) *length = 0;	/* default return */
 410.718 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 410.719 +  elt = mail_elt (stream,msgno);/* get elt */
 410.720 +				/* is message in current message file? */
 410.721 +  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
 410.722 +    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
 410.723 +    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
 410.724 +					     elt->private.spare.data),
 410.725 +					     O_RDONLY,NIL)) < 0) return "";
 410.726 +				/* got file */
 410.727 +    LOCAL->curmsg = elt->private.spare.data;
 410.728 +  }    
 410.729 +  lseek (LOCAL->msgfd,elt->private.special.offset,L_SET);
 410.730 +				/* size of special data and header */
 410.731 +  j = elt->private.msg.header.offset + elt->private.msg.header.text.size;
 410.732 +  if (j > LOCAL->buflen) {	/* is buffer big enough? */
 410.733 +				/* no, make one that is */
 410.734 +    fs_give ((void **) &LOCAL->buf);
 410.735 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = j) + 1);
 410.736 +  }
 410.737 +  /* Maybe someday validate internaldate too */
 410.738 +				/* slurp special data + header, validate */
 410.739 +  if ((read (LOCAL->msgfd,LOCAL->buf,j) == j) &&
 410.740 +      !strncmp (LOCAL->buf,MSGTOK,MSGTSZ) &&
 410.741 +      (elt->private.uid == strtoul ((char *) LOCAL->buf + MSGTSZ,&s,16)) &&
 410.742 +      (*s++ == ':') && (s = strchr (s,':')) &&
 410.743 +      (k = strtoul (s+1,&s,16)) && (*s++ == ':') &&
 410.744 +      (s < (char *) (LOCAL->buf + elt->private.msg.header.offset))) {
 410.745 +				/* won, set offset and size of message */
 410.746 +    i = elt->private.msg.header.offset;
 410.747 +    *length = elt->private.msg.header.text.size;
 410.748 +    if (k != elt->rfc822_size) {
 410.749 +      sprintf (tmp,"Inconsistency in mix message size, uid=%lx (%lu != %lu)",
 410.750 +	       elt->private.uid,elt->rfc822_size,k);
 410.751 +      MM_LOG (tmp,WARN);
 410.752 +    }
 410.753 +  }
 410.754 +  else {			/* document the problem */
 410.755 +    LOCAL->buf[100] = '\0';	/* tie off buffer at no more than 100 octets */
 410.756 +				/* or at newline, whichever is first */
 410.757 +    if (s = strpbrk (LOCAL->buf,"\015\012")) *s = '\0';
 410.758 +    sprintf (tmp,"Error reading mix message header, uid=%lx, s=%.0lx, h=%s",
 410.759 +	     elt->private.uid,elt->rfc822_size,LOCAL->buf);
 410.760 +    MM_LOG (tmp,ERROR);
 410.761 +    *length = i = j = 0;	/* default to empty */
 410.762 +  }
 410.763 +  LOCAL->buf[j] = '\0';		/* tie off buffer at the end */
 410.764 +  return (char *) LOCAL->buf + i;
 410.765 +}
 410.766 +
 410.767 +/* MIX mail fetch message text (body only)
 410.768 + * Accepts: MAIL stream
 410.769 + *	    message # to fetch
 410.770 + *	    pointer to returned stringstruct
 410.771 + *	    option flags
 410.772 + * Returns: T on success, NIL on failure
 410.773 + */
 410.774 +
 410.775 +long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 410.776 +{
 410.777 +  unsigned long i;
 410.778 +  FDDATA d;
 410.779 +  MESSAGECACHE *elt;
 410.780 +				/* UID call "impossible" */
 410.781 +  if (flags & FT_UID) return NIL;
 410.782 +  elt = mail_elt (stream,msgno);
 410.783 +				/* is message in current message file? */
 410.784 +  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
 410.785 +    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
 410.786 +    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
 410.787 +					     elt->private.spare.data),
 410.788 +					     O_RDONLY,NIL)) < 0) return NIL;
 410.789 +				/* got file */
 410.790 +    LOCAL->curmsg = elt->private.spare.data;
 410.791 +  }    
 410.792 +				/* doing non-peek fetch? */
 410.793 +  if (!(flags & FT_PEEK) && !elt->seen) {
 410.794 +    FILE *idxf;			/* yes, process metadata/index/status */
 410.795 +    FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
 410.796 +    elt->seen = T;		/* mark as seen */
 410.797 +    MM_FLAGS (stream,elt->msgno);
 410.798 +				/* update status file if possible */
 410.799 +    if (statf && !stream->rdonly) {
 410.800 +      elt->private.mod = LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
 410.801 +      mix_status_update (stream,statf,NIL);
 410.802 +    }
 410.803 +    if (idxf) fclose (idxf);	/* release index and status file */
 410.804 +    if (statf) fclose (statf);
 410.805 +  } 
 410.806 +  d.fd = LOCAL->msgfd;		/* set up file descriptor */
 410.807 +				/* offset of message text */
 410.808 +  d.pos = elt->private.special.offset + elt->private.msg.header.offset +
 410.809 +    elt->private.msg.header.text.size;
 410.810 +  d.chunk = LOCAL->buf;		/* initial buffer chunk */
 410.811 +  d.chunksize = CHUNKSIZE;	/* chunk size */
 410.812 +  INIT (bs,fd_string,&d,elt->rfc822_size - elt->private.msg.header.text.size);
 410.813 +  return T;
 410.814 +}
 410.815 +
 410.816 +/* MIX mail modify flags
 410.817 + * Accepts: MAIL stream
 410.818 + *	    sequence
 410.819 + *	    flag(s)
 410.820 + *	    option flags
 410.821 + */
 410.822 +
 410.823 +void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 410.824 +{
 410.825 +  MESSAGECACHE *elt;
 410.826 +  unsigned long i,uf,ffkey;
 410.827 +  long f;
 410.828 +  short nf;
 410.829 +  FILE *idxf;
 410.830 +  FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
 410.831 +  unsigned long seq = mix_modseq (LOCAL->statusseq);
 410.832 +				/* find first free key */
 410.833 +  for (ffkey = 0; (ffkey < NUSERFLAGS) && stream->user_flags[ffkey]; ++ffkey);
 410.834 +				/* parse sequence and flags */
 410.835 +  if (((flags & ST_UID) ? mail_uid_sequence (stream,sequence) :
 410.836 +       mail_sequence (stream,sequence)) &&
 410.837 +      ((f = mail_parse_flags (stream,flag,&uf)) || uf)) {
 410.838 +				/* alter flags */
 410.839 +    for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++)
 410.840 +      if ((elt = mail_elt (stream,i))->sequence) {
 410.841 +	struct {		/* old flags */
 410.842 +	  unsigned int seen : 1;
 410.843 +	  unsigned int deleted : 1;
 410.844 +	  unsigned int flagged : 1;
 410.845 +	  unsigned int answered : 1;
 410.846 +	  unsigned int draft : 1;
 410.847 +	  unsigned long user_flags;
 410.848 +	} old;
 410.849 +	old.seen = elt->seen; old.deleted = elt->deleted;
 410.850 +	old.flagged = elt->flagged; old.answered = elt->answered;
 410.851 +	old.draft = elt->draft; old.user_flags = elt->user_flags;
 410.852 +	if (f&fSEEN) elt->seen = nf;
 410.853 +	if (f&fDELETED) elt->deleted = nf;
 410.854 +	if (f&fFLAGGED) elt->flagged = nf;
 410.855 +	if (f&fANSWERED) elt->answered = nf;
 410.856 +	if (f&fDRAFT) elt->draft = nf;
 410.857 +				/* user flags */
 410.858 +	if (flags & ST_SET) elt->user_flags |= uf;
 410.859 +	else elt->user_flags &= ~uf;
 410.860 +	if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
 410.861 +	    (old.flagged != elt->flagged) ||
 410.862 +	    (old.answered != elt->answered) || (old.draft != elt->draft) ||
 410.863 +	    (old.user_flags != elt->user_flags)) {
 410.864 +	  if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
 410.865 +	  MM_FLAGS (stream,elt->msgno);
 410.866 +	}
 410.867 +      }
 410.868 +				/* update status file after change */
 410.869 +    if (statf && (seq == LOCAL->statusseq))
 410.870 +      mix_status_update (stream,statf,NIL);
 410.871 +				/* update metadata if created a keyword */
 410.872 +    if ((ffkey < NUSERFLAGS) && stream->user_flags[ffkey] &&
 410.873 +	!mix_meta_update (stream))
 410.874 +      MM_LOG ("Error updating mix metadata after keyword creation",ERROR);
 410.875 +  }
 410.876 +  if (statf) fclose (statf);	/* release status file if still open */
 410.877 +  if (idxf) fclose (idxf);	/* release index file */
 410.878 +}
 410.879 +
 410.880 +/* MIX mail sort messages
 410.881 + * Accepts: mail stream
 410.882 + *	    character set
 410.883 + *	    search program
 410.884 + *	    sort program
 410.885 + *	    option flags
 410.886 + * Returns: vector of sorted message sequences or NIL if error
 410.887 + */
 410.888 +
 410.889 +unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
 410.890 +			 SORTPGM *pgm,long flags)
 410.891 +{
 410.892 +  unsigned long *ret;
 410.893 +  FILE *sortcache = mix_sortcache_open (stream);
 410.894 +  ret = mail_sort_msgs (stream,charset,spg,pgm,flags);
 410.895 +  mix_sortcache_update (stream,&sortcache);
 410.896 +  return ret;
 410.897 +}
 410.898 +
 410.899 +
 410.900 +/* MIX mail thread messages
 410.901 + * Accepts: mail stream
 410.902 + *	    thread type
 410.903 + *	    character set
 410.904 + *	    search program
 410.905 + *	    option flags
 410.906 + * Returns: thread node tree or NIL if error
 410.907 + */
 410.908 +
 410.909 +THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
 410.910 +			SEARCHPGM *spg,long flags)
 410.911 +{
 410.912 +  THREADNODE *ret;
 410.913 +  FILE *sortcache = mix_sortcache_open (stream);
 410.914 +  ret = mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs);
 410.915 +  mix_sortcache_update (stream,&sortcache);
 410.916 +  return ret;
 410.917 +}
 410.918 +
 410.919 +/* MIX mail ping mailbox
 410.920 + * Accepts: MAIL stream
 410.921 + * Returns: T if stream alive, else NIL
 410.922 + */
 410.923 +
 410.924 +static int snarfing = 0;	/* lock against recursive snarfing */
 410.925 +
 410.926 +long mix_ping (MAILSTREAM *stream)
 410.927 +{
 410.928 +  FILE *idxf,*statf;
 410.929 +  struct stat sbuf;
 410.930 +  STRING msg;
 410.931 +  MESSAGECACHE *elt;
 410.932 +  int mfd,ifd,sfd;
 410.933 +  unsigned long i,msglen;
 410.934 +  char *message,date[MAILTMPLEN],flags[MAILTMPLEN];
 410.935 +  MAILSTREAM *sysibx = NIL;
 410.936 +  long ret = NIL;
 410.937 +  long snarfok = LONGT;
 410.938 +				/* time to snarf? */
 410.939 +  if (stream->inbox && !stream->rdonly && !snarfing &&
 410.940 +      (time (0) >= (LOCAL->lastsnarf +
 410.941 +		    (time_t) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
 410.942 +    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
 410.943 +    copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 410.944 +    MM_CRITICAL (stream);	/* go critical */
 410.945 +    snarfing = T;		/* don't recursively snarf */
 410.946 +				/* disable APPENDUID/COPYUID callbacks */
 410.947 +    mail_parameters (NIL,SET_APPENDUID,NIL);
 410.948 +    mail_parameters (NIL,SET_COPYUID,NIL);
 410.949 +				/* sizes match and anything in sysinbox? */
 410.950 +    if (!stat (sysinbox (),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
 410.951 +	sbuf.st_size &&	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 410.952 +	!sysibx->rdonly && sysibx->nmsgs) {
 410.953 +				/* for each message in sysibx mailbox */
 410.954 +      for (i = 1; snarfok && (i <= sysibx->nmsgs); ++i)
 410.955 +	if (!(elt = mail_elt (sysibx,i))->deleted &&
 410.956 +	    (message = mail_fetch_message (sysibx,i,&msglen,FT_PEEK)) &&
 410.957 +	    msglen) {
 410.958 +	  mail_date (date,elt);	/* make internal date string */
 410.959 +				/* make flag string */
 410.960 +	  flags[0] = flags[1] = '\0';
 410.961 +	  if (elt->seen) strcat (flags," \\Seen");
 410.962 +	  if (elt->flagged) strcat (flags," \\Flagged");
 410.963 +	  if (elt->answered) strcat (flags," \\Answered");
 410.964 +	  if (elt->draft) strcat (flags," \\Draft");
 410.965 +	  flags[0] = '(';
 410.966 +	  strcat (flags,")");
 410.967 +	  INIT (&msg,mail_string,message,msglen);
 410.968 +	  if (snarfok = mail_append_full (stream,"INBOX",flags,date,&msg)) {
 410.969 +	    char sequence[15];
 410.970 +	    sprintf (sequence,"%lu",i);
 410.971 +	    mail_flag (sysibx,sequence,"\\Deleted",ST_SET);
 410.972 +	  }
 410.973 +	}
 410.974 +
 410.975 +				/* now expunge all those messages */
 410.976 +      if (snarfok) mail_expunge (sysibx);
 410.977 +      else {
 410.978 +	sprintf (LOCAL->buf,"Can't copy new mail at message: %lu",i - 1);
 410.979 +	MM_LOG (LOCAL->buf,WARN);
 410.980 +      }
 410.981 +    }
 410.982 +    if (sysibx) mail_close (sysibx);
 410.983 +				/* reenable APPENDUID/COPYUID */
 410.984 +    mail_parameters (NIL,SET_APPENDUID,(void *) au);
 410.985 +    mail_parameters (NIL,SET_COPYUID,(void *) cu);
 410.986 +    snarfing = NIL;		/* no longer snarfing */
 410.987 +    MM_NOCRITICAL (stream);	/* release critical */
 410.988 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 410.989 +  }
 410.990 +				/* expunging OK if global flag set */
 410.991 +  if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
 410.992 +				/* process metadata/index/status */
 410.993 +  if (statf = mix_parse (stream,&idxf,LONGT,
 410.994 +			 (LOCAL->internal ? NIL : LONGT))) {
 410.995 +    fclose (statf);		/* just close the status file */
 410.996 +    ret = LONGT;		/* declare success */
 410.997 +  }
 410.998 +  if (idxf) fclose (idxf);	/* release index file */
 410.999 +  LOCAL->expok = NIL;		/* expunge no longer OK */
410.1000 +  if (!ret) mix_abort (stream);	/* murdelyze stream if ping fails */
410.1001 +  return ret;
410.1002 +}
410.1003 +
410.1004 +
410.1005 +/* MIX mail checkpoint mailbox (burp only)
410.1006 + * Accepts: MAIL stream
410.1007 + */
410.1008 +
410.1009 +void mix_check (MAILSTREAM *stream)
410.1010 +{
410.1011 +  if (stream->rdonly)		/* won't do on readonly files! */
410.1012 +    MM_LOG ("Checkpoint ignored on readonly mailbox",NIL);
410.1013 +				/* do burp-only expunge action */
410.1014 +  if (mix_expunge (stream,"",NIL)) MM_LOG ("Check completed",(long) NIL);
410.1015 +}
410.1016 +
410.1017 +/* MIX mail expunge mailbox
410.1018 + * Accepts: MAIL stream
410.1019 + *	    sequence to expunge if non-NIL, empty string for burp only
410.1020 + *	    expunge options
410.1021 + * Returns: T on success, NIL if failure
410.1022 + */
410.1023 +
410.1024 +long mix_expunge (MAILSTREAM *stream,char *sequence,long options)
410.1025 +{
410.1026 +  FILE *idxf = NIL;
410.1027 +  FILE *statf = NIL;
410.1028 +  MESSAGECACHE *elt;
410.1029 +  int ifd,sfd;
410.1030 +  long ret;
410.1031 +  unsigned long i;
410.1032 +  unsigned long nexp = 0;
410.1033 +  unsigned long reclaimed = 0;
410.1034 +  int burponly = (sequence && !*sequence);
410.1035 +  LOCAL->expok = T;		/* expunge during ping is OK */
410.1036 +  if (!(ret = burponly || !sequence ||
410.1037 +	((options & EX_UID) ?
410.1038 +	 mail_uid_sequence (stream,sequence) :
410.1039 +	 mail_sequence (stream,sequence))) || stream->rdonly);
410.1040 +				/* read index and open status exclusive */
410.1041 +  else if (statf = mix_parse (stream,&idxf,LONGT,
410.1042 +			      LOCAL->internal ? NIL : LONGT)) {
410.1043 +				/* expunge unless just burping */
410.1044 +    if (!burponly) for (i = 1; i <= stream->nmsgs;) {
410.1045 +      elt = mail_elt (stream,i);/* need to expunge this message? */
410.1046 +      if (sequence ? elt->sequence : elt->deleted) {
410.1047 +	++nexp;			/* yes, make it so */
410.1048 +	mail_expunged (stream,i);
410.1049 +      }
410.1050 +      else ++i;		       /* otherwise advance to next message */
410.1051 +    }
410.1052 +
410.1053 +				/* burp if can get exclusive access */
410.1054 +    if (!flock (LOCAL->mfd,LOCK_EX|LOCK_NB)) {
410.1055 +      void *a;
410.1056 +      struct direct **names = NIL;
410.1057 +      long nfiles = scandir (stream->mailbox,&names,mix_select,mix_msgfsort);
410.1058 +      if (nfiles > 0) {		/* if have message files */
410.1059 +	MIXBURP *burp,*cur;
410.1060 +				/* initialize burp list */
410.1061 +	for (i = 0, burp = cur = NIL; i < nfiles; ++i) {
410.1062 +	  MIXBURP *nxt = (MIXBURP *) memset (fs_get (sizeof (MIXBURP)),0,
410.1063 +					     sizeof (MIXBURP));
410.1064 +				/* another file found */
410.1065 +	  if (cur) cur = cur->next = nxt;
410.1066 +	  else cur = burp = nxt;
410.1067 +	  cur->name = names[i]->d_name;
410.1068 +	  cur->fileno = strtoul (cur->name + sizeof (MIXNAME) - 1,NIL,16);
410.1069 +	  cur->tail = &cur->set;
410.1070 +	  fs_give ((void **) &names[i]);
410.1071 +	}
410.1072 +				/* now load ranges */
410.1073 +	for (i = 1, cur = burp; ret && (i <= stream->nmsgs); i++) {
410.1074 +				/* is this message in current set? */
410.1075 +	  elt = mail_elt (stream,i);
410.1076 +	  if (cur && (elt->private.spare.data != cur->fileno)) {
410.1077 +				/* restart if necessary */
410.1078 +	    if (elt->private.spare.data < cur->fileno) cur = burp;
410.1079 +				/* hunt for appropriate mailbox */
410.1080 +	    while (cur && (elt->private.spare.data > cur->fileno))
410.1081 +	      cur = cur->next;
410.1082 +				/* ought to have found it now... */
410.1083 +	    if (cur && (elt->private.spare.data != cur->fileno)) cur = NIL;
410.1084 +	  }
410.1085 +				/* if found, add to set */
410.1086 +	  if (cur) ret = mix_addset (&cur->tail,elt->private.special.offset,
410.1087 +				     elt->private.msg.header.offset +
410.1088 +				     elt->rfc822_size);
410.1089 +	  else {		/* uh-oh */
410.1090 +	    sprintf (LOCAL->buf,"Can't locate mix message file %.08lx",
410.1091 +		     elt->private.spare.data);
410.1092 +	    MM_LOG (LOCAL->buf,ERROR);
410.1093 +	    ret = NIL;
410.1094 +	  }
410.1095 +	}
410.1096 +	if (ret) 		/* if no errors, burp all files */
410.1097 +	  for (cur = burp; ret && cur; cur = cur->next) {
410.1098 +				/* if non-empty, burp it */
410.1099 +	    if (cur->set.last) ret = mix_burp (stream,cur,&reclaimed);
410.1100 +				/* empty, delete it unless new msg file */
410.1101 +	    else if (mix_file_data (LOCAL->buf,stream->mailbox,cur->fileno) &&
410.1102 +		     ((cur->fileno == LOCAL->newmsg) ?
410.1103 +		      truncate (LOCAL->buf,0) : unlink (LOCAL->buf))) {
410.1104 +	      sprintf (LOCAL->buf,
410.1105 +		       "Can't delete empty message file %.80s: %.80s",
410.1106 +		       cur->name,strerror (errno));
410.1107 +	      MM_LOG (LOCAL->buf,WARN);
410.1108 +	    }
410.1109 +	  }
410.1110 +      }
410.1111 +      else MM_LOG ("No mix message files found during expunge",WARN);
410.1112 +				/* free directory list */
410.1113 +      if (a = (void *) names) fs_give ((void **) &a);
410.1114 +    }
410.1115 +
410.1116 +				/* either way, re-acquire shared lock */
410.1117 +    if (flock (LOCAL->mfd,LOCK_SH|LOCK_NB))
410.1118 +      fatal ("Unable to re-acquire metadata shared lock!");
410.1119 +    /* Do this step even if ret is NIL (meaning some burp problem)! */
410.1120 +    if (nexp || reclaimed) {	/* rewrite index and status if changed */
410.1121 +      LOCAL->indexseq = mix_modseq (LOCAL->indexseq);
410.1122 +      if (mix_index_update (stream,idxf,NIL)) {
410.1123 +	LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
410.1124 +				/* set failure if update fails */
410.1125 +	ret = mix_status_update (stream,statf,NIL);
410.1126 +      }
410.1127 +    }
410.1128 +  }
410.1129 +  if (statf) fclose (statf);	/* close status if still open */
410.1130 +  if (idxf) fclose (idxf);	/* close index if still open */
410.1131 +  LOCAL->expok = NIL;		/* cancel expok */
410.1132 +  if (ret) {			/* only if success */
410.1133 +    char *s = NIL;
410.1134 +    if (nexp) sprintf (s = LOCAL->buf,"Expunged %lu messages",nexp);
410.1135 +    else if (reclaimed)
410.1136 +      sprintf (s=LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
410.1137 +    else if (!burponly)
410.1138 +      s = stream->rdonly ? "Expunge ignored on readonly mailbox" :
410.1139 +	   "No messages deleted, so no update needed";
410.1140 +    if (s) MM_LOG (s,(long) NIL);
410.1141 +  }
410.1142 +  return ret;
410.1143 +}
410.1144 +
410.1145 +/* MIX test for message file name
410.1146 + * Accepts: candidate directory name
410.1147 + * Returns: T if message file name, NIL otherwise
410.1148 + *
410.1149 + * ".mix" with no suffix was used by experimental versions
410.1150 + */
410.1151 +
410.1152 +int mix_select (struct direct *name)
410.1153 +{
410.1154 +  char c,*s;
410.1155 +				/* make sure name has prefix */
410.1156 +  if (mix_dirfmttest (name->d_name)) {
410.1157 +    for (c = *(s = name->d_name + sizeof (MIXNAME) - 1); c && isxdigit (c);
410.1158 +	 c = *s++);
410.1159 +    if (!c) return T;		/* all-hex or no suffix */
410.1160 +  }
410.1161 +  return NIL;			/* not suffix or non-hex */
410.1162 +}
410.1163 +
410.1164 +
410.1165 +/* MIX msg file name comparision
410.1166 + * Accepts: first candidate directory entry
410.1167 + *	    second candidate directory entry
410.1168 + * Returns: -1 if d1 < d2, 0 if d1 == d2, 1 d1 > d2
410.1169 + */
410.1170 +
410.1171 +int mix_msgfsort (const void *d1,const void *d2)
410.1172 +{
410.1173 +  char *n1 = (*(struct direct **) d1)->d_name + sizeof (MIXNAME) - 1;
410.1174 +  char *n2 = (*(struct direct **) d2)->d_name + sizeof (MIXNAME) - 1;
410.1175 +  return compare_ulong (*n1 ? strtoul (n1,NIL,16) : 0,
410.1176 +			*n2 ? strtoul (n2,NIL,16) : 0);
410.1177 +}
410.1178 +
410.1179 +
410.1180 +/* MIX add a range to a set
410.1181 + * Accepts: pointer to set to add
410.1182 + *	    start of set
410.1183 + *	    size of set
410.1184 + * Returns: T if success, set updated, NIL otherwise
410.1185 + */
410.1186 +
410.1187 +long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size)
410.1188 +{
410.1189 +  SEARCHSET *s = *set;
410.1190 +  if (start < s->last) {	/* sanity check */
410.1191 +    char tmp[MAILTMPLEN];
410.1192 +    sprintf (tmp,"Backwards-running mix index %lu < %lu",start,s->last);
410.1193 +    MM_LOG (tmp,ERROR);
410.1194 +    return NIL;
410.1195 +  }
410.1196 +				/* range initially empty? */
410.1197 +  if (!s->last) s->first = start;
410.1198 +  else if (start > s->last)	/* no, start new range if can't append */
410.1199 +    (*set = s = s->next = mail_newsearchset ())->first = start;
410.1200 +  s->last = start + size;	/* end of current range */
410.1201 +  return LONGT;
410.1202 +}
410.1203 +
410.1204 +/* MIX burp message file
410.1205 + * Accepts: MAIL stream
410.1206 + *	    current burp block for this message
410.1207 + * Returns: T if successful, NIL if failed
410.1208 + */
410.1209 +
410.1210 +static char *staterr = "Error in stat of mix message file %.80s: %.80s";
410.1211 +static char *truncerr = "Error truncating mix message file %.80s: %.80s";
410.1212 +
410.1213 +long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed)
410.1214 +{
410.1215 +  MESSAGECACHE *elt;
410.1216 +  SEARCHSET *set;
410.1217 +  struct stat sbuf;
410.1218 +  off_t rpos,wpos;
410.1219 +  size_t size,wsize,wpending,written;
410.1220 +  int fd;
410.1221 +  FILE *f;
410.1222 +  void *s;
410.1223 +  unsigned long i;
410.1224 +  long ret = NIL;
410.1225 +				/* build file name */
410.1226 +  mix_file_data (LOCAL->buf,stream->mailbox,burp->fileno);
410.1227 +				/* need to burp at start or multiple ranges? */
410.1228 +  if (!burp->set.first && !burp->set.next) {
410.1229 +				/* easy case, single range at start of file */
410.1230 +    if (stat (LOCAL->buf,&sbuf)) {
410.1231 +      sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
410.1232 +      MM_LOG (LOCAL->buf,ERROR);
410.1233 +    }
410.1234 +				/* is this range sane? */
410.1235 +    else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
410.1236 +				/* if matches range then no burp needed! */
410.1237 +      if (burp->set.last == sbuf.st_size) ret = LONGT;
410.1238 +				/* just need to remove cruft at end */
410.1239 +      else if (ret = !truncate (LOCAL->buf,burp->set.last))
410.1240 +	*reclaimed += sbuf.st_size - burp->set.last;
410.1241 +      else {
410.1242 +	sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
410.1243 +	MM_LOG (LOCAL->buf,ERROR);
410.1244 +      }
410.1245 +    }
410.1246 +  }
410.1247 +				/* have to do more work, get the file */
410.1248 +  else if (((fd = open (LOCAL->buf,O_RDWR,NIL)) < 0) ||
410.1249 +	   !(f = fdopen (fd,"r+b"))) {
410.1250 +    sprintf (LOCAL->buf,"Error opening mix message file %.80s: %.80s",
410.1251 +	     burp->name,strerror (errno));
410.1252 +    MM_LOG (LOCAL->buf,ERROR);
410.1253 +    if (fd >= 0) close (fd);	/* in case fdopen() failure */
410.1254 +  }
410.1255 +  else if (fstat (fd,&sbuf)) {	/* get file size */
410.1256 +    sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
410.1257 +    MM_LOG (LOCAL->buf,ERROR);
410.1258 +    fclose (f);
410.1259 +  }
410.1260 +
410.1261 +				/* only if sane */
410.1262 +  else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
410.1263 +				/* make sure each range starts with token */
410.1264 +    for (set = &burp->set; set; set = set->next)
410.1265 +      if (fseek (f,set->first,SEEK_SET) ||
410.1266 +	  (fread (LOCAL->buf,1,MSGTSZ,f) != MSGTSZ) ||
410.1267 +	  strncmp (LOCAL->buf,MSGTOK,MSGTSZ)) {
410.1268 +	sprintf (LOCAL->buf,"Bad message token in mix message file at %lu",
410.1269 +		 set->first);
410.1270 +	MM_LOG (LOCAL->buf,ERROR);
410.1271 +	fclose (f);
410.1272 +	return NIL;		/* burp fails for this file */
410.1273 +      }
410.1274 +				/* burp out each old message */
410.1275 +    for (set = &burp->set, wpos = 0; set; set = set->next) {
410.1276 +				/* move down this range */
410.1277 +      for (rpos = set->first, size = set->last - set->first;
410.1278 +	   size; size -= wsize) {
410.1279 +	if (rpos != wpos) {	/* data to skip at start? */
410.1280 +				/* no, slide this buffer down */
410.1281 +	  wsize = min (size,LOCAL->buflen);
410.1282 +				/* failure is not an option here */
410.1283 +	  while (fseek (f,rpos,SEEK_SET) ||
410.1284 +		 (fread (LOCAL->buf,1,wsize,f) != wsize)) {
410.1285 +	    MM_NOTIFY (stream,strerror (errno),WARN);
410.1286 +	    MM_DISKERROR (stream,errno,T);
410.1287 +	  }
410.1288 +				/* nor here */
410.1289 +	  while (fseek (f,wpos,SEEK_SET)) {
410.1290 +	    MM_NOTIFY (stream,strerror (errno),WARN);
410.1291 +	    MM_DISKERROR (stream,errno,T);
410.1292 +	  }
410.1293 +				/* and especially not here */
410.1294 +	  for (s = LOCAL->buf, wpending = wsize; wpending; wpending -= written)
410.1295 +	    if (!(written = fwrite (LOCAL->buf,1,wpending,f))) {
410.1296 +	      MM_NOTIFY (stream,strerror (errno),WARN);
410.1297 +	      MM_DISKERROR (stream,errno,T);
410.1298 +	    }
410.1299 +	}
410.1300 +	else wsize = size;	/* nothing to skip, say we wrote it all */
410.1301 +	rpos += wsize; wpos += wsize;
410.1302 +      }
410.1303 +    }
410.1304 +
410.1305 +    while (fflush (f)) {	/* failure also not an option here... */
410.1306 +      MM_NOTIFY (stream,strerror (errno),WARN);
410.1307 +      MM_DISKERROR (stream,errno,T);
410.1308 +    }
410.1309 +    if (ftruncate (fd,wpos)) {	/* flush cruft at end of file */
410.1310 +      sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
410.1311 +      MM_LOG (LOCAL->buf,WARN);
410.1312 +    }
410.1313 +    else *reclaimed += rpos - wpos;
410.1314 +    ret = !fclose (f);		/* close file */
410.1315 +				/* slide down message positions in index */
410.1316 +    for (i = 1,rpos = 0; i <= stream->nmsgs; ++i)
410.1317 +      if ((elt = mail_elt (stream,i))->private.spare.data == burp->fileno) {
410.1318 +	elt->private.special.offset = rpos;
410.1319 +	rpos += elt->private.msg.header.offset + elt->rfc822_size;
410.1320 +      }
410.1321 +				/* debugging */
410.1322 +    if (rpos != wpos) fatal ("burp size consistency check!");
410.1323 +  }
410.1324 +  return ret;
410.1325 +}
410.1326 +
410.1327 +
410.1328 +/* MIX burp sanity check to make sure not burping off end of file
410.1329 + * Accepts: burp set
410.1330 + *	    file size
410.1331 + *	    file name
410.1332 + * Returns: T if sane, NIL if insane
410.1333 + */
410.1334 +
410.1335 +long mix_burp_check (SEARCHSET *set,size_t size,char *file)
410.1336 +{
410.1337 +  do if (set->last > size) {	/* sanity check */
410.1338 +    char tmp[MAILTMPLEN];
410.1339 +    sprintf (tmp,"Unexpected short mix message file %.80s %lu < %lu",
410.1340 +	     file,size,set->last);
410.1341 +    MM_LOG (tmp,ERROR);
410.1342 +    return NIL;			/* don't burp this file at all */
410.1343 +  } while (set = set->next);
410.1344 +  return LONGT;
410.1345 +}
410.1346 +
410.1347 +/* MIX mail copy message(s)
410.1348 + * Accepts: MAIL stream
410.1349 + *	    sequence
410.1350 + *	    destination mailbox
410.1351 + *	    copy options
410.1352 + * Returns: T if copy successful, else NIL
410.1353 + */
410.1354 +
410.1355 +long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
410.1356 +{
410.1357 +  FDDATA d;
410.1358 +  STRING st;
410.1359 +  char tmp[2*MAILTMPLEN];
410.1360 +  long ret = mix_isvalid (mailbox,LOCAL->buf);
410.1361 +  mailproxycopy_t pc =
410.1362 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
410.1363 +  MAILSTREAM *astream = NIL;
410.1364 +  FILE *idxf = NIL;
410.1365 +  FILE *msgf = NIL;
410.1366 +  FILE *statf = NIL;
410.1367 +  if (!ret) switch (errno) {	/* make sure valid mailbox */
410.1368 +  case NIL:			/* no error in stat() */
410.1369 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
410.1370 +    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
410.1371 +    MM_LOG (tmp,ERROR);
410.1372 +    break;
410.1373 +  default:			/* some stat() error */
410.1374 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
410.1375 +    break;
410.1376 +  }
410.1377 +				/* get sequence to copy */
410.1378 +  else if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
410.1379 +		    mail_sequence (stream,sequence))));
410.1380 +				/* acquire stream to append */
410.1381 +  else if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
410.1382 +		  !astream->rdonly &&
410.1383 +		  (((MIXLOCAL *) astream->local)->expok = T) &&
410.1384 +		  (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
410.1385 +	   LONGT : NIL) {
410.1386 +    int fd;
410.1387 +    unsigned long i;
410.1388 +    MESSAGECACHE *elt;
410.1389 +    unsigned long newsize,hdrsize,size;
410.1390 +    MIXLOCAL *local = (MIXLOCAL *) astream->local;
410.1391 +    unsigned long seq = mix_modseq (local->metaseq);
410.1392 +				/* make sure new modseq fits */
410.1393 +    if (local->indexseq > seq) seq = local->indexseq + 1;
410.1394 +    if (local->statusseq > seq) seq = local->statusseq + 1;
410.1395 +				/* calculate size of per-message header */
410.1396 +    sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
410.1397 +    hdrsize = strlen (local->buf);
410.1398 +
410.1399 +    MM_CRITICAL (stream);	/* go critical */
410.1400 +    astream->silent = T;	/* no events here */
410.1401 +				/* calculate size that will be added */
410.1402 +    for (i = 1, newsize = 0; i <= stream->nmsgs; ++i)
410.1403 +      if ((elt = mail_elt (stream,i))->sequence)
410.1404 +	newsize += hdrsize + elt->rfc822_size;
410.1405 +				/* open data file */
410.1406 +    if (msgf = mix_data_open (astream,&fd,&size,newsize)) {
410.1407 +      char *t;
410.1408 +      unsigned long j,uid,uidv;
410.1409 +      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
410.1410 +      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
410.1411 +      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
410.1412 +      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); ++i) 
410.1413 +	if (((elt = mail_elt (stream,i))->sequence) && elt->rfc822_size) {
410.1414 +				/* is message in current message file? */
410.1415 +	  if ((LOCAL->msgfd < 0) ||
410.1416 +	      (elt->private.spare.data != LOCAL->curmsg)) {
410.1417 +	    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
410.1418 +	    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,
410.1419 +						     stream->mailbox,
410.1420 +						     elt->private.spare.data),
410.1421 +				      O_RDONLY,NIL)) >= 0)
410.1422 +	      LOCAL->curmsg = elt->private.spare.data;
410.1423 +	  }
410.1424 +	  if (LOCAL->msgfd < 0) ret = NIL;
410.1425 +	  else {		/* got file */
410.1426 +	    d.fd = LOCAL->msgfd;/* set up file descriptor */
410.1427 +				/* start of message */
410.1428 +	    d.pos = elt->private.special.offset +
410.1429 +	      elt->private.msg.header.offset;
410.1430 +	    d.chunk = LOCAL->buf;
410.1431 +	    d.chunksize = CHUNKSIZE;
410.1432 +	    INIT (&st,fd_string,&d,elt->rfc822_size);
410.1433 +				/* init flag string */
410.1434 +	    tmp[0] = tmp[1] = '\0';
410.1435 +	    if (j = elt->user_flags) do
410.1436 +	      if ((t = stream->user_flags[find_rightmost_bit (&j)]) && *t)
410.1437 +		strcat (strcat (tmp," "),t);
410.1438 +	    while (j);
410.1439 +	    if (elt->seen) strcat (tmp," \\Seen");
410.1440 +	    if (elt->deleted) strcat (tmp," \\Deleted");
410.1441 +	    if (elt->flagged) strcat (tmp," \\Flagged");
410.1442 +	    if (elt->answered) strcat (tmp," \\Answered");
410.1443 +	    if (elt->draft) strcat (tmp," \\Draft");
410.1444 +	    tmp[0] = '(';	/* wrap list */
410.1445 +	    strcat (tmp,")");
410.1446 +				/* if append OK, add to source set */
410.1447 +	    if ((ret = mix_append_msg (astream,msgf,tmp,elt,&st,dest,
410.1448 +				       seq)) &&	source)
410.1449 +	      mail_append_set (source,mail_uid (stream,i));
410.1450 +	  }
410.1451 +	}
410.1452 +
410.1453 +				/* finish write if success */
410.1454 +      if (ret && (ret = !fflush (msgf))) {
410.1455 +	fclose (msgf);		/* all good, close the msg file now */
410.1456 +				/* write new metadata, index, and status */
410.1457 +	local->metaseq = local->indexseq = local->statusseq = seq;
410.1458 +	if (ret = (mix_meta_update (astream) &&
410.1459 +		   mix_index_update (astream,idxf,LONGT))) {
410.1460 +				/* success, delete if doing a move */
410.1461 +	  if (options & CP_MOVE)
410.1462 +	    for (i = 1; i <= stream->nmsgs; i++)
410.1463 +	      if ((elt = mail_elt (stream,i))->sequence) {
410.1464 +		elt->deleted = T;
410.1465 +		if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
410.1466 +		MM_FLAGS (stream,elt->msgno);
410.1467 +	      }
410.1468 +				/* done with status file now */
410.1469 +	  mix_status_update (astream,statf,LONGT);
410.1470 +				/* return sets if doing COPYUID */
410.1471 +	  if (cu) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
410.1472 +	  source = dest = NIL;	/* don't free these sets now */
410.1473 +	}
410.1474 +      }
410.1475 +      else {			/* error */
410.1476 +	if (errno) {		/* output error message if system call error */
410.1477 +	  sprintf (tmp,"Message copy failed: %.80s",strerror (errno));
410.1478 +	  MM_LOG (tmp,ERROR);
410.1479 +	}
410.1480 +	ftruncate (fd,size);	/* revert file */
410.1481 +	close (fd);		/* make sure that fclose doesn't corrupt us */
410.1482 +	fclose (msgf);		/* free the stdio resources */
410.1483 +      }
410.1484 +				/* flush any sets remaining */
410.1485 +      mail_free_searchset (&source);
410.1486 +      mail_free_searchset (&dest);
410.1487 +    }
410.1488 +    else {			/* message file open failed */
410.1489 +      sprintf (tmp,"Error opening copy message file: %.80s",
410.1490 +	       strerror (errno));
410.1491 +      MM_LOG (tmp,ERROR);
410.1492 +      ret = NIL;
410.1493 +    }
410.1494 +    MM_NOCRITICAL (stream);
410.1495 +  }
410.1496 +  else MM_LOG ("Can't open copy mailbox",ERROR);
410.1497 +  if (statf) fclose (statf);	/* close status if still open */
410.1498 +  if (idxf) fclose (idxf);	/* close index if still open */
410.1499 +				/* finished with append stream */
410.1500 +  if (astream) mail_close (astream);
410.1501 +  return ret;			/* return state */
410.1502 +}
410.1503 +
410.1504 +/* MIX mail append message from stringstruct
410.1505 + * Accepts: MAIL stream
410.1506 + *	    destination mailbox
410.1507 + *	    append callback
410.1508 + *	    data for callback
410.1509 + * Returns: T if append successful, else NIL
410.1510 + */
410.1511 +
410.1512 +long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
410.1513 +{
410.1514 +  STRING *message;
410.1515 +  char *flags,*date,tmp[MAILTMPLEN];
410.1516 +				/* N.B.: can't use LOCAL->buf for tmp */
410.1517 +  long ret = mix_isvalid (mailbox,tmp);
410.1518 +				/* default stream to prototype */
410.1519 +  if (!stream) stream = user_flags (&mixproto);
410.1520 +  if (!ret) switch (errno) {	/* if not valid mailbox */
410.1521 +  case ENOENT:			/* no such file? */
410.1522 +    if (ret = compare_cstring (mailbox,"INBOX") ?
410.1523 +	NIL : mix_create (NIL,"INBOX"))
410.1524 +      break;
410.1525 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
410.1526 +    break;
410.1527 +  default:
410.1528 +    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
410.1529 +    MM_LOG (tmp,ERROR);
410.1530 +    break;
410.1531 +  }
410.1532 +
410.1533 +				/* get first message */
410.1534 +  if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) {
410.1535 +    MAILSTREAM *astream;
410.1536 +    FILE *idxf = NIL;
410.1537 +    FILE *msgf = NIL;
410.1538 +    FILE *statf = NIL;
410.1539 +    if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
410.1540 +	       !astream->rdonly &&
410.1541 +	       (((MIXLOCAL *) astream->local)->expok = T) &&
410.1542 +	       (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
410.1543 +	LONGT : NIL) {
410.1544 +      int fd;
410.1545 +      unsigned long size,hdrsize;
410.1546 +      MESSAGECACHE elt;
410.1547 +      MIXLOCAL *local = (MIXLOCAL *) astream->local;
410.1548 +      unsigned long seq = mix_modseq (local->metaseq);
410.1549 +				/* make sure new modseq fits */
410.1550 +      if (local->indexseq > seq) seq = local->indexseq + 1;
410.1551 +      if (local->statusseq > seq) seq = local->statusseq + 1;
410.1552 +				/* calculate size of per-message header */
410.1553 +      sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
410.1554 +      hdrsize = strlen (local->buf);
410.1555 +      MM_CRITICAL (astream);	/* go critical */
410.1556 +      astream->silent = T;	/* no events here */
410.1557 +				/* open data file */
410.1558 +      if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) {
410.1559 +	appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
410.1560 +	SEARCHSET *dst = au ? mail_newsearchset () : NIL;
410.1561 +	while (ret && message) {/* while good to go and have messages */
410.1562 +	  errno = NIL;		/* in case one of these causes failure */
410.1563 +				/* guard against zero-length */
410.1564 +	  if (!(ret = SIZE (message)))
410.1565 +	    MM_LOG ("Append of zero-length message",ERROR);
410.1566 +	  else if (date && !(ret = mail_parse_date (&elt,date))) {
410.1567 +	    sprintf (tmp,"Bad date in append: %.80s",date);
410.1568 +	    MM_LOG (tmp,ERROR);
410.1569 +	  }
410.1570 +	  else {
410.1571 +	    if (!date) {	/* if date not specified, use now */
410.1572 +	      internal_date (tmp);
410.1573 +	      mail_parse_date (&elt,tmp);
410.1574 +	    }
410.1575 +	    ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) &&
410.1576 +	      MM_APPEND (af) (stream,data,&flags,&date,&message);
410.1577 +	  }
410.1578 +	}
410.1579 +
410.1580 +				/* finish write if success */
410.1581 +	if (ret && (ret = !fflush (msgf))) {
410.1582 +	  fclose (msgf);	/* all good, close the msg file now */
410.1583 +				/* write new metadata, index, and status */
410.1584 +	  local->metaseq = local->indexseq = local->statusseq = seq;
410.1585 +	  if ((ret = (mix_meta_update (astream) &&
410.1586 +		      mix_index_update (astream,idxf,LONGT) &&
410.1587 +		      mix_status_update (astream,statf,LONGT))) && au) {
410.1588 +	      (*au) (mailbox,astream->uid_validity,dst);
410.1589 +	      dst = NIL;	/* don't free this set now */
410.1590 +	  }
410.1591 +	}
410.1592 +	else {			/* failure */
410.1593 +	  if (errno) {		/* output error message if system call error */
410.1594 +	    sprintf (tmp,"Message append failed: %.80s",strerror (errno));
410.1595 +	    MM_LOG (tmp,ERROR);
410.1596 +	  }
410.1597 +	  ftruncate (fd,size);	/* revert all writes to file*/
410.1598 +	  close (fd);		/* make sure that fclose doesn't corrupt us */
410.1599 +	  fclose (msgf);	/* free the stdio resources */
410.1600 +	}
410.1601 +				/* flush any set remaining */
410.1602 +	mail_free_searchset (&dst);
410.1603 +      }
410.1604 +      else {			/* message file open failed */
410.1605 +	sprintf (tmp,"Error opening append message file: %.80s",
410.1606 +		 strerror (errno));
410.1607 +	MM_LOG (tmp,ERROR);
410.1608 +	ret = NIL;
410.1609 +      }
410.1610 +      MM_NOCRITICAL (astream);	/* release critical */
410.1611 +    }
410.1612 +    else MM_LOG ("Can't open append mailbox",ERROR);
410.1613 +    if (statf) fclose (statf);	/* close status if still open */
410.1614 +    if (idxf) fclose (idxf);	/* close index if still open */
410.1615 +    if (astream) mail_close (astream);
410.1616 +  }
410.1617 +  return ret;
410.1618 +}
410.1619 +
410.1620 +/* MIX mail append single message
410.1621 + * Accepts: MAIL stream
410.1622 + *	    flags for new message if non-NIL
410.1623 + *	    elt with source date if non-NIL
410.1624 + *	    stringstruct of message text
410.1625 + *	    searchset to place UID
410.1626 + *	    modseq of message
410.1627 + * Returns: T if success, NIL if failure
410.1628 + */
410.1629 +
410.1630 +long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
410.1631 +		     STRING *msg,SEARCHSET *set,unsigned long seq)
410.1632 +{
410.1633 +  MESSAGECACHE *elt;
410.1634 +  int c,cs;
410.1635 +  unsigned long i,j,k,uf,hoff;
410.1636 +  long sf;
410.1637 +  stream->kwd_create = NIL;	/* don't copy unknown keywords */
410.1638 +  sf = mail_parse_flags (stream,flags,&uf);
410.1639 +				/* swell the cache */
410.1640 +  mail_exists (stream,++stream->nmsgs);
410.1641 +				/* assign new UID from metadata */
410.1642 +  (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last;
410.1643 +  elt->private.mod = seq;	/* set requested modseq in status */
410.1644 +  elt->rfc822_size = SIZE (msg);/* copy message size and date to index */
410.1645 +  elt->year = delt->year; elt->month = delt->month; elt->day = delt->day;
410.1646 +  elt->hours = delt->hours; elt->minutes = delt->minutes;
410.1647 +  elt->seconds = delt->seconds; elt->zoccident = delt->zoccident;
410.1648 +  elt->zhours = delt->zhours; elt->zminutes = delt->zminutes;
410.1649 +  /*
410.1650 +   * Do NOT set elt->valid here!  mix_status_update() uses it to determine
410.1651 +   * whether a message should be marked as old.
410.1652 +   */
410.1653 +  if (sf&fSEEN) elt->seen = T;	/* copy flags to status */
410.1654 +  if (sf&fDELETED) elt->deleted = T;
410.1655 +  if (sf&fFLAGGED) elt->flagged = T;
410.1656 +  if (sf&fANSWERED) elt->answered = T;
410.1657 +  if (sf&fDRAFT) elt->draft = T;
410.1658 +  elt->user_flags |= uf;
410.1659 +				/* message is in new message file */
410.1660 +  elt->private.spare.data = LOCAL->newmsg;
410.1661 +
410.1662 +				/* offset to message internal header */
410.1663 +  elt->private.special.offset = ftell (f);
410.1664 +				/* build header for message */
410.1665 +  fprintf (f,MSRFMT,MSGTOK,elt->private.uid,
410.1666 +	   elt->year + BASEYEAR,elt->month,elt->day,
410.1667 +	   elt->hours,elt->minutes,elt->seconds,
410.1668 +	   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
410.1669 +	   elt->rfc822_size);
410.1670 +				/* offset to header from  internal header */
410.1671 +  elt->private.msg.header.offset = ftell (f) - elt->private.special.offset;
410.1672 +  for (cs = 0; SIZE (msg); ) {	/* copy message */
410.1673 +    if (elt->private.msg.header.text.size) {
410.1674 +      if (msg->cursize)		/* blat entire chunk if have it */
410.1675 +	for (j = msg->cursize; j; j -= k)
410.1676 +	  if (!(k = fwrite (msg->curpos,1,j,f))) return NIL;
410.1677 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
410.1678 +    }
410.1679 +    else {			/* still searching for delimiter */
410.1680 +      c = 0xff & SNX (msg);	/* get source character */
410.1681 +      if (putc (c,f) == EOF) return NIL;
410.1682 +      switch (cs) {		/* decide what to do based on state */
410.1683 +      case 0:			/* previous char ordinary */
410.1684 +	if (c == '\015') cs = 1;/* advance if CR */
410.1685 +	break;
410.1686 +      case 1:			/* previous CR, advance if LF */
410.1687 +	cs = (c == '\012') ? 2 : 0;
410.1688 +	break;
410.1689 +      case 2:			/* previous CRLF, advance if CR */
410.1690 +	cs = (c == '\015') ? 3 : 0;
410.1691 +	break;
410.1692 +      case 3:			/* previous CRLFCR, done if LF */
410.1693 +	if (c == '\012') elt->private.msg.header.text.size =
410.1694 +			   elt->rfc822_size - SIZE (msg);
410.1695 +	cs = 0;			/* reset mechanism */
410.1696 +	break;
410.1697 +      }
410.1698 +    }
410.1699 +  }
410.1700 +				/* if no delimiter, header is entire msg */
410.1701 +  if (!elt->private.msg.header.text.size)
410.1702 +    elt->private.msg.header.text.size = elt->rfc822_size;
410.1703 +				/* add this message to set */
410.1704 +  mail_append_set (set,elt->private.uid);
410.1705 +  return LONGT;			/* success */
410.1706 +}
410.1707 +
410.1708 +/* MIX mail read metadata, index, and status
410.1709 + * Accepts: MAIL stream
410.1710 + *	    returned index file
410.1711 + *	    index file flags (non-NIL if want to add/remove messages)
410.1712 + *	    status file flags (non-NIL if want to update elt->valid and old)
410.1713 + * Returns: open status file, or NIL if failure
410.1714 + *
410.1715 + * Note that this routine can return an open index file even if it fails!
410.1716 + */
410.1717 +
410.1718 +static char *shortmsg =
410.1719 +  "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)";
410.1720 +
410.1721 +FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags)
410.1722 +{
410.1723 +  int fd;
410.1724 +  unsigned long i;
410.1725 +  char *s,*t;
410.1726 +  struct stat sbuf;
410.1727 +  FILE *statf = NIL;
410.1728 +  short metarepairneeded = 0;
410.1729 +  short indexrepairneeded = 0;
410.1730 +  short silent = stream->silent;
410.1731 +  *idxf = NIL;			/* in case error */
410.1732 +				/* readonly means no updates */
410.1733 +  if (stream->rdonly) iflags = sflags = NIL;
410.1734 +				/* open index file */
410.1735 +  if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0)
410.1736 +    MM_LOG ("Error opening mix index file",ERROR);
410.1737 +				/* acquire exclusive access and FILE */
410.1738 +  else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) &&
410.1739 +	   !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) {
410.1740 +    MM_LOG ("Error obtaining stream on mix index file",ERROR);
410.1741 +    flock (fd,LOCK_UN);		/* relinquish lock */
410.1742 +    close (fd);
410.1743 +  }
410.1744 +
410.1745 +				/* slurp metadata */
410.1746 +  else if (s = mix_meta_slurp (stream,&i)) {
410.1747 +    unsigned long j = 0;	/* non-zero if UIDVALIDITY/UIDLAST changed */
410.1748 +    if (i != LOCAL->metaseq) {	/* metadata changed? */
410.1749 +      char *t,*k;
410.1750 +      LOCAL->metaseq = i;	/* note new metadata sequence */
410.1751 +      while (s && *s) {		/* parse entire metadata file */
410.1752 +				/* locate end of line */
410.1753 +	if (s = strstr (t = s,"\015\012")) {
410.1754 +	  *s = '\0';		/* tie off line */
410.1755 +	  s += 2;		/* skip past CRLF */
410.1756 +	  switch (*t++) {	/* parse line */
410.1757 +	  case 'V':		/* UIDVALIDITY */
410.1758 +	    if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) {
410.1759 +	      MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR);
410.1760 +	      return NIL;	/* give up */
410.1761 +	    }
410.1762 +	    if (i != stream->uid_validity) j = stream->uid_validity = i;
410.1763 +	    break;
410.1764 +	  case 'L':		/* new UIDLAST */
410.1765 +	    if (!isxdigit (*t)) {
410.1766 +	      MM_LOG ("Error in mix metadata file UIDLAST record",ERROR);
410.1767 +	      return NIL;	/* give up */
410.1768 +	    }
410.1769 +	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
410.1770 +	      j = stream->uid_last = i;
410.1771 +	    break;
410.1772 +	  case 'N':		/* new message file */
410.1773 +	    if (!isxdigit (*t)) {
410.1774 +	      MM_LOG ("Error in mix metadata file new msg record",ERROR);
410.1775 +	      return NIL;	/* give up */
410.1776 +	    }
410.1777 +	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
410.1778 +	      LOCAL->newmsg = i;
410.1779 +	    break;
410.1780 +	  case 'K':		/* new keyword list */
410.1781 +	    for (i = 0; t && *t && (i < NUSERFLAGS); ++i) {
410.1782 +	      if (t = strchr (k = t,' ')) *t++ = '\0';
410.1783 +				/* make sure keyword non-empty */
410.1784 +	      if (*k && (strlen (k) <= MAXUSERFLAG)) {
410.1785 +				/* in case value changes (shouldn't happen) */
410.1786 +		if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){
410.1787 +		  char tmp[MAILTMPLEN];
410.1788 +		  sprintf (tmp,"flag rename old=%.80s new=%.80s",
410.1789 +			   stream->user_flags[i],k);
410.1790 +		  MM_LOG (tmp,WARN);
410.1791 +		  fs_give ((void **) &stream->user_flags[i]);
410.1792 +		}
410.1793 +		if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k);
410.1794 +	      }
410.1795 +	      else break;	/* empty keyword */
410.1796 +	    }
410.1797 +	    if ((i < NUSERFLAGS) && stream->user_flags[i]) {
410.1798 +	      MM_LOG ("Error in mix metadata file keyword record",ERROR);
410.1799 +	      return NIL;	/* give up */
410.1800 +	    }
410.1801 +	    else if (i == NUSERFLAGS) stream->kwd_create = NIL;
410.1802 +	    break;
410.1803 +	  }
410.1804 +	}
410.1805 +	if (t && *t) {		/* junk in line */
410.1806 +	  MM_LOG ("Error in mix metadata record",ERROR);
410.1807 +	  return NIL;		/* give up */
410.1808 +	}
410.1809 +      }
410.1810 +    }
410.1811 +
410.1812 +				/* get sequence */
410.1813 +    if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) {
410.1814 +      MM_LOG ("Error in mix index file sequence record",ERROR);
410.1815 +      return NIL;		/* give up */
410.1816 +    }
410.1817 +				/* sequence changed from last time? */
410.1818 +    else if (j || (i > LOCAL->indexseq)) {
410.1819 +      unsigned long uid,nmsgs,curfile,curfilesize,curpos;
410.1820 +      char *t,*msg,tmp[MAILTMPLEN];
410.1821 +				/* start with no messages */
410.1822 +      curfile = curfilesize = curpos = nmsgs = 0;
410.1823 +				/* update sequence iff expunging OK */
410.1824 +      if (LOCAL->expok) LOCAL->indexseq = i;
410.1825 +				/* get first elt */
410.1826 +      while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) &&
410.1827 +	     *s)
410.1828 +	switch (*s) {
410.1829 +	case ':':		/* message record */
410.1830 +	  if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID";
410.1831 +	  else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) &&
410.1832 +		     isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) &&
410.1833 +		     isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) &&
410.1834 +		     isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) &&
410.1835 +		     isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) &&
410.1836 +		     ((t[14] == '+') || (t[14] == '-')) && 
410.1837 +		     isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) &&
410.1838 +		     isdigit (t[18]))) msg = "internaldate";
410.1839 +	  else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size";
410.1840 +	  else {
410.1841 +	    unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) +
410.1842 +			      ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR;
410.1843 +	    unsigned int m = ((t[4] - '0') * 10) + t[5] - '0';
410.1844 +	    unsigned int d = ((t[6] - '0') * 10) + t[7] - '0';
410.1845 +	    unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0';
410.1846 +	    unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0';
410.1847 +	    unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0';
410.1848 +	    unsigned int z = (t[14] == '-') ? 1 : 0;
410.1849 +	    unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0';
410.1850 +	    unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0';
410.1851 +	    unsigned long size = strtoul (s,&s,16);
410.1852 +	    if ((*s++ == ':') && isxdigit (*s)) {
410.1853 +	      unsigned long file = strtoul (s,&s,16);
410.1854 +	      if ((*s++ == ':') && isxdigit (*s)) {
410.1855 +		unsigned long pos = strtoul (s,&s,16);
410.1856 +		if ((*s++ == ':') && isxdigit (*s)) {
410.1857 +		  unsigned long hpos = strtoul (s,&s,16);
410.1858 +		  if ((*s++ == ':') && isxdigit (*s)) {
410.1859 +		    unsigned long hsiz = strtoul (s,&s,16);
410.1860 +		    if (uid > stream->uid_last) {
410.1861 +		      sprintf (tmp,"mix index invalid UID (%08lx < %08lx)",
410.1862 +			       uid,stream->uid_last);
410.1863 +		      if (stream->rdonly) {
410.1864 +			MM_LOG (tmp,ERROR);
410.1865 +			return NIL;
410.1866 +		      }
410.1867 +		      strcat (tmp,", repaired");
410.1868 +		      MM_LOG (tmp,WARN);
410.1869 +		      stream->uid_last = uid;
410.1870 +		      metarepairneeded = T;
410.1871 +		    }
410.1872 +
410.1873 +				/* ignore expansion values */
410.1874 +		    if (*s++ == ':') {
410.1875 +		      MESSAGECACHE *elt;
410.1876 +		      ++nmsgs;	/* this is another mesage */
410.1877 +				/* within current known range of messages? */
410.1878 +		      while (nmsgs <= stream->nmsgs) {
410.1879 +				/* yes, get corresponding elt */
410.1880 +			elt = mail_elt (stream,nmsgs);
410.1881 +				/* existing message with matching data? */
410.1882 +			if (uid == elt->private.uid) {
410.1883 +				/* beware of Dracula's resurrection */
410.1884 +			  if (elt->private.ghost) {
410.1885 +			    sprintf (tmp,"mix index data unexpunged UID: %lx",
410.1886 +				     uid);
410.1887 +			    MM_LOG (tmp,ERROR);
410.1888 +			    return NIL;
410.1889 +			  }
410.1890 +				/* also of static data changing */
410.1891 +			  if ((size != elt->rfc822_size) ||
410.1892 +			      (file != elt->private.spare.data) ||
410.1893 +			      (pos != elt->private.special.offset) ||
410.1894 +			      (hpos != elt->private.msg.header.offset) ||
410.1895 +			      (hsiz != elt->private.msg.header.text.size) ||
410.1896 +			      (y != elt->year) || (m != elt->month) ||
410.1897 +			      (d != elt->day) || (hh != elt->hours) ||
410.1898 +			      (mm != elt->minutes) || (ss != elt->seconds) ||
410.1899 +			      (z != elt->zoccident) || (zh != elt->zhours) ||
410.1900 +			      (zm != elt->zminutes)) {
410.1901 +			    sprintf (tmp,"mix index data mismatch: %lx",uid);
410.1902 +			    MM_LOG (tmp,ERROR);
410.1903 +			    return NIL;
410.1904 +			  }
410.1905 +			  break;
410.1906 +			}
410.1907 +				/* existing msg with lower UID is expunged */
410.1908 +			else if (uid > elt->private.uid) {
410.1909 +			  if (LOCAL->expok) mail_expunged (stream,nmsgs);
410.1910 +			  else {/* message expunged, but not yet for us */
410.1911 +			    ++nmsgs;
410.1912 +			    elt->private.ghost = T;
410.1913 +			  }
410.1914 +			}
410.1915 +			else {	/* unexpected message record */
410.1916 +			  sprintf (tmp,"mix index UID mismatch (%lx < %lx)",
410.1917 +				   uid,elt->private.uid);
410.1918 +			  MM_LOG (tmp,ERROR);
410.1919 +			  return NIL;
410.1920 +			}
410.1921 +		      }
410.1922 +
410.1923 +				/* time to create a new message? */
410.1924 +		      if (nmsgs > stream->nmsgs) {
410.1925 +				/* defer announcing until later */
410.1926 +			stream->silent = T;
410.1927 +			mail_exists (stream,nmsgs);
410.1928 +			stream->silent = silent;
410.1929 +			(elt = mail_elt (stream,nmsgs))->recent = T;
410.1930 +			elt->private.uid = uid; elt->rfc822_size = size;
410.1931 +			elt->private.spare.data = file;
410.1932 +			elt->private.special.offset = pos;
410.1933 +			elt->private.msg.header.offset = hpos;
410.1934 +			elt->private.msg.header.text.size = hsiz;
410.1935 +			elt->year = y; elt->month = m; elt->day = d;
410.1936 +			elt->hours = hh; elt->minutes = mm;
410.1937 +			elt->seconds = ss; elt->zoccident = z;
410.1938 +			elt->zhours = zh; elt->zminutes = zm;
410.1939 +				/* message in same file? */
410.1940 +			if (curfile == file) {
410.1941 +			  if (pos < curpos) {
410.1942 +			    MESSAGECACHE *plt = mail_elt (stream,elt->msgno-1);
410.1943 +				/* uh-oh, calculate delta? */
410.1944 +			    i = curpos - pos;
410.1945 +			    sprintf (tmp,shortmsg,plt->msgno,plt->private.uid,
410.1946 +				     i,pos,curpos);
410.1947 +				/* possible to fix? */
410.1948 +			    if (!stream->rdonly && LOCAL->expok &&
410.1949 +				(i < plt->rfc822_size)) {
410.1950 +			      plt->rfc822_size -= i;
410.1951 +			      if (plt->rfc822_size <
410.1952 +				  plt->private.msg.header.text.size)
410.1953 +				plt->private.msg.header.text.size =
410.1954 +				  plt->rfc822_size;
410.1955 +			      strcat (tmp,", repaired");
410.1956 +			      indexrepairneeded = T;
410.1957 +			    }
410.1958 +			    MM_LOG (tmp,WARN);
410.1959 +			  }
410.1960 +			}
410.1961 +			else {	/* new file, restart */
410.1962 +			  if (stat (mix_file_data (LOCAL->buf,stream->mailbox,
410.1963 +						   curfile = file),&sbuf)) {
410.1964 +			    sprintf (tmp,"Missing mix data file: %.500s",
410.1965 +				     LOCAL->buf);
410.1966 +			    MM_LOG (tmp,ERROR);
410.1967 +			    return NIL;
410.1968 +			  }
410.1969 +			  curfile = file;
410.1970 +			  curfilesize = sbuf.st_size;
410.1971 +			}
410.1972 +
410.1973 +				/* position of message in file */
410.1974 +			curpos = pos + elt->private.msg.header.offset +
410.1975 +			  elt->rfc822_size;
410.1976 +				/* short file? */
410.1977 +			if (curfilesize < curpos) {
410.1978 +				/* uh-oh, calculate delta? */
410.1979 +			    i = curpos - curfilesize;
410.1980 +			    sprintf (tmp,shortmsg,elt->msgno,elt->private.uid,
410.1981 +				     i,curfilesize,curpos);
410.1982 +				/* possible to fix? */
410.1983 +			    if (!stream->rdonly && LOCAL->expok &&
410.1984 +				(i < elt->rfc822_size)) {
410.1985 +			      elt->rfc822_size -= i;
410.1986 +			      if (elt->rfc822_size <
410.1987 +				  elt->private.msg.header.text.size)
410.1988 +				elt->private.msg.header.text.size =
410.1989 +				  elt->rfc822_size;
410.1990 +			      strcat (tmp,", repaired");
410.1991 +			      indexrepairneeded = T;
410.1992 +			    }
410.1993 +			    MM_LOG (tmp,WARN);
410.1994 +			}
410.1995 +		      }
410.1996 +		      break;
410.1997 +		    }
410.1998 +		    else msg = "expansion";
410.1999 +		  }
410.2000 +		  else msg = "header size";
410.2001 +		}
410.2002 +		else msg = "header position";
410.2003 +	      }
410.2004 +	      else msg = "message position";
410.2005 +	    }
410.2006 +	    else msg = "file#";
410.2007 +	  }
410.2008 +	  sprintf (tmp,"Error in %s in mix index file: %.500s",msg,s);
410.2009 +	  MM_LOG (tmp,ERROR);
410.2010 +	  return NIL;
410.2011 +	default:
410.2012 +	  sprintf (tmp,"Unknown record in mix index file: %.500s",s);
410.2013 +	  MM_LOG (tmp,ERROR);
410.2014 +	  return NIL;
410.2015 +	}
410.2016 +      if (!s) return NIL;	/* barfage from mix_read_record() */
410.2017 +				/* expunge trailing messages not in index */
410.2018 +      if (LOCAL->expok) while (nmsgs < stream->nmsgs)
410.2019 +	mail_expunged (stream,stream->nmsgs);
410.2020 +    }
410.2021 +
410.2022 +				/* repair metadata and index if needed */
410.2023 +    if ((metarepairneeded ? mix_meta_update (stream) : T) &&
410.2024 +	(indexrepairneeded ? mix_index_update (stream,*idxf,NIL) : T)) {
410.2025 +      MESSAGECACHE *elt;
410.2026 +      int fd;
410.2027 +      unsigned long uid,uf,sf,mod;
410.2028 +      char *s;
410.2029 +      int updatep = NIL;
410.2030 +				/* open status file */
410.2031 +      if ((fd = open (LOCAL->status,
410.2032 +		      stream->rdonly ? O_RDONLY : O_RDWR,NIL)) < 0)
410.2033 +	MM_LOG ("Error opening mix status file",ERROR);
410.2034 +				/* acquire exclusive access and FILE */
410.2035 +      else if (!flock (fd,stream->rdonly ? LOCK_SH : LOCK_EX) &&
410.2036 +	       !(statf = fdopen (fd,stream->rdonly ? "rb" : "r+b"))) {
410.2037 +	MM_LOG ("Error obtaining stream on mix status file",ERROR);
410.2038 +	flock (fd,LOCK_UN);	/* relinquish lock */
410.2039 +	close (fd);
410.2040 +      }
410.2041 +				/* get sequence */
410.2042 +      else if (!(i = mix_read_sequence (statf)) ||
410.2043 +	       ((i < LOCAL->statusseq) && stream->nmsgs && (i != 1))) {
410.2044 +	sprintf (LOCAL->buf,
410.2045 +		 "Error in mix status sequence record, i=%lx, seq=%lx",
410.2046 +		 i,LOCAL->statusseq);
410.2047 +	MM_LOG (LOCAL->buf,ERROR);
410.2048 +      }
410.2049 +				/* sequence changed from last time? */
410.2050 +      else if (i != LOCAL->statusseq) {
410.2051 +				/* update sequence, get first elt */
410.2052 +	if (i > LOCAL->statusseq) LOCAL->statusseq = i;
410.2053 +	if (stream->nmsgs) {
410.2054 +	  elt = mail_elt (stream,i = 1);
410.2055 +
410.2056 +				/* read message records */
410.2057 +	  while ((t = s = mix_read_record (statf,LOCAL->buf,LOCAL->buflen,
410.2058 +					   "status")) && *s && (*s++ == ':') &&
410.2059 +		 isxdigit (*s)) {
410.2060 +	    uid = strtoul (s,&s,16);
410.2061 +	    if ((*s++ == ':') && isxdigit (*s)) {
410.2062 +	      uf = strtoul (s,&s,16);
410.2063 +	      if ((*s++ == ':') && isxdigit (*s)) {
410.2064 +		sf = strtoul (s,&s,16);
410.2065 +		if ((*s++ == ':') && isxdigit (*s)) {
410.2066 +		  mod = strtoul (s,&s,16);
410.2067 +				/* ignore expansion values */
410.2068 +		  if (*s++ == ':') {
410.2069 +				/* need to move ahead to next elt? */
410.2070 +		    while ((uid > elt->private.uid) && (i < stream->nmsgs))
410.2071 +		      elt = mail_elt (stream,++i);
410.2072 +				/* update elt if altered */
410.2073 +		    if ((uid == elt->private.uid) &&
410.2074 +			(!elt->valid || (mod != elt->private.mod))) {
410.2075 +		      elt->user_flags = uf;
410.2076 +		      elt->private.mod = mod;
410.2077 +		      elt->seen = (sf & fSEEN) ? T : NIL;
410.2078 +		      elt->deleted = (sf & fDELETED) ? T : NIL;
410.2079 +		      elt->flagged = (sf & fFLAGGED) ? T : NIL;
410.2080 +		      elt->answered = (sf & fANSWERED) ? T : NIL;
410.2081 +		      elt->draft = (sf & fDRAFT) ? T : NIL;
410.2082 +				/* announce if altered existing message */
410.2083 +		      if (elt->valid) MM_FLAGS (stream,elt->msgno);
410.2084 +				/* first time, is old message? */
410.2085 +		      else if (sf & fOLD) {
410.2086 +				/* yes, clear recent and set valid */
410.2087 +			elt->recent = NIL;
410.2088 +			elt->valid = T;
410.2089 +		      }
410.2090 +				/* recent, allowed to update its status? */
410.2091 +		      else if (sflags) {
410.2092 +				/* yes, set valid and check in status */
410.2093 +			elt->valid = T;
410.2094 +			elt->private.mod = mix_modseq (elt->private.mod);
410.2095 +			updatep = T;
410.2096 +		      }
410.2097 +		      /* leave valid unset and recent if sflags not set */
410.2098 +		    }
410.2099 +		    continue;	/* everything looks good */
410.2100 +		  }
410.2101 +		}
410.2102 +	      }
410.2103 +	    }
410.2104 +	    break;		/* error somewhere */
410.2105 +	  }
410.2106 +
410.2107 +	  if (t && *t) {	/* non-null means bogus record */
410.2108 +	    char msg[MAILTMPLEN];
410.2109 +	    sprintf (msg,"Error in mix status file message record%s: %.80s",
410.2110 +		     stream->rdonly ? "" : ", fixing",t);
410.2111 +	    MM_LOG (msg,WARN);
410.2112 +				/* update it if not readonly */
410.2113 +	    if (!stream->rdonly) updatep = T;
410.2114 +	  }
410.2115 +	  if (updatep) {		/* need to update? */
410.2116 +	    LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
410.2117 +	    mix_status_update (stream,statf,LONGT);
410.2118 +	  }
410.2119 +	}
410.2120 +      }
410.2121 +    }
410.2122 +  }
410.2123 +  if (statf) {			/* still happy? */
410.2124 +    unsigned long j;
410.2125 +    stream->silent = silent;	/* now notify upper level */
410.2126 +    mail_exists (stream,stream->nmsgs);
410.2127 +    for (i = 1, j = 0; i <= stream->nmsgs; ++i)
410.2128 +      if (mail_elt (stream,i)->recent) ++j;
410.2129 +    mail_recent (stream,j);
410.2130 +  }
410.2131 +  return statf;
410.2132 +}
410.2133 +
410.2134 +/* MIX metadata file routines */
410.2135 +
410.2136 +/* MIX read metadata
410.2137 + * Accepts: MAIL stream
410.2138 + *	    return pointer for modseq
410.2139 + * Returns: pointer to metadata after modseq or NIL if failure
410.2140 + */
410.2141 +
410.2142 +char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq)
410.2143 +{
410.2144 +  struct stat sbuf;
410.2145 +  char *s;
410.2146 +  char *ret = NIL;
410.2147 +  if (fstat (LOCAL->mfd,&sbuf))
410.2148 +    MM_LOG ("Error obtaining size of mix metatdata file",ERROR);
410.2149 +  if (sbuf.st_size > LOCAL->buflen) {
410.2150 +				/* should be just a few dozen bytes */
410.2151 +    if (sbuf.st_size > METAMAX) fatal ("absurd mix metadata file size");
410.2152 +    fs_give ((void **) &LOCAL->buf);
410.2153 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1);
410.2154 +  }
410.2155 +				/* read current metadata file */
410.2156 +  LOCAL->buf[sbuf.st_size] = '\0';
410.2157 +  if (lseek (LOCAL->mfd,0,L_SET) ||
410.2158 +      (read (LOCAL->mfd,s = LOCAL->buf,sbuf.st_size) != sbuf.st_size))
410.2159 +    MM_LOG ("Error reading mix metadata file",ERROR);
410.2160 +  else if ((*s != 'S') || !isxdigit (s[1]) ||
410.2161 +	   ((*seq = strtoul (s+1,&s,16)) < LOCAL->metaseq) ||
410.2162 +	   (*s++ != '\015') || (*s++ != '\012'))
410.2163 +    MM_LOG ("Error in mix metadata file sequence record",ERROR);
410.2164 +  else ret = s;
410.2165 +  return ret;
410.2166 +}
410.2167 +
410.2168 +/* MIX update metadata
410.2169 + * Accepts: MAIL stream
410.2170 + * Returns: T on success, NIL if error
410.2171 + *
410.2172 + * Index MUST be locked!!
410.2173 + */
410.2174 +
410.2175 +long mix_meta_update (MAILSTREAM *stream)
410.2176 +{
410.2177 +  long ret;
410.2178 +				/* do nothing if stream readonly */
410.2179 +  if (stream->rdonly) ret = LONGT;
410.2180 +  else {
410.2181 +    unsigned char c,*s,*ss,*t;
410.2182 +    unsigned long i;
410.2183 +    /* The worst-case metadata is limited to:
410.2184 +     *    4 * (1 + 8 + 2) + (NUSERFLAGS * (MAXUSERFLAG + 1))
410.2185 +     * which comes out to 1994 octets.  This is much smaller than the normal
410.2186 +     * CHUNKSIZE definition of 64K, and CHUNKSIZE is the smallest size of
410.2187 +     * LOCAL->buf.
410.2188 +     *
410.2189 +     * If more stuff gets added to the metadata, or if you change the value
410.2190 +     * of NUSERFLAGS, MAXUSERFLAG or CHUNKSIZE, be sure to recalculate the
410.2191 +     * above assertation.
410.2192 +     */
410.2193 +    sprintf (LOCAL->buf,SEQFMT,LOCAL->metaseq = mix_modseq (LOCAL->metaseq));
410.2194 +    sprintf (LOCAL->buf + strlen (LOCAL->buf),MTAFMT,
410.2195 +	     stream->uid_validity,stream->uid_last,LOCAL->newmsg);
410.2196 +    for (i = 0, c = 'K', s = ss = LOCAL->buf + strlen (LOCAL->buf);
410.2197 +	 (i < NUSERFLAGS) && (t = stream->user_flags[i]); ++i) {
410.2198 +      if (!*t) fatal ("impossible empty keyword");
410.2199 +      *s++ = c;			/* write delimiter */
410.2200 +      while (*t) *s++ = *t++;	/* write keyword */
410.2201 +      c = ' ';			/* delimiter is now space */
410.2202 +    }
410.2203 +    if (s != ss) {		/* tie off keywords line */
410.2204 +      *s++ = '\015'; *s++ = '\012';
410.2205 +    }
410.2206 +				/* calculate length of metadata */
410.2207 +    if ((i = s - LOCAL->buf) > LOCAL->buflen)
410.2208 +      fatal ("impossible buffer overflow");
410.2209 +    lseek (LOCAL->mfd,0,L_SET);	/* rewind file */
410.2210 +				/* write new metadata */
410.2211 +    ret = (write (LOCAL->mfd,LOCAL->buf,i) == i) ? LONGT : NIL;
410.2212 +    ftruncate (LOCAL->mfd,i);	/* and tie off at that point */
410.2213 +  }
410.2214 +  return ret;
410.2215 +}
410.2216 +
410.2217 +/* MIX index file routines */
410.2218 +
410.2219 +
410.2220 +/* MIX update index
410.2221 + * Accepts: MAIL stream
410.2222 + *	    open FILE
410.2223 + *	    expansion check flag
410.2224 + * Returns: T on success, NIL if error
410.2225 + */
410.2226 +
410.2227 +long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag)
410.2228 +{
410.2229 +  unsigned long i;
410.2230 +  long ret = LONGT;
410.2231 +  if (!stream->rdonly) {	/* do nothing if stream readonly */
410.2232 +    if (flag) {			/* need to do expansion check? */
410.2233 +      char tmp[MAILTMPLEN];
410.2234 +      size_t size;
410.2235 +      struct stat sbuf;
410.2236 +				/* calculate file size we need */
410.2237 +      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
410.2238 +	if (!mail_elt (stream,i)->private.ghost) ++size;
410.2239 +      if (size) {		/* Winston Smith's first dairy entry */
410.2240 +	sprintf (tmp,IXRFMT,0,14,4,4,13,0,0,'+',0,0,0,0,0,0,0);
410.2241 +	size *= strlen (tmp);
410.2242 +      }
410.2243 +				/* calculate file size we need */
410.2244 +      sprintf (tmp,SEQFMT,LOCAL->indexseq);
410.2245 +      size += strlen (tmp);
410.2246 +				/* get current file size */
410.2247 +      if (fstat (fileno (idxf),&sbuf)) {
410.2248 +	MM_LOG ("Error getting size of mix index file",ERROR);
410.2249 +	ret = NIL;
410.2250 +      }
410.2251 +				/* need to write additional space? */
410.2252 +      else if (sbuf.st_size < size) {
410.2253 +	void *buf = fs_get (size -= sbuf.st_size);
410.2254 +	memset (buf,0,size);
410.2255 +	if (fseek (idxf,0,SEEK_END) || (fwrite (buf,1,size,idxf) != size) ||
410.2256 +	    fflush (idxf)) {
410.2257 +	  fseek (idxf,sbuf.st_size,SEEK_SET);
410.2258 +	  ftruncate (fileno (idxf),sbuf.st_size);
410.2259 +	  MM_LOG ("Error extending mix index file",ERROR);
410.2260 +	  ret = NIL;
410.2261 +	}
410.2262 +	fs_give ((void **) &buf);
410.2263 +      }
410.2264 +    }
410.2265 +
410.2266 +    if (ret) {			/* if still good to go */
410.2267 +      rewind (idxf);		/* let's start at the very beginning */
410.2268 +				/* write modseq first */
410.2269 +      fprintf (idxf,SEQFMT,LOCAL->indexseq);
410.2270 +				/* then write all messages */
410.2271 +      for (i = 1; ret && (i <= stream->nmsgs); i++) {
410.2272 +	MESSAGECACHE *elt = mail_elt (stream,i);
410.2273 +	if (!elt->private.ghost)/* only write living messages */
410.2274 +	  fprintf (idxf,IXRFMT,elt->private.uid,
410.2275 +		   elt->year + BASEYEAR,elt->month,elt->day,
410.2276 +		   elt->hours,elt->minutes,elt->seconds,
410.2277 +		   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
410.2278 +		   elt->rfc822_size,elt->private.spare.data,
410.2279 +		   elt->private.special.offset,
410.2280 +		   elt->private.msg.header.offset,
410.2281 +		   elt->private.msg.header.text.size);
410.2282 +	if (ferror (idxf)) {
410.2283 +	  MM_LOG ("Error updating mix index file",ERROR);
410.2284 +	  ret = NIL;
410.2285 +	}
410.2286 +      }
410.2287 +      if (fflush (idxf)) {
410.2288 +	MM_LOG ("Error flushing mix index file",ERROR);
410.2289 +	ret = NIL;
410.2290 +      }
410.2291 +      if (ret) ftruncate (fileno (idxf),ftell (idxf));
410.2292 +    }
410.2293 +  }
410.2294 +  return ret;
410.2295 +}
410.2296 +
410.2297 +/* MIX status file routines */
410.2298 +
410.2299 +
410.2300 +/* MIX update status
410.2301 + * Accepts: MAIL stream
410.2302 + *	    pointer to open FILE
410.2303 + *	    expansion check flag
410.2304 + * Returns: T on success, NIL if error
410.2305 + */
410.2306 +
410.2307 +long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag)
410.2308 +{
410.2309 +  unsigned long i;
410.2310 +  char tmp[MAILTMPLEN];
410.2311 +  long ret = LONGT;
410.2312 +  if (!stream->rdonly) {	/* do nothing if stream readonly */
410.2313 +    if (flag) {			/* need to do expansion check? */
410.2314 +      char tmp[MAILTMPLEN];
410.2315 +      size_t size;
410.2316 +      struct stat sbuf;
410.2317 +				/* calculate file size we need */
410.2318 +      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
410.2319 +	if (!mail_elt (stream,i)->private.ghost) ++size;
410.2320 +      if (size) {		/* number of living messages */
410.2321 +	sprintf (tmp,STRFMT,0,0,0,0);
410.2322 +	size *= strlen (tmp);
410.2323 +      }
410.2324 +      sprintf (tmp,SEQFMT,LOCAL->statusseq);
410.2325 +      size += strlen (tmp);
410.2326 +				/* get current file size */
410.2327 +      if (fstat (fileno (statf),&sbuf)) {
410.2328 +	MM_LOG ("Error getting size of mix status file",ERROR);
410.2329 +	ret = NIL;
410.2330 +      }
410.2331 +				/* need to write additional space? */
410.2332 +      else if (sbuf.st_size < size) {
410.2333 +	void *buf = fs_get (size -= sbuf.st_size);
410.2334 +	memset (buf,0,size);
410.2335 +	if (fseek (statf,0,SEEK_END) || (fwrite (buf,1,size,statf) != size) ||
410.2336 +	    fflush (statf)) {
410.2337 +	  fseek (statf,sbuf.st_size,SEEK_SET);
410.2338 +	  ftruncate (fileno (statf),sbuf.st_size);
410.2339 +	  MM_LOG ("Error extending mix status file",ERROR);
410.2340 +	  ret = NIL;
410.2341 +	}
410.2342 +	fs_give ((void **) &buf);
410.2343 +      }
410.2344 +    }
410.2345 +
410.2346 +    if (ret) {			/* if still good to go */
410.2347 +      rewind (statf);		/* let's start at the very beginning */
410.2348 +				/* write sequence */
410.2349 +      fprintf (statf,SEQFMT,LOCAL->statusseq);
410.2350 +				/* write message status records */
410.2351 +      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
410.2352 +	MESSAGECACHE *elt = mail_elt (stream,i);
410.2353 +				/* make sure all messages have a modseq */
410.2354 +	if (!elt->private.mod) elt->private.mod = LOCAL->statusseq;
410.2355 +	if (!elt->private.ghost)/* only write living messages */
410.2356 +	  fprintf (statf,STRFMT,elt->private.uid,elt->user_flags,
410.2357 +		   (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
410.2358 +		   (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
410.2359 +		   (fDRAFT * elt->draft) + (elt->valid ? fOLD : NIL),
410.2360 +		   elt->private.mod);
410.2361 +	if (ferror (statf)) {
410.2362 +	  sprintf (tmp,"Error updating mix status file: %.80s",
410.2363 +		   strerror (errno));
410.2364 +	  MM_LOG (tmp,ERROR);
410.2365 +	  ret = NIL;
410.2366 +	}
410.2367 +      }
410.2368 +      if (ret && fflush (statf)) {
410.2369 +	MM_LOG ("Error flushing mix status file",ERROR);
410.2370 +	ret = NIL;
410.2371 +      }
410.2372 +      if (ret) ftruncate (fileno (statf),ftell (statf));
410.2373 +    }
410.2374 +  }
410.2375 +  return ret;
410.2376 +}
410.2377 +
410.2378 +/* MIX data file routines */
410.2379 +
410.2380 +
410.2381 +/* MIX open data file
410.2382 + * Accepts: MAIL stream
410.2383 + *	    pointer to returned fd if success
410.2384 + *	    pointer to returned size if success
410.2385 + *	    size of new data to be added
410.2386 + * Returns: open FILE, or NIL if failure
410.2387 + *
410.2388 + * The curend test assumes that the last message of the mailbox is the furthest
410.2389 + * point that the current data file extends, and thus that is all that needs to
410.2390 + * be tested for short file prevention.
410.2391 + */
410.2392 +
410.2393 +FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
410.2394 +		     unsigned long newsize)
410.2395 +{
410.2396 +  FILE *msgf = NIL;
410.2397 +  struct stat sbuf;
410.2398 +  MESSAGECACHE *elt = stream->nmsgs ? mail_elt (stream,stream->nmsgs) : NIL;
410.2399 +  unsigned long curend = (elt && (elt->private.spare.data == LOCAL->newmsg)) ?
410.2400 +    elt->private.special.offset + elt->private.msg.header.offset +
410.2401 +    elt->rfc822_size : 0;
410.2402 +				/* allow create if curend 0 */
410.2403 +  if ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox,LOCAL->newmsg),
410.2404 +		   O_RDWR | (curend ? NIL : O_CREAT),NIL)) >= 0) {
410.2405 +    fstat (*fd,&sbuf);		/* get current file size */
410.2406 +				/* can we use this file? */
410.2407 +    if ((curend <= sbuf.st_size) &&
410.2408 +	(!sbuf.st_size || ((sbuf.st_size + newsize) <= MIXDATAROLL)))
410.2409 +      *size = sbuf.st_size;	/* yes, return current size */
410.2410 +    else {			/* short file or becoming too long */
410.2411 +      if (curend > sbuf.st_size) {
410.2412 +	char tmp[MAILTMPLEN];
410.2413 +	sprintf (tmp,"short mix message file %.08lx (%ld > %ld), rolling",
410.2414 +		 LOCAL->newmsg,curend,sbuf.st_size);
410.2415 +	MM_LOG (tmp,WARN);	/* shouldn't happen */
410.2416 +      }
410.2417 +      close (*fd);		/* roll to a new file */
410.2418 +      while ((*fd = open (mix_file_data
410.2419 +			  (LOCAL->buf,stream->mailbox,
410.2420 +			   LOCAL->newmsg = mix_modseq (LOCAL->newmsg)),
410.2421 +			  O_RDWR | O_CREAT | O_EXCL,sbuf.st_mode)) < 0);
410.2422 +      *size = 0;		/* brand new file */
410.2423 +      fchmod (*fd,sbuf.st_mode);/* with same mode as previous file */
410.2424 +    }
410.2425 +  }
410.2426 +  if (*fd >= 0) {		/* have a data file? */
410.2427 +				/* yes, get stdio and set position */
410.2428 +    if (msgf = fdopen (*fd,"r+b")) fseek (msgf,*size,SEEK_SET);
410.2429 +    else close (*fd);		/* fdopen() failed? */
410.2430 +  }
410.2431 +  return msgf;			/* return results */
410.2432 +}
410.2433 +
410.2434 +/* MIX open sortcache
410.2435 + * Accepts: MAIL stream
410.2436 + * Returns: open FILE, or NIL if failure or could only get readonly sortcache
410.2437 + */
410.2438 +
410.2439 +FILE *mix_sortcache_open (MAILSTREAM *stream)
410.2440 +{
410.2441 +  int fd,refwd;
410.2442 +  unsigned long i,uid,sentdate,fromlen,tolen,cclen,subjlen,msgidlen,reflen;
410.2443 +  char *s,*t,*msg,tmp[MAILTMPLEN];
410.2444 +  MESSAGECACHE *elt;
410.2445 +  SORTCACHE *sc;
410.2446 +  STRINGLIST *sl;
410.2447 +  struct stat sbuf;
410.2448 +  int rdonly = NIL;
410.2449 +  FILE *srtcf = NIL;
410.2450 +  mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
410.2451 +  fstat (LOCAL->mfd,&sbuf);
410.2452 +  if (!stream->nmsgs);		/* do nothing if mailbox empty */
410.2453 +				/* open sortcache file */
410.2454 +  else if (((fd = open (LOCAL->sortcache,O_RDWR|O_CREAT,sbuf.st_mode)) < 0) &&
410.2455 +	   !(rdonly = ((fd = open (LOCAL->sortcache,O_RDONLY,NIL)) >= 0)))
410.2456 +    MM_LOG ("Error opening mix sortcache file",WARN);
410.2457 +				/* acquire lock and FILE */
410.2458 +  else if (!flock (fd,rdonly ? LOCK_SH : LOCK_EX) &&
410.2459 +	   !(srtcf = fdopen (fd,rdonly ? "rb" : "r+b"))) {
410.2460 +    MM_LOG ("Error obtaining stream on mix sortcache file",WARN);
410.2461 +    flock (fd,LOCK_UN);		/* relinquish lock */
410.2462 +    close (fd);
410.2463 +  }
410.2464 +  else if (!(i = mix_read_sequence (srtcf)) || (i < LOCAL->sortcacheseq))
410.2465 +    MM_LOG ("Error in mix sortcache file sequence record",WARN);
410.2466 +				/* sequence changed from last time? */
410.2467 +  else if (i > LOCAL->sortcacheseq) {
410.2468 +    LOCAL->sortcacheseq = i;	/* update sequence */
410.2469 +    while ((s = t = mix_read_record (srtcf,LOCAL->buf,LOCAL->buflen,
410.2470 +				     "sortcache")) && *s &&
410.2471 +	   (msg = "uid") && (*s++ == ':') && isxdigit (*s)) {
410.2472 +      uid = strtoul (s,&s,16);
410.2473 +      if ((*s++ == ':') && isxdigit (*s)) {
410.2474 +	sentdate = strtoul (s,&s,16);
410.2475 +	if ((*s++ == ':') && isxdigit (*s)) {
410.2476 +	  fromlen = strtoul (s,&s,16);
410.2477 +	  if ((*s++ == ':') && isxdigit (*s)) {
410.2478 +	    tolen = strtoul (s,&s,16);
410.2479 +	    if ((*s++ == ':') && isxdigit (*s)) {
410.2480 +	      cclen = strtoul (s,&s,16);
410.2481 +	      if ((*s++ == ':') && ((*s == 'R') || (*s == ' ')) &&
410.2482 +		  isxdigit (s[1])) {
410.2483 +		refwd = (*s++ == 'R') ? T : NIL;
410.2484 +		subjlen = strtoul (s,&s,16);
410.2485 +		if ((*s++ == ':') && isxdigit (*s)) {
410.2486 +		  msgidlen = strtoul (s,&s,16);
410.2487 +		  if ((*s++ == ':') && isxdigit (*s)) {
410.2488 +		    reflen = strtoul (s,&s,16);
410.2489 +				/* ignore expansion values */
410.2490 +		    if (*s++ == ':') {
410.2491 +
410.2492 +		      if (i = mail_msgno (stream,uid)) {
410.2493 +			sc = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
410.2494 +			sc->size = (elt = mail_elt (stream,i))->rfc822_size;
410.2495 +			sc->date = sentdate;
410.2496 +			sc->arrival = elt->day ? mail_longdate (elt) : 1;
410.2497 +			if (refwd) sc->refwd = T;
410.2498 +			if (fromlen) {
410.2499 +			  if (sc->from) fseek (srtcf,fromlen + 2,SEEK_CUR);
410.2500 +			  else if ((getc (srtcf) != 'F') ||
410.2501 +				   (fread (sc->from = (char *) fs_get(fromlen),
410.2502 +					   1,fromlen-1,srtcf) != (fromlen-1))||
410.2503 +				   (sc->from[fromlen-1] = '\0') ||
410.2504 +				   (getc (srtcf) != '\015') ||
410.2505 +				   (getc (srtcf) != '\012')) {
410.2506 +			    msg = "from data";
410.2507 +			    break;
410.2508 +			  }
410.2509 +			}
410.2510 +			if (tolen) {
410.2511 +			  if (sc->to) fseek (srtcf,tolen + 2,SEEK_CUR);
410.2512 +			  else if ((getc (srtcf) != 'T') ||
410.2513 +				   (fread (sc->to = (char *) fs_get (tolen),
410.2514 +					   1,tolen-1,srtcf) != (tolen - 1)) ||
410.2515 +				   (sc->to[tolen-1] = '\0') ||
410.2516 +				   (getc (srtcf) != '\015') ||
410.2517 +				   (getc (srtcf) != '\012')) {
410.2518 +			    msg = "to data";
410.2519 +			    break;
410.2520 +			  }
410.2521 +			}
410.2522 +			if (cclen) {
410.2523 +			  if (sc->cc) fseek (srtcf,cclen + 2,SEEK_CUR);
410.2524 +			  else if ((getc (srtcf) != 'C') ||
410.2525 +				   (fread (sc->cc = (char *) fs_get (cclen),
410.2526 +					   1,cclen-1,srtcf) != (cclen - 1)) ||
410.2527 +				   (sc->cc[cclen-1] = '\0') ||
410.2528 +				   (getc (srtcf) != '\015') ||
410.2529 +				   (getc (srtcf) != '\012')) {
410.2530 +			    msg = "cc data";
410.2531 +			    break;
410.2532 +			  }
410.2533 +			}
410.2534 +			if (subjlen) {
410.2535 +			  if (sc->subject) fseek (srtcf,subjlen + 2,SEEK_CUR);
410.2536 +			  else if ((getc (srtcf) != 'S') ||
410.2537 +				     (fread (sc->subject =
410.2538 +					     (char *) fs_get (subjlen),1,
410.2539 +					     subjlen-1,srtcf) != (subjlen-1))||
410.2540 +				   (sc->subject[subjlen-1] = '\0') ||
410.2541 +				   (getc (srtcf) != '\015') ||
410.2542 +				   (getc (srtcf) != '\012')) {
410.2543 +			    msg = "subject data";
410.2544 +			    break;
410.2545 +			  }
410.2546 +			}
410.2547 +
410.2548 +			if (msgidlen) {
410.2549 +			  if (sc->message_id)
410.2550 +			    fseek (srtcf,msgidlen + 2,SEEK_CUR);
410.2551 +			  else if ((getc (srtcf) != 'M') ||
410.2552 +				   (fread (sc->message_id = 
410.2553 +					   (char *) fs_get (msgidlen),1,
410.2554 +					   msgidlen-1,srtcf) != (msgidlen-1))||
410.2555 +				   (sc->message_id[msgidlen-1] = '\0') ||
410.2556 +				   (getc (srtcf) != '\015') ||
410.2557 +				   (getc (srtcf) != '\012')) {
410.2558 +			    msg = "message-id data";
410.2559 +			    break;
410.2560 +			  }
410.2561 +			}
410.2562 +			if (reflen) {
410.2563 +			  if (sc->references) fseek(srtcf,reflen + 2,SEEK_CUR);
410.2564 +				/* make sure it fits */
410.2565 +			  else {
410.2566 +			    if (reflen >= LOCAL->buflen) {
410.2567 +			      fs_give ((void **) &LOCAL->buf);
410.2568 +			      LOCAL->buf = (char *)
410.2569 +				fs_get ((LOCAL->buflen = reflen) + 1);
410.2570 +			      }
410.2571 +			    if ((getc (srtcf) != 'R') ||
410.2572 +				(fread (LOCAL->buf,1,reflen-1,srtcf) !=
410.2573 +				 (reflen - 1)) ||
410.2574 +				(LOCAL->buf[reflen-1] = '\0') ||
410.2575 +				(getc (srtcf) != '\015') ||
410.2576 +				(getc (srtcf) != '\012')) {
410.2577 +			      msg = "references data";
410.2578 +			      break;
410.2579 +			    }
410.2580 +			    for (s = LOCAL->buf,sl = NIL,
410.2581 +				   sc->references = mail_newstringlist ();
410.2582 +				 s && *s; s += i + 1) {
410.2583 +			      if ((i = strtoul (s,&s,16)) && (*s++ == ':') &&
410.2584 +				  (s[i] == ':')) {
410.2585 +				if (sl) sl = sl->next = mail_newstringlist();
410.2586 +				else sl = sc->references;
410.2587 +				s[i] = '\0';
410.2588 +				sl->text.data = cpystr (s);
410.2589 +				sl->text.size = i;
410.2590 +			      }
410.2591 +			      else s = NIL;
410.2592 +			    }
410.2593 +			    if (!s || *s ||
410.2594 +				(s != ((char *) LOCAL->buf + reflen - 1))) {
410.2595 +			      msg = "references length consistency check";
410.2596 +			      break;
410.2597 +			    }
410.2598 +			  }
410.2599 +			}
410.2600 +		      }
410.2601 +
410.2602 +				/* UID not found, ignore this message */
410.2603 +		      else fseek (srtcf,((fromlen ? fromlen + 2 : 0) +
410.2604 +					 (tolen ? tolen + 2 : 0) +
410.2605 +					 (cclen ? cclen + 2 : 0) +
410.2606 +					 (subjlen ? subjlen + 2 : 0) +
410.2607 +					 (msgidlen ? msgidlen + 2 : 0) +
410.2608 +					 (reflen ? reflen + 2 : 0)),
410.2609 +				  SEEK_CUR);
410.2610 +		      continue;
410.2611 +		    }
410.2612 +		    else msg = "expansion";
410.2613 +		  }
410.2614 +		  else msg = "references";
410.2615 +		}
410.2616 +		else msg = "message-id";
410.2617 +	      }
410.2618 +	      else msg = "subject";
410.2619 +	    }
410.2620 +	    else msg = "cc";
410.2621 +	  }
410.2622 +	  else msg = "to";
410.2623 +	}
410.2624 +	else msg = "from";
410.2625 +      }
410.2626 +      else msg = "sentdate";
410.2627 +      break;			/* error somewhere */
410.2628 +    }
410.2629 +    if (!t || *t) {		/* error detected? */
410.2630 +      if (t) {			/* non-null means bogus record */
410.2631 +	sprintf (tmp,"Error in %s in mix sortcache record: %.500s",msg,t);
410.2632 +	MM_LOG (tmp,WARN);
410.2633 +      }
410.2634 +      fclose (srtcf);		/* either way, must punt */
410.2635 +      srtcf = NIL;
410.2636 +    }
410.2637 +  }
410.2638 +  if (rdonly && srtcf) {	/* can't update if readonly */
410.2639 +    unlink (LOCAL->sortcache);	/* try deleting it */
410.2640 +    fclose (srtcf);		/* so close it and return as if error */
410.2641 +    srtcf = NIL;
410.2642 +  }
410.2643 +  else fchmod (fd,sbuf.st_mode);
410.2644 +  return srtcf;
410.2645 +}
410.2646 +
410.2647 +/* MIX update and close sortcache
410.2648 + * Accepts: MAIL stream
410.2649 + *	    pointer to open FILE (if FILE is NIL, do nothing)
410.2650 + * Returns: T on success, NIL on error
410.2651 + */
410.2652 +
410.2653 +long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache)
410.2654 +{
410.2655 +  FILE *f = *sortcache;
410.2656 +  long ret = LONGT;
410.2657 +  if (f) {			/* ignore if no file */
410.2658 +    unsigned long i,j;
410.2659 +    mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
410.2660 +    for (i = 1; (i <= stream->nmsgs) &&
410.2661 +	   !((SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE))->dirty; ++i);
410.2662 +    if (i <= stream->nmsgs) {	/* only update if some entry is dirty */
410.2663 +      rewind (f);		/* let's start at the very beginning */
410.2664 +				/* write sequence */
410.2665 +      fprintf (f,SEQFMT,LOCAL->sortcacheseq = mix_modseq(LOCAL->sortcacheseq));
410.2666 +      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
410.2667 +	MESSAGECACHE *elt = mail_elt (stream,i);
410.2668 +	SORTCACHE *s = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
410.2669 +	STRINGLIST *sl;
410.2670 +	s->dirty = NIL;		/* no longer dirty */
410.2671 +	if (sl = s->references)	/* count length of references */
410.2672 +	  for (j = 1; sl && sl->text.data; sl = sl->next)
410.2673 +	    j += 10 + sl->text.size;
410.2674 +	else j = 0;		/* no references yet */
410.2675 +	fprintf (f,SCRFMT,elt->private.uid,s->date,
410.2676 +		 s->from ? strlen (s->from) + 1 : 0,
410.2677 +		 s->to ? strlen (s->to) + 1 : 0,s->cc ? strlen (s->cc) + 1 : 0,
410.2678 +		 s->refwd ? 'R' : ' ',s->subject ? strlen (s->subject) + 1: 0,
410.2679 +		 s->message_id ? strlen (s->message_id) + 1 : 0,j);
410.2680 +	if (s->from) fprintf (f,"F%s\015\012",s->from);
410.2681 +	if (s->to) fprintf (f,"T%s\015\012",s->to);
410.2682 +	if (s->cc) fprintf (f,"C%s\015\012",s->cc);
410.2683 +	if (s->subject) fprintf (f,"S%s\015\012",s->subject);
410.2684 +	if (s->message_id) fprintf (f,"M%s\015\012",s->message_id);
410.2685 +	if (j) {		/* any references to write? */
410.2686 +	  fputc ('R',f);	/* yes, do so */
410.2687 +	  for (sl = s->references; sl && sl->text.data; sl = sl->next)
410.2688 +	    fprintf (f,"%08lx:%s:",sl->text.size,sl->text.data);
410.2689 +	  fputs ("\015\012",f);
410.2690 +	}
410.2691 +	if (ferror (f)) {
410.2692 +	  MM_LOG ("Error updating mix sortcache file",WARN);
410.2693 +	  ret = NIL;
410.2694 +	}
410.2695 +      }
410.2696 +      if (ret && fflush (f)) {
410.2697 +	MM_LOG ("Error flushing mix sortcache file",WARN);
410.2698 +	ret = NIL;
410.2699 +      }
410.2700 +      if (ret) ftruncate (fileno (f),ftell (f));
410.2701 +    }
410.2702 +    if (fclose (f)) {
410.2703 +      MM_LOG ("Error closing mix sortcache file",WARN);
410.2704 +      ret = NIL;
410.2705 +    }
410.2706 +  }
410.2707 +  return ret;
410.2708 +}
410.2709 +
410.2710 +/* MIX generic file routines */
410.2711 +
410.2712 +/* MIX read record
410.2713 + * Accepts: open FILE
410.2714 + *	    buffer
410.2715 + *	    buffer length
410.2716 + *	    record type
410.2717 + * Returns: buffer if success, else NIL (zero-length buffer means EOF)
410.2718 + */
410.2719 +
410.2720 +char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type)
410.2721 +{
410.2722 +  char *s,tmp[MAILTMPLEN];
410.2723 +				/* ensure string tied off */
410.2724 +  buf[buflen-2] = buf[buflen-1] = '\0';
410.2725 +  while (fgets (buf,buflen-1,f)) {
410.2726 +    if (s = strchr (buf,'\012')) {
410.2727 +      if ((s != buf) && (s[-1] == '\015')) --s;
410.2728 +      *s = '\0';		/* tie off buffer */
410.2729 +      if (s != buf) return buf;	/* return if non-empty buffer */
410.2730 +      sprintf (tmp,"Empty mix %s record",type);
410.2731 +      MM_LOG (tmp,WARN);
410.2732 +    }
410.2733 +    else if (buf[buflen-2]) {	/* overlong record is bad news */
410.2734 +      sprintf (tmp,"Oversize mix %s record: %.512s",type,buf);
410.2735 +      MM_LOG (tmp,ERROR);
410.2736 +      return NIL;
410.2737 +    }
410.2738 +    else {
410.2739 +      sprintf (tmp,"Truncated mix %s record: %.512s",type,buf);
410.2740 +      MM_LOG (tmp,WARN);
410.2741 +      return buf;		/* pass to caller anyway */
410.2742 +    }
410.2743 +  }
410.2744 +  buf[0] = '\0';		/* return empty buffer on EOF */
410.2745 +  return buf;
410.2746 +}
410.2747 +
410.2748 +/* MIX read sequence record
410.2749 + * Accepts: open FILE
410.2750 + * Returns: sequence value, or NIL if failure
410.2751 + */
410.2752 +
410.2753 +unsigned long mix_read_sequence (FILE *f)
410.2754 +{
410.2755 +  unsigned long ret;
410.2756 +  char *s,tmp[MAILTMPLEN];
410.2757 +  if (!mix_read_record (f,tmp,MAILTMPLEN-1,"sequence")) return NIL;
410.2758 +  switch (tmp[0]) {		/* examine record */
410.2759 +  case '\0':			/* end of file */
410.2760 +    ret = 1;			/* start a new sequence regime */
410.2761 +    break;
410.2762 +  case 'S':			/* sequence record */
410.2763 +    if (isxdigit (tmp[1])) {	/* must be followed by hex value */
410.2764 +      ret = strtoul (tmp+1,&s,16);
410.2765 +      if (!*s) break;		/* and nothing more */
410.2766 +    }
410.2767 +				/* drop into default case */
410.2768 +  default:			/* anything else is an error */
410.2769 +    return NIL;			/* return error */
410.2770 +  }
410.2771 +  return ret;
410.2772 +}
410.2773 +
410.2774 +/* MIX internal routines */
410.2775 +
410.2776 +
410.2777 +/* MIX mail build directory name
410.2778 + * Accepts: destination string
410.2779 + *          source
410.2780 + * Returns: destination or empty string if error
410.2781 + */
410.2782 +
410.2783 +char *mix_dir (char *dst,char *name)
410.2784 +{
410.2785 +  char *s;
410.2786 +				/* empty string if mailboxfile fails */
410.2787 +  if (!mailboxfile (dst,name)) *dst = '\0';
410.2788 +				/* driver-selected INBOX  */
410.2789 +  else if (!*dst) mailboxfile (dst,"~/INBOX");
410.2790 +				/* tie off unnecessary trailing / */
410.2791 +  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
410.2792 +  return dst;
410.2793 +}
410.2794 +
410.2795 +
410.2796 +/* MIX mail build file name
410.2797 + * Accepts: destination string
410.2798 + *	    directory name
410.2799 + *	    file name
410.2800 + * Returns: destination
410.2801 + */
410.2802 +
410.2803 +char *mix_file (char *dst,char *dir,char *name)
410.2804 +{
410.2805 +  sprintf (dst,"%.500s/%.80s%.80s",dir,MIXNAME,name);
410.2806 +  return dst;
410.2807 +}
410.2808 +
410.2809 +
410.2810 +/* MIX mail build file name from data file number
410.2811 + * Accepts: destination string
410.2812 + *	    directory name
410.2813 + *	    data file number
410.2814 + * Returns: destination
410.2815 + */
410.2816 +
410.2817 +char *mix_file_data (char *dst,char *dir,unsigned long data)
410.2818 +{
410.2819 +  char tmp[MAILTMPLEN];
410.2820 +  if (data) sprintf (tmp,"%08lx",data);
410.2821 +  else tmp[0] = '\0';		/* compatibility with experimental version */
410.2822 +  return mix_file (dst,dir,tmp);
410.2823 +}
410.2824 +
410.2825 +/* MIX mail get new modseq
410.2826 + * Accepts: old modseq
410.2827 + * Returns: new modseq value
410.2828 + */
410.2829 +
410.2830 +unsigned long mix_modseq (unsigned long oldseq)
410.2831 +{
410.2832 +				/* normally time now */
410.2833 +  unsigned long ret = (unsigned long) time (NIL);
410.2834 +				/* ensure that modseq doesn't go backwards */
410.2835 +  if (ret <= oldseq) ret = oldseq + 1;
410.2836 +  return ret;
410.2837 +}
   411.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   411.2 +++ b/src/osdep/unix/mkauths	Mon Sep 14 15:17:45 2009 +0900
   411.3 @@ -0,0 +1,40 @@
   411.4 +#!/bin/sh
   411.5 +# ========================================================================
   411.6 +# Copyright 1988-2006 University of Washington
   411.7 +#
   411.8 +# Licensed under the Apache License, Version 2.0 (the "License");
   411.9 +# you may not use this file except in compliance with the License.
  411.10 +# You may obtain a copy of the License at
  411.11 +#
  411.12 +#     http://www.apache.org/licenses/LICENSE-2.0
  411.13 +#
  411.14 +# 
  411.15 +# ========================================================================
  411.16 +
  411.17 +# Program:	Authenticator Linkage Generator
  411.18 +#
  411.19 +# Author:	Mark Crispin
  411.20 +#		Networks and Distributed Computing
  411.21 +#		Computing & Communications
  411.22 +#		University of Washington
  411.23 +#		Administration Building, AG-44
  411.24 +#		Seattle, WA  98195
  411.25 +#		Internet: MRC@CAC.Washington.EDU
  411.26 +#
  411.27 +# Date:		5 December 1995
  411.28 +# Last Edited:	30 August 2006
  411.29 +
  411.30 +# Erase old authenticators list
  411.31 +rm -f auths.c
  411.32 +touch auths.c
  411.33 +
  411.34 +# Now define the new list
  411.35 +for authenticator
  411.36 + do
  411.37 +  if [ -f Makefile."$authenticator" ]; then
  411.38 +    make -f Makefile."$authenticator" `cat SPECIALS`
  411.39 +  fi
  411.40 +  echo "extern AUTHENTICATOR auth_"$authenticator";" >> linkage.h
  411.41 +  echo "  auth_link (&auth_"$authenticator");		/* link in the $authenticator authenticator */" | cat >> linkage.c
  411.42 +  echo "#include \"auth_"$authenticator".c\"" >> auths.c
  411.43 +done
   412.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   412.2 +++ b/src/osdep/unix/mmdf.c	Mon Sep 14 15:17:45 2009 +0900
   412.3 @@ -0,0 +1,2549 @@
   412.4 +/* ========================================================================
   412.5 + * Copyright 1988-2008 University of Washington
   412.6 + *
   412.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   412.8 + * you may not use this file except in compliance with the License.
   412.9 + * You may obtain a copy of the License at
  412.10 + *
  412.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  412.12 + *
  412.13 + * 
  412.14 + * ========================================================================
  412.15 + */
  412.16 +
  412.17 +/*
  412.18 + * Program:	MMDF mail routines
  412.19 + *
  412.20 + * Author:	Mark Crispin
  412.21 + *		UW Technology
  412.22 + *		University of Washington
  412.23 + *		Seattle, WA  98195
  412.24 + *		Internet: MRC@Washington.EDU
  412.25 + *
  412.26 + * Date:	20 December 1989
  412.27 + * Last Edited:	27 March 2008
  412.28 + */
  412.29 +
  412.30 +
  412.31 +#include <stdio.h>
  412.32 +#include <ctype.h>
  412.33 +#include <errno.h>
  412.34 +extern int errno;		/* just in case */
  412.35 +#include <signal.h>
  412.36 +#include "mail.h"
  412.37 +#include "osdep.h"
  412.38 +#include <time.h>
  412.39 +#include <sys/stat.h>
  412.40 +#include "pseudo.h"
  412.41 +#include "fdstring.h"
  412.42 +#include "misc.h"
  412.43 +#include "dummy.h"
  412.44 +
  412.45 +/* Supposedly, this page has everything the MMDF driver needs to know about
  412.46 + * the MMDF delimiter.  By changing these macros, the MMDF driver should
  412.47 + * change with it.  Note that if you change the length of MMDFHDRTXT you
  412.48 + * also need to change the ISMMDF and RETIFMMDFWRD macros to reflect the new
  412.49 + * size.
  412.50 + */
  412.51 +
  412.52 +
  412.53 +/* Useful MMDF constants */
  412.54 +
  412.55 +#define MMDFCHR '\01'		/* MMDF character */
  412.56 +#define MMDFCHRS 0x01010101	/* MMDF header character spread in a word */
  412.57 +				/* MMDF header text */
  412.58 +#define MMDFHDRTXT "\01\01\01\01\n"
  412.59 +				/* length of MMDF header text */
  412.60 +#define MMDFHDRLEN (sizeof (MMDFHDRTXT) - 1)
  412.61 +
  412.62 +
  412.63 +/* Validate MMDF header
  412.64 + * Accepts: pointer to candidate string to validate as an MMDF header
  412.65 + * Returns: T if valid; else NIL
  412.66 + */
  412.67 +
  412.68 +#define ISMMDF(s)							\
  412.69 +  ((*(s) == MMDFCHR) && ((s)[1] == MMDFCHR) && ((s)[2] == MMDFCHR) &&	\
  412.70 +   ((s)[3] == MMDFCHR) && ((s)[4] == '\n'))
  412.71 +
  412.72 +
  412.73 +/* Return if a 32-bit word has the start of an MMDF header
  412.74 + * Accepts: pointer to word of four bytes to validate as an MMDF header
  412.75 + * Returns: pointer to MMDF header, else proceeds
  412.76 + */
  412.77 +
  412.78 +#define RETIFMMDFWRD(s) {						\
  412.79 +  if (s[3] == MMDFCHR) {						\
  412.80 +    if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == MMDFCHR) &&	\
  412.81 +	(s[7] == '\n')) return s + 3;					\
  412.82 +    else if (s[2] == MMDFCHR) {						\
  412.83 +      if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == '\n'))	\
  412.84 +	return s + 2;							\
  412.85 +      else if (s[1] == MMDFCHR) {					\
  412.86 +	if ((s[4] == MMDFCHR) && (s[5] == '\n')) return s + 1;		\
  412.87 +	else if ((*s == MMDFCHR) && (s[4] == '\n')) return s;		\
  412.88 +      }									\
  412.89 +    }									\
  412.90 +  }									\
  412.91 +}
  412.92 +
  412.93 +/* Validate line
  412.94 + * Accepts: pointer to candidate string to validate as a From header
  412.95 + *	    return pointer to end of date/time field
  412.96 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  412.97 + *	    return pointer to offset from t of time zone (if non-zero)
  412.98 + * Returns: t,ti,zn set if valid From string, else ti is NIL
  412.99 + */
 412.100 +
 412.101 +#define VALID(s,x,ti,zn) {						\
 412.102 +  ti = 0;								\
 412.103 +  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
 412.104 +      (s[4] == ' ')) {							\
 412.105 +    for (x = s + 5; *x && *x != '\n'; x++);				\
 412.106 +    if (*x) {								\
 412.107 +      if (x - s >= 41) {						\
 412.108 +	for (zn = -1; x[zn] != ' '; zn--);				\
 412.109 +	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
 412.110 +	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
 412.111 +	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
 412.112 +	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
 412.113 +	  x += zn - 12;							\
 412.114 +      }									\
 412.115 +      if (x - s >= 27) {						\
 412.116 +	if (x[-5] == ' ') {						\
 412.117 +	  if (x[-8] == ':') zn = 0,ti = -5;				\
 412.118 +	  else if (x[-9] == ' ') ti = zn = -9;				\
 412.119 +	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
 412.120 +	    ti = zn = -11;						\
 412.121 +	}								\
 412.122 +	else if (x[-4] == ' ') {					\
 412.123 +	  if (x[-9] == ' ') zn = -4,ti = -9;				\
 412.124 +	}								\
 412.125 +	else if (x[-6] == ' ') {					\
 412.126 +	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
 412.127 +	    zn = -6,ti = -11;						\
 412.128 +	}								\
 412.129 +	if (ti && !((x[ti - 3] == ':') &&				\
 412.130 +		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
 412.131 +		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
 412.132 +		    (x[ti - 11] == ' '))) ti = 0;			\
 412.133 +      }									\
 412.134 +    }									\
 412.135 +  }									\
 412.136 +}
 412.137 +
 412.138 +/* You are not expected to understand this macro, but read the next page if
 412.139 + * you are not faint of heart.
 412.140 + *
 412.141 + * Known formats to the VALID macro are:
 412.142 + *		From user Wed Dec  2 05:53 1992
 412.143 + * BSD		From user Wed Dec  2 05:53:22 1992
 412.144 + * SysV		From user Wed Dec  2 05:53 PST 1992
 412.145 + * rn		From user Wed Dec  2 05:53:22 PST 1992
 412.146 + *		From user Wed Dec  2 05:53 -0700 1992
 412.147 + * emacs	From user Wed Dec  2 05:53:22 -0700 1992
 412.148 + *		From user Wed Dec  2 05:53 1992 PST
 412.149 + *		From user Wed Dec  2 05:53:22 1992 PST
 412.150 + *		From user Wed Dec  2 05:53 1992 -0700
 412.151 + * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
 412.152 + *
 412.153 + * Plus all of the above with `` remote from xxx'' after it. Thank you very
 412.154 + * much, smail and Solaris, for making my life considerably more complicated.
 412.155 + */
 412.156 +
 412.157 +/*
 412.158 + * What?  You want to understand the VALID macro anyway?  Alright, since you
 412.159 + * insist.  Actually, it isn't really all that difficult, provided that you
 412.160 + * take it step by step.
 412.161 + *
 412.162 + * Line 1	Initializes the return ti value to failure (0);
 412.163 + * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
 412.164 + * Lines 4-5	Validates that there is an end of line and points x at it.
 412.165 + * Lines 6-13	First checks to see if the line is at least 41 characters long.
 412.166 + *		If so, it scans backwards to find the rightmost space.  From
 412.167 + *		that point, it scans backwards to see if the string matches
 412.168 + *		`` remote from''.  If so, it sets x to point to the space at
 412.169 + *		the start of the string.
 412.170 + * Line 14	Makes sure that there are at least 27 characters in the line.
 412.171 + * Lines 15-20	Checks if the date/time ends with the year (there is a space
 412.172 + *		five characters back).  If there is a colon three characters
 412.173 + *		further back, there is no timezone field, so zn is set to 0
 412.174 + *		and ti is set in front of the year.  Otherwise, there must
 412.175 + *		either to be a space four characters back for a three-letter
 412.176 + *		timezone, or a space six characters back followed by a + or -
 412.177 + *		for a numeric timezone; in either case, zn and ti become the
 412.178 + *		offset of the space immediately before it.
 412.179 + * Lines 21-23	Are the failure case for line 14.  If there is a space four
 412.180 + *		characters back, it is a three-letter timezone; there must be a
 412.181 + *		space for the year nine characters back.  zn is the zone
 412.182 + *		offset; ti is the offset of the space.
 412.183 + * Lines 24-27	Are the failure case for line 20.  If there is a space six
 412.184 + *		characters back, it is a numeric timezone; there must be a
 412.185 + *		space eleven characters back and a + or - five characters back.
 412.186 + *		zn is the zone offset; ti is the offset of the space.
 412.187 + * Line 28-31	If ti is valid, make sure that the string before ti is of the
 412.188 + *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
 412.189 + *		invalidate ti.  There must be a colon three characters back
 412.190 + *		and a space six or nine	characters back (depending upon
 412.191 + *		whether or not the character six characters back is a colon).
 412.192 + *		There must be a space three characters further back (in front
 412.193 + *		of the day), one seven characters back (in front of the month),
 412.194 + *		and one eleven characters back (in front of the day of week).
 412.195 + *		ti is set to be the offset of the space before the time.
 412.196 + *
 412.197 + * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
 412.198 + * newer pipelined machines it is faster being open-coded than it would be if
 412.199 + * subroutines are called.
 412.200 + *
 412.201 + * Why does it scan backwards from the end of the line, instead of doing the
 412.202 + * much easier forward scan?  There is no deterministic way to parse the
 412.203 + * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
 412.204 + * see if unquoted spaces were possible.  They are, and I've encountered enough
 412.205 + * evil mail to be totally unwilling to trust that ``it will never happen''.
 412.206 + */
 412.207 +
 412.208 +/* Build parameters */
 412.209 +
 412.210 +#define KODRETRY 15		/* kiss-of-death retry in seconds */
 412.211 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
 412.212 +
 412.213 +
 412.214 +/* MMDF I/O stream local data */
 412.215 +
 412.216 +typedef struct mmdf_local {
 412.217 +  unsigned int dirty : 1;	/* disk copy needs updating */
 412.218 +  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
 412.219 +  unsigned int pseudo : 1;	/* uses a pseudo message */
 412.220 +  unsigned int appending : 1;	/* don't mark new messages as old */
 412.221 +  int fd;			/* mailbox file descriptor */
 412.222 +  int ld;			/* lock file descriptor */
 412.223 +  char *lname;			/* lock file name */
 412.224 +  off_t filesize;		/* file size parsed */
 412.225 +  time_t filetime;		/* last file time */
 412.226 +  unsigned char *buf;		/* temporary buffer */
 412.227 +  unsigned long buflen;		/* current size of temporary buffer */
 412.228 +  unsigned long uid;		/* current text uid */
 412.229 +  SIZEDTEXT text;		/* current text */
 412.230 +  unsigned long textlen;	/* current text length */
 412.231 +  char *line;			/* returned line */
 412.232 +  char *linebuf;		/* line readin buffer */
 412.233 +  unsigned long linebuflen;	/* current line readin buffer length */
 412.234 +} MMDFLOCAL;
 412.235 +
 412.236 +
 412.237 +/* Convenient access to local data */
 412.238 +
 412.239 +#define LOCAL ((MMDFLOCAL *) stream->local)
 412.240 +
 412.241 +
 412.242 +/* MMDF protected file structure */
 412.243 +
 412.244 +typedef struct mmdf_file {
 412.245 +  MAILSTREAM *stream;		/* current stream */
 412.246 +  off_t curpos;			/* current file position */
 412.247 +  off_t protect;		/* protected position */
 412.248 +  off_t filepos;		/* current last written file position */
 412.249 +  char *buf;			/* overflow buffer */
 412.250 +  size_t buflen;		/* current overflow buffer length */
 412.251 +  char *bufpos;			/* current buffer position */
 412.252 +} MMDFFILE;
 412.253 +
 412.254 +/* Function prototypes */
 412.255 +
 412.256 +DRIVER *mmdf_valid (char *name);
 412.257 +long mmdf_isvalid (char *name,char *tmp);
 412.258 +long mmdf_isvalid_fd (int fd,char *tmp);
 412.259 +void *mmdf_parameters (long function,void *value);
 412.260 +void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 412.261 +void mmdf_list (MAILSTREAM *stream,char *ref,char *pat);
 412.262 +void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat);
 412.263 +long mmdf_create (MAILSTREAM *stream,char *mailbox);
 412.264 +long mmdf_delete (MAILSTREAM *stream,char *mailbox);
 412.265 +long mmdf_rename (MAILSTREAM *stream,char *old,char *newname);
 412.266 +MAILSTREAM *mmdf_open (MAILSTREAM *stream);
 412.267 +void mmdf_close (MAILSTREAM *stream,long options);
 412.268 +char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
 412.269 +		   unsigned long *length,long flags);
 412.270 +long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 412.271 +char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 412.272 +		      unsigned long *length,long flags);
 412.273 +void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 412.274 +long mmdf_ping (MAILSTREAM *stream);
 412.275 +void mmdf_check (MAILSTREAM *stream);
 412.276 +long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options);
 412.277 +long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 412.278 +long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 412.279 +int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 412.280 +		     STRING *msg);
 412.281 +int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
 412.282 +
 412.283 +void mmdf_abort (MAILSTREAM *stream);
 412.284 +char *mmdf_file (char *dst,char *name);
 412.285 +int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
 412.286 +void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
 412.287 +int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
 412.288 +char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
 412.289 +unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr);
 412.290 +unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
 412.291 +			    unsigned long uid,long flag);
 412.292 +long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
 412.293 +		   long flags);
 412.294 +long mmdf_extend (MAILSTREAM *stream,unsigned long size);
 412.295 +void mmdf_write (MMDFFILE *f,char *s,unsigned long i);
 412.296 +void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size);
 412.297 +
 412.298 +/* MMDF mail routines */
 412.299 +
 412.300 +
 412.301 +/* Driver dispatch used by MAIL */
 412.302 +
 412.303 +DRIVER mmdfdriver = {
 412.304 +  "mmdf",			/* driver name */
 412.305 +				/* driver flags */
 412.306 +  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
 412.307 +  (DRIVER *) NIL,		/* next driver */
 412.308 +  mmdf_valid,			/* mailbox is valid for us */
 412.309 +  mmdf_parameters,		/* manipulate parameters */
 412.310 +  mmdf_scan,			/* scan mailboxes */
 412.311 +  mmdf_list,			/* list mailboxes */
 412.312 +  mmdf_lsub,			/* list subscribed mailboxes */
 412.313 +  NIL,				/* subscribe to mailbox */
 412.314 +  NIL,				/* unsubscribe from mailbox */
 412.315 +  mmdf_create,			/* create mailbox */
 412.316 +  mmdf_delete,			/* delete mailbox */
 412.317 +  mmdf_rename,			/* rename mailbox */
 412.318 +  mail_status_default,		/* status of mailbox */
 412.319 +  mmdf_open,			/* open mailbox */
 412.320 +  mmdf_close,			/* close mailbox */
 412.321 +  NIL,				/* fetch message "fast" attributes */
 412.322 +  NIL,				/* fetch message flags */
 412.323 +  NIL,				/* fetch overview */
 412.324 +  NIL,				/* fetch message envelopes */
 412.325 +  mmdf_header,			/* fetch message header */
 412.326 +  mmdf_text,			/* fetch message text */
 412.327 +  NIL,				/* fetch partial message text */
 412.328 +  NIL,				/* unique identifier */
 412.329 +  NIL,				/* message number */
 412.330 +  NIL,				/* modify flags */
 412.331 +  mmdf_flagmsg,			/* per-message modify flags */
 412.332 +  NIL,				/* search for message based on criteria */
 412.333 +  NIL,				/* sort messages */
 412.334 +  NIL,				/* thread messages */
 412.335 +  mmdf_ping,			/* ping mailbox to see if still alive */
 412.336 +  mmdf_check,			/* check for new messages */
 412.337 +  mmdf_expunge,			/* expunge deleted messages */
 412.338 +  mmdf_copy,			/* copy messages to another mailbox */
 412.339 +  mmdf_append,			/* append string message to mailbox */
 412.340 +  NIL				/* garbage collect stream */
 412.341 +};
 412.342 +
 412.343 +				/* prototype stream */
 412.344 +MAILSTREAM mmdfproto = {&mmdfdriver};
 412.345 +
 412.346 +char *mmdfhdr = MMDFHDRTXT;	/* MMDF header */
 412.347 +
 412.348 +/* MMDF mail validate mailbox
 412.349 + * Accepts: mailbox name
 412.350 + * Returns: our driver if name is valid, NIL otherwise
 412.351 + */
 412.352 +
 412.353 +DRIVER *mmdf_valid (char *name)
 412.354 +{
 412.355 +  char tmp[MAILTMPLEN];
 412.356 +  return mmdf_isvalid (name,tmp) ? &mmdfdriver : NIL;
 412.357 +}
 412.358 +
 412.359 +
 412.360 +/* MMDF mail test for valid mailbox name
 412.361 + * Accepts: mailbox name
 412.362 + *	    scratch buffer
 412.363 + * Returns: T if valid, NIL otherwise
 412.364 + */
 412.365 +
 412.366 +long mmdf_isvalid (char *name,char *tmp)
 412.367 +{
 412.368 +  int fd;
 412.369 +  int ret = NIL;
 412.370 +  char *t,file[MAILTMPLEN];
 412.371 +  struct stat sbuf;
 412.372 +  time_t tp[2];
 412.373 +  errno = EINVAL;		/* assume invalid argument */
 412.374 +				/* must be non-empty file */
 412.375 +  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
 412.376 +    if (!sbuf.st_size)errno = 0;/* empty file */
 412.377 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 412.378 +				/* error -1 for invalid format */
 412.379 +      if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1;
 412.380 +      close (fd);		/* close the file */
 412.381 +				/* \Marked status? */
 412.382 +      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
 412.383 +	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 412.384 +	tp[1] = sbuf.st_mtime;
 412.385 +	utime (file,tp);	/* set the times */
 412.386 +      }
 412.387 +    }
 412.388 +  }
 412.389 +  return ret;			/* return what we should */
 412.390 +}
 412.391 +
 412.392 +/* MMDF mail test for valid mailbox
 412.393 + * Accepts: file descriptor
 412.394 + *	    scratch buffer
 412.395 + * Returns: T if valid, NIL otherwise
 412.396 + */
 412.397 +
 412.398 +long mmdf_isvalid_fd (int fd,char *tmp)
 412.399 +{
 412.400 +  int ret = NIL;
 412.401 +  memset (tmp,'\0',MAILTMPLEN);
 412.402 +  if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL;
 412.403 +  return ret;			/* return what we should */
 412.404 +}
 412.405 +
 412.406 +
 412.407 +/* MMDF manipulate driver parameters
 412.408 + * Accepts: function code
 412.409 + *	    function-dependent value
 412.410 + * Returns: function-dependent return value
 412.411 + */
 412.412 +
 412.413 +void *mmdf_parameters (long function,void *value)
 412.414 +{
 412.415 +  void *ret = NIL;
 412.416 +  switch ((int) function) {
 412.417 +  case GET_INBOXPATH:
 412.418 +    if (value) ret = dummy_file ((char *) value,"INBOX");
 412.419 +    break;
 412.420 +  }
 412.421 +  return ret;
 412.422 +}
 412.423 +
 412.424 +/* MMDF mail scan mailboxes
 412.425 + * Accepts: mail stream
 412.426 + *	    reference
 412.427 + *	    pattern to search
 412.428 + *	    string to scan
 412.429 + */
 412.430 +
 412.431 +void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 412.432 +{
 412.433 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 412.434 +}
 412.435 +
 412.436 +
 412.437 +/* MMDF mail list mailboxes
 412.438 + * Accepts: mail stream
 412.439 + *	    reference
 412.440 + *	    pattern to search
 412.441 + */
 412.442 +
 412.443 +void mmdf_list (MAILSTREAM *stream,char *ref,char *pat)
 412.444 +{
 412.445 +  if (stream) dummy_list (NIL,ref,pat);
 412.446 +}
 412.447 +
 412.448 +
 412.449 +/* MMDF mail list subscribed mailboxes
 412.450 + * Accepts: mail stream
 412.451 + *	    reference
 412.452 + *	    pattern to search
 412.453 + */
 412.454 +
 412.455 +void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat)
 412.456 +{
 412.457 +  if (stream) dummy_lsub (NIL,ref,pat);
 412.458 +}
 412.459 +
 412.460 +/* MMDF mail create mailbox
 412.461 + * Accepts: MAIL stream
 412.462 + *	    mailbox name to create
 412.463 + * Returns: T on success, NIL on failure
 412.464 + */
 412.465 +
 412.466 +long mmdf_create (MAILSTREAM *stream,char *mailbox)
 412.467 +{
 412.468 +  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
 412.469 +  long ret = NIL;
 412.470 +  int i,fd;
 412.471 +  time_t ti = time (0);
 412.472 +  if (!(s = dummy_file (mbx,mailbox))) {
 412.473 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 412.474 +    MM_LOG (tmp,ERROR);
 412.475 +  }
 412.476 +				/* create underlying file */
 412.477 +  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
 412.478 +				/* done if dir-only or whiner */
 412.479 +    if (((s = strrchr (s,'/')) && !s[1]) ||
 412.480 +	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
 412.481 +    else if ((fd = open (mbx,O_WRONLY,
 412.482 +		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
 412.483 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 412.484 +      MM_LOG (tmp,ERROR);
 412.485 +      unlink (mbx);		/* delete the file */
 412.486 +    }
 412.487 +    else {			/* initialize header */
 412.488 +      memset (tmp,'\0',MAILTMPLEN);
 412.489 +      sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti));
 412.490 +      rfc822_date (s = tmp + strlen (tmp));
 412.491 +      sprintf (s += strlen (s),	/* write the pseudo-header */
 412.492 +	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
 412.493 +	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
 412.494 +	       (unsigned long) ti);
 412.495 +      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
 412.496 +	sprintf (s += strlen (s)," %s",default_user_flag (i));
 412.497 +      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
 412.498 +      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
 412.499 +      else {
 412.500 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
 412.501 +		 strerror (errno));
 412.502 +	MM_LOG (tmp,ERROR);
 412.503 +	unlink (mbx);		/* delete the file */
 412.504 +      }
 412.505 +      close (fd);		/* close file */
 412.506 +    }
 412.507 +  }
 412.508 +				/* set proper protections */
 412.509 +  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
 412.510 +}
 412.511 +
 412.512 +/* MMDF mail delete mailbox
 412.513 + * Accepts: MAIL stream
 412.514 + *	    mailbox name to delete
 412.515 + * Returns: T on success, NIL on failure
 412.516 + */
 412.517 +
 412.518 +long mmdf_delete (MAILSTREAM *stream,char *mailbox)
 412.519 +{
 412.520 +  return mmdf_rename (stream,mailbox,NIL);
 412.521 +}
 412.522 +
 412.523 +
 412.524 +/* MMDF mail rename mailbox
 412.525 + * Accepts: MAIL stream
 412.526 + *	    old mailbox name
 412.527 + *	    new mailbox name (or NIL for delete)
 412.528 + * Returns: T on success, NIL on failure
 412.529 + */
 412.530 +
 412.531 +long mmdf_rename (MAILSTREAM *stream,char *old,char *newname)
 412.532 +{
 412.533 +  long ret = NIL;
 412.534 +  char c,*s = NIL;
 412.535 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 412.536 +  DOTLOCK lockx;
 412.537 +  int fd,ld;
 412.538 +  long i;
 412.539 +  struct stat sbuf;
 412.540 +  MM_CRITICAL (stream);	/* get the c-client lock */
 412.541 +  if (!dummy_file (file,old) ||
 412.542 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 412.543 +		   ((s = strrchr (tmp,'/')) && !s[1]))))
 412.544 +    sprintf (tmp,newname ?
 412.545 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 412.546 +	     "Can't delete mailbox %.80s: invalid name",
 412.547 +	     old,newname);
 412.548 +				/* lock out other c-clients */
 412.549 +  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
 412.550 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 412.551 +
 412.552 +  else {
 412.553 +    if ((fd = mmdf_lock (file,O_RDWR,
 412.554 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
 412.555 +			 &lockx,LOCK_EX)) < 0)
 412.556 +       sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
 412.557 +    else {
 412.558 +      if (newname) {		/* want rename? */
 412.559 +				/* found superior to destination name? */
 412.560 +	if (s = strrchr (s,'/')) {
 412.561 +	  c = *++s;		/* remember first character of inferior */
 412.562 +	  *s = '\0';		/* tie off to get just superior */
 412.563 +				/* name doesn't exist, create it */
 412.564 +	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 412.565 +	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
 412.566 +	    mmdf_unlock (fd,NIL,&lockx);
 412.567 +	    mmdf_unlock (ld,NIL,NIL);
 412.568 +	    unlink (lock);
 412.569 +	    MM_NOCRITICAL (stream);
 412.570 +	    return ret;		/* return success or failure */
 412.571 +	  }
 412.572 +	  *s = c;		/* restore full name */
 412.573 +	}
 412.574 +	if (rename (file,tmp))
 412.575 +	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 412.576 +		   strerror (errno));
 412.577 +	else ret = T;		/* set success */
 412.578 +      }
 412.579 +      else if (unlink (file))
 412.580 +	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 412.581 +      else ret = T;		/* set success */
 412.582 +      mmdf_unlock (fd,NIL,&lockx);
 412.583 +    }
 412.584 +    mmdf_unlock (ld,NIL,NIL);	/* flush the lock */
 412.585 +    unlink (lock);
 412.586 +  }
 412.587 +  MM_NOCRITICAL (stream);	/* no longer critical */
 412.588 +  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
 412.589 +  return ret;			/* return success or failure */
 412.590 +}
 412.591 +
 412.592 +/* MMDF mail open
 412.593 + * Accepts: Stream to open
 412.594 + * Returns: Stream on success, NIL on failure
 412.595 + */
 412.596 +
 412.597 +MAILSTREAM *mmdf_open (MAILSTREAM *stream)
 412.598 +{
 412.599 +  long i;
 412.600 +  int fd;
 412.601 +  char tmp[MAILTMPLEN];
 412.602 +  DOTLOCK lock;
 412.603 +  long retry;
 412.604 +				/* return prototype for OP_PROTOTYPE call */
 412.605 +  if (!stream) return user_flags (&mmdfproto);
 412.606 +  retry = stream->silent ? 1 : KODRETRY;
 412.607 +  if (stream->local) fatal ("mmdf recycle stream");
 412.608 +  stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL));
 412.609 +				/* note if an INBOX or not */
 412.610 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 412.611 +				/* canonicalize the stream mailbox name */
 412.612 +  if (!dummy_file (tmp,stream->mailbox)) {
 412.613 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 412.614 +    MM_LOG (tmp,ERROR);
 412.615 +    return NIL;
 412.616 +  }
 412.617 +				/* flush old name */
 412.618 +  fs_give ((void **) &stream->mailbox);
 412.619 +				/* save canonical name */
 412.620 +  stream->mailbox = cpystr (tmp);
 412.621 +  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
 412.622 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 412.623 +  LOCAL->buflen = CHUNKSIZE - 1;
 412.624 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 412.625 +  LOCAL->text.size = CHUNKSIZE - 1;
 412.626 +  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
 412.627 +  LOCAL->linebuflen = CHUNKSIZE - 1;
 412.628 +  stream->sequence++;		/* bump sequence number */
 412.629 +
 412.630 +				/* make lock for read/write access */
 412.631 +  if (!stream->rdonly) while (retry) {
 412.632 +				/* try to lock file */
 412.633 +    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
 412.634 +				/* suppressing kiss-of-death? */
 412.635 +      if (stream->nokod) retry = 0;
 412.636 +				/* no, first time through? */
 412.637 +      else if (retry-- == KODRETRY) {
 412.638 +				/* learned other guy's PID and can signal? */
 412.639 +	if (i && !kill ((int) i,SIGUSR2)) {
 412.640 +	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
 412.641 +	  MM_LOG (tmp,WARN);
 412.642 +	}
 412.643 +	else retry = 0;		/* give up */
 412.644 +      }
 412.645 +      if (!stream->silent) {	/* nothing if silent stream */
 412.646 +	if (retry) sleep (1);	/* wait a second before trying again */
 412.647 +	else MM_LOG ("Mailbox is open by another process, access is readonly",
 412.648 +		     WARN);
 412.649 +      }
 412.650 +    }
 412.651 +    else {			/* got the lock, nobody else can alter state */
 412.652 +      LOCAL->ld = fd;		/* note lock's fd and name */
 412.653 +      LOCAL->lname = cpystr (tmp);
 412.654 +				/* make sure mode OK (don't use fchmod()) */
 412.655 +      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
 412.656 +      if (stream->silent) i = 0;/* silent streams won't accept KOD */
 412.657 +      else {			/* note our PID in the lock */
 412.658 +	sprintf (tmp,"%d",getpid ());
 412.659 +	write (fd,tmp,(i = strlen (tmp))+1);
 412.660 +      }
 412.661 +      ftruncate (fd,i);		/* make sure tied off */
 412.662 +      fsync (fd);		/* make sure it's available */
 412.663 +      retry = 0;		/* no more need to try */
 412.664 +    }
 412.665 +  }
 412.666 +
 412.667 +				/* parse mailbox */
 412.668 +  stream->nmsgs = stream->recent = 0;
 412.669 +				/* will we be able to get write access? */
 412.670 +  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
 412.671 +    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 412.672 +    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
 412.673 +    close (LOCAL->ld);		/* close the lock file */
 412.674 +    LOCAL->ld = -1;		/* no more lock fd */
 412.675 +    unlink (LOCAL->lname);	/* delete it */
 412.676 +  }
 412.677 +				/* reset UID validity */
 412.678 +  stream->uid_validity = stream->uid_last = 0;
 412.679 +  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
 412.680 +    mmdf_abort (stream);	/* abort if can't get RW silent stream */
 412.681 +				/* parse mailbox */
 412.682 +  else if (mmdf_parse (stream,&lock,LOCK_SH)) {
 412.683 +    mmdf_unlock (LOCAL->fd,stream,&lock);
 412.684 +    mail_unlock (stream);
 412.685 +    MM_NOCRITICAL (stream);	/* done with critical */
 412.686 +  }
 412.687 +  if (!LOCAL) return NIL;	/* failure if stream died */
 412.688 +				/* make sure upper level knows readonly */
 412.689 +  stream->rdonly = (LOCAL->ld < 0);
 412.690 +				/* notify about empty mailbox */
 412.691 +  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
 412.692 +  if (!stream->rdonly) {	/* flags stick if readwrite */
 412.693 +    stream->perm_seen = stream->perm_deleted =
 412.694 +      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
 412.695 +    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
 412.696 +      stream->perm_user_flags = 0xffffffff;
 412.697 +				/* and maybe can create them too! */
 412.698 +      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
 412.699 +    }
 412.700 +  }
 412.701 +  return stream;		/* return stream alive to caller */
 412.702 +}
 412.703 +
 412.704 +
 412.705 +/* MMDF mail close
 412.706 + * Accepts: MAIL stream
 412.707 + *	    close options
 412.708 + */
 412.709 +
 412.710 +void mmdf_close (MAILSTREAM *stream,long options)
 412.711 +{
 412.712 +  int silent = stream->silent;
 412.713 +  stream->silent = T;		/* go silent */
 412.714 +				/* expunge if requested */
 412.715 +  if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL);
 412.716 +				/* else dump final checkpoint */
 412.717 +  else if (LOCAL->dirty) mmdf_check (stream);
 412.718 +  stream->silent = silent;	/* restore old silence state */
 412.719 +  mmdf_abort (stream);		/* now punt the file and local data */
 412.720 +}
 412.721 +
 412.722 +/* MMDF mail fetch message header
 412.723 + * Accepts: MAIL stream
 412.724 + *	    message # to fetch
 412.725 + *	    pointer to returned header text length
 412.726 + *	    option flags
 412.727 + * Returns: message header in RFC822 format
 412.728 + */
 412.729 +
 412.730 +				/* lines to filter from header */
 412.731 +static STRINGLIST *mmdf_hlines = NIL;
 412.732 +
 412.733 +char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
 412.734 +		   unsigned long *length,long flags)
 412.735 +{
 412.736 +  MESSAGECACHE *elt;
 412.737 +  unsigned char *s,*t,*tl;
 412.738 +  *length = 0;			/* default to empty */
 412.739 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 412.740 +  elt = mail_elt (stream,msgno);/* get cache */
 412.741 +  if (!mmdf_hlines) {		/* once only code */
 412.742 +    STRINGLIST *lines = mmdf_hlines = mail_newstringlist ();
 412.743 +    lines->text.size = strlen ((char *) (lines->text.data =
 412.744 +					 (unsigned char *) "Status"));
 412.745 +    lines = lines->next = mail_newstringlist ();
 412.746 +    lines->text.size = strlen ((char *) (lines->text.data =
 412.747 +					 (unsigned char *) "X-Status"));
 412.748 +    lines = lines->next = mail_newstringlist ();
 412.749 +    lines->text.size = strlen ((char *) (lines->text.data =
 412.750 +					 (unsigned char *) "X-Keywords"));
 412.751 +    lines = lines->next = mail_newstringlist ();
 412.752 +    lines->text.size = strlen ((char *) (lines->text.data =
 412.753 +					 (unsigned char *) "X-UID"));
 412.754 +    lines = lines->next = mail_newstringlist ();
 412.755 +    lines->text.size = strlen ((char *) (lines->text.data =
 412.756 +					 (unsigned char *) "X-IMAP"));
 412.757 +    lines = lines->next = mail_newstringlist ();
 412.758 +    lines->text.size = strlen ((char *) (lines->text.data =
 412.759 +					 (unsigned char *) "X-IMAPbase"));
 412.760 +  }
 412.761 +				/* go to header position */
 412.762 +  lseek (LOCAL->fd,elt->private.special.offset +
 412.763 +	 elt->private.msg.header.offset,L_SET);
 412.764 +
 412.765 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 412.766 +    if (elt->private.msg.header.text.size > LOCAL->buflen) {
 412.767 +      fs_give ((void **) &LOCAL->buf);
 412.768 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 412.769 +				     elt->private.msg.header.text.size) + 1);
 412.770 +    }
 412.771 +				/* read message */
 412.772 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
 412.773 +				/* got text, tie off string */
 412.774 +    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
 412.775 +				/* squeeze out CRs (in case from PC) */
 412.776 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 412.777 +      if (*t != '\r') *s++ = *t;
 412.778 +    *s = '\0';
 412.779 +    *length = s - LOCAL->buf;	/* adjust length */
 412.780 +  }
 412.781 +  else {			/* need to make a CRLF version */
 412.782 +    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
 412.783 +	  elt->private.msg.header.text.size);
 412.784 +				/* tie off string, and convert to CRLF */
 412.785 +    s[elt->private.msg.header.text.size] = '\0';
 412.786 +    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
 412.787 +			  elt->private.msg.header.text.size);
 412.788 +    fs_give ((void **) &s);	/* free readin buffer */
 412.789 +				/* squeeze out spurious CRs */
 412.790 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 412.791 +      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
 412.792 +    *s = '\0';
 412.793 +    *length = s - LOCAL->buf;	/* adjust length */
 412.794 +  }
 412.795 +  *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT);
 412.796 +  return (char *) LOCAL->buf;	/* return processed copy */
 412.797 +}
 412.798 +
 412.799 +/* MMDF mail fetch message text
 412.800 + * Accepts: MAIL stream
 412.801 + *	    message # to fetch
 412.802 + *	    pointer to returned stringstruct
 412.803 + *	    option flags
 412.804 + * Returns: T on success, NIL if failure
 412.805 + */
 412.806 +
 412.807 +long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 412.808 +{
 412.809 +  char *s;
 412.810 +  unsigned long i;
 412.811 +  MESSAGECACHE *elt;
 412.812 +				/* UID call "impossible" */
 412.813 +  if (flags & FT_UID) return NIL;
 412.814 +  elt = mail_elt (stream,msgno);/* get cache element */
 412.815 +				/* if message not seen */
 412.816 +  if (!(flags & FT_PEEK) && !elt->seen) {
 412.817 +				/* mark message seen and dirty */
 412.818 +    elt->seen = elt->private.dirty = LOCAL->dirty = T;
 412.819 +    MM_FLAGS (stream,msgno);
 412.820 +  }
 412.821 +  s = mmdf_text_work (stream,elt,&i,flags);
 412.822 +  INIT (bs,mail_string,s,i);	/* set up stringstruct */
 412.823 +  return T;			/* success */
 412.824 +}
 412.825 +
 412.826 +/* MMDF mail fetch message text worker routine
 412.827 + * Accepts: MAIL stream
 412.828 + *	    message cache element
 412.829 + *	    pointer to returned header text length
 412.830 + *	    option flags
 412.831 + */
 412.832 +
 412.833 +char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 412.834 +		      unsigned long *length,long flags)
 412.835 +{
 412.836 +  FDDATA d;
 412.837 +  STRING bs;
 412.838 +  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
 412.839 +				/* go to text position */
 412.840 +  lseek (LOCAL->fd,elt->private.special.offset +
 412.841 +	 elt->private.msg.text.offset,L_SET);
 412.842 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 412.843 +    if (elt->private.msg.text.text.size > LOCAL->buflen) {
 412.844 +      fs_give ((void **) &LOCAL->buf);
 412.845 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 412.846 +				     elt->private.msg.text.text.size) + 1);
 412.847 +    }
 412.848 +				/* read message */
 412.849 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
 412.850 +				/* got text, tie off string */
 412.851 +    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
 412.852 +				/* squeeze out CRs (in case from PC) */
 412.853 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 412.854 +      if (*t != '\r') *s++ = *t;
 412.855 +    *s = '\0';
 412.856 +    *length = s - LOCAL->buf;	/* adjust length */
 412.857 +    return (char *) LOCAL->buf;
 412.858 +  }
 412.859 +
 412.860 +				/* have it cached already? */
 412.861 +  if (elt->private.uid != LOCAL->uid) {
 412.862 +				/* not cached, cache it now */
 412.863 +    LOCAL->uid = elt->private.uid;
 412.864 +				/* is buffer big enough? */
 412.865 +    if (elt->rfc822_size > LOCAL->text.size) {
 412.866 +      /* excessively conservative, but the right thing is too hard to do */
 412.867 +      fs_give ((void **) &LOCAL->text.data);
 412.868 +      LOCAL->text.data = (unsigned char *)
 412.869 +	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
 412.870 +    }
 412.871 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
 412.872 +    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
 412.873 +    d.chunk = tmp;		/* initial buffer chunk */
 412.874 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
 412.875 +    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
 412.876 +    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
 412.877 +    case '\r':			/* carriage return seen */
 412.878 +      break;
 412.879 +    case '\n':
 412.880 +      *s++ = '\r';		/* insert a CR */
 412.881 +    default:
 412.882 +      *s++ = c;			/* copy characters */
 412.883 +    }
 412.884 +    *s = '\0';			/* tie off buffer */
 412.885 +				/* calculate length of cached data */
 412.886 +    LOCAL->textlen = s - LOCAL->text.data;
 412.887 +  }
 412.888 +  *length = LOCAL->textlen;	/* return from cache */
 412.889 +  return (char *) LOCAL->text.data;
 412.890 +}
 412.891 +
 412.892 +/* MMDF per-message modify flag
 412.893 + * Accepts: MAIL stream
 412.894 + *	    message cache element
 412.895 + */
 412.896 +
 412.897 +void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 412.898 +{
 412.899 +				/* only after finishing */
 412.900 +  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
 412.901 +}
 412.902 +
 412.903 +
 412.904 +/* MMDF mail ping mailbox
 412.905 + * Accepts: MAIL stream
 412.906 + * Returns: T if stream alive, else NIL
 412.907 + */
 412.908 +
 412.909 +long mmdf_ping (MAILSTREAM *stream)
 412.910 +{
 412.911 +  DOTLOCK lock;
 412.912 +  struct stat sbuf;
 412.913 +  long reparse;
 412.914 +				/* big no-op if not readwrite */
 412.915 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
 412.916 +    if (stream->rdonly) {	/* does he want to give up readwrite? */
 412.917 +				/* checkpoint if we changed something */
 412.918 +      if (LOCAL->dirty) mmdf_check (stream);
 412.919 +      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
 412.920 +      close (LOCAL->ld);	/* close the readwrite lock file */
 412.921 +      LOCAL->ld = -1;		/* no more readwrite lock fd */
 412.922 +      unlink (LOCAL->lname);	/* delete the readwrite lock file */
 412.923 +    }
 412.924 +    else {			/* see if need to reparse */
 412.925 +      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
 412.926 +				/* get current mailbox size */
 412.927 +	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
 412.928 +	else if (stat (stream->mailbox,&sbuf)) {
 412.929 +	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
 412.930 +		   strerror (errno));
 412.931 +	  MM_LOG (LOCAL->buf,ERROR);
 412.932 +	  mmdf_abort (stream);
 412.933 +	  return NIL;
 412.934 +	}
 412.935 +	reparse = (sbuf.st_size != LOCAL->filesize);
 412.936 +      }
 412.937 +				/* parse if mailbox changed */
 412.938 +      if ((LOCAL->ddirty || reparse) && mmdf_parse (stream,&lock,LOCK_EX)) {
 412.939 +				/* force checkpoint if double-dirty */
 412.940 +	if (LOCAL->ddirty) mmdf_rewrite (stream,NIL,&lock,NIL);
 412.941 +				/* unlock mailbox */
 412.942 +	else mmdf_unlock (LOCAL->fd,stream,&lock);
 412.943 +	mail_unlock (stream);	/* and stream */
 412.944 +				/* done with critical */
 412.945 +	MM_NOCRITICAL (stream);
 412.946 +      }
 412.947 +    }
 412.948 +  }
 412.949 +  return LOCAL ? LONGT : NIL;	/* return if still alive */
 412.950 +}
 412.951 +
 412.952 +/* MMDF mail check mailbox
 412.953 + * Accepts: MAIL stream
 412.954 + */
 412.955 +
 412.956 +void mmdf_check (MAILSTREAM *stream)
 412.957 +{
 412.958 +  DOTLOCK lock;
 412.959 +				/* parse and lock mailbox */
 412.960 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 412.961 +      mmdf_parse (stream,&lock,LOCK_EX)) {
 412.962 +				/* any unsaved changes? */
 412.963 +    if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock,NIL)) {
 412.964 +      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
 412.965 +    }
 412.966 +				/* no checkpoint needed, just unlock */
 412.967 +    else mmdf_unlock (LOCAL->fd,stream,&lock);
 412.968 +    mail_unlock (stream);	/* unlock the stream */
 412.969 +    MM_NOCRITICAL (stream);	/* done with critical */
 412.970 +  }
 412.971 +}
 412.972 +
 412.973 +
 412.974 +/* MMDF mail expunge mailbox
 412.975 + * Accepts: MAIL stream
 412.976 + *	    sequence to expunge if non-NIL
 412.977 + *	    expunge options
 412.978 + * Returns: T, always
 412.979 + */
 412.980 +
 412.981 +long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options)
 412.982 +{
 412.983 +  long ret;
 412.984 +  unsigned long i;
 412.985 +  DOTLOCK lock;
 412.986 +  char *msg = NIL;
 412.987 +  if (ret = (sequence ? ((options & EX_UID) ?
 412.988 +			 mail_uid_sequence (stream,sequence) :
 412.989 +			 mail_sequence (stream,sequence)) : LONGT) &&
 412.990 +      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 412.991 +      mmdf_parse (stream,&lock,LOCK_EX)) {
 412.992 +				/* check expunged messages if not dirty */
 412.993 +    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
 412.994 +      MESSAGECACHE *elt = mail_elt (stream,i);
 412.995 +      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
 412.996 +    }
 412.997 +    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
 412.998 +      mmdf_unlock (LOCAL->fd,stream,&lock);
 412.999 +      msg = "No messages deleted, so no update needed";
412.1000 +    }
412.1001 +    else if (mmdf_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
412.1002 +      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
412.1003 +      else msg = "Mailbox checkpointed, but no messages expunged";
412.1004 +    }
412.1005 +				/* rewrite failed */
412.1006 +    else mmdf_unlock (LOCAL->fd,stream,&lock);
412.1007 +    mail_unlock (stream);	/* unlock the stream */
412.1008 +    MM_NOCRITICAL (stream);	/* done with critical */
412.1009 +    if (msg && !stream->silent) MM_LOG (msg,NIL);
412.1010 +  }
412.1011 +  else if (!stream->silent)
412.1012 +    MM_LOG ("Expunge ignored on readonly mailbox",WARN);
412.1013 +  return ret;
412.1014 +}
412.1015 +
412.1016 +/* MMDF mail copy message(s)
412.1017 + * Accepts: MAIL stream
412.1018 + *	    sequence
412.1019 + *	    destination mailbox
412.1020 + *	    copy options
412.1021 + * Returns: T if copy successful, else NIL
412.1022 + */
412.1023 +
412.1024 +long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
412.1025 +{
412.1026 +  struct stat sbuf;
412.1027 +  int fd;
412.1028 +  char *s,file[MAILTMPLEN];
412.1029 +  DOTLOCK lock;
412.1030 +  time_t tp[2];
412.1031 +  unsigned long i,j;
412.1032 +  MESSAGECACHE *elt;
412.1033 +  long ret = T;
412.1034 +  mailproxycopy_t pc =
412.1035 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
412.1036 +  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
412.1037 +			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
412.1038 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
412.1039 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
412.1040 +  MAILSTREAM *tstream = NIL;
412.1041 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
412.1042 +	mail_sequence (stream,sequence))) return NIL;
412.1043 +				/* make sure destination is valid */
412.1044 +  if (!(mmdf_valid (mailbox) || !errno))
412.1045 +    switch (errno) {
412.1046 +    case ENOENT:		/* no such file? */
412.1047 +      if (compare_cstring (mailbox,"INBOX")) {
412.1048 +	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
412.1049 +	return NIL;
412.1050 +      }
412.1051 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
412.1052 +      mmdf_create (NIL,"INBOX");/* create empty INBOX */
412.1053 +    case EACCES:		/* file protected */
412.1054 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
412.1055 +      MM_LOG (LOCAL->buf,ERROR);
412.1056 +      return NIL;
412.1057 +    case EINVAL:
412.1058 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
412.1059 +      sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox);
412.1060 +      MM_LOG (LOCAL->buf,ERROR);
412.1061 +      return NIL;
412.1062 +    default:
412.1063 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
412.1064 +      sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox);
412.1065 +      MM_LOG (LOCAL->buf,ERROR);
412.1066 +      return NIL;
412.1067 +    }
412.1068 +
412.1069 +				/* try to open rewrite for UIDPLUS */
412.1070 +  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
412.1071 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
412.1072 +    tstream = mail_close (tstream);
412.1073 +  if (cu && !tstream) {		/* wanted a COPYUID? */
412.1074 +    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
412.1075 +	     mailbox);
412.1076 +    MM_LOG (LOCAL->buf,WARN);
412.1077 +    cu = NIL;			/* don't try to do COPYUID */
412.1078 +  }
412.1079 +  LOCAL->buf[0] = '\0';
412.1080 +  MM_CRITICAL (stream);		/* go critical */
412.1081 +  if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
412.1082 +		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
412.1083 +		       &lock,LOCK_EX)) < 0) {
412.1084 +    MM_NOCRITICAL (stream);	/* done with critical */
412.1085 +    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
412.1086 +    MM_LOG (LOCAL->buf,ERROR);	/* log the error */
412.1087 +    return NIL;			/* failed */
412.1088 +  }
412.1089 +  fstat (fd,&sbuf);		/* get current file size */
412.1090 +				/* write all requested messages to mailbox */
412.1091 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
412.1092 +    if ((elt = mail_elt (stream,i))->sequence) {
412.1093 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
412.1094 +      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
412.1095 +      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
412.1096 +      else {			/* internal header succeeded */
412.1097 +	s = mmdf_header (stream,i,&j,FT_INTERNAL);
412.1098 +				/* header size, sans trailing newline */
412.1099 +	if (j && (s[j - 2] == '\n')) j--;
412.1100 +	if (write (fd,s,j) < 0) ret = NIL;
412.1101 +	else {			/* message header succeeded */
412.1102 +	  j = tstream ?		/* write UIDPLUS data if have readwrite */
412.1103 +	    mmdf_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
412.1104 +	    mmdf_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
412.1105 +	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
412.1106 +	  else {		/* message status succeeded */
412.1107 +	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
412.1108 +	    if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0))
412.1109 +	      ret = NIL;
412.1110 +	    else if (cu) {	/* need to pass back new UID? */
412.1111 +	      mail_append_set (source,mail_uid (stream,i));
412.1112 +	      mail_append_set (dest,tstream->uid_last);
412.1113 +	    }
412.1114 +	  }
412.1115 +	}
412.1116 +      }
412.1117 +    }
412.1118 +
412.1119 +  if (!ret || fsync (fd)) {	/* force out the update */
412.1120 +    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
412.1121 +    ftruncate (fd,sbuf.st_size);
412.1122 +    ret = NIL;
412.1123 +  }
412.1124 +				/* force UIDVALIDITY assignment now */
412.1125 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
412.1126 +				/* return sets if doing COPYUID */
412.1127 +  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
412.1128 +  else {			/* flush any sets we may have built */
412.1129 +    mail_free_searchset (&source);
412.1130 +    mail_free_searchset (&dest);
412.1131 +  }
412.1132 +  tp[1] = time (0);		/* set mtime to now */
412.1133 +  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
412.1134 +  else tp[0] =			/* else preserve \Marked status */
412.1135 +	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
412.1136 +	 sbuf.st_atime : tp[1];
412.1137 +  utime (file,tp);		/* set the times */
412.1138 +  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
412.1139 +  if (tstream) {		/* update last UID if we can */
412.1140 +    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
412.1141 +    local->dirty = T;		/* do a rewrite */
412.1142 +    local->appending = T;	/* but not at the cost of marking as old */
412.1143 +    tstream = mail_close (tstream);
412.1144 +  }
412.1145 +				/* log the error */
412.1146 +  if (!ret) MM_LOG (LOCAL->buf,ERROR);
412.1147 +				/* delete if requested message */
412.1148 +  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
412.1149 +    if ((elt = mail_elt (stream,i))->sequence)
412.1150 +      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
412.1151 +  MM_NOCRITICAL (stream);	/* release critical */
412.1152 +  return ret;
412.1153 +}
412.1154 +
412.1155 +/* MMDF mail append message from stringstruct
412.1156 + * Accepts: MAIL stream
412.1157 + *	    destination mailbox
412.1158 + *	    append callback
412.1159 + *	    data for callback
412.1160 + * Returns: T if append successful, else NIL
412.1161 + */
412.1162 +
412.1163 +#define BUFLEN 8*MAILTMPLEN
412.1164 +
412.1165 +long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
412.1166 +{
412.1167 +  struct stat sbuf;
412.1168 +  int fd;
412.1169 +  unsigned long i;
412.1170 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
412.1171 +  time_t tp[2];
412.1172 +  FILE *sf,*df;
412.1173 +  MESSAGECACHE elt;
412.1174 +  DOTLOCK lock;
412.1175 +  STRING *message;
412.1176 +  unsigned long uidlocation = 0;
412.1177 +  appenduid_t au = (appenduid_t)
412.1178 +    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
412.1179 +     mail_parameters (NIL,GET_APPENDUID,NIL));
412.1180 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
412.1181 +  long ret = LONGT;
412.1182 +  MAILSTREAM *tstream = NIL;
412.1183 +				/* default stream to prototype */
412.1184 +  if (!stream) {		/* stream specified? */
412.1185 +    stream = &mmdfproto;	/* no, default stream to prototype */
412.1186 +    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
412.1187 +      fs_give ((void **) &stream->user_flags[i]);
412.1188 +  }
412.1189 +  if (!mmdf_valid (mailbox)) switch (errno) {
412.1190 +  case ENOENT:			/* no such file? */
412.1191 +    if (compare_cstring (mailbox,"INBOX")) {
412.1192 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
412.1193 +      return NIL;
412.1194 +    }
412.1195 +    mmdf_create (NIL,"INBOX");	/* create empty INBOX */
412.1196 +  case 0:			/* merely empty file? */
412.1197 +    tstream = stream;
412.1198 +    break;
412.1199 +  case EACCES:			/* file protected */
412.1200 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
412.1201 +    MM_LOG (tmp,ERROR);
412.1202 +    return NIL;
412.1203 +  case EINVAL:
412.1204 +    sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox);
412.1205 +    MM_LOG (tmp,ERROR);
412.1206 +    return NIL;
412.1207 +  default:
412.1208 +    sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox);
412.1209 +    MM_LOG (tmp,ERROR);
412.1210 +    return NIL;
412.1211 +  }
412.1212 +				/* get sniffing stream for keywords */
412.1213 +  else if (!(tstream = mail_open (NIL,mailbox,
412.1214 +				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
412.1215 +    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
412.1216 +    MM_LOG (tmp,ERROR);
412.1217 +    return NIL;
412.1218 +  }
412.1219 +
412.1220 +				/* get first message */
412.1221 +  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
412.1222 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
412.1223 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
412.1224 +    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
412.1225 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
412.1226 +      MM_LOG (tmp,ERROR);
412.1227 +      return NIL;
412.1228 +    }
412.1229 +    unlink (tmp);
412.1230 +  }
412.1231 +  do {				/* parse date */
412.1232 +    if (!date) rfc822_date (date = tmp);
412.1233 +    if (!mail_parse_date (&elt,date)) {
412.1234 +      sprintf (tmp,"Bad date in append: %.80s",date);
412.1235 +      MM_LOG (tmp,ERROR);
412.1236 +    }
412.1237 +    else {			/* user wants to suppress time zones? */
412.1238 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
412.1239 +	time_t when = mail_longdate (&elt);
412.1240 +	date = ctime (&when);	/* use traditional date */
412.1241 +      }
412.1242 +				/* use POSIX-style date */
412.1243 +      else date = mail_cdate (tmp,&elt);
412.1244 +      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
412.1245 +      else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) {
412.1246 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
412.1247 +	MM_LOG (tmp,ERROR);
412.1248 +      }
412.1249 +				/* get next message */
412.1250 +      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
412.1251 +    }
412.1252 +    fclose (sf);		/* punt scratch file */
412.1253 +    return NIL;			/* give up */
412.1254 +  } while (message);		/* until no more messages */
412.1255 +  if (fflush (sf)) {
412.1256 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
412.1257 +    MM_LOG (tmp,ERROR);
412.1258 +    fclose (sf);		/* punt scratch file */
412.1259 +    return NIL;			/* give up */
412.1260 +  }
412.1261 +  i = ftell (sf);		/* size of scratch file */
412.1262 +  if (tstream != stream) tstream = mail_close (tstream);
412.1263 +
412.1264 +  MM_CRITICAL (stream);		/* go critical */
412.1265 +				/* try to open readwrite for UIDPLUS */
412.1266 +  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
412.1267 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
412.1268 +    tstream = mail_close (tstream);
412.1269 +  if (au && !tstream) {		/* wanted an APPENDUID? */
412.1270 +    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
412.1271 +    MM_LOG (tmp,WARN);
412.1272 +    au = NIL;
412.1273 +  }
412.1274 +  if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
412.1275 +			(long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
412.1276 +			&lock,LOCK_EX)) < 0) ||
412.1277 +      !(df = fdopen (fd,"ab"))) {
412.1278 +    MM_NOCRITICAL (stream);	/* done with critical */
412.1279 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
412.1280 +    MM_LOG (tmp,ERROR);
412.1281 +    return NIL;
412.1282 +  }
412.1283 +  fstat (fd,&sbuf);		/* get current file size */
412.1284 +  rewind (sf);
412.1285 +  tp[1] = time (0);		/* set mtime to now */
412.1286 +				/* write all messages */
412.1287 +  if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) ||
412.1288 +      (fflush (df) == EOF) || fsync (fd)) {
412.1289 +    sprintf (buf,"Message append failed: %s",strerror (errno));
412.1290 +    MM_LOG (buf,ERROR);
412.1291 +    ftruncate (fd,sbuf.st_size);
412.1292 +    tp[0] =			/* preserve \Marked status */
412.1293 +      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
412.1294 +      sbuf.st_atime : tp[1];
412.1295 +    ret = NIL;			/* return error */
412.1296 +  }
412.1297 +  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
412.1298 +  utime (file,tp);		/* set the times */
412.1299 +  fclose (sf);			/* done with scratch file */
412.1300 +				/* force UIDVALIDITY assignment now */
412.1301 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
412.1302 +				/* return sets if doing APPENDUID */
412.1303 +  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
412.1304 +  else mail_free_searchset (&dst);
412.1305 +  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
412.1306 +  fclose (df);
412.1307 +  if (tstream) {		/* update last UID if we can */
412.1308 +    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
412.1309 +    local->dirty = T;		/* do a rewrite */
412.1310 +    local->appending = T;	/* but not at the cost of marking as old */
412.1311 +    tstream = mail_close (tstream);
412.1312 +  }
412.1313 +  MM_NOCRITICAL (stream);	/* release critical */
412.1314 +  return ret;
412.1315 +}
412.1316 +
412.1317 +/* Collect and write single message to append scratch file
412.1318 + * Accepts: MAIL stream
412.1319 + *	    scratch file
412.1320 + *	    flags
412.1321 + *	    date
412.1322 + *	    message stringstruct
412.1323 + * Returns: NIL if write error, else T
412.1324 + */
412.1325 +
412.1326 +int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
412.1327 +  		     STRING *msg)
412.1328 +{
412.1329 +  unsigned char *s,*t;
412.1330 +  unsigned long uf;
412.1331 +  long f = mail_parse_flags (stream,flags,&uf);
412.1332 +				/* write metadata, note date ends with NL */
412.1333 +  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
412.1334 +  while (uf)			/* write user flags */    
412.1335 +    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
412.1336 +	(fprintf (sf," %s",s) < 0)) return NIL;
412.1337 +  if (putc ('\n',sf) == EOF) return NIL;
412.1338 +  while (SIZE (msg)) {		/* copy text to scratch file */
412.1339 +    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
412.1340 +      if (!*s) *s = 0x80;	/* disallow NUL */
412.1341 +				/* write buffered text */
412.1342 +    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
412.1343 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
412.1344 +    else return NIL;		/* failed */
412.1345 +  }
412.1346 +				/* write trailing newline and return */
412.1347 +  return (putc ('\n',sf) == EOF) ? NIL : T;
412.1348 +}
412.1349 +
412.1350 +/* Append messages from scratch file to mailbox
412.1351 + * Accepts: MAIL stream
412.1352 + *	    source file
412.1353 + *	    destination file
412.1354 + *	    uidset to update if non-NIL
412.1355 + * Returns: T if success, NIL if failure
412.1356 + */
412.1357 +
412.1358 +int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
412.1359 +{
412.1360 +  int c;
412.1361 +  long f;
412.1362 +  unsigned long i,j;
412.1363 +  char *x,tmp[MAILTMPLEN];
412.1364 +  int hdrp = T;
412.1365 +				/* get message metadata line */
412.1366 +  while (fgets (tmp,MAILTMPLEN,sf)) {
412.1367 +    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
412.1368 +    f = strtol (tmp,&x,10);	/* get flags */
412.1369 +    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
412.1370 +    i = strtoul (x,&x,10);	/* get message size */
412.1371 +    if ((*x++ != ' ') ||	/* build initial header */
412.1372 +	(fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(),
412.1373 +		  mylocalhost(),x) < 0) ||
412.1374 +	(f&fSEEN && (putc ('R',df) == EOF)) ||
412.1375 +	(fputs ("\nX-Status: ",df) == EOF) ||
412.1376 +	(f&fDELETED && (putc ('D',df) == EOF)) ||
412.1377 +	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
412.1378 +	(f&fANSWERED && (putc ('A',df) == EOF)) ||
412.1379 +	(f&fDRAFT && (putc ('T',df) == EOF)) ||
412.1380 +	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
412.1381 +				/* copy keywords */
412.1382 +    while ((c = getc (sf)) != '\n') switch (c) {
412.1383 +    case EOF:
412.1384 +      return NIL;
412.1385 +    default:
412.1386 +      if (putc (c,df) == EOF) return NIL;
412.1387 +    }
412.1388 +    if ((putc ('\n',df) == EOF) ||
412.1389 +	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
412.1390 +      return NIL;
412.1391 +
412.1392 +    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
412.1393 +				/* get read line length */
412.1394 +      if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun");
412.1395 +      i -= j;			/* number of bytes left */
412.1396 +				/* squish out ^A and CRs (note copies NUL) */
412.1397 +      for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp));
412.1398 +      if (!j) continue;		/* do nothing if line emptied */
412.1399 +				/* start of line? */
412.1400 +      if ((c == '\n')) switch (tmp[0]) {
412.1401 +      case 'S': case 's':	/* possible "Status:" */
412.1402 +	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
412.1403 +	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
412.1404 +	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
412.1405 +	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
412.1406 +	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
412.1407 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
412.1408 +	break;
412.1409 +      case 'X': case 'x':	/* possible X-??? header */
412.1410 +	if (hdrp && (tmp[1] == '-') &&
412.1411 +				/* possible X-UID: */
412.1412 +	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
412.1413 +	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
412.1414 +	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
412.1415 +				/* possible X-IMAP: */
412.1416 +	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
412.1417 +	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
412.1418 +	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
412.1419 +	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
412.1420 +	      ((tmp[6] == ':') ||
412.1421 +				/* or X-IMAPbase: */
412.1422 +	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
412.1423 +		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
412.1424 +		((tmp[8] == 's') || (tmp[8] == 'S')) &&
412.1425 +		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
412.1426 +				/* possible X-Status: */
412.1427 +	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
412.1428 +	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
412.1429 +	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
412.1430 +	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
412.1431 +	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
412.1432 +	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
412.1433 +				/* possible X-Keywords: */
412.1434 +	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
412.1435 +	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
412.1436 +	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
412.1437 +	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
412.1438 +	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
412.1439 +	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
412.1440 +	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
412.1441 +	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
412.1442 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
412.1443 +	break;
412.1444 +      case '\n':		/* blank line */
412.1445 +	hdrp = NIL;
412.1446 +	break;
412.1447 +      default:			/* nothing to do */
412.1448 +	break;
412.1449 +      }
412.1450 +				/* just write the line */
412.1451 +      if (fwrite (tmp,1,j,df) != j) return NIL;
412.1452 +    }
412.1453 +				/* make sure read entire msg & wrote trailer */
412.1454 +    if (i || (fputs (mmdfhdr,df) == EOF)) return NIL;
412.1455 +				/* update set */
412.1456 +    if (stream) mail_append_set (set,stream->uid_last);
412.1457 +  }
412.1458 +  return T;
412.1459 +}
412.1460 +
412.1461 +/* Internal routines */
412.1462 +
412.1463 +
412.1464 +/* MMDF mail abort stream
412.1465 + * Accepts: MAIL stream
412.1466 + */
412.1467 +
412.1468 +void mmdf_abort (MAILSTREAM *stream)
412.1469 +{
412.1470 +  if (LOCAL) {			/* only if a file is open */
412.1471 +    if (LOCAL->fd >= 0) close (LOCAL->fd);
412.1472 +    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
412.1473 +      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
412.1474 +      close (LOCAL->ld);	/* close the lock file */
412.1475 +      unlink (LOCAL->lname);	/* and delete it */
412.1476 +    }
412.1477 +    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
412.1478 +				/* free local text buffers */
412.1479 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
412.1480 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
412.1481 +    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
412.1482 +    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
412.1483 +				/* nuke the local data */
412.1484 +    fs_give ((void **) &stream->local);
412.1485 +    stream->dtb = NIL;		/* log out the DTB */
412.1486 +  }
412.1487 +}
412.1488 +
412.1489 +/* MMDF open and lock mailbox
412.1490 + * Accepts: file name to open/lock
412.1491 + *	    file open mode
412.1492 + *	    destination buffer for lock file name
412.1493 + *	    type of locking operation (LOCK_SH or LOCK_EX)
412.1494 + */
412.1495 +
412.1496 +int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
412.1497 +{
412.1498 +  int fd;
412.1499 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
412.1500 +  (*bn) (BLOCK_FILELOCK,NIL);
412.1501 +				/* try locking the easy way */
412.1502 +  if (dotlock_lock (file,lock,-1)) {
412.1503 +				/* got dotlock file, easy open */
412.1504 +    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
412.1505 +    else dotlock_unlock (lock);	/* open failed, free the dotlock */
412.1506 +  }
412.1507 +				/* no dot lock file, open file now */
412.1508 +  else if ((fd = open (file,flags,mode)) >= 0) {
412.1509 +				/* try paranoid way to make a dot lock file */
412.1510 +    if (dotlock_lock (file,lock,fd)) {
412.1511 +      close (fd);		/* get fresh fd in case of timing race */
412.1512 +      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
412.1513 +				/* open failed, free the dotlock */
412.1514 +      else dotlock_unlock (lock);
412.1515 +    }
412.1516 +    else flock (fd,op);		/* paranoid way failed, just flock() it */
412.1517 +  }
412.1518 +  (*bn) (BLOCK_NONE,NIL);
412.1519 +  return fd;
412.1520 +}
412.1521 +
412.1522 +/* MMDF unlock and close mailbox
412.1523 + * Accepts: file descriptor
412.1524 + *	    (optional) mailbox stream to check atime/mtime
412.1525 + *	    (optional) lock file name
412.1526 + */
412.1527 +
412.1528 +void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
412.1529 +{
412.1530 +  if (stream) {			/* need to muck with times? */
412.1531 +    struct stat sbuf;
412.1532 +    time_t tp[2];
412.1533 +    time_t now = time (0);
412.1534 +    fstat (fd,&sbuf);		/* get file times */
412.1535 +    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
412.1536 +      tp[0] = now;		/* set atime to now */
412.1537 +				/* set mtime to (now - 1) if necessary */
412.1538 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
412.1539 +    }
412.1540 +    else if (stream->recent) {	/* readonly with recent messages */
412.1541 +      if ((sbuf.st_atime >= sbuf.st_mtime) ||
412.1542 +	  (sbuf.st_atime >= sbuf.st_ctime))
412.1543 +				/* keep past mtime, whack back atime */
412.1544 +	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
412.1545 +      else now = 0;		/* no time change needed */
412.1546 +    }
412.1547 +				/* readonly with no recent messages */
412.1548 +    else if ((sbuf.st_atime < sbuf.st_mtime) ||
412.1549 +	     (sbuf.st_atime < sbuf.st_ctime)) {
412.1550 +      tp[0] = now;		/* set atime to now */
412.1551 +				/* set mtime to (now - 1) if necessary */
412.1552 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
412.1553 +    }
412.1554 +    else now = 0;		/* no time change needed */
412.1555 +				/* set the times, note change */
412.1556 +    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
412.1557 +  }
412.1558 +  flock (fd,LOCK_UN);		/* release flock'ers */
412.1559 +  if (!stream) close (fd);	/* close the file if no stream */
412.1560 +  dotlock_unlock (lock);	/* flush the lock file if any */
412.1561 +}
412.1562 +
412.1563 +/* MMDF mail parse and lock mailbox
412.1564 + * Accepts: MAIL stream
412.1565 + *	    space to write lock file name
412.1566 + *	    type of locking operation
412.1567 + * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
412.1568 + */
412.1569 +
412.1570 +int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
412.1571 +{
412.1572 +  int ti,zn,m;
412.1573 +  unsigned long i,j,k;
412.1574 +  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
412.1575 +  int retain = T;
412.1576 +  unsigned long nmsgs = stream->nmsgs;
412.1577 +  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
412.1578 +  unsigned long recent = stream->recent;
412.1579 +  unsigned long oldnmsgs = stream->nmsgs;
412.1580 +  short silent = stream->silent;
412.1581 +  short pseudoseen = NIL;
412.1582 +  struct stat sbuf;
412.1583 +  STRING bs;
412.1584 +  FDDATA d;
412.1585 +  MESSAGECACHE *elt;
412.1586 +  mail_lock (stream);		/* guard against recursion or pingers */
412.1587 +				/* toss out previous descriptor */
412.1588 +  if (LOCAL->fd >= 0) close (LOCAL->fd);
412.1589 +  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
412.1590 +  if ((LOCAL->fd = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ?
412.1591 +			      O_RDWR : O_RDONLY,
412.1592 +			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
412.1593 +			      lock,op)) < 0) {
412.1594 +    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
412.1595 +    MM_LOG (tmp,ERROR);
412.1596 +    mmdf_abort (stream);
412.1597 +    mail_unlock (stream);
412.1598 +    MM_NOCRITICAL (stream);	/* done with critical */
412.1599 +    return NIL;
412.1600 +  }
412.1601 +  fstat (LOCAL->fd,&sbuf);	/* get status */
412.1602 +				/* validate change in size */
412.1603 +  if (sbuf.st_size < LOCAL->filesize) {
412.1604 +    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
412.1605 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
412.1606 +    MM_LOG (tmp,ERROR);		/* this is pretty bad */
412.1607 +    mmdf_unlock (LOCAL->fd,stream,lock);
412.1608 +    mmdf_abort (stream);
412.1609 +    mail_unlock (stream);
412.1610 +    MM_NOCRITICAL (stream);	/* done with critical */
412.1611 +    return NIL;
412.1612 +  }
412.1613 +
412.1614 +				/* new data? */
412.1615 +  else if (i = sbuf.st_size - LOCAL->filesize) {
412.1616 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
412.1617 +    d.pos = LOCAL->filesize;	/* get to that position in the file */
412.1618 +    d.chunk = LOCAL->buf;	/* initial buffer chunk */
412.1619 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
412.1620 +    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
412.1621 +				/* skip leading whitespace for broken MTAs */
412.1622 +    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
412.1623 +	   (c == ' ') || (c == '\t')) SNX (&bs);
412.1624 +    if (SIZE (&bs)) {		/* read new data */
412.1625 +				/* remember internal header position */
412.1626 +      j = LOCAL->filesize + GETPOS (&bs);
412.1627 +      s = mmdf_mbxline (stream,&bs,&i);
412.1628 +      stream->silent = T;	/* quell main program new message events */
412.1629 +      do {			/* read MMDF header */
412.1630 +	if (!(i && ISMMDF (s))){/* see if valid MMDF header */
412.1631 +	  sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
412.1632 +		   (char *) s);
412.1633 +				/* see if we can back up to a line */
412.1634 +	  if (i && (j > MMDFHDRLEN)) {
412.1635 +	    SETPOS (&bs,j -= MMDFHDRLEN);
412.1636 +				/* read previous line */
412.1637 +	    s = mmdf_mbxline (stream,&bs,&i);
412.1638 +				/* kill the error if it looks good */
412.1639 +	    if (i && ISMMDF (s)) tmp[0] = '\0';
412.1640 +	  }
412.1641 +	  if (tmp[0]) {
412.1642 +	    MM_LOG (tmp,ERROR);
412.1643 +	    mmdf_unlock (LOCAL->fd,stream,lock);
412.1644 +	    mmdf_abort (stream);
412.1645 +	    mail_unlock (stream);
412.1646 +	    MM_NOCRITICAL (stream);
412.1647 +	    return NIL;
412.1648 +	  }
412.1649 +	}
412.1650 +				/* instantiate first new message */
412.1651 +	mail_exists (stream,++nmsgs);
412.1652 +	(elt = mail_elt (stream,nmsgs))->valid = T;
412.1653 +	recent++;		/* assume recent by default */
412.1654 +	elt->recent = T;
412.1655 +				/* note position/size of internal header */
412.1656 +	elt->private.special.offset = j;
412.1657 +	elt->private.special.text.size = i;
412.1658 +
412.1659 +	s = mmdf_mbxline (stream,&bs,&i);
412.1660 +	ti = 0;			/* assume not a valid date */
412.1661 +	zn = 0,t = NIL;
412.1662 +	if (i) VALID (s,t,ti,zn);
412.1663 +	if (ti) {		/* generate plausible IMAPish date string */
412.1664 +				/* this is also part of header */
412.1665 +	  elt->private.special.text.size += i;
412.1666 +	  date[2] = date[6] = date[20] = '-'; date[11] = ' ';
412.1667 +	  date[14] = date[17] = ':';
412.1668 +				/* dd */
412.1669 +	  date[0] = t[ti - 2]; date[1] = t[ti - 1];
412.1670 +				/* mmm */
412.1671 +	  date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
412.1672 +				/* hh */
412.1673 +	  date[12] = t[ti + 1]; date[13] = t[ti + 2];
412.1674 +				/* mm */
412.1675 +	  date[15] = t[ti + 4]; date[16] = t[ti + 5];
412.1676 +	  if (t[ti += 6]==':'){	/* ss */
412.1677 +	    date[18] = t[++ti]; date[19] = t[++ti];
412.1678 +	    ti++;		/* move to space */
412.1679 +	  }
412.1680 +	  else date[18] = date[19] = '0';
412.1681 +				/* yy -- advance over timezone if necessary */
412.1682 +	  if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
412.1683 +	  date[7] = t[ti + 1]; date[8] = t[ti + 2];
412.1684 +	  date[9] = t[ti + 3]; date[10] = t[ti + 4];
412.1685 +				/* zzz */
412.1686 +	  t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
412.1687 +	  date[21] = *t++; date[22] = *t++; date[23] = *t++;
412.1688 +	  if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
412.1689 +	  else {		/* numeric time zone */
412.1690 +	    date[24] = *t++; date[25] = *t++;
412.1691 +	    date[26] = '\0'; date[20] = ' ';
412.1692 +	  }
412.1693 +				/* set internal date */
412.1694 +	  if (!mail_parse_date (elt,date)) {
412.1695 +	    sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
412.1696 +	    MM_LOG (tmp,WARN);
412.1697 +	  }
412.1698 +	}
412.1699 +	else {			/* make date from file date */
412.1700 +	  struct tm *tm = gmtime (&sbuf.st_mtime);
412.1701 +	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
412.1702 +	  elt->year = tm->tm_year + 1900 - BASEYEAR;
412.1703 +	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
412.1704 +	  elt->seconds = tm->tm_sec;
412.1705 +	  elt->zhours = 0; elt->zminutes = 0;
412.1706 +	  t = NIL;		/* suppress line read */
412.1707 +	}
412.1708 +				/* header starts here */
412.1709 +	elt->private.msg.header.offset = elt->private.special.text.size;
412.1710 +
412.1711 +	do {			/* look for message body */
412.1712 +	  j = GETPOS (&bs);	/* note position before line */
412.1713 +	  if (t) s = t = mmdf_mbxline (stream,&bs,&i);
412.1714 +	  else t = s;		/* this line read was suppressed */
412.1715 +	  if (ISMMDF (s)) {	/* found terminator in header? */
412.1716 +	    SETPOS (&bs,j);	/* oops, back up before line */
412.1717 +				/* must insert a newline */
412.1718 +	    elt->private.spare.data++;
412.1719 +	    break;		/* punt */
412.1720 +	  }
412.1721 +				/* this line is part of header */
412.1722 +	  elt->private.msg.header.text.size += i;
412.1723 +	  if (i) switch (*s) {	/* check header lines */
412.1724 +	  case 'X':		/* possible X-???: line */
412.1725 +	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
412.1726 +				/* X-Status: becomes Status: in S case */
412.1727 +	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
412.1728 +		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
412.1729 +				/* possible X-Keywords */
412.1730 +	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
412.1731 +		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
412.1732 +		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
412.1733 +		SIZEDTEXT uf;
412.1734 +		retain = NIL;	/* don't retain continuation */
412.1735 +		s += 11;	/* flush leading whitespace */
412.1736 +		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
412.1737 +		  while (*s == ' ') s++;
412.1738 +				/* find end of keyword */
412.1739 +		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
412.1740 +				/* got a keyword? */
412.1741 +		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
412.1742 +		    uf.data = (unsigned char *) s;
412.1743 +		    uf.size = k;
412.1744 +		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
412.1745 +		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
412.1746 +			elt->user_flags |= ((long) 1) << j;
412.1747 +			break;
412.1748 +		      }
412.1749 +		  }
412.1750 +		  s = u;	/* advance to next keyword */
412.1751 +		}
412.1752 +		break;
412.1753 +	      }
412.1754 +
412.1755 +				/* possible X-IMAP */
412.1756 +	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
412.1757 +		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
412.1758 +					 ((s[6] == 'b') && (s[7] == 'a') &&
412.1759 +					  (s[8] == 's') && (s[9] == 'e') &&
412.1760 +					  (s[10] == ':')))) {
412.1761 +		retain = NIL;	/* don't retain continuation */
412.1762 +		if ((nmsgs == 1) && !stream->uid_validity) {
412.1763 +				/* advance to data */
412.1764 +		  s += m ? 7 : 11;
412.1765 +				/* flush whitespace */
412.1766 +		  while (*s == ' ') s++;
412.1767 +		  j = 0;	/* slurp UID validity */
412.1768 +				/* found a digit? */
412.1769 +		  while (isdigit (*s)) {
412.1770 +		    j *= 10;	/* yes, add it in */
412.1771 +		    j += *s++ - '0';
412.1772 +		  }
412.1773 +				/* flush whitespace */
412.1774 +		  while (*s == ' ') s++;
412.1775 +				/* must have valid UID validity and UID last */
412.1776 +		  if (j && isdigit (*s)) {
412.1777 +				/* pseudo-header seen if X-IMAP */
412.1778 +		    if (m) pseudoseen = LOCAL->pseudo = T;
412.1779 +				/* save UID validity */
412.1780 +		    stream->uid_validity = j;
412.1781 +		    j = 0;	/* slurp UID last */
412.1782 +		    while (isdigit (*s)) {
412.1783 +		      j *= 10;	/* yes, add it in */
412.1784 +		      j += *s++ - '0';
412.1785 +		    }
412.1786 +				/* save UID last */
412.1787 +		    stream->uid_last = j;
412.1788 +				/* process keywords */
412.1789 +		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
412.1790 +			 s = u,j++) {
412.1791 +				/* flush leading whitespace */
412.1792 +		      while (*s == ' ') s++;
412.1793 +		      u = strpbrk (s," \n\r");
412.1794 +				/* got a keyword? */
412.1795 +		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
412.1796 +			  (k <= MAXUSERFLAG)) {
412.1797 +			if (stream->user_flags[j])
412.1798 +			  fs_give ((void **) &stream->user_flags[j]);
412.1799 +			stream->user_flags[j] = (char *) fs_get (k + 1);
412.1800 +			strncpy (stream->user_flags[j],s,k);
412.1801 +			stream->user_flags[j][k] = '\0';
412.1802 +		      }
412.1803 +		    }
412.1804 +		  }
412.1805 +		}
412.1806 +		break;
412.1807 +	      }
412.1808 +
412.1809 +				/* possible X-UID */
412.1810 +	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
412.1811 +		       s[5] == ':') {
412.1812 +		retain = NIL;	/* don't retain continuation */
412.1813 +				/* only believe if have a UID validity */
412.1814 +		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
412.1815 +		  s += 6;	/* advance to UID value */
412.1816 +				/* flush whitespace */
412.1817 +		  while (*s == ' ') s++;
412.1818 +		  j = 0;
412.1819 +				/* found a digit? */
412.1820 +		  while (isdigit (*s)) {
412.1821 +		    j *= 10;	/* yes, add it in */
412.1822 +		    j += *s++ - '0';
412.1823 +		  }
412.1824 +				/* flush remainder of line */
412.1825 +		  while (*s != '\n') s++;
412.1826 +				/* make sure not duplicated */
412.1827 +		  if (elt->private.uid)
412.1828 +		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
412.1829 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
412.1830 +			     j,elt->private.uid);
412.1831 +				/* make sure UID doesn't go backwards */
412.1832 +		  else if (j <= prevuid)
412.1833 +		    sprintf (tmp,"Message %lu UID %lu less than %lu",
412.1834 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
412.1835 +			     j,prevuid + 1);
412.1836 +#if 0	/* this is currently broken by UIDPLUS */
412.1837 +				/* or skip by mailbox's recorded last */
412.1838 +		  else if (j > stream->uid_last)
412.1839 +		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
412.1840 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
412.1841 +			     j,stream->uid_last);
412.1842 +#endif
412.1843 +		  else {	/* normal UID case */
412.1844 +		    prevuid = elt->private.uid = j;
412.1845 +#if 1	/* temporary kludge for UIDPLUS */
412.1846 +		    if (prevuid > stream->uid_last) {
412.1847 +		      stream->uid_last = prevuid;
412.1848 +		      LOCAL->ddirty = LOCAL->dirty = T;
412.1849 +		    }		    
412.1850 +#endif
412.1851 +		    break;	/* exit this cruft */
412.1852 +		  }
412.1853 +		  MM_LOG (tmp,WARN);
412.1854 +				/* invalidate UID validity */
412.1855 +		  stream->uid_validity = 0;
412.1856 +		  elt->private.uid = 0;
412.1857 +		}
412.1858 +		break;
412.1859 +	      }
412.1860 +	    }
412.1861 +				/* otherwise fall into S case */
412.1862 +
412.1863 +	  case 'S':		/* possible Status: line */
412.1864 +	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
412.1865 +		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
412.1866 +	      retain = NIL;	/* don't retain continuation */
412.1867 +	      s += 6;		/* advance to status flags */
412.1868 +	      do switch (*s++) {/* parse flags */
412.1869 +	      case 'R':		/* message read */
412.1870 +		elt->seen = T;
412.1871 +		break;
412.1872 +	      case 'O':		/* message old */
412.1873 +		if (elt->recent) {
412.1874 +		  elt->recent = NIL;
412.1875 +		  recent--;	/* it really wasn't recent */
412.1876 +		}
412.1877 +		break;
412.1878 +	      case 'D':		/* message deleted */
412.1879 +		elt->deleted = T;
412.1880 +		break;
412.1881 +	      case 'F':		/* message flagged */
412.1882 +		elt->flagged = T;
412.1883 +		break;
412.1884 +	      case 'A':		/* message answered */
412.1885 +		elt->answered = T;
412.1886 +		break;
412.1887 +	      case 'T':		/* message is a draft */
412.1888 +		elt->draft = T;
412.1889 +		break;
412.1890 +	      default:		/* some other crap */
412.1891 +		break;
412.1892 +	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
412.1893 +	      break;		/* all done */
412.1894 +	    }
412.1895 +				/* otherwise fall into default case */
412.1896 +
412.1897 +	  default:		/* ordinary header line */
412.1898 +	    if ((*s == 'S') || (*s == 's') ||
412.1899 +		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
412.1900 +	      unsigned char *e,*v;
412.1901 +				/* must match what mail_filter() does */
412.1902 +	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
412.1903 +		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
412.1904 +		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
412.1905 +				  (c != '\r') && (c != '\n')));
412.1906 +		   *v++ = *u++);
412.1907 +	      *v = '\0';	/* tie off */
412.1908 +				/* matches internal header? */
412.1909 +	      if (!compare_cstring (tmp,"STATUS") ||
412.1910 +		  !compare_cstring (tmp,"X-STATUS") ||
412.1911 +		  !compare_cstring (tmp,"X-KEYWORDS") ||
412.1912 +		  !compare_cstring (tmp,"X-UID") ||
412.1913 +		  !compare_cstring (tmp,"X-IMAP") ||
412.1914 +		  !compare_cstring (tmp,"X-IMAPBASE")) {
412.1915 +		char err[MAILTMPLEN];
412.1916 +		sprintf (err,"Discarding bogus %s header in message %lu",
412.1917 +			 (char *) tmp,elt->msgno);
412.1918 +		MM_LOG (err,WARN);
412.1919 +		retain = NIL;	/* don't retain continuation */
412.1920 +		break;		/* different case or something */
412.1921 +	      }
412.1922 +	    }
412.1923 +				/* retain or non-continuation? */
412.1924 +	    if (retain || ((*s != ' ') && (*s != '\t'))) {
412.1925 +	      retain = T;	/* retaining continuation now */
412.1926 +				/* line length in LF format newline */
412.1927 +	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
412.1928 +				/* "internal" header size */
412.1929 +	      elt->private.spare.data += k;
412.1930 +				/* message size */
412.1931 +	      elt->rfc822_size += k + 1;
412.1932 +	    }
412.1933 +	    else {
412.1934 +	      char err[MAILTMPLEN];
412.1935 +	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
412.1936 +		      elt->msgno,(char *) s);
412.1937 +	      if (u = strpbrk (err,"\r\n")) *u = '\0';
412.1938 +	      MM_LOG (err,WARN);
412.1939 +	      break;		/* different case or something */
412.1940 +	    }
412.1941 +	    break;
412.1942 +	  }
412.1943 +	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
412.1944 +				/* "internal" header sans trailing newline */
412.1945 +	if (i) elt->private.spare.data--;
412.1946 +				/* assign a UID if none found */
412.1947 +	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
412.1948 +	  prevuid = elt->private.uid = ++stream->uid_last;
412.1949 +	  elt->private.dirty = T;
412.1950 +	}
412.1951 +	else elt->private.dirty = elt->recent;
412.1952 +
412.1953 +				/* note size of header, location of text */
412.1954 +	elt->private.msg.header.text.size =
412.1955 +	  (elt->private.msg.text.offset =
412.1956 +	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
412.1957 +	     elt->private.special.text.size;
412.1958 +				/* note current position */
412.1959 +	j = LOCAL->filesize + GETPOS (&bs);
412.1960 +	if (i) do {		/* look for next message */
412.1961 +	  s = mmdf_mbxline (stream,&bs,&i);
412.1962 +	  if (i) {		/* got new data? */
412.1963 +	    if (ISMMDF (s)) break;
412.1964 +	    else {		/* not a header line, add it to message */
412.1965 +	      elt->rfc822_size += i;
412.1966 +	      for (j = 0; j < i; ++j) switch (s[j]) {
412.1967 +	      case '\r':	/* squeeze out CRs */
412.1968 +		elt->rfc822_size -= 1;
412.1969 +		break;
412.1970 +	      case '\n':	/* LF becomes CRLF */
412.1971 +		elt->rfc822_size += 1;
412.1972 +		break;
412.1973 +	      default:
412.1974 +		break;
412.1975 +	      }
412.1976 +				/* update current position */
412.1977 +	      j = LOCAL->filesize + GETPOS (&bs);
412.1978 +	    }
412.1979 +	  }
412.1980 +	} while (i);		/* until found a header */
412.1981 +	elt->private.msg.text.text.size = j -
412.1982 +	  (elt->private.special.offset + elt->private.msg.text.offset);
412.1983 +	if (i) {		/* get next header line */
412.1984 +				/* remember first internal header position */
412.1985 +	  j = LOCAL->filesize + GETPOS (&bs);
412.1986 +	  s = mmdf_mbxline (stream,&bs,&i);
412.1987 +	}
412.1988 +				/* until end of buffer */
412.1989 +      } while (!stream->sniff && i);
412.1990 +      if (pseudoseen) {		/* flush pseudo-message if present */
412.1991 +				/* decrement recent count */
412.1992 +	if (mail_elt (stream,1)->recent) recent--;
412.1993 +				/* and the exists count */
412.1994 +	mail_exists (stream,nmsgs--);
412.1995 +	mail_expunged(stream,1);/* fake an expunge of that message */
412.1996 +      }
412.1997 +				/* need to start a new UID validity? */
412.1998 +      if (!stream->uid_validity) {
412.1999 +	stream->uid_validity = time (0);
412.2000 +				/* in case a whiner with no life */
412.2001 +	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
412.2002 +	  stream->uid_nosticky = T;
412.2003 +	else if (nmsgs) {	/* don't bother if empty file */
412.2004 +				/* make dirty to restart UID epoch */
412.2005 +	  LOCAL->ddirty = LOCAL->dirty = T;
412.2006 +				/* need to rewrite msg 1 if not pseudo */
412.2007 +	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
412.2008 +	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
412.2009 +	}
412.2010 +      }
412.2011 +      stream->nmsgs = oldnmsgs;	/* whack it back down */
412.2012 +      stream->silent = silent;	/* restore old silent setting */
412.2013 +				/* notify upper level of new mailbox sizes */
412.2014 +      mail_exists (stream,nmsgs);
412.2015 +      mail_recent (stream,recent);
412.2016 +				/* mark dirty so O flags are set */
412.2017 +      if (recent) LOCAL->dirty = T;
412.2018 +    }
412.2019 +  }
412.2020 +				/* no change, don't babble if never got time */
412.2021 +  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
412.2022 +    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
412.2023 +				/* update parsed file size and time */
412.2024 +  LOCAL->filesize = sbuf.st_size;
412.2025 +  LOCAL->filetime = sbuf.st_mtime;
412.2026 +  return T;			/* return the winnage */
412.2027 +}
412.2028 +
412.2029 +/* MMDF read line from mailbox
412.2030 + * Accepts: mail stream
412.2031 + *	    stringstruct
412.2032 + *	    pointer to line size
412.2033 + * Returns: pointer to input line
412.2034 + */
412.2035 +
412.2036 +char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
412.2037 +{
412.2038 +  unsigned long i,j,k,m;
412.2039 +  char *s,*t,*te;
412.2040 +  char *ret = "";
412.2041 +				/* flush old buffer */
412.2042 +  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
412.2043 +				/* if buffer needs refreshing */
412.2044 +  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
412.2045 +  if (SIZE (bs)) {		/* find newline */
412.2046 +				/* end of fast scan */
412.2047 +    te = (t = (s = bs->curpos) + bs->cursize) - 12;
412.2048 +    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
412.2049 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
412.2050 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
412.2051 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
412.2052 +      --s;			/* back up */
412.2053 +      break;			/* exit loop */
412.2054 +    }
412.2055 +				/* final character-at-a-time scan */
412.2056 +    while ((s < t) && (*s != '\n')) ++s;
412.2057 +				/* difficult case if line spans buffer */
412.2058 +    if ((i = s - bs->curpos) == bs->cursize) {
412.2059 +				/* have space in line buffer? */
412.2060 +      if (i > LOCAL->linebuflen) {
412.2061 +	fs_give ((void **) &LOCAL->linebuf);
412.2062 +	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
412.2063 +      }
412.2064 +				/* remember what we have so far */
412.2065 +      memcpy (LOCAL->linebuf,bs->curpos,i);
412.2066 +				/* load next buffer */
412.2067 +      SETPOS (bs,k = GETPOS (bs) + i);
412.2068 +				/* end of fast scan */
412.2069 +      te = (t = (s = bs->curpos) + bs->cursize) - 12;
412.2070 +				/* fast scan in overlap buffer */
412.2071 +      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
412.2072 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
412.2073 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
412.2074 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
412.2075 +	--s;			/* back up */
412.2076 +	break;			/* exit loop */
412.2077 +      }
412.2078 +
412.2079 +				/* final character-at-a-time scan */
412.2080 +      while ((s < t) && (*s != '\n')) ++s;
412.2081 +				/* huge line? */
412.2082 +      if ((j = s - bs->curpos) == bs->cursize) {
412.2083 +	SETPOS (bs,GETPOS (bs) + j);
412.2084 +				/* look for end of line (s-l-o-w!!) */
412.2085 +	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
412.2086 +	SETPOS (bs,k);		/* go back to where it started */
412.2087 +      }
412.2088 +				/* got size of data, make buffer for return */
412.2089 +      ret = LOCAL->line = (char *) fs_get (i + j + 2);
412.2090 +				/* copy first chunk */
412.2091 +      memcpy (ret,LOCAL->linebuf,i);
412.2092 +      while (j) {		/* copy remainder */
412.2093 +	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
412.2094 +	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
412.2095 +	i += k;			/* account for this much read in */
412.2096 +	j -= k;
412.2097 +	bs->curpos += k;	/* increment new position */
412.2098 +	bs->cursize -= k;	/* eat that many bytes */
412.2099 +      }
412.2100 +				/* read newline at end */
412.2101 +      if (SIZE (bs)) ret[i++] = SNX (bs);
412.2102 +      ret[i] = '\0';		/* makes debugging easier */
412.2103 +    }
412.2104 +    else {			/* this is easy */
412.2105 +      ret = bs->curpos;		/* string it at this position */
412.2106 +      bs->curpos += ++i;	/* increment new position */
412.2107 +      bs->cursize -= i;		/* eat that many bytes */
412.2108 +    }
412.2109 +    *size = i;			/* return that to user */
412.2110 +  }
412.2111 +  else *size = 0;		/* end of data, return empty */
412.2112 +				/* embedded MMDF header at end of line? */
412.2113 +  if ((*size > sizeof (MMDFHDRTXT)) &&
412.2114 +      (s = ret + *size - (i = sizeof (MMDFHDRTXT) - 1)) && ISMMDF (s)) {
412.2115 +    SETPOS (bs,GETPOS (bs) - i);/* back up to start of MMDF header */
412.2116 +    *size -= i;			/* reduce length of line */
412.2117 +    ret[*size - 1] = '\n';	/* force newline at end */
412.2118 +  }
412.2119 +  return ret;
412.2120 +}
412.2121 +
412.2122 +/* MMDF make pseudo-header
412.2123 + * Accepts: MAIL stream
412.2124 + *	    buffer to write pseudo-header
412.2125 + * Returns: length of pseudo-header
412.2126 + */
412.2127 +
412.2128 +unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr)
412.2129 +{
412.2130 +  int i;
412.2131 +  char *s,tmp[MAILTMPLEN];
412.2132 +  time_t now = time (0);
412.2133 +  rfc822_fixed_date (tmp);
412.2134 +  sprintf (hdr,"%sFrom %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
412.2135 +	   mmdfhdr,pseudo_from,ctime (&now),
412.2136 +	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
412.2137 +	   (unsigned long) now,mylocalhost (),stream->uid_validity,
412.2138 +	   stream->uid_last);
412.2139 +  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
412.2140 +    if (stream->user_flags[i])
412.2141 +      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
412.2142 +  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
412.2143 +  return strlen (hdr);
412.2144 +}
412.2145 +
412.2146 +/* MMDF make status string
412.2147 + * Accepts: MAIL stream
412.2148 + *	    destination string to write
412.2149 + *	    message cache entry
412.2150 + *	    UID to write if non-zero (else use elt->private.uid)
412.2151 + *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
412.2152 + * Returns: length of string
412.2153 + */
412.2154 +
412.2155 +unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
412.2156 +			    unsigned long uid,long flag)
412.2157 +{
412.2158 +  char *t,stack[64];
412.2159 +  char *s = status;
412.2160 +  unsigned long n;
412.2161 +  int pad = 50;
412.2162 +  int sticky = uid ? T : !stream->uid_nosticky;
412.2163 +  /* This used to use sprintf(), but thanks to certain cretinous C libraries
412.2164 +     with horribly slow implementations of sprintf() I had to change it to this
412.2165 +     mess.  At least it should be fast. */
412.2166 +  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
412.2167 +    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
412.2168 +    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
412.2169 +    t = stack;
412.2170 +    n = stream->uid_validity;	/* push UID validity digits on the stack */
412.2171 +    do *t++ = (char) (n % 10) + '0';
412.2172 +    while (n /= 10);
412.2173 +				/* pop UID validity digits from stack */
412.2174 +    while (t > stack) *s++ = *--t;
412.2175 +   *s++ = ' ';
412.2176 +    n = stream->uid_last;	/* push UID last digits on the stack */
412.2177 +    do *t++ = (char) (n % 10) + '0';
412.2178 +    while (n /= 10);
412.2179 +				/* pop UID last digits from stack */
412.2180 +    while (t > stack) *s++ = *--t;
412.2181 +    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
412.2182 +      for (*s++ = ' '; *t; *s++ = *t++);
412.2183 +    *s++ = '\n';
412.2184 +    pad += 30;			/* increased padding if have IMAPbase */
412.2185 +  }
412.2186 +  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
412.2187 +  *s++ = ':'; *s++ = ' ';
412.2188 +  if (elt->seen) *s++ = 'R';
412.2189 +				/* only write O if have a UID */
412.2190 +  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
412.2191 +  *s++ = '\n';
412.2192 +  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
412.2193 +  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
412.2194 +  if (elt->deleted) *s++ = 'D';
412.2195 +  if (elt->flagged) *s++ = 'F';
412.2196 +  if (elt->answered) *s++ = 'A';
412.2197 +  if (elt->draft) *s++ = 'T';
412.2198 +    *s++ = '\n';
412.2199 +
412.2200 +  if (sticky) {			/* only do this if UIDs sticky */
412.2201 +    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
412.2202 +    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
412.2203 +    if (n = elt->user_flags) do {
412.2204 +      *s++ = ' ';
412.2205 +      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
412.2206 +    } while (n);
412.2207 +    n = s - status;		/* get size of stuff so far */
412.2208 +				/* pad X-Keywords to make size constant */
412.2209 +    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
412.2210 +    *s++ = '\n';
412.2211 +    if (flag) {			/* want to include UID? */
412.2212 +      t = stack;
412.2213 +				/* push UID digits on the stack */
412.2214 +      n = uid ? uid : elt->private.uid;
412.2215 +      do *t++ = (char) (n % 10) + '0';
412.2216 +      while (n /= 10);
412.2217 +      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
412.2218 +      *s++ = ' ';
412.2219 +				/* pop UID from stack */
412.2220 +      while (t > stack) *s++ = *--t;
412.2221 +      *s++ = '\n';
412.2222 +    }
412.2223 +  }
412.2224 +  *s++ = '\n'; *s = '\0';	/* end of extended message status */
412.2225 +  return s - status;		/* return size of resulting string */
412.2226 +}
412.2227 +
412.2228 +/* Rewrite mailbox file
412.2229 + * Accepts: MAIL stream, must be critical and locked
412.2230 + *	    return pointer to number of expunged messages if want expunge
412.2231 + *	    lock file name
412.2232 + *	    expunge sequence, not deleted flag
412.2233 + * Returns: T if success and mailbox unlocked, NIL if failure
412.2234 + */
412.2235 +
412.2236 +#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
412.2237 +
412.2238 +long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
412.2239 +		   long flags)
412.2240 +{
412.2241 +  MESSAGECACHE *elt;
412.2242 +  MMDFFILE f;
412.2243 +  char *s;
412.2244 +  time_t tp[2];
412.2245 +  long ret,flag;
412.2246 +  unsigned long i,j;
412.2247 +  unsigned long recent = stream->recent;
412.2248 +  unsigned long size = LOCAL->pseudo ? mmdf_pseudo (stream,LOCAL->buf) : 0;
412.2249 +  if (nexp) *nexp = 0;		/* initially nothing expunged */
412.2250 +				/* calculate size of mailbox after rewrite */
412.2251 +  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
412.2252 +    elt = mail_elt (stream,i);	/* get cache */
412.2253 +    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
412.2254 +				/* add RFC822 size of this message */
412.2255 +      size += elt->private.special.text.size + elt->private.spare.data +
412.2256 +	mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
412.2257 +	  elt->private.msg.text.text.size + MMDFHDRLEN;
412.2258 +      flag = 1;			/* only count X-IMAPbase once */
412.2259 +    }
412.2260 +  }
412.2261 +				/* no messages, has a life, and no pseudo */
412.2262 +  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
412.2263 +    LOCAL->pseudo = T;		/* so make a pseudo-message now */
412.2264 +    size = mmdf_pseudo (stream,LOCAL->buf);
412.2265 +  }
412.2266 +				/* extend the file as necessary */
412.2267 +  if (ret = mmdf_extend (stream,size)) {
412.2268 +    /* Set up buffered I/O file structure
412.2269 +     * curpos	current position being written through buffering
412.2270 +     * filepos	current position being written physically to the disk
412.2271 +     * bufpos	current position being written in the buffer
412.2272 +     * protect	current maximum position that can be written to the disk
412.2273 +     *		before buffering is forced
412.2274 +     * The code tries to buffer so that that disk is written in multiples of
412.2275 +     * OVERBLOWBUFLEN bytes.
412.2276 +     */
412.2277 +    f.stream = stream;		/* note mail stream */
412.2278 +    f.curpos = f.filepos = 0;	/* start of file */
412.2279 +    f.protect = stream->nmsgs ?	/* initial protection pointer */
412.2280 +    mail_elt (stream,1)->private.special.offset : 8192;
412.2281 +    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
412.2282 +
412.2283 +    if (LOCAL->pseudo)		/* update pseudo-header */
412.2284 +      mmdf_write (&f,LOCAL->buf,mmdf_pseudo (stream,LOCAL->buf));
412.2285 +				/* loop through all messages */
412.2286 +    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
412.2287 +      elt = mail_elt (stream,i);/* get cache */
412.2288 +				/* expunge this message? */
412.2289 +      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
412.2290 +				/* one less recent message */
412.2291 +	if (elt->recent) --recent;
412.2292 +	mail_expunged(stream,i);/* notify upper levels */
412.2293 +	++*nexp;		/* count up one more expunged message */
412.2294 +      }
412.2295 +      else {			/* preserve this message */
412.2296 +	i++;			/* advance to next message */
412.2297 +	if ((flag < 0) ||	/* need to rewrite message? */
412.2298 +	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
412.2299 +	    (elt->private.msg.header.text.size !=
412.2300 +	     (elt->private.spare.data +
412.2301 +	      mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
412.2302 +	  unsigned long newoffset = f.curpos;
412.2303 +				/* yes, seek to internal header */
412.2304 +	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
412.2305 +	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
412.2306 +				/* see if need to squeeze out a CR */
412.2307 +	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
412.2308 +	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
412.2309 +	    --size;		/* squeezed out a CR from PC */
412.2310 +	  }
412.2311 +				/* protection pointer moves to RFC822 header */
412.2312 +	  f.protect = elt->private.special.offset +
412.2313 +	    elt->private.msg.header.offset;
412.2314 +				/* write internal header */
412.2315 +	  mmdf_write (&f,LOCAL->buf,elt->private.special.text.size);
412.2316 +				/* get RFC822 header */
412.2317 +	  s = mmdf_header (stream,elt->msgno,&j,FT_INTERNAL);
412.2318 +				/* in case this got decremented */
412.2319 +	  elt->private.msg.header.offset = elt->private.special.text.size;
412.2320 +				/* header size, sans trailing newline */
412.2321 +	  if ((j < 2) || (s[j - 2] == '\n')) j--;
412.2322 +				/* this can happen if CRs were squeezed */
412.2323 +	  if (j < elt->private.spare.data) {
412.2324 +				/* so fix up counts */
412.2325 +	    size -= elt->private.spare.data - j;
412.2326 +	    elt->private.spare.data = j;
412.2327 +	  }
412.2328 +	  else if (j != elt->private.spare.data)
412.2329 +	    fatal ("header size inconsistent");
412.2330 +				/* protection pointer moves to RFC822 text */
412.2331 +	  f.protect = elt->private.special.offset +
412.2332 +	    elt->private.msg.text.offset;
412.2333 +	  mmdf_write (&f,s,j);	/* write RFC822 header */
412.2334 +				/* write status and UID */
412.2335 +	  mmdf_write (&f,LOCAL->buf,
412.2336 +		      j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag));
412.2337 +	  flag = 1;		/* only write X-IMAPbase once */
412.2338 +				/* new file header size */
412.2339 +	  elt->private.msg.header.text.size = elt->private.spare.data + j;
412.2340 +
412.2341 +				/* did text move? */
412.2342 +	  if (f.curpos != f.protect) {
412.2343 +				/* get message text */
412.2344 +	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
412.2345 +				/* this can happen if CRs were squeezed */
412.2346 +	    if (j < elt->private.msg.text.text.size) {
412.2347 +				/* so fix up counts */
412.2348 +	      size -= elt->private.msg.text.text.size - j;
412.2349 +	      elt->private.msg.text.text.size = j;
412.2350 +	    }
412.2351 +				/* can't happen it says here */
412.2352 +	    else if (j > elt->private.msg.text.text.size)
412.2353 +	      fatal ("text size inconsistent");
412.2354 +				/* new text offset, status/UID may change it */
412.2355 +	    elt->private.msg.text.offset = f.curpos - newoffset;
412.2356 +				/* protection pointer moves to next message */
412.2357 +	    f.protect = (i <= stream->nmsgs) ?
412.2358 +	      mail_elt (stream,i)->private.special.offset :
412.2359 +		(f.curpos + j + MMDFHDRLEN);
412.2360 +	    mmdf_write (&f,s,j);/* write text */
412.2361 +				/* write trailing newline */
412.2362 +	    mmdf_write (&f,mmdfhdr,MMDFHDRLEN);
412.2363 +	  }
412.2364 +	  else {		/* tie off header and status */
412.2365 +	    mmdf_write (&f,NIL,NIL);
412.2366 +	    f.curpos = f.protect =/* restart everything at end of message */
412.2367 +	      f.filepos += elt->private.msg.text.text.size + MMDFHDRLEN;
412.2368 +	  }
412.2369 +				/* new internal header offset */
412.2370 +	  elt->private.special.offset = newoffset;
412.2371 +	  elt->private.dirty =NIL;/* message is now clean */
412.2372 +	}
412.2373 +	else {			/* no need to rewrite this message */
412.2374 +				/* tie off previous message if needed */
412.2375 +	  mmdf_write (&f,NIL,NIL);
412.2376 +	  f.curpos = f.protect =/* restart everything at end of message */
412.2377 +	    f.filepos += elt->private.special.text.size +
412.2378 +	      elt->private.msg.header.text.size +
412.2379 +		elt->private.msg.text.text.size + MMDFHDRLEN;
412.2380 +	}
412.2381 +      }
412.2382 +    }
412.2383 +
412.2384 +    mmdf_write (&f,NIL,NIL);	/* tie off final message */
412.2385 +    if (size != f.filepos) fatal ("file size inconsistent");
412.2386 +    fs_give ((void **) &f.buf);	/* free buffer */
412.2387 +				/* make sure tied off */
412.2388 +    ftruncate (LOCAL->fd,LOCAL->filesize = size);
412.2389 +    fsync (LOCAL->fd);		/* make sure the updates take */
412.2390 +    if (size && (flag < 0)) fatal ("lost UID base information");
412.2391 +				/* no longer dirty */
412.2392 +    LOCAL->ddirty = LOCAL->dirty = NIL;
412.2393 +  				/* notify upper level of new mailbox sizes */
412.2394 +    mail_exists (stream,stream->nmsgs);
412.2395 +    mail_recent (stream,recent);
412.2396 +				/* set atime to now, mtime a second earlier */
412.2397 +    tp[1] = (tp[0] = time (0)) - 1;
412.2398 +				/* set the times, note change */
412.2399 +    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
412.2400 +    close (LOCAL->fd);		/* close and reopen file */
412.2401 +    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
412.2402 +			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
412.2403 +	< 0) {
412.2404 +      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
412.2405 +      MM_LOG (LOCAL->buf,ERROR);
412.2406 +      mmdf_abort (stream);
412.2407 +    }
412.2408 +    dotlock_unlock (lock);	/* flush the lock file */
412.2409 +  }
412.2410 +  return ret;			/* return state from algorithm */
412.2411 +}
412.2412 +
412.2413 +/* Extend MMDF mailbox file
412.2414 + * Accepts: MAIL stream
412.2415 + *	    new desired size
412.2416 + * Return: T if success, else NIL
412.2417 + */
412.2418 +
412.2419 +long mmdf_extend (MAILSTREAM *stream,unsigned long size)
412.2420 +{
412.2421 +  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
412.2422 +  if (i) {			/* does the mailbox need to grow? */
412.2423 +    if (i > LOCAL->buflen) {	/* make sure have enough space */
412.2424 +				/* this user won the lottery all right */
412.2425 +      fs_give ((void **) &LOCAL->buf);
412.2426 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
412.2427 +    }
412.2428 +    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
412.2429 +    while (T) {			/* until write successful or punt */
412.2430 +      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
412.2431 +      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
412.2432 +      else {
412.2433 +	long e = errno;		/* note error before doing ftruncate */
412.2434 +	ftruncate (LOCAL->fd,LOCAL->filesize);
412.2435 +	if (MM_DISKERROR (stream,e,NIL)) {
412.2436 +	  fsync (LOCAL->fd);	/* user chose to punt */
412.2437 +	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
412.2438 +	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
412.2439 +	  return NIL;
412.2440 +	}
412.2441 +      }
412.2442 +    }
412.2443 +  }
412.2444 +  return LONGT;
412.2445 +}
412.2446 +
412.2447 +/* Write data to buffered file
412.2448 + * Accepts: buffered file pointer
412.2449 + *	    file data or NIL to indicate "flush buffer"
412.2450 + *	    date size (ignored for "flush buffer")
412.2451 + * Does not return until success
412.2452 + */
412.2453 +
412.2454 +void mmdf_write (MMDFFILE *f,char *buf,unsigned long size)
412.2455 +{
412.2456 +  unsigned long i,j,k;
412.2457 +  if (buf) {			/* doing buffered write? */
412.2458 +    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
412.2459 +				/* yes, have space in current buffer chunk? */
412.2460 +    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
412.2461 +				/* yes, fill up buffer as much as we can */
412.2462 +      memcpy (f->bufpos,buf,k = min (j,size));
412.2463 +      f->bufpos += k;		/* new buffer position */
412.2464 +      f->curpos += k;		/* new current position */
412.2465 +      if (j -= k) return;	/* all done if still have buffer free space */
412.2466 +      buf += k;			/* full, get new unwritten data pointer */
412.2467 +      size -= k;		/* new data size */
412.2468 +      i += k;			/* new buffer data size */
412.2469 +    }
412.2470 +    /* This chunk of the buffer is full.  See if can make some space by
412.2471 +     * writing to the disk, if there's enough unprotected space to do so.
412.2472 +     * Try to fill out any unaligned chunk, along with any subsequent full
412.2473 +     * chunks that will fit in unprotected space.
412.2474 +     */
412.2475 +				/* any unprotected space we can write to? */
412.2476 +    if (j = min (i,f->protect - f->filepos)) {
412.2477 +				/* yes, filepos not at chunk boundary? */
412.2478 +      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
412.2479 +	j -= k;			/* yes, and can write out partial chunk */
412.2480 +      else k = 0;		/* no partial chunk to write */
412.2481 +				/* if at least a chunk free, write that too */
412.2482 +      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
412.2483 +      if (k) {			/* write data if there is anything we can */
412.2484 +	mmdf_phys_write (f,f->buf,k);
412.2485 +				/* slide buffer */
412.2486 +	if (i -= k) memmove (f->buf,f->buf + k,i);
412.2487 +	f->bufpos = f->buf + i;	/* new end of buffer */
412.2488 +      }
412.2489 +    }
412.2490 +
412.2491 +    /* Have flushed the buffer as best as possible.  All done if no more
412.2492 +     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
412.2493 +     * data is larger than a chunk AND the unprotected space is also larger
412.2494 +     * than a chunk, then write as many chunks as we can directly from the
412.2495 +     * data.  Buffer the rest, expanding the buffer as needed.
412.2496 +     */
412.2497 +    if (size) {			/* have more data that we need to buffer? */
412.2498 +				/* can write any of it to disk instead? */
412.2499 +      if ((f->bufpos == f->buf) && 
412.2500 +	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
412.2501 +				/* write as much as we can right now */
412.2502 +	mmdf_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
412.2503 +	buf += j;		/* new data pointer */
412.2504 +	size -= j;		/* new data size */
412.2505 +	f->curpos += j;		/* advance current pointer */
412.2506 +      }
412.2507 +      if (size) {		/* still have data that we need to buffer? */
412.2508 +				/* yes, need to expand the buffer? */
412.2509 +	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
412.2510 +				/* note current position in buffer */
412.2511 +	  j = f->bufpos - f->buf;
412.2512 +	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
412.2513 +	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
412.2514 +				/* in case buffer relocated */
412.2515 +	  f->bufpos = f->buf + j;
412.2516 +	}
412.2517 +				/* buffer remaining data */
412.2518 +	memcpy (f->bufpos,buf,size);
412.2519 +	f->bufpos += size;	/* new end of buffer */
412.2520 +	f->curpos += size;	/* advance current pointer */
412.2521 +      }
412.2522 +    }
412.2523 +  }
412.2524 +  else {			/* flush buffer to disk */
412.2525 +    mmdf_phys_write (f,f->buf,i = f->bufpos - f->buf);
412.2526 +    f->bufpos = f->buf;		/* reset buffer */
412.2527 +				/* update positions */
412.2528 +    f->curpos = f->protect = f->filepos;
412.2529 +  }
412.2530 +}
412.2531 +
412.2532 +/* Physical disk write
412.2533 + * Accepts: buffered file pointer
412.2534 + *	    buffer address
412.2535 + *	    buffer size
412.2536 + * Does not return until success
412.2537 + */
412.2538 +
412.2539 +void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size)
412.2540 +{
412.2541 +  MAILSTREAM *stream = f->stream;
412.2542 +				/* write data at desired position */
412.2543 +  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
412.2544 +		  (write (LOCAL->fd,buf,size) < 0))) {
412.2545 +    int e;
412.2546 +    char tmp[MAILTMPLEN];
412.2547 +    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
412.2548 +    MM_LOG (tmp,ERROR);
412.2549 +    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
412.2550 +  }
412.2551 +  f->filepos += size;		/* update file position */
412.2552 +}
   413.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   413.2 +++ b/src/osdep/unix/mtx.c	Mon Sep 14 15:17:45 2009 +0900
   413.3 @@ -0,0 +1,1371 @@
   413.4 +/* ========================================================================
   413.5 + * Copyright 1988-2007 University of Washington
   413.6 + *
   413.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   413.8 + * you may not use this file except in compliance with the License.
   413.9 + * You may obtain a copy of the License at
  413.10 + *
  413.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  413.12 + *
  413.13 + * 
  413.14 + * ========================================================================
  413.15 + */
  413.16 +
  413.17 +/*
  413.18 + * Program:	MTX mail routines
  413.19 + *
  413.20 + * Author:	Mark Crispin
  413.21 + *		Networks and Distributed Computing
  413.22 + *		Computing & Communications
  413.23 + *		University of Washington
  413.24 + *		Administration Building, AG-44
  413.25 + *		Seattle, WA  98195
  413.26 + *		Internet: MRC@CAC.Washington.EDU
  413.27 + *
  413.28 + * Date:	22 May 1990
  413.29 + * Last Edited:	11 October 2007
  413.30 + */
  413.31 +
  413.32 +
  413.33 +/*				FILE TIME SEMANTICS
  413.34 + *
  413.35 + * The atime is the last read time of the file.
  413.36 + * The mtime is the last flags update time of the file.
  413.37 + * The ctime is the last write time of the file.
  413.38 + */
  413.39 +
  413.40 +#include <stdio.h>
  413.41 +#include <ctype.h>
  413.42 +#include <errno.h>
  413.43 +extern int errno;		/* just in case */
  413.44 +#include "mail.h"
  413.45 +#include "osdep.h"
  413.46 +#include <pwd.h>
  413.47 +#include <sys/stat.h>
  413.48 +#include <sys/time.h>
  413.49 +#include "misc.h"
  413.50 +#include "dummy.h"
  413.51 +#include "fdstring.h"
  413.52 +
  413.53 +/* MTX I/O stream local data */
  413.54 +	
  413.55 +typedef struct mtx_local {
  413.56 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  413.57 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  413.58 +  int fd;			/* file descriptor for I/O */
  413.59 +  off_t filesize;		/* file size parsed */
  413.60 +  time_t filetime;		/* last file time */
  413.61 +  time_t lastsnarf;		/* last snarf time */
  413.62 +  unsigned char *buf;		/* temporary buffer */
  413.63 +  unsigned long buflen;		/* current size of temporary buffer */
  413.64 +} MTXLOCAL;
  413.65 +
  413.66 +
  413.67 +/* Convenient access to local data */
  413.68 +
  413.69 +#define LOCAL ((MTXLOCAL *) stream->local)
  413.70 +
  413.71 +
  413.72 +/* Function prototypes */
  413.73 +
  413.74 +DRIVER *mtx_valid (char *name);
  413.75 +int mtx_isvalid (char *name,char *tmp);
  413.76 +void *mtx_parameters (long function,void *value);
  413.77 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  413.78 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
  413.79 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  413.80 +long mtx_create (MAILSTREAM *stream,char *mailbox);
  413.81 +long mtx_delete (MAILSTREAM *stream,char *mailbox);
  413.82 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
  413.83 +long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
  413.84 +MAILSTREAM *mtx_open (MAILSTREAM *stream);
  413.85 +void mtx_close (MAILSTREAM *stream,long options);
  413.86 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
  413.87 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
  413.88 +		  unsigned long *length,long flags);
  413.89 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  413.90 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  413.91 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  413.92 +long mtx_ping (MAILSTREAM *stream);
  413.93 +void mtx_check (MAILSTREAM *stream);
  413.94 +void mtx_snarf (MAILSTREAM *stream);
  413.95 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
  413.96 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  413.97 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  413.98 +
  413.99 +char *mtx_file (char *dst,char *name);
 413.100 +long mtx_parse (MAILSTREAM *stream);
 413.101 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
 413.102 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 413.103 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
 413.104 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 413.105 +			  unsigned long *size);
 413.106 +
 413.107 +/* MTX mail routines */
 413.108 +
 413.109 +
 413.110 +/* Driver dispatch used by MAIL */
 413.111 +
 413.112 +DRIVER mtxdriver = {
 413.113 +  "mtx",			/* driver name */
 413.114 +				/* driver flags */
 413.115 +  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY|DR_LOCKING,
 413.116 +  (DRIVER *) NIL,		/* next driver */
 413.117 +  mtx_valid,			/* mailbox is valid for us */
 413.118 +  mtx_parameters,		/* manipulate parameters */
 413.119 +  mtx_scan,			/* scan mailboxes */
 413.120 +  mtx_list,			/* list mailboxes */
 413.121 +  mtx_lsub,			/* list subscribed mailboxes */
 413.122 +  NIL,				/* subscribe to mailbox */
 413.123 +  NIL,				/* unsubscribe from mailbox */
 413.124 +  dummy_create,			/* create mailbox */
 413.125 +  mtx_delete,			/* delete mailbox */
 413.126 +  mtx_rename,			/* rename mailbox */
 413.127 +  mtx_status,			/* status of mailbox */
 413.128 +  mtx_open,			/* open mailbox */
 413.129 +  mtx_close,			/* close mailbox */
 413.130 +  mtx_flags,			/* fetch message "fast" attributes */
 413.131 +  mtx_flags,			/* fetch message flags */
 413.132 +  NIL,				/* fetch overview */
 413.133 +  NIL,				/* fetch message envelopes */
 413.134 +  mtx_header,			/* fetch message header */
 413.135 +  mtx_text,			/* fetch message body */
 413.136 +  NIL,				/* fetch partial message text */
 413.137 +  NIL,				/* unique identifier */
 413.138 +  NIL,				/* message number */
 413.139 +  mtx_flag,			/* modify flags */
 413.140 +  mtx_flagmsg,			/* per-message modify flags */
 413.141 +  NIL,				/* search for message based on criteria */
 413.142 +  NIL,				/* sort messages */
 413.143 +  NIL,				/* thread messages */
 413.144 +  mtx_ping,			/* ping mailbox to see if still alive */
 413.145 +  mtx_check,			/* check for new messages */
 413.146 +  mtx_expunge,			/* expunge deleted messages */
 413.147 +  mtx_copy,			/* copy messages to another mailbox */
 413.148 +  mtx_append,			/* append string message to mailbox */
 413.149 +  NIL				/* garbage collect stream */
 413.150 +};
 413.151 +
 413.152 +				/* prototype stream */
 413.153 +MAILSTREAM mtxproto = {&mtxdriver};
 413.154 +
 413.155 +/* MTX mail validate mailbox
 413.156 + * Accepts: mailbox name
 413.157 + * Returns: our driver if name is valid, NIL otherwise
 413.158 + */
 413.159 +
 413.160 +DRIVER *mtx_valid (char *name)
 413.161 +{
 413.162 +  char tmp[MAILTMPLEN];
 413.163 +  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
 413.164 +}
 413.165 +
 413.166 +
 413.167 +/* MTX mail test for valid mailbox
 413.168 + * Accepts: mailbox name
 413.169 + * Returns: T if valid, NIL otherwise
 413.170 + */
 413.171 +
 413.172 +int mtx_isvalid (char *name,char *tmp)
 413.173 +{
 413.174 +  int fd;
 413.175 +  int ret = NIL;
 413.176 +  char *s,file[MAILTMPLEN];
 413.177 +  struct stat sbuf;
 413.178 +  time_t tp[2];
 413.179 +  errno = EINVAL;		/* assume invalid argument */
 413.180 +				/* if file, get its status */
 413.181 +  if ((s = mtx_file (file,name)) && !stat (s,&sbuf)) {
 413.182 +    if (!sbuf.st_size) {	/* allow empty file if INBOX */
 413.183 +      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
 413.184 +      else errno = 0;		/* empty file */
 413.185 +    }
 413.186 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 413.187 +      memset (tmp,'\0',MAILTMPLEN);
 413.188 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
 413.189 +	  (s[1] == '\012')) {	/* valid format? */
 413.190 +	*s = '\0';		/* tie off header */
 413.191 +				/* must begin with dd-mmm-yy" */
 413.192 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 413.193 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 413.194 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 413.195 +      }
 413.196 +      else errno = -1;		/* bogus format */
 413.197 +      close (fd);		/* close the file */
 413.198 +				/* \Marked status? */
 413.199 +      if (sbuf.st_ctime > sbuf.st_atime) {
 413.200 +	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 413.201 +	tp[1] = sbuf.st_mtime;
 413.202 +	utime (file,tp);	/* set the times */
 413.203 +      }
 413.204 +    }
 413.205 +  }
 413.206 +				/* in case INBOX but not mtx format */
 413.207 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 413.208 +  return ret;			/* return what we should */
 413.209 +}
 413.210 +
 413.211 +/* MTX manipulate driver parameters
 413.212 + * Accepts: function code
 413.213 + *	    function-dependent value
 413.214 + * Returns: function-dependent return value
 413.215 + */
 413.216 +
 413.217 +void *mtx_parameters (long function,void *value)
 413.218 +{
 413.219 +  void *ret = NIL;
 413.220 +  switch ((int) function) {
 413.221 +  case GET_INBOXPATH:
 413.222 +    if (value) ret = mtx_file ((char *) value,"INBOX");
 413.223 +    break;
 413.224 +  }
 413.225 +  return ret;
 413.226 +}
 413.227 +
 413.228 +
 413.229 +/* MTX mail scan mailboxes
 413.230 + * Accepts: mail stream
 413.231 + *	    reference
 413.232 + *	    pattern to search
 413.233 + *	    string to scan
 413.234 + */
 413.235 +
 413.236 +void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 413.237 +{
 413.238 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 413.239 +}
 413.240 +
 413.241 +
 413.242 +/* MTX mail list mailboxes
 413.243 + * Accepts: mail stream
 413.244 + *	    reference
 413.245 + *	    pattern to search
 413.246 + */
 413.247 +
 413.248 +void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
 413.249 +{
 413.250 +  if (stream) dummy_list (NIL,ref,pat);
 413.251 +}
 413.252 +
 413.253 +
 413.254 +/* MTX mail list subscribed mailboxes
 413.255 + * Accepts: mail stream
 413.256 + *	    reference
 413.257 + *	    pattern to search
 413.258 + */
 413.259 +
 413.260 +void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 413.261 +{
 413.262 +  if (stream) dummy_lsub (NIL,ref,pat);
 413.263 +}
 413.264 +
 413.265 +/* MTX mail delete mailbox
 413.266 + * Accepts: MAIL stream
 413.267 + *	    mailbox name to delete
 413.268 + * Returns: T on success, NIL on failure
 413.269 + */
 413.270 +
 413.271 +long mtx_delete (MAILSTREAM *stream,char *mailbox)
 413.272 +{
 413.273 +  return mtx_rename (stream,mailbox,NIL);
 413.274 +}
 413.275 +
 413.276 +
 413.277 +/* MTX mail rename mailbox
 413.278 + * Accepts: MAIL stream
 413.279 + *	    old mailbox name
 413.280 + *	    new mailbox name (or NIL for delete)
 413.281 + * Returns: T on success, NIL on failure
 413.282 + */
 413.283 +
 413.284 +long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
 413.285 +{
 413.286 +  long ret = T;
 413.287 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 413.288 +  int fd,ld;
 413.289 +  struct stat sbuf;
 413.290 +  if (!mtx_file (file,old) ||
 413.291 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 413.292 +		   ((s = strrchr (tmp,'/')) && !s[1])))) {
 413.293 +    sprintf (tmp,newname ?
 413.294 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 413.295 +	     "Can't delete mailbox %.80s: invalid name",
 413.296 +	     old,newname);
 413.297 +    MM_LOG (tmp,ERROR);
 413.298 +    return NIL;
 413.299 +  }
 413.300 +  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
 413.301 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 413.302 +    MM_LOG (tmp,ERROR);
 413.303 +    return NIL;
 413.304 +  }
 413.305 +				/* get exclusive parse/append permission */
 413.306 +  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
 413.307 +    MM_LOG ("Unable to lock rename mailbox",ERROR);
 413.308 +    return NIL;
 413.309 +  }
 413.310 +				/* lock out other users */
 413.311 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 413.312 +    close (fd);			/* couldn't lock, give up on it then */
 413.313 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 413.314 +    MM_LOG (tmp,ERROR);
 413.315 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 413.316 +    return NIL;
 413.317 +  }
 413.318 +
 413.319 +  if (newname) {		/* want rename? */
 413.320 +    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
 413.321 +      c = *++s;			/* remember first character of inferior */
 413.322 +      *s = '\0';		/* tie off to get just superior */
 413.323 +				/* name doesn't exist, create it */
 413.324 +      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 413.325 +	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
 413.326 +	ret = NIL;
 413.327 +      else *s = c;		/* restore full name */
 413.328 +    }
 413.329 +				/* rename the file */
 413.330 +    if (ret && rename (file,tmp)) {
 413.331 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 413.332 +	       strerror (errno));
 413.333 +      MM_LOG (tmp,ERROR);
 413.334 +      ret = NIL;		/* set failure */
 413.335 +    }
 413.336 +  }
 413.337 +  else if (unlink (file)) {
 413.338 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 413.339 +    MM_LOG (tmp,ERROR);
 413.340 +    ret = NIL;			/* set failure */
 413.341 +  }
 413.342 +  flock (fd,LOCK_UN);		/* release lock on the file */
 413.343 +  close (fd);			/* close the file */
 413.344 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 413.345 +				/* recreate file if renamed INBOX */
 413.346 +  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"INBOX.MTX");
 413.347 +  return ret;			/* return success */
 413.348 +}
 413.349 +
 413.350 +/* Mtx Mail status
 413.351 + * Accepts: mail stream
 413.352 + *	    mailbox name
 413.353 + *	    status flags
 413.354 + * Returns: T on success, NIL on failure
 413.355 + */
 413.356 +
 413.357 +long mtx_status (MAILSTREAM *stream,char *mbx,long flags)
 413.358 +{
 413.359 +  MAILSTATUS status;
 413.360 +  unsigned long i;
 413.361 +  MAILSTREAM *tstream = NIL;
 413.362 +  MAILSTREAM *systream = NIL;
 413.363 +				/* make temporary stream (unless this mbx) */
 413.364 +  if (!stream && !(stream = tstream =
 413.365 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
 413.366 +  status.flags = flags;		/* return status values */
 413.367 +  status.messages = stream->nmsgs;
 413.368 +  status.recent = stream->recent;
 413.369 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 413.370 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 413.371 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 413.372 +  status.uidnext = stream->uid_last + 1;
 413.373 +  status.uidvalidity = stream->uid_validity;
 413.374 +				/* calculate post-snarf results */
 413.375 +  if (!status.recent && stream->inbox &&
 413.376 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
 413.377 +    status.messages += systream->nmsgs;
 413.378 +    status.recent += systream->recent;
 413.379 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 413.380 +      for (i = 1; i <= systream->nmsgs; i++)
 413.381 +	if (!mail_elt (systream,i)->seen) status.unseen++;
 413.382 +				/* kludge but probably good enough */
 413.383 +    status.uidnext += systream->nmsgs;
 413.384 +  }
 413.385 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 413.386 +  if (tstream) mail_close (tstream);
 413.387 +  if (systream) mail_close (systream);
 413.388 +  return T;			/* success */
 413.389 +}
 413.390 +
 413.391 +/* MTX mail open
 413.392 + * Accepts: stream to open
 413.393 + * Returns: stream on success, NIL on failure
 413.394 + */
 413.395 +
 413.396 +MAILSTREAM *mtx_open (MAILSTREAM *stream)
 413.397 +{
 413.398 +  int fd,ld;
 413.399 +  char tmp[MAILTMPLEN];
 413.400 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 413.401 +				/* return prototype for OP_PROTOTYPE call */
 413.402 +  if (!stream) return user_flags (&mtxproto);
 413.403 +  if (stream->local) fatal ("mtx recycle stream");
 413.404 +  user_flags (stream);		/* set up user flags */
 413.405 +				/* canonicalize the mailbox name */
 413.406 +  if (!mtx_file (tmp,stream->mailbox)) {
 413.407 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 413.408 +    MM_LOG (tmp,ERROR);
 413.409 +  }
 413.410 +  if (stream->rdonly ||
 413.411 +      (fd = open (tmp,O_RDWR,NIL)) < 0) {
 413.412 +    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 413.413 +      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
 413.414 +      MM_LOG (tmp,ERROR);
 413.415 +      return NIL;
 413.416 +    }
 413.417 +    else if (!stream->rdonly) {	/* got it, but readonly */
 413.418 +      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 413.419 +      stream->rdonly = T;
 413.420 +    }
 413.421 +  }
 413.422 +  stream->local = fs_get (sizeof (MTXLOCAL));
 413.423 +  LOCAL->fd = fd;		/* bind the file */
 413.424 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 413.425 +  LOCAL->buflen = CHUNKSIZE - 1;
 413.426 +				/* note if an INBOX or not */
 413.427 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 413.428 +  fs_give ((void **) &stream->mailbox);
 413.429 +  stream->mailbox = cpystr (tmp);
 413.430 +				/* get shared parse permission */
 413.431 +  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
 413.432 +    MM_LOG ("Unable to lock open mailbox",ERROR);
 413.433 +    return NIL;
 413.434 +  }
 413.435 +  (*bn) (BLOCK_FILELOCK,NIL);
 413.436 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 413.437 +  (*bn) (BLOCK_NONE,NIL);
 413.438 +  unlockfd (ld,tmp);		/* release shared parse permission */
 413.439 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 413.440 +				/* time not set up yet */
 413.441 +  LOCAL->lastsnarf = LOCAL->filetime = 0;
 413.442 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 413.443 +  stream->sequence++;		/* bump sequence number */
 413.444 +				/* parse mailbox */
 413.445 +  stream->nmsgs = stream->recent = 0;
 413.446 +  if (mtx_ping (stream) && !stream->nmsgs)
 413.447 +    MM_LOG ("Mailbox is empty",(long) NIL);
 413.448 +  if (!LOCAL) return NIL;	/* failure if stream died */
 413.449 +  stream->perm_seen = stream->perm_deleted =
 413.450 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 413.451 +      stream->rdonly ? NIL : T;
 413.452 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 413.453 +  return stream;		/* return stream to caller */
 413.454 +}
 413.455 +
 413.456 +/* MTX mail close
 413.457 + * Accepts: MAIL stream
 413.458 + *	    close options
 413.459 + */
 413.460 +
 413.461 +void mtx_close (MAILSTREAM *stream,long options)
 413.462 +{
 413.463 +  if (stream && LOCAL) {	/* only if a file is open */
 413.464 +    int silent = stream->silent;
 413.465 +    stream->silent = T;		/* note this stream is dying */
 413.466 +    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
 413.467 +    stream->silent = silent;	/* restore previous status */
 413.468 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 413.469 +    close (LOCAL->fd);		/* close the local file */
 413.470 +				/* free local text buffer */
 413.471 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 413.472 +				/* nuke the local data */
 413.473 +    fs_give ((void **) &stream->local);
 413.474 +    stream->dtb = NIL;		/* log out the DTB */
 413.475 +  }
 413.476 +}
 413.477 +
 413.478 +
 413.479 +/* MTX mail fetch flags
 413.480 + * Accepts: MAIL stream
 413.481 + *	    sequence
 413.482 + *	    option flags
 413.483 + * Sniffs at file to see if some other process changed the flags
 413.484 + */
 413.485 +
 413.486 +void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
 413.487 +{
 413.488 +  unsigned long i;
 413.489 +  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
 413.490 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 413.491 +       mail_sequence (stream,sequence)))
 413.492 +    for (i = 1; i <= stream->nmsgs; i++) 
 413.493 +      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
 413.494 +}
 413.495 +
 413.496 +/* MTX mail fetch message header
 413.497 + * Accepts: MAIL stream
 413.498 + *	    message # to fetch
 413.499 + *	    pointer to returned header text length
 413.500 + *	    option flags
 413.501 + * Returns: message header in RFC822 format
 413.502 + */
 413.503 +
 413.504 +char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 413.505 +		  long flags)
 413.506 +{
 413.507 +  *length = 0;			/* default to empty */
 413.508 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 413.509 +				/* get to header position */
 413.510 +  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
 413.511 +				/* is buffer big enough? */
 413.512 +  if (*length > LOCAL->buflen) {
 413.513 +    fs_give ((void **) &LOCAL->buf);
 413.514 +    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
 413.515 +  }
 413.516 +  LOCAL->buf[*length] = '\0';	/* tie off string */
 413.517 +				/* slurp the data */
 413.518 +  read (LOCAL->fd,LOCAL->buf,*length);
 413.519 +  return (char *) LOCAL->buf;
 413.520 +}
 413.521 +
 413.522 +/* MTX mail fetch message text (body only)
 413.523 + * Accepts: MAIL stream
 413.524 + *	    message # to fetch
 413.525 + *	    pointer to returned header text length
 413.526 + *	    option flags
 413.527 + * Returns: T, always
 413.528 + */
 413.529 +
 413.530 +long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 413.531 +{
 413.532 +  FDDATA d;
 413.533 +  unsigned long i,j;
 413.534 +  MESSAGECACHE *elt;
 413.535 +				/* UID call "impossible" */
 413.536 +  if (flags & FT_UID) return NIL;
 413.537 +  elt = mtx_elt (stream,msgno);	/* get message status */
 413.538 +				/* if message not seen */
 413.539 +  if (!(flags & FT_PEEK) && !elt->seen) {
 413.540 +    elt->seen = T;		/* mark message as seen */
 413.541 +				/* recalculate status */
 413.542 +    mtx_update_status (stream,msgno,NIL);
 413.543 +    MM_FLAGS (stream,msgno);
 413.544 +  }
 413.545 +				/* find header position */
 413.546 +  i = mtx_hdrpos (stream,msgno,&j);
 413.547 +  d.fd = LOCAL->fd;		/* set up file descriptor */
 413.548 +  d.pos = i + j;
 413.549 +  d.chunk = LOCAL->buf;		/* initial buffer chunk */
 413.550 +  d.chunksize = CHUNKSIZE;
 413.551 +  INIT (bs,fd_string,&d,elt->rfc822_size - j);
 413.552 +  return T;			/* success */
 413.553 +}
 413.554 +
 413.555 +/* MTX mail modify flags
 413.556 + * Accepts: MAIL stream
 413.557 + *	    sequence
 413.558 + *	    flag(s)
 413.559 + *	    option flags
 413.560 + */
 413.561 +
 413.562 +void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 413.563 +{
 413.564 +  time_t tp[2];
 413.565 +  struct stat sbuf;
 413.566 +  if (!stream->rdonly) {	/* make sure the update takes */
 413.567 +    fsync (LOCAL->fd);
 413.568 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 413.569 +    tp[1] = LOCAL->filetime = sbuf.st_mtime;
 413.570 +    tp[0] = time (0);		/* make sure read comes after all that */
 413.571 +    utime (stream->mailbox,tp);
 413.572 +  }
 413.573 +}
 413.574 +
 413.575 +
 413.576 +/* MTX mail per-message modify flags
 413.577 + * Accepts: MAIL stream
 413.578 + *	    message cache element
 413.579 + */
 413.580 +
 413.581 +void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 413.582 +{
 413.583 +  struct stat sbuf;
 413.584 +				/* maybe need to do a checkpoint? */
 413.585 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 413.586 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 413.587 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 413.588 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 413.589 +  }
 413.590 +				/* recalculate status */
 413.591 +  mtx_update_status (stream,elt->msgno,NIL);
 413.592 +}
 413.593 +
 413.594 +/* MTX mail ping mailbox
 413.595 + * Accepts: MAIL stream
 413.596 + * Returns: T if stream still alive, NIL if not
 413.597 + */
 413.598 +
 413.599 +long mtx_ping (MAILSTREAM *stream)
 413.600 +{
 413.601 +  unsigned long i = 1;
 413.602 +  long r = T;
 413.603 +  int ld;
 413.604 +  char lock[MAILTMPLEN];
 413.605 +  struct stat sbuf;
 413.606 +  if (stream && LOCAL) {	/* only if stream already open */
 413.607 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 413.608 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 413.609 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 413.610 +				/* check for changed message status */
 413.611 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 413.612 +      LOCAL->filetime = sbuf.st_mtime;
 413.613 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 413.614 +	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
 413.615 +      while (i <= stream->nmsgs) mtx_elt (stream,i++);
 413.616 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 413.617 +    }
 413.618 +				/* get shared parse/append permission */
 413.619 +    if ((sbuf.st_size != LOCAL->filesize) &&
 413.620 +	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 413.621 +				/* parse resulting mailbox */
 413.622 +      r = (mtx_parse (stream)) ? T : NIL;
 413.623 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 413.624 +    }
 413.625 +    if (LOCAL) {		/* stream must still be alive */
 413.626 +				/* snarf if this is a read-write inbox */
 413.627 +      if (stream->inbox && !stream->rdonly) {
 413.628 +	mtx_snarf (stream);
 413.629 +	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
 413.630 +	if ((sbuf.st_size != LOCAL->filesize) &&
 413.631 +	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 413.632 +				/* parse resulting mailbox */
 413.633 +	  r = (mtx_parse (stream)) ? T : NIL;
 413.634 +	  unlockfd (ld,lock);	/* release shared parse/append permission */
 413.635 +	}
 413.636 +      }
 413.637 +    }
 413.638 +  }
 413.639 +  return r;			/* return result of the parse */
 413.640 +}
 413.641 +
 413.642 +
 413.643 +/* MTX mail check mailbox (reparses status too)
 413.644 + * Accepts: MAIL stream
 413.645 + */
 413.646 +
 413.647 +void mtx_check (MAILSTREAM *stream)
 413.648 +{
 413.649 +				/* mark that a check is desired */
 413.650 +  if (LOCAL) LOCAL->mustcheck = T;
 413.651 +  if (mtx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 413.652 +}
 413.653 +
 413.654 +/* MTX mail snarf messages from system inbox
 413.655 + * Accepts: MAIL stream
 413.656 + */
 413.657 +
 413.658 +void mtx_snarf (MAILSTREAM *stream)
 413.659 +{
 413.660 +  unsigned long i = 0;
 413.661 +  unsigned long j,r,hdrlen,txtlen;
 413.662 +  struct stat sbuf;
 413.663 +  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
 413.664 +  MESSAGECACHE *elt;
 413.665 +  MAILSTREAM *sysibx = NIL;
 413.666 +  int ld;
 413.667 +				/* give up if can't get exclusive permission */
 413.668 +  if ((time (0) >= (LOCAL->lastsnarf +
 413.669 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
 413.670 +      strcmp (sysinbox (),stream->mailbox) &&
 413.671 +      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
 413.672 +    MM_CRITICAL (stream);	/* go critical */
 413.673 +				/* sizes match and anything in sysinbox? */
 413.674 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 413.675 +	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
 413.676 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 413.677 +	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
 413.678 +				/* yes, go to end of file in our mailbox */
 413.679 +      lseek (LOCAL->fd,sbuf.st_size,L_SET);
 413.680 +				/* for each message in sysibx mailbox */
 413.681 +      while (r && (++i <= sysibx->nmsgs)) {
 413.682 +				/* snarf message from system INBOX */
 413.683 +	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
 413.684 +	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
 413.685 +				/* if have a message */
 413.686 +	if (j = hdrlen + txtlen) {
 413.687 +				/* calculate header line */
 413.688 +	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
 413.689 +	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
 413.690 +		   ",%lu;0000000000%02o\015\012",j,(unsigned)
 413.691 +		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 413.692 +		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 413.693 +		    (fDRAFT * elt->draft)));
 413.694 +				/* copy message */
 413.695 +	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
 413.696 +	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
 413.697 +	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
 413.698 +	}
 413.699 +	fs_give ((void **) &hdr);
 413.700 +      }
 413.701 +
 413.702 +				/* make sure all the updates take */
 413.703 +      if (fsync (LOCAL->fd)) r = 0;
 413.704 +      if (r) {			/* delete all the messages we copied */
 413.705 +	if (r == 1) strcpy (tmp,"1");
 413.706 +	else sprintf (tmp,"1:%lu",r);
 413.707 +	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 413.708 +	mail_expunge (sysibx);	/* now expunge all those messages */
 413.709 +      }
 413.710 +      else {
 413.711 +	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
 413.712 +	MM_LOG (LOCAL->buf,WARN);
 413.713 +	ftruncate (LOCAL->fd,sbuf.st_size);
 413.714 +      }
 413.715 +      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
 413.716 +      LOCAL->filetime = sbuf.st_mtime;
 413.717 +    }
 413.718 +    if (sysibx) mail_close (sysibx);
 413.719 +    MM_NOCRITICAL (stream);	/* release critical */
 413.720 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 413.721 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 413.722 +  }
 413.723 +}
 413.724 +
 413.725 +/* MTX mail expunge mailbox
 413.726 + * Accepts: MAIL stream
 413.727 + *	    sequence to expunge if non-NIL
 413.728 + *	    expunge options
 413.729 + * Returns: T, always
 413.730 + */
 413.731 +
 413.732 +long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
 413.733 +{
 413.734 +  long ret;
 413.735 +  time_t tp[2];
 413.736 +  struct stat sbuf;
 413.737 +  off_t pos = 0;
 413.738 +  int ld;
 413.739 +  unsigned long i = 1;
 413.740 +  unsigned long j,k,m,recent;
 413.741 +  unsigned long n = 0;
 413.742 +  unsigned long delta = 0;
 413.743 +  char lock[MAILTMPLEN];
 413.744 +  MESSAGECACHE *elt;
 413.745 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 413.746 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 413.747 +			   mail_uid_sequence (stream,sequence) :
 413.748 +			   mail_sequence (stream,sequence)) : LONGT) &&
 413.749 +	mtx_ping (stream)));	/* parse sequence if given, ping stream */
 413.750 +  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
 413.751 +  else {
 413.752 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 413.753 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 413.754 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 413.755 +    }
 413.756 +  /* The cretins who designed flock() created a window of vulnerability in
 413.757 +   * upgrading locks from shared to exclusive or downgrading from exclusive
 413.758 +   * to shared.  Rather than maintain the lock at shared status at a minimum,
 413.759 +   * flock() actually *releases* the former lock.  Obviously they never talked
 413.760 +   * to any database guys.  Fortunately, we have the parse/append permission
 413.761 +   * lock.  If we require this lock before going exclusive on the mailbox,
 413.762 +   * another process can not sneak in and steal the exclusive mailbox lock on
 413.763 +   * us, because it will block on trying to get parse/append permission first.
 413.764 +   */
 413.765 +				/* get exclusive parse/append permission */
 413.766 +    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
 413.767 +      MM_LOG ("Unable to lock expunge mailbox",ERROR);
 413.768 +				/* make sure see any newly-arrived messages */
 413.769 +    else if (!mtx_parse (stream));
 413.770 +				/* get exclusive access */
 413.771 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 413.772 +      (*bn) (BLOCK_FILELOCK,NIL);
 413.773 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 413.774 +      (*bn) (BLOCK_NONE,NIL);
 413.775 +      MM_LOG ("Can't expunge because mailbox is in use by another process",
 413.776 +	      ERROR);
 413.777 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 413.778 +    }
 413.779 +
 413.780 +    else {
 413.781 +      MM_CRITICAL (stream);	/* go critical */
 413.782 +      recent = stream->recent;	/* get recent now that pinged and locked */
 413.783 +				/* for each message */
 413.784 +      while (i <= stream->nmsgs) {
 413.785 +				/* get cache element */
 413.786 +	elt = mtx_elt (stream,i);
 413.787 +				/* number of bytes to smash or preserve */
 413.788 +	k = elt->private.special.text.size + elt->rfc822_size;
 413.789 +				/* if need to expunge this message */
 413.790 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 413.791 +				/* if recent, note one less recent message */
 413.792 +	  if (elt->recent) --recent;
 413.793 +	  delta += k;		/* number of bytes to delete */
 413.794 +				/* notify upper levels */
 413.795 +	  mail_expunged (stream,i);
 413.796 +	  n++;			/* count up one more expunged message */
 413.797 +	}
 413.798 +	else if (i++ && delta) {/* preserved message */
 413.799 +				/* first byte to preserve */
 413.800 +	  j = elt->private.special.offset;
 413.801 +	  do {			/* read from source position */
 413.802 +	    m = min (k,LOCAL->buflen);
 413.803 +	    lseek (LOCAL->fd,j,L_SET);
 413.804 +	    read (LOCAL->fd,LOCAL->buf,m);
 413.805 +	    pos = j - delta;	/* write to destination position */
 413.806 +	    lseek (LOCAL->fd,pos,L_SET);
 413.807 +	    while (T) {
 413.808 +	      lseek (LOCAL->fd,pos,L_SET);
 413.809 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 413.810 +	      MM_NOTIFY (stream,strerror (errno),WARN);
 413.811 +	      MM_DISKERROR (stream,errno,T);
 413.812 +	    }
 413.813 +	    pos += m;		/* new position */
 413.814 +	    j += m;		/* next chunk, perhaps */
 413.815 +	  } while (k -= m);	/* until done */
 413.816 +				/* note the new address of this text */
 413.817 +	  elt->private.special.offset -= delta;
 413.818 +	}
 413.819 +				/* preserved but no deleted messages */
 413.820 +	else pos = elt->private.special.offset + k;
 413.821 +      }
 413.822 +      if (n) {			/* truncate file after last message */
 413.823 +	if (pos != (LOCAL->filesize -= delta)) {
 413.824 +	  sprintf (LOCAL->buf,
 413.825 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 413.826 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 413.827 +	  MM_LOG (LOCAL->buf,WARN);
 413.828 +	  LOCAL->filesize = pos;/* fix it then */
 413.829 +	}
 413.830 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 413.831 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 413.832 +				/* output the news */
 413.833 +	MM_LOG (LOCAL->buf,(long) NIL);
 413.834 +      }
 413.835 +      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 413.836 +      fsync (LOCAL->fd);	/* force disk update */
 413.837 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 413.838 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
 413.839 +      tp[0] = time (0);		/* reset atime to now */
 413.840 +      utime (stream->mailbox,tp);
 413.841 +      MM_NOCRITICAL (stream);	/* release critical */
 413.842 +				/* notify upper level of new mailbox size */
 413.843 +      mail_exists (stream,stream->nmsgs);
 413.844 +      mail_recent (stream,recent);
 413.845 +      (*bn) (BLOCK_FILELOCK,NIL);
 413.846 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 413.847 +      (*bn) (BLOCK_NONE,NIL);
 413.848 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 413.849 +    }
 413.850 +  }
 413.851 +  return ret;
 413.852 +}
 413.853 +
 413.854 +/* MTX mail copy message(s)
 413.855 + * Accepts: MAIL stream
 413.856 + *	    sequence
 413.857 + *	    destination mailbox
 413.858 + *	    copy options
 413.859 + * Returns: T if success, NIL if failed
 413.860 + */
 413.861 +
 413.862 +long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 413.863 +{
 413.864 +  struct stat sbuf;
 413.865 +  time_t tp[2];
 413.866 +  MESSAGECACHE *elt;
 413.867 +  unsigned long i,j,k;
 413.868 +  long ret = LONGT;
 413.869 +  int fd,ld;
 413.870 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 413.871 +  mailproxycopy_t pc =
 413.872 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 413.873 +				/* make sure valid mailbox */
 413.874 +  if (!mtx_isvalid (mailbox,LOCAL->buf)) switch (errno) {
 413.875 +  case ENOENT:			/* no such file? */
 413.876 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 413.877 +    return NIL;
 413.878 +  case 0:			/* merely empty file? */
 413.879 +    break;
 413.880 +  case EACCES:			/* file protected */
 413.881 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 413.882 +    MM_LOG (LOCAL->buf,ERROR);
 413.883 +    return NIL;
 413.884 +  case EINVAL:
 413.885 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 413.886 +    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
 413.887 +    MM_LOG (LOCAL->buf,ERROR);
 413.888 +    return NIL;
 413.889 +  default:
 413.890 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 413.891 +    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
 413.892 +    MM_LOG (LOCAL->buf,ERROR);
 413.893 +    return NIL;
 413.894 +  }
 413.895 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 413.896 +	mail_sequence (stream,sequence))) return NIL;
 413.897 +				/* got file? */  
 413.898 +  if ((fd = open (mtx_file (file,mailbox),O_RDWR,NIL)) < 0) {
 413.899 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
 413.900 +    MM_LOG (LOCAL->buf,ERROR);
 413.901 +    return NIL;
 413.902 +  }
 413.903 +  MM_CRITICAL (stream);		/* go critical */
 413.904 +				/* get exclusive parse/append permission */
 413.905 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
 413.906 +    MM_LOG ("Unable to lock copy mailbox",ERROR);
 413.907 +    MM_NOCRITICAL (stream);
 413.908 +    return NIL;
 413.909 +  }
 413.910 +  fstat (fd,&sbuf);		/* get current file size */
 413.911 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
 413.912 +
 413.913 +				/* for each requested message */
 413.914 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
 413.915 +    if ((elt = mail_elt (stream,i))->sequence) {
 413.916 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 413.917 +				/* number of bytes to copy */
 413.918 +      k = elt->private.special.text.size + elt->rfc822_size;
 413.919 +      do {			/* read from source position */
 413.920 +	j = min (k,LOCAL->buflen);
 413.921 +	read (LOCAL->fd,LOCAL->buf,j);
 413.922 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 413.923 +      } while (ret && (k -= j));/* until done */
 413.924 +    }
 413.925 +				/* make sure all the updates take */
 413.926 +  if (!(ret && (ret = !fsync (fd)))) {
 413.927 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
 413.928 +    MM_LOG (LOCAL->buf,ERROR);
 413.929 +    ftruncate (fd,sbuf.st_size);
 413.930 +  }
 413.931 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
 413.932 +				/* else preserve \Marked status */
 413.933 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
 413.934 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
 413.935 +  utime (file,tp);		/* set the times */
 413.936 +  close (fd);			/* close the file */
 413.937 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 413.938 +  MM_NOCRITICAL (stream);	/* release critical */
 413.939 +				/* delete all requested messages */
 413.940 +  if (ret && (options & CP_MOVE)) {
 413.941 +    for (i = 1; i <= stream->nmsgs; i++)
 413.942 +      if ((elt = mtx_elt (stream,i))->sequence) {
 413.943 +	elt->deleted = T;	/* mark message deleted */
 413.944 +				/* recalculate status */
 413.945 +	mtx_update_status (stream,i,NIL);
 413.946 +      }
 413.947 +    if (!stream->rdonly) {	/* make sure the update takes */
 413.948 +      fsync (LOCAL->fd);
 413.949 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 413.950 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
 413.951 +      tp[0] = time (0);		/* make sure atime remains greater */
 413.952 +      utime (stream->mailbox,tp);
 413.953 +    }
 413.954 +  }
 413.955 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
 413.956 +    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
 413.957 +  return ret;
 413.958 +}
 413.959 +
 413.960 +/* MTX mail append message from stringstruct
 413.961 + * Accepts: MAIL stream
 413.962 + *	    destination mailbox
 413.963 + *	    append callback
 413.964 + *	    data for callback
 413.965 + * Returns: T if append successful, else NIL
 413.966 + */
 413.967 +
 413.968 +long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 413.969 +{
 413.970 +  struct stat sbuf;
 413.971 +  int fd,ld,c;
 413.972 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 413.973 +  time_t tp[2];
 413.974 +  FILE *df;
 413.975 +  MESSAGECACHE elt;
 413.976 +  long f;
 413.977 +  unsigned long i,uf;
 413.978 +  STRING *message;
 413.979 +  long ret = LONGT;
 413.980 +				/* default stream to prototype */
 413.981 +  if (!stream) stream = user_flags (&mtxproto);
 413.982 +				/* make sure valid mailbox */
 413.983 +  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
 413.984 +  case ENOENT:			/* no such file? */
 413.985 +    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"INBOX.MTX");
 413.986 +    else {
 413.987 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
 413.988 +      return NIL;
 413.989 +    }
 413.990 +				/* falls through */
 413.991 +  case 0:			/* merely empty file? */
 413.992 +    break;
 413.993 +  case EACCES:			/* file protected */
 413.994 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
 413.995 +    MM_LOG (tmp,ERROR);
 413.996 +    return NIL;
 413.997 +  case EINVAL:
 413.998 +    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
 413.999 +    MM_LOG (tmp,ERROR);
413.1000 +    return NIL;
413.1001 +  default:
413.1002 +    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
413.1003 +    MM_LOG (tmp,ERROR);
413.1004 +    return NIL;
413.1005 +  }
413.1006 +				/* get first message */
413.1007 +  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
413.1008 +
413.1009 +				/* open destination mailbox */
413.1010 +  if (((fd = open (mtx_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
413.1011 +      !(df = fdopen (fd,"ab"))) {
413.1012 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
413.1013 +    MM_LOG (tmp,ERROR);
413.1014 +    return NIL;
413.1015 +  }
413.1016 +				/* get parse/append permission */
413.1017 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
413.1018 +    MM_LOG ("Unable to lock append mailbox",ERROR);
413.1019 +    close (fd);
413.1020 +    return NIL;
413.1021 +  }
413.1022 +  MM_CRITICAL (stream);		/* go critical */
413.1023 +  fstat (fd,&sbuf);		/* get current file size */
413.1024 +  errno = 0;
413.1025 +  do {				/* parse flags */
413.1026 +    if (!SIZE (message)) {	/* guard against zero-length */
413.1027 +      MM_LOG ("Append of zero-length message",ERROR);
413.1028 +      ret = NIL;
413.1029 +      break;
413.1030 +    }
413.1031 +    f = mail_parse_flags (stream,flags,&i);
413.1032 +				/* reverse bits (dontcha wish we had CIRC?) */
413.1033 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
413.1034 +    if (date) {			/* parse date if given */
413.1035 +      if (!mail_parse_date (&elt,date)) {
413.1036 +	sprintf (tmp,"Bad date in append: %.80s",date);
413.1037 +	MM_LOG (tmp,ERROR);
413.1038 +	ret = NIL;		/* mark failure */
413.1039 +	break;
413.1040 +      }
413.1041 +      mail_date (tmp,&elt);	/* write preseved date */
413.1042 +    }
413.1043 +    else internal_date (tmp);	/* get current date in IMAP format */
413.1044 +				/* write header */
413.1045 +    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
413.1046 +		 (unsigned long) f) < 0) ret = NIL;
413.1047 +    else {			/* write message */
413.1048 +      if (i) do c = 0xff & SNX (message);
413.1049 +      while ((putc (c,df) != EOF) && --i);
413.1050 +				/* get next message */
413.1051 +      if (i || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL;
413.1052 +    }
413.1053 +  } while (ret && message);
413.1054 +				/* if error... */
413.1055 +  if (!ret || (fflush (df) == EOF)) {
413.1056 +    ftruncate (fd,sbuf.st_size);/* revert file */
413.1057 +    close (fd);			/* make sure fclose() doesn't corrupt us */
413.1058 +    if (errno) {
413.1059 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
413.1060 +      MM_LOG (tmp,ERROR);
413.1061 +    }
413.1062 +    ret = NIL;
413.1063 +  }
413.1064 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
413.1065 +				/* else preserve \Marked status */
413.1066 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
413.1067 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
413.1068 +  utime (file,tp);		/* set the times */
413.1069 +  fclose (df);			/* close the file */
413.1070 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
413.1071 +  MM_NOCRITICAL (stream);	/* release critical */
413.1072 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
413.1073 +    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
413.1074 +	    WARN);
413.1075 +  return ret;
413.1076 +}
413.1077 +
413.1078 +/* Internal routines */
413.1079 +
413.1080 +
413.1081 +/* MTX mail generate file string
413.1082 + * Accepts: temporary buffer to write into
413.1083 + *	    mailbox name string
413.1084 + * Returns: local file string or NIL if failure
413.1085 + */
413.1086 +
413.1087 +char *mtx_file (char *dst,char *name)
413.1088 +{
413.1089 +  char tmp[MAILTMPLEN];
413.1090 +  char *s = mailboxfile (dst,name);
413.1091 +				/* return our standard inbox */
413.1092 +  return (s && !*s) ? mailboxfile (dst,mtx_isvalid ("~/INBOX",tmp) ?
413.1093 +				   "~/INBOX" : "INBOX.MTX") : s;
413.1094 +}
413.1095 +
413.1096 +/* MTX mail parse mailbox
413.1097 + * Accepts: MAIL stream
413.1098 + * Returns: T if parse OK
413.1099 + *	    NIL if failure, stream aborted
413.1100 + */
413.1101 +
413.1102 +long mtx_parse (MAILSTREAM *stream)
413.1103 +{
413.1104 +  struct stat sbuf;
413.1105 +  MESSAGECACHE *elt = NIL;
413.1106 +  unsigned char c,*s,*t,*x;
413.1107 +  char tmp[MAILTMPLEN];
413.1108 +  unsigned long i,j;
413.1109 +  long curpos = LOCAL->filesize;
413.1110 +  long nmsgs = stream->nmsgs;
413.1111 +  long recent = stream->recent;
413.1112 +  short added = NIL;
413.1113 +  short silent = stream->silent;
413.1114 +  fstat (LOCAL->fd,&sbuf);	/* get status */
413.1115 +  if (sbuf.st_size < curpos) {	/* sanity check */
413.1116 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
413.1117 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
413.1118 +    MM_LOG (tmp,ERROR);
413.1119 +    mtx_close (stream,NIL);
413.1120 +    return NIL;
413.1121 +  }
413.1122 +  stream->silent = T;		/* don't pass up exists events yet */
413.1123 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
413.1124 +				/* get to that position in the file */
413.1125 +    lseek (LOCAL->fd,curpos,L_SET);
413.1126 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
413.1127 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
413.1128 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
413.1129 +	       i ? strerror (errno) : "no data read");
413.1130 +      MM_LOG (tmp,ERROR);
413.1131 +      mtx_close (stream,NIL);
413.1132 +      return NIL;
413.1133 +    }
413.1134 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
413.1135 +    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
413.1136 +      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
413.1137 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
413.1138 +      MM_LOG (tmp,ERROR);
413.1139 +      mtx_close (stream,NIL);
413.1140 +      return NIL;
413.1141 +    }
413.1142 +    *s = '\0';			/* tie off header line */
413.1143 +    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
413.1144 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
413.1145 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
413.1146 +	       (unsigned long) curpos,(char *) LOCAL->buf);
413.1147 +      MM_LOG (tmp,ERROR);
413.1148 +      mtx_close (stream,NIL);
413.1149 +      return NIL;
413.1150 +    }
413.1151 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
413.1152 +
413.1153 +    added = T;			/* note that a new message was added */
413.1154 +				/* swell the cache */
413.1155 +    mail_exists (stream,++nmsgs);
413.1156 +				/* instantiate an elt for this message */
413.1157 +    (elt = mail_elt (stream,nmsgs))->valid = T;
413.1158 +    elt->private.uid = ++stream->uid_last;
413.1159 +				/* note file offset of header */
413.1160 +    elt->private.special.offset = curpos;
413.1161 +				/* in case error */
413.1162 +    elt->private.special.text.size = 0;
413.1163 +				/* header size not known yet */
413.1164 +    elt->private.msg.header.text.size = 0;
413.1165 +    x = s;			/* parse the header components */
413.1166 +    if (mail_parse_date (elt,LOCAL->buf) &&
413.1167 +	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
413.1168 +	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
413.1169 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
413.1170 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
413.1171 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
413.1172 +      elt->private.special.text.size = i;
413.1173 +    else {			/* oops */
413.1174 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
413.1175 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
413.1176 +      MM_LOG (tmp,ERROR);
413.1177 +      mtx_close (stream,NIL);
413.1178 +      return NIL;
413.1179 +    }
413.1180 +				/* make sure didn't run off end of file */
413.1181 +    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
413.1182 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
413.1183 +	       elt->private.special.offset,(unsigned long) curpos,
413.1184 +	       (unsigned long) sbuf.st_size);
413.1185 +      MM_LOG (tmp,ERROR);
413.1186 +      mtx_close (stream,NIL);
413.1187 +      return NIL;
413.1188 +    }
413.1189 +    c = t[10];			/* remember first system flags byte */
413.1190 +    t[10] = '\0';		/* tie off flags */
413.1191 +    j = strtoul (t,NIL,8);	/* get user flags value */
413.1192 +    t[10] = c;			/* restore first system flags byte */
413.1193 +				/* set up all valid user flags (reversed!) */
413.1194 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
413.1195 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
413.1196 +				/* calculate system flags */
413.1197 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
413.1198 +    if (j & fDELETED) elt->deleted = T;
413.1199 +    if (j & fFLAGGED) elt->flagged = T;
413.1200 +    if (j & fANSWERED) elt->answered = T;
413.1201 +    if (j & fDRAFT) elt->draft = T;
413.1202 +    if (!(j & fOLD)) {		/* newly arrived message? */
413.1203 +      elt->recent = T;
413.1204 +      recent++;			/* count up a new recent message */
413.1205 +				/* mark it as old */
413.1206 +      mtx_update_status (stream,nmsgs,NIL);
413.1207 +    }
413.1208 +  }
413.1209 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
413.1210 +				/* update parsed file size and time */
413.1211 +  LOCAL->filesize = sbuf.st_size;
413.1212 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
413.1213 +  LOCAL->filetime = sbuf.st_mtime;
413.1214 +  if (added && !stream->rdonly){/* make sure atime updated */
413.1215 +    time_t tp[2];
413.1216 +    tp[0] = time (0);
413.1217 +    tp[1] = LOCAL->filetime;
413.1218 +    utime (stream->mailbox,tp);
413.1219 +  }
413.1220 +  stream->silent = silent;	/* can pass up events now */
413.1221 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
413.1222 +  mail_recent (stream,recent);	/* and of change in recent messages */
413.1223 +  return LONGT;			/* return the winnage */
413.1224 +}
413.1225 +
413.1226 +/* MTX get cache element with status updating from file
413.1227 + * Accepts: MAIL stream
413.1228 + *	    message number
413.1229 + * Returns: cache element
413.1230 + */
413.1231 +
413.1232 +MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
413.1233 +{
413.1234 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
413.1235 +  struct {			/* old flags */
413.1236 +    unsigned int seen : 1;
413.1237 +    unsigned int deleted : 1;
413.1238 +    unsigned int flagged : 1;
413.1239 +    unsigned int answered : 1;
413.1240 +    unsigned int draft : 1;
413.1241 +    unsigned long user_flags;
413.1242 +  } old;
413.1243 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
413.1244 +  old.answered = elt->answered; old.draft = elt->draft;
413.1245 +  old.user_flags = elt->user_flags;
413.1246 +  mtx_read_flags (stream,elt);
413.1247 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
413.1248 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
413.1249 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
413.1250 +    MM_FLAGS (stream,msgno);	/* let top level know */
413.1251 +  return elt;
413.1252 +}
413.1253 +
413.1254 +/* MTX read flags from file
413.1255 + * Accepts: MAIL stream
413.1256 + * Returns: cache element
413.1257 + */
413.1258 +
413.1259 +void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
413.1260 +{
413.1261 +  unsigned long i,j;
413.1262 +				/* noop if readonly and have valid flags */
413.1263 +  if (stream->rdonly && elt->valid) return;
413.1264 +				/* set the seek pointer */
413.1265 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
413.1266 +	 elt->private.special.text.size - 14,L_SET);
413.1267 +				/* read the new flags */
413.1268 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
413.1269 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
413.1270 +    fatal (LOCAL->buf);
413.1271 +  }
413.1272 +				/* calculate system flags */
413.1273 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
413.1274 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
413.1275 +  elt->flagged = i & fFLAGGED ? T : NIL;
413.1276 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
413.1277 +  LOCAL->buf[10] = '\0';	/* tie off flags */
413.1278 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
413.1279 +				/* set up all valid user flags (reversed!) */
413.1280 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
413.1281 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
413.1282 +  elt->valid = T;		/* have valid flags now */
413.1283 +}
413.1284 +
413.1285 +/* MTX update status string
413.1286 + * Accepts: MAIL stream
413.1287 + *	    message number
413.1288 + *	    flag saying whether or not to sync
413.1289 + */
413.1290 +
413.1291 +void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
413.1292 +{
413.1293 +  time_t tp[2];
413.1294 +  struct stat sbuf;
413.1295 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
413.1296 +  unsigned long j,k = 0;
413.1297 +				/* readonly */
413.1298 +  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
413.1299 +  else {			/* readwrite */
413.1300 +    j = elt->user_flags;	/* get user flags */
413.1301 +				/* reverse bits (dontcha wish we had CIRC?) */
413.1302 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
413.1303 +				/* print new flag string */
413.1304 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
413.1305 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
413.1306 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
413.1307 +	      (fDRAFT * elt->draft)));
413.1308 +				/* get to that place in the file */
413.1309 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
413.1310 +	   elt->private.special.text.size - 14,L_SET);
413.1311 +				/* write new flags */
413.1312 +    write (LOCAL->fd,LOCAL->buf,12);
413.1313 +    if (syncflag) {		/* sync if requested */
413.1314 +      fsync (LOCAL->fd);
413.1315 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
413.1316 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
413.1317 +      tp[0] = time (0);		/* make sure read is later */
413.1318 +      utime (stream->mailbox,tp);
413.1319 +    }
413.1320 +  }
413.1321 +}
413.1322 +
413.1323 +/* MTX locate header for a message
413.1324 + * Accepts: MAIL stream
413.1325 + *	    message number
413.1326 + *	    pointer to returned header size
413.1327 + * Returns: position of header in file
413.1328 + */
413.1329 +
413.1330 +unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
413.1331 +			  unsigned long *size)
413.1332 +{
413.1333 +  unsigned long siz;
413.1334 +  long i = 0;
413.1335 +  int q = 0;
413.1336 +  char *s,tmp[MAILTMPLEN];
413.1337 +  MESSAGECACHE *elt = mtx_elt (stream,msgno);
413.1338 +  unsigned long ret = elt->private.special.offset +
413.1339 +    elt->private.special.text.size;
413.1340 +				/* is header size known? */
413.1341 +  if (!(*size = elt->private.msg.header.text.size)) {
413.1342 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
413.1343 +				/* search message for CRLF CRLF */
413.1344 +    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
413.1345 +				/* read another buffer as necessary */
413.1346 +      if ((--i <= 0) &&		/* buffer empty? */
413.1347 +	  (read (LOCAL->fd,s = tmp,
413.1348 +		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
413.1349 +	return ret;		/* I/O error? */
413.1350 +      switch (q) {		/* sniff at buffer */
413.1351 +      case 0:			/* first character */
413.1352 +	q = (*s++ == '\015') ? 1 : 0;
413.1353 +	break;
413.1354 +      case 1:			/* second character */
413.1355 +	q = (*s++ == '\012') ? 2 : 0;
413.1356 +	break;
413.1357 +      case 2:			/* third character */
413.1358 +	q = (*s++ == '\015') ? 3 : 0;
413.1359 +	break;
413.1360 +      case 3:			/* fourth character */
413.1361 +	if (*s++ == '\012') {	/* have the sequence? */
413.1362 +				/* yes, note for later */
413.1363 +	  elt->private.msg.header.text.size = *size = siz;
413.1364 +	  return ret;
413.1365 +	}
413.1366 +	q = 0;			/* lost... */
413.1367 +	break;
413.1368 +      }
413.1369 +    }
413.1370 +				/* header consumes entire message */
413.1371 +    elt->private.msg.header.text.size = *size = elt->rfc822_size;
413.1372 +  }
413.1373 +  return ret;
413.1374 +}
   414.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   414.2 +++ b/src/osdep/unix/mx.c	Mon Sep 14 15:17:45 2009 +0900
   414.3 @@ -0,0 +1,1287 @@
   414.4 +/* ========================================================================
   414.5 + * Copyright 1988-2008 University of Washington
   414.6 + *
   414.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   414.8 + * you may not use this file except in compliance with the License.
   414.9 + * You may obtain a copy of the License at
  414.10 + *
  414.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  414.12 + *
  414.13 + * 
  414.14 + * ========================================================================
  414.15 + */
  414.16 +
  414.17 +/*
  414.18 + * Program:	MX mail routines
  414.19 + *
  414.20 + * Author(s):	Mark Crispin
  414.21 + *		Networks and Distributed Computing
  414.22 + *		Computing & Communications
  414.23 + *		University of Washington
  414.24 + *		Administration Building, AG-44
  414.25 + *		Seattle, WA  98195
  414.26 + *		Internet: MRC@CAC.Washington.EDU
  414.27 + *
  414.28 + * Date:	3 May 1996
  414.29 + * Last Edited:	6 January 2008
  414.30 + */
  414.31 +
  414.32 +
  414.33 +#include <stdio.h>
  414.34 +#include <ctype.h>
  414.35 +#include <errno.h>
  414.36 +extern int errno;		/* just in case */
  414.37 +#include "mail.h"
  414.38 +#include "osdep.h"
  414.39 +#include <pwd.h>
  414.40 +#include <sys/stat.h>
  414.41 +#include <sys/time.h>
  414.42 +#include "misc.h"
  414.43 +#include "dummy.h"
  414.44 +#include "fdstring.h"
  414.45 +
  414.46 +/* Index file */
  414.47 +
  414.48 +#define MXINDEXNAME "/.mxindex"
  414.49 +#define MXINDEX(d,s) strcat (mx_file (d,s),MXINDEXNAME)
  414.50 +
  414.51 +
  414.52 +/* MX I/O stream local data */
  414.53 +	
  414.54 +typedef struct mx_local {
  414.55 +  int fd;			/* file descriptor of open index */
  414.56 +  unsigned char *buf;		/* temporary buffer */
  414.57 +  unsigned long buflen;		/* current size of temporary buffer */
  414.58 +  unsigned long cachedtexts;	/* total size of all cached texts */
  414.59 +  time_t scantime;		/* last time directory scanned */
  414.60 +} MXLOCAL;
  414.61 +
  414.62 +
  414.63 +/* Convenient access to local data */
  414.64 +
  414.65 +#define LOCAL ((MXLOCAL *) stream->local)
  414.66 +
  414.67 +
  414.68 +/* Function prototypes */
  414.69 +
  414.70 +DRIVER *mx_valid (char *name);
  414.71 +int mx_isvalid (char *name,char *tmp);
  414.72 +int mx_namevalid (char *name);
  414.73 +void *mx_parameters (long function,void *value);
  414.74 +long mx_dirfmttest (char *name);
  414.75 +void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  414.76 +long mx_scan_contents (char *name,char *contents,unsigned long csiz,
  414.77 +		       unsigned long fsiz);
  414.78 +void mx_list (MAILSTREAM *stream,char *ref,char *pat);
  414.79 +void mx_lsub (MAILSTREAM *stream,char *ref,char *pat);
  414.80 +long mx_subscribe (MAILSTREAM *stream,char *mailbox);
  414.81 +long mx_unsubscribe (MAILSTREAM *stream,char *mailbox);
  414.82 +long mx_create (MAILSTREAM *stream,char *mailbox);
  414.83 +long mx_delete (MAILSTREAM *stream,char *mailbox);
  414.84 +long mx_rename (MAILSTREAM *stream,char *old,char *newname);
  414.85 +int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name);
  414.86 +MAILSTREAM *mx_open (MAILSTREAM *stream);
  414.87 +void mx_close (MAILSTREAM *stream,long options);
  414.88 +void mx_fast (MAILSTREAM *stream,char *sequence,long flags);
  414.89 +char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt);
  414.90 +char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
  414.91 +		 long flags);
  414.92 +long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  414.93 +void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  414.94 +void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  414.95 +long mx_ping (MAILSTREAM *stream);
  414.96 +void mx_check (MAILSTREAM *stream);
  414.97 +long mx_expunge (MAILSTREAM *stream,char *sequence,long options);
  414.98 +long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
  414.99 +	      long options);
 414.100 +long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 414.101 +long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
 414.102 +		    STRING *st,SEARCHSET *set);
 414.103 +
 414.104 +int mx_select (struct direct *name);
 414.105 +int mx_numsort (const void *d1,const void *d2);
 414.106 +char *mx_file (char *dst,char *name);
 414.107 +long mx_lockindex (MAILSTREAM *stream);
 414.108 +void mx_unlockindex (MAILSTREAM *stream);
 414.109 +void mx_setdate (char *file,MESSAGECACHE *elt);
 414.110 +
 414.111 +
 414.112 +/* MX mail routines */
 414.113 +
 414.114 +
 414.115 +/* Driver dispatch used by MAIL */
 414.116 +
 414.117 +DRIVER mxdriver = {
 414.118 +  "mx",				/* driver name */
 414.119 +				/* driver flags */
 414.120 +  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT,
 414.121 +  (DRIVER *) NIL,		/* next driver */
 414.122 +  mx_valid,			/* mailbox is valid for us */
 414.123 +  mx_parameters,		/* manipulate parameters */
 414.124 +  mx_scan,			/* scan mailboxes */
 414.125 +  mx_list,			/* find mailboxes */
 414.126 +  mx_lsub,			/* find subscribed mailboxes */
 414.127 +  mx_subscribe,			/* subscribe to mailbox */
 414.128 +  mx_unsubscribe,		/* unsubscribe from mailbox */
 414.129 +  mx_create,			/* create mailbox */
 414.130 +  mx_delete,			/* delete mailbox */
 414.131 +  mx_rename,			/* rename mailbox */
 414.132 +  mail_status_default,		/* status of mailbox */
 414.133 +  mx_open,			/* open mailbox */
 414.134 +  mx_close,			/* close mailbox */
 414.135 +  mx_fast,			/* fetch message "fast" attributes */
 414.136 +  NIL,				/* fetch message flags */
 414.137 +  NIL,				/* fetch overview */
 414.138 +  NIL,				/* fetch message envelopes */
 414.139 +  mx_header,			/* fetch message header only */
 414.140 +  mx_text,			/* fetch message body only */
 414.141 +  NIL,				/* fetch partial message test */
 414.142 +  NIL,				/* unique identifier */
 414.143 +  NIL,				/* message number */
 414.144 +  mx_flag,			/* modify flags */
 414.145 +  mx_flagmsg,			/* per-message modify flags */
 414.146 +  NIL,				/* search for message based on criteria */
 414.147 +  NIL,				/* sort messages */
 414.148 +  NIL,				/* thread messages */
 414.149 +  mx_ping,			/* ping mailbox to see if still alive */
 414.150 +  mx_check,			/* check for new messages */
 414.151 +  mx_expunge,			/* expunge deleted messages */
 414.152 +  mx_copy,			/* copy messages to another mailbox */
 414.153 +  mx_append,			/* append string message to mailbox */
 414.154 +  NIL				/* garbage collect stream */
 414.155 +};
 414.156 +
 414.157 +				/* prototype stream */
 414.158 +MAILSTREAM mxproto = {&mxdriver};
 414.159 +
 414.160 +/* MX mail validate mailbox
 414.161 + * Accepts: mailbox name
 414.162 + * Returns: our driver if name is valid, NIL otherwise
 414.163 + */
 414.164 +
 414.165 +DRIVER *mx_valid (char *name)
 414.166 +{
 414.167 +  char tmp[MAILTMPLEN];
 414.168 +  return mx_isvalid (name,tmp) ? &mxdriver : NIL;
 414.169 +}
 414.170 +
 414.171 +
 414.172 +/* MX mail test for valid mailbox
 414.173 + * Accepts: mailbox name
 414.174 + *	    temporary buffer to use
 414.175 + * Returns: T if valid, NIL otherwise with errno holding dir stat error
 414.176 + */
 414.177 +
 414.178 +int mx_isvalid (char *name,char *tmp)
 414.179 +{
 414.180 +  struct stat sbuf;
 414.181 +  errno = NIL;			/* zap error */
 414.182 +  if ((strlen (name) <= NETMAXMBX) && *mx_file (tmp,name) &&
 414.183 +      !stat (tmp,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
 414.184 +				/* name is directory; is it mx? */
 414.185 +    if (!stat (MXINDEX (tmp,name),&sbuf) &&
 414.186 +	((sbuf.st_mode & S_IFMT) == S_IFREG)) return T;
 414.187 +    errno = NIL;		/* directory but not mx */
 414.188 +  }
 414.189 +  else if (!compare_cstring (name,"INBOX")) errno = NIL;
 414.190 +  return NIL;
 414.191 +}
 414.192 +
 414.193 +
 414.194 +/* MX mail test for valid mailbox
 414.195 + * Accepts: mailbox name
 414.196 + * Returns: T if valid, NIL otherwise
 414.197 + */
 414.198 +
 414.199 +int mx_namevalid (char *name)
 414.200 +{
 414.201 +  char *s = (*name == '/') ? name + 1 : name;
 414.202 +  while (s && *s) {		/* make sure valid name */
 414.203 +    if (isdigit (*s)) s++;	/* digit, check this node further... */
 414.204 +    else if (*s == '/') break;	/* all digit node, barf */
 414.205 +				/* non-digit, skip to next node or return */
 414.206 +    else if (!((s = strchr (s+1,'/')) && *++s)) return T;
 414.207 +  }
 414.208 +  return NIL;			/* all numeric or empty node */
 414.209 +}
 414.210 +
 414.211 +/* MX manipulate driver parameters
 414.212 + * Accepts: function code
 414.213 + *	    function-dependent value
 414.214 + * Returns: function-dependent return value
 414.215 + */
 414.216 +
 414.217 +void *mx_parameters (long function,void *value)
 414.218 +{
 414.219 +  void *ret = NIL;
 414.220 +  switch ((int) function) {
 414.221 +  case GET_INBOXPATH:
 414.222 +    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
 414.223 +    break;
 414.224 +  case GET_DIRFMTTEST:
 414.225 +    ret = (void *) mx_dirfmttest;
 414.226 +    break;
 414.227 +  case GET_SCANCONTENTS:
 414.228 +    ret = (void *) mx_scan_contents;
 414.229 +    break;
 414.230 +  }
 414.231 +  return ret;
 414.232 +}
 414.233 +
 414.234 +
 414.235 +/* MX test for directory format internal node
 414.236 + * Accepts: candidate node name
 414.237 + * Returns: T if internal name, NIL otherwise
 414.238 + */
 414.239 +
 414.240 +long mx_dirfmttest (char *name)
 414.241 +{
 414.242 +  int c;
 414.243 +				/* success if index name or all-numberic */
 414.244 +  if (strcmp (name,MXINDEXNAME+1))
 414.245 +    while (c = *name++) if (!isdigit (c)) return NIL;
 414.246 +  return LONGT;
 414.247 +}
 414.248 +
 414.249 +/* MX scan mailboxes
 414.250 + * Accepts: mail stream
 414.251 + *	    reference
 414.252 + *	    pattern to search
 414.253 + *	    string to scan
 414.254 + */
 414.255 +
 414.256 +void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 414.257 +{
 414.258 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 414.259 +}
 414.260 +
 414.261 +
 414.262 +/* MX scan mailbox for contents
 414.263 + * Accepts: mailbox name
 414.264 + *	    desired contents
 414.265 + *	    contents size
 414.266 + *	    file size (ignored)
 414.267 + * Returns: NIL if contents not found, T if found
 414.268 + */
 414.269 +
 414.270 +long mx_scan_contents (char *name,char *contents,unsigned long csiz,
 414.271 +			unsigned long fsiz)
 414.272 +{
 414.273 +  long i,nfiles;
 414.274 +  void *a;
 414.275 +  char *s;
 414.276 +  long ret = NIL;
 414.277 +  size_t namelen = strlen (name);
 414.278 +  struct stat sbuf;
 414.279 +  struct direct **names = NIL;
 414.280 +  if ((nfiles = scandir (name,&names,mx_select,mx_numsort)) > 0)
 414.281 +    for (i = 0; i < nfiles; ++i) {
 414.282 +      if (!ret) {
 414.283 +	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
 414.284 +		 "%s/%s",name,names[i]->d_name);
 414.285 +	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
 414.286 +	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
 414.287 +	fs_give ((void **) &s);
 414.288 +      }
 414.289 +      fs_give ((void **) &names[i]);
 414.290 +    }
 414.291 +				/* free directory list */
 414.292 +  if (a = (void *) names) fs_give ((void **) &a);
 414.293 +  return ret;
 414.294 +}
 414.295 +
 414.296 +/* MX list mailboxes
 414.297 + * Accepts: mail stream
 414.298 + *	    reference
 414.299 + *	    pattern to search
 414.300 + */
 414.301 +
 414.302 +void mx_list (MAILSTREAM *stream,char *ref,char *pat)
 414.303 +{
 414.304 +  if (stream) dummy_list (NIL,ref,pat);
 414.305 +}
 414.306 +
 414.307 +
 414.308 +/* MX list subscribed mailboxes
 414.309 + * Accepts: mail stream
 414.310 + *	    reference
 414.311 + *	    pattern to search
 414.312 + */
 414.313 +
 414.314 +void mx_lsub (MAILSTREAM *stream,char *ref,char *pat)
 414.315 +{
 414.316 +  if (stream) dummy_lsub (NIL,ref,pat);
 414.317 +}
 414.318 +
 414.319 +/* MX mail subscribe to mailbox
 414.320 + * Accepts: mail stream
 414.321 + *	    mailbox to add to subscription list
 414.322 + * Returns: T on success, NIL on failure
 414.323 + */
 414.324 +
 414.325 +long mx_subscribe (MAILSTREAM *stream,char *mailbox)
 414.326 +{
 414.327 +  return sm_subscribe (mailbox);
 414.328 +}
 414.329 +
 414.330 +
 414.331 +/* MX mail unsubscribe to mailbox
 414.332 + * Accepts: mail stream
 414.333 + *	    mailbox to delete from subscription list
 414.334 + * Returns: T on success, NIL on failure
 414.335 + */
 414.336 +
 414.337 +long mx_unsubscribe (MAILSTREAM *stream,char *mailbox)
 414.338 +{
 414.339 +  return sm_unsubscribe (mailbox);
 414.340 +}
 414.341 +
 414.342 +/* MX mail create mailbox
 414.343 + * Accepts: mail stream
 414.344 + *	    mailbox name to create
 414.345 + * Returns: T on success, NIL on failure
 414.346 + */
 414.347 +
 414.348 +long mx_create (MAILSTREAM *stream,char *mailbox)
 414.349 +{
 414.350 +  DRIVER *test;
 414.351 +  int fd;
 414.352 +  char *s,tmp[MAILTMPLEN];
 414.353 +  int mask = umask (0);
 414.354 +  long ret = NIL;
 414.355 +  if (!mx_namevalid (mailbox))	/* validate name */
 414.356 +    sprintf (tmp,"Can't create mailbox %.80s: invalid MX-format name",mailbox);
 414.357 +				/* must not already exist */
 414.358 +  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
 414.359 +	   strcmp (test->name,"dummy"))
 414.360 +    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
 414.361 +				/* create directory */
 414.362 +  else if (!dummy_create_path (stream,MXINDEX (tmp,mailbox),
 414.363 +			       get_dir_protection (mailbox)))
 414.364 +    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
 414.365 +  else {			/* success */
 414.366 +				/* set index protection */
 414.367 +    set_mbx_protections (mailbox,tmp);
 414.368 +				/* tie off directory name */
 414.369 +    *(s = strrchr (tmp,'/') + 1) = '\0';
 414.370 +				/* set directory protection */
 414.371 +    set_mbx_protections (mailbox,tmp);
 414.372 +    ret = LONGT;
 414.373 +  }
 414.374 +  umask (mask);			/* restore mask */
 414.375 +  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
 414.376 +  return ret;
 414.377 +}
 414.378 +
 414.379 +/* MX mail delete mailbox
 414.380 + *	    mailbox name to delete
 414.381 + * Returns: T on success, NIL on failure
 414.382 + */
 414.383 +
 414.384 +long mx_delete (MAILSTREAM *stream,char *mailbox)
 414.385 +{
 414.386 +  DIR *dirp;
 414.387 +  struct direct *d;
 414.388 +  char *s;
 414.389 +  char tmp[MAILTMPLEN];
 414.390 +  if (!mx_isvalid (mailbox,tmp))
 414.391 +    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
 414.392 +				/* delete index */
 414.393 +  else if (unlink (MXINDEX (tmp,mailbox)))
 414.394 +    sprintf (tmp,"Can't delete mailbox %.80s index: %s",
 414.395 +	     mailbox,strerror (errno));
 414.396 +  else {			/* get directory name */
 414.397 +    *(s = strrchr (tmp,'/')) = '\0';
 414.398 +    if (dirp = opendir (tmp)) {	/* open directory */
 414.399 +      *s++ = '/';		/* restore delimiter */
 414.400 +				/* massacre messages */
 414.401 +      while (d = readdir (dirp)) if (mx_select (d)) {
 414.402 +	strcpy (s,d->d_name);	/* make path */
 414.403 +	unlink (tmp);		/* sayonara */
 414.404 +      }
 414.405 +      closedir (dirp);		/* flush directory */
 414.406 +      *(s = strrchr (tmp,'/')) = '\0';
 414.407 +      if (rmdir (tmp)) {	/* try to remove the directory */
 414.408 +	sprintf (tmp,"Can't delete name %.80s: %s",mailbox,strerror (errno));
 414.409 +	MM_LOG (tmp,WARN);
 414.410 +      }
 414.411 +    }
 414.412 +    return T;			/* always success */
 414.413 +  }
 414.414 +  MM_LOG (tmp,ERROR);		/* something failed */
 414.415 +  return NIL;
 414.416 +}
 414.417 +
 414.418 +/* MX mail rename mailbox
 414.419 + * Accepts: MX mail stream
 414.420 + *	    old mailbox name
 414.421 + *	    new mailbox name
 414.422 + * Returns: T on success, NIL on failure
 414.423 + */
 414.424 +
 414.425 +long mx_rename (MAILSTREAM *stream,char *old,char *newname)
 414.426 +{
 414.427 +  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
 414.428 +  struct stat sbuf;
 414.429 +  if (!mx_isvalid (old,tmp))
 414.430 +    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
 414.431 +  else if (!mx_namevalid (newname))
 414.432 +    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MX-format name",
 414.433 +	     newname);
 414.434 +				/* new mailbox name must not be valid */
 414.435 +  else if (mx_isvalid (newname,tmp))
 414.436 +    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
 414.437 +	     newname);
 414.438 +  else {
 414.439 +    mx_file (tmp,old);		/* build old directory name */
 414.440 +    mx_file (tmp1,newname);	/* and new directory name */
 414.441 +				/* easy if not INBOX */
 414.442 +    if (compare_cstring (old,"INBOX")) {
 414.443 +				/* found superior to destination name? */
 414.444 +      if (s = strrchr (mx_file (tmp1,newname),'/')) {
 414.445 +	c = *++s;	    /* remember first character of inferior */
 414.446 +	*s = '\0';		/* tie off to get just superior */
 414.447 +				/* name doesn't exist, create it */
 414.448 +	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 414.449 +	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
 414.450 +	  return NIL;
 414.451 +	*s = c;			/* restore full name */
 414.452 +      }
 414.453 +      if (!rename (tmp,tmp1)) return LONGT;
 414.454 +    }
 414.455 +
 414.456 +				/* RFC 3501 requires this */
 414.457 +    else if (dummy_create_path (stream,strcat (tmp1,"/"),
 414.458 +				get_dir_protection (newname))) {
 414.459 +      void *a;
 414.460 +      int i,n,lasterror;
 414.461 +      struct direct **names = NIL;
 414.462 +      size_t srcl = strlen (tmp);
 414.463 +      size_t dstl = strlen (tmp1);
 414.464 +				/* rename each mx file to new directory */
 414.465 +      for (i = lasterror = 0,n = scandir (tmp,&names,mx_select,mx_numsort);
 414.466 +	   i < n; ++i) {
 414.467 +	if (mx_rename_work (tmp,srcl,tmp1,dstl,names[i]->d_name))
 414.468 +	  lasterror = errno;
 414.469 +	fs_give ((void **) &names[i]);
 414.470 +      }
 414.471 +				/* free directory list */
 414.472 +      if (a = (void *) names) fs_give ((void **) &a);
 414.473 +      if (lasterror || mx_rename_work (tmp,srcl,tmp1,dstl,MXINDEXNAME+1))
 414.474 +	errno = lasterror;
 414.475 +      else return mx_create (NIL,"INBOX");
 414.476 +    }
 414.477 +    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
 414.478 +	     old,newname,strerror (errno));
 414.479 +  }
 414.480 +  MM_LOG (tmp,ERROR);		/* something failed */
 414.481 +  return NIL;
 414.482 +}
 414.483 +
 414.484 +
 414.485 +/* MX rename worker routine
 414.486 + * Accepts: source directory name
 414.487 + *	    source directory name length
 414.488 + *	    destination directory name
 414.489 + *	    destination directory name length
 414.490 + *	    name of node to move
 414.491 + * Returns: zero if success, non-zero if error
 414.492 + */
 414.493 +
 414.494 +int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name)
 414.495 +{
 414.496 +  int ret;
 414.497 +  size_t len = strlen (name);
 414.498 +  char *s = (char *) fs_get (srcl + len + 2);
 414.499 +  char *d = (char *) fs_get (dstl + len + 1);
 414.500 +  sprintf (s,"%s/%s",src,name);
 414.501 +  sprintf (d,"%s%s",dst,name);
 414.502 +  ret = rename (s,d);
 414.503 +  fs_give ((void **) &s);
 414.504 +  fs_give ((void **) &d);
 414.505 +  return ret;
 414.506 +}
 414.507 +
 414.508 +/* MX mail open
 414.509 + * Accepts: stream to open
 414.510 + * Returns: stream on success, NIL on failure
 414.511 + */
 414.512 +
 414.513 +MAILSTREAM *mx_open (MAILSTREAM *stream)
 414.514 +{
 414.515 +  char tmp[MAILTMPLEN];
 414.516 +				/* return prototype for OP_PROTOTYPE call */
 414.517 +  if (!stream) return user_flags (&mxproto);
 414.518 +  if (stream->local) fatal ("mx recycle stream");
 414.519 +  stream->local = fs_get (sizeof (MXLOCAL));
 414.520 +				/* note if an INBOX or not */
 414.521 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 414.522 +  mx_file (tmp,stream->mailbox);/* get directory name */
 414.523 +				/* canonicalize mailbox name */
 414.524 +  fs_give ((void **) &stream->mailbox);
 414.525 +  stream->mailbox = cpystr (tmp);
 414.526 +				/* make temporary buffer */
 414.527 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 414.528 +  LOCAL->buflen = CHUNKSIZE - 1;
 414.529 +  LOCAL->scantime = 0;		/* not scanned yet */
 414.530 +  LOCAL->fd = -1;		/* no index yet */
 414.531 +  LOCAL->cachedtexts = 0;	/* no cached texts */
 414.532 +  stream->sequence++;		/* bump sequence number */
 414.533 +				/* parse mailbox */
 414.534 +  stream->nmsgs = stream->recent = 0;
 414.535 +  if (mx_ping (stream) && !(stream->nmsgs || stream->silent))
 414.536 +    MM_LOG ("Mailbox is empty",(long) NIL);
 414.537 +  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
 414.538 +    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
 414.539 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 414.540 +  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
 414.541 +    NIL : T;			/* can we create new user flags? */
 414.542 +  return stream;		/* return stream to caller */
 414.543 +}
 414.544 +
 414.545 +/* MX mail close
 414.546 + * Accepts: MAIL stream
 414.547 + *	    close options
 414.548 + */
 414.549 +
 414.550 +void mx_close (MAILSTREAM *stream,long options)
 414.551 +{
 414.552 +  if (LOCAL) {			/* only if a file is open */
 414.553 +    int silent = stream->silent;
 414.554 +    stream->silent = T;		/* note this stream is dying */
 414.555 +    if (options & CL_EXPUNGE) mx_expunge (stream,NIL,NIL);
 414.556 +				/* free local scratch buffer */
 414.557 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 414.558 +				/* nuke the local data */
 414.559 +    fs_give ((void **) &stream->local);
 414.560 +    stream->dtb = NIL;		/* log out the DTB */
 414.561 +    stream->silent = silent;	/* reset silent state */
 414.562 +  }
 414.563 +}
 414.564 +
 414.565 +/* MX mail fetch fast information
 414.566 + * Accepts: MAIL stream
 414.567 + *	    sequence
 414.568 + *	    option flags
 414.569 + */
 414.570 +
 414.571 +void mx_fast (MAILSTREAM *stream,char *sequence,long flags)
 414.572 +{
 414.573 +  unsigned long i;
 414.574 +  MESSAGECACHE *elt;
 414.575 +  if (stream && LOCAL &&
 414.576 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 414.577 +       mail_sequence (stream,sequence)))
 414.578 +    for (i = 1; i <= stream->nmsgs; i++)
 414.579 +      if ((elt = mail_elt (stream,i))->sequence) mx_fast_work (stream,elt);
 414.580 +}
 414.581 +
 414.582 +
 414.583 +/* MX mail fetch fast information
 414.584 + * Accepts: MAIL stream
 414.585 + *	    message cache element
 414.586 + * Returns: name of message file
 414.587 + */
 414.588 +
 414.589 +char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt)
 414.590 +{
 414.591 +  struct stat sbuf;
 414.592 +  struct tm *tm;
 414.593 +				/* build message file name */
 414.594 +  sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
 414.595 +				/* have size yet? */
 414.596 +  if (!elt->rfc822_size && !stat (LOCAL->buf,&sbuf)) {
 414.597 +				/* make plausible IMAPish date string */
 414.598 +    tm = gmtime (&sbuf.st_mtime);
 414.599 +    elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
 414.600 +    elt->year = tm->tm_year + 1900 - BASEYEAR;
 414.601 +    elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
 414.602 +    elt->seconds = tm->tm_sec;
 414.603 +    elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0;
 414.604 +    elt->rfc822_size = sbuf.st_size;
 414.605 +  }
 414.606 +  return (char *) LOCAL->buf;	/* return file name */
 414.607 +}
 414.608 +
 414.609 +/* MX mail fetch message header
 414.610 + * Accepts: MAIL stream
 414.611 + *	    message # to fetch
 414.612 + *	    pointer to returned header text length
 414.613 + *	    option flags
 414.614 + * Returns: message header in RFC822 format
 414.615 + */
 414.616 +
 414.617 +char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
 414.618 +		 long flags)
 414.619 +{
 414.620 +  unsigned long i;
 414.621 +  int fd;
 414.622 +  MESSAGECACHE *elt;
 414.623 +  *length = 0;			/* default to empty */
 414.624 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 414.625 +  elt = mail_elt (stream,msgno);/* get elt */
 414.626 +  if (!elt->private.msg.header.text.data) {
 414.627 +				/* purge cache if too big */
 414.628 +    if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
 414.629 +      mail_gc (stream,GC_TEXTS);/* just can't keep that much */
 414.630 +      LOCAL->cachedtexts = 0;
 414.631 +    }
 414.632 +    if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return "";
 414.633 +				/* is buffer big enough? */
 414.634 +    if (elt->rfc822_size > LOCAL->buflen) {
 414.635 +      fs_give ((void **) &LOCAL->buf);
 414.636 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
 414.637 +    }
 414.638 +				/* slurp message */
 414.639 +    read (fd,LOCAL->buf,elt->rfc822_size);
 414.640 +				/* tie off file */
 414.641 +    LOCAL->buf[elt->rfc822_size] = '\0';
 414.642 +    close (fd);			/* flush message file */
 414.643 +				/* find end of header */
 414.644 +    if (elt->rfc822_size < 4) i = 0;
 414.645 +    else for (i = 4; (i < elt->rfc822_size) &&
 414.646 +	      !((LOCAL->buf[i - 4] == '\015') &&
 414.647 +		(LOCAL->buf[i - 3] == '\012') &&
 414.648 +		(LOCAL->buf[i - 2] == '\015') &&
 414.649 +		(LOCAL->buf[i - 1] == '\012')); i++);
 414.650 +				/* copy header */
 414.651 +    cpytxt (&elt->private.msg.header.text,LOCAL->buf,i);
 414.652 +    cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i);
 414.653 +				/* add to cached size */
 414.654 +    LOCAL->cachedtexts += elt->rfc822_size;
 414.655 +  }
 414.656 +  *length = elt->private.msg.header.text.size;
 414.657 +  return (char *) elt->private.msg.header.text.data;
 414.658 +}
 414.659 +
 414.660 +/* MX mail fetch message text (body only)
 414.661 + * Accepts: MAIL stream
 414.662 + *	    message # to fetch
 414.663 + *	    pointer to returned stringstruct
 414.664 + *	    option flags
 414.665 + * Returns: T on success, NIL on failure
 414.666 + */
 414.667 +
 414.668 +long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 414.669 +{
 414.670 +  unsigned long i;
 414.671 +  MESSAGECACHE *elt;
 414.672 +				/* UID call "impossible" */
 414.673 +  if (flags & FT_UID) return NIL;
 414.674 +  elt = mail_elt (stream,msgno);
 414.675 +				/* snarf message if don't have it yet */
 414.676 +  if (!elt->private.msg.text.text.data) {
 414.677 +    mx_header (stream,msgno,&i,flags);
 414.678 +    if (!elt->private.msg.text.text.data) return NIL;
 414.679 +  }
 414.680 +				/* mark as seen */
 414.681 +  if (!(flags & FT_PEEK) && mx_lockindex (stream)) {
 414.682 +    elt->seen = T;
 414.683 +    mx_unlockindex (stream);
 414.684 +    MM_FLAGS (stream,msgno);
 414.685 +  }
 414.686 +  INIT (bs,mail_string,elt->private.msg.text.text.data,
 414.687 +	elt->private.msg.text.text.size);
 414.688 +  return T;
 414.689 +}
 414.690 +
 414.691 +/* MX mail modify flags
 414.692 + * Accepts: MAIL stream
 414.693 + *	    sequence
 414.694 + *	    flag(s)
 414.695 + *	    option flags
 414.696 + */
 414.697 +
 414.698 +void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 414.699 +{
 414.700 +  mx_unlockindex (stream);	/* finished with index */
 414.701 +}
 414.702 +
 414.703 +
 414.704 +/* MX per-message modify flags
 414.705 + * Accepts: MAIL stream
 414.706 + *	    message cache element
 414.707 + */
 414.708 +
 414.709 +void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 414.710 +{
 414.711 +  mx_lockindex (stream);	/* lock index if not already locked */
 414.712 +}
 414.713 +
 414.714 +/* MX mail ping mailbox
 414.715 + * Accepts: MAIL stream
 414.716 + * Returns: T if stream alive, else NIL
 414.717 + */
 414.718 +
 414.719 +long mx_ping (MAILSTREAM *stream)
 414.720 +{
 414.721 +  MAILSTREAM *sysibx = NIL;
 414.722 +  MESSAGECACHE *elt,*selt;
 414.723 +  struct stat sbuf;
 414.724 +  char *s,tmp[MAILTMPLEN];
 414.725 +  int fd;
 414.726 +  unsigned long i,j,r,old;
 414.727 +  long nmsgs = stream->nmsgs;
 414.728 +  long recent = stream->recent;
 414.729 +  int silent = stream->silent;
 414.730 +  if (stat (stream->mailbox,&sbuf)) return NIL;
 414.731 +  stream->silent = T;		/* don't pass up exists events yet */
 414.732 +  if (sbuf.st_ctime != LOCAL->scantime) {
 414.733 +    struct direct **names = NIL;
 414.734 +    long nfiles = scandir (stream->mailbox,&names,mx_select,mx_numsort);
 414.735 +    if (nfiles < 0) nfiles = 0;	/* in case error */
 414.736 +    old = stream->uid_last;
 414.737 +				/* note scanned now */
 414.738 +    LOCAL->scantime = sbuf.st_ctime;
 414.739 +				/* scan directory */
 414.740 +    for (i = 0; i < nfiles; ++i) {
 414.741 +				/* if newly seen, add to list */
 414.742 +      if ((j = atoi (names[i]->d_name)) > old) {
 414.743 +				/* swell the cache */
 414.744 +	mail_exists (stream,++nmsgs);
 414.745 +	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
 414.746 +	elt->valid = T;		/* note valid flags */
 414.747 +	if (old) {		/* other than the first pass? */
 414.748 +	  elt->recent = T;	/* yup, mark as recent */
 414.749 +	  recent++;		/* bump recent count */
 414.750 +	}
 414.751 +      }
 414.752 +      fs_give ((void **) &names[i]);
 414.753 +    }
 414.754 +				/* free directory */
 414.755 +    if (s = (void *) names) fs_give ((void **) &s);
 414.756 +  }
 414.757 +  stream->nmsgs = nmsgs;	/* don't upset mail_uid() */
 414.758 +
 414.759 +				/* if INBOX, snarf from system INBOX  */
 414.760 +  if (mx_lockindex (stream) && stream->inbox &&
 414.761 +      !strcmp (sysinbox (),stream->mailbox)) {
 414.762 +    old = stream->uid_last;
 414.763 +    MM_CRITICAL (stream);	/* go critical */
 414.764 +				/* see if anything in system inbox */
 414.765 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 414.766 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 414.767 +	!sysibx->rdonly && (r = sysibx->nmsgs)) {
 414.768 +      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
 414.769 +				/* build file name we will use */
 414.770 +	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,++old);
 414.771 +				/* snarf message from Berkeley mailbox */
 414.772 +	selt = mail_elt (sysibx,i);
 414.773 +	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
 414.774 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
 414.775 +	     >= 0) &&
 414.776 +	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) &&
 414.777 +	    (write (fd,s,j) == j) &&
 414.778 +	    (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) &&
 414.779 +	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
 414.780 +				/* swell the cache */
 414.781 +	  mail_exists (stream,++nmsgs);
 414.782 +	  stream->uid_last =	/* create new elt, note its file number */
 414.783 +	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
 414.784 +	  recent++;		/* bump recent count */
 414.785 +				/* set up initial flags and date */
 414.786 +	  elt->valid = elt->recent = T;
 414.787 +	  elt->seen = selt->seen;
 414.788 +	  elt->deleted = selt->deleted;
 414.789 +	  elt->flagged = selt->flagged;
 414.790 +	  elt->answered = selt->answered;
 414.791 +	  elt->draft = selt->draft;
 414.792 +	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
 414.793 +	  elt->hours = selt->hours;elt->minutes = selt->minutes;
 414.794 +	  elt->seconds = selt->seconds;
 414.795 +	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
 414.796 +	  elt->zoccident = selt->zoccident;
 414.797 +	  mx_setdate (LOCAL->buf,elt);
 414.798 +	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
 414.799 +	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 414.800 +	}
 414.801 +	else {			/* failed to snarf */
 414.802 +	  if (fd) {		/* did it ever get opened? */
 414.803 +	    close (fd);		/* close descriptor */
 414.804 +	    unlink (LOCAL->buf);/* flush this file */
 414.805 +	  }
 414.806 +	  sprintf (tmp,"Message copy to MX mailbox failed: %.80s",
 414.807 +		   s,strerror (errno));
 414.808 +	  MM_LOG (tmp,ERROR);
 414.809 +	  r = 0;		/* stop the snarf in its tracks */
 414.810 +	}
 414.811 +      }
 414.812 +				/* update scan time */
 414.813 +      if (!stat (stream->mailbox,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
 414.814 +      mail_expunge (sysibx);	/* now expunge all those messages */
 414.815 +    }
 414.816 +    if (sysibx) mail_close (sysibx);
 414.817 +    MM_NOCRITICAL (stream);	/* release critical */
 414.818 +  }
 414.819 +  mx_unlockindex (stream);	/* done with index */
 414.820 +  stream->silent = silent;	/* can pass up events now */
 414.821 +  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
 414.822 +  mail_recent (stream,recent);
 414.823 +  return T;			/* return that we are alive */
 414.824 +}
 414.825 +
 414.826 +/* MX mail check mailbox
 414.827 + * Accepts: MAIL stream
 414.828 + */
 414.829 +
 414.830 +void mx_check (MAILSTREAM *stream)
 414.831 +{
 414.832 +  if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 414.833 +}
 414.834 +
 414.835 +
 414.836 +/* MX mail expunge mailbox
 414.837 + * Accepts: MAIL stream
 414.838 + *	    sequence to expunge if non-NIL
 414.839 + *	    expunge options
 414.840 + * Returns: T, always
 414.841 + */
 414.842 +
 414.843 +long mx_expunge (MAILSTREAM *stream,char *sequence,long options)
 414.844 +{
 414.845 +  long ret;
 414.846 +  MESSAGECACHE *elt;
 414.847 +  unsigned long i = 1;
 414.848 +  unsigned long n = 0;
 414.849 +  unsigned long recent = stream->recent;
 414.850 +  if (ret = (sequence ? ((options & EX_UID) ?
 414.851 +			 mail_uid_sequence (stream,sequence) :
 414.852 +			 mail_sequence (stream,sequence)) : LONGT) &&
 414.853 +      mx_lockindex (stream)) {	/* lock the index */
 414.854 +    MM_CRITICAL (stream);	/* go critical */
 414.855 +    while (i <= stream->nmsgs) {/* for each message */
 414.856 +      elt = mail_elt (stream,i);/* if deleted, need to trash it */
 414.857 +      if (elt->deleted && (sequence ? elt->sequence : T)) {
 414.858 +	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
 414.859 +	if (unlink (LOCAL->buf)) {/* try to delete the message */
 414.860 +	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
 414.861 +		   strerror (errno));
 414.862 +	  MM_LOG (LOCAL->buf,(long) NIL);
 414.863 +	  break;
 414.864 +	}
 414.865 +				/* note uncached */
 414.866 +	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
 414.867 +				elt->private.msg.header.text.size : 0) +
 414.868 +			       (elt->private.msg.text.text.data ?
 414.869 +				elt->private.msg.text.text.size : 0));
 414.870 +	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
 414.871 +	if(elt->recent)--recent;/* if recent, note one less recent message */
 414.872 +	mail_expunged(stream,i);/* notify upper levels */
 414.873 +	n++;			/* count up one more expunged message */
 414.874 +      }
 414.875 +      else i++;			/* otherwise try next message */
 414.876 +    }
 414.877 +    if (n) {			/* output the news if any expunged */
 414.878 +      sprintf (LOCAL->buf,"Expunged %lu messages",n);
 414.879 +      MM_LOG (LOCAL->buf,(long) NIL);
 414.880 +    }
 414.881 +    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 414.882 +    MM_NOCRITICAL (stream);	/* release critical */
 414.883 +    mx_unlockindex (stream);	/* finished with index */
 414.884 +				/* notify upper level of new mailbox size */
 414.885 +    mail_exists (stream,stream->nmsgs);
 414.886 +    mail_recent (stream,recent);
 414.887 +  }
 414.888 +  return ret;
 414.889 +}
 414.890 +
 414.891 +/* MX mail copy message(s)
 414.892 + * Accepts: MAIL stream
 414.893 + *	    sequence
 414.894 + *	    destination mailbox
 414.895 + *	    copy options
 414.896 + * Returns: T if copy successful, else NIL
 414.897 + */
 414.898 +
 414.899 +long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 414.900 +{
 414.901 +  FDDATA d;
 414.902 +  STRING st;
 414.903 +  MESSAGECACHE *elt;
 414.904 +  MAILSTREAM *astream;
 414.905 +  struct stat sbuf;
 414.906 +  int fd;
 414.907 +  unsigned long i,j,uid,uidv;
 414.908 +  char *t,tmp[MAILTMPLEN];
 414.909 +  long ret;
 414.910 +  mailproxycopy_t pc =
 414.911 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 414.912 +				/* make sure valid mailbox */
 414.913 +  if (!mx_valid (mailbox)) switch (errno) {
 414.914 +  case NIL:			/* no error in stat() */
 414.915 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 414.916 +    sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox);
 414.917 +    MM_LOG (LOCAL->buf,ERROR);
 414.918 +    return NIL;
 414.919 +  default:			/* some stat() error */
 414.920 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 414.921 +    return NIL;
 414.922 +  }
 414.923 +				/* copy the messages */
 414.924 +  if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 414.925 +	       mail_sequence (stream,sequence))));
 414.926 +				/* acquire stream to append to */
 414.927 +  else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
 414.928 +    MM_LOG ("Can't open copy mailbox",ERROR);
 414.929 +    ret = NIL;
 414.930 +  }
 414.931 +  else {
 414.932 +    MM_CRITICAL (stream);	/* go critical */
 414.933 +    if (!(ret = mx_lockindex (astream)))
 414.934 +      MM_LOG ("Message copy failed: unable to lock index",ERROR);
 414.935 +    else {
 414.936 +
 414.937 +      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
 414.938 +      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 414.939 +      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 414.940 +      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) 
 414.941 +      if ((elt = mail_elt (stream,i))->sequence) {
 414.942 +	if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL))
 414.943 +		   >= 0)) {
 414.944 +	  fstat (fd,&sbuf);	/* get size of message */
 414.945 +	  d.fd = fd;		/* set up file descriptor */
 414.946 +	  d.pos = 0;		/* start of file */
 414.947 +	  d.chunk = LOCAL->buf;
 414.948 +	  d.chunksize = CHUNKSIZE;
 414.949 +	  INIT (&st,fd_string,&d,sbuf.st_size);
 414.950 +				/* init flag string */
 414.951 +	  tmp[0] = tmp[1] = '\0';
 414.952 +	  if (j = elt->user_flags) do
 414.953 +	    if (t = stream->user_flags[find_rightmost_bit (&j)])
 414.954 +	      strcat (strcat (tmp," "),t);
 414.955 +	  while (j);
 414.956 +	  if (elt->seen) strcat (tmp," \\Seen");
 414.957 +	  if (elt->deleted) strcat (tmp," \\Deleted");
 414.958 +	  if (elt->flagged) strcat (tmp," \\Flagged");
 414.959 +	  if (elt->answered) strcat (tmp," \\Answered");
 414.960 +	  if (elt->draft) strcat (tmp," \\Draft");
 414.961 +	  tmp[0] = '(';		/* open list */
 414.962 +	  strcat (tmp,")");	/* close list */
 414.963 +	  if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) {
 414.964 +				/* add to source set if needed */
 414.965 +	    if (source) mail_append_set (source,mail_uid (stream,i));
 414.966 +				/* delete if doing a move */
 414.967 +	    if (options & CP_MOVE) elt->deleted = T;
 414.968 +	  }
 414.969 +	}
 414.970 +      }
 414.971 +				/* return sets if doing COPYUID */
 414.972 +      if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
 414.973 +      else {			/* flush any sets we may have built */
 414.974 +	mail_free_searchset (&source);
 414.975 +	mail_free_searchset (&dest);
 414.976 +      }
 414.977 +      mx_unlockindex (astream);	/* unlock index */
 414.978 +    }
 414.979 +    MM_NOCRITICAL (stream);
 414.980 +    mail_close (astream);	/* finished with append stream */
 414.981 +  }
 414.982 +  return ret;			/* return success */
 414.983 +}
 414.984 +
 414.985 +/* MX mail append message from stringstruct
 414.986 + * Accepts: MAIL stream
 414.987 + *	    destination mailbox
 414.988 + *	    append callback
 414.989 + *	    data for callback
 414.990 + * Returns: T if append successful, else NIL
 414.991 + */
 414.992 +
 414.993 +long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 414.994 +{
 414.995 +  MESSAGECACHE elt;
 414.996 +  MAILSTREAM *astream;
 414.997 +  char *flags,*date,tmp[MAILTMPLEN];
 414.998 +  STRING *message;
 414.999 +  long ret = LONGT;
414.1000 +				/* default stream to prototype */
414.1001 +  if (!stream) stream = user_flags (&mxproto);
414.1002 +				/* N.B.: can't use LOCAL->buf for tmp */
414.1003 +				/* make sure valid mailbox */
414.1004 +  if (!mx_isvalid (mailbox,tmp)) switch (errno) {
414.1005 +  case ENOENT:			/* no such file? */
414.1006 +    if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX");
414.1007 +    else {
414.1008 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
414.1009 +      return NIL;
414.1010 +    }
414.1011 +				/* falls through */
414.1012 +  case 0:			/* merely empty file? */
414.1013 +    break;
414.1014 +  case EINVAL:
414.1015 +    sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox);
414.1016 +    MM_LOG (tmp,ERROR);
414.1017 +    return NIL;
414.1018 +  default:
414.1019 +    sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox);
414.1020 +    MM_LOG (tmp,ERROR);
414.1021 +    return NIL;
414.1022 +  }
414.1023 +
414.1024 +				/* get first message */
414.1025 +  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
414.1026 +  if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
414.1027 +    MM_LOG ("Can't open append mailbox",ERROR);
414.1028 +    return NIL;
414.1029 +  }
414.1030 +  MM_CRITICAL (astream);	/* go critical */
414.1031 +				/* lock the index */
414.1032 +  if (!(ret = mx_lockindex (astream)))
414.1033 +    MM_LOG ("Message append failed: unable to lock index",ERROR);
414.1034 +  else {
414.1035 +    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
414.1036 +    SEARCHSET *dst = au ? mail_newsearchset () : NIL;
414.1037 +    do {
414.1038 +				/* guard against zero-length */
414.1039 +      if (!(ret = SIZE (message)))
414.1040 +	MM_LOG ("Append of zero-length message",ERROR);
414.1041 +      else if (date && !(ret = mail_parse_date (&elt,date))) {
414.1042 +	sprintf (tmp,"Bad date in append: %.80s",date);
414.1043 +	MM_LOG (tmp,ERROR);
414.1044 +      }
414.1045 +      else ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&&
414.1046 +	     MM_APPEND (af) (stream,data,&flags,&date,&message);
414.1047 +    } while (ret && message);
414.1048 +				/* return sets if doing APPENDUID */
414.1049 +    if (au && ret) (*au) (mailbox,astream->uid_validity,dst);
414.1050 +    else mail_free_searchset (&dst);
414.1051 +    mx_unlockindex (astream);	/* unlock index */
414.1052 +  }
414.1053 +  MM_NOCRITICAL (astream);	/* release critical */
414.1054 +  mail_close (astream);
414.1055 +  return ret;
414.1056 +}
414.1057 +
414.1058 +/* MX mail append single message
414.1059 + * Accepts: MAIL stream
414.1060 + *	    flags for new message if non-NIL
414.1061 + *	    elt with source date if non-NIL
414.1062 + *	    stringstruct of message text
414.1063 + *	    searchset to place UID
414.1064 + * Returns: T if success, NIL if failure
414.1065 + */
414.1066 +
414.1067 +long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
414.1068 +		    STRING *st,SEARCHSET *set)
414.1069 +{
414.1070 +  char tmp[MAILTMPLEN];
414.1071 +  int fd;
414.1072 +  unsigned long uf;
414.1073 +  long f = mail_parse_flags (stream,flags,&uf);
414.1074 +				/* make message file name */
414.1075 +  sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last);
414.1076 +  if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
414.1077 +		  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
414.1078 +    sprintf (tmp,"Can't create append message: %s",strerror (errno));
414.1079 +    MM_LOG (tmp,ERROR);
414.1080 +    return NIL;
414.1081 +  }
414.1082 +  while (SIZE (st)) {		/* copy the file */
414.1083 +    if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) {
414.1084 +      unlink (tmp);		/* delete file */
414.1085 +      close (fd);		/* close the file */
414.1086 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
414.1087 +      MM_LOG (tmp,ERROR);
414.1088 +      return NIL;
414.1089 +    }
414.1090 +    SETPOS (st,GETPOS (st) + st->cursize);
414.1091 +  }
414.1092 +  close (fd);			/* close the file */
414.1093 +  if (elt) mx_setdate (tmp,elt);/* set file date */
414.1094 +				/* swell the cache */
414.1095 +  mail_exists (stream,++stream->nmsgs);
414.1096 +				/* copy flags */
414.1097 +  mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid =
414.1098 +		   stream->uid_last);
414.1099 +  if (f&fSEEN) elt->seen = T;
414.1100 +  if (f&fDELETED) elt->deleted = T;
414.1101 +  if (f&fFLAGGED) elt->flagged = T;
414.1102 +  if (f&fANSWERED) elt->answered = T;
414.1103 +  if (f&fDRAFT) elt->draft = T;
414.1104 +  elt->user_flags |= uf;
414.1105 +  return LONGT;
414.1106 +}
414.1107 +
414.1108 +/* Internal routines */
414.1109 +
414.1110 +
414.1111 +/* MX file name selection test
414.1112 + * Accepts: candidate directory entry
414.1113 + * Returns: T to use file name, NIL to skip it
414.1114 + */
414.1115 +
414.1116 +int mx_select (struct direct *name)
414.1117 +{
414.1118 +  char c;
414.1119 +  char *s = name->d_name;
414.1120 +  while (c = *s++) if (!isdigit (c)) return NIL;
414.1121 +  return T;
414.1122 +}
414.1123 +
414.1124 +
414.1125 +/* MX file name comparision
414.1126 + * Accepts: first candidate directory entry
414.1127 + *	    second candidate directory entry
414.1128 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
414.1129 + */
414.1130 +
414.1131 +int mx_numsort (const void *d1,const void *d2)
414.1132 +{
414.1133 +  return atoi ((*(struct direct **) d1)->d_name) -
414.1134 +    atoi ((*(struct direct **) d2)->d_name);
414.1135 +}
414.1136 +
414.1137 +
414.1138 +/* MX mail build file name
414.1139 + * Accepts: destination string
414.1140 + *          source
414.1141 + * Returns: destination
414.1142 + */
414.1143 +
414.1144 +char *mx_file (char *dst,char *name)
414.1145 +{
414.1146 +  char *s;
414.1147 +				/* empty string if mailboxfile fails */
414.1148 +  if (!mailboxfile (dst,name)) *dst = '\0';
414.1149 +				/* driver-selected INBOX  */
414.1150 +  else if (!*dst) mailboxfile (dst,"~/INBOX");
414.1151 +				/* tie off unnecessary trailing / */
414.1152 +  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
414.1153 +  return dst;
414.1154 +}
414.1155 +
414.1156 +/* MX read and lock index
414.1157 + * Accepts: MAIL stream
414.1158 + * Returns: T if success, NIL if failure
414.1159 + */
414.1160 +
414.1161 +long mx_lockindex (MAILSTREAM *stream)
414.1162 +{
414.1163 +  unsigned long uf,sf,uid;
414.1164 +  int k = 0;
414.1165 +  unsigned long msgno = 1;
414.1166 +  struct stat sbuf;
414.1167 +  char *s,*t,*idx,tmp[2*MAILTMPLEN];
414.1168 +  MESSAGECACHE *elt;
414.1169 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
414.1170 +  if ((LOCAL->fd < 0) &&	/* get index file, no-op if already have it */
414.1171 +      (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME),
414.1172 +			 O_RDWR|O_CREAT,
414.1173 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
414.1174 +      >= 0) {
414.1175 +    (*bn) (BLOCK_FILELOCK,NIL);
414.1176 +    flock (LOCAL->fd,LOCK_EX);	/* get exclusive lock */
414.1177 +    (*bn) (BLOCK_NONE,NIL);
414.1178 +    fstat (LOCAL->fd,&sbuf);	/* get size of index */
414.1179 +				/* slurp index */
414.1180 +    read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
414.1181 +    idx[sbuf.st_size] = '\0';	/* tie off index */
414.1182 +				/* parse index */
414.1183 +    if (sbuf.st_size) while (s && *s) switch (*s) {
414.1184 +    case 'V':			/* UID validity record */
414.1185 +      stream->uid_validity = strtoul (s+1,&s,16);
414.1186 +      break;
414.1187 +    case 'L':			/* UID last record */
414.1188 +      stream->uid_last = strtoul (s+1,&s,16);
414.1189 +      break;
414.1190 +    case 'K':			/* keyword */
414.1191 +				/* find end of keyword */
414.1192 +      if (s = strchr (t = ++s,'\n')) {
414.1193 +	*s++ = '\0';		/* tie off keyword */
414.1194 +				/* copy keyword */
414.1195 +	if ((k < NUSERFLAGS) && !stream->user_flags[k] &&
414.1196 +	    (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t);
414.1197 +	k++;			/* one more keyword */
414.1198 +      }
414.1199 +      break;
414.1200 +
414.1201 +    case 'M':			/* message status record */
414.1202 +      uid = strtoul (s+1,&s,16);/* get UID for this message */
414.1203 +      if (*s == ';') {		/* get user flags */
414.1204 +	uf = strtoul (s+1,&s,16);
414.1205 +	if (*s == '.') {	/* get system flags */
414.1206 +	  sf = strtoul (s+1,&s,16);
414.1207 +	  while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid))
414.1208 +	    msgno++;		/* find message number for this UID */
414.1209 +	  if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) {
414.1210 +	    (elt = mail_elt (stream,msgno))->valid = T;
414.1211 +	    elt->user_flags=uf; /* set user and system flags in elt */
414.1212 +	    if (sf & fSEEN) elt->seen = T;
414.1213 +	    if (sf & fDELETED) elt->deleted = T;
414.1214 +	    if (sf & fFLAGGED) elt->flagged = T;
414.1215 +	    if (sf & fANSWERED) elt->answered = T;
414.1216 +	    if (sf & fDRAFT) elt->draft = T;
414.1217 +	  }
414.1218 +	  break;
414.1219 +	}
414.1220 +      }
414.1221 +    default:			/* bad news */
414.1222 +      sprintf (tmp,"Error in index: %.80s",s);
414.1223 +      MM_LOG (tmp,ERROR);
414.1224 +      *s = NIL;			/* ignore remainder of index */
414.1225 +    }
414.1226 +    else {			/* new index */
414.1227 +      stream->uid_validity = time (0);
414.1228 +      user_flags (stream);	/* init stream with default user flags */
414.1229 +    }
414.1230 +    fs_give ((void **) &idx);	/* flush index */
414.1231 +  }
414.1232 +  return (LOCAL->fd >= 0) ? T : NIL;
414.1233 +}
414.1234 +
414.1235 +/* MX write and unlock index
414.1236 + * Accepts: MAIL stream
414.1237 + */
414.1238 +
414.1239 +#define MXIXBUFLEN 2048
414.1240 +
414.1241 +void mx_unlockindex (MAILSTREAM *stream)
414.1242 +{
414.1243 +  unsigned long i,j;
414.1244 +  off_t size = 0;
414.1245 +  char *s,tmp[MXIXBUFLEN + 64];
414.1246 +  MESSAGECACHE *elt;
414.1247 +  if (LOCAL->fd >= 0) {
414.1248 +    lseek (LOCAL->fd,0,L_SET);	/* rewind file */
414.1249 +				/* write header */
414.1250 +    sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last);
414.1251 +    for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
414.1252 +      sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]);
414.1253 +				/* write messages */
414.1254 +    for (i = 1; i <= stream->nmsgs; i++) {
414.1255 +				/* filled buffer? */
414.1256 +      if (((s += strlen (s)) - tmp) > MXIXBUFLEN) {
414.1257 +	write (LOCAL->fd,tmp,j = s - tmp);
414.1258 +	size += j;
414.1259 +	*(s = tmp) = '\0';	/* dump out and restart buffer */
414.1260 +      }
414.1261 +      elt = mail_elt (stream,i);
414.1262 +      sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned)
414.1263 +	      ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
414.1264 +	       (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
414.1265 +	       (fDRAFT * elt->draft)));
414.1266 +    }
414.1267 +				/* write tail end of buffer */
414.1268 +    if ((s += strlen (s)) != tmp) {
414.1269 +      write (LOCAL->fd,tmp,j = s - tmp);
414.1270 +      size += j;
414.1271 +    }
414.1272 +    ftruncate (LOCAL->fd,size);
414.1273 +    flock (LOCAL->fd,LOCK_UN);	/* unlock the index */
414.1274 +    close (LOCAL->fd);		/* finished with file */
414.1275 +    LOCAL->fd = -1;		/* no index now */
414.1276 +  }
414.1277 +}
414.1278 +
414.1279 +/* Set date for message
414.1280 + * Accepts: file name
414.1281 + *	    elt containing date
414.1282 + */
414.1283 +
414.1284 +void mx_setdate (char *file,MESSAGECACHE *elt)
414.1285 +{
414.1286 +  time_t tp[2];
414.1287 +  tp[0] = time (0);		/* atime is now */
414.1288 +  tp[1] = mail_longdate (elt);	/* modification time */
414.1289 +  utime (file,tp);		/* set the times */
414.1290 +}
   415.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   415.2 +++ b/src/osdep/unix/news.c	Mon Sep 14 15:17:45 2009 +0900
   415.3 @@ -0,0 +1,738 @@
   415.4 +/* ========================================================================
   415.5 + * Copyright 1988-2007 University of Washington
   415.6 + *
   415.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   415.8 + * you may not use this file except in compliance with the License.
   415.9 + * You may obtain a copy of the License at
  415.10 + *
  415.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  415.12 + *
  415.13 + * 
  415.14 + * ========================================================================
  415.15 + */
  415.16 +
  415.17 +/*
  415.18 + * Program:	News routines
  415.19 + *
  415.20 + * Author:	Mark Crispin
  415.21 + *		Networks and Distributed Computing
  415.22 + *		Computing & Communications
  415.23 + *		University of Washington
  415.24 + *		Administration Building, AG-44
  415.25 + *		Seattle, WA  98195
  415.26 + *		Internet: MRC@CAC.Washington.EDU
  415.27 + *
  415.28 + * Date:	4 September 1991
  415.29 + * Last Edited:	30 January 2007
  415.30 + */
  415.31 +
  415.32 +
  415.33 +#include <stdio.h>
  415.34 +#include <ctype.h>
  415.35 +#include <errno.h>
  415.36 +extern int errno;		/* just in case */
  415.37 +#include "mail.h"
  415.38 +#include "osdep.h"
  415.39 +#include <sys/stat.h>
  415.40 +#include <sys/time.h>
  415.41 +#include "misc.h"
  415.42 +#include "newsrc.h"
  415.43 +#include "fdstring.h"
  415.44 +
  415.45 +
  415.46 +/* news_load_message() flags */
  415.47 +
  415.48 +#define NLM_HEADER 0x1		/* load message text */
  415.49 +#define NLM_TEXT 0x2		/* load message text */
  415.50 +
  415.51 +/* NEWS I/O stream local data */
  415.52 +	
  415.53 +typedef struct news_local {
  415.54 +  unsigned int dirty : 1;	/* disk copy of .newsrc needs updating */
  415.55 +  char *dir;			/* spool directory name */
  415.56 +  char *name;			/* local mailbox name */
  415.57 +  unsigned char buf[CHUNKSIZE];	/* scratch buffer */
  415.58 +  unsigned long cachedtexts;	/* total size of all cached texts */
  415.59 +} NEWSLOCAL;
  415.60 +
  415.61 +
  415.62 +/* Convenient access to local data */
  415.63 +
  415.64 +#define LOCAL ((NEWSLOCAL *) stream->local)
  415.65 +
  415.66 +
  415.67 +/* Function prototypes */
  415.68 +
  415.69 +DRIVER *news_valid (char *name);
  415.70 +DRIVER *news_isvalid (char *name,char *mbx);
  415.71 +void *news_parameters (long function,void *value);
  415.72 +void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  415.73 +void news_list (MAILSTREAM *stream,char *ref,char *pat);
  415.74 +void news_lsub (MAILSTREAM *stream,char *ref,char *pat);
  415.75 +long news_canonicalize (char *ref,char *pat,char *pattern);
  415.76 +long news_subscribe (MAILSTREAM *stream,char *mailbox);
  415.77 +long news_unsubscribe (MAILSTREAM *stream,char *mailbox);
  415.78 +long news_create (MAILSTREAM *stream,char *mailbox);
  415.79 +long news_delete (MAILSTREAM *stream,char *mailbox);
  415.80 +long news_rename (MAILSTREAM *stream,char *old,char *newname);
  415.81 +MAILSTREAM *news_open (MAILSTREAM *stream);
  415.82 +int news_select (struct direct *name);
  415.83 +int news_numsort (const void *d1,const void *d2);
  415.84 +void news_close (MAILSTREAM *stream,long options);
  415.85 +void news_fast (MAILSTREAM *stream,char *sequence,long flags);
  415.86 +void news_flags (MAILSTREAM *stream,char *sequence,long flags);
  415.87 +void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
  415.88 +char *news_header (MAILSTREAM *stream,unsigned long msgno,
  415.89 +		   unsigned long *length,long flags);
  415.90 +long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  415.91 +void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  415.92 +long news_ping (MAILSTREAM *stream);
  415.93 +void news_check (MAILSTREAM *stream);
  415.94 +long news_expunge (MAILSTREAM *stream,char *sequence,long options);
  415.95 +long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  415.96 +long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  415.97 +
  415.98 +/* News routines */
  415.99 +
 415.100 +
 415.101 +/* Driver dispatch used by MAIL */
 415.102 +
 415.103 +DRIVER newsdriver = {
 415.104 +  "news",			/* driver name */
 415.105 +				/* driver flags */
 415.106 +  DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_NONEWMAIL|DR_DIRFMT,
 415.107 +  (DRIVER *) NIL,		/* next driver */
 415.108 +  news_valid,			/* mailbox is valid for us */
 415.109 +  news_parameters,		/* manipulate parameters */
 415.110 +  news_scan,			/* scan mailboxes */
 415.111 +  news_list,			/* find mailboxes */
 415.112 +  news_lsub,			/* find subscribed mailboxes */
 415.113 +  news_subscribe,		/* subscribe to mailbox */
 415.114 +  news_unsubscribe,		/* unsubscribe from mailbox */
 415.115 +  news_create,			/* create mailbox */
 415.116 +  news_delete,			/* delete mailbox */
 415.117 +  news_rename,			/* rename mailbox */
 415.118 +  mail_status_default,		/* status of mailbox */
 415.119 +  news_open,			/* open mailbox */
 415.120 +  news_close,			/* close mailbox */
 415.121 +  news_fast,			/* fetch message "fast" attributes */
 415.122 +  news_flags,			/* fetch message flags */
 415.123 +  NIL,				/* fetch overview */
 415.124 +  NIL,				/* fetch message envelopes */
 415.125 +  news_header,			/* fetch message header */
 415.126 +  news_text,			/* fetch message body */
 415.127 +  NIL,				/* fetch partial message text */
 415.128 +  NIL,				/* unique identifier */
 415.129 +  NIL,				/* message number */
 415.130 +  NIL,				/* modify flags */
 415.131 +  news_flagmsg,			/* per-message modify flags */
 415.132 +  NIL,				/* search for message based on criteria */
 415.133 +  NIL,				/* sort messages */
 415.134 +  NIL,				/* thread messages */
 415.135 +  news_ping,			/* ping mailbox to see if still alive */
 415.136 +  news_check,			/* check for new messages */
 415.137 +  news_expunge,			/* expunge deleted messages */
 415.138 +  news_copy,			/* copy messages to another mailbox */
 415.139 +  news_append,			/* append string message to mailbox */
 415.140 +  NIL				/* garbage collect stream */
 415.141 +};
 415.142 +
 415.143 +				/* prototype stream */
 415.144 +MAILSTREAM newsproto = {&newsdriver};
 415.145 +
 415.146 +/* News validate mailbox
 415.147 + * Accepts: mailbox name
 415.148 + * Returns: our driver if name is valid, NIL otherwise
 415.149 + */
 415.150 +
 415.151 +DRIVER *news_valid (char *name)
 415.152 +{
 415.153 +  int fd;
 415.154 +  char *s,*t,*u;
 415.155 +  struct stat sbuf;
 415.156 +  if ((name[0] == '#') && (name[1] == 'n') && (name[2] == 'e') &&
 415.157 +      (name[3] == 'w') && (name[4] == 's') && (name[5] == '.') &&
 415.158 +      !strchr (name,'/') &&
 415.159 +      !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
 415.160 +      ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),O_RDONLY,
 415.161 +		   NIL)) >= 0)) {
 415.162 +    fstat (fd,&sbuf);		/* get size of active file */
 415.163 +				/* slurp in active file */
 415.164 +    read (fd,t = s = (char *) fs_get (sbuf.st_size+1),sbuf.st_size);
 415.165 +    s[sbuf.st_size] = '\0';	/* tie off file */
 415.166 +    close (fd);			/* flush file */
 415.167 +    while (*t && (u = strchr (t,' '))) {
 415.168 +      *u++ = '\0';		/* tie off at end of name */
 415.169 +      if (!strcmp (name+6,t)) {
 415.170 +	fs_give ((void **) &s);	/* flush data */
 415.171 +	return &newsdriver;
 415.172 +      }
 415.173 +      t = 1 + strchr (u,'\n');	/* next line */
 415.174 +    }
 415.175 +    fs_give ((void **) &s);	/* flush data */
 415.176 +  }
 415.177 +  return NIL;			/* return status */
 415.178 +}
 415.179 +
 415.180 +/* News manipulate driver parameters
 415.181 + * Accepts: function code
 415.182 + *	    function-dependent value
 415.183 + * Returns: function-dependent return value
 415.184 + */
 415.185 +
 415.186 +void *news_parameters (long function,void *value)
 415.187 +{
 415.188 +  return (function == GET_NEWSRC) ? env_parameters (function,value) : NIL;
 415.189 +}
 415.190 +
 415.191 +
 415.192 +/* News scan mailboxes
 415.193 + * Accepts: mail stream
 415.194 + *	    reference
 415.195 + *	    pattern to search
 415.196 + *	    string to scan
 415.197 + */
 415.198 +
 415.199 +void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 415.200 +{
 415.201 +  char tmp[MAILTMPLEN];
 415.202 +  if (news_canonicalize (ref,pat,tmp))
 415.203 +    mm_log ("Scan not valid for news mailboxes",ERROR);
 415.204 +}
 415.205 +
 415.206 +/* News find list of newsgroups
 415.207 + * Accepts: mail stream
 415.208 + *	    reference
 415.209 + *	    pattern to search
 415.210 + */
 415.211 +
 415.212 +void news_list (MAILSTREAM *stream,char *ref,char *pat)
 415.213 +{
 415.214 +  int fd;
 415.215 +  int i;
 415.216 +  char *s,*t,*u,*r,pattern[MAILTMPLEN],name[MAILTMPLEN];
 415.217 +  struct stat sbuf;
 415.218 +  if (!pat || !*pat) {		/* empty pattern? */
 415.219 +    if (news_canonicalize (ref,"*",pattern)) {
 415.220 +				/* tie off name at root */
 415.221 +      if (s = strchr (pattern,'.')) *++s = '\0';
 415.222 +      else pattern[0] = '\0';
 415.223 +      mm_list (stream,'.',pattern,LATT_NOSELECT);
 415.224 +    }
 415.225 +  }
 415.226 +  else if (news_canonicalize (ref,pat,pattern) &&
 415.227 +	   !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
 415.228 +	   ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),
 415.229 +			O_RDONLY,NIL)) >= 0)) {
 415.230 +    fstat (fd,&sbuf);		/* get file size and read data */
 415.231 +    read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
 415.232 +    close (fd);			/* close file */
 415.233 +    s[sbuf.st_size] = '\0';	/* tie off string */
 415.234 +    strcpy (name,"#news.");	/* write initial prefix */
 415.235 +    i = strlen (pattern);	/* length of pattern */
 415.236 +    if (pattern[--i] != '%') i = 0;
 415.237 +    if (t = strtok_r (s,"\n",&r)) do if (u = strchr (t,' ')) {
 415.238 +      *u = '\0';		/* tie off at end of name */
 415.239 +      strcpy (name + 6,t);	/* make full form of name */
 415.240 +      if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL);
 415.241 +      else if (i && (u = strchr (name + i,'.'))) {
 415.242 +	*u = '\0';		/* tie off at delimiter, see if matches */
 415.243 +	if (pmatch_full (name,pattern,'.'))
 415.244 +	  mm_list (stream,'.',name,LATT_NOSELECT);
 415.245 +      }
 415.246 +    } while (t = strtok_r (NIL,"\n",&r));
 415.247 +    fs_give ((void **) &s);
 415.248 +  }
 415.249 +}
 415.250 +
 415.251 +/* News find list of subscribed newsgroups
 415.252 + * Accepts: mail stream
 415.253 + *	    reference
 415.254 + *	    pattern to search
 415.255 + */
 415.256 +
 415.257 +void news_lsub (MAILSTREAM *stream,char *ref,char *pat)
 415.258 +{
 415.259 +  char pattern[MAILTMPLEN];
 415.260 +				/* return data from newsrc */
 415.261 +  if (news_canonicalize (ref,pat,pattern)) newsrc_lsub (stream,pattern);
 415.262 +}
 415.263 +
 415.264 +
 415.265 +/* News canonicalize newsgroup name
 415.266 + * Accepts: reference
 415.267 + *	    pattern
 415.268 + *	    returned single pattern
 415.269 + * Returns: T on success, NIL on failure
 415.270 + */
 415.271 +
 415.272 +long news_canonicalize (char *ref,char *pat,char *pattern)
 415.273 +{
 415.274 +  unsigned long i;
 415.275 +  char *s;
 415.276 +  if (ref && *ref) {		/* have a reference */
 415.277 +    strcpy (pattern,ref);	/* copy reference to pattern */
 415.278 +				/* # overrides mailbox field in reference */
 415.279 +    if (*pat == '#') strcpy (pattern,pat);
 415.280 +				/* pattern starts, reference ends, with . */
 415.281 +    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
 415.282 +      strcat (pattern,pat + 1);	/* append, omitting one of the period */
 415.283 +    else strcat (pattern,pat);	/* anything else is just appended */
 415.284 +  }
 415.285 +  else strcpy (pattern,pat);	/* just have basic name */
 415.286 +  if ((pattern[0] == '#') && (pattern[1] == 'n') && (pattern[2] == 'e') &&
 415.287 +      (pattern[3] == 'w') && (pattern[4] == 's') && (pattern[5] == '.') &&
 415.288 +      !strchr (pattern,'/')) {	/* count wildcards */
 415.289 +    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
 415.290 +				/* success if not too many */
 415.291 +    if (i <= MAXWILDCARDS) return LONGT;
 415.292 +    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
 415.293 +  }
 415.294 +  return NIL;
 415.295 +}
 415.296 +
 415.297 +/* News subscribe to mailbox
 415.298 + * Accepts: mail stream
 415.299 + *	    mailbox to add to subscription list
 415.300 + * Returns: T on success, NIL on failure
 415.301 + */
 415.302 +
 415.303 +long news_subscribe (MAILSTREAM *stream,char *mailbox)
 415.304 +{
 415.305 +  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,':') : NIL;
 415.306 +}
 415.307 +
 415.308 +
 415.309 +/* NEWS unsubscribe to mailbox
 415.310 + * Accepts: mail stream
 415.311 + *	    mailbox to delete from subscription list
 415.312 + * Returns: T on success, NIL on failure
 415.313 + */
 415.314 +
 415.315 +long news_unsubscribe (MAILSTREAM *stream,char *mailbox)
 415.316 +{
 415.317 +  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,'!') : NIL;
 415.318 +}
 415.319 +
 415.320 +/* News create mailbox
 415.321 + * Accepts: mail stream
 415.322 + *	    mailbox name to create
 415.323 + * Returns: T on success, NIL on failure
 415.324 + */
 415.325 +
 415.326 +long news_create (MAILSTREAM *stream,char *mailbox)
 415.327 +{
 415.328 +  return NIL;			/* never valid for News */
 415.329 +}
 415.330 +
 415.331 +
 415.332 +/* News delete mailbox
 415.333 + *	    mailbox name to delete
 415.334 + * Returns: T on success, NIL on failure
 415.335 + */
 415.336 +
 415.337 +long news_delete (MAILSTREAM *stream,char *mailbox)
 415.338 +{
 415.339 +  return NIL;			/* never valid for News */
 415.340 +}
 415.341 +
 415.342 +
 415.343 +/* News rename mailbox
 415.344 + * Accepts: mail stream
 415.345 + *	    old mailbox name
 415.346 + *	    new mailbox name
 415.347 + * Returns: T on success, NIL on failure
 415.348 + */
 415.349 +
 415.350 +long news_rename (MAILSTREAM *stream,char *old,char *newname)
 415.351 +{
 415.352 +  return NIL;			/* never valid for News */
 415.353 +}
 415.354 +
 415.355 +/* News open
 415.356 + * Accepts: stream to open
 415.357 + * Returns: stream on success, NIL on failure
 415.358 + */
 415.359 +
 415.360 +MAILSTREAM *news_open (MAILSTREAM *stream)
 415.361 +{
 415.362 +  long i,nmsgs;
 415.363 +  char *s,tmp[MAILTMPLEN];
 415.364 +  struct direct **names = NIL;
 415.365 +  				/* return prototype for OP_PROTOTYPE call */
 415.366 +  if (!stream) return &newsproto;
 415.367 +  if (stream->local) fatal ("news recycle stream");
 415.368 +				/* build directory name */
 415.369 +  sprintf (s = tmp,"%s/%s",(char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),
 415.370 +	   stream->mailbox + 6);
 415.371 +  while (s = strchr (s,'.')) *s = '/';
 415.372 +				/* scan directory */
 415.373 +  if ((nmsgs = scandir (tmp,&names,news_select,news_numsort)) >= 0) {
 415.374 +    mail_exists (stream,nmsgs);	/* notify upper level that messages exist */
 415.375 +    stream->local = fs_get (sizeof (NEWSLOCAL));
 415.376 +    LOCAL->dirty = NIL;		/* no update to .newsrc needed yet */
 415.377 +    LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
 415.378 +    LOCAL->name = cpystr (stream->mailbox + 6);
 415.379 +    for (i = 0; i < nmsgs; ++i) {
 415.380 +      stream->uid_last = mail_elt (stream,i+1)->private.uid =
 415.381 +	atoi (names[i]->d_name);
 415.382 +      fs_give ((void **) &names[i]);
 415.383 +    }
 415.384 +    s = (void *) names;		/* stupid language */
 415.385 +    fs_give ((void **) &s);	/* free directory */
 415.386 +    LOCAL->cachedtexts = 0;	/* no cached texts */
 415.387 +    stream->sequence++;		/* bump sequence number */
 415.388 +    stream->rdonly = stream->perm_deleted = T;
 415.389 +				/* UIDs are always valid */
 415.390 +    stream->uid_validity = 0xbeefface;
 415.391 +				/* read .newsrc entries */
 415.392 +    mail_recent (stream,newsrc_read (LOCAL->name,stream));
 415.393 +				/* notify if empty newsgroup */
 415.394 +    if (!(stream->nmsgs || stream->silent)) {
 415.395 +      sprintf (tmp,"Newsgroup %s is empty",LOCAL->name);
 415.396 +      mm_log (tmp,WARN);
 415.397 +    }
 415.398 +  }
 415.399 +  else mm_log ("Unable to scan newsgroup spool directory",ERROR);
 415.400 +  return LOCAL ? stream : NIL;	/* if stream is alive, return to caller */
 415.401 +}
 415.402 +
 415.403 +/* News file name selection test
 415.404 + * Accepts: candidate directory entry
 415.405 + * Returns: T to use file name, NIL to skip it
 415.406 + */
 415.407 +
 415.408 +int news_select (struct direct *name)
 415.409 +{
 415.410 +  char c;
 415.411 +  char *s = name->d_name;
 415.412 +  while (c = *s++) if (!isdigit (c)) return NIL;
 415.413 +  return T;
 415.414 +}
 415.415 +
 415.416 +
 415.417 +/* News file name comparision
 415.418 + * Accepts: first candidate directory entry
 415.419 + *	    second candidate directory entry
 415.420 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
 415.421 + */
 415.422 +
 415.423 +int news_numsort (const void *d1,const void *d2)
 415.424 +{
 415.425 +  return atoi ((*(struct direct **) d1)->d_name) -
 415.426 +    atoi ((*(struct direct **) d2)->d_name);
 415.427 +}
 415.428 +
 415.429 +
 415.430 +/* News close
 415.431 + * Accepts: MAIL stream
 415.432 + *	    option flags
 415.433 + */
 415.434 +
 415.435 +void news_close (MAILSTREAM *stream,long options)
 415.436 +{
 415.437 +  if (LOCAL) {			/* only if a file is open */
 415.438 +    news_check (stream);	/* dump final checkpoint */
 415.439 +    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
 415.440 +    if (LOCAL->name) fs_give ((void **) &LOCAL->name);
 415.441 +				/* nuke the local data */
 415.442 +    fs_give ((void **) &stream->local);
 415.443 +    stream->dtb = NIL;		/* log out the DTB */
 415.444 +  }
 415.445 +}
 415.446 +
 415.447 +/* News fetch fast information
 415.448 + * Accepts: MAIL stream
 415.449 + *	    sequence
 415.450 + *	    option flags
 415.451 + */
 415.452 +
 415.453 +void news_fast (MAILSTREAM *stream,char *sequence,long flags)
 415.454 +{
 415.455 +  MESSAGECACHE *elt;
 415.456 +  unsigned long i;
 415.457 +				/* set up metadata for all messages */
 415.458 +  if (stream && LOCAL && ((flags & FT_UID) ?
 415.459 +			  mail_uid_sequence (stream,sequence) :
 415.460 +			  mail_sequence (stream,sequence)))
 415.461 +    for (i = 1; i <= stream->nmsgs; i++)
 415.462 +      if ((elt = mail_elt (stream,i))->sequence &&
 415.463 +	  !(elt->day && elt->rfc822_size)) news_load_message (stream,i,NIL);
 415.464 +}
 415.465 +
 415.466 +
 415.467 +/* News fetch flags
 415.468 + * Accepts: MAIL stream
 415.469 + *	    sequence
 415.470 + *	    option flags
 415.471 + */
 415.472 +
 415.473 +void news_flags (MAILSTREAM *stream,char *sequence,long flags)
 415.474 +{
 415.475 +  unsigned long i;
 415.476 +  if ((flags & FT_UID) ?	/* validate all elts */
 415.477 +      mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))
 415.478 +    for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;
 415.479 +}
 415.480 +
 415.481 +/* News load message into cache
 415.482 + * Accepts: MAIL stream
 415.483 + *	    message #
 415.484 + *	    option flags
 415.485 + */
 415.486 +
 415.487 +void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
 415.488 +{
 415.489 +  unsigned long i,j,nlseen;
 415.490 +  int fd;
 415.491 +  unsigned char c,*t;
 415.492 +  struct stat sbuf;
 415.493 +  MESSAGECACHE *elt;
 415.494 +  FDDATA d;
 415.495 +  STRING bs;
 415.496 +  elt = mail_elt (stream,msgno);/* get elt */
 415.497 +				/* build message file name */
 415.498 +  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
 415.499 +				/* anything we need not currently cached? */
 415.500 +  if ((!elt->day || !elt->rfc822_size ||
 415.501 +       ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
 415.502 +       ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) &&
 415.503 +      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
 415.504 +    fstat (fd,&sbuf);		/* get file metadata */
 415.505 +    d.fd = fd;			/* set up file descriptor */
 415.506 +    d.pos = 0;			/* start of file */
 415.507 +    d.chunk = LOCAL->buf;
 415.508 +    d.chunksize = CHUNKSIZE;
 415.509 +    INIT (&bs,fd_string,&d,sbuf.st_size);
 415.510 +    if (!elt->day) {		/* set internaldate to file date */
 415.511 +      struct tm *tm = gmtime (&sbuf.st_mtime);
 415.512 +      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
 415.513 +      elt->year = tm->tm_year + 1900 - BASEYEAR;
 415.514 +      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
 415.515 +      elt->seconds = tm->tm_sec;
 415.516 +      elt->zhours = 0; elt->zminutes = 0;
 415.517 +    }
 415.518 +
 415.519 +    if (!elt->rfc822_size) {	/* know message size yet? */
 415.520 +      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
 415.521 +      case '\015':		/* unlikely carriage return */
 415.522 +	if (!j || (CHR (&bs) != '\012')) {
 415.523 +	  i++;			/* ugh, raw CR */
 415.524 +	  nlseen = NIL;
 415.525 +	  break;
 415.526 +	}
 415.527 +	SNX (&bs);		/* eat the line feed, drop in */
 415.528 +      case '\012':		/* line feed? */
 415.529 +	i += 2;			/* count a CRLF */
 415.530 +				/* header size known yet? */
 415.531 +	if (!elt->private.msg.header.text.size && nlseen) {
 415.532 +				/* note position in file */
 415.533 +	  elt->private.special.text.size = GETPOS (&bs);
 415.534 +				/* and CRLF-adjusted size */
 415.535 +	  elt->private.msg.header.text.size = i;
 415.536 +	}
 415.537 +	nlseen = T;		/* note newline seen */
 415.538 +	break;
 415.539 +      default:			/* ordinary chararacter */
 415.540 +	i++;
 415.541 +	nlseen = NIL;
 415.542 +	break;
 415.543 +      }
 415.544 +      SETPOS (&bs,0);		/* restore old position */
 415.545 +      elt->rfc822_size = i;	/* note that we have size now */
 415.546 +				/* header is entire message if no delimiter */
 415.547 +      if (!elt->private.msg.header.text.size)
 415.548 +	elt->private.msg.header.text.size = elt->rfc822_size;
 415.549 +				/* text is remainder of message */
 415.550 +      elt->private.msg.text.text.size =
 415.551 +	elt->rfc822_size - elt->private.msg.header.text.size;
 415.552 +    }
 415.553 +
 415.554 +				/* need to load cache with message data? */
 415.555 +    if (((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
 415.556 +	((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) {
 415.557 +				/* purge cache if too big */
 415.558 +      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
 415.559 +				/* just can't keep that much */
 415.560 +	mail_gc (stream,GC_TEXTS);
 415.561 +	LOCAL->cachedtexts = 0;
 415.562 +      }
 415.563 +      if ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) {
 415.564 +	t = elt->private.msg.header.text.data =
 415.565 +	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
 415.566 +	LOCAL->cachedtexts += elt->private.msg.header.text.size;
 415.567 +				/* read in message header */
 415.568 +	for (i = 0; i <= elt->private.msg.header.text.size; i++)
 415.569 +	  switch (c = SNX (&bs)) {
 415.570 +	  case '\015':		/* unlikely carriage return */
 415.571 +	    *t++ = c;
 415.572 +	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
 415.573 +	    break;
 415.574 +	  case '\012':		/* line feed? */
 415.575 +	    *t++ = '\015';
 415.576 +	  default:
 415.577 +	    *t++ = c;
 415.578 +	    break;
 415.579 +	  }
 415.580 +	*t = '\0';		/* tie off string */
 415.581 +      }
 415.582 +      if ((flags & NLM_TEXT) && !elt->private.msg.text.text.data) {
 415.583 +	t = elt->private.msg.text.text.data =
 415.584 +	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
 415.585 +	SETPOS (&bs,elt->private.msg.header.text.size);
 415.586 +	LOCAL->cachedtexts += elt->private.msg.text.text.size;
 415.587 +				/* read in message text */
 415.588 +	for (i = 0; i <= elt->private.msg.text.text.size; i++)
 415.589 +	  switch (c = SNX (&bs)) {
 415.590 +	  case '\015':		/* unlikely carriage return */
 415.591 +	    *t++ = c;
 415.592 +	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
 415.593 +	    break;
 415.594 +	  case '\012':		/* line feed? */
 415.595 +	    *t++ = '\015';
 415.596 +	  default:
 415.597 +	    *t++ = c;
 415.598 +	    break;
 415.599 +	  }
 415.600 +	*t = '\0';		/* tie off string */
 415.601 +      }
 415.602 +    }
 415.603 +    close (fd);			/* flush message file */
 415.604 +  }
 415.605 +}
 415.606 +
 415.607 +/* News fetch message header
 415.608 + * Accepts: MAIL stream
 415.609 + *	    message # to fetch
 415.610 + *	    pointer to returned header text length
 415.611 + *	    option flags
 415.612 + * Returns: message header in RFC822 format
 415.613 + */
 415.614 +
 415.615 +char *news_header (MAILSTREAM *stream,unsigned long msgno,
 415.616 +		   unsigned long *length,long flags)
 415.617 +{
 415.618 +  MESSAGECACHE *elt;
 415.619 +  *length = 0;			/* default to empty */
 415.620 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 415.621 +  elt = mail_elt (stream,msgno);/* get elt */
 415.622 +  if (!elt->private.msg.header.text.data)
 415.623 +    news_load_message (stream,msgno,NLM_HEADER);
 415.624 +  *length = elt->private.msg.header.text.size;
 415.625 +  return (char *) elt->private.msg.header.text.data;
 415.626 +}
 415.627 +
 415.628 +
 415.629 +/* News fetch message text (body only)
 415.630 + * Accepts: MAIL stream
 415.631 + *	    message # to fetch
 415.632 + *	    pointer to returned stringstruct
 415.633 + *	    option flags
 415.634 + * Returns: T on success, NIL on failure
 415.635 + */
 415.636 +
 415.637 +long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 415.638 +{
 415.639 +  MESSAGECACHE *elt;
 415.640 +				/* UID call "impossible" */
 415.641 +  if (flags & FT_UID) return NIL;
 415.642 +  elt = mail_elt (stream,msgno);/* get elt */
 415.643 +				/* snarf message if don't have it yet */
 415.644 +  if (!elt->private.msg.text.text.data) {
 415.645 +    news_load_message (stream,msgno,NLM_TEXT);
 415.646 +    if (!elt->private.msg.text.text.data) return NIL;
 415.647 +  }
 415.648 +  if (!(flags & FT_PEEK)) {	/* mark as seen */
 415.649 +    mail_elt (stream,msgno)->seen = T;
 415.650 +    mm_flags (stream,msgno);
 415.651 +  }
 415.652 +  INIT (bs,mail_string,elt->private.msg.text.text.data,
 415.653 +	elt->private.msg.text.text.size);
 415.654 +  return T;
 415.655 +}
 415.656 +
 415.657 +/* News per-message modify flag
 415.658 + * Accepts: MAIL stream
 415.659 + *	    message cache element
 415.660 + */
 415.661 +
 415.662 +void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 415.663 +{
 415.664 +  if (!LOCAL->dirty) {		/* only bother checking if not dirty yet */
 415.665 +    if (elt->valid) {		/* if done, see if deleted changed */
 415.666 +      if (elt->sequence != elt->deleted) LOCAL->dirty = T;
 415.667 +      elt->sequence = T;	/* leave the sequence set */
 415.668 +    }
 415.669 +				/* note current setting of deleted flag */
 415.670 +    else elt->sequence = elt->deleted;
 415.671 +  }
 415.672 +}
 415.673 +
 415.674 +
 415.675 +/* News ping mailbox
 415.676 + * Accepts: MAIL stream
 415.677 + * Returns: T if stream alive, else NIL
 415.678 + */
 415.679 +
 415.680 +long news_ping (MAILSTREAM *stream)
 415.681 +{
 415.682 +  return T;			/* always alive */
 415.683 +}
 415.684 +
 415.685 +
 415.686 +/* News check mailbox
 415.687 + * Accepts: MAIL stream
 415.688 + */
 415.689 +
 415.690 +void news_check (MAILSTREAM *stream)
 415.691 +{
 415.692 +				/* never do if no updates */
 415.693 +  if (LOCAL->dirty) newsrc_write (LOCAL->name,stream);
 415.694 +  LOCAL->dirty = NIL;
 415.695 +}
 415.696 +
 415.697 +
 415.698 +/* News expunge mailbox
 415.699 + * Accepts: MAIL stream
 415.700 + *	    sequence to expunge if non-NIL
 415.701 + *	    expunge options
 415.702 + * Returns: T if success, NIL if failure
 415.703 + */
 415.704 +
 415.705 +long news_expunge (MAILSTREAM *stream,char *sequence,long options)
 415.706 +{
 415.707 +  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
 415.708 +  return LONGT;
 415.709 +}
 415.710 +
 415.711 +/* News copy message(s)
 415.712 + * Accepts: MAIL stream
 415.713 + *	    sequence
 415.714 + *	    destination mailbox
 415.715 + *	    option flags
 415.716 + * Returns: T if copy successful, else NIL
 415.717 + */
 415.718 +
 415.719 +long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 415.720 +{
 415.721 +  mailproxycopy_t pc =
 415.722 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 415.723 +  if (pc) return (*pc) (stream,sequence,mailbox,options);
 415.724 +  mm_log ("Copy not valid for News",ERROR);
 415.725 +  return NIL;
 415.726 +}
 415.727 +
 415.728 +
 415.729 +/* News append message from stringstruct
 415.730 + * Accepts: MAIL stream
 415.731 + *	    destination mailbox
 415.732 + *	    append callback function
 415.733 + *	    data for callback
 415.734 + * Returns: T if append successful, else NIL
 415.735 + */
 415.736 +
 415.737 +long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 415.738 +{
 415.739 +  mm_log ("Append not valid for news",ERROR);
 415.740 +  return NIL;
 415.741 +}
   416.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   416.2 +++ b/src/osdep/unix/nl_unix.c	Mon Sep 14 15:17:45 2009 +0900
   416.3 @@ -0,0 +1,92 @@
   416.4 +/* ========================================================================
   416.5 + * Copyright 1988-2006 University of Washington
   416.6 + *
   416.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   416.8 + * you may not use this file except in compliance with the License.
   416.9 + * You may obtain a copy of the License at
  416.10 + *
  416.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  416.12 + *
  416.13 + * 
  416.14 + * ========================================================================
  416.15 + */
  416.16 +
  416.17 +/*
  416.18 + * Program:	UNIX/VMS newline routines
  416.19 + *
  416.20 + * Author:	Mark Crispin
  416.21 + *		Networks and Distributed Computing
  416.22 + *		Computing & Communications
  416.23 + *		University of Washington
  416.24 + *		Administration Building, AG-44
  416.25 + *		Seattle, WA  98195
  416.26 + *		Internet: MRC@CAC.Washington.EDU
  416.27 + *
  416.28 + * Date:	1 August 1988
  416.29 + * Last Edited:	30 August 2006
  416.30 + */
  416.31 +
  416.32 +/* Copy string with CRLF newlines
  416.33 + * Accepts: destination string
  416.34 + *	    pointer to size of destination string buffer
  416.35 + *	    source string
  416.36 + *	    length of source string
  416.37 + * Returns: length of copied string
  416.38 + */
  416.39 +
  416.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  416.41 +			  unsigned char *src,unsigned long srcl)
  416.42 +{
  416.43 +  long i = srcl * 2,j;
  416.44 +  unsigned char c,*d = src;
  416.45 +  if (*dst) {			/* candidate destination provided? */
  416.46 +				/* count NLs if doesn't fit worst-case */
  416.47 +    if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++;
  416.48 +				/* still too small, must reset destination */
  416.49 +    if (i > *dstl) fs_give ((void **) dst);
  416.50 +  }
  416.51 +				/* make a new buffer if needed */
  416.52 +  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
  416.53 +  d = *dst;			/* destination string */
  416.54 +  if (srcl) do {		/* main copy loop */
  416.55 +    if ((c = *src++) < '\016') {
  416.56 +				/* prepend CR to LF */
  416.57 +      if (c == '\012') *d++ = '\015';
  416.58 +				/* unlikely CR */
  416.59 +      else if ((c == '\015') && (srcl > 1) && (*src == '\012')) {
  416.60 +	*d++ = c;		/* copy the CR */
  416.61 +	c = *src++;		/* grab the LF */
  416.62 +	--srcl;			/* adjust the count */
  416.63 +      }
  416.64 +    }
  416.65 +    *d++ = c;			/* copy character */
  416.66 +  } while (--srcl);
  416.67 +  *d = '\0';			/* tie off destination */
  416.68 +  return d - *dst;		/* return length */
  416.69 +}
  416.70 +
  416.71 +/* Length of string after strcrlfcpy applied
  416.72 + * Accepts: source string
  416.73 + * Returns: length of string
  416.74 + */
  416.75 +
  416.76 +unsigned long strcrlflen (STRING *s)
  416.77 +{
  416.78 +  unsigned long pos = GETPOS (s);
  416.79 +  unsigned long i = SIZE (s);
  416.80 +  unsigned long j = i;
  416.81 +  while (j--) switch (SNX (s)) {/* search for newlines */
  416.82 +  case '\015':			/* unlikely carriage return */
  416.83 +    if (j && (CHR (s) == '\012')) {
  416.84 +      SNX (s);			/* eat the line feed */
  416.85 +      j--;
  416.86 +    }
  416.87 +    break;
  416.88 +  case '\012':			/* line feed? */
  416.89 +    i++;
  416.90 +  default:			/* ordinary chararacter */
  416.91 +    break;
  416.92 +  }
  416.93 +  SETPOS (s,pos);		/* restore old position */
  416.94 +  return i;
  416.95 +}
   417.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   417.2 +++ b/src/osdep/unix/opendir.c	Mon Sep 14 15:17:45 2009 +0900
   417.3 @@ -0,0 +1,79 @@
   417.4 +/* ========================================================================
   417.5 + * Copyright 1988-2006 University of Washington
   417.6 + *
   417.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   417.8 + * you may not use this file except in compliance with the License.
   417.9 + * You may obtain a copy of the License at
  417.10 + *
  417.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  417.12 + *
  417.13 + * 
  417.14 + * ========================================================================
  417.15 + */
  417.16 +
  417.17 +/*
  417.18 + * Program:	Read directories
  417.19 + *
  417.20 + * Author:	Mark Crispin
  417.21 + *		Networks and Distributed Computing
  417.22 + *		Computing & Communications
  417.23 + *		University of Washington
  417.24 + *		Administration Building, AG-44
  417.25 + *		Seattle, WA  98195
  417.26 + *		Internet: MRC@CAC.Washington.EDU
  417.27 + *
  417.28 + * Date:	16 December 1993
  417.29 + * Last Edited:	30 August 2006
  417.30 + */
  417.31 +
  417.32 +/* Emulator for BSD opendir() call
  417.33 + * Accepts: directory name
  417.34 + * Returns: directory structure pointer
  417.35 + */
  417.36 +
  417.37 +DIR *opendir (char *name)
  417.38 +{
  417.39 +  DIR *d = NIL;
  417.40 +  struct stat sbuf;
  417.41 +  int fd = open (name,O_RDONLY,NIL);
  417.42 +  errno = ENOTDIR;		/* default error is bogus directory */
  417.43 +  if ((fd >= 0) && !(fstat (fd,&sbuf)) && ((sbuf.st_mode&S_IFMT) == S_IFDIR)) {
  417.44 +    d = (DIR *) fs_get (sizeof (DIR));
  417.45 +				/* initialize structure */
  417.46 +    d->dd_loc = 0;
  417.47 +    read (fd,d->dd_buf = (char *) fs_get (sbuf.st_size),
  417.48 +	  d->dd_size = sbuf.st_size);
  417.49 +  }
  417.50 +  else if (d) fs_give ((void **) &d);
  417.51 +  if (fd >= 0) close (fd);
  417.52 +  return d;
  417.53 +}
  417.54 +
  417.55 +
  417.56 +/* Emulator for BSD closedir() call
  417.57 + * Accepts: directory structure pointer
  417.58 + */
  417.59 +
  417.60 +int closedir (DIR *d)
  417.61 +{
  417.62 +				/* free storage */
  417.63 +  fs_give ((void **) &(d->dd_buf));
  417.64 +  fs_give ((void **) &d);
  417.65 +  return NIL;			/* return */
  417.66 +}
  417.67 +
  417.68 +
  417.69 +/* Emulator for BSD readdir() call
  417.70 + * Accepts: directory structure pointer
  417.71 + */
  417.72 +
  417.73 +struct direct *readdir (DIR *d)
  417.74 +{
  417.75 +				/* loop through directory */
  417.76 +  while (d->dd_loc < d->dd_size) {
  417.77 +    struct direct *dp = (struct direct *) (d->dd_buf + d->dd_loc);
  417.78 +    d->dd_loc += sizeof (struct direct);
  417.79 +    if (dp->d_ino) return dp;	/* if have a good entry return it */
  417.80 +  }
  417.81 +  return NIL;			/* all done */
  417.82 +}
   418.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   418.2 +++ b/src/osdep/unix/os_a32.c	Mon Sep 14 15:17:45 2009 +0900
   418.3 @@ -0,0 +1,60 @@
   418.4 +/* ========================================================================
   418.5 + * Copyright 1988-2006 University of Washington
   418.6 + *
   418.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   418.8 + * you may not use this file except in compliance with the License.
   418.9 + * You may obtain a copy of the License at
  418.10 + *
  418.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  418.12 + *
  418.13 + * 
  418.14 + * ========================================================================
  418.15 + */
  418.16 +
  418.17 +/*
  418.18 + * Program:	Operating-system dependent routines -- AIX 3.2 on RS 6000
  418.19 + *
  418.20 + * Author:	Mark Crispin
  418.21 + *		Networks and Distributed Computing
  418.22 + *		Computing & Communications
  418.23 + *		University of Washington
  418.24 + *		Administration Building, AG-44
  418.25 + *		Seattle, WA  98195
  418.26 + *		Internet: MRC@CAC.Washington.EDU
  418.27 + *
  418.28 + * Date:	1 August 1988
  418.29 + * Last Edited:	30 August 2006
  418.30 + */
  418.31 + 
  418.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  418.33 +#include "mail.h"
  418.34 +#include "osdep.h"
  418.35 +#include <stdio.h>
  418.36 +#include <sys/time.h>
  418.37 +#include <sys/socket.h>
  418.38 +#include <sys/stat.h>
  418.39 +#include <netinet/in.h>
  418.40 +#include <arpa/inet.h>
  418.41 +#include <netdb.h>
  418.42 +#include <ctype.h>
  418.43 +#include <errno.h>
  418.44 +extern int errno;		/* just in case */
  418.45 +#include <pwd.h>
  418.46 +#include "misc.h"
  418.47 +#include <sys/select.h>
  418.48 +
  418.49 +char *crypt (char *key,char *salt);
  418.50 +
  418.51 +extern int sys_nerr;
  418.52 +extern char *sys_errlist[];
  418.53 +
  418.54 +
  418.55 +#include "fs_unix.c"
  418.56 +#include "ftl_unix.c"
  418.57 +#include "nl_unix.c"
  418.58 +#include "env_unix.c"
  418.59 +#include "tcp_unix.c"
  418.60 +#include "gr_waitp.c"
  418.61 +#include "tz_sv4.c"
  418.62 +#include "flocksim.c"
  418.63 +#include "utime.c"
   419.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   419.2 +++ b/src/osdep/unix/os_a32.h	Mon Sep 14 15:17:45 2009 +0900
   419.3 @@ -0,0 +1,50 @@
   419.4 +/* ========================================================================
   419.5 + * Copyright 1988-2006 University of Washington
   419.6 + *
   419.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   419.8 + * you may not use this file except in compliance with the License.
   419.9 + * You may obtain a copy of the License at
  419.10 + *
  419.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  419.12 + *
  419.13 + * 
  419.14 + * ========================================================================
  419.15 + */
  419.16 +
  419.17 +/*
  419.18 + * Program:	Operating-system dependent routines -- AIX on RS6000
  419.19 + *
  419.20 + * Author:	Mark Crispin
  419.21 + *		Networks and Distributed Computing
  419.22 + *		Computing & Communications
  419.23 + *		University of Washington
  419.24 + *		Administration Building, AG-44
  419.25 + *		Seattle, WA  98195
  419.26 + *		Internet: MRC@CAC.Washington.EDU
  419.27 + *
  419.28 + * Date:	1 August 1988
  419.29 + * Last Edited:	30 August 2006
  419.30 + */
  419.31 +
  419.32 +#include <stdlib.h>
  419.33 +#include <unistd.h>
  419.34 +#include <string.h>
  419.35 +#include <sys/types.h>
  419.36 +#include <time.h>		/* for struct tm */
  419.37 +#include <dirent.h>
  419.38 +#include <fcntl.h>
  419.39 +#include <utime.h>
  419.40 +#include <syslog.h>
  419.41 +#include <sys/file.h>
  419.42 +#include <ustat.h>
  419.43 +
  419.44 +
  419.45 +#define utime portable_utime
  419.46 +int portable_utime (char *file,time_t timep[2]);
  419.47 +
  419.48 +#include "env_unix.h"
  419.49 +#include "fs.h"
  419.50 +#include "ftl.h"
  419.51 +#include "nl.h"
  419.52 +#include "tcp.h"
  419.53 +#include "flocksim.h"
   420.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   420.2 +++ b/src/osdep/unix/os_a41.c	Mon Sep 14 15:17:45 2009 +0900
   420.3 @@ -0,0 +1,61 @@
   420.4 +/* ========================================================================
   420.5 + * Copyright 1988-2006 University of Washington
   420.6 + *
   420.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   420.8 + * you may not use this file except in compliance with the License.
   420.9 + * You may obtain a copy of the License at
  420.10 + *
  420.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  420.12 + *
  420.13 + * 
  420.14 + * ========================================================================
  420.15 + */
  420.16 +
  420.17 +/*
  420.18 + * Program:	Operating-system dependent routines -- AIX 4.1 on RS 6000
  420.19 + *
  420.20 + * Author:	Mark Crispin
  420.21 + *		Networks and Distributed Computing
  420.22 + *		Computing & Communications
  420.23 + *		University of Washington
  420.24 + *		Administration Building, AG-44
  420.25 + *		Seattle, WA  98195
  420.26 + *		Internet: MRC@CAC.Washington.EDU
  420.27 + *
  420.28 + * Date:	1 August 1988
  420.29 + * Last Edited:	30 August 2006
  420.30 + */
  420.31 + 
  420.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  420.33 +#include "mail.h"
  420.34 +#include "osdep.h"
  420.35 +#include <stdio.h>
  420.36 +#include <sys/time.h>
  420.37 +#include <sys/socket.h>
  420.38 +#include <sys/stat.h>
  420.39 +#include <netinet/in.h>
  420.40 +#include <arpa/inet.h>
  420.41 +#include <netdb.h>
  420.42 +#include <ctype.h>
  420.43 +#include <errno.h>
  420.44 +extern int errno;		/* just in case */
  420.45 +#include <pwd.h>
  420.46 +#include "misc.h"
  420.47 +#include <sys/select.h>
  420.48 +#include <stddef.h>		/* needed for authenticate() */
  420.49 +
  420.50 +int authenticate (char *UserName,char *Response,int *Reenter,char **Message);
  420.51 +
  420.52 +extern int sys_nerr;
  420.53 +extern char *sys_errlist[];
  420.54 +
  420.55 +
  420.56 +#include "fs_unix.c"
  420.57 +#include "ftl_unix.c"
  420.58 +#include "nl_unix.c"
  420.59 +#include "env_unix.c"
  420.60 +#include "tcp_unix.c"
  420.61 +#include "gr_waitp.c"
  420.62 +#include "tz_sv4.c"
  420.63 +#include "flocksim.c"
  420.64 +#include "utime.c"
   421.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   421.2 +++ b/src/osdep/unix/os_a41.h	Mon Sep 14 15:17:45 2009 +0900
   421.3 @@ -0,0 +1,50 @@
   421.4 +/* ========================================================================
   421.5 + * Copyright 1988-2006 University of Washington
   421.6 + *
   421.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   421.8 + * you may not use this file except in compliance with the License.
   421.9 + * You may obtain a copy of the License at
  421.10 + *
  421.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  421.12 + *
  421.13 + * 
  421.14 + * ========================================================================
  421.15 + */
  421.16 +
  421.17 +/*
  421.18 + * Program:	Operating-system dependent routines -- AIX on RS6000
  421.19 + *
  421.20 + * Author:	Mark Crispin
  421.21 + *		Networks and Distributed Computing
  421.22 + *		Computing & Communications
  421.23 + *		University of Washington
  421.24 + *		Administration Building, AG-44
  421.25 + *		Seattle, WA  98195
  421.26 + *		Internet: MRC@CAC.Washington.EDU
  421.27 + *
  421.28 + * Date:	1 August 1988
  421.29 + * Last Edited:	30 August 2006
  421.30 + */
  421.31 +
  421.32 +#include <stdlib.h>
  421.33 +#include <unistd.h>
  421.34 +#include <string.h>
  421.35 +#include <sys/types.h>
  421.36 +#include <time.h>		/* for struct tm */
  421.37 +#include <dirent.h>
  421.38 +#include <fcntl.h>
  421.39 +#include <utime.h>
  421.40 +#include <syslog.h>
  421.41 +#include <sys/file.h>
  421.42 +#include <ustat.h>
  421.43 +
  421.44 +
  421.45 +#define utime portable_utime
  421.46 +int portable_utime (char *file,time_t timep[2]);
  421.47 +
  421.48 +#include "env_unix.h"
  421.49 +#include "fs.h"
  421.50 +#include "ftl.h"
  421.51 +#include "nl.h"
  421.52 +#include "tcp.h"
  421.53 +#include "flocksim.h"
   422.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   422.2 +++ b/src/osdep/unix/os_aix.c	Mon Sep 14 15:17:45 2009 +0900
   422.3 @@ -0,0 +1,64 @@
   422.4 +/* ========================================================================
   422.5 + * Copyright 1988-2007 University of Washington
   422.6 + *
   422.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   422.8 + * you may not use this file except in compliance with the License.
   422.9 + * You may obtain a copy of the License at
  422.10 + *
  422.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  422.12 + *
  422.13 + * 
  422.14 + * ========================================================================
  422.15 + */
  422.16 +
  422.17 +/*
  422.18 + * Program:	Operating-system dependent routines -- AIX version
  422.19 + *
  422.20 + * Author:	Mark Crispin
  422.21 + *		Networks and Distributed Computing
  422.22 + *		Computing & Communications
  422.23 + *		University of Washington
  422.24 + *		Administration Building, AG-44
  422.25 + *		Seattle, WA  98195
  422.26 + *		Internet: MRC@CAC.Washington.EDU
  422.27 + *
  422.28 + * Date:	1 August 1988
  422.29 + * Last Edited:	16 August 2007
  422.30 + */
  422.31 + 
  422.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  422.33 +#include "mail.h"
  422.34 +#include "osdep.h"
  422.35 +#include <stdio.h>
  422.36 +#include <sys/time.h>
  422.37 +#include <sys/stat.h>
  422.38 +#include <sys/socket.h>
  422.39 +#include <netinet/in.h>
  422.40 +#include <arpa/inet.h>
  422.41 +#include <netdb.h>
  422.42 +#include <ctype.h>
  422.43 +#include <errno.h>
  422.44 +extern int errno;		/* just in case */
  422.45 +#include <pwd.h>
  422.46 +#include "misc.h"
  422.47 +
  422.48 +char *crypt (char *key,char *salt);
  422.49 +
  422.50 +extern long timezone;
  422.51 +extern int daylight;
  422.52 +extern char *tzname[2];
  422.53 +
  422.54 +extern int sys_nerr;
  422.55 +extern char *sys_errlist[];
  422.56 +
  422.57 +
  422.58 +#include "fs_unix.c"
  422.59 +#include "ftl_unix.c"
  422.60 +#include "nl_unix.c"
  422.61 +#include "env_unix.c"
  422.62 +#define fork vfork
  422.63 +#include "tcp_unix.c"
  422.64 +#include "gr_waitp.c"
  422.65 +#include "memmove.c"
  422.66 +#include "strerror.c"
  422.67 +#include "tz_sv4.c"
   423.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   423.2 +++ b/src/osdep/unix/os_aix.h	Mon Sep 14 15:17:45 2009 +0900
   423.3 @@ -0,0 +1,47 @@
   423.4 +/* ========================================================================
   423.5 + * Copyright 1988-2006 University of Washington
   423.6 + *
   423.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   423.8 + * you may not use this file except in compliance with the License.
   423.9 + * You may obtain a copy of the License at
  423.10 + *
  423.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  423.12 + *
  423.13 + * 
  423.14 + * ========================================================================
  423.15 + */
  423.16 +
  423.17 +/*
  423.18 + * Program:	Operating-system dependent routines -- AIX version
  423.19 + *
  423.20 + * Author:	Mark Crispin
  423.21 + *		Networks and Distributed Computing
  423.22 + *		Computing & Communications
  423.23 + *		University of Washington
  423.24 + *		Administration Building, AG-44
  423.25 + *		Seattle, WA  98195
  423.26 + *		Internet: MRC@CAC.Washington.EDU
  423.27 + *
  423.28 + * Date:	1 August 1988
  423.29 + * Last Edited:	30 August 2006
  423.30 + */
  423.31 +
  423.32 +#include <stdlib.h>
  423.33 +#include <string.h>
  423.34 +#include <sys/types.h>
  423.35 +#include <sys/dir.h>
  423.36 +#include <fcntl.h>
  423.37 +#include <syslog.h>
  423.38 +#include <sys/file.h>
  423.39 +
  423.40 +
  423.41 +#define direct dirent
  423.42 +
  423.43 +char *strerror (int n);
  423.44 +void *memmove (void *s,void *ct,size_t n);
  423.45 +
  423.46 +#include "env_unix.h"
  423.47 +#include "fs.h"
  423.48 +#include "ftl.h"
  423.49 +#include "nl.h"
  423.50 +#include "tcp.h"
   424.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   424.2 +++ b/src/osdep/unix/os_aos.c	Mon Sep 14 15:17:45 2009 +0900
   424.3 @@ -0,0 +1,63 @@
   424.4 +/* ========================================================================
   424.5 + * Copyright 1988-2007 University of Washington
   424.6 + *
   424.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   424.8 + * you may not use this file except in compliance with the License.
   424.9 + * You may obtain a copy of the License at
  424.10 + *
  424.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  424.12 + *
  424.13 + * 
  424.14 + * ========================================================================
  424.15 + */
  424.16 +
  424.17 +/*
  424.18 + * Program:	Operating-system dependent routines -- 4.3BSD version
  424.19 + *
  424.20 + * Author:	Mark Crispin
  424.21 + *		Networks and Distributed Computing
  424.22 + *		Computing & Communications
  424.23 + *		University of Washington
  424.24 + *		Administration Building, AG-44
  424.25 + *		Seattle, WA  98195
  424.26 + *
  424.27 + * Date:	11 May 1989
  424.28 + * Last Edited:	16 August 2007
  424.29 + */
  424.30 +
  424.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  424.32 +#include "mail.h"
  424.33 +#include "osdep.h"
  424.34 +#include <stdio.h>
  424.35 +#include <sys/stat.h>
  424.36 +#include <sys/time.h>
  424.37 +#include <sys/socket.h>
  424.38 +#include <netinet/in.h>
  424.39 +#include <arpa/inet.h>
  424.40 +#include <netdb.h>
  424.41 +#include <ctype.h>
  424.42 +#include <errno.h>
  424.43 +extern int errno;		/* just in case */
  424.44 +#include <pwd.h>
  424.45 +#include "misc.h"
  424.46 +
  424.47 +
  424.48 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  424.49 +#define toint(c)       ((c)-'0')
  424.50 +
  424.51 +extern int sys_nerr;
  424.52 +extern char *sys_errlist[];
  424.53 +
  424.54 +
  424.55 +#include "fs_unix.c"
  424.56 +#include "ftl_unix.c"
  424.57 +#include "nl_unix.c"
  424.58 +#include "env_unix.c"
  424.59 +#define fork vfork
  424.60 +#include "tcp_unix.c"
  424.61 +#include "gr_wait.c"
  424.62 +#include "memmove.c"
  424.63 +#include "strerror.c"
  424.64 +#include "strstr.c"
  424.65 +#include "strtoul.c"
  424.66 +#include "tz_bsd.c"
   425.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   425.2 +++ b/src/osdep/unix/os_aos.h	Mon Sep 14 15:17:45 2009 +0900
   425.3 @@ -0,0 +1,50 @@
   425.4 +/* ========================================================================
   425.5 + * Copyright 1988-2006 University of Washington
   425.6 + *
   425.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   425.8 + * you may not use this file except in compliance with the License.
   425.9 + * You may obtain a copy of the License at
  425.10 + *
  425.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  425.12 + *
  425.13 + * 
  425.14 + * ========================================================================
  425.15 + */
  425.16 +
  425.17 +/*
  425.18 + * Program:	Operating-system dependent routines -- AOS version
  425.19 + *
  425.20 + * Author:	Mark Crispin
  425.21 + *		Networks and Distributed Computing
  425.22 + *		Computing & Communications
  425.23 + *		University of Washington
  425.24 + *		Administration Building, AG-44
  425.25 + *		Seattle, WA  98195
  425.26 + *		Internet: MRC@CAC.Washington.EDU
  425.27 + *
  425.28 + * Date:	11 May 1989
  425.29 + * Last Edited:	30 August 2006
  425.30 + */
  425.31 +
  425.32 +#include <string.h>
  425.33 +#include <sys/types.h>
  425.34 +#include <sys/dir.h>
  425.35 +#include <fcntl.h>
  425.36 +#include <syslog.h>
  425.37 +#include <sys/file.h>
  425.38 +
  425.39 +
  425.40 +char *getenv (char *name);
  425.41 +char *strstr (char *cs,char *ct);
  425.42 +char *strerror (int n);
  425.43 +void *memmove (void *s,void *ct,size_t n);
  425.44 +unsigned long strtoul (char *s,char **endp,int base);
  425.45 +void *malloc (size_t byteSize);
  425.46 +void free (void *ptr);
  425.47 +void *realloc (void *oldptr,size_t newsize);
  425.48 +
  425.49 +#include "env_unix.h"
  425.50 +#include "fs.h"
  425.51 +#include "ftl.h"
  425.52 +#include "nl.h"
  425.53 +#include "tcp.h"
   426.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   426.2 +++ b/src/osdep/unix/os_art.c	Mon Sep 14 15:17:45 2009 +0900
   426.3 @@ -0,0 +1,86 @@
   426.4 +/* ========================================================================
   426.5 + * Copyright 1988-2006 University of Washington
   426.6 + *
   426.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   426.8 + * you may not use this file except in compliance with the License.
   426.9 + * You may obtain a copy of the License at
  426.10 + *
  426.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  426.12 + *
  426.13 + * 
  426.14 + * ========================================================================
  426.15 + */
  426.16 +
  426.17 +/*
  426.18 + * Program:	Operating-system dependent routines -- AIX/RT version
  426.19 + *
  426.20 + * Author:	Mark Crispin
  426.21 + *		Networks and Distributed Computing
  426.22 + *		Computing & Communications
  426.23 + *		University of Washington
  426.24 + *		Administration Building, AG-44
  426.25 + *		Seattle, WA  98195
  426.26 + *		Internet: MRC@CAC.Washington.EDU
  426.27 + *
  426.28 + * Date:	10 April 1992
  426.29 + * Last Edited:	30 August 2006
  426.30 + */
  426.31 +
  426.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  426.33 +#include "mail.h"
  426.34 +#include "osdep.h"
  426.35 +#include <ctype.h>
  426.36 +#include <stdio.h>
  426.37 +#include <sys/stat.h>
  426.38 +#include <netinet/in.h>
  426.39 +#include <arpa/inet.h>
  426.40 +#include <netdb.h>
  426.41 +#include <errno.h>
  426.42 +extern int errno;
  426.43 +#include <pwd.h>
  426.44 +#include <sys/socket.h>
  426.45 +#include <time.h>
  426.46 +#define KERNEL
  426.47 +#include <sys/time.h>
  426.48 +#undef KERNEL
  426.49 +#include "misc.h"
  426.50 +
  426.51 +#define DIR_SIZE(d) sizeof (DIR)
  426.52 +
  426.53 +extern int sys_nerr;
  426.54 +extern char *sys_errlist[];
  426.55 +
  426.56 +#define toint(c)	((c)-'0')
  426.57 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  426.58 +
  426.59 +#define	NBBY	8	/* number of bits in a byte */
  426.60 +#define	FD_SETSIZE	256
  426.61 +
  426.62 +typedef long	fd_mask;
  426.63 +#define NFDBITS	(sizeof(fd_mask) * NBBY)
  426.64 +					/* bits per mask */
  426.65 +#define	howmany(x, y)	(((x)+((y)-1))/(y))
  426.66 +
  426.67 +typedef	struct fd_set {
  426.68 +  fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
  426.69 +} fd_set;
  426.70 +
  426.71 +#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= \
  426.72 +					(1 << ((n) % NFDBITS)))
  426.73 +#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= \
  426.74 +					~(1 << ((n) % NFDBITS)))
  426.75 +#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & \
  426.76 +					(1 << ((n) % NFDBITS)))
  426.77 +#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
  426.78 +
  426.79 +
  426.80 +#include "fs_unix.c" 
  426.81 +#include "ftl_unix.c"
  426.82 +#include "nl_unix.c"
  426.83 +#include "env_unix.c"
  426.84 +#include "tcp_unix.c"
  426.85 +#include "gr_wait.c"
  426.86 +#include "flocksim.c"
  426.87 +#include "memmove2.c"
  426.88 +#include "strerror.c"
  426.89 +#include "tz_sv4.c"
   427.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   427.2 +++ b/src/osdep/unix/os_art.h	Mon Sep 14 15:17:45 2009 +0900
   427.3 @@ -0,0 +1,81 @@
   427.4 +/* ========================================================================
   427.5 + * Copyright 1988-2006 University of Washington
   427.6 + *
   427.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   427.8 + * you may not use this file except in compliance with the License.
   427.9 + * You may obtain a copy of the License at
  427.10 + *
  427.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  427.12 + *
  427.13 + * 
  427.14 + * ========================================================================
  427.15 + */
  427.16 +
  427.17 +/*
  427.18 + * Program:	Operating-system dependent routines -- AIX/RT version
  427.19 + *
  427.20 + * Author:	Mark Crispin
  427.21 + *		Networks and Distributed Computing
  427.22 + *		Computing & Communications
  427.23 + *		University of Washington
  427.24 + *		Administration Building, AG-44
  427.25 + *		Seattle, WA  98195
  427.26 + *		Internet: MRC@CAC.Washington.EDU
  427.27 + *
  427.28 + * Date:	10 April 1992
  427.29 + * Last Edited:	15 September 2006
  427.30 + */
  427.31 +
  427.32 +#include <unistd.h>
  427.33 +#include <string.h>
  427.34 +#include <memory.h>
  427.35 +#include <sys/types.h>
  427.36 +#define direct dirent
  427.37 +#include <dirent.h>
  427.38 +#include <fcntl.h>
  427.39 +#include <sys/syslog.h>
  427.40 +#include <sys/file.h>
  427.41 +#include <ustat.h>
  427.42 +
  427.43 +
  427.44 +/* Different names between BSD and SVR4 */
  427.45 +
  427.46 +#define L_SET SEEK_SET
  427.47 +#define L_INCR SEEK_CUR
  427.48 +#define L_XTND SEEK_END
  427.49 +
  427.50 +#define random lrand48
  427.51 +
  427.52 +#define SIGSTOP SIGQUIT
  427.53 +
  427.54 +
  427.55 +/* For setitimer() emulation */
  427.56 +
  427.57 +#define ITIMER_REAL 0
  427.58 +
  427.59 +struct passwd *getpwent (void);
  427.60 +struct passwd *getpwuid (int uid);
  427.61 +struct passwd *getpwnam (char *name);
  427.62 +char *getenv (char *name);
  427.63 +long gethostid (void);
  427.64 +void *memmove (void *s,void *ct,size_t n);
  427.65 +char *strstr (char *cs,char *ct);
  427.66 +char *strerror (int n);
  427.67 +unsigned long strtoul (char *s,char **endp,int base);
  427.68 +typedef int (*select_t) (struct direct *name);
  427.69 +typedef int (*compar_t) (void *d1,void *d2);
  427.70 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  427.71 +	     compar_t compar);
  427.72 +int alphasort (void *d1,void *d2);
  427.73 +void *malloc (size_t byteSize);
  427.74 +void free (void *ptr);
  427.75 +void *realloc (void *oldptr,size_t newsize);
  427.76 +int openlog (ident,logopt,facility);
  427.77 +int syslog (priority,message,parameters ...);
  427.78 +
  427.79 +#include "env_unix.h"
  427.80 +#include "fs.h"
  427.81 +#include "ftl.h"
  427.82 +#include "nl.h"
  427.83 +#include "tcp.h"
  427.84 +#include "flocksim.h"
   428.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   428.2 +++ b/src/osdep/unix/os_asv.c	Mon Sep 14 15:17:45 2009 +0900
   428.3 @@ -0,0 +1,70 @@
   428.4 +/* ========================================================================
   428.5 + * Copyright 1988-2006 University of Washington
   428.6 + *
   428.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   428.8 + * you may not use this file except in compliance with the License.
   428.9 + * You may obtain a copy of the License at
  428.10 + *
  428.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  428.12 + *
  428.13 + * 
  428.14 + * ========================================================================
  428.15 + */
  428.16 +
  428.17 +/*
  428.18 + * Program:	Operating-system dependent routines -- Altos System V version
  428.19 + *
  428.20 + * Author:	Mark Crispin
  428.21 + *		Networks and Distributed Computing
  428.22 + *		Computing & Communications
  428.23 + *		University of Washington
  428.24 + *		Administration Building, AG-44
  428.25 + *		Seattle, WA  98195
  428.26 + *		Internet: MRC@CAC.Washington.EDU
  428.27 + *
  428.28 + * Date:	10 April 1992
  428.29 + * Last Edited:	30 August 2006
  428.30 + */
  428.31 +
  428.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  428.33 +#include "mail.h"
  428.34 +#include "osdep.h"
  428.35 +#include <ctype.h>
  428.36 +#include <stdio.h>
  428.37 +#include <sys/stat.h>
  428.38 +#include <sys/tiuser.h>
  428.39 +#include <sys/stropts.h>
  428.40 +#include <sys/poll.h>
  428.41 +#include <netinet/in.h>
  428.42 +#include <arpa/inet.h>
  428.43 +#include <netdb.h>
  428.44 +#include <errno.h>
  428.45 +#include <pwd.h>
  428.46 +#include <sys/socket.h>
  428.47 +#include "misc.h"
  428.48 +
  428.49 +extern int sys_nerr;
  428.50 +extern char *sys_errlist[];
  428.51 +
  428.52 +#define toint(c)	((c)-'0')
  428.53 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  428.54 +
  428.55 +#define DIR_SIZE(d) d->d_reclen
  428.56 +
  428.57 +#define pid_t short		/* may not be known on all ASV systems */
  428.58 +
  428.59 +#include "strstr.c"
  428.60 +#include "fs_unix.c"
  428.61 +#include "ftl_unix.c"
  428.62 +#include "nl_unix.c"
  428.63 +#include "env_unix.c"
  428.64 +#include "tcp_unix.c"
  428.65 +#include "gr_waitp.c"
  428.66 +#include "strerror.c"
  428.67 +#include "flocksim.c"
  428.68 +#include "scandir.c"
  428.69 +#include "strtoul.c"
  428.70 +#include "tz_sv4.c"
  428.71 +#include "gethstid.c"
  428.72 +#include "memmove.c"
  428.73 +#include "fsync.c"
   429.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   429.2 +++ b/src/osdep/unix/os_asv.h	Mon Sep 14 15:17:45 2009 +0900
   429.3 @@ -0,0 +1,76 @@
   429.4 +/* ========================================================================
   429.5 + * Copyright 1988-2006 University of Washington
   429.6 + *
   429.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   429.8 + * you may not use this file except in compliance with the License.
   429.9 + * You may obtain a copy of the License at
  429.10 + *
  429.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  429.12 + *
  429.13 + * 
  429.14 + * ========================================================================
  429.15 + */
  429.16 +
  429.17 +/*
  429.18 + * Program:	Operating-system dependent routines -- Altos System V version
  429.19 + *
  429.20 + * Author:	Mark Crispin
  429.21 + *		Networks and Distributed Computing
  429.22 + *		Computing & Communications
  429.23 + *		University of Washington
  429.24 + *		Administration Building, AG-44
  429.25 + *		Seattle, WA  98195
  429.26 + *		Internet: MRC@CAC.Washington.EDU
  429.27 + *
  429.28 + * Date:	10 April 1992
  429.29 + * Last Edited:	15 September 2006
  429.30 + */
  429.31 +
  429.32 +#include <string.h>
  429.33 +#include <sys/types.h>
  429.34 +#include <dirent.h>
  429.35 +#include <fcntl.h>
  429.36 +#include <unistd.h>
  429.37 +#include <time.h>
  429.38 +#include <sys/time.h>
  429.39 +#include <syslog.h>
  429.40 +#include <sys/file.h>
  429.41 +#include <ustat.h>
  429.42 +
  429.43 +
  429.44 +/* Different names, equivalent things in BSD and SysV */
  429.45 +
  429.46 +#define L_SET SEEK_SET
  429.47 +#define L_INCR SEEK_CUR
  429.48 +#define L_XTND SEEK_END
  429.49 +
  429.50 +#define direct dirent
  429.51 +
  429.52 +#define ftruncate chsize
  429.53 +#define random lrand48
  429.54 +
  429.55 +
  429.56 +struct passwd *getpwent (void);
  429.57 +struct passwd *getpwuid (int uid);
  429.58 +struct passwd *getpwnam (char *name);
  429.59 +char *getenv (char *name);
  429.60 +long gethostid (void);
  429.61 +void *memmove (void *s,void *ct,size_t n);
  429.62 +char *strstr (char *cs,char *ct);
  429.63 +char *strerror (int n);
  429.64 +unsigned long strtoul (char *s,char **endp,int base);
  429.65 +typedef int (*select_t) (struct direct *name);
  429.66 +typedef int (*compar_t) (void *d1,void *d2);
  429.67 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  429.68 +	     compar_t compar);
  429.69 +int alphasort (void *d1,void *d2);
  429.70 +void *malloc (size_t byteSize);
  429.71 +void free (void *ptr);
  429.72 +void *realloc (void *oldptr,size_t newsize);
  429.73 +
  429.74 +#include "env_unix.h"
  429.75 +#include "fs.h"
  429.76 +#include "ftl.h"
  429.77 +#include "nl.h"
  429.78 +#include "tcp.h"
  429.79 +#include "flocksim.h"
   430.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   430.2 +++ b/src/osdep/unix/os_aux.c	Mon Sep 14 15:17:45 2009 +0900
   430.3 @@ -0,0 +1,62 @@
   430.4 +/* ========================================================================
   430.5 + * Copyright 1988-2006 University of Washington
   430.6 + *
   430.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   430.8 + * you may not use this file except in compliance with the License.
   430.9 + * You may obtain a copy of the License at
  430.10 + *
  430.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  430.12 + *
  430.13 + * 
  430.14 + * ========================================================================
  430.15 + */
  430.16 +
  430.17 +/*
  430.18 + * Program:	Operating-system dependent routines -- A/UX version
  430.19 + *
  430.20 + * Author:	Mark Crispin
  430.21 + *		Networks and Distributed Computing
  430.22 + *		Computing & Communications
  430.23 + *		University of Washington
  430.24 + *		Administration Building, AG-44
  430.25 + *		Seattle, WA  98195
  430.26 + *
  430.27 + * Date:	11 May 1989
  430.28 + * Last Edited:	30 August 2006
  430.29 + */
  430.30 +
  430.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  430.32 +#include "mail.h"
  430.33 +#include "osdep.h"
  430.34 +#include <ctype.h>
  430.35 +#include <stdio.h>
  430.36 +#include <sys/stat.h>
  430.37 +#include <sys/time.h>
  430.38 +#include <time.h>
  430.39 +#include <sys/socket.h>
  430.40 +#include <netinet/in.h>
  430.41 +#include <arpa/inet.h>
  430.42 +#include <netdb.h>
  430.43 +#include <errno.h>
  430.44 +#include <pwd.h>
  430.45 +#include "misc.h"
  430.46 +
  430.47 +
  430.48 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  430.49 +#define toint(c)       ((c)-'0')
  430.50 +
  430.51 +extern char *sys_errlist[];
  430.52 +extern int sys_nerr;
  430.53 +
  430.54 +#include "fs_unix.c"
  430.55 +#include "ftl_unix.c"
  430.56 +#include "nl_unix.c"
  430.57 +#include "env_unix.c"
  430.58 +#include "tcp_unix.c"
  430.59 +#include "gr_wait.c"
  430.60 +#include "flocksim.c"
  430.61 +#include "strerror.c"
  430.62 +#include "strtoul.c"
  430.63 +#include "strpbrk.c"		/* the A/UX version is bogus! */
  430.64 +#include "memmove.c"
  430.65 +#include "tz_sv4.c"
   431.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   431.2 +++ b/src/osdep/unix/os_aux.h	Mon Sep 14 15:17:45 2009 +0900
   431.3 @@ -0,0 +1,51 @@
   431.4 +/* ========================================================================
   431.5 + * Copyright 1988-2006 University of Washington
   431.6 + *
   431.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   431.8 + * you may not use this file except in compliance with the License.
   431.9 + * You may obtain a copy of the License at
  431.10 + *
  431.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  431.12 + *
  431.13 + * 
  431.14 + * ========================================================================
  431.15 + */
  431.16 +
  431.17 +/*
  431.18 + * Program:	Operating-system dependent routines -- A/UX version
  431.19 + *
  431.20 + * Author:	Mark Crispin
  431.21 + *		Networks and Distributed Computing
  431.22 + *		Computing & Communications
  431.23 + *		University of Washington
  431.24 + *		Administration Building, AG-44
  431.25 + *		Seattle, WA  98195
  431.26 + *		Internet: MRC@CAC.Washington.EDU
  431.27 + *
  431.28 + * Date:	11 May 1989
  431.29 + * Last Edited:	30 August 2006
  431.30 + */
  431.31 +
  431.32 +
  431.33 +#include <sys/types.h>
  431.34 +#include <sys/dir.h>
  431.35 +#include <stdlib.h>
  431.36 +#include <strings.h>
  431.37 +#include <time.h>
  431.38 +#include <sys/file.h>
  431.39 +#include <fcntl.h>
  431.40 +#include <syslog.h>
  431.41 +
  431.42 +
  431.43 +extern int errno;
  431.44 +
  431.45 +char *strerror (int n);
  431.46 +unsigned long strtoul (char *s,char **endp,int base);
  431.47 +void *memmove (void *s,void *ct,size_t n);
  431.48 +
  431.49 +#include "env_unix.h"
  431.50 +#include "fs.h"
  431.51 +#include "ftl.h"
  431.52 +#include "nl.h"
  431.53 +#include "tcp.h"
  431.54 +#include "flocksim.h"
   432.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   432.2 +++ b/src/osdep/unix/os_bsd.c	Mon Sep 14 15:17:45 2009 +0900
   432.3 @@ -0,0 +1,63 @@
   432.4 +/* ========================================================================
   432.5 + * Copyright 1988-2007 University of Washington
   432.6 + *
   432.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   432.8 + * you may not use this file except in compliance with the License.
   432.9 + * You may obtain a copy of the License at
  432.10 + *
  432.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  432.12 + *
  432.13 + * 
  432.14 + * ========================================================================
  432.15 + */
  432.16 +
  432.17 +/*
  432.18 + * Program:	Operating-system dependent routines -- 4.3BSD version
  432.19 + *
  432.20 + * Author:	Mark Crispin
  432.21 + *		Networks and Distributed Computing
  432.22 + *		Computing & Communications
  432.23 + *		University of Washington
  432.24 + *		Administration Building, AG-44
  432.25 + *		Seattle, WA  98195
  432.26 + *
  432.27 + * Date:	11 May 1989
  432.28 + * Last Edited:	16 August 2007
  432.29 + */
  432.30 +
  432.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  432.32 +#include "mail.h"
  432.33 +#include "osdep.h"
  432.34 +#include <stdio.h>
  432.35 +#include <sys/stat.h>
  432.36 +#include <sys/time.h>
  432.37 +#include <sys/socket.h>
  432.38 +#include <netinet/in.h>
  432.39 +#include <arpa/inet.h>
  432.40 +#include <netdb.h>
  432.41 +#include <ctype.h>
  432.42 +#include <errno.h>
  432.43 +extern int errno;		/* just in case */
  432.44 +#include <pwd.h>
  432.45 +#include "misc.h"
  432.46 +
  432.47 +
  432.48 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  432.49 +#define toint(c)       ((c)-'0')
  432.50 +
  432.51 +extern int sys_nerr;
  432.52 +extern char *sys_errlist[];
  432.53 +
  432.54 +
  432.55 +#include "fs_unix.c"
  432.56 +#include "ftl_unix.c"
  432.57 +#include "nl_unix.c"
  432.58 +#include "env_unix.c"
  432.59 +#define fork vfork
  432.60 +#include "tcp_unix.c"
  432.61 +#include "gr_wait.c"
  432.62 +#include "memmove.c"
  432.63 +#include "strerror.c"
  432.64 +#include "strstr.c"
  432.65 +#include "strtoul.c"
  432.66 +#include "tz_bsd.c"
   433.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   433.2 +++ b/src/osdep/unix/os_bsd.h	Mon Sep 14 15:17:45 2009 +0900
   433.3 @@ -0,0 +1,51 @@
   433.4 +/* ========================================================================
   433.5 + * Copyright 1988-2006 University of Washington
   433.6 + *
   433.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   433.8 + * you may not use this file except in compliance with the License.
   433.9 + * You may obtain a copy of the License at
  433.10 + *
  433.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  433.12 + *
  433.13 + * 
  433.14 + * ========================================================================
  433.15 + */
  433.16 +
  433.17 +/*
  433.18 + * Program:	Operating-system dependent routines -- 4.3BSD version
  433.19 + *
  433.20 + * Author:	Mark Crispin
  433.21 + *		Networks and Distributed Computing
  433.22 + *		Computing & Communications
  433.23 + *		University of Washington
  433.24 + *		Administration Building, AG-44
  433.25 + *		Seattle, WA  98195
  433.26 + *		Internet: MRC@CAC.Washington.EDU
  433.27 + *
  433.28 + * Date:	11 May 1989
  433.29 + * Last Edited:	30 August 2006
  433.30 + */
  433.31 +
  433.32 +#include <string.h>
  433.33 +#include <sys/types.h>
  433.34 +#include <sys/dir.h>
  433.35 +#include <fcntl.h>
  433.36 +#include <syslog.h>
  433.37 +#include <sys/file.h>
  433.38 +#include <machine/endian.h>	/* needed for htons() prototypes */
  433.39 +
  433.40 +
  433.41 +char *getenv (char *name);
  433.42 +char *strstr (char *cs,char *ct);
  433.43 +char *strerror (int n);
  433.44 +void *memmove (void *s,void *ct,size_t n);
  433.45 +unsigned long strtoul (char *s,char **endp,int base);
  433.46 +void *malloc (size_t byteSize);
  433.47 +void free (void *ptr);
  433.48 +void *realloc (void *oldptr,size_t newsize);
  433.49 +
  433.50 +#include "env_unix.h"
  433.51 +#include "fs.h"
  433.52 +#include "ftl.h"
  433.53 +#include "nl.h"
  433.54 +#include "tcp.h"
   434.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   434.2 +++ b/src/osdep/unix/os_bsf.c	Mon Sep 14 15:17:45 2009 +0900
   434.3 @@ -0,0 +1,54 @@
   434.4 +/* ========================================================================
   434.5 + * Copyright 1988-2007 University of Washington
   434.6 + *
   434.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   434.8 + * you may not use this file except in compliance with the License.
   434.9 + * You may obtain a copy of the License at
  434.10 + *
  434.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  434.12 + *
  434.13 + * 
  434.14 + * ========================================================================
  434.15 + */
  434.16 +
  434.17 +/*
  434.18 + * Program:	Operating-system dependent routines -- BSDI BSD/386 version
  434.19 + *
  434.20 + * Author:	Mark Crispin
  434.21 + *		Networks and Distributed Computing
  434.22 + *		Computing & Communications
  434.23 + *		University of Washington
  434.24 + *		Administration Building, AG-44
  434.25 + *		Seattle, WA  98195
  434.26 + *		Internet: MRC@CAC.Washington.EDU
  434.27 + *
  434.28 + * Date:	1 August 1988
  434.29 + * Last Edited:	16 August 2007
  434.30 + */
  434.31 + 
  434.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  434.33 +#include "mail.h"
  434.34 +#include "osdep.h"
  434.35 +#include <stdio.h>
  434.36 +#include <sys/time.h>
  434.37 +#include <sys/stat.h>
  434.38 +#include <sys/socket.h>
  434.39 +#include <netinet/in.h>
  434.40 +#include <arpa/inet.h>
  434.41 +#include <netdb.h>
  434.42 +#include <ctype.h>
  434.43 +#include <errno.h>
  434.44 +extern int errno;		/* just in case */
  434.45 +#include <pwd.h>
  434.46 +#include "misc.h"
  434.47 +
  434.48 +
  434.49 +#include "fs_unix.c"
  434.50 +#include "ftl_unix.c"
  434.51 +#include "nl_unix.c"
  434.52 +#include "env_unix.c"
  434.53 +#include "getspnam.c"
  434.54 +#define fork vfork
  434.55 +#include "tcp_unix.c"
  434.56 +#include "gr_waitp.c"
  434.57 +#include "tz_bsd.c"
   435.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   435.2 +++ b/src/osdep/unix/os_bsf.h	Mon Sep 14 15:17:45 2009 +0900
   435.3 @@ -0,0 +1,46 @@
   435.4 +/* ========================================================================
   435.5 + * Copyright 1988-2006 University of Washington
   435.6 + *
   435.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   435.8 + * you may not use this file except in compliance with the License.
   435.9 + * You may obtain a copy of the License at
  435.10 + *
  435.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  435.12 + *
  435.13 + * 
  435.14 + * ========================================================================
  435.15 + */
  435.16 +
  435.17 +/*
  435.18 + * Program:	Operating-system dependent routines -- FreeBSD version
  435.19 + *
  435.20 + * Author:	Mark Crispin
  435.21 + *		Networks and Distributed Computing
  435.22 + *		Computing & Communications
  435.23 + *		University of Washington
  435.24 + *		Administration Building, AG-44
  435.25 + *		Seattle, WA  98195
  435.26 + *		Internet: MRC@CAC.Washington.EDU
  435.27 + *
  435.28 + * Date:	5 March 1993
  435.29 + * Last Edited:	30 August 2006
  435.30 + */
  435.31 +
  435.32 +#include <stdlib.h>
  435.33 +#include <unistd.h>
  435.34 +#include <string.h>
  435.35 +#include <sys/types.h>
  435.36 +#include <dirent.h>
  435.37 +#include <fcntl.h>
  435.38 +#include <syslog.h>
  435.39 +#include <sys/file.h>
  435.40 +
  435.41 +
  435.42 +#define direct dirent
  435.43 +
  435.44 +
  435.45 +#include "env_unix.h"
  435.46 +#include "fs.h"
  435.47 +#include "ftl.h"
  435.48 +#include "nl.h"
  435.49 +#include "tcp.h"
   436.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   436.2 +++ b/src/osdep/unix/os_bsi.c	Mon Sep 14 15:17:45 2009 +0900
   436.3 @@ -0,0 +1,54 @@
   436.4 +/* ========================================================================
   436.5 + * Copyright 1988-2007 University of Washington
   436.6 + *
   436.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   436.8 + * you may not use this file except in compliance with the License.
   436.9 + * You may obtain a copy of the License at
  436.10 + *
  436.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  436.12 + *
  436.13 + * 
  436.14 + * ========================================================================
  436.15 + */
  436.16 +
  436.17 +/*
  436.18 + * Program:	Operating-system dependent routines -- BSDI BSD/386 version
  436.19 + *
  436.20 + * Author:	Mark Crispin
  436.21 + *		Networks and Distributed Computing
  436.22 + *		Computing & Communications
  436.23 + *		University of Washington
  436.24 + *		Administration Building, AG-44
  436.25 + *		Seattle, WA  98195
  436.26 + *		Internet: MRC@CAC.Washington.EDU
  436.27 + *
  436.28 + * Date:	1 August 1988
  436.29 + * Last Edited:	16 August 2007
  436.30 + */
  436.31 + 
  436.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  436.33 +#include "mail.h"
  436.34 +#include "osdep.h"
  436.35 +#include <stdio.h>
  436.36 +#include <sys/time.h>
  436.37 +#include <sys/stat.h>
  436.38 +#include <sys/socket.h>
  436.39 +#include <netinet/in.h>
  436.40 +#include <arpa/inet.h>
  436.41 +#include <netdb.h>
  436.42 +#include <ctype.h>
  436.43 +#include <errno.h>
  436.44 +extern int errno;		/* just in case */
  436.45 +#include <pwd.h>
  436.46 +#include "misc.h"
  436.47 +
  436.48 +
  436.49 +#include "fs_unix.c"
  436.50 +#include "ftl_unix.c"
  436.51 +#include "nl_unix.c"
  436.52 +#include "env_unix.c"
  436.53 +#include "getspnam.c"
  436.54 +#define fork vfork
  436.55 +#include "tcp_unix.c"
  436.56 +#include "gr_waitp.c"
  436.57 +#include "tz_bsd.c"
   437.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   437.2 +++ b/src/osdep/unix/os_bsi.h	Mon Sep 14 15:17:45 2009 +0900
   437.3 @@ -0,0 +1,43 @@
   437.4 +/* ========================================================================
   437.5 + * Copyright 1988-2006 University of Washington
   437.6 + *
   437.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   437.8 + * you may not use this file except in compliance with the License.
   437.9 + * You may obtain a copy of the License at
  437.10 + *
  437.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  437.12 + *
  437.13 + * 
  437.14 + * ========================================================================
  437.15 + */
  437.16 +
  437.17 +/*
  437.18 + * Program:	Operating-system dependent routines -- BSDI BSD/386 version
  437.19 + *
  437.20 + * Author:	Mark Crispin
  437.21 + *		Networks and Distributed Computing
  437.22 + *		Computing & Communications
  437.23 + *		University of Washington
  437.24 + *		Administration Building, AG-44
  437.25 + *		Seattle, WA  98195
  437.26 + *		Internet: MRC@CAC.Washington.EDU
  437.27 + *
  437.28 + * Date:	5 March 1993
  437.29 + * Last Edited:	30 August 2006
  437.30 + */
  437.31 +
  437.32 +#include <stdlib.h>
  437.33 +#include <unistd.h>
  437.34 +#include <string.h>
  437.35 +#include <sys/types.h>
  437.36 +#include <sys/dir.h>
  437.37 +#include <fcntl.h>
  437.38 +#include <syslog.h>
  437.39 +#include <sys/file.h>
  437.40 +
  437.41 +
  437.42 +#include "env_unix.h"
  437.43 +#include "fs.h"
  437.44 +#include "ftl.h"
  437.45 +#include "nl.h"
  437.46 +#include "tcp.h"
   438.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   438.2 +++ b/src/osdep/unix/os_cvx.c	Mon Sep 14 15:17:45 2009 +0900
   438.3 @@ -0,0 +1,57 @@
   438.4 +/* ========================================================================
   438.5 + * Copyright 1988-2007 University of Washington
   438.6 + *
   438.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   438.8 + * you may not use this file except in compliance with the License.
   438.9 + * You may obtain a copy of the License at
  438.10 + *
  438.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  438.12 + *
  438.13 + * 
  438.14 + * ========================================================================
  438.15 + */
  438.16 +
  438.17 +/*
  438.18 + * Program:	Operating-system dependent routines -- Convex version
  438.19 + *
  438.20 + * Author:	Mark Crispin
  438.21 + *		Networks and Distributed Computing
  438.22 + *		Computing & Communications
  438.23 + *		University of Washington
  438.24 + *		Administration Building, AG-44
  438.25 + *		Seattle, WA  98195
  438.26 + *
  438.27 + * Date:	11 May 1989
  438.28 + * Last Edited:	16 August 2007
  438.29 + */
  438.30 +
  438.31 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  438.32 +#define toint(c)       ((c)-'0')
  438.33 +
  438.34 +#include <stdio.h>
  438.35 +
  438.36 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  438.37 +#include "mail.h"
  438.38 +#include "osdep.h"
  438.39 +#include <stdio.h>
  438.40 +#include <sys/stat.h>
  438.41 +#include <sys/time.h>
  438.42 +#include <sys/socket.h>
  438.43 +#include <netinet/in.h>
  438.44 +#include <arpa/inet.h>
  438.45 +#include <netdb.h>
  438.46 +#include <ctype.h>
  438.47 +#include <errno.h>
  438.48 +extern int errno;		/* just in case */
  438.49 +#include <pwd.h>
  438.50 +#include "misc.h"
  438.51 +
  438.52 +
  438.53 +#include "fs_unix.c"
  438.54 +#include "ftl_unix.c"
  438.55 +#include "nl_unix.c"
  438.56 +#include "env_unix.c"
  438.57 +#define fork vfork
  438.58 +#include "tcp_unix.c"
  438.59 +#include "gr_wait.c"
  438.60 +#include "tz_nul.c"
   439.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   439.2 +++ b/src/osdep/unix/os_cvx.h	Mon Sep 14 15:17:45 2009 +0900
   439.3 @@ -0,0 +1,45 @@
   439.4 +/* ========================================================================
   439.5 + * Copyright 1988-2006 University of Washington
   439.6 + *
   439.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   439.8 + * you may not use this file except in compliance with the License.
   439.9 + * You may obtain a copy of the License at
  439.10 + *
  439.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  439.12 + *
  439.13 + * 
  439.14 + * ========================================================================
  439.15 + */
  439.16 +
  439.17 +/*
  439.18 + * Program:	Operating-system dependent routines -- Convex version
  439.19 + *
  439.20 + * Author:	Mark Crispin
  439.21 + *		Networks and Distributed Computing
  439.22 + *		Computing & Communications
  439.23 + *		University of Washington
  439.24 + *		Administration Building, AG-44
  439.25 + *		Seattle, WA  98195
  439.26 + *		Internet: MRC@CAC.Washington.EDU
  439.27 + *
  439.28 + * Date:	11 May 1989
  439.29 + * Last Edited:	30 August 2006
  439.30 + */
  439.31 +
  439.32 +#include <string.h>
  439.33 +#include <sys/types.h>
  439.34 +#include <sys/dir.h>
  439.35 +#include <sys/timeb.h>
  439.36 +#include <fcntl.h>
  439.37 +#include <syslog.h>
  439.38 +#include <sys/file.h>
  439.39 +
  439.40 +
  439.41 +void *malloc (size_t byteSize);
  439.42 +void *realloc (void *oldptr,size_t newsize);
  439.43 +
  439.44 +#include "env_unix.h"
  439.45 +#include "fs.h"
  439.46 +#include "ftl.h"
  439.47 +#include "nl.h"
  439.48 +#include "tcp.h"
   440.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   440.2 +++ b/src/osdep/unix/os_cyg.c	Mon Sep 14 15:17:45 2009 +0900
   440.3 @@ -0,0 +1,71 @@
   440.4 +/* ========================================================================
   440.5 + * Copyright 1988-2006 University of Washington
   440.6 + *
   440.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   440.8 + * you may not use this file except in compliance with the License.
   440.9 + * You may obtain a copy of the License at
  440.10 + *
  440.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  440.12 + *
  440.13 + * 
  440.14 + * ========================================================================
  440.15 + */
  440.16 +
  440.17 +/*
  440.18 + * Program:	Operating-system dependent routines -- Cygwin version
  440.19 + *
  440.20 + * Author:	Mark Crispin
  440.21 + *		Networks and Distributed Computing
  440.22 + *		Computing & Communications
  440.23 + *		University of Washington
  440.24 + *		Administration Building, AG-44
  440.25 + *		Seattle, WA  98195
  440.26 + *		Internet: MRC@CAC.Washington.EDU
  440.27 + *
  440.28 + * Date:	1 August 1988
  440.29 + * Last Edited:	30 August 2006
  440.30 + */
  440.31 + 
  440.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  440.33 +#include "mail.h"
  440.34 +#include "osdep.h"
  440.35 +#include <stdio.h>
  440.36 +#include <sys/stat.h>
  440.37 +#include <sys/time.h>
  440.38 +#include <sys/socket.h>
  440.39 +#include <netinet/in.h>
  440.40 +#include <arpa/inet.h>
  440.41 +#include <netdb.h>
  440.42 +#include <ctype.h>
  440.43 +#include <errno.h>
  440.44 +extern int errno;		/* just in case */
  440.45 +#include <pwd.h>
  440.46 +#include <crypt.h>
  440.47 +#include "misc.h"
  440.48 +
  440.49 +
  440.50 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  440.51 +#define toint(c)       ((c)-'0')
  440.52 +
  440.53 +#include "fs_unix.c"
  440.54 +#include "ftl_unix.c"
  440.55 +#include "nl_unix.c"
  440.56 +#include "env_unix.c"
  440.57 +#include "tcp_unix.c"
  440.58 +#include "gr_wait.c"
  440.59 +#include "tz_nul.c"
  440.60 +#include "flockcyg.c"
  440.61 +#include "gethstid.c"
  440.62 +
  440.63 +
  440.64 +/* Emulator for geteuid() call
  440.65 + * Returns: effective UID
  440.66 + */
  440.67 +
  440.68 +#undef geteuid
  440.69 +
  440.70 +uid_t Geteuid (void)
  440.71 +{
  440.72 +  uid_t ret = geteuid ();
  440.73 +  return (ret == SYSTEMUID) ? 0 : ret;
  440.74 +}
   441.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   441.2 +++ b/src/osdep/unix/os_cyg.h	Mon Sep 14 15:17:45 2009 +0900
   441.3 @@ -0,0 +1,71 @@
   441.4 +/* ========================================================================
   441.5 + * Copyright 1988-2006 University of Washington
   441.6 + *
   441.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   441.8 + * you may not use this file except in compliance with the License.
   441.9 + * You may obtain a copy of the License at
  441.10 + *
  441.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  441.12 + *
  441.13 + * 
  441.14 + * ========================================================================
  441.15 + */
  441.16 +
  441.17 +/*
  441.18 + * Program:	Operating-system dependent routines -- Cygwin version
  441.19 + *
  441.20 + * Author:	Mark Crispin
  441.21 + *		Networks and Distributed Computing
  441.22 + *		Computing & Communications
  441.23 + *		University of Washington
  441.24 + *		Administration Building, AG-44
  441.25 + *		Seattle, WA  98195
  441.26 + *		Internet: MRC@CAC.Washington.EDU
  441.27 + *
  441.28 + * Date:	1 August 1988
  441.29 + * Last Edited:	30 August 2006
  441.30 + */
  441.31 +
  441.32 +#include <string.h>
  441.33 +#include <stdlib.h>
  441.34 +#include <unistd.h>
  441.35 +#include <sys/types.h>
  441.36 +#include <dirent.h>
  441.37 +#include <fcntl.h>
  441.38 +#include <syslog.h>
  441.39 +#include <sys/file.h>
  441.40 +#include <time.h>
  441.41 +#include <sys/time.h>
  441.42 +
  441.43 +#define direct dirent
  441.44 +
  441.45 +
  441.46 +#define CYGKLUDGEOFFSET 1	/* don't write 1st byte of shared-lock files */
  441.47 +
  441.48 +/* Cygwin gets this wrong */
  441.49 +
  441.50 +#define setpgrp setpgid
  441.51 +
  441.52 +#define SYSTEMUID 18		/* Cygwin returns this for SYSTEM */
  441.53 +#define geteuid Geteuid
  441.54 +uid_t Geteuid (void);
  441.55 +
  441.56 +/* Now Cygwin has reportedly joined this madness.  Use ifndef in case it shares
  441.57 +   the SVR4 <sys/file.h> silliness too */
  441.58 +#ifndef L_SET
  441.59 +#define L_SET SEEK_SET
  441.60 +#endif
  441.61 +#ifndef L_INCR
  441.62 +#define L_INCR SEEK_CUR
  441.63 +#endif
  441.64 +#ifndef L_XTND
  441.65 +#define L_XTND SEEK_END
  441.66 +#endif
  441.67 +
  441.68 +
  441.69 +#include "env_unix.h"
  441.70 +#include "fs.h"
  441.71 +#include "ftl.h"
  441.72 +#include "nl.h"
  441.73 +#include "tcp.h"
  441.74 +#include "flockcyg.h"
   442.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   442.2 +++ b/src/osdep/unix/os_d-g.c	Mon Sep 14 15:17:45 2009 +0900
   442.3 @@ -0,0 +1,54 @@
   442.4 +/* ========================================================================
   442.5 + * Copyright 1988-2006 University of Washington
   442.6 + *
   442.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   442.8 + * you may not use this file except in compliance with the License.
   442.9 + * You may obtain a copy of the License at
  442.10 + *
  442.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  442.12 + *
  442.13 + * 
  442.14 + * ========================================================================
  442.15 + */
  442.16 +
  442.17 +/*
  442.18 + * Program:	Operating-system dependent routines -- D-G version
  442.19 + *
  442.20 + * Author:	Mark Crispin
  442.21 + *		Networks and Distributed Computing
  442.22 + *		Computing & Communications
  442.23 + *		University of Washington
  442.24 + *		Administration Building, AG-44
  442.25 + *		Seattle, WA  98195
  442.26 + *		Internet: MRC@CAC.Washington.EDU
  442.27 + *
  442.28 + * Date:	1 August 1988
  442.29 + * Last Edited:	30 August 2006
  442.30 + */
  442.31 + 
  442.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  442.33 +#include "mail.h"
  442.34 +#include "osdep.h"
  442.35 +#include <stdio.h>
  442.36 +#include <sys/time.h>
  442.37 +#include <sys/stat.h>
  442.38 +#include <sys/socket.h>
  442.39 +#include <netinet/in.h>
  442.40 +#include <arpa/inet.h>
  442.41 +#include <netdb.h>
  442.42 +#include <ctype.h>
  442.43 +#include <errno.h>
  442.44 +extern int errno;		/* just in case */
  442.45 +#include <pwd.h>
  442.46 +#include "misc.h"
  442.47 +
  442.48 +
  442.49 +#include "fs_unix.c"
  442.50 +#include "ftl_unix.c"
  442.51 +#include "nl_unix.c"
  442.52 +#include "env_unix.c"
  442.53 +#include "tcp_unix.c"
  442.54 +#include "gr_waitp.c"
  442.55 +#include "tz_sv4.c"
  442.56 +#include "flocksim.c"
  442.57 +#include "utime.c"
   443.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   443.2 +++ b/src/osdep/unix/os_d-g.h	Mon Sep 14 15:17:45 2009 +0900
   443.3 @@ -0,0 +1,56 @@
   443.4 +/* ========================================================================
   443.5 + * Copyright 1988-2006 University of Washington
   443.6 + *
   443.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   443.8 + * you may not use this file except in compliance with the License.
   443.9 + * You may obtain a copy of the License at
  443.10 + *
  443.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  443.12 + *
  443.13 + * 
  443.14 + * ========================================================================
  443.15 + */
  443.16 +
  443.17 +/*
  443.18 + * Program:	Operating-system dependent routines -- D-G version
  443.19 + *
  443.20 + * Author:	Mark Crispin
  443.21 + *		Networks and Distributed Computing
  443.22 + *		Computing & Communications
  443.23 + *		University of Washington
  443.24 + *		Administration Building, AG-44
  443.25 + *		Seattle, WA  98195
  443.26 + *		Internet: MRC@CAC.Washington.EDU
  443.27 + *
  443.28 + * Date:	1 August 1988
  443.29 + * Last Edited:	30 August 2006
  443.30 + */
  443.31 +
  443.32 +#include <stdlib.h>
  443.33 +#include <unistd.h>
  443.34 +#include <string.h>
  443.35 +#include <sys/types.h>
  443.36 +#include <dirent.h>
  443.37 +#include <sys/dir.h>
  443.38 +#include <time.h>		/* for struct tm */
  443.39 +#include <fcntl.h>
  443.40 +#define _USEC_UTIME_FLAVOR	/* break it for compatibility with */
  443.41 +#include <utime.h>		/*  the incompatible past */
  443.42 +#include <syslog.h>
  443.43 +#include <sys/file.h>
  443.44 +
  443.45 +
  443.46 +/* D-G gets this wrong */
  443.47 +
  443.48 +#define setpgrp setpgrp2
  443.49 +
  443.50 +
  443.51 +#define utime portable_utime
  443.52 +int portable_utime (char *file,time_t timep[2]);
  443.53 +
  443.54 +#include "env_unix.h"
  443.55 +#include "fs.h"
  443.56 +#include "ftl.h"
  443.57 +#include "nl.h"
  443.58 +#include "tcp.h"
  443.59 +#include "flocksim.h"
   444.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   444.2 +++ b/src/osdep/unix/os_do4.c	Mon Sep 14 15:17:45 2009 +0900
   444.3 @@ -0,0 +1,58 @@
   444.4 +/* ========================================================================
   444.5 + * Copyright 1988-2007 University of Washington
   444.6 + *
   444.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   444.8 + * you may not use this file except in compliance with the License.
   444.9 + * You may obtain a copy of the License at
  444.10 + *
  444.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  444.12 + *
  444.13 + * 
  444.14 + * ========================================================================
  444.15 + */
  444.16 +
  444.17 +/*
  444.18 + * Program:	Operating-system dependent routines -- Apollo Domain/OS sr10.4
  444.19 + *
  444.20 + * Author:	Mark Crispin
  444.21 + *		Networks and Distributed Computing
  444.22 + *		Computing & Communications
  444.23 + *		University of Washington
  444.24 + *		Administration Building, AG-44
  444.25 + *		Seattle, WA  98195
  444.26 + *
  444.27 + * Date:	11 May 1989
  444.28 + * Last Edited:	16 August 2007
  444.29 + */
  444.30 +
  444.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  444.32 +#include "mail.h"
  444.33 +#include "osdep.h"
  444.34 +#include <stdio.h>
  444.35 +#include <sys/stat.h>
  444.36 +#include <sys/time.h>
  444.37 +#include <sys/socket.h>
  444.38 +#include <arpa/inet.h>
  444.39 +#include <netdb.h>
  444.40 +#include <ctype.h>
  444.41 +#include <errno.h>
  444.42 +extern int errno;		/* just in case */
  444.43 +#include <pwd.h>
  444.44 +#include "misc.h"
  444.45 +
  444.46 +
  444.47 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  444.48 +#define toint(c)       ((c)-'0')
  444.49 +
  444.50 +extern int sys_nerr;
  444.51 +extern char *sys_errlist[];
  444.52 +
  444.53 +
  444.54 +#include "fs_unix.c"
  444.55 +#include "ftl_unix.c"
  444.56 +#include "nl_unix.c"
  444.57 +#include "env_unix.c"
  444.58 +#define fork vfork
  444.59 +#include "tcp_unix.c"
  444.60 +#include "gr_waitp.c"
  444.61 +#include "tz_sv4.c"
   445.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   445.2 +++ b/src/osdep/unix/os_do4.h	Mon Sep 14 15:17:45 2009 +0900
   445.3 @@ -0,0 +1,47 @@
   445.4 +/* ========================================================================
   445.5 + * Copyright 1988-2006 University of Washington
   445.6 + *
   445.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   445.8 + * you may not use this file except in compliance with the License.
   445.9 + * You may obtain a copy of the License at
  445.10 + *
  445.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  445.12 + *
  445.13 + * 
  445.14 + * ========================================================================
  445.15 + */
  445.16 +
  445.17 +/*
  445.18 + * Program:	Operating-system dependent routines -- Apollo Domain/OS sr10.4
  445.19 + *
  445.20 + * Author:	Mark Crispin
  445.21 + *		Networks and Distributed Computing
  445.22 + *		Computing & Communications
  445.23 + *		University of Washington
  445.24 + *		Administration Building, AG-44
  445.25 + *		Seattle, WA  98195
  445.26 + *		Internet: MRC@CAC.Washington.EDU
  445.27 + *
  445.28 + * Date:	11 May 1989
  445.29 + * Last Edited:	30 August 2006
  445.30 + */
  445.31 +
  445.32 +#include <string.h>
  445.33 +#include <sys/types.h>
  445.34 +#include <stdlib.h>
  445.35 +#include <sys/dir.h>
  445.36 +#include <fcntl.h>
  445.37 +#include <syslog.h>
  445.38 +#include <sys/file.h>
  445.39 +#ifndef htons
  445.40 +#include <netinet/in.h>		/* needed for htons() prototypes */
  445.41 +#endif
  445.42 +
  445.43 +extern int daylight;		/* local timzone uses daylight savings time */
  445.44 +extern long altzone;		/* seconds west of UTC during daylight time */
  445.45 +
  445.46 +#include "env_unix.h"
  445.47 +#include "fs.h"
  445.48 +#include "ftl.h"
  445.49 +#include "nl.h"
  445.50 +#include "tcp.h"
   446.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   446.2 +++ b/src/osdep/unix/os_drs.c	Mon Sep 14 15:17:45 2009 +0900
   446.3 @@ -0,0 +1,57 @@
   446.4 +/* ========================================================================
   446.5 + * Copyright 1988-2006 University of Washington
   446.6 + *
   446.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   446.8 + * you may not use this file except in compliance with the License.
   446.9 + * You may obtain a copy of the License at
  446.10 + *
  446.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  446.12 + *
  446.13 + * 
  446.14 + * ========================================================================
  446.15 + */
  446.16 +
  446.17 +/*
  446.18 + * Program:	Operating-system dependent routines -- ICL DRS/NX
  446.19 + *
  446.20 + * Author:	Mark Crispin
  446.21 + *		Networks and Distributed Computing
  446.22 + *		Computing & Communications
  446.23 + *		University of Washington
  446.24 + *		Administration Building, AG-44
  446.25 + *		Seattle, WA  98195
  446.26 + *		Internet: MRC@CAC.Washington.EDU
  446.27 + *
  446.28 + * Date:	1 August 1988
  446.29 + * Last Edited:	30 August 2006
  446.30 + */
  446.31 + 
  446.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  446.33 +#include "mail.h"
  446.34 +#include "osdep.h"
  446.35 +#include <stdio.h>
  446.36 +#include <sys/time.h>
  446.37 +#include <sys/socket.h>
  446.38 +#include <sys/stat.h>
  446.39 +#include <netinet/in.h>
  446.40 +#include <arpa/inet.h>
  446.41 +#include <netdb.h>
  446.42 +#include <ctype.h>
  446.43 +#include <errno.h>
  446.44 +extern int errno;		/* just in case */
  446.45 +#include <pwd.h>
  446.46 +#include "misc.h"
  446.47 +
  446.48 +char *crypt (char *key,char *salt);
  446.49 +
  446.50 +#define DIR_SIZE(d) d->d_reclen
  446.51 +
  446.52 +#include "fs_unix.c"
  446.53 +#include "ftl_unix.c"
  446.54 +#include "nl_unix.c"
  446.55 +#include "env_unix.c"
  446.56 +#include "tcp_unix.c"
  446.57 +#include "gr_waitp.c"
  446.58 +#include "tz_sv4.c"
  446.59 +#include "flocksim.c"
  446.60 +#include "scandir.c"
   447.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   447.2 +++ b/src/osdep/unix/os_drs.h	Mon Sep 14 15:17:45 2009 +0900
   447.3 @@ -0,0 +1,59 @@
   447.4 +/* ========================================================================
   447.5 + * Copyright 1988-2006 University of Washington
   447.6 + *
   447.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   447.8 + * you may not use this file except in compliance with the License.
   447.9 + * You may obtain a copy of the License at
  447.10 + *
  447.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  447.12 + *
  447.13 + * 
  447.14 + * ========================================================================
  447.15 + */
  447.16 +
  447.17 +/*
  447.18 + * Program:	Operating-system dependent routines -- ICL DRS/NX version
  447.19 + *
  447.20 + * Author:	Mark Crispin
  447.21 + *		Networks and Distributed Computing
  447.22 + *		Computing & Communications
  447.23 + *		University of Washington
  447.24 + *		Administration Building, AG-44
  447.25 + *		Seattle, WA  98195
  447.26 + *		Internet: MRC@CAC.Washington.EDU
  447.27 + *
  447.28 + * Date:	1 August 1988
  447.29 + * Last Edited:	15 September 2006
  447.30 + */
  447.31 +
  447.32 +#include <stdlib.h>
  447.33 +#include <unistd.h>
  447.34 +#include <string.h>
  447.35 +#include <sys/types.h>
  447.36 +#include <sys/dir.h>
  447.37 +#include <time.h>		/* for struct tm */
  447.38 +#include <dirent.h>
  447.39 +#include <fcntl.h>
  447.40 +#include <syslog.h>
  447.41 +#include <sys/file.h>
  447.42 +#include <ustat.h>
  447.43 +
  447.44 +
  447.45 +#define random rand
  447.46 +#define direct dirent
  447.47 +
  447.48 +
  447.49 +long gethostid (void);
  447.50 +typedef int (*select_t) (struct direct *name);
  447.51 +typedef int (*compar_t) (void *d1,void *d2);
  447.52 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  447.53 +	     compar_t compar);
  447.54 +int alphasort (void *d1,void *d2);
  447.55 +
  447.56 +
  447.57 +#include "env_unix.h"
  447.58 +#include "fs.h"
  447.59 +#include "ftl.h"
  447.60 +#include "nl.h"
  447.61 +#include "tcp.h"
  447.62 +#include "flocksim.h"
   448.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   448.2 +++ b/src/osdep/unix/os_dyn.c	Mon Sep 14 15:17:45 2009 +0900
   448.3 @@ -0,0 +1,64 @@
   448.4 +/* ========================================================================
   448.5 + * Copyright 1988-2007 University of Washington
   448.6 + *
   448.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   448.8 + * you may not use this file except in compliance with the License.
   448.9 + * You may obtain a copy of the License at
  448.10 + *
  448.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  448.12 + *
  448.13 + * 
  448.14 + * ========================================================================
  448.15 + */
  448.16 +
  448.17 +/*
  448.18 + * Program:	Operating-system dependent routines -- Dynix version
  448.19 + *
  448.20 + * Author:	Mark Crispin
  448.21 + *		Networks and Distributed Computing
  448.22 + *		Computing & Communications
  448.23 + *		University of Washington
  448.24 + *		Administration Building, AG-44
  448.25 + *		Seattle, WA  98195
  448.26 + *
  448.27 + * Date:	11 May 1989
  448.28 + * Last Edited:	16 August 2007
  448.29 + */
  448.30 +
  448.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  448.32 +#include "mail.h"
  448.33 +#include "osdep.h"
  448.34 +#include <ctype.h>
  448.35 +#include <stdio.h>
  448.36 +#include <sys/stat.h>
  448.37 +#include <sys/time.h>
  448.38 +#include <sys/socket.h>
  448.39 +#include <netinet/in.h>
  448.40 +#include <arpa/inet.h>
  448.41 +#include <netdb.h>
  448.42 +#include <errno.h>
  448.43 +extern int errno;		/* just in case */
  448.44 +#include <pwd.h>
  448.45 +#include "misc.h"
  448.46 +
  448.47 +extern int sys_nerr;
  448.48 +extern char *sys_errlist[];
  448.49 +
  448.50 +#define toint(c)	((c)-'0')
  448.51 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  448.52 +
  448.53 +
  448.54 +#include "fs_unix.c"
  448.55 +#include "ftl_unix.c"
  448.56 +#include "nl_unix.c"
  448.57 +#include "env_unix.c"
  448.58 +#define fork vfork
  448.59 +#include "tcp_unix.c"
  448.60 +#include "gr_wait.c"
  448.61 +#include "memmove.c"
  448.62 +#include "strerror.c"
  448.63 +#include "strpbrk.c"
  448.64 +#include "strstr.c"
  448.65 +#include "strtoul.c"
  448.66 +#include "strtok.c"
  448.67 +#include "tz_nul.c"
   449.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   449.2 +++ b/src/osdep/unix/os_dyn.h	Mon Sep 14 15:17:45 2009 +0900
   449.3 @@ -0,0 +1,61 @@
   449.4 +/* ========================================================================
   449.5 + * Copyright 1988-2007 University of Washington
   449.6 + *
   449.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   449.8 + * you may not use this file except in compliance with the License.
   449.9 + * You may obtain a copy of the License at
  449.10 + *
  449.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  449.12 + *
  449.13 + * 
  449.14 + * ========================================================================
  449.15 + */
  449.16 +
  449.17 +/*
  449.18 + * Program:	Operating-system dependent routines -- Dynix version
  449.19 + *
  449.20 + * Author:	Mark Crispin
  449.21 + *		Networks and Distributed Computing
  449.22 + *		Computing & Communications
  449.23 + *		University of Washington
  449.24 + *		Administration Building, AG-44
  449.25 + *		Seattle, WA  98195
  449.26 + *		Internet: MRC@CAC.Washington.EDU
  449.27 + *
  449.28 + * Date:	11 May 1989
  449.29 + * Last Edited:	30 January 2007
  449.30 + */
  449.31 +
  449.32 +#include <strings.h>
  449.33 +#include <sys/types.h>
  449.34 +#include <sys/dir.h>
  449.35 +#include <fcntl.h>
  449.36 +#include <syslog.h>
  449.37 +#include <sys/file.h>
  449.38 +
  449.39 +
  449.40 +typedef unsigned long size_t;
  449.41 +
  449.42 +char *strtok (char *s,char *ct);
  449.43 +char *strtok_r (char *s,char *ct,char **r);
  449.44 +char *strstr (char *cs,char *ct);
  449.45 +char *strpbrk (char *cs,char *ct);
  449.46 +char *strerror (int n);
  449.47 +void *memmove (void *s,void *ct,size_t n);
  449.48 +void *memset (void *s,int c,size_t n);
  449.49 +unsigned long strtoul (char *s,char **endp,int base);
  449.50 +void *malloc (size_t byteSize);
  449.51 +void free (void *ptr);
  449.52 +void *realloc (void *oldptr,size_t newsize);
  449.53 +
  449.54 +int errno;
  449.55 +
  449.56 +#define memcpy memmove
  449.57 +#define strchr index
  449.58 +#define strrchr rindex
  449.59 +
  449.60 +#include "env_unix.h"
  449.61 +#include "fs.h"
  449.62 +#include "ftl.h"
  449.63 +#include "nl.h"
  449.64 +#include "tcp.h"
   450.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   450.2 +++ b/src/osdep/unix/os_hpp.c	Mon Sep 14 15:17:45 2009 +0900
   450.3 @@ -0,0 +1,77 @@
   450.4 +/* ========================================================================
   450.5 + * Copyright 1988-2007 University of Washington
   450.6 + *
   450.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   450.8 + * you may not use this file except in compliance with the License.
   450.9 + * You may obtain a copy of the License at
  450.10 + *
  450.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  450.12 + *
  450.13 + * 
  450.14 + * ========================================================================
  450.15 + */
  450.16 +
  450.17 +/*
  450.18 + * Program:	Operating-system dependent routines -- HP/UX version
  450.19 + *
  450.20 + * Author:	Mark Crispin
  450.21 + *		Networks and Distributed Computing
  450.22 + *		Computing & Communications
  450.23 + *		University of Washington
  450.24 + *		Administration Building, AG-44
  450.25 + *		Seattle, WA  98195
  450.26 + *		Internet: MRC@CAC.Washington.EDU
  450.27 + *
  450.28 + * Date:	11 May 1989
  450.29 + * Last Edited:	16 August 2007
  450.30 + */
  450.31 +
  450.32 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  450.33 +#define toint(c)       ((c)-'0')
  450.34 +
  450.35 +#include <stdio.h>
  450.36 +
  450.37 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  450.38 +#include "mail.h"
  450.39 +#include "osdep.h"
  450.40 +#include <stdio.h>
  450.41 +#include <sys/stat.h>
  450.42 +#include <sys/time.h>
  450.43 +#include <sys/socket.h>
  450.44 +#include <sys/utsname.h>
  450.45 +#include <netinet/in.h>
  450.46 +#include <arpa/inet.h>
  450.47 +#include <netdb.h>
  450.48 +#include <ctype.h>
  450.49 +#include <errno.h>
  450.50 +extern int errno;		/* just in case */
  450.51 +extern char *sys_errlist[];
  450.52 +extern int sys_nerr;
  450.53 +#include <pwd.h>
  450.54 +#include "misc.h"
  450.55 +
  450.56 +
  450.57 +#include "fs_unix.c"
  450.58 +#include "ftl_unix.c"
  450.59 +#include "nl_unix.c"
  450.60 +#include "env_unix.c"
  450.61 +#define fork vfork
  450.62 +#include "tcp_unix.c"
  450.63 +#include "gr_waitp.c"
  450.64 +#include "flocksim.c"
  450.65 +#include "tz_sv4.c"
  450.66 +#undef setpgrp
  450.67 +#include "setpgrp.c"
  450.68 +#include "utime.c"
  450.69 +
  450.70 +/* Emulator for BSD gethostid() call
  450.71 + * Returns: a unique identifier for the system.  
  450.72 + * Even though HP/UX has an undocumented gethostid() system call,
  450.73 + * it does not work (at least for non-privileged users).  
  450.74 + */
  450.75 +
  450.76 +long gethostid (void)
  450.77 +{
  450.78 +  struct utsname udata;
  450.79 +  return (uname (&udata)) ? 0xfeedface : atol (udata.__idnumber);
  450.80 +}
   451.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   451.2 +++ b/src/osdep/unix/os_hpp.h	Mon Sep 14 15:17:45 2009 +0900
   451.3 @@ -0,0 +1,63 @@
   451.4 +/* ========================================================================
   451.5 + * Copyright 1988-2006 University of Washington
   451.6 + *
   451.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   451.8 + * you may not use this file except in compliance with the License.
   451.9 + * You may obtain a copy of the License at
  451.10 + *
  451.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  451.12 + *
  451.13 + * 
  451.14 + * ========================================================================
  451.15 + */
  451.16 +
  451.17 +/*
  451.18 + * Program:	Operating-system dependent routines -- HP/UX version
  451.19 + *
  451.20 + * Author:	Mark Crispin
  451.21 + *		Networks and Distributed Computing
  451.22 + *		Computing & Communications
  451.23 + *		University of Washington
  451.24 + *		Administration Building, AG-44
  451.25 + *		Seattle, WA  98195
  451.26 + *		Internet: MRC@CAC.Washington.EDU
  451.27 + *
  451.28 + * Date:	11 May 1989
  451.29 + * Last Edited:	20 December 2006
  451.30 + */
  451.31 +
  451.32 +#include <string.h>
  451.33 +
  451.34 +#include <sys/types.h>
  451.35 +#include <stdlib.h>
  451.36 +#include <dirent.h>
  451.37 +#include <fcntl.h>
  451.38 +#include <unistd.h>
  451.39 +#include <time.h>
  451.40 +#include <utime.h>
  451.41 +#include <syslog.h>
  451.42 +#include <sys/file.h>
  451.43 +#include <ustat.h>
  451.44 +
  451.45 +
  451.46 +#define direct dirent
  451.47 +#define random lrand48
  451.48 +
  451.49 +
  451.50 +/* Many versions of SysV get this wrong */
  451.51 +
  451.52 +#define setpgrp(a,b) Setpgrp(a,b)
  451.53 +int Setpgrp (int pid,int gid);
  451.54 +
  451.55 +
  451.56 +#define utime portable_utime
  451.57 +int portable_utime (char *file,time_t timep[2]);
  451.58 +
  451.59 +long gethostid (void);
  451.60 +
  451.61 +#include "env_unix.h"
  451.62 +#include "fs.h"
  451.63 +#include "ftl.h"
  451.64 +#include "nl.h"
  451.65 +#include "tcp.h"
  451.66 +#include "flocksim.h"
   452.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   452.2 +++ b/src/osdep/unix/os_isc.c	Mon Sep 14 15:17:45 2009 +0900
   452.3 @@ -0,0 +1,68 @@
   452.4 +/* ========================================================================
   452.5 + * Copyright 1988-2006 University of Washington
   452.6 + *
   452.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   452.8 + * you may not use this file except in compliance with the License.
   452.9 + * You may obtain a copy of the License at
  452.10 + *
  452.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  452.12 + *
  452.13 + * 
  452.14 + * ========================================================================
  452.15 + */
  452.16 +
  452.17 +/*
  452.18 + * Program:	Operating-system dependent routines -- ISC version
  452.19 + *
  452.20 + * Author:	Mark Crispin
  452.21 + *		Networks and Distributed Computing
  452.22 + *		Computing & Communications
  452.23 + *		University of Washington
  452.24 + *		Administration Building, AG-44
  452.25 + *		Seattle, WA  98195
  452.26 + *		Internet: MRC@CAC.Washington.EDU
  452.27 + *
  452.28 + * Date:	10 April 1992
  452.29 + * Last Edited:	30 August 2006
  452.30 + */
  452.31 +
  452.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  452.33 +#include "mail.h"
  452.34 +#include "osdep.h"
  452.35 +#include <ctype.h>
  452.36 +#include <stdio.h>
  452.37 +#include <sys/stat.h>
  452.38 +#include <sys/tiuser.h>
  452.39 +#include <sys/stropts.h>
  452.40 +#include <sys/poll.h>
  452.41 +#include <netinet/in.h>
  452.42 +#include <arpa/inet.h>
  452.43 +#include <netdb.h>
  452.44 +#include <errno.h>
  452.45 +#include <net/errno.h>
  452.46 +#include <pwd.h>
  452.47 +#include <shadow.h>
  452.48 +#include <sys/socket.h>
  452.49 +#include "misc.h"
  452.50 +
  452.51 +extern int sys_nerr;
  452.52 +extern char *sys_errlist[];
  452.53 +
  452.54 +#define toint(c)	((c)-'0')
  452.55 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  452.56 +
  452.57 +#define DIR_SIZE(d) d->d_reclen
  452.58 +
  452.59 +#define pid_t short		/* may not be known on all ISC systems */
  452.60 +
  452.61 +#include "fs_unix.c"
  452.62 +#include "ftl_unix.c"
  452.63 +#include "nl_unix.c"
  452.64 +#include "env_unix.c"
  452.65 +#include "tcp_unix.c"
  452.66 +#include "gr_waitp.c"
  452.67 +#include "strerror.c"
  452.68 +#include "flocksim.c"
  452.69 +#include "scandir.c"
  452.70 +#include "tz_sv4.c"
  452.71 +#include "fsync.c"
   453.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   453.2 +++ b/src/osdep/unix/os_isc.h	Mon Sep 14 15:17:45 2009 +0900
   453.3 @@ -0,0 +1,70 @@
   453.4 +/* ========================================================================
   453.5 + * Copyright 1988-2006 University of Washington
   453.6 + *
   453.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   453.8 + * you may not use this file except in compliance with the License.
   453.9 + * You may obtain a copy of the License at
  453.10 + *
  453.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  453.12 + *
  453.13 + * 
  453.14 + * ========================================================================
  453.15 + */
  453.16 +
  453.17 +/*
  453.18 + * Program:	Operating-system dependent routines -- ISC version
  453.19 + *
  453.20 + * Author:	Mark Crispin
  453.21 + *		Networks and Distributed Computing
  453.22 + *		Computing & Communications
  453.23 + *		University of Washington
  453.24 + *		Administration Building, AG-44
  453.25 + *		Seattle, WA  98195
  453.26 + *		Internet: MRC@CAC.Washington.EDU
  453.27 + *
  453.28 + * Date:	10 April 1992
  453.29 + * Last Edited:	15 September 2006
  453.30 + */
  453.31 +
  453.32 +#include <string.h>
  453.33 +#include <sys/types.h>
  453.34 +#include <sys/bsdtypes.h>
  453.35 +#include <stdlib.h>
  453.36 +#include <dirent.h>
  453.37 +#include <fcntl.h>
  453.38 +#include <unistd.h>
  453.39 +#include <time.h>
  453.40 +#include <syslog.h>
  453.41 +#include <sys/file.h>
  453.42 +#include <ustat.h>
  453.43 +
  453.44 +
  453.45 +/* Different names, equivalent things in BSD and SysV */
  453.46 +
  453.47 +/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
  453.48 +#ifndef L_SET
  453.49 +#define L_SET SEEK_SET
  453.50 +#endif
  453.51 +#define L_INCR SEEK_CUR
  453.52 +#define L_XTND SEEK_END
  453.53 +
  453.54 +#define direct dirent
  453.55 +
  453.56 +#define ftruncate chsize
  453.57 +#define random lrand48
  453.58 +
  453.59 +long gethostid (void);
  453.60 +void *memmove (void *s,void *ct,size_t n);
  453.61 +typedef int (*select_t) (struct direct *name);
  453.62 +typedef int (*compar_t) (void *d1,void *d2);
  453.63 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  453.64 +	     compar_t compar);
  453.65 +int alphasort (void *d1,void *d2);
  453.66 +
  453.67 +
  453.68 +#include "env_unix.h"
  453.69 +#include "fs.h"
  453.70 +#include "ftl.h"
  453.71 +#include "nl.h"
  453.72 +#include "tcp.h"
  453.73 +#include "flocksim.h"
   454.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   454.2 +++ b/src/osdep/unix/os_lnx.c	Mon Sep 14 15:17:45 2009 +0900
   454.3 @@ -0,0 +1,54 @@
   454.4 +/* ========================================================================
   454.5 + * Copyright 1988-2007 University of Washington
   454.6 + *
   454.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   454.8 + * you may not use this file except in compliance with the License.
   454.9 + * You may obtain a copy of the License at
  454.10 + *
  454.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  454.12 + *
  454.13 + * 
  454.14 + * ========================================================================
  454.15 + */
  454.16 +
  454.17 +/*
  454.18 + * Program:	Operating-system dependent routines -- old Linux version
  454.19 + *
  454.20 + * Author:	Mark Crispin
  454.21 + *		Networks and Distributed Computing
  454.22 + *		Computing & Communications
  454.23 + *		University of Washington
  454.24 + *		Administration Building, AG-44
  454.25 + *		Seattle, WA  98195
  454.26 + *		Internet: MRC@CAC.Washington.EDU
  454.27 + *
  454.28 + * Date:	1 August 1993
  454.29 + * Last Edited:	16 August 2007
  454.30 + */
  454.31 + 
  454.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  454.33 +#include "mail.h"
  454.34 +#include "osdep.h"
  454.35 +#include <stdio.h>
  454.36 +#include <sys/time.h>
  454.37 +#include <sys/stat.h>
  454.38 +#include <sys/socket.h>
  454.39 +#include <netinet/in.h>
  454.40 +#include <arpa/inet.h>
  454.41 +#include <netdb.h>
  454.42 +#include <ctype.h>
  454.43 +#include <errno.h>
  454.44 +extern int errno;		/* just in case */
  454.45 +#include <pwd.h>
  454.46 +#include "misc.h"
  454.47 +
  454.48 +
  454.49 +#include "fs_unix.c"
  454.50 +#include "ftl_unix.c"
  454.51 +#include "nl_unix.c"
  454.52 +#include "env_unix.c"
  454.53 +#define fork vfork
  454.54 +#include "tcp_unix.c"
  454.55 +#include "gr_waitp.c"
  454.56 +#include "tz_sv4.c"
  454.57 +#include "flocklnx.c"
   455.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   455.2 +++ b/src/osdep/unix/os_lnx.h	Mon Sep 14 15:17:45 2009 +0900
   455.3 @@ -0,0 +1,67 @@
   455.4 +/* ========================================================================
   455.5 + * Copyright 1988-2006 University of Washington
   455.6 + *
   455.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   455.8 + * you may not use this file except in compliance with the License.
   455.9 + * You may obtain a copy of the License at
  455.10 + *
  455.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  455.12 + *
  455.13 + * 
  455.14 + * ========================================================================
  455.15 + */
  455.16 +
  455.17 +/*
  455.18 + * Program:	Operating-system dependent routines -- Linux version
  455.19 + *
  455.20 + * Author:	Mark Crispin
  455.21 + *		Networks and Distributed Computing
  455.22 + *		Computing & Communications
  455.23 + *		University of Washington
  455.24 + *		Administration Building, AG-44
  455.25 + *		Seattle, WA  98195
  455.26 + *		Internet: MRC@CAC.Washington.EDU
  455.27 + *
  455.28 + * Date:	10 September 1993
  455.29 + * Last Edited:	30 August 2006
  455.30 + */
  455.31 +
  455.32 +/*
  455.33 + *** These lines are claimed to be necessary to build on Debian Linux on an
  455.34 + *** Alpha.
  455.35 + */
  455.36 +
  455.37 +#ifndef _XOPEN_SOURCE
  455.38 +#define _XOPEN_SOURCE 1
  455.39 +#endif /* _XOPEN_SOURCE */
  455.40 +#ifndef _BSD_SOURCE
  455.41 +#define _BSD_SOURCE 1
  455.42 +#endif /* _BSD_SOURCE */
  455.43 +
  455.44 +/* end Debian Linux on Alpha strangeness */
  455.45 +
  455.46 +#include <stdlib.h>
  455.47 +#include <string.h>
  455.48 +#include <unistd.h>
  455.49 +#include <sys/types.h>
  455.50 +#include <dirent.h>
  455.51 +#include <time.h>		/* for struct tm */
  455.52 +#include <fcntl.h>
  455.53 +#include <syslog.h>
  455.54 +#include <sys/file.h>
  455.55 +
  455.56 +
  455.57 +/* Linux gets this wrong */
  455.58 +
  455.59 +#define setpgrp setpgid
  455.60 +
  455.61 +#define direct dirent
  455.62 +
  455.63 +#define flock safe_flock
  455.64 +
  455.65 +
  455.66 +#include "env_unix.h"
  455.67 +#include "fs.h"
  455.68 +#include "ftl.h"
  455.69 +#include "nl.h"
  455.70 +#include "tcp.h"
   456.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   456.2 +++ b/src/osdep/unix/os_lyn.c	Mon Sep 14 15:17:45 2009 +0900
   456.3 @@ -0,0 +1,54 @@
   456.4 +/* ========================================================================
   456.5 + * Copyright 1988-2006 University of Washington
   456.6 + *
   456.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   456.8 + * you may not use this file except in compliance with the License.
   456.9 + * You may obtain a copy of the License at
  456.10 + *
  456.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  456.12 + *
  456.13 + * 
  456.14 + * ========================================================================
  456.15 + */
  456.16 +
  456.17 +/*
  456.18 + * Program:	Operating-system dependent routines -- LynxOS version
  456.19 + *
  456.20 + * Author:	Mark Crispin
  456.21 + *		Networks and Distributed Computing
  456.22 + *		Computing & Communications
  456.23 + *		University of Washington
  456.24 + *		Administration Building, AG-44
  456.25 + *		Seattle, WA  98195
  456.26 + *		Internet: MRC@CAC.Washington.EDU
  456.27 + *
  456.28 + * Date:	1 August 1988
  456.29 + * Last Edited:	30 August 2006
  456.30 + */
  456.31 + 
  456.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  456.33 +#include "mail.h"
  456.34 +#include "osdep.h"
  456.35 +#include <stdio.h>
  456.36 +#include <sys/time.h>
  456.37 +#include <sys/stat.h>
  456.38 +#include <sys/socket.h>
  456.39 +#include <netinet/in.h>
  456.40 +#include <arpa/inet.h>
  456.41 +#include <netdb.h>
  456.42 +#include <ctype.h>
  456.43 +#include <errno.h>
  456.44 +extern int errno;		/* just in case */
  456.45 +#include <pwd.h>
  456.46 +#include "misc.h"
  456.47 +
  456.48 +char *crypt (char *key,char *salt);
  456.49 +
  456.50 +
  456.51 +#include "fs_unix.c"
  456.52 +#include "ftl_unix.c"
  456.53 +#include "nl_unix.c"
  456.54 +#include "env_unix.c"
  456.55 +#include "tcp_unix.c"
  456.56 +#include "gr_waitp.c"
  456.57 +#include "tz_nul.c"
   457.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   457.2 +++ b/src/osdep/unix/os_lyn.h	Mon Sep 14 15:17:45 2009 +0900
   457.3 @@ -0,0 +1,44 @@
   457.4 +/* ========================================================================
   457.5 + * Copyright 1988-2006 University of Washington
   457.6 + *
   457.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   457.8 + * you may not use this file except in compliance with the License.
   457.9 + * You may obtain a copy of the License at
  457.10 + *
  457.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  457.12 + *
  457.13 + * 
  457.14 + * ========================================================================
  457.15 + */
  457.16 +
  457.17 +/*
  457.18 + * Program:	Operating-system dependent routines -- LynxOS version
  457.19 + *
  457.20 + * Author:	Mark Crispin
  457.21 + *		Networks and Distributed Computing
  457.22 + *		Computing & Communications
  457.23 + *		University of Washington
  457.24 + *		Administration Building, AG-44
  457.25 + *		Seattle, WA  98195
  457.26 + *		Internet: MRC@CAC.Washington.EDU
  457.27 + *
  457.28 + * Date:	5 March 1993
  457.29 + * Last Edited:	30 August 2006
  457.30 + */
  457.31 +
  457.32 +#include <stdlib.h>
  457.33 +#include <string.h>
  457.34 +#include <sys/types.h>
  457.35 +#include <sys/dir.h>
  457.36 +#include <fcntl.h>
  457.37 +#include <syslog.h>
  457.38 +#include <sys/file.h>
  457.39 +
  457.40 +#define gethostid clock
  457.41 +
  457.42 +
  457.43 +#include "env_unix.h"
  457.44 +#include "fs.h"
  457.45 +#include "ftl.h"
  457.46 +#include "nl.h"
  457.47 +#include "tcp.h"
   458.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   458.2 +++ b/src/osdep/unix/os_mct.c	Mon Sep 14 15:17:45 2009 +0900
   458.3 @@ -0,0 +1,52 @@
   458.4 +/* ========================================================================
   458.5 + * Copyright 1988-2006 University of Washington
   458.6 + *
   458.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   458.8 + * you may not use this file except in compliance with the License.
   458.9 + * You may obtain a copy of the License at
  458.10 + *
  458.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  458.12 + *
  458.13 + * 
  458.14 + * ========================================================================
  458.15 + */
  458.16 +
  458.17 +/*
  458.18 + * Program:	Operating-system dependent routines -- MachTen version
  458.19 + *
  458.20 + * Author:	Mark Crispin
  458.21 + *		Networks and Distributed Computing
  458.22 + *		Computing & Communications
  458.23 + *		University of Washington
  458.24 + *		Administration Building, AG-44
  458.25 + *		Seattle, WA  98195
  458.26 + *		Internet: MRC@CAC.Washington.EDU
  458.27 + *
  458.28 + * Date:	1 August 1988
  458.29 + * Last Edited:	7 December 2006
  458.30 + */
  458.31 +
  458.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  458.33 +#include "mail.h"
  458.34 +#include "osdep.h"
  458.35 +#include <stdio.h>
  458.36 +#include <sys/time.h>
  458.37 +#include <sys/stat.h>
  458.38 +#include <sys/socket.h>
  458.39 +#include <netinet/in.h>
  458.40 +#include <arpa/inet.h>
  458.41 +#include <netdb.h>
  458.42 +#include <ctype.h>
  458.43 +#include <errno.h>
  458.44 +extern int errno;		/* just in case */
  458.45 +#include <pwd.h>
  458.46 +#include "misc.h"
  458.47 +
  458.48 +
  458.49 +#include "fs_unix.c"
  458.50 +#include "ftl_unix.c"
  458.51 +#include "nl_unix.c"
  458.52 +#include "env_unix.c"
  458.53 +#include "tcp_unix.c"
  458.54 +#include "gr_wait4.c"
  458.55 +#include "tz_bsd.c"
   459.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   459.2 +++ b/src/osdep/unix/os_mct.h	Mon Sep 14 15:17:45 2009 +0900
   459.3 @@ -0,0 +1,44 @@
   459.4 +/* ========================================================================
   459.5 + * Copyright 1988-2006 University of Washington
   459.6 + *
   459.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   459.8 + * you may not use this file except in compliance with the License.
   459.9 + * You may obtain a copy of the License at
  459.10 + *
  459.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  459.12 + *
  459.13 + * 
  459.14 + * ========================================================================
  459.15 + */
  459.16 +
  459.17 +/*
  459.18 + * Program:	Operating-system dependent routines -- MachTen version
  459.19 + *
  459.20 + * Author:	Mark Crispin
  459.21 + *		Networks and Distributed Computing
  459.22 + *		Computing & Communications
  459.23 + *		University of Washington
  459.24 + *		Administration Building, AG-44
  459.25 + *		Seattle, WA  98195
  459.26 + *		Internet: MRC@CAC.Washington.EDU
  459.27 + *
  459.28 + * Date:	1 August 1988
  459.29 + * Last Edited:	7 December 2006
  459.30 + */
  459.31 +
  459.32 +#include <stdlib.h>
  459.33 +#include <unistd.h>
  459.34 +#include <string.h>
  459.35 +#include <sys/types.h>
  459.36 +#include <sys/dir.h>
  459.37 +#include <fcntl.h>
  459.38 +#include <syslog.h>
  459.39 +#include <sys/file.h>
  459.40 +
  459.41 +#define unix 1
  459.42 +
  459.43 +#include "env_unix.h"
  459.44 +#include "fs.h"
  459.45 +#include "ftl.h"
  459.46 +#include "nl.h"
  459.47 +#include "tcp.h"
   460.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   460.2 +++ b/src/osdep/unix/os_mnt.c	Mon Sep 14 15:17:45 2009 +0900
   460.3 @@ -0,0 +1,53 @@
   460.4 +/* ========================================================================
   460.5 + * Copyright 1988-2007 University of Washington
   460.6 + *
   460.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   460.8 + * you may not use this file except in compliance with the License.
   460.9 + * You may obtain a copy of the License at
  460.10 + *
  460.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  460.12 + *
  460.13 + * 
  460.14 + * ========================================================================
  460.15 + */
  460.16 +
  460.17 +/*
  460.18 + * Program:	Operating-system dependent routines -- Mint version
  460.19 + *
  460.20 + * Author:	Mark Crispin
  460.21 + *		Networks and Distributed Computing
  460.22 + *		Computing & Communications
  460.23 + *		University of Washington
  460.24 + *		Administration Building, AG-44
  460.25 + *		Seattle, WA  98195
  460.26 + *		Internet: MRC@CAC.Washington.EDU
  460.27 + *
  460.28 + * Date:	1 August 1988
  460.29 + * Last Edited:	16 August 2007
  460.30 + */
  460.31 + 
  460.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  460.33 +#include "mail.h"
  460.34 +#include "osdep.h"
  460.35 +#include <stdio.h>
  460.36 +#include <sys/time.h>
  460.37 +#include <sys/stat.h>
  460.38 +#include <sys/socket.h>
  460.39 +#include <netinet/in.h>
  460.40 +#include <arpa/inet.h>
  460.41 +#include <netdb.h>
  460.42 +#include <ctype.h>
  460.43 +#include <errno.h>
  460.44 +extern int errno;		/* just in case */
  460.45 +#include <pwd.h>
  460.46 +#include "misc.h"
  460.47 +
  460.48 +
  460.49 +#include "fs_unix.c"
  460.50 +#include "ftl_unix.c"
  460.51 +#include "nl_unix.c"
  460.52 +#include "env_unix.c"
  460.53 +#define fork vfork
  460.54 +#include "tcp_unix.c"
  460.55 +#include "gr_waitp.c"
  460.56 +#include "tz_nul.c"
   461.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   461.2 +++ b/src/osdep/unix/os_mnt.h	Mon Sep 14 15:17:45 2009 +0900
   461.3 @@ -0,0 +1,51 @@
   461.4 +/* ========================================================================
   461.5 + * Copyright 1988-2006 University of Washington
   461.6 + *
   461.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   461.8 + * you may not use this file except in compliance with the License.
   461.9 + * You may obtain a copy of the License at
  461.10 + *
  461.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  461.12 + *
  461.13 + * 
  461.14 + * ========================================================================
  461.15 + */
  461.16 +
  461.17 +/*
  461.18 + * Program:	Operating-system dependent routines -- Mint version
  461.19 + *
  461.20 + * Author:	Mark Crispin
  461.21 + *		Networks and Distributed Computing
  461.22 + *		Computing & Communications
  461.23 + *		University of Washington
  461.24 + *		Administration Building, AG-44
  461.25 + *		Seattle, WA  98195
  461.26 + *		Internet: MRC@CAC.Washington.EDU
  461.27 + *
  461.28 + * Date:	10 September 1993
  461.29 + * Last Edited:	30 August 2006
  461.30 + */
  461.31 +
  461.32 +#include <stdlib.h>
  461.33 +#include <unistd.h>
  461.34 +#include <string.h>
  461.35 +#include <sys/types.h>
  461.36 +#include <sys/dir.h>
  461.37 +#include <fcntl.h>
  461.38 +#include <syslog.h>
  461.39 +#include <sys/file.h>
  461.40 +#include <time.h>
  461.41 +#include <portlib.h>
  461.42 + 
  461.43 +#define EAGAIN EWOULDBLOCK
  461.44 +#define FNDELAY O_NDELAY 
  461.45 + 
  461.46 +/* MiNT gets this wrong */
  461.47 + 
  461.48 +#define setpgrp setpgid
  461.49 + 
  461.50 +#include "env_unix.h"
  461.51 +#include "fs.h"
  461.52 +#include "ftl.h"
  461.53 +#include "nl.h"
  461.54 +#include "tcp.h"
   462.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   462.2 +++ b/src/osdep/unix/os_nto.c	Mon Sep 14 15:17:45 2009 +0900
   462.3 @@ -0,0 +1,76 @@
   462.4 +/* ========================================================================
   462.5 + * Copyright 1988-2006 University of Washington
   462.6 + *
   462.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   462.8 + * you may not use this file except in compliance with the License.
   462.9 + * You may obtain a copy of the License at
  462.10 + *
  462.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  462.12 + *
  462.13 + * 
  462.14 + * ========================================================================
  462.15 + */
  462.16 +
  462.17 +/*
  462.18 + * Program:	Operating-system dependent routines -- QNX Neutrino RTP version
  462.19 + *
  462.20 + * Author:	Mark Crispin
  462.21 + *		Networks and Distributed Computing
  462.22 + *		Computing & Communications
  462.23 + *		University of Washington
  462.24 + *		Administration Building, AG-44
  462.25 + *		Seattle, WA  98195
  462.26 + *		Internet: MRC@CAC.Washington.EDU
  462.27 + *
  462.28 + * Date:	1 August 1993
  462.29 + * Last Edited:	30 August 2006
  462.30 + */
  462.31 +
  462.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  462.33 +#include "mail.h"
  462.34 +#include "osdep.h"
  462.35 +#include <stdio.h>
  462.36 +#include <sys/stat.h>
  462.37 +#include <sys/time.h>
  462.38 +#include <sys/socket.h>
  462.39 +#include <netinet/in.h>
  462.40 +#include <arpa/inet.h>
  462.41 +#include <netdb.h>
  462.42 +#include <ctype.h>
  462.43 +#include <errno.h>
  462.44 +extern int errno;		/* just in case */
  462.45 +#include <pwd.h>
  462.46 +#include <shadow.h>
  462.47 +#include <sys/select.h>
  462.48 +#include "misc.h"
  462.49 +
  462.50 +#define DIR_SIZE(d) d->d_reclen
  462.51 +
  462.52 +#include "fs_unix.c"
  462.53 +#include "ftl_unix.c"
  462.54 +#include "nl_unix.c"
  462.55 +#include "env_unix.c"
  462.56 +#include "tcp_unix.c"
  462.57 +#include "gr_wait.c"
  462.58 +#include "tz_sv4.c"
  462.59 +#include "gethstid.c"
  462.60 +#include "flocksim.c"
  462.61 +#include "utime.c"
  462.62 +
  462.63 +/* QNX local readdir()
  462.64 + * Accepts: directory structure
  462.65 + * Returns: direct struct or NIL if failed
  462.66 + */
  462.67 +
  462.68 +#undef readdir
  462.69 +
  462.70 +struct direct *Readdir (DIR *dirp)
  462.71 +{
  462.72 +  static struct direct dc;
  462.73 +  struct dirent *de = readdir (dirp);
  462.74 +  if (!de) return NIL;		/* end of data */
  462.75 +  dc.d_fileno = 0;		/* could get from de->stat.st_ino */
  462.76 +  dc.d_namlen = strlen (strcpy (dc.d_name,de->d_name));
  462.77 +  dc.d_reclen = sizeof (dc);
  462.78 +  return &dc;
  462.79 +}
   463.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   463.2 +++ b/src/osdep/unix/os_nto.h	Mon Sep 14 15:17:45 2009 +0900
   463.3 @@ -0,0 +1,75 @@
   463.4 +/* ========================================================================
   463.5 + * Copyright 1988-2006 University of Washington
   463.6 + *
   463.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   463.8 + * you may not use this file except in compliance with the License.
   463.9 + * You may obtain a copy of the License at
  463.10 + *
  463.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  463.12 + *
  463.13 + * 
  463.14 + * ========================================================================
  463.15 + */
  463.16 +
  463.17 +/*
  463.18 + * Program:	Operating-system dependent routines -- QNX Neutrino RTP version
  463.19 + *
  463.20 + * Author:	Mark Crispin
  463.21 + *		Networks and Distributed Computing
  463.22 + *		Computing & Communications
  463.23 + *		University of Washington
  463.24 + *		Administration Building, AG-44
  463.25 + *		Seattle, WA  98195
  463.26 + *		Internet: MRC@CAC.Washington.EDU
  463.27 + *
  463.28 + * Date:	10 September 1993
  463.29 + * Last Edited:	30 August 2006
  463.30 + */
  463.31 +
  463.32 +#include <stdlib.h>
  463.33 +#include <string.h>
  463.34 +#include <syslog.h>
  463.35 +#include <dirent.h>
  463.36 +#include <fcntl.h>
  463.37 +#include <unistd.h>
  463.38 +#include <sys/dir.h>
  463.39 +#include <sys/types.h>
  463.40 +#include <time.h>
  463.41 +#include <utime.h>
  463.42 +
  463.43 +
  463.44 +/* QNX gets these wrong */
  463.45 +
  463.46 +#define setpgrp setpgid
  463.47 +#define readdir Readdir
  463.48 +#define FNDELAY O_NONBLOCK
  463.49 +#define d_ino d_fileno
  463.50 +
  463.51 +
  463.52 +/* Different names, equivalent things in BSD and SysV */
  463.53 +
  463.54 +#ifndef L_SET
  463.55 +#define L_SET SEEK_SET
  463.56 +#endif
  463.57 +#ifndef L_INCR
  463.58 +#define L_INCR SEEK_CUR
  463.59 +#endif
  463.60 +#ifndef L_XTND
  463.61 +#define L_XTND SEEK_END
  463.62 +#endif
  463.63 +
  463.64 +
  463.65 +#define utime portable_utime
  463.66 +int portable_utime (char *file,time_t timep[2]);
  463.67 +
  463.68 +long gethostid (void);
  463.69 +struct direct *Readdir (DIR *dirp);
  463.70 +typedef int (*select_t) (struct direct *name);
  463.71 +typedef int (*compar_t) (void *d1,void *d2);
  463.72 +
  463.73 +#include "env_unix.h"
  463.74 +#include "fs.h"
  463.75 +#include "ftl.h"
  463.76 +#include "nl.h"
  463.77 +#include "tcp.h"
  463.78 +#include "flocksim.h"
   464.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   464.2 +++ b/src/osdep/unix/os_nxt.c	Mon Sep 14 15:17:45 2009 +0900
   464.3 @@ -0,0 +1,54 @@
   464.4 +/* ========================================================================
   464.5 + * Copyright 1988-2007 University of Washington
   464.6 + *
   464.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   464.8 + * you may not use this file except in compliance with the License.
   464.9 + * You may obtain a copy of the License at
  464.10 + *
  464.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  464.12 + *
  464.13 + * 
  464.14 + * ========================================================================
  464.15 + */
  464.16 +
  464.17 +/*
  464.18 + * Program:	Operating-system dependent routines -- NeXT version
  464.19 + *
  464.20 + * Author:	Mark Crispin
  464.21 + *		Networks and Distributed Computing
  464.22 + *		Computing & Communications
  464.23 + *		University of Washington
  464.24 + *		Administration Building, AG-44
  464.25 + *		Seattle, WA  98195
  464.26 + *		Internet: MRC@CAC.Washington.EDU
  464.27 + *
  464.28 + * Date:	1 August 1988
  464.29 + * Last Edited:	16 August 2007
  464.30 + */
  464.31 +
  464.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  464.33 +#include "mail.h"
  464.34 +#include "osdep.h"
  464.35 +#include <stdio.h>
  464.36 +#include <sys/time.h>
  464.37 +#include <sys/stat.h>
  464.38 +#include <sys/socket.h>
  464.39 +#include <netinet/in.h>
  464.40 +#include <arpa/inet.h>
  464.41 +#include <netdb.h>
  464.42 +#include <ctype.h>
  464.43 +#include <errno.h>
  464.44 +extern int errno;		/* just in case */
  464.45 +#include <pwd.h>
  464.46 +#include "misc.h"
  464.47 +
  464.48 +
  464.49 +#include "fs_unix.c"
  464.50 +#include "ftl_unix.c"
  464.51 +#include "nl_unix.c"
  464.52 +#include "env_unix.c"
  464.53 +#define fork vfork
  464.54 +#include "tcp_unix.c"
  464.55 +#include "gr_wait4.c"
  464.56 +#include "tz_bsd.c"
  464.57 +#include "strtok.c"
   465.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   465.2 +++ b/src/osdep/unix/os_nxt.h	Mon Sep 14 15:17:45 2009 +0900
   465.3 @@ -0,0 +1,50 @@
   465.4 +/* ========================================================================
   465.5 + * Copyright 1988-2007 University of Washington
   465.6 + *
   465.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   465.8 + * you may not use this file except in compliance with the License.
   465.9 + * You may obtain a copy of the License at
  465.10 + *
  465.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  465.12 + *
  465.13 + * 
  465.14 + * ========================================================================
  465.15 + */
  465.16 +
  465.17 +/*
  465.18 + * Program:	Operating-system dependent routines -- NeXT version
  465.19 + *
  465.20 + * Author:	Mark Crispin
  465.21 + *		Networks and Distributed Computing
  465.22 + *		Computing & Communications
  465.23 + *		University of Washington
  465.24 + *		Administration Building, AG-44
  465.25 + *		Seattle, WA  98195
  465.26 + *		Internet: MRC@CAC.Washington.EDU
  465.27 + *
  465.28 + * Date:	1 August 1988
  465.29 + * Last Edited:	30 January 2007
  465.30 + */
  465.31 +
  465.32 +#include <libc.h>
  465.33 +#include <stdlib.h>
  465.34 +#include <string.h>
  465.35 +#include <sys/types.h>
  465.36 +#include <sys/dir.h>
  465.37 +#include <fcntl.h>
  465.38 +#include <syslog.h>
  465.39 +#include <sys/file.h>
  465.40 +
  465.41 +/* Use ours instead of theirs */
  465.42 +
  465.43 +#define strtok STRTOK
  465.44 +#define strtok_r STRTOK_R
  465.45 +
  465.46 +char *strtok (char *s,char *ct);
  465.47 +char *strtok_r (char *s,char *ct,char **r);
  465.48 +
  465.49 +#include "env_unix.h"
  465.50 +#include "fs.h"
  465.51 +#include "ftl.h"
  465.52 +#include "nl.h"
  465.53 +#include "tcp.h"
   466.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   466.2 +++ b/src/osdep/unix/os_os4.c	Mon Sep 14 15:17:45 2009 +0900
   466.3 @@ -0,0 +1,57 @@
   466.4 +/* ========================================================================
   466.5 + * Copyright 1988-2006 University of Washington
   466.6 + *
   466.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   466.8 + * you may not use this file except in compliance with the License.
   466.9 + * You may obtain a copy of the License at
  466.10 + *
  466.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  466.12 + *
  466.13 + * 
  466.14 + * ========================================================================
  466.15 + */
  466.16 +
  466.17 +/*
  466.18 + * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64 4
  466.19 + *
  466.20 + * Author:	Mark Crispin
  466.21 + *		Networks and Distributed Computing
  466.22 + *		Computing & Communications
  466.23 + *		University of Washington
  466.24 + *		Administration Building, AG-44
  466.25 + *		Seattle, WA  98195
  466.26 + *		Internet: MRC@CAC.Washington.EDU
  466.27 + *
  466.28 + * Date:	1 August 1988
  466.29 + * Last Edited:	30 August 2006
  466.30 + */
  466.31 + 
  466.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  466.33 +#include "mail.h"
  466.34 +#include "osdep.h"
  466.35 +#include <stdio.h>
  466.36 +#include <sys/time.h>
  466.37 +#include <sys/stat.h>
  466.38 +#include <sys/socket.h>
  466.39 +#include <netinet/in.h>
  466.40 +#include <arpa/inet.h>
  466.41 +#include <netdb.h>
  466.42 +#include <ctype.h>
  466.43 +#include <errno.h>
  466.44 +extern int errno;		/* just in case */
  466.45 +#include <pwd.h>
  466.46 +#include "misc.h"
  466.47 +#include <sia.h>
  466.48 +#include <siad.h>
  466.49 +#include <ustat.h>
  466.50 +
  466.51 +
  466.52 +#include "fs_unix.c"
  466.53 +#include "ftl_unix.c"
  466.54 +#include "nl_unix.c"
  466.55 +#include "env_unix.c"
  466.56 +#include "gr_waitp.c"
  466.57 +#include "tcp_unix.c"
  466.58 +#include "tz_bsd.c"
  466.59 +#undef flock
  466.60 +#include "flocksim.c"
   467.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   467.2 +++ b/src/osdep/unix/os_os4.h	Mon Sep 14 15:17:45 2009 +0900
   467.3 @@ -0,0 +1,51 @@
   467.4 +/* ========================================================================
   467.5 + * Copyright 1988-2006 University of Washington
   467.6 + *
   467.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   467.8 + * you may not use this file except in compliance with the License.
   467.9 + * You may obtain a copy of the License at
  467.10 + *
  467.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  467.12 + *
  467.13 + * 
  467.14 + * ========================================================================
  467.15 + */
  467.16 +
  467.17 +/*
  467.18 + * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
  467.19 + *
  467.20 + * Author:	Mark Crispin
  467.21 + *		Networks and Distributed Computing
  467.22 + *		Computing & Communications
  467.23 + *		University of Washington
  467.24 + *		Administration Building, AG-44
  467.25 + *		Seattle, WA  98195
  467.26 + *		Internet: MRC@CAC.Washington.EDU
  467.27 + *
  467.28 + * Date:	1 August 1988
  467.29 + * Last Edited:	30 August 2006
  467.30 + */
  467.31 +
  467.32 +#include <stdlib.h>
  467.33 +#include <unistd.h>
  467.34 +#include <string.h>
  467.35 +#include <sys/types.h>
  467.36 +#include <dirent.h>
  467.37 +#include <time.h>		/* for struct tm */
  467.38 +#include <fcntl.h>
  467.39 +#include <syslog.h>
  467.40 +#include <sys/file.h>
  467.41 +
  467.42 +
  467.43 +/* OSF/1 gets this wrong */
  467.44 +
  467.45 +#define setpgrp setpgid
  467.46 +
  467.47 +#define direct dirent
  467.48 +
  467.49 +#include "env_unix.h"
  467.50 +#include "fs.h"
  467.51 +#include "ftl.h"
  467.52 +#include "nl.h"
  467.53 +#include "tcp.h"
  467.54 +#include "flocksim.h"
   468.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   468.2 +++ b/src/osdep/unix/os_osf.c	Mon Sep 14 15:17:45 2009 +0900
   468.3 @@ -0,0 +1,55 @@
   468.4 +/* ========================================================================
   468.5 + * Copyright 1988-2006 University of Washington
   468.6 + *
   468.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   468.8 + * you may not use this file except in compliance with the License.
   468.9 + * You may obtain a copy of the License at
  468.10 + *
  468.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  468.12 + *
  468.13 + * 
  468.14 + * ========================================================================
  468.15 + */
  468.16 +
  468.17 +/*
  468.18 + * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
  468.19 + *
  468.20 + * Author:	Mark Crispin
  468.21 + *		Networks and Distributed Computing
  468.22 + *		Computing & Communications
  468.23 + *		University of Washington
  468.24 + *		Administration Building, AG-44
  468.25 + *		Seattle, WA  98195
  468.26 + *		Internet: MRC@CAC.Washington.EDU
  468.27 + *
  468.28 + * Date:	1 August 1988
  468.29 + * Last Edited:	30 August 2006
  468.30 + */
  468.31 + 
  468.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  468.33 +#include "mail.h"
  468.34 +#include "osdep.h"
  468.35 +#include <stdio.h>
  468.36 +#include <sys/time.h>
  468.37 +#include <sys/stat.h>
  468.38 +#include <sys/socket.h>
  468.39 +#include <netinet/in.h>
  468.40 +#include <arpa/inet.h>
  468.41 +#include <netdb.h>
  468.42 +#include <ctype.h>
  468.43 +#include <errno.h>
  468.44 +extern int errno;		/* just in case */
  468.45 +#include <pwd.h>
  468.46 +#include "misc.h"
  468.47 +#include <ustat.h>
  468.48 +
  468.49 +
  468.50 +#include "fs_unix.c"
  468.51 +#include "ftl_unix.c"
  468.52 +#include "nl_unix.c"
  468.53 +#include "env_unix.c"
  468.54 +#include "gr_waitp.c"
  468.55 +#include "tcp_unix.c"
  468.56 +#include "tz_bsd.c"
  468.57 +#undef flock
  468.58 +#include "flocksim.c"
   469.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   469.2 +++ b/src/osdep/unix/os_osf.h	Mon Sep 14 15:17:45 2009 +0900
   469.3 @@ -0,0 +1,51 @@
   469.4 +/* ========================================================================
   469.5 + * Copyright 1988-2006 University of Washington
   469.6 + *
   469.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   469.8 + * you may not use this file except in compliance with the License.
   469.9 + * You may obtain a copy of the License at
  469.10 + *
  469.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  469.12 + *
  469.13 + * 
  469.14 + * ========================================================================
  469.15 + */
  469.16 +
  469.17 +/*
  469.18 + * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
  469.19 + *
  469.20 + * Author:	Mark Crispin
  469.21 + *		Networks and Distributed Computing
  469.22 + *		Computing & Communications
  469.23 + *		University of Washington
  469.24 + *		Administration Building, AG-44
  469.25 + *		Seattle, WA  98195
  469.26 + *		Internet: MRC@CAC.Washington.EDU
  469.27 + *
  469.28 + * Date:	1 August 1988
  469.29 + * Last Edited:	30 August 2006
  469.30 + */
  469.31 +
  469.32 +#include <stdlib.h>
  469.33 +#include <unistd.h>
  469.34 +#include <string.h>
  469.35 +#include <sys/types.h>
  469.36 +#include <dirent.h>
  469.37 +#include <time.h>		/* for struct tm */
  469.38 +#include <fcntl.h>
  469.39 +#include <syslog.h>
  469.40 +#include <sys/file.h>
  469.41 +
  469.42 +
  469.43 +/* OSF/1 gets this wrong */
  469.44 +
  469.45 +#define setpgrp setpgid
  469.46 +
  469.47 +#define direct dirent
  469.48 +
  469.49 +#include "env_unix.h"
  469.50 +#include "fs.h"
  469.51 +#include "ftl.h"
  469.52 +#include "nl.h"
  469.53 +#include "tcp.h"
  469.54 +#include "flocksim.h"
   470.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   470.2 +++ b/src/osdep/unix/os_osx.c	Mon Sep 14 15:17:45 2009 +0900
   470.3 @@ -0,0 +1,54 @@
   470.4 +/* ========================================================================
   470.5 + * Copyright 1988-2007 University of Washington
   470.6 + *
   470.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   470.8 + * you may not use this file except in compliance with the License.
   470.9 + * You may obtain a copy of the License at
  470.10 + *
  470.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  470.12 + *
  470.13 + * 
  470.14 + * ========================================================================
  470.15 + */
  470.16 +
  470.17 +/*
  470.18 + * Program:	Operating-system dependent routines -- Mac OS X version
  470.19 + *
  470.20 + * Author:	Mark Crispin
  470.21 + *		Networks and Distributed Computing
  470.22 + *		Computing & Communications
  470.23 + *		University of Washington
  470.24 + *		Administration Building, AG-44
  470.25 + *		Seattle, WA  98195
  470.26 + *		Internet: MRC@CAC.Washington.EDU
  470.27 + *
  470.28 + * Date:	1 August 1988
  470.29 + * Last Edited:	16 August 2007
  470.30 + */
  470.31 +
  470.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  470.33 +#include "mail.h"
  470.34 +#include "osdep.h"
  470.35 +#include <stdio.h>
  470.36 +#include <sys/time.h>
  470.37 +#include <sys/stat.h>
  470.38 +#include <sys/socket.h>
  470.39 +#include <netinet/in.h>
  470.40 +#include <arpa/inet.h>
  470.41 +#include <netdb.h>
  470.42 +#include <ctype.h>
  470.43 +#include <errno.h>
  470.44 +extern int errno;		/* just in case */
  470.45 +#include <pwd.h>
  470.46 +#include "misc.h"
  470.47 +
  470.48 +
  470.49 +#include "fs_unix.c"
  470.50 +#include "ftl_unix.c"
  470.51 +#include "nl_unix.c"
  470.52 +#include "env_unix.c"
  470.53 +#define fork vfork
  470.54 +#include "getspnam.c"
  470.55 +#include "tcp_unix.c"
  470.56 +#include "gr_wait4.c"
  470.57 +#include "tz_bsd.c"
   471.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   471.2 +++ b/src/osdep/unix/os_osx.h	Mon Sep 14 15:17:45 2009 +0900
   471.3 @@ -0,0 +1,56 @@
   471.4 +/* ========================================================================
   471.5 + * Copyright 1988-2006 University of Washington
   471.6 + *
   471.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   471.8 + * you may not use this file except in compliance with the License.
   471.9 + * You may obtain a copy of the License at
  471.10 + *
  471.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  471.12 + *
  471.13 + * 
  471.14 + * ========================================================================
  471.15 + */
  471.16 +
  471.17 +/*
  471.18 + * Program:	Operating-system dependent routines -- Mac OS X version
  471.19 + *
  471.20 + * Author:	Mark Crispin
  471.21 + *		Networks and Distributed Computing
  471.22 + *		Computing & Communications
  471.23 + *		University of Washington
  471.24 + *		Administration Building, AG-44
  471.25 + *		Seattle, WA  98195
  471.26 + *		Internet: MRC@CAC.Washington.EDU
  471.27 + *
  471.28 + * Date:	1 August 1988
  471.29 + * Last Edited:	26 October 2007
  471.30 + */
  471.31 +
  471.32 +#include <stdlib.h>
  471.33 +#include <unistd.h>
  471.34 +#include <string.h>
  471.35 +#include <sys/types.h>
  471.36 +#include <sys/dir.h>
  471.37 +#include <fcntl.h>
  471.38 +#include <syslog.h>
  471.39 +#include <sys/file.h>
  471.40 +
  471.41 +
  471.42 +/* Mac OS X gets this wrong as of Leopard */
  471.43 +
  471.44 +#define setpgrp setpgid
  471.45 +
  471.46 +
  471.47 +#define unix 1
  471.48 +
  471.49 +/* Mac OS X security framework also has checkpw, and this causes
  471.50 + * multiple-definition problems when building Alpine.
  471.51 + */
  471.52 +
  471.53 +#define checkpw Checkpw
  471.54 +
  471.55 +#include "env_unix.h"
  471.56 +#include "fs.h"
  471.57 +#include "ftl.h"
  471.58 +#include "nl.h"
  471.59 +#include "tcp.h"
   472.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   472.2 +++ b/src/osdep/unix/os_ptx.c	Mon Sep 14 15:17:45 2009 +0900
   472.3 @@ -0,0 +1,115 @@
   472.4 +/* ========================================================================
   472.5 + * Copyright 1988-2007 University of Washington
   472.6 + *
   472.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   472.8 + * you may not use this file except in compliance with the License.
   472.9 + * You may obtain a copy of the License at
  472.10 + *
  472.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  472.12 + *
  472.13 + * 
  472.14 + * ========================================================================
  472.15 + */
  472.16 +
  472.17 +/*
  472.18 + * Program:	Operating-system dependent routines -- PTX version
  472.19 + *
  472.20 + * Author:	Mark Crispin
  472.21 + *		Networks and Distributed Computing
  472.22 + *		Computing & Communications
  472.23 + *		University of Washington
  472.24 + *		Administration Building, AG-44
  472.25 + *		Seattle, WA  98195
  472.26 + *		Internet: MRC@CAC.Washington.EDU
  472.27 + *
  472.28 + * Date:	11 May 1989
  472.29 + * Last Edited:	16 August 2007
  472.30 + */
  472.31 +
  472.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  472.33 +#include "mail.h"
  472.34 +#include "osdep.h"
  472.35 +#include <ctype.h>
  472.36 +#include <stdio.h>
  472.37 +#include <sys/stat.h>
  472.38 +#include <sys/time.h>
  472.39 +#include <sys/tiuser.h>
  472.40 +#include <sys/stropts.h>
  472.41 +#include <sys/socket.h>
  472.42 +#include <sys/poll.h>
  472.43 +#include <netinet/in.h>
  472.44 +#include <arpa/inet.h>
  472.45 +#include <netdb.h>
  472.46 +#include <errno.h>
  472.47 +#include <pwd.h>
  472.48 +#include <shadow.h>
  472.49 +#include <sys/select.h>
  472.50 +#include "misc.h"
  472.51 +
  472.52 +extern int sys_nerr;
  472.53 +extern char *sys_errlist[];
  472.54 +
  472.55 +#define DIR_SIZE(d) d->d_reclen
  472.56 +
  472.57 +#define toint(c)	((c)-'0')
  472.58 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  472.59 +
  472.60 +
  472.61 +#include "fs_unix.c"
  472.62 +#include "ftl_unix.c"
  472.63 +#include "nl_unix.c"
  472.64 +#define env_init ENV_INIT
  472.65 +#include "env_unix.c"
  472.66 +#undef env_init
  472.67 +#define getpeername Getpeername
  472.68 +#define fork vfork
  472.69 +#include "tcp_unix.c"
  472.70 +#include "gr_waitp.c"
  472.71 +#include "flocksim.c"
  472.72 +#include "scandir.c"
  472.73 +#include "tz_sv4.c"
  472.74 +#include "utime.c"
  472.75 +
  472.76 +/* Jacket around env_init() to work around PTX inetd braindamage */
  472.77 +
  472.78 +static char may_need_server_init = T;
  472.79 +
  472.80 +long env_init (char *user,char *home)
  472.81 +{
  472.82 +  if (may_need_server_init) {	/* maybe need to do server init cruft? */
  472.83 +    may_need_server_init = NIL;	/* not any more we don't */
  472.84 +    if (!getuid ()) {		/* if root, we're most likely a server */
  472.85 +      t_sync (0);		/* PTX inetd is stupid, stupid, stupid */
  472.86 +      ioctl (0,I_PUSH,"tirdwr");/*  it needs this cruft, else servers won't */
  472.87 +      dup2 (0,1);		/*  work.  How obnoxious!!! */
  472.88 +    }
  472.89 +  }
  472.90 +  ENV_INIT (user,home);		/* call the real routine */
  472.91 +}
  472.92 +
  472.93 +/* Emulator for BSD gethostid() call
  472.94 + * Returns: unique identifier for this machine
  472.95 + */
  472.96 +
  472.97 +long gethostid (void)
  472.98 +{
  472.99 +  struct sockaddr_in sin;
 472.100 +  int inet = t_open (TLI_TCP, O_RDWR, 0);
 472.101 +  if (inet < 0) return 0;
 472.102 +  getmyinaddr (inet,&sin,sizeof (sin));
 472.103 +  close (inet);
 472.104 +  return sin.sin_addr.s_addr;
 472.105 +}
 472.106 +
 472.107 +
 472.108 +/* Replaced version of getpeername() that jackets into getpeerinaddr()
 472.109 + * Accepts: file descriptor
 472.110 + *	    pointer to Internet socket addr
 472.111 + *	    length
 472.112 + * Returns: zero if success, data in socket addr
 472.113 + */
 472.114 +
 472.115 +int Getpeername (int s,struct sockaddr *name,int *namelen)
 472.116 +{
 472.117 +  return getpeerinaddr (s,(struct sockaddr_in *) name,*namelen);
 472.118 +}
   473.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   473.2 +++ b/src/osdep/unix/os_ptx.h	Mon Sep 14 15:17:45 2009 +0900
   473.3 @@ -0,0 +1,72 @@
   473.4 +/* ========================================================================
   473.5 + * Copyright 1988-2006 University of Washington
   473.6 + *
   473.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   473.8 + * you may not use this file except in compliance with the License.
   473.9 + * You may obtain a copy of the License at
  473.10 + *
  473.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  473.12 + *
  473.13 + * 
  473.14 + * ========================================================================
  473.15 + */
  473.16 +
  473.17 +/*
  473.18 + * Program:	Operating-system dependent routines -- PTX version
  473.19 + *
  473.20 + * Author:	Mark Crispin
  473.21 + *		Networks and Distributed Computing
  473.22 + *		Computing & Communications
  473.23 + *		University of Washington
  473.24 + *		Administration Building, AG-44
  473.25 + *		Seattle, WA  98195
  473.26 + *		Internet: MRC@CAC.Washington.EDU
  473.27 + *
  473.28 + * Date:	11 May 1989
  473.29 + * Last Edited:	15 September 2006
  473.30 + */
  473.31 +
  473.32 +#include <string.h>
  473.33 +
  473.34 +#include <sys/types.h>
  473.35 +#include <sys/dir.h>
  473.36 +#include <stdlib.h>
  473.37 +#include <fcntl.h>
  473.38 +#include <unistd.h>
  473.39 +#include <time.h>
  473.40 +#include <utime.h>
  473.41 +#include <dirent.h>
  473.42 +#include <stropts.h>		/* needed in daemons */
  473.43 +#include <syslog.h>
  473.44 +#include <sys/file.h>
  473.45 +#include <ustat.h>
  473.46 +
  473.47 +
  473.48 +/* Different names, equivalent things in BSD and SysV */
  473.49 +
  473.50 +#define L_SET SEEK_SET
  473.51 +#define L_INCR SEEK_CUR
  473.52 +#define L_XTND SEEK_END
  473.53 +
  473.54 +#define direct dirent
  473.55 +#define random lrand48
  473.56 +
  473.57 +
  473.58 +#define utime portable_utime
  473.59 +int portable_utime (char *file,time_t timep[2]);
  473.60 +
  473.61 +long gethostid (void);
  473.62 +typedef int (*select_t) (struct direct *name);
  473.63 +typedef int (*compar_t) (void *d1,void *d2);
  473.64 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  473.65 +	     compar_t compar);
  473.66 +int alphasort (void *d1,void *d2);
  473.67 +long ENV_INIT (char *user,char *home);
  473.68 +
  473.69 +
  473.70 +#include "env_unix.h"
  473.71 +#include "fs.h"
  473.72 +#include "ftl.h"
  473.73 +#include "nl.h"
  473.74 +#include "tcp.h"
  473.75 +#include "flocksim.h"
   474.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   474.2 +++ b/src/osdep/unix/os_pyr.c	Mon Sep 14 15:17:45 2009 +0900
   474.3 @@ -0,0 +1,61 @@
   474.4 +/* ========================================================================
   474.5 + * Copyright 1988-2006 University of Washington
   474.6 + *
   474.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   474.8 + * you may not use this file except in compliance with the License.
   474.9 + * You may obtain a copy of the License at
  474.10 + *
  474.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  474.12 + *
  474.13 + * 
  474.14 + * ========================================================================
  474.15 + */
  474.16 +
  474.17 +/*
  474.18 + * Program:	Operating-system dependent routines -- Pyramid OSx 4.4c version
  474.19 + *
  474.20 + * Author:	Mark Crispin
  474.21 + *		Networks and Distributed Computing
  474.22 + *		Computing & Communications
  474.23 + *		University of Washington
  474.24 + *		Administration Building, AG-44
  474.25 + *		Seattle, WA  98195
  474.26 + *
  474.27 + * Date:	11 May 1989
  474.28 + * Last Edited:	30 August 2006
  474.29 + */
  474.30 +
  474.31 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  474.32 +#define toint(c)       ((c)-'0')
  474.33 +
  474.34 +
  474.35 +#include "tcp_unix.h"           /* must be before osdep includes tcp.h */
  474.36 +#include "mail.h"
  474.37 +#include "osdep.h"
  474.38 +#include <stdio.h>
  474.39 +#include <sys/stat.h>
  474.40 +#include <sys/time.h>
  474.41 +#include <sys/socket.h>
  474.42 +#include <netinet/in.h>
  474.43 +#include <arpa/inet.h>
  474.44 +#include <netdb.h>
  474.45 +#include <ctype.h>
  474.46 +#include <errno.h>
  474.47 +extern int errno;		/* just in case */
  474.48 +#include <pwd.h>
  474.49 +#include "misc.h"
  474.50 +
  474.51 +
  474.52 +#include "fs_unix.c"
  474.53 +#include "ftl_unix.c"
  474.54 +#include "nl_unix.c"
  474.55 +#include "env_unix.c"
  474.56 +#include "tcp_unix.c"
  474.57 +#include "gr_wait.c"
  474.58 +#include "memmove.c"
  474.59 +#include "memset.c"
  474.60 +#include "strerror.c"
  474.61 +#include "strpbrk.c"
  474.62 +#include "strstr.c"
  474.63 +#include "strtok.c"
  474.64 +#include "tz_nul.c"
   475.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   475.2 +++ b/src/osdep/unix/os_pyr.h	Mon Sep 14 15:17:45 2009 +0900
   475.3 @@ -0,0 +1,58 @@
   475.4 +/* ========================================================================
   475.5 + * Copyright 1988-2007 University of Washington
   475.6 + *
   475.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   475.8 + * you may not use this file except in compliance with the License.
   475.9 + * You may obtain a copy of the License at
  475.10 + *
  475.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  475.12 + *
  475.13 + * 
  475.14 + * ========================================================================
  475.15 + */
  475.16 +
  475.17 +/*
  475.18 + * Program:	Operating-system dependent routines -- Pyramid OSx 4.4c version
  475.19 + *
  475.20 + * Author:	Mark Crispin
  475.21 + *		Networks and Distributed Computing
  475.22 + *		Computing & Communications
  475.23 + *		University of Washington
  475.24 + *		Administration Building, AG-44
  475.25 + *		Seattle, WA  98195
  475.26 + *		Internet: MRC@CAC.Washington.EDU
  475.27 + *
  475.28 + * Date:	11 May 1989
  475.29 + * Last Edited:	30 January 2007
  475.30 + */
  475.31 +
  475.32 +#include <strings.h>
  475.33 +#include <sys/types.h>
  475.34 +#include <sys/dir.h>
  475.35 +#include <fcntl.h>
  475.36 +#include <syslog.h>
  475.37 +#include <sys/file.h>
  475.38 +
  475.39 +
  475.40 +char *strtok (char *s,char *ct);
  475.41 +char *strtok_r (char *s,char *ct,char **r);
  475.42 +char *strstr (char *cs,char *ct);
  475.43 +char *strpbrk (char *cs,char *ct);
  475.44 +char *strerror (int n);
  475.45 +void *memmove (void *s,void *ct,size_t n);
  475.46 +void *memset (void *s,int c,size_t n);
  475.47 +void *malloc (size_t byteSize);
  475.48 +void free (void *ptr);
  475.49 +void *realloc (void *oldptr,size_t newsize);
  475.50 +
  475.51 +int errno;
  475.52 +
  475.53 +#define memcpy memmove
  475.54 +#define strchr index
  475.55 +#define strrchr rindex
  475.56 +
  475.57 +#include "env_unix.h"
  475.58 +#include "fs.h"
  475.59 +#include "ftl.h"
  475.60 +#include "nl.h"
  475.61 +#include "tcp.h"
   476.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   476.2 +++ b/src/osdep/unix/os_qnx.c	Mon Sep 14 15:17:45 2009 +0900
   476.3 @@ -0,0 +1,77 @@
   476.4 +/* ========================================================================
   476.5 + * Copyright 1988-2006 University of Washington
   476.6 + *
   476.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   476.8 + * you may not use this file except in compliance with the License.
   476.9 + * You may obtain a copy of the License at
  476.10 + *
  476.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  476.12 + *
  476.13 + * 
  476.14 + * ========================================================================
  476.15 + */
  476.16 +
  476.17 +/*
  476.18 + * Program:	Operating-system dependent routines -- QNX version
  476.19 + *
  476.20 + * Author:	Mark Crispin
  476.21 + *		Networks and Distributed Computing
  476.22 + *		Computing & Communications
  476.23 + *		University of Washington
  476.24 + *		Administration Building, AG-44
  476.25 + *		Seattle, WA  98195
  476.26 + *		Internet: MRC@CAC.Washington.EDU
  476.27 + *
  476.28 + * Date:	1 August 1993
  476.29 + * Last Edited:	20 December 2006
  476.30 + */
  476.31 +
  476.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  476.33 +#include "mail.h"
  476.34 +#include "osdep.h"
  476.35 +#include <stdio.h>
  476.36 +#include <sys/stat.h>
  476.37 +#include <sys/time.h>
  476.38 +#include <sys/socket.h>
  476.39 +#include <netinet/in.h>
  476.40 +#include <arpa/inet.h>
  476.41 +#include <netdb.h>
  476.42 +#include <ctype.h>
  476.43 +#include <errno.h>
  476.44 +extern int errno;		/* just in case */
  476.45 +#include <pwd.h>
  476.46 +#include <shadow.h>
  476.47 +#include <sys/select.h>
  476.48 +#include "misc.h"
  476.49 +
  476.50 +#define DIR_SIZE(d) d->d_reclen
  476.51 +
  476.52 +extern char *crypt (const char *pw, const char *salt);
  476.53 +
  476.54 +#include "fs_unix.c"
  476.55 +#include "ftl_unix.c"
  476.56 +#include "nl_unix.c"
  476.57 +#include "env_unix.c"
  476.58 +#include "tcp_unix.c"
  476.59 +#include "gr_waitp.c"
  476.60 +#include "tz_sv4.c"
  476.61 +#include "gethstid.c"
  476.62 +#include "scandir.c"
  476.63 +
  476.64 +/* QNX local readdir()
  476.65 + * Accepts: directory structure
  476.66 + * Returns: direct struct or NIL if failed
  476.67 + */
  476.68 +
  476.69 +#undef readdir
  476.70 +
  476.71 +struct direct *Readdir (DIR *dirp)
  476.72 +{
  476.73 +  static struct direct dc;
  476.74 +  struct dirent *de = readdir (dirp);
  476.75 +  if (!de) return NIL;		/* end of data */
  476.76 +  dc.d_fileno = 0;		/* could get from de->stat.st_ino */
  476.77 +  dc.d_namlen = strlen (strcpy (dc.d_name,de->d_name));
  476.78 +  dc.d_reclen = sizeof (dc);
  476.79 +  return &dc;
  476.80 +}
   477.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   477.2 +++ b/src/osdep/unix/os_qnx.h	Mon Sep 14 15:17:45 2009 +0900
   477.3 @@ -0,0 +1,62 @@
   477.4 +/* ========================================================================
   477.5 + * Copyright 1988-2006 University of Washington
   477.6 + *
   477.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   477.8 + * you may not use this file except in compliance with the License.
   477.9 + * You may obtain a copy of the License at
  477.10 + *
  477.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  477.12 + *
  477.13 + * 
  477.14 + * ========================================================================
  477.15 + */
  477.16 +
  477.17 +/*
  477.18 + * Program:	Operating-system dependent routines -- QNX version
  477.19 + *
  477.20 + * Author:	Mark Crispin
  477.21 + *		Networks and Distributed Computing
  477.22 + *		Computing & Communications
  477.23 + *		University of Washington
  477.24 + *		Administration Building, AG-44
  477.25 + *		Seattle, WA  98195
  477.26 + *		Internet: MRC@CAC.Washington.EDU
  477.27 + *
  477.28 + * Date:	10 September 1993
  477.29 + * Last Edited:	20 December 2006
  477.30 + */
  477.31 +
  477.32 +#include <stdlib.h>
  477.33 +#include <string.h>
  477.34 +#include <syslog.h>
  477.35 +#include <dirent.h>
  477.36 +#include <fcntl.h>
  477.37 +#include <unistd.h>
  477.38 +#include <sys/file.h>
  477.39 +#include <sys/dir.h>
  477.40 +#include <sys/types.h>
  477.41 +#include </usr/include/unix.h>
  477.42 +#include <time.h>
  477.43 +#include <utime.h>
  477.44 +
  477.45 +
  477.46 +/* QNX gets these wrong */
  477.47 +
  477.48 +#define setpgrp setpgid
  477.49 +#define readdir Readdir
  477.50 +#define FNDELAY O_NONBLOCK
  477.51 +#define d_ino d_fileno
  477.52 +
  477.53 +typedef int (*select_t) (struct direct *name);
  477.54 +typedef int (*compar_t) (void *d1,void *d2);
  477.55 +
  477.56 +#include "env_unix.h"
  477.57 +#include "fs.h"
  477.58 +#include "ftl.h"
  477.59 +#include "nl.h"
  477.60 +#include "tcp.h"
  477.61 +
  477.62 +long gethostid(void);
  477.63 +struct direct *Readdir (DIR *dirp);
  477.64 +
  477.65 +extern long random (void);
   478.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   478.2 +++ b/src/osdep/unix/os_s40.c	Mon Sep 14 15:17:45 2009 +0900
   478.3 @@ -0,0 +1,64 @@
   478.4 +/* ========================================================================
   478.5 + * Copyright 1988-2007 University of Washington
   478.6 + *
   478.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   478.8 + * you may not use this file except in compliance with the License.
   478.9 + * You may obtain a copy of the License at
  478.10 + *
  478.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  478.12 + *
  478.13 + * 
  478.14 + * ========================================================================
  478.15 + */
  478.16 +
  478.17 +/*
  478.18 + * Program:	Operating-system dependent routines -- SUN-OS 4.0 version
  478.19 + *
  478.20 + * Author:	Mark Crispin
  478.21 + *		Networks and Distributed Computing
  478.22 + *		Computing & Communications
  478.23 + *		University of Washington
  478.24 + *		Administration Building, AG-44
  478.25 + *		Seattle, WA  98195
  478.26 + *		Internet: MRC@CAC.Washington.EDU
  478.27 + *
  478.28 + * Date:	11 May 1989
  478.29 + * Last Edited:	16 August 2007
  478.30 + */
  478.31 +
  478.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  478.33 +#include "mail.h"
  478.34 +#include "osdep.h"
  478.35 +#include <stdio.h>
  478.36 +#include <sys/stat.h>
  478.37 +#include <sys/time.h>
  478.38 +#include <sys/socket.h>
  478.39 +#include <netinet/in.h>
  478.40 +#include <arpa/inet.h>
  478.41 +#include <netdb.h>
  478.42 +#include <ctype.h>
  478.43 +#include <errno.h>
  478.44 +extern int errno;		/* just in case */
  478.45 +#include <pwd.h>
  478.46 +#include "misc.h"
  478.47 +
  478.48 +extern int sys_nerr;
  478.49 +extern char *sys_errlist[];
  478.50 +
  478.51 +#define toint(c)	((c)-'0')
  478.52 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  478.53 +
  478.54 +
  478.55 +#include "fs_unix.c"
  478.56 +#include "ftl_unix.c"
  478.57 +#include "nl_unix.c"
  478.58 +#include "env_unix.c"
  478.59 +#define fork vfork
  478.60 +#include "tcp_unix.c"
  478.61 +#include "gr_wait4.c"
  478.62 +#include "memmove.c"
  478.63 +#include "strerror.c"
  478.64 +#define strstr Strstr		/* override SUN's broken version */
  478.65 +#include "strstr.c"
  478.66 +#include "strtoul.c"
  478.67 +#include "tz_bsd.c"
   479.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   479.2 +++ b/src/osdep/unix/os_s40.h	Mon Sep 14 15:17:45 2009 +0900
   479.3 @@ -0,0 +1,33 @@
   479.4 +/* ========================================================================
   479.5 + * Copyright 1988-2006 University of Washington
   479.6 + *
   479.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   479.8 + * you may not use this file except in compliance with the License.
   479.9 + * You may obtain a copy of the License at
  479.10 + *
  479.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  479.12 + *
  479.13 + * 
  479.14 + * ========================================================================
  479.15 + */
  479.16 +
  479.17 +/*
  479.18 + * Program:	Operating-system dependent routines -- SUN-OS 4.0 version
  479.19 + *
  479.20 + * Author:	Mark Crispin
  479.21 + *		Networks and Distributed Computing
  479.22 + *		Computing & Communications
  479.23 + *		University of Washington
  479.24 + *		Administration Building, AG-44
  479.25 + *		Seattle, WA  98195
  479.26 + *		Internet: MRC@CAC.Washington.EDU
  479.27 + *
  479.28 + * Date:	11 May 1989
  479.29 + * Last Edited:	30 August 2006
  479.30 + */
  479.31 +
  479.32 +void *malloc (size_t byteSize);
  479.33 +void free (void *ptr);
  479.34 +void *realloc (void *oldptr,size_t newsize);
  479.35 +
  479.36 +#include "os_sun.h"		/* now use regular SUN-OS file */
   480.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   480.2 +++ b/src/osdep/unix/os_sc5.c	Mon Sep 14 15:17:45 2009 +0900
   480.3 @@ -0,0 +1,63 @@
   480.4 +/* ========================================================================
   480.5 + * Copyright 1988-2006 University of Washington
   480.6 + *
   480.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   480.8 + * you may not use this file except in compliance with the License.
   480.9 + * You may obtain a copy of the License at
  480.10 + *
  480.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  480.12 + *
  480.13 + * 
  480.14 + * ========================================================================
  480.15 + */
  480.16 +
  480.17 +/*
  480.18 + * Program:	Operating-system dependent routines -- SCO Unix version
  480.19 + *
  480.20 + * Author:	Mark Crispin
  480.21 + *		Networks and Distributed Computing
  480.22 + *		Computing & Communications
  480.23 + *		University of Washington
  480.24 + *		Administration Building, AG-44
  480.25 + *		Seattle, WA  98195
  480.26 + *		Internet: MRC@CAC.Washington.EDU
  480.27 + *
  480.28 + * Date:	1 August 1988
  480.29 + * Last Edited:	30 August 2006
  480.30 + */
  480.31 + 
  480.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  480.33 +#include <sys/time.h>		/* must be before osdep.h */
  480.34 +#include "mail.h"
  480.35 +#include <stdio.h>
  480.36 +#include "osdep.h"
  480.37 +#include <sys/stat.h>
  480.38 +#include <sys/socket.h>
  480.39 +#include <netinet/in.h>
  480.40 +#include <arpa/inet.h>
  480.41 +#include <netdb.h>
  480.42 +#include <ctype.h>
  480.43 +#include <errno.h>
  480.44 +#include "misc.h"
  480.45 +#define SecureWare		/* protected subsystem */
  480.46 +#include <sys/security.h>
  480.47 +#include <sys/audit.h>
  480.48 +#include <prot.h>
  480.49 +#include <pwd.h>
  480.50 +
  480.51 +#define DIR_SIZE(d) d->d_reclen
  480.52 +
  480.53 +#include "fs_unix.c"
  480.54 +#include "ftl_unix.c"
  480.55 +#include "nl_unix.c"
  480.56 +#include "env_unix.c"
  480.57 +#include "tcp_unix.c"
  480.58 +#include "gr_waitp.c"
  480.59 +#include "flocksim.c"
  480.60 +#include "scandir.c"
  480.61 +#include "tz_sv4.c"
  480.62 +#include "gethstid.c"
  480.63 +#undef setpgrp
  480.64 +#include "setpgrp.c"
  480.65 +#include "rename.c"
  480.66 +#include "utime.c"
   481.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   481.2 +++ b/src/osdep/unix/os_sc5.h	Mon Sep 14 15:17:45 2009 +0900
   481.3 @@ -0,0 +1,76 @@
   481.4 +/* ========================================================================
   481.5 + * Copyright 1988-2006 University of Washington
   481.6 + *
   481.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   481.8 + * you may not use this file except in compliance with the License.
   481.9 + * You may obtain a copy of the License at
  481.10 + *
  481.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  481.12 + *
  481.13 + * 
  481.14 + * ========================================================================
  481.15 + */
  481.16 +
  481.17 +/*
  481.18 + * Program:	Operating-system dependent routines -- SCO Unix version
  481.19 + *
  481.20 + * Author:	Mark Crispin
  481.21 + *		Networks and Distributed Computing
  481.22 + *		Computing & Communications
  481.23 + *		University of Washington
  481.24 + *		Administration Building, AG-44
  481.25 + *		Seattle, WA  98195
  481.26 + *		Internet: MRC@CAC.Washington.EDU
  481.27 + *
  481.28 + * Date:	1 August 1988
  481.29 + * Last Edited:	20 December 2006
  481.30 + */
  481.31 +
  481.32 +#include <stdlib.h>
  481.33 +#include <string.h>
  481.34 +#include <sys/types.h>
  481.35 +#include <sys/dir.h>
  481.36 +#include <fcntl.h>
  481.37 +#include <unistd.h>
  481.38 +#include <time.h>
  481.39 +#include <utime.h>
  481.40 +#include <dirent.h>
  481.41 +#include <syslog.h>
  481.42 +#include <sys/file.h>
  481.43 +#include <ustat.h>
  481.44 +
  481.45 +/* SCO gets this wrong */
  481.46 +
  481.47 +#define setpgrp Setpgrp
  481.48 +int Setpgrp (int pid,int gid);
  481.49 +
  481.50 +#define rename Rename
  481.51 +
  481.52 +
  481.53 +/* Different names, equivalent things in BSD and SysV */
  481.54 +
  481.55 +#define L_SET SEEK_SET
  481.56 +#define L_INCR SEEK_CUR
  481.57 +#define L_XTND SEEK_END
  481.58 +
  481.59 +#define direct dirent
  481.60 +
  481.61 +#define utime portable_utime
  481.62 +int portable_utime (char *file,time_t timep[2]);
  481.63 +
  481.64 +
  481.65 +long gethostid (void);
  481.66 +typedef int (*select_t) (struct direct *name);
  481.67 +typedef int (*compar_t) (void *d1,void *d2);
  481.68 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  481.69 +	     compar_t compar);
  481.70 +int alphasort (void *d1,void *d2);
  481.71 +int fsync (int fd);
  481.72 +
  481.73 +
  481.74 +#include "env_unix.h"
  481.75 +#include "fs.h"
  481.76 +#include "ftl.h"
  481.77 +#include "nl.h"
  481.78 +#include "tcp.h"
  481.79 +#include "flocksim.h"
   482.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   482.2 +++ b/src/osdep/unix/os_sco.c	Mon Sep 14 15:17:45 2009 +0900
   482.3 @@ -0,0 +1,66 @@
   482.4 +/* ========================================================================
   482.5 + * Copyright 1988-2006 University of Washington
   482.6 + *
   482.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   482.8 + * you may not use this file except in compliance with the License.
   482.9 + * You may obtain a copy of the License at
  482.10 + *
  482.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  482.12 + *
  482.13 + * 
  482.14 + * ========================================================================
  482.15 + */
  482.16 +
  482.17 +/*
  482.18 + * Program:	Operating-system dependent routines -- SCO Unix version
  482.19 + *
  482.20 + * Author:	Mark Crispin
  482.21 + *		Networks and Distributed Computing
  482.22 + *		Computing & Communications
  482.23 + *		University of Washington
  482.24 + *		Administration Building, AG-44
  482.25 + *		Seattle, WA  98195
  482.26 + *		Internet: MRC@CAC.Washington.EDU
  482.27 + *
  482.28 + * Date:	1 August 1988
  482.29 + * Last Edited:	30 August 2006
  482.30 + */
  482.31 + 
  482.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  482.33 +#include <sys/time.h>		/* must be before osdep.h */
  482.34 +#include "mail.h"
  482.35 +#include <stdio.h>
  482.36 +#include "osdep.h"
  482.37 +#include <sys/stat.h>
  482.38 +#include <sys/socket.h>
  482.39 +#include <netinet/in.h>
  482.40 +#include <arpa/inet.h>
  482.41 +#include <netdb.h>
  482.42 +#include <ctype.h>
  482.43 +#include <errno.h>
  482.44 +#include "misc.h"
  482.45 +#define SecureWare		/* protected subsystem */
  482.46 +#include <sys/security.h>
  482.47 +#include <sys/audit.h>
  482.48 +#include <prot.h>
  482.49 +#include <pwd.h>
  482.50 +
  482.51 +char *bigcrypt (char *key,char *salt);
  482.52 +
  482.53 +#define DIR_SIZE(d) d->d_reclen
  482.54 +
  482.55 +#include "fs_unix.c"
  482.56 +#include "ftl_unix.c"
  482.57 +#include "nl_unix.c"
  482.58 +#include "env_unix.c"
  482.59 +#include "tcp_unix.c"
  482.60 +#include "gr_waitp.c"
  482.61 +#include "flocksim.c"
  482.62 +#include "scandir.c"
  482.63 +#include "tz_sv4.c"
  482.64 +#include "gethstid.c"
  482.65 +#include "fsync.c"
  482.66 +#undef setpgrp
  482.67 +#include "setpgrp.c"
  482.68 +#include "rename.c"
  482.69 +#include "utime.c"
   483.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   483.2 +++ b/src/osdep/unix/os_sco.h	Mon Sep 14 15:17:45 2009 +0900
   483.3 @@ -0,0 +1,79 @@
   483.4 +/* ========================================================================
   483.5 + * Copyright 1988-2006 University of Washington
   483.6 + *
   483.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   483.8 + * you may not use this file except in compliance with the License.
   483.9 + * You may obtain a copy of the License at
  483.10 + *
  483.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  483.12 + *
  483.13 + * 
  483.14 + * ========================================================================
  483.15 + */
  483.16 +
  483.17 +/*
  483.18 + * Program:	Operating-system dependent routines -- SCO Unix version
  483.19 + *
  483.20 + * Author:	Mark Crispin
  483.21 + *		Networks and Distributed Computing
  483.22 + *		Computing & Communications
  483.23 + *		University of Washington
  483.24 + *		Administration Building, AG-44
  483.25 + *		Seattle, WA  98195
  483.26 + *		Internet: MRC@CAC.Washington.EDU
  483.27 + *
  483.28 + * Date:	1 August 1988
  483.29 + * Last Edited:	20 December 2006
  483.30 + */
  483.31 +
  483.32 +#include <stdlib.h>
  483.33 +#include <string.h>
  483.34 +#include <sys/types.h>
  483.35 +#include <sys/dir.h>
  483.36 +#include <fcntl.h>
  483.37 +#include <unistd.h>
  483.38 +#include <time.h>
  483.39 +#include <utime.h>
  483.40 +#include <dirent.h>
  483.41 +#include <syslog.h>
  483.42 +#include <sys/file.h>
  483.43 +#include <ustat.h>
  483.44 +
  483.45 +/* SCO gets this wrong */
  483.46 +
  483.47 +#define setpgrp Setpgrp
  483.48 +int Setpgrp (int pid,int gid);
  483.49 +
  483.50 +#define rename Rename
  483.51 +
  483.52 +
  483.53 +/* Different names, equivalent things in BSD and SysV */
  483.54 +
  483.55 +#define L_SET SEEK_SET
  483.56 +#define L_INCR SEEK_CUR
  483.57 +#define L_XTND SEEK_END
  483.58 +
  483.59 +#define direct dirent
  483.60 +
  483.61 +#define utime portable_utime
  483.62 +int portable_utime (char *file,time_t timep[2]);
  483.63 +
  483.64 +#define ftruncate chsize
  483.65 +#define random rand
  483.66 +
  483.67 +
  483.68 +long gethostid (void);
  483.69 +typedef int (*select_t) (struct direct *name);
  483.70 +typedef int (*compar_t) (void *d1,void *d2);
  483.71 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  483.72 +	     compar_t compar);
  483.73 +int alphasort (void *d1,void *d2);
  483.74 +int fsync (int fd);
  483.75 +
  483.76 +
  483.77 +#include "env_unix.h"
  483.78 +#include "fs.h"
  483.79 +#include "ftl.h"
  483.80 +#include "nl.h"
  483.81 +#include "tcp.h"
  483.82 +#include "flocksim.h"
   484.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   484.2 +++ b/src/osdep/unix/os_sgi.c	Mon Sep 14 15:17:45 2009 +0900
   484.3 @@ -0,0 +1,57 @@
   484.4 +/* ========================================================================
   484.5 + * Copyright 1988-2006 University of Washington
   484.6 + *
   484.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   484.8 + * you may not use this file except in compliance with the License.
   484.9 + * You may obtain a copy of the License at
  484.10 + *
  484.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  484.12 + *
  484.13 + * 
  484.14 + * ========================================================================
  484.15 + */
  484.16 +
  484.17 +/*
  484.18 + * Program:	Operating-system dependent routines -- SGI version
  484.19 + *
  484.20 + * Author:	Mark Crispin
  484.21 + *		Networks and Distributed Computing
  484.22 + *		Computing & Communications
  484.23 + *		University of Washington
  484.24 + *		Administration Building, AG-44
  484.25 + *		Seattle, WA  98195
  484.26 + *		Internet: MRC@CAC.Washington.EDU
  484.27 + *
  484.28 + * Date:	1 August 1988
  484.29 + * Last Edited:	30 August 2006
  484.30 + */
  484.31 + 
  484.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  484.33 +#include "mail.h"
  484.34 +#include "osdep.h"
  484.35 +#include <stdio.h>
  484.36 +#include <bstring.h>
  484.37 +#include <sys/time.h>
  484.38 +#include <sys/stat.h>
  484.39 +#include <sys/socket.h>
  484.40 +#include <netinet/in.h>
  484.41 +#include <arpa/inet.h>
  484.42 +#include <netdb.h>
  484.43 +#include <ctype.h>
  484.44 +#include <errno.h>
  484.45 +extern int errno;		/* just in case */
  484.46 +#include <pwd.h>
  484.47 +#include "misc.h"
  484.48 +
  484.49 +
  484.50 +#include "fs_unix.c"
  484.51 +#include "ftl_unix.c"
  484.52 +#include "nl_unix.c"
  484.53 +#include "env_unix.c"
  484.54 +#include "tcp_unix.c"
  484.55 +#include "gr_waitp.c"
  484.56 +#include "tz_nul.c"
  484.57 +#include "flocksim.c"
  484.58 +#undef setpgrp
  484.59 +#include "setpgrp.c"
  484.60 +#include "utime.c"
   485.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   485.2 +++ b/src/osdep/unix/os_sgi.h	Mon Sep 14 15:17:45 2009 +0900
   485.3 @@ -0,0 +1,59 @@
   485.4 +/* ========================================================================
   485.5 + * Copyright 1988-2006 University of Washington
   485.6 + *
   485.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   485.8 + * you may not use this file except in compliance with the License.
   485.9 + * You may obtain a copy of the License at
  485.10 + *
  485.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  485.12 + *
  485.13 + * 
  485.14 + * ========================================================================
  485.15 + */
  485.16 +
  485.17 +/*
  485.18 + * Program:	Operating-system dependent routines -- SGI version
  485.19 + *
  485.20 + * Author:	Mark Crispin
  485.21 + *		Networks and Distributed Computing
  485.22 + *		Computing & Communications
  485.23 + *		University of Washington
  485.24 + *		Administration Building, AG-44
  485.25 + *		Seattle, WA  98195
  485.26 + *		Internet: MRC@CAC.Washington.EDU
  485.27 + *
  485.28 + * Date:	1 August 1988
  485.29 + * Last Edited:	20 December 2006
  485.30 + */
  485.31 +
  485.32 +#include <stdlib.h>
  485.33 +#include <unistd.h>
  485.34 +#include <string.h>
  485.35 +#include <sys/types.h>
  485.36 +#include <dirent.h>
  485.37 +#include <time.h>		/* for struct tm */
  485.38 +#include <utime.h>
  485.39 +#include <fcntl.h>
  485.40 +#include <sys/syslog.h>
  485.41 +#include <sys/file.h>
  485.42 +#include <ustat.h>
  485.43 +
  485.44 +/* Many versions of SysV get this wrong */
  485.45 +
  485.46 +#define setpgrp(a,b) Setpgrp(a,b)
  485.47 +int Setpgrp (int pid,int gid);
  485.48 +
  485.49 +
  485.50 +#define direct dirent
  485.51 +
  485.52 +#define fatal cclient_fatal
  485.53 +
  485.54 +#define utime portable_utime
  485.55 +int portable_utime (char *file,time_t timep[2]);
  485.56 +
  485.57 +#include "env_unix.h"
  485.58 +#include "fs.h"
  485.59 +#include "ftl.h"
  485.60 +#include "nl.h"
  485.61 +#include "tcp.h"
  485.62 +#include "flocksim.h"
   486.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   486.2 +++ b/src/osdep/unix/os_shp.c	Mon Sep 14 15:17:45 2009 +0900
   486.3 @@ -0,0 +1,79 @@
   486.4 +/* ========================================================================
   486.5 + * Copyright 1988-2007 University of Washington
   486.6 + *
   486.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   486.8 + * you may not use this file except in compliance with the License.
   486.9 + * You may obtain a copy of the License at
  486.10 + *
  486.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  486.12 + *
  486.13 + * 
  486.14 + * ========================================================================
  486.15 + */
  486.16 +
  486.17 +/*
  486.18 + * Program:	Operating-system dependent routines -- HP/UX version
  486.19 + *
  486.20 + * Author:	Mark Crispin
  486.21 + *		Networks and Distributed Computing
  486.22 + *		Computing & Communications
  486.23 + *		University of Washington
  486.24 + *		Administration Building, AG-44
  486.25 + *		Seattle, WA  98195
  486.26 + *		Internet: MRC@CAC.Washington.EDU
  486.27 + *
  486.28 + * Date:	11 May 1989
  486.29 + * Last Edited:	16 August 2007
  486.30 + */
  486.31 +
  486.32 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  486.33 +#define toint(c)       ((c)-'0')
  486.34 +
  486.35 +#include <stdio.h>
  486.36 +
  486.37 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  486.38 +#include "mail.h"
  486.39 +#include "osdep.h"
  486.40 +#include <stdio.h>
  486.41 +#include <sys/stat.h>
  486.42 +#include <sys/time.h>
  486.43 +#include <sys/socket.h>
  486.44 +#include <sys/utsname.h>
  486.45 +#include <netinet/in.h>
  486.46 +#include <arpa/inet.h>
  486.47 +#include <netdb.h>
  486.48 +#include <ctype.h>
  486.49 +#include <errno.h>
  486.50 +extern int errno;		/* just in case */
  486.51 +extern char *sys_errlist[];
  486.52 +extern int sys_nerr;
  486.53 +#include <pwd.h>
  486.54 +#include <hpsecurity.h>
  486.55 +#include <prot.h>
  486.56 +#include "misc.h"
  486.57 +
  486.58 +
  486.59 +#include "fs_unix.c"
  486.60 +#include "ftl_unix.c"
  486.61 +#include "nl_unix.c"
  486.62 +#include "env_unix.c"
  486.63 +#define fork vfork
  486.64 +#include "tcp_unix.c"
  486.65 +#include "gr_waitp.c"
  486.66 +#include "flocksim.c"
  486.67 +#include "tz_sv4.c"
  486.68 +#undef setpgrp
  486.69 +#include "setpgrp.c"
  486.70 +#include "utime.c"
  486.71 +
  486.72 +/* Emulator for BSD gethostid() call
  486.73 + * Returns: a unique identifier for the system.  
  486.74 + * Even though HP/UX has an undocumented gethostid() system call,
  486.75 + * it does not work (at least for non-privileged users).  
  486.76 + */
  486.77 +
  486.78 +long gethostid (void)
  486.79 +{
  486.80 +  struct utsname udata;
  486.81 +  return (uname (&udata)) ? 0xfeedface : atol (udata.__idnumber);
  486.82 +}
   487.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   487.2 +++ b/src/osdep/unix/os_shp.h	Mon Sep 14 15:17:45 2009 +0900
   487.3 @@ -0,0 +1,63 @@
   487.4 +/* ========================================================================
   487.5 + * Copyright 1988-2006 University of Washington
   487.6 + *
   487.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   487.8 + * you may not use this file except in compliance with the License.
   487.9 + * You may obtain a copy of the License at
  487.10 + *
  487.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  487.12 + *
  487.13 + * 
  487.14 + * ========================================================================
  487.15 + */
  487.16 +
  487.17 +/*
  487.18 + * Program:	Operating-system dependent routines -- HP/UX version
  487.19 + *
  487.20 + * Author:	Mark Crispin
  487.21 + *		Networks and Distributed Computing
  487.22 + *		Computing & Communications
  487.23 + *		University of Washington
  487.24 + *		Administration Building, AG-44
  487.25 + *		Seattle, WA  98195
  487.26 + *		Internet: MRC@CAC.Washington.EDU
  487.27 + *
  487.28 + * Date:	11 May 1989
  487.29 + * Last Edited:	20 December 2006
  487.30 + */
  487.31 +
  487.32 +#include <string.h>
  487.33 +
  487.34 +#include <sys/types.h>
  487.35 +#include <stdlib.h>
  487.36 +#include <dirent.h>
  487.37 +#include <fcntl.h>
  487.38 +#include <unistd.h>
  487.39 +#include <time.h>
  487.40 +#include <utime.h>
  487.41 +#include <syslog.h>
  487.42 +#include <sys/file.h>
  487.43 +#include <ustat.h>
  487.44 +
  487.45 +
  487.46 +#define direct dirent
  487.47 +#define random lrand48
  487.48 +
  487.49 +
  487.50 +/* Many versions of SysV get this wrong */
  487.51 +
  487.52 +#define setpgrp(a,b) Setpgrp(a,b)
  487.53 +int Setpgrp (int pid,int gid);
  487.54 +
  487.55 +
  487.56 +#define utime portable_utime
  487.57 +int portable_utime (char *file,time_t timep[2]);
  487.58 +
  487.59 +long gethostid (void);
  487.60 +
  487.61 +#include "env_unix.h"
  487.62 +#include "fs.h"
  487.63 +#include "ftl.h"
  487.64 +#include "nl.h"
  487.65 +#include "tcp.h"
  487.66 +#include "flocksim.h"
   488.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   488.2 +++ b/src/osdep/unix/os_slx.c	Mon Sep 14 15:17:45 2009 +0900
   488.3 @@ -0,0 +1,56 @@
   488.4 +/* ========================================================================
   488.5 + * Copyright 1988-2007 University of Washington
   488.6 + *
   488.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   488.8 + * you may not use this file except in compliance with the License.
   488.9 + * You may obtain a copy of the License at
  488.10 + *
  488.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  488.12 + *
  488.13 + * 
  488.14 + * ========================================================================
  488.15 + */
  488.16 +
  488.17 +/*
  488.18 + * Program:	Operating-system dependent routines -- modern Linux version
  488.19 + *
  488.20 + * Author:	Mark Crispin
  488.21 + *		Networks and Distributed Computing
  488.22 + *		Computing & Communications
  488.23 + *		University of Washington
  488.24 + *		Administration Building, AG-44
  488.25 + *		Seattle, WA  98195
  488.26 + *		Internet: MRC@CAC.Washington.EDU
  488.27 + *
  488.28 + * Date:	1 August 1993
  488.29 + * Last Edited:	16 August 2007
  488.30 + */
  488.31 + 
  488.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  488.33 +#include "mail.h"
  488.34 +#include "osdep.h"
  488.35 +#include <stdio.h>
  488.36 +#include <sys/time.h>
  488.37 +#include <sys/stat.h>
  488.38 +#include <sys/socket.h>
  488.39 +#include <netinet/in.h>
  488.40 +#include <arpa/inet.h>
  488.41 +#include <netdb.h>
  488.42 +#include <ctype.h>
  488.43 +#include <errno.h>
  488.44 +extern int errno;		/* just in case */
  488.45 +#include <pwd.h>
  488.46 +#include <shadow.h>
  488.47 +#include "misc.h"
  488.48 +
  488.49 +
  488.50 +#include "fs_unix.c"
  488.51 +#include "ftl_unix.c"
  488.52 +#include "nl_unix.c"
  488.53 +#include "env_unix.c"
  488.54 +#include "getspnam.c"		/* has socklen_t in spite of man page?? */
  488.55 +#define fork vfork
  488.56 +#include "tcp_unix.c"
  488.57 +#include "gr_waitp.c"
  488.58 +#include "tz_sv4.c"
  488.59 +#include "flocklnx.c"
   489.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   489.2 +++ b/src/osdep/unix/os_slx.h	Mon Sep 14 15:17:45 2009 +0900
   489.3 @@ -0,0 +1,67 @@
   489.4 +/* ========================================================================
   489.5 + * Copyright 1988-2006 University of Washington
   489.6 + *
   489.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   489.8 + * you may not use this file except in compliance with the License.
   489.9 + * You may obtain a copy of the License at
  489.10 + *
  489.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  489.12 + *
  489.13 + * 
  489.14 + * ========================================================================
  489.15 + */
  489.16 +
  489.17 +/*
  489.18 + * Program:	Operating-system dependent routines -- Linux version
  489.19 + *
  489.20 + * Author:	Mark Crispin
  489.21 + *		Networks and Distributed Computing
  489.22 + *		Computing & Communications
  489.23 + *		University of Washington
  489.24 + *		Administration Building, AG-44
  489.25 + *		Seattle, WA  98195
  489.26 + *		Internet: MRC@CAC.Washington.EDU
  489.27 + *
  489.28 + * Date:	10 September 1993
  489.29 + * Last Edited:	30 August 2006
  489.30 + */
  489.31 +
  489.32 +/*
  489.33 + *** These lines are claimed to be necessary to build on Debian Linux on an
  489.34 + *** Alpha.
  489.35 + */
  489.36 +
  489.37 +#ifndef _XOPEN_SOURCE
  489.38 +#define _XOPEN_SOURCE 1
  489.39 +#endif /* _XOPEN_SOURCE */
  489.40 +#ifndef _BSD_SOURCE
  489.41 +#define _BSD_SOURCE 1
  489.42 +#endif /* _BSD_SOURCE */
  489.43 +
  489.44 +/* end Debian Linux on Alpha strangeness */
  489.45 +
  489.46 +#include <stdlib.h>
  489.47 +#include <string.h>
  489.48 +#include <unistd.h>
  489.49 +#include <sys/types.h>
  489.50 +#include <dirent.h>
  489.51 +#include <time.h>		/* for struct tm */
  489.52 +#include <fcntl.h>
  489.53 +#include <syslog.h>
  489.54 +#include <sys/file.h>
  489.55 +
  489.56 +
  489.57 +/* Linux gets this wrong */
  489.58 +
  489.59 +#define setpgrp setpgid
  489.60 +
  489.61 +#define direct dirent
  489.62 +
  489.63 +#define flock safe_flock
  489.64 +
  489.65 +
  489.66 +#include "env_unix.h"
  489.67 +#include "fs.h"
  489.68 +#include "ftl.h"
  489.69 +#include "nl.h"
  489.70 +#include "tcp.h"
   490.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   490.2 +++ b/src/osdep/unix/os_sol.c	Mon Sep 14 15:17:45 2009 +0900
   490.3 @@ -0,0 +1,71 @@
   490.4 +/* ========================================================================
   490.5 + * Copyright 1988-2007 University of Washington
   490.6 + *
   490.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   490.8 + * you may not use this file except in compliance with the License.
   490.9 + * You may obtain a copy of the License at
  490.10 + *
  490.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  490.12 + *
  490.13 + * 
  490.14 + * ========================================================================
  490.15 + */
  490.16 +
  490.17 +/*
  490.18 + * Program:	Operating-system dependent routines -- Solaris version
  490.19 + *
  490.20 + * Author:	Mark Crispin
  490.21 + *		Networks and Distributed Computing
  490.22 + *		Computing & Communications
  490.23 + *		University of Washington
  490.24 + *		Administration Building, AG-44
  490.25 + *		Seattle, WA  98195
  490.26 + *		Internet: MRC@CAC.Washington.EDU
  490.27 + *
  490.28 + * Date:	10 April 1992
  490.29 + * Last Edited:	16 August 2007
  490.30 + */
  490.31 +
  490.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  490.33 +#include "mail.h"
  490.34 +#include "osdep.h"
  490.35 +#include <ctype.h>
  490.36 +#include <stdio.h>
  490.37 +#include <sys/stat.h>
  490.38 +#include <sys/tiuser.h>
  490.39 +#include <sys/stropts.h>
  490.40 +#include <netinet/in.h>
  490.41 +#include <arpa/inet.h>
  490.42 +#include <netdb.h>
  490.43 +#include <errno.h>
  490.44 +#include <pwd.h>
  490.45 +#include <shadow.h>
  490.46 +#include <crypt.h>
  490.47 +#include <sys/socket.h>
  490.48 +#include <sys/select.h>
  490.49 +#include "misc.h"
  490.50 +
  490.51 +extern int sys_nerr;
  490.52 +extern char *sys_errlist[];
  490.53 +
  490.54 +#define DIR_SIZE(d) d->d_reclen
  490.55 +
  490.56 +#define toint(c)	((c)-'0')
  490.57 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  490.58 +
  490.59 +
  490.60 +#include "fs_unix.c"
  490.61 +#include "ftl_unix.c"
  490.62 +#include "nl_unix.c"
  490.63 +#include "env_unix.c"
  490.64 +#include "getspnam.c"
  490.65 +#define fork vfork
  490.66 +#include "tcp_unix.c"
  490.67 +#include "gr_waitp.c"
  490.68 +#include "flocksim.c"
  490.69 +#include "scandir.c"
  490.70 +#include "tz_sv4.c"
  490.71 +#include "gethstid.c"
  490.72 +#undef setpgrp
  490.73 +#include "setpgrp.c"
  490.74 +#include "utime.c"
   491.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   491.2 +++ b/src/osdep/unix/os_soln.h	Mon Sep 14 15:17:45 2009 +0900
   491.3 @@ -0,0 +1,87 @@
   491.4 +/* ========================================================================
   491.5 + * Copyright 1988-2006 University of Washington
   491.6 + *
   491.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   491.8 + * you may not use this file except in compliance with the License.
   491.9 + * You may obtain a copy of the License at
  491.10 + *
  491.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  491.12 + *
  491.13 + * 
  491.14 + * ========================================================================
  491.15 + */
  491.16 +
  491.17 +/*
  491.18 + * Program:	Operating-system dependent routines -- Solaris version
  491.19 + *
  491.20 + * Author:	Mark Crispin
  491.21 + *		Networks and Distributed Computing
  491.22 + *		Computing & Communications
  491.23 + *		University of Washington
  491.24 + *		Administration Building, AG-44
  491.25 + *		Seattle, WA  98195
  491.26 + *		Internet: MRC@CAC.Washington.EDU
  491.27 + *
  491.28 + * Date:	1 August 1988
  491.29 + * Last Edited:	20 December 2006
  491.30 + */
  491.31 +
  491.32 +#include <string.h>
  491.33 +
  491.34 +#include <sys/types.h>
  491.35 +#include <stdlib.h>
  491.36 +#include <dirent.h>
  491.37 +#include <fcntl.h>
  491.38 +#include <unistd.h>
  491.39 +#include <time.h>
  491.40 +#include <utime.h>
  491.41 +#include <syslog.h>
  491.42 +#include <sys/file.h>
  491.43 +#include <ustat.h>
  491.44 +
  491.45 +
  491.46 +/* Many versions of SysV get this wrong */
  491.47 +
  491.48 +#define setpgrp(a,b) Setpgrp(a,b)
  491.49 +int Setpgrp (int pid,int gid);
  491.50 +
  491.51 +
  491.52 +/* Different names, equivalent things in BSD and SysV */
  491.53 +
  491.54 +/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
  491.55 +#ifndef L_SET
  491.56 +#define L_SET SEEK_SET
  491.57 +#endif
  491.58 +#ifndef L_INCR
  491.59 +#define L_INCR SEEK_CUR
  491.60 +#endif
  491.61 +#ifndef L_XTND
  491.62 +#define L_XTND SEEK_END
  491.63 +#endif
  491.64 +
  491.65 +#define direct dirent
  491.66 +#define random lrand48
  491.67 +
  491.68 +#define scandir Scandir
  491.69 +#define alphasort Alphasort
  491.70 +
  491.71 +#define getpass getpassphrase
  491.72 +
  491.73 +
  491.74 +#define utime portable_utime
  491.75 +int portable_utime (char *file,time_t timep[2]);
  491.76 +
  491.77 +long gethostid (void);
  491.78 +typedef int (*select_t) (struct direct *name);
  491.79 +typedef int (*compar_t) (const void *d1,const void *d2);
  491.80 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  491.81 +	     compar_t compar);
  491.82 +int alphasort (void *d1,void *d2);
  491.83 +
  491.84 +
  491.85 +#include "env_unix.h"
  491.86 +#include "fs.h"
  491.87 +#include "ftl.h"
  491.88 +#include "nl.h"
  491.89 +#include "tcp.h"
  491.90 +#include "flocksim.h"
   492.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   492.2 +++ b/src/osdep/unix/os_solo.h	Mon Sep 14 15:17:45 2009 +0900
   492.3 @@ -0,0 +1,84 @@
   492.4 +/* ========================================================================
   492.5 + * Copyright 1988-2006 University of Washington
   492.6 + *
   492.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   492.8 + * you may not use this file except in compliance with the License.
   492.9 + * You may obtain a copy of the License at
  492.10 + *
  492.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  492.12 + *
  492.13 + * 
  492.14 + * ========================================================================
  492.15 + */
  492.16 +
  492.17 +/*
  492.18 + * Program:	Operating-system dependent routines -- Solaris version
  492.19 + *
  492.20 + * Author:	Mark Crispin
  492.21 + *		Networks and Distributed Computing
  492.22 + *		Computing & Communications
  492.23 + *		University of Washington
  492.24 + *		Administration Building, AG-44
  492.25 + *		Seattle, WA  98195
  492.26 + *		Internet: MRC@CAC.Washington.EDU
  492.27 + *
  492.28 + * Date:	1 August 1988
  492.29 + * Last Edited:	20 December 2006
  492.30 + */
  492.31 +
  492.32 +#include <string.h>
  492.33 +
  492.34 +#include <sys/types.h>
  492.35 +#include <stdlib.h>
  492.36 +#include <dirent.h>
  492.37 +#include <fcntl.h>
  492.38 +#include <unistd.h>
  492.39 +#include <time.h>
  492.40 +#include <utime.h>
  492.41 +#include <syslog.h>
  492.42 +#include <sys/file.h>
  492.43 +#include <ustat.h>
  492.44 +
  492.45 +
  492.46 +/* Many versions of SysV get this wrong */
  492.47 +
  492.48 +#define setpgrp(a,b) Setpgrp(a,b)
  492.49 +int Setpgrp (int pid,int gid);
  492.50 +
  492.51 +
  492.52 +/* Different names, equivalent things in BSD and SysV */
  492.53 +
  492.54 +/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
  492.55 +#ifndef L_SET
  492.56 +#define L_SET SEEK_SET
  492.57 +#endif
  492.58 +#ifndef L_INCR
  492.59 +#define L_INCR SEEK_CUR
  492.60 +#endif
  492.61 +#ifndef L_XTND
  492.62 +#define L_XTND SEEK_END
  492.63 +#endif
  492.64 +
  492.65 +#define direct dirent
  492.66 +#define random lrand48
  492.67 +
  492.68 +#define scandir Scandir
  492.69 +#define alphasort Alphasort
  492.70 +
  492.71 +#define utime portable_utime
  492.72 +int portable_utime (char *file,time_t timep[2]);
  492.73 +
  492.74 +long gethostid (void);
  492.75 +typedef int (*select_t) (struct direct *name);
  492.76 +typedef int (*compar_t) (const void *d1,const void *d2);
  492.77 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  492.78 +	     compar_t compar);
  492.79 +int alphasort (void *d1,void *d2);
  492.80 +
  492.81 +
  492.82 +#include "env_unix.h"
  492.83 +#include "fs.h"
  492.84 +#include "ftl.h"
  492.85 +#include "nl.h"
  492.86 +#include "tcp.h"
  492.87 +#include "flocksim.h"
   493.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   493.2 +++ b/src/osdep/unix/os_sos.c	Mon Sep 14 15:17:45 2009 +0900
   493.3 @@ -0,0 +1,57 @@
   493.4 +/* ========================================================================
   493.5 + * Copyright 1988-2006 University of Washington
   493.6 + *
   493.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   493.8 + * you may not use this file except in compliance with the License.
   493.9 + * You may obtain a copy of the License at
  493.10 + *
  493.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  493.12 + *
  493.13 + * 
  493.14 + * ========================================================================
  493.15 + */
  493.16 +
  493.17 +/*
  493.18 + * Program:	Operating-system dependent routines -- S OSF/Digital UNIX/Tru64
  493.19 + *
  493.20 + * Author:	Mark Crispin
  493.21 + *		Networks and Distributed Computing
  493.22 + *		Computing & Communications
  493.23 + *		University of Washington
  493.24 + *		Administration Building, AG-44
  493.25 + *		Seattle, WA  98195
  493.26 + *		Internet: MRC@CAC.Washington.EDU
  493.27 + *
  493.28 + * Date:	1 August 1988
  493.29 + * Last Edited:	30 August 2006
  493.30 + */
  493.31 + 
  493.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  493.33 +#include "mail.h"
  493.34 +#include "osdep.h"
  493.35 +#include <stdio.h>
  493.36 +#include <sys/time.h>
  493.37 +#include <sys/stat.h>
  493.38 +#include <sys/socket.h>
  493.39 +#include <netinet/in.h>
  493.40 +#include <arpa/inet.h>
  493.41 +#include <netdb.h>
  493.42 +#include <ctype.h>
  493.43 +#include <errno.h>
  493.44 +extern int errno;		/* just in case */
  493.45 +#include <pwd.h>
  493.46 +#include "misc.h"
  493.47 +#include <sys/security.h>
  493.48 +#include <prot.h>
  493.49 +#include <ustat.h>
  493.50 +
  493.51 +
  493.52 +#include "fs_unix.c"
  493.53 +#include "ftl_unix.c"
  493.54 +#include "nl_unix.c"
  493.55 +#include "env_unix.c"
  493.56 +#include "tcp_unix.c"
  493.57 +#include "gr_waitp.c"
  493.58 +#include "tz_bsd.c"
  493.59 +#undef flock
  493.60 +#include "flocksim.c"
   494.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   494.2 +++ b/src/osdep/unix/os_sos.h	Mon Sep 14 15:17:45 2009 +0900
   494.3 @@ -0,0 +1,51 @@
   494.4 +/* ========================================================================
   494.5 + * Copyright 1988-2006 University of Washington
   494.6 + *
   494.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   494.8 + * you may not use this file except in compliance with the License.
   494.9 + * You may obtain a copy of the License at
  494.10 + *
  494.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  494.12 + *
  494.13 + * 
  494.14 + * ========================================================================
  494.15 + */
  494.16 +
  494.17 +/*
  494.18 + * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
  494.19 + *
  494.20 + * Author:	Mark Crispin
  494.21 + *		Networks and Distributed Computing
  494.22 + *		Computing & Communications
  494.23 + *		University of Washington
  494.24 + *		Administration Building, AG-44
  494.25 + *		Seattle, WA  98195
  494.26 + *		Internet: MRC@CAC.Washington.EDU
  494.27 + *
  494.28 + * Date:	1 August 1988
  494.29 + * Last Edited:	30 August 2006
  494.30 + */
  494.31 +
  494.32 +#include <stdlib.h>
  494.33 +#include <unistd.h>
  494.34 +#include <string.h>
  494.35 +#include <sys/types.h>
  494.36 +#include <dirent.h>
  494.37 +#include <time.h>		/* for struct tm */
  494.38 +#include <fcntl.h>
  494.39 +#include <syslog.h>
  494.40 +#include <sys/file.h>
  494.41 +
  494.42 +
  494.43 +/* OSF/1 gets this wrong */
  494.44 +
  494.45 +#define setpgrp setpgid
  494.46 +
  494.47 +#define direct dirent
  494.48 +
  494.49 +#include "env_unix.h"
  494.50 +#include "fs.h"
  494.51 +#include "ftl.h"
  494.52 +#include "nl.h"
  494.53 +#include "tcp.h"
  494.54 +#include "flocksim.h"
   495.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   495.2 +++ b/src/osdep/unix/os_sua.c	Mon Sep 14 15:17:45 2009 +0900
   495.3 @@ -0,0 +1,54 @@
   495.4 +/* ========================================================================
   495.5 + * Copyright 1988-2007 University of Washington
   495.6 + *
   495.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   495.8 + * you may not use this file except in compliance with the License.
   495.9 + * You may obtain a copy of the License at
  495.10 + *
  495.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  495.12 + *
  495.13 + * 
  495.14 + * ========================================================================
  495.15 + */
  495.16 +
  495.17 +/*
  495.18 + * Program:	Operating-system dependent routines -- Windows Vista SUA
  495.19 + *
  495.20 + * Author:	Mark Crispin
  495.21 + *		Networks and Distributed Computing
  495.22 + *		Computing & Communications
  495.23 + *		University of Washington
  495.24 + *		Administration Building, AG-44
  495.25 + *		Seattle, WA  98195
  495.26 + *		Internet: MRC@CAC.Washington.EDU
  495.27 + *
  495.28 + * Date:	1 August 1993
  495.29 + * Last Edited:	16 August 2007
  495.30 + */
  495.31 + 
  495.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  495.33 +#include "mail.h"
  495.34 +#include "osdep.h"
  495.35 +#include <stdio.h>
  495.36 +#include <sys/time.h>
  495.37 +#include <sys/stat.h>
  495.38 +#include <sys/socket.h>
  495.39 +#include <netinet/in.h>
  495.40 +#include <arpa/inet.h>
  495.41 +#include <netdb.h>
  495.42 +#include <ctype.h>
  495.43 +#include <errno.h>
  495.44 +extern int errno;		/* just in case */
  495.45 +#include <pwd.h>
  495.46 +#include "misc.h"
  495.47 +
  495.48 +
  495.49 +#include "fs_unix.c"
  495.50 +#include "ftl_unix.c"
  495.51 +#include "nl_unix.c"
  495.52 +#include "env_unix.c"
  495.53 +#define fork vfork
  495.54 +#include "tcp_unix.c"
  495.55 +#include "gr_waitp.c"
  495.56 +#include "tz_sv4.c"
  495.57 +#include "gethstid.c"
   496.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   496.2 +++ b/src/osdep/unix/os_sua.h	Mon Sep 14 15:17:45 2009 +0900
   496.3 @@ -0,0 +1,50 @@
   496.4 +/* ========================================================================
   496.5 + * Copyright 1988-2007 University of Washington
   496.6 + *
   496.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   496.8 + * you may not use this file except in compliance with the License.
   496.9 + * You may obtain a copy of the License at
  496.10 + *
  496.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  496.12 + *
  496.13 + * 
  496.14 + * ========================================================================
  496.15 + */
  496.16 +
  496.17 +/*
  496.18 + * Program:	Operating-system dependent routines -- Windows Vista SUA
  496.19 + *
  496.20 + * Author:	Mark Crispin
  496.21 + *		Networks and Distributed Computing
  496.22 + *		Computing & Communications
  496.23 + *		University of Washington
  496.24 + *		Administration Building, AG-44
  496.25 + *		Seattle, WA  98195
  496.26 + *		Internet: MRC@CAC.Washington.EDU
  496.27 + *
  496.28 + * Date:	10 September 1993
  496.29 + * Last Edited:	4 May 2007
  496.30 + */
  496.31 +
  496.32 +#define _REENTRANT		/* for strtok_r() */
  496.33 +#include <stdlib.h>
  496.34 +#include <string.h>
  496.35 +#include <unistd.h>
  496.36 +#include <sys/types.h>
  496.37 +#include <dirent.h>
  496.38 +#include <time.h>		/* for struct tm */
  496.39 +#include <fcntl.h>
  496.40 +#include <syslog.h>
  496.41 +#include <sys/file.h>
  496.42 +
  496.43 +
  496.44 +#define setpgrp setpgid
  496.45 +
  496.46 +#define direct dirent
  496.47 +
  496.48 +
  496.49 +#include "env_unix.h"
  496.50 +#include "fs.h"
  496.51 +#include "ftl.h"
  496.52 +#include "nl.h"
  496.53 +#include "tcp.h"
   497.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   497.2 +++ b/src/osdep/unix/os_sun.c	Mon Sep 14 15:17:45 2009 +0900
   497.3 @@ -0,0 +1,64 @@
   497.4 +/* ========================================================================
   497.5 + * Copyright 1988-2007 University of Washington
   497.6 + *
   497.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   497.8 + * you may not use this file except in compliance with the License.
   497.9 + * You may obtain a copy of the License at
  497.10 + *
  497.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  497.12 + *
  497.13 + * 
  497.14 + * ========================================================================
  497.15 + */
  497.16 +
  497.17 +/*
  497.18 + * Program:	Operating-system dependent routines -- SUN-OS version
  497.19 + *
  497.20 + * Author:	Mark Crispin
  497.21 + *		Networks and Distributed Computing
  497.22 + *		Computing & Communications
  497.23 + *		University of Washington
  497.24 + *		Administration Building, AG-44
  497.25 + *		Seattle, WA  98195
  497.26 + *		Internet: MRC@CAC.Washington.EDU
  497.27 + *
  497.28 + * Date:	11 May 1989
  497.29 + * Last Edited:	16 August 2007
  497.30 + */
  497.31 +
  497.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  497.33 +#include "mail.h"
  497.34 +#include "osdep.h"
  497.35 +#include <stdio.h>
  497.36 +#include <sys/stat.h>
  497.37 +#include <sys/time.h>
  497.38 +#include <sys/socket.h>
  497.39 +#include <netinet/in.h>
  497.40 +#include <arpa/inet.h>
  497.41 +#include <netdb.h>
  497.42 +#include <ctype.h>
  497.43 +#include <errno.h>
  497.44 +extern int errno;		/* just in case */
  497.45 +#include <pwd.h>
  497.46 +#include "misc.h"
  497.47 +
  497.48 +extern int sys_nerr;
  497.49 +extern char *sys_errlist[];
  497.50 +
  497.51 +#define toint(c)	((c)-'0')
  497.52 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  497.53 +
  497.54 +
  497.55 +#include "fs_unix.c"
  497.56 +#include "ftl_unix.c"
  497.57 +#include "nl_unix.c"
  497.58 +#include "env_unix.c"
  497.59 +#define fork vfork
  497.60 +#include "tcp_unix.c"
  497.61 +#include "gr_waitp.c"
  497.62 +#include "memmove.c"
  497.63 +#include "strerror.c"
  497.64 +#define strstr Strstr		/* override SUN's broken version */
  497.65 +#include "strstr.c"
  497.66 +#include "strtoul.c"
  497.67 +#include "tz_bsd.c"
   498.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   498.2 +++ b/src/osdep/unix/os_sun.h	Mon Sep 14 15:17:45 2009 +0900
   498.3 @@ -0,0 +1,51 @@
   498.4 +/* ========================================================================
   498.5 + * Copyright 1988-2006 University of Washington
   498.6 + *
   498.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   498.8 + * you may not use this file except in compliance with the License.
   498.9 + * You may obtain a copy of the License at
  498.10 + *
  498.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  498.12 + *
  498.13 + * 
  498.14 + * ========================================================================
  498.15 + */
  498.16 +
  498.17 +/*
  498.18 + * Program:	Operating-system dependent routines -- SUN-OS version
  498.19 + *
  498.20 + * Author:	Mark Crispin
  498.21 + *		Networks and Distributed Computing
  498.22 + *		Computing & Communications
  498.23 + *		University of Washington
  498.24 + *		Administration Building, AG-44
  498.25 + *		Seattle, WA  98195
  498.26 + *		Internet: MRC@CAC.Washington.EDU
  498.27 + *
  498.28 + * Date:	11 May 1989
  498.29 + * Last Edited:	30 August 2006
  498.30 + */
  498.31 +
  498.32 +#include <sys/types.h>
  498.33 +#include <sys/dir.h>
  498.34 +#include <stdlib.h>
  498.35 +#include <string.h>
  498.36 +#include <fcntl.h>
  498.37 +#include <syslog.h>
  498.38 +#include <sys/file.h>
  498.39 +
  498.40 +
  498.41 +#define strstr Strstr		/* override system definition */
  498.42 +
  498.43 +#include "env_unix.h"
  498.44 +#include "fs.h"
  498.45 +#include "ftl.h"
  498.46 +#include "nl.h"
  498.47 +#include "tcp.h"
  498.48 +
  498.49 +char *Strstr (char *cs,char *ct);
  498.50 +char *strerror (int n);
  498.51 +unsigned long strtoul (char *s,char **endp,int base);
  498.52 +#define memcpy memmove
  498.53 +void *memmove (void *s,void *ct,size_t n);
  498.54 +void *memset (void *s,int c,size_t n);
   499.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   499.2 +++ b/src/osdep/unix/os_sv2.c	Mon Sep 14 15:17:45 2009 +0900
   499.3 @@ -0,0 +1,128 @@
   499.4 +/* ========================================================================
   499.5 + * Copyright 1988-2006 University of Washington
   499.6 + *
   499.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   499.8 + * you may not use this file except in compliance with the License.
   499.9 + * You may obtain a copy of the License at
  499.10 + *
  499.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  499.12 + *
  499.13 + * 
  499.14 + * ========================================================================
  499.15 + */
  499.16 +
  499.17 +/*
  499.18 + * Program:	Operating-system dependent routines -- SVR2 version
  499.19 + *
  499.20 + * Author:	Mark Crispin
  499.21 + *		Networks and Distributed Computing
  499.22 + *		Computing & Communications
  499.23 + *		University of Washington
  499.24 + *		Administration Building, AG-44
  499.25 + *		Seattle, WA  98195
  499.26 + *		Internet: MRC@CAC.Washington.EDU
  499.27 + *
  499.28 + * Date:	10 April 1992
  499.29 + * Last Edited:	30 August 2006
  499.30 + */
  499.31 +
  499.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  499.33 +#include "mail.h"
  499.34 +#include "osdep.h"
  499.35 +#include <ctype.h>
  499.36 +#include <stdio.h>
  499.37 +#include <sys/stat.h>
  499.38 +#include <netinet/in.h>
  499.39 +#include <arpa/inet.h>
  499.40 +#include <netdb.h>
  499.41 +#include <errno.h>
  499.42 +extern int errno;
  499.43 +#include <pwd.h>
  499.44 +#include <sys/socket.h>
  499.45 +#include <time.h>
  499.46 +#define KERNEL
  499.47 +#include <sys/time.h>
  499.48 +#undef KERNEL
  499.49 +#include "misc.h"
  499.50 +
  499.51 +#define DIR_SIZE(d) sizeof (DIR)
  499.52 +
  499.53 +extern int sys_nerr;
  499.54 +extern char *sys_errlist[];
  499.55 +
  499.56 +#define toint(c)	((c)-'0')
  499.57 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  499.58 +
  499.59 +#define	NBBY	8	/* number of bits in a byte */
  499.60 +#define	FD_SETSIZE	256
  499.61 +
  499.62 +typedef long	fd_mask;
  499.63 +#define NFDBITS	(sizeof(fd_mask) * NBBY)
  499.64 +					/* bits per mask */
  499.65 +#define	howmany(x, y)	(((x)+((y)-1))/(y))
  499.66 +
  499.67 +typedef	struct fd_set {
  499.68 +  fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
  499.69 +} fd_set;
  499.70 +
  499.71 +#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= \
  499.72 +					(1 << ((n) % NFDBITS)))
  499.73 +#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= \
  499.74 +					~(1 << ((n) % NFDBITS)))
  499.75 +#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & \
  499.76 +					(1 << ((n) % NFDBITS)))
  499.77 +#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
  499.78 +
  499.79 +
  499.80 +#include "fs_unix.c"
  499.81 +#include "ftl_unix.c"
  499.82 +#include "nl_unix.c"
  499.83 +#include "env_unix.c"
  499.84 +#include "tcp_unix.c"
  499.85 +#include "gr_wait.c"
  499.86 +#include "flocksim.c"
  499.87 +#include "opendir.c"
  499.88 +#include "scandir.c"
  499.89 +#include "memmove2.c"
  499.90 +#include "strstr.c"
  499.91 +#include "strerror.c"
  499.92 +#include "strtoul.c"
  499.93 +#include "tz_sv4.c"
  499.94 +#include "gethstid.c"
  499.95 +#include "fsync.c"
  499.96 +#undef setpgrp
  499.97 +#include "setpgrp.c"
  499.98 +
  499.99 +/* Emulator for BSD syslog() routine
 499.100 + * Accepts: priority
 499.101 + *	    message
 499.102 + *	    parameters
 499.103 + */
 499.104 +
 499.105 +int syslog (int priority,char *message,char *parameters)
 499.106 +{
 499.107 +  /* nothing here for now */
 499.108 +}
 499.109 +
 499.110 +
 499.111 +/* Emulator for BSD openlog() routine
 499.112 + * Accepts: identity
 499.113 + *	    options
 499.114 + *	    facility
 499.115 + */
 499.116 +
 499.117 +int openlog (char *ident,int logopt,int facility)
 499.118 +{
 499.119 +  /* nothing here for now */
 499.120 +}
 499.121 +
 499.122 +
 499.123 +/* Emulator for BSD ftruncate() routine
 499.124 + * Accepts: file descriptor
 499.125 + *	    length
 499.126 + */
 499.127 +
 499.128 +int ftruncate (int fd,unsigned long length)
 499.129 +{
 499.130 +  return -1;			/* gotta figure out how to do this */
 499.131 +}
   500.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   500.2 +++ b/src/osdep/unix/os_sv2.h	Mon Sep 14 15:17:45 2009 +0900
   500.3 @@ -0,0 +1,120 @@
   500.4 +/* ========================================================================
   500.5 + * Copyright 1988-2006 University of Washington
   500.6 + *
   500.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   500.8 + * you may not use this file except in compliance with the License.
   500.9 + * You may obtain a copy of the License at
  500.10 + *
  500.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  500.12 + *
  500.13 + * 
  500.14 + * ========================================================================
  500.15 + */
  500.16 +
  500.17 +/*
  500.18 + * Program:	Operating-system dependent routines -- SVR2 version
  500.19 + *
  500.20 + * Author:	Mark Crispin
  500.21 + *		Networks and Distributed Computing
  500.22 + *		Computing & Communications
  500.23 + *		University of Washington
  500.24 + *		Administration Building, AG-44
  500.25 + *		Seattle, WA  98195
  500.26 + *		Internet: MRC@CAC.Washington.EDU
  500.27 + *
  500.28 + * Date:	10 April 1992
  500.29 + * Last Edited:	20 December 2006
  500.30 + */
  500.31 +
  500.32 +#include <unistd.h>
  500.33 +#include <string.h>
  500.34 +#define char void
  500.35 +#include <memory.h>
  500.36 +#undef char
  500.37 +#include <sys/types.h>
  500.38 +#include <sys/dir.h>
  500.39 +#include <fcntl.h>
  500.40 +#include <syslog.h>
  500.41 +#include <sys/file.h>
  500.42 +#include <ustat.h>
  500.43 +
  500.44 +
  500.45 +/* Many versions of SysV get this wrong */
  500.46 +
  500.47 +#define setpgrp(a,b) Setpgrp(a,b)
  500.48 +int Setpgrp (int pid,int gid);
  500.49 +
  500.50 +
  500.51 +/* Different names between BSD and SVR4 */
  500.52 +
  500.53 +#define L_SET SEEK_SET
  500.54 +#define L_INCR SEEK_CUR
  500.55 +#define L_XTND SEEK_END
  500.56 +
  500.57 +#define lstat stat
  500.58 +#define random lrand48
  500.59 +
  500.60 +#define SIGSTOP SIGQUIT
  500.61 +
  500.62 +#define S_IFLNK 0120000
  500.63 +
  500.64 +
  500.65 +/* syslog() emulation */
  500.66 +
  500.67 +#define LOG_MAIL	(2<<3)	/* mail system */
  500.68 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  500.69 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  500.70 +#define LOG_ALERT	1	/* action must be taken immediately */
  500.71 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  500.72 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  500.73 +#define LOG_NDELAY	0x08	/* don't delay open */
  500.74 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  500.75 +
  500.76 +
  500.77 +/* For setitimer() emulation */
  500.78 +
  500.79 +#define ITIMER_REAL	0
  500.80 +
  500.81 +
  500.82 +/* For opendir() emulation */
  500.83 +
  500.84 +typedef struct _dirdesc {
  500.85 +  int dd_fd;
  500.86 +  long dd_loc;
  500.87 +  long dd_size;
  500.88 +  char *dd_buf;
  500.89 +} DIR;
  500.90 +
  500.91 +struct passwd *getpwent (void);
  500.92 +struct passwd *getpwuid (int uid);
  500.93 +struct passwd *getpwnam (char *name);
  500.94 +struct group *getgrnam (char *name);
  500.95 +
  500.96 +char *getenv (char *name);
  500.97 +long gethostid (void);
  500.98 +void *memmove (void *s,void *ct,size_t n);
  500.99 +char *strstr (char *cs,char *ct);
 500.100 +char *strerror (int n);
 500.101 +unsigned long strtoul (char *s,char **endp,int base);
 500.102 +DIR *opendir (char * name);
 500.103 +int closedir (DIR *d);
 500.104 +struct direct *readdir (DIR *d);
 500.105 +typedef int (*select_t) (struct direct *name);
 500.106 +typedef int (*compar_t) (void *d1,void *d2);
 500.107 +int scandir (char *dirname,struct direct ***namelist,select_t select,
 500.108 +	     compar_t compar);
 500.109 +int alphasort (void *d1,void *d2);
 500.110 +int fsync (int fd);
 500.111 +int openlog (ident,logopt,facility);
 500.112 +int syslog (priority,message,parameters ...);
 500.113 +void *malloc (size_t byteSize);
 500.114 +void free (void *ptr);
 500.115 +void *realloc (void *oldptr,size_t newsize);
 500.116 +
 500.117 +
 500.118 +#include "env_unix.h"
 500.119 +#include "fs.h"
 500.120 +#include "ftl.h"
 500.121 +#include "nl.h"
 500.122 +#include "tcp.h"
 500.123 +#include "flocksim.h"
   501.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   501.2 +++ b/src/osdep/unix/os_sv4.c	Mon Sep 14 15:17:45 2009 +0900
   501.3 @@ -0,0 +1,68 @@
   501.4 +/* ========================================================================
   501.5 + * Copyright 1988-2006 University of Washington
   501.6 + *
   501.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   501.8 + * you may not use this file except in compliance with the License.
   501.9 + * You may obtain a copy of the License at
  501.10 + *
  501.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  501.12 + *
  501.13 + * 
  501.14 + * ========================================================================
  501.15 + */
  501.16 +
  501.17 +/*
  501.18 + * Program:	Operating-system dependent routines -- SVR4 version
  501.19 + *
  501.20 + * Author:	Mark Crispin
  501.21 + *		Networks and Distributed Computing
  501.22 + *		Computing & Communications
  501.23 + *		University of Washington
  501.24 + *		Administration Building, AG-44
  501.25 + *		Seattle, WA  98195
  501.26 + *		Internet: MRC@CAC.Washington.EDU
  501.27 + *
  501.28 + * Date:	10 April 1992
  501.29 + * Last Edited:	30 August 2006
  501.30 + */
  501.31 +
  501.32 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  501.33 +#include "mail.h"
  501.34 +#include "osdep.h"
  501.35 +#include <ctype.h>
  501.36 +#include <stdio.h>
  501.37 +#include <sys/stat.h>
  501.38 +#include <sys/tiuser.h>
  501.39 +#include <sys/stropts.h>
  501.40 +#include <netinet/in.h>
  501.41 +#include <arpa/inet.h>
  501.42 +#include <netdb.h>
  501.43 +#include <errno.h>
  501.44 +#include <pwd.h>
  501.45 +#include <shadow.h>
  501.46 +#include <sys/socket.h>
  501.47 +#include <sys/select.h>
  501.48 +#include "misc.h"
  501.49 +
  501.50 +extern int sys_nerr;
  501.51 +extern char *sys_errlist[];
  501.52 +
  501.53 +#define DIR_SIZE(d) d->d_reclen
  501.54 +
  501.55 +#define toint(c)	((c)-'0')
  501.56 +#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
  501.57 +
  501.58 +
  501.59 +#include "fs_unix.c"
  501.60 +#include "ftl_unix.c"
  501.61 +#include "nl_unix.c"
  501.62 +#include "env_unix.c"
  501.63 +#include "tcp_unix.c"
  501.64 +#include "gr_waitp.c"
  501.65 +#include "flocksim.c"
  501.66 +#include "scandir.c"
  501.67 +#include "tz_sv4.c"
  501.68 +#include "gethstid.c"
  501.69 +#undef setpgrp
  501.70 +#include "setpgrp.c"
  501.71 +#include "utime.c"
   502.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   502.2 +++ b/src/osdep/unix/os_sv4.h	Mon Sep 14 15:17:45 2009 +0900
   502.3 @@ -0,0 +1,78 @@
   502.4 +/* ========================================================================
   502.5 + * Copyright 1988-2006 University of Washington
   502.6 + *
   502.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   502.8 + * you may not use this file except in compliance with the License.
   502.9 + * You may obtain a copy of the License at
  502.10 + *
  502.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  502.12 + *
  502.13 + * 
  502.14 + * ========================================================================
  502.15 + */
  502.16 +
  502.17 +/*
  502.18 + * Program:	Operating-system dependent routines -- SVR4 version
  502.19 + *
  502.20 + * Author:	Mark Crispin
  502.21 + *		Networks and Distributed Computing
  502.22 + *		Computing & Communications
  502.23 + *		University of Washington
  502.24 + *		Administration Building, AG-44
  502.25 + *		Seattle, WA  98195
  502.26 + *		Internet: MRC@CAC.Washington.EDU
  502.27 + *
  502.28 + * Date:	10 April 1992
  502.29 + * Last Edited:	20 December 2006
  502.30 + */
  502.31 +
  502.32 +#include <string.h>
  502.33 +
  502.34 +#include <sys/types.h>
  502.35 +#include <stdlib.h>
  502.36 +#include <dirent.h>
  502.37 +#include <fcntl.h>
  502.38 +#include <unistd.h>
  502.39 +#include <time.h>
  502.40 +#include <utime.h>
  502.41 +#include <syslog.h>
  502.42 +#include <sys/file.h>
  502.43 +#include <ustat.h>
  502.44 +
  502.45 +
  502.46 +/* Many versions of SysV get this wrong */
  502.47 +
  502.48 +#define setpgrp(a,b) Setpgrp(a,b)
  502.49 +int Setpgrp (int pid,int gid);
  502.50 +
  502.51 +
  502.52 +/* Different names, equivalent things in BSD and SysV */
  502.53 +
  502.54 +/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
  502.55 +#ifndef L_SET
  502.56 +#define L_SET SEEK_SET
  502.57 +#endif
  502.58 +#define L_INCR SEEK_CUR
  502.59 +#define L_XTND SEEK_END
  502.60 +
  502.61 +#define direct dirent
  502.62 +#define random lrand48
  502.63 +
  502.64 +
  502.65 +#define utime portable_utime
  502.66 +int portable_utime (char *file,time_t timep[2]);
  502.67 +
  502.68 +long gethostid (void);
  502.69 +typedef int (*select_t) (struct direct *name);
  502.70 +typedef int (*compar_t) (void *d1,void *d2);
  502.71 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  502.72 +	     compar_t compar);
  502.73 +int alphasort (void *d1,void *d2);
  502.74 +
  502.75 +
  502.76 +#include "env_unix.h"
  502.77 +#include "fs.h"
  502.78 +#include "ftl.h"
  502.79 +#include "nl.h"
  502.80 +#include "tcp.h"
  502.81 +#include "flocksim.h"
   503.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   503.2 +++ b/src/osdep/unix/os_ult.c	Mon Sep 14 15:17:45 2009 +0900
   503.3 @@ -0,0 +1,52 @@
   503.4 +/* ========================================================================
   503.5 + * Copyright 1988-2007 University of Washington
   503.6 + *
   503.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   503.8 + * you may not use this file except in compliance with the License.
   503.9 + * You may obtain a copy of the License at
  503.10 + *
  503.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  503.12 + *
  503.13 + * 
  503.14 + * ========================================================================
  503.15 + */
  503.16 +
  503.17 +/*
  503.18 + * Program:	Operating-system dependent routines -- Ultrix version
  503.19 + *
  503.20 + * Author:	Mark Crispin
  503.21 + *		Networks and Distributed Computing
  503.22 + *		Computing & Communications
  503.23 + *		University of Washington
  503.24 + *		Administration Building, AG-44
  503.25 + *		Seattle, WA  98195
  503.26 + *
  503.27 + * Date:	11 May 1989
  503.28 + * Last Edited:	16 August 2007
  503.29 + */
  503.30 +
  503.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  503.32 +#include "mail.h"
  503.33 +#include "osdep.h"
  503.34 +#include <stdio.h>
  503.35 +#include <sys/stat.h>
  503.36 +#include <sys/time.h>
  503.37 +#include <sys/socket.h>
  503.38 +#include <netinet/in.h>
  503.39 +#include <arpa/inet.h>
  503.40 +#include <netdb.h>
  503.41 +#include <ctype.h>
  503.42 +#include <errno.h>
  503.43 +extern int errno;		/* just in case */
  503.44 +#include <pwd.h>
  503.45 +#include "misc.h"
  503.46 +
  503.47 +
  503.48 +#include "fs_unix.c"
  503.49 +#include "ftl_unix.c"
  503.50 +#include "nl_unix.c"
  503.51 +#include "env_unix.c"
  503.52 +#define fork vfork
  503.53 +#include "tcp_unix.c"
  503.54 +#include "gr_waitp.c"
  503.55 +#include "tz_bsd.c"
   504.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   504.2 +++ b/src/osdep/unix/os_ult.h	Mon Sep 14 15:17:45 2009 +0900
   504.3 @@ -0,0 +1,42 @@
   504.4 +/* ========================================================================
   504.5 + * Copyright 1988-2006 University of Washington
   504.6 + *
   504.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   504.8 + * you may not use this file except in compliance with the License.
   504.9 + * You may obtain a copy of the License at
  504.10 + *
  504.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  504.12 + *
  504.13 + * 
  504.14 + * ========================================================================
  504.15 + */
  504.16 +
  504.17 +/*
  504.18 + * Program:	Operating-system dependent routines -- Ultrix version
  504.19 + *
  504.20 + * Author:	Mark Crispin
  504.21 + *		Networks and Distributed Computing
  504.22 + *		Computing & Communications
  504.23 + *		University of Washington
  504.24 + *		Administration Building, AG-44
  504.25 + *		Seattle, WA  98195
  504.26 + *		Internet: MRC@CAC.Washington.EDU
  504.27 + *
  504.28 + * Date:	11 May 1989
  504.29 + * Last Edited:	30 August 2006
  504.30 + */
  504.31 +
  504.32 +#include <sys/types.h>
  504.33 +#include <sys/dir.h>
  504.34 +#include <stdlib.h>
  504.35 +#include <string.h>
  504.36 +#include <fcntl.h>
  504.37 +#include <sys/syslog.h>
  504.38 +#include <sys/file.h>
  504.39 +
  504.40 +
  504.41 +#include "env_unix.h"
  504.42 +#include "fs.h"
  504.43 +#include "ftl.h"
  504.44 +#include "nl.h"
  504.45 +#include "tcp.h"
   505.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   505.2 +++ b/src/osdep/unix/os_vu2.c	Mon Sep 14 15:17:45 2009 +0900
   505.3 @@ -0,0 +1,82 @@
   505.4 +/* ========================================================================
   505.5 + * Copyright 1988-2007 University of Washington
   505.6 + *
   505.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   505.8 + * you may not use this file except in compliance with the License.
   505.9 + * You may obtain a copy of the License at
  505.10 + *
  505.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  505.12 + *
  505.13 + * 
  505.14 + * ========================================================================
  505.15 + */
  505.16 +
  505.17 +/*
  505.18 + * Program:	Operating-system dependent routines -- VAX Ultrix 2.3 version
  505.19 + *
  505.20 + * Author:	Mark Crispin
  505.21 + *		Networks and Distributed Computing
  505.22 + *		Computing & Communications
  505.23 + *		University of Washington
  505.24 + *		Administration Building, AG-44
  505.25 + *		Seattle, WA  98195
  505.26 + *
  505.27 + * Date:	11 May 1989
  505.28 + * Last Edited:	16 August 2007
  505.29 + */
  505.30 +
  505.31 +#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
  505.32 +#include "mail.h"
  505.33 +#include "osdep.h"
  505.34 +#include <stdio.h>
  505.35 +#include <sys/stat.h>
  505.36 +#include <sys/time.h>
  505.37 +#include <sys/socket.h>
  505.38 +#include <netinet/in.h>
  505.39 +#include <arpa/inet.h>
  505.40 +#include <netdb.h>
  505.41 +#include <ctype.h>
  505.42 +#include <errno.h>
  505.43 +extern int errno;		/* just in case */
  505.44 +#include <pwd.h>
  505.45 +#include "misc.h"
  505.46 +
  505.47 +#define NFDBITS	(sizeof(long) * 8)
  505.48 +
  505.49 +#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= \
  505.50 +					(1 << ((n) % NFDBITS)))
  505.51 +#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= \
  505.52 +					~(1 << ((n) % NFDBITS)))
  505.53 +#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & \
  505.54 +					(1 << ((n) % NFDBITS)))
  505.55 +#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
  505.56 +
  505.57 +
  505.58 +/* Old Ultrix has its own wierd inet_addr() that returns a in_addr struct. */
  505.59 +
  505.60 +/* Portable inet_addr () that returns a u_long
  505.61 + * Accepts: dotted host string
  505.62 + * Returns: u_long
  505.63 + */
  505.64 +
  505.65 +u_long portable_inet_addr (char *hostname)
  505.66 +{
  505.67 +  struct in_addr *in = &inet_addr (hostname);
  505.68 +  return in->s_addr;
  505.69 +}
  505.70 +
  505.71 +
  505.72 +#define inet_addr portable_inet_addr
  505.73 +
  505.74 +#include "fs_unix.c"
  505.75 +#include "ftl_unix.c"
  505.76 +#include "nl_unix.c"
  505.77 +#include "env_unix.c"
  505.78 +#define fork vfork
  505.79 +#include "tcp_unix.c"
  505.80 +#include "gr_wait.c"
  505.81 +#include "memmove.c"
  505.82 +#include "strerror.c"
  505.83 +#include "strstr.c"
  505.84 +#include "strtoul.c"
  505.85 +#include "tz_nul.c"
   506.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   506.2 +++ b/src/osdep/unix/os_vu2.h	Mon Sep 14 15:17:45 2009 +0900
   506.3 @@ -0,0 +1,79 @@
   506.4 +/* ========================================================================
   506.5 + * Copyright 1988-2006 University of Washington
   506.6 + *
   506.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   506.8 + * you may not use this file except in compliance with the License.
   506.9 + * You may obtain a copy of the License at
  506.10 + *
  506.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  506.12 + *
  506.13 + * 
  506.14 + * ========================================================================
  506.15 + */
  506.16 +
  506.17 +/*
  506.18 + * Program:	Operating-system dependent routines -- VAX Ultrix 2.3 version
  506.19 + *
  506.20 + * Author:	Mark Crispin
  506.21 + *		Networks and Distributed Computing
  506.22 + *		Computing & Communications
  506.23 + *		University of Washington
  506.24 + *		Administration Building, AG-44
  506.25 + *		Seattle, WA  98195
  506.26 + *		Internet: MRC@CAC.Washington.EDU
  506.27 + *
  506.28 + * Date:	11 May 1989
  506.29 + * Last Edited:	30 August 2006
  506.30 + */
  506.31 +
  506.32 +#include <memory.h>
  506.33 +#include <sys/types.h>
  506.34 +#include <sys/dir.h>
  506.35 +#include <string.h>
  506.36 +#include <fcntl.h>
  506.37 +#include <syslog.h>
  506.38 +#include <sys/file.h>
  506.39 +
  506.40 +
  506.41 +/* syslog() emulation */
  506.42 +
  506.43 +#define LOG_MAIL	(2<<3)	/* mail system */
  506.44 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  506.45 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  506.46 +#define LOG_EMERG	0	/* system is unusable */
  506.47 +#define LOG_ALERT	1	/* action must be taken immediately */
  506.48 +#define LOG_CRIT	2	/* critical conditions */
  506.49 +#define LOG_ERR		3	/* error conditions */
  506.50 +#define LOG_WARNING	4	/* warning conditions */
  506.51 +#define LOG_NOTICE	5	/* normal but signification condition */
  506.52 +#define LOG_INFO	6	/* informational */
  506.53 +#define LOG_DEBUG	7	/* debug-level messages */
  506.54 +#define LOG_PID		0x01	/* log the pid with each message */
  506.55 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  506.56 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  506.57 +#define LOG_NDELAY	0x08	/* don't delay open */
  506.58 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  506.59 +
  506.60 +
  506.61 +#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  506.62 +#define toint(c)       ((c)-'0')
  506.63 +
  506.64 +extern int sys_nerr;
  506.65 +extern char *sys_errlist[];
  506.66 +
  506.67 +
  506.68 +char *getenv (char *name);
  506.69 +char *strstr (char *cs,char *ct);
  506.70 +char *strerror (int n);
  506.71 +void *memmove (void *s,void *ct,size_t n);
  506.72 +unsigned long strtoul (char *s,char **endp,int base);
  506.73 +void *malloc (size_t byteSize);
  506.74 +void free (void *ptr);
  506.75 +void *realloc (void *oldptr,size_t newsize);
  506.76 +u_long portable_inet_addr (char *hostname);
  506.77 +
  506.78 +#include "env_unix.h"
  506.79 +#include "fs.h"
  506.80 +#include "ftl.h"
  506.81 +#include "nl.h"
  506.82 +#include "tcp.h"
   507.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   507.2 +++ b/src/osdep/unix/phile.c	Mon Sep 14 15:17:45 2009 +0900
   507.3 @@ -0,0 +1,553 @@
   507.4 +/* ========================================================================
   507.5 + * Copyright 1988-2006 University of Washington
   507.6 + *
   507.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   507.8 + * you may not use this file except in compliance with the License.
   507.9 + * You may obtain a copy of the License at
  507.10 + *
  507.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  507.12 + *
  507.13 + * 
  507.14 + * ========================================================================
  507.15 + */
  507.16 +
  507.17 +/*
  507.18 + * Program:	File routines
  507.19 + *
  507.20 + * Author:	Mark Crispin
  507.21 + *		Networks and Distributed Computing
  507.22 + *		Computing & Communications
  507.23 + *		University of Washington
  507.24 + *		Administration Building, AG-44
  507.25 + *		Seattle, WA  98195
  507.26 + *		Internet: MRC@CAC.Washington.EDU
  507.27 + *
  507.28 + * Date:	25 August 1993
  507.29 + * Last Edited:	9 May 2006
  507.30 + */
  507.31 +
  507.32 +
  507.33 +#include <stdio.h>
  507.34 +#include <ctype.h>
  507.35 +#include <errno.h>
  507.36 +extern int errno;		/* just in case */
  507.37 +#include <signal.h>
  507.38 +#include "mail.h"
  507.39 +#include "osdep.h"
  507.40 +#include <pwd.h>
  507.41 +#include <sys/stat.h>
  507.42 +#include <sys/time.h>
  507.43 +#include "rfc822.h"
  507.44 +#include "misc.h"
  507.45 +#include "dummy.h"
  507.46 +
  507.47 +/* Types returned from phile_type() */
  507.48 +
  507.49 +#define PTYPEBINARY 0		/* binary data */
  507.50 +#define PTYPETEXT 1		/* textual data */
  507.51 +#define PTYPECRTEXT 2		/* textual data with CR */
  507.52 +#define PTYPE8 4		/* textual 8bit data */
  507.53 +#define PTYPEISO2022JP 8	/* textual Japanese */
  507.54 +#define PTYPEISO2022KR 16	/* textual Korean */
  507.55 +#define PTYPEISO2022CN 32	/* textual Chinese */
  507.56 +
  507.57 +
  507.58 +/* PHILE I/O stream local data */
  507.59 +	
  507.60 +typedef struct phile_local {
  507.61 +  ENVELOPE *env;		/* file envelope */
  507.62 +  BODY *body;			/* file body */
  507.63 +  char tmp[MAILTMPLEN];		/* temporary buffer */
  507.64 +} PHILELOCAL;
  507.65 +
  507.66 +
  507.67 +/* Convenient access to local data */
  507.68 +
  507.69 +#define LOCAL ((PHILELOCAL *) stream->local)
  507.70 +
  507.71 +
  507.72 +/* Function prototypes */
  507.73 +
  507.74 +DRIVER *phile_valid (char *name);
  507.75 +int phile_isvalid (char *name,char *tmp);
  507.76 +void *phile_parameters (long function,void *value);
  507.77 +void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  507.78 +void phile_list (MAILSTREAM *stream,char *ref,char *pat);
  507.79 +void phile_lsub (MAILSTREAM *stream,char *ref,char *pat);
  507.80 +long phile_create (MAILSTREAM *stream,char *mailbox);
  507.81 +long phile_delete (MAILSTREAM *stream,char *mailbox);
  507.82 +long phile_rename (MAILSTREAM *stream,char *old,char *newname);
  507.83 +long phile_status (MAILSTREAM *stream,char *mbx,long flags);
  507.84 +MAILSTREAM *phile_open (MAILSTREAM *stream);
  507.85 +int phile_type (unsigned char *s,unsigned long i,unsigned long *j);
  507.86 +void phile_close (MAILSTREAM *stream,long options);
  507.87 +ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
  507.88 +			   long flags);
  507.89 +char *phile_header (MAILSTREAM *stream,unsigned long msgno,
  507.90 +		    unsigned long *length,long flags);
  507.91 +long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  507.92 +long phile_ping (MAILSTREAM *stream);
  507.93 +void phile_check (MAILSTREAM *stream);
  507.94 +long phile_expunge (MAILSTREAM *stream,char *sequence,long options);
  507.95 +long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  507.96 +long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  507.97 +
  507.98 +/* File routines */
  507.99 +
 507.100 +
 507.101 +/* Driver dispatch used by MAIL */
 507.102 +
 507.103 +DRIVER philedriver = {
 507.104 +  "phile",			/* driver name */
 507.105 +				/* driver flags */
 507.106 +  DR_LOCAL|DR_READONLY|DR_NOSTICKY,
 507.107 +  (DRIVER *) NIL,		/* next driver */
 507.108 +  phile_valid,			/* mailbox is valid for us */
 507.109 +  phile_parameters,		/* manipulate parameters */
 507.110 +  phile_scan,			/* scan mailboxes */
 507.111 +  phile_list,			/* list mailboxes */
 507.112 +  phile_lsub,			/* list subscribed mailboxes */
 507.113 +  NIL,				/* subscribe to mailbox */
 507.114 +  NIL,				/* unsubscribe from mailbox */
 507.115 +  dummy_create,			/* create mailbox */
 507.116 +  dummy_delete,			/* delete mailbox */
 507.117 +  dummy_rename,			/* rename mailbox */
 507.118 +  phile_status,			/* status of mailbox */
 507.119 +  phile_open,			/* open mailbox */
 507.120 +  phile_close,			/* close mailbox */
 507.121 +  NIL,				/* fetch message "fast" attributes */
 507.122 +  NIL,				/* fetch message flags */
 507.123 +  NIL,				/* fetch overview */
 507.124 +  phile_structure,		/* fetch message envelopes */
 507.125 +  phile_header,			/* fetch message header only */
 507.126 +  phile_text,			/* fetch message body only */
 507.127 +  NIL,				/* fetch partial message text */
 507.128 +  NIL,				/* unique identifier */
 507.129 +  NIL,				/* message number */
 507.130 +  NIL,				/* modify flags */
 507.131 +  NIL,				/* per-message modify flags */
 507.132 +  NIL,				/* search for message based on criteria */
 507.133 +  NIL,				/* sort messages */
 507.134 +  NIL,				/* thread messages */
 507.135 +  phile_ping,			/* ping mailbox to see if still alive */
 507.136 +  phile_check,			/* check for new messages */
 507.137 +  phile_expunge,		/* expunge deleted messages */
 507.138 +  phile_copy,			/* copy messages to another mailbox */
 507.139 +  phile_append,			/* append string message to mailbox */
 507.140 +  NIL				/* garbage collect stream */
 507.141 +};
 507.142 +
 507.143 +				/* prototype stream */
 507.144 +MAILSTREAM phileproto = {&philedriver};
 507.145 +
 507.146 +/* File validate mailbox
 507.147 + * Accepts: mailbox name
 507.148 + * Returns: our driver if name is valid, NIL otherwise
 507.149 + */
 507.150 +
 507.151 +DRIVER *phile_valid (char *name)
 507.152 +{
 507.153 +  char tmp[MAILTMPLEN];
 507.154 +  return phile_isvalid (name,tmp) ? &philedriver : NIL;
 507.155 +}
 507.156 +
 507.157 +
 507.158 +/* File test for valid mailbox
 507.159 + * Accepts: mailbox name
 507.160 + * Returns: T if valid, NIL otherwise
 507.161 + */
 507.162 +
 507.163 +int phile_isvalid (char *name,char *tmp)
 507.164 +{
 507.165 +  struct stat sbuf;
 507.166 +  char *s;
 507.167 +				/* INBOX never accepted, any other name is */
 507.168 +  return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) &&
 507.169 +	  !(sbuf.st_mode & S_IFDIR) &&
 507.170 +				/* only allow empty files if no empty proto
 507.171 +				   or if #ftp */
 507.172 +	  (sbuf.st_size || !default_proto (T) ||
 507.173 +	   ((*name == '#') && ((name[1] == 'f') || (name[1] == 'F')) &&
 507.174 +	    ((name[2] == 't') || (name[2] == 'T')) &&
 507.175 +	    ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/'))));
 507.176 +}
 507.177 +
 507.178 +/* File manipulate driver parameters
 507.179 + * Accepts: function code
 507.180 + *	    function-dependent value
 507.181 + * Returns: function-dependent return value
 507.182 + */
 507.183 +
 507.184 +void *phile_parameters (long function,void *value)
 507.185 +{
 507.186 +  return NIL;
 507.187 +}
 507.188 +
 507.189 +/* File mail scan mailboxes
 507.190 + * Accepts: mail stream
 507.191 + *	    reference
 507.192 + *	    pattern to search
 507.193 + *	    string to scan
 507.194 + */
 507.195 +
 507.196 +void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 507.197 +{
 507.198 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 507.199 +}
 507.200 +
 507.201 +
 507.202 +/* File list mailboxes
 507.203 + * Accepts: mail stream
 507.204 + *	    reference
 507.205 + *	    pattern to search
 507.206 + */
 507.207 +
 507.208 +void phile_list (MAILSTREAM *stream,char *ref,char *pat)
 507.209 +{
 507.210 +  if (stream) dummy_list (NIL,ref,pat);
 507.211 +}
 507.212 +
 507.213 +
 507.214 +/* File list subscribed mailboxes
 507.215 + * Accepts: mail stream
 507.216 + *	    reference
 507.217 + *	    pattern to search
 507.218 + */
 507.219 +
 507.220 +void phile_lsub (MAILSTREAM *stream,char *ref,char *pat)
 507.221 +{
 507.222 +  if (stream) dummy_lsub (NIL,ref,pat);
 507.223 +}
 507.224 +
 507.225 +
 507.226 +/* File status
 507.227 + * Accepts: mail stream
 507.228 + *	    mailbox name
 507.229 + *	    status flags
 507.230 + * Returns: T on success, NIL on failure
 507.231 + */
 507.232 +
 507.233 +long phile_status (MAILSTREAM *stream,char *mbx,long flags)
 507.234 +{
 507.235 +  char *s,tmp[MAILTMPLEN];
 507.236 +  MAILSTATUS status;
 507.237 +  struct stat sbuf;
 507.238 +  long ret = NIL;
 507.239 +  if ((s = mailboxfile (tmp,mbx)) && *s && !stat (s,&sbuf)) {
 507.240 +    status.flags = flags;	/* return status values */
 507.241 +    status.unseen = (stream && mail_elt (stream,1)->seen) ? 0 : 1;
 507.242 +    status.messages = status.recent = status.uidnext = 1;
 507.243 +    status.uidvalidity = sbuf.st_mtime;
 507.244 +				/* pass status to main program */
 507.245 +    mm_status (stream,mbx,&status);
 507.246 +    ret = LONGT;		/* success */
 507.247 +  }
 507.248 +  return ret;
 507.249 +}
 507.250 +
 507.251 +/* File open
 507.252 + * Accepts: Stream to open
 507.253 + * Returns: Stream on success, NIL on failure
 507.254 + */
 507.255 +
 507.256 +MAILSTREAM *phile_open (MAILSTREAM *stream)
 507.257 +{
 507.258 +  int i,k,fd;
 507.259 +  unsigned long j,m;
 507.260 +  char *s,tmp[MAILTMPLEN];
 507.261 +  struct passwd *pw;
 507.262 +  struct stat sbuf;
 507.263 +  struct tm *t;
 507.264 +  MESSAGECACHE *elt;
 507.265 +  SIZEDTEXT *buf;
 507.266 +				/* return prototype for OP_PROTOTYPE call */
 507.267 +  if (!stream) return &phileproto;
 507.268 +  if (stream->local) fatal ("phile recycle stream");
 507.269 +				/* open associated file */
 507.270 +  if (!mailboxfile (tmp,stream->mailbox) || !tmp[0] || stat (tmp,&sbuf) ||
 507.271 +      (fd = open (tmp,O_RDONLY,NIL)) < 0) {
 507.272 +    sprintf (tmp,"Unable to open file %s",stream->mailbox);
 507.273 +    mm_log (tmp,ERROR);
 507.274 +    return NIL;
 507.275 +  }
 507.276 +  fs_give ((void **) &stream->mailbox);
 507.277 +  stream->mailbox = cpystr (tmp);
 507.278 +  stream->local = fs_get (sizeof (PHILELOCAL));
 507.279 +  mail_exists (stream,1);	/* make sure upper level knows */
 507.280 +  mail_recent (stream,1);
 507.281 +  elt = mail_elt (stream,1);	/* instantiate cache element */
 507.282 +  elt->valid = elt->recent = T;	/* mark valid flags */
 507.283 +  stream->sequence++;		/* bump sequence number */
 507.284 +  stream->rdonly = T;		/* make sure upper level knows readonly */
 507.285 +				/* instantiate a new envelope and body */
 507.286 +  LOCAL->env = mail_newenvelope ();
 507.287 +  LOCAL->body = mail_newbody ();
 507.288 +
 507.289 +  t = gmtime (&sbuf.st_mtime);	/* get UTC time and Julian day */
 507.290 +  i = t->tm_hour * 60 + t->tm_min;
 507.291 +  k = t->tm_yday;
 507.292 +  t = localtime(&sbuf.st_mtime);/* get local time */
 507.293 +				/* calculate time delta */
 507.294 +  i = t->tm_hour * 60 + t->tm_min - i;
 507.295 +  if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
 507.296 +  k = abs (i);			/* time from UTC either way */
 507.297 +  elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec;
 507.298 +  elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
 507.299 +  elt->year = t->tm_year - (BASEYEAR - 1900);
 507.300 +  elt->zoccident = (k == i) ? 0 : 1;
 507.301 +  elt->zhours = k/60;
 507.302 +  elt->zminutes = k % 60;
 507.303 +  sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d",
 507.304 +	   days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 507.305 +	   t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+',
 507.306 +	   elt->zhours,elt->zminutes);
 507.307 +				/* set up Date field */
 507.308 +  LOCAL->env->date = cpystr (tmp);
 507.309 +
 507.310 +				/* fill in From field from file owner */
 507.311 +  LOCAL->env->from = mail_newaddr ();
 507.312 +  if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name);
 507.313 +  else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid);
 507.314 +  LOCAL->env->from->mailbox = cpystr (tmp);
 507.315 +  LOCAL->env->from->host = cpystr (mylocalhost ());
 507.316 +				/* set subject to be mailbox name */
 507.317 +  LOCAL->env->subject = cpystr (stream->mailbox);
 507.318 +				/* slurp the data */
 507.319 +  (buf = &elt->private.special.text)->size = sbuf.st_size;
 507.320 +  read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size);
 507.321 +  buf->data[buf->size] = '\0';
 507.322 +  close (fd);			/* close the file */
 507.323 +				/* analyze data type */
 507.324 +  if (i = phile_type (buf->data,buf->size,&j)) {
 507.325 +    LOCAL->body->type = TYPETEXT;
 507.326 +    LOCAL->body->subtype = cpystr ("PLAIN");
 507.327 +    if (!(i & PTYPECRTEXT)) {	/* change Internet newline format as needed */
 507.328 +      s = (char *) buf->data;	/* make copy of UNIX-format string */
 507.329 +      buf->data = NIL;		/* zap the buffer */
 507.330 +      buf->size = strcrlfcpy (&buf->data,&m,s,buf->size);
 507.331 +      fs_give ((void **) &s);	/* flush original UNIX-format string */
 507.332 +    }
 507.333 +    LOCAL->body->parameter = mail_newbody_parameter ();
 507.334 +    LOCAL->body->parameter->attribute = cpystr ("charset");
 507.335 +    LOCAL->body->parameter->value =
 507.336 +      cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" :
 507.337 +	      (i & PTYPEISO2022KR) ? "ISO-2022-KR" :
 507.338 +	      (i & PTYPEISO2022CN) ? "ISO-2022-CN" :
 507.339 +	      (i & PTYPE8) ? "X-UNKNOWN" : "US-ASCII");
 507.340 +    LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT;
 507.341 +    LOCAL->body->size.lines = j;
 507.342 +  }
 507.343 +  else {			/* binary data */
 507.344 +    LOCAL->body->type = TYPEAPPLICATION;
 507.345 +    LOCAL->body->subtype = cpystr ("OCTET-STREAM");
 507.346 +    LOCAL->body->parameter = mail_newbody_parameter ();
 507.347 +    LOCAL->body->parameter->attribute = cpystr ("name");
 507.348 +    LOCAL->body->parameter->value =
 507.349 +      cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox);
 507.350 +    LOCAL->body->encoding = ENCBASE64;
 507.351 +    buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size);
 507.352 +    fs_give ((void **) &s);	/* flush originary binary contents */
 507.353 +  }
 507.354 +  phile_header (stream,1,&j,NIL);
 507.355 +  LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size;
 507.356 +  elt->rfc822_size = j + buf->size;
 507.357 +				/* only one message ever... */
 507.358 +  stream->uid_validity = sbuf.st_mtime;
 507.359 +  stream->uid_last = elt->private.uid = 1;
 507.360 +  return stream;		/* return stream alive to caller */
 507.361 +}
 507.362 +
 507.363 +/* File determine data type
 507.364 + * Accepts: data to examine
 507.365 + *	    size of data
 507.366 + *	    pointer to line count return
 507.367 + * Returns: PTYPE mask of data type
 507.368 + */
 507.369 +
 507.370 +int phile_type (unsigned char *s,unsigned long i,unsigned long *j)
 507.371 +{
 507.372 +  int ret = PTYPETEXT;
 507.373 +  char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
 507.374 +  *j = 0;			/* no lines */
 507.375 +				/* check type of every character */
 507.376 +  while (i--) switch (charvec[*s++]) {
 507.377 +  case 'A':
 507.378 +    ret |= PTYPE8;		/* 8bit character */
 507.379 +    break;
 507.380 +  case 'a':
 507.381 +    break;			/* ASCII character */
 507.382 +  case 'b':
 507.383 +    return PTYPEBINARY;		/* binary byte seen, stop immediately */
 507.384 +  case 'c':
 507.385 +    ret |= PTYPECRTEXT;		/* CR indicates Internet text */
 507.386 +    break;
 507.387 +  case 'e':			/* ESC */
 507.388 +    if (*s == '$') {		/* ISO-2022 sequence? */
 507.389 +      switch (s[1]) {
 507.390 +      case 'B': case '@': ret |= PTYPEISO2022JP; break;
 507.391 +      case ')':
 507.392 +	switch (s[2]) {
 507.393 +	case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break;
 507.394 +	case 'C': ret |= PTYPEISO2022KR; break;
 507.395 +	}
 507.396 +      case '*':
 507.397 +	switch (s[2]) {
 507.398 +	case 'H': ret |= PTYPEISO2022CN; break;
 507.399 +	}
 507.400 +      case '+':
 507.401 +	switch (s[2]) {
 507.402 +	case 'I': case 'J': case 'K': case 'L': case 'M':
 507.403 +	  ret |= PTYPEISO2022CN; break;
 507.404 +	}
 507.405 +      }
 507.406 +    }
 507.407 +    break;
 507.408 +  case 'l':			/* newline */
 507.409 +    (*j)++;
 507.410 +    break;
 507.411 +  }
 507.412 +  return ret;			/* return type of data */
 507.413 +}
 507.414 +
 507.415 +/* File close
 507.416 + * Accepts: MAIL stream
 507.417 + *	    close options
 507.418 + */
 507.419 +
 507.420 +void phile_close (MAILSTREAM *stream,long options)
 507.421 +{
 507.422 +  if (LOCAL) {			/* only if a file is open */
 507.423 +    fs_give ((void **) &mail_elt (stream,1)->private.special.text.data);
 507.424 +				/* nuke the local data */
 507.425 +    fs_give ((void **) &stream->local);
 507.426 +    stream->dtb = NIL;		/* log out the DTB */
 507.427 +  }
 507.428 +}
 507.429 +
 507.430 +/* File fetch structure
 507.431 + * Accepts: MAIL stream
 507.432 + *	    message # to fetch
 507.433 + *	    pointer to return body
 507.434 + *	    option flags
 507.435 + * Returns: envelope of this message, body returned in body value
 507.436 + *
 507.437 + * Fetches the "fast" information as well
 507.438 + */
 507.439 +
 507.440 +ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
 507.441 +			   long flags)
 507.442 +{
 507.443 +  if (body) *body = LOCAL->body;
 507.444 +  return LOCAL->env;		/* return the envelope */
 507.445 +}
 507.446 +
 507.447 +
 507.448 +/* File fetch message header
 507.449 + * Accepts: MAIL stream
 507.450 + *	    message # to fetch
 507.451 + *	    pointer to returned header text length
 507.452 + *	    option flags
 507.453 + * Returns: message header in RFC822 format
 507.454 + */
 507.455 +
 507.456 +char *phile_header (MAILSTREAM *stream,unsigned long msgno,
 507.457 +		    unsigned long *length,long flags)
 507.458 +{
 507.459 +  rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body);
 507.460 +  *length = strlen (LOCAL->tmp);
 507.461 +  return LOCAL->tmp;
 507.462 +}
 507.463 +
 507.464 +
 507.465 +/* File fetch message text (body only)
 507.466 + * Accepts: MAIL stream
 507.467 + *	    message # to fetch
 507.468 + *	    pointer to returned stringstruct
 507.469 + *	    option flags
 507.470 + * Returns: T, always
 507.471 + */
 507.472 +
 507.473 +long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 507.474 +{
 507.475 +  SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text;
 507.476 +  if (!(flags &FT_PEEK)) {	/* mark message as seen */
 507.477 +    mail_elt (stream,msgno)->seen = T;
 507.478 +    mm_flags (stream,msgno);
 507.479 +  }
 507.480 +  INIT (bs,mail_string,buf->data,buf->size);
 507.481 +  return T;
 507.482 +}
 507.483 +
 507.484 +/* File ping mailbox
 507.485 + * Accepts: MAIL stream
 507.486 + * Returns: T if stream alive, else NIL
 507.487 + * No-op for readonly files, since read/writer can expunge it from under us!
 507.488 + */
 507.489 +
 507.490 +long phile_ping (MAILSTREAM *stream)
 507.491 +{
 507.492 +  return T;
 507.493 +}
 507.494 +
 507.495 +/* File check mailbox
 507.496 + * Accepts: MAIL stream
 507.497 + * No-op for readonly files, since read/writer can expunge it from under us!
 507.498 + */
 507.499 +
 507.500 +void phile_check (MAILSTREAM *stream)
 507.501 +{
 507.502 +  mm_log ("Check completed",NIL);
 507.503 +}
 507.504 +
 507.505 +/* File expunge mailbox
 507.506 + * Accepts: MAIL stream
 507.507 + *	    sequence to expunge if non-NIL
 507.508 + *	    expunge options
 507.509 + * Returns: T if success, NIL if failure
 507.510 + */
 507.511 +
 507.512 +long phile_expunge (MAILSTREAM *stream,char *sequence,long options)
 507.513 +{
 507.514 +  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
 507.515 +  return LONGT;
 507.516 +}
 507.517 +
 507.518 +/* File copy message(s)
 507.519 + * Accepts: MAIL stream
 507.520 + *	    sequence
 507.521 + *	    destination mailbox
 507.522 + *	    copy options
 507.523 + * Returns: T if copy successful, else NIL
 507.524 + */
 507.525 +
 507.526 +long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 507.527 +{
 507.528 +  char tmp[MAILTMPLEN];
 507.529 +  mailproxycopy_t pc =
 507.530 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 507.531 +  if (pc) return (*pc) (stream,sequence,mailbox,options);
 507.532 +  sprintf (tmp,"Can't copy - file \"%s\" is not in valid mailbox format",
 507.533 +	   stream->mailbox);
 507.534 +  mm_log (tmp,ERROR);
 507.535 +  return NIL;
 507.536 +}
 507.537 +
 507.538 +
 507.539 +/* File append message from stringstruct
 507.540 + * Accepts: MAIL stream
 507.541 + *	    destination mailbox
 507.542 + *	    append callback function
 507.543 + *	    data for callback
 507.544 + * Returns: T if append successful, else NIL
 507.545 + */
 507.546 +
 507.547 +long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 507.548 +{
 507.549 +  char tmp[MAILTMPLEN],file[MAILTMPLEN];
 507.550 +  char *s = mailboxfile (file,mailbox);
 507.551 +  if (s && *s) 
 507.552 +    sprintf (tmp,"Can't append - not in valid mailbox format: %.80s",s);
 507.553 +  else sprintf (tmp,"Can't append - invalid name: %.80s",mailbox);
 507.554 +  mm_log (tmp,ERROR);
 507.555 +  return NIL;
 507.556 +}
   508.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   508.2 +++ b/src/osdep/unix/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   508.3 @@ -0,0 +1,89 @@
   508.4 +/* ========================================================================
   508.5 + * Copyright 1988-2006 University of Washington
   508.6 + *
   508.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   508.8 + * you may not use this file except in compliance with the License.
   508.9 + * You may obtain a copy of the License at
  508.10 + *
  508.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  508.12 + *
  508.13 + * 
  508.14 + * ========================================================================
  508.15 + */
  508.16 +
  508.17 +/*
  508.18 + * Program:	IMAP Wildcard Matching Routines (case-dependent)
  508.19 + *
  508.20 + * Author:	Mark Crispin
  508.21 + *		Networks and Distributed Computing
  508.22 + *		Computing & Communications
  508.23 + *		University of Washington
  508.24 + *		Administration Building, AG-44
  508.25 + *		Seattle, WA  98195
  508.26 + *		Internet: MRC@CAC.Washington.EDU
  508.27 + *
  508.28 + * Date:	15 June 2000
  508.29 + * Last Edited:	30 August 2006
  508.30 + */
  508.31 +
  508.32 +/* Wildcard pattern match
  508.33 + * Accepts: base string
  508.34 + *	    pattern string
  508.35 + *	    delimiter character
  508.36 + * Returns: T if pattern matches base, else NIL
  508.37 + */
  508.38 +
  508.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  508.40 +{
  508.41 +  switch (*pat) {
  508.42 +  case '%':			/* non-recursive */
  508.43 +				/* % at end, OK if no inferiors */
  508.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  508.45 +                                /* scan remainder of string until delimiter */
  508.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  508.47 +    while ((*s != delim) && *s++);
  508.48 +    break;
  508.49 +  case '*':			/* match 0 or more characters */
  508.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  508.51 +				/* scan remainder of string */
  508.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  508.53 +    while (*s++);
  508.54 +    break;
  508.55 +  case '\0':			/* end of pattern */
  508.56 +    return *s ? NIL : T;	/* success if also end of base */
  508.57 +  default:			/* match this character */
  508.58 +    return (*pat == *s) ? pmatch_full (s+1,pat+1,delim) : NIL;
  508.59 +  }
  508.60 +  return NIL;
  508.61 +}
  508.62 +
  508.63 +/* Directory pattern match
  508.64 + * Accepts: base string
  508.65 + *	    pattern string
  508.66 + *	    delimiter character
  508.67 + * Returns: T if base is a matching directory of pattern, else NIL
  508.68 + */
  508.69 +
  508.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  508.71 +{
  508.72 +  switch (*pat) {
  508.73 +  case '%':			/* non-recursive */
  508.74 +    if (!*s) return T;		/* end of base means have a subset match */
  508.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  508.76 +				/* scan remainder of string until delimiter */
  508.77 +    do if (dmatch (s,pat,delim)) return T;
  508.78 +    while ((*s != delim) && *s++);
  508.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  508.80 +    return dmatch (s,pat,delim);/* do new scan */
  508.81 +  case '*':			/* match 0 or more characters */
  508.82 +    return T;			/* unconditional match */
  508.83 +  case '\0':			/* end of pattern */
  508.84 +    break;
  508.85 +  default:			/* match this character */
  508.86 +    if (*s) return (*pat == *s) ? dmatch (s+1,pat+1,delim) : NIL;
  508.87 +				/* end of base, return if at delimiter */
  508.88 +    else if (*pat == delim) return T;
  508.89 +    break;
  508.90 +  }
  508.91 +  return NIL;
  508.92 +}
   509.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   509.2 +++ b/src/osdep/unix/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
   509.3 @@ -0,0 +1,36 @@
   509.4 +/* ========================================================================
   509.5 + * Copyright 1988-2006 University of Washington
   509.6 + *
   509.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   509.8 + * you may not use this file except in compliance with the License.
   509.9 + * You may obtain a copy of the License at
  509.10 + *
  509.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  509.12 + *
  509.13 + * 
  509.14 + * ========================================================================
  509.15 + */
  509.16 +
  509.17 +/*
  509.18 + * Program:	Pseudo Header Strings
  509.19 + *
  509.20 + * Author:	Mark Crispin
  509.21 + *		Networks and Distributed Computing
  509.22 + *		Computing & Communications
  509.23 + *		University of Washington
  509.24 + *		Administration Building, AG-44
  509.25 + *		Seattle, WA  98195
  509.26 + *		Internet: MRC@CAC.Washington.EDU
  509.27 + *
  509.28 + * Date:	26 September 1996
  509.29 + * Last Edited:	30 August 2006
  509.30 + */
  509.31 +
  509.32 +/* Local sites may wish to alter this text */
  509.33 +
  509.34 +char *pseudo_from = "MAILER-DAEMON";
  509.35 +char *pseudo_name = "Mail System Internal Data";
  509.36 +char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
  509.37 +char *pseudo_msg =
  509.38 +  "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."
  509.39 +  ;
   510.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   510.2 +++ b/src/osdep/unix/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
   510.3 @@ -0,0 +1,30 @@
   510.4 +/* ========================================================================
   510.5 + * Copyright 1988-2006 University of Washington
   510.6 + *
   510.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   510.8 + * you may not use this file except in compliance with the License.
   510.9 + * You may obtain a copy of the License at
  510.10 + *
  510.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  510.12 + *
  510.13 + * 
  510.14 + * ========================================================================
  510.15 + */
  510.16 +
  510.17 +/*
  510.18 + * Program:	Pseudo Header Strings
  510.19 + *
  510.20 + * Author:	Mark Crispin
  510.21 + *		Networks and Distributed Computing
  510.22 + *		Computing & Communications
  510.23 + *		University of Washington
  510.24 + *		Administration Building, AG-44
  510.25 + *		Seattle, WA  98195
  510.26 + *		Internet: MRC@CAC.Washington.EDU
  510.27 + *
  510.28 + * Date:	26 September 1996
  510.29 + * Last Edited:	30 August 2006
  510.30 + */
  510.31 +
  510.32 +
  510.33 +extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
   511.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   511.2 +++ b/src/osdep/unix/rename.c	Mon Sep 14 15:17:45 2009 +0900
   511.3 @@ -0,0 +1,44 @@
   511.4 +/* ========================================================================
   511.5 + * Copyright 1988-2006 University of Washington
   511.6 + *
   511.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   511.8 + * you may not use this file except in compliance with the License.
   511.9 + * You may obtain a copy of the License at
  511.10 + *
  511.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  511.12 + *
  511.13 + * 
  511.14 + * ========================================================================
  511.15 + */
  511.16 +
  511.17 +/*
  511.18 + * Program:	Rename file
  511.19 + *
  511.20 + * Author:	Mark Crispin
  511.21 + *		Networks and Distributed Computing
  511.22 + *		Computing & Communications
  511.23 + *		University of Washington
  511.24 + *		Administration Building, AG-44
  511.25 + *		Seattle, WA  98195
  511.26 + *		Internet: MRC@CAC.Washington.EDU
  511.27 + *
  511.28 + * Date:	20 May 1996
  511.29 + * Last Edited:	30 August 2006
  511.30 + */
  511.31 + 
  511.32 +/* Emulator for working Unix rename() call
  511.33 + * Accepts: old file name
  511.34 + *	    new file name
  511.35 + * Returns: 0 if success, -1 if error with error in errno
  511.36 + */
  511.37 +
  511.38 +int Rename (char *oldname,char *newname)
  511.39 +{
  511.40 +  int ret;
  511.41 +  unlink (newname);		/* make sure the old name doesn't exist */
  511.42 +				/* link to new name, unlink old name */
  511.43 +  if (!(ret = link (oldname,newname))) unlink (oldname);
  511.44 +  return ret;
  511.45 +}
  511.46 +
  511.47 +
   512.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   512.2 +++ b/src/osdep/unix/scandir.c	Mon Sep 14 15:17:45 2009 +0900
   512.3 @@ -0,0 +1,81 @@
   512.4 +/* ========================================================================
   512.5 + * Copyright 1988-2006 University of Washington
   512.6 + *
   512.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   512.8 + * you may not use this file except in compliance with the License.
   512.9 + * You may obtain a copy of the License at
  512.10 + *
  512.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  512.12 + *
  512.13 + * 
  512.14 + * ========================================================================
  512.15 + */
  512.16 +
  512.17 +/*
  512.18 + * Program:	Scan directories
  512.19 + *
  512.20 + * Author:	Mark Crispin
  512.21 + *		Networks and Distributed Computing
  512.22 + *		Computing & Communications
  512.23 + *		University of Washington
  512.24 + *		Administration Building, AG-44
  512.25 + *		Seattle, WA  98195
  512.26 + *		Internet: MRC@CAC.Washington.EDU
  512.27 + *
  512.28 + * Date:	1 August 1988
  512.29 + * Last Edited:	15 September 2006
  512.30 + */
  512.31 + 
  512.32 +/* Emulator for BSD scandir() call
  512.33 + * Accepts: directory name
  512.34 + *	    destination pointer of names array
  512.35 + *	    selection function
  512.36 + *	    comparison function
  512.37 + * Returns: number of elements in the array or -1 if error
  512.38 + */
  512.39 +
  512.40 +int scandir (char *dirname,struct direct ***namelist,select_t select,
  512.41 +	     compar_t compar)
  512.42 +{
  512.43 +  struct direct *p,*d,**names;
  512.44 +  int nitems;
  512.45 +  struct stat stb;
  512.46 +  long nlmax;
  512.47 +  DIR *dirp = opendir (dirname);/* open directory and get status poop */
  512.48 +  if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
  512.49 +  nlmax = stb.st_size / 24;	/* guesstimate at number of files */
  512.50 +  names = (struct direct **) fs_get (nlmax * sizeof (struct direct *));
  512.51 +  nitems = 0;			/* initially none found */
  512.52 +  while (d = readdir (dirp)) {	/* read directory item */
  512.53 +				/* matches select criterion? */
  512.54 +    if (select && !(*select) (d)) continue;
  512.55 +				/* get size of direct record for this file */
  512.56 +    p = (struct direct *) fs_get (DIR_SIZE (d));
  512.57 +    p->d_ino = d->d_ino;	/* copy the poop */
  512.58 +    strcpy (p->d_name,d->d_name);
  512.59 +    if (++nitems >= nlmax) {	/* if out of space, try bigger guesstimate */
  512.60 +      void *s = (void *) names;	/* stupid language */
  512.61 +      nlmax *= 2;		/* double it */
  512.62 +      fs_resize ((void **) &s,nlmax * sizeof (struct direct *));
  512.63 +      names = (struct direct **) s;
  512.64 +    }
  512.65 +    names[nitems - 1] = p;	/* store this file there */
  512.66 +  }
  512.67 +  closedir (dirp);		/* done with directory */
  512.68 +				/* sort if necessary */
  512.69 +  if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar);
  512.70 +  *namelist = names;		/* return directory */
  512.71 +  return nitems;		/* and size */
  512.72 +}
  512.73 +
  512.74 +/* Alphabetic file name comparision
  512.75 + * Accepts: first candidate directory entry
  512.76 + *	    second candidate directory entry
  512.77 + * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
  512.78 + */
  512.79 +
  512.80 +int alphasort (void *d1,void *d2)
  512.81 +{
  512.82 +  return strcmp ((*(struct direct **) d1)->d_name,
  512.83 +		 (*(struct direct **) d2)->d_name);
  512.84 +}
   513.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   513.2 +++ b/src/osdep/unix/setpgrp.c	Mon Sep 14 15:17:45 2009 +0900
   513.3 @@ -0,0 +1,39 @@
   513.4 +/* ========================================================================
   513.5 + * Copyright 1988-2006 University of Washington
   513.6 + *
   513.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   513.8 + * you may not use this file except in compliance with the License.
   513.9 + * You may obtain a copy of the License at
  513.10 + *
  513.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  513.12 + *
  513.13 + * 
  513.14 + * ========================================================================
  513.15 + */
  513.16 +
  513.17 +/*
  513.18 + * Program:	Set process group emulator
  513.19 + *
  513.20 + * Author:	Mark Crispin
  513.21 + *		Networks and Distributed Computing
  513.22 + *		Computing & Communications
  513.23 + *		University of Washington
  513.24 + *		Administration Building, AG-44
  513.25 + *		Seattle, WA  98195
  513.26 + *		Internet: MRC@CAC.Washington.EDU
  513.27 + *
  513.28 + * Date:	3 May 1995
  513.29 + * Last Edited:	30 August 2006
  513.30 + */
  513.31 +
  513.32 +
  513.33 +/* Emulator for BSD setpgrp() call
  513.34 + * Accepts: process ID
  513.35 + *	    group ID
  513.36 + * Returns: 0 if successful, -1 if failure
  513.37 + */
  513.38 +
  513.39 +int Setpgrp (int pid,int gid)
  513.40 +{
  513.41 +  return setpgrp ();
  513.42 +}
   514.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   514.2 +++ b/src/osdep/unix/sig_bsd.c	Mon Sep 14 15:17:45 2009 +0900
   514.3 @@ -0,0 +1,40 @@
   514.4 +/* ========================================================================
   514.5 + * Copyright 1988-2006 University of Washington
   514.6 + *
   514.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   514.8 + * you may not use this file except in compliance with the License.
   514.9 + * You may obtain a copy of the License at
  514.10 + *
  514.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  514.12 + *
  514.13 + * 
  514.14 + * ========================================================================
  514.15 + */
  514.16 +
  514.17 +/*
  514.18 + * Program:	BSD Signals
  514.19 + *
  514.20 + * Author:	Mark Crispin
  514.21 + *		Networks and Distributed Computing
  514.22 + *		Computing & Communications
  514.23 + *		University of Washington
  514.24 + *		Administration Building, AG-44
  514.25 + *		Seattle, WA  98195
  514.26 + *		Internet: MRC@CAC.Washington.EDU
  514.27 + *
  514.28 + * Date:	29 April 1997
  514.29 + * Last Edited:	30 August 2006
  514.30 + */
  514.31 + 
  514.32 +#include <signal.h>
  514.33 +
  514.34 +/* Arm a signal
  514.35 + * Accepts: signal number
  514.36 + *	    desired action
  514.37 + * Returns: old action
  514.38 + */
  514.39 +
  514.40 +void *arm_signal (int sig,void *action)
  514.41 +{
  514.42 +  return (void *) signal (sig,action);
  514.43 +}
   515.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   515.2 +++ b/src/osdep/unix/sig_psx.c	Mon Sep 14 15:17:45 2009 +0900
   515.3 @@ -0,0 +1,51 @@
   515.4 +/* ========================================================================
   515.5 + * Copyright 1988-2006 University of Washington
   515.6 + *
   515.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   515.8 + * you may not use this file except in compliance with the License.
   515.9 + * You may obtain a copy of the License at
  515.10 + *
  515.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  515.12 + *
  515.13 + * 
  515.14 + * ========================================================================
  515.15 + */
  515.16 +
  515.17 +/*
  515.18 + * Program:	POSIX Signals
  515.19 + *
  515.20 + * Author:	Mark Crispin
  515.21 + *		Networks and Distributed Computing
  515.22 + *		Computing & Communications
  515.23 + *		University of Washington
  515.24 + *		Administration Building, AG-44
  515.25 + *		Seattle, WA  98195
  515.26 + *		Internet: MRC@CAC.Washington.EDU
  515.27 + *
  515.28 + * Date:	29 April 1997
  515.29 + * Last Edited:	30 August 2006
  515.30 + */
  515.31 + 
  515.32 +#include <signal.h>
  515.33 +#include <string.h>
  515.34 +
  515.35 +#ifndef SA_RESTART
  515.36 +#define SA_RESTART 0
  515.37 +#endif
  515.38 +
  515.39 +/* Arm a signal
  515.40 + * Accepts: signal number
  515.41 + *	    desired action
  515.42 + * Returns: old action
  515.43 + */
  515.44 +
  515.45 +void *arm_signal (int sig,void *action)
  515.46 +{
  515.47 +  struct sigaction nact,oact;
  515.48 +  memset (&nact,0,sizeof (struct sigaction));
  515.49 +  sigemptyset (&nact.sa_mask);	/* no signals blocked */
  515.50 +  nact.sa_handler = action;	/* set signal handler */
  515.51 +  nact.sa_flags = SA_RESTART;	/* needed on Linux, nice on SVR4 */
  515.52 +  sigaction (sig,&nact,&oact);	/* do the signal action */
  515.53 +  return (void *) oact.sa_handler;
  515.54 +}
   516.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   516.2 +++ b/src/osdep/unix/sig_sv4.c	Mon Sep 14 15:17:45 2009 +0900
   516.3 @@ -0,0 +1,40 @@
   516.4 +/* ========================================================================
   516.5 + * Copyright 1988-2006 University of Washington
   516.6 + *
   516.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   516.8 + * you may not use this file except in compliance with the License.
   516.9 + * You may obtain a copy of the License at
  516.10 + *
  516.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  516.12 + *
  516.13 + * 
  516.14 + * ========================================================================
  516.15 + */
  516.16 +
  516.17 +/*
  516.18 + * Program:	SVR4 Signals
  516.19 + *
  516.20 + * Author:	Mark Crispin
  516.21 + *		Networks and Distributed Computing
  516.22 + *		Computing & Communications
  516.23 + *		University of Washington
  516.24 + *		Administration Building, AG-44
  516.25 + *		Seattle, WA  98195
  516.26 + *		Internet: MRC@CAC.Washington.EDU
  516.27 + *
  516.28 + * Date:	29 April 1997
  516.29 + * Last Edited:	30 August 2006
  516.30 + */
  516.31 + 
  516.32 +#include <signal.h>
  516.33 +
  516.34 +/* Arm a signal
  516.35 + * Accepts: signal number
  516.36 + *	    desired action
  516.37 + * Returns: old action
  516.38 + */
  516.39 +
  516.40 +void *arm_signal (int sig,void *action)
  516.41 +{
  516.42 +  return (void *) sigset (sig,action);
  516.43 +}
   517.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   517.2 +++ b/src/osdep/unix/ssl_none.c	Mon Sep 14 15:17:45 2009 +0900
   517.3 @@ -0,0 +1,141 @@
   517.4 +/* ========================================================================
   517.5 + * Copyright 1988-2006 University of Washington
   517.6 + *
   517.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   517.8 + * you may not use this file except in compliance with the License.
   517.9 + * You may obtain a copy of the License at
  517.10 + *
  517.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  517.12 + *
  517.13 + * 
  517.14 + * ========================================================================
  517.15 + */
  517.16 +
  517.17 +/*
  517.18 + * Program:	Dummy (no SSL) authentication/encryption module
  517.19 + *
  517.20 + * Author:	Mark Crispin
  517.21 + *		Networks and Distributed Computing
  517.22 + *		Computing & Communications
  517.23 + *		University of Washington
  517.24 + *		Administration Building, AG-44
  517.25 + *		Seattle, WA  98195
  517.26 + *		Internet: MRC@CAC.Washington.EDU
  517.27 + *
  517.28 + * Date:	7 February 2001
  517.29 + * Last Edited:	30 August 2006
  517.30 + */
  517.31 +
  517.32 +/* Init server for SSL
  517.33 + * Accepts: server name
  517.34 + */
  517.35 +
  517.36 +void ssl_server_init (char *server)
  517.37 +{
  517.38 +  syslog (LOG_ERR,"This server does not support SSL");
  517.39 +  exit (1);			/* punt this program too */
  517.40 +}
  517.41 +
  517.42 +
  517.43 +/* Start TLS
  517.44 + * Accepts: /etc/services service name
  517.45 + * Returns: cpystr'd error string if TLS failed, else NIL for success
  517.46 + */
  517.47 +
  517.48 +char *ssl_start_tls (char *server)
  517.49 +{
  517.50 +  return cpystr ("This server does not support TLS");
  517.51 +}
  517.52 +
  517.53 +/* Get character
  517.54 + * Returns: character or EOF
  517.55 + */
  517.56 +
  517.57 +int PBIN (void)
  517.58 +{
  517.59 +  return getchar ();
  517.60 +}
  517.61 +
  517.62 +
  517.63 +/* Get string
  517.64 + * Accepts: destination string pointer
  517.65 + *	    number of bytes available
  517.66 + * Returns: destination string pointer or NIL if EOF
  517.67 + */
  517.68 +
  517.69 +char *PSIN (char *s,int n)
  517.70 +{
  517.71 +  return fgets (s,n,stdin);
  517.72 +}
  517.73 +
  517.74 +
  517.75 +/* Get record
  517.76 + * Accepts: destination string pointer
  517.77 + *	    number of bytes to read
  517.78 + * Returns: T if success, NIL otherwise
  517.79 + */
  517.80 +
  517.81 +long PSINR (char *s,unsigned long n)
  517.82 +{
  517.83 +  unsigned long i;
  517.84 +  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
  517.85 +  return n ? NIL : LONGT;
  517.86 +}
  517.87 +
  517.88 +
  517.89 +/* Wait for input
  517.90 + * Accepts: timeout in seconds
  517.91 + * Returns: T if have input on stdin, else NIL
  517.92 + */
  517.93 +
  517.94 +long INWAIT (long seconds)
  517.95 +{
  517.96 +  return server_input_wait (seconds);
  517.97 +}
  517.98 +
  517.99 +/* Put character
 517.100 + * Accepts: character
 517.101 + * Returns: character written or EOF
 517.102 + */
 517.103 +
 517.104 +int PBOUT (int c)
 517.105 +{
 517.106 +  return putchar (c);
 517.107 +}
 517.108 +
 517.109 +
 517.110 +/* Put string
 517.111 + * Accepts: source string pointer
 517.112 + * Returns: 0 or EOF if error
 517.113 + */
 517.114 +
 517.115 +int PSOUT (char *s)
 517.116 +{
 517.117 +  return fputs (s,stdout);
 517.118 +}
 517.119 +
 517.120 +
 517.121 +/* Put record
 517.122 + * Accepts: source sized text
 517.123 + * Returns: 0 or EOF if error
 517.124 + */
 517.125 +
 517.126 +int PSOUTR (SIZEDTEXT *s)
 517.127 +{
 517.128 +  unsigned char *t;
 517.129 +  unsigned long i,j;
 517.130 +  for (t = s->data,i = s->size;
 517.131 +       (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)));
 517.132 +       t += j,i -= j);
 517.133 +  return i ? EOF : NIL;
 517.134 +}
 517.135 +
 517.136 +
 517.137 +/* Flush output
 517.138 + * Returns: 0 or EOF if error
 517.139 + */
 517.140 +
 517.141 +int PFLUSH (void)
 517.142 +{
 517.143 +  return fflush (stdout);
 517.144 +}
   518.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   518.2 +++ b/src/osdep/unix/ssl_unix.c	Mon Sep 14 15:17:45 2009 +0900
   518.3 @@ -0,0 +1,821 @@
   518.4 +/* ========================================================================
   518.5 + * Copyright 1988-2008 University of Washington
   518.6 + *
   518.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   518.8 + * you may not use this file except in compliance with the License.
   518.9 + * You may obtain a copy of the License at
  518.10 + *
  518.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  518.12 + *
  518.13 + * 
  518.14 + * ========================================================================
  518.15 + */
  518.16 +
  518.17 +/*
  518.18 + * Program:	SSL authentication/encryption module
  518.19 + *
  518.20 + * Author:	Mark Crispin
  518.21 + *		Networks and Distributed Computing
  518.22 + *		Computing & Communications
  518.23 + *		University of Washington
  518.24 + *		Administration Building, AG-44
  518.25 + *		Seattle, WA  98195
  518.26 + *		Internet: MRC@CAC.Washington.EDU
  518.27 + *
  518.28 + * Date:	22 September 1998
  518.29 + * Last Edited:	13 January 2007
  518.30 + */
  518.31 +
  518.32 +#define crypt ssl_private_crypt
  518.33 +#include <x509v3.h>
  518.34 +#include <ssl.h>
  518.35 +#include <err.h>
  518.36 +#include <pem.h>
  518.37 +#include <buffer.h>
  518.38 +#include <bio.h>
  518.39 +#include <crypto.h>
  518.40 +#include <rand.h>
  518.41 +#undef crypt
  518.42 +
  518.43 +#define SSLBUFLEN 8192
  518.44 +#define SSLCIPHERLIST "ALL:!LOW"
  518.45 +
  518.46 +
  518.47 +/* SSL I/O stream */
  518.48 +
  518.49 +typedef struct ssl_stream {
  518.50 +  TCPSTREAM *tcpstream;		/* TCP stream */
  518.51 +  SSL_CTX *context;		/* SSL context */
  518.52 +  SSL *con;			/* SSL connection */
  518.53 +  int ictr;			/* input counter */
  518.54 +  char *iptr;			/* input pointer */
  518.55 +  char ibuf[SSLBUFLEN];		/* input buffer */
  518.56 +} SSLSTREAM;
  518.57 +
  518.58 +#include "sslio.h"
  518.59 +
  518.60 +/* Function prototypes */
  518.61 +
  518.62 +static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
  518.63 +static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags);
  518.64 +static int ssl_open_verify (int ok,X509_STORE_CTX *ctx);
  518.65 +static char *ssl_validate_cert (X509 *cert,char *host);
  518.66 +static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat);
  518.67 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
  518.68 +			       long *contd);
  518.69 +static long ssl_abort (SSLSTREAM *stream);
  518.70 +static RSA *ssl_genkey (SSL *con,int export,int keylength);
  518.71 +
  518.72 +
  518.73 +/* Secure Sockets Layer network driver dispatch */
  518.74 +
  518.75 +static struct ssl_driver ssldriver = {
  518.76 +  ssl_open,			/* open connection */
  518.77 +  ssl_aopen,			/* open preauthenticated connection */
  518.78 +  ssl_getline,			/* get a line */
  518.79 +  ssl_getbuffer,		/* get a buffer */
  518.80 +  ssl_soutr,			/* output pushed data */
  518.81 +  ssl_sout,			/* output string */
  518.82 +  ssl_close,			/* close connection */
  518.83 +  ssl_host,			/* return host name */
  518.84 +  ssl_remotehost,		/* return remote host name */
  518.85 +  ssl_port,			/* return port number */
  518.86 +  ssl_localhost			/* return local host name */
  518.87 +};
  518.88 +				/* non-NIL if doing SSL primary I/O */
  518.89 +static SSLSTDIOSTREAM *sslstdio = NIL;
  518.90 +static char *start_tls = NIL;	/* non-NIL if start TLS requested */
  518.91 +
  518.92 +/* One-time SSL initialization */
  518.93 +
  518.94 +static int sslonceonly = 0;
  518.95 +
  518.96 +void ssl_onceonlyinit (void)
  518.97 +{
  518.98 +  if (!sslonceonly++) {		/* only need to call it once */
  518.99 +    int fd;
 518.100 +    char tmp[MAILTMPLEN];
 518.101 +    struct stat sbuf;
 518.102 +				/* if system doesn't have /dev/urandom */
 518.103 +    if (stat ("/dev/urandom",&sbuf)) {
 518.104 +      while ((fd = open (tmpnam (tmp),O_WRONLY|O_CREAT|O_EXCL,0600)) < 0)
 518.105 +	sleep (1);
 518.106 +      unlink (tmp);		/* don't need the file */
 518.107 +      fstat (fd,&sbuf);		/* get information about the file */
 518.108 +      close (fd);		/* flush descriptor */
 518.109 +				/* not great but it'll have to do */
 518.110 +      sprintf (tmp + strlen (tmp),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
 518.111 +	       tcp_serveraddr (),(unsigned long) tcp_serverport (),
 518.112 +	       tcp_clientaddr (),(unsigned long) tcp_clientport (),
 518.113 +	       (unsigned long) sbuf.st_ino,(unsigned long) time (0),
 518.114 +	       (unsigned long) gethostid (),(unsigned long) getpid ());
 518.115 +      RAND_seed (tmp,strlen (tmp));
 518.116 +    }
 518.117 +				/* apply runtime linkage */
 518.118 +    mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
 518.119 +    mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
 518.120 +    SSL_library_init ();	/* add all algorithms */
 518.121 +  }
 518.122 +}
 518.123 +
 518.124 +/* SSL open
 518.125 + * Accepts: host name
 518.126 + *	    contact service name
 518.127 + *	    contact port number
 518.128 + * Returns: SSL stream if success else NIL
 518.129 + */
 518.130 +
 518.131 +SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
 518.132 +{
 518.133 +  TCPSTREAM *stream = tcp_open (host,service,port);
 518.134 +  return stream ? ssl_start (stream,host,port) : NIL;
 518.135 +}
 518.136 +
 518.137 +
 518.138 +/* SSL authenticated open
 518.139 + * Accepts: host name
 518.140 + *	    service name
 518.141 + *	    returned user name buffer
 518.142 + * Returns: SSL stream if success else NIL
 518.143 + */
 518.144 +
 518.145 +SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
 518.146 +{
 518.147 +  return NIL;			/* don't use this mechanism with SSL */
 518.148 +}
 518.149 +
 518.150 +/* Start SSL/TLS negotiations
 518.151 + * Accepts: open TCP stream of session
 518.152 + *	    user's host name
 518.153 + *	    flags
 518.154 + * Returns: SSL stream if success else NIL
 518.155 + */
 518.156 +
 518.157 +static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
 518.158 +{
 518.159 +  char *reason,tmp[MAILTMPLEN];
 518.160 +  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
 518.161 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 518.162 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
 518.163 +  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 518.164 +					    sizeof (SSLSTREAM));
 518.165 +  stream->tcpstream = tstream;	/* bind TCP stream */
 518.166 +				/* do the work */
 518.167 +  reason = ssl_start_work (stream,host,flags);
 518.168 +  (*bn) (BLOCK_NONSENSITIVE,data);
 518.169 +  if (reason) {			/* failed? */
 518.170 +    ssl_close (stream);		/* failed to do SSL */
 518.171 +    stream = NIL;		/* no stream returned */
 518.172 +    switch (*reason) {		/* analyze reason */
 518.173 +    case '*':			/* certificate failure */
 518.174 +      ++reason;			/* skip over certificate failure indication */
 518.175 +				/* pass to error callback */
 518.176 +      if (sf) (*sf) (host,reason,flags);
 518.177 +      else {			/* no error callback, build error message */
 518.178 +	sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
 518.179 +	mm_log (tmp,ERROR);
 518.180 +      }
 518.181 +    case '\0':			/* user answered no to certificate callback */
 518.182 +      if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
 518.183 +	stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 518.184 +				       sizeof (SSLSTREAM));
 518.185 +      break;
 518.186 +    default:			/* non-certificate failure */
 518.187 +      if (flags & NET_TRYSSL);	/* no error output if tryssl */
 518.188 +				/* pass to error callback */
 518.189 +      else if (sf) (*sf) (host,reason,flags);
 518.190 +      else {			/* no error callback, build error message */
 518.191 +	sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
 518.192 +	mm_log (tmp,ERROR);
 518.193 +      }
 518.194 +      break;
 518.195 +    }
 518.196 +  }
 518.197 +  return stream;
 518.198 +}
 518.199 +
 518.200 +/* Start SSL/TLS negotiations worker routine
 518.201 + * Accepts: SSL stream
 518.202 + *	    user's host name
 518.203 + *	    flags
 518.204 + * Returns: NIL if success, else error reason
 518.205 + */
 518.206 +
 518.207 +				/* evil but I had no choice */
 518.208 +static char *ssl_last_error = NIL;
 518.209 +static char *ssl_last_host = NIL;
 518.210 +
 518.211 +static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags)
 518.212 +{
 518.213 +  BIO *bio;
 518.214 +  X509 *cert;
 518.215 +  unsigned long sl,tl;
 518.216 +  char *s,*t,*err,tmp[MAILTMPLEN];
 518.217 +  sslcertificatequery_t scq =
 518.218 +    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
 518.219 +  sslclientcert_t scc =
 518.220 +    (sslclientcert_t) mail_parameters (NIL,GET_SSLCLIENTCERT,NIL);
 518.221 +  sslclientkey_t sck =
 518.222 +    (sslclientkey_t) mail_parameters (NIL,GET_SSLCLIENTKEY,NIL);
 518.223 +  if (ssl_last_error) fs_give ((void **) &ssl_last_error);
 518.224 +  ssl_last_host = host;
 518.225 +  if (!(stream->context = SSL_CTX_new ((flags & NET_TLSCLIENT) ?
 518.226 +				       TLSv1_client_method () :
 518.227 +				       SSLv23_client_method ())))
 518.228 +    return "SSL context failed";
 518.229 +  SSL_CTX_set_options (stream->context,0);
 518.230 +				/* disable certificate validation? */
 518.231 +  if (flags & NET_NOVALIDATECERT)
 518.232 +    SSL_CTX_set_verify (stream->context,SSL_VERIFY_NONE,NIL);
 518.233 +  else SSL_CTX_set_verify (stream->context,SSL_VERIFY_PEER,ssl_open_verify);
 518.234 +				/* set default paths to CAs... */
 518.235 +  SSL_CTX_set_default_verify_paths (stream->context);
 518.236 +				/* ...unless a non-standard path desired */
 518.237 +  if (s = (char *) mail_parameters (NIL,GET_SSLCAPATH,NIL))
 518.238 +    SSL_CTX_load_verify_locations (stream->context,NIL,s);
 518.239 +				/* want to send client certificate? */
 518.240 +  if (scc && (s = (*scc) ()) && (sl = strlen (s))) {
 518.241 +    if (cert = PEM_read_bio_X509 (bio = BIO_new_mem_buf (s,sl),NIL,NIL,NIL)) {
 518.242 +      SSL_CTX_use_certificate (stream->context,cert);
 518.243 +      X509_free (cert);
 518.244 +    }
 518.245 +    BIO_free (bio);
 518.246 +    if (!cert) return "SSL client certificate failed";
 518.247 +				/* want to supply private key? */
 518.248 +    if ((t = (sck ? (*sck) () : s)) && (tl = strlen (t))) {
 518.249 +      EVP_PKEY *key;
 518.250 +      if (key = PEM_read_bio_PrivateKey (bio = BIO_new_mem_buf (t,tl),
 518.251 +					 NIL,NIL,"")) {
 518.252 +	SSL_CTX_use_PrivateKey (stream->context,key);
 518.253 +	EVP_PKEY_free (key);
 518.254 +      }
 518.255 +      BIO_free (bio);
 518.256 +      memset (t,0,tl);		/* erase key */
 518.257 +    }
 518.258 +    if (s != t) memset (s,0,sl);/* erase certificate if different from key */
 518.259 +  }
 518.260 +
 518.261 +				/* create connection */
 518.262 +  if (!(stream->con = (SSL *) SSL_new (stream->context)))
 518.263 +    return "SSL connection failed";
 518.264 +  bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE);
 518.265 +  SSL_set_bio (stream->con,bio,bio);
 518.266 +  SSL_set_connect_state (stream->con);
 518.267 +  if (SSL_in_init (stream->con)) SSL_total_renegotiations (stream->con);
 518.268 +				/* now negotiate SSL */
 518.269 +  if (SSL_write (stream->con,"",0) < 0)
 518.270 +    return ssl_last_error ? ssl_last_error : "SSL negotiation failed";
 518.271 +				/* need to validate host names? */
 518.272 +  if (!(flags & NET_NOVALIDATECERT) &&
 518.273 +      (err = ssl_validate_cert (cert = SSL_get_peer_certificate (stream->con),
 518.274 +				host))) {
 518.275 +				/* application callback */
 518.276 +    if (scq) return (*scq) (err,host,cert ? cert->name : "???") ? NIL : "";
 518.277 +				/* error message to return via mm_log() */
 518.278 +    sprintf (tmp,"*%.128s: %.255s",err,cert ? cert->name : "???");
 518.279 +    return ssl_last_error = cpystr (tmp);
 518.280 +  }
 518.281 +  return NIL;
 518.282 +}
 518.283 +
 518.284 +/* SSL certificate verification callback
 518.285 + * Accepts: error flag
 518.286 + *	    X509 context
 518.287 + * Returns: error flag
 518.288 + */
 518.289 +
 518.290 +static int ssl_open_verify (int ok,X509_STORE_CTX *ctx)
 518.291 +{
 518.292 +  char *err,cert[256],tmp[MAILTMPLEN];
 518.293 +  sslcertificatequery_t scq =
 518.294 +    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
 518.295 +  if (!ok) {			/* in case failure */
 518.296 +    err = (char *) X509_verify_cert_error_string
 518.297 +      (X509_STORE_CTX_get_error (ctx));
 518.298 +    X509_NAME_oneline (X509_get_subject_name
 518.299 +		       (X509_STORE_CTX_get_current_cert (ctx)),cert,255);
 518.300 +    if (!scq) {			/* mm_log() error message if no callback */
 518.301 +      sprintf (tmp,"*%.128s: %.255s",err,cert);
 518.302 +      ssl_last_error = cpystr (tmp);
 518.303 +    }
 518.304 +				/* ignore error if application says to */
 518.305 +    else if ((*scq) (err,ssl_last_host,cert)) ok = T;
 518.306 +				/* application wants punt */
 518.307 +    else ssl_last_error = cpystr ("");
 518.308 +  }
 518.309 +  return ok;
 518.310 +}
 518.311 +
 518.312 +
 518.313 +/* SSL validate certificate
 518.314 + * Accepts: certificate
 518.315 + *	    host to validate against
 518.316 + * Returns: NIL if validated, else string of error message
 518.317 + */
 518.318 +
 518.319 +static char *ssl_validate_cert (X509 *cert,char *host)
 518.320 +{
 518.321 +  int i,n;
 518.322 +  char *s,*t,*ret;
 518.323 +  void *ext;
 518.324 +  GENERAL_NAME *name;
 518.325 +				/* make sure have a certificate */
 518.326 +  if (!cert) ret = "No certificate from server";
 518.327 +				/* and that it has a name */
 518.328 +  else if (!cert->name) ret = "No name in certificate";
 518.329 +				/* locate CN */
 518.330 +  else if (s = strstr (cert->name,"/CN=")) {
 518.331 +    if (t = strchr (s += 4,'/')) *t = '\0';
 518.332 +				/* host name matches pattern? */
 518.333 +    ret = ssl_compare_hostnames (host,s) ? NIL :
 518.334 +      "Server name does not match certificate";
 518.335 +    if (t) *t = '/';		/* restore smashed delimiter */
 518.336 +				/* if mismatch, see if in extensions */
 518.337 +    if (ret && (ext = X509_get_ext_d2i (cert,NID_subject_alt_name,NIL,NIL)) &&
 518.338 +	(n = sk_GENERAL_NAME_num (ext)))
 518.339 +      /* older versions of OpenSSL use "ia5" instead of dNSName */
 518.340 +      for (i = 0; ret && (i < n); i++)
 518.341 +	if ((name = sk_GENERAL_NAME_value (ext,i)) &&
 518.342 +	    (name->type = GEN_DNS) && (s = name->d.ia5->data) &&
 518.343 +	    ssl_compare_hostnames (host,s)) ret = NIL;
 518.344 +  }
 518.345 +  else ret = "Unable to locate common name in certificate";
 518.346 +  return ret;
 518.347 +}
 518.348 +
 518.349 +/* Case-independent wildcard pattern match
 518.350 + * Accepts: base string
 518.351 + *	    pattern string
 518.352 + * Returns: T if pattern matches base, else NIL
 518.353 + */
 518.354 +
 518.355 +static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat)
 518.356 +{
 518.357 +  long ret = NIL;
 518.358 +  switch (*pat) {
 518.359 +  case '*':			/* wildcard */
 518.360 +    if (pat[1]) {		/* there must be a pattern suffix */
 518.361 +				/* there is, scan base against it */
 518.362 +      do if (ssl_compare_hostnames (s,pat+1)) ret = LONGT;
 518.363 +      while (!ret && (*s != '.') && *s++);
 518.364 +    }
 518.365 +    break;
 518.366 +  case '\0':			/* end of pattern */
 518.367 +    if (!*s) ret = LONGT;	/* success if base is also at end */
 518.368 +    break;
 518.369 +  default:			/* non-wildcard, recurse if match */
 518.370 +    if (!compare_uchar (*pat,*s)) ret = ssl_compare_hostnames (s+1,pat+1);
 518.371 +    break;
 518.372 +  }
 518.373 +  return ret;
 518.374 +}
 518.375 +
 518.376 +/* SSL receive line
 518.377 + * Accepts: SSL stream
 518.378 + * Returns: text line string or NIL if failure
 518.379 + */
 518.380 +
 518.381 +char *ssl_getline (SSLSTREAM *stream)
 518.382 +{
 518.383 +  unsigned long n,contd;
 518.384 +  char *ret = ssl_getline_work (stream,&n,&contd);
 518.385 +  if (ret && contd) {		/* got a line needing continuation? */
 518.386 +    STRINGLIST *stl = mail_newstringlist ();
 518.387 +    STRINGLIST *stc = stl;
 518.388 +    do {			/* collect additional lines */
 518.389 +      stc->text.data = (unsigned char *) ret;
 518.390 +      stc->text.size = n;
 518.391 +      stc = stc->next = mail_newstringlist ();
 518.392 +      ret = ssl_getline_work (stream,&n,&contd);
 518.393 +    } while (ret && contd);
 518.394 +    if (ret) {			/* stash final part of line on list */
 518.395 +      stc->text.data = (unsigned char *) ret;
 518.396 +      stc->text.size = n;
 518.397 +				/* determine how large a buffer we need */
 518.398 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 518.399 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 518.400 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 518.401 +	memcpy (ret + n,stc->text.data,stc->text.size);
 518.402 +      ret[n] = '\0';
 518.403 +    }
 518.404 +    mail_free_stringlist (&stl);/* either way, done with list */
 518.405 +  }
 518.406 +  return ret;
 518.407 +}
 518.408 +
 518.409 +/* SSL receive line or partial line
 518.410 + * Accepts: SSL stream
 518.411 + *	    pointer to return size
 518.412 + *	    pointer to return continuation flag
 518.413 + * Returns: text line string, size and continuation flag, or NIL if failure
 518.414 + */
 518.415 +
 518.416 +static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
 518.417 +			       long *contd)
 518.418 +{
 518.419 +  unsigned long n;
 518.420 +  char *s,*ret,c,d;
 518.421 +  *contd = NIL;			/* assume no continuation */
 518.422 +				/* make sure have data */
 518.423 +  if (!ssl_getdata (stream)) return NIL;
 518.424 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 518.425 +    d = *stream->iptr++;	/* slurp another character */
 518.426 +    if ((c == '\015') && (d == '\012')) {
 518.427 +      ret = (char *) fs_get (n--);
 518.428 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 518.429 +      ret[n] = '\0';		/* tie off string with null */
 518.430 +      return ret;
 518.431 +    }
 518.432 +  }
 518.433 +				/* copy partial string from buffer */
 518.434 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 518.435 +				/* get more data from the net */
 518.436 +  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
 518.437 +				/* special case of newline broken by buffer */
 518.438 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 518.439 +    stream->iptr++;		/* eat the line feed */
 518.440 +    stream->ictr--;
 518.441 +    ret[*size = --n] = '\0';	/* tie off string with null */
 518.442 +  }
 518.443 +  else *contd = LONGT;		/* continuation needed */
 518.444 +  return ret;
 518.445 +}
 518.446 +
 518.447 +/* SSL receive buffer
 518.448 + * Accepts: SSL stream
 518.449 + *	    size in bytes
 518.450 + *	    buffer to read into
 518.451 + * Returns: T if success, NIL otherwise
 518.452 + */
 518.453 +
 518.454 +long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
 518.455 +{
 518.456 +  unsigned long n;
 518.457 +  while (size > 0) {		/* until request satisfied */
 518.458 +    if (!ssl_getdata (stream)) return NIL;
 518.459 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 518.460 +				/* do the copy */
 518.461 +    memcpy (buffer,stream->iptr,n);
 518.462 +    buffer += n;		/* update pointer */
 518.463 +    stream->iptr += n;
 518.464 +    size -= n;			/* update # of bytes to do */
 518.465 +    stream->ictr -= n;
 518.466 +  }
 518.467 +  buffer[0] = '\0';		/* tie off string */
 518.468 +  return T;
 518.469 +}
 518.470 +
 518.471 +/* SSL receive data
 518.472 + * Accepts: TCP/IP stream
 518.473 + * Returns: T if success, NIL otherwise
 518.474 + */
 518.475 +
 518.476 +long ssl_getdata (SSLSTREAM *stream)
 518.477 +{
 518.478 +  int i,sock;
 518.479 +  fd_set fds,efds;
 518.480 +  struct timeval tmo;
 518.481 +  tcptimeout_t tmoh = (tcptimeout_t) mail_parameters (NIL,GET_TIMEOUT,NIL);
 518.482 +  long ttmo_read = (long) mail_parameters (NIL,GET_READTIMEOUT,NIL);
 518.483 +  time_t t = time (0);
 518.484 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 518.485 +  if (!stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return NIL;
 518.486 +				/* tcp_unix should have prevented this */
 518.487 +  if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
 518.488 +  (*bn) (BLOCK_TCPREAD,NIL);
 518.489 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 518.490 +    time_t tl = time (0);	/* start of request */
 518.491 +    time_t now = tl;
 518.492 +    int ti = ttmo_read ? now + ttmo_read : 0;
 518.493 +    if (SSL_pending (stream->con)) i = 1;
 518.494 +    else {
 518.495 +      if (tcpdebug) mm_log ("Reading SSL data",TCPDEBUG);
 518.496 +      tmo.tv_usec = 0;
 518.497 +      FD_ZERO (&fds);		/* initialize selection vector */
 518.498 +      FD_ZERO (&efds);		/* handle errors too */
 518.499 +      FD_SET (sock,&fds);	/* set bit in selection vector */
 518.500 +      FD_SET (sock,&efds);	/* set bit in error selection vector */
 518.501 +      errno = NIL;		/* block and read */
 518.502 +      do {			/* block under timeout */
 518.503 +	tmo.tv_sec = ti ? ti - now : 0;
 518.504 +	i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);
 518.505 +	now = time (0);		/* fake timeout if interrupt & time expired */
 518.506 +	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 518.507 +      } while ((i < 0) && (errno == EINTR));
 518.508 +    }
 518.509 +    if (i) {			/* non-timeout result from select? */
 518.510 +      errno = 0;		/* just in case */
 518.511 +      if (i > 0)		/* read what we can */
 518.512 +	while (((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) < 0) &&
 518.513 +	       ((errno == EINTR) ||
 518.514 +		(SSL_get_error (stream->con,i) == SSL_ERROR_WANT_READ)));
 518.515 +      if (i <= 0) {		/* error seen? */
 518.516 +	if (tcpdebug) {
 518.517 +	  char *s,tmp[MAILTMPLEN];
 518.518 +	  if (i) sprintf (s = tmp,"SSL data read I/O error %d SSL error %d",
 518.519 +			  errno,SSL_get_error (stream->con,i));
 518.520 +	  else s = "SSL data read end of file";
 518.521 +	  mm_log (s,TCPDEBUG);
 518.522 +	}
 518.523 +	return ssl_abort (stream);
 518.524 +      }
 518.525 +      stream->iptr = stream->ibuf;/* point at TCP buffer */
 518.526 +      stream->ictr = i;		/* set new byte count */
 518.527 +      if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
 518.528 +    }
 518.529 +				/* timeout, punt unless told not to */
 518.530 +    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
 518.531 +      if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
 518.532 +      return ssl_abort (stream);
 518.533 +    }
 518.534 +  }
 518.535 +  (*bn) (BLOCK_NONE,NIL);
 518.536 +  return T;
 518.537 +}
 518.538 +
 518.539 +/* SSL send string as record
 518.540 + * Accepts: SSL stream
 518.541 + *	    string pointer
 518.542 + * Returns: T if success else NIL
 518.543 + */
 518.544 +
 518.545 +long ssl_soutr (SSLSTREAM *stream,char *string)
 518.546 +{
 518.547 +  return ssl_sout (stream,string,(unsigned long) strlen (string));
 518.548 +}
 518.549 +
 518.550 +
 518.551 +/* SSL send string
 518.552 + * Accepts: SSL stream
 518.553 + *	    string pointer
 518.554 + *	    byte count
 518.555 + * Returns: T if success else NIL
 518.556 + */
 518.557 +
 518.558 +long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
 518.559 +{
 518.560 +  long i;
 518.561 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 518.562 +  if (!stream->con) return NIL;
 518.563 +  (*bn) (BLOCK_TCPWRITE,NIL);
 518.564 +  if (tcpdebug) mm_log ("Writing to SSL",TCPDEBUG);
 518.565 +				/* until request satisfied */
 518.566 +  for (i = 0; size > 0; string += i,size -= i)
 518.567 +				/* write as much as we can */
 518.568 +    if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) {
 518.569 +      if (tcpdebug) {
 518.570 +	char tmp[MAILTMPLEN];
 518.571 +	sprintf (tmp,"SSL data write I/O error %d SSL error %d",
 518.572 +		 errno,SSL_get_error (stream->con,i));
 518.573 +	mm_log (tmp,TCPDEBUG);
 518.574 +      }
 518.575 +      return ssl_abort (stream);/* write failed */
 518.576 +    }
 518.577 +  if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
 518.578 +  (*bn) (BLOCK_NONE,NIL);
 518.579 +  return LONGT;			/* all done */
 518.580 +}
 518.581 +
 518.582 +/* SSL close
 518.583 + * Accepts: SSL stream
 518.584 + */
 518.585 +
 518.586 +void ssl_close (SSLSTREAM *stream)
 518.587 +{
 518.588 +  ssl_abort (stream);		/* nuke the stream */
 518.589 +  fs_give ((void **) &stream);	/* flush the stream */
 518.590 +}
 518.591 +
 518.592 +
 518.593 +/* SSL abort stream
 518.594 + * Accepts: SSL stream
 518.595 + * Returns: NIL always
 518.596 + */
 518.597 +
 518.598 +static long ssl_abort (SSLSTREAM *stream)
 518.599 +{
 518.600 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 518.601 +  if (stream->con) {		/* close SSL connection */
 518.602 +    SSL_shutdown (stream->con);
 518.603 +    SSL_free (stream->con);
 518.604 +    stream->con = NIL;
 518.605 +  }
 518.606 +  if (stream->context) {	/* clean up context */
 518.607 +    SSL_CTX_free (stream->context);
 518.608 +    stream->context = NIL;
 518.609 +  }
 518.610 +  if (stream->tcpstream) {	/* close TCP stream */
 518.611 +    tcp_close (stream->tcpstream);
 518.612 +    stream->tcpstream = NIL;
 518.613 +  }
 518.614 +  (*bn) (BLOCK_NONE,NIL);
 518.615 +  return NIL;
 518.616 +}
 518.617 +
 518.618 +/* SSL get host name
 518.619 + * Accepts: SSL stream
 518.620 + * Returns: host name for this stream
 518.621 + */
 518.622 +
 518.623 +char *ssl_host (SSLSTREAM *stream)
 518.624 +{
 518.625 +  return tcp_host (stream->tcpstream);
 518.626 +}
 518.627 +
 518.628 +
 518.629 +/* SSL get remote host name
 518.630 + * Accepts: SSL stream
 518.631 + * Returns: host name for this stream
 518.632 + */
 518.633 +
 518.634 +char *ssl_remotehost (SSLSTREAM *stream)
 518.635 +{
 518.636 +  return tcp_remotehost (stream->tcpstream);
 518.637 +}
 518.638 +
 518.639 +
 518.640 +/* SSL return port for this stream
 518.641 + * Accepts: SSL stream
 518.642 + * Returns: port number for this stream
 518.643 + */
 518.644 +
 518.645 +unsigned long ssl_port (SSLSTREAM *stream)
 518.646 +{
 518.647 +  return tcp_port (stream->tcpstream);
 518.648 +}
 518.649 +
 518.650 +
 518.651 +/* SSL get local host name
 518.652 + * Accepts: SSL stream
 518.653 + * Returns: local host name
 518.654 + */
 518.655 +
 518.656 +char *ssl_localhost (SSLSTREAM *stream)
 518.657 +{
 518.658 +  return tcp_localhost (stream->tcpstream);
 518.659 +}
 518.660 +
 518.661 +/* Start TLS
 518.662 + * Accepts: /etc/services service name
 518.663 + * Returns: cpystr'd error string if TLS failed, else NIL for success
 518.664 + */
 518.665 +
 518.666 +char *ssl_start_tls (char *server)
 518.667 +{
 518.668 +  char tmp[MAILTMPLEN];
 518.669 +  struct stat sbuf;
 518.670 +  if (sslstdio) return cpystr ("Already in an SSL session");
 518.671 +  if (start_tls) return cpystr ("TLS already started");
 518.672 +  if (server) {			/* build specific certificate/key file name */
 518.673 +    sprintf (tmp,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
 518.674 +    if (stat (tmp,&sbuf)) {	/* use non-specific name if no specific file */
 518.675 +      sprintf (tmp,"%s/%s.pem",SSL_CERT_DIRECTORY,server);
 518.676 +      if (stat (tmp,&sbuf)) return cpystr ("Server certificate not installed");
 518.677 +    }
 518.678 +    start_tls = server;		/* switch to STARTTLS mode */
 518.679 +  }
 518.680 +  return NIL;
 518.681 +}
 518.682 +
 518.683 +/* Init server for SSL
 518.684 + * Accepts: server name
 518.685 + */
 518.686 +
 518.687 +void ssl_server_init (char *server)
 518.688 +{
 518.689 +  char cert[MAILTMPLEN],key[MAILTMPLEN];
 518.690 +  unsigned long i;
 518.691 +  struct stat sbuf;
 518.692 +  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
 518.693 +					    sizeof (SSLSTREAM));
 518.694 +  ssl_onceonlyinit ();		/* make sure algorithms added */
 518.695 +  ERR_load_crypto_strings ();
 518.696 +  SSL_load_error_strings ();
 518.697 +				/* build specific certificate/key file names */
 518.698 +  sprintf (cert,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
 518.699 +  sprintf (key,"%s/%s-%s.pem",SSL_KEY_DIRECTORY,server,tcp_serveraddr ());
 518.700 +				/* use non-specific name if no specific cert */
 518.701 +  if (stat (cert,&sbuf)) sprintf (cert,"%s/%s.pem",SSL_CERT_DIRECTORY,server);
 518.702 +  if (stat (key,&sbuf)) {	/* use non-specific name if no specific key */
 518.703 +    sprintf (key,"%s/%s.pem",SSL_KEY_DIRECTORY,server);
 518.704 +				/* use cert file as fallback for key */
 518.705 +    if (stat (key,&sbuf)) strcpy (key,cert);
 518.706 +  }
 518.707 +				/* create context */
 518.708 +  if (!(stream->context = SSL_CTX_new (start_tls ?
 518.709 +				       TLSv1_server_method () :
 518.710 +				       SSLv23_server_method ())))
 518.711 +    syslog (LOG_ALERT,"Unable to create SSL context, host=%.80s",
 518.712 +	    tcp_clienthost ());
 518.713 +  else {			/* set context options */
 518.714 +    SSL_CTX_set_options (stream->context,SSL_OP_ALL);
 518.715 +				/* set cipher list */
 518.716 +    if (!SSL_CTX_set_cipher_list (stream->context,SSLCIPHERLIST))
 518.717 +      syslog (LOG_ALERT,"Unable to set cipher list %.80s, host=%.80s",
 518.718 +	      SSLCIPHERLIST,tcp_clienthost ());
 518.719 +				/* load certificate */
 518.720 +    else if (!SSL_CTX_use_certificate_chain_file (stream->context,cert))
 518.721 +      syslog (LOG_ALERT,"Unable to load certificate from %.80s, host=%.80s",
 518.722 +	      cert,tcp_clienthost ());
 518.723 +				/* load key */
 518.724 +    else if (!(SSL_CTX_use_RSAPrivateKey_file (stream->context,key,
 518.725 +					       SSL_FILETYPE_PEM)))
 518.726 +      syslog (LOG_ALERT,"Unable to load private key from %.80s, host=%.80s",
 518.727 +	      key,tcp_clienthost ());
 518.728 +
 518.729 +    else {			/* generate key if needed */
 518.730 +      if (SSL_CTX_need_tmp_RSA (stream->context))
 518.731 +	SSL_CTX_set_tmp_rsa_callback (stream->context,ssl_genkey);
 518.732 +				/* create new SSL connection */
 518.733 +      if (!(stream->con = SSL_new (stream->context)))
 518.734 +	syslog (LOG_ALERT,"Unable to create SSL connection, host=%.80s",
 518.735 +		tcp_clienthost ());
 518.736 +      else {			/* set file descriptor */
 518.737 +	SSL_set_fd (stream->con,0);
 518.738 +				/* all OK if accepted */
 518.739 +	if (SSL_accept (stream->con) < 0)
 518.740 +	  syslog (LOG_INFO,"Unable to accept SSL connection, host=%.80s",
 518.741 +		  tcp_clienthost ());
 518.742 +	else {			/* server set up */
 518.743 +	  sslstdio = (SSLSTDIOSTREAM *)
 518.744 +	    memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof (SSLSTDIOSTREAM));
 518.745 +	  sslstdio->sslstream = stream;
 518.746 +				/* available space in output buffer */
 518.747 +	  sslstdio->octr = SSLBUFLEN;
 518.748 +				/* current output buffer pointer */
 518.749 +	  sslstdio->optr = sslstdio->obuf;
 518.750 +				/* allow plaintext if disable value was 2 */
 518.751 +	  if ((long) mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) > 1)
 518.752 +	    mail_parameters (NIL,SET_DISABLEPLAINTEXT,NIL);
 518.753 +				/* unhide PLAIN SASL authenticator */
 518.754 +	  mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"PLAIN");
 518.755 +	  mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"LOGIN");
 518.756 +	  return;
 518.757 +	}
 518.758 +      }
 518.759 +    }  
 518.760 +  }
 518.761 +  while (i = ERR_get_error ())	/* SSL failure */
 518.762 +    syslog (LOG_ERR,"SSL error status: %.80s",ERR_error_string (i,NIL));
 518.763 +  ssl_close (stream);		/* punt stream */
 518.764 +  exit (1);			/* punt this program too */
 518.765 +}
 518.766 +
 518.767 +/* Generate one-time key for server
 518.768 + * Accepts: SSL connection
 518.769 + *	    export flag
 518.770 + *	    keylength
 518.771 + * Returns: generated key, always
 518.772 + */
 518.773 +
 518.774 +static RSA *ssl_genkey (SSL *con,int export,int keylength)
 518.775 +{
 518.776 +  unsigned long i;
 518.777 +  static RSA *key = NIL;
 518.778 +  if (!key) {			/* if don't have a key already */
 518.779 +				/* generate key */
 518.780 +    if (!(key = RSA_generate_key (export ? keylength : 1024,RSA_F4,NIL,NIL))) {
 518.781 +      syslog (LOG_ALERT,"Unable to generate temp key, host=%.80s",
 518.782 +	      tcp_clienthost ());
 518.783 +      while (i = ERR_get_error ())
 518.784 +	syslog (LOG_ALERT,"SSL error status: %s",ERR_error_string (i,NIL));
 518.785 +      exit (1);
 518.786 +    }
 518.787 +  }
 518.788 +  return key;
 518.789 +}
 518.790 +
 518.791 +/* Wait for stdin input
 518.792 + * Accepts: timeout in seconds
 518.793 + * Returns: T if have input on stdin, else NIL
 518.794 + */
 518.795 +
 518.796 +long ssl_server_input_wait (long seconds)
 518.797 +{
 518.798 +  int i,sock;
 518.799 +  fd_set fds,efd;
 518.800 +  struct timeval tmo;
 518.801 +  SSLSTREAM *stream;
 518.802 +  if (!sslstdio) return server_input_wait (seconds);
 518.803 +				/* input available in buffer */
 518.804 +  if (((stream = sslstdio->sslstream)->ictr > 0) ||
 518.805 +      !stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return LONGT;
 518.806 +				/* sock ought to be 0 always */
 518.807 +  if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
 518.808 +				/* input available from SSL */
 518.809 +  if (SSL_pending (stream->con) &&
 518.810 +      ((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) > 0)) {
 518.811 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 518.812 +    stream->ictr = i;		/* set new byte count */
 518.813 +    return LONGT;
 518.814 +  }
 518.815 +  FD_ZERO (&fds);		/* initialize selection vector */
 518.816 +  FD_ZERO (&efd);		/* initialize selection vector */
 518.817 +  FD_SET (sock,&fds);		/* set bit in selection vector */
 518.818 +  FD_SET (sock,&efd);		/* set bit in selection vector */
 518.819 +  tmo.tv_sec = seconds; tmo.tv_usec = 0;
 518.820 +				/* see if input available from the socket */
 518.821 +  return select (sock+1,&fds,0,&efd,&tmo) ? LONGT : NIL;
 518.822 +}
 518.823 +
 518.824 +#include "sslstdio.c"
   519.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   519.2 +++ b/src/osdep/unix/sslstdio.c	Mon Sep 14 15:17:45 2009 +0900
   519.3 @@ -0,0 +1,169 @@
   519.4 +/* ========================================================================
   519.5 + * Copyright 1988-2006 University of Washington
   519.6 + *
   519.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   519.8 + * you may not use this file except in compliance with the License.
   519.9 + * You may obtain a copy of the License at
  519.10 + *
  519.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  519.12 + *
  519.13 + * 
  519.14 + * ========================================================================
  519.15 + */
  519.16 +
  519.17 +/*
  519.18 + * Program:	SSL standard I/O routines for server use
  519.19 + *
  519.20 + * Author:	Mark Crispin
  519.21 + *		Networks and Distributed Computing
  519.22 + *		Computing & Communications
  519.23 + *		University of Washington
  519.24 + *		Administration Building, AG-44
  519.25 + *		Seattle, WA  98195
  519.26 + *		Internet: MRC@CAC.Washington.EDU
  519.27 + *
  519.28 + * Date:	22 September 1998
  519.29 + * Last Edited:	30 August 2006
  519.30 + */
  519.31 +
  519.32 +/* Get character
  519.33 + * Returns: character or EOF
  519.34 + */
  519.35 +
  519.36 +int PBIN (void)
  519.37 +{
  519.38 +  if (!sslstdio) return getchar ();
  519.39 +  if (!ssl_getdata (sslstdio->sslstream)) return EOF;
  519.40 +				/* one last byte available */
  519.41 +  sslstdio->sslstream->ictr--;
  519.42 +  return (int) *(sslstdio->sslstream->iptr)++;
  519.43 +}
  519.44 +
  519.45 +
  519.46 +/* Get string
  519.47 + * Accepts: destination string pointer
  519.48 + *	    number of bytes available
  519.49 + * Returns: destination string pointer or NIL if EOF
  519.50 + */
  519.51 +
  519.52 +char *PSIN (char *s,int n)
  519.53 +{
  519.54 +  int i,c;
  519.55 +  if (start_tls) {		/* doing a start TLS? */
  519.56 +    ssl_server_init (start_tls);/* enter the mode */
  519.57 +    start_tls = NIL;		/* don't do this again */
  519.58 +  }
  519.59 +  if (!sslstdio) return fgets (s,n,stdin);
  519.60 +  for (i = c = 0, n-- ; (c != '\n') && (i < n); sslstdio->sslstream->ictr--) {
  519.61 +    if ((sslstdio->sslstream->ictr <= 0) && !ssl_getdata (sslstdio->sslstream))
  519.62 +      return NIL;		/* read error */
  519.63 +    c = s[i++] = *(sslstdio->sslstream->iptr)++;
  519.64 +  }
  519.65 +  s[i] = '\0';			/* tie off string */
  519.66 +  return s;
  519.67 +}
  519.68 +
  519.69 +
  519.70 +/* Get record
  519.71 + * Accepts: destination string pointer
  519.72 + *	    number of bytes to read
  519.73 + * Returns: T if success, NIL otherwise
  519.74 + */
  519.75 +
  519.76 +long PSINR (char *s,unsigned long n)
  519.77 +{
  519.78 +  unsigned long i;
  519.79 +  if (start_tls) {		/* doing a start TLS? */
  519.80 +    ssl_server_init (start_tls);/* enter the mode */
  519.81 +    start_tls = NIL;		/* don't do this again */
  519.82 +  }
  519.83 +  if (sslstdio) return ssl_getbuffer (sslstdio->sslstream,n,s);
  519.84 +				/* non-SSL case */
  519.85 +  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
  519.86 +  return n ? NIL : LONGT;
  519.87 +}
  519.88 +
  519.89 +
  519.90 +/* Wait for stdin input
  519.91 + * Accepts: timeout in seconds
  519.92 + * Returns: T if have input on stdin, else NIL
  519.93 + */
  519.94 +
  519.95 +long INWAIT (long seconds)
  519.96 +{
  519.97 +  return (sslstdio ? ssl_server_input_wait : server_input_wait) (seconds);
  519.98 +}
  519.99 +
 519.100 +/* Put character
 519.101 + * Accepts: character
 519.102 + * Returns: character written or EOF
 519.103 + */
 519.104 +
 519.105 +int PBOUT (int c)
 519.106 +{
 519.107 +  if (!sslstdio) return putchar (c);
 519.108 +				/* flush buffer if full */
 519.109 +  if (!sslstdio->octr && PFLUSH ()) return EOF;
 519.110 +  sslstdio->octr--;		/* count down one character */
 519.111 +  *sslstdio->optr++ = c;	/* write character */
 519.112 +  return c;			/* return that character */
 519.113 +}
 519.114 +
 519.115 +
 519.116 +/* Put string
 519.117 + * Accepts: destination string pointer
 519.118 + * Returns: 0 or EOF if error
 519.119 + */
 519.120 +
 519.121 +int PSOUT (char *s)
 519.122 +{
 519.123 +  if (!sslstdio) return fputs (s,stdout);
 519.124 +  while (*s) {			/* flush buffer if full */
 519.125 +    if (!sslstdio->octr && PFLUSH ()) return EOF;
 519.126 +    *sslstdio->optr++ = *s++;	/* write one more character */
 519.127 +    sslstdio->octr--;		/* count down one character */
 519.128 +  }
 519.129 +  return 0;			/* success */
 519.130 +}
 519.131 +
 519.132 +/* Put record
 519.133 + * Accepts: source sized text
 519.134 + * Returns: 0 or EOF if error
 519.135 + */
 519.136 +
 519.137 +int PSOUTR (SIZEDTEXT *s)
 519.138 +{
 519.139 +  unsigned char *t = s->data;
 519.140 +  unsigned long i = s->size;
 519.141 +  unsigned long j;
 519.142 +  if (sslstdio) while (i) {	/* until request satisfied */
 519.143 +				/* flush buffer if full */
 519.144 +    if (!sslstdio->octr && PFLUSH ()) break;
 519.145 +				/* blat as big a chucnk as we can */
 519.146 +    memcpy (sslstdio->optr,t,j = min (i,sslstdio->octr));
 519.147 +    sslstdio->optr += j;	/* account for chunk */
 519.148 +    sslstdio->octr -= j;
 519.149 +    t += j;
 519.150 +    i -= j;
 519.151 +  }
 519.152 +  else while (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)))
 519.153 +    t += j,i -= j;
 519.154 +  return i ? EOF : NIL;
 519.155 +}
 519.156 +
 519.157 +
 519.158 +/* Flush output
 519.159 + * Returns: 0 or EOF if error
 519.160 + */
 519.161 +
 519.162 +int PFLUSH (void)
 519.163 +{
 519.164 +  if (!sslstdio) return fflush (stdout);
 519.165 +				/* force out buffer */
 519.166 +  if (!ssl_sout (sslstdio->sslstream,sslstdio->obuf,
 519.167 +		 SSLBUFLEN - sslstdio->octr)) return EOF;
 519.168 +				/* renew output buffer */
 519.169 +  sslstdio->optr = sslstdio->obuf;
 519.170 +  sslstdio->octr = SSLBUFLEN;
 519.171 +  return 0;			/* success */
 519.172 +}
   520.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   520.2 +++ b/src/osdep/unix/strerror.c	Mon Sep 14 15:17:45 2009 +0900
   520.3 @@ -0,0 +1,37 @@
   520.4 +/* ========================================================================
   520.5 + * Copyright 1988-2006 University of Washington
   520.6 + *
   520.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   520.8 + * you may not use this file except in compliance with the License.
   520.9 + * You may obtain a copy of the License at
  520.10 + *
  520.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  520.12 + *
  520.13 + * 
  520.14 + * ========================================================================
  520.15 + */
  520.16 +
  520.17 +/*
  520.18 + * Program:	Error number to string
  520.19 + *
  520.20 + * Author:	Mark Crispin
  520.21 + *		Networks and Distributed Computing
  520.22 + *		Computing & Communications
  520.23 + *		University of Washington
  520.24 + *		Administration Building, AG-44
  520.25 + *		Seattle, WA  98195
  520.26 + *		Internet: MRC@CAC.Washington.EDU
  520.27 + *
  520.28 + * Date:	1 August 1988
  520.29 + * Last Edited:	30 August 2006
  520.30 + */
  520.31 + 
  520.32 +/* Return implementation-defined string corresponding to error
  520.33 + * Accepts: error number
  520.34 + * Returns: string for that error
  520.35 + */
  520.36 +
  520.37 +char *strerror (int n)
  520.38 +{
  520.39 +  return (n >= 0 && n < sys_nerr) ? sys_errlist[n] : NIL;
  520.40 +}
   521.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   521.2 +++ b/src/osdep/unix/tcp_unix.c	Mon Sep 14 15:17:45 2009 +0900
   521.3 @@ -0,0 +1,1043 @@
   521.4 +/* ========================================================================
   521.5 + * Copyright 1988-2008 University of Washington
   521.6 + *
   521.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   521.8 + * you may not use this file except in compliance with the License.
   521.9 + * You may obtain a copy of the License at
  521.10 + *
  521.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  521.12 + *
  521.13 + * 
  521.14 + * ========================================================================
  521.15 + */
  521.16 +
  521.17 +/*
  521.18 + * Program:	UNIX TCP/IP routines
  521.19 + *
  521.20 + * Author:	Mark Crispin
  521.21 + *		Networks and Distributed Computing
  521.22 + *		Computing & Communications
  521.23 + *		University of Washington
  521.24 + *		Administration Building, AG-44
  521.25 + *		Seattle, WA  98195
  521.26 + *		Internet: MRC@CAC.Washington.EDU
  521.27 + *
  521.28 + * Date:	1 August 1988
  521.29 + * Last Edited:	13 January 2008
  521.30 + */
  521.31 +
  521.32 +#include "ip_unix.c"
  521.33 +
  521.34 +#undef write			/* don't use redefined write() */
  521.35 + 
  521.36 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  521.37 +static long ttmo_open = 0;	/* TCP timeouts, in seconds */
  521.38 +static long ttmo_read = 0;
  521.39 +static long ttmo_write = 0;
  521.40 +static long rshtimeout = 15;	/* rsh timeout */
  521.41 +static char *rshcommand = NIL;	/* rsh command */
  521.42 +static char *rshpath = NIL;	/* rsh path */
  521.43 +static long sshtimeout = 15;	/* ssh timeout */
  521.44 +static char *sshcommand = NIL;	/* ssh command */
  521.45 +static char *sshpath = NIL;	/* ssh path */
  521.46 +static long allowreversedns = T;/* allow reverse DNS lookup */
  521.47 +static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
  521.48 +static char *myClientAddr = NIL;/* client IP address */
  521.49 +static char *myClientHost = NIL;/* client DNS name */
  521.50 +static long myClientPort = -1;	/* client port number */
  521.51 +static char *myServerAddr = NIL;/* server IP address */
  521.52 +static char *myServerHost = NIL;/* server DNS name */
  521.53 +static long myServerPort = -1;	/* server port number */
  521.54 +
  521.55 +extern long maxposint;		/* get this from write.c */
  521.56 +
  521.57 +/* Local function prototypes */
  521.58 +
  521.59 +int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
  521.60 +		     char *tmp,int *ctr,char *hst);
  521.61 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  521.62 +			       long *contd);
  521.63 +long tcp_abort (TCPSTREAM *stream);
  521.64 +char *tcp_name (struct sockaddr *sadr,long flag);
  521.65 +char *tcp_name_valid (char *s);
  521.66 +
  521.67 +/* TCP/IP manipulate parameters
  521.68 + * Accepts: function code
  521.69 + *	    function-dependent value
  521.70 + * Returns: function-dependent return value
  521.71 + */
  521.72 +
  521.73 +void *tcp_parameters (long function,void *value)
  521.74 +{
  521.75 +  void *ret = NIL;
  521.76 +  switch ((int) function) {
  521.77 +  case SET_TIMEOUT:
  521.78 +    tmoh = (tcptimeout_t) value;
  521.79 +  case GET_TIMEOUT:
  521.80 +    ret = (void *) tmoh;
  521.81 +    break;
  521.82 +  case SET_OPENTIMEOUT:
  521.83 +    ttmo_open = (long) value;
  521.84 +  case GET_OPENTIMEOUT:
  521.85 +    ret = (void *) ttmo_open;
  521.86 +    break;
  521.87 +  case SET_READTIMEOUT:
  521.88 +    ttmo_read = (long) value;
  521.89 +  case GET_READTIMEOUT:
  521.90 +    ret = (void *) ttmo_read;
  521.91 +    break;
  521.92 +  case SET_WRITETIMEOUT:
  521.93 +    ttmo_write = (long) value;
  521.94 +  case GET_WRITETIMEOUT:
  521.95 +    ret = (void *) ttmo_write;
  521.96 +    break;
  521.97 +  case SET_ALLOWREVERSEDNS:
  521.98 +    allowreversedns = (long) value;
  521.99 +  case GET_ALLOWREVERSEDNS:
 521.100 +    ret = (void *) allowreversedns;
 521.101 +    break;
 521.102 +  case SET_TCPDEBUG:
 521.103 +    tcpdebug = (long) value;
 521.104 +  case GET_TCPDEBUG:
 521.105 +    ret = (void *) tcpdebug;
 521.106 +    break;
 521.107 +
 521.108 +  case SET_RSHTIMEOUT:
 521.109 +    rshtimeout = (long) value;
 521.110 +  case GET_RSHTIMEOUT:
 521.111 +    ret = (void *) rshtimeout;
 521.112 +    break;
 521.113 +  case SET_RSHCOMMAND:
 521.114 +    if (rshcommand) fs_give ((void **) &rshcommand);
 521.115 +    rshcommand = cpystr ((char *) value);
 521.116 +  case GET_RSHCOMMAND:
 521.117 +    ret = (void *) rshcommand;
 521.118 +    break;
 521.119 +  case SET_RSHPATH:
 521.120 +    if (rshpath) fs_give ((void **) &rshpath);
 521.121 +    rshpath = cpystr ((char *) value);
 521.122 +  case GET_RSHPATH:
 521.123 +    ret = (void *) rshpath;
 521.124 +    break;
 521.125 +  case SET_SSHTIMEOUT:
 521.126 +    sshtimeout = (long) value;
 521.127 +  case GET_SSHTIMEOUT:
 521.128 +    ret = (void *) sshtimeout;
 521.129 +    break;
 521.130 +  case SET_SSHCOMMAND:
 521.131 +    if (sshcommand) fs_give ((void **) &sshcommand);
 521.132 +    sshcommand = cpystr ((char *) value);
 521.133 +  case GET_SSHCOMMAND:
 521.134 +    ret = (void *) sshcommand;
 521.135 +    break;
 521.136 +  case SET_SSHPATH:
 521.137 +    if (sshpath) fs_give ((void **) &sshpath);
 521.138 +    sshpath = cpystr ((char *) value);
 521.139 +  case GET_SSHPATH:
 521.140 +    ret = (void *) sshpath;
 521.141 +    break;
 521.142 +  }
 521.143 +  return ret;
 521.144 +}
 521.145 +
 521.146 +/* TCP/IP open
 521.147 + * Accepts: host name
 521.148 + *	    contact service name
 521.149 + *	    contact port number and optional silent flag
 521.150 + * Returns: TCP/IP stream if success else NIL
 521.151 + */
 521.152 +
 521.153 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
 521.154 +{
 521.155 +  TCPSTREAM *stream = NIL;
 521.156 +  int family;
 521.157 +  int sock = -1;
 521.158 +  int ctr = 0;
 521.159 +  int silent = (port & NET_SILENT) ? T : NIL;
 521.160 +  int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr;
 521.161 +  char *s,*hostname,tmp[MAILTMPLEN];
 521.162 +  void *adr;
 521.163 +  size_t adrlen;
 521.164 +  struct servent *sv = NIL;
 521.165 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.166 +  void *data,*next;
 521.167 +  port &= 0xffff;		/* erase flags */
 521.168 +				/* lookup service */
 521.169 +  if (service && (sv = getservbyname (service,"tcp")))
 521.170 +    port = ntohs (sv->s_port);
 521.171 +  /* The domain literal form is used (rather than simply the dotted decimal
 521.172 +     as with other Unix programs) because it has to be a valid "host name"
 521.173 +     in mailsystem terminology. */
 521.174 +				/* look like domain literal? */
 521.175 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
 521.176 +    strcpy (tmp,host+1);	/* yes, copy number part */
 521.177 +    tmp[(strlen (tmp))-1] = '\0';
 521.178 +    if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) {
 521.179 +      (*bn) (BLOCK_TCPOPEN,NIL);
 521.180 +				/* get an open socket for this system */
 521.181 +      sock = tcp_socket_open (family,adr,adrlen,port,tmp,ctrp,hostname = host);
 521.182 +      (*bn) (BLOCK_NONE,NIL);
 521.183 +      fs_give ((void **) &adr);
 521.184 +    }
 521.185 +    else sprintf (tmp,"Bad format domain-literal: %.80s",host);
 521.186 +  }
 521.187 +
 521.188 +  else {			/* lookup host name */
 521.189 +    if (tcpdebug) {
 521.190 +      sprintf (tmp,"DNS resolution %.80s",host);
 521.191 +      mm_log (tmp,TCPDEBUG);
 521.192 +    }
 521.193 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 521.194 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
 521.195 +    if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next)))
 521.196 +      sprintf (tmp,"No such host as %.80s",host);
 521.197 +    (*bn) (BLOCK_NONSENSITIVE,data);
 521.198 +    (*bn) (BLOCK_NONE,NIL);
 521.199 +    if (s) {			/* DNS resolution won? */
 521.200 +      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
 521.201 +      do {
 521.202 +	(*bn) (BLOCK_TCPOPEN,NIL);
 521.203 +	if (((sock = tcp_socket_open (family,s,adrlen,port,tmp,ctrp,
 521.204 +				      hostname)) < 0) &&
 521.205 +	    (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) &&
 521.206 +	    !silent) mm_log (tmp,WARN);
 521.207 +	(*bn) (BLOCK_NONE,NIL);
 521.208 +      } while ((sock < 0) && s);/* repeat until success or no more addreses */
 521.209 +    }
 521.210 +  }
 521.211 +  if (sock >= 0)  {		/* won */
 521.212 +    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
 521.213 +				   sizeof (TCPSTREAM));
 521.214 +    stream->port = port;	/* port number */
 521.215 +				/* init sockets */
 521.216 +    stream->tcpsi = stream->tcpso = sock;
 521.217 +				/* stash in the snuck-in byte */
 521.218 +    if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0];
 521.219 +				/* copy official host name */
 521.220 +    stream->host = cpystr (hostname);
 521.221 +    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
 521.222 +  }
 521.223 +  else if (!silent) mm_log (tmp,ERROR);
 521.224 +  return stream;		/* return success */
 521.225 +}
 521.226 +
 521.227 +/* Open a TCP socket
 521.228 + * Accepts: protocol family
 521.229 + *	    address to connect to
 521.230 + *	    address length
 521.231 + *	    port
 521.232 + *	    scratch buffer
 521.233 + *	    pointer to "first byte read in" storage or NIL
 521.234 + *	    host name for error message
 521.235 + * Returns: socket if success, else -1 with error string in scratch buffer
 521.236 + */
 521.237 +
 521.238 +int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
 521.239 +		     char *tmp,int *ctr,char *hst)
 521.240 +{
 521.241 +  int i,ti,sock,flgs;
 521.242 +  size_t len;
 521.243 +  time_t now;
 521.244 +  struct protoent *pt = getprotobyname ("tcp");
 521.245 +  fd_set fds,efds;
 521.246 +  struct timeval tmo;
 521.247 +  struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len);
 521.248 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.249 +				/* fetid Solaris */
 521.250 +  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
 521.251 +  sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr));
 521.252 +  mm_log (tmp,NIL);
 521.253 +				/* make a socket */
 521.254 +  if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
 521.255 +    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
 521.256 +    (*bn) (BLOCK_NONSENSITIVE,data);
 521.257 +  }
 521.258 +  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
 521.259 +    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
 521.260 +	     sock,FD_SETSIZE);
 521.261 +    (*bn) (BLOCK_NONSENSITIVE,data);
 521.262 +    close (sock);
 521.263 +    sock = -1;
 521.264 +    errno = EMFILE;
 521.265 +  }
 521.266 +
 521.267 +  else {			/* get current socket flags */
 521.268 +    flgs = fcntl (sock,F_GETFL,0);
 521.269 +				/* set non-blocking if want open timeout */
 521.270 +    if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY);
 521.271 +				/* open connection */
 521.272 +    while ((i = connect (sock,sadr,len)) < 0 && (errno == EINTR));
 521.273 +    (*bn) (BLOCK_NONSENSITIVE,data);
 521.274 +    if (i < 0) switch (errno) {	/* failed? */
 521.275 +    case EAGAIN:		/* DG brain damage */
 521.276 +    case EINPROGRESS:		/* what we expect to happen */
 521.277 +    case EALREADY:		/* or another form of it */
 521.278 +    case EISCONN:		/* restart after interrupt? */
 521.279 +    case EADDRINUSE:		/* restart after interrupt? */
 521.280 +      break;			/* well, not really, it was interrupted */
 521.281 +    default:
 521.282 +      sprintf (tmp,"Can't connect to %.80s,%u: %s",hst,(unsigned int) port,
 521.283 +	       strerror (errno));
 521.284 +      close (sock);		/* flush socket */
 521.285 +      sock = -1;
 521.286 +    }
 521.287 +    if ((sock >= 0) && ctr) {	/* want open timeout? */
 521.288 +      now = time (0);		/* open timeout */
 521.289 +      ti = ttmo_open ? now + ttmo_open : 0;
 521.290 +      tmo.tv_usec = 0;
 521.291 +      FD_ZERO (&fds);		/* initialize selection vector */
 521.292 +      FD_ZERO (&efds);		/* handle errors too */
 521.293 +      FD_SET (sock,&fds);	/* block for error or readable */
 521.294 +      FD_SET (sock,&efds);
 521.295 +      do {			/* block under timeout */
 521.296 +	tmo.tv_sec = ti ? ti - now : 0;
 521.297 +	i = select (sock+1,&fds,NIL,&efds,ti ? &tmo : NIL);
 521.298 +	now = time (0);		/* fake timeout if interrupt & time expired */
 521.299 +	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 521.300 +      } while ((i < 0) && (errno == EINTR));
 521.301 +      if (i > 0) {		/* success, make sure really connected */
 521.302 +				/* restore blocking status */
 521.303 +	fcntl (sock,F_SETFL,flgs);
 521.304 +	/* This used to be a zero-byte read(), but that crashes Solaris */
 521.305 +				/* get socket status */
 521.306 +	while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR));
 521.307 +      }	
 521.308 +      if (i <= 0) {		/* timeout or error? */
 521.309 +	i = i ? errno : ETIMEDOUT;/* determine error code */
 521.310 +	close (sock);		/* flush socket */
 521.311 +	sock = -1;
 521.312 +	errno = i;		/* return error code */
 521.313 +	sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst,
 521.314 +		 (unsigned long) port,strerror (errno));
 521.315 +      }
 521.316 +    }
 521.317 +  }
 521.318 +  fs_give ((void **) &sadr);
 521.319 +  return sock;			/* return the socket */
 521.320 +}
 521.321 +  
 521.322 +/* TCP/IP authenticated open
 521.323 + * Accepts: host name
 521.324 + *	    service name
 521.325 + *	    returned user name buffer
 521.326 + * Returns: TCP/IP stream if success else NIL
 521.327 + */
 521.328 +
 521.329 +#define MAXARGV 20
 521.330 +
 521.331 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 521.332 +{
 521.333 +  TCPSTREAM *stream = NIL;
 521.334 +  void *adr;
 521.335 +  char host[MAILTMPLEN],tmp[MAILTMPLEN],*path,*argv[MAXARGV+1],*r;
 521.336 +  int i,ti,pipei[2],pipeo[2];
 521.337 +  size_t len;
 521.338 +  time_t now;
 521.339 +  struct timeval tmo;
 521.340 +  fd_set fds,efds;
 521.341 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.342 +#ifdef SSHPATH			/* ssh path defined yet? */
 521.343 +  if (!sshpath) sshpath = cpystr (SSHPATH);
 521.344 +#endif
 521.345 +#ifdef RSHPATH			/* rsh path defined yet? */
 521.346 +  if (!rshpath) rshpath = cpystr (RSHPATH);
 521.347 +#endif
 521.348 +  if (*service == '*') {	/* want ssh? */
 521.349 +				/* return immediately if ssh disabled */
 521.350 +    if (!(sshpath && (ti = sshtimeout))) return NIL;
 521.351 +				/* ssh command prototype defined yet? */
 521.352 +    if (!sshcommand) sshcommand = cpystr ("%s %s -l %s exec /etc/r%sd");
 521.353 +  }
 521.354 +				/* want rsh? */
 521.355 +  else if (rshpath && (ti = rshtimeout)) {
 521.356 +				/* rsh command prototype defined yet? */
 521.357 +    if (!rshcommand) rshcommand = cpystr ("%s %s -l %s exec /etc/r%sd");
 521.358 +  }
 521.359 +  else return NIL;		/* rsh disabled */
 521.360 +				/* look like domain literal? */
 521.361 +  if (mb->host[0] == '[' && mb->host[i = (strlen (mb->host))-1] == ']') {
 521.362 +    strcpy (host,mb->host+1);	/* yes, copy without brackets */
 521.363 +    host[i-1] = '\0';
 521.364 +				/* validate domain literal */
 521.365 +    if (adr = ip_stringtoaddr (host,&len,&i)) fs_give ((void **) &adr);
 521.366 +    else {
 521.367 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
 521.368 +      mm_log (tmp,ERROR);
 521.369 +      return NIL;
 521.370 +    }
 521.371 +  }
 521.372 +  else strcpy (host,tcp_canonical (mb->host));
 521.373 +
 521.374 +  if (*service == '*')		/* build ssh command */
 521.375 +    sprintf (tmp,sshcommand,sshpath,host,
 521.376 +	     mb->user[0] ? mb->user : myusername (),service + 1);
 521.377 +  else sprintf (tmp,rshcommand,rshpath,host,
 521.378 +		mb->user[0] ? mb->user : myusername (),service);
 521.379 +  if (tcpdebug) {
 521.380 +    char msg[MAILTMPLEN];
 521.381 +    sprintf (msg,"Trying %.100s",tmp);
 521.382 +    mm_log (msg,TCPDEBUG);
 521.383 +  }
 521.384 +				/* parse command into argv */
 521.385 +  for (i = 1,path = argv[0] = strtok_r (tmp," ",&r);
 521.386 +       (i < MAXARGV) && (argv[i] = strtok_r (NIL," ",&r)); i++);
 521.387 +  argv[i] = NIL;		/* make sure argv tied off */
 521.388 +				/* make command pipes */
 521.389 +  if (pipe (pipei) < 0) return NIL;
 521.390 +  if ((pipei[0] >= FD_SETSIZE) || (pipei[1] >= FD_SETSIZE) ||
 521.391 +      (pipe (pipeo) < 0)) {
 521.392 +    close (pipei[0]); close (pipei[1]);
 521.393 +    return NIL;
 521.394 +  }
 521.395 +  (*bn) (BLOCK_TCPOPEN,NIL);	/* quell alarm up here for NeXT */
 521.396 +  if ((pipeo[0] >= FD_SETSIZE) || (pipeo[1] >= FD_SETSIZE) ||
 521.397 +      ((i = fork ()) < 0)) {	/* make inferior process */
 521.398 +    close (pipei[0]); close (pipei[1]);
 521.399 +    close (pipeo[0]); close (pipeo[1]);
 521.400 +    (*bn) (BLOCK_NONE,NIL);
 521.401 +    return NIL;
 521.402 +  }
 521.403 +  if (!i) {			/* if child */
 521.404 +    alarm (0);			/* never have alarms in children */
 521.405 +    if (!fork ()) {		/* make grandchild so it's inherited by init */
 521.406 +      int cf;			/* don't alter parent vars in case vfork() */
 521.407 +      int maxfd = max (20,max (max(pipei[0],pipei[1]),max(pipeo[0],pipeo[1])));
 521.408 +      dup2 (pipei[1],1);	/* parent's input is my output */
 521.409 +      dup2 (pipei[1],2);	/* parent's input is my error output too */
 521.410 +      dup2 (pipeo[0],0);	/* parent's output is my input */
 521.411 +				/* close all unnecessary descriptors */
 521.412 +      for (cf = 3; cf <= maxfd; cf++) close (cf);
 521.413 +      setpgrp (0,getpid ());	/* be our own process group */
 521.414 +      _exit (execv (path,argv));/* now run it */
 521.415 +    }
 521.416 +    _exit (1);			/* child is done */
 521.417 +  }
 521.418 +  grim_pid_reap (i,NIL);	/* reap child; grandchild now owned by init */
 521.419 +  close (pipei[1]);		/* close child's side of the pipes */
 521.420 +  close (pipeo[0]);
 521.421 +
 521.422 +				/* create TCP/IP stream */
 521.423 +  stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
 521.424 +				 sizeof (TCPSTREAM));
 521.425 +				/* copy remote host name from argument */
 521.426 +  stream->remotehost = cpystr (stream->host = cpystr (host));
 521.427 +  stream->tcpsi = pipei[0];	/* init sockets */
 521.428 +  stream->tcpso = pipeo[1];
 521.429 +  stream->ictr = 0;		/* init input counter */
 521.430 +  stream->port = 0xffffffff;	/* no port number */
 521.431 +  ti += now = time (0);		/* open timeout */
 521.432 +  tmo.tv_usec = 0;		/* initialize usec timeout */
 521.433 +  FD_ZERO (&fds);		/* initialize selection vector */
 521.434 +  FD_ZERO (&efds);		/* handle errors too */
 521.435 +  FD_SET (stream->tcpsi,&fds);	/* set bit in selection vector */
 521.436 +  FD_SET (stream->tcpsi,&efds);	/* set bit in error selection vector */
 521.437 +  FD_SET (stream->tcpso,&efds);	/* set bit in error selection vector */
 521.438 +  do {				/* block under timeout */
 521.439 +    tmo.tv_sec = ti - now;
 521.440 +    i = select (max (stream->tcpsi,stream->tcpso)+1,&fds,NIL,&efds,&tmo);
 521.441 +    now = time (0);		/* fake timeout if interrupt & time expired */
 521.442 +    if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 521.443 +  } while ((i < 0) && (errno == EINTR));
 521.444 +  if (i <= 0) {			/* timeout or error? */
 521.445 +    sprintf (tmp,i ? "error in %s to IMAP server" :
 521.446 +	     "%s to IMAP server timed out",(*service == '*') ? "ssh" : "rsh");
 521.447 +    mm_log (tmp,WARN);
 521.448 +    tcp_close (stream);		/* punt stream */
 521.449 +    stream = NIL;
 521.450 +  }
 521.451 +  (*bn) (BLOCK_NONE,NIL);
 521.452 +				/* return user name */
 521.453 +  strcpy (usrbuf,mb->user[0] ? mb->user : myusername ());
 521.454 +  return stream;		/* return success */
 521.455 +}
 521.456 +
 521.457 +/* TCP receive line
 521.458 + * Accepts: TCP stream
 521.459 + * Returns: text line string or NIL if failure
 521.460 + */
 521.461 +
 521.462 +char *tcp_getline (TCPSTREAM *stream)
 521.463 +{
 521.464 +  unsigned long n,contd;
 521.465 +  char *ret = tcp_getline_work (stream,&n,&contd);
 521.466 +  if (ret && contd) {		/* got a line needing continuation? */
 521.467 +    STRINGLIST *stl = mail_newstringlist ();
 521.468 +    STRINGLIST *stc = stl;
 521.469 +    do {			/* collect additional lines */
 521.470 +      stc->text.data = (unsigned char *) ret;
 521.471 +      stc->text.size = n;
 521.472 +      stc = stc->next = mail_newstringlist ();
 521.473 +      ret = tcp_getline_work (stream,&n,&contd);
 521.474 +    } while (ret && contd);
 521.475 +    if (ret) {			/* stash final part of line on list */
 521.476 +      stc->text.data = (unsigned char *) ret;
 521.477 +      stc->text.size = n;
 521.478 +				/* determine how large a buffer we need */
 521.479 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 521.480 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 521.481 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 521.482 +	memcpy (ret + n,stc->text.data,stc->text.size);
 521.483 +      ret[n] = '\0';
 521.484 +    }
 521.485 +    mail_free_stringlist (&stl);/* either way, done with list */
 521.486 +  }
 521.487 +  return ret;
 521.488 +}
 521.489 +
 521.490 +/* TCP receive line or partial line
 521.491 + * Accepts: TCP stream
 521.492 + *	    pointer to return size
 521.493 + *	    pointer to return continuation flag
 521.494 + * Returns: text line string, size and continuation flag, or NIL if failure
 521.495 + */
 521.496 +
 521.497 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 521.498 +			       long *contd)
 521.499 +{
 521.500 +  unsigned long n;
 521.501 +  char *s,*ret,c,d;
 521.502 +  *contd = NIL;			/* assume no continuation */
 521.503 +				/* make sure have data */
 521.504 +  if (!tcp_getdata (stream)) return NIL;
 521.505 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 521.506 +    d = *stream->iptr++;	/* slurp another character */
 521.507 +    if ((c == '\015') && (d == '\012')) {
 521.508 +      ret = (char *) fs_get (n--);
 521.509 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 521.510 +      ret[n] = '\0';		/* tie off string with null */
 521.511 +      return ret;
 521.512 +    }
 521.513 +  }
 521.514 +				/* copy partial string from buffer */
 521.515 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 521.516 +				/* get more data from the net */
 521.517 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 521.518 +				/* special case of newline broken by buffer */
 521.519 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 521.520 +    stream->iptr++;		/* eat the line feed */
 521.521 +    stream->ictr--;
 521.522 +    ret[*size = --n] = '\0';	/* tie off string with null */
 521.523 +  }
 521.524 +  else *contd = LONGT;		/* continuation needed */
 521.525 +  return ret;
 521.526 +}
 521.527 +
 521.528 +/* TCP/IP receive buffer
 521.529 + * Accepts: TCP/IP stream
 521.530 + *	    size in bytes
 521.531 + *	    buffer to read into
 521.532 + * Returns: T if success, NIL otherwise
 521.533 + */
 521.534 +
 521.535 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
 521.536 +{
 521.537 +  unsigned long n;
 521.538 +				/* make sure socket still alive */
 521.539 +  if (stream->tcpsi < 0) return NIL;
 521.540 +				/* can transfer bytes from buffer? */
 521.541 +  if (n = min (size,stream->ictr)) {
 521.542 +    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
 521.543 +    s += n;			/* update pointer */
 521.544 +    stream->iptr +=n;
 521.545 +    size -= n;			/* update # of bytes to do */
 521.546 +    stream->ictr -=n;
 521.547 +  }
 521.548 +  if (size) {
 521.549 +    int i;
 521.550 +    fd_set fds,efds;
 521.551 +    struct timeval tmo;
 521.552 +    time_t t = time (0);
 521.553 +    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.554 +    (*bn) (BLOCK_TCPREAD,NIL);
 521.555 +    while (size > 0) {		/* until request satisfied */
 521.556 +      time_t tl = time (0);
 521.557 +      time_t now = tl;
 521.558 +      time_t ti = ttmo_read ? now + ttmo_read : 0;
 521.559 +      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
 521.560 +      tmo.tv_usec = 0;
 521.561 +      FD_ZERO (&fds);		/* initialize selection vector */
 521.562 +      FD_ZERO (&efds);		/* handle errors too */
 521.563 +				/* set bit in selection vectors */
 521.564 +      FD_SET (stream->tcpsi,&fds);
 521.565 +      FD_SET (stream->tcpsi,&efds);
 521.566 +      errno = NIL;		/* initially no error */
 521.567 +      do {			/* block under timeout */
 521.568 +	tmo.tv_sec = ti ? ti - now : 0;
 521.569 +	i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
 521.570 +	now = time (0);		/* fake timeout if interrupt & time expired */
 521.571 +	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 521.572 +      } while ((i < 0) && (errno == EINTR));
 521.573 +      if (i) {			/* non-timeout result from select? */
 521.574 +	if (i > 0)		/* read what we can */
 521.575 +	  while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0)
 521.576 +		 && (errno == EINTR));
 521.577 +	if (i <= 0) {		/* error seen? */
 521.578 +	  if (tcpdebug) {
 521.579 +	    char tmp[MAILTMPLEN];
 521.580 +	    if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno);
 521.581 +	    else s = "TCP buffer read end of file";
 521.582 +	    mm_log (s,TCPDEBUG);
 521.583 +	  }
 521.584 +	  return tcp_abort (stream);
 521.585 +	}
 521.586 +	s += i;			/* success, point at new place to write */
 521.587 +	size -= i;		/* reduce byte count */
 521.588 +	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
 521.589 +      }
 521.590 +				/* timeout, punt unless told not to */
 521.591 +      else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
 521.592 +	if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
 521.593 +	return tcp_abort (stream);
 521.594 +      }
 521.595 +    }
 521.596 +    (*bn) (BLOCK_NONE,NIL);
 521.597 +  }
 521.598 +  *s = '\0';			/* tie off string */
 521.599 +  return LONGT;
 521.600 +}
 521.601 +
 521.602 +/* TCP/IP receive data
 521.603 + * Accepts: TCP/IP stream
 521.604 + * Returns: T if success, NIL otherwise
 521.605 + */
 521.606 +
 521.607 +long tcp_getdata (TCPSTREAM *stream)
 521.608 +{
 521.609 +  int i;
 521.610 +  fd_set fds,efds;
 521.611 +  struct timeval tmo;
 521.612 +  time_t t = time (0);
 521.613 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.614 +  if (stream->tcpsi < 0) return NIL;
 521.615 +  (*bn) (BLOCK_TCPREAD,NIL);
 521.616 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 521.617 +    time_t tl = time (0);	/* start of request */
 521.618 +    time_t now = tl;
 521.619 +    time_t ti = ttmo_read ? now + ttmo_read : 0;
 521.620 +    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
 521.621 +    tmo.tv_usec = 0;
 521.622 +    FD_ZERO (&fds);		/* initialize selection vector */
 521.623 +    FD_ZERO (&efds);		/* handle errors too */
 521.624 +    FD_SET (stream->tcpsi,&fds);/* set bit in selection vectors */
 521.625 +    FD_SET (stream->tcpsi,&efds);
 521.626 +    errno = NIL;		/* initially no error */
 521.627 +    do {			/* block under timeout */
 521.628 +      tmo.tv_sec = ti ? ti - now : 0;
 521.629 +      i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
 521.630 +      now = time (0);		/* fake timeout if interrupt & time expired */
 521.631 +      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 521.632 +    } while ((i < 0) && (errno == EINTR));
 521.633 +    if (i) {			/* non-timeout result from select? */
 521.634 +				/* read what we can */
 521.635 +      if (i > 0) while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
 521.636 +			(errno == EINTR));
 521.637 +      if (i <= 0) {		/* error seen? */
 521.638 +	if (tcpdebug) {
 521.639 +	  char *s,tmp[MAILTMPLEN];
 521.640 +	  if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno);
 521.641 +	  else s = "TCP data read end of file";
 521.642 +	  mm_log (s,TCPDEBUG);
 521.643 +	}
 521.644 +	return tcp_abort (stream);
 521.645 +      }
 521.646 +      stream->ictr = i;		/* success, set new count and pointer */
 521.647 +      stream->iptr = stream->ibuf;
 521.648 +      if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
 521.649 +    }
 521.650 +				/* timeout, punt unless told not to */
 521.651 +    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
 521.652 +      if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
 521.653 +      return tcp_abort (stream);/* error or timeout no-continue */
 521.654 +    }
 521.655 +  }
 521.656 +  (*bn) (BLOCK_NONE,NIL);
 521.657 +  return T;
 521.658 +}
 521.659 +
 521.660 +/* TCP/IP send string as record
 521.661 + * Accepts: TCP/IP stream
 521.662 + *	    string pointer
 521.663 + * Returns: T if success else NIL
 521.664 + */
 521.665 +
 521.666 +long tcp_soutr (TCPSTREAM *stream,char *string)
 521.667 +{
 521.668 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 521.669 +}
 521.670 +
 521.671 +
 521.672 +/* TCP/IP send string
 521.673 + * Accepts: TCP/IP stream
 521.674 + *	    string pointer
 521.675 + *	    byte count
 521.676 + * Returns: T if success else NIL
 521.677 + */
 521.678 +
 521.679 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 521.680 +{
 521.681 +  int i;
 521.682 +  fd_set fds,efds;
 521.683 +  struct timeval tmo;
 521.684 +  time_t t = time (0);
 521.685 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.686 +  if (stream->tcpso < 0) return NIL;
 521.687 +  (*bn) (BLOCK_TCPWRITE,NIL);
 521.688 +  while (size > 0) {		/* until request satisfied */
 521.689 +    time_t tl = time (0);	/* start of request */
 521.690 +    time_t now = tl;
 521.691 +    time_t ti = ttmo_write ? now + ttmo_write : 0;
 521.692 +    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
 521.693 +    tmo.tv_usec = 0;
 521.694 +    FD_ZERO (&fds);		/* initialize selection vector */
 521.695 +    FD_ZERO (&efds);		/* handle errors too */
 521.696 +    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
 521.697 +    FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */
 521.698 +    errno = NIL;		/* block and write */
 521.699 +    do {			/* block under timeout */
 521.700 +      tmo.tv_sec = ti ? ti - now : 0;
 521.701 +      i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL);
 521.702 +      now = time (0);		/* fake timeout if interrupt & time expired */
 521.703 +      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
 521.704 +    } while ((i < 0) && (errno == EINTR));
 521.705 +    if (i) {			/* non-timeout result from select? */
 521.706 +				/* write what we can */
 521.707 +      if (i > 0) while (((i = write (stream->tcpso,string,size)) < 0) &&
 521.708 +			(errno == EINTR));
 521.709 +      if (i <= 0) {		/* error seen? */
 521.710 +	if (tcpdebug) {
 521.711 +	  char tmp[MAILTMPLEN];
 521.712 +	  sprintf (tmp,"TCP write I/O error %d",errno);
 521.713 +	  mm_log (tmp,TCPDEBUG);
 521.714 +	}
 521.715 +	return tcp_abort (stream);
 521.716 +      }
 521.717 +      string += i;		/* how much we sent */
 521.718 +      size -= i;		/* count this size */
 521.719 +      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
 521.720 +    }
 521.721 +				/* timeout, punt unless told not to */
 521.722 +    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
 521.723 +      if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
 521.724 +      return tcp_abort (stream);
 521.725 +    }
 521.726 +  }
 521.727 +  (*bn) (BLOCK_NONE,NIL);
 521.728 +  return T;			/* all done */
 521.729 +}
 521.730 +
 521.731 +/* TCP/IP close
 521.732 + * Accepts: TCP/IP stream
 521.733 + */
 521.734 +
 521.735 +void tcp_close (TCPSTREAM *stream)
 521.736 +{
 521.737 +  tcp_abort (stream);		/* nuke the stream */
 521.738 +				/* flush host names */
 521.739 +  if (stream->host) fs_give ((void **) &stream->host);
 521.740 +  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
 521.741 +  if (stream->localhost) fs_give ((void **) &stream->localhost);
 521.742 +  fs_give ((void **) &stream);	/* flush the stream */
 521.743 +}
 521.744 +
 521.745 +
 521.746 +/* TCP/IP abort stream
 521.747 + * Accepts: TCP/IP stream
 521.748 + * Returns: NIL always
 521.749 + */
 521.750 +
 521.751 +long tcp_abort (TCPSTREAM *stream)
 521.752 +{
 521.753 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.754 +  if (stream->tcpsi >= 0) {	/* no-op if no socket */
 521.755 +    (*bn) (BLOCK_TCPCLOSE,NIL);
 521.756 +    close (stream->tcpsi);	/* nuke the socket */
 521.757 +    if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
 521.758 +    stream->tcpsi = stream->tcpso = -1;
 521.759 +  }
 521.760 +  (*bn) (BLOCK_NONE,NIL);
 521.761 +  return NIL;
 521.762 +}
 521.763 +
 521.764 +/* TCP/IP get host name
 521.765 + * Accepts: TCP/IP stream
 521.766 + * Returns: host name for this stream
 521.767 + */
 521.768 +
 521.769 +char *tcp_host (TCPSTREAM *stream)
 521.770 +{
 521.771 +  return stream->host;		/* use tcp_remotehost() if want guarantees */
 521.772 +}
 521.773 +
 521.774 +
 521.775 +/* TCP/IP get remote host name
 521.776 + * Accepts: TCP/IP stream
 521.777 + * Returns: host name for this stream
 521.778 + */
 521.779 +
 521.780 +char *tcp_remotehost (TCPSTREAM *stream)
 521.781 +{
 521.782 +  if (!stream->remotehost) {
 521.783 +    size_t sadrlen;
 521.784 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 521.785 +    stream->remotehost =	/* get socket's peer name */
 521.786 +      getpeername (stream->tcpsi,sadr,(void *) &sadrlen) ?
 521.787 +        cpystr (stream->host) : tcp_name (sadr,NIL);
 521.788 +    fs_give ((void **) &sadr);
 521.789 +  }
 521.790 +  return stream->remotehost;
 521.791 +}
 521.792 +
 521.793 +
 521.794 +/* TCP/IP return port for this stream
 521.795 + * Accepts: TCP/IP stream
 521.796 + * Returns: port number for this stream
 521.797 + */
 521.798 +
 521.799 +unsigned long tcp_port (TCPSTREAM *stream)
 521.800 +{
 521.801 +  return stream->port;		/* return port number */
 521.802 +}
 521.803 +
 521.804 +
 521.805 +/* TCP/IP get local host name
 521.806 + * Accepts: TCP/IP stream
 521.807 + * Returns: local host name
 521.808 + */
 521.809 +
 521.810 +char *tcp_localhost (TCPSTREAM *stream)
 521.811 +{
 521.812 +  if (!stream->localhost) {
 521.813 +    size_t sadrlen;
 521.814 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 521.815 +    stream->localhost =		/* get socket's name */
 521.816 +      ((stream->port & 0xffff000) ||
 521.817 +       getsockname (stream->tcpsi,sadr,(void *) &sadrlen)) ?
 521.818 +      cpystr (mylocalhost ()) : tcp_name (sadr,NIL);
 521.819 +    fs_give ((void **) &sadr);
 521.820 +  }
 521.821 +  return stream->localhost;	/* return local host name */
 521.822 +}
 521.823 +
 521.824 +/* TCP/IP get client host address (server calls only)
 521.825 + * Returns: client host address
 521.826 + */
 521.827 +
 521.828 +char *tcp_clientaddr ()
 521.829 +{
 521.830 +  if (!myClientAddr) {
 521.831 +    size_t sadrlen;
 521.832 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 521.833 +    if (getpeername (0,sadr,(void *) &sadrlen))
 521.834 +      myClientAddr = cpystr ("UNKNOWN");
 521.835 +    else {			/* get stdin's peer name */
 521.836 +      myClientAddr = cpystr (ip_sockaddrtostring (sadr));
 521.837 +      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
 521.838 +    }
 521.839 +    fs_give ((void **) &sadr);
 521.840 +  }
 521.841 +  return myClientAddr;
 521.842 +}
 521.843 +
 521.844 +
 521.845 +/* TCP/IP get client host name (server calls only)
 521.846 + * Returns: client host name
 521.847 + */
 521.848 +
 521.849 +char *tcp_clienthost ()
 521.850 +{
 521.851 +  if (!myClientHost) {
 521.852 +    size_t sadrlen;
 521.853 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 521.854 +    if (getpeername (0,sadr,(void *) &sadrlen)) {
 521.855 +      char *s,*t,*v,tmp[MAILTMPLEN];
 521.856 +      if ((s = getenv (t = "SSH_CLIENT")) ||
 521.857 +	  (s = getenv (t = "KRB5REMOTEADDR")) ||
 521.858 +	  (s = getenv (t = "SSH2_CLIENT"))) {
 521.859 +	if (v = strchr (s,' ')) *v = '\0';
 521.860 +	sprintf (v = tmp,"%.80s=%.80s",t,s);
 521.861 +      }
 521.862 +      else v = "UNKNOWN";
 521.863 +      myClientHost = cpystr (v);
 521.864 +    }
 521.865 +    else {			/* get stdin's peer name */
 521.866 +      myClientHost = tcp_name (sadr,T);
 521.867 +      if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr));
 521.868 +      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
 521.869 +    }
 521.870 +    fs_give ((void **) &sadr);
 521.871 +  }
 521.872 +  return myClientHost;
 521.873 +}
 521.874 +
 521.875 +
 521.876 +/* TCP/IP get client port number (server calls only)
 521.877 + * Returns: client port number
 521.878 + */
 521.879 +
 521.880 +long tcp_clientport ()
 521.881 +{
 521.882 +  if (!myClientHost && !myClientAddr) tcp_clientaddr ();
 521.883 +  return myClientPort;
 521.884 +}
 521.885 +
 521.886 +/* TCP/IP get server host address (server calls only)
 521.887 + * Returns: server host address
 521.888 + */
 521.889 +
 521.890 +char *tcp_serveraddr ()
 521.891 +{
 521.892 +  if (!myServerAddr) {
 521.893 +    size_t sadrlen;
 521.894 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 521.895 +    if (getsockname (0,sadr,(void *) &sadrlen))
 521.896 +      myServerAddr = cpystr ("UNKNOWN");
 521.897 +    else {			/* get stdin's name */
 521.898 +      myServerAddr = cpystr (ip_sockaddrtostring (sadr));
 521.899 +      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
 521.900 +    }
 521.901 +    fs_give ((void **) &sadr);
 521.902 +  }
 521.903 +  return myServerAddr;
 521.904 +}
 521.905 +
 521.906 +
 521.907 +/* TCP/IP get server host name (server calls only)
 521.908 + * Returns: server host name
 521.909 + */
 521.910 +
 521.911 +char *tcp_serverhost ()
 521.912 +{
 521.913 +  if (!myServerHost) {		/* once-only */
 521.914 +    size_t sadrlen;
 521.915 +    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
 521.916 +				/* get stdin's name */
 521.917 +    if (getsockname (0,sadr,(void *) &sadrlen))
 521.918 +      myServerHost = cpystr (mylocalhost ());
 521.919 +    else {			/* get stdin's name */
 521.920 +      myServerHost = tcp_name (sadr,NIL);
 521.921 +      if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr));
 521.922 +      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
 521.923 +    }
 521.924 +    fs_give ((void **) &sadr);
 521.925 +  }
 521.926 +  return myServerHost;
 521.927 +}
 521.928 +
 521.929 +
 521.930 +/* TCP/IP get server port number (server calls only)
 521.931 + * Returns: server port number
 521.932 + */
 521.933 +
 521.934 +long tcp_serverport ()
 521.935 +{
 521.936 +  if (!myServerHost && !myServerAddr) tcp_serveraddr ();
 521.937 +  return myServerPort;
 521.938 +}
 521.939 +
 521.940 +/* TCP/IP return canonical form of host name
 521.941 + * Accepts: host name
 521.942 + * Returns: canonical form of host name
 521.943 + */
 521.944 +
 521.945 +char *tcp_canonical (char *name)
 521.946 +{
 521.947 +  char *ret,host[MAILTMPLEN];
 521.948 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 521.949 +  void *data;
 521.950 +				/* look like domain literal? */
 521.951 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 521.952 +  (*bn) (BLOCK_DNSLOOKUP,NIL);	/* quell alarms */
 521.953 +  data = (*bn) (BLOCK_SENSITIVE,NIL);
 521.954 +  if (tcpdebug) {
 521.955 +    sprintf (host,"DNS canonicalization %.80s",name);
 521.956 +    mm_log (host,TCPDEBUG);
 521.957 +  }
 521.958 +				/* get canonical name */
 521.959 +  if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name;
 521.960 +  (*bn) (BLOCK_NONSENSITIVE,data);
 521.961 +  (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 521.962 +  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
 521.963 +  return ret;
 521.964 +}
 521.965 +
 521.966 +/* TCP/IP return name from socket
 521.967 + * Accepts: socket
 521.968 + *	    verbose flag
 521.969 + * Returns: cpystr name
 521.970 + */
 521.971 +
 521.972 +char *tcp_name (struct sockaddr *sadr,long flag)
 521.973 +{
 521.974 +  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
 521.975 +  sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr));
 521.976 +  if (allowreversedns) {
 521.977 +    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
 521.978 +    void *data;
 521.979 +    if (tcpdebug) {
 521.980 +      sprintf (tmp,"Reverse DNS resolution %s",adr);
 521.981 +      mm_log (tmp,TCPDEBUG);
 521.982 +    }
 521.983 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 521.984 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
 521.985 +				/* translate address to name */
 521.986 +    if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) {
 521.987 +				/* produce verbose form if needed */
 521.988 +      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
 521.989 +      else ret = t;
 521.990 +    }
 521.991 +    (*bn) (BLOCK_NONSENSITIVE,data);
 521.992 +    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 521.993 +    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
 521.994 +  }
 521.995 +  return cpystr (ret);
 521.996 +}
 521.997 +
 521.998 +
 521.999 +/* TCP/IP validate name
521.1000 + * Accepts: domain name
521.1001 + * Returns: name if valid, NIL otherwise
521.1002 + */
521.1003 +
521.1004 +char *tcp_name_valid (char *s)
521.1005 +{
521.1006 +  int c;
521.1007 +  char *ret,*tail;
521.1008 +				/* must be non-empty and not too long */
521.1009 +  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
521.1010 +				/* must be alnum, dot, or hyphen */
521.1011 +    while ((c = *s++) && (s <= tail) &&
521.1012 +	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
521.1013 +	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
521.1014 +    if (c) ret = NIL;
521.1015 +  }
521.1016 +  return ret;
521.1017 +}
521.1018 +
521.1019 +/* TCP/IP check if client is given host name
521.1020 + * Accepts: candidate host name
521.1021 + * Returns: T if match, NIL otherwise
521.1022 + */
521.1023 +
521.1024 +long tcp_isclienthost (char *host)
521.1025 +{
521.1026 +  int family;
521.1027 +  size_t adrlen,sadrlen,len;
521.1028 +  void *adr,*next;
521.1029 +  struct sockaddr *sadr;
521.1030 +  long ret = NIL;
521.1031 +				/* make sure that myClientAddr is set */
521.1032 +  if (tcp_clienthost () && myClientAddr)
521.1033 +				/* get sockaddr of client */
521.1034 +    for (adr = ip_nametoaddr (host,&adrlen,&family,NIL,&next); adr && !ret;
521.1035 +	 adr = ip_nametoaddr (NIL,&adrlen,&family,NIL,&next)) {
521.1036 +				/* build sockaddr of given address */
521.1037 +      sadr = ip_sockaddr (family,adr,adrlen,1,&len);
521.1038 +      if (!strcmp (myClientAddr,ip_sockaddrtostring (sadr))) ret = LONGT;
521.1039 +      fs_give ((void **) &sadr);	/* done with client sockaddr */
521.1040 +    }
521.1041 +  return ret;
521.1042 +}
521.1043 +
521.1044 +/* Following statement must be at end of this module */
521.1045 +
521.1046 +#undef fork			/* undo any use of vfork() */
   522.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   522.2 +++ b/src/osdep/unix/tcp_unix.h	Mon Sep 14 15:17:45 2009 +0900
   522.3 @@ -0,0 +1,48 @@
   522.4 +/* ========================================================================
   522.5 + * Copyright 1988-2006 University of Washington
   522.6 + *
   522.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   522.8 + * you may not use this file except in compliance with the License.
   522.9 + * You may obtain a copy of the License at
  522.10 + *
  522.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  522.12 + *
  522.13 + * 
  522.14 + * ========================================================================
  522.15 + */
  522.16 +
  522.17 +/*
  522.18 + * Program:	UNIX TCP/IP routines
  522.19 + *
  522.20 + * Author:	Mark Crispin
  522.21 + *		Networks and Distributed Computing
  522.22 + *		Computing & Communications
  522.23 + *		University of Washington
  522.24 + *		Administration Building, AG-44
  522.25 + *		Seattle, WA  98195
  522.26 + *		Internet: MRC@CAC.Washington.EDU
  522.27 + *
  522.28 + * Date:	1 August 1988
  522.29 + * Last Edited:	30 August 2006
  522.30 + */
  522.31 +
  522.32 +
  522.33 +/* TCP input buffer */
  522.34 +
  522.35 +#define BUFLEN 8192
  522.36 +
  522.37 +
  522.38 +/* TCP I/O stream */
  522.39 +
  522.40 +#define TCPSTREAM struct tcp_stream
  522.41 +TCPSTREAM {
  522.42 +  char *host;			/* host name */
  522.43 +  unsigned long port;		/* port number */
  522.44 +  char *localhost;		/* local host name */
  522.45 +  char *remotehost;		/* remote host name */
  522.46 +  int tcpsi;			/* input socket */
  522.47 +  int tcpso;			/* output socket */
  522.48 +  int ictr;			/* input counter */
  522.49 +  char *iptr;			/* input pointer */
  522.50 +  char ibuf[BUFLEN];		/* input buffer */
  522.51 +};
   523.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   523.2 +++ b/src/osdep/unix/tenex.c	Mon Sep 14 15:17:45 2009 +0900
   523.3 @@ -0,0 +1,1470 @@
   523.4 +/* ========================================================================
   523.5 + * Copyright 1988-2007 University of Washington
   523.6 + *
   523.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   523.8 + * you may not use this file except in compliance with the License.
   523.9 + * You may obtain a copy of the License at
  523.10 + *
  523.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  523.12 + *
  523.13 + * 
  523.14 + * ========================================================================
  523.15 + */
  523.16 +
  523.17 +/*
  523.18 + * Program:	Tenex mail routines
  523.19 + *
  523.20 + * Author:	Mark Crispin
  523.21 + *		Networks and Distributed Computing
  523.22 + *		Computing & Communications
  523.23 + *		University of Washington
  523.24 + *		Administration Building, AG-44
  523.25 + *		Seattle, WA  98195
  523.26 + *		Internet: MRC@CAC.Washington.EDU
  523.27 + *
  523.28 + * Date:	22 May 1990
  523.29 + * Last Edited:	11 October 2007
  523.30 + */
  523.31 +
  523.32 +
  523.33 +/*				FILE TIME SEMANTICS
  523.34 + *
  523.35 + * The atime is the last read time of the file.
  523.36 + * The mtime is the last flags update time of the file.
  523.37 + * The ctime is the last write time of the file.
  523.38 + *
  523.39 + *				TEXT SIZE SEMANTICS
  523.40 + *
  523.41 + * Most of the text sizes are in internal (LF-only) form, except for the
  523.42 + * msg.text size.  Beware.
  523.43 + */
  523.44 +
  523.45 +#include <stdio.h>
  523.46 +#include <ctype.h>
  523.47 +#include <errno.h>
  523.48 +extern int errno;		/* just in case */
  523.49 +#include "mail.h"
  523.50 +#include "osdep.h"
  523.51 +#include <sys/stat.h>
  523.52 +#include "misc.h"
  523.53 +#include "dummy.h"
  523.54 +
  523.55 +/* TENEX I/O stream local data */
  523.56 +	
  523.57 +typedef struct tenex_local {
  523.58 +  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
  523.59 +  unsigned int mustcheck: 1;	/* if ping must do a check instead */
  523.60 +  int fd;			/* file descriptor for I/O */
  523.61 +  off_t filesize;		/* file size parsed */
  523.62 +  time_t filetime;		/* last file time */
  523.63 +  time_t lastsnarf;		/* local snarf time */
  523.64 +  unsigned char *buf;		/* temporary buffer */
  523.65 +  unsigned long buflen;		/* current size of temporary buffer */
  523.66 +  unsigned long uid;		/* current text uid */
  523.67 +  SIZEDTEXT text;		/* current text */
  523.68 +} TENEXLOCAL;
  523.69 +
  523.70 +
  523.71 +/* Convenient access to local data */
  523.72 +
  523.73 +#define LOCAL ((TENEXLOCAL *) stream->local)
  523.74 +
  523.75 +
  523.76 +/* Function prototypes */
  523.77 +
  523.78 +DRIVER *tenex_valid (char *name);
  523.79 +int tenex_isvalid (char *name,char *tmp);
  523.80 +void *tenex_parameters (long function,void *value);
  523.81 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  523.82 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
  523.83 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
  523.84 +long tenex_create (MAILSTREAM *stream,char *mailbox);
  523.85 +long tenex_delete (MAILSTREAM *stream,char *mailbox);
  523.86 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
  523.87 +long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
  523.88 +MAILSTREAM *tenex_open (MAILSTREAM *stream);
  523.89 +void tenex_close (MAILSTREAM *stream,long options);
  523.90 +void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
  523.91 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
  523.92 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
  523.93 +		    unsigned long *length,long flags);
  523.94 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
  523.95 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
  523.96 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
  523.97 +long tenex_ping (MAILSTREAM *stream);
  523.98 +void tenex_check (MAILSTREAM *stream);
  523.99 +void tenex_snarf (MAILSTREAM *stream);
 523.100 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
 523.101 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 523.102 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 523.103 +
 523.104 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
 523.105 +char *tenex_file (char *dst,char *name);
 523.106 +long tenex_parse (MAILSTREAM *stream);
 523.107 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
 523.108 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
 523.109 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
 523.110 +			  long syncflag);
 523.111 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
 523.112 +			    unsigned long *size);
 523.113 +
 523.114 +/* Tenex mail routines */
 523.115 +
 523.116 +
 523.117 +/* Driver dispatch used by MAIL */
 523.118 +
 523.119 +DRIVER tenexdriver = {
 523.120 +  "tenex",			/* driver name */
 523.121 +  DR_LOCAL|DR_MAIL|DR_NOSTICKY|DR_LOCKING,
 523.122 +				/* driver flags */
 523.123 +  (DRIVER *) NIL,		/* next driver */
 523.124 +  tenex_valid,			/* mailbox is valid for us */
 523.125 +  tenex_parameters,		/* manipulate parameters */
 523.126 +  tenex_scan,			/* scan mailboxes */
 523.127 +  tenex_list,			/* list mailboxes */
 523.128 +  tenex_lsub,			/* list subscribed mailboxes */
 523.129 +  NIL,				/* subscribe to mailbox */
 523.130 +  NIL,				/* unsubscribe from mailbox */
 523.131 +  dummy_create,			/* create mailbox */
 523.132 +  tenex_delete,			/* delete mailbox */
 523.133 +  tenex_rename,			/* rename mailbox */
 523.134 +  tenex_status,			/* status of mailbox */
 523.135 +  tenex_open,			/* open mailbox */
 523.136 +  tenex_close,			/* close mailbox */
 523.137 +  tenex_fast,			/* fetch message "fast" attributes */
 523.138 +  tenex_flags,			/* fetch message flags */
 523.139 +  NIL,				/* fetch overview */
 523.140 +  NIL,				/* fetch message envelopes */
 523.141 +  tenex_header,			/* fetch message header */
 523.142 +  tenex_text,			/* fetch message body */
 523.143 +  NIL,				/* fetch partial message text */
 523.144 +  NIL,				/* unique identifier */
 523.145 +  NIL,				/* message number */
 523.146 +  tenex_flag,			/* modify flags */
 523.147 +  tenex_flagmsg,		/* per-message modify flags */
 523.148 +  NIL,				/* search for message based on criteria */
 523.149 +  NIL,				/* sort messages */
 523.150 +  NIL,				/* thread messages */
 523.151 +  tenex_ping,			/* ping mailbox to see if still alive */
 523.152 +  tenex_check,			/* check for new messages */
 523.153 +  tenex_expunge,		/* expunge deleted messages */
 523.154 +  tenex_copy,			/* copy messages to another mailbox */
 523.155 +  tenex_append,			/* append string message to mailbox */
 523.156 +  NIL				/* garbage collect stream */
 523.157 +};
 523.158 +
 523.159 +				/* prototype stream */
 523.160 +MAILSTREAM tenexproto = {&tenexdriver};
 523.161 +
 523.162 +/* Tenex mail validate mailbox
 523.163 + * Accepts: mailbox name
 523.164 + * Returns: our driver if name is valid, NIL otherwise
 523.165 + */
 523.166 +
 523.167 +DRIVER *tenex_valid (char *name)
 523.168 +{
 523.169 +  char tmp[MAILTMPLEN];
 523.170 +  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
 523.171 +}
 523.172 +
 523.173 +
 523.174 +/* Tenex mail test for valid mailbox
 523.175 + * Accepts: mailbox name
 523.176 + * Returns: T if valid, NIL otherwise
 523.177 + */
 523.178 +
 523.179 +int tenex_isvalid (char *name,char *tmp)
 523.180 +{
 523.181 +  int fd;
 523.182 +  int ret = NIL;
 523.183 +  char *s,file[MAILTMPLEN];
 523.184 +  struct stat sbuf;
 523.185 +  time_t tp[2];
 523.186 +  errno = EINVAL;		/* assume invalid argument */
 523.187 +				/* if file, get its status */
 523.188 +  if ((s = tenex_file (file,name)) && !stat (s,&sbuf)) {
 523.189 +    if (!sbuf.st_size) {	/* allow empty file if INBOX */
 523.190 +      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
 523.191 +      else errno = 0;		/* empty file */
 523.192 +    }
 523.193 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 523.194 +      memset (tmp,'\0',MAILTMPLEN);
 523.195 +      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
 523.196 +	  (s[-1] != '\015')) {	/* valid format? */
 523.197 +	*s = '\0';		/* tie off header */
 523.198 +				/* must begin with dd-mmm-yy" */
 523.199 +	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
 523.200 +		(tmp[1] == '-' && tmp[5] == '-')) &&
 523.201 +	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
 523.202 +      }
 523.203 +      else errno = -1;		/* bogus format */
 523.204 +      close (fd);		/* close the file */
 523.205 +				/* \Marked status? */
 523.206 +      if (sbuf.st_ctime > sbuf.st_atime) {
 523.207 +	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
 523.208 +	tp[1] = sbuf.st_mtime;
 523.209 +	utime (file,tp);	/* set the times */
 523.210 +      }
 523.211 +    }
 523.212 +  }
 523.213 +				/* in case INBOX but not tenex format */
 523.214 +  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
 523.215 +  return ret;			/* return what we should */
 523.216 +}
 523.217 +
 523.218 +/* Tenex manipulate driver parameters
 523.219 + * Accepts: function code
 523.220 + *	    function-dependent value
 523.221 + * Returns: function-dependent return value
 523.222 + */
 523.223 +
 523.224 +void *tenex_parameters (long function,void *value)
 523.225 +{
 523.226 +  void *ret = NIL;
 523.227 +  switch ((int) function) {
 523.228 +  case GET_INBOXPATH:
 523.229 +    if (value) ret = tenex_file ((char *) value,"INBOX");
 523.230 +    break;
 523.231 +  }
 523.232 +  return ret;
 523.233 +}
 523.234 +
 523.235 +
 523.236 +/* Tenex mail scan mailboxes
 523.237 + * Accepts: mail stream
 523.238 + *	    reference
 523.239 + *	    pattern to search
 523.240 + *	    string to scan
 523.241 + */
 523.242 +
 523.243 +void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 523.244 +{
 523.245 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 523.246 +}
 523.247 +
 523.248 +
 523.249 +/* Tenex mail list mailboxes
 523.250 + * Accepts: mail stream
 523.251 + *	    reference
 523.252 + *	    pattern to search
 523.253 + */
 523.254 +
 523.255 +void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
 523.256 +{
 523.257 +  if (stream) dummy_list (NIL,ref,pat);
 523.258 +}
 523.259 +
 523.260 +
 523.261 +/* Tenex mail list subscribed mailboxes
 523.262 + * Accepts: mail stream
 523.263 + *	    reference
 523.264 + *	    pattern to search
 523.265 + */
 523.266 +
 523.267 +void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
 523.268 +{
 523.269 +  if (stream) dummy_lsub (NIL,ref,pat);
 523.270 +}
 523.271 +
 523.272 +/* Tenex mail delete mailbox
 523.273 + * Accepts: MAIL stream
 523.274 + *	    mailbox name to delete
 523.275 + * Returns: T on success, NIL on failure
 523.276 + */
 523.277 +
 523.278 +long tenex_delete (MAILSTREAM *stream,char *mailbox)
 523.279 +{
 523.280 +  return tenex_rename (stream,mailbox,NIL);
 523.281 +}
 523.282 +
 523.283 +
 523.284 +/* Tenex mail rename mailbox
 523.285 + * Accepts: MAIL stream
 523.286 + *	    old mailbox name
 523.287 + *	    new mailbox name (or NIL for delete)
 523.288 + * Returns: T on success, NIL on failure
 523.289 + */
 523.290 +
 523.291 +long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
 523.292 +{
 523.293 +  long ret = T;
 523.294 +  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 523.295 +  int fd,ld;
 523.296 +  struct stat sbuf;
 523.297 +  if (!tenex_file (file,old) ||
 523.298 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 523.299 +		   ((s = strrchr (tmp,'/')) && !s[1])))) {
 523.300 +    sprintf (tmp,newname ?
 523.301 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 523.302 +	     "Can't delete mailbox %.80s: invalid name",
 523.303 +	     old,newname);
 523.304 +    MM_LOG (tmp,ERROR);
 523.305 +    return NIL;
 523.306 +  }
 523.307 +  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
 523.308 +    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
 523.309 +    MM_LOG (tmp,ERROR);
 523.310 +    return NIL;
 523.311 +  }
 523.312 +				/* get exclusive parse/append permission */
 523.313 +  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
 523.314 +    MM_LOG ("Unable to lock rename mailbox",ERROR);
 523.315 +    return NIL;
 523.316 +  }
 523.317 +				/* lock out other users */
 523.318 +  if (flock (fd,LOCK_EX|LOCK_NB)) {
 523.319 +    close (fd);			/* couldn't lock, give up on it then */
 523.320 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 523.321 +    MM_LOG (tmp,ERROR);
 523.322 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 523.323 +    return NIL;
 523.324 +  }
 523.325 +
 523.326 +  if (newname) {		/* want rename? */
 523.327 +    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
 523.328 +      c = *++s;			/* remember first character of inferior */
 523.329 +      *s = '\0';		/* tie off to get just superior */
 523.330 +				/* name doesn't exist, create it */
 523.331 +      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 523.332 +	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
 523.333 +	ret = NIL;
 523.334 +      else *s = c;		/* restore full name */
 523.335 +    }
 523.336 +				/* rename the file */
 523.337 +    if (ret && rename (file,tmp)) {
 523.338 +      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 523.339 +	       strerror (errno));
 523.340 +      MM_LOG (tmp,ERROR);
 523.341 +      ret = NIL;		/* set failure */
 523.342 +    }
 523.343 +  }
 523.344 +  else if (unlink (file)) {
 523.345 +    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 523.346 +    MM_LOG (tmp,ERROR);
 523.347 +    ret = NIL;			/* set failure */
 523.348 +  }
 523.349 +  flock (fd,LOCK_UN);		/* release lock on the file */
 523.350 +  close (fd);			/* close the file */
 523.351 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
 523.352 +				/* recreate file if renamed INBOX */
 523.353 +  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"mail.txt");
 523.354 +  return ret;			/* return success */
 523.355 +}
 523.356 +
 523.357 +/* Tenex Mail status
 523.358 + * Accepts: mail stream
 523.359 + *	    mailbox name
 523.360 + *	    status flags
 523.361 + * Returns: T on success, NIL on failure
 523.362 + */
 523.363 +
 523.364 +long tenex_status (MAILSTREAM *stream,char *mbx,long flags)
 523.365 +{
 523.366 +  MAILSTATUS status;
 523.367 +  unsigned long i;
 523.368 +  MAILSTREAM *tstream = NIL;
 523.369 +  MAILSTREAM *systream = NIL;
 523.370 +				/* make temporary stream (unless this mbx) */
 523.371 +  if (!stream && !(stream = tstream =
 523.372 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
 523.373 +  status.flags = flags;		/* return status values */
 523.374 +  status.messages = stream->nmsgs;
 523.375 +  status.recent = stream->recent;
 523.376 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 523.377 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
 523.378 +      if (!mail_elt (stream,i)->seen) status.unseen++;
 523.379 +  status.uidnext = stream->uid_last + 1;
 523.380 +  status.uidvalidity = stream->uid_validity;
 523.381 +				/* calculate post-snarf results */
 523.382 +  if (!status.recent && stream->inbox &&
 523.383 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
 523.384 +    status.messages += systream->nmsgs;
 523.385 +    status.recent += systream->recent;
 523.386 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
 523.387 +      for (i = 1; i <= systream->nmsgs; i++)
 523.388 +	if (!mail_elt (systream,i)->seen) status.unseen++;
 523.389 +				/* kludge but probably good enough */
 523.390 +    status.uidnext += systream->nmsgs;
 523.391 +  }
 523.392 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
 523.393 +  if (tstream) mail_close (tstream);
 523.394 +  if (systream) mail_close (systream);
 523.395 +  return T;			/* success */
 523.396 +}
 523.397 +
 523.398 +/* Tenex mail open
 523.399 + * Accepts: stream to open
 523.400 + * Returns: stream on success, NIL on failure
 523.401 + */
 523.402 +
 523.403 +MAILSTREAM *tenex_open (MAILSTREAM *stream)
 523.404 +{
 523.405 +  int fd,ld;
 523.406 +  char tmp[MAILTMPLEN];
 523.407 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 523.408 +				/* return prototype for OP_PROTOTYPE call */
 523.409 +  if (!stream) return user_flags (&tenexproto);
 523.410 +  if (stream->local) fatal ("tenex recycle stream");
 523.411 +  user_flags (stream);		/* set up user flags */
 523.412 +				/* canonicalize the mailbox name */
 523.413 +  if (!tenex_file (tmp,stream->mailbox)) {
 523.414 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 523.415 +    MM_LOG (tmp,ERROR);
 523.416 +  }
 523.417 +  if (stream->rdonly ||
 523.418 +      (fd = open (tmp,O_RDWR,NIL)) < 0) {
 523.419 +    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
 523.420 +      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
 523.421 +      MM_LOG (tmp,ERROR);
 523.422 +      return NIL;
 523.423 +    }
 523.424 +    else if (!stream->rdonly) {	/* got it, but readonly */
 523.425 +      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 523.426 +      stream->rdonly = T;
 523.427 +    }
 523.428 +  }
 523.429 +  stream->local = fs_get (sizeof (TENEXLOCAL));
 523.430 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 523.431 +  LOCAL->buflen = CHUNKSIZE - 1;
 523.432 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 523.433 +  LOCAL->text.size = CHUNKSIZE - 1;
 523.434 +
 523.435 +				/* note if an INBOX or not */
 523.436 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 523.437 +  LOCAL->fd = fd;		/* bind the file */
 523.438 +				/* flush old name */
 523.439 +  fs_give ((void **) &stream->mailbox);
 523.440 +				/* save canonical name */
 523.441 +  stream->mailbox = cpystr (tmp);
 523.442 +				/* get shared parse permission */
 523.443 +  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
 523.444 +    MM_LOG ("Unable to lock open mailbox",ERROR);
 523.445 +    return NIL;
 523.446 +  }
 523.447 +  (*bn) (BLOCK_FILELOCK,NIL);
 523.448 +  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
 523.449 +  (*bn) (BLOCK_NONE,NIL);
 523.450 +  unlockfd (ld,tmp);		/* release shared parse permission */
 523.451 +  LOCAL->filesize = 0;		/* initialize parsed file size */
 523.452 +				/* time not set up yet */
 523.453 +  LOCAL->lastsnarf = LOCAL->filetime = 0;
 523.454 +  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 523.455 +  stream->sequence++;		/* bump sequence number */
 523.456 +				/* parse mailbox */
 523.457 +  stream->nmsgs = stream->recent = 0;
 523.458 +  if (tenex_ping (stream) && !stream->nmsgs)
 523.459 +    MM_LOG ("Mailbox is empty",(long) NIL);
 523.460 +  if (!LOCAL) return NIL;	/* failure if stream died */
 523.461 +  stream->perm_seen = stream->perm_deleted =
 523.462 +    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
 523.463 +      stream->rdonly ? NIL : T;
 523.464 +  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
 523.465 +  return stream;		/* return stream to caller */
 523.466 +}
 523.467 +
 523.468 +/* Tenex mail close
 523.469 + * Accepts: MAIL stream
 523.470 + *	    close options
 523.471 + */
 523.472 +
 523.473 +void tenex_close (MAILSTREAM *stream,long options)
 523.474 +{
 523.475 +  if (stream && LOCAL) {	/* only if a file is open */
 523.476 +    int silent = stream->silent;
 523.477 +    stream->silent = T;		/* note this stream is dying */
 523.478 +    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
 523.479 +    stream->silent = silent;	/* restore previous status */
 523.480 +    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
 523.481 +    close (LOCAL->fd);		/* close the local file */
 523.482 +				/* free local text buffer */
 523.483 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
 523.484 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
 523.485 +				/* nuke the local data */
 523.486 +    fs_give ((void **) &stream->local);
 523.487 +    stream->dtb = NIL;		/* log out the DTB */
 523.488 +  }
 523.489 +}
 523.490 +
 523.491 +/* Tenex mail fetch fast data
 523.492 + * Accepts: MAIL stream
 523.493 + *	    sequence
 523.494 + *	    option flags
 523.495 + */
 523.496 +
 523.497 +void tenex_fast (MAILSTREAM *stream,char *sequence,long flags)
 523.498 +{
 523.499 +  STRING bs;
 523.500 +  MESSAGECACHE *elt;
 523.501 +  unsigned long i;
 523.502 +  if (stream && LOCAL &&
 523.503 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 523.504 +       mail_sequence (stream,sequence)))
 523.505 +    for (i = 1; i <= stream->nmsgs; i++)
 523.506 +      if ((elt = mail_elt (stream,i))->sequence) {
 523.507 +	if (!elt->rfc822_size) { /* have header size yet? */
 523.508 +	  lseek (LOCAL->fd,elt->private.special.offset +
 523.509 +		 elt->private.special.text.size,L_SET);
 523.510 +				/* resize bigbuf if necessary */
 523.511 +	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
 523.512 +	    fs_give ((void **) &LOCAL->buf);
 523.513 +	    LOCAL->buflen = elt->private.msg.full.text.size;
 523.514 +	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
 523.515 +	  }
 523.516 +				/* tie off string */
 523.517 +	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
 523.518 +				/* read in the message */
 523.519 +	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
 523.520 +	  INIT (&bs,mail_string,(void *) LOCAL->buf,
 523.521 +		elt->private.msg.full.text.size);
 523.522 +				/* calculate its CRLF size */
 523.523 +	  elt->rfc822_size = strcrlflen (&bs);
 523.524 +	}
 523.525 +	tenex_elt (stream,i);	/* get current flags from file */
 523.526 +      }
 523.527 +}
 523.528 +
 523.529 +
 523.530 +/* Tenex mail fetch flags
 523.531 + * Accepts: MAIL stream
 523.532 + *	    sequence
 523.533 + *	    option flags
 523.534 + * Sniffs at file to get flags
 523.535 + */
 523.536 +
 523.537 +void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
 523.538 +{
 523.539 +  unsigned long i;
 523.540 +  if (stream && LOCAL &&
 523.541 +      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
 523.542 +       mail_sequence (stream,sequence)))
 523.543 +    for (i = 1; i <= stream->nmsgs; i++)
 523.544 +      if (mail_elt (stream,i)->sequence) tenex_elt (stream,i);
 523.545 +}
 523.546 +
 523.547 +/* TENEX mail fetch message header
 523.548 + * Accepts: MAIL stream
 523.549 + *	    message # to fetch
 523.550 + *	    pointer to returned header text length
 523.551 + *	    option flags
 523.552 + * Returns: message header in RFC822 format
 523.553 + */
 523.554 +
 523.555 +char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
 523.556 +		    unsigned long *length,long flags)
 523.557 +{
 523.558 +  char *s;
 523.559 +  unsigned long i;
 523.560 +  *length = 0;			/* default to empty */
 523.561 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 523.562 +				/* get to header position */
 523.563 +  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
 523.564 +  if (flags & FT_INTERNAL) {
 523.565 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 523.566 +      fs_give ((void **) &LOCAL->buf);
 523.567 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 523.568 +    }
 523.569 +				/* slurp the data */
 523.570 +    read (LOCAL->fd,LOCAL->buf,*length = i);
 523.571 +  }
 523.572 +  else {
 523.573 +    s = (char *) fs_get (i + 1);/* get readin buffer */
 523.574 +    s[i] = '\0';		/* tie off string */
 523.575 +    read (LOCAL->fd,s,i);	/* slurp the data */
 523.576 +				/* make CRLF copy of string */
 523.577 +    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
 523.578 +    fs_give ((void **) &s);	/* free readin buffer */
 523.579 +  }
 523.580 +  return (char *) LOCAL->buf;
 523.581 +}
 523.582 +
 523.583 +/* TENEX mail fetch message text (body only)
 523.584 + * Accepts: MAIL stream
 523.585 + *	    message # to fetch
 523.586 + *	    pointer to returned stringstruct
 523.587 + *	    option flags
 523.588 + * Returns: T, always
 523.589 + */
 523.590 +
 523.591 +long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 523.592 +{
 523.593 +  char *s;
 523.594 +  unsigned long i,j;
 523.595 +  MESSAGECACHE *elt;
 523.596 +				/* UID call "impossible" */
 523.597 +  if (flags & FT_UID) return NIL;
 523.598 +				/* get message status */
 523.599 +  elt = tenex_elt (stream,msgno);
 523.600 +				/* if message not seen */
 523.601 +  if (!(flags & FT_PEEK) && !elt->seen) {
 523.602 +    elt->seen = T;		/* mark message as seen */
 523.603 +				/* recalculate status */
 523.604 +    tenex_update_status (stream,msgno,T);
 523.605 +    MM_FLAGS (stream,msgno);
 523.606 +  }
 523.607 +  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
 523.608 +				/* find header position */
 523.609 +    i = tenex_hdrpos (stream,msgno,&j);
 523.610 +    if (i > LOCAL->buflen) {	/* resize if not enough space */
 523.611 +      fs_give ((void **) &LOCAL->buf);
 523.612 +      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
 523.613 +    }
 523.614 +				/* go to text position */
 523.615 +    lseek (LOCAL->fd,i + j,L_SET);
 523.616 +				/* slurp the data */
 523.617 +    read (LOCAL->fd,LOCAL->buf,i);
 523.618 +				/* set up stringstruct for internal */
 523.619 +    INIT (bs,mail_string,LOCAL->buf,i);
 523.620 +  }
 523.621 +  else {			/* normal form, previous text cached? */
 523.622 +    if (elt->private.uid == LOCAL->uid)
 523.623 +      i = elt->private.msg.text.text.size;
 523.624 +    else {			/* not cached, cache it now */
 523.625 +      LOCAL->uid = elt->private.uid;
 523.626 +				/* find header position */
 523.627 +      i = tenex_hdrpos (stream,msgno,&j);
 523.628 +				/* go to text position */
 523.629 +      lseek (LOCAL->fd,i + j,L_SET);
 523.630 +      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
 523.631 +      s[i] = '\0';		/* tie off string */
 523.632 +      read (LOCAL->fd,s,i);	/* slurp the data */
 523.633 +				/* make CRLF copy of string */
 523.634 +      i = elt->private.msg.text.text.size =
 523.635 +	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
 523.636 +      fs_give ((void **) &s);	/* free readin buffer */
 523.637 +    }
 523.638 +				/* set up stringstruct */
 523.639 +    INIT (bs,mail_string,LOCAL->text.data,i);
 523.640 +  }
 523.641 +  return T;			/* success */
 523.642 +}
 523.643 +
 523.644 +/* Tenex mail modify flags
 523.645 + * Accepts: MAIL stream
 523.646 + *	    sequence
 523.647 + *	    flag(s)
 523.648 + *	    option flags
 523.649 + */
 523.650 +
 523.651 +void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
 523.652 +{
 523.653 +  time_t tp[2];
 523.654 +  struct stat sbuf;
 523.655 +  if (!stream->rdonly) {	/* make sure the update takes */
 523.656 +    fsync (LOCAL->fd);
 523.657 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 523.658 +    tp[1] = LOCAL->filetime = sbuf.st_mtime;
 523.659 +    tp[0] = time (0);		/* make sure read comes after all that */
 523.660 +    utime (stream->mailbox,tp);
 523.661 +  }
 523.662 +}
 523.663 +
 523.664 +
 523.665 +/* Tenex mail per-message modify flags
 523.666 + * Accepts: MAIL stream
 523.667 + *	    message cache element
 523.668 + */
 523.669 +
 523.670 +void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 523.671 +{
 523.672 +  struct stat sbuf;
 523.673 +				/* maybe need to do a checkpoint? */
 523.674 +  if (LOCAL->filetime && !LOCAL->shouldcheck) {
 523.675 +    fstat (LOCAL->fd,&sbuf);	/* get current write time */
 523.676 +    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 523.677 +    LOCAL->filetime = 0;	/* don't do this test for any other messages */
 523.678 +  }
 523.679 +				/* recalculate status */
 523.680 +  tenex_update_status (stream,elt->msgno,NIL);
 523.681 +}
 523.682 +
 523.683 +/* Tenex mail ping mailbox
 523.684 + * Accepts: MAIL stream
 523.685 + * Returns: T if stream still alive, NIL if not
 523.686 + */
 523.687 +
 523.688 +long tenex_ping (MAILSTREAM *stream)
 523.689 +{
 523.690 +  unsigned long i = 1;
 523.691 +  long r = T;
 523.692 +  int ld;
 523.693 +  char lock[MAILTMPLEN];
 523.694 +  struct stat sbuf;
 523.695 +  if (stream && LOCAL) {	/* only if stream already open */
 523.696 +    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
 523.697 +    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
 523.698 +	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
 523.699 +				/* check for changed message status */
 523.700 +    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
 523.701 +      LOCAL->filetime = sbuf.st_mtime;
 523.702 +      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
 523.703 +	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
 523.704 +      while (i <= stream->nmsgs) tenex_elt (stream,i++);
 523.705 +      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
 523.706 +    }
 523.707 +				/* get shared parse/append permission */
 523.708 +    if ((sbuf.st_size != LOCAL->filesize) &&
 523.709 +	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 523.710 +				/* parse resulting mailbox */
 523.711 +      r = (tenex_parse (stream)) ? T : NIL;
 523.712 +      unlockfd (ld,lock);	/* release shared parse/append permission */
 523.713 +    }
 523.714 +    if (LOCAL) {		/* stream must still be alive */
 523.715 +				/* snarf if this is a read-write inbox */
 523.716 +      if (stream->inbox && !stream->rdonly) {
 523.717 +	tenex_snarf (stream);
 523.718 +	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
 523.719 +	if ((sbuf.st_size != LOCAL->filesize) &&
 523.720 +	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
 523.721 +				/* parse resulting mailbox */
 523.722 +	  r = (tenex_parse (stream)) ? T : NIL;
 523.723 +	  unlockfd (ld,lock);	/* release shared parse/append permission */
 523.724 +	}
 523.725 +      }
 523.726 +    }
 523.727 +  }
 523.728 +  return r;			/* return result of the parse */
 523.729 +}
 523.730 +
 523.731 +
 523.732 +/* Tenex mail check mailbox (reparses status too)
 523.733 + * Accepts: MAIL stream
 523.734 + */
 523.735 +
 523.736 +void tenex_check (MAILSTREAM *stream)
 523.737 +{
 523.738 +				/* mark that a check is desired */
 523.739 +  if (LOCAL) LOCAL->mustcheck = T;
 523.740 +  if (tenex_ping (stream)) MM_LOG ("Check completed",(long) NIL);
 523.741 +}
 523.742 +
 523.743 +/* Tenex mail snarf messages from system inbox
 523.744 + * Accepts: MAIL stream
 523.745 + */
 523.746 +
 523.747 +void tenex_snarf (MAILSTREAM *stream)
 523.748 +{
 523.749 +  unsigned long i = 0;
 523.750 +  unsigned long j,r,hdrlen,txtlen;
 523.751 +  struct stat sbuf;
 523.752 +  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
 523.753 +  MESSAGECACHE *elt;
 523.754 +  MAILSTREAM *sysibx = NIL;
 523.755 +  int ld;
 523.756 +				/* give up if can't get exclusive permission */
 523.757 +  if ((time (0) >= (LOCAL->lastsnarf +
 523.758 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
 523.759 +      strcmp (sysinbox (),stream->mailbox) &&
 523.760 +      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
 523.761 +    MM_CRITICAL (stream);	/* go critical */
 523.762 +				/* sizes match and anything in sysinbox? */
 523.763 +    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
 523.764 +	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
 523.765 +	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
 523.766 +	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
 523.767 +				/* yes, go to end of file in our mailbox */
 523.768 +      lseek (LOCAL->fd,sbuf.st_size,L_SET);
 523.769 +				/* for each message in sysibx mailbox */
 523.770 +      while (r && (++i <= sysibx->nmsgs)) {
 523.771 +				/* snarf message from system INBOX */
 523.772 +	hdr = cpystr (mail_fetchheader_full(sysibx,i,NIL,&hdrlen,FT_INTERNAL));
 523.773 +	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|FT_PEEK);
 523.774 +				/* if have a message */
 523.775 +	if (j = hdrlen + txtlen) {
 523.776 +				/* calculate header line */
 523.777 +	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
 523.778 +	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
 523.779 +		   ",%lu;0000000000%02o\n",j,(unsigned)
 523.780 +		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
 523.781 +		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
 523.782 +		    (fDRAFT * elt->draft)));
 523.783 +				/* copy message */
 523.784 +	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
 523.785 +	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
 523.786 +	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
 523.787 +	}
 523.788 +	fs_give ((void **) &hdr);
 523.789 +      }
 523.790 +
 523.791 +				/* make sure all the updates take */
 523.792 +      if (fsync (LOCAL->fd)) r = 0;
 523.793 +      if (r) {			/* delete all the messages we copied */
 523.794 +	if (r == 1) strcpy (tmp,"1");
 523.795 +	else sprintf (tmp,"1:%lu",r);
 523.796 +	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
 523.797 +	mail_expunge (sysibx);	/* now expunge all those messages */
 523.798 +      }
 523.799 +      else {
 523.800 +	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
 523.801 +	MM_LOG (LOCAL->buf,WARN);
 523.802 +	ftruncate (LOCAL->fd,sbuf.st_size);
 523.803 +      }
 523.804 +      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
 523.805 +      LOCAL->filetime = sbuf.st_mtime;
 523.806 +    }
 523.807 +    if (sysibx) mail_close (sysibx);
 523.808 +    MM_NOCRITICAL (stream);	/* release critical */
 523.809 +    unlockfd (ld,lock);		/* release exclusive parse/append permission */
 523.810 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
 523.811 +  }
 523.812 +}
 523.813 +
 523.814 +/* Tenex mail expunge mailbox
 523.815 + * Accepts: MAIL stream
 523.816 + *	    sequence to expunge if non-NIL
 523.817 + *	    expunge options
 523.818 + * Returns: T, always
 523.819 + */
 523.820 +
 523.821 +long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
 523.822 +{
 523.823 +  long ret;
 523.824 +  time_t tp[2];
 523.825 +  struct stat sbuf;
 523.826 +  off_t pos = 0;
 523.827 +  int ld;
 523.828 +  unsigned long i = 1;
 523.829 +  unsigned long j,k,m,recent;
 523.830 +  unsigned long n = 0;
 523.831 +  unsigned long delta = 0;
 523.832 +  char lock[MAILTMPLEN];
 523.833 +  MESSAGECACHE *elt;
 523.834 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 523.835 +  if (!(ret = (sequence ? ((options & EX_UID) ?
 523.836 +			   mail_uid_sequence (stream,sequence) :
 523.837 +			   mail_sequence (stream,sequence)) : LONGT) &&
 523.838 +	tenex_ping (stream)));	/* parse sequence if given, ping stream */
 523.839 +  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
 523.840 +  else {
 523.841 +    if (LOCAL->filetime && !LOCAL->shouldcheck) {
 523.842 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
 523.843 +      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
 523.844 +    }
 523.845 +  /* The cretins who designed flock() created a window of vulnerability in
 523.846 +   * upgrading locks from shared to exclusive or downgrading from exclusive
 523.847 +   * to shared.  Rather than maintain the lock at shared status at a minimum,
 523.848 +   * flock() actually *releases* the former lock.  Obviously they never talked
 523.849 +   * to any database guys.  Fortunately, we have the parse/append permission
 523.850 +   * lock.  If we require this lock before going exclusive on the mailbox,
 523.851 +   * another process can not sneak in and steal the exclusive mailbox lock on
 523.852 +   * us, because it will block on trying to get parse/append permission first.
 523.853 +   */
 523.854 +				/* get exclusive parse/append permission */
 523.855 +    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
 523.856 +      MM_LOG ("Unable to lock expunge mailbox",ERROR);
 523.857 +				/* make sure see any newly-arrived messages */
 523.858 +    else if (!tenex_parse (stream));
 523.859 +				/* get exclusive access */
 523.860 +    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
 523.861 +      (*bn) (BLOCK_FILELOCK,NIL);
 523.862 +      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
 523.863 +      (*bn) (BLOCK_NONE,NIL);
 523.864 +      MM_LOG ("Can't expunge because mailbox is in use by another process",
 523.865 +	      ERROR);
 523.866 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 523.867 +    }
 523.868 +
 523.869 +    else {
 523.870 +      MM_CRITICAL (stream);	/* go critical */
 523.871 +      recent = stream->recent;	/* get recent now that pinged and locked */
 523.872 +				/* for each message */
 523.873 +      while (i <= stream->nmsgs) {
 523.874 +				/* get cache element */
 523.875 +	elt = tenex_elt (stream,i);
 523.876 +				/* number of bytes to smash or preserve */
 523.877 +	k = elt->private.special.text.size + tenex_size (stream,i);
 523.878 +				/* if need to expunge this message */
 523.879 +	if (elt->deleted && (sequence ? elt->sequence : T)) {
 523.880 +				/* if recent, note one less recent message */
 523.881 +	  if (elt->recent) --recent;
 523.882 +	  delta += k;		/* number of bytes to delete */
 523.883 +				/* notify upper levels */
 523.884 +	  mail_expunged (stream,i);
 523.885 +	  n++;			/* count up one more expunged message */
 523.886 +	}
 523.887 +	else if (i++ && delta) {/* preserved message */
 523.888 +				/* first byte to preserve */
 523.889 +	  j = elt->private.special.offset;
 523.890 +	  do {			/* read from source position */
 523.891 +	    m = min (k,LOCAL->buflen);
 523.892 +	    lseek (LOCAL->fd,j,L_SET);
 523.893 +	    read (LOCAL->fd,LOCAL->buf,m);
 523.894 +	    pos = j - delta;	/* write to destination position */
 523.895 +	    lseek (LOCAL->fd,pos,L_SET);
 523.896 +	    while (T) {
 523.897 +	      lseek (LOCAL->fd,pos,L_SET);
 523.898 +	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
 523.899 +	      MM_NOTIFY (stream,strerror (errno),WARN);
 523.900 +	      MM_DISKERROR (stream,errno,T);
 523.901 +	    }
 523.902 +	    pos += m;		/* new position */
 523.903 +	    j += m;		/* next chunk, perhaps */
 523.904 +	  } while (k -= m);		/* until done */
 523.905 +				/* note the new address of this text */
 523.906 +	  elt->private.special.offset -= delta;
 523.907 +	}
 523.908 +				/* preserved but no deleted messages */
 523.909 +	else pos = elt->private.special.offset + k;
 523.910 +      }
 523.911 +
 523.912 +      if (n) {			/* truncate file after last message */
 523.913 +	if (pos != (LOCAL->filesize -= delta)) {
 523.914 +	  sprintf (LOCAL->buf,
 523.915 +		   "Calculated size mismatch %lu != %lu, delta = %lu",
 523.916 +		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
 523.917 +	  MM_LOG (LOCAL->buf,WARN);
 523.918 +	  LOCAL->filesize = pos;/* fix it then */
 523.919 +	}
 523.920 +	ftruncate (LOCAL->fd,LOCAL->filesize);
 523.921 +	sprintf (LOCAL->buf,"Expunged %lu messages",n);
 523.922 +				/* output the news */
 523.923 +	MM_LOG (LOCAL->buf,(long) NIL);
 523.924 +      }
 523.925 +      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
 523.926 +      fsync (LOCAL->fd);		/* force disk update */
 523.927 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
 523.928 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
 523.929 +      tp[0] = time (0);		/* reset atime to now */
 523.930 +      utime (stream->mailbox,tp);
 523.931 +      MM_NOCRITICAL (stream);	/* release critical */
 523.932 +				/* notify upper level of new mailbox size */
 523.933 +      mail_exists (stream,stream->nmsgs);
 523.934 +      mail_recent (stream,recent);
 523.935 +      (*bn) (BLOCK_FILELOCK,NIL);
 523.936 +      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
 523.937 +      (*bn) (BLOCK_NONE,NIL);
 523.938 +      unlockfd (ld,lock);	/* release exclusive parse/append permission */
 523.939 +    }
 523.940 +  }
 523.941 +  return LONGT;
 523.942 +}
 523.943 +
 523.944 +/* Tenex mail copy message(s)
 523.945 + * Accepts: MAIL stream
 523.946 + *	    sequence
 523.947 + *	    destination mailbox
 523.948 + *	    copy options
 523.949 + * Returns: T if success, NIL if failed
 523.950 + */
 523.951 +
 523.952 +long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 523.953 +{
 523.954 +  struct stat sbuf;
 523.955 +  time_t tp[2];
 523.956 +  MESSAGECACHE *elt;
 523.957 +  unsigned long i,j,k;
 523.958 +  long ret = LONGT;
 523.959 +  int fd,ld;
 523.960 +  char file[MAILTMPLEN],lock[MAILTMPLEN];
 523.961 +  mailproxycopy_t pc =
 523.962 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 523.963 +				/* make sure valid mailbox */
 523.964 +  if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) {
 523.965 +  case ENOENT:			/* no such file? */
 523.966 +    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 523.967 +    return NIL;
 523.968 +  case 0:			/* merely empty file? */
 523.969 +    break;
 523.970 +  case EACCES:			/* file protected */
 523.971 +    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 523.972 +    MM_LOG (LOCAL->buf,ERROR);
 523.973 +    return NIL;
 523.974 +  case EINVAL:
 523.975 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 523.976 +    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
 523.977 +    MM_LOG (LOCAL->buf,ERROR);
 523.978 +    return NIL;
 523.979 +  default:
 523.980 +    if (pc) return (*pc) (stream,sequence,mailbox,options);
 523.981 +    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
 523.982 +    MM_LOG (LOCAL->buf,ERROR);
 523.983 +    return NIL;
 523.984 +  }
 523.985 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 523.986 +	mail_sequence (stream,sequence))) return NIL;
 523.987 +				/* got file? */  
 523.988 +  if ((fd = open (tenex_file(file,mailbox),O_RDWR,NIL)) < 0) {
 523.989 +    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
 523.990 +    MM_LOG (LOCAL->buf,ERROR);
 523.991 +    return NIL;
 523.992 +  }
 523.993 +  MM_CRITICAL (stream);		/* go critical */
 523.994 +				/* get exclusive parse/append permission */
 523.995 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
 523.996 +    MM_LOG ("Unable to lock copy mailbox",ERROR);
 523.997 +    MM_NOCRITICAL (stream);
 523.998 +    return NIL;
 523.999 +  }
523.1000 +  fstat (fd,&sbuf);		/* get current file size */
523.1001 +  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
523.1002 +
523.1003 +				/* for each requested message */
523.1004 +  for (i = 1; ret && (i <= stream->nmsgs); i++) 
523.1005 +    if ((elt = mail_elt (stream,i))->sequence) {
523.1006 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
523.1007 +				/* number of bytes to copy */
523.1008 +      k = elt->private.special.text.size + tenex_size (stream,i);
523.1009 +      do {			/* read from source position */
523.1010 +	j = min (k,LOCAL->buflen);
523.1011 +	read (LOCAL->fd,LOCAL->buf,j);
523.1012 +	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
523.1013 +      } while (ret && (k -= j));/* until done */
523.1014 +    }
523.1015 +				/* make sure all the updates take */
523.1016 +  if (!(ret && (ret = !fsync (fd)))) {
523.1017 +    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
523.1018 +    MM_LOG (LOCAL->buf,ERROR);
523.1019 +    ftruncate (fd,sbuf.st_size);
523.1020 +  }
523.1021 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
523.1022 +				/* else preserve \Marked status */
523.1023 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
523.1024 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
523.1025 +  utime (file,tp);		/* set the times */
523.1026 +  close (fd);			/* close the file */
523.1027 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
523.1028 +  MM_NOCRITICAL (stream);	/* release critical */
523.1029 +				/* delete all requested messages */
523.1030 +  if (ret && (options & CP_MOVE)) {
523.1031 +    for (i = 1; i <= stream->nmsgs; i++)
523.1032 +      if ((elt = tenex_elt (stream,i))->sequence) {
523.1033 +	elt->deleted = T;	/* mark message deleted */
523.1034 +				/* recalculate status */
523.1035 +	tenex_update_status (stream,i,NIL);
523.1036 +      }
523.1037 +    if (!stream->rdonly) {	/* make sure the update takes */
523.1038 +      fsync (LOCAL->fd);
523.1039 +      fstat (LOCAL->fd,&sbuf);	/* get current write time */
523.1040 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
523.1041 +      tp[0] = time (0);		/* make sure atime remains greater */
523.1042 +      utime (stream->mailbox,tp);
523.1043 +    }
523.1044 +  }
523.1045 +  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
523.1046 +    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
523.1047 +  return ret;
523.1048 +}
523.1049 +
523.1050 +/* Tenex mail append message from stringstruct
523.1051 + * Accepts: MAIL stream
523.1052 + *	    destination mailbox
523.1053 + *	    append callback
523.1054 + *	    data for callback
523.1055 + * Returns: T if append successful, else NIL
523.1056 + */
523.1057 +
523.1058 +long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
523.1059 +{
523.1060 +  struct stat sbuf;
523.1061 +  int fd,ld,c;
523.1062 +  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
523.1063 +  time_t tp[2];
523.1064 +  FILE *df;
523.1065 +  MESSAGECACHE elt;
523.1066 +  long f;
523.1067 +  unsigned long i,j,uf,size;
523.1068 +  STRING *message;
523.1069 +  long ret = LONGT;
523.1070 +				/* default stream to prototype */
523.1071 +  if (!stream) stream = user_flags (&tenexproto);
523.1072 +				/* make sure valid mailbox */
523.1073 +  if (!tenex_isvalid (mailbox,tmp)) switch (errno) {
523.1074 +  case ENOENT:			/* no such file? */
523.1075 +    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"mail.txt");
523.1076 +    else {
523.1077 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
523.1078 +      return NIL;
523.1079 +    }
523.1080 +				/* falls through */
523.1081 +  case 0:			/* merely empty file? */
523.1082 +    break;
523.1083 +  case EACCES:			/* file protected */
523.1084 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
523.1085 +    MM_LOG (tmp,ERROR);
523.1086 +    return NIL;
523.1087 +  case EINVAL:
523.1088 +    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
523.1089 +    MM_LOG (tmp,ERROR);
523.1090 +    return NIL;
523.1091 +  default:
523.1092 +    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
523.1093 +    MM_LOG (tmp,ERROR);
523.1094 +    return NIL;
523.1095 +  }
523.1096 +				/* get first message */
523.1097 +  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
523.1098 +
523.1099 +				/* open destination mailbox */
523.1100 +  if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
523.1101 +      !(df = fdopen (fd,"ab"))) {
523.1102 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
523.1103 +    MM_LOG (tmp,ERROR);
523.1104 +    return NIL;
523.1105 +  }
523.1106 +				/* get parse/append permission */
523.1107 +  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
523.1108 +    MM_LOG ("Unable to lock append mailbox",ERROR);
523.1109 +    close (fd);
523.1110 +    return NIL;
523.1111 +  }
523.1112 +  MM_CRITICAL (stream);		/* go critical */
523.1113 +  fstat (fd,&sbuf);		/* get current file size */
523.1114 +  errno = 0;
523.1115 +  do {				/* parse flags */ 
523.1116 +    if (!SIZE (message)) {	/* guard against zero-length */
523.1117 +      MM_LOG ("Append of zero-length message",ERROR);
523.1118 +      ret = NIL;
523.1119 +      break;
523.1120 +    }
523.1121 +    f = mail_parse_flags (stream,flags,&i);
523.1122 +				/* reverse bits (dontcha wish we had CIRC?) */
523.1123 +    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
523.1124 +    if (date) {			/* parse date if given */
523.1125 +      if (!mail_parse_date (&elt,date)) {
523.1126 +	sprintf (tmp,"Bad date in append: %.80s",date);
523.1127 +	MM_LOG (tmp,ERROR);
523.1128 +	ret = NIL;		/* mark failure */
523.1129 +	break;
523.1130 +      }
523.1131 +      mail_date (tmp,&elt);	/* write preseved date */
523.1132 +    }
523.1133 +    else internal_date (tmp);	/* get current date in IMAP format */
523.1134 +    i = GETPOS (message);	/* remember current position */
523.1135 +    for (j = SIZE (message), size = 0; j; --j)
523.1136 +      if (SNX (message) != '\015') ++size;
523.1137 +    SETPOS (message,i);		/* restore position */
523.1138 +				/* write header */
523.1139 +    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
523.1140 +      ret = NIL;
523.1141 +    else {			/* write message */
523.1142 +      while (size) if ((c = 0xff & SNX (message)) != '\015') {
523.1143 +	if (putc (c,df) != EOF) --size;
523.1144 +	else break;
523.1145 +      }
523.1146 +				/* get next message */
523.1147 +      if (size || !MM_APPEND (af) (stream,data,&flags,&date,&message))
523.1148 +	ret = NIL;
523.1149 +    }
523.1150 +  } while (ret && message);
523.1151 +				/* if error... */
523.1152 +  if (!ret || (fflush (df) == EOF)) {
523.1153 +    ftruncate (fd,sbuf.st_size);/* revert file */
523.1154 +    close (fd);			/* make sure fclose() doesn't corrupt us */
523.1155 +    if (errno) {
523.1156 +      sprintf (tmp,"Message append failed: %s",strerror (errno));
523.1157 +      MM_LOG (tmp,ERROR);
523.1158 +    }
523.1159 +    ret = NIL;
523.1160 +  }
523.1161 +  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
523.1162 +				/* else preserve \Marked status */
523.1163 +  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
523.1164 +  tp[1] = sbuf.st_mtime;	/* preserve mtime */
523.1165 +  utime (file,tp);		/* set the times */
523.1166 +  fclose (df);			/* close the file */
523.1167 +  unlockfd (ld,lock);		/* release exclusive parse/append permission */
523.1168 +  MM_NOCRITICAL (stream);	/* release critical */
523.1169 +  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
523.1170 +    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
523.1171 +	    WARN);
523.1172 +  return ret;
523.1173 +}
523.1174 +
523.1175 +/* Internal routines */
523.1176 +
523.1177 +
523.1178 +/* Tenex mail return internal message size in bytes
523.1179 + * Accepts: MAIL stream
523.1180 + *	    message #
523.1181 + * Returns: internal size of message
523.1182 + */
523.1183 +
523.1184 +unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
523.1185 +{
523.1186 +  MESSAGECACHE *elt = mail_elt (stream,m);
523.1187 +  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
523.1188 +	  LOCAL->filesize) -
523.1189 +	    (elt->private.special.offset + elt->private.special.text.size);
523.1190 +}
523.1191 +
523.1192 +
523.1193 +/* Tenex mail generate file string
523.1194 + * Accepts: temporary buffer to write into
523.1195 + *	    mailbox name string
523.1196 + * Returns: local file string or NIL if failure
523.1197 + */
523.1198 +
523.1199 +char *tenex_file (char *dst,char *name)
523.1200 +{
523.1201 +  char tmp[MAILTMPLEN];
523.1202 +  char *s = mailboxfile (dst,name);
523.1203 +				/* return our standard inbox */
523.1204 +  return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ?
523.1205 +				   "~/INBOX" : "mail.txt") : s;
523.1206 +}
523.1207 +
523.1208 +/* Tenex mail parse mailbox
523.1209 + * Accepts: MAIL stream
523.1210 + * Returns: T if parse OK
523.1211 + *	    NIL if failure, stream aborted
523.1212 + */
523.1213 +
523.1214 +long tenex_parse (MAILSTREAM *stream)
523.1215 +{
523.1216 +  struct stat sbuf;
523.1217 +  MESSAGECACHE *elt = NIL;
523.1218 +  unsigned char c,*s,*t,*x;
523.1219 +  char tmp[MAILTMPLEN];
523.1220 +  unsigned long i,j;
523.1221 +  long curpos = LOCAL->filesize;
523.1222 +  long nmsgs = stream->nmsgs;
523.1223 +  long recent = stream->recent;
523.1224 +  short added = NIL;
523.1225 +  short silent = stream->silent;
523.1226 +  fstat (LOCAL->fd,&sbuf);	/* get status */
523.1227 +  if (sbuf.st_size < curpos) {	/* sanity check */
523.1228 +    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
523.1229 +	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
523.1230 +    MM_LOG (tmp,ERROR);
523.1231 +    tenex_close (stream,NIL);
523.1232 +    return NIL;
523.1233 +  }
523.1234 +  stream->silent = T;		/* don't pass up exists events yet */
523.1235 +  while (sbuf.st_size - curpos){/* while there is stuff to parse */
523.1236 +				/* get to that position in the file */
523.1237 +    lseek (LOCAL->fd,curpos,L_SET);
523.1238 +    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
523.1239 +      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
523.1240 +	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
523.1241 +	       i ? strerror (errno) : "no data read");
523.1242 +      MM_LOG (tmp,ERROR);
523.1243 +      tenex_close (stream,NIL);
523.1244 +      return NIL;
523.1245 +    }
523.1246 +    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
523.1247 +    if (!(s = strchr (LOCAL->buf,'\012'))) {
523.1248 +      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
523.1249 +	       (unsigned long) curpos,i,(char *) LOCAL->buf);
523.1250 +      MM_LOG (tmp,ERROR);
523.1251 +      tenex_close (stream,NIL);
523.1252 +      return NIL;
523.1253 +    }
523.1254 +    *s = '\0';			/* tie off header line */
523.1255 +    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
523.1256 +    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
523.1257 +      sprintf (tmp,"Unable to parse internal header at %lu: %s",
523.1258 +	       (unsigned long) curpos,(char *) LOCAL->buf);
523.1259 +      MM_LOG (tmp,ERROR);
523.1260 +      tenex_close (stream,NIL);
523.1261 +      return NIL;
523.1262 +    }
523.1263 +    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
523.1264 +
523.1265 +    added = T;			/* note that a new message was added */
523.1266 +				/* swell the cache */
523.1267 +    mail_exists (stream,++nmsgs);
523.1268 +				/* instantiate an elt for this message */
523.1269 +    (elt = mail_elt (stream,nmsgs))->valid = T;
523.1270 +    elt->private.uid = ++stream->uid_last;
523.1271 +				/* note file offset of header */
523.1272 +    elt->private.special.offset = curpos;
523.1273 +				/* in case error */
523.1274 +    elt->private.special.text.size = 0;
523.1275 +				/* header size not known yet */
523.1276 +    elt->private.msg.header.text.size = 0;
523.1277 +    x = s;			/* parse the header components */
523.1278 +    if (mail_parse_date (elt,LOCAL->buf) &&
523.1279 +	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
523.1280 +	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
523.1281 +	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
523.1282 +	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
523.1283 +	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
523.1284 +      elt->private.special.text.size = i;
523.1285 +    else {			/* oops */
523.1286 +      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
523.1287 +	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
523.1288 +      MM_LOG (tmp,ERROR);
523.1289 +      tenex_close (stream,NIL);
523.1290 +      return NIL;
523.1291 +    }
523.1292 +				/* make sure didn't run off end of file */
523.1293 +    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
523.1294 +      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
523.1295 +	       elt->private.special.offset,(unsigned long) curpos,
523.1296 +	       (unsigned long) sbuf.st_size);
523.1297 +      MM_LOG (tmp,ERROR);
523.1298 +      tenex_close (stream,NIL);
523.1299 +      return NIL;
523.1300 +    }
523.1301 +    c = t[10];			/* remember first system flags byte */
523.1302 +    t[10] = '\0';		/* tie off flags */
523.1303 +    j = strtoul (t,NIL,8);	/* get user flags value */
523.1304 +    t[10] = c;			/* restore first system flags byte */
523.1305 +				/* set up all valid user flags (reversed!) */
523.1306 +    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
523.1307 +		  stream->user_flags[i]) elt->user_flags |= 1 << i;
523.1308 +				/* calculate system flags */
523.1309 +    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
523.1310 +    if (j & fDELETED) elt->deleted = T;
523.1311 +    if (j & fFLAGGED) elt->flagged = T;
523.1312 +    if (j & fANSWERED) elt->answered = T;
523.1313 +    if (j & fDRAFT) elt->draft = T;
523.1314 +    if (!(j & fOLD)) {		/* newly arrived message? */
523.1315 +      elt->recent = T;
523.1316 +      recent++;			/* count up a new recent message */
523.1317 +				/* mark it as old */
523.1318 +      tenex_update_status (stream,nmsgs,NIL);
523.1319 +    }
523.1320 +  }
523.1321 +  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
523.1322 +				/* update parsed file size and time */
523.1323 +  LOCAL->filesize = sbuf.st_size;
523.1324 +  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
523.1325 +  LOCAL->filetime = sbuf.st_mtime;
523.1326 +  if (added && !stream->rdonly){/* make sure atime updated */
523.1327 +    time_t tp[2];
523.1328 +    tp[0] = time (0);
523.1329 +    tp[1] = LOCAL->filetime;
523.1330 +    utime (stream->mailbox,tp);
523.1331 +  }
523.1332 +  stream->silent = silent;	/* can pass up events now */
523.1333 +  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
523.1334 +  mail_recent (stream,recent);	/* and of change in recent messages */
523.1335 +  return LONGT;			/* return the winnage */
523.1336 +}
523.1337 +
523.1338 +/* Tenex get cache element with status updating from file
523.1339 + * Accepts: MAIL stream
523.1340 + *	    message number
523.1341 + * Returns: cache element
523.1342 + */
523.1343 +
523.1344 +MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
523.1345 +{
523.1346 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
523.1347 +  struct {			/* old flags */
523.1348 +    unsigned int seen : 1;
523.1349 +    unsigned int deleted : 1;
523.1350 +    unsigned int flagged : 1;
523.1351 +    unsigned int answered : 1;
523.1352 +    unsigned int draft : 1;
523.1353 +    unsigned long user_flags;
523.1354 +  } old;
523.1355 +  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
523.1356 +  old.answered = elt->answered; old.draft = elt->draft;
523.1357 +  old.user_flags = elt->user_flags;
523.1358 +  tenex_read_flags (stream,elt);
523.1359 +  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
523.1360 +      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
523.1361 +      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
523.1362 +    MM_FLAGS (stream,msgno);	/* let top level know */
523.1363 +  return elt;
523.1364 +}
523.1365 +
523.1366 +/* Tenex read flags from file
523.1367 + * Accepts: MAIL stream
523.1368 + * Returns: cache element
523.1369 + */
523.1370 +
523.1371 +void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
523.1372 +{
523.1373 +  unsigned long i,j;
523.1374 +				/* noop if readonly and have valid flags */
523.1375 +  if (stream->rdonly && elt->valid) return;
523.1376 +				/* set the seek pointer */
523.1377 +  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
523.1378 +	 elt->private.special.text.size - 13,L_SET);
523.1379 +				/* read the new flags */
523.1380 +  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
523.1381 +    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
523.1382 +    fatal (LOCAL->buf);
523.1383 +  }
523.1384 +				/* calculate system flags */
523.1385 +  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
523.1386 +  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
523.1387 +  elt->flagged = i & fFLAGGED ? T : NIL;
523.1388 +  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
523.1389 +  LOCAL->buf[10] = '\0';	/* tie off flags */
523.1390 +  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
523.1391 +				/* set up all valid user flags (reversed!) */
523.1392 +  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
523.1393 +		stream->user_flags[i]) elt->user_flags |= 1 << i;
523.1394 +  elt->valid = T;		/* have valid flags now */
523.1395 +}
523.1396 +
523.1397 +/* Tenex update status string
523.1398 + * Accepts: MAIL stream
523.1399 + *	    message number
523.1400 + *	    flag saying whether or not to sync
523.1401 + */
523.1402 +
523.1403 +void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
523.1404 +{
523.1405 +  time_t tp[2];
523.1406 +  struct stat sbuf;
523.1407 +  MESSAGECACHE *elt = mail_elt (stream,msgno);
523.1408 +  unsigned long j,k = 0;
523.1409 +				/* readonly */
523.1410 +  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
523.1411 +  else {			/* readwrite */
523.1412 +    j = elt->user_flags;	/* get user flags */
523.1413 +				/* reverse bits (dontcha wish we had CIRC?) */
523.1414 +    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
523.1415 +				/* print new flag string */
523.1416 +    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
523.1417 +	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
523.1418 +	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
523.1419 +	      (fDRAFT * elt->draft)));
523.1420 +				/* get to that place in the file */
523.1421 +    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
523.1422 +	   elt->private.special.text.size - 13,L_SET);
523.1423 +				/* write new flags */
523.1424 +    write (LOCAL->fd,LOCAL->buf,12);
523.1425 +    if (syncflag) {		/* sync if requested */
523.1426 +      fsync (LOCAL->fd);
523.1427 +      fstat (LOCAL->fd,&sbuf);	/* get new write time */
523.1428 +      tp[1] = LOCAL->filetime = sbuf.st_mtime;
523.1429 +      tp[0] = time (0);		/* make sure read is later */
523.1430 +      utime (stream->mailbox,tp);
523.1431 +    }
523.1432 +  }
523.1433 +}
523.1434 +
523.1435 +/* Tenex locate header for a message
523.1436 + * Accepts: MAIL stream
523.1437 + *	    message number
523.1438 + *	    pointer to returned header size
523.1439 + * Returns: position of header in file
523.1440 + */
523.1441 +
523.1442 +unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
523.1443 +			    unsigned long *size)
523.1444 +{
523.1445 +  unsigned long siz;
523.1446 +  long i = 0;
523.1447 +  char c = '\0';
523.1448 +  char *s = NIL;
523.1449 +  MESSAGECACHE *elt = tenex_elt (stream,msgno);
523.1450 +  unsigned long ret = elt->private.special.offset +
523.1451 +    elt->private.special.text.size;
523.1452 +  unsigned long msiz = tenex_size (stream,msgno);
523.1453 +				/* is header size known? */
523.1454 +  if (!(*size = elt->private.msg.header.text.size)) {
523.1455 +    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
523.1456 +				/* search message for LF LF */
523.1457 +    for (siz = 0; siz < msiz; siz++) {
523.1458 +      if (--i <= 0)		/* read another buffer as necessary */
523.1459 +	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
523.1460 +				/* two newline sequence? */
523.1461 +      if ((c == '\012') && (*s == '\012')) {
523.1462 +				/* yes, note for later */
523.1463 +	elt->private.msg.header.text.size = (*size = siz + 1);
523.1464 +		
523.1465 +	return ret;		/* return to caller */
523.1466 +      }
523.1467 +      else c = *s++;		/* next character */
523.1468 +    }
523.1469 +				/* header consumes entire message */
523.1470 +    elt->private.msg.header.text.size = *size = msiz;
523.1471 +  }
523.1472 +  return ret;
523.1473 +}
   524.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   524.2 +++ b/src/osdep/unix/truncate.c	Mon Sep 14 15:17:45 2009 +0900
   524.3 @@ -0,0 +1,43 @@
   524.4 +/* ========================================================================
   524.5 + * Copyright 1988-2006 University of Washington
   524.6 + *
   524.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   524.8 + * you may not use this file except in compliance with the License.
   524.9 + * You may obtain a copy of the License at
  524.10 + *
  524.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  524.12 + *
  524.13 + * 
  524.14 + * ========================================================================
  524.15 + */
  524.16 +
  524.17 +/*
  524.18 + * Program:	Truncate a file
  524.19 + *
  524.20 + * Author:	Mark Crispin
  524.21 + *		Networks and Distributed Computing
  524.22 + *		Computing & Communications
  524.23 + *		University of Washington
  524.24 + *		Administration Building, AG-44
  524.25 + *		Seattle, WA  98195
  524.26 + *		Internet: MRC@CAC.Washington.EDU
  524.27 + *
  524.28 + * Date:	30 June 1994
  524.29 + * Last Edited:	30 August 2006
  524.30 + */
  524.31 +
  524.32 +/* Emulator for ftruncate() call
  524.33 + * Accepts: file descriptor
  524.34 + *	    length
  524.35 + * Returns: 0 if success, -1 if failure
  524.36 + */
  524.37 +
  524.38 +int ftruncate (int fd,off_t length)
  524.39 +{
  524.40 +  struct flock fb;
  524.41 +  fb.l_whence = 0;
  524.42 +  fb.l_len = 0;
  524.43 +  fb.l_start = length;
  524.44 +  fb.l_type = F_WRLCK;		/* write lock on file space */
  524.45 +  return fcntl (fd,F_FREESP,&fb);
  524.46 +}
   525.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   525.2 +++ b/src/osdep/unix/tz_bsd.c	Mon Sep 14 15:17:45 2009 +0900
   525.3 @@ -0,0 +1,38 @@
   525.4 +/* ========================================================================
   525.5 + * Copyright 1988-2006 University of Washington
   525.6 + *
   525.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   525.8 + * you may not use this file except in compliance with the License.
   525.9 + * You may obtain a copy of the License at
  525.10 + *
  525.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  525.12 + *
  525.13 + * 
  525.14 + * ========================================================================
  525.15 + */
  525.16 +
  525.17 +/*
  525.18 + * Program:	BSD-style Time Zone String
  525.19 + *
  525.20 + * Author:	Mark Crispin
  525.21 + *		Networks and Distributed Computing
  525.22 + *		Computing & Communications
  525.23 + *		University of Washington
  525.24 + *		Administration Building, AG-44
  525.25 + *		Seattle, WA  98195
  525.26 + *		Internet: MRC@CAC.Washington.EDU
  525.27 + *
  525.28 + * Date:	30 August 1994
  525.29 + * Last Edited:	30 August 2006
  525.30 + */
  525.31 +
  525.32 +
  525.33 +/* Append local timezone name
  525.34 + * Accepts: destination string
  525.35 + */
  525.36 +
  525.37 +void rfc822_timezone (char *s,void *t)
  525.38 +{
  525.39 +				/* append timezone from tm struct */
  525.40 +  sprintf (s + strlen (s)," (%.50s)",((struct tm *) t)->tm_zone);
  525.41 +}
   526.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   526.2 +++ b/src/osdep/unix/tz_nul.c	Mon Sep 14 15:17:45 2009 +0900
   526.3 @@ -0,0 +1,36 @@
   526.4 +/* ========================================================================
   526.5 + * Copyright 1988-2006 University of Washington
   526.6 + *
   526.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   526.8 + * you may not use this file except in compliance with the License.
   526.9 + * You may obtain a copy of the License at
  526.10 + *
  526.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  526.12 + *
  526.13 + * 
  526.14 + * ========================================================================
  526.15 + */
  526.16 +
  526.17 +/*
  526.18 + * Program:	Null Time Zone String (unknown)
  526.19 + *
  526.20 + * Author:	Mark Crispin
  526.21 + *		Networks and Distributed Computing
  526.22 + *		Computing & Communications
  526.23 + *		University of Washington
  526.24 + *		Administration Building, AG-44
  526.25 + *		Seattle, WA  98195
  526.26 + *		Internet: MRC@CAC.Washington.EDU
  526.27 + *
  526.28 + * Date:	30 August 1994
  526.29 + * Last Edited:	30 August 2006
  526.30 + */
  526.31 +
  526.32 +
  526.33 +/* Append local timezone name
  526.34 + * Accepts: destination string
  526.35 + */
  526.36 +
  526.37 +void rfc822_timezone (char *s,void *t)
  526.38 +{
  526.39 +}
   527.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   527.2 +++ b/src/osdep/unix/tz_sv4.c	Mon Sep 14 15:17:45 2009 +0900
   527.3 @@ -0,0 +1,39 @@
   527.4 +/* ========================================================================
   527.5 + * Copyright 1988-2006 University of Washington
   527.6 + *
   527.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   527.8 + * you may not use this file except in compliance with the License.
   527.9 + * You may obtain a copy of the License at
  527.10 + *
  527.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  527.12 + *
  527.13 + * 
  527.14 + * ========================================================================
  527.15 + */
  527.16 +
  527.17 +/*
  527.18 + * Program:	SVR4-style Time Zone String
  527.19 + *
  527.20 + * Author:	Mark Crispin
  527.21 + *		Networks and Distributed Computing
  527.22 + *		Computing & Communications
  527.23 + *		University of Washington
  527.24 + *		Administration Building, AG-44
  527.25 + *		Seattle, WA  98195
  527.26 + *		Internet: MRC@CAC.Washington.EDU
  527.27 + *
  527.28 + * Date:	30 August 1994
  527.29 + * Last Edited:	30 August 2006
  527.30 + */
  527.31 +
  527.32 +
  527.33 +/* Append local timezone name
  527.34 + * Accepts: destination string
  527.35 + */
  527.36 +
  527.37 +void rfc822_timezone (char *s,void *t)
  527.38 +{
  527.39 +  tzset ();			/* get timezone from TZ environment stuff */
  527.40 +  sprintf (s + strlen (s)," (%.50s)",
  527.41 +	   tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]);
  527.42 +}
   528.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   528.2 +++ b/src/osdep/unix/unix.c	Mon Sep 14 15:17:45 2009 +0900
   528.3 @@ -0,0 +1,2708 @@
   528.4 +/* ========================================================================
   528.5 + * Copyright 1988-2008 University of Washington
   528.6 + *
   528.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   528.8 + * you may not use this file except in compliance with the License.
   528.9 + * You may obtain a copy of the License at
  528.10 + *
  528.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  528.12 + *
  528.13 + * 
  528.14 + * ========================================================================
  528.15 + */
  528.16 +
  528.17 +/*
  528.18 + * Program:	UNIX mail routines
  528.19 + *
  528.20 + * Author:	Mark Crispin
  528.21 + *		UW Technology
  528.22 + *		University of Washington
  528.23 + *		Seattle, WA  98195
  528.24 + *		Internet: MRC@Washington.EDU
  528.25 + *
  528.26 + * Date:	20 December 1989
  528.27 + * Last Edited:	27 March 2008
  528.28 + */
  528.29 +
  528.30 +
  528.31 +/*				DEDICATION
  528.32 + *
  528.33 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  528.34 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  528.35 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  528.36 + * a two-month bout with cirrhosis of the liver.
  528.37 + *
  528.38 + *  He was a dear friend, and I miss him terribly.
  528.39 + *
  528.40 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  528.41 + */
  528.42 +
  528.43 +#include <stdio.h>
  528.44 +#include <ctype.h>
  528.45 +#include <errno.h>
  528.46 +extern int errno;		/* just in case */
  528.47 +#include <signal.h>
  528.48 +#include "mail.h"
  528.49 +#include "osdep.h"
  528.50 +#include <time.h>
  528.51 +#include <sys/stat.h>
  528.52 +#include "unix.h"
  528.53 +#include "pseudo.h"
  528.54 +#include "fdstring.h"
  528.55 +#include "misc.h"
  528.56 +#include "dummy.h"
  528.57 +
  528.58 +/* UNIX I/O stream local data */
  528.59 +
  528.60 +typedef struct unix_local {
  528.61 +  unsigned int dirty : 1;	/* disk copy needs updating */
  528.62 +  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
  528.63 +  unsigned int pseudo : 1;	/* uses a pseudo message */
  528.64 +  unsigned int appending : 1;	/* don't mark new messages as old */
  528.65 +  int fd;			/* mailbox file descriptor */
  528.66 +  int ld;			/* lock file descriptor */
  528.67 +  char *lname;			/* lock file name */
  528.68 +  off_t filesize;		/* file size parsed */
  528.69 +  time_t filetime;		/* last file time */
  528.70 +  time_t lastsnarf;		/* last snarf time (for mbox driver) */
  528.71 +  unsigned char *buf;		/* temporary buffer */
  528.72 +  unsigned long buflen;		/* current size of temporary buffer */
  528.73 +  unsigned long uid;		/* current text uid */
  528.74 +  SIZEDTEXT text;		/* current text */
  528.75 +  unsigned long textlen;	/* current text length */
  528.76 +  char *line;			/* returned line */
  528.77 +  char *linebuf;		/* line readin buffer */
  528.78 +  unsigned long linebuflen;	/* current line readin buffer length */
  528.79 +} UNIXLOCAL;
  528.80 +
  528.81 +
  528.82 +/* Convenient access to local data */
  528.83 +
  528.84 +#define LOCAL ((UNIXLOCAL *) stream->local)
  528.85 +
  528.86 +
  528.87 +/* UNIX protected file structure */
  528.88 +
  528.89 +typedef struct unix_file {
  528.90 +  MAILSTREAM *stream;		/* current stream */
  528.91 +  off_t curpos;			/* current file position */
  528.92 +  off_t protect;		/* protected position */
  528.93 +  off_t filepos;		/* current last written file position */
  528.94 +  char *buf;			/* overflow buffer */
  528.95 +  size_t buflen;		/* current overflow buffer length */
  528.96 +  char *bufpos;			/* current buffer position */
  528.97 +} UNIXFILE;
  528.98 +
  528.99 +/* Function prototypes */
 528.100 +
 528.101 +DRIVER *unix_valid (char *name);
 528.102 +long unix_isvalid_fd (int fd);
 528.103 +void *unix_parameters (long function,void *value);
 528.104 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
 528.105 +void unix_list (MAILSTREAM *stream,char *ref,char *pat);
 528.106 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
 528.107 +long unix_create (MAILSTREAM *stream,char *mailbox);
 528.108 +long unix_delete (MAILSTREAM *stream,char *mailbox);
 528.109 +long unix_rename (MAILSTREAM *stream,char *old,char *newname);
 528.110 +MAILSTREAM *unix_open (MAILSTREAM *stream);
 528.111 +void unix_close (MAILSTREAM *stream,long options);
 528.112 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 528.113 +		   unsigned long *length,long flags);
 528.114 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
 528.115 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 528.116 +		      unsigned long *length,long flags);
 528.117 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
 528.118 +long unix_ping (MAILSTREAM *stream);
 528.119 +void unix_check (MAILSTREAM *stream);
 528.120 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
 528.121 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
 528.122 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 528.123 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
 528.124 +		     STRING *msg);
 528.125 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
 528.126 +
 528.127 +void unix_abort (MAILSTREAM *stream);
 528.128 +char *unix_file (char *dst,char *name);
 528.129 +int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
 528.130 +void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
 528.131 +int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
 528.132 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
 528.133 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
 528.134 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
 528.135 +			    unsigned long uid,long flag);
 528.136 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
 528.137 +		   long flags);
 528.138 +long unix_extend (MAILSTREAM *stream,unsigned long size);
 528.139 +void unix_write (UNIXFILE *f,char *s,unsigned long i);
 528.140 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
 528.141 +
 528.142 +/* mbox mail routines */
 528.143 +
 528.144 +/* Function prototypes */
 528.145 +
 528.146 +DRIVER *mbox_valid (char *name);
 528.147 +long mbox_create (MAILSTREAM *stream,char *mailbox);
 528.148 +long mbox_delete (MAILSTREAM *stream,char *mailbox);
 528.149 +long mbox_rename (MAILSTREAM *stream,char *old,char *newname);
 528.150 +long mbox_status (MAILSTREAM *stream,char *mbx,long flags);
 528.151 +MAILSTREAM *mbox_open (MAILSTREAM *stream);
 528.152 +long mbox_ping (MAILSTREAM *stream);
 528.153 +void mbox_check (MAILSTREAM *stream);
 528.154 +long mbox_expunge (MAILSTREAM *stream,char *sequence,long options);
 528.155 +long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
 528.156 +
 528.157 +
 528.158 +/* UNIX mail routines */
 528.159 +
 528.160 +
 528.161 +/* Driver dispatch used by MAIL */
 528.162 +
 528.163 +DRIVER unixdriver = {
 528.164 +  "unix",			/* driver name */
 528.165 +				/* driver flags */
 528.166 +  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
 528.167 +  (DRIVER *) NIL,		/* next driver */
 528.168 +  unix_valid,			/* mailbox is valid for us */
 528.169 +  unix_parameters,		/* manipulate parameters */
 528.170 +  unix_scan,			/* scan mailboxes */
 528.171 +  unix_list,			/* list mailboxes */
 528.172 +  unix_lsub,			/* list subscribed mailboxes */
 528.173 +  NIL,				/* subscribe to mailbox */
 528.174 +  NIL,				/* unsubscribe from mailbox */
 528.175 +  unix_create,			/* create mailbox */
 528.176 +  unix_delete,			/* delete mailbox */
 528.177 +  unix_rename,			/* rename mailbox */
 528.178 +  mail_status_default,		/* status of mailbox */
 528.179 +  unix_open,			/* open mailbox */
 528.180 +  unix_close,			/* close mailbox */
 528.181 +  NIL,				/* fetch message "fast" attributes */
 528.182 +  NIL,				/* fetch message flags */
 528.183 +  NIL,				/* fetch overview */
 528.184 +  NIL,				/* fetch message envelopes */
 528.185 +  unix_header,			/* fetch message header */
 528.186 +  unix_text,			/* fetch message text */
 528.187 +  NIL,				/* fetch partial message text */
 528.188 +  NIL,				/* unique identifier */
 528.189 +  NIL,				/* message number */
 528.190 +  NIL,				/* modify flags */
 528.191 +  unix_flagmsg,			/* per-message modify flags */
 528.192 +  NIL,				/* search for message based on criteria */
 528.193 +  NIL,				/* sort messages */
 528.194 +  NIL,				/* thread messages */
 528.195 +  unix_ping,			/* ping mailbox to see if still alive */
 528.196 +  unix_check,			/* check for new messages */
 528.197 +  unix_expunge,			/* expunge deleted messages */
 528.198 +  unix_copy,			/* copy messages to another mailbox */
 528.199 +  unix_append,			/* append string message to mailbox */
 528.200 +  NIL				/* garbage collect stream */
 528.201 +};
 528.202 +
 528.203 +				/* prototype stream */
 528.204 +MAILSTREAM unixproto = {&unixdriver};
 528.205 +
 528.206 +				/* driver parameters */
 528.207 +static long unix_fromwidget = T;
 528.208 +
 528.209 +/* UNIX mail validate mailbox
 528.210 + * Accepts: mailbox name
 528.211 + * Returns: our driver if name is valid, NIL otherwise
 528.212 + */
 528.213 +
 528.214 +DRIVER *unix_valid (char *name)
 528.215 +{
 528.216 +  int fd;
 528.217 +  DRIVER *ret = NIL;
 528.218 +  char *t,file[MAILTMPLEN];
 528.219 +  struct stat sbuf;
 528.220 +  time_t tp[2];
 528.221 +  errno = EINVAL;		/* assume invalid argument */
 528.222 +				/* must be non-empty file */
 528.223 +  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
 528.224 +    if (!sbuf.st_size)errno = 0;/* empty file */
 528.225 +    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
 528.226 +				/* OK if mailbox format good */
 528.227 +      if (unix_isvalid_fd (fd)) ret = &unixdriver;
 528.228 +      else errno = -1;		/* invalid format */
 528.229 +      close (fd);		/* close the file */
 528.230 +				/* \Marked status? */
 528.231 +      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
 528.232 +	tp[0] = sbuf.st_atime;	/* yes, preserve atime and mtime */
 528.233 +	tp[1] = sbuf.st_mtime;
 528.234 +	utime (file,tp);	/* set the times */
 528.235 +      }
 528.236 +    }
 528.237 +  }
 528.238 +  return ret;			/* return what we should */
 528.239 +}
 528.240 +
 528.241 +/* UNIX mail test for valid mailbox
 528.242 + * Accepts: file descriptor
 528.243 + *	    scratch buffer
 528.244 + * Returns: T if valid, NIL otherwise
 528.245 + */
 528.246 +
 528.247 +long unix_isvalid_fd (int fd)
 528.248 +{
 528.249 +  int zn;
 528.250 +  int ret = NIL;
 528.251 +  char tmp[MAILTMPLEN],*s,*t,c = '\n';
 528.252 +  memset (tmp,'\0',MAILTMPLEN);
 528.253 +  if (read (fd,tmp,MAILTMPLEN-1) >= 0) {
 528.254 +    for (s = tmp; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');)
 528.255 +      c = *s++;
 528.256 +    if (c == '\n') VALID (s,t,ret,zn);
 528.257 +  }
 528.258 +  return ret;			/* return what we should */
 528.259 +}
 528.260 +
 528.261 +
 528.262 +/* UNIX manipulate driver parameters
 528.263 + * Accepts: function code
 528.264 + *	    function-dependent value
 528.265 + * Returns: function-dependent return value
 528.266 + */
 528.267 +
 528.268 +void *unix_parameters (long function,void *value)
 528.269 +{
 528.270 +  void *ret = NIL;
 528.271 +  switch ((int) function) {
 528.272 +  case GET_INBOXPATH:
 528.273 +    if (value) ret = dummy_file ((char *) value,"INBOX");
 528.274 +    break;
 528.275 +  case SET_FROMWIDGET:
 528.276 +    unix_fromwidget = (long) value;
 528.277 +  case GET_FROMWIDGET:
 528.278 +    ret = (void *) unix_fromwidget;
 528.279 +    break;
 528.280 +  }
 528.281 +  return ret;
 528.282 +}
 528.283 +
 528.284 +/* UNIX mail scan mailboxes
 528.285 + * Accepts: mail stream
 528.286 + *	    reference
 528.287 + *	    pattern to search
 528.288 + *	    string to scan
 528.289 + */
 528.290 +
 528.291 +void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 528.292 +{
 528.293 +  if (stream) dummy_scan (NIL,ref,pat,contents);
 528.294 +}
 528.295 +
 528.296 +
 528.297 +/* UNIX mail list mailboxes
 528.298 + * Accepts: mail stream
 528.299 + *	    reference
 528.300 + *	    pattern to search
 528.301 + */
 528.302 +
 528.303 +void unix_list (MAILSTREAM *stream,char *ref,char *pat)
 528.304 +{
 528.305 +  if (stream) dummy_list (NIL,ref,pat);
 528.306 +}
 528.307 +
 528.308 +
 528.309 +/* UNIX mail list subscribed mailboxes
 528.310 + * Accepts: mail stream
 528.311 + *	    reference
 528.312 + *	    pattern to search
 528.313 + */
 528.314 +
 528.315 +void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
 528.316 +{
 528.317 +  if (stream) dummy_lsub (NIL,ref,pat);
 528.318 +}
 528.319 +
 528.320 +/* UNIX mail create mailbox
 528.321 + * Accepts: MAIL stream
 528.322 + *	    mailbox name to create
 528.323 + * Returns: T on success, NIL on failure
 528.324 + */
 528.325 +
 528.326 +long unix_create (MAILSTREAM *stream,char *mailbox)
 528.327 +{
 528.328 +  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
 528.329 +  long ret = NIL;
 528.330 +  int i,fd;
 528.331 +  time_t ti = time (0);
 528.332 +  if (!(s = dummy_file (mbx,mailbox))) {
 528.333 +    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
 528.334 +    MM_LOG (tmp,ERROR);
 528.335 +  }
 528.336 +				/* create underlying file */
 528.337 +  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
 528.338 +				/* done if dir-only or whiner */
 528.339 +    if (((s = strrchr (s,'/')) && !s[1]) ||
 528.340 +	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
 528.341 +    else if ((fd = open (mbx,O_WRONLY,
 528.342 +		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
 528.343 +      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
 528.344 +      MM_LOG (tmp,ERROR);
 528.345 +      unlink (mbx);		/* delete the file */
 528.346 +    }
 528.347 +    else {			/* initialize header */
 528.348 +      memset (tmp,'\0',MAILTMPLEN);
 528.349 +      sprintf (tmp,"From %s %sDate: ",pseudo_from,ctime (&ti));
 528.350 +      rfc822_fixed_date (s = tmp + strlen (tmp));
 528.351 +				/* write the pseudo-header */
 528.352 +      sprintf (s += strlen (s),
 528.353 +	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
 528.354 +	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
 528.355 +	       (unsigned long) ti);
 528.356 +      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
 528.357 +	sprintf (s += strlen (s)," %s",default_user_flag (i));
 528.358 +      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
 528.359 +      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
 528.360 +      else {
 528.361 +	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
 528.362 +		 strerror (errno));
 528.363 +	MM_LOG (tmp,ERROR);
 528.364 +	unlink (mbx);		/* delete the file */
 528.365 +      }
 528.366 +      close (fd);		/* close file */
 528.367 +    }
 528.368 +  }
 528.369 +				/* set proper protections */
 528.370 +  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
 528.371 +}
 528.372 +
 528.373 +/* UNIX mail delete mailbox
 528.374 + * Accepts: MAIL stream
 528.375 + *	    mailbox name to delete
 528.376 + * Returns: T on success, NIL on failure
 528.377 + */
 528.378 +
 528.379 +long unix_delete (MAILSTREAM *stream,char *mailbox)
 528.380 +{
 528.381 +  return unix_rename (stream,mailbox,NIL);
 528.382 +}
 528.383 +
 528.384 +
 528.385 +/* UNIX mail rename mailbox
 528.386 + * Accepts: MAIL stream
 528.387 + *	    old mailbox name
 528.388 + *	    new mailbox name (or NIL for delete)
 528.389 + * Returns: T on success, NIL on failure
 528.390 + */
 528.391 +
 528.392 +long unix_rename (MAILSTREAM *stream,char *old,char *newname)
 528.393 +{
 528.394 +  long ret = NIL;
 528.395 +  char c,*s = NIL;
 528.396 +  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
 528.397 +  DOTLOCK lockx;
 528.398 +  int fd,ld;
 528.399 +  long i;
 528.400 +  struct stat sbuf;
 528.401 +  MM_CRITICAL (stream);		/* get the c-client lock */
 528.402 +  if (!dummy_file (file,old) ||
 528.403 +      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
 528.404 +		   ((s = strrchr (tmp,'/')) && !s[1]))))
 528.405 +    sprintf (tmp,newname ?
 528.406 +	     "Can't rename mailbox %.80s to %.80s: invalid name" :
 528.407 +	     "Can't delete mailbox %.80s: invalid name",
 528.408 +	     old,newname);
 528.409 +				/* lock out other c-clients */
 528.410 +  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
 528.411 +    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
 528.412 +
 528.413 +  else {
 528.414 +    if ((fd = unix_lock (file,O_RDWR,
 528.415 +			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
 528.416 +			 &lockx,LOCK_EX)) < 0)
 528.417 +      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
 528.418 +    else {
 528.419 +      if (newname) {		/* want rename? */
 528.420 +				/* found superior to destination name? */
 528.421 +	if (s = strrchr (s,'/')) {
 528.422 +	  c = *++s;		/* remember first character of inferior */
 528.423 +	  *s = '\0';		/* tie off to get just superior */
 528.424 +				/* name doesn't exist, create it */
 528.425 +	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
 528.426 +	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
 528.427 +	    unix_unlock (fd,NIL,&lockx);
 528.428 +	    unix_unlock (ld,NIL,NIL);
 528.429 +	    unlink (lock);
 528.430 +	    MM_NOCRITICAL (stream);
 528.431 +	    return ret;		/* return success or failure */
 528.432 +	  }
 528.433 +	  *s = c;		/* restore full name */
 528.434 +	}
 528.435 +	if (rename (file,tmp))
 528.436 +	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
 528.437 +		   strerror (errno));
 528.438 +	else ret = T;		/* set success */
 528.439 +      }
 528.440 +      else if (unlink (file))
 528.441 +	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
 528.442 +      else ret = T;		/* set success */
 528.443 +      unix_unlock (fd,NIL,&lockx);
 528.444 +    }
 528.445 +    unix_unlock (ld,NIL,NIL);	/* flush the lock */
 528.446 +    unlink (lock);
 528.447 +  }
 528.448 +  MM_NOCRITICAL (stream);	/* no longer critical */
 528.449 +  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
 528.450 +  return ret;			/* return success or failure */
 528.451 +}
 528.452 +
 528.453 +/* UNIX mail open
 528.454 + * Accepts: Stream to open
 528.455 + * Returns: Stream on success, NIL on failure
 528.456 + */
 528.457 +
 528.458 +MAILSTREAM *unix_open (MAILSTREAM *stream)
 528.459 +{
 528.460 +  long i;
 528.461 +  int fd;
 528.462 +  char tmp[MAILTMPLEN];
 528.463 +  DOTLOCK lock;
 528.464 +  long retry;
 528.465 +				/* return prototype for OP_PROTOTYPE call */
 528.466 +  if (!stream) return user_flags (&unixproto);
 528.467 +  retry = stream->silent ? 1 : KODRETRY;
 528.468 +  if (stream->local) fatal ("unix recycle stream");
 528.469 +  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
 528.470 +				/* note if an INBOX or not */
 528.471 +  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
 528.472 +				/* canonicalize the stream mailbox name */
 528.473 +  if (!dummy_file (tmp,stream->mailbox)) {
 528.474 +    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
 528.475 +    MM_LOG (tmp,ERROR);
 528.476 +    return NIL;
 528.477 +  }
 528.478 +				/* flush old name */
 528.479 +  fs_give ((void **) &stream->mailbox);
 528.480 +				/* save canonical name */
 528.481 +  stream->mailbox = cpystr (tmp);
 528.482 +  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
 528.483 +  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
 528.484 +  LOCAL->buflen = CHUNKSIZE - 1;
 528.485 +  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
 528.486 +  LOCAL->text.size = CHUNKSIZE - 1;
 528.487 +  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
 528.488 +  LOCAL->linebuflen = CHUNKSIZE - 1;
 528.489 +  stream->sequence++;		/* bump sequence number */
 528.490 +
 528.491 +				/* make lock for read/write access */
 528.492 +  if (!stream->rdonly) while (retry) {
 528.493 +				/* try to lock file */
 528.494 +    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
 528.495 +				/* suppressing kiss-of-death? */
 528.496 +      if (stream->nokod) retry = 0;
 528.497 +				/* no, first time through? */
 528.498 +      else if (retry-- == KODRETRY) {
 528.499 +				/* learned other guy's PID and can signal? */
 528.500 +	if (i && !kill ((int) i,SIGUSR2)) {
 528.501 +	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
 528.502 +	  MM_LOG (tmp,WARN);
 528.503 +	}
 528.504 +	else retry = 0;		/* give up */
 528.505 +      }
 528.506 +      if (!stream->silent) {	/* nothing if silent stream */
 528.507 +	if (retry) sleep (1);	/* wait a second before trying again */
 528.508 +	else MM_LOG ("Mailbox is open by another process, access is readonly",
 528.509 +		     WARN);
 528.510 +      }
 528.511 +    }
 528.512 +    else {			/* got the lock, nobody else can alter state */
 528.513 +      LOCAL->ld = fd;		/* note lock's fd and name */
 528.514 +      LOCAL->lname = cpystr (tmp);
 528.515 +				/* make sure mode OK (don't use fchmod()) */
 528.516 +      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
 528.517 +      if (stream->silent) i = 0;/* silent streams won't accept KOD */
 528.518 +      else {			/* note our PID in the lock */
 528.519 +	sprintf (tmp,"%d",getpid ());
 528.520 +	write (fd,tmp,(i = strlen (tmp))+1);
 528.521 +      }
 528.522 +      ftruncate (fd,i);		/* make sure tied off */
 528.523 +      fsync (fd);		/* make sure it's available */
 528.524 +      retry = 0;		/* no more need to try */
 528.525 +    }
 528.526 +  }
 528.527 +
 528.528 +				/* parse mailbox */
 528.529 +  stream->nmsgs = stream->recent = 0;
 528.530 +				/* will we be able to get write access? */
 528.531 +  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
 528.532 +    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
 528.533 +    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
 528.534 +    close (LOCAL->ld);		/* close the lock file */
 528.535 +    LOCAL->ld = -1;		/* no more lock fd */
 528.536 +    unlink (LOCAL->lname);	/* delete it */
 528.537 +  }
 528.538 +				/* reset UID validity */
 528.539 +  stream->uid_validity = stream->uid_last = 0;
 528.540 +  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
 528.541 +    unix_abort (stream);	/* abort if can't get RW silent stream */
 528.542 +				/* parse mailbox */
 528.543 +  else if (unix_parse (stream,&lock,LOCK_SH)) {
 528.544 +    unix_unlock (LOCAL->fd,stream,&lock);
 528.545 +    mail_unlock (stream);
 528.546 +    MM_NOCRITICAL (stream);	/* done with critical */
 528.547 +  }
 528.548 +  if (!LOCAL) return NIL;	/* failure if stream died */
 528.549 +				/* make sure upper level knows readonly */
 528.550 +  stream->rdonly = (LOCAL->ld < 0);
 528.551 +				/* notify about empty mailbox */
 528.552 +  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
 528.553 +  if (!stream->rdonly) {	/* flags stick if readwrite */
 528.554 +    stream->perm_seen = stream->perm_deleted =
 528.555 +      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
 528.556 +    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
 528.557 +      stream->perm_user_flags = 0xffffffff;
 528.558 +				/* and maybe can create them too! */
 528.559 +      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
 528.560 +    }
 528.561 +  }
 528.562 +  return stream;		/* return stream alive to caller */
 528.563 +}
 528.564 +
 528.565 +
 528.566 +/* UNIX mail close
 528.567 + * Accepts: MAIL stream
 528.568 + *	    close options
 528.569 + */
 528.570 +
 528.571 +void unix_close (MAILSTREAM *stream,long options)
 528.572 +{
 528.573 +  int silent = stream->silent;
 528.574 +  stream->silent = T;		/* go silent */
 528.575 +				/* expunge if requested */
 528.576 +  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
 528.577 +				/* else dump final checkpoint */
 528.578 +  else if (LOCAL->dirty) unix_check (stream);
 528.579 +  stream->silent = silent;	/* restore old silence state */
 528.580 +  unix_abort (stream);		/* now punt the file and local data */
 528.581 +}
 528.582 +
 528.583 +/* UNIX mail fetch message header
 528.584 + * Accepts: MAIL stream
 528.585 + *	    message # to fetch
 528.586 + *	    pointer to returned header text length
 528.587 + *	    option flags
 528.588 + * Returns: message header in RFC822 format
 528.589 + */
 528.590 +
 528.591 +				/* lines to filter from header */
 528.592 +static STRINGLIST *unix_hlines = NIL;
 528.593 +
 528.594 +char *unix_header (MAILSTREAM *stream,unsigned long msgno,
 528.595 +		   unsigned long *length,long flags)
 528.596 +{
 528.597 +  MESSAGECACHE *elt;
 528.598 +  unsigned char *s,*t,*tl;
 528.599 +  *length = 0;			/* default to empty */
 528.600 +  if (flags & FT_UID) return "";/* UID call "impossible" */
 528.601 +  elt = mail_elt (stream,msgno);/* get cache */
 528.602 +  if (!unix_hlines) {		/* once only code */
 528.603 +    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
 528.604 +    lines->text.size = strlen ((char *) (lines->text.data =
 528.605 +					 (unsigned char *) "Status"));
 528.606 +    lines = lines->next = mail_newstringlist ();
 528.607 +    lines->text.size = strlen ((char *) (lines->text.data =
 528.608 +					 (unsigned char *) "X-Status"));
 528.609 +    lines = lines->next = mail_newstringlist ();
 528.610 +    lines->text.size = strlen ((char *) (lines->text.data =
 528.611 +					 (unsigned char *) "X-Keywords"));
 528.612 +    lines = lines->next = mail_newstringlist ();
 528.613 +    lines->text.size = strlen ((char *) (lines->text.data =
 528.614 +					 (unsigned char *) "X-UID"));
 528.615 +    lines = lines->next = mail_newstringlist ();
 528.616 +    lines->text.size = strlen ((char *) (lines->text.data =
 528.617 +					 (unsigned char *) "X-IMAP"));
 528.618 +    lines = lines->next = mail_newstringlist ();
 528.619 +    lines->text.size = strlen ((char *) (lines->text.data =
 528.620 +					 (unsigned char *) "X-IMAPbase"));
 528.621 +  }
 528.622 +				/* go to header position */
 528.623 +  lseek (LOCAL->fd,elt->private.special.offset +
 528.624 +	 elt->private.msg.header.offset,L_SET);
 528.625 +
 528.626 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 528.627 +    if (elt->private.msg.header.text.size > LOCAL->buflen) {
 528.628 +      fs_give ((void **) &LOCAL->buf);
 528.629 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 528.630 +				     elt->private.msg.header.text.size) + 1);
 528.631 +    }
 528.632 +				/* read message */
 528.633 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
 528.634 +				/* got text, tie off string */
 528.635 +    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
 528.636 +				/* squeeze out CRs (in case from PC) */
 528.637 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 528.638 +      if (*t != '\r') *s++ = *t;
 528.639 +    *s = '\0';
 528.640 +    *length = s - LOCAL->buf;	/* adjust length */
 528.641 +  }
 528.642 +  else {			/* need to make a CRLF version */
 528.643 +    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
 528.644 +	  elt->private.msg.header.text.size);
 528.645 +				/* tie off string, and convert to CRLF */
 528.646 +    s[elt->private.msg.header.text.size] = '\0';
 528.647 +    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
 528.648 +			  elt->private.msg.header.text.size);
 528.649 +    fs_give ((void **) &s);	/* free readin buffer */
 528.650 +				/* squeeze out spurious CRs */
 528.651 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 528.652 +      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
 528.653 +    *s = '\0';
 528.654 +    *length = s - LOCAL->buf;	/* adjust length */
 528.655 +  }
 528.656 +  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
 528.657 +  return (char *) LOCAL->buf;	/* return processed copy */
 528.658 +}
 528.659 +
 528.660 +/* UNIX mail fetch message text
 528.661 + * Accepts: MAIL stream
 528.662 + *	    message # to fetch
 528.663 + *	    pointer to returned stringstruct
 528.664 + *	    option flags
 528.665 + * Returns: T on success, NIL if failure
 528.666 + */
 528.667 +
 528.668 +long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
 528.669 +{
 528.670 +  char *s;
 528.671 +  unsigned long i;
 528.672 +  MESSAGECACHE *elt;
 528.673 +				/* UID call "impossible" */
 528.674 +  if (flags & FT_UID) return NIL;
 528.675 +  elt = mail_elt (stream,msgno);/* get cache element */
 528.676 +				/* if message not seen */
 528.677 +  if (!(flags & FT_PEEK) && !elt->seen) {
 528.678 +				/* mark message seen and dirty */
 528.679 +    elt->seen = elt->private.dirty = LOCAL->dirty = T;
 528.680 +    MM_FLAGS (stream,msgno);
 528.681 +  }
 528.682 +  s = unix_text_work (stream,elt,&i,flags);
 528.683 +  INIT (bs,mail_string,s,i);	/* set up stringstruct */
 528.684 +  return T;			/* success */
 528.685 +}
 528.686 +
 528.687 +/* UNIX mail fetch message text worker routine
 528.688 + * Accepts: MAIL stream
 528.689 + *	    message cache element
 528.690 + *	    pointer to returned header text length
 528.691 + *	    option flags
 528.692 + */
 528.693 +
 528.694 +char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
 528.695 +		      unsigned long *length,long flags)
 528.696 +{
 528.697 +  FDDATA d;
 528.698 +  STRING bs;
 528.699 +  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
 528.700 +				/* go to text position */
 528.701 +  lseek (LOCAL->fd,elt->private.special.offset +
 528.702 +	 elt->private.msg.text.offset,L_SET);
 528.703 +  if (flags & FT_INTERNAL) {	/* initial data OK? */
 528.704 +    if (elt->private.msg.text.text.size > LOCAL->buflen) {
 528.705 +      fs_give ((void **) &LOCAL->buf);
 528.706 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
 528.707 +				     elt->private.msg.text.text.size) + 1);
 528.708 +    }
 528.709 +				/* read message */
 528.710 +    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
 528.711 +				/* got text, tie off string */
 528.712 +    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
 528.713 +				/* squeeze out CRs (in case from PC) */
 528.714 +    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
 528.715 +      if (*t != '\r') *s++ = *t;
 528.716 +    *s = '\0';
 528.717 +    *length = s - LOCAL->buf;	/* adjust length */
 528.718 +    return (char *) LOCAL->buf;
 528.719 +  }
 528.720 +
 528.721 +				/* have it cached already? */
 528.722 +  if (elt->private.uid != LOCAL->uid) {
 528.723 +				/* not cached, cache it now */
 528.724 +    LOCAL->uid = elt->private.uid;
 528.725 +				/* is buffer big enough? */
 528.726 +    if (elt->rfc822_size > LOCAL->text.size) {
 528.727 +      /* excessively conservative, but the right thing is too hard to do */
 528.728 +      fs_give ((void **) &LOCAL->text.data);
 528.729 +      LOCAL->text.data = (unsigned char *)
 528.730 +	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
 528.731 +    }
 528.732 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
 528.733 +    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
 528.734 +    d.chunk = tmp;		/* initial buffer chunk */
 528.735 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
 528.736 +    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
 528.737 +    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
 528.738 +    case '\r':			/* carriage return seen */
 528.739 +      break;
 528.740 +    case '\n':
 528.741 +      *s++ = '\r';		/* insert a CR */
 528.742 +    default:
 528.743 +      *s++ = c;			/* copy characters */
 528.744 +    }
 528.745 +    *s = '\0';			/* tie off buffer */
 528.746 +				/* calculate length of cached data */
 528.747 +    LOCAL->textlen = s - LOCAL->text.data;
 528.748 +  }
 528.749 +  *length = LOCAL->textlen;	/* return from cache */
 528.750 +  return (char *) LOCAL->text.data;
 528.751 +}
 528.752 +
 528.753 +/* UNIX per-message modify flag
 528.754 + * Accepts: MAIL stream
 528.755 + *	    message cache element
 528.756 + */
 528.757 +
 528.758 +void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
 528.759 +{
 528.760 +				/* only after finishing */
 528.761 +  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
 528.762 +}
 528.763 +
 528.764 +
 528.765 +/* UNIX mail ping mailbox
 528.766 + * Accepts: MAIL stream
 528.767 + * Returns: T if stream alive, else NIL
 528.768 + */
 528.769 +
 528.770 +long unix_ping (MAILSTREAM *stream)
 528.771 +{
 528.772 +  DOTLOCK lock;
 528.773 +  struct stat sbuf;
 528.774 +  long reparse;
 528.775 +				/* big no-op if not readwrite */
 528.776 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
 528.777 +    if (stream->rdonly) {	/* does he want to give up readwrite? */
 528.778 +				/* checkpoint if we changed something */
 528.779 +      if (LOCAL->dirty) unix_check (stream);
 528.780 +      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
 528.781 +      close (LOCAL->ld);	/* close the readwrite lock file */
 528.782 +      LOCAL->ld = -1;		/* no more readwrite lock fd */
 528.783 +      unlink (LOCAL->lname);	/* delete the readwrite lock file */
 528.784 +    }
 528.785 +    else {			/* see if need to reparse */
 528.786 +      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
 528.787 +				/* get current mailbox size */
 528.788 +	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
 528.789 +	else if (stat (stream->mailbox,&sbuf)) {
 528.790 +	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
 528.791 +		   strerror (errno));
 528.792 +	  MM_LOG (LOCAL->buf,ERROR);
 528.793 +	  unix_abort (stream);
 528.794 +	  return NIL;
 528.795 +	}
 528.796 +	reparse = (sbuf.st_size != LOCAL->filesize);
 528.797 +      }
 528.798 +				/* parse if mailbox changed */
 528.799 +      if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) {
 528.800 +				/* force checkpoint if double-dirty */
 528.801 +	if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL);
 528.802 +				/* unlock mailbox */
 528.803 +	else unix_unlock (LOCAL->fd,stream,&lock);
 528.804 +	mail_unlock (stream);	/* and stream */
 528.805 +	MM_NOCRITICAL (stream);	/* done with critical */
 528.806 +      }
 528.807 +    }
 528.808 +  }
 528.809 +  return LOCAL ? LONGT : NIL;	/* return if still alive */
 528.810 +}
 528.811 +
 528.812 +/* UNIX mail check mailbox
 528.813 + * Accepts: MAIL stream
 528.814 + */
 528.815 +
 528.816 +void unix_check (MAILSTREAM *stream)
 528.817 +{
 528.818 +  DOTLOCK lock;
 528.819 +				/* parse and lock mailbox */
 528.820 +  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 528.821 +      unix_parse (stream,&lock,LOCK_EX)) {
 528.822 +				/* any unsaved changes? */
 528.823 +    if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) {
 528.824 +      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
 528.825 +    }
 528.826 +				/* no checkpoint needed, just unlock */
 528.827 +    else unix_unlock (LOCAL->fd,stream,&lock);
 528.828 +    mail_unlock (stream);	/* unlock the stream */
 528.829 +    MM_NOCRITICAL (stream);	/* done with critical */
 528.830 +  }
 528.831 +}
 528.832 +
 528.833 +
 528.834 +/* UNIX mail expunge mailbox
 528.835 + * Accepts: MAIL stream
 528.836 + *	    sequence to expunge if non-NIL
 528.837 + *	    expunge options
 528.838 + * Returns: T, always
 528.839 + */
 528.840 +
 528.841 +long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
 528.842 +{
 528.843 +  long ret;
 528.844 +  unsigned long i;
 528.845 +  DOTLOCK lock;
 528.846 +  char *msg = NIL;
 528.847 +				/* parse and lock mailbox */
 528.848 +  if (ret = (sequence ? ((options & EX_UID) ?
 528.849 +			 mail_uid_sequence (stream,sequence) :
 528.850 +			 mail_sequence (stream,sequence)) : LONGT) &&
 528.851 +      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
 528.852 +      unix_parse (stream,&lock,LOCK_EX)) {
 528.853 +				/* check expunged messages if not dirty */
 528.854 +    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
 528.855 +      MESSAGECACHE *elt = mail_elt (stream,i);
 528.856 +      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
 528.857 +    }
 528.858 +    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
 528.859 +      unix_unlock (LOCAL->fd,stream,&lock);
 528.860 +      msg = "No messages deleted, so no update needed";
 528.861 +    }
 528.862 +    else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
 528.863 +      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
 528.864 +      else msg = "Mailbox checkpointed, but no messages expunged";
 528.865 +    }
 528.866 +				/* rewrite failed */
 528.867 +    else unix_unlock (LOCAL->fd,stream,&lock);
 528.868 +    mail_unlock (stream);	/* unlock the stream */
 528.869 +    MM_NOCRITICAL (stream);	/* done with critical */
 528.870 +    if (msg && !stream->silent) MM_LOG (msg,NIL);
 528.871 +  }
 528.872 +  else if (!stream->silent) MM_LOG("Expunge ignored on readonly mailbox",WARN);
 528.873 +  return ret;
 528.874 +}
 528.875 +
 528.876 +/* UNIX mail copy message(s)
 528.877 + * Accepts: MAIL stream
 528.878 + *	    sequence
 528.879 + *	    destination mailbox
 528.880 + *	    copy options
 528.881 + * Returns: T if copy successful, else NIL
 528.882 + */
 528.883 +
 528.884 +long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 528.885 +{
 528.886 +  struct stat sbuf;
 528.887 +  int fd;
 528.888 +  char *s,file[MAILTMPLEN];
 528.889 +  DOTLOCK lock;
 528.890 +  time_t tp[2];
 528.891 +  unsigned long i,j;
 528.892 +  MESSAGECACHE *elt;
 528.893 +  long ret = T;
 528.894 +  mailproxycopy_t pc =
 528.895 +    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
 528.896 +  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
 528.897 +			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
 528.898 +  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
 528.899 +  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
 528.900 +  MAILSTREAM *tstream = NIL;
 528.901 +  DRIVER *d;
 528.902 +  for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
 528.903 +       (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE));
 528.904 +       d = d->next);		/* see if mbox driver active */
 528.905 +  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 528.906 +	mail_sequence (stream,sequence))) return NIL;
 528.907 +				/* make sure destination is valid */
 528.908 +  if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) ||
 528.909 +	unix_valid (mailbox) || !errno))
 528.910 +    switch (errno) {
 528.911 +    case ENOENT:		/* no such file? */
 528.912 +      if (compare_cstring (mailbox,"INBOX")) {
 528.913 +	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
 528.914 +	return NIL;
 528.915 +      }
 528.916 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 528.917 +      unix_create (NIL,"INBOX");/* create empty INBOX */
 528.918 +    case EACCES:		/* file protected */
 528.919 +      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
 528.920 +      MM_LOG (LOCAL->buf,ERROR);
 528.921 +      return NIL;
 528.922 +    case EINVAL:
 528.923 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 528.924 +      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
 528.925 +      MM_LOG (LOCAL->buf,ERROR);
 528.926 +      return NIL;
 528.927 +    default:
 528.928 +      if (pc) return (*pc) (stream,sequence,mailbox,options);
 528.929 +      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
 528.930 +      MM_LOG (LOCAL->buf,ERROR);
 528.931 +      return NIL;
 528.932 +    }
 528.933 +
 528.934 +				/* try to open rewrite for UIDPLUS */
 528.935 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
 528.936 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
 528.937 +    tstream = mail_close (tstream);
 528.938 +  if (cu && !tstream) {		/* wanted a COPYUID? */
 528.939 +    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
 528.940 +	     mailbox);
 528.941 +    MM_LOG (LOCAL->buf,WARN);
 528.942 +    cu = NIL;			/* don't try to do COPYUID */
 528.943 +  }
 528.944 +  LOCAL->buf[0] = '\0';
 528.945 +  MM_CRITICAL (stream);		/* go critical */
 528.946 +  if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
 528.947 +		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
 528.948 +		       &lock,LOCK_EX)) < 0) {
 528.949 +    MM_NOCRITICAL (stream);	/* done with critical */
 528.950 +    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
 528.951 +    MM_LOG (LOCAL->buf,ERROR);/* log the error */
 528.952 +    return NIL;			/* failed */
 528.953 +  }
 528.954 +  fstat (fd,&sbuf);		/* get current file size */
 528.955 +				/* write all requested messages to mailbox */
 528.956 +  for (i = 1; ret && (i <= stream->nmsgs); i++)
 528.957 +    if ((elt = mail_elt (stream,i))->sequence) {
 528.958 +      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
 528.959 +      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
 528.960 +      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
 528.961 +      else {			/* internal header succeeded */
 528.962 +	s = unix_header (stream,i,&j,FT_INTERNAL);
 528.963 +				/* header size, sans trailing newline */
 528.964 +	if (j && (s[j - 2] == '\n')) j--;
 528.965 +	if (write (fd,s,j) < 0) ret = NIL;
 528.966 +	else {			/* message header succeeded */
 528.967 +	  j = tstream ?		/* write UIDPLUS data if have readwrite */
 528.968 +	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
 528.969 +	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
 528.970 +	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
 528.971 +	  else {		/* message status succeeded */
 528.972 +	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
 528.973 +	    if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL;
 528.974 +	    else if (cu) {	/* need to pass back new UID? */
 528.975 +	      mail_append_set (source,mail_uid (stream,i));
 528.976 +	      mail_append_set (dest,tstream->uid_last);
 528.977 +	    }
 528.978 +	  }
 528.979 +	}
 528.980 +      }
 528.981 +    }
 528.982 +
 528.983 +  if (!ret || fsync (fd)) {	/* force out the update */
 528.984 +    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
 528.985 +    ftruncate (fd,sbuf.st_size);
 528.986 +    ret = NIL;
 528.987 +  }
 528.988 +				/* force UIDVALIDITY assignment now */
 528.989 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
 528.990 +				/* return sets if doing COPYUID */
 528.991 +  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
 528.992 +  else {			/* flush any sets we may have built */
 528.993 +    mail_free_searchset (&source);
 528.994 +    mail_free_searchset (&dest);
 528.995 +  }
 528.996 +  tp[1] = time (0);		/* set mtime to now */
 528.997 +  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
 528.998 +  else tp[0] =			/* else preserve \Marked status */
 528.999 +	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
528.1000 +	 sbuf.st_atime : tp[1];
528.1001 +  utime (file,tp);		/* set the times */
528.1002 +  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
528.1003 +  if (tstream) {		/* update last UID if we can */
528.1004 +    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
528.1005 +    local->dirty = T;		/* do a rewrite */
528.1006 +    local->appending = T;	/* but not at the cost of marking as old */
528.1007 +    tstream = mail_close (tstream);
528.1008 +  }
528.1009 +				/* log the error */
528.1010 +  if (!ret) MM_LOG (LOCAL->buf,ERROR);
528.1011 +				/* delete if requested message */
528.1012 +  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
528.1013 +    if ((elt = mail_elt (stream,i))->sequence)
528.1014 +      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
528.1015 +  MM_NOCRITICAL (stream);	/* release critical */
528.1016 +  return ret;
528.1017 +}
528.1018 +
528.1019 +/* UNIX mail append message from stringstruct
528.1020 + * Accepts: MAIL stream
528.1021 + *	    destination mailbox
528.1022 + *	    append callback
528.1023 + *	    data for callback
528.1024 + * Returns: T if append successful, else NIL
528.1025 + */
528.1026 +
528.1027 +#define BUFLEN 8*MAILTMPLEN
528.1028 +
528.1029 +long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
528.1030 +{
528.1031 +  struct stat sbuf;
528.1032 +  int fd;
528.1033 +  unsigned long i;
528.1034 +  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
528.1035 +  time_t tp[2];
528.1036 +  FILE *sf,*df;
528.1037 +  MESSAGECACHE elt;
528.1038 +  DOTLOCK lock;
528.1039 +  STRING *message;
528.1040 +  unsigned long uidlocation = 0;
528.1041 +  appenduid_t au = (appenduid_t)
528.1042 +    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
528.1043 +     mail_parameters (NIL,GET_APPENDUID,NIL));
528.1044 +  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
528.1045 +  long ret = LONGT;
528.1046 +  MAILSTREAM *tstream = NIL;
528.1047 +  if (!stream) {		/* stream specified? */
528.1048 +    stream = &unixproto;	/* no, default stream to prototype */
528.1049 +    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
528.1050 +      fs_give ((void **) &stream->user_flags[i]);
528.1051 +  }
528.1052 +  if (!unix_valid (mailbox)) switch (errno) {
528.1053 +  case ENOENT:			/* no such file? */
528.1054 +    if (compare_cstring (mailbox,"INBOX")) {
528.1055 +      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
528.1056 +      return NIL;
528.1057 +    }
528.1058 +    unix_create (NIL,"INBOX");	/* create empty INBOX */
528.1059 +  case 0:			/* merely empty file? */
528.1060 +    tstream = stream;
528.1061 +    break;
528.1062 +  case EACCES:			/* file protected */
528.1063 +    sprintf (tmp,"Can't access destination: %.80s",mailbox);
528.1064 +    MM_LOG (tmp,ERROR);
528.1065 +    return NIL;
528.1066 +  case EINVAL:
528.1067 +    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
528.1068 +    MM_LOG (tmp,ERROR);
528.1069 +    return NIL;
528.1070 +  default:
528.1071 +    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
528.1072 +    MM_LOG (tmp,ERROR);
528.1073 +    return NIL;
528.1074 +  }
528.1075 +				/* get sniffing stream for keywords */
528.1076 +  else if (!(tstream = mail_open (NIL,mailbox,
528.1077 +				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
528.1078 +    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
528.1079 +    MM_LOG (tmp,ERROR);
528.1080 +    return NIL;
528.1081 +  }
528.1082 +
528.1083 +				/* get first message */
528.1084 +  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
528.1085 +  if (!(sf = tmpfile ())) {	/* must have scratch file */
528.1086 +    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
528.1087 +    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
528.1088 +      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
528.1089 +      MM_LOG (tmp,ERROR);
528.1090 +      return NIL;
528.1091 +    }
528.1092 +    unlink (tmp);
528.1093 +  }
528.1094 +  do {				/* parse date */
528.1095 +    if (!date) rfc822_date (date = tmp);
528.1096 +    if (!mail_parse_date (&elt,date)) {
528.1097 +      sprintf (tmp,"Bad date in append: %.80s",date);
528.1098 +      MM_LOG (tmp,ERROR);
528.1099 +    }
528.1100 +    else {			/* user wants to suppress time zones? */
528.1101 +      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
528.1102 +	time_t when = mail_longdate (&elt);
528.1103 +	date = ctime (&when);	/* use traditional date */
528.1104 +      }
528.1105 +				/* use POSIX-style date */
528.1106 +      else date = mail_cdate (tmp,&elt);
528.1107 +      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
528.1108 +      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
528.1109 +	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
528.1110 +	MM_LOG (tmp,ERROR);
528.1111 +      }
528.1112 +				/* get next message */
528.1113 +      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
528.1114 +    }
528.1115 +    fclose (sf);		/* punt scratch file */
528.1116 +    return NIL;			/* give up */
528.1117 +  } while (message);		/* until no more messages */
528.1118 +  if (fflush (sf)) {
528.1119 +    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
528.1120 +    MM_LOG (tmp,ERROR);
528.1121 +    fclose (sf);		/* punt scratch file */
528.1122 +    return NIL;			/* give up */
528.1123 +  }
528.1124 +  i = ftell (sf);		/* size of scratch file */
528.1125 +				/* close sniffing stream */
528.1126 +  if (tstream != stream) tstream = mail_close (tstream);
528.1127 +
528.1128 +  MM_CRITICAL (stream);		/* go critical */
528.1129 +				/* try to open readwrite for UIDPLUS */
528.1130 +  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
528.1131 +				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
528.1132 +    tstream = mail_close (tstream);
528.1133 +  if (au && !tstream) {		/* wanted an APPENDUID? */
528.1134 +    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
528.1135 +    MM_LOG (tmp,WARN);
528.1136 +    au = NIL;
528.1137 +  }
528.1138 +  if (((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
528.1139 +		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
528.1140 +			&lock,LOCK_EX)) < 0) ||
528.1141 +      !(df = fdopen (fd,"ab"))) {
528.1142 +    MM_NOCRITICAL (stream);	/* done with critical */
528.1143 +    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
528.1144 +    MM_LOG (tmp,ERROR);
528.1145 +    return NIL;
528.1146 +  }
528.1147 +  fstat (fd,&sbuf);		/* get current file size */
528.1148 +  rewind (sf);
528.1149 +  tp[1] = time (0);		/* set mtime to now */
528.1150 +				/* write all messages */
528.1151 +  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
528.1152 +      (fflush (df) == EOF) || fsync (fd)) {
528.1153 +    sprintf (buf,"Message append failed: %s",strerror (errno));
528.1154 +    MM_LOG (buf,ERROR);
528.1155 +    ftruncate (fd,sbuf.st_size);
528.1156 +    tp[0] =			/* preserve \Marked status */
528.1157 +      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
528.1158 +      sbuf.st_atime : tp[1];
528.1159 +    ret = NIL;			/* return error */
528.1160 +  }
528.1161 +  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
528.1162 +  utime (file,tp);		/* set the times */
528.1163 +  fclose (sf);			/* done with scratch file */
528.1164 +				/* force UIDVALIDITY assignment now */
528.1165 +  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
528.1166 +				/* return sets if doing APPENDUID */
528.1167 +  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
528.1168 +  else mail_free_searchset (&dst);
528.1169 +  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
528.1170 +  fclose (df);			/* note that unix_unlock() released the fd */
528.1171 +  if (tstream) {		/* update last UID if we can */
528.1172 +    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
528.1173 +    local->dirty = T;		/* do a rewrite */
528.1174 +    local->appending = T;	/* but not at the cost of marking as old */
528.1175 +    tstream = mail_close (tstream);
528.1176 +  }
528.1177 +  MM_NOCRITICAL (stream);	/* release critical */
528.1178 +  return ret;
528.1179 +}
528.1180 +
528.1181 +/* Collect and write single message to append scratch file
528.1182 + * Accepts: MAIL stream
528.1183 + *	    scratch file
528.1184 + *	    flags
528.1185 + *	    date
528.1186 + *	    message stringstruct
528.1187 + * Returns: NIL if write error, else T
528.1188 + */
528.1189 +
528.1190 +int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
528.1191 +		     STRING *msg)
528.1192 +{
528.1193 +  unsigned char *s,*t;
528.1194 +  unsigned long uf;
528.1195 +  long f = mail_parse_flags (stream,flags,&uf);
528.1196 +				/* write metadata, note date ends with NL */
528.1197 +  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
528.1198 +  while (uf)			/* write user flags */    
528.1199 +    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
528.1200 +	(fprintf (sf," %s",s) < 0)) return NIL;
528.1201 +  if (putc ('\n',sf) == EOF) return NIL;
528.1202 +  while (SIZE (msg)) {		/* copy text to scratch file */
528.1203 +    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
528.1204 +      if (!*s) *s = 0x80;	/* disallow NUL */
528.1205 +				/* write buffered text */
528.1206 +    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
528.1207 +      SETPOS (msg,GETPOS (msg) + msg->cursize);
528.1208 +    else return NIL;		/* failed */
528.1209 +  }
528.1210 +				/* write trailing newline and return */
528.1211 +  return (putc ('\n',sf) == EOF) ? NIL : T;
528.1212 +}
528.1213 +
528.1214 +/* Append messages from scratch file to mailbox
528.1215 + * Accepts: MAIL stream
528.1216 + *	    source file
528.1217 + *	    destination file
528.1218 + *	    uidset to update if non-NIL
528.1219 + * Returns: T if success, NIL if failure
528.1220 + */
528.1221 +
528.1222 +int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
528.1223 +{
528.1224 +  int ti,zn,c;
528.1225 +  long f;
528.1226 +  unsigned long i,j;
528.1227 +  char *x,tmp[MAILTMPLEN];
528.1228 +  int hdrp = T;
528.1229 +				/* get message metadata line */
528.1230 +  while (fgets (tmp,MAILTMPLEN,sf)) {
528.1231 +    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
528.1232 +    f = strtol (tmp,&x,10);	/* get flags */
528.1233 +    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
528.1234 +    i = strtoul (x,&x,10);	/* get message size */
528.1235 +    if ((*x++ != ' ') ||	/* build initial header */
528.1236 +	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
528.1237 +	(f&fSEEN && (putc ('R',df) == EOF)) ||
528.1238 +	(fputs ("\nX-Status: ",df) == EOF) ||
528.1239 +	(f&fDELETED && (putc ('D',df) == EOF)) ||
528.1240 +	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
528.1241 +	(f&fANSWERED && (putc ('A',df) == EOF)) ||
528.1242 +	(f&fDRAFT && (putc ('T',df) == EOF)) ||
528.1243 +	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
528.1244 +				/* copy keywords */
528.1245 +    while ((c = getc (sf)) != '\n') switch (c) {
528.1246 +    case EOF:
528.1247 +      return NIL;
528.1248 +    default:
528.1249 +      if (putc (c,df) == EOF) return NIL;
528.1250 +    }
528.1251 +    if ((putc ('\n',df) == EOF) ||
528.1252 +	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
528.1253 +      return NIL;
528.1254 +
528.1255 +    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
528.1256 +				/* get read line length */
528.1257 +      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
528.1258 +      i -= j;			/* number of bytes left */
528.1259 +				/* squish out CRs (note also copies NUL) */
528.1260 +      for (x = tmp; x = strchr (x,'\r'); --j) memmove (x,x+1,j-(x-tmp));
528.1261 +      if (!j) continue;		/* do nothing if line emptied */
528.1262 +				/* start of line? */
528.1263 +      if ((c == '\n')) switch (tmp[0]) {
528.1264 +      case 'F':			/* possible "From " (case counts here) */
528.1265 +	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
528.1266 +	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
528.1267 +	  if (!unix_fromwidget) {
528.1268 +	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
528.1269 +	    if (!ti) break;	/*  it looks like a valid header */
528.1270 +	  }			/* write the widget */
528.1271 +	  if (putc ('>',df) == EOF) return NIL;
528.1272 +	}
528.1273 +	break;
528.1274 +      case 'S': case 's':	/* possible "Status:" */
528.1275 +	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
528.1276 +	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
528.1277 +	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
528.1278 +	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
528.1279 +	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
528.1280 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
528.1281 +	break;
528.1282 +      case 'X': case 'x':	/* possible X-??? header */
528.1283 +	if (hdrp && (tmp[1] == '-') &&
528.1284 +				/* possible X-UID: */
528.1285 +	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
528.1286 +	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
528.1287 +	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
528.1288 +				/* possible X-IMAP: */
528.1289 +	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
528.1290 +	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
528.1291 +	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
528.1292 +	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
528.1293 +	      ((tmp[6] == ':') ||
528.1294 +				/* or X-IMAPbase: */
528.1295 +	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
528.1296 +		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
528.1297 +		((tmp[8] == 's') || (tmp[8] == 'S')) &&
528.1298 +		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
528.1299 +				/* possible X-Status: */
528.1300 +	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
528.1301 +	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
528.1302 +	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
528.1303 +	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
528.1304 +	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
528.1305 +	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
528.1306 +				/* possible X-Keywords: */
528.1307 +	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
528.1308 +	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
528.1309 +	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
528.1310 +	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
528.1311 +	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
528.1312 +	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
528.1313 +	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
528.1314 +	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
528.1315 +	    (fputs ("X-Original-",df) == EOF)) return NIL;
528.1316 +      case '\n':		/* blank line */
528.1317 +	hdrp = NIL;
528.1318 +	break;
528.1319 +      default:			/* nothing to do */
528.1320 +	break;
528.1321 +      }
528.1322 +				/* just write the line */
528.1323 +      if (fwrite (tmp,1,j,df) != j) return NIL;
528.1324 +    }
528.1325 +    if (i) return NIL;		/* didn't read entire message */
528.1326 +				/* update set */
528.1327 +    if (stream) mail_append_set (set,stream->uid_last);
528.1328 +  }
528.1329 +  return T;
528.1330 +}
528.1331 +
528.1332 +/* Internal routines */
528.1333 +
528.1334 +
528.1335 +/* UNIX mail abort stream
528.1336 + * Accepts: MAIL stream
528.1337 + */
528.1338 +
528.1339 +void unix_abort (MAILSTREAM *stream)
528.1340 +{
528.1341 +  if (LOCAL) {			/* only if a file is open */
528.1342 +    if (LOCAL->fd >= 0) close (LOCAL->fd);
528.1343 +    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
528.1344 +      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
528.1345 +      close (LOCAL->ld);	/* close the lock file */
528.1346 +      unlink (LOCAL->lname);	/* and delete it */
528.1347 +    }
528.1348 +    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
528.1349 +				/* free local text buffers */
528.1350 +    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
528.1351 +    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
528.1352 +    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
528.1353 +    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
528.1354 +				/* nuke the local data */
528.1355 +    fs_give ((void **) &stream->local);
528.1356 +    stream->dtb = NIL;		/* log out the DTB */
528.1357 +  }
528.1358 +}
528.1359 +
528.1360 +/* UNIX open and lock mailbox
528.1361 + * Accepts: file name to open/lock
528.1362 + *	    file open mode
528.1363 + *	    destination buffer for lock file name
528.1364 + *	    type of locking operation (LOCK_SH or LOCK_EX)
528.1365 + */
528.1366 +
528.1367 +int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
528.1368 +{
528.1369 +  int fd;
528.1370 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
528.1371 +  (*bn) (BLOCK_FILELOCK,NIL);
528.1372 +				/* try locking the easy way */
528.1373 +  if (dotlock_lock (file,lock,-1)) {
528.1374 +				/* got dotlock file, easy open */
528.1375 +    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
528.1376 +    else dotlock_unlock (lock);	/* open failed, free the dotlock */
528.1377 +  }
528.1378 +				/* no dot lock file, open file now */
528.1379 +  else if ((fd = open (file,flags,mode)) >= 0) {
528.1380 +				/* try paranoid way to make a dot lock file */
528.1381 +    if (dotlock_lock (file,lock,fd)) {
528.1382 +      close (fd);		/* get fresh fd in case of timing race */
528.1383 +      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
528.1384 +				/* open failed, free the dotlock */
528.1385 +      else dotlock_unlock (lock);
528.1386 +    }
528.1387 +    else flock (fd,op);		/* paranoid way failed, just flock() it */
528.1388 +  }
528.1389 +  (*bn) (BLOCK_NONE,NIL);
528.1390 +  return fd;
528.1391 +}
528.1392 +
528.1393 +/* UNIX unlock and close mailbox
528.1394 + * Accepts: file descriptor
528.1395 + *	    (optional) mailbox stream to check atime/mtime
528.1396 + *	    (optional) lock file name
528.1397 + */
528.1398 +
528.1399 +void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
528.1400 +{
528.1401 +  if (stream) {			/* need to muck with times? */
528.1402 +    struct stat sbuf;
528.1403 +    time_t tp[2];
528.1404 +    time_t now = time (0);
528.1405 +    fstat (fd,&sbuf);		/* get file times */
528.1406 +    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
528.1407 +      tp[0] = now;		/* set atime to now */
528.1408 +				/* set mtime to (now - 1) if necessary */
528.1409 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
528.1410 +    }
528.1411 +    else if (stream->recent) {	/* readonly with recent messages */
528.1412 +      if ((sbuf.st_atime >= sbuf.st_mtime) ||
528.1413 +	  (sbuf.st_atime >= sbuf.st_ctime))
528.1414 +				/* keep past mtime, whack back atime */
528.1415 +	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
528.1416 +      else now = 0;		/* no time change needed */
528.1417 +    }
528.1418 +				/* readonly with no recent messages */
528.1419 +    else if ((sbuf.st_atime < sbuf.st_mtime) ||
528.1420 +	     (sbuf.st_atime < sbuf.st_ctime)) {
528.1421 +      tp[0] = now;		/* set atime to now */
528.1422 +				/* set mtime to (now - 1) if necessary */
528.1423 +      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
528.1424 +    }
528.1425 +    else now = 0;		/* no time change needed */
528.1426 +				/* set the times, note change */
528.1427 +    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
528.1428 +  }
528.1429 +  flock (fd,LOCK_UN);		/* release flock'ers */
528.1430 +  if (!stream) close (fd);	/* close the file if no stream */
528.1431 +  dotlock_unlock (lock);	/* flush the lock file if any */
528.1432 +}
528.1433 +
528.1434 +/* UNIX mail parse and lock mailbox
528.1435 + * Accepts: MAIL stream
528.1436 + *	    space to write lock file name
528.1437 + *	    type of locking operation
528.1438 + * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
528.1439 + */
528.1440 +
528.1441 +int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
528.1442 +{
528.1443 +  int zn;
528.1444 +  unsigned long i,j,k,m;
528.1445 +  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
528.1446 +  int ti = 0,retain = T;
528.1447 +  unsigned long nmsgs = stream->nmsgs;
528.1448 +  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
528.1449 +  unsigned long recent = stream->recent;
528.1450 +  unsigned long oldnmsgs = stream->nmsgs;
528.1451 +  short silent = stream->silent;
528.1452 +  short pseudoseen = NIL;
528.1453 +  struct stat sbuf;
528.1454 +  STRING bs;
528.1455 +  FDDATA d;
528.1456 +  MESSAGECACHE *elt;
528.1457 +  mail_lock (stream);		/* guard against recursion or pingers */
528.1458 +				/* toss out previous descriptor */
528.1459 +  if (LOCAL->fd >= 0) close (LOCAL->fd);
528.1460 +  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
528.1461 +  if ((LOCAL->fd = unix_lock (stream->mailbox,(LOCAL->ld >= 0) ?
528.1462 +			      O_RDWR : O_RDONLY,
528.1463 +			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
528.1464 +			      lock,op)) < 0) {
528.1465 +    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
528.1466 +    MM_LOG (tmp,ERROR);
528.1467 +    unix_abort (stream);
528.1468 +    mail_unlock (stream);
528.1469 +    MM_NOCRITICAL (stream);	/* done with critical */
528.1470 +    return NIL;
528.1471 +  }
528.1472 +  fstat (LOCAL->fd,&sbuf);	/* get status */
528.1473 +				/* validate change in size */
528.1474 +  if (sbuf.st_size < LOCAL->filesize) {
528.1475 +    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
528.1476 +	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
528.1477 +    MM_LOG (tmp,ERROR);		/* this is pretty bad */
528.1478 +    unix_unlock (LOCAL->fd,stream,lock);
528.1479 +    unix_abort (stream);
528.1480 +    mail_unlock (stream);
528.1481 +    MM_NOCRITICAL (stream);	/* done with critical */
528.1482 +    return NIL;
528.1483 +  }
528.1484 +
528.1485 +				/* new data? */
528.1486 +  else if (i = sbuf.st_size - LOCAL->filesize) {
528.1487 +    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
528.1488 +    d.pos = LOCAL->filesize;	/* get to that position in the file */
528.1489 +    d.chunk = LOCAL->buf;	/* initial buffer chunk */
528.1490 +    d.chunksize = CHUNKSIZE;	/* file chunk size */
528.1491 +    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
528.1492 +				/* skip leading whitespace for broken MTAs */
528.1493 +    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
528.1494 +	   (c == ' ') || (c == '\t')) SNX (&bs);
528.1495 +    if (SIZE (&bs)) {		/* read new data */
528.1496 +				/* remember internal header position */
528.1497 +      j = LOCAL->filesize + GETPOS (&bs);
528.1498 +      s = unix_mbxline (stream,&bs,&i);
528.1499 +      t = NIL,zn = 0;
528.1500 +      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
528.1501 +      if (!ti) {		/* someone pulled the rug from under us */
528.1502 +	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
528.1503 +		 (char *) s);
528.1504 +	MM_LOG (tmp,ERROR);
528.1505 +	unix_unlock (LOCAL->fd,stream,lock);
528.1506 +	unix_abort (stream);
528.1507 +	mail_unlock (stream);
528.1508 +				/* done with critical */
528.1509 +	MM_NOCRITICAL (stream);
528.1510 +	return NIL;
528.1511 +      }
528.1512 +      stream->silent = T;	/* quell main program new message events */
528.1513 +      do {			/* found a message */
528.1514 +				/* instantiate first new message */
528.1515 +	mail_exists (stream,++nmsgs);
528.1516 +	(elt = mail_elt (stream,nmsgs))->valid = T;
528.1517 +	recent++;		/* assume recent by default */
528.1518 +	elt->recent = T;
528.1519 +				/* note position/size of internal header */
528.1520 +	elt->private.special.offset = j;
528.1521 +	elt->private.msg.header.offset = elt->private.special.text.size = i;
528.1522 +
528.1523 +				/* generate plausible IMAPish date string */
528.1524 +	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
528.1525 +	date[14] = date[17] = ':';
528.1526 +				/* dd */
528.1527 +	date[0] = t[ti - 2]; date[1] = t[ti - 1];
528.1528 +				/* mmm */
528.1529 +	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
528.1530 +				/* hh */
528.1531 +	date[12] = t[ti + 1]; date[13] = t[ti + 2];
528.1532 +				/* mm */
528.1533 +	date[15] = t[ti + 4]; date[16] = t[ti + 5];
528.1534 +	if (t[ti += 6] == ':') {/* ss */
528.1535 +	  date[18] = t[++ti]; date[19] = t[++ti];
528.1536 +	  ti++;			/* move to space */
528.1537 +	}
528.1538 +	else date[18] = date[19] = '0';
528.1539 +				/* yy -- advance over timezone if necessary */
528.1540 +	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
528.1541 +	date[7] = t[ti + 1]; date[8] = t[ti + 2];
528.1542 +	date[9] = t[ti + 3]; date[10] = t[ti + 4];
528.1543 +				/* zzz */
528.1544 +	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
528.1545 +	date[21] = *t++; date[22] = *t++; date[23] = *t++;
528.1546 +	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
528.1547 +	else {			/* numeric time zone */
528.1548 +	  date[24] = *t++; date[25] = *t++;
528.1549 +	  date[26] = '\0'; date[20] = ' ';
528.1550 +	}
528.1551 +				/* set internal date */
528.1552 +	if (!mail_parse_date (elt,date)) {
528.1553 +	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
528.1554 +	  MM_LOG (tmp,WARN);
528.1555 +	}
528.1556 +
528.1557 +	do {			/* look for message body */
528.1558 +	  s = t = unix_mbxline (stream,&bs,&i);
528.1559 +	  if (i) switch (*s) {	/* check header lines */
528.1560 +	  case 'X':		/* possible X-???: line */
528.1561 +	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
528.1562 +				/* X-Status: becomes Status: in S case */
528.1563 +	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
528.1564 +		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
528.1565 +				/* possible X-Keywords */
528.1566 +	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
528.1567 +		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
528.1568 +		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
528.1569 +		SIZEDTEXT uf;
528.1570 +		retain = NIL;	/* don't retain continuation */
528.1571 +		s += 11;	/* flush leading whitespace */
528.1572 +		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
528.1573 +		  while (*s == ' ') s++;
528.1574 +				/* find end of keyword */
528.1575 +		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
528.1576 +				/* got a keyword? */
528.1577 +		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
528.1578 +		    uf.data = (unsigned char *) s;
528.1579 +		    uf.size = k;
528.1580 +		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
528.1581 +		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
528.1582 +			elt->user_flags |= ((long) 1) << j;
528.1583 +			break;
528.1584 +		      }
528.1585 + 		  }
528.1586 +		  s = u;	/* advance to next keyword */
528.1587 +		}
528.1588 +		break;
528.1589 +	      }
528.1590 +
528.1591 +				/* possible X-IMAP */
528.1592 +	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
528.1593 +		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
528.1594 +					 ((s[6] == 'b') && (s[7] == 'a') &&
528.1595 +					  (s[8] == 's') && (s[9] == 'e') &&
528.1596 +					  (s[10] == ':')))) {
528.1597 +		retain = NIL;	/* don't retain continuation */
528.1598 +		if ((nmsgs == 1) && !stream->uid_validity) {
528.1599 +				/* advance to data */
528.1600 +		  s += m ? 7 : 11;
528.1601 +				/* flush whitespace */
528.1602 +		  while (*s == ' ') s++;
528.1603 +		  j = 0;	/* slurp UID validity */
528.1604 +				/* found a digit? */
528.1605 +		  while (isdigit (*s)) {
528.1606 +		    j *= 10;	/* yes, add it in */
528.1607 +		    j += *s++ - '0';
528.1608 +		  }
528.1609 +				/* flush whitespace */
528.1610 +		  while (*s == ' ') s++;
528.1611 +				/* must have valid UID validity and UID last */
528.1612 +		  if (j && isdigit (*s)) {
528.1613 +				/* pseudo-header seen if X-IMAP */
528.1614 +		    if (m) pseudoseen = LOCAL->pseudo = T;
528.1615 +				/* save UID validity */
528.1616 +		    stream->uid_validity = j;
528.1617 +		    j = 0;	/* slurp UID last */
528.1618 +		    while (isdigit (*s)) {
528.1619 +		      j *= 10;	/* yes, add it in */
528.1620 +		      j += *s++ - '0';
528.1621 +		    }
528.1622 +				/* save UID last */
528.1623 +		    stream->uid_last = j;
528.1624 +				/* process keywords */
528.1625 +		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
528.1626 +			 s = u,j++) {
528.1627 +				/* flush leading whitespace */
528.1628 +		      while (*s == ' ') s++;
528.1629 +		      u = strpbrk (s," \n\r");
528.1630 +				/* got a keyword? */
528.1631 +		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
528.1632 +			  (k <= MAXUSERFLAG)) {
528.1633 +			if (stream->user_flags[j])
528.1634 +			  fs_give ((void **) &stream->user_flags[j]);
528.1635 +			stream->user_flags[j] = (char *) fs_get (k + 1);
528.1636 +			strncpy (stream->user_flags[j],s,k);
528.1637 +			stream->user_flags[j][k] = '\0';
528.1638 +		      }
528.1639 +		    }
528.1640 +		  }
528.1641 +		}
528.1642 +		break;
528.1643 +	      }
528.1644 +
528.1645 +				/* possible X-UID */
528.1646 +	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
528.1647 +		       s[5] == ':') {
528.1648 +		retain = NIL;	/* don't retain continuation */
528.1649 +				/* only believe if have a UID validity */
528.1650 +		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
528.1651 +		  s += 6;	/* advance to UID value */
528.1652 +				/* flush whitespace */
528.1653 +		  while (*s == ' ') s++;
528.1654 +		  j = 0;
528.1655 +				/* found a digit? */
528.1656 +		  while (isdigit (*s)) {
528.1657 +		    j *= 10;	/* yes, add it in */
528.1658 +		    j += *s++ - '0';
528.1659 +		  }
528.1660 +				/* flush remainder of line */
528.1661 +		  while (*s != '\n') s++;
528.1662 +				/* make sure not duplicated */
528.1663 +		  if (elt->private.uid)
528.1664 +		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
528.1665 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
528.1666 +			     j,elt->private.uid);
528.1667 +				/* make sure UID doesn't go backwards */
528.1668 +		  else if (j <= prevuid)
528.1669 +		    sprintf (tmp,"Message %lu UID %lu less than %lu",
528.1670 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
528.1671 +			     j,prevuid + 1);
528.1672 +#if 0	/* this is currently broken by UIDPLUS */
528.1673 +				/* or skip by mailbox's recorded last */
528.1674 +		  else if (j > stream->uid_last)
528.1675 +		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
528.1676 +			     pseudoseen ? elt->msgno - 1 : elt->msgno,
528.1677 +			     j,stream->uid_last);
528.1678 +#endif
528.1679 +		  else {	/* normal UID case */
528.1680 +		    prevuid = elt->private.uid = j;
528.1681 +#if 1	/* temporary kludge for UIDPLUS */
528.1682 +		    if (prevuid > stream->uid_last) {
528.1683 +		      stream->uid_last = prevuid;
528.1684 +		      LOCAL->ddirty = LOCAL->dirty = T;
528.1685 +		    }		    
528.1686 +#endif
528.1687 +		    break;	/* exit this cruft */
528.1688 +		  }
528.1689 +		  MM_LOG (tmp,WARN);
528.1690 +				/* invalidate UID validity */
528.1691 +		  stream->uid_validity = 0;
528.1692 +		  elt->private.uid = 0;
528.1693 +		}
528.1694 +		break;
528.1695 +	      }
528.1696 +	    }
528.1697 +				/* otherwise fall into S case */
528.1698 +
528.1699 +	  case 'S':		/* possible Status: line */
528.1700 +	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
528.1701 +		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
528.1702 +	      retain = NIL;	/* don't retain continuation */
528.1703 +	      s += 6;		/* advance to status flags */
528.1704 +	      do switch (*s++) {/* parse flags */
528.1705 +	      case 'R':		/* message read */
528.1706 +		elt->seen = T;
528.1707 +		break;
528.1708 +	      case 'O':		/* message old */
528.1709 +		if (elt->recent) {
528.1710 +		  elt->recent = NIL;
528.1711 +		  recent--;	/* it really wasn't recent */
528.1712 +		}
528.1713 +		break;
528.1714 +	      case 'D':		/* message deleted */
528.1715 +		elt->deleted = T;
528.1716 +		break;
528.1717 +	      case 'F':		/* message flagged */
528.1718 +		elt->flagged = T;
528.1719 +		break;
528.1720 +	      case 'A':		/* message answered */
528.1721 +		elt->answered = T;
528.1722 +		break;
528.1723 +	      case 'T':		/* message is a draft */
528.1724 +		elt->draft = T;
528.1725 +		break;
528.1726 +	      default:		/* some other crap */
528.1727 +		break;
528.1728 +	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
528.1729 +	      break;		/* all done */
528.1730 +	    }
528.1731 +				/* otherwise fall into default case */
528.1732 +
528.1733 +	  default:		/* ordinary header line */
528.1734 +	    if ((*s == 'S') || (*s == 's') ||
528.1735 +		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
528.1736 +	      unsigned char *e,*v;
528.1737 +				/* must match what mail_filter() does */
528.1738 +	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
528.1739 +		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
528.1740 +		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
528.1741 +				  (c != '\r') && (c != '\n')));
528.1742 +		   *v++ = *u++);
528.1743 +	      *v = '\0';	/* tie off */
528.1744 +				/* matches internal header? */
528.1745 +	      if (!compare_cstring (tmp,"STATUS") ||
528.1746 +		  !compare_cstring (tmp,"X-STATUS") ||
528.1747 +		  !compare_cstring (tmp,"X-KEYWORDS") ||
528.1748 +		  !compare_cstring (tmp,"X-UID") ||
528.1749 +		  !compare_cstring (tmp,"X-IMAP") ||
528.1750 +		  !compare_cstring (tmp,"X-IMAPBASE")) {
528.1751 +		char err[MAILTMPLEN];
528.1752 +		sprintf (err,"Discarding bogus %s header in message %lu",
528.1753 +			 (char *) tmp,elt->msgno);
528.1754 +		MM_LOG (err,WARN);
528.1755 +		retain = NIL;	/* don't retain continuation */
528.1756 +		break;		/* different case or something */
528.1757 +	      }
528.1758 +	    }
528.1759 +				/* retain or non-continuation? */
528.1760 +	    if (retain || ((*s != ' ') && (*s != '\t'))) {
528.1761 +	      retain = T;	/* retaining continuation now */
528.1762 +				/* line length in LF format newline */
528.1763 +	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
528.1764 +				/* "internal" header size */
528.1765 +	      elt->private.spare.data += k;
528.1766 +				/* message size */
528.1767 +	      elt->rfc822_size += k + 1;
528.1768 +	    }
528.1769 +	    else {
528.1770 +	      char err[MAILTMPLEN];
528.1771 +	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
528.1772 +		      elt->msgno,(char *) s);
528.1773 +	      if (u = strpbrk (err,"\r\n")) *u = '\0';
528.1774 +	      MM_LOG (err,WARN);
528.1775 +	      break;		/* different case or something */
528.1776 +	    }
528.1777 +	    break;
528.1778 +	  }
528.1779 +	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
528.1780 +				/* "internal" header sans trailing newline */
528.1781 +	if (i) elt->private.spare.data--;
528.1782 +				/* assign a UID if none found */
528.1783 +	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
528.1784 +	  prevuid = elt->private.uid = ++stream->uid_last;
528.1785 +	  elt->private.dirty = T;
528.1786 +	  LOCAL->ddirty = T;	/* force update */
528.1787 +	}
528.1788 +	else elt->private.dirty = elt->recent;
528.1789 +
528.1790 +				/* note size of header, location of text */
528.1791 +	elt->private.msg.header.text.size = 
528.1792 +	  (elt->private.msg.text.offset =
528.1793 +	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
528.1794 +	     elt->private.special.text.size;
528.1795 +	k = m = 0;		/* no previous line size yet */
528.1796 +				/* note current position */
528.1797 +	j = LOCAL->filesize + GETPOS (&bs);
528.1798 +	if (i) do {		/* look for next message */
528.1799 +	  s = unix_mbxline (stream,&bs,&i);
528.1800 +	  if (i) {		/* got new data? */
528.1801 +	    VALID (s,t,ti,zn);	/* yes, parse line */
528.1802 +	    if (!ti) {		/* not a header line, add it to message */
528.1803 +	      elt->rfc822_size += i;
528.1804 +	      for (j = 0; j < i; ++j) switch (s[j]) {
528.1805 +	      case '\r':	/* squeeze out CRs */
528.1806 +		elt->rfc822_size -= 1;
528.1807 +		break;
528.1808 +	      case '\n':	/* LF becomes CRLF */
528.1809 +		elt->rfc822_size += 1;
528.1810 +		break;
528.1811 +	      default:
528.1812 +		break;
528.1813 +	      }
528.1814 +	      if ((i == 1) && (*s == '\n')) {
528.1815 +		k = 2;
528.1816 +		m = 1;
528.1817 +	      }
528.1818 +	      else if ((i == 2) && (*s == '\r') && (s[1] == '\n'))
528.1819 +		k = m = 2;
528.1820 +	      else k = m = 0;	/* file does not end with newline! */
528.1821 +				/* update current position */
528.1822 +	      j = LOCAL->filesize + GETPOS (&bs);
528.1823 +	    }
528.1824 +	  }
528.1825 +	} while (i && !ti);	/* until found a header */
528.1826 +	elt->private.msg.text.text.size = j -
528.1827 +	  (elt->private.special.offset + elt->private.msg.text.offset);
528.1828 +				/* flush ending blank line */
528.1829 +	elt->private.msg.text.text.size -= m;
528.1830 +	elt->rfc822_size -= k;
528.1831 +				/* until end of buffer */
528.1832 +      } while (!stream->sniff && i);
528.1833 +      if (pseudoseen) {		/* flush pseudo-message if present */
528.1834 +				/* decrement recent count */
528.1835 +	if (mail_elt (stream,1)->recent) recent--;
528.1836 +				/* and the exists count */
528.1837 +	mail_exists (stream,nmsgs--);
528.1838 +	mail_expunged(stream,1);/* fake an expunge of that message */
528.1839 +      }
528.1840 +				/* need to start a new UID validity? */
528.1841 +      if (!stream->uid_validity) {
528.1842 +	stream->uid_validity = time (0);
528.1843 +				/* in case a whiner with no life */
528.1844 +	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
528.1845 +	  stream->uid_nosticky = T;
528.1846 +	else if (nmsgs) {	/* don't bother if empty file */
528.1847 +				/* make dirty to restart UID epoch */
528.1848 +	  LOCAL->ddirty = LOCAL->dirty = T;
528.1849 +				/* need to rewrite msg 1 if not pseudo */
528.1850 +	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
528.1851 +	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
528.1852 +	}
528.1853 +      }
528.1854 +      stream->nmsgs = oldnmsgs;	/* whack it back down */
528.1855 +      stream->silent = silent;	/* restore old silent setting */
528.1856 +				/* notify upper level of new mailbox sizes */
528.1857 +      mail_exists (stream,nmsgs);
528.1858 +      mail_recent (stream,recent);
528.1859 +				/* mark dirty so O flags are set */
528.1860 +      if (recent) LOCAL->dirty = T;
528.1861 +    }
528.1862 +  }
528.1863 +				/* no change, don't babble if never got time */
528.1864 +  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
528.1865 +    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
528.1866 +				/* update parsed file size and time */
528.1867 +  LOCAL->filesize = sbuf.st_size;
528.1868 +  LOCAL->filetime = sbuf.st_mtime;
528.1869 +  return T;			/* return the winnage */
528.1870 +}
528.1871 +
528.1872 +/* UNIX read line from mailbox
528.1873 + * Accepts: mail stream
528.1874 + *	    stringstruct
528.1875 + *	    pointer to line size
528.1876 + * Returns: pointer to input line
528.1877 + */
528.1878 +
528.1879 +char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
528.1880 +{
528.1881 +  unsigned long i,j,k,m;
528.1882 +  char *s,*t,*te;
528.1883 +  char *ret = "";
528.1884 +				/* flush old buffer */
528.1885 +  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
528.1886 +				/* if buffer needs refreshing */
528.1887 +  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
528.1888 +  if (SIZE (bs)) {		/* find newline */
528.1889 +				/* end of fast scan */
528.1890 +    te = (t = (s = bs->curpos) + bs->cursize) - 12;
528.1891 +    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
528.1892 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
528.1893 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
528.1894 +		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
528.1895 +      --s;			/* back up */
528.1896 +      break;			/* exit loop */
528.1897 +    }
528.1898 +				/* final character-at-a-time scan */
528.1899 +    while ((s < t) && (*s != '\n')) ++s;
528.1900 +				/* difficult case if line spans buffer */
528.1901 +    if ((i = s - bs->curpos) == bs->cursize) {
528.1902 +				/* have space in line buffer? */
528.1903 +      if (i > LOCAL->linebuflen) {
528.1904 +	fs_give ((void **) &LOCAL->linebuf);
528.1905 +	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
528.1906 +      }
528.1907 +				/* remember what we have so far */
528.1908 +      memcpy (LOCAL->linebuf,bs->curpos,i);
528.1909 +				/* load next buffer */
528.1910 +      SETPOS (bs,k = GETPOS (bs) + i);
528.1911 +				/* end of fast scan */
528.1912 +      te = (t = (s = bs->curpos) + bs->cursize) - 12;
528.1913 +				/* fast scan in overlap buffer */
528.1914 +      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
528.1915 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
528.1916 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
528.1917 +			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
528.1918 +	--s;			/* back up */
528.1919 +	break;			/* exit loop */
528.1920 +      }
528.1921 +
528.1922 +				/* final character-at-a-time scan */
528.1923 +      while ((s < t) && (*s != '\n')) ++s;
528.1924 +				/* huge line? */
528.1925 +      if ((j = s - bs->curpos) == bs->cursize) {
528.1926 +	SETPOS (bs,GETPOS (bs) + j);
528.1927 +				/* look for end of line (s-l-o-w!!) */
528.1928 +	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
528.1929 +	SETPOS (bs,k);		/* go back to where it started */
528.1930 +      }
528.1931 +				/* got size of data, make buffer for return */
528.1932 +      ret = LOCAL->line = (char *) fs_get (i + j + 2);
528.1933 +				/* copy first chunk */
528.1934 +      memcpy (ret,LOCAL->linebuf,i);
528.1935 +      while (j) {		/* copy remainder */
528.1936 +	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
528.1937 +	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
528.1938 +	i += k;			/* account for this much read in */
528.1939 +	j -= k;
528.1940 +	bs->curpos += k;	/* increment new position */
528.1941 +	bs->cursize -= k;	/* eat that many bytes */
528.1942 +      }
528.1943 +      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
528.1944 +				/* read newline at end */
528.1945 +      if (SIZE (bs)) ret[i++] = SNX (bs);
528.1946 +      ret[i] = '\0';		/* makes debugging easier */
528.1947 +    }
528.1948 +    else {			/* this is easy */
528.1949 +      ret = bs->curpos;		/* string it at this position */
528.1950 +      bs->curpos += ++i;	/* increment new position */
528.1951 +      bs->cursize -= i;		/* eat that many bytes */
528.1952 +    }
528.1953 +    *size = i;			/* return that to user */
528.1954 +  }
528.1955 +  else *size = 0;		/* end of data, return empty */
528.1956 +  return ret;
528.1957 +}
528.1958 +
528.1959 +/* UNIX make pseudo-header
528.1960 + * Accepts: MAIL stream
528.1961 + *	    buffer to write pseudo-header
528.1962 + * Returns: length of pseudo-header
528.1963 + */
528.1964 +
528.1965 +unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
528.1966 +{
528.1967 +  int i;
528.1968 +  char *s,tmp[MAILTMPLEN];
528.1969 +  time_t now = time (0);
528.1970 +  rfc822_fixed_date (tmp);
528.1971 +  sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
528.1972 +	   pseudo_from,ctime (&now),
528.1973 +	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
528.1974 +	   (unsigned long) now,mylocalhost (),stream->uid_validity,
528.1975 +	   stream->uid_last);
528.1976 +  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
528.1977 +    if (stream->user_flags[i])
528.1978 +      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
528.1979 +  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
528.1980 +  return strlen (hdr);		/* return header length */
528.1981 +}
528.1982 +
528.1983 +/* UNIX make status string
528.1984 + * Accepts: MAIL stream
528.1985 + *	    destination string to write
528.1986 + *	    message cache entry
528.1987 + *	    UID to write if non-zero (else use elt->private.uid)
528.1988 + *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
528.1989 + * Returns: length of string
528.1990 + */
528.1991 +
528.1992 +unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
528.1993 +			    unsigned long uid,long flag)
528.1994 +{
528.1995 +  char *t,stack[64];
528.1996 +  char *s = status;
528.1997 +  unsigned long n;
528.1998 +  int pad = 50;
528.1999 +  int sticky = uid ? T : !stream->uid_nosticky;
528.2000 +  /* This used to use sprintf(), but thanks to certain cretinous C libraries
528.2001 +     with horribly slow implementations of sprintf() I had to change it to this
528.2002 +     mess.  At least it should be fast. */
528.2003 +  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
528.2004 +    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
528.2005 +    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
528.2006 +    t = stack;
528.2007 +    n = stream->uid_validity;	/* push UID validity digits on the stack */
528.2008 +    do *t++ = (char) (n % 10) + '0';
528.2009 +    while (n /= 10);
528.2010 +				/* pop UID validity digits from stack */
528.2011 +    while (t > stack) *s++ = *--t;
528.2012 +    *s++ = ' ';
528.2013 +    n = stream->uid_last;	/* push UID last digits on the stack */
528.2014 +    do *t++ = (char) (n % 10) + '0';
528.2015 +    while (n /= 10);
528.2016 +				/* pop UID last digits from stack */
528.2017 +    while (t > stack) *s++ = *--t;
528.2018 +    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
528.2019 +      for (*s++ = ' '; *t; *s++ = *t++);
528.2020 +    *s++ = '\n';
528.2021 +    pad += 30;			/* increased padding if have IMAPbase */
528.2022 +  }
528.2023 +  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
528.2024 +  *s++ = ':'; *s++ = ' ';
528.2025 +  if (elt->seen) *s++ = 'R';
528.2026 +				/* only write O if have a UID */
528.2027 +  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
528.2028 +  *s++ = '\n';
528.2029 +  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
528.2030 +  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
528.2031 +  if (elt->deleted) *s++ = 'D';
528.2032 +  if (elt->flagged) *s++ = 'F';
528.2033 +  if (elt->answered) *s++ = 'A';
528.2034 +  if (elt->draft) *s++ = 'T';
528.2035 +  *s++ = '\n';
528.2036 +
528.2037 +  if (sticky) {			/* only do this if UIDs sticky */
528.2038 +    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
528.2039 +    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
528.2040 +    if (n = elt->user_flags) do {
528.2041 +      *s++ = ' ';
528.2042 +      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
528.2043 +    } while (n);
528.2044 +    n = s - status;		/* get size of stuff so far */
528.2045 +				/* pad X-Keywords to make size constant */
528.2046 +    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
528.2047 +    *s++ = '\n';
528.2048 +    if (flag) {			/* want to include UID? */
528.2049 +      t = stack;
528.2050 +				/* push UID digits on the stack */
528.2051 +      n = uid ? uid : elt->private.uid;
528.2052 +      do *t++ = (char) (n % 10) + '0';
528.2053 +      while (n /= 10);
528.2054 +      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
528.2055 +      *s++ = ' ';
528.2056 +				/* pop UID from stack */
528.2057 +      while (t > stack) *s++ = *--t;
528.2058 +      *s++ = '\n';
528.2059 +    }
528.2060 +  }
528.2061 +  *s++ = '\n'; *s = '\0';	/* end of extended message status */
528.2062 +  return s - status;		/* return size of resulting string */
528.2063 +}
528.2064 +
528.2065 +/* Rewrite mailbox file
528.2066 + * Accepts: MAIL stream, must be critical and locked
528.2067 + *	    return pointer to number of expunged messages if want expunge
528.2068 + *	    lock file name
528.2069 + *	    expunge sequence, not deleted flag
528.2070 + * Returns: T if success and mailbox unlocked, NIL if failure
528.2071 + */
528.2072 +
528.2073 +#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
528.2074 +
528.2075 +long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
528.2076 +		   long flags)
528.2077 +{
528.2078 +  MESSAGECACHE *elt;
528.2079 +  UNIXFILE f;
528.2080 +  char *s;
528.2081 +  time_t tp[2];
528.2082 +  long ret,flag;
528.2083 +  unsigned long i,j;
528.2084 +  unsigned long recent = stream->recent;
528.2085 +  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
528.2086 +  if (nexp) *nexp = 0;		/* initially nothing expunged */
528.2087 +				/* calculate size of mailbox after rewrite */
528.2088 +  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
528.2089 +    elt = mail_elt (stream,i);	/* get cache */
528.2090 +    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
528.2091 +				/* add RFC822 size of this message */
528.2092 +      size += elt->private.special.text.size + elt->private.spare.data +
528.2093 +	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
528.2094 +	  elt->private.msg.text.text.size + 1;
528.2095 +      flag = 1;			/* only count X-IMAPbase once */
528.2096 +    }
528.2097 +  }
528.2098 +				/* no messages, has a life, and no pseudo */
528.2099 +  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
528.2100 +    LOCAL->pseudo = T;		/* so make a pseudo-message now */
528.2101 +    size = unix_pseudo (stream,LOCAL->buf);
528.2102 +  }
528.2103 +				/* extend the file as necessary */
528.2104 +  if (ret = unix_extend (stream,size)) {
528.2105 +    /* Set up buffered I/O file structure
528.2106 +     * curpos	current position being written through buffering
528.2107 +     * filepos	current position being written physically to the disk
528.2108 +     * bufpos	current position being written in the buffer
528.2109 +     * protect	current maximum position that can be written to the disk
528.2110 +     *		before buffering is forced
528.2111 +     * The code tries to buffer so that that disk is written in multiples of
528.2112 +     * OVERBLOWBUFLEN bytes.
528.2113 +     */
528.2114 +    f.stream = stream;		/* note mail stream */
528.2115 +    f.curpos = f.filepos = 0;	/* start of file */
528.2116 +    f.protect = stream->nmsgs ?	/* initial protection pointer */
528.2117 +    mail_elt (stream,1)->private.special.offset : 8192;
528.2118 +    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
528.2119 +
528.2120 +    if (LOCAL->pseudo)		/* update pseudo-header */
528.2121 +      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
528.2122 +				/* loop through all messages */
528.2123 +    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
528.2124 +      elt = mail_elt (stream,i);/* get cache */
528.2125 +				/* expunge this message? */
528.2126 +      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
528.2127 +				/* one less recent message */
528.2128 +	if (elt->recent) --recent;
528.2129 +	mail_expunged(stream,i);/* notify upper levels */
528.2130 +	++*nexp;		/* count up one more expunged message */
528.2131 +      }
528.2132 +      else {			/* preserve this message */
528.2133 +	i++;			/* advance to next message */
528.2134 +	if ((flag < 0) ||	/* need to rewrite message? */
528.2135 +	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
528.2136 +	    (elt->private.msg.header.text.size !=
528.2137 +	     (elt->private.spare.data +
528.2138 +	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
528.2139 +	  unsigned long newoffset = f.curpos;
528.2140 +				/* yes, seek to internal header */
528.2141 +	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
528.2142 +	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
528.2143 +				/* see if need to squeeze out a CR */
528.2144 +	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
528.2145 +	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
528.2146 +	    --size;		/* squeezed out a CR from PC */
528.2147 +	  }
528.2148 +				/* protection pointer moves to RFC822 header */
528.2149 +	  f.protect = elt->private.special.offset +
528.2150 +	    elt->private.msg.header.offset;
528.2151 +				/* write internal header */
528.2152 +	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
528.2153 +				/* get RFC822 header */
528.2154 +	  s = unix_header (stream,elt->msgno,&j,FT_INTERNAL);
528.2155 +				/* in case this got decremented */
528.2156 +	  elt->private.msg.header.offset = elt->private.special.text.size;
528.2157 +				/* header size, sans trailing newline */
528.2158 +	  if ((j < 2) || (s[j - 2] == '\n')) j--;
528.2159 +				/* this can happen if CRs were squeezed */
528.2160 +	  if (j < elt->private.spare.data) {
528.2161 +				/* so fix up counts */
528.2162 +	    size -= elt->private.spare.data - j;
528.2163 +	    elt->private.spare.data = j;
528.2164 +	  }
528.2165 +	  else if (j != elt->private.spare.data)
528.2166 +	    fatal ("header size inconsistent");
528.2167 +				/* protection pointer moves to RFC822 text */
528.2168 +	  f.protect = elt->private.special.offset +
528.2169 +	    elt->private.msg.text.offset;
528.2170 +	  unix_write (&f,s,j);	/* write RFC822 header */
528.2171 +				/* write status and UID */
528.2172 +	  unix_write (&f,LOCAL->buf,
528.2173 +		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
528.2174 +	  flag = 1;		/* only write X-IMAPbase once */
528.2175 +				/* new file header size */
528.2176 +	  elt->private.msg.header.text.size = elt->private.spare.data + j;
528.2177 +
528.2178 +				/* did text move? */
528.2179 +	  if (f.curpos != f.protect) {
528.2180 +				/* get message text */
528.2181 +	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
528.2182 +				/* this can happen if CRs were squeezed */
528.2183 +	    if (j < elt->private.msg.text.text.size) {
528.2184 +				/* so fix up counts */
528.2185 +	      size -= elt->private.msg.text.text.size - j;
528.2186 +	      elt->private.msg.text.text.size = j;
528.2187 +	    }
528.2188 +				/* can't happen it says here */
528.2189 +	    else if (j > elt->private.msg.text.text.size)
528.2190 +	      fatal ("text size inconsistent");
528.2191 +				/* new text offset, status/UID may change it */
528.2192 +	    elt->private.msg.text.offset = f.curpos - newoffset;
528.2193 +				/* protection pointer moves to next message */
528.2194 +	    f.protect = (i <= stream->nmsgs) ?
528.2195 +	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1);
528.2196 +	    unix_write (&f,s,j);/* write text */
528.2197 +				/* write trailing newline */
528.2198 +	    unix_write (&f,"\n",1);
528.2199 +	  }
528.2200 +	  else {		/* tie off header and status */
528.2201 +	    unix_write (&f,NIL,NIL);
528.2202 +				/* protection pointer moves to next message */
528.2203 +	    f.protect = (i <= stream->nmsgs) ?
528.2204 +	      mail_elt (stream,i)->private.special.offset : size;
528.2205 +				/* locate end of message text */
528.2206 +	    j = f.filepos + elt->private.msg.text.text.size;
528.2207 +				/* trailing newline already there? */
528.2208 +	    if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
528.2209 +	    else {		/* trailing newline missing, write it */
528.2210 +	      f.curpos = f.filepos = j;
528.2211 +	      unix_write (&f,"\n",1);
528.2212 +	    }
528.2213 +	  }
528.2214 +				/* new internal header offset */
528.2215 +	  elt->private.special.offset = newoffset;
528.2216 +	  elt->private.dirty =NIL;/* message is now clean */
528.2217 +	}
528.2218 +	else {			/* no need to rewrite this message */
528.2219 +				/* tie off previous message if needed */
528.2220 +	  unix_write (&f,NIL,NIL);
528.2221 +				/* protection pointer moves to next message */
528.2222 +	  f.protect = (i <= stream->nmsgs) ?
528.2223 +	    mail_elt (stream,i)->private.special.offset : size;
528.2224 +				/* locate end of message text */
528.2225 +	  j = f.filepos + elt->private.special.text.size +
528.2226 +	    elt->private.msg.header.text.size +
528.2227 +	      elt->private.msg.text.text.size;
528.2228 +				/* trailing newline already there? */
528.2229 +	  if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
528.2230 +	  else {		/* trailing newline missing, write it */
528.2231 +	    f.curpos = f.filepos = j;
528.2232 +	    unix_write (&f,"\n",1);
528.2233 +	  }
528.2234 +	}
528.2235 +      }
528.2236 +    }
528.2237 +
528.2238 +    unix_write (&f,NIL,NIL);	/* tie off final message */
528.2239 +    if (size != f.filepos) fatal ("file size inconsistent");
528.2240 +    fs_give ((void **) &f.buf);	/* free buffer */
528.2241 +				/* make sure tied off */
528.2242 +    ftruncate (LOCAL->fd,LOCAL->filesize = size);
528.2243 +    fsync (LOCAL->fd);		/* make sure the updates take */
528.2244 +    if (size && (flag < 0)) fatal ("lost UID base information");
528.2245 +				/* no longer dirty */
528.2246 +    LOCAL->ddirty = LOCAL->dirty = NIL;
528.2247 +  				/* notify upper level of new mailbox sizes */
528.2248 +    mail_exists (stream,stream->nmsgs);
528.2249 +    mail_recent (stream,recent);
528.2250 +				/* set atime to now, mtime a second earlier */
528.2251 +    tp[1] = (tp[0] = time (0)) - 1;
528.2252 +				/* set the times, note change */
528.2253 +    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
528.2254 +    close (LOCAL->fd);		/* close and reopen file */
528.2255 +    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
528.2256 +			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
528.2257 +	< 0) {
528.2258 +      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
528.2259 +      MM_LOG (LOCAL->buf,ERROR);
528.2260 +      unix_abort (stream);
528.2261 +    }
528.2262 +    dotlock_unlock (lock);	/* flush the lock file */
528.2263 +  }
528.2264 +  return ret;			/* return state from algorithm */
528.2265 +}
528.2266 +
528.2267 +/* Extend UNIX mailbox file
528.2268 + * Accepts: MAIL stream
528.2269 + *	    new desired size
528.2270 + * Return: T if success, else NIL
528.2271 + */
528.2272 +
528.2273 +long unix_extend (MAILSTREAM *stream,unsigned long size)
528.2274 +{
528.2275 +  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
528.2276 +  if (i) {			/* does the mailbox need to grow? */
528.2277 +    if (i > LOCAL->buflen) {	/* make sure have enough space */
528.2278 +				/* this user won the lottery all right */
528.2279 +      fs_give ((void **) &LOCAL->buf);
528.2280 +      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
528.2281 +    }
528.2282 +    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
528.2283 +    while (T) {			/* until write successful or punt */
528.2284 +      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
528.2285 +      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
528.2286 +      else {
528.2287 +	long e = errno;		/* note error before doing ftruncate */
528.2288 +	ftruncate (LOCAL->fd,LOCAL->filesize);
528.2289 +	if (MM_DISKERROR (stream,e,NIL)) {
528.2290 +	  fsync (LOCAL->fd);	/* user chose to punt */
528.2291 +	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
528.2292 +	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
528.2293 +	  return NIL;
528.2294 +	}
528.2295 +      }
528.2296 +    }
528.2297 +  }
528.2298 +  return LONGT;
528.2299 +}
528.2300 +
528.2301 +/* Write data to buffered file
528.2302 + * Accepts: buffered file pointer
528.2303 + *	    file data or NIL to indicate "flush buffer"
528.2304 + *	    date size (ignored for "flush buffer")
528.2305 + * Does not return until success
528.2306 + */
528.2307 +
528.2308 +void unix_write (UNIXFILE *f,char *buf,unsigned long size)
528.2309 +{
528.2310 +  unsigned long i,j,k;
528.2311 +  if (buf) {			/* doing buffered write? */
528.2312 +    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
528.2313 +				/* yes, have space in current buffer chunk? */
528.2314 +    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
528.2315 +				/* yes, fill up buffer as much as we can */
528.2316 +      memcpy (f->bufpos,buf,k = min (j,size));
528.2317 +      f->bufpos += k;		/* new buffer position */
528.2318 +      f->curpos += k;		/* new current position */
528.2319 +      if (j -= k) return;	/* all done if still have buffer free space */
528.2320 +      buf += k;			/* full, get new unwritten data pointer */
528.2321 +      size -= k;		/* new data size */
528.2322 +      i += k;			/* new buffer data size */
528.2323 +    }
528.2324 +    /* This chunk of the buffer is full.  See if can make some space by
528.2325 +     * writing to the disk, if there's enough unprotected space to do so.
528.2326 +     * Try to fill out any unaligned chunk, along with any subsequent full
528.2327 +     * chunks that will fit in unprotected space.
528.2328 +     */
528.2329 +				/* any unprotected space we can write to? */
528.2330 +    if (j = min (i,f->protect - f->filepos)) {
528.2331 +				/* yes, filepos not at chunk boundary? */
528.2332 +      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
528.2333 +	j -= k;			/* yes, and can write out partial chunk */
528.2334 +      else k = 0;		/* no partial chunk to write */
528.2335 +				/* if at least a chunk free, write that too */
528.2336 +      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
528.2337 +      if (k) {			/* write data if there is anything we can */
528.2338 +	unix_phys_write (f,f->buf,k);
528.2339 +				/* slide buffer */
528.2340 +	if (i -= k) memmove (f->buf,f->buf + k,i);
528.2341 +	f->bufpos = f->buf + i;	/* new end of buffer */
528.2342 +      }
528.2343 +    }
528.2344 +
528.2345 +    /* Have flushed the buffer as best as possible.  All done if no more
528.2346 +     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
528.2347 +     * data is larger than a chunk AND the unprotected space is also larger
528.2348 +     * than a chunk, then write as many chunks as we can directly from the
528.2349 +     * data.  Buffer the rest, expanding the buffer as needed.
528.2350 +     */
528.2351 +    if (size) {			/* have more data that we need to buffer? */
528.2352 +				/* can write any of it to disk instead? */
528.2353 +      if ((f->bufpos == f->buf) && 
528.2354 +	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
528.2355 +				/* write as much as we can right now */
528.2356 +	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
528.2357 +	buf += j;		/* new data pointer */
528.2358 +	size -= j;		/* new data size */
528.2359 +	f->curpos += j;		/* advance current pointer */
528.2360 +      }
528.2361 +      if (size) {		/* still have data that we need to buffer? */
528.2362 +				/* yes, need to expand the buffer? */
528.2363 +	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
528.2364 +				/* note current position in buffer */
528.2365 +	  j = f->bufpos - f->buf;
528.2366 +	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
528.2367 +	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
528.2368 +				/* in case buffer relocated */
528.2369 +	  f->bufpos = f->buf + j;
528.2370 +	}
528.2371 +				/* buffer remaining data */
528.2372 +	memcpy (f->bufpos,buf,size);
528.2373 +	f->bufpos += size;	/* new end of buffer */
528.2374 +	f->curpos += size;	/* advance current pointer */
528.2375 +      }
528.2376 +    }
528.2377 +  }
528.2378 +  else {			/* flush buffer to disk */
528.2379 +    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
528.2380 +    f->bufpos = f->buf;		/* reset buffer */
528.2381 +				/* update positions */
528.2382 +    f->curpos = f->protect = f->filepos;
528.2383 +  }
528.2384 +}
528.2385 +
528.2386 +/* Physical disk write
528.2387 + * Accepts: buffered file pointer
528.2388 + *	    buffer address
528.2389 + *	    buffer size
528.2390 + * Does not return until success
528.2391 + */
528.2392 +
528.2393 +void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
528.2394 +{
528.2395 +  MAILSTREAM *stream = f->stream;
528.2396 +				/* write data at desired position */
528.2397 +  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
528.2398 +		  (write (LOCAL->fd,buf,size) < 0))) {
528.2399 +    int e;
528.2400 +    char tmp[MAILTMPLEN];
528.2401 +    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
528.2402 +    MM_LOG (tmp,ERROR);
528.2403 +    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
528.2404 +  }
528.2405 +  f->filepos += size;		/* update file position */
528.2406 +}
528.2407 +
528.2408 +/* MBOX mail routines */
528.2409 +
528.2410 +
528.2411 +/* Driver dispatch used by MAIL */
528.2412 +
528.2413 +DRIVER mboxdriver = {
528.2414 +  "mbox",			/* driver name */
528.2415 +				/* driver flags */
528.2416 +  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY,
528.2417 +  (DRIVER *) NIL,		/* next driver */
528.2418 +  mbox_valid,			/* mailbox is valid for us */
528.2419 +  unix_parameters,		/* manipulate parameters */
528.2420 +  unix_scan,			/* scan mailboxes */
528.2421 +  unix_list,			/* find mailboxes */
528.2422 +  unix_lsub,			/* find subscribed mailboxes */
528.2423 +  NIL,				/* subscribe to mailbox */
528.2424 +  NIL,				/* unsubscribe from mailbox */
528.2425 +  mbox_create,			/* create mailbox */
528.2426 +  mbox_delete,			/* delete mailbox */
528.2427 +  mbox_rename,			/* rename mailbox */
528.2428 +  mbox_status,			/* status of mailbox */
528.2429 +  mbox_open,			/* open mailbox */
528.2430 +  unix_close,			/* close mailbox */
528.2431 +  NIL,				/* fetch message "fast" attributes */
528.2432 +  NIL,				/* fetch message flags */
528.2433 +  NIL,				/* fetch overview */
528.2434 +  NIL,				/* fetch message structure */
528.2435 +  unix_header,			/* fetch message header */
528.2436 +  unix_text,			/* fetch message body */
528.2437 +  NIL,				/* fetch partial message text */
528.2438 +  NIL,				/* unique identifier */
528.2439 +  NIL,				/* message number */
528.2440 +  NIL,				/* modify flags */
528.2441 +  unix_flagmsg,			/* per-message modify flags */
528.2442 +  NIL,				/* search for message based on criteria */
528.2443 +  NIL,				/* sort messages */
528.2444 +  NIL,				/* thread messages */
528.2445 +  mbox_ping,			/* ping mailbox to see if still alive */
528.2446 +  mbox_check,			/* check for new messages */
528.2447 +  mbox_expunge,			/* expunge deleted messages */
528.2448 +  unix_copy,			/* copy messages to another mailbox */
528.2449 +  mbox_append,			/* append string message to mailbox */
528.2450 +  NIL				/* garbage collect stream */
528.2451 +};
528.2452 +
528.2453 +				/* prototype stream */
528.2454 +MAILSTREAM mboxproto = {&mboxdriver};
528.2455 +
528.2456 +/* MBOX mail validate mailbox
528.2457 + * Accepts: mailbox name
528.2458 + * Returns: our driver if name is valid, NIL otherwise
528.2459 + */
528.2460 +
528.2461 +DRIVER *mbox_valid (char *name)
528.2462 +{
528.2463 +				/* only INBOX, mbox must exist */
528.2464 +  if (!compare_cstring (name,"INBOX") && (unix_valid ("mbox") || !errno) &&
528.2465 +      (unix_valid (sysinbox()) || !errno || (errno == ENOENT)))
528.2466 +    return &mboxdriver;
528.2467 +  return NIL;			/* can't win (yet, anyway) */
528.2468 +}
528.2469 +
528.2470 +/* MBOX mail create mailbox
528.2471 + * Accepts: MAIL stream
528.2472 + *	    mailbox name to create
528.2473 + * Returns: T on success, NIL on failure
528.2474 + */
528.2475 +
528.2476 +long mbox_create (MAILSTREAM *stream,char *mailbox)
528.2477 +{
528.2478 +  char tmp[MAILTMPLEN];
528.2479 +  if (!compare_cstring (mailbox,"INBOX")) return unix_create (NIL,"mbox");
528.2480 +  sprintf (tmp,"Can't create non-INBOX name as mbox: %.80s",mailbox);
528.2481 +  MM_LOG (tmp,ERROR);
528.2482 +  return NIL;
528.2483 +}
528.2484 +
528.2485 +
528.2486 +/* MBOX mail delete mailbox
528.2487 + * Accepts: MAIL stream
528.2488 + *	    mailbox name to delete
528.2489 + * Returns: T on success, NIL on failure
528.2490 + */
528.2491 +
528.2492 +long mbox_delete (MAILSTREAM *stream,char *mailbox)
528.2493 +{
528.2494 +  return mbox_rename (stream,mailbox,NIL);
528.2495 +}
528.2496 +
528.2497 +
528.2498 +/* MBOX mail rename mailbox
528.2499 + * Accepts: MAIL stream
528.2500 + *	    old mailbox name
528.2501 + *	    new mailbox name (or NIL for delete)
528.2502 + * Returns: T on success, NIL on failure
528.2503 + */
528.2504 +
528.2505 +long mbox_rename (MAILSTREAM *stream,char *old,char *newname)
528.2506 +{
528.2507 +  char tmp[MAILTMPLEN];
528.2508 +  long ret = unix_rename (stream,"~/mbox",newname);
528.2509 +				/* recreate file if renamed INBOX */
528.2510 +  if (ret) unix_create (NIL,"mbox");
528.2511 +  else MM_LOG (tmp,ERROR);	/* log error */
528.2512 +  return ret;			/* return success */
528.2513 +}
528.2514 +
528.2515 +/* MBOX Mail status
528.2516 + * Accepts: mail stream
528.2517 + *	    mailbox name
528.2518 + *	    status flags
528.2519 + * Returns: T on success, NIL on failure
528.2520 + */
528.2521 +
528.2522 +long mbox_status (MAILSTREAM *stream,char *mbx,long flags)
528.2523 +{
528.2524 +  MAILSTATUS status;
528.2525 +  unsigned long i;
528.2526 +  MAILSTREAM *tstream = NIL;
528.2527 +  MAILSTREAM *systream = NIL;
528.2528 +				/* make temporary stream (unless this mbx) */
528.2529 +  if (!stream && !(stream = tstream =
528.2530 +		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
528.2531 +  status.flags = flags;		/* return status values */
528.2532 +  status.messages = stream->nmsgs;
528.2533 +  status.recent = stream->recent;
528.2534 +  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
528.2535 +    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
528.2536 +      if (!mail_elt (stream,i)->seen) status.unseen++;
528.2537 +  status.uidnext = stream->uid_last + 1;
528.2538 +  status.uidvalidity = stream->uid_validity;
528.2539 +  if (!status.recent &&		/* calculate post-snarf results */
528.2540 +      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
528.2541 +    status.messages += systream->nmsgs;
528.2542 +    status.recent += systream->recent;
528.2543 +    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
528.2544 +      for (i = 1; i <= systream->nmsgs; i++)
528.2545 +	if (!mail_elt (systream,i)->seen) status.unseen++;
528.2546 +				/* kludge but probably good enough */
528.2547 +    status.uidnext += systream->nmsgs;
528.2548 +  }
528.2549 +  MM_STATUS(stream,mbx,&status);/* pass status to main program */
528.2550 +  if (tstream) mail_close (tstream);
528.2551 +  if (systream) mail_close (systream);
528.2552 +  return T;			/* success */
528.2553 +}
528.2554 +
528.2555 +/* MBOX mail open
528.2556 + * Accepts: stream to open
528.2557 + * Returns: stream on success, NIL on failure
528.2558 + */
528.2559 +
528.2560 +MAILSTREAM *mbox_open (MAILSTREAM *stream)
528.2561 +{
528.2562 +  unsigned long i = 1;
528.2563 +  unsigned long recent = 0;
528.2564 +				/* return prototype for OP_PROTOTYPE call */
528.2565 +  if (!stream) return &mboxproto;
528.2566 +				/* change mailbox file name */
528.2567 +  fs_give ((void **) &stream->mailbox);
528.2568 +  stream->mailbox = cpystr ("mbox");
528.2569 +				/* open mailbox, snarf new mail */
528.2570 +  if (!(unix_open (stream) && mbox_ping (stream))) return NIL;
528.2571 +  stream->inbox = T;		/* mark that this is an INBOX */
528.2572 +				/* notify upper level of mailbox sizes */
528.2573 +  mail_exists (stream,stream->nmsgs);
528.2574 +  while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent;
528.2575 +  mail_recent (stream,recent);	/* including recent messages */
528.2576 +  return stream;
528.2577 +}
528.2578 +
528.2579 +/* MBOX mail ping mailbox
528.2580 + * Accepts: MAIL stream
528.2581 + * Returns: T if stream alive, else NIL
528.2582 + * No-op for readonly files, since read/writer can expunge it from under us!
528.2583 + */
528.2584 +
528.2585 +static int snarfed = 0;		/* number of snarfs */
528.2586 +
528.2587 +long mbox_ping (MAILSTREAM *stream)
528.2588 +{
528.2589 +  int sfd;
528.2590 +  unsigned long size;
528.2591 +  struct stat sbuf;
528.2592 +  char *s;
528.2593 +  DOTLOCK lock,lockx;
528.2594 +				/* time to try snarf and sysinbox non-empty? */
528.2595 +  if (LOCAL && !stream->rdonly && !stream->lock &&
528.2596 +      (time (0) >= (LOCAL->lastsnarf +
528.2597 +		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
528.2598 +      !stat (sysinbox (),&sbuf) && sbuf.st_size) {
528.2599 +    MM_CRITICAL (stream);	/* yes, go critical */
528.2600 +				/* open and lock sysinbox */
528.2601 +    if ((sfd = unix_lock (sysinbox (),O_RDWR,
528.2602 +			  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
528.2603 +			  &lockx,LOCK_EX)) >= 0) {
528.2604 +				/* locked sysinbox in good format? */
528.2605 +      if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) ||
528.2606 +	  !unix_isvalid_fd (sfd)) {
528.2607 +	sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format",
528.2608 +		 sysinbox ());
528.2609 +	MM_LOG (LOCAL->buf,ERROR);
528.2610 +      }
528.2611 +				/* sysinbox good, parse and excl-lock mbox */
528.2612 +      else if (unix_parse (stream,&lock,LOCK_EX)) {
528.2613 +	lseek (sfd,0,L_SET);	/* read entire sysinbox into memory */
528.2614 +	read (sfd,s = (char *) fs_get (size + 1),size);
528.2615 +	s[size] = '\0';		/* tie it off */
528.2616 +				/* append to end of mbox */
528.2617 +	lseek (LOCAL->fd,LOCAL->filesize,L_SET);
528.2618 +
528.2619 +				/* copy to mbox */
528.2620 +	if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) {
528.2621 +	  sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno));
528.2622 +	  MM_LOG (LOCAL->buf,WARN);
528.2623 +				/* revert mbox to previous size */
528.2624 +	  ftruncate (LOCAL->fd,LOCAL->filesize);
528.2625 +	}
528.2626 +				/* sysinbox better not have changed */
528.2627 +	else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) {
528.2628 +	  sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu",
528.2629 +		   sysinbox (),size,(unsigned long) sbuf.st_size);
528.2630 +	  MM_LOG (LOCAL->buf,ERROR);
528.2631 +				/* revert mbox to previous size */
528.2632 +	  ftruncate (LOCAL->fd,LOCAL->filesize);
528.2633 +	  /* Believe it or not, a Singaporean government system actually had
528.2634 +	   * symlinks from /var/mail/user to ~user/mbox.  To compound this
528.2635 +	   * error, they used an SVR4 system; BSD and OSF locks would have
528.2636 +	   * prevented it but not SVR4 locks.
528.2637 +	   */
528.2638 +	  if (!fstat (sfd,&sbuf) && (size == sbuf.st_size))
528.2639 +	    syslog (LOG_ALERT,"File %s and %s are the same file!",
528.2640 +		    sysinbox (),stream->mailbox);
528.2641 +	}
528.2642 +	else {			/* data copied OK */
528.2643 +	  ftruncate (sfd,0);	/* truncate sysinbox to zero bytes */
528.2644 +	  if (!snarfed++) {	/* have we snarfed before? */
528.2645 +				/* syslog if server, else user log */
528.2646 +	    sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s",
528.2647 +		     size,stream->mailbox,sysinbox ());
528.2648 +	    if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
528.2649 +			"unknown"))
528.2650 +	      syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ());
528.2651 +	    else MM_LOG (LOCAL->buf,WARN);
528.2652 +	  }
528.2653 +	}
528.2654 +				/* done with sysinbox text */
528.2655 +	fs_give ((void **) &s);
528.2656 +				/* all done with mbox */
528.2657 +	unix_unlock (LOCAL->fd,stream,&lock);
528.2658 +	mail_unlock (stream);	/* unlock the stream */
528.2659 +	MM_NOCRITICAL (stream);	/* done with critical */
528.2660 +      }
528.2661 +				/* all done with sysinbox */
528.2662 +      unix_unlock (sfd,NIL,&lockx);
528.2663 +    }
528.2664 +    MM_NOCRITICAL (stream);	/* done with critical */
528.2665 +    LOCAL->lastsnarf = time (0);/* note time of last snarf */
528.2666 +  }
528.2667 +  return unix_ping (stream);	/* do the unix routine now */
528.2668 +}
528.2669 +
528.2670 +/* MBOX mail check mailbox
528.2671 + * Accepts: MAIL stream
528.2672 + */
528.2673 +
528.2674 +void mbox_check (MAILSTREAM *stream)
528.2675 +{
528.2676 +				/* do local ping, then do unix routine */
528.2677 +  if (mbox_ping (stream)) unix_check (stream);
528.2678 +}
528.2679 +
528.2680 +
528.2681 +/* MBOX mail expunge mailbox
528.2682 + * Accepts: MAIL stream
528.2683 + *	    sequence to expunge if non-NIL
528.2684 + *	    expunge options
528.2685 + * Returns: T, always
528.2686 + */
528.2687 +
528.2688 +long mbox_expunge (MAILSTREAM *stream,char *sequence,long options)
528.2689 +{
528.2690 +  long ret = unix_expunge (stream,sequence,options);
528.2691 +  mbox_ping (stream);		/* do local ping */
528.2692 +  return ret;
528.2693 +}
528.2694 +
528.2695 +
528.2696 +/* MBOX mail append message from stringstruct
528.2697 + * Accepts: MAIL stream
528.2698 + *	    destination mailbox
528.2699 + *	    append callback
528.2700 + *	    data for callback
528.2701 + * Returns: T if append successful, else NIL
528.2702 + */
528.2703 +
528.2704 +long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
528.2705 +{
528.2706 +  char tmp[MAILTMPLEN];
528.2707 +  if (mbox_valid (mailbox)) return unix_append (stream,"mbox",af,data);
528.2708 +  sprintf (tmp,"Can't append to that name: %.80s",mailbox);
528.2709 +  MM_LOG (tmp,ERROR);
528.2710 +  return NIL;
528.2711 +}
   529.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   529.2 +++ b/src/osdep/unix/unix.h	Mon Sep 14 15:17:45 2009 +0900
   529.3 @@ -0,0 +1,161 @@
   529.4 +/* ========================================================================
   529.5 + * Copyright 1988-2006 University of Washington
   529.6 + *
   529.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   529.8 + * you may not use this file except in compliance with the License.
   529.9 + * You may obtain a copy of the License at
  529.10 + *
  529.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  529.12 + *
  529.13 + * 
  529.14 + * ========================================================================
  529.15 + */
  529.16 +
  529.17 +/*
  529.18 + * Program:	UNIX mail routines
  529.19 + *
  529.20 + * Author:	Mark Crispin
  529.21 + *		Networks and Distributed Computing
  529.22 + *		Computing & Communications
  529.23 + *		University of Washington
  529.24 + *		Administration Building, AG-44
  529.25 + *		Seattle, WA  98195
  529.26 + *		Internet: MRC@CAC.Washington.EDU
  529.27 + *
  529.28 + * Date:	20 December 1989
  529.29 + * Last Edited:	30 August 2006
  529.30 + */
  529.31 +
  529.32 +
  529.33 +/*				DEDICATION
  529.34 + *
  529.35 + *  This file is dedicated to my dog, Unix, also known as Yun-chan and
  529.36 + * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
  529.37 + * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
  529.38 + * a two-month bout with cirrhosis of the liver.
  529.39 + *
  529.40 + *  He was a dear friend, and I miss him terribly.
  529.41 + *
  529.42 + *  Lift a leg, Yunie.  Luv ya forever!!!!
  529.43 + */
  529.44 +
  529.45 +/* Validate line
  529.46 + * Accepts: pointer to candidate string to validate as a From header
  529.47 + *	    return pointer to end of date/time field
  529.48 + *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  529.49 + *	    return pointer to offset from t of time zone (if non-zero)
  529.50 + * Returns: t,ti,zn set if valid From string, else ti is NIL
  529.51 + */
  529.52 +
  529.53 +#define VALID(s,x,ti,zn) {						\
  529.54 +  ti = 0;								\
  529.55 +  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
  529.56 +      (s[4] == ' ')) {							\
  529.57 +    for (x = s + 5; *x && *x != '\012'; x++);				\
  529.58 +    if (*x) {								\
  529.59 +      if (x[-1] == '\015') --x;						\
  529.60 +      if (x - s >= 41) {						\
  529.61 +	for (zn = -1; x[zn] != ' '; zn--);				\
  529.62 +	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
  529.63 +	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
  529.64 +	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
  529.65 +	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
  529.66 +	  x += zn - 12;							\
  529.67 +      }									\
  529.68 +      if (x - s >= 27) {						\
  529.69 +	if (x[-5] == ' ') {						\
  529.70 +	  if (x[-8] == ':') zn = 0,ti = -5;				\
  529.71 +	  else if (x[-9] == ' ') ti = zn = -9;				\
  529.72 +	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
  529.73 +	    ti = zn = -11;						\
  529.74 +	}								\
  529.75 +	else if (x[-4] == ' ') {					\
  529.76 +	  if (x[-9] == ' ') zn = -4,ti = -9;				\
  529.77 +	}								\
  529.78 +	else if (x[-6] == ' ') {					\
  529.79 +	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
  529.80 +	    zn = -6,ti = -11;						\
  529.81 +	}								\
  529.82 +	if (ti && !((x[ti - 3] == ':') &&				\
  529.83 +		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
  529.84 +		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
  529.85 +		    (x[ti - 11] == ' '))) ti = 0;			\
  529.86 +      }									\
  529.87 +    }									\
  529.88 +  }									\
  529.89 +}
  529.90 +
  529.91 +/* You are not expected to understand this macro, but read the next page if
  529.92 + * you are not faint of heart.
  529.93 + *
  529.94 + * Known formats to the VALID macro are:
  529.95 + *		From user Wed Dec  2 05:53 1992
  529.96 + * BSD		From user Wed Dec  2 05:53:22 1992
  529.97 + * SysV		From user Wed Dec  2 05:53 PST 1992
  529.98 + * rn		From user Wed Dec  2 05:53:22 PST 1992
  529.99 + *		From user Wed Dec  2 05:53 -0700 1992
 529.100 + * emacs	From user Wed Dec  2 05:53:22 -0700 1992
 529.101 + *		From user Wed Dec  2 05:53 1992 PST
 529.102 + *		From user Wed Dec  2 05:53:22 1992 PST
 529.103 + *		From user Wed Dec  2 05:53 1992 -0700
 529.104 + * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
 529.105 + *
 529.106 + * Plus all of the above with `` remote from xxx'' after it. Thank you very
 529.107 + * much, smail and Solaris, for making my life considerably more complicated.
 529.108 + */
 529.109 +
 529.110 +/*
 529.111 + * What?  You want to understand the VALID macro anyway?  Alright, since you
 529.112 + * insist.  Actually, it isn't really all that difficult, provided that you
 529.113 + * take it step by step.
 529.114 + *
 529.115 + * Line 1	Initializes the return ti value to failure (0);
 529.116 + * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
 529.117 + * Lines 4-6	Validates that there is an end of line and points x at it.
 529.118 + * Lines 7-14	First checks to see if the line is at least 41 characters long.
 529.119 + *		If so, it scans backwards to find the rightmost space.  From
 529.120 + *		that point, it scans backwards to see if the string matches
 529.121 + *		`` remote from''.  If so, it sets x to point to the space at
 529.122 + *		the start of the string.
 529.123 + * Line 15	Makes sure that there are at least 27 characters in the line.
 529.124 + * Lines 16-21	Checks if the date/time ends with the year (there is a space
 529.125 + *		five characters back).  If there is a colon three characters
 529.126 + *		further back, there is no timezone field, so zn is set to 0
 529.127 + *		and ti is set in front of the year.  Otherwise, there must
 529.128 + *		either to be a space four characters back for a three-letter
 529.129 + *		timezone, or a space six characters back followed by a + or -
 529.130 + *		for a numeric timezone; in either case, zn and ti become the
 529.131 + *		offset of the space immediately before it.
 529.132 + * Lines 22-24	Are the failure case for line 14.  If there is a space four
 529.133 + *		characters back, it is a three-letter timezone; there must be a
 529.134 + *		space for the year nine characters back.  zn is the zone
 529.135 + *		offset; ti is the offset of the space.
 529.136 + * Lines 25-28	Are the failure case for line 20.  If there is a space six
 529.137 + *		characters back, it is a numeric timezone; there must be a
 529.138 + *		space eleven characters back and a + or - five characters back.
 529.139 + *		zn is the zone offset; ti is the offset of the space.
 529.140 + * Line 29-32	If ti is valid, make sure that the string before ti is of the
 529.141 + *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
 529.142 + *		invalidate ti.  There must be a colon three characters back
 529.143 + *		and a space six or nine	characters back (depending upon
 529.144 + *		whether or not the character six characters back is a colon).
 529.145 + *		There must be a space three characters further back (in front
 529.146 + *		of the day), one seven characters back (in front of the month),
 529.147 + *		and one eleven characters back (in front of the day of week).
 529.148 + *		ti is set to be the offset of the space before the time.
 529.149 + *
 529.150 + * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
 529.151 + * newer pipelined machines it is faster being open-coded than it would be if
 529.152 + * subroutines are called.
 529.153 + *
 529.154 + * Why does it scan backwards from the end of the line, instead of doing the
 529.155 + * much easier forward scan?  There is no deterministic way to parse the
 529.156 + * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
 529.157 + * see if unquoted spaces were possible.  They are, and I've encountered enough
 529.158 + * evil mail to be totally unwilling to trust that ``it will never happen''.
 529.159 + */
 529.160 +
 529.161 +/* Build parameters */
 529.162 +
 529.163 +#define KODRETRY 15		/* kiss-of-death retry in seconds */
 529.164 +#define LOCKTIMEOUT 5		/* lock timeout in minutes */
   530.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   530.2 +++ b/src/osdep/unix/utime.c	Mon Sep 14 15:17:45 2009 +0900
   530.3 @@ -0,0 +1,45 @@
   530.4 +/* ========================================================================
   530.5 + * Copyright 1988-2006 University of Washington
   530.6 + *
   530.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   530.8 + * you may not use this file except in compliance with the License.
   530.9 + * You may obtain a copy of the License at
  530.10 + *
  530.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  530.12 + *
  530.13 + * 
  530.14 + * ========================================================================
  530.15 + */
  530.16 +
  530.17 +/*
  530.18 + * Program:	BSD utime() emulator
  530.19 + *
  530.20 + * Author:	Mark Crispin
  530.21 + *		Networks and Distributed Computing
  530.22 + *		Computing & Communications
  530.23 + *		University of Washington
  530.24 + *		Administration Building, AG-44
  530.25 + *		Seattle, WA  98195
  530.26 + *		Internet: MRC@CAC.Washington.EDU
  530.27 + *
  530.28 + * Date:	10 October 1996
  530.29 + * Last Edited:	30 August 2006
  530.30 + */
  530.31 +
  530.32 +#undef utime
  530.33 +
  530.34 +/* Portable utime() that takes it args like real Unix systems
  530.35 + * Accepts: file path
  530.36 + *	    traditional utime() argument
  530.37 + * Returns: utime() results
  530.38 + */
  530.39 +
  530.40 +int portable_utime (char *file,time_t timep[2])
  530.41 +{
  530.42 +  struct utimbuf times;
  530.43 +				/* in case there's other cruft there */
  530.44 +  memset (&times,0,sizeof (struct utimbuf));
  530.45 +  times.actime = timep[0];	/* copy the portable values */
  530.46 +  times.modtime = timep[1];
  530.47 +  return utime (file,&times);	/* now call the SVR4 routine */
  530.48 +}
   531.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   531.2 +++ b/src/osdep/unix/write.c	Mon Sep 14 15:17:45 2009 +0900
   531.3 @@ -0,0 +1,59 @@
   531.4 +/* ========================================================================
   531.5 + * Copyright 1988-2006 University of Washington
   531.6 + *
   531.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   531.8 + * you may not use this file except in compliance with the License.
   531.9 + * You may obtain a copy of the License at
  531.10 + *
  531.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  531.12 + *
  531.13 + * 
  531.14 + * ========================================================================
  531.15 + */
  531.16 +
  531.17 +/*
  531.18 + * Program:	Write data, treating partial writes as an error
  531.19 + *
  531.20 + * Author:	Mark Crispin
  531.21 + *		Networks and Distributed Computing
  531.22 + *		Computing & Communications
  531.23 + *		University of Washington
  531.24 + *		Administration Building, AG-44
  531.25 + *		Seattle, WA  98195
  531.26 + *		Internet: MRC@CAC.Washington.EDU
  531.27 + *
  531.28 + * Date:	26 May 1995
  531.29 + * Last Edited:	30 August 2006
  531.30 + */
  531.31 +
  531.32 +/*  The whole purpose of this unfortunate routine is to deal with DOS and
  531.33 + * certain cretinous versions of UNIX which decided that the "bytes actually
  531.34 + * written" return value from write() gave them license to use that for things
  531.35 + * that are really errors, such as disk quota exceeded, maximum file size
  531.36 + * exceeded, disk full, etc.
  531.37 + * 
  531.38 + *  BSD won't screw us this way on the local filesystem, but who knows what
  531.39 + * some NFS-mounted filesystem will do.
  531.40 + */
  531.41 +
  531.42 +#undef write
  531.43 +
  531.44 +/* Write data to file
  531.45 + * Accepts: file descriptor
  531.46 + *	    I/O vector structure
  531.47 + *	    number of vectors in structure
  531.48 + * Returns: number of bytes written if successful, -1 if failure
  531.49 + */
  531.50 +
  531.51 +long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
  531.52 +
  531.53 +long safe_write (int fd,char *buf,long nbytes)
  531.54 +{
  531.55 +  long i,j;
  531.56 +  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
  531.57 +    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
  531.58 +	   (errno == EINTR));
  531.59 +    if (j < 0) return j;
  531.60 +  }
  531.61 +  return nbytes;
  531.62 +}
   532.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   532.2 +++ b/src/osdep/vms/build.com	Mon Sep 14 15:17:45 2009 +0900
   532.3 @@ -0,0 +1,99 @@
   532.4 +$! ========================================================================
   532.5 +$! Copyright 1988-2006 University of Washington
   532.6 +$!
   532.7 +$! Licensed under the Apache License, Version 2.0 (the "License");
   532.8 +$! you may not use this file except in compliance with the License.
   532.9 +$! You may obtain a copy of the License at
  532.10 +$!
  532.11 +$!     http://www.apache.org/licenses/LICENSE-2.0
  532.12 +$!
  532.13 +$! 
  532.14 +$! ========================================================================
  532.15 +$!
  532.16 +$! Program:	Portable c-client build for VMS
  532.17 +$!
  532.18 +$! Author:	Mark Crispin
  532.19 +$!		Networks and Distributed Computing
  532.20 +$!		Computing & Communications
  532.21 +$!		University of Washington
  532.22 +$!		Administration Building, AG-44
  532.23 +$!		Seattle, WA  98195
  532.24 +$!		Internet: MRC@CAC.Washington.EDU
  532.25 +$!
  532.26 +$! Date:	2 August 1994
  532.27 +$! Last Edited:	30 August 2006
  532.28 +$!
  532.29 +$!  Change this to your local timezone.  This value is the number of minutes
  532.30 +$! east of UTC (formerly known as GMT).  Sample values: -300 (US east coast),
  532.31 +$! -480 (US west coast), 540 (Japan), 60 (western Europe).
  532.32 +$!  VAX C's HELP information says that you should be able to use gmtime(), but
  532.33 +$! it returns 0 for the struct.  ftime(), you ask?  It, too, returns 0 for a
  532.34 +$! timezone.  Nothing sucks like a VAX!
  532.35 +$!
  532.36 +$ CC_TIMEZONE=-480
  532.37 +$!
  532.38 +$! CC options
  532.39 +$!
  532.40 +$ CC_PREF = "/OPTIMIZE/INCLUDE=[]"
  532.41 +$ CC_PREF = CC_PREF + "/DEFINE=net_getbuffer=NET_GETBUF"
  532.42 +$ CC_PREF = CC_PREF + "/DEFINE=LOCALTIMEZONE='CC_TIMEZONE'"
  532.43 +$!
  532.44 +$! Determine TCP type
  532.45 +$!
  532.46 +$ TCP_TYPE = "VMSN"		! default to none
  532.47 +$ IF F$LOCATE("MULTINET", P1) .LT. F$LENGTH(P1)
  532.48 +$ THEN
  532.49 +$	DEFINE SYS MULTINET_ROOT:[MULTINET.INCLUDE.SYS],sys$library
  532.50 +$	DEFINE NETINET MULTINET_ROOT:[MULTINET.INCLUDE.NETINET]
  532.51 +$	DEFINE ARPA MULTINET_ROOT:[MULTINET.INCLUDE.ARPA]
  532.52 +$	TCP_TYPE = "VMSM"	! Multinet
  532.53 +$	LINK_OPT = ",LINK_MNT/OPTION"
  532.54 +$ ENDIF
  532.55 +$ IF F$LOCATE("NETLIB", P1) .LT. F$LENGTH(P1)
  532.56 +$ THEN
  532.57 +$	DEFINE SYS SYS$LIBRARY:	! normal .H location
  532.58 +$	DEFINE NETINET SYS$LIBRARY:
  532.59 +$	DEFINE ARPA SYS$LIBRARY:
  532.60 +$	LINK_OPT = ",LINK_NLB/OPTION"
  532.61 +$	TCP_TYPE = "VMSL"	! NETLIB
  532.62 +$ ENDIF
  532.63 +$ IF TCP_TYPE .EQS. "VMSN"
  532.64 +$ THEN
  532.65 +$	DEFINE SYS SYS$LIBRARY:	! normal .H location
  532.66 +$	DEFINE NETINET SYS$LIBRARY:
  532.67 +$	DEFINE ARPA SYS$LIBRARY:
  532.68 +$	LINK_OPT = ""
  532.69 +$ ENDIF
  532.70 +$!
  532.71 +$ COPY TCP_'TCP_TYPE'.C TCP_VMS.C;
  532.72 +$!
  532.73 +$ COPY OS_VMS.H OSDEP.H;
  532.74 +$ SET VERIFY
  532.75 +$ CC'CC_PREF' MAIL
  532.76 +$ CC'CC_PREF' IMAP4R1
  532.77 +$ CC'CC_PREF' SMTP
  532.78 +$ CC'CC_PREF' NNTP
  532.79 +$ CC'CC_PREF' POP3
  532.80 +$ CC'CC_PREF' DUMMYVMS
  532.81 +$ CC'CC_PREF' RFC822
  532.82 +$ CC'CC_PREF' MISC
  532.83 +$ CC'CC_PREF' OS_VMS
  532.84 +$ CC'CC_PREF' SMANAGER
  532.85 +$ CC'CC_PREF' FLSTRING
  532.86 +$ CC'CC_PREF' NEWSRC
  532.87 +$ CC'CC_PREF' NETMSG
  532.88 +$ CC'CC_PREF' UTF8
  532.89 +$ CC'CC_PREF' UTF8AUX
  532.90 +$ CC'CC_PREF' MTEST
  532.91 +$ CC'CC_PREF' MAILUTIL
  532.92 +$!
  532.93 +$ LINK MTEST,OS_VMS,MAIL,IMAP4R1,SMTP,NNTP,POP3,DUMMYVMS,RFC822,MISC,UTF8,-
  532.94 +	UTF8AUX,SMANAGER,FLSTRING,NEWSRC,NETMSG,-
  532.95 +	SYS$INPUT:/OPTION'LINK_OPT',LINK/OPTION
  532.96 +PSECT=_CTYPE_,NOWRT
  532.97 +$ LINK MAILUTIL,OS_VMS,MAIL,IMAP4R1,SMTP,NNTP,POP3,DUMMYVMS,RFC822,MISC,UTF8,-
  532.98 +	UTF8AUX,SMANAGER,FLSTRING,NEWSRC,NETMSG,-
  532.99 +	SYS$INPUT:/OPTION'LINK_OPT',LINK/OPTION
 532.100 +PSECT=_CTYPE_,NOWRT
 532.101 +$ SET NOVERIFY
 532.102 +$ EXIT
   533.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   533.2 +++ b/src/osdep/vms/clean.com	Mon Sep 14 15:17:45 2009 +0900
   533.3 @@ -0,0 +1,26 @@
   533.4 +$! ========================================================================
   533.5 +$! Copyright 1988-2006 University of Washington
   533.6 +$!
   533.7 +$! Licensed under the Apache License, Version 2.0 (the "License");
   533.8 +$! you may not use this file except in compliance with the License.
   533.9 +$! You may obtain a copy of the License at
  533.10 +$!
  533.11 +$!     http://www.apache.org/licenses/LICENSE-2.0
  533.12 +$!
  533.13 +$! 
  533.14 +$! ========================================================================
  533.15 +$!
  533.16 +$! Program:	Portable c-client cleanup for VMS
  533.17 +$!
  533.18 +$! Author:	Mark Crispin
  533.19 +$!		Networks and Distributed Computing
  533.20 +$!		Computing & Communications
  533.21 +$!		University of Washington
  533.22 +$!		Administration Building, AG-44
  533.23 +$!		Seattle, WA  98195
  533.24 +$!		Internet: MRC@CAC.Washington.EDU
  533.25 +$!
  533.26 +$! Date:	14 June 1995
  533.27 +$! Last Edited:	30 August 2006
  533.28 +$!
  533.29 +$ DELETE *.OBJ;*,OSDEP.*;*,TCP_VMS.C;*,MTEST.EXE;*,MAILUTIL.EXE;*
   534.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   534.2 +++ b/src/osdep/vms/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   534.3 @@ -0,0 +1,43 @@
   534.4 +/* ========================================================================
   534.5 + * Copyright 1988-2006 University of Washington
   534.6 + *
   534.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   534.8 + * you may not use this file except in compliance with the License.
   534.9 + * You may obtain a copy of the License at
  534.10 + *
  534.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  534.12 + *
  534.13 + * 
  534.14 + * ========================================================================
  534.15 + */
  534.16 +
  534.17 +/*
  534.18 + * Program:	Dummy routines
  534.19 + *
  534.20 + * Author:	Mark Crispin
  534.21 + *		Networks and Distributed Computing
  534.22 + *		Computing & Communications
  534.23 + *		University of Washington
  534.24 + *		Administration Building, AG-44
  534.25 + *		Seattle, WA  98195
  534.26 + *		Internet: MRC@CAC.Washington.EDU
  534.27 + *
  534.28 + * Date:	9 May 1991
  534.29 + * Last Edited:	30 August 2006
  534.30 + */
  534.31 +
  534.32 +/* Exported function prototypes */
  534.33 +
  534.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  534.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  534.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  534.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  534.38 +		    unsigned long csiz,unsigned long fsiz);
  534.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  534.40 +			  unsigned long fsiz);
  534.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  534.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  534.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  534.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  534.45 +char *dummy_file (char *dst,char *name);
  534.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   535.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   535.2 +++ b/src/osdep/vms/dummyvms.c	Mon Sep 14 15:17:45 2009 +0900
   535.3 @@ -0,0 +1,295 @@
   535.4 +/* ========================================================================
   535.5 + * Copyright 1988-2006 University of Washington
   535.6 + *
   535.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   535.8 + * you may not use this file except in compliance with the License.
   535.9 + * You may obtain a copy of the License at
  535.10 + *
  535.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  535.12 + *
  535.13 + * 
  535.14 + * ========================================================================
  535.15 + */
  535.16 +
  535.17 +/*
  535.18 + * Program:	Dummy routines for VMS
  535.19 + *
  535.20 + * Author:	Mark Crispin
  535.21 + *		Networks and Distributed Computing
  535.22 + *		Computing & Communications
  535.23 + *		University of Washington
  535.24 + *		Administration Building, AG-44
  535.25 + *		Seattle, WA  98195
  535.26 + *		Internet: MRC@CAC.Washington.EDU
  535.27 + *
  535.28 + * Date:	24 May 1993
  535.29 + * Last Edited:	30 August 2006
  535.30 + */
  535.31 +
  535.32 +
  535.33 +#include <ctype.h>
  535.34 +#include <stdio.h>
  535.35 +#include "mail.h"
  535.36 +#include "osdep.h"
  535.37 +#include "dummy.h"
  535.38 +#include "misc.h"
  535.39 +
  535.40 +/* Function prototypes */
  535.41 +
  535.42 +DRIVER *dummy_valid (char *name);
  535.43 +void *dummy_parameters (long function,void *value);
  535.44 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  535.45 +void dummy_close (MAILSTREAM *stream,long options);
  535.46 +long dummy_ping (MAILSTREAM *stream);
  535.47 +void dummy_check (MAILSTREAM *stream);
  535.48 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  535.49 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  535.50 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  535.51 +
  535.52 +/* Dummy routines */
  535.53 +
  535.54 +
  535.55 +/* Driver dispatch used by MAIL */
  535.56 +
  535.57 +DRIVER dummydriver = {
  535.58 +  "dummy",			/* driver name */
  535.59 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  535.60 +  (DRIVER *) NIL,		/* next driver */
  535.61 +  dummy_valid,			/* mailbox is valid for us */
  535.62 +  dummy_parameters,		/* manipulate parameters */
  535.63 +  dummy_scan,			/* scan mailboxes */
  535.64 +  dummy_list,			/* list mailboxes */
  535.65 +  dummy_lsub,			/* list subscribed mailboxes */
  535.66 +  NIL,				/* subscribe to mailbox */
  535.67 +  NIL,				/* unsubscribe from mailbox */
  535.68 +  dummy_create,			/* create mailbox */
  535.69 +  dummy_delete,			/* delete mailbox */
  535.70 +  dummy_rename,			/* rename mailbox */
  535.71 +  mail_status_default,		/* status of mailbox */
  535.72 +  dummy_open,			/* open mailbox */
  535.73 +  dummy_close,			/* close mailbox */
  535.74 +  NIL,				/* fetch message "fast" attributes */
  535.75 +  NIL,				/* fetch message flags */
  535.76 +  NIL,				/* fetch overview */
  535.77 +  NIL,				/* fetch message structure */
  535.78 +  NIL,				/* fetch header */
  535.79 +  NIL,				/* fetch text */
  535.80 +  NIL,				/* fetch message data */
  535.81 +  NIL,				/* unique identifier */
  535.82 +  NIL,				/* message number from UID */
  535.83 +  NIL,				/* modify flags */
  535.84 +  NIL,				/* per-message modify flags */
  535.85 +  NIL,				/* search for message based on criteria */
  535.86 +  NIL,				/* sort messages */
  535.87 +  NIL,				/* thread messages */
  535.88 +  dummy_ping,			/* ping mailbox to see if still alive */
  535.89 +  dummy_check,			/* check for new messages */
  535.90 +  dummy_expunge,		/* expunge deleted messages */
  535.91 +  dummy_copy,			/* copy messages to another mailbox */
  535.92 +  dummy_append,			/* append string message to mailbox */
  535.93 +  NIL				/* garbage collect stream */
  535.94 +};
  535.95 +
  535.96 +
  535.97 +				/* prototype stream */
  535.98 +MAILSTREAM dummyproto = {&dummydriver};
  535.99 +
 535.100 +/* Dummy validate mailbox
 535.101 + * Accepts: mailbox name
 535.102 + * Returns: our driver if name is valid, NIL otherwise
 535.103 + */
 535.104 +
 535.105 +DRIVER *dummy_valid (char *name)
 535.106 +{
 535.107 +  char tmp[MAILTMPLEN];
 535.108 +				/* must be valid local mailbox */
 535.109 +  return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ?
 535.110 +    &dummydriver : NIL;
 535.111 +}
 535.112 +
 535.113 +
 535.114 +/* Dummy manipulate driver parameters
 535.115 + * Accepts: function code
 535.116 + *	    function-dependent value
 535.117 + * Returns: function-dependent return value
 535.118 + */
 535.119 +
 535.120 +void *dummy_parameters (long function,void *value)
 535.121 +{
 535.122 +  return NIL;
 535.123 +}
 535.124 +
 535.125 +/* Dummy scan mailboxes
 535.126 + * Accepts: mail stream
 535.127 + *	    reference
 535.128 + *	    pattern to search
 535.129 + *	    string to scan
 535.130 + */
 535.131 +
 535.132 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 535.133 +{
 535.134 +				/* return silently */
 535.135 +}
 535.136 +
 535.137 +
 535.138 +/* Dummy list mailboxes
 535.139 + * Accepts: mail stream
 535.140 + *	    reference
 535.141 + *	    pattern to search
 535.142 + */
 535.143 +
 535.144 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 535.145 +{
 535.146 +				/* return silently */
 535.147 +}
 535.148 +
 535.149 +
 535.150 +/* Dummy list subscribed mailboxes
 535.151 + * Accepts: mail stream
 535.152 + *	    reference
 535.153 + *	    pattern to search
 535.154 + */
 535.155 +
 535.156 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 535.157 +{
 535.158 +				/* return silently */
 535.159 +}
 535.160 +
 535.161 +/* Dummy create mailbox
 535.162 + * Accepts: mail stream
 535.163 + *	    mailbox name to create
 535.164 + *	    driver type to use
 535.165 + * Returns: T on success, NIL on failure
 535.166 + */
 535.167 +
 535.168 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 535.169 +{
 535.170 +  return NIL;			/* always fails */
 535.171 +}
 535.172 +
 535.173 +
 535.174 +/* Dummy delete mailbox
 535.175 + * Accepts: mail stream
 535.176 + *	    mailbox name to delete
 535.177 + * Returns: T on success, NIL on failure
 535.178 + */
 535.179 +
 535.180 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 535.181 +{
 535.182 +  return NIL;			/* always fails */
 535.183 +}
 535.184 +
 535.185 +
 535.186 +/* Mail rename mailbox
 535.187 + * Accepts: mail stream
 535.188 + *	    old mailbox name
 535.189 + *	    new mailbox name
 535.190 + * Returns: T on success, NIL on failure
 535.191 + */
 535.192 +
 535.193 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 535.194 +{
 535.195 +  return NIL;			/* always fails */
 535.196 +}
 535.197 +
 535.198 +/* Dummy open
 535.199 + * Accepts: stream to open
 535.200 + * Returns: stream on success, NIL on failure
 535.201 + */
 535.202 +
 535.203 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 535.204 +{
 535.205 +  char tmp[MAILTMPLEN];
 535.206 +				/* OP_PROTOTYPE call or silence */
 535.207 +  if (!stream || stream->silent) return NIL;
 535.208 +  if (compare_cstring (stream->mailbox,"INBOX")) {
 535.209 +    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
 535.210 +    mm_log (tmp,ERROR);
 535.211 +    return NIL;			/* always fails */
 535.212 +  }
 535.213 +  if (!stream->silent) {	/* only if silence not requested */
 535.214 +    mail_exists (stream,0);	/* say there are 0 messages */
 535.215 +    mail_recent (stream,0);
 535.216 +    stream->uid_validity = time (0);
 535.217 +  }
 535.218 +  stream->inbox = T;		/* note that it's an INBOX */
 535.219 +  return stream;		/* return success */
 535.220 +}
 535.221 +
 535.222 +
 535.223 +/* Dummy close
 535.224 + * Accepts: MAIL stream
 535.225 + *	    options
 535.226 + */
 535.227 +
 535.228 +void dummy_close (MAILSTREAM *stream,long options)
 535.229 +{
 535.230 +				/* return silently */
 535.231 +}
 535.232 +
 535.233 +/* Dummy ping mailbox
 535.234 + * Accepts: MAIL stream
 535.235 + * Returns: T if stream alive, else NIL
 535.236 + * No-op for readonly files, since read/writer can expunge it from under us!
 535.237 + */
 535.238 +
 535.239 +long dummy_ping (MAILSTREAM *stream)
 535.240 +{
 535.241 +  return T;
 535.242 +}
 535.243 +
 535.244 +
 535.245 +/* Dummy check mailbox
 535.246 + * Accepts: MAIL stream
 535.247 + * No-op for readonly files, since read/writer can expunge it from under us!
 535.248 + */
 535.249 +
 535.250 +void dummy_check (MAILSTREAM *stream)
 535.251 +{
 535.252 +  dummy_ping (stream);		/* invoke ping */
 535.253 +}
 535.254 +
 535.255 +
 535.256 +/* Dummy expunge mailbox
 535.257 + * Accepts: MAIL stream
 535.258 + *	    sequence to expunge if non-NIL
 535.259 + *	    expunge options
 535.260 + * Returns: T, always
 535.261 + */
 535.262 +
 535.263 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 535.264 +{
 535.265 +  return LONGT;
 535.266 +}
 535.267 +
 535.268 +/* Dummy copy message(s)
 535.269 + * Accepts: MAIL stream
 535.270 + *	    sequence
 535.271 + *	    destination mailbox
 535.272 + *	    options
 535.273 + * Returns: T if copy successful, else NIL
 535.274 + */
 535.275 +
 535.276 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 535.277 +{
 535.278 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 535.279 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 535.280 +  return NIL;
 535.281 +}
 535.282 +
 535.283 +
 535.284 +/* Dummy append message string
 535.285 + * Accepts: mail stream
 535.286 + *	    destination mailbox
 535.287 + *	    append callback function
 535.288 + *	    data for callback
 535.289 + * Returns: T on success, NIL on failure
 535.290 + */
 535.291 +
 535.292 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 535.293 +{
 535.294 +  char tmp[MAILTMPLEN];
 535.295 +  sprintf (tmp,"Can't append to %s",mailbox);
 535.296 +  mm_log (tmp,ERROR);		/* pass up error */
 535.297 +  return NIL;			/* always fails */
 535.298 +}
   536.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   536.2 +++ b/src/osdep/vms/env_vms.c	Mon Sep 14 15:17:45 2009 +0900
   536.3 @@ -0,0 +1,174 @@
   536.4 +/* ========================================================================
   536.5 + * Copyright 1988-2006 University of Washington
   536.6 + *
   536.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   536.8 + * you may not use this file except in compliance with the License.
   536.9 + * You may obtain a copy of the License at
  536.10 + *
  536.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  536.12 + *
  536.13 + * 
  536.14 + * ========================================================================
  536.15 + */
  536.16 +
  536.17 +/*
  536.18 + * Program:	VMS environment routines
  536.19 + *
  536.20 + * Author:	Mark Crispin
  536.21 + *		Networks and Distributed Computing
  536.22 + *		Computing & Communications
  536.23 + *		University of Washington
  536.24 + *		Administration Building, AG-44
  536.25 + *		Seattle, WA  98195
  536.26 + *		Internet: MRC@CAC.Washington.EDU
  536.27 + *
  536.28 + * Date:	2 August 1994
  536.29 + * Last Edited:	30 August 2006
  536.30 + */
  536.31 +
  536.32 +
  536.33 +static char *myUserName = NIL;	/* user name */
  536.34 +static char *myLocalHost = NIL;	/* local host name */
  536.35 +static char *myHomeDir = NIL;	/* home directory name */
  536.36 +static char *myNewsrc = NIL;	/* newsrc file name */
  536.37 +
  536.38 +#include "pmatch.c"		/* include wildcard pattern matcher */
  536.39 +
  536.40 +/* Environment manipulate parameters
  536.41 + * Accepts: function code
  536.42 + *	    function-dependent value
  536.43 + * Returns: function-dependent return value
  536.44 + */
  536.45 +
  536.46 +void *env_parameters (long function,void *value)
  536.47 +{
  536.48 +  void *ret = NIL;
  536.49 +  switch ((int) function) {
  536.50 +  case SET_USERNAME:
  536.51 +    myUserName = cpystr ((char *) value);
  536.52 +  case GET_USERNAME:
  536.53 +    ret = (void *) myUserName;
  536.54 +    break;
  536.55 +  case SET_HOMEDIR:
  536.56 +    myHomeDir = cpystr ((char *) value);
  536.57 +  case GET_HOMEDIR:
  536.58 +    ret = (void *) myHomeDir;
  536.59 +    break;
  536.60 +  case SET_LOCALHOST:
  536.61 +    myLocalHost = cpystr ((char *) value);
  536.62 +  case GET_LOCALHOST:
  536.63 +    ret = (void *) myLocalHost;
  536.64 +    break;
  536.65 +  case SET_NEWSRC:
  536.66 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  536.67 +    myNewsrc = cpystr ((char *) value);
  536.68 +  case GET_NEWSRC:
  536.69 +    if (!myNewsrc) {		/* set news file name if not defined */
  536.70 +      char tmp[MAILTMPLEN];
  536.71 +      sprintf (tmp,"%s:.newsrc",myhomedir ());
  536.72 +      myNewsrc = cpystr (tmp);
  536.73 +    }
  536.74 +    ret = (void *) myNewsrc;
  536.75 +    break;
  536.76 +  }
  536.77 +  return ret;
  536.78 +}
  536.79 + 
  536.80 +/* Write current time
  536.81 + * Accepts: destination string
  536.82 + *	    optional format of day-of-week prefix
  536.83 + *	    format of date and time
  536.84 + */
  536.85 +
  536.86 +static void do_date (char *date,char *prefix,char *fmt)
  536.87 +{
  536.88 +  time_t tn = time (0);
  536.89 +  struct tm *t = localtime (&tn);
  536.90 +  int zone = LOCALTIMEZONE + (t->tm_isdst ? 60 : 0);
  536.91 +  if (prefix) {			/* want day of week? */
  536.92 +    sprintf (date,prefix,days[t->tm_wday]);
  536.93 +    date += strlen (date);	/* make next sprintf append */
  536.94 +  }
  536.95 +				/* output the date */
  536.96 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  536.97 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
  536.98 +}
  536.99 +
 536.100 +
 536.101 +/* Write current time in RFC 822 format
 536.102 + * Accepts: destination string
 536.103 + */
 536.104 +
 536.105 +void rfc822_date (char *date)
 536.106 +{
 536.107 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d");
 536.108 +}
 536.109 +
 536.110 +
 536.111 +/* Write current time in internal format
 536.112 + * Accepts: destination string
 536.113 + */
 536.114 +
 536.115 +void internal_date (char *date)
 536.116 +{
 536.117 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d");
 536.118 +}
 536.119 +
 536.120 +/* Return my user name
 536.121 + * Returns: my user name
 536.122 + */
 536.123 +
 536.124 +char *myusername ()
 536.125 +{
 536.126 +  struct stat sbuf;
 536.127 +  char tmp[MAILTMPLEN];
 536.128 +
 536.129 +  if (!myUserName) {		/* get user name if don't have it yet */
 536.130 +    myUserName = cpystr (cuserid (NIL));
 536.131 +    myHomeDir = cpystr ("SYS$LOGIN");
 536.132 +  }
 536.133 +  return myUserName;
 536.134 +}
 536.135 +
 536.136 +
 536.137 +/* Return my home directory name
 536.138 + * Returns: my home directory name
 536.139 + */
 536.140 +
 536.141 +char *myhomedir ()
 536.142 +{
 536.143 +  if (!myHomeDir) myusername ();/* initialize if first time */
 536.144 +  return myHomeDir;
 536.145 +}
 536.146 +
 536.147 +
 536.148 +/* Determine default prototype stream to user
 536.149 + * Accepts: type (NIL for create, T for append)
 536.150 + * Returns: default prototype stream
 536.151 + */
 536.152 +
 536.153 +MAILSTREAM *default_proto (long type)
 536.154 +{
 536.155 +  return NIL;			/* no default prototype */
 536.156 +}
 536.157 +
 536.158 +/* Emulator for BSD syslog() routine
 536.159 + * Accepts: priority
 536.160 + *	    message
 536.161 + *	    parameters
 536.162 + */
 536.163 +
 536.164 +void syslog (int priority,const char *message,...)
 536.165 +{
 536.166 +}
 536.167 +
 536.168 +
 536.169 +/* Emulator for BSD openlog() routine
 536.170 + * Accepts: identity
 536.171 + *	    options
 536.172 + *	    facility
 536.173 + */
 536.174 +
 536.175 +void openlog (const char *ident,int logopt,int facility)
 536.176 +{
 536.177 +}
   537.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   537.2 +++ b/src/osdep/vms/env_vms.h	Mon Sep 14 15:17:45 2009 +0900
   537.3 @@ -0,0 +1,60 @@
   537.4 +/* ========================================================================
   537.5 + * Copyright 1988-2006 University of Washington
   537.6 + *
   537.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   537.8 + * you may not use this file except in compliance with the License.
   537.9 + * You may obtain a copy of the License at
  537.10 + *
  537.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  537.12 + *
  537.13 + * 
  537.14 + * ========================================================================
  537.15 + */
  537.16 +
  537.17 +/*
  537.18 + * Program:	VMS environment routines
  537.19 + *
  537.20 + * Author:	Mark Crispin
  537.21 + *		Networks and Distributed Computing
  537.22 + *		Computing & Communications
  537.23 + *		University of Washington
  537.24 + *		Administration Building, AG-44
  537.25 + *		Seattle, WA  98195
  537.26 + *		Internet: MRC@CAC.Washington.EDU
  537.27 + *
  537.28 + * Date:	2 August 1994
  537.29 + * Last Edited:	30 August 2006
  537.30 + */
  537.31 +
  537.32 +
  537.33 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\SUBSCRIPTIONS.TXT",myhomedir ())
  537.34 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\SUBSCRIPTIONS.TMP",myhomedir ())
  537.35 +
  537.36 +/* Function prototypes */
  537.37 +
  537.38 +#include "env.h"
  537.39 +
  537.40 +char *myusername ();
  537.41 +
  537.42 +
  537.43 +/* syslog() emulation */
  537.44 +
  537.45 +#define LOG_MAIL	(2<<3)	/* mail system */
  537.46 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  537.47 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  537.48 +#define LOG_EMERG	0	/* system is unusable */
  537.49 +#define LOG_ALERT	1	/* action must be taken immediately */
  537.50 +#define LOG_CRIT	2	/* critical conditions */
  537.51 +#define LOG_ERR		3	/* error conditions */
  537.52 +#define LOG_WARNING	4	/* warning conditions */
  537.53 +#define LOG_NOTICE	5	/* normal but signification condition */
  537.54 +#define LOG_INFO	6	/* informational */
  537.55 +#define LOG_DEBUG	7	/* debug-level messages */
  537.56 +#define LOG_PID		0x01	/* log the pid with each message */
  537.57 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  537.58 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  537.59 +#define LOG_NDELAY	0x08	/* don't delay open */
  537.60 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  537.61 +
  537.62 +void openlog (const char *ident,int logopt,int facility);
  537.63 +void syslog (int priority,const char *message,...);
   538.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   538.2 +++ b/src/osdep/vms/fs_vms.c	Mon Sep 14 15:17:45 2009 +0900
   538.3 @@ -0,0 +1,62 @@
   538.4 +/* ========================================================================
   538.5 + * Copyright 1988-2006 University of Washington
   538.6 + *
   538.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   538.8 + * you may not use this file except in compliance with the License.
   538.9 + * You may obtain a copy of the License at
  538.10 + *
  538.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  538.12 + *
  538.13 + * 
  538.14 + * ========================================================================
  538.15 + */
  538.16 +
  538.17 +/*
  538.18 + * Program:	Free storage management routines
  538.19 + *
  538.20 + * Author:	Mark Crispin
  538.21 + *		Networks and Distributed Computing
  538.22 + *		Computing & Communications
  538.23 + *		University of Washington
  538.24 + *		Administration Building, AG-44
  538.25 + *		Seattle, WA  98195
  538.26 + *		Internet: MRC@CAC.Washington.EDU
  538.27 + *
  538.28 + * Date:	1 August 1988
  538.29 + * Last Edited:	30 August 2006
  538.30 + */
  538.31 +
  538.32 +/* Get a block of free storage
  538.33 + * Accepts: size of desired block
  538.34 + * Returns: free storage block
  538.35 + */
  538.36 +
  538.37 +void *fs_get (size_t size)
  538.38 +{
  538.39 +  void *block = malloc (size ? size : (size_t) 1);
  538.40 +  if (!block) fatal ("Out of memory");
  538.41 +  return (block);
  538.42 +}
  538.43 +
  538.44 +
  538.45 +/* Resize a block of free storage
  538.46 + * Accepts: ** pointer to current block
  538.47 + *	    new size
  538.48 + */
  538.49 +
  538.50 +void fs_resize (void **block,size_t size)
  538.51 +{
  538.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  538.53 +    fatal ("Can't resize memory");
  538.54 +}
  538.55 +
  538.56 +
  538.57 +/* Return a block of free storage
  538.58 + * Accepts: ** pointer to free storage block
  538.59 + */
  538.60 +
  538.61 +void fs_give (void **block)
  538.62 +{
  538.63 +  free (*block);
  538.64 +  *block = NIL;
  538.65 +}
   539.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   539.2 +++ b/src/osdep/vms/ftl_vms.c	Mon Sep 14 15:17:45 2009 +0900
   539.3 @@ -0,0 +1,38 @@
   539.4 +/* ========================================================================
   539.5 + * Copyright 1988-2006 University of Washington
   539.6 + *
   539.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   539.8 + * you may not use this file except in compliance with the License.
   539.9 + * You may obtain a copy of the License at
  539.10 + *
  539.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  539.12 + *
  539.13 + * 
  539.14 + * ========================================================================
  539.15 + */
  539.16 +
  539.17 +/*
  539.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  539.19 + *
  539.20 + * Author:	Mark Crispin
  539.21 + *		Networks and Distributed Computing
  539.22 + *		Computing & Communications
  539.23 + *		University of Washington
  539.24 + *		Administration Building, AG-44
  539.25 + *		Seattle, WA  98195
  539.26 + *		Internet: MRC@CAC.Washington.EDU
  539.27 + *
  539.28 + * Date:	1 August 1988
  539.29 + * Last Edited:	30 August 2006
  539.30 + */
  539.31 +
  539.32 +
  539.33 +/* Report a fatal error
  539.34 + * Accepts: string to output
  539.35 + */
  539.36 +
  539.37 +void fatal (char *string)
  539.38 +{
  539.39 +  mm_fatal (string);		/* pass up the string */
  539.40 +  abort ();			/* die horribly */
  539.41 +}
   540.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   540.2 +++ b/src/osdep/vms/link.opt	Mon Sep 14 15:17:45 2009 +0900
   540.3 @@ -0,0 +1,1 @@
   540.4 +SYS$SHARE:VAXCRTL/SHARE
   541.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   541.2 +++ b/src/osdep/vms/link_mnt.opt	Mon Sep 14 15:17:45 2009 +0900
   541.3 @@ -0,0 +1,1 @@
   541.4 +MULTINET:MULTINET_SOCKET_LIBRARY/SHARE
   542.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   542.2 +++ b/src/osdep/vms/link_nlb.opt	Mon Sep 14 15:17:45 2009 +0900
   542.3 @@ -0,0 +1,1 @@
   542.4 +NETLIB_SHR/SHARE
   543.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   543.2 +++ b/src/osdep/vms/linkage.c	Mon Sep 14 15:17:45 2009 +0900
   543.3 @@ -0,0 +1,37 @@
   543.4 +/* ========================================================================
   543.5 + * Copyright 1988-2007 University of Washington
   543.6 + *
   543.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   543.8 + * you may not use this file except in compliance with the License.
   543.9 + * You may obtain a copy of the License at
  543.10 + *
  543.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  543.12 + *
  543.13 + * 
  543.14 + * ========================================================================
  543.15 + */
  543.16 +
  543.17 +/*
  543.18 + * Program:	Default driver linkage
  543.19 + *
  543.20 + * Author:	Mark Crispin
  543.21 + *		Networks and Distributed Computing
  543.22 + *		Computing & Communications
  543.23 + *		University of Washington
  543.24 + *		Administration Building, AG-44
  543.25 + *		Seattle, WA  98195
  543.26 + *		Internet: MRC@CAC.Washington.EDU
  543.27 + *
  543.28 + * Date:	13 June 1995
  543.29 + * Last Edited:	23 May 2007
  543.30 + */
  543.31 +
  543.32 +  mail_link (&imapdriver);		/* link in the imap driver */
  543.33 +  mail_link (&nntpdriver);		/* link in the nntp driver */
  543.34 +  mail_link (&pop3driver);		/* link in the pop3 driver */
  543.35 +  mail_link (&dummydriver);		/* link in the dummy driver */
  543.36 +  auth_link (&auth_ext);		/* link in the ext authenticator */
  543.37 +  auth_link (&auth_md5);		/* link in the md5 authenticator */
  543.38 +  auth_link (&auth_pla);		/* link in the plain authenticator */
  543.39 +  auth_link (&auth_log);		/* link in the log authenticator */
  543.40 +  mail_versioncheck (CCLIENTVERSION);	/* validate version */
   544.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   544.2 +++ b/src/osdep/vms/linkage.h	Mon Sep 14 15:17:45 2009 +0900
   544.3 @@ -0,0 +1,36 @@
   544.4 +/* ========================================================================
   544.5 + * Copyright 1988-2006 University of Washington
   544.6 + *
   544.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   544.8 + * you may not use this file except in compliance with the License.
   544.9 + * You may obtain a copy of the License at
  544.10 + *
  544.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  544.12 + *
  544.13 + * 
  544.14 + * ========================================================================
  544.15 + */
  544.16 +
  544.17 +/*
  544.18 + * Program:	Default driver linkage
  544.19 + *
  544.20 + * Author:	Mark Crispin
  544.21 + *		Networks and Distributed Computing
  544.22 + *		Computing & Communications
  544.23 + *		University of Washington
  544.24 + *		Administration Building, AG-44
  544.25 + *		Seattle, WA  98195
  544.26 + *		Internet: MRC@CAC.Washington.EDU
  544.27 + *
  544.28 + * Date:	13 June 1995
  544.29 + * Last Edited:	30 August 2006
  544.30 + */
  544.31 +
  544.32 +extern DRIVER imapdriver;
  544.33 +extern DRIVER nntpdriver;
  544.34 +extern DRIVER pop3driver;
  544.35 +extern DRIVER dummydriver;
  544.36 +extern AUTHENTICATOR auth_ext;
  544.37 +extern AUTHENTICATOR auth_log;
  544.38 +extern AUTHENTICATOR auth_md5;
  544.39 +extern AUTHENTICATOR auth_pla;
   545.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   545.2 +++ b/src/osdep/vms/nl_vms.c	Mon Sep 14 15:17:45 2009 +0900
   545.3 @@ -0,0 +1,92 @@
   545.4 +/* ========================================================================
   545.5 + * Copyright 1988-2006 University of Washington
   545.6 + *
   545.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   545.8 + * you may not use this file except in compliance with the License.
   545.9 + * You may obtain a copy of the License at
  545.10 + *
  545.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  545.12 + *
  545.13 + * 
  545.14 + * ========================================================================
  545.15 + */
  545.16 +
  545.17 +/*
  545.18 + * Program:	UNIX/VMS newline routines
  545.19 + *
  545.20 + * Author:	Mark Crispin
  545.21 + *		Networks and Distributed Computing
  545.22 + *		Computing & Communications
  545.23 + *		University of Washington
  545.24 + *		Administration Building, AG-44
  545.25 + *		Seattle, WA  98195
  545.26 + *		Internet: MRC@CAC.Washington.EDU
  545.27 + *
  545.28 + * Date:	1 August 1988
  545.29 + * Last Edited:	30 August 2006
  545.30 + */
  545.31 +
  545.32 +/* Copy string with CRLF newlines
  545.33 + * Accepts: destination string
  545.34 + *	    pointer to size of destination string buffer
  545.35 + *	    source string
  545.36 + *	    length of source string
  545.37 + * Returns: length of copied string
  545.38 + */
  545.39 +
  545.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  545.41 +			  unsigned char *src,unsigned long srcl)
  545.42 +{
  545.43 +  long i = srcl * 2,j;
  545.44 +  unsigned char c,*d = src;
  545.45 +  if (*dst) {			/* candidate destination provided? */
  545.46 +				/* count NLs if doesn't fit worst-case */
  545.47 +    if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++;
  545.48 +				/* still too small, must reset destination */
  545.49 +    if (i > *dstl) fs_give ((void **) dst);
  545.50 +  }
  545.51 +				/* make a new buffer if needed */
  545.52 +  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
  545.53 +  d = *dst;			/* destination string */
  545.54 +  if (srcl) do {		/* main copy loop */
  545.55 +    if ((c = *src++) < '\016') {
  545.56 +				/* prepend CR to LF */
  545.57 +      if (c == '\012') *d++ = '\015';
  545.58 +				/* unlikely CR */
  545.59 +      else if ((c == '\015') && (srcl > 1) && (*src == '\012')) {
  545.60 +	*d++ = c;		/* copy the CR */
  545.61 +	c = *src++;		/* grab the LF */
  545.62 +	--srcl;			/* adjust the count */
  545.63 +      }
  545.64 +    }
  545.65 +    *d++ = c;			/* copy character */
  545.66 +  } while (--srcl);
  545.67 +  *d = '\0';			/* tie off destination */
  545.68 +  return d - *dst;		/* return length */
  545.69 +}
  545.70 +
  545.71 +/* Length of string after strcrlfcpy applied
  545.72 + * Accepts: source string
  545.73 + * Returns: length of string
  545.74 + */
  545.75 +
  545.76 +unsigned long strcrlflen (STRING *s)
  545.77 +{
  545.78 +  unsigned long pos = GETPOS (s);
  545.79 +  unsigned long i = SIZE (s);
  545.80 +  unsigned long j = i;
  545.81 +  while (j--) switch (SNX (s)) {/* search for newlines */
  545.82 +  case '\015':			/* unlikely carriage return */
  545.83 +    if (j && (CHR (s) == '\012')) {
  545.84 +      SNX (s);			/* eat the line feed */
  545.85 +      j--;
  545.86 +    }
  545.87 +    break;
  545.88 +  case '\012':			/* line feed? */
  545.89 +    i++;
  545.90 +  default:			/* ordinary chararacter */
  545.91 +    break;
  545.92 +  }
  545.93 +  SETPOS (s,pos);		/* restore old position */
  545.94 +  return i;
  545.95 +}
   546.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   546.2 +++ b/src/osdep/vms/os_vms.c	Mon Sep 14 15:17:45 2009 +0900
   546.3 @@ -0,0 +1,76 @@
   546.4 +/* ========================================================================
   546.5 + * Copyright 1988-2006 University of Washington
   546.6 + *
   546.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   546.8 + * you may not use this file except in compliance with the License.
   546.9 + * You may obtain a copy of the License at
  546.10 + *
  546.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  546.12 + *
  546.13 + * 
  546.14 + * ========================================================================
  546.15 + */
  546.16 +
  546.17 +/*
  546.18 + * Program:	Operating-system dependent routines -- VMS version
  546.19 + *
  546.20 + * Author:	Mark Crispin
  546.21 + *		Networks and Distributed Computing
  546.22 + *		Computing & Communications
  546.23 + *		University of Washington
  546.24 + *		Administration Building, AG-44
  546.25 + *		Seattle, WA  98195
  546.26 + *		Internet: MRC@CAC.Washington.EDU
  546.27 + *
  546.28 + * Date:	2 August 1994
  546.29 + * Last Edited:	30 August 2006
  546.30 + */
  546.31 + 
  546.32 +#include "tcp_vms.h"		/* must be before osdep includes tcp.h */
  546.33 +#include "mail.h"
  546.34 +#include "osdep.h"
  546.35 +#include <stdio.h>
  546.36 +#include <sys/time.h>
  546.37 +#include <sys/stat.h>
  546.38 +#include <sys/socket.h>
  546.39 +#include <netinet/in.h>
  546.40 +#include <arpa/inet.h>
  546.41 +#include <netdb.h>
  546.42 +#include <ctype.h>
  546.43 +#include <errno.h>
  546.44 +extern int errno;		/* just in case */
  546.45 +#include "misc.h"
  546.46 +
  546.47 +
  546.48 +#include "fs_vms.c"
  546.49 +#include "ftl_vms.c"
  546.50 +#include "nl_vms.c"
  546.51 +#include "env_vms.c"
  546.52 +#include "tcp_vms.c"
  546.53 +
  546.54 +#define server_login(user,pass,authuser,argc,argv) NIL
  546.55 +#define authserver_login(user,authuser,argc,argv) NIL
  546.56 +#define myusername() ""		/* dummy definition to prevent build errors */
  546.57 +#define MD5ENABLE ""
  546.58 +
  546.59 +#include "auth_md5.c"
  546.60 +#include "auth_pla.c"
  546.61 +#include "auth_log.c"
  546.62 +
  546.63 +
  546.64 +/* Emulator for UNIX getpass() call
  546.65 + * Accepts: prompt
  546.66 + * Returns: password
  546.67 + */
  546.68 +
  546.69 +#define PWDLEN 128		/* used by Linux */
  546.70 +
  546.71 +char *getpass (const char *prompt)
  546.72 +{
  546.73 +  char *s;
  546.74 +  static char pwd[PWDLEN];
  546.75 +  fputs (prompt,stdout);
  546.76 +  fgets (pwd,PWDLEN-1,stdin);
  546.77 +  if (s = strchr (pwd,'\n')) *s = '\0';
  546.78 +  return pwd;
  546.79 +}
   547.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   547.2 +++ b/src/osdep/vms/os_vms.h	Mon Sep 14 15:17:45 2009 +0900
   547.3 @@ -0,0 +1,52 @@
   547.4 +/* ========================================================================
   547.5 + * Copyright 1988-2007 University of Washington
   547.6 + *
   547.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   547.8 + * you may not use this file except in compliance with the License.
   547.9 + * You may obtain a copy of the License at
  547.10 + *
  547.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  547.12 + *
  547.13 + * 
  547.14 + * ========================================================================
  547.15 + */
  547.16 +
  547.17 +/*
  547.18 + * Program:	Operating-system dependent routines -- VMS version
  547.19 + *
  547.20 + * Author:	Mark Crispin
  547.21 + *		Networks and Distributed Computing
  547.22 + *		Computing & Communications
  547.23 + *		University of Washington
  547.24 + *		Administration Building, AG-44
  547.25 + *		Seattle, WA  98195
  547.26 + *		Internet: MRC@CAC.Washington.EDU
  547.27 + *
  547.28 + * Date:	2 August 1994
  547.29 + * Last Edited:	30 January 2007
  547.30 + */
  547.31 +
  547.32 +#include <stdlib.h>
  547.33 +#include <string.h>
  547.34 +#include <sys/types.h>
  547.35 +#include <unixio.h>
  547.36 +#include <file.h>
  547.37 +#include <stat.h>
  547.38 +
  547.39 +#define L_SET SEEK_SET
  547.40 +#define L_INCR SEEK_CUR
  547.41 +#define L_XTND SEEK_END
  547.42 +
  547.43 +#include "env_vms.h"
  547.44 +#include "fs.h"
  547.45 +#include "ftl.h"
  547.46 +#include "nl.h"
  547.47 +#include "tcp.h"
  547.48 +
  547.49 +#define	gethostid clock
  547.50 +#define random rand
  547.51 +#define unlink delete
  547.52 +
  547.53 +char *getpass (const char *prompt);
  547.54 +
  547.55 +#define strtok_r(a,b,c) strtok(a,b)
   548.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   548.2 +++ b/src/osdep/vms/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   548.3 @@ -0,0 +1,89 @@
   548.4 +/* ========================================================================
   548.5 + * Copyright 1988-2006 University of Washington
   548.6 + *
   548.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   548.8 + * you may not use this file except in compliance with the License.
   548.9 + * You may obtain a copy of the License at
  548.10 + *
  548.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  548.12 + *
  548.13 + * 
  548.14 + * ========================================================================
  548.15 + */
  548.16 +
  548.17 +/*
  548.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  548.19 + *
  548.20 + * Author:	Mark Crispin
  548.21 + *		Networks and Distributed Computing
  548.22 + *		Computing & Communications
  548.23 + *		University of Washington
  548.24 + *		Administration Building, AG-44
  548.25 + *		Seattle, WA  98195
  548.26 + *		Internet: MRC@CAC.Washington.EDU
  548.27 + *
  548.28 + * Date:	15 June 2000
  548.29 + * Last Edited:	30 August 2006
  548.30 + */
  548.31 +
  548.32 +/* Wildcard pattern match
  548.33 + * Accepts: base string
  548.34 + *	    pattern string
  548.35 + *	    delimiter character
  548.36 + * Returns: T if pattern matches base, else NIL
  548.37 + */
  548.38 +
  548.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  548.40 +{
  548.41 +  switch (*pat) {
  548.42 +  case '%':			/* non-recursive */
  548.43 +				/* % at end, OK if no inferiors */
  548.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  548.45 +                                /* scan remainder of string until delimiter */
  548.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  548.47 +    while ((*s != delim) && *s++);
  548.48 +    break;
  548.49 +  case '*':			/* match 0 or more characters */
  548.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  548.51 +				/* scan remainder of string */
  548.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  548.53 +    while (*s++);
  548.54 +    break;
  548.55 +  case '\0':			/* end of pattern */
  548.56 +    return *s ? NIL : T;	/* success if also end of base */
  548.57 +  default:			/* match this character */
  548.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  548.59 +  }
  548.60 +  return NIL;
  548.61 +}
  548.62 +
  548.63 +/* Directory pattern match
  548.64 + * Accepts: base string
  548.65 + *	    pattern string
  548.66 + *	    delimiter character
  548.67 + * Returns: T if base is a matching directory of pattern, else NIL
  548.68 + */
  548.69 +
  548.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  548.71 +{
  548.72 +  switch (*pat) {
  548.73 +  case '%':			/* non-recursive */
  548.74 +    if (!*s) return T;		/* end of base means have a subset match */
  548.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  548.76 +				/* scan remainder of string until delimiter */
  548.77 +    do if (dmatch (s,pat,delim)) return T;
  548.78 +    while ((*s != delim) && *s++);
  548.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  548.80 +    return dmatch (s,pat,delim);/* do new scan */
  548.81 +  case '*':			/* match 0 or more characters */
  548.82 +    return T;			/* unconditional match */
  548.83 +  case '\0':			/* end of pattern */
  548.84 +    break;
  548.85 +  default:			/* match this character */
  548.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  548.87 +				/* end of base, return if at delimiter */
  548.88 +    else if (*pat == delim) return T;
  548.89 +    break;
  548.90 +  }
  548.91 +  return NIL;
  548.92 +}
   549.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   549.2 +++ b/src/osdep/vms/tcp_vms.h	Mon Sep 14 15:17:45 2009 +0900
   549.3 @@ -0,0 +1,52 @@
   549.4 +/* ========================================================================
   549.5 + * Copyright 1988-2006 University of Washington
   549.6 + *
   549.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   549.8 + * you may not use this file except in compliance with the License.
   549.9 + * You may obtain a copy of the License at
  549.10 + *
  549.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  549.12 + *
  549.13 + * 
  549.14 + * ========================================================================
  549.15 + */
  549.16 +
  549.17 +/*
  549.18 + * Program:	VMS TCP/IP routines
  549.19 + *
  549.20 + * Author:	Mark Crispin
  549.21 + *		Networks and Distributed Computing
  549.22 + *		Computing & Communications
  549.23 + *		University of Washington
  549.24 + *		Administration Building, AG-44
  549.25 + *		Seattle, WA  98195
  549.26 + *		Internet: MRC@CAC.Washington.EDU
  549.27 + *
  549.28 + * Date:	1 August 1988
  549.29 + * Last Edited:	30 August 2006
  549.30 + */
  549.31 +
  549.32 +
  549.33 +/* TCP input buffer */
  549.34 +
  549.35 +#define BUFLEN 8192
  549.36 +
  549.37 +
  549.38 +/* TCP I/O stream */
  549.39 +
  549.40 +#define TCPSTREAM struct tcp_stream
  549.41 +TCPSTREAM {
  549.42 +  char *host;			/* host name */
  549.43 +  unsigned long port;		/* port number */
  549.44 +  char *localhost;		/* local host name */
  549.45 +  int tcpsi;			/* input socket */
  549.46 +  int tcpso;			/* output socket */
  549.47 +  int ictr;			/* input counter */
  549.48 +  char *iptr;			/* input pointer */
  549.49 +  char ibuf[BUFLEN];		/* input buffer */
  549.50 +};
  549.51 +
  549.52 +
  549.53 +/* Local function prototypes */
  549.54 +
  549.55 +long tcp_abort (TCPSTREAM *stream);
   550.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   550.2 +++ b/src/osdep/vms/tcp_vmsl.c	Mon Sep 14 15:17:45 2009 +0900
   550.3 @@ -0,0 +1,378 @@
   550.4 +/* ========================================================================
   550.5 + * Copyright 1988-2008 University of Washington
   550.6 + *
   550.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   550.8 + * you may not use this file except in compliance with the License.
   550.9 + * You may obtain a copy of the License at
  550.10 + *
  550.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  550.12 + *
  550.13 + * 
  550.14 + * ========================================================================
  550.15 + */
  550.16 +
  550.17 +/*
  550.18 + * Program:	VMS TCP/IP routines for Netlib.
  550.19 + *
  550.20 + * Author:	Mark Crispin
  550.21 + *		Networks and Distributed Computing
  550.22 + *		Computing & Communications
  550.23 + *		University of Washington
  550.24 + *		Administration Building, AG-44
  550.25 + *		Seattle, WA  98195
  550.26 + *		Internet: MRC@CAC.Washington.EDU
  550.27 + *
  550.28 + * Date:	2 August 1994
  550.29 + * Last Edited:	13 January 2008
  550.30 + */
  550.31 +
  550.32 +/* Thanks to Yehavi Bourvine at The Hebrew University of Jerusalem who
  550.33 +   contributed the original VMS code */
  550.34 +
  550.35 +#include <descrip.h>
  550.36 +
  550.37 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  550.38 +			       long *contd);
  550.39 +
  550.40 +/* TCP/IP manipulate parameters
  550.41 + * Accepts: function code
  550.42 + *	    function-dependent value
  550.43 + * Returns: function-dependent return value
  550.44 + */
  550.45 +
  550.46 +void *tcp_parameters (long function,void *value)
  550.47 +{
  550.48 +  return NIL;
  550.49 +}
  550.50 +
  550.51 + 
  550.52 +/* TCP/IP open
  550.53 + * Accepts: host name
  550.54 + *	    contact service name
  550.55 + *	    contact port number
  550.56 + * Returns: TCP/IP stream if success else NIL
  550.57 + */
  550.58 +
  550.59 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  550.60 +{
  550.61 +  TCPSTREAM *stream = NIL;
  550.62 +  unsigned long sock;
  550.63 +  int status;
  550.64 +  char tmp[MAILTMPLEN];
  550.65 +				/* hostname to connect to */
  550.66 +  struct dsc$descriptor HostDesc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
  550.67 +  port &= 0xffff;		/* erase flags */
  550.68 +				/* assign a local socket */
  550.69 +  if (!((status = net_assign (&sock)) & 0x1)) {
  550.70 +    sprintf (tmp,"Unable to assign to net, status=%d",status);
  550.71 +    mm_log (tmp,ERROR);
  550.72 +    return NIL;
  550.73 +  }
  550.74 +  if (!((status = net_bind (&sock,1)) & 0x1)) {
  550.75 +    sprintf (tmp,"Unable to create local socket, status=%d",status);
  550.76 +    mm_log (tmp,ERROR);
  550.77 +    return NIL;
  550.78 +  }
  550.79 +				/* open connection */
  550.80 +  HostDesc.dsc$w_length = strlen (host);
  550.81 +  HostDesc.dsc$a_pointer = host;
  550.82 +  if (!((status = tcp_connect (&sock,&HostDesc,port)) & 0x1)) {
  550.83 +    sprintf (tmp,"Can't connect to %.80s,%lu: %s",host,port,strerror (errno));
  550.84 +    mm_log (tmp,ERROR);
  550.85 +    return NIL;
  550.86 +  }
  550.87 +				/* create TCP/IP stream */
  550.88 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  550.89 +  stream->host = cpystr (host);	/* copy official host name */
  550.90 +				/* copy local host name */
  550.91 +  stream->localhost = cpystr (mylocalhost ());
  550.92 +  stream->port = port;		/* copy port number */
  550.93 +				/* init sockets */
  550.94 +  stream->tcpsi = stream->tcpso = sock;
  550.95 +  stream->ictr = 0;		/* init input counter */
  550.96 +  return stream;		/* return success */
  550.97 +}
  550.98 +
  550.99 +/* TCP/IP authenticated open
 550.100 + * Accepts: NETMBX specifier
 550.101 + *	    service name
 550.102 + *	    returned user name buffer
 550.103 + * Returns: TCP/IP stream if success else NIL
 550.104 + */
 550.105 +
 550.106 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 550.107 +{
 550.108 +  return NIL;
 550.109 +}
 550.110 +
 550.111 +/* TCP receive line
 550.112 + * Accepts: TCP stream
 550.113 + * Returns: text line string or NIL if failure
 550.114 + */
 550.115 +
 550.116 +char *tcp_getline (TCPSTREAM *stream)
 550.117 +{
 550.118 +  unsigned long n,contd;
 550.119 +  char *ret = tcp_getline_work (stream,&n,&contd);
 550.120 +  if (ret && contd) {		/* got a line needing continuation? */
 550.121 +    STRINGLIST *stl = mail_newstringlist ();
 550.122 +    STRINGLIST *stc = stl;
 550.123 +    do {			/* collect additional lines */
 550.124 +      stc->text.data = (unsigned char *) ret;
 550.125 +      stc->text.size = n;
 550.126 +      stc = stc->next = mail_newstringlist ();
 550.127 +      ret = tcp_getline_work (stream,&n,&contd);
 550.128 +    } while (ret && contd);
 550.129 +    if (ret) {			/* stash final part of line on list */
 550.130 +      stc->text.data = (unsigned char *) ret;
 550.131 +      stc->text.size = n;
 550.132 +				/* determine how large a buffer we need */
 550.133 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 550.134 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 550.135 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 550.136 +	memcpy (ret + n,stc->text.data,stc->text.size);
 550.137 +      ret[n] = '\0';
 550.138 +    }
 550.139 +    mail_free_stringlist (&stl);/* either way, done with list */
 550.140 +  }
 550.141 +  return ret;
 550.142 +}
 550.143 +
 550.144 +/* TCP receive line or partial line
 550.145 + * Accepts: TCP stream
 550.146 + *	    pointer to return size
 550.147 + *	    pointer to return continuation flag
 550.148 + * Returns: text line string, size and continuation flag, or NIL if failure
 550.149 + */
 550.150 +
 550.151 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 550.152 +			       long *contd)
 550.153 +{
 550.154 +  unsigned long n;
 550.155 +  char *s,*ret,c,d;
 550.156 +  *contd = NIL;			/* assume no continuation */
 550.157 +				/* make sure have data */
 550.158 +  if (!tcp_getdata (stream)) return NIL;
 550.159 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 550.160 +    d = *stream->iptr++;	/* slurp another character */
 550.161 +    if ((c == '\015') && (d == '\012')) {
 550.162 +      ret = (char *) fs_get (n--);
 550.163 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 550.164 +      ret[n] = '\0';		/* tie off string with null */
 550.165 +      return ret;
 550.166 +    }
 550.167 +  }
 550.168 +				/* copy partial string from buffer */
 550.169 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 550.170 +				/* get more data from the net */
 550.171 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 550.172 +				/* special case of newline broken by buffer */
 550.173 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 550.174 +    stream->iptr++;		/* eat the line feed */
 550.175 +    stream->ictr--;
 550.176 +    ret[*size = --n] = '\0';	/* tie off string with null */
 550.177 +  }
 550.178 +  else *contd = LONGT;		/* continuation needed */
 550.179 +  return ret;
 550.180 +}
 550.181 +
 550.182 +/* TCP/IP receive buffer
 550.183 + * Accepts: TCP/IP stream
 550.184 + *	    size in bytes
 550.185 + *	    buffer to read into
 550.186 + * Returns: T if success, NIL otherwise
 550.187 + */
 550.188 +
 550.189 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 550.190 +{
 550.191 +  unsigned long n;
 550.192 +  char *bufptr = buffer;
 550.193 +  while (size > 0) {		/* until request satisfied */
 550.194 +    if (!tcp_getdata (stream)) return NIL;
 550.195 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 550.196 +				/* do the copy */
 550.197 +    memcpy (bufptr,stream->iptr,n);
 550.198 +    bufptr += n;		/* update pointer */
 550.199 +    stream->iptr +=n;
 550.200 +    size -= n;			/* update # of bytes to do */
 550.201 +    stream->ictr -=n;
 550.202 +  }
 550.203 +  bufptr[0] = '\0';		/* tie off string */
 550.204 +  return T;
 550.205 +}
 550.206 +
 550.207 +
 550.208 +/* TCP/IP receive data
 550.209 + * Accepts: TCP/IP stream
 550.210 + * Returns: T if success, NIL otherwise
 550.211 + */
 550.212 +
 550.213 +long tcp_getdata (TCPSTREAM *stream)
 550.214 +{
 550.215 +  char tmp[MAILTMPLEN];
 550.216 +  int i,status;
 550.217 +  /* Note: the doc says we need here dynamic descriptor, but we need static
 550.218 +   * one... */
 550.219 +  struct dsc$descriptor BufDesc = {BUFLEN,DSC$K_DTYPE_T,DSC$K_CLASS_S,
 550.220 +				     stream->ibuf};
 550.221 +  static short iosb[4];
 550.222 +  if (stream->tcpsi < 0) return NIL;
 550.223 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 550.224 +    if (!((status = tcp_receive(&(stream->tcpsi), &BufDesc, iosb)) & 0x1)) {
 550.225 +      sprintf (tmp,"Error reading from TcpIp/NETLIB, status=%d",status);
 550.226 +      mm_log (tmp,ERROR);
 550.227 +      return tcp_abort (stream);
 550.228 +    }
 550.229 +    if (iosb[1] > BUFLEN) i = BUFLEN;
 550.230 +    else i = iosb[1];
 550.231 +    if (i < 1) return tcp_abort (stream);
 550.232 +    stream->ictr = i;		/* set new byte count */
 550.233 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 550.234 +  }
 550.235 +  return T;
 550.236 +}
 550.237 +
 550.238 +/* TCP/IP send string as record
 550.239 + * Accepts: TCP/IP stream
 550.240 + *	    string pointer
 550.241 + * Returns: T if success else NIL
 550.242 + */
 550.243 +
 550.244 +long tcp_soutr (TCPSTREAM *stream,char *string)
 550.245 +{
 550.246 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 550.247 +}
 550.248 +
 550.249 +
 550.250 +/* TCP/IP send string
 550.251 + * Accepts: TCP/IP stream
 550.252 + *	    string pointer
 550.253 + *	    byte count
 550.254 + * Returns: T if success else NIL
 550.255 + */
 550.256 +
 550.257 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 550.258 +{
 550.259 +  int status;
 550.260 +  struct dsc$descriptor_s BufDesc = {strlen(string),DSC$K_DTYPE_T,
 550.261 +				       DSC$K_CLASS_S,string };
 550.262 +				/* 2 = Do not add \r\n */
 550.263 +  return ((status = tcp_send (&(stream->tcpso),&BufDesc,2)) & 0x1) ? T :
 550.264 +    tcp_abort (stream);
 550.265 +}
 550.266 +
 550.267 +/* TCP/IP close
 550.268 + * Accepts: TCP/IP stream
 550.269 + */
 550.270 +
 550.271 +void tcp_close (TCPSTREAM *stream)
 550.272 +{
 550.273 +  tcp_abort (stream);		/* nuke the stream */
 550.274 +				/* flush host names */
 550.275 +  fs_give ((void **) &stream->host);
 550.276 +  fs_give ((void **) &stream->localhost);
 550.277 +  fs_give ((void **) &stream);	/* flush the stream */
 550.278 +}
 550.279 +
 550.280 +
 550.281 +/* TCP/IP abort stream
 550.282 + * Accepts: TCP/IP stream
 550.283 + * Returns: NIL always
 550.284 + */
 550.285 +
 550.286 +long tcp_abort (TCPSTREAM *stream)
 550.287 +{
 550.288 +  if (stream->tcpsi >= 0) {	/* no-op if no socket */
 550.289 +				/* nuke the socket */
 550.290 +    tcp_disconnect (&(stream->tcpsi));
 550.291 +    stream->tcpsi = stream->tcpso = -1;
 550.292 +  }
 550.293 +  return NIL;
 550.294 +}
 550.295 +
 550.296 +/* TCP/IP get host name
 550.297 + * Accepts: TCP/IP stream
 550.298 + * Returns: host name for this stream
 550.299 + */
 550.300 +
 550.301 +char *tcp_host (TCPSTREAM *stream)
 550.302 +{
 550.303 +  return stream->host;		/* return host name */
 550.304 +}
 550.305 +
 550.306 +
 550.307 +/* TCP/IP get remote host name
 550.308 + * Accepts: TCP/IP stream
 550.309 + * Returns: host name for this stream
 550.310 + */
 550.311 +
 550.312 +char *tcp_remotehost (TCPSTREAM *stream)
 550.313 +{
 550.314 +  return stream->host;		/* return host name */
 550.315 +}
 550.316 +
 550.317 +
 550.318 +/* TCP/IP return port for this stream
 550.319 + * Accepts: TCP/IP stream
 550.320 + * Returns: port number for this stream
 550.321 + */
 550.322 +
 550.323 +unsigned long tcp_port (TCPSTREAM *stream)
 550.324 +{
 550.325 +  return stream->port;		/* return port number */
 550.326 +}
 550.327 +
 550.328 +
 550.329 +/* TCP/IP get local host name
 550.330 + * Accepts: TCP/IP stream
 550.331 + * Returns: local host name
 550.332 + */
 550.333 +
 550.334 +char *tcp_localhost (TCPSTREAM *stream)
 550.335 +{
 550.336 +  return stream->localhost;	/* return local host name */
 550.337 +}
 550.338 +
 550.339 +/* Return my local host name
 550.340 + * Returns: my local host name
 550.341 + */
 550.342 +
 550.343 +char *mylocalhost ()
 550.344 +{
 550.345 +  int status;
 550.346 +  char tmp[MAILTMPLEN];
 550.347 +  if (!myLocalHost) {		/* have local host yet? */
 550.348 +				/* receives local host name */
 550.349 +    struct dsc$descriptor LocalhostDesc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,NULL};
 550.350 +    if (!((status = net_get_hostname (&LocalhostDesc)) & 0x1)) {
 550.351 +      sprintf (tmp,"Can't get local hostname, status=%d",status);
 550.352 +      mm_log (tmp,ERROR);
 550.353 +      return "UNKNOWN";
 550.354 +    }
 550.355 +    strncpy (tmp,LocalhostDesc.dsc$a_pointer,LocalhostDesc.dsc$w_length);
 550.356 +    tmp[LocalhostDesc.dsc$w_length] = '\0';
 550.357 +    str$free1_dx (&LocalhostDesc);
 550.358 +    myLocalHost = cpystr (tmp);
 550.359 +  }
 550.360 +  return myLocalHost;
 550.361 +}
 550.362 +
 550.363 +/* TCP/IP return canonical form of host name
 550.364 + * Accepts: host name
 550.365 + * Returns: canonical form of host name
 550.366 + */
 550.367 +
 550.368 +char *tcp_canonical (char *name)
 550.369 +{
 550.370 +  return name;
 550.371 +}
 550.372 +
 550.373 +
 550.374 +/* TCP/IP get client host name (server calls only)
 550.375 + * Returns: client host name
 550.376 + */
 550.377 +
 550.378 +char *tcp_clienthost ()
 550.379 +{
 550.380 +  return "UNKNOWN";
 550.381 +}
   551.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   551.2 +++ b/src/osdep/vms/tcp_vmsm.c	Mon Sep 14 15:17:45 2009 +0900
   551.3 @@ -0,0 +1,479 @@
   551.4 +/* ========================================================================
   551.5 + * Copyright 1988-2008 University of Washington
   551.6 + *
   551.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   551.8 + * you may not use this file except in compliance with the License.
   551.9 + * You may obtain a copy of the License at
  551.10 + *
  551.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  551.12 + *
  551.13 + * 
  551.14 + * ========================================================================
  551.15 + */
  551.16 +
  551.17 +/*
  551.18 + * Program:	VMS TCP/IP routines for Multinet
  551.19 + *
  551.20 + * Author:	Mark Crispin
  551.21 + *		Networks and Distributed Computing
  551.22 + *		Computing & Communications
  551.23 + *		University of Washington
  551.24 + *		Administration Building, AG-44
  551.25 + *		Seattle, WA  98195
  551.26 + *		Internet: MRC@CAC.Washington.EDU
  551.27 + *
  551.28 + * Date:	2 August 1994
  551.29 + * Last Edited:	13 January 2008
  551.30 + */
  551.31 +
  551.32 +			
  551.33 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  551.34 +static long ttmo_read = 0;	/* TCP timeouts, in seconds */
  551.35 +static long ttmo_write = 0;
  551.36 +
  551.37 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  551.38 +			       long *contd);
  551.39 +
  551.40 +/* TCP/IP manipulate parameters
  551.41 + * Accepts: function code
  551.42 + *	    function-dependent value
  551.43 + * Returns: function-dependent return value
  551.44 + */
  551.45 +
  551.46 +void *tcp_parameters (long function,void *value)
  551.47 +{
  551.48 +  void *ret = NIL;
  551.49 +  switch ((int) function) {
  551.50 +  case SET_TIMEOUT:
  551.51 +    tmoh = (tcptimeout_t) value;
  551.52 +  case GET_TIMEOUT:
  551.53 +    ret = (void *) tmoh;
  551.54 +    break;
  551.55 +  case SET_READTIMEOUT:
  551.56 +    ttmo_read = (long) value;
  551.57 +  case GET_READTIMEOUT:
  551.58 +    ret = (void *) ttmo_read;
  551.59 +    break;
  551.60 +  case SET_WRITETIMEOUT:
  551.61 +    ttmo_write = (long) value;
  551.62 +  case GET_WRITETIMEOUT:
  551.63 +    ret = (void *) ttmo_write;
  551.64 +    break;
  551.65 +  }
  551.66 +  return ret;
  551.67 +}
  551.68 + 
  551.69 +/* TCP/IP open
  551.70 + * Accepts: host name
  551.71 + *	    contact service name
  551.72 + *	    contact port number
  551.73 + * Returns: TCP/IP stream if success else NIL
  551.74 + */
  551.75 +
  551.76 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  551.77 +{
  551.78 +  TCPSTREAM *stream = NIL;
  551.79 +  int sock;
  551.80 +  char *s;
  551.81 +  struct sockaddr_in sin;
  551.82 +  struct hostent *host_name;
  551.83 +  char hostname[MAILTMPLEN];
  551.84 +  char tmp[MAILTMPLEN];
  551.85 +  struct protoent *pt = getprotobyname ("tcp");
  551.86 +  struct servent *sv = NIL;
  551.87 +  port &= 0xffff;		/* erase flags */
  551.88 +  if (service) {		/* service specified? */
  551.89 +    if (*service == '*') {	/* yes, special alt driver kludge? */
  551.90 +      sv = getservbyname (service + 1,"tcp");
  551.91 +    }
  551.92 +    else sv = getservbyname (service,"tcp");
  551.93 +  }
  551.94 +				/* user service name port */
  551.95 +  if (sv) port = ntohs (sin.sin_port = sv->s_port);
  551.96 + 				/* copy port number in network format */
  551.97 +  else sin.sin_port = htons (port);
  551.98 +  /* The domain literal form is used (rather than simply the dotted decimal
  551.99 +     as with other Unix programs) because it has to be a valid "host name"
 551.100 +     in mailsystem terminology. */
 551.101 +				/* look like domain literal? */
 551.102 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
 551.103 +    strcpy (hostname,host+1);	/* yes, copy number part */
 551.104 +    hostname[(strlen (hostname))-1] = '\0';
 551.105 +    if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
 551.106 +      sin.sin_family = AF_INET;	/* family is always Internet */
 551.107 +      strcpy (hostname,host);	/* hostname is user's argument */
 551.108 +    }
 551.109 +    else {
 551.110 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
 551.111 +      mm_log (tmp,ERROR);
 551.112 +      return NIL;
 551.113 +    }
 551.114 +  }
 551.115 +
 551.116 +  else {			/* lookup host name, note that brain-dead Unix
 551.117 +				   requires lowercase! */
 551.118 +    strcpy (hostname,host);	/* in case host is in write-protected memory */
 551.119 +    if ((host_name = gethostbyname (lcase (hostname)))) {
 551.120 +				/* copy address type */
 551.121 +      sin.sin_family = host_name->h_addrtype;
 551.122 +				/* copy host name */
 551.123 +      strcpy (hostname,host_name->h_name);
 551.124 +				/* copy host addresses */
 551.125 +      memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
 551.126 +    }
 551.127 +    else {
 551.128 +      sprintf (tmp,"No such host as %.80s",host);
 551.129 +      mm_log (tmp,ERROR);
 551.130 +      return NIL;
 551.131 +    }
 551.132 +  }
 551.133 +				/* get a TCP stream */
 551.134 +  if ((sock = socket (sin.sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
 551.135 +    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
 551.136 +    mm_log (tmp,ERROR);
 551.137 +    return NIL;
 551.138 +  }
 551.139 +#if 0
 551.140 +  /* Maybe this test is necessary.  It depends upon how VMS implements
 551.141 +   * fd_set.  UNIX-style fd_set needs it; Windows-style does not.
 551.142 +   */
 551.143 +  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
 551.144 +    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
 551.145 +	     sock,FD_SETSIZE);
 551.146 +    close (sock);
 551.147 +    return NIL;
 551.148 +  }
 551.149 +#endif
 551.150 +				/* open connection */
 551.151 +  if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) {
 551.152 +    sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
 551.153 +	     strerror (errno));
 551.154 +    mm_log (tmp,ERROR);
 551.155 +    return NIL;
 551.156 +  }
 551.157 +				/* create TCP/IP stream */
 551.158 +  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
 551.159 +				/* copy official host name */
 551.160 +  stream->host = cpystr (hostname);
 551.161 +				/* get local name */
 551.162 +  gethostname (tmp,MAILTMPLEN-1);
 551.163 +  stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
 551.164 +			      host_name->h_name : tmp);
 551.165 +				/* init sockets */
 551.166 +  stream->port = port;		/* port number */
 551.167 +  stream->tcpsi = stream->tcpso = sock;
 551.168 +  stream->ictr = 0;		/* init input counter */
 551.169 +  return stream;		/* return success */
 551.170 +}
 551.171 +
 551.172 +/* TCP/IP authenticated open
 551.173 + * Accepts: NETMBX specifier
 551.174 + *	    service name
 551.175 + *	    returned user name buffer
 551.176 + * Returns: TCP/IP stream if success else NIL
 551.177 + */
 551.178 +
 551.179 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 551.180 +{
 551.181 +  return NIL;
 551.182 +}
 551.183 +
 551.184 +/* TCP receive line
 551.185 + * Accepts: TCP stream
 551.186 + * Returns: text line string or NIL if failure
 551.187 + */
 551.188 +
 551.189 +char *tcp_getline (TCPSTREAM *stream)
 551.190 +{
 551.191 +  unsigned long n,contd;
 551.192 +  char *ret = tcp_getline_work (stream,&n,&contd);
 551.193 +  if (ret && contd) {		/* got a line needing continuation? */
 551.194 +    STRINGLIST *stl = mail_newstringlist ();
 551.195 +    STRINGLIST *stc = stl;
 551.196 +    do {			/* collect additional lines */
 551.197 +      stc->text.data = (unsigned char *) ret;
 551.198 +      stc->text.size = n;
 551.199 +      stc = stc->next = mail_newstringlist ();
 551.200 +      ret = tcp_getline_work (stream,&n,&contd);
 551.201 +    } while (ret && contd);
 551.202 +    if (ret) {			/* stash final part of line on list */
 551.203 +      stc->text.data = (unsigned char *) ret;
 551.204 +      stc->text.size = n;
 551.205 +				/* determine how large a buffer we need */
 551.206 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 551.207 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 551.208 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 551.209 +	memcpy (ret + n,stc->text.data,stc->text.size);
 551.210 +      ret[n] = '\0';
 551.211 +    }
 551.212 +    mail_free_stringlist (&stl);/* either way, done with list */
 551.213 +  }
 551.214 +  return ret;
 551.215 +}
 551.216 +
 551.217 +/* TCP receive line or partial line
 551.218 + * Accepts: TCP stream
 551.219 + *	    pointer to return size
 551.220 + *	    pointer to return continuation flag
 551.221 + * Returns: text line string, size and continuation flag, or NIL if failure
 551.222 + */
 551.223 +
 551.224 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 551.225 +			       long *contd)
 551.226 +{
 551.227 +  unsigned long n;
 551.228 +  char *s,*ret,c,d;
 551.229 +  *contd = NIL;			/* assume no continuation */
 551.230 +				/* make sure have data */
 551.231 +  if (!tcp_getdata (stream)) return NIL;
 551.232 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 551.233 +    d = *stream->iptr++;	/* slurp another character */
 551.234 +    if ((c == '\015') && (d == '\012')) {
 551.235 +      ret = (char *) fs_get (n--);
 551.236 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 551.237 +      ret[n] = '\0';		/* tie off string with null */
 551.238 +      return ret;
 551.239 +    }
 551.240 +  }
 551.241 +				/* copy partial string from buffer */
 551.242 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 551.243 +				/* get more data from the net */
 551.244 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 551.245 +				/* special case of newline broken by buffer */
 551.246 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 551.247 +    stream->iptr++;		/* eat the line feed */
 551.248 +    stream->ictr--;
 551.249 +    ret[*size = --n] = '\0';	/* tie off string with null */
 551.250 +  }
 551.251 +  else *contd = LONGT;		/* continuation needed */
 551.252 +  return ret;
 551.253 +}
 551.254 +
 551.255 +/* TCP/IP receive buffer
 551.256 + * Accepts: TCP/IP stream
 551.257 + *	    size in bytes
 551.258 + *	    buffer to read into
 551.259 + * Returns: T if success, NIL otherwise
 551.260 + */
 551.261 +
 551.262 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
 551.263 +{
 551.264 +  unsigned long n;
 551.265 +  char *bufptr = buffer;
 551.266 +  while (size > 0) {		/* until request satisfied */
 551.267 +    if (!tcp_getdata (stream)) return NIL;
 551.268 +    n = min (size,stream->ictr);/* number of bytes to transfer */
 551.269 +				/* do the copy */
 551.270 +    memcpy (bufptr,stream->iptr,n);
 551.271 +    bufptr += n;		/* update pointer */
 551.272 +    stream->iptr +=n;
 551.273 +    size -= n;			/* update # of bytes to do */
 551.274 +    stream->ictr -=n;
 551.275 +  }
 551.276 +  bufptr[0] = '\0';		/* tie off string */
 551.277 +  return T;
 551.278 +}
 551.279 +
 551.280 +/* TCP/IP receive data
 551.281 + * Accepts: TCP/IP stream
 551.282 + * Returns: T if success, NIL otherwise
 551.283 + */
 551.284 +
 551.285 +long tcp_getdata (TCPSTREAM *stream)
 551.286 +{
 551.287 +  int i;
 551.288 +  fd_set fds,efds;
 551.289 +  struct timeval tmo;
 551.290 +  time_t t = time (0);
 551.291 +  if (stream->tcpsi < 0) return NIL;
 551.292 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 551.293 +    time_t tl = time (0);	/* start of request */
 551.294 +    tmo.tv_sec = ttmo_read;	/* read timeout */
 551.295 +    tmo.tv_usec = 0;
 551.296 +    FD_ZERO (&fds);		/* initialize selection vector */
 551.297 +    FD_ZERO (&efds);		/* handle errors too */
 551.298 +    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
 551.299 +    FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */
 551.300 +    errno = NIL;		/* block and read */
 551.301 +    while (((i = select (getdtablesize (),&fds,0,&efds,ttmo_read ? &tmo:0))<0)
 551.302 +	   && (errno == EINTR));
 551.303 +    if (!i) {			/* timeout? */
 551.304 +      time_t tc = time (0);
 551.305 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
 551.306 +      else return tcp_abort (stream);
 551.307 +    }
 551.308 +    else if (i < 0) return tcp_abort (stream);
 551.309 +    while (((i = socket_read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
 551.310 +	   (errno == EINTR));
 551.311 +    if (i < 1) return tcp_abort (stream);
 551.312 +    stream->iptr = stream->ibuf;/* point at TCP buffer */
 551.313 +    stream->ictr = i;		/* set new byte count */
 551.314 +  }
 551.315 +  return T;
 551.316 +}
 551.317 +
 551.318 +/* TCP/IP send string as record
 551.319 + * Accepts: TCP/IP stream
 551.320 + *	    string pointer
 551.321 + * Returns: T if success else NIL
 551.322 + */
 551.323 +
 551.324 +long tcp_soutr (TCPSTREAM *stream,char *string)
 551.325 +{
 551.326 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 551.327 +}
 551.328 +
 551.329 +
 551.330 +/* TCP/IP send string
 551.331 + * Accepts: TCP/IP stream
 551.332 + *	    string pointer
 551.333 + *	    byte count
 551.334 + * Returns: T if success else NIL
 551.335 + */
 551.336 +
 551.337 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 551.338 +{
 551.339 +  int i;
 551.340 +  fd_set fds;
 551.341 +  struct timeval tmo;
 551.342 +  time_t t = time (0);
 551.343 +  if (stream->tcpso < 0) return NIL;
 551.344 +  while (size > 0) {		/* until request satisfied */
 551.345 +    time_t tl = time (0);	/* start of request */
 551.346 +    tmo.tv_sec = ttmo_write;	/* write timeout */
 551.347 +    tmo.tv_usec = 0;
 551.348 +    FD_ZERO (&fds);		/* initialize selection vector */
 551.349 +    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
 551.350 +    errno = NIL;		/* block and write */
 551.351 +    while (((i = select (getdtablesize (),0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
 551.352 +	   && (errno == EINTR));
 551.353 +    if (!i) {			/* timeout? */
 551.354 +      time_t tc = time (0);
 551.355 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
 551.356 +      else return tcp_abort (stream);
 551.357 +    }
 551.358 +    else if (i < 0) return tcp_abort (stream);
 551.359 +    while (((i = socket_write (stream->tcpso,string,size)) < 0) &&
 551.360 +	   (errno == EINTR));
 551.361 +    if (i < 0) return tcp_abort (stream);
 551.362 +    size -= i;			/* how much we sent */
 551.363 +    string += i;
 551.364 +  }
 551.365 +  return T;			/* all done */
 551.366 +}
 551.367 +
 551.368 +/* TCP/IP close
 551.369 + * Accepts: TCP/IP stream
 551.370 + */
 551.371 +
 551.372 +void tcp_close (TCPSTREAM *stream)
 551.373 +{
 551.374 +  tcp_abort (stream);		/* nuke the stream */
 551.375 +				/* flush host names */
 551.376 +  fs_give ((void **) &stream->host);
 551.377 +  fs_give ((void **) &stream->localhost);
 551.378 +  fs_give ((void **) &stream);	/* flush the stream */
 551.379 +}
 551.380 +
 551.381 +
 551.382 +/* TCP/IP abort stream
 551.383 + * Accepts: TCP/IP stream
 551.384 + * Returns: NIL always
 551.385 + */
 551.386 +
 551.387 +long tcp_abort (TCPSTREAM *stream)
 551.388 +{
 551.389 +  int i;
 551.390 +  if (stream->tcpsi >= 0) {	/* no-op if no socket */
 551.391 +				/* nuke the socket */
 551.392 +    socket_close (stream->tcpsi);
 551.393 +    if (stream->tcpsi != stream->tcpso) socket_close (stream->tcpso);
 551.394 +    stream->tcpsi = stream->tcpso = -1;
 551.395 +  }
 551.396 +  return NIL;
 551.397 +}
 551.398 +
 551.399 +/* TCP/IP get host name
 551.400 + * Accepts: TCP/IP stream
 551.401 + * Returns: host name for this stream
 551.402 + */
 551.403 +
 551.404 +char *tcp_host (TCPSTREAM *stream)
 551.405 +{
 551.406 +  return stream->host;		/* return host name */
 551.407 +}
 551.408 +
 551.409 +
 551.410 +/* TCP/IP get remote host name
 551.411 + * Accepts: TCP/IP stream
 551.412 + * Returns: host name for this stream
 551.413 + */
 551.414 +
 551.415 +char *tcp_remotehost (TCPSTREAM *stream)
 551.416 +{
 551.417 +  return stream->host;		/* return host name */
 551.418 +}
 551.419 +
 551.420 +
 551.421 +/* TCP/IP return port for this stream
 551.422 + * Accepts: TCP/IP stream
 551.423 + * Returns: port number for this stream
 551.424 + */
 551.425 +
 551.426 +unsigned long tcp_port (TCPSTREAM *stream)
 551.427 +{
 551.428 +  return stream->port;		/* return port number */
 551.429 +}
 551.430 +
 551.431 +
 551.432 +/* TCP/IP get local host name
 551.433 + * Accepts: TCP/IP stream
 551.434 + * Returns: local host name
 551.435 + */
 551.436 +
 551.437 +char *tcp_localhost (TCPSTREAM *stream)
 551.438 +{
 551.439 +  return stream->localhost;	/* return local host name */
 551.440 +}
 551.441 +
 551.442 +/* Return my local host name
 551.443 + * Returns: my local host name
 551.444 + */
 551.445 +
 551.446 +char *mylocalhost ()
 551.447 +{
 551.448 +  char tmp[MAILTMPLEN];
 551.449 +  struct hostent *hn;
 551.450 +  if (!myLocalHost) {		/* have local host yet? */
 551.451 +    gethostname(tmp,MAILTMPLEN);/* get local host name */
 551.452 +    myLocalHost = cpystr ((hn = gethostbyname (tmp)) ? hn->h_name : tmp);
 551.453 +  }
 551.454 +  return myLocalHost;
 551.455 +}
 551.456 +
 551.457 +
 551.458 +/* TCP/IP return canonical form of host name
 551.459 + * Accepts: host name
 551.460 + * Returns: canonical form of host name
 551.461 + */
 551.462 +
 551.463 +char *tcp_canonical (char *name)
 551.464 +{
 551.465 +  char host[MAILTMPLEN];
 551.466 +  struct hostent *he;
 551.467 +				/* look like domain literal? */
 551.468 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 551.469 +				/* note that Unix requires lowercase! */
 551.470 +  else return (he = gethostbyname (lcase (strcpy (host,name)))) ?
 551.471 +    he->h_name : name;
 551.472 +}
 551.473 +
 551.474 +
 551.475 +/* TCP/IP get client host name (server calls only)
 551.476 + * Returns: client host name
 551.477 + */
 551.478 +
 551.479 +char *tcp_clienthost ()
 551.480 +{
 551.481 +  return "UNKNOWN";
 551.482 +}
   552.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   552.2 +++ b/src/osdep/vms/tcp_vmsn.c	Mon Sep 14 15:17:45 2009 +0900
   552.3 @@ -0,0 +1,222 @@
   552.4 +/* ========================================================================
   552.5 + * Copyright 1988-2006 University of Washington
   552.6 + *
   552.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   552.8 + * you may not use this file except in compliance with the License.
   552.9 + * You may obtain a copy of the License at
  552.10 + *
  552.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  552.12 + *
  552.13 + * 
  552.14 + * ========================================================================
  552.15 + */
  552.16 +
  552.17 +/*
  552.18 + * Program:	Dummy VMS TCP/IP routines for non-TCP/IP systems
  552.19 + *
  552.20 + * Author:	Mark Crispin
  552.21 + *		Networks and Distributed Computing
  552.22 + *		Computing & Communications
  552.23 + *		University of Washington
  552.24 + *		Administration Building, AG-44
  552.25 + *		Seattle, WA  98195
  552.26 + *		Internet: MRC@CAC.Washington.EDU
  552.27 + *
  552.28 + * Date:	2 August 1994
  552.29 + * Last Edited:	30 August 2006
  552.30 + */
  552.31 + 
  552.32 +/* TCP/IP manipulate parameters
  552.33 + * Accepts: function code
  552.34 + *	    function-dependent value
  552.35 + * Returns: function-dependent return value
  552.36 + */
  552.37 +
  552.38 +void *tcp_parameters (long function,void *value)
  552.39 +{
  552.40 +  return NIL;
  552.41 +}
  552.42 +
  552.43 +
  552.44 +/* TCP/IP open
  552.45 + * Accepts: host name
  552.46 + *	    contact service name
  552.47 + *	    contact port number
  552.48 + * Returns: TCP/IP stream if success else NIL
  552.49 + */
  552.50 +
  552.51 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  552.52 +{
  552.53 +  char tmp[MAILTMPLEN];
  552.54 +  port &= 0xffff;		/* erase flags */
  552.55 +  if (port) sprintf (tmp,"Can't connect to %.80s,%d: no TCP",host,port);
  552.56 +  else sprintf (tmp,"Can't connect to %.80s,%s: no TCP",host,service);
  552.57 +  mm_log (tmp,ERROR);
  552.58 +  return NIL;
  552.59 +}
  552.60 +
  552.61 +
  552.62 +/* TCP/IP authenticated open
  552.63 + * Accepts: NETMBX specifier
  552.64 + *	    service name
  552.65 + *	    returned user name buffer
  552.66 + * Returns: TCP/IP stream if success else NIL
  552.67 + */
  552.68 +
  552.69 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
  552.70 +{
  552.71 +  return NIL;
  552.72 +}
  552.73 +
  552.74 +/* TCP/IP receive line
  552.75 + * Accepts: TCP/IP stream
  552.76 + * Returns: text line string or NIL if failure
  552.77 + */
  552.78 +
  552.79 +char *tcp_getline (TCPSTREAM *stream)
  552.80 +{
  552.81 +  return NIL;
  552.82 +}
  552.83 +
  552.84 +
  552.85 +/* TCP/IP receive buffer
  552.86 + * Accepts: TCP/IP stream
  552.87 + *	    size in bytes
  552.88 + *	    buffer to read into
  552.89 + * Returns: T if success, NIL otherwise
  552.90 + */
  552.91 +
  552.92 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  552.93 +{
  552.94 +  return NIL;
  552.95 +}
  552.96 +
  552.97 +
  552.98 +/* TCP/IP receive data
  552.99 + * Accepts: TCP/IP stream
 552.100 + * Returns: T if success, NIL otherwise
 552.101 + */
 552.102 +
 552.103 +long tcp_getdata (TCPSTREAM *stream)
 552.104 +{
 552.105 +  return NIL;
 552.106 +}
 552.107 +
 552.108 +/* TCP/IP send string as record
 552.109 + * Accepts: TCP/IP stream
 552.110 + *	    string pointer
 552.111 + * Returns: T if success else NIL
 552.112 + */
 552.113 +
 552.114 +long tcp_soutr (TCPSTREAM *stream,char *string)
 552.115 +{
 552.116 +  return NIL;
 552.117 +}
 552.118 +
 552.119 +
 552.120 +/* TCP/IP send string
 552.121 + * Accepts: TCP/IP stream
 552.122 + *	    string pointer
 552.123 + *	    byte count
 552.124 + * Returns: T if success else NIL
 552.125 + */
 552.126 +
 552.127 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 552.128 +{
 552.129 +  return NIL;
 552.130 +}
 552.131 +
 552.132 +
 552.133 +/* TCP/IP close
 552.134 + * Accepts: TCP/IP stream
 552.135 + */
 552.136 +
 552.137 +void tcp_close (TCPSTREAM *stream)
 552.138 +{
 552.139 +}
 552.140 +
 552.141 +
 552.142 +/* TCP/IP abort stream
 552.143 + * Accepts: TCP/IP stream
 552.144 + * Returns: NIL always
 552.145 + */
 552.146 +
 552.147 +long tcp_abort (TCPSTREAM *stream)
 552.148 +{
 552.149 +  return NIL;
 552.150 +}
 552.151 +
 552.152 +/* TCP/IP get host name
 552.153 + * Accepts: TCP/IP stream
 552.154 + * Returns: host name for this stream
 552.155 + */
 552.156 +
 552.157 +char *tcp_host (TCPSTREAM *stream)
 552.158 +{
 552.159 +  return NIL;
 552.160 +}
 552.161 +
 552.162 +
 552.163 +/* TCP/IP get remote host name
 552.164 + * Accepts: TCP/IP stream
 552.165 + * Returns: host name for this stream
 552.166 + */
 552.167 +
 552.168 +char *tcp_remotehost (TCPSTREAM *stream)
 552.169 +{
 552.170 +  return NIL;
 552.171 +}
 552.172 +
 552.173 +
 552.174 +/* TCP/IP get local host name
 552.175 + * Accepts: TCP/IP stream
 552.176 + * Returns: local host name
 552.177 + */
 552.178 +
 552.179 +char *tcp_localhost (TCPSTREAM *stream)
 552.180 +{
 552.181 +  return NIL;
 552.182 +}
 552.183 +
 552.184 +
 552.185 +/* TCP/IP return port for this stream
 552.186 + * Accepts: TCP/IP stream
 552.187 + * Returns: port number for this stream
 552.188 + */
 552.189 +
 552.190 +unsigned long tcp_port (TCPSTREAM *stream)
 552.191 +{
 552.192 +  return 0xffffffff;		/* return port number */
 552.193 +}
 552.194 +
 552.195 +
 552.196 +/* Return my local host name
 552.197 + * Returns: my local host name
 552.198 + */
 552.199 +
 552.200 +char *mylocalhost ()
 552.201 +{
 552.202 +				/* have local host yet? */
 552.203 +  if (!myLocalHost) myLocalHost = cpystr (getenv ("SYS$NODE"));
 552.204 +  return myLocalHost;
 552.205 +}
 552.206 +
 552.207 +/* TCP/IP return canonical form of host name
 552.208 + * Accepts: host name
 552.209 + * Returns: canonical form of host name
 552.210 + */
 552.211 +
 552.212 +char *tcp_canonical (char *name)
 552.213 +{
 552.214 +  return name;
 552.215 +}
 552.216 +
 552.217 +
 552.218 +/* TCP/IP get client host name (server calls only)
 552.219 + * Returns: client host name
 552.220 + */
 552.221 +
 552.222 +char *tcp_clienthost ()
 552.223 +{
 552.224 +  return "UNKNOWN";
 552.225 +}
   553.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   553.2 +++ b/src/osdep/wce/drivers.bat	Mon Sep 14 15:17:45 2009 +0900
   553.3 @@ -0,0 +1,33 @@
   553.4 +@ECHO OFF
   553.5 +REM ========================================================================
   553.6 +REM Copyright 1988-2006 University of Washington
   553.7 +REM
   553.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   553.9 +REM you may not use this file except in compliance with the License.
  553.10 +REM You may obtain a copy of the License at
  553.11 +REM
  553.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  553.13 +REM
  553.14 +REM 
  553.15 +REM ========================================================================
  553.16 +
  553.17 +REM Program:	Driver Linkage Generator for DOS/NT
  553.18 +REM
  553.19 +REM Author:	Mark Crispin
  553.20 +REM		Networks and Distributed Computing
  553.21 +REM		Computing & Communications
  553.22 +REM		University of Washington
  553.23 +REM		Administration Building, AG-44
  553.24 +REM		Seattle, WA  98195
  553.25 +REM		Internet: MRC@CAC.Washington.EDU
  553.26 +REM
  553.27 +REM Date:	11 October 1989
  553.28 +REM Last Edited:30 August 2006
  553.29 +
  553.30 +REM Erase old driver linkage
  553.31 +IF EXIST LINKAGE.* DEL LINKAGE.*
  553.32 +
  553.33 +REM Now define the new list
  553.34 +FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
  553.35 +
  553.36 +EXIT 0
   554.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   554.2 +++ b/src/osdep/wce/drivraux.bat	Mon Sep 14 15:17:45 2009 +0900
   554.3 @@ -0,0 +1,30 @@
   554.4 +@ECHO OFF
   554.5 +REM ========================================================================
   554.6 +REM Copyright 1988-2006 University of Washington
   554.7 +REM
   554.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   554.9 +REM you may not use this file except in compliance with the License.
  554.10 +REM You may obtain a copy of the License at
  554.11 +REM
  554.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  554.13 +REM
  554.14 +REM 
  554.15 +REM ========================================================================
  554.16 +
  554.17 +REM Program:	Driver Linkage Generator auxillary for NT/Win9x
  554.18 +REM
  554.19 +REM Author:	Mark Crispin
  554.20 +REM		Networks and Distributed Computing
  554.21 +REM		Computing & Communications
  554.22 +REM		University of Washington
  554.23 +REM		Administration Building, AG-44
  554.24 +REM		Seattle, WA  98195
  554.25 +REM		Internet: MRC@CAC.Washington.EDU
  554.26 +REM
  554.27 +REM Date:	11 October 1989
  554.28 +REM Last Edited:30 August 2006
  554.29 +
  554.30 +ECHO extern DRIVER %1driver; >> LINKAGE.H
  554.31 +REM Note the introduction of the caret to quote the ampersand in NT
  554.32 +if "%OS%" == "Windows_NT" ECHO   mail_link (^&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
  554.33 +if "%OS%" == "" ECHO   mail_link (&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
   555.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   555.2 +++ b/src/osdep/wce/dummy.h	Mon Sep 14 15:17:45 2009 +0900
   555.3 @@ -0,0 +1,43 @@
   555.4 +/* ========================================================================
   555.5 + * Copyright 1988-2006 University of Washington
   555.6 + *
   555.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   555.8 + * you may not use this file except in compliance with the License.
   555.9 + * You may obtain a copy of the License at
  555.10 + *
  555.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  555.12 + *
  555.13 + * 
  555.14 + * ========================================================================
  555.15 + */
  555.16 +
  555.17 +/*
  555.18 + * Program:	Dummy routines
  555.19 + *
  555.20 + * Author:	Mark Crispin
  555.21 + *		Networks and Distributed Computing
  555.22 + *		Computing & Communications
  555.23 + *		University of Washington
  555.24 + *		Administration Building, AG-44
  555.25 + *		Seattle, WA  98195
  555.26 + *		Internet: MRC@CAC.Washington.EDU
  555.27 + *
  555.28 + * Date:	9 May 1991
  555.29 + * Last Edited:	30 August 2006
  555.30 + */
  555.31 +
  555.32 +/* Exported function prototypes */
  555.33 +
  555.34 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
  555.35 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
  555.36 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
  555.37 +long scan_contents (DRIVER *dtb,char *name,char *contents,
  555.38 +		    unsigned long csiz,unsigned long fsiz);
  555.39 +long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
  555.40 +			  unsigned long fsiz);
  555.41 +long dummy_create (MAILSTREAM *stream,char *mailbox);
  555.42 +long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
  555.43 +long dummy_delete (MAILSTREAM *stream,char *mailbox);
  555.44 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
  555.45 +char *dummy_file (char *dst,char *name);
  555.46 +long dummy_canonicalize (char *tmp,char *ref,char *pat);
   556.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   556.2 +++ b/src/osdep/wce/dummywce.c	Mon Sep 14 15:17:45 2009 +0900
   556.3 @@ -0,0 +1,301 @@
   556.4 +/* ========================================================================
   556.5 + * Copyright 1988-2006 University of Washington
   556.6 + *
   556.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   556.8 + * you may not use this file except in compliance with the License.
   556.9 + * You may obtain a copy of the License at
  556.10 + *
  556.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  556.12 + *
  556.13 + * 
  556.14 + * ========================================================================
  556.15 + */
  556.16 +
  556.17 +/*
  556.18 + * Program:	Dummy routines for WCE
  556.19 + *
  556.20 + * Author:	Mark Crispin
  556.21 + *		Networks and Distributed Computing
  556.22 + *		Computing & Communications
  556.23 + *		University of Washington
  556.24 + *		Administration Building, AG-44
  556.25 + *		Seattle, WA  98195
  556.26 + *		Internet: MRC@CAC.Washington.EDU
  556.27 + *
  556.28 + * Date:	24 May 1993
  556.29 + * Last Edited:	30 August 2006
  556.30 + */
  556.31 +
  556.32 +
  556.33 +#include <ctype.h>
  556.34 +#include <stdio.h>
  556.35 +#include <errno.h>
  556.36 +#include <fcntl.h>
  556.37 +#include <direct.h>
  556.38 +#include "mail.h"
  556.39 +#include "osdep.h"
  556.40 +#include <sys\stat.h>
  556.41 +#include <dos.h>
  556.42 +#include "dummy.h"
  556.43 +#include "misc.h"
  556.44 +
  556.45 +/* Function prototypes */
  556.46 +
  556.47 +DRIVER *dummy_valid (char *name);
  556.48 +void *dummy_parameters (long function,void *value);
  556.49 +MAILSTREAM *dummy_open (MAILSTREAM *stream);
  556.50 +void dummy_close (MAILSTREAM *stream,long options);
  556.51 +long dummy_ping (MAILSTREAM *stream);
  556.52 +void dummy_check (MAILSTREAM *stream);
  556.53 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
  556.54 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
  556.55 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
  556.56 +
  556.57 +/* Dummy routines */
  556.58 +
  556.59 +
  556.60 +/* Driver dispatch used by MAIL */
  556.61 +
  556.62 +DRIVER dummydriver = {
  556.63 +  "dummy",			/* driver name */
  556.64 +  DR_LOCAL|DR_MAIL,		/* driver flags */
  556.65 +  (DRIVER *) NIL,		/* next driver */
  556.66 +  dummy_valid,			/* mailbox is valid for us */
  556.67 +  dummy_parameters,		/* manipulate parameters */
  556.68 +  dummy_scan,			/* scan mailboxes */
  556.69 +  dummy_list,			/* list mailboxes */
  556.70 +  dummy_lsub,			/* list subscribed mailboxes */
  556.71 +  NIL,				/* subscribe to mailbox */
  556.72 +  NIL,				/* unsubscribe from mailbox */
  556.73 +  dummy_create,			/* create mailbox */
  556.74 +  dummy_delete,			/* delete mailbox */
  556.75 +  dummy_rename,			/* rename mailbox */
  556.76 +  mail_status_default,		/* status of mailbox */
  556.77 +  dummy_open,			/* open mailbox */
  556.78 +  dummy_close,			/* close mailbox */
  556.79 +  NIL,				/* fetch message "fast" attributes */
  556.80 +  NIL,				/* fetch message flags */
  556.81 +  NIL,				/* fetch overview */
  556.82 +  NIL,				/* fetch message structure */
  556.83 +  NIL,				/* fetch header */
  556.84 +  NIL,				/* fetch text */
  556.85 +  NIL,				/* fetch message data */
  556.86 +  NIL,				/* unique identifier */
  556.87 +  NIL,				/* message number from UID */
  556.88 +  NIL,				/* modify flags */
  556.89 +  NIL,				/* per-message modify flags */
  556.90 +  NIL,				/* search for message based on criteria */
  556.91 +  NIL,				/* sort messages */
  556.92 +  NIL,				/* thread messages */
  556.93 +  dummy_ping,			/* ping mailbox to see if still alive */
  556.94 +  dummy_check,			/* check for new messages */
  556.95 +  dummy_expunge,		/* expunge deleted messages */
  556.96 +  dummy_copy,			/* copy messages to another mailbox */
  556.97 +  dummy_append,			/* append string message to mailbox */
  556.98 +  NIL				/* garbage collect stream */
  556.99 +};
 556.100 +
 556.101 +
 556.102 +				/* prototype stream */
 556.103 +MAILSTREAM dummyproto = {&dummydriver};
 556.104 +
 556.105 +				/* driver parameters */
 556.106 +static char *file_extension = NIL;
 556.107 +
 556.108 +/* Dummy validate mailbox
 556.109 + * Accepts: mailbox name
 556.110 + * Returns: our driver if name is valid, NIL otherwise
 556.111 + */
 556.112 +
 556.113 +DRIVER *dummy_valid (char *name)
 556.114 +{
 556.115 +  char *s,tmp[MAILTMPLEN];
 556.116 +  struct stat sbuf;
 556.117 +				/* must be valid local mailbox */
 556.118 +  return (name && *name && (*name != '{') &&
 556.119 +	  (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ?
 556.120 +	    &dummydriver : NIL;
 556.121 +}
 556.122 +
 556.123 +
 556.124 +/* Dummy manipulate driver parameters
 556.125 + * Accepts: function code
 556.126 + *	    function-dependent value
 556.127 + * Returns: function-dependent return value
 556.128 + */
 556.129 +
 556.130 +void *dummy_parameters (long function,void *value)
 556.131 +{
 556.132 +  return value;
 556.133 +}
 556.134 +
 556.135 +/* Dummy scan mailboxes
 556.136 + * Accepts: mail stream
 556.137 + *	    reference
 556.138 + *	    pattern to search
 556.139 + *	    string to scan
 556.140 + */
 556.141 +
 556.142 +void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
 556.143 +{
 556.144 +				/* return silently */
 556.145 +}
 556.146 +
 556.147 +/* Dummy list mailboxes
 556.148 + * Accepts: mail stream
 556.149 + *	    reference
 556.150 + *	    pattern to search
 556.151 + */
 556.152 +
 556.153 +void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
 556.154 +{
 556.155 +				/* return silently */
 556.156 +}
 556.157 +
 556.158 +
 556.159 +/* Dummy list subscribed mailboxes
 556.160 + * Accepts: mail stream
 556.161 + *	    pattern to search
 556.162 + */
 556.163 +
 556.164 +void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
 556.165 +{
 556.166 +				/* return silently */
 556.167 +}
 556.168 +
 556.169 +/* Dummy create mailbox
 556.170 + * Accepts: mail stream
 556.171 + *	    mailbox name to create
 556.172 + * Returns: T on success, NIL on failure
 556.173 + */
 556.174 +
 556.175 +long dummy_create (MAILSTREAM *stream,char *mailbox)
 556.176 +{
 556.177 +  return NIL;			/* always fails */
 556.178 +}
 556.179 +
 556.180 +
 556.181 +/* Dummy delete mailbox
 556.182 + * Accepts: mail stream
 556.183 + *	    mailbox name to delete
 556.184 + * Returns: T on success, NIL on failure
 556.185 + */
 556.186 +
 556.187 +long dummy_delete (MAILSTREAM *stream,char *mailbox)
 556.188 +{
 556.189 +  return NIL;			/* always fails */
 556.190 +}
 556.191 +
 556.192 +
 556.193 +/* Mail rename mailbox
 556.194 + * Accepts: mail stream
 556.195 + *	    old mailbox name
 556.196 + *	    new mailbox name
 556.197 + * Returns: T on success, NIL on failure
 556.198 + */
 556.199 +
 556.200 +long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
 556.201 +{
 556.202 +  return NIL;			/* always fails */
 556.203 +}
 556.204 +
 556.205 +/* Dummy open
 556.206 + * Accepts: stream to open
 556.207 + * Returns: stream on success, NIL on failure
 556.208 + */
 556.209 +
 556.210 +MAILSTREAM *dummy_open (MAILSTREAM *stream)
 556.211 +{
 556.212 +  char tmp[MAILTMPLEN];
 556.213 +				/* OP_PROTOTYPE call or silence */
 556.214 +  if (!stream || stream->silent) return NIL;
 556.215 +  if (compare_cstring (stream->mailbox,"INBOX")) {
 556.216 +    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
 556.217 +    mm_log (tmp,ERROR);
 556.218 +    return NIL;			/* always fails */
 556.219 +  }
 556.220 +  if (!stream->silent) {	/* only if silence not requested */
 556.221 +    mail_exists (stream,0);	/* say there are 0 messages */
 556.222 +    mail_recent (stream,0);
 556.223 +    stream->uid_validity = time (0);
 556.224 +  }
 556.225 +  stream->inbox = T;		/* note that it's an INBOX */
 556.226 +  return stream;		/* return success */
 556.227 +}
 556.228 +
 556.229 +
 556.230 +/* Dummy close
 556.231 + * Accepts: MAIL stream
 556.232 + *	    options
 556.233 + */
 556.234 +
 556.235 +void dummy_close (MAILSTREAM *stream,long options)
 556.236 +{
 556.237 +				/* return silently */
 556.238 +}
 556.239 +
 556.240 +/* Dummy ping mailbox
 556.241 + * Accepts: MAIL stream
 556.242 + * Returns: T if stream alive, else NIL
 556.243 + * No-op for readonly files, since read/writer can expunge it from under us!
 556.244 + */
 556.245 +
 556.246 +long dummy_ping (MAILSTREAM *stream)
 556.247 +{
 556.248 +  return T;
 556.249 +}
 556.250 +
 556.251 +
 556.252 +/* Dummy check mailbox
 556.253 + * Accepts: MAIL stream
 556.254 + * No-op for readonly files, since read/writer can expunge it from under us!
 556.255 + */
 556.256 +
 556.257 +void dummy_check (MAILSTREAM *stream)
 556.258 +{
 556.259 +  dummy_ping (stream);		/* invoke ping */
 556.260 +}
 556.261 +
 556.262 +
 556.263 +/* Dummy expunge mailbox
 556.264 + * Accepts: MAIL stream
 556.265 + *	    sequence to expunge if non-NIL
 556.266 + *	    expunge options
 556.267 + * Returns: T, always
 556.268 + */
 556.269 +
 556.270 +long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
 556.271 +{
 556.272 +  return LONGT;
 556.273 +}
 556.274 +
 556.275 +/* Dummy copy message(s)
 556.276 + * Accepts: MAIL stream
 556.277 + *	    sequence
 556.278 + *	    destination mailbox
 556.279 + *	    options
 556.280 + * Returns: T if copy successful, else NIL
 556.281 + */
 556.282 +
 556.283 +long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
 556.284 +{
 556.285 +  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
 556.286 +      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
 556.287 +  return NIL;
 556.288 +}
 556.289 +
 556.290 +
 556.291 +/* Dummy append message string
 556.292 + * Accepts: mail stream
 556.293 + *	    destination mailbox
 556.294 + *	    stringstruct of message to append
 556.295 + * Returns: T on success, NIL on failure
 556.296 + */
 556.297 +
 556.298 +long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
 556.299 +{
 556.300 +  char tmp[MAILTMPLEN];
 556.301 +  sprintf (tmp,"Can't append to %s",mailbox);
 556.302 +  mm_log (tmp,ERROR);		/* pass up error */
 556.303 +  return NIL;			/* always fails */
 556.304 +}
   557.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   557.2 +++ b/src/osdep/wce/env_wce.c	Mon Sep 14 15:17:45 2009 +0900
   557.3 @@ -0,0 +1,301 @@
   557.4 +/* ========================================================================
   557.5 + * Copyright 1988-2006 University of Washington
   557.6 + *
   557.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   557.8 + * you may not use this file except in compliance with the License.
   557.9 + * You may obtain a copy of the License at
  557.10 + *
  557.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  557.12 + *
  557.13 + * 
  557.14 + * ========================================================================
  557.15 + */
  557.16 +
  557.17 +/*
  557.18 + * Program:	WCE environment routines
  557.19 + *
  557.20 + * Author:	Mark Crispin
  557.21 + *		Networks and Distributed Computing
  557.22 + *		Computing & Communications
  557.23 + *		University of Washington
  557.24 + *		Administration Building, AG-44
  557.25 + *		Seattle, WA  98195
  557.26 + *		Internet: MRC@CAC.Washington.EDU
  557.27 + *
  557.28 + * Date:	1 August 1988
  557.29 + * Last Edited:	30 August 2006
  557.30 + */
  557.31 +
  557.32 +
  557.33 +static char *myUserName = NIL;	/* user name */
  557.34 +static char *myLocalHost = NIL;	/* local host name */
  557.35 +static char *myClientHost = NIL;/* client host name */
  557.36 +static char *myServerHost = NIL;/* server host name */
  557.37 +static char *myHomeDir = NIL;	/* home directory name */
  557.38 +static char *myNewsrc = NIL;	/* newsrc file name */
  557.39 +static char *sysInbox = NIL;	/* system inbox name */
  557.40 +static long list_max_level = 5;	/* maximum level of list recursion */
  557.41 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
  557.42 +				/* home namespace */
  557.43 +static NAMESPACE nshome = {"",'\\',NIL,NIL};
  557.44 +				/* namespace list */
  557.45 +static NAMESPACE *nslist[3] = {&nshome,NIL,NIL};
  557.46 +static long alarm_countdown = 0;/* alarm count down */
  557.47 +static void (*alarm_rang) ();	/* alarm interrupt function */
  557.48 +static unsigned int rndm = 0;	/* initial `random' number */
  557.49 +
  557.50 +
  557.51 +/* Dummy definitions to prevent errors */
  557.52 +
  557.53 +#define server_login(user,pass,authuser,argc,argv) NIL
  557.54 +#define authserver_login(user,authuser,argc,argv) NIL
  557.55 +#define myusername() ""
  557.56 +#define MD5ENABLE "\\.nosuch.."
  557.57 +
  557.58 +#include "pmatch.c"		/* include wildcard pattern matcher */
  557.59 +
  557.60 +/* Environment manipulate parameters
  557.61 + * Accepts: function code
  557.62 + *	    function-dependent value
  557.63 + * Returns: function-dependent return value
  557.64 + */
  557.65 +
  557.66 +void *env_parameters (long function,void *value)
  557.67 +{
  557.68 +  void *ret = NIL;
  557.69 +  switch ((int) function) {
  557.70 +  case GET_NAMESPACE:
  557.71 +    ret = (void *) nslist;
  557.72 +    break;
  557.73 +  case SET_HOMEDIR:
  557.74 +    myHomeDir = cpystr ((char *) value);
  557.75 +  case GET_HOMEDIR:
  557.76 +    ret = (void *) myHomeDir;
  557.77 +    break;
  557.78 +  case SET_LOCALHOST:
  557.79 +    myLocalHost = cpystr ((char *) value);
  557.80 +  case GET_LOCALHOST:
  557.81 +    ret = (void *) myLocalHost;
  557.82 +    break;
  557.83 +  case SET_NEWSRC:
  557.84 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
  557.85 +    myNewsrc = cpystr ((char *) value);
  557.86 +  case GET_NEWSRC:
  557.87 +    if (!myNewsrc) {		/* set news file name if not defined */
  557.88 +      char tmp[MAILTMPLEN];
  557.89 +      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
  557.90 +      myNewsrc = cpystr (tmp);
  557.91 +    }
  557.92 +    ret = (void *) myNewsrc;
  557.93 +    break;
  557.94 +  case SET_SYSINBOX:
  557.95 +    if (sysInbox) fs_give ((void **) &sysInbox);
  557.96 +    sysInbox = cpystr ((char *) value);
  557.97 +  case GET_SYSINBOX:
  557.98 +    ret = (void *) sysInbox;
  557.99 +    break;
 557.100 +  case SET_LISTMAXLEVEL:
 557.101 +    list_max_level = (long) value;
 557.102 +  case GET_LISTMAXLEVEL:
 557.103 +    ret = (void *) list_max_level;
 557.104 +    break;
 557.105 +  case SET_DISABLE822TZTEXT:
 557.106 +    no822tztext = value ? T : NIL;
 557.107 +  case GET_DISABLE822TZTEXT:
 557.108 +    ret = (void *) (no822tztext ? VOIDT : NIL);
 557.109 +    break;
 557.110 +  }
 557.111 +  return ret;
 557.112 +}
 557.113 +
 557.114 +/* Write current time
 557.115 + * Accepts: destination string
 557.116 + *	    optional format of day-of-week prefix
 557.117 + *	    format of date and time
 557.118 + *	    flag whether to append symbolic timezone
 557.119 + */
 557.120 +
 557.121 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
 557.122 +{
 557.123 +  time_t tn = time (0);
 557.124 +  struct tm *t = gmtime (&tn);
 557.125 +  int zone = t->tm_hour * 60 + t->tm_min;
 557.126 +  int julian = t->tm_yday;
 557.127 +  t = localtime (&tn);		/* get local time now */
 557.128 +				/* minus UTC minutes since midnight */
 557.129 +  zone = t->tm_hour * 60 + t->tm_min - zone;
 557.130 +  /* julian can be one of:
 557.131 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
 557.132 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
 557.133 +   *    0  local time is same day as UTC, no offset
 557.134 +   *   -1  local time is 1 day behind UTC, offset -24 hours
 557.135 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
 557.136 +   */
 557.137 +  if (julian = t->tm_yday -julian)
 557.138 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
 557.139 +  if (prefix) {			/* want day of week? */
 557.140 +    sprintf (date,prefix,days[t->tm_wday]);
 557.141 +    date += strlen (date);	/* make next sprintf append */
 557.142 +  }
 557.143 +				/* output the date */
 557.144 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
 557.145 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
 557.146 +  if (suffix) {			/* append timezone suffix if desired */
 557.147 +    char *tz;
 557.148 +    tzset ();			/* get timezone from TZ environment stuff */
 557.149 +    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
 557.150 +    if (tz && tz[0]) sprintf (date + strlen (date)," (%s)",tz);
 557.151 +  }
 557.152 +}
 557.153 +
 557.154 +
 557.155 +/* Write current time in RFC 822 format
 557.156 + * Accepts: destination string
 557.157 + */
 557.158 +
 557.159 +void rfc822_date (char *date)
 557.160 +{
 557.161 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
 557.162 +	   no822tztext ? NIL : T);
 557.163 +}
 557.164 +
 557.165 +
 557.166 +/* Write current time in internal format
 557.167 + * Accepts: destination string
 557.168 + */
 557.169 +
 557.170 +void internal_date (char *date)
 557.171 +{
 557.172 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
 557.173 +}
 557.174 +
 557.175 +/* Return random number
 557.176 + */
 557.177 +
 557.178 +long random ()
 557.179 +{
 557.180 +  if (!rndm) srand (rndm = (unsigned) time (0L));
 557.181 +  return (long) rand ();
 557.182 +}
 557.183 +
 557.184 +/* Return default drive
 557.185 + * Returns: default drive
 557.186 + */
 557.187 +
 557.188 +static char *defaultDrive (void)
 557.189 +{
 557.190 +  char *s;
 557.191 +  return ((s = getenv ("SystemDrive")) && *s) ? s : "C:";
 557.192 +}
 557.193 +
 557.194 +
 557.195 +/* Return home drive from environment variables
 557.196 + * Returns: home drive
 557.197 + */
 557.198 +
 557.199 +static char *homeDrive (void)
 557.200 +{
 557.201 +  char *s;
 557.202 +  return ((s = getenv ("HOMEDRIVE")) && *s) ? s : defaultDrive ();
 557.203 +}
 557.204 +
 557.205 +
 557.206 +/* Return home path from environment variables
 557.207 + * Accepts: path to write into
 557.208 + * Returns: home path or NIL if it can't be determined
 557.209 + */
 557.210 +
 557.211 +static char *homePath (char *path)
 557.212 +{
 557.213 +  int i;
 557.214 +  char *s;
 557.215 +  if (!((s = getenv ("HOMEPATH")) && (i = strlen (s)))) return NIL;
 557.216 +  if (((s[i-1] == '\\') || (s[i-1] == '/'))) s[i-1] = '\0';
 557.217 +  sprintf (path,"%s%s",homeDrive (),s);
 557.218 +  return path;
 557.219 +}
 557.220 +
 557.221 +/* Return my home directory name
 557.222 + * Returns: my home directory name
 557.223 + */
 557.224 +
 557.225 +char *myhomedir ()
 557.226 +{
 557.227 +  char tmp[MAILTMPLEN];
 557.228 +				/* initialize if first time */
 557.229 +  if (!myHomeDir) myHomeDir = homePath (tmp);
 557.230 +  return myHomeDir ? myHomeDir : homeDrive ();
 557.231 +}
 557.232 +
 557.233 +/* Return system standard INBOX
 557.234 + * Accepts: buffer string
 557.235 + */
 557.236 +
 557.237 +char *sysinbox ()
 557.238 +{
 557.239 +  char tmp[MAILTMPLEN];
 557.240 +  if (!sysInbox) {		/* initialize if first time */
 557.241 +    sprintf (tmp,"%s\\INBOX",myhomedir ());
 557.242 +    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
 557.243 +  }
 557.244 +  return sysInbox;
 557.245 +}
 557.246 +
 557.247 +
 557.248 +/* Return mailbox file name
 557.249 + * Accepts: destination buffer
 557.250 + *	    mailbox name
 557.251 + * Returns: file name
 557.252 + */
 557.253 +
 557.254 +char *mailboxfile (char *dst,char *name)
 557.255 +{
 557.256 +  char *dir = myhomedir ();
 557.257 +  *dst = '\0';			/* default to empty string */
 557.258 +  if (((name[0] == 'I') || (name[0] == 'i')) &&
 557.259 +      ((name[1] == 'N') || (name[1] == 'n')) &&
 557.260 +      ((name[2] == 'B') || (name[2] == 'b')) &&
 557.261 +      ((name[3] == 'O') || (name[3] == 'o')) &&
 557.262 +      ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) name = NIL;
 557.263 +				/* reject namespace names or names with / */
 557.264 +  if (name && ((*name == '#') || strchr (name,'/'))) return NIL;
 557.265 +  else if (!name) return dst;	/* driver selects the INBOX name */
 557.266 +				/* absolute path name? */
 557.267 +  else if ((*name == '\\') || (name[1] == ':')) return strcpy (dst,name);
 557.268 +				/* build resulting name */
 557.269 +  sprintf (dst,"%s\\%s",dir,name);
 557.270 +  return dst;			/* return it */
 557.271 +}
 557.272 +
 557.273 +
 557.274 +/* Determine default prototype stream to user
 557.275 + * Accepts: type (NIL for create, T for append)
 557.276 + * Returns: default prototype stream
 557.277 + */
 557.278 +
 557.279 +MAILSTREAM *default_proto (long type)
 557.280 +{
 557.281 +  extern MAILSTREAM CREATEPROTO,APPENDPROTO;
 557.282 +  return type ? &APPENDPROTO : &CREATEPROTO;
 557.283 +}
 557.284 +
 557.285 +/* Emulator for BSD syslog() routine
 557.286 + * Accepts: priority
 557.287 + *	    message
 557.288 + *	    parameters
 557.289 + */
 557.290 +
 557.291 +void syslog (int priority,const char *message,...)
 557.292 +{
 557.293 +}
 557.294 +
 557.295 +
 557.296 +/* Emulator for BSD openlog() routine
 557.297 + * Accepts: identity
 557.298 + *	    options
 557.299 + *	    facility
 557.300 + */
 557.301 +
 557.302 +void openlog (const char *ident,int logopt,int facility)
 557.303 +{
 557.304 +}
   558.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   558.2 +++ b/src/osdep/wce/env_wce.h	Mon Sep 14 15:17:45 2009 +0900
   558.3 @@ -0,0 +1,70 @@
   558.4 +/* ========================================================================
   558.5 + * Copyright 1988-2006 University of Washington
   558.6 + *
   558.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   558.8 + * you may not use this file except in compliance with the License.
   558.9 + * You may obtain a copy of the License at
  558.10 + *
  558.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  558.12 + *
  558.13 + * 
  558.14 + * ========================================================================
  558.15 + */
  558.16 +
  558.17 +/*
  558.18 + * Program:	WCE environment routines
  558.19 + *
  558.20 + * Author:	Mark Crispin
  558.21 + *		Networks and Distributed Computing
  558.22 + *		Computing & Communications
  558.23 + *		University of Washington
  558.24 + *		Administration Building, AG-44
  558.25 + *		Seattle, WA  98195
  558.26 + *		Internet: MRC@CAC.Washington.EDU
  558.27 + *
  558.28 + * Date:	1 August 1988
  558.29 + * Last Edited:	30 August 2006
  558.30 + */
  558.31 +
  558.32 +
  558.33 +#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\MAILBOX.LST",myhomedir ())
  558.34 +#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\MAILBOX.TMP",myhomedir ())
  558.35 +
  558.36 +#define L_SET SEEK_SET
  558.37 +
  558.38 +/* Function prototypes */
  558.39 +
  558.40 +#include "env.h"
  558.41 +
  558.42 +static char *defaultDrive (void);
  558.43 +static char *homeDrive (void);
  558.44 +static char *homePath (char *path);
  558.45 +char *sysinbox ();
  558.46 +long random ();
  558.47 +unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
  558.48 +			    unsigned long srcl);
  558.49 +unsigned long unix_crlflen (STRING *s);
  558.50 +#define getpid random
  558.51 +
  558.52 +
  558.53 +/* syslog() emulation */
  558.54 +
  558.55 +#define LOG_MAIL	(2<<3)	/* mail system */
  558.56 +#define LOG_DAEMON	(3<<3)	/* system daemons */
  558.57 +#define LOG_AUTH	(4<<3)	/* security/authorization messages */
  558.58 +#define LOG_EMERG	0	/* system is unusable */
  558.59 +#define LOG_ALERT	1	/* action must be taken immediately */
  558.60 +#define LOG_CRIT	2	/* critical conditions */
  558.61 +#define LOG_ERR		3	/* error conditions */
  558.62 +#define LOG_WARNING	4	/* warning conditions */
  558.63 +#define LOG_NOTICE	5	/* normal but signification condition */
  558.64 +#define LOG_INFO	6	/* informational */
  558.65 +#define LOG_DEBUG	7	/* debug-level messages */
  558.66 +#define LOG_PID		0x01	/* log the pid with each message */
  558.67 +#define LOG_CONS	0x02	/* log on the console if errors in sending */
  558.68 +#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
  558.69 +#define LOG_NDELAY	0x08	/* don't delay open */
  558.70 +#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
  558.71 +
  558.72 +void openlog (const char *ident,int logopt,int facility);
  558.73 +void syslog (int priority,const char *message,...);
   559.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   559.2 +++ b/src/osdep/wce/fs_wce.c	Mon Sep 14 15:17:45 2009 +0900
   559.3 @@ -0,0 +1,62 @@
   559.4 +/* ========================================================================
   559.5 + * Copyright 1988-2006 University of Washington
   559.6 + *
   559.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   559.8 + * you may not use this file except in compliance with the License.
   559.9 + * You may obtain a copy of the License at
  559.10 + *
  559.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  559.12 + *
  559.13 + * 
  559.14 + * ========================================================================
  559.15 + */
  559.16 +
  559.17 +/*
  559.18 + * Program:	Free storage management routines
  559.19 + *
  559.20 + * Author:	Mark Crispin
  559.21 + *		Networks and Distributed Computing
  559.22 + *		Computing & Communications
  559.23 + *		University of Washington
  559.24 + *		Administration Building, AG-44
  559.25 + *		Seattle, WA  98195
  559.26 + *		Internet: MRC@CAC.Washington.EDU
  559.27 + *
  559.28 + * Date:	1 August 1988
  559.29 + * Last Edited:	30 August 2006
  559.30 + */
  559.31 +
  559.32 +/* Get a block of free storage
  559.33 + * Accepts: size of desired block
  559.34 + * Returns: free storage block
  559.35 + */
  559.36 +
  559.37 +void *fs_get (size_t size)
  559.38 +{
  559.39 +  void *block = malloc (size ? size : (size_t) 1);
  559.40 +  if (!block) fatal ("Out of memory");
  559.41 +  return (block);
  559.42 +}
  559.43 +
  559.44 +
  559.45 +/* Resize a block of free storage
  559.46 + * Accepts: ** pointer to current block
  559.47 + *	    new size
  559.48 + */
  559.49 +
  559.50 +void fs_resize (void **block,size_t size)
  559.51 +{
  559.52 +  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
  559.53 +    fatal ("Can't resize memory");
  559.54 +}
  559.55 +
  559.56 +
  559.57 +/* Return a block of free storage
  559.58 + * Accepts: ** pointer to free storage block
  559.59 + */
  559.60 +
  559.61 +void fs_give (void **block)
  559.62 +{
  559.63 +  free (*block);
  559.64 +  *block = NIL;
  559.65 +}
   560.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   560.2 +++ b/src/osdep/wce/ftl_wce.c	Mon Sep 14 15:17:45 2009 +0900
   560.3 @@ -0,0 +1,38 @@
   560.4 +/* ========================================================================
   560.5 + * Copyright 1988-2006 University of Washington
   560.6 + *
   560.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   560.8 + * you may not use this file except in compliance with the License.
   560.9 + * You may obtain a copy of the License at
  560.10 + *
  560.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  560.12 + *
  560.13 + * 
  560.14 + * ========================================================================
  560.15 + */
  560.16 +
  560.17 +/*
  560.18 + * Program:	DOS/VMS/TOPS-20 crash management routines
  560.19 + *
  560.20 + * Author:	Mark Crispin
  560.21 + *		Networks and Distributed Computing
  560.22 + *		Computing & Communications
  560.23 + *		University of Washington
  560.24 + *		Administration Building, AG-44
  560.25 + *		Seattle, WA  98195
  560.26 + *		Internet: MRC@CAC.Washington.EDU
  560.27 + *
  560.28 + * Date:	1 August 1988
  560.29 + * Last Edited:	30 August 2006
  560.30 + */
  560.31 +
  560.32 +
  560.33 +/* Report a fatal error
  560.34 + * Accepts: string to output
  560.35 + */
  560.36 +
  560.37 +void fatal (char *string)
  560.38 +{
  560.39 +  mm_fatal (string);		/* pass up the string */
  560.40 +  abort ();			/* die horribly */
  560.41 +}
   561.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   561.2 +++ b/src/osdep/wce/makefile.wce	Mon Sep 14 15:17:45 2009 +0900
   561.3 @@ -0,0 +1,96 @@
   561.4 +# ========================================================================
   561.5 +# Copyright 1988-2006 University of Washington
   561.6 +#
   561.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   561.8 +# you may not use this file except in compliance with the License.
   561.9 +# You may obtain a copy of the License at
  561.10 +#
  561.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  561.12 +#
  561.13 +# 
  561.14 +# ========================================================================
  561.15 +
  561.16 +# Program:	Portable C client makefile -- WCE version
  561.17 +#
  561.18 +# Author:	Mark Crispin
  561.19 +#		Networks and Distributed Computing
  561.20 +#		Computing & Communications
  561.21 +#		University of Washington
  561.22 +#		Administration Building, AG-44
  561.23 +#		Seattle, WA  98195
  561.24 +#		Internet: MRC@CAC.Washington.EDU
  561.25 +#
  561.26 +# Date:		11 May 1989
  561.27 +# Last Edited:	30 August 2006
  561.28 +
  561.29 +
  561.30 +EXTRAAUTHENTICATORS=
  561.31 +DEFAULTAUTHENTICATORS=ext md5 pla log
  561.32 +EXTRADRIVERS =
  561.33 +DRIVERS = imap nntp pop3
  561.34 +DEFAULTDRIVER = dummy
  561.35 +CFLAGS= /MT /W3 /D_SH3_ -nologo $(EXTRACFLAGS)
  561.36 +CC = shcl
  561.37 +CCLIENTLIB= cclient.lib
  561.38 +
  561.39 +all:	$(CCLIENTLIB)
  561.40 +
  561.41 +.c.obj:
  561.42 +	$(CC) -c $(CFLAGS) $*.c
  561.43 +
  561.44 +osdep.h: os_wce.h
  561.45 +	copy os_wce.h osdep.h
  561.46 +	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
  561.47 +	setproto $(DEFAULTDRIVER) $(DEFAULTDRIVER)
  561.48 +	mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
  561.49 +
  561.50 +mail.obj: mail.h misc.h osdep.h mail.c
  561.51 +
  561.52 +misc.obj: mail.h misc.h misc.c
  561.53 +
  561.54 +flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
  561.55 +
  561.56 +netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
  561.57 +
  561.58 +newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
  561.59 +
  561.60 +rfc822.obj: mail.h rfc822.h misc.h rfc822.c
  561.61 +
  561.62 +smanager.obj: mail.h misc.h smanager.c
  561.63 +
  561.64 +utf8.obj: mail.h misc.h osdep.h utf8.h
  561.65 +
  561.66 +utf8aux.obj: mail.h misc.h osdep.h utf8.h
  561.67 +
  561.68 +imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
  561.69 +
  561.70 +nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
  561.71 +
  561.72 +pop3.obj: mail.h pop3.h rfc822.h misc.h osdep.h pop3.c
  561.73 +
  561.74 +smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
  561.75 +
  561.76 +os_wce.obj: mail.h osdep.h env_wce.h fs.h ftl.h nl.h tcp.h tcp_wce.h \
  561.77 +	os_wce.c fs_wce.c ftl_wce.c nl_wce.c env_wce.c tcp_wce.c \
  561.78 +	auth_md5.c auth_log.c pmatch.c
  561.79 +
  561.80 +dummywce.obj: mail.h dummy.h misc.h osdep.h dummywce.c
  561.81 +
  561.82 +$(CCLIENTLIB): mail.obj misc.obj flstring.obj netmsg.obj \
  561.83 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
  561.84 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_wce.obj \
  561.85 +	dummywce.obj
  561.86 +	erase $(CCLIENTLIB)
  561.87 +	LIB /NOLOGO /OUT:cclient.lib \
  561.88 +	mail.obj misc.obj flstring.obj netmsg.obj \
  561.89 +	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
  561.90 +	imap4r1.obj nntp.obj pop3.obj smtp.obj os_wce.obj \
  561.91 +	dummywce.obj
  561.92 +
  561.93 +clean:
  561.94 +	del *.lib *.obj linkage.* osdep.* auths.c *.exe *.exp || rem
  561.95 +
  561.96 +# A monument to a hack of long ago and far away...
  561.97 +
  561.98 +love:
  561.99 +	@echo not war?
   562.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   562.2 +++ b/src/osdep/wce/mkautaux.bat	Mon Sep 14 15:17:45 2009 +0900
   562.3 @@ -0,0 +1,31 @@
   562.4 +@ECHO OFF
   562.5 +REM ========================================================================
   562.6 +REM Copyright 1988-2006 University of Washington
   562.7 +REM
   562.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   562.9 +REM you may not use this file except in compliance with the License.
  562.10 +REM You may obtain a copy of the License at
  562.11 +REM
  562.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  562.13 +REM
  562.14 +REM 
  562.15 +REM ========================================================================
  562.16 +
  562.17 +REM Program:	Authenticator Linkage Generator auxillary for NT/Win9x
  562.18 +REM
  562.19 +REM Author:	Mark Crispin
  562.20 +REM		Networks and Distributed Computing
  562.21 +REM		Computing & Communications
  562.22 +REM		University of Washington
  562.23 +REM		Administration Building, AG-44
  562.24 +REM		Seattle, WA  98195
  562.25 +REM		Internet: MRC@CAC.Washington.EDU
  562.26 +REM
  562.27 +REM Date:	6 December 1995
  562.28 +REM Last Edited:30 August 2006
  562.29 +
  562.30 +ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
  562.31 +REM Note the introduction of the caret to quote the ampersand in NT
  562.32 +if "%OS%" == "Windows_NT" ECHO   auth_link (^&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
  562.33 +if "%OS%" == "" ECHO   auth_link (&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
  562.34 +ECHO #include "auth_%1.c" >> AUTHS.C
   563.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   563.2 +++ b/src/osdep/wce/mkauths.bat	Mon Sep 14 15:17:45 2009 +0900
   563.3 @@ -0,0 +1,33 @@
   563.4 +@ECHO OFF
   563.5 +REM ========================================================================
   563.6 +REM Copyright 1988-2006 University of Washington
   563.7 +REM
   563.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   563.9 +REM you may not use this file except in compliance with the License.
  563.10 +REM You may obtain a copy of the License at
  563.11 +REM
  563.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  563.13 +REM
  563.14 +REM 
  563.15 +REM ========================================================================
  563.16 +
  563.17 +REM Program:	Authenticator Linkage Generator for DOS and Windows
  563.18 +REM
  563.19 +REM Author:	Mark Crispin
  563.20 +REM		Networks and Distributed Computing
  563.21 +REM		Computing & Communications
  563.22 +REM		University of Washington
  563.23 +REM		Administration Building, AG-44
  563.24 +REM		Seattle, WA  98195
  563.25 +REM		Internet: MRC@CAC.Washington.EDU
  563.26 +REM
  563.27 +REM Date:	6 December 1995
  563.28 +REM Last Edited:30 August 2006
  563.29 +
  563.30 +REM Erase old authenticators list
  563.31 +IF EXIST AUTHS.C DEL AUTHS.C
  563.32 +
  563.33 +REM Now define the new list
  563.34 +FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
  563.35 +
  563.36 +EXIT 0
   564.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   564.2 +++ b/src/osdep/wce/nl_wce.c	Mon Sep 14 15:17:45 2009 +0900
   564.3 @@ -0,0 +1,61 @@
   564.4 +/* ========================================================================
   564.5 + * Copyright 1988-2006 University of Washington
   564.6 + *
   564.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   564.8 + * you may not use this file except in compliance with the License.
   564.9 + * You may obtain a copy of the License at
  564.10 + *
  564.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  564.12 + *
  564.13 + * 
  564.14 + * ========================================================================
  564.15 + */
  564.16 +
  564.17 +/*
  564.18 + * Program:	Windows/TOPS-20 newline routines
  564.19 + *
  564.20 + * Author:	Mark Crispin
  564.21 + *		Networks and Distributed Computing
  564.22 + *		Computing & Communications
  564.23 + *		University of Washington
  564.24 + *		Administration Building, AG-44
  564.25 + *		Seattle, WA  98195
  564.26 + *		Internet: MRC@CAC.Washington.EDU
  564.27 + *
  564.28 + * Date:	1 August 1988
  564.29 + * Last Edited:	30 August 2006
  564.30 + */
  564.31 +
  564.32 +/* Copy string with CRLF newlines
  564.33 + * Accepts: destination string
  564.34 + *	    pointer to size of destination string buffer
  564.35 + *	    source string
  564.36 + *	    length of source string
  564.37 + * Returns: length of copied string
  564.38 + */
  564.39 +
  564.40 +unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
  564.41 +			  unsigned char *src,unsigned long srcl)
  564.42 +{
  564.43 +				/* flush destination buffer if too small */
  564.44 +  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
  564.45 +  if (!*dst) {			/* make a new buffer if needed */
  564.46 +    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
  564.47 +    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
  564.48 +  }
  564.49 +				/* copy strings */
  564.50 +  if (srcl) memcpy (*dst,src,(size_t) srcl);
  564.51 +  *(*dst + srcl) = '\0';	/* tie off destination */
  564.52 +  return srcl;			/* return length */
  564.53 +}
  564.54 +
  564.55 +
  564.56 +/* Length of string after strcrlfcpy applied
  564.57 + * Accepts: source string
  564.58 + * Returns: length of string
  564.59 + */
  564.60 +
  564.61 +unsigned long strcrlflen (STRING *s)
  564.62 +{
  564.63 +  return SIZE (s);		/* no-brainer on DOS! */
  564.64 +}
   565.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   565.2 +++ b/src/osdep/wce/os_wce.c	Mon Sep 14 15:17:45 2009 +0900
   565.3 @@ -0,0 +1,45 @@
   565.4 +/* ========================================================================
   565.5 + * Copyright 1988-2006 University of Washington
   565.6 + *
   565.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   565.8 + * you may not use this file except in compliance with the License.
   565.9 + * You may obtain a copy of the License at
  565.10 + *
  565.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  565.12 + *
  565.13 + * 
  565.14 + * ========================================================================
  565.15 + */
  565.16 +
  565.17 +/*
  565.18 + * Program:	Operating-system dependent routines -- WCE version
  565.19 + *
  565.20 + * Author:	Mark Crispin
  565.21 + *		Networks and Distributed Computing
  565.22 + *		Computing & Communications
  565.23 + *		University of Washington
  565.24 + *		Administration Building, AG-44
  565.25 + *		Seattle, WA  98195
  565.26 + *		Internet: MRC@CAC.Washington.EDU
  565.27 + *
  565.28 + * Date:	11 April 1989
  565.29 + * Last Edited:	30 August 2006
  565.30 + */
  565.31 +
  565.32 +#include "tcp_wce.h"		/* must be before osdep includes tcp.h */
  565.33 +#include "mail.h"
  565.34 +#include "osdep.h"
  565.35 +#include <winsock.h>
  565.36 +#include <stdio.h>
  565.37 +#include <time.h>
  565.38 +#include <sys\timeb.h>
  565.39 +#include <fcntl.h>
  565.40 +#include <sys\stat.h>
  565.41 +#include "misc.h"
  565.42 +
  565.43 +#include "fs_wce.c"
  565.44 +#include "ftl_wce.c"
  565.45 +#include "nl_wce.c"
  565.46 +#include "env_wce.c"
  565.47 +#include "tcp_wce.c"
  565.48 +#include "auths.c"
   566.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   566.2 +++ b/src/osdep/wce/os_wce.h	Mon Sep 14 15:17:45 2009 +0900
   566.3 @@ -0,0 +1,53 @@
   566.4 +/* ========================================================================
   566.5 + * Copyright 1988-2006 University of Washington
   566.6 + *
   566.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   566.8 + * you may not use this file except in compliance with the License.
   566.9 + * You may obtain a copy of the License at
  566.10 + *
  566.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  566.12 + *
  566.13 + * 
  566.14 + * ========================================================================
  566.15 + */
  566.16 +
  566.17 +/*
  566.18 + * Program:	Operating-system dependent routines -- WCE version
  566.19 + *
  566.20 + * Author:	Mark Crispin
  566.21 + *		Networks and Distributed Computing
  566.22 + *		Computing & Communications
  566.23 + *		University of Washington
  566.24 + *		Administration Building, AG-44
  566.25 + *		Seattle, WA  98195
  566.26 + *		Internet: MRC@CAC.Washington.EDU
  566.27 + *
  566.28 + * Date:	11 May 1989
  566.29 + * Last Edited:	30 August 2006
  566.30 + */
  566.31 +
  566.32 +#include <stdlib.h>
  566.33 +#include <stdio.h>
  566.34 +#include <string.h>
  566.35 +				/* missing in string.h */
  566.36 +_CRTIMP char * __cdecl strpbrk (const char *, const char *);
  566.37 +_CRTIMP	char * __cdecl strrchr(const char *, int);
  566.38 +#include <sys\types.h>
  566.39 +#undef ERROR
  566.40 +#include <windows.h>
  566.41 +#undef ERROR
  566.42 +#define ERROR (long) 2		/* must match mail.h */
  566.43 +#include <time.h>
  566.44 +#include <io.h>
  566.45 +
  566.46 +#define gethostid clock
  566.47 +#define	WSA_VERSION	((1 << 8) | 1)
  566.48 +
  566.49 +#include "env_wce.h"
  566.50 +#include "fs.h"
  566.51 +#include "ftl.h"
  566.52 +#include "nl.h"
  566.53 +#include "tcp.h"
  566.54 +
  566.55 +#undef noErr
  566.56 +#undef MAC
   567.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   567.2 +++ b/src/osdep/wce/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
   567.3 @@ -0,0 +1,89 @@
   567.4 +/* ========================================================================
   567.5 + * Copyright 1988-2006 University of Washington
   567.6 + *
   567.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   567.8 + * you may not use this file except in compliance with the License.
   567.9 + * You may obtain a copy of the License at
  567.10 + *
  567.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  567.12 + *
  567.13 + * 
  567.14 + * ========================================================================
  567.15 + */
  567.16 +
  567.17 +/*
  567.18 + * Program:	IMAP Wildcard Matching Routines (case-independent)
  567.19 + *
  567.20 + * Author:	Mark Crispin
  567.21 + *		Networks and Distributed Computing
  567.22 + *		Computing & Communications
  567.23 + *		University of Washington
  567.24 + *		Administration Building, AG-44
  567.25 + *		Seattle, WA  98195
  567.26 + *		Internet: MRC@CAC.Washington.EDU
  567.27 + *
  567.28 + * Date:	15 June 2000
  567.29 + * Last Edited:	30 August 2006
  567.30 + */
  567.31 +
  567.32 +/* Wildcard pattern match
  567.33 + * Accepts: base string
  567.34 + *	    pattern string
  567.35 + *	    delimiter character
  567.36 + * Returns: T if pattern matches base, else NIL
  567.37 + */
  567.38 +
  567.39 +long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
  567.40 +{
  567.41 +  switch (*pat) {
  567.42 +  case '%':			/* non-recursive */
  567.43 +				/* % at end, OK if no inferiors */
  567.44 +    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
  567.45 +                                /* scan remainder of string until delimiter */
  567.46 +    do if (pmatch_full (s,pat+1,delim)) return T;
  567.47 +    while ((*s != delim) && *s++);
  567.48 +    break;
  567.49 +  case '*':			/* match 0 or more characters */
  567.50 +    if (!pat[1]) return T;	/* * at end, unconditional match */
  567.51 +				/* scan remainder of string */
  567.52 +    do if (pmatch_full (s,pat+1,delim)) return T;
  567.53 +    while (*s++);
  567.54 +    break;
  567.55 +  case '\0':			/* end of pattern */
  567.56 +    return *s ? NIL : T;	/* success if also end of base */
  567.57 +  default:			/* match this character */
  567.58 +    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
  567.59 +  }
  567.60 +  return NIL;
  567.61 +}
  567.62 +
  567.63 +/* Directory pattern match
  567.64 + * Accepts: base string
  567.65 + *	    pattern string
  567.66 + *	    delimiter character
  567.67 + * Returns: T if base is a matching directory of pattern, else NIL
  567.68 + */
  567.69 +
  567.70 +long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
  567.71 +{
  567.72 +  switch (*pat) {
  567.73 +  case '%':			/* non-recursive */
  567.74 +    if (!*s) return T;		/* end of base means have a subset match */
  567.75 +    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
  567.76 +				/* scan remainder of string until delimiter */
  567.77 +    do if (dmatch (s,pat,delim)) return T;
  567.78 +    while ((*s != delim) && *s++);
  567.79 +    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
  567.80 +    return dmatch (s,pat,delim);/* do new scan */
  567.81 +  case '*':			/* match 0 or more characters */
  567.82 +    return T;			/* unconditional match */
  567.83 +  case '\0':			/* end of pattern */
  567.84 +    break;
  567.85 +  default:			/* match this character */
  567.86 +    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
  567.87 +				/* end of base, return if at delimiter */
  567.88 +    else if (*pat == delim) return T;
  567.89 +    break;
  567.90 +  }
  567.91 +  return NIL;
  567.92 +}
   568.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   568.2 +++ b/src/osdep/wce/setproto.bat	Mon Sep 14 15:17:45 2009 +0900
   568.3 @@ -0,0 +1,29 @@
   568.4 +@ECHO OFF
   568.5 +REM ========================================================================
   568.6 +REM Copyright 1988-2006 University of Washington
   568.7 +REM
   568.8 +REM Licensed under the Apache License, Version 2.0 (the "License");
   568.9 +REM you may not use this file except in compliance with the License.
  568.10 +REM You may obtain a copy of the License at
  568.11 +REM
  568.12 +REM     http://www.apache.org/licenses/LICENSE-2.0
  568.13 +REM
  568.14 +REM 
  568.15 +REM ========================================================================
  568.16 +
  568.17 +REM Program:	Set default prototype for DOS/NT
  568.18 +REM
  568.19 +REM Author:	Mark Crispin
  568.20 +REM		Networks and Distributed Computing
  568.21 +REM		Computing & Communications
  568.22 +REM		University of Washington
  568.23 +REM		Administration Building, AG-44
  568.24 +REM		Seattle, WA  98195
  568.25 +REM		Internet: MRC@CAC.Washington.EDU
  568.26 +REM
  568.27 +REM Date:	 9 October 1995
  568.28 +REM Last Edited: 30 August 2006
  568.29 +
  568.30 +REM Set the default drivers
  568.31 +ECHO #define CREATEPROTO %1proto >> LINKAGE.H
  568.32 +ECHO #define APPENDPROTO %2proto >> LINKAGE.H
   569.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   569.2 +++ b/src/osdep/wce/tcp_wce.c	Mon Sep 14 15:17:45 2009 +0900
   569.3 @@ -0,0 +1,818 @@
   569.4 +/* ========================================================================
   569.5 + * Copyright 1988-2008 University of Washington
   569.6 + *
   569.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   569.8 + * you may not use this file except in compliance with the License.
   569.9 + * You may obtain a copy of the License at
  569.10 + *
  569.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  569.12 + *
  569.13 + * 
  569.14 + * ========================================================================
  569.15 + */
  569.16 +
  569.17 +/*
  569.18 + * Program:	Winsock TCP/IP routines
  569.19 + *
  569.20 + * Author:	Mark Crispin from Mike Seibel's Winsock code
  569.21 + *		Networks and Distributed Computing
  569.22 + *		Computing & Communications
  569.23 + *		University of Washington
  569.24 + *		Administration Building, AG-44
  569.25 + *		Seattle, WA  98195
  569.26 + *		Internet: MRC@CAC.Washington.EDU
  569.27 + *
  569.28 + * Date:	11 April 1989
  569.29 + * Last Edited:	13 January 2008
  569.30 + */
  569.31 +
  569.32 +
  569.33 +#define TCPMAXSEND 32768
  569.34 +
  569.35 +/* Private functions */
  569.36 +
  569.37 +int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
  569.38 +		     unsigned long port);
  569.39 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
  569.40 +			       long *contd);
  569.41 +long tcp_abort (TCPSTREAM *stream);
  569.42 +long tcp_close_socket (SOCKET *sock);
  569.43 +char *tcp_name (struct sockaddr_in *sin,long flag);
  569.44 +char *tcp_name_valid (char *s);
  569.45 +
  569.46 +
  569.47 +/* Private data */
  569.48 +
  569.49 +int wsa_initted = 0;		/* init ? */
  569.50 +static int wsa_sock_open = 0;	/* keep track of open sockets */
  569.51 +static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
  569.52 +static long ttmo_read = 0;	/* TCP timeouts, in seconds */
  569.53 +static long ttmo_write = 0;
  569.54 +static long allowreversedns = T;/* allow reverse DNS lookup */
  569.55 +static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
  569.56 +
  569.57 +/* TCP/IP manipulate parameters
  569.58 + * Accepts: function code
  569.59 + *	    function-dependent value
  569.60 + * Returns: function-dependent return value
  569.61 + */
  569.62 +
  569.63 +void *tcp_parameters (long function,void *value)
  569.64 +{
  569.65 +  void *ret = NIL;
  569.66 +  switch ((int) function) {
  569.67 +  case SET_TIMEOUT:
  569.68 +    tmoh = (tcptimeout_t) value;
  569.69 +  case GET_TIMEOUT:
  569.70 +    ret = (void *) tmoh;
  569.71 +    break;
  569.72 +  case SET_READTIMEOUT:
  569.73 +    ttmo_read = (long) value;
  569.74 +  case GET_READTIMEOUT:
  569.75 +    ret = (void *) ttmo_read;
  569.76 +    break;
  569.77 +  case SET_WRITETIMEOUT:
  569.78 +    ttmo_write = (long) value;
  569.79 +  case GET_WRITETIMEOUT:
  569.80 +    ret = (void *) ttmo_write;
  569.81 +    break;
  569.82 +  case SET_ALLOWREVERSEDNS:
  569.83 +    allowreversedns = (long) value;
  569.84 +  case GET_ALLOWREVERSEDNS:
  569.85 +    ret = (void *) allowreversedns;
  569.86 +    break;
  569.87 +  case SET_TCPDEBUG:
  569.88 +    tcpdebug = (long) value;
  569.89 +  case GET_TCPDEBUG:
  569.90 +    ret = (void *) tcpdebug;
  569.91 +    break;
  569.92 +  }
  569.93 +  return ret;
  569.94 +}
  569.95 +
  569.96 +/* TCP/IP open
  569.97 + * Accepts: host name
  569.98 + *	    contact service name
  569.99 + *	    contact port number and optional silent flag
 569.100 + * Returns: TCP/IP stream if success else NIL
 569.101 + */
 569.102 +
 569.103 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
 569.104 +{
 569.105 +  TCPSTREAM *stream = NIL;
 569.106 +  int i;
 569.107 +  SOCKET sock = INVALID_SOCKET;
 569.108 +  int silent = (port & NET_SILENT) ? T : NIL;
 569.109 +  char *s;
 569.110 +  struct sockaddr_in sin;
 569.111 +  struct hostent *he;
 569.112 +  char hostname[MAILTMPLEN];
 569.113 +  char tmp[MAILTMPLEN];
 569.114 +  struct servent *sv = NIL;
 569.115 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 569.116 +  if (!wsa_initted++) {		/* init Windows Sockets */
 569.117 +    WSADATA wsock;
 569.118 +    if (i = (int) WSAStartup (WSA_VERSION,&wsock)) {
 569.119 +      wsa_initted = 0;		/* in case we try again */
 569.120 +      sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
 569.121 +      mm_log (tmp,ERROR);
 569.122 +      return NIL;
 569.123 +    }
 569.124 +  }
 569.125 +  port &= 0xffff;		/* erase flags */
 569.126 +				/* lookup service */
 569.127 +  if (service && (sv = getservbyname (service,"tcp")))
 569.128 +    port = ntohs (sin.sin_port = sv->s_port);
 569.129 + 				/* copy port number in network format */
 569.130 +  else sin.sin_port = htons ((u_short) port);
 569.131 +  /* The domain literal form is used (rather than simply the dotted decimal
 569.132 +     as with other Windows programs) because it has to be a valid "host name"
 569.133 +     in mailsystem terminology. */
 569.134 +  sin.sin_family = AF_INET;	/* family is always Internet */
 569.135 +				/* look like domain literal? */
 569.136 +  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
 569.137 +    strcpy (tmp,host+1);	/* yes, copy number part */
 569.138 +    tmp[strlen (tmp)-1] = '\0';
 569.139 +    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
 569.140 +      sprintf (tmp,"Bad format domain-literal: %.80s",host);
 569.141 +      mm_log (tmp,ERROR);
 569.142 +      return NIL;
 569.143 +    }
 569.144 +    else {
 569.145 +      sin.sin_family = AF_INET;	/* family is always Internet */
 569.146 +      strcpy (hostname,host);
 569.147 +      (*bn) (BLOCK_TCPOPEN,NIL);
 569.148 +      sock = tcp_socket_open (&sin,tmp,hostname,port);
 569.149 +      (*bn) (BLOCK_NONE,NIL);
 569.150 +    }
 569.151 +  }
 569.152 +
 569.153 +  else {			/* lookup host name */
 569.154 +    if (tcpdebug) {
 569.155 +      sprintf (tmp,"DNS resolution %.80s",host);
 569.156 +      mm_log (tmp,TCPDEBUG);
 569.157 +    }
 569.158 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
 569.159 +    if (!(he = gethostbyname (lcase (strcpy (tmp,host)))))
 569.160 +      sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
 569.161 +    (*bn) (BLOCK_NONE,NIL);
 569.162 +    if (he) {			/* DNS resolution won? */
 569.163 +      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
 569.164 +				/* copy address type */
 569.165 +      sin.sin_family = he->h_addrtype;
 569.166 +				/* copy host name */
 569.167 +      strcpy (hostname,he->h_name);
 569.168 +      wsa_sock_open++;		/* prevent tcp_close_socket() from freeing in
 569.169 +				   loop */
 569.170 +      for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) {
 569.171 +	if (i && !silent) mm_log (tmp,WARN);
 569.172 +	memcpy (&sin.sin_addr,s,he->h_length);
 569.173 +	(*bn) (BLOCK_TCPOPEN,NIL);
 569.174 +	sock = tcp_socket_open (&sin,tmp,hostname,port);
 569.175 +	(*bn) (BLOCK_NONE,NIL);
 569.176 +      }
 569.177 +      wsa_sock_open--;		/* undo protection */
 569.178 +    }
 569.179 +  }
 569.180 +  if (sock == INVALID_SOCKET) {	/* error? */
 569.181 +    if (!silent) mm_log (tmp,ERROR);
 569.182 +    tcp_close_socket (&sock);	/* do possible cleanup action */
 569.183 +  }
 569.184 +  else {			/* got a socket, create TCP/IP stream */
 569.185 +    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
 569.186 +				   sizeof (TCPSTREAM));
 569.187 +    stream->port = port;	/* port number */
 569.188 +				/* init socket */
 569.189 +    stream->tcpsi = stream->tcpso = sock;
 569.190 +    stream->ictr = 0;		/* init input counter */
 569.191 +				/* copy official host name */
 569.192 +    stream->host = cpystr (hostname);
 569.193 +    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
 569.194 +  }
 569.195 +  return stream;		/* return success */
 569.196 +}
 569.197 +
 569.198 +/* Open a TCP socket
 569.199 + * Accepts: Internet socket address block
 569.200 + *	    scratch buffer
 569.201 + *	    host name for error message
 569.202 + *	    port number for error message
 569.203 + * Returns: socket if success, else -1 with error string in scratch buffer
 569.204 + */
 569.205 +
 569.206 +int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
 569.207 +		     unsigned long port)
 569.208 +{
 569.209 +  int sock;
 569.210 +  char *s;
 569.211 +  sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
 569.212 +  mm_log (tmp,NIL);
 569.213 +				/* get a TCP stream */
 569.214 +  if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
 569.215 +    sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
 569.216 +    return -1;
 569.217 +  }
 569.218 +  wsa_sock_open++;		/* count this socket as open */
 569.219 +				/* open connection */
 569.220 +  if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) ==
 569.221 +      SOCKET_ERROR) {
 569.222 +    switch (WSAGetLastError ()){/* analyze error */
 569.223 +    case WSAECONNREFUSED:
 569.224 +      s = "Refused";
 569.225 +      break;
 569.226 +    case WSAENOBUFS:
 569.227 +      s = "Insufficient system resources";
 569.228 +      break;
 569.229 +    case WSAETIMEDOUT:
 569.230 +      s = "Timed out";
 569.231 +      break;
 569.232 +    case WSAEHOSTUNREACH:
 569.233 +      s = "Host unreachable";
 569.234 +      break;
 569.235 +    default:
 569.236 +      s = "Unknown error";
 569.237 +      break;
 569.238 +    }
 569.239 +    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s,
 569.240 +	     WSAGetLastError ());
 569.241 +    tcp_close_socket (&sock);	/* flush socket */
 569.242 +    sock = INVALID_SOCKET;
 569.243 +  }
 569.244 +  return sock;			/* return the socket */
 569.245 +}
 569.246 +  
 569.247 +/* TCP/IP authenticated open
 569.248 + * Accepts: NETMBX specifier
 569.249 + *	    service name
 569.250 + *	    returned user name buffer
 569.251 + * Returns: TCP/IP stream if success else NIL
 569.252 + */
 569.253 +
 569.254 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
 569.255 +{
 569.256 +  return NIL;			/* always NIL on Windows */
 569.257 +}
 569.258 +
 569.259 +/* TCP receive line
 569.260 + * Accepts: TCP stream
 569.261 + * Returns: text line string or NIL if failure
 569.262 + */
 569.263 +
 569.264 +char *tcp_getline (TCPSTREAM *stream)
 569.265 +{
 569.266 +  unsigned long n,contd;
 569.267 +  char *ret = tcp_getline_work (stream,&n,&contd);
 569.268 +  if (ret && contd) {		/* got a line needing continuation? */
 569.269 +    STRINGLIST *stl = mail_newstringlist ();
 569.270 +    STRINGLIST *stc = stl;
 569.271 +    do {			/* collect additional lines */
 569.272 +      stc->text.data = (unsigned char *) ret;
 569.273 +      stc->text.size = n;
 569.274 +      stc = stc->next = mail_newstringlist ();
 569.275 +      ret = tcp_getline_work (stream,&n,&contd);
 569.276 +    } while (ret && contd);
 569.277 +    if (ret) {			/* stash final part of line on list */
 569.278 +      stc->text.data = (unsigned char *) ret;
 569.279 +      stc->text.size = n;
 569.280 +				/* determine how large a buffer we need */
 569.281 +      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
 569.282 +      ret = fs_get (n + 1);	/* copy parts into buffer */
 569.283 +      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
 569.284 +	memcpy (ret + n,stc->text.data,stc->text.size);
 569.285 +      ret[n] = '\0';
 569.286 +    }
 569.287 +    mail_free_stringlist (&stl);/* either way, done with list */
 569.288 +  }
 569.289 +  return ret;
 569.290 +}
 569.291 +
 569.292 +/* TCP receive line or partial line
 569.293 + * Accepts: TCP stream
 569.294 + *	    pointer to return size
 569.295 + *	    pointer to return continuation flag
 569.296 + * Returns: text line string, size and continuation flag, or NIL if failure
 569.297 + */
 569.298 +
 569.299 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
 569.300 +			       long *contd)
 569.301 +{
 569.302 +  unsigned long n;
 569.303 +  char *s,*ret,c,d;
 569.304 +  *contd = NIL;			/* assume no continuation */
 569.305 +				/* make sure have data */
 569.306 +  if (!tcp_getdata (stream)) return NIL;
 569.307 +  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
 569.308 +    d = *stream->iptr++;	/* slurp another character */
 569.309 +    if ((c == '\015') && (d == '\012')) {
 569.310 +      ret = (char *) fs_get (n--);
 569.311 +      memcpy (ret,s,*size = n);	/* copy into a free storage string */
 569.312 +      ret[n] = '\0';		/* tie off string with null */
 569.313 +      return ret;
 569.314 +    }
 569.315 +  }
 569.316 +				/* copy partial string from buffer */
 569.317 +  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
 569.318 +				/* get more data from the net */
 569.319 +  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
 569.320 +				/* special case of newline broken by buffer */
 569.321 +  else if ((c == '\015') && (*stream->iptr == '\012')) {
 569.322 +    stream->iptr++;		/* eat the line feed */
 569.323 +    stream->ictr--;
 569.324 +    ret[*size = --n] = '\0';	/* tie off string with null */
 569.325 +  }
 569.326 +  else *contd = LONGT;		/* continuation needed */
 569.327 +  return ret;
 569.328 +}
 569.329 +
 569.330 +/* TCP/IP receive buffer
 569.331 + * Accepts: TCP/IP stream
 569.332 + *	    size in bytes
 569.333 + *	    buffer to read into
 569.334 + * Returns: T if success, NIL otherwise
 569.335 + */
 569.336 +
 569.337 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
 569.338 +{
 569.339 +  unsigned long n;
 569.340 +				/* make sure socket still alive */
 569.341 +  if (stream->tcpsi == INVALID_SOCKET) return NIL;
 569.342 +				/* can transfer bytes from buffer? */
 569.343 +  if (n = min (size,stream->ictr)) {
 569.344 +    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
 569.345 +    s += n;			/* update pointer */
 569.346 +    stream->iptr +=n;
 569.347 +    size -= n;			/* update # of bytes to do */
 569.348 +    stream->ictr -=n;
 569.349 +  }
 569.350 +  if (size) {
 569.351 +    int i;
 569.352 +    fd_set fds;
 569.353 +    struct timeval tmo;
 569.354 +    time_t tc,t = time (0);
 569.355 +    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 569.356 +    (*bn) (BLOCK_TCPREAD,NIL);
 569.357 +    while (size > 0) {		/* until request satisfied */
 569.358 +      time_t tl = time (0);
 569.359 +      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
 569.360 +      FD_ZERO (&fds);		/* initialize selection vector */
 569.361 +      FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
 569.362 +      tmo.tv_sec = ttmo_read;
 569.363 +      tmo.tv_usec = 0;
 569.364 +				/* block and read */
 569.365 +      switch ((stream->tcpsi == stream->tcpso) ?
 569.366 +	      select (stream->tcpsi+1,&fds,0,0,
 569.367 +		      ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
 569.368 +      case SOCKET_ERROR:		/* error */
 569.369 +	if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
 569.370 +	break;
 569.371 +      case 0:			/* timeout */
 569.372 +	tc = time (0);
 569.373 +	if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
 569.374 +	return tcp_abort (stream);
 569.375 +      default:
 569.376 +	if (stream->tcpsi == stream->tcpso)
 569.377 +	  while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) ==
 569.378 +		  SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
 569.379 +	else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) <
 569.380 +		     0) && (errno == EINTR));
 569.381 +	switch (i) {
 569.382 +	case SOCKET_ERROR:	/* error */
 569.383 +	case 0:			/* no data read */
 569.384 +	  return tcp_abort (stream);
 569.385 +	default:
 569.386 +	  s += i;		/* point at new place to write */
 569.387 +	  size -= i;		/* reduce byte count */
 569.388 +	  if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
 569.389 +	}
 569.390 +      }
 569.391 +    }
 569.392 +    (*bn) (BLOCK_NONE,NIL);
 569.393 +  }
 569.394 +  *s = '\0';			/* tie off string */
 569.395 +  return T;
 569.396 +}
 569.397 +
 569.398 +/* TCP/IP receive data
 569.399 + * Accepts: TCP/IP stream
 569.400 + * Returns: T if success, NIL otherwise
 569.401 + */
 569.402 +
 569.403 +long tcp_getdata (TCPSTREAM *stream)
 569.404 +{
 569.405 +  struct timeval tmo;
 569.406 +  int i;
 569.407 +  fd_set fds;
 569.408 +  time_t tc,t = time (0);
 569.409 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 569.410 +  FD_ZERO (&fds);		/* initialize selection vector */
 569.411 +  if (stream->tcpsi == INVALID_SOCKET) return NIL;
 569.412 +  (*bn) (BLOCK_TCPREAD,NIL);
 569.413 +  tmo.tv_sec = ttmo_read;
 569.414 +  tmo.tv_usec = 0;
 569.415 +  while (stream->ictr < 1) {	/* if nothing in the buffer */
 569.416 +    time_t tl = time (0);
 569.417 +    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
 569.418 +    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
 569.419 +				/* block and read */
 569.420 +    switch ((stream->tcpsi == stream->tcpso) ?
 569.421 +	    select (stream->tcpsi+1,&fds,0,0,
 569.422 +		    ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
 569.423 +    case SOCKET_ERROR:		/* error */
 569.424 +      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
 569.425 +      break;
 569.426 +    case 0:			/* timeout */
 569.427 +      tc = time (0);
 569.428 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
 569.429 +      return tcp_abort (stream);
 569.430 +    default:
 569.431 +      if (stream->tcpsi == stream->tcpso)
 569.432 +	while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
 569.433 +		SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
 569.434 +      else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
 569.435 +		  (errno == EINTR));
 569.436 +      switch (i) {
 569.437 +      case SOCKET_ERROR:	/* error */
 569.438 +      case 0:			/* no data read */
 569.439 +	return tcp_abort (stream);
 569.440 +      default:
 569.441 +	stream->ictr = i;	/* set new byte count */
 569.442 +				/* point at TCP buffer */
 569.443 +	stream->iptr = stream->ibuf;
 569.444 +	if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
 569.445 +      }
 569.446 +    }
 569.447 +  }
 569.448 +  (*bn) (BLOCK_NONE,NIL);
 569.449 +  return T;
 569.450 +}
 569.451 +
 569.452 +/* TCP/IP send string as record
 569.453 + * Accepts: TCP/IP stream
 569.454 + *	    string pointer
 569.455 + * Returns: T if success else NIL
 569.456 + */
 569.457 +
 569.458 +long tcp_soutr (TCPSTREAM *stream,char *string)
 569.459 +{
 569.460 +  return tcp_sout (stream,string,(unsigned long) strlen (string));
 569.461 +}
 569.462 +
 569.463 +
 569.464 +/* TCP/IP send string
 569.465 + * Accepts: TCP/IP stream
 569.466 + *	    string pointer
 569.467 + *	    byte count
 569.468 + * Returns: T if success else NIL
 569.469 + */
 569.470 +
 569.471 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
 569.472 +{
 569.473 +  int i;
 569.474 +  struct timeval tmo;
 569.475 +  fd_set fds;
 569.476 +  time_t tc,t = time (0);
 569.477 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 569.478 +  tmo.tv_sec = ttmo_write;
 569.479 +  tmo.tv_usec = 0;
 569.480 +  FD_ZERO (&fds);		/* initialize selection vector */
 569.481 +  if (stream->tcpso == INVALID_SOCKET) return NIL;
 569.482 +  (*bn) (BLOCK_TCPWRITE,NIL);
 569.483 +  while (size > 0) {		/* until request satisfied */
 569.484 +    time_t tl = time (0);
 569.485 +    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
 569.486 +    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
 569.487 +				/* block and write */
 569.488 +    switch ((stream->tcpsi == stream->tcpso) ?
 569.489 +	    select (stream->tcpso+1,NULL,&fds,NULL,
 569.490 +		    tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) {
 569.491 +    case SOCKET_ERROR:		/* error */
 569.492 +      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
 569.493 +      break;
 569.494 +    case 0:			/* timeout */
 569.495 +      tc = time (0);
 569.496 +      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
 569.497 +      return tcp_abort (stream);
 569.498 +    default:
 569.499 +      if (stream->tcpsi == stream->tcpso)
 569.500 +	while (((i = send (stream->tcpso,string,
 569.501 +			   (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) &&
 569.502 +	       (WSAGetLastError () == WSAEINTR));
 569.503 +      else while (((i = write (stream->tcpso,string,
 569.504 +			       min (size,TCPMAXSEND))) < 0) &&
 569.505 +		  (errno == EINTR));
 569.506 +      if (i == SOCKET_ERROR) return tcp_abort (stream);
 569.507 +      size -= i;		/* count this size */
 569.508 +      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
 569.509 +      string += i;
 569.510 +    }
 569.511 +  }
 569.512 +  (*bn) (BLOCK_NONE,NIL);
 569.513 +  return T;			/* all done */
 569.514 +}
 569.515 +
 569.516 +
 569.517 +/* TCP/IP close
 569.518 + * Accepts: TCP/IP stream
 569.519 + */
 569.520 +
 569.521 +void tcp_close (TCPSTREAM *stream)
 569.522 +{
 569.523 +  tcp_abort (stream);		/* nuke the sockets */
 569.524 +				/* flush host names */
 569.525 +  if (stream->host) fs_give ((void **) &stream->host);
 569.526 +  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
 569.527 +  if (stream->localhost) fs_give ((void **) &stream->localhost);
 569.528 +  fs_give ((void **) &stream);	/* flush the stream */
 569.529 +}
 569.530 +
 569.531 +
 569.532 +/* TCP/IP abort sockets
 569.533 + * Accepts: TCP/IP stream
 569.534 + * Returns: NIL, always
 569.535 + */
 569.536 +
 569.537 +long tcp_abort (TCPSTREAM *stream)
 569.538 +{
 569.539 +  if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
 569.540 +  else stream->tcpso = INVALID_SOCKET;
 569.541 +  return tcp_close_socket (&stream->tcpsi);
 569.542 +}
 569.543 +
 569.544 +
 569.545 +/* TCP/IP abort stream
 569.546 + * Accepts: WinSock socket
 569.547 + * Returns: NIL, always
 569.548 + */
 569.549 +
 569.550 +long tcp_close_socket (SOCKET *sock)
 569.551 +{
 569.552 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 569.553 +				/* something to close? */
 569.554 +  if (sock && (*sock != INVALID_SOCKET)) {
 569.555 +    (*bn) (BLOCK_TCPCLOSE,NIL);
 569.556 +    closesocket (*sock);	/* WinSock socket close */
 569.557 +    *sock = INVALID_SOCKET;
 569.558 +    (*bn) (BLOCK_NONE,NIL);
 569.559 +    wsa_sock_open--;		/* drop this socket */
 569.560 +  }
 569.561 +				/* no more open streams? */
 569.562 +  if (wsa_initted && !wsa_sock_open) {
 569.563 +    mm_log ("Winsock cleanup",NIL);
 569.564 +    wsa_initted = 0;		/* no more sockets, so... */
 569.565 +    WSACleanup ();		/* free up resources until needed */
 569.566 +  }
 569.567 +  return NIL;
 569.568 +}
 569.569 +
 569.570 +/* TCP/IP get host name
 569.571 + * Accepts: TCP/IP stream
 569.572 + * Returns: host name for this stream
 569.573 + */
 569.574 +
 569.575 +char *tcp_host (TCPSTREAM *stream)
 569.576 +{
 569.577 +  return stream->host;		/* use tcp_remotehost() if want guarantees */
 569.578 +}
 569.579 +
 569.580 +
 569.581 +/* TCP/IP get remote host name
 569.582 + * Accepts: TCP/IP stream
 569.583 + * Returns: host name for this stream
 569.584 + */
 569.585 +
 569.586 +char *tcp_remotehost (TCPSTREAM *stream)
 569.587 +{
 569.588 +  if (!stream->remotehost) {
 569.589 +    struct sockaddr_in sin;
 569.590 +    int sinlen = sizeof (struct sockaddr_in);
 569.591 +    stream->remotehost =	/* get socket's peer name */
 569.592 +      ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
 569.593 +	SOCKET_ERROR) || (sinlen <= 0)) ?
 569.594 +	  cpystr (stream->host) : tcp_name (&sin,NIL);
 569.595 +  }
 569.596 +  return stream->remotehost;
 569.597 +}
 569.598 +
 569.599 +
 569.600 +/* TCP/IP return port for this stream
 569.601 + * Accepts: TCP/IP stream
 569.602 + * Returns: port number for this stream
 569.603 + */
 569.604 +
 569.605 +unsigned long tcp_port (TCPSTREAM *stream)
 569.606 +{
 569.607 +  return stream->port;		/* return port number */
 569.608 +}
 569.609 +
 569.610 +
 569.611 +/* TCP/IP get local host name
 569.612 + * Accepts: TCP/IP stream
 569.613 + * Returns: local host name
 569.614 + */
 569.615 +
 569.616 +char *tcp_localhost (TCPSTREAM *stream)
 569.617 +{
 569.618 +  if (!stream->localhost) {
 569.619 +    struct sockaddr_in sin;
 569.620 +    int sinlen = sizeof (struct sockaddr_in);
 569.621 +    stream->localhost =		/* get socket's name */
 569.622 +      ((stream->port & 0xffff000) ||
 569.623 +       ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
 569.624 +	 SOCKET_ERROR) || (sinlen <= 0))) ?
 569.625 +	   cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
 569.626 +  }
 569.627 +  return stream->localhost;	/* return local host name */
 569.628 +}
 569.629 +
 569.630 +/* TCP/IP get client host address (server calls only)
 569.631 + * Returns: client host address
 569.632 + */
 569.633 +
 569.634 +char *tcp_clientaddr ()
 569.635 +{
 569.636 +  if (!myClientAddr) {
 569.637 +    struct sockaddr_in sin;
 569.638 +    int sinlen = sizeof (struct sockaddr_in);
 569.639 +    myClientAddr =		/* get stdin's peer name */
 569.640 +      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 569.641 +       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
 569.642 +  }
 569.643 +  return myClientAddr;
 569.644 +}
 569.645 +
 569.646 +
 569.647 +/* TCP/IP get client host name (server calls only)
 569.648 + * Returns: client host name
 569.649 + */
 569.650 +
 569.651 +char *tcp_clienthost ()
 569.652 +{
 569.653 +  if (!myClientHost) {
 569.654 +    struct sockaddr_in sin;
 569.655 +    int sinlen = sizeof (struct sockaddr_in);
 569.656 +    myClientHost =		/* get stdin's peer name */
 569.657 +      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 569.658 +       (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T);
 569.659 +  }
 569.660 +  return myClientHost;
 569.661 +}
 569.662 +
 569.663 +/* TCP/IP get server host address (server calls only)
 569.664 + * Returns: server host address
 569.665 + */
 569.666 +
 569.667 +char *tcp_serveraddr ()
 569.668 +{
 569.669 +  if (!myServerAddr) {
 569.670 +    struct sockaddr_in sin;
 569.671 +    int sinlen = sizeof (struct sockaddr_in);
 569.672 +    myServerAddr =		/* get stdin's peer name */
 569.673 +      ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 569.674 +       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
 569.675 +  }
 569.676 +  return myServerAddr;
 569.677 +}
 569.678 +
 569.679 +
 569.680 +/* TCP/IP get server host name (server calls only)
 569.681 + * Returns: server host name
 569.682 + */
 569.683 +
 569.684 +static long myServerPort = -1;
 569.685 +
 569.686 +char *tcp_serverhost ()
 569.687 +{
 569.688 +  if (!myServerHost) {
 569.689 +    struct sockaddr_in sin;
 569.690 +    int sinlen = sizeof (struct sockaddr_in);
 569.691 +    if (!wsa_initted++) {	/* init Windows Sockets */
 569.692 +      WSADATA wsock;
 569.693 +      if (WSAStartup (WSA_VERSION,&wsock)) {
 569.694 +	wsa_initted = 0;
 569.695 +	return "random-pc";	/* try again later? */
 569.696 +      }
 569.697 +    }
 569.698 +				/* get stdin's name */
 569.699 +    if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
 569.700 +	(sinlen <= 0)) myServerHost = cpystr (mylocalhost ());
 569.701 +    else {
 569.702 +      myServerHost = tcp_name (&sin,NIL);
 569.703 +      myServerPort = ntohs (sin.sin_port);
 569.704 +    }
 569.705 +  }
 569.706 +  return myServerHost;
 569.707 +}
 569.708 +
 569.709 +
 569.710 +/* TCP/IP get server port number (server calls only)
 569.711 + * Returns: server port number
 569.712 + */
 569.713 +
 569.714 +long tcp_serverport ()
 569.715 +{
 569.716 +  if (!myServerHost) tcp_serverhost ();
 569.717 +  return myServerPort;
 569.718 +}
 569.719 +
 569.720 +/* TCP/IP return canonical form of host name
 569.721 + * Accepts: host name
 569.722 + * Returns: canonical form of host name
 569.723 + */
 569.724 +
 569.725 +char *tcp_canonical (char *name)
 569.726 +{
 569.727 +  char *ret,host[MAILTMPLEN];
 569.728 +  struct hostent *he;
 569.729 +  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
 569.730 +				/* look like domain literal? */
 569.731 +  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
 569.732 +  (*bn) (BLOCK_DNSLOOKUP,NIL);
 569.733 +  if (tcpdebug) {
 569.734 +    sprintf (host,"DNS canonicalization %.80s",name);
 569.735 +    mm_log (host,TCPDEBUG);
 569.736 +  }
 569.737 +				/* note that NT requires lowercase! */
 569.738 +  ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name;
 569.739 +  (*bn) (BLOCK_NONE,NIL);
 569.740 +  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
 569.741 +  return ret;
 569.742 +}
 569.743 +
 569.744 +
 569.745 +/* TCP/IP return name from socket
 569.746 + * Accepts: socket
 569.747 + *	    verbose flag
 569.748 + * Returns: cpystr name
 569.749 + */
 569.750 +
 569.751 +char *tcp_name (struct sockaddr_in *sin,long flag)
 569.752 +{
 569.753 +  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
 569.754 +  sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
 569.755 +  if (allowreversedns) {
 569.756 +    struct hostent *he;
 569.757 +    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
 569.758 +    void *data;
 569.759 +    if (tcpdebug) {
 569.760 +      sprintf (tmp,"Reverse DNS resolution %s",adr);
 569.761 +      mm_log (tmp,TCPDEBUG);
 569.762 +    }
 569.763 +    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
 569.764 +    data = (*bn) (BLOCK_SENSITIVE,NIL);
 569.765 +				/* translate address to name */
 569.766 +    if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
 569.767 +						 sizeof (struct in_addr),
 569.768 +						 sin->sin_family)) ?
 569.769 +			    (char *) he->h_name : NIL)) {
 569.770 +				/* produce verbose form if needed */
 569.771 +      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
 569.772 +      else ret = t;
 569.773 +    }
 569.774 +    (*bn) (BLOCK_NONSENSITIVE,data);
 569.775 +    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
 569.776 +    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
 569.777 +  }
 569.778 +  return cpystr (ret);
 569.779 +}
 569.780 +
 569.781 +/* Return my local host name
 569.782 + * Returns: my local host name
 569.783 + */
 569.784 +
 569.785 +char *mylocalhost (void)
 569.786 +{
 569.787 +  if (!myLocalHost) {
 569.788 +    char tmp[MAILTMPLEN];
 569.789 +    if (!wsa_initted++) {	/* init Windows Sockets */
 569.790 +      WSADATA wsock;
 569.791 +      if (WSAStartup (WSA_VERSION,&wsock)) {
 569.792 +	wsa_initted = 0;
 569.793 +	return "random-pc";	/* try again later? */
 569.794 +      }
 569.795 +    }
 569.796 +    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
 569.797 +			  "random-pc" : tcp_canonical (tmp));
 569.798 +  }
 569.799 +  return myLocalHost;
 569.800 +}
 569.801 +
 569.802 +
 569.803 +/* Validate name
 569.804 + * Accepts: domain name
 569.805 + * Returns: T if valid, NIL otherwise
 569.806 + */
 569.807 +
 569.808 +char *tcp_name_valid (char *s)
 569.809 +{
 569.810 +  int c;
 569.811 +  char *ret,*tail;
 569.812 +				/* must be non-empty and not too long */
 569.813 +  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
 569.814 +				/* must be alnum, dot, or hyphen */
 569.815 +    while ((c = *s++) && (s <= tail) &&
 569.816 +	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
 569.817 +	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
 569.818 +    if (c) ret = NIL;
 569.819 +  }
 569.820 +  return ret;
 569.821 +}
   570.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   570.2 +++ b/src/osdep/wce/tcp_wce.h	Mon Sep 14 15:17:45 2009 +0900
   570.3 @@ -0,0 +1,46 @@
   570.4 +/* ========================================================================
   570.5 + * Copyright 1988-2006 University of Washington
   570.6 + *
   570.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   570.8 + * you may not use this file except in compliance with the License.
   570.9 + * You may obtain a copy of the License at
  570.10 + *
  570.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  570.12 + *
  570.13 + * 
  570.14 + * ========================================================================
  570.15 + */
  570.16 +
  570.17 +/*
  570.18 + * Program:	Winsock TCP/IP routines
  570.19 + *
  570.20 + * Author:	Mike Seibel from Unix version by Mark Crispin
  570.21 + *		Computing & Communications
  570.22 + *		University of Washington
  570.23 + *		Administration Building, AG-44
  570.24 + *		Seattle, WA  98195
  570.25 + *		Internet: MRC@CAC.Washington.EDU
  570.26 + *
  570.27 + * Date:	11 April 1989
  570.28 + * Last Edited:	30 August 2006
  570.29 + */
  570.30 +
  570.31 +/* TCP input buffer -- must be large enough to prevent overflow */
  570.32 +
  570.33 +#define BUFLEN 8192
  570.34 +
  570.35 +
  570.36 +/* TCP I/O stream (must be before osdep.h is included) */
  570.37 +
  570.38 +#define TCPSTREAM struct tcp_stream
  570.39 +TCPSTREAM {
  570.40 +  char *host;			/* host name */
  570.41 +  char *remotehost;		/* remote host name */
  570.42 +  unsigned long port;		/* port number */
  570.43 +  char *localhost;		/* local host name */
  570.44 +  int tcpsi;			/* input tcp socket */
  570.45 +  int tcpso;			/* output tcp socket */
  570.46 +  long ictr;			/* input counter */
  570.47 +  char *iptr;			/* input pointer */
  570.48 +  char ibuf[BUFLEN];		/* input buffer */
  570.49 +};
   571.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   571.2 +++ b/src/tmail/Makefile	Mon Sep 14 15:17:45 2009 +0900
   571.3 @@ -0,0 +1,53 @@
   571.4 +# ========================================================================
   571.5 +# Copyright 1988-2006 University of Washington
   571.6 +#
   571.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   571.8 +# you may not use this file except in compliance with the License.
   571.9 +# You may obtain a copy of the License at
  571.10 +#
  571.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  571.12 +#
  571.13 +# 
  571.14 +# ========================================================================
  571.15 +
  571.16 +
  571.17 +# Program:	tmail Makefile
  571.18 +#
  571.19 +# Author:	Mark Crispin
  571.20 +#		Networks and Distributed Computing
  571.21 +#		Computing & Communications
  571.22 +#		University of Washington
  571.23 +#		Administration Building, AG-44
  571.24 +#		Seattle, WA  98195
  571.25 +#		Internet: MRC@CAC.Washington.EDU
  571.26 +#
  571.27 +# Date:		5 April 1993
  571.28 +# Last Edited:	10 September 2007
  571.29 +
  571.30 +
  571.31 +C = ../c-client
  571.32 +CCLIENTLIB = $C/c-client.a
  571.33 +SHELL = /bin/sh
  571.34 +
  571.35 +# Get local definitions from c-client directory
  571.36 +
  571.37 +CC = `cat $C/CCTYPE`
  571.38 +CFLAGS = -I$C `cat $C/CFLAGS`
  571.39 +LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
  571.40 +
  571.41 +tmail: $(CCLIENTLIB) tmail.o tquota.o
  571.42 +	$(CC) $(CFLAGS) -o tmail tmail.o tquota.o $(LDFLAGS)
  571.43 +
  571.44 +tmail.o: $C/mail.h $C/misc.h $C/osdep.h tquota.h
  571.45 +
  571.46 +tquota.o: tquota.h
  571.47 +
  571.48 +$(CCLIENTLIB):
  571.49 +	cd $C;make
  571.50 +
  571.51 +clean:
  571.52 +	rm -f *.o tmail
  571.53 +
  571.54 +# A monument to a hack of long ago and far away...
  571.55 +love:
  571.56 +	@echo 'not war?'
   572.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   572.2 +++ b/src/tmail/tmail.1	Mon Sep 14 15:17:45 2009 +0900
   572.3 @@ -0,0 +1,205 @@
   572.4 +.ig
   572.5 + * ========================================================================
   572.6 + * Copyright 1988-2007 University of Washington
   572.7 + *
   572.8 + * Licensed under the Apache License, Version 2.0 (the "License");
   572.9 + * you may not use this file except in compliance with the License.
  572.10 + * You may obtain a copy of the License at
  572.11 + *
  572.12 + *     http://www.apache.org/licenses/LICENSE-2.0
  572.13 + *
  572.14 + * 
  572.15 + * ========================================================================
  572.16 +..
  572.17 +.TH TMAIL 1 "September 27, 2007"
  572.18 +.SH NAME
  572.19 +tmail \- Mail Delivery Module
  572.20 +.nh
  572.21 +.SH SYNOPSIS
  572.22 +.B tmail
  572.23 +.I [-b format] [\-D] [-f from_name] [\-I inbox_specifier] user[+folder] ...
  572.24 +.SH DESCRIPTION
  572.25 +.I tmail
  572.26 +delivers mail to a user's INBOX or a designated folder.
  572.27 +.I tmail
  572.28 +may be configured as a drop-in replacement for
  572.29 +.IR binmail (1),
  572.30 +.IR mail.local (1)
  572.31 +or any program intended for use for mail delivery by a mail delivery program
  572.32 +such as
  572.33 +.IR sendmail (8).
  572.34 +.PP
  572.35 +.I tmail
  572.36 +is intended to be used for direct delivery by the mailer daemon;
  572.37 +.IR dmail (1)
  572.38 +is the preferred tool for user applications, e.g. a mail delivery
  572.39 +filter such as
  572.40 +.IR procmail (1) .
  572.41 +If
  572.42 +.I tmail
  572.43 +is used for a user application,
  572.44 +then the calling program must be aware of the restrictions noted below.
  572.45 +.PP
  572.46 +When
  572.47 +.I tmail
  572.48 +exits, it returns exit status values to enable the mail delivery program
  572.49 +to determine whether a message was delivered successfully or had a
  572.50 +temporary (requeue for later delivery) or permanent (return to sender)
  572.51 +failure.
  572.52 +.PP
  572.53 +If the 
  572.54 +.I +folder
  572.55 +extension is included in the user argument, 
  572.56 +.I tmail
  572.57 +will attempt to deliver to the designated folder.  If the folder does not 
  572.58 +exist or the extension is not included, the message is delivered to the 
  572.59 +user's INBOX.
  572.60 +If delivery is to INBOX and no INBOX currently exists,
  572.61 +.I tmail
  572.62 +will create a new INBOX, using the \fB-I\fR or \fB-b\fR flag if specified.
  572.63 +.I tmail
  572.64 +recognizes the format of an existing INBOX or folder, and appends the new
  572.65 +message in that format.
  572.66 +.PP
  572.67 +The \fB-b\fR flag specifies a format to create INBOX if INBOX does not
  572.68 +already exist.  This flag requires privileges, and can not be used with
  572.69 +\fB-I\fR.  The argument is
  572.70 +a format name such as mix, mbx, etc.
  572.71 +.PP
  572.72 +The \fB-D\fR flag specifies debugging; this enables additional message
  572.73 +telemetry.
  572.74 +.PP
  572.75 +The \fB-f\fR or \fB-r\fR flag is used by
  572.76 +the mail delivery program to specify a Return-Path.  The header
  572.77 +.br
  572.78 +   Return-Path: <\fIfrom_name\fR> 
  572.79 +.br 
  572.80 +is prepended to the message before delivery.  
  572.81 +.PP
  572.82 +The \fB-I\fR flag is used by the mail delivery program
  572.83 +to specify an alternative INBOX name.  This flag requires privileges,
  572.84 +and can not be used with \fB-b\fR.  This affects the location and format
  572.85 +of INBOX.  If specified, it should be in one of three forms:
  572.86 +.sp
  572.87 +The first form of argument to \fB-I\fR is the string "INBOX", which
  572.88 +means to write to the system default inbox using the system default
  572.89 +mailbox format.  These system defaults are defined when the c-client
  572.90 +library is built.
  572.91 +.sp
  572.92 +The second form of argument to \fB-I\fR is a delivery specification,
  572.93 +consisting of "#driver.", a c-client mailbox format driver name, "/",
  572.94 +and a file name.  This will write to the specified file in the
  572.95 +specified format.  For example, #driver.mbx/INBOX will write to file
  572.96 +"INBOX" in the home directory in mbx format; and
  572.97 +#driver.unix/mail/incoming will write to file "incoming" in the
  572.98 +user's "mail" subdirectory in unix (default UNIX) format.
  572.99 +.sp
 572.100 +The third form of argument to \fB-I\fR is any other name.  Normally,
 572.101 +this will write to the specified file on the user's home directory in
 572.102 +the specified format.  However, certain names are special.  These are:
 572.103 +.PP
 572.104 +.nf
 572.105 +  value       equivalant to
 572.106 +  -----       -------------
 572.107 +  INBOX.MTX   #driver.mtx/INBOX.MTX
 572.108 +  mbox        #driver.unix/mbox
 572.109 +  mail.txt    #driver.tenex/mail.txt
 572.110 +.fi
 572.111 +.PP
 572.112 +If \fB-I\fR is not specified, the default action is \fB-I INBOX\fR.
 572.113 +.PP
 572.114 +If multiple recipients are specified on the command line,
 572.115 +.I tmail
 572.116 +spawns one child process per recipient to perform actual delivery.  This
 572.117 +way of calling
 572.118 +.I tmail
 572.119 +is not recommended; see below under
 572.120 +.IR RESTRICTIONS .
 572.121 +.SH INSTALLATION
 572.122 +If 
 572.123 +.I tmail
 572.124 +is to be used for mail delivery from the mail delivery program, it 
 572.125 +.I must
 572.126 +be installed setuid root.
 572.127 +.sp
 572.128 +If sendmail is the mail delivery program,
 572.129 +.I tmail
 572.130 +is invoked from sendmail.cf.  Look for the "Mlocal" line, and substitute
 572.131 +the path name for the
 572.132 +.I tmail
 572.133 +binary in place of /bin/mail, /usr/lib/mail.local, etc.  You should also
 572.134 +add the flag to invoke
 572.135 +.I tmail
 572.136 +with CRLF style newlines; this is usually done with E=\\r\\n in the Mlocal
 572.137 +line.
 572.138 +.sp
 572.139 +Here is an example of an Mlocal line in sendmail version 8:
 572.140 +.sp
 572.141 +.nf
 572.142 +Mlocal, P=/usr/local/etc/tmail, F=lsDFMAw5:/|@qPrn+,
 572.143 +  S=10/30, R=20/40, E=\\r\\n, T=DNS/RFC822/X-Unix,
 572.144 +  A=tmail $u
 572.145 +.fi
 572.146 +.PP
 572.147 +If
 572.148 +.I tmail
 572.149 +is to be called with the \fB-I\fR flag, it must be invoked with both
 572.150 +real and effective UID root.  Many sendmail configurations invoke the
 572.151 +local mailer as the sending user when that user is local, which
 572.152 +will prevent \fB-b\fR or \fB-I\fR from working.
 572.153 +.SH SECURITY CONSIDERATIONS
 572.154 +If
 572.155 +.I tmail
 572.156 +is invoked by an ordinary user, the Received: header line will
 572.157 +indicate the name or UID of the user that invoked it.
 572.158 +.PP
 572.159 +Ordinary users are not permitted to use the \fB-b\fR or \fB-I\fR flag since
 572.160 +otherwise a user could create any file on another user's directory.
 572.161 +.PP
 572.162 +.I tmail
 572.163 +can deliver mail to home directories.  In addition,
 572.164 +.I tmail
 572.165 +can be used to deliver mail to other mail folders in a home directory
 572.166 +or an inferior directory of a home directory.
 572.167 +.SH RESTRICTIONS
 572.168 +The calling program should invoke
 572.169 +.I tmail
 572.170 +with CRLF newlines, otherwise
 572.171 +.I tmail
 572.172 +will complain in syslog.
 572.173 +.PP
 572.174 +Absolute pathnames and 
 572.175 +.I ~user
 572.176 +specifications are not permitted in
 572.177 +.I +folder
 572.178 +extensions.
 572.179 +.PP
 572.180 +Ordinary users are not permitted to use the \fB-I\fR flag.
 572.181 +.PP
 572.182 +IMAP4 namespace names are not yet supported in 
 572.183 +.I +folder
 572.184 +extensions.
 572.185 +.PP
 572.186 +It is not possible to use
 572.187 +.I tmail
 572.188 +to deliver to
 572.189 +.IR mh (1)
 572.190 +format mailboxes.
 572.191 +.PP
 572.192 +If delivery to multiple users is specified and delivery to any single user
 572.193 +fails, the entire delivery will be reported as having failed, even though
 572.194 +delivery to other users may have succeeded.  If
 572.195 +.I tmail
 572.196 +is used for mail delivery from
 572.197 +.IR sendmail (8),
 572.198 +a separate tmail invocation should be done for each user.  Otherwise a
 572.199 +delivery failure for a single user in a message going to multiple users
 572.200 +will cause multiple deliveries to all the other users every time
 572.201 +.IR sendmail (8),
 572.202 +retries.
 572.203 +.SH AUTHOR
 572.204 +Mark Crispin, MRC@CAC.Washington.EDU
 572.205 +.SH "SEE ALSO"
 572.206 +binmail(1)
 572.207 +.br
 572.208 +sendmail(8)
   573.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   573.2 +++ b/src/tmail/tmail.c	Mon Sep 14 15:17:45 2009 +0900
   573.3 @@ -0,0 +1,800 @@
   573.4 +/* ========================================================================
   573.5 + * Copyright 1988-2007 University of Washington
   573.6 + *
   573.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   573.8 + * you may not use this file except in compliance with the License.
   573.9 + * You may obtain a copy of the License at
  573.10 + *
  573.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  573.12 + *
  573.13 + * 
  573.14 + * ========================================================================
  573.15 + */
  573.16 +
  573.17 +/*
  573.18 + * Program:	Mail Delivery Module
  573.19 + *
  573.20 + * Author:	Mark Crispin
  573.21 + *		Networks and Distributed Computing
  573.22 + *		Computing & Communications
  573.23 + *		University of Washington
  573.24 + *		Administration Building, AG-44
  573.25 + *		Seattle, WA  98195
  573.26 + *		Internet: MRC@CAC.Washington.EDU
  573.27 + *
  573.28 + * Date:	5 April 1993
  573.29 + * Last Edited:	30 October 2008
  573.30 + */
  573.31 +
  573.32 +#include <stdio.h>
  573.33 +#include <pwd.h>
  573.34 +#include <errno.h>
  573.35 +extern int errno;		/* just in case */
  573.36 +#include <sysexits.h>
  573.37 +#include <sys/file.h>
  573.38 +#include <sys/stat.h>
  573.39 +#include "c-client.h"
  573.40 +#include "tquota.h"
  573.41 +
  573.42 +
  573.43 +/* Globals */
  573.44 +
  573.45 +char *version = "22";		/* tmail edit version */
  573.46 +int debug = NIL;		/* debugging (don't fork) */
  573.47 +int trycreate = NIL;		/* flag saying gotta create before appending */
  573.48 +int critical = NIL;		/* flag saying in critical code */
  573.49 +char *sender = NIL;		/* message origin */
  573.50 +char *inbox = NIL;		/* inbox file */
  573.51 +long precedence = 0;		/* delivery precedence - used by quota hook */
  573.52 +DRIVER *format = NIL;		/* desired format */
  573.53 +
  573.54 +
  573.55 +/* Function prototypes */
  573.56 +
  573.57 +void file_string_init (STRING *s,void *data,unsigned long size);
  573.58 +char file_string_next (STRING *s);
  573.59 +void file_string_setpos (STRING *s,unsigned long i);
  573.60 +int main (int argc,char *argv[]);
  573.61 +int deliver (FILE *f,unsigned long msglen,char *user);
  573.62 +long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
  573.63 +int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
  573.64 +		    uid_t uid,char *tmp);
  573.65 +int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp);
  573.66 +int fail (char *string,int code);
  573.67 +char *getusername (char *s,char **t);
  573.68 +
  573.69 +
  573.70 +/* File string driver for file stringstructs */
  573.71 +
  573.72 +STRINGDRIVER file_string = {
  573.73 +  file_string_init,		/* initialize string structure */
  573.74 +  file_string_next,		/* get next byte in string structure */
  573.75 +  file_string_setpos		/* set position in string structure */
  573.76 +};
  573.77 +
  573.78 +
  573.79 +/* Cache buffer for file stringstructs */
  573.80 +
  573.81 +#define CHUNKLEN 16384
  573.82 +char chunk[CHUNKLEN];
  573.83 +
  573.84 +/* Initialize file string structure for file stringstruct
  573.85 + * Accepts: string structure
  573.86 + *	    pointer to string
  573.87 + *	    size of string
  573.88 + */
  573.89 +
  573.90 +void file_string_init (STRING *s,void *data,unsigned long size)
  573.91 +{
  573.92 +  s->data = data;		/* note fd */
  573.93 +  s->size = size;		/* note size */
  573.94 +  s->chunk = chunk;
  573.95 +  s->chunksize = (unsigned long) CHUNKLEN;
  573.96 +  SETPOS (s,0);			/* set initial position */
  573.97 +}
  573.98 +
  573.99 +
 573.100 +/* Get next character from file stringstruct
 573.101 + * Accepts: string structure
 573.102 + * Returns: character, string structure chunk refreshed
 573.103 + */
 573.104 +
 573.105 +char file_string_next (STRING *s)
 573.106 +{
 573.107 +  char c = *s->curpos++;	/* get next byte */
 573.108 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
 573.109 +  return c;			/* return the byte */
 573.110 +}
 573.111 +
 573.112 +
 573.113 +/* Set string pointer position for file stringstruct
 573.114 + * Accepts: string structure
 573.115 + *	    new position
 573.116 + */
 573.117 +
 573.118 +void file_string_setpos (STRING *s,unsigned long i)
 573.119 +{
 573.120 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
 573.121 +  s->offset = i;		/* set new offset */
 573.122 +  s->curpos = s->chunk;		/* reset position */
 573.123 +				/* set size of data */
 573.124 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
 573.125 +				/* move to that position in the file */
 573.126 +    fseek ((FILE *) s->data,s->offset,SEEK_SET);
 573.127 +    fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
 573.128 +  }
 573.129 +}
 573.130 +
 573.131 +/* Main program */
 573.132 +
 573.133 +int main (int argc,char *argv[])
 573.134 +{
 573.135 +  FILE *f = NIL;
 573.136 +  int pid,c,ret = 0;
 573.137 +  unsigned long msglen,status = 0;
 573.138 +  char *s,tmp[MAILTMPLEN];
 573.139 +  uid_t ruid = getuid ();
 573.140 +  struct passwd *pwd;
 573.141 +  openlog ("tmail",LOG_PID,LOG_MAIL);
 573.142 +#include "linkage.c"
 573.143 +				/* make sure have some arguments */
 573.144 +  if (--argc < 1) _exit (fail ("usage: tmail [-D] user[+folder]",EX_USAGE));
 573.145 +				/* process all flags */
 573.146 +  while (argc && (*(s = *++argv)) == '-') {
 573.147 +    argc--;			/* gobble this argument */
 573.148 +    switch (s[1]) {		/* what is this flag? */
 573.149 +    case 'D':			/* debug */
 573.150 +      debug = T;		/* don't fork */
 573.151 +      break;
 573.152 +    case 'I':			/* inbox specifier */
 573.153 +      if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
 573.154 +      if (argc--) inbox = cpystr (*++argv);
 573.155 +      else _exit (fail ("missing argument to -I",EX_USAGE));
 573.156 +      break;
 573.157 +    case 'f':			/* new name for this flag */
 573.158 +    case 'r':			/* flag giving return path */
 573.159 +      if (sender) _exit (fail ("duplicate -f or -r",EX_USAGE));
 573.160 +      if (argc--) sender = cpystr (*++argv);
 573.161 +      else _exit (fail ("missing argument to -f or -r",EX_USAGE));
 573.162 +      break;
 573.163 +    case 'b':			/* create INBOX in this format */
 573.164 +      if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
 573.165 +      if (!argc--) _exit (fail ("missing argument to -b",EX_USAGE));
 573.166 +      if (!(format = mail_parameters (NIL,GET_DRIVER,*++argv)))
 573.167 +	_exit (fail ("unknown format to -b",EX_USAGE));
 573.168 +      else if (!(format->flags & DR_LOCAL) ||
 573.169 +	       !compare_cstring (format->name,"dummy"))
 573.170 +	_exit (fail ("invalid format to -b",EX_USAGE));
 573.171 +      break;
 573.172 +    /* following flags are undocumented */
 573.173 +    case 'p':			/* precedence for quota */
 573.174 +      if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
 573.175 +      else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
 573.176 +	precedence = atol (s);
 573.177 +      else _exit (fail ("missing argument to -p",EX_USAGE));
 573.178 +      break;
 573.179 +    case 'd':			/* obsolete flag meaning multiple users */
 573.180 +      break;			/* ignore silently */
 573.181 +    /* -s has been deprecated and replaced by the -s and -k flags in dmail.
 573.182 +     * dmail's -k flag does what -s once did in tmail; dmail's -s flag
 573.183 +     * takes no argument and just sets \Seen.  Flag setting is more properly
 573.184 +     * done in dmail which runs as the user and is clearly at the user's
 573.185 +     * behest.  Since tmail runs privileged, -s would have to be disabled
 573.186 +     * unless the caller is also privileged.
 573.187 +     */
 573.188 +    case 's':			/* obsolete flag meaning delivery flags */
 573.189 +      if (!argc--)		/* takes an argument */
 573.190 +	_exit (fail ("missing argument to deprecated flag",EX_USAGE));
 573.191 +      syslog (LOG_INFO,"tmail called with deprecated flag: -s %.200s",*++argv);
 573.192 +      break;
 573.193 +    default:			/* anything else */
 573.194 +      _exit (fail ("unknown switch",EX_USAGE));
 573.195 +    }
 573.196 +  }
 573.197 +
 573.198 +  if (!argc) ret = fail ("no recipients",EX_USAGE);
 573.199 +  else if (!(f = tmpfile ())) ret = fail ("can't make temp file",EX_TEMPFAIL);
 573.200 +  else {			/* build delivery headers */
 573.201 +    if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
 573.202 +				/* start Received line: */
 573.203 +    fprintf (f,"Received: via tmail-%s.%s",CCLIENTVERSION,version);
 573.204 +				/* not root or daemon? */
 573.205 +    if (ruid && !((pwd = getpwnam ("daemon")) && (ruid == pwd->pw_uid))) {
 573.206 +      pwd = getpwuid (ruid);	/* get unprivileged user's information */
 573.207 +      if (inbox || format) {
 573.208 +	if (pwd) sprintf (tmp,"user %.80s",pwd->pw_name);
 573.209 +	else sprintf (tmp,"UID %ld",(long) ruid);
 573.210 +	strcat (tmp," is not privileged to use -b or -I");
 573.211 +	_exit (fail (tmp,EX_USAGE));
 573.212 +      }
 573.213 +      fputs (" (invoked by ",f);
 573.214 +      if (pwd) fprintf (f,"user %s",pwd->pw_name);
 573.215 +      else fprintf (f,"UID %ld",(long) ruid);
 573.216 +      fputs (")",f);
 573.217 +    }
 573.218 +				/* write "for" if single recipient */
 573.219 +    if (argc == 1) fprintf (f," for %s",*argv);
 573.220 +    fputs ("; ",f);
 573.221 +    rfc822_date (tmp);
 573.222 +    fputs (tmp,f);
 573.223 +    fputs ("\015\012",f);
 573.224 +				/* copy text from standard input */
 573.225 +    if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
 573.226 +	(s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
 573.227 +    if (s[-1] == '\015') {	/* nuke leading "From " line */
 573.228 +      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
 573.229 +	  (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
 573.230 +      while ((c = getchar ()) != EOF) putc (c,f);
 573.231 +    }
 573.232 +    else {
 573.233 +      mm_log ("tmail called with LF-only newlines",WARN);
 573.234 +      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
 573.235 +	  (tmp[3] != 'm') || (tmp[4] != ' ')) {
 573.236 +	*s++ = '\015';		/* overwrite NL with CRLF */
 573.237 +	*s++ = '\012';
 573.238 +	*s = '\0';		/* tie off string */
 573.239 +	fputs (tmp,f);		/* write line */
 573.240 +      }
 573.241 +				/* copy text from standard input */
 573.242 +      while ((c = getchar ()) != EOF) {
 573.243 +				/* add CR if needed */
 573.244 +	if (c == '\012') putc ('\015',f);
 573.245 +	putc (c,f);
 573.246 +      }
 573.247 +    }
 573.248 +    msglen = ftell (f);		/* size of message */
 573.249 +    fflush (f);			/* make sure all changes written out */
 573.250 +
 573.251 +    if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
 573.252 +    else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
 573.253 +				/* single delivery */
 573.254 +    else if (argc == 1) ret = deliver (f,msglen,*argv);
 573.255 +    else do {			/* multiple delivery uses daughter forks */
 573.256 +      if ((pid = fork ()) < 0) ret = fail (strerror (errno),EX_OSERR);
 573.257 +      else if (pid) {		/* mother process */
 573.258 +	grim_pid_reap_status (pid,NIL,(void *) status);
 573.259 +				/* normal termination? */
 573.260 +	if (!ret) ret = (status & 0xff) ? EX_SOFTWARE : (status & 0xff00) >> 8;
 573.261 +      }
 573.262 +				/* daughter process */
 573.263 +      else _exit (deliver (f,msglen,*argv));
 573.264 +    } while (--argc && *argv++);
 573.265 +    mm_dlog (ret ? "error in delivery" : "all recipients delivered");
 573.266 +  }
 573.267 +  if (f) fclose (f);		/* all done with temporary file */
 573.268 +  _exit (ret);			/* normal exit */
 573.269 +  return 0;			/* stupid gcc */
 573.270 +}
 573.271 +
 573.272 +/* Deliver message to recipient list
 573.273 + * Accepts: file description of message temporary file
 573.274 + *	    size of message temporary file in bytes
 573.275 + *	    recipient name
 573.276 + * Returns: NIL if success, else error code
 573.277 + */
 573.278 +
 573.279 +int deliver (FILE *f,unsigned long msglen,char *user)
 573.280 +{
 573.281 +  MAILSTREAM *ds = NIL;
 573.282 +  char *s,*t,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
 573.283 +  struct passwd *pwd;
 573.284 +  STRING st;
 573.285 +  struct stat sbuf;
 573.286 +  uid_t duid;
 573.287 +  uid_t euid = geteuid ();
 573.288 +				/* get user record */
 573.289 +  if (!(pwd = getpwnam (getusername (user,&mailbox)))) {
 573.290 +    sprintf (tmp,"no such user as %.80s",user);
 573.291 +    return fail (tmp,EX_NOUSER);
 573.292 +  }
 573.293 +				/* absurd is absurd */
 573.294 +  if (mailbox && (strlen (mailbox) > 256))
 573.295 +    return fail ("absurd folder name",EX_NOUSER);
 573.296 +				/* big security hole if this is allowed */
 573.297 +  if (!(duid = pwd->pw_uid)) return fail ("mail to root prohibited",EX_NOUSER);
 573.298 +				/* log in as user if different than euid */
 573.299 +  if ((duid != euid) && !loginpw (pwd,1,&user)) {
 573.300 +    sprintf (tmp,"unable to log in UID %ld from UID %ld",
 573.301 +	     (long) duid,(long) euid);
 573.302 +    return fail (tmp,EX_NOUSER);
 573.303 +  }
 573.304 +				/* can't use pwd after this point */
 573.305 +  env_init (pwd->pw_name,pwd->pw_dir);
 573.306 +  sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
 573.307 +  mm_dlog (tmp);
 573.308 +				/* prepare stringstruct */
 573.309 +  INIT (&st,file_string,(void *) f,msglen);
 573.310 +  if (mailbox) {		/* non-INBOX name */
 573.311 +    switch (mailbox[0]) {	/* make sure a valid name */
 573.312 +    default:			/* other names, try to deliver if not INBOX */
 573.313 +      if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
 573.314 +	  !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
 573.315 +	  !deliver_safely (NIL,&st,mailbox,path,duid,tmp)) return NIL;
 573.316 +    case '%': case '*':		/* wildcards not valid */
 573.317 +    case '#':			/* namespace name not valid */
 573.318 +    case '/':			/* absolute path names not valid */
 573.319 +    case '~':			/* user names not valid */
 573.320 +      sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
 573.321 +      mm_log (tmp,WARN);
 573.322 +      break;
 573.323 +    }
 573.324 +    mm_dlog ("retrying delivery to INBOX");
 573.325 +    SETPOS (&st,0);		/* rewind stringstruct just in case */
 573.326 +  }
 573.327 +
 573.328 +				/* -I specified and not "-I INBOX"? */
 573.329 +  if (inbox && !(((inbox[0] == 'I') || (inbox[0] == 'i')) &&
 573.330 +		 ((inbox[1] == 'N') || (inbox[1] == 'n')) &&
 573.331 +		 ((inbox[2] == 'B') || (inbox[2] == 'b')) &&
 573.332 +		 ((inbox[3] == 'O') || (inbox[3] == 'o')) &&
 573.333 +		 ((inbox[4] == 'X') || (inbox[4] == 'x')) && !inbox[5])) {
 573.334 +    DRIVER *dv = NIL;
 573.335 +				/* "-I #driver.xxx/name"? */
 573.336 +    if ((*inbox == '#') && ((inbox[1] == 'd') || (inbox[1] == 'D')) &&
 573.337 +	((inbox[2] == 'r') || (inbox[2] == 'R')) &&
 573.338 +	((inbox[3] == 'i') || (inbox[3] == 'I')) &&
 573.339 +	((inbox[4] == 'v') || (inbox[4] == 'V')) &&
 573.340 +	((inbox[5] == 'e') || (inbox[5] == 'E')) &&
 573.341 +	((inbox[6] == 'r') || (inbox[6] == 'R')) && (inbox[7] == '.') &&
 573.342 +	(s = strchr (inbox+8,'/'))) {
 573.343 +      *s = '\0';		/* temporarily tie off driver name */
 573.344 +      if (!((dv = mail_parameters (NIL,GET_DRIVER,(void *) (inbox+8))) &&
 573.345 +	    (mailboxfile (path,s[1] ? s + 1 : "&&&&&") == path) &&
 573.346 +	    (s[1] || ((t = strstr (path,"&&&&&")) && strcpy (t,"INBOX"))))) {
 573.347 +	path[0] = '\0';		/* bad -I argument, no path resolved */
 573.348 +	sprintf (tmp,"Unable to resolve driver in %.80s, -I ignored",inbox);
 573.349 +	mm_log (tmp,WARN);
 573.350 +      }
 573.351 +      *s = '/';			/* restore delimiter */
 573.352 +    }
 573.353 +				/* resolve "-I other" specification */
 573.354 +    else if (mailboxfile (path,inbox) && path[0]) {
 573.355 +				/* resolution succeeded, impute driver */
 573.356 +      if (!strcmp (inbox,"mail.txt"))
 573.357 +	dv = mail_parameters (NIL,GET_DRIVER,(void *) "tenex");
 573.358 +      else if (!strcmp (inbox,"INBOX.MTX"))
 573.359 +	dv = mail_parameters (NIL,GET_DRIVER,(void *) "mtx");
 573.360 +      else if (!strcmp (inbox,"mbox"))
 573.361 +	dv = mail_parameters (NIL,GET_DRIVER,(void *) "unix");
 573.362 +    }
 573.363 +    else {			/* bad -I argument */
 573.364 +      path[0] = '\0';		/* no path resolved */
 573.365 +      sprintf (tmp,"Unable to resolve %.80s, -I ignored",inbox);
 573.366 +      mm_log (tmp,WARN);
 573.367 +    }
 573.368 +    if (*path) {		/* -I successfully resolved a path? */
 573.369 +      MAILSTREAM dpr;
 573.370 +      dpr.dtb = dv;
 573.371 +      if (dv) ds = &dpr;
 573.372 +				/* supplicate to the Evil One if necessary */
 573.373 +      if (lstat (path,&sbuf) && !path_create (ds,path)) {
 573.374 +				/* the Evil One rejected the plea */
 573.375 +	sprintf (tmp,"Unable to create %.80s, -I ignored",path);
 573.376 +	mm_log (tmp,WARN);
 573.377 +      }
 573.378 +				/* now attempt delivery */
 573.379 +      else return deliver_safely (ds,&st,inbox,path,duid,tmp);
 573.380 +    }
 573.381 +  }
 573.382 +
 573.383 +				/* no -I, resolve "INBOX" into path */
 573.384 +  if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
 573.385 +				/* clear box, get generic INBOX prototype */
 573.386 +    if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
 573.387 +      fatal ("no INBOX prototype");
 573.388 +				/* standard system driver? */
 573.389 +    if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
 573.390 +      strcpy (path,sysinbox ());/* use system INBOX */
 573.391 +      if (!lstat (path,&sbuf))	/* deliver to existing system INBOX */
 573.392 +	return deliver_safely (ds,&st,mailbox,path,duid,tmp);
 573.393 +    }
 573.394 +    else {			/* other driver, try ~/INBOX */
 573.395 +      if ((mailboxfile (path,"&&&&&") == path) &&
 573.396 +	  (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
 573.397 +	  !lstat (path,&sbuf)){	/* deliver to existing ~/INBOX */
 573.398 +	sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
 573.399 +	return deliver_safely (ds,&st,cpystr (tmp),path,duid,tmp);
 573.400 +      }
 573.401 +    }
 573.402 +				/* not dummy, deliver to driver imputed path */
 573.403 +    if (strcmp (ds->dtb->name,"dummy"))
 573.404 +      return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
 573.405 +	deliver_safely (ds,&st,mailbox,path,duid,tmp) :
 573.406 +	  fail ("unable to resolve INBOX path",EX_CANTCREAT);
 573.407 +				/* dummy, empty imputed append path exist? */
 573.408 +    if (ibxpath (ds = default_proto (T),&mailbox,path) &&
 573.409 +	!lstat (path,&sbuf) && !sbuf.st_size)
 573.410 +      return deliver_safely (ds,&st,mailbox,path,duid,tmp);
 573.411 +				/* impute path that we will create */
 573.412 +    if (!ibxpath (ds = format ? (format->open) (NIL) : default_proto (NIL),
 573.413 +		  &mailbox,path))
 573.414 +      return fail ("unable to resolve INBOX",EX_CANTCREAT);
 573.415 +  }
 573.416 +				/* black box, must create, get create proto */
 573.417 +  else if (lstat (path,&sbuf)) ds = default_proto (NIL);
 573.418 +  else {			/* black box, existing file */
 573.419 +				/* empty file, get append prototype */
 573.420 +    if (!sbuf.st_size) ds = default_proto (T);
 573.421 +				/* non-empty, get prototype from its data */
 573.422 +    else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
 573.423 +      fatal ("no INBOX prototype");
 573.424 +				/* error if unknown format */
 573.425 +    if (!strcmp (ds->dtb->name,"phile"))
 573.426 +      return fail ("unknown format INBOX",EX_UNAVAILABLE);
 573.427 +				/* otherwise can deliver to it */
 573.428 +    return deliver_safely (ds,&st,mailbox,path,duid,tmp);
 573.429 +  }
 573.430 +  sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
 573.431 +  mm_dlog (tmp);
 573.432 +				/* supplicate to the Evil One */
 573.433 +  if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
 573.434 +  sprintf (tmp,"created %.80s",path);
 573.435 +  mm_dlog (tmp);
 573.436 +				/* deliver the message */
 573.437 +  return deliver_safely (ds,&st,mailbox,path,duid,tmp);
 573.438 +}
 573.439 +
 573.440 +/* Resolve INBOX from driver prototype into mailbox name and filesystem path
 573.441 + * Accepts: driver prototype
 573.442 + * 	    pointer to mailbox name string pointer
 573.443 + *	    buffer to return mailbox path
 573.444 + * Returns: T if success, NIL if error
 573.445 + */
 573.446 +
 573.447 +long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
 573.448 +{
 573.449 +  char *s,tmp[MAILTMPLEN];
 573.450 +  long ret = T;
 573.451 +  if (!ds) ret = NIL;
 573.452 +  else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
 573.453 +    strcpy (path,sysinbox ());	/* use system INBOX for unix and MMDF */
 573.454 +  else if (!strcmp (ds->dtb->name,"tenex"))
 573.455 +    ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
 573.456 +  else if (!strcmp (ds->dtb->name,"mtx"))
 573.457 +    ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
 573.458 +  else if (!strcmp (ds->dtb->name,"mbox"))
 573.459 +    ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
 573.460 +				/* better not be a namespace driver */
 573.461 +  else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
 573.462 +				/* INBOX in home directory */
 573.463 +  else ret = ((mailboxfile (path,"&&&&&") == path) &&
 573.464 +	      (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
 573.465 +  if (ret) {			/* don't bother if lossage */
 573.466 +    sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
 573.467 +    *mailbox = cpystr (tmp);	/* name of INBOX in this namespace */
 573.468 +  }
 573.469 +  return ret;
 573.470 +}
 573.471 +
 573.472 +/* Deliver safely
 573.473 + * Accepts: prototype stream to force mailbox format
 573.474 + *	    stringstruct of message temporary file
 573.475 + *	    mailbox name
 573.476 + *	    filesystem path name
 573.477 + *	    user id
 573.478 + *	    scratch buffer for messages
 573.479 + * Returns: NIL if success, else error code
 573.480 + */
 573.481 +
 573.482 +int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
 573.483 +		    uid_t uid,char *tmp)
 573.484 +{
 573.485 +  struct stat sbuf;
 573.486 +  int i = delivery_unsafe (path,uid,&sbuf,tmp);
 573.487 +  if (i) return i;		/* give up now if delivery unsafe */
 573.488 +				/* directory, not file */
 573.489 +  if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
 573.490 +    if (sbuf.st_mode & 0001) {	/* listable directories may be worrisome */
 573.491 +      sprintf (tmp,"WARNING: directory %.80s is listable",path);
 573.492 +      mm_log (tmp,WARN);
 573.493 +    }
 573.494 +  }
 573.495 +  else {			/* file, not directory */
 573.496 +    if (sbuf.st_nlink != 1) {	/* multiple links may be worrisome */
 573.497 +      sprintf (tmp,"WARNING: multiple links to file %.80s",path);
 573.498 +      mm_log (tmp,WARN);
 573.499 +    }
 573.500 +    if (sbuf.st_mode & 0111) {	/* executable files may be worrisome */
 573.501 +      sprintf (tmp,"WARNING: file %.80s is executable",path);
 573.502 +      mm_log (tmp,WARN);
 573.503 +    }
 573.504 +  }
 573.505 +  if (sbuf.st_mode & 0002) {	/* public-write files may be worrisome */
 573.506 +    sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
 573.507 +    mm_log (tmp,WARN);
 573.508 +  }
 573.509 +  if (sbuf.st_mode & 0004) {	/* public-write files may be worrisome */
 573.510 +    sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
 573.511 +    mm_log (tmp,WARN);
 573.512 +  }
 573.513 +				/* check site-written quota procedure */
 573.514 +  if (!tmail_quota (st,path,uid,tmp,sender,precedence)) return fail (tmp,-1);
 573.515 +				/* so far, so good */
 573.516 +  sprintf (tmp,"%s appending to %.80s (%s %.80s)",
 573.517 +	   prt ? prt->dtb->name : "default",mailbox,
 573.518 +	   ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
 573.519 +  mm_dlog (tmp);
 573.520 +				/* do the append now! */
 573.521 +  if (!mail_append (prt,mailbox,st)) {
 573.522 +    sprintf (tmp,"message delivery failed to %.80s",path);
 573.523 +    return fail (tmp,EX_CANTCREAT);
 573.524 +  }
 573.525 +				/* note success */
 573.526 +  sprintf (tmp,"delivered to %.80s",path);
 573.527 +  mm_log (tmp,NIL);
 573.528 +				/* make sure nothing evil this way comes */
 573.529 +  return delivery_unsafe (path,uid,&sbuf,tmp);
 573.530 +}
 573.531 +
 573.532 +/* Verify that delivery is safe
 573.533 + * Accepts: path name
 573.534 + *	    user id
 573.535 + *	    stat buffer
 573.536 + *	    scratch buffer for messages
 573.537 + * Returns: NIL if delivery is safe, error code if unsafe
 573.538 + */
 573.539 +
 573.540 +int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp)
 573.541 +{
 573.542 +  u_short type;
 573.543 +  sprintf (tmp,"Verifying safe delivery to %.80s by UID %ld",path,(long) uid);
 573.544 +  mm_dlog (tmp);
 573.545 +				/* prepare message just in case */
 573.546 +  sprintf (tmp,"delivery to %.80s unsafe: ",path);
 573.547 +				/* unsafe if can't get its status */
 573.548 +  if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
 573.549 +  else if (sbuf->st_uid != uid)	/* unsafe if UID does not match */
 573.550 +    sprintf (tmp + strlen (tmp),"uid mismatch (%ld != %ld)",
 573.551 +	     (long) sbuf->st_uid,(long) uid);
 573.552 +				/* check file type */
 573.553 +  else switch (sbuf->st_mode & S_IFMT) {
 573.554 +  case S_IFDIR:			/* directory is always OK */
 573.555 +    return NIL;
 573.556 +  case S_IFREG:			/* file is unsafe if setuid */
 573.557 +    if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
 573.558 +				/* or setgid */
 573.559 +    else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
 573.560 +    else return NIL;		/* otherwise safe */
 573.561 +    break;
 573.562 +  case S_IFCHR: strcat (tmp,"character special"); break;
 573.563 +  case S_IFBLK: strcat (tmp,"block special"); break;
 573.564 +  case S_IFLNK: strcat (tmp,"symbolic link"); break;
 573.565 +  case S_IFSOCK: strcat (tmp,"socket"); break;
 573.566 +  default:
 573.567 +    sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
 573.568 +  }
 573.569 +  return fail (tmp,EX_CANTCREAT);
 573.570 +}
 573.571 +
 573.572 +/* Report an error
 573.573 + * Accepts: string to output
 573.574 + */
 573.575 +
 573.576 +int fail (char *string,int code)
 573.577 +{
 573.578 +  mm_log (string,ERROR);	/* pass up the string */
 573.579 +  switch (code) {
 573.580 +#if T
 573.581 +  case EX_USAGE:
 573.582 +  case EX_OSERR:
 573.583 +  case EX_SOFTWARE:
 573.584 +  case EX_NOUSER:
 573.585 +  case EX_CANTCREAT:
 573.586 +  case EX_UNAVAILABLE:
 573.587 +    code = EX_TEMPFAIL;		/* coerce these to TEMPFAIL */
 573.588 +#endif
 573.589 +    break;
 573.590 +  case -1:			/* quota failure... */
 573.591 +    code = EX_CANTCREAT;	/* ...really returns this code */
 573.592 +    break;
 573.593 +  default:
 573.594 +    break;
 573.595 +  }
 573.596 +  return code;			/* error code to return */
 573.597 +}
 573.598 +
 573.599 +
 573.600 +/* Get user name from username+mailbox specifier
 573.601 + * Accepts: username/mailbox specifier
 573.602 + *	    pointer to return location for mailbox specifier
 573.603 + * Returns: user name, mailbox specifier value NIL if INBOX, patches out +
 573.604 + */
 573.605 +
 573.606 +char *getusername (char *s,char **t)
 573.607 +{
 573.608 +  if (*t = strchr (s,'+')) {	/* have a mailbox specifier? */
 573.609 +    *(*t)++ = '\0';		/* yes, tie off user name */
 573.610 +				/* user+ and user+INBOX same as user */
 573.611 +    if (!**t || !compare_cstring ((unsigned char *) *t,"INBOX")) *t = NIL;
 573.612 +  }
 573.613 +  return s;			/* return user name */
 573.614 +}
 573.615 +
 573.616 +/* Co-routines from MAIL library */
 573.617 +
 573.618 +
 573.619 +/* Message matches a search
 573.620 + * Accepts: MAIL stream
 573.621 + *	    message number
 573.622 + */
 573.623 +
 573.624 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
 573.625 +{
 573.626 +  fatal ("mm_searched() call");
 573.627 +}
 573.628 +
 573.629 +
 573.630 +/* Message exists (i.e. there are that many messages in the mailbox)
 573.631 + * Accepts: MAIL stream
 573.632 + *	    message number
 573.633 + */
 573.634 +
 573.635 +void mm_exists (MAILSTREAM *stream,unsigned long number)
 573.636 +{
 573.637 +  fatal ("mm_exists() call");
 573.638 +}
 573.639 +
 573.640 +
 573.641 +/* Message expunged
 573.642 + * Accepts: MAIL stream
 573.643 + *	    message number
 573.644 + */
 573.645 +
 573.646 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
 573.647 +{
 573.648 +  fatal ("mm_expunged() call");
 573.649 +}
 573.650 +
 573.651 +
 573.652 +/* Message flags update seen
 573.653 + * Accepts: MAIL stream
 573.654 + *	    message number
 573.655 + */
 573.656 +
 573.657 +void mm_flags (MAILSTREAM *stream,unsigned long number)
 573.658 +{
 573.659 +}
 573.660 +
 573.661 +/* Mailbox found
 573.662 + * Accepts: MAIL stream
 573.663 + *	    delimiter
 573.664 + *	    mailbox name
 573.665 + *	    mailbox attributes
 573.666 + */
 573.667 +
 573.668 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 573.669 +{
 573.670 +  fatal ("mm_list() call");
 573.671 +}
 573.672 +
 573.673 +
 573.674 +/* Subscribed mailbox found
 573.675 + * Accepts: MAIL stream
 573.676 + *	    delimiter
 573.677 + *	    mailbox name
 573.678 + *	    mailbox attributes
 573.679 + */
 573.680 +
 573.681 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
 573.682 +{
 573.683 +  fatal ("mm_lsub() call");
 573.684 +}
 573.685 +
 573.686 +
 573.687 +/* Mailbox status
 573.688 + * Accepts: MAIL stream
 573.689 + *	    mailbox name
 573.690 + *	    mailbox status
 573.691 + */
 573.692 +
 573.693 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
 573.694 +{
 573.695 +  fatal ("mm_status() call");
 573.696 +}
 573.697 +
 573.698 +/* Notification event
 573.699 + * Accepts: MAIL stream
 573.700 + *	    string to log
 573.701 + *	    error flag
 573.702 + */
 573.703 +
 573.704 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
 573.705 +{
 573.706 +  char tmp[MAILTMPLEN];
 573.707 +  tmp[11] = '\0';		/* see if TRYCREATE */
 573.708 +  if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
 573.709 +  mm_log (string,errflg);	/* just do mm_log action */
 573.710 +}
 573.711 +
 573.712 +
 573.713 +/* Log an event for the user to see
 573.714 + * Accepts: string to log
 573.715 + *	    error flag
 573.716 + */
 573.717 +
 573.718 +void mm_log (char *string,long errflg)
 573.719 +{
 573.720 +  if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
 573.721 +  else {			/* ordinary logging */
 573.722 +    fprintf (stderr,"%s\n",string);
 573.723 +    switch (errflg) {  
 573.724 +    case NIL:			/* no error */
 573.725 +      syslog (LOG_INFO,"%s",string);
 573.726 +      break;
 573.727 +    case PARSE:			/* parsing problem */
 573.728 +    case WARN:			/* warning */
 573.729 +      syslog (LOG_WARNING,"%s",string);
 573.730 +      break;
 573.731 +    case ERROR:			/* error */
 573.732 +    default:
 573.733 +      syslog (LOG_ERR,"%s",string);
 573.734 +      break;
 573.735 +    }
 573.736 +  }
 573.737 +}
 573.738 +
 573.739 +
 573.740 +/* Log an event to debugging telemetry
 573.741 + * Accepts: string to log
 573.742 + */
 573.743 +
 573.744 +void mm_dlog (char *string)
 573.745 +{
 573.746 +  if (debug) fprintf (stderr,"%s\n",string);
 573.747 +  syslog (LOG_DEBUG,"%s",string);
 573.748 +}
 573.749 +
 573.750 +/* Get user name and password for this host
 573.751 + * Accepts: parse of network mailbox name
 573.752 + *	    where to return user name
 573.753 + *	    where to return password
 573.754 + *	    trial count
 573.755 + */
 573.756 +
 573.757 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
 573.758 +{
 573.759 +  fatal ("mm_login() call");
 573.760 +}
 573.761 +
 573.762 +
 573.763 +/* About to enter critical code
 573.764 + * Accepts: stream
 573.765 + */
 573.766 +
 573.767 +void mm_critical (MAILSTREAM *stream)
 573.768 +{
 573.769 +  critical = T;			/* note in critical code */
 573.770 +}
 573.771 +
 573.772 +
 573.773 +/* About to exit critical code
 573.774 + * Accepts: stream
 573.775 + */
 573.776 +
 573.777 +void mm_nocritical (MAILSTREAM *stream)
 573.778 +{
 573.779 +  critical = NIL;		/* note not in critical code */
 573.780 +}
 573.781 +
 573.782 +
 573.783 +/* Disk error found
 573.784 + * Accepts: stream
 573.785 + *	    system error code
 573.786 + *	    flag indicating that mailbox may be clobbered
 573.787 + * Returns: T if user wants to abort
 573.788 + */
 573.789 +
 573.790 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
 573.791 +{
 573.792 +  return T;
 573.793 +}
 573.794 +
 573.795 +
 573.796 +/* Log a fatal error event
 573.797 + * Accepts: string to log
 573.798 + */
 573.799 +
 573.800 +void mm_fatal (char *string)
 573.801 +{
 573.802 +  printf ("?%s\n",string);	/* shouldn't happen normally */
 573.803 +}
   574.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   574.2 +++ b/src/tmail/tquota.c	Mon Sep 14 15:17:45 2009 +0900
   574.3 @@ -0,0 +1,45 @@
   574.4 +/* ========================================================================
   574.5 + * Copyright 1988-2007 University of Washington
   574.6 + *
   574.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   574.8 + * you may not use this file except in compliance with the License.
   574.9 + * You may obtain a copy of the License at
  574.10 + *
  574.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  574.12 + *
  574.13 + * 
  574.14 + * ========================================================================
  574.15 + */
  574.16 +
  574.17 +/*
  574.18 + * Program:	Mail Delivery Module Quota Hook
  574.19 + *
  574.20 + * Author:	Mark Crispin
  574.21 + *		Networks and Distributed Computing
  574.22 + *		Computing & Communications
  574.23 + *		University of Washington
  574.24 + *		Administration Building, AG-44
  574.25 + *		Seattle, WA  98195
  574.26 + *		Internet: MRC@CAC.Washington.EDU
  574.27 + *
  574.28 + * Date:	10 September 2007
  574.29 + * Last Edited:	10 September 2007
  574.30 + */
  574.31 +
  574.32 +#include "c-client.h"
  574.33 +
  574.34 +/* Site-written routine to validate delivery per quota and policy
  574.35 + * Accepts: stringstruct of message temporary file
  574.36 + *	    filesystem path
  574.37 + *	    recipient user id
  574.38 + *	    return path
  574.39 + *	    buffer to write error message
  574.40 + *	    precedence setting
  574.41 + * Returns: T if can deliver, or NIL if quota issue and must bounce
  574.42 + */
  574.43 +
  574.44 +long tmail_quota (STRING *msg,char *path,uid_t uid,char *tmp,char *sender,
  574.45 +		  long precedence)
  574.46 +{
  574.47 +  return LONGT;			/* dummy success return */
  574.48 +}
   575.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   575.2 +++ b/src/tmail/tquota.h	Mon Sep 14 15:17:45 2009 +0900
   575.3 @@ -0,0 +1,32 @@
   575.4 +/* ========================================================================
   575.5 + * Copyright 1988-2007 University of Washington
   575.6 + *
   575.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   575.8 + * you may not use this file except in compliance with the License.
   575.9 + * You may obtain a copy of the License at
  575.10 + *
  575.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  575.12 + *
  575.13 + * 
  575.14 + * ========================================================================
  575.15 + */
  575.16 +
  575.17 +/*
  575.18 + * Program:	Mail Delivery Module Quota Hook
  575.19 + *
  575.20 + * Author:	Mark Crispin
  575.21 + *		Networks and Distributed Computing
  575.22 + *		Computing & Communications
  575.23 + *		University of Washington
  575.24 + *		Administration Building, AG-44
  575.25 + *		Seattle, WA  98195
  575.26 + *		Internet: MRC@CAC.Washington.EDU
  575.27 + *
  575.28 + * Date:	10 September 2007
  575.29 + * Last Edited:	10 September 2007
  575.30 + */
  575.31 +
  575.32 +/* Function prototypes */
  575.33 +
  575.34 +long tmail_quota (STRING *msg,char *path,uid_t uid,char *tmp,char *sender,
  575.35 +		  long precedence);
   576.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   576.2 +++ b/tools/Makefile	Mon Sep 14 15:17:45 2009 +0900
   576.3 @@ -0,0 +1,36 @@
   576.4 +# ========================================================================
   576.5 +# Copyright 1988-2006 University of Washington
   576.6 +#
   576.7 +# Licensed under the Apache License, Version 2.0 (the "License");
   576.8 +# you may not use this file except in compliance with the License.
   576.9 +# You may obtain a copy of the License at
  576.10 +#
  576.11 +#     http://www.apache.org/licenses/LICENSE-2.0
  576.12 +#
  576.13 +# 
  576.14 +# ========================================================================
  576.15 +
  576.16 +# Program:	Tools Makefile
  576.17 +#
  576.18 +# Author:	Mark Crispin
  576.19 +#		Networks and Distributed Computing
  576.20 +#		Computing & Communications
  576.21 +#		University of Washington
  576.22 +#		Administration Building, AG-44
  576.23 +#		Seattle, WA  98195
  576.24 +#		Internet: MRC@CAC.Washington.EDU
  576.25 +
  576.26 +
  576.27 +CC=cc
  576.28 +RM=rm -f
  576.29 +
  576.30 +
  576.31 +uahelper:
  576.32 +	$(CC) -o uahelper uahelper.c $(LDFLAGS)
  576.33 +
  576.34 +clean:
  576.35 +	sh -c '$(RM) *.o uahelper || true'
  576.36 +
  576.37 +# A monument to a hack of long ago and far away...
  576.38 +love:
  576.39 +	@echo 'not war?'
   577.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   577.2 +++ b/tools/an	Mon Sep 14 15:17:45 2009 +0900
   577.3 @@ -0,0 +1,41 @@
   577.4 +#!/bin/sh
   577.5 +
   577.6 +# ========================================================================
   577.7 +# Copyright 1988-2007 University of Washington
   577.8 +#
   577.9 +# Licensed under the Apache License, Version 2.0 (the "License");
  577.10 +# you may not use this file except in compliance with the License.
  577.11 +# You may obtain a copy of the License at
  577.12 +#
  577.13 +#     http://www.apache.org/licenses/LICENSE-2.0
  577.14 +#
  577.15 +# 
  577.16 +# ========================================================================
  577.17 +
  577.18 +BASE=`pwd`
  577.19 +
  577.20 +if [ ! -d $3 ]; then
  577.21 + mkdir $3
  577.22 +fi
  577.23 +
  577.24 +for i in $2/Makefile* ; do
  577.25 +  if [ -f $i ] ; then
  577.26 +    $1 "$BASE/$i" "$BASE/$3"
  577.27 +  fi
  577.28 +done
  577.29 +
  577.30 +if [ -f $2/drivers ]; then
  577.31 +  $1 "$BASE/$2/drivers" "$BASE/$3"
  577.32 +fi
  577.33 +
  577.34 +if [ -f $2/mkauths ]; then
  577.35 +  $1 "$BASE/$2/mkauths" "$BASE/$3"
  577.36 +fi
  577.37 +
  577.38 +cd $2
  577.39 +
  577.40 +for j in *.[ch]; do
  577.41 +  $1 "$BASE/$2/$j" "$BASE/$3"
  577.42 +done
  577.43 +
  577.44 +exit 0
   578.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   578.2 +++ b/tools/ua	Mon Sep 14 15:17:45 2009 +0900
   578.3 @@ -0,0 +1,45 @@
   578.4 +#!/bin/sh
   578.5 +
   578.6 +# ========================================================================
   578.7 +# Copyright 1988-2006 University of Washington
   578.8 +#
   578.9 +# Licensed under the Apache License, Version 2.0 (the "License");
  578.10 +# you may not use this file except in compliance with the License.
  578.11 +# You may obtain a copy of the License at
  578.12 +#
  578.13 +#     http://www.apache.org/licenses/LICENSE-2.0
  578.14 +#
  578.15 +# 
  578.16 +# ========================================================================
  578.17 +
  578.18 +BASE=`pwd`
  578.19 +
  578.20 +if [ ! -f tools/uahelper ]; then
  578.21 +  (cd tools;make)
  578.22 +fi
  578.23 +
  578.24 +if [ ! -d $3 ]; then
  578.25 + mkdir $3
  578.26 +fi
  578.27 +
  578.28 +for i in $2/Makefile* ; do
  578.29 +  if [ -f $i ] ; then
  578.30 +    $1 "$BASE/$i" "$BASE/$3"
  578.31 +  fi
  578.32 +done
  578.33 +
  578.34 +if [ -f $2/drivers ]; then
  578.35 +  $1 "$BASE/$2/drivers" "$BASE/$3"
  578.36 +fi
  578.37 +
  578.38 +if [ -f $2/mkauths ]; then
  578.39 +  $1 "$BASE/$2/mkauths" "$BASE/$3"
  578.40 +fi
  578.41 +
  578.42 +cd $2
  578.43 +
  578.44 +for j in *.[ch]; do
  578.45 +  "$BASE/tools/uahelper" < $j > "$BASE/$3/$j"
  578.46 +done
  578.47 +
  578.48 +exit 0
   579.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   579.2 +++ b/tools/uahelper.c	Mon Sep 14 15:17:45 2009 +0900
   579.3 @@ -0,0 +1,262 @@
   579.4 +/* ========================================================================
   579.5 + * Copyright 1988-2006 University of Washington
   579.6 + *
   579.7 + * Licensed under the Apache License, Version 2.0 (the "License");
   579.8 + * you may not use this file except in compliance with the License.
   579.9 + * You may obtain a copy of the License at
  579.10 + *
  579.11 + *     http://www.apache.org/licenses/LICENSE-2.0
  579.12 + *
  579.13 + * 
  579.14 + * ========================================================================
  579.15 + */
  579.16 +
  579.17 +/*
  579.18 + * Program:	unANSIify
  579.19 + *
  579.20 + * Author:	Mark Crispin
  579.21 + *		Networks and Distributed Computing
  579.22 + *		Computing & Communications
  579.23 + *		University of Washington
  579.24 + *		4545 15th Ave NE
  579.25 + *		Seattle, WA  98105-4527
  579.26 + *		Internet: MRC@CAC.Washington.EDU
  579.27 + *
  579.28 + * Date:	1 June 1995
  579.29 + * Last Edited:	30 August 2006
  579.30 + */
  579.31 +
  579.32 +
  579.33 +/* This program is designed to make traditional C sources out of my source
  579.34 + * files which use ANSI syntax.  This program depends heavily upon knowledge
  579.35 + * of the way I write code, and is not a general purpose tool.  I hope that
  579.36 + * someday someone will provide a general purpose tool...
  579.37 + */
  579.38 +
  579.39 +#include <stdio.h>
  579.40 +
  579.41 +#define LINELENGTH 1000
  579.42 +
  579.43 +
  579.44 +/* Find first non-whitespace
  579.45 + * Accepts: string
  579.46 + * Returns: 0 if no non-whitespace found, or pointer to non-whitespace
  579.47 + */
  579.48 +
  579.49 +char *fndnws (s)
  579.50 +     char *s;
  579.51 +{
  579.52 +  while ((*s == ' ') || (*s == '\t'))
  579.53 +    if ((*s++ == '\n') || !*s) return (char *) 0;
  579.54 +  return s;
  579.55 +}
  579.56 +
  579.57 +
  579.58 +/* Find first whitespace
  579.59 + * Accepts: string
  579.60 + * Returns: 0 if no whitespace found, or pointer to whitespace
  579.61 + */
  579.62 +
  579.63 +char *fndws (s)
  579.64 +     char *s;
  579.65 +{
  579.66 +  while ((*s != ' ') && (*s != '\t'))
  579.67 +    if ((*s++ == '\n') || !*s) return (char *) 0;
  579.68 +  return s;
  579.69 +}
  579.70 +
  579.71 +
  579.72 +/* Find end of commend
  579.73 + * Accepts: string
  579.74 + * Returns: -1 if end of comment found, else 0
  579.75 + */
  579.76 +
  579.77 +int fndcmt (s)
  579.78 +     char *s;
  579.79 +{
  579.80 +  while (*s && (*s != '\n'))
  579.81 +    if ((*s++ == '*') && (*s == '/')) return -1;
  579.82 +  return 0;
  579.83 +}
  579.84 +
  579.85 +/* Output a line
  579.86 + * Accepts: string
  579.87 + */
  579.88 +
  579.89 +void poot (s)
  579.90 +     char *s;
  579.91 +{
  579.92 +  if (s) fputs (s,stdout);
  579.93 +}
  579.94 +
  579.95 +
  579.96 +/* Skip prefix
  579.97 + * Accepts: string
  579.98 + * Returns: updated string
  579.99 + */
 579.100 +
 579.101 +char *skipfx (s)
 579.102 +     char *s;
 579.103 +{
 579.104 +  char c,*t = s,*tt;
 579.105 +				/* skip leading whitespace too */
 579.106 +  while ((*s == ' ') || (*s == '\t')) *s++;
 579.107 +  if (s != t) {
 579.108 +    c = *s;			/* save character */
 579.109 +    *s = '\0';			/* tie off prefix */
 579.110 +    poot (t);			/* output prefix */
 579.111 +    *s = c;			/* restore character */
 579.112 +  }
 579.113 +				/* a typedef? */
 579.114 +  if (((s[0] == 't') && (s[1] == 'y') && (s[2] == 'p') && (s[3] == 'e') &&
 579.115 +       (s[4] == 'd') && (s[5] == 'e') && (s[6] == 'f')) &&
 579.116 +      (t = fndws (s)) && (t = fndnws (t))) {
 579.117 +    if ((t[0] == 'u') && (t[1] == 'n') && (t[2] == 's') && (t[3] == 'i') &&
 579.118 +	(t[4] == 'g') && (t[5] == 'n') && (t[6] == 'e') && (t[7] == 'd') &&
 579.119 +	(tt = fndws (t+7)) && (tt = fndnws (tt))) t = tt;
 579.120 +    c = *t;			/* save character */
 579.121 +    *t = '\0';			/* tie off prefix */
 579.122 +    poot (s);			/* output prefix */
 579.123 +    *t = c;			/* restore character */
 579.124 +    s = t;			/* new string pointer */
 579.125 +  }
 579.126 +				/* static with known prefix */
 579.127 +  else if (((s[0] == 's') && (s[1] == 't') && (s[2] == 'a') &&
 579.128 +	    (s[3] == 't') && (s[4] == 'i') && (s[5] == 'c') &&
 579.129 +	    (s[6] == ' ')) &&
 579.130 +	   (((s[7] == 'u') && (s[8] == 'n') && (s[9] == 's') &&
 579.131 +	     (s[10] == 'i') && (s[11] == 'g') && (s[12] == 'n') &&
 579.132 +	     (s[13] == 'e') && (s[14] == 'd')) ||
 579.133 +	    ((s[7] == 's') && (s[8] == 't') && (s[9] == 'r') &&
 579.134 +	     (s[10] == 'u') && (s[11] == 'c') && (s[12] == 't')) ||
 579.135 +	    ((s[7] == 'd') && (s[8] == 'o')) ||
 579.136 +	    ((s[9] == 'e') && (s[10] == 'l') && (s[11] == 's') &&
 579.137 +	     (s[12] == 'e'))) &&
 579.138 +	   (t = fndws (s)) && (t = fndnws (t)) &&
 579.139 +	   (t = fndws (t)) && (t = fndnws (t))) {
 579.140 +    c = *t;			/* save character */
 579.141 +    *t = '\0';			/* tie off prefix */
 579.142 +    poot (s);			/* output prefix */
 579.143 +    *t = c;			/* restore character */
 579.144 +    s = t;			/* new string pointer */
 579.145 +  }
 579.146 +				/* one of the known prefixes? */
 579.147 +  else if ((((s[0] == 'u') && (s[1] == 'n') && (s[2] == 's') &&
 579.148 +	     (s[3] == 'i') && (s[4] == 'g') && (s[5] == 'n') &&
 579.149 +	     (s[6] == 'e') && (s[7] == 'd')) ||
 579.150 +	    ((s[0] == 's') && (s[1] == 't') && (s[2] == 'r') &&
 579.151 +	     (s[3] == 'u') && (s[4] == 'c') && (s[5] == 't')) ||
 579.152 +	    ((s[0] == 's') && (s[1] == 't') && (s[2] == 'a') &&
 579.153 +	     (s[3] == 't') && (s[4] == 'i') && (s[5] == 'c')) ||
 579.154 +	    ((s[0] == 'd') && (s[1] == 'o')) ||
 579.155 +	    ((s[0] == 'e') && (s[1] == 'l') && (s[2] == 's') &&
 579.156 +	     (s[3] == 'e'))) &&
 579.157 +	   (t = fndws (s)) && (t = fndnws (t))) {
 579.158 +    c = *t;			/* save character */
 579.159 +    *t = '\0';			/* tie off prefix */
 579.160 +    poot (s);			/* output prefix */
 579.161 +    *t = c;			/* restore character */
 579.162 +    s = t;			/* new string pointer */
 579.163 +  }
 579.164 +				/* may look like a proto, but isn't */
 579.165 +  else if ((s[0] == 'r') && (s[1] == 'e') && (s[2] == 't') && (s[3] == 'u') &&
 579.166 +	   (s[4] == 'r') && (s[5] == 'n')) {
 579.167 +    poot (s);
 579.168 +    return 0;
 579.169 +  }
 579.170 +  return s;
 579.171 +}
 579.172 +
 579.173 +/* UnANSI a line
 579.174 + * Accepts: string
 579.175 + */
 579.176 +
 579.177 +void unansi (s)
 579.178 +     char *s;
 579.179 +{
 579.180 +  char c,*t = s,*u,*v;
 579.181 +  while (t[1] && (t[1] != '\n')) t++;
 579.182 +  switch (*t) {
 579.183 +  case ',':			/* continued on next line? */
 579.184 +				/* slurp remainder of line */
 579.185 +    fgets (t + 1,LINELENGTH - (t + 1 - s),stdin);
 579.186 +    unansi (s);			/* try again */
 579.187 +    break;
 579.188 +  case ';':			/* function prototype? */
 579.189 +				/* yes, tie it off */
 579.190 +    *(fndws (fndnws (fndws (fndnws (s))))) = '\0';
 579.191 +    printf ("%s ();\n",s);	/* and output non-ANSI form */
 579.192 +    break;
 579.193 +  case ')':
 579.194 +    *t = '\0';			/* tie off args */
 579.195 +    if (*(t = fndnws (fndws (fndnws (fndws (fndnws (s)))))) == '(') {
 579.196 +      *t++ = '\0';		/* tie off */
 579.197 +      while ((*t == ' ') || (*t == '\t')) t++;
 579.198 +      if ((t[0] == 'v') && (t[1] == 'o') && (t[2] == 'i') && (t[3] == 'd') &&
 579.199 +	  !t[4]) *t = '\0';	/* make void be same as null */
 579.200 +      printf ("%s(",s);		/* output start of function */
 579.201 +      s = t;
 579.202 +      while (*s) {		/* for each argument */
 579.203 +	while ((*s == ' ') || (*s == '\t')) s++;
 579.204 +	for (u = v = s; (*u && (*u != ',') && (*u != '[')); u++)
 579.205 +	  if ((*u == ' ') || (*u == '\t')) v = u;
 579.206 +	c = *u;			/* remember delimiter */
 579.207 +	*u = '\0';		/* tie off argument name */
 579.208 +	while (*++v == '*');	/* remove leading pointer indication */
 579.209 +	fputs (v,stdout);	/* write variable name */
 579.210 +	*(s = u) = c;		/* restore delimiter */
 579.211 +	while (*s && (*s != ',')) *s++;
 579.212 +	if (*s) fputc (*s++,stdout);
 579.213 +      }
 579.214 +      puts (")");		/* end of function */
 579.215 +      while (*t) {		/* for each argument */
 579.216 +	fputs ("     ",stdout);
 579.217 +	while ((*t == ' ') || (*t == '\t')) t++;
 579.218 +	while (*t && (*t != ',')) fputc (*t++,stdout);
 579.219 +	puts (";");
 579.220 +	if (*t == ',') t++;
 579.221 +      }
 579.222 +    }
 579.223 +    else printf ("%s)",s);	/* say what?? */
 579.224 +    break;
 579.225 +  default:			/* doesn't look like a function */
 579.226 +    poot (s);
 579.227 +  }
 579.228 +}
 579.229 +
 579.230 +main ()
 579.231 +{
 579.232 +  char *s,*t,line[LINELENGTH];
 579.233 +  int c;
 579.234 +  while (s = fgets (line,LINELENGTH,stdin)) switch (line[0]) {
 579.235 +  case '/':			/* comment */
 579.236 +    if ((s[1] != '*') || fndcmt (s+2)) poot (line);
 579.237 +    else do poot (line);
 579.238 +    while (!fndcmt (line) && (s = fgets (line,LINELENGTH,stdin)));
 579.239 +    break;
 579.240 +  case '{':			/* open function */
 579.241 +  case '}':			/* close function */
 579.242 +  case '\f':			/* formfeed */
 579.243 +  case '\n':			/* newline */
 579.244 +  case '#':			/* preprocessor command */
 579.245 +    poot (line);
 579.246 +    break;
 579.247 +  case '\t':			/* whitespace */
 579.248 +  case ' ':
 579.249 +				/* look like function arg def in structure? */
 579.250 +    if ((t = skipfx (line)) && (s = fndws (t)) && (s = fndnws (s)) &&
 579.251 +	(((*s == '(') && (s[1] == '*')) ||
 579.252 +	 ((*s == '*') && (s[1] == '(') && (s[2] == '*'))) &&
 579.253 +	(s = fndws (s)) && (s[-1] == ')') && (s = fndnws (s)) && (*s == '('))
 579.254 +      unansi (t);
 579.255 +    else poot (t);
 579.256 +    break;
 579.257 +  default:			/* begins with anything else */
 579.258 +				/* look like function proto or def? */
 579.259 +    if ((t = skipfx (line)) && (s = fndws (t)) && (s = fndnws (s)) &&
 579.260 +	(s = fndws (s)) && (s = fndnws (s)) && (*s == '('))
 579.261 +      unansi (t);
 579.262 +    else poot (t);
 579.263 +    break;
 579.264 +  }
 579.265 +}

UW-IMAP'd extensions by yuuji